def test_register(self): plugin1 = object() plugin2 = object() plugin3 = object() upgrade = lambda *args, **kwargs: None with patch('monitorrent.plugin_managers.plugins', dict()), \ patch('monitorrent.upgrade_manager.upgrades', list()) as upgrades: register_plugin('type1', 'name1', plugin1) register_plugin('type1', 'name2', plugin2) register_plugin('type2', 'name3', plugin3, upgrade=upgrade) self.assertEqual(get_all_plugins(), {'name1': plugin1, 'name2': plugin2, 'name3': plugin3}) self.assertEqual(get_plugins('type1'), {'name1': plugin1, 'name2': plugin2}) self.assertEqual(get_plugins('type2'), {'name3': plugin3}) self.assertEqual(upgrades, [upgrade])
def test_register(self): plugin1 = object() plugin2 = object() plugin3 = object() upgrade = lambda *args, **kwargs: None with patch('monitorrent.plugin_managers.plugins', dict()), \ patch('monitorrent.upgrade_manager.upgrades', list()) as upgrades: register_plugin('type1', 'name1', plugin1) register_plugin('type1', 'name2', plugin2) register_plugin('type2', 'name3', plugin3, upgrade=upgrade) self.assertEqual(get_all_plugins(), { 'name1': plugin1, 'name2': plugin2, 'name3': plugin3 }) self.assertEqual(get_plugins('type1'), { 'name1': plugin1, 'name2': plugin2 }) self.assertEqual(get_plugins('type2'), {'name3': plugin3}) self.assertEqual(upgrades, [upgrade])
"name": torrent['name'], "date_added": datetime.utcfromtimestamp(torrent['time_added']).replace(tzinfo=pytz.utc) } def add_torrent(self, torrent): # TODO add path to download # path_to_download = None client = self._get_client() if not client: return False try: client.connect() return client.call("core.add_torrent_file", None, base64.encodebytes(torrent), None) except: return False def remove_torrent(self, torrent_hash): client = self._get_client() if not client: return False try: client.connect() return client.call("core.remove_torrent", torrent_hash.lower(), False) except: return False register_plugin('client', 'deluge', DelugeClientPlugin())
def add_torrent(self, torrent_content, torrent_settings): path = self.check_connection() if not path: return False try: try: torrent = Torrent(torrent_content) except Exception as e: return False filename = torrent.info_hash + ".torrent" with open(os.path.join(path, filename), "wb") as f: f.write(torrent.raw_content) return True except OSError: return False def remove_torrent(self, torrent_hash): path = self.check_connection() if not path: return False try: torrent = self.find_torrent(torrent_hash) if not torrent: return False os.remove(os.path.join(path, torrent["name"])) return True except OSError: return False register_plugin('client', DownloaderPlugin.name, DownloaderPlugin())
with DBSession() as db: cred = db.query(self.credentials_class).first() if not cred: return False username = cred.username password = cred.password if not username or not password or not cred.uid or not cred.bb_data: return False self.tracker.setup(cred.uid, cred.bb_data) return self.tracker.verify() def can_parse_url(self, url): return self.tracker.can_parse_url(url) def parse_url(self, url): return self.tracker.parse_url(url) # Tapochek has different ids for topic and download # TODO possible performance optimization - store id for download in database def _prepare_request(self, topic): headers = {'referer': topic.url, 'host': "tapochek.net"} cookies = self.tracker.get_cookies() request = requests.Request('GET', self.tracker.get_download_url(topic.url), headers=headers, cookies=cookies) return request.prepare() register_plugin('tracker', PLUGIN_NAME, TapochekNetPlugin())
try: torrent = client.get_torrent(torrent_hash.lower(), ['id', 'hashString', 'addedDate', 'name']) return { "name": torrent.name, "date_added": torrent.date_added.replace(tzinfo=reference.LocalTimezone()).astimezone(utc) } except KeyError: return False def add_torrent(self, torrent): client = self.check_connection() if not client: return False try: client.add_torrent(base64.encodestring(torrent)) return True except transmissionrpc.TransmissionError: return False def remove_torrent(self, torrent_hash): client = self.check_connection() if not client: return False try: client.remove_torrent(torrent_hash.lower(), delete_data=False) return True except transmissionrpc.TransmissionError: return False register_plugin('client', 'transmission', TransmissionClientPlugin())
if not parsed_url: return None # format list self.topic_form[0]['content'][1]['options'] = parsed_url['format_list'] settings = { 'display_name': parsed_url['original_name'], 'format': parsed_url['format_list'][0] } return settings def _set_topic_params(self, url, parsed_url, topic, params): """ :param url: str :type topic: AnidubTopic """ super(AnidubPlugin, self)._set_topic_params(url, parsed_url, topic, params) if parsed_url is not None: topic.format_list = ",".join(parsed_url['format_list']) def _prepare_request(self, topic): url = self.tracker.get_download_url(topic.url, topic.format) if url is None: return None headers = {'referer': topic.url} cookies = self.tracker.get_cookies() request = requests.Request('GET', url, cookies=cookies, headers=headers) return request.prepare() register_plugin('tracker', PLUGIN_NAME, AnidubPlugin())
def get_headers(self, access_token): return {'Access-Token': access_token} @property def settings_class(self): return PushbulletSettings def notify(self, header, body, url=None): settings = self.get_settings() if not settings or not settings.access_token: raise PushbulletException(1, "Access Token was not specified") type = u'link' if url else u'note' parameters = { u'type': type, u'title': header, u'body': body, u'url': url } request = requests.post('https://api.pushbullet.com/v2/pushes', data=parameters, headers=self.get_headers( settings.access_token)) if request.status_code != 200: raise PushbulletException( 2, 'Failed to send Pushbullet notification') return True register_plugin('notifier', 'pushbullet', PushbulletNotifierPlugin())
@staticmethod def _get_title(title): return {'original_name': title} class UnionpeerOrgPlugin(ExecuteWithHashChangeMixin, TrackerPluginBase): tracker = UnionpeerOrgTracker() topic_class = UnionpeerOrgTopic topic_form = [{ 'type': 'row', 'content': [{ 'type': 'text', 'model': 'display_name', 'label': 'Name', 'flex': 100 }] }] def can_parse_url(self, url): return self.tracker.can_parse_url(url) def parse_url(self, url): return self.tracker.parse_url(url) def _prepare_request(self, topic): return self.tracker.get_download_url(topic.url) register_plugin('tracker', PLUGIN_NAME, UnionpeerOrgPlugin(), upgrade=upgrade)
def prepare_add_topic(self, url): parsed_url = self.tracker.parse_url(url) if not parsed_url: return None self._set_format_list(parsed_url['format_list']) settings = { 'display_name': parsed_url['original_name'], 'format': parsed_url['format_list'][0] } return settings def _set_format_list(self, format_list): self.topic_form[0]['content'][1]['options'] = format_list def _prepare_request(self, topic): url = self.tracker.get_download_url(topic.url, topic.format) if url is None: return None headers = {'referer': topic.url} request = requests.Request('GET', url, headers=headers) return request.prepare() def _set_topic_params(self, url, parsed_url, topic, params): super(AnilibriaTvPlugin, self)._set_topic_params(self, parsed_url, topic, params) if parsed_url is not None and parsed_url['format_list'] is not None: topic.format_list = ",".join(parsed_url['format_list']) register_plugin('tracker', PLUGIN_NAME, AnilibriaTvPlugin(), upgrade=upgrade)
except Exception as e: # TODO: Log unexpected excepton return LoginResult.Unknown def verify(self): with DBSession() as db: cred = db.query(self.credentials_class).first() if not cred: return False username = cred.username password = cred.password if not username or not password or not cred.uid or not cred.bbe_data: return False self.tracker.setup(cred.uid, cred.bbe_data) return self.tracker.verify() def can_parse_url(self, url): return self.tracker.can_parse_url(url) def parse_url(self, url): return self.tracker.parse_url(url) def _prepare_request(self, topic): headers = {'referer': topic.url, 'host': "dl.free-torrents.org"} cookies = self.tracker.get_cookies() request = requests.Request('GET', self.tracker.get_download_url(topic.url), headers=headers, cookies=cookies) return request.prepare() register_plugin('tracker', PLUGIN_NAME, FreeTorrentsOrgPlugin())
def get_headers(self, access_token): return { 'Access-Token': access_token } @property def settings_class(self): return PushbulletSettings def notify(self, header, body, url=None): settings = self.get_settings() if not settings or not settings.access_token: raise PushbulletException(1, "Access Token was not specified") type = u'link' if url else u'note' parameters = { u'type': type, u'title': header, u'body': body, u'url': url } request = requests.post('https://api.pushbullet.com/v2/pushes', data=parameters, headers=self.get_headers(settings.access_token)) if request.status_code != 200: raise PushbulletException(2, 'Failed to send Pushbullet notification') return True register_plugin('notifier', 'pushbullet', PushbulletNotifierPlugin())
# TODO: Log unexpected excepton return LoginResult.Unknown def verify(self): with DBSession() as db: cred = db.query(self.credentials_class).first() if not cred: return False username = cred.username password = cred.password if not username or not password or not cred.user_id or not cred.sid: return False self.tracker.setup(cred.user_id, cred.sid) return self.tracker.verify() def can_parse_url(self, url): return self.tracker.can_parse_url(url) def parse_url(self, url): return self.tracker.parse_url(url) def _prepare_request(self, topic): cookies = self.tracker.get_cookies() request = requests.Request('GET', self.tracker.get_download_url(topic.url), cookies=cookies) return request.prepare() register_plugin('tracker', PLUGIN_NAME, NnmClubPlugin())
'model': 'access_token', 'flex': 50 }] }] @property def settings_class(self): return TelegramSettings def notify(self, header, body, url=None): settings = self.get_settings() if not settings or not settings.access_token or not settings.chat_id: raise TelegramException(1, "Access Token or User Id was not specified") api_url = self._telegram_api_format.format(settings.access_token, 'sendMessage') text = header + '\n\n' + body if url: text = text + '\n' + url parameters = { u'chat_id': settings.chat_id, u'text': text, } request = requests.post(api_url, data=parameters) if request.status_code != 200: raise TelegramException(2, 'Failed to send Telegram notification') return True register_plugin('notifier', 'telegram', TelegramNotifierPlugin())
'flex': 50 }] }] @property def settings_class(self): return PushAllSettings def notify(self, header, body, url=None): settings = self.get_settings() if not settings or not settings.access_token or not settings.user_id: raise PushAllException(1, "Access Token or User Id was not specified") parameters = { u'type': 'self', u'title': header, u'text': body, u'url': url, u'id': settings.user_id, u'key': settings.access_token } request = requests.post('https://pushall.ru/api.php', data=parameters) result = json.loads(request.text) if 'error' in result: raise PushAllException(2, 'Failed to send PushAll notification') return True register_plugin('notifier', 'pushall', PushAllNotifierPlugin())
return {'original_name': title} class RutorOrgPlugin(ExecuteWithHashChangeMixin, TrackerPluginBase): tracker = RutorOrgTracker() topic_class = RutorOrgTopic topic_form = [{ 'type': 'row', 'content': [{ 'type': 'text', 'model': 'display_name', 'label': 'Name', 'flex': 100 }] }] def can_parse_url(self, url): return self.tracker.can_parse_url(url) def parse_url(self, url): return self.tracker.parse_url(url) def _prepare_request(self, topic): return self.tracker.get_download_url(topic.url) def check_download(self, response): return self.tracker.check_download(response) register_plugin('tracker', PLUGIN_NAME, RutorOrgPlugin(), upgrade=upgrade)
return LoginResult.Unknown except Exception as e: # TODO: Log unexpected excepton return LoginResult.Unknown def verify(self): with DBSession() as db: cred = db.query(self.credentials_class).first() if not cred: return False username = cred.username password = cred.password if not username or not password or not cred.user_id or not cred.sid: return False self.tracker.setup(cred.user_id, cred.sid) return self.tracker.verify() def can_parse_url(self, url): return self.tracker.can_parse_url(url) def parse_url(self, url): return self.tracker.parse_url(url) def _prepare_request(self, topic): cookies = self.tracker.get_cookies() request = requests.Request('GET', self.tracker.get_download_url(topic.url), cookies=cookies) return request.prepare() register_plugin('tracker', PLUGIN_NAME, NnmClubPlugin())
return False try: files = {"torrents": BytesIO(torrent)} data = None if torrent_settings is not None: data = {} if torrent_settings.download_dir is not None: data['savepath'] = torrent_settings.download_dir r = parameters['session'].post(parameters['target'] + "command/upload", data=data, files=files) return r.status_code == 200 except: return False # TODO switch to remove torrent with data def remove_torrent(self, torrent_hash): parameters = self._get_params() if not parameters: return False try: #qbittorrent uses case sensitive lower case hash torrent_hash = torrent_hash.lower() payload = {"hashes": torrent_hash} r = parameters['session'].post(parameters['target'] + "command/delete", data=payload) return r.status_code == 200 except: return False register_plugin('client', 'qbittorrent', QBittorrentClientPlugin())
except: return False def add_torrent(self, torrent, torrent_settings): parameters = self._get_params() if not parameters: return False try: payload = {"action": "add-file", "token": parameters["token"]} files = {"torrent_file": BytesIO(torrent)} r = parameters['session'].post(parameters['target'], params=payload, files=files) return r.status_code == 200 except: return False # TODO switch to remove torrent with data def remove_torrent(self, torrent_hash): parameters = self._get_params() if not parameters: return False try: payload = {"action": "remove", "hash": torrent_hash, "token": parameters["token"]} parameters['session'].get(parameters['target'], params=payload) return True except: return False register_plugin('client', 'utorrent', UTorrentClientPlugin())
def verify(self): with DBSession() as db: cred = db.query(self.credentials_class).first() if not cred: return False username = cred.username password = cred.password if not username or not password or not cred.uid or not cred.bb_data: return False self.tracker.setup(cred.uid, cred.bb_data) return self.tracker.verify() def can_parse_url(self, url): return self.tracker.can_parse_url(url) def parse_url(self, url): return self.tracker.parse_url(url) def _prepare_request(self, topic): headers = {'referer': topic.url, 'host': "rutracker.org"} cookies = self.tracker.get_cookies() request = requests.Request('POST', self.tracker.get_download_url(topic.url), headers=headers, cookies=cookies) return request.prepare() register_plugin('tracker', PLUGIN_NAME, RutrackerPlugin())
text = text + '\n' + url text = self._remove_tags(text) chat_ids = [c.strip() for c in settings.chat_ids.split(',')] errors_chat_ids = None for chat_id in chat_ids: parameters = { u'chat_id': chat_id, u'text': text, } request = requests.post(api_url, data=parameters) if request.status_code != 200: if errors_chat_ids is None: errors_chat_ids = [] errors_chat_ids.append(chat_id) if errors_chat_ids is not None and len(errors_chat_ids) > 0: raise TelegramException( 2, 'Failed to send Telegram notification to {0}'.format( errors_chat_ids)) return True def _remove_tags(self, text): return self._remove_tags_regex.sub(u"", text) register_plugin('notifier', 'telegram', TelegramNotifierPlugin(), upgrade)
def settings_class(self): return PushoverSettings @property def get_type(self): return NotifierType.short_text def notify(self, header, body, url=None): settings = self.get_settings() if not settings or not settings.access_token or not settings.user_id: raise PushoverException( 1, "Access Token or User Id was not specified") parameters = { u'token': settings.access_token, u'title': header, u'message': body, u'url': url, u'user': settings.user_id, u'key': settings.access_token } request = requests.post('https://api.pushover.net/1/messages.json', data=parameters) if request.status_code != 200: raise PushoverException(2, 'Failed to send Pushover notification') return True register_plugin('notifier', 'pushover', PushoverNotifierPlugin())
def get_type(self): return NotifierType.short_text @property def settings_class(self): return PushAllSettings def notify(self, header, body, url=None): settings = self.get_settings() if not settings or not settings.access_token or not settings.user_id: raise PushAllException( 1, "Access Token or User Id was not specified") parameters = { u'type': 'self', u'title': header, u'text': body, u'url': url, u'id': settings.user_id, u'key': settings.access_token } request = requests.post('https://pushall.ru/api.php', data=parameters) result = json.loads(request.text) if 'error' in result: raise PushAllException(2, 'Failed to send PushAll notification') return True register_plugin('notifier', 'pushall', PushAllNotifierPlugin())
class AnilibriaTvPlugin(ExecuteWithHashChangeMixin, TrackerPluginBase): tracker = AnilibriaTvTracker() topic_class = AnilibriaTvTopic topic_form = [{ 'type': 'row', 'content': [{ 'type': 'text', 'model': 'display_name', 'label': 'Name', 'flex': 100 }] }] def can_parse_url(self, url): return self.tracker.can_parse_url(url) def parse_url(self, url): return self.tracker.parse_url(url) def _prepare_request(self, topic): url = self.tracker.get_download_url(topic.url) if url is None: return None headers = {'referer': topic.url} request = requests.Request('GET', url, headers=headers) return request.prepare() register_plugin('tracker', PLUGIN_NAME, AnilibriaTvPlugin())
parameters = self._get_params() if not parameters: return False payload = {"action": "add-file", "token": parameters["token"]} files = {"torrent_file": BytesIO(torrent)} if torrent_settings is not None: if torrent_settings.download_dir is not None: payload['path'] = torrent_settings.download_dir r = parameters['session'].post(parameters['target'], params=payload, files=files) return r.status_code == 200 # TODO switch to remove torrent with data def remove_torrent(self, torrent_hash): parameters = self._get_params() if not parameters: return False payload = { "action": "remove", "hash": torrent_hash, "token": parameters["token"] } parameters['session'].get(parameters['target'], params=payload) return True register_plugin('client', 'utorrent', UTorrentClientPlugin())
def add_torrent(self, torrent, torrent_settings): """ :type torrent: str :type torrent_settings: clients.TopicSettings | None """ client = self.check_connection() if not client: return False try: torrent_settings_dict = {} if torrent_settings is not None: if torrent_settings.download_dir is not None: torrent_settings_dict['download_dir'] = torrent_settings.download_dir client.add_torrent(base64.b64encode(torrent).decode('utf-8'), **torrent_settings_dict) return True except transmissionrpc.TransmissionError: return False def remove_torrent(self, torrent_hash): client = self.check_connection() if not client: return False try: client.remove_torrent(torrent_hash.lower(), delete_data=False) return True except transmissionrpc.TransmissionError: return False register_plugin('client', 'transmission', TransmissionClientPlugin())
resut.append({'season_info': info, 'download_info': download_info}) return resut def check_download(self, response): if response.status_code == 200: return Status.Ok if response.status_code == 302 and response.headers.get('location', '') == '/': return Status.NotFound return Status.Error def _get_display_name(self, parsed_url): if 'name' in parsed_url: return u"{0} / {1}".format(parsed_url['name'], parsed_url['original_name']) return parsed_url['original_name'] def _set_topic_params(self, url, parsed_url, topic, params): """ :param url: str :type topic: LostFilmTVSeries """ super(LostFilmPlugin, self)._set_topic_params(url, parsed_url, topic, params) if parsed_url is not None: topic.search_name = parsed_url['original_name'] register_plugin('tracker', PLUGIN_NAME, LostFilmPlugin(), upgrade=upgrade)
return server def notify(self, header, body, url=None): settings = self.get_settings() if not settings: raise EmailException(1, 'Settings not specified') if not settings.host: raise EmailException(2, 'SMTP host not specified') if not settings.to_addr: raise EmailException(3, 'Email to address not specified') server = self._create_server(settings) self._server_authenticate(server, settings) try: msg = MIMEMultipart() msg['From'] = settings.login msg['To'] = settings.to_addr msg['Subject'] = header msg.attach(MIMEText(body)) if url: msg.attach(MIMEText('\n' + url)) server.sendmail(settings.login, settings.to_addr, msg.as_string()) return True except smtplib.SMTPResponseException as e: raise EmailException(5, 'SMTP: failed to deliver the message') finally: server.quit() register_plugin('notifier', 'email', EmailNotifierPlugin())
return server def notify(self, header, body, url=None): settings = self.get_settings() if not settings: raise EmailException(1, "Settings not specified") if not settings.host: raise EmailException(2, "SMTP host not specified") if not settings.to_addr: raise EmailException(3, "Email to address not specified") server = self._create_server(settings) self._server_authenticate(server, settings) try: msg = MIMEMultipart() msg["From"] = settings.login msg["To"] = settings.to_addr msg["Subject"] = header msg.attach(MIMEText(body)) if url: msg.attach(MIMEText("\n" + url)) server.sendmail(settings.login, settings.to_addr, msg.as_string()) return True except smtplib.SMTPResponseException as e: raise EmailException(5, "SMTP: failed to deliver the message") finally: server.quit() register_plugin("notifier", "email", EmailNotifierPlugin())
except Exception as e: # TODO: Log unexpected excepton return LoginResult.Unknown def verify(self): with DBSession() as db: cred = db.query(self.credentials_class).first() if not cred: return False username = cred.username password = cred.password if not username or not password or not cred.uid or not cred.bb_data: return False self.tracker.setup(cred.uid, cred.bb_data) return self.tracker.verify() def can_parse_url(self, url): return self.tracker.can_parse_url(url) def parse_url(self, url): return self.tracker.parse_url(url) def _prepare_request(self, topic): headers = {'referer': topic.url, 'host': "dl.rutracker.org"} cookies = self.tracker.get_cookies() request = requests.Request('POST', self.tracker.get_download_url(topic.url), headers=headers, cookies=cookies) return request.prepare() register_plugin('tracker', PLUGIN_NAME, RutrackerPlugin())
# TODO: Log unexpected excepton return LoginResult.Unknown def verify(self): with DBSession() as db: cred = db.query(self.credentials_class).first() if not cred: return False username = cred.username password = cred.password if not username or not password or not cred.uid or not cred.bb_data: return False self.tracker.setup(cred.uid, cred.bb_data) return self.tracker.verify() def can_parse_url(self, url): return self.tracker.can_parse_url(url) def parse_url(self, url): return self.tracker.parse_url(url) # Tapochek has different ids for topic and download # TODO possible performance optimization - store id for download in database def _prepare_request(self, topic): headers = {'referer': topic.url, 'host': "tapochek.net"} cookies = self.tracker.get_cookies() request = requests.Request('GET', self.tracker.get_download_url(topic.url), headers=headers, cookies=cookies) return request.prepare() register_plugin('tracker', PLUGIN_NAME, TapochekNetPlugin())
def add_torrent(self, torrent_content): path = self.check_connection() if not path: return False try: try: torrent = Torrent(torrent_content) except Exception as e: return False filename = torrent.info_hash + ".torrent" with open(os.path.join(path, filename), "wb") as f: f.write(torrent.raw_content) return True except OSError: return False def remove_torrent(self, torrent_hash): path = self.check_connection() if not path: return False try: torrent = self.find_torrent(torrent_hash) if not torrent: return False os.remove(os.path.join(path, torrent["name"])) return True except OSError: return False register_plugin('client', DownloaderPlugin.name, DownloaderPlugin())
def can_parse_url(self, url): return self.tracker.can_parse_url(url) def parse_url(self, url): return self.tracker.parse_url(url) def check_changes(self, topic): last_torrent_update = self.tracker.get_last_torrent_update(topic.url) topic_last_torrent_update = topic.last_torrent_update min_date = pytz.utc.localize(datetime.datetime.min) if (not last_torrent_update and not topic_last_torrent_update ) or (topic_last_torrent_update or min_date) < (last_torrent_update or min_date): topic.last_torrent_update = last_torrent_update return True return False def _prepare_request(self, topic): headers = {'referer': topic.url} cookies = self.tracker.get_cookies() request = requests.Request('GET', self.tracker.get_download_url(topic.url), headers=headers, cookies=cookies) return request.prepare() register_plugin('tracker', PLUGIN_NAME, KinozalPlugin(), upgrade)
def add_torrent(self, torrent, torrent_settings): """ :type torrent_settings: clients.TopicSettings | None """ client = self._get_client() if not client: return False savepath = None if torrent_settings is not None and torrent_settings.download_dir is not None: savepath = torrent_settings.download_dir with tempfile.NamedTemporaryFile() as tmp: tmp.write(torrent) tmp.flush() r = client.torrents_add(save_path=savepath, torrent_files=[tmp.name]) return r def remove_torrent(self, torrent_hash): client = self._get_client() if not client: return False client.torrents_delete(hashes=[torrent_hash.lower()]) return True register_plugin('client', 'qbittorrent', QBittorrentClientPlugin())