mirror of
https://github.com/Ferrite-iOS/Ferrite.git
synced 2026-04-21 08:52:00 +00:00
Debrid: Make TorBox a rich service and fix cloud downloads
TorBox can now show if there's a batch before loading a file. Cloud downloads should check the server in case there's a different method to fetch a download link. Signed-off-by: kingbri <bdashore3@proton.me>
This commit is contained in:
parent
89367b72da
commit
d0728e1a9b
8 changed files with 58 additions and 54 deletions
|
|
@ -347,8 +347,8 @@ class AllDebrid: PollingDebridSource, ObservableObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not used
|
// Not used
|
||||||
func checkUserDownloads(link: String) async throws -> String? {
|
func checkUserDownloads(link: String) -> String? {
|
||||||
nil
|
link
|
||||||
}
|
}
|
||||||
|
|
||||||
// The downloadId is actually the download link
|
// The downloadId is actually the download link
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ class OffCloud: DebridSource, ObservableObject {
|
||||||
let id = "OffCloud"
|
let id = "OffCloud"
|
||||||
let abbreviation = "OC"
|
let abbreviation = "OC"
|
||||||
let website = "https://offcloud.com"
|
let website = "https://offcloud.com"
|
||||||
let description = "OffCloud is a debrid service that is used for downloads and media playback. " +
|
let description: String? = "OffCloud is a debrid service that is used for downloads and media playback. " +
|
||||||
"You must pay to access this service. \n\n" +
|
"You must pay to access this service. \n\n" +
|
||||||
"This service does not inform if a torrent is a batch before downloading."
|
"This service does not inform if a torrent is a batch before downloading."
|
||||||
|
|
||||||
|
|
@ -229,13 +229,13 @@ class OffCloud: DebridSource, ObservableObject {
|
||||||
return streamUrlString
|
return streamUrlString
|
||||||
}
|
}
|
||||||
|
|
||||||
func getUserDownloads() async throws {}
|
func getUserDownloads() {}
|
||||||
|
|
||||||
func checkUserDownloads(link: String) async throws -> String? {
|
func checkUserDownloads(link: String) -> String? {
|
||||||
nil
|
link
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteDownload(downloadId: String) async throws {}
|
func deleteDownload(downloadId: String) {}
|
||||||
|
|
||||||
func getUserTorrents() async throws {
|
func getUserTorrents() async throws {
|
||||||
var request = URLRequest(url: try buildRequestURL(urlString: "\(baseApiUrl)/cloud/history"))
|
var request = URLRequest(url: try buildRequestURL(urlString: "\(baseApiUrl)/cloud/history"))
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ class Premiumize: OAuthDebridSource, ObservableObject {
|
||||||
let id = "Premiumize"
|
let id = "Premiumize"
|
||||||
let abbreviation = "PM"
|
let abbreviation = "PM"
|
||||||
let website = "https://premiumize.me"
|
let website = "https://premiumize.me"
|
||||||
let description = "Premiumize is a debrid service that is used for downloads and media playback with seeding. " +
|
let description: String? = "Premiumize is a debrid service that is used for downloads and media playback with seeding. " +
|
||||||
"You must pay to access the service."
|
"You must pay to access the service."
|
||||||
|
|
||||||
@Published var authProcessing: Bool = false
|
@Published var authProcessing: Bool = false
|
||||||
|
|
@ -369,7 +369,7 @@ class Premiumize: OAuthDebridSource, ObservableObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
// No user torrents for Premiumize
|
// No user torrents for Premiumize
|
||||||
func getUserTorrents() async throws {}
|
func getUserTorrents() {}
|
||||||
|
|
||||||
func deleteTorrent(torrentId: String?) async throws {}
|
func deleteTorrent(torrentId: String?) {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -483,7 +483,7 @@ class RealDebrid: PollingDebridSource, ObservableObject {
|
||||||
|
|
||||||
// Not used
|
// Not used
|
||||||
func checkUserDownloads(link: String) -> String? {
|
func checkUserDownloads(link: String) -> String? {
|
||||||
nil
|
link
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteDownload(downloadId: String) async throws {
|
func deleteDownload(downloadId: String) async throws {
|
||||||
|
|
|
||||||
|
|
@ -17,9 +17,8 @@ class TorBox: DebridSource, ObservableObject {
|
||||||
let id = "TorBox"
|
let id = "TorBox"
|
||||||
let abbreviation = "TB"
|
let abbreviation = "TB"
|
||||||
let website = "https://torbox.app"
|
let website = "https://torbox.app"
|
||||||
let description = "TorBox is a debrid service that is used for downloads and media playback with seeding. " +
|
let description: String? = "TorBox is a debrid service that is used for downloads and media playback with seeding. " +
|
||||||
"Both free and paid plans are available. \n\n" +
|
"Both free and paid plans are available."
|
||||||
"This service does not inform if a torrent is a batch before downloading."
|
|
||||||
|
|
||||||
@Published var authProcessing: Bool = false
|
@Published var authProcessing: Bool = false
|
||||||
var isLoggedIn: Bool {
|
var isLoggedIn: Bool {
|
||||||
|
|
@ -109,6 +108,7 @@ class TorBox: DebridSource, ObservableObject {
|
||||||
var components = URLComponents(string: "\(baseApiUrl)/torrents/checkcached")!
|
var components = URLComponents(string: "\(baseApiUrl)/torrents/checkcached")!
|
||||||
components.queryItems = sendMagnets.map { URLQueryItem(name: "hash", value: $0.hash) }
|
components.queryItems = sendMagnets.map { URLQueryItem(name: "hash", value: $0.hash) }
|
||||||
components.queryItems?.append(URLQueryItem(name: "format", value: "list"))
|
components.queryItems?.append(URLQueryItem(name: "format", value: "list"))
|
||||||
|
components.queryItems?.append(URLQueryItem(name: "list_files", value: "true"))
|
||||||
|
|
||||||
guard let url = components.url else {
|
guard let url = components.url else {
|
||||||
throw DebridError.InvalidUrl
|
throw DebridError.InvalidUrl
|
||||||
|
|
@ -124,12 +124,21 @@ class TorBox: DebridSource, ObservableObject {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let availableHashes = iaObjects.map {
|
let availableHashes = iaObjects.map { iaObject in
|
||||||
DebridIA(
|
DebridIA(
|
||||||
magnet: Magnet(hash: $0.hash, link: nil),
|
magnet: Magnet(hash: iaObject.hash, link: nil),
|
||||||
source: self.id,
|
source: self.id,
|
||||||
expiryTimeStamp: Date().timeIntervalSince1970 + 300,
|
expiryTimeStamp: Date().timeIntervalSince1970 + 300,
|
||||||
files: []
|
files: iaObject.files.enumerated().compactMap { index, iaFile in
|
||||||
|
guard let fileName = iaFile.name.split(separator: "/").last else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return DebridIAFile(
|
||||||
|
fileId: index,
|
||||||
|
name: String(fileName)
|
||||||
|
)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -150,25 +159,12 @@ class TorBox: DebridSource, ObservableObject {
|
||||||
throw DebridError.IsCaching
|
throw DebridError.IsCaching
|
||||||
}
|
}
|
||||||
|
|
||||||
if filteredTorrent.files.count > 1 {
|
guard let torrentFile = filteredTorrent.files[safe: iaFile?.fileId ?? 0] else {
|
||||||
var copiedIA = ia
|
throw DebridError.EmptyTorrents
|
||||||
|
|
||||||
copiedIA?.files = filteredTorrent.files.map { torrentFile in
|
|
||||||
DebridIAFile(
|
|
||||||
fileId: torrentFile.id,
|
|
||||||
name: torrentFile.shortName,
|
|
||||||
streamUrlString: String(torrentId)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (nil, copiedIA)
|
|
||||||
} else if let torrentFile = filteredTorrent.files.first {
|
|
||||||
let restrictedFile = DebridIAFile(fileId: torrentFile.id, name: torrentFile.name, streamUrlString: String(torrentId))
|
|
||||||
|
|
||||||
return (restrictedFile, nil)
|
|
||||||
} else {
|
|
||||||
return (nil, nil)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let restrictedFile = DebridIAFile(fileId: torrentFile.id, name: torrentFile.name, streamUrlString: String(torrentId))
|
||||||
|
return (restrictedFile, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func createTorrent(magnet: Magnet) async throws -> Int {
|
private func createTorrent(magnet: Magnet) async throws -> Int {
|
||||||
|
|
@ -233,13 +229,13 @@ class TorBox: DebridSource, ObservableObject {
|
||||||
// MARK: - Cloud methods
|
// MARK: - Cloud methods
|
||||||
|
|
||||||
// Unused
|
// Unused
|
||||||
func getUserDownloads() async throws {}
|
func getUserDownloads() {}
|
||||||
|
|
||||||
func checkUserDownloads(link: String) async throws -> String? {
|
func checkUserDownloads(link: String) -> String? {
|
||||||
nil
|
link
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteDownload(downloadId: String) async throws {}
|
func deleteDownload(downloadId: String) {}
|
||||||
|
|
||||||
func getUserTorrents() async throws {
|
func getUserTorrents() async throws {
|
||||||
let torrentList = try await myTorrentList()
|
let torrentList = try await myTorrentList()
|
||||||
|
|
@ -252,7 +248,7 @@ class TorBox: DebridSource, ObservableObject {
|
||||||
fileName: torrent.name,
|
fileName: torrent.name,
|
||||||
status: torrent.downloadState == "cached" || torrent.downloadState == "completed" ? "downloaded" : torrent.downloadState,
|
status: torrent.downloadState == "cached" || torrent.downloadState == "completed" ? "downloaded" : torrent.downloadState,
|
||||||
hash: torrent.hash,
|
hash: torrent.hash,
|
||||||
links: [String(torrent.id)]
|
links: torrent.files.map { String($0.id) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ extension Premiumize {
|
||||||
struct DDLResponse: Codable {
|
struct DDLResponse: Codable {
|
||||||
let status: String
|
let status: String
|
||||||
let content: [DDLData]?
|
let content: [DDLData]?
|
||||||
let location: String
|
|
||||||
let filename: String
|
let filename: String
|
||||||
let filesize: Int
|
let filesize: Int
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,12 @@ extension TorBox {
|
||||||
let name: String
|
let name: String
|
||||||
let size: Int
|
let size: Int
|
||||||
let hash: String
|
let hash: String
|
||||||
|
let files: [InstantAvailabilityFile]
|
||||||
|
}
|
||||||
|
|
||||||
|
struct InstantAvailabilityFile: Codable, Sendable {
|
||||||
|
let name: String
|
||||||
|
let size: Int
|
||||||
}
|
}
|
||||||
|
|
||||||
struct InstantAvailabilityDataFailure: Codable, Sendable {
|
struct InstantAvailabilityDataFailure: Codable, Sendable {
|
||||||
|
|
|
||||||
|
|
@ -24,21 +24,24 @@ struct CloudDownloadView: View {
|
||||||
Button(cloudDownload.fileName) {
|
Button(cloudDownload.fileName) {
|
||||||
navModel.resultFromCloud = true
|
navModel.resultFromCloud = true
|
||||||
navModel.selectedTitle = cloudDownload.fileName
|
navModel.selectedTitle = cloudDownload.fileName
|
||||||
debridManager.downloadUrl = cloudDownload.link
|
var historyEntry = HistoryEntryJson(
|
||||||
|
name: cloudDownload.fileName,
|
||||||
PersistenceController.shared.createHistory(
|
source: debridSource.id
|
||||||
HistoryEntryJson(
|
|
||||||
name: cloudDownload.fileName,
|
|
||||||
url: cloudDownload.link,
|
|
||||||
source: debridSource.id
|
|
||||||
),
|
|
||||||
performSave: true
|
|
||||||
)
|
)
|
||||||
|
|
||||||
pluginManager.runDefaultAction(
|
debridManager.currentDebridTask = Task {
|
||||||
urlString: debridManager.downloadUrl,
|
await debridManager.fetchDebridDownload(magnet: nil, cloudInfo: cloudDownload.link)
|
||||||
navModel: navModel
|
|
||||||
)
|
if !debridManager.downloadUrl.isEmpty {
|
||||||
|
historyEntry.url = debridManager.downloadUrl
|
||||||
|
PersistenceController.shared.createHistory(historyEntry, performSave: true)
|
||||||
|
|
||||||
|
pluginManager.runDefaultAction(
|
||||||
|
urlString: debridManager.downloadUrl,
|
||||||
|
navModel: navModel
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.disabledAppearance(navModel.currentChoiceSheet != nil, dimmedOpacity: 0.7, animation: .easeOut(duration: 0.2))
|
.disabledAppearance(navModel.currentChoiceSheet != nil, dimmedOpacity: 0.7, animation: .easeOut(duration: 0.2))
|
||||||
.tint(.primary)
|
.tint(.primary)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue