From 22cd45bc412e87d9b7aae412bc05c2a771d62e3e Mon Sep 17 00:00:00 2001 From: morpheus65535 Date: Mon, 18 Jan 2021 23:49:51 -0500 Subject: [PATCH] Languages profiles (#1232) Implementing the languages profiles functionality. --- bazarr/api.py | 304 +++++++-------- bazarr/app.py | 3 +- bazarr/check_update.py | 1 + bazarr/config.py | 9 +- bazarr/database.py | 177 ++++++++- bazarr/embedded_subs_reader.py | 2 + bazarr/event_handler.py | 2 + bazarr/filesystem.py | 2 + bazarr/get_args.py | 1 + bazarr/get_episodes.py | 11 +- bazarr/get_languages.py | 44 --- bazarr/get_movies.py | 38 +- bazarr/get_series.py | 25 +- bazarr/get_subtitle.py | 380 ++++++++++-------- bazarr/helper.py | 1 + bazarr/init.py | 2 - bazarr/list_subtitles.py | 299 ++++++++------ bazarr/main.py | 11 +- bazarr/scheduler.py | 17 +- bazarr/server.py | 2 + libs/subliminal_patch/core.py | 5 +- views/_main.html | 6 +- views/episodes.html | 123 +++--- views/movie.html | 122 +++--- views/movies.html | 97 ++--- views/movieseditor.html | 70 +--- views/series.html | 105 ++--- views/serieseditor.html | 69 +--- views/settingslanguages.html | 685 +++++++++++++++++++++++++++------ views/settingsradarr.html | 4 +- views/settingssonarr.html | 4 +- views/settingssubtitles.html | 24 +- 32 files changed, 1531 insertions(+), 1114 deletions(-) diff --git a/bazarr/api.py b/bazarr/api.py index 2b4745814..40a510602 100644 --- a/bazarr/api.py +++ b/bazarr/api.py @@ -1,15 +1,12 @@ # coding=utf-8 -import os import ast from datetime import timedelta -import datetime from dateutil import rrule import pretty import time from operator import itemgetter import platform -import io import re import json @@ -18,13 +15,13 @@ from config import settings, base_url, save_settings from init import * import logging -from database import database, get_exclusion_clause +from database import database, get_exclusion_clause, get_profiles_list, get_desired_languages, get_profile_id_name, \ + get_audio_profile_languages, update_profile_id_list from helper import path_mappings -from get_languages import language_from_alpha3, language_from_alpha2, alpha2_from_alpha3, alpha2_from_language, \ - alpha3_from_language, alpha3_from_alpha2 -from get_subtitle import download_subtitle, series_download_subtitles, movies_download_subtitles, \ - manual_search, manual_download_subtitle, manual_upload_subtitle, wanted_search_missing_subtitles_series, \ - wanted_search_missing_subtitles_movies, episode_download_subtitles, movies_download_subtitles +from get_languages import language_from_alpha2, alpha3_from_alpha2 +from get_subtitle import download_subtitle, series_download_subtitles, manual_search, manual_download_subtitle, \ + manual_upload_subtitle, wanted_search_missing_subtitles_series, wanted_search_missing_subtitles_movies, \ + episode_download_subtitles, movies_download_subtitles from notifier import send_notifications, send_notifications_movie from list_subtitles import store_subtitles, store_subtitles_movie, series_scan_subtitles, movies_scan_subtitles, \ list_missing_subtitles, list_missing_subtitles_movies @@ -128,6 +125,12 @@ class Languages(Resource): return jsonify(result) +class LanguagesProfiles(Resource): + @authenticate + def get(self): + return jsonify(data=get_profiles_list()) + + class Notifications(Resource): @authenticate def get(self): @@ -182,6 +185,40 @@ class ResetProviders(Resource): class SaveSettings(Resource): @authenticate def post(self): + languages_profiles = request.form.get('languages_profiles') + if languages_profiles: + existing_ids = database.execute('SELECT profileId FROM table_languages_profiles') + existing = [x['profileId'] for x in existing_ids] + for item in json.loads(languages_profiles): + if item['profileId'] in existing: + # Update existing profiles + database.execute('UPDATE table_languages_profiles SET name = ?, cutoff = ?, items = ? ' + 'WHERE profileId = ?', (item['name'], + item['cutoff'] if item['cutoff'] != '' else None, + item['items'], + item['profileId'])) + existing.remove(item['profileId']) + else: + # Add new profiles + database.execute('INSERT INTO table_languages_profiles (profileId, name, cutoff, items) ' + 'VALUES (?, ?, ?, ?)', (item['profileId'], + item['name'], + item['cutoff'] if item['cutoff'] != '' else None, + item['items'])) + for profileId in existing: + # Unassign this profileId from series and movies + database.execute('UPDATE table_shows SET profileId = null WHERE profileId = ?', (profileId,)) + database.execute('UPDATE table_movies SET profileId = null WHERE profileId = ?', (profileId,)) + # Remove deleted profiles + database.execute('DELETE FROM table_languages_profiles WHERE profileId = ?', (profileId,)) + + update_profile_id_list() + + if settings.general.getboolean('use_sonarr'): + scheduler.add_job(list_missing_subtitles, kwargs={'send_event': False}) + if settings.general.getboolean('use_radarr'): + scheduler.add_job(list_missing_subtitles_movies, kwargs={'send_event': False}) + save_settings(zip(request.form.keys(), request.form.listvalues())) return '', 200 @@ -283,10 +320,6 @@ class Series(Resource): if seriesId: result = database.execute("SELECT * FROM table_shows WHERE sonarrSeriesId=? ORDER BY sortTitle ASC LIMIT ? " "OFFSET ?", (seriesId, length, start)) - desired_languages = database.execute("SELECT languages FROM table_shows WHERE sonarrSeriesId=?", - (seriesId,), only_one=True)['languages'] - if desired_languages == "None": - desired_languages = '[]' else: result = database.execute("SELECT * FROM table_shows ORDER BY sortTitle ASC LIMIT ? OFFSET ?", (length, start)) for item in result: @@ -294,11 +327,10 @@ class Series(Resource): item.update({"DT_RowId": 'row_' + str(item['sonarrSeriesId'])}) # Parse audio language - item.update({"audio_language": {"name": item['audio_language'], - "code2": alpha2_from_language(item['audio_language']) or None, - "code3": alpha3_from_language(item['audio_language']) or None}}) + item.update({"audio_language": get_audio_profile_languages(series_id=item['sonarrSeriesId'])}) # Parse desired languages + item['languages'] = str(get_desired_languages(item['profileId'])) if item['languages'] and item['languages'] != 'None': item.update({"languages": ast.literal_eval(item['languages'])}) for i, subs in enumerate(item['languages']): @@ -306,6 +338,9 @@ class Series(Resource): "code2": subs, "code3": alpha3_from_alpha2(subs)} + # Parse profileId + item['profileId'] = {"id": item['profileId'], "name": get_profile_id_name(item['profileId'])} + # Parse alternate titles if item['alternateTitles']: item.update({"alternateTitles": ast.literal_eval(item['alternateTitles'])}) @@ -343,42 +378,20 @@ class Series(Resource): item.update({"episodeFileCount": episodeFileCount}) # Add the series desired subtitles language code2 - try: - item.update({"desired_languages": desired_languages}) - except NameError: - pass + item.update({"desired_languages": get_desired_languages(item['profileId']['id'])}) + return jsonify(draw=draw, recordsTotal=row_count, recordsFiltered=row_count, data=result) @authenticate def post(self): seriesId = request.args.get('seriesid') - lang = request.form.getlist('languages') - if len(lang) > 0: - pass - else: - lang = 'None' + languages_profile = request.form.get('languages') - single_language = settings.general.getboolean('single_language') - if single_language: - if str(lang) == "['None']": - lang = 'None' - else: - lang = str(lang) - else: - if str(lang) == "['']": - lang = '[]' - - hi = request.form.get('hi') - forced = request.form.get('forced') - - if hi == "on": - hi = "True" - else: - hi = "False" + if languages_profile == 'None': + languages_profile = None - result = database.execute("UPDATE table_shows SET languages=?, hearing_impaired=?, forced=? WHERE " - "sonarrSeriesId=?", (str(lang), hi, forced, seriesId)) + database.execute("UPDATE table_shows SET profileId=? WHERE sonarrSeriesId=?", (languages_profile, seriesId)) list_missing_subtitles(no=seriesId) @@ -392,7 +405,7 @@ class SeriesEditor(Resource): def get(self, **kwargs): draw = request.args.get('draw') - result = database.execute("SELECT sonarrSeriesId, title, languages, hearing_impaired, forced, audio_language " + result = database.execute("SELECT sonarrSeriesId, title, audio_language, profileId " "FROM table_shows ORDER BY sortTitle") row_count = len(result) @@ -402,11 +415,10 @@ class SeriesEditor(Resource): item.update({"DT_RowId": 'row_' + str(item['sonarrSeriesId'])}) # Parse audio language - item.update({"audio_language": {"name": item['audio_language'], - "code2": alpha2_from_language(item['audio_language']) or None, - "code3": alpha3_from_language(item['audio_language']) or None}}) + item.update({"audio_language": get_audio_profile_languages(series_id=item['sonarrSeriesId'])}) # Parse desired languages + item['languages'] = str(get_desired_languages(item['profileId'])) if item['languages'] and item['languages'] != 'None': item.update({"languages": ast.literal_eval(item['languages'])}) for i, subs in enumerate(item['languages']): @@ -414,43 +426,30 @@ class SeriesEditor(Resource): "code2": subs, "code3": alpha3_from_alpha2(subs)} + # Parse profileId + item['profileId'] = {"id": item['profileId'], "name": get_profile_id_name(item['profileId'])} + return jsonify(draw=draw, recordsTotal=row_count, recordsFiltered=row_count, data=result) class SeriesEditSave(Resource): @authenticate def post(self): - lang = request.form.getlist('languages[]') - hi = request.form.getlist('hi[]') - forced = request.form.getlist('forced[]') + lang = request.form.get('languages') - if lang == ['None']: - lang = 'None' + if lang == 'None': + lang = None seriesIdList = [] seriesidLangList = [] - seriesidHiList = [] - seriesidForcedList = [] for item in request.form.getlist('seriesid[]'): seriesid = item.lstrip('row_') seriesIdList.append(seriesid) - if len(lang): - seriesidLangList.append([str(lang), seriesid]) - if len(hi): - seriesidHiList.append([hi[0], seriesid]) - if len(forced): - seriesidForcedList.append([forced[0], seriesid]) + seriesidLangList.append([lang, seriesid]) try: - if len(lang): - database.execute("UPDATE table_shows SET languages=? WHERE sonarrSeriesId=?", seriesidLangList, - execute_many=True) - if len(hi): - database.execute("UPDATE table_shows SET hearing_impaired=? WHERE sonarrSeriesId=?", seriesidHiList, - execute_many=True) - if len(forced): - database.execute("UPDATE table_shows SET forced=? WHERE sonarrSeriesId=?", seriesidForcedList, - execute_many=True) + database.execute("UPDATE table_shows SET profileId=? WHERE sonarrSeriesId=?", seriesidLangList, + execute_many=True) except: pass else: @@ -476,27 +475,22 @@ class Episodes(Resource): (seriesId,), only_one=True)['count'] if episodeId: result = database.execute("SELECT * FROM table_episodes WHERE sonarrEpisodeId=?", (episodeId,)) - desired_languages = database.execute("SELECT languages FROM table_shows WHERE sonarrSeriesId=?", - (seriesId,), only_one=True)['languages'] - if desired_languages == "None": - desired_languages = '[]' elif seriesId: result = database.execute("SELECT * FROM table_episodes WHERE sonarrSeriesId=? ORDER BY season DESC, " "episode DESC", (seriesId,)) - desired_languages = database.execute("SELECT languages FROM table_shows WHERE sonarrSeriesId=?", - (seriesId,), only_one=True)['languages'] - if desired_languages == "None": - desired_languages = '[]' else: return "Series ID not provided", 400 + + profileId = database.execute("SELECT profileId FROM table_shows WHERE sonarrSeriesId = ?", (seriesId,), + only_one=True)['profileId'] + desired_languages = str(get_desired_languages(profileId)) + for item in result: # Add Datatables rowId item.update({"DT_RowId": 'row_' + str(item['sonarrEpisodeId'])}) # Parse audio language - item.update({"audio_language": {"name": item['audio_language'], - "code2": alpha2_from_language(item['audio_language']) or None, - "code3": alpha3_from_language(item['audio_language']) or None}}) + item.update({"audio_language": get_audio_profile_languages(episode_id=item['sonarrEpisodeId'])}) # Parse subtitles if item['subtitles']: @@ -616,8 +610,12 @@ class EpisodesSubtitlesDownload(Resource): title = request.form.get('title') providers_list = get_providers() providers_auth = get_providers_auth() - audio_language = database.execute("SELECT audio_language FROM table_episodes WHERE sonarrEpisodeId=?", - (sonarrEpisodeId,), only_one=True)['audio_language'] + + audio_language_list = get_audio_profile_languages(episode_id=sonarrEpisodeId) + if len(audio_language_list) > 0: + audio_language = audio_language_list[0]['name'] + else: + audio_language = 'None' try: result = download_subtitle(episodePath, language, audio_language, hi, forced, providers_list, providers_auth, sceneName, @@ -659,14 +657,12 @@ class EpisodesSubtitlesManualSearch(Resource): sceneName = request.form.get('sceneName') if sceneName == "null": sceneName = "None" - language = request.form.get('language') - hi = request.form.get('hi').capitalize() - forced = request.form.get('forced').capitalize() + profileId = request.form.get('profileId') title = request.form.get('title') providers_list = get_providers() providers_auth = get_providers_auth() - data = manual_search(episodePath, language, hi, forced, providers_list, providers_auth, sceneName, title, + data = manual_search(episodePath, profileId, providers_list, providers_auth, sceneName, title, 'series') if not data: data = [] @@ -690,8 +686,12 @@ class EpisodesSubtitlesManualDownload(Resource): sonarrEpisodeId = request.form.get('sonarrEpisodeId') title = request.form.get('title') providers_auth = get_providers_auth() - audio_language = database.execute("SELECT audio_language FROM table_episodes WHERE sonarrEpisodeId=?", - (sonarrEpisodeId,), only_one=True)['audio_language'] + + audio_language_list = get_audio_profile_languages(episode_id=sonarrEpisodeId) + if len(audio_language_list) > 0: + audio_language = audio_language_list[0]['name'] + else: + audio_language = 'None' try: result = manual_download_subtitle(episodePath, language, audio_language, hi, forced, subtitle, @@ -887,10 +887,6 @@ class Movies(Resource): if moviesId: result = database.execute("SELECT * FROM table_movies WHERE radarrId=? ORDER BY sortTitle ASC LIMIT ? " "OFFSET ?", (moviesId, length, start)) - desired_languages = database.execute("SELECT languages FROM table_movies WHERE radarrId=?", - (moviesId,), only_one=True)['languages'] - if desired_languages == "None": - desired_languages = '[]' else: result = database.execute("SELECT * FROM table_movies ORDER BY sortTitle ASC LIMIT ? OFFSET ?", (length, start)) @@ -899,11 +895,10 @@ class Movies(Resource): item.update({"DT_RowId": 'row_' + str(item['radarrId'])}) # Parse audio language - item.update({"audio_language": {"name": item['audio_language'], - "code2": alpha2_from_language(item['audio_language']) or None, - "code3": alpha3_from_language(item['audio_language']) or None}}) + item.update({"audio_language": get_audio_profile_languages(movie_id=item['radarrId'])}) # Parse desired languages + item['languages'] = str(get_desired_languages(item['profileId'])) if item['languages'] and item['languages'] != 'None': item.update({"languages": ast.literal_eval(item['languages'])}) for i, subs in enumerate(item['languages']): @@ -911,6 +906,9 @@ class Movies(Resource): "code2": subs, "code3": alpha3_from_alpha2(subs)} + # Parse profileId + item['profileId'] = {"id": item['profileId'], "name": get_profile_id_name(item['profileId'])} + # Parse alternate titles if item['alternativeTitles']: item.update({"alternativeTitles": ast.literal_eval(item['alternativeTitles'])}) @@ -975,42 +973,20 @@ class Movies(Resource): item.update({"exist": os.path.isfile(mapped_path)}) # Add the movie desired subtitles language code2 - try: - item.update({"desired_languages": desired_languages}) - except NameError: - pass + item.update({"desired_languages": get_desired_languages(item['profileId']['id'])}) + return jsonify(draw=draw, recordsTotal=row_count, recordsFiltered=row_count, data=result) @authenticate def post(self): radarrId = request.args.get('radarrid') - lang = request.form.getlist('languages') - if len(lang) > 0: - pass - else: - lang = 'None' - - single_language = settings.general.getboolean('single_language') - if single_language: - if str(lang) == "['None']": - lang = 'None' - else: - lang = str(lang) - else: - if str(lang) == "['']": - lang = '[]' - - hi = request.form.get('hi') - forced = request.form.get('forced') + languages_profile = request.form.get('languages') - if hi == "on": - hi = "True" - else: - hi = "False" + if languages_profile == 'None': + languages_profile = None - result = database.execute("UPDATE table_movies SET languages=?, hearing_impaired=?, forced=? WHERE " - "radarrId=?", (str(lang), hi, forced, radarrId)) + database.execute("UPDATE table_movies SET profileId=? WHERE radarrId=?", (languages_profile, radarrId)) list_missing_subtitles_movies(no=radarrId) @@ -1024,7 +1000,7 @@ class MoviesEditor(Resource): def get(self): draw = request.args.get('draw') - result = database.execute("SELECT radarrId, title, languages, hearing_impaired, forced, audio_language " + result = database.execute("SELECT radarrId, title, audio_language, profileId " "FROM table_movies ORDER BY sortTitle") row_count = len(result) @@ -1034,11 +1010,10 @@ class MoviesEditor(Resource): item.update({"DT_RowId": 'row_' + str(item['radarrId'])}) # Parse audio language - item.update({"audio_language": {"name": item['audio_language'], - "code2": alpha2_from_language(item['audio_language']) or None, - "code3": alpha3_from_language(item['audio_language']) or None}}) + item.update({"audio_language": get_audio_profile_languages(movie_id=item['radarrId'])}) # Parse desired languages + item['languages'] = str(get_desired_languages(item['profileId'])) if item['languages'] and item['languages'] != 'None': item.update({"languages": ast.literal_eval(item['languages'])}) for i, subs in enumerate(item['languages']): @@ -1046,42 +1021,29 @@ class MoviesEditor(Resource): "code2": subs, "code3": alpha3_from_alpha2(subs)} + # Parse profileId + item['profileId'] = {"id": item['profileId'], "name": get_profile_id_name(item['profileId'])} + return jsonify(draw=draw, recordsTotal=row_count, recordsFiltered=row_count, data=result) class MoviesEditSave(Resource): @authenticate def post(self): - lang = request.form.getlist('languages[]') - hi = request.form.getlist('hi[]') - forced = request.form.getlist('forced[]') + lang = request.form.get('languages') - if lang == ['None']: - lang = 'None' + if lang == 'None': + lang = None radarrIdList = [] radarrIdLangList = [] - radarrIdHiList = [] - radarrIdForcedList = [] for item in request.form.getlist('radarrid[]'): radarrid = item.lstrip('row_') radarrIdList.append(radarrid) - if len(lang): - radarrIdLangList.append([str(lang), radarrid]) - if len(hi): - radarrIdHiList.append([hi[0], radarrid]) - if len(forced): - radarrIdForcedList.append([forced[0], radarrid]) + radarrIdLangList.append([lang, radarrid]) try: - if len(lang): - database.execute("UPDATE table_movies SET languages=? WHERE radarrId=?", radarrIdLangList, - execute_many=True) - if len(hi): - database.execute("UPDATE table_movies SET hearing_impaired=? WHERE radarrId=?", radarrIdHiList, - execute_many=True) - if len(forced): - database.execute("UPDATE table_movies SET forced=? WHERE radarrId=?", radarrIdForcedList, - execute_many=True) + database.execute("UPDATE table_movies SET profileId=? WHERE radarrId=?", radarrIdLangList, + execute_many=True) except: pass else: @@ -1131,8 +1093,12 @@ class MovieSubtitlesDownload(Resource): title = request.form.get('title') providers_list = get_providers() providers_auth = get_providers_auth() - audio_language = database.execute("SELECT audio_language FROM table_movies WHERE radarrId=?", (radarrId,), - only_one=True)['audio_language'] + + audio_language_list = get_audio_profile_languages(movie_id=radarrId) + if len(audio_language_list) > 0: + audio_language = audio_language_list[0]['name'] + else: + audio_language = 'None' try: result = download_subtitle(moviePath, language, audio_language, hi, forced, providers_list, @@ -1174,14 +1140,12 @@ class MovieSubtitlesManualSearch(Resource): sceneName = request.form.get('sceneName') if sceneName == "null": sceneName = "None" - language = request.form.get('language') - hi = request.form.get('hi').capitalize() - forced = request.form.get('forced').capitalize() + profileId = request.form.get('profileId') title = request.form.get('title') providers_list = get_providers() providers_auth = get_providers_auth() - data = manual_search(moviePath, language, hi, forced, providers_list, providers_auth, sceneName, title, + data = manual_search(moviePath, profileId, providers_list, providers_auth, sceneName, title, 'movie') if not data: data = [] @@ -1204,8 +1168,12 @@ class MovieSubtitlesManualDownload(Resource): radarrId = request.form.get('radarrId') title = request.form.get('title') providers_auth = get_providers_auth() - audio_language = database.execute("SELECT audio_language FROM table_movies WHERE radarrId=?", (radarrId,), - only_one=True)['audio_language'] + + audio_language_list = get_audio_profile_languages(movie_id=radarrId) + if len(audio_language_list) > 0: + audio_language = audio_language_list[0]['name'] + else: + audio_language = 'None' try: result = manual_download_subtitle(moviePath, language, audio_language, hi, forced, subtitle, @@ -1412,8 +1380,7 @@ class HistorySeries(Resource): "table_episodes.sonarrEpisodeId = table_history.sonarrEpisodeId INNER JOIN table_shows on " "table_shows.sonarrSeriesId = table_episodes.sonarrSeriesId WHERE action IN (" + ','.join(map(str, query_actions)) + ") AND timestamp > ? AND score is not null" + - get_exclusion_clause('series') + " GROUP BY table_history.video_path, table_history.language", - (minimum_timestamp,)) + get_exclusion_clause('series') + " GROUP BY table_history.video_path", (minimum_timestamp,)) for upgradable_episode in upgradable_episodes: if upgradable_episode['timestamp'] > minimum_timestamp: @@ -1433,16 +1400,16 @@ class HistorySeries(Resource): "table_episodes.title as episodeTitle, table_history.timestamp, table_history.subs_id, " "table_history.description, table_history.sonarrSeriesId, table_episodes.path, " "table_history.language, table_history.score, table_shows.tags, table_history.action, " - "table_history.subtitles_path, table_history.sonarrEpisodeId, table_history.provider " - "FROM table_history LEFT JOIN table_shows on table_shows.sonarrSeriesId = " - "table_history.sonarrSeriesId LEFT JOIN table_episodes on " + "table_history.subtitles_path, table_history.sonarrEpisodeId, table_history.provider, " + "table_shows.seriesType FROM table_history LEFT JOIN table_shows on " + "table_shows.sonarrSeriesId = table_history.sonarrSeriesId LEFT JOIN table_episodes on " "table_episodes.sonarrEpisodeId = table_history.sonarrEpisodeId WHERE " "table_episodes.title is not NULL ORDER BY timestamp DESC LIMIT ? OFFSET ?", (length, start)) for item in data: # Mark episode as upgradable or not - if {"video_path": str(item['path']), "timestamp": float(item['timestamp']), "score": str(item['score']), "tags": str(item['tags']), "monitored": str(item['monitored'])} in upgradable_episodes_not_perfect: + if {"video_path": str(item['path']), "timestamp": float(item['timestamp']), "score": str(item['score']), "tags": str(item['tags']), "monitored": str(item['monitored']), "seriesType": str(item['seriesType'])} in upgradable_episodes_not_perfect: item.update({"upgradable": True}) else: item.update({"upgradable": False}) @@ -1516,8 +1483,8 @@ class HistoryMovies(Resource): upgradable_movies = database.execute( "SELECT video_path, MAX(timestamp) as timestamp, score, tags, monitored FROM table_history_movie " "INNER JOIN table_movies on table_movies.radarrId=table_history_movie.radarrId WHERE action IN (" + - ','.join(map(str, query_actions)) + ") AND timestamp > ? AND score is not NULL" + - get_exclusion_clause('movie') + " GROUP BY video_path, language", (minimum_timestamp,)) + ','.join(map(str, query_actions)) + ") AND timestamp > ? AND score is not NULL" + + get_exclusion_clause('movie') + " GROUP BY video_path", (minimum_timestamp,)) for upgradable_movie in upgradable_movies: if upgradable_movie['timestamp'] > minimum_timestamp: @@ -1661,7 +1628,7 @@ class WantedSeries(Resource): data = database.execute("SELECT table_shows.title as seriesTitle, table_episodes.monitored, " "table_episodes.season || 'x' || table_episodes.episode as episode_number, " "table_episodes.title as episodeTitle, table_episodes.missing_subtitles, " - "table_episodes.sonarrSeriesId, table_episodes.path, table_shows.hearing_impaired, " + "table_episodes.sonarrSeriesId, table_episodes.path, " "table_episodes.sonarrEpisodeId, table_episodes.scene_name, table_shows.tags, " "table_episodes.failedAttempts, table_shows.seriesType FROM table_episodes INNER JOIN " "table_shows on table_shows.sonarrSeriesId = table_episodes.sonarrSeriesId WHERE " @@ -1707,7 +1674,7 @@ class WantedMovies(Resource): data_count = database.execute("SELECT tags, monitored FROM table_movies WHERE missing_subtitles != '[]'" + get_exclusion_clause('movie')) row_count = len(data_count) - data = database.execute("SELECT title, missing_subtitles, radarrId, path, hearing_impaired, sceneName, " + data = database.execute("SELECT title, missing_subtitles, radarrId, path, sceneName, " "failedAttempts, tags, monitored FROM table_movies WHERE missing_subtitles != '[]'" + get_exclusion_clause('movie') + " ORDER BY _rowid_ DESC LIMIT " + length + " OFFSET " + start) @@ -2002,6 +1969,7 @@ api.add_resource(BadgesSeries, '/badges_series') api.add_resource(BadgesMovies, '/badges_movies') api.add_resource(BadgesProviders, '/badges_providers') api.add_resource(Languages, '/languages') +api.add_resource(LanguagesProfiles, '/languages_profiles') api.add_resource(Notifications, '/notifications') api.add_resource(Search, '/search_json') diff --git a/bazarr/app.py b/bazarr/app.py index 62ed9c8a6..cb5f5bc93 100644 --- a/bazarr/app.py +++ b/bazarr/app.py @@ -1,4 +1,5 @@ -#!/bin/env python +# coding=utf-8 + from flask import Flask, redirect, render_template, request, url_for from flask_debugtoolbar import DebugToolbarExtension from flask_socketio import SocketIO diff --git a/bazarr/check_update.py b/bazarr/check_update.py index 63695b88d..5cc39b765 100644 --- a/bazarr/check_update.py +++ b/bazarr/check_update.py @@ -1,4 +1,5 @@ # coding=utf-8 + import os import logging import json diff --git a/bazarr/config.py b/bazarr/config.py index b49dfd8b7..f62cbd9be 100644 --- a/bazarr/config.py +++ b/bazarr/config.py @@ -1,4 +1,5 @@ # coding=utf-8 + import hashlib import os @@ -30,13 +31,9 @@ defaults = { 'use_radarr': 'False', 'path_mappings_movie': '[]', 'serie_default_enabled': 'False', - 'serie_default_language': '[]', - 'serie_default_hi': 'False', - 'serie_default_forced': 'False', + 'serie_default_profile': '', 'movie_default_enabled': 'False', - 'movie_default_language': '[]', - 'movie_default_hi': 'False', - 'movie_default_forced': 'False', + 'movie_default_profile': '', 'page_size': '25', 'page_size_manual_search': '10', 'minimum_score_movie': '70', diff --git a/bazarr/database.py b/bazarr/database.py index b17ddccc6..06f43e0bb 100644 --- a/bazarr/database.py +++ b/bazarr/database.py @@ -1,7 +1,10 @@ +# coding=utf-8 + import os import ast import sqlite3 import logging +import json from sqlite3worker import Sqlite3Worker @@ -9,6 +12,9 @@ from get_args import args from helper import path_mappings from config import settings +global profile_id_list +profile_id_list = [] + def db_init(): if not os.path.exists(os.path.join(args.config_dir, 'db', 'bazarr.db')): @@ -95,6 +101,7 @@ def db_upgrade(): ['table_shows', 'tags', 'text', '[]'], ['table_shows', 'seriesType', 'text', ''], ['table_shows', 'imdbId', 'text', ''], + ['table_shows', 'profileId', 'integer'], ['table_episodes', 'format', 'text'], ['table_episodes', 'resolution', 'text'], ['table_episodes', 'video_codec', 'text'], @@ -112,6 +119,7 @@ def db_upgrade(): ['table_movies', 'forced', 'text', 'False'], ['table_movies', 'movie_file_id', 'integer'], ['table_movies', 'tags', 'text', '[]'], + ['table_movies', 'profileId', 'integer'], ['table_history', 'video_path', 'text'], ['table_history', 'language', 'text'], ['table_history', 'provider', 'text'], @@ -143,20 +151,61 @@ def db_upgrade(): except: pass - # Fix null languages, hearing-impaired and forced for series and movies. - database.execute("UPDATE table_shows SET languages = '[]' WHERE languages is null") - database.execute("UPDATE table_shows SET hearing_impaired = 'False' WHERE hearing_impaired is null") - database.execute("UPDATE table_shows SET forced = 'False' WHERE forced is null") - database.execute("UPDATE table_movies SET languages = '[]' WHERE languages is null") - database.execute("UPDATE table_movies SET hearing_impaired = 'False' WHERE hearing_impaired is null") - database.execute("UPDATE table_movies SET forced = 'False' WHERE forced is null") - # Create blacklist tables database.execute("CREATE TABLE IF NOT EXISTS table_blacklist (sonarr_series_id integer, sonarr_episode_id integer, " "timestamp integer, provider text, subs_id text, language text)") database.execute("CREATE TABLE IF NOT EXISTS table_blacklist_movie (radarr_id integer, timestamp integer, " "provider text, subs_id text, language text)") + # Create languages profiles table and populate it + lang_table_content = database.execute("SELECT * FROM table_languages_profiles") + if isinstance(lang_table_content, list): + lang_table_exist = True + else: + lang_table_exist = False + database.execute("CREATE TABLE IF NOT EXISTS table_languages_profiles (" + "profileId INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL, " + "cutoff INTEGER, items TEXT NOT NULL)") + + if not lang_table_exist: + profiles_to_create = database.execute("SELECT DISTINCT languages, hearing_impaired, forced " + "FROM (SELECT languages, hearing_impaired, forced FROM table_shows " + "UNION ALL SELECT languages, hearing_impaired, forced FROM table_movies) " + "a WHERE languages NOT null and languages NOT IN ('None', '[]')") + for profile in profiles_to_create: + profile_items = [] + languages_list = ast.literal_eval(profile['languages']) + for i, language in enumerate(languages_list, 1): + if profile['forced'] == 'Both': + profile_items.append({'id': i, 'language': language, 'forced': 'True', + 'hi': profile['hearing_impaired'], 'audio_exclude': 'False'}) + profile_items.append({'id': i, 'language': language, 'forced': 'False', + 'hi': profile['hearing_impaired'], 'audio_exclude': 'False'}) + else: + profile_items.append({'id': i, 'language': language, 'forced': profile['forced'], + 'hi': profile['hearing_impaired'], 'audio_exclude': 'False'}) + # Create profiles + new_profile_name = profile['languages'] + ' (' + profile['hearing_impaired'] + '/' + profile['forced'] + ')' + database.execute("INSERT INTO table_languages_profiles (name, cutoff, items) VALUES(" + "?,null,?)", (new_profile_name, json.dumps(profile_items),)) + created_profile_id = database.execute("SELECT profileId FROM table_languages_profiles WHERE name = ?", + (new_profile_name,), only_one=True)['profileId'] + # Assign profiles to series and movies + database.execute("UPDATE table_shows SET profileId = ? WHERE languages = ? AND hearing_impaired = ? AND " + "forced = ?", (created_profile_id, profile['languages'], profile['hearing_impaired'], + profile['forced'])) + database.execute("UPDATE table_movies SET profileId = ? WHERE languages = ? AND hearing_impaired = ? AND " + "forced = ?", (created_profile_id, profile['languages'], profile['hearing_impaired'], + profile['forced'])) + + # null languages, forced and hearing_impaired for all series and movies + database.execute("UPDATE table_shows SET languages = null, forced = null, hearing_impaired = null") + database.execute("UPDATE table_movies SET languages = null, forced = null, hearing_impaired = null") + + # Force series, episodes and movies sync with Sonarr to get all the audio track from video files + # Set environment variable that is going to be use during the init process to run sync once Bazarr is ready. + os.environ['BAZARR_AUDIO_PROFILES_MIGRATION'] = '1' + def get_exclusion_clause(type): where_clause = '' @@ -184,3 +233,115 @@ def get_exclusion_clause(type): where_clause += ' AND table_shows.seriesType != "' + type + '"' return where_clause + + +def update_profile_id_list(): + global profile_id_list + profile_id_list = database.execute("SELECT profileId, name, cutoff, items FROM table_languages_profiles") + + +def get_profiles_list(profile_id=None): + if not len(profile_id_list): + update_profile_id_list() + + if profile_id: + for profile in profile_id_list: + if profile['profileId'] == profile_id: + return profile + else: + return profile_id_list + + +def get_desired_languages(profile_id): + languages = [] + + if not len(profile_id_list): + update_profile_id_list() + + if profile_id: + for profile in profile_id_list: + profileId, name, cutoff, items = profile.values() + if profileId == int(profile_id): + items_list = ast.literal_eval(items) + languages = [x['language'] for x in items_list] + break + + return languages + + +def get_profile_id_name(profile_id): + name_from_id = None + + if not len(profile_id_list): + update_profile_id_list() + + if profile_id: + for profile in profile_id_list: + profileId, name, cutoff, items = profile.values() + if profileId == int(profile_id): + name_from_id = name + break + + return name_from_id + + +def get_profile_cutoff(profile_id): + cutoff_language = None + + if not len(profile_id_list): + update_profile_id_list() + + if profile_id: + cutoff_language = [] + for profile in profile_id_list: + profileId, name, cutoff, items = profile.values() + if cutoff: + if profileId == int(profile_id): + for item in ast.literal_eval(items): + if item['id'] == cutoff: + return [item] + elif cutoff == 65535: + cutoff_language.append(item) + + if not len(cutoff_language): + cutoff_language = None + + return cutoff_language + + +def get_audio_profile_languages(series_id=None, episode_id=None, movie_id=None): + from get_languages import alpha2_from_language, alpha3_from_language + audio_languages = [] + + if series_id: + audio_languages_list_str = database.execute("SELECT audio_language FROM table_shows WHERE sonarrSeriesId=?", + (series_id,), only_one=True)['audio_language'] + audio_languages_list = ast.literal_eval(audio_languages_list_str) + for language in audio_languages_list: + audio_languages.append( + {"name": language, + "code2": alpha2_from_language(language) or None, + "code3": alpha3_from_language(language) or None} + ) + elif episode_id: + audio_languages_list_str = database.execute("SELECT audio_language FROM table_episodes WHERE sonarrEpisodeId=?", + (episode_id,), only_one=True)['audio_language'] + audio_languages_list = ast.literal_eval(audio_languages_list_str) + for language in audio_languages_list: + audio_languages.append( + {"name": language, + "code2": alpha2_from_language(language) or None, + "code3": alpha3_from_language(language) or None} + ) + elif movie_id: + audio_languages_list_str = database.execute("SELECT audio_language FROM table_movies WHERE radarrId=?", + (movie_id,), only_one=True)['audio_language'] + audio_languages_list = ast.literal_eval(audio_languages_list_str) + for language in audio_languages_list: + audio_languages.append( + {"name": language, + "code2": alpha2_from_language(language) or None, + "code3": alpha3_from_language(language) or None} + ) + + return audio_languages diff --git a/bazarr/embedded_subs_reader.py b/bazarr/embedded_subs_reader.py index 5c42922f1..8eb0f0fe5 100644 --- a/bazarr/embedded_subs_reader.py +++ b/bazarr/embedded_subs_reader.py @@ -1,3 +1,5 @@ +# coding=utf-8 + import enzyme from enzyme.exceptions import MalformedMKVError import logging diff --git a/bazarr/event_handler.py b/bazarr/event_handler.py index a66d9cdfb..e824ea492 100644 --- a/bazarr/event_handler.py +++ b/bazarr/event_handler.py @@ -1,3 +1,5 @@ +# coding=utf-8 + import json from app import socketio diff --git a/bazarr/filesystem.py b/bazarr/filesystem.py index f6d94c6ae..09b04a2cd 100644 --- a/bazarr/filesystem.py +++ b/bazarr/filesystem.py @@ -1,3 +1,5 @@ +# coding=utf-8 + import os import requests import logging diff --git a/bazarr/get_args.py b/bazarr/get_args.py index 498762c32..57b258d5b 100644 --- a/bazarr/get_args.py +++ b/bazarr/get_args.py @@ -1,4 +1,5 @@ # coding=utf-8 + import os import argparse diff --git a/bazarr/get_episodes.py b/bazarr/get_episodes.py index 2e355beab..2e32e897e 100644 --- a/bazarr/get_episodes.py +++ b/bazarr/get_episodes.py @@ -1,11 +1,12 @@ # coding=utf-8 + import requests import logging from database import database, dict_converter, get_exclusion_clause from config import settings, url_sonarr from helper import path_mappings -from list_subtitles import list_missing_subtitles, store_subtitles, series_full_scan_subtitles +from list_subtitles import store_subtitles, series_full_scan_subtitles from get_subtitle import episode_download_subtitles from event_handler import event_stream @@ -85,12 +86,12 @@ def sync_episodes(): videoCodec = None audioCodec = None - audio_language = None + audio_language = [] if 'language' in episode['episodeFile'] and len(episode['episodeFile']['language']): item = episode['episodeFile']['language'] if isinstance(item, dict): if 'name' in item: - audio_language = item['name'] + audio_language.append(item['name']) else: audio_language = database.execute("SELECT audio_language FROM table_shows WHERE " "sonarrSeriesId=?", (episode['seriesId'],), @@ -113,7 +114,7 @@ def sync_episodes(): 'video_codec': videoCodec, 'audio_codec': audioCodec, 'episode_file_id': episode['episodeFile']['id'], - 'audio_language': audio_language}) + 'audio_language': str(audio_language)}) else: episodes_to_add.append({'sonarrSeriesId': episode['seriesId'], 'sonarrEpisodeId': episode['id'], @@ -128,7 +129,7 @@ def sync_episodes(): 'video_codec': videoCodec, 'audio_codec': audioCodec, 'episode_file_id': episode['episodeFile']['id'], - 'audio_language': audio_language}) + 'audio_language': str(audio_language)}) # Remove old episodes from DB removed_episodes = list(set(current_episodes_db_list) - set(current_episodes_sonarr)) diff --git a/bazarr/get_languages.py b/bazarr/get_languages.py index f418a8bd5..9d96c4620 100644 --- a/bazarr/get_languages.py +++ b/bazarr/get_languages.py @@ -1,7 +1,6 @@ # coding=utf-8 import pycountry -import ast from subzero.language import Language from database import database @@ -76,48 +75,5 @@ def get_language_set(): return language_set -def clean_desired_languages(): - from list_subtitles import list_missing_subtitles, list_missing_subtitles_movies - enabled_languages = [] - enabled_languages_temp = database.execute("SELECT code2 FROM table_settings_languages WHERE enabled=1") - for language in enabled_languages_temp: - enabled_languages.append(language['code2']) - - series_languages = database.execute("SELECT sonarrSeriesId, languages FROM table_shows") - movies_languages = database.execute("SELECT radarrId, languages FROM table_movies") - - for item in series_languages: - if item['languages'] != 'None': - try: - languages_list = ast.literal_eval(item['languages']) - except: - pass - else: - cleaned_languages_list = [] - for language in languages_list: - if language in enabled_languages: - cleaned_languages_list.append(language) - if cleaned_languages_list != languages_list: - database.execute("UPDATE table_shows SET languages=? WHERE sonarrSeriesId=?", - (str(cleaned_languages_list), item['sonarrSeriesId'])) - list_missing_subtitles(no=item['sonarrSeriesId']) - - for item in movies_languages: - if item['languages'] != 'None': - try: - languages_list = ast.literal_eval(item['languages']) - except: - pass - else: - cleaned_languages_list = [] - for language in languages_list: - if language in enabled_languages: - cleaned_languages_list.append(language) - if cleaned_languages_list != languages_list: - database.execute("UPDATE table_movies SET languages=? WHERE radarrId=?", - (str(cleaned_languages_list), item['radarrId'])) - list_missing_subtitles_movies(no=item['radarrId']) - - if __name__ == '__main__': load_language_in_db() diff --git a/bazarr/get_movies.py b/bazarr/get_movies.py index 38b25bf16..eecd7ef62 100644 --- a/bazarr/get_movies.py +++ b/bazarr/get_movies.py @@ -7,7 +7,7 @@ import logging from config import settings, url_radarr from helper import path_mappings from utils import get_radarr_version -from list_subtitles import store_subtitles_movie, list_missing_subtitles_movies, movies_full_scan_subtitles +from list_subtitles import store_subtitles_movie, movies_full_scan_subtitles from get_subtitle import movies_download_subtitles from database import database, dict_converter, get_exclusion_clause @@ -26,13 +26,11 @@ def update_movies(): movie_default_enabled = settings.general.getboolean('movie_default_enabled') if movie_default_enabled is True: - movie_default_language = settings.general.movie_default_language - movie_default_hi = settings.general.movie_default_hi - movie_default_forced = settings.general.movie_default_forced + movie_default_profile = settings.general.movie_default_profile + if movie_default_profile == '': + movie_default_profile = None else: - movie_default_language = '[]' - movie_default_hi = 'False' - movie_default_forced = 'False' + movie_default_profile = None if apikey_radarr is None: pass @@ -146,13 +144,14 @@ def update_movies(): videoCodec = None audioCodec = None - audio_language = None + audio_language = [] if radarr_version.startswith('0'): if 'mediaInfo' in movie['movieFile']: if 'audioLanguages' in movie['movieFile']['mediaInfo']: - audio_language_list = movie['movieFile']['mediaInfo']['audioLanguages'].split('/') - if len(audio_language_list): - audio_language = audio_language_list[0].strip() + audio_languages_list = movie['movieFile']['mediaInfo']['audioLanguages'].split('/') + if len(audio_languages_list): + for audio_language_list in audio_languages_list: + audio_language.append(audio_language_list.strip()) if not audio_language: audio_language = profile_id_to_language(movie['qualityProfileId'], audio_profiles) else: @@ -160,8 +159,7 @@ def update_movies(): for item in movie['movieFile']['languages']: if isinstance(item, dict): if 'name' in item: - audio_language = item['name'] - break + audio_language.append(item['name']) tags = [d['label'] for d in tagsDict if d['id'] in movie['tags']] @@ -175,7 +173,7 @@ def update_movies(): 'tmdbId': str(movie["tmdbId"]), 'poster': poster, 'fanart': fanart, - 'audio_language': audio_language, + 'audio_language': str(audio_language), 'sceneName': sceneName, 'monitored': str(bool(movie['monitored'])), 'year': str(movie['year']), @@ -194,13 +192,11 @@ def update_movies(): 'title': movie["title"], 'path': movie["path"] + separator + movie['movieFile']['relativePath'], 'tmdbId': str(movie["tmdbId"]), - 'languages': movie_default_language, 'subtitles': '[]', - 'hearing_impaired': movie_default_hi, 'overview': overview, 'poster': poster, 'fanart': fanart, - 'audio_language': audio_language, + 'audio_language': str(audio_language), 'sceneName': sceneName, 'monitored': str(bool(movie['monitored'])), 'sortTitle': movie['sortTitle'], @@ -211,9 +207,9 @@ def update_movies(): 'video_codec': videoCodec, 'audio_codec': audioCodec, 'imdbId': imdbId, - 'forced': movie_default_forced, 'movie_file_id': int(movie['movieFile']['id']), - 'tags': str(tags)}) + 'tags': str(tags), + 'profileId': movie_default_profile}) else: logging.error( 'BAZARR Radarr returned a movie without a file path: ' + movie["path"] + separator + @@ -315,8 +311,10 @@ def get_profile_list(): def profile_id_to_language(id, profiles): for profile in profiles: + profiles_to_return = [] if id == profile[0]: - return profile[1] + profiles_to_return.append(profile[1]) + return profiles_to_return def RadarrFormatAudioCodec(audioFormat, audioCodecID, audioProfile, audioAdditionalFeatures): diff --git a/bazarr/get_series.py b/bazarr/get_series.py index 64c7987e2..fcdee9ddf 100644 --- a/bazarr/get_series.py +++ b/bazarr/get_series.py @@ -22,13 +22,11 @@ def update_series(): serie_default_enabled = settings.general.getboolean('serie_default_enabled') if serie_default_enabled is True: - serie_default_language = settings.general.serie_default_language - serie_default_hi = settings.general.serie_default_hi - serie_default_forced = settings.general.serie_default_forced + serie_default_profile = settings.general.serie_default_profile + if serie_default_profile == '': + serie_default_profile = None else: - serie_default_language = '[]' - serie_default_hi = 'False' - serie_default_forced = 'False' + serie_default_profile = None audio_profiles = get_profile_list() tagsDict = get_tags() @@ -76,6 +74,7 @@ def update_series(): if show['alternateTitles'] is not None: alternate_titles = str([item['title'] for item in show['alternateTitles']]) + audio_language = [] if sonarr_version.startswith('2'): audio_language = profile_id_to_language(show['qualityProfileId'], audio_profiles) else: @@ -96,7 +95,7 @@ def update_series(): 'overview': overview, 'poster': poster, 'fanart': fanart, - 'audio_language': audio_language, + 'audio_language': str(audio_language), 'sortTitle': show['sortTitle'], 'year': str(show['year']), 'alternateTitles': alternate_titles, @@ -107,20 +106,18 @@ def update_series(): series_to_add.append({'title': show["title"], 'path': show["path"], 'tvdbId': show["tvdbId"], - 'languages': serie_default_language, - 'hearing_impaired': serie_default_hi, 'sonarrSeriesId': show["id"], 'overview': overview, 'poster': poster, 'fanart': fanart, - 'audio_language': audio_language, + 'audio_language': str(audio_language), 'sortTitle': show['sortTitle'], 'year': str(show['year']), 'alternateTitles': alternate_titles, - 'forced': serie_default_forced, 'tags': str(tags), 'seriesType': show['seriesType'], - 'imdbId': imdbId}) + 'imdbId': imdbId, + 'profileId': serie_default_profile}) # Remove old series from DB removed_series = list(set(current_shows_db_list) - set(current_shows_sonarr)) @@ -197,9 +194,11 @@ def get_profile_list(): def profile_id_to_language(id_, profiles): + profiles_to_return = [] for profile in profiles: if id_ == profile[0]: - return profile[1] + profiles_to_return.append(profile[1]) + return profiles_to_return def get_tags(): diff --git a/bazarr/get_subtitle.py b/bazarr/get_subtitle.py index cc08183cb..e9b502270 100644 --- a/bazarr/get_subtitle.py +++ b/bazarr/get_subtitle.py @@ -30,7 +30,8 @@ from get_providers import get_providers, get_providers_auth, provider_throttle, from knowit import api from subsyncer import subsync from guessit import guessit -from database import database, dict_mapper, get_exclusion_clause +from database import database, dict_mapper, get_exclusion_clause, get_profiles_list, get_audio_profile_languages, \ + get_desired_languages from analytics import track_event from locale import getpreferredencoding @@ -304,44 +305,48 @@ def download_subtitle(path, language, audio_language, hi, forced, providers, pro logging.debug('BAZARR Ended searching Subtitles for file: ' + path) -def manual_search(path, language, hi, forced, providers, providers_auth, sceneName, title, media_type): +def manual_search(path, profileId, providers, providers_auth, sceneName, title, media_type): logging.debug('BAZARR Manually searching subtitles for this file: ' + path) final_subtitles = [] - initial_hi = True if hi == "True" else False - if hi == "True": - hi = "force HI" - else: - hi = "force non-HI" + initial_language_set = set() language_set = set() - if forced == "True": - providers_auth['podnapisi']['only_foreign'] = True - providers_auth['subscene']['only_foreign'] = True - providers_auth['opensubtitles']['only_foreign'] = True - else: - providers_auth['podnapisi']['only_foreign'] = False - providers_auth['subscene']['only_foreign'] = False - providers_auth['opensubtitles']['only_foreign'] = False + # where [3] is items list of dict(id, lang, forced, hi) + language_items = ast.literal_eval(get_profiles_list(profile_id=int(profileId))['items']) + + for language in language_items: + lang_id, lang, forced, hi, audio_exclude = language.values() - for lang in ast.literal_eval(language): lang = alpha3_from_alpha2(lang) if lang == 'pob': lang_obj = Language('por', 'BR') - if forced == "True": - lang_obj = Language.rebuild(lang_obj, forced=True) else: lang_obj = Language(lang) - if forced == "True": - lang_obj = Language.rebuild(lang_obj, forced=True) - language_set.add(lang_obj) + if forced == "True": + lang_obj = Language.rebuild(lang_obj, forced=True) - if forced != "True": - lang_obj_hi = Language.rebuild(lang_obj, hi=True) - language_set.add(lang_obj_hi) + providers_auth['podnapisi']['also_foreign'] = True + providers_auth['opensubtitles']['also_foreign'] = True + + if hi == "True": + lang_obj = Language.rebuild(lang_obj, hi=True) + + initial_language_set.add(lang_obj) + + language_set = initial_language_set.copy() + for language in language_set.copy(): + lang_obj_for_hi = language + if not language.forced and not language.hi: + lang_obj_hi = Language.rebuild(lang_obj_for_hi, hi=True) + elif not language.forced and language.hi: + lang_obj_hi = Language.rebuild(lang_obj_for_hi, hi=False) + else: + continue + language_set.add(lang_obj_hi) minimum_score = settings.general.minimum_score minimum_score_movie = settings.general.minimum_score_movie @@ -365,6 +370,22 @@ def manual_search(path, language, hi, forced, providers, providers_auth, sceneNa blacklist=get_blacklist(media_type=media_type), throttle_callback=provider_throttle, language_hook=None) # fixme + + if 'subscene' in providers: + subscene_language_set = set() + for language in language_set: + if language.forced: + subscene_language_set.add(language) + if len(subscene_language_set): + providers_auth['subscene']['only_foreign'] = True + subtitles_subscene = list_all_subtitles([video], subscene_language_set, + providers=['subscene'], + provider_configs=providers_auth, + blacklist=get_blacklist(media_type=media_type), + throttle_callback=provider_throttle, + language_hook=None) # fixme + providers_auth['subscene']['only_foreign'] = False + subtitles[video] += subtitles_subscene[video] else: subtitles = [] logging.info("BAZARR All providers are throttled") @@ -390,6 +411,20 @@ def manual_search(path, language, hi, forced, providers, providers_auth, sceneNa logging.debug(u"BAZARR Skipping %s, because it doesn't match our series/episode", s) continue + initial_hi_match = False + for language in initial_language_set: + if s.language.basename == language.basename and \ + s.language.forced == language.forced and \ + s.language.hi == language.hi: + initial_hi = language.hi + initial_hi_match = True + break + if not initial_hi_match: + initial_hi = None + + if initial_hi_match: + matches.add('hearing_impaired') + score, score_without_hash = compute_score(matches, s, video, hearing_impaired=initial_hi) if 'hash' not in matches: not_matched = scores - matches @@ -680,21 +715,14 @@ def manual_upload_subtitle(path, language, forced, title, scene_name, media_type def series_download_subtitles(no): episodes_details = database.execute("SELECT table_episodes.path, table_episodes.missing_subtitles, monitored, " "table_episodes.sonarrEpisodeId, table_episodes.scene_name, table_shows.tags, " - "table_shows.seriesType, table_episodes.audio_language FROM table_episodes " - "INNER JOIN table_shows on table_shows.sonarrSeriesId = " + "table_shows.seriesType, table_episodes.audio_language, table_shows.title " + "FROM table_episodes INNER JOIN table_shows on table_shows.sonarrSeriesId = " "table_episodes.sonarrSeriesId WHERE table_episodes.sonarrSeriesId=? and " "missing_subtitles!='[]'" + get_exclusion_clause('series'), (no,)) if not episodes_details: logging.debug("BAZARR no episode for that sonarrSeriesId can be found in database:", str(no)) return - series_details = database.execute( - "SELECT hearing_impaired, title, forced FROM table_shows WHERE sonarrSeriesId=?", - (no,), only_one=True) - if not series_details: - logging.debug("BAZARR no series with that sonarrSeriesId can be found in database:", str(no)) - return - providers_list = get_providers() providers_auth = get_providers_auth() @@ -704,15 +732,21 @@ def series_download_subtitles(no): if providers_list: for language in ast.literal_eval(episode['missing_subtitles']): if language is not None: + audio_language_list = get_audio_profile_languages(episode_id=episode['sonarrEpisodeId']) + if len(audio_language_list) > 0: + audio_language = audio_language_list[0]['name'] + else: + audio_language = 'None' + result = download_subtitle(path_mappings.path_replace(episode['path']), str(alpha3_from_alpha2(language.split(':')[0])), - episode['audio_language'], - series_details['hearing_impaired'], + audio_language, + "True" if language.endswith(':hi') else "False", "True" if language.endswith(':forced') else "False", providers_list, providers_auth, str(episode['scene_name']), - series_details['title'], + episode['title'], 'series') if result is not None: message = result[0] @@ -740,10 +774,9 @@ def series_download_subtitles(no): def episode_download_subtitles(no): episodes_details = database.execute("SELECT table_episodes.path, table_episodes.missing_subtitles, monitored, " "table_episodes.sonarrEpisodeId, table_episodes.scene_name, table_shows.tags, " - "table_shows.hearing_impaired, table_shows.title, table_shows.sonarrSeriesId, " - "table_shows.forced, table_episodes.audio_language, table_shows.seriesType FROM " - "table_episodes LEFT JOIN table_shows on table_episodes.sonarrSeriesId = " - "table_shows.sonarrSeriesId WHERE sonarrEpisodeId=?" + + "table_shows.title, table_shows.sonarrSeriesId, table_episodes.audio_language, " + "table_shows.seriesType FROM table_episodes LEFT JOIN table_shows on " + "table_episodes.sonarrSeriesId = table_shows.sonarrSeriesId WHERE sonarrEpisodeId=?" + get_exclusion_clause('series'), (no,)) if not episodes_details: logging.debug("BAZARR no episode with that sonarrEpisodeId can be found in database:", str(no)) @@ -756,10 +789,16 @@ def episode_download_subtitles(no): if providers_list: for language in ast.literal_eval(episode['missing_subtitles']): if language is not None: + audio_language_list = get_audio_profile_languages(episode_id=episode['sonarrEpisodeId']) + if len(audio_language_list) > 0: + audio_language = audio_language_list[0]['name'] + else: + audio_language = 'None' + result = download_subtitle(path_mappings.path_replace(episode['path']), str(alpha3_from_alpha2(language.split(':')[0])), - episode['audio_language'], - episode['hearing_impaired'], + audio_language, + "True" if language.endswith(':hi') else "False", "True" if language.endswith(':forced') else "False", providers_list, providers_auth, @@ -791,7 +830,7 @@ def episode_download_subtitles(no): def movies_download_subtitles(no): movies = database.execute( - "SELECT path, missing_subtitles, audio_language, radarrId, sceneName, hearing_impaired, title, forced, tags, " + "SELECT path, missing_subtitles, audio_language, radarrId, sceneName, title, tags, " "monitored FROM table_movies WHERE radarrId=?" + get_exclusion_clause('movie'), (no,)) if not len(movies): logging.debug("BAZARR no movie with that radarrId can be found in database:", str(no)) @@ -810,10 +849,16 @@ def movies_download_subtitles(no): for i, language in enumerate(ast.literal_eval(movie['missing_subtitles']), 1): if providers_list: if language is not None: + audio_language_list = get_audio_profile_languages(movie_id=movie['radarrId']) + if len(audio_language_list) > 0: + audio_language = audio_language_list[0]['name'] + else: + audio_language = 'None' + result = download_subtitle(path_mappings.path_replace_movie(movie['path']), str(alpha3_from_alpha2(language.split(':')[0])), - movie['audio_language'], - movie['hearing_impaired'], + audio_language, + "True" if language.endswith(':hi') else "False", "True" if language.endswith(':forced') else "False", providers_list, providers_auth, @@ -845,8 +890,8 @@ def movies_download_subtitles(no): def wanted_download_subtitles(path, l, count_episodes): episodes_details = database.execute("SELECT table_episodes.path, table_episodes.missing_subtitles, " "table_episodes.sonarrEpisodeId, table_episodes.sonarrSeriesId, " - "table_shows.hearing_impaired, table_episodes.audio_language, table_episodes.scene_name," - "table_episodes.failedAttempts, table_shows.title, table_shows.forced " + "table_episodes.audio_language, table_episodes.scene_name," + "table_episodes.failedAttempts, table_shows.title " "FROM table_episodes LEFT JOIN table_shows on " "table_episodes.sonarrSeriesId = table_shows.sonarrSeriesId " "WHERE table_episodes.path=? and table_episodes.missing_subtitles!='[]'", @@ -874,10 +919,16 @@ def wanted_download_subtitles(path, l, count_episodes): for i in range(len(attempt)): if attempt[i][0] == language: if search_active(attempt[i][1]): + audio_language_list = get_audio_profile_languages(episode_id=episode['sonarrEpisodeId']) + if len(audio_language_list) > 0: + audio_language = audio_language_list[0]['name'] + else: + audio_language = 'None' + result = download_subtitle(path_mappings.path_replace(episode['path']), str(alpha3_from_alpha2(language.split(':')[0])), - episode['audio_language'], - episode['hearing_impaired'], + audio_language, + "True" if language.endswith(':hi') else "False", "True" if language.endswith(':forced') else "False", providers_list, providers_auth, @@ -910,8 +961,8 @@ def wanted_download_subtitles(path, l, count_episodes): def wanted_download_subtitles_movie(path, l, count_movies): movies_details = database.execute( - "SELECT path, missing_subtitles, radarrId, hearing_impaired, audio_language, sceneName, " - "failedAttempts, title, forced FROM table_movies WHERE path = ? " + "SELECT path, missing_subtitles, radarrId, audio_language, sceneName, " + "failedAttempts, title FROM table_movies WHERE path = ? " "AND missing_subtitles != '[]'", (path_mappings.path_replace_reverse_movie(path),)) providers_list = get_providers() @@ -936,10 +987,16 @@ def wanted_download_subtitles_movie(path, l, count_movies): for i in range(len(attempt)): if attempt[i][0] == language: if search_active(attempt[i][1]) is True: + audio_language_list = get_audio_profile_languages(movie_id=movie['radarrId']) + if len(audio_language_list) > 0: + audio_language = audio_language_list[0]['name'] + else: + audio_language = 'None' + result = download_subtitle(path_mappings.path_replace_movie(movie['path']), str(alpha3_from_alpha2(language.split(':')[0])), - movie['audio_language'], - movie['hearing_impaired'], + audio_language, + "True" if language.endswith(':hi') else "False", "True" if language.endswith(':forced') else "False", providers_list, providers_auth, @@ -1144,17 +1201,17 @@ def upgrade_subtitles(): if settings.general.getboolean('use_sonarr'): upgradable_episodes = database.execute("SELECT table_history.video_path, table_history.language, " - "table_history.score, table_shows.hearing_impaired, " - "table_episodes.audio_language, table_episodes.scene_name, table_episodes.title," - "table_episodes.sonarrSeriesId, table_episodes.sonarrEpisodeId," - "MAX(table_history.timestamp) as timestamp, table_episodes.monitored, " - "table_shows.languages, table_shows.forced, table_shows.tags, " - "table_shows.seriesType FROM table_history INNER JOIN table_shows on " - "table_shows.sonarrSeriesId = table_history.sonarrSeriesId INNER JOIN " - "table_episodes on table_episodes.sonarrEpisodeId = " - "table_history.sonarrEpisodeId WHERE action IN " - "(" + ','.join(map(str, query_actions)) + ") AND timestamp > ? AND score" - " is not null" + get_exclusion_clause('series') + " GROUP BY " + "table_history.score, table_shows.tags, table_shows.profileId, " + "table_episodes.audio_language, table_episodes.scene_name, " + "table_episodes.title, table_episodes.sonarrSeriesId, " + "table_episodes.sonarrEpisodeId, MAX(table_history.timestamp) " + "as timestamp, table_episodes.monitored, table_shows.seriesType FROM " + "table_history INNER JOIN table_shows on table_shows.sonarrSeriesId = " + "table_history.sonarrSeriesId INNER JOIN table_episodes on " + "table_episodes.sonarrEpisodeId = table_history.sonarrEpisodeId WHERE " + "action IN (" + ','.join(map(str, query_actions)) + + ") AND timestamp > ? AND score is not null" + + get_exclusion_clause('series') + " GROUP BY " "table_history.video_path, table_history.language", (minimum_timestamp,)) upgradable_episodes_not_perfect = [] @@ -1177,13 +1234,13 @@ def upgrade_subtitles(): if settings.general.getboolean('use_radarr'): upgradable_movies = database.execute("SELECT table_history_movie.video_path, table_history_movie.language, " - "table_history_movie.score, table_movies.hearing_impaired, " + "table_history_movie.score, table_movies.profileId, " "table_movies.audio_language, table_movies.sceneName, table_movies.title, " "table_movies.radarrId, MAX(table_history_movie.timestamp) as timestamp, " - "table_movies.languages, table_movies.forced, table_movies.tags, " - "table_movies.monitored FROM table_history_movie INNER JOIN table_movies " - "on table_movies.radarrId = table_history_movie.radarrId WHERE action IN " - "(" + ','.join(map(str, query_actions)) + ") AND timestamp > ? AND score " + "table_movies.tags, table_movies.monitored FROM table_history_movie INNER " + "JOIN table_movies on table_movies.radarrId = " + "table_history_movie.radarrId WHERE action IN (" + + ','.join(map(str, query_actions)) + ") AND timestamp > ? AND score " "is not null" + get_exclusion_clause('movie') + " GROUP BY " "table_history_movie.video_path, table_history_movie.language", (minimum_timestamp,)) @@ -1210,110 +1267,113 @@ def upgrade_subtitles(): if settings.general.getboolean('use_sonarr'): for i, episode in enumerate(episodes_to_upgrade, 1): - if episode['languages'] in [None, 'None', '[]']: - continue providers = get_providers() if not providers: logging.info("BAZARR All providers are throttled") return - if episode['languages']: - desired_languages = ast.literal_eval(str(episode['languages'])) - if episode['forced'] == "True": - forced_languages = [l + ":forced" for l in desired_languages] - elif episode['forced'] == "Both": - forced_languages = [l + ":forced" for l in desired_languages] + desired_languages - else: - forced_languages = desired_languages + if episode['language'].endswith('forced'): + language = episode['language'].split(':')[0] + is_forced = True + is_hi = False + elif episode['language'].endswith('hi'): + language = episode['language'].split(':')[0] + is_forced = False + is_hi = True + else: + language = episode['language'].split(':')[0] + is_forced = False + is_hi = False - if episode['language'] in forced_languages: - if episode['language'].endswith('forced'): - language = episode['language'].split(':')[0] - is_forced = "True" - else: - language = episode['language'] - is_forced = "False" - - result = download_subtitle(path_mappings.path_replace(episode['video_path']), - str(alpha3_from_alpha2(language)), - episode['audio_language'], - episode['hearing_impaired'], - is_forced, - providers_list, - providers_auth, - str(episode['scene_name']), - episode['title'], - 'series', - forced_minimum_score=int(episode['score']), - is_upgrade=True) - if result is not None: - message = result[0] - path = result[1] - forced = result[5] - if result[8]: - language_code = result[2] + ":hi" - elif forced: - language_code = result[2] + ":forced" - else: - language_code = result[2] - provider = result[3] - score = result[4] - subs_id = result[6] - subs_path = result[7] - store_subtitles(episode['video_path'], path_mappings.path_replace(episode['video_path'])) - history_log(3, episode['sonarrSeriesId'], episode['sonarrEpisodeId'], message, path, - language_code, provider, score, subs_id, subs_path) - send_notifications(episode['sonarrSeriesId'], episode['sonarrEpisodeId'], message) + audio_language_list = get_audio_profile_languages(episode_id=episode['sonarrEpisodeId']) + if len(audio_language_list) > 0: + audio_language = audio_language_list[0]['name'] + else: + audio_language = 'None' + + result = download_subtitle(path_mappings.path_replace(episode['video_path']), + str(alpha3_from_alpha2(language)), + audio_language, + is_hi, + is_forced, + providers_list, + providers_auth, + str(episode['scene_name']), + episode['title'], + 'series', + forced_minimum_score=int(episode['score']), + is_upgrade=True) + if result is not None: + message = result[0] + path = result[1] + forced = result[5] + if result[8]: + language_code = result[2] + ":hi" + elif forced: + language_code = result[2] + ":forced" + else: + language_code = result[2] + provider = result[3] + score = result[4] + subs_id = result[6] + subs_path = result[7] + store_subtitles(episode['video_path'], path_mappings.path_replace(episode['video_path'])) + history_log(3, episode['sonarrSeriesId'], episode['sonarrEpisodeId'], message, path, + language_code, provider, score, subs_id, subs_path) + send_notifications(episode['sonarrSeriesId'], episode['sonarrEpisodeId'], message) if settings.general.getboolean('use_radarr'): for i, movie in enumerate(movies_to_upgrade, 1): - if movie['languages'] in [None, 'None', '[]']: - continue providers = get_providers() if not providers: logging.info("BAZARR All providers are throttled") return - if movie['languages']: - desired_languages = ast.literal_eval(str(movie['languages'])) - if movie['forced'] == "True": - forced_languages = [l + ":forced" for l in desired_languages] - elif movie['forced'] == "Both": - forced_languages = [l + ":forced" for l in desired_languages] + desired_languages - else: - forced_languages = desired_languages + if not providers: + logging.info("BAZARR All providers are throttled") + return + if episode['language'].endswith('forced'): + language = episode['language'].split(':')[0] + is_forced = True + is_hi = False + elif episode['language'].endswith('hi'): + language = episode['language'].split(':')[0] + is_forced = False + is_hi = True + else: + language = episode['language'].split(':')[0] + is_forced = False + is_hi = False - if movie['language'] in forced_languages: - if movie['language'].endswith('forced'): - language = movie['language'].split(':')[0] - is_forced = "True" - else: - language = movie['language'] - is_forced = "False" - - result = download_subtitle(path_mappings.path_replace_movie(movie['video_path']), - str(alpha3_from_alpha2(language)), - movie['audio_language'], - movie['hearing_impaired'], - is_forced, - providers_list, - providers_auth, - str(movie['sceneName']), - movie['title'], - 'movie', - forced_minimum_score=int(movie['score']), - is_upgrade=True) - if result is not None: - message = result[0] - path = result[1] - forced = result[5] - language_code = result[2] + ":forced" if forced else result[2] - provider = result[3] - score = result[4] - subs_id = result[6] - subs_path = result[7] - store_subtitles_movie(movie['video_path'], - path_mappings.path_replace_movie(movie['video_path'])) - history_log_movie(3, movie['radarrId'], message, path, language_code, provider, score, subs_id, subs_path) - send_notifications_movie(movie['radarrId'], message) + audio_language_list = get_audio_profile_languages(movie_id=movie['radarrId']) + if len(audio_language_list) > 0: + audio_language = audio_language_list[0]['name'] + else: + audio_language = 'None' + + result = download_subtitle(path_mappings.path_replace_movie(movie['video_path']), + str(alpha3_from_alpha2(language)), + audio_language, + is_hi, + is_forced, + providers_list, + providers_auth, + str(movie['sceneName']), + movie['title'], + 'movie', + forced_minimum_score=int(movie['score']), + is_upgrade=True) + if result is not None: + message = result[0] + path = result[1] + forced = result[5] + language_code = result[2] + ":forced" if forced else result[2] + provider = result[3] + score = result[4] + subs_id = result[6] + subs_path = result[7] + store_subtitles_movie(movie['video_path'], + path_mappings.path_replace_movie(movie['video_path'])) + history_log_movie(3, movie['radarrId'], message, path, language_code, provider, score, subs_id, subs_path) + send_notifications_movie(movie['radarrId'], message) def postprocessing(command, path): diff --git a/bazarr/helper.py b/bazarr/helper.py index 73ad6f869..339f73cfa 100644 --- a/bazarr/helper.py +++ b/bazarr/helper.py @@ -1,4 +1,5 @@ # coding=utf-8 + import ast import os import re diff --git a/bazarr/init.py b/bazarr/init.py index 442804e66..07a3affe0 100644 --- a/bazarr/init.py +++ b/bazarr/init.py @@ -3,8 +3,6 @@ import os import io import rarfile -import json -import hashlib import sys import subprocess diff --git a/bazarr/list_subtitles.py b/bazarr/list_subtitles.py index 6d0d3a4c8..bb997ad22 100644 --- a/bazarr/list_subtitles.py +++ b/bazarr/list_subtitles.py @@ -9,8 +9,8 @@ from guess_language import guess_language from subliminal_patch import core, search_external_subtitles from subzero.language import Language -from database import database -from get_languages import alpha2_from_alpha3, get_language_set +from database import database, get_profiles_list, get_profile_cutoff +from get_languages import alpha2_from_alpha3, language_from_alpha2, get_language_set from config import settings from helper import path_mappings, get_subtitle_destination_folder @@ -203,157 +203,212 @@ def store_subtitles_movie(original_path, reversed_path): def list_missing_subtitles(no=None, epno=None, send_event=True): - if no is not None: - episodes_subtitles_clause = " WHERE table_episodes.sonarrSeriesId=" + str(no) - elif epno is not None: + if epno is not None: episodes_subtitles_clause = " WHERE table_episodes.sonarrEpisodeId=" + str(epno) + elif no is not None: + episodes_subtitles_clause = " WHERE table_episodes.sonarrSeriesId=" + str(no) else: episodes_subtitles_clause = "" episodes_subtitles = database.execute("SELECT table_shows.sonarrSeriesId, table_episodes.sonarrEpisodeId, " - "table_episodes.subtitles, table_shows.languages, table_shows.forced, " - "table_shows.hearing_impaired FROM table_episodes LEFT JOIN table_shows " - "on table_episodes.sonarrSeriesId = table_shows.sonarrSeriesId" + - episodes_subtitles_clause) + "table_episodes.subtitles, table_shows.profileId, " + "table_episodes.audio_language FROM table_episodes " + "LEFT JOIN table_shows on table_episodes.sonarrSeriesId = " + "table_shows.sonarrSeriesId" + episodes_subtitles_clause) if isinstance(episodes_subtitles, str): logging.error("BAZARR list missing subtitles query to DB returned this instead of rows: " + episodes_subtitles) return - missing_subtitles_global = [] use_embedded_subs = settings.general.getboolean('use_embedded_subs') + for episode_subtitles in episodes_subtitles: - actual_subtitles_temp = [] - desired_subtitles_temp = [] - actual_subtitles = [] - desired_subtitles = [] - missing_subtitles = [] - if episode_subtitles['subtitles'] is not None: - if use_embedded_subs: - actual_subtitles = ast.literal_eval(episode_subtitles['subtitles']) - else: - actual_subtitles_temp = ast.literal_eval(episode_subtitles['subtitles']) - for subtitle in actual_subtitles_temp: - if subtitle[1] is not None: - actual_subtitles.append(subtitle) - if episode_subtitles['languages'] is not None: - desired_subtitles = ast.literal_eval(episode_subtitles['languages']) - if desired_subtitles: - desired_subtitles_enum = enumerate(desired_subtitles) - else: - desired_subtitles_enum = None - - if episode_subtitles['hearing_impaired'] == "True" and desired_subtitles is not None: - for i, desired_subtitle in desired_subtitles_enum: - desired_subtitles[i] = desired_subtitle + ":hi" - elif episode_subtitles['forced'] == "True" and desired_subtitles is not None: - for i, desired_subtitle in desired_subtitles_enum: - desired_subtitles[i] = desired_subtitle + ":forced" - elif episode_subtitles['forced'] == "Both" and desired_subtitles is not None: - for desired_subtitle in desired_subtitles: - desired_subtitles_temp.append(desired_subtitle) - desired_subtitles_temp.append(desired_subtitle + ":forced") - desired_subtitles = desired_subtitles_temp - actual_subtitles_list = [] - if desired_subtitles is None: - missing_subtitles_global.append(tuple(['[]', episode_subtitles['sonarrEpisodeId'], - episode_subtitles['sonarrSeriesId']])) - else: - for item in actual_subtitles: - if item[0] == "pt-BR": - actual_subtitles_list.append("pb") - elif item[0] == "pt-BR:forced": - actual_subtitles_list.append("pb:forced") + missing_subtitles_text = '[]' + if episode_subtitles['profileId']: + # get desired subtitles + desired_subtitles_temp = get_profiles_list(profile_id=episode_subtitles['profileId']) + desired_subtitles_list = [] + if desired_subtitles_temp: + for language in ast.literal_eval(desired_subtitles_temp['items']): + if language['audio_exclude'] == "True": + if language_from_alpha2(language['language']) in ast.literal_eval(episode_subtitles['audio_language']): + continue + desired_subtitles_list.append([language['language'], language['forced'], language['hi']]) + + # get existing subtitles + actual_subtitles_list = [] + if episode_subtitles['subtitles'] is not None: + if use_embedded_subs: + actual_subtitles_temp = ast.literal_eval(episode_subtitles['subtitles']) else: - actual_subtitles_list.append(item[0]) - missing_subtitles = list(set(desired_subtitles) - set(actual_subtitles_list)) - hi_subs_to_remove = [] - for item in missing_subtitles: - if item + ':hi' in actual_subtitles_list: - hi_subs_to_remove.append(item) - missing_subtitles = list(set(missing_subtitles) - set(hi_subs_to_remove)) - missing_subtitles_global.append(tuple([str(missing_subtitles), episode_subtitles['sonarrEpisodeId'], - episode_subtitles['sonarrSeriesId']])) - - for missing_subtitles_item in missing_subtitles_global: + actual_subtitles_temp = [x for x in ast.literal_eval(episode_subtitles['subtitles']) if x[1]] + + for subtitles in actual_subtitles_temp: + subtitles = subtitles[0].split(':') + lang = subtitles[0] + forced = False + hi = False + if len(subtitles) > 1: + if subtitles[1] == 'forced': + forced = True + hi = False + elif subtitles[1] == 'hi': + forced = False + hi = True + actual_subtitles_list.append([lang, str(forced), str(hi)]) + + # check if cutoff is reached and skip any further check + cutoff_met = False + cutoff_temp_list = get_profile_cutoff(profile_id=episode_subtitles['profileId']) + + if cutoff_temp_list: + for cutoff_temp in cutoff_temp_list: + cutoff_language = [cutoff_temp['language'], cutoff_temp['forced'], cutoff_temp['hi']] + if cutoff_language in actual_subtitles_list: + cutoff_met = True + missing_subtitles_text = str([]) + elif cutoff_language and [cutoff_language[0], 'True', 'False'] in actual_subtitles_list: + cutoff_met = True + missing_subtitles_text = str([]) + elif cutoff_language and [cutoff_language[0], 'False', 'True'] in actual_subtitles_list: + cutoff_met = True + missing_subtitles_text = str([]) + + if not cutoff_met: + # if cutoff isn't met or None, we continue + + # get difference between desired and existing subtitles + missing_subtitles_list = [] + for item in desired_subtitles_list: + if item not in actual_subtitles_list: + missing_subtitles_list.append(item) + + # remove missing that have forced or hi subtitles for this language in existing + for item in actual_subtitles_list: + if item[1] == 'True' or item[2] == 'True': + try: + missing_subtitles_list.remove([item[0], 'False', 'False']) + except ValueError: + pass + + # make the missing languages list looks like expected + missing_subtitles_output_list = [] + for item in missing_subtitles_list: + lang = item[0] + if item[1] == 'True': + lang += ':forced' + elif item[2] == 'True': + lang += ':hi' + missing_subtitles_output_list.append(lang) + + missing_subtitles_text = str(missing_subtitles_output_list) + database.execute("UPDATE table_episodes SET missing_subtitles=? WHERE sonarrEpisodeId=?", - (missing_subtitles_item[0], missing_subtitles_item[1])) + (missing_subtitles_text, episode_subtitles['sonarrEpisodeId'])) if send_event: - event_stream(type='episode', action='update', series=missing_subtitles_item[2], - episode=missing_subtitles_item[1]) + event_stream(type='episode', action='update', series=episode_subtitles['sonarrSeriesId'], + episode=episode_subtitles['sonarrEpisodeId']) event_stream(type='badges_series') -def list_missing_subtitles_movies(no=None, send_event=True): +def list_missing_subtitles_movies(no=None, epno=None, send_event=True): if no is not None: movies_subtitles_clause = " WHERE radarrId=" + str(no) else: movies_subtitles_clause = "" - movies_subtitles = database.execute("SELECT radarrId, subtitles, languages, forced, hearing_impaired FROM " - "table_movies" + movies_subtitles_clause) + movies_subtitles = database.execute("SELECT radarrId, subtitles, profileId, audio_language FROM table_movies" + + movies_subtitles_clause) if isinstance(movies_subtitles, str): logging.error("BAZARR list missing subtitles query to DB returned this instead of rows: " + movies_subtitles) return - - missing_subtitles_global = [] + + use_embedded_subs = settings.general.getboolean('use_embedded_subs') + for movie_subtitles in movies_subtitles: - actual_subtitles_temp = [] - desired_subtitles_temp = [] - actual_subtitles = [] - desired_subtitles = [] - missing_subtitles = [] - if movie_subtitles['subtitles'] is not None: - if use_embedded_subs: - actual_subtitles = ast.literal_eval(movie_subtitles['subtitles']) - else: - actual_subtitles_temp = ast.literal_eval(movie_subtitles['subtitles']) - for subtitle in actual_subtitles_temp: - if subtitle[1] is not None: - actual_subtitles.append(subtitle) - if movie_subtitles['languages'] is not None: - desired_subtitles = ast.literal_eval(movie_subtitles['languages']) - if desired_subtitles: - desired_subtitles_enum = enumerate(desired_subtitles) - else: - desired_subtitles_enum = None - - if movie_subtitles['hearing_impaired'] == "True" and desired_subtitles is not None: - for i, desired_subtitle in desired_subtitles_enum: - desired_subtitles[i] = desired_subtitle + ":hi" - elif movie_subtitles['forced'] == "True" and desired_subtitles is not None: - for i, desired_subtitle in desired_subtitles_enum: - desired_subtitles[i] = desired_subtitle + ":forced" - elif movie_subtitles['forced'] == "Both" and desired_subtitles is not None: - for desired_subtitle in desired_subtitles: - desired_subtitles_temp.append(desired_subtitle) - desired_subtitles_temp.append(desired_subtitle + ":forced") - desired_subtitles = desired_subtitles_temp - actual_subtitles_list = [] - if desired_subtitles is None: - missing_subtitles_global.append(tuple(['[]', movie_subtitles['radarrId']])) - else: - for item in actual_subtitles: - if item[0] == "pt-BR": - actual_subtitles_list.append("pb") - elif item[0] == "pt-BR:forced": - actual_subtitles_list.append("pb:forced") + missing_subtitles_text = '[]' + if movie_subtitles['profileId']: + # get desired subtitles + desired_subtitles_temp = get_profiles_list(profile_id=movie_subtitles['profileId']) + desired_subtitles_list = [] + if desired_subtitles_temp: + for language in ast.literal_eval(desired_subtitles_temp['items']): + if language['audio_exclude'] == "True": + if language_from_alpha2(language['language']) in ast.literal_eval(movie_subtitles['audio_language']): + continue + desired_subtitles_list.append([language['language'], language['forced'], language['hi']]) + + # get existing subtitles + actual_subtitles_list = [] + if movie_subtitles['subtitles'] is not None: + if use_embedded_subs: + actual_subtitles_temp = ast.literal_eval(movie_subtitles['subtitles']) else: - actual_subtitles_list.append(item[0]) - missing_subtitles = list(set(desired_subtitles) - set(actual_subtitles_list)) - hi_subs_to_remove = [] - for item in missing_subtitles: - if item + ':hi' in actual_subtitles_list: - hi_subs_to_remove.append(item) - missing_subtitles = list(set(missing_subtitles) - set(hi_subs_to_remove)) - missing_subtitles_global.append(tuple([str(missing_subtitles), movie_subtitles['radarrId']])) - - for missing_subtitles_item in missing_subtitles_global: + actual_subtitles_temp = [x for x in ast.literal_eval(movie_subtitles['subtitles']) if x[1]] + + for subtitles in actual_subtitles_temp: + subtitles = subtitles[0].split(':') + lang = subtitles[0] + forced = False + hi = False + if len(subtitles) > 1: + if subtitles[1] == 'forced': + forced = True + hi = False + elif subtitles[1] == 'hi': + forced = False + hi = True + actual_subtitles_list.append([lang, str(forced), str(hi)]) + + # check if cutoff is reached and skip any further check + cutoff_met = False + cutoff_temp_list = get_profile_cutoff(profile_id=movie_subtitles['profileId']) + + if cutoff_temp_list: + for cutoff_temp in cutoff_temp_list: + cutoff_language = [cutoff_temp['language'], cutoff_temp['forced'], cutoff_temp['hi']] + if cutoff_language in actual_subtitles_list: + cutoff_met = True + missing_subtitles_text = str([]) + elif cutoff_language and [cutoff_language[0], 'True', 'False'] in actual_subtitles_list: + cutoff_met = True + missing_subtitles_text = str([]) + elif cutoff_language and [cutoff_language[0], 'False', 'True'] in actual_subtitles_list: + cutoff_met = True + missing_subtitles_text = str([]) + + if not cutoff_met: + # get difference between desired and existing subtitles + missing_subtitles_list = [] + for item in desired_subtitles_list: + if item not in actual_subtitles_list: + missing_subtitles_list.append(item) + + # remove missing that have forced or hi subtitles for this language in existing + for item in actual_subtitles_list: + if item[1] == 'True' or item[2] == 'True': + try: + missing_subtitles_list.remove([item[0], 'False', 'False']) + except ValueError: + pass + + # make the missing languages list looks like expected + missing_subtitles_output_list = [] + for item in missing_subtitles_list: + lang = item[0] + if item[1] == 'True': + lang += ':forced' + elif item[2] == 'True': + lang += ':hi' + missing_subtitles_output_list.append(lang) + + missing_subtitles_text = str(missing_subtitles_output_list) + database.execute("UPDATE table_movies SET missing_subtitles=? WHERE radarrId=?", - (missing_subtitles_item[0], missing_subtitles_item[1])) + (missing_subtitles_text, movie_subtitles['radarrId'])) if send_event: - event_stream(type='movie', action='update', movie=missing_subtitles_item[1]) + event_stream(type='movie', action='update', movie=movie_subtitles['radarrId']) event_stream(type='badges_movies') diff --git a/bazarr/main.py b/bazarr/main.py index d4a965464..0203f2e42 100644 --- a/bazarr/main.py +++ b/bazarr/main.py @@ -1,32 +1,29 @@ # coding=utf-8 -bazarr_version = '0.9.0.8' +bazarr_version = '0.9.1' import os os.environ["BAZARR_VERSION"] = bazarr_version import gc -import sys import libs import hashlib import apprise -import requests import calendar from get_args import args from logger import empty_log -from config import settings, url_sonarr, url_radarr, url_radarr_short, url_sonarr_short, base_url, configure_proxy_func +from config import settings, url_sonarr, url_radarr, configure_proxy_func from init import * -from database import database, dict_mapper +from database import database from notifier import update_notifier from urllib.parse import unquote -from get_languages import load_language_in_db, language_from_alpha3, language_from_alpha2, alpha2_from_alpha3, \ - alpha3_from_alpha2 +from get_languages import load_language_in_db, language_from_alpha2, alpha3_from_alpha2 from flask import make_response, request, redirect, abort, render_template, Response, session, flash, url_for, \ send_file, stream_with_context diff --git a/bazarr/scheduler.py b/bazarr/scheduler.py index b9477d84f..2bac3f1c6 100644 --- a/bazarr/scheduler.py +++ b/bazarr/scheduler.py @@ -4,7 +4,8 @@ from get_episodes import sync_episodes, update_all_episodes from get_movies import update_movies, update_all_movies from get_series import update_series from config import settings -from get_subtitle import wanted_search_missing_subtitles_series, wanted_search_missing_subtitles_movies, upgrade_subtitles +from get_subtitle import wanted_search_missing_subtitles_series, wanted_search_missing_subtitles_movies, \ + upgrade_subtitles from utils import cache_maintenance from get_args import args if not args.no_update: @@ -21,6 +22,7 @@ from calendar import day_name import pretty from random import randrange from event_handler import event_stream +import os class Scheduler: @@ -62,10 +64,10 @@ class Scheduler: if args.no_tasks: self.__no_task() - def add_job(self, job, name=None, max_instances=1, coalesce=True, args=None): + def add_job(self, job, name=None, max_instances=1, coalesce=True, args=None, kwargs=None): self.aps_scheduler.add_job( job, DateTrigger(run_date=datetime.now()), name=name, id=name, max_instances=max_instances, - coalesce=coalesce, args=args) + coalesce=coalesce, args=args, kwargs=kwargs) def execute_job_now(self, taskid): self.aps_scheduler.modify_job(taskid, next_run_time=datetime.now()) @@ -252,3 +254,12 @@ class Scheduler: scheduler = Scheduler() + +# Force the execution of the sync process with Sonarr and Radarr after migration to v0.9.1 +if 'BAZARR_AUDIO_PROFILES_MIGRATION' in os.environ: + if settings.general.getboolean('use_sonarr'): + scheduler.aps_scheduler.modify_job('update_series', next_run_time=datetime.now()) + scheduler.aps_scheduler.modify_job('sync_episodes', next_run_time=datetime.now()) + if settings.general.getboolean('use_radarr'): + scheduler.aps_scheduler.modify_job('update_movies', next_run_time=datetime.now()) + del os.environ['BAZARR_AUDIO_PROFILES_MIGRATION'] diff --git a/bazarr/server.py b/bazarr/server.py index 539c6e84b..260969677 100644 --- a/bazarr/server.py +++ b/bazarr/server.py @@ -1,3 +1,5 @@ +# coding=utf-8 + import warnings import logging import os diff --git a/libs/subliminal_patch/core.py b/libs/subliminal_patch/core.py index 55bbb2e07..0dc7d6ecd 100644 --- a/libs/subliminal_patch/core.py +++ b/libs/subliminal_patch/core.py @@ -823,9 +823,8 @@ def get_subtitle_path(video_path, language=None, extension='.srt', forced_tag=Fa if forced_tag: tags.append("forced") - # fixme when we'll be ready to add .hi to filename when saving a subtitles - # elif hi_tag: - # tags.append("hi") + elif hi_tag: + tags.append("hi") if language: subtitle_root += '.' + str(language.basename) diff --git a/views/_main.html b/views/_main.html index 1efd57ab2..83d31d16e 100644 --- a/views/_main.html +++ b/views/_main.html @@ -269,11 +269,11 @@ class="fas fa-cogs"> Settings diff --git a/views/episodes.html b/views/episodes.html index 83073ccf6..785ff6613 100644 --- a/views/episodes.html +++ b/views/episodes.html @@ -87,7 +87,9 @@ title="None" data-html="true">
-
+
+
+
@@ -95,7 +97,7 @@ title="None" data-html="true">Tags
-
+
@@ -117,7 +119,7 @@ Episode Title - Audio Language + Audio Languages Existing Subtitles Missing Subtitles Manual Search @@ -287,42 +289,19 @@
- Audio Profile + Audio Profile Languages
+
- Subtitles Language(s) + Languages Profile
- -
-
-
-
- Hearing-Impaired -
-
- -
-
-
-
- Forced -
-
- +
@@ -564,6 +543,7 @@ episodesDetailsRefresh(); getLanguages(); getEnabledLanguages(); + getLanguagesProfiles(); var collapsedGroups = {}; @@ -636,7 +616,16 @@ } }, { - data: 'audio_language.name' + data: 'audio_language', + render: function (data) { + var audio_languages = ''; + data.forEach(appendFunc); + return audio_languages; + + function appendFunc(value) { + audio_languages = audio_languages + '' + value.name + ' '; + } + } }, { data: null, @@ -686,7 +675,7 @@ var advtag = ''; } - languages = languages + '' + value.code2 + advtag + ' '; + languages = languages + '' + value.code2 + advtag + ' '; } } }, @@ -694,7 +683,7 @@ data: null, render: function (data) { if (data.desired_languages !== '[]') { - return ''; + return ''; } else { return '' } @@ -704,7 +693,7 @@ data: null, render: function (data) { if (data.desired_languages !== '[]') { - return ''; + return ''; } else { return '' } @@ -783,9 +772,7 @@ episodePath = $(this).attr("data-episodePath"); sceneName = $(this).attr("data-sceneName"); - language = $(this).attr("data-language"); - hi = seriesDetails['hearing_impaired']; - forced = seriesDetails['forced']; + profileId = seriesDetails['profileId'].id; sonarrSeriesId = seriesDetails['sonarrSeriesId']; sonarrEpisodeId = $(this).attr("data-sonarrEpisodeId"); var languages = Array.from(seriesDetails['languages']); @@ -795,9 +782,7 @@ const values = { episodePath: episodePath, sceneName: sceneName, - language: language, - hi: hi, - forced: forced, + profileId: profileId, sonarrSeriesId: sonarrSeriesId, sonarrEpisodeId: sonarrEpisodeId, title: seriesDetails['title'] @@ -906,7 +891,7 @@ data: null, searchable: false, render: function (data) { - return ''; + return ''; } } ] @@ -956,7 +941,7 @@ $('#upload_sonarrSeriesId').val($(this).data("sonarrseriesid")); $('#upload_sonarrEpisodeId').val($(this).data("sonarrepisodeid")); $('#upload_title').val($(this).data("episode_title")); - $('#upload_audioLanguage').val($(this).data("audio_language")); + $('#upload_audioLanguage').val(($(this).data("audio_language").length) ? $(this).data("audio_language")[0].name : 'None'); $('#manual_language_select').empty(); $.each(enabledLanguages, function (i, item) { @@ -1340,26 +1325,20 @@ $('#edit_button').on('click', function (e) { e.preventDefault(); $("#edit_series_title_span").html(seriesDetails['title']); - $("#edit_audio_language_span").text(seriesDetails['audio_language']['name']); + $("#edit_audio_language_span").empty(); + $.each(seriesDetails['audio_language'], function (i, item) { + $("#edit_audio_language_span").append('
' + item['name'] + '
'); + }) $('#edit_sonarrSeriesId').val(seriesDetails['sonarrSeriesId']); $('#edit_languages_select').empty(); - if ('{{settings.general.single_language}}' === 'True') { - $('#edit_languages_select').selectpicker({maxOptions: 1}); - $('#edit_languages_select').append(''); - } - $.each(enabledLanguages, function (i, item) { - $('#edit_languages_select').append(''); + $('#edit_languages_select').append(''); + $.each(languagesProfiles, function (i, item) { + $('#edit_languages_select').append(''); }); $("#edit_languages_select").selectpicker("refresh"); - var selected_languages = Array(); - $.each(Array.from(seriesDetails['languages']), function (i, item) { - selected_languages.push(item.code2); - }); - $('#edit_languages_select').selectpicker('val', selected_languages); - $('#hi_checkbox').prop('checked', (seriesDetails['hearing_impaired'] === 'True')); - $('#edit_forced_select').val(seriesDetails['forced']).change(); + $('#edit_languages_select').selectpicker('val', ((seriesDetails['profileId'].id) ? seriesDetails['profileId'].id : 'None')); $('#editModal') .modal({ @@ -1826,30 +1805,23 @@ $('#seriesTags').hide(); } - $('#seriesAudioLanguage').text(seriesDetails['audio_language']['name']); + $("#seriesAudioLanguage").empty(); + $.each(seriesDetails['audio_language'], function (i, item) { + $("#seriesAudioLanguage").append('
' + item['name'] + '
'); + }) $('#seriesMappedPath').text(seriesDetails['mapped_path']); $('#seriesMappedPath').attr("data-original-title", seriesDetails['mapped_path']); $('#seriesFileCount').text(seriesDetails['episodeFileCount'] + ' files'); $('#seriesType').text(seriesDetails['seriesType']); - var languages = ''; - if (seriesDetails['languages'] && seriesDetails['languages'] !== 'None') { - seriesDetails['languages'].forEach(appendFunc); - } - - function appendFunc(value) { - languages = languages + '' + value.code2 + ' '; - } + $('#seriesSubtitlesLanguagesProfile').text(seriesDetails['profileId'].name); - $('#seriesSubtitlesLanguages').html(languages); - $('#seriesHearingImpaired').text('Hearing-Impaired: ' + seriesDetails['hearing_impaired']); - $('#seriesForced').text('Forced: ' + seriesDetails['forced']); $('#seriesDescription').text(seriesDetails['overview']); - if (seriesDetails['desired_languages'] == '[]') { - $('#search_button').hide(); - } else { + if (seriesDetails['profileId'].id) { $('#search_button').show(); + } else { + $('#search_button').hide(); } $('[data-toggle="tooltip"]').tooltip({html: true}); @@ -1873,5 +1845,14 @@ } }); } + + function getLanguagesProfiles() { + $.ajax({ + url: "{{ url_for('api.languagesprofiles') }}", + success: function (data) { + languagesProfiles = data['data']; + } + }); + } {% endblock tail %} diff --git a/views/movie.html b/views/movie.html index d7fd9e8c6..1d67d2817 100644 --- a/views/movie.html +++ b/views/movie.html @@ -94,17 +94,15 @@
-
+
+
+
Tags
-
-
-
-
-
+
@@ -244,33 +242,10 @@
- Subtitles Language(s) -
-
- -
-
-
-
- Hearing-Impaired -
-
- -
-
-
-
- Forced + Languages Profile
- +
@@ -511,6 +486,7 @@ movieDetailsRefresh(); getLanguages(); getEnabledLanguages(); + getLanguagesProfiles(); //test $('#movieSubtitles').on('click', '.remove_subtitles', function(e){ @@ -544,8 +520,8 @@ moviePath: movieDetails['mapped_path'], sceneName: movieDetails['sceneName'], language: $(this).attr("data-language"), - hi: movieDetails['hearing_impaired'], - forced:$(this).attr("data-forced"), + hi: $(this).attr("data-hi"), + forced: $(this).attr("data-forced"), radarrId: movieDetails['radarrId'], title: movieDetails['title'] }; @@ -569,9 +545,7 @@ moviePath = movieDetails['mapped_path']; sceneName = movieDetails['sceneName']; - language = movieDetails['desired_languages']; - hi = movieDetails['hearing_impaired']; - forced = movieDetails['forced']; + profileId = movieDetails['profileId'].id; radarrId = movieDetails['radarrId']; var languages = Array.from(movieDetails['languages']); var is_pb = languages.includes('pb'); @@ -580,9 +554,7 @@ const values = { moviePath: moviePath, sceneName: sceneName, - language: language, - hi: hi, - forced: forced, + profileId: profileId, radarrId: radarrId, title: movieDetails['title'] }; @@ -683,7 +655,7 @@ { data: null, searchable: false, render: function ( data ) { - return ''; + return ''; } } ] @@ -730,7 +702,7 @@ $('#upload_sceneName').val(movieDetails['sceneName']); $('#upload_radarrId').val(movieDetails['radarrId']); $('#upload_title').val(movieDetails['title']); - $('#upload_audioLanguage').val(movieDetails['audio_language']['name']); + $('#upload_audioLanguage').val((movieDetails['audio_language'].length) ? movieDetails['audio_language'][0].name : 'None'); $('#manual_language_select').empty(); $.each(enabledLanguages, function (i, item) { @@ -794,26 +766,20 @@ $('#edit_button').on('click', function(e){ e.preventDefault(); $("#edit_movie_title_span").html(movieDetails['title']); - $("#edit_audio_language_span").text(movieDetails['audio_language']['name']); - $('#edit_radarrId').val(movieDetails['radarrId']); + $("#edit_audio_language_span").empty(); + $.each(movieDetails['audio_language'], function (i, item) { + $("#edit_audio_language_span").append('
' + item['name'] + '
'); + }) + $('#edit_radarrId').val(movieDetails['radarrId']); $('#edit_languages_select').empty(); - if ('{{settings.general.single_language}}' === 'True') { - $('#edit_languages_select').selectpicker({maxOptions: 1}); - $('#edit_languages_select').append(''); - } - $.each(enabledLanguages, function (i, item) { - $('#edit_languages_select').append(''); + $('#edit_languages_select').append(''); + $.each(languagesProfiles, function (i, item) { + $('#edit_languages_select').append(''); }); $("#edit_languages_select").selectpicker("refresh"); - var selected_languages = Array(); - $.each(Array.from(movieDetails['languages']), function (i, item) { - selected_languages.push(item.code2); - }); - $('#edit_languages_select').selectpicker('val', selected_languages); - $('#hi_checkbox').prop('checked', (movieDetails['hearing_impaired'] === 'True')); - $('#edit_forced_select').val(movieDetails['forced']).change(); + $('#edit_languages_select').selectpicker('val', ((movieDetails['profileId'].id) ? movieDetails['profileId'].id : 'None')); $('#editModal') .modal({ @@ -1223,22 +1189,15 @@ $('#movieTags').hide(); } - $('#movieAudioLanguage').text(movieDetails['audio_language']['name']); - $('#movieMappedPath').text(movieDetails['mapped_path']); + $("#movieAudioLanguage").empty(); + $.each(movieDetails['audio_language'], function (i, item) { + $("#movieAudioLanguage").append('
' + item['name'] + '
'); + }) + $('#movieMappedPath').text(movieDetails['mapped_path']); $('#movieMappedPath').attr("data-original-title", movieDetails['mapped_path']); - var languages = ''; - if (movieDetails['languages'] && movieDetails['languages'] !== 'None') { - movieDetails['languages'].forEach(appendFunc); - } - - function appendFunc(value) { - languages += '' + value.code2 + ' '; - } + $('#movieSubtitlesLanguagesProfile').text(movieDetails['profileId'].name); - $('#movieSubtitlesLanguages').html(languages); - $('#movieHearingImpaired').text('Hearing-Impaired: ' + movieDetails['hearing_impaired']); - $('#movieForced').text('Forced: ' + movieDetails['forced']); $('#movieDescription').text(movieDetails['overview']); var missing_languages = ''; @@ -1248,11 +1207,11 @@ function missingAppendFunc(value) { if (value.forced) { - missing_languages += ' '; + missing_languages += ' '; } else if (value.hi) { - missing_languages += ' '; + missing_languages += ' '; } else { - missing_languages += ' '; + missing_languages += ' '; } } @@ -1260,14 +1219,14 @@ $('[data-toggle="tooltip"]').tooltip({html: true}); - if (movieDetails['desired_languages'] == '[]') { - $('#search_button').hide(); - $('#manual_button').hide(); - $('#upload_button').hide(); - } else { + if (movieDetails['profileId'].id) { $('#search_button').show(); $('#manual_button').show(); $('#upload_button').show(); + } else { + $('#search_button').hide(); + $('#manual_button').hide(); + $('#upload_button').hide(); } @@ -1335,5 +1294,14 @@ } }); } + + function getLanguagesProfiles() { + $.ajax({ + url: "{{ url_for('api.languagesprofiles') }}", + success: function (data) { + languagesProfiles = data['data']; + } + }); + } {% endblock tail %} diff --git a/views/movies.html b/views/movies.html index 482206dcf..1a1d65a98 100644 --- a/views/movies.html +++ b/views/movies.html @@ -24,9 +24,7 @@ Name Path Exist Audio Language - Subtitles Languages - Hearing-Impaired - Forced + Languages Profile Missing Subtitles @@ -55,34 +53,10 @@
- Subtitles Language(s) + Languages Profile
- -
-
-
-
- Hearing-Impaired -
-
- -
-
-
-
- Forced -
-
- +
@@ -102,8 +76,7 @@ {% block tail %} {% endblock tail %} diff --git a/views/settingsradarr.html b/views/settingsradarr.html index 3a7a359ca..1f51af3ae 100644 --- a/views/settingsradarr.html +++ b/views/settingsradarr.html @@ -202,7 +202,7 @@ @@ -242,7 +242,7 @@ diff --git a/views/settingssonarr.html b/views/settingssonarr.html index e7ec5983b..a4e53e5e8 100644 --- a/views/settingssonarr.html +++ b/views/settingssonarr.html @@ -215,7 +215,7 @@ @@ -255,7 +255,7 @@ diff --git a/views/settingssubtitles.html b/views/settingssubtitles.html index 02a3d2dec..0de71fd19 100644 --- a/views/settingssubtitles.html +++ b/views/settingssubtitles.html @@ -422,19 +422,19 @@ -
-
- Subtitles synchronization debugging -
-
- - -
-
+
+
+ Subtitles synchronization debugging +
+
+ + +
+
Subtitles synchronization score threshold for series