mirror of
https://github.com/clinton-hall/nzbToMedia.git
synced 2024-11-14 09:30:21 -08:00
f98d6fff65
* Added Python3.12 and future 3.13 * Fix Radarr result handling * remove py2.7 and py3.7 support
1056 lines
39 KiB
Python
1056 lines
39 KiB
Python
# coding=utf-8
|
|
|
|
from __future__ import (
|
|
absolute_import,
|
|
division,
|
|
print_function,
|
|
unicode_literals,
|
|
)
|
|
|
|
import itertools
|
|
import locale
|
|
import os
|
|
import platform
|
|
import re
|
|
import subprocess
|
|
import sys
|
|
import time
|
|
|
|
import eol
|
|
import libs.autoload
|
|
import libs.util
|
|
|
|
if not libs.autoload.completed:
|
|
sys.exit('Could not load vendored libraries.')
|
|
|
|
try:
|
|
import win32event
|
|
except ImportError:
|
|
if sys.platform == 'win32':
|
|
sys.exit('Please install pywin32')
|
|
|
|
APP_ROOT = libs.util.module_path(parent=True)
|
|
SOURCE_ROOT = libs.util.module_path()
|
|
|
|
# init preliminaries
|
|
SYS_ARGV = sys.argv[1:]
|
|
APP_FILENAME = sys.argv[0]
|
|
APP_NAME = os.path.basename(APP_FILENAME)
|
|
LOG_DIR = os.path.join(APP_ROOT, 'logs')
|
|
LOG_FILE = os.path.join(LOG_DIR, 'nzbtomedia.log')
|
|
PID_FILE = os.path.join(LOG_DIR, 'nzbtomedia.pid')
|
|
CONFIG_FILE = os.path.join(APP_ROOT, 'autoProcessMedia.cfg')
|
|
CONFIG_SPEC_FILE = os.path.join(APP_ROOT, 'autoProcessMedia.cfg.spec')
|
|
CONFIG_MOVIE_FILE = os.path.join(APP_ROOT, 'autoProcessMovie.cfg')
|
|
CONFIG_TV_FILE = os.path.join(APP_ROOT, 'autoProcessTv.cfg')
|
|
TEST_FILE = os.path.join(APP_ROOT, 'tests', 'test.mp4')
|
|
MYAPP = None
|
|
|
|
import six
|
|
from six.moves import reload_module
|
|
|
|
from core import logger, main_db, version_check, databases, transcoder
|
|
from core.configuration import config
|
|
from core.plugins.downloaders.configuration import (
|
|
configure_nzbs,
|
|
configure_torrents,
|
|
configure_torrent_class,
|
|
)
|
|
from core.plugins.downloaders.utils import (
|
|
pause_torrent,
|
|
remove_torrent,
|
|
resume_torrent,
|
|
)
|
|
from core.plugins.plex import configure_plex
|
|
from core.utils import (
|
|
RunningProcess,
|
|
category_search,
|
|
clean_dir,
|
|
copy_link,
|
|
extract_files,
|
|
flatten,
|
|
get_dirs,
|
|
get_download_info,
|
|
list_media_files,
|
|
make_dir,
|
|
parse_args,
|
|
rchmod,
|
|
remove_dir,
|
|
remove_read_only,
|
|
restart,
|
|
sanitize_name,
|
|
update_download_info_status,
|
|
wake_up,
|
|
)
|
|
|
|
__version__ = '12.1.13'
|
|
|
|
# Client Agents
|
|
NZB_CLIENTS = ['sabnzbd', 'nzbget', 'manual']
|
|
TORRENT_CLIENTS = ['transmission', 'deluge', 'utorrent', 'rtorrent', 'qbittorrent', 'other', 'manual']
|
|
|
|
# sickbeard fork/branch constants
|
|
FORK_DEFAULT = 'default'
|
|
FORK_FAILED = 'failed'
|
|
FORK_FAILED_TORRENT = 'failed-torrent'
|
|
FORK_SICKCHILL = 'SickChill'
|
|
FORK_SICKCHILL_API = 'SickChill-api'
|
|
FORK_SICKBEARD_API = 'SickBeard-api'
|
|
FORK_MEDUSA = 'Medusa'
|
|
FORK_MEDUSA_API = 'Medusa-api'
|
|
FORK_MEDUSA_APIV2 = 'Medusa-apiv2'
|
|
FORK_SICKGEAR = 'SickGear'
|
|
FORK_SICKGEAR_API = 'SickGear-api'
|
|
FORK_STHENO = 'Stheno'
|
|
|
|
FORKS = {
|
|
FORK_DEFAULT: {'dir': None},
|
|
FORK_FAILED: {'dirName': None, 'failed': None},
|
|
FORK_FAILED_TORRENT: {'dir': None, 'failed': None, 'process_method': None},
|
|
FORK_SICKCHILL: {'proc_dir': None, 'failed': None, 'process_method': None, 'force': None, 'delete_on': None, 'force_next': None},
|
|
FORK_SICKCHILL_API: {'path': None, 'proc_dir': None, 'failed': None, 'process_method': None, 'force': None, 'force_replace': None, 'return_data': None, 'type': None, 'delete': None, 'force_next': None, 'is_priority': None, 'cmd': 'postprocess'},
|
|
FORK_SICKBEARD_API: {'path': None, 'failed': None, 'process_method': None, 'force_replace': None, 'return_data': None, 'type': None, 'delete': None, 'force_next': None, 'cmd': 'postprocess'},
|
|
FORK_MEDUSA: {'proc_dir': None, 'failed': None, 'process_method': None, 'force': None, 'delete_on': None, 'ignore_subs': None},
|
|
FORK_MEDUSA_API: {'path': None, 'failed': None, 'process_method': None, 'force_replace': None, 'return_data': None, 'type': None, 'delete_files': None, 'is_priority': None, 'cmd': 'postprocess'},
|
|
FORK_MEDUSA_APIV2: {'proc_dir': None, 'resource': None, 'failed': None, 'process_method': None, 'force': None, 'type': None, 'delete_on': None, 'is_priority': None},
|
|
FORK_SICKGEAR: {'dir': None, 'failed': None, 'process_method': None, 'force': None},
|
|
FORK_SICKGEAR_API: {'path': None, 'process_method': None, 'force_replace': None, 'return_data': None, 'type': None, 'is_priority': None, 'failed': None, 'cmd': 'sg.postprocess'},
|
|
FORK_STHENO: {'proc_dir': None, 'failed': None, 'process_method': None, 'force': None, 'delete_on': None, 'ignore_subs': None},
|
|
}
|
|
ALL_FORKS = {k: None for k in set(list(itertools.chain.from_iterable([FORKS[x].keys() for x in FORKS.keys()])))}
|
|
|
|
# SiCKRAGE OAuth2
|
|
SICKRAGE_OAUTH_CLIENT_ID = 'nzbtomedia'
|
|
SICKRAGE_OAUTH_TOKEN_URL = 'https://auth.sickrage.ca/realms/sickrage/protocol/openid-connect/token'
|
|
|
|
# NZBGet Exit Codes
|
|
NZBGET_POSTPROCESS_PAR_CHECK = 92
|
|
NZBGET_POSTPROCESS_SUCCESS = 93
|
|
NZBGET_POSTPROCESS_ERROR = 94
|
|
NZBGET_POSTPROCESS_NONE = 95
|
|
|
|
CFG = None
|
|
LOG_DEBUG = None
|
|
LOG_DB = None
|
|
LOG_ENV = None
|
|
LOG_GIT = None
|
|
SYS_ENCODING = None
|
|
FAILED = False
|
|
|
|
AUTO_UPDATE = None
|
|
NZBTOMEDIA_VERSION = __version__
|
|
NEWEST_VERSION = None
|
|
NEWEST_VERSION_STRING = None
|
|
VERSION_NOTIFY = None
|
|
GIT_PATH = None
|
|
GIT_USER = None
|
|
GIT_BRANCH = None
|
|
GIT_REPO = None
|
|
FORCE_CLEAN = None
|
|
SAFE_MODE = None
|
|
NOEXTRACTFAILED = None
|
|
|
|
NZB_CLIENT_AGENT = None
|
|
SABNZBD_HOST = None
|
|
SABNZBD_PORT = None
|
|
SABNZBD_APIKEY = None
|
|
NZB_DEFAULT_DIRECTORY = None
|
|
|
|
TORRENT_CLIENT_AGENT = None
|
|
TORRENT_CLASS = None
|
|
USE_LINK = None
|
|
OUTPUT_DIRECTORY = None
|
|
NOFLATTEN = []
|
|
DELETE_ORIGINAL = None
|
|
TORRENT_CHMOD_DIRECTORY = None
|
|
TORRENT_DEFAULT_DIRECTORY = None
|
|
TORRENT_RESUME = None
|
|
TORRENT_RESUME_ON_FAILURE = None
|
|
|
|
REMOTE_PATHS = []
|
|
|
|
UTORRENT_WEB_UI = None
|
|
UTORRENT_USER = None
|
|
UTORRENT_PASSWORD = None
|
|
|
|
TRANSMISSION_HOST = None
|
|
TRANSMISSION_PORT = None
|
|
TRANSMISSION_USER = None
|
|
TRANSMISSION_PASSWORD = None
|
|
|
|
SYNO_HOST = None
|
|
SYNO_PORT = None
|
|
SYNO_USER = None
|
|
SYNO_PASSWORD = None
|
|
|
|
DELUGE_HOST = None
|
|
DELUGE_PORT = None
|
|
DELUGE_USER = None
|
|
DELUGE_PASSWORD = None
|
|
|
|
QBITTORRENT_HOST = None
|
|
QBITTORRENT_PORT = None
|
|
QBITTORRENT_USER = None
|
|
QBITTORRENT_PASSWORD = None
|
|
|
|
PLEX_SSL = None
|
|
PLEX_HOST = None
|
|
PLEX_PORT = None
|
|
PLEX_TOKEN = None
|
|
PLEX_SECTION = []
|
|
|
|
EXT_CONTAINER = []
|
|
COMPRESSED_CONTAINER = []
|
|
MEDIA_CONTAINER = []
|
|
AUDIO_CONTAINER = []
|
|
META_CONTAINER = []
|
|
|
|
SECTIONS = []
|
|
CATEGORIES = []
|
|
FORK_SET = []
|
|
|
|
MOUNTED = None
|
|
GETSUBS = False
|
|
TRANSCODE = None
|
|
CONCAT = None
|
|
FFMPEG_PATH = None
|
|
SYS_PATH = None
|
|
DUPLICATE = None
|
|
IGNOREEXTENSIONS = []
|
|
VEXTENSION = None
|
|
OUTPUTVIDEOPATH = None
|
|
PROCESSOUTPUT = False
|
|
GENERALOPTS = []
|
|
OTHEROPTS = []
|
|
ALANGUAGE = None
|
|
AINCLUDE = False
|
|
SLANGUAGES = []
|
|
SINCLUDE = False
|
|
SUBSDIR = None
|
|
ALLOWSUBS = False
|
|
SEXTRACT = False
|
|
SEMBED = False
|
|
BURN = False
|
|
DEFAULTS = None
|
|
VCODEC = None
|
|
VCODEC_ALLOW = []
|
|
VPRESET = None
|
|
VFRAMERATE = None
|
|
VBITRATE = None
|
|
VLEVEL = None
|
|
VCRF = None
|
|
VRESOLUTION = None
|
|
ACODEC = None
|
|
ACODEC_ALLOW = []
|
|
ACHANNELS = None
|
|
ABITRATE = None
|
|
ACODEC2 = None
|
|
ACODEC2_ALLOW = []
|
|
ACHANNELS2 = None
|
|
ABITRATE2 = None
|
|
ACODEC3 = None
|
|
ACODEC3_ALLOW = []
|
|
ACHANNELS3 = None
|
|
ABITRATE3 = None
|
|
SCODEC = None
|
|
OUTPUTFASTSTART = None
|
|
OUTPUTQUALITYPERCENT = None
|
|
FFMPEG = None
|
|
SEVENZIP = None
|
|
SHOWEXTRACT = 0
|
|
PAR2CMD = None
|
|
FFPROBE = None
|
|
CHECK_MEDIA = None
|
|
REQUIRE_LAN = None
|
|
NICENESS = []
|
|
HWACCEL = False
|
|
|
|
PASSWORDS_FILE = None
|
|
DOWNLOAD_INFO = None
|
|
GROUPS = None
|
|
|
|
USER_SCRIPT_MEDIAEXTENSIONS = None
|
|
USER_SCRIPT = None
|
|
USER_SCRIPT_PARAM = None
|
|
USER_SCRIPT_SUCCESSCODES = None
|
|
USER_SCRIPT_CLEAN = None
|
|
USER_DELAY = None
|
|
USER_SCRIPT_RUNONCE = None
|
|
|
|
__INITIALIZED__ = False
|
|
|
|
|
|
def configure_logging():
|
|
global LOG_FILE
|
|
global LOG_DIR
|
|
|
|
if 'NTM_LOGFILE' in os.environ:
|
|
LOG_FILE = os.environ['NTM_LOGFILE']
|
|
LOG_DIR = os.path.split(LOG_FILE)[0]
|
|
|
|
if not make_dir(LOG_DIR):
|
|
print('No log folder, logging to screen only')
|
|
|
|
|
|
def configure_process():
|
|
global MYAPP
|
|
|
|
MYAPP = RunningProcess()
|
|
while MYAPP.alreadyrunning():
|
|
print('Waiting for existing session to end')
|
|
time.sleep(30)
|
|
|
|
|
|
def configure_locale():
|
|
global SYS_ENCODING
|
|
|
|
try:
|
|
locale.setlocale(locale.LC_ALL, '')
|
|
SYS_ENCODING = locale.getpreferredencoding()
|
|
except (locale.Error, IOError):
|
|
pass
|
|
|
|
# For OSes that are poorly configured I'll just randomly force UTF-8
|
|
if not SYS_ENCODING or SYS_ENCODING in ('ANSI_X3.4-1968', 'US-ASCII', 'ASCII'):
|
|
SYS_ENCODING = 'UTF-8'
|
|
|
|
if six.PY2:
|
|
if not hasattr(sys, 'setdefaultencoding'):
|
|
reload_module(sys)
|
|
|
|
try:
|
|
# pylint: disable=E1101
|
|
# On non-unicode builds this will raise an AttributeError, if encoding type is not valid it throws a LookupError
|
|
sys.setdefaultencoding(SYS_ENCODING)
|
|
except Exception:
|
|
print('Sorry, you MUST add the nzbToMedia folder to the PYTHONPATH environment variable'
|
|
'\nor find another way to force Python to use {codec} for string encoding.'.format
|
|
(codec=SYS_ENCODING))
|
|
if 'NZBOP_SCRIPTDIR' in os.environ:
|
|
sys.exit(NZBGET_POSTPROCESS_ERROR)
|
|
else:
|
|
sys.exit(1)
|
|
|
|
|
|
def configure_migration():
|
|
global CONFIG_FILE
|
|
global CFG
|
|
|
|
# run migrate to convert old cfg to new style cfg plus fix any cfg missing values/options.
|
|
if not config.migrate():
|
|
logger.error('Unable to migrate config file {0}, exiting ...'.format(CONFIG_FILE))
|
|
if 'NZBOP_SCRIPTDIR' in os.environ:
|
|
pass # We will try and read config from Environment.
|
|
else:
|
|
sys.exit(-1)
|
|
|
|
# run migrate to convert NzbGet data from old cfg style to new cfg style
|
|
if 'NZBOP_SCRIPTDIR' in os.environ:
|
|
CFG = config.addnzbget()
|
|
|
|
else: # load newly migrated config
|
|
logger.info('Loading config from [{0}]'.format(CONFIG_FILE))
|
|
CFG = config()
|
|
|
|
|
|
def configure_logging_part_2():
|
|
global LOG_DB
|
|
global LOG_DEBUG
|
|
global LOG_ENV
|
|
global LOG_GIT
|
|
|
|
# Enable/Disable DEBUG Logging
|
|
LOG_DB = int(CFG['General']['log_db'])
|
|
LOG_DEBUG = int(CFG['General']['log_debug'])
|
|
LOG_ENV = int(CFG['General']['log_env'])
|
|
LOG_GIT = int(CFG['General']['log_git'])
|
|
|
|
if LOG_ENV:
|
|
for item in os.environ:
|
|
logger.info('{0}: {1}'.format(item, os.environ[item]), 'ENVIRONMENT')
|
|
|
|
|
|
def configure_general():
|
|
global VERSION_NOTIFY
|
|
global GIT_REPO
|
|
global GIT_PATH
|
|
global GIT_USER
|
|
global GIT_BRANCH
|
|
global FORCE_CLEAN
|
|
global FFMPEG_PATH
|
|
global SYS_PATH
|
|
global CHECK_MEDIA
|
|
global REQUIRE_LAN
|
|
global SAFE_MODE
|
|
global NOEXTRACTFAILED
|
|
|
|
# Set Version and GIT variables
|
|
VERSION_NOTIFY = int(CFG['General']['version_notify'])
|
|
GIT_REPO = 'nzbToMedia'
|
|
GIT_PATH = CFG['General']['git_path']
|
|
GIT_USER = CFG['General']['git_user'] or 'clinton-hall'
|
|
GIT_BRANCH = CFG['General']['git_branch'] or 'master'
|
|
FORCE_CLEAN = int(CFG['General']['force_clean'])
|
|
FFMPEG_PATH = CFG['General']['ffmpeg_path']
|
|
SYS_PATH = CFG['General']['sys_path']
|
|
CHECK_MEDIA = int(CFG['General']['check_media'])
|
|
REQUIRE_LAN = None if not CFG['General']['require_lan'] else CFG['General']['require_lan'].split(',')
|
|
SAFE_MODE = int(CFG['General']['safe_mode'])
|
|
NOEXTRACTFAILED = int(CFG['General']['no_extract_failed'])
|
|
|
|
|
|
def configure_updates():
|
|
global AUTO_UPDATE
|
|
global MYAPP
|
|
|
|
AUTO_UPDATE = int(CFG['General']['auto_update'])
|
|
version_checker = version_check.CheckVersion()
|
|
|
|
# Check for updates via GitHUB
|
|
if version_checker.check_for_new_version() and AUTO_UPDATE:
|
|
logger.info('Auto-Updating nzbToMedia, Please wait ...')
|
|
if version_checker.update():
|
|
# restart nzbToMedia
|
|
try:
|
|
del MYAPP
|
|
except Exception:
|
|
pass
|
|
restart()
|
|
else:
|
|
logger.error('Update failed, not restarting. Check your log for more information.')
|
|
|
|
# Set Current Version
|
|
logger.info('nzbToMedia Version:{version} Branch:{branch} ({system} {release})'.format
|
|
(version=NZBTOMEDIA_VERSION, branch=GIT_BRANCH,
|
|
system=platform.system(), release=platform.release()))
|
|
|
|
|
|
def configure_wake_on_lan():
|
|
if int(CFG['WakeOnLan']['wake']):
|
|
wake_up()
|
|
|
|
|
|
def configure_groups():
|
|
global GROUPS
|
|
|
|
GROUPS = CFG['Custom']['remove_group']
|
|
|
|
if isinstance(GROUPS, str):
|
|
GROUPS = GROUPS.split(',')
|
|
|
|
if GROUPS == ['']:
|
|
GROUPS = None
|
|
|
|
|
|
def configure_remote_paths():
|
|
global REMOTE_PATHS
|
|
|
|
REMOTE_PATHS = CFG['Network']['mount_points'] or []
|
|
|
|
if REMOTE_PATHS:
|
|
if isinstance(REMOTE_PATHS, list):
|
|
REMOTE_PATHS = ','.join(REMOTE_PATHS) # fix in case this imported as list.
|
|
|
|
REMOTE_PATHS = (
|
|
# /volume1/Public/,E:\|/volume2/share/,\\NAS\
|
|
tuple(item.split(','))
|
|
for item in REMOTE_PATHS.split('|')
|
|
)
|
|
|
|
REMOTE_PATHS = [
|
|
# strip trailing and leading whitespaces
|
|
(local.strip(), remote.strip())
|
|
for local, remote in REMOTE_PATHS
|
|
]
|
|
|
|
|
|
def configure_niceness():
|
|
global NICENESS
|
|
|
|
with open(os.devnull, 'w') as devnull:
|
|
try:
|
|
subprocess.Popen(['nice'], stdout=devnull, stderr=devnull).communicate()
|
|
if len(CFG['Posix']['niceness'].split(',')) > 1: #Allow passing of absolute command, not just value.
|
|
NICENESS.extend(CFG['Posix']['niceness'].split(','))
|
|
else:
|
|
NICENESS.extend(['nice', '-n{0}'.format(int(CFG['Posix']['niceness']))])
|
|
except Exception:
|
|
pass
|
|
try:
|
|
subprocess.Popen(['ionice'], stdout=devnull, stderr=devnull).communicate()
|
|
try:
|
|
NICENESS.extend(['ionice', '-c{0}'.format(int(CFG['Posix']['ionice_class']))])
|
|
except Exception:
|
|
pass
|
|
try:
|
|
if 'ionice' in NICENESS:
|
|
NICENESS.extend(['-n{0}'.format(int(CFG['Posix']['ionice_classdata']))])
|
|
else:
|
|
NICENESS.extend(['ionice', '-n{0}'.format(int(CFG['Posix']['ionice_classdata']))])
|
|
except Exception:
|
|
pass
|
|
except Exception:
|
|
pass
|
|
|
|
|
|
def configure_containers():
|
|
global COMPRESSED_CONTAINER
|
|
global MEDIA_CONTAINER
|
|
global AUDIO_CONTAINER
|
|
global META_CONTAINER
|
|
|
|
COMPRESSED_CONTAINER = [re.compile(r'.r\d{2}$', re.I),
|
|
re.compile(r'.part\d+.rar$', re.I),
|
|
re.compile('.rar$', re.I)]
|
|
COMPRESSED_CONTAINER += [re.compile('{0}$'.format(ext), re.I) for ext in
|
|
CFG['Extensions']['compressedExtensions']]
|
|
MEDIA_CONTAINER = CFG['Extensions']['mediaExtensions']
|
|
AUDIO_CONTAINER = CFG['Extensions']['audioExtensions']
|
|
META_CONTAINER = CFG['Extensions']['metaExtensions'] # .nfo,.sub,.srt
|
|
|
|
if isinstance(COMPRESSED_CONTAINER, str):
|
|
COMPRESSED_CONTAINER = COMPRESSED_CONTAINER.split(',')
|
|
|
|
if isinstance(MEDIA_CONTAINER, str):
|
|
MEDIA_CONTAINER = MEDIA_CONTAINER.split(',')
|
|
|
|
if isinstance(AUDIO_CONTAINER, str):
|
|
AUDIO_CONTAINER = AUDIO_CONTAINER.split(',')
|
|
|
|
if isinstance(META_CONTAINER, str):
|
|
META_CONTAINER = META_CONTAINER.split(',')
|
|
|
|
|
|
def configure_transcoder():
|
|
global MOUNTED
|
|
global GETSUBS
|
|
global TRANSCODE
|
|
global DUPLICATE
|
|
global CONCAT
|
|
global IGNOREEXTENSIONS
|
|
global OUTPUTFASTSTART
|
|
global GENERALOPTS
|
|
global OTHEROPTS
|
|
global OUTPUTQUALITYPERCENT
|
|
global OUTPUTVIDEOPATH
|
|
global PROCESSOUTPUT
|
|
global ALANGUAGE
|
|
global AINCLUDE
|
|
global SLANGUAGES
|
|
global SINCLUDE
|
|
global SEXTRACT
|
|
global SEMBED
|
|
global SUBSDIR
|
|
global VEXTENSION
|
|
global VCODEC
|
|
global VPRESET
|
|
global VFRAMERATE
|
|
global VBITRATE
|
|
global VRESOLUTION
|
|
global VCRF
|
|
global VLEVEL
|
|
global VCODEC_ALLOW
|
|
global ACODEC
|
|
global ACODEC_ALLOW
|
|
global ACHANNELS
|
|
global ABITRATE
|
|
global ACODEC2
|
|
global ACODEC2_ALLOW
|
|
global ACHANNELS2
|
|
global ABITRATE2
|
|
global ACODEC3
|
|
global ACODEC3_ALLOW
|
|
global ACHANNELS3
|
|
global ABITRATE3
|
|
global SCODEC
|
|
global BURN
|
|
global HWACCEL
|
|
global ALLOWSUBS
|
|
global DEFAULTS
|
|
|
|
MOUNTED = None
|
|
GETSUBS = int(CFG['Transcoder']['getSubs'])
|
|
TRANSCODE = int(CFG['Transcoder']['transcode'])
|
|
DUPLICATE = int(CFG['Transcoder']['duplicate'])
|
|
CONCAT = int(CFG['Transcoder']['concat'])
|
|
IGNOREEXTENSIONS = (CFG['Transcoder']['ignoreExtensions'])
|
|
if isinstance(IGNOREEXTENSIONS, str):
|
|
IGNOREEXTENSIONS = IGNOREEXTENSIONS.split(',')
|
|
OUTPUTFASTSTART = int(CFG['Transcoder']['outputFastStart'])
|
|
GENERALOPTS = (CFG['Transcoder']['generalOptions'])
|
|
if isinstance(GENERALOPTS, str):
|
|
GENERALOPTS = GENERALOPTS.split(',')
|
|
if GENERALOPTS == ['']:
|
|
GENERALOPTS = []
|
|
if '-fflags' not in GENERALOPTS:
|
|
GENERALOPTS.append('-fflags')
|
|
if '+genpts' not in GENERALOPTS:
|
|
GENERALOPTS.append('+genpts')
|
|
OTHEROPTS = (CFG['Transcoder']['otherOptions'])
|
|
if isinstance(OTHEROPTS, str):
|
|
OTHEROPTS = OTHEROPTS.split(',')
|
|
if OTHEROPTS == ['']:
|
|
OTHEROPTS = []
|
|
try:
|
|
OUTPUTQUALITYPERCENT = int(CFG['Transcoder']['outputQualityPercent'])
|
|
except Exception:
|
|
pass
|
|
OUTPUTVIDEOPATH = CFG['Transcoder']['outputVideoPath']
|
|
PROCESSOUTPUT = int(CFG['Transcoder']['processOutput'])
|
|
ALANGUAGE = CFG['Transcoder']['audioLanguage']
|
|
AINCLUDE = int(CFG['Transcoder']['allAudioLanguages'])
|
|
SLANGUAGES = CFG['Transcoder']['subLanguages']
|
|
if isinstance(SLANGUAGES, str):
|
|
SLANGUAGES = SLANGUAGES.split(',')
|
|
if SLANGUAGES == ['']:
|
|
SLANGUAGES = []
|
|
SINCLUDE = int(CFG['Transcoder']['allSubLanguages'])
|
|
SEXTRACT = int(CFG['Transcoder']['extractSubs'])
|
|
SEMBED = int(CFG['Transcoder']['embedSubs'])
|
|
SUBSDIR = CFG['Transcoder']['externalSubDir']
|
|
VEXTENSION = CFG['Transcoder']['outputVideoExtension'].strip()
|
|
VCODEC = CFG['Transcoder']['outputVideoCodec'].strip()
|
|
VCODEC_ALLOW = CFG['Transcoder']['VideoCodecAllow'].strip()
|
|
if isinstance(VCODEC_ALLOW, str):
|
|
VCODEC_ALLOW = VCODEC_ALLOW.split(',')
|
|
if VCODEC_ALLOW == ['']:
|
|
VCODEC_ALLOW = []
|
|
VPRESET = CFG['Transcoder']['outputVideoPreset'].strip()
|
|
try:
|
|
VFRAMERATE = float(CFG['Transcoder']['outputVideoFramerate'].strip())
|
|
except Exception:
|
|
pass
|
|
try:
|
|
VCRF = int(CFG['Transcoder']['outputVideoCRF'].strip())
|
|
except Exception:
|
|
pass
|
|
try:
|
|
VLEVEL = CFG['Transcoder']['outputVideoLevel'].strip()
|
|
except Exception:
|
|
pass
|
|
try:
|
|
VBITRATE = int((CFG['Transcoder']['outputVideoBitrate'].strip()).replace('k', '000'))
|
|
except Exception:
|
|
pass
|
|
VRESOLUTION = CFG['Transcoder']['outputVideoResolution']
|
|
ACODEC = CFG['Transcoder']['outputAudioCodec'].strip()
|
|
ACODEC_ALLOW = CFG['Transcoder']['AudioCodecAllow'].strip()
|
|
if isinstance(ACODEC_ALLOW, str):
|
|
ACODEC_ALLOW = ACODEC_ALLOW.split(',')
|
|
if ACODEC_ALLOW == ['']:
|
|
ACODEC_ALLOW = []
|
|
try:
|
|
ACHANNELS = int(CFG['Transcoder']['outputAudioChannels'].strip())
|
|
except Exception:
|
|
pass
|
|
try:
|
|
ABITRATE = int((CFG['Transcoder']['outputAudioBitrate'].strip()).replace('k', '000'))
|
|
except Exception:
|
|
pass
|
|
ACODEC2 = CFG['Transcoder']['outputAudioTrack2Codec'].strip()
|
|
ACODEC2_ALLOW = CFG['Transcoder']['AudioCodec2Allow'].strip()
|
|
if isinstance(ACODEC2_ALLOW, str):
|
|
ACODEC2_ALLOW = ACODEC2_ALLOW.split(',')
|
|
if ACODEC2_ALLOW == ['']:
|
|
ACODEC2_ALLOW = []
|
|
try:
|
|
ACHANNELS2 = int(CFG['Transcoder']['outputAudioTrack2Channels'].strip())
|
|
except Exception:
|
|
pass
|
|
try:
|
|
ABITRATE2 = int((CFG['Transcoder']['outputAudioTrack2Bitrate'].strip()).replace('k', '000'))
|
|
except Exception:
|
|
pass
|
|
ACODEC3 = CFG['Transcoder']['outputAudioOtherCodec'].strip()
|
|
ACODEC3_ALLOW = CFG['Transcoder']['AudioOtherCodecAllow'].strip()
|
|
if isinstance(ACODEC3_ALLOW, str):
|
|
ACODEC3_ALLOW = ACODEC3_ALLOW.split(',')
|
|
if ACODEC3_ALLOW == ['']:
|
|
ACODEC3_ALLOW = []
|
|
try:
|
|
ACHANNELS3 = int(CFG['Transcoder']['outputAudioOtherChannels'].strip())
|
|
except Exception:
|
|
pass
|
|
try:
|
|
ABITRATE3 = int((CFG['Transcoder']['outputAudioOtherBitrate'].strip()).replace('k', '000'))
|
|
except Exception:
|
|
pass
|
|
SCODEC = CFG['Transcoder']['outputSubtitleCodec'].strip()
|
|
BURN = int(CFG['Transcoder']['burnInSubtitle'].strip())
|
|
DEFAULTS = CFG['Transcoder']['outputDefault'].strip()
|
|
HWACCEL = int(CFG['Transcoder']['hwAccel'])
|
|
|
|
allow_subs = ['.mkv', '.mp4', '.m4v', 'asf', 'wma', 'wmv']
|
|
codec_alias = {
|
|
'libx264': ['libx264', 'h264', 'h.264', 'AVC', 'MPEG-4'],
|
|
'libmp3lame': ['libmp3lame', 'mp3'],
|
|
'libfaac': ['libfaac', 'aac', 'faac'],
|
|
}
|
|
transcode_defaults = {
|
|
'iPad': {
|
|
'VEXTENSION': '.mp4', 'VCODEC': 'libx264', 'VPRESET': None, 'VFRAMERATE': None, 'VBITRATE': None, 'VCRF': None, 'VLEVEL': None,
|
|
'VRESOLUTION': None, 'VCODEC_ALLOW': ['libx264', 'h264', 'h.264', 'AVC', 'avc', 'mpeg4', 'msmpeg4', 'MPEG-4'],
|
|
'ACODEC': 'aac', 'ACODEC_ALLOW': ['libfaac'], 'ABITRATE': None, 'ACHANNELS': 2,
|
|
'ACODEC2': 'ac3', 'ACODEC2_ALLOW': ['ac3'], 'ABITRATE2': None, 'ACHANNELS2': 6,
|
|
'ACODEC3': None, 'ACODEC3_ALLOW': [], 'ABITRATE3': None, 'ACHANNELS3': None,
|
|
'SCODEC': 'mov_text',
|
|
},
|
|
'iPad-1080p': {
|
|
'VEXTENSION': '.mp4', 'VCODEC': 'libx264', 'VPRESET': None, 'VFRAMERATE': None, 'VBITRATE': None, 'VCRF': None, 'VLEVEL': None,
|
|
'VRESOLUTION': '1920:1080', 'VCODEC_ALLOW': ['libx264', 'h264', 'h.264', 'AVC', 'avc', 'mpeg4', 'msmpeg4', 'MPEG-4'],
|
|
'ACODEC': 'aac', 'ACODEC_ALLOW': ['libfaac'], 'ABITRATE': None, 'ACHANNELS': 2,
|
|
'ACODEC2': 'ac3', 'ACODEC2_ALLOW': ['ac3'], 'ABITRATE2': None, 'ACHANNELS2': 6,
|
|
'ACODEC3': None, 'ACODEC3_ALLOW': [], 'ABITRATE3': None, 'ACHANNELS3': None,
|
|
'SCODEC': 'mov_text',
|
|
},
|
|
'iPad-720p': {
|
|
'VEXTENSION': '.mp4', 'VCODEC': 'libx264', 'VPRESET': None, 'VFRAMERATE': None, 'VBITRATE': None, 'VCRF': None, 'VLEVEL': None,
|
|
'VRESOLUTION': '1280:720', 'VCODEC_ALLOW': ['libx264', 'h264', 'h.264', 'AVC', 'avc', 'mpeg4', 'msmpeg4', 'MPEG-4'],
|
|
'ACODEC': 'aac', 'ACODEC_ALLOW': ['libfaac'], 'ABITRATE': None, 'ACHANNELS': 2,
|
|
'ACODEC2': 'ac3', 'ACODEC2_ALLOW': ['ac3'], 'ABITRATE2': None, 'ACHANNELS2': 6,
|
|
'ACODEC3': None, 'ACODEC3_ALLOW': [], 'ABITRATE3': None, 'ACHANNELS3': None,
|
|
'SCODEC': 'mov_text',
|
|
},
|
|
'Apple-TV': {
|
|
'VEXTENSION': '.mp4', 'VCODEC': 'libx264', 'VPRESET': None, 'VFRAMERATE': None, 'VBITRATE': None, 'VCRF': None, 'VLEVEL': None,
|
|
'VRESOLUTION': '1280:720', 'VCODEC_ALLOW': ['libx264', 'h264', 'h.264', 'AVC', 'avc', 'mpeg4', 'msmpeg4', 'MPEG-4'],
|
|
'ACODEC': 'ac3', 'ACODEC_ALLOW': ['ac3'], 'ABITRATE': None, 'ACHANNELS': 6,
|
|
'ACODEC2': 'aac', 'ACODEC2_ALLOW': ['libfaac'], 'ABITRATE2': None, 'ACHANNELS2': 2,
|
|
'ACODEC3': None, 'ACODEC3_ALLOW': [], 'ABITRATE3': None, 'ACHANNELS3': None,
|
|
'SCODEC': 'mov_text',
|
|
},
|
|
'iPod': {
|
|
'VEXTENSION': '.mp4', 'VCODEC': 'libx264', 'VPRESET': None, 'VFRAMERATE': None, 'VBITRATE': None, 'VCRF': None, 'VLEVEL': None,
|
|
'VRESOLUTION': '1280:720', 'VCODEC_ALLOW': ['libx264', 'h264', 'h.264', 'AVC', 'avc', 'mpeg4', 'msmpeg4', 'MPEG-4'],
|
|
'ACODEC': 'aac', 'ACODEC_ALLOW': ['libfaac'], 'ABITRATE': 128000, 'ACHANNELS': 2,
|
|
'ACODEC2': None, 'ACODEC2_ALLOW': [], 'ABITRATE2': None, 'ACHANNELS2': None,
|
|
'ACODEC3': None, 'ACODEC3_ALLOW': [], 'ABITRATE3': None, 'ACHANNELS3': None,
|
|
'SCODEC': 'mov_text',
|
|
},
|
|
'iPhone': {
|
|
'VEXTENSION': '.mp4', 'VCODEC': 'libx264', 'VPRESET': None, 'VFRAMERATE': None, 'VBITRATE': None, 'VCRF': None, 'VLEVEL': None,
|
|
'VRESOLUTION': '460:320', 'VCODEC_ALLOW': ['libx264', 'h264', 'h.264', 'AVC', 'avc', 'mpeg4', 'msmpeg4', 'MPEG-4'],
|
|
'ACODEC': 'aac', 'ACODEC_ALLOW': ['libfaac'], 'ABITRATE': 128000, 'ACHANNELS': 2,
|
|
'ACODEC2': None, 'ACODEC2_ALLOW': [], 'ABITRATE2': None, 'ACHANNELS2': None,
|
|
'ACODEC3': None, 'ACODEC3_ALLOW': [], 'ABITRATE3': None, 'ACHANNELS3': None,
|
|
'SCODEC': 'mov_text',
|
|
},
|
|
'PS3': {
|
|
'VEXTENSION': '.mp4', 'VCODEC': 'libx264', 'VPRESET': None, 'VFRAMERATE': None, 'VBITRATE': None, 'VCRF': None, 'VLEVEL': None,
|
|
'VRESOLUTION': None, 'VCODEC_ALLOW': ['libx264', 'h264', 'h.264', 'AVC', 'avc', 'mpeg4', 'msmpeg4', 'MPEG-4'],
|
|
'ACODEC': 'ac3', 'ACODEC_ALLOW': ['ac3'], 'ABITRATE': None, 'ACHANNELS': 6,
|
|
'ACODEC2': 'aac', 'ACODEC2_ALLOW': ['libfaac'], 'ABITRATE2': None, 'ACHANNELS2': 2,
|
|
'ACODEC3': None, 'ACODEC3_ALLOW': [], 'ABITRATE3': None, 'ACHANNELS3': None,
|
|
'SCODEC': 'mov_text',
|
|
},
|
|
'xbox': {
|
|
'VEXTENSION': '.mp4', 'VCODEC': 'libx264', 'VPRESET': None, 'VFRAMERATE': None, 'VBITRATE': None, 'VCRF': None, 'VLEVEL': None,
|
|
'VRESOLUTION': None, 'VCODEC_ALLOW': ['libx264', 'h264', 'h.264', 'AVC', 'avc', 'mpeg4', 'msmpeg4', 'MPEG-4'],
|
|
'ACODEC': 'ac3', 'ACODEC_ALLOW': ['ac3'], 'ABITRATE': None, 'ACHANNELS': 6,
|
|
'ACODEC2': None, 'ACODEC2_ALLOW': [], 'ABITRATE2': None, 'ACHANNELS2': None,
|
|
'ACODEC3': None, 'ACODEC3_ALLOW': [], 'ABITRATE3': None, 'ACHANNELS3': None,
|
|
'SCODEC': 'mov_text',
|
|
},
|
|
'Roku-480p': {
|
|
'VEXTENSION': '.mp4', 'VCODEC': 'libx264', 'VPRESET': None, 'VFRAMERATE': None, 'VBITRATE': None, 'VCRF': None, 'VLEVEL': None,
|
|
'VRESOLUTION': None, 'VCODEC_ALLOW': ['libx264', 'h264', 'h.264', 'AVC', 'avc', 'mpeg4', 'msmpeg4', 'MPEG-4'],
|
|
'ACODEC': 'aac', 'ACODEC_ALLOW': ['libfaac'], 'ABITRATE': 128000, 'ACHANNELS': 2,
|
|
'ACODEC2': 'ac3', 'ACODEC2_ALLOW': ['ac3'], 'ABITRATE2': None, 'ACHANNELS2': 6,
|
|
'ACODEC3': None, 'ACODEC3_ALLOW': [], 'ABITRATE3': None, 'ACHANNELS3': None,
|
|
'SCODEC': 'mov_text',
|
|
},
|
|
'Roku-720p': {
|
|
'VEXTENSION': '.mp4', 'VCODEC': 'libx264', 'VPRESET': None, 'VFRAMERATE': None, 'VBITRATE': None, 'VCRF': None, 'VLEVEL': None,
|
|
'VRESOLUTION': None, 'VCODEC_ALLOW': ['libx264', 'h264', 'h.264', 'AVC', 'avc', 'mpeg4', 'msmpeg4', 'MPEG-4'],
|
|
'ACODEC': 'aac', 'ACODEC_ALLOW': ['libfaac'], 'ABITRATE': 128000, 'ACHANNELS': 2,
|
|
'ACODEC2': 'ac3', 'ACODEC2_ALLOW': ['ac3'], 'ABITRATE2': None, 'ACHANNELS2': 6,
|
|
'ACODEC3': None, 'ACODEC3_ALLOW': [], 'ABITRATE3': None, 'ACHANNELS3': None,
|
|
'SCODEC': 'mov_text',
|
|
},
|
|
'Roku-1080p': {
|
|
'VEXTENSION': '.mp4', 'VCODEC': 'libx264', 'VPRESET': None, 'VFRAMERATE': None, 'VBITRATE': None, 'VCRF': None, 'VLEVEL': None,
|
|
'VRESOLUTION': None, 'VCODEC_ALLOW': ['libx264', 'h264', 'h.264', 'AVC', 'avc', 'mpeg4', 'msmpeg4', 'MPEG-4'],
|
|
'ACODEC': 'aac', 'ACODEC_ALLOW': ['libfaac'], 'ABITRATE': 160000, 'ACHANNELS': 2,
|
|
'ACODEC2': 'ac3', 'ACODEC2_ALLOW': ['ac3'], 'ABITRATE2': None, 'ACHANNELS2': 6,
|
|
'ACODEC3': None, 'ACODEC3_ALLOW': [], 'ABITRATE3': None, 'ACHANNELS3': None,
|
|
'SCODEC': 'mov_text',
|
|
},
|
|
'mkv': {
|
|
'VEXTENSION': '.mkv', 'VCODEC': 'libx264', 'VPRESET': None, 'VFRAMERATE': None, 'VBITRATE': None, 'VCRF': None, 'VLEVEL': None,
|
|
'VRESOLUTION': None, 'VCODEC_ALLOW': ['libx264', 'h264', 'h.264', 'AVC', 'avc', 'mpeg4', 'msmpeg4', 'MPEG-4', 'mpeg2video'],
|
|
'ACODEC': 'dts', 'ACODEC_ALLOW': ['libfaac', 'dts', 'ac3', 'mp2', 'mp3'], 'ABITRATE': None, 'ACHANNELS': 8,
|
|
'ACODEC2': None, 'ACODEC2_ALLOW': [], 'ABITRATE2': None, 'ACHANNELS2': None,
|
|
'ACODEC3': 'ac3', 'ACODEC3_ALLOW': ['libfaac', 'dts', 'ac3', 'mp2', 'mp3'], 'ABITRATE3': None, 'ACHANNELS3': 8,
|
|
'SCODEC': 'mov_text'
|
|
},
|
|
'mkv-bluray': {
|
|
'VEXTENSION': '.mkv', 'VCODEC': 'libx265', 'VPRESET': None, 'VFRAMERATE': None, 'VBITRATE': None, 'VCRF': None, 'VLEVEL': None,
|
|
'VRESOLUTION': None, 'VCODEC_ALLOW': ['libx264', 'h264', 'h.264', 'hevc', 'h265', 'libx265', 'h.265', 'AVC', 'avc', 'mpeg4', 'msmpeg4', 'MPEG-4', 'mpeg2video'],
|
|
'ACODEC': 'dts', 'ACODEC_ALLOW': ['libfaac', 'dts', 'ac3', 'mp2', 'mp3'], 'ABITRATE': None, 'ACHANNELS': 8,
|
|
'ACODEC2': None, 'ACODEC2_ALLOW': [], 'ABITRATE2': None, 'ACHANNELS2': None,
|
|
'ACODEC3': 'ac3', 'ACODEC3_ALLOW': ['libfaac', 'dts', 'ac3', 'mp2', 'mp3'], 'ABITRATE3': None, 'ACHANNELS3': 8,
|
|
'SCODEC': 'mov_text',
|
|
},
|
|
'mp4-scene-release': {
|
|
'VEXTENSION': '.mp4', 'VCODEC': 'libx264', 'VPRESET': None, 'VFRAMERATE': None, 'VBITRATE': None, 'VCRF': 19, 'VLEVEL': '3.1',
|
|
'VRESOLUTION': None, 'VCODEC_ALLOW': ['libx264', 'h264', 'h.264', 'AVC', 'avc', 'mpeg4', 'msmpeg4', 'MPEG-4', 'mpeg2video'],
|
|
'ACODEC': 'dts', 'ACODEC_ALLOW': ['libfaac', 'dts', 'ac3', 'mp2', 'mp3'], 'ABITRATE': None, 'ACHANNELS': 8,
|
|
'ACODEC2': None, 'ACODEC2_ALLOW': [], 'ABITRATE2': None, 'ACHANNELS2': None,
|
|
'ACODEC3': 'ac3', 'ACODEC3_ALLOW': ['libfaac', 'dts', 'ac3', 'mp2', 'mp3'], 'ABITRATE3': None, 'ACHANNELS3': 8,
|
|
'SCODEC': 'mov_text',
|
|
},
|
|
'MKV-SD': {
|
|
'VEXTENSION': '.mkv', 'VCODEC': 'libx264', 'VPRESET': None, 'VFRAMERATE': None, 'VBITRATE': '1200k', 'VCRF': None, 'VLEVEL': None,
|
|
'VRESOLUTION': '720: -1', 'VCODEC_ALLOW': ['libx264', 'h264', 'h.264', 'AVC', 'avc', 'mpeg4', 'msmpeg4', 'MPEG-4'],
|
|
'ACODEC': 'aac', 'ACODEC_ALLOW': ['libfaac'], 'ABITRATE': 128000, 'ACHANNELS': 2,
|
|
'ACODEC2': 'ac3', 'ACODEC2_ALLOW': ['ac3'], 'ABITRATE2': None, 'ACHANNELS2': 6,
|
|
'ACODEC3': None, 'ACODEC3_ALLOW': [], 'ABITRATE3': None, 'ACHANNELS3': None,
|
|
'SCODEC': 'mov_text',
|
|
},
|
|
}
|
|
if DEFAULTS and DEFAULTS in transcode_defaults:
|
|
VEXTENSION = transcode_defaults[DEFAULTS]['VEXTENSION']
|
|
VCODEC = transcode_defaults[DEFAULTS]['VCODEC']
|
|
VPRESET = transcode_defaults[DEFAULTS]['VPRESET']
|
|
VFRAMERATE = transcode_defaults[DEFAULTS]['VFRAMERATE']
|
|
VBITRATE = transcode_defaults[DEFAULTS]['VBITRATE']
|
|
VRESOLUTION = transcode_defaults[DEFAULTS]['VRESOLUTION']
|
|
VCRF = transcode_defaults[DEFAULTS]['VCRF']
|
|
VLEVEL = transcode_defaults[DEFAULTS]['VLEVEL']
|
|
VCODEC_ALLOW = transcode_defaults[DEFAULTS]['VCODEC_ALLOW']
|
|
ACODEC = transcode_defaults[DEFAULTS]['ACODEC']
|
|
ACODEC_ALLOW = transcode_defaults[DEFAULTS]['ACODEC_ALLOW']
|
|
ACHANNELS = transcode_defaults[DEFAULTS]['ACHANNELS']
|
|
ABITRATE = transcode_defaults[DEFAULTS]['ABITRATE']
|
|
ACODEC2 = transcode_defaults[DEFAULTS]['ACODEC2']
|
|
ACODEC2_ALLOW = transcode_defaults[DEFAULTS]['ACODEC2_ALLOW']
|
|
ACHANNELS2 = transcode_defaults[DEFAULTS]['ACHANNELS2']
|
|
ABITRATE2 = transcode_defaults[DEFAULTS]['ABITRATE2']
|
|
ACODEC3 = transcode_defaults[DEFAULTS]['ACODEC3']
|
|
ACODEC3_ALLOW = transcode_defaults[DEFAULTS]['ACODEC3_ALLOW']
|
|
ACHANNELS3 = transcode_defaults[DEFAULTS]['ACHANNELS3']
|
|
ABITRATE3 = transcode_defaults[DEFAULTS]['ABITRATE3']
|
|
SCODEC = transcode_defaults[DEFAULTS]['SCODEC']
|
|
transcode_defaults = {} # clear memory
|
|
if transcode_defaults in ['mp4-scene-release'] and not OUTPUTQUALITYPERCENT:
|
|
OUTPUTQUALITYPERCENT = 100
|
|
|
|
if VEXTENSION in allow_subs:
|
|
ALLOWSUBS = 1
|
|
if not VCODEC_ALLOW and VCODEC:
|
|
VCODEC_ALLOW.extend([VCODEC])
|
|
for codec in VCODEC_ALLOW:
|
|
if codec in codec_alias:
|
|
extra = [item for item in codec_alias[codec] if item not in VCODEC_ALLOW]
|
|
VCODEC_ALLOW.extend(extra)
|
|
if not ACODEC_ALLOW and ACODEC:
|
|
ACODEC_ALLOW.extend([ACODEC])
|
|
for codec in ACODEC_ALLOW:
|
|
if codec in codec_alias:
|
|
extra = [item for item in codec_alias[codec] if item not in ACODEC_ALLOW]
|
|
ACODEC_ALLOW.extend(extra)
|
|
if not ACODEC2_ALLOW and ACODEC2:
|
|
ACODEC2_ALLOW.extend([ACODEC2])
|
|
for codec in ACODEC2_ALLOW:
|
|
if codec in codec_alias:
|
|
extra = [item for item in codec_alias[codec] if item not in ACODEC2_ALLOW]
|
|
ACODEC2_ALLOW.extend(extra)
|
|
if not ACODEC3_ALLOW and ACODEC3:
|
|
ACODEC3_ALLOW.extend([ACODEC3])
|
|
for codec in ACODEC3_ALLOW:
|
|
if codec in codec_alias:
|
|
extra = [item for item in codec_alias[codec] if item not in ACODEC3_ALLOW]
|
|
ACODEC3_ALLOW.extend(extra)
|
|
|
|
|
|
def configure_passwords_file():
|
|
global PASSWORDS_FILE
|
|
|
|
PASSWORDS_FILE = CFG['passwords']['PassWordFile']
|
|
|
|
|
|
def configure_sections(section):
|
|
global SECTIONS
|
|
global CATEGORIES
|
|
# check for script-defied section and if None set to allow sections
|
|
SECTIONS = CFG[
|
|
tuple(x for x in CFG if CFG[x].sections and CFG[x].isenabled())
|
|
if not section else (section,)
|
|
]
|
|
for section, subsections in SECTIONS.items():
|
|
CATEGORIES.extend([subsection for subsection in subsections if CFG[section][subsection].isenabled()])
|
|
CATEGORIES = list(set(CATEGORIES))
|
|
|
|
|
|
def configure_utility_locations():
|
|
global SHOWEXTRACT
|
|
global SEVENZIP
|
|
global FFMPEG
|
|
global FFPROBE
|
|
global PAR2CMD
|
|
|
|
# Setup FFMPEG, FFPROBE and SEVENZIP locations
|
|
if platform.system() == 'Windows':
|
|
FFMPEG = os.path.join(FFMPEG_PATH, 'ffmpeg.exe')
|
|
FFPROBE = os.path.join(FFMPEG_PATH, 'ffprobe.exe')
|
|
SEVENZIP = os.path.join(APP_ROOT, 'core', 'extractor', 'bin', platform.machine(), '7z.exe')
|
|
SHOWEXTRACT = int(str(CFG['Windows']['show_extraction']), 0)
|
|
|
|
if not (os.path.isfile(FFMPEG)): # problem
|
|
FFMPEG = None
|
|
logger.warning('Failed to locate ffmpeg.exe. Transcoding disabled!')
|
|
logger.warning('Install ffmpeg with x264 support to enable this feature ...')
|
|
|
|
if not (os.path.isfile(FFPROBE)):
|
|
FFPROBE = None
|
|
if CHECK_MEDIA:
|
|
logger.warning('Failed to locate ffprobe.exe. Video corruption detection disabled!')
|
|
logger.warning('Install ffmpeg with x264 support to enable this feature ...')
|
|
|
|
else:
|
|
if SYS_PATH:
|
|
os.environ['PATH'] += ':' + SYS_PATH
|
|
try:
|
|
SEVENZIP = subprocess.Popen(['which', '7z'], stdout=subprocess.PIPE).communicate()[0].strip().decode()
|
|
except Exception:
|
|
pass
|
|
if not SEVENZIP:
|
|
try:
|
|
SEVENZIP = subprocess.Popen(['which', '7zr'], stdout=subprocess.PIPE).communicate()[0].strip().decode()
|
|
except Exception:
|
|
pass
|
|
if not SEVENZIP:
|
|
try:
|
|
SEVENZIP = subprocess.Popen(['which', '7za'], stdout=subprocess.PIPE).communicate()[0].strip().decode()
|
|
except Exception:
|
|
pass
|
|
if not SEVENZIP:
|
|
SEVENZIP = None
|
|
logger.warning(
|
|
'Failed to locate 7zip. Transcoding of disk images and extraction of .7z files will not be possible!')
|
|
try:
|
|
PAR2CMD = subprocess.Popen(['which', 'par2'], stdout=subprocess.PIPE).communicate()[0].strip().decode()
|
|
except Exception:
|
|
pass
|
|
if not PAR2CMD:
|
|
PAR2CMD = None
|
|
logger.warning(
|
|
'Failed to locate par2. Repair and rename using par files will not be possible!')
|
|
if os.path.isfile(os.path.join(FFMPEG_PATH, 'ffmpeg')) or os.access(os.path.join(FFMPEG_PATH, 'ffmpeg'),
|
|
os.X_OK):
|
|
FFMPEG = os.path.join(FFMPEG_PATH, 'ffmpeg')
|
|
elif os.path.isfile(os.path.join(FFMPEG_PATH, 'avconv')) or os.access(os.path.join(FFMPEG_PATH, 'avconv'),
|
|
os.X_OK):
|
|
FFMPEG = os.path.join(FFMPEG_PATH, 'avconv')
|
|
else:
|
|
try:
|
|
FFMPEG = subprocess.Popen(['which', 'ffmpeg'], stdout=subprocess.PIPE).communicate()[0].strip().decode()
|
|
except Exception:
|
|
pass
|
|
if not FFMPEG:
|
|
try:
|
|
FFMPEG = subprocess.Popen(['which', 'avconv'], stdout=subprocess.PIPE).communicate()[0].strip().decode()
|
|
except Exception:
|
|
pass
|
|
if not FFMPEG:
|
|
FFMPEG = None
|
|
logger.warning('Failed to locate ffmpeg. Transcoding disabled!')
|
|
logger.warning('Install ffmpeg with x264 support to enable this feature ...')
|
|
|
|
if os.path.isfile(os.path.join(FFMPEG_PATH, 'ffprobe')) or os.access(os.path.join(FFMPEG_PATH, 'ffprobe'),
|
|
os.X_OK):
|
|
FFPROBE = os.path.join(FFMPEG_PATH, 'ffprobe')
|
|
elif os.path.isfile(os.path.join(FFMPEG_PATH, 'avprobe')) or os.access(os.path.join(FFMPEG_PATH, 'avprobe'),
|
|
os.X_OK):
|
|
FFPROBE = os.path.join(FFMPEG_PATH, 'avprobe')
|
|
else:
|
|
try:
|
|
FFPROBE = subprocess.Popen(['which', 'ffprobe'], stdout=subprocess.PIPE).communicate()[0].strip().decode()
|
|
except Exception:
|
|
pass
|
|
if not FFPROBE:
|
|
try:
|
|
FFPROBE = subprocess.Popen(['which', 'avprobe'], stdout=subprocess.PIPE).communicate()[0].strip().decode()
|
|
except Exception:
|
|
pass
|
|
if not FFPROBE:
|
|
FFPROBE = None
|
|
if CHECK_MEDIA:
|
|
logger.warning('Failed to locate ffprobe. Video corruption detection disabled!')
|
|
logger.warning('Install ffmpeg with x264 support to enable this feature ...')
|
|
|
|
|
|
def check_python():
|
|
"""Check End-of-Life status for Python version."""
|
|
# Raise if end of life
|
|
eol.check()
|
|
|
|
# Warn if within grace period
|
|
grace_period = 365 # days
|
|
eol.warn_for_status(grace_period=-grace_period)
|
|
|
|
# Log warning if within grace period
|
|
days_left = eol.lifetime()
|
|
if days_left > 0:
|
|
logger.info(
|
|
'Python v{major}.{minor} will reach end of life in {x} days.'.format(
|
|
major=sys.version_info[0],
|
|
minor=sys.version_info[1],
|
|
x=days_left,
|
|
),
|
|
)
|
|
else:
|
|
logger.info(
|
|
'Python v{major}.{minor} reached end of life {x} days ago.'.format(
|
|
major=sys.version_info[0],
|
|
minor=sys.version_info[1],
|
|
x=-days_left,
|
|
),
|
|
)
|
|
if days_left <= grace_period:
|
|
logger.warning('Please upgrade to a more recent Python version.')
|
|
|
|
|
|
def initialize(section=None):
|
|
global __INITIALIZED__
|
|
|
|
if __INITIALIZED__:
|
|
return False
|
|
|
|
configure_logging()
|
|
configure_process()
|
|
configure_locale()
|
|
|
|
# init logging
|
|
logger.ntm_log_instance.init_logging()
|
|
|
|
configure_migration()
|
|
configure_logging_part_2()
|
|
|
|
# check python version
|
|
check_python()
|
|
|
|
# initialize the main SB database
|
|
main_db.upgrade_database(main_db.DBConnection(), databases.InitialSchema)
|
|
|
|
configure_general()
|
|
configure_updates()
|
|
configure_wake_on_lan()
|
|
configure_nzbs(CFG)
|
|
configure_torrents(CFG)
|
|
configure_remote_paths()
|
|
configure_plex(CFG)
|
|
configure_niceness()
|
|
configure_containers()
|
|
configure_transcoder()
|
|
configure_passwords_file()
|
|
configure_utility_locations()
|
|
configure_sections(section)
|
|
configure_torrent_class()
|
|
configure_groups()
|
|
|
|
__INITIALIZED__ = True
|
|
|
|
# finished initializing
|
|
return __INITIALIZED__
|