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.
2074 lines
101 KiB
2074 lines
101 KiB
{% extends '_main.html' %}
|
|
|
|
{% block title %}Series - Bazarr{% endblock %}
|
|
|
|
{% block page_head %}
|
|
<style>
|
|
#seriesFanart {
|
|
background-repeat: no-repeat;
|
|
background-size: cover;
|
|
background-position: top center;
|
|
box-sizing: initial;
|
|
margin-left: -32px;
|
|
margin-top: -5px;
|
|
padding: 2em;
|
|
}
|
|
|
|
#seriesDetails {
|
|
padding: 30px;
|
|
background: rgba(0, 0, 0, 0.7);
|
|
color: white;
|
|
margin: -32px;
|
|
}
|
|
|
|
#seriesPoster {
|
|
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;
|
|
}
|
|
|
|
.dtrg-start {
|
|
cursor: pointer;
|
|
}
|
|
|
|
.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>
|
|
</div>
|
|
{% endblock bcleft %}
|
|
|
|
{% block bcright %}
|
|
<div class="d-flex m-t-5 justify-content-end">
|
|
<button class="btn btn-outline" id="mass_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="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 Series</div>
|
|
</button>
|
|
</div>
|
|
{% endblock bcright %}
|
|
|
|
{% block body %}
|
|
<div class="container-fluid" id="seriesFanart">
|
|
<div class="row justify-content-md-center" id="seriesDetails">
|
|
<div class="col-sm-auto" id="seriesPosterColumn">
|
|
<img id="seriesPoster" src="">
|
|
</div>
|
|
<div class="col">
|
|
<div class="container-fluid">
|
|
<div class="row">
|
|
<h1><span id="seriesTitle"></span></h1>
|
|
<i class="far fa-clone" id="seriesAlternateTitles" data-toggle="tooltip" data-placement="right"
|
|
title="None" data-html="true"></i>
|
|
</div>
|
|
<div class="row">
|
|
<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>
|
|
<h5><span id="seriesTags" 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="seriesSubtitlesLanguagesProfile" class="badge badge-secondary"></span></h5>
|
|
</div>
|
|
<div class="row">
|
|
<h5><span id="seriesHearingImpaired" class="badge badge-secondary"></span></h5>
|
|
<h5><span id="seriesForced" class="badge badge-secondary"></span></h5>
|
|
</div>
|
|
<div class="row">
|
|
<span id="seriesDescription"></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- ============================================================== -->
|
|
<!-- Bread crumb and right sidebar toggle -->
|
|
<!-- ============================================================== -->
|
|
<table id="episodes" class="table table-striped" style="width:100%">
|
|
<thead>
|
|
<tr>
|
|
<th></th>
|
|
<th>Episode</th>
|
|
<th>Title</th>
|
|
<th>Audio Languages</th>
|
|
<th>Existing Subtitles</th>
|
|
<th>Missing Subtitles</th>
|
|
<th>Manual Search</th>
|
|
<th>Manual Upload</th>
|
|
<th>Tools</th>
|
|
</tr>
|
|
</thead>
|
|
</table>
|
|
|
|
<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="series_title_span"></span></h5><br>
|
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
|
<span aria-hidden="true">×</span>
|
|
</button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<h6>Episode path: <span id="episode_path_span" class="badge badge-secondary"></span>
|
|
<br>Scenename: <span id="episode_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_series_title_span"></span></h5><br>
|
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
|
<span aria-hidden="true">×</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_episodePath" name="episodePath" value=""/>
|
|
<input type="hidden" id="upload_sceneName" name="sceneName" value=""/>
|
|
<input type="hidden" id="upload_sonarrSeriesId" name="sonarrSeriesId" value=""/>
|
|
<input type="hidden" id="upload_sonarrEpisodeId" name="sonarrEpisodeId" 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="massUploadModal" 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="mass_upload_title_span"></span></h5><br>
|
|
<button type="button" class="close" id="mass_upload_close_btn" data-dismiss="modal" aria-label="Close">
|
|
<span aria-hidden="true">×</span>
|
|
</button>
|
|
</div>
|
|
<form class="form" name="edit_form" id="mass_upload_form">
|
|
<div class="modal-body">
|
|
<div class="container-fluid">
|
|
<div class="row form-group">
|
|
<div class="custom-file">
|
|
<input type="file" accept=".srt" multiple class="custom-file-input" id="mass_upload_file_list">
|
|
<label id="mass-upload-file-label" class="custom-file-label" for="upload">Choose files</label>
|
|
</div>
|
|
</div>
|
|
<!-- Store episodes we previous collect -->
|
|
<input type="hidden" id="mass-upload-exist-episodes" value=""/>
|
|
|
|
<table id="upload_table" class="table table-striped" style="width:100%">
|
|
<thead>
|
|
<tr>
|
|
<th></th>
|
|
<th style="text-align: left;">Filename</th>
|
|
<th style="text-align: left;">Season</th>
|
|
<th style="text-align: left;">Episode</th>
|
|
<th style="text-align: center;">Action</th>
|
|
</tr>
|
|
</thead>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer justify-content-between">
|
|
<div>
|
|
<div>
|
|
<select class="selectpicker" id="mass_upload_language_select" name="language"></select>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<button type="submit" id="mass_upload_save_button" class="btn btn-info">Upload</button>
|
|
<button type="button" class="btn btn-secondary" id="mass_upload_cancel_btn" data-dismiss="modal">Cancel</button>
|
|
</div>
|
|
</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_series_title_span"></span></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">
|
|
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">
|
|
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_sonarrSeriesId" name="sonarrSeriesId" 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="episodeHistoryModal" 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="episode_history_title_span"></span></h5><br>
|
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
|
<span aria-hidden="true">×</span>
|
|
</button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="container-fluid">
|
|
<table id="episode_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="episodeToolsModal" 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="episode_tools_title_span"></span></h5><br>
|
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
|
<span aria-hidden="true">×</span>
|
|
</button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="container-fluid">
|
|
<table id="episode_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="episodeSubtitleModColorModal" 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">×</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="episodeSubtitleTranslateModal" 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">×</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="episodeSubtitleModFpsModal" 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">×</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="episodeSubtitleModOffsetModal" 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">×</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;
|
|
});
|
|
|
|
$('#series_nav').addClass("active");
|
|
|
|
seriesDetailsRefresh();
|
|
episodesDetailsRefresh();
|
|
getLanguages();
|
|
getEnabledLanguages();
|
|
getLanguagesProfiles();
|
|
|
|
var collapsedGroups = {};
|
|
|
|
var table = $('#episodes').DataTable({
|
|
dom: "tr",
|
|
processing: true,
|
|
serverSide: true,
|
|
language: {
|
|
zeroRecords: 'No Episodes Found For This Series',
|
|
processing: "Loading Episodes..."
|
|
},
|
|
searching: false,
|
|
ordering: false,
|
|
lengthChange: false,
|
|
responsive: true,
|
|
pageLength: {{ settings.general.page_size }},
|
|
ajax: "{{ url_for('api.episodes') }}?seriesid={{id}}",
|
|
initComplete: function() {
|
|
$('.dtrg-start').each( function(i, item) {
|
|
if (i > 0) {
|
|
var name = $(item).data('name');
|
|
collapsedGroups[name] = !collapsedGroups[name];
|
|
table.draw(false);
|
|
}
|
|
})
|
|
},
|
|
rowGroup: {
|
|
dataSrc: 'season',
|
|
startRender: function (rows, group) {
|
|
var collapsed = !!collapsedGroups[group];
|
|
|
|
rows.nodes().each(function (r) {
|
|
r.style.display = collapsed ? 'none' : '';
|
|
});
|
|
|
|
if (collapsed) {
|
|
var chevron_icon = '<i class="fas fa-chevron-circle-right"></i>';
|
|
} else {
|
|
var chevron_icon = '<i class="fas fa-chevron-circle-down"></i>';
|
|
}
|
|
|
|
|
|
return $('<tr/>')
|
|
.append('<td colspan=' + rows.columns()[0].length + '>Season ' + group + ' ' + chevron_icon + '</td>')
|
|
.attr('data-name', group)
|
|
.toggleClass('collapsed', collapsed);
|
|
}
|
|
},
|
|
columns: [
|
|
{
|
|
data: "monitored",
|
|
render: function (data, type, row) {
|
|
if (data === 'False') {
|
|
return '<i class="far fa-bookmark" data-toggle="tooltip" data-placement="right" title="Episode unmonitored in Sonarr"></i>';
|
|
} else if (data === 'True') {
|
|
return '<i class="fas fa-bookmark" data-toggle="tooltip" data-placement="right" title="Episode monitored in Sonarr"></i>';
|
|
}
|
|
}
|
|
},
|
|
{data: "episode"},
|
|
{
|
|
data: null,
|
|
render: function (data) {
|
|
var title_path = '<a href="" data-toggle="tooltip" title="Path is: ' + data.mapped_path + '" data-season=' + data.season + ' data-episode=' + data.episode + ' data-episodeTitle="' + data.title + '" data-sonarrEpisodeId=' + data.sonarrEpisodeId + ' class="episode_history">' + data.title + '</a>';
|
|
if (data.scene_name) {
|
|
return '<i class="fas fa-info-circle" data-toggle="tooltip" data-placement="right" title="' + data.scene_name + '"></i> ' + title_path;
|
|
} else {
|
|
return title_path;
|
|
}
|
|
}
|
|
},
|
|
{
|
|
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,
|
|
render: function (data) {
|
|
if (data.subtitles !== 'None') {
|
|
var languages = '';
|
|
data.subtitles.forEach(appendFunc);
|
|
return languages;
|
|
} else {
|
|
return null;
|
|
}
|
|
|
|
function appendFunc(value) {
|
|
if (value[0].forced) {
|
|
var advtag = ':forced';
|
|
} else if (value[0].hi) {
|
|
var advtag = ':HI';
|
|
} else {
|
|
var advtag = '';
|
|
}
|
|
|
|
if (value[1] === null) {
|
|
languages = languages + '<span class="badge badge-secondary" data-toggle="tooltip" data-placement="right" title="' + value[0].name + advtag + '">' + value[0].code2 + advtag + '</span> ';
|
|
} else {
|
|
languages = languages + '<a href="" class="remove_subtitles badge badge-secondary" data-toggle="tooltip" data-placement="right" title="' + value[0].name + advtag + '" data-episodePath="' + data.mapped_path + '" data-language="' + value[0].code3 + '" data-forced="' + value[0].forced + '" data-hi="' + value[0].hi + '" data-subtitlesPath="' + value[1] + '" data-sonarrEpisodeId=' + data.sonarrEpisodeId + '>' + value[0].code2 + advtag + ' <i class="far fa-trash-alt"></i></a> ';
|
|
}
|
|
}
|
|
}
|
|
},
|
|
{
|
|
data: null,
|
|
render: function (data) {
|
|
if (data.missing_subtitles !== 'None') {
|
|
var languages = '';
|
|
data.missing_subtitles.forEach(appendFunc);
|
|
return languages;
|
|
} else {
|
|
return null;
|
|
}
|
|
|
|
function appendFunc(value) {
|
|
if (value.forced) {
|
|
var advtag = ':forced';
|
|
} else if (value.hi) {
|
|
var advtag = ':HI';
|
|
} else {
|
|
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="' + value.hi + '" data-forced="' + value.forced + '" data-sonarrepisodeid=' + data.sonarrEpisodeId + '>' + value.code2 + advtag + ' <i class="fas fa-search"></i></a> ';
|
|
}
|
|
}
|
|
},
|
|
{
|
|
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-sonarrEpisodeId=' + data.sonarrEpisodeId + '><i class="fas fa-user"></i></a>';
|
|
} else {
|
|
return ''
|
|
}
|
|
}
|
|
},
|
|
{
|
|
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=\'' + JSON.stringify(data.audio_language) + '\'><i class="fas fa-cloud-upload-alt"></i></a>';
|
|
} else {
|
|
return ''
|
|
}
|
|
}
|
|
},
|
|
{
|
|
data: null,
|
|
render: function (data) {
|
|
return '<a href="" class="episode_tools badge badge-secondary" data-sonarrEpisodeId="' + data.sonarrEpisodeId + '" data-season="' + data.season + '" data-episode="' + data.episode + '" data-episode_title="' + data.title + '"><i class="fa fa-briefcase"></i></a>';
|
|
}
|
|
}
|
|
]
|
|
});
|
|
|
|
$('#episodes').on('click', 'tr.dtrg-start', function () {
|
|
var name = $(this).data('name');
|
|
collapsedGroups[name] = !collapsedGroups[name];
|
|
table.draw(false);
|
|
});
|
|
|
|
$('#episodes').on('click', '.remove_subtitles', function (e) {
|
|
$(this).tooltip('dispose');
|
|
e.preventDefault();
|
|
const values = {
|
|
episodePath: $(this).attr("data-episodePath"),
|
|
language: $(this).attr("data-language"),
|
|
forced: $(this).attr("data-forced"),
|
|
hi: $(this).attr("data-hi"),
|
|
subtitlesPath: $(this).attr("data-subtitlesPath"),
|
|
sonarrSeriesId: seriesDetails['sonarrSeriesId'],
|
|
sonarrEpisodeId: $(this).attr("data-sonarrEpisodeId"),
|
|
tvdbid: seriesDetails['tvdbId']
|
|
};
|
|
var cell = $(this).parent();
|
|
$.ajax({
|
|
url: "{{ url_for('api.episodessubtitlesdelete') }}",
|
|
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>');
|
|
}
|
|
});
|
|
});
|
|
|
|
$('#episodes').on('click', '.get_subtitle', function (e) {
|
|
$(this).tooltip('dispose');
|
|
e.preventDefault();
|
|
const values = {
|
|
episodePath: $(this).attr("data-episodepath"),
|
|
sceneName: $(this).attr("data-scenename"),
|
|
language: $(this).attr("data-language"),
|
|
hi: $(this).attr("data-hi"),
|
|
forced: $(this).attr("data-forced"),
|
|
sonarrSeriesId: seriesDetails['sonarrSeriesId'],
|
|
sonarrEpisodeId: $(this).attr('data-sonarrepisodeid'),
|
|
title: seriesDetails['title']
|
|
};
|
|
var cell = $(this).parent();
|
|
$.ajax({
|
|
url: "{{ url_for('api.episodessubtitlesdownload') }}",
|
|
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>');
|
|
}
|
|
});
|
|
});
|
|
|
|
$('#episodes').on('click', '.manual_search', function (e) {
|
|
e.preventDefault();
|
|
$("#series_title_span").html(seriesDetails['title'] + ' - ' + $(this).data("season") + 'x' + $(this).data("episode") + ' - ' + $(this).data("episode_title"));
|
|
$("#episode_path_span").html($(this).attr("data-episodePath"));
|
|
if ($(this).attr("data-sceneName") === 'null') {
|
|
$("#episode_scenename_span").html('Not provided by Sonarr');
|
|
} else {
|
|
$("#episode_scenename_span").html($(this).attr("data-sceneName"));
|
|
}
|
|
|
|
episodePath = $(this).attr("data-episodePath");
|
|
sceneName = $(this).attr("data-sceneName");
|
|
profileId = seriesDetails['profileId'].id;
|
|
sonarrSeriesId = seriesDetails['sonarrSeriesId'];
|
|
sonarrEpisodeId = $(this).attr("data-sonarrEpisodeId");
|
|
var languages = Array.from(seriesDetails['languages']);
|
|
var is_pb = languages.includes('pb');
|
|
var is_pt = languages.includes('pt');
|
|
|
|
const values = {
|
|
episodePath: episodePath,
|
|
sceneName: sceneName,
|
|
profileId: profileId,
|
|
sonarrSeriesId: sonarrSeriesId,
|
|
sonarrEpisodeId: sonarrEpisodeId,
|
|
title: seriesDetails['title']
|
|
};
|
|
|
|
$('#search_result').DataTable({
|
|
destroy: true,
|
|
language: {
|
|
zeroRecords: 'No Subtitles Found For This Episode',
|
|
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.episodessubtitlesmanualsearch') }}',
|
|
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-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>';
|
|
}
|
|
}
|
|
]
|
|
});
|
|
|
|
$('#manualSearchModal')
|
|
.modal({
|
|
focus: false
|
|
});
|
|
});
|
|
|
|
$('#search_result').on('click', '.manual_download', function (e) {
|
|
e.preventDefault();
|
|
const values = {
|
|
episodePath: $(this).attr("data-episodepath"),
|
|
sceneName: $(this).attr("data-scenename"),
|
|
language: $(this).attr("data-language"),
|
|
hi: seriesDetails['hearing_impaired'],
|
|
forced: $(this).attr("data-forced"),
|
|
provider: $(this).attr("data-provider"),
|
|
subtitle: $(this).attr("data-subtitle"),
|
|
sonarrSeriesId: seriesDetails['sonarrSeriesId'],
|
|
sonarrEpisodeId: $(this).attr('data-sonarrepisodeid'),
|
|
title: seriesDetails['title']
|
|
};
|
|
var cell = $(this).parent()
|
|
;
|
|
$.ajax({
|
|
url: "{{ url_for('api.episodessubtitlesmanualdownload') }}",
|
|
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');
|
|
}
|
|
});
|
|
});
|
|
|
|
$('#episodes').on('click', '.upload_subtitle', function (e) {
|
|
e.preventDefault();
|
|
$("#upload_series_title_span").html(seriesDetails['title'] + ' - ' + $(this).data("season") + 'x' + $(this).data("episode") + ' - ' + $(this).data("episode_title"));
|
|
$('#upload_episodePath').val($(this).data("episodepath"));
|
|
$('#upload_sceneName').val($(this).data("scenename"));
|
|
$('#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").length) ? $(this).data("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.episodessubtitlesupload') }}",
|
|
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.episodesscandisk', seriesid=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.episodessearchmissing', seriesid=id) }}",
|
|
type: 'GET',
|
|
beforeSend: function () {
|
|
$('#search_button').find("i").addClass('fa-spin');
|
|
},
|
|
complete: function () {
|
|
$('#search_button').find("i").removeClass('fa-spin');
|
|
}
|
|
});
|
|
});
|
|
|
|
const UploadStatus = {
|
|
ERROR: 0,
|
|
VALID: 1,
|
|
UPLOAD: 2,
|
|
DONE: 3
|
|
}
|
|
|
|
$('#mass_upload_button').on('click', function (e) {
|
|
e.preventDefault();
|
|
|
|
$('#upload_table').DataTable({
|
|
destroy: true,
|
|
processing: true,
|
|
language: {
|
|
zeroRecords: 'Select Subtitles to Get Started',
|
|
processing: "Loading Subtitle..."
|
|
},
|
|
searching: false,
|
|
ordering: false,
|
|
lengthChange: false,
|
|
serverSide: false,
|
|
responsive: true,
|
|
columns: [
|
|
{
|
|
data: null,
|
|
render: function(data, type, row) {
|
|
switch (data.status) {
|
|
case UploadStatus.VALID:
|
|
return '<i class="fas fa-check px-1"></i>'
|
|
case UploadStatus.UPLOAD:
|
|
return '<i class="spinner-border spinner-border-sm px-1" role="status" />'
|
|
case UploadStatus.DONE:
|
|
return '<i class="far fa-check-circle px-1"></i>'
|
|
case UploadStatus.ERROR:
|
|
default:
|
|
return '<i class="fas fa-exclamation-triangle px-1"></i>'
|
|
}
|
|
}
|
|
},
|
|
{data: 'filename'},
|
|
{
|
|
data: "season",
|
|
render: function(data, type, row) {
|
|
let cls = []
|
|
let readonly = false
|
|
if (data <= 0) {
|
|
if (row.status !== UploadStatus.UPLOAD) {
|
|
cls.push('is-invalid');
|
|
} else {
|
|
readonly = true
|
|
}
|
|
} else {
|
|
if (row.status === UploadStatus.UPLOAD) {
|
|
readonly = true;
|
|
}
|
|
}
|
|
return `<input type="text" ${readonly ? 'readonly' : ''} \
|
|
class="mass-upload-season-input form-control ${cls.join(' ')}" \
|
|
value="${data}" />`
|
|
}
|
|
},
|
|
{
|
|
data: "episode",
|
|
render: function(data, type, row) {
|
|
let cls = []
|
|
let readonly = false
|
|
if (data <= 0) {
|
|
if (row.status !== UploadStatus.UPLOAD) {
|
|
cls.push('is-invalid');
|
|
} else {
|
|
readonly = true
|
|
}
|
|
} else {
|
|
if (row.status === UploadStatus.UPLOAD) {
|
|
readonly = true;
|
|
}
|
|
}
|
|
return `<input type="text" ${readonly ? 'readonly' : ''} \
|
|
class="mass-upload-episode-input form-control ${cls.join(' ')}" \
|
|
value="${data}" />`
|
|
}
|
|
},
|
|
{
|
|
data: null,
|
|
render: function(data, type, row) {
|
|
return `<a href="" class="mass-upload-del-button badge badge-secondary"><i class="far fa-trash-alt"></i></a>`
|
|
}
|
|
}
|
|
]
|
|
})
|
|
|
|
// reset
|
|
$('#upload_table').DataTable().table().clear().draw();
|
|
$('#mass_upload_file_list').val("")
|
|
$('#mass-upload-file-label').text('Choose files')
|
|
|
|
$("#mass_upload_title_span")
|
|
.html(`${seriesDetails['title']} - Upload`);
|
|
|
|
$('#mass_upload_language_select')
|
|
.empty();
|
|
$.each(enabledLanguages, function (i, item) {
|
|
$('#mass_upload_language_select')
|
|
.append(`<option value="${item.code2}">${item.name}</option>`);
|
|
});
|
|
$("#mass_upload_language_select")
|
|
.selectpicker("refresh");
|
|
|
|
$('#mass_upload_forced_checkbox')
|
|
.val(seriesDetails['forced'])
|
|
.change();
|
|
|
|
$('#massUploadModal')
|
|
.modal({
|
|
focus: false
|
|
});
|
|
});
|
|
|
|
$('#upload_table').on('click', '.mass-upload-del-button', function(e) {
|
|
e.preventDefault();
|
|
$('#upload_table').DataTable()
|
|
.row($(this).parents('tr'))
|
|
.remove()
|
|
.draw();
|
|
});
|
|
|
|
$('#upload_table').on('change', '.mass-upload-season-input', function(e) {
|
|
const value = $(this).val();
|
|
|
|
let row = $('#upload_table').DataTable().row($(this).parents('tr'));
|
|
let data = row.data();
|
|
data.season = value;
|
|
|
|
data.status = UploadStatus.ERROR;
|
|
for(const exist of episodesDetails.data) {
|
|
if (exist.episode == data.episode && exist.season == data.season) {
|
|
data.status = UploadStatus.VALID;
|
|
data.exist = exist
|
|
break;
|
|
}
|
|
}
|
|
|
|
row.data(data).draw()
|
|
})
|
|
|
|
$('#upload_table').on('change', '.mass-upload-episode-input', function(e) {
|
|
const value = $(this).val();
|
|
|
|
let row = $('#upload_table').DataTable().row($(this).parents('tr'));
|
|
let data = row.data();
|
|
data.episode = value;
|
|
|
|
data.status = UploadStatus.ERROR;
|
|
for(const exist of episodesDetails.data) {
|
|
if (exist.episode == data.episode && exist.season == data.season) {
|
|
data.status = UploadStatus.VALID;
|
|
data.exist = exist
|
|
break;
|
|
}
|
|
}
|
|
|
|
row.data(data).draw()
|
|
})
|
|
|
|
$('#mass_upload_file_list').change(function() {
|
|
let filelist = $('#mass_upload_file_list').get(0).files
|
|
$('#mass-upload-file-label').text(`${filelist.length} Files`)
|
|
|
|
$('#mass_upload_save_button').prop('disabled', true)
|
|
$('#mass_upload_close_btn').prop('disabled', true);
|
|
$('#mass_upload_cancel_btn').prop('disabled', true);
|
|
|
|
let table = $('#upload_table').DataTable();
|
|
|
|
table.table().clear().draw();
|
|
|
|
const episodes = episodesDetails.data
|
|
|
|
let promiselist = []
|
|
|
|
for (const file of filelist) {
|
|
const name = file.name;
|
|
|
|
const object = {
|
|
file: file,
|
|
filename: name,
|
|
season: 0,
|
|
episode: 0,
|
|
status: UploadStatus.UPLOAD,
|
|
exist: null
|
|
}
|
|
|
|
const cacheRow = table.row.add(object)
|
|
|
|
promiselist.push(Promise.resolve($.ajax({
|
|
url: "{{ url_for('api.subtitlenameinfo') }}",
|
|
type: "GET",
|
|
dataType: "json",
|
|
data: {
|
|
filename: name
|
|
},
|
|
complete: function(data) {
|
|
const response = data.responseJSON.data;
|
|
const season = (response.season ?? 1);
|
|
|
|
let existdata = null
|
|
for(const exist of episodes) {
|
|
if (exist.episode == response.episode && exist.season == season) {
|
|
existdata = exist;
|
|
break;
|
|
}
|
|
}
|
|
|
|
let complete = {
|
|
file: file,
|
|
filename: name,
|
|
season: season,
|
|
episode: response.episode ?? 0,
|
|
status: existdata != null ? UploadStatus.VALID : UploadStatus.ERROR,
|
|
exist: existdata,
|
|
row: cacheRow
|
|
};
|
|
table.row(cacheRow).data(complete)
|
|
.draw();
|
|
|
|
},
|
|
error: function(data) {
|
|
let error = {
|
|
file: file,
|
|
filename: name,
|
|
season: 0,
|
|
episode: 0,
|
|
status: UploadStatus.ERROR,
|
|
exist: null,
|
|
row: cacheRow
|
|
};
|
|
table.row(cacheRow).data(error)
|
|
.draw();
|
|
}
|
|
})))
|
|
}
|
|
|
|
table.table().draw();
|
|
|
|
Promise.all(promiselist)
|
|
.then(function(){
|
|
$('#mass_upload_save_button').prop('disabled', false)
|
|
$('#mass_upload_close_btn').prop('disabled', false);
|
|
$('#mass_upload_cancel_btn').prop('disabled', false);
|
|
})
|
|
})
|
|
|
|
$('#mass_upload_form').on('submit', function(e) {
|
|
e.preventDefault();
|
|
$('#mass_upload_save_button').html('<div class="spinner-border spinner-border-sm" role="status"></div>');
|
|
|
|
const formdata = new FormData(document.getElementById("mass_upload_form"));
|
|
|
|
const language = formdata.get("language");
|
|
|
|
let table = $('#upload_table').DataTable();
|
|
|
|
const uploadlist = table.data().toArray().filter(function(item) {
|
|
return item.status === UploadStatus.VALID
|
|
});
|
|
|
|
const promiselist = uploadlist.map(function(item) {
|
|
const data = {
|
|
sonarrSeriesId: item.exist.sonarrSeriesId,
|
|
sonarrEpisodeId: item.exist.sonarrEpisodeId,
|
|
language: language,
|
|
upload: item.file,
|
|
episodePath: item.exist.mapped_path,
|
|
// sceneName,
|
|
title: item.exist.title,
|
|
audioLanguage: item.exist.audio_language.name,
|
|
forced: false
|
|
}
|
|
|
|
const form = new FormData()
|
|
for(const key in data) {
|
|
form.append(key, data[key])
|
|
}
|
|
|
|
const cacheRow = item.row ?? null
|
|
|
|
item.status = UploadStatus.UPLOAD;
|
|
|
|
let row = table.row(cacheRow);
|
|
|
|
row.data(item).draw()
|
|
|
|
return Promise.resolve($.ajax({
|
|
url: "{{ url_for('api.episodessubtitlesupload') }}",
|
|
data: form,
|
|
processData: false,
|
|
contentType: false,
|
|
type: 'POST',
|
|
complete: function(e) {
|
|
item.status = UploadStatus.DONE;
|
|
row.data(item).draw()
|
|
},
|
|
error: function(e) {
|
|
item.status = UploadStatus.ERROR;
|
|
row.data(item).draw()
|
|
}
|
|
}));
|
|
})
|
|
|
|
Promise.all(promiselist)
|
|
.then(function(){
|
|
$('#massUploadModal').modal('hide');
|
|
})
|
|
.catch(function() {
|
|
})
|
|
.finally(function() {
|
|
$('#mass_upload_save_button').html('Upload');
|
|
})
|
|
})
|
|
|
|
$('#edit_button').on('click', function (e) {
|
|
e.preventDefault();
|
|
$("#edit_series_title_span").html(seriesDetails['title']);
|
|
$("#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();
|
|
$('#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', ((seriesDetails['profileId'].id) ? seriesDetails['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.series') }}?seriesid={{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 () {
|
|
seriesDetailsRefresh();
|
|
$('#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.series === {{id}}) {
|
|
if (event_json.type === 'series' && event_json.action === 'update' && event_json.episode == null) {
|
|
seriesDetailsRefresh();
|
|
}
|
|
|
|
if (event_json.type === 'episode' && event_json.action === 'insert') {
|
|
$.ajax({
|
|
url: "{{ url_for('api.episodes') }}?seriesid=" + event_json.series + "&episodeid=" + event_json.episode,
|
|
success: function (data) {
|
|
if (data.data.length) {
|
|
$('#episodes').DataTable().rows.add(data.data);
|
|
$('#episodes').DataTable().columns.adjust().draw(false);
|
|
$('[data-toggle="tooltip"]').tooltip({html: true});
|
|
}
|
|
}
|
|
})
|
|
} else if (event_json.type === 'episode' && event_json.action === 'update') {
|
|
var rowId = $('#episodes').DataTable().row('#row_' + event_json.episode);
|
|
if (rowId.length) {
|
|
$.ajax({
|
|
url: "{{ url_for('api.episodes') }}?seriesid=" + event_json.series + "&episodeid=" + event_json.episode,
|
|
success: function (data) {
|
|
if (data.data.length) {
|
|
$('#episodes').DataTable().row(rowId).data(data.data[0]).draw('page');
|
|
$('[data-toggle="tooltip"]').tooltip({html: true});
|
|
}
|
|
}
|
|
})
|
|
}
|
|
} else if (event_json.type === 'episode' && event_json.action === 'delete') {
|
|
var rowId = $('#episodes').DataTable().row('#row_' + event_json.episode);
|
|
if (rowId.length) {
|
|
$('#episodes').DataTable().row(rowId).remove();
|
|
$('#episodes').DataTable().columns.adjust().draw(false);
|
|
$('[data-toggle="tooltip"]').tooltip({html: true});
|
|
}
|
|
}
|
|
}
|
|
|
|
if (event_json.type === 'episodeBlacklist' || event_json.type === 'episodeHistory') {
|
|
if ($('#episode_history_result').DataTable().ajax.json()) {
|
|
$('#episode_history_result').DataTable().ajax.reload(null, false);
|
|
$('[data-toggle="tooltip"]').tooltip({html: true});
|
|
}
|
|
}
|
|
});
|
|
|
|
$('#episodes').on('click', '.episode_history', function (e) {
|
|
$(this).tooltip('dispose');
|
|
e.preventDefault();
|
|
|
|
$("#episode_history_title_span").html(seriesDetails['title'] + ' - ' + $(this).data("season") + 'x' + $(this).data("episode") + ' - ' + $(this).data("episodetitle"));
|
|
|
|
sonarrEpisodeId = $(this).data("sonarrepisodeid");
|
|
|
|
$('#episode_history_result').DataTable({
|
|
destroy: true,
|
|
language: {
|
|
zeroRecords: 'No History Records Found For This Episode'
|
|
},
|
|
paging: true,
|
|
lengthChange: false,
|
|
pageLength: 5,
|
|
searching: true,
|
|
ordering: false,
|
|
scrollX: true,
|
|
processing: true,
|
|
serverSide: false,
|
|
ajax: {
|
|
url: '{{ url_for( 'api.episodeshistory' )}}?episodeid=' + sonarrEpisodeId
|
|
},
|
|
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-sonarrSeriesId="' + data.sonarrSeriesId + '" data-sonarrEpisodeId="' + data.sonarrEpisodeId + '" 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.mapped_subtitles_path + '"><i class="far fa-file-excel"></i></a>';
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
]
|
|
});
|
|
|
|
$('#episodeHistoryModal')
|
|
.modal({
|
|
focus: false
|
|
});
|
|
});
|
|
|
|
$('#episode_history_result').on('click', '.blacklist_subtitles', function (e) {
|
|
$(this).tooltip('dispose');
|
|
e.preventDefault();
|
|
const values = {
|
|
sonarr_series_id: $(this).attr('data-sonarrseriesid'),
|
|
sonarr_episode_id: $(this).attr('data-sonarrepisodeid'),
|
|
provider: $(this).attr('data-provider'),
|
|
subs_id: $(this).attr('data-subs_id'),
|
|
language: $(this).attr('data-language'),
|
|
forced: $(this).attr('data-forced'),
|
|
video_path: $(this).attr('data-video_path'),
|
|
subtitles_path: $(this).attr('data-subtitles_path'),
|
|
hi: $(this).attr('data-hi')
|
|
};
|
|
var cell = $(this).parent();
|
|
$.ajax({
|
|
url: "{{ url_for('api.blacklistepisodesubtitlesadd') }}",
|
|
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>');
|
|
}
|
|
});
|
|
});
|
|
|
|
$('#episodes').on('click', '.episode_tools', function (e) {
|
|
$(this).tooltip('dispose');
|
|
e.preventDefault();
|
|
|
|
$("#episode_tools_title_span").html(seriesDetails['title'] + ' - ' + $(this).data("season") + 'x' + $(this).data("episode") + ' - ' + $(this).data("episode_title"));
|
|
|
|
sonarrEpisodeId = $(this).data("sonarrepisodeid");
|
|
|
|
$('#episode_tools_result').DataTable({
|
|
destroy: true,
|
|
language: {
|
|
zeroRecords: 'No External Subtitles Found For This Episode'
|
|
},
|
|
paging: true,
|
|
lengthChange: false,
|
|
pageLength: 5,
|
|
searching: true,
|
|
ordering: false,
|
|
scrollX: true,
|
|
processing: false,
|
|
serverSide: false,
|
|
ajax: {
|
|
url: '{{ url_for( 'api.episodestools' )}}?episodeid=' + sonarrEpisodeId
|
|
},
|
|
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;
|
|
}
|
|
}
|
|
]
|
|
});
|
|
|
|
$('#episodeToolsModal')
|
|
.modal({
|
|
focus: false
|
|
});
|
|
});
|
|
|
|
$('#episode_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: 'series'
|
|
};
|
|
|
|
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 () {
|
|
$('#episodeToolsModal').modal('hide');
|
|
}
|
|
});
|
|
});
|
|
|
|
$('#episode_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 () {
|
|
$('#episodeToolsModal').modal('hide');
|
|
}
|
|
});
|
|
});
|
|
|
|
$('#episode_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"))
|
|
|
|
$('#episodeToolsModal').modal('hide');
|
|
$('#episodeSubtitleModColorModal')
|
|
.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 () {
|
|
$('#episodeSubtitleModColorModal').modal('hide');
|
|
}
|
|
});
|
|
});
|
|
|
|
$('#episodeSubtitleModColorModal').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>');
|
|
});
|
|
|
|
$('#episode_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"))
|
|
|
|
$('#episodeToolsModal').modal('hide');
|
|
$('#episodeSubtitleModFpsModal')
|
|
.modal({
|
|
focus: false
|
|
});
|
|
});
|
|
|
|
$('#episode_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");
|
|
|
|
$('#episodeToolsModal').modal('hide');
|
|
$('#episodeSubtitleTranslateModal')
|
|
.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 () {
|
|
$('#episodeSubtitleModFpsModal').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: 'series',
|
|
};
|
|
|
|
$.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 () {
|
|
$('#episodeSubtitleTranslateModal').modal('hide');
|
|
}
|
|
});
|
|
});
|
|
|
|
$('#episodeSubtitleModFpsModal').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>');
|
|
});
|
|
|
|
$('#episode_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"))
|
|
|
|
$('#episodeToolsModal').modal('hide');
|
|
$('#episodeSubtitleModOffsetModal')
|
|
.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 () {
|
|
$('#episodeSubtitleModOffsetModal').modal('hide');
|
|
}
|
|
});
|
|
});
|
|
|
|
$('#episodeSubtitleModOffsetModal').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>');
|
|
});
|
|
|
|
$('#episodeSubtitleTranslateModal').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>');
|
|
});
|
|
|
|
});
|
|
|
|
function episodesDetailsRefresh() {
|
|
$.ajax({
|
|
url: "{{ url_for('api.episodes') }}",
|
|
type: "GET",
|
|
dataType: "json",
|
|
data: {
|
|
seriesid: "{{id}}",
|
|
},
|
|
complete: function(data) {
|
|
const response = data.responseJSON;
|
|
episodesDetails = response
|
|
}
|
|
})
|
|
}
|
|
|
|
function seriesDetailsRefresh() {
|
|
$.ajax({
|
|
url: "{{ url_for('api.series') }}?seriesid={{id}}"
|
|
}).done(function (data) {
|
|
seriesDetails = data.data[0];
|
|
$(document).prop('title', seriesDetails['title'] + ' - Bazarr');
|
|
$('#seriesFanart').css('background-image', "url('{{ url_for('image_proxy', url='MediaCover/'+id+'/fanart.jpg') }}')");
|
|
$('#seriesPoster').attr("src", "{{ url_for('image_proxy', url='MediaCover/'+id+'/poster-250.jpg') }}");
|
|
$('#seriesTitle').text(seriesDetails['title']);
|
|
|
|
if (seriesDetails['alternateTitles'].length > 0) {
|
|
$('#seriesAlternateTitles').attr("data-original-title", "<b>Alternative Titles:</b><br>" + seriesDetails['alternateTitles']);
|
|
} else {
|
|
$('#seriesAlternateTitles').hide();
|
|
}
|
|
|
|
if (seriesDetails['tags'].length > 0) {
|
|
$('#seriesTags').attr("data-original-title", "<b>Tags:</b><br>" + seriesDetails['tags']);
|
|
} else {
|
|
$('#seriesTags').hide();
|
|
}
|
|
|
|
$("#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']);
|
|
|
|
$('#seriesSubtitlesLanguagesProfile').text(seriesDetails['profileId'].name);
|
|
|
|
$('#seriesDescription').text(seriesDetails['overview']);
|
|
|
|
if (seriesDetails['profileId'].id) {
|
|
$('#search_button').show();
|
|
} else {
|
|
$('#search_button').hide();
|
|
}
|
|
|
|
$('[data-toggle="tooltip"]').tooltip({html: true});
|
|
});
|
|
}
|
|
|
|
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 %}
|