jerrymakesjelly / autoremove-torrents

Automatically remove torrents according to your strategies.
https://pypi.org/project/autoremove-torrents/
MIT License
735 stars 121 forks source link

New api support? #46

Closed Jorman closed 4 years ago

Jorman commented 5 years ago

Hi, is possible to support new api from version 4.2? More here https://github.com/qbittorrent/qBittorrent/wiki/Web-API-Documentation#get-torrent-list

sununs commented 4 years ago

嗯,4.2不能登录了

0bo commented 4 years ago

同问,目前QB4.2.1,error log如下供参考:

Thu, 19 Dec 2019 17:14:34 main.py[line:44] INFO Auto Remove Torrents 1.4.6
Thu, 19 Dec 2019 17:14:34 main.py[line:46] INFO Loading configurations...
Thu, 19 Dec 2019 17:14:34 main.py[line:49] INFO Found 1 task(s) in the file.
Thu, 19 Dec 2019 17:14:34 task.py[line:115] INFO Running task 'my_task'...
Thu, 19 Dec 2019 17:14:34 task.py[line:75] INFO Logging in...
Thu, 19 Dec 2019 17:14:34 main.py[line:57] ERROR autoremovetorrents.exception.loginfailure.LoginFailure: The server returned HTTP 404.
Thu, 19 Dec 2019 17:14:34 main.py[line:58] ERROR Task my_task fails. 
Thu, 19 Dec 2019 17:14:34 main.py[line:59] DEBUG Exception Logged
Traceback (most recent call last):
  File "c:\users\xxx\appdata\local\programs\python\python37\lib\site-packages\autoremovetorrents\main.py", line 55, in pre_processor
    Task(task_name, result[task_name], not view_mode).execute()
  File "c:\users\xxx\appdata\local\programs\python\python37\lib\site-packages\autoremovetorrents\task.py", line 116, in execute
    self._login()
  File "c:\users\xxx\appdata\local\programs\python\python37\lib\site-packages\autoremovetorrents\task.py", line 77, in _login
    self._client.login(self._username, self._password)
  File "c:\users\xxx\appdata\local\programs\python\python37\lib\site-packages\autoremovetorrents\client\qbittorrent.py", line 34, in login
    raise LoginFailure('The server returned HTTP %d.' % request.status_code)
autoremovetorrents.exception.loginfailure.LoginFailure: The server returned HTTP 404.
Jorman commented 4 years ago

@colingpt Thanks for this, only one question, are these changes backwards compatible? If not, is possible to make some like this? https://github.com/Flexget/Flexget/pull/2525/commits/c0570d658d0dd776c6dad477bc4f34d51a3b8dfd So in this way either older or newer qBittorrent api can be used

Jorman commented 4 years ago

@colingpt I tried your modification but don't work for me, qBittorrent 4.2.1. I modified the file and this work for me:

#-*- coding:utf-8 -*-
import requests
import time
from ..torrent import Torrent
from ..torrentstatus import TorrentStatus
from ..exception.loginfailure import LoginFailure
from ..exception.deletionfailure import DeletionFailure
from ..exception.connectionfailure import ConnectionFailure

class qBittorrent(object):
    def __init__(self, host):
        # Host
        self._host = host
        # Requests Session
        self._session = requests.Session()
        # Host
        self._host = host
        # Torrents list cache
        self._torrents_list_cache = []
        self._refresh_cycle = 30
        self._refresh_time = 0

    # Login to qBittorrent
    def login(self, username, password):
        try:
            request = self._session.post(self._host+'/api/v2/auth/login', data={'username':username, 'password':password})
        except Exception as exc:
            raise ConnectionFailure(str(exc))

        if request.status_code == 200:
            if request.text == 'Fails.': # Fail
                raise LoginFailure(request.text)
        else:
            raise LoginFailure('The server returned HTTP %d.' % request.status_code)

    # Get qBittorrent Version
    def version(self):
        request = self._session.get(self._host+'/api/v2/app/version')
        return ('qBittorrent %s' % request.text)

    # Get Torrents List
    def torrents_list(self):
        # Request torrents list
        torrent_hash = []
        request = self._session.get(self._host+'/api/v2/torrents/info?filter=all')
        result = request.json()
        # Save to cache
        self._torrents_list_cache = result
        self._refresh_time = time.time()
        # Get hash for each torrent
        for torrent in result:
            torrent_hash.append(torrent['hash'])
        return torrent_hash

    # Get Torrent's Generic Properties
    def _torrent_generic_properties(self, torrent_hash):
        return self._session.get(self._host+'/api/v2/torrents/properties?hash='+torrent_hash).json()

    # Get Torrent's Tracker
    def _torrent_trackers(self, torrent_hash):
        return self._session.get(self._host+'/api/v2/torrents/trackers?hash='+torrent_hash).json()

    # Get Torrent Properties
    def torrent_properties(self, torrent_hash):
        if time.time() - self._refresh_time > self._refresh_cycle: # Out of date
            self.torrents_list()
        for torrent in self._torrents_list_cache:
            if torrent['hash'] == torrent_hash:
                # Get other information
                properties = self._torrent_generic_properties(torrent_hash)
                trackers = self._torrent_trackers(torrent_hash)
                return Torrent(
                    torrent['hash'], torrent['name'],
                    torrent['category'] if 'category' in torrent else torrent['label'],
                    [tracker['url'] for tracker in trackers],
                    qBittorrent._judge_status(torrent['state']), 
                    torrent['state'] == 'stalledUP' or torrent['state'] == 'stalledDL',
                    torrent['size'], torrent['ratio'],
                    properties['total_uploaded'], properties['addition_date'],
                    properties['seeding_time'])

    # Judge Torrent Status (qBittorrent doesn't have stopped status)
    @staticmethod
    def _judge_status(state):
        if state == 'downloading' or state == 'stalledDL':
            status = TorrentStatus.Downloading
        elif state == 'queuedDL' or state == 'queuedUP':
            status = TorrentStatus.Queued
        elif state == 'uploading' or state == 'stalledUP':
            status = TorrentStatus.Uploading
        elif state == 'checkingUP' or state == 'checkingDL':
            status = TorrentStatus.Checking
        elif state == 'pausedUP' or state == 'pausedDL':
            status = TorrentStatus.Paused
        else:
            status = TorrentStatus.Unknown
        return status

    # Remove Torrent
    def remove_torrent(self, torrent_hash):
        self._session.post(self._host+'/api/v2/torrents/delete?hashes=', data={'hashes':torrent_hash}+'&deleteFiles=false')

    # Remove Torrent and Data
    def remove_data(self, torrent_hash):
        self._session.post(self._host+'/api/v2/torrents/delete?hashes=', data={'hashes':torrent_hash}+'&deleteFiles=true')

But is not backward compatible

Jorman commented 4 years ago

False allarm, I got error on removing phase, I'll try to understand why

xiuluo commented 4 years ago

@colingpt I tried your modification but don't work for me, qBittorrent 4.2.1. I modified the file and this work for me:

#-*- coding:utf-8 -*-
import requests
import time
from ..torrent import Torrent
from ..torrentstatus import TorrentStatus
from ..exception.loginfailure import LoginFailure
from ..exception.deletionfailure import DeletionFailure
from ..exception.connectionfailure import ConnectionFailure

class qBittorrent(object):
    def __init__(self, host):
        # Host
        self._host = host
        # Requests Session
        self._session = requests.Session()
        # Host
        self._host = host
        # Torrents list cache
        self._torrents_list_cache = []
        self._refresh_cycle = 30
        self._refresh_time = 0

    # Login to qBittorrent
    def login(self, username, password):
        try:
            request = self._session.post(self._host+'/api/v2/auth/login', data={'username':username, 'password':password})
        except Exception as exc:
            raise ConnectionFailure(str(exc))

        if request.status_code == 200:
            if request.text == 'Fails.': # Fail
                raise LoginFailure(request.text)
        else:
            raise LoginFailure('The server returned HTTP %d.' % request.status_code)

    # Get qBittorrent Version
    def version(self):
        request = self._session.get(self._host+'/api/v2/app/version')
        return ('qBittorrent %s' % request.text)

    # Get Torrents List
    def torrents_list(self):
        # Request torrents list
        torrent_hash = []
        request = self._session.get(self._host+'/api/v2/torrents/info?filter=all')
        result = request.json()
        # Save to cache
        self._torrents_list_cache = result
        self._refresh_time = time.time()
        # Get hash for each torrent
        for torrent in result:
            torrent_hash.append(torrent['hash'])
        return torrent_hash

    # Get Torrent's Generic Properties
    def _torrent_generic_properties(self, torrent_hash):
        return self._session.get(self._host+'/api/v2/torrents/properties?hash='+torrent_hash).json()

    # Get Torrent's Tracker
    def _torrent_trackers(self, torrent_hash):
        return self._session.get(self._host+'/api/v2/torrents/trackers?hash='+torrent_hash).json()

    # Get Torrent Properties
    def torrent_properties(self, torrent_hash):
        if time.time() - self._refresh_time > self._refresh_cycle: # Out of date
            self.torrents_list()
        for torrent in self._torrents_list_cache:
            if torrent['hash'] == torrent_hash:
                # Get other information
                properties = self._torrent_generic_properties(torrent_hash)
                trackers = self._torrent_trackers(torrent_hash)
                return Torrent(
                    torrent['hash'], torrent['name'],
                    torrent['category'] if 'category' in torrent else torrent['label'],
                    [tracker['url'] for tracker in trackers],
                    qBittorrent._judge_status(torrent['state']), 
                    torrent['state'] == 'stalledUP' or torrent['state'] == 'stalledDL',
                    torrent['size'], torrent['ratio'],
                    properties['total_uploaded'], properties['addition_date'],
                    properties['seeding_time'])

    # Judge Torrent Status (qBittorrent doesn't have stopped status)
    @staticmethod
    def _judge_status(state):
        if state == 'downloading' or state == 'stalledDL':
            status = TorrentStatus.Downloading
        elif state == 'queuedDL' or state == 'queuedUP':
            status = TorrentStatus.Queued
        elif state == 'uploading' or state == 'stalledUP':
            status = TorrentStatus.Uploading
        elif state == 'checkingUP' or state == 'checkingDL':
            status = TorrentStatus.Checking
        elif state == 'pausedUP' or state == 'pausedDL':
            status = TorrentStatus.Paused
        else:
            status = TorrentStatus.Unknown
        return status

    # Remove Torrent
    def remove_torrent(self, torrent_hash):
        self._session.post(self._host+'/api/v2/torrents/delete?hashes=', data={'hashes':torrent_hash}+'&deleteFiles=false')

    # Remove Torrent and Data
    def remove_data(self, torrent_hash):
        self._session.post(self._host+'/api/v2/torrents/delete?hashes=', data={'hashes':torrent_hash}+'&deleteFiles=true')

But is not backward compatible

Fri, 03 Jan 2020 15:33:27 main.py[line:57] ERROR TypeError: init() missing 1 required positional argument: 'seeding_time'

Jorman commented 4 years ago

This working for me, just tried, is a mix from @colingpt code

#-*- coding:utf-8 -*-
import requests
import time
from ..torrent import Torrent
from ..torrentstatus import TorrentStatus
from ..exception.loginfailure import LoginFailure
from ..exception.deletionfailure import DeletionFailure
from ..exception.connectionfailure import ConnectionFailure

class qBittorrent(object):
    def __init__(self, host):
        # Host
        self._host = host
        # Requests Session
        self._session = requests.Session()
        # Host
        self._host = host
        # Torrents list cache
        self._torrents_list_cache = []
        self._refresh_cycle = 30
        self._refresh_time = 0

    # Login to qBittorrent
    def login(self, username, password):
        try:
            request = self._session.post(self._host+'/api/v2/auth/login', data={'username':username, 'password':password})
        except Exception as exc:
            raise ConnectionFailure(str(exc))

        if request.status_code == 200:
            if request.text == 'Fails.': # Fail
                raise LoginFailure(request.text)
        else:
            raise LoginFailure('The server returned HTTP %d.' % request.status_code)

    # Get qBittorrent Version
    def version(self):
        request = self._session.get(self._host+'/api/v2/app/version')
        return ('qBittorrent %s' % request.text)

    # Get Torrents List
    def torrents_list(self):
        # Request torrents list
        torrent_hash = []
        request = self._session.get(self._host+'/api/v2/torrents/info?filter=all')
        result = request.json()
        # Save to cache
        self._torrents_list_cache = result
        self._refresh_time = time.time()
        # Get hash for each torrent
        for torrent in result:
            torrent_hash.append(torrent['hash'])
        return torrent_hash

    # Get Torrent's Generic Properties
    def _torrent_generic_properties(self, torrent_hash):
        return self._session.get(self._host+'/api/v2/torrents/properties?hash='+torrent_hash).json()

    # Get Torrent's Tracker
    def _torrent_trackers(self, torrent_hash):
        return self._session.get(self._host+'/api/v2/torrents/trackers?hash='+torrent_hash).json()

    # Get Torrent Properties
    def torrent_properties(self, torrent_hash):
        if time.time() - self._refresh_time > self._refresh_cycle: # Out of date
            self.torrents_list()
        for torrent in self._torrents_list_cache:
            if torrent['hash'] == torrent_hash:
                # Get other information
                properties = self._torrent_generic_properties(torrent_hash)
                trackers = self._torrent_trackers(torrent_hash)
                return Torrent(
                    torrent['hash'], torrent['name'],
                    torrent['category'] if 'category' in torrent else torrent['label'],
                    [tracker['url'] for tracker in trackers],
                    qBittorrent._judge_status(torrent['state']), 
                    torrent['state'] == 'stalledUP' or torrent['state'] == 'stalledDL',
                    torrent['size'], torrent['ratio'],
                    properties['total_uploaded'], properties['addition_date'],
                    properties['seeding_time'])

    # Judge Torrent Status (qBittorrent doesn't have stopped status)
    @staticmethod
    def _judge_status(state):
        if state == 'downloading' or state == 'stalledDL':
            status = TorrentStatus.Downloading
        elif state == 'queuedDL' or state == 'queuedUP':
            status = TorrentStatus.Queued
        elif state == 'uploading' or state == 'stalledUP':
            status = TorrentStatus.Uploading
        elif state == 'checkingUP' or state == 'checkingDL':
            status = TorrentStatus.Checking
        elif state == 'pausedUP' or state == 'pausedDL':
            status = TorrentStatus.Paused
        else:
            status = TorrentStatus.Unknown
        return status

    # Remove Torrent
    def remove_torrent(self, torrent_hash):
        # self._session.post(self._host+'/api/v2/torrents/delete?hashes=', data={'hashes':torrent_hash}+'&deleteFiles=false')
        requests.get(self._host+'/api/v2/torrents/delete?hashes='+torrent_hash+'&deleteFiles=false')    
    # Remove Torrent and Data
    def remove_data(self, torrent_hash):
        # self._session.post(self._host+'/api/v2/torrents/delete?hashes=', data={'hashes':torrent_hash}+'&deleteFiles=true')
        requests.get(self._host+'/api/v2/torrents/delete?hashes='+torrent_hash+'&deleteFiles=true')

Maybe there's a better way to do that, I'm not a programmer so

jerrymakesjelly commented 4 years ago

I will fix this problem as soon as possible.