diff --git a/bazarr/config.py b/bazarr/config.py index 99ee5c33f..a783a92d9 100644 --- a/bazarr/config.py +++ b/bazarr/config.py @@ -35,7 +35,9 @@ defaults = { 'enabled_providers': '', 'throtteled_providers': '', 'multithreading': 'True', - 'chmod': '0640' + 'chmod': '0640', + 'subfolder': 'current', + 'subfolder_custom': '' }, 'auth': { 'type': 'None', diff --git a/bazarr/get_subtitle.py b/bazarr/get_subtitle.py index 040505a9e..e703023ef 100644 --- a/bazarr/get_subtitle.py +++ b/bazarr/get_subtitle.py @@ -1,6 +1,7 @@ # coding=utf-8 import os +import sys import sqlite3 import ast import logging @@ -24,7 +25,7 @@ from get_languages import language_from_alpha3, alpha2_from_alpha3, alpha3_from_ from bs4 import UnicodeDammit from config import settings from helper import path_replace, path_replace_movie, path_replace_reverse, \ - path_replace_reverse_movie, pp_replace + path_replace_reverse_movie, pp_replace, get_target_folder, force_unicode from list_subtitles import store_subtitles, list_missing_subtitles, store_subtitles_movie, list_missing_subtitles_movies from utils import history_log, history_log_movie from notifier import send_notifications, send_notifications_movie @@ -99,25 +100,6 @@ def get_scores(video, media_type, min_score_movie_perc=60 * 100 / 120.0, min_sco return min_score, max_score, set(scores) -def force_unicode(s): - """ - Ensure a string is unicode, not encoded; used for enforcing file paths to be unicode upon saving a subtitle, - to prevent encoding issues when saving a subtitle to a non-ascii path. - :param s: string - :return: unicode string - """ - if not isinstance(s, types.UnicodeType): - try: - s = s.decode("utf-8") - except UnicodeDecodeError: - t = chardet.detect(s) - try: - s = s.decode(t["encoding"]) - except UnicodeDecodeError: - s = UnicodeDammit(s).unicode_markup - return s - - def download_subtitle(path, language, hi, providers, providers_auth, sceneName, title, media_type): # fixme: supply all missing languages, not only one, to hit providers only once who support multiple languages in # one query @@ -183,10 +165,12 @@ def download_subtitle(path, language, hi, providers, providers_auth, sceneName, continue try: + fld = get_target_folder(path) + chmod = int(settings.general.chmod) if sys.platform.startswith('linux') else None saved_subtitles = save_subtitles(video.original_path, subtitles, single=single, tags=None, # fixme - directory=None, # fixme - chmod=int(settings.general.chmod), # fixme + directory=fld, + chmod=chmod, # formats=("srt", "vtt") path_decoder=force_unicode ) diff --git a/bazarr/helper.py b/bazarr/helper.py index ecd29c8fa..654c30d2d 100644 --- a/bazarr/helper.py +++ b/bazarr/helper.py @@ -2,6 +2,7 @@ import ast import os import re +import types from config import settings @@ -63,3 +64,50 @@ def pp_replace(pp_command, episode, subtitles, language, language_code2, languag pp_command = pp_command.replace('{{subtitles_language_code2}}', language_code2) pp_command = pp_command.replace('{{subtitles_language_code3}}', language_code3) return pp_command + + +def get_subtitle_destination_folder(): + fld_custom = str(settings.general.subfolder_custom).strip() if settings.general.subfolder_custom else None + return fld_custom or ( + settings.general.subfolder if settings.general.subfolder != "current" else None) + + +def get_target_folder(file_path): + fld = None + fld_custom = str(settings.general.subfolder_custom).strip() \ + if settings.general.subfolder_custom else None + + if fld_custom or settings.general.subfolder != "current": + # specific subFolder requested, create it if it doesn't exist + fld_base = os.path.split(file_path)[0] + if fld_custom: + if fld_custom.startswith("/"): + # absolute folder + fld = fld_custom + else: + fld = os.path.join(fld_base, fld_custom) + else: + fld = os.path.join(fld_base, settings.general.subfolder) + fld = force_unicode(fld) + if not os.path.exists(fld): + os.makedirs(fld) + return fld + + +def force_unicode(s): + """ + Ensure a string is unicode, not encoded; used for enforcing file paths to be unicode upon saving a subtitle, + to prevent encoding issues when saving a subtitle to a non-ascii path. + :param s: string + :return: unicode string + """ + if not isinstance(s, types.UnicodeType): + try: + s = s.decode("utf-8") + except UnicodeDecodeError: + t = chardet.detect(s) + try: + s = s.decode(t["encoding"]) + except UnicodeDecodeError: + s = UnicodeDammit(s).unicode_markup + return s diff --git a/bazarr/list_subtitles.py b/bazarr/list_subtitles.py index 504daf57e..72b88fc09 100644 --- a/bazarr/list_subtitles.py +++ b/bazarr/list_subtitles.py @@ -19,7 +19,7 @@ from get_args import args from get_languages import alpha2_from_alpha3 from config import settings from helper import path_replace, path_replace_movie, path_replace_reverse, \ - path_replace_reverse_movie + path_replace_reverse_movie, get_subtitle_destination_folder from queueconfig import q4ws @@ -54,8 +54,8 @@ def store_subtitles(file): brazilian_portuguese = [".pt-br", ".pob", "pb"] try: - # fixme: set subliminal_patch.core.CUSTOM_PATHS to a list of absolute folders or subfolders to support - # subtitles outside the media file folder + dest_folder = get_subtitle_destination_folder() + subliminal_patch.core.CUSTOM_PATHS = [dest_folder] if dest_folder else [] subtitles = search_external_subtitles(file) except Exception as e: logging.exception("BAZARR unable to index external subtitles.") @@ -134,9 +134,9 @@ def store_subtitles_movie(file): pass else: logging.debug("BAZARR This file isn't an .mkv file.") - - # fixme: set subliminal_patch.core.CUSTOM_PATHS to a list of absolute folders or subfolders to support - # subtitles outside the media file folder + + dest_folder = get_subtitle_destination_folder() + subliminal_patch.core.CUSTOM_PATHS = [dest_folder] if dest_folder else [] subtitles = search_external_subtitles(file) brazilian_portuguese = [".pt-br", ".pob", "pb"] try: diff --git a/bazarr/main.py b/bazarr/main.py index f7c7870a7..c46179e52 100644 --- a/bazarr/main.py +++ b/bazarr/main.py @@ -46,7 +46,7 @@ from utils import history_log, history_log_movie from scheduler import * from notifier import send_notifications, send_notifications_movie from config import settings, url_sonarr, url_radarr, url_radarr_short, url_sonarr_short, base_url -from helper import path_replace_movie +from helper import path_replace_movie, get_subtitle_destination_folder from subliminal_patch.extensions import provider_registry as provider_manager reload(sys) @@ -268,6 +268,13 @@ def save_wizard(): settings_general_use_radarr = 'False' else: settings_general_use_radarr = 'True' + settings_general_embedded = request.forms.get('settings_general_embedded') + if settings_general_embedded is None: + settings_general_embedded = 'False' + else: + settings_general_embedded = 'True' + settings_subfolder = request.forms.get('settings_subfolder') + settings_subfolder_custom = request.forms.get('settings_subfolder_custom') settings.general.ip = text_type(settings_general_ip) settings.general.port = text_type(settings_general_port) @@ -277,6 +284,9 @@ def save_wizard(): 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.subfolder = text_type(settings_subfolder) + settings.general.subfolder_custom = text_type(settings_subfolder_custom) + settings.general.use_embedded_subs = text_type(settings_general_embedded) settings_sonarr_ip = request.forms.get('settings_sonarr_ip') settings_sonarr_port = request.forms.get('settings_sonarr_port') @@ -1163,6 +1173,8 @@ def save_settings(): else: settings_general_use_radarr = 'True' settings_page_size = request.forms.get('settings_page_size') + settings_subfolder = request.forms.get('settings_subfolder') + settings_subfolder_custom = request.forms.get('settings_subfolder_custom') 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')), @@ -1188,6 +1200,8 @@ def save_settings(): 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.subfolder = text_type(settings_subfolder) + settings.general.subfolder_custom = text_type(settings_subfolder_custom) settings.general.minimum_score_movie = text_type(settings_general_minimum_score_movies) settings.general.use_embedded_subs = text_type(settings_general_embedded) settings.general.adaptive_searching = text_type(settings_general_adaptive_searching) @@ -1601,12 +1615,13 @@ def remove_subtitles(): language = request.forms.get('language') subtitlesPath = request.forms.get('subtitlesPath') sonarrSeriesId = request.forms.get('sonarrSeriesId') - sonarrEpisodeId = request.forms.get('sonarrEpisodeId') + subfolder = ('\\' + get_subtitle_destination_folder() + '\\') if get_subtitle_destination_folder() else '\\' + subtitlesPath = os.path.split(subtitlesPath) try: - os.remove(subtitlesPath) + os.remove(subtitlesPath[0] + subfolder + subtitlesPath[1]) result = language_from_alpha3(language) + " subtitles deleted from disk." - history_log(0, sonarrSeriesId, sonarrEpisodeId, result) + history_log_movie(0, radarrId, result) except OSError: pass store_subtitles(unicode(episodePath)) @@ -1621,9 +1636,11 @@ def remove_subtitles_movie(): language = request.forms.get('language') subtitlesPath = request.forms.get('subtitlesPath') radarrId = request.forms.get('radarrId') - + subfolder = ('\\' + get_subtitle_destination_folder() + '\\') if get_subtitle_destination_folder() else '\\' + subtitlesPath = os.path.split(subtitlesPath) + try: - os.remove(subtitlesPath) + os.remove(subtitlesPath[0] + subfolder + subtitlesPath[1]) result = language_from_alpha3(language) + " subtitles deleted from disk." history_log_movie(0, radarrId, result) except OSError: diff --git a/views/settings.tpl b/views/settings.tpl index 84e025d87..185103dcc 100644 --- a/views/settings.tpl +++ b/views/settings.tpl @@ -152,7 +152,8 @@ - + % import sys + % if sys.platform.startswith('linux'):
@@ -172,6 +173,7 @@
+ %end
@@ -1059,6 +1061,52 @@
+
+
+ +
+
+ +
+ + +
+ +
+
+ +
+
+
+
+ +
+
+
+ + +
+
@@ -2049,6 +2097,8 @@ $('#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_subfolder').dropdown('clear'); + $('#settings_subfolder').dropdown('set selected', '{{!settings.general.subfolder}}'); $('#settings_proxy_type').dropdown('clear'); $('#settings_proxy_type').dropdown('set selected','{{!settings.proxy.type}}'); $('#settings_providers').dropdown('clear'); @@ -2103,6 +2153,8 @@ } ] }, + % if sys.platform.startswith('linux') + : settings_general_chmod: { rules: [ { @@ -2111,6 +2163,8 @@ } ] }, + % + end settings_auth_password : { depends: 'settings_auth_username', rules : [ diff --git a/views/wizard.tpl b/views/wizard.tpl index 132afb3ec..8a4b5c070 100644 --- a/views/wizard.tpl +++ b/views/wizard.tpl @@ -335,6 +335,82 @@ Prev
+ +
Subtitles options
+
+
+ +
+
+ +
+
+ +
+ + +
+ +
+
+ +
+
+
+
+ +
+
+
+ + +
+ +
+
+ +
+
+
+ + +
+
+ +
+ +
+
+
Subtitles providers
@@ -1288,6 +1364,11 @@ $(function() { } else { $("#radarr_ssl_div").checkbox('uncheck'); } + if ($('#settings_embedded').data("embedded") === "True") { + $("#settings_embedded").checkbox('check'); + } else { + $("#settings_embedded").checkbox('uncheck'); + } if ($('#settings_addic7ed_random_agents').data("randomagents") === "True") { $("#settings_addic7ed_random_agents").checkbox('check'); @@ -1448,6 +1529,8 @@ $(function() { $('#settings_providers').dropdown('set selected',{{!enabled_providers}}); $('#settings_languages').dropdown('clear'); $('#settings_languages').dropdown('set selected',{{!enabled_languages}}); + $('#settings_subfolder').dropdown('clear'); + $('#settings_subfolder').dropdown('set selected', '{{!settings.general.subfolder}}'); $('#settings_providers').dropdown(); $('#settings_languages').dropdown();