diff --git a/public/js/app_control.js b/public/js/app_control.js index 4839be4..253f747 100644 --- a/public/js/app_control.js +++ b/public/js/app_control.js @@ -1935,11 +1935,6 @@ window.onload = async function () { return; } - if (!vod_link && !video_src && !video_file && !embed_src) { - showResponse('warning', 'Ajoute au moins une source (VOD / video_src / video_file / embed_src).'); - return; - } - try { const res = await fetch('/api/movies/add', { method: 'POST', @@ -2187,11 +2182,6 @@ window.onload = async function () { return; } - if (!vod_link && !video_src && !video_file && !embed_src) { - showResponse('warning', 'Ajoute au moins une source (VOD / video_src / video_file / embed_src).'); - return; - } - const body = { imdb_id, year: yearRaw === '' ? null : year, diff --git a/public/js/app_user-stat.js b/public/js/app_user-stat.js index ff35d84..f95f26b 100644 --- a/public/js/app_user-stat.js +++ b/public/js/app_user-stat.js @@ -444,13 +444,27 @@ window.addEventListener('DOMContentLoaded', async function () { const watchedLabel = formatWatchedDate(movie?.watchedDate); const posterUrl = normalizePosterUrl(movie?.poster); + const cleanUrl = (v) => { + const s = (typeof v === 'string' ? v.trim() : ''); + if (!s || s === '#' || s.toLowerCase() === 'about:blank') return ''; + return s; + }; + + // Click behavior (requested): + // - If vod_link is set => go to it + // - Else if any playable source exists => go to player + // - Else => not clickable + const vodLink = cleanUrl(movie?.vod_link); + const hasPlayableSource = !!cleanUrl(movie?.video_src) || !!cleanUrl(movie?.embed_src) || !!cleanUrl(movie?.video_file); + const isClickable = !!vodLink || (!!movieId && hasPlayableSource); + const item = document.createElement('div'); item.className = 'stats-movie-item'; - if (movieId) { + if (isClickable) { item.classList.add('stats-movie-item--clickable'); item.setAttribute('role', 'link'); item.setAttribute('tabindex', '0'); - item.setAttribute('aria-label', `Ouvrir le lecteur: ${title}`); + item.setAttribute('aria-label', vodLink ? `Ouvrir le lien: ${title}` : `Ouvrir le lecteur: ${title}`); } const poster = document.createElement('img'); @@ -468,22 +482,36 @@ window.addEventListener('DOMContentLoaded', async function () { try { poster.removeAttribute('src'); } catch (_) {} }); - function openPlayerIfPossible(evt) { - if (!movieId) return; + function openIfPossible(evt) { + if (!isClickable) return; // Don't hijack clicks inside controls (IMDb button, details summary, etc.) const target = evt?.target; if (target && typeof target.closest === 'function') { if (target.closest('a, button, summary, details')) return; } - window.location.href = `/player.html?id=${encodeURIComponent(movieId)}`; + + if (vodLink) { + // Use a new tab (keeps the app state intact) + try { + const w = window.open(vodLink, '_blank', 'noopener,noreferrer'); + if (!w) window.location.href = vodLink; + } catch (_) { + window.location.href = vodLink; + } + return; + } + + if (movieId && hasPlayableSource) { + window.location.href = `/player.html?id=${encodeURIComponent(movieId)}`; + } } - if (movieId) { - item.addEventListener('click', openPlayerIfPossible); + if (isClickable) { + item.addEventListener('click', openIfPossible); item.addEventListener('keydown', (e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); - openPlayerIfPossible(e); + openIfPossible(e); } }); } diff --git a/routes/users.js b/routes/users.js index 4e989a8..9197593 100644 --- a/routes/users.js +++ b/routes/users.js @@ -130,7 +130,7 @@ router.get("/stats", verifyToken, async (req, res) => { // Fetch movies (optionally filtered by year) const allMovies = await Movie.find({ year }) - .select("imdb_id title poster rating category year") + .select("imdb_id title poster rating category year vod_link player_mode video_src embed_src video_file") .lean(); const totalMoviesCount = allMovies.length; @@ -158,6 +158,11 @@ router.get("/stats", verifyToken, async (req, res) => { rating: movie.rating || "", category: movie.category || "", year: Number.isInteger(movie.year) ? movie.year : year, + vod_link: movie.vod_link || "", + player_mode: movie.player_mode || "auto", + video_src: movie.video_src || "", + embed_src: movie.embed_src || "", + video_file: movie.video_file || "", watchedDate: wm?.watchedDate ? new Date(wm.watchedDate).toISOString() : null, }; })