mirror of
https://github.com/house-of-vanity/gaspar.git
synced 2025-07-06 10:14:07 +00:00
Add qBittorrent support.
This commit is contained in:
@ -1 +1 @@
|
||||
__version__ = "0.1.2"
|
||||
__version__ = "0.2.0"
|
||||
|
@ -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)
|
@ -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):
|
||||
|
@ -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
29
gaspar/qbittorrent.py
Normal 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
|
@ -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
96
gaspar/torrent_clients.py
Normal 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}"
|
@ -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(
|
||||
|
@ -1,2 +1,3 @@
|
||||
python-telegram-bot==13.4
|
||||
transmission-rpc==2.0.4
|
||||
qbittorrent-api==v2021.8.23
|
||||
|
Reference in New Issue
Block a user