diff --git a/Ferrite/API/AllDebridWrapper.swift b/Ferrite/API/AllDebridWrapper.swift index d0251e5..95d4ea4 100644 --- a/Ferrite/API/AllDebridWrapper.swift +++ b/Ferrite/API/AllDebridWrapper.swift @@ -19,6 +19,8 @@ public class AllDebrid: PollingDebridSource { let jsonDecoder = JSONDecoder() + // MARK: - Auth + // Fetches information for PIN auth public func getAuthUrl() async throws -> URL { let url = try buildRequestURL(urlString: "\(baseApiUrl)/pin/get") @@ -106,6 +108,8 @@ public class AllDebrid: PollingDebridSource { UserDefaults.standard.removeObject(forKey: "AllDebrid.UseManualKey") } + // MARK: - Common request + // Wrapper request function which matches the responses and returns data @discardableResult private func performRequest(request: inout URLRequest, requestName: String) async throws -> Data { guard let token = getToken() else { @@ -147,6 +151,34 @@ public class AllDebrid: PollingDebridSource { } } + // MARK: - Instant availability + + public func instantAvailability(magnets: [Magnet]) async throws -> [DebridIA] { + let queryItems = magnets.map { URLQueryItem(name: "magnets[]", value: $0.hash) } + var request = URLRequest(url: try buildRequestURL(urlString: "\(baseApiUrl)/magnet/instant", queryItems: queryItems)) + + let data = try await performRequest(request: &request, requestName: #function) + let rawResponse = try jsonDecoder.decode(ADResponse.self, from: data).data + + let filteredMagnets = rawResponse.magnets.filter { $0.instant == true && $0.files != nil } + let availableHashes = filteredMagnets.map { magnetResp in + // Force unwrap is OK here since the filter caught any nil values + let files = magnetResp.files!.enumerated().map { index, magnetFile in + DebridIAFile(fileId: index, name: magnetFile.name) + } + + return DebridIA( + magnet: Magnet(hash: magnetResp.hash, link: magnetResp.magnet), + expiryTimeStamp: Date().timeIntervalSince1970 + 300, + files: files + ) + } + + return availableHashes + } + + // MARK: - Downloading + // Wrapper function to fetch a download link from the API public func getDownloadLink(magnet: Magnet, ia: DebridIA?, iaFile: DebridIAFile?) async throws -> String { let magnetID = try await addMagnet(magnet: magnet) @@ -226,6 +258,8 @@ public class AllDebrid: PollingDebridSource { try await performRequest(request: &request, requestName: #function) } + // MARK: - Cloud methods + // Referred to as "User magnets" in AllDebrid's API public func getUserTorrents() async throws -> [DebridCloudTorrent] { var request = URLRequest(url: try buildRequestURL(urlString: "\(baseApiUrl)/magnet/status")) @@ -288,28 +322,4 @@ public class AllDebrid: PollingDebridSource { try await performRequest(request: &request, requestName: #function) } - - public func instantAvailability(magnets: [Magnet]) async throws -> [DebridIA] { - let queryItems = magnets.map { URLQueryItem(name: "magnets[]", value: $0.hash) } - var request = URLRequest(url: try buildRequestURL(urlString: "\(baseApiUrl)/magnet/instant", queryItems: queryItems)) - - let data = try await performRequest(request: &request, requestName: #function) - let rawResponse = try jsonDecoder.decode(ADResponse.self, from: data).data - - let filteredMagnets = rawResponse.magnets.filter { $0.instant == true && $0.files != nil } - let availableHashes = filteredMagnets.map { magnetResp in - // Force unwrap is OK here since the filter caught any nil values - let files = magnetResp.files!.enumerated().map { index, magnetFile in - DebridIAFile(fileId: index, name: magnetFile.name) - } - - return DebridIA( - magnet: Magnet(hash: magnetResp.hash, link: magnetResp.magnet), - expiryTimeStamp: Date().timeIntervalSince1970 + 300, - files: files - ) - } - - return availableHashes - } } diff --git a/Ferrite/API/PremiumizeWrapper.swift b/Ferrite/API/PremiumizeWrapper.swift index 54d489f..3216ad6 100644 --- a/Ferrite/API/PremiumizeWrapper.swift +++ b/Ferrite/API/PremiumizeWrapper.swift @@ -18,6 +18,8 @@ public class Premiumize: OAuthDebridSource { let jsonDecoder = JSONDecoder() + // MARK: - Auth + public func getAuthUrl() throws -> URL { var urlComponents = URLComponents(string: baseAuthUrl)! urlComponents.queryItems = [ @@ -68,6 +70,8 @@ public class Premiumize: OAuthDebridSource { UserDefaults.standard.removeObject(forKey: "Premiumize.UseManualKey") } + // MARK: - Common request + // Wrapper request function which matches the responses and returns data @discardableResult private func performRequest(request: inout URLRequest, requestName: String) async throws -> Data { guard let token = getToken() else { @@ -112,54 +116,7 @@ public class Premiumize: OAuthDebridSource { } } - // Function to divide and execute cache endpoint requests in parallel - // Calls this for 100 hashes at a time due to API limits - public func divideCacheRequests(magnets: [Magnet]) async throws -> [Magnet] { - let availableMagnets = try await withThrowingTaskGroup(of: [Magnet].self) { group in - for chunk in magnets.chunked(into: 100) { - group.addTask { - try await self.checkCache(magnets: chunk) - } - } - - var chunkedMagnets: [Magnet] = [] - for try await magnetArray in group { - chunkedMagnets += magnetArray - } - - return chunkedMagnets - } - - return availableMagnets - } - - // Parent function for initial checking of the cache - func checkCache(magnets: [Magnet]) async throws -> [Magnet] { - var urlComponents = URLComponents(string: "\(baseApiUrl)/cache/check")! - urlComponents.queryItems = magnets.map { URLQueryItem(name: "items[]", value: $0.hash) } - guard let url = urlComponents.url else { - throw PMError.InvalidUrl - } - - var request = URLRequest(url: url) - - let data = try await performRequest(request: &request, requestName: #function) - let rawResponse = try jsonDecoder.decode(CacheCheckResponse.self, from: data) - - if rawResponse.response.isEmpty { - throw PMError.EmptyData - } else { - let availableMagnets = magnets.enumerated().compactMap { index, magnet in - if rawResponse.response[safe: index] == true { - return magnet - } else { - return nil - } - } - - return availableMagnets - } - } + // MARK: - Instant availability // Function to divide and execute DDL endpoint requests in parallel // Calls this for 10 requests at a time to not overwhelm API servers @@ -218,6 +175,57 @@ public class Premiumize: OAuthDebridSource { } } + // Function to divide and execute cache endpoint requests in parallel + // Calls this for 100 hashes at a time due to API limits + public func divideCacheRequests(magnets: [Magnet]) async throws -> [Magnet] { + let availableMagnets = try await withThrowingTaskGroup(of: [Magnet].self) { group in + for chunk in magnets.chunked(into: 100) { + group.addTask { + try await self.checkCache(magnets: chunk) + } + } + + var chunkedMagnets: [Magnet] = [] + for try await magnetArray in group { + chunkedMagnets += magnetArray + } + + return chunkedMagnets + } + + return availableMagnets + } + + // Parent function for initial checking of the cache + func checkCache(magnets: [Magnet]) async throws -> [Magnet] { + var urlComponents = URLComponents(string: "\(baseApiUrl)/cache/check")! + urlComponents.queryItems = magnets.map { URLQueryItem(name: "items[]", value: $0.hash) } + guard let url = urlComponents.url else { + throw PMError.InvalidUrl + } + + var request = URLRequest(url: url) + + let data = try await performRequest(request: &request, requestName: #function) + let rawResponse = try jsonDecoder.decode(CacheCheckResponse.self, from: data) + + if rawResponse.response.isEmpty { + throw PMError.EmptyData + } else { + let availableMagnets = magnets.enumerated().compactMap { index, magnet in + if rawResponse.response[safe: index] == true { + return magnet + } else { + return nil + } + } + + return availableMagnets + } + } + + // MARK: - Downloading + // Wrapper function to fetch a DDL link from the API public func getDownloadLink(magnet: Magnet, ia: DebridIA?, iaFile: DebridIAFile?) async throws -> String { // Store the item in PM cloud for later use @@ -249,6 +257,8 @@ public class Premiumize: OAuthDebridSource { try await performRequest(request: &request, requestName: #function) } + // MARK: - Cloud methods + public func getUserDownloads() async throws -> [DebridCloudDownload] { var request = URLRequest(url: URL(string: "\(baseApiUrl)/item/listall")!) diff --git a/Ferrite/API/RealDebridWrapper.swift b/Ferrite/API/RealDebridWrapper.swift index 59a362b..38256bb 100644 --- a/Ferrite/API/RealDebridWrapper.swift +++ b/Ferrite/API/RealDebridWrapper.swift @@ -29,6 +29,8 @@ public class RealDebrid: PollingDebridSource { UserDefaults.standard.removeObject(forKey: forKey) } + // MARK: - Auth + // Fetches the device code from RD public func getAuthUrl() async throws -> URL { var urlComponents = URLComponents(string: "\(baseAuthUrl)/device/code")! @@ -189,6 +191,8 @@ public class RealDebrid: PollingDebridSource { } } + // MARK: - Common request + // Wrapper request function which matches the responses and returns data @discardableResult private func performRequest(request: inout URLRequest, requestName: String) async throws -> Data { guard let token = await fetchToken() else { @@ -213,6 +217,8 @@ public class RealDebrid: PollingDebridSource { } } + // MARK: - Instant availability + // Checks if the magnet is streamable on RD public func instantAvailability(magnets: [Magnet]) async throws -> [DebridIA] { var availableHashes: [DebridIA] = [] @@ -284,6 +290,8 @@ public class RealDebrid: PollingDebridSource { return availableHashes } + // MARK: - Downloading + // Wrapper function to fetch a download link from the API public func getDownloadLink(magnet: Magnet, ia: DebridIA?, iaFile: DebridIAFile?) async throws -> String { let selectedMagnetId = try await addMagnet(magnet: magnet) @@ -376,6 +384,8 @@ public class RealDebrid: PollingDebridSource { return rawResponse.download } + // MARK: - Cloud methods + // Gets the user's torrent library public func getUserTorrents() async throws -> [DebridCloudTorrent] { var request = URLRequest(url: URL(string: "\(baseApiUrl)/torrents")!)