Change allow Python 3.12.5

Fix person ids fetching
Fix wrong added death dates (by allowing overwriting deathday with None if birthday is on source)
Fix parsing changes to IMDb bio
Update test data
- Change improve efficiency when saving config.ini
Change prevent saving unchanged config.ini
Change add flushing to config.ini file saving (configobj hack)
Change add ConfigEvents queue for saving the config ini more efficiently
Change catch other errors for saving config
- Change improve efficiency when saving viewshow glide
Change don't call '/home/set-display-show-glide' in the first place if there  is no reason (params) to do so
Change add sanity check for set_display_show_glide, only save changed values
This commit is contained in:
Prinz23 2024-06-28 02:57:31 +01:00 committed by JackDandy
parent 80cffd7cef
commit 0c0e25e73c
34 changed files with 126 additions and 16 deletions

View file

@ -1,6 +1,11 @@
### 3.32.4 (2024-06-2x xx:xx:00 UTC)
### 3.32.4 (2024-08-10 11:40:00 UTC)
* Change person cards to not display "eps" when number of eps is unknown
* Fix wrong added death dates
* Fix parsing changes to IMDb bio
* Change improve efficiency when saving config.ini
* Change improve efficiency when saving viewshow glide
* Change allow Python 3.12.5
### 3.32.3 (2024-06-26 18:10:00 UTC)

View file

@ -4,6 +4,7 @@ Libs with customisations...
/lib/backports/configparser
/lib/browser_ua
/lib/bs4
/lib/configobj/__init__.py
/lib/dateutil/zoneinfo/__init__.py
/lib/dateutil/tz/tz.py
/lib/enzyme

View file

@ -245,7 +245,9 @@ $(document).ready(function() {
if (saveTime){
params.slidetime = $.SickGear.config.glideSlideTime;
}
$.get($.SickGear.Root + '/home/set-display-show-glide', params);
if (!$.isEmptyObject(params)){
$.get($.SickGear.Root + '/home/set-display-show-glide', params);
}
}
}

View file

@ -219,7 +219,7 @@ class IMDbIndexer(TVInfoBase):
if not bio:
return
with BS4Parser(bio) as bio_item:
bv = bio_item.find(string='Mini Bio', recursive=True).find_next('p')
bv = bio_item.find('div', attrs={'data-testid': re.compile('mini_bio$')}, recursive=True)
for a in bv.findAll('a'):
a.replaceWithChildren()
for b in bv.findAll('br'):

View file

@ -2097,6 +2097,7 @@ class ConfigObj(Section):
else:
with open(self.filename, 'wb') as h:
h.write(output_bytes)
h.flush()
def validate(self, validator, preserve_errors=False, copy=False,
section=None):

View file

@ -38,7 +38,7 @@ warnings.filterwarnings('ignore', message='.*deprecated in cryptography.*')
versions = [((3, 8, 2), (3, 8, 19)),
((3, 9, 0), (3, 9, 2)), ((3, 9, 4), (3, 9, 19)),
((3, 10, 0), (3, 12, 4))] # 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)):
major, minor, micro = sys.version_info[:3]
print('Python %s.%s.%s detected.' % (major, minor, micro))

View file

@ -16,6 +16,7 @@
from collections import OrderedDict
from threading import Lock
import copy
import datetime
import io
import os
@ -39,6 +40,7 @@ from . import auto_media_process, properFinder # must come after the above impo
from .common import SD, SKIPPED, USER_AGENT
from .config import check_section, check_setting_int, check_setting_str, ConfigMigrator, minimax
from .databases import cache_db, failed_db, mainDB
from .event_queue import ConfigEvents
from .indexers.indexer_api import TVInfoAPI
from .indexers.indexer_config import TVINFO_IMDB, TVINFO_TVDB, TmdbIndexer
from .providers.generic import GenericProvider
@ -73,6 +75,7 @@ ENV = {}
CFG = None # type: ConfigObj
CONFIG_FILE = ''
CONFIG_VERSION = None
CONFIG_OLD = None
# Default encryption version (0 for None)
ENCRYPTION_VERSION = 0
@ -86,6 +89,7 @@ DATA_DIR = ''
# system events
# noinspection PyTypeChecker
events = None # type: Events
config_events = None # type: ConfigEvents
show_queue_scheduler = None # type: Optional[scheduler.Scheduler]
search_queue_scheduler = None # type: Optional[scheduler.Scheduler]
@ -667,7 +671,7 @@ def init_stage_1(console_logging):
WEB_HOST, WEB_ROOT, ACTUAL_CACHE_DIR, CACHE_DIR, ZONEINFO_DIR, ADD_SHOWS_WO_DIR, ADD_SHOWS_METALANG, \
CREATE_MISSING_SHOW_DIRS, SHOW_DIRS_WITH_DOTS, \
RECENTSEARCH_STARTUP, NAMING_FORCE_FOLDERS, SOCKET_TIMEOUT, DEBUG, TVINFO_DEFAULT, \
CONFIG_FILE, CONFIG_VERSION, \
CONFIG_FILE, CONFIG_VERSION, CONFIG_OLD, \
REMOVE_FILENAME_CHARS, IMPORT_DEFAULT_CHECKED_SHOWS, WANTEDLIST_CACHE, MODULE_UPDATE_STRING, EXT_UPDATES
# Add Show Search
global RESULTS_SORTBY
@ -1537,7 +1541,7 @@ def init_stage_2():
search_recent_scheduler, search_subtitles_scheduler, \
search_queue_scheduler, show_queue_scheduler, people_queue_scheduler, \
watched_state_queue_scheduler, emby_watched_state_scheduler, plex_watched_state_scheduler, \
process_media_scheduler, background_mapping_task
process_media_scheduler, background_mapping_task, config_events
# Gen Config/Misc
global SHOW_UPDATE_HOUR, UPDATE_INTERVAL, UPDATE_PACKAGES_INTERVAL
@ -1728,6 +1732,9 @@ def init_stage_2():
except (BaseException, Exception):
pass
config_events = ConfigEvents(_save_config)
config_events.start()
__INITIALIZED__ = True
return True
@ -1801,7 +1808,7 @@ def sig_handler(signum=None, _=None):
def halt():
global __INITIALIZED__, started
global __INITIALIZED__, started, config_events
logger.debug('Check INIT_LOCK on halt')
with INIT_LOCK:
@ -1811,6 +1818,11 @@ def halt():
logger.log('Exiting threads')
try:
config_events.stopit()
except (BaseException, Exception):
pass
for p in provider_ping_thread_pool:
provider_ping_thread_pool[p].stop = True
@ -1854,6 +1866,11 @@ def halt():
except (BaseException, Exception) as e:
logger.log('Thread %s exception %s' % (thread.name, e))
try:
config_events.join(10)
except RuntimeError:
pass
__INITIALIZED__ = False
started = False
@ -1869,10 +1886,23 @@ def save_all():
# save config
logger.log('Saving config file to disk')
save_config()
_save_config(force=True)
def save_config():
def save_config(force=False):
# type: (bool) -> None
"""
add queue request for saving the config.ini
:param force: force save config even if unchanged
"""
global config_events
config_events.put(force)
def _save_config(force=False, **kwargs):
# type: (bool, ...) -> None
global CONFIG_OLD
new_config = ConfigObj()
new_config.filename = CONFIG_FILE
@ -2425,6 +2455,9 @@ def save_config():
new_config['ANIME'] = {}
new_config['ANIME']['anime_treat_as_hdtv'] = int(ANIME_TREAT_AS_HDTV)
if not force and CONFIG_OLD == new_config and os.path.isfile(new_config.filename):
logger.debug('config.ini not dirty, not saving.')
return
from sg_helpers import copy_file
backup_config = re.sub(r'\.ini$', '.bak', CONFIG_FILE)
from .config import check_valid_config
@ -2440,6 +2473,7 @@ def save_config():
for _ in range(0, 3):
new_config.write()
if check_valid_config(CONFIG_FILE):
CONFIG_OLD = copy.deepcopy(new_config)
return
logger.warning('saving config file failed, retrying...')
remove_file_perm(CONFIG_FILE)

View file

@ -2,6 +2,67 @@ import queue
import threading
class SetQueue(queue.Queue):
def _init(self, maxsize):
self.queue = set()
def _put(self, item):
self.queue.add(item)
def _get(self):
return self.queue.pop()
class ConfigEvents(threading.Thread):
def __init__(self, callback):
super(ConfigEvents, self).__init__()
self.queue = SetQueue()
self.callback = callback
self.name = 'CONFIG-EVENTS'
self._stopper = threading.Event()
def put(self, etype):
# type: (bool) -> None
"""
put config save event into queue
:param etype: force save config.ini if unchanged
"""
self.queue.put(etype)
def stopit(self):
self._stopper.set()
def run(self):
while not self._stopper.is_set():
try:
# get event type
ev_type = self.queue.get(True, 5)
except queue.Empty:
continue
except(BaseException, Exception):
continue
if ev_type in (True, False, None):
if ev_type is None:
continue
from sickgear import logger
logger.debug(f'Callback {self.callback.__name__}(event type:{ev_type})')
try:
# perform callback if we got an event type
self.callback(ev_type)
# event completed
self.queue.task_done()
except queue.Empty:
pass
except (BaseException, Exception):
pass
# exiting thread
self._stopper.clear()
class Event(object):
def __init__(self, etype):
self._type = etype

View file

@ -583,7 +583,7 @@ class Person(Referential):
continue
if cur_key not in self.__dict__:
raise Exception('Person has no property [%s]' % cur_key)
if None is not cur_value:
if None is not cur_value or ('deathday' == cur_key and kwargs.get('birthday')):
if 'akas' == cur_key:
cur_value.update(self.akas)
elif 'nicknames' == cur_key:
@ -768,7 +768,7 @@ class Person(Referential):
self._data_failure = True
logger.warning('Error searching extra info for person: %s - %s' % (self.name, ex(e)))
continue
if None is not pd and imdb_confirmed and TVINFO_IMDB == cur_tv_src:
if None is not pd and imdb_confirmed and TVINFO_IMDB == cur_tv_info_src:
rp = pd
break
# noinspection PyUnresolvedReferences

View file

@ -1053,12 +1053,18 @@ class MainHandler(WebHandler):
@staticmethod
def set_display_show_glide(slidetime=None, tvid_prodid=None, start_at=None):
if tvid_prodid and start_at:
dirty_config = False
if tvid_prodid and start_at and start_at != sickgear.DISPLAY_SHOW_GLIDE.get(tvid_prodid, {}).get('start_at'):
sickgear.DISPLAY_SHOW_GLIDE.setdefault(tvid_prodid, {}).update({'start_at': start_at})
dirty_config = True
if slidetime:
sickgear.DISPLAY_SHOW_GLIDE_SLIDETIME = sg_helpers.try_int(slidetime, 3000)
sickgear.save_config()
if slidetime and (
int_slidetime := sg_helpers.try_int(slidetime, 3000)) != sickgear.DISPLAY_SHOW_GLIDE_SLIDETIME:
sickgear.DISPLAY_SHOW_GLIDE_SLIDETIME = int_slidetime
dirty_config = True
if dirty_config:
sickgear.save_config()
@staticmethod
def set_poster_sortby(sort):

View file

@ -1 +1 @@
2024-06-25
2024-06-28