Add optional MDBList movie ratings

This commit is contained in:
ponzischeme89
2026-08-03 08:55:52 +12:00
parent b6b2a9c25a
commit 666da9c5d3
18 changed files with 840 additions and 4 deletions
+78
View File
@@ -202,6 +202,9 @@
<a class="rail-link" href="/admin/features" data-section="features" title="Features">
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 7h10M18 7h2M4 17h2m4 0h10M14 4v6M6 14v6"/></svg><span>Features</span>
</a>
<a class="rail-link" href="/admin/ratings" data-section="ratings" title="Movie ratings">
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="m12 3 2.1 5.4 5.9.4-4.6 3.8 1.5 5.7-4.9-3.2-4.9 3.2 1.5-5.7L4 8.8l5.9-.4L12 3Z"/></svg><span>Movie ratings</span>
</a>
<a class="rail-link" href="/admin/library" data-section="library" title="Library">
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 5.5h16v13H4zM8 5.5v13M4 10h4"/></svg><span>Library</span>
</a>
@@ -346,6 +349,36 @@
</table></div>
</section>
<section id="ratings" data-admin-page="ratings">
<h2>MDBList movie ratings</h2>
<p class="muted" style="margin-top:0">
Optionally enrich movie details with ratings fetched by the gateway. The API key
stays on this server, responses are cached for 24 hours, and failures never block a TV.
</p>
<div class="row" style="margin-bottom:14px">
<label style="display:flex;align-items:center;gap:9px">
<input type="checkbox" id="mdblist-enabled">
<span>Show external movie ratings</span>
</label>
<span id="mdblist-state" class="pill muted">off</span>
</div>
<div style="display:grid;gap:8px;margin-bottom:16px">
<label class="muted" for="mdblist-api-key">MDBList API key</label>
<div class="row">
<input type="password" id="mdblist-api-key" autocomplete="new-password" placeholder="Paste an API key">
<label style="display:flex;align-items:center;gap:7px">
<input type="checkbox" id="mdblist-clear-key"> Remove saved key
</label>
</div>
<span class="muted" style="font-size:12px">Leave the field blank to keep the currently saved key.</span>
</div>
<h2 style="margin-bottom:8px">Sources shown on TVs</h2>
<div id="mdblist-sources" style="display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:9px;margin-bottom:16px">
<span class="muted">Loading sources…</span>
</div>
<button id="mdblist-save">Save ratings settings</button>
</section>
<section id="playback" data-admin-page="playback">
<h2>Playback experience</h2>
<p class="muted" style="margin-top:0">
@@ -458,6 +491,7 @@ const pageCopy = {
recommendations: ['Recommendations', 'Pressure-test personalised rows and title scores per user.'],
requests: ['Media requests', 'Control who can request missing movies and shows.'],
features: ['Features', 'Roll out, stop and recover optional TV behaviour from the server.'],
ratings: ['Movie ratings', 'Configure optional server-side MDBList ratings for movie details.'],
playback: ['Playback', 'Control server-driven playback presentation on every TV.'],
maintenance: ['Maintenance', 'Control gateway availability for every television.'],
updates: ['App updates', 'Publish optional or mandatory client update policy.'],
@@ -643,6 +677,33 @@ function renderStatus(status) {
renderFeatures(status.features || {}, status.clients || []);
const mdblist = status.mdblist || {};
const mdblistEnabled = document.getElementById('mdblist-enabled');
if (document.activeElement !== mdblistEnabled) mdblistEnabled.checked = Boolean(mdblist.enabled);
const mdblistState = document.getElementById('mdblist-state');
mdblistState.textContent = mdblist.enabled
? 'on · ' + ((mdblist.sources || []).length) + ' sources'
: (mdblist.apiKeyConfigured ? 'off · key saved' : 'off · no key');
mdblistState.className = 'pill ' + (mdblist.enabled ? 'ok' : 'muted');
const keyField = document.getElementById('mdblist-api-key');
keyField.placeholder = mdblist.apiKeyConfigured ? 'Saved key (leave blank to keep)' : 'Paste an API key';
const sourceNames = {
imdb:'IMDb', tomatoes:'Rotten Tomatoes', audience:'Rotten Tomatoes Audience',
metacritic:'Metacritic', letterboxd:'Letterboxd', rogerebert:'Roger Ebert',
tmdb:'TMDb', trakt:'Trakt', mal:'MyAnimeList',
score:'MDBList Score', score_average:'MDBList Average',
};
const sourceBox = document.getElementById('mdblist-sources');
if (!sourceBox.contains(document.activeElement)) {
const selectedSources = new Set(mdblist.sources || []);
sourceBox.innerHTML = (mdblist.availableSources || []).map((source) =>
'<label style="display:flex;align-items:center;gap:8px">' +
'<input type="checkbox" data-mdblist-source="' + escapeHtml(source) + '"' +
(selectedSources.has(source) ? ' checked' : '') + '>' +
'<span>' + escapeHtml(sourceNames[source] || source) + '</span></label>'
).join('') || '<span class="muted">No rating sources available.</span>';
}
const playback = status.playbackPolicy || {};
const prerollEnabled = document.getElementById('preroll-enabled');
const prerollDuration = document.getElementById('preroll-duration');
@@ -964,6 +1025,23 @@ document.getElementById('playback-save').addEventListener('click', () => {
}));
});
document.getElementById('mdblist-save').addEventListener('click', () => {
const sources = [...document.querySelectorAll('[data-mdblist-source]:checked')]
.map((box) => box.dataset.mdblistSource);
act(() => api('/admin/api/mdblist-settings', {
method: 'POST',
body: JSON.stringify({
enabled: document.getElementById('mdblist-enabled').checked,
apiKey: document.getElementById('mdblist-api-key').value.trim(),
clearApiKey: document.getElementById('mdblist-clear-key').checked,
sources,
}),
}).then(() => {
document.getElementById('mdblist-api-key').value = '';
document.getElementById('mdblist-clear-key').checked = false;
}));
});
function updatePolicyBody(enabled) {
return JSON.stringify({
enabled,