Release v1.53.0
Some checks failed
Test and SonarQube / quality (push) Has been cancelled

This commit is contained in:
mARTin-B78 2026-09-23 00:01:25 +02:00
parent ab5fce10bf
commit ba3b374246
5 changed files with 65 additions and 14 deletions

View File

@ -9,6 +9,16 @@ Follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) · versioned wi
---
## [1.53.0] — 2026-09-23
### Added
- **Magazine: the "All pages" grid is colour-coded by review status** — blank (no article yet, the normal mid-review state), red (has content, not reviewed), yellow (reviewed), green (reviewed and MP3 generated), grey (reviewed, nothing to narrate — a blank page or an ad). A small legend explains the colours.
### Fixed
- **Magazine: "Review this page" on a page-coverage gap failed with "Method Not Allowed."** The endpoint it needs (`POST /api/magazine/{doc_id}/articles`, added alongside the gap-jump feature itself) had never actually been deployed with a container restart.
---
## [1.52.1] — 2026-09-22
### Fixed
@ -4419,7 +4429,8 @@ Initial feature-complete release.
---
[Unreleased]: https://github.com/mARTin-B78/tts-voice-creator-clone-and-design-2/compare/v1.52.1...HEAD
[Unreleased]: https://github.com/mARTin-B78/tts-voice-creator-clone-and-design-2/compare/v1.53.0...HEAD
[1.53.0]: https://github.com/mARTin-B78/tts-voice-creator-clone-and-design-2/compare/v1.52.1...v1.53.0
[1.52.1]: https://github.com/mARTin-B78/tts-voice-creator-clone-and-design-2/compare/v1.52.0...v1.52.1
[1.52.0]: https://github.com/mARTin-B78/tts-voice-creator-clone-and-design-2/compare/v1.51.0...v1.52.0
[1.51.0]: https://github.com/mARTin-B78/tts-voice-creator-clone-and-design-2/compare/v1.50.0...v1.51.0

View File

@ -1 +1 @@
1.52.1
1.53.0

View File

@ -10,7 +10,7 @@
<meta name="format-detection" content="telephone=no">
<meta name="color-scheme" content="light dark">
<meta name="theme-color" content="#2563EB">
<meta name="app-version" content="1.52.1">
<meta name="app-version" content="1.53.0">
<link rel="manifest" href="/manifest.webmanifest">
<link rel="icon" href="/static/icon.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="/static/icon.svg">
@ -27,12 +27,12 @@
<!-- ── Core styles (local — no CDN dependency for first paint) ────────── -->
<link rel="stylesheet" href="/static/vendor/mdi/materialdesignicons.min.css">
<link rel="stylesheet" href="/static/style.css?v=1.52.1">
<link rel="stylesheet" href="/static/css/resource-diagnostics.css?v=1.52.1">
<link rel="stylesheet" href="/static/css/background-jobs.css?v=1.52.1">
<link rel="stylesheet" href="/static/css/voice-design.css?v=1.52.1">
<link rel="stylesheet" href="/static/css/rehearser.css?v=1.52.1">
<link rel="stylesheet" href="/static/css/audiobook.css?v=1.52.1">
<link rel="stylesheet" href="/static/style.css?v=1.53.0">
<link rel="stylesheet" href="/static/css/resource-diagnostics.css?v=1.53.0">
<link rel="stylesheet" href="/static/css/background-jobs.css?v=1.53.0">
<link rel="stylesheet" href="/static/css/voice-design.css?v=1.53.0">
<link rel="stylesheet" href="/static/css/rehearser.css?v=1.53.0">
<link rel="stylesheet" href="/static/css/audiobook.css?v=1.53.0">
<!-- ── Flag icons — non-blocking (loaded async, icons appear after JS) ── -->
@ -403,7 +403,7 @@ window.toggleNavTree = function(treeId, chevronId) {
</script>
<!-- loader.js: fetches sections → loads JS modules → removes skeleton -->
<script src="/static/loader.js?v=1.52.1"></script>
<script src="/static/loader.js?v=1.53.0"></script>
</body>
</html>

View File

@ -779,6 +779,25 @@ const MAG_PAGES_COLS_KEY = 'ttsvc_mag_pages_cols';
// magUncoveredPageRanges). This is the complete picture: a page can belong
// to zero articles (never reviewed), one, or several (a page shared by two
// short pieces), and this shows all three cases rather than picking one.
// One of five states per page, cheap to compute from data already loaded
// (no extra layout/OCR fetch just to colour an overview grid):
// blank -- no article touches this page at all yet
// detected -- an article does, but it's still sitting at its
// just-detected status -- OCR ran, a human hasn't looked
// approved -- reviewed and approved, no audio rendered yet
// audio -- reviewed, approved, and has a generated MP3
// empty -- reviewed and rejected ("Not an article") on every article
// that touches it -- a blank page or an ad, not a gap
// A page touched by several articles takes the most-attention-needed state
// among them (audio beats approved beats detected beats empty).
function magPageState(arts) {
if (!arts.length) return 'blank';
if (arts.some((a) => a.has_audio)) return 'audio';
if (arts.some((a) => a.status === 'detected')) return 'detected';
if (arts.some((a) => a.status === 'approved')) return 'approved';
return 'empty';
}
function renderPagesView(host) {
const pageCount = state.doc?.pageCount || 0;
if (!pageCount) { host.innerHTML = '<p class="muted">Page count unknown yet.</p>'; return; }
@ -787,10 +806,17 @@ function renderPagesView(host) {
if (!byPage.has(p)) byPage.set(p, []);
byPage.get(p).push(a);
}));
let html = '<div class="mag-pages-grid" style="--cols:' + state.pagesCols + '">';
const legend = [
['blank', 'not reviewed yet'], ['detected', 'has content, not reviewed'],
['approved', 'reviewed'], ['audio', 'reviewed + audio generated'], ['empty', 'reviewed, nothing to narrate'],
];
let html = '<p class="mag-pages-legend">' +
legend.map(([cls, label]) => '<span class="mag-pages-legend-item"><span class="mag-pages-legend-swatch is-page-' + cls + '"></span>' + label + '</span>').join('') +
'</p>';
html += '<div class="mag-pages-grid" style="--cols:' + state.pagesCols + '">';
for (let p = 1; p <= pageCount; p++) {
const arts = byPage.get(p) || [];
html += '<div class="mag-card-wrap"><div class="mag-card' + (arts.length ? '' : ' is-uncovered') + '">' +
html += '<div class="mag-card-wrap"><div class="mag-card is-page-' + magPageState(arts) + '">' +
'<img class="mag-card-thumb" loading="lazy" alt="Page ' + p + '" src="/api/magazine/' + esc(state.doc.id) + '/pages/' + p + '">' +
'<span class="mag-card-title">Page ' + p + '</span>' +
(arts.length

View File

@ -4945,8 +4945,22 @@ input[list="lang-codes"] {
#mag-cols-value { min-width: 16px; text-align: right; }
@media (max-width: 900px) { .mag-pages-grid { grid-template-columns: repeat(min(var(--cols, 8), 4), 1fr); } }
@media (max-width: 560px) { .mag-pages-grid { grid-template-columns: repeat(min(var(--cols, 8), 2), 1fr); } }
.mag-card.is-uncovered { border-color: var(--yellow, #d97706);
background: color-mix(in srgb, var(--yellow, #d97706) 6%, var(--surface)); }
/* Page-state colours in the "All pages" grid -- blank (no article yet) is
deliberately the plain default look, not a warning: an untouched page is
normal mid-review, unlike a page that already has content sitting
unreviewed (detected, red) or with nothing worth narrating (empty, grey,
which is a completed decision, not a problem). */
.mag-card.is-page-detected { border-color: var(--red); background: color-mix(in srgb, var(--red) 8%, var(--surface)); }
.mag-card.is-page-approved { border-color: var(--yellow); background: color-mix(in srgb, var(--yellow) 8%, var(--surface)); }
.mag-card.is-page-audio { border-color: var(--green); background: color-mix(in srgb, var(--green) 8%, var(--surface)); }
.mag-card.is-page-empty { border-color: var(--subtext); background: color-mix(in srgb, var(--subtext) 8%, var(--surface)); }
.mag-pages-legend { display: flex; flex-wrap: wrap; gap: 6px 14px; font-size: 12px; color: var(--subtext); margin: 0 0 12px; }
.mag-pages-legend-item { display: inline-flex; align-items: center; gap: 5px; }
.mag-pages-legend-swatch { width: 12px; height: 12px; border-radius: 3px; border: 2px solid var(--border); }
.mag-pages-legend-swatch.is-page-detected { border-color: var(--red); background: color-mix(in srgb, var(--red) 20%, var(--surface)); }
.mag-pages-legend-swatch.is-page-approved { border-color: var(--yellow); background: color-mix(in srgb, var(--yellow) 20%, var(--surface)); }
.mag-pages-legend-swatch.is-page-audio { border-color: var(--green); background: color-mix(in srgb, var(--green) 20%, var(--surface)); }
.mag-pages-legend-swatch.is-page-empty { border-color: var(--subtext); background: color-mix(in srgb, var(--subtext) 20%, var(--surface)); }
.mag-audio-export { display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
padding: 10px 14px; margin-bottom: 12px; border: 1px solid var(--border); border-radius: var(--radius);