def init_object_registries(): """Initializes RPC and tracker objects registries with settings from configuration file. :return: """ LOGGER.debug('Initializing objects registries from configuration file ...') cfg = config.load() settings_to_registry_map = { 'rpc': RPCClassesRegistry, 'notifiers': NotifierClassesRegistry, 'bots': BotClassesRegistry, } for settings_entry, registry_cls in settings_to_registry_map.items(): for alias, settings in cfg[settings_entry].items(): registry_obj = registry_cls.get(alias) registry_obj and registry_obj.spawn_with_settings(settings).register() # Special case for trackers to initialize public trackers automatically. for alias, tracker_cls in TrackerClassesRegistry.get().items(): settings = cfg['trackers'].get(alias) if settings is None: if issubclass(tracker_cls, GenericPrivateTracker): # No use in registering a private tracker without credentials. continue # Considered public tracker. Use default settings. tracker_cls.spawn_with_settings(settings or {}).register()
def init_object_registries(): """Initializes RPC and tracker objects registries with settings from configuration file. :return: """ LOGGER.debug('Initializing objects registries from configuration file ...') cfg = TorrtConfig.load() for alias, rpc_settings in cfg['rpc'].items(): rpc = RPCClassesRegistry.get(alias) if rpc is not None: obj = rpc.spawn_with_settings(rpc_settings) obj.register() for domain, tracker_settings in cfg['trackers'].items(): tracker = TrackerClassesRegistry.get(domain) if tracker is not None: obj = tracker.spawn_with_settings(tracker_settings) obj.register()
def configure_tracker(tracker_alias, settings_dict): """Configures tracker using given settings. Saves successful configuration. :param tracker_alias: tracker alias :param settings_dict: settings dictionary to configure tracker with :return: """ LOGGER.info('Configuring `%s` tracker ...', tracker_alias) tracker_class = TrackerClassesRegistry.get(tracker_alias) if tracker_class is not None: tracker_obj = tracker_class.spawn_with_settings(settings_dict) configured = tracker_obj.test_configuration() if configured: tracker_obj.save_settings() LOGGER.info('Tracker `%s` is configured', tracker_alias) else: LOGGER.error('Tracker `%s` configuration failed. Check your settings', tracker_alias) else: LOGGER.error('Tracker `%s` is unknown', tracker_alias)
def process_commands(): def settings_dict_from_list(lst): settings_dict = {} for s in lst: splitted = s.split('=') settings_dict[splitted[0]] = splitted[1] return settings_dict arg_parser = argparse.ArgumentParser('torrt', description='Automates torrent updates for you.', version='.'.join(map(str, VERSION))) arg_parser.add_argument('--verbose', help='Switch to show debug messages', dest='verbose', action='store_true') subp_main = arg_parser.add_subparsers(title='Supported commands', dest='command') subp_main.add_parser('list_rpc', help='Shows known RPCs aliases') subp_main.add_parser('list_trackers', help='Shows known trackers aliases') subp_main.add_parser('list_torrents', help='Shows torrents registered for updates') parser_configure_tracker = subp_main.add_parser('configure_tracker', help='Sets torrent tracker settings (login credentials, etc.)', description='E.g.: configure_tracker rutracker.org username=idle password=pSW0rt') parser_configure_tracker.add_argument('tracker_alias', help='Tracker alias (usually domain) to apply settings to') parser_configure_tracker.add_argument('settings', help='Settings string, format: setting1=val1 setting2=val2. Supported settings (any of): username, password', nargs='*') parser_configure_rpc = subp_main.add_parser('configure_rpc', help='Sets RPCs settings (login credentials, etc.)', description='E.g.: configure_rpc transmission user=idle password=pSW0rt') parser_configure_rpc.add_argument('rpc_alias', help='RPC alias to apply settings to') parser_configure_rpc.add_argument('settings', help='Settings string, format: setting1=val1 setting2=val2. Supported settings (any of): url, host, port, user, password', nargs='*') parser_walk = subp_main.add_parser('walk', help='Walks through registered torrents and performs automatic updates') parser_walk.add_argument('-f', help='Forces walk. Forced walks do not respect walk interval settings', dest='forced', action='store_true') parser_set_interval = subp_main.add_parser('set_walk_interval', help='Sets an interval *in hours* between consecutive torrent updates checks') parser_set_interval.add_argument('walk_interval', help='Interval *in hours* between consecutive torrent updates checks') parser_enable_rpc = subp_main.add_parser('enable_rpc', help='Enables RPC by its alias') parser_enable_rpc.add_argument('alias', help='Alias of RPC to enable') parser_disable_rpc = subp_main.add_parser('disable_rpc', help='Disables RPC by its alias') parser_disable_rpc.add_argument('alias', help='Alias of RPC to disable') parser_add_torrent = subp_main.add_parser('add_torrent', help='Adds torrent from an URL both to torrt and torrent clients') parser_add_torrent.add_argument('url', help='URL to download torrent from') parser_add_torrent.add_argument('-d', help='Destination path to download torrent contents into (in filesystem where torrent client daemon works)', dest='download_to', default=None) parser_remove_torrent = subp_main.add_parser('remove_torrent', help='Removes torrent by its hash both from torrt and torrent clients') parser_remove_torrent.add_argument('hash', help='Torrent identifying hash') parser_remove_torrent.add_argument('-d', help='If set data downloaded for torrent will also be removed', dest='delete_data', action='store_true') parser_register_torrent = subp_main.add_parser('register_torrent', help='Registers torrent within torrt by its hash (for torrents already existing at torrent clients)') parser_register_torrent.add_argument('hash', help='Torrent identifying hash') parser_unregister_torrent = subp_main.add_parser('unregister_torrent', help='Unregisters torrent from torrt by its hash') parser_unregister_torrent.add_argument('hash', help='Torrent identifying hash') args = arg_parser.parse_args() args = vars(args) loggin_level = logging.INFO if args['verbose']: loggin_level = logging.DEBUG configure_logging(loggin_level) bootstrap() if args['command'] == 'enable_rpc': toggle_rpc(args['alias'], True) elif args['command'] == 'disable_rpc': toggle_rpc(args['alias'], False) elif args['command'] == 'list_trackers': for tracker_alias, tracker in TrackerClassesRegistry.get().items(): LOGGER.info(tracker_alias) elif args['command'] == 'list_rpc': rpc_statuses = {} for rpc_alias, rpc in RPCClassesRegistry.get().items(): rpc_statuses[rpc_alias] = 'unconfigured' for rpc_alias, rpc in RPCObjectsRegistry.get().items(): rpc_statuses[rpc_alias] = 'enabled' if rpc.enabled else 'disabled' for rpc_alias, rpc_status in rpc_statuses.items(): LOGGER.info('%s\t status=%s' % (rpc_alias, rpc_status)) elif args['command'] == 'list_torrents': for torrent_hash, torrent_data in get_registerd_torrents().items(): LOGGER.info('%s\t%s' % (torrent_hash, torrent_data['name'])) elif args['command'] == 'walk': walk(forced=args['forced'], silent=True) elif args['command'] == 'set_walk_interval': set_walk_interval(args['walk_interval']) elif args['command'] == 'add_torrent': add_torrent_from_url(args['url'], args['download_to']) elif args['command'] == 'remove_torrent': remove_torrent(args['hash'], args['delete_data']) elif args['command'] == 'register_torrent': register_torrent(args['hash']) elif args['command'] == 'unregister_torrent': unregister_torrent(args['hash']) elif args['command'] == 'configure_rpc': configure_rpc(args['rpc_alias'], settings_dict_from_list(args['settings'])) elif args['command'] == 'configure_tracker': configure_tracker(args['tracker_alias'], settings_dict_from_list(args['settings']))
} def before_download(self, url): """Used to perform some required actions right before .torrent download.""" self.cookies['bb_dl'] = self.get_id_from_link( url) # A check that user himself have visited torrent's page ;) def get_download_link(self, url): """Tries to find .torrent file download link at forum thread page and return that one.""" page_soup = self.get_response(url, referer=url, cookies=self.cookies, query_string=self.query_string, as_soup=True) page_links = self.find_links(url, page_soup) download_link = None for page_link in page_links: if 'dl.rutracker.org' in page_link: download_link = page_link if 'guest' in download_link: download_link = None LOGGER.debug('Login is required to download torrent file') if self.login(): download_link = self.get_download_link(url) break return download_link # With that one we tell torrt to handle links to `rutracker.org` domain with RutrackerHandler class. TrackerClassesRegistry.add(RuTrackerTracker)
url, referer=url, cookies=self.cookies, query_string=self.query_string, as_soup=True ) download_link = self.find_links(url, page_soup, r'dl\.php') self.form_token = self.get_form_token(page_soup) return download_link def get_form_token(self, page_soup): form_token_lines = [line for line in page_soup.text.split('\n\t') if line.startswith('form_token')] try: return form_token_lines[0].split(':')[1][2:-2] except IndexError: return def download_torrent(self, url, referer=None): LOGGER.debug('Downloading torrent file from %s ...', url) self.before_download(url) # rutracker require POST action to download torrent file if self.form_token: form_data = {'form_token': self.form_token} else: form_data = None response = self.get_response( url, form_data=form_data, cookies=self.cookies, query_string=self.get_auth_query_string(), referer=referer ) if response is None: return None return response.content # With that one we tell torrt to handle links to `rutracker.org` domain with RutrackerHandler class. TrackerClassesRegistry.add(RuTrackerTracker)
def process_commands(): def settings_dict_from_list(lst): settings_dict = {} for s in lst: splitted = s.split('=') settings_dict[splitted[0]] = splitted[1] return settings_dict arg_parser = argparse.ArgumentParser( 'torrt', description='Automates torrent updates for you.') arg_parser.add_argument('--version', action='version', version='%(prog)s ' + '.'.join(map(str, VERSION))) subp_main = arg_parser.add_subparsers(title='Supported commands', dest='command') subp_main.add_parser('list_rpc', help='Shows known RPCs aliases') subp_main.add_parser('list_trackers', help='Shows known trackers aliases') subp_main.add_parser('list_torrents', help='Shows torrents registered for updates') subp_main.add_parser('list_notifiers', help='Shows configured notifiers') parser_configure_tracker = subp_main.add_parser( 'configure_tracker', help='Sets torrent tracker settings (login credentials, etc.)', description= 'E.g.: configure_tracker rutracker.org username=idle password=pSW0rt') parser_configure_tracker.add_argument( 'tracker_alias', help='Tracker alias (usually domain) to apply settings to') parser_configure_tracker.add_argument( 'settings', help='Settings string, format: setting1=val1 setting2=val2. ' 'Supported settings (any of): username, password', nargs='*') parser_configure_rpc = subp_main.add_parser( 'configure_rpc', help='Sets RPCs settings (login credentials, etc.)', description='E.g.: configure_rpc transmission user=idle password=pSW0rt' ) parser_configure_rpc.add_argument('rpc_alias', help='RPC alias to apply settings to') parser_configure_rpc.add_argument( 'settings', help='Settings string, format: setting1=val1 setting2=val2. ' 'Supported settings (any of): url, host, port, user, password', nargs='*') parser_configure_notifier = subp_main.add_parser( 'configure_notifier', help='Sets Notifiers settings (smtp credentials, etc.)', description= 'E.g.: configure_notifier email [email protected] user=idle password=pSW0rt' ) parser_configure_notifier.add_argument( 'notifier_alias', help='Notifier alias to apply settings to') parser_configure_notifier.add_argument( 'settings', help='Settings string, format: setting1=val1 setting2=val2. ' 'Supported settings for email notifier (any of): email, host, port, use_tls, user, password.' 'Supported settings for telegram notifier: token, chat_id.', nargs='*') parser_configure_bot = subp_main.add_parser( 'configure_bot', help='Sets Bot settings (token, etc.)', description='E.g.: configure_bot telegram token=YourBotSuperToken') parser_configure_bot.add_argument('bot_alias', help='Bot alias to apply settings to') parser_configure_bot.add_argument( 'settings', help='Settings string, format: setting1=val1 setting2=val2. ' 'Supported settings for telegram bot: token.', nargs='*') parser_walk = subp_main.add_parser( 'walk', help='Walks through registered torrents and performs automatic updates' ) parser_walk.add_argument( '-f', help='Forces walk. Forced walks do not respect walk interval settings', dest='forced', action='store_true') parser_walk.add_argument( '--dump', help= 'Dump web pages scraped by torrt into current or a given directory', dest='dump') parser_run_bots = subp_main.add_parser('run_bots', help='Run registered bots') parser_run_bots.add_argument('aliases', help='Bots to run aliases', nargs='*') parser_set_interval = subp_main.add_parser( 'set_walk_interval', help= 'Sets an interval *in hours* between consecutive torrent updates checks' ) parser_set_interval.add_argument( 'walk_interval', help='Interval *in hours* between consecutive torrent updates checks') parser_enable_rpc = subp_main.add_parser('enable_rpc', help='Enables RPC by its alias') parser_enable_rpc.add_argument('alias', help='Alias of RPC to enable') parser_disable_rpc = subp_main.add_parser('disable_rpc', help='Disables RPC by its alias') parser_disable_rpc.add_argument('alias', help='Alias of RPC to disable') parser_add_torrent = subp_main.add_parser( 'add_torrent', help='Adds torrent from an URL both to torrt and torrent clients') parser_add_torrent.add_argument('url', help='URL to download torrent from') parser_add_torrent.add_argument( '-d', help= 'Destination path to download torrent contents into (in filesystem where torrent client daemon works)', dest='download_to', default=None) parser_add_torrent.add_argument( '--dump', help= 'Dump web pages scraped by torrt into current or a given directory', dest='dump') parser_remove_torrent = subp_main.add_parser( 'remove_torrent', help='Removes torrent by its hash both from torrt and torrent clients') parser_remove_torrent.add_argument('hash', help='Torrent identifying hash') parser_remove_torrent.add_argument( '-d', help='If set data downloaded for torrent will also be removed', dest='delete_data', action='store_true') parser_register_torrent = subp_main.add_parser( 'register_torrent', help= 'Registers torrent within torrt by its hash (for torrents already existing at torrent clients)' ) parser_register_torrent.add_argument('hash', help='Torrent identifying hash') parser_register_torrent.add_argument('-u', dest='url', default=None, help='URL to download torrent from') parser_unregister_torrent = subp_main.add_parser( 'unregister_torrent', help='Unregisters torrent from torrt by its hash') parser_unregister_torrent.add_argument('hash', help='Torrent identifying hash') parser_remove_notifier = subp_main.add_parser( 'remove_notifier', help='Remove configured notifier by its alias') parser_remove_notifier.add_argument('alias', help='Alias of notifier to remove') for parser in subp_main.choices.values(): parser.add_argument('--verbose', help='Switch to show debug messages', dest='verbose', action='store_true') args = arg_parser.parse_args() args = vars(args) configure_logging(logging.DEBUG if args.get('verbose') else logging.INFO) bootstrap() dump_into = args.get('dump') if dump_into: GlobalParam.set('dump_into', path.abspath(dump_into)) if args['command'] == 'enable_rpc': toggle_rpc(args['alias'], True) elif args['command'] == 'disable_rpc': toggle_rpc(args['alias'], False) elif args['command'] == 'list_trackers': for tracker_alias, _ in TrackerClassesRegistry.get().items(): LOGGER.info(tracker_alias) elif args['command'] == 'list_rpc': rpc_statuses = {} for rpc_alias, rpc in RPCClassesRegistry.get().items(): rpc_statuses[rpc_alias] = 'unconfigured' for rpc_alias, rpc in RPCObjectsRegistry.get().items(): rpc_statuses[rpc_alias] = 'enabled' if rpc.enabled else 'disabled' for rpc_alias, rpc_status in rpc_statuses.items(): LOGGER.info(f'{rpc_alias}\t status={rpc_status}') elif args['command'] == 'list_torrents': for torrent_hash, torrent_data in get_registered_torrents().items(): LOGGER.info(f"{torrent_hash}\t{torrent_data['name']}") elif args['command'] == 'list_notifiers': notifiers = {} for notifier_alias in NotifierClassesRegistry.get().keys(): notifiers[notifier_alias] = 'unconfigured' for notifier_alias in NotifierObjectsRegistry.get().keys(): notifiers[notifier_alias] = 'enabled' for notifier_alias, notifier_status in notifiers.items(): LOGGER.info(f"{notifier_alias}\t status={notifier_status}") elif args['command'] == 'walk': walk(forced=args['forced'], silent=True) elif args['command'] == 'set_walk_interval': set_walk_interval(args['walk_interval']) elif args['command'] == 'add_torrent': add_torrent_from_url(args['url'], args['download_to']) elif args['command'] == 'remove_torrent': remove_torrent(args['hash'], args['delete_data']) elif args['command'] == 'register_torrent': register_torrent(args['hash'], url=args['url']) elif args['command'] == 'unregister_torrent': unregister_torrent(args['hash']) elif args['command'] == 'configure_rpc': configure_rpc(args['rpc_alias'], settings_dict_from_list(args['settings'])) elif args['command'] == 'configure_tracker': configure_tracker(args['tracker_alias'], settings_dict_from_list(args['settings'])) elif args['command'] == 'configure_notifier': configure_notifier(args['notifier_alias'], settings_dict_from_list(args['settings'])) elif args['command'] == 'remove_notifier': remove_notifier(args['alias']) elif args['command'] == 'configure_bot': configure_bot(args['bot_alias'], settings_dict_from_list(args['settings'])) elif args['command'] == 'run_bots': run_bots(args['aliases'])
class KinozalTracker(GenericPrivateTracker): """This class implements .torrent files downloads for http://kinozal.tv/ tracker.""" alias = 'kinozal.tv' login_url = 'http://%(domain)s/takelogin.php' auth_cookie_name = 'uid' mirrors = ['kinozal.me'] encoding = 'cp1251' def get_login_form_data(self, login, password): """Returns a dictionary with data to be pushed to authorization form.""" return {'username': login, 'password': password, 'returnto': ''} def get_id_from_link(self, url): """Returns forum thread identifier from full thread URL.""" return url.split('=')[1] def get_download_link(self, url): """Tries to find .torrent file download link at forum thread page and return that one.""" response = self.get_response(url, cookies=self.cookies) page_soup = self.make_page_soup(response.text) expected_link = '/download.+\=%s' % self.get_id_from_link(url) download_link = self.find_links(url, page_soup, definite=expected_link) return download_link TrackerClassesRegistry.add(KinozalTracker)
quality_divs = page_soup.select('div.torrent > div.torrent_c > div') for quality_div in quality_divs: available_qualities.append(quality_div['id']) LOGGER.debug('Available in qualities: %s' % ', '.join(available_qualities)) if available_qualities: prefered_qualities = [quality for quality in self.quality_prefs if quality in available_qualities] if not prefered_qualities: LOGGER.debug('Torrent is not available in preferred qualities: %s' % ', '.join(self.quality_prefs)) else: target_quality = prefered_qualities[0] LOGGER.debug('Trying to get torrent in `%s` quality ...' % target_quality) target_links = page_soup.select('div#%s div.torrent_h a' % target_quality) if target_links: if isinstance(target_links, list): download_link = target_links[0]['href'] else: download_link = target_links['href'] download_link = self.expand_link(url, download_link) else: LOGGER.debug('Unable to find a link for `%s` quality' % target_quality) return download_link TrackerClassesRegistry.add(AniDUBTracker)
prefered_qualities = [ quality for quality in self.quality_prefs if quality in available_qualities ] if not prefered_qualities: LOGGER.debug( 'Torrent is not available in preferred qualities: %s', ', '.join(self.quality_prefs)) else: target_quality = prefered_qualities[0] LOGGER.debug('Trying to get torrent in `%s` quality ...', target_quality) target_links = page_soup.select('div#%s div.torrent_h a' % target_quality) if target_links: if isinstance(target_links, list): download_link = target_links[0]['href'] else: download_link = target_links['href'] download_link = self.expand_link(url, download_link) else: LOGGER.debug('Unable to find a link for `%s` quality', target_quality) return download_link TrackerClassesRegistry.add(AniDUBTracker)
url, div.select('div.torrent-fourth-col a.torrent-download-link' )[0]['href']) available_qualities[quality] = link else: LOGGER.warning('Cannot extract quality from `%s`', quality_str) LOGGER.debug('Available in qualities: %s', ', '.join(available_qualities.keys())) if available_qualities: preferred_qualities = [ quality for quality in self.quality_prefs if quality in available_qualities ] if not preferred_qualities: LOGGER.debug( 'Torrent is not available in preferred qualities: %s', ', '.join(self.quality_prefs)) else: target_quality = preferred_qualities[0] LOGGER.debug('Trying to get torrent in `%s` quality ...', target_quality) return available_qualities[target_quality] return None TrackerClassesRegistry.add(AnilibriaTracker)
def get_login_form_data(self, login, password): index_page = self.get_response(url=(self.login_url % {'domain': self.alias})) soup_response = self.make_page_soup(index_page.text) sid = soup_response.find(attrs={'name': 'sid'}).get('value') self.cookies = index_page.cookies self.login_url += '&sid=%s' % sid return {'username': login, 'password': password, 'autologin': '******', 'redirect': 'index.php', 'sid': sid, 'login': six.u('Вход')} def get_download_link(self, url): """Tries to find .torrent file download link at forum thread page and return that one.""" page_soup = self.get_response( url, referer=url, cookies=self.cookies, query_string=self.query_string, as_soup=True ) domain = self.extract_domain(url) is_anonymous = self.find_links(url, page_soup, r'\./ucp\.php\?mode=login') is not None if not self.logged_in or is_anonymous: self.logged_in = False self.login(domain) page_soup = self.get_response( url, referer=url, cookies=self.cookies, query_string=self.query_string, as_soup=True ) download_tag = page_soup.find('a', text='Скачать торрент') if download_tag: return self.expand_link(url, download_tag['href']) TrackerClassesRegistry.add(CasstudioTracker)
def process_commands(): def settings_dict_from_list(lst): settings_dict = {} for s in lst: splitted = s.split('=') settings_dict[splitted[0]] = splitted[1] return settings_dict arg_parser = argparse.ArgumentParser( 'torrt', description='Automates torrent updates for you.', version='.'.join(map(str, VERSION))) arg_parser.add_argument('--verbose', help='Switch to show debug messages', dest='verbose', action='store_true') subp_main = arg_parser.add_subparsers(title='Supported commands', dest='command') subp_main.add_parser('list_rpc', help='Shows known RPCs aliases') subp_main.add_parser('list_trackers', help='Shows known trackers aliases') subp_main.add_parser('list_torrents', help='Shows torrents registered for updates') parser_configure_tracker = subp_main.add_parser( 'configure_tracker', help='Sets torrent tracker settings (login credentials, etc.)', description= 'E.g.: configure_tracker rutracker.org username=idle password=pSW0rt') parser_configure_tracker.add_argument( 'tracker_alias', help='Tracker alias (usually domain) to apply settings to') parser_configure_tracker.add_argument( 'settings', help='Settings string, format: setting1=val1 setting2=val2. ' 'Supported settings (any of): username, password', nargs='*') parser_configure_rpc = subp_main.add_parser( 'configure_rpc', help='Sets RPCs settings (login credentials, etc.)', description='E.g.: configure_rpc transmission user=idle password=pSW0rt' ) parser_configure_rpc.add_argument('rpc_alias', help='RPC alias to apply settings to') parser_configure_rpc.add_argument( 'settings', help='Settings string, format: setting1=val1 setting2=val2. ' 'Supported settings (any of): url, host, port, user, password', nargs='*') parser_walk = subp_main.add_parser( 'walk', help='Walks through registered torrents and performs automatic updates' ) parser_walk.add_argument( '-f', help='Forces walk. Forced walks do not respect walk interval settings', dest='forced', action='store_true') parser_set_interval = subp_main.add_parser( 'set_walk_interval', help= 'Sets an interval *in hours* between consecutive torrent updates checks' ) parser_set_interval.add_argument( 'walk_interval', help='Interval *in hours* between consecutive torrent updates checks') parser_enable_rpc = subp_main.add_parser('enable_rpc', help='Enables RPC by its alias') parser_enable_rpc.add_argument('alias', help='Alias of RPC to enable') parser_disable_rpc = subp_main.add_parser('disable_rpc', help='Disables RPC by its alias') parser_disable_rpc.add_argument('alias', help='Alias of RPC to disable') parser_add_torrent = subp_main.add_parser( 'add_torrent', help='Adds torrent from an URL both to torrt and torrent clients') parser_add_torrent.add_argument('url', help='URL to download torrent from') parser_add_torrent.add_argument( '-d', help= 'Destination path to download torrent contents into (in filesystem where torrent client daemon works)', dest='download_to', default=None) parser_remove_torrent = subp_main.add_parser( 'remove_torrent', help='Removes torrent by its hash both from torrt and torrent clients') parser_remove_torrent.add_argument('hash', help='Torrent identifying hash') parser_remove_torrent.add_argument( '-d', help='If set data downloaded for torrent will also be removed', dest='delete_data', action='store_true') parser_register_torrent = subp_main.add_parser( 'register_torrent', help= 'Registers torrent within torrt by its hash (for torrents already existing at torrent clients)' ) parser_register_torrent.add_argument('hash', help='Torrent identifying hash') parser_unregister_torrent = subp_main.add_parser( 'unregister_torrent', help='Unregisters torrent from torrt by its hash') parser_unregister_torrent.add_argument('hash', help='Torrent identifying hash') args = arg_parser.parse_args() args = vars(args) loggin_level = logging.INFO if args['verbose']: loggin_level = logging.DEBUG configure_logging(loggin_level) bootstrap() if args['command'] == 'enable_rpc': toggle_rpc(args['alias'], True) elif args['command'] == 'disable_rpc': toggle_rpc(args['alias'], False) elif args['command'] == 'list_trackers': for tracker_alias, _ in TrackerClassesRegistry.get().items(): LOGGER.info(tracker_alias) elif args['command'] == 'list_rpc': rpc_statuses = {} for rpc_alias, rpc in RPCClassesRegistry.get().items(): rpc_statuses[rpc_alias] = 'unconfigured' for rpc_alias, rpc in RPCObjectsRegistry.get().items(): rpc_statuses[rpc_alias] = 'enabled' if rpc.enabled else 'disabled' for rpc_alias, rpc_status in rpc_statuses.items(): LOGGER.info('%s\t status=%s', rpc_alias, rpc_status) elif args['command'] == 'list_torrents': for torrent_hash, torrent_data in get_registerd_torrents().items(): LOGGER.info('%s\t%s', torrent_hash, torrent_data['name']) elif args['command'] == 'walk': walk(forced=args['forced'], silent=True) elif args['command'] == 'set_walk_interval': set_walk_interval(args['walk_interval']) elif args['command'] == 'add_torrent': add_torrent_from_url(args['url'], args['download_to']) elif args['command'] == 'remove_torrent': remove_torrent(args['hash'], args['delete_data']) elif args['command'] == 'register_torrent': register_torrent(args['hash']) elif args['command'] == 'unregister_torrent': unregister_torrent(args['hash']) elif args['command'] == 'configure_rpc': configure_rpc(args['rpc_alias'], settings_dict_from_list(args['settings'])) elif args['command'] == 'configure_tracker': configure_tracker(args['tracker_alias'], settings_dict_from_list(args['settings']))
class NNMClubTracker(GenericPrivateTracker): """This class implements .torrent files downloads for http://nnm-club.me tracker.""" alias = "nnm-club.me" login_url = "http://nnm-club.me/forum/login.php" auth_qs_param_name = "sid" def get_login_form_data(self, login, password): """Returns a dictionary with data to be pushed to authorization form.""" return {"username": login, "password": password, "autologin": 1, "redirect": "", "login": "******"} def get_download_link(self, url): """Tries to find .torrent file download link at forum thread page and return that one.""" page_soup = self.get_response( url, referer=url, cookies=self.cookies, query_string=self.get_auth_query_string(), as_soup=True ) download_link = self.find_links(url, page_soup, definite="download\.php") if download_link is None: LOGGER.debug("Login is required to download torrent file") if self.login(): download_link = self.get_download_link(url) return download_link # With that one we tell torrt to handle links to `nnm-club.me` domain with NNMClubTracker class. TrackerClassesRegistry.add(NNMClubTracker)
else: target_quality = preferred_qualities[0] LOGGER.debug('Trying to get torrent in `%s` quality ...', target_quality) return available_qualities[target_quality] return None @staticmethod def sanitize_quality(quality_str): """ Turn passed quality_str into common format in order to simplify comparison. Examples: * `sanitize_quality('WEBRip 1080p')` -> 'webrip1080p' * `sanitize_quality('WEBRip-1080p')` -> 'webrip1080p' * `sanitize_quality('WEBRip_1080p')` -> 'webrip1080p' * `sanitize_quality('')` -> '' * `sanitize_quality(None)` -> '' :type quality_str: Optional[str] :param quality_str: originally extracted quality string with non-word characters :return: quality string without non-word characters in lower-case """ if quality_str: return REGEX_NON_WORD.sub('', quality_str).lower() return '' TrackerClassesRegistry.add(AnilibriaTracker)
return { 'username': login, 'password': password, 'autologin': 1, 'redirect': '', 'login': '******' } def get_download_link(self, url): """Tries to find .torrent file download link at forum thread page and return that one.""" page_soup = self.get_response( url, referer=url, cookies=self.cookies, query_string=self.get_auth_query_string(), as_soup=True) download_link = self.find_links(url, page_soup, definite='download\.php') if download_link is None: LOGGER.debug('Login is required to download torrent file') if self.login(): download_link = self.get_download_link(url) return download_link # With that one we tell torrt to handle links to `nnm-club.me` domain with NNMClubTracker class. TrackerClassesRegistry.add(NNMClubTracker)
def process_commands(): def settings_dict_from_list(lst): settings_dict = {} for s in lst: splitted = s.split('=') settings_dict[splitted[0]] = splitted[1] return settings_dict arg_parser = argparse.ArgumentParser('torrt', description='Automates torrent updates for you.') arg_parser.add_argument('--version', action='version', version='%(prog)s ' + '.'.join(map(str, VERSION))) subp_main = arg_parser.add_subparsers(title='Supported commands', dest='command') subp_main.add_parser('list_rpc', help='Shows known RPCs aliases') subp_main.add_parser('list_trackers', help='Shows known trackers aliases') subp_main.add_parser('list_torrents', help='Shows torrents registered for updates') subp_main.add_parser('list_notifiers', help='Shows configured notifiers') parser_configure_tracker = subp_main.add_parser( 'configure_tracker', help='Sets torrent tracker settings (login credentials, etc.)', description='E.g.: configure_tracker rutracker.org username=idle password=pSW0rt') parser_configure_tracker.add_argument( 'tracker_alias', help='Tracker alias (usually domain) to apply settings to') parser_configure_tracker.add_argument( 'settings', help='Settings string, format: setting1=val1 setting2=val2. ' 'Supported settings (any of): username, password', nargs='*') parser_configure_rpc = subp_main.add_parser( 'configure_rpc', help='Sets RPCs settings (login credentials, etc.)', description='E.g.: configure_rpc transmission user=idle password=pSW0rt') parser_configure_rpc.add_argument( 'rpc_alias', help='RPC alias to apply settings to') parser_configure_rpc.add_argument( 'settings', help='Settings string, format: setting1=val1 setting2=val2. ' 'Supported settings (any of): url, host, port, user, password', nargs='*') parser_configure_notifier = subp_main.add_parser( 'configure_notifier', help='Sets Notifiers settings (smtp credentials, etc.)', description='E.g.: configure_notifier email [email protected] user=idle password=pSW0rt') parser_configure_notifier.add_argument( 'notifier_alias', help='Notifier alias to apply settings to') parser_configure_notifier.add_argument( 'settings', help='Settings string, format: setting1=val1 setting2=val2. ' 'Supported settings for email notifier (any of): email, host, port, use_tls, user, password.' 'Supported settings for telegram notifier: token, chat_id.', nargs='*') parser_configure_bot = subp_main.add_parser( 'configure_bot', help='Sets Bot settings (token, etc.)', description='E.g.: configure_bot telegram token=YourBotSuperToken') parser_configure_bot.add_argument( 'bot_alias', help='Bot alias to apply settings to') parser_configure_bot.add_argument( 'settings', help='Settings string, format: setting1=val1 setting2=val2. ' 'Supported settings for telegram bot: token.', nargs='*') parser_walk = subp_main.add_parser( 'walk', help='Walks through registered torrents and performs automatic updates') parser_walk.add_argument( '-f', help='Forces walk. Forced walks do not respect walk interval settings', dest='forced', action='store_true') parser_walk.add_argument( '--dump', help='Dump web pages scraped by torrt into current or a given directory', dest='dump') parser_run_bots = subp_main.add_parser( 'run_bots', help='Run registered bots') parser_run_bots.add_argument( 'aliases', help='Bots to run aliases', nargs='*') parser_set_interval = subp_main.add_parser( 'set_walk_interval', help='Sets an interval *in hours* between consecutive torrent updates checks') parser_set_interval.add_argument( 'walk_interval', help='Interval *in hours* between consecutive torrent updates checks') parser_enable_rpc = subp_main.add_parser('enable_rpc', help='Enables RPC by its alias') parser_enable_rpc.add_argument('alias', help='Alias of RPC to enable') parser_disable_rpc = subp_main.add_parser('disable_rpc', help='Disables RPC by its alias') parser_disable_rpc.add_argument('alias', help='Alias of RPC to disable') parser_add_torrent = subp_main.add_parser( 'add_torrent', help='Adds torrent from an URL both to torrt and torrent clients') parser_add_torrent.add_argument( 'url', help='URL to download torrent from') parser_add_torrent.add_argument( '-d', help='Destination path to download torrent contents into (in filesystem where torrent client daemon works)', dest='download_to', default=None) parser_remove_torrent = subp_main.add_parser( 'remove_torrent', help='Removes torrent by its hash both from torrt and torrent clients') parser_remove_torrent.add_argument( 'hash', help='Torrent identifying hash') parser_remove_torrent.add_argument( '-d', help='If set data downloaded for torrent will also be removed', dest='delete_data', action='store_true') parser_register_torrent = subp_main.add_parser( 'register_torrent', help='Registers torrent within torrt by its hash (for torrents already existing at torrent clients)') parser_register_torrent.add_argument( 'hash', help='Torrent identifying hash') parser_register_torrent.add_argument( '-u', dest='url', default=None, help='URL to download torrent from') parser_unregister_torrent = subp_main.add_parser( 'unregister_torrent', help='Unregisters torrent from torrt by its hash') parser_unregister_torrent.add_argument( 'hash', help='Torrent identifying hash') parser_remove_notifier = subp_main.add_parser( 'remove_notifier', help='Remove configured notifier by its alias') parser_remove_notifier.add_argument('alias', help='Alias of notifier to remove') for parser in subp_main.choices.values(): parser.add_argument('--verbose', help='Switch to show debug messages', dest='verbose', action='store_true') args = arg_parser.parse_args() args = vars(args) configure_logging(logging.DEBUG if args.get('verbose') else logging.INFO) bootstrap() if args['command'] == 'enable_rpc': toggle_rpc(args['alias'], True) elif args['command'] == 'disable_rpc': toggle_rpc(args['alias'], False) elif args['command'] == 'list_trackers': for tracker_alias, _ in TrackerClassesRegistry.get().items(): LOGGER.info(tracker_alias) elif args['command'] == 'list_rpc': rpc_statuses = {} for rpc_alias, rpc in RPCClassesRegistry.get().items(): rpc_statuses[rpc_alias] = 'unconfigured' for rpc_alias, rpc in RPCObjectsRegistry.get().items(): rpc_statuses[rpc_alias] = 'enabled' if rpc.enabled else 'disabled' for rpc_alias, rpc_status in rpc_statuses.items(): LOGGER.info('%s\t status=%s', rpc_alias, rpc_status) elif args['command'] == 'list_torrents': for torrent_hash, torrent_data in get_registered_torrents().items(): LOGGER.info('%s\t%s', torrent_hash, torrent_data['name']) elif args['command'] == 'list_notifiers': notifiers = {} for notifier_alias in NotifierClassesRegistry.get().keys(): notifiers[notifier_alias] = 'unconfigured' for notifier_alias in NotifierObjectsRegistry.get().keys(): notifiers[notifier_alias] = 'enabled' for notifier_alias, notifier_status in notifiers.items(): LOGGER.info('%s\t status=%s', notifier_alias, notifier_status) elif args['command'] == 'walk': dump_into = args.get('dump') if dump_into: GlobalParam.set('dump_into', path.abspath(dump_into)) walk(forced=args['forced'], silent=True) elif args['command'] == 'set_walk_interval': set_walk_interval(args['walk_interval']) elif args['command'] == 'add_torrent': add_torrent_from_url(args['url'], args['download_to']) elif args['command'] == 'remove_torrent': remove_torrent(args['hash'], args['delete_data']) elif args['command'] == 'register_torrent': register_torrent(args['hash'], url=args['url']) elif args['command'] == 'unregister_torrent': unregister_torrent(args['hash']) elif args['command'] == 'configure_rpc': configure_rpc(args['rpc_alias'], settings_dict_from_list(args['settings'])) elif args['command'] == 'configure_tracker': configure_tracker(args['tracker_alias'], settings_dict_from_list(args['settings'])) elif args['command'] == 'configure_notifier': configure_notifier(args['notifier_alias'], settings_dict_from_list(args['settings'])) elif args['command'] == 'remove_notifier': remove_notifier(args['alias']) elif args['command'] == 'configure_bot': configure_bot(args['bot_alias'], settings_dict_from_list(args['settings'])) elif args['command'] == 'run_bots': run_bots(args['aliases'])