Commit Graph

37 Commits

Author SHA1 Message Date
adc1fab3f8 feat(magazine): driving mode as top bar, flexible content and pinned controls dock with picture, lyrics and compact views
Controls can no longer fall off screen (320x568 up to tablets and landscape), share no longer overlaps the title.
Picture view with zoom/pan, Spotify-style whole-text lyrics with follow/back-to-current, minimize to current line,
persisted view choice, 44px segmented control.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 16:54:21 +02:00
f88fefcee4 feat(magazine): driving mode shows three sentence lines and syncs per frame
Previous/current/next sentence in a fixed-height box with a fade, tap to jump. The
highlight is a binary search over sentence starts on audio.currentTime every animation
frame, with forced resync on seeking, seeked, ratechange, play, pause and visibility; the
marked word uses the sentence's own span. Playwright covers seeks, 1.5x/2x, rapid seeks.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 14:57:39 +02:00
f5b5993e4d feat(magazine): share an article or magazine as a deep link into driving mode
Share buttons (toolbar, playlist, driving mode) build #s-magazine?doc=..&article=..&mode=drive; opening it routes to the article and starts driving mode with a Tap-to-play prompt if autoplay is blocked. Ids are validated strictly; access is unchanged.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 12:18:05 +02:00
9ad881ada8 feat(magazine): manage OPDS catalogues in the app, env-based login, result paging
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-30 11:03:03 +02:00
268ed391a3 feat(magazine): EPUB 3 Media Overlay export with measured sentence timings; tolerate missing mutagen
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-30 10:33:08 +02:00
0005ae0ebd feat(magazine): import a magazine from PNG/JPEG page images
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-30 10:19:14 +02:00
c3c5c55f17 feat(magazine): find and import issues from the Internet Archive and OPDS catalogues
Also reuses the existing magFmtClock for the contents list (the duplicate
tripped the frontend collision gate).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-29 17:35:08 +02:00
a23e4be2a1 feat(magazine): Contents button in the sticky review bar
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-28 18:00:10 +02:00
d0fba6a16f feat(magazine): text flow indicator (arrows, chips, reading-view seams); Auto-fix all pages with backup
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-28 10:46:55 +02:00
b85f40e263 feat(magazine): live per-page issue markers and panel, one-click page auto-fix, run fixes boxes too
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-28 10:41:39 +02:00
91caa6cf90 feat(magazine): fuse paragraphs across columns/pages, article-aware acronyms, German/English spellcheck
- fuse_paragraph_blocks joins a paragraph split by a column or page break into one
  narration block (reader, podcast source and MP3), keeping source regions for highlighting
- language decided once per article; per-article acronym glossary (LLM classifies unknown
  acronyms from context), letter-spelled acronym lists, extended DE/EN database
- core/spelling: dictionary findings (compounds, inflections, line-break hyphens, other-language
  words), marked in review and listed per page/article; guarded LLM agent fixes; quality run
  now includes the spelling pass
- keep suspended compound hyphens (Programmier- und) when merging regions / building layouts

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-28 08:09:30 +02:00
48c546fbc8 fix(magazine): region-type picker and page-quality buttons work; stronger quality audit
Some checks are pending
Test and SonarQube / quality (push) Waiting to run
- Export the region-type picker handlers and magRunPageQuality to the page (they threw
  "not defined", so the picker never opened and Find missed text / Verify OCR did nothing)
- Add a unit test that fails when an inline mag* handler is not exported
- Quality audit: pixel-level clipping check on all four box edges, duplicate-article
  detection, detected full-page advertisements skipped and shown green (no manual button)
- Driving mode text is karaoke-style (whole article, current sentence and word highlighted)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-26 23:07:19 +02:00
9904459913 feat(magazine): whole-magazine quality check, page stages, ad pages, driving-mode player
Some checks are pending
Test and SonarQube / quality (push) Waiting to run
- Quality run: per-page missed-text recovery, guarded OCR re-read and a pixel audit
  (uncovered ink, overlapping boxes, clipped box edges); report saved as quality_report.json
- Thumbnail grid: quality-stage colours, flag badge, live per-page indicator for every
  batch step (OCR, detection, figure fixing, quality run, audio)
- Pages can be approved as advertisements (not narrated, skipped by quality run)
- Driving mode: +/-15 s, seek bar, playback speed, text and image toggles
- Plus the previously uncommitted 1.53.5 magazine/OCR work in the same tree

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-26 19:29:43 +02:00
b1c0197652 Release v1.53.2
Some checks are pending
Test and SonarQube / quality (push) Waiting to run
2026-09-24 07:44:16 +02:00
ab5fce10bf Release v1.52.1
Some checks are pending
Test and SonarQube / quality (push) Waiting to run
2026-09-22 23:53:34 +02:00
2ba4daa742 Release v1.52.0
Some checks are pending
Test and SonarQube / quality (push) Waiting to run
2026-09-22 23:33:44 +02:00
ab10516383 Release v1.49.0
Some checks are pending
Test and SonarQube / quality (push) Waiting to run
2026-09-22 23:14:27 +02:00
633aede41c Release v1.48.0
Some checks are pending
Test and SonarQube / quality (push) Waiting to run
2026-09-22 23:00:00 +02:00
0fa042f494 Release v1.47.1
Some checks are pending
Test and SonarQube / quality (push) Waiting to run
2026-09-22 22:56:06 +02:00
bc3f82d975 Release v1.46.0
Some checks are pending
Test and SonarQube / quality (push) Waiting to run
2026-09-22 21:16:42 +02:00
94331320c0 feat(magazine): one-click draw tool, table regions, batch approve, MP3 export, remove-all-boxes
Some checks are pending
Test and SonarQube / quality (push) Waiting to run
Bundles this session's magazine review work: a single "Draw region" tool
replacing six preset-kind buttons; "Table" as a real, non-narrated region
type; uniform auto-OCR for every text-like drawn/re-read region with a
Tesseract fallback when the vision OCR backend is unreachable; a thumbnail
grid view and inline title editing for the article list; batch
approve/reject; standalone MP3 export with embedded title/author/album,
lyrics and cover art (adds mutagen); "Remove all boxes" for starting a
tangled page from scratch; Approve advancing straight to the next article;
a merged, sticky review toolbar; and a fix for stale image previews after
resizing a region's box.

Also fixes several character-portrait rendering biases confirmed live
across this session's DSA audiobook cast (routes/conversation.py): modern
or bald/receding hair regardless of established coverage, armored women
rendering masculinized, duplicated/malformed weapons, a ranged weapon
rendering as a firearm due to a German compound-word regex miss, an
established dwarf rendered with human proportions, and occasional extra
hands or lost non-human species in scene panels.

See CHANGELOG.md [1.43.0] for the full list.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-22 20:14:11 +02:00
1edc941dbf feat(magazine): live region boxes in the import preview; interrupted imports no longer spin for ever
Some checks are pending
Test and SonarQube / quality (push) Waiting to run
The preview carries each page's regions (percent of the page, type, reading
order) for the reading pass and the labelling pass, drawn over the page image
with a legend. A server restart that killed the import left it "running" for
ever; the status route now reports it as failed. v1.42.0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 01:09:12 +02:00
e3d6cb2cca feat(magazine): fix Edit boxes, add spread view, searchable narrator picker and Prepare audio
- fix: Edit boxes and page-nav controls were dead clicks (handlers never exported
  to root); resize from any edge/corner instead of only bottom-right
- feat: two-page spread in review (page images above, OCR lists beneath)
- feat: searchable voice picker for narrator and podcast hosts
- feat: Prepare audio synthesises the whole article ahead of playback; playback
  also stays three sentences ahead
- fix: sync index.html cache-busting version with VERSION (was stuck at 1.26.12)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-18 23:10:16 +02:00
c81ae28da2 feat(magazine): add figure/chart/table description generation and spoken narration
Some checks are pending
Test and SonarQube / quality (push) Waiting to run
Adds a "Describe" action per figure in article review: sends the cropped
image to the configured vision engine (with fallback) for a type-aware
one- or two-sentence description -- a chart gets a prompt about what it
measures and its trend, a table about headings and what stands out, etc.
Editable before approval. A new "Read figure descriptions" toggle in the
reading controls speaks these where they occur; purely additive, off by
default, and a figure with no description behaves exactly as before.

New core/magazine.py describe_visual_region()/_chain() reuse the same
reliability guards as page OCR (repetition-loop detection, sentence-
boundary truncation). New routes: POST .../images/{id}/describe
(background job), PATCH .../images/{id} (manual edit), descriptions=1 on
the article-text endpoint.

Live-verified end to end against the ingested c't KI Wissen 2026
magazine. Also found and documented a real, config-dependent limitation:
the currently-configured primary vision engine is transcription-only and
returns empty content for any descriptive prompt (confirmed with three
different prompts) -- not a code defect, but description generation
needs a genuinely caption-capable engine reachable as the fallback.

251 tests passing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-14 17:39:57 +02:00
96b0b9dd71 fix(magazine): finish and harden the live ingest preview
Some checks are pending
Test and SonarQube / quality (push) Waiting to run
Resumes an in-progress, uncommitted change from a previous session: the
live "page image + recognised text" preview shown during ingestion was
reworked to render formatted HTML (styled headings, a figure
placeholder) instead of a plain-text dump, but was left with a
duplication bug, dead code, inline styles, and no tests.

- Fixed duplication: a figure block's own transcribed text (usually its
  on-screen UI copy) was rendered as an ordinary paragraph in addition
  to the new figure placeholder box. Figure/chart/table/code blocks are
  now represented only by the placeholder.
- Furniture/sidebar/pullquote/ad text is shown muted instead of being
  dropped with no replacement, and is never promoted to a heading
  regardless of font size.
- Factored the formatting logic out of the progress closure into a
  standalone, unit-tested _render_ingest_preview_html().
- Replaced dead getattr(bbox, "y0", ...) calls (bbox is always a plain
  [x, y, w, h] list) with direct indexing, moved statistics/logging
  imports to module level, switched manual character replacement to
  html.escape(), and bounded the preview by an accumulated line budget
  instead of a blind slice that could truncate mid-tag.
- Replaced inline style="..." with CSS classes matching the panel's
  existing dark console treatment.
- The frontend now always uses innerHTML (every text node is escaped
  server-side), dropping the startsWith('<') content-type sniffing.
- Marked the preview panel aria-hidden -- decorative, and would
  otherwise churn noisily for screen reader users on top of the
  adjacent progress bar.

Verified against the real c't KI Wissen 2026 layout: a figure's raw
OCR text no longer appears twice, a real headline renders as <h3>, a
footer/pull-quote render muted, and all text is correctly escaped.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-12 15:24:16 +02:00
a4b7c18a2f Fix magazine dropzone upload button and finalize side-by-side layout 2026-09-10 17:44:37 +02:00
c1a2d6dc74 Release v1.26.14: Studio-style side-by-side Magazine upload layout with Durchsuchen button
Some checks failed
Test and SonarQube / quality (push) Has been cancelled
2026-09-10 14:45:00 +02:00
29dc913ed1 Release v1.26.10
Some checks are pending
Test and SonarQube / quality (push) Waiting to run
2026-09-10 12:50:33 +02:00
e6211f1333 Release v1.26.9
Some checks are pending
Test and SonarQube / quality (push) Waiting to run
2026-09-10 12:45:42 +02:00
c1d86ec13d fix: return All magazines to library
Some checks are pending
Test and SonarQube / quality (push) Waiting to run
2026-09-09 17:14:27 +02:00
272d4872bd fix: use native Unlimited-OCR layout regions
Some checks are pending
Test and SonarQube / quality (push) Waiting to run
2026-09-09 13:27:14 +02:00
85080f4b82 feat: add live ingest preview, region icons/ownership badges, manual region drawing to magazine review
Some checks are pending
Test and SonarQube / quality (push) Waiting to run
Ingestion now streams each page's image and recognised text into a
console-styled preview panel (Baidu Unlimited-OCR demo style) as pages
finish, instead of a bare progress bar -- raw text is written to a
per-job ingest_preview.json file since the background-job result field
strips text-like keys for data minimization.

Split-screen review boxes and their matching list rows now show a
centred icon for the region's kind and, when a region on a shared page
belongs to a different article, a badge naming that article, so a
claimed region is never mistaken for unclaimed text.

Added a "Draw it" mode: click-drag a box directly on the page image to
add a region the layout engine missed, as typed/OCRed text or as a new
figure (add_manual_region, POST /api/magazine/{doc_id}/pages/{page}/regions).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-07 18:52:21 +02:00
5adba6b4c0 feat: split-screen article review with numbered regions, per-page/whole-magazine "OCR again", and a real column-interleaving fix it found
Some checks are pending
Test and SonarQube / quality (push) Waiting to run
Split-screen review: the rendered page (left) with a numbered box per
detected block, the extracted text (right) with matching numbers.
Clicking either side highlights the other. Checkboxes moved from a flat
list into this layout without changing their semantics (still gate
what gets narrated).

"OCR again": reocr_page() forces one page through the configured
vision engine again, replacing only that page's blocks -- deliberately
does NOT call build_articles(), so an already-approved article is not
silently re-grouped. A magazine-level option re-reads every page and
re-runs detection (with a confirmation, since that does reset article
status). extract_pages() gained force_vision_ocr to skip its quality
gate for this case.

Building the numbered-box review immediately did what it was built to
do -- surfaced a real bug on live production data (real magazine, real
scan, not a synthetic fixture): a photo caption at 49.9% of the page
width sat in the gutter between two genuinely separate columns and
merged them into one, so every block on the page came back column=0
and reading order fell back to pure top-to-bottom, interleaving the
two columns' sentences. Fixed two compounding causes: column boundary
detection now excludes blocks much wider than the page's median width,
and detect_columns' gutter threshold (3.5%) was itself narrower than
some real magazine gutters (~2.1% measured) -- lowered to 1.5%.

10 new/updated tests, including one built directly from the real
measured page-17 block coordinates that exposed the bug.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-07 14:00:34 +02:00
e81fa64448 fix: magazine state persistence, misfiled in book library, confidence badge layout, docker-socket-proxy crash loop
Magazine "forgets" the open document (real bug, confirmed live):
- A full page reload or the browser's own Back button tears down all
  in-memory JS state; magInit() always defaulted to the empty library
  view with no way back to what was open. Persists the last-opened
  magazine id in localStorage and auto-reopens it on load, falling back
  to the library only if that document no longer exists.
- The actual root cause of the reported duplicate: readerRenderLibrary()
  (Studio/Reader "Source") and libraryRenderBooks() (Library > Books)
  both listed EVERY document from the shared reader_library store with
  no kind filter, so a magazine (kind: "magazine") was already showing
  up there disguised as a plain book. The magazine never actually
  vanished -- it was misfiled in a different list, which is what led to
  the user re-uploading it and getting a real duplicate under a
  different kind. Both listings now exclude kind: "magazine".

Confidence badge layout (Studio Characters review):
- The badge (radiobox is already positioned after the speaker name in
  DOM order) rendered on its own line far below the name because both
  .ab-cv-spk and .ab-cv-txt were `display: block`, forcing a line break
  regardless of markup order. Wrapped the name + badge + check button in
  a shared flex row (.ab-cv-spk-row) so the badge now sits directly
  beside the name/after "NARRATOR" as requested, without needing to
  touch the two existing incremental-patch code paths (they insert
  relative to the same elements, now just nested one level deeper).

docker-socket-proxy crash loop (found while restarting for the magazine
Python changes to take effect -- unrelated to this session's earlier
work, landed in an earlier commit during the interruption):
- read_only: true left the entrypoint with nowhere to write its own
  haproxy.cfg ("Read-only file system"), crash-looping the container and
  leaving the app without Docker access. Removed read_only for this one
  service -- cap_drop: ALL, no-new-privileges, and the :ro socket mount
  already provide the real hardening.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-07 09:39:20 +02:00
5b0c8e0bf5 feat: add drag-and-drop dropzone to the magazine upload form
Replaces the plain <input type="file"> with the same reader-dropzone
component the Book/Source screen already uses (reused CSS, no new
styles needed beyond grid/layout adjustments) -- drag a PDF onto the
zone or click "Choose file", both paths route through the same hidden
input magCreate() already reads via a DataTransfer handoff, so no other
logic needed to change. Shows the chosen/dropped filename in place of
the default hint text, and resets it after a successful add.

Verified live: click-to-choose and a simulated real 'drop' DragEvent
both populate the file input correctly, dragover highlighting toggles,
no console errors from the app itself.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-07 00:03:01 +02:00
813e06c914 feat: complete magazine P1 (images, play-all, karaoke, driving mode, sidebar exclusion) + OCR engines page + second OCR engine
Magazine P1:
- Images shown automatically during playback (assign_images_to_articles
  links each figure to the article whose column it falls in; the client
  shows the last image reached in reading order as playback advances).
- "Play all articles" queues every approved article and advances
  automatically at the end of each rather than stopping.
- Word-level highlighting, explicitly documented as an ESTIMATE (no
  forced-alignment/timestamp source exists): each word's share of the
  sentence's real measured audio duration is proportional to its
  character length. A checkbox turns it off; sentence highlighting
  (measured, not estimated) is unaffected.
- Driving mode: full-screen overlay, two oversized controls, reuses
  whatever is already playing/queued.
- Sidebars/pull-out boxes excluded from narration automatically
  (mark_sidebars: an anomalously narrow column vs. the page's regular
  grid). Fixed a real defect found while building this: a full-width
  headline was left in the column-width analysis and could bridge two
  genuinely separate columns into one, hiding a real sidebar column
  entirely -- caught by a failing test before the fix.

Second OCR engine + fallback ladder:
- KDL Frontier Parser nano wired in via vision_ocr_page_chain (ordered
  engine list, first usable result wins, tesseract last resort).
  Confirmed live: ~3x faster than Baidu (~12s vs ~40s/page) but returns
  plain text with NO coordinate markers, unlike Baidu's labeled regions.
  _whole_page_region treats the whole response as one ambiguous
  full-page block (gated by ocr_quality_score) rather than discarding
  usable text just because it lacks layout structure.

OCR engines page + a real UI bug:
- The OCR & Document Parsing page had no .s-engines-page[data-page="ocr"]
  markup at all -- renderLocalContainers already supported an OCR grid
  generically, but $('dc-grid-ocr') was always null, so the card grid
  silently never rendered. Added an Active OCR Engine panel mirroring
  Active Language Model exactly, plus the Local grid -- both configured
  engines now appear as ready-made cards, no "Add Custom" dialog needed.
- Fixed the audiobook pipeline's "Previous/Next" nav bar bleeding into
  every .section-head in the document (confirmed live on the Engines
  page: a "Cast Audiobook" button and "STEP 1/8" hint that made no sense
  there). Changed from a blocklist (naming each unrelated section as
  noticed) to an allowlist of the pipeline's three actual destinations.

Verified live end-to-end: play-all queue building and manual advance,
word-span markup, driving-mode toggle, OCR page showing both engines as
local cards, zero stray nav bars on the Engines page, no console errors.

20 new backend tests (156 total in the magazine module).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 23:39:34 +02:00
71a398b82f feat: add magazine reader frontend (P1)
Studio -> Magazines: library, contents tree grouped by section with
confidence/pages/listening-time/audio status, the Stage D review
screen (tick/untick layout blocks, correct title/author, approve or
reject), a reflowed article view with click-to-seek sentence
highlighting, a linked original-page view showing the source bounding
box, and a podcast panel (2-3 host pickers, script generation,
turn-by-turn playback).

Wired into the existing lazy-module system (module-manifest.json,
loader.js, nav.js) rather than a separate app. Reuses /api/tts-preview
for both narration and podcast turns -- no new audio pipeline.

Fixes found building this:
- The pane toggle used role="tab" without the full ARIA tabs pattern
  (aria-selected, roving tabindex, arrow-key nav) -- fails WCAG 2.2 AA
  and hid the buttons from role-based tooling. Replaced with a button
  group + aria-pressed, matching the plain-click interaction it
  actually has.
- Print layout cues ("(continued on page 8)") were being sent to TTS
  verbatim -- narration would have spoken the parenthetical aloud.
  Stripped from the narration copy only; layout.json keeps the
  original for the review screen.
- has_podcast now comes from the articles listing so opening an
  article without a generated script skips a doomed GET instead of a
  routine 404 on every open.

Verified against the real API contract with Playwright (library,
review pre-selection, approval, sentence highlighting + PDF-page
linking, podcast approval gate, zero console errors across the flow)
and manually end-to-end against a real ingested fixture, screenshots
included. Full suite: 94 Python tests, 33/34 desktop Playwright tests
(one unrelated pre-existing flaky DOM-count assertion).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 15:00:58 +02:00