pageta/apps/extension
Till JS fb057da372 fix(web): Umlaute im Bookmarklet-Weg nicht mehr verlieren
winfuture.de/news,161132.html per Bookmarklet gespeichert: ArticleSaved
trug 39 Ersatzzeichen im Text. Der Server-Fix vom 29.07. galt nur dem
Server-Abruf. Das Bookmarklet baut sein <form> im fremden Dokument, und
ein Formular ohne accept-charset kodiert im Zeichensatz dieses Dokuments
(winfuture: ISO-8859-1, `ö` als %F6) — request.formData() liest UTF-8.

- Bookmarklet setzt acceptCharset='UTF-8'.
- Hook liest den Body über $lib/form-body: Escapes selbst zu Bytes,
  striktes UTF-8, sonst Windows-1252. Repariert auch alte Lesezeichen,
  die nicht mitdeployt werden.
- collectPageta holte Folgeseiten per res.text() — dieselbe Falle, jetzt
  BOM > Header > <meta>. Kopie in der Erweiterung zeichengleich.

106 Tests grün (10 neu, Latin-1-Test per Mutation rot gesehen),
svelte-check 0 Fehler, Erweiterungs-Check grün.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HgK5h7sUgh9cdqyv85RBCq
2026-09-14 16:28:08 +02:00
..
icons feat: Extraktion — Zustände trennen, reparieren, und der Weg an harte Wände 2026-07-27 00:58:47 +02:00
scripts feat: mehrseitige Artikel vollständig sichern 2026-07-27 14:25:03 +02:00
background.js feat: mehrseitige Artikel vollständig sichern 2026-07-27 14:25:03 +02:00
manifest.json feat: Extraktion — Zustände trennen, reparieren, und der Weg an harte Wände 2026-07-27 00:58:47 +02:00
options.html feat: Extraktion — Zustände trennen, reparieren, und der Weg an harte Wände 2026-07-27 00:58:47 +02:00
options.js feat: Extraktion — Zustände trennen, reparieren, und der Weg an harte Wände 2026-07-27 00:58:47 +02:00
package.json feat: Extraktion — Zustände trennen, reparieren, und der Weg an harte Wände 2026-07-27 00:58:47 +02:00
page-collector.js fix(web): Umlaute im Bookmarklet-Weg nicht mehr verlieren 2026-09-14 16:28:08 +02:00
README.md docs(extension): Prüf-Anleitung und ehrlicher Teststand 2026-07-27 16:48:54 +02:00

Pageta — Browser-Erweiterung

Ein Klick speichert die geöffnete Seite in die Lese-Liste — mit dem Text, den du siehst.

Wozu, wenn es das Bookmarklet schon gibt

Das Bookmarklet kann dasselbe, aber es muss erst in die Lesezeichenleiste gezogen werden — für die meisten Menschen ist das die Stelle, an der sie aufhören. Die Erweiterung ist ein Symbol in der Leiste.

Beide lösen dasselbe Problem: Quellen wie golem.de antworten auf jede Anfrage ohne Cookies mit ihrer Zustimmungs-Abfrage statt mit dem Artikel — auch dann, wenn der Abrufer sich als normaler Browser ausgibt (gemessen 2026-07-27 aus dem Produktions-Container, siehe docs/EXTRAKTION.md). Serverseitig kommt da nichts vorbei. Der Artikel existiert nur in deinem Tab.

Wie sie arbeitet

Klick aufs Symbol
  → activeTab erlaubt EINMALIG, diesen einen Tab zu lesen
  → collectPageta() im Tab: Seite 1 + erkannte Folgeseiten, je geleichtert
  → { url, title, pages, missing }
  → POST <instanz>/lese-liste/add/receive        (dieselbe Route wie das Bookmarklet)
  → 303 auf /lese-liste/add?pickup=<einweg-token>   (2 Minuten gültig)
  → neuer Tab holt das Payload ab und speichert lokal-first über event-sync

Es gibt bewusst einen Eingang für Bookmarklet und Erweiterung. Zwei Transportwege für dieselbe Sache wären zwei Wege, die auseinanderdriften.

Mehrseitige Artikel

Ein Artikel auf drei Seiten liegt komplett hinter derselben Wand — Seite 2 holt der Server genauso wenig wie Seite 1. Also holt sie der Tab: ein fetch aus der Seite heraus trägt die Sitzung mit.

Folgeseiten findet page-collector.js ohne quellenspezifische Selektoren — ein Link zählt, wenn seine Adresse sich von der aktuellen nur in einem Seitenzähler unterscheidet (-2.html, ?page=2, /seite/2/); findet sich keine Seitenliste, folgt es der rel="next"-Kette. Gedeckelt bei 20 Seiten und 6 MB, mit kurzer Pause zwischen den Abrufen.

Diese Datei ist eine zeichengleiche Kopie von apps/web/src/lib/page-collector.js — dieselbe Logik treibt das Bookmarklet (dort als Quelltext in der javascript:-Adresse). Einen Bundler, der beide bedient, gibt es nicht; die Erweiterung soll bewusst ohne Build auskommen. scripts/check.mjs bricht ab, sobald die Kopien auseinanderlaufen.

Was sie nicht tut

  • Keine dauerhafte Leseerlaubnis. activeTab gilt für den Klick, nicht für den Verlauf. Ohne Klick sieht die Erweiterung keine Seite.
  • Kein API-Schlüssel. Es zählt die Anmeldung, die dein Browser ohnehin hat. Nichts Geheimes liegt in der Erweiterung.
  • Keine Telemetrie, keine Fremd-Server, kein Hintergrund-Verkehr. Sie spricht ausschließlich mit deiner Pageta-Instanz, und nur wenn du klickst.

Lokal ausprobieren

Chrome / Edge / Brave

  1. chrome://extensions → Entwicklermodus an
  2. „Entpackte Erweiterung laden" → diesen Ordner wählen
  3. Symbol anheften, Artikel öffnen, klicken

Firefox (ab 121)

  1. about:debugging#/runtime/this-firefox
  2. „Temporäres Add-on laden…" → manifest.json wählen

Eine andere Instanz (Selbst-Hosting) stellst du in den Erweiterungs- Einstellungen ein; die Erlaubnis für diese Adresse wird dort abgefragt.

Der erste Klick — was passieren soll

Nimm eine Seite mit Zustimmungs-Abfrage, an der der Server scheitert; ein Golem-Artikel ist der verlässlichste Fall.

  1. Artikel in einem Tab öffnen, Cookie-Abfrage wegklicken (das ist der Punkt — die Erweiterung nutzt genau diese Zustimmung).
  2. Auf das Pageta-Symbol klicken.
  3. Erwartung: Symbol zeigt kurz …, dann ✓; ein neuer Tab öffnet /lese-liste/add?pickup=… und speichert.
  4. In der Lese-Liste steht der Artikel mit echtem Titel und Volltext — nicht mit „Quelle blockiert".

Wenn das Symbol ! zeigt: Rechtsklick → „Verwaltung" → „Service Worker" öffnet die Konsole der Erweiterung; dort steht der Grund.

Läuft der Klick auf einer internen Seite (chrome://, Store-Seiten) oder auf Pageta selbst, zeigt das Symbol – und tut bewusst nichts.

Paketieren

pnpm --filter @pageta/extension package     # → dist/pageta-extension-<version>.zip

Das Zip ist das, was in den Chrome Web Store bzw. bei addons.mozilla.org hochgeladen wird.

Offene Punkte

  • Store-Einreichung ist nicht angestoßen. Chrome Web Store verlangt ein Entwicklerkonto (einmalig 5 USD) und eine Datenschutz-Begründung je Berechtigung; Firefox verlangt Signierung. Beides ist Vereinsarbeit, keine Programmierarbeit — bis dahin ist die Erweiterung über „entpackt laden" nutzbar.
  • Kein Kontextmenü-Eintrag („Link in Pageta speichern"). Braucht die contextMenus-Berechtigung; erst einbauen, wenn jemand danach fragt.
  • Der Klick-Weg im Browser ist ungetestet. Maschinell geprüft sind: Manifest, referenzierte Dateien, Berechtigungs-Rahmen, Syntax aller Skripte (scripts/check.mjs), die Sammel-Logik (12 Tests in apps/web/src/lib/page-collector.test.ts) und der Transport End-to-End gegen die Live-Instanz: POST → 303 → Einweg-Token → Abholung liefert das Payload → zweite Abholung 404. Was fehlt, ist genau die MV3-Verdrahtung dazwischen — action.onClicked → scripting.executeScript → fetch mit credentials cross-origin. Die braucht einen echten Browser-Load; eine Automatisierung darf chrome://extensions nicht bedienen. Anleitung oben, dauert eine Minute.