Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions monitorrent/plugin_managers.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,20 @@ def find_torrent(self, torrent_hash):
result = self.default_client.find_torrent(torrent_hash)
return result or False

def get_download_status(self, client_name):
client = self.get_client(client_name)
result = client.get_download_status()
return result or False

def get_download_status_by_id(self, torrent_id):
"""

:type torrent_id: str
"""
if self.default_client is None:
return False
return self.default_client.get_download_status_by_hash(torrent_id)

def add_torrent(self, torrent, topic_settings):
"""
:type torrent: str
Expand Down
37 changes: 37 additions & 0 deletions monitorrent/plugins/clients/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,43 @@
from enum import Enum

from monitorrent.plugins.trackers import Topic


class TorrentDownloadStatus(Enum):
Queued = 1,
Preparing = 2,
Checking = 3,
Downloading = 5,
Verifying = 6,
Finished = 7,
Seeding = 8,
Paused = 9,
Error = 10,
Unknown = 20


class DownloadStatus(dict):
def __init__(self, downloaded_bytes, total_bytes, download_speed, upload_speed, torrent_status, progress, ratio):
"""
:type downloaded_bytes: int
:type total_bytes: int
:type download_speed: int
:type upload_speed: int
:type torrent_status: TorrentDownloadStatus
:type progress: float
:type ratio: float
"""

super(DownloadStatus, self).__init__()
self.downloaded_bytes = downloaded_bytes
self.total_bytes = total_bytes
self.download_speed = download_speed
self.upload_speed = upload_speed
self.torrent_status = torrent_status
self.progress = progress
self.ratio = ratio


class TopicSettings(object):
download_dir = None

Expand Down
52 changes: 51 additions & 1 deletion monitorrent/plugins/clients/deluge.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import six
import base64

import structlog
Expand All @@ -9,6 +8,8 @@
from monitorrent.plugin_managers import register_plugin
from datetime import datetime

from monitorrent.plugins.clients import DownloadStatus, TorrentDownloadStatus

log = structlog.get_logger()


Expand All @@ -22,6 +23,23 @@ class DelugeCredentials(Base):
password = Column(String, nullable=True)


status_mapping = {
"Queued": TorrentDownloadStatus.Queued,
"Downloading": TorrentDownloadStatus.Downloading,
"Seeding": TorrentDownloadStatus.Seeding,
"Paused": TorrentDownloadStatus.Paused,
"Checking": TorrentDownloadStatus.Checking,
"Error": TorrentDownloadStatus.Error,
}


def get_status(status, is_paused):
if is_paused:
return TorrentDownloadStatus.Paused
else:
return status_mapping[status]


class DelugeClientPlugin(object):
name = "deluge"
form = [{
Expand Down Expand Up @@ -139,5 +157,37 @@ def remove_torrent(self, torrent_hash):
return client.call("core.remove_torrent",
torrent_hash.lower(), False)

def get_download_status(self):
client = self._get_client()
client.connect()
result = client.call("core.get_torrents_status",
{}, [])
statuses = {}
for key, value in result.items():
statuses[key.decode("utf-8")] = DownloadStatus(value[b'total_done'], value[b'total_size'],
value[b'download_payload_rate'],
value[b'upload_payload_rate'],
get_status(value[b'state'].decode("utf-8"),
value[b'paused']),
value[b'progress'], value[b'ratio'])
return statuses

def get_download_status_by_hash(self, torrent_hash):
client = self._get_client()
lower_hash = torrent_hash.lower()
if not client:
return False
client.connect()
result = client.call("core.get_torrents_status",
{'hash': lower_hash}, ['total_done', 'total_size', 'download_payload_rate',
'upload_payload_rate', 'state', 'progress'])
value = result.popitem()[1]
return DownloadStatus(value[b'total_done'], value[b'total_size'],
value[b'download_payload_rate'],
value[b'upload_payload_rate'],
get_status(value[b'state'].decode("utf-8"),
value[b'paused']),
value[b'progress'], value[b'ratio'])


register_plugin('client', 'deluge', DelugeClientPlugin())
7 changes: 7 additions & 0 deletions monitorrent/plugins/clients/downloader.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from sqlalchemy import Column, Integer, String
from monitorrent.db import Base, DBSession
from monitorrent.plugin_managers import register_plugin
from monitorrent.plugins.clients import DownloadStatus, TorrentDownloadStatus
from monitorrent.utils.bittorrent_ex import Torrent
import base64

Expand Down Expand Up @@ -108,4 +109,10 @@ def remove_torrent(self, torrent_hash):
except OSError:
return False

def get_download_status(self):
return {"": DownloadStatus(0, 0, 0, 0, TorrentDownloadStatus.Unknown, 0, 0)}

def get_download_status_by_hash(self, torrent_hash):
return DownloadStatus(0, 0, 0, 0, TorrentDownloadStatus.Unknown, 0, 0)

register_plugin('client', DownloaderPlugin.name, DownloaderPlugin())
44 changes: 44 additions & 0 deletions monitorrent/plugins/clients/qbittorrent.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,27 @@
from datetime import datetime
import dateutil.parser

from monitorrent.plugins.clients import DownloadStatus, TorrentDownloadStatus

status_mapping = {
"queuedUP": TorrentDownloadStatus.Queued,
"queuedDL": TorrentDownloadStatus.Queued,
"stalledDL": TorrentDownloadStatus.Downloading,
"metaDL": TorrentDownloadStatus.Downloading,
"downloading": TorrentDownloadStatus.Downloading,
"stalledUP": TorrentDownloadStatus.Seeding,
"uploading": TorrentDownloadStatus.Seeding,
"pausedDL": TorrentDownloadStatus.Paused,
"pausedUP": TorrentDownloadStatus.Paused,
"checkingUP": TorrentDownloadStatus.Checking,
"checkingDL": TorrentDownloadStatus.Checking,
"error": TorrentDownloadStatus.Error,
}


def get_status(status):
return status_mapping[status]


class QBittorrentCredentials(Base):
__tablename__ = "qbittorrent_credentials"
Expand Down Expand Up @@ -167,5 +188,28 @@ def remove_torrent(self, torrent_hash):
r = parameters['session'].post(parameters['target'] + "command/delete", data=payload)
return r.status_code == 200

def get_download_status(self):
parameters = self._get_params()
response = parameters['session'].get(parameters['target'] + "query/torrents/")
response.raise_for_status()
result = response.json()
torrents = {}
for torrent in result:
torrents[torrent['hash']] = DownloadStatus(torrent['progress'] * torrent['size'], torrent['size'],
torrent['dlspeed'],
torrent['upspeed'], get_status(torrent['state']),
torrent['progress'], torrent['ratio'])
return torrents

def get_download_status_by_hash(self, torrent_hash):
parameters = self._get_params()
torrent_hash = torrent_hash.lower()
response = parameters['session'].get(parameters['target'] + "query/propertiesGeneral/" + torrent_hash)
response.raise_for_status()
result = response.json()
return DownloadStatus(result['total_downloaded'], result['total_size'], result['dl_speed'],
result['up_speed'], TorrentDownloadStatus.Unknown,
result['total_downloaded'] / result['total_size'] * 100, result['share_ratio'])


register_plugin('client', 'qbittorrent', QBittorrentClientPlugin())
32 changes: 32 additions & 0 deletions monitorrent/plugins/clients/transmission.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,20 @@
from monitorrent.plugin_managers import register_plugin
import base64

from monitorrent.plugins.clients import DownloadStatus, TorrentDownloadStatus

status_mapping = {
"stopped": TorrentDownloadStatus.Paused,
"check pending": TorrentDownloadStatus.Checking,
"checking": TorrentDownloadStatus.Checking,
"downloading": TorrentDownloadStatus.Downloading,
"seeding": TorrentDownloadStatus.Seeding
}


def get_status(status):
return status_mapping[status]


class TransmissionCredentials(Base):
__tablename__ = "transmission_credentials"
Expand Down Expand Up @@ -115,4 +129,22 @@ def remove_torrent(self, torrent_hash):
client.remove_torrent(torrent_hash.lower(), delete_data=False)
return True

def get_download_status(self):
client = self.check_connection()
torrents = client.get_torrents(None, [])
result = {}
for torrent in torrents:
result[torrent.hashString] = DownloadStatus(torrent.downloadedEver, torrent.totalSize,
torrent.rateDownload,
torrent.rateUpload,
get_status(torrent.status), torrent.progress, torrent.ratio)
return result

def get_download_status_by_hash(self, torrent_hash):
client = self.check_connection()
torrent = client.get_torrent(torrent_hash.lower(), [])
return DownloadStatus(torrent.downloadedEver, torrent.totalSize, torrent.rateDownload, torrent.rateUpload,
get_status(torrent.status), torrent.progress, torrent.ratio)


register_plugin('client', 'transmission', TransmissionClientPlugin())
56 changes: 56 additions & 0 deletions monitorrent/plugins/clients/utorrent.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,45 @@

import json

from aenum import IntFlag

import requests
from io import BytesIO
from sqlalchemy import Column, Integer, String

from monitorrent.db import Base, DBSession
from monitorrent.plugin_managers import register_plugin
from monitorrent.plugins.clients import DownloadStatus, TorrentDownloadStatus
from monitorrent.utils.soup import get_soup


class StatusFlags(IntFlag):
Started = 1,
Checking = 2,
StartAfterCheck = 4,
Checked = 8,
Error = 16,
Paused = 32,
Queued = 64,
Loaded = 128


def get_status(status):
if StatusFlags.Error in status:
return TorrentDownloadStatus.Error
elif StatusFlags.Paused in status:
return TorrentDownloadStatus.Paused
elif StatusFlags.Started in status:
return TorrentDownloadStatus.Downloading
elif StatusFlags.Checking in status:
return TorrentDownloadStatus.Checking
elif StatusFlags.Queued in status:
return TorrentDownloadStatus.Queued
elif StatusFlags.Checked in status:
return TorrentDownloadStatus.Paused



class UTorrentCredentials(Base):
__tablename__ = "utorrent_credentials"

Expand Down Expand Up @@ -137,4 +167,30 @@ def remove_torrent(self, torrent_hash):
parameters['session'].get(parameters['target'], params=payload)
return True

def get_download_status(self):
parameters = self._get_params()
payload = {"list": '1', "token": parameters["token"]}
torrents = parameters['session'].get(parameters['target'],
params=payload)
array = json.loads(torrents.text)['torrents']
result = {}
for torrent in array:
result[torrent[0]] = DownloadStatus(torrent[5], torrent[3], torrent[9], torrent[8],
get_status(StatusFlags(torrent[1])),
float(torrent[4]) / 10.0, torrent[7])
return result

def get_download_status_by_hash(self, torrent_hash):
parameters = self._get_params()

payload = {"list": '1', "token": parameters["token"]}
torrents = parameters['session'].get(parameters['target'],
params=payload)
array = json.loads(torrents.text)['torrents']
torrent = next(torrent for torrent in array if torrent[0] == torrent_hash)
if torrent:
return DownloadStatus(torrent[5], torrent[3], torrent[9], torrent[8], get_status(StatusFlags(torrent[1])),
float(torrent[4]) / 10.0, torrent[7])


register_plugin('client', 'utorrent', UTorrentClientPlugin())
43 changes: 42 additions & 1 deletion monitorrent/rest/clients.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import json
from builtins import str
from builtins import object
import falcon
Expand Down Expand Up @@ -56,7 +57,21 @@ def on_put(self, req, resp, client):
resp.status = falcon.HTTP_NO_CONTENT


# noinspection PyUnusedLocal
class TorrentStatus(object):
def __init__(self, clients_manager):
"""
:type clients_manager: ClientsManager
"""
self.clients_manager = clients_manager

def on_get(self, req, resp, torrent_hash):
"""

:type torrent_hash: str
"""
resp.json = self.clients_manager.get_download_status_by_id(torrent_hash).__dict__ # noinspection PyUnusedLocal


class ClientCheck(object):
def __init__(self, clients_manager):
"""
Expand Down Expand Up @@ -125,4 +140,30 @@ def on_put(self, req, resp, client):
except KeyError as e:
log.error("Client could not be found", client=client, exception=str(e))
raise falcon.HTTPNotFound(title='Client plugin \'{0}\' not found'.format(client), description=str(e))
except Exception as e:
log.error("An error has occurred", exception=str(e))
raise falcon.HTTPInternalServerError(title='A server has encountered an error', description=str(e))
resp.status = falcon.HTTP_NO_CONTENT


class ClientStatus(object):
def __init__(self, clients_manager):
"""
:type clients_manager: ClientsManager
"""
self.clients_manager = clients_manager

def on_get(self, req, resp, client):
try:
result = self.clients_manager.get_download_status(client)
result_dict = {}
for key, value in result.items():
result_dict[key] = value.__dict__
resp.json = result_dict
except KeyError as e:
log.error("Client could not be found", client=client, exception=str(e))
raise falcon.HTTPNotFound(title='Client plugin \'{0}\' not found'.format(client), description=str(e))
except Exception as e:
log.error("An error has occurred", exception=str(e))
raise falcon.HTTPInternalServerError(title='A server has encountered an error', description=str(e))
resp.status = falcon.HTTP_OK
Loading