mirror of
https://github.com/SickGear/SickGear.git
synced 2024-12-24 11:43:38 +00:00
Merge branch 'main' into dev
This commit is contained in:
commit
c6bfc9c3d1
37 changed files with 211 additions and 16 deletions
75
.gitlab-ci.yml
Normal file
75
.gitlab-ci.yml
Normal file
|
@ -0,0 +1,75 @@
|
|||
test 3.8:
|
||||
image: python:3.8
|
||||
stage: test
|
||||
before_script:
|
||||
- pip install responses
|
||||
- pip install -r requirements.txt
|
||||
- pip install coveralls
|
||||
script:
|
||||
- cd ./tests
|
||||
- coverage run --source=.. --omit=../lib/* ./all_tests.py
|
||||
when: manual
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH == "main"
|
||||
- if: $CI_COMMIT_BRANCH == "dev"
|
||||
|
||||
test 3.9:
|
||||
image: python:3.9
|
||||
stage: test
|
||||
before_script:
|
||||
- pip install responses
|
||||
- pip install -r requirements.txt
|
||||
- pip install coveralls
|
||||
script:
|
||||
- cd ./tests
|
||||
- coverage run --source=.. --omit=../lib/* ./all_tests.py
|
||||
when: manual
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH == "main"
|
||||
- if: $CI_COMMIT_BRANCH == "dev"
|
||||
|
||||
test 3.10:
|
||||
image: python:3.10
|
||||
stage: test
|
||||
before_script:
|
||||
- pip install responses
|
||||
- pip install -r requirements.txt
|
||||
- pip install coveralls
|
||||
script:
|
||||
- cd ./tests
|
||||
- coverage run --source=.. --omit=../lib/* ./all_tests.py
|
||||
when: manual
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH == "main"
|
||||
- if: $CI_COMMIT_BRANCH == "dev"
|
||||
|
||||
test 3.11:
|
||||
image: python:3.11
|
||||
stage: test
|
||||
before_script:
|
||||
- pip install responses
|
||||
- pip install -r requirements.txt
|
||||
- pip install coveralls
|
||||
script:
|
||||
- cd ./tests
|
||||
- coverage run --source=.. --omit=../lib/* ./all_tests.py
|
||||
when: manual
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH == "main"
|
||||
- if: $CI_COMMIT_BRANCH == "dev"
|
||||
|
||||
test 3.12:
|
||||
image: python:3.12
|
||||
stage: test
|
||||
before_script:
|
||||
- pip install responses
|
||||
- pip install -r requirements.txt
|
||||
- pip install coveralls
|
||||
script:
|
||||
- cd ./tests
|
||||
- coverage run --source=.. --omit=../lib/* ./all_tests.py
|
||||
when: manual
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH == "main"
|
||||
- if: $CI_COMMIT_BRANCH == "dev"
|
||||
|
10
CHANGES.md
10
CHANGES.md
|
@ -5,6 +5,16 @@
|
|||
* Update urllib3 2.2.1 (54d6edf) to 2.2.2 (27e2a5c)
|
||||
|
||||
|
||||
### 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)
|
||||
|
||||
* Fix votes on shows/IMDb cards
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -595,7 +595,7 @@ $(function() {
|
|||
#if $this_show.get('p_chars')
|
||||
<p style='overflow-y:auto;max-height:152px'>
|
||||
#for $char in $this_show['p_chars']
|
||||
<span style='display:block;clear:both;font-weight:bold;font-size:0.9em;color:#393'>as $char[0]#if $RoleTypes.ActorMain != $char[1]# ($char[2]/$char[3] eps)#end if#</span>
|
||||
<span style='display:block;clear:both;font-weight:bold;font-size:0.9em;color:#393'>as $char[0]#if $RoleTypes.ActorMain != $char[1]# ($char[2]#if $char[3]#/$char[3] eps#end if#)#end if#</span>
|
||||
#end for
|
||||
</p>
|
||||
#end if
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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'):
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1 +1 @@
|
|||
2024-06-25
|
||||
2024-06-28
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,9 +1,14 @@
|
|||
import os
|
||||
import sys
|
||||
import warnings
|
||||
warnings.filterwarnings('ignore', module=r'.*fuz.*', message='.*Sequence.*')
|
||||
warnings.filterwarnings('ignore', module=r'.*connectionpool.*', message='.*certificate verification.*')
|
||||
|
||||
import unittest
|
||||
|
||||
sys.path.insert(1, os.path.abspath('..'))
|
||||
sys.path.insert(1, os.path.abspath('../lib'))
|
||||
|
||||
from sickgear import properFinder
|
||||
|
||||
import sickgear
|
||||
|
|
Loading…
Reference in a new issue