Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Support Sonarr multi-season packs
- Improved x265, H.266, VC1 and VVC codec replacements
- Open the exact movie on Letterboxd instead of a search
- Filter movies and series by tag
- Use custom filters from the Radarr and Sonarr web interface, or create your own

### Changed
- Show filter, sort and instance buttons together on folded iPhone Duo
Expand Down
3 changes: 3 additions & 0 deletions Ruddarr.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@
BBAD4DA72FF4A8FC0066994A /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = {
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = (
Models/CustomFilters/CustomFilter.swift,
"Models/CustomFilters/CustomFilter+Matching.swift",
Models/CustomFilters/CustomFilterResource.swift,
Services/NetworkInterfaces.swift,
Services/NetworkSnapshot.swift,
Services/ResolverRouting.swift,
Expand Down
24 changes: 24 additions & 0 deletions Ruddarr/Dependencies/API/API+Live.swift
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,30 @@ extension InstanceAPI {
.appending(path: "/api/v3/notification")
.appending(path: String(model.id ?? 0))

return try await API.request(method: .delete, url: url, instance: instance)
}, customFilters: { instance in
let url = try await instance.baseURL()
.appending(path: "/api/v3/customfilter")

// The endpoint returns every app screen's filters, so one odd entry mustn't fail the rest.
let filters: [LossyDecoded<CustomFilterResource>] = try await API.request(url: url, instance: instance)
return filters.compactMap(\.wrappedValue)
}, createCustomFilter: { model, instance in
let url = try await instance.baseURL()
.appending(path: "/api/v3/customfilter")

return try await API.request(method: .post, url: url, body: model, instance: instance)
}, updateCustomFilter: { model, instance in
let url = try await instance.baseURL()
.appending(path: "/api/v3/customfilter")
.appending(path: String(model.id ?? 0))

return try await API.request(method: .put, url: url, body: model, instance: instance)
}, deleteCustomFilter: { model, instance in
let url = try await instance.baseURL()
.appending(path: "/api/v3/customfilter")
.appending(path: String(model.id ?? 0))

return try await API.request(method: .delete, url: url, instance: instance)
})
}
Expand Down
15 changes: 15 additions & 0 deletions Ruddarr/Dependencies/API/API+Mock.swift
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,21 @@ extension InstanceAPI {
}, deleteNotification: { _, _ in
try await Task.sleep(for: .seconds(2))

return API.Empty()
}, customFilters: { _ in
try await Task.sleep(for: .seconds(1))
let filters: [CustomFilterResource] = loadPreviewData(filename: "custom-filters")
return filters
}, createCustomFilter: { model, _ in
try await Task.sleep(for: .seconds(1))
var created = model
created.id = Int.random(in: 1_000...9_999)
return created
}, updateCustomFilter: { model, _ in
try await Task.sleep(for: .seconds(1))
return model
}, deleteCustomFilter: { _, _ in
try await Task.sleep(for: .seconds(1))
return API.Empty()
})
}
Expand Down
6 changes: 6 additions & 0 deletions Ruddarr/Dependencies/API/API.swift
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ struct InstanceAPI: Sendable {
var createNotification: @Sendable (InstanceNotification, Instance) async throws -> InstanceNotification
var updateNotification: @Sendable (InstanceNotification, Instance) async throws -> InstanceNotification
var deleteNotification: @Sendable (InstanceNotification, Instance) async throws -> API.Empty

/// Every custom filter on the server, of every `type`. Entries that fail to decode are dropped.
var customFilters: @Sendable (Instance) async throws -> [CustomFilterResource]
var createCustomFilter: @Sendable (CustomFilterResource, Instance) async throws -> CustomFilterResource
var updateCustomFilter: @Sendable (CustomFilterResource, Instance) async throws -> CustomFilterResource
var deleteCustomFilter: @Sendable (CustomFilterResource, Instance) async throws -> API.Empty
}

extension API {
Expand Down
Loading