SickGear/sickgear/__init__.py

2565 lines
119 KiB
Python
Raw Normal View History

#
# This file is part of SickGear.
#
# SickGear is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# SickGear is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with SickGear. If not, see <http://www.gnu.org/licenses/>.
from collections import OrderedDict
from threading import Lock
import copy
import datetime
import io
import os
import re
import signal
import socket
import time
import webbrowser
# apparently py2exe won't build these unless they're imported somewhere
import os.path
import sys
import threading
import uuid
import zlib
from . import classes, db, helpers, image_cache, indexermapper, logger, metadata, naming, people_queue, providers, \
scene_exceptions, scene_numbering, scheduler, search_backlog, search_propers, search_queue, search_recent, \
show_queue, show_updater, subtitles, trakt_helpers, version_checker, watchedstate_queue
from . import auto_media_process, properFinder # must come after the above imports
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
from .providers.newznab import NewznabConstants
from .tv import TVidProdid
from .watchedstate import EmbyWatchedStateUpdater, PlexWatchedStateUpdater
from .webserve import History
from adba.aniDBerrors import AniDBError
# noinspection PyProtectedMember
from browser_ua import get_ua
from configobj import ConfigObj
from api_trakt import TraktAPI
from _23 import b64encodestring, decode_bytes, scandir
from sg_helpers import remove_file_perm
from six import iteritems, string_types
import sg_helpers
# noinspection PyUnreachableCode
if False:
from typing import AnyStr, Dict, List, Optional
from adba import Connection
from .event_queue import Events
from .tv import TVShow
from lib.api_trakt.trakt import TraktAccount
PID = None
ENV = {}
# noinspection PyTypeChecker
CFG = None # type: ConfigObj
CONFIG_FILE = ''
CONFIG_VERSION = None
CONFIG_OLD = None
CONFIG_LOADED = False
# Default encryption version (0 for None)
ENCRYPTION_VERSION = 0
PROG_DIR = '.'
MY_FULLNAME = None
MY_ARGS = []
SYS_ENCODING = ''
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]
people_queue_scheduler = None # type: Optional[scheduler.Scheduler]
watched_state_queue_scheduler = None # type: Optional[scheduler.Scheduler]
update_software_scheduler = None # type: Optional[scheduler.Scheduler]
update_packages_scheduler = None # type: Optional[scheduler.Scheduler]
update_show_scheduler = None # type: Optional[scheduler.Scheduler]
update_release_mappings_scheduler = None # type: Optional[scheduler.Scheduler]
search_recent_scheduler = None # type: Optional[scheduler.Scheduler]
search_backlog_scheduler = None # type: Optional[search_backlog.BacklogSearchScheduler]
search_propers_scheduler = None # type: Optional[scheduler.Scheduler]
search_subtitles_scheduler = None # type: Optional[scheduler.Scheduler]
emby_watched_state_scheduler = None # type: Optional[scheduler.Scheduler]
plex_watched_state_scheduler = None # type: Optional[scheduler.Scheduler]
process_media_scheduler = None # type: Optional[scheduler.Scheduler]
# noinspection PyTypeChecker
background_mapping_task = None # type: threading.Thread
# deprecated
# trakt_checker_scheduler = None
provider_ping_thread_pool = {}
showList = [] # type: List[TVShow]
showDict = {} # type: Dict[int, TVShow]
switched_shows = {} # type: Dict[AnyStr, AnyStr]
UPDATE_SHOWS_ON_START = False
SHOW_UPDATE_HOUR = 3
# non ui settings
REMOVE_FILENAME_CHARS = None
IMPORT_DEFAULT_CHECKED_SHOWS = 0
# /non ui settings
provider_list = []
newznab_providers = []
torrent_rss_providers = []
metadata_provider_dict = {}
MODULE_UPDATE_STRING = None
NEWEST_VERSION_STRING = None
MIN_UPDATE_INTERVAL = 1
DEFAULT_UPDATE_INTERVAL = 12
UPDATE_NOTIFY = False
UPDATE_AUTO = False
UPDATE_INTERVAL = DEFAULT_UPDATE_INTERVAL
NOTIFY_ON_UPDATE = False
MIN_UPDATE_PACKAGES_INTERVAL = 1
MAX_UPDATE_PACKAGES_INTERVAL = 9999
DEFAULT_UPDATE_PACKAGES_INTERVAL = 24
UPDATE_PACKAGES_NOTIFY = False
UPDATE_PACKAGES_AUTO = False
UPDATE_PACKAGES_MENU = False
UPDATE_PACKAGES_INTERVAL = DEFAULT_UPDATE_PACKAGES_INTERVAL
CUR_COMMIT_HASH = None
EXT_UPDATES = False
BRANCH = ''
GIT_REMOTE = ''
CUR_COMMIT_BRANCH = ''
INIT_LOCK = Lock()
started = False
ACTUAL_LOG_DIR = None
LOG_DIR = None
FILE_LOGGING_PRESET = 'DEBUG'
SOCKET_TIMEOUT = None
WEB_PORT = None
WEB_LOG = 0
WEB_ROOT = None
WEB_USERNAME = None
WEB_PASSWORD = None
WEB_HOST = None
WEB_IPV6 = 0
WEB_IPV64 = 0
HANDLE_REVERSE_PROXY = False
SEND_SECURITY_HEADERS = True
ALLOWED_HOSTS = None
ALLOW_ANYIP = True
PROXY_SETTING = None
PROXY_INDEXERS = True
CPU_PRESET = 'DISABLED'
ANON_REDIRECT = None
USE_API = False
API_KEYS = []
ENABLE_HTTPS = False
HTTPS_CERT = None
HTTPS_KEY = None
LAUNCH_BROWSER = False
CACHE_DIR = None
ACTUAL_CACHE_DIR = None
ZONEINFO_DIR = None
ROOT_DIRS = None
TRASH_REMOVE_SHOW = False
TRASH_ROTATE_LOGS = False
HOME_SEARCH_FOCUS = True
DISPLAY_FREESPACE = True
SORT_ARTICLE = False
DEBUG = False
SHOW_TAGS = []
SHOW_TAG_DEFAULT = ''
SHOWLIST_TAGVIEW = ''
METADATA_XBMC = None
METADATA_XBMC_12PLUS = None
METADATA_MEDIABROWSER = None
METADATA_PS3 = None
METADATA_WDTV = None
METADATA_TIVO = None
METADATA_MEDE8ER = None
METADATA_KODI = None
RESULTS_SORTBY = None
TVINFO_DEFAULT = 0
TVINFO_TIMEOUT = 20
QUALITY_DEFAULT = SD
WANTED_BEGIN_DEFAULT = 0
WANTED_LATEST_DEFAULT = 0
PAUSE_DEFAULT = False
STATUS_DEFAULT = SKIPPED
SCENE_DEFAULT = False
SUBTITLES_DEFAULT = False
FLATTEN_FOLDERS_DEFAULT = False
ANIME_DEFAULT = False
USE_IMDB_INFO = True
IMDB_ACCOUNTS = []
IMDB_DEFAULT_LIST_ID = '64552276'
IMDB_DEFAULT_LIST_NAME = 'SickGear'
PROVIDER_ORDER = []
PROVIDER_HOMES = {}
NAMING_MULTI_EP = False
NAMING_ANIME_MULTI_EP = False
NAMING_PATTERN = None
NAMING_ABD_PATTERN = None
NAMING_CUSTOM_ABD = False
NAMING_SPORTS_PATTERN = None
NAMING_CUSTOM_SPORTS = False
NAMING_ANIME_PATTERN = None
NAMING_CUSTOM_ANIME = False
NAMING_FORCE_FOLDERS = False
NAMING_STRIP_YEAR = False
NAMING_ANIME = 3
USE_NZBS = False
USE_TORRENTS = False
NZB_METHOD = None
NZB_DIR = None
USENET_RETENTION = 500
TORRENT_METHOD = None
TORRENT_DIR = None
DOWNLOAD_PROPERS = False
PROPERS_WEBDL_ONEGRP = True
WEBDL_TYPES = []
ALLOW_HIGH_PRIORITY = False
NEWZNAB_DATA = ''
DEFAULT_MEDIAPROCESS_INTERVAL = 10
DEFAULT_BACKLOG_PERIOD = 21
DEFAULT_RECENTSEARCH_INTERVAL = 40
DEFAULT_WATCHEDSTATE_INTERVAL = 10
MEDIAPROCESS_INTERVAL = DEFAULT_MEDIAPROCESS_INTERVAL
BACKLOG_PERIOD = DEFAULT_BACKLOG_PERIOD
BACKLOG_LIMITED_PERIOD = 7
RECENTSEARCH_INTERVAL = DEFAULT_RECENTSEARCH_INTERVAL
RECENTSEARCH_STARTUP = False
BACKLOG_NOFULL = False
MIN_MEDIAPROCESS_INTERVAL = 1
MIN_RECENTSEARCH_INTERVAL = 10
MIN_BACKLOG_PERIOD = 7
MAX_BACKLOG_PERIOD = 42
MIN_WATCHEDSTATE_INTERVAL = 10
MAX_WATCHEDSTATE_INTERVAL = 60
SEARCH_UNAIRED = False
UNAIRED_RECENT_SEARCH_ONLY = True
FLARESOLVERR_HOST = None
ADD_SHOWS_WO_DIR = False
ADD_SHOWS_METALANG = 'en'
CREATE_MISSING_SHOW_DIRS = False
SHOW_DIRS_WITH_DOTS = False
RENAME_EPISODES = False
RENAME_TBA_EPISODES = True
RENAME_NAME_CHANGED_EPISODES = False
AIRDATE_EPISODES = False
PROCESS_AUTOMATICALLY = False
KEEP_PROCESSED_DIR = False
PROCESS_LAST_DIR = None
PROCESS_LAST_METHOD = None
PROCESS_LAST_CLEANUP = False
PROCESS_METHOD = None
MOVE_ASSOCIATED_FILES = False
POSTPONE_IF_SYNC_FILES = True
PROCESS_POSITIVE_LOG = True
NFO_RENAME = True
TV_DOWNLOAD_DIR = None
UNPACK = False
SKIP_REMOVED_FILES = False
NZBGET_USERNAME = None
NZBGET_PASSWORD = None
NZBGET_CATEGORY = None
NZBGET_HOST = None
NZBGET_USE_HTTPS = False
NZBGET_PRIORITY = 100
NZBGET_SCRIPT_VERSION = None
NZBGET_MAP = None
NZBGET_SKIP_PM = False
SAB_USERNAME = None
SAB_PASSWORD = None
SAB_APIKEY = None
SAB_CATEGORY = None
SAB_HOST = ''
TORRENT_USERNAME = None
TORRENT_PASSWORD = None
TORRENT_HOST = ''
TORRENT_PATH = ''
TORRENT_SEED_TIME = 0
TORRENT_PAUSED = False
TORRENT_HIGH_BANDWIDTH = False
TORRENT_LABEL = ''
TORRENT_LABEL_VAR = 1
TORRENT_VERIFY_CERT = False
USE_EMBY = False
EMBY_UPDATE_LIBRARY = False
EMBY_PARENT_MAPS = None
EMBY_HOST = None
EMBY_APIKEY = None
EMBY_WATCHEDSTATE_SCHEDULED = False
EMBY_WATCHEDSTATE_INTERVAL = DEFAULT_WATCHEDSTATE_INTERVAL
USE_KODI = False
KODI_ALWAYS_ON = True
KODI_NOTIFY_ONSNATCH = False
KODI_NOTIFY_ONDOWNLOAD = False
KODI_NOTIFY_ONSUBTITLEDOWNLOAD = False
KODI_UPDATE_LIBRARY = False
KODI_UPDATE_FULL = False
KODI_UPDATE_ONLYFIRST = False
KODI_PARENT_MAPS = None
KODI_HOST = ''
KODI_USERNAME = None
KODI_PASSWORD = None
USE_PLEX = False
PLEX_NOTIFY_ONSNATCH = False
PLEX_NOTIFY_ONDOWNLOAD = False
PLEX_NOTIFY_ONSUBTITLEDOWNLOAD = False
PLEX_UPDATE_LIBRARY = False
PLEX_PARENT_MAPS = None
PLEX_SERVER_HOST = None
PLEX_HOST = None
PLEX_USERNAME = None
PLEX_PASSWORD = None
PLEX_WATCHEDSTATE_SCHEDULED = False
PLEX_WATCHEDSTATE_INTERVAL = DEFAULT_WATCHEDSTATE_INTERVAL
USE_XBMC = False
XBMC_ALWAYS_ON = True
XBMC_NOTIFY_ONSNATCH = False
XBMC_NOTIFY_ONDOWNLOAD = False
XBMC_NOTIFY_ONSUBTITLEDOWNLOAD = False
XBMC_UPDATE_LIBRARY = False
XBMC_UPDATE_FULL = False
XBMC_UPDATE_ONLYFIRST = False
XBMC_HOST = ''
XBMC_USERNAME = None
XBMC_PASSWORD = None
QUEUE_UPDATE_LIBRARY = []
USE_NMJ = False
NMJ_HOST = None
NMJ_DATABASE = None
NMJ_MOUNT = None
USE_NMJv2 = False
NMJv2_HOST = None
NMJv2_DATABASE = None
NMJv2_DBLOC = None
USE_SYNOINDEX = False
SYNOINDEX_UPDATE_LIBRARY = True
USE_SYNOLOGYNOTIFIER = False
SYNOLOGYNOTIFIER_NOTIFY_ONSNATCH = False
SYNOLOGYNOTIFIER_NOTIFY_ONDOWNLOAD = False
SYNOLOGYNOTIFIER_NOTIFY_ONSUBTITLEDOWNLOAD = False
USE_PYTIVO = False
PYTIVO_HOST = ''
PYTIVO_SHARE_NAME = ''
PYTIVO_TIVO_NAME = ''
USE_BOXCAR2 = False
BOXCAR2_NOTIFY_ONSNATCH = False
BOXCAR2_NOTIFY_ONDOWNLOAD = False
BOXCAR2_NOTIFY_ONSUBTITLEDOWNLOAD = False
BOXCAR2_ACCESSTOKEN = None
BOXCAR2_SOUND = None
USE_PUSHBULLET = False
PUSHBULLET_NOTIFY_ONSNATCH = False
PUSHBULLET_NOTIFY_ONDOWNLOAD = False
PUSHBULLET_NOTIFY_ONSUBTITLEDOWNLOAD = False
PUSHBULLET_ACCESS_TOKEN = None
PUSHBULLET_DEVICE_IDEN = None
USE_PUSHOVER = False
PUSHOVER_NOTIFY_ONSNATCH = False
PUSHOVER_NOTIFY_ONDOWNLOAD = False
PUSHOVER_NOTIFY_ONSUBTITLEDOWNLOAD = False
PUSHOVER_USERKEY = None
PUSHOVER_APIKEY = None
PUSHOVER_PRIORITY = '0'
PUSHOVER_DEVICE = None
PUSHOVER_SOUND = None
USE_GROWL = False
GROWL_NOTIFY_ONSNATCH = False
GROWL_NOTIFY_ONDOWNLOAD = False
GROWL_NOTIFY_ONSUBTITLEDOWNLOAD = False
GROWL_HOST = ''
USE_PROWL = False
PROWL_NOTIFY_ONSNATCH = False
PROWL_NOTIFY_ONDOWNLOAD = False
PROWL_NOTIFY_ONSUBTITLEDOWNLOAD = False
PROWL_API = None
PROWL_PRIORITY = '0'
USE_LIBNOTIFY = False
LIBNOTIFY_NOTIFY_ONSNATCH = False
LIBNOTIFY_NOTIFY_ONDOWNLOAD = False
LIBNOTIFY_NOTIFY_ONSUBTITLEDOWNLOAD = False
USE_PUSHALOT = False
PUSHALOT_NOTIFY_ONSNATCH = False
PUSHALOT_NOTIFY_ONDOWNLOAD = False
PUSHALOT_NOTIFY_ONSUBTITLEDOWNLOAD = False
PUSHALOT_AUTHORIZATIONTOKEN = None
USE_TRAKT = False
TRAKT_REMOVE_WATCHLIST = False
TRAKT_REMOVE_SERIESLIST = False
TRAKT_USE_WATCHLIST = False
TRAKT_METHOD_ADD = 0
TRAKT_START_PAUSED = False
TRAKT_SYNC = False
TRAKT_DEFAULT_INDEXER = None
TRAKT_UPDATE_COLLECTION = {}
USE_SLACK = False
SLACK_NOTIFY_ONSNATCH = False
SLACK_NOTIFY_ONDOWNLOAD = False
SLACK_NOTIFY_ONSUBTITLEDOWNLOAD = False
SLACK_CHANNEL = None
SLACK_AS_AUTHED = False
SLACK_BOT_NAME = None
SLACK_ICON_URL = None
SLACK_ACCESS_TOKEN = None
USE_DISCORD = False
DISCORD_NOTIFY_ONSNATCH = False
DISCORD_NOTIFY_ONDOWNLOAD = False
DISCORD_NOTIFY_ONSUBTITLEDOWNLOAD = False
DISCORD_AS_AUTHED = False
DISCORD_USERNAME = None
DISCORD_ICON_URL = None
DISCORD_AS_TTS = 0
DISCORD_ACCESS_TOKEN = None
USE_GITTER = False
GITTER_NOTIFY_ONSNATCH = False
GITTER_NOTIFY_ONDOWNLOAD = False
GITTER_NOTIFY_ONSUBTITLEDOWNLOAD = False
GITTER_ROOM = None
GITTER_ACCESS_TOKEN = None
USE_TELEGRAM = False
TELEGRAM_NOTIFY_ONSNATCH = False
TELEGRAM_NOTIFY_ONDOWNLOAD = False
TELEGRAM_NOTIFY_ONSUBTITLEDOWNLOAD = False
TELEGRAM_SEND_IMAGE = True
TELEGRAM_QUIET = False
TELEGRAM_ACCESS_TOKEN = None
TELEGRAM_CHATID = None
USE_EMAIL = False
EMAIL_OLD_SUBJECTS = False
EMAIL_NOTIFY_ONSNATCH = False
EMAIL_NOTIFY_ONDOWNLOAD = False
EMAIL_NOTIFY_ONSUBTITLEDOWNLOAD = False
EMAIL_HOST = None
EMAIL_PORT = 25
EMAIL_TLS = False
EMAIL_USER = None
EMAIL_PASSWORD = None
EMAIL_FROM = None
EMAIL_LIST = None
USE_ANIDB = False
ANIDB_USERNAME = None
ANIDB_PASSWORD = None
ANIDB_USE_MYLIST = False
# noinspection PyTypeChecker
ADBA_CONNECTION = None # type: Connection
ANIME_TREAT_AS_HDTV = False
GUI_NAME = ''
DEFAULT_HOME = None
FANART_LIMIT = None
FANART_PANEL = None
FANART_RATINGS = {}
HOME_LAYOUT = None
FOOTER_TIME_LAYOUT = 0
POSTER_SORTBY = None
POSTER_SORTDIR = None
DISPLAY_SHOW_GLIDE = {}
DISPLAY_SHOW_GLIDE_SLIDETIME = 3000
DISPLAY_SHOW_VIEWMODE = 0
DISPLAY_SHOW_BACKGROUND = False
DISPLAY_SHOW_BACKGROUND_TRANSLUCENT = False
DISPLAY_SHOW_VIEWART = 0
DISPLAY_SHOW_MINIMUM = True
DISPLAY_SHOW_SPECIALS = False
EPISODE_VIEW_VIEWMODE = 0
EPISODE_VIEW_BACKGROUND = False
EPISODE_VIEW_BACKGROUND_TRANSLUCENT = False
EPISODE_VIEW_LAYOUT = None
EPISODE_VIEW_SORT = None
EPISODE_VIEW_DISPLAY_PAUSED = 0
EPISODE_VIEW_POSTERS = True
EPISODE_VIEW_MISSED_RANGE = 7
HISTORY_LAYOUT = None
BROWSELIST_HIDDEN = []
BROWSELIST_MRU = {}
FUZZY_DATING = False
TRIM_ZERO = False
DATE_PRESET = None
TIME_PRESET = None
TIME_PRESET_W_SECONDS = None
TIMEZONE_DISPLAY = None
THEME_NAME = None
USE_SUBTITLES = False
SUBTITLES_LANGUAGES = []
SUBTITLES_DIR = ''
SUBTITLES_OS_HASH = True
SUBTITLES_SERVICES_LIST = []
SUBTITLES_SERVICES_ENABLED = []
SUBTITLES_SERVICES_AUTH = [['', '']]
SUBTITLES_HISTORY = False
SUBTITLES_FINDER_INTERVAL = 1
USE_FAILED_DOWNLOADS = False
DELETE_FAILED = False
BACKUP_DB_PATH = '' # type: AnyStr
BACKUP_DB_ONEDAY = False # type: bool
BACKUP_DB_MAX_COUNT = 14 # type: int
BACKUP_DB_DEFAULT_COUNT = 14 # type: int
UPDATES_TODO = {}
EXTRA_SCRIPTS = []
SG_EXTRA_SCRIPTS = []
GIT_PATH = None
IGNORE_WORDS = {
r'^(?=.*?\bspanish\b)((?!spanish.?princess).)*$',
'core2hd', 'hevc', 'MrLss', 'reenc', 'x265', 'danish', 'deutsch', 'dutch', 'flemish', 'french',
'german', 'italian', 'nordic', 'norwegian', 'portuguese', 'spanish', 'swedish', 'turkish'
}
IGNORE_WORDS_REGEX = True
REQUIRE_WORDS = set()
REQUIRE_WORDS_REGEX = False
WANTEDLIST_CACHE = None
CALENDAR_UNPROTECTED = False
TMDB_API_KEY = TmdbIndexer.API_KEY
FANART_API_KEY = '3728ca1a2a937ba0c93b6e63cc86cecb'
# to switch between staging and production TRAKT environment
TRAKT_STAGING = False
TRAKT_TIMEOUT = 60
TRAKT_VERIFY = True
TRAKT_CONNECTED_ACCOUNT = None
TRAKT_ACCOUNTS = {} # type: Dict[int, TraktAccount]
TRAKT_MRU = ''
if TRAKT_STAGING:
# staging trakt values:
TRAKT_CLIENT_ID = '2aae3052f90b14235d184cc8f709b12b4fd8ae35f339a060a890c70db92be87a'
TRAKT_CLIENT_SECRET = '900e03471220503843d4a856bfbef17080cddb630f2b7df6a825e96e3ff3c39e'
TRAKT_PIN_URL = 'https://staging.trakt.tv/pin/638'
TRAKT_BASE_URL = 'http' + '://api.staging.trakt.tv/'
else:
# production trakt values:
TRAKT_CLIENT_ID = 'f1c453c67d81f1307f9118172c408a883eb186b094d5ea33080d59ddedb7fc7c'
TRAKT_CLIENT_SECRET = '12efb6fb6e863a08934d9904032a90008325df7e23514650cade55e7e7c118c5'
TRAKT_PIN_URL = 'https://trakt.tv/pin/6314'
TRAKT_BASE_URL = 'https://api.trakt.tv/'
Add menu Shows/"TMDB Cards". Add top rated, popular, trending today, trending this week, to TMDB cards. Change Shows/Add show... Trakt and IMDb card descriptions to be dynamic. Add network data to trakt cards. Add fallback for show cast when no suitable items are found in tvdb_api. Change refactor for trakt lib update. Change sanitise api response dates for cards (an invalid trakt date caused a UI glitch). Fix issue where trakt can return no tvdb id causing a card to not display. Change view-show TVDb genre links to use anon link setting. Change remove displayShow.tmpl code for '|' sep as it is a fixed list string at data source. Change add TVINFO_FANSITE placeholder icon. Change refactor api sg.`CMD_SickGearShowsBrowseTrakt`. --- Refactor date handling to make it's usage consistent from indexerapi Split when_past out to to started_past and return_past for UI. Fix trakt returning dates. Change bring properly into use, the proper new season returning date. Change remove PY2 unused import statements. --- Fix issue with Trakt cards where an incorrect cache image obscures the default card placeholder image. Simplify airtime for cards. Remove nonsense TMDB api overview text. Rearrange cards order on top menu. --- Remove unused vars and simplify regex use cases. Fix tv cards issue with Trakt and Tvmaze where show_info does not carry a first episode_info. Instantiate with TVInfoEpisode() instead of None, so that expected properties exist without a need for Nonetype tests. Change simplify `overview` and `airtime` use after lib output type is made trustable. Change cards view to not allow items with no seriesname.
2023-03-09 02:13:52 +00:00
IMDB_MRU = ''
MC_MRU = ''
Add menu Shows/"TMDB Cards". Add top rated, popular, trending today, trending this week, to TMDB cards. Change Shows/Add show... Trakt and IMDb card descriptions to be dynamic. Add network data to trakt cards. Add fallback for show cast when no suitable items are found in tvdb_api. Change refactor for trakt lib update. Change sanitise api response dates for cards (an invalid trakt date caused a UI glitch). Fix issue where trakt can return no tvdb id causing a card to not display. Change view-show TVDb genre links to use anon link setting. Change remove displayShow.tmpl code for '|' sep as it is a fixed list string at data source. Change add TVINFO_FANSITE placeholder icon. Change refactor api sg.`CMD_SickGearShowsBrowseTrakt`. --- Refactor date handling to make it's usage consistent from indexerapi Split when_past out to to started_past and return_past for UI. Fix trakt returning dates. Change bring properly into use, the proper new season returning date. Change remove PY2 unused import statements. --- Fix issue with Trakt cards where an incorrect cache image obscures the default card placeholder image. Simplify airtime for cards. Remove nonsense TMDB api overview text. Rearrange cards order on top menu. --- Remove unused vars and simplify regex use cases. Fix tv cards issue with Trakt and Tvmaze where show_info does not carry a first episode_info. Instantiate with TVInfoEpisode() instead of None, so that expected properties exist without a need for Nonetype tests. Change simplify `overview` and `airtime` use after lib output type is made trustable. Change cards view to not allow items with no seriesname.
2023-03-09 02:13:52 +00:00
NE_MRU = ''
TMDB_MRU = ''
TVC_MRU = ''
TVM_MRU = ''
COOKIE_SECRET = b64encodestring(uuid.uuid4().bytes + uuid.uuid4().bytes)
CACHE_IMAGE_URL_LIST = classes.ImageUrlList()
__INITIALIZED__ = False
__INIT_STAGE__ = 0
# don't reassign MEMCACHE var without reassigning sg_helpers.MEMCACHE
# and scene_exceptions.MEMCACHE
# as long as the pointer is the same (dict only modified) all is fine
MEMCACHE = {}
sg_helpers.MEMCACHE = MEMCACHE
scene_exceptions.MEMCACHE = MEMCACHE
MEMCACHE_FLAG_IMAGES = {}
def get_backlog_cycle_time():
cycletime = RECENTSEARCH_INTERVAL * 2 + 7
return max([cycletime, 720])
def initialize(console_logging=True):
with INIT_LOCK:
# Misc
global __INITIALIZED__, __INIT_STAGE__
if __INITIALIZED__:
return False
__INIT_STAGE__ += 1
if 1 == __INIT_STAGE__:
init_stage_1(console_logging)
else:
return init_stage_2()
def init_stage_1(console_logging):
# Misc
global showList, showDict, switched_shows, provider_list, newznab_providers, torrent_rss_providers, \
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_OLD, CONFIG_LOADED, \
REMOVE_FILENAME_CHARS, IMPORT_DEFAULT_CHECKED_SHOWS, WANTEDLIST_CACHE, MODULE_UPDATE_STRING, EXT_UPDATES
# Add Show Search
global RESULTS_SORTBY
# Add Show Defaults
global QUALITY_DEFAULT, WANTED_BEGIN_DEFAULT, WANTED_LATEST_DEFAULT, SHOW_TAG_DEFAULT, PAUSE_DEFAULT, \
STATUS_DEFAULT, SCENE_DEFAULT, SUBTITLES_DEFAULT, FLATTEN_FOLDERS_DEFAULT, ANIME_DEFAULT
# Post-processing
global KEEP_PROCESSED_DIR, PROCESS_LAST_DIR, PROCESS_LAST_METHOD, PROCESS_LAST_CLEANUP
# Views
global GUI_NAME, HOME_LAYOUT, FOOTER_TIME_LAYOUT, POSTER_SORTBY, POSTER_SORTDIR, DISPLAY_SHOW_SPECIALS, \
EPISODE_VIEW_LAYOUT, EPISODE_VIEW_SORT, EPISODE_VIEW_DISPLAY_PAUSED, \
EPISODE_VIEW_MISSED_RANGE, EPISODE_VIEW_POSTERS, FANART_PANEL, FANART_RATINGS, \
EPISODE_VIEW_VIEWMODE, EPISODE_VIEW_BACKGROUND, EPISODE_VIEW_BACKGROUND_TRANSLUCENT, \
DISPLAY_SHOW_GLIDE, DISPLAY_SHOW_GLIDE_SLIDETIME, \
DISPLAY_SHOW_VIEWMODE, DISPLAY_SHOW_BACKGROUND, DISPLAY_SHOW_BACKGROUND_TRANSLUCENT, \
DISPLAY_SHOW_VIEWART, DISPLAY_SHOW_MINIMUM, DISPLAY_SHOW_SPECIALS, HISTORY_LAYOUT, \
BROWSELIST_HIDDEN, BROWSELIST_MRU
# Gen Config/Misc
global LAUNCH_BROWSER, UPDATE_SHOWS_ON_START, SHOW_UPDATE_HOUR, \
TRASH_REMOVE_SHOW, TRASH_ROTATE_LOGS, ACTUAL_LOG_DIR, LOG_DIR, TVINFO_TIMEOUT, ROOT_DIRS, \
UPDATE_NOTIFY, UPDATE_AUTO, UPDATE_INTERVAL, NOTIFY_ON_UPDATE,\
UPDATE_PACKAGES_NOTIFY, UPDATE_PACKAGES_AUTO, UPDATE_PACKAGES_MENU, UPDATE_PACKAGES_INTERVAL
# Gen Config/Interface
global THEME_NAME, DEFAULT_HOME, FANART_LIMIT, SHOWLIST_TAGVIEW, SHOW_TAGS, \
HOME_SEARCH_FOCUS, USE_IMDB_INFO, IMDB_ACCOUNTS, DISPLAY_FREESPACE, SORT_ARTICLE, FUZZY_DATING, TRIM_ZERO, \
DATE_PRESET, TIME_PRESET, TIME_PRESET_W_SECONDS, TIMEZONE_DISPLAY, \
WEB_USERNAME, WEB_PASSWORD, CALENDAR_UNPROTECTED, USE_API, API_KEYS, WEB_PORT, WEB_LOG, \
ENABLE_HTTPS, HTTPS_CERT, HTTPS_KEY, WEB_IPV6, WEB_IPV64, HANDLE_REVERSE_PROXY, \
SEND_SECURITY_HEADERS, ALLOWED_HOSTS, ALLOW_ANYIP
# Gen Config/Advanced
global BRANCH, CUR_COMMIT_BRANCH, GIT_REMOTE, CUR_COMMIT_HASH, GIT_PATH, CPU_PRESET, ANON_REDIRECT, \
ENCRYPTION_VERSION, PROXY_SETTING, PROXY_INDEXERS, FILE_LOGGING_PRESET
# Search Settings/Episode
global DOWNLOAD_PROPERS, PROPERS_WEBDL_ONEGRP, WEBDL_TYPES, RECENTSEARCH_INTERVAL, \
BACKLOG_LIMITED_PERIOD, BACKLOG_NOFULL, BACKLOG_PERIOD, USENET_RETENTION, IGNORE_WORDS, REQUIRE_WORDS, \
IGNORE_WORDS, IGNORE_WORDS_REGEX, REQUIRE_WORDS, REQUIRE_WORDS_REGEX, \
ALLOW_HIGH_PRIORITY, SEARCH_UNAIRED, UNAIRED_RECENT_SEARCH_ONLY, FLARESOLVERR_HOST
# Search Settings/NZB search
global USE_NZBS, NZB_METHOD, NZB_DIR, SAB_HOST, SAB_USERNAME, SAB_PASSWORD, SAB_APIKEY, SAB_CATEGORY, \
NZBGET_USE_HTTPS, NZBGET_HOST, NZBGET_USERNAME, NZBGET_PASSWORD, NZBGET_CATEGORY, NZBGET_PRIORITY, \
NZBGET_SCRIPT_VERSION, NZBGET_MAP, NZBGET_SKIP_PM
# Search Settings/Torrent search
global USE_TORRENTS, TORRENT_METHOD, TORRENT_DIR, TORRENT_HOST, TORRENT_USERNAME, TORRENT_PASSWORD, \
TORRENT_LABEL, TORRENT_LABEL_VAR, TORRENT_PATH, TORRENT_SEED_TIME, TORRENT_PAUSED, \
TORRENT_HIGH_BANDWIDTH, TORRENT_VERIFY_CERT
# Media Providers
global PROVIDER_ORDER, NEWZNAB_DATA, PROVIDER_HOMES
# Subtitles
global USE_SUBTITLES, SUBTITLES_LANGUAGES, SUBTITLES_DIR, SUBTITLES_FINDER_INTERVAL, SUBTITLES_OS_HASH, \
SUBTITLES_HISTORY, SUBTITLES_SERVICES_LIST, SUBTITLES_SERVICES_ENABLED, SUBTITLES_SERVICES_AUTH
# Media Process/Post-Processing
global TV_DOWNLOAD_DIR, PROCESS_METHOD, PROCESS_AUTOMATICALLY, MEDIAPROCESS_INTERVAL, \
POSTPONE_IF_SYNC_FILES, PROCESS_POSITIVE_LOG, EXTRA_SCRIPTS, SG_EXTRA_SCRIPTS, \
DEFAULT_MEDIAPROCESS_INTERVAL, MIN_MEDIAPROCESS_INTERVAL, \
UNPACK, SKIP_REMOVED_FILES, MOVE_ASSOCIATED_FILES, NFO_RENAME, \
RENAME_EPISODES, RENAME_TBA_EPISODES, RENAME_NAME_CHANGED_EPISODES, \
AIRDATE_EPISODES, USE_FAILED_DOWNLOADS, DELETE_FAILED
# Media Process/Episode Naming
global NAMING_PATTERN, NAMING_MULTI_EP, NAMING_STRIP_YEAR, NAMING_CUSTOM_ABD, NAMING_ABD_PATTERN, \
NAMING_CUSTOM_SPORTS, NAMING_SPORTS_PATTERN, \
NAMING_CUSTOM_ANIME, NAMING_ANIME_PATTERN, NAMING_ANIME_MULTI_EP, NAMING_ANIME
# Media Process/Metadata
global METADATA_KODI, METADATA_MEDE8ER, METADATA_XBMC, METADATA_MEDIABROWSER, \
METADATA_PS3, METADATA_TIVO, METADATA_WDTV, METADATA_XBMC_12PLUS
# Notification Settings/HT and NAS
global USE_EMBY, EMBY_UPDATE_LIBRARY, EMBY_PARENT_MAPS, EMBY_HOST, EMBY_APIKEY, \
EMBY_WATCHEDSTATE_SCHEDULED, EMBY_WATCHEDSTATE_INTERVAL, \
USE_KODI, KODI_ALWAYS_ON, KODI_UPDATE_LIBRARY, KODI_UPDATE_FULL, KODI_UPDATE_ONLYFIRST, \
KODI_PARENT_MAPS, KODI_HOST, KODI_USERNAME, KODI_PASSWORD, KODI_NOTIFY_ONSNATCH, \
KODI_NOTIFY_ONDOWNLOAD, KODI_NOTIFY_ONSUBTITLEDOWNLOAD, \
USE_XBMC, XBMC_ALWAYS_ON, XBMC_NOTIFY_ONSNATCH, XBMC_NOTIFY_ONDOWNLOAD, XBMC_NOTIFY_ONSUBTITLEDOWNLOAD, \
XBMC_UPDATE_LIBRARY, XBMC_UPDATE_FULL, XBMC_UPDATE_ONLYFIRST, XBMC_HOST, XBMC_USERNAME, XBMC_PASSWORD, \
USE_PLEX, PLEX_USERNAME, PLEX_PASSWORD, PLEX_UPDATE_LIBRARY, PLEX_PARENT_MAPS, PLEX_SERVER_HOST, \
PLEX_NOTIFY_ONSNATCH, PLEX_NOTIFY_ONDOWNLOAD, PLEX_NOTIFY_ONSUBTITLEDOWNLOAD, PLEX_HOST, \
PLEX_WATCHEDSTATE_SCHEDULED, PLEX_WATCHEDSTATE_INTERVAL, \
USE_NMJ, NMJ_HOST, NMJ_DATABASE, NMJ_MOUNT, \
USE_NMJv2, NMJv2_HOST, NMJv2_DATABASE, NMJv2_DBLOC, \
USE_SYNOINDEX, \
USE_SYNOLOGYNOTIFIER, SYNOLOGYNOTIFIER_NOTIFY_ONSNATCH, \
SYNOLOGYNOTIFIER_NOTIFY_ONDOWNLOAD, SYNOLOGYNOTIFIER_NOTIFY_ONSUBTITLEDOWNLOAD, \
USE_PYTIVO, PYTIVO_HOST, PYTIVO_SHARE_NAME, PYTIVO_TIVO_NAME
# Notification Settings/Devices
global USE_GROWL, GROWL_NOTIFY_ONSNATCH, GROWL_NOTIFY_ONDOWNLOAD, GROWL_NOTIFY_ONSUBTITLEDOWNLOAD, \
GROWL_HOST, \
USE_PROWL, PROWL_NOTIFY_ONSNATCH, PROWL_NOTIFY_ONDOWNLOAD, PROWL_NOTIFY_ONSUBTITLEDOWNLOAD, \
PROWL_API, PROWL_PRIORITY, \
USE_LIBNOTIFY, LIBNOTIFY_NOTIFY_ONSNATCH, LIBNOTIFY_NOTIFY_ONDOWNLOAD, \
LIBNOTIFY_NOTIFY_ONSUBTITLEDOWNLOAD, \
USE_PUSHOVER, PUSHOVER_NOTIFY_ONSNATCH, PUSHOVER_NOTIFY_ONDOWNLOAD, PUSHOVER_NOTIFY_ONSUBTITLEDOWNLOAD, \
PUSHOVER_USERKEY, PUSHOVER_APIKEY, PUSHOVER_PRIORITY, PUSHOVER_DEVICE, PUSHOVER_SOUND, \
USE_BOXCAR2, BOXCAR2_NOTIFY_ONSNATCH, BOXCAR2_NOTIFY_ONDOWNLOAD, BOXCAR2_NOTIFY_ONSUBTITLEDOWNLOAD, \
BOXCAR2_ACCESSTOKEN, BOXCAR2_SOUND, \
USE_PUSHALOT, PUSHALOT_NOTIFY_ONSNATCH, PUSHALOT_NOTIFY_ONDOWNLOAD, \
PUSHALOT_NOTIFY_ONSUBTITLEDOWNLOAD, PUSHALOT_AUTHORIZATIONTOKEN, \
USE_PUSHBULLET, PUSHBULLET_NOTIFY_ONSNATCH, PUSHBULLET_NOTIFY_ONDOWNLOAD, \
PUSHBULLET_NOTIFY_ONSUBTITLEDOWNLOAD, PUSHBULLET_ACCESS_TOKEN, PUSHBULLET_DEVICE_IDEN
# Notification Settings/Social
global USE_TRAKT, TRAKT_CONNECTED_ACCOUNT, TRAKT_ACCOUNTS, TRAKT_MRU, TRAKT_VERIFY, \
TRAKT_USE_WATCHLIST, TRAKT_REMOVE_WATCHLIST, TRAKT_TIMEOUT, TRAKT_METHOD_ADD, TRAKT_START_PAUSED, \
TRAKT_SYNC, TRAKT_DEFAULT_INDEXER, TRAKT_REMOVE_SERIESLIST, TRAKT_UPDATE_COLLECTION, \
Add menu Shows/"TMDB Cards". Add top rated, popular, trending today, trending this week, to TMDB cards. Change Shows/Add show... Trakt and IMDb card descriptions to be dynamic. Add network data to trakt cards. Add fallback for show cast when no suitable items are found in tvdb_api. Change refactor for trakt lib update. Change sanitise api response dates for cards (an invalid trakt date caused a UI glitch). Fix issue where trakt can return no tvdb id causing a card to not display. Change view-show TVDb genre links to use anon link setting. Change remove displayShow.tmpl code for '|' sep as it is a fixed list string at data source. Change add TVINFO_FANSITE placeholder icon. Change refactor api sg.`CMD_SickGearShowsBrowseTrakt`. --- Refactor date handling to make it's usage consistent from indexerapi Split when_past out to to started_past and return_past for UI. Fix trakt returning dates. Change bring properly into use, the proper new season returning date. Change remove PY2 unused import statements. --- Fix issue with Trakt cards where an incorrect cache image obscures the default card placeholder image. Simplify airtime for cards. Remove nonsense TMDB api overview text. Rearrange cards order on top menu. --- Remove unused vars and simplify regex use cases. Fix tv cards issue with Trakt and Tvmaze where show_info does not carry a first episode_info. Instantiate with TVInfoEpisode() instead of None, so that expected properties exist without a need for Nonetype tests. Change simplify `overview` and `airtime` use after lib output type is made trustable. Change cards view to not allow items with no seriesname.
2023-03-09 02:13:52 +00:00
MC_MRU, NE_MRU, TMDB_MRU, TVC_MRU, TVM_MRU, \
USE_SLACK, SLACK_NOTIFY_ONSNATCH, SLACK_NOTIFY_ONDOWNLOAD, SLACK_NOTIFY_ONSUBTITLEDOWNLOAD, \
SLACK_CHANNEL, SLACK_AS_AUTHED, SLACK_BOT_NAME, SLACK_ICON_URL, SLACK_ACCESS_TOKEN, \
USE_DISCORD, DISCORD_NOTIFY_ONSNATCH, DISCORD_NOTIFY_ONDOWNLOAD, \
DISCORD_NOTIFY_ONSUBTITLEDOWNLOAD, \
DISCORD_AS_AUTHED, DISCORD_USERNAME, DISCORD_ICON_URL, DISCORD_AS_TTS, DISCORD_ACCESS_TOKEN,\
USE_GITTER, GITTER_NOTIFY_ONSNATCH, GITTER_NOTIFY_ONDOWNLOAD, GITTER_NOTIFY_ONSUBTITLEDOWNLOAD,\
GITTER_ROOM, GITTER_ACCESS_TOKEN, \
USE_TELEGRAM, TELEGRAM_NOTIFY_ONSNATCH, TELEGRAM_NOTIFY_ONDOWNLOAD, TELEGRAM_NOTIFY_ONSUBTITLEDOWNLOAD, \
TELEGRAM_SEND_IMAGE, TELEGRAM_QUIET, TELEGRAM_ACCESS_TOKEN, TELEGRAM_CHATID, \
USE_EMAIL, EMAIL_NOTIFY_ONSNATCH, EMAIL_NOTIFY_ONDOWNLOAD, EMAIL_NOTIFY_ONSUBTITLEDOWNLOAD, EMAIL_FROM, \
EMAIL_HOST, EMAIL_PORT, EMAIL_TLS, EMAIL_USER, EMAIL_PASSWORD, EMAIL_LIST, EMAIL_OLD_SUBJECTS
# Anime Settings
global ANIME_TREAT_AS_HDTV, USE_ANIDB, ANIDB_USERNAME, ANIDB_PASSWORD, ANIDB_USE_MYLIST
# db backup settings
global BACKUP_DB_PATH, BACKUP_DB_ONEDAY, BACKUP_DB_MAX_COUNT, BACKUP_DB_DEFAULT_COUNT
# pip update states
global UPDATES_TODO
for stanza in ('General', 'Blackhole', 'SABnzbd', 'NZBGet', 'Emby', 'Kodi', 'XBMC', 'PLEX',
'Growl', 'Prowl', 'Slack', 'Discord', 'Boxcar2', 'NMJ', 'NMJv2',
'Synology', 'SynologyNotifier',
'pyTivo', 'Pushalot', 'Pushbullet', 'Subtitles'):
check_section(CFG, stanza)
update_config = False
WANTEDLIST_CACHE = common.WantedQualities()
# wanted branch
BRANCH = check_setting_str(CFG, 'General', 'branch', '')
# git_remote
GIT_REMOTE = check_setting_str(CFG, 'General', 'git_remote', 'origin')
ACTUAL_CACHE_DIR = check_setting_str(CFG, 'General', 'cache_dir', 'cache')
# unless they specify, put the cache dir inside the data dir
if not os.path.isabs(ACTUAL_CACHE_DIR):
CACHE_DIR = os.path.join(DATA_DIR, ACTUAL_CACHE_DIR)
else:
CACHE_DIR = ACTUAL_CACHE_DIR
if not helpers.make_dir(CACHE_DIR):
logger.error('!!! creating local cache dir failed, using system default')
CACHE_DIR = None
# clean cache folders
if CACHE_DIR:
helpers.clear_cache()
ZONEINFO_DIR = os.path.join(CACHE_DIR, 'zoneinfo')
if not os.path.isdir(ZONEINFO_DIR) and not helpers.make_path(ZONEINFO_DIR):
logger.error('!!! creating local zoneinfo dir failed')
sg_helpers.CACHE_DIR = CACHE_DIR
sg_helpers.DATA_DIR = DATA_DIR
THEME_NAME = check_setting_str(CFG, 'GUI', 'theme_name', 'dark')
GUI_NAME = check_setting_str(CFG, 'GUI', 'gui_name', 'slick')
DEFAULT_HOME = check_setting_str(CFG, 'GUI', 'default_home', 'episodes')
FANART_LIMIT = check_setting_int(CFG, 'GUI', 'fanart_limit', 3)
FANART_PANEL = check_setting_str(CFG, 'GUI', 'fanart_panel', 'highlight2')
FANART_RATINGS = sg_helpers.ast_eval(check_setting_str(CFG, 'GUI', 'fanart_ratings', None), {})
USE_IMDB_INFO = bool(check_setting_int(CFG, 'GUI', 'use_imdb_info', 1))
IMDB_ACCOUNTS = CFG.get('GUI', []).get('imdb_accounts', [IMDB_DEFAULT_LIST_ID, IMDB_DEFAULT_LIST_NAME])
HOME_SEARCH_FOCUS = bool(check_setting_int(CFG, 'General', 'home_search_focus', HOME_SEARCH_FOCUS))
DISPLAY_FREESPACE = bool(check_setting_int(CFG, 'General', 'display_freespace', 1))
SORT_ARTICLE = bool(check_setting_int(CFG, 'General', 'sort_article', 0))
FUZZY_DATING = bool(check_setting_int(CFG, 'GUI', 'fuzzy_dating', 0))
TRIM_ZERO = bool(check_setting_int(CFG, 'GUI', 'trim_zero', 0))
DATE_PRESET = check_setting_str(CFG, 'GUI', 'date_preset', '%x')
TIME_PRESET_W_SECONDS = check_setting_str(CFG, 'GUI', 'time_preset', '%I:%M:%S %p')
TIME_PRESET = TIME_PRESET_W_SECONDS.replace(':%S', '')
TIMEZONE_DISPLAY = check_setting_str(CFG, 'GUI', 'timezone_display', 'network')
SHOW_TAGS = check_setting_str(CFG, 'GUI', 'show_tags', 'Show List').split(',')
SHOW_TAG_DEFAULT = check_setting_str(CFG, 'GUI', 'show_tag_default',
check_setting_str(CFG, 'GUI', 'default_show_tag', 'Show List'))
SHOWLIST_TAGVIEW = check_setting_str(CFG, 'GUI', 'showlist_tagview', 'standard')
ACTUAL_LOG_DIR = check_setting_str(CFG, 'General', 'log_dir', 'Logs')
# put the log dir inside the data dir, unless an absolute path
LOG_DIR = os.path.normpath(os.path.join(DATA_DIR, ACTUAL_LOG_DIR))
if not helpers.make_dir(LOG_DIR):
logger.error('!!! no log folder, logging to screen only!')
FILE_LOGGING_PRESET = check_setting_str(CFG, 'General', 'file_logging_preset', 'DEBUG')
if bool(check_setting_int(CFG, 'General', 'file_logging_db', 0)):
FILE_LOGGING_PRESET = 'DB'
elif 'DB' == FILE_LOGGING_PRESET:
FILE_LOGGING_PRESET = 'DEBUG'
SOCKET_TIMEOUT = check_setting_int(CFG, 'General', 'socket_timeout', 30)
socket.setdefaulttimeout(SOCKET_TIMEOUT)
WEB_HOST = check_setting_str(CFG, 'General', 'web_host', '0.0.0.0')
WEB_PORT = minimax(check_setting_int(CFG, 'General', 'web_port', 8081), 8081, 21, 65535)
WEB_ROOT = check_setting_str(CFG, 'General', 'web_root', '').rstrip('/')
WEB_IPV6 = bool(check_setting_int(CFG, 'General', 'web_ipv6', 0))
WEB_IPV64 = bool(check_setting_int(CFG, 'General', 'web_ipv64', 0))
WEB_LOG = bool(check_setting_int(CFG, 'General', 'web_log', 0))
ENCRYPTION_VERSION = check_setting_int(CFG, 'General', 'encryption_version', 0)
WEB_USERNAME = check_setting_str(CFG, 'General', 'web_username', '')
WEB_PASSWORD = check_setting_str(CFG, 'General', 'web_password', '')
LAUNCH_BROWSER = bool(check_setting_int(CFG, 'General', 'launch_browser', 1))
CPU_PRESET = check_setting_str(CFG, 'General', 'cpu_preset', 'DISABLED')
ANON_REDIRECT = check_setting_str(CFG, 'General', 'anon_redirect', '')
PROXY_SETTING = check_setting_str(CFG, 'General', 'proxy_setting', '')
sg_helpers.PROXY_SETTING = PROXY_SETTING
sg_helpers.USER_AGENT = USER_AGENT
from . import notifiers
sg_helpers.NOTIFIERS = notifiers
PROXY_INDEXERS = bool(check_setting_int(CFG, 'General', 'proxy_indexers', 1))
# attempt to help prevent users from breaking links by using a bad url
if not ANON_REDIRECT.endswith('?'):
ANON_REDIRECT = ''
UPDATE_SHOWS_ON_START = bool(check_setting_int(CFG, 'General', 'update_shows_on_start', 0))
SHOW_UPDATE_HOUR = check_setting_int(CFG, 'General', 'show_update_hour', 3)
SHOW_UPDATE_HOUR = minimax(SHOW_UPDATE_HOUR, 3, 0, 23)
TRASH_REMOVE_SHOW = bool(check_setting_int(CFG, 'General', 'trash_remove_show', 0))
sg_helpers.TRASH_REMOVE_SHOW = TRASH_REMOVE_SHOW
TRASH_ROTATE_LOGS = bool(check_setting_int(CFG, 'General', 'trash_rotate_logs', 0))
USE_API = bool(check_setting_int(CFG, 'General', 'use_api', 0))
API_KEYS = [k.split(':::') for k in check_setting_str(CFG, 'General', 'api_keys', '').split('|||') if k]
if not API_KEYS:
tmp_api_key = check_setting_str(CFG, 'General', 'api_key', None)
if None is not tmp_api_key:
API_KEYS = [['app name (old key)', tmp_api_key]]
DEBUG = bool(check_setting_int(CFG, 'General', 'debug', 0))
ENABLE_HTTPS = bool(check_setting_int(CFG, 'General', 'enable_https', 0))
HTTPS_CERT = check_setting_str(CFG, 'General', 'https_cert', 'server.crt')
HTTPS_KEY = check_setting_str(CFG, 'General', 'https_key', 'server.key')
HANDLE_REVERSE_PROXY = bool(check_setting_int(CFG, 'General', 'handle_reverse_proxy', 0))
SEND_SECURITY_HEADERS = bool(check_setting_int(CFG, 'General', 'send_security_headers', 1))
ALLOWED_HOSTS = check_setting_str(CFG, 'General', 'allowed_hosts', '')
ALLOW_ANYIP = bool(check_setting_int(CFG, 'General', 'allow_anyip', 1))
ROOT_DIRS = check_setting_str(CFG, 'General', 'root_dirs', '')
if not re.match(r'\d+\|[^|]+(?:\|[^|]+)*', ROOT_DIRS):
ROOT_DIRS = ''
RESULTS_SORTBY = check_setting_str(CFG, 'General', 'results_sortby', '')
QUALITY_DEFAULT = check_setting_int(CFG, 'General', 'quality_default', SD)
STATUS_DEFAULT = check_setting_int(CFG, 'General', 'status_default', SKIPPED)
WANTED_BEGIN_DEFAULT = check_setting_int(CFG, 'General', 'wanted_begin_default', 0)
WANTED_LATEST_DEFAULT = check_setting_int(CFG, 'General', 'wanted_latest_default', 0)
UPDATE_NOTIFY = bool(check_setting_int(CFG, 'General', 'update_notify', None))
if None is UPDATE_NOTIFY:
UPDATE_NOTIFY = check_setting_int(CFG, 'General', 'version_notify', 1) # deprecated 2020.11.21 no config update
UPDATE_AUTO = bool(check_setting_int(CFG, 'General', 'update_auto', None))
if None is UPDATE_AUTO:
UPDATE_AUTO = check_setting_int(CFG, 'General', 'auto_update', 0) # deprecated 2020.11.21 no config update
UPDATE_INTERVAL = max(
MIN_UPDATE_INTERVAL,
check_setting_int(CFG, 'General', 'update_interval', DEFAULT_UPDATE_INTERVAL))
NOTIFY_ON_UPDATE = bool(check_setting_int(CFG, 'General', 'notify_on_update', 1))
UPDATE_PACKAGES_NOTIFY = bool(
check_setting_int(CFG, 'General', 'update_packages_notify', 'win' == sys.platform[0:3]))
UPDATE_PACKAGES_AUTO = bool(check_setting_int(CFG, 'General', 'update_packages_auto', 0))
UPDATE_PACKAGES_MENU = bool(check_setting_int(CFG, 'General', 'update_packages_menu', 0))
UPDATE_PACKAGES_INTERVAL = max(
MIN_UPDATE_PACKAGES_INTERVAL,
check_setting_int(CFG, 'General', 'update_packages_interval', DEFAULT_UPDATE_PACKAGES_INTERVAL))
TVINFO_DEFAULT = check_setting_int(CFG, 'General', 'indexer_default', 0)
if TVINFO_DEFAULT and not TVInfoAPI(TVINFO_DEFAULT).config['active']:
TVINFO_DEFAULT = TVINFO_TVDB
TVINFO_TIMEOUT = check_setting_int(CFG, 'General', 'indexer_timeout', 20)
PAUSE_DEFAULT = bool(check_setting_int(CFG, 'General', 'pause default', 0))
SCENE_DEFAULT = bool(check_setting_int(CFG, 'General', 'scene_default', 0))
FLATTEN_FOLDERS_DEFAULT = bool(check_setting_int(CFG, 'General', 'flatten_folders_default', 0))
ANIME_DEFAULT = bool(check_setting_int(CFG, 'General', 'anime_default', 0))
PROVIDER_ORDER = check_setting_str(CFG, 'General', 'provider_order', '').split()
PROVIDER_HOMES = sg_helpers.ast_eval(check_setting_str(CFG, 'General', 'provider_homes', None), {})
NAMING_PATTERN = check_setting_str(CFG, 'General', 'naming_pattern', 'Season %0S/%SN - S%0SE%0E - %EN')
NAMING_ABD_PATTERN = check_setting_str(CFG, 'General', 'naming_abd_pattern', '%SN - %A.D - %EN')
NAMING_CUSTOM_ABD = bool(check_setting_int(CFG, 'General', 'naming_custom_abd', 0))
NAMING_SPORTS_PATTERN = check_setting_str(CFG, 'General', 'naming_sports_pattern', '%SN - %A-D - %EN')
NAMING_ANIME_PATTERN = check_setting_str(CFG, 'General', 'naming_anime_pattern',
'Season %0S/%SN - S%0SE%0E - %EN')
NAMING_ANIME = check_setting_int(CFG, 'General', 'naming_anime', 3)
NAMING_CUSTOM_SPORTS = bool(check_setting_int(CFG, 'General', 'naming_custom_sports', 0))
NAMING_CUSTOM_ANIME = bool(check_setting_int(CFG, 'General', 'naming_custom_anime', 0))
NAMING_MULTI_EP = check_setting_int(CFG, 'General', 'naming_multi_ep', 1)
NAMING_ANIME_MULTI_EP = check_setting_int(CFG, 'General', 'naming_anime_multi_ep', 1)
NAMING_FORCE_FOLDERS = naming.check_force_season_folders()
NAMING_STRIP_YEAR = bool(check_setting_int(CFG, 'General', 'naming_strip_year', 0))
USE_NZBS = bool(check_setting_int(CFG, 'General', 'use_nzbs', 0))
USE_TORRENTS = bool(check_setting_int(CFG, 'General', 'use_torrents', 0))
NZB_METHOD = check_setting_str(CFG, 'General', 'nzb_method', 'blackhole')
if NZB_METHOD not in ('blackhole', 'sabnzbd', 'nzbget'):
NZB_METHOD = 'blackhole'
TORRENT_METHOD = check_setting_str(CFG, 'General', 'torrent_method', 'blackhole')
if TORRENT_METHOD not in ('blackhole', 'deluge', 'download_station', 'qbittorrent',
'rtorrent', 'transmission', 'utorrent'):
TORRENT_METHOD = 'blackhole'
DOWNLOAD_PROPERS = bool(check_setting_int(CFG, 'General', 'download_propers', 1))
PROPERS_WEBDL_ONEGRP = bool(check_setting_int(CFG, 'General', 'propers_webdl_onegrp', 1))
ALLOW_HIGH_PRIORITY = bool(check_setting_int(CFG, 'General', 'allow_high_priority', 1))
RECENTSEARCH_STARTUP = bool(check_setting_int(CFG, 'General', 'recentsearch_startup', 0))
BACKLOG_NOFULL = bool(check_setting_int(CFG, 'General', 'backlog_nofull', 0))
SKIP_REMOVED_FILES = check_setting_int(CFG, 'General', 'skip_removed_files', 0)
USENET_RETENTION = check_setting_int(CFG, 'General', 'usenet_retention', 500)
MEDIAPROCESS_INTERVAL = check_setting_int(CFG, 'General', 'mediaprocess_interval', DEFAULT_MEDIAPROCESS_INTERVAL)
if MEDIAPROCESS_INTERVAL < MIN_MEDIAPROCESS_INTERVAL:
MEDIAPROCESS_INTERVAL = MIN_MEDIAPROCESS_INTERVAL
RECENTSEARCH_INTERVAL = check_setting_int(CFG, 'General', 'recentsearch_interval', DEFAULT_RECENTSEARCH_INTERVAL)
if RECENTSEARCH_INTERVAL < MIN_RECENTSEARCH_INTERVAL:
RECENTSEARCH_INTERVAL = MIN_RECENTSEARCH_INTERVAL
# special case during dev to migrate backlog_interval to backlog_period
BACKLOG_PERIOD = check_setting_int(CFG, 'General', 'backlog_period',
check_setting_int(CFG, 'General', 'backlog_interval', DEFAULT_BACKLOG_PERIOD))
BACKLOG_PERIOD = minimax(BACKLOG_PERIOD, DEFAULT_BACKLOG_PERIOD, MIN_BACKLOG_PERIOD, MAX_BACKLOG_PERIOD)
BACKLOG_LIMITED_PERIOD = check_setting_int(CFG, 'General', 'backlog_limited_period', 7)
SEARCH_UNAIRED = bool(check_setting_int(CFG, 'General', 'search_unaired', 0))
UNAIRED_RECENT_SEARCH_ONLY = bool(check_setting_int(CFG, 'General', 'unaired_recent_search_only', 1))
FLARESOLVERR_HOST = check_setting_str(CFG, 'General', 'flaresolverr_host', '')
sg_helpers.FLARESOLVERR_HOST = FLARESOLVERR_HOST
NZB_DIR = check_setting_str(CFG, 'Blackhole', 'nzb_dir', '')
TORRENT_DIR = check_setting_str(CFG, 'Blackhole', 'torrent_dir', '')
TV_DOWNLOAD_DIR = check_setting_str(CFG, 'General', 'tv_download_dir', '')
PROCESS_AUTOMATICALLY = bool(check_setting_int(CFG, 'General', 'process_automatically', 0))
UNPACK = bool(check_setting_int(CFG, 'General', 'unpack', 0))
RENAME_EPISODES = bool(check_setting_int(CFG, 'General', 'rename_episodes', 1))
RENAME_TBA_EPISODES = bool(check_setting_int(CFG, 'General', 'rename_tba_episodes', 1))
RENAME_NAME_CHANGED_EPISODES = bool(check_setting_int(CFG, 'General', 'rename_name_changed_episodes', 0))
AIRDATE_EPISODES = bool(check_setting_int(CFG, 'General', 'airdate_episodes', 0))
KEEP_PROCESSED_DIR = bool(check_setting_int(CFG, 'General', 'keep_processed_dir', 1))
PROCESS_METHOD = check_setting_str(CFG, 'General', 'process_method', 'copy' if KEEP_PROCESSED_DIR else 'move')
PROCESS_LAST_DIR = check_setting_str(CFG, 'General', 'process_last_dir', TV_DOWNLOAD_DIR)
PROCESS_LAST_METHOD = check_setting_str(CFG, 'General', 'process_last_method', PROCESS_METHOD)
PROCESS_LAST_CLEANUP = bool(check_setting_int(CFG, 'General', 'process_last_cleanup', 0))
MOVE_ASSOCIATED_FILES = bool(check_setting_int(CFG, 'General', 'move_associated_files', 0))
POSTPONE_IF_SYNC_FILES = bool(check_setting_int(CFG, 'General', 'postpone_if_sync_files', 1))
PROCESS_POSITIVE_LOG = bool(check_setting_int(CFG, 'General', 'process_positive_log', 0))
NFO_RENAME = bool(check_setting_int(CFG, 'General', 'nfo_rename', 1))
CREATE_MISSING_SHOW_DIRS = bool(check_setting_int(CFG, 'General', 'create_missing_show_dirs', 0))
SHOW_DIRS_WITH_DOTS = bool(check_setting_int(CFG, 'General', 'show_dirs_with_dots', 0))
ADD_SHOWS_WO_DIR = bool(check_setting_int(CFG, 'General', 'add_shows_wo_dir', 0))
ADD_SHOWS_METALANG = check_setting_str(CFG, 'General', 'add_shows_metalang', 'en')
REMOVE_FILENAME_CHARS = check_setting_str(CFG, 'General', 'remove_filename_chars', '')
sg_helpers.REMOVE_FILENAME_CHARS = REMOVE_FILENAME_CHARS
IMPORT_DEFAULT_CHECKED_SHOWS = bool(check_setting_int(CFG, 'General', 'import_default_checked_shows', 0))
SAB_USERNAME = check_setting_str(CFG, 'SABnzbd', 'sab_username', '')
SAB_PASSWORD = check_setting_str(CFG, 'SABnzbd', 'sab_password', '')
SAB_APIKEY = check_setting_str(CFG, 'SABnzbd', 'sab_apikey', '')
SAB_CATEGORY = check_setting_str(CFG, 'SABnzbd', 'sab_category', 'tv')
SAB_HOST = check_setting_str(CFG, 'SABnzbd', 'sab_host', '')
# first check using official name case, then with case of legacy
# todo: migrate config, (just not atm due to testing map feature)
NZBGET_USERNAME = (check_setting_str(CFG, 'NZBGet', 'nzbget_username', '')
or check_setting_str(CFG, 'NZBget', 'nzbget_username', 'nzbget'))
NZBGET_PASSWORD = (check_setting_str(CFG, 'NZBGet', 'nzbget_password', '')
or check_setting_str(CFG, 'NZBget', 'nzbget_password', 'tegbzn6789'))
NZBGET_CATEGORY = (check_setting_str(CFG, 'NZBGet', 'nzbget_category', '')
or check_setting_str(CFG, 'NZBget', 'nzbget_category', 'tv'))
NZBGET_HOST = (check_setting_str(CFG, 'NZBGet', 'nzbget_host', '')
or check_setting_str(CFG, 'NZBget', 'nzbget_host', ''))
NZBGET_USE_HTTPS = (bool(check_setting_int(CFG, 'NZBGet', 'nzbget_use_https', 0))
or bool(check_setting_int(CFG, 'NZBget', 'nzbget_use_https', 0)))
NZBGET_PRIORITY = check_setting_int(CFG, 'NZBGet', 'nzbget_priority', None)
if None is NZBGET_PRIORITY:
NZBGET_PRIORITY = check_setting_int(CFG, 'NZBget', 'nzbget_priority', 100)
NZBGET_MAP = check_setting_str(CFG, 'NZBGet', 'nzbget_map', '')
NZBGET_SKIP_PM = bool(check_setting_int(CFG, 'NZBGet', 'nzbget_skip_process_media', 0))
try:
ng_script_file = os.path.join(os.path.dirname(os.path.dirname(__file__)),
'autoProcessTV', 'SickGear-NG', 'SickGear-NG.py')
with io.open(ng_script_file, 'r', encoding='utf8') as ng:
text = ng.read()
NZBGET_SCRIPT_VERSION = re.search(r""".*version: (\d+\.\d+)""", text, flags=re.M).group(1)
except (BaseException, Exception):
NZBGET_SCRIPT_VERSION = None
TORRENT_USERNAME = check_setting_str(CFG, 'TORRENT', 'torrent_username', '')
TORRENT_PASSWORD = check_setting_str(CFG, 'TORRENT', 'torrent_password', '')
TORRENT_HOST = check_setting_str(CFG, 'TORRENT', 'torrent_host', '')
TORRENT_PATH = check_setting_str(CFG, 'TORRENT', 'torrent_path', '')
TORRENT_SEED_TIME = check_setting_int(CFG, 'TORRENT', 'torrent_seed_time', 0)
TORRENT_PAUSED = bool(check_setting_int(CFG, 'TORRENT', 'torrent_paused', 0))
TORRENT_HIGH_BANDWIDTH = bool(check_setting_int(CFG, 'TORRENT', 'torrent_high_bandwidth', 0))
TORRENT_LABEL = check_setting_str(CFG, 'TORRENT', 'torrent_label', '')
TORRENT_LABEL_VAR = check_setting_int(CFG, 'TORRENT', 'torrent_label_var', 1)
TORRENT_VERIFY_CERT = bool(check_setting_int(CFG, 'TORRENT', 'torrent_verify_cert', 0))
USE_EMBY = bool(check_setting_int(CFG, 'Emby', 'use_emby', 0))
EMBY_UPDATE_LIBRARY = bool(check_setting_int(CFG, 'Emby', 'emby_update_library', 0))
EMBY_PARENT_MAPS = check_setting_str(CFG, 'Emby', 'emby_parent_maps', '')
EMBY_HOST = check_setting_str(CFG, 'Emby', 'emby_host', '')
EMBY_APIKEY = check_setting_str(CFG, 'Emby', 'emby_apikey', '')
EMBY_WATCHEDSTATE_SCHEDULED = bool(check_setting_int(CFG, 'Emby', 'emby_watchedstate_scheduled', 0))
EMBY_WATCHEDSTATE_INTERVAL = minimax(check_setting_int(
CFG, 'Emby', 'emby_watchedstate_interval', DEFAULT_WATCHEDSTATE_INTERVAL),
DEFAULT_WATCHEDSTATE_INTERVAL, MIN_WATCHEDSTATE_INTERVAL, MAX_WATCHEDSTATE_INTERVAL)
USE_KODI = bool(check_setting_int(CFG, 'Kodi', 'use_kodi', 0))
KODI_ALWAYS_ON = bool(check_setting_int(CFG, 'Kodi', 'kodi_always_on', 1))
KODI_NOTIFY_ONSNATCH = bool(check_setting_int(CFG, 'Kodi', 'kodi_notify_onsnatch', 0))
KODI_NOTIFY_ONDOWNLOAD = bool(check_setting_int(CFG, 'Kodi', 'kodi_notify_ondownload', 0))
KODI_NOTIFY_ONSUBTITLEDOWNLOAD = bool(check_setting_int(CFG, 'Kodi', 'kodi_notify_onsubtitledownload', 0))
KODI_UPDATE_LIBRARY = bool(check_setting_int(CFG, 'Kodi', 'kodi_update_library', 0))
KODI_UPDATE_FULL = bool(check_setting_int(CFG, 'Kodi', 'kodi_update_full', 0))
KODI_UPDATE_ONLYFIRST = bool(check_setting_int(CFG, 'Kodi', 'kodi_update_onlyfirst', 0))
KODI_PARENT_MAPS = check_setting_str(CFG, 'Kodi', 'kodi_parent_maps', '')
KODI_HOST = check_setting_str(CFG, 'Kodi', 'kodi_host', '')
KODI_USERNAME = check_setting_str(CFG, 'Kodi', 'kodi_username', '')
KODI_PASSWORD = check_setting_str(CFG, 'Kodi', 'kodi_password', '')
USE_XBMC = bool(check_setting_int(CFG, 'XBMC', 'use_xbmc', 0))
XBMC_ALWAYS_ON = bool(check_setting_int(CFG, 'XBMC', 'xbmc_always_on', 1))
XBMC_NOTIFY_ONSNATCH = bool(check_setting_int(CFG, 'XBMC', 'xbmc_notify_onsnatch', 0))
XBMC_NOTIFY_ONDOWNLOAD = bool(check_setting_int(CFG, 'XBMC', 'xbmc_notify_ondownload', 0))
XBMC_NOTIFY_ONSUBTITLEDOWNLOAD = bool(check_setting_int(CFG, 'XBMC', 'xbmc_notify_onsubtitledownload', 0))
XBMC_UPDATE_LIBRARY = bool(check_setting_int(CFG, 'XBMC', 'xbmc_update_library', 0))
XBMC_UPDATE_FULL = bool(check_setting_int(CFG, 'XBMC', 'xbmc_update_full', 0))
XBMC_UPDATE_ONLYFIRST = bool(check_setting_int(CFG, 'XBMC', 'xbmc_update_onlyfirst', 0))
XBMC_HOST = check_setting_str(CFG, 'XBMC', 'xbmc_host', '')
XBMC_USERNAME = check_setting_str(CFG, 'XBMC', 'xbmc_username', '')
XBMC_PASSWORD = check_setting_str(CFG, 'XBMC', 'xbmc_password', '')
USE_PLEX = bool(check_setting_int(CFG, 'Plex', 'use_plex', 0))
PLEX_NOTIFY_ONSNATCH = bool(check_setting_int(CFG, 'Plex', 'plex_notify_onsnatch', 0))
PLEX_NOTIFY_ONDOWNLOAD = bool(check_setting_int(CFG, 'Plex', 'plex_notify_ondownload', 0))
PLEX_NOTIFY_ONSUBTITLEDOWNLOAD = bool(check_setting_int(CFG, 'Plex', 'plex_notify_onsubtitledownload', 0))
PLEX_UPDATE_LIBRARY = bool(check_setting_int(CFG, 'Plex', 'plex_update_library', 0))
PLEX_PARENT_MAPS = check_setting_str(CFG, 'Plex', 'plex_parent_maps', '')
PLEX_SERVER_HOST = check_setting_str(CFG, 'Plex', 'plex_server_host', '')
PLEX_HOST = check_setting_str(CFG, 'Plex', 'plex_host', '')
PLEX_USERNAME = check_setting_str(CFG, 'Plex', 'plex_username', '')
PLEX_PASSWORD = check_setting_str(CFG, 'Plex', 'plex_password', '')
PLEX_WATCHEDSTATE_SCHEDULED = bool(check_setting_int(CFG, 'Plex', 'plex_watchedstate_scheduled', 0))
PLEX_WATCHEDSTATE_INTERVAL = minimax(check_setting_int(
CFG, 'Plex', 'plex_watchedstate_interval', DEFAULT_WATCHEDSTATE_INTERVAL),
DEFAULT_WATCHEDSTATE_INTERVAL, MIN_WATCHEDSTATE_INTERVAL, MAX_WATCHEDSTATE_INTERVAL)
USE_GROWL = bool(check_setting_int(CFG, 'Growl', 'use_growl', 0))
GROWL_NOTIFY_ONSNATCH = bool(check_setting_int(CFG, 'Growl', 'growl_notify_onsnatch', 0))
GROWL_NOTIFY_ONDOWNLOAD = bool(check_setting_int(CFG, 'Growl', 'growl_notify_ondownload', 0))
GROWL_NOTIFY_ONSUBTITLEDOWNLOAD = bool(check_setting_int(CFG, 'Growl', 'growl_notify_onsubtitledownload', 0))
GROWL_HOST = check_setting_str(CFG, 'Growl', 'growl_host', '')
# GROWL_PASSWORD = check_setting_str(CFG, 'Growl', 'growl_password', '')
USE_PROWL = bool(check_setting_int(CFG, 'Prowl', 'use_prowl', 0))
PROWL_NOTIFY_ONSNATCH = bool(check_setting_int(CFG, 'Prowl', 'prowl_notify_onsnatch', 0))
PROWL_NOTIFY_ONDOWNLOAD = bool(check_setting_int(CFG, 'Prowl', 'prowl_notify_ondownload', 0))
PROWL_NOTIFY_ONSUBTITLEDOWNLOAD = bool(check_setting_int(CFG, 'Prowl', 'prowl_notify_onsubtitledownload', 0))
PROWL_API = check_setting_str(CFG, 'Prowl', 'prowl_api', '')
PROWL_PRIORITY = check_setting_str(CFG, 'Prowl', 'prowl_priority', '0')
USE_BOXCAR2 = bool(check_setting_int(CFG, 'Boxcar2', 'use_boxcar2', 0))
BOXCAR2_NOTIFY_ONSNATCH = bool(check_setting_int(CFG, 'Boxcar2', 'boxcar2_notify_onsnatch', 0))
BOXCAR2_NOTIFY_ONDOWNLOAD = bool(check_setting_int(CFG, 'Boxcar2', 'boxcar2_notify_ondownload', 0))
BOXCAR2_NOTIFY_ONSUBTITLEDOWNLOAD = bool(
check_setting_int(CFG, 'Boxcar2', 'boxcar2_notify_onsubtitledownload', 0))
BOXCAR2_ACCESSTOKEN = check_setting_str(CFG, 'Boxcar2', 'boxcar2_accesstoken', '')
BOXCAR2_SOUND = check_setting_str(CFG, 'Boxcar2', 'boxcar2_sound', 'default')
USE_PUSHOVER = bool(check_setting_int(CFG, 'Pushover', 'use_pushover', 0))
PUSHOVER_NOTIFY_ONSNATCH = bool(check_setting_int(CFG, 'Pushover', 'pushover_notify_onsnatch', 0))
PUSHOVER_NOTIFY_ONDOWNLOAD = bool(check_setting_int(CFG, 'Pushover', 'pushover_notify_ondownload', 0))
PUSHOVER_NOTIFY_ONSUBTITLEDOWNLOAD = bool(
check_setting_int(CFG, 'Pushover', 'pushover_notify_onsubtitledownload', 0))
PUSHOVER_USERKEY = check_setting_str(CFG, 'Pushover', 'pushover_userkey', '')
PUSHOVER_APIKEY = check_setting_str(CFG, 'Pushover', 'pushover_apikey', '')
PUSHOVER_PRIORITY = check_setting_str(CFG, 'Pushover', 'pushover_priority', '0')
PUSHOVER_DEVICE = check_setting_str(CFG, 'Pushover', 'pushover_device', 'all')
PUSHOVER_SOUND = check_setting_str(CFG, 'Pushover', 'pushover_sound', 'pushover')
USE_LIBNOTIFY = bool(check_setting_int(CFG, 'Libnotify', 'use_libnotify', 0))
LIBNOTIFY_NOTIFY_ONSNATCH = bool(check_setting_int(CFG, 'Libnotify', 'libnotify_notify_onsnatch', 0))
LIBNOTIFY_NOTIFY_ONDOWNLOAD = bool(check_setting_int(CFG, 'Libnotify', 'libnotify_notify_ondownload', 0))
LIBNOTIFY_NOTIFY_ONSUBTITLEDOWNLOAD = bool(
check_setting_int(CFG, 'Libnotify', 'libnotify_notify_onsubtitledownload', 0))
USE_NMJ = bool(check_setting_int(CFG, 'NMJ', 'use_nmj', 0))
NMJ_HOST = check_setting_str(CFG, 'NMJ', 'nmj_host', '')
NMJ_DATABASE = check_setting_str(CFG, 'NMJ', 'nmj_database', '')
NMJ_MOUNT = check_setting_str(CFG, 'NMJ', 'nmj_mount', '')
USE_NMJv2 = bool(check_setting_int(CFG, 'NMJv2', 'use_nmjv2', 0))
NMJv2_HOST = check_setting_str(CFG, 'NMJv2', 'nmjv2_host', '')
NMJv2_DATABASE = check_setting_str(CFG, 'NMJv2', 'nmjv2_database', '')
NMJv2_DBLOC = check_setting_str(CFG, 'NMJv2', 'nmjv2_dbloc', '')
USE_SYNOINDEX = bool(check_setting_int(CFG, 'Synology', 'use_synoindex', 0))
USE_SYNOLOGYNOTIFIER = bool(check_setting_int(CFG, 'SynologyNotifier', 'use_synologynotifier', 0))
SYNOLOGYNOTIFIER_NOTIFY_ONSNATCH = bool(
check_setting_int(CFG, 'SynologyNotifier', 'synologynotifier_notify_onsnatch', 0))
SYNOLOGYNOTIFIER_NOTIFY_ONDOWNLOAD = bool(
check_setting_int(CFG, 'SynologyNotifier', 'synologynotifier_notify_ondownload', 0))
SYNOLOGYNOTIFIER_NOTIFY_ONSUBTITLEDOWNLOAD = bool(
check_setting_int(CFG, 'SynologyNotifier', 'synologynotifier_notify_onsubtitledownload', 0))
USE_TRAKT = bool(check_setting_int(CFG, 'Trakt', 'use_trakt', 0))
TRAKT_REMOVE_WATCHLIST = bool(check_setting_int(CFG, 'Trakt', 'trakt_remove_watchlist', 0))
TRAKT_REMOVE_SERIESLIST = bool(check_setting_int(CFG, 'Trakt', 'trakt_remove_serieslist', 0))
TRAKT_USE_WATCHLIST = bool(check_setting_int(CFG, 'Trakt', 'trakt_use_watchlist', 0))
TRAKT_METHOD_ADD = check_setting_int(CFG, 'Trakt', 'trakt_method_add', 0)
TRAKT_START_PAUSED = bool(check_setting_int(CFG, 'Trakt', 'trakt_start_paused', 0))
TRAKT_SYNC = bool(check_setting_int(CFG, 'Trakt', 'trakt_sync', 0))
TRAKT_DEFAULT_INDEXER = check_setting_int(CFG, 'Trakt', 'trakt_default_indexer', 1)
TRAKT_UPDATE_COLLECTION = trakt_helpers.read_config_string(
check_setting_str(CFG, 'Trakt', 'trakt_update_collection', ''))
TRAKT_ACCOUNTS = TraktAPI.read_config_string(check_setting_str(CFG, 'Trakt', 'trakt_accounts', ''))
TRAKT_MRU = check_setting_str(CFG, 'Trakt', 'trakt_mru', '')
MC_MRU = check_setting_str(CFG, 'Metacritic', 'mc_mru', '')
Add menu Shows/"TMDB Cards". Add top rated, popular, trending today, trending this week, to TMDB cards. Change Shows/Add show... Trakt and IMDb card descriptions to be dynamic. Add network data to trakt cards. Add fallback for show cast when no suitable items are found in tvdb_api. Change refactor for trakt lib update. Change sanitise api response dates for cards (an invalid trakt date caused a UI glitch). Fix issue where trakt can return no tvdb id causing a card to not display. Change view-show TVDb genre links to use anon link setting. Change remove displayShow.tmpl code for '|' sep as it is a fixed list string at data source. Change add TVINFO_FANSITE placeholder icon. Change refactor api sg.`CMD_SickGearShowsBrowseTrakt`. --- Refactor date handling to make it's usage consistent from indexerapi Split when_past out to to started_past and return_past for UI. Fix trakt returning dates. Change bring properly into use, the proper new season returning date. Change remove PY2 unused import statements. --- Fix issue with Trakt cards where an incorrect cache image obscures the default card placeholder image. Simplify airtime for cards. Remove nonsense TMDB api overview text. Rearrange cards order on top menu. --- Remove unused vars and simplify regex use cases. Fix tv cards issue with Trakt and Tvmaze where show_info does not carry a first episode_info. Instantiate with TVInfoEpisode() instead of None, so that expected properties exist without a need for Nonetype tests. Change simplify `overview` and `airtime` use after lib output type is made trustable. Change cards view to not allow items with no seriesname.
2023-03-09 02:13:52 +00:00
NE_MRU = check_setting_str(CFG, 'NextEpisode', 'ne_mru', '')
TMDB_MRU = check_setting_str(CFG, 'TMDB', 'tmdb_mru', '')
TVC_MRU = check_setting_str(CFG, 'TVCalendar', 'tvc_mru', '')
TVM_MRU = check_setting_str(CFG, 'TVmaze', 'tvm_mru', '')
USE_PYTIVO = bool(check_setting_int(CFG, 'pyTivo', 'use_pytivo', 0))
PYTIVO_HOST = check_setting_str(CFG, 'pyTivo', 'pytivo_host', '')
PYTIVO_SHARE_NAME = check_setting_str(CFG, 'pyTivo', 'pytivo_share_name', '')
PYTIVO_TIVO_NAME = check_setting_str(CFG, 'pyTivo', 'pytivo_tivo_name', '')
USE_PUSHALOT = bool(check_setting_int(CFG, 'Pushalot', 'use_pushalot', 0))
PUSHALOT_NOTIFY_ONSNATCH = bool(check_setting_int(CFG, 'Pushalot', 'pushalot_notify_onsnatch', 0))
PUSHALOT_NOTIFY_ONDOWNLOAD = bool(check_setting_int(CFG, 'Pushalot', 'pushalot_notify_ondownload', 0))
PUSHALOT_NOTIFY_ONSUBTITLEDOWNLOAD = bool(
check_setting_int(CFG, 'Pushalot', 'pushalot_notify_onsubtitledownload', 0))
PUSHALOT_AUTHORIZATIONTOKEN = check_setting_str(CFG, 'Pushalot', 'pushalot_authorizationtoken', '')
USE_PUSHBULLET = bool(check_setting_int(CFG, 'Pushbullet', 'use_pushbullet', 0))
PUSHBULLET_NOTIFY_ONSNATCH = bool(check_setting_int(CFG, 'Pushbullet', 'pushbullet_notify_onsnatch', 0))
PUSHBULLET_NOTIFY_ONDOWNLOAD = bool(check_setting_int(CFG, 'Pushbullet', 'pushbullet_notify_ondownload', 0))
PUSHBULLET_NOTIFY_ONSUBTITLEDOWNLOAD = bool(
check_setting_int(CFG, 'Pushbullet', 'pushbullet_notify_onsubtitledownload', 0))
PUSHBULLET_ACCESS_TOKEN = check_setting_str(CFG, 'Pushbullet', 'pushbullet_access_token', '')
PUSHBULLET_DEVICE_IDEN = check_setting_str(CFG, 'Pushbullet', 'pushbullet_device_iden', '')
USE_SLACK = bool(check_setting_int(CFG, 'Slack', 'use_slack', 0))
SLACK_NOTIFY_ONSNATCH = bool(check_setting_int(CFG, 'Slack', 'slack_notify_onsnatch', 0))
SLACK_NOTIFY_ONDOWNLOAD = bool(check_setting_int(CFG, 'Slack', 'slack_notify_ondownload', 0))
SLACK_NOTIFY_ONSUBTITLEDOWNLOAD = bool(check_setting_int(CFG, 'Slack', 'slack_notify_onsubtitledownload', 0))
SLACK_CHANNEL = check_setting_str(CFG, 'Slack', 'slack_channel', '')
SLACK_AS_AUTHED = bool(check_setting_int(CFG, 'Slack', 'slack_as_authed', 0))
SLACK_BOT_NAME = check_setting_str(CFG, 'Slack', 'slack_bot_name', '')
SLACK_ICON_URL = check_setting_str(CFG, 'Slack', 'slack_icon_url', '')
SLACK_ACCESS_TOKEN = check_setting_str(CFG, 'Slack', 'slack_access_token', '')
USE_DISCORD = bool(check_setting_int(CFG, 'Discord', 'use_discord', 0))
DISCORD_NOTIFY_ONSNATCH = bool(check_setting_int(CFG, 'Discord', 'discord_notify_onsnatch', 0))
DISCORD_NOTIFY_ONDOWNLOAD = bool(check_setting_int(CFG, 'Discord', 'discord_notify_ondownload', 0))
DISCORD_NOTIFY_ONSUBTITLEDOWNLOAD = bool(
check_setting_int(CFG, 'Discord', 'discord_notify_onsubtitledownload', 0))
DISCORD_AS_AUTHED = bool(check_setting_int(CFG, 'Discord', 'discord_as_authed', 0))
DISCORD_USERNAME = check_setting_str(CFG, 'Discord', 'discord_username', '')
DISCORD_ICON_URL = check_setting_str(CFG, 'Discord', 'discord_icon_url', '')
DISCORD_AS_TTS = bool(check_setting_str(CFG, 'Discord', 'discord_as_tts', 0))
DISCORD_ACCESS_TOKEN = check_setting_str(CFG, 'Discord', 'discord_access_token', '')
USE_GITTER = bool(check_setting_int(CFG, 'Gitter', 'use_gitter', 0))
GITTER_NOTIFY_ONSNATCH = bool(check_setting_int(CFG, 'Gitter', 'gitter_notify_onsnatch', 0))
GITTER_NOTIFY_ONDOWNLOAD = bool(check_setting_int(CFG, 'Gitter', 'gitter_notify_ondownload', 0))
GITTER_NOTIFY_ONSUBTITLEDOWNLOAD = bool(check_setting_int(CFG, 'Gitter', 'gitter_notify_onsubtitledownload', 0))
GITTER_ROOM = check_setting_str(CFG, 'Gitter', 'gitter_room', '')
GITTER_ACCESS_TOKEN = check_setting_str(CFG, 'Gitter', 'gitter_access_token', '')
USE_TELEGRAM = bool(check_setting_int(CFG, 'Telegram', 'use_telegram', 0))
TELEGRAM_NOTIFY_ONSNATCH = bool(check_setting_int(CFG, 'Telegram', 'telegram_notify_onsnatch', 0))
TELEGRAM_NOTIFY_ONDOWNLOAD = bool(check_setting_int(CFG, 'Telegram', 'telegram_notify_ondownload', 0))
TELEGRAM_NOTIFY_ONSUBTITLEDOWNLOAD = bool(check_setting_int(
CFG, 'Telegram', 'telegram_notify_onsubtitledownload', 0))
TELEGRAM_SEND_IMAGE = bool(check_setting_int(CFG, 'Telegram', 'telegram_send_image', 1))
TELEGRAM_QUIET = bool(check_setting_int(CFG, 'Telegram', 'telegram_quiet', 0))
TELEGRAM_ACCESS_TOKEN = check_setting_str(CFG, 'Telegram', 'telegram_access_token', '')
TELEGRAM_CHATID = check_setting_str(CFG, 'Telegram', 'telegram_chatid', '')
USE_EMAIL = bool(check_setting_int(CFG, 'Email', 'use_email', 0))
EMAIL_OLD_SUBJECTS = bool(check_setting_int(CFG, 'Email', 'email_old_subjects',
None is not EMAIL_HOST and any(EMAIL_HOST)))
EMAIL_NOTIFY_ONSNATCH = bool(check_setting_int(CFG, 'Email', 'email_notify_onsnatch', 0))
EMAIL_NOTIFY_ONDOWNLOAD = bool(check_setting_int(CFG, 'Email', 'email_notify_ondownload', 0))
EMAIL_NOTIFY_ONSUBTITLEDOWNLOAD = bool(check_setting_int(CFG, 'Email', 'email_notify_onsubtitledownload', 0))
EMAIL_HOST = check_setting_str(CFG, 'Email', 'email_host', '')
EMAIL_PORT = check_setting_int(CFG, 'Email', 'email_port', 25)
EMAIL_TLS = bool(check_setting_int(CFG, 'Email', 'email_tls', 0))
EMAIL_USER = check_setting_str(CFG, 'Email', 'email_user', '')
EMAIL_PASSWORD = check_setting_str(CFG, 'Email', 'email_password', '')
EMAIL_FROM = check_setting_str(CFG, 'Email', 'email_from', '')
EMAIL_LIST = check_setting_str(CFG, 'Email', 'email_list', '')
USE_SUBTITLES = bool(check_setting_int(CFG, 'Subtitles', 'use_subtitles', 0))
SUBTITLES_LANGUAGES = check_setting_str(CFG, 'Subtitles', 'subtitles_languages', '').split(',')
if SUBTITLES_LANGUAGES[0] == '':
SUBTITLES_LANGUAGES = []
SUBTITLES_DIR = check_setting_str(CFG, 'Subtitles', 'subtitles_dir', '')
SUBTITLES_SERVICES_LIST = check_setting_str(CFG, 'Subtitles', 'SUBTITLES_SERVICES_LIST', '').split(',')
SUBTITLES_SERVICES_ENABLED = [int(x) for x in
check_setting_str(CFG, 'Subtitles', 'SUBTITLES_SERVICES_ENABLED', '').split('|')
if x]
SUBTITLES_SERVICES_AUTH = [k.split(':::') for k in
check_setting_str(CFG, 'Subtitles', 'subtitles_services_auth', ':::').split('|||')
if k]
try:
# unlikely to happen, but did happen once, so added here as defensive
dct_cfg = sg_helpers.ast_eval(check_setting_str(CFG, 'Subtitles', 'subtitles_services_auth', ':::'), {})
SUBTITLES_SERVICES_AUTH = [[dct_cfg['os_user'], dct_cfg['os_pass']]]
except (BaseException, Exception):
pass
SUBTITLES_DEFAULT = bool(check_setting_int(CFG, 'Subtitles', 'subtitles_default', 0))
SUBTITLES_HISTORY = bool(check_setting_int(CFG, 'Subtitles', 'subtitles_history', 0))
SUBTITLES_FINDER_INTERVAL = check_setting_int(CFG, 'Subtitles', 'subtitles_finder_interval', 1)
SUBTITLES_OS_HASH = bool(check_setting_int(CFG, 'Subtitles', 'subtitles_os_hash', 1))
USE_FAILED_DOWNLOADS = bool(check_setting_int(CFG, 'FailedDownloads', 'use_failed_downloads', 0))
DELETE_FAILED = bool(check_setting_int(CFG, 'FailedDownloads', 'delete_failed', 0))
GIT_PATH = check_setting_str(CFG, 'General', 'git_path', '')
IGNORE_WORDS, IGNORE_WORDS_REGEX = helpers.split_word_str(
check_setting_str(CFG, 'General', 'ignore_words', helpers.generate_word_str(IGNORE_WORDS, IGNORE_WORDS_REGEX)))
REQUIRE_WORDS, REQUIRE_WORDS_REGEX = helpers.split_word_str(
check_setting_str(CFG, 'General', 'require_words',
helpers.generate_word_str(REQUIRE_WORDS, REQUIRE_WORDS_REGEX)))
CALENDAR_UNPROTECTED = bool(check_setting_int(CFG, 'General', 'calendar_unprotected', 0))
EXTRA_SCRIPTS = [x.strip() for x in check_setting_str(CFG, 'General', 'extra_scripts', '').split('|') if
x.strip()]
SG_EXTRA_SCRIPTS = [x.strip() for x in check_setting_str(CFG, 'General', 'sg_extra_scripts', '').split('|') if
x.strip()]
USE_ANIDB = bool(check_setting_int(CFG, 'ANIDB', 'use_anidb', 0))
ANIDB_USERNAME = check_setting_str(CFG, 'ANIDB', 'anidb_username', '')
ANIDB_PASSWORD = check_setting_str(CFG, 'ANIDB', 'anidb_password', '')
ANIDB_USE_MYLIST = bool(check_setting_int(CFG, 'ANIDB', 'anidb_use_mylist', 0))
ANIME_TREAT_AS_HDTV = bool(check_setting_int(CFG, 'ANIME', 'anime_treat_as_hdtv', 0))
METADATA_XBMC = check_setting_str(CFG, 'General', 'metadata_xbmc', '0|0|0|0|0|0|0|0|0|0')
METADATA_XBMC_12PLUS = check_setting_str(CFG, 'General', 'metadata_xbmc_12plus', '0|0|0|0|0|0|0|0|0|0')
METADATA_MEDIABROWSER = check_setting_str(CFG, 'General', 'metadata_mediabrowser', '0|0|0|0|0|0|0|0|0|0')
METADATA_PS3 = check_setting_str(CFG, 'General', 'metadata_ps3', '0|0|0|0|0|0|0|0|0|0')
METADATA_WDTV = check_setting_str(CFG, 'General', 'metadata_wdtv', '0|0|0|0|0|0|0|0|0|0')
METADATA_TIVO = check_setting_str(CFG, 'General', 'metadata_tivo', '0|0|0|0|0|0|0|0|0|0')
METADATA_MEDE8ER = check_setting_str(CFG, 'General', 'metadata_mede8er', '0|0|0|0|0|0|0|0|0|0')
METADATA_KODI = check_setting_str(CFG, 'General', 'metadata_kodi', '0|0|0|0|0|0|0|0|0|0')
HOME_LAYOUT = check_setting_str(CFG, 'GUI', 'home_layout', 'poster')
FOOTER_TIME_LAYOUT = check_setting_int(CFG, 'GUI', 'footer_time_layout', 0)
POSTER_SORTBY = check_setting_str(CFG, 'GUI', 'poster_sortby', 'name')
POSTER_SORTDIR = check_setting_int(CFG, 'GUI', 'poster_sortdir', 1)
DISPLAY_SHOW_GLIDE = sg_helpers.ast_eval(check_setting_str(CFG, 'GUI', 'display_show_glide', None), {})
DISPLAY_SHOW_GLIDE_SLIDETIME = check_setting_int(CFG, 'GUI', 'display_show_glide_slidetime', 3000)
DISPLAY_SHOW_VIEWMODE = check_setting_int(CFG, 'GUI', 'display_show_viewmode', 2)
DISPLAY_SHOW_BACKGROUND = bool(check_setting_int(CFG, 'GUI', 'display_show_background', 1))
DISPLAY_SHOW_BACKGROUND_TRANSLUCENT = bool(check_setting_int(
CFG, 'GUI', 'display_show_background_translucent', 1))
DISPLAY_SHOW_VIEWART = check_setting_int(CFG, 'GUI', 'display_show_viewart', 0)
DISPLAY_SHOW_MINIMUM = bool(check_setting_int(CFG, 'GUI', 'display_show_minimum', 1))
DISPLAY_SHOW_SPECIALS = bool(check_setting_int(CFG, 'GUI', 'display_show_specials', 0))
EPISODE_VIEW_VIEWMODE = check_setting_int(CFG, 'GUI', 'episode_view_viewmode', 2)
EPISODE_VIEW_BACKGROUND = bool(check_setting_int(CFG, 'GUI', 'episode_view_background', 1))
EPISODE_VIEW_BACKGROUND_TRANSLUCENT = bool(check_setting_int(
CFG, 'GUI', 'episode_view_background_translucent', 1))
EPISODE_VIEW_LAYOUT = check_setting_str(CFG, 'GUI', 'episode_view_layout', 'daybyday')
EPISODE_VIEW_SORT = check_setting_str(CFG, 'GUI', 'episode_view_sort', 'time')
EPISODE_VIEW_DISPLAY_PAUSED = check_setting_int(CFG, 'GUI', 'episode_view_display_paused', 1)
EPISODE_VIEW_POSTERS = bool(check_setting_int(CFG, 'GUI', 'episode_view_posters', 1))
EPISODE_VIEW_MISSED_RANGE = check_setting_int(CFG, 'GUI', 'episode_view_missed_range', 7)
HISTORY_LAYOUT = check_setting_str(CFG, 'GUI', 'history_layout', 'detailed')
BROWSELIST_HIDDEN = list(map(
lambda y: TVidProdid.glue in y and y or '%s%s%s' % (
(TVINFO_TVDB, TVINFO_IMDB)[bool(helpers.parse_imdb_id(y))], TVidProdid.glue, y),
[x.strip() for x in check_setting_str(CFG, 'GUI', 'browselist_hidden', '').split('|~|') if x.strip()]))
BROWSELIST_MRU = sg_helpers.ast_eval(check_setting_str(CFG, 'GUI', 'browselist_prefs', None), {})
BACKUP_DB_PATH = check_setting_str(CFG, 'Backup', 'backup_db_path', '')
BACKUP_DB_ONEDAY = bool(check_setting_int(CFG, 'Backup', 'backup_db_oneday', 0))
BACKUP_DB_MAX_COUNT = minimax(check_setting_int(CFG, 'Backup', 'backup_db_max_count', BACKUP_DB_DEFAULT_COUNT),
BACKUP_DB_DEFAULT_COUNT, 0, 90)
UPDATES_TODO = sg_helpers.ast_eval(check_setting_str(CFG, 'Updates', 'updates_todo', None), {})
sg_helpers.db = db
sg_helpers.DOMAIN_FAILURES.load_from_db()
# initialize NZB and TORRENT providers
provider_list = providers.provider_modules()
NEWZNAB_DATA = check_setting_str(CFG, 'Newznab', 'newznab_data', '')
newznab_providers = providers.newznab_source_list(NEWZNAB_DATA)
torrentrss_data = check_setting_str(CFG, 'TorrentRss', 'torrentrss_data', '')
torrent_rss_providers = providers.torrent_rss_source_list(torrentrss_data)
# dynamically load provider settings
for torrent_prov in [curProvider for curProvider in providers.sorted_sources()
if GenericProvider.TORRENT == curProvider.providerType]:
prov_id = torrent_prov.get_id()
prov_id_uc = torrent_prov.get_id().upper()
torrent_prov.enabled = bool(check_setting_int(CFG, prov_id_uc, prov_id, False))
# check str with a def of list, don't add to block settings
if getattr(torrent_prov, 'url_edit', None):
torrent_prov.url_home = check_setting_str(CFG, prov_id_uc, prov_id + '_url_home', [])
# check int with a default of str, don't add to block settings
attr = 'seed_time'
if hasattr(torrent_prov, attr):
torrent_prov.seed_time = check_setting_int(CFG, prov_id_uc, '%s_%s' % (prov_id, attr), '')
# custom cond, don't add to block settings
attr = 'enable_recentsearch'
if hasattr(torrent_prov, attr):
torrent_prov.enable_recentsearch = bool(check_setting_int(
CFG, prov_id_uc, '%s_%s' % (prov_id, attr), True)) or not getattr(torrent_prov, 'supports_backlog')
# check str with a default of list, don't add to block settings
if hasattr(torrent_prov, 'filter'):
torrent_prov.filter = check_setting_str(CFG, prov_id_uc, prov_id + '_filter', [])
for (attr, default) in [
('enable_backlog', True), ('enable_scheduled_backlog', True),
('api_key', ''), ('hash', ''), ('digest', ''),
('username', ''), ('uid', ''), ('password', ''), ('passkey', ''),
('options', ''),
('_seed_ratio', ''), ('minseed', 0), ('minleech', 0),
('scene_only', False), ('scene_or_contain', ''), ('scene_loose', False), ('scene_loose_active', False),
('scene_rej_nuked', False), ('scene_nuked_active', False),
('freeleech', False), ('confirmed', False), ('reject_m2ts', False), ('use_after_get_data', True),
('search_mode', 'eponly'), ('search_fallback', False)
]:
if hasattr(torrent_prov, attr):
attr_check = '%s_%s' % (prov_id, attr.strip('_'))
if isinstance(default, bool):
setattr(torrent_prov, attr, bool(check_setting_int(CFG, prov_id_uc, attr_check, default)))
elif isinstance(default, string_types):
setattr(torrent_prov, attr, check_setting_str(CFG, prov_id_uc, attr_check, default))
elif isinstance(default, int):
setattr(torrent_prov, attr, check_setting_int(CFG, prov_id_uc, attr_check, default))
for nzb_prov in [curProvider for curProvider in providers.sorted_sources()
if GenericProvider.NZB == curProvider.providerType]:
prov_id = nzb_prov.get_id()
prov_id_uc = nzb_prov.get_id().upper()
nzb_prov.enabled = bool(check_setting_int(CFG, prov_id_uc, prov_id, False))
attr = 'enable_recentsearch'
if hasattr(nzb_prov, attr):
nzb_prov.enable_recentsearch = bool(check_setting_int(
CFG, prov_id_uc, '%s_%s' % (prov_id, attr), True)) or not getattr(nzb_prov, 'supports_backlog')
for (attr, default) in [
('enable_backlog', True), ('enable_scheduled_backlog', True),
('api_key', ''), ('digest', ''), ('username', ''),
('scene_only', False), ('scene_or_contain', ''), ('scene_loose', False), ('scene_loose_active', False),
('scene_rej_nuked', False), ('scene_nuked_active', False),
('search_mode', 'eponly'), ('search_fallback', False), ('server_type', NewznabConstants.SERVER_DEFAULT)
]:
if hasattr(nzb_prov, attr):
attr_check = '%s_%s' % (prov_id, attr.strip('_'))
if isinstance(default, bool):
setattr(nzb_prov, attr, bool(check_setting_int(CFG, prov_id_uc, attr_check, default)))
elif isinstance(default, string_types):
setattr(nzb_prov, attr, check_setting_str(CFG, prov_id_uc, attr_check, default))
elif isinstance(default, int):
setattr(nzb_prov, attr, check_setting_int(CFG, prov_id_uc, attr_check, default))
for cur_provider in filter(lambda p: abs(zlib.crc32(decode_bytes(p.name))) + 40000400 in (
1449593765, 1597250020, 1524942228, 160758496, 2925374331
) or (p.url and abs(zlib.crc32(decode_bytes(re.sub(r'[./]', '', p.url[-10:])))) + 40000400 in (
2417143804,)), providers.sorted_sources()):
header = {'User-Agent': get_ua()}
if hasattr(cur_provider, 'nn'):
cur_provider.nn = False
cur_provider.ui_string()
# noinspection PyProtectedMember
header = callable(getattr(cur_provider, '_init_api', False)) and False is cur_provider._init_api() \
and header or {}
cur_provider.headers.update(header)
update_config |= cur_provider.should_save_config()
# current commit hash
CUR_COMMIT_HASH = check_setting_str(CFG, 'General', 'cur_commit_hash', '')
# current commit branch
CUR_COMMIT_BRANCH = check_setting_str(CFG, 'General', 'cur_commit_branch', '')
if not CUR_COMMIT_HASH or '00000000000000000000000000000000000' == CUR_COMMIT_HASH:
tmp_v = version_checker.SoftwareUpdater()
if 'git' == tmp_v.install_type:
# noinspection PyProtectedMember
tmp_v.updater._find_installed_version()
if not CUR_COMMIT_HASH:
# in case git fails for some reason, set dummy hash to enable update for next start
CUR_COMMIT_HASH = '00000000000000000000000000000000000'
if not CUR_COMMIT_BRANCH:
# noinspection PyProtectedMember
tmp_branch = tmp_v.updater._find_installed_branch()
if tmp_branch:
CUR_COMMIT_BRANCH = tmp_branch
update_config = True
EXT_UPDATES = (35 > len(CUR_COMMIT_HASH) or not bool(re.match('^[a-z0-9]+$', CUR_COMMIT_HASH))) and \
('docker/other', 'snap')['snap' in CUR_COMMIT_HASH]
if not os.path.isfile(CONFIG_FILE):
logger.debug(f'Unable to find \'{CONFIG_FILE}\', all settings will be default!')
update_config = True
# Get expected config version
CONFIG_VERSION = max(ConfigMigrator(CFG).migration_names)
# we have fully loaded all config settings into vars
CONFIG_LOADED = True
if update_config:
_save_config(force=True)
# start up all the threads
old_log = os.path.join(LOG_DIR, 'sickgear.log')
if os.path.isfile(old_log):
try:
os.rename(old_log, os.path.join(LOG_DIR, logger.sb_log_instance.log_file))
except (BaseException, Exception):
pass
logger.sb_log_instance.init_logging(console_logging=console_logging)
showList = []
showDict = {}
# dict of switched shows for web redirects
switched_shows = {}
def init_stage_2():
# Misc
global __INITIALIZED__, MEMCACHE, MEMCACHE_FLAG_IMAGES, RECENTSEARCH_STARTUP
# Schedulers
# global trakt_checker_scheduler
global update_software_scheduler, update_packages_scheduler, \
update_show_scheduler, update_release_mappings_scheduler, \
search_backlog_scheduler, search_propers_scheduler, \
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, config_events
# Gen Config/Misc
global SHOW_UPDATE_HOUR, UPDATE_INTERVAL, UPDATE_PACKAGES_INTERVAL
# Search Settings/Episode
global RECENTSEARCH_INTERVAL
# Subtitles
global USE_SUBTITLES, SUBTITLES_FINDER_INTERVAL
# Media Process/Post-Processing
global PROCESS_AUTOMATICALLY, MEDIAPROCESS_INTERVAL
# Media Process/Metadata
global metadata_provider_dict, METADATA_KODI, METADATA_MEDE8ER, METADATA_MEDIABROWSER, \
METADATA_PS3, METADATA_TIVO, METADATA_WDTV, METADATA_XBMC, METADATA_XBMC_12PLUS
# Notification Settings/HT and NAS
global EMBY_WATCHEDSTATE_INTERVAL, PLEX_WATCHEDSTATE_INTERVAL
# initialize main database
my_db = db.DBConnection()
2023-02-24 11:46:07 +00:00
db.migration_code(my_db)
# initialize the cache database
my_db = db.DBConnection('cache.db')
2023-02-24 11:46:07 +00:00
db.upgrade_database(my_db, cache_db.InitialSchema)
# initialize the failed downloads database
my_db = db.DBConnection('failed.db')
2023-02-24 11:46:07 +00:00
db.upgrade_database(my_db, failed_db.InitialSchema)
# fix up any db problems
my_db = db.DBConnection()
2023-02-24 11:46:07 +00:00
db.sanity_check_db(my_db, mainDB.MainSanityCheck)
# initialize metadata_providers
metadata_provider_dict = metadata.get_metadata_generator_dict()
for cur_metadata_tuple in [(METADATA_KODI, metadata.kodi),
(METADATA_MEDE8ER, metadata.mede8er),
(METADATA_MEDIABROWSER, metadata.mediabrowser),
(METADATA_PS3, metadata.ps3),
(METADATA_TIVO, metadata.tivo),
(METADATA_WDTV, metadata.wdtv),
(METADATA_XBMC, metadata.xbmc),
(METADATA_XBMC_12PLUS, metadata.xbmc_12plus),
]:
(cur_metadata_config, cur_metadata_class) = cur_metadata_tuple
tmp_provider = cur_metadata_class.metadata_class()
tmp_provider.set_config(cur_metadata_config)
metadata_provider_dict[tmp_provider.name] = tmp_provider
# initialize schedulers
# /
# queues must be first
show_queue_scheduler = scheduler.Scheduler(
show_queue.ShowQueue(),
cycle_time=datetime.timedelta(seconds=3),
thread_name='SHOWQUEUE')
search_queue_scheduler = scheduler.Scheduler(
search_queue.SearchQueue(),
cycle_time=datetime.timedelta(seconds=3),
thread_name='SEARCHQUEUE')
people_queue_scheduler = scheduler.Scheduler(
people_queue.PeopleQueue(),
cycle_time=datetime.timedelta(seconds=3),
thread_name='PEOPLEQUEUE'
)
watched_state_queue_scheduler = scheduler.Scheduler(
watchedstate_queue.WatchedStateQueue(),
cycle_time=datetime.timedelta(seconds=3),
thread_name='WATCHEDSTATEQUEUE')
# /
# updaters
update_software_scheduler = scheduler.Scheduler(
version_checker.SoftwareUpdater(),
cycle_time=datetime.timedelta(hours=UPDATE_INTERVAL),
thread_name='SOFTWAREUPDATE',
silent=False)
update_packages_scheduler = scheduler.Scheduler(
version_checker.PackagesUpdater(),
cycle_time=datetime.timedelta(hours=UPDATE_PACKAGES_INTERVAL),
# run_delay=datetime.timedelta(minutes=2),
thread_name='PACKAGESUPDATE',
silent=False)
update_show_scheduler = scheduler.Scheduler(
show_updater.ShowUpdater(),
cycle_time=datetime.timedelta(hours=1),
start_time=datetime.time(hour=SHOW_UPDATE_HOUR),
thread_name='SHOWDATAUPDATE',
prevent_cycle_run=show_queue_scheduler.action.is_show_update_running) # 3AM
classes.loading_msg.message = 'Loading show maps'
update_release_mappings_scheduler = scheduler.Scheduler(
scene_exceptions.ReleaseMap(),
cycle_time=datetime.timedelta(hours=2),
thread_name='SHOWMAPSUPDATE',
silent=False)
# /
# searchers
init_search_delay = int(os.environ.get('INIT_SEARCH_DELAY', 0))
# enter 4499 (was 4489) for experimental internal provider intervals
update_interval = datetime.timedelta(minutes=(RECENTSEARCH_INTERVAL, 1)[4499 == RECENTSEARCH_INTERVAL])
update_now = datetime.timedelta(minutes=0)
search_recent_scheduler = scheduler.Scheduler(
search_recent.RecentSearcher(),
cycle_time=update_interval,
run_delay=update_now if RECENTSEARCH_STARTUP else datetime.timedelta(minutes=init_search_delay or 5),
thread_name='RECENTSEARCH',
prevent_cycle_run=search_queue_scheduler.action.is_recentsearch_in_progress)
if [x for x in providers.sorted_sources()
if x.is_active() and getattr(x, 'enable_backlog', None) and GenericProvider.NZB == x.providerType]:
nextbacklogpossible = datetime.datetime.fromtimestamp(
search_backlog.BacklogSearcher().last_runtime) + datetime.timedelta(hours=23)
now = datetime.datetime.now()
if nextbacklogpossible > now:
time_diff = nextbacklogpossible - now
if (time_diff > datetime.timedelta(hours=12) and
nextbacklogpossible - datetime.timedelta(hours=12) > now):
time_diff = time_diff - datetime.timedelta(hours=12)
else:
time_diff = datetime.timedelta(minutes=0)
backlogdelay = helpers.try_int((time_diff.total_seconds() / 60) + 10, 10)
else:
backlogdelay = 10
search_backlog_scheduler = search_backlog.BacklogSearchScheduler(
search_backlog.BacklogSearcher(),
cycle_time=datetime.timedelta(minutes=get_backlog_cycle_time()),
run_delay=datetime.timedelta(minutes=init_search_delay or backlogdelay),
thread_name='BACKLOGSEARCH',
prevent_cycle_run=search_queue_scheduler.action.is_standard_backlog_in_progress)
last_proper_search = datetime.datetime.fromtimestamp(properFinder.get_last_proper_search())
time_diff = datetime.timedelta(days=1) - (datetime.datetime.now() - last_proper_search)
if time_diff < datetime.timedelta(seconds=0):
properdelay = 20
else:
properdelay = helpers.try_int((time_diff.total_seconds() / 60) + 5, 20)
search_propers_scheduler = scheduler.Scheduler(
search_propers.ProperSearcher(),
cycle_time=datetime.timedelta(days=1),
run_delay=datetime.timedelta(minutes=init_search_delay or properdelay),
thread_name='PROPERSSEARCH',
prevent_cycle_run=search_queue_scheduler.action.is_propersearch_in_progress)
search_subtitles_scheduler = scheduler.Scheduler(
subtitles.SubtitlesFinder(),
cycle_time=datetime.timedelta(hours=SUBTITLES_FINDER_INTERVAL),
thread_name='SUBTITLESEARCH',
silent=not USE_SUBTITLES)
# /
# others
emby_watched_state_scheduler = scheduler.Scheduler(
EmbyWatchedStateUpdater(),
cycle_time=datetime.timedelta(minutes=EMBY_WATCHEDSTATE_INTERVAL),
run_delay=datetime.timedelta(minutes=5),
thread_name='EMBYWATCHEDSTATE')
plex_watched_state_scheduler = scheduler.Scheduler(
PlexWatchedStateUpdater(),
cycle_time=datetime.timedelta(minutes=PLEX_WATCHEDSTATE_INTERVAL),
run_delay=datetime.timedelta(minutes=5),
thread_name='PLEXWATCHEDSTATE')
process_media_scheduler = scheduler.Scheduler(
auto_media_process.MediaProcess(),
cycle_time=datetime.timedelta(minutes=MEDIAPROCESS_INTERVAL),
thread_name='PROCESSMEDIA',
silent=not PROCESS_AUTOMATICALLY)
background_mapping_task = threading.Thread(name='MAPPINGUPDATES', target=indexermapper.load_mapped_ids,
kwargs={'load_all': True})
Add menu Shows/"TMDB Cards". Add top rated, popular, trending today, trending this week, to TMDB cards. Change Shows/Add show... Trakt and IMDb card descriptions to be dynamic. Add network data to trakt cards. Add fallback for show cast when no suitable items are found in tvdb_api. Change refactor for trakt lib update. Change sanitise api response dates for cards (an invalid trakt date caused a UI glitch). Fix issue where trakt can return no tvdb id causing a card to not display. Change view-show TVDb genre links to use anon link setting. Change remove displayShow.tmpl code for '|' sep as it is a fixed list string at data source. Change add TVINFO_FANSITE placeholder icon. Change refactor api sg.`CMD_SickGearShowsBrowseTrakt`. --- Refactor date handling to make it's usage consistent from indexerapi Split when_past out to to started_past and return_past for UI. Fix trakt returning dates. Change bring properly into use, the proper new season returning date. Change remove PY2 unused import statements. --- Fix issue with Trakt cards where an incorrect cache image obscures the default card placeholder image. Simplify airtime for cards. Remove nonsense TMDB api overview text. Rearrange cards order on top menu. --- Remove unused vars and simplify regex use cases. Fix tv cards issue with Trakt and Tvmaze where show_info does not carry a first episode_info. Instantiate with TVInfoEpisode() instead of None, so that expected properties exist without a need for Nonetype tests. Change simplify `overview` and `airtime` use after lib output type is made trustable. Change cards view to not allow items with no seriesname.
2023-03-09 02:13:52 +00:00
MEMCACHE['history_tab_limit'] = 13
MEMCACHE['history_tab'] = History.menu_tab(MEMCACHE['history_tab_limit'])
try:
with scandir(os.path.join(PROG_DIR, 'gui', GUI_NAME, 'images', 'flags')) as s_d:
for f in s_d:
if f.is_file():
MEMCACHE_FLAG_IMAGES[os.path.splitext(f.name)[0].lower()] = True
except (BaseException, Exception):
pass
config_events = ConfigEvents(_save_config)
config_events.start()
__INITIALIZED__ = True
return True
def enabled_schedulers(is_init=False):
# ([], [trakt_checker_scheduler])[USE_TRAKT] + \
return ([], [events])[is_init] \
+ ([], [update_software_scheduler, update_packages_scheduler,
update_show_scheduler, update_release_mappings_scheduler,
search_recent_scheduler, search_backlog_scheduler,
search_propers_scheduler, search_subtitles_scheduler,
show_queue_scheduler, search_queue_scheduler,
people_queue_scheduler, watched_state_queue_scheduler,
emby_watched_state_scheduler, plex_watched_state_scheduler,
process_media_scheduler
]
)[not MEMCACHE.get('update_restart')] \
+ ([events], [])[is_init]
def start():
global started
with INIT_LOCK:
if __INITIALIZED__:
# Load all Indexer mappings in background
indexermapper.defunct_indexer = [
i for i in TVInfoAPI().all_sources if TVInfoAPI(i).config.get('defunct')]
indexermapper.indexer_list = [i for i in TVInfoAPI().all_sources if TVInfoAPI(i).config.get('show_url')
and True is not TVInfoAPI(i).config.get('people_only')]
background_mapping_task.start()
for p in providers.sorted_sources():
if p.is_active() and getattr(p, 'ping_iv', None):
# noinspection PyProtectedMember
provider_ping_thread_pool[p.get_id()] = threading.Thread(
name='PING-PROVIDER %s' % p.name, target=p._ping)
provider_ping_thread_pool[p.get_id()].start()
for thread in enabled_schedulers(is_init=True): # type: threading.Thread
thread.start()
started = True
def restart(soft=True, update_pkg=None):
if not soft:
if update_pkg:
MY_ARGS.append('--update-pkg')
logger.log('Trigger event restart')
events.put(events.SystemEvent.RESTART)
else:
halt()
save_all()
logger.log('Re-initializing all data')
initialize()
def sig_handler(signum=None, _=None):
is_ctrlbreak = 'win32' == sys.platform and signal.SIGBREAK == signum
msg = 'Signal "%s" found' % (signal.SIGINT == signum and 'CTRL-C' or is_ctrlbreak and 'CTRL+BREAK' or
signal.SIGTERM == signum and 'Termination' or signum)
if None is signum or signum in (signal.SIGINT, signal.SIGTERM) or is_ctrlbreak:
logger.log('%s, saving and exiting...' % msg)
events.put(events.SystemEvent.SHUTDOWN)
else:
logger.log('%s, not exiting' % msg)
def halt():
global __INITIALIZED__, started, config_events
logger.debug('Check INIT_LOCK on halt')
with INIT_LOCK:
logger.debug(f'Check __INITIALIZED__ on halt: {__INITIALIZED__}')
if __INITIALIZED__:
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
for p in provider_ping_thread_pool:
try:
provider_ping_thread_pool[p].join(10)
logger.log('Thread %s has exit' % provider_ping_thread_pool[p].name)
except RuntimeError:
logger.log('Fail, thread %s did not exit' % provider_ping_thread_pool[p].name)
pass
if ADBA_CONNECTION:
try:
ADBA_CONNECTION.logout()
except AniDBError:
pass
try:
ADBA_CONNECTION.join(10)
logger.log('Thread %s has exit' % ADBA_CONNECTION.name)
except (BaseException, Exception):
logger.log('Fail, thread %s did not exit' % ADBA_CONNECTION.name)
for thread in enabled_schedulers(): # type: scheduler.Scheduler
try:
thread.stopit()
if getattr(thread, 'action', None) and getattr(thread.action, 'save_queue', None):
try:
thread.action.save_queue()
except (BaseException, Exception):
pass
except Exception as e:
logger.log('Thread %s stop failed with: %s' % (thread.name, e))
for thread in enabled_schedulers(): # type: threading.Thread
try:
thread.join(10)
logger.log('Thread %s has exit' % thread.name)
except RuntimeError:
# this just means it's the current thread, can be ignored
logger.log('Thread %s is exiting' % thread.name)
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
def save_all():
if not MEMCACHE.get('update_restart'):
global showList
# write all shows
logger.log('Saving all shows to the database')
for show_obj in showList: # type: tv.TVShow
show_obj.save_to_db()
# save config
logger.log('Saving config file to disk')
_save_config(force=True)
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_LOADED
if not CONFIG_LOADED:
return
# use queue if it's available, otherwise, call save_config directly
hasattr(config_events, 'put') and config_events.put(force) or _save_config(force)
def _save_config(force=False, **kwargs):
# type: (bool, ...) -> None
global CONFIG_OLD, CONFIG_LOADED
if not CONFIG_LOADED:
return
new_config = ConfigObj()
new_config.filename = CONFIG_FILE
# For passwords, you must include the word `password` in the item_name and
# add `helpers.encrypt(ITEM_NAME, ENCRYPTION_VERSION)` in save_config()
new_config['General'] = dict()
s_z = check_setting_int(CFG, 'General', 'stack_size', 0)
if s_z:
new_config['General']['stack_size'] = s_z
new_config['General']['config_version'] = CONFIG_VERSION
new_config['General']['branch'] = BRANCH
new_config['General']['git_remote'] = GIT_REMOTE
new_config['General']['cur_commit_hash'] = CUR_COMMIT_HASH
new_config['General']['cur_commit_branch'] = CUR_COMMIT_BRANCH
new_config['General']['encryption_version'] = int(ENCRYPTION_VERSION)
new_config['General']['log_dir'] = ACTUAL_LOG_DIR if ACTUAL_LOG_DIR else 'Logs'
new_config['General']['file_logging_preset'] = FILE_LOGGING_PRESET \
if FILE_LOGGING_PRESET and 'DB' != FILE_LOGGING_PRESET else 'DEBUG'
new_config['General']['file_logging_db'] = 0
new_config['General']['socket_timeout'] = SOCKET_TIMEOUT
new_config['General']['web_host'] = WEB_HOST
new_config['General']['web_port'] = WEB_PORT
new_config['General']['web_ipv6'] = int(WEB_IPV6)
new_config['General']['web_ipv64'] = int(WEB_IPV64)
new_config['General']['web_log'] = int(WEB_LOG)
new_config['General']['web_root'] = WEB_ROOT
new_config['General']['web_username'] = WEB_USERNAME
new_config['General']['web_password'] = helpers.encrypt(WEB_PASSWORD, ENCRYPTION_VERSION)
new_config['General']['cpu_preset'] = CPU_PRESET
new_config['General']['anon_redirect'] = ANON_REDIRECT
new_config['General']['use_api'] = int(USE_API)
new_config['General']['api_keys'] = '|||'.join([':::'.join(a) for a in API_KEYS])
new_config['General']['debug'] = int(DEBUG)
new_config['General']['enable_https'] = int(ENABLE_HTTPS)
new_config['General']['https_cert'] = HTTPS_CERT
new_config['General']['https_key'] = HTTPS_KEY
new_config['General']['handle_reverse_proxy'] = int(HANDLE_REVERSE_PROXY)
new_config['General']['send_security_headers'] = int(SEND_SECURITY_HEADERS)
new_config['General']['allowed_hosts'] = ALLOWED_HOSTS
new_config['General']['allow_anyip'] = int(ALLOW_ANYIP)
new_config['General']['use_nzbs'] = int(USE_NZBS)
new_config['General']['use_torrents'] = int(USE_TORRENTS)
new_config['General']['nzb_method'] = NZB_METHOD
new_config['General']['torrent_method'] = TORRENT_METHOD
new_config['General']['usenet_retention'] = int(USENET_RETENTION)
new_config['General']['mediaprocess_interval'] = int(MEDIAPROCESS_INTERVAL)
new_config['General']['recentsearch_interval'] = int(RECENTSEARCH_INTERVAL)
new_config['General']['backlog_period'] = int(BACKLOG_PERIOD)
new_config['General']['backlog_limited_period'] = int(BACKLOG_LIMITED_PERIOD)
new_config['General']['download_propers'] = int(DOWNLOAD_PROPERS)
new_config['General']['propers_webdl_onegrp'] = int(PROPERS_WEBDL_ONEGRP)
new_config['General']['allow_high_priority'] = int(ALLOW_HIGH_PRIORITY)
new_config['General']['recentsearch_startup'] = int(RECENTSEARCH_STARTUP)
new_config['General']['backlog_nofull'] = int(BACKLOG_NOFULL)
new_config['General']['skip_removed_files'] = int(SKIP_REMOVED_FILES)
new_config['General']['results_sortby'] = str(RESULTS_SORTBY)
new_config['General']['indexer_default'] = int(TVINFO_DEFAULT)
new_config['General']['indexer_timeout'] = int(TVINFO_TIMEOUT)
new_config['General']['quality_default'] = int(QUALITY_DEFAULT)
new_config['General']['wanted_begin_default'] = int(WANTED_BEGIN_DEFAULT)
new_config['General']['wanted_latest_default'] = int(WANTED_LATEST_DEFAULT)
new_config['General']['pause default'] = int(PAUSE_DEFAULT)
new_config['General']['status_default'] = int(STATUS_DEFAULT)
new_config['General']['scene_default'] = int(SCENE_DEFAULT)
new_config['General']['flatten_folders_default'] = int(FLATTEN_FOLDERS_DEFAULT)
new_config['General']['anime_default'] = int(ANIME_DEFAULT)
new_config['General']['provider_order'] = ' '.join(PROVIDER_ORDER)
new_config['General']['provider_homes'] = '%s' % dict([(pid, v) for pid, v in list(PROVIDER_HOMES.items())
if pid in [
p.get_id() for p in [x for x in providers.sorted_sources() if GenericProvider.TORRENT == x.providerType]]])
new_config['General']['update_notify'] = int(UPDATE_NOTIFY)
new_config['General']['update_auto'] = int(UPDATE_AUTO)
new_config['General']['update_interval'] = int(UPDATE_INTERVAL)
new_config['General']['notify_on_update'] = int(NOTIFY_ON_UPDATE)
new_config['General']['update_packages_notify'] = int(UPDATE_PACKAGES_NOTIFY)
new_config['General']['update_packages_auto'] = int(UPDATE_PACKAGES_AUTO)
new_config['General']['update_packages_menu'] = int(UPDATE_PACKAGES_MENU)
new_config['General']['update_packages_interval'] = int(UPDATE_PACKAGES_INTERVAL)
new_config['General']['naming_strip_year'] = int(NAMING_STRIP_YEAR)
new_config['General']['naming_pattern'] = NAMING_PATTERN
new_config['General']['naming_custom_abd'] = int(NAMING_CUSTOM_ABD)
new_config['General']['naming_abd_pattern'] = NAMING_ABD_PATTERN
new_config['General']['naming_custom_sports'] = int(NAMING_CUSTOM_SPORTS)
new_config['General']['naming_sports_pattern'] = NAMING_SPORTS_PATTERN
new_config['General']['naming_custom_anime'] = int(NAMING_CUSTOM_ANIME)
new_config['General']['naming_anime_pattern'] = NAMING_ANIME_PATTERN
new_config['General']['naming_multi_ep'] = int(NAMING_MULTI_EP)
new_config['General']['naming_anime_multi_ep'] = int(NAMING_ANIME_MULTI_EP)
new_config['General']['naming_anime'] = int(NAMING_ANIME)
new_config['General']['launch_browser'] = int(LAUNCH_BROWSER)
new_config['General']['update_shows_on_start'] = int(UPDATE_SHOWS_ON_START)
new_config['General']['show_update_hour'] = int(SHOW_UPDATE_HOUR)
new_config['General']['trash_remove_show'] = int(TRASH_REMOVE_SHOW)
new_config['General']['trash_rotate_logs'] = int(TRASH_ROTATE_LOGS)
new_config['General']['home_search_focus'] = int(HOME_SEARCH_FOCUS)
new_config['General']['display_freespace'] = int(DISPLAY_FREESPACE)
new_config['General']['sort_article'] = int(SORT_ARTICLE)
new_config['General']['proxy_setting'] = PROXY_SETTING
sg_helpers.PROXY_SETTING = PROXY_SETTING
new_config['General']['proxy_indexers'] = int(PROXY_INDEXERS)
new_config['General']['metadata_xbmc'] = METADATA_XBMC
new_config['General']['metadata_xbmc_12plus'] = METADATA_XBMC_12PLUS
new_config['General']['metadata_mediabrowser'] = METADATA_MEDIABROWSER
new_config['General']['metadata_ps3'] = METADATA_PS3
new_config['General']['metadata_wdtv'] = METADATA_WDTV
new_config['General']['metadata_tivo'] = METADATA_TIVO
new_config['General']['metadata_mede8er'] = METADATA_MEDE8ER
new_config['General']['metadata_kodi'] = METADATA_KODI
new_config['General']['search_unaired'] = int(SEARCH_UNAIRED)
new_config['General']['unaired_recent_search_only'] = int(UNAIRED_RECENT_SEARCH_ONLY)
new_config['General']['flaresolverr_host'] = FLARESOLVERR_HOST
new_config['General']['cache_dir'] = ACTUAL_CACHE_DIR if ACTUAL_CACHE_DIR else 'cache'
sg_helpers.CACHE_DIR = CACHE_DIR
sg_helpers.DATA_DIR = DATA_DIR
new_config['General']['root_dirs'] = ROOT_DIRS if ROOT_DIRS else ''
new_config['General']['tv_download_dir'] = TV_DOWNLOAD_DIR
new_config['General']['keep_processed_dir'] = int(KEEP_PROCESSED_DIR)
new_config['General']['process_method'] = PROCESS_METHOD
new_config['General']['process_last_dir'] = PROCESS_LAST_DIR
new_config['General']['process_last_method'] = PROCESS_LAST_METHOD
new_config['General']['process_last_cleanup'] = int(PROCESS_LAST_CLEANUP)
new_config['General']['move_associated_files'] = int(MOVE_ASSOCIATED_FILES)
new_config['General']['postpone_if_sync_files'] = int(POSTPONE_IF_SYNC_FILES)
new_config['General']['process_positive_log'] = int(PROCESS_POSITIVE_LOG)
new_config['General']['nfo_rename'] = int(NFO_RENAME)
new_config['General']['process_automatically'] = int(PROCESS_AUTOMATICALLY)
new_config['General']['unpack'] = int(UNPACK)
new_config['General']['rename_episodes'] = int(RENAME_EPISODES)
new_config['General']['rename_tba_episodes'] = int(RENAME_TBA_EPISODES)
new_config['General']['rename_name_changed_episodes'] = int(RENAME_NAME_CHANGED_EPISODES)
new_config['General']['airdate_episodes'] = int(AIRDATE_EPISODES)
new_config['General']['create_missing_show_dirs'] = int(CREATE_MISSING_SHOW_DIRS)
new_config['General']['show_dirs_with_dots'] = int(SHOW_DIRS_WITH_DOTS)
new_config['General']['add_shows_wo_dir'] = int(ADD_SHOWS_WO_DIR)
new_config['General']['add_shows_metalang'] = ADD_SHOWS_METALANG
new_config['General']['remove_filename_chars'] = REMOVE_FILENAME_CHARS
new_config['General']['import_default_checked_shows'] = int(IMPORT_DEFAULT_CHECKED_SHOWS)
new_config['General']['extra_scripts'] = '|'.join(EXTRA_SCRIPTS)
new_config['General']['sg_extra_scripts'] = '|'.join(SG_EXTRA_SCRIPTS)
new_config['General']['git_path'] = GIT_PATH
new_config['General']['ignore_words'] = helpers.generate_word_str(IGNORE_WORDS, IGNORE_WORDS_REGEX)
new_config['General']['require_words'] = helpers.generate_word_str(REQUIRE_WORDS, REQUIRE_WORDS_REGEX)
new_config['General']['calendar_unprotected'] = int(CALENDAR_UNPROTECTED)
new_config['Updates'] = {}
new_config['Updates']['updates_todo'] = '%s' % (UPDATES_TODO or {})
new_config['Backup'] = {}
if BACKUP_DB_PATH:
new_config['Backup']['backup_db_path'] = BACKUP_DB_PATH
new_config['Backup']['backup_db_oneday'] = int(BACKUP_DB_ONEDAY)
new_config['Backup']['backup_db_max_count'] = BACKUP_DB_MAX_COUNT
default_not_zero = ('enable_recentsearch', 'enable_backlog', 'enable_scheduled_backlog', 'use_after_get_data')
for src in filter(lambda px: GenericProvider.TORRENT == px.providerType, providers.sorted_sources()):
src_id = src.get_id()
src_id_uc = src_id.upper()
new_config[src_id_uc] = {}
if int(src.enabled):
new_config[src_id_uc][src_id] = int(src.enabled)
if getattr(src, 'url_edit', None):
new_config[src_id_uc][src_id + '_url_home'] = src.url_home
if getattr(src, 'password', None):
new_config[src_id_uc][src_id + '_password'] = helpers.encrypt(src.password, ENCRYPTION_VERSION)
for (attr, value) in [
(k, getattr(src, k, v) if not v else helpers.try_int(getattr(src, k, None)))
for (k, v) in [
('enable_recentsearch', 1), ('enable_backlog', 1), ('enable_scheduled_backlog', 1),
('api_key', None), ('passkey', None), ('digest', None), ('hash', None), ('username', ''), ('uid', ''),
('minseed', 1), ('minleech', 1), ('seed_time', None),
('confirmed', 1), ('freeleech', 1), ('reject_m2ts', 1), ('use_after_get_data', 1),
('scene_only', None), ('scene_or_contain', ''), ('scene_loose', None), ('scene_loose_active', None),
('scene_rej_nuked', None), ('scene_nuked_active', None),
('search_mode', None), ('search_fallback', 1)
]
if hasattr(src, k)]:
if (value and not ('search_mode' == attr and 'eponly' == value)
# must allow the following to save '0' not '1' because default is enable (1) instead of disable (0)
and (attr not in default_not_zero) or not value and (attr in default_not_zero)):
new_config[src_id_uc]['%s_%s' % (src_id, attr)] = value
if getattr(src, '_seed_ratio', None):
new_config[src_id_uc][src_id + '_seed_ratio'] = src.seed_ratio()
if getattr(src, 'filter', None):
new_config[src_id_uc][src_id + '_filter'] = src.filter
if not new_config[src_id_uc]:
del new_config[src_id_uc]
default_not_zero = ('enable_recentsearch', 'enable_backlog', 'enable_scheduled_backlog')
for src in filter(lambda px: GenericProvider.NZB == px.providerType, providers.sorted_sources()):
src_id = src.get_id()
src_id_uc = src.get_id().upper()
new_config[src_id_uc] = {}
if int(src.enabled):
new_config[src_id_uc][src_id] = int(src.enabled)
for attr in filter(lambda _a: None is not getattr(src, _a, None),
('api_key', 'digest', 'username', 'search_mode')):
if 'search_mode' != attr or 'eponly' != getattr(src, attr):
new_config[src_id_uc]['%s_%s' % (src_id, attr)] = getattr(src, attr)
for attr in filter(lambda _a: None is not getattr(src, _a, None), (
'enable_recentsearch', 'enable_backlog', 'enable_scheduled_backlog',
'scene_only', 'scene_loose', 'scene_loose_active',
'scene_rej_nuked', 'scene_nuked_active',
'search_fallback', 'server_type')):
value = helpers.try_int(getattr(src, attr, None))
# must allow the following to save '0' not '1' because default is enable (1) instead of disable (0)
if (value and (attr not in default_not_zero)) or (not value and (attr in default_not_zero)):
new_config[src_id_uc]['%s_%s' % (src_id, attr)] = value
attr = 'scene_or_contain'
if getattr(src, attr, None):
new_config[src_id_uc]['%s_%s' % (src_id, attr)] = getattr(src, attr, '')
if not new_config[src_id_uc]:
del new_config[src_id_uc]
cfg_keys = []
for (cfg, items) in iteritems(OrderedDict([
# -----------------------------------
# Config/Search
# -----------------------------------
('Blackhole', [
('nzb_dir', NZB_DIR), ('torrent_dir', TORRENT_DIR)]),
('NZBGet', [
('username', NZBGET_USERNAME), ('password', helpers.encrypt(NZBGET_PASSWORD, ENCRYPTION_VERSION)),
('host', NZBGET_HOST),
('category', NZBGET_CATEGORY),
('use_https', int(NZBGET_USE_HTTPS)),
('priority', NZBGET_PRIORITY),
('map', NZBGET_MAP),
('skip_process_media', int(NZBGET_SKIP_PM)),
]),
('SABnzbd', [
('username', SAB_USERNAME), ('password', helpers.encrypt(SAB_PASSWORD, ENCRYPTION_VERSION)),
('apikey', SAB_APIKEY),
('host', SAB_HOST),
('category', SAB_CATEGORY),
]),
('TORRENT', [
('username', TORRENT_USERNAME), ('password', helpers.encrypt(TORRENT_PASSWORD, ENCRYPTION_VERSION)),
('host', TORRENT_HOST),
('path', TORRENT_PATH),
('seed_time', int(TORRENT_SEED_TIME)),
('paused', int(TORRENT_PAUSED)),
('high_bandwidth', int(TORRENT_HIGH_BANDWIDTH)),
('label', TORRENT_LABEL),
('label_var', int(TORRENT_LABEL_VAR)),
('verify_cert', int(TORRENT_VERIFY_CERT)),
]),
# -----------------------------------
# Config/Notifications
# -----------------------------------
('Emby', [
('use_%s', int(USE_EMBY)),
('apikey', EMBY_APIKEY), ('host', EMBY_HOST),
('update_library', int(EMBY_UPDATE_LIBRARY)),
('watchedstate_scheduled', int(EMBY_WATCHEDSTATE_SCHEDULED)),
('watchedstate_interval', int(EMBY_WATCHEDSTATE_INTERVAL)),
('parent_maps', EMBY_PARENT_MAPS),
]),
('Kodi', [
('use_%s', int(USE_KODI)),
('username', KODI_USERNAME), ('password', helpers.encrypt(KODI_PASSWORD, ENCRYPTION_VERSION)),
('host', KODI_HOST),
('always_on', int(KODI_ALWAYS_ON)), ('update_library', int(KODI_UPDATE_LIBRARY)),
('update_full', int(KODI_UPDATE_FULL)),
('update_onlyfirst', int(KODI_UPDATE_ONLYFIRST)),
('parent_maps', KODI_PARENT_MAPS),
]),
('Plex', [
('use_%s', int(USE_PLEX)),
('username', PLEX_USERNAME), ('password', helpers.encrypt(PLEX_PASSWORD, ENCRYPTION_VERSION)),
('host', PLEX_HOST),
('update_library', int(PLEX_UPDATE_LIBRARY)),
('watchedstate_scheduled', int(PLEX_WATCHEDSTATE_SCHEDULED)),
('watchedstate_interval', int(PLEX_WATCHEDSTATE_INTERVAL)),
('parent_maps', PLEX_PARENT_MAPS),
('server_host', PLEX_SERVER_HOST),
]),
('XBMC', [
('use_%s', int(USE_XBMC)),
('username', XBMC_USERNAME), ('password', helpers.encrypt(XBMC_PASSWORD, ENCRYPTION_VERSION)),
('host', XBMC_HOST),
('always_on', int(XBMC_ALWAYS_ON)), ('update_library', int(XBMC_UPDATE_LIBRARY)),
('update_full', int(XBMC_UPDATE_FULL)),
('update_onlyfirst', int(XBMC_UPDATE_ONLYFIRST)),
]),
('NMJ', [
('use_%s', int(USE_NMJ)),
('host', NMJ_HOST),
('database', NMJ_DATABASE),
('mount', NMJ_MOUNT),
]),
('NMJv2', [
('use_%s', int(USE_NMJv2)),
('host', NMJv2_HOST),
('database', NMJv2_DATABASE),
('dbloc', NMJv2_DBLOC),
]),
('Synology', [
('use_synoindex', int(USE_SYNOINDEX)),
]),
('SynologyNotifier', [
('use_%s', int(USE_SYNOLOGYNOTIFIER)),
]),
('pyTivo', [
('use_%s', int(USE_PYTIVO)),
('host', PYTIVO_HOST),
('share_name', PYTIVO_SHARE_NAME),
('tivo_name', PYTIVO_TIVO_NAME),
]),
('Boxcar2', [
('use_%s', int(USE_BOXCAR2)),
('accesstoken', BOXCAR2_ACCESSTOKEN),
('sound', BOXCAR2_SOUND if 'default' != BOXCAR2_SOUND else None),
]),
('Pushbullet', [
('use_%s', int(USE_PUSHBULLET)),
('access_token', PUSHBULLET_ACCESS_TOKEN),
('device_iden', PUSHBULLET_DEVICE_IDEN),
]),
('Pushover', [
('use_%s', int(USE_PUSHOVER)),
('userkey', PUSHOVER_USERKEY),
('apikey', PUSHOVER_APIKEY),
('priority', PUSHOVER_PRIORITY if '0' != PUSHOVER_PRIORITY else None),
('device', PUSHOVER_DEVICE if 'all' != PUSHOVER_DEVICE else None),
('sound', PUSHOVER_SOUND if 'pushover' != PUSHOVER_SOUND else None),
]),
('Growl', [
('use_%s', int(USE_GROWL)),
('host', GROWL_HOST),
# ('password', helpers.encrypt(GROWL_PASSWORD, ENCRYPTION_VERSION)),
]),
('Prowl', [
('use_%s', int(USE_PROWL)),
('api', PROWL_API),
('priority', PROWL_PRIORITY if '0' != PROWL_PRIORITY else None),
]),
('Libnotify', [
('use_%s', int(USE_LIBNOTIFY))
]),
# deprecated service
# new_config['Pushalot'] = {}
# new_config['Pushalot']['use_pushalot'] = int(USE_PUSHALOT)
# new_config['Pushalot']['pushalot_authorizationtoken'] = PUSHALOT_AUTHORIZATIONTOKEN
('Trakt', [
('use_%s', int(USE_TRAKT)),
('update_collection', TRAKT_UPDATE_COLLECTION
and trakt_helpers.build_config_string(TRAKT_UPDATE_COLLECTION)),
('accounts', TraktAPI.build_config_string(TRAKT_ACCOUNTS)),
('mru', TRAKT_MRU),
# new_config['Trakt'] = {}
# new_config['Trakt']['trakt_remove_watchlist'] = int(TRAKT_REMOVE_WATCHLIST)
# new_config['Trakt']['trakt_remove_serieslist'] = int(TRAKT_REMOVE_SERIESLIST)
# new_config['Trakt']['trakt_use_watchlist'] = int(TRAKT_USE_WATCHLIST)
# new_config['Trakt']['trakt_method_add'] = int(TRAKT_METHOD_ADD)
# new_config['Trakt']['trakt_start_paused'] = int(TRAKT_START_PAUSED)
# new_config['Trakt']['trakt_sync'] = int(TRAKT_SYNC)
# new_config['Trakt']['trakt_default_indexer'] = int(TRAKT_DEFAULT_INDEXER)
]),
('Metacritic', [
('mru', MC_MRU)
]),
Add menu Shows/"TMDB Cards". Add top rated, popular, trending today, trending this week, to TMDB cards. Change Shows/Add show... Trakt and IMDb card descriptions to be dynamic. Add network data to trakt cards. Add fallback for show cast when no suitable items are found in tvdb_api. Change refactor for trakt lib update. Change sanitise api response dates for cards (an invalid trakt date caused a UI glitch). Fix issue where trakt can return no tvdb id causing a card to not display. Change view-show TVDb genre links to use anon link setting. Change remove displayShow.tmpl code for '|' sep as it is a fixed list string at data source. Change add TVINFO_FANSITE placeholder icon. Change refactor api sg.`CMD_SickGearShowsBrowseTrakt`. --- Refactor date handling to make it's usage consistent from indexerapi Split when_past out to to started_past and return_past for UI. Fix trakt returning dates. Change bring properly into use, the proper new season returning date. Change remove PY2 unused import statements. --- Fix issue with Trakt cards where an incorrect cache image obscures the default card placeholder image. Simplify airtime for cards. Remove nonsense TMDB api overview text. Rearrange cards order on top menu. --- Remove unused vars and simplify regex use cases. Fix tv cards issue with Trakt and Tvmaze where show_info does not carry a first episode_info. Instantiate with TVInfoEpisode() instead of None, so that expected properties exist without a need for Nonetype tests. Change simplify `overview` and `airtime` use after lib output type is made trustable. Change cards view to not allow items with no seriesname.
2023-03-09 02:13:52 +00:00
('NextEpisode', [
('mru', NE_MRU)
]),
('TMDB', [
('mru', TMDB_MRU)
]),
('TVCalendar', [
('mru', TVC_MRU)
]),
('TVmaze', [
('mru', TVM_MRU)
]),
('Slack', [
('use_%s', int(USE_SLACK)),
('channel', SLACK_CHANNEL),
('as_authed', int(SLACK_AS_AUTHED)),
('bot_name', SLACK_BOT_NAME),
('icon_url', SLACK_ICON_URL),
('access_token', SLACK_ACCESS_TOKEN),
]),
('Discord', [
('use_%s', int(USE_DISCORD)),
('as_authed', int(DISCORD_AS_AUTHED)),
('username', DISCORD_USERNAME),
('icon_url', DISCORD_ICON_URL),
('as_tts', int(DISCORD_AS_TTS)),
('access_token', DISCORD_ACCESS_TOKEN),
]),
('Gitter', [
('use_%s', int(USE_GITTER)),
('room', GITTER_ROOM),
('access_token', GITTER_ACCESS_TOKEN),
]),
('Telegram', [
('use_%s', int(USE_TELEGRAM)),
('send_image', int(TELEGRAM_SEND_IMAGE)),
('quiet', int(TELEGRAM_QUIET)),
('access_token', TELEGRAM_ACCESS_TOKEN),
('chatid', TELEGRAM_CHATID),
]),
('Email', [
('use_%s', int(USE_EMAIL)),
('old_subjects', int(EMAIL_OLD_SUBJECTS)),
('host', EMAIL_HOST), ('port', int(EMAIL_PORT) if 25 != int(EMAIL_PORT) else None),
('tls', int(EMAIL_TLS)),
('user', EMAIL_USER), ('password', helpers.encrypt(EMAIL_PASSWORD, ENCRYPTION_VERSION)),
('from', EMAIL_FROM),
('list', EMAIL_LIST),
]),
# (, [(, )]),
])):
cfg_lc = cfg.lower()
cfg_keys += [cfg]
new_config[cfg] = {}
for (k, v) in filter(lambda arg: any([arg[1]]) or (
# allow saving where item value default is non-zero but 0 is a required setting value
cfg_lc in ('kodi', 'xbmc', 'synoindex', 'nzbget', 'torrent', 'telegram')
and arg[0] in ('always_on', 'priority', 'send_image'))
or ('rtorrent' == new_config['General']['torrent_method'] and 'label_var' == arg[0]), items):
k = '%s' in k and (k % cfg_lc) or (cfg_lc + '_' + k)
# correct for cases where keys are named in an inconsistent manner to parent stanza
k = k.replace('blackhole_', '').replace('sabnzbd_', 'sab_')
new_config[cfg].update({k: v})
for (notifier, onsnatch, ondownload, onsubtitledownload) in [
('Kodi', KODI_NOTIFY_ONSNATCH, KODI_NOTIFY_ONDOWNLOAD, KODI_NOTIFY_ONSUBTITLEDOWNLOAD),
('Plex', PLEX_NOTIFY_ONSNATCH, PLEX_NOTIFY_ONDOWNLOAD, PLEX_NOTIFY_ONSUBTITLEDOWNLOAD),
('XBMC', XBMC_NOTIFY_ONSNATCH, XBMC_NOTIFY_ONDOWNLOAD, XBMC_NOTIFY_ONSUBTITLEDOWNLOAD),
('SynologyNotifier', SYNOLOGYNOTIFIER_NOTIFY_ONSNATCH, SYNOLOGYNOTIFIER_NOTIFY_ONDOWNLOAD,
SYNOLOGYNOTIFIER_NOTIFY_ONSUBTITLEDOWNLOAD),
('Boxcar2', BOXCAR2_NOTIFY_ONSNATCH, BOXCAR2_NOTIFY_ONDOWNLOAD, BOXCAR2_NOTIFY_ONSUBTITLEDOWNLOAD),
('Pushbullet', PUSHBULLET_NOTIFY_ONSNATCH, PUSHBULLET_NOTIFY_ONDOWNLOAD, PUSHBULLET_NOTIFY_ONSUBTITLEDOWNLOAD),
('Pushover', PUSHOVER_NOTIFY_ONSNATCH, PUSHOVER_NOTIFY_ONDOWNLOAD, PUSHOVER_NOTIFY_ONSUBTITLEDOWNLOAD),
('Growl', GROWL_NOTIFY_ONSNATCH, GROWL_NOTIFY_ONDOWNLOAD, GROWL_NOTIFY_ONSUBTITLEDOWNLOAD),
('Prowl', PROWL_NOTIFY_ONSNATCH, PROWL_NOTIFY_ONDOWNLOAD, PROWL_NOTIFY_ONSUBTITLEDOWNLOAD),
('Libnotify', LIBNOTIFY_NOTIFY_ONSNATCH, LIBNOTIFY_NOTIFY_ONDOWNLOAD, LIBNOTIFY_NOTIFY_ONSUBTITLEDOWNLOAD),
# ('Pushalot', PUSHALOT_NOTIFY_ONSNATCH, PUSHALOT_NOTIFY_ONDOWNLOAD, PUSHALOT_NOTIFY_ONSUBTITLEDOWNLOAD),
('Slack', SLACK_NOTIFY_ONSNATCH, SLACK_NOTIFY_ONDOWNLOAD, SLACK_NOTIFY_ONSUBTITLEDOWNLOAD),
('Discord', DISCORD_NOTIFY_ONSNATCH, DISCORD_NOTIFY_ONDOWNLOAD, DISCORD_NOTIFY_ONSUBTITLEDOWNLOAD),
('Gitter', GITTER_NOTIFY_ONSNATCH, GITTER_NOTIFY_ONDOWNLOAD, GITTER_NOTIFY_ONSUBTITLEDOWNLOAD),
('Telegram', TELEGRAM_NOTIFY_ONSNATCH, TELEGRAM_NOTIFY_ONDOWNLOAD, TELEGRAM_NOTIFY_ONSUBTITLEDOWNLOAD),
('Email', EMAIL_NOTIFY_ONSNATCH, EMAIL_NOTIFY_ONDOWNLOAD, EMAIL_NOTIFY_ONSUBTITLEDOWNLOAD),
]:
if any([onsnatch, ondownload, onsubtitledownload]):
if onsnatch:
new_config[notifier]['%s_notify_onsnatch' % notifier.lower()] = int(onsnatch)
if ondownload:
new_config[notifier]['%s_notify_ondownload' % notifier.lower()] = int(ondownload)
if onsubtitledownload:
new_config[notifier]['%s_notify_onsubtitledownload' % notifier.lower()] = int(onsubtitledownload)
# remove empty stanzas
for k in filter(lambda c: not new_config[c], cfg_keys):
del new_config[k]
new_config['Newznab'] = {}
new_config['Newznab']['newznab_data'] = NEWZNAB_DATA
torrent_rss = '!!!'.join([x.config_str() for x in torrent_rss_providers])
if torrent_rss:
new_config['TorrentRss'] = {}
new_config['TorrentRss']['torrentrss_data'] = torrent_rss
new_config['GUI'] = {}
new_config['GUI']['gui_name'] = GUI_NAME
new_config['GUI']['theme_name'] = THEME_NAME
new_config['GUI']['default_home'] = DEFAULT_HOME
new_config['GUI']['fanart_limit'] = FANART_LIMIT
new_config['GUI']['fanart_panel'] = FANART_PANEL
new_config['GUI']['fanart_ratings'] = '%s' % (FANART_RATINGS or {})
new_config['GUI']['use_imdb_info'] = int(USE_IMDB_INFO)
new_config['GUI']['imdb_accounts'] = IMDB_ACCOUNTS
new_config['GUI']['fuzzy_dating'] = int(FUZZY_DATING)
new_config['GUI']['trim_zero'] = int(TRIM_ZERO)
new_config['GUI']['date_preset'] = DATE_PRESET
new_config['GUI']['time_preset'] = TIME_PRESET_W_SECONDS
new_config['GUI']['timezone_display'] = TIMEZONE_DISPLAY
new_config['GUI']['show_tags'] = ','.join(SHOW_TAGS)
new_config['GUI']['showlist_tagview'] = SHOWLIST_TAGVIEW
new_config['GUI']['home_layout'] = HOME_LAYOUT
new_config['GUI']['footer_time_layout'] = FOOTER_TIME_LAYOUT
new_config['GUI']['poster_sortby'] = POSTER_SORTBY
new_config['GUI']['poster_sortdir'] = POSTER_SORTDIR
new_config['GUI']['display_show_glide'] = '%s' % (DISPLAY_SHOW_GLIDE or {})
new_config['GUI']['display_show_glide_slidetime'] = int(DISPLAY_SHOW_GLIDE_SLIDETIME)
new_config['GUI']['display_show_viewmode'] = int(DISPLAY_SHOW_VIEWMODE)
new_config['GUI']['display_show_background'] = int(DISPLAY_SHOW_BACKGROUND)
new_config['GUI']['display_show_background_translucent'] = int(DISPLAY_SHOW_BACKGROUND_TRANSLUCENT)
new_config['GUI']['display_show_viewart'] = int(DISPLAY_SHOW_VIEWART)
new_config['GUI']['display_show_minimum'] = int(DISPLAY_SHOW_MINIMUM)
new_config['GUI']['display_show_specials'] = int(DISPLAY_SHOW_SPECIALS)
new_config['GUI']['episode_view_viewmode'] = int(EPISODE_VIEW_VIEWMODE)
new_config['GUI']['episode_view_background'] = int(EPISODE_VIEW_BACKGROUND)
new_config['GUI']['episode_view_background_translucent'] = int(EPISODE_VIEW_BACKGROUND_TRANSLUCENT)
new_config['GUI']['episode_view_layout'] = EPISODE_VIEW_LAYOUT
new_config['GUI']['episode_view_sort'] = EPISODE_VIEW_SORT
new_config['GUI']['episode_view_display_paused'] = int(EPISODE_VIEW_DISPLAY_PAUSED)
new_config['GUI']['episode_view_posters'] = int(EPISODE_VIEW_POSTERS)
new_config['GUI']['episode_view_missed_range'] = int(EPISODE_VIEW_MISSED_RANGE)
new_config['GUI']['poster_sortby'] = POSTER_SORTBY
new_config['GUI']['poster_sortdir'] = POSTER_SORTDIR
new_config['GUI']['show_tags'] = ','.join(SHOW_TAGS)
new_config['GUI']['showlist_tagview'] = SHOWLIST_TAGVIEW
new_config['GUI']['show_tag_default'] = SHOW_TAG_DEFAULT
new_config['GUI']['history_layout'] = HISTORY_LAYOUT
new_config['GUI']['browselist_hidden'] = '|~|'.join(BROWSELIST_HIDDEN)
new_config['GUI']['browselist_prefs'] = '%s' % (BROWSELIST_MRU or {})
new_config['Subtitles'] = {}
new_config['Subtitles']['use_subtitles'] = int(USE_SUBTITLES)
new_config['Subtitles']['subtitles_languages'] = ','.join(SUBTITLES_LANGUAGES)
new_config['Subtitles']['SUBTITLES_SERVICES_LIST'] = ','.join(SUBTITLES_SERVICES_LIST)
new_config['Subtitles']['SUBTITLES_SERVICES_ENABLED'] = '|'.join([str(x) for x in SUBTITLES_SERVICES_ENABLED])
new_config['Subtitles']['subtitles_services_auth'] = '|||'.join([':::'.join(a) for a in SUBTITLES_SERVICES_AUTH])
new_config['Subtitles']['subtitles_dir'] = SUBTITLES_DIR
new_config['Subtitles']['subtitles_default'] = int(SUBTITLES_DEFAULT)
new_config['Subtitles']['subtitles_history'] = int(SUBTITLES_HISTORY)
new_config['Subtitles']['subtitles_finder_interval'] = int(SUBTITLES_FINDER_INTERVAL)
new_config['Subtitles']['subtitles_os_hash'] = SUBTITLES_OS_HASH
new_config['FailedDownloads'] = {}
new_config['FailedDownloads']['use_failed_downloads'] = int(USE_FAILED_DOWNLOADS)
new_config['FailedDownloads']['delete_failed'] = int(DELETE_FAILED)
new_config['ANIDB'] = {}
new_config['ANIDB']['use_anidb'] = int(USE_ANIDB)
new_config['ANIDB']['anidb_username'] = ANIDB_USERNAME
new_config['ANIDB']['anidb_password'] = helpers.encrypt(ANIDB_PASSWORD, ENCRYPTION_VERSION)
new_config['ANIDB']['anidb_use_mylist'] = int(ANIDB_USE_MYLIST)
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
try:
if check_valid_config(CONFIG_FILE):
for _t in range(0, 3):
2024-10-07 00:06:24 +00:00
copy_file(CONFIG_FILE, backup_config)
if not check_valid_config(backup_config):
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)
2 > _t and time.sleep(3)
else:
break
else:
logger.warning('existing config file is invalid, not backing it up')
backup_config = None
except (BaseException, Exception):
backup_config = None
for _t in range(0, 3):
new_config.write()
if check_valid_config(CONFIG_FILE):
CONFIG_OLD = copy.deepcopy(new_config)
return
if 2 > _t:
logger.debug('saving config file failed, retrying...')
else:
logger.warning('saving config file failed.')
remove_file_perm(CONFIG_FILE)
2 > _t and time.sleep(3)
# we only get here if the config saving failed multiple times
if None is not backup_config and os.path.isfile(backup_config):
logger.error('saving config file failed, using backup file')
try:
copy_file(backup_config, CONFIG_FILE)
logger.log('using old backup config file')
return
except (BaseException, Exception):
logger.error('failed to use backup config file')
from sg_helpers import scantree
try:
target_base = os.path.join(BACKUP_DB_PATH or os.path.join(DATA_DIR, 'backup'))
file_list = [f for f in scantree(target_base, include='config', filter_kind=False)]
if file_list:
logger.log('trying to use latest config.ini backup')
# sort newest to oldest backup
file_list.sort(key=lambda _f: _f.stat(follow_symlinks=False).st_mtime)
import zipfile
try:
with zipfile.ZipFile(file_list[0].path, mode='r') as zf:
zf.extractall(target_base)
backup_config_file = os.path.join(target_base, 'config.ini')
if os.path.isfile(backup_config_file):
os.replace(backup_config_file, CONFIG_FILE)
if check_valid_config(CONFIG_FILE):
logger.log(f'used latest config.ini backup file: {file_list[0].name}')
return
else:
logger.error(f'failed to use latest config.ini backup file: {file_list[0].name}')
remove_file_perm(CONFIG_FILE)
except (BaseException, Exception):
pass
finally:
try:
remove_file_perm(backup_config_file)
except (BaseException, Exception):
pass
logger.error('failed to use latest config.ini')
except (BaseException, Exception):
pass
logger.error('saving config file failed and no backup available')
def launch_browser(start_port=None):
if not start_port:
start_port = WEB_PORT
browser_url = 'http%s://localhost:%d%s' % (('s', '')[not ENABLE_HTTPS], start_port, WEB_ROOT)
try:
webbrowser.open(browser_url, 2, True)
except (BaseException, Exception):
try:
webbrowser.open(browser_url, 1, True)
except (BaseException, Exception):
logger.error('Unable to launch a browser')