diff --git a/client/src/lib/artists.ts b/client/src/lib/artists.ts new file mode 100644 index 0000000..7007992 --- /dev/null +++ b/client/src/lib/artists.ts @@ -0,0 +1,161 @@ +// Samodejno iz /opt/folx-shared/artists.json (29. 8. 2026). Ne urejaj rocno. +export const ARTISTS: string[] = [ + "Zillertaler Haderlumpen", + "Die Jungen Klostertaler", + "Die Jungen Zillertaler", + "Anna-Carina Woitschack", + "Engelbert Humperdinck", + "Kastelruther Spatzen", + "Die 4 von der Koralm", + "Florian Silbereisen", + "Oesch's die Dritten", + "Melissa Naschenweng", + "Die Schlagerpiloten", + "Gioiello Sabbatelli", + "Maximilian Sedlmayr", + "Wildecker Herzbuben", + "Michelle\" Schlager", + "Marianne Rosenberg", + "Esteriore Brothers", + "Alexandra Hofmann", + "Fantasy\" Schlager", + "Alpen Oberkrainer", + "Sigrid und Marina", + "Giovanni Zarrella", + "Paolo Santa Maria", + "Vanessa Siziliano", + "Hansi Hinterseer", + "Andreas Gabalier", + "Daniela Alfinito", + "Olaf der Flipper", + "Nockalm Quintett", + "Damiano Maiolini", + "Stefanie Hertel", + "Die Draufgänger", + "Die Zillertaler", + "Ybbstal Express", + "Die Pagger Buam", + "Die Grubertaler", + "Michael Wendler", + "Die Cappuccinos", + "Alexander Fuchs", + "Gerrit Grünberg", + "Helene Fischer", + "Wolfgang Petry", + "Christin Stark", + "Oswald Sattler", + "Lucas Cordalis", + "Die Stoakogler", + "Die Mayrhofner", + "Francine Jordi", + "Bernhard Brink", + "Alexander Rier", + "Nino de Angelo", + "Costa Cordalis", + "Matthias Reim", + "Beatrice Egli", + "Roland Kaiser", + "Anita Hofmann", + "Vincent Gross", + "Ramon Roselly", + "Sonia Liebing", + "Melanie Payer", + "Joelina Drews", + "Ursprung Buam", + "Steirergreens", + "Zellberg Buam", + "Melanie Oesch", + "Monika Martin", + "Eric Philippi", + "Rosanna Rocci", + "Andrea Kiewel", + "Pietro Basile", + "Nevio Passero", + "Laterndl Trio", + "Stefan Mross", + "Semino Rossi", + "Norbert Rier", + "Angela Wiedl", + "Peter Maffay", + "Saso Avsenik", + "Jürgen Drews", + "Die Flippers", + "Klostertaler", + "Lechner Buam", + "Die Paldauer", + "Marc Pircher", + "Hansi Berger", + "Ella Endlich", + "Oliver Haidt", + "Ralph Siegel", + "Johnny Logan", + "Bonnie Tyler", + "Sašo Avsenik", + "Mark Medlock", + "Laura Müller", + "Andrea Berg", + "Achim Petry", + "Maite Kelly", + "Vanessa Mai", + "Ross Antony", + "Ireen Sheer", + "Kerstin Ott", + "Die Edlseer", + "Die Fetzign", + "Die Ladiner", + "Jörg Bausch", + "Stefan Roos", + "Julian Reim", + "Linda Hesse", + "Anna Heesch", + "Rod Stewart", + "Luca Stangl", + "Hein Simons", + "Grubertaler", + "Marie Reim", + "Die Amigos", + "Ben Zucker", + "Luca Hänni", + "Die Lauser", + "Ralph Sieg", + "Anni Perka", + "Andy Borg", + "Stereoact", + "Calimeros", + "Feuerherz", + "Mary Roos", + "Voxxclub", + "Die Seer", + "Michelle", + "voXXclub", + "DJ Ötzi", + "Ragazzi", + "Fantasy", + "Nik P.", + "Nockis", + "Nicole", + "Amigos", + "Andita", + "Belsy", + "Harpo", +]; + +const norm = (s: string) => + s.toLowerCase().replace(/[-\u2010-\u2015\u00ad]/g, " ").replace(/\s+/g, " "); + +const NORMED = ARTISTS.map((a) => [a, norm(a)] as const); + +/** Ime izvajalca iz naslova; prazen niz, ce ga ni na seznamu. */ +export function artistKey(title: string): string { + const t = norm(title || ""); + let best = ""; + let bestPos = Infinity; + for (const [orig, n] of NORMED) { + const p = t.indexOf(n); + if (p >= 0 && (p < bestPos || (p === bestPos && orig.length > best.length))) { + best = orig; + bestPos = p; + } + } + return best ? norm(best) : ""; +} diff --git a/client/src/pages/home.tsx b/client/src/pages/home.tsx index 1e64c69..588d3f5 100644 --- a/client/src/pages/home.tsx +++ b/client/src/pages/home.tsx @@ -1,4 +1,5 @@ import { useQuery } from "@tanstack/react-query"; +import { artistKey } from "@/lib/artists"; import { Link } from "wouter"; import { type Article } from "@shared/schema"; import { format } from "date-fns"; @@ -772,6 +773,27 @@ export default function Home() { return [...head, ...tail]; }, [articles]); + // Na naslovnici isti izvajalec ne sme stati drug ob drugem: med dvema clankoma + // istega izvajalca mora biti vsaj 5 mest. Clanek ostane v rubriki News in v indeksu. + const RAZMIK = 5; + const spaced = useMemo(() => { + const rest = [...shuffled]; + const out: Article[] = []; + const recent: string[] = []; + while (rest.length) { + let idx = rest.findIndex((a) => { + const k = artistKey(a.title || ""); + return !k || !recent.includes(k); + }); + if (idx < 0) idx = 0; + const a = rest.splice(idx, 1)[0]; + out.push(a); + recent.push(artistKey(a.title || "")); + if (recent.length >= RAZMIK) recent.shift(); + } + return out; + }, [shuffled]); + const widgets = useMemo(() => [ { id: "horoscope", el: }, { id: "news", el:
}, @@ -794,19 +816,19 @@ export default function Home() { for (let r = 0; r < widgetRows; r++) { if (wi < widgets.length) items.push({ type: "widget", key: `w-${widgets[wi].id}`, widget: widgets[wi++] }); if (wi < widgets.length) items.push({ type: "widget", key: `w-${widgets[wi].id}`, widget: widgets[wi++] }); - if (ai < shuffled.length) items.push({ type: "article", key: `a-${shuffled[ai].id}`, article: shuffled[ai++] }); - if (ai < shuffled.length) items.push({ type: "article", key: `a-${shuffled[ai].id}`, article: shuffled[ai++] }); + if (ai < spaced.length) items.push({ type: "article", key: `a-${spaced[ai].id}`, article: spaced[ai++] }); + if (ai < spaced.length) items.push({ type: "article", key: `a-${spaced[ai].id}`, article: spaced[ai++] }); } - while (ai < shuffled.length) { - items.push({ type: "article", key: `a-${shuffled[ai].id}`, article: shuffled[ai++] }); + while (ai < spaced.length) { + items.push({ type: "article", key: `a-${spaced[ai].id}`, article: spaced[ai++] }); } const remainder = items.length % 4; - if (remainder > 0 && shuffled.length > 0) { + if (remainder > 0 && spaced.length > 0) { let fill = 0; while (items.length % 4 !== 0) { - const art = shuffled[fill % shuffled.length]; + const art = spaced[fill % spaced.length]; items.push({ type: "article", key: `fill-${fill}`, article: art }); fill++; } @@ -824,7 +846,7 @@ export default function Home() { } return items; - }, [shuffled, widgets]); + }, [spaced, widgets]); const gridRows: (typeof gridItems)[] = useMemo(() => { const rows: (typeof gridItems)[] = [];