diff --git a/README.md b/README.md index 7e4953efd..d438b2cc4 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ Screenshots: Changelog: ========== -* Nightly : ◆ **AutoDownload**: *(new)* Now able to use series custom Seeders, custom Includes and custom Excludes. ◆ **DataBase**: *(fix)* Make TRAKT_ID unique to prevent duplicate records. ◆ **TMDBfanArt**: *(new)* Refactor image loading to use TMDB. This complements and progressively takes over from FanArt. ◆ **Languages**: *(new)* Greek, Turkish, Slovak, South African English. ◆ **Languages**: *(fix)* Chinese, Dutch. ◆ **Log_GR**: *(del)* Drop Error-Tracking-Loggr, the service is no longer available. ◆ **sceneNameResolver**: *(new)* add custom support to subtract/add days from date formated serie names eg YYYY MM DD[-1]. ◆ **SearchEngines**: *(new)* Add ETag (extratorrent.st), IsoHunt2 (isohunt.tv), TGx (torrentgalaxy.to), EXT (ext.to), KATws (kickass.ws), Knaben (knaben.eu), TheRARBG (t-rb.org). ◆ **SearchEngines**: *(del)* KATcr is broken, TorrentZ2 is gone, ETTV is gone, Zooqle is gone, RarBG is gone, EzTV no results without cookie. ◆ **SearchEngines**: *(fix)* Limetorrrents DL links and new domain, 1337x DL links, TPB (*0.org) + fix details link, TPB mirror resolver (piratebayproxy.net), torrentdownloads new domain, fix details link for Jackett indexers. ◆ **Standalone**: *(new)* Mac OSX ARM64 package now available. ◆ **Standalone**: *(upgrade)* NWJS 0.87.0 with Chromium 124. ◆ **Standalone**: *(fix)* Prevent Chromium 112+ freezing tabs if idle. Switch chromium-args: --flag-switches-begin --disable-features=HighEfficiencyModeAvailable --flag-switches-end. **Standalone**: *(fix)* Rework saving widow position.◆ **TorrentClient**: *(new)* Introducing tTorrent client. ◆ **TorrentClient**: *(fix)* replace deprecated rTorrent calls, add support for qBitTorrent 4.2+, ignore aria2 metadata file reports. ◆ **TorrentClient**: *(fix)* qBitTorrent 4.5+ fix API call to remove torrent ◆ ◆ **TorrentClient**: *(fix)* qBitTorrent 5.0+ fix API call to start/stop torrent ◆ **TorrentClient**: *(fix)* Upgrade Tixati API for 2.86+. Note that older versions are no longer supported. ◆ **TorrentDialogs**: *(fix)* magnetLinks were being submitted twice due to NWJS bug. ◆ **TorrentDialogs**: *(add)* Add WEB to the quality list of the torrent search dialogues. ◆ **TorrentDialogs**: *(fix)* Trap SE errors so dialogues can report. ◆ **TorrentDialog2**: *(add)* individual SE spinners during searching. ◆ **TorrentMonitor**: *(fix)* Auto-Stop-All now works as intended. ◆ **Trakt**: *(new)* Preserve watched timestamp from Trakt.TV during import. ◆ **TraktTrending**: *(new)* Add option to view by Ended, Returning or Cancelled. ◆ **TraktTrending**: *(new)* Now updated Daily instead of Weekly. ◆ **TraktUpdateServices**: *(fix)* Support added for new API restrictions. ◆ **Misc**: *Bug fixes*. +* Nightly : ◆ **AutoDownload**: *(new)* Now able to use series custom Seeders, custom Includes and custom Excludes. ◆ **DataBase**: *(fix)* Make TRAKT_ID unique to prevent duplicate records. ◆ **TMDBfanArt**: *(new)* Refactor image loading to use TMDB. This complements and progressively takes over from FanArt. ◆ **Languages**: *(new)* Greek, Turkish, Slovak, South African English. ◆ **Languages**: *(fix)* Chinese, Dutch. ◆ **Log_GR**: *(del)* Drop Error-Tracking-Loggr, the service is no longer available. ◆ **sceneNameResolver**: *(new)* add custom support to subtract/add days from date formated serie names eg YYYY MM DD[-1]. ◆ **SearchEngines**: *(new)* Add ETag (extratorrent.st), IsoHunt2 (isohunt.tv), TGx (torrentgalaxy.to), EXT (ext.to), KATws (kickass.ws), Knaben (knaben.eu), TheRARBG (t-rb.org). ◆ **SearchEngines**: *(del)* KATcr is broken, TorrentZ2 is gone, ETTV is gone, Zooqle is gone, RarBG is gone, EzTV no results without cookie. ◆ **SearchEngines**: *(fix)* Limetorrrents DL links and new domain, 1337x DL links, TPB (*0.org) + fix details link, TPB mirror resolver (piratebayproxy.net), torrentdownloads new domain, fix details link for Jackett indexers. ◆ **Standalone**: *(new)* Mac OSX ARM64 package now available. ◆ **Standalone**: *(upgrade)* NWJS 0.87.0 with Chromium 124. ◆ **Standalone**: *(fix)* Prevent Chromium 112+ freezing tabs if idle. Switch chromium-args: --flag-switches-begin --disable-features=HighEfficiencyModeAvailable --flag-switches-end. **Standalone**: *(fix)* Rework saving widow position.◆ **TorrentClient**: *(new)* Introducing tTorrent client. ◆ **TorrentClient**: *(fix)* replace deprecated rTorrent calls, add support for qBitTorrent 4.2+, ignore aria2 metadata file reports. ◆ **TorrentClient**: *(fix)* qBitTorrent 4.5+ fix API call to remove torrent ◆ ◆ **TorrentClient**: *(fix)* qBitTorrent 5.0+ fix API call to start/stop torrent, drop support for qBt prior to 4.1 ◆ **TorrentClient**: *(fix)* Upgrade Tixati API for 2.86+. Note that older versions are no longer supported. ◆ **TorrentDialogs**: *(fix)* magnetLinks were being submitted twice due to NWJS bug. ◆ **TorrentDialogs**: *(add)* Add WEB to the quality list of the torrent search dialogues. ◆ **TorrentDialogs**: *(fix)* Trap SE errors so dialogues can report. ◆ **TorrentDialog2**: *(add)* individual SE spinners during searching. ◆ **TorrentMonitor**: *(fix)* Auto-Stop-All now works as intended. ◆ **Trakt**: *(new)* Preserve watched timestamp from Trakt.TV during import. ◆ **TraktTrending**: *(new)* Add option to view by Ended, Returning or Cancelled. ◆ **TraktTrending**: *(new)* Now updated Daily instead of Weekly. ◆ **TraktUpdateServices**: *(fix)* Support added for new API restrictions. ◆ **Misc**: *Bug fixes*. * v1.1.5 : ◆ **AutoDownload**: *(new)* Now able to download .torrent files \o/. ◆ **Database**: *(fix)* Moved the database management services to the *Background* task, to minimise interruptions to DB updates and maintain integrity. ◆ **Favourites**: *(new)* Remembers last used sort selection. ◆ **Favourites**: *(new)* Introducing Anime support. Now a search can use the absolute episode number when available. • Series Settings allows the user to select any available Alias to replace the default Title in searches. ◆ **SearchEngines**: *(new)* Introducing Jackett! You can use the Jackett proxy to access your favourite open/semi-private/private trackers as DuckieTV Search Engines. ◆ **SearchEngines**: *(removed)* IsoHunt.to is gone. ◆ **Standalone**: *(upgrade)* NWJS 25.0 with Chromium 61 and Node 8.4.0 ◆ **TorrentClient**: *(new)* Introducing Aria2 client. ◆ **TorrentClient**: *(new)* Introducing BiglyBT client. ◆ **TorrentClient**: *(fix)* Can now connect with qBitTorrent 3.3.14 (and newer) with CSRF protection. ◆ **TorrentClient**: *(fix)* Can now connect with Deluge 1.3.14 (and newer) with CSRF protection. ◆ **Torrent Dialog [multi-SE]**: *(new)* Remembers last used sort selection. ◆ **Trakt-Sync**: *(upgrade)* When an episode is marked as downloaded it is added to the collected list of a user's Trakt account. ◆ **Trakt-Trending sidepanel**: *(upgrade)* Now using buttons instead of mouse-hover to improve browsing experience. ◆ **Misc**: *Bug fixes*. * v1.1.4 : ◆ Performance: Massive database write performance improvement. ◆ User Interface: Split up favorites and adding mode, introduced 'todo' mode. You can now add multiple shows at once. • (new) Yellow stars now indicate show or season premieres ◆ Images: (fix) switched to Fanart.tv for all images after Trakt.tv ended support ◆ AutoDownload: (new) using global Require/Ignore Keywords • (new) series custom-search-provider option • (new) option to ignore global Quality, Require and Ignore keywords via series custom settings • (new) use series custom search string • (new) use global/custom size min/max • (fix) episodes with date scene names bug • (new) monitor autoDownload activity via status sidepanel • (new) make AD wait until episode has aired before searching • (new) series custom AD additional delay before searching ◆ FastSearch: (new) introducing the fast-search feature. Just start typing and a dialog pops up with the first six matches of your series from favourites, series from Trakt.TV, and the first 9 matches of episodes from favourites and torrent search. ◆ Standalone: (upgrade) nwjs 20.x chromium 56.x Node 7.5.x (fix) linux minimize bug • (new) option to open add-new-torrent panel on torrentHost • (fix) linux and mac multi-systray bug • (fix) defaults for first-time users bug • (new) option to set the color of the system tray icon ◆ TorrentClients: (new) rTorrent and Ktorrent clients • (new) add remove-torrent functionality to all client Interfaces • (fix) Deluge auto-stop and downloaded bugs • (fix) qBittorrent auto-stop bug • (fix) renamed qBittorrent client to qBittorrent (pre 3.2) for clarity • (new) add series custom download path option for torrentClients that support it ◆ SearchEngines: (fix) remove Strike, KAT and Torrentz as they are gone • (new) add 1337x, Idope, IsoHunt, KATcr, LimeTorrents, SkyTorrents, TorrentDownloads, TorrentZ2 and Zooqle • (fix) drop find-random-KAT-mirror feature as rockaproxy is gone • (fix) bug in RarBG causing non-found results after 15 minutes • (new) add 2160p search quality ◆ Favorites: (new) sort menu for name, added, first-aired and not-watched-count • (new) series poster context-menu for mark-all-watched, show/hide from calendar, and remove-series ◆ Series Sidepanel: (new) option to make the episodes-button jump to the first not-watched season • (fix) mark-all-watched did not sync to Trakt.TV • (new) confirm mark-all-watched dialog ◆ Season Sidepanel: (fix) jump to active season ignores specials unless there is no other seasons • (fix) mark-all-watched did not sync to Trakt.TV • (new) confirm mark-all-watched dialog ◆ Episode Sidepanel: (fix) overview text not height limited bug ◆ Calendar: (fix) events multi-episodes badge incorrectly counted hidden specials bug • (new) Series option to ignore global Hide Specials from calendar • (new) events single click to mark episode as watched • (new) Highlight season premiers with gold star ◆ Top10: (fix) invalid-data handling bug ◆ Subtitles: (fix) net::err_empty_response handling bug ◆ Translations: Russian by galeksandrp, updated italian translations by lamaresh, updated Dutch translations ◆ TraktTV: (new) Option to change the frequency of the Episode updates. ◆ TorrentDialog: (new) Option to sort the Seeders, Leechers and Size column • (new) Option to search using all the Search Engines at once • (add) Option to enable Sort menu to sort by Age. ◆ Backup: (new) A Backup can now be automatically scheduled. Choose between Never,Daily,Weekly or the default Monthly. ◆ Misc bug fixes. * v1.1.3 : • Translations: Romanian by honeybunny from Addic7ed, French by Tra-Vis, Norwegian by hexjelly, Spanish by iachopolo • Bug fixes for Torrent Client Integrations • Improve Autodownload torrent search matching • Fixed adding shows with numeric titles • optionally display season and episode on calendar • integrated XEM • added marking all of a days shows as downloaded • Season navigation • settings/display options for standalone minimize to Taskbar or Systray • misc bug fixes. diff --git a/js/controllers/settings/TorrentClients/qBittorrent32plus.js b/js/controllers/settings/TorrentClients/qBittorrent41plus.js similarity index 62% rename from js/controllers/settings/TorrentClients/qBittorrent32plus.js rename to js/controllers/settings/TorrentClients/qBittorrent41plus.js index 5c2756728..34c244c7c 100644 --- a/js/controllers/settings/TorrentClients/qBittorrent32plus.js +++ b/js/controllers/settings/TorrentClients/qBittorrent41plus.js @@ -1,5 +1,5 @@ -DuckieTV.controller('qbt32plusCtrl', ['qBittorrent32plus', 'SettingsService', 'FormlyLoader', - function(qBittorrent32plus, SettingsService, FormlyLoader) { +DuckieTV.controller('qbt41plusCtrl', ['qBittorrent41plus', 'SettingsService', 'FormlyLoader', + function(qBittorrent41plus, SettingsService, FormlyLoader) { var vm = this vm.error = null @@ -16,22 +16,22 @@ DuckieTV.controller('qbt32plusCtrl', ['qBittorrent32plus', 'SettingsService', 'F }) vm.isConnected = function() { - return qBittorrent32plus.isConnected() + return qBittorrent41plus.isConnected() } vm.test = function() { vm.error = false // console.log("Testing settings"); - qBittorrent32plus.Disconnect() - qBittorrent32plus.setConfig(vm.model) - qBittorrent32plus.connect().then(function(connected) { - console.info('qBittorrent 3.2+ connected! (save settings)', connected) + qBittorrent41plus.Disconnect() + qBittorrent41plus.setConfig(vm.model) + qBittorrent41plus.connect().then(function(connected) { + console.info('qBittorrent 4.1+ connected! (save settings)', connected) vm.error = null - qBittorrent32plus.saveConfig() + qBittorrent41plus.saveConfig() window.location.reload() }, function(error) { vm.error = error - console.error('qBittorrent 3.2+ connect error!', error) + console.error('qBittorrent 4.1+ connect error!', error) }) } } diff --git a/js/controllers/settings/TorrentClients/qBittorrentPre32.js b/js/controllers/settings/TorrentClients/qBittorrentPre32.js deleted file mode 100644 index a2c9ef266..000000000 --- a/js/controllers/settings/TorrentClients/qBittorrentPre32.js +++ /dev/null @@ -1,38 +0,0 @@ -DuckieTV.controller('qbtCtrl', ['qBittorrent', 'SettingsService', 'FormlyLoader', - function(qBittorrent, SettingsService, FormlyLoader) { - var vm = this - vm.error = null - - FormlyLoader.load('TorrentClientSettings').then(function(fields) { - vm.model = { - server: SettingsService.get('qbittorrent.server'), - port: SettingsService.get('qbittorrent.port'), - use_auth: SettingsService.get('qbittorrent.use_auth'), - username: SettingsService.get('qbittorrent.username'), - password: SettingsService.get('qbittorrent.password') - } - - vm.fields = fields - }) - - vm.isConnected = function() { - return qBittorrent.isConnected() - } - - vm.test = function() { - vm.error = false - // console.log("Testing settings"); - qBittorrent.Disconnect() - qBittorrent.setConfig(vm.model) - qBittorrent.connect().then(function(connected) { - console.info('qBittorrent (pre3.2) connected! (save settings)', connected) - vm.error = null - qBittorrent.saveConfig() - window.location.reload() - }, function(error) { - vm.error = error - console.error('qBittorrent {pre3.2) connect error!', error) - }) - } - } -]) diff --git a/js/controllers/sidepanel/AboutCtrl.js b/js/controllers/sidepanel/AboutCtrl.js index 5cd0a55b5..8d4452bd7 100644 --- a/js/controllers/sidepanel/AboutCtrl.js +++ b/js/controllers/sidepanel/AboutCtrl.js @@ -201,8 +201,8 @@ DuckieTV.controller('AboutCtrl', ['$scope', '$http', '$injector', 'SettingsServi // dump filtered user preferences, redact passwords var userPrefs = angular.fromJson(localStorage.getItem('userPreferences')) - var unwantedClientKeys = ['aria2', 'biglybt', 'deluge', 'ktorrent', 'qbittorrent', 'qbittorrent32plus', 'rtorrent', 'tixati', 'transmission', 'utorrent', 'utorrentwebui', 'vuze'] - var activeClientKey = localStorage.getItem('torrenting.client').replace(/ /g, '').replace('3.2+', '32plus').replace('(pre3.2)', '').toLowerCase() + var unwantedClientKeys = ['aria2', 'biglybt', 'deluge', 'ktorrent', 'qbittorrent', 'qbittorrent41plus', 'rtorrent', 'tixati', 'transmission', 'utorrent', 'utorrentwebui', 'vuze'] + var activeClientKey = localStorage.getItem('torrenting.client').replace(/ /g, '').replace('4.1+', '41plus').toLowerCase() unwantedClientKeys.splice(unwantedClientKeys.indexOf(activeClientKey), 1) // drop active client from list Object.keys(userPrefs).map(function(key) { // redact passwords diff --git a/js/controllers/sidepanel/TorrentCtrl.js b/js/controllers/sidepanel/TorrentCtrl.js index 80daca866..15a78b675 100644 --- a/js/controllers/sidepanel/TorrentCtrl.js +++ b/js/controllers/sidepanel/TorrentCtrl.js @@ -30,7 +30,7 @@ DuckieTV.controller('TorrentCtrl', ['$rootScope', '$injector', '$filter', 'Ducki } vm.getTorrentClientTemplate = function() { - return DuckieTorrent.getClientName().toLowerCase().replace(/ /g, '').replace('(pre3.2)', 'Pre32').replace(/3.2\+/, '32plus') + return DuckieTorrent.getClientName().toLowerCase().replace(/ /g, '').replace(/4.1\+/, '41plus') } vm.getTorrentsCount = function() { diff --git a/js/services/SettingsService.js b/js/services/SettingsService.js index 0fdef5579..f78411f41 100644 --- a/js/services/SettingsService.js +++ b/js/services/SettingsService.js @@ -156,11 +156,6 @@ DuckieTV.factory('SettingsService', ['$injector', 'availableLanguageKeys', 'cust 'mirror.TorrentDownloads': 'https://www.torrentdownloads.pro', 'mirror.TGx': 'https://torrentgalaxy.to', 'notifications.enabled': true, // chrome notifications for download started/finished - 'qbittorrent.password': 'admin', - 'qbittorrent.port': 8080, - 'qbittorrent.server': 'http://localhost', - 'qbittorrent.use_auth': true, - 'qbittorrent.username': 'admin', 'qbittorrent32plus.password': 'admin', 'qbittorrent32plus.port': 8080, 'qbittorrent32plus.server': 'http://localhost', diff --git a/js/services/TorrentClients/qBittorrentPre32.js b/js/services/TorrentClients/qBittorrent.js similarity index 88% rename from js/services/TorrentClients/qBittorrentPre32.js rename to js/services/TorrentClients/qBittorrent.js index 1e244bb8f..7ee7b5217 100644 --- a/js/services/TorrentClients/qBittorrentPre32.js +++ b/js/services/TorrentClients/qBittorrent.js @@ -2,9 +2,9 @@ * qBittorrent * * API Docs: - * https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-Documentation + * https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-Documentation (appears to have been deleted) * - * Works for both 3.2+ and below. + * base qBt support, for 4.1+ * * - Does not support setting the download directory * - Does not support setting the label @@ -18,28 +18,7 @@ qBittorrentData.extends(TorrentData, { return this.name }, getDownloadSpeed: function() { - if (typeof this.dlspeed === 'string') { - // qBitTorrent < 3.2 - var rate = parseInt(this.dlspeed.split(' ')[0]) - var units = this.dlspeed.split(' ')[1] - switch (units) { - case 'KiB/s': - rate = rate * 1024 - break - case 'MiB/s': - rate = rate * 1024 * 1024 - break - case 'GiB/s': - rate = rate * 1024 * 1024 * 1024 - break - case 'B/s': - default: - } - } else { - // qBitTorrent 3.2+ - rate = this.dlspeed - } - return rate // Bytes/second + return this.dlspeed // Bytes/second }, getProgress: function() { return this.round(this.progress * 100, 1) @@ -72,7 +51,7 @@ qBittorrentData.extends(TorrentData, { }) /** - * qBittorrent < 3.2 client + * qBittorrent client */ DuckieTorrent.factory('qBittorrentRemote', ['BaseTorrentRemote', function(BaseTorrentRemote) { @@ -223,7 +202,7 @@ DuckieTorrent.factory('qBittorrentRemote', ['BaseTorrentRemote', qBittorrent.extends(BaseTorrentClient, {}) var service = new qBittorrent() - service.setName('qBittorrent (pre3.2)') + service.setName('qBittorrent') service.setAPI(new qBittorrentAPI()) service.setRemote(new qBittorrentRemote()) service.setConfigMappings({ @@ -249,11 +228,3 @@ DuckieTorrent.factory('qBittorrentRemote', ['BaseTorrentRemote', return service } ]) - - .run(['DuckieTorrent', 'qBittorrent', 'SettingsService', - function(DuckieTorrent, qBittorrent, SettingsService) { - if (SettingsService.get('torrenting.enabled')) { - DuckieTorrent.register('qBittorrent (pre3.2)', qBittorrent) - } - } - ]) diff --git a/js/services/TorrentClients/qBittorrent32plus.js b/js/services/TorrentClients/qBittorrent32plus.js deleted file mode 100644 index 411b05882..000000000 --- a/js/services/TorrentClients/qBittorrent32plus.js +++ /dev/null @@ -1,288 +0,0 @@ -/** - * qBittorrent32plus >= 3.2 client - * - * API Docs: - * https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-Documentation v3.2.0-v4.0.4 APIv1 - * https://github.com/qbittorrent/qBittorrent/wiki/Web-API-Documentation v4.1+ APIv2 - * - * - Supports setting download directory (After qBittorrent v3.3.1, using APIv1 subversion 7+) - * - Supports setting label (After qBittorrent v3.3.1, using APIv1 subversion 7+) - */ - -DuckieTorrent.factory('qBittorrent32plusAPI', ['qBittorrentAPI', '$http', '$q', - function(qBittorrentAPI, $http, $q) { - var qBittorrent32plusAPI = function() { - qBittorrentAPI.call(this) - this.config.apiVersion = 1 // lets assume the API is v1 to begin with - this.config.apiSubVersion = 0 - } - qBittorrent32plusAPI.extends(qBittorrentAPI, { - login: function() { - var self = this - var method = (self.config.apiVersion == 2) ? 'loginv2' : 'login' - return $http.post(this.getUrl(method), 'username=' + encodeURIComponent(this.config.username) + '&password=' + encodeURIComponent(this.config.password), { - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - 'X-Forwarded-Host': window.location.origin - } - }).then(function(result) { - if (result.data == 'Ok.') { - if (window.debugTSE) console.debug('qBittorrent32plusAPI.login', result.data) - if (self.config.apiVersion == 2) { - return self.request('versionv2').then(function(result) { - var subs = result.data.split('.') - self.config.apiSubVersion = subs[1] - return true - }) - } - return true - } else { - if (window.debugTSE) console.debug('qBittorrent32plusAPI.login', result.data) - throw 'Login failed!' - } - }) - }, - portscan: function() { - var self = this - if (self.config.apiVersion == 2) { - // APIv2 requires a login before any other calls are made - return self.login().then(function() { - return true - }) - } else { - // APIv1 allows us to poll for port then login when found - return this.request('version').then(function(result) { - self.config.apiSubVersion = result.data - return self.login().then(function() { - return true - }) - }, function(err) { - if (err.status == 404) { - // method not found? lets try APIv2 - self.config.apiVersion = 2 - } - return false - }) - } - }, - addMagnet: function(magnetHash, dlPath, label) { - var self = this - var method = (self.config.apiVersion == 2) ? 'addmagnetv2' : 'addmagnet' - if ((self.config.apiVersion == 2) || ((self.config.apiVersion == 1) && (self.config.apiSubVersion > 6))) { - // APIv2 or APIv1 sub > 6 - var fd = new FormData() - fd.append('urls', magnetHash) - if (dlPath !== undefined && dlPath !== null) { - fd.append('savepath', dlPath) - } - if (label !== undefined && label !== null) { - fd.append('category', label) - } - var headers = { - 'Content-Type': undefined, - 'X-Forwarded-Host': window.location.origin - } - return $http.post(this.getUrl(method), fd, { - headers: headers - }).then(function(result) { - if (window.debugTSE) console.debug('qBittorrent32plusAPI.addmagnet', result.data) - }) - } else { - // APIv1 sub < 7 - var headers = { - 'Content-Type': 'application/x-www-form-urlencoded' - } - return $http.post(this.getUrl(method), 'urls=' + encodeURIComponent(magnetHash), { - headers: headers - }) - } - }, - addTorrentByUpload: function(data, infoHash, releaseName, dlPath, label) { - var self = this - var method = (self.config.apiVersion == 2) ? 'addfilev2' : 'addfile' - var headers = { - 'Content-Type': undefined, - 'X-Forwarded-Host': window.location.origin - } - var fd = new FormData() - fd.append('torrents', data, releaseName + '.torrent') - - if ((self.config.apiVersion == 2) || ((self.config.apiVersion == 1) && (self.config.apiSubVersion > 6))) { - // APIv2 or APIv1 sub > 6 - if (dlPath !== undefined && dlPath !== null) { - fd.append('savepath', dlPath) - } - if (label !== undefined && label !== null) { - fd.append('category', label) - } - } - - return $http.post(this.getUrl(method), fd, { - transformRequest: angular.identity, - headers: headers - }).then(function(result) { - if (window.debugTSE) console.debug('qBittorrent32plusAPI.addTorrentByUpload', result.data) - var currentTry = 0 - var maxTries = 5 - // wait for qBittorrent to add the torrent to the list. we poll 5 times until we find it, otherwise abort. - return $q(function(resolve, reject) { - function verifyAdded() { - currentTry++ - self.getTorrents().then(function(result) { - var hash = null - // for each torrent compare the torrent.hash with .torrent infoHash - result.map(function(torrent) { - if (torrent.hash.toUpperCase() == infoHash) { - hash = infoHash - } - }) - if (hash !== null) { - resolve(hash) - } else { - if (currentTry < maxTries) { - setTimeout(verifyAdded, 1000) - } else { - throw 'Hash ' + infoHash + ' not found for torrent ' + releaseName + ' in ' + maxTries + ' tries.' - } - } - }) - } - setTimeout(verifyAdded, 1000) - }) - }) - }, - /** - * qBittorrent APIv2 or APIv1 sub > 6 supports setting the Download Path when adding magnets and .torrents. - */ - isDownloadPathSupported: function() { - var self = this - return ((self.config.apiVersion == 2) || ((self.config.apiVersion == 1) && (self.config.apiSubVersion > 6))) - }, - /** - * qBittorrent APIv2 or APIv1 sub > 6 supports setting the Label when adding magnets and .torrents. - */ - isLabelSupported: function() { - var self = this - return ((self.config.apiVersion == 2) || ((self.config.apiVersion == 1) && (self.config.apiSubVersion > 6))) - }, - remove: function(magnetHash) { - var self = this - if (self.config.apiVersion == 2) { - var fd = new FormData() - fd.append('hashes', magnetHash) - fd.append('deleteFiles', false) - var headers = { - 'Content-Type': undefined, - 'X-Forwarded-Host': window.location.origin - } - return $http.post(this.getUrl('removev2'), fd, { - headers: headers - }).then(function(result) { - if (window.debugTSE) console.debug('qBittorrent32plusAPI.removev2', result.data) - }) - } else { - return $http.post(this.getUrl('remove'), 'hashes=' + encodeURIComponent(magnetHash), { - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - 'X-Forwarded-Host': window.location.origin - } - }) - } - }, - getTorrents: function() { - var self = this - var method = (self.config.apiVersion == 2) ? 'torrentsv2' : 'torrents' - return this.request(method).then(function(data) { - return data.data - }) - }, - getFiles: function(hash) { - var self = this - var method = (self.config.apiVersion == 2) ? 'filesv2' : 'files' - return this.request(method, hash).then(function(data) { - var method = (self.config.apiVersion == 2) ? 'generalv2' : 'general' - return self.request(method, hash).then(function(general) { - data.data.downloaddir = (general.data.save_path) ? general.data.save_path.slice(0, -1) : undefined - return data.data - }) - }) - }, - execute: function(method, id) { - var self = this - var hashkey = 'hash=' - if (self.config.apiVersion == 2) { - hashkey = 'hashes=' - } - if ((self.config.apiVersion == 2) && (self.config.apiSubVersion > 10)) { - method = method + 'v211' - } else { - method = method + 'v2' - } - var headers = { - 'Content-Type': 'application/x-www-form-urlencoded', - 'X-Forwarded-Host': window.location.origin - } - return $http.post(this.getUrl(method), hashkey + id, { - headers: headers - }) - } - }) - return qBittorrent32plusAPI - } -]) - - .factory('qBittorrent32plus', ['BaseTorrentClient', 'qBittorrentRemote', 'qBittorrent32plusAPI', - function(BaseTorrentClient, qBittorrentRemote, qBittorrent32plusAPI) { - var qBittorrent32plus = function() { - BaseTorrentClient.call(this) - } - qBittorrent32plus.extends(BaseTorrentClient, {}) - - var service = new qBittorrent32plus() - service.setName('qBittorrent 3.2+') - service.setAPI(new qBittorrent32plusAPI()) - service.setRemote(new qBittorrentRemote()) - service.setConfigMappings({ - server: 'qbittorrent32plus.server', - port: 'qbittorrent32plus.port', - username: 'qbittorrent32plus.username', - password: 'qbittorrent32plus.password', - use_auth: 'qbittorrent32plus.use_auth' - }) - service.setEndpoints({ - torrents: '/query/torrents', - torrentsv2: '/api/v2/torrents/info', - addmagnet: '/command/download', - addmagnetv2: '/api/v2/torrents/add', - addfile: '/command/upload', - addfilev2: '/api/v2/torrents/add', - resume: '/command/resume', - resumev2: '/api/v2/torrents/resume', - resumev211: '/api/v2/torrents/start', - pause: '/command/pause', - pausev2: '/api/v2/torrents/pause', - pausev211: '/api/v2/torrents/stop', - remove: '/command/delete', - removev2: '/api/v2/torrents/delete', - files: '/query/propertiesFiles/%s', - filesv2: '/api/v2/torrents/files?hash=%s', - general: '/query/propertiesGeneral/%s', - generalv2: '/api/v2/torrents/properties?hash=%s', - version: '/version/api', - versionv2: '/api/v2/app/webapiVersion', - login: '/login', - loginv2: '/api/v2/auth/login' - }) - service.readConfig() - - return service - } - ]) - - .run(['DuckieTorrent', 'qBittorrent32plus', 'SettingsService', - function(DuckieTorrent, qBittorrent32plus, SettingsService) { - if (SettingsService.get('torrenting.enabled')) { - DuckieTorrent.register('qBittorrent 3.2+', qBittorrent32plus) - } - } - ]) diff --git a/js/services/TorrentClients/qBittorrent41plus.js b/js/services/TorrentClients/qBittorrent41plus.js new file mode 100644 index 000000000..71acbf3b7 --- /dev/null +++ b/js/services/TorrentClients/qBittorrent41plus.js @@ -0,0 +1,219 @@ +/** + * qBittorrent41plus >= 4.1 client + * + * API Docs: + * https://github.com/qbittorrent/qBittorrent/wiki/Web-API-Documentation v4.1+ APIv2 (appear to have been deleted) + * + */ + +DuckieTorrent.factory('qBittorrent41plusAPI', ['qBittorrentAPI', '$http', '$q', + function(qBittorrentAPI, $http, $q) { + var qBittorrent41plusAPI = function() { + qBittorrentAPI.call(this) + this.config.apiVersion = 2 + this.config.apiSubVersion = 0 + } + qBittorrent41plusAPI.extends(qBittorrentAPI, { + login: function() { + var self = this + return $http.post(this.getUrl('login'), 'username=' + encodeURIComponent(this.config.username) + '&password=' + encodeURIComponent(this.config.password), { + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + 'X-Forwarded-Host': window.location.origin + } + }).then(function(result) { + if (result.data == 'Ok.') { + if (window.debugTSE) console.debug('qBittorrent41plusAPI.login', result.data) + return self.request('version').then(function(result) { + var subs = result.data.split('.') + self.config.apiSubVersion = subs[1] + return true + }) + } else { + if (window.debugTSE) console.debug('qBittorrent41plusAPI.login', result.data) + throw 'Login failed!' + } + }) + }, + portscan: function() { + var self = this + return self.login().then(function() { + return true + }) + }, + addMagnet: function(magnetHash, dlPath, label) { + var self = this + var fd = new FormData() + fd.append('urls', magnetHash) + if (dlPath !== undefined && dlPath !== null) { + fd.append('savepath', dlPath) + } + if (label !== undefined && label !== null) { + fd.append('category', label) + } + var headers = { + 'Content-Type': undefined, + 'X-Forwarded-Host': window.location.origin + } + return $http.post(this.getUrl('addmagnet'), fd, { + headers: headers + }).then(function(result) { + if (window.debugTSE) console.debug('qBittorrent41plusAPI.addmagnet', result.data) + }) + }, + addTorrentByUpload: function(data, infoHash, releaseName, dlPath, label) { + var self = this + var headers = { + 'Content-Type': undefined, + 'X-Forwarded-Host': window.location.origin + } + var fd = new FormData() + fd.append('torrents', data, releaseName + '.torrent') + + if (dlPath !== undefined && dlPath !== null) { + fd.append('savepath', dlPath) + } + if (label !== undefined && label !== null) { + fd.append('category', label) + } + + return $http.post(this.getUrl('addfile'), fd, { + transformRequest: angular.identity, + headers: headers + }).then(function(result) { + if (window.debugTSE) console.debug('qBittorrent41plusAPI.addTorrentByUpload', result.data) + var currentTry = 0 + var maxTries = 5 + // wait for qBittorrent to add the torrent to the list. we poll 5 times until we find it, otherwise abort. + return $q(function(resolve, reject) { + function verifyAdded() { + currentTry++ + self.getTorrents().then(function(result) { + var hash = null + // for each torrent compare the torrent.hash with .torrent infoHash + result.map(function(torrent) { + if (torrent.hash.toUpperCase() == infoHash) { + hash = infoHash + } + }) + if (hash !== null) { + resolve(hash) + } else { + if (currentTry < maxTries) { + setTimeout(verifyAdded, 1000) + } else { + throw 'Hash ' + infoHash + ' not found for torrent ' + releaseName + ' in ' + maxTries + ' tries.' + } + } + }) + } + setTimeout(verifyAdded, 1000) + }) + }) + }, + /** + * Supports setting the Download Path when adding magnets and .torrents. + */ + isDownloadPathSupported: function() { + return true + }, + /** + * Supports setting the Label when adding magnets and .torrents. + */ + isLabelSupported: function() { + return true + }, + remove: function(magnetHash) { + var self = this + var fd = new FormData() + fd.append('hashes', magnetHash) + fd.append('deleteFiles', false) + var headers = { + 'Content-Type': undefined, + 'X-Forwarded-Host': window.location.origin + } + return $http.post(this.getUrl('remove'), fd, { + headers: headers + }).then(function(result) { + if (window.debugTSE) console.debug('qBittorrent41plusAPI.remove', result.data) + }) + }, + getTorrents: function() { + var self = this + return this.request('torrents').then(function(data) { + return data.data + }) + }, + getFiles: function(hash) { + var self = this + return this.request('files', hash).then(function(data) { + return self.request('general', hash).then(function(general) { + data.data.downloaddir = (general.data.save_path) ? general.data.save_path.slice(0, -1) : undefined + return data.data + }) + }) + }, + execute: function(method, id) { + var self = this + var hashkey = 'hashes=' + if (self.config.apiSubVersion > 10) { + method = method + 'sub11' + } + var headers = { + 'Content-Type': 'application/x-www-form-urlencoded', + 'X-Forwarded-Host': window.location.origin + } + return $http.post(this.getUrl(method), hashkey + id, { + headers: headers + }) + } + }) + return qBittorrent41plusAPI + } +]) + + .factory('qBittorrent41plus', ['BaseTorrentClient', 'qBittorrentRemote', 'qBittorrent41plusAPI', + function(BaseTorrentClient, qBittorrentRemote, qBittorrent41plusAPI) { + var qBittorrent41plus = function() { + BaseTorrentClient.call(this) + } + qBittorrent41plus.extends(BaseTorrentClient, {}) + + var service = new qBittorrent41plus() + service.setName('qBittorrent 4.1+') + service.setAPI(new qBittorrent41plusAPI()) + service.setRemote(new qBittorrentRemote()) + service.setConfigMappings({ + server: 'qbittorrent32plus.server', + port: 'qbittorrent32plus.port', + username: 'qbittorrent32plus.username', + password: 'qbittorrent32plus.password', + use_auth: 'qbittorrent32plus.use_auth' + }) + service.setEndpoints({ + torrents: '/api/v2/torrents/info', + addmagnet: '/api/v2/torrents/add', + addfile: '/api/v2/torrents/add', + resume: '/api/v2/torrents/resume', + resumesub11: '/api/v2/torrents/start', + pause: '/api/v2/torrents/pause', + pausesub11: '/api/v2/torrents/stop', + remove: '/api/v2/torrents/delete', + files: '/api/v2/torrents/files?hash=%s', + general: '/api/v2/torrents/properties?hash=%s', + version: '/api/v2/app/webapiVersion', + login: '/api/v2/auth/login' + }) + service.readConfig() + + return service + } + ]) + + .run(['DuckieTorrent', 'qBittorrent41plus', 'SettingsService', + function(DuckieTorrent, qBittorrent41plus, SettingsService) { + if (SettingsService.get('torrenting.enabled')) { + DuckieTorrent.register('qBittorrent 4.1+', qBittorrent41plus) + } + } + ]) diff --git a/js/services/UpgradeNotificationService.js b/js/services/UpgradeNotificationService.js index b81a36d92..d7c7fab39 100644 --- a/js/services/UpgradeNotificationService.js +++ b/js/services/UpgradeNotificationService.js @@ -26,7 +26,7 @@ DuckieTV.run(['dialogs', '$http', '