mirror of
https://github.com/SickGear/SickGear.git
synced 2024-11-14 17:05:05 +00:00
Merge branch 'main' into dev
This commit is contained in:
commit
eef5ddb171
15 changed files with 76 additions and 33 deletions
13
CHANGES.md
13
CHANGES.md
|
@ -5,6 +5,19 @@
|
||||||
* Update urllib3 2.2.1 (54d6edf) to 2.2.2 (27e2a5c)
|
* Update urllib3 2.2.1 (54d6edf) to 2.2.2 (27e2a5c)
|
||||||
|
|
||||||
|
|
||||||
|
### 3.32.8 (2024-10-07 00:30:00 UTC)
|
||||||
|
|
||||||
|
* Change min required Python version to 3.9
|
||||||
|
* Change add support for Python 3.9.20, 3.10.15, 3.11.10, 3.12.7
|
||||||
|
* Change update fallback zoneinfo to 2024b
|
||||||
|
* Change improve config.ini save failure messages
|
||||||
|
* Change add '-f' to copy_file command for 'posix' systems
|
||||||
|
* Fix Fanart.tv and CF data fetch
|
||||||
|
* Fix TVC images
|
||||||
|
* Change add '.avif' extensions as valid image type (used by tvc cards)
|
||||||
|
* Change hide lazy load animation when loading fails (unsupported image format)
|
||||||
|
|
||||||
|
|
||||||
### 3.32.7 (2024-08-13 11:30:00 UTC)
|
### 3.32.7 (2024-08-13 11:30:00 UTC)
|
||||||
|
|
||||||
* Change to prevent saving config.ini before it's fully loaded
|
* Change to prevent saving config.ini before it's fully loaded
|
||||||
|
|
|
@ -1485,6 +1485,8 @@ home_browseShows.tmpl
|
||||||
border-top-left-radius:5px;
|
border-top-left-radius:5px;
|
||||||
border-top-right-radius:5px;
|
border-top-right-radius:5px;
|
||||||
border-bottom:1px solid #111;
|
border-bottom:1px solid #111;
|
||||||
|
background-position:50% 50%;
|
||||||
|
text-decoration: none !important;
|
||||||
background-image:url("../images/poster-dark.jpg")
|
background-image:url("../images/poster-dark.jpg")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,17 @@
|
||||||
function initLazyload(){
|
function hide_lazy_ani (element){
|
||||||
$.ll = new LazyLoad({elements_selector:'img[data-original]', callback_load:function(element){
|
if (element.id) {
|
||||||
if (element.id) {
|
var el = document.getElementById('loading-' + element.id), className = 'hide';
|
||||||
var el = document.getElementById('loading-' + element.id), className = 'hide';
|
if (!!document.body.classList) {
|
||||||
if (!!document.body.classList) {
|
el.classList.add(className);
|
||||||
el.classList.add(className);
|
} else {
|
||||||
} else {
|
el.className += (el.className ? ' ' : '') + className;
|
||||||
el.className += (el.className ? ' ' : '') + className;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}});
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function initLazyload(){
|
||||||
|
$.ll = new LazyLoad({elements_selector:'img[data-original]', callback_load: hide_lazy_ani,
|
||||||
|
callback_error: hide_lazy_ani});
|
||||||
$.ll.handleScroll();
|
$.ll.handleScroll();
|
||||||
return !0;
|
return !0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,8 +56,8 @@ class CloudflareScraper(Session):
|
||||||
and resp.status_code in (503, 429, 403)):
|
and resp.status_code in (503, 429, 403)):
|
||||||
self.start_time = time.time()
|
self.start_time = time.time()
|
||||||
if (re.search('(?i)cloudflare', resp.headers.get('Server', ''))
|
if (re.search('(?i)cloudflare', resp.headers.get('Server', ''))
|
||||||
and b'jschl_vc' in resp.content
|
and b'_cf_chl_' in resp.content
|
||||||
and b'jschl_answer' in resp.content):
|
or (b'jschl_vc' in resp.content and b'jschl_answer' in resp.content)):
|
||||||
resp = self.solve_cf_challenge(resp, url_solver, **kwargs)
|
resp = self.solve_cf_challenge(resp, url_solver, **kwargs)
|
||||||
elif b'ddgu' in resp.content:
|
elif b'ddgu' in resp.content:
|
||||||
resp = self.solve_ddg_challenge(resp, **kwargs)
|
resp = self.solve_ddg_challenge(resp, **kwargs)
|
||||||
|
|
Binary file not shown.
|
@ -7,11 +7,12 @@ from sg_helpers import get_url
|
||||||
|
|
||||||
|
|
||||||
class Request(object):
|
class Request(object):
|
||||||
def __init__(self, apikey, tvdb_id, ws=fanart.WS.TV, types=None):
|
def __init__(self, apikey, tvdb_id, ws=fanart.WS.TV, types=None, **kwargs):
|
||||||
self._apikey = apikey
|
self._apikey = apikey
|
||||||
self._tvdb_id = tvdb_id
|
self._tvdb_id = tvdb_id
|
||||||
self._ws = ws
|
self._ws = ws
|
||||||
self._types = types
|
self._types = types
|
||||||
|
self._kwargs = kwargs
|
||||||
self._response = None
|
self._response = None
|
||||||
self._web_url = 'https://fanart.tv/series/%s'
|
self._web_url = 'https://fanart.tv/series/%s'
|
||||||
self._assets_url = 'https://assets.fanart.tv'
|
self._assets_url = 'https://assets.fanart.tv'
|
||||||
|
@ -22,7 +23,7 @@ class Request(object):
|
||||||
def response(self):
|
def response(self):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
rjson = get_url(str(self), parse_json=True)
|
rjson = get_url(str(self), parse_json=True, **self._kwargs)
|
||||||
image_type = self._types or u'showbackground'
|
image_type = self._types or u'showbackground'
|
||||||
rhtml = self.scrape_web(image_type)
|
rhtml = self.scrape_web(image_type)
|
||||||
if not isinstance(rjson, dict) and 0 == len(rhtml[image_type]):
|
if not isinstance(rjson, dict) and 0 == len(rhtml[image_type]):
|
||||||
|
@ -31,7 +32,7 @@ class Request(object):
|
||||||
if not isinstance(rjson, dict):
|
if not isinstance(rjson, dict):
|
||||||
rjson = {image_type: []}
|
rjson = {image_type: []}
|
||||||
|
|
||||||
if 0 != len(rhtml[image_type]):
|
if None is not rhtml and 0 != len(rhtml[image_type]):
|
||||||
rjson_ids = map(lambda i: i['id'], rjson[image_type])
|
rjson_ids = map(lambda i: i['id'], rjson[image_type])
|
||||||
for item in filter(lambda i: i['id'] not in rjson_ids, rhtml[image_type]):
|
for item in filter(lambda i: i['id'] not in rjson_ids, rhtml[image_type]):
|
||||||
rjson[image_type] += [item]
|
rjson[image_type] += [item]
|
||||||
|
@ -48,7 +49,7 @@ class Request(object):
|
||||||
|
|
||||||
def scrape_web(self, image_type):
|
def scrape_web(self, image_type):
|
||||||
try:
|
try:
|
||||||
data = get_url(self._web_url % self._tvdb_id)
|
data = get_url(self._web_url % self._tvdb_id, **self._kwargs)
|
||||||
if not data:
|
if not data:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
|
@ -1148,7 +1148,7 @@ def scantree(path, # type: AnyStr
|
||||||
|
|
||||||
def copy_file(src_file, dest_file):
|
def copy_file(src_file, dest_file):
|
||||||
if os.name.startswith('posix'):
|
if os.name.startswith('posix'):
|
||||||
subprocess.call(['cp', src_file, dest_file])
|
subprocess.call(['cp', '-f', src_file, dest_file])
|
||||||
else:
|
else:
|
||||||
shutil.copyfile(src_file, dest_file)
|
shutil.copyfile(src_file, dest_file)
|
||||||
|
|
||||||
|
|
|
@ -36,9 +36,8 @@ warnings.filterwarnings('ignore', module=r'.*ssl_.*', message='.*SSLContext obje
|
||||||
warnings.filterwarnings('ignore', module=r'.*zoneinfo.*', message='.*file or directory.*')
|
warnings.filterwarnings('ignore', module=r'.*zoneinfo.*', message='.*file or directory.*')
|
||||||
warnings.filterwarnings('ignore', message='.*deprecated in cryptography.*')
|
warnings.filterwarnings('ignore', message='.*deprecated in cryptography.*')
|
||||||
|
|
||||||
versions = [((3, 8, 2), (3, 8, 19)),
|
versions = [((3, 9, 0), (3, 9, 2)), ((3, 9, 4), (3, 9, 20)),
|
||||||
((3, 9, 0), (3, 9, 2)), ((3, 9, 4), (3, 9, 19)),
|
((3, 10, 0), (3, 12, 7))] # inclusive version ranges
|
||||||
((3, 10, 0), (3, 12, 5))] # inclusive version ranges
|
|
||||||
if not any(list(map(lambda v: v[0] <= sys.version_info[:3] <= v[1], versions))) and not int(os.environ.get('PYT', 0)):
|
if not any(list(map(lambda v: v[0] <= sys.version_info[:3] <= v[1], versions))) and not int(os.environ.get('PYT', 0)):
|
||||||
major, minor, micro = sys.version_info[:3]
|
major, minor, micro = sys.version_info[:3]
|
||||||
print('Python %s.%s.%s detected.' % (major, minor, micro))
|
print('Python %s.%s.%s detected.' % (major, minor, micro))
|
||||||
|
|
|
@ -2475,22 +2475,36 @@ def _save_config(force=False, **kwargs):
|
||||||
backup_config = re.sub(r'\.ini$', '.bak', CONFIG_FILE)
|
backup_config = re.sub(r'\.ini$', '.bak', CONFIG_FILE)
|
||||||
from .config import check_valid_config
|
from .config import check_valid_config
|
||||||
try:
|
try:
|
||||||
|
if check_valid_config(CONFIG_FILE):
|
||||||
|
for _t in range(0, 3):
|
||||||
copy_file(CONFIG_FILE, backup_config)
|
copy_file(CONFIG_FILE, backup_config)
|
||||||
if not check_valid_config(backup_config):
|
if not check_valid_config(backup_config):
|
||||||
logger.error('config file seams to be invalid, not backing up.')
|
if 2 > _t:
|
||||||
|
logger.debug('backup config file seems to be invalid, retrying...')
|
||||||
|
else:
|
||||||
|
logger.warning('backup config file seems to be invalid, not backing up.')
|
||||||
|
backup_config = None
|
||||||
remove_file_perm(backup_config)
|
remove_file_perm(backup_config)
|
||||||
|
2 > _t and time.sleep(3)
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
logger.warning('existing config file is invalid, not backing it up')
|
||||||
backup_config = None
|
backup_config = None
|
||||||
except (BaseException, Exception):
|
except (BaseException, Exception):
|
||||||
backup_config = None
|
backup_config = None
|
||||||
|
|
||||||
for _ in range(0, 3):
|
for _t in range(0, 3):
|
||||||
new_config.write()
|
new_config.write()
|
||||||
if check_valid_config(CONFIG_FILE):
|
if check_valid_config(CONFIG_FILE):
|
||||||
CONFIG_OLD = copy.deepcopy(new_config)
|
CONFIG_OLD = copy.deepcopy(new_config)
|
||||||
return
|
return
|
||||||
logger.warning('saving config file failed, retrying...')
|
if 2 > _t:
|
||||||
|
logger.debug('saving config file failed, retrying...')
|
||||||
|
else:
|
||||||
|
logger.warning('saving config file failed.')
|
||||||
remove_file_perm(CONFIG_FILE)
|
remove_file_perm(CONFIG_FILE)
|
||||||
time.sleep(3)
|
2 > _t and time.sleep(3)
|
||||||
|
|
||||||
# we only get here if the config saving failed multiple times
|
# we only get here if the config saving failed multiple times
|
||||||
if None is not backup_config and os.path.isfile(backup_config):
|
if None is not backup_config and os.path.isfile(backup_config):
|
||||||
|
|
|
@ -484,7 +484,7 @@ def backup_config():
|
||||||
logger.log('backing up config.ini')
|
logger.log('backing up config.ini')
|
||||||
try:
|
try:
|
||||||
if not check_valid_config(sickgear.CONFIG_FILE):
|
if not check_valid_config(sickgear.CONFIG_FILE):
|
||||||
logger.error('config file seams to be invalid, not backing up.')
|
logger.error('config file seems to be invalid, not backing up.')
|
||||||
return
|
return
|
||||||
now = datetime.datetime.now()
|
now = datetime.datetime.now()
|
||||||
d = datetime.datetime.strftime(now, '%Y-%m-%d')
|
d = datetime.datetime.strftime(now, '%Y-%m-%d')
|
||||||
|
@ -493,7 +493,7 @@ def backup_config():
|
||||||
target = os.path.join(target_base, 'config.ini')
|
target = os.path.join(target_base, 'config.ini')
|
||||||
copy_file(sickgear.CONFIG_FILE, target)
|
copy_file(sickgear.CONFIG_FILE, target)
|
||||||
if not check_valid_config(target):
|
if not check_valid_config(target):
|
||||||
logger.error('config file seams to be invalid, not backing up.')
|
logger.error('config file seems to be invalid, not backing up.')
|
||||||
remove_file_perm(target)
|
remove_file_perm(target)
|
||||||
return
|
return
|
||||||
compress_file(target, 'config.ini')
|
compress_file(target, 'config.ini')
|
||||||
|
|
|
@ -171,7 +171,7 @@ def has_image_ext(filename):
|
||||||
:rtype: bool
|
:rtype: bool
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
if os.path.splitext(filename)[1].lower() in ['.bmp', '.gif', '.jpeg', '.jpg', '.png', '.webp']:
|
if os.path.splitext(filename)[1].lower() in ['.avif', '.bmp', '.gif', '.jpeg', '.jpg', '.png', '.webp']:
|
||||||
return True
|
return True
|
||||||
except (BaseException, Exception):
|
except (BaseException, Exception):
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -1198,7 +1198,8 @@ class GenericMetadata(object):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if tvdb_id:
|
if tvdb_id:
|
||||||
request = fanartRequest(apikey=sickgear.FANART_API_KEY, tvdb_id=tvdb_id, types=types[image_type])
|
request = fanartRequest(apikey=sickgear.FANART_API_KEY, tvdb_id=tvdb_id, types=types[image_type],
|
||||||
|
url_solver=sickgear.FLARESOLVERR_HOST)
|
||||||
resp = request.response()
|
resp = request.response()
|
||||||
itemlist = []
|
itemlist = []
|
||||||
dedupe = []
|
dedupe = []
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
3.8.2
|
3.9.0
|
|
@ -5936,9 +5936,19 @@ class AddShows(Home):
|
||||||
url_path = info['href'].strip()
|
url_path = info['href'].strip()
|
||||||
|
|
||||||
title = info.find('h2').get_text(strip=True)
|
title = info.find('h2').get_text(strip=True)
|
||||||
img_uri = info.get('data-original', '').strip()
|
img_uri = None
|
||||||
if not img_uri:
|
# try image locations e.g. https://pogd.es/assets/bg/KAOS.jpg
|
||||||
img_uri = re.findall(r'(?i).*?image:\s*url\(([^)]+)', info.attrs['style'])[0].strip()
|
img_name = re.sub(r'[:\s]+', '-', title)
|
||||||
|
for cur_type in ('jpg', 'jpeg', 'webp', 'png', 'gif', 'bmp', 'avif'):
|
||||||
|
uri = f'https://pogd.es/assets/bg/{img_name}.{cur_type}'
|
||||||
|
if helpers.check_url(uri):
|
||||||
|
img_uri = uri
|
||||||
|
break
|
||||||
|
if None is img_uri:
|
||||||
|
# use alternative avif image fallback as only supported by new browsers
|
||||||
|
img_uri = info.get('data-original', '').strip()
|
||||||
|
if not img_uri: # old image fallback (pre 2024-08-18)
|
||||||
|
img_uri = re.findall(r'(?i).*?image:\s*url\(([^)]+)', info.attrs['style'])[0].strip()
|
||||||
images = dict(poster=dict(thumb='imagecache?path=browse/thumb/tvc&source=%s' % img_uri))
|
images = dict(poster=dict(thumb='imagecache?path=browse/thumb/tvc&source=%s' % img_uri))
|
||||||
sickgear.CACHE_IMAGE_URL_LIST.add_url(img_uri)
|
sickgear.CACHE_IMAGE_URL_LIST.add_url(img_uri)
|
||||||
title = re.sub(r'(?i)(?::\s*season\s*\d+|\s*\((?:19|20)\d{2}\))?$', '', title.strip())
|
title = re.sub(r'(?i)(?::\s*season\s*\d+|\s*\((?:19|20)\d{2}\))?$', '', title.strip())
|
||||||
|
|
|
@ -206,7 +206,7 @@ def setup_test_db():
|
||||||
|
|
||||||
def teardown_test_db():
|
def teardown_test_db():
|
||||||
"""Deletes the test db
|
"""Deletes the test db
|
||||||
although this seams not to work on my system it leaves me with an zero kb file
|
although this seems not to work on my system it leaves me with an zero kb file
|
||||||
"""
|
"""
|
||||||
# uncomment next line so leave the db intact between test and at the end
|
# uncomment next line so leave the db intact between test and at the end
|
||||||
# return False
|
# return False
|
||||||
|
|
Loading…
Reference in a new issue