2018-10-31 19:34:40 +00:00
|
|
|
# coding=utf-8
|
|
|
|
|
2018-08-23 19:58:15 +00:00
|
|
|
import os
|
2020-07-27 13:18:13 +00:00
|
|
|
import io
|
2020-06-10 16:04:54 +00:00
|
|
|
import sys
|
|
|
|
import subprocess
|
2019-07-14 22:14:45 +00:00
|
|
|
import subliminal
|
|
|
|
import datetime
|
2021-11-02 22:32:15 +00:00
|
|
|
import time
|
2022-05-18 10:46:52 +00:00
|
|
|
import rarfile
|
2021-11-02 22:32:15 +00:00
|
|
|
|
2022-05-01 12:00:20 +00:00
|
|
|
from dogpile.cache.region import register_backend as register_cache_backend
|
|
|
|
|
2022-12-15 16:00:56 +00:00
|
|
|
from app.config import settings, configure_captcha_func, get_array_from
|
2022-05-01 12:00:20 +00:00
|
|
|
from app.get_args import args
|
|
|
|
from app.logger import configure_logging
|
2022-05-18 10:46:52 +00:00
|
|
|
from utilities.binaries import get_binary, BinaryNotFound
|
2022-05-01 12:00:20 +00:00
|
|
|
from utilities.path_mappings import path_mappings
|
|
|
|
from utilities.backup import restore_from_backup
|
|
|
|
|
2021-11-02 22:32:15 +00:00
|
|
|
# set start time global variable as epoch
|
|
|
|
global startTime
|
|
|
|
startTime = time.time()
|
2019-07-14 22:14:45 +00:00
|
|
|
|
2022-02-23 03:55:07 +00:00
|
|
|
# restore backup if required
|
|
|
|
restore_from_backup()
|
|
|
|
|
2019-04-03 13:56:34 +00:00
|
|
|
# set subliminal_patch user agent
|
2021-08-11 19:35:39 +00:00
|
|
|
os.environ["SZ_USER_AGENT"] = "Bazarr/{}".format(os.environ["BAZARR_VERSION"])
|
2019-04-03 13:56:34 +00:00
|
|
|
|
2018-10-31 19:34:40 +00:00
|
|
|
# Check if args.config_dir exist
|
|
|
|
if not os.path.exists(args.config_dir):
|
2018-08-23 19:58:15 +00:00
|
|
|
# Create config_dir directory tree
|
|
|
|
try:
|
2018-10-31 19:34:40 +00:00
|
|
|
os.mkdir(os.path.join(args.config_dir))
|
2018-08-23 19:58:15 +00:00
|
|
|
except OSError:
|
2019-11-07 00:35:30 +00:00
|
|
|
print("BAZARR The configuration directory doesn't exist and Bazarr cannot create it (permission issue?).")
|
2018-08-23 19:58:15 +00:00
|
|
|
exit(2)
|
|
|
|
|
2018-10-31 19:34:40 +00:00
|
|
|
if not os.path.exists(os.path.join(args.config_dir, 'config')):
|
|
|
|
os.mkdir(os.path.join(args.config_dir, 'config'))
|
|
|
|
if not os.path.exists(os.path.join(args.config_dir, 'db')):
|
|
|
|
os.mkdir(os.path.join(args.config_dir, 'db'))
|
|
|
|
if not os.path.exists(os.path.join(args.config_dir, 'log')):
|
|
|
|
os.mkdir(os.path.join(args.config_dir, 'log'))
|
2019-07-14 22:14:45 +00:00
|
|
|
if not os.path.exists(os.path.join(args.config_dir, 'cache')):
|
|
|
|
os.mkdir(os.path.join(args.config_dir, 'cache'))
|
2022-05-01 12:00:20 +00:00
|
|
|
if not os.path.exists(os.path.join(args.config_dir, 'backup')):
|
|
|
|
os.mkdir(os.path.join(args.config_dir, 'backup'))
|
2022-02-23 03:55:07 +00:00
|
|
|
if not os.path.exists(os.path.join(args.config_dir, 'restore')):
|
|
|
|
os.mkdir(os.path.join(args.config_dir, 'restore'))
|
2019-11-06 05:08:17 +00:00
|
|
|
|
2022-05-01 12:00:20 +00:00
|
|
|
# set subliminal_patch hearing-impaired extension to use when naming subtitles
|
|
|
|
os.environ["SZ_HI_EXTENSION"] = settings.general.hi_extension
|
|
|
|
|
|
|
|
# set anti-captcha provider and key
|
|
|
|
configure_captcha_func()
|
|
|
|
|
2023-03-17 13:58:56 +00:00
|
|
|
# import Google Analytics module to make sure logging is properly configured afterwards
|
|
|
|
from ga4mp import GtagMP # noqa E402
|
2023-03-17 13:01:15 +00:00
|
|
|
|
2022-05-01 12:00:20 +00:00
|
|
|
# configure logging
|
2019-11-06 05:08:17 +00:00
|
|
|
configure_logging(settings.general.getboolean('debug') or args.debug)
|
2022-01-03 03:59:30 +00:00
|
|
|
import logging # noqa E402
|
2019-07-14 22:14:45 +00:00
|
|
|
|
2021-07-27 02:38:42 +00:00
|
|
|
|
|
|
|
def is_virtualenv():
|
|
|
|
# return True if Bazarr have been start from within a virtualenv or venv
|
2021-09-10 02:51:16 +00:00
|
|
|
base_prefix = getattr(sys, "base_prefix", None)
|
2023-01-29 21:44:56 +00:00
|
|
|
# real_prefix will return None if not in a virtualenv environment or the default python path
|
2021-09-10 02:51:16 +00:00
|
|
|
real_prefix = getattr(sys, "real_prefix", None) or sys.prefix
|
|
|
|
return base_prefix != real_prefix
|
2021-07-27 02:38:42 +00:00
|
|
|
|
|
|
|
|
2020-06-10 16:04:54 +00:00
|
|
|
# deploy requirements.txt
|
|
|
|
if not args.no_update:
|
|
|
|
try:
|
2023-04-21 10:25:09 +00:00
|
|
|
import lxml, numpy, webrtcvad, setuptools, PIL # noqa E401
|
2020-06-10 16:04:54 +00:00
|
|
|
except ImportError:
|
|
|
|
try:
|
2022-01-03 03:59:30 +00:00
|
|
|
import pip # noqa W0611
|
2020-06-10 16:04:54 +00:00
|
|
|
except ImportError:
|
|
|
|
logging.info('BAZARR unable to install requirements (pip not installed).')
|
|
|
|
else:
|
2020-09-16 15:21:35 +00:00
|
|
|
if os.path.expanduser("~") == '/':
|
|
|
|
logging.info('BAZARR unable to install requirements (user without home directory).')
|
2020-07-27 13:18:13 +00:00
|
|
|
else:
|
2020-09-16 15:21:35 +00:00
|
|
|
logging.info('BAZARR installing requirements...')
|
2021-05-12 00:11:26 +00:00
|
|
|
try:
|
2021-07-27 02:38:42 +00:00
|
|
|
pip_command = [sys.executable, '-m', 'pip', 'install', '-qq', '--disable-pip-version-check',
|
2021-08-09 13:14:56 +00:00
|
|
|
'-r', os.path.join(os.path.dirname(os.path.dirname(__file__)), 'requirements.txt')]
|
2021-07-27 02:38:42 +00:00
|
|
|
if not is_virtualenv():
|
|
|
|
# --user only make sense if not running under venv
|
|
|
|
pip_command.insert(4, '--user')
|
|
|
|
subprocess.check_output(pip_command, stderr=subprocess.STDOUT)
|
2021-05-12 00:11:26 +00:00
|
|
|
except subprocess.CalledProcessError as e:
|
|
|
|
logging.exception('BAZARR requirements.txt installation result: {}'.format(e.stdout))
|
|
|
|
os._exit(1)
|
|
|
|
else:
|
|
|
|
logging.info('BAZARR requirements installed.')
|
|
|
|
|
2020-09-16 15:21:35 +00:00
|
|
|
try:
|
|
|
|
restart_file = io.open(os.path.join(args.config_dir, "bazarr.restart"), "w", encoding='UTF-8')
|
|
|
|
except Exception as e:
|
2022-05-01 12:00:20 +00:00
|
|
|
logging.error('BAZARR Cannot create restart file: ' + repr(e))
|
2020-09-16 15:21:35 +00:00
|
|
|
else:
|
|
|
|
logging.info('Bazarr is being restarted...')
|
|
|
|
restart_file.write(str(''))
|
|
|
|
restart_file.close()
|
|
|
|
os._exit(0)
|
2020-06-10 16:04:54 +00:00
|
|
|
|
2019-11-27 03:12:16 +00:00
|
|
|
# create random api_key if there's none in config.ini
|
2020-05-22 16:49:02 +00:00
|
|
|
if not settings.auth.apikey or settings.auth.apikey.startswith("b'"):
|
2019-11-27 03:12:16 +00:00
|
|
|
from binascii import hexlify
|
2020-04-17 10:36:45 +00:00
|
|
|
settings.auth.apikey = hexlify(os.urandom(16)).decode()
|
2019-11-27 03:12:16 +00:00
|
|
|
with open(os.path.join(args.config_dir, 'config', 'config.ini'), 'w+') as handle:
|
|
|
|
settings.write(handle)
|
|
|
|
|
2020-07-05 13:16:17 +00:00
|
|
|
# create random Flask secret_key if there's none in config.ini
|
|
|
|
if not settings.general.flask_secret_key:
|
|
|
|
from binascii import hexlify
|
|
|
|
settings.general.flask_secret_key = hexlify(os.urandom(16)).decode()
|
|
|
|
with open(os.path.join(args.config_dir, 'config', 'config.ini'), 'w+') as handle:
|
|
|
|
settings.write(handle)
|
|
|
|
|
2019-12-30 19:28:03 +00:00
|
|
|
# change default base_url to ''
|
2021-03-25 14:22:43 +00:00
|
|
|
settings.general.base_url = settings.general.base_url.rstrip('/')
|
|
|
|
with open(os.path.join(args.config_dir, 'config', 'config.ini'), 'w+') as handle:
|
|
|
|
settings.write(handle)
|
|
|
|
|
|
|
|
# migrate enabled_providers from comma separated string to list
|
|
|
|
if isinstance(settings.general.enabled_providers, str) and not settings.general.enabled_providers.startswith('['):
|
|
|
|
settings.general.enabled_providers = str(settings.general.enabled_providers.split(","))
|
2021-03-30 20:52:23 +00:00
|
|
|
with open(os.path.join(args.config_dir, 'config', 'config.ini'), 'w+') as handle:
|
|
|
|
settings.write(handle)
|
|
|
|
|
2022-01-27 22:52:46 +00:00
|
|
|
# Read package_info (if exists) to override some settings by package maintainers
|
|
|
|
# This file can also provide some info about the package version and author
|
2021-03-31 03:45:59 +00:00
|
|
|
package_info_file = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'package_info')
|
2021-03-30 20:52:23 +00:00
|
|
|
if os.path.isfile(package_info_file):
|
|
|
|
try:
|
2021-04-07 23:39:11 +00:00
|
|
|
splitted_lines = []
|
2021-03-30 20:52:23 +00:00
|
|
|
package_info = {}
|
|
|
|
with open(package_info_file) as file:
|
2021-04-07 23:39:11 +00:00
|
|
|
lines = file.readlines()
|
|
|
|
for line in lines:
|
|
|
|
splitted_lines += line.split(r'\n')
|
|
|
|
for line in splitted_lines:
|
2022-01-27 22:52:46 +00:00
|
|
|
splitted_line = line.split('=', 1)
|
2021-03-30 20:52:23 +00:00
|
|
|
if len(splitted_line) == 2:
|
|
|
|
package_info[splitted_line[0].lower()] = splitted_line[1].replace('\n', '')
|
|
|
|
else:
|
|
|
|
continue
|
2022-01-27 22:52:46 +00:00
|
|
|
# package author can force a branch to follow
|
2021-03-30 20:52:23 +00:00
|
|
|
if 'branch' in package_info:
|
|
|
|
settings.general.branch = package_info['branch']
|
2022-01-27 22:52:46 +00:00
|
|
|
# package author can disable update
|
|
|
|
if package_info.get('updatemethod', '') == 'External':
|
|
|
|
os.environ['BAZARR_UPDATE_ALLOWED'] = '0'
|
|
|
|
os.environ['BAZARR_UPDATE_MESSAGE'] = package_info.get('updatemethodmessage', '')
|
|
|
|
# package author can provide version and contact info
|
|
|
|
os.environ['BAZARR_PACKAGE_VERSION'] = package_info.get('packageversion', '')
|
|
|
|
os.environ['BAZARR_PACKAGE_AUTHOR'] = package_info.get('packageauthor', '')
|
2022-01-03 03:59:30 +00:00
|
|
|
except Exception:
|
2021-03-30 20:52:23 +00:00
|
|
|
pass
|
|
|
|
else:
|
|
|
|
with open(os.path.join(args.config_dir, 'config', 'config.ini'), 'w+') as handle:
|
|
|
|
settings.write(handle)
|
2019-12-30 19:28:03 +00:00
|
|
|
|
2019-07-14 22:14:45 +00:00
|
|
|
# Configure dogpile file caching for Subliminal request
|
|
|
|
register_cache_backend("subzero.cache.file", "subzero.cache_backends.file", "SZFileBackend")
|
|
|
|
subliminal.region.configure('subzero.cache.file', expiration_time=datetime.timedelta(days=30),
|
2022-05-01 12:00:20 +00:00
|
|
|
arguments={'appname': "sz_cache", 'app_cache_dir': args.config_dir},
|
|
|
|
replace_existing_backend=True)
|
2019-07-14 22:14:45 +00:00
|
|
|
subliminal.region.backend.sync()
|
2019-01-15 16:25:13 +00:00
|
|
|
|
2018-11-28 11:53:37 +00:00
|
|
|
if not os.path.exists(os.path.join(args.config_dir, 'config', 'releases.txt')):
|
2022-05-01 12:00:20 +00:00
|
|
|
from app.check_update import check_releases
|
2018-11-02 19:08:07 +00:00
|
|
|
check_releases()
|
|
|
|
logging.debug("BAZARR Created releases file")
|
2018-08-23 19:58:15 +00:00
|
|
|
|
2023-02-20 21:04:09 +00:00
|
|
|
if not os.path.exists(os.path.join(args.config_dir, 'config', 'announcements.txt')):
|
|
|
|
from app.announcements import get_announcements_to_file
|
|
|
|
get_announcements_to_file()
|
|
|
|
logging.debug("BAZARR Created announcements file")
|
|
|
|
|
2018-10-31 19:34:40 +00:00
|
|
|
config_file = os.path.normpath(os.path.join(args.config_dir, 'config', 'config.ini'))
|
2018-08-23 19:58:15 +00:00
|
|
|
|
2021-01-31 13:39:10 +00:00
|
|
|
# Move GA visitor from config.ini to dedicated file
|
|
|
|
if settings.analytics.visitor:
|
|
|
|
with open(os.path.normpath(os.path.join(args.config_dir, 'config', 'analytics.dat')), 'w+') as handle:
|
|
|
|
handle.write(settings.analytics.visitor)
|
|
|
|
with open(os.path.normpath(os.path.join(args.config_dir, 'config', 'config.ini')), 'w+') as handle:
|
|
|
|
settings.remove_option('analytics', 'visitor')
|
|
|
|
settings.write(handle)
|
|
|
|
|
|
|
|
# Clean unused settings from config.ini
|
|
|
|
with open(os.path.normpath(os.path.join(args.config_dir, 'config', 'config.ini')), 'w+') as handle:
|
|
|
|
settings.remove_option('general', 'throtteled_providers')
|
2021-02-26 15:57:47 +00:00
|
|
|
settings.remove_option('general', 'update_restart')
|
2021-01-31 13:39:10 +00:00
|
|
|
settings.write(handle)
|
|
|
|
|
|
|
|
|
2022-12-14 02:14:32 +00:00
|
|
|
# Remove deprecated providers from enabled providers in config.ini
|
2023-04-22 12:25:33 +00:00
|
|
|
from subliminal_patch.extensions import provider_registry # noqa E401
|
2022-12-15 16:00:56 +00:00
|
|
|
existing_providers = provider_registry.names()
|
|
|
|
enabled_providers = get_array_from(settings.general.enabled_providers)
|
|
|
|
settings.general.enabled_providers = str([x for x in enabled_providers if x in existing_providers])
|
|
|
|
with open(os.path.join(args.config_dir, 'config', 'config.ini'), 'w+') as handle:
|
|
|
|
settings.write(handle)
|
2022-12-14 02:14:32 +00:00
|
|
|
|
|
|
|
|
2019-01-26 03:56:55 +00:00
|
|
|
def init_binaries():
|
|
|
|
try:
|
2022-05-18 10:46:52 +00:00
|
|
|
exe = get_binary("unar")
|
|
|
|
rarfile.UNAR_TOOL = exe
|
|
|
|
rarfile.UNRAR_TOOL = None
|
|
|
|
rarfile.tool_setup(unrar=False, unar=True, bsdtar=False, force=True)
|
|
|
|
except (BinaryNotFound, rarfile.RarCannotExec):
|
|
|
|
try:
|
|
|
|
exe = get_binary("unrar")
|
|
|
|
rarfile.UNRAR_TOOL = exe
|
|
|
|
rarfile.UNAR_TOOL = None
|
|
|
|
rarfile.tool_setup(unrar=True, unar=False, bsdtar=False, force=True)
|
|
|
|
except (BinaryNotFound, rarfile.RarCannotExec):
|
|
|
|
logging.exception("BAZARR requires a rar archive extraction utilities (unrar, unar) and it can't be found.")
|
|
|
|
raise BinaryNotFound
|
|
|
|
else:
|
|
|
|
logging.debug("Using UnRAR from: %s", exe)
|
|
|
|
return exe
|
|
|
|
else:
|
|
|
|
logging.debug("Using unar from: %s", exe)
|
|
|
|
return exe
|
2019-01-26 03:56:55 +00:00
|
|
|
|
2019-06-11 18:45:48 +00:00
|
|
|
|
2022-05-26 10:37:12 +00:00
|
|
|
# keep this import at the end to prevent peewee.OperationalError: unable to open database file
|
|
|
|
from app.database import init_db, migrate_db # noqa E402
|
2021-05-27 16:28:46 +00:00
|
|
|
init_db()
|
2021-06-19 04:03:40 +00:00
|
|
|
migrate_db()
|
2019-02-12 21:57:04 +00:00
|
|
|
init_binaries()
|
2020-05-19 13:27:13 +00:00
|
|
|
path_mappings.update()
|