arnaucube
arnaucube/configsPublic Self-hosted repository
configs/server-dockers/jellyfin-news/index.html
server-dockers/jellyfin-news/index.htmlRaw
 1<!doctype html>
 2<html lang="en">
 3<head>
 4  <meta charset="utf-8">
 5  <meta name="viewport" content="width=device-width, initial-scale=1">
 6  <title>Jellyfin updates</title>
 7  <style>
 8    body { max-width: 760px; margin: 2rem auto; padding: 0 1rem; font: 16px/1.5 system-ui, sans-serif; color: #202124; }
 9    h1 { margin-bottom: .25rem; }
10    .controls { display: flex; flex-wrap: wrap; gap: .65rem; margin: 1.5rem 0; align-items: center; }
11    button, input { font: inherit; padding: .6rem .8rem; }
12    button { cursor: pointer; }
13    input { width: 5rem; }
14    #status { min-height: 1.5rem; color: #555; }
15    textarea { box-sizing: border-box; width: 100%; min-height: 22rem; padding: 1rem; font: 15px/1.5 ui-monospace, monospace; resize: vertical; }
16    .copy { margin-top: .65rem; }
17  </style>
18</head>
19<body>
20  <h1>Jellyfin updates</h1>
21  <p>Choose a period, then copy the generated recap.</p>
22
23  <div class="controls">
24    <button data-report="/api/current-week">Current week</button>
25  </div>
26
27  <div class="controls">
28    <label for="week-offset">Week offset:</label>
29    <input id="week-offset" type="number" min="-1200" max="-1" value="-1" required>
30    <button id="selected-week">Load selected week</button>
31    <span>−1 is last week, −2 is two weeks ago</span>
32  </div>
33
34  <div class="controls">
35    <label for="month-offset">Month offset:</label>
36    <input id="month-offset" type="number" min="-1200" max="-1" value="-1" required>
37    <button id="selected-month">Load selected month</button>
38    <span>−1 is last month, −2 is two months ago</span>
39  </div>
40
41  <p id="status" role="status"></p>
42  <textarea id="output" readonly aria-label="Jellyfin update output" placeholder="Your recap will appear here"></textarea>
43  <button id="copy" class="copy">Copy to clipboard</button>
44
45  <script>
46    const output = document.querySelector('#output');
47    const status = document.querySelector('#status');
48    const buttons = [...document.querySelectorAll('button')];
49
50    async function loadReport(url) {
51      buttons.forEach(button => button.disabled = true);
52      status.textContent = 'Loading…';
53      try {
54        const response = await fetch(url, { headers: { Accept: 'text/plain' } });
55        const text = await response.text();
56        if (!response.ok) throw new Error(text.trim() || `Request failed (${response.status})`);
57        output.value = text;
58        status.textContent = 'Recap ready.';
59      } catch (error) {
60        status.textContent = error.message;
61      } finally {
62        buttons.forEach(button => button.disabled = false);
63      }
64    }
65
66    document.querySelectorAll('[data-report]').forEach(button => {
67      button.addEventListener('click', () => loadReport(button.dataset.report));
68    });
69
70    document.querySelector('#selected-week').addEventListener('click', () => {
71      const offset = document.querySelector('#week-offset').value;
72      loadReport(`/api/week?offset=${encodeURIComponent(offset)}`);
73    });
74
75    document.querySelector('#selected-month').addEventListener('click', () => {
76      const offset = document.querySelector('#month-offset').value;
77      loadReport(`/api/month?offset=${encodeURIComponent(offset)}`);
78    });
79
80    document.querySelector('#copy').addEventListener('click', async () => {
81      if (!output.value) return;
82      try {
83        await navigator.clipboard.writeText(output.value);
84      } catch (_) {
85        output.select();
86        document.execCommand('copy');
87        output.setSelectionRange(0, 0);
88      }
89      status.textContent = 'Copied to clipboard.';
90    });
91  </script>
92</body>
93</html>