PageSourceSearch

https://nightlineradio.de/static/js/song-history.js

js nightlineradio.de collected 2026-10-02 01:52:29 UTC 2,717 bytes, 86 lines download raw bytes

1document.addEventListener("DOMContentLoaded", function () {
2  const historyContainer = document.getElementById("song-history");
3  const tableContainer = document.getElementById("playlist-container");
4  const endpoint = "/api/played";
5  const timeFormatter = new Intl.DateTimeFormat("de-DE", {
6    timeZone: "Europe/Berlin",
7    hour: "2-digit",
8    minute: "2-digit"
9  });
10  const dateFormatter = new Intl.DateTimeFormat("de-DE", {
11    timeZone: "Europe/Berlin",
12    day: "2-digit",
13    month: "2-digit",
14    year: "numeric"
15  });
16
17  function escapeHtml(value) {
18    return String(value)
19      .replace(/&/g, "&")
20      .replace(/</g, "&lt;")
21      .replace(/>/g, "&gt;")
22      .replace(/"/g, "&quot;")
23      .replace(/'/g, "&#039;");
24  }
25
26  function normalize(data) {
27    if (!Array.isArray(data)) return [];
28    return data
29      .filter((entry) => entry && entry.playedat && entry.title)
30      .sort((a, b) => Number(b.playedat) - Number(a.playedat));
31  }
32
33  function renderCompact(entries) {
34    if (!historyContainer) return;
35    const body = historyContainer.querySelector("#body") || historyContainer;
36    if (!entries.length) {
37      body.textContent = "Playlist konnte nicht geladen werden.";
38      return;
39    }
40
41    const nowPlaying = escapeHtml(entries[0].title);
42    const rows = entries
43      .map((entry) => {
44        const date = new Date(Number(entry.playedat) * 1000);
45        return escapeHtml(timeFormatter.format(date)) + "  -  " + escapeHtml(entry.title);
46      })
47      .join("<br>");
48
49    body.innerHTML = "now playing: " + nowPlaying + "<br><br>" + rows;
50  }
51
52  function renderTable(entries) {
53    if (!tableContainer) return;
54    if (!entries.length) {
55      tableContainer.textContent = "Playlist konnte nicht geladen werden.";
56      return;
57    }
58
59    const rows = entries
60      .map((entry) => {
61        const date = new Date(Number(entry.playedat) * 1000);
62        return "<tr><td>" + dateFormatter.format(date) + "</td><td>" +
63          timeFormatter.format(date) + "</td><td>" + escapeHtml(entry.title) + "</td></tr>";
64      })
65      .join("");
66
67    tableContainer.innerHTML = "<table class=\"playlist\"><thead><tr><th>Datum</th><th>Uhrzeit</th><th>Titel</th></tr></thead><tbody>" + rows + "</tbody></table>";
68  }
69
70  async function loadHistory() {
71    try {
72      const response = await fetch(endpoint, { cache: "no-store" });
73      if (!response.ok) throw new Error("HTTP " + response.status);
74      const entries = normalize(await response.json());
75      renderCompact(entries);
76      renderTable(entries);
77    } catch (error) {
78      console.error(error);
79      renderCompact([]);
80      renderTable([]);
81    }
82  }
83
84  loadHistory();
85  window.setInterval(loadHistory, 60000);
86});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.