Treewide: Cleanup and rename

Signed-off-by: kingbri <bdashore3@proton.me>
This commit is contained in:
kingbri 2024-06-16 15:37:00 -05:00
parent 646c22c9be
commit 078e48d316
12 changed files with 128 additions and 142 deletions

View file

@ -139,7 +139,7 @@
0CB6516528C5A5D700DCA721 /* InlinedList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CB6516428C5A5D700DCA721 /* InlinedList.swift */; }; 0CB6516528C5A5D700DCA721 /* InlinedList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CB6516428C5A5D700DCA721 /* InlinedList.swift */; };
0CB6516A28C5B4A600DCA721 /* InlineHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CB6516928C5B4A600DCA721 /* InlineHeader.swift */; }; 0CB6516A28C5B4A600DCA721 /* InlineHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CB6516928C5B4A600DCA721 /* InlineHeader.swift */; };
0CB725322C123E6F0047FC0B /* CloudDownloadView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CB725312C123E6F0047FC0B /* CloudDownloadView.swift */; }; 0CB725322C123E6F0047FC0B /* CloudDownloadView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CB725312C123E6F0047FC0B /* CloudDownloadView.swift */; };
0CB725342C123E760047FC0B /* CloudTorrentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CB725332C123E760047FC0B /* CloudTorrentView.swift */; }; 0CB725342C123E760047FC0B /* CloudMagnetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CB725332C123E760047FC0B /* CloudMagnetView.swift */; };
0CBAB83628D12ED500AC903E /* DisableInteraction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CBAB83528D12ED500AC903E /* DisableInteraction.swift */; }; 0CBAB83628D12ED500AC903E /* DisableInteraction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CBAB83528D12ED500AC903E /* DisableInteraction.swift */; };
0CBC76FD288D914F0054BE44 /* BatchChoiceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CBC76FC288D914F0054BE44 /* BatchChoiceView.swift */; }; 0CBC76FD288D914F0054BE44 /* BatchChoiceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CBC76FC288D914F0054BE44 /* BatchChoiceView.swift */; };
0CBC76FF288DAAD00054BE44 /* NavigationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CBC76FE288DAAD00054BE44 /* NavigationViewModel.swift */; }; 0CBC76FF288DAAD00054BE44 /* NavigationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CBC76FE288DAAD00054BE44 /* NavigationViewModel.swift */; };
@ -294,7 +294,7 @@
0CB6516428C5A5D700DCA721 /* InlinedList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InlinedList.swift; sourceTree = "<group>"; }; 0CB6516428C5A5D700DCA721 /* InlinedList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InlinedList.swift; sourceTree = "<group>"; };
0CB6516928C5B4A600DCA721 /* InlineHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InlineHeader.swift; sourceTree = "<group>"; }; 0CB6516928C5B4A600DCA721 /* InlineHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InlineHeader.swift; sourceTree = "<group>"; };
0CB725312C123E6F0047FC0B /* CloudDownloadView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloudDownloadView.swift; sourceTree = "<group>"; }; 0CB725312C123E6F0047FC0B /* CloudDownloadView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloudDownloadView.swift; sourceTree = "<group>"; };
0CB725332C123E760047FC0B /* CloudTorrentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloudTorrentView.swift; sourceTree = "<group>"; }; 0CB725332C123E760047FC0B /* CloudMagnetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloudMagnetView.swift; sourceTree = "<group>"; };
0CBAB83528D12ED500AC903E /* DisableInteraction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisableInteraction.swift; sourceTree = "<group>"; }; 0CBAB83528D12ED500AC903E /* DisableInteraction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisableInteraction.swift; sourceTree = "<group>"; };
0CBC76FC288D914F0054BE44 /* BatchChoiceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BatchChoiceView.swift; sourceTree = "<group>"; }; 0CBC76FC288D914F0054BE44 /* BatchChoiceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BatchChoiceView.swift; sourceTree = "<group>"; };
0CBC76FE288DAAD00054BE44 /* NavigationViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationViewModel.swift; sourceTree = "<group>"; }; 0CBC76FE288DAAD00054BE44 /* NavigationViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationViewModel.swift; sourceTree = "<group>"; };
@ -430,7 +430,7 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
0CB725312C123E6F0047FC0B /* CloudDownloadView.swift */, 0CB725312C123E6F0047FC0B /* CloudDownloadView.swift */,
0CB725332C123E760047FC0B /* CloudTorrentView.swift */, 0CB725332C123E760047FC0B /* CloudMagnetView.swift */,
); );
path = Cloud; path = Cloud;
sourceTree = "<group>"; sourceTree = "<group>";
@ -896,7 +896,7 @@
0C84FCE529E4B43200B0DFE4 /* SelectedDebridFilterView.swift in Sources */, 0C84FCE529E4B43200B0DFE4 /* SelectedDebridFilterView.swift in Sources */,
0CA148EC288903F000DE2211 /* ContentView.swift in Sources */, 0CA148EC288903F000DE2211 /* ContentView.swift in Sources */,
0CC389532970AD900066D06F /* Action+CoreDataClass.swift in Sources */, 0CC389532970AD900066D06F /* Action+CoreDataClass.swift in Sources */,
0CB725342C123E760047FC0B /* CloudTorrentView.swift in Sources */, 0CB725342C123E760047FC0B /* CloudMagnetView.swift in Sources */,
0C03EB72296F619900162E9A /* PluginList+CoreDataProperties.swift in Sources */, 0C03EB72296F619900162E9A /* PluginList+CoreDataProperties.swift in Sources */,
0C95D8D828A55B03005E22B3 /* DefaultActionPickerView.swift in Sources */, 0C95D8D828A55B03005E22B3 /* DefaultActionPickerView.swift in Sources */,
0C44E2AF28D52E8A007711AE /* BackupsView.swift in Sources */, 0C44E2AF28D52E8A007711AE /* BackupsView.swift in Sources */,

View file

@ -28,7 +28,7 @@ class AllDebrid: PollingDebridSource, ObservableObject {
@Published var IAValues: [DebridIA] = [] @Published var IAValues: [DebridIA] = []
@Published var cloudDownloads: [DebridCloudDownload] = [] @Published var cloudDownloads: [DebridCloudDownload] = []
@Published var cloudTorrents: [DebridCloudTorrent] = [] @Published var cloudMagnets: [DebridCloudMagnet] = []
var cloudTTL: Double = 0.0 var cloudTTL: Double = 0.0
private let baseApiUrl = "https://api.alldebrid.com/v4" private let baseApiUrl = "https://api.alldebrid.com/v4"
@ -217,8 +217,8 @@ class AllDebrid: PollingDebridSource, ObservableObject {
func getRestrictedFile(magnet: Magnet, ia: DebridIA?, iaFile: DebridIAFile?) async throws -> (restrictedFile: DebridIAFile?, newIA: DebridIA?) { func getRestrictedFile(magnet: Magnet, ia: DebridIA?, iaFile: DebridIAFile?) async throws -> (restrictedFile: DebridIAFile?, newIA: DebridIA?) {
let selectedMagnetId: String let selectedMagnetId: String
if let existingMagnet = cloudTorrents.first(where: { $0.hash == magnet.hash && $0.status == "Ready" }) { if let existingMagnet = cloudMagnets.first(where: { $0.hash == magnet.hash && $0.status == "Ready" }) {
selectedMagnetId = existingMagnet.torrentId selectedMagnetId = existingMagnet.cloudMagnetId
} else { } else {
let magnetId = try await addMagnet(magnet: magnet) let magnetId = try await addMagnet(magnet: magnet)
selectedMagnetId = String(magnetId) selectedMagnetId = String(magnetId)
@ -269,10 +269,10 @@ class AllDebrid: PollingDebridSource, ObservableObject {
let rawResponse = try jsonDecoder.decode(ADResponse<MagnetStatusResponse>.self, from: data).data let rawResponse = try jsonDecoder.decode(ADResponse<MagnetStatusResponse>.self, from: data).data
// Better to fetch no link at all than the wrong link // Better to fetch no link at all than the wrong link
if let torrentFile = rawResponse.magnets[safe: 0]?.links[safe: selectedIndex ?? -1] { if let cloudMagnetFile = rawResponse.magnets[safe: 0]?.links[safe: selectedIndex ?? -1] {
return DebridIAFile(fileId: 0, name: torrentFile.filename, streamUrlString: torrentFile.link) return DebridIAFile(fileId: 0, name: cloudMagnetFile.filename, streamUrlString: cloudMagnetFile.link)
} else { } else {
throw DebridError.EmptyTorrents throw DebridError.EmptyUserMagnets
} }
} }
@ -300,32 +300,31 @@ class AllDebrid: PollingDebridSource, ObservableObject {
// MARK: - Cloud methods // MARK: - Cloud methods
// Referred to as "User magnets" in AllDebrid's API func getUserMagnets() async throws {
func getUserTorrents() async throws {
var request = URLRequest(url: try buildRequestURL(urlString: "\(baseApiUrl)/magnet/status")) var request = URLRequest(url: try buildRequestURL(urlString: "\(baseApiUrl)/magnet/status"))
let data = try await performRequest(request: &request, requestName: #function) let data = try await performRequest(request: &request, requestName: #function)
let rawResponse = try jsonDecoder.decode(ADResponse<MagnetStatusResponse>.self, from: data).data let rawResponse = try jsonDecoder.decode(ADResponse<MagnetStatusResponse>.self, from: data).data
cloudTorrents = rawResponse.magnets.map { magnetResponse in cloudMagnets = rawResponse.magnets.map { magnetResponse in
DebridCloudTorrent( DebridCloudMagnet(
torrentId: String(magnetResponse.id), cloudMagnetId: String(magnetResponse.id),
source: self.id, source: self.id,
fileName: magnetResponse.filename, fileName: magnetResponse.filename,
status: magnetResponse.status, status: magnetResponse.status == "Ready" ? "downloaded" : magnetResponse.status,
hash: magnetResponse.hash, hash: magnetResponse.hash,
links: magnetResponse.links.map(\.link) links: magnetResponse.links.map(\.link)
) )
} }
} }
func deleteTorrent(torrentId: String?) async throws { func deleteUserMagnet(cloudMagnetId: String?) async throws {
guard let torrentId else { guard let cloudMagnetId else {
throw DebridError.FailedRequest(description: "The torrentID \(String(describing: torrentId)) is invalid") throw DebridError.FailedRequest(description: "The cloud magnetID \(String(describing: cloudMagnetId)) is invalid")
} }
let queryItems = [ let queryItems = [
URLQueryItem(name: "id", value: torrentId) URLQueryItem(name: "id", value: cloudMagnetId)
] ]
var request = URLRequest(url: try buildRequestURL(urlString: "\(baseApiUrl)/magnet/delete", queryItems: queryItems)) var request = URLRequest(url: try buildRequestURL(urlString: "\(baseApiUrl)/magnet/delete", queryItems: queryItems))
@ -352,7 +351,7 @@ class AllDebrid: PollingDebridSource, ObservableObject {
} }
// The downloadId is actually the download link // The downloadId is actually the download link
func deleteDownload(downloadId: String) async throws { func deleteUserDownload(downloadId: String) async throws {
let queryItems = [ let queryItems = [
URLQueryItem(name: "link", value: downloadId) URLQueryItem(name: "link", value: downloadId)
] ]

View file

@ -7,19 +7,13 @@
import Foundation import Foundation
// Torrents: /cloud/history
// IA: /cache (JSON array of hashes)
// Add Magnet: /cloud (URL param in JSON body)
// Get files/unrestrict: /cloud/explore/\(requestId)
// Delete torrent (website URL, not API URL): /cloud/remove/\(torrentId)
class OffCloud: DebridSource, ObservableObject { 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: String? = "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 magnet link is a batch before downloading."
@Published var authProcessing: Bool = false @Published var authProcessing: Bool = false
var isLoggedIn: Bool { var isLoggedIn: Bool {
@ -36,7 +30,7 @@ class OffCloud: DebridSource, ObservableObject {
@Published var IAValues: [DebridIA] = [] @Published var IAValues: [DebridIA] = []
@Published var cloudDownloads: [DebridCloudDownload] = [] @Published var cloudDownloads: [DebridCloudDownload] = []
@Published var cloudTorrents: [DebridCloudTorrent] = [] @Published var cloudMagnets: [DebridCloudMagnet] = []
var cloudTTL: Double = 0.0 var cloudTTL: Double = 0.0
private let baseApiUrl = "https://offcloud.com/api" private let baseApiUrl = "https://offcloud.com/api"
@ -140,11 +134,11 @@ class OffCloud: DebridSource, ObservableObject {
// Cloud in OffCloud's API // Cloud in OffCloud's API
func getRestrictedFile(magnet: Magnet, ia: DebridIA?, iaFile: DebridIAFile?) async throws -> (restrictedFile: DebridIAFile?, newIA: DebridIA?) { func getRestrictedFile(magnet: Magnet, ia: DebridIA?, iaFile: DebridIAFile?) async throws -> (restrictedFile: DebridIAFile?, newIA: DebridIA?) {
let selectedTorrent: DebridCloudTorrent let selectedMagnet: DebridCloudMagnet
// Don't queue a new job if the torrent already exists // Don't queue a new job if the magnet already exists in the user's account
if let existingTorrent = cloudTorrents.first(where: { $0.hash == magnet.hash && $0.status == "downloaded" }) { if let existingCloudMagnet = cloudMagnets.first(where: { $0.hash == magnet.hash && $0.status == "downloaded" }) {
selectedTorrent = existingTorrent selectedMagnet = existingCloudMagnet
} else { } else {
let cloudDownloadResponse = try await offcloudDownload(magnet: magnet) let cloudDownloadResponse = try await offcloudDownload(magnet: magnet)
@ -152,8 +146,8 @@ class OffCloud: DebridSource, ObservableObject {
throw DebridError.IsCaching throw DebridError.IsCaching
} }
selectedTorrent = DebridCloudTorrent( selectedMagnet = DebridCloudMagnet(
torrentId: cloudDownloadResponse.requestId, cloudMagnetId: cloudDownloadResponse.requestId,
source: id, source: id,
fileName: cloudDownloadResponse.fileName, fileName: cloudDownloadResponse.fileName,
status: cloudDownloadResponse.status, status: cloudDownloadResponse.status,
@ -162,7 +156,7 @@ class OffCloud: DebridSource, ObservableObject {
) )
} }
let cloudExploreLinks = try await cloudExplore(requestId: selectedTorrent.torrentId) let cloudExploreLinks = try await cloudExplore(requestId: selectedMagnet.cloudMagnetId)
if cloudExploreLinks.count > 1 { if cloudExploreLinks.count > 1 {
var copiedIA = ia var copiedIA = ia
@ -183,7 +177,7 @@ class OffCloud: DebridSource, ObservableObject {
} else if let exploreLink = cloudExploreLinks.first { } else if let exploreLink = cloudExploreLinks.first {
let restrictedFile = DebridIAFile( let restrictedFile = DebridIAFile(
fileId: 0, fileId: 0,
name: selectedTorrent.fileName, name: selectedMagnet.fileName,
streamUrlString: exploreLink streamUrlString: exploreLink
) )
@ -235,21 +229,21 @@ class OffCloud: DebridSource, ObservableObject {
link link
} }
func deleteDownload(downloadId: String) {} func deleteUserDownload(downloadId: String) {}
func getUserTorrents() async throws { func getUserMagnets() async throws {
var request = URLRequest(url: try buildRequestURL(urlString: "\(baseApiUrl)/cloud/history")) var request = URLRequest(url: try buildRequestURL(urlString: "\(baseApiUrl)/cloud/history"))
let data = try await performRequest(request: &request, requestName: "cloudHistory") let data = try await performRequest(request: &request, requestName: "cloudHistory")
let rawResponse = try jsonDecoder.decode([CloudHistoryResponse].self, from: data) let rawResponse = try jsonDecoder.decode([CloudHistoryResponse].self, from: data)
cloudTorrents = rawResponse.compactMap { cloudHistory in cloudMagnets = rawResponse.compactMap { cloudHistory in
guard let magnetHash = Magnet(hash: nil, link: cloudHistory.originalLink).hash else { guard let magnetHash = Magnet(hash: nil, link: cloudHistory.originalLink).hash else {
return nil return nil
} }
return DebridCloudTorrent( return DebridCloudMagnet(
torrentId: cloudHistory.requestId, cloudMagnetId: cloudHistory.requestId,
source: self.id, source: self.id,
fileName: cloudHistory.fileName, fileName: cloudHistory.fileName,
status: cloudHistory.status, status: cloudHistory.status,
@ -260,12 +254,12 @@ class OffCloud: DebridSource, ObservableObject {
} }
// Uses the base website because this isn't present in the API path but still works like the API? // Uses the base website because this isn't present in the API path but still works like the API?
func deleteTorrent(torrentId: String?) async throws { func deleteUserMagnet(cloudMagnetId: String?) async throws {
guard let torrentId else { guard let cloudMagnetId else {
throw DebridError.InvalidPostBody throw DebridError.InvalidPostBody
} }
var request = URLRequest(url: try buildRequestURL(urlString: "\(website)/cloud/remove/\(torrentId)")) var request = URLRequest(url: try buildRequestURL(urlString: "\(website)/cloud/remove/\(cloudMagnetId)"))
try await performRequest(request: &request, requestName: "cloudRemove") try await performRequest(request: &request, requestName: "cloudRemove")
} }
} }

View file

@ -29,7 +29,7 @@ class Premiumize: OAuthDebridSource, ObservableObject {
@Published var IAValues: [DebridIA] = [] @Published var IAValues: [DebridIA] = []
@Published var cloudDownloads: [DebridCloudDownload] = [] @Published var cloudDownloads: [DebridCloudDownload] = []
@Published var cloudTorrents: [DebridCloudTorrent] = [] @Published var cloudMagnets: [DebridCloudMagnet] = []
var cloudTTL: Double = 0.0 var cloudTTL: Double = 0.0
private let baseAuthUrl = "https://www.premiumize.me/authorize" private let baseAuthUrl = "https://www.premiumize.me/authorize"
@ -355,7 +355,7 @@ class Premiumize: OAuthDebridSource, ObservableObject {
try await itemDetails(itemID: link).link try await itemDetails(itemID: link).link
} }
func deleteDownload(downloadId: String) async throws { func deleteUserDownload(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")
@ -368,8 +368,8 @@ class Premiumize: OAuthDebridSource, ObservableObject {
try await performRequest(request: &request, requestName: #function) try await performRequest(request: &request, requestName: #function)
} }
// No user torrents for Premiumize // No user magnets for Premiumize
func getUserTorrents() {} func getUserMagnets() {}
func deleteTorrent(torrentId: String?) {} func deleteUserMagnet(cloudMagnetId: String?) {}
} }

View file

@ -30,7 +30,7 @@ class RealDebrid: PollingDebridSource, ObservableObject {
@Published var IAValues: [DebridIA] = [] @Published var IAValues: [DebridIA] = []
@Published var cloudDownloads: [DebridCloudDownload] = [] @Published var cloudDownloads: [DebridCloudDownload] = []
@Published var cloudTorrents: [DebridCloudTorrent] = [] @Published var cloudMagnets: [DebridCloudMagnet] = []
var cloudTTL: Double = 0.0 var cloudTTL: Double = 0.0
private let baseAuthUrl = "https://api.real-debrid.com/oauth/v2" private let baseAuthUrl = "https://api.real-debrid.com/oauth/v2"
@ -261,7 +261,6 @@ class RealDebrid: PollingDebridSource, ObservableObject {
let data = try await performRequest(request: &request, requestName: #function) let data = try await performRequest(request: &request, requestName: #function)
// Does not account for torrent packs at the moment
let rawResponseDict = try jsonDecoder.decode([String: InstantAvailabilityResponse].self, from: data) let rawResponseDict = try jsonDecoder.decode([String: InstantAvailabilityResponse].self, from: data)
for (hash, response) in rawResponseDict { for (hash, response) in rawResponseDict {
@ -320,9 +319,9 @@ class RealDebrid: PollingDebridSource, ObservableObject {
var selectedMagnetId = "" var selectedMagnetId = ""
do { do {
// Don't queue a new job if the torrent already exists // Don't queue a new job if the magnet already exists in the user's library
if let existingTorrent = cloudTorrents.first(where: { $0.hash == magnet.hash && $0.status == "downloaded" }) { if let existingCloudMagnet = cloudMagnets.first(where: { $0.hash == magnet.hash && $0.status == "downloaded" }) {
selectedMagnetId = existingTorrent.torrentId selectedMagnetId = existingCloudMagnet.cloudMagnetId
} else { } else {
selectedMagnetId = try await addMagnet(magnet: magnet) selectedMagnetId = try await addMagnet(magnet: magnet)
@ -330,15 +329,15 @@ class RealDebrid: PollingDebridSource, ObservableObject {
} }
// RealDebrid has 1 as the first ID for a file // RealDebrid has 1 as the first ID for a file
let torrentFile = try await torrentInfo( let restrictedFile = try await torrentInfo(
debridID: selectedMagnetId, debridID: selectedMagnetId,
selectedFileId: iaFile?.fileId ?? 1 selectedFileId: iaFile?.fileId ?? 1
) )
return (torrentFile, nil) return (restrictedFile, nil)
} catch { } catch {
if case DebridError.EmptyTorrents = error, !selectedMagnetId.isEmpty { if case DebridError.EmptyUserMagnets = error, !selectedMagnetId.isEmpty {
try? await deleteTorrent(torrentId: selectedMagnetId) try? await deleteUserMagnet(cloudMagnetId: selectedMagnetId)
} }
// Re-raise the error to the calling function // Re-raise the error to the calling function
@ -396,17 +395,17 @@ class RealDebrid: PollingDebridSource, ObservableObject {
let filteredFiles = rawResponse.files.filter { $0.selected == 1 } let filteredFiles = rawResponse.files.filter { $0.selected == 1 }
let linkIndex = filteredFiles.firstIndex(where: { $0.id == selectedFileId }) let linkIndex = filteredFiles.firstIndex(where: { $0.id == selectedFileId })
// Let the user know if a torrent is downloading // Let the user know if a magnet is downloading
if let torrentLink = rawResponse.links[safe: linkIndex ?? -1], rawResponse.status == "downloaded" { if let cloudMagnetLink = rawResponse.links[safe: linkIndex ?? -1], rawResponse.status == "downloaded" {
return DebridIAFile( return DebridIAFile(
fileId: 0, fileId: 0,
name: rawResponse.filename, name: rawResponse.filename,
streamUrlString: torrentLink streamUrlString: cloudMagnetLink
) )
} else if rawResponse.status == "downloading" || rawResponse.status == "queued" { } else if rawResponse.status == "downloading" || rawResponse.status == "queued" {
throw DebridError.IsCaching throw DebridError.IsCaching
} else { } else {
throw DebridError.EmptyTorrents throw DebridError.EmptyUserMagnets
} }
} }
@ -429,15 +428,15 @@ class RealDebrid: PollingDebridSource, ObservableObject {
// MARK: - Cloud methods // MARK: - Cloud methods
// Gets the user's torrent library // Gets the user's cloud magnet library
func getUserTorrents() async throws { func getUserMagnets() async throws {
var request = URLRequest(url: URL(string: "\(baseApiUrl)/torrents")!) var request = URLRequest(url: URL(string: "\(baseApiUrl)/torrents")!)
let data = try await performRequest(request: &request, requestName: #function) let data = try await performRequest(request: &request, requestName: #function)
let rawResponse = try jsonDecoder.decode([UserTorrentsResponse].self, from: data) let rawResponse = try jsonDecoder.decode([UserTorrentsResponse].self, from: data)
cloudTorrents = rawResponse.map { response in cloudMagnets = rawResponse.map { response in
DebridCloudTorrent( DebridCloudMagnet(
torrentId: response.id, cloudMagnetId: response.id,
source: self.id, source: self.id,
fileName: response.filename, fileName: response.filename,
status: response.status, status: response.status,
@ -447,21 +446,21 @@ class RealDebrid: PollingDebridSource, ObservableObject {
} }
} }
// Deletes a torrent download from RD // Deletes a magnet download from RD
func deleteTorrent(torrentId: String?) async throws { func deleteUserMagnet(cloudMagnetId: String?) async throws {
let deleteId: String let deleteId: String
if let torrentId { if let cloudMagnetId {
deleteId = torrentId deleteId = cloudMagnetId
} else { } else {
// Refresh the torrent cloud // Refresh the user magnet list
// The first file is the currently caching one // The first file is the currently caching one
let _ = try await getUserTorrents() let _ = try await getUserMagnets()
guard let firstTorrent = cloudTorrents[safe: -1] else { guard let firstCloudMagnet = cloudMagnets[safe: -1] else {
throw DebridError.EmptyTorrents throw DebridError.EmptyUserMagnets
} }
deleteId = firstTorrent.torrentId deleteId = firstCloudMagnet.cloudMagnetId
} }
var request = URLRequest(url: URL(string: "\(baseApiUrl)/torrents/delete/\(deleteId)")!) var request = URLRequest(url: URL(string: "\(baseApiUrl)/torrents/delete/\(deleteId)")!)
@ -486,7 +485,7 @@ class RealDebrid: PollingDebridSource, ObservableObject {
link link
} }
func deleteDownload(downloadId: String) async throws { func deleteUserDownload(downloadId: String) async throws {
var request = URLRequest(url: URL(string: "\(baseApiUrl)/downloads/delete/\(downloadId)")!) var request = URLRequest(url: URL(string: "\(baseApiUrl)/downloads/delete/\(downloadId)")!)
request.httpMethod = "DELETE" request.httpMethod = "DELETE"

View file

@ -7,12 +7,6 @@
import Foundation import Foundation
// Torrents: /torrents/mylist
// IA: /torrents/checkcached
// Add Magnet: /torrents/createtorrent
// Delete torrent: /torrents/controltorrent
// Unrestrict: /torrents/requestdl
class TorBox: DebridSource, ObservableObject { class TorBox: DebridSource, ObservableObject {
let id = "TorBox" let id = "TorBox"
let abbreviation = "TB" let abbreviation = "TB"
@ -35,7 +29,7 @@ class TorBox: DebridSource, ObservableObject {
@Published var IAValues: [DebridIA] = [] @Published var IAValues: [DebridIA] = []
@Published var cloudDownloads: [DebridCloudDownload] = [] @Published var cloudDownloads: [DebridCloudDownload] = []
@Published var cloudTorrents: [DebridCloudTorrent] = [] @Published var cloudMagnets: [DebridCloudMagnet] = []
var cloudTTL: Double = 0.0 var cloudTTL: Double = 0.0
private let baseApiUrl = "https://api.torbox.app/v1/api" private let baseApiUrl = "https://api.torbox.app/v1/api"
@ -148,22 +142,22 @@ class TorBox: DebridSource, ObservableObject {
// MARK: - Downloading // MARK: - Downloading
func getRestrictedFile(magnet: Magnet, ia: DebridIA?, iaFile: DebridIAFile?) async throws -> (restrictedFile: DebridIAFile?, newIA: DebridIA?) { func getRestrictedFile(magnet: Magnet, ia: DebridIA?, iaFile: DebridIAFile?) async throws -> (restrictedFile: DebridIAFile?, newIA: DebridIA?) {
let torrentId = try await createTorrent(magnet: magnet) let cloudMagnetId = try await createTorrent(magnet: magnet)
let torrentList = try await myTorrentList() let cloudMagnetList = try await myTorrentList()
guard let filteredTorrent = torrentList.first(where: { $0.id == torrentId }) else { guard let filteredCloudMagnet = cloudMagnetList.first(where: { $0.id == cloudMagnetId }) else {
throw DebridError.FailedRequest(description: "A torrent wasn't found. Are you sure it's cached?") throw DebridError.FailedRequest(description: "Could not find a cached magnet. Are you sure it's cached?")
} }
// If the torrent isn't saved, it's considered as caching // If the user magnet isn't saved, it's considered as caching
guard filteredTorrent.downloadState == "cached" || filteredTorrent.downloadState == "completed" else { guard filteredCloudMagnet.downloadState == "cached" || filteredCloudMagnet.downloadState == "completed" else {
throw DebridError.IsCaching throw DebridError.IsCaching
} }
guard let torrentFile = filteredTorrent.files[safe: iaFile?.fileId ?? 0] else { guard let cloudMagnetFile = filteredCloudMagnet.files[safe: iaFile?.fileId ?? 0] else {
throw DebridError.EmptyTorrents throw DebridError.EmptyUserMagnets
} }
let restrictedFile = DebridIAFile(fileId: torrentFile.id, name: torrentFile.name, streamUrlString: String(torrentId)) let restrictedFile = DebridIAFile(fileId: cloudMagnetFile.id, name: cloudMagnetFile.name, streamUrlString: String(cloudMagnetId))
return (restrictedFile, nil) return (restrictedFile, nil)
} }
@ -235,26 +229,26 @@ class TorBox: DebridSource, ObservableObject {
link link
} }
func deleteDownload(downloadId: String) {} func deleteUserDownload(downloadId: String) {}
func getUserTorrents() async throws { func getUserMagnets() async throws {
let torrentList = try await myTorrentList() let cloudMagnetList = try await myTorrentList()
cloudTorrents = torrentList.map { torrent in cloudMagnets = cloudMagnetList.map { cloudMagnet in
// Only need one link to force a green badge // Only need one link to force a green badge
DebridCloudTorrent( DebridCloudMagnet(
torrentId: String(torrent.id), cloudMagnetId: String(cloudMagnet.id),
source: self.id, source: self.id,
fileName: torrent.name, fileName: cloudMagnet.name,
status: torrent.downloadState == "cached" || torrent.downloadState == "completed" ? "downloaded" : torrent.downloadState, status: cloudMagnet.downloadState == "cached" || cloudMagnet.downloadState == "completed" ? "downloaded" : cloudMagnet.downloadState,
hash: torrent.hash, hash: cloudMagnet.hash,
links: torrent.files.map { String($0.id) } links: cloudMagnet.files.map { String($0.id) }
) )
} }
} }
func deleteTorrent(torrentId: String?) async throws { func deleteUserMagnet(cloudMagnetId: String?) async throws {
guard let torrentId else { guard let cloudMagnetId else {
throw DebridError.InvalidPostBody throw DebridError.InvalidPostBody
} }
@ -262,7 +256,7 @@ class TorBox: DebridSource, ObservableObject {
request.httpMethod = "POST" request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type") request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let body = ControlTorrentRequest(torrentId: torrentId, operation: "Delete") let body = ControlTorrentRequest(torrentId: cloudMagnetId, operation: "Delete")
request.httpBody = try jsonEncoder.encode(body) request.httpBody = try jsonEncoder.encode(body)
try await performRequest(request: &request, requestName: "controltorrent") try await performRequest(request: &request, requestName: "controltorrent")

View file

@ -35,8 +35,8 @@ struct DebridCloudDownload: Hashable, Sendable {
let link: String let link: String
} }
struct DebridCloudTorrent: Hashable, Sendable { struct DebridCloudMagnet: Hashable, Sendable {
let torrentId: String let cloudMagnetId: String
let source: String let source: String
let fileName: String let fileName: String
let status: String let status: String
@ -50,7 +50,7 @@ enum DebridError: Error {
case InvalidResponse case InvalidResponse
case InvalidToken case InvalidToken
case EmptyData case EmptyData
case EmptyTorrents case EmptyUserMagnets
case IsCaching case IsCaching
case FailedRequest(description: String) case FailedRequest(description: String)
case AuthQuery(description: String) case AuthQuery(description: String)

View file

@ -27,7 +27,7 @@ protocol DebridSource: AnyObservableObject {
// Cloud variables // Cloud variables
var cloudDownloads: [DebridCloudDownload] { get set } var cloudDownloads: [DebridCloudDownload] { get set }
var cloudTorrents: [DebridCloudTorrent] { get set } var cloudMagnets: [DebridCloudMagnet] { get set }
var cloudTTL: Double { get set } var cloudTTL: Double { get set }
// Common authentication functions // Common authentication functions
@ -39,7 +39,7 @@ protocol DebridSource: AnyObservableObject {
// 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
// Torrents also checked here // Cloud magnets also checked here
func getRestrictedFile(magnet: Magnet, ia: DebridIA?, iaFile: DebridIAFile?) async throws -> (restrictedFile: DebridIAFile?, newIA: DebridIA?) func getRestrictedFile(magnet: Magnet, ia: DebridIA?, iaFile: DebridIAFile?) async throws -> (restrictedFile: DebridIAFile?, newIA: DebridIA?)
// Unrestricts a locked file // Unrestricts a locked file
@ -48,11 +48,11 @@ protocol DebridSource: AnyObservableObject {
// User downloads functions // User downloads functions
func getUserDownloads() async throws func getUserDownloads() async throws
func checkUserDownloads(link: String) async throws -> String? func checkUserDownloads(link: String) async throws -> String?
func deleteDownload(downloadId: String) async throws func deleteUserDownload(downloadId: String) async throws
// User torrent functions // User magnet functions
func getUserTorrents() async throws func getUserMagnets() async throws
func deleteTorrent(torrentId: String?) async throws func deleteUserMagnet(cloudMagnetId: String?) async throws
} }
extension DebridSource { extension DebridSource {

View file

@ -157,7 +157,7 @@ class DebridManager: ObservableObject {
func selectDebridResult(magnet: Magnet) -> Bool { func selectDebridResult(magnet: Magnet) -> Bool {
guard let magnetHash = magnet.hash else { guard let magnetHash = magnet.hash else {
logManager?.error("DebridManager: Could not find the torrent magnet hash") logManager?.error("DebridManager: Could not find the magnet hash")
return false return false
} }
@ -415,9 +415,9 @@ class DebridManager: ObservableObject {
if bypassTTL || Date().timeIntervalSince1970 > selectedSource.cloudTTL { if bypassTTL || Date().timeIntervalSince1970 > selectedSource.cloudTTL {
do { do {
// Populates the inner downloads and torrent arrays // Populates the inner downloads and magnet arrays
try await selectedSource.getUserDownloads() try await selectedSource.getUserDownloads()
try await selectedSource.getUserTorrents() try await selectedSource.getUserMagnets()
// Update the TTL to 5 minutes from now // Update the TTL to 5 minutes from now
selectedSource.cloudTTL = Date().timeIntervalSince1970 + 300 selectedSource.cloudTTL = Date().timeIntervalSince1970 + 300
@ -436,7 +436,7 @@ class DebridManager: ObservableObject {
} }
do { do {
try await selectedSource.deleteDownload(downloadId: download.downloadId) try await selectedSource.deleteUserDownload(downloadId: download.downloadId)
await fetchDebridCloud(bypassTTL: true) await fetchDebridCloud(bypassTTL: true)
} catch { } catch {
@ -456,19 +456,19 @@ class DebridManager: ObservableObject {
} }
} }
func deleteCloudTorrent(_ torrent: DebridCloudTorrent) async { func deleteUserMagnet(_ cloudMagnet: DebridCloudMagnet) async {
guard let selectedSource = selectedDebridSource else { guard let selectedSource = selectedDebridSource else {
return return
} }
do { do {
try await selectedSource.deleteTorrent(torrentId: torrent.torrentId) try await selectedSource.deleteUserMagnet(cloudMagnetId: cloudMagnet.cloudMagnetId)
await fetchDebridCloud(bypassTTL: true) await fetchDebridCloud(bypassTTL: true)
} catch { } catch {
switch error { switch error {
case DebridError.NotImplemented: case DebridError.NotImplemented:
let message = "Torrent deletion for \(selectedSource.id) is not implemented. Please use the service's website." let message = "Magnet deletion for \(selectedSource.id) is not implemented. Please use the service's website."
notImplementedMessage = message notImplementedMessage = message
showNotImplementedAlert.toggle() showNotImplementedAlert.toggle()
@ -477,7 +477,7 @@ class DebridManager: ObservableObject {
showToast: false showToast: false
) )
default: default:
await sendDebridError(error, prefix: "\(selectedSource.id) torrent delete error") await sendDebridError(error, prefix: "\(selectedSource.id) magnet delete error")
} }
} }
} }

View file

@ -1,5 +1,5 @@
// //
// CloudTorrentView.swift // CloudMagnetView.swift
// Ferrite // Ferrite
// //
// Created by Brian Dashore on 6/6/24. // Created by Brian Dashore on 6/6/24.
@ -7,7 +7,7 @@
import SwiftUI import SwiftUI
struct CloudTorrentView: View { struct CloudMagnetView: View {
@EnvironmentObject var navModel: NavigationViewModel @EnvironmentObject var navModel: NavigationViewModel
@EnvironmentObject var debridManager: DebridManager @EnvironmentObject var debridManager: DebridManager
@EnvironmentObject var pluginManager: PluginManager @EnvironmentObject var pluginManager: PluginManager
@ -17,27 +17,27 @@ struct CloudTorrentView: View {
@Binding var searchText: String @Binding var searchText: String
var body: some View { var body: some View {
DisclosureGroup("Torrents") { DisclosureGroup("Magnets") {
ForEach(debridSource.cloudTorrents.filter { ForEach(debridSource.cloudMagnets.filter {
searchText.isEmpty ? true : $0.fileName.lowercased().contains(searchText.lowercased()) searchText.isEmpty ? true : $0.fileName.lowercased().contains(searchText.lowercased())
}, id: \.self) { cloudTorrent in }, id: \.self) { cloudMagnet in
Button { Button {
if cloudTorrent.status == "downloaded", !cloudTorrent.links.isEmpty { if cloudMagnet.status == "downloaded", !cloudMagnet.links.isEmpty {
navModel.resultFromCloud = true navModel.resultFromCloud = true
navModel.selectedTitle = cloudTorrent.fileName navModel.selectedTitle = cloudMagnet.fileName
var historyInfo = HistoryEntryJson( var historyInfo = HistoryEntryJson(
name: cloudTorrent.fileName, name: cloudMagnet.fileName,
source: debridSource.id source: debridSource.id
) )
Task { Task {
let magnet = Magnet(hash: cloudTorrent.hash, link: nil) let magnet = Magnet(hash: cloudMagnet.hash, link: nil)
await debridManager.populateDebridIA([magnet]) await debridManager.populateDebridIA([magnet])
if debridManager.selectDebridResult(magnet: magnet) { if debridManager.selectDebridResult(magnet: magnet) {
// Is this a batch? // Is this a batch?
if cloudTorrent.links.count == 1 { if cloudMagnet.links.count == 1 {
await debridManager.fetchDebridDownload(magnet: magnet) await debridManager.fetchDebridDownload(magnet: magnet)
// Bump to batch // Bump to batch
@ -67,15 +67,15 @@ struct CloudTorrentView: View {
} }
} label: { } label: {
VStack(alignment: .leading, spacing: 10) { VStack(alignment: .leading, spacing: 10) {
Text(cloudTorrent.fileName) Text(cloudMagnet.fileName)
.font(.callout) .font(.callout)
.fixedSize(horizontal: false, vertical: true) .fixedSize(horizontal: false, vertical: true)
.lineLimit(4) .lineLimit(4)
HStack { HStack {
Text(cloudTorrent.status.capitalizingFirstLetter()) Text(cloudMagnet.status.capitalizingFirstLetter())
Spacer() Spacer()
DebridLabelView(debridSource: debridSource, cloudLinks: cloudTorrent.links) DebridLabelView(debridSource: debridSource, cloudLinks: cloudMagnet.links)
} }
.font(.caption) .font(.caption)
} }
@ -85,9 +85,9 @@ struct CloudTorrentView: View {
} }
.onDelete { offsets in .onDelete { offsets in
for index in offsets { for index in offsets {
if let cloudTorrent = debridSource.cloudTorrents[safe: index] { if let cloudMagnet = debridSource.cloudMagnets[safe: index] {
Task { Task {
await debridManager.deleteCloudTorrent(cloudTorrent) await debridManager.deleteUserMagnet(cloudMagnet)
} }
} }
} }

View file

@ -20,8 +20,8 @@ struct DebridCloudView: View {
CloudDownloadView(debridSource: debridSource, searchText: $searchText) CloudDownloadView(debridSource: debridSource, searchText: $searchText)
} }
if !debridSource.cloudTorrents.isEmpty { if !debridSource.cloudMagnets.isEmpty {
CloudTorrentView(debridSource: debridSource, searchText: $searchText) CloudMagnetView(debridSource: debridSource, searchText: $searchText)
} }
} }
.listStyle(.plain) .listStyle(.plain)

View file

@ -125,7 +125,7 @@ struct SearchResultButtonView: View {
.alert("Caching file", isPresented: $debridManager.showDeleteAlert) { .alert("Caching file", isPresented: $debridManager.showDeleteAlert) {
Button("Yes", role: .destructive) { Button("Yes", role: .destructive) {
Task { Task {
try? await debridManager.selectedDebridSource?.deleteTorrent(torrentId: nil) try? await debridManager.selectedDebridSource?.deleteUserMagnet(cloudMagnetId: nil)
} }
} }
Button("Cancel", role: .cancel) {} Button("Cancel", role: .cancel) {}