diff --git a/Dreadnought/Client.swift b/Dreadnought/Client.swift index 052a675..ab49f47 100644 --- a/Dreadnought/Client.swift +++ b/Dreadnought/Client.swift @@ -140,6 +140,20 @@ class TorrentClient: ObservableObject { } } } + + func forceResume(hashes: Set) { + guard let url = baseURL?.appending(path: "api/v2/torrents/setForceStart"), let cookie = self.cookies else { + return + } + let headers: HTTPHeaders = ["Cookie": cookie] + let parameters = ["hashes": hashes.joined(separator: "|"), "value": "true"] + AF.request(url, method: .post, parameters: parameters, encoder: URLEncodedFormParameterEncoder.default, headers: headers).response { response in + if let error = response.error { + Logger.torrentClient.info("Error when pausing torrent(s): \(error)") + return + } + } + } func loadPreferences() { if let clientCookie = UserDefaults.standard.string(forKey: PreferenceNames.clientCookie) { @@ -201,6 +215,20 @@ class TorrentClient: ObservableObject { } } + func pause(hashes: Set) { + guard let url = baseURL?.appending(path: "api/v2/torrents/pause"), let cookie = self.cookies else { + return + } + let headers: HTTPHeaders = ["Cookie": cookie] + let parameters = ["hashes": hashes.joined(separator: "|")] + AF.request(url, method: .post, parameters: parameters, encoder: URLEncodedFormParameterEncoder.default, headers: headers).response { response in + if let error = response.error { + Logger.torrentClient.info("Error when pausing torrent(s): \(error)") + return + } + } + } + /// Update client state from given main data. func processMainData(mainData: MainData) { self.rid = mainData.rid @@ -250,6 +278,20 @@ class TorrentClient: ObservableObject { } } + func resume(hashes: Set) { + guard let url = baseURL?.appending(path: "api/v2/torrents/resume"), let cookie = self.cookies else { + return + } + let headers: HTTPHeaders = ["Cookie": cookie] + let parameters = ["hashes": hashes.joined(separator: "|")] + AF.request(url, method: .post, parameters: parameters, encoder: URLEncodedFormParameterEncoder.default, headers: headers).response { response in + if let error = response.error { + Logger.torrentClient.info("Error when pausing torrent(s): \(error)") + return + } + } + } + func setCategory(hashes: Set, category: String) { guard let url = baseURL?.appending(path: "api/v2/torrents/setCategory"), let cookie = self.cookies else { return diff --git a/Dreadnought/ContentView.swift b/Dreadnought/ContentView.swift index ca7358c..611f0c6 100644 --- a/Dreadnought/ContentView.swift +++ b/Dreadnought/ContentView.swift @@ -298,6 +298,18 @@ struct TorrentList: View { .focusedValue(\.torrents, selectedTorrents) .focusedValue(\.torrentActions, torrentActions) .contextMenu(forSelectionType: Torrent.ID.self) { items in + Button("Resume") { + client.resume(hashes: items) + } + Button("Pause") { + client.pause(hashes: items) + } + Button("Force resume") { + client.forceResume(hashes: items) + } + + Divider() + Button("Remove", role: .destructive) { torrentActions.torrentsPendingRemoval = items } diff --git a/Dreadnought/DreadnoughtApp.swift b/Dreadnought/DreadnoughtApp.swift index e3a3ba3..e9d5111 100644 --- a/Dreadnought/DreadnoughtApp.swift +++ b/Dreadnought/DreadnoughtApp.swift @@ -23,11 +23,31 @@ extension FocusedValues { struct TorrentCommands: Commands { @FocusedValue(\.torrents) var torrents: TorrentSelection? @FocusedValue(\.torrentActions) var torrentActions: TorrentActions? + + let client: TorrentClient var disabled: Bool { self.torrents?.isEmpty ?? true } var body: some Commands { CommandMenu("Torrent") { + Button("Resume") { + guard let torrents = torrents else { return } + client.resume(hashes: torrents) + } + .disabled(disabled) + Button("Pause") { + guard let torrents = torrents else { return } + client.pause(hashes: torrents) + } + .disabled(disabled) + Button("Force resume") { + guard let torrents = torrents else { return } + client.forceResume(hashes: torrents) + } + .disabled(disabled) + + Divider() + Button("Remove") { guard let torrents = torrents else { return } torrentActions?.torrentsPendingRemoval = torrents @@ -64,7 +84,7 @@ struct DreadnoughtApp: App { } .keyboardShortcut("1", modifiers: .command) .commands { - TorrentCommands() + TorrentCommands(client: client) CommandGroup(before: .importExport) { Button("Make default for magnet links", action: self.makeDefaultMagnetHandler) }