torrt 1.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- torrt/__init__.py +3 -0
- torrt/base_bot.py +31 -0
- torrt/base_notifier.py +46 -0
- torrt/base_rpc.py +83 -0
- torrt/base_tracker.py +596 -0
- torrt/bots/__init__.py +0 -0
- torrt/bots/telegram_bot.py +343 -0
- torrt/exceptions.py +30 -0
- torrt/main.py +281 -0
- torrt/notifiers/__init__.py +0 -0
- torrt/notifiers/mail.py +92 -0
- torrt/notifiers/telegram.py +60 -0
- torrt/rpc/__init__.py +1 -0
- torrt/rpc/deluge.py +131 -0
- torrt/rpc/qbittorrent.py +196 -0
- torrt/rpc/transmission.py +167 -0
- torrt/rpc/utorrent.py +160 -0
- torrt/toolbox.py +483 -0
- torrt/trackers/__init__.py +0 -0
- torrt/trackers/anidub.py +94 -0
- torrt/trackers/anilibria.py +178 -0
- torrt/trackers/casstudio.py +58 -0
- torrt/trackers/eniahd.py +46 -0
- torrt/trackers/kinozal.py +54 -0
- torrt/trackers/nnmclub.py +53 -0
- torrt/trackers/rutor.py +41 -0
- torrt/trackers/rutracker.py +85 -0
- torrt/trackers/ytsmx.py +145 -0
- torrt/utils.py +752 -0
- torrt-1.1.0.dist-info/METADATA +83 -0
- torrt-1.1.0.dist-info/RECORD +34 -0
- torrt-1.1.0.dist-info/WHEEL +4 -0
- torrt-1.1.0.dist-info/entry_points.txt +2 -0
- torrt-1.1.0.dist-info/licenses/LICENSE +27 -0
torrt/__init__.py
ADDED
torrt/base_bot.py
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from .exceptions import TorrtBotException
|
|
2
|
+
from .utils import BotClassesRegistry, BotObjectsRegistry, WithSettings
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class BaseBot(WithSettings):
|
|
6
|
+
|
|
7
|
+
config_entry_name: str = 'bots'
|
|
8
|
+
|
|
9
|
+
def __init_subclass__(cls, **kwargs):
|
|
10
|
+
if cls.alias:
|
|
11
|
+
BotClassesRegistry.add(cls)
|
|
12
|
+
|
|
13
|
+
def register(self):
|
|
14
|
+
"""Adds this object intoBotObjectsRegistry."""
|
|
15
|
+
|
|
16
|
+
BotObjectsRegistry.add(self)
|
|
17
|
+
|
|
18
|
+
def test_configuration(self) -> bool:
|
|
19
|
+
"""This should implement a configuration test, for example check given credentials."""
|
|
20
|
+
return False
|
|
21
|
+
|
|
22
|
+
def run(self):
|
|
23
|
+
"""Run bot to receive incoming commands."""
|
|
24
|
+
|
|
25
|
+
class BotRegistrationFailed(TorrtBotException):
|
|
26
|
+
|
|
27
|
+
"""Bot is failed to register (missing dependency or precondition)
|
|
28
|
+
|
|
29
|
+
This exception must be raised during bot class construction
|
|
30
|
+
|
|
31
|
+
"""
|
torrt/base_notifier.py
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
from .utils import NotifierClassesRegistry, NotifierObjectsRegistry, WithSettings
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class BaseNotifier(WithSettings):
|
|
5
|
+
"""Base Notifier class. All Notifier classes should inherit from this."""
|
|
6
|
+
|
|
7
|
+
config_entry_name: str = 'notifiers'
|
|
8
|
+
|
|
9
|
+
def __init_subclass__(cls, **kwargs):
|
|
10
|
+
if cls.alias:
|
|
11
|
+
NotifierClassesRegistry.add(cls)
|
|
12
|
+
|
|
13
|
+
def register(self):
|
|
14
|
+
"""Adds this object into NotificationObjectsRegistry."""
|
|
15
|
+
|
|
16
|
+
NotifierObjectsRegistry.add(self)
|
|
17
|
+
|
|
18
|
+
def send_message(self, msg: str): # pragma: nocover
|
|
19
|
+
"""Send prepared message
|
|
20
|
+
|
|
21
|
+
:param msg: Prepared by notifier backend message
|
|
22
|
+
|
|
23
|
+
"""
|
|
24
|
+
raise NotImplementedError
|
|
25
|
+
|
|
26
|
+
def make_message(self, torrent_data: dict) -> str: # pragma: nocover
|
|
27
|
+
"""Creates message in format suitable for notifier backend
|
|
28
|
+
|
|
29
|
+
:param: torrent_data: dictionary with updated torrents data during the walk operation
|
|
30
|
+
|
|
31
|
+
"""
|
|
32
|
+
raise NotImplementedError
|
|
33
|
+
|
|
34
|
+
def test_configuration(self) -> bool:
|
|
35
|
+
"""This should implement a configuration test, for example check given credentials."""
|
|
36
|
+
|
|
37
|
+
return False
|
|
38
|
+
|
|
39
|
+
def send(self, updated_data):
|
|
40
|
+
"""Send message to user
|
|
41
|
+
|
|
42
|
+
:param: updated_data: dict - dictionary with updated torrents data during the walk operation
|
|
43
|
+
|
|
44
|
+
"""
|
|
45
|
+
msg = self.make_message(updated_data)
|
|
46
|
+
self.send_message(msg)
|
torrt/base_rpc.py
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
from typing import Any, ClassVar
|
|
2
|
+
|
|
3
|
+
from .utils import HttpClient, RPCClassesRegistry, RPCObjectsRegistry, TorrentData, WithSettings
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class BaseRPC(WithSettings):
|
|
7
|
+
"""Base RPC class. All RPC classes should inherit from this."""
|
|
8
|
+
|
|
9
|
+
config_entry_name: str = 'rpc'
|
|
10
|
+
|
|
11
|
+
torrent_fields_map: ClassVar[dict[str, str]] = {}
|
|
12
|
+
"""mapping from torrent fields names in terms of RPC to field names in term of torrt"""
|
|
13
|
+
|
|
14
|
+
enabled: bool = False
|
|
15
|
+
|
|
16
|
+
def __init__(self, **kwargs):
|
|
17
|
+
super().__init__(**kwargs)
|
|
18
|
+
|
|
19
|
+
self.client = HttpClient(
|
|
20
|
+
silence_exceptions=True,
|
|
21
|
+
dump_fname_tpl=f'%(ts)s_{self.__class__.__name__}.json',
|
|
22
|
+
tunnel=False,
|
|
23
|
+
json=True,
|
|
24
|
+
)
|
|
25
|
+
self.logged_in = False
|
|
26
|
+
|
|
27
|
+
def __init_subclass__(cls, **kwargs):
|
|
28
|
+
if cls.alias:
|
|
29
|
+
RPCClassesRegistry.add(cls)
|
|
30
|
+
|
|
31
|
+
def register(self):
|
|
32
|
+
"""Adds this object into RPCObjectsRegistry."""
|
|
33
|
+
|
|
34
|
+
RPCObjectsRegistry.add(self)
|
|
35
|
+
|
|
36
|
+
@classmethod
|
|
37
|
+
def normalize_field_names(cls, torrent_info: dict):
|
|
38
|
+
"""Translates from torrent fields names in terms of RPC to field names in term of torrt.
|
|
39
|
+
Updates accordingly a given torrent_info inplace.
|
|
40
|
+
|
|
41
|
+
:param torrent_info:
|
|
42
|
+
|
|
43
|
+
"""
|
|
44
|
+
for old_name, new_name in cls.torrent_fields_map.items():
|
|
45
|
+
if old_name in torrent_info:
|
|
46
|
+
torrent_info[new_name] = torrent_info[old_name]
|
|
47
|
+
|
|
48
|
+
def method_get_torrents(self, hashes: list[str] | None = None) -> list[dict]: # pragma: nocover
|
|
49
|
+
"""This should return a dictionary with torrents info from RPC.
|
|
50
|
+
Each torrent info should be normalized (see normalize_field_names()).
|
|
51
|
+
|
|
52
|
+
:param hashes: torrent hashes
|
|
53
|
+
|
|
54
|
+
"""
|
|
55
|
+
raise NotImplementedError
|
|
56
|
+
|
|
57
|
+
def method_add_torrent(
|
|
58
|
+
self, torrent: TorrentData, *, download_to: str = '', params: dict | None = None) -> Any: # pragma: nocover
|
|
59
|
+
"""Adds torrent to torrent client using RPC.
|
|
60
|
+
|
|
61
|
+
:param torrent: torrent info
|
|
62
|
+
:param download_to: path to download files from torrent into (in terms of torrent client filesystem)
|
|
63
|
+
:param params: optional information attached to torrent that should be preserved
|
|
64
|
+
|
|
65
|
+
"""
|
|
66
|
+
raise NotImplementedError
|
|
67
|
+
|
|
68
|
+
def method_remove_torrent(self, hash_str: str, *, with_data: bool = False) -> Any: # pragma: nocover
|
|
69
|
+
"""Removes torrent from torrent client using RPC.
|
|
70
|
+
|
|
71
|
+
:param hash_str: torrent identifying hash
|
|
72
|
+
:param with_data: flag to also remove files from torrent
|
|
73
|
+
|
|
74
|
+
"""
|
|
75
|
+
raise NotImplementedError
|
|
76
|
+
|
|
77
|
+
def method_get_version(self) -> str: # pragma: nocover
|
|
78
|
+
"""Returns torrent client API version."""
|
|
79
|
+
raise NotImplementedError
|
|
80
|
+
|
|
81
|
+
def test_configuration(self) -> str:
|
|
82
|
+
# This is to conform to common interface.
|
|
83
|
+
return self.method_get_version()
|