mirror of
https://github.com/Ferrite-iOS/Ferrite.git
synced 2026-04-21 00:42:07 +00:00
Debrid: Add protocol for cloud handling
Cloud downloads and torrents are now unified under their own protocol and models. Downloads and torrents are separated. Signed-off-by: kingbri <bdashore3@proton.me>
This commit is contained in:
parent
37450ef979
commit
9e306eff1e
9 changed files with 204 additions and 129 deletions
|
|
@ -10,6 +10,8 @@ import Foundation
|
||||||
// TODO: Fix errors
|
// TODO: Fix errors
|
||||||
public class AllDebrid: PollingDebridSource {
|
public class AllDebrid: PollingDebridSource {
|
||||||
public let id = "AllDebrid"
|
public let id = "AllDebrid"
|
||||||
|
public let abbreviation = "AD"
|
||||||
|
public let website = "https://alldebrid.com"
|
||||||
public var authTask: Task<Void, Error>?
|
public var authTask: Task<Void, Error>?
|
||||||
|
|
||||||
let baseApiUrl = "https://api.alldebrid.com/v4"
|
let baseApiUrl = "https://api.alldebrid.com/v4"
|
||||||
|
|
@ -203,28 +205,6 @@ public class AllDebrid: PollingDebridSource {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func userMagnets() async throws -> [MagnetStatusData] {
|
|
||||||
var request = URLRequest(url: try buildRequestURL(urlString: "\(baseApiUrl)/magnet/status"))
|
|
||||||
|
|
||||||
let data = try await performRequest(request: &request, requestName: #function)
|
|
||||||
let rawResponse = try jsonDecoder.decode(ADResponse<MagnetStatusResponse>.self, from: data).data
|
|
||||||
|
|
||||||
if rawResponse.magnets.isEmpty {
|
|
||||||
throw ADError.EmptyData
|
|
||||||
} else {
|
|
||||||
return rawResponse.magnets
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public func deleteMagnet(magnetId: Int) async throws {
|
|
||||||
let queryItems = [
|
|
||||||
URLQueryItem(name: "id", value: String(magnetId))
|
|
||||||
]
|
|
||||||
var request = URLRequest(url: try buildRequestURL(urlString: "\(baseApiUrl)/magnet/delete", queryItems: queryItems))
|
|
||||||
|
|
||||||
try await performRequest(request: &request, requestName: #function)
|
|
||||||
}
|
|
||||||
|
|
||||||
public func unlockLink(lockedLink: String) async throws -> String {
|
public func unlockLink(lockedLink: String) async throws -> String {
|
||||||
let queryItems = [
|
let queryItems = [
|
||||||
URLQueryItem(name: "link", value: lockedLink)
|
URLQueryItem(name: "link", value: lockedLink)
|
||||||
|
|
@ -246,7 +226,40 @@ public class AllDebrid: PollingDebridSource {
|
||||||
try await performRequest(request: &request, requestName: #function)
|
try await performRequest(request: &request, requestName: #function)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func savedLinks() async throws -> [SavedLink] {
|
// 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"))
|
||||||
|
|
||||||
|
let data = try await performRequest(request: &request, requestName: #function)
|
||||||
|
let rawResponse = try jsonDecoder.decode(ADResponse<MagnetStatusResponse>.self, from: data).data
|
||||||
|
|
||||||
|
if rawResponse.magnets.isEmpty {
|
||||||
|
throw ADError.EmptyData
|
||||||
|
}
|
||||||
|
|
||||||
|
let torrents = rawResponse.magnets.map { magnetResponse in
|
||||||
|
DebridCloudTorrent(
|
||||||
|
torrentId: String(magnetResponse.id),
|
||||||
|
fileName: magnetResponse.filename,
|
||||||
|
status: magnetResponse.status,
|
||||||
|
hash: magnetResponse.hash,
|
||||||
|
links: magnetResponse.links.map { $0.link }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return torrents
|
||||||
|
}
|
||||||
|
|
||||||
|
public func deleteTorrent(torrentId: String) async throws {
|
||||||
|
let queryItems = [
|
||||||
|
URLQueryItem(name: "id", value: torrentId)
|
||||||
|
]
|
||||||
|
var request = URLRequest(url: try buildRequestURL(urlString: "\(baseApiUrl)/magnet/delete", queryItems: queryItems))
|
||||||
|
|
||||||
|
try await performRequest(request: &request, requestName: #function)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func getUserDownloads() async throws -> [DebridCloudDownload] {
|
||||||
var request = URLRequest(url: try buildRequestURL(urlString: "\(baseApiUrl)/user/links"))
|
var request = URLRequest(url: try buildRequestURL(urlString: "\(baseApiUrl)/user/links"))
|
||||||
|
|
||||||
let data = try await performRequest(request: &request, requestName: #function)
|
let data = try await performRequest(request: &request, requestName: #function)
|
||||||
|
|
@ -254,14 +267,22 @@ public class AllDebrid: PollingDebridSource {
|
||||||
|
|
||||||
if rawResponse.links.isEmpty {
|
if rawResponse.links.isEmpty {
|
||||||
throw ADError.EmptyData
|
throw ADError.EmptyData
|
||||||
} else {
|
|
||||||
return rawResponse.links
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The link is also the ID
|
||||||
|
let downloads = rawResponse.links.map { link in
|
||||||
|
DebridCloudDownload(
|
||||||
|
downloadId: link.link, fileName: link.filename, link: link.link
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return downloads
|
||||||
}
|
}
|
||||||
|
|
||||||
public func deleteLink(link: String) async throws {
|
// The downloadId is actually the download link
|
||||||
|
public func deleteDownload(downloadId: String) async throws {
|
||||||
let queryItems = [
|
let queryItems = [
|
||||||
URLQueryItem(name: "link", value: link)
|
URLQueryItem(name: "link", value: downloadId)
|
||||||
]
|
]
|
||||||
var request = URLRequest(url: try buildRequestURL(urlString: "\(baseApiUrl)/user/links/delete", queryItems: queryItems))
|
var request = URLRequest(url: try buildRequestURL(urlString: "\(baseApiUrl)/user/links/delete", queryItems: queryItems))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@ import Foundation
|
||||||
|
|
||||||
public class Premiumize: OAuthDebridSource {
|
public class Premiumize: OAuthDebridSource {
|
||||||
public let id = "Premiumize"
|
public let id = "Premiumize"
|
||||||
|
public let abbreviation = "PM"
|
||||||
|
public let website = "https://premiumize.me"
|
||||||
|
|
||||||
let baseAuthUrl = "https://www.premiumize.me/authorize"
|
let baseAuthUrl = "https://www.premiumize.me/authorize"
|
||||||
let baseApiUrl = "https://www.premiumize.me/api"
|
let baseApiUrl = "https://www.premiumize.me/api"
|
||||||
|
|
@ -247,7 +249,7 @@ public class Premiumize: OAuthDebridSource {
|
||||||
try await performRequest(request: &request, requestName: #function)
|
try await performRequest(request: &request, requestName: #function)
|
||||||
}
|
}
|
||||||
|
|
||||||
func userItems() async throws -> [UserItem] {
|
public func getUserDownloads() async throws -> [DebridCloudDownload] {
|
||||||
var request = URLRequest(url: URL(string: "\(baseApiUrl)/item/listall")!)
|
var request = URLRequest(url: URL(string: "\(baseApiUrl)/item/listall")!)
|
||||||
|
|
||||||
let data = try await performRequest(request: &request, requestName: #function)
|
let data = try await performRequest(request: &request, requestName: #function)
|
||||||
|
|
@ -257,7 +259,12 @@ public class Premiumize: OAuthDebridSource {
|
||||||
throw PMError.EmptyData
|
throw PMError.EmptyData
|
||||||
}
|
}
|
||||||
|
|
||||||
return rawResponse.files
|
// The "link" is the ID for Premiumize
|
||||||
|
let downloads = rawResponse.files.map { file in
|
||||||
|
DebridCloudDownload(downloadId: file.id, fileName: file.name, link: file.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
return downloads
|
||||||
}
|
}
|
||||||
|
|
||||||
func itemDetails(itemID: String) async throws -> ItemDetailsResponse {
|
func itemDetails(itemID: String) async throws -> ItemDetailsResponse {
|
||||||
|
|
@ -275,16 +282,25 @@ public class Premiumize: OAuthDebridSource {
|
||||||
return rawResponse
|
return rawResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteItem(itemID: String) async throws {
|
public func deleteDownload(downloadId: String) async throws {
|
||||||
var request = URLRequest(url: URL(string: "\(baseApiUrl)/item/delete")!)
|
var request = URLRequest(url: URL(string: "\(baseApiUrl)/item/delete")!)
|
||||||
request.httpMethod = "POST"
|
request.httpMethod = "POST"
|
||||||
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
|
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
|
||||||
|
|
||||||
var bodyComponents = URLComponents()
|
var bodyComponents = URLComponents()
|
||||||
bodyComponents.queryItems = [URLQueryItem(name: "id", value: itemID)]
|
bodyComponents.queryItems = [URLQueryItem(name: "id", value: downloadId)]
|
||||||
|
|
||||||
request.httpBody = bodyComponents.query?.data(using: .utf8)
|
request.httpBody = bodyComponents.query?.data(using: .utf8)
|
||||||
|
|
||||||
try await performRequest(request: &request, requestName: #function)
|
try await performRequest(request: &request, requestName: #function)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// No user torrents for Premiumize
|
||||||
|
public func getUserTorrents() async throws -> [DebridCloudTorrent] {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
public func deleteTorrent(torrentId: String) async throws {
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@ import Foundation
|
||||||
|
|
||||||
public class RealDebrid: PollingDebridSource {
|
public class RealDebrid: PollingDebridSource {
|
||||||
public let id = "RealDebrid"
|
public let id = "RealDebrid"
|
||||||
|
public let abbreviation = "RD"
|
||||||
|
public let website = "https://real-debrid.com"
|
||||||
public var authTask: Task<Void, Error>?
|
public var authTask: Task<Void, Error>?
|
||||||
|
|
||||||
let baseAuthUrl = "https://api.real-debrid.com/oauth/v2"
|
let baseAuthUrl = "https://api.real-debrid.com/oauth/v2"
|
||||||
|
|
@ -357,24 +359,6 @@ public class RealDebrid: PollingDebridSource {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets the user's torrent library
|
|
||||||
public func userTorrents() async throws -> [UserTorrentsResponse] {
|
|
||||||
var request = URLRequest(url: URL(string: "\(baseApiUrl)/torrents")!)
|
|
||||||
|
|
||||||
let data = try await performRequest(request: &request, requestName: #function)
|
|
||||||
let rawResponse = try jsonDecoder.decode([UserTorrentsResponse].self, from: data)
|
|
||||||
|
|
||||||
return rawResponse
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deletes a torrent download from RD
|
|
||||||
public func deleteTorrent(debridID: String) async throws {
|
|
||||||
var request = URLRequest(url: URL(string: "\(baseApiUrl)/torrents/delete/\(debridID)")!)
|
|
||||||
request.httpMethod = "DELETE"
|
|
||||||
|
|
||||||
try await performRequest(request: &request, requestName: #function)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Downloads link from selectFiles for playback
|
// Downloads link from selectFiles for playback
|
||||||
public func unrestrictLink(debridDownloadLink: String) async throws -> String {
|
public func unrestrictLink(debridDownloadLink: String) async throws -> String {
|
||||||
var request = URLRequest(url: URL(string: "\(baseApiUrl)/unrestrict/link")!)
|
var request = URLRequest(url: URL(string: "\(baseApiUrl)/unrestrict/link")!)
|
||||||
|
|
@ -392,18 +376,48 @@ public class RealDebrid: PollingDebridSource {
|
||||||
return rawResponse.download
|
return rawResponse.download
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Gets the user's torrent library
|
||||||
|
public func getUserTorrents() async throws -> [DebridCloudTorrent] {
|
||||||
|
var request = URLRequest(url: URL(string: "\(baseApiUrl)/torrents")!)
|
||||||
|
|
||||||
|
let data = try await performRequest(request: &request, requestName: #function)
|
||||||
|
let rawResponse = try jsonDecoder.decode([UserTorrentsResponse].self, from: data)
|
||||||
|
let torrents = rawResponse.map { response in
|
||||||
|
DebridCloudTorrent(
|
||||||
|
torrentId: response.id,
|
||||||
|
fileName: response.filename,
|
||||||
|
status: response.status,
|
||||||
|
hash: response.hash,
|
||||||
|
links: response.links
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return torrents
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deletes a torrent download from RD
|
||||||
|
public func deleteTorrent(torrentId: String) async throws {
|
||||||
|
var request = URLRequest(url: URL(string: "\(baseApiUrl)/torrents/delete/\(torrentId)")!)
|
||||||
|
request.httpMethod = "DELETE"
|
||||||
|
|
||||||
|
try await performRequest(request: &request, requestName: #function)
|
||||||
|
}
|
||||||
|
|
||||||
// Gets the user's downloads
|
// Gets the user's downloads
|
||||||
public func userDownloads() async throws -> [UserDownloadsResponse] {
|
public func getUserDownloads() async throws -> [DebridCloudDownload] {
|
||||||
var request = URLRequest(url: URL(string: "\(baseApiUrl)/downloads")!)
|
var request = URLRequest(url: URL(string: "\(baseApiUrl)/downloads")!)
|
||||||
|
|
||||||
let data = try await performRequest(request: &request, requestName: #function)
|
let data = try await performRequest(request: &request, requestName: #function)
|
||||||
let rawResponse = try jsonDecoder.decode([UserDownloadsResponse].self, from: data)
|
let rawResponse = try jsonDecoder.decode([UserDownloadsResponse].self, from: data)
|
||||||
|
let downloads = rawResponse.map { response in
|
||||||
|
DebridCloudDownload(downloadId: response.id, fileName: response.filename, link: response.download)
|
||||||
|
}
|
||||||
|
|
||||||
return rawResponse
|
return downloads
|
||||||
}
|
}
|
||||||
|
|
||||||
public func deleteDownload(debridID: String) async throws {
|
public func deleteDownload(downloadId: String) async throws {
|
||||||
var request = URLRequest(url: URL(string: "\(baseApiUrl)/downloads/delete/\(debridID)")!)
|
var request = URLRequest(url: URL(string: "\(baseApiUrl)/downloads/delete/\(downloadId)")!)
|
||||||
request.httpMethod = "DELETE"
|
request.httpMethod = "DELETE"
|
||||||
|
|
||||||
try await performRequest(request: &request, requestName: #function)
|
try await performRequest(request: &request, requestName: #function)
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public struct DebridIA: Sendable, Hashable {
|
public struct DebridIA: Hashable, Sendable {
|
||||||
let magnet: Magnet
|
let magnet: Magnet
|
||||||
let expiryTimeStamp: Double
|
let expiryTimeStamp: Double
|
||||||
var files: [DebridIAFile]
|
var files: [DebridIAFile]
|
||||||
|
|
@ -27,4 +27,16 @@ public struct DebridIAFile: Hashable, Sendable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct DebridCloudFile {}
|
public struct DebridCloudDownload: Hashable, Sendable {
|
||||||
|
let downloadId: String
|
||||||
|
let fileName: String
|
||||||
|
let link: String
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct DebridCloudTorrent: Hashable, Sendable {
|
||||||
|
let torrentId: String
|
||||||
|
let fileName: String
|
||||||
|
let status: String
|
||||||
|
let hash: String
|
||||||
|
let links: [String]
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ import Foundation
|
||||||
public protocol DebridSource {
|
public protocol DebridSource {
|
||||||
// ID of the service
|
// ID of the service
|
||||||
var id: String { get }
|
var id: String { get }
|
||||||
|
var abbreviation: String { get }
|
||||||
|
var website: String { get }
|
||||||
|
|
||||||
// Common authentication functions
|
// Common authentication functions
|
||||||
func setApiKey(_ key: String) -> Bool
|
func setApiKey(_ key: String) -> Bool
|
||||||
|
|
@ -18,6 +20,14 @@ public protocol DebridSource {
|
||||||
// Fetches a download link from a source
|
// Fetches a download link from a source
|
||||||
// Include the instant availability information with the args
|
// Include the instant availability information with the args
|
||||||
func getDownloadLink(magnet: Magnet, ia: DebridIA?, iaFile: DebridIAFile?) async throws -> String
|
func getDownloadLink(magnet: Magnet, ia: DebridIA?, iaFile: DebridIAFile?) async throws -> String
|
||||||
|
|
||||||
|
// Fetches cloud information from the service
|
||||||
|
func getUserDownloads() async throws -> [DebridCloudDownload]
|
||||||
|
func getUserTorrents() async throws -> [DebridCloudTorrent]
|
||||||
|
|
||||||
|
// Deletes information from the service
|
||||||
|
func deleteDownload(downloadId: String) async throws
|
||||||
|
func deleteTorrent(torrentId: String) async throws
|
||||||
}
|
}
|
||||||
|
|
||||||
public protocol PollingDebridSource: DebridSource {
|
public protocol PollingDebridSource: DebridSource {
|
||||||
|
|
|
||||||
|
|
@ -69,8 +69,8 @@ public class DebridManager: ObservableObject {
|
||||||
|
|
||||||
// TODO: Maybe make these generic?
|
// TODO: Maybe make these generic?
|
||||||
// RealDebrid cloud variables
|
// RealDebrid cloud variables
|
||||||
@Published var realDebridCloudTorrents: [RealDebrid.UserTorrentsResponse] = []
|
@Published var realDebridCloudTorrents: [DebridCloudTorrent] = []
|
||||||
@Published var realDebridCloudDownloads: [RealDebrid.UserDownloadsResponse] = []
|
@Published var realDebridCloudDownloads: [DebridCloudDownload] = []
|
||||||
var realDebridCloudTTL: Double = 0.0
|
var realDebridCloudTTL: Double = 0.0
|
||||||
|
|
||||||
// AllDebrid auth variables
|
// AllDebrid auth variables
|
||||||
|
|
@ -83,8 +83,8 @@ public class DebridManager: ObservableObject {
|
||||||
var selectedAllDebridFile: DebridIAFile?
|
var selectedAllDebridFile: DebridIAFile?
|
||||||
|
|
||||||
// AllDebrid cloud variables
|
// AllDebrid cloud variables
|
||||||
@Published var allDebridCloudMagnets: [AllDebrid.MagnetStatusData] = []
|
@Published var allDebridCloudMagnets: [DebridCloudTorrent] = []
|
||||||
@Published var allDebridCloudLinks: [AllDebrid.SavedLink] = []
|
@Published var allDebridCloudLinks: [DebridCloudDownload] = []
|
||||||
var allDebridCloudTTL: Double = 0.0
|
var allDebridCloudTTL: Double = 0.0
|
||||||
|
|
||||||
// Premiumize auth variables
|
// Premiumize auth variables
|
||||||
|
|
@ -97,7 +97,7 @@ public class DebridManager: ObservableObject {
|
||||||
var selectedPremiumizeFile: DebridIAFile?
|
var selectedPremiumizeFile: DebridIAFile?
|
||||||
|
|
||||||
// Premiumize cloud variables
|
// Premiumize cloud variables
|
||||||
@Published var premiumizeCloudItems: [Premiumize.UserItem] = []
|
@Published var premiumizeCloudItems: [DebridCloudDownload] = []
|
||||||
var premiumizeCloudTTL: Double = 0.0
|
var premiumizeCloudTTL: Double = 0.0
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
|
|
@ -651,8 +651,8 @@ public class DebridManager: ObservableObject {
|
||||||
public func fetchRdCloud(bypassTTL: Bool = false) async {
|
public func fetchRdCloud(bypassTTL: Bool = false) async {
|
||||||
if bypassTTL || Date().timeIntervalSince1970 > realDebridCloudTTL {
|
if bypassTTL || Date().timeIntervalSince1970 > realDebridCloudTTL {
|
||||||
do {
|
do {
|
||||||
realDebridCloudTorrents = try await realDebrid.userTorrents()
|
realDebridCloudTorrents = try await realDebrid.getUserTorrents()
|
||||||
realDebridCloudDownloads = try await realDebrid.userDownloads()
|
realDebridCloudDownloads = try await realDebrid.getUserDownloads()
|
||||||
|
|
||||||
// 5 minutes
|
// 5 minutes
|
||||||
realDebridCloudTTL = Date().timeIntervalSince1970 + 300
|
realDebridCloudTTL = Date().timeIntervalSince1970 + 300
|
||||||
|
|
@ -664,7 +664,7 @@ public class DebridManager: ObservableObject {
|
||||||
|
|
||||||
func deleteRdDownload(downloadID: String) async {
|
func deleteRdDownload(downloadID: String) async {
|
||||||
do {
|
do {
|
||||||
try await realDebrid.deleteDownload(debridID: downloadID)
|
try await realDebrid.deleteDownload(downloadId: downloadID)
|
||||||
|
|
||||||
// Bypass TTL to get current RD values
|
// Bypass TTL to get current RD values
|
||||||
await fetchRdCloud(bypassTTL: true)
|
await fetchRdCloud(bypassTTL: true)
|
||||||
|
|
@ -676,7 +676,7 @@ public class DebridManager: ObservableObject {
|
||||||
func deleteRdTorrent(torrentID: String? = nil, presentError: Bool = true) async {
|
func deleteRdTorrent(torrentID: String? = nil, presentError: Bool = true) async {
|
||||||
do {
|
do {
|
||||||
if let torrentID {
|
if let torrentID {
|
||||||
try await realDebrid.deleteTorrent(debridID: torrentID)
|
try await realDebrid.deleteTorrent(torrentId: torrentID)
|
||||||
} else {
|
} else {
|
||||||
throw RealDebrid.RDError.FailedRequest(description: "No torrent ID was provided")
|
throw RealDebrid.RDError.FailedRequest(description: "No torrent ID was provided")
|
||||||
}
|
}
|
||||||
|
|
@ -688,7 +688,7 @@ public class DebridManager: ObservableObject {
|
||||||
func checkRdUserDownloads(userTorrentLink: String) async -> String? {
|
func checkRdUserDownloads(userTorrentLink: String) async -> String? {
|
||||||
do {
|
do {
|
||||||
let existingLinks = realDebridCloudDownloads.first { $0.link == userTorrentLink }
|
let existingLinks = realDebridCloudDownloads.first { $0.link == userTorrentLink }
|
||||||
if let existingLink = existingLinks?.download {
|
if let existingLink = existingLinks?.fileName {
|
||||||
return existingLink
|
return existingLink
|
||||||
} else {
|
} else {
|
||||||
return try await realDebrid.unrestrictLink(debridDownloadLink: userTorrentLink)
|
return try await realDebrid.unrestrictLink(debridDownloadLink: userTorrentLink)
|
||||||
|
|
@ -761,8 +761,8 @@ public class DebridManager: ObservableObject {
|
||||||
public func fetchAdCloud(bypassTTL: Bool = false) async {
|
public func fetchAdCloud(bypassTTL: Bool = false) async {
|
||||||
if bypassTTL || Date().timeIntervalSince1970 > allDebridCloudTTL {
|
if bypassTTL || Date().timeIntervalSince1970 > allDebridCloudTTL {
|
||||||
do {
|
do {
|
||||||
allDebridCloudMagnets = try await allDebrid.userMagnets()
|
allDebridCloudMagnets = try await allDebrid.getUserTorrents()
|
||||||
allDebridCloudLinks = try await allDebrid.savedLinks()
|
allDebridCloudLinks = try await allDebrid.getUserDownloads()
|
||||||
|
|
||||||
// 5 minutes
|
// 5 minutes
|
||||||
allDebridCloudTTL = Date().timeIntervalSince1970 + 300
|
allDebridCloudTTL = Date().timeIntervalSince1970 + 300
|
||||||
|
|
@ -774,7 +774,7 @@ public class DebridManager: ObservableObject {
|
||||||
|
|
||||||
func deleteAdLink(link: String) async {
|
func deleteAdLink(link: String) async {
|
||||||
do {
|
do {
|
||||||
try await allDebrid.deleteLink(link: link)
|
try await allDebrid.deleteDownload(downloadId: link)
|
||||||
|
|
||||||
await fetchAdCloud(bypassTTL: true)
|
await fetchAdCloud(bypassTTL: true)
|
||||||
} catch {
|
} catch {
|
||||||
|
|
@ -782,9 +782,9 @@ public class DebridManager: ObservableObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteAdMagnet(magnetId: Int) async {
|
func deleteAdMagnet(magnetId: String) async {
|
||||||
do {
|
do {
|
||||||
try await allDebrid.deleteMagnet(magnetId: magnetId)
|
try await allDebrid.deleteTorrent(torrentId: magnetId)
|
||||||
|
|
||||||
await fetchAdCloud(bypassTTL: true)
|
await fetchAdCloud(bypassTTL: true)
|
||||||
} catch {
|
} catch {
|
||||||
|
|
@ -817,7 +817,7 @@ public class DebridManager: ObservableObject {
|
||||||
public func fetchPmCloud(bypassTTL: Bool = false) async {
|
public func fetchPmCloud(bypassTTL: Bool = false) async {
|
||||||
if bypassTTL || Date().timeIntervalSince1970 > premiumizeCloudTTL {
|
if bypassTTL || Date().timeIntervalSince1970 > premiumizeCloudTTL {
|
||||||
do {
|
do {
|
||||||
let userItems = try await premiumize.userItems()
|
let userItems = try await premiumize.getUserDownloads()
|
||||||
withAnimation {
|
withAnimation {
|
||||||
premiumizeCloudItems = userItems
|
premiumizeCloudItems = userItems
|
||||||
}
|
}
|
||||||
|
|
@ -835,7 +835,7 @@ public class DebridManager: ObservableObject {
|
||||||
|
|
||||||
public func deletePmItem(id: String) async {
|
public func deletePmItem(id: String) async {
|
||||||
do {
|
do {
|
||||||
try await premiumize.deleteItem(itemID: id)
|
try await premiumize.deleteDownload(downloadId: id)
|
||||||
|
|
||||||
// Bypass TTL to get current RD values
|
// Bypass TTL to get current RD values
|
||||||
await fetchPmCloud(bypassTTL: true)
|
await fetchPmCloud(bypassTTL: true)
|
||||||
|
|
|
||||||
|
|
@ -17,17 +17,17 @@ struct AllDebridCloudView: View {
|
||||||
var body: some View {
|
var body: some View {
|
||||||
DisclosureGroup("Links") {
|
DisclosureGroup("Links") {
|
||||||
ForEach(debridManager.allDebridCloudLinks.filter {
|
ForEach(debridManager.allDebridCloudLinks.filter {
|
||||||
searchText.isEmpty ? true : $0.filename.lowercased().contains(searchText.lowercased())
|
searchText.isEmpty ? true : $0.fileName.lowercased().contains(searchText.lowercased())
|
||||||
}, id: \.self) { downloadResponse in
|
}, id: \.self) { cloudDownload in
|
||||||
Button(downloadResponse.filename) {
|
Button(cloudDownload.fileName) {
|
||||||
navModel.resultFromCloud = true
|
navModel.resultFromCloud = true
|
||||||
navModel.selectedTitle = downloadResponse.filename
|
navModel.selectedTitle = cloudDownload.fileName
|
||||||
debridManager.downloadUrl = downloadResponse.link
|
debridManager.downloadUrl = cloudDownload.link
|
||||||
|
|
||||||
PersistenceController.shared.createHistory(
|
PersistenceController.shared.createHistory(
|
||||||
HistoryEntryJson(
|
HistoryEntryJson(
|
||||||
name: downloadResponse.filename,
|
name: cloudDownload.fileName,
|
||||||
url: downloadResponse.link,
|
url: cloudDownload.link,
|
||||||
source: DebridType.allDebrid.toString()
|
source: DebridType.allDebrid.toString()
|
||||||
),
|
),
|
||||||
performSave: true
|
performSave: true
|
||||||
|
|
@ -43,9 +43,9 @@ struct AllDebridCloudView: View {
|
||||||
}
|
}
|
||||||
.onDelete { offsets in
|
.onDelete { offsets in
|
||||||
for index in offsets {
|
for index in offsets {
|
||||||
if let savedLink = debridManager.allDebridCloudLinks[safe: index] {
|
if let cloudDownload = debridManager.allDebridCloudLinks[safe: index] {
|
||||||
Task {
|
Task {
|
||||||
await debridManager.deleteAdLink(link: savedLink.link)
|
await debridManager.deleteAdLink(link: cloudDownload.downloadId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -54,26 +54,26 @@ struct AllDebridCloudView: View {
|
||||||
|
|
||||||
DisclosureGroup("Magnets") {
|
DisclosureGroup("Magnets") {
|
||||||
ForEach(debridManager.allDebridCloudMagnets.filter {
|
ForEach(debridManager.allDebridCloudMagnets.filter {
|
||||||
searchText.isEmpty ? true : $0.filename.lowercased().contains(searchText.lowercased())
|
searchText.isEmpty ? true : $0.fileName.lowercased().contains(searchText.lowercased())
|
||||||
}, id: \.id) { magnet in
|
}, id: \.self) { cloudTorrent in
|
||||||
Button {
|
Button {
|
||||||
if magnet.status == "Ready", !magnet.links.isEmpty {
|
if cloudTorrent.status == "Ready", !cloudTorrent.links.isEmpty {
|
||||||
navModel.resultFromCloud = true
|
navModel.resultFromCloud = true
|
||||||
navModel.selectedTitle = magnet.filename
|
navModel.selectedTitle = cloudTorrent.fileName
|
||||||
|
|
||||||
var historyInfo = HistoryEntryJson(
|
var historyInfo = HistoryEntryJson(
|
||||||
name: magnet.filename,
|
name: cloudTorrent.fileName,
|
||||||
source: DebridType.allDebrid.toString()
|
source: DebridType.allDebrid.toString()
|
||||||
)
|
)
|
||||||
|
|
||||||
Task {
|
Task {
|
||||||
if magnet.links.count == 1 {
|
if cloudTorrent.links.count == 1 {
|
||||||
if let lockedLink = magnet.links[safe: 0]?.link {
|
if let torrentLink = cloudTorrent.links[safe: 0] {
|
||||||
await debridManager.fetchDebridDownload(magnet: nil, cloudInfo: lockedLink)
|
await debridManager.fetchDebridDownload(magnet: nil, cloudInfo: torrentLink)
|
||||||
|
|
||||||
if !debridManager.downloadUrl.isEmpty {
|
if !debridManager.downloadUrl.isEmpty {
|
||||||
historyInfo.url = debridManager.downloadUrl
|
historyInfo.url = debridManager.downloadUrl
|
||||||
PersistenceController.shared.createHistory(historyInfo, performSave: true)
|
PersistenceController.shared.createHistory(historyInfo, performSave: true)
|
||||||
|
|
||||||
pluginManager.runDefaultAction(
|
pluginManager.runDefaultAction(
|
||||||
urlString: debridManager.downloadUrl,
|
urlString: debridManager.downloadUrl,
|
||||||
navModel: navModel
|
navModel: navModel
|
||||||
|
|
@ -81,7 +81,7 @@ struct AllDebridCloudView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let magnet = Magnet(hash: magnet.hash, link: nil)
|
let magnet = Magnet(hash: cloudTorrent.hash, link: nil)
|
||||||
|
|
||||||
// Do not clear old IA values
|
// Do not clear old IA values
|
||||||
await debridManager.populateDebridIA([magnet])
|
await debridManager.populateDebridIA([magnet])
|
||||||
|
|
@ -93,27 +93,29 @@ struct AllDebridCloudView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} label: {
|
} label: {
|
||||||
VStack(alignment: .leading, spacing: 10) {
|
VStack(alignment: .leading, spacing: 10) {
|
||||||
Text(magnet.filename)
|
Text(cloudTorrent.fileName)
|
||||||
|
.font(.callout)
|
||||||
|
.fixedSize(horizontal: false, vertical: true)
|
||||||
|
.lineLimit(4)
|
||||||
|
|
||||||
HStack {
|
HStack {
|
||||||
Text(magnet.status)
|
Text(cloudTorrent.status.capitalizingFirstLetter())
|
||||||
Spacer()
|
Spacer()
|
||||||
DebridLabelView(cloudLinks: magnet.links.map(\.link))
|
DebridLabelView(cloudLinks: cloudTorrent.links)
|
||||||
}
|
}
|
||||||
.font(.caption)
|
.font(.caption)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.disabledAppearance(navModel.currentChoiceSheet != nil, dimmedOpacity: 0.9, animation: .easeOut(duration: 0.2))
|
.disabledAppearance(navModel.currentChoiceSheet != nil, dimmedOpacity: 0.7, animation: .easeOut(duration: 0.2))
|
||||||
.tint(.primary)
|
.tint(.primary)
|
||||||
}
|
}
|
||||||
.onDelete { offsets in
|
.onDelete { offsets in
|
||||||
for index in offsets {
|
for index in offsets {
|
||||||
if let magnet = debridManager.allDebridCloudMagnets[safe: index] {
|
if let cloudTorrent = debridManager.allDebridCloudMagnets[safe: index] {
|
||||||
Task {
|
Task {
|
||||||
await debridManager.deleteAdMagnet(magnetId: magnet.id)
|
await debridManager.deleteAdMagnet(magnetId: cloudTorrent.torrentId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,20 +17,20 @@ struct PremiumizeCloudView: View {
|
||||||
var body: some View {
|
var body: some View {
|
||||||
DisclosureGroup("Items") {
|
DisclosureGroup("Items") {
|
||||||
ForEach(debridManager.premiumizeCloudItems.filter {
|
ForEach(debridManager.premiumizeCloudItems.filter {
|
||||||
searchText.isEmpty ? true : $0.name.lowercased().contains(searchText.lowercased())
|
searchText.isEmpty ? true : $0.fileName.lowercased().contains(searchText.lowercased())
|
||||||
}, id: \.id) { item in
|
}, id: \.self) { cloudDownload in
|
||||||
Button(item.name) {
|
Button(cloudDownload.fileName) {
|
||||||
Task {
|
Task {
|
||||||
navModel.resultFromCloud = true
|
navModel.resultFromCloud = true
|
||||||
navModel.selectedTitle = item.name
|
navModel.selectedTitle = cloudDownload.fileName
|
||||||
|
|
||||||
await debridManager.fetchDebridDownload(magnet: nil, cloudInfo: item.id)
|
await debridManager.fetchDebridDownload(magnet: nil, cloudInfo: cloudDownload.downloadId)
|
||||||
|
|
||||||
if !debridManager.downloadUrl.isEmpty {
|
if !debridManager.downloadUrl.isEmpty {
|
||||||
PersistenceController.shared.createHistory(
|
PersistenceController.shared.createHistory(
|
||||||
HistoryEntryJson(
|
HistoryEntryJson(
|
||||||
name: item.name,
|
name: cloudDownload.fileName,
|
||||||
url: debridManager.downloadUrl,
|
url: cloudDownload.link,
|
||||||
source: DebridType.premiumize.toString()
|
source: DebridType.premiumize.toString()
|
||||||
),
|
),
|
||||||
performSave: true
|
performSave: true
|
||||||
|
|
@ -48,9 +48,9 @@ struct PremiumizeCloudView: View {
|
||||||
}
|
}
|
||||||
.onDelete { offsets in
|
.onDelete { offsets in
|
||||||
for index in offsets {
|
for index in offsets {
|
||||||
if let item = debridManager.premiumizeCloudItems[safe: index] {
|
if let cloudDownload = debridManager.premiumizeCloudItems[safe: index] {
|
||||||
Task {
|
Task {
|
||||||
await debridManager.deletePmItem(id: item.id)
|
await debridManager.deletePmItem(id: cloudDownload.downloadId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,17 +18,17 @@ struct RealDebridCloudView: View {
|
||||||
Group {
|
Group {
|
||||||
DisclosureGroup("Downloads") {
|
DisclosureGroup("Downloads") {
|
||||||
ForEach(debridManager.realDebridCloudDownloads.filter {
|
ForEach(debridManager.realDebridCloudDownloads.filter {
|
||||||
searchText.isEmpty ? true : $0.filename.lowercased().contains(searchText.lowercased())
|
searchText.isEmpty ? true : $0.fileName .lowercased().contains(searchText.lowercased())
|
||||||
}, id: \.self) { downloadResponse in
|
}, id: \.self) { cloudDownload in
|
||||||
Button(downloadResponse.filename) {
|
Button(cloudDownload.fileName) {
|
||||||
navModel.resultFromCloud = true
|
navModel.resultFromCloud = true
|
||||||
navModel.selectedTitle = downloadResponse.filename
|
navModel.selectedTitle = cloudDownload.fileName
|
||||||
debridManager.downloadUrl = downloadResponse.download
|
debridManager.downloadUrl = cloudDownload.link
|
||||||
|
|
||||||
PersistenceController.shared.createHistory(
|
PersistenceController.shared.createHistory(
|
||||||
HistoryEntryJson(
|
HistoryEntryJson(
|
||||||
name: downloadResponse.filename,
|
name: cloudDownload.fileName,
|
||||||
url: downloadResponse.download,
|
url: cloudDownload.link,
|
||||||
source: DebridType.realDebrid.toString()
|
source: DebridType.realDebrid.toString()
|
||||||
),
|
),
|
||||||
performSave: true
|
performSave: true
|
||||||
|
|
@ -44,9 +44,9 @@ struct RealDebridCloudView: View {
|
||||||
}
|
}
|
||||||
.onDelete { offsets in
|
.onDelete { offsets in
|
||||||
for index in offsets {
|
for index in offsets {
|
||||||
if let downloadResponse = debridManager.realDebridCloudDownloads[safe: index] {
|
if let cloudDownload = debridManager.realDebridCloudDownloads[safe: index] {
|
||||||
Task {
|
Task {
|
||||||
await debridManager.deleteRdDownload(downloadID: downloadResponse.id)
|
await debridManager.deleteRdDownload(downloadID: cloudDownload.downloadId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -55,21 +55,21 @@ struct RealDebridCloudView: View {
|
||||||
|
|
||||||
DisclosureGroup("Torrents") {
|
DisclosureGroup("Torrents") {
|
||||||
ForEach(debridManager.realDebridCloudTorrents.filter {
|
ForEach(debridManager.realDebridCloudTorrents.filter {
|
||||||
searchText.isEmpty ? true : $0.filename.lowercased().contains(searchText.lowercased())
|
searchText.isEmpty ? true : $0.fileName.lowercased().contains(searchText.lowercased())
|
||||||
}, id: \.self) { torrentResponse in
|
}, id: \.self) { cloudTorrent in
|
||||||
Button {
|
Button {
|
||||||
if torrentResponse.status == "downloaded", !torrentResponse.links.isEmpty {
|
if cloudTorrent.status == "downloaded", !cloudTorrent.links.isEmpty {
|
||||||
navModel.resultFromCloud = true
|
navModel.resultFromCloud = true
|
||||||
navModel.selectedTitle = torrentResponse.filename
|
navModel.selectedTitle = cloudTorrent.fileName
|
||||||
|
|
||||||
var historyInfo = HistoryEntryJson(
|
var historyInfo = HistoryEntryJson(
|
||||||
name: torrentResponse.filename,
|
name: cloudTorrent.fileName,
|
||||||
source: DebridType.realDebrid.toString()
|
source: DebridType.realDebrid.toString()
|
||||||
)
|
)
|
||||||
|
|
||||||
Task {
|
Task {
|
||||||
if torrentResponse.links.count == 1 {
|
if cloudTorrent.links.count == 1 {
|
||||||
if let torrentLink = torrentResponse.links[safe: 0] {
|
if let torrentLink = cloudTorrent.links[safe: 0] {
|
||||||
await debridManager.fetchDebridDownload(magnet: nil, cloudInfo: torrentLink)
|
await debridManager.fetchDebridDownload(magnet: nil, cloudInfo: torrentLink)
|
||||||
if !debridManager.downloadUrl.isEmpty {
|
if !debridManager.downloadUrl.isEmpty {
|
||||||
historyInfo.url = debridManager.downloadUrl
|
historyInfo.url = debridManager.downloadUrl
|
||||||
|
|
@ -82,7 +82,7 @@ struct RealDebridCloudView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let magnet = Magnet(hash: torrentResponse.hash, link: nil)
|
let magnet = Magnet(hash: cloudTorrent.hash, link: nil)
|
||||||
|
|
||||||
// Do not clear old IA values
|
// Do not clear old IA values
|
||||||
await debridManager.populateDebridIA([magnet])
|
await debridManager.populateDebridIA([magnet])
|
||||||
|
|
@ -96,15 +96,15 @@ struct RealDebridCloudView: View {
|
||||||
}
|
}
|
||||||
} label: {
|
} label: {
|
||||||
VStack(alignment: .leading, spacing: 10) {
|
VStack(alignment: .leading, spacing: 10) {
|
||||||
Text(torrentResponse.filename)
|
Text(cloudTorrent.fileName)
|
||||||
.font(.callout)
|
.font(.callout)
|
||||||
.fixedSize(horizontal: false, vertical: true)
|
.fixedSize(horizontal: false, vertical: true)
|
||||||
.lineLimit(4)
|
.lineLimit(4)
|
||||||
|
|
||||||
HStack {
|
HStack {
|
||||||
Text(torrentResponse.status.capitalizingFirstLetter())
|
Text(cloudTorrent.status.capitalizingFirstLetter())
|
||||||
Spacer()
|
Spacer()
|
||||||
DebridLabelView(cloudLinks: torrentResponse.links)
|
DebridLabelView(cloudLinks: cloudTorrent.links)
|
||||||
}
|
}
|
||||||
.font(.caption)
|
.font(.caption)
|
||||||
}
|
}
|
||||||
|
|
@ -114,9 +114,9 @@ struct RealDebridCloudView: View {
|
||||||
}
|
}
|
||||||
.onDelete { offsets in
|
.onDelete { offsets in
|
||||||
for index in offsets {
|
for index in offsets {
|
||||||
if let torrentResponse = debridManager.realDebridCloudTorrents[safe: index] {
|
if let cloudTorrent = debridManager.realDebridCloudTorrents[safe: index] {
|
||||||
Task {
|
Task {
|
||||||
await debridManager.deleteRdTorrent(torrentID: torrentResponse.id)
|
await debridManager.deleteRdTorrent(torrentID: cloudTorrent.torrentId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue