-
-
-
If you use a server file (below) and leave this empty, it will auto-use /api/video/<movieId>.
+
+
+
-
-
-
-
Relative path under VIDEO_FILES_DIR (default: public/video).
+
+
+
+
-
-
-
+
+
+
+
+
-
-
+
+
+
+
+
Si coché, le serveur refait un appel OMDb via l’IMDB ID au moment de l’enregistrement.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
diff --git a/public/js/app_change-password.js b/public/js/app_change-password.js
index 8da74f8..c8aa0f0 100644
--- a/public/js/app_change-password.js
+++ b/public/js/app_change-password.js
@@ -7,7 +7,27 @@ function isTokenExpired(decoded) {
return !!decoded.exp && decoded.exp < currentTime;
}
+async function applyActiveOscarYearToTitle() {
+ const base = 'Pool Oscars';
+ const current = String(document.title || base);
+ const sep = ' - ';
+ const idx = current.indexOf(sep);
+ const suffix = idx >= 0 ? current.slice(idx) : '';
+
+ try {
+ const res = await fetch('/api/settings/year', { method: 'GET' });
+ const data = res.ok ? await res.json().catch(() => null) : null;
+ const year = Number(data?.year);
+ document.title = Number.isInteger(year) ? `${base} (${year})${suffix}` : `${base}${suffix}`;
+ } catch (_) {
+ document.title = `${base}${suffix}`;
+ }
+}
+
window.onload = function () {
+ // Best-effort: update page title with active year.
+ applyActiveOscarYearToTitle();
+
const token = localStorage.getItem('auth_token');
if (!token) {
window.location.href = '/';
diff --git a/public/js/app_checklist.js b/public/js/app_checklist.js
index 26f2409..0c74d9c 100644
--- a/public/js/app_checklist.js
+++ b/public/js/app_checklist.js
@@ -254,7 +254,7 @@ window.addEventListener('DOMContentLoaded', async function () {
}
const activeYear = await fetchActiveYear();
- document.title = `Pool Oscars ${activeYear} - Checklist`;
+ document.title = `Pool Oscars (${activeYear}) - Checklist`;
const oscarYearEl = document.getElementById('oscar-year');
if (oscarYearEl) oscarYearEl.textContent = String(activeYear);
diff --git a/public/js/app_control.js b/public/js/app_control.js
index f8e511e..11c1ffe 100644
--- a/public/js/app_control.js
+++ b/public/js/app_control.js
@@ -2332,7 +2332,7 @@ window.onload = async function () {
// Initial load
activeYear = await fetchActiveYear();
if (activeYear) {
- document.title = `Pool Oscars ${activeYear} - Admin`;
+ document.title = `Pool Oscars (${activeYear}) - Admin`;
}
hookModal100Inputs();
@@ -2352,7 +2352,7 @@ window.onload = async function () {
activeYear = await setActiveYear(y);
activeYearInput.value = String(activeYear);
yearInput.value = String(activeYear);
- document.title = `Pool Oscars ${activeYear} - Admin`;
+ document.title = `Pool Oscars (${activeYear}) - Admin`;
showResponse('success', `Année active appliquée: ${activeYear}`);
await refreshYears();
await loadMoviesForManagement();
diff --git a/public/js/app_index.js b/public/js/app_index.js
index b625f9e..e3efd56 100644
--- a/public/js/app_index.js
+++ b/public/js/app_index.js
@@ -2,6 +2,26 @@ function decodeJwt(token) {
return JSON.parse(atob(token.split('.')[1]));
}
+async function applyActiveOscarYearToTitle() {
+ const base = 'Pool Oscars';
+ const current = String(document.title || base);
+ const sep = ' - ';
+ const idx = current.indexOf(sep);
+ const suffix = idx >= 0 ? current.slice(idx) : '';
+
+ try {
+ const res = await fetch('/api/settings/year', { method: 'GET' });
+ const data = res.ok ? await res.json().catch(() => null) : null;
+ const year = Number(data?.year);
+ document.title = Number.isInteger(year) ? `${base} (${year})${suffix}` : `${base}${suffix}`;
+ } catch (_) {
+ document.title = `${base}${suffix}`;
+ }
+}
+
+// Fire and forget.
+applyActiveOscarYearToTitle();
+
// Check if the user is already logged in by looking for auth_token in localStorage
const existingToken = localStorage.getItem('auth_token');
if (existingToken) {
diff --git a/public/js/app_movies.js b/public/js/app_movies.js
index 528fc18..029bc32 100644
--- a/public/js/app_movies.js
+++ b/public/js/app_movies.js
@@ -224,7 +224,7 @@ window.addEventListener('DOMContentLoaded', async function () {
}
const activeYear = await fetchActiveYear();
- document.title = `Pool Oscars ${activeYear} - Films`;
+ document.title = `Pool Oscars (${activeYear}) - Films`;
const oscarYearEl = document.getElementById('oscar-year');
if (oscarYearEl) oscarYearEl.textContent = String(activeYear);
diff --git a/public/js/app_player.js b/public/js/app_player.js
index 4ffbadd..21ce919 100644
--- a/public/js/app_player.js
+++ b/public/js/app_player.js
@@ -23,6 +23,18 @@ function normalizeUserId(raw) {
return /^[a-f0-9]{24}$/i.test(s) ? s : null;
}
+async function fetchActiveOscarYear() {
+ try {
+ const res = await fetch('/api/settings/year', { method: 'GET' });
+ if (!res.ok) return null;
+ const data = await res.json().catch(() => null);
+ const year = Number(data?.year);
+ return Number.isInteger(year) ? year : null;
+ } catch (_) {
+ return null;
+ }
+}
+
async function fetchPlaybackProgress(movieId, token) {
try {
const res = await fetch(`/api/movies/${encodeURIComponent(movieId)}/progress`, {
@@ -341,12 +353,15 @@ function formatClock(seconds) {
return `${m}:${String(sec).padStart(2, '0')}`;
}
-function setHeader(movie) {
+function setHeader(movie, { activeYear } = {}) {
const titleEl = document.getElementById('movie-title');
const categoryEl = document.getElementById('movie-category');
const ratingEl = document.getElementById('movie-rating');
- if (titleEl) titleEl.textContent = movie?.title || 'Player';
+ const year = Number.isInteger(activeYear) ? activeYear : null;
+ const titlePrefix = year ? `Pool Oscars (${year})` : 'Pool Oscars';
+
+ if (titleEl) titleEl.textContent = movie?.title || titlePrefix;
if (categoryEl) {
const cat = movie?.category ? String(movie.category) : '';
@@ -358,7 +373,7 @@ function setHeader(movie) {
ratingEl.textContent = r ? `⭐ ${r}` : '';
}
- document.title = movie?.title ? `Player - ${movie.title}` : 'Player';
+ document.title = movie?.title ? `${titlePrefix} - ${movie.title}` : titlePrefix;
}
function normalizeVodLink(raw) {
@@ -475,18 +490,6 @@ function hideAllPlayers() {
}
}
-function setOpenOriginal(raw) {
- const openOriginal = document.getElementById('open-original');
- if (!openOriginal) return;
- if (raw) {
- openOriginal.href = raw;
- openOriginal.classList.remove('d-none');
- } else {
- openOriginal.removeAttribute('href');
- openOriginal.classList.add('d-none');
- }
-}
-
function isApiVideoUrl(raw) {
const s = String(raw || '').trim();
if (!s) return false;
@@ -597,9 +600,6 @@ async function playVodLink(vodLink, { token } = {}) {
return;
}
- // "Open original" button
- setOpenOriginal(raw);
-
// Prefer known embed providers
const yt = toYoutubeEmbed(raw);
if (yt) {
@@ -721,6 +721,9 @@ window.onload = async function () {
return;
}
+ // Load the active Oscar year in parallel with the movie fetch.
+ const activeYearPromise = fetchActiveOscarYear();
+
let decoded = null;
try {
decoded = decodeJwt(token);
@@ -771,11 +774,11 @@ window.onload = async function () {
return;
}
- setHeader(movie);
+ const activeYear = await activeYearPromise;
+ setHeader(movie, { activeYear });
const resolved = resolveMovieSource(movie);
if (!resolved?.src) {
- setOpenOriginal(null);
setSourceLabel('—');
hideAllPlayers();
showAlert('No playable source configured for this movie.');
@@ -786,10 +789,9 @@ window.onload = async function () {
if (resolved.isLegacy) {
// Legacy source: never embed it in the player.
- setOpenOriginal(resolved.src);
- setSourceLabel('Legacy link (opens in new tab)');
+ setSourceLabel('Legacy link');
hideAllPlayers();
- showAlertVariant('Legacy source: use “Open original” to watch in a new tab.', 'warning');
+ showAlertVariant('Legacy source: this link is not playable in the in-app player.', 'warning');
return;
}
diff --git a/public/js/app_register.js b/public/js/app_register.js
index cd83fcc..91fa923 100644
--- a/public/js/app_register.js
+++ b/public/js/app_register.js
@@ -2,6 +2,26 @@ function decodeJwt(token) {
return JSON.parse(atob(token.split('.')[1]));
}
+async function applyActiveOscarYearToTitle() {
+ const base = 'Pool Oscars';
+ const current = String(document.title || base);
+ const sep = ' - ';
+ const idx = current.indexOf(sep);
+ const suffix = idx >= 0 ? current.slice(idx) : '';
+
+ try {
+ const res = await fetch('/api/settings/year', { method: 'GET' });
+ const data = res.ok ? await res.json().catch(() => null) : null;
+ const year = Number(data?.year);
+ document.title = Number.isInteger(year) ? `${base} (${year})${suffix}` : `${base}${suffix}`;
+ } catch (_) {
+ document.title = `${base}${suffix}`;
+ }
+}
+
+// Fire and forget.
+applyActiveOscarYearToTitle();
+
// Check if the user is already logged in by looking for auth_token in localStorage
const existingToken = localStorage.getItem('auth_token');
if (existingToken) {
diff --git a/public/js/app_user-stat.js b/public/js/app_user-stat.js
index 2b015c8..15a5f89 100644
--- a/public/js/app_user-stat.js
+++ b/public/js/app_user-stat.js
@@ -365,7 +365,7 @@ window.addEventListener('DOMContentLoaded', async function () {
pageLoader.setProgress(20);
const activeYear = await fetchActiveYear();
if (activeYear) {
- document.title = `Pool Oscars ${activeYear} - Statistiques des utilisateurs`;
+ document.title = `Pool Oscars (${activeYear}) - Statistiques des utilisateurs`;
const h2 = document.querySelector('h2');
if (h2) h2.textContent = `Statistiques des utilisateurs (${activeYear})`;
}
diff --git a/public/player.html b/public/player.html
index d5b1409..26d9c4c 100644
--- a/public/player.html
+++ b/public/player.html
@@ -5,7 +5,7 @@
-
Player
+
Pool Oscars
@@ -120,9 +120,8 @@
Admin