Improve client command.

This commit is contained in:
AB
2021-02-27 02:29:08 +03:00
parent 441223a315
commit 2b12ecec02
7 changed files with 199 additions and 133 deletions

14
README
View File

@ -9,10 +9,20 @@
Gaspar telegram bot written in python.
Fetures:
* notify about topic update on rutracker via telegram.
* is able to push new magnet link into your Transmission RPC client.
* Notify about topic update on rutracker.org via Telegram.
* Can push new magnet link into your Transmission web client.
running instance - @let_you_know_bot
⣿⣿⣿⡷⠊⡢⡹⣦⡑⢂⢕⢂⢕⢂⢕⢂⠕⠔⠌⠝⠛⠶⠶⢶⣦⣄⢂⢕⢂⢕
⣿⣿⠏⣠⣾⣦⡐⢌⢿⣷⣦⣅⡑⠕⠡⠐⢿⠿⣛⠟⠛⠛⠛⠛⠡⢷⡈⢂⢕⢂
⠟⣡⣾⣿⣿⣿⣿⣦⣑⠝⢿⣿⣿⣿⣿⣿⡵⢁⣤⣶⣶⣿⢿⢿⢿⡟⢻⣤⢑⢂
⣾⣿⣿⡿⢟⣛⣻⣿⣿⣿⣦⣬⣙⣻⣿⣿⣷⣿⣿⢟⢝⢕⢕⢕⢕⢽⣿⣿⣷⣔
⣿⣿⠵⠚⠉⢀⣀⣀⣈⣿⣿⣿⣿⣿⣿⣿⣿⣿⣗⢕⢕⢕⢕⢕⢕⣽⣿⣿⣿⣿
⢷⣂⣠⣴⣾⡿⡿⡻⡻⣿⣿⣴⣿⣿⣿⣿⣿⣿⣷⣵⣵⣵⣷⣿⣿⣿⣿⣿⣿⡿
⢌⠻⣿⡿⡫⡪⡪⡪⡪⣺⣿⣿⣿⣿⣿⠿⠿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠃
⠣⡁⠹⡪⡪⡪⡪⣪⣾⣿⣿⣿⣿⠋⠐⢉⢍⢄⢌⠻⣿⣿⣿⣿⣿⣿⣿⣿⠏⠈
⡣⡘⢄⠙⣾⣾⣾⣿⣿⣿⣿⣿⣿⡀⢐⢕⢕⢕⢕⢕⡘⣿⣿⣿⣿⣿⣿⠏⠠⠈
⠌⢊⢂⢣⠹⣿⣿⣿⣿⣿⣿⣿⣿⣧⢐⢕⢕⢕⢕⢕⢅⣿⣿⣿⣿⡿⢋⢜⠠⠈

View File

@ -4,12 +4,15 @@
.. moduleauthor:: AB <github.com/house-of-vanity>
"""
import sqlite3
import logging
import os
import sqlite3
from .transmission import check_connection
log = logging.getLogger(__name__)
class DBInitException(Exception):
""" Exception at DB Init """
@ -19,6 +22,7 @@ class DBInitException(Exception):
class DataBase:
"""This class create or use existent SQLite database file. It provides
high-level methods for database."""
def __init__(self):
"""
Constructor creates new SQLite database if
@ -85,7 +89,7 @@ class DataBase:
:type conn: object
:return: None
"""
#log.debug("Close connection to %s", self.basefile)
# log.debug("Close connection to %s", self.basefile)
conn.close()
def copy_to_history(self, tor_id):
@ -106,13 +110,25 @@ class DataBase:
self.execute(sql, attrs)
def add_client(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
def get_client(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):
return self.execute(sql, (user_id,))[0]
else:
return False
def drop_client(self, user_id):
sql = "DELETE FROM tr_clients WHERE user_id = ?"
self.execute(sql, (user_id,))
def get_attr(self, tor_id, attr):
sql = """SELECT %s FROM torrents WHERE id = ? ORDER BY reg_time DESC LIMIT 1""" % attr
@ -188,6 +204,7 @@ class DataBase:
chat_instance['first_name'],
chat_instance['last_name'],
))
def save_alert(self, user_id, tor_id):
sql = """INSERT OR IGNORE INTO alerts(
'user_id',
@ -227,6 +244,3 @@ class DataBase:
for sub in self.execute(sql, (tor_id,)):
subs.append(sub[0])
return subs

View File

@ -1,12 +1,12 @@
import logging
import os
import sys
import logging
from urllib import parse
from telegram import *
from telegram.ext import Updater, MessageHandler, CommandHandler, PrefixHandler, filters
from .rutracker import Torrent
from telegram.ext import Updater, MessageHandler, CommandHandler, filters
from .notify import update_watcher
from .database import DataBase
from .rutracker import Torrent
from .tools import format_topic
logging.basicConfig(
@ -14,14 +14,15 @@ logging.basicConfig(
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
log = logging.getLogger(__name__)
token = os.environ.get('TG_TOKEN')
if not token:
log.error("Env var TG_TOKEN isn't set.")
sys.exit(1)
def main():
"""Run bot."""
def add(update, context):
if 'https://rutracker.org' in update.message.text:
try:
@ -50,7 +51,6 @@ def main():
pre='You will be alerted about\n')
update.message.reply_text(msg, parse_mode='HTML', disable_web_page_preview=True)
def list_alerts(update, context):
log.info(
"Got /list request from user [%s] %s",
@ -90,19 +90,38 @@ def main():
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][/rpc_path]</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(u_id)
log.info(tr_client)
if tr_client:
tr_line = f"Your client: <code>{tr_client[0]}://{tr_client[1]}:{tr_client[2]}{tr_client[5]}</code>\n" \
r"/delete_client"
else:
tr_line = False
update.message.reply_text(
'Gaspar is able to add new topics to your private Transmission server.'
'Send transmission RPC address like <b>http(s)://[user:pass]host[:port][/rpc_path]</b>',
'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
Torrent().db.add_client(u_id, scheme, hostname, port, username, password, path)
if Torrent().db.add_client(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):
log.info(
"Got /delete request from user [%s] %s",
update.message.chat['id'],
update.message.from_user.username)
Torrent().db.drop_client(update.message.chat['id'])
update.message.reply_text(f'Client deleted.')
def delete(update, context):
log.info(
@ -112,15 +131,16 @@ def main():
tor_id = update.message.text.split('_')[1]
try:
Torrent().db.delete_tor(update.message.chat['id'], tor_id)
context.bot.sendMessage(update.message.chat['id'], f'Deleted {tor_id}')
update.message.reply_text(f'Deleted {tor_id}')
except:
context.bot.sendMessage(update.message.chat['id'], f'Faled to delete {tor_id}')
update.message.reply_text(f'Faled to delete {tor_id}')
updater = Updater(token, use_context=True)
update_watcher(updater.bot)
updater.dispatcher.add_handler(CommandHandler('list', list_alerts))
updater.dispatcher.add_handler(CommandHandler('client', handle_client))
updater.dispatcher.add_handler(CommandHandler('delete_client', delete_client))
updater.dispatcher.add_handler(MessageHandler(filters.Filters.regex(r'/delete_'), delete))
updater.dispatcher.add_handler(MessageHandler(filters.Filters.text, add))

View File

@ -1,7 +1,8 @@
import time
import threading
import logging
import threading
import time
from datetime import datetime
from .rutracker import Torrent
from .tools import format_topic
from .transmission import add_tor
@ -12,14 +13,16 @@ log = logging.getLogger(__name__)
torrent = Torrent()
def sizeof_fmt(num, suffix='B'):
num = int(num)
for unit in ['','Ki','Mi','Gi','Ti','Pi','Ei','Zi']:
for unit in ['', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi']:
if abs(num) < 1024.0:
return "%3.1f%s%s" % (num, unit, suffix)
num /= 1024.0
return "%.1f%s%s" % (num, 'Yi', suffix)
def update(tor_id):
torrent.tor_id = tor_id
if torrent.is_outdated():
@ -29,6 +32,7 @@ def update(tor_id):
else:
return False
def update_watcher(bot):
def __thread():
while True:
@ -36,7 +40,8 @@ def update_watcher(bot):
raw = torrent.db.get_alerts()
for alert in raw:
alerts.append(alert['id'])
log.info("Checking for updates. Configured interval: %sh , [%s secs]", UPDATE_INTERVAL/60/60, UPDATE_INTERVAL)
log.info("Checking for updates. Configured interval: %sh , [%s secs]", UPDATE_INTERVAL / 60 / 60,
UPDATE_INTERVAL)
log.info("Checking alert %s", alert['topic_title'])
if update(alert['id']):
log.info("Found update for [%s] %s", torrent.meta['id'], torrent.meta['topic_title'])
@ -57,7 +62,8 @@ def update_watcher(bot):
log.info("Push update to client Transmission RPC for %s", torrent.meta['info_hash'])
msg = f"{msg}\n* Added to your Transmission: {scheme}://{hostname}:{port}/{path}"
else:
log.warning("Failed push update to client Transmission RPC for %s", torrent.meta['info_hash'])
log.warning("Failed push update to client Transmission RPC for %s",
torrent.meta['info_hash'])
except:
pass
bot.sendMessage(sub, msg, parse_mode='HTML', disable_web_page_preview=True)
@ -66,5 +72,6 @@ def update_watcher(bot):
else:
log.info("There is no update for %s", alert['topic_title'])
time.sleep(UPDATE_INTERVAL)
update_thread = threading.Thread(target=__thread)
update_thread.start()

View File

@ -1,5 +1,4 @@
import json
import os
import logging
import re
import urllib.request
@ -8,6 +7,7 @@ from .database import DataBase
log = logging.getLogger(__name__)
class Torrent:
def __init__(self, tor_id=None):
self.db = DataBase()
@ -28,7 +28,6 @@ class Torrent:
if tor_id:
return self.get_tor_topic_data(tor_id)
def get_tor_topic_data(self, tor_id):
data = dict()
with urllib.request.urlopen(
@ -62,6 +61,6 @@ class Torrent:
if not self.tor_id:
log.warn("Torrent id not presented.")
return False
ep_str = re.search(r"\[\d+(\+\d+)?(-\d+)?( +)?(из)?( +)?\d+(\+\d+)?(-\d+)?\]", self.meta["topic_title"]).group(0)
ep_str = re.search(r"\[\d+(\+\d+)?(-\d+)?( +)?(из)?( +)?\d+(\+\d+)?(-\d+)?\]", self.meta["topic_title"]).group(
0)
return ep_str

View File

@ -1,13 +1,15 @@
from datetime import datetime
def format_topic(tor_id, topic_title, size, info_hash, reg_time, pre=''):
def sizeof_fmt(num, suffix='B'):
num = int(num)
for unit in ['','Ki','Mi','Gi','Ti','Pi','Ei','Zi']:
for unit in ['', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi']:
if abs(num) < 1024.0:
return "%3.1f%s%s" % (num, unit, suffix)
num /= 1024.0
return "%.1f%s%s" % (num, 'Yi', suffix)
size = sizeof_fmt(size)
reg_time = datetime.utcfromtimestamp(int(reg_time)
).strftime('%b-%d-%Y')

View File

@ -1,5 +1,6 @@
from transmission_rpc import Client
def add_tor(scheme, hostname, port, username, password, path, tor_hash):
try:
c = Client(
@ -15,3 +16,16 @@ def add_tor(scheme, hostname, port, username, password, path, tor_hash):
except:
return False
def check_connection(scheme, hostname, port, username, password, path):
try:
c = Client(
host=hostname,
port=port,
username=username,
password=password,
protocol=scheme,
path=path)
return True if c.rpc_version else False
except:
return False