Add qBittorrent support.

This commit is contained in:
AB
2021-11-23 01:41:33 +03:00
parent b5ffccd7cc
commit b1e26ca591
10 changed files with 178 additions and 75 deletions

View File

@ -1 +1 @@
__version__ = "0.1.2"
__version__ = "0.2.0"

View File

@ -6,10 +6,10 @@ from urllib import parse
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update
from telegram.ext import Updater, MessageHandler, CommandHandler, filters, CallbackQueryHandler, CallbackContext
from .torrent_clients import add_client, detect_client, easy_send
from .notify import update_watcher
from .rutracker import Torrent
from .tools import format_topic
from .transmission import easy_send
logging.basicConfig(
level=logging.INFO,
@ -88,42 +88,28 @@ def main():
"Got /client request from user [%s] %s",
u_id,
update.message.from_user.username)
try:
addr = update.message.text.split()[1]
log.info("Client Transmission RPC address - %s", addr)
tr = parse.urlparse(addr)
scheme = tr.scheme if tr.scheme else False
hostname = tr.hostname if tr.hostname else False
username = tr.username if tr.username else False
password = tr.password if tr.password else False
path = tr.path if tr.path else '/transmission/rpc'
port = tr.port if tr.port else (80 if scheme == 'http' else 443)
if not scheme or not hostname:
update.message.reply_text(
f'Can\'t understand : <b>{update.message.text}</b>. '
'Send transmission RPC address like <b>http(s)://[user:pass]host[:port][/transmission/rpc]</b>',
parse_mode='HTML',
disable_web_page_preview=True)
return
except:
if len(update.message.text.split()) > 1:
msg = add_client(update.message.text.split()[1], u_id)
update.message.reply_text(msg)
else:
tr_client = Torrent().db.get_client_rpc(u_id)
if tr_client:
tr_line = f"Your client: <code>{tr_client[0]}://{tr_client[1]}:{tr_client[2]}{tr_client[5]}</code>\n" \
log.info("tr_client: %s", tr_client)
try:
user_pass = f"{tr_client[3]}:{tr_client[4]}@" if tr_client[3] and tr_client[4] else ""
tr_client_check = detect_client(f"{tr_client[0]}://{user_pass}{tr_client[1]}:{tr_client[2]}{tr_client[5] if tr_client[5] != None else ''}")
except:
tr_client_check = False
if tr_client and tr_client_check:
tr_line = f"Your have configured client.\nURL: <code>{tr_client[0]}://{tr_client[1]}:{tr_client[2]}{tr_client[5] if tr_client[5] != None else ''}</code>\n" \
f"Client: <code>{tr_client_check}</code>\nStatus: <code>Works</code>\n" \
r"/delete_client"
elif tr_client:
tr_line = f"Your have configured client.\nURL: <code>{tr_client[0]}://{tr_client[1]}:{tr_client[2]}{tr_client[5] if tr_client[5] != None else ''}</code>\n" \
f"Client: <code>{tr_client_check}</code>\nStatus: <code>Conenction failed!</code>\n" \
r"/delete_client"
else:
tr_line = False
update.message.reply_text(
'Gaspar can add new topics to your private Transmission server. '
'Send transmission RPC address like \n<b>http(s)://[user:pass]host[:port][/transmission/rpc]</b>\n'
f'{tr_line if tr_line else "You have no configured client."}',
parse_mode='HTML',
disable_web_page_preview=True)
return
if Torrent().db.add_client_rpc(u_id, scheme, hostname, port, username, password, path):
update.message.reply_text(f'Client reachable and saved.')
else:
update.message.reply_text(f'Client unreachable.')
tr_line = "You have no configured client."
update.message.reply_text(tr_line, parse_mode='HTML', disable_web_page_preview=True)
def delete_client(update, context):
log.info(
@ -147,7 +133,7 @@ def main():
def button(update: Update, context: CallbackContext) -> None:
query = update.callback_query
u_id = query.message.chat['id']
torrent_id = query.data.split('.')[1]
torrent = Torrent(torrent_id)
@ -164,7 +150,7 @@ def main():
query.edit_message_text(text=f"{msg}", parse_mode='HTML',
disable_web_page_preview=True)
else:
easy_send(client_id=query.from_user, torent=torrent)
easy_send(user_id=u_id, torrent_hash=torrent.meta['info_hash'])
query.answer()
query.edit_message_text(text=f"{msg}📨 <b>Sent to RPC /client</b>", parse_mode='HTML',
disable_web_page_preview=True)

View File

@ -33,9 +33,10 @@ class DataBase:
"""
self.scheme = os.environ.get('TG_SCHEME') if os.environ.get('TG_SCHEME') else '/usr/share/gaspar/scheme.sql'
self.basefile = os.environ.get('TG_DB') if os.environ.get('TG_DB') else '/usr/share/gaspar/data.sqlite'
log.debug("self.scheme: %s, self.basefile: %s", self.scheme, self.basefile)
try:
conn = self.connect()
log.debig("Using '%s' base file.", os.path.realpath(self.basefile))
log.debug("Using '%s' base file.", os.path.realpath(self.basefile))
except:
log.debug('Could not connect to DataBase.')
return None
@ -111,18 +112,17 @@ class DataBase:
self.execute(sql, attrs)
def add_client_rpc(self, user_id, scheme, hostname, port, username, password, path):
if check_connection(scheme, hostname, port, username, password, path):
sql = """INSERT OR REPLACE INTO tr_clients(user_id, scheme, hostname, port, username, password, path)
VALUES(?, ?, ?, ?, ?, ?, ?);"""
self.execute(sql, (user_id, scheme, hostname, port, username, password, path))
return True
else:
return False
sql = """INSERT OR REPLACE INTO tr_clients(user_id, scheme, hostname, port, username, password, path)
VALUES(?, ?, ?, ?, ?, ?, ?);"""
log.info("%s", (user_id, scheme, hostname, port, username, password, path))
x = self.execute(sql, (user_id, scheme, hostname, port, username, password, path))
log.info("add_client_rpc: %s", x)
return True
def get_client_rpc(self, user_id):
sql = "SELECT scheme, hostname, port, username, password, path FROM tr_clients WHERE user_id = ?"
res = self.execute(sql, (user_id,))
if len(res):
if res:
return self.execute(sql, (user_id,))[0]
else:
return False
@ -230,14 +230,15 @@ class DataBase:
torrents t JOIN alerts a ON a.tor_id = t.id GROUP BY t.id"""
raw = self.execute(sql, ())
alerts = list()
for alert in raw:
tmp = dict()
tmp['id'] = alert[3]
tmp['reg_time'] = alert[1]
tmp['topic_title'] = alert[2]
tmp['size'] = alert[0]
tmp['info_hash'] = alert[4]
alerts.append(tmp)
if not isinstance(raw, int):
for alert in raw:
tmp = dict()
tmp['id'] = alert[3]
tmp['reg_time'] = alert[1]
tmp['topic_title'] = alert[2]
tmp['size'] = alert[0]
tmp['info_hash'] = alert[4]
alerts.append(tmp)
return alerts
def get_subscribers(self, tor_id):

View File

@ -5,7 +5,7 @@ from datetime import datetime
from .rutracker import Torrent
from .tools import format_topic
from .transmission import send_to_client_rpc
from .torrent_clients import easy_send
UPDATE_INTERVAL = 2 * 60 * 60 # in secs.
@ -58,8 +58,8 @@ def update_watcher(bot):
for sub in subs:
try:
scheme, hostname, port, username, password, path = torrent.db.get_client_rpc(sub)
if send_to_client_rpc(scheme, hostname, port, username, password, path, torrent.meta['info_hash']):
log.info("Push update to client Transmission RPC for %s", torrent.meta['info_hash'])
if easy_send(torrent.meta['info_hash'], sub):
log.info("Push update to client %s", torrent.meta['info_hash'])
msg = f"{msg}📨 <b>Sent to RPC /client</b>"
else:
log.warning("Failed push update to client Transmission RPC for %s",

29
gaspar/qbittorrent.py Normal file
View File

@ -0,0 +1,29 @@
import qbittorrentapi as qbt
import logging
log = logging.getLogger(__name__)
def easy_send(torent, client_id):
try:
scheme, hostname, port, username, password, path = torent.db.get_client_rpc(client_id['id'])
if send_to_client_rpc(scheme, hostname, port, username, password, path, torent.meta['info_hash']):
log.info("Push update to qBittorrent client for %s", torent.meta['topic_title'])
except Exception as e:
log.warning("Failed push update to qBittorrent client for %s: %s",
torent.meta['topic_title'], e)
def send_to_client_rpc(scheme, hostname, port, username, password, path, tor_hash):
try:
host = f"{scheme}://{hostname}{path if path != None else ''}"
c = qbt.Client(
host=host,
port=port,
username=username,
password=password)
m = f'magnet:?xt=urn:btih:{tor_hash}'
c.torrents_add(urls=m)
return True
except Excepion as exc:
log.warn("Failed to send to qBittorrent: %s", host)
return False

View File

@ -37,13 +37,13 @@ CREATE TABLE IF NOT EXISTS "alerts" (
UNIQUE(user_id, tor_id)
);
CREATE TABLE IF NOT EXISTS "tr_clients" (
user_id TEXT,
scheme TEXT,
hostname TEXT,
port TEXT,
username TEXT,
password TEXT,
path TEXT,
user_id TEXT,
scheme TEXT,
hostname TEXT,
port INTEGER,
username TEXT DEFAULT NULL,
password TEXT DEFAULT NULL,
path TEXT,
UNIQUE(user_id)
);
COMMIT;

96
gaspar/torrent_clients.py Normal file
View File

@ -0,0 +1,96 @@
#from .transmission import easy_send
#from transmission_rpc import Client
import qbittorrentapi as qbt
import transmission_rpc as transm
from urllib import parse
import logging
from .rutracker import Torrent
from .transmission import send_to_client_rpc as send_to_transm
from .qbittorrent import send_to_client_rpc as send_to_qbt
log = logging.getLogger(__name__)
def easy_send(torrent_hash, user_id):
try:
torrent = Torrent()
scheme, hostname, port, username, password, path = torrent.db.get_client_rpc(user_id)
user_pass = f"{username}:{password}@" if password and username else ""
tr_client_check = detect_client(f"{scheme}://{user_pass}{hostname}:{port}{path if path != None else ''}")
if tr_client_check == "Transmission":
if send_to_transm(scheme, hostname, port, username, password, path, torrent_hash):
log.info(f"Push update to client {tr_client_check} RPC for %s", torrent_hash)
elif tr_client_check == "qBittorrent":
if send_to_qbt(scheme, hostname, port, username, password, path, torrent_hash):
log.info(f"Push update to client {tr_client_check} RPC for %s", torrent_hash)
else:
return False
except Exception as e:
log.warning("Failed push update to client for %s: %s",
torrent_hash, e)
return True
def _parse_address(address):
client = {}
try:
tr = parse.urlparse(address)
client["scheme"] = tr.scheme if tr.scheme else False
client["hostname"] = tr.hostname if tr.hostname else False
client["username"] = tr.username if tr.username else None
client["password"] = tr.password if tr.password else None
client["path"] = tr.path if tr.path else None
client["port"] = tr.port if tr.port else (80 if client["scheme"] == 'http' else 443)
except Exception as e:
log.debug("_parse_address: %s", e)
pass
return client
def detect_client(address):
client = False
tr = _parse_address(address)
# Check for qBittorrent v4.1.0+
try:
qbt_client = qbt.Client(
host=f"{tr['scheme']}://{tr['hostname']}",
port=tr['port'],
username=tr['username'],
password=tr['password'])
try:
qbt_client.auth_log_in()
except qbt.LoginFailed as e:
pass
client = "qBittorrent"
except Exception as e:
log.debug("detect_client.qBittorrent: %s", e)
pass
# Check for Transmission
try:
c = transm.Client(
host=tr['hostname'],
port=tr['port'],
username=tr['username'],
password=tr['password'],
protocol=tr['scheme'],
path=tr['path'])
c.rpc_version
client = "Transmission"
except Exception as e:
log.debug("detect_client.Transmission: %s", e)
pass
log.info(f"Detected {client}")
return client
def add_client(address, u_id):
tr = _parse_address(address)
client = detect_client(address)
if not client:
return client
if Torrent().db.add_client_rpc(
u_id,
tr['scheme'],
tr['hostname'],
tr['port'],
tr['username'],
tr['password'],
tr['path']):
return f"Added {client}"

View File

@ -3,16 +3,6 @@ import logging
log = logging.getLogger(__name__)
def easy_send(torent, client_id):
try:
scheme, hostname, port, username, password, path = torent.db.get_client_rpc(client_id['id'])
if send_to_client_rpc(scheme, hostname, port, username, password, path, torent.meta['info_hash']):
log.info("Push update to client Transmission RPC for %s", torent.meta['topic_title'])
except Exception as e:
log.warning("Failed push update to client Transmission RPC for %s: %s",
torent.meta['topic_title'], e)
def send_to_client_rpc(scheme, hostname, port, username, password, path, tor_hash):
try:
c = Client(

View File

@ -1,2 +1,3 @@
python-telegram-bot==13.4
transmission-rpc==2.0.4
qbittorrent-api==v2021.8.23

View File

@ -28,7 +28,7 @@ setup(
packages=['gaspar'],
long_description=read('README'),
classifiers=[
"Development Status :: 3 - Alpha",
"Development Status :: 3 - Beta",
"Topic :: Utilities",
],
entry_points={