Debrid: Add common functions for existing magnets/downloads

This fixes cloud magnet fetching and also doesn't duplicate magnets
inside the cloud service. Unrestricted links don't get duplicated,
so no need to check against those.

Signed-off-by: kingbri <bdashore3@proton.me>
This commit is contained in:
kingbri 2024-06-03 23:56:56 -04:00
parent 273403b711
commit 0caf8a8120
8 changed files with 88 additions and 94 deletions

View file

@ -181,10 +181,18 @@ public class AllDebrid: PollingDebridSource {
// 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)
public func getDownloadLink(magnet: Magnet, ia: DebridIA?, iaFile: DebridIAFile?, userTorrents: [DebridCloudTorrent] = []) async throws -> String {
let selectedMagnetId: String
if let existingMagnet = userTorrents.first(where: { $0.hash == magnet.hash && $0.status == "Ready" }) {
selectedMagnetId = existingMagnet.torrentId
} else {
let magnetId = try await addMagnet(magnet: magnet)
selectedMagnetId = String(magnetId)
}
let lockedLink = try await fetchMagnetStatus(
magnetId: magnetID,
magnetId: selectedMagnetId,
selectedIndex: iaFile?.fileId ?? 0
)
@ -221,9 +229,9 @@ public class AllDebrid: PollingDebridSource {
}
}
public func fetchMagnetStatus(magnetId: Int, selectedIndex: Int?) async throws -> String {
public func fetchMagnetStatus(magnetId: String, selectedIndex: Int?) async throws -> String {
let queryItems = [
URLQueryItem(name: "id", value: String(magnetId))
URLQueryItem(name: "id", value: magnetId)
]
var request = URLRequest(url: try buildRequestURL(urlString: "\(baseApiUrl)/magnet/status", queryItems: queryItems))
@ -315,6 +323,11 @@ public class AllDebrid: PollingDebridSource {
return downloads
}
// Not used
public func checkUserDownloads(link: String, userDownloads: [DebridCloudDownload]) async throws -> String? {
nil
}
// The downloadId is actually the download link
public func deleteDownload(downloadId: String) async throws {
let queryItems = [

View file

@ -251,7 +251,7 @@ public class Premiumize: OAuthDebridSource {
// MARK: - Downloading
// Wrapper function to fetch a DDL link from the API
public func getDownloadLink(magnet: Magnet, ia: DebridIA?, iaFile: DebridIAFile?) async throws -> String {
public func getDownloadLink(magnet: Magnet, ia: DebridIA?, iaFile: DebridIAFile?, userTorrents: [DebridCloudTorrent] = []) async throws -> String {
// Store the item in PM cloud for later use
try await createTransfer(magnet: magnet)
@ -316,6 +316,11 @@ public class Premiumize: OAuthDebridSource {
return rawResponse
}
public func checkUserDownloads(link: String, userDownloads: [DebridCloudDownload]) async throws -> String? {
// Link is the cloud item ID
try await itemDetails(itemID: link).link
}
public func deleteDownload(downloadId: String) async throws {
var request = URLRequest(url: URL(string: "\(baseApiUrl)/item/delete")!)
request.httpMethod = "POST"

View file

@ -295,14 +295,22 @@ public class RealDebrid: PollingDebridSource {
// 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)
public func getDownloadLink(magnet: Magnet, ia: DebridIA?, iaFile: DebridIAFile?, userTorrents: [DebridCloudTorrent] = []) async throws -> String {
let selectedMagnetId: String
try await selectFiles(debridID: selectedMagnetId, fileIds: iaFile?.batchIds ?? [])
// Don't queue a new job if the torrent already exists
if let existingTorrent = userTorrents.first(where: { $0.hash == magnet.hash && $0.status == "downloaded" }) {
selectedMagnetId = existingTorrent.torrentId
} else {
selectedMagnetId = try await addMagnet(magnet: magnet)
try await selectFiles(debridID: selectedMagnetId, fileIds: iaFile?.batchIds ?? [])
}
// RealDebrid has 1 as the first ID for a file
let torrentLink = try await torrentInfo(
debridID: selectedMagnetId,
selectedIndex: iaFile?.fileId ?? 0
selectedFileId: iaFile?.fileId ?? 1
)
let downloadLink = try await unrestrictLink(debridDownloadLink: torrentLink)
@ -351,13 +359,13 @@ public class RealDebrid: PollingDebridSource {
}
// Gets the info of a torrent from a given ID
public func torrentInfo(debridID: String, selectedIndex: Int?) async throws -> String {
public func torrentInfo(debridID: String, selectedFileId: Int?) async throws -> String {
var request = URLRequest(url: URL(string: "\(baseApiUrl)/torrents/info/\(debridID)")!)
let data = try await performRequest(request: &request, requestName: #function)
let rawResponse = try jsonDecoder.decode(TorrentInfoResponse.self, from: data)
let filteredFiles = rawResponse.files.filter { $0.selected == 1 }
let linkIndex = filteredFiles.firstIndex(where: { $0.id == selectedIndex })
let linkIndex = filteredFiles.firstIndex(where: { $0.id == selectedFileId })
// Let the user know if a torrent is downloading
if let torrentLink = rawResponse.links[safe: linkIndex ?? -1], rawResponse.status == "downloaded" {
@ -429,6 +437,11 @@ public class RealDebrid: PollingDebridSource {
return downloads
}
// Not used
public func checkUserDownloads(link: String, userDownloads: [DebridCloudDownload]) -> String? {
nil
}
public func deleteDownload(downloadId: String) async throws {
var request = URLRequest(url: URL(string: "\(baseApiUrl)/downloads/delete/\(downloadId)")!)
request.httpMethod = "DELETE"

View file

@ -21,14 +21,16 @@ public protocol DebridSource {
// Fetches a download link from a source
// Include the instant availability information with the args
func getDownloadLink(magnet: Magnet, ia: DebridIA?, iaFile: DebridIAFile?) async throws -> String
// Torrents also checked here
func getDownloadLink(magnet: Magnet, ia: DebridIA?, iaFile: DebridIAFile?, userTorrents: [DebridCloudTorrent]) async throws -> String
// Fetches cloud information from the service
// User downloads functions
func getUserDownloads() async throws -> [DebridCloudDownload]
func getUserTorrents() async throws -> [DebridCloudTorrent]
// Deletes information from the service
func checkUserDownloads(link: String, userDownloads: [DebridCloudDownload]) async throws -> String?
func deleteDownload(downloadId: String) async throws
// User torrent functions
func getUserTorrents() async throws -> [DebridCloudTorrent]
func deleteTorrent(torrentId: String) async throws
}

View file

@ -559,42 +559,21 @@ public class DebridManager: ObservableObject {
switch selectedDebridType {
case .realDebrid:
await fetchRdDownload(magnet: magnet, existingLink: cloudInfo)
await fetchRdDownload(magnet: magnet, cloudInfo: cloudInfo)
case .allDebrid:
await fetchAdDownload(magnet: magnet, existingLockedLink: cloudInfo)
await fetchAdDownload(magnet: magnet, cloudInfo: cloudInfo)
case .premiumize:
await fetchPmDownload(magnet: magnet, cloudItemId: cloudInfo)
await fetchPmDownload(magnet: magnet, cloudInfo: cloudInfo)
case .none:
break
}
}
func fetchRdDownload(magnet: Magnet?, existingLink: String?) async {
// If an existing link is passed in args, set it to that. Otherwise, find one from RD cloud.
/*
let torrentLink: String?
if let existingLink {
torrentLink = existingLink
} else {
// Bypass the TTL for up to date information
await fetchRdCloud(bypassTTL: true)
let existingTorrent = realDebridCloudTorrents.first { $0.hash == selectedRealDebridItem?.magnet.hash && $0.status == "downloaded" }
torrentLink = existingTorrent?.links[safe: selectedRealDebridFile?.batchFileIndex ?? 0]
}
*/
func fetchRdDownload(magnet: Magnet?, cloudInfo: String?) async {
do {
// If the links match from a user's downloads, no need to re-run a download
/*
if let torrentLink,
let downloadLink = await checkRdUserDownloads(userTorrentLink: torrentLink)
{
downloadUrl = downloadLink
} else */
if let magnet {
let downloadLink = try await realDebrid.getDownloadLink(
magnet: magnet, ia: selectedRealDebridItem, iaFile: selectedRealDebridFile
magnet: magnet, ia: selectedRealDebridItem, iaFile: selectedRealDebridFile, userTorrents: realDebridCloudTorrents
)
// Update the UI
@ -612,7 +591,9 @@ public class DebridManager: ObservableObject {
default:
await sendDebridError(error, prefix: "RealDebrid download error", cancelString: "Download cancelled")
// await deleteRdTorrent(torrentID: selectedRealDebridID, presentError: false)
if let torrentId = selectedRealDebridID {
try? await realDebrid.deleteTorrent(torrentId: torrentId)
}
}
logManager?.hideIndeterminateToast()
@ -685,32 +666,11 @@ public class DebridManager: ObservableObject {
}
}
func fetchAdDownload(magnet: Magnet?, existingLockedLink: String?) async {
// If an existing link is passed in args, set it to that. Otherwise, find one from AD cloud.
/*
let lockedLink: String?
if let existingLockedLink {
lockedLink = existingLockedLink
} else {
// Bypass the TTL for up to date information
await fetchAdCloud(bypassTTL: true)
let existingMagnet = allDebridCloudMagnets.first { $0.hash == selectedAllDebridItem?.magnet.hash && $0.status == "Ready" }
lockedLink = existingMagnet?.links[safe: selectedAllDebridFile?.fileId ?? 0]?.link
}
*/
func fetchAdDownload(magnet: Magnet?, cloudInfo: String?) async {
do {
/*
if let lockedLink,
let unlockedLink = await checkAdUserLinks(lockedLink: lockedLink)
{
downloadUrl = unlockedLink
} else if let magnet {
*/
if let magnet {
let downloadLink = try await allDebrid.getDownloadLink(
magnet: magnet, ia: selectedAllDebridItem, iaFile: selectedAllDebridFile
magnet: magnet, ia: selectedAllDebridItem, iaFile: selectedAllDebridFile, userTorrents: allDebridCloudMagnets
)
// Update UI
@ -777,11 +737,14 @@ public class DebridManager: ObservableObject {
}
}
func fetchPmDownload(magnet: Magnet?, cloudItemId: String? = nil) async {
func fetchPmDownload(magnet: Magnet?, cloudInfo: String? = nil) async {
do {
if let cloudItemId {
downloadUrl = try await premiumize.itemDetails(itemID: cloudItemId).link
} else if let magnet {
if let cloudInfo {
downloadUrl = try await premiumize.checkUserDownloads(link: cloudInfo, userDownloads: premiumizeCloudItems) ?? ""
return
}
if let magnet {
let downloadLink = try await premiumize.getDownloadLink(
magnet: magnet, ia: selectedPremiumizeItem, iaFile: selectedPremiumizeFile
)

View file

@ -67,9 +67,14 @@ struct AllDebridCloudView: View {
)
Task {
if cloudTorrent.links.count == 1 {
if let torrentLink = cloudTorrent.links[safe: 0] {
await debridManager.fetchDebridDownload(magnet: nil, cloudInfo: torrentLink)
let magnet = Magnet(hash: cloudTorrent.hash, link: nil)
await debridManager.populateDebridIA([magnet])
if debridManager.selectDebridResult(magnet: magnet) {
// Is this a batch?
if cloudTorrent.links.count == 1 {
await debridManager.fetchDebridDownload(magnet: magnet)
if !debridManager.downloadUrl.isEmpty {
historyInfo.url = debridManager.downloadUrl
PersistenceController.shared.createHistory(historyInfo, performSave: true)
@ -79,14 +84,8 @@ struct AllDebridCloudView: View {
navModel: navModel
)
}
}
} else {
let magnet = Magnet(hash: cloudTorrent.hash, link: nil)
// Do not clear old IA values
await debridManager.populateDebridIA([magnet])
if debridManager.selectDebridResult(magnet: magnet) {
} else {
navModel.selectedMagnet = magnet
navModel.selectedHistoryInfo = historyInfo
navModel.currentChoiceSheet = .batch
}

View file

@ -68,9 +68,14 @@ struct RealDebridCloudView: View {
)
Task {
if cloudTorrent.links.count == 1 {
if let torrentLink = cloudTorrent.links[safe: 0] {
await debridManager.fetchDebridDownload(magnet: nil, cloudInfo: torrentLink)
let magnet = Magnet(hash: cloudTorrent.hash, link: nil)
await debridManager.populateDebridIA([magnet])
if debridManager.selectDebridResult(magnet: magnet) {
// Is this a batch?
if cloudTorrent.links.count == 1 {
await debridManager.fetchDebridDownload(magnet: magnet)
if !debridManager.downloadUrl.isEmpty {
historyInfo.url = debridManager.downloadUrl
PersistenceController.shared.createHistory(historyInfo, performSave: true)
@ -80,14 +85,8 @@ struct RealDebridCloudView: View {
navModel: navModel
)
}
}
} else {
let magnet = Magnet(hash: cloudTorrent.hash, link: nil)
// Do not clear old IA values
await debridManager.populateDebridIA([magnet])
if debridManager.selectDebridResult(magnet: magnet) {
} else {
navModel.selectedMagnet = magnet
navModel.selectedHistoryInfo = historyInfo
navModel.currentChoiceSheet = .batch
}

View file

@ -85,7 +85,7 @@ struct BatchChoiceView: View {
// Common function to communicate betwen VMs and queue/display a download
func queueCommonDownload(fileName: String) {
debridManager.currentDebridTask = Task {
await debridManager.fetchDebridDownload(magnet: navModel.resultFromCloud ? nil : navModel.selectedMagnet)
await debridManager.fetchDebridDownload(magnet: navModel.selectedMagnet)
if !debridManager.downloadUrl.isEmpty {
try? await Task.sleep(seconds: 1)