def __init__(self, config_section): super(HDBits, self).__init__(config_section) self.endpoint = config.get_default(self._config_section, 'endpoint', 'https://hdbits.org/api') self.enabled = config.getboolean(self._config_section, 'enabled') self.interval = config.get_default(self._config_section, 'interval', self.interval, int)
def login(self): user = config.get_default(self._config_section, 'user', None) password = config.get_default(self._config_section, 'password', None) passkey = config.get_default(self._config_section, 'passkey', None) if not user and password and passkey: self.log.warn("Cannot use PTP service, no username or password set") return False try: resp = self.session.post( 'https://tls.passthepopcorn.me/ajax.php?action=login', { 'username': user, 'password': password, 'passkey': passkey, 'keeplogged': '1', 'login': '******' } ) if not resp.status_code == 200: raise ApiError("Invalid response code received: {}".format(resp.status_code)) data = resp.json() if not data['Result'].upper() == 'OK': raise AuthenticationError(data['Message']) except (ApiError, AuthenticationError) as err: self.log.error(err.message) except Exception as err: self.log.exception(err) else: self._authenticated = True return self._authenticated
def smtp_client(): """ Create a configured SMTP instance ready to send :return: :rtype: """ srv = None try: use_ssl = config.get_default_boolean(_config_key, 'ssl', False) username = config.get_default(_config_key, 'username', "") password = config.get_default(_config_key, 'password', "") args = { 'host': config.get_default(_config_key, 'host', 'localhost'), 'port': config.get_default(_config_key, 'port', 25, int) } if use_ssl: srv = smtplib.SMTP_SSL(**args) else: srv = smtplib.SMTP(**args) if config.get_default_boolean(_config_key, 'starttls', False): srv.starttls() if username and password: srv.login(username, password) yield srv finally: if srv and hasattr(srv, 'quit'): srv.quit()
def login(self): user = config.get_default(self._config_section, 'user', None) password = config.get_default(self._config_section, 'password', None) passkey = config.get_default(self._config_section, 'passkey', None) if not user and password and passkey: self.log.warn( "Cannot use PTP service, no username or password set") return False try: resp = self.session.post( 'https://tls.passthepopcorn.me/ajax.php?action=login', { 'username': user, 'password': password, 'passkey': passkey, 'keeplogged': '1', 'login': '******' }) if not resp.status_code == 200: raise ApiError("Invalid response code received: {}".format( resp.status_code)) data = resp.json() if not data['Result'].upper() == 'OK': raise AuthenticationError(data['Message']) except (ApiError, AuthenticationError) as err: self.log.error(err.message) except Exception as err: self.log.exception(err) else: self._authenticated = True return self._authenticated
def __init__(self, config_section): super(PTP, self).__init__(config_section) self.endpoint = config.get_default(self._config_section, 'endpoint', 'https://tls.passthepopcorn.me') self.enabled = config.getboolean(self._config_section, 'enabled') self.interval = config.get_default(self._config_section, 'interval', self.interval, int) self._authenticated = False self.session = requests.Session() if self.enabled: self.login()
def init_webui(self): """ Initialize and start the flask based webui. This does not check if it is enabled, so that must happen prior to calling this :return: :rtype: """ host = config.get_default('flask', 'listen_host', 'localhost') port = config.get_default('flask', 'listen_port', 5000, int) from tranny.app import create_app wsgi_app = create_app() socketio_app = SocketIOServer((host, port), wsgi_app, resource='socket.io') socketio_app.serve_forever()
def __init__(self, host=None, port=None, user=None, password=None): if not host: host = config.get_default(self._config_key, "host", "localhost") self.host = host if not port: port = config.get_default(self._config_key, "port", DEFAULT_PORT, int) self.port = port if not user: user = config.get_default(self._config_key, "user", None) self.user = user if not password: password = config.get_default(self._config_key, "password", None) self.password = password self.connect()
def init_webui(self): """ Initialize and start the flask based webui. This does not check if it is enabled, so that must happen prior to calling this :return: :rtype: """ host = config.get_default('flask', 'listen_host', 'localhost') port = config.get_default('flask', 'listen_port', 5000, int) from tranny.app import create_app self.wsgi_app = create_app() self.wsgi_socketio = SocketIOServer((host, port), self.wsgi_app, resource='socket.io') self.wsgi_server = gevent.Greenlet(self.wsgi_socketio.serve_forever)
def init_client(client_type=None): """ Import & initialize the client set in the configuration file and return the usable instance. :param client_type: Manually specify a client to load :type client_type: unicode :return: Configured backend torrent instance :rtype: ClientProvider """ if not client_type: client_type = config.get_default("general", "client", "transmission").lower() if client_type == "rtorrent": from tranny.client.rtorrent import RTorrentClient as Client elif client_type == "transmission": from tranny.client.transmission import TransmissionClient as Client elif client_type == "utorrent": #from tranny.client.utorrent import UTorrentClient as TorrentClient raise NotImplementedError("Utorrent support is currently incomplete. Please use another client") elif client_type == "deluge": from tranny.client.deluge import DelugeClient as Client else: raise ConfigError("Invalid client type supplied: {0}".format(client_type)) config_values = config.get_section_values(Client.config_key) return Client(**config_values)
def init_client(client_type=None): """ Import & initialize the client set in the configuration file and return the usable instance. :param client_type: Manually specify a client to load :type client_type: unicode :return: Configured backend torrent instance :rtype: ClientProvider """ if not client_type: client_type = config.get_default("general", "client", "transmission").lower() if client_type == "rtorrent": from tranny.client.rtorrent import RTorrentClient as Client elif client_type == "transmission": from tranny.client.transmission import TransmissionClient as Client elif client_type == "utorrent": # from tranny.client.utorrent import UTorrentClient as TorrentClient raise NotImplementedError( "Utorrent support is currently incomplete. Please use another client" ) elif client_type == "deluge": from tranny.client.deluge import DelugeClient as Client elif client_type == "simplefile": from tranny.client.simplefile import SimpleFileClient as Client else: raise ConfigError( "Invalid client type supplied: {0}".format(client_type)) config_values = config.get_section_values(Client.config_key) client = Client(**config_values) from tranny.app import plugin_manager plugin_manager.register(client) return client
def __init__(self, host=None, port=None, user=None, password=None): super(TransmissionClient, self).__init__() if not host: host = config.get_default(self.config_key, "host", "localhost") self.host = host if not port: port = config.get_default(self.config_key, "port", DEFAULT_PORT, int) self.port = port if not user: user = config.get_default(self.config_key, "user", None) self.user = user if not password: password = config.get_default(self.config_key, "password", None) self.password = password self.client = None self.connect()
def _get_request(method, *args, **kwargs): params = kwargs.get('params', None) args = [i for i in args if i] key = config.get_default('service_trakt', 'api_key', None) if not key: return {} full_url = "".join([_make_url(method, key), '/' if args else "", '/'.join(map(unicode, args))]) return net.http_request(full_url, params=params, method='get')
def _get_request(method, *args, **kwargs): params = kwargs.get('params', None) args = [i for i in args if i] key = config.get_default('service_trakt', 'api_key', None) if not key: return {} full_url = "".join([ _make_url(method, key), '/' if args else "", '/'.join(map(str, args)) ]) return net.http_request(full_url, params=params, method='get')
def _post_request(method, data): key = config.get_default('service_trakt', 'api_key', None) if not key: return {} username = config.get("service_trakt", "username") password = config.get("service_trakt", "password") url = _make_url(method, key, json=False) data['username'] = username data['password'] = hashlib.sha1(password).hexdigest() results = net.http_request(url, data=data, method='post') return results
def _make_imdb(): """ Configure and return the imdb object ready for use :return: Imdb instance for querying :rtype: IMDbBase """ # TODO fix this sillyness access_method = config.get_default(config_section, 'sql', 'http') if access_method.lower() in ["1", "true"]: access_method = "sql" elif access_method.lower() in ["0", "false"]: access_method = "http" kwargs = {} if access_method == 'sql': kwargs = {"uri": config.get('db', 'uri'), "useORM": "sqlalchemy"} i = IMDb(access_method, **kwargs) if access_method == "http": if config.getboolean("proxy", "enabled"): i.set_proxy(config.get_default("proxy", "server", '')) return i
def is_replacement(self, release_info): """ :param release_info: """ fetch_proper = config.get_default("general", "fetch_proper", True, bool) # Skip releases unless they are considered propers or repacks if fetch_proper and not (release_info.is_repack or release_info.is_repack): self.log.debug("Skipped previously downloaded release ({0}): {1}".format( release_info.release_key, release_info.release_name)) return False return True
def main(): """ Main entry point for the application. Runs the command parsed from the CLI using the argparse func system """ # Exception raised on exit due to threading module loading before gevent # This preemptive patching prevents this # see: http://stackoverflow.com/questions/8774958/keyerror-in-module-threading-after-a-successful-py-test-run import sys if 'threading' in sys.modules: del sys.modules['threading'] import gevent import gevent.monkey gevent.monkey.patch_all() # Setup logger & config from tranny.app import config # Execute the user command arguments = parse_args() try: if arguments.loglevel: log_level = arguments.loglevel.upper() elif config.has_option("log", "level"): log_level = config.get_default("log", "level") else: log_level = "INFO" log_fmt = config.get_default("log", "format", "%(levelname)s %(asctime)s %(name)s: %(message)s") logging.basicConfig(level=logging.getLevelName(log_level), format=log_fmt) if arguments.config: config.initialize(arguments.config) arguments.func(arguments) except Exception: logging.exception("Fatal error, cannot start!") sys.exit(1) else: sys.exit(0)
def is_replacement(self, release_info): """ :param release_info: """ fetch_proper = config.get_default("general", "fetch_proper", True, bool) # Skip releases unless they are considered propers or repacks if fetch_proper and not (release_info.is_repack or release_info.is_repack): self.log.debug( "Skipped previously downloaded release ({0}): {1}".format( release_info.release_key, release_info.release_name)) return False return True
def _make_imdb(): """ Configure and return the imdb object ready for use :return: Imdb instance for querying :rtype: IMDbBase """ # TODO fix this sillyness access_method = config.get_default(config_section, 'sql', 'http') if access_method.lower() in ["1", "true"]: access_method = "sql" elif access_method.lower() in ["0", "false"]: access_method = "http" kwargs = {} if access_method == 'sql': kwargs = { "uri": config.get('db', 'uri'), "useORM": "sqlalchemy" } i = IMDb(access_method, **kwargs) if access_method == "http": if config.getboolean("proxy", "enabled"): i.set_proxy(config.get_default("proxy", "server", '')) return i
def __init__(self, config_section): """ Provides a basic interface to generate new torrents from external services. :param config_section: :type config_section: """ # Timestamp of last successful update self.enabled = False self.last_update = 0 self._config_section = config_section self.interval = config.get_default(config_section, "interval", 60, int) self.log = logging.getLogger(config_section) self.log.debug("Initialized {} Provider ({} State): {}".format( self.__class__.__name__, 'Enabled' if self.enabled else 'Disabled', self.name))
def __init__(self, config_section): """ Provides a basic interface to generate new torrents from external services. :param config_section: :type config_section: """ # Timestamp of last successful update self.enabled = False self.last_update = 0 self._config_section = config_section self.interval = config.get_default(config_section, "interval", 60, int) self.log = logging.getLogger(config_section) self.log.debug("Initialized {} Provider ({} State): {}".format( self.__class__.__name__, 'Enabled' if self.enabled else 'Disabled', self.name) )
def __init__(self, service_manager): """ :param service_manager: :type service_manager: tranny.manager.ServiceManager continue :return: :rtype: """ self._service_manager = service_manager self._observer = Observer() for section in config.find_sections("watch"): try: section_name = config.get_default(section, "section", False) watch_path = config.get(section, "path") if not exists(watch_path): log.warn( "Watch path does not exist {0}".format(watch_path)) except (NoOptionError, NoSectionError): log.warn( "Failed to get dl_path key for watch section {0}. Does not exist" .format(section)) continue dl_path = expanduser( config.get("section_{0}".format(section_name), "dl_path")) if not dl_path or not exists(dl_path) or not isdir(dl_path): log.warning( "Invalid download directory {0}. Disabling watch service for this directory" .format(dl_path)) watch_path = None if not config.has_section("section_{0}".format(section_name)): log.warning( "Invalid section name specified for watch dir: {0}".format( section_name)) if watch_path: self._observer.schedule(self, watch_path, recursive=True) self._path_sections[watch_path] = section_name if not self._path_sections: log.warning("No valid watch dirs found, disabling service") self._observer.start()
def main(): """ Main entry point for the application. Runs the command parsed from the CLI using the argparse func system """ # Exception raised on exit due to threading module loading before gevent # This preemptive patching prevents this # see: http://stackoverflow.com/questions/8774958/keyerror-in-module-threading-after-a-successful-py-test-run import sys if 'threading' in sys.modules: del sys.modules['threading'] import gevent import gevent.monkey gevent.monkey.patch_all() # Setup logger & config from tranny.app import config # Execute the user command arguments = parse_args() try: if arguments.loglevel: log_level = arguments.loglevel.upper() elif config.has_option("log", "level"): log_level = config.get_default("log", "level") else: log_level = "INFO" setup_logging(config, log_level) if arguments.config: config.initialize(arguments.config) arguments.func(arguments) except Exception: logging.exception("Fatal error, cannot start!") sys.exit(1) else: sys.exit(0)
def __init__(self, service_manager): """ :param service_manager: :type service_manager: tranny.manager.ServiceManager continue :return: :rtype: """ self._service_manager = service_manager self._observer = Observer() for section in config.find_sections("watch"): try: section_name = config.get_default(section, "section", False) watch_path = config.get(section, "path") if not exists(watch_path): logger.warn("Watch path does not exist {0}".format(watch_path)) except (NoOptionError, NoSectionError): logger.warn("Failed to get dl_path key for watch section {0}. Does not exist".format( section )) continue dl_path = expanduser(config.get("section_{0}".format(section_name), "dl_path")) if not dl_path or not exists(dl_path) or not isdir(dl_path): logger.warning( "Invalid download directory {0}. Disabling watch service for this directory".format(dl_path) ) watch_path = None if not config.has_section("section_{0}".format(section_name)): logger.warning("Invalid section name specified for watch dir: {0}".format(section_name)) if watch_path: self._observer.schedule(self, watch_path, recursive=True) self._path_sections[watch_path] = section_name if not self._path_sections: logger.warning("No valid watch dirs found, disabling service") self._observer.start()
# -*- coding: utf-8 -*- from __future__ import unicode_literals, with_statement import unittest from testcase import TrannyTestCase, tapedeck from tranny.app import config from tranny.provider.broadcastthenet import BroadcastTheNet btn_api = config.get_default("provider_broadcastthenet", "api_token", False) @unittest.skipUnless(btn_api, "No API Key set for BTN") class BTNAPITest(TrannyTestCase): def setUp(self): self.api = BroadcastTheNet() def test_user_info(self): response = self.api.user_info() self.assertTrue(response) def test_get_newest(self): response = self.api.get_torrents_browse(10) self.assertEqual(10, len(response['torrents'])) def test_get_torrent_url(self): with tapedeck.use_cassette(self.track("test_get_torrent_url_a")): torrent_ids = self.api.get_torrents_browse(1)['torrents'].keys() for torrent_id in torrent_ids: with tapedeck.use_cassette(self.track("test_get_torrent_url_{}".format(torrent_id))): url = self.api.get_torrent_url(torrent_id) self.assertTrue(torrent_id in url)
def gen_conf(): log_conf = { 'version': 1, 'disable_existing_loggers': True, 'formatters': { 'verbose': { 'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s' }, 'default': { 'format': config.get_default("log", "format", "%(levelname)s %(asctime)s %(name)s: %(message)s") }, }, 'handlers': { 'console': { 'level': log_level, 'class': 'logging.StreamHandler', 'formatter': 'default' }, 'email': { 'level': 'ERROR', 'class': 'logging.handlers.SMTPHandler', 'mailhost': config.get_default("mail", "server", "localhost"), 'fromaddr': config.get_default("mail", 'fromaddr', ""), 'toaddrs': config.get_default("mail", "toaddr", "").split(","), 'subject': "Tranny Application Error", 'credentials': [ config.get_default("mail", "username", ""), config.get_default("mail", "password") ] }, 'file': { 'class': 'logging.handlers.RotatingFileHandler', 'level': log_level, 'filename': join(config.config_path, 'polytorrent.log'), 'mode': 'a', 'maxBytes': 10485760, 'backupCount': 5 } }, 'loggers': { '': { 'level': log_level, 'handlers': ['console'] } } } def set_log_levels(loggers, level): for logger_name in loggers: log_conf['loggers'][logger_name] = {'level': level} set_log_levels(['GuessEpisodeInfoFromPosition', 'GuessProperties', 'GuessEpisodesRexps', 'GuessReleaseGroup', 'guessit.matcher', 'GuessEpisodeDetails', 'GuessEpisodeInfoFromPosition'], logging.ERROR) set_log_levels(['requests', 'imdbpy', 'guessit'], logging.WARNING) if config.get_default_boolean("log", "email_enabled", False): log_conf['loggers']['']['handlers'].append("email") if config.get_default_boolean("log", "file_enabled", True): log_conf['loggers']['']['handlers'].append("file") return log_conf
def strip_key(request): """ Remove API key before saving request to fixtures """ api_key = config.get_default('service_trakt', 'api_key', "") request.uri = request.uri.replace(api_key, "X" * 20) return request
# -*- coding: utf-8 -*- from __future__ import unicode_literals, with_statement import unittest from testcase import TrannyTestCase, tapedeck from tranny.app import config from tranny.provider.broadcastthenet import BroadcastTheNet btn_api = config.get_default("provider_broadcastthenet", "api_token", False) @unittest.skipUnless(btn_api, "No API Key set for BTN") class BTNAPITest(TrannyTestCase): def setUp(self): self.api = BroadcastTheNet() def test_user_info(self): response = self.api.user_info() self.assertTrue(response) def test_get_newest(self): response = self.api.get_torrents_browse(10) self.assertEqual(10, len(response['torrents'])) def test_get_torrent_url(self): with tapedeck.use_cassette(self.track("test_get_torrent_url_a")): torrent_ids = self.api.get_torrents_browse(1)['torrents'].keys() for torrent_id in torrent_ids: with tapedeck.use_cassette( self.track("test_get_torrent_url_{}".format(torrent_id))): url = self.api.get_torrent_url(torrent_id) self.assertTrue(torrent_id in url)