Debrid: Add split for download and unrestrict

Some debrid services aren't "rich", which means that they don't
broadcast whether an instantly available torrent is a batch or a
single file. This results in all torrents either having the green
badge or red badge based on what hash is given.

However, batches need to intercept the download itself which requires
the download function to be split into download and unrestrict. In
between, there's room for the batch sheet to act.

Signed-off-by: kingbri <bdashore3@proton.me>
This commit is contained in:
kingbri 2024-06-12 23:55:12 -04:00
parent e1eca593f3
commit 4beb953596
9 changed files with 164 additions and 81 deletions

View file

@ -12,6 +12,9 @@
0C03EB72296F619900162E9A /* PluginList+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C03EB70296F619900162E9A /* PluginList+CoreDataProperties.swift */; };
0C0755C6293424A200ECA142 /* DebridLabelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C0755C5293424A200ECA142 /* DebridLabelView.swift */; };
0C0755C8293425B500ECA142 /* DebridManagerModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C0755C7293425B500ECA142 /* DebridManagerModels.swift */; };
0C07C6002C19FEBF00808A46 /* OffCloudWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C07C5FF2C19FEBF00808A46 /* OffCloudWrapper.swift */; };
0C07C6022C1A016B00808A46 /* OffCloudModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C07C6012C1A016B00808A46 /* OffCloudModels.swift */; };
0C07C6042C1A859B00808A46 /* FormDataBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C07C6032C1A859B00808A46 /* FormDataBody.swift */; };
0C0974B029CCAAAF006DE7A3 /* OperatingSystemVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C0974AF29CCAAAF006DE7A3 /* OperatingSystemVersion.swift */; };
0C0D50E5288DFE7F0035ECC8 /* SourceModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C0D50E4288DFE7F0035ECC8 /* SourceModels.swift */; };
0C0D50E7288DFF850035ECC8 /* PluginAggregateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C0D50E6288DFF850035ECC8 /* PluginAggregateView.swift */; };
@ -94,6 +97,8 @@
0C84FCE729E4B61A00B0DFE4 /* FilterModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C84FCE629E4B61A00B0DFE4 /* FilterModels.swift */; };
0C84FCE929E5ADEF00B0DFE4 /* FilterAmountLabelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C84FCE829E5ADEF00B0DFE4 /* FilterAmountLabelView.swift */; };
0C871BDF29994D9D005279AC /* FilterLabelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C871BDE29994D9D005279AC /* FilterLabelView.swift */; };
0C890E492C188808003B17B5 /* TorBoxWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C890E482C188808003B17B5 /* TorBoxWrapper.swift */; };
0C890E4B2C188FA7003B17B5 /* TorBoxModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C890E4A2C188FA7003B17B5 /* TorBoxModels.swift */; };
0C8AE2482C0FFB6600701675 /* Store.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C8AE2472C0FFB6600701675 /* Store.swift */; };
0C8DC35229CE287E008A83AD /* PluginInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C8DC35129CE287E008A83AD /* PluginInfoView.swift */; };
0C8DC35429CE2AB5008A83AD /* SourceSettingsBaseUrlView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C8DC35329CE2AB5008A83AD /* SourceSettingsBaseUrlView.swift */; };
@ -167,6 +172,9 @@
0C03EB70296F619900162E9A /* PluginList+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PluginList+CoreDataProperties.swift"; sourceTree = "<group>"; };
0C0755C5293424A200ECA142 /* DebridLabelView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebridLabelView.swift; sourceTree = "<group>"; };
0C0755C7293425B500ECA142 /* DebridManagerModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebridManagerModels.swift; sourceTree = "<group>"; };
0C07C5FF2C19FEBF00808A46 /* OffCloudWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OffCloudWrapper.swift; sourceTree = "<group>"; };
0C07C6012C1A016B00808A46 /* OffCloudModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OffCloudModels.swift; sourceTree = "<group>"; };
0C07C6032C1A859B00808A46 /* FormDataBody.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormDataBody.swift; sourceTree = "<group>"; };
0C0974AF29CCAAAF006DE7A3 /* OperatingSystemVersion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OperatingSystemVersion.swift; sourceTree = "<group>"; };
0C0D50E4288DFE7F0035ECC8 /* SourceModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SourceModels.swift; sourceTree = "<group>"; };
0C0D50E6288DFF850035ECC8 /* PluginAggregateView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PluginAggregateView.swift; sourceTree = "<group>"; };
@ -244,6 +252,8 @@
0C84FCE629E4B61A00B0DFE4 /* FilterModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilterModels.swift; sourceTree = "<group>"; };
0C84FCE829E5ADEF00B0DFE4 /* FilterAmountLabelView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilterAmountLabelView.swift; sourceTree = "<group>"; };
0C871BDE29994D9D005279AC /* FilterLabelView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilterLabelView.swift; sourceTree = "<group>"; };
0C890E482C188808003B17B5 /* TorBoxWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TorBoxWrapper.swift; sourceTree = "<group>"; };
0C890E4A2C188FA7003B17B5 /* TorBoxModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TorBoxModels.swift; sourceTree = "<group>"; };
0C8AE2472C0FFB6600701675 /* Store.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Store.swift; sourceTree = "<group>"; };
0C8DC35129CE287E008A83AD /* PluginInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PluginInfoView.swift; sourceTree = "<group>"; };
0C8DC35329CE2AB5008A83AD /* SourceSettingsBaseUrlView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SourceSettingsBaseUrlView.swift; sourceTree = "<group>"; };
@ -410,6 +420,8 @@
0C3E00D7296F5B9A00ECECB2 /* PluginModels.swift */,
0C6771F929B3D1AE005D38D2 /* KodiModels.swift */,
0C1A3E5129C8A7F500DA9730 /* SettingsModels.swift */,
0C890E4A2C188FA7003B17B5 /* TorBoxModels.swift */,
0C07C6012C1A016B00808A46 /* OffCloudModels.swift */,
);
path = Models;
sourceTree = "<group>";
@ -463,6 +475,7 @@
0C1A3E5529C9488C00DA9730 /* CodableWrapper.swift */,
0CD0265629FEFBF900A83D25 /* FerriteKeychain.swift */,
0C8AE2472C0FFB6600701675 /* Store.swift */,
0C07C6032C1A859B00808A46 /* FormDataBody.swift */,
);
path = Utils;
sourceTree = "<group>";
@ -661,6 +674,8 @@
0C422E7D293542EA00486D65 /* PremiumizeWrapper.swift */,
0CA148D0288903F000DE2211 /* RealDebridWrapper.swift */,
0C6771F329B3B4FD005D38D2 /* KodiWrapper.swift */,
0C890E482C188808003B17B5 /* TorBoxWrapper.swift */,
0C07C5FF2C19FEBF00808A46 /* OffCloudWrapper.swift */,
);
path = API;
sourceTree = "<group>";
@ -829,9 +844,11 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0C07C6042C1A859B00808A46 /* FormDataBody.swift in Sources */,
0C7ED14328D65518009E29AD /* FileManager.swift in Sources */,
0C03EB71296F619900162E9A /* PluginList+CoreDataClass.swift in Sources */,
0C6771FA29B3D1AE005D38D2 /* KodiModels.swift in Sources */,
0C07C6002C19FEBF00808A46 /* OffCloudWrapper.swift in Sources */,
0C0D50E5288DFE7F0035ECC8 /* SourceModels.swift in Sources */,
0CB6516528C5A5D700DCA721 /* InlinedList.swift in Sources */,
0C8DC35429CE2AB5008A83AD /* SourceSettingsBaseUrlView.swift in Sources */,
@ -927,6 +944,7 @@
0C84FCE929E5ADEF00B0DFE4 /* FilterAmountLabelView.swift in Sources */,
0C10848B28BD9A38008F0BA6 /* SettingsAppVersionView.swift in Sources */,
0CA05457288EE58200850554 /* SettingsPluginListView.swift in Sources */,
0C07C6022C1A016B00808A46 /* OffCloudModels.swift in Sources */,
0C78041D28BFB3EA001E8CA3 /* String.swift in Sources */,
0C31133C28B1ABFA004DCB0D /* SourceJsonParser+CoreDataClass.swift in Sources */,
0CBC76FF288DAAD00054BE44 /* NavigationViewModel.swift in Sources */,
@ -940,6 +958,7 @@
0C6771F429B3B4FD005D38D2 /* KodiWrapper.swift in Sources */,
0C3E00D0296F4DB200ECECB2 /* ActionModels.swift in Sources */,
0C44E2AD28D51C63007711AE /* BackupManager.swift in Sources */,
0C890E4B2C188FA7003B17B5 /* TorBoxModels.swift in Sources */,
0C7075E429D374C50093DB2D /* Color.swift in Sources */,
0C8DC35229CE287E008A83AD /* PluginInfoView.swift in Sources */,
0C422E80293542F300486D65 /* PremiumizeModels.swift in Sources */,
@ -956,6 +975,7 @@
0CE1C4182981E8D700418F20 /* Plugin.swift in Sources */,
0CEC8AB2299B3B57007BFE8F /* LibraryPickerView.swift in Sources */,
0C6771F629B3B602005D38D2 /* SettingsKodiView.swift in Sources */,
0C890E492C188808003B17B5 /* TorBoxWrapper.swift in Sources */,
0CF1ABDC2C0C04B2009F6C26 /* Debrid.swift in Sources */,
0C84F4842895BFED0074B7C9 /* SourceHtmlParser+CoreDataClass.swift in Sources */,
0C32FB572890D1F2002BD219 /* ListRowViews.swift in Sources */,
@ -1035,6 +1055,7 @@
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_STRICT_CONCURRENCY = minimal;
};
name = Debug;
};
@ -1090,6 +1111,7 @@
SDKROOT = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
SWIFT_STRICT_CONCURRENCY = minimal;
VALIDATE_PRODUCT = YES;
};
name = Release;

View file

@ -214,7 +214,7 @@ class AllDebrid: PollingDebridSource, ObservableObject {
// MARK: - Downloading
// Wrapper function to fetch a download link from the API
func getDownloadLink(magnet: Magnet, ia: DebridIA?, iaFile: DebridIAFile?) async throws -> String {
func getRestrictedFile(magnet: Magnet, ia: DebridIA?, iaFile: DebridIAFile?) async throws -> (restrictedFile: DebridIAFile?, newIA: DebridIA?) {
let selectedMagnetId: String
if let existingMagnet = cloudTorrents.first(where: { $0.hash == magnet.hash && $0.status == "Ready" }) {
@ -229,10 +229,7 @@ class AllDebrid: PollingDebridSource, ObservableObject {
selectedIndex: iaFile?.fileId ?? 0
)
try await saveLink(link: lockedLink)
let downloadUrl = try await unlockLink(lockedLink: lockedLink)
return downloadUrl
return (lockedLink, nil)
}
// Adds a magnet link to the user's AD account
@ -262,7 +259,7 @@ class AllDebrid: PollingDebridSource, ObservableObject {
}
}
func fetchMagnetStatus(magnetId: String, selectedIndex: Int?) async throws -> String {
func fetchMagnetStatus(magnetId: String, selectedIndex: Int?) async throws -> DebridIAFile {
let queryItems = [
URLQueryItem(name: "id", value: magnetId)
]
@ -272,20 +269,21 @@ class AllDebrid: PollingDebridSource, ObservableObject {
let rawResponse = try jsonDecoder.decode(ADResponse<MagnetStatusResponse>.self, from: data).data
// Better to fetch no link at all than the wrong link
if let linkWrapper = rawResponse.magnets[safe: 0]?.links[safe: selectedIndex ?? -1] {
return linkWrapper.link
if let torrentFile = rawResponse.magnets[safe: 0]?.links[safe: selectedIndex ?? -1] {
return DebridIAFile(fileId: 0, name: torrentFile.filename, streamUrlString: torrentFile.link)
} else {
throw DebridError.EmptyTorrents
}
}
func unlockLink(lockedLink: String) async throws -> String {
// Known as unlockLink in AD's API
func unrestrictFile(_ restrictedFile: DebridIAFile) async throws -> String {
let queryItems = [
URLQueryItem(name: "link", value: lockedLink)
URLQueryItem(name: "link", value: restrictedFile.streamUrlString)
]
var request = URLRequest(url: try buildRequestURL(urlString: "\(baseApiUrl)/link/unlock", queryItems: queryItems))
let data = try await performRequest(request: &request, requestName: #function)
let data = try await performRequest(request: &request, requestName: "unlockLink")
let rawResponse = try jsonDecoder.decode(ADResponse<UnlockLinkResponse>.self, from: data).data
return rawResponse.link

View file

@ -277,20 +277,27 @@ class Premiumize: OAuthDebridSource, ObservableObject {
// MARK: - Downloading
// Wrapper function to fetch a DDL link from the API
func getDownloadLink(magnet: Magnet, ia: DebridIA?, iaFile: DebridIAFile?) async throws -> String {
func getRestrictedFile(magnet: Magnet, ia: DebridIA?, iaFile: DebridIAFile?) async throws -> (restrictedFile: DebridIAFile?, newIA: DebridIA?) {
// Store the item in PM cloud for later use
try await createTransfer(magnet: magnet)
if let iaFile, let streamUrlString = iaFile.streamUrlString {
return streamUrlString
} else if let premiumizeItem = ia, let firstFile = premiumizeItem.files[safe: 0], let streamUrlString = firstFile.streamUrlString {
return streamUrlString
if let iaFile {
return (iaFile, nil)
} else if let premiumizeItem = ia, let firstFile = premiumizeItem.files[safe: 0] {
return (firstFile, nil)
} else {
throw DebridError.FailedRequest(description: "Could not fetch your file from the Premiumize API")
}
}
func unrestrictFile(_ restrictedFile: DebridIAFile) async throws -> String {
guard let streamUrlString = restrictedFile.streamUrlString else {
throw DebridError.FailedRequest(description: "Could not get a streaming URL from the Premiumize API")
}
return streamUrlString
}
private func createTransfer(magnet: Magnet) async throws {
guard let magnetLink = magnet.link else {
throw DebridError.FailedRequest(description: "The magnet link is invalid")

View file

@ -273,62 +273,50 @@ class RealDebrid: PollingDebridSource, ObservableObject {
continue
}
// Is this a batch?
if data.rd.count > 1 || data.rd[0].count > 1 {
// Batch array
let batches = data.rd.map { fileDict in
let batchFiles: [RealDebrid.IABatchFile] = fileDict.map { key, value in
// Force unwrapped ID. Is safe because ID is guaranteed on a successful response
RealDebrid.IABatchFile(id: Int(key)!, fileName: value.filename)
}.sorted(by: { $0.id < $1.id })
// Handle files array
let batches = data.rd.map { fileDict in
let batchFiles: [RealDebrid.IABatchFile] = fileDict.map { key, value in
// Force unwrapped ID. Is safe because ID is guaranteed on a successful response
RealDebrid.IABatchFile(id: Int(key)!, fileName: value.filename)
}.sorted(by: { $0.id < $1.id })
return RealDebrid.IABatch(files: batchFiles)
}
return RealDebrid.IABatch(files: batchFiles)
}
var files: [DebridIAFile] = []
var files: [DebridIAFile] = []
for batch in batches {
let batchFileIds = batch.files.map(\.id)
for batch in batches {
let batchFileIds = batch.files.map(\.id)
for batchFile in batch.files {
if !files.contains(where: { $0.fileId == batchFile.id }) {
files.append(
DebridIAFile(
fileId: batchFile.id,
name: batchFile.fileName,
batchIds: batchFileIds
)
for batchFile in batch.files {
if !files.contains(where: { $0.fileId == batchFile.id }) {
files.append(
DebridIAFile(
fileId: batchFile.id,
name: batchFile.fileName,
batchIds: batchFileIds
)
}
)
}
}
// TTL: 5 minutes
IAValues.append(
DebridIA(
magnet: Magnet(hash: hash, link: nil),
source: id,
expiryTimeStamp: Date().timeIntervalSince1970 + 300,
files: files
)
)
} else {
IAValues.append(
DebridIA(
magnet: Magnet(hash: hash, link: nil),
source: id,
expiryTimeStamp: Date().timeIntervalSince1970 + 300,
files: []
)
)
}
// TTL: 5 minutes
IAValues.append(
DebridIA(
magnet: Magnet(hash: hash, link: nil),
source: id,
expiryTimeStamp: Date().timeIntervalSince1970 + 300,
files: files
)
)
}
}
// MARK: - Downloading
// Wrapper function to fetch a download link from the API
func getDownloadLink(magnet: Magnet, ia: DebridIA?, iaFile: DebridIAFile?) async throws -> String {
func getRestrictedFile(magnet: Magnet, ia: DebridIA?, iaFile: DebridIAFile?) async throws -> (restrictedFile: DebridIAFile?, newIA: DebridIA?) {
var selectedMagnetId = ""
do {
@ -342,13 +330,12 @@ class RealDebrid: PollingDebridSource, ObservableObject {
}
// RealDebrid has 1 as the first ID for a file
let torrentLink = try await torrentInfo(
let torrentFile = try await torrentInfo(
debridID: selectedMagnetId,
selectedFileId: iaFile?.fileId ?? 1
)
let downloadLink = try await unrestrictLink(debridDownloadLink: torrentLink)
return downloadLink
return (torrentFile, nil)
} catch {
if case DebridError.EmptyTorrents = error, !selectedMagnetId.isEmpty {
try? await deleteTorrent(torrentId: selectedMagnetId)
@ -401,7 +388,7 @@ class RealDebrid: PollingDebridSource, ObservableObject {
}
// Gets the info of a torrent from a given ID
func torrentInfo(debridID: String, selectedFileId: Int?) async throws -> String {
func torrentInfo(debridID: String, selectedFileId: Int?) async throws -> DebridIAFile {
var request = URLRequest(url: URL(string: "\(baseApiUrl)/torrents/info/\(debridID)")!)
let data = try await performRequest(request: &request, requestName: #function)
@ -411,7 +398,11 @@ class RealDebrid: PollingDebridSource, ObservableObject {
// Let the user know if a torrent is downloading
if let torrentLink = rawResponse.links[safe: linkIndex ?? -1], rawResponse.status == "downloaded" {
return torrentLink
return DebridIAFile(
fileId: 0,
name: rawResponse.filename,
streamUrlString: torrentLink
)
} else if rawResponse.status == "downloading" || rawResponse.status == "queued" {
throw DebridError.IsCaching
} else {
@ -420,13 +411,13 @@ class RealDebrid: PollingDebridSource, ObservableObject {
}
// Downloads link from selectFiles for playback
func unrestrictLink(debridDownloadLink: String) async throws -> String {
func unrestrictFile(_ restrictedFile: DebridIAFile) async throws -> String {
var request = URLRequest(url: URL(string: "\(baseApiUrl)/unrestrict/link")!)
request.httpMethod = "POST"
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
var bodyComponents = URLComponents()
bodyComponents.queryItems = [URLQueryItem(name: "link", value: debridDownloadLink)]
bodyComponents.queryItems = [URLQueryItem(name: "link", value: restrictedFile.streamUrlString)]
request.httpBody = bodyComponents.query?.data(using: .utf8)

View file

@ -39,7 +39,10 @@ protocol DebridSource: AnyObservableObject {
// Fetches a download link from a source
// Include the instant availability information with the args
// Torrents also checked here
func getDownloadLink(magnet: Magnet, ia: DebridIA?, iaFile: DebridIAFile?) async throws -> String
func getRestrictedFile(magnet: Magnet, ia: DebridIA?, iaFile: DebridIAFile?) async throws -> (restrictedFile: DebridIAFile?, newIA: DebridIA?)
// Unrestricts a locked file
func unrestrictFile(_ restrictedFile: DebridIAFile) async throws -> String
// User downloads functions
func getUserDownloads() async throws

View file

@ -39,6 +39,7 @@ class DebridManager: ObservableObject {
var selectedDebridItem: DebridIA?
var selectedDebridFile: DebridIAFile?
var requiresUnrestrict: Bool = false
// TODO: Figure out a way to remove this var
private var selectedOAuthDebridSource: OAuthDebridSource?
@ -167,6 +168,11 @@ class DebridManager: ObservableObject {
if let IAItem = selectedSource.IAValues.first(where: { magnetHash == $0.magnet.hash }) {
selectedDebridItem = IAItem
if IAItem.files.count == 1 {
selectedDebridFile = IAItem.files[safe: 0]
}
return true
} else {
logManager?.error("DebridManager: Could not find the associated \(selectedSource.id) entry for magnet hash \(magnetHash)")
@ -311,8 +317,8 @@ class DebridManager: ObservableObject {
// Cloudinfo is used for any extra information provided by debrid cloud
func fetchDebridDownload(magnet: Magnet?, cloudInfo: String? = nil) async {
defer {
currentDebridTask = nil
logManager?.hideIndeterminateToast()
currentDebridTask = nil
}
logManager?.updateIndeterminateToast("Loading content", cancelAction: {
@ -331,12 +337,24 @@ class DebridManager: ObservableObject {
}
if let magnet {
let downloadLink = try await debridSource.getDownloadLink(
let (restrictedFile, newIA) = try await debridSource.getRestrictedFile(
magnet: magnet, ia: selectedDebridItem, iaFile: selectedDebridFile
)
// Indicate that a link needs to be selected (batch)
if let newIA {
selectedDebridItem = newIA
requiresUnrestrict = true
return
}
guard let restrictedFile else {
throw DebridError.FailedRequest(description: "No files found for your request")
}
// Update the UI
downloadUrl = downloadLink
downloadUrl = try await debridSource.unrestrictFile(restrictedFile)
} else {
throw DebridError.FailedRequest(description: "Could not fetch your file from \(debridSource.id)'s cache or API")
}
@ -350,8 +368,34 @@ class DebridManager: ObservableObject {
default:
await sendDebridError(error, prefix: "\(debridSource.id) download error", cancelString: "Download cancelled")
}
}
return
}
func unrestrictDownload() async {
defer {
logManager?.hideIndeterminateToast()
requiresUnrestrict = false
}
logManager?.updateIndeterminateToast("Loading content", cancelAction: {
self.currentDebridTask?.cancel()
self.currentDebridTask = nil
})
guard let debridFile = selectedDebridFile, let debridSource = selectedDebridSource else {
logManager?.error("DebridManager: Could not unrestrict the selected debrid file.")
return
}
do {
let downloadLink = try await debridSource.unrestrictFile(debridFile)
downloadUrl = downloadLink
} catch {
await sendDebridError(error, prefix: "\(debridSource.id) unrestrict error", cancelString: "Unrestrict cancelled")
}
}

View file

@ -40,6 +40,14 @@ struct CloudTorrentView: View {
if cloudTorrent.links.count == 1 {
await debridManager.fetchDebridDownload(magnet: magnet)
// Bump to batch
if debridManager.requiresUnrestrict {
navModel.selectedHistoryInfo = historyInfo
navModel.currentChoiceSheet = .batch
return
}
if !debridManager.downloadUrl.isEmpty {
historyInfo.url = debridManager.downloadUrl
PersistenceController.shared.createHistory(historyInfo, performSave: true)

View file

@ -32,17 +32,23 @@ struct SearchResultButtonView: View {
case .full:
if debridManager.selectDebridResult(magnet: result.magnet) {
debridManager.currentDebridTask = Task {
let historyEntry = HistoryEntryJson(
name: result.title,
url: debridManager.downloadUrl,
source: result.source
)
await debridManager.fetchDebridDownload(magnet: result.magnet)
// Bump to batch
if debridManager.requiresUnrestrict {
navModel.selectedHistoryInfo = historyEntry
navModel.currentChoiceSheet = .batch
return
}
if !debridManager.downloadUrl.isEmpty {
PersistenceController.shared.createHistory(
HistoryEntryJson(
name: result.title,
url: debridManager.downloadUrl,
source: result.source
),
performSave: true
)
PersistenceController.shared.createHistory(historyEntry, performSave: true)
pluginManager.runDefaultAction(
urlString: debridManager.downloadUrl,
@ -133,9 +139,9 @@ struct SearchResultButtonView: View {
Button("Cancel", role: .cancel) {}
} message: {
Text(
"\(String(describing: debridManager.selectedDebridSource?.id)) is currently caching this file. " +
"\(debridManager.selectedDebridSource?.id ?? "Unknown Debrid") is currently caching this file. " +
"Would you like to delete it? \n\n" +
"Progress can be checked on the RealDebrid website."
"Progress can be checked on the \(debridManager.selectedDebridSource?.id ?? "Unknown Debrid") website."
)
}
.onReceive(NotificationCenter.default.publisher(for: .didDeleteBookmark)) { notification in

View file

@ -60,7 +60,11 @@ 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.selectedMagnet)
if debridManager.requiresUnrestrict {
await debridManager.unrestrictDownload()
} else {
await debridManager.fetchDebridDownload(magnet: navModel.selectedMagnet)
}
if !debridManager.downloadUrl.isEmpty {
try? await Task.sleep(seconds: 1)