Video server and timestamp #45
+10
-1
@@ -418,6 +418,7 @@
|
|||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th style="width: 1%;">Sel.</th>
|
<th style="width: 1%;">Sel.</th>
|
||||||
|
<th style="width: 1%;">ID</th>
|
||||||
<th>Titre</th>
|
<th>Titre</th>
|
||||||
<th style="width: 12%;">Player</th>
|
<th style="width: 12%;">Player</th>
|
||||||
<th style="width: 20%;">Catégorie</th>
|
<th style="width: 20%;">Catégorie</th>
|
||||||
@@ -426,7 +427,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody id="admin-movies-body">
|
<tbody id="admin-movies-body">
|
||||||
<tr><td colspan="6" class="text-muted">Charge la liste…</td></tr>
|
<tr><td colspan="7" class="text-muted">Charge la liste…</td></tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
@@ -679,6 +680,14 @@
|
|||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<input type="hidden" id="edit_movie_id">
|
<input type="hidden" id="edit_movie_id">
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<div class="text-muted small mb-1">Movie ID</div>
|
||||||
|
<div class="d-flex gap-2 align-items-center">
|
||||||
|
<code class="flex-grow-1" id="edit_movie_id_label">—</code>
|
||||||
|
<button type="button" class="btn btn-outline-secondary btn-sm" id="copy-movie-id">Copier</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="row g-3">
|
<div class="row g-3">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<label for="edit_imdb_id" class="form-label">IMDB ID (ex: tt1234567)</label>
|
<label for="edit_imdb_id" class="form-label">IMDB ID (ex: tt1234567)</label>
|
||||||
|
|||||||
@@ -98,6 +98,8 @@ window.onload = async function () {
|
|||||||
const saveMovieChangesBtn = document.getElementById('save-movie-changes');
|
const saveMovieChangesBtn = document.getElementById('save-movie-changes');
|
||||||
|
|
||||||
const editMovieIdEl = document.getElementById('edit_movie_id');
|
const editMovieIdEl = document.getElementById('edit_movie_id');
|
||||||
|
const editMovieIdLabelEl = document.getElementById('edit_movie_id_label');
|
||||||
|
const copyMovieIdBtn = document.getElementById('copy-movie-id');
|
||||||
const editImdbIdEl = document.getElementById('edit_imdb_id');
|
const editImdbIdEl = document.getElementById('edit_imdb_id');
|
||||||
const editYearEl = document.getElementById('edit_year');
|
const editYearEl = document.getElementById('edit_year');
|
||||||
const editCategoryEl = document.getElementById('edit_category');
|
const editCategoryEl = document.getElementById('edit_category');
|
||||||
@@ -145,6 +147,17 @@ window.onload = async function () {
|
|||||||
.replace(/'/g, ''');
|
.replace(/'/g, ''');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function copyToClipboard(text) {
|
||||||
|
const t = String(text || '').trim();
|
||||||
|
if (!t) return false;
|
||||||
|
try {
|
||||||
|
await navigator.clipboard.writeText(t);
|
||||||
|
return true;
|
||||||
|
} catch (_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function sanitizeHtml(raw) {
|
function sanitizeHtml(raw) {
|
||||||
const html = String(raw || '');
|
const html = String(raw || '');
|
||||||
const withoutScripts = html.replace(/<script\b[\s\S]*?<\/script>/gi, '');
|
const withoutScripts = html.replace(/<script\b[\s\S]*?<\/script>/gi, '');
|
||||||
@@ -2021,6 +2034,7 @@ window.onload = async function () {
|
|||||||
if (!movie) return;
|
if (!movie) return;
|
||||||
|
|
||||||
editMovieIdEl.value = movie._id || '';
|
editMovieIdEl.value = movie._id || '';
|
||||||
|
if (editMovieIdLabelEl) editMovieIdLabelEl.textContent = movie._id || '—';
|
||||||
editImdbIdEl.value = movie.imdb_id || '';
|
editImdbIdEl.value = movie.imdb_id || '';
|
||||||
editYearEl.value = movie.year ? String(movie.year) : '';
|
editYearEl.value = movie.year ? String(movie.year) : '';
|
||||||
editCategoryEl.value = movie.category || '';
|
editCategoryEl.value = movie.category || '';
|
||||||
@@ -2147,12 +2161,12 @@ window.onload = async function () {
|
|||||||
async function loadMoviesForManagement() {
|
async function loadMoviesForManagement() {
|
||||||
const year = manageYearSelect.value;
|
const year = manageYearSelect.value;
|
||||||
const url = year ? `/api/movies?year=${encodeURIComponent(year)}` : '/api/movies';
|
const url = year ? `/api/movies?year=${encodeURIComponent(year)}` : '/api/movies';
|
||||||
adminMoviesBody.innerHTML = `<tr><td colspan="6" class="text-muted">Chargement…</td></tr>`;
|
adminMoviesBody.innerHTML = `<tr><td colspan="7" class="text-muted">Chargement…</td></tr>`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await fetch(url, { method: 'GET' });
|
const res = await fetch(url, { method: 'GET' });
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
adminMoviesBody.innerHTML = `<tr><td colspan="6" class="text-danger">Erreur lors du chargement (${res.status})</td></tr>`;
|
adminMoviesBody.innerHTML = `<tr><td colspan="7" class="text-danger">Erreur lors du chargement (${res.status})</td></tr>`;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const movies = await res.json();
|
const movies = await res.json();
|
||||||
@@ -2160,7 +2174,7 @@ window.onload = async function () {
|
|||||||
moviesById = new Map(movies.map((m) => [m._id, m]));
|
moviesById = new Map(movies.map((m) => [m._id, m]));
|
||||||
|
|
||||||
if (!movies.length) {
|
if (!movies.length) {
|
||||||
adminMoviesBody.innerHTML = `<tr><td colspan="6" class="text-muted">Aucun film.</td></tr>`;
|
adminMoviesBody.innerHTML = `<tr><td colspan="7" class="text-muted">Aucun film.</td></tr>`;
|
||||||
updateSelectionUI();
|
updateSelectionUI();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -2195,11 +2209,19 @@ window.onload = async function () {
|
|||||||
.map((b) => `<span class="badge ${b.cls} me-1 mb-1">${b.text}</span>`)
|
.map((b) => `<span class="badge ${b.cls} me-1 mb-1">${b.text}</span>`)
|
||||||
.join('');
|
.join('');
|
||||||
|
|
||||||
|
const movieId = String(m._id || '');
|
||||||
|
const shortId = movieId ? `${movieId.slice(0, 6)}…${movieId.slice(-4)}` : '—';
|
||||||
|
|
||||||
const tr = document.createElement('tr');
|
const tr = document.createElement('tr');
|
||||||
tr.innerHTML = `
|
tr.innerHTML = `
|
||||||
<td>
|
<td>
|
||||||
<input type="checkbox" class="form-check-input" data-movie-id="${m._id}">
|
<input type="checkbox" class="form-check-input" data-movie-id="${m._id}">
|
||||||
</td>
|
</td>
|
||||||
|
<td class="text-nowrap">
|
||||||
|
<button type="button" class="btn btn-sm btn-outline-secondary font-monospace" data-copy-movie-id="${escapeHtml(movieId)}" title="${escapeHtml(movieId)}">
|
||||||
|
${escapeHtml(shortId)}
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="fw-semibold">${m.title || '(sans titre)'}</div>
|
<div class="fw-semibold">${m.title || '(sans titre)'}</div>
|
||||||
<div class="text-muted small">${m.imdb_id || ''}</div>
|
<div class="text-muted small">${m.imdb_id || ''}</div>
|
||||||
@@ -2224,9 +2246,22 @@ window.onload = async function () {
|
|||||||
btn.addEventListener('click', () => openEditModal(btn.getAttribute('data-edit-movie-id')));
|
btn.addEventListener('click', () => openEditModal(btn.getAttribute('data-edit-movie-id')));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
adminMoviesBody.querySelectorAll('button[data-copy-movie-id]').forEach((btn) => {
|
||||||
|
btn.addEventListener('click', async () => {
|
||||||
|
const id = btn.getAttribute('data-copy-movie-id');
|
||||||
|
if (!id) return;
|
||||||
|
const ok = await copyToClipboard(id);
|
||||||
|
if (ok) {
|
||||||
|
showResponse('success', 'Movie ID copié.');
|
||||||
|
} else {
|
||||||
|
showResponse('warning', 'Impossible de copier automatiquement. Copie manuellement.');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
updateSelectionUI();
|
updateSelectionUI();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
adminMoviesBody.innerHTML = `<tr><td colspan="6" class="text-danger">${err.message || 'Erreur réseau'}</td></tr>`;
|
adminMoviesBody.innerHTML = `<tr><td colspan="7" class="text-danger">${err.message || 'Erreur réseau'}</td></tr>`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2281,6 +2316,19 @@ window.onload = async function () {
|
|||||||
saveMovieChangesBtn.addEventListener('click', saveMovieChanges);
|
saveMovieChangesBtn.addEventListener('click', saveMovieChanges);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (copyMovieIdBtn) {
|
||||||
|
copyMovieIdBtn.addEventListener('click', async () => {
|
||||||
|
const id = String(editMovieIdEl?.value || '').trim();
|
||||||
|
if (!id) return;
|
||||||
|
const ok = await copyToClipboard(id);
|
||||||
|
if (ok) {
|
||||||
|
showResponse('success', 'Movie ID copié.');
|
||||||
|
} else {
|
||||||
|
showResponse('warning', 'Impossible de copier automatiquement. Copie manuellement.');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Initial load
|
// Initial load
|
||||||
activeYear = await fetchActiveYear();
|
activeYear = await fetchActiveYear();
|
||||||
if (activeYear) {
|
if (activeYear) {
|
||||||
|
|||||||
Reference in New Issue
Block a user