This commit is contained in:
AB
2020-05-24 21:14:54 +03:00
parent 287fc31e46
commit 46e59d3eb6
7 changed files with 163 additions and 140 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
__pycache__/
data.sqlite

Binary file not shown.

View File

@ -7,7 +7,10 @@
import sqlite3
import logging
log = logging.getLogger(__name__)
log = logging.getLogger("gaspar.%s" % __name__)
class DBInitException(Exception):
""" Exception at DB Init """
# class DataBase create or use existent SQLite database file. It provides
@ -39,9 +42,11 @@ class DataBase:
cursor.executescript(sql)
except Exception as e:
log.debug('Could not create scheme - %s', e)
raise DBInitException
else:
log.debug("Error! cannot create the database connection.")
log.info('DB created.')
raise DBInitException
log.info('DB connected.')
self.close(conn)
def connect(self, basefile):
@ -81,130 +86,9 @@ class DataBase:
#log.debug("Close connection to %s", self.basefile)
conn.close()
def add_mod(self, file_meta, author='Anonymous'):
secure_name = file_meta['secure_name']
real_name = file_meta['real_name']
mime = file_meta['mime']
file_hash = file_meta['hash']
title = file_meta['title']
sample = file_meta['sample']
message = file_meta['message']
metaphone = file_meta['metaphone']
sql = """INSERT OR IGNORE INTO
mods('secure_name', 'real_name', 'mime', 'hash',
'author', 'title', 'sample', 'message', 'metaphone')
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"""
self.execute(sql, (
secure_name,
real_name,
mime,
file_hash,
author,
title,
sample,
message,
metaphone,
))
return True
def get_mods(self, limit, offset):
sql = """SELECT
rowid, real_name, title, mime,
strftime('%s', date) as str_time, author, date, hash, secure_name
FROM mods LIMIT ?,?"""
mods = list()
result = self.execute(sql, (offset, limit))
for mod in result:
mods.append(
{
'id': mod[0],
'real_name': mod[1],
'title': mod[2],
'mimetype': mod[3],
'str_time': mod[4],
'author': mod[5],
'time': mod[6],
'hash': mod[7],
'secure_name': mod[8],
}
)
return mods
def get_mod(self, mod_id):
sql = """SELECT
rowid, real_name, secure_name, mime,
strftime('%s', date) as str_time, author, date,
hash, title, sample, message
FROM mods WHERE rowid = ?"""
result = self.execute(sql, (mod_id,))
if result:
meta = result[0]
mod = {
'id': meta[0],
'real_name': meta[1],
'secure_name': meta[2],
'mimetype': meta[3],
'time': meta[4],
'author': meta[5],
'str_time': meta[6],
'hash': meta[7],
'title': meta[8],
'sample': meta[9],
'message': meta[10],
}
else:
mod = list()
return mod
def find_mod(self, param=None):
"""
Looking for mod dublicates.
:param param: name or hash of module to search.
:type param: string
:return: list
"""
sql = """SELECT rowid FROM mods WHERE real_name == ? OR
hash == ? ORDER BY rowid DESC LIMIT 1"""
result = self.execute(sql, (param, param))
return result
def search(self, query):
"""
Perform module search through the base.
"""
sql = """SELECT rowid, secure_name, title, mime, date,
strftime('%s', date) as str_time FROM mods
WHERE
secure_name LIKE ? OR
title LIKE ? OR
message LIKE ? OR
sample LIKE ?"""
query_mask = f"%{query}%"
result = self.execute(sql, tuple(query_mask for i in range(0, 4)))
log.debug(result)
return result
def signin(self, name, password):
"""
auth client
"""
result = {"status": False, 'message': 'User is invalid.'}
sql = "SELECT name, password FROM users WHERE name = ?"
ret = self.execute(sql, (name,))
if len(ret) == 0:
result = {'status': False, 'message': 'User doesn\'t exist'}
elif len(ret) == 1:
stored_hash = ret[0][1]
print(stored_hash, password)
print(verify_password(stored_hash, password))
if verify_password(stored_hash, password):
result = {"status": True, 'message': 'User is valid.'}
return result
def copy_to_history(self, tor_id):
sql = "SELECT * FROM torrents WHERE id = ?"
attrs = self.execute(sql, (tor_id,))[0]
print(attrs)
sql = """INSERT OR IGNORE INTO torrents_history(
'id',
'info_hash',
@ -215,7 +99,7 @@ class DataBase:
'tor_status',
'seeders',
'topic_title',
'seeder_last_seen',
'seeder_last_seen'
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ? )"""
self.execute(sql, attrs)
@ -288,5 +172,45 @@ class DataBase:
chat_instance['first_name'],
chat_instance['last_name'],
))
return True
def save_alert(self, user_id, tor_id):
sql = """INSERT OR IGNORE INTO alerts(
'user_id',
'tor_id'
) VALUES (?, ?)"""
self.execute(sql, (
user_id,
tor_id
))
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
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"""
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)
return alerts
def get_subscribers(self, tor_id):
sql = "SELECT user_id FROM alerts WHERE tor_id = ?"
subs = list()
for sub in self.execute(sql, (tor_id,)):
subs.append(sub[0])
return subs

40
main.py
View File

@ -2,17 +2,21 @@ import os
import logging
from urllib import parse
from rutracker import Torrent
from notify import update_watcher
from datetime import datetime
from database import DataBase
from telegram import *
from telegram.ext import Updater, MessageHandler, CommandHandler, filters
logging.basicConfig(
level=logging.DEBUG,
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
log = logging.getLogger(__name__)
log = logging.getLogger("gaspar.%s" % __name__)
torrent = Torrent()
def sizeof_fmt(num, suffix='B'):
num = int(num)
for unit in ['','Ki','Mi','Gi','Ti','Pi','Ei','Zi']:
if abs(num) < 1024.0:
return "%3.1f%s%s" % (num, unit, suffix)
@ -34,30 +38,48 @@ def main():
else:
update.message.reply_text("Send me a URL to rutracker.org topic.")
return
log.info(
"Got /add request from user [%s] %s",
update.message.chat['id'],
update.message.from_user.username)
torrent = Torrent(tor_id)
torrent.db.save_tor(torrent.meta)
torrent.db.save_user(update.message.chat)
torrent.db.save_alert(update.message.chat['id'], torrent.meta['id'])
# log.debug(torrent.is_outdated())
# log.debug(torrent.update())
reg_time = datetime.utcfromtimestamp(int(torrent.meta['reg_time'])
).strftime('%b-%d')
).strftime('%b-%d-%Y')
msg = f"""{torrent.meta['topic_title']}
<b>Size:</b> {sizeof_fmt(torrent.meta['size'])}
<b>Hash: </b> {torrent.meta['info_hash']}
<b>Updated: </b>{reg_time}"""
log.info(msg)
update.message.reply_text(msg, parse_mode='HTML')
def hello(update, context):
update.message.reply_text(
'Hello {}'.format(update.message.from_user.first_name))
def list_alerts(update, context):
log.info(
"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'])
if len(alerts) == 0:
update.message.reply_text("You have no configured alerts.")
return True
msg = "<b>Configured alerts:</b>\n"
for alert in alerts:
reg_time = datetime.utcfromtimestamp(int(alert['reg_time'])
).strftime('%b-%d-%Y')
msg += f"""<a href='https://rutracker.org/forum/viewtopic.php?t={alert['id']}'><b>{alert['topic_title']}</b></a>
<b>💿Size:</b> {sizeof_fmt(alert['size'])}
<b>#⃣Hash: </b> {alert['info_hash']}
<b>📅Updated: </b>{reg_time}\n"""
update.message.reply_text(msg, parse_mode='HTML', disable_web_page_preview=True)
updater = Updater(token, use_context=True)
update_watcher(updater.bot)
updater.dispatcher.add_handler(MessageHandler(filters.Filters.text, add))
updater.dispatcher.add_handler(CommandHandler('list', list_alerts))
updater.start_polling()
updater.idle()

52
notify.py Normal file
View File

@ -0,0 +1,52 @@
import time
import threading
import logging
from rutracker import Torrent
from datetime import datetime
UPDATE_INTERVAL = 6 * 60 * 60 # in secs
log = logging.getLogger("gaspar.%s" % __name__)
torrent = Torrent()
def sizeof_fmt(num, suffix='B'):
num = int(num)
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():
log.info("%s if outdated. Updating.", torrent.meta['topic_title'])
torrent.update()
return True
else:
return False
def update_watcher(bot):
def __thread():
while True:
alerts = list()
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)
if update(alert['id']):
log.info("Found update for [%s] %s", torrent.meta['id'], torrent.meta['topic_title'])
reg_time = datetime.utcfromtimestamp(int(torrent.meta['reg_time'])
).strftime('%b-%d-%Y')
msg = f"""<i>Topic updated</i>\n<a href='https://rutracker.org/forum/viewtopic.php?t={torrent.meta['id']}'><b>{torrent.meta['topic_title']}</b></a>
<b>💿Size:</b> {sizeof_fmt(torrent.meta['size'])}
<b>#⃣Hash: </b> {torrent.meta['info_hash']}
<b>📅Updated: </b>{reg_time}\n"""
subs = torrent.db.get_subscribers(alert['id'])
for sub in subs:
bot.sendMessage(sub, msg, parse_mode='HTML', disable_web_page_preview=True)
time.sleep(UPDATE_INTERVAL / 60 / 60 / 4.)
time.sleep(UPDATE_INTERVAL)
update_thread = threading.Thread(target=__thread)
update_thread.start()

View File

@ -3,14 +3,27 @@ from database import DataBase
import logging
import re
log = logging.getLogger(__name__)
log = logging.getLogger("gaspar.%s" % __name__)
class Torrent:
def __init__(self, tor_id):
def __init__(self, tor_id=None):
self.db = DataBase("scheme.sql")
self.api_url = "http://api.rutracker.org/v1/"
self.meta = self.get_tor_topic_data(tor_id)
log.debug("Torrent info: %s", self.meta)
self.tor_id = tor_id
self.meta = None
if self.tor_id != None:
self.get_tor_topic_data(self.tor_id)
log.debug("Torrent info: %s", self.meta)
@property
def tor_id(self):
return self.__tor_id
@tor_id.setter
def tor_id(self, tor_id):
self.__tor_id = tor_id
if tor_id:
self.get_tor_topic_data(tor_id)
def get_tor_topic_data(self, tor_id):
data = dict()
@ -20,17 +33,27 @@ class Torrent:
data = json.loads(url.read().decode())
data = data["result"][tor_id]
data["id"] = tor_id
return data
log.info("Getting info for [%s] %s%s", tor_id, data["topic_title"][:60], '...')
self.meta = data
def is_outdated(self):
if not self.tor_id:
log.warn("Torrent id not presented.")
return False
stored_reg_time = int(self.db.get_attr(self.meta["id"], 'reg_time'))
actual_reg_time = self.meta["reg_time"]
return actual_reg_time != stored_reg_time
def update(self):
if not self.tor_id:
log.warn("Torrent id not presented.")
return False
self.db.update(self.meta)
def episodes(self):
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)
return ep_str

View File

@ -33,7 +33,8 @@ CREATE TABLE IF NOT EXISTS "users" (
);
CREATE TABLE IF NOT EXISTS "alerts" (
user_id TEXT,
tor_id TEXT
tor_id TEXT,
UNIQUE(user_id, tor_id)
);
COMMIT;