mirror of https://github.com/morpheus65535/bazarr
Languages profiles (#1232)
Implementing the languages profiles functionality.
This commit is contained in:
parent
240a3759cf
commit
22cd45bc41
304
bazarr/api.py
304
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 = '[]'
|
||||
if languages_profile == 'None':
|
||||
languages_profile = None
|
||||
|
||||
hi = request.form.get('hi')
|
||||
forced = request.form.get('forced')
|
||||
|
||||
if hi == "on":
|
||||
hi = "True"
|
||||
else:
|
||||
hi = "False"
|
||||
|
||||
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'
|
||||
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 = '[]'
|
||||
if languages_profile == 'None':
|
||||
languages_profile = None
|
||||
|
||||
hi = request.form.get('hi')
|
||||
forced = request.form.get('forced')
|
||||
|
||||
if hi == "on":
|
||||
hi = "True"
|
||||
else:
|
||||
hi = "False"
|
||||
|
||||
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')
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# coding=utf-8
|
||||
|
||||
import os
|
||||
import logging
|
||||
import json
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# coding=utf-8
|
||||
|
||||
import enzyme
|
||||
from enzyme.exceptions import MalformedMKVError
|
||||
import logging
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# coding=utf-8
|
||||
|
||||
import json
|
||||
from app import socketio
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# coding=utf-8
|
||||
|
||||
import os
|
||||
import requests
|
||||
import logging
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# coding=utf-8
|
||||
|
||||
import os
|
||||
import argparse
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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():
|
||||
|
|
|
@ -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
|
||||
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
|
||||
|
||||
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:
|
||||
forced_languages = desired_languages
|
||||
|
||||
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)
|
||||
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"
|
||||
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)),
|
||||
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)
|
||||
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):
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# coding=utf-8
|
||||
|
||||
import ast
|
||||
import os
|
||||
import re
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
import os
|
||||
import io
|
||||
import rarfile
|
||||
import json
|
||||
import hashlib
|
||||
import sys
|
||||
import subprocess
|
||||
|
||||
|
|
|
@ -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
|
||||
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']])
|
||||
|
||||
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")
|
||||
# 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']]))
|
||||
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)
|
||||
|
||||
for missing_subtitles_item in missing_subtitles_global:
|
||||
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")
|
||||
|
||||
use_embedded_subs = settings.general.getboolean('use_embedded_subs')
|
||||
|
||||
for movie_subtitles in movies_subtitles:
|
||||
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')
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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']
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# coding=utf-8
|
||||
|
||||
import warnings
|
||||
import logging
|
||||
import os
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -269,11 +269,11 @@
|
|||
class="fas fa-cogs"></i><span class="hide-menu"> Settings</span></a>
|
||||
<ul aria-expanded="false" class="collapse">
|
||||
<li><a href="{{ url_for('settingsgeneral') }}"> General</a></li>
|
||||
<li><a href="{{ url_for('settingssonarr') }}"> Sonarr</a></li>
|
||||
<li><a href="{{ url_for('settingsradarr') }}"> Radarr</a></li>
|
||||
<li><a href="{{ url_for('settingssubtitles') }}"> Subtitles</a></li>
|
||||
<li><a href="{{ url_for('settingslanguages') }}"> Languages</a></li>
|
||||
<li><a href="{{ url_for('settingsproviders') }}"> Providers</a></li>
|
||||
<li><a href="{{ url_for('settingssubtitles') }}"> Subtitles</a></li>
|
||||
<li><a href="{{ url_for('settingssonarr') }}"> Sonarr</a></li>
|
||||
<li><a href="{{ url_for('settingsradarr') }}"> Radarr</a></li>
|
||||
<li><a href="{{ url_for('settingsnotifications') }}"> Notifications</a></li>
|
||||
<li><a href="{{ url_for('settingsscheduler') }}"> Scheduler</a></li>
|
||||
</ul>
|
||||
|
|
|
@ -87,7 +87,9 @@
|
|||
title="None" data-html="true"></i>
|
||||
</div>
|
||||
<div class="row">
|
||||
<h5><span id="seriesAudioLanguage" class="badge badge-secondary"></span></h5>
|
||||
<h5><span id="seriesAudioLanguage"></span></h5>
|
||||
</div>
|
||||
<div class="row">
|
||||
<h5><span id="seriesMappedPath" class="badge badge-secondary"></span></h5>
|
||||
<h5><span id="seriesFileCount" class="badge badge-secondary"></span></h5>
|
||||
<h5><span id="seriesType" class="badge badge-secondary"></span></h5>
|
||||
|
@ -95,7 +97,7 @@
|
|||
title="None" data-html="true">Tags</span></h5>
|
||||
</div>
|
||||
<div class="row">
|
||||
<h5><span id="seriesSubtitlesLanguages"></span></h5>
|
||||
<h5><span id="seriesSubtitlesLanguagesProfile" class="badge badge-secondary"></span></h5>
|
||||
</div>
|
||||
<div class="row">
|
||||
<h5><span id="seriesHearingImpaired" class="badge badge-secondary"></span></h5>
|
||||
|
@ -117,7 +119,7 @@
|
|||
<th></th>
|
||||
<th>Episode</th>
|
||||
<th>Title</th>
|
||||
<th>Audio Language</th>
|
||||
<th>Audio Languages</th>
|
||||
<th>Existing Subtitles</th>
|
||||
<th>Missing Subtitles</th>
|
||||
<th>Manual Search</th>
|
||||
|
@ -287,42 +289,19 @@
|
|||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-sm-3 text-right">
|
||||
Audio Profile
|
||||
Audio Profile Languages
|
||||
</div>
|
||||
<div class="form-group col-sm-8 pl-sm-0">
|
||||
<span id="edit_audio_language_span"></span>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div class="row">
|
||||
<div class="col-sm-3 text-right">
|
||||
Subtitles Language(s)
|
||||
Languages Profile
|
||||
</div>
|
||||
<div class="form-group col-sm-8 pl-sm-0">
|
||||
<select class="selectpicker" id="edit_languages_select" name="languages" multiple
|
||||
data-live-search="true"></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-3 text-right">
|
||||
Hearing-Impaired
|
||||
</div>
|
||||
<div class="form-group col-sm-1 pl-sm-0">
|
||||
<label class="custom-control custom-checkbox">
|
||||
<input type="checkbox" class="custom-control-input" id="hi_checkbox" name="hi">
|
||||
<span class="custom-control-label" for="hi_checkbox"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-3 text-right">
|
||||
Forced
|
||||
</div>
|
||||
<div class="form-group col-sm-8 pl-sm-0">
|
||||
<select class="selectpicker" id="edit_forced_select" name="forced">
|
||||
<option value="False">False</option>
|
||||
<option value="True">True</option>
|
||||
<option value="Both">Both</option>
|
||||
</select>
|
||||
<select class="selectpicker" id="edit_languages_select" name="languages"></select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -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 + '<span class="badge badge-secondary">' + value.name + '</span> ';
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
data: null,
|
||||
|
@ -686,7 +675,7 @@
|
|||
var advtag = '';
|
||||
}
|
||||
|
||||
languages = languages + '<a href="" class="get_subtitle badge badge-secondary" data-toggle="tooltip" data-placement="right" title="' + value.name + advtag + '" data-episodepath="' + data.mapped_path + '" data-scenename="' + data.scene_name + '" data-title="' + data.title + '" data-language="' + value.code3 + '" data-hi="' + seriesDetails.hearing_impaired + '" data-forced="' + value.forced + '" data-sonarrepisodeid=' + data.sonarrEpisodeId + '>' + value.code2 + advtag + ' <i class="fas fa-search"></i></a> ';
|
||||
languages = languages + '<a href="" class="get_subtitle badge badge-secondary" data-toggle="tooltip" data-placement="right" title="' + value.name + advtag + '" data-episodepath="' + data.mapped_path + '" data-scenename="' + data.scene_name + '" data-title="' + data.title + '" data-language="' + value.code3 + '" data-hi="' + value.hi + '" data-forced="' + value.forced + '" data-sonarrepisodeid=' + data.sonarrEpisodeId + '>' + value.code2 + advtag + ' <i class="fas fa-search"></i></a> ';
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -694,7 +683,7 @@
|
|||
data: null,
|
||||
render: function (data) {
|
||||
if (data.desired_languages !== '[]') {
|
||||
return '<a href="" class="manual_search badge badge-secondary" data-season=' + data.season + ' data-episode=' + data.episode + ' data-episode_title="' + data.title + '" data-episodePath="' + data.mapped_path + '" data-sceneName="' + data.scene_name + '" data-language="' + data.desired_languages + '" data-sonarrEpisodeId=' + data.sonarrEpisodeId + '><i class="fas fa-user"></i></a>';
|
||||
return '<a href="" class="manual_search badge badge-secondary" data-season=' + data.season + ' data-episode=' + data.episode + ' data-episode_title="' + data.title + '" data-episodePath="' + data.mapped_path + '" data-sceneName="' + data.scene_name + '" data-sonarrEpisodeId=' + data.sonarrEpisodeId + '><i class="fas fa-user"></i></a>';
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
|
@ -704,7 +693,7 @@
|
|||
data: null,
|
||||
render: function (data) {
|
||||
if (data.desired_languages !== '[]') {
|
||||
return '<a href="" class="upload_subtitle badge badge-secondary" data-episodePath="' + data.mapped_path + '" data-sceneName"' + data.scene_name + '" data-sonarrSeriesId="' + seriesDetails['sonarrSeriesId'] + '" data-sonarrEpisodeId="' + data.sonarrEpisodeId + '" data-season="' + data.season + '" data-episode="' + data.episode + '" data-episode_title="' + data.title + '" data-audio_language="' + data.audio_language.name + '"><i class="fas fa-cloud-upload-alt"></i></a>';
|
||||
return '<a href="" class="upload_subtitle badge badge-secondary" data-episodePath="' + data.mapped_path + '" data-sceneName"' + data.scene_name + '" data-sonarrSeriesId="' + seriesDetails['sonarrSeriesId'] + '" data-sonarrEpisodeId="' + data.sonarrEpisodeId + '" data-season="' + data.season + '" data-episode="' + data.episode + '" data-episode_title="' + data.title + '" data-audio_language=\'' + JSON.stringify(data.audio_language) + '\'><i class="fas fa-cloud-upload-alt"></i></a>';
|
||||
} 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 '<a href="" class="manual_download badge badge-secondary" data-episodePath="' + episodePath + '" data-sceneName="' + sceneName + '" data-sonarrEpisodeId=' + sonarrEpisodeId + ' data-subtitle="' + data.subtitle + '" data-provider="' + data.provider + '" data-language="' + data.language + '" data-forced="' + forced + '"><i class="fas fa-download" style="margin-right:0px" ></i></a>';
|
||||
return '<a href="" class="manual_download badge badge-secondary" data-episodePath="' + episodePath + '" data-sceneName="' + sceneName + '" data-sonarrEpisodeId=' + sonarrEpisodeId + ' data-subtitle="' + data.subtitle + '" data-provider="' + data.provider + '" data-language="' + data.language + '" data-forced="' + data.forced + '"><i class="fas fa-download" style="margin-right:0px" ></i></a>';
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -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('<div class="badge badge-secondary">' + item['name'] + '</div> ');
|
||||
})
|
||||
$('#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('<option value="None">None</option>');
|
||||
}
|
||||
$.each(enabledLanguages, function (i, item) {
|
||||
$('#edit_languages_select').append('<option value="' + item.code2 + '">' + item.name + '</option>');
|
||||
$('#edit_languages_select').append('<option value="None">None</option>');
|
||||
$.each(languagesProfiles, function (i, item) {
|
||||
$('#edit_languages_select').append('<option value="' + item.profileId + '">' + item.name + '</option>');
|
||||
});
|
||||
$("#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('<div class="badge badge-secondary"><i class="fa fa-music"></i> ' + item['name'] + '</div> ');
|
||||
})
|
||||
$('#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);
|
||||
}
|
||||
$('#seriesSubtitlesLanguagesProfile').text(seriesDetails['profileId'].name);
|
||||
|
||||
function appendFunc(value) {
|
||||
languages = languages + '<span class="badge badge-secondary" data-toggle="tooltip" data-placement="right" title="' + value.name + '">' + value.code2 + '</span> ';
|
||||
}
|
||||
|
||||
$('#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'];
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
{% endblock tail %}
|
||||
|
|
122
views/movie.html
122
views/movie.html
|
@ -94,17 +94,15 @@
|
|||
<i class="far fa-clone" id="moviealternativeTitles" data-toggle="tooltip" data-placement="right" title="None" data-html="true"></i>
|
||||
</div>
|
||||
<div class="row">
|
||||
<h5><span id="movieAudioLanguage" class="badge badge-secondary"></span></h5>
|
||||
<h5><span id="movieAudioLanguage"></span></h5>
|
||||
</div>
|
||||
<div class="row">
|
||||
<h5><span id="movieMappedPath" data-toggle="tooltip" data-placement="right" title="None" class="badge badge-secondary"></span></h5>
|
||||
<h5><span id="movieTags" class="badge badge-secondary" data-toggle="tooltip" data-placement="right"
|
||||
title="None" data-html="true">Tags</span></h5>
|
||||
</div>
|
||||
<div class="row">
|
||||
<h5><span id="movieSubtitlesLanguages"></span></h5>
|
||||
</div>
|
||||
<div class="row">
|
||||
<h5><span id="movieHearingImpaired" class="badge badge-secondary"></span></h5>
|
||||
<h5><span id="movieForced" class="badge badge-secondary"></span></h5>
|
||||
<h5><span id="movieSubtitlesLanguagesProfile" class="badge badge-secondary"></span></h5>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span id="movieDescription"></span>
|
||||
|
@ -244,33 +242,10 @@
|
|||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-3 text-right">
|
||||
Subtitles Language(s)
|
||||
Languages Profile
|
||||
</div>
|
||||
<div class="form-group col-sm-8 pl-sm-0">
|
||||
<select class="selectpicker" id="edit_languages_select" name="languages" multiple data-live-search="true"></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-3 text-right">
|
||||
Hearing-Impaired
|
||||
</div>
|
||||
<div class="form-group col-sm-1 pl-sm-0">
|
||||
<label class="custom-control custom-checkbox">
|
||||
<input type="checkbox" class="custom-control-input" id="hi_checkbox" name="hi">
|
||||
<span class="custom-control-label" for="hi_checkbox"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-3 text-right">
|
||||
Forced
|
||||
</div>
|
||||
<div class="form-group col-sm-8 pl-sm-0">
|
||||
<select class="selectpicker" id="edit_forced_select" name="forced">
|
||||
<option value="False">False</option>
|
||||
<option value="True">True</option>
|
||||
<option value="Both">Both</option>
|
||||
</select>
|
||||
<select class="selectpicker" id="edit_languages_select" name="languages"></select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -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 '<a href="" class="manual_download badge badge-secondary" data-moviePath="'+moviePath+'" data-sceneName="'+sceneName+'" data-subtitle="'+data.subtitle+'" data-provider="'+data.provider+'" data-language="'+data.language+'" data-forced="'+forced+'"><i class="fas fa-download" style="margin-right:0px" ></i></a>';
|
||||
return '<a href="" class="manual_download badge badge-secondary" data-moviePath="'+moviePath+'" data-sceneName="'+sceneName+'" data-subtitle="'+data.subtitle+'" data-provider="'+data.provider+'" data-language="'+data.language+'" data-forced="'+data.forced+'"><i class="fas fa-download" style="margin-right:0px" ></i></a>';
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -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('<div class="badge badge-secondary">' + item['name'] + '</div> ');
|
||||
})
|
||||
$('#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('<option value="None">None</option>');
|
||||
}
|
||||
$.each(enabledLanguages, function (i, item) {
|
||||
$('#edit_languages_select').append('<option value="'+item.code2+'">'+item.name+'</option>');
|
||||
$('#edit_languages_select').append('<option value="None">None</option>');
|
||||
$.each(languagesProfiles, function (i, item) {
|
||||
$('#edit_languages_select').append('<option value="'+item.profileId+'">'+item.name+'</option>');
|
||||
});
|
||||
$("#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('<div class="badge badge-secondary"><i class="fa fa-music"></i> ' + item['name'] + '</div> ');
|
||||
})
|
||||
$('#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);
|
||||
}
|
||||
$('#movieSubtitlesLanguagesProfile').text(movieDetails['profileId'].name);
|
||||
|
||||
function appendFunc(value) {
|
||||
languages += '<span class="badge badge-secondary" data-toggle="tooltip" data-placement="right" title="' + value.name + '">' + value.code2 + '</span> ';
|
||||
}
|
||||
|
||||
$('#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 += '<button class="get_subtitle btn btn-secondary btn-sm" type="button" data-toggle="tooltip" data-placement="right" data-original-title="' + value.name + '" data-language="' + value.code3 + '" data-forced=' + value.forced + '>' + value.code2 + ':forced <i class="fas fa-search"></i></button> ';
|
||||
missing_languages += '<button class="get_subtitle btn btn-secondary btn-sm" type="button" data-toggle="tooltip" data-placement="right" data-original-title="' + value.name + ' Forced" data-language="' + value.code3 + '" data-hi="' + value.hi + '" data-forced="' + value.forced + '">' + value.code2 + ':forced <i class="fas fa-search"></i></button> ';
|
||||
} else if (value.hi) {
|
||||
missing_languages += '<button class="get_subtitle btn btn-secondary btn-sm" type="button" data-toggle="tooltip" data-placement="right" data-original-title="' + value.name + '" data-language="' + value.code3 + '" data-forced=' + value.forced + '>' + value.code2 + ':HI <i class="fas fa-search"></i></button> ';
|
||||
missing_languages += '<button class="get_subtitle btn btn-secondary btn-sm" type="button" data-toggle="tooltip" data-placement="right" data-original-title="' + value.name + ' HI" data-language="' + value.code3 + '" data-hi="' + value.hi + '" data-forced="' + value.forced + '">' + value.code2 + ':HI <i class="fas fa-search"></i></button> ';
|
||||
} else {
|
||||
missing_languages += '<button class="get_subtitle btn btn-secondary btn-sm" type="button" data-toggle="tooltip" data-placement="right" data-original-title="' + value.name + '" data-language="' + value.code3 + '" data-forced=' + value.forced + '>' + value.code2 + ' <i class="fas fa-search"></i></button> ';
|
||||
missing_languages += '<button class="get_subtitle btn btn-secondary btn-sm" type="button" data-toggle="tooltip" data-placement="right" data-original-title="' + value.name + '" data-language="' + value.code3 + '" data-hi="' + value.hi + '" data-forced="' + value.forced + '">' + value.code2 + ' <i class="fas fa-search"></i></button> ';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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'];
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
{% endblock tail %}
|
||||
|
|
|
@ -24,9 +24,7 @@
|
|||
<th>Name</th>
|
||||
<th>Path Exist</th>
|
||||
<th>Audio Language</th>
|
||||
<th>Subtitles Languages</th>
|
||||
<th>Hearing-Impaired</th>
|
||||
<th>Forced</th>
|
||||
<th>Languages Profile</th>
|
||||
<th>Missing Subtitles</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
|
@ -55,34 +53,10 @@
|
|||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-3 text-right">
|
||||
Subtitles Language(s)
|
||||
Languages Profile
|
||||
</div>
|
||||
<div class="form-group col-sm-8 pl-sm-0">
|
||||
<select class="selectpicker" id="edit_languages_select" name="languages" multiple
|
||||
data-live-search="true"></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-3 text-right">
|
||||
Hearing-Impaired
|
||||
</div>
|
||||
<div class="form-group col-sm-1 pl-sm-0">
|
||||
<label class="custom-control custom-checkbox">
|
||||
<input type="checkbox" class="custom-control-input" id="hi_checkbox" name="hi">
|
||||
<span class="custom-control-label" for="hi_checkbox"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-3 text-right">
|
||||
Forced
|
||||
</div>
|
||||
<div class="form-group col-sm-8 pl-sm-0">
|
||||
<select class="selectpicker" id="edit_forced_select" name="forced">
|
||||
<option value="False">False</option>
|
||||
<option value="True">True</option>
|
||||
<option value="Both">Both</option>
|
||||
</select>
|
||||
<select class="selectpicker" id="edit_languages_select" name="languages"></select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -102,8 +76,7 @@
|
|||
{% block tail %}
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
getLanguages();
|
||||
getEnabledLanguages();
|
||||
getLanguagesProfiles();
|
||||
|
||||
events.on('event', function (event) {
|
||||
var event_json = JSON.parse(event);
|
||||
|
@ -185,29 +158,20 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
{data: "audio_language.name"},
|
||||
{
|
||||
data: "languages",
|
||||
data: 'audio_language',
|
||||
render: function (data) {
|
||||
if (data && data !== 'None') {
|
||||
var languages = '';
|
||||
data.forEach(appendFunc);
|
||||
return languages;
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
var audio_languages = '';
|
||||
data.forEach(appendFunc);
|
||||
return audio_languages;
|
||||
|
||||
function appendFunc(value) {
|
||||
languages = languages + '<span class="badge badge-secondary" data-toggle="tooltip" data-placement="right" title="' + value.name + '">' + value.code2 + '</span> ';
|
||||
audio_languages = audio_languages + '<span class="badge badge-secondary">' + value.name + '</span> ';
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
data: "hearing_impaired",
|
||||
className: "dt-center"
|
||||
},
|
||||
{
|
||||
data: "forced",
|
||||
data: "profileId.name",
|
||||
className: "dt-center"
|
||||
},
|
||||
{
|
||||
|
@ -229,7 +193,7 @@
|
|||
{
|
||||
data: null,
|
||||
render: function (data) {
|
||||
return '<a href="" class="edit_button badge badge-secondary" data-radarrId=' + data.radarrId + ' data-audiolanguage="' + data.audio_language.name + '" data-title="' + data.title + '" data-languages=' + JSON.stringify(data.languages) + ' data-hi="' + data.hearing_impaired + '" data-forced="' + data.forced + '"><i class="fas fa-wrench"></i></a>';
|
||||
return '<a href="" class="edit_button badge badge-secondary" data-radarrId=' + data.radarrId + ' data-audiolanguage=\'' + JSON.stringify(data.audio_language) + '\' data-title="' + data.title + '" data-languages_profile=' + data.profileId.id + ' data-hi="' + data.hearing_impaired + '" data-forced="' + data.forced + '"><i class="fas fa-wrench"></i></a>';
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -239,28 +203,20 @@
|
|||
$('#movies').on('click', '.edit_button', function (e) {
|
||||
e.preventDefault();
|
||||
$("#edit_movies_title_span").html($(this).data('title'));
|
||||
$("#edit_audio_language_span").html($(this).data('audiolanguage'));
|
||||
$("#edit_audio_language_span").empty();
|
||||
$.each($(this).data('audiolanguage'), function (i, item) {
|
||||
$("#edit_audio_language_span").append('<div class="badge badge-secondary">' + item['name'] + '</div> ');
|
||||
})
|
||||
$('#edit_radarrId').val($(this).data('radarrid'));
|
||||
|
||||
|
||||
$('#edit_languages_select').empty();
|
||||
if ('{{settings.general.single_language}}' === 'True') {
|
||||
$('#edit_languages_select').selectpicker({maxOptions: 1});
|
||||
}
|
||||
if ('{{settings.general.single_language}}' === 'True') {
|
||||
$('#edit_languages_select').append('<option value="None">None</option>');
|
||||
}
|
||||
$.each(enabledLanguages, function (i, item) {
|
||||
$('#edit_languages_select').append('<option value="' + item.code2 + '">' + item.name + '</option>');
|
||||
$('#edit_languages_select').append('<option value="None">None</option>');
|
||||
$.each(languagesProfiles, function (i, item) {
|
||||
$('#edit_languages_select').append('<option value="' + item.profileId + '">' + item.name + '</option>');
|
||||
});
|
||||
$("#edit_languages_select").selectpicker("refresh");
|
||||
var selected_languages = Array();
|
||||
$.each(Array.from($(this).data('languages')), function (i, item) {
|
||||
selected_languages.push(item.code2);
|
||||
});
|
||||
$('#edit_languages_select').selectpicker('val', selected_languages);
|
||||
$('#hi_checkbox').prop('checked', ($(this).data('hi') === 'True'));
|
||||
$('#edit_forced_select').val($(this).data('forced')).change();
|
||||
$('#edit_languages_select').selectpicker('val', (($(this).data('languages_profile')) ? $(this).data('languages_profile') : 'None'));
|
||||
|
||||
$('#editModal')
|
||||
.modal({
|
||||
|
@ -288,20 +244,11 @@
|
|||
});
|
||||
});
|
||||
|
||||
function getLanguages() {
|
||||
function getLanguagesProfiles() {
|
||||
$.ajax({
|
||||
url: "{{ url_for('api.languages') }}?enabled=false",
|
||||
url: "{{ url_for('api.languagesprofiles') }}",
|
||||
success: function (data) {
|
||||
availableLanguages = data;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getEnabledLanguages() {
|
||||
$.ajax({
|
||||
url: "{{ url_for('api.languages') }}?enabled=true",
|
||||
success: function (data) {
|
||||
enabledLanguages = data;
|
||||
languagesProfiles = data['data'];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -17,37 +17,16 @@
|
|||
<th></th>
|
||||
<th>Name</th>
|
||||
<th>Audio Language</th>
|
||||
<th>Subtitles Languages</th>
|
||||
<th>Hearing-Impaired</th>
|
||||
<th>Forced</th>
|
||||
<th>Languages Profile</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
|
||||
<nav id="edit_bar" class="navbar fixed-bottom navbar-dark bg-dark">
|
||||
<nav id="edit_bar" class="navbar fixed-bottom navbar-dark bg-dark justify-content-end">
|
||||
<div class="form-check form-check-inline">
|
||||
<div class="form-group" style="margin-bottom: 0px;">
|
||||
<label for="languages_select">Language(s): </label>
|
||||
<select class="selectpicker" id="languages_select" name="languages" title="No change" multiple></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<div class="form-group" style="margin-bottom: 0px;">
|
||||
<label for="hi_select">Hearing-Impaired: </label>
|
||||
<select class="selectpicker show-tick" id="hi_select" name="hi" title="No change" multiple>
|
||||
<option value="False">False</option>
|
||||
<option value="True">True</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<div class="form-group" style="margin-bottom: 0px;">
|
||||
<label for="forced_select">Forced: </label>
|
||||
<select class="selectpicker show-tick" id="forced_select" name="forced" title="No change" multiple>
|
||||
<option value="False">False</option>
|
||||
<option value="True">True</option>
|
||||
<option value="Both">Both</option>
|
||||
</select>
|
||||
<label for="languages_select">Languages Profile: </label>
|
||||
<select class="selectpicker" id="languages_select" name="languages"></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
|
@ -114,29 +93,20 @@
|
|||
return '<a href="' + "{{ url_for( 'movie', no='tempvalue' ) }}".replace("tempvalue", data.radarrId) + '">' + data.title + '</a>'
|
||||
}
|
||||
},
|
||||
{data: "audio_language.name"},
|
||||
{
|
||||
data: "languages",
|
||||
data: 'audio_language',
|
||||
render: function (data) {
|
||||
if (data && data !== 'None') {
|
||||
var languages = '';
|
||||
data.forEach(appendFunc);
|
||||
return languages;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
var audio_languages = '';
|
||||
data.forEach(appendFunc);
|
||||
return audio_languages;
|
||||
|
||||
function appendFunc(value) {
|
||||
languages = languages + '<span class="badge badge-secondary" data-toggle="tooltip" data-placement="right" title="' + value.name + '">' + value.code2 + '</span> ';
|
||||
audio_languages = audio_languages + '<span class="badge badge-secondary">' + value.name + '</span> ';
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
data: "hearing_impaired",
|
||||
className: "dt-center"
|
||||
},
|
||||
{
|
||||
data: "forced",
|
||||
data: "profileId.name",
|
||||
className: "dt-center"
|
||||
}
|
||||
]
|
||||
|
@ -180,19 +150,11 @@
|
|||
}
|
||||
});
|
||||
|
||||
if ('{{settings.general.single_language}}' === 'True') {
|
||||
$('#languages_select').selectpicker({maxOptions: 1});
|
||||
}
|
||||
$('#hi_select').selectpicker({maxOptions: 1});
|
||||
$('#forced_select').selectpicker({maxOptions: 1});
|
||||
|
||||
$('#save_button').on('click', function (e) {
|
||||
e.preventDefault();
|
||||
const values = {
|
||||
radarrid: table.rows({selected: true}).ids().toArray(),
|
||||
languages: $('#languages_select').val(),
|
||||
hi: $('#hi_select').val(),
|
||||
forced: $('#forced_select').val()
|
||||
languages: $('#languages_select').val()
|
||||
};
|
||||
|
||||
$.ajax({
|
||||
|
@ -208,9 +170,7 @@
|
|||
},
|
||||
success: function () {
|
||||
table.rows().deselect();
|
||||
$('#languages_select').selectpicker('val', '');
|
||||
$('#hi_select').selectpicker('val', '');
|
||||
$('#forced_select').selectpicker('val', '');
|
||||
$('#languages_select').selectpicker('val', 'None');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -218,11 +178,11 @@
|
|||
|
||||
function getEnabledLanguages() {
|
||||
$.ajax({
|
||||
url: "{{ url_for('api.languages') }}?enabled=true",
|
||||
url: "{{ url_for('api.languagesprofiles') }}",
|
||||
success: function (data) {
|
||||
$('#languages_select').append('<option value="None">None</option>');
|
||||
$.each(data, function (i, item) {
|
||||
$('#languages_select').append('<option value="' + item.code2 + '">' + item.name + '</option>');
|
||||
$.each(data['data'], function (i, item) {
|
||||
$('#languages_select').append('<option value="' + item.profileId + '">' + item.name + '</option>');
|
||||
});
|
||||
$("#languages_select").selectpicker("refresh");
|
||||
}
|
||||
|
|
|
@ -22,10 +22,8 @@
|
|||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Path Exist</th>
|
||||
<th>Audio Profile</th>
|
||||
<th>Subtitles Languages</th>
|
||||
<th>Hearing-Impaired</th>
|
||||
<th>Forced</th>
|
||||
<th>Audio Profile Languages</th>
|
||||
<th>Languages Profile</th>
|
||||
<th>Subtitles</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
|
@ -46,42 +44,19 @@
|
|||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-sm-3 text-right">
|
||||
Audio Profile
|
||||
Audio Profile Languages
|
||||
</div>
|
||||
<div class="form-group col-sm-8 pl-sm-0">
|
||||
<span id="edit_audio_language_span"></span>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div class="row">
|
||||
<div class="col-sm-3 text-right">
|
||||
Subtitles Language(s)
|
||||
Languages Profile
|
||||
</div>
|
||||
<div class="form-group col-sm-8 pl-sm-0">
|
||||
<select class="selectpicker" id="edit_languages_select" name="languages" multiple
|
||||
data-live-search="true"></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-3 text-right">
|
||||
Hearing-Impaired
|
||||
</div>
|
||||
<div class="form-group col-sm-1 pl-sm-0">
|
||||
<label class="custom-control custom-checkbox">
|
||||
<input type="checkbox" class="custom-control-input" id="hi_checkbox" name="hi">
|
||||
<span class="custom-control-label" for="hi_checkbox"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-3 text-right">
|
||||
Forced
|
||||
</div>
|
||||
<div class="form-group col-sm-8 pl-sm-0">
|
||||
<select class="selectpicker" id="edit_forced_select" name="forced">
|
||||
<option value="False">False</option>
|
||||
<option value="True">True</option>
|
||||
<option value="Both">Both</option>
|
||||
</select>
|
||||
<select class="selectpicker" id="edit_languages_select" name="languages"></select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -102,8 +77,7 @@
|
|||
{% block tail %}
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
getLanguages();
|
||||
getEnabledLanguages();
|
||||
getLanguagesProfiles();
|
||||
|
||||
events.on('event', function (event) {
|
||||
var event_json = JSON.parse(event);
|
||||
|
@ -176,29 +150,20 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
{data: "audio_language.name"},
|
||||
{
|
||||
data: "languages",
|
||||
data: 'audio_language',
|
||||
render: function (data) {
|
||||
if (data && data !== 'None') {
|
||||
var languages = '';
|
||||
data.forEach(appendFunc);
|
||||
return languages;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
var audio_languages = '';
|
||||
data.forEach(appendFunc);
|
||||
return audio_languages;
|
||||
|
||||
function appendFunc(value) {
|
||||
languages = languages + '<span class="badge badge-secondary" data-toggle="tooltip" data-placement="right" title="' + value.name + '">' + value.code2 + '</span> ';
|
||||
audio_languages = audio_languages + '<span class="badge badge-secondary">' + value.name + '</span> ';
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
data: "hearing_impaired",
|
||||
className: "dt-center"
|
||||
},
|
||||
{
|
||||
data: "forced",
|
||||
data: "profileId.name",
|
||||
className: "dt-center"
|
||||
},
|
||||
{
|
||||
|
@ -209,7 +174,8 @@
|
|||
var completed = data.episodeFileCount - data.episodeMissingCount;
|
||||
var completed_style = '';
|
||||
var completed_text = '';
|
||||
if (data.episodeFileCount && data.languages !== 'None') {
|
||||
console.log(data.profileId);
|
||||
if (data.episodeFileCount && data.profileId.id !== null) {
|
||||
completed_style = ' style="width: ' + completed / total * 100 + '%;"';
|
||||
completed_text = completed + '/' + total;
|
||||
}
|
||||
|
@ -219,7 +185,7 @@
|
|||
{
|
||||
data: null,
|
||||
render: function (data) {
|
||||
return '<a href="" class="edit_button badge badge-secondary" data-sonarrSeriesId=' + data.sonarrSeriesId + ' data-audiolanguage="' + data.audio_language.name + '" data-title="' + data.title + '" data-languages=' + JSON.stringify(data.languages) + ' data-hi="' + data.hearing_impaired + '" data-forced="' + data.forced + '"><i class="fas fa-wrench"></i></a>';
|
||||
return '<a href="" class="edit_button badge badge-secondary" data-sonarrSeriesId=' + data.sonarrSeriesId + ' data-audiolanguage=\'' + JSON.stringify(data.audio_language) + '\' data-title="' + data.title + '" data-languages_profile=' + data.profileId.id + ' data-hi="' + data.hearing_impaired + '" data-forced="' + data.forced + '"><i class="fas fa-wrench"></i></a>';
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -229,28 +195,20 @@
|
|||
$('#series').on('click', '.edit_button', function (e) {
|
||||
e.preventDefault();
|
||||
$("#edit_series_title_span").html($(this).data('title'));
|
||||
$("#edit_audio_language_span").html($(this).data('audiolanguage'));
|
||||
$("#edit_audio_language_span").empty();
|
||||
$.each($(this).data('audiolanguage'), function (i, item) {
|
||||
$("#edit_audio_language_span").append('<div class="badge badge-secondary">' + item['name'] + '</div> ');
|
||||
})
|
||||
$('#edit_sonarrSeriesId').val($(this).data('sonarrseriesid'));
|
||||
|
||||
|
||||
$('#edit_languages_select').empty();
|
||||
if ('{{settings.general.single_language}}' === 'True') {
|
||||
$('#edit_languages_select').selectpicker({maxOptions: 1});
|
||||
}
|
||||
if ('{{settings.general.single_language}}' === 'True') {
|
||||
$('#edit_languages_select').append('<option value="None">None</option>');
|
||||
}
|
||||
$.each(enabledLanguages, function (i, item) {
|
||||
$('#edit_languages_select').append('<option value="' + item.code2 + '">' + item.name + '</option>');
|
||||
$('#edit_languages_select').append('<option value="None">None</option>');
|
||||
$.each(languagesProfiles, function (i, item) {
|
||||
$('#edit_languages_select').append('<option value="' + item.profileId + '">' + item.name + '</option>');
|
||||
});
|
||||
$("#edit_languages_select").selectpicker("refresh");
|
||||
var selected_languages = Array();
|
||||
$.each(Array.from($(this).data('languages')), function (i, item) {
|
||||
selected_languages.push(item.code2);
|
||||
});
|
||||
$('#edit_languages_select').selectpicker('val', selected_languages);
|
||||
$('#hi_checkbox').prop('checked', ($(this).data('hi') === 'True'));
|
||||
$('#edit_forced_select').val($(this).data('forced')).change();
|
||||
$('#edit_languages_select').selectpicker('val', (($(this).data('languages_profile')) ? $(this).data('languages_profile') : 'None'));
|
||||
|
||||
$('#editModal')
|
||||
.modal({
|
||||
|
@ -278,20 +236,11 @@
|
|||
});
|
||||
});
|
||||
|
||||
function getLanguages() {
|
||||
function getLanguagesProfiles() {
|
||||
$.ajax({
|
||||
url: "{{ url_for('api.languages') }}?enabled=false",
|
||||
url: "{{ url_for('api.languagesprofiles') }}",
|
||||
success: function (data) {
|
||||
availableLanguages = data;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getEnabledLanguages() {
|
||||
$.ajax({
|
||||
url: "{{ url_for('api.languages') }}?enabled=true",
|
||||
success: function (data) {
|
||||
enabledLanguages = data;
|
||||
languagesProfiles = data['data'];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -16,38 +16,17 @@
|
|||
<tr>
|
||||
<th></th>
|
||||
<th>Name</th>
|
||||
<th>Audio Profile</th>
|
||||
<th>Subtitles Languages</th>
|
||||
<th>Hearing-Impaired</th>
|
||||
<th>Forced</th>
|
||||
<th>Audio Profile Languages</th>
|
||||
<th>Languages Profile</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
|
||||
<nav id="edit_bar" class="navbar fixed-bottom navbar-dark bg-dark">
|
||||
<nav id="edit_bar" class="navbar fixed-bottom navbar-dark bg-dark justify-content-end">
|
||||
<div class="form-check form-check-inline">
|
||||
<div class="form-group" style="margin-bottom: 0px;">
|
||||
<label for="languages_select">Language(s): </label>
|
||||
<select class="selectpicker" id="languages_select" name="languages" title="No change" multiple></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<div class="form-group" style="margin-bottom: 0px;">
|
||||
<label for="hi_select">Hearing-Impaired: </label>
|
||||
<select class="selectpicker show-tick" id="hi_select" name="hi" title="No change" multiple>
|
||||
<option value="False">False</option>
|
||||
<option value="True">True</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<div class="form-group" style="margin-bottom: 0px;">
|
||||
<label for="forced_select">Forced: </label>
|
||||
<select class="selectpicker show-tick" id="forced_select" name="forced" title="No change" multiple>
|
||||
<option value="False">False</option>
|
||||
<option value="True">True</option>
|
||||
<option value="Both">Both</option>
|
||||
</select>
|
||||
<label for="languages_select">Languages Profile: </label>
|
||||
<select class="selectpicker" id="languages_select" name="languages"></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
|
@ -114,25 +93,19 @@
|
|||
return '<a href="' + "{{ url_for( 'episodes', no='tempvalue' ) }}".replace("tempvalue", data.sonarrSeriesId) + '">' + data.title + '</a>'
|
||||
}
|
||||
},
|
||||
{data: "audio_language.name"},
|
||||
{
|
||||
data: "languages",
|
||||
data: 'audio_language',
|
||||
render: function (data) {
|
||||
if (data && data !== 'None') {
|
||||
var languages = '';
|
||||
data.forEach(appendFunc);
|
||||
return languages;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
var audio_languages = '';
|
||||
data.forEach(appendFunc);
|
||||
return audio_languages;
|
||||
|
||||
function appendFunc(value) {
|
||||
languages = languages + '<span class="badge badge-secondary" data-toggle="tooltip" data-placement="right" title="' + value.name + '">' + value.code2 + '</span> ';
|
||||
audio_languages = audio_languages + '<span class="badge badge-secondary">' + value.name + '</span> ';
|
||||
}
|
||||
}
|
||||
},
|
||||
{data: "hearing_impaired", className: "dt-center"},
|
||||
{data: "forced", className: "dt-center"}
|
||||
{data: "profileId.name", className: "dt-center"}
|
||||
]
|
||||
});
|
||||
|
||||
|
@ -174,19 +147,11 @@
|
|||
}
|
||||
});
|
||||
|
||||
if ('{{settings.general.single_language}}' === 'True') {
|
||||
$('#languages_select').selectpicker({maxOptions: 1});
|
||||
}
|
||||
$('#hi_select').selectpicker({maxOptions: 1});
|
||||
$('#forced_select').selectpicker({maxOptions: 1});
|
||||
|
||||
$('#save_button').on('click', function (e) {
|
||||
e.preventDefault();
|
||||
const values = {
|
||||
seriesid: table.rows({selected: true}).ids().toArray(),
|
||||
languages: $('#languages_select').val(),
|
||||
hi: $('#hi_select').val(),
|
||||
forced: $('#forced_select').val()
|
||||
languages: $('#languages_select').val()
|
||||
};
|
||||
|
||||
$.ajax({
|
||||
|
@ -202,9 +167,7 @@
|
|||
},
|
||||
success: function () {
|
||||
table.rows().deselect();
|
||||
$('#languages_select').selectpicker('val', '');
|
||||
$('#hi_select').selectpicker('val', '');
|
||||
$('#forced_select').selectpicker('val', '');
|
||||
$('#languages_select').selectpicker('val', 'None');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -212,11 +175,11 @@
|
|||
|
||||
function getEnabledLanguages() {
|
||||
$.ajax({
|
||||
url: "{{ url_for('api.languages') }}?enabled=true",
|
||||
url: "{{ url_for('api.languagesprofiles') }}",
|
||||
success: function (data) {
|
||||
$('#languages_select').append('<option value="None">None</option>');
|
||||
$.each(data, function (i, item) {
|
||||
$('#languages_select').append('<option value="' + item.code2 + '">' + item.name + '</option>');
|
||||
$.each(data['data'], function (i, item) {
|
||||
$('#languages_select').append('<option value="' + item.profileId + '">' + item.name + '</option>');
|
||||
});
|
||||
$("#languages_select").selectpicker("refresh");
|
||||
}
|
||||
|
|
|
@ -7,6 +7,10 @@
|
|||
.warning {
|
||||
color: red;
|
||||
}
|
||||
|
||||
table.dataTable tbody tr.selected a, table.dataTable tbody th.selected a, table.dataTable tbody td.selected a {
|
||||
color: revert;
|
||||
}
|
||||
</style>
|
||||
{% endblock page_head %}
|
||||
|
||||
|
@ -31,7 +35,7 @@
|
|||
{% block body %}
|
||||
<div class="container-fluid" style="padding-top: 3em;">
|
||||
<form class="form" name="settings_form" id="settings_form">
|
||||
<h4>Subtitles languages</h4>
|
||||
<h4>Subtitles Languages</h4>
|
||||
<hr/>
|
||||
<div class="row">
|
||||
<div class="col-sm-3 text-right">
|
||||
|
@ -49,7 +53,7 @@
|
|||
<br>
|
||||
<div class="row">
|
||||
<div class="col-sm-3 text-right">
|
||||
<b>Enabled Languages</b>
|
||||
<b>Languages Filter</b>
|
||||
</div>
|
||||
<div class="form-group col-sm-8 pl-sm-0">
|
||||
<select class="selectpicker" id="enabled_languages" name="enabled_languages" data-live-search="true" multiple></select>
|
||||
|
@ -57,6 +61,24 @@
|
|||
</div>
|
||||
<br>
|
||||
|
||||
<h4>Languages Profiles</h4>
|
||||
<hr/>
|
||||
<div class="row">
|
||||
<div class="col-sm-8">
|
||||
<table class="table table-striped" id="languages_profiles" style="width:100%;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Name</th>
|
||||
<th>Cutoff</th>
|
||||
<th>Languages</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
|
||||
<h4>Default Settings</h4>
|
||||
<hr>
|
||||
<div class="row">
|
||||
|
@ -74,38 +96,13 @@
|
|||
<div id="series_default_div">
|
||||
<div class="row">
|
||||
<div class="col-sm-4 text-right">
|
||||
<b>Languages</b>
|
||||
<b>Languages Profile Id</b>
|
||||
</div>
|
||||
<div class="form-group col-sm-8 pl-sm-0">
|
||||
<select class="selectpicker" id="settings-general-serie_default_language" name="settings-general-serie_default_language" multiple></select>
|
||||
<select class="selectpicker" id="settings-general-serie_default_profile" name="settings-general-serie_default_profile"></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-4 text-right">
|
||||
<b>Hearing-Impaired</b>
|
||||
</div>
|
||||
<div class="form-group col-sm-1">
|
||||
<label class="custom-control custom-checkbox">
|
||||
<input type="checkbox" class="custom-control-input" id="settings-general-serie_default_hi" name="settings-general-serie_default_hi">
|
||||
<span class="custom-control-label" for="settings-general-serie_default_hi"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-4 text-right">
|
||||
<b>Forced</b>
|
||||
</div>
|
||||
<div class="form-group col-sm-8 pl-sm-0">
|
||||
<select class="selectpicker" id="settings-general-serie_default_forced" name="settings-general-serie_default_forced">
|
||||
<option value="False">False</option>
|
||||
<option value="True">True</option>
|
||||
<option value="Both">Both</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
</div>
|
||||
<br>
|
||||
<div class="row">
|
||||
<div class="col-sm-3 text-right">
|
||||
<b>Movies Default Settings</b>
|
||||
|
@ -121,39 +118,140 @@
|
|||
<div id="movies_default_div">
|
||||
<div class="row">
|
||||
<div class="col-sm-4 text-right">
|
||||
<b>Languages</b>
|
||||
<b>Languages Profile Id</b>
|
||||
</div>
|
||||
<div class="form-group col-sm-8 pl-sm-0">
|
||||
<select class="selectpicker" id="settings-general-movie_default_language" name="settings-general-movie_default_language" multiple></select>
|
||||
<select class="selectpicker" id="settings-general-movie_default_profile" name="settings-general-movie_default_profile"></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-4 text-right">
|
||||
<b>Hearing-Impaired</b>
|
||||
</div>
|
||||
<div class="form-group col-sm-1">
|
||||
<label class="custom-control custom-checkbox">
|
||||
<input type="checkbox" class="custom-control-input" id="settings-general-movie_default_hi" name="settings-general-movie_default_hi">
|
||||
<span class="custom-control-label" for="settings-general-movie_default_hi"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-4 text-right">
|
||||
<b>Forced</b>
|
||||
</div>
|
||||
<div class="form-group col-sm-8 pl-sm-0">
|
||||
<select class="selectpicker" id="settings-general-movie_default_forced" name="settings-general-movie_default_forced">
|
||||
<option value="False">False</option>
|
||||
<option value="True">True</option>
|
||||
<option value="Both">Both</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="addModal" class="modal" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Add Languages Profile</h5><br>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<form class="form" name="add_form" id="add_form">
|
||||
<div class="modal-body">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-sm-3 text-right">
|
||||
Profile name
|
||||
</div>
|
||||
<div class="col-sm-8">
|
||||
<input type="text" class="form-control" id="add_profile_name" name="add_profile_name" value="">
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div class="row">
|
||||
<div class="col-sm-3 text-right">
|
||||
Languages
|
||||
</div>
|
||||
<div class="col-sm-8">
|
||||
<table class="table table-striped" id="add_languages_profiles" style="width:100%;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>Id</th>
|
||||
<th>Language</th>
|
||||
<th>Forced</th>
|
||||
<th>Hearing-Impaired</th>
|
||||
<th>Ignore If Matching Audio Track</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div class="row">
|
||||
<div class="col-sm-3 text-right">
|
||||
Language ID cutoff (ignore others if existing)
|
||||
</div>
|
||||
<div class="col-sm-8">
|
||||
<select class="selectpicker show-tick" id="add_language_cutoff" name="add_language_cutoff">
|
||||
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" id="add_save_button" class="btn btn-info">Add</button>
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="editModal" class="modal" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Edit Languages Profile</h5><br>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<form class="form" name="edit_form" id="edit_form">
|
||||
<div class="modal-body">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-sm-3 text-right">
|
||||
Profile name
|
||||
</div>
|
||||
<div class="col-sm-8">
|
||||
<input type="text" class="form-control" id="edit_profile_name" name="edit_profile_name" value="">
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div class="row">
|
||||
<div class="col-sm-3 text-right">
|
||||
Languages
|
||||
</div>
|
||||
<div class="col-sm-8">
|
||||
<table class="table table-striped" id="edit_languages_profiles" style="width:100%;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>Id</th>
|
||||
<th>Language</th>
|
||||
<th>Forced</th>
|
||||
<th>Hearing-Impaired</th>
|
||||
<th>Ignore If Matching Audio Track</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div class="row">
|
||||
<div class="col-sm-3 text-right">
|
||||
Language ID cutoff (ignore others if existing)
|
||||
</div>
|
||||
<div class="col-sm-8">
|
||||
<select class="selectpicker show-tick inline_select_edit" id="edit_language_cutoff" name="edit_language_cutoff">
|
||||
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<input type="hidden" id="edit_profile_id" value="" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" id="edit_save_button" class="btn btn-info">Edit</button>
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock body %}
|
||||
|
||||
{% block tail %}
|
||||
|
@ -173,57 +271,324 @@
|
|||
$('#save_button_checkmark').hide();
|
||||
$('#save_button').prop('disabled', true).css('cursor', 'not-allowed');
|
||||
|
||||
// Listen to selection change on enabled_languages select and keep series and movies default language select synced
|
||||
$('#enabled_languages').on('changed.bs.select', function(event, clickedIndex, isSelected, previousValue) {
|
||||
actual = $("#enabled_languages option:selected").map(function() {
|
||||
return $(this).val();
|
||||
}).get();
|
||||
|
||||
if (previousValue) {
|
||||
var added = actual.filter(x => !previousValue.includes(x));
|
||||
var removed = previousValue.filter(x => !actual.includes(x));
|
||||
|
||||
if (added.length > 0) {
|
||||
$('#settings-general-serie_default_language').append('<option value="' + added[0] + '">' + $("#enabled_languages option[value="+added[0]+"]").text() + '</option>');
|
||||
$('#settings-general-movie_default_language').append('<option value="' + added[0] + '">' + $("#enabled_languages option[value="+added[0]+"]").text() + '</option>');
|
||||
}
|
||||
if (removed.length > 0) {
|
||||
$("#settings-general-serie_default_language option[value="+removed[0]+"]").remove();
|
||||
$("#settings-general-movie_default_language option[value="+removed[0]+"]").remove();
|
||||
}
|
||||
} else {
|
||||
$(actual).each( function(i, item) {
|
||||
if ($('#settings-general-serie_default_language option[value='+item+']').length < 1) {
|
||||
$('#settings-general-serie_default_language').append('<option value="' + item + '">' + $("#enabled_languages option[value="+item+"]").text() + '</option>');
|
||||
$('#settings-general-movie_default_language').append('<option value="' + item + '">' + $("#enabled_languages option[value="+item+"]").text() + '</option>');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$('#settings-general-serie_default_language').selectpicker('val', {{settings.general.serie_default_language|safe}});
|
||||
$('#settings-general-movie_default_language').selectpicker('val', {{settings.general.movie_default_language|safe}});
|
||||
$("#settings-general-serie_default_language").selectpicker("refresh");
|
||||
$("#settings-general-movie_default_language").selectpicker("refresh");
|
||||
})
|
||||
|
||||
// Set Select input values
|
||||
$('#settings-general-serie_default_forced').val('{{settings.general.serie_default_forced}}').trigger('change');
|
||||
$('#settings-general-movie_default_forced').val('{{settings.general.movie_default_forced}}').trigger('change');
|
||||
$('#settings-general-serie_default_profile').val('{{settings.general.serie_default_profile}}').trigger('change');
|
||||
$('#settings-general-movie_default_profile').val('{{settings.general.movie_default_profile}}').trigger('change');
|
||||
$('.selectpicker').selectpicker('refresh')
|
||||
|
||||
// Listen to single language checkbox change to adapt languages menus
|
||||
$('#settings-general-single_language').on('change', function() {
|
||||
if ($(this).prop('checked')) {
|
||||
$('#settings-general-serie_default_language').selectpicker({maxOptions:1}).selectpicker('refresh');
|
||||
$('#settings-general-movie_default_language').selectpicker({maxOptions:1}).selectpicker('refresh');
|
||||
$('#settings-general-serie_default_language').selectpicker('val', $('#settings-general-serie_default_language').val()[0]);
|
||||
$('#settings-general-movie_default_language').selectpicker('val', $('#settings-general-movie_default_language').val()[0]);
|
||||
} else {
|
||||
$('#settings-general-serie_default_language').selectpicker({maxOptions:false}).selectpicker('refresh');
|
||||
$('#settings-general-movie_default_language').selectpicker({maxOptions:false}).selectpicker('refresh');
|
||||
}
|
||||
// Set Checkbox input values
|
||||
$('#settings-general-single_language').prop('checked', {{'true' if settings.general.getboolean('single_language') else 'false'}}).trigger('change');
|
||||
$('#settings-general-serie_default_enabled').prop('checked', {{'true' if settings.general.getboolean('serie_default_enabled') else 'false'}}).trigger('change');
|
||||
$('#settings-general-movie_default_enabled').prop('checked', {{'true' if settings.general.getboolean('movie_default_enabled') else 'false'}}).trigger('change');
|
||||
|
||||
var table = $('#languages_profiles').DataTable({
|
||||
dom: 'Bfrtip',
|
||||
select: {
|
||||
style: 'single'
|
||||
},
|
||||
language: {
|
||||
zeroRecords: 'No Languages Profiles'
|
||||
},
|
||||
searching: false,
|
||||
ordering: false,
|
||||
lengthChange: true,
|
||||
responsive: false,
|
||||
paging: false,
|
||||
info: false,
|
||||
processing: true,
|
||||
serverSide: false,
|
||||
ajax: {
|
||||
url: "{{ url_for('api.languagesprofiles') }}",
|
||||
type: 'GET'
|
||||
},
|
||||
columns: [
|
||||
{ data: 'profileId',
|
||||
visible: false
|
||||
},
|
||||
{ data: 'name' },
|
||||
{ data: 'cutoff',
|
||||
visible: false
|
||||
},
|
||||
{ data: 'items',
|
||||
render: function(data, type, row) {
|
||||
var languages = '';
|
||||
$(eval(data)).each(function (index, value) {
|
||||
if (value.forced == 'True') {
|
||||
languages += '<span class="badge badge-secondary"' + ((row.cutoff == '65535' || value.id == row.cutoff) ? ' data-toggle="tooltip" title="Ignore others if this one is available" style="background-color:#911f93;"' : '') + '>' + value.language + ':forced' + ((value.audio_exclude === "True") ? ' <i class="fa fa-ban" data-toggle="tooltip" title="Ignore if matching audio track available"></i>' : '') + '</span> ';
|
||||
} else if (value.hi == 'True') {
|
||||
languages += '<span class="badge badge-secondary"' + ((row.cutoff == '65535' || value.id == row.cutoff) ? ' data-toggle="tooltip" title="Ignore others if this one is available" style="background-color:#911f93;"' : '') + '>' + value.language + ':hi' + ((value.audio_exclude === "True") ? ' <i class="fa fa-ban" data-toggle="tooltip" title="Ignore if matching audio track available"></i>' : '') + '</span> ';
|
||||
} else {
|
||||
languages += '<span class="badge badge-secondary"' + ((row.cutoff == '65535' || value.id == row.cutoff) ? ' data-toggle="tooltip" title="Ignore others if this one is available" style="background-color:#911f93;"' : '') + '>' + value.language + ((value.audio_exclude === "True") ? ' <i class="fa fa-ban" data-toggle="tooltip" title="Ignore if matching audio track available"></i>' : '') + '</span> ';
|
||||
}
|
||||
});
|
||||
return languages;
|
||||
}
|
||||
}
|
||||
],
|
||||
buttons: [{
|
||||
text: 'Add',
|
||||
action: function () {
|
||||
if ($('#add_languages_profiles').DataTable().rows().length) {
|
||||
$('#add_languages_profiles').DataTable().clear();
|
||||
}
|
||||
$('#add_profile_name').val('');
|
||||
$('#add_languages_profiles').DataTable().destroy();
|
||||
var table_add = $('#add_languages_profiles').DataTable({
|
||||
dom: 'Bfrtip',
|
||||
select: {
|
||||
style: 'single'
|
||||
},
|
||||
language: {
|
||||
zeroRecords: 'No Languages In This Profile'
|
||||
},
|
||||
searching: false,
|
||||
ordering: false,
|
||||
lengthChange: false,
|
||||
responsive: false,
|
||||
paging: false,
|
||||
info: false,
|
||||
data: null,
|
||||
columns: [
|
||||
{ data: 'id',
|
||||
visible: false
|
||||
},
|
||||
{ data: 'id' },
|
||||
{ data: 'language',
|
||||
render: function (data) {
|
||||
var enabled_languages = Array();
|
||||
$('#enabled_languages option:selected').each(function(){
|
||||
enabled_languages.push([$(this).val(), $(this).text()]);
|
||||
});
|
||||
|
||||
var html_dropdown = '<select class="selectpicker show-tick inline_select_add" data-width="fit">';
|
||||
for (i = 0; i < enabled_languages.length; i++) {
|
||||
html_dropdown += '<option value="' + enabled_languages[i][0] + '"' + ((data == enabled_languages[i][0]) ? ' selected="selected"' : '') + '>' + enabled_languages[i][1] + '</option>';
|
||||
}
|
||||
html_dropdown += '</select>';
|
||||
|
||||
return html_dropdown;
|
||||
}
|
||||
},
|
||||
{ data: 'forced',
|
||||
render: function(data) {
|
||||
return '<select class="selectpicker show-tick inline_select_add" data-width="fit"><option value="True"' + ((data === 'True') ? ' selected="selected"' : '') + '>True</option><option value="False"' + ((data === 'False') ? ' selected="selected"' : '') + '>False</option></select>';
|
||||
}
|
||||
},
|
||||
{ data: 'hi',
|
||||
render: function(data) {
|
||||
return '<select class="selectpicker show-tick inline_select_add" data-width="fit"><option value="True"' + ((data === 'True') ? ' selected="selected"' : '') + '>True</option><option value="False"' + ((data === 'False') ? ' selected="selected"' : '') + '>False</option></select>';
|
||||
}
|
||||
},
|
||||
{ data: 'audio_exclude',
|
||||
render: function(data) {
|
||||
return '<select class="selectpicker show-tick inline_select_add" data-width="fit"><option value="True"' + ((data === 'True') ? ' selected="selected"' : '') + '>True</option><option value="False"' + ((data === 'False') ? ' selected="selected"' : '') + '>False</option></select>';
|
||||
}
|
||||
}
|
||||
],
|
||||
buttons: [{
|
||||
text: 'Add',
|
||||
action: function () {
|
||||
var language_id = 0;
|
||||
if (table_add.rows().data().toArray().length) {
|
||||
language_id = Math.max(...table_add.column(0).data().toArray());
|
||||
}
|
||||
language_id++;
|
||||
table_add.row.add({
|
||||
id: language_id,
|
||||
language: '',
|
||||
forced: 'False',
|
||||
hi: 'False',
|
||||
audio_exclude: 'False'
|
||||
}).draw();
|
||||
$('.inline_select_add').selectpicker('refresh');
|
||||
|
||||
$('.inline_select_add.selectpicker').on('changed.bs.select', function () {
|
||||
table_add.row( $(this).closest('tr') ).cell( $(this).closest('td') ).data($(this).val());
|
||||
$('.inline_select_add').selectpicker('refresh');
|
||||
table_add.draw();
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
extend: 'selected',
|
||||
text: 'Delete',
|
||||
action: function () {
|
||||
table_add.row( { selected: true } ).remove().draw();
|
||||
}
|
||||
}]
|
||||
});
|
||||
$('#addModal').modal('show');
|
||||
}
|
||||
},
|
||||
{
|
||||
extend: 'selected',
|
||||
text: 'Edit',
|
||||
action: function () {
|
||||
$('#edit_profile_name').val(table.row( { selected: true } ).data()['name']);
|
||||
var items = $.parseJSON(table.row( { selected: true } ).data()['items']);
|
||||
$('#edit_languages_profiles').DataTable().destroy();
|
||||
var table_edit = $('#edit_languages_profiles').DataTable({
|
||||
dom: 'Bfrtip',
|
||||
select: {
|
||||
style: 'single'
|
||||
},
|
||||
language: {
|
||||
zeroRecords: 'No Languages In This Profile'
|
||||
},
|
||||
searching: false,
|
||||
ordering: false,
|
||||
lengthChange: false,
|
||||
responsive: false,
|
||||
paging: false,
|
||||
info: false,
|
||||
data: items,
|
||||
columns: [
|
||||
{ data: 'id',
|
||||
visible: false
|
||||
},
|
||||
{ data: 'id' },
|
||||
{ data: 'language',
|
||||
render: function (data) {
|
||||
var enabled_languages = Array();
|
||||
$('#enabled_languages option:selected').each(function(){
|
||||
enabled_languages.push([$(this).val(), $(this).text()]);
|
||||
});
|
||||
|
||||
var html_dropdown = '<select class="selectpicker show-tick inline_select_edit" data-width="fit">';
|
||||
for (i = 0; i < enabled_languages.length; i++) {
|
||||
html_dropdown += '<option value="' + enabled_languages[i][0] + '"' + ((data == enabled_languages[i][0]) ? ' selected="selected"' : '') + '>' + enabled_languages[i][1] + '</option>';
|
||||
}
|
||||
html_dropdown += '</select>'
|
||||
|
||||
return html_dropdown;
|
||||
}
|
||||
},
|
||||
{ data: 'forced',
|
||||
render: function(data) {
|
||||
return '<select class="selectpicker show-tick inline_select_edit" data-width="fit"><option value="True"' + ((data === 'True') ? ' selected="selected"' : '') + '>True</option><option value="False"' + ((data === 'False') ? ' selected="selected"' : '') + '>False</option></select>';
|
||||
}
|
||||
},
|
||||
{ data: 'hi',
|
||||
render: function(data) {
|
||||
return '<select class="selectpicker show-tick inline_select_edit" data-width="fit"><option value="True"' + ((data === 'True') ? ' selected="selected"' : '') + '>True</option><option value="False"' + ((data === 'False') ? ' selected="selected"' : '') + '>False</option></select>';
|
||||
}
|
||||
},
|
||||
{ data: 'audio_exclude',
|
||||
render: function(data) {
|
||||
return '<select class="selectpicker show-tick inline_select_edit" data-width="fit"><option value="True"' + ((data === 'True') ? ' selected="selected"' : '') + '>True</option><option value="False"' + ((data === 'False') ? ' selected="selected"' : '') + '>False</option></select>';
|
||||
}
|
||||
}
|
||||
],
|
||||
buttons: [{
|
||||
text: 'Add',
|
||||
action: function () {
|
||||
var language_id = 0;
|
||||
if (table_edit.rows().data().toArray().length) {
|
||||
language_id = Math.max(...table_edit.column(0).data().toArray());
|
||||
}
|
||||
language_id++;
|
||||
table_edit.row.add({
|
||||
id: language_id,
|
||||
language: '',
|
||||
forced: 'False',
|
||||
hi: 'False',
|
||||
audio_exclude: 'False'
|
||||
}).draw();
|
||||
$('.inline_select_edit').selectpicker('refresh');
|
||||
|
||||
$('.inline_select_edit.selectpicker').on('changed.bs.select', function () {
|
||||
table_edit.row( $(this).closest('tr') ).cell( $(this).closest('td') ).data($(this).val());
|
||||
$('.inline_select_edit').selectpicker('refresh');
|
||||
table_edit.draw();
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
extend: 'selected',
|
||||
text: 'Delete',
|
||||
action: function () {
|
||||
table_edit.row( { selected: true } ).remove().draw();
|
||||
}
|
||||
}]
|
||||
});
|
||||
$('#edit_language_cutoff').val(table.row( { selected: true } ).data()['cutoff']);
|
||||
$('#edit_profile_id').val(table.row( { selected: true } ).data()['profileId']);
|
||||
$('.inline_select_edit').selectpicker('refresh');
|
||||
$('#editModal').modal('show');
|
||||
|
||||
$('.inline_select_edit.selectpicker').on('changed.bs.select', function () {
|
||||
table_edit.row( $(this).closest('tr') ).cell( $(this).closest('td') ).data($(this).val());
|
||||
$('.inline_select_edit').selectpicker('refresh');
|
||||
table_edit.draw();
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
extend: 'selected',
|
||||
text: 'Delete',
|
||||
action: function () {
|
||||
table.row( { selected: true } ).remove().draw();
|
||||
$('#settings_form').trigger('change');
|
||||
}
|
||||
}]
|
||||
});
|
||||
|
||||
$('#add_profile_name').on('input', function() {
|
||||
if ($('#add_languages_profiles').DataTable().rows().count() && $('#add_profile_name').val()) {
|
||||
$('#add_save_button').prop('disabled', false).css('cursor', 'auto');
|
||||
} else {
|
||||
$('#add_save_button').prop('disabled', true).css('cursor', 'not-allowed');
|
||||
}
|
||||
})
|
||||
|
||||
$('#add_languages_profiles').DataTable().on( 'draw', function () {
|
||||
if ($('#add_languages_profiles').DataTable().rows().count() && $('#add_profile_name').val()) {
|
||||
$('#add_save_button').prop('disabled', false).css('cursor', 'auto');
|
||||
} else {
|
||||
$('#add_save_button').prop('disabled', true).css('cursor', 'not-allowed');
|
||||
}
|
||||
|
||||
var previousValue = $("#add_language_cutoff").val();
|
||||
$("#add_language_cutoff").empty();
|
||||
$('#add_language_cutoff').append('<option value="">Disabled</option>');
|
||||
$('#add_language_cutoff').append('<option value="65535">Any of them</option>');
|
||||
|
||||
var ids = $('#add_languages_profiles').DataTable().rows().data().pluck( 'id' ).toArray();
|
||||
$(ids).each( function(i, item) {
|
||||
$('#add_language_cutoff').append('<option value="' + item + '">' + item + '</option>');
|
||||
});
|
||||
$("#add_language_cutoff").val(previousValue);
|
||||
$("#add_language_cutoff").selectpicker("refresh");
|
||||
} );
|
||||
|
||||
$('#edit_profile_name').on('input', function() {
|
||||
if ($('#edit_languages_profiles').DataTable().rows().count() && $('#edit_profile_name').val()) {
|
||||
$('#edit_save_button').prop('disabled', false).css('cursor', 'auto');
|
||||
} else {
|
||||
$('#edit_save_button').prop('disabled', true).css('cursor', 'not-allowed');
|
||||
}
|
||||
})
|
||||
|
||||
$('#edit_languages_profiles').DataTable().on( 'draw', function () {
|
||||
if ($('#edit_languages_profiles').DataTable().rows().count() && $('#edit_profile_name').val()) {
|
||||
$('#edit_save_button').prop('disabled', false).css('cursor', 'auto');
|
||||
} else {
|
||||
$('#edit_save_button').prop('disabled', true).css('cursor', 'not-allowed');
|
||||
}
|
||||
|
||||
var previousValue = $("#edit_language_cutoff").val();
|
||||
$("#edit_language_cutoff").empty();
|
||||
$('#edit_language_cutoff').append('<option value="">Disabled</option>');
|
||||
$('#edit_language_cutoff').append('<option value="65535">Any of them</option>');
|
||||
|
||||
var ids = $('#edit_languages_profiles').DataTable().rows().data().pluck( 'id' ).toArray();
|
||||
$(ids).each( function(i, item) {
|
||||
$('#edit_language_cutoff').append('<option value="' + item + '">' + item + '</option>');
|
||||
});
|
||||
$("#edit_language_cutoff").val(previousValue);
|
||||
$("#edit_language_cutoff").selectpicker("refresh");
|
||||
} );
|
||||
|
||||
// Hide *_div on default-enabled change
|
||||
$('#settings-general-serie_default_enabled').on('change', function() {
|
||||
if ($(this).prop('checked')) {
|
||||
|
@ -241,28 +606,55 @@
|
|||
}
|
||||
});
|
||||
|
||||
// Set Checkbox input values
|
||||
$('#settings-general-single_language').prop('checked', {{'true' if settings.general.getboolean('single_language') else 'false'}}).trigger('change');
|
||||
$('#settings-general-serie_default_enabled').prop('checked', {{'true' if settings.general.getboolean('serie_default_enabled') else 'false'}}).trigger('change');
|
||||
$('#settings-general-serie_default_hi').prop('checked', {{'true' if settings.general.getboolean('serie_default_hi') else 'false'}}).trigger('change');
|
||||
$('#settings-general-movie_default_enabled').prop('checked', {{'true' if settings.general.getboolean('movie_default_enabled') else 'false'}}).trigger('change');
|
||||
$('#settings-general-movie_default_hi').prop('checked', {{'true' if settings.general.getboolean('movie_default_hi') else 'false'}}).trigger('change');
|
||||
// Listen to profiles change and populate the default dropdowns accordingly
|
||||
$('#languages_profiles').DataTable().on( 'draw', function () {
|
||||
if ($("#settings-general-serie_default_profile").length > 1) {
|
||||
var previousValueSerie = $("#settings-general-serie_default_profile").val();
|
||||
} else {
|
||||
var previousValueSerie = '{{settings.general.serie_default_profile}}';
|
||||
}
|
||||
if ($("#settings-general-movie_default_profile").length > 1) {
|
||||
var previousValueMovie = $("#settings-general-movie_default_profile").val();
|
||||
} else {
|
||||
var previousValueMovie = '{{settings.general.movie_default_profile}}';
|
||||
}
|
||||
|
||||
$("#settings-general-serie_default_profile").empty();
|
||||
$("#settings-general-movie_default_profile").empty();
|
||||
$('#settings-general-serie_default_profile').append('<option value="">None</option>');
|
||||
$('#settings-general-movie_default_profile').append('<option value="">None</option>');
|
||||
|
||||
var ids = $('#languages_profiles').DataTable().rows().data().toArray();
|
||||
$(ids).each( function(i, item) {
|
||||
$('#settings-general-serie_default_profile').append('<option value="' + item.profileId + '">' + item.name + '</option>');
|
||||
$('#settings-general-movie_default_profile').append('<option value="' + item.profileId + '">' + item.name + '</option>');
|
||||
});
|
||||
$("#settings-general-serie_default_profile").val(previousValueSerie);
|
||||
$("#settings-general-movie_default_profile").val(previousValueMovie);
|
||||
$("#settings-general-serie_default_profile").selectpicker("refresh");
|
||||
$("#settings-general-movie_default_profile").selectpicker("refresh");
|
||||
} );
|
||||
|
||||
$('#save_button').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
$('#save_button').on('click', function() {
|
||||
var formdata = new FormData(document.getElementById("settings_form"));
|
||||
|
||||
// Make sure empty default languages select are send (bug in bootstrap-select)
|
||||
if (formdata.get('settings-general-serie_default_language') == null) {
|
||||
formdata.append('settings-general-serie_default_language', null)
|
||||
if (formdata.get('settings-general-serie_default_profile') == null) {
|
||||
formdata.append('settings-general-serie_default_profile', null)
|
||||
}
|
||||
if (formdata.get('settings-general-movie_default_language') == null) {
|
||||
formdata.append('settings-general-movie_default_language', null)
|
||||
if (formdata.get('settings-general-movie_default_profile') == null) {
|
||||
formdata.append('settings-general-movie_default_profile', null)
|
||||
}
|
||||
|
||||
// Make sure all checkbox input are sent with true/false value
|
||||
$('input[type=checkbox]').each(function () {
|
||||
formdata.set($(this).prop('id'), $(this).prop('checked'));
|
||||
});
|
||||
|
||||
formdata.append('languages_profiles', JSON.stringify(table.rows().data().toArray()));
|
||||
|
||||
$.ajax({
|
||||
url: "{{ url_for('api.savesettings') }}",
|
||||
data: formdata,
|
||||
|
@ -282,42 +674,87 @@
|
|||
});
|
||||
});
|
||||
|
||||
$('#add_save_button').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
var table_add = $('#add_languages_profiles').DataTable();
|
||||
var items = [];
|
||||
table_add.rows().every( function (row) {
|
||||
var row_item = table_add.cells( row, '' ).render( 'display' );
|
||||
var language = $(row_item[2]).filter('select').selectpicker().val();
|
||||
var forced = $(row_item[3]).filter('select').val();
|
||||
var hi = $(row_item[4]).filter('select').val();
|
||||
var audio_exclude = $(row_item[5]).filter('select').val();
|
||||
items.push({
|
||||
id: row_item[1],
|
||||
language: language,
|
||||
forced: forced,
|
||||
hi: hi,
|
||||
audio_exclude: audio_exclude
|
||||
});
|
||||
})
|
||||
|
||||
if (table.rows().data().toArray().length === 0) {
|
||||
var languages_profile_id = 0;
|
||||
} else {
|
||||
var languages_profile_id = Math.max(...table.column(0).data().toArray());
|
||||
}
|
||||
languages_profile_id++
|
||||
table.row.add({
|
||||
profileId: languages_profile_id,
|
||||
name: $('#add_profile_name').val(),
|
||||
cutoff: $('#add_language_cutoff').val(),
|
||||
items: JSON.stringify(items)
|
||||
}).draw();
|
||||
$('#addModal').modal('hide');
|
||||
$('#settings_form').trigger('change');
|
||||
});
|
||||
|
||||
$('#edit_save_button').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
var table_edit = $('#edit_languages_profiles').DataTable();
|
||||
var items = [];
|
||||
table_edit.rows().every( function (row) {
|
||||
var row_item = table_edit.cells( row, '' ).render( 'display' );
|
||||
var language = $(row_item[2]).filter('select').selectpicker().val();
|
||||
var forced = $(row_item[3]).filter('select').val();
|
||||
var hi = $(row_item[4]).filter('select').val();
|
||||
var audio_exclude = $(row_item[5]).filter('select').val();
|
||||
items.push({
|
||||
id: row_item[1],
|
||||
language: language,
|
||||
forced: forced,
|
||||
hi: hi,
|
||||
audio_exclude: audio_exclude
|
||||
});
|
||||
})
|
||||
table.row( { selected: true } ).data({
|
||||
profileId: parseInt($('#edit_profile_id').val()),
|
||||
name: $('#edit_profile_name').val(),
|
||||
cutoff: $('#edit_language_cutoff').val(),
|
||||
items: JSON.stringify(items)
|
||||
});
|
||||
$('#editModal').modal('hide');
|
||||
$('#settings_form').trigger('change');
|
||||
});
|
||||
|
||||
function getLanguages() {
|
||||
$.ajax({
|
||||
url: "{{ url_for('api.languages') }}?enabled=false",
|
||||
success: function (data) {
|
||||
$('#enabled_languages').empty();
|
||||
$.each(data, function (i, item) {
|
||||
$('#enabled_languages').append('<option value="' + item.code2 + '">' + item.name + '</option>');
|
||||
$('#enabled_languages').append('<option value="' + item.code2 + '"' + ((item.enabled) ? ' selected="selected"' : '') + '>' + item.name + '</option>');
|
||||
});
|
||||
getEnabledLanguages();
|
||||
$("#enabled_languages").selectpicker("refresh");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getEnabledLanguages() {
|
||||
$.ajax({
|
||||
url: "{{ url_for('api.languages') }}?enabled=true",
|
||||
success: function (data) {
|
||||
let optArr = [];
|
||||
$.each(data, function (i, item) {
|
||||
optArr.push(item.code2);
|
||||
});
|
||||
$('#enabled_languages').selectpicker('val', optArr);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// monitor changes to the settings_form
|
||||
setTimeout(
|
||||
function()
|
||||
{
|
||||
$('#settings_form').on('change', function() {
|
||||
form_changed = true;
|
||||
$('#save_button').prop('disabled', false).css('cursor', 'auto');
|
||||
})
|
||||
}, 1000);
|
||||
$('#settings_form').on('change', function() {
|
||||
form_changed = true;
|
||||
$('#save_button').prop('disabled', false).css('cursor', 'auto');
|
||||
})
|
||||
});
|
||||
</script>
|
||||
{% endblock tail %}
|
||||
|
|
|
@ -202,7 +202,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" id="add_save_button" class="btn btn-info">Save</button>
|
||||
<button type="submit" id="add_save_button" class="btn btn-info">Add</button>
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
|
||||
</div>
|
||||
</form>
|
||||
|
@ -242,7 +242,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" id="edit_save_button" class="btn btn-info">Save</button>
|
||||
<button type="submit" id="edit_save_button" class="btn btn-info">Edit</button>
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
@ -215,7 +215,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" id="add_save_button" class="btn btn-info">Save</button>
|
||||
<button type="submit" id="add_save_button" class="btn btn-info">Add</button>
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
|
||||
</div>
|
||||
</form>
|
||||
|
@ -255,7 +255,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" id="edit_save_button" class="btn btn-info">Save</button>
|
||||
<button type="submit" id="edit_save_button" class="btn btn-info">Edit</button>
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
@ -422,19 +422,19 @@
|
|||
<label>Enable the automatic subtitles synchronization after downloading a subtitles.</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-4 text-right">
|
||||
<b>Subtitles synchronization debugging</b>
|
||||
</div>
|
||||
<div class="form-group col-sm-8">
|
||||
<label class="custom-control custom-checkbox">
|
||||
<input type="checkbox" class="custom-control-input" id="settings-subsync-debug" name="settings-subsync-debug">
|
||||
<span class="custom-control-label" for="settings-subsync-debug"></span>
|
||||
</label>
|
||||
<label>Do not actually sync the subtitles but generate a .tar.gz file to be able to open an issue for ffsubsync. This file will reside alongside the media file.</label>
|
||||
</div>
|
||||
</div>
|
||||
<div id="subsync_div">
|
||||
<div class="row">
|
||||
<div class="col-sm-4 text-right">
|
||||
<b>Subtitles synchronization debugging</b>
|
||||
</div>
|
||||
<div class="form-group col-sm-8">
|
||||
<label class="custom-control custom-checkbox">
|
||||
<input type="checkbox" class="custom-control-input" id="settings-subsync-debug" name="settings-subsync-debug">
|
||||
<span class="custom-control-label" for="settings-subsync-debug"></span>
|
||||
</label>
|
||||
<label>Do not actually sync the subtitles but generate a .tar.gz file to be able to open an issue for ffsubsync. This file will reside alongside the media file.</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-4 text-right">
|
||||
<b>Subtitles synchronization score threshold for series</b>
|
||||
|
|
Loading…
Reference in New Issue