Release v2.4.2
This commit is contained in:
+48
-24
@@ -60,7 +60,7 @@ function createPlayerPlaylistService(options) {
|
||||
try {
|
||||
const [screenRows] = await pool.query('SELECT id, name, slug, playlist_id, created_at, modified_at, created_by, modified_by FROM d_screens WHERE slug = ?', [slug]);
|
||||
if (!screenRows.length) {
|
||||
return { screen: null, playlist: null, slides: [], rssFeeds: [], apiSources: [], scheduleGroups: [] };
|
||||
return { screen: null, playlist: null, slides: [], rssFeeds: [], apiSources: [], timetableGroups: [] };
|
||||
}
|
||||
|
||||
const screen = screenRows[0];
|
||||
@@ -71,8 +71,8 @@ function createPlayerPlaylistService(options) {
|
||||
slides: [],
|
||||
rssFeeds: [],
|
||||
apiSources: [],
|
||||
scheduleGroups: [],
|
||||
revision: getPlaylistRevision(screen, null, [], [], [], [], [])
|
||||
timetableGroups: [],
|
||||
revision: getPlaylistRevision(screen, null, [], [], [], [], [], [])
|
||||
};
|
||||
await writeSnapshot(slug, payloadWithoutPlaylist);
|
||||
return payloadWithoutPlaylist;
|
||||
@@ -82,7 +82,7 @@ function createPlayerPlaylistService(options) {
|
||||
const playlist = playlistRows[0] || null;
|
||||
const [slideRows] = await pool.query(`
|
||||
SELECT sl.id, sl.title, sl.template_id, sl.content_json, sl.created_at, sl.modified_at,
|
||||
ps.position, ps.duration_seconds AS duration_seconds, ps.use_video_duration, ps.schedule_mode, ps.schedule_start_datetime, ps.schedule_end_datetime, ps.schedule_start_time, ps.schedule_end_time, ps.schedule_days_json,
|
||||
ps.position, ps.duration_seconds AS duration_seconds, ps.use_video_duration, ps.disable_audio,
|
||||
st.name AS template_name, cs.name AS canvas_size_name, cs.width AS canvas_size_width, cs.height AS canvas_size_height, cs.width AS canvas_width, cs.height AS canvas_height
|
||||
FROM c_playlist_slides ps
|
||||
JOIN c_slides sl ON sl.id = ps.slide_id
|
||||
@@ -91,6 +91,21 @@ function createPlayerPlaylistService(options) {
|
||||
WHERE ps.playlist_id = ?
|
||||
ORDER BY ps.position ASC, ps.id ASC
|
||||
`, [screen.playlist_id]);
|
||||
const [scheduleRuleRows] = await pool.query(`
|
||||
SELECT r.id, r.playlist_slide_id, r.position, r.start_datetime, r.end_datetime, r.start_time, r.end_time, r.schedule_days_json, r.created_at, r.modified_at, r.created_by, r.modified_by
|
||||
FROM c_playlist_slide_schedule_rules r
|
||||
JOIN c_playlist_slides ps ON ps.id = r.playlist_slide_id
|
||||
WHERE ps.playlist_id = ?
|
||||
ORDER BY r.playlist_slide_id ASC, r.position ASC, r.id ASC
|
||||
`, [screen.playlist_id]);
|
||||
const rulesBySlideId = {};
|
||||
scheduleRuleRows.forEach(function (rule) {
|
||||
const slideId = Number(rule.playlist_slide_id);
|
||||
if (!rulesBySlideId[slideId]) {
|
||||
rulesBySlideId[slideId] = [];
|
||||
}
|
||||
rulesBySlideId[slideId].push(rule);
|
||||
});
|
||||
|
||||
const templateIds = slideRows
|
||||
.filter(function (slide) { return slide.template_id; })
|
||||
@@ -138,10 +153,17 @@ function createPlayerPlaylistService(options) {
|
||||
const slides = slideRows.map(function (slide) {
|
||||
const storedDuration = Number(slide.duration_seconds || 0);
|
||||
const videoDuration = slide.use_video_duration ? getVideoRegionDurationSeconds(slide.content_json) : null;
|
||||
const disableAudio = slide.disable_audio === undefined || slide.disable_audio === null ? true : Boolean(slide.disable_audio);
|
||||
const videoCacheBust = String(slide.modified_at || slide.content_json || slide.id || '');
|
||||
const content = common.parseJsonSafe(slide.content_json) || {};
|
||||
Object.keys(content).forEach(function (key) {
|
||||
const region = content[key];
|
||||
if (region && typeof region === 'object') {
|
||||
const regionType = String(region.type || '').trim().toLowerCase();
|
||||
if (regionType === 'video' || regionType === 'rtmp') {
|
||||
region.disable_audio = disableAudio;
|
||||
}
|
||||
}
|
||||
if (region && typeof region === 'object' && String(region.type || '').trim().toLowerCase() === 'video') {
|
||||
region.cache_bust = videoCacheBust;
|
||||
}
|
||||
@@ -152,12 +174,8 @@ function createPlayerPlaylistService(options) {
|
||||
modified_at: slide.modified_at,
|
||||
duration_seconds: videoDuration || storedDuration,
|
||||
use_video_duration: Boolean(slide.use_video_duration),
|
||||
schedule_mode: slide.schedule_mode,
|
||||
schedule_start_datetime: slide.schedule_start_datetime,
|
||||
schedule_end_datetime: slide.schedule_end_datetime,
|
||||
schedule_start_time: slide.schedule_start_time,
|
||||
schedule_end_time: slide.schedule_end_time,
|
||||
schedule_days_json: slide.schedule_days_json,
|
||||
disable_audio: disableAudio,
|
||||
scheduleRules: rulesBySlideId[Number(slide.id)] || [],
|
||||
template_id: slide.template_id,
|
||||
template: slide.template_id ? templatesById[slide.template_id] || null : null,
|
||||
content: content
|
||||
@@ -187,14 +205,14 @@ function createPlayerPlaylistService(options) {
|
||||
});
|
||||
}
|
||||
|
||||
let scheduleGroups = [];
|
||||
if (typeof common.fetchSchedulesData === 'function') {
|
||||
const scheduleData = await common.fetchSchedulesData(pool);
|
||||
scheduleGroups = Array.isArray(scheduleData && scheduleData.scheduleGroups) ? scheduleData.scheduleGroups : [];
|
||||
let timetableGroups = [];
|
||||
if (typeof common.fetchTimetablesData === 'function') {
|
||||
const timetableData = await common.fetchTimetablesData(pool);
|
||||
timetableGroups = Array.isArray(timetableData && timetableData.timetableGroups) ? timetableData.timetableGroups : [];
|
||||
}
|
||||
|
||||
const revision = getPlaylistRevision(screen, playlist, slideRows, templateRows, regionRows, rssFeeds, apiSources, scheduleGroups);
|
||||
const payload = { screen: screen, playlist: playlist, slides: slides, rssFeeds: rssFeeds, apiSources: apiSources, scheduleGroups: scheduleGroups, revision: revision };
|
||||
const revision = getPlaylistRevision(screen, playlist, slideRows, scheduleRuleRows, templateRows, regionRows, rssFeeds, apiSources, timetableGroups);
|
||||
const payload = { screen: screen, playlist: playlist, slides: slides, rssFeeds: rssFeeds, apiSources: apiSources, timetableGroups: timetableGroups, revision: revision };
|
||||
await writeSnapshot(slug, payload);
|
||||
return payload;
|
||||
} catch (error) {
|
||||
@@ -211,7 +229,7 @@ function createPlayerPlaylistService(options) {
|
||||
hash.update('\0');
|
||||
}
|
||||
|
||||
function getPlaylistRevision(screen, playlist, slideRows, templateRows, regionRows, rssFeeds, apiSources, scheduleGroups) {
|
||||
function getPlaylistRevision(screen, playlist, slideRows, scheduleRuleRows, templateRows, regionRows, rssFeeds, apiSources, timetableGroups) {
|
||||
const hash = crypto.createHash('sha1');
|
||||
|
||||
updatePlaylistRevisionHash(hash, screen && screen.id);
|
||||
@@ -232,12 +250,18 @@ function createPlayerPlaylistService(options) {
|
||||
updatePlaylistRevisionHash(hash, slide.position);
|
||||
updatePlaylistRevisionHash(hash, slide.duration_seconds);
|
||||
updatePlaylistRevisionHash(hash, slide.use_video_duration);
|
||||
updatePlaylistRevisionHash(hash, slide.schedule_mode);
|
||||
updatePlaylistRevisionHash(hash, slide.schedule_start_datetime);
|
||||
updatePlaylistRevisionHash(hash, slide.schedule_end_datetime);
|
||||
updatePlaylistRevisionHash(hash, slide.schedule_start_time);
|
||||
updatePlaylistRevisionHash(hash, slide.schedule_end_time);
|
||||
updatePlaylistRevisionHash(hash, slide.schedule_days_json);
|
||||
updatePlaylistRevisionHash(hash, slide.disable_audio);
|
||||
});
|
||||
|
||||
(Array.isArray(scheduleRuleRows) ? scheduleRuleRows : []).forEach(function (rule) {
|
||||
updatePlaylistRevisionHash(hash, rule.id);
|
||||
updatePlaylistRevisionHash(hash, rule.playlist_slide_id);
|
||||
updatePlaylistRevisionHash(hash, rule.position);
|
||||
updatePlaylistRevisionHash(hash, rule.start_datetime);
|
||||
updatePlaylistRevisionHash(hash, rule.end_datetime);
|
||||
updatePlaylistRevisionHash(hash, rule.start_time);
|
||||
updatePlaylistRevisionHash(hash, rule.end_time);
|
||||
updatePlaylistRevisionHash(hash, rule.schedule_days_json);
|
||||
});
|
||||
|
||||
(Array.isArray(templateRows) ? templateRows : []).forEach(function (template) {
|
||||
@@ -268,7 +292,7 @@ function createPlayerPlaylistService(options) {
|
||||
|
||||
updatePlaylistRevisionHash(hash, JSON.stringify(rssFeeds || []));
|
||||
updatePlaylistRevisionHash(hash, JSON.stringify(apiSources || []));
|
||||
updatePlaylistRevisionHash(hash, JSON.stringify(scheduleGroups || []));
|
||||
updatePlaylistRevisionHash(hash, JSON.stringify(timetableGroups || []));
|
||||
|
||||
return hash.digest('hex');
|
||||
}
|
||||
|
||||
@@ -165,7 +165,7 @@ function renderSlideMarkup(markup, shouldFade) {
|
||||
|
||||
video.autoplay = true;
|
||||
video.loop = true;
|
||||
video.muted = true;
|
||||
video.muted = !(video.dataset && video.dataset.disableAudio === '0');
|
||||
video.playsInline = true;
|
||||
|
||||
function startPlayback() {
|
||||
|
||||
@@ -340,31 +340,82 @@ function parseTimeToMinutes(value) {
|
||||
return Number(match[1]) * 60 + Number(match[2]);
|
||||
}
|
||||
|
||||
// Determine whether a slide should be shown at the current time.
|
||||
function isSlideActive(slide, now) {
|
||||
const mode = String(slide.schedule_mode || 'always');
|
||||
if (mode === 'always') {
|
||||
return true;
|
||||
function normalizeScheduleRule(rule) {
|
||||
const input = rule && typeof rule === 'object' ? rule : {};
|
||||
const startDatetime = String(input.start_datetime || input.startDateTime || '').trim();
|
||||
const endDatetime = String(input.end_datetime || input.endDateTime || '').trim();
|
||||
const startTime = String(input.start_time || input.startTime || '').trim();
|
||||
const endTime = String(input.end_time || input.endTime || '').trim();
|
||||
const days = parseScheduleDays(input.days);
|
||||
|
||||
if (startDatetime || endDatetime) {
|
||||
if (!startDatetime || !endDatetime) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (mode === 'dates') {
|
||||
const start = slide.schedule_start_datetime ? new Date(slide.schedule_start_datetime) : null;
|
||||
const end = slide.schedule_end_datetime ? new Date(slide.schedule_end_datetime) : null;
|
||||
if (!start || !end || Number.isNaN(start.getTime()) || Number.isNaN(end.getTime())) {
|
||||
return false;
|
||||
if (startTime || endTime) {
|
||||
if (!startTime || !endTime) {
|
||||
return null;
|
||||
}
|
||||
return now >= start && now <= end;
|
||||
}
|
||||
if (mode === 'times') {
|
||||
const days = parseScheduleDays(slide.schedule_days_json);
|
||||
if (!days.length) {
|
||||
if (!startDatetime && !endDatetime && !startTime && !endTime && !days.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
start_datetime: startDatetime || null,
|
||||
end_datetime: endDatetime || null,
|
||||
start_time: startTime || null,
|
||||
end_time: endTime || null,
|
||||
days: days
|
||||
};
|
||||
}
|
||||
|
||||
function parseScheduleRules(value) {
|
||||
let rawRules = [];
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
rawRules = value;
|
||||
} else {
|
||||
const raw = String(value || '').trim();
|
||||
if (!raw) {
|
||||
return [];
|
||||
}
|
||||
try {
|
||||
const parsed = JSON.parse(raw);
|
||||
rawRules = Array.isArray(parsed) ? parsed : [];
|
||||
} catch (_error) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
return rawRules.map(normalizeScheduleRule).filter(Boolean);
|
||||
}
|
||||
|
||||
function matchesScheduleRule(rule, now) {
|
||||
const normalized = normalizeScheduleRule(rule);
|
||||
if (!normalized) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (normalized.start_datetime && normalized.end_datetime) {
|
||||
const start = new Date(normalized.start_datetime);
|
||||
const end = new Date(normalized.end_datetime);
|
||||
if (Number.isNaN(start.getTime()) || Number.isNaN(end.getTime())) {
|
||||
return false;
|
||||
}
|
||||
const day = now.getDay();
|
||||
if (days.indexOf(day) === -1) {
|
||||
if (now < start || now > end) {
|
||||
return false;
|
||||
}
|
||||
const startMinutes = parseTimeToMinutes(slide.schedule_start_time);
|
||||
const endMinutes = parseTimeToMinutes(slide.schedule_end_time);
|
||||
}
|
||||
|
||||
if (normalized.days.length && normalized.days.indexOf(now.getDay()) === -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (normalized.start_time && normalized.end_time) {
|
||||
const startMinutes = parseTimeToMinutes(normalized.start_time);
|
||||
const endMinutes = parseTimeToMinutes(normalized.end_time);
|
||||
if (startMinutes === null || endMinutes === null) {
|
||||
return false;
|
||||
}
|
||||
@@ -374,8 +425,20 @@ function isSlideActive(slide, now) {
|
||||
}
|
||||
return nowMinutes >= startMinutes || nowMinutes <= endMinutes;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Determine whether a slide should be shown at the current time.
|
||||
function isSlideActive(slide, now) {
|
||||
const rules = Array.isArray(slide.scheduleRules) ? slide.scheduleRules : [];
|
||||
if (!rules.length) {
|
||||
return true;
|
||||
}
|
||||
return rules.some(function (rule) {
|
||||
return matchesScheduleRule(rule, now);
|
||||
});
|
||||
}
|
||||
// Build the cache key for a template layout.
|
||||
function getTemplateLayoutCacheKey(template) {
|
||||
var viewportKey = window.innerWidth + 'x' + window.innerHeight;
|
||||
|
||||
@@ -8,7 +8,7 @@ function renderRtmpRegion(region, regionContent) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return '<div class="template-region rtmp" style="' + region.baseStyle + '"><video class="template-region-rtmp-video" data-rtmp-source="' + escapeHtml(url) + '" data-rtmp-disable-audio="' + (disableAudio ? '1' : '0') + '" data-rtmp-skip-unavailable="' + (skipUnavailable ? '1' : '0') + '" autoplay playsinline preload="auto" tabindex="-1" disablepictureinpicture></video><div class="template-region-placeholder template-region-rtmp-placeholder">Loading RTMP stream...</div></div>';
|
||||
return '<div class="template-region rtmp" style="' + region.baseStyle + '"><video class="template-region-rtmp-video" data-rtmp-source="' + escapeHtml(url) + '" data-rtmp-disable-audio="' + (disableAudio ? '1' : '0') + '" data-rtmp-skip-unavailable="' + (skipUnavailable ? '1' : '0') + '" autoplay playsinline preload="auto" tabindex="-1" disablepictureinpicture' + (disableAudio ? ' muted' : '') + '></video><div class="template-region-placeholder template-region-rtmp-placeholder">Loading RTMP stream...</div></div>';
|
||||
}
|
||||
|
||||
function getRtmpSessionUrl(sourceUrl, disableAudio) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Schedule region rendering for live playback.
|
||||
// Timetable region rendering for live playback.
|
||||
|
||||
var registry = window.pulsePlayerRegionTypes;
|
||||
|
||||
@@ -97,7 +97,7 @@ function sanitizeRichText(html) {
|
||||
});
|
||||
}
|
||||
|
||||
function substituteScheduleVariables(html, entry) {
|
||||
function substituteTimetableVariables(html, entry) {
|
||||
var source = String(html || '');
|
||||
return source.replace(/\{\{\s*([^{}]+?)\s*\}\}/g, function (_match, expression) {
|
||||
if (!entry || typeof entry !== 'object') {
|
||||
@@ -117,16 +117,16 @@ function renderTemplate(template, context) {
|
||||
if (!source) {
|
||||
return '';
|
||||
}
|
||||
return substituteScheduleVariables(source, context);
|
||||
return substituteTimetableVariables(source, context);
|
||||
}
|
||||
|
||||
function getScheduleGroups() {
|
||||
return Array.isArray(initialData && initialData.scheduleGroups) ? initialData.scheduleGroups : [];
|
||||
function getTimetableGroups() {
|
||||
return Array.isArray(initialData && initialData.timetableGroups) ? initialData.timetableGroups : [];
|
||||
}
|
||||
|
||||
function getGroupById(groupId, groups) {
|
||||
var normalizedId = Number(groupId || 0);
|
||||
return (Array.isArray(groups) ? groups : getScheduleGroups()).find(function (group) {
|
||||
return (Array.isArray(groups) ? groups : getTimetableGroups()).find(function (group) {
|
||||
return Number(group.id) === normalizedId;
|
||||
}) || null;
|
||||
}
|
||||
@@ -174,6 +174,12 @@ function getVisibleEntries(groupId, displayMode, maxItems, groups) {
|
||||
return isUpcoming(entry, now);
|
||||
});
|
||||
|
||||
if (!entries.length && mode === 'upcoming') {
|
||||
entries = getEntries(groupId, groups).filter(function (entry) {
|
||||
return isLive(entry, now);
|
||||
});
|
||||
}
|
||||
|
||||
return entries.slice(0, Math.max(1, Number(maxItems || 5)));
|
||||
}
|
||||
|
||||
@@ -216,22 +222,23 @@ function getTextStyle(region, regionContent) {
|
||||
function renderRegion(region, regionContent) {
|
||||
var value = String(regionContent && (regionContent.value !== undefined ? regionContent.value : regionContent.text !== undefined ? regionContent.text : '') || '').trim();
|
||||
var style = getTextStyle(region, regionContent || {});
|
||||
var groups = getScheduleGroups();
|
||||
var groupId = regionContent && regionContent.schedule_group_id !== undefined ? regionContent.schedule_group_id : '';
|
||||
var groups = getTimetableGroups();
|
||||
var groupId = regionContent && regionContent.timetable_group_id !== undefined ? regionContent.timetable_group_id : '';
|
||||
var displayMode = regionContent && regionContent.display_mode ? regionContent.display_mode : 'upcoming';
|
||||
var maxItems = regionContent && regionContent.max_items !== undefined ? regionContent.max_items : 5;
|
||||
var group = getGroupById(groupId, groups);
|
||||
var entries = getVisibleEntries(groupId, displayMode, maxItems, groups);
|
||||
if (!entries.length) {
|
||||
entries = getEntries(groupId, groups).slice(0, Math.max(1, Number(maxItems || 5)));
|
||||
}
|
||||
var width = Math.max(1, Math.round(Number(region && region.pixelWidth ? region.pixelWidth : 0) || 1));
|
||||
var height = Math.max(1, Math.round(Number(region && region.pixelHeight ? region.pixelHeight : 0) || 1));
|
||||
var canvasScale = Number(region && region.canvasScale ? region.canvasScale : 1) || 1;
|
||||
var contentStyle = 'width:' + width + 'px;height:' + height + 'px;transform:scale(' + canvasScale + ');transform-origin:top left;' + (style.font_family ? 'font-family:' + escapeHtml(style.font_family) + ';' : '') + (style.font_size ? 'font-size:' + Math.max(1, Math.round(Number(style.font_size))) + 'px;' : '') + (style.font_color ? 'color:' + escapeHtml(style.font_color) + ';' : '');
|
||||
|
||||
if (!value) {
|
||||
return '<div class="template-region schedule" style="' + region.baseStyle + '"><div class="template-region-text-scale" style="width:100%;height:100%;overflow:hidden;' + (style.font_family ? 'font-family:' + escapeHtml(style.font_family) + ';' : '') + (style.font_size ? 'font-size:' + Math.max(1, Math.round(Number(style.font_size))) + 'px;' : '') + (style.font_color ? 'color:' + escapeHtml(style.font_color) + ';' : '') + '"></div></div>';
|
||||
return '<div class="template-region timetable" style="' + region.baseStyle + '"><div class="template-region-text-scale" style="' + contentStyle + ' overflow:hidden;"></div></div>';
|
||||
}
|
||||
|
||||
return '<div class="template-region schedule" style="' + region.baseStyle + '"><div class="template-region-text-scale" style="width:100%;height:100%;overflow:hidden;' + (style.font_family ? 'font-family:' + escapeHtml(style.font_family) + ';' : '') + (style.font_size ? 'font-size:' + Math.max(1, Math.round(Number(style.font_size))) + 'px;' : '') + (style.font_color ? 'color:' + escapeHtml(style.font_color) + ';' : '') + '">' + entries.map(function (entry, index) {
|
||||
return '<div class="schedule-region-entry" data-schedule-entry-index="' + index + '">' + sanitizeRichText(substituteScheduleVariables(value, Object.assign({}, entry || {}, {
|
||||
return '<div class="template-region timetable" style="' + region.baseStyle + '"><div class="template-region-text-scale" style="' + contentStyle + ' overflow:hidden;">' + entries.map(function (entry, index) {
|
||||
return '<div class="timetable-region-entry" data-timetable-entry-index="' + index + '">' + sanitizeRichText(substituteTimetableVariables(value, Object.assign({}, entry || {}, {
|
||||
start: entry && entry.start_datetime !== undefined ? entry.start_datetime : '',
|
||||
end: entry && entry.end_datetime !== undefined ? entry.end_datetime : '',
|
||||
group: group || {},
|
||||
@@ -241,6 +248,6 @@ function renderRegion(region, regionContent) {
|
||||
}).join('') + '</div></div>';
|
||||
}
|
||||
|
||||
registry.register('schedule', {
|
||||
registry.register('timetable', {
|
||||
renderRegion: renderRegion
|
||||
});
|
||||
@@ -111,6 +111,7 @@ function renderVideoRegion(region, regionContent) {
|
||||
var regionKey = getVideoRegionCacheKey(region);
|
||||
var cachedSrc = regionKey ? String(videoRegionLastGoodSrcCache[regionKey] || '').trim() : '';
|
||||
var cachedSrcVersioned = appendCacheBust(cachedSrc, regionContent && regionContent.cache_bust);
|
||||
var disableAudio = regionContent && regionContent.disable_audio === undefined ? true : Boolean(regionContent && regionContent.disable_audio);
|
||||
|
||||
if (!requestedSrc) {
|
||||
return '';
|
||||
@@ -121,7 +122,7 @@ function renderVideoRegion(region, regionContent) {
|
||||
videoRegionLastGoodSrcCache[regionKey] = requestedSrc;
|
||||
}
|
||||
setVideoSourceAvailability(requestedSrc, true);
|
||||
return '<div class="template-region video" style="' + region.baseStyle + '"><video src="' + escapeHtml(requestedSrcVersioned) + '" title="' + escapeHtml(region.label) + '" autoplay muted loop playsinline preload="auto" disablepictureinpicture oncanplay="this.play().catch(function () {})" onloadedmetadata="this.play().catch(function () {})"></video></div>';
|
||||
return '<div class="template-region video" style="' + region.baseStyle + '"><video src="' + escapeHtml(requestedSrcVersioned) + '" title="' + escapeHtml(region.label) + '" data-disable-audio="' + (disableAudio ? '1' : '0') + '" autoplay' + (disableAudio ? ' muted' : '') + ' loop playsinline preload="auto" disablepictureinpicture oncanplay="this.play().catch(function () {})" onloadedmetadata="this.play().catch(function () {})"></video></div>';
|
||||
}
|
||||
|
||||
var requestedState = getVideoSourceAvailability(requestedSrc);
|
||||
@@ -131,7 +132,7 @@ function renderVideoRegion(region, regionContent) {
|
||||
if (regionKey) {
|
||||
videoRegionLastGoodSrcCache[regionKey] = requestedSrc;
|
||||
}
|
||||
return '<div class="template-region video" style="' + region.baseStyle + '"><video src="' + escapeHtml(requestedSrcVersioned) + '" title="' + escapeHtml(region.label) + '" autoplay muted loop playsinline preload="auto" disablepictureinpicture oncanplay="this.play().catch(function () {})" onloadedmetadata="this.play().catch(function () {})"></video></div>';
|
||||
return '<div class="template-region video" style="' + region.baseStyle + '"><video src="' + escapeHtml(requestedSrcVersioned) + '" title="' + escapeHtml(region.label) + '" data-disable-audio="' + (disableAudio ? '1' : '0') + '" autoplay' + (disableAudio ? ' muted' : '') + ' loop playsinline preload="auto" disablepictureinpicture oncanplay="this.play().catch(function () {})" onloadedmetadata="this.play().catch(function () {})"></video></div>';
|
||||
}
|
||||
|
||||
scheduleVideoSourceProbe(regionKey, requestedSrc, false);
|
||||
@@ -140,7 +141,7 @@ function renderVideoRegion(region, regionContent) {
|
||||
if (cachedSrc !== requestedSrc) {
|
||||
logVideoRegionStatus('Keeping the previous playable video until the new mirrored file finishes transferring.', 'region=' + regionKey + ' old=' + cachedSrc + ' new=' + requestedSrc);
|
||||
}
|
||||
return '<div class="template-region video" style="' + region.baseStyle + '"><video src="' + escapeHtml(cachedSrcVersioned) + '" title="' + escapeHtml(region.label) + '" autoplay muted loop playsinline preload="auto" disablepictureinpicture oncanplay="this.play().catch(function () {})" onloadedmetadata="this.play().catch(function () {})"></video></div>';
|
||||
return '<div class="template-region video" style="' + region.baseStyle + '"><video src="' + escapeHtml(cachedSrcVersioned) + '" title="' + escapeHtml(region.label) + '" data-disable-audio="' + (disableAudio ? '1' : '0') + '" autoplay' + (disableAudio ? ' muted' : '') + ' loop playsinline preload="auto" disablepictureinpicture oncanplay="this.play().catch(function () {})" onloadedmetadata="this.play().catch(function () {})"></video></div>';
|
||||
}
|
||||
|
||||
return '';
|
||||
|
||||
@@ -4,7 +4,7 @@ const Handlebars = require('handlebars');
|
||||
const path = require('path');
|
||||
const { mediaKind, safeJsonForScript, getPlayerPageTemplate, getPlayerClientNameScript, getPlayerPageOfflineScript, getPlayerPagePlaylistScript, getPlayerPageCommandsScript, getPlayerPageRenderingScript, getPlayerPagePlaybackScript, getAnnouncementIconsDataScript, getPlayerAnnouncementTemplatesDataScript, getPlayerAnnouncementTemplatesScript, getPlayerPageAnnouncementsScript, getPlayerPageScript, getPlayerRegionScripts, getPlayerOnboardingLandingScript, getPlayerOnboardingFormScript } = require('./render-helpers');
|
||||
const { createThumbnailPreviewBootstrapScript } = require('./thumbnail-preview');
|
||||
const { createPageAuthBundle, createPageFetchAuthScript } = require('../request-auth');
|
||||
const { createPageAuthBundle, createPageFetchAuthScript } = require('#src/request-auth');
|
||||
const { getFontStylesheetHref } = require('#src/web/lib/media/font-library');
|
||||
|
||||
const PLAYER_MEDIA_DIR = path.join(__dirname, '..', '..', 'media');
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
const fs = require('fs');
|
||||
const express = require('express');
|
||||
const path = require('path');
|
||||
const { getSharedSecret, createPageAuthBundle, verifyPageAuthToken, verifyRequestAuth } = require('../request-auth');
|
||||
const { getSharedSecret, createPageAuthBundle, verifyPageAuthToken, verifyRequestAuth } = require('#src/request-auth');
|
||||
const { buildThumbnailPreviewData } = require('./thumbnail-preview');
|
||||
|
||||
const TRANSIENT_DB_ERROR_CODES = ['ECONNREFUSED', 'ECONNRESET', 'ETIMEDOUT', 'EPIPE', 'ENOTFOUND', 'PROTOCOL_CONNECTION_LOST', 'POOL_CLOSED', 'ERR_POOL_CLOSED'];
|
||||
@@ -259,9 +259,9 @@ function registerPlayerRoutes(app, options) {
|
||||
});
|
||||
}
|
||||
|
||||
if (typeof common.fetchSchedulesData === 'function') {
|
||||
const scheduleData = await common.fetchSchedulesData(pool);
|
||||
data.scheduleGroups = Array.isArray(scheduleData && scheduleData.scheduleGroups) ? scheduleData.scheduleGroups : [];
|
||||
if (typeof common.fetchTimetablesData === 'function') {
|
||||
const timetableData = await common.fetchTimetablesData(pool);
|
||||
data.timetableGroups = Array.isArray(timetableData && timetableData.timetableGroups) ? timetableData.timetableGroups : [];
|
||||
}
|
||||
|
||||
res.set('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate');
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
const crypto = require('crypto');
|
||||
const { WebSocketServer, WebSocket } = require('ws');
|
||||
const { isClientNameAvailable } = require('../data/client-name-check');
|
||||
const { verifyPageAuthToken, verifyRequestAuth } = require('../request-auth');
|
||||
const { isClientNameAvailable } = require('#src/data/client-name-check');
|
||||
const { verifyPageAuthToken, verifyRequestAuth } = require('#src/request-auth');
|
||||
|
||||
function normalizePlayerPublicBaseUrl(pageUrl) {
|
||||
const value = String(pageUrl || '').trim();
|
||||
|
||||
@@ -15,7 +15,7 @@ function buildThumbnailPreviewData(slide) {
|
||||
slides: [slide],
|
||||
rssFeeds: [],
|
||||
apiSources: [],
|
||||
scheduleGroups: [],
|
||||
timetableGroups: [],
|
||||
revision: String(slide.modified_at || slide.id || Date.now())
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user