mirror of
https://github.com/morpheus65535/bazarr.git
synced 2025-04-23 22:27:17 -04:00
Merge remote-tracking branch 'origin/development' into subliminal_patch
# Conflicts: # libs/subliminal/subtitle.py
This commit is contained in:
commit
4beaeaa99e
41 changed files with 1978 additions and 505 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -6,3 +6,4 @@ cachefile.dbm
|
|||
*.pyc
|
||||
.idea/*
|
||||
bazarr.pid
|
||||
/venv
|
||||
|
|
|
@ -44,17 +44,8 @@ def check_and_apply_update():
|
|||
updated()
|
||||
|
||||
def updated():
|
||||
from scheduler import shutdown_scheduler
|
||||
from main import restart
|
||||
|
||||
conn = sqlite3.connect(os.path.join(config_dir, 'db/bazarr.db'), timeout=30)
|
||||
c = conn.cursor()
|
||||
c.execute("UPDATE system SET updated = 1")
|
||||
conn.commit()
|
||||
c.close()
|
||||
|
||||
# Shutdown the scheduler waiting for jobs to finish
|
||||
shutdown_scheduler()
|
||||
|
||||
# Restart Bazarr
|
||||
restart()
|
||||
c.close()
|
|
@ -20,8 +20,15 @@ CREATE TABLE "table_settings_providers" (
|
|||
`password` "text",
|
||||
PRIMARY KEY(`name`)
|
||||
);
|
||||
CREATE TABLE "table_settings_notifier" (
|
||||
`name` TEXT,
|
||||
`url` TEXT,
|
||||
`enabled` INTEGER,
|
||||
PRIMARY KEY(`name`)
|
||||
);
|
||||
CREATE TABLE "table_settings_languages" (
|
||||
`code3` TEXT NOT NULL UNIQUE,
|
||||
`code3b` TEXT,
|
||||
`code2` TEXT,
|
||||
`name` TEXT NOT NULL,
|
||||
`enabled` INTEGER,
|
||||
|
|
|
@ -18,6 +18,13 @@ def load_language_in_db():
|
|||
c.executemany('''INSERT OR IGNORE INTO table_settings_languages(code3, code2, name) VALUES(?, ?, ?)''', langs)
|
||||
c.execute('''INSERT OR IGNORE INTO table_settings_languages(code3, code2, name) VALUES(?, ?, ?)''', ('pob','pb','Brazilian Portuguese'))
|
||||
|
||||
langs = [[lang.bibliographic,lang.alpha_3]
|
||||
for lang in pycountry.languages
|
||||
if hasattr(lang, 'alpha_2') and hasattr(lang, 'bibliographic')]
|
||||
|
||||
# Update languages in database table
|
||||
c.executemany('''UPDATE table_settings_languages SET code3b = ? WHERE code3 = ?''', langs)
|
||||
|
||||
# Commit changes to database table
|
||||
db.commit()
|
||||
|
||||
|
@ -40,7 +47,7 @@ def language_from_alpha3(lang):
|
|||
db = sqlite3.connect(os.path.join(config_dir, 'db/bazarr.db'), timeout=30)
|
||||
c = db.cursor()
|
||||
try:
|
||||
result = c.execute('''SELECT name FROM table_settings_languages WHERE code3 = ?''', (lang,)).fetchone()[0]
|
||||
result = c.execute('''SELECT name FROM table_settings_languages WHERE code3 = ? OR code3b = ?''', (lang,lang)).fetchone()[0]
|
||||
except:
|
||||
result = None
|
||||
db.close()
|
||||
|
@ -52,7 +59,7 @@ def alpha2_from_alpha3(lang):
|
|||
db = sqlite3.connect(os.path.join(config_dir, 'db/bazarr.db'), timeout=30)
|
||||
c = db.cursor()
|
||||
try:
|
||||
result = c.execute('''SELECT code2 FROM table_settings_languages WHERE code3 = ?''', (lang,)).fetchone()[0]
|
||||
result = c.execute('''SELECT code2 FROM table_settings_languages WHERE code3 = ? OR code3b = ?''', (lang,lang)).fetchone()[0]
|
||||
except:
|
||||
result = None
|
||||
db.close()
|
||||
|
|
|
@ -37,7 +37,7 @@ def get_general_settings():
|
|||
if cfg.has_option('general', 'path_mappings'):
|
||||
path_mappings = cfg.get('general', 'path_mappings')
|
||||
else:
|
||||
path_mappings = []
|
||||
path_mappings = '[]'
|
||||
|
||||
if cfg.has_option('general', 'log_level'):
|
||||
log_level = cfg.get('general', 'log_level')
|
||||
|
@ -67,7 +67,7 @@ def get_general_settings():
|
|||
if cfg.has_option('general', 'use_scenename'):
|
||||
use_scenename = cfg.getboolean('general', 'use_scenename')
|
||||
else:
|
||||
use_scenename = False
|
||||
use_scenename = True
|
||||
|
||||
if cfg.has_option('general', 'use_postprocessing'):
|
||||
use_postprocessing = cfg.getboolean('general', 'use_postprocessing')
|
||||
|
@ -92,7 +92,7 @@ def get_general_settings():
|
|||
if cfg.has_option('general', 'path_mappings_movie'):
|
||||
path_mappings_movie = cfg.get('general', 'path_mappings_movie')
|
||||
else:
|
||||
path_mappings_movie = []
|
||||
path_mappings_movie = '[]'
|
||||
|
||||
if cfg.has_option('general', 'serie_default_enabled'):
|
||||
serie_default_enabled = cfg.getboolean('general', 'serie_default_enabled')
|
||||
|
@ -137,7 +137,7 @@ def get_general_settings():
|
|||
if cfg.has_option('general', 'use_embedded_subs'):
|
||||
use_embedded_subs = cfg.getboolean('general', 'use_embedded_subs')
|
||||
else:
|
||||
use_embedded_subs = False
|
||||
use_embedded_subs = True
|
||||
|
||||
if cfg.has_option('general', 'only_monitored'):
|
||||
only_monitored = cfg.getboolean('general', 'only_monitored')
|
||||
|
@ -151,20 +151,20 @@ def get_general_settings():
|
|||
|
||||
else:
|
||||
ip = '0.0.0.0'
|
||||
port = '6768'
|
||||
port = '6767'
|
||||
base_url = '/'
|
||||
path_mappings = []
|
||||
path_mappings = '[]'
|
||||
log_level = 'INFO'
|
||||
branch = 'master'
|
||||
auto_update = True
|
||||
single_language = False
|
||||
minimum_score = '90'
|
||||
use_scenename = False
|
||||
use_scenename = True
|
||||
use_postprocessing = False
|
||||
postprocessing_cmd = ''
|
||||
use_sonarr = False
|
||||
use_radarr = False
|
||||
path_mappings_movie = []
|
||||
path_mappings_movie = '[]'
|
||||
serie_default_enabled = False
|
||||
serie_default_language = []
|
||||
serie_default_hi = 'False'
|
||||
|
@ -173,7 +173,7 @@ def get_general_settings():
|
|||
movie_default_hi = 'False'
|
||||
page_size = '25'
|
||||
minimum_score_movie = '70'
|
||||
use_embedded_subs = False
|
||||
use_embedded_subs = True
|
||||
only_monitored = False
|
||||
adaptive_searching = False
|
||||
|
||||
|
@ -366,7 +366,7 @@ def get_radarr_settings():
|
|||
full_update = 'Dayly'
|
||||
else:
|
||||
ip = '127.0.0.1'
|
||||
port = '8989'
|
||||
port = '7878'
|
||||
base_url = '/'
|
||||
ssl = False
|
||||
apikey = ''
|
||||
|
|
|
@ -67,53 +67,66 @@ def download_subtitle(path, language, hi, providers, providers_auth, sceneName,
|
|||
logging.exception("BAZARR Error trying to get subtitle list from provider for this file: " + path)
|
||||
else:
|
||||
subtitles_list = []
|
||||
sorted_subtitles = sorted([(s, compute_score(s, video, hearing_impaired=hi)) for s in subtitles], key=operator.itemgetter(1), reverse=True)
|
||||
for s, preliminary_score in sorted_subtitles:
|
||||
if media_type == "movie":
|
||||
if (preliminary_score / max_score * 100) < int(minimum_score_movie):
|
||||
continue
|
||||
matched = set(s.get_matches(video))
|
||||
if hi == s.hearing_impaired:
|
||||
matched.add('hearing_impaired')
|
||||
not_matched = set(score.movie_scores.keys()) - matched
|
||||
required = set(['title'])
|
||||
if any(elem in required for elem in not_matched):
|
||||
continue
|
||||
elif media_type == "series":
|
||||
if (preliminary_score / max_score * 100) < int(minimum_score):
|
||||
continue
|
||||
matched = set(s.get_matches(video))
|
||||
if hi == s.hearing_impaired:
|
||||
matched.add('hearing_impaired')
|
||||
not_matched = set(score.episode_scores.keys()) - matched
|
||||
required = set(['series', 'season', 'episode'])
|
||||
if any(elem in required for elem in not_matched):
|
||||
continue
|
||||
subtitles_list.append(s)
|
||||
logging.debug('BAZARR ' + str(len(subtitles_list)) + " subtitles have been found for this file: " + path)
|
||||
if len(subtitles_list) > 0:
|
||||
try:
|
||||
best_subtitle = subtitles_list[0]
|
||||
download_subtitles([best_subtitle], providers=providers, provider_configs=providers_auth)
|
||||
logging.debug('BAZARR Subtitles file downloaded for this file:' + path)
|
||||
except Exception as e:
|
||||
logging.exception('BAZARR Error downloading subtitles for this file ' + path)
|
||||
return None
|
||||
else:
|
||||
try:
|
||||
sorted_subtitles = sorted([(s, compute_score(s, video, hearing_impaired=hi)) for s in subtitles], key=operator.itemgetter(1), reverse=True)
|
||||
except Exception as e:
|
||||
logging.exception('BAZARR Exception raised while trying to compute score for this file: ' + path)
|
||||
return None
|
||||
else:
|
||||
for s, preliminary_score in sorted_subtitles:
|
||||
if media_type == "movie":
|
||||
if (preliminary_score / max_score * 100) < int(minimum_score_movie):
|
||||
continue
|
||||
matched = set(s.get_matches(video))
|
||||
if hi == s.hearing_impaired:
|
||||
matched.add('hearing_impaired')
|
||||
not_matched = set(score.movie_scores.keys()) - matched
|
||||
required = set(['title'])
|
||||
if any(elem in required for elem in not_matched):
|
||||
continue
|
||||
elif media_type == "series":
|
||||
if (preliminary_score / max_score * 100) < int(minimum_score):
|
||||
continue
|
||||
matched = set(s.get_matches(video))
|
||||
if hi == s.hearing_impaired:
|
||||
matched.add('hearing_impaired')
|
||||
not_matched = set(score.episode_scores.keys()) - matched
|
||||
required = set(['series', 'season', 'episode'])
|
||||
if any(elem in required for elem in not_matched):
|
||||
continue
|
||||
subtitles_list.append(s)
|
||||
logging.debug('BAZARR ' + str(len(subtitles_list)) + " subtitles have been found for this file: " + path)
|
||||
if len(subtitles_list) > 0:
|
||||
try:
|
||||
calculated_score = round(float(compute_score(best_subtitle, video, hearing_impaired=hi)) / max_score * 100, 2)
|
||||
if used_sceneName == True:
|
||||
video = scan_video(path)
|
||||
single = get_general_settings()[7]
|
||||
if single is True:
|
||||
result = save_subtitles(video, [best_subtitle], single=True, encoding='utf-8')
|
||||
else:
|
||||
result = save_subtitles(video, [best_subtitle], encoding='utf-8')
|
||||
pdownload_result = False
|
||||
for subtitle in subtitles_list:
|
||||
download_result = p.download_subtitle(subtitle)
|
||||
if download_result == True:
|
||||
logging.debug('BAZARR Subtitles file downloaded from ' + str(subtitle.provider_name) + ' for this file: ' + path)
|
||||
break
|
||||
else:
|
||||
logging.warning('BAZARR Subtitles file skipped from ' + str(subtitle.provider_name) + ' for this file: ' + path + ' because no content was returned by the provider (probably throttled).')
|
||||
continue
|
||||
if download_result == False:
|
||||
logging.error('BAZARR Tried to download a subtitles for file: ' + path + " but we weren't able to do it this time (probably being throttled). Going to retry on next search.")
|
||||
return None
|
||||
except Exception as e:
|
||||
logging.exception('BAZARR Error saving subtitles file to disk for this file:' + path)
|
||||
pass
|
||||
logging.exception('BAZARR Error downloading subtitles for this file ' + path)
|
||||
return None
|
||||
else:
|
||||
if len(result) > 0:
|
||||
try:
|
||||
calculated_score = round(float(compute_score(subtitle, video, hearing_impaired=hi)) / max_score * 100, 2)
|
||||
if used_sceneName == True:
|
||||
video = scan_video(path)
|
||||
single = get_general_settings()[7]
|
||||
if single is True:
|
||||
result = save_subtitles(video, [subtitle], single=True, encoding='utf-8')
|
||||
else:
|
||||
result = save_subtitles(video, [subtitle], encoding='utf-8')
|
||||
except Exception as e:
|
||||
logging.exception('BAZARR Error saving subtitles file to disk for this file:' + path)
|
||||
pass
|
||||
else:
|
||||
downloaded_provider = result[0].provider_name
|
||||
downloaded_language = language_from_alpha3(result[0].language.alpha3)
|
||||
downloaded_language_code2 = alpha2_from_alpha3(result[0].language.alpha3)
|
||||
|
@ -153,11 +166,9 @@ def download_subtitle(path, language, hi, providers, providers_auth, sceneName,
|
|||
logging.info('BAZARR Post-processing result for file ' + path + ' : ' + out)
|
||||
|
||||
return message
|
||||
else:
|
||||
logging.error('BAZARR Tried to download best subtitles available for file: ' + path + ' but it had no content. Going to retry on next search.')
|
||||
return None
|
||||
else:
|
||||
return None
|
||||
else:
|
||||
logging.debug('BAZARR No subtitles were found for this file: ' + path)
|
||||
return None
|
||||
logging.debug('BAZARR Ended searching subtitles for file: ' + path)
|
||||
|
||||
def manual_search(path, language, hi, providers, providers_auth, sceneName, media_type):
|
||||
|
@ -262,8 +273,7 @@ def manual_download_subtitle(path, language, hi, subtitle, provider, providers_a
|
|||
pass
|
||||
else:
|
||||
try:
|
||||
best_subtitle = subtitle
|
||||
download_subtitles([best_subtitle], providers=provider, provider_configs=providers_auth)
|
||||
download_subtitles([subtitle], providers=provider, provider_configs=providers_auth)
|
||||
logging.debug('BAZARR Subtitles file downloaded for this file:' + path)
|
||||
except Exception as e:
|
||||
logging.exception('BAZARR Error downloading subtitles for this file ' + path)
|
||||
|
@ -271,13 +281,13 @@ def manual_download_subtitle(path, language, hi, subtitle, provider, providers_a
|
|||
else:
|
||||
single = get_general_settings()[7]
|
||||
try:
|
||||
score = round(float(compute_score(best_subtitle, video, hearing_impaired=hi)) / type_of_score * 100, 2)
|
||||
score = round(float(compute_score(subtitle, video, hearing_impaired=hi)) / type_of_score * 100, 2)
|
||||
if used_sceneName == True:
|
||||
video = scan_video(path)
|
||||
if single is True:
|
||||
result = save_subtitles(video, [best_subtitle], single=True, encoding='utf-8')
|
||||
result = save_subtitles(video, [subtitle], single=True, encoding='utf-8')
|
||||
else:
|
||||
result = save_subtitles(video, [best_subtitle], encoding='utf-8')
|
||||
result = save_subtitles(video, [subtitle], encoding='utf-8')
|
||||
except Exception as e:
|
||||
logging.exception('BAZARR Error saving subtitles file to disk for this file:' + path)
|
||||
return None
|
||||
|
@ -320,7 +330,7 @@ def manual_download_subtitle(path, language, hi, subtitle, provider, providers_a
|
|||
|
||||
return message
|
||||
else:
|
||||
logging.error('BAZARR Tried to manually download a subtitles for file: ' + path + ' but it had no content. Going to retry on next search.')
|
||||
logging.error('BAZARR Tried to manually download a subtitles for file: ' + path + " but we weren't able to do (probably throttled by ' + str(subtitle.provider_name) + '. Please retry later or select a subtitles from another provider.")
|
||||
return None
|
||||
logging.debug('BAZARR Ended manually downloading subtitles for file: ' + path)
|
||||
|
||||
|
|
179
bazarr/init.py
179
bazarr/init.py
|
@ -28,185 +28,6 @@ if os.path.exists(os.path.join(config_dir, 'log')) is False:
|
|||
config_file = os.path.normpath(os.path.join(config_dir, 'config/config.ini'))
|
||||
|
||||
cfg = ConfigParser()
|
||||
try:
|
||||
# Open database connection
|
||||
db = sqlite3.connect(os.path.join(os.path.dirname(__file__), 'data/db/bazarr.db'), timeout=30)
|
||||
c = db.cursor()
|
||||
|
||||
# Get general settings from database table
|
||||
c.execute("SELECT * FROM table_settings_general")
|
||||
general_settings = c.fetchone()
|
||||
c.execute('''SELECT * FROM table_settings_auth''')
|
||||
auth_settings = c.fetchone()
|
||||
c.execute('''SELECT * FROM table_settings_sonarr''')
|
||||
sonarr_settings = c.fetchone()
|
||||
c.execute('''SELECT * FROM table_settings_radarr''')
|
||||
radarr_settings = c.fetchone()
|
||||
|
||||
c.execute("DROP TABLE table_settings_general")
|
||||
c.execute("DROP TABLE table_settings_auth")
|
||||
c.execute("DROP TABLE table_settings_sonarr")
|
||||
c.execute("DROP TABLE table_settings_radarr")
|
||||
|
||||
# Close database connection
|
||||
db.close()
|
||||
|
||||
section = 'general'
|
||||
|
||||
if not cfg.has_section(section):
|
||||
cfg.add_section(section)
|
||||
|
||||
cfg.set(section, 'ip', str(general_settings[0]))
|
||||
cfg.set(section, 'port', str(general_settings[1]))
|
||||
cfg.set(section, 'base_url', general_settings[2])
|
||||
cfg.set(section, 'path_mappings', general_settings[3])
|
||||
cfg.set(section, 'log_level', general_settings[4])
|
||||
cfg.set(section, 'branch', general_settings[5])
|
||||
cfg.set(section, 'auto_update', general_settings[6])
|
||||
cfg.set(section, 'single_language', general_settings[9])
|
||||
cfg.set(section, 'minimum_score', general_settings[10])
|
||||
cfg.set(section, 'use_scenename', general_settings[11])
|
||||
cfg.set(section, 'use_postprocessing', general_settings[12])
|
||||
cfg.set(section, 'postprocessing_cmd', general_settings[13])
|
||||
cfg.set(section, 'use_sonarr', general_settings[14])
|
||||
cfg.set(section, 'use_radarr', general_settings[15])
|
||||
cfg.set(section, 'path_mappings_movie', general_settings[16])
|
||||
cfg.set(section, 'serie_default_enabled', general_settings[17])
|
||||
cfg.set(section, 'serie_default_language', general_settings[18])
|
||||
cfg.set(section, 'serie_default_hi', general_settings[19])
|
||||
cfg.set(section, 'movie_default_enabled', general_settings[20])
|
||||
cfg.set(section, 'movie_default_language', general_settings[21])
|
||||
cfg.set(section, 'movie_default_hi', general_settings[22])
|
||||
cfg.set(section, 'page_size', general_settings[23])
|
||||
cfg.set(section, 'minimum_score_movie', general_settings[24])
|
||||
cfg.set(section, 'use_embedded_subs', general_settings[25])
|
||||
cfg.set(section, 'only_monitored', general_settings[26])
|
||||
|
||||
section = 'auth'
|
||||
|
||||
if not cfg.has_section(section):
|
||||
cfg.add_section(section)
|
||||
|
||||
cfg.set(section, 'enabled', auth_settings[0])
|
||||
cfg.set(section, 'username', auth_settings[1])
|
||||
cfg.set(section, 'password', auth_settings[2])
|
||||
|
||||
section = 'sonarr'
|
||||
|
||||
if not cfg.has_section(section):
|
||||
cfg.add_section(section)
|
||||
|
||||
cfg.set(section, 'ip', sonarr_settings[0])
|
||||
cfg.set(section, 'port', str(sonarr_settings[1]))
|
||||
cfg.set(section, 'base_url', sonarr_settings[2])
|
||||
cfg.set(section, 'ssl', sonarr_settings[3])
|
||||
cfg.set(section, 'apikey', sonarr_settings[4])
|
||||
cfg.set(section, 'full_update', sonarr_settings[5])
|
||||
|
||||
section = 'radarr'
|
||||
|
||||
if not cfg.has_section(section):
|
||||
cfg.add_section(section)
|
||||
|
||||
cfg.set(section, 'ip', radarr_settings[0])
|
||||
cfg.set(section, 'port', str(radarr_settings[1]))
|
||||
cfg.set(section, 'base_url', radarr_settings[2])
|
||||
cfg.set(section, 'ssl', radarr_settings[3])
|
||||
cfg.set(section, 'apikey', radarr_settings[4])
|
||||
cfg.set(section, 'full_update', radarr_settings[5])
|
||||
|
||||
with open(config_file, 'w+') as configfile:
|
||||
cfg.write(configfile)
|
||||
|
||||
|
||||
logging.info('BAZARR Config file succesfully migrated from database')
|
||||
|
||||
except sqlite3.OperationalError:
|
||||
if os.path.exists(config_file) is False:
|
||||
cfg = ConfigParser()
|
||||
|
||||
section = 'general'
|
||||
|
||||
if not cfg.has_section(section):
|
||||
cfg.add_section(section)
|
||||
|
||||
cfg.set(section, 'ip', "0.0.0.0")
|
||||
cfg.set(section, 'port', "6767")
|
||||
cfg.set(section, 'base_url', "/")
|
||||
cfg.set(section, 'path_mappings', '[]')
|
||||
cfg.set(section, 'log_level', "INFO")
|
||||
cfg.set(section, 'branch', "master")
|
||||
cfg.set(section, 'auto_update', "True")
|
||||
cfg.set(section, 'single_language', "False")
|
||||
cfg.set(section, 'minimum_score', "90")
|
||||
cfg.set(section, 'use_scenename', "False")
|
||||
cfg.set(section, 'use_postprocessing', "False")
|
||||
cfg.set(section, 'postprocessing_cmd', "False")
|
||||
cfg.set(section, 'use_sonarr', "False")
|
||||
cfg.set(section, 'use_radarr', "False")
|
||||
cfg.set(section, 'path_mappings_movie', '[]')
|
||||
cfg.set(section, 'serie_default_enabled', "False")
|
||||
cfg.set(section, 'serie_default_language', '')
|
||||
cfg.set(section, 'serie_default_hi', "False")
|
||||
cfg.set(section, 'movie_default_enabled', "False")
|
||||
cfg.set(section, 'movie_default_language', '')
|
||||
cfg.set(section, 'movie_default_hi', "False")
|
||||
cfg.set(section, 'page_size', "25")
|
||||
cfg.set(section, 'minimum_score_movie', "70")
|
||||
cfg.set(section, 'use_embedded_subs', "False")
|
||||
cfg.set(section, 'only_monitored', "False")
|
||||
cfg.set(section, 'adaptive_searching', "False")
|
||||
|
||||
section = 'proxy'
|
||||
|
||||
if not cfg.has_section(section):
|
||||
cfg.add_section(section)
|
||||
|
||||
cfg.set(section, 'type', "None")
|
||||
cfg.set(section, 'url', "")
|
||||
cfg.set(section, 'port', "")
|
||||
cfg.set(section, 'username', "")
|
||||
cfg.set(section, 'password', "")
|
||||
cfg.set(section, 'exclude', "localhost,127.0.0.1")
|
||||
|
||||
section = 'auth'
|
||||
|
||||
if not cfg.has_section(section):
|
||||
cfg.add_section(section)
|
||||
|
||||
cfg.set(section, 'type', "None")
|
||||
cfg.set(section, 'username', "")
|
||||
cfg.set(section, 'password', "")
|
||||
|
||||
section = 'sonarr'
|
||||
|
||||
if not cfg.has_section(section):
|
||||
cfg.add_section(section)
|
||||
|
||||
cfg.set(section, 'ip', "127.0.0.1")
|
||||
cfg.set(section, 'port', "8989")
|
||||
cfg.set(section, 'base_url', "/")
|
||||
cfg.set(section, 'ssl', "False")
|
||||
cfg.set(section, 'apikey', "")
|
||||
cfg.set(section, 'full_update', "Daily")
|
||||
|
||||
section = 'radarr'
|
||||
|
||||
if not cfg.has_section(section):
|
||||
cfg.add_section(section)
|
||||
|
||||
cfg.set(section, 'ip', "127.0.0.1")
|
||||
cfg.set(section, 'port', "7878")
|
||||
cfg.set(section, 'base_url', "/")
|
||||
cfg.set(section, 'ssl', "False")
|
||||
cfg.set(section, 'apikey', "")
|
||||
cfg.set(section, 'full_update', "Daily")
|
||||
|
||||
|
||||
with open(config_file, 'w+') as configfile:
|
||||
cfg.write(configfile)
|
||||
|
||||
logging.info('BAZARR Config file created successfully')
|
||||
try:
|
||||
# Get SQL script from file
|
||||
fd = open(os.path.join(os.path.dirname(__file__), 'create_db.sql'), 'r')
|
||||
|
|
440
bazarr/main.py
440
bazarr/main.py
|
@ -17,6 +17,8 @@ import signal
|
|||
import sqlite3
|
||||
from init import *
|
||||
from update_db import *
|
||||
from notifier import update_notifier
|
||||
update_notifier()
|
||||
|
||||
|
||||
from get_settings import get_general_settings, get_proxy_settings
|
||||
|
@ -49,7 +51,7 @@ def configure_logging():
|
|||
fh.setFormatter(f)
|
||||
logging.getLogger("enzyme").setLevel(logging.CRITICAL)
|
||||
logging.getLogger("apscheduler").setLevel(logging.WARNING)
|
||||
logging.getLogger("subliminal").setLevel(logging.DEBUG)
|
||||
logging.getLogger("subliminal").setLevel(logging.CRITICAL)
|
||||
logging.getLogger("guessit").setLevel(logging.WARNING)
|
||||
logging.getLogger("rebulk").setLevel(logging.WARNING)
|
||||
logging.getLogger("stevedore.extension").setLevel(logging.CRITICAL)
|
||||
|
@ -90,6 +92,7 @@ import ast
|
|||
import hashlib
|
||||
import time
|
||||
import urllib
|
||||
from six import text_type
|
||||
|
||||
from get_languages import load_language_in_db, language_from_alpha3
|
||||
from get_providers import load_providers, get_providers, get_providers_auth
|
||||
|
@ -222,10 +225,221 @@ def restart():
|
|||
except Exception as e:
|
||||
logging.error('BAZARR Cannot create bazarr.restart file.')
|
||||
else:
|
||||
print 'Bazarr is being restarted...'
|
||||
logging.info('Bazarr is being restarted...')
|
||||
restart_file.write('')
|
||||
restart_file.close()
|
||||
|
||||
|
||||
@route(base_url + 'wizard')
|
||||
@custom_auth_basic(check_credentials)
|
||||
def wizard():
|
||||
authorize()
|
||||
db = sqlite3.connect(os.path.join(config_dir, 'db/bazarr.db'), timeout=30)
|
||||
c = db.cursor()
|
||||
settings_languages = c.execute("SELECT * FROM table_settings_languages ORDER BY name").fetchall()
|
||||
settings_providers = c.execute("SELECT * FROM table_settings_providers ORDER BY name").fetchall()
|
||||
c.close()
|
||||
|
||||
settings_general = get_general_settings()
|
||||
settings_sonarr = get_sonarr_settings()
|
||||
settings_radarr = get_radarr_settings()
|
||||
|
||||
return template('wizard', __file__=__file__, bazarr_version=bazarr_version, settings_general=settings_general,
|
||||
settings_languages=settings_languages, settings_providers=settings_providers,
|
||||
settings_sonarr=settings_sonarr, settings_radarr=settings_radarr, base_url=base_url)
|
||||
|
||||
|
||||
@route(base_url + 'save_wizard', method='POST')
|
||||
@custom_auth_basic(check_credentials)
|
||||
def save_wizard():
|
||||
authorize()
|
||||
|
||||
conn = sqlite3.connect(os.path.join(config_dir, 'db/bazarr.db'), timeout=30)
|
||||
c = conn.cursor()
|
||||
|
||||
settings_general_ip = request.forms.get('settings_general_ip')
|
||||
settings_general_port = request.forms.get('settings_general_port')
|
||||
settings_general_baseurl = request.forms.get('settings_general_baseurl')
|
||||
if settings_general_baseurl.endswith('/') is False:
|
||||
settings_general_baseurl += '/'
|
||||
settings_general_sourcepath = request.forms.getall('settings_general_sourcepath')
|
||||
settings_general_destpath = request.forms.getall('settings_general_destpath')
|
||||
settings_general_pathmapping = []
|
||||
settings_general_pathmapping.extend([list(a) for a in zip(settings_general_sourcepath, settings_general_destpath)])
|
||||
settings_general_sourcepath_movie = request.forms.getall('settings_general_sourcepath_movie')
|
||||
settings_general_destpath_movie = request.forms.getall('settings_general_destpath_movie')
|
||||
settings_general_pathmapping_movie = []
|
||||
settings_general_pathmapping_movie.extend(
|
||||
[list(a) for a in zip(settings_general_sourcepath_movie, settings_general_destpath_movie)])
|
||||
settings_general_single_language = request.forms.get('settings_general_single_language')
|
||||
if settings_general_single_language is None:
|
||||
settings_general_single_language = 'False'
|
||||
else:
|
||||
settings_general_single_language = 'True'
|
||||
settings_general_adaptive_searching = request.forms.get('settings_general_adaptive_searching')
|
||||
if settings_general_adaptive_searching is None:
|
||||
settings_general_adaptive_searching = 'False'
|
||||
else:
|
||||
settings_general_adaptive_searching = 'True'
|
||||
settings_general_use_sonarr = request.forms.get('settings_general_use_sonarr')
|
||||
if settings_general_use_sonarr is None:
|
||||
settings_general_use_sonarr = 'False'
|
||||
else:
|
||||
settings_general_use_sonarr = 'True'
|
||||
settings_general_use_radarr = request.forms.get('settings_general_use_radarr')
|
||||
if settings_general_use_radarr is None:
|
||||
settings_general_use_radarr = 'False'
|
||||
else:
|
||||
settings_general_use_radarr = 'True'
|
||||
|
||||
cfg = ConfigParser()
|
||||
|
||||
if not cfg.has_section('general'):
|
||||
cfg.add_section('general')
|
||||
|
||||
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', 'log_level', text_type(get_general_settings()[4]))
|
||||
cfg.set('general', 'branch', text_type(get_general_settings()[5]))
|
||||
cfg.set('general', 'auto_update', text_type(get_general_settings()[6]))
|
||||
cfg.set('general', 'single_language', text_type(settings_general_single_language))
|
||||
cfg.set('general', 'minimum_score', text_type(get_general_settings()[8]))
|
||||
cfg.set('general', 'use_scenename', text_type(text_type(get_general_settings()[9])))
|
||||
cfg.set('general', 'use_postprocessing', text_type(get_general_settings()[10]))
|
||||
cfg.set('general', 'postprocessing_cmd', text_type(get_general_settings()[11]))
|
||||
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(get_general_settings()[21]))
|
||||
cfg.set('general', 'minimum_score_movie', text_type(get_general_settings()[22]))
|
||||
cfg.set('general', 'use_embedded_subs', text_type(get_general_settings()[23]))
|
||||
cfg.set('general', 'only_monitored', text_type(get_general_settings()[24]))
|
||||
cfg.set('general', 'adaptive_searching', text_type(settings_general_adaptive_searching))
|
||||
|
||||
if not cfg.has_section('proxy'):
|
||||
cfg.add_section('proxy')
|
||||
|
||||
cfg.set('proxy', 'type', text_type(get_proxy_settings()[0]))
|
||||
cfg.set('proxy', 'url', text_type(get_proxy_settings()[1]))
|
||||
cfg.set('proxy', 'port', text_type(get_proxy_settings()[2]))
|
||||
cfg.set('proxy', 'username', text_type(get_proxy_settings()[3]))
|
||||
cfg.set('proxy', 'password', text_type(get_proxy_settings()[4]))
|
||||
cfg.set('proxy', 'exclude', text_type(get_proxy_settings()[5]))
|
||||
|
||||
if not cfg.has_section('auth'):
|
||||
cfg.add_section('auth')
|
||||
|
||||
cfg.set('auth', 'type', text_type(get_auth_settings()[0]))
|
||||
cfg.set('auth', 'username', text_type(get_auth_settings()[1]))
|
||||
cfg.set('auth', 'password', text_type(get_auth_settings()[2]))
|
||||
|
||||
settings_sonarr_ip = request.forms.get('settings_sonarr_ip')
|
||||
settings_sonarr_port = request.forms.get('settings_sonarr_port')
|
||||
settings_sonarr_baseurl = request.forms.get('settings_sonarr_baseurl')
|
||||
settings_sonarr_ssl = request.forms.get('settings_sonarr_ssl')
|
||||
if settings_sonarr_ssl is None:
|
||||
settings_sonarr_ssl = 'False'
|
||||
else:
|
||||
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(get_sonarr_settings()[5]))
|
||||
|
||||
settings_radarr_ip = request.forms.get('settings_radarr_ip')
|
||||
settings_radarr_port = request.forms.get('settings_radarr_port')
|
||||
settings_radarr_baseurl = request.forms.get('settings_radarr_baseurl')
|
||||
settings_radarr_ssl = request.forms.get('settings_radarr_ssl')
|
||||
if settings_radarr_ssl is None:
|
||||
settings_radarr_ssl = 'False'
|
||||
else:
|
||||
settings_radarr_ssl = 'True'
|
||||
settings_radarr_apikey = request.forms.get('settings_radarr_apikey')
|
||||
if settings_radarr_apikey != '':
|
||||
cfg.set('general', 'use_radarr', 'True')
|
||||
else:
|
||||
cfg.set('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(get_radarr_settings()[5]))
|
||||
|
||||
settings_subliminal_providers = request.forms.getall('settings_subliminal_providers')
|
||||
c.execute("UPDATE table_settings_providers SET enabled = 0")
|
||||
for item in settings_subliminal_providers:
|
||||
c.execute("UPDATE table_settings_providers SET enabled = '1' WHERE name = ?", (item,))
|
||||
|
||||
settings_subliminal_languages = request.forms.getall('settings_subliminal_languages')
|
||||
c.execute("UPDATE table_settings_languages SET enabled = 0")
|
||||
for item in settings_subliminal_languages:
|
||||
c.execute("UPDATE table_settings_languages SET enabled = '1' WHERE code2 = ?", (item,))
|
||||
|
||||
settings_serie_default_enabled = request.forms.get('settings_serie_default_enabled')
|
||||
if settings_serie_default_enabled is None:
|
||||
settings_serie_default_enabled = 'False'
|
||||
else:
|
||||
settings_serie_default_enabled = 'True'
|
||||
cfg.set('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_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_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_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_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))
|
||||
|
||||
with open(config_file, 'w+') as f:
|
||||
cfg.write(f)
|
||||
|
||||
logging.info('Config file created successfully')
|
||||
|
||||
conn.commit()
|
||||
c.close()
|
||||
|
||||
configured()
|
||||
redirect(base_url)
|
||||
|
||||
|
||||
@route(base_url + 'static/:path#.+#', name='static')
|
||||
@custom_auth_basic(check_credentials)
|
||||
def static(path):
|
||||
|
@ -294,6 +508,8 @@ def redirect_root():
|
|||
redirect(base_url + 'series')
|
||||
elif get_general_settings()[13] is True:
|
||||
redirect(base_url + 'movies')
|
||||
elif os.path.exists(os.path.join(config_dir, 'config/config.ini')) is False:
|
||||
redirect(base_url + 'wizard')
|
||||
else:
|
||||
redirect(base_url + 'settings')
|
||||
|
||||
|
@ -303,11 +519,11 @@ def redirect_root():
|
|||
def series():
|
||||
authorize()
|
||||
single_language = get_general_settings()[7]
|
||||
|
||||
|
||||
db = sqlite3.connect(os.path.join(config_dir, 'db/bazarr.db'), timeout=30)
|
||||
db.create_function("path_substitution", 1, path_replace)
|
||||
c = db.cursor()
|
||||
|
||||
|
||||
c.execute("SELECT COUNT(*) FROM table_shows")
|
||||
missing_count = c.fetchone()
|
||||
missing_count = missing_count[0]
|
||||
|
@ -317,19 +533,28 @@ def series():
|
|||
page_size = int(get_general_settings()[21])
|
||||
offset = (int(page) - 1) * page_size
|
||||
max_page = int(math.ceil(missing_count / (page_size + 0.0)))
|
||||
|
||||
|
||||
if get_general_settings()[24] is True:
|
||||
monitored_only_query_string = ' AND monitored = "True"'
|
||||
else:
|
||||
monitored_only_query_string = ""
|
||||
|
||||
c.execute("SELECT tvdbId, title, path_substitution(path), languages, hearing_impaired, sonarrSeriesId, poster, audio_language FROM table_shows ORDER BY sortTitle ASC LIMIT ? OFFSET ?", (page_size, offset,))
|
||||
data = c.fetchall()
|
||||
c.execute("SELECT code2, name FROM table_settings_languages WHERE enabled = 1")
|
||||
languages = c.fetchall()
|
||||
c.execute("SELECT table_shows.sonarrSeriesId, COUNT(table_episodes.missing_subtitles) FROM table_shows LEFT JOIN table_episodes ON table_shows.sonarrSeriesId=table_episodes.sonarrSeriesId WHERE table_shows.languages IS NOT 'None' AND table_episodes.missing_subtitles IS NOT '[]' GROUP BY table_shows.sonarrSeriesId")
|
||||
c.execute("SELECT table_shows.sonarrSeriesId, COUNT(table_episodes.missing_subtitles) FROM table_shows LEFT JOIN table_episodes ON table_shows.sonarrSeriesId=table_episodes.sonarrSeriesId WHERE table_shows.languages IS NOT 'None' AND table_episodes.missing_subtitles IS NOT '[]'" + monitored_only_query_string + " GROUP BY table_shows.sonarrSeriesId")
|
||||
missing_subtitles_list = c.fetchall()
|
||||
c.execute("SELECT table_shows.sonarrSeriesId, COUNT(table_episodes.missing_subtitles) FROM table_shows LEFT JOIN table_episodes ON table_shows.sonarrSeriesId=table_episodes.sonarrSeriesId WHERE table_shows.languages IS NOT 'None' GROUP BY table_shows.sonarrSeriesId")
|
||||
c.execute("SELECT table_shows.sonarrSeriesId, COUNT(table_episodes.missing_subtitles) FROM table_shows LEFT JOIN table_episodes ON table_shows.sonarrSeriesId=table_episodes.sonarrSeriesId WHERE table_shows.languages IS NOT 'None'" + monitored_only_query_string + " GROUP BY table_shows.sonarrSeriesId")
|
||||
total_subtitles_list = c.fetchall()
|
||||
c.close()
|
||||
output = template('series', __file__=__file__, bazarr_version=bazarr_version, rows=data, missing_subtitles_list=missing_subtitles_list, total_subtitles_list=total_subtitles_list, languages=languages, missing_count=missing_count, page=page, max_page=max_page, base_url=base_url, single_language=single_language, page_size=page_size, current_port=port)
|
||||
output = template('series', __file__=__file__, bazarr_version=bazarr_version, rows=data,
|
||||
missing_subtitles_list=missing_subtitles_list, total_subtitles_list=total_subtitles_list,
|
||||
languages=languages, missing_count=missing_count, page=page, max_page=max_page, base_url=base_url,
|
||||
single_language=single_language, page_size=page_size, current_port=port)
|
||||
return output
|
||||
|
||||
|
||||
@route(base_url + 'serieseditor')
|
||||
@custom_auth_basic(check_credentials)
|
||||
def serieseditor():
|
||||
|
@ -1102,197 +1327,16 @@ def save_settings():
|
|||
with open(config_file, 'wb') as f:
|
||||
cfg.write(f)
|
||||
|
||||
settings_notifier_Boxcar_enabled = request.forms.get('settings_notifier_Boxcar_enabled')
|
||||
if settings_notifier_Boxcar_enabled == 'on':
|
||||
settings_notifier_Boxcar_enabled = 1
|
||||
else:
|
||||
settings_notifier_Boxcar_enabled = 0
|
||||
settings_notifier_Boxcar_url = request.forms.get('settings_notifier_Boxcar_url')
|
||||
c.execute("UPDATE table_settings_notifier SET enabled = ?, url = ? WHERE name = 'Boxcar'", (settings_notifier_Boxcar_enabled, settings_notifier_Boxcar_url))
|
||||
|
||||
settings_notifier_Faast_enabled = request.forms.get('settings_notifier_Faast_enabled')
|
||||
if settings_notifier_Faast_enabled == 'on':
|
||||
settings_notifier_Faast_enabled = 1
|
||||
else:
|
||||
settings_notifier_Faast_enabled = 0
|
||||
settings_notifier_Faast_url = request.forms.get('settings_notifier_Faast_url')
|
||||
c.execute("UPDATE table_settings_notifier SET enabled = ?, url = ? WHERE name = 'Faast'", (settings_notifier_Faast_enabled, settings_notifier_Faast_url))
|
||||
|
||||
settings_notifier_Growl_enabled = request.forms.get('settings_notifier_Growl_enabled')
|
||||
if settings_notifier_Growl_enabled == 'on':
|
||||
settings_notifier_Growl_enabled = 1
|
||||
else:
|
||||
settings_notifier_Growl_enabled = 0
|
||||
settings_notifier_Growl_url = request.forms.get('settings_notifier_Growl_url')
|
||||
c.execute("UPDATE table_settings_notifier SET enabled = ?, url = ? WHERE name = 'Growl'", (settings_notifier_Growl_enabled, settings_notifier_Growl_url))
|
||||
|
||||
settings_notifier_Join_enabled = request.forms.get('settings_notifier_Join_enabled')
|
||||
if settings_notifier_Join_enabled == 'on':
|
||||
settings_notifier_Join_enabled = 1
|
||||
else:
|
||||
settings_notifier_Join_enabled = 0
|
||||
settings_notifier_Join_url = request.forms.get('settings_notifier_Join_url')
|
||||
c.execute("UPDATE table_settings_notifier SET enabled = ?, url = ? WHERE name = 'Join'", (settings_notifier_Join_enabled, settings_notifier_Join_url))
|
||||
|
||||
settings_notifier_KODI_enabled = request.forms.get('settings_notifier_KODI_enabled')
|
||||
if settings_notifier_KODI_enabled == 'on':
|
||||
settings_notifier_KODI_enabled = 1
|
||||
else:
|
||||
settings_notifier_KODI_enabled = 0
|
||||
settings_notifier_KODI_url = request.forms.get('settings_notifier_KODI_url')
|
||||
c.execute("UPDATE table_settings_notifier SET enabled = ?, url = ? WHERE name = 'KODI'", (settings_notifier_KODI_enabled, settings_notifier_KODI_url))
|
||||
|
||||
settings_notifier_Mattermost_enabled = request.forms.get('settings_notifier_Mattermost_enabled')
|
||||
if settings_notifier_Mattermost_enabled == 'on':
|
||||
settings_notifier_Mattermost_enabled = 1
|
||||
else:
|
||||
settings_notifier_Mattermost_enabled = 0
|
||||
settings_notifier_Mattermost_url = request.forms.get('settings_notifier_Mattermost_url')
|
||||
c.execute("UPDATE table_settings_notifier SET enabled = ?, url = ? WHERE name = 'Mattermost'", (settings_notifier_Mattermost_enabled, settings_notifier_Mattermost_url))
|
||||
|
||||
settings_notifier_NMA_enabled = request.forms.get('settings_notifier_Notify My Android_enabled')
|
||||
if settings_notifier_NMA_enabled == 'on':
|
||||
settings_notifier_NMA_enabled = 1
|
||||
else:
|
||||
settings_notifier_NMA_enabled = 0
|
||||
settings_notifier_NMA_url = request.forms.get('settings_notifier_Notify My Android_url')
|
||||
c.execute("UPDATE table_settings_notifier SET enabled = ?, url = ? WHERE name = 'Notify My Android'", (settings_notifier_NMA_enabled, settings_notifier_NMA_url))
|
||||
|
||||
settings_notifier_Prowl_enabled = request.forms.get('settings_notifier_Prowl_enabled')
|
||||
if settings_notifier_Prowl_enabled == 'on':
|
||||
settings_notifier_Prowl_enabled = 1
|
||||
else:
|
||||
settings_notifier_Prowl_enabled = 0
|
||||
settings_notifier_Prowl_url = request.forms.get('settings_notifier_Prowl_url')
|
||||
c.execute("UPDATE table_settings_notifier SET enabled = ?, url = ? WHERE name = 'Prowl'", (settings_notifier_Prowl_enabled, settings_notifier_Prowl_url))
|
||||
|
||||
settings_notifier_Pushalot_enabled = request.forms.get('settings_notifier_Pushalot_enabled')
|
||||
if settings_notifier_Pushalot_enabled == 'on':
|
||||
settings_notifier_Pushalot_enabled = 1
|
||||
else:
|
||||
settings_notifier_Pushalot_enabled = 0
|
||||
settings_notifier_Pushalot_url = request.forms.get('settings_notifier_Pushalot_url')
|
||||
c.execute("UPDATE table_settings_notifier SET enabled = ?, url = ? WHERE name = 'Pushalot'", (settings_notifier_Pushalot_enabled, settings_notifier_Pushalot_url))
|
||||
|
||||
settings_notifier_PushBullet_enabled = request.forms.get('settings_notifier_PushBullet_enabled')
|
||||
if settings_notifier_PushBullet_enabled == 'on':
|
||||
settings_notifier_PushBullet_enabled = 1
|
||||
else:
|
||||
settings_notifier_PushBullet_enabled = 0
|
||||
settings_notifier_PushBullet_url = request.forms.get('settings_notifier_PushBullet_url')
|
||||
c.execute("UPDATE table_settings_notifier SET enabled = ?, url = ? WHERE name = 'PushBullet'", (settings_notifier_PushBullet_enabled, settings_notifier_PushBullet_url))
|
||||
|
||||
settings_notifier_Pushjet_enabled = request.forms.get('settings_notifier_Pushjet_enabled')
|
||||
if settings_notifier_Pushjet_enabled == 'on':
|
||||
settings_notifier_Pushjet_enabled = 1
|
||||
else:
|
||||
settings_notifier_Pushjet_enabled = 0
|
||||
settings_notifier_Pushjet_url = request.forms.get('settings_notifier_Pushjet_url')
|
||||
c.execute("UPDATE table_settings_notifier SET enabled = ?, url = ? WHERE name = 'Pushjet'", (settings_notifier_Pushjet_enabled, settings_notifier_Pushjet_url))
|
||||
|
||||
settings_notifier_Pushover_enabled = request.forms.get('settings_notifier_Pushover_enabled')
|
||||
if settings_notifier_Pushover_enabled == 'on':
|
||||
settings_notifier_Pushover_enabled = 1
|
||||
else:
|
||||
settings_notifier_Pushover_enabled = 0
|
||||
settings_notifier_Pushover_url = request.forms.get('settings_notifier_Pushover_url')
|
||||
c.execute("UPDATE table_settings_notifier SET enabled = ?, url = ? WHERE name = 'Pushover'", (settings_notifier_Pushover_enabled, settings_notifier_Pushover_url))
|
||||
|
||||
settings_notifier_RocketChat_enabled = request.forms.get('settings_notifier_Rocket.Chat_enabled')
|
||||
if settings_notifier_RocketChat_enabled == 'on':
|
||||
settings_notifier_RocketChat_enabled = 1
|
||||
else:
|
||||
settings_notifier_RocketChat_enabled = 0
|
||||
settings_notifier_RocketChat_url = request.forms.get('settings_notifier_Rocket.Chat_url')
|
||||
c.execute("UPDATE table_settings_notifier SET enabled = ?, url = ? WHERE name = 'Rocket.Chat'", (settings_notifier_RocketChat_enabled, settings_notifier_RocketChat_url))
|
||||
|
||||
settings_notifier_Slack_enabled = request.forms.get('settings_notifier_Slack_enabled')
|
||||
if settings_notifier_Slack_enabled == 'on':
|
||||
settings_notifier_Slack_enabled = 1
|
||||
else:
|
||||
settings_notifier_Slack_enabled = 0
|
||||
settings_notifier_Slack_url = request.forms.get('settings_notifier_Slack_url')
|
||||
c.execute("UPDATE table_settings_notifier SET enabled = ?, url = ? WHERE name = 'Slack'", (settings_notifier_Slack_enabled, settings_notifier_Slack_url))
|
||||
|
||||
settings_notifier_SuperToasty_enabled = request.forms.get('settings_notifier_Super Toasty_enabled')
|
||||
if settings_notifier_SuperToasty_enabled == 'on':
|
||||
settings_notifier_SuperToasty_enabled = 1
|
||||
else:
|
||||
settings_notifier_SuperToasty_enabled = 0
|
||||
settings_notifier_SuperToasty_url = request.forms.get('settings_notifier_Super Toasty_url')
|
||||
c.execute("UPDATE table_settings_notifier SET enabled = ?, url = ? WHERE name = 'Super Toasty'", (settings_notifier_SuperToasty_enabled, settings_notifier_SuperToasty_url))
|
||||
|
||||
settings_notifier_Telegram_enabled = request.forms.get('settings_notifier_Telegram_enabled')
|
||||
if settings_notifier_Telegram_enabled == 'on':
|
||||
settings_notifier_Telegram_enabled = 1
|
||||
else:
|
||||
settings_notifier_Telegram_enabled = 0
|
||||
settings_notifier_Telegram_url = request.forms.get('settings_notifier_Telegram_url')
|
||||
c.execute("UPDATE table_settings_notifier SET enabled = ?, url = ? WHERE name = 'Telegram'", (settings_notifier_Telegram_enabled, settings_notifier_Telegram_url))
|
||||
|
||||
settings_notifier_Twitter_enabled = request.forms.get('settings_notifier_Twitter_enabled')
|
||||
if settings_notifier_Twitter_enabled == 'on':
|
||||
settings_notifier_Twitter_enabled = 1
|
||||
else:
|
||||
settings_notifier_Twitter_enabled = 0
|
||||
settings_notifier_Twitter_url = request.forms.get('settings_notifier_Twitter_url')
|
||||
c.execute("UPDATE table_settings_notifier SET enabled = ?, url = ? WHERE name = 'Twitter'", (settings_notifier_Twitter_enabled, settings_notifier_Twitter_url))
|
||||
|
||||
settings_notifier_XBMC_enabled = request.forms.get('settings_notifier_XBMC_enabled')
|
||||
if settings_notifier_XBMC_enabled == 'on':
|
||||
settings_notifier_XBMC_enabled = 1
|
||||
else:
|
||||
settings_notifier_XBMC_enabled = 0
|
||||
settings_notifier_XBMC_url = request.forms.get('settings_notifier_XBMC_url')
|
||||
c.execute("UPDATE table_settings_notifier SET enabled = ?, url = ? WHERE name = 'XBMC'", (settings_notifier_XBMC_enabled, settings_notifier_XBMC_url))
|
||||
|
||||
settings_notifier_Discord_enabled = request.forms.get('settings_notifier_Discord_enabled')
|
||||
if settings_notifier_Discord_enabled == 'on':
|
||||
settings_notifier_Discord_enabled = 1
|
||||
else:
|
||||
settings_notifier_Discord_enabled = 0
|
||||
settings_notifier_Discord_url = request.forms.get('settings_notifier_Discord_url')
|
||||
c.execute("UPDATE table_settings_notifier SET enabled = ?, url = ? WHERE name = 'Discord'", (settings_notifier_Discord_enabled, settings_notifier_Discord_url))
|
||||
|
||||
settings_notifier_E_Mail_enabled = request.forms.get('settings_notifier_E-Mail_enabled')
|
||||
if settings_notifier_E_Mail_enabled == 'on':
|
||||
settings_notifier_E_Mail_enabled = 1
|
||||
else:
|
||||
settings_notifier_E_Mail_enabled = 0
|
||||
settings_notifier_E_Mail_url = request.forms.get('settings_notifier_E-Mail_url')
|
||||
c.execute("UPDATE table_settings_notifier SET enabled = ?, url = ? WHERE name = 'E-Mail'", (settings_notifier_E_Mail_enabled, settings_notifier_E_Mail_url))
|
||||
|
||||
settings_notifier_Emby_enabled = request.forms.get('settings_notifier_Emby_enabled')
|
||||
if settings_notifier_Emby_enabled == 'on':
|
||||
settings_notifier_Emby_enabled = 1
|
||||
else:
|
||||
settings_notifier_Emby_enabled = 0
|
||||
settings_notifier_Emby_url = request.forms.get('settings_notifier_Emby_url')
|
||||
c.execute("UPDATE table_settings_notifier SET enabled = ?, url = ? WHERE name = 'Emby'", (settings_notifier_Emby_enabled, settings_notifier_Emby_url))
|
||||
|
||||
settings_notifier_IFTTT_enabled = request.forms.get('settings_notifier_IFTTT_enabled')
|
||||
if settings_notifier_IFTTT_enabled == 'on':
|
||||
settings_notifier_IFTTT_enabled = 1
|
||||
else:
|
||||
settings_notifier_IFTTT_enabled = 0
|
||||
settings_notifier_IFTTT_url = request.forms.get('settings_notifier_IFTTT_url')
|
||||
c.execute("UPDATE table_settings_notifier SET enabled = ?, url = ? WHERE name = 'IFTTT'", (settings_notifier_IFTTT_enabled, settings_notifier_IFTTT_url))
|
||||
|
||||
settings_notifier_Stride_enabled = request.forms.get('settings_notifier_Stride_enabled')
|
||||
if settings_notifier_Stride_enabled == 'on':
|
||||
settings_notifier_Stride_enabled = 1
|
||||
else:
|
||||
settings_notifier_Stride_enabled = 0
|
||||
settings_notifier_Stride_url = request.forms.get('settings_notifier_Stride_url')
|
||||
c.execute("UPDATE table_settings_notifier SET enabled = ?, url = ? WHERE name = 'Stride'", (settings_notifier_Stride_enabled, settings_notifier_Stride_url))
|
||||
|
||||
settings_notifier_Windows_enabled = request.forms.get('settings_notifier_Windows_enabled')
|
||||
if settings_notifier_Windows_enabled == 'on':
|
||||
settings_notifier_Windows_enabled = 1
|
||||
else:
|
||||
settings_notifier_Windows_enabled = 0
|
||||
settings_notifier_Windows_url = request.forms.get('settings_notifier_Windows_url')
|
||||
c.execute("UPDATE table_settings_notifier SET enabled = ?, url = ? WHERE name = 'Windows'", (settings_notifier_Windows_enabled, settings_notifier_Windows_url))
|
||||
notifiers = c.execute("SELECT * FROM table_settings_notifier ORDER BY name").fetchall()
|
||||
for notifier in notifiers:
|
||||
enabled = request.forms.get('settings_notifier_' + notifier[0] + '_enabled')
|
||||
if enabled == 'on':
|
||||
enabled = 1
|
||||
else:
|
||||
enabled = 0
|
||||
notifier_url = request.forms.get('settings_notifier_' + notifier[0] + '_url')
|
||||
c.execute("UPDATE table_settings_notifier SET enabled = ?, url = ? WHERE name = ?",
|
||||
(enabled, notifier_url, notifier[0]))
|
||||
|
||||
conn.commit()
|
||||
c.close()
|
||||
|
|
|
@ -3,6 +3,41 @@ from get_argv import config_dir
|
|||
import apprise
|
||||
import os
|
||||
import sqlite3
|
||||
import logging
|
||||
|
||||
|
||||
def update_notifier():
|
||||
# define apprise object
|
||||
a = apprise.Apprise()
|
||||
|
||||
# Retrieve all of the details
|
||||
results = a.details()
|
||||
|
||||
notifiers_new = []
|
||||
notifiers_old = []
|
||||
|
||||
conn_db = sqlite3.connect(os.path.join(config_dir, 'db/bazarr.db'), timeout=30)
|
||||
c_db = conn_db.cursor()
|
||||
notifiers_current = c_db.execute('SELECT name FROM table_settings_notifier').fetchall()
|
||||
for x in results['schemas']:
|
||||
if x['service_name'] not in str(notifiers_current):
|
||||
notifiers_new.append(x['service_name'])
|
||||
logging.debug('Adding new notifier agent: ' + x['service_name'])
|
||||
else:
|
||||
notifiers_old.append(x['service_name'])
|
||||
notifier_current = [i[0] for i in notifiers_current]
|
||||
|
||||
notifiers_to_delete = list(set(notifier_current) - set(notifiers_old))
|
||||
|
||||
for notifier_new in notifiers_new:
|
||||
c_db.execute('INSERT INTO `table_settings_notifier` (name, enabled) VALUES (?, ?);', (notifier_new, '0'))
|
||||
|
||||
for notifier_to_delete in notifiers_to_delete:
|
||||
c_db.execute('DELETE FROM `table_settings_notifier` WHERE name=?', (notifier_to_delete,))
|
||||
|
||||
conn_db.commit()
|
||||
c_db.close()
|
||||
|
||||
|
||||
def get_notifier_providers():
|
||||
conn_db = sqlite3.connect(os.path.join(config_dir, 'db/bazarr.db'), timeout=30)
|
||||
|
|
|
@ -29,43 +29,18 @@ if os.path.exists(os.path.join(config_dir, 'db/bazarr.db')) == True:
|
|||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
c.execute('CREATE TABLE `table_settings_notifier` (`name` TEXT, `url` TEXT, `enabled` INTEGER);')
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
providers = ['Boxcar','Faast','Growl','Join','KODI','Mattermost','Notify My Android','Prowl','Pushalot','PushBullet','Pushjet','Pushover','Rocket.Chat','Slack','Super Toasty','Telegram','Twitter','XBMC']
|
||||
for provider in providers:
|
||||
c.execute('INSERT INTO `table_settings_notifier` (name, enabled) VALUES (?, ?);', (provider,'0'))
|
||||
|
||||
try:
|
||||
c.execute('alter table table_shows add column "sortTitle" "text"')
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
c.execute('CREATE TABLE "table_movies" ( `tmdbId` TEXT NOT NULL UNIQUE, `title` TEXT NOT NULL, `path` TEXT NOT NULL UNIQUE, `languages` TEXT, `subtitles` TEXT, `missing_subtitles` TEXT, `hearing_impaired` TEXT, `radarrId` INTEGER NOT NULL UNIQUE, `overview` TEXT, `poster` TEXT, `fanart` TEXT, "audio_language" "text", `sceneName` TEXT, PRIMARY KEY(`tmdbId`) )')
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
c.execute('CREATE TABLE "table_history_movie" ( `id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE, `action` INTEGER NOT NULL, `radarrId` INTEGER NOT NULL, `timestamp` INTEGER NOT NULL, `description` TEXT NOT NULL )')
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
c.execute('DELETE FROM table_settings_notifier WHERE rowid > 24') #Modify this if we add more notification provider
|
||||
rows = c.execute('SELECT name FROM table_settings_notifier WHERE name = "Discord"').fetchall()
|
||||
rows = c.execute('SELECT name FROM table_settings_notifier WHERE name = "Kodi/XBMC"').fetchall()
|
||||
if len(rows) == 0:
|
||||
providers = ['Discord', 'E-Mail', 'Emby', 'IFTTT', 'Stride', 'Windows']
|
||||
for provider in providers:
|
||||
c.execute('INSERT INTO `table_settings_notifier` (name, enabled) VALUES (?, ?);', (provider, '0'))
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
c.execute('CREATE TABLE `system` ( `configured` TEXT, `updated` TEXT)')
|
||||
c.execute('INSERT INTO `system` (configured, updated) VALUES (?, ?);', ('0', '0'))
|
||||
providers = [['KODI', 'Kodi/XBMC'], ['Windows', 'Windows Notification'], ['Super Toasty', 'Toasty'],
|
||||
['PushBullet', 'Pushbullet'], ['Mattermost', 'MatterMost']]
|
||||
for provider_old, provider_new in providers:
|
||||
c.execute('UPDATE table_settings_notifier SET name=? WHERE name=?', (provider_new, provider_old))
|
||||
except:
|
||||
pass
|
||||
|
||||
|
@ -75,6 +50,11 @@ if os.path.exists(os.path.join(config_dir, 'db/bazarr.db')) == True:
|
|||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
c.execute('alter table table_settings_languages add column "code3b" "text"')
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
# Commit change to db
|
||||
db.commit()
|
||||
|
@ -87,13 +67,13 @@ if os.path.exists(os.path.join(config_dir, 'db/bazarr.db')) == True:
|
|||
else:
|
||||
from scheduler import execute_now
|
||||
from get_settings import get_general_settings
|
||||
|
||||
integration = get_general_settings()
|
||||
if integration[12] is True:
|
||||
execute_now('sync_episodes')
|
||||
if integration[13] is True:
|
||||
execute_now('update_movies')
|
||||
|
||||
|
||||
try:
|
||||
c.execute('alter table table_episodes add column "monitored" TEXT')
|
||||
db.commit()
|
||||
|
@ -102,6 +82,7 @@ if os.path.exists(os.path.join(config_dir, 'db/bazarr.db')) == True:
|
|||
else:
|
||||
from scheduler import execute_now
|
||||
from get_settings import get_general_settings
|
||||
|
||||
integration = get_general_settings()
|
||||
if integration[12] is True:
|
||||
execute_now('sync_episodes')
|
||||
|
@ -114,6 +95,7 @@ if os.path.exists(os.path.join(config_dir, 'db/bazarr.db')) == True:
|
|||
else:
|
||||
from scheduler import execute_now
|
||||
from get_settings import get_general_settings
|
||||
|
||||
integration = get_general_settings()
|
||||
if integration[13] is True:
|
||||
execute_now('update_movies')
|
||||
|
|
|
@ -32,6 +32,7 @@ from .AppriseAsset import AppriseAsset
|
|||
|
||||
from . import NotifyBase
|
||||
from . import plugins
|
||||
from . import __version__
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -54,6 +55,9 @@ def __load_matrix():
|
|||
|
||||
# Get our plugin
|
||||
plugin = getattr(plugins, entry)
|
||||
if not hasattr(plugin, 'app_id'): # pragma: no branch
|
||||
# Filter out non-notification modules
|
||||
continue
|
||||
|
||||
# Load protocol(s) if defined
|
||||
proto = getattr(plugin, 'protocol', None)
|
||||
|
@ -277,6 +281,52 @@ class Apprise(object):
|
|||
|
||||
return status
|
||||
|
||||
def details(self):
|
||||
"""
|
||||
Returns the details associated with the Apprise object
|
||||
|
||||
"""
|
||||
|
||||
# general object returned
|
||||
response = {
|
||||
# Defines the current version of Apprise
|
||||
'version': __version__,
|
||||
# Lists all of the currently supported Notifications
|
||||
'schemas': [],
|
||||
# Includes the configured asset details
|
||||
'asset': self.asset.details(),
|
||||
}
|
||||
|
||||
# to add it's mapping to our hash table
|
||||
for entry in sorted(dir(plugins)):
|
||||
|
||||
# Get our plugin
|
||||
plugin = getattr(plugins, entry)
|
||||
if not hasattr(plugin, 'app_id'): # pragma: no branch
|
||||
# Filter out non-notification modules
|
||||
continue
|
||||
|
||||
# Standard protocol(s) should be None or a tuple
|
||||
protocols = getattr(plugin, 'protocol', None)
|
||||
if compat_is_basestring(protocols):
|
||||
protocols = (protocols, )
|
||||
|
||||
# Secure protocol(s) should be None or a tuple
|
||||
secure_protocols = getattr(plugin, 'secure_protocol', None)
|
||||
if compat_is_basestring(secure_protocols):
|
||||
secure_protocols = (secure_protocols, )
|
||||
|
||||
# Build our response object
|
||||
response['schemas'].append({
|
||||
'service_name': getattr(plugin, 'service_name', None),
|
||||
'service_url': getattr(plugin, 'service_url', None),
|
||||
'setup_url': getattr(plugin, 'setup_url', None),
|
||||
'protocols': protocols,
|
||||
'secure_protocols': secure_protocols,
|
||||
})
|
||||
|
||||
return response
|
||||
|
||||
def __len__(self):
|
||||
"""
|
||||
Returns the number of servers loaded
|
||||
|
|
|
@ -62,12 +62,13 @@ class AppriseAsset(object):
|
|||
|
||||
# Image URL Mask
|
||||
image_url_mask = \
|
||||
'http://nuxref.com/apprise/themes/{THEME}/' \
|
||||
'apprise-{TYPE}-{XY}{EXTENSION}'
|
||||
'https://github.com/caronc/apprise/raw/master/apprise/assets/' \
|
||||
'themes/{THEME}/apprise-{TYPE}-{XY}{EXTENSION}'
|
||||
|
||||
# Application Logo
|
||||
image_url_logo = \
|
||||
'http://nuxref.com/apprise/themes/{THEME}/apprise-logo.png'
|
||||
'https://github.com/caronc/apprise/raw/master/apprise/assets/' \
|
||||
'themes/{THEME}/apprise-logo.png'
|
||||
|
||||
# Image Path Mask
|
||||
image_path_mask = abspath(join(
|
||||
|
@ -216,6 +217,21 @@ class AppriseAsset(object):
|
|||
|
||||
return None
|
||||
|
||||
def details(self):
|
||||
"""
|
||||
Returns the details associated with the AppriseAsset object
|
||||
|
||||
"""
|
||||
return {
|
||||
'app_id': self.app_id,
|
||||
'app_desc': self.app_desc,
|
||||
'default_extension': self.default_extension,
|
||||
'theme': self.theme,
|
||||
'image_path_mask': self.image_url_mask,
|
||||
'image_url_mask': self.image_url_mask,
|
||||
'image_url_logo': self.image_url_logo,
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def hex_to_rgb(value):
|
||||
"""
|
||||
|
|
|
@ -34,7 +34,6 @@ except ImportError:
|
|||
from ..utils import parse_url
|
||||
from ..utils import parse_bool
|
||||
from ..utils import is_hostname
|
||||
from ..common import NOTIFY_IMAGE_SIZES
|
||||
from ..common import NOTIFY_TYPES
|
||||
from ..common import NotifyFormat
|
||||
from ..common import NOTIFY_FORMATS
|
||||
|
@ -70,7 +69,8 @@ PATHSPLIT_LIST_DELIM = re.compile(r'[ \t\r\n,\\/]+')
|
|||
# Regular expression retrieved from:
|
||||
# http://www.regular-expressions.info/email.html
|
||||
IS_EMAIL_RE = re.compile(
|
||||
r"(?P<userid>[a-z0-9$%+=_~-]+"
|
||||
r"((?P<label>[^+]+)\+)?"
|
||||
r"(?P<userid>[a-z0-9$%=_~-]+"
|
||||
r"(?:\.[a-z0-9$%+=_~-]+)"
|
||||
r"*)@(?P<domain>(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+"
|
||||
r"[a-z0-9](?:[a-z0-9-]*"
|
||||
|
@ -84,16 +84,25 @@ class NotifyBase(object):
|
|||
This is the base class for all notification services
|
||||
"""
|
||||
|
||||
# The default descriptive name associated with the Notification
|
||||
service_name = None
|
||||
|
||||
# The services URL
|
||||
service_url = None
|
||||
|
||||
# The default simple (insecure) protocol
|
||||
# all inheriting entries must provide their protocol lookup
|
||||
# protocol:// (in this example they would specify 'protocol')
|
||||
protocol = ''
|
||||
protocol = None
|
||||
|
||||
# The default secure protocol
|
||||
# all inheriting entries must provide their protocol lookup
|
||||
# protocols:// (in this example they would specify 'protocols')
|
||||
# This value can be the same as the defined protocol.
|
||||
secure_protocol = ''
|
||||
secure_protocol = None
|
||||
|
||||
# A URL that takes you to the setup/help of the specific protocol
|
||||
setup_url = None
|
||||
|
||||
# Most Servers do not like more then 1 request per 5 seconds, so 5.5 gives
|
||||
# us a safe play range...
|
||||
|
|
|
@ -63,9 +63,18 @@ class NotifyBoxcar(NotifyBase):
|
|||
A wrapper for Boxcar Notifications
|
||||
"""
|
||||
|
||||
# The default descriptive name associated with the Notification
|
||||
service_name = 'Boxcar'
|
||||
|
||||
# The services URL
|
||||
service_url = 'https://boxcar.io/'
|
||||
|
||||
# All boxcar notifications are secure
|
||||
secure_protocol = 'boxcar'
|
||||
|
||||
# A URL that takes you to the setup/help of the specific protocol
|
||||
setup_url = 'https://github.com/caronc/apprise/wiki/Notify_boxcar'
|
||||
|
||||
# Boxcar URL
|
||||
notify_url = 'https://boxcar-api.io/api/push/'
|
||||
|
||||
|
|
|
@ -49,10 +49,18 @@ class NotifyDiscord(NotifyBase):
|
|||
A wrapper to Discord Notifications
|
||||
|
||||
"""
|
||||
# The default descriptive name associated with the Notification
|
||||
service_name = 'Discord'
|
||||
|
||||
# The services URL
|
||||
service_url = 'https://discordapp.com/'
|
||||
|
||||
# The default secure protocol
|
||||
secure_protocol = 'discord'
|
||||
|
||||
# A URL that takes you to the setup/help of the specific protocol
|
||||
setup_url = 'https://github.com/caronc/apprise/wiki/Notify_discored'
|
||||
|
||||
# Discord Webhook
|
||||
notify_url = 'https://discordapp.com/api/webhooks'
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ WEBBASE_LOOKUP_TABLE = (
|
|||
# Google GMail
|
||||
(
|
||||
'Google Mail',
|
||||
re.compile(r'^(?P<id>[^@]+)@(?P<domain>gmail\.com)$', re.I),
|
||||
re.compile(r'^((?P<label>[^+]+)\+)?(?P<id>[^@]+)@(?P<domain>gmail\.com)$', re.I),
|
||||
{
|
||||
'port': 587,
|
||||
'smtp_host': 'smtp.gmail.com',
|
||||
|
@ -59,7 +59,7 @@ WEBBASE_LOOKUP_TABLE = (
|
|||
# Pronto Mail
|
||||
(
|
||||
'Pronto Mail',
|
||||
re.compile(r'^(?P<id>[^@]+)@(?P<domain>prontomail\.com)$', re.I),
|
||||
re.compile(r'^((?P<label>[^+]+)\+)?(?P<id>[^@]+)@(?P<domain>prontomail\.com)$', re.I),
|
||||
{
|
||||
'port': 465,
|
||||
'smtp_host': 'secure.emailsrvr.com',
|
||||
|
@ -71,7 +71,7 @@ WEBBASE_LOOKUP_TABLE = (
|
|||
# Microsoft Hotmail
|
||||
(
|
||||
'Microsoft Hotmail',
|
||||
re.compile(r'^(?P<id>[^@]+)@(?P<domain>(hotmail|live)\.com)$', re.I),
|
||||
re.compile(r'^((?P<label>[^+]+)\+)?(?P<id>[^@]+)@(?P<domain>(hotmail|live)\.com)$', re.I),
|
||||
{
|
||||
'port': 587,
|
||||
'smtp_host': 'smtp.live.com',
|
||||
|
@ -83,7 +83,7 @@ WEBBASE_LOOKUP_TABLE = (
|
|||
# Yahoo Mail
|
||||
(
|
||||
'Yahoo Mail',
|
||||
re.compile(r'^(?P<id>[^@]+)@(?P<domain>yahoo\.(ca|com))$', re.I),
|
||||
re.compile(r'^((?P<label>[^+]+)\+)?(?P<id>[^@]+)@(?P<domain>yahoo\.(ca|com))$', re.I),
|
||||
{
|
||||
'port': 465,
|
||||
'smtp_host': 'smtp.mail.yahoo.com',
|
||||
|
@ -95,7 +95,7 @@ WEBBASE_LOOKUP_TABLE = (
|
|||
# Catch All
|
||||
(
|
||||
'Custom',
|
||||
re.compile(r'^(?P<id>[^@]+)@(?P<domain>.+)$', re.I),
|
||||
re.compile(r'^((?P<label>[^+]+)\+)?(?P<id>[^@]+)@(?P<domain>.+)$', re.I),
|
||||
{
|
||||
# Setting smtp_host to None is a way of
|
||||
# auto-detecting it based on other parameters
|
||||
|
@ -113,12 +113,18 @@ class NotifyEmail(NotifyBase):
|
|||
|
||||
"""
|
||||
|
||||
# The default descriptive name associated with the Notification
|
||||
service_name = 'E-Mail'
|
||||
|
||||
# The default simple (insecure) protocol
|
||||
protocol = 'mailto'
|
||||
|
||||
# The default secure protocol
|
||||
secure_protocol = 'mailtos'
|
||||
|
||||
# A URL that takes you to the setup/help of the specific protocol
|
||||
setup_url = 'https://github.com/caronc/apprise/wiki/Notify_email'
|
||||
|
||||
# Default Non-Encryption Port
|
||||
default_port = 25
|
||||
|
||||
|
|
|
@ -37,6 +37,11 @@ class NotifyEmby(NotifyBase):
|
|||
"""
|
||||
A wrapper for Emby Notifications
|
||||
"""
|
||||
# The default descriptive name associated with the Notification
|
||||
service_name = 'Emby'
|
||||
|
||||
# The services URL
|
||||
service_url = 'https://emby.media/'
|
||||
|
||||
# The default protocol
|
||||
protocol = 'emby'
|
||||
|
@ -44,6 +49,9 @@ class NotifyEmby(NotifyBase):
|
|||
# The default secure protocol
|
||||
secure_protocol = 'embys'
|
||||
|
||||
# A URL that takes you to the setup/help of the specific protocol
|
||||
setup_url = 'https://github.com/caronc/apprise/wiki/Notify_emby'
|
||||
|
||||
# Emby uses the http protocol with JSON requests
|
||||
emby_default_port = 8096
|
||||
|
||||
|
|
|
@ -28,9 +28,18 @@ class NotifyFaast(NotifyBase):
|
|||
A wrapper for Faast Notifications
|
||||
"""
|
||||
|
||||
# The default descriptive name associated with the Notification
|
||||
service_name = 'Faast'
|
||||
|
||||
# The services URL
|
||||
service_url = 'http://www.faast.io/'
|
||||
|
||||
# The default protocol (this is secure for faast)
|
||||
protocol = 'faast'
|
||||
|
||||
# A URL that takes you to the setup/help of the specific protocol
|
||||
setup_url = 'https://github.com/caronc/apprise/wiki/Notify_faast'
|
||||
|
||||
# Faast uses the http protocol with JSON requests
|
||||
notify_url = 'https://www.appnotifications.com/account/notifications.json'
|
||||
|
||||
|
|
|
@ -50,9 +50,18 @@ class NotifyGrowl(NotifyBase):
|
|||
|
||||
"""
|
||||
|
||||
# The default descriptive name associated with the Notification
|
||||
service_name = 'Growl'
|
||||
|
||||
# The services URL
|
||||
service_url = 'http://growl.info/'
|
||||
|
||||
# The default protocol
|
||||
protocol = 'growl'
|
||||
|
||||
# A URL that takes you to the setup/help of the specific protocol
|
||||
setup_url = 'https://github.com/caronc/apprise/wiki/Notify_growl'
|
||||
|
||||
# Default Growl Port
|
||||
default_port = 23053
|
||||
|
||||
|
|
|
@ -43,6 +43,18 @@ class NotifyIFTTT(NotifyBase):
|
|||
|
||||
"""
|
||||
|
||||
# The default descriptive name associated with the Notification
|
||||
service_name = 'IFTTT'
|
||||
|
||||
# The services URL
|
||||
service_url = 'https://ifttt.com/'
|
||||
|
||||
# The default protocol
|
||||
protocol = 'ifttt'
|
||||
|
||||
# A URL that takes you to the setup/help of the specific protocol
|
||||
setup_url = 'https://github.com/caronc/apprise/wiki/Notify_ifttt'
|
||||
|
||||
# Even though you'll add 'Ingredients' as {{ Value1 }} to your Applets,
|
||||
# you must use their lowercase value in the HTTP POST.
|
||||
ifttt_default_key_prefix = 'value'
|
||||
|
@ -65,9 +77,6 @@ class NotifyIFTTT(NotifyBase):
|
|||
# value1, value2, and value3).
|
||||
ifttt_default_type_key = 'value3'
|
||||
|
||||
# The default protocol
|
||||
protocol = 'ifttt'
|
||||
|
||||
# IFTTT uses the http protocol with JSON requests
|
||||
notify_url = 'https://maker.ifttt.com/trigger/{event}/with/key/{apikey}'
|
||||
|
||||
|
|
|
@ -30,12 +30,18 @@ class NotifyJSON(NotifyBase):
|
|||
A wrapper for JSON Notifications
|
||||
"""
|
||||
|
||||
# The default descriptive name associated with the Notification
|
||||
service_name = 'JSON'
|
||||
|
||||
# The default protocol
|
||||
protocol = 'json'
|
||||
|
||||
# The default secure protocol
|
||||
secure_protocol = 'jsons'
|
||||
|
||||
# A URL that takes you to the setup/help of the specific protocol
|
||||
setup_url = 'https://github.com/caronc/apprise/wiki/Notify_Custom_JSON'
|
||||
|
||||
# Allows the user to specify the NotifyImageSize object
|
||||
image_size = NotifyImageSize.XY_128
|
||||
|
||||
|
|
|
@ -64,9 +64,18 @@ class NotifyJoin(NotifyBase):
|
|||
A wrapper for Join Notifications
|
||||
"""
|
||||
|
||||
# The default descriptive name associated with the Notification
|
||||
service_name = 'Join'
|
||||
|
||||
# The services URL
|
||||
service_url = 'https://joaoapps.com/join/'
|
||||
|
||||
# The default protocol
|
||||
protocol = 'join'
|
||||
|
||||
# A URL that takes you to the setup/help of the specific protocol
|
||||
setup_url = 'https://github.com/caronc/apprise/wiki/Notify_join'
|
||||
|
||||
# Join uses the http protocol with JSON requests
|
||||
notify_url = \
|
||||
'https://joinjoaomgcd.appspot.com/_ah/api/messaging/v1/sendPush'
|
||||
|
|
|
@ -37,12 +37,21 @@ class NotifyMatterMost(NotifyBase):
|
|||
A wrapper for MatterMost Notifications
|
||||
"""
|
||||
|
||||
# The default descriptive name associated with the Notification
|
||||
service_name = 'MatterMost'
|
||||
|
||||
# The services URL
|
||||
service_url = 'https://mattermost.com/'
|
||||
|
||||
# The default protocol
|
||||
protocol = 'mmost'
|
||||
|
||||
# The default secure protocol
|
||||
secure_protocol = 'mmosts'
|
||||
|
||||
# A URL that takes you to the setup/help of the specific protocol
|
||||
setup_url = 'https://github.com/caronc/apprise/wiki/Notify_mattermost'
|
||||
|
||||
# The default Mattermost port
|
||||
default_port = 8065
|
||||
|
||||
|
|
|
@ -59,9 +59,18 @@ class NotifyProwl(NotifyBase):
|
|||
A wrapper for Prowl Notifications
|
||||
"""
|
||||
|
||||
# The default descriptive name associated with the Notification
|
||||
service_name = 'Prowl'
|
||||
|
||||
# The services URL
|
||||
service_url = 'https://www.prowlapp.com/'
|
||||
|
||||
# The default secure protocol
|
||||
secure_protocol = 'prowl'
|
||||
|
||||
# A URL that takes you to the setup/help of the specific protocol
|
||||
setup_url = 'https://github.com/caronc/apprise/wiki/Notify_prowl'
|
||||
|
||||
# Prowl uses the http protocol with JSON requests
|
||||
notify_url = 'https://api.prowlapp.com/publicapi/add'
|
||||
|
||||
|
|
|
@ -45,9 +45,18 @@ class NotifyPushBullet(NotifyBase):
|
|||
A wrapper for PushBullet Notifications
|
||||
"""
|
||||
|
||||
# The default descriptive name associated with the Notification
|
||||
service_name = 'Pushbullet'
|
||||
|
||||
# The services URL
|
||||
service_url = 'https://www.pushbullet.com/'
|
||||
|
||||
# The default secure protocol
|
||||
secure_protocol = 'pbul'
|
||||
|
||||
# A URL that takes you to the setup/help of the specific protocol
|
||||
setup_url = 'https://github.com/caronc/apprise/wiki/Notify_pushbullet'
|
||||
|
||||
# PushBullet uses the http protocol with JSON requests
|
||||
notify_url = 'https://api.pushbullet.com/v2/pushes'
|
||||
|
||||
|
|
|
@ -40,9 +40,18 @@ class NotifyPushalot(NotifyBase):
|
|||
A wrapper for Pushalot Notifications
|
||||
"""
|
||||
|
||||
# The default descriptive name associated with the Notification
|
||||
service_name = 'Pushalot'
|
||||
|
||||
# The services URL
|
||||
service_url = 'https://pushalot.com/'
|
||||
|
||||
# The default protocol is always secured
|
||||
secure_protocol = 'palot'
|
||||
|
||||
# A URL that takes you to the setup/help of the specific protocol
|
||||
setup_url = 'https://github.com/caronc/apprise/wiki/Notify_pushalot'
|
||||
|
||||
# Pushalot uses the http protocol with JSON requests
|
||||
notify_url = 'https://pushalot.com/api/sendmessage'
|
||||
|
||||
|
|
|
@ -32,12 +32,21 @@ class NotifyPushjet(NotifyBase):
|
|||
A wrapper for Pushjet Notifications
|
||||
"""
|
||||
|
||||
# The default descriptive name associated with the Notification
|
||||
service_name = 'Pushjet'
|
||||
|
||||
# The services URL
|
||||
service_url = 'https://pushjet.io/'
|
||||
|
||||
# The default protocol
|
||||
protocol = 'pjet'
|
||||
|
||||
# The default secure protocol
|
||||
secure_protocol = 'pjets'
|
||||
|
||||
# A URL that takes you to the setup/help of the specific protocol
|
||||
setup_url = 'https://github.com/caronc/apprise/wiki/Notify_pushjet'
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
"""
|
||||
Initialize Pushjet Object
|
||||
|
|
|
@ -68,9 +68,18 @@ class NotifyPushover(NotifyBase):
|
|||
A wrapper for Pushover Notifications
|
||||
"""
|
||||
|
||||
# The default descriptive name associated with the Notification
|
||||
service_name = 'Pushover'
|
||||
|
||||
# The services URL
|
||||
service_url = 'https://pushover.net/'
|
||||
|
||||
# All pushover requests are secure
|
||||
secure_protocol = 'pover'
|
||||
|
||||
# A URL that takes you to the setup/help of the specific protocol
|
||||
setup_url = 'https://github.com/caronc/apprise/wiki/Notify_pushover'
|
||||
|
||||
# Pushover uses the http protocol with JSON requests
|
||||
notify_url = 'https://api.pushover.net/1/messages.json'
|
||||
|
||||
|
|
|
@ -44,12 +44,21 @@ class NotifyRocketChat(NotifyBase):
|
|||
A wrapper for Notify Rocket.Chat Notifications
|
||||
"""
|
||||
|
||||
# The default descriptive name associated with the Notification
|
||||
service_name = 'Rocket.Chat'
|
||||
|
||||
# The services URL
|
||||
service_url = 'https://rocket.chat/'
|
||||
|
||||
# The default protocol
|
||||
protocol = 'rocket'
|
||||
|
||||
# The default secure protocol
|
||||
secure_protocol = 'rockets'
|
||||
|
||||
# A URL that takes you to the setup/help of the specific protocol
|
||||
setup_url = 'https://github.com/caronc/apprise/wiki/Notify_rocketchat'
|
||||
|
||||
# Defines the maximum allowable characters in the title
|
||||
title_maxlen = 200
|
||||
|
||||
|
|
|
@ -71,9 +71,18 @@ class NotifySlack(NotifyBase):
|
|||
A wrapper for Slack Notifications
|
||||
"""
|
||||
|
||||
# The default descriptive name associated with the Notification
|
||||
service_name = 'Slack'
|
||||
|
||||
# The services URL
|
||||
service_url = 'https://slack.com/'
|
||||
|
||||
# The default secure protocol
|
||||
secure_protocol = 'slack'
|
||||
|
||||
# A URL that takes you to the setup/help of the specific protocol
|
||||
setup_url = 'https://github.com/caronc/apprise/wiki/Notify_slack'
|
||||
|
||||
# Slack uses the http protocol with JSON requests
|
||||
notify_url = 'https://hooks.slack.com/services'
|
||||
|
||||
|
|
|
@ -61,10 +61,18 @@ class NotifyStride(NotifyBase):
|
|||
A wrapper to Stride Notifications
|
||||
|
||||
"""
|
||||
# The default descriptive name associated with the Notification
|
||||
service_name = 'Stride'
|
||||
|
||||
# The services URL
|
||||
service_url = 'https://www.stride.com/'
|
||||
|
||||
# The default secure protocol
|
||||
secure_protocol = 'stride'
|
||||
|
||||
# A URL that takes you to the setup/help of the specific protocol
|
||||
setup_url = 'https://github.com/caronc/apprise/wiki/Notify_stride'
|
||||
|
||||
# Stride Webhook
|
||||
notify_url = 'https://api.atlassian.com/site/{cloud_id}/' \
|
||||
'conversation/{convo_id}/message'
|
||||
|
|
|
@ -81,10 +81,18 @@ class NotifyTelegram(NotifyBase):
|
|||
"""
|
||||
A wrapper for Telegram Notifications
|
||||
"""
|
||||
# The default descriptive name associated with the Notification
|
||||
service_name = 'Telegram'
|
||||
|
||||
# The services URL
|
||||
service_url = 'https://telegram.org/'
|
||||
|
||||
# The default secure protocol
|
||||
secure_protocol = 'tgram'
|
||||
|
||||
# A URL that takes you to the setup/help of the specific protocol
|
||||
setup_url = 'https://github.com/caronc/apprise/wiki/Notify_telegram'
|
||||
|
||||
# Telegram uses the http protocol with JSON requests
|
||||
notify_url = 'https://api.telegram.org/bot'
|
||||
|
||||
|
|
|
@ -34,9 +34,18 @@ class NotifyToasty(NotifyBase):
|
|||
A wrapper for Toasty Notifications
|
||||
"""
|
||||
|
||||
# The default descriptive name associated with the Notification
|
||||
service_name = 'Toasty'
|
||||
|
||||
# The services URL
|
||||
service_url = 'http://supertoasty.com/'
|
||||
|
||||
# The default protocol
|
||||
protocol = 'toasty'
|
||||
|
||||
# A URL that takes you to the setup/help of the specific protocol
|
||||
setup_url = 'https://github.com/caronc/apprise/wiki/Notify_toasty'
|
||||
|
||||
# Toasty uses the http protocol with JSON requests
|
||||
notify_url = 'http://api.supertoasty.com/notify/'
|
||||
|
||||
|
|
|
@ -26,9 +26,18 @@ class NotifyTwitter(NotifyBase):
|
|||
|
||||
"""
|
||||
|
||||
# The default descriptive name associated with the Notification
|
||||
service_name = 'Twitter'
|
||||
|
||||
# The services URL
|
||||
service_url = 'https://twitter.com/'
|
||||
|
||||
# The default secure protocol
|
||||
secure_protocol = 'tweet'
|
||||
|
||||
# A URL that takes you to the setup/help of the specific protocol
|
||||
setup_url = 'https://github.com/caronc/apprise/wiki/Notify_twitter'
|
||||
|
||||
# The maximum allowable characters allowed in the body per message
|
||||
# This is used during a Private DM Message Size (not Public Tweets
|
||||
# which are limited to 240 characters)
|
||||
|
|
|
@ -47,9 +47,15 @@ class NotifyWindows(NotifyBase):
|
|||
A wrapper for local Windows Notifications
|
||||
"""
|
||||
|
||||
# The default descriptive name associated with the Notification
|
||||
service_name = 'Windows Notification'
|
||||
|
||||
# The default protocol
|
||||
protocol = 'windows'
|
||||
|
||||
# A URL that takes you to the setup/help of the specific protocol
|
||||
setup_url = 'https://github.com/caronc/apprise/wiki/Notify_windows'
|
||||
|
||||
# Allows the user to specify the NotifyImageSize object
|
||||
image_size = NotifyImageSize.XY_128
|
||||
|
||||
|
|
|
@ -31,12 +31,21 @@ class NotifyXBMC(NotifyBase):
|
|||
A wrapper for XBMC/KODI Notifications
|
||||
"""
|
||||
|
||||
# The default descriptive name associated with the Notification
|
||||
service_name = 'Kodi/XBMC'
|
||||
|
||||
# The services URL
|
||||
service_url = 'http://kodi.tv/'
|
||||
|
||||
# The default protocols
|
||||
protocol = ('xbmc', 'kodi')
|
||||
|
||||
# The default secure protocols
|
||||
secure_protocol = ('xbmc', 'kodis')
|
||||
|
||||
# A URL that takes you to the setup/help of the specific protocol
|
||||
setup_url = 'https://github.com/caronc/apprise/wiki/Notify_kodi'
|
||||
|
||||
# XBMC uses the http protocol with JSON requests
|
||||
xbmc_default_port = 8080
|
||||
|
||||
|
|
|
@ -30,12 +30,18 @@ class NotifyXML(NotifyBase):
|
|||
A wrapper for XML Notifications
|
||||
"""
|
||||
|
||||
# The default descriptive name associated with the Notification
|
||||
service_name = 'XML'
|
||||
|
||||
# The default protocol
|
||||
protocol = 'xml'
|
||||
|
||||
# The default secure protocol
|
||||
secure_protocol = 'xmls'
|
||||
|
||||
# A URL that takes you to the setup/help of the specific protocol
|
||||
setup_url = 'https://github.com/caronc/apprise/wiki/Notify_Custom_XML'
|
||||
|
||||
# Allows the user to specify the NotifyImageSize object
|
||||
image_size = NotifyImageSize.XY_128
|
||||
|
||||
|
|
|
@ -6,6 +6,8 @@ import os
|
|||
import chardet
|
||||
import pysrt
|
||||
|
||||
import types
|
||||
|
||||
from .score import get_equivalent_release_groups
|
||||
from .video import Episode, Movie
|
||||
from .utils import sanitize, sanitize_release_group
|
||||
|
@ -238,8 +240,19 @@ def guess_matches(video, guess, partial=False):
|
|||
if video.resolution and 'screen_size' in guess and guess['screen_size'] == video.resolution:
|
||||
matches.add('resolution')
|
||||
# format
|
||||
if video.format and 'format' in guess and guess['format'].lower() == video.format.lower():
|
||||
matches.add('format')
|
||||
if 'format' in guess and video.format:
|
||||
formats = guess["format"]
|
||||
if not isinstance(formats, types.ListType):
|
||||
formats = [formats]
|
||||
|
||||
video_formats = video.format
|
||||
if not isinstance(video_formats, types.ListType):
|
||||
video_formats = [video_formats]
|
||||
|
||||
lwr = lambda x: "tv" if x in ("HDTV", "SDTV", "TV") else x.lower()
|
||||
|
||||
if set(list(map(lwr, formats))) & set(list(map(lwr, video_formats))):
|
||||
matches.add('format')
|
||||
# video_codec
|
||||
if video.video_codec and 'video_codec' in guess and guess['video_codec'] == video.video_codec:
|
||||
matches.add('video_codec')
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
apprise=0.0.9
|
||||
apprise=0.5.2
|
||||
apscheduler=3.5.1
|
||||
babelfish=0.5.5
|
||||
backports.functools-lru-cache=1.5
|
||||
|
@ -6,12 +6,11 @@ Beaker=1.10.0
|
|||
bottle=0.12.13
|
||||
bottle-fdsend=0.1.1
|
||||
chardet=3.0.4
|
||||
cherrypy=8.9.1 <-- Never update
|
||||
configparser=3.5.0
|
||||
dogpile.cache=0.6.5
|
||||
enzyme=0.4.1
|
||||
gitpython=2.1.9
|
||||
guessit=3.0.0
|
||||
guessit=2.1.4
|
||||
langdetect=1.0.7
|
||||
py-pretty=1
|
||||
pycountry=18.2.23
|
||||
|
|
|
@ -41,6 +41,12 @@
|
|||
.fast.backward, .backward, .forward, .fast.forward { pointer-events: auto; }
|
||||
.fast.backward.disabled, .backward.disabled, .forward.disabled, .fast.forward.disabled { pointer-events: none; }
|
||||
.ui.progress:last-child {margin: 0 0 0em !important;}
|
||||
|
||||
.ui.progress .bar>.progress {
|
||||
right: auto;
|
||||
left: .5em;
|
||||
color: rgba(0, 0, 0, 0.60);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
|
1282
views/wizard.tpl
Normal file
1282
views/wizard.tpl
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue