working dyn video duration

This commit is contained in:
jr-k 2024-07-21 21:32:11 +02:00
parent e2a3eeaf43
commit 69620d806d
13 changed files with 87 additions and 10 deletions

View File

@ -162,5 +162,12 @@ jQuery(document).ready(function ($) {
showToast(l.js_common_copied); showToast(l.js_common_copied);
}); });
// Weird fix for toggle in modals
$(document).on('click', '.modal .toggle label', function (e) {
const $toggle = $(this).parents('.toggle:eq(0)');
const $checkbox = $toggle.find('input[type=checkbox]');
$checkbox.prop('checked', !$checkbox.prop('checked'));
});
}); });

View File

@ -98,7 +98,7 @@ jQuery(document).ready(function ($) {
$datetimepickerStart.toggleClass('hidden', !isDatetimeStart); $datetimepickerStart.toggleClass('hidden', !isDatetimeStart);
$datetimepickerEnd.toggleClass('hidden', !isDatetimeEnd); $datetimepickerEnd.toggleClass('hidden', !isDatetimeEnd);
$durationGroup.toggleClass('hidden', isNotification && isDatetimeEnd); $durationGroup.toggleClass('hidden', (isNotification && isDatetimeEnd) || parseInt($targetDuration.val()) === auto_duration_cheatcode);
$scheduleEndGroup.toggleClass('hidden', isLoopStart); $scheduleEndGroup.toggleClass('hidden', isLoopStart);
$durationGroup.find('.widget input').prop('required', $durationGroup.is(':visible')); $durationGroup.find('.widget input').prop('required', $durationGroup.is(':visible'));
@ -125,6 +125,18 @@ jQuery(document).ready(function ($) {
flushValues(); flushValues();
}; };
const inputAutoDurationUpdate = function (enableAutoDuration) {
const $modal = $('.modal-slide:visible');
const $input = $modal.find('.slide-auto-duration');
const $durationGroup = $modal.find('.slide-duration-group');
const $durationInput = $durationGroup.find('input');
const $autoDurationGroup = $modal.find('.slide-auto-duration-group');
const activeAutoDuration = $input.prop('checked');
$durationGroup.toggleClass('hidden', enableAutoDuration && activeAutoDuration);
$autoDurationGroup.toggleClass('hidden', !enableAutoDuration);
$durationInput.val(enableAutoDuration && activeAutoDuration ? auto_duration_cheatcode : 3);
};
const main = function () { const main = function () {
$("ul.slides").sortable({ $("ul.slides").sortable({
@ -147,7 +159,7 @@ jQuery(document).ready(function ($) {
$(document).on('click', '.content-explr-picker', function () { $(document).on('click', '.content-explr-picker', function () {
showPickers('modal-content-explr-picker', function (content) { showPickers('modal-content-explr-picker', function (content) {
inputContentUpdate(content) inputContentUpdate(content);
}); });
}); });
@ -157,8 +169,11 @@ jQuery(document).ready(function ($) {
const $inputLabel = $group.find('.target-label'); const $inputLabel = $group.find('.target-label');
const $inputId = $group.find('.target'); const $inputId = $group.find('.target');
const $actionShow = $group.find('.slide-content-show'); const $actionShow = $group.find('.slide-content-show');
const invalidContent = content === undefined || !content.id;
if (content === undefined || !content.id) { inputAutoDurationUpdate(!invalidContent && content.type === 'video');
if (invalidContent) {
$inputLabel.val(''); $inputLabel.val('');
$inputId.val(''); $inputId.val('');
$actionShow.addClass('hidden'); $actionShow.addClass('hidden');
@ -170,6 +185,10 @@ jQuery(document).ready(function ($) {
$actionShow.removeClass('hidden'); $actionShow.removeClass('hidden');
}; };
$(document).on('change', '.slide-auto-duration', function () {
inputAutoDurationUpdate(true);
});
$(document).on('click', '.slide-content-show', function () { $(document).on('click', '.slide-content-show', function () {
window.open($(this).attr('data-route').replace('__id__', $(this).parents('.widget:eq(0)').find('.target').val())); window.open($(this).attr('data-route').replace('__id__', $(this).parents('.widget:eq(0)').find('.target').val()));
}); });
@ -186,6 +205,9 @@ jQuery(document).ready(function ($) {
const hasDateTimeEnd = hasCronEnd && validateCronDateTime(slide.cron_schedule_end); const hasDateTimeEnd = hasCronEnd && validateCronDateTime(slide.cron_schedule_end);
const isNotification = slide.is_notification; const isNotification = slide.is_notification;
$modal.find('#slide-edit-auto-duration').prop('checked', slide.duration === auto_duration_cheatcode);
inputContentUpdate(slide.content); inputContentUpdate(slide.content);
$modal.find('input[type=text]:visible:eq(0)').focus().select(); $modal.find('input[type=text]:visible:eq(0)').focus().select();

View File

@ -33,6 +33,7 @@
"slideshow_slide_form_section_scheduling": "Scheduling", "slideshow_slide_form_section_scheduling": "Scheduling",
"slideshow_slide_form_label_name": "Name", "slideshow_slide_form_label_name": "Name",
"slideshow_slide_form_label_enabled": "Enable/Disable", "slideshow_slide_form_label_enabled": "Enable/Disable",
"slideshow_slide_form_label_auto_duration": "Use video's duration as timer",
"slideshow_slide_form_label_add_content": "Upload to library", "slideshow_slide_form_label_add_content": "Upload to library",
"slideshow_slide_form_label_from_library": "From library", "slideshow_slide_form_label_from_library": "From library",
"slideshow_slide_form_label_content_id": "Content", "slideshow_slide_form_label_content_id": "Content",

View File

@ -34,6 +34,7 @@
"slideshow_slide_form_label_name": "Nombre", "slideshow_slide_form_label_name": "Nombre",
"slideshow_slide_form_label_add_content": "Upload a la biblioteca", "slideshow_slide_form_label_add_content": "Upload a la biblioteca",
"slideshow_slide_form_label_enabled": "Activar/Desactivar", "slideshow_slide_form_label_enabled": "Activar/Desactivar",
"slideshow_slide_form_label_auto_duration": "Utilizar la duración del vídeo",
"slideshow_slide_form_label_from_library": "Dalla biblioteca", "slideshow_slide_form_label_from_library": "Dalla biblioteca",
"slideshow_slide_form_label_content_id": "Contenido", "slideshow_slide_form_label_content_id": "Contenido",
"slideshow_slide_form_label_location": "Ubicación", "slideshow_slide_form_label_location": "Ubicación",

View File

@ -33,6 +33,7 @@
"slideshow_slide_form_section_scheduling": "Programmation", "slideshow_slide_form_section_scheduling": "Programmation",
"slideshow_slide_form_label_name": "Nom", "slideshow_slide_form_label_name": "Nom",
"slideshow_slide_form_label_enabled": "Activer/Désactiver", "slideshow_slide_form_label_enabled": "Activer/Désactiver",
"slideshow_slide_form_label_auto_duration": "Utiliser la durée de la vidéo",
"slideshow_slide_form_label_add_content": "Upload à la bibliothèque", "slideshow_slide_form_label_add_content": "Upload à la bibliothèque",
"slideshow_slide_form_label_from_library": "Depuis la bibliothèque", "slideshow_slide_form_label_from_library": "Depuis la bibliothèque",
"slideshow_slide_form_label_content_id": "Contenu", "slideshow_slide_form_label_content_id": "Contenu",

View File

@ -33,6 +33,7 @@
"slideshow_slide_form_section_scheduling": "Programmazione", "slideshow_slide_form_section_scheduling": "Programmazione",
"slideshow_slide_form_label_name": "Nome", "slideshow_slide_form_label_name": "Nome",
"slideshow_slide_form_label_enabled": "Abilita/Disabilita", "slideshow_slide_form_label_enabled": "Abilita/Disabilita",
"slideshow_slide_form_label_auto_duration": "Utilizza la durata del video",
"slideshow_slide_form_label_add_content": "Upload alla biblioteca", "slideshow_slide_form_label_add_content": "Upload alla biblioteca",
"slideshow_slide_form_label_from_library": "Dalla biblioteca", "slideshow_slide_form_label_from_library": "Dalla biblioteca",
"slideshow_slide_form_label_content_id": "Contenuti", "slideshow_slide_form_label_content_id": "Contenuti",

View File

@ -8,7 +8,7 @@ from flask import Flask, render_template, redirect, request, url_for, send_from_
from pathlib import Path from pathlib import Path
from src.model.entity.Slide import Slide from src.model.entity.Slide import Slide
from src.model.enum.ContentType import ContentType from src.model.enum.ContentType import ContentType, AUTO_DURATION_CHEATCODE
from src.exceptions.NoFallbackPlaylistException import NoFallbackPlaylistException from src.exceptions.NoFallbackPlaylistException import NoFallbackPlaylistException
from src.service.ModelStore import ModelStore from src.service.ModelStore import ModelStore
from src.interface.ObController import ObController from src.interface.ObController import ObController
@ -60,7 +60,8 @@ class PlayerController(ObController):
slide_animation_enabled=animation_enabled, slide_animation_enabled=animation_enabled,
slide_animation_entrance_effect=slide_animation_entrance_effect, slide_animation_entrance_effect=slide_animation_entrance_effect,
slide_animation_speed=slide_animation_speed, slide_animation_speed=slide_animation_speed,
animation_speed_duration=animation_speed_duration animation_speed_duration=animation_speed_duration,
auto_duration_cheatcode=AUTO_DURATION_CHEATCODE
) )
def player_default(self): def player_default(self):
@ -167,8 +168,6 @@ class PlayerController(ObController):
'hard_refresh_request': self._model_store.variable().get_one_by_name("refresh_player_request").as_int() 'hard_refresh_request': self._model_store.variable().get_one_by_name("refresh_player_request").as_int()
} }
logging.info(playlists['loop'])
return playlists return playlists
def _check_slide_enablement(self, loop: List, notifications: List, slide: Dict) -> None: def _check_slide_enablement(self, loop: List, notifications: List, slide: Dict) -> None:

View File

@ -4,7 +4,7 @@ from flask import Flask, render_template, redirect, request, url_for, jsonify, a
from src.service.ModelStore import ModelStore from src.service.ModelStore import ModelStore
from src.model.entity.Playlist import Playlist from src.model.entity.Playlist import Playlist
from src.model.enum.FolderEntity import FolderEntity from src.model.enum.FolderEntity import FolderEntity
from src.model.enum.ContentType import ContentType from src.model.enum.ContentType import ContentType, AUTO_DURATION_CHEATCODE
from src.interface.ObController import ObController from src.interface.ObController import ObController
@ -49,6 +49,7 @@ class PlaylistController(ObController):
folders_tree=self._model_store.folder().get_folder_tree(FolderEntity.CONTENT), folders_tree=self._model_store.folder().get_folder_tree(FolderEntity.CONTENT),
enum_content_type=ContentType, enum_content_type=ContentType,
enum_folder_entity=FolderEntity, enum_folder_entity=FolderEntity,
auto_duration_cheatcode=AUTO_DURATION_CHEATCODE,
) )
def playlist_add(self): def playlist_add(self):

View File

@ -5,6 +5,8 @@ from typing import Union, List, Optional
from src.util.utils import str_to_enum from src.util.utils import str_to_enum
AUTO_DURATION_CHEATCODE = 98769876
class ContentInputType(Enum): class ContentInputType(Enum):

View File

@ -75,6 +75,7 @@
let clockValue = 0; let clockValue = 0;
let curItemIndex = -1; let curItemIndex = -1;
let secondsBeforeNext = 0; let secondsBeforeNext = 0;
const durationsOverride = {};
const introSlide = document.getElementById('IntroSlide'); const introSlide = document.getElementById('IntroSlide');
const notificationSlide = document.getElementById('NotificationSlide'); const notificationSlide = document.getElementById('NotificationSlide');
const firstSlide = document.getElementById('FirstSlide'); const firstSlide = document.getElementById('FirstSlide');
@ -157,6 +158,10 @@
pause(); pause();
}; };
const isDurationAuto = function(duration) {
return duration === {{ auto_duration_cheatcode }};
} ;
const lookupPreviousItem = function() { const lookupPreviousItem = function() {
return (curItemIndex - 1 < 0) ? items.loop[items.loop.length - 1] : items.loop[curItemIndex - 1]; return (curItemIndex - 1 < 0) ? items.loop[items.loop.length - 1] : items.loop[curItemIndex - 1];
}; };
@ -191,7 +196,14 @@
if (!item) { if (!item) {
return tickRefreshResolutionMs/1000; return tickRefreshResolutionMs/1000;
} }
return item.duration + Math.ceil(animation_speed_duration/1000);
let duration = item.duration;
if (durationsOverride[item.id]) {
duration = durationsOverride[item.id];
}
return duration + Math.ceil(animation_speed_duration/1000);
}; };
const main = function() { const main = function() {
@ -363,7 +375,8 @@
delayNoisyContentJIT = lookupCurrentItem().id !== item.id ? delayNoisyContentJIT : 0; delayNoisyContentJIT = lookupCurrentItem().id !== item.id ? delayNoisyContentJIT : 0;
video.addEventListener('loadedmetadata', function() { video.addEventListener('loadedmetadata', function() {
if (item.duration !== video.duration) { if (item.duration !== video.duration && isDurationAuto(item.duration)) {
durationsOverride[item.id] = video.duration;
console.warn('Given duration ' + item.duration + 's is different from video file ' + Math.ceil(video.duration) + 's'); console.warn('Given duration ' + item.duration + 's is different from video file ' + Math.ceil(video.duration) + 's');
} }
}); });

View File

@ -13,6 +13,7 @@
{% block add_js %} {% block add_js %}
<script type="text/javascript"> <script type="text/javascript">
var auto_duration_cheatcode = {{ auto_duration_cheatcode }};
var route_slide_position = '{{ url_for('slideshow_slide_position') }}'; var route_slide_position = '{{ url_for('slideshow_slide_position') }}';
var choices_translations = { var choices_translations = {

View File

@ -81,6 +81,24 @@
</div> </div>
</div> </div>
<div class="form-group form-group-horizontal slide-auto-duration-group">
<label for="">{{ l.slideshow_slide_form_label_auto_duration }}</label>
<div class="widget">
<div class="toggle">
<input type="checkbox" class="slide-auto-duration" id="slide-add-auto-duration" />
<label for="slide-add-auto-duration"></label>
</div>
</div>
</div>
<div class="form-group slide-duration-group">
<label for="slide-add-duration">{{ l.slideshow_slide_form_label_duration }}</label>
<div class="widget widget-unit">
<input type="number" name="duration" id="slide-add-duration" required="required" value="3" />
<span class="unit">{{ l.slideshow_slide_form_label_duration_unit }}</span>
</div>
</div>
<div class="actions"> <div class="actions">
<button type="button" class="btn btn-naked modal-close"> <button type="button" class="btn btn-naked modal-close">
{{ l.common_close }} {{ l.common_close }}

View File

@ -72,6 +72,16 @@
</div> </div>
</div> </div>
<div class="form-group form-group-horizontal slide-auto-duration-group">
<label for="">{{ l.slideshow_slide_form_label_auto_duration }}</label>
<div class="widget">
<div class="toggle">
<input type="checkbox" class="slide-auto-duration" id="slide-edit-auto-duration" />
<label for="slide-edit-auto-duration"></label>
</div>
</div>
</div>
<div class="form-group slide-duration-group"> <div class="form-group slide-duration-group">
<label for="slide-edit-duration">{{ l.slideshow_slide_form_label_duration }}</label> <label for="slide-edit-duration">{{ l.slideshow_slide_form_label_duration }}</label>
<div class="widget widget-unit"> <div class="widget widget-unit">