You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
bazarr/views/movie.html

1521 lines
59 KiB

{% extends '_main.html' %}
{% block title %}Movie - Bazarr{% endblock %}
{% block page_head %}
<style>
#movieFanart {
background-repeat: no-repeat;
background-size: cover;
background-position: top center;
box-sizing: initial;
margin-left: -32px;
margin-top: -5px;
padding: 2em;
}
#movieDetails {
padding: 30px;
background: rgba(0, 0, 0, 0.7);
color: white;
margin: -32px;
}
#moviePoster {
max-height: 250px;
}
h1 {
color: white;
}
span {
margin-right: 0.5em;
}
.badge {
display: inline-block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
vertical-align: middle;
}
.dropdown-menu li.disabled {
cursor: not-allowed;
}
</style>
{% endblock page_head %}
{% block bcleft %}
<div class="">
<button class="btn btn-outline" id="scan_button">
<div><i class="fas fa-sync align-top text-themecolor text-center font-20" aria-hidden="true"></i></div>
<div class="align-bottom text-themecolor small text-center">Scan Disk</div>
</button>
<button class="btn btn-outline" id="search_button">
<div><i class="fas fa-search align-top text-themecolor text-center font-20" aria-hidden="true"></i></div>
<div class="align-bottom text-themecolor small text-center">Search</div>
</button>
<button class="btn btn-outline" id="manual_button">
<div><i class="fas fa-user align-top text-themecolor text-center font-20" aria-hidden="true"></i></div>
<div class="align-bottom text-themecolor small text-center">Manual</div>
</button>
<button class="btn btn-outline" id="upload_button">
<div><i class=" fas fa-cloud-upload-alt align-top text-themecolor text-center font-20" aria-hidden="true"></i></div>
<div class="align-bottom text-themecolor small text-center">Upload</div>
</button>
<button class="btn btn-outline" id="history_button">
<div><i class="fas fa-history align-top text-themecolor text-center font-20" aria-hidden="true"></i></div>
<div class="align-bottom text-themecolor small text-center">History</div>
</button>
<button class="btn btn-outline" id="tools_button">
<div><i class="fa fa-briefcase align-top text-themecolor text-center font-20" aria-hidden="true"></i></div>
<div class="align-bottom text-themecolor small text-center">Tools</div>
</button>
</div>
{% endblock bcleft %}
{% block bcright %}
<div class="d-flex m-t-5 justify-content-end">
<button class="btn btn-outline" id="edit_button">
<div><i class="fas fa-wrench align-top text-themecolor text-center font-20" aria-hidden="true"></i></div>
<div class="align-bottom text-themecolor small text-center">Edit Movie</div>
</button>
</div>
{% endblock bcright %}
{% block body %}
<div class="container-fluid" id="movieFanart">
<div class="row justify-content-md-center" id="movieDetails">
<div class="col-sm-auto" id="moviePosterColumn">
<img id="moviePoster" src="">
</div>
<div class="col" id="movieDetailsColumn">
<div class="container-fluid">
<div class="row">
<h1><span id="movieTitle"></span></h1>
<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"></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="movieSubtitlesLanguagesProfile" class="badge badge-secondary"></span></h5>
</div>
<div class="row">
<span id="movieDescription"></span>
</div>
</div>
</div>
</div>
</div>
<!-- Bread crumb and right sidebar toggle -->
<!-- ============================================================== -->
<table id="movieSubtitles" class="table table-striped" style="width:100%">
<thead>
<tr>
<th>Subtitles Path</th>
<th>Language(s)</th>
<th></th>
</tr>
</thead>
</table>
<br>
<h5 style="font-weight: 500;">Missing Subtitles</h5>
<span id="missingSubtitles"></span>
<div id="manualSearchModal" class="modal" tabindex="-1" role="dialog" data-backdrop="static">
<div class="modal-dialog modal-xl" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title"><span id="movie_title_span"></span></h5><br>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<h6>Movie path: <span id="movie_path_span" class="badge badge-secondary"></span>
<br>Scenename: <span id="movie_scenename_span" class="badge badge-secondary"></span></h6>
<div class="container-fluid" style="padding:0px;">
<table id="search_result" class="table table-striped" style="width:100%">
<thead>
<tr>
<th style="text-align: left;">Score:</th>
<th></th>
<th style="text-align: left;">Provider:</th>
<th style="text-align: left;">Matching:</th>
<th style="text-align: left;">Releases:</th>
<th style="text-align: left;">Uploader:</th>
<th></th>
</tr>
</thead>
</table>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
</div>
</div>
</div>
</div>
<div id="uploadModal" 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"><span id="upload_movie_title_span"></span></h5><br>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<form class="form" name="upload_form" id="upload_form">
<div class="modal-body">
<div class="container-fluid">
<div class="row">
<div class="col-sm-2 text-right">
Language
</div>
<div class="form-group col-sm-8 pl-sm-0">
<select class="selectpicker" id="manual_language_select" name="language"></select>
</div>
</div>
<div class="row">
<div class="col-sm-2 text-right">
Forced
</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="forced_checkbox" name="forced">
<span class="custom-control-label" for="forced_checkbox"></span>
</label>
</div>
</div>
<div class="row">
<div class="col-sm-2 text-right">
File
</div>
<div class="form-group col-sm-7 pl-sm-0">
<div class="custom-file">
<input type="file" accept=".srt" class="custom-file-input" id="upload" name="upload">
<label class="custom-file-label" for="upload">Choose file</label>
</div>
</div>
</div>
</div>
<input type="hidden" id="upload_moviePath" name="moviePath" value="" />
<input type="hidden" id="upload_sceneName" name="sceneName" value="" />
<input type="hidden" id="upload_radarrId" name="radarrId" value="" />
<input type="hidden" id="upload_title" name="title" value="" />
<input type="hidden" id="upload_audioLanguage" name="audioLanguage" value="" />
</div>
<div class="modal-footer">
<span id="upload_save_button_span"><button type="submit" id="upload_save_button" class="btn btn-info">Save</button></span>
<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"><span id="edit_movie_title_span"></span></h5><br>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</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">
Audio Language
</div>
<div class="form-group col-sm-8 pl-sm-0">
<span id="edit_audio_language_span"></span>
</div>
</div>
<div class="row">
<div class="col-sm-3 text-right">
Languages Profile
</div>
<div class="form-group col-sm-8 pl-sm-0">
<select class="selectpicker" id="edit_languages_select" name="languages"></select>
</div>
</div>
</div>
<input type="hidden" id="edit_radarrId" name="radarrId" value="" />
</div>
<div class="modal-footer">
<button type="submit" id="edit_save_button" class="btn btn-info"><span id="edit_save_button_span">Save</span></button>
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
</div>
</form>
</div>
</div>
</div>
<div id="movieHistoryModal" class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog modal-xl" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title"><span id="movie_history_title_span"></span></h5><br>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="container-fluid">
<table id="movie_history_result" class="table table-striped" style="width:100%">
<thead>
<tr>
<th></th>
<th style="text-align: left;">Language.:</th>
<th style="text-align: left;">Provider:</th>
<th style="text-align: left;">Score:</th>
<th style="text-align: left;">Date:</th>
<th style="text-align: left;">Actions:</th>
</tr>
</thead>
</table>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<div id="movieToolsModal" class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog modal-xl" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title"><span id="movie_tools_title_span"></span></h5><br>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="container-fluid">
<table id="movie_tools_result" class="table table-striped" style="width:100%">
<thead>
<tr>
<th style="text-align: left;">Language:</th>
<th style="text-align: left;">Filename:</th>
<th style="text-align: left;">Tools:</th>
</tr>
</thead>
</table>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<div id="movieSubtitleModColorModal" class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Choose Color</h5><br>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<form class="form" name="subtitles_mod_color_form" id="subtitles_mod_color_form">
<div class="modal-body">
<div class="container-fluid">
<div class="row">
<div class="col text-right">
<b>Color Name</b>
</div>
<div class="form-group col">
<select class="form-control selectpicker" id="subzero_color_name">
<option value="white">White</option>
<option value="light-grey">Light Grey</option>
<option value="red">Red</option>
<option value="green">Green</option>
<option value="yellow">Yellow</option>
<option value="blue">Blue</option>
<option value="magenta">Magenta</option>
<option value="cyan">Cyan</option>
<option value="black">Black</option>
<option value="dark-red">Dark Red</option>
<option value="dark-green">Dark Green</option>
<option value="dark-yellow">Dark Yellow</option>
<option value="dark-blue">Dark Blue</option>
<option value="dark-magenta">Dark Magenta</option>
<option value="dark-cyan">Dark Cyan</option>
<option value="dark-grey">Dark Grey</option>
</select>
</div>
<input type="hidden" id="subzero_color_data_language" value="" />
<input type="hidden" id="subzero_color_data_path" value="" />
</div>
</div>
</div>
<div class="modal-footer">
<span id="subtitles_mod_color_save_button_span"><button type="submit" id="subtitles_mod_color_save_button" class="btn btn-info">Save</button></span>
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</form>
</div>
</div>
</div>
<div id="movieSubtitleTranslateModal" class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Translate Subtitles</h5><br>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<form class="form" name="subtitles_translate_form" id="subtitles_translate_form">
<div class="modal-body">
<div class="container-fluid">
<div class="row">
<div class="col text-right">
<b>Language Name</b>
</div>
<div class="form-group col">
<select class="form-control selectpicker" id="translate_language_select">
</select>
</div>
</div>
<input type="hidden" id="translate_data_path" value="" />
<input type="hidden" id="translate_data_videopath" value="" />
<input type="hidden" id="translate_data_forced" value="" />
<input type="hidden" id="translate_data_hi" value="" />
</div>
</div>
<div class="modal-footer">
<span id="subtitles_translate_save_button_span"><button type="submit" id="subtitles_translate_save_button" class="btn btn-info">Translate</button></span>
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</form>
</div>
</div>
</div>
<div id="movieSubtitleModFpsModal" class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Convert frame rate of subtitle</h5><br>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<form class="form" name="subtitles_mod_fps_form" id="subtitles_mod_fps_form">
<div class="modal-body">
<div class="container-fluid">
<div class="row">
<div class="col text-right">
<b>From frame rate</b>
</div>
<div class="form-group col">
<input type="text" class="form-control" list="default_frame_rates" id="subzero_fps_from" minlength="2" maxlength="6" required autocomplete>
<datalist id="default_frame_rates">
<option value="23.976">23.976</option>
<option value="24">24</option>
<option value="25">25</option>
<option value="29.97">29.97</option>
<option value="30">30</option>
</datalist>
</div>
</div>
<div class="row">
<div class="col text-right">
<b>To frame rate</b>
</div>
<div class="form-group col">
<input type="text" class="form-control" list="default_frame_rates" id="subzero_fps_to" minlength="2" maxlength="6" required autocomplete>
</div>
</div>
<input type="hidden" id="subzero_fps_data_language" value="" />
<input type="hidden" id="subzero_fps_data_path" value="" />
</div>
</div>
<div class="modal-footer">
<span id="subtitles_mod_fps_save_button_span"><button type="submit" id="subtitles_mod_fps_save_button" class="btn btn-info">Save</button></span>
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</form>
</div>
</div>
</div>
<div id="movieSubtitleModOffsetModal" class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Adjust All Times</h5><br>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<form class="form" name="subtitles_mod_offset_form" id="subtitles_mod_offset_form">
<div class="modal-body">
<div class="container-fluid">
<div class="row">
<div class="col text-right">
<b>Hour:min:sec:ms</b>
</div>
<div class="form-group col">
<input type="text" class="form-control" id="subzero_offset_time" minlength="12" maxlength="12" required value="00:00:00.100">
</div>
</div>
<div class="row justify-content-center">
<div class="form-group col-sm-7">
<label class="custom-control custom-radio">
<input type="radio" class="custom-control-input" id="subzero_offset_show_earlier" name="subzero_offset_dir" checked value="0">
<span class="custom-control-label" for="subzero_offset_show_earlier">Show earlier</span>
</label>
</div>
</div>
<div class="row justify-content-center">
<div class="form-group col-sm-7">
<label class="custom-control custom-radio">
<input type="radio" class="custom-control-input" id="subzero_offset_show_later" name="subzero_offset_dir" value="1">
<span class="custom-control-label" for="subzero_offset_show_later">Show later</span>
</label>
</div>
</div>
<input type="hidden" id="subzero_offset_data_language" value="" />
<input type="hidden" id="subzero_offset_data_path" value="" />
</div>
</div>
<div class="modal-footer">
<span id="subtitles_mod_offset_save_button_span"><button type="submit" id="subtitles_mod_offset_save_button" class="btn btn-info">Save</button></span>
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</form>
</div>
</div>
</div>
{% endblock body %}
{% block tail %}
<script>
// make the filename appear in upload file dialog once a file have been selected.
$(document).ready(function () {
document.querySelector('.custom-file-input').addEventListener('change',function(e){
var fileName = document.getElementById("upload").files[0].name;
var nextSibling = e.target.nextElementSibling;
nextSibling.innerText = fileName;
});
$('#movies_nav').addClass("active");
movieDetailsRefresh();
getLanguages();
getEnabledLanguages();
getLanguagesProfiles();
//test
$('#movieSubtitles').on('click', '.remove_subtitles', function(e){
$(this).tooltip('dispose');
e.preventDefault();
const values = {
moviePath: movieDetails['mapped_path'],
language: $(this).data("language"),
forced: $(this).data("forced"),
hi: $(this).data("hi"),
subtitlesPath: $(this).data("subtitlespath"),
radarrId: movieDetails['radarrId'],
tmdbid: movieDetails['tmdbId']
};
var cell = $(this).parent();
$.ajax({
url: "{{ url_for('api.moviesubtitlesdelete') }}",
type: "DELETE",
dataType: "json",
data: values,
beforeSend: function() {
cell.html('<div class="spinner-border spinner-border-sm" role="status"><span class="sr-only">Loading...</span></div>');
}
});
});
$(document).on('click', '.get_subtitle', function(e){
$(this).tooltip('dispose');
e.preventDefault();
const values = {
moviePath: movieDetails['mapped_path'],
sceneName: movieDetails['sceneName'],
language: $(this).attr("data-language"),
hi: $(this).attr("data-hi"),
forced: $(this).attr("data-forced"),
radarrId: movieDetails['radarrId'],
title: movieDetails['title']
};
var button = $(this).closest('button' + '');
$.ajax({
url: "{{ url_for('api.moviesubtitlesdownload') }}",
type: "POST",
dataType: "json",
data: values,
beforeSend: function() {
button.html('<div class="spinner-border spinner-border-sm" role="status"><span class="sr-only">Loading...</span></div>');
}
});
});
$('#manual_button').on('click', function(e){
e.preventDefault();
$("#movie_title_span").html(movieDetails['title']);
$("#movie_path_span").html(movieDetails['mapped_path']);
if (movieDetails['sceneName'] === null) {
$("#movie_scenename_span").html('Not provided by Radarr');
} else {
$("#movie_scenename_span").html(movieDetails['sceneName']);
}
moviePath = movieDetails['mapped_path'];
sceneName = movieDetails['sceneName'];
profileId = movieDetails['profileId'].id;
radarrId = movieDetails['radarrId'];
var languages = Array.from(movieDetails['languages']);
var is_pb = languages.includes('pb');
var is_pt = languages.includes('pt');
const values = {
moviePath: moviePath,
sceneName: sceneName,
profileId: profileId,
radarrId: radarrId,
title: movieDetails['title']
};
$('#search_result').DataTable( {
destroy: true,
language: {
zeroRecords: 'No Subtitles Found For This Movie',
processing: "Searching{% if settings.general.anti_captcha_provider != 'None' %} (possibly solving captcha){% endif %}...",
search: "Filter:"
},
paging: true,
lengthChange: true,
pageLength: {{ settings.general.page_size_manual_search }},
lengthMenu: [ 5, 10, 15, 20, 25 ],
searching: true,
responsive: true,
//scrollX: true, // causing dropdown to not show in short list
ordering: false,
processing: true,
serverSide: false,
ajax: {
url: '{{ url_for('api.moviesubtitlesmanualsearch') }}',
type: 'POST',
data: values
},
columns: [
{ data: 'score',
render: function ( data ) {
return data +'%';
}
},
{ data: null,
render: function ( data ) {
let lng = data.language;
if ( data.language === "pt" && is_pb === true && is_pt === false) {
lng = 'pb'
}
let text = '<div class="badge badge-secondary" style="margin:1px;">' + lng.toUpperCase() + '</div>';
if (data.forced == "True") {
text += '<div class="badge badge-dark" style="margin:1px;">Forced</div>';
}
if (data.hearing_impaired == "True") {
text += '<div class="badge badge-dark" style="margin:1px;">HI</div>';
}
return text;
}
},
{ data: null,
render: function ( data ) {
if (data.url) {
return '<a href="' + data.url + '" target="_blank">' + data.provider + '</a>';
} else {
return data.provider;
}
}
},
{ data: null,
searchable: false,
render: function ( data ) {
const array_matches = data.matches;
const array_dont_matches = data.dont_matches;
let i;
let text = '<div class="dropdown"><div class="btn-group dropdown"><button class="btn btn-secondary btn-sm dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" style="margin:1px;"><i class="fas fa-check-circle" style="color: green;"></i> '+array_matches.length+'</button><div class="dropdown-menu" aria-labelledby="dropdownMenuButton">';
for (i = 0; i < array_matches.length; i++) {
text += '<a class="dropdown-item disabled" href="#">' + array_matches[i] + '</a>';
}
text += '</div>';
text += '<div class="dropdown"><button class="btn btn-secondary btn-sm dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" style="margin:1px;"><i class="fas fa-times-circle" style="color: red;"></i> '+array_dont_matches.length+'</button><div class="dropdown-menu" aria-labelledby="dropdownMenuButton">';
for (i = 0; i < array_dont_matches.length; i++) {
text += '<a class="dropdown-item disabled" href="#">' + array_dont_matches[i] + '</a>';
}
text += '</div></div></div>';
return text;
}
},
{ data: null,
render: function ( data ) {
const array_release_info = data.release_info;
let i;
let text;
if (array_release_info.length == 1) {
text = '<div style="font-size: 75%;font-weight: 400;">' + array_release_info[0] + '</div>';
}
else {
text = '<div class="dropdown"><button class="btn btn-secondary btn-sm dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><i class="\tfas fa-comment-dots"></i> ' + array_release_info.length + '</button><div class="dropdown-menu" aria-labelledby="dropdownMenuButton">';
for (i = 0; i < array_release_info.length; i++) {
text += '<a class="dropdown-item" href="#">' + array_release_info[i] + '</a>';
}
text += '</div></div>';
}
return text;
}
},
{ data: 'uploader',
render: function ( data ) {
return '<div class="badge badge-secondary">' + data + '</div>';
}
},
{ 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="'+data.forced+'"><i class="fas fa-download" style="margin-right:0px" ></i></a>';
}
}
]
} );
$('#manualSearchModal')
.modal({
focus: false
});
});
$('#search_result').on('click', '.manual_download', function(e){
e.preventDefault();
const values = {
moviePath: $(this).attr("data-moviepath"),
sceneName: $(this).attr("data-scenename"),
language: $(this).attr("data-language"),
hi: movieDetails['hearing_impaired'],
forced: $(this).attr("data-forced"),
provider: $(this).attr("data-provider"),
subtitle: $(this).attr("data-subtitle"),
radarrId: movieDetails['radarrId'],
title: movieDetails['title']
};
var cell = $(this).parent();
$.ajax({
url: "{{ url_for('api.moviesubtitlesmanualdownload') }}",
type: "POST",
dataType: "json",
data: values,
beforeSend: function() {
cell.html('<div class="spinner-border spinner-border-sm" role="status"><span class="sr-only">Loading...</span></div>');
},
complete: function(data) {
$('#manualSearchModal').modal('hide');
}
});
});
$('#upload_button').on('click', function(e){
e.preventDefault();
$("#upload_movie_title_span").html(movieDetails['title']);
$('#upload_moviePath').val(movieDetails['mapped_path']);
$('#upload_sceneName').val(movieDetails['sceneName']);
$('#upload_radarrId').val(movieDetails['radarrId']);
$('#upload_title').val(movieDetails['title']);
$('#upload_audioLanguage').val((movieDetails['audio_language'].length) ? movieDetails['audio_language'][0].name : 'None');
$('#manual_language_select').empty();
$.each(enabledLanguages, function (i, item) {
$('#manual_language_select').append('<option value="'+item.code2+'">'+item.name+'</option>');
});
$("#manual_language_select").selectpicker("refresh");
$('#uploadModal')
.modal({
focus: false
});
});
$('#upload_form').on('submit', function(e){
e.preventDefault();
var formdata = new FormData(document.getElementById("upload_form"));
$.ajax({
url: "{{ url_for('api.moviesubtitlesupload') }}",
data: formdata,
processData: false,
contentType: false,
type: 'POST',
beforeSend: function () {
$('#upload_save_button').html('<div class="spinner-border spinner-border-sm" role="status"><span class="sr-only">Loading...</span></div>');
},
complete: function(){
$('#uploadModal').modal('hide');
}
});
});
$('#scan_button').on('click', function(e){
e.preventDefault();
$.ajax({
url: "{{ url_for('api.moviescandisk', radarrid=id) }}",
type: 'GET',
beforeSend: function() {
$('#scan_button').find("i").addClass('fa-spin');
},
complete: function() {
$('#scan_button').find("i").removeClass('fa-spin');
}
});
});
$('#search_button').on('click', function(e){
e.preventDefault();
$.ajax({
url: "{{ url_for('api.moviesearchmissing', radarrid=id) }}",
type: 'GET',
beforeSend: function() {
$('#search_button').find("i").addClass('fa-spin');
},
complete: function() {
$('#search_button').find("i").removeClass('fa-spin');
}
});
});
$('#edit_button').on('click', function(e){
e.preventDefault();
$("#edit_movie_title_span").html(movieDetails['title']);
$("#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();
$('#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");
$('#edit_languages_select').selectpicker('val', ((movieDetails['profileId'].id) ? movieDetails['profileId'].id : 'None'));
$('#editModal')
.modal({
focus: false
});
});
$('#edit_form').on('submit', function(e){
e.preventDefault();
var formdata = new FormData(document.getElementById("edit_form"));
$.ajax({
url: "{{ url_for('api.movies') }}?radarrid={{id}}",
data: formdata,
processData: false,
contentType: false,
type: 'POST',
beforeSend: function () {
$('#edit_save_button_span').html('<div class="spinner-border spinner-border-sm" role="status"><span class="sr-only">Loading...</span></div>');
},
success: function(){
movieDetailsRefresh();
$('#editModal').modal('hide');
$('#edit_save_button_span').html('Save');
}
});
});
$('#uploadModal').on('hidden.bs.modal', function () {
$(this).find('form').trigger('reset');
$('.custom-file-label').text('Choose file')
$('#upload_save_button_span').html('<button type="submit" id="upload_save_button" class="btn btn-info">Save</button>');
});
events.on('event', function(event) {
var event_json = JSON.parse(event);
if (event_json.type === 'movie') {
if (event_json.movie === {{id}}) {
movieDetailsRefresh();
}
}
if (event_json.type === 'movieBlacklist' || event_json.type === 'movieHistory') {
if ($('#movie_history_result').DataTable().ajax.json()) {
$('#movie_history_result').DataTable().ajax.reload(null, false);
$('[data-toggle="tooltip"]').tooltip({html: true});
}
}
});
$('#history_button').on('click', function(e){
$(this).tooltip('dispose');
e.preventDefault();
$("#movie_history_title_span").html(movieDetails['title']);
radarrId = movieDetails['radarrId'];
$('#movie_history_result').DataTable( {
destroy: true,
language: {
zeroRecords: 'No History Records Found For This Movie'
},
paging: true,
lengthChange: false,
pageLength: 5,
searching: true,
ordering: false,
scrollX: true,
processing: true,
serverSide: false,
ajax: {
url: '{{ url_for( 'api.moviehistory' )}}?radarrid=' + radarrId
},
columns: [
{
data: 'action',
render: function(data) {
if (data === 0) {return "<i class='fas fa-trash' title='Subtitle file has been erased.' data-toggle='tooltip' data-placement='right'></i>";}
else if (data === 1) {return "<i class='fas fa-download' title='Subtitle file has been downloaded.' data-toggle='tooltip' data-placement='right'></i>";}
else if (data === 2) {return "<i class='fas fa-user' title='Subtitle file has been manually downloaded.' data-toggle='tooltip' data-placement='right'></i>";}
else if (data === 3) {return "<i class='fas fa-recycle' title='Subtitle file has been upgraded.' data-toggle='tooltip' data-placement='right'></i>";}
else if (data === 4) {return "<i class='fas fa-cloud-upload-alt' title='Subtitle file has been manually uploaded.' data-toggle='tooltip' data-placement='right'></i>";}
else if (data === 5) {return "<i class='fas fa-clock' title='Subtitle file has been synced.' data-toggle='tooltip' data-placement='right'></i>";}
else if (data === 6) {return "<i class='fas fa-language' title='Subtitle file has been translated.' data-toggle='tooltip' data-placement='right'></i>";}
}
},
{
data: 'language',
render: function (value) {
if (value) {
var language_string = '';
if (value.hi) {
language_string = ' HI';
} else if (value.forced) {
language_string = ' forced';
}
return value.name + language_string;
} else {
return '<i>undefined</i>'
}
}
},
{ data: 'provider' },
{ data: 'score'},
{ data: 'timestamp'},
{
data: null,
render: function (data) {
if (data.subs_id && data.subtitles_path && !data.blacklisted) {
return '<a href="" class="blacklist_subtitles badge badge-secondary" data-toggle="tooltip" data-placement="right" title="Blacklist this subtitles" data-radarrid="' + data.radarrId + '" data-language="' + data.language.code2 + '" data-forced="' + data.language.forced + '" data-hi="' + data.language.hi + '" data-provider="' + data.provider + '" data-subs_id="' + data.subs_id + '" data-video_path="' + data.video_path + '" data-subtitles_path="' + data.subtitles_path + '"><i class="far fa-file-excel"></i></a>';
} else {
return null;
}
}
}
]
} );
$('#movieHistoryModal')
.modal({
focus: false
});
});
$('#movie_history_result').on('click', '.blacklist_subtitles', function (e) {
$(this).tooltip('dispose');
e.preventDefault();
const values = {
radarr_id: $(this).attr('data-radarrid'),
provider: $(this).attr('data-provider'),
subs_id: $(this).attr('data-subs_id'),
language: $(this).attr('data-language'),
forced: $(this).attr('data-forced'),
hi: $(this).attr('data-hi'),
video_path: $(this).attr('data-video_path'),
subtitles_path: $(this).attr('data-subtitles_path')
};
var cell = $(this).parent();
$.ajax({
url: "{{ url_for('api.blacklistmoviesubtitlesadd') }}",
type: "POST",
dataType: "json",
data: values,
beforeSend: function () {
cell.html('<div class="spinner-border spinner-border-sm" role="status"><span class="sr-only">Loading...</span></div>');
}
});
});
$('#tools_button').on('click', function (e) {
$(this).tooltip('dispose');
e.preventDefault();
$("#movie_tools_title_span").html(movieDetails['title']);
radarrId = movieDetails['radarrId'];
$('#movie_tools_result').DataTable({
destroy: true,
language: {
zeroRecords: 'No External Subtitles Found For This Movie'
},
paging: true,
lengthChange: false,
pageLength: 5,
searching: true,
ordering: false,
scrollX: true,
processing: false,
serverSide: false,
ajax: {
url: '{{ url_for( 'api.movietools' )}}?movieid=' + radarrId
},
columns: [
{data: 'language.name'},
{data: 'filename'},
{
data: null,
"render": function (data) {
var tools = '';
tools += '<a href="" class="subtitles_sync badge badge-secondary" data-language="' + data.language.code3 + '" data-path="' + data.path + '" data-videopath="' + data.videopath + '" data-toggle="tooltip" data-placement="right" title="Sync"><i class="far fa-play-circle"></i></a> ';
tools += '<a href="" class="subtitles_mod badge badge-secondary" data-language="' + data.language.code3 + '" data-path="' + data.path + '" data-mod = "remove_HI" data-toggle="tooltip" data-placement="right" title="Remove HI-tags"><i class="fa fa-deaf"></i></a> ';
tools += '<a href="" class="subtitles_mod badge badge-secondary" data-language="' + data.language.code3 + '" data-path="' + data.path + '" data-mod = "remove_tags" data-toggle="tooltip" data-placement="right" title="Remove style tags"><i class="fa fa-code"></i></a> ';
tools += '<a href="" class="subtitles_mod badge badge-secondary" data-language="' + data.language.code3 + '" data-path="' + data.path + '" data-mod = "OCR_fixes" data-toggle="tooltip" data-placement="right" title="OCR Fixes"><i class="fa fa-image"></i></a> ';
tools += '<a href="" class="subtitles_mod badge badge-secondary" data-language="' + data.language.code3 + '" data-path="' + data.path + '" data-mod = "common" data-toggle="tooltip" data-placement="right" title="Common Fixes"><i class="fas fa-magic"></i></a> ';
tools += '<a href="" class="subtitles_mod badge badge-secondary" data-language="' + data.language.code3 + '" data-path="' + data.path + '" data-mod = "fix_uppercase" data-toggle="tooltip" data-placement="right" title="Fix Uppercase"><i class="fa fa-text-height"></i></a> ';
tools += '<a href="" class="subtitles_mod badge badge-secondary" data-language="' + data.language.code3 + '" data-path="' + data.path + '" data-mod = "reverse_rtl" data-toggle="tooltip" data-placement="right" title="Reverse RTL"><i class="fa fa-exchange-alt"></i></a> ';
tools += '<a href="" class="subtitles_mod_color badge badge-secondary" data-language="' + data.language.code3 + '" data-path="' + data.path + '" data-toggle="tooltip" data-placement="right" title = "Adds color to your subtitles"><i class="fa fa-paint-brush"></i></a> ';
tools += '<a href="" class="subtitles_mod_fps badge badge-secondary" data-language="' + data.language.code3 + '" data-path="' + data.path + '" data-toggle="tooltip" data-placement="right" title = "Change Frame Rate"><i class="fa fa-film"></i></a> ';
tools += '<a href="" class="subtitles_mod_offset badge badge-secondary" data-language="' + data.language.code3 + '" data-path="' + data.path + '" data-toggle="tooltip" data-placement="right" title = "Adjust all times (show earlier/later)"><i class="fa fa-clock"></i></a> ';
tools += '<a href="" class="subtitles_translate badge badge-secondary" data-forced="' + data.language.forced + '" data-hi="' + data.language.hi + '" data-language="' + data.language.code3 + '" data-path="' + data.path + '" data-videopath="' + data.videopath + '" data-toggle="tooltip" data-placement="right" title = "Translate your subtitles"><i class="fa fa-language"></i></a> ';
return tools;
}
}
]
});
$('#movieToolsModal')
.modal({
focus: false
});
});
$('#movie_tools_result').on('click', '.subtitles_sync', function (e) {
e.preventDefault();
const values = {
language: $(this).attr("data-language"),
subtitlesPath: $(this).attr("data-path"),
videoPath: $(this).attr("data-videopath"),
mediaType: 'movies'
};
var cell = $(this).parent()
;
$.ajax({
url: "{{ url_for('api.syncsubtitles') }}",
type: "POST",
dataType: "json",
data: values,
beforeSend: function () {
$('.subtitles_sync').tooltip('hide')
cell.html('<div class="spinner-border spinner-border-sm" role="status"><span class="sr-only">Loading...</span></div>');
},
complete: function (data) {
$('#movieToolsModal').modal('hide');
}
});
});
$('#movie_tools_result').on('click', '.subtitles_mod', function (e) {
e.preventDefault();
const values = {
language: $(this).attr("data-language"),
subtitlesPath: $(this).attr("data-path"),
mod: $(this).attr("data-mod"),
};
var cell = $(this).parent();
$.ajax({
url: "{{ url_for('api.submods') }}",
type: "POST",
dataType: "json",
data: values,
beforeSend: function () {
$('.subtitles_mod').tooltip('hide')
cell.html('<div class="spinner-border spinner-border-sm" role="status"><span class="sr-only">Loading...</span></div>');
},
complete: function () {
$('#movieToolsModal').modal('hide');
}
});
});
$('#movie_tools_result').on('click', '.subtitles_mod_color', function (e) {
e.preventDefault();
$('#subzero_color_data_language').val($(this).attr("data-language"))
$('#subzero_color_data_path').val($(this).attr("data-path"))
$('#movieToolsModal').modal('hide');
$('#movieSubtitleModColorModal')
.modal({
focus: false
});
});
$('#subtitles_mod_color_form').on('submit', function (e) {
e.preventDefault();
const values = {
language: $('#subzero_color_data_language').val(),
subtitlesPath: $('#subzero_color_data_path').val(),
mod: 'color(name=' + $('#subzero_color_name').val() + ')',
};
$.ajax({
url: "{{ url_for('api.submods') }}",
type: "POST",
dataType: "json",
data: values,
beforeSend: function () {
$('#subtitles_mod_color_save_button').html('<div class="spinner-border spinner-border-sm" role="status"><span class="sr-only">Loading...</span></div>');
},
complete: function () {
$('#movieSubtitleModColorModal').modal('hide');
}
});
});
$('#movieSubtitleModColorModal').on('hidden.bs.modal', function (e) {
$('#subtitles_mod_color_save_button_span').html('<button type="submit" id="subtitles_mod_color_save_button" class="btn btn-info">Save</button>');
});
$('#movie_tools_result').on('click', '.subtitles_mod_fps', function (e) {
e.preventDefault();
$('#subzero_fps_data_language').val($(this).attr("data-language"))
$('#subzero_fps_data_path').val($(this).attr("data-path"))
$('#movieToolsModal').modal('hide');
$('#movieSubtitleModFpsModal')
.modal({
focus: false
});
});
$('#movie_tools_result').on('click', '.subtitles_translate', function (e) {
e.preventDefault();
$('#translate_data_language').val($(this).attr("data-language"))
$('#translate_data_path').val($(this).attr("data-path"))
$('#translate_data_videopath').val($(this).attr("data-videopath"))
$('#translate_data_forced').val($(this).attr("data-forced"))
$('#translate_data_hi').val($(this).attr("data-hi"))
$('#translate_language_select')
.empty();
$.each(enabledLanguages, function (i, item) {
$('#translate_language_select')
.append('<option value="' + item.code3 + '"' + ((item.code2 in GOOGLE_CODES_TO_LANGUAGES) ? '' : 'data-subtext="Unsupported" disabled') + '>' + item.name + '</option>');
});
$("#translate_language_select").selectpicker("refresh");
$('#movieToolsModal').modal('hide');
$('#movieSubtitleTranslateModal')
.modal({
focus: false
});
});
$('#subtitles_mod_fps_form').on('submit', function (e) {
e.preventDefault();
const values = {
language: $('#subzero_fps_data_language').val(),
subtitlesPath: $('#subzero_fps_data_path').val(),
mod: 'change_FPS(from=' + $('#subzero_fps_from').val() + ',to=' + $('#subzero_fps_to').val() + ')',
};
$.ajax({
url: "{{ url_for('api.submods') }}",
type: "POST",
dataType: "json",
data: values,
beforeSend: function () {
$('#subtitles_mod_fps_save_button').html('<div class="spinner-border spinner-border-sm" role="status"><span class="sr-only">Loading...</span></div>');
},
complete: function () {
$('#movieSubtitleModFpsModal').modal('hide');
}
});
});
$('#subtitles_translate_form').on('submit', function (e) {
e.preventDefault();
const values = {
language: $('#translate_language_select').val(),
subtitlesPath: $('#translate_data_path').val(),
videoPath: $('#translate_data_videopath').val(),
forced: $('#translate_data_forced').val(),
hi: $('#translate_data_hi').val(),
mediaType: 'movie',
};
$.ajax({
url: "{{ url_for('api.subtranslate') }}",
type: "POST",
dataType: "json",
data: values,
beforeSend: function () {
$('#subtitles_translate_save_button').html('<div class="spinner-border spinner-border-sm" role="status"><span class="sr-only">Loading...</span></div>');
},
complete: function () {
$('#movieSubtitleTranslateModal').modal('hide');
}
});
});
$('#movieSubtitleModFpsModal').on('hidden.bs.modal', function (e) {
$('#subtitles_mod_fps_save_button_span').html('<button type="submit" id="subtitles_mod_fps_save_button" class="btn btn-info">Save</button>');
});
$('#movieSubtitleTranslateModal').on('hidden.bs.modal', function (e) {
$('#subtitles_translate_save_button_span').html('<button type="submit" id="subtitles_translate_save_button" class="btn btn-info">Translate</button>');
});
$('#movie_tools_result').on('click', '.subtitles_mod_offset', function (e) {
e.preventDefault();
$('#subzero_offset_data_language').val($(this).attr("data-language"))
$('#subzero_offset_data_path').val($(this).attr("data-path"))
$('#movieToolsModal').modal('hide');
$('#movieSubtitleModOffsetModal')
.modal({
focus: false
});
});
$('#subtitles_mod_offset_form').on('submit', function (e) {
e.preventDefault();
let times = $('#subzero_offset_time').val().match(/(\d\d):(\d\d):(\d\d)[\.,:](\d\d\d)/);
if (times == null || times.length != 5) return false;
let sign = '';
if ($('input[name="subzero_offset_dir"]:checked').val() == "0") {
sign = '-';
}
const values = {
language: $('#subzero_offset_data_language').val(),
subtitlesPath: $('#subzero_offset_data_path').val(),
mod: 'shift_offset(h='+sign+times[1]+',m='+sign+times[2]+',s='+sign+times[3]+',ms='+sign+times[4]+')',
};
$.ajax({
url: "{{ url_for('api.submods') }}",
type: "POST",
dataType: "json",
data: values,
beforeSend: function () {
$('#subtitles_mod_offset_save_button').html('<div class="spinner-border spinner-border-sm" role="status"><span class="sr-only">Loading...</span></div>');
},
complete: function () {
$('#movieSubtitleModOffsetModal').modal('hide');
}
});
});
$('#movieSubtitleModOffsetModal').on('hidden.bs.modal', function (e) {
$('#subtitles_mod_offset_save_button_span').html('<button type="submit" id="subtitles_mod_offset_save_button" class="btn btn-info">Save</button>');
});
});
function movieDetailsRefresh() {
$.ajax({
url: "{{ url_for('api.movies') }}?radarrid={{id}}"
}).done(function (data) {
movieDetails = data.data[0];
$(document).prop('title', movieDetails['title'] + ' - Bazarr');
$('#movieFanart').css('background-image', "url('{{ url_for('image_proxy_movies', url='MediaCover/'+id+'/fanart.jpg') }}')");
$('#moviePoster').attr("src", "{{ url_for('image_proxy_movies', url='MediaCover/'+id+'/poster-250.jpg') }}");
$('#movieTitle').text(movieDetails['title']);
if (movieDetails['alternativeTitles'].length > 0) {
$('#moviealternativeTitles').attr("data-original-title", "<b>Alternative Titles:</b><br>" + movieDetails['alternativeTitles']);
} else {
$('#moviealternativeTitles').hide();
}
if (movieDetails['tags'].length > 0) {
$('#movieTags').attr("data-original-title", "<b>Tags:</b><br>" + movieDetails['tags']);
} else {
$('#movieTags').hide();
}
$("#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']);
$('#movieSubtitlesLanguagesProfile').text(movieDetails['profileId'].name);
$('#movieDescription').text(movieDetails['overview']);
var missing_languages = '';
if (movieDetails['missing_subtitles'] !== 'None') {
movieDetails['missing_subtitles'].forEach(missingAppendFunc);
}
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 + ' 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 + ' 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-hi="' + value.hi + '" data-forced="' + value.forced + '">' + value.code2 + ' <i class="fas fa-search"></i></button> ';
}
}
$('#missingSubtitles').html(missing_languages);
$('[data-toggle="tooltip"]').tooltip({html: true});
if (movieDetails['profileId'].id) {
$('#search_button').show();
$('#manual_button').show();
$('#upload_button').show();
} else {
$('#search_button').hide();
$('#manual_button').hide();
$('#upload_button').hide();
}
var table = $('#movieSubtitles').DataTable({
destroy: true,
language: {
zeroRecords: 'No Subtitles Found For This Movie'
},
"searching": false,
"ordering": false,
"paging": false,
"info": false,
"lengthChange": false,
"responsive": true,
"data" : movieDetails['subtitles'],
"columns" : [
{ "data" : null,
"render": function(data) {
if (data['path']) {
return data['path'];
} else {
return 'Video File Subtitles Track';
}
}
},
{ "data" : null,
"render": function(data) {
if (data['forced']) {
return '<span class="badge badge-secondary">' + data['name'] + ' forced</span>';
} else if (data['hi']) {
return '<span class="badge badge-secondary">' + data['name'] + ' HI</span>';
} else {
return '<span class="badge badge-secondary">' + data['name'] + '</span>';
}
}
},
{ "data" : null,
"render": function(data) {
if (data['path']) {
return '<button type="button" class="remove_subtitles close" aria-label="Close" data-toggle="tooltip" data-placement="right" title="Delete Subtitles File" data-language='+data['code3']+' data-forced='+data['forced']+' data-hi='+data['hi']+' data-subtitlesPath="'+data['path']+'"><span aria-hidden="true">&times;</span></button>';
} else {
return '';
}
}
}
]
});
});
}
function getLanguages() {
$.ajax({
url: "{{ url_for('api.languages') }}?enabled=false",
success:function(data) {
availableLanguages = data;
}
});
}
function getEnabledLanguages() {
$.ajax({
url: "{{ url_for('api.languages') }}?enabled=true",
success:function(data) {
enabledLanguages = data;
}
});
}
function getLanguagesProfiles() {
$.ajax({
url: "{{ url_for('api.languagesprofiles') }}",
success: function (data) {
languagesProfiles = data['data'];
}
});
}
GOOGLE_CODES_TO_LANGUAGES = {
'af': 'afrikaans',
'sq': 'albanian',
'am': 'amharic',
'ar': 'arabic',
'hy': 'armenian',
'az': 'azerbaijani',
'eu': 'basque',
'be': 'belarusian',
'bn': 'bengali',
'bs': 'bosnian',
'bg': 'bulgarian',
'ca': 'catalan',
'ceb': 'cebuano',
'ny': 'chichewa',
'zh-cn': 'chinese (simplified)',
'zh-tw': 'chinese (traditional)',
'co': 'corsican',
'hr': 'croatian',
'cs': 'czech',
'da': 'danish',
'nl': 'dutch',
'en': 'english',
'eo': 'esperanto',
'et': 'estonian',
'tl': 'filipino',
'fi': 'finnish',
'fr': 'french',
'fy': 'frisian',
'gl': 'galician',
'ka': 'georgian',
'de': 'german',
'el': 'greek',
'gu': 'gujarati',
'ht': 'haitian creole',
'ha': 'hausa',
'haw': 'hawaiian',
'iw': 'hebrew',
'hi': 'hindi',
'hmn': 'hmong',
'hu': 'hungarian',
'is': 'icelandic',
'ig': 'igbo',
'id': 'indonesian',
'ga': 'irish',
'it': 'italian',
'ja': 'japanese',
'jw': 'javanese',
'kn': 'kannada',
'kk': 'kazakh',
'km': 'khmer',
'ko': 'korean',
'ku': 'kurdish (kurmanji)',
'ky': 'kyrgyz',
'lo': 'lao',
'la': 'latin',
'lv': 'latvian',
'lt': 'lithuanian',
'lb': 'luxembourgish',
'mk': 'macedonian',
'mg': 'malagasy',
'ms': 'malay',
'ml': 'malayalam',
'mt': 'maltese',
'mi': 'maori',
'mr': 'marathi',
'mn': 'mongolian',
'my': 'myanmar (burmese)',
'ne': 'nepali',
'no': 'norwegian',
'ps': 'pashto',
'fa': 'persian',
'pl': 'polish',
'pt': 'portuguese',
'pa': 'punjabi',
'ro': 'romanian',
'ru': 'russian',
'sm': 'samoan',
'gd': 'scots gaelic',
'sr': 'serbian',
'st': 'sesotho',
'sn': 'shona',
'sd': 'sindhi',
'si': 'sinhala',
'sk': 'slovak',
'sl': 'slovenian',
'so': 'somali',
'es': 'spanish',
'su': 'sundanese',
'sw': 'swahili',
'sv': 'swedish',
'tg': 'tajik',
'ta': 'tamil',
'te': 'telugu',
'th': 'thai',
'tr': 'turkish',
'uk': 'ukrainian',
'ur': 'urdu',
'uz': 'uzbek',
'vi': 'vietnamese',
'cy': 'welsh',
'xh': 'xhosa',
'yi': 'yiddish',
'yo': 'yoruba',
'zu': 'zulu',
'fil': 'Filipino',
'he': 'Hebrew'
};
</script>
{% endblock tail %}