From 5cf02070996433b8cc155a415066414254a9743d Mon Sep 17 00:00:00 2001 From: AB Date: Thu, 25 Feb 2021 22:06:53 +0300 Subject: [PATCH] Added delete feature. Minor fixes. --- gaspar/database.py | 29 +++++++++++++++++------------ gaspar/gaspar.py | 33 +++++++++++++++++++++++---------- gaspar/notify.py | 4 +++- gaspar/rutracker.py | 7 +++++-- gaspar/tools.py | 7 ++++--- 5 files changed, 52 insertions(+), 28 deletions(-) diff --git a/gaspar/database.py b/gaspar/database.py index 58581f8..195bbcf 100644 --- a/gaspar/database.py +++ b/gaspar/database.py @@ -19,7 +19,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, scheme, basefile='/usr/share/gaspar/data.sqlite'): + def __init__(self): """ Constructor creates new SQLite database if it doesn't exist. Uses SQL code from file for DB init. @@ -27,15 +27,15 @@ class DataBase: :type scheme: string :return: None """ - self.scheme = '' - self.basefile = basefile + 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' try: - conn = self.connect(basefile=basefile) - log.info("Using '%s' base file.", os.path.realpath(basefile)) + conn = self.connect() + log.info("Using '%s' base file.", os.path.realpath(self.basefile)) except: log.debug('Could not connect to DataBase.') return None - with open(scheme, 'r') as scheme_sql: + with open(self.scheme, 'r') as scheme_sql: sql = scheme_sql.read() self.scheme = sql if conn is not None: @@ -51,15 +51,15 @@ class DataBase: log.info('DB connected.') self.close(conn) - def connect(self, basefile): + def connect(self): """ Create connect object for basefile :param basefile: SQLite database filename :type basefile: string :return: sqlite3 connect object """ - #log.debug("Open connection to %s", basefile) - return sqlite3.connect(basefile, check_same_thread=False) + log.info("Open connection to %s", os.path.realpath(self.basefile)) + return sqlite3.connect(self.basefile, check_same_thread=False) def execute(self, sql, params): """ @@ -69,7 +69,7 @@ class DataBase: :type sql: string :return: list of response. Empty list when no rows are available. """ - conn = self.connect(basefile=self.basefile) + conn = self.connect() log.debug("Executing: %s %s", sql, params) cursor = conn.cursor() cursor.execute(sql, params) @@ -170,6 +170,11 @@ class DataBase: tor_data["topic_title"], tor_data["seeder_last_seen"], )) + + def delete_tor(self, user_id, tor_id): + sql = "DELETE FROM alerts WHERE user_id = ? AND tor_id = ?" + self.execute(sql, (user_id, tor_id)) + def save_user(self, chat_instance): sql = """INSERT OR IGNORE INTO users( 'id', @@ -196,14 +201,14 @@ class DataBase: def get_alerts(self, user_id=None): if user_id: sql = """SELECT t.size, t.reg_time, t.topic_title, t.id, t.info_hash FROM - torrents t LEFT JOIN alerts a ON a.tor_id = t.id + torrents t JOIN alerts a ON a.tor_id = t.id WHERE a.user_id = ?""" raw = self.execute(sql, ( user_id, )) else: sql = """SELECT t.size, t.reg_time, t.topic_title, t.id, t.info_hash FROM - torrents t LEFT 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, ()) alerts = list() for alert in raw: diff --git a/gaspar/gaspar.py b/gaspar/gaspar.py index 55cf502..29afc98 100644 --- a/gaspar/gaspar.py +++ b/gaspar/gaspar.py @@ -3,7 +3,7 @@ import sys import logging from urllib import parse from telegram import * -from telegram.ext import Updater, MessageHandler, CommandHandler, filters +from telegram.ext import Updater, MessageHandler, CommandHandler, PrefixHandler, filters from .rutracker import Torrent from .notify import update_watcher from .database import DataBase @@ -14,21 +14,20 @@ logging.basicConfig( format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') log = logging.getLogger(__name__) -torrent = Torrent() + +token = os.environ.get('TG_TOKEN') +if not token: + log.error("Env var TG_TOKEN isn't set.") + sys.exit(1) def main(): - token = os.environ.get('TG_TOKEN') - if not token: - log.error("Env var TG_TOKEN isn't set.") - sys.exit(1) """Run bot.""" - def add(update, context): if 'https://rutracker.org' in update.message.text: try: tor_id = parse.parse_qs(parse.urlsplit(update.message.text).query)['t'][0] except KeyError: - log.warn("URL provided doesn't contains any torrent id.") + log.warning("URL provided doesn't contains any torrent id.") update.message.reply_text("URL provided doesn't contains any torrent id.") return else: @@ -57,7 +56,7 @@ def main(): "Got /list request from user [%s] %s", update.message.chat['id'], update.message.from_user.username) - alerts = torrent.db.get_alerts(update.message.chat['id']) + alerts = Torrent().db.get_alerts(update.message.chat['id']) if len(alerts) == 0: update.message.reply_text("You have no configured alerts.") return True @@ -102,14 +101,27 @@ def main(): parse_mode='HTML', disable_web_page_preview=True) return - torrent.db.add_client(u_id, scheme, hostname, port, username, password, path) + Torrent().db.add_client(u_id, scheme, hostname, port, username, password, path) + + def delete(update, context): + log.info( + "Got /delete request from user [%s] %s", + update.message.chat['id'], + update.message.from_user.username) + 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}') + except: + context.bot.sendMessage(update.message.chat['id'], 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(MessageHandler(filters.Filters.regex(r'/delete_'), delete)) updater.dispatcher.add_handler(MessageHandler(filters.Filters.text, add)) updater.start_polling() @@ -117,4 +129,5 @@ def main(): if __name__ == '__main__': + log = logging.getLogger('gaspar') main() diff --git a/gaspar/notify.py b/gaspar/notify.py index 3de028c..5f318f4 100644 --- a/gaspar/notify.py +++ b/gaspar/notify.py @@ -51,15 +51,17 @@ def update_watcher(bot): pre='Topic has been updated\n') subs = torrent.db.get_subscribers(alert['id']) for sub in subs: - bot.sendMessage(sub, msg, parse_mode='HTML', disable_web_page_preview=True) try: scheme, hostname, port, username, password, path = torrent.db.get_client(sub) if add_tor(scheme, hostname, port, username, password, path, torrent.meta['info_hash']): 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']) except: pass + bot.sendMessage(sub, msg, parse_mode='HTML', disable_web_page_preview=True) + time.sleep(1) else: log.info("There is no update for %s", alert['topic_title']) diff --git a/gaspar/rutracker.py b/gaspar/rutracker.py index 79609dd..29e2262 100644 --- a/gaspar/rutracker.py +++ b/gaspar/rutracker.py @@ -1,13 +1,16 @@ -import urllib.request, json +import json +import os import logging import re +import urllib.request + from .database import DataBase log = logging.getLogger(__name__) class Torrent: def __init__(self, tor_id=None): - self.db = DataBase("/usr/share/gaspar/scheme.sql") + self.db = DataBase() self.api_url = "http://api.rutracker.org/v1/" self.tor_id = tor_id self.meta = None diff --git a/gaspar/tools.py b/gaspar/tools.py index f4f859a..222608a 100644 --- a/gaspar/tools.py +++ b/gaspar/tools.py @@ -12,7 +12,8 @@ def format_topic(tor_id, topic_title, size, info_hash, reg_time, pre=''): reg_time = datetime.utcfromtimestamp(int(reg_time) ).strftime('%b-%d-%Y') msg = f"""{pre}{topic_title} -💿 Size: {size} -#️⃣ Hash: {info_hash} -📅 Updated: {reg_time}\n""" +💿 Size: {size} +#️⃣ Hash: {info_hash} +📅 Updated: {reg_time} +❌ Unsubscribe: /delete_{tor_id}\n""" return msg