@gentbajko/slopify 3.11.1 → 3.11.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,5 @@
1
+ # Slopify 3.11.2
2
+
3
+ Released 6 October 2026.
4
+
5
+ - **An article fix the narration already had keeps the video.** After 3.11.1 kept such a chunk's narration, the word timing still counted as changed, so the captions, shorts, description and video were marked outdated anyway. The timing now reads the spoken text the same way before and after, so only what the article itself feeds (the PDF) is remade.
@@ -0,0 +1,5 @@
1
+ # Slopify 3.11.3
2
+
3
+ Released 6 October 2026.
4
+
5
+ - **A project no longer waits on steps it doesn't need.** Steps an edit planned (a narration or a render) were carried into every later version while their inputs looked the same, even once a later save showed the result already made was the one wanted. The project then stayed waiting, its video step pending, and wasn't offered as ready to upload. A step that never started is now carried only while it is for what the version wants; otherwise the finished result is used.
@@ -1,4 +1,16 @@
1
1
  [
2
+ {
3
+ "id": "3.11.3",
4
+ "title": "Slopify 3.11.3",
5
+ "version": "3.11.3",
6
+ "date": "2026-10-06"
7
+ },
8
+ {
9
+ "id": "3.11.2",
10
+ "title": "Slopify 3.11.2",
11
+ "version": "3.11.2",
12
+ "date": "2026-10-06"
13
+ },
2
14
  {
3
15
  "id": "3.11.1",
4
16
  "title": "Slopify 3.11.1",
@@ -94,7 +94,10 @@ export function audioRecipes(context, text) {
94
94
  pending = true;
95
95
  parts.push(...group);
96
96
  }
97
- if (transcripts.some((row) => row.effective !== row.original))
97
+ // A chunk with its own narration edit keeps the transcript in this form even once the article
98
+ // says the same (`bodyNarrationGroups`), so the word timing made from it stays current.
99
+ if (transcripts.some((row) => row.effective !== row.original) ||
100
+ groups.some((group) => content.narrationOverrides[group.key]?.kind === "text"))
98
101
  bodyTranscript = ["narration-transcript-v1", transcripts.map((row) => row.effective)];
99
102
  if (text.narrationText === null) {
100
103
  futurePronunciation.push(...pronunciationFutureValues(context, text.glossary, text.article, "audio:body:future", null), ...aliasFutureValues(context, "audio:body:future", null));
@@ -46,7 +46,16 @@ export function transitionRevisionWork(deps, input) {
46
46
  if (before !== undefined &&
47
47
  before === after &&
48
48
  (input.baseFingerprints !== undefined ||
49
- before === (row.desired_fingerprint ?? row.fingerprint))) {
49
+ before === (row.desired_fingerprint ?? row.fingerprint)) &&
50
+ // A held step nobody started carries over only while it is for what is wanted now:
51
+ // one planned for a result an edit no longer asks for (the edit's narration turned out
52
+ // to be the one already made) kept the project waiting on work it doesn't need.
53
+ // A step reserved under its own key is for its own result; one unfolded under another
54
+ // key (a narration chunk's parts) is matched by what that key wanted.
55
+ !(after !==
56
+ (logicalKey === row.work_key
57
+ ? row.fingerprint
58
+ : (row.desired_fingerprint ?? row.fingerprint)) && unstarted(db, row.work_id))) {
50
59
  db.prepare(`INSERT INTO revision_work_reservations(project_id,revision_id,work_key,work_id,piece_id,fingerprint,logical_key,desired_fingerprint) VALUES (?,?,?,?,?,?,?,?)`).run(input.projectId, input.revisionId, row.work_key, row.work_id, row.piece_id, row.fingerprint, logicalKey, after);
51
60
  carried.add(logicalKey);
52
61
  if (own !== undefined)
@@ -111,6 +120,15 @@ export function transitionRevisionWork(deps, input) {
111
120
  }
112
121
  });
113
122
  }
123
+ // Held and never begun: no attempt, nothing submitted, no planning context.
124
+ function unstarted(db, workId) {
125
+ return (db
126
+ .prepare(`SELECT 1 FROM revision_work w WHERE w.id=? AND w.state='pending' AND w.dispatch_state='held'
127
+ AND w.recipe_context IS NULL
128
+ AND NOT EXISTS(SELECT 1 FROM attempts a WHERE a.work_id=w.id)
129
+ AND NOT EXISTS(SELECT 1 FROM revision_work_pieces p WHERE p.work_id=w.id AND p.submitted_at IS NOT NULL)`)
130
+ .get(workId) !== undefined);
131
+ }
114
132
  // A finished row wins over a held one. A held row counts only while nothing ran for it:
115
133
  // no attempt, nothing submitted, and no planning context (admission gives a row that).
116
134
  function existingWork(db, projectId, key, fingerprint) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gentbajko/slopify",
3
- "version": "3.11.1",
3
+ "version": "3.11.3",
4
4
  "description": "Turn a prompt into a finished video, locally, with your own provider keys",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Gent Bajko",