-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.js
More file actions
246 lines (225 loc) · 7.83 KB
/
Copy pathindex.js
File metadata and controls
246 lines (225 loc) · 7.83 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
// --- Autobahn App API Beispiel: Sperrungen auf der A671 abrufen ---
function showCurrentClosures(autobahn) {
const url = `https://verkehr.autobahn.de/o/autobahn/${autobahn}/services/closure`;
fetch(url)
.then(response => {
if (!response.ok) throw new Error('Netzwerkantwort war nicht ok');
return response.json();
})
.then(data => {
// Die API liefert ein Objekt mit "closure"-Array
const closures = Array.isArray(data.closure) ? data.closure : [];
// Filtere nur aktuelle Sperrungen (future === false)
const active = closures.filter(item => item && item.future === false);
const relevanteStichwoerter = ["Mainz", "Rüsselsheim", "Wiesbaden", "Darmstadt", "Raunheim", "Groß-Gerau", "Büttelborn", "Bischofsheim", "Mörfelden-Walldorf", "Mörfelden", "Walldorf", "Langen", "Weiterstadt", "Ginsheim-Gustavsburg", "Mainz -> Wiesbaden"];
const relevant = active.filter(item =>
relevanteStichwoerter.some(kw =>
(item.title && item.title.includes(kw)) ||
(item.subtitle && item.subtitle.includes(kw)) ||
(item.description && item.description.some(line => line.includes(kw)))
)
);
// Für jede Autobahn ein eigenes Ausgabefeld
const elId = `autobahn-closures-${autobahn}`;
let el = document.getElementById(elId);
if (!el) {
// Falls das Element noch nicht existiert, erstelle es unterhalb von autobahn-closures (Sammelcontainer)
const container = document.getElementById("autobahn-closures");
if (container) {
el = document.createElement("div");
el.id = elId;
el.style.marginBottom = "1em";
container.appendChild(el);
}
}
if (el) {
if (relevant.length === 0) {
// el.innerHTML += "Keine aktuellen Sperrungen.";
} else {
//el.innerHTML = `<h3>${autobahn}</h3>`;
el.innerHTML += relevant.map(item => {
let beginn = '';
let ende = '';
if (item.description && item.description.length > 3) {
beginn = item.description[1]; // Zeile 2: Beginn
ende = item.description[2]; // Zeile 3: Ende
}
return `<div>
<strong>${item.title || "Sperrung"}</strong><!-- <br> -->
${item.subtitle ? item.subtitle + '<br>' : ''}
${beginn ? '<b>' + beginn + '</b><!-- <br> -->' : ''}
${ende ? '<b>' + ende + '</b><br>' : ''}
</div>`;
}).join("<hr>");
}
}
})
.catch(error => {
console.error(`Fehler beim Abrufen für ${autobahn}:`, error);
});
}
// Beispielaufrufe:
showCurrentClosures('A3');
showCurrentClosures('A5');
showCurrentClosures('A60');
showCurrentClosures('A67');
showCurrentClosures('A671');
// --- Ende Autobahn App API Beispiel ---
function hashStringToInt(str) {
let h = 2166136261;
for (let i = 0; i < str.length; i++) h ^= str.charCodeAt(i), h += (h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24);
return h >>> 0;
}
function mulberry32(a) {
return function () {
let t = (a += 0x6D2B79F5);
t = Math.imul(t ^ (t >>> 15), t | 1);
t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
};
}
function dayKeyWithCutoff(cutoffHourLocal = 5) {
const now = new Date();
// If current local time is before cutoff, use previous calendar day
const d = new Date(now);
if (d.getHours() < cutoffHourLocal) {
d.setDate(d.getDate() - 1);
}
const y = d.getFullYear();
const m = String(d.getMonth() + 1).padStart(2, "0");
const day = String(d.getDate()).padStart(2, "0");
return `${y}-${m}-${day}`;
}
async function loadHoroscopes() {
const res = await fetch("horoskop.csv");
if (!res.ok) throw new Error("CSV konnte nicht geladen werden");
const raw = await res.text();
const lines = raw
.split(/\r?\n/)
.map((l) => l.trim())
.filter((l) => l.length > 0);
if (lines.length === 0) return [];
const hasHeader = /überschrift/i.test(lines[0]) && /text/i.test(lines[0]);
const dataLines = hasHeader ? lines.slice(1) : lines;
const items = dataLines
.map((l) => {
const parts = l.split(";");
if (parts.length < 2) return null;
const title = parts[0].trim();
const text = parts.slice(1).join(";").trim();
if (!title || !text) return null;
return { title, text };
})
.filter(Boolean);
return items;
}
function pickDaily(items) {
if (!items || items.length === 0) return null;
const seed = hashStringToInt(dayKeyWithCutoff(5));
const rnd = mulberry32(seed);
const idx = Math.floor(rnd() * items.length);
return items[idx];
}
function msUntilNextCutoff(cutoffHourLocal = 5) {
const now = new Date();
const next = new Date(now);
next.setHours(cutoffHourLocal, 0, 0, 0);
if (now >= next) {
next.setDate(next.getDate() + 1);
}
return next - now;
}
function scheduleDailyReload(cutoffHourLocal = 5) {
const ms = msUntilNextCutoff(cutoffHourLocal);
if (ms > 0 && Number.isFinite(ms)) {
setTimeout(() => {
// Reload the page to pick up the new daily selection
location.reload();
}, ms);
}
}
function escapeHtml(value) {
return String(value ?? "")
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/\"/g, """)
.replace(/'/g, "'");
}
function formatDateTime(value) {
if (!value) return "";
const d = new Date(value);
if (Number.isNaN(d.getTime())) return String(value);
return d.toLocaleString("de-DE", {
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
});
}
async function fetchJson(url, { signal } = {}) {
const res = await fetch(url, { signal });
if (!res.ok) throw new Error(`HTTP ${res.status} für ${url}`);
return res.json();
}
function parseDashboardEntry(entry) {
const id = entry?.id;
const payload = entry?.payload || {};
const data = payload?.data || {};
return {
id,
provider: data?.provider || payload?.data?.provider || payload?.provider,
severity: data?.severity || payload?.data?.severity || payload?.severity,
msgType: data?.msgType || payload?.data?.msgType || payload?.msgType,
headline: data?.headline || entry?.i18nTitle?.de || payload?.i18nTitle?.de,
sent: entry?.sent || data?.sent || payload?.sent,
areaType: data?.area?.type,
areaData: data?.area?.data,
event: data?.transKeys?.event,
};
}
function isProbablyCancelled(item) {
const msg = String(item?.msgType || "").toLowerCase();
return msg === "cancel";
}
function renderHoroscope(itemOrMessage) {
const el = document.getElementById("horoskop-content");
if (!el) return;
// If a string is provided, render it as a message
if (typeof itemOrMessage === "string") {
el.textContent = itemOrMessage;
return;
}
const item = itemOrMessage;
if (!item) {
el.textContent = "Keine Horoskope gefunden.";
return;
}
el.innerHTML = `<div class="fw-semibold">${item.title}</div><div>${item.text}</div>`;
}
document.addEventListener("DOMContentLoaded", async () => {
try {
const items = await loadHoroscopes();
const selection = pickDaily(items);
renderHoroscope(selection);
} catch (e) {
renderHoroscope("Fehler beim Laden des Horoskops.");
}
// Auto-reload at the next cutoff (05:00 local time)
scheduleDailyReload(5);
// Set QR code and link to feedback page
try {
const feedbackUrl = new URL("feedback.html", location.href).toString();
const qr = document.getElementById("feedback-qr");
if (qr) {
const size = 200;
const api = "https://api.qrserver.com/v1/create-qr-code/";
qr.src = `${api}?size=${size}x${size}&data=${encodeURIComponent(feedbackUrl)}`;
}
const link = document.getElementById("feedback-link");
if (link) link.href = feedbackUrl;
} catch (_) {
// ignore QR/link errors
}
});