mirror of
https://github.com/house-of-vanity/gaspar.git
synced 2025-08-21 07:27:16 +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 import InlineKeyboardButton, InlineKeyboardMarkup, Update
|
||||||
from telegram.ext import Updater, MessageHandler, CommandHandler, filters, CallbackQueryHandler, CallbackContext
|
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 .notify import update_watcher
|
||||||
from .rutracker import Torrent
|
from .rutracker import Torrent
|
||||||
from .tools import format_topic
|
from .tools import format_topic
|
||||||
from .transmission import easy_send
|
|
||||||
|
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
level=logging.INFO,
|
level=logging.INFO,
|
||||||
@@ -88,42 +88,28 @@ def main():
|
|||||||
"Got /client request from user [%s] %s",
|
"Got /client request from user [%s] %s",
|
||||||
u_id,
|
u_id,
|
||||||
update.message.from_user.username)
|
update.message.from_user.username)
|
||||||
try:
|
if len(update.message.text.split()) > 1:
|
||||||
addr = update.message.text.split()[1]
|
msg = add_client(update.message.text.split()[1], u_id)
|
||||||
log.info("Client Transmission RPC address - %s", addr)
|
update.message.reply_text(msg)
|
||||||
tr = parse.urlparse(addr)
|
else:
|
||||||
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:
|
|
||||||
tr_client = Torrent().db.get_client_rpc(u_id)
|
tr_client = Torrent().db.get_client_rpc(u_id)
|
||||||
if tr_client:
|
log.info("tr_client: %s", tr_client)
|
||||||
tr_line = f"Your client: <code>{tr_client[0]}://{tr_client[1]}:{tr_client[2]}{tr_client[5]}</code>\n" \
|
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"
|
r"/delete_client"
|
||||||
else:
|
else:
|
||||||
tr_line = False
|
tr_line = "You have no configured client."
|
||||||
update.message.reply_text(
|
update.message.reply_text(tr_line, parse_mode='HTML', disable_web_page_preview=True)
|
||||||
'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.')
|
|
||||||
|
|
||||||
def delete_client(update, context):
|
def delete_client(update, context):
|
||||||
log.info(
|
log.info(
|
||||||
@@ -147,7 +133,7 @@ def main():
|
|||||||
|
|
||||||
def button(update: Update, context: CallbackContext) -> None:
|
def button(update: Update, context: CallbackContext) -> None:
|
||||||
query = update.callback_query
|
query = update.callback_query
|
||||||
|
u_id = query.message.chat['id']
|
||||||
|
|
||||||
torrent_id = query.data.split('.')[1]
|
torrent_id = query.data.split('.')[1]
|
||||||
torrent = Torrent(torrent_id)
|
torrent = Torrent(torrent_id)
|
||||||
@@ -164,7 +150,7 @@ def main():
|
|||||||
query.edit_message_text(text=f"{msg}", parse_mode='HTML',
|
query.edit_message_text(text=f"{msg}", parse_mode='HTML',
|
||||||
disable_web_page_preview=True)
|
disable_web_page_preview=True)
|
||||||
else:
|
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.answer()
|
||||||
query.edit_message_text(text=f"{msg}📨 <b>Sent to RPC /client</b>", parse_mode='HTML',
|
query.edit_message_text(text=f"{msg}📨 <b>Sent to RPC /client</b>", parse_mode='HTML',
|
||||||
disable_web_page_preview=True)
|
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.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'
|
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:
|
try:
|
||||||
conn = self.connect()
|
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:
|
except:
|
||||||
log.debug('Could not connect to DataBase.')
|
log.debug('Could not connect to DataBase.')
|
||||||
return None
|
return None
|
||||||
@@ -111,18 +112,17 @@ class DataBase:
|
|||||||
self.execute(sql, attrs)
|
self.execute(sql, attrs)
|
||||||
|
|
||||||
def add_client_rpc(self, user_id, scheme, hostname, port, username, password, path):
|
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)
|
sql = """INSERT OR REPLACE INTO tr_clients(user_id, scheme, hostname, port, username, password, path)
|
||||||
VALUES(?, ?, ?, ?, ?, ?, ?);"""
|
VALUES(?, ?, ?, ?, ?, ?, ?);"""
|
||||||
self.execute(sql, (user_id, scheme, hostname, port, username, password, path))
|
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
|
return True
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def get_client_rpc(self, user_id):
|
def get_client_rpc(self, user_id):
|
||||||
sql = "SELECT scheme, hostname, port, username, password, path FROM tr_clients WHERE user_id = ?"
|
sql = "SELECT scheme, hostname, port, username, password, path FROM tr_clients WHERE user_id = ?"
|
||||||
res = self.execute(sql, (user_id,))
|
res = self.execute(sql, (user_id,))
|
||||||
if len(res):
|
if res:
|
||||||
return self.execute(sql, (user_id,))[0]
|
return self.execute(sql, (user_id,))[0]
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
@@ -230,6 +230,7 @@ class DataBase:
|
|||||||
torrents t JOIN alerts a ON a.tor_id = t.id GROUP BY t.id"""
|
torrents t JOIN alerts a ON a.tor_id = t.id GROUP BY t.id"""
|
||||||
raw = self.execute(sql, ())
|
raw = self.execute(sql, ())
|
||||||
alerts = list()
|
alerts = list()
|
||||||
|
if not isinstance(raw, int):
|
||||||
for alert in raw:
|
for alert in raw:
|
||||||
tmp = dict()
|
tmp = dict()
|
||||||
tmp['id'] = alert[3]
|
tmp['id'] = alert[3]
|
||||||
|
@@ -5,7 +5,7 @@ from datetime import datetime
|
|||||||
|
|
||||||
from .rutracker import Torrent
|
from .rutracker import Torrent
|
||||||
from .tools import format_topic
|
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.
|
UPDATE_INTERVAL = 2 * 60 * 60 # in secs.
|
||||||
|
|
||||||
@@ -58,8 +58,8 @@ def update_watcher(bot):
|
|||||||
for sub in subs:
|
for sub in subs:
|
||||||
try:
|
try:
|
||||||
scheme, hostname, port, username, password, path = torrent.db.get_client_rpc(sub)
|
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']):
|
if easy_send(torrent.meta['info_hash'], sub):
|
||||||
log.info("Push update to client Transmission RPC for %s", torrent.meta['info_hash'])
|
log.info("Push update to client %s", torrent.meta['info_hash'])
|
||||||
msg = f"{msg}📨 <b>Sent to RPC /client</b>"
|
msg = f"{msg}📨 <b>Sent to RPC /client</b>"
|
||||||
else:
|
else:
|
||||||
log.warning("Failed push update to client Transmission RPC for %s",
|
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
|
@@ -40,9 +40,9 @@ CREATE TABLE IF NOT EXISTS "tr_clients" (
|
|||||||
user_id TEXT,
|
user_id TEXT,
|
||||||
scheme TEXT,
|
scheme TEXT,
|
||||||
hostname TEXT,
|
hostname TEXT,
|
||||||
port TEXT,
|
port INTEGER,
|
||||||
username TEXT,
|
username TEXT DEFAULT NULL,
|
||||||
password TEXT,
|
password TEXT DEFAULT NULL,
|
||||||
path TEXT,
|
path TEXT,
|
||||||
UNIQUE(user_id)
|
UNIQUE(user_id)
|
||||||
);
|
);
|
||||||
|
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__)
|
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):
|
def send_to_client_rpc(scheme, hostname, port, username, password, path, tor_hash):
|
||||||
try:
|
try:
|
||||||
c = Client(
|
c = Client(
|
||||||
|
@@ -1,2 +1,3 @@
|
|||||||
python-telegram-bot==13.4
|
python-telegram-bot==13.4
|
||||||
transmission-rpc==2.0.4
|
transmission-rpc==2.0.4
|
||||||
|
qbittorrent-api==v2021.8.23
|
||||||
|
2
setup.py
2
setup.py
@@ -28,7 +28,7 @@ setup(
|
|||||||
packages=['gaspar'],
|
packages=['gaspar'],
|
||||||
long_description=read('README'),
|
long_description=read('README'),
|
||||||
classifiers=[
|
classifiers=[
|
||||||
"Development Status :: 3 - Alpha",
|
"Development Status :: 3 - Beta",
|
||||||
"Topic :: Utilities",
|
"Topic :: Utilities",
|
||||||
],
|
],
|
||||||
entry_points={
|
entry_points={
|
||||||
|
Reference in New Issue
Block a user