tts-voice-creator-clone-and.../static/sections/s-magazine.html
mARTin-B78 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

204 lines
12 KiB
HTML

<div class="section-head">
<span class="section-icon"><span class="mdi mdi-newspaper-variant-outline"></span></span>
<div class="section-title">
<h2>Magazines</h2>
<p>Listen to a magazine one article at a time &mdash; from its true beginning to its true end, without adverts, sidebars or a neighbouring piece spliced into the middle.</p>
</div>
</div>
<!-- ── Library ──────────────────────────────────────────────────────── -->
<div id="mag-view-library">
<div class="card mag-new">
<h3>Add a magazine or paper</h3>
<div class="reader-source-grid">
<div class="reader-paste-panel">
<div class="reader-source-method">
<span class="mdi mdi-file-document-edit-outline"></span>
<div><strong>Import &amp; Metadata</strong><span>Select a PDF file or configure optional title and issue details.</span></div>
</div>
<div class="mag-new-grid" style="margin-top: 4px; margin-bottom: 4px;">
<label for="mag-new-title">Title <span class="muted">(optional)</span>
<input id="mag-new-title" type="text" placeholder="Auto-filled from PDF filename if blank" autocomplete="off">
</label>
<label for="mag-new-issue">Issue <span class="muted">(optional)</span>
<input id="mag-new-issue" type="text" placeholder="e.g. September 2026" autocomplete="off">
</label>
</div>
<div class="reader-paste-actions" style="margin-top: auto; padding-top: 6px;">
<label class="btn-primary btn-sm reader-file-pick" id="mag-browse-btn" title="Choose a PDF file from your computer">
<span class="mdi mdi-folder-open-outline"></span> Durchsuchen
<input type="file" id="mag-new-file" accept="application/pdf" style="display:none">
</label>
</div>
</div>
<div class="reader-dropzone" id="mag-dropzone" style="cursor: pointer;">
<span class="mdi mdi-cloud-upload-outline reader-dropzone-icon" id="mag-dropzone-icon"></span>
<strong id="mag-dropzone-title">Drop a PDF document</strong>
<span class="note" id="mag-dropzone-note">Scanned issues work too &mdash; pages without selectable text are read with OCR.</span>
<div class="mag-dropzone-progress" id="mag-dropzone-progress" hidden>
<div class="mag-dropzone-progress-bar"></div>
</div>
<label class="btn-secondary btn-sm reader-file-pick" id="mag-dropzone-pick-btn" title="Choose a PDF file">
<span class="mdi mdi-file-upload-outline"></span> Import PDF
</label>
</div>
</div>
</div>
<h3>Your magazines</h3>
<div id="mag-library-list" class="mag-grid"></div>
</div>
<!-- ── Contents ─────────────────────────────────────────────────────── -->
<div id="mag-view-contents" hidden>
<div class="mag-bar">
<button type="button" class="btn-sm" onclick="magBackToLibrary()">
<span class="mdi mdi-arrow-left"></span> All magazines
</button>
<h3 id="mag-doc-title">Magazine</h3>
<div class="mag-bar-actions">
<button type="button" class="btn-sm primary" onclick="magPlayAll()">
<span class="mdi mdi-playlist-play"></span> Play all articles
</button>
<button type="button" class="btn-sm" onclick="magIngest()">
<span class="mdi mdi-refresh"></span> Re-run detection
</button>
<button type="button" class="btn-sm" onclick="magReocrMagazine()" title="Send every page through the configured OCR engine again, then re-detect articles">
<span class="mdi mdi-text-recognition"></span> OCR again (whole magazine)
</button>
</div>
</div>
<div id="mag-ingest-status" class="mag-status" hidden></div>
<!-- Decorative "watch it work" visualisation -- the essential
progress information (percentage, page count, done/failed) is
in #mag-ingest-status above, which is what a screen reader user
needs; this panel adds nothing beyond that but noisy churn. -->
<div id="mag-ingest-preview" class="mag-ingest-preview" hidden aria-hidden="true">
<div class="mag-ingest-preview-side">
<span class="mag-ingest-preview-label">Page</span>
<img id="mag-ingest-preview-img" alt="Page currently being read">
</div>
<div class="mag-ingest-preview-resize" id="mag-ingest-preview-resize" role="separator" aria-orientation="vertical" aria-label="Resize page and recognised text panes" title="Drag to resize page and recognised text panes"></div>
<div class="mag-ingest-preview-side">
<span class="mag-ingest-preview-label">Recognised text</span>
<div id="mag-ingest-preview-text" class="mag-ingest-preview-text"></div>
</div>
</div>
<div id="mag-contents"></div>
</div>
<!-- ── Review (Stage D) ─────────────────────────────────────────────── -->
<div id="mag-view-review" hidden>
<div class="mag-bar">
<button type="button" class="btn-sm" onclick="magBackToContents()">
<span class="mdi mdi-arrow-left"></span> Contents
</button>
<h3>Review article boundaries</h3>
</div>
<div id="mag-review"></div>
</div>
<!-- ── Reading ──────────────────────────────────────────────────────── -->
<div id="mag-view-read" hidden>
<div class="mag-bar">
<button type="button" class="btn-sm" onclick="magBackToContents()">
<span class="mdi mdi-arrow-left"></span> Contents
</button>
<div class="mag-read-id">
<h3 id="mag-read-title">Article</h3>
<span id="mag-read-by" class="muted"></span>
<span id="mag-read-pages" class="muted"></span>
</div>
<button type="button" class="btn-sm" onclick="magToggleDriving()" title="Large controls for listening without looking at the screen">
<span class="mdi mdi-car-outline"></span> Driving mode
</button>
</div>
<div class="mag-controls">
<div class="mag-voice-pick">
<label for="mag-voice">Narrator</label>
<select id="mag-voice"></select>
</div>
<button type="button" class="btn primary" id="mag-play" onclick="magPlay()"
aria-label="Play narration">
<span class="mdi mdi-play"></span> Listen
</button>
<button type="button" class="btn" id="mag-prepare" onclick="magPrepareAudio()"
title="Synthesise the whole article now, so it plays straight through without waiting sentence by sentence">
<span class="mdi mdi-waveform"></span> Prepare audio
</button>
<span id="mag-prep-status" class="muted" role="status" aria-live="polite"></span>
<span id="mag-read-progress" class="muted" aria-live="polite"></span>
<span id="mag-queue-progress" class="muted" aria-live="polite"></span>
<label class="mag-karaoke-toggle" title="Highlight each word approximately as it is spoken">
<input type="checkbox" id="mag-karaoke-cb" checked onchange="TTVC.magazine.karaoke = this.checked">
Word highlighting
</label>
<label class="mag-karaoke-toggle" title="Speak each figure's description where it appears, if one has been generated in review. Takes effect next time this article is opened.">
<input type="checkbox" id="mag-read-descriptions">
Read figure descriptions
</label>
<div class="mag-pane-tabs" role="group" aria-label="Reading view">
<button type="button" class="btn-sm active" data-mag-pane="reflow"
aria-pressed="true" onclick="magSetPane('reflow')">Article</button>
<button type="button" class="btn-sm" data-mag-pane="pdf"
aria-pressed="false" onclick="magSetPane('pdf')">Original page</button>
</div>
</div>
<div id="mag-pane-reflow" class="mag-pane">
<div id="mag-read-image" class="mag-read-image" hidden></div>
<div id="mag-article" class="mag-article"></div>
</div>
<div id="mag-pane-pdf" class="mag-pane" hidden>
<div class="mag-page-wrap">
<img id="mag-page-img" alt="">
<div id="mag-page-box" class="mag-page-box" hidden></div>
</div>
<p id="mag-page-label" class="muted"></p>
</div>
<!-- Podcast mode -->
<details class="card mag-podcast">
<summary><span class="mdi mdi-podcast"></span> Podcast mode &mdash; discuss this article</summary>
<p class="muted">Two or three hosts discuss the article for someone who has not read it. The script is written by the configured LLM from the article text; it will not invent facts, but it is a generated discussion, not the author&rsquo;s words.</p>
<div class="mag-hosts">
<div class="mag-voice-pick"><label for="mag-host-a">Host A</label><select id="mag-host-a"></select></div>
<div class="mag-voice-pick"><label for="mag-host-b">Host B</label><select id="mag-host-b"></select></div>
<div class="mag-voice-pick"><label for="mag-host-c">Host C <span class="muted">(optional)</span></label><select id="mag-host-c"></select></div>
</div>
<div class="mag-podcast-actions">
<button type="button" class="btn" id="mag-podcast-gen" onclick="magGeneratePodcast()">Generate script</button>
<button type="button" class="btn primary" id="mag-podcast-play" onclick="magPlayPodcast()" hidden>Play podcast</button>
</div>
<div id="mag-podcast-script"></div>
</details>
</div>
<!-- ── Driving mode overlay ─────────────────────────────────────────── -->
<!-- Large controls, minimal text, no interaction required beyond play/
pause/skip -- reuses whatever is already playing rather than its
own playback path. -->
<div id="mag-driving" class="mag-driving" hidden role="dialog" aria-label="Driving mode">
<button type="button" class="mag-driving-exit" onclick="magToggleDriving()" aria-label="Exit driving mode">
<span class="mdi mdi-close"></span>
</button>
<div class="mag-driving-body">
<h2 id="mag-driving-title">Article</h2>
<p id="mag-driving-by" class="muted"></p>
<div id="mag-driving-queue" class="mag-driving-queue" hidden>
<span id="mag-queue-progress-2" class="muted"></span>
</div>
<div class="mag-driving-controls">
<button type="button" class="mag-driving-btn" onclick="magQueueNext()" aria-label="Next article" title="Next article (only in Play all)">
<span class="mdi mdi-skip-next"></span>
</button>
<button type="button" class="mag-driving-btn mag-driving-play" id="mag-driving-play" onclick="magPlay()" aria-label="Play">
<span class="mdi mdi-play"></span>
</button>
</div>
</div>
</div>