Aberrant/rtorrent.py

136 lines
3.0 KiB
Python
Raw Normal View History

2019-01-16 12:49:42 -05:00
#!/usr/bin/env python3
"""
This module handles the interface with rTorrent via XMLRPC.
"""
2019-02-14 15:00:21 -05:00
import re
import time
import threading
2019-01-16 12:49:42 -05:00
import xmlrpc.client
2019-02-14 15:00:21 -05:00
NUM_INST = 10
WATCH_HANDLE = None
sp = []
torrents = [[]] * NUM_INST
2019-02-13 10:20:55 -05:00
class Torrent:
def __init__(self, raw):
self.hash = raw[0]
self.name = raw[1]
2019-02-14 15:00:21 -05:00
2019-02-13 10:20:55 -05:00
self.active = raw[2]
self.complete = raw[3]
if not self.active:
self.state = "inactive"
elif self.complete:
self.state = "seeding"
else:
self.state = "leeching"
2019-02-14 15:00:21 -05:00
2019-02-13 10:20:55 -05:00
self.downrate = raw[4]
2019-02-18 15:54:49 -05:00
self.downrate_str = size_units(self.downrate) + '/s'
2019-02-13 10:20:55 -05:00
self.uprate = raw[5]
2019-02-18 15:54:49 -05:00
self.uprate_str = size_units(self.uprate) + '/s'
2019-02-14 15:00:21 -05:00
2019-02-15 07:33:55 -05:00
self.tracker = get_tracker(raw[6])
2019-02-18 15:54:49 -05:00
self.down_total = raw[7]
self.total_size = raw[8]
self.total_size_str = size_units(self.total_size)
self.down_percent = round((self.down_total / self.total_size) * 100, 2)
2019-02-14 15:00:21 -05:00
class Watch(threading.Thread):
"""A thread class that continously queries the rTorrent instances."""
def __init__(self):
super(Watch, self).__init__()
self._stop_event = threading.Event()
def stop(self):
self._stop_event.set()
def stopped(self):
return self._stop_event.is_set()
def run(self):
global torrents
while not self.stopped():
for n in range(NUM_INST):
if self.stopped():
break
torrents[n] = get_all(n)
self._stop_event.wait(2)
2019-01-16 12:49:42 -05:00
2019-02-14 15:00:21 -05:00
2019-02-18 15:54:49 -05:00
def size_units(rate):
"""Helper to assign appropriate prefixes to numbers."""
unit = "B"
if rate > 1024:
rate /= 1024
unit = "KiB"
2019-02-14 15:00:21 -05:00
if rate > 1024:
rate /= 1024
2019-02-18 15:54:49 -05:00
unit = "MiB"
2019-02-14 15:00:21 -05:00
if rate > 1024:
rate /= 1024
2019-02-18 15:54:49 -05:00
unit = "GiB"
2019-02-14 15:00:21 -05:00
rate = round(rate, 1)
return str(rate) + unit
2019-02-15 07:33:55 -05:00
def get_tracker(path):
"""
At present I don't have an efficient way to get the tracker url
with the d.multicall2() function, so we parse it from the
directory path.
"""
return path.split('/')[4]
2019-02-14 15:00:21 -05:00
def all_torrents():
"""Helper that returns a list of all torrents."""
res = []
for item in torrents:
res += item
return res
def get_all(n):
"""Gets all torrent information from a instance and returns it."""
res = sp[n].d.multicall2('', 'main',
2019-02-13 10:20:55 -05:00
'd.hash=',
'd.name=',
'd.is_active=',
'd.complete=',
'd.down.rate=',
'd.up.rate=',
2019-02-15 07:33:55 -05:00
'd.directory=',
2019-02-18 15:54:49 -05:00
'd.completed_bytes=',
'd.size_bytes=',
2019-02-13 10:20:55 -05:00
)
2019-02-14 15:00:21 -05:00
return [Torrent(raw) for raw in res]
def init():
"""Initializes the rTorrent interface."""
global WATCH_HANDLE
2019-02-18 15:54:49 -05:00
global sp
for n in range(NUM_INST):
s = xmlrpc.client.ServerProxy(f"http://localhost:8000/RPC{n}")
sp.append(s)
2019-02-14 15:00:21 -05:00
WATCH_HANDLE = Watch()
WATCH_HANDLE.start()
def stop_watch(sig, frame):
"""Stops the watch thread."""
global WATCH_HANDLE
WATCH_HANDLE.stop()
2019-01-16 12:49:42 -05:00
def get_active():
2019-02-13 10:20:55 -05:00
"""Returns all actively seeding or leeching torrents."""
2019-02-14 15:00:21 -05:00
active = [t for t in all_torrents() if t.downrate or t.uprate]
2019-02-13 10:20:55 -05:00
return active
2019-02-18 10:32:19 -05:00
def get_stats():
"""Returns various statistical information about the torrents."""
trackers = [t.tracker for t in all_torrents()]
tracker_stats = {tr: trackers.count(tr) for tr in set(trackers)}
tracker_stats = dict(sorted(tracker_stats.items()))
tracker_stats['total'] = len(trackers)
return tracker_stats