Add qBitTorrent torrent server API implementation
- init torrent.api - Add qBitTorrent class
This commit is contained in:
parent
e8acbd89c7
commit
cf48b90f2a
6
setup.py
6
setup.py
|
@ -7,10 +7,6 @@ setup(
|
||||||
author="ORUDO",
|
author="ORUDO",
|
||||||
author_email="root@orudo.ru",
|
author_email="root@orudo.ru",
|
||||||
description="A simple Telegram bot that will allow you to upload torrent files / magnet links to a remote Torrent server (qBitTorrent, Transmission, etc.)",
|
description="A simple Telegram bot that will allow you to upload torrent files / magnet links to a remote Torrent server (qBitTorrent, Transmission, etc.)",
|
||||||
install_requires=[
|
install_requires=["aiohttp>=3.10.0", "aiofiles>=24.1.0", "aiofiles>=24.1.0"],
|
||||||
"aiohttp>=3.10.0",
|
|
||||||
"aiofiles>=24.1.0",
|
|
||||||
"aiofiles>=24.1.0"
|
|
||||||
],
|
|
||||||
packages=["tubot", "tubot.static", "tubot.torrent"],
|
packages=["tubot", "tubot.static", "tubot.torrent"],
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,130 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
########################################
|
||||||
|
# Torrent Server API's implementations #
|
||||||
|
########################################
|
||||||
|
|
||||||
|
# Imports
|
||||||
|
from http.cookies import SimpleCookie
|
||||||
|
from aiohttp import ClientSession, ClientResponse, FormData
|
||||||
|
from tubot.torrent.abc import TorrentAPI
|
||||||
|
from tubot.torrent.torrents import TorrentFile, TorrentMagnet, TorrentURL
|
||||||
|
from tubot.torrent.types import ServerTypes, TorrentListBuilder
|
||||||
|
from tubot.static.functions import validate
|
||||||
|
|
||||||
|
|
||||||
|
class qBitTorrent(TorrentAPI):
|
||||||
|
"""
|
||||||
|
qBitTorrent API implementation
|
||||||
|
"""
|
||||||
|
|
||||||
|
host: str
|
||||||
|
username: str
|
||||||
|
password: str
|
||||||
|
cookie: SimpleCookie | None
|
||||||
|
_atype = ServerTypes.qBitTorrent
|
||||||
|
|
||||||
|
def __init__(self, host: str, username: str, password: str) -> None:
|
||||||
|
"""
|
||||||
|
:param host: qBitTorrent remote server adress
|
||||||
|
:param username: qBitTorrent remote username
|
||||||
|
:param password: qBitTorrent remote password
|
||||||
|
"""
|
||||||
|
super().__init__()
|
||||||
|
self.cookie = None
|
||||||
|
self.host = host
|
||||||
|
self.username = username
|
||||||
|
self.password = password
|
||||||
|
|
||||||
|
async def _get(
|
||||||
|
self, api: str, cookie: SimpleCookie | None = None
|
||||||
|
) -> ClientResponse:
|
||||||
|
"""
|
||||||
|
Send get request to Torrent server
|
||||||
|
|
||||||
|
:param api: API schema
|
||||||
|
:param cookie: Cookies for auth
|
||||||
|
"""
|
||||||
|
async with ClientSession() as session:
|
||||||
|
return await session.get(url=f"{self.host}/{api}", cookies=cookie)
|
||||||
|
|
||||||
|
async def _post(
|
||||||
|
self,
|
||||||
|
api: str,
|
||||||
|
cookie: SimpleCookie | None = None,
|
||||||
|
data: dict | FormData | None = None,
|
||||||
|
) -> ClientResponse:
|
||||||
|
"""
|
||||||
|
Send post request to Torrent server
|
||||||
|
|
||||||
|
:param api: API schema
|
||||||
|
:param cookie: Cookies for auth
|
||||||
|
:param data: Request data
|
||||||
|
"""
|
||||||
|
async with ClientSession() as session:
|
||||||
|
return await session.post(
|
||||||
|
url=f"{self.host}/{api}", cookies=cookie, data=data
|
||||||
|
)
|
||||||
|
|
||||||
|
async def auth(self) -> bool:
|
||||||
|
"""
|
||||||
|
Generates cookies for auth
|
||||||
|
"""
|
||||||
|
creds = {"username": self.username, "password": self.password}
|
||||||
|
resp = await self._post(api="api/v2/auth/login", data=creds)
|
||||||
|
try:
|
||||||
|
if resp.status == 200:
|
||||||
|
cookies = resp.cookies
|
||||||
|
resp = await self._get(api="api/v2/app/version", cookie=cookies)
|
||||||
|
if resp.status != 200:
|
||||||
|
raise ValueError("Auth error")
|
||||||
|
self.cookie = cookies
|
||||||
|
return True
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def upload_file(self, torrent: TorrentFile) -> None:
|
||||||
|
await validate(self)
|
||||||
|
await validate(torrent, "Bad .torrent file")
|
||||||
|
bytes = await torrent.getbytes()
|
||||||
|
data = FormData()
|
||||||
|
data.add_field(
|
||||||
|
"torrents",
|
||||||
|
bytes,
|
||||||
|
filename=torrent.content,
|
||||||
|
content_type="application/x-bittorrent",
|
||||||
|
)
|
||||||
|
data.add_field("savepath", torrent.dest)
|
||||||
|
await self._post("api/v2/torrents/add", cookie=self.cookie, data=data)
|
||||||
|
|
||||||
|
async def upload_magnet(self, torrent: TorrentMagnet) -> None:
|
||||||
|
await validate(self)
|
||||||
|
await validate(torrent, "Bad magnet link")
|
||||||
|
data = {"urls": torrent.content, "savepath": torrent.dest}
|
||||||
|
await self._post("api/v2/torrents/add", cookie=self.cookie, data=data)
|
||||||
|
|
||||||
|
async def upload_url(self, torrent: TorrentURL) -> None:
|
||||||
|
await validate(self)
|
||||||
|
await validate(torrent, "Bad url")
|
||||||
|
data = {"urls": torrent.content, "savepath": torrent.dest}
|
||||||
|
await self._post("api/v2/torrents/add", cookie=self.cookie, data=data)
|
||||||
|
|
||||||
|
@property
|
||||||
|
async def torrent_list(self) -> str:
|
||||||
|
await validate(self)
|
||||||
|
responce = await self._get(
|
||||||
|
"api/v2/torrents/info?filter=completed,downloading&sort=progress",
|
||||||
|
cookie=self.cookie,
|
||||||
|
)
|
||||||
|
responce = await responce.json()
|
||||||
|
lst = tuple(
|
||||||
|
map(lambda i: (i["name"], i["state"], float(i["progress"])), responce)
|
||||||
|
)
|
||||||
|
lb = TorrentListBuilder()
|
||||||
|
for torrent in lst:
|
||||||
|
lb.append(torrent)
|
||||||
|
return str(lb)
|
||||||
|
|
||||||
|
async def __validate__(self) -> bool:
|
||||||
|
return await self.auth()
|
|
@ -24,9 +24,10 @@ class ServerTypes(Enum):
|
||||||
Types of Torrent servers API's
|
Types of Torrent servers API's
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
qBitTorrent = "qBitTorrent Remote API"
|
||||||
|
|
||||||
|
|
||||||
class TorrentFromServer(object):
|
class TorrentFromServer(object):
|
||||||
|
|
||||||
name: str
|
name: str
|
||||||
state: str
|
state: str
|
||||||
percent: float
|
percent: float
|
||||||
|
@ -34,10 +35,10 @@ class TorrentFromServer(object):
|
||||||
def __init__(self, name: str, state: str, percent: float) -> None:
|
def __init__(self, name: str, state: str, percent: float) -> None:
|
||||||
self.name = name
|
self.name = name
|
||||||
self.state = state
|
self.state = state
|
||||||
self.percent = percent
|
self.percent = round(percent * 100, 1)
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
return f"*Torrent:* {self.name}\n*State:* {self.state}\n*Progress:* {self.percent}"
|
return f"*Torrent:* {self.name}\n*State:* {self.state}\n*Progress:* {self.percent}%"
|
||||||
|
|
||||||
|
|
||||||
class TorrentListBuilder(object):
|
class TorrentListBuilder(object):
|
||||||
|
@ -52,7 +53,7 @@ class TorrentListBuilder(object):
|
||||||
|
|
||||||
def append(self, torrent_data: Iterable) -> "TorrentListBuilder":
|
def append(self, torrent_data: Iterable) -> "TorrentListBuilder":
|
||||||
item = TorrentFromServer(*torrent_data)
|
item = TorrentFromServer(*torrent_data)
|
||||||
self.collection.append(item)
|
self.collection.append(str(item))
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
|
|
Reference in New Issue