diff --git a/README.md b/README.md index 42000426..b932cc3a 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ A simple tool to take the work out of uploading. - Can re-use existing torrents instead of hashing new - Generates proper name for your upload using Mediainfo/BDInfo and TMDb/IMDb conforming to site rules - Checks for existing releases already on site - - Uploads to ACM/Aither/AL/ANT/BHD/BHDTV/BLU/CBR/FNP/FL/HDB/HDT/HP/HUNO/JPTV/LCD/LST/LT/MTV/NBL/OE/OTW/PSS/PTP/PTER/RF/R4E(limited)/RTF/SHRI/SN/SPD/STC/STT/TLC/THR/TL/TVC/TTG/ULCX/UTP + - Uploads to ACM/Aither/AL/ANT/BHD/BHDTV/BLU/CBR/FNP/FL/HDB/HDT/HP/HUNO/JPTV/LCD/LST/LT/MTV/NBL/OE/OTW/PSS/PTP/PTER/RF/R4E(limited)/RTF/SHRI/SN/SPD/STC/STT/TLC/THR/TL/TVC/TTG/ULCX/UTP/YOINK - Adds to your client with fast resume, seeding instantly (rtorrent/qbittorrent/deluge/watch folder) - ALL WITH MINIMAL INPUT! - Currently works with .mkv/.mp4/Blu-ray/DVD/HD-DVDs diff --git a/data/example-config.py b/data/example-config.py index 0fbb5f2e..b4c7cf04 100644 --- a/data/example-config.py +++ b/data/example-config.py @@ -76,9 +76,9 @@ "TRACKERS": { # Which trackers do you want to upload to? - # Available tracker: ACM, AITHER, AL, ANT, BHD, BHDTV, BLU, CBR, FNP, HDB, HDT, HP, HUNO, LCD, LST, LT, MTV, NBL, OE, OTW, PSS, PTER, PTP, R4E, RF, RTF, SN, STC, STT, THR, TIK, TL, ULCX, UTP + # Available tracker: ACM, AITHER, AL, ANT, BHD, BHDTV, BLU, CBR, FNP, HDB, HDT, HP, HUNO, LCD, LST, LT, MTV, NBL, OE, OTW, PSS, PTER, PTP, R4E, RF, RTF, SN, STC, STT, THR, TIK, TL, ULCX, UTP, YOINK # Remove the trackers from the default_trackers list that are not used, to save being asked everytime - "default_trackers": "ACM, AITHER, AL, ANT, BHD, BHDTV, BLU, CBR, FNP, HDB, HDT, HP, HUNO, LCD, LST, LT, MTV, NBL, OE, OTW, PSS, PTER, PTP, R4E, RF, RTF, SN, STC, STT, THR, TIK, TL, ULCX, UTP", + "default_trackers": "ACM, AITHER, AL, ANT, BHD, BHDTV, BLU, CBR, FNP, HDB, HDT, HP, HUNO, LCD, LST, LT, MTV, NBL, OE, OTW, PSS, PTER, PTP, R4E, RF, RTF, SN, STC, STT, THR, TIK, TL, ULCX, UTP, YOINK", "ACM": { "api_key": "ACM api key", @@ -324,6 +324,11 @@ "announce_url": "https://UTP/announce/customannounceurl", # "anon" : False }, + "YOINK": { + "api_key": "YOINK api key", + "announce_url": "https://yoinked.org/announce/customannounceurl", + # "anon" : "False" + }, }, # enable_search to True will automatically try and find a suitable hash to save having to rehash when creating torrents diff --git a/src/trackers/YOINK.py b/src/trackers/YOINK.py new file mode 100644 index 00000000..6370fa5c --- /dev/null +++ b/src/trackers/YOINK.py @@ -0,0 +1,219 @@ +# -*- coding: utf-8 -*- +# import discord +import asyncio +import requests +from str2bool import str2bool +import platform +import bencodepy +import os +import glob + +from src.trackers.COMMON import COMMON +from src.console import console + + +class YOINK(): + """ + Edit for Tracker: + Edit BASE.torrent with announce and source + Check for duplicates + Set type/category IDs + Upload + """ + + def __init__(self, config): + self.config = config + self.tracker = 'YOINK' + self.source_flag = 'YOINK' + self.upload_url = 'https://yoinked.org/api/torrents/upload' + self.search_url = 'https://yoinked.org/api/torrents/filter' + self.signature = "\n[center][url=https://github.com/Audionut/Upload-Assistant]Created by L4G's Upload Assistant[/url][/center]" + self.banned_groups = ["YTS,YiFY,LAMA,MeGUSTA,NAHOM,GalaxyRG,RARBG"] + pass + + async def get_cat_id(self, category_name): + category_id = { + 'MOVIE': '1', + 'TV': '2', + }.get(category_name, '0') + return category_id + + async def get_type_id(self, type): + type_id = { + 'DISC': '1', + 'REMUX': '2', + 'WEBDL': '4', + 'WEBRIP': '5', + 'HDTV': '6', + 'ENCODE': '3' + }.get(type, '0') + return type_id + + async def get_res_id(self, resolution): + resolution_id = { + '8640p': '10', + '4320p': '1', + '2160p': '2', + '1440p': '3', + '1080p': '3', + '1080i': '4', + '720p': '5', + '576p': '6', + '576i': '7', + '480p': '8', + '480i': '9' + }.get(resolution, '10') + return resolution_id + + async def upload(self, meta, disctype): + common = COMMON(config=self.config) + await common.edit_torrent(meta, self.tracker, self.source_flag) + cat_id = await self.get_cat_id(meta['category']) + type_id = await self.get_type_id(meta['type']) + resolution_id = await self.get_res_id(meta['resolution']) + await common.unit3d_edit_desc(meta, self.tracker, self.signature) + region_id = await common.unit3d_region_ids(meta.get('region')) + distributor_id = await common.unit3d_distributor_ids(meta.get('distributor')) + if meta['anon'] == 0 and bool(str2bool(str(self.config['TRACKERS'][self.tracker].get('anon', "False")))) is False: + anon = 0 + else: + anon = 1 + + if meta['bdinfo'] is not None: + mi_dump = None + bd_dump = open(f"{meta['base_dir']}/tmp/{meta['uuid']}/BD_SUMMARY_00.txt", 'r', encoding='utf-8').read() + else: + mi_dump = open(f"{meta['base_dir']}/tmp/{meta['uuid']}/MEDIAINFO.txt", 'r', encoding='utf-8').read() + bd_dump = None + desc = open(f"{meta['base_dir']}/tmp/{meta['uuid']}/[{self.tracker}]DESCRIPTION.txt", 'r', encoding='utf-8').read() + open_torrent = open(f"{meta['base_dir']}/tmp/{meta['uuid']}/[{self.tracker}]{meta['clean_name']}.torrent", 'rb') + files = {'torrent': open_torrent} + base_dir = meta['base_dir'] + uuid = meta['uuid'] + specified_dir_path = os.path.join(base_dir, "tmp", uuid, "*.nfo") + nfo_files = glob.glob(specified_dir_path) + nfo_file = None + if nfo_files: + nfo_file = open(nfo_files[0], 'rb') + if nfo_file: + files['nfo'] = ("nfo_file.nfo", nfo_file, "text/plain") + data = { + 'name': meta['name'], + 'description': desc, + 'mediainfo': mi_dump, + 'bdinfo': bd_dump, + 'category_id': cat_id, + 'type_id': type_id, + 'resolution_id': resolution_id, + 'tmdb': meta['tmdb'], + 'imdb': meta['imdb_id'].replace('tt', ''), + 'tvdb': meta['tvdb_id'], + 'mal': meta['mal_id'], + 'igdb': 0, + 'anonymous': anon, + 'stream': meta['stream'], + 'sd': meta['sd'], + 'keywords': meta['keywords'], + 'personal_release': int(meta.get('personalrelease', False)), + 'internal': 0, + 'featured': 0, + 'free': 0, + 'doubleup': 0, + 'sticky': 0, + } + # Internal + if self.config['TRACKERS'][self.tracker].get('internal', False) is True: + if meta['tag'] != "" and (meta['tag'][1:] in self.config['TRACKERS'][self.tracker].get('internal_groups', [])): + data['internal'] = 1 + + if region_id != 0: + data['region_id'] = region_id + if distributor_id != 0: + data['distributor_id'] = distributor_id + if meta.get('category') == "TV": + data['season_number'] = meta.get('season_int', '0') + data['episode_number'] = meta.get('episode_int', '0') + headers = { + 'User-Agent': f'Upload Assistant/2.1 ({platform.system()} {platform.release()})' + } + params = { + 'api_token': self.config['TRACKERS'][self.tracker]['api_key'].strip() + } + + if meta['debug'] is False: + response = requests.post(url=self.upload_url, files=files, data=data, headers=headers, params=params) + try: + console.print(response.json()) + except Exception: + console.print("It may have uploaded, go check") + return + else: + console.print("[cyan]Request Data:") + console.print(data) + open_torrent.close() + + async def search_existing(self, meta, disctype): + dupes = [] + console.print("[yellow]Searching for existing torrents on site...") + params = { + 'api_token': self.config['TRACKERS'][self.tracker]['api_key'].strip(), + 'tmdbId': meta['tmdb'], + 'categories[]': await self.get_cat_id(meta['category']), + 'types[]': await self.get_type_id(meta['type']), + 'resolutions[]': await self.get_res_id(meta['resolution']), + 'name': "" + } + if meta.get('edition', "") != "": + params['name'] = params['name'] + f" {meta['edition']}" + try: + response = requests.get(url=self.search_url, params=params) + response = response.json() + for each in response['data']: + result = [each][0]['attributes']['name'] + # difference = SequenceMatcher(None, meta['clean_name'], result).ratio() + # if difference >= 0.05: + dupes.append(result) + except Exception: + console.print('[bold red]Unable to search for existing torrents on site. Either the site is down or your API key is incorrect') + await asyncio.sleep(5) + + return dupes + + async def search_torrent_page(self, meta, disctype): + torrent_file_path = f"{meta['base_dir']}/tmp/{meta['uuid']}/[{self.tracker}]{meta['clean_name']}.torrent" + Name = meta['name'] + quoted_name = f'"{Name}"' + + params = { + 'api_token': self.config['TRACKERS'][self.tracker]['api_key'].strip(), + 'name': quoted_name + } + + try: + response = requests.get(url=self.search_url, params=params) + response.raise_for_status() + response_data = response.json() + + if response_data['data'] and isinstance(response_data['data'], list): + details_link = response_data['data'][0]['attributes'].get('details_link') + + if details_link: + with open(torrent_file_path, 'rb') as open_torrent: + torrent_data = open_torrent.read() + + torrent = bencodepy.decode(torrent_data) + torrent[b'comment'] = details_link.encode('utf-8') + updated_torrent_data = bencodepy.encode(torrent) + + with open(torrent_file_path, 'wb') as updated_torrent_file: + updated_torrent_file.write(updated_torrent_data) + + return details_link + else: + return None + else: + return None + + except requests.exceptions.RequestException as e: + print(f"An error occurred during the request: {e}") + return None diff --git a/upload.py b/upload.py index 273ddb27..d0897c2e 100644 --- a/upload.py +++ b/upload.py @@ -45,6 +45,7 @@ from src.trackers.PSS import PSS from src.trackers.ULCX import ULCX from src.trackers.SPD import SPD +from src.trackers.YOINK import YOINK import json from pathlib import Path import asyncio @@ -257,7 +258,7 @@ async def do_the_thing(base_dir): common = COMMON(config=config) api_trackers = [ 'ACM', 'AITHER', 'AL', 'BHD', 'BLU', 'CBR', 'FNP', 'HUNO', 'JPTV', 'LCD', 'LST', 'LT', - 'OE', 'OTW', 'PSS', 'RF', 'R4E', 'SHRI', 'STC', 'STT', 'TIK', 'ULCX', 'UTP' + 'OE', 'OTW', 'PSS', 'RF', 'R4E', 'SHRI', 'STC', 'STT', 'TIK', 'ULCX', 'UTP', 'YOINK' ] other_api_trackers = [ 'ANT', 'BHDTV', 'NBL', 'RTF', 'SN', 'SPD', 'TL', 'TVC' @@ -270,7 +271,7 @@ async def do_the_thing(base_dir): 'FNP': FNP, 'FL': FL, 'HDB': HDB, 'HDT': HDT, 'HP': HP, 'HUNO': HUNO, 'JPTV': JPTV, 'LCD': LCD, 'LST': LST, 'LT': LT, 'MTV': MTV, 'NBL': NBL, 'OE': OE, 'OTW': OTW, 'PSS': PSS, 'PTP': PTP, 'PTER': PTER, 'R4E': R4E, 'RF': RF, 'RTF': RTF, 'SHRI': SHRI, 'SN': SN, 'SPD': SPD, 'STC': STC, 'STT': STT, 'THR': THR, - 'TIK': TIK, 'TL': TL, 'TVC': TVC, 'TTG': TTG, 'ULCX': ULCX, 'UTP': UTP + 'TIK': TIK, 'TL': TL, 'TVC': TVC, 'TTG': TTG, 'ULCX': ULCX, 'UTP': UTP, 'YOINK': YOINK, } tracker_capabilities = {