commit d5cdd0cf135dc45af6afb1c9e056f9cdd30e77c3
parent 24474441c47aa71c48fb999c78165c06ff85ec91
Author: JayVii <jayvii[AT]posteo[DOT]de>
Date: Mon, 20 Oct 2025 14:18:46 +0200
feat: implement preview mode
Diffstat:
14 files changed, 998 insertions(+), 737 deletions(-)
diff --git a/.htaccess b/.htaccess
@@ -11,6 +11,7 @@ RedirectMatch 404 ^/.htaccess$
RedirectMatch 404 ^/.reuse/.*$
RedirectMatch 404 ^/README.md$
RedirectMatch 404 ^/tools/.*$
+RedirectMatch 404 ^/lib/.*$
# Define custom 404 page
ErrorDocument 404 /404.html
diff --git a/index.php b/index.php
@@ -10,94 +10,27 @@
true
);
- /* OPML Generator */
+ /* Load libraries */
+ foreach (glob("./lib/*.php") as $lib) {
+ include($lib);
+ }
+
+ /* Custom Actions ------------------------------------------------------- */
/* Check for user input */
if (!is_null($_POST["action"])) {
/* Generate OPML */
if ($_POST["action"] === "gen_opml") {
-
- /* Gather news sources from selection */
- $input_keys = preg_grep(
- "/^source-[0-9]+$/",
- array_keys($_POST)
- );
- $sources = array();
- foreach ($input_keys as $key) {
- array_push(
- $sources,
- $config["sources"][$_POST[$key]]
- );
- }
-
- $exp_hash = md5(serialize($sources));
- $file_name = "kontra_" . date("Y-m-d") . "_" . $exp_hash . ".opml";
-
- /* Set Download and content type headers */
- header('Content-Type: application/xml; charset=UTF-8');
- header(
- 'Content-Disposition: Attachment;filename="' . $file_name . '"'
- );
-
- /* Build OPML file */
-?>
-
-<opml version="2.0">
-<head>
- <title>
- Nachrichten-Export von Kontra -
- <?php echo "https://" . $_SERVER["SERVER_NAME"] . PHP_EOL; ?>
- </title>
-</head>
-<body>
-
-<?php
-
- /* Cycle through each source and write source entry */
- $indexes = array(
- "regions", "languages", "access", "medium", "topics"
- );
- foreach ($sources as $source) {
-
- /* Construct title */
- $title = $config["publisher"][$source["publisher"][0]]["name"] .
- ": " . $source["title"];
-
- /* Create category list */
- $categories = array();
- foreach ($indexes as $index) {
- foreach ($source[$index] as $category) {
- array_push(
- $categories,
- $config[$index][$category]["name"]
- );
- }
- }
-
-?>
-
-<outline
- title="<?php echo $title; ?>"
- text="<?php echo $title; ?>"
- category="<?php echo implode(",", $categories); ?>"
- xmlUrl="<?php echo $source["rss"]; ?>"
- htmlUrl="<?php echo $source["web"]; ?>"
-/>
-
-<?php
-
- } // foreach-source
-
-?>
-
-</body>
-</opml>
-
-<?php
-
+ gen_opml($config);
die();
} // if-action
+
+ /* Preview feeds */
+ if ($_POST["action"] === "preview") {
+ gen_preview($config);
+ die();
+ }
} // if-input
?>
@@ -106,673 +39,31 @@
<html>
<!-- Head -->
- <head>
- <meta charset=utf-8>
- <meta name=viewport content="width=device-width,initial-scale=1">
- <link rel=icon href=assets/img/favicon.png type=image/png>
- <link rel=icon href=assets/img/favicon.ico type=x-image/ico>
- <link rel=stylesheet href=assets/css/simple.min.css media=all>
- <link rel=stylesheet href=assets/css/custom.css>
- <script async src=assets/js/filter_engines.js></script>
- <title>Kontra - Das progressive Nachrichtenarchiv</title>
- </head>
+ <?php gen_html_head(); ?>
<!-- Body -->
<body>
- <!-- Header -->
- <header>
- <nav>
- <a href="#sources">
- Nachrichten
- </a>
- <a href="#faqs">
- Was ist das?
- </a>
- <a href="https://src.jayvii.de/pub/kontra/" target="_blank">
- Hilf mit!
- </a>
- </nav>
- <h1>Kontra</h1>
- <p>Das progressive Nachrichtenarchiv</p>
- </header>
+ <!-- Header / Navigation -->
+ <?php gen_html_navigation(); ?>
<!-- Description -->
- <div class="fullheight">
- <div class="description">
- <strong style="font-size: 133%;">
- Nachrichten von Links! Ohne Tracking, ohne Tech-Konzerne und
- ohne algorithmisches Framing.
- </strong>
- <p>
- Auf dieser Seite befinden sich viele seriöse Medienquellen
- aus dem <em>progressiven</em> Spektrum von Zeitungen,
- Magazinen und sonstigen journalistischen Veröffentlichungen,
- aus denen sich persönliche Nachrichten-Feeds erstellen
- lassen.
- </p>
- </div>
- <div class="buttonrow">
- <a href="#usage" class="button c2">
- Wie funktioniert das?
- </a>
- <a href="#sources" class="button c2">
- Zu den Nachrichten!
- </a>
- </div>
- </div>
-
- <div class="fullheight screenshots" id="usage">
- <h3>Was ist Kontra?</h3>
- <figure class="buttonrow">
- <img style="flex:26%;min-width:91px;margin:2.5px;" src="assets/img/applications/gfeeds_mobile.jpg">
- <img style="flex:72%;min-width:252px;margin:2.5px;" src="assets/img/applications/gfeeds_desktop.jpg">
- <figcaption style="width:100%;">
- Nachrichten Feeds aus Kontra in <a href="https://gfeeds.gabmus.org/" target="_blank">Gnome Feeds</a>
- </figcaption>
- </figure>
- <p>
- Kontra versetzt Nutzer:innen in die Lage, selbstbestimmt
- personalisierte Nachrichten-Feeds von seriösen <em>progressiven</em>
- Quellen zu erstellen, um immer auf dem Laufenden zu bleiben.
- Und das selbstverständlich
- <strong>ohne <a href="https://de.wikipedia.org/wiki/Web_Analytics" target="_blank">Tracking</a></strong>,
- <strong>ohne Datensammelwut</strong>,
- <strong>ohne Konto-Zwang</strong>
- <strong>ohne <a href="https://de.wikipedia.org/wiki/Soziales_Netzwerk_(Internet)#Kritik" target="_blank">Algorithmen</a></strong> und
- <strong>ohne <a href="https://de.wikipedia.org/wiki/Lock-in-Effekt" target="_blank">Lock-In Effekte</a></strong>.
- Wie das funktioniert, erfährst du <a href="#faqs">hier</a>!
- </p>
- <p>
- Die in Kontra hinterlegten Medien behandeln ein breites Spektrum
- an Themen und mit unterschiedlichen Fokuspunkten. Sie vereint
- eine <em>progressive</em> und politisch <em>linke</em>
- Sichtweise. Die Idee hinter Kontra ist, die Nutzung von Medien
- zu vereinfachen und Menschen in die Lage zu versetzen, selbst
- kuratierte Nachrichtenquellen und Themenbereiche zu verfolgen.
- </p>
- <p>
- Kontra ist ein Archiv mit aktuell
- <strong><?php echo count($config["sources"]); ?></strong>
- Nachrichten-Feeds aus
- <strong><?php echo count($config["publisher"]); ?></strong>
- unterschiedlichen Quellen, zu
- <strong><?php echo count($config["topics"]); ?></strong>
- Themenbereichen, innerhalb von
- <strong><?php echo count($config["regions"]); ?></strong>
- Regionen, in
- <strong><?php echo count($config["languages"]); ?></strong>
- verschiedenen Sprachen. Nutzer:innen können sich aus diesem
- Katalog eigene Nachrichten-Feeds gänzlich nach ihren Interessen
- zusammenstellen. Die hier herunterladbaren
- <a href="https://de.wikipedia.org/wiki/Outline_Processor_Markup_Language" target="_blank">
- Nachrichten-Feed Dateien</a>
- können in beliebigen
- <a href="https://de.wikipedia.org/wiki/Feedreader" target="_blank">
- Feed-Readern</a>
- eingeladen und sofort genutzt werden!
- Zum Beispiel in diesen
- <a href="https://fsfe.org/freesoftware/freesoftware.de.html" target="_blank">
- Freien</a>
- und kostenlosen Apps für Android und iOS:
- <ul>
- <li><a href="https://apps.apple.com/us/app/netnewswire-rss-reader/id1480640210" target="_blank">NetNewsWire (iOS)</a></li>
- <li><a href="https://apps.apple.com/us/app/twine-rss-reader/id6465694958" target="_blank">Twine (iOS)</a></li>
- <li><a href="https://play.google.com/store/apps/details?id=com.nononsenseapps.feeder.play" target="_blank">Feeder (Android)</a></li>
- <li><a href="https://play.google.com/store/apps/details?id=dev.sasikanth.rss.reader" target="_blank">Twine (Android)</a></li>
- <li><a href="https://freshrss.org/" target="_blank">FreshRSS (Web)</a></li>
- <li><a href="https://www.thunderbird.net/de/" target="_blank">Thunderbird (Windows, MacOS, Linux)</a></li>
- <li><a href="https://gfeeds.gabmus.org/" target="_blank">Feeds (Linux)</a></li>
- <li><a href="https://apps.gnome.org/de/NewsFlash/" target="_blank">NewsFlash (Linux)</a></li>
- <li><a href="https://apps.kde.org/de/alligator/" target="_blank">Alligator (Linux)</a></li>
- <li><a href="https://alternativeto.net/browse/search/?q=rss%20reader" target="_blank">und viele weitere</a>...</li>
- </ul>
- </p>
- <p>
- Ganz einfach in nur <strong>zwei Minuten</strong> loslegen!
- Nachrichtenquellen aussuchen, Feed-Datei herunterladen, in
- den Reader importieren und sofort informiert werden.
- </p>
-
- <div class="buttonrow">
- <a href="#faqs" class="button c2">
- Mehr erfahren
- </a>
- <a href="#sources" class="button c2">
- Zu den Nachrichten!
- </a>
- </div>
- </div>
-
- <!-- Search Engine Lists -->
- <h3 id="sources" style="margin-top:5em;">
- Eigenen Nachrichten-Feed generieren
- </h3>
- <p>
- Wähle beliebig viele Nachrichtenquellen aus der unteren Liste aus
- und klicke auf den <strong>Nachrichten-Feed erzeugen</strong> Knopf.
- Speichere die darauf angebotene OPML-Datei ab und importiere sie in
- deinen RSS-Reader.
- </p>
- <p>
- Kontra bietet zur Zeit Zugriff auf
- <strong><?php echo count($config["sources"]); ?></strong>
- Nachrichten-Feeds aus
- <strong><?php echo count($config["publisher"]); ?></strong>
- unterschiedlichen Quellen, zu
- <strong><?php echo count($config["topics"]); ?></strong>
- Themenbereichen, innerhalb von
- <strong><?php echo count($config["regions"]); ?></strong>
- Regionen, in
- <strong><?php echo count($config["languages"]); ?></strong>
- verschiedenen Sprachen. Nutze die Suchfunktion und die
- Kategorienliste, um die Auswahl zu erleichtern.
- </p>
- <!-- Filterbar -->
- <input
- id="sources_filterbar"
- name="sources"
- type="text"
- placeholder="Suche nach Nachrichtenquellen oder Kategorien..."
- oninput="filter_sources('sources_filterbar');"
- >
- <noscript>
- <div class="notice">
- <p>
- Achtung: Die Nutzung der Suchfunktion benötigt aktiviertes
- JavaScript. Entweder unterstützt dein Browser diese
- Funktion nicht, oder du hast sie auf dieser Seite blockiert.
- <strong>
- Du kannst dennoch einen Nachrichten-Feed erzeugen, jedoch
- ohne die Suchfunktion oben dafür nutzen zu können.
- </strong>
- </p>
- </div>
- </noscript>
-
- <!-- Category Buttons -->
- <details id="categories">
- <summary>Kategorien</summary>
-
- <h4>Themen</h4>
- <div class="row">
-
- <!-- List all configured regions -->
- <?php
- foreach ($config["topics"] as $topic) {
- ?>
- <button
- onclick="filter_category('<?php echo $topic["name"]; ?>');"
- title="<?php echo $topic["description"]; ?>"
- >
- <?php echo "#" . $topic["name"]; ?>
- </button>
- <?php
- }
- ?>
-
- </div>
-
- <h4>Regionen</h4>
- <div class="row">
+ <?php gen_html_description(); ?>
- <!-- List all configured regions -->
- <?php
- foreach ($config["regions"] as $region) {
- ?>
- <button
- onclick="filter_category('<?php echo $region["name"]; ?>');"
- title="<?php echo $region["description"]; ?>"
- >
- <?php echo "#" . $region["name"]; ?>
- </button>
- <?php
- }
- ?>
+ <!-- Usage -->
+ <?php gen_html_usage($config); ?>
- </div>
-
- <h4>Sprachen</h4>
- <div class="row">
-
- <!-- List all configured languages -->
- <?php
- foreach ($config["languages"] as $language) {
- ?>
- <button
- onclick="filter_category('<?php echo $language["name"]; ?>');"
- title="<?php echo $language["description"]; ?>"
- >
- <?php echo "#" . $language["name"]; ?>
- </button>
- <?php
- }
- ?>
-
- </div>
-
- <h4>Zugriff</h4>
- <div class="row">
-
- <!-- List all configured access types -->
- <?php
- foreach ($config["access"] as $access) {
- ?>
- <button
- onclick="filter_category('<?php echo $access["name"]; ?>');"
- title="<?php echo $access["description"]; ?>"
- >
- <?php echo "#" . $access["name"]; ?>
- </button>
- <?php
- }
- ?>
-
- </div>
-
- <h4>Medium</h4>
- <div class="row">
-
- <!-- List all configured media -->
- <?php
- foreach ($config["medium"] as $medium) {
- ?>
- <button
- onclick="filter_category('<?php echo $medium["name"]; ?>');"
- title="<?php echo $medium["description"]; ?>"
- >
- <?php echo "#" . $medium["name"]; ?>
- </button>
- <?php
- }
- ?>
-
- </div>
-
- <h4>Quellen</h4>
- <div class="row">
-
- <!-- List all configured sources -->
- <?php
- foreach ($config["publisher"] as $publisher) {
- ?>
- <button
- onclick="filter_category('<?php echo $publisher["button"]; ?>');"
- title="<?php echo $publisher["description"]; ?>"
- >
- <?php echo "#" . $publisher["button"]; ?>
- </button>
- <?php
- }
- ?>
-
- </div>
-
- </details>
+ <!-- Categories List -->
+ <?php gen_html_categories($config); ?>
<!-- Sources List -->
- <form id="sources-selection" method="post">
-
- <!-- Submit button -->
- <div class="submit-container">
- <input type="submit" value="Nachrichten-Feed erzeugen!">
- <a href="#sources" class="button" title="Nach oben">
- 👆 <stretch class="nomobile">Nach oben</stretch>
- </a>
- <a href="#faqs" class="button" title="Nach unten">
- 👇 <stretch class="nomobile">Nach unten</stretch>
- </a>
- </div>
- <input type="hidden" name="action" value="gen_opml">
- <?php
- $cnt = 0;
- foreach ($config["sources"] as $id => $source) {
- $cnt++; // increase counter for POST field ID
-
- /* Gather publishing medium info */
- $publisher = $config["publisher"][
- array_pop($source["publisher"])
- ];
- ?>
- <article>
- <!-- Entry-Head -->
- <h3>
- <a href="<?php echo $source["web"]; ?>" target="_blank">
- <?php
- echo $publisher["name"] . ": " . $source["title"];
- ?>
- </a>
- </h3>
-
- <!-- Description -->
- <p>
- <?php
- echo $publisher["desc"] . " " . $source["desc"];
- ?>
- </p>
-
- <!-- Choose this Button -->
- <input
- type="checkbox"
- name="<?php echo "source-" . $cnt; ?>"
- value="<?php echo $id; ?>"
- >
- <label for="<?php echo $id; ?>">
- Diese Nachrichtenquelle auswählen
- </label>
-
- <!-- Entry-Categories -->
- <table style="width:100%;">
-
- <tr>
- <th>Quelle:</th>
- <td>
- <mark title="<?php echo $publisher["desc"];?>">
- <?php echo "#" . $publisher["button"]; ?>
- </mark>
- </td>
- </tr>
-
- <tr>
- <th>Region:</th>
- <td>
- <?php
- foreach ($source["regions"] as $region) {
- $catentry = $config["regions"][$region]
- ?>
- <mark title="<?php echo $catentry["description"];?>">
- <?php echo "#" . $catentry["name"]; ?>
- </mark>
- <?php
- }
- ?>
- </td>
- </tr>
-
- <tr>
- <th>Sprachen:</th>
- <td>
- <?php
- foreach ($source["languages"] as $language) {
- $catentry = $config["languages"][$language]
- ?>
- <mark title="<?php echo $catentry["description"];?>">
- <?php echo "#" . $catentry["name"]; ?>
- </mark>
- <?php
- }
- ?>
- </td>
- </tr>
-
- <tr>
- <th>Zugang:</th>
- <td>
- <?php
- foreach ($source["access"] as $access) {
- $catentry = $config["access"][$access]
- ?>
- <mark title="<?php echo $catentry["description"];?>">
- <?php echo "#" . $catentry["name"]; ?>
- </mark>
- <?php
- }
- ?>
- </td>
- </tr>
-
- <tr>
- <th>Medium:</th>
- <td>
- <?php
- foreach ($source["medium"] as $medium) {
- $catentry = $config["medium"][$medium]
- ?>
- <mark title="<?php echo $catentry["description"];?>">
- <?php echo "#" . $catentry["name"]; ?>
- </mark>
- <?php
- }
- ?>
- </td>
- </tr>
-
- <tr>
- <th>Themen:</th>
- <td>
- <?php
- foreach ($source["topics"] as $topic) {
- $catentry = $config["topics"][$topic]
- ?>
- <mark title="<?php echo $catentry["description"];?>">
- <?php echo "#" . $catentry["name"]; ?>
- </mark>
- <?php
- }
- ?>
- </td>
- <tr>
- </table>
-
- </article>
- <?php
- }
- ?>
- </form>
+ <?php gen_html_feeds($config); ?>
<!-- FAQs / About-Section -->
- <section id="faqs">
-
- <h3>Was ist <em>Kontra</em>?</h3>
-
- <details>
- <summary>Was sind Feed-Reader / RSS-Reader?</summary>
- <p>
- Feed- oder RSS-Reader erlauben es, so genannte RSS-Feeds zu
- <em>abonnieren</em>, um regelmäßig Nachrichten von diesen zu
- erhalten. Das Konzept ist vergleichbar mit einem E-Mail
- Newsletter.
- </p>
- <p>
- Der Unterschied besteht darin, dass man, um einen Newsletter
- erhalten zu können, den Versender:innen eine E-Mail Adresse
- hinterlegen muss. Newsletter werden dann aktiv von den
- Versender:innen an bekannte Empfänger:innen verschickt.
- </p>
- <p>
- Bei RSS-Feeds ist es umgekehrt. Empfänger:innen (bzw. von
- ihnen genutzt Feed-Reader) ziehen sich die Nachrichten von
- den Nachrichten-Seiten oder Blogs selbst. Letztere wissen
- dabei gar nicht, wer die Empfänger:innen sind oder wie viele
- es letztendlich sind.
- </p>
- <p>
- Der RSS-Reader ist lediglich die Software, welche die
- Nachrichten empfängt und diese oft in einem Listen-Format
- zum Lesen anzeigt. Es gibt eine Vielzahl wirklich guter
- und zeitgemäßer RSS-Reader für alle möglichen Endgeräte,
- ganz egal ob am PC, Smartphone, Tablet, E-Book-Reader oder
- per Webbrowser.
- </p>
- <p>
- Folgende RSS-Reader sind kostenlos und darüber hinaus noch
- <a href="https://fsfe.org/freesoftware/freesoftware.de.html" target="_blank">
- Freie, Open Source Software
- </a>:
- <ul>
- <li><a href="https://apps.apple.com/us/app/netnewswire-rss-reader/id1480640210" target="_blank">NetNewsWire (iOS)</a></li>
- <li><a href="https://apps.apple.com/us/app/twine-rss-reader/id6465694958" target="_blank">Twine (iOS)</a></li>
- <li><a href="https://play.google.com/store/apps/details?id=com.nononsenseapps.feeder.play" target="_blank">Feeder (Android)</a></li>
- <li><a href="https://play.google.com/store/apps/details?id=dev.sasikanth.rss.reader" target="_blank">Twine (Android)</a></li>
- <li><a href="https://freshrss.org/" target="_blank">FreshRSS (Web)</a></li>
- <li><a href="https://www.thunderbird.net/de/" target="_blank">Thunderbird (Windows, MacOS, Linux)</a></li>
- <li><a href="https://gfeeds.gabmus.org/" target="_blank">Feeds (Linux)</a></li>
- <li><a href="https://apps.kde.org/de/alligator/" target="_blank">Alligator (Linux)</a></li>
- <li><a href="https://alternativeto.net/browse/search/?q=rss%20reader" target="_blank">und viele weitere</a>...</li>
- </ul>
- </p>
- </details>
-
- <details>
- <summary>Kann ich weitere Nachrichten-Feeds abonnieren?</summary>
- <p>
- Ja! Gibt es Nachrichtenquellen, die nicht in Kontra
- enthalten sind, kann man diese auch einzeln im eigenen
- Feed-Reader abonnieren. Auch das ist sehr einfach und dauert
- in der Regel nur wenige Sekunden.
- </p>
- <p>
- Fast alle Online-Medien haben eine Unterseite, auf der sie
- ihre RSS-Feeds auflisten. Folgende Medien sind
- beispielsweise wegen des Fokus auf dediziert progressive Medien
- nicht in Kontra enthalten, lassen sich aber sehr einfach
- über einen RSS-Reader abonnieren:
- <ul>
- <li><a href="https://www.tagesschau.de/infoservices/rssfeeds" target="_blank">Tagesschau (ÖRR)</a></li>
- <li><a href="https://www.deutschlandfunk.de/rss-angebot-102.html" target="_blank">Deutschlandfunk (ÖRR)</a></li>
- <li><a href="https://www.sueddeutsche.de/service/updates-mit-rss-uebersicht-aller-rss-feeds-fuer-sz-de-sz-magazin-und-jetzt-de-1.393950" target="_blank">Süddeutsche Zeitung</a></li>
- </ul>
- </p>
- </details>
-
- <details>
- <summary>Ist Kontra kostenlos?</summary>
- <p>
- Ja! Kontra ist und bleibt kostenlos. Es ist lediglich ein
- kleines privates Software-Projekt einer Einzelperson.
- </p>
- <p>
- Zudem wird Kontra als
- <a href="https://fsfe.org/freesoftware/freesoftware.de.html" target="_blank">
- Freie, Open Source Software
- </a>
- entwickelt. Der Programm-Code kann also von allen jederzeit
- eingesehen werden. Verbesserungsvorschläge oder eigene
- Code-Beiträge sind stets willkommen. Es ist auch erlaubt,
- eigene Projekte auf Kontra aufzubauen. Diese müssen jedoch
- ebenfalls unter einer Freien Software-Lizenz stehen.
- </p>
- <p>
- Du möchtest helfen?
- <a href="https://src.jayvii.de/pub/kontra/" target="_blank">
- Hier
- </a> findest du mehr Informationen dazu.
- </p>
- </details>
-
- <details>
- <summary>Ist das <em>Abonnieren</em> eines RSS-Feed kostenlos?</summary>
- <p>
- Ja! Allerdings kann es sein, dass einige der in den
- Nachrichten-Feeds angebotenen Artikel hinter einer
- Bezahlschranke liegen, also oft nicht in voller Länge
- gelesen werden können, ohne ein Abonnement bei der
- jeweiligen Online-Publikation, bzw. ein Zeitungsabonnement
- abzuschließen.
- </p>
- <p>
- Kontra kennzeichnet Nachrichtenquellen, bei denen einige
- Artikel hinter einer Bezahlschranke liegen können.
- Nachrichtenquellen, die niemals eine Bezahlschranke nutzen
- sind ebenfalls in einer eigenen Kategorie.
- </p>
- </details>
-
- <details>
- <summary>Sammelt Kontra meine Daten?</summary>
- <p>
- Nein! Kontra sammelt keinerlei Datein über Personen und
- Geräte, die diese Seite besuchen und Kontra nutzen.
- Technisch bedingt, wird bei jedem Aufruf <em>jeder</em>
- Webseite im Internet mindestens die eigene IP-Adresse und
- oft noch weitere Informationen über das Betriebssystem, den
- Webbrowser, bzw. das verwendete Gerät übermittelt. Kontra
- speichert <strong>keine</strong> dieser Informationen.
- </p>
- <p>
- Zudem stellt Kontra lediglich das Archiv von RSS-Feeds zur
- Verfügung. Kontra speichert außerdem keine Informationen
- darüber, welche Nachrichtenquellen von Nutzer:innen
- ausgewählt werden.
- </p>
- <p>
- Mit dem Herunterladen der Feed-Datei endet der
- Datenaustausch zwischen den Nutzer:innen und Kontra. Kontra
- hat technisch bedingt keinen Einblick darin, ob und welche
- Nachrichten Nutzende in einen Feedreader einlesen oder
- welche Nachrichten tatsächlich von Nutzer:innen gelesen
- werden. Das liegt daran, dass die Nachrichten
- <strong>direkt</strong> und ohne Umwege von den jeweiligen
- Nachrichtenseiten kommen und zu keinem Zeitpunkt über Kontra
- laufen.
- </p>
- </details>
-
- <details>
- <summary>Welche Technik nutzt Kontra?</summary>
- <p>
- Millionen Webseiten und Online-Zeitungen weltweit bieten die
- offene Schnittstelle
- <a href="https://de.wikipedia.org/wiki/RSS_(Web-Feed)" target="_blank">
- RSS
- </a> (zu deutsch: <em>sehr einfache Verbreitung</em>) an.
- Nahezu jeder Blog, jede Nachrichtenseite und
- Online-Veröffentlichungen nutzen einen <em>RSS</em> Feed.
- Das ist eine maschinenlesbare Datei, welche alle dort
- veröffentlichte Nachrichten und einige Zusatzinformationen
- (Veröffentlichungszeitpunkt, Autor:in, Kurzzusammenfassung,
- usw.) enthält. RSS kann als <em>schwarzes Brett</em>
- digitaler Medien verstanden werden.
- </p>
- <p>
- Kontra stellt eben diese RSS-Feeds für alle von Nutzer:innen
- ausgewählte Medien in einer herunterladbaren Datei zusammen,
- die in üblichen Feedreadern (siehe:
- <em><strong>Was sind Feedreader?</strong></em>) importiert
- werden kann. Diese Datei basiert auf dem offenen
- <a href="https://de.wikipedia.org/wiki/Outline_Processor_Markup_Language", target="_blank">
- OPML
- </a> Format und wird von nahezu allen RSS/Feed-Readern
- verstanden. Damit gewährleistet Kontra, dass es keinen
- sogenannten <em>Lock-In</em> Effekt gibt, der Nutzer:innen
- an eine einzige App binden und der Wechsel zu Alternativen
- erschwert.
- </p>
- <p>
- Die angesprochenen OPML-Dateien enthalten nicht nur die
- RSS-Feeds selbst, sondern auch alle Kategorien, die man
- ihnen innerhalb des eigenen Feed-Readers zugewiesen hat. Die
- OPML-Dateien aus Kontra enthalten alle Kategorie-Label, die
- auch in der Liste sichtbar sind.
- </p>
- <p>
- <strong>Kurzum:</strong> RSS und OPML sind die grundlegende
- Technik, auf die <em>Kontra</em> setzt. Nachrichten können
- darüber direkt von Blogs und Zeitungen bezogen werden, ohne
- dass Dritte Einsicht darin haben. Feeds können in nahezu
- allen Feedreadern importiert und exportiert werden. Ein
- Wechsel von einer App zu einer anderen ist also innerhalb
- von Sekunden möglich.
- </p>
- </details>
-
- </section>
+ <?php gen_html_faqs($config); ?>
- <footer>
- <h4>Disclaimer</h4>
- <p>
- Die Schlagzeilen, Inhalte oder Einstellungen der Redakteur:innen
- und Autor:innen der hier aufgeführten Nachrichtenagenturen,
- Blogs und Zeitungen spiegeln nicht unbedingt die Meinungen und
- Einstellungen der Entwickler:innen und Betreiber:innen von
- <em>Kontra</em> wider. <em>Kontra</em> ist ein Quellenarchiv für
- Nachrichtenaggregatoren, der Inhalte aus vielen verschiedenen
- Quellen zusammenführt werden. <em>Kontra</em> hat
- selbstverständlich keinen direkten Einfluss auf den
- redaktionellen Inhalt.
- </p>
- <em>Version:</em> <code><?php echo $config["version"]; ?></code>
- </footer>
+ <!-- Footer -->
+ <?php gen_html_footer($config); ?>
</body>
diff --git a/lib/gen_html_categories.php b/lib/gen_html_categories.php
@@ -0,0 +1,172 @@
+<?php
+function gen_html_categories($config) {
+?>
+
+<h3 id="sources" style="margin-top:5em;">
+ Eigenen Nachrichten-Feed generieren
+</h3>
+<p>
+ Wähle beliebig viele Nachrichtenquellen aus der unteren Liste aus
+ und klicke auf den <strong>Nachrichten-Feed erzeugen</strong> Knopf.
+ Speichere die darauf angebotene OPML-Datei ab und importiere sie in
+ deinen RSS-Reader.
+</p>
+<p>
+ Kontra bietet zur Zeit Zugriff auf
+ <strong><?php echo count($config["sources"]); ?></strong>
+ Nachrichten-Feeds aus
+ <strong><?php echo count($config["publisher"]); ?></strong>
+ unterschiedlichen Quellen, zu
+ <strong><?php echo count($config["topics"]); ?></strong>
+ Themenbereichen, innerhalb von
+ <strong><?php echo count($config["regions"]); ?></strong>
+ Regionen, in
+ <strong><?php echo count($config["languages"]); ?></strong>
+ verschiedenen Sprachen. Nutze die Suchfunktion und die
+ Kategorienliste, um die Auswahl zu erleichtern.
+</p>
+<!-- Filterbar -->
+<input
+ id="sources_filterbar"
+ name="sources"
+ type="text"
+ placeholder="Suche nach Nachrichtenquellen oder Kategorien..."
+ oninput="filter_sources('sources_filterbar');"
+>
+<noscript>
+ <div class="notice">
+ <p>
+ Achtung: Die Nutzung der Suchfunktion benötigt aktiviertes
+ JavaScript. Entweder unterstützt dein Browser diese
+ Funktion nicht, oder du hast sie auf dieser Seite blockiert.
+ <strong>
+ Du kannst dennoch einen Nachrichten-Feed erzeugen, jedoch
+ ohne die Suchfunktion oben dafür nutzen zu können.
+ </strong>
+ </p>
+ </div>
+</noscript>
+
+<!-- Category Buttons -->
+<details id="categories">
+ <summary>Kategorien</summary>
+
+ <h4>Themen</h4>
+ <div class="row">
+
+ <!-- List all configured regions -->
+ <?php
+ foreach ($config["topics"] as $topic) {
+ ?>
+ <button
+ onclick="filter_category('<?php echo $topic["name"]; ?>');"
+ title="<?php echo $topic["description"]; ?>"
+ >
+ <?php echo "#" . $topic["name"]; ?>
+ </button>
+ <?php
+ }
+ ?>
+
+ </div>
+
+ <h4>Regionen</h4>
+ <div class="row">
+
+ <!-- List all configured regions -->
+ <?php
+ foreach ($config["regions"] as $region) {
+ ?>
+ <button
+ onclick="filter_category('<?php echo $region["name"]; ?>');"
+ title="<?php echo $region["description"]; ?>"
+ >
+ <?php echo "#" . $region["name"]; ?>
+ </button>
+ <?php
+ }
+ ?>
+
+ </div>
+
+ <h4>Sprachen</h4>
+ <div class="row">
+
+ <!-- List all configured languages -->
+ <?php
+ foreach ($config["languages"] as $language) {
+ ?>
+ <button
+ onclick="filter_category('<?php echo $language["name"]; ?>');"
+ title="<?php echo $language["description"]; ?>"
+ >
+ <?php echo "#" . $language["name"]; ?>
+ </button>
+ <?php
+ }
+ ?>
+
+ </div>
+
+ <h4>Zugriff</h4>
+ <div class="row">
+
+ <!-- List all configured access types -->
+ <?php
+ foreach ($config["access"] as $access) {
+ ?>
+ <button
+ onclick="filter_category('<?php echo $access["name"]; ?>');"
+ title="<?php echo $access["description"]; ?>"
+ >
+ <?php echo "#" . $access["name"]; ?>
+ </button>
+ <?php
+ }
+ ?>
+
+ </div>
+
+ <h4>Medium</h4>
+ <div class="row">
+
+ <!-- List all configured media -->
+ <?php
+ foreach ($config["medium"] as $medium) {
+ ?>
+ <button
+ onclick="filter_category('<?php echo $medium["name"]; ?>');"
+ title="<?php echo $medium["description"]; ?>"
+ >
+ <?php echo "#" . $medium["name"]; ?>
+ </button>
+ <?php
+ }
+ ?>
+
+ </div>
+
+ <h4>Quellen</h4>
+ <div class="row">
+
+ <!-- List all configured sources -->
+ <?php
+ foreach ($config["publisher"] as $publisher) {
+ ?>
+ <button
+ onclick="filter_category('<?php echo $publisher["button"]; ?>');"
+ title="<?php echo $publisher["description"]; ?>"
+ >
+ <?php echo "#" . $publisher["button"]; ?>
+ </button>
+ <?php
+ }
+ ?>
+
+ </div>
+
+</details>
+
+<?php
+}
+?>
diff --git a/lib/gen_html_description.php b/lib/gen_html_description.php
@@ -0,0 +1,31 @@
+<?php
+function gen_html_description() {
+?>
+
+<div class="fullheight">
+ <div class="description">
+ <strong style="font-size: 133%;">
+ Nachrichten von Links! Ohne Tracking, ohne Tech-Konzerne und
+ ohne algorithmisches Framing.
+ </strong>
+ <p>
+ Auf dieser Seite befinden sich viele seriöse Medienquellen
+ aus dem <em>progressiven</em> Spektrum von Zeitungen,
+ Magazinen und sonstigen journalistischen Veröffentlichungen,
+ aus denen sich persönliche Nachrichten-Feeds erstellen
+ lassen.
+ </p>
+ </div>
+ <div class="buttonrow">
+ <a href="#usage" class="button c2">
+ Wie funktioniert das?
+ </a>
+ <a href="#sources" class="button c2">
+ Zu den Nachrichten!
+ </a>
+ </div>
+</div>
+
+<?php
+}
+?>
diff --git a/lib/gen_html_faqs.php b/lib/gen_html_faqs.php
@@ -0,0 +1,204 @@
+<?php
+function gen_html_faqs($config) {
+?>
+
+<section id="faqs">
+
+ <h3>Was ist <em>Kontra</em>?</h3>
+
+ <details>
+ <summary>Was sind Feed-Reader / RSS-Reader?</summary>
+ <p>
+ Feed- oder RSS-Reader erlauben es, so genannte RSS-Feeds zu
+ <em>abonnieren</em>, um regelmäßig Nachrichten von diesen zu
+ erhalten. Das Konzept ist vergleichbar mit einem E-Mail
+ Newsletter.
+ </p>
+ <p>
+ Der Unterschied besteht darin, dass man, um einen Newsletter
+ erhalten zu können, den Versender:innen eine E-Mail Adresse
+ hinterlegen muss. Newsletter werden dann aktiv von den
+ Versender:innen an bekannte Empfänger:innen verschickt.
+ </p>
+ <p>
+ Bei RSS-Feeds ist es umgekehrt. Empfänger:innen (bzw. von
+ ihnen genutzt Feed-Reader) ziehen sich die Nachrichten von
+ den Nachrichten-Seiten oder Blogs selbst. Letztere wissen
+ dabei gar nicht, wer die Empfänger:innen sind oder wie viele
+ es letztendlich sind.
+ </p>
+ <p>
+ Der RSS-Reader ist lediglich die Software, welche die
+ Nachrichten empfängt und diese oft in einem Listen-Format
+ zum Lesen anzeigt. Es gibt eine Vielzahl wirklich guter
+ und zeitgemäßer RSS-Reader für alle möglichen Endgeräte,
+ ganz egal ob am PC, Smartphone, Tablet, E-Book-Reader oder
+ per Webbrowser.
+ </p>
+ <p>
+ Folgende RSS-Reader sind kostenlos und darüber hinaus noch
+ <a href="https://fsfe.org/freesoftware/freesoftware.de.html" target="_blank">
+ Freie, Open Source Software
+ </a>:
+ <ul>
+ <li><a href="https://apps.apple.com/us/app/netnewswire-rss-reader/id1480640210" target="_blank">NetNewsWire (iOS)</a></li>
+ <li><a href="https://apps.apple.com/us/app/twine-rss-reader/id6465694958" target="_blank">Twine (iOS)</a></li>
+ <li><a href="https://play.google.com/store/apps/details?id=com.nononsenseapps.feeder.play" target="_blank">Feeder (Android)</a></li>
+ <li><a href="https://play.google.com/store/apps/details?id=dev.sasikanth.rss.reader" target="_blank">Twine (Android)</a></li>
+ <li><a href="https://freshrss.org/" target="_blank">FreshRSS (Web)</a></li>
+ <li><a href="https://www.thunderbird.net/de/" target="_blank">Thunderbird (Windows, MacOS, Linux)</a></li>
+ <li><a href="https://gfeeds.gabmus.org/" target="_blank">Feeds (Linux)</a></li>
+ <li><a href="https://apps.kde.org/de/alligator/" target="_blank">Alligator (Linux)</a></li>
+ <li><a href="https://alternativeto.net/browse/search/?q=rss%20reader" target="_blank">und viele weitere</a>...</li>
+ </ul>
+ </p>
+ </details>
+
+ <details>
+ <summary>Kann ich weitere Nachrichten-Feeds abonnieren?</summary>
+ <p>
+ Ja! Gibt es Nachrichtenquellen, die nicht in Kontra
+ enthalten sind, kann man diese auch einzeln im eigenen
+ Feed-Reader abonnieren. Auch das ist sehr einfach und dauert
+ in der Regel nur wenige Sekunden.
+ </p>
+ <p>
+ Fast alle Online-Medien haben eine Unterseite, auf der sie
+ ihre RSS-Feeds auflisten. Folgende Medien sind
+ beispielsweise wegen des Fokus auf dediziert progressive Medien
+ nicht in Kontra enthalten, lassen sich aber sehr einfach
+ über einen RSS-Reader abonnieren:
+ <ul>
+ <li><a href="https://www.tagesschau.de/infoservices/rssfeeds" target="_blank">Tagesschau (ÖRR)</a></li>
+ <li><a href="https://www.deutschlandfunk.de/rss-angebot-102.html" target="_blank">Deutschlandfunk (ÖRR)</a></li>
+ <li><a href="https://www.sueddeutsche.de/service/updates-mit-rss-uebersicht-aller-rss-feeds-fuer-sz-de-sz-magazin-und-jetzt-de-1.393950" target="_blank">Süddeutsche Zeitung</a></li>
+ </ul>
+ </p>
+ </details>
+
+ <details>
+ <summary>Ist Kontra kostenlos?</summary>
+ <p>
+ Ja! Kontra ist und bleibt kostenlos. Es ist lediglich ein
+ kleines privates Software-Projekt einer Einzelperson.
+ </p>
+ <p>
+ Zudem wird Kontra als
+ <a href="https://fsfe.org/freesoftware/freesoftware.de.html" target="_blank">
+ Freie, Open Source Software
+ </a>
+ entwickelt. Der Programm-Code kann also von allen jederzeit
+ eingesehen werden. Verbesserungsvorschläge oder eigene
+ Code-Beiträge sind stets willkommen. Es ist auch erlaubt,
+ eigene Projekte auf Kontra aufzubauen. Diese müssen jedoch
+ ebenfalls unter einer Freien Software-Lizenz stehen.
+ </p>
+ <p>
+ Du möchtest helfen?
+ <a href="https://src.jayvii.de/pub/kontra/" target="_blank">
+ Hier
+ </a> findest du mehr Informationen dazu.
+ </p>
+ </details>
+
+ <details>
+ <summary>Ist das <em>Abonnieren</em> eines RSS-Feed kostenlos?</summary>
+ <p>
+ Ja! Allerdings kann es sein, dass einige der in den
+ Nachrichten-Feeds angebotenen Artikel hinter einer
+ Bezahlschranke liegen, also oft nicht in voller Länge
+ gelesen werden können, ohne ein Abonnement bei der
+ jeweiligen Online-Publikation, bzw. ein Zeitungsabonnement
+ abzuschließen.
+ </p>
+ <p>
+ Kontra kennzeichnet Nachrichtenquellen, bei denen einige
+ Artikel hinter einer Bezahlschranke liegen können.
+ Nachrichtenquellen, die niemals eine Bezahlschranke nutzen
+ sind ebenfalls in einer eigenen Kategorie.
+ </p>
+ </details>
+
+ <details>
+ <summary>Sammelt Kontra meine Daten?</summary>
+ <p>
+ Nein! Kontra sammelt keinerlei Datein über Personen und
+ Geräte, die diese Seite besuchen und Kontra nutzen.
+ Technisch bedingt, wird bei jedem Aufruf <em>jeder</em>
+ Webseite im Internet mindestens die eigene IP-Adresse und
+ oft noch weitere Informationen über das Betriebssystem, den
+ Webbrowser, bzw. das verwendete Gerät übermittelt. Kontra
+ speichert <strong>keine</strong> dieser Informationen.
+ </p>
+ <p>
+ Zudem stellt Kontra lediglich das Archiv von RSS-Feeds zur
+ Verfügung. Kontra speichert außerdem keine Informationen
+ darüber, welche Nachrichtenquellen von Nutzer:innen
+ ausgewählt werden.
+ </p>
+ <p>
+ Mit dem Herunterladen der Feed-Datei endet der
+ Datenaustausch zwischen den Nutzer:innen und Kontra. Kontra
+ hat technisch bedingt keinen Einblick darin, ob und welche
+ Nachrichten Nutzende in einen Feedreader einlesen oder
+ welche Nachrichten tatsächlich von Nutzer:innen gelesen
+ werden. Das liegt daran, dass die Nachrichten
+ <strong>direkt</strong> und ohne Umwege von den jeweiligen
+ Nachrichtenseiten kommen und zu keinem Zeitpunkt über Kontra
+ laufen.
+ </p>
+ </details>
+
+ <details>
+ <summary>Welche Technik nutzt Kontra?</summary>
+ <p>
+ Millionen Webseiten und Online-Zeitungen weltweit bieten die
+ offene Schnittstelle
+ <a href="https://de.wikipedia.org/wiki/RSS_(Web-Feed)" target="_blank">
+ RSS
+ </a> (zu deutsch: <em>sehr einfache Verbreitung</em>) an.
+ Nahezu jeder Blog, jede Nachrichtenseite und
+ Online-Veröffentlichungen nutzen einen <em>RSS</em> Feed.
+ Das ist eine maschinenlesbare Datei, welche alle dort
+ veröffentlichte Nachrichten und einige Zusatzinformationen
+ (Veröffentlichungszeitpunkt, Autor:in, Kurzzusammenfassung,
+ usw.) enthält. RSS kann als <em>schwarzes Brett</em>
+ digitaler Medien verstanden werden.
+ </p>
+ <p>
+ Kontra stellt eben diese RSS-Feeds für alle von Nutzer:innen
+ ausgewählte Medien in einer herunterladbaren Datei zusammen,
+ die in üblichen Feedreadern (siehe:
+ <em><strong>Was sind Feedreader?</strong></em>) importiert
+ werden kann. Diese Datei basiert auf dem offenen
+ <a href="https://de.wikipedia.org/wiki/Outline_Processor_Markup_Language", target="_blank">
+ OPML
+ </a> Format und wird von nahezu allen RSS/Feed-Readern
+ verstanden. Damit gewährleistet Kontra, dass es keinen
+ sogenannten <em>Lock-In</em> Effekt gibt, der Nutzer:innen
+ an eine einzige App binden und der Wechsel zu Alternativen
+ erschwert.
+ </p>
+ <p>
+ Die angesprochenen OPML-Dateien enthalten nicht nur die
+ RSS-Feeds selbst, sondern auch alle Kategorien, die man
+ ihnen innerhalb des eigenen Feed-Readers zugewiesen hat. Die
+ OPML-Dateien aus Kontra enthalten alle Kategorie-Label, die
+ auch in der Liste sichtbar sind.
+ </p>
+ <p>
+ <strong>Kurzum:</strong> RSS und OPML sind die grundlegende
+ Technik, auf die <em>Kontra</em> setzt. Nachrichten können
+ darüber direkt von Blogs und Zeitungen bezogen werden, ohne
+ dass Dritte Einsicht darin haben. Feeds können in nahezu
+ allen Feedreadern importiert und exportiert werden. Ein
+ Wechsel von einer App zu einer anderen ist also innerhalb
+ von Sekunden möglich.
+ </p>
+ </details>
+
+</section>
+
+<?php
+}
+?>
diff --git a/lib/gen_html_feeds.php b/lib/gen_html_feeds.php
@@ -0,0 +1,174 @@
+<?php
+function gen_html_feeds($config) {
+?>
+
+<form id="sources-selection" method="post" target="_blank">
+
+ <!-- Submit button -->
+ <div class="submit-container">
+ <button
+ type="submit"
+ name="action"
+ value="gen_opml"
+ title="Erzeugt die OPML-Datei, die in den RSS-Reader importiert werden kann"
+ >
+ Feed erzeugen
+ </button>
+ <button
+ type="submit"
+ name="action"
+ value="preview"
+ title="Leitet auf eine Vorschau der ausgewählten Feeds weiter"
+ >
+ Feed-Vorschau
+ </button>
+ <a href="#sources" class="button" title="Nach oben">
+ 👆 <stretch class="nomobile">Nach oben</stretch>
+ </a>
+ <a href="#faqs" class="button" title="Nach unten">
+ 👇 <stretch class="nomobile">Nach unten</stretch>
+ </a>
+ </div>
+ <?php
+ $cnt = 0;
+ foreach ($config["sources"] as $id => $source) {
+ $cnt++; // increase counter for POST field ID
+
+ /* Gather publishing medium info */
+ $publisher = $config["publisher"][
+ array_pop($source["publisher"])
+ ];
+ ?>
+ <article>
+ <!-- Entry-Head -->
+ <h3>
+ <a
+ href="<?php echo $source["web"]; ?>"
+ target="_blank"
+ rel="nofollow noindex ugc"
+ >
+ <?php
+ echo $publisher["name"] . ": " . $source["title"];
+ ?>
+ </a>
+ </h3>
+
+ <!-- Description -->
+ <p>
+ <?php
+ echo $publisher["desc"] . " " . $source["desc"];
+ ?>
+ </p>
+
+ <!-- Choose this Button -->
+ <input
+ type="checkbox"
+ name="<?php echo "source-" . $cnt; ?>"
+ value="<?php echo $id; ?>"
+ >
+ <label for="<?php echo $id; ?>">
+ Diese Nachrichtenquelle auswählen
+ </label>
+
+ <!-- Entry-Categories -->
+ <table style="width:100%;">
+
+ <tr>
+ <th>Quelle:</th>
+ <td>
+ <mark title="<?php echo $publisher["desc"];?>">
+ <?php echo "#" . $publisher["button"]; ?>
+ </mark>
+ </td>
+ </tr>
+
+ <tr>
+ <th>Region:</th>
+ <td>
+ <?php
+ foreach ($source["regions"] as $region) {
+ $catentry = $config["regions"][$region]
+ ?>
+ <mark title="<?php echo $catentry["description"];?>">
+ <?php echo "#" . $catentry["name"]; ?>
+ </mark>
+ <?php
+ }
+ ?>
+ </td>
+ </tr>
+
+ <tr>
+ <th>Sprachen:</th>
+ <td>
+ <?php
+ foreach ($source["languages"] as $language) {
+ $catentry = $config["languages"][$language]
+ ?>
+ <mark title="<?php echo $catentry["description"];?>">
+ <?php echo "#" . $catentry["name"]; ?>
+ </mark>
+ <?php
+ }
+ ?>
+ </td>
+ </tr>
+
+ <tr>
+ <th>Zugang:</th>
+ <td>
+ <?php
+ foreach ($source["access"] as $access) {
+ $catentry = $config["access"][$access]
+ ?>
+ <mark title="<?php echo $catentry["description"];?>">
+ <?php echo "#" . $catentry["name"]; ?>
+ </mark>
+ <?php
+ }
+ ?>
+ </td>
+ </tr>
+
+ <tr>
+ <th>Medium:</th>
+ <td>
+ <?php
+ foreach ($source["medium"] as $medium) {
+ $catentry = $config["medium"][$medium]
+ ?>
+ <mark title="<?php echo $catentry["description"];?>">
+ <?php echo "#" . $catentry["name"]; ?>
+ </mark>
+ <?php
+ }
+ ?>
+ </td>
+ </tr>
+
+ <tr>
+ <th>Themen:</th>
+ <td>
+ <?php
+ foreach ($source["topics"] as $topic) {
+ $catentry = $config["topics"][$topic]
+ ?>
+ <mark title="<?php echo $catentry["description"];?>">
+ <?php echo "#" . $catentry["name"]; ?>
+ </mark>
+ <?php
+ }
+ ?>
+ </td>
+ <tr>
+ </table>
+
+ </article>
+ <?php
+ }
+ ?>
+</form>
+
+<?php
+}
+?>
diff --git a/lib/gen_html_footer.php b/lib/gen_html_footer.php
@@ -0,0 +1,23 @@
+<?php
+function gen_html_footer($config){
+?>
+
+<footer>
+ <h4>Disclaimer</h4>
+ <p>
+ Die Schlagzeilen, Inhalte oder Einstellungen der Redakteur:innen
+ und Autor:innen der hier aufgeführten Nachrichtenagenturen,
+ Blogs und Zeitungen spiegeln nicht unbedingt die Meinungen und
+ Einstellungen der Entwickler:innen und Betreiber:innen von
+ <em>Kontra</em> wider. <em>Kontra</em> ist ein Quellenarchiv für
+ Nachrichtenaggregatoren, der Inhalte aus vielen verschiedenen
+ Quellen zusammenführt werden. <em>Kontra</em> hat
+ selbstverständlich keinen direkten Einfluss auf den
+ redaktionellen Inhalt.
+ </p>
+ <em>Version:</em> <code><?php echo $config["version"]; ?></code>
+</footer>
+
+<?php
+}
+?>
diff --git a/lib/gen_html_head.php b/lib/gen_html_head.php
@@ -0,0 +1,18 @@
+<?php
+function gen_html_head() {
+?>
+
+<head>
+ <meta charset=utf-8>
+ <meta name=viewport content="width=device-width,initial-scale=1">
+ <link rel=icon href=assets/img/favicon.png type=image/png>
+ <link rel=icon href=assets/img/favicon.ico type=x-image/ico>
+ <link rel=stylesheet href=assets/css/simple.min.css media=all>
+ <link rel=stylesheet href=assets/css/custom.css>
+ <script async src=assets/js/filter_engines.js></script>
+ <title>Kontra - Das progressive Nachrichtenarchiv</title>
+</head>
+
+<?php
+}
+?>
diff --git a/lib/gen_html_navigation.php b/lib/gen_html_navigation.php
@@ -0,0 +1,23 @@
+<?php
+function gen_html_navigation() {
+?>
+
+<header>
+ <nav>
+ <a href="/#sources">
+ Nachrichten
+ </a>
+ <a href="/#faqs">
+ Was ist das?
+ </a>
+ <a href="https://src.jayvii.de/pub/kontra/" target="_blank">
+ Hilf mit!
+ </a>
+ </nav>
+ <h1>Kontra</h1>
+ <p>Das progressive Nachrichtenarchiv</p>
+</header>
+
+<?php
+}
+?>
diff --git a/lib/gen_html_preview.php b/lib/gen_html_preview.php
@@ -0,0 +1,92 @@
+<?php
+function gen_preview($config) {
+
+ /* Gather news sources from selection */
+ $input_keys = preg_grep(
+ "/^source-[0-9]+$/",
+ array_keys($_POST)
+ );
+ $sources = array();
+ foreach ($input_keys as $key) {
+ array_push(
+ $sources,
+ $config["sources"][$_POST[$key]]
+ );
+ }
+
+
+ $feed = array();
+ foreach ($sources as $source) {
+ $tmp = parse_rss(
+ $source["rss"],
+ $source["topics"],
+ $config["publisher"][$source["publisher"][0]]["name"] . ": " .
+ $source["title"]
+ );
+ foreach ($tmp as $item) {
+ array_push($feed, $item);
+ }
+ }
+
+ uasort($feed, "sort_by_date_rev");
+
+
+?>
+
+<!doctype html>
+<html>
+
+ <!-- Head -->
+ <?php gen_html_head(); ?>
+
+ <!-- Body -->
+ <body>
+
+ <!-- Header / Navigation -->
+ <?php gen_html_navigation(); ?>
+
+ <!-- Feed Preview -->
+<?php
+ foreach ($feed as $item) {
+?>
+ <section>
+ <!-- Headline -->
+ <h3>
+ <a
+ href="<?php echo $item["link"]; ?>"
+ target="_blank"
+ rel="nofollow noindex ugc"
+ >
+ <?php echo $item["title"]; ?>
+ </a>
+ </h3>
+ <!-- Information -->
+ <em><?php echo $item["publ"]; ?></em>
+ <br>
+ <em><?php echo $item["date"]; ?></em>
+ <!-- Content -->
+ <p><?php echo $item["desc"]; ?></p>
+ <!-- Categories -->
+ <?php
+ foreach ($item["cats"] as $cat) {
+ ?>
+ <mark><?php echo $config["topics"][$cat]["name"]; ?></mark>
+ <?php
+ }
+ ?>
+ </section>
+
+<?php
+ }
+?>
+
+ <!-- Footer -->
+ <?php gen_html_footer(); ?>
+
+ </body>
+
+</html>
+
+<?php
+}
+?>
diff --git a/lib/gen_html_usage.php b/lib/gen_html_usage.php
@@ -0,0 +1,88 @@
+<?php
+function gen_html_usage($config) {
+?>
+
+<div class="fullheight screenshots" id="usage">
+ <h3>Was ist Kontra?</h3>
+ <figure class="buttonrow">
+ <img style="flex:26%;min-width:91px;margin:2.5px;" src="assets/img/applications/gfeeds_mobile.jpg">
+ <img style="flex:72%;min-width:252px;margin:2.5px;" src="assets/img/applications/gfeeds_desktop.jpg">
+ <figcaption style="width:100%;">
+ Nachrichten Feeds aus Kontra in <a href="https://gfeeds.gabmus.org/" target="_blank">Gnome Feeds</a>
+ </figcaption>
+ </figure>
+ <p>
+ Kontra versetzt Nutzer:innen in die Lage, selbstbestimmt
+ personalisierte Nachrichten-Feeds von seriösen <em>progressiven</em>
+ Quellen zu erstellen, um immer auf dem Laufenden zu bleiben.
+ Und das selbstverständlich
+ <strong>ohne <a href="https://de.wikipedia.org/wiki/Web_Analytics" target="_blank">Tracking</a></strong>,
+ <strong>ohne Datensammelwut</strong>,
+ <strong>ohne Konto-Zwang</strong>
+ <strong>ohne <a href="https://de.wikipedia.org/wiki/Soziales_Netzwerk_(Internet)#Kritik" target="_blank">Algorithmen</a></strong> und
+ <strong>ohne <a href="https://de.wikipedia.org/wiki/Lock-in-Effekt" target="_blank">Lock-In Effekte</a></strong>.
+ Wie das funktioniert, erfährst du <a href="#faqs">hier</a>!
+ </p>
+ <p>
+ Die in Kontra hinterlegten Medien behandeln ein breites Spektrum
+ an Themen und mit unterschiedlichen Fokuspunkten. Sie vereint
+ eine <em>progressive</em> und politisch <em>linke</em>
+ Sichtweise. Die Idee hinter Kontra ist, die Nutzung von Medien
+ zu vereinfachen und Menschen in die Lage zu versetzen, selbst
+ kuratierte Nachrichtenquellen und Themenbereiche zu verfolgen.
+ </p>
+ <p>
+ Kontra ist ein Archiv mit aktuell
+ <strong><?php echo count($config["sources"]); ?></strong>
+ Nachrichten-Feeds aus
+ <strong><?php echo count($config["publisher"]); ?></strong>
+ unterschiedlichen Quellen, zu
+ <strong><?php echo count($config["topics"]); ?></strong>
+ Themenbereichen, innerhalb von
+ <strong><?php echo count($config["regions"]); ?></strong>
+ Regionen, in
+ <strong><?php echo count($config["languages"]); ?></strong>
+ verschiedenen Sprachen. Nutzer:innen können sich aus diesem
+ Katalog eigene Nachrichten-Feeds gänzlich nach ihren Interessen
+ zusammenstellen. Die hier herunterladbaren
+ <a href="https://de.wikipedia.org/wiki/Outline_Processor_Markup_Language" target="_blank">
+ Nachrichten-Feed Dateien</a>
+ können in beliebigen
+ <a href="https://de.wikipedia.org/wiki/Feedreader" target="_blank">
+ Feed-Readern</a>
+ eingeladen und sofort genutzt werden!
+ Zum Beispiel in diesen
+ <a href="https://fsfe.org/freesoftware/freesoftware.de.html" target="_blank">
+ Freien</a>
+ und kostenlosen Apps für Android und iOS:
+ <ul>
+ <li><a href="https://apps.apple.com/us/app/netnewswire-rss-reader/id1480640210" target="_blank">NetNewsWire (iOS)</a></li>
+ <li><a href="https://apps.apple.com/us/app/twine-rss-reader/id6465694958" target="_blank">Twine (iOS)</a></li>
+ <li><a href="https://play.google.com/store/apps/details?id=com.nononsenseapps.feeder.play" target="_blank">Feeder (Android)</a></li>
+ <li><a href="https://play.google.com/store/apps/details?id=dev.sasikanth.rss.reader" target="_blank">Twine (Android)</a></li>
+ <li><a href="https://freshrss.org/" target="_blank">FreshRSS (Web)</a></li>
+ <li><a href="https://www.thunderbird.net/de/" target="_blank">Thunderbird (Windows, MacOS, Linux)</a></li>
+ <li><a href="https://gfeeds.gabmus.org/" target="_blank">Feeds (Linux)</a></li>
+ <li><a href="https://apps.gnome.org/de/NewsFlash/" target="_blank">NewsFlash (Linux)</a></li>
+ <li><a href="https://apps.kde.org/de/alligator/" target="_blank">Alligator (Linux)</a></li>
+ <li><a href="https://alternativeto.net/browse/search/?q=rss%20reader" target="_blank">und viele weitere</a>...</li>
+ </ul>
+ </p>
+ <p>
+ Ganz einfach in nur <strong>zwei Minuten</strong> loslegen!
+ Nachrichtenquellen aussuchen, Feed-Datei herunterladen, in
+ den Reader importieren und sofort informiert werden.
+ </p>
+ <div class="buttonrow">
+ <a href="#faqs" class="button c2">
+ Mehr erfahren
+ </a>
+ <a href="#sources" class="button c2">
+ Zu den Nachrichten!
+ </a>
+ </div>
+</div>
+
+<?php
+}
+?>
diff --git a/lib/gen_opml.php b/lib/gen_opml.php
@@ -0,0 +1,83 @@
+<?php
+
+function gen_opml($config) {
+
+ /* Gather news sources from selection */
+ $input_keys = preg_grep(
+ "/^source-[0-9]+$/",
+ array_keys($_POST)
+ );
+ $sources = array();
+ foreach ($input_keys as $key) {
+ array_push(
+ $sources,
+ $config["sources"][$_POST[$key]]
+ );
+ }
+
+ $exp_hash = md5(serialize($sources));
+ $file_name = "kontra_" . date("Y-m-d") . "_" . $exp_hash . ".opml";
+
+ /* Set Download and content type headers */
+ header('Content-Type: application/xml; charset=UTF-8');
+ header('Content-Disposition: Attachment;filename="' . $file_name . '"');
+
+ /* Build OPML file */
+?>
+
+<opml version="2.0">
+<head>
+ <title>
+ Nachrichten-Export von Kontra -
+ <?php echo "https://" . $_SERVER["SERVER_NAME"] . PHP_EOL; ?>
+ </title>
+</head>
+<body>
+
+<?php
+
+ /* Cycle through each source and write source entry */
+ $indexes = array(
+ "regions", "languages", "access", "medium", "topics"
+ );
+ foreach ($sources as $source) {
+
+ /* Construct title */
+ $title = $config["publisher"][$source["publisher"][0]]["name"] .
+ ": " . $source["title"];
+
+ /* Create category list */
+ $categories = array();
+ foreach ($indexes as $index) {
+ foreach ($source[$index] as $category) {
+ array_push(
+ $categories,
+ $config[$index][$category]["name"]
+ );
+ }
+ }
+
+?>
+
+<outline
+ title="<?php echo $title; ?>"
+ text="<?php echo $title; ?>"
+ category="<?php echo implode(",", $categories); ?>"
+ xmlUrl="<?php echo $source["rss"]; ?>"
+ htmlUrl="<?php echo $source["web"]; ?>"
+/>
+
+<?php
+
+ } // foreach-source
+
+?>
+
+</body>
+</opml>
+
+<?php
+
+} // function
+
+?>
diff --git a/lib/parse_rss.php b/lib/parse_rss.php
@@ -0,0 +1,62 @@
+<!--
+SPDX-License-Identifier: AGPL-3.0-or-later
+SPDX-FileCopyrightText: 2025 JayVii <jayvii+kontra[AT]posteo[DOT]de>
+-->
+<?php
+
+function parse_rss($url, $categories, $name) {
+
+ /* gather XML from URL */
+ $xml = simplexml_load_file($url);
+
+ /* parse every item from XML */
+ $out = array();
+ for ($i = 0; $i < count($xml->channel->item); $i++) {
+
+ /* fetch required objects */
+ $title = (string) $xml->channel->item[$i]->title;
+ $link = (string) $xml->channel->item[$i]->link;
+ $description = (string) $xml->channel->item[$i]->description;
+ $pubDate = (string) $xml->channel->item[$i]->pubDate;
+ $timestamp = (string) strtotime($pubDate);
+
+ /* insert objects into array*/
+ array_push(
+ $out,
+ array(
+ "publ" => $name,
+ "cats" => $categories,
+ "title" => $title,
+ "link" => $link,
+ "desc" => $description,
+ "date" => $pubDate
+ )
+ );
+
+ }
+
+ /* return final array */
+ return($out);
+
+}
+
+/* Sort by date */
+function sort_by_date($a, $b) {
+ $at = strtotime($a["date"]);
+ $bt = strtotime($b["date"]);
+ if ($at > $bt) {
+ return(+1);
+ }
+ if ($at < $bt) {
+ return(-1);
+ }
+ if ($at == $bt) {
+ return(0);
+ }
+}
+function sort_by_date_rev($a, $b) {
+ return(sort_by_date($a, $b) * (-1));
+}
+
+?>
+
diff --git a/news-sources.json b/news-sources.json
@@ -1,5 +1,5 @@
{
- "version": "1.2.9",
+ "version": "1.3.0",
"sources": {
"drr": {
"title": "Alle Artikel",
@@ -4503,4 +4503,4 @@
"description": "Wissenschaft und Forschung"
}
}
-}
-\ No newline at end of file
+}