2023-01-12 01:04:47 +00:00
|
|
|
# coding=utf-8
|
|
|
|
import warnings
|
|
|
|
warnings.filterwarnings('ignore', module=r'.*fuz.*', message='.*Sequence.*')
|
|
|
|
warnings.filterwarnings('ignore', module=r'.*dateutil.*', message='.*Unicode.*')
|
|
|
|
warnings.filterwarnings('ignore', module=r'.*', message=r'.*Python 2\.6.*')
|
|
|
|
|
|
|
|
import datetime
|
|
|
|
import os.path
|
|
|
|
import random
|
|
|
|
import sys
|
|
|
|
import test_lib as test
|
|
|
|
import unittest
|
|
|
|
|
|
|
|
sys.path.insert(1, os.path.abspath('..'))
|
|
|
|
sys.path.insert(1, os.path.abspath('../lib'))
|
|
|
|
|
|
|
|
from lxml_etree import etree
|
|
|
|
from lib.dateutil import parser
|
|
|
|
from sickgear.indexers.indexer_config import *
|
|
|
|
from sickgear.network_timezones import SG_TIMEZONE
|
|
|
|
from sickgear.providers import newznab
|
|
|
|
from six import iteritems, iterkeys
|
|
|
|
|
|
|
|
import sickgear
|
|
|
|
|
|
|
|
sickgear.SYS_ENCODING = 'UTF-8'
|
|
|
|
|
|
|
|
DEBUG = VERBOSE = False
|
|
|
|
|
|
|
|
item_parse_test_cases = [
|
|
|
|
(('Show.Name.S02E01.720p.HDTV.x264-GROUP', 'https://test.h/test/hhhh'),
|
|
|
|
('Show.Name.S02E01.720p.HDTV.x264-GROUP', 'https://test.h/test/hhhh')),
|
|
|
|
(('Show.Name.S02E02.720p.HDTV.x264-GROUP-JUNK', 'https://test.h/test/hhhh'),
|
|
|
|
('Show.Name.S02E02.720p.HDTV.x264-GROUP', 'https://test.h/test/hhhh')),
|
|
|
|
(('Show.Name.S02E03.720p.HDTV.x264-GROUP[JUNK]', 'https://test.h'),
|
|
|
|
('Show.Name.S02E03.720p.HDTV.x264-GROUP', 'https://test.h')),
|
|
|
|
(('Show.Name.S02E04.720p.HDTV.x264-GROUP-JUNK-JUNK', 'https://test.h'),
|
|
|
|
('Show.Name.S02E04.720p.HDTV.x264-GROUP', 'https://test.h')),
|
|
|
|
(('Show.Name.S02E05.720p.HDTV.x264-GROUP-JUNK[JUNK]', 'https://test.h'),
|
|
|
|
('Show.Name.S02E05.720p.HDTV.x264-GROUP', 'https://test.h')),
|
2023-03-08 13:44:20 +00:00
|
|
|
(('Show.Name.S02E06.720p.HDTV.x264-GROUP-JUNK[JUNK帝]', 'https://test.h'),
|
|
|
|
('Show.Name.S02E06.720p.HDTV.x264-GROUP', 'https://test.h')),
|
|
|
|
(('Show.Name.S02E07-EpName帝.720p.HDTV.x264-GROUP帝-JUNK[JUNK帝]', 'https://test.h'),
|
|
|
|
('Show.Name.S02E07-EpName帝.720p.HDTV.x264-GROUP帝', 'https://test.h')),
|
|
|
|
(('[grp 帝] Show Name - 11 [1024x576 h264 AAC ger-sub][123456].mp4', 'https://test.h'),
|
|
|
|
('[grp.帝].Show.Name.-.11.[1024x576.h264.AAC.ger-sub][123456]', 'https://test.h')),
|
2023-01-12 01:04:47 +00:00
|
|
|
]
|
|
|
|
|
|
|
|
size_test_cases = [
|
|
|
|
((1000, 'ad87987dadf7987987'), (1000, 'ad87987dadf7987987')),
|
|
|
|
((1254105454, 'ffdds7766dgdzhghdzghdgg'), (1254105454, 'ffdds7766dgdzhghdzghdgg')),
|
|
|
|
((-1, ''), (-1, None))
|
|
|
|
]
|
|
|
|
|
|
|
|
pubdate_test_cases = [
|
|
|
|
'Sat, 28 Jul 2018 07:33:06 +0000',
|
|
|
|
'Sun, 10 Sep 2017 23:11:09 +0200'
|
|
|
|
]
|
|
|
|
|
|
|
|
caps_test_cases = [
|
|
|
|
{
|
|
|
|
'name': 'newznab',
|
|
|
|
'data_files': {'caps': 'newznab_caps.xml'},
|
|
|
|
'caps': {
|
|
|
|
TVINFO_TVDB: 'tvdbid', TVINFO_TVRAGE: 'rid', TVINFO_TVMAZE: 'tvmazeid',
|
|
|
|
newznab.NewznabConstants.SEARCH_EPISODE: 'ep', newznab.NewznabConstants.SEARCH_SEASON: 'season',
|
|
|
|
newznab.NewznabConstants.SEARCH_TEXT: 'q'
|
|
|
|
},
|
|
|
|
'cats': {
|
|
|
|
newznab.NewznabConstants.CAT_SD: ['5030'], newznab.NewznabConstants.CAT_SPORT: ['5060'],
|
|
|
|
newznab.NewznabConstants.CAT_ANIME: ['5070'], newznab.NewznabConstants.CAT_UHD: ['5045'],
|
|
|
|
newznab.NewznabConstants.CAT_HD: ['5040']
|
|
|
|
},
|
|
|
|
'all_cats': [
|
|
|
|
{'id': '5070', 'name': 'Anime'}, {'id': '5185', 'name': 'Docu HD'},
|
|
|
|
{'id': '5180', 'name': 'Docu SD'}, {'id': '5020', 'name': 'Foreign'},
|
|
|
|
{'id': '5040', 'name': 'HD'}, {'id': '5200', 'name': 'HEVC'},
|
|
|
|
{'id': '5050', 'name': 'Other'}, {'id': '5030', 'name': 'SD'},
|
|
|
|
{'id': '5060', 'name': 'Sport'}, {'id': '5045', 'name': 'UHD'}
|
|
|
|
],
|
|
|
|
'limits': 100,
|
|
|
|
'server_type': newznab.NewznabConstants.SERVER_DEFAULT
|
|
|
|
}, {
|
|
|
|
'name': 'nzedb',
|
|
|
|
'data_files': {'caps': 'nzedb_caps.xml'},
|
|
|
|
'caps': {
|
|
|
|
TVINFO_TVDB: 'tvdbid', TVINFO_TVRAGE: 'rid', TVINFO_TVMAZE: 'tvmazeid', TVINFO_TRAKT: 'traktid',
|
|
|
|
TVINFO_IMDB: 'imdbid', TVINFO_TMDB: 'tmdbid',
|
|
|
|
newznab.NewznabConstants.SEARCH_EPISODE: 'ep', newznab.NewznabConstants.SEARCH_SEASON: 'season',
|
|
|
|
newznab.NewznabConstants.SEARCH_TEXT: 'q'
|
|
|
|
},
|
|
|
|
'cats': {
|
|
|
|
newznab.NewznabConstants.CAT_SD: ['5030'], newznab.NewznabConstants.CAT_SPORT: ['5060'],
|
|
|
|
newznab.NewznabConstants.CAT_ANIME: ['5070'], newznab.NewznabConstants.CAT_UHD: ['5045'],
|
|
|
|
newznab.NewznabConstants.CAT_HD: ['5040'], newznab.NewznabConstants.CAT_WEBDL: ['5010']
|
|
|
|
},
|
|
|
|
'all_cats': [
|
|
|
|
{'id': '5070', 'name': 'Anime'}, {'id': '5080', 'name': 'Documentary'},
|
|
|
|
{'id': '5020', 'name': 'Foreign'}, {'id': '5040', 'name': 'HD'},
|
|
|
|
{'id': '5999', 'name': 'Other'}, {'id': '5030', 'name': 'SD'},
|
|
|
|
{'id': '5060', 'name': 'Sport'}, {'id': '5045', 'name': 'UHD'},
|
|
|
|
{'id': '5010', 'name': 'WEB-DL'}
|
|
|
|
],
|
|
|
|
'limits': 100,
|
|
|
|
'server_type': newznab.NewznabConstants.SERVER_DEFAULT
|
|
|
|
}, {
|
|
|
|
'name': 'nntmux',
|
|
|
|
'data_files': {'caps': 'nntmux_caps.xml'},
|
|
|
|
'caps': {
|
|
|
|
TVINFO_TVDB: 'tvdbid', TVINFO_TVRAGE: 'rid', TVINFO_TVMAZE: 'tvmazeid', TVINFO_TRAKT: 'traktid',
|
|
|
|
TVINFO_IMDB: 'imdbid', TVINFO_TMDB: 'tmdbid',
|
|
|
|
newznab.NewznabConstants.SEARCH_EPISODE: 'ep', newznab.NewznabConstants.SEARCH_SEASON: 'season',
|
|
|
|
newznab.NewznabConstants.SEARCH_TEXT: 'q'
|
|
|
|
},
|
|
|
|
'cats': {
|
|
|
|
newznab.NewznabConstants.CAT_SD: ['5030'], newznab.NewznabConstants.CAT_SPORT: ['5060'],
|
|
|
|
newznab.NewznabConstants.CAT_ANIME: ['5070'], newznab.NewznabConstants.CAT_UHD: ['5045'],
|
|
|
|
newznab.NewznabConstants.CAT_HD: ['5040'], newznab.NewznabConstants.CAT_WEBDL: ['5010']
|
|
|
|
},
|
|
|
|
'all_cats': [
|
|
|
|
{'id': '5070', 'name': 'Anime'}, {'id': '5080', 'name': 'Documentary'},
|
|
|
|
{'id': '5020', 'name': 'Foreign'}, {'id': '5040', 'name': 'HD'}, {'id': '5999', 'name': 'Other'},
|
|
|
|
{'id': '5030', 'name': 'SD'}, {'id': '5060', 'name': 'Sport'}, {'id': '5045', 'name': 'UHD'},
|
|
|
|
{'id': '5010', 'name': 'WEB-DL'}, {'id': '5090', 'name': 'X265'}
|
|
|
|
],
|
|
|
|
'limits': 100,
|
|
|
|
'server_type': newznab.NewznabConstants.SERVER_DEFAULT
|
|
|
|
}, {
|
|
|
|
'name': 'spotweb',
|
|
|
|
'data_files': {'caps': 'spotweb_caps.xml'},
|
|
|
|
'caps': {
|
|
|
|
TVINFO_TVRAGE: 'rid', TVINFO_TVMAZE: 'tvmazeid',
|
|
|
|
newznab.NewznabConstants.SEARCH_EPISODE: 'ep', newznab.NewznabConstants.SEARCH_SEASON: 'season',
|
|
|
|
newznab.NewznabConstants.SEARCH_TEXT: 'q'
|
|
|
|
},
|
|
|
|
'cats': {
|
|
|
|
newznab.NewznabConstants.CAT_SD: ['5030'], newznab.NewznabConstants.CAT_SPORT: ['5060'],
|
|
|
|
newznab.NewznabConstants.CAT_ANIME: ['5070'], newznab.NewznabConstants.CAT_HD: ['5040']
|
|
|
|
},
|
|
|
|
'all_cats': [
|
|
|
|
{'id': '5020', 'name': 'Foreign'}, {'id': '5030', 'name': 'SD'}, {'id': '5040', 'name': 'HD'},
|
|
|
|
{'id': '5050', 'name': 'Other'}, {'id': '5060', 'name': 'Sport'}, {'id': '5070', 'name': 'Anime'}
|
|
|
|
],
|
|
|
|
'limits': 500,
|
|
|
|
'server_type': newznab.NewznabConstants.SERVER_SPOTWEB
|
|
|
|
}, {
|
|
|
|
'name': 'NZBHydra',
|
|
|
|
'data_files': {'caps': 'hydra1_caps.xml'},
|
|
|
|
'caps': {
|
|
|
|
TVINFO_TVDB: 'tvdbid', TVINFO_TVRAGE: 'rid',
|
|
|
|
newznab.NewznabConstants.SEARCH_EPISODE: 'ep', newznab.NewznabConstants.SEARCH_SEASON: 'season',
|
|
|
|
newznab.NewznabConstants.SEARCH_TEXT: 'q'
|
|
|
|
},
|
|
|
|
'cats': {
|
|
|
|
newznab.NewznabConstants.CAT_SD: ['5030'], newznab.NewznabConstants.CAT_SPORT: ['5060'],
|
|
|
|
newznab.NewznabConstants.CAT_ANIME: ['5070'], newznab.NewznabConstants.CAT_HD: ['5040']
|
|
|
|
},
|
|
|
|
'all_cats': [
|
|
|
|
{'id': '5020', 'name': 'Foreign'}, {'id': '5030', 'name': 'SD'}, {'id': '5040', 'name': 'HD'},
|
|
|
|
{'id': '5050', 'name': 'Other'}, {'id': '5060', 'name': 'Sport'}, {'id': '5070', 'name': 'Anime'},
|
|
|
|
{'id': '5080', 'name': 'Documentary'}
|
|
|
|
],
|
|
|
|
'limits': 100,
|
|
|
|
'server_type': newznab.NewznabConstants.SERVER_HYDRA1
|
|
|
|
}, {
|
|
|
|
'name': 'NZBHydra 2',
|
|
|
|
'data_files': {'caps': 'hydra2_caps.xml'},
|
|
|
|
'caps': {
|
|
|
|
TVINFO_TVDB: 'tvdbid', TVINFO_TVRAGE: 'rid', TVINFO_TVMAZE: 'tvmazeid', TVINFO_TRAKT: 'traktid',
|
|
|
|
newznab.NewznabConstants.SEARCH_EPISODE: 'ep', newznab.NewznabConstants.SEARCH_SEASON: 'season',
|
|
|
|
newznab.NewznabConstants.SEARCH_TEXT: 'q'
|
|
|
|
},
|
|
|
|
'cats': {
|
|
|
|
newznab.NewznabConstants.CAT_SD: ['5030'], newznab.NewznabConstants.CAT_SPORT: ['5060'],
|
|
|
|
newznab.NewznabConstants.CAT_ANIME: ['5070'], newznab.NewznabConstants.CAT_HD: ['5040']
|
|
|
|
},
|
|
|
|
'all_cats': [
|
|
|
|
{'id': '5070', 'name': 'Anime'}, {'id': '5040', 'name': 'TV HD'}, {'id': '5030', 'name': 'TV SD'}
|
|
|
|
],
|
|
|
|
'limits': 100,
|
|
|
|
'server_type': newznab.NewznabConstants.SERVER_HYDRA2
|
|
|
|
},
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
class FakeNewznabProvider(newznab.NewznabProvider):
|
|
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
self.FILEDIR = os.path.join(test.TESTDIR, 'newznab_data')
|
|
|
|
self._data_files_dict = ({}, kwargs['data_files_dict'])[isinstance(kwargs.get('data_files_dict'), dict)]
|
|
|
|
if 'data_files_dict' in kwargs:
|
|
|
|
del kwargs['data_files_dict']
|
|
|
|
super(FakeNewznabProvider, self).__init__(*args, **kwargs)
|
|
|
|
|
|
|
|
def _read_data(self, filename):
|
|
|
|
try:
|
|
|
|
f = os.path.join(self.FILEDIR, filename)
|
|
|
|
if os.path.isfile(f):
|
|
|
|
with open(f, 'rb') as d:
|
|
|
|
return d.read()
|
|
|
|
except (BaseException, Exception):
|
|
|
|
return
|
|
|
|
|
|
|
|
# simulate Data from provider
|
|
|
|
def get_url(self, url, skip_auth=False, use_tmr_limit=True, *args, **kwargs):
|
|
|
|
data = None
|
|
|
|
if '/api?' in url:
|
|
|
|
api_parameter = url[url.find('/api?') + 5:]
|
|
|
|
if 't=caps' in api_parameter and 'caps' in self._data_files_dict:
|
|
|
|
data = self._read_data(self._data_files_dict['caps'])
|
|
|
|
return data
|
|
|
|
|
|
|
|
|
|
|
|
class BasicTests(test.SickbeardTestDBCase):
|
|
|
|
|
|
|
|
ns = {'newznab': 'http://www.newznab.com/DTD/2010/feeds/attributes/', 'atom': 'http://www.w3.org/2005/Atom'}
|
|
|
|
ns_parsed = dict((k, '{%s}' % v) for (k, v) in ns.items())
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def _create_item(title, link, size=-1, uuid='', ids=None, pubdate=None):
|
|
|
|
item = etree.Element('item', nsmap=BasicTests.ns)
|
|
|
|
title_item = etree.Element('title')
|
|
|
|
title_item.text = title
|
|
|
|
link_item = etree.Element('link')
|
|
|
|
link_item.text = link
|
|
|
|
item.append(title_item)
|
|
|
|
item.append(link_item)
|
|
|
|
if -1 != size:
|
|
|
|
size_item = etree.Element('{%s}attr' % BasicTests.ns['newznab'], nsmap=BasicTests.ns)
|
|
|
|
size_item.set('name', 'size')
|
|
|
|
size_item.set('value', '%s' % size)
|
|
|
|
item.append(size_item)
|
|
|
|
if uuid:
|
|
|
|
uuid_item = etree.Element('{%s}attr' % BasicTests.ns['newznab'], nsmap=BasicTests.ns)
|
|
|
|
uuid_item.set('name', 'guid')
|
|
|
|
uuid_item.set('value', '%s' % uuid)
|
|
|
|
item.append(uuid_item)
|
|
|
|
if ids:
|
|
|
|
for a, b in iteritems(ids):
|
|
|
|
ids_item = etree.Element('{%s}attr' % BasicTests.ns['newznab'], nsmap=BasicTests.ns)
|
|
|
|
ids_item.set('name', a)
|
|
|
|
ids_item.set('value', '%s' % b)
|
|
|
|
item.append(ids_item)
|
|
|
|
if pubdate:
|
|
|
|
pubdate_item = etree.Element('pubDate')
|
|
|
|
pubdate_item.text = pubdate
|
|
|
|
item.append(pubdate_item)
|
|
|
|
return item
|
|
|
|
|
|
|
|
def test_title_and_url(self):
|
|
|
|
|
|
|
|
if VERBOSE:
|
|
|
|
print('Running tests')
|
|
|
|
|
|
|
|
newznab_provider = newznab.NewznabProvider('test', '')
|
|
|
|
|
|
|
|
for cur_test, cur_expected in item_parse_test_cases:
|
|
|
|
item = self._create_item(cur_test[0], cur_test[1])
|
|
|
|
result = newznab_provider._title_and_url(item)
|
|
|
|
self.assertEqual(cur_expected, result)
|
|
|
|
|
|
|
|
def test_get_size_uid(self):
|
|
|
|
|
|
|
|
newznab_provider = newznab.NewznabProvider('test', '')
|
|
|
|
|
|
|
|
for cur_test, cur_expected in size_test_cases:
|
|
|
|
item = self._create_item('Show.Name.S01E01.x264-Group', 'http://test.h', cur_test[0], cur_test[1])
|
|
|
|
result = newznab_provider.get_size_uid(item, name_space=BasicTests.ns_parsed)
|
|
|
|
self.assertEqual(cur_expected, result)
|
|
|
|
|
|
|
|
def test_parse_ids(self):
|
|
|
|
ids_test_cases = []
|
|
|
|
for k in iterkeys(newznab.NewznabConstants.providerToIndexerMapping):
|
|
|
|
rand_id = random.randrange(1, 99999999)
|
|
|
|
ids_test_cases.append(({k: rand_id}, {newznab.NewznabConstants.providerToIndexerMapping[k]: rand_id}))
|
|
|
|
|
|
|
|
all_case = {}
|
|
|
|
all_case_ex = {}
|
|
|
|
for k in iterkeys(newznab.NewznabConstants.providerToIndexerMapping):
|
|
|
|
rand_id = random.randrange(1, 99999999)
|
|
|
|
all_case.update({k: rand_id})
|
|
|
|
all_case_ex.update({newznab.NewznabConstants.providerToIndexerMapping[k]: rand_id})
|
|
|
|
|
|
|
|
ids_test_cases.append((all_case, all_case_ex))
|
|
|
|
|
|
|
|
newznab_provider = newznab.NewznabProvider('test', '')
|
|
|
|
|
|
|
|
for cur_test, cur_expected in ids_test_cases:
|
|
|
|
item = self._create_item('Show.Name.S01E01.x264-Group', 'https://test.h', ids=cur_test)
|
|
|
|
result = newznab_provider.cache.parse_ids(item, BasicTests.ns_parsed)
|
|
|
|
self.assertEqual(cur_expected, result)
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def _parse_pub_date(date_str):
|
|
|
|
parsed_date = None
|
|
|
|
try:
|
|
|
|
if date_str:
|
|
|
|
p = parser.parse(date_str, fuzzy=True)
|
|
|
|
try:
|
|
|
|
p = p.astimezone(SG_TIMEZONE)
|
|
|
|
except (BaseException, Exception):
|
|
|
|
pass
|
|
|
|
if isinstance(p, datetime.datetime):
|
|
|
|
parsed_date = p.replace(tzinfo=None)
|
|
|
|
except (BaseException, Exception):
|
|
|
|
pass
|
|
|
|
|
|
|
|
return parsed_date
|
|
|
|
|
|
|
|
def test_parse_pub_date(self):
|
|
|
|
newznab_provider = newznab.NewznabProvider('test', '')
|
|
|
|
|
|
|
|
for cur_test in pubdate_test_cases:
|
|
|
|
item = self._create_item('Show.Name.S01E01.x264-Group', 'https://test.h', pubdate=cur_test)
|
|
|
|
result = newznab_provider._parse_pub_date(item)
|
|
|
|
cur_expected = self._parse_pub_date(cur_test)
|
|
|
|
self.assertEqual(cur_expected, result)
|
|
|
|
|
|
|
|
|
|
|
|
class FakeProviderTests(test.SickbeardTestDBCase):
|
|
|
|
|
|
|
|
def test_caps(self):
|
|
|
|
self.longMessage = True
|
|
|
|
for cur_test in caps_test_cases:
|
|
|
|
newznab_provider = FakeNewznabProvider('test', 'https://fake.fake/', data_files_dict=cur_test['data_files'])
|
|
|
|
newznab_provider.enabled = True
|
|
|
|
# TODO: This test is now failing, this next line returns data that does not match the test data
|
|
|
|
newznab_provider.get_caps()
|
|
|
|
msg = 'Test case: %s' % cur_test['name']
|
|
|
|
self.assertEqual(cur_test['server_type'], newznab_provider.server_type, msg=msg)
|
|
|
|
self.assertEqual(cur_test['limits'], newznab_provider.limits, msg=msg)
|
|
|
|
self.assertEqual(cur_test['caps'], newznab_provider.caps, msg=msg)
|
|
|
|
self.assertEqual(cur_test['cats'], newznab_provider.cats, msg=msg)
|
|
|
|
self.assertEqual(cur_test['all_cats'], newznab_provider.all_cats, msg=msg)
|
|
|
|
|
|
|
|
|
|
|
|
if '__main__' == __name__:
|
|
|
|
if 1 < len(sys.argv):
|
|
|
|
suite = unittest.TestLoader().loadTestsFromName('newznab_tests.BasicTests.test_' + sys.argv[1])
|
|
|
|
else:
|
|
|
|
suite = unittest.TestLoader().loadTestsFromTestCase(BasicTests)
|
|
|
|
unittest.TextTestRunner(verbosity=2).run(suite)
|
|
|
|
|
|
|
|
suite = unittest.TestLoader().loadTestsFromTestCase(FakeProviderTests)
|
|
|
|
unittest.TextTestRunner(verbosity=2).run(FakeNewznabProvider)
|