diff --git a/Animebyter/animebyter.py b/Animebyter/animebyter.py new file mode 100644 index 0000000..6e7210b --- /dev/null +++ b/Animebyter/animebyter.py @@ -0,0 +1,197 @@ +from feedparser import parse +from aiohttp import ClientSession +from discord.ext.commands import Bot +from tinydb import TinyDB, Query +from os.path import join +from os import getenv +from asyncio import sleep +from traceback import print_exc + +client = Bot('ab!') +QB_URL = getenv("qbit_url") +INTERVAL = int(getenv("INTERVAL")) if getenv("INTERVAL") else 300 +web = ClientSession() +db = TinyDB("animebyter.json") +chn = int(getenv("channel")) + +downloading = [] + +class Anime: + def __init__(self,name,le,tl,res): + self.title = name + self.last_episode = le + self.torrent_link = tl + self.resolution = res.strip() + +async def login_qb(): + async with web.post(QB_URL+'/login',data={'username':getenv("qbit_user"),'password':getenv("qbit_pass")}) as res: + if res.status!=200: + print("Could not authenticate with qBittorrent. Exiting...") + exit(1) + else: + print("Logged in to qBittorrent") + +async def get_airing(): + r = [] + res = await web.get("https://animebytes.tv/feed/rss_torrents_airing_anime/{}".format(getenv("ab_key"))) + if res.status==200: + txt = await res.text() + rss = parse(txt) + for i in rss['entries']: + try: + title = i['ab_grouptitle'] + ep = int((''.join(x for x in i['ab_torrentproperty'].split("|")[6] if x.isdigit())).strip()) + link = i['link'] + r.append(Anime(title,ep,link,i['ab_torrentproperty'].split("|")[3])) + except Exception: + continue + return r + +async def add_torrent(anime): + print("Adding episode {} of {}".format(anime.last_episode,anime.title)) + path = "/mnt/Storage/Anime" + try: + res = await web.post(QB_URL+'/command/download',data={'urls':anime.torrent_link,'savepath':join(path,anime.title),'label':'Anime'}) + except Exception as e: + print(str(e)) + return + finally: + res.close() + if res.status==200: + msg = "Added episode {} of {}".format(anime.last_episode,anime.title) + print(msg) + return msg + else: + print("Failed to add episode {} of {} ({})".format(anime.last_episode,anime.title,res.status)) + +async def main(): + print("Starting new episode checker") + while True: + try: + print("Checking for new episodes") + airing = await get_airing() + for i in airing: + res = db.search(Query().title==i.title) + if res: + le = res[0]['last_episode'] + if le {} has finished downloading.".format(i)) + else: + print("Something went wrong with fetching downloads ({}: {})".format(res.status,await res.text())) + except Exception as e: + print(str(e)) + print_exc() + continue + finally: + await sleep(10) + +def chunks(s, n=1999): + for start in range(0, len(s), n): + yield s[start:start+n] + +@client.command(pass_context=True) +async def add(ctx): + airing = await get_airing() + txt = "" + for i,v in enumerate(airing): + txt+="{}) {}\n".format(i,v.title) + msgs = [] + for i in chunks(txt): + msgs.append(await ctx.send(i)) + msg = await client.wait_for('message',check=lambda m: m.author==ctx.author and m.channel==ctx.channel) + await ctx.channel.delete_messages(msgs) + if msg: + try: + msg = int(msg.content) + except Exception as e: + return await ctx.send(e) + if msg>=len(airing): + return await ctx.send("Invalid number") + an = airing[msg] + db.insert({'title':an.title,'last_episode':an.last_episode-1}) + return await ctx.send("Added {}".format(an.title)) + + +@client.command(pass_context=True) +async def remove(ctx): + watching = db.all() + txt = "" + for i,v in enumerate(watching): + txt+="{}) {}\n".format(i,v['title']) + msgs = [] + for i in chunks(txt): + msgs.append(await ctx.send(i)) + msg = await client.wait_for('message',check=lambda m: m.author==ctx.author and m.channel==ctx.channel) + if len(msgs)==1: + await msgs[0].delete() + else: + await ctx.channel.delete_messages(msgs) + if msg: + try: + msg = int(msg.content) + except Exception as e: + return await ctx.send(e) + if msg>=len(watching): + return await ctx.send("Invalid number") + an = watching[msg] + db.remove(Query().title==an['title']) + return await ctx.send("Removed {}".format(an)) + +@client.command(pass_context=True) +async def down(ctx): + airing = await get_airing() + txt = "" + for i,v in enumerate(airing): + txt+="{}) {} (Episode: {})[{}]\n".format(i,v.title,v.last_episode,v.resolution) + msgs = [] + for i in chunks(txt): + msgs.append(await ctx.send(i)) + msg = await client.wait_for('message',check=lambda m: m.author==ctx.author and m.channel==ctx.channel) + print(msg) + await ctx.channel.delete_messages(msgs) + if msg: + try: + msg = int(msg.content) + except Exception as e: + return await ctx.send(e) + if msg>=len(airing): + return await ctx.send("Invalid number") + await ctx.send(await add_torrent(airing[msg])) + +@client.event +async def on_ready(): + print("Starting animebyter") + await login_qb() + client.loop.create_task(main()) + client.loop.create_task(dl_watchdog()) + +client.run(getenv("discord_token")) diff --git a/Animebyter/animebyter.service b/Animebyter/animebyter.service new file mode 100644 index 0000000..b2f4833 --- /dev/null +++ b/Animebyter/animebyter.service @@ -0,0 +1,21 @@ +[Unit] +Description=Adds new episodes from animebytes on qbittorrent +After=network.target qbittorrent.service + +[Service] + +WorkingDirectory=/home/marios/Animebyter #The location of the animebyter script +ExecStart=/usr/bin/python3.7 animebyter.py +User=marios +Restart=always + +Environment=qbit_url=http://127.0.0.1:8080 #URL of your qBittorrent WebUI +Environment=qbit_user=admin #Username for qBittorrent WebUI +Environment=qbit_pass=adminadmin #Password for qBittorrent WebUI +Environment=ab_key=YOUR_ANIMEBYTES_TOKEN #Your animebytes token. You can find this by querying any of the RSS feeds +Environment=channel=THE_CHANNEL_YOU_WANT_TO_SEND_NOTIFICATIONS_IN #The ID of the channel you want to send notifications in on discord +Environment=discord_token=YOUR_DISCORD_TOKEN #The token of your discord bot +Environment=INTERVAL=300 #It will look for new episodes every x seconds + +[Install] +WantedBy=multi-user.target diff --git a/Caddy_Logger/caddy_logger.py b/Caddy_Logger/caddy_logger.py new file mode 100644 index 0000000..f8560a0 --- /dev/null +++ b/Caddy_Logger/caddy_logger.py @@ -0,0 +1,48 @@ +import socket +from os import getenv +from datetime import datetime +import pymysql + +class LogItem: + def __init__(self,line): + self.ip = line.split(" ")[0] + self.timestamp = datetime.strptime(line.split("[")[1].split("]")[0].split("+")[0].strip(),"%d/%b/%Y:%H:%M:%S") + req = line.split('"')[1].split(' ') + self.method = req[0] + self.path = req[1] + self.http = req[2] + self.status = int(line.split('"')[2].split(' ')[1]) + +print("Starting log server") +db_conn = pymysql.connect(host=getenv("db_host"),user=getenv("db_user"),password=getenv("db_pass"),db=getenv("db_db"),autocommit=True) +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +s.bind((getenv("tcp_ip"),int(getenv("tcp_port")))) +s.listen(True) + +with db_conn.cursor() as db: + db.execute(""" + CREATE TABLE IF NOT EXISTS `caddy_logs` ( + `ip` varchar(255) DEFAULT NULL, + `timestamp` datetime DEFAULT NULL, + `path` varchar(255) DEFAULT NULL, + `method` varchar(255) DEFAULT NULL, + `http` varchar(255) DEFAULT NULL, + `status` int(11) DEFAULT NULL + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + """) + +while True: + conn, addr = s.accept() + print("Caddy connected from {}".format(addr)) + while True: + data = conn.recv(4096) + if not data: + break + data = data.decode("utf-8").split("]:")[1].strip() + itm = LogItem(data) + try: + with db_conn.cursor() as db: + db.execute("INSERT INTO `caddy_logs` (`ip`, `timestamp`, `path`, `method`, `http`, `status`) VALUES (%s, %s, %s, %s, %s, %s)",(itm.ip,itm.timestamp,itm.path,itm.method,itm.http,itm.status,)) + except Exception: + continue + conn.close() diff --git a/Caddy_Logger/caddy_logger.service b/Caddy_Logger/caddy_logger.service new file mode 100644 index 0000000..ed4dcfd --- /dev/null +++ b/Caddy_Logger/caddy_logger.service @@ -0,0 +1,20 @@ +[Unit] +Description=Caddy log parser +After=network.target mysql.service +Requires=mysql.service + +[Service] +Environment=tcp_ip=127.0.0.1 #The address to run the tcp server on +Environment=tcp_port=6969 #The port to run the tcp server on +Environment=db_host=127.0.0.1 #Your mysql server address +Environment=db_user=root #Your mysql user +Environment=db_pass=MYSQL_PASSWORD #Your mysql password +Environment=db_db=ip_logging #The database in which you log IPs +User=marios +ExecStart=/usr/bin/python3 /home/caddy_logger.py #Change this according to where you have the script saved + +#ATTENTION: Add the following under the directive you want to log from in your caddyfile +#log syslog+tcp://127.0.0.1:6969 (Without the # obviously) + +[Install] +WantedBy=multi-user.target