Continue development for new config backend

This commit is contained in:
Halali 2018-12-27 20:19:59 +01:00
parent e9677354a2
commit fcc663af91
25 changed files with 493 additions and 417 deletions

View File

@ -1,22 +1,19 @@
from get_argv import config_dir
from get_settings import get_general_settings
# coding=utf-8
import os
import logging
import sqlite3
import json
import requests
from get_argv import config_dir, no_update
from config import settings
if not no_update:
import git
from get_argv import config_dir
from config import settings
current_working_directory = os.path.dirname(os.path.dirname(__file__))
def gitconfig():
g = git.Repo.init(current_working_directory)
config_read = g.config_reader()
@ -34,6 +31,7 @@ def gitconfig():
logging.debug('BAZARR Settings git email')
config_write.set_value("user", "email", "bazarr@fake.email")
def check_and_apply_update():
gitconfig()
check_releases()

View File

@ -1,53 +1,76 @@
# coding=utf-8
import os
import configparser
from simpleconfigparser import simpleconfigparser
from get_argv import config_dir
defaults = {
'general': {
'ip': '0.0.0.0',
'port': '6767',
'base_url': '/',
'path_mappings': '[]',
'debug': 'False',
'branch': 'master',
'auto_update': 'True',
'single_language': 'False',
'minimum_score': '90',
'use_scenename': 'True',
'use_postprocessing': 'False',
'postprocessing_cmd': '',
'use_sonarr': 'False',
'use_radarr': 'False',
'path_mappings_movie': '[]',
'serie_default_enabled': 'False',
'serie_default_language': '[]',
'serie_default_hi': 'False',
'movie_default_enabled': 'False',
'movie_default_language': [],
'movie_default_hi': 'False',
'page_size': '25',
'minimum_score_movie': '70',
'use_embedded_subs': 'True',
'only_monitored': 'False',
'adaptive_searching': 'False'
},
'auth': {
'type': 'None',
'username': '',
'password': ''
},
'sonarr': {
'ip': '127.0.0.1',
'port': '8989',
'base_url': '/',
'ssl': 'False',
'apikey': '',
'full_update': 'Daily'
},
'radarr': {
'ip': '127.0.0.1',
'port': '7878',
'base_url': '/',
'ssl': 'False',
'apikey': '',
'full_update': 'Daily'
},
'proxy': {
'type': 'None',
'url': '',
'port': '',
'username': '',
'password': '',
'exclude': 'localhost,127.0.0.1'
}}
class _ConfigSection(object):
"""Hold settings for a section of the configuration file."""
settings = simpleconfigparser(defaults=defaults)
settings.read(os.path.join(config_dir, 'config', 'config.ini'))
def __getattr__(self, attr):
if attr in self.__dict__:
return self.__dict__[attr]
else:
raise AttributeError('No "%s" setting in section.' % attr)
def __getitem__(self, item):
return getattr(self, item)
def __repr__(self):
return str(tuple(self.__dict__.keys()))
def read(config_file):
"""Read settings from file and return a dot notation object."""
config = configparser.ConfigParser()
config.read(unicode(config_file))
dotini = _ConfigSection()
for section in config.sections():
s = _ConfigSection()
for key, value in config.items(section):
if value == "True":
value = True
elif value == "False":
value = False
setattr(s, key, value)
setattr(dotini, section, s)
return dotini
settings = read(os.path.join(os.path.join(config_dir, 'config', 'config.ini')))
base_url = settings.general.base_url
# sonarr url
if settings.sonarr.ssl:
if settings.sonarr.getboolean('ssl'):
protocol_sonarr = "https"
else:
protocol_sonarr = "http"
@ -63,7 +86,7 @@ url_sonarr = protocol_sonarr + "://" + settings.sonarr.ip + ":" + settings.sonar
url_sonarr_short = protocol_sonarr + "://" + settings.sonarr.ip + ":" + settings.sonarr.port
# radarr url
if settings.radarr.ssl:
if settings.radarr.getboolean('ssl'):
protocol_radarr = "https"
else:
protocol_radarr = "http"

View File

@ -13,7 +13,7 @@ from list_subtitles import store_subtitles_movie, list_missing_subtitles_movies
def update_movies():
logging.debug('BAZARR Starting movie sync from Radarr.')
apikey_radarr = settings.radarr.apikey
movie_default_enabled = settings.general.movie_default_enabled
movie_default_enabled = settings.general.getboolean('movie_default_enabled')
movie_default_language = settings.general.movie_default_language
movie_default_hi = settings.general.movie_default_hi

View File

@ -11,7 +11,7 @@ from list_subtitles import list_missing_subtitles
def update_series():
apikey_sonarr = settings.sonarr.apikey
serie_default_enabled = settings.general.serie_default_enabled
serie_default_enabled = settings.general.getboolean('serie_default_enabled')
serie_default_language = settings.general.serie_default_language
serie_default_hi = settings.general.serie_default_hi

View File

@ -42,10 +42,10 @@ def download_subtitle(path, language, hi, providers, providers_auth, sceneName,
else:
language_set.add(Language(language))
use_scenename = settings.general.use_scenename
use_scenename = settings.general.getboolean('use_scenename')
minimum_score = settings.general.minimum_score
minimum_score_movie = settings.general.minimum_score_movie
use_postprocessing = settings.general.use_postprocessing
use_postprocessing = settings.general.getboolean('use_postprocessing')
postprocessing_cmd = settings.general.postprocessing_cmd
try:
@ -122,7 +122,7 @@ def download_subtitle(path, language, hi, providers, providers_auth, sceneName,
calculated_score = round(float(compute_score(subtitle, video, hearing_impaired=hi)) / max_score * 100, 2)
if used_sceneName:
video = scan_video(path)
single = settings.general.single_language
single = settings.general.getboolean('single_language')
if single is True:
result = save_subtitles(video, [subtitle], single=True, encoding='utf-8')
else:
@ -193,8 +193,8 @@ def manual_search(path, language, hi, providers, providers_auth, sceneName, medi
else:
language_set.add(Language(lang))
use_scenename = settings.general.use_scenename
use_postprocessing = settings.general.use_postprocessing
use_scenename = settings.general.getboolean('use_scenename')
use_postprocessing = settings.general.getboolean('use_postprocessing')
postprocessing_cmd = settings.general.postprocessing_cmd
try:
@ -265,8 +265,8 @@ def manual_download_subtitle(path, language, hi, subtitle, provider, providers_a
type_of_score = 360
elif media_type == 'movie':
type_of_score = 120
use_scenename = settings.general.use_scenename
use_postprocessing = settings.general.use_postprocessing
use_scenename = settings.general.getboolean('use_scenename')
use_postprocessing = settings.general.getboolean('use_postprocessing')
postprocessing_cmd = settings.general.postprocessing_cmd
language = alpha3_from_alpha2(language)
@ -293,7 +293,7 @@ def manual_download_subtitle(path, language, hi, subtitle, provider, providers_a
logging.exception('BAZARR Error downloading subtitles for this file ' + path)
return None
else:
single = settings.general.single_language
single = settings.general.getboolean('single_language')
try:
score = round(float(compute_score(subtitle, video, hearing_impaired=hi)) / type_of_score * 100, 2)
if used_sceneName == True:
@ -350,7 +350,7 @@ def manual_download_subtitle(path, language, hi, subtitle, provider, providers_a
def series_download_subtitles(no):
if settings.general.only_monitored:
if settings.general.getboolean('only_monitored'):
monitored_only_query_string = ' AND monitored = "True"'
else:
monitored_only_query_string = ""
@ -482,7 +482,7 @@ def wanted_search_missing_subtitles():
db.create_function("path_substitution_movie", 1, path_replace_movie)
c = db.cursor()
if settings.general.only_monitored:
if settings.general.getboolean('only_monitored'):
monitored_only_query_string = ' AND monitored = "True"'
else:
monitored_only_query_string = ""
@ -495,11 +495,11 @@ def wanted_search_missing_subtitles():
c.close()
if settings.general.use_sonarr:
if settings.general.getboolean('use_sonarr'):
for episode in episodes:
wanted_download_subtitles(episode[0])
if settings.general.use_radarr:
if settings.general.getboolean('use_radarr'):
for movie in movies:
wanted_download_subtitles_movie(movie[0])
@ -507,7 +507,7 @@ def wanted_search_missing_subtitles():
def search_active(timestamp):
if settings.general.only_monitored:
if settings.general.getboolean('only_monitored'):
search_deadline = timedelta(weeks=3)
search_delta = timedelta(weeks=1)
aa = datetime.fromtimestamp(float(timestamp))

View File

@ -175,7 +175,7 @@ def list_missing_subtitles(*no):
c_db.close()
missing_subtitles_global = []
use_embedded_subs = settings.general.use_embedded_subs
use_embedded_subs = settings.general.getboolean('use_embedded_subs')
for episode_subtitles in episodes_subtitles:
actual_subtitles_temp = []
actual_subtitles = []
@ -222,7 +222,7 @@ def list_missing_subtitles_movies(*no):
c_db.close()
missing_subtitles_global = []
use_embedded_subs = settings.general.use_embedded_subs
use_embedded_subs = settings.general.getboolean('use_embedded_subs')
for movie_subtitles in movies_subtitles:
actual_subtitles_temp = []
actual_subtitles = []

View File

@ -23,7 +23,7 @@ import logging
from logger import configure_logging, empty_log
from config import settings, url_sonarr, url_radarr, url_radarr_short, url_sonarr_short, base_url
configure_logging(settings.general.debug)
configure_logging(settings.general.getboolean('debug'))
import requests
if settings.proxy.type != 'None':
@ -264,48 +264,38 @@ def save_wizard():
else:
settings_general_use_radarr = 'True'
cfg = ConfigParser()
if not cfg.has_section('general'):
cfg.add_section('general')
settings.general.ip = text_type(settings_general_ip)
settings.general.port = text_type(settings_general_port)
settings.general.base_url = text_type(settings_general_baseurl)
settings.general.path_mappings = text_type(settings_general_pathmapping)
settings.general.debug = text_type(settings.general.getboolean('debug'))
settings.general.branch = text_type(settings.general.branch)
settings.general.auto_update = text_type(settings.general.getboolean('auto_update'))
settings.general.single_language = text_type(settings_general_single_language)
settings.general.minimum_score = text_type(settings.general.minimum_score)
settings.general.use_scenename = text_type(text_type(settings.general.getboolean('use_scenename')))
settings.general.use_postprocessing = text_type(settings.general.getboolean('use_postprocessing'))
settings.general.postprocessing_cmd = text_type(settings.general.postprocessing_cmd)
settings.general.use_sonarr = text_type(settings_general_use_sonarr)
settings.general.use_radarr = text_type(settings_general_use_radarr)
settings.general.path_mappings_movie = text_type(settings_general_pathmapping_movie)
settings.general.page_size = text_type(settings.general.page_size)
settings.general.minimum_score_movie = text_type(settings.general.minimum_score_movie)
settings.general.use_embedded_subs = text_type(settings.general.getboolean('use_embedded_subs'))
settings.general.only_monitored = text_type(settings.general.getboolean('only_monitored'))
settings.general.adaptive_searching = text_type(settings_general_adaptive_searching)
cfg.set('general', 'ip', text_type(settings_general_ip))
cfg.set('general', 'port', text_type(settings_general_port))
cfg.set('general', 'base_url', text_type(settings_general_baseurl))
cfg.set('general', 'path_mappings', text_type(settings_general_pathmapping))
cfg.set('general', 'debug', text_type(settings.general.debug))
cfg.set('general', 'branch', text_type(settings.general.branch))
cfg.set('general', 'auto_update', text_type(settings.general.auto_update))
cfg.set('general', 'single_language', text_type(settings_general_single_language))
cfg.set('general', 'minimum_score', text_type(settings.general.minimum_score))
cfg.set('general', 'use_scenename', text_type(text_type(settings.general.use_scenename)))
cfg.set('general', 'use_postprocessing', text_type(settings.general.use_postprocessing))
cfg.set('general', 'postprocessing_cmd', text_type(settings.general.postprocessing_cmd))
cfg.set('general', 'use_sonarr', text_type(settings_general_use_sonarr))
cfg.set('general', 'use_radarr', text_type(settings_general_use_radarr))
cfg.set('general', 'path_mappings_movie', text_type(settings_general_pathmapping_movie))
cfg.set('general', 'page_size', text_type(settings.general.page_size))
cfg.set('general', 'minimum_score_movie', text_type(settings.general.minimum_score_movie))
cfg.set('general', 'use_embedded_subs', text_type(settings.general.use_embedded_subs))
cfg.set('general', 'only_monitored', text_type(settings.general.only_monitored))
cfg.set('general', 'adaptive_searching', text_type(settings_general_adaptive_searching))
settings.proxy.type = text_type(settings.proxy.type)
settings.proxy.url = text_type(settings.proxy.url)
settings.proxy.port = text_type(settings.proxy.port)
settings.proxy.username = text_type(settings.proxy.username)
settings.proxy.password = text_type(settings.proxy.password)
settings.proxy.exclude = text_type(settings.proxy.exclude)
if not cfg.has_section('proxy'):
cfg.add_section('proxy')
cfg.set('proxy', 'type', text_type(settings.proxy.type))
cfg.set('proxy', 'url', text_type(settings.proxy.url))
cfg.set('proxy', 'port', text_type(settings.proxy.port))
cfg.set('proxy', 'username', text_type(settings.proxy.username))
cfg.set('proxy', 'password', text_type(settings.proxy.password))
cfg.set('proxy', 'exclude', text_type(settings.proxy.exclude))
if not cfg.has_section('auth'):
cfg.add_section('auth')
cfg.set('auth', 'type', text_type(settings.auth.type))
cfg.set('auth', 'username', text_type(settings.auth.username))
cfg.set('auth', 'password', text_type(settings.auth.password))
settings.auth.type = text_type(settings.auth.type)
settings.auth.username = text_type(settings.auth.username)
settings.auth.password = text_type(settings.auth.password)
settings_sonarr_ip = request.forms.get('settings_sonarr_ip')
settings_sonarr_port = request.forms.get('settings_sonarr_port')
@ -317,15 +307,12 @@ def save_wizard():
settings_sonarr_ssl = 'True'
settings_sonarr_apikey = request.forms.get('settings_sonarr_apikey')
if not cfg.has_section('sonarr'):
cfg.add_section('sonarr')
cfg.set('sonarr', 'ip', text_type(settings_sonarr_ip))
cfg.set('sonarr', 'port', text_type(settings_sonarr_port))
cfg.set('sonarr', 'base_url', text_type(settings_sonarr_baseurl))
cfg.set('sonarr', 'ssl', text_type(settings_sonarr_ssl))
cfg.set('sonarr', 'apikey', text_type(settings_sonarr_apikey))
cfg.set('sonarr', 'full_update', text_type(settings.sonarr.full_update))
settings.sonarr.ip = text_type(settings_sonarr_ip)
settings.sonarr.port = text_type(settings_sonarr_port)
settings.sonarr.base_url = text_type(settings_sonarr_baseurl)
settings.sonarr.ssl = text_type(settings_sonarr_ssl)
settings.sonarr.apikey = text_type(settings_sonarr_apikey)
settings.sonarr.full_update = text_type(settings.sonarr.full_update)
settings_radarr_ip = request.forms.get('settings_radarr_ip')
settings_radarr_port = request.forms.get('settings_radarr_port')
@ -337,19 +324,16 @@ def save_wizard():
settings_radarr_ssl = 'True'
settings_radarr_apikey = request.forms.get('settings_radarr_apikey')
if settings_radarr_apikey != '':
cfg.set('general', 'use_radarr', 'True')
settings.general.use_radarr = 'True'
else:
cfg.set('general', 'use_radarr', 'False')
settings.general.use_radarr = 'False'
if not cfg.has_section('radarr'):
cfg.add_section('radarr')
cfg.set('radarr', 'ip', text_type(settings_radarr_ip))
cfg.set('radarr', 'port', text_type(settings_radarr_port))
cfg.set('radarr', 'base_url', text_type(settings_radarr_baseurl))
cfg.set('radarr', 'ssl', text_type(settings_radarr_ssl))
cfg.set('radarr', 'apikey', text_type(settings_radarr_apikey))
cfg.set('radarr', 'full_update', text_type(settings.radarr.full_update))
settings.radarr.ip = text_type(settings_radarr_ip)
settings.radarr.port = text_type(settings_radarr_port)
settings.radarr.base_url = text_type(settings_radarr_baseurl)
settings.radarr.ssl = text_type(settings_radarr_ssl)
settings.radarr.apikey = text_type(settings_radarr_apikey)
settings.radarr.full_update = text_type(settings.radarr.full_update)
settings_subliminal_providers = request.forms.getall('settings_subliminal_providers')
c.execute("UPDATE table_settings_providers SET enabled = 0")
@ -366,41 +350,41 @@ def save_wizard():
settings_serie_default_enabled = 'False'
else:
settings_serie_default_enabled = 'True'
cfg.set('general', 'serie_default_enabled', text_type(settings_serie_default_enabled))
settings.general.serie_default_enabled = text_type(settings_serie_default_enabled)
settings_serie_default_languages = str(request.forms.getall('settings_serie_default_languages'))
if settings_serie_default_languages == "['None']":
settings_serie_default_languages = 'None'
cfg.set('general', 'serie_default_language', text_type(settings_serie_default_languages))
settings.general.serie_default_language = text_type(settings_serie_default_languages)
settings_serie_default_hi = request.forms.get('settings_serie_default_hi')
if settings_serie_default_hi is None:
settings_serie_default_hi = 'False'
else:
settings_serie_default_hi = 'True'
cfg.set('general', 'serie_default_hi', text_type(settings_serie_default_hi))
settings.general.serie_default_hi = text_type(settings_serie_default_hi)
settings_movie_default_enabled = request.forms.get('settings_movie_default_enabled')
if settings_movie_default_enabled is None:
settings_movie_default_enabled = 'False'
else:
settings_movie_default_enabled = 'True'
cfg.set('general', 'movie_default_enabled', text_type(settings_movie_default_enabled))
settings.general.movie_default_enabled = text_type(settings_movie_default_enabled)
settings_movie_default_languages = str(request.forms.getall('settings_movie_default_languages'))
if settings_movie_default_languages == "['None']":
settings_movie_default_languages = 'None'
cfg.set('general', 'movie_default_language', text_type(settings_movie_default_languages))
settings.general.movie_default_language = text_type(settings_movie_default_languages)
settings_movie_default_hi = request.forms.get('settings_movie_default_hi')
if settings_movie_default_hi is None:
settings_movie_default_hi = 'False'
else:
settings_movie_default_hi = 'True'
cfg.set('general', 'movie_default_hi', text_type(settings_movie_default_hi))
settings.general.movie_default_hi = text_type(settings_movie_default_hi)
with open(config_file, 'w+') as f:
cfg.write(f)
with open(os.path.join(config_dir, 'config', 'config.ini'), 'w+') as handle:
settings.write(handle)
logging.info('Config file created successfully')
@ -472,11 +456,11 @@ def image_proxy_movies(url):
@custom_auth_basic(check_credentials)
def redirect_root():
authorize()
if settings.general.use_sonarr is True:
if settings.general.getboolean('use_sonarr'):
redirect(base_url + 'series')
elif settings.general.use_radarr is True:
elif settings.general.getboolean('use_radarr'):
redirect(base_url + 'movies')
elif os.path.exists(os.path.join(config_dir, 'config/config.ini')) is False:
elif not os.path.exists(os.path.join(config_dir, 'config/config.ini')):
redirect(base_url + 'wizard')
else:
redirect(base_url + 'settings')
@ -486,7 +470,7 @@ def redirect_root():
@custom_auth_basic(check_credentials)
def series():
authorize()
single_language = settings.general.single_language
single_language = settings.general.getboolean('single_language')
db = sqlite3.connect(os.path.join(config_dir, 'db', 'bazarr.db'), timeout=30)
db.create_function("path_substitution", 1, path_replace)
@ -502,7 +486,7 @@ def series():
offset = (int(page) - 1) * page_size
max_page = int(math.ceil(missing_count / (page_size + 0.0)))
if settings.general.only_monitored is True:
if settings.general.getboolean('only_monitored'):
monitored_only_query_string = ' AND monitored = "True"'
else:
monitored_only_query_string = ""
@ -527,7 +511,7 @@ def series():
@custom_auth_basic(check_credentials)
def serieseditor():
authorize()
single_language = settings.general.single_language
single_language = settings.general.getboolean('single_language')
db = sqlite3.connect(os.path.join(config_dir, 'db', 'bazarr.db'), timeout=30)
db.create_function("path_substitution", 1, path_replace)
@ -554,14 +538,14 @@ def search_json(query):
c = db.cursor()
search_list = []
if settings.general.use_sonarr is True:
if settings.general.getboolean('use_sonarr'):
c.execute("SELECT title, sonarrSeriesId FROM table_shows WHERE title LIKE ? ORDER BY title",
('%' + query + '%',))
series = c.fetchall()
for serie in series:
search_list.append(dict([('name', serie[0]), ('url', base_url + 'episodes/' + str(serie[1]))]))
if settings.general.use_radarr is True:
if settings.general.getboolean('use_radarr'):
c.execute("SELECT title, radarrId FROM table_movies WHERE title LIKE ? ORDER BY title", ('%' + query + '%',))
movies = c.fetchall()
for movie in movies:
@ -584,7 +568,7 @@ def edit_series(no):
else:
lang = 'None'
single_language = settings.general.single_language
single_language = settings.general.getboolean('single_language')
if single_language is True:
if str(lang) == "['None']":
lang = 'None'
@ -649,7 +633,7 @@ def edit_serieseditor():
@custom_auth_basic(check_credentials)
def episodes(no):
authorize()
# single_language = settings.general.single_language
# single_language = settings.general.getboolean('single_language')
conn = sqlite3.connect(os.path.join(config_dir, 'db', 'bazarr.db'), timeout=30)
conn.create_function("path_substitution", 1, path_replace)
@ -675,7 +659,7 @@ def episodes(no):
@custom_auth_basic(check_credentials)
def movies():
authorize()
single_language = settings.general.single_language
single_language = settings.general.getboolean('single_language')
db = sqlite3.connect(os.path.join(config_dir, 'db', 'bazarr.db'), timeout=30)
db.create_function("path_substitution", 1, path_replace_movie)
@ -704,7 +688,7 @@ def movies():
@custom_auth_basic(check_credentials)
def movieseditor():
authorize()
single_language = settings.general.single_language
single_language = settings.general.getboolean('single_language')
db = sqlite3.connect(os.path.join(config_dir, 'db', 'bazarr.db'), timeout=30)
db.create_function("path_substitution", 1, path_replace_movie)
@ -793,7 +777,7 @@ def edit_movie(no):
@custom_auth_basic(check_credentials)
def movie(no):
authorize()
# single_language = settings.general.single_language
# single_language = settings.general.getboolean('single_language')
conn = sqlite3.connect(os.path.join(config_dir, 'db', 'bazarr.db'), timeout=30)
conn.create_function("path_substitution", 1, path_replace_movie)
@ -952,7 +936,7 @@ def wantedseries():
db.create_function("path_substitution", 1, path_replace)
c = db.cursor()
if settings.general.only_monitored is True:
if settings.general.getboolean('only_monitored'):
monitored_only_query_string = ' AND monitored = "True"'
else:
monitored_only_query_string = ""
@ -981,7 +965,7 @@ def wantedmovies():
db.create_function("path_substitution", 1, path_replace_movie)
c = db.cursor()
if settings.general.only_monitored is True:
if settings.general.getboolean('only_monitored'):
monitored_only_query_string = ' AND monitored = "True"'
else:
monitored_only_query_string = ""
@ -1109,42 +1093,33 @@ def save_settings():
settings_general_use_radarr = 'True'
settings_page_size = request.forms.get('settings_page_size')
before = (unicode(settings.general.ip), int(settings.general.port), unicode(settings.general.base_url), unicode(settings.general.path_mappings), unicode(settings.general.use_sonarr), unicode(settings.general.use_radarr), unicode(settings.general.path_mappings_movie))
before = (unicode(settings.general.ip), int(settings.general.port), unicode(settings.general.base_url), unicode(settings.general.path_mappings), unicode(settings.general.getboolean('use_sonarr')), unicode(settings.general.getboolean('use_radarr')), unicode(settings.general.path_mappings_movie))
after = (unicode(settings_general_ip), int(settings_general_port), unicode(settings_general_baseurl), unicode(settings_general_pathmapping), unicode(settings_general_use_sonarr), unicode(settings_general_use_radarr), unicode(settings_general_pathmapping_movie))
from six import text_type
cfg = ConfigParser()
with open(config_file, 'r') as f:
cfg.read_file(f)
cfg.set('general', 'ip', text_type(settings_general_ip))
cfg.set('general', 'port', text_type(settings_general_port))
cfg.set('general', 'base_url', text_type(settings_general_baseurl))
cfg.set('general', 'path_mappings', text_type(settings_general_pathmapping))
cfg.set('general', 'debug', text_type(settings_general_debug))
cfg.set('general', 'branch', text_type(settings_general_branch))
cfg.set('general', 'auto_update', text_type(settings_general_automatic))
cfg.set('general', 'single_language', text_type(settings_general_single_language))
cfg.set('general', 'minimum_score', text_type(settings_general_minimum_score))
cfg.set('general', 'use_scenename', text_type(settings_general_scenename))
cfg.set('general', 'use_postprocessing', text_type(settings_general_use_postprocessing))
cfg.set('general', 'postprocessing_cmd', text_type(settings_general_postprocessing_cmd))
cfg.set('general', 'use_sonarr', text_type(settings_general_use_sonarr))
cfg.set('general', 'use_radarr', text_type(settings_general_use_radarr))
cfg.set('general', 'path_mappings_movie', text_type(settings_general_pathmapping_movie))
cfg.set('general', 'page_size', text_type(settings_page_size))
cfg.set('general', 'minimum_score_movie', text_type(settings_general_minimum_score_movies))
cfg.set('general', 'use_embedded_subs', text_type(settings_general_embedded))
cfg.set('general', 'only_monitored', text_type(settings_general_only_monitored))
cfg.set('general', 'adaptive_searching', text_type(settings_general_adaptive_searching))
settings.general.ip = text_type(settings_general_ip)
settings.general.port = text_type(settings_general_port)
settings.general.base_url = text_type(settings_general_baseurl)
settings.general.path_mappings = text_type(settings_general_pathmapping)
settings.general.debug = text_type(settings_general_debug)
settings.general.branch = text_type(settings_general_branch)
settings.general.auto_update = text_type(settings_general_automatic)
settings.general.single_language = text_type(settings_general_single_language)
settings.general.minimum_score = text_type(settings_general_minimum_score)
settings.general.use_scenename = text_type(settings_general_scenename)
settings.general.use_postprocessing = text_type(settings_general_use_postprocessing)
settings.general.postprocessing_cmd = text_type(settings_general_postprocessing_cmd)
settings.general.use_sonarr = text_type(settings_general_use_sonarr)
settings.general.use_radarr = text_type(settings_general_use_radarr)
settings.general.path_mappings_movie = text_type(settings_general_pathmapping_movie)
settings.general.page_size = text_type(settings_page_size)
settings.general.minimum_score_movie = text_type(settings_general_minimum_score_movies)
settings.general.use_embedded_subs = text_type(settings_general_embedded)
settings.general.only_monitored = text_type(settings_general_only_monitored)
settings.general.adaptive_searching = text_type(settings_general_adaptive_searching)
if after != before:
configured()
if not cfg.has_section('proxy'):
cfg.add_section('proxy')
settings_proxy_type = request.forms.get('settings_proxy_type')
settings_proxy_url = request.forms.get('settings_proxy_url')
settings_proxy_port = request.forms.get('settings_proxy_port')
@ -1156,18 +1131,18 @@ def save_settings():
if before_proxy_password[0] != settings_proxy_type:
configured()
if before_proxy_password[1] == settings_proxy_password:
cfg.set('proxy', 'type', text_type(settings_proxy_type))
cfg.set('proxy', 'url', text_type(settings_proxy_url))
cfg.set('proxy', 'port', text_type(settings_proxy_port))
cfg.set('proxy', 'username', text_type(settings_proxy_username))
cfg.set('proxy', 'exclude', text_type(settings_proxy_exclude))
settings.proxy.type = text_type(settings_proxy_type)
settings.proxy.url = text_type(settings_proxy_url)
settings.proxy.port = text_type(settings_proxy_port)
settings.proxy.username = text_type(settings_proxy_username)
settings.proxy.exclude = text_type(settings_proxy_exclude)
else:
cfg.set('proxy', 'type', text_type(settings_proxy_type))
cfg.set('proxy', 'url', text_type(settings_proxy_url))
cfg.set('proxy', 'port', text_type(settings_proxy_port))
cfg.set('proxy', 'username', text_type(settings_proxy_username))
cfg.set('proxy', 'password', text_type(settings_proxy_password))
cfg.set('proxy', 'exclude', text_type(settings_proxy_exclude))
settings.proxy.type = text_type(settings_proxy_type)
settings.proxy.url = text_type(settings_proxy_url)
settings.proxy.port = text_type(settings_proxy_port)
settings.proxy.username = text_type(settings_proxy_username)
settings.proxy.password = text_type(settings_proxy_password)
settings.proxy.exclude = text_type(settings_proxy_exclude)
settings_auth_type = request.forms.get('settings_auth_type')
settings_auth_username = request.forms.get('settings_auth_username')
@ -1176,12 +1151,12 @@ def save_settings():
if settings.auth.type != settings_auth_type:
configured()
if settings.auth.password == settings_auth_password:
cfg.set('auth', 'type', text_type(settings_auth_type))
cfg.set('auth', 'username', text_type(settings_auth_username))
settings.auth.type = text_type(settings_auth_type)
settings.auth.username = text_type(settings_auth_username)
else:
cfg.set('auth', 'type', text_type(settings_auth_type))
cfg.set('auth', 'username', text_type(settings_auth_username))
cfg.set('auth', 'password', hashlib.md5(settings_auth_password).hexdigest())
settings.auth.type = text_type(settings_auth_type)
settings.auth.username = text_type(settings_auth_username)
settings.auth.password = hashlib.md5(settings_auth_password).hexdigest()
if settings_auth_username not in aaa._store.users:
cork = Cork(os.path.normpath(os.path.join(config_dir, 'config')), initialize=True)
cork._store.roles[''] = 100
@ -1217,12 +1192,12 @@ def save_settings():
settings_sonarr_apikey = request.forms.get('settings_sonarr_apikey')
settings_sonarr_sync = request.forms.get('settings_sonarr_sync')
cfg.set('sonarr', 'ip', text_type(settings_sonarr_ip))
cfg.set('sonarr', 'port', text_type(settings_sonarr_port))
cfg.set('sonarr', 'base_url', text_type(settings_sonarr_baseurl))
cfg.set('sonarr', 'ssl', text_type(settings_sonarr_ssl))
cfg.set('sonarr', 'apikey', text_type(settings_sonarr_apikey))
cfg.set('sonarr', 'full_update', text_type(settings_sonarr_sync))
settings.sonarr.ip = text_type(settings_sonarr_ip)
settings.sonarr.port = text_type(settings_sonarr_port)
settings.sonarr.base_url = text_type(settings_sonarr_baseurl)
settings.sonarr.ssl = text_type(settings_sonarr_ssl)
settings.sonarr.apikey = text_type(settings_sonarr_apikey)
settings.sonarr.full_update = text_type(settings_sonarr_sync)
settings_radarr_ip = request.forms.get('settings_radarr_ip')
settings_radarr_port = request.forms.get('settings_radarr_port')
@ -1235,12 +1210,12 @@ def save_settings():
settings_radarr_apikey = request.forms.get('settings_radarr_apikey')
settings_radarr_sync = request.forms.get('settings_radarr_sync')
cfg.set('radarr', 'ip', text_type(settings_radarr_ip))
cfg.set('radarr', 'port', text_type(settings_radarr_port))
cfg.set('radarr', 'base_url', text_type(settings_radarr_baseurl))
cfg.set('radarr', 'ssl', text_type(settings_radarr_ssl))
cfg.set('radarr', 'apikey', text_type(settings_radarr_apikey))
cfg.set('radarr', 'full_update', text_type(settings_radarr_sync))
settings.radarr.ip = text_type(settings_radarr_ip)
settings.radarr.port = text_type(settings_radarr_port)
settings.radarr.base_url = text_type(settings_radarr_baseurl)
settings.radarr.ssl = text_type(settings_radarr_ssl)
settings.radarr.apikey = text_type(settings_radarr_apikey)
settings.radarr.full_update = text_type(settings_radarr_sync)
settings_subliminal_providers = request.forms.getall('settings_subliminal_providers')
c.execute("UPDATE table_settings_providers SET enabled = 0")
@ -1267,43 +1242,43 @@ def save_settings():
settings_serie_default_enabled = 'False'
else:
settings_serie_default_enabled = 'True'
cfg.set('general', 'serie_default_enabled', text_type(settings_serie_default_enabled))
settings.general.serie_default_enabled = text_type(settings_serie_default_enabled)
settings_serie_default_languages = str(request.forms.getall('settings_serie_default_languages'))
if settings_serie_default_languages == "['None']":
settings_serie_default_languages = 'None'
cfg.set('general', 'serie_default_language', text_type(settings_serie_default_languages))
settings.general.serie_default_language = text_type(settings_serie_default_languages)
settings_serie_default_hi = request.forms.get('settings_serie_default_hi')
if settings_serie_default_hi is None:
settings_serie_default_hi = 'False'
else:
settings_serie_default_hi = 'True'
cfg.set('general', 'serie_default_hi', text_type(settings_serie_default_hi))
settings.general.serie_default_hi = text_type(settings_serie_default_hi)
settings_movie_default_enabled = request.forms.get('settings_movie_default_enabled')
if settings_movie_default_enabled is None:
settings_movie_default_enabled = 'False'
else:
settings_movie_default_enabled = 'True'
cfg.set('general', 'movie_default_enabled', text_type(settings_movie_default_enabled))
settings.general.movie_default_enabled = text_type(settings_movie_default_enabled)
settings_movie_default_languages = str(request.forms.getall('settings_movie_default_languages'))
if settings_movie_default_languages == "['None']":
settings_movie_default_languages = 'None'
cfg.set('general', 'movie_default_language', text_type(settings_movie_default_languages))
settings.general.movie_default_language = text_type(settings_movie_default_languages)
settings_movie_default_hi = request.forms.get('settings_movie_default_hi')
if settings_movie_default_hi is None:
settings_movie_default_hi = 'False'
else:
settings_movie_default_hi = 'True'
cfg.set('general', 'movie_default_hi', text_type(settings_movie_default_hi))
settings.general.movie_default_hi = text_type(settings_movie_default_hi)
with open(config_file, 'wb') as f:
cfg.write(f)
with open(os.path.join(config_dir, 'config', 'config.ini'), 'w+') as handle:
settings.write(handle)
configure_logging(settings.general.debug)
configure_logging(settings.general.getboolean('debug'))
notifiers = c.execute("SELECT * FROM table_settings_notifier ORDER BY name").fetchall()
for notifier in notifiers:
@ -1450,7 +1425,7 @@ def system():
releases = ast.literal_eval(f.read())
import platform
use_sonarr = settings.general.use_sonarr
use_sonarr = settings.general.getboolean('use_sonarr')
apikey_sonarr = settings.sonarr.apikey
sv = url_sonarr + "/api/system/status?apikey=" + apikey_sonarr
sonarr_version = ''
@ -1460,7 +1435,7 @@ def system():
except:
pass
use_radarr = settings.general.use_radarr
use_radarr = settings.general.getboolean('use_radarr')
apikey_radarr = settings.radarr.apikey
rv = url_radarr + "/api/system/status?apikey=" + apikey_radarr
radarr_version = ''

View File

@ -19,7 +19,7 @@ from tzlocal import get_localzone
def sonarr_full_update():
if settings.general.use_sonarr:
if settings.general.getboolean('use_sonarr'):
full_update = settings.sonarr.full_update
if full_update == "Daily":
scheduler.add_job(update_all_episodes, CronTrigger(hour=4), max_instances=1, coalesce=True,
@ -36,7 +36,7 @@ def sonarr_full_update():
def radarr_full_update():
if settings.general.use_radarr:
if settings.general.getboolean('use_radarr'):
full_update = settings.radarr.full_update
if full_update == "Daily":
scheduler.add_job(update_all_movies, CronTrigger(hour=5), max_instances=1, coalesce=True, misfire_grace_time=15,
@ -70,14 +70,14 @@ else:
scheduler.add_job(check_releases, IntervalTrigger(hours=6), max_instances=1, coalesce=True, misfire_grace_time=15,
id='update_release', name='Update release info')
if settings.general.use_sonarr:
if settings.general.getboolean('use_sonarr'):
scheduler.add_job(update_series, IntervalTrigger(minutes=1), max_instances=1, coalesce=True, misfire_grace_time=15, id='update_series', name='Update series list from Sonarr')
scheduler.add_job(sync_episodes, IntervalTrigger(minutes=5), max_instances=1, coalesce=True, misfire_grace_time=15, id='sync_episodes', name='Sync episodes with Sonarr')
if settings.general.use_radarr:
if settings.general.getboolean('use_radarr'):
scheduler.add_job(update_movies, IntervalTrigger(minutes=5), max_instances=1, coalesce=True, misfire_grace_time=15, id='update_movies', name='Update movies list from Radarr')
if settings.general.use_sonarr or settings.general.use_radarr:
if settings.general.getboolean('use_sonarr') or settings.general.getboolean('use_radarr'):
scheduler.add_job(wanted_search_missing_subtitles, IntervalTrigger(hours=3), max_instances=1, coalesce=True, misfire_grace_time=15, id='wanted_search_missing_subtitles', name='Search for wanted subtitles')
sonarr_full_update()

View File

@ -73,9 +73,9 @@ if os.path.exists(os.path.join(config_dir, 'db', 'bazarr.db')):
except:
pass
else:
if settings.general.use_sonarr:
if settings.general.getboolean('use_sonarr'):
execute_now('sync_episodes')
if settings.general.use_radarr:
if settings.general.getboolean('use_radarr'):
execute_now('update_movies')
try:
@ -84,7 +84,7 @@ if os.path.exists(os.path.join(config_dir, 'db', 'bazarr.db')):
except:
pass
else:
if settings.general.use_sonarr:
if settings.general.getboolean('use_sonarr'):
execute_now('sync_episodes')
try:
@ -93,7 +93,7 @@ if os.path.exists(os.path.join(config_dir, 'db', 'bazarr.db')):
except:
pass
else:
if settings.general.use_radarr:
if settings.general.getboolean('use_radarr'):
execute_now('update_movies')
db.close()

View File

@ -1 +1,11 @@
__path__ = __import__('pkgutil').extend_path(__path__, __name__)
# A Python "namespace package" http://www.python.org/dev/peps/pep-0382/
# This always goes inside of a namespace package's __init__.py
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)
try:
import pkg_resources
pkg_resources.declare_namespace(__name__)
except ImportError:
pass

View File

@ -20,8 +20,7 @@ ConfigParser -- responsible for parsing a list of
__init__(defaults=None, dict_type=_default_dict, allow_no_value=False,
delimiters=('=', ':'), comment_prefixes=('#', ';'),
inline_comment_prefixes=None, strict=True,
empty_lines_in_values=True, default_section='DEFAULT',
interpolation=<unset>, converters=<unset>):
empty_lines_in_values=True):
Create the parser. When `defaults' is given, it is initialized into the
dictionary or intrinsic defaults. The keys must be strings, the values
must be appropriate for %()s string interpolation.
@ -135,17 +134,15 @@ import re
import sys
import warnings
from backports.configparser.helpers import OrderedDict as _default_dict
from backports.configparser.helpers import ChainMap as _ChainMap
from backports.configparser.helpers import from_none, open, str, PY2
from backports.configparser2.helpers import OrderedDict as _default_dict
from backports.configparser2.helpers import ChainMap as _ChainMap
from backports.configparser2.helpers import from_none, open, str, PY2
__all__ = ["NoSectionError", "DuplicateOptionError", "DuplicateSectionError",
"NoOptionError", "InterpolationError", "InterpolationDepthError",
"InterpolationMissingOptionError", "InterpolationSyntaxError",
"ParsingError", "MissingSectionHeaderError",
"InterpolationSyntaxError", "ParsingError",
"MissingSectionHeaderError",
"ConfigParser", "SafeConfigParser", "RawConfigParser",
"Interpolation", "BasicInterpolation", "ExtendedInterpolation",
"LegacyInterpolation", "SectionProxy", "ConverterMapping",
"DEFAULTSECT", "MAX_INTERPOLATION_DEPTH"]
DEFAULTSECT = "DEFAULT"
@ -254,9 +251,12 @@ class InterpolationMissingOptionError(InterpolationError):
"""A string substitution required a setting which was not available."""
def __init__(self, option, section, rawval, reference):
msg = ("Bad value substitution: option {0!r} in section {1!r} contains "
"an interpolation key {2!r} which is not a valid option name. "
"Raw value: {3!r}".format(option, section, reference, rawval))
msg = ("Bad value substitution:\n"
"\tsection: [%s]\n"
"\toption : %s\n"
"\tkey : %s\n"
"\trawval : %s\n"
% (section, option, reference, rawval))
InterpolationError.__init__(self, option, section, msg)
self.reference = reference
self.args = (option, section, rawval, reference)
@ -274,11 +274,11 @@ class InterpolationDepthError(InterpolationError):
"""Raised when substitutions are nested too deeply."""
def __init__(self, option, section, rawval):
msg = ("Recursion limit exceeded in value substitution: option {0!r} "
"in section {1!r} contains an interpolation key which "
"cannot be substituted in {2} steps. Raw value: {3!r}"
"".format(option, section, MAX_INTERPOLATION_DEPTH,
rawval))
msg = ("Value interpolation too deeply recursive:\n"
"\tsection: [%s]\n"
"\toption : %s\n"
"\trawval : %s\n"
% (section, option, rawval))
InterpolationError.__init__(self, option, section, msg)
self.args = (option, section, rawval)
@ -374,7 +374,7 @@ class BasicInterpolation(Interpolation):
would resolve the "%(dir)s" to the value of dir. All reference
expansions are done late, on demand. If a user needs to use a bare % in
a configuration file, she can escape it by writing %%. Other % usage
a configuration file, she can escape it by writing %%. Other other % usage
is considered a user error and raises `InterpolationSyntaxError'."""
_KEYCRE = re.compile(r"%\(([^)]+)\)s")
@ -394,9 +394,8 @@ class BasicInterpolation(Interpolation):
def _interpolate_some(self, parser, option, accum, rest, section, map,
depth):
rawval = parser.get(section, option, raw=True, fallback=rest)
if depth > MAX_INTERPOLATION_DEPTH:
raise InterpolationDepthError(option, section, rawval)
raise InterpolationDepthError(option, section, rest)
while rest:
p = rest.find("%")
if p < 0:
@ -421,7 +420,7 @@ class BasicInterpolation(Interpolation):
v = map[var]
except KeyError:
raise from_none(InterpolationMissingOptionError(
option, section, rawval, var))
option, section, rest, var))
if "%" in v:
self._interpolate_some(parser, option, accum, v,
section, map, depth + 1)
@ -455,9 +454,8 @@ class ExtendedInterpolation(Interpolation):
def _interpolate_some(self, parser, option, accum, rest, section, map,
depth):
rawval = parser.get(section, option, raw=True, fallback=rest)
if depth > MAX_INTERPOLATION_DEPTH:
raise InterpolationDepthError(option, section, rawval)
raise InterpolationDepthError(option, section, rest)
while rest:
p = rest.find("$")
if p < 0:
@ -494,7 +492,7 @@ class ExtendedInterpolation(Interpolation):
"More than one ':' found: %r" % (rest,))
except (KeyError, NoSectionError, NoOptionError):
raise from_none(InterpolationMissingOptionError(
option, section, rawval, ":".join(path)))
option, section, rest, ":".join(path)))
if "$" in v:
self._interpolate_some(parser, opt, accum, v, sect,
dict(parser.items(sect, raw=True)),
@ -598,12 +596,10 @@ class RawConfigParser(MutableMapping):
empty_lines_in_values = kwargs.get('empty_lines_in_values', True)
default_section = kwargs.get('default_section', DEFAULTSECT)
interpolation = kwargs.get('interpolation', _UNSET)
converters = kwargs.get('converters', _UNSET)
self._dict = dict_type
self._sections = self._dict()
self._defaults = self._dict()
self._converters = ConverterMapping(self)
self._proxies = self._dict()
self._proxies[default_section] = SectionProxy(self, default_section)
if defaults:
@ -631,8 +627,6 @@ class RawConfigParser(MutableMapping):
self._interpolation = self._DEFAULT_INTERPOLATION
if self._interpolation is None:
self._interpolation = Interpolation()
if converters is not _UNSET:
self._converters.update(converters)
def defaults(self):
return self._defaults
@ -813,40 +807,48 @@ class RawConfigParser(MutableMapping):
def _get(self, section, conv, option, **kwargs):
return conv(self.get(section, option, **kwargs))
def _get_conv(self, section, option, conv, **kwargs):
def getint(self, section, option, **kwargs):
# keyword-only arguments
kwargs.setdefault('raw', False)
kwargs.setdefault('vars', None)
fallback = kwargs.pop('fallback', _UNSET)
raw = kwargs.get('raw', False)
vars = kwargs.get('vars', None)
fallback = kwargs.get('fallback', _UNSET)
try:
return self._get(section, conv, option, **kwargs)
return self._get(section, int, option, raw=raw, vars=vars)
except (NoSectionError, NoOptionError):
if fallback is _UNSET:
raise
return fallback
# getint, getfloat and getboolean provided directly for backwards compat
def getint(self, section, option, **kwargs):
# keyword-only arguments
kwargs.setdefault('raw', False)
kwargs.setdefault('vars', None)
kwargs.setdefault('fallback', _UNSET)
return self._get_conv(section, option, int, **kwargs)
else:
return fallback
def getfloat(self, section, option, **kwargs):
# keyword-only arguments
kwargs.setdefault('raw', False)
kwargs.setdefault('vars', None)
kwargs.setdefault('fallback', _UNSET)
return self._get_conv(section, option, float, **kwargs)
raw = kwargs.get('raw', False)
vars = kwargs.get('vars', None)
fallback = kwargs.get('fallback', _UNSET)
try:
return self._get(section, float, option, raw=raw, vars=vars)
except (NoSectionError, NoOptionError):
if fallback is _UNSET:
raise
else:
return fallback
def getboolean(self, section, option, **kwargs):
# keyword-only arguments
kwargs.setdefault('raw', False)
kwargs.setdefault('vars', None)
kwargs.setdefault('fallback', _UNSET)
return self._get_conv(section, option, self._convert_to_boolean,
**kwargs)
raw = kwargs.get('raw', False)
vars = kwargs.get('vars', None)
fallback = kwargs.get('fallback', _UNSET)
try:
return self._get(section, self._convert_to_boolean, option,
raw=raw, vars=vars)
except (NoSectionError, NoOptionError):
if fallback is _UNSET:
raise
else:
return fallback
def items(self, section=_UNSET, raw=False, vars=None):
"""Return a list of (name, value) tuples for each option in a section.
@ -1222,10 +1224,6 @@ class RawConfigParser(MutableMapping):
return section, option, value
@property
def converters(self):
return self._converters
class ConfigParser(RawConfigParser):
"""ConfigParser implementing interpolation."""
@ -1266,10 +1264,6 @@ class SectionProxy(MutableMapping):
"""Creates a view on a section of the specified `name` in `parser`."""
self._parser = parser
self._name = name
for conv in parser.converters:
key = 'get' + conv
getter = functools.partial(self.get, _impl=getattr(parser, key))
setattr(self, key, getter)
def __repr__(self):
return '<Section: {0}>'.format(self._name)
@ -1303,6 +1297,38 @@ class SectionProxy(MutableMapping):
else:
return self._parser.defaults()
def get(self, option, fallback=None, **kwargs):
# keyword-only arguments
raw = kwargs.get('raw', False)
vars = kwargs.get('vars', None)
return self._parser.get(self._name, option, raw=raw, vars=vars,
fallback=fallback)
def getint(self, option, fallback=None, **kwargs):
# keyword-only arguments
raw = kwargs.get('raw', False)
vars = kwargs.get('vars', None)
return self._parser.getint(self._name, option, raw=raw, vars=vars,
fallback=fallback)
def getfloat(self, option, fallback=None, **kwargs):
# keyword-only arguments
raw = kwargs.get('raw', False)
vars = kwargs.get('vars', None)
return self._parser.getfloat(self._name, option, raw=raw, vars=vars,
fallback=fallback)
def getboolean(self, option, fallback=None, **kwargs):
# keyword-only arguments
raw = kwargs.get('raw', False)
vars = kwargs.get('vars', None)
return self._parser.getboolean(self._name, option, raw=raw, vars=vars,
fallback=fallback)
@property
def parser(self):
# The parser object of the proxy is read-only.
@ -1312,79 +1338,3 @@ class SectionProxy(MutableMapping):
def name(self):
# The name of the section on a proxy is read-only.
return self._name
def get(self, option, fallback=None, **kwargs):
"""Get an option value.
Unless `fallback` is provided, `None` will be returned if the option
is not found.
"""
# keyword-only arguments
kwargs.setdefault('raw', False)
kwargs.setdefault('vars', None)
_impl = kwargs.pop('_impl', None)
# If `_impl` is provided, it should be a getter method on the parser
# object that provides the desired type conversion.
if not _impl:
_impl = self._parser.get
return _impl(self._name, option, fallback=fallback, **kwargs)
class ConverterMapping(MutableMapping):
"""Enables reuse of get*() methods between the parser and section proxies.
If a parser class implements a getter directly, the value for the given
key will be ``None``. The presence of the converter name here enables
section proxies to find and use the implementation on the parser class.
"""
GETTERCRE = re.compile(r"^get(?P<name>.+)$")
def __init__(self, parser):
self._parser = parser
self._data = {}
for getter in dir(self._parser):
m = self.GETTERCRE.match(getter)
if not m or not callable(getattr(self._parser, getter)):
continue
self._data[m.group('name')] = None # See class docstring.
def __getitem__(self, key):
return self._data[key]
def __setitem__(self, key, value):
try:
k = 'get' + key
except TypeError:
raise ValueError('Incompatible key: {} (type: {})'
''.format(key, type(key)))
if k == 'get':
raise ValueError('Incompatible key: cannot use "" as a name')
self._data[key] = value
func = functools.partial(self._parser._get_conv, conv=value)
func.converter = value
setattr(self._parser, k, func)
for proxy in self._parser.values():
getter = functools.partial(proxy.get, _impl=func)
setattr(proxy, k, getter)
def __delitem__(self, key):
try:
k = 'get' + (key or None)
except TypeError:
raise KeyError(key)
del self._data[key]
for inst in itertools.chain((self._parser,), self._parser.values()):
try:
delattr(inst, k)
except AttributeError:
# don't raise since the entry was present in _data, silently
# clean up
continue
def __iter__(self):
return iter(self._data)
def __len__(self):
return len(self._data)

View File

@ -9,7 +9,7 @@ from __future__ import print_function
from __future__ import unicode_literals
from backports.configparser import (
from backports.configparser2 import (
RawConfigParser,
ConfigParser,
SafeConfigParser,
@ -31,7 +31,6 @@ from backports.configparser import (
InterpolationDepthError,
ParsingError,
MissingSectionHeaderError,
ConverterMapping,
_UNSET,
DEFAULTSECT,
@ -39,14 +38,3 @@ from backports.configparser import (
_default_dict,
_ChainMap,
)
__all__ = ["NoSectionError", "DuplicateOptionError", "DuplicateSectionError",
"NoOptionError", "InterpolationError", "InterpolationDepthError",
"InterpolationMissingOptionError", "InterpolationSyntaxError",
"ParsingError", "MissingSectionHeaderError",
"ConfigParser", "SafeConfigParser", "RawConfigParser",
"Interpolation", "BasicInterpolation", "ExtendedInterpolation",
"LegacyInterpolation", "SectionProxy", "ConverterMapping",
"DEFAULTSECT", "MAX_INTERPOLATION_DEPTH"]
# NOTE: names missing from __all__ imported anyway for backwards compatibility.

View File

@ -0,0 +1,131 @@
# -*- coding: utf-8 -*-
"""
The MIT License
Copyright (c) 2013 Helgi Þorbjörnsson <helgi@php.net>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""
try:
from configparser import ConfigParser as configparser, NoOptionError, NoSectionError
except ImportError:
from ConfigParser import SafeConfigParser as configparser, NoOptionError, NoSectionError
class simpleconfigparser(configparser):
class Section(dict):
"""
Contain the section specific items that can be accessed via object properties
"""
parser = None
section = None
def __init__(self, section, parser):
self.section = section
self.parser = parser
def __getitem__(self, name, raw=False, vars=None):
"""Fetch a value via the dict handler"""
if name not in simpleconfigparser.Section.__dict__:
return self.parser.get(self.section, name, raw, vars)
def __setitem__(self, name, value):
"""Set a value via the dict handler"""
if name in simpleconfigparser.Section.__dict__:
return dict.__setitem__(self, name, value)
return self.parser.set(self.section, name, value)
def __getattr__(self, name, raw=False, vars=None):
"""Fetch a value via the object handler"""
if name not in simpleconfigparser.Section.__dict__:
return self.parser.get(self.section, name, raw, vars)
def __setattr__(self, name, value):
"""Set a value via the object handler"""
if name in simpleconfigparser.Section.__dict__:
return object.__setattr__(self, name, value)
return self.parser.set(self.section, name, value)
def getboolean(self, name):
if not self.section:
return None
return self.parser.getboolean(self.section, name)
def items(self):
if not self.section:
return None
items = []
for key, value in self.parser.items(self.section):
# strip quotes
items.append((key, value.strip('"\'')))
return items
def __init__(self, defaults=None, *args, **kwargs):
configparser.__init__(self, defaults=None, *args, **kwargs)
# Improved defaults handling
if isinstance(defaults, dict):
for section, values in defaults.items():
# Break out original format defaults was passed in
if not isinstance(values, dict):
break
if section not in self.sections():
self.add_section(section)
for name, value in values.items():
self.set(section, name, str(value))
def __getitem__(self, name):
"""Access a section via a dict handler"""
if name not in simpleconfigparser.__dict__:
if name not in self.sections():
self.add_section(name)
return simpleconfigparser.Section(name, self)
return None
def __getattr__(self, name, raw=False, vars=None):
"""Access a section via a object handler"""
if name not in simpleconfigparser.__dict__:
if name not in self.sections():
self.add_section(name)
return simpleconfigparser.Section(name, self)
return None
def set(self, section, option, value=None):
try:
return configparser.set(self, section, option, value)
except NoSectionError:
return None
def get(self, section, option, raw=False, vars=None):
try:
# Strip out quotes from the edges
return configparser.get(self, section, option, raw=raw, vars=vars).strip('"\'')
except NoOptionError:
return None

View File

@ -6,7 +6,7 @@ Beaker=1.10.0
bottle=0.12.13
bottle-fdsend=0.1.1
chardet=3.0.4
configparser=3.5.0
configparser2=4.0.0
dogpile.cache=0.6.5
enzyme=0.4.1
gitpython=2.1.9
@ -19,6 +19,7 @@ pytz=2018.4
rarfile=3.0
requests=2.18.4
six=1.11.0
SimpleConfigParser=0.1.0
stevedore=1.28.0
subliminal=2.1.0dev
tzlocal=1.5.1

View File

@ -91,7 +91,7 @@
%from get_languages import *
%from config import settings
%from helper import path_replace
%single_language = settings.general.single_language
%single_language = settings.general.getboolean('single_language')
<div style="display: none;"><img src="{{base_url}}image_proxy{{details[3]}}"></div>
<div id='loader' class="ui page dimmer">
<div id="loader_text" class="ui indeterminate text loader">Loading...</div>
@ -222,7 +222,7 @@
if missing_languages is not None:
from get_subtitle import search_active
for language in missing_languages:
if episode[10] is not None and settings.general.adaptive_searching and language in episode[10]:
if episode[10] is not None and settings.general.getboolean('adaptive_searching') and language in episode[10]:
for lang in ast.literal_eval(episode[10]):
if language in lang:
if search_active(lang[1]):

View File

@ -51,8 +51,8 @@
<div id="fondblanc" class="ui container">
<div class="ui top attached tabular menu">
<a id="series_tab" class="tabs item active" data-enabled="{{settings.general.use_sonarr}}" data-tab="series">Series</a>
<a id="movies_tab" class="tabs item" data-enabled="{{settings.general.use_radarr}}" data-tab="movies">Movies</a>
<a id="series_tab" class="tabs item active" data-enabled="{{settings.general.getboolean('use_sonarr')}}" data-tab="series">Series</a>
<a id="movies_tab" class="tabs item" data-enabled="{{settings.general.getboolean('use_radarr')}}" data-tab="movies">Movies</a>
</div>
<div class="ui bottom attached tab segment" data-tab="series">
<div class="content">

View File

@ -26,7 +26,7 @@
% import sqlite3
% from config import settings
%if settings.general.only_monitored:
%if settings.general.getboolean('only_monitored'):
% monitored_only_query_string = ' AND monitored = "True"'
%else:
% monitored_only_query_string = ""
@ -50,13 +50,13 @@
<div class="sixteen wide column">
<div class="ui inverted borderless labeled icon massive menu six item">
<div class="ui container">
% if settings.general.use_sonarr:
% if settings.general.getboolean('use_sonarr'):
<a class="item" href="{{base_url}}series">
<i class="play icon"></i>
Series
</a>
% end
% if settings.general.use_radarr:
% if settings.general.getboolean('use_radarr'):
<a class="item" href="{{base_url}}movies">
<i class="film icon"></i>
Movies
@ -68,12 +68,12 @@
</a>
<a class="item" href="{{base_url}}wanted">
<i class="warning sign icon">
% if settings.general.use_sonarr:
% if settings.general.getboolean('use_sonarr'):
<div class="floating ui tiny yellow label" style="left:90% !important;top:0.5em !important;">
{{wanted_series[0]}}
</div>
% end
% if settings.general.use_radarr:
% if settings.general.getboolean('use_radarr'):
<div class="floating ui tiny green label" style="left:90% !important;top:3em !important;">
{{wanted_movies[0]}}
</div>

View File

@ -82,7 +82,7 @@
%from get_languages import *
%from config import settings
%from helper import path_replace_movie
%single_language = settings.general.single_language
%single_language = settings.general.getboolean('single_language')
<div style="display: none;"><img src="{{base_url}}image_proxy_movies{{details[3]}}"></div>
<div id='loader' class="ui page dimmer">
<div id="loader_text" class="ui indeterminate text loader">Loading...</div>
@ -188,7 +188,7 @@
</table>
<%
for missing_subs_language in missing_subs_languages:
if details[14] is not None and settings.general.adaptive_searching and missing_subs_language in details[14]:
if details[14] is not None and settings.general.getboolean('adaptive_searching') and missing_subs_language in details[14]:
for lang in ast.literal_eval(details[14]):
if missing_subs_language in lang:
if search_active(lang[1]):

View File

@ -141,7 +141,7 @@
<label>Enable debug logging</label>
</div>
<div class="five wide column">
<div id="settings_debug" class="ui toggle checkbox" data-debug={{settings.general.debug}}>
<div id="settings_debug" class="ui toggle checkbox" data-debug={{settings.general.getboolean('debug')}}>
<input name="settings_general_debug" type="checkbox">
<label></label>
</div>
@ -372,7 +372,7 @@
<label>Use Sonarr</label>
</div>
<div class="one wide column">
<div id="settings_use_sonarr" class="ui toggle checkbox" data-enabled={{settings.general.use_sonarr}}>
<div id="settings_use_sonarr" class="ui toggle checkbox" data-enabled={{settings.general.getboolean('use_sonarr')}}>
<input name="settings_general_use_sonarr" type="checkbox">
<label></label>
</div>
@ -391,7 +391,7 @@
<label>Use Radarr</label>
</div>
<div class="one wide column">
<div id="settings_use_radarr" class="ui toggle checkbox" data-enabled={{settings.general.use_radarr}}>
<div id="settings_use_radarr" class="ui toggle checkbox" data-enabled={{settings.general.getboolean('use_radarr')}}>
<input name="settings_general_use_radarr" type="checkbox">
<label></label>
</div>
@ -566,7 +566,7 @@
<label>Use post-processing</label>
</div>
<div class="one wide column">
<div id="settings_use_postprocessing" class="ui toggle checkbox" data-postprocessing={{settings.general.use_postprocessing}}>
<div id="settings_use_postprocessing" class="ui toggle checkbox" data-postprocessing={{settings.general.getboolean('use_postprocessing')}}>
<input name="settings_general_use_postprocessing" type="checkbox">
<label></label>
</div>
@ -660,7 +660,7 @@
<label>Automatic</label>
</div>
<div class="one wide column">
<div id="settings_automatic_div" class="ui toggle checkbox" data-automatic={{settings.general.auto_update}}>
<div id="settings_automatic_div" class="ui toggle checkbox" data-automatic={{settings.general.getboolean('auto_update')}}>
<input name="settings_general_automatic" type="checkbox">
<label></label>
</div>
@ -756,7 +756,7 @@
<label>SSL enabled</label>
</div>
<div class="one wide column">
<div id="sonarr_ssl_div" class="ui toggle checkbox" data-ssl={{settings.sonarr.ssl}}>
<div id="sonarr_ssl_div" class="ui toggle checkbox" data-ssl={{settings.sonarr.getboolean('ssl')}}>
<input id="settings_sonarr_ssl" name="settings_sonarr_ssl" type="checkbox">
<label></label>
</div>
@ -882,7 +882,7 @@
<label>SSL enabled</label>
</div>
<div class="one wide column">
<div id="radarr_ssl_div" class="ui toggle checkbox" data-ssl={{settings.radarr.ssl}}>
<div id="radarr_ssl_div" class="ui toggle checkbox" data-ssl={{settings.radarr.getboolean('ssl')}}>
<input id="settings_radarr_ssl" name="settings_radarr_ssl" type="checkbox">
<label></label>
</div>
@ -945,7 +945,7 @@
<label>Use scene name when available</label>
</div>
<div class="one wide column">
<div id="settings_scenename" class="ui toggle checkbox" data-scenename={{settings.general.use_scenename}}>
<div id="settings_scenename" class="ui toggle checkbox" data-scenename={{settings.general.getboolean('use_scenename')}}>
<input name="settings_general_scenename" type="checkbox">
<label></label>
</div>
@ -1004,7 +1004,7 @@
<label>Use embedded subtitles</label>
</div>
<div class="one wide column">
<div id="settings_embedded" class="ui toggle checkbox" data-embedded={{settings.general.use_embedded_subs}}>
<div id="settings_embedded" class="ui toggle checkbox" data-embedded={{settings.general.getboolean('use_embedded_subs')}}>
<input name="settings_general_embedded" type="checkbox">
<label></label>
</div>
@ -1023,7 +1023,7 @@
<label>Download only monitored</label>
</div>
<div class="one wide column">
<div id="settings_only_monitored" class="ui toggle checkbox" data-monitored={{settings.general.only_monitored}}>
<div id="settings_only_monitored" class="ui toggle checkbox" data-monitored={{settings.general.getboolean('only_monitored')}}>
<input name="settings_general_only_monitored" type="checkbox">
<label></label>
</div>
@ -1042,7 +1042,7 @@
<label>Adaptive searching</label>
</div>
<div class="one wide column">
<div id="settings_adaptive_searching" class="ui toggle checkbox" data-adaptive={{settings.general.adaptive_searching}}>
<div id="settings_adaptive_searching" class="ui toggle checkbox" data-adaptive={{settings.general.getboolean('adaptive_searching')}}>
<input name="settings_general_adaptive_searching" type="checkbox">
<label></label>
</div>
@ -1172,7 +1172,7 @@
<label>Single language</label>
</div>
<div class="one wide column">
<div id="settings_single_language" class="ui toggle checkbox" data-single-language={{settings.general.single_language}}>
<div id="settings_single_language" class="ui toggle checkbox" data-single-language={{settings.general.getboolean('single_language')}}>
<input name="settings_general_single_language" type="checkbox">
<label></label>
</div>
@ -1217,7 +1217,7 @@
</div>
<div class="one wide column">
<div class="nine wide column">
<div id="settings_serie_default_enabled_div" class="ui toggle checkbox" data-enabled="{{settings.general.serie_default_enabled}}">
<div id="settings_serie_default_enabled_div" class="ui toggle checkbox" data-enabled="{{settings.general.getboolean('serie_default_enabled')}}">
<input name="settings_serie_default_enabled" id="settings_serie_default_enabled" type="checkbox">
<label></label>
</div>
@ -1239,7 +1239,7 @@
<div class="eleven wide column">
<div class='field'>
<select name="settings_serie_default_languages" id="settings_serie_default_languages" multiple="" class="ui fluid search selection dropdown">
%if settings.general.single_language is False:
%if settings.general.getboolean('single_language') is False:
<option value="">Languages</option>
%else:
<option value="None">None</option>
@ -1255,7 +1255,7 @@
</div>
<div class="eleven wide column">
<div class="nine wide column">
<div id="settings_serie_default_hi_div" class="ui toggle checkbox" data-hi="{{settings.general.serie_default_hi}}">
<div id="settings_serie_default_hi_div" class="ui toggle checkbox" data-hi="{{settings.general.getboolean('serie_default_hi')}}">
<input name="settings_serie_default_hi" id="settings_serie_default_hi" type="checkbox">
<label></label>
</div>
@ -1274,7 +1274,7 @@
</div>
<div class="one wide column">
<div class="nine wide column">
<div id="settings_movie_default_enabled_div" class="ui toggle checkbox" data-enabled="{{settings.general.movie_default_enabled}}">
<div id="settings_movie_default_enabled_div" class="ui toggle checkbox" data-enabled="{{settings.general.getboolean('movie_default_enabled')}}">
<input name="settings_movie_default_enabled" id="settings_movie_default_enabled" type="checkbox">
<label></label>
</div>
@ -1296,7 +1296,7 @@
<div class="eleven wide column">
<div class='field'>
<select name="settings_movie_default_languages" id="settings_movie_default_languages" multiple="" class="ui fluid search selection dropdown">
%if settings.general.single_language is False:
%if settings.general.getboolean('single_language') is False:
<option value="">Languages</option>
%else:
<option value="None">None</option>
@ -1312,7 +1312,7 @@
</div>
<div class="eleven wide column">
<div class="nine wide column">
<div id="settings_movie_default_hi_div" class="ui toggle checkbox" data-hi="{{settings.general.movie_default_hi}}">
<div id="settings_movie_default_hi_div" class="ui toggle checkbox" data-hi="{{settings.general.getboolean('movie_default_hi')}}">
<input name="settings_movie_default_hi" id="settings_movie_default_hi" type="checkbox">
<label></label>
</div>
@ -1671,7 +1671,7 @@
$('#settings_loglevel').dropdown('clear');
$('#settings_loglevel').dropdown('set selected','{{!settings.general.debug}}');
$('#settings_loglevel').dropdown('set selected','{{!settings.general.getboolean('debug')}}');
$('#settings_page_size').dropdown('clear');
$('#settings_page_size').dropdown('set selected','{{!settings.general.page_size}}');
$('#settings_proxy_type').dropdown('clear');

View File

@ -136,7 +136,7 @@
</div>
</div>
</div>
% if settings.general.use_sonarr:
% if settings.general.getboolean('use_sonarr'):
<div class="middle aligned row">
<div class="right aligned four wide column">
<label>Sonarr version</label>
@ -150,7 +150,7 @@
</div>
</div>
% end
% if settings.general.use_radarr:
% if settings.general.getboolean('use_radarr'):
<div class="middle aligned row">
<div class="right aligned four wide column">
<label>Radarr version</label>

View File

@ -38,7 +38,7 @@
% import sqlite3
% from config import settings
%if settings.general.only_monitored:
%if settings.general.getboolean('only_monitored'):
% monitored_only_query_string = ' AND monitored = "True"'
%else:
% monitored_only_query_string = ""
@ -57,12 +57,12 @@
<div id="fondblanc" class="ui container">
<div class="ui top attached tabular menu">
<a id="series_tab" class="tabs item active" data-enabled="{{settings.general.use_sonarr}}" data-tab="series">Series
<a id="series_tab" class="tabs item active" data-enabled="{{settings.general.getboolean('use_sonarr')}}" data-tab="series">Series
<div class="ui tiny yellow label">
{{wanted_series[0]}}
</div>
</a>
<a id="movies_tab" class="tabs item" data-enabled="{{settings.general.use_radarr}}" data-tab="movies">Movies
<a id="movies_tab" class="tabs item" data-enabled="{{settings.general.getboolean('use_radarr')}}" data-tab="movies">Movies
<div class="ui tiny green label">
{{wanted_movies[0]}}
</div>

View File

@ -67,7 +67,7 @@
from get_subtitle import search_active
from config import settings
for language in missing_languages:
if row[6] is not None and settings.general.adaptive_searching and language in row[6]:
if row[6] is not None and settings.general.getboolean('adaptive_searching') and language in row[6]:
for lang in ast.literal_eval(row[6]):
if language in lang:
active = search_active(lang[1])

View File

@ -74,7 +74,7 @@
from get_subtitle import search_active
from config import settings
for language in missing_languages:
if row[9] is not None and settings.general.adaptive_searching and language in row[9]:
if row[9] is not None and settings.general.getboolean('adaptive_searching') and language in row[9]:
for lang in ast.literal_eval(row[9]):
if language in lang:
active = search_active(lang[1])

View File

@ -367,7 +367,7 @@
<label>Single language</label>
</div>
<div class="one wide column">
<div id="settings_single_language" class="ui toggle checkbox" data-single-language={{settings.general.single_language}}>
<div id="settings_single_language" class="ui toggle checkbox" data-single-language={{settings.general.getboolean('single_language')}}>
<input name="settings_general_single_language" type="checkbox">
<label></label>
</div>
@ -434,7 +434,7 @@
<div class="eleven wide column">
<div class='field'>
<select name="settings_serie_default_languages" id="settings_serie_default_languages" multiple="" class="ui fluid search selection dropdown">
%if not settings.general.single_language:
%if not settings.general.getboolean('single_language'):
<option value="">Languages</option>
%else:
<option value="None">None</option>
@ -491,7 +491,7 @@
<div class="eleven wide column">
<div class='field'>
<select name="settings_movie_default_languages" id="settings_movie_default_languages" multiple="" class="ui fluid search selection dropdown">
%if not settings.general.single_language:
%if not settings.general.getboolean('single_language'):
<option value="">Languages</option>
%else:
<option value="None">None</option>