@gentbajko/slopify 3.10.1 → 3.10.2

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.10.2
2
+
3
+ Released 6 October 2026.
4
+
5
+ - **Writing the YouTube description again no longer remakes the video.** A video with chapter cards draws them from the description, so writing the description again (YouTube → Write again) used to render the whole video again. A finished video now keeps the description it was drawn from: only the description, tags, pinned comment and titles are written again. The video is still remade when something it shows changes (its images, narration, captions or edit settings), and then its chapter cards follow the current description.
@@ -1,4 +1,10 @@
1
1
  [
2
+ {
3
+ "id": "3.10.2",
4
+ "title": "Slopify 3.10.2",
5
+ "version": "3.10.2",
6
+ "date": "2026-10-06"
7
+ },
2
8
  {
3
9
  "id": "3.10.1",
4
10
  "title": "Slopify 3.10.1",
@@ -20,7 +20,36 @@ function withLines(master, lines) {
20
20
  ? master
21
21
  : { values: [...master.values, ...lines.values], keys: [...master.keys, ...lines.keys] };
22
22
  }
23
+ // Every recipe of a version. A finished video whose only change is a description written again
24
+ // keeps the description its chapter cards were drawn from: the video is never remade for a new
25
+ // description, only when what it shows changes.
23
26
  export function buildRecipes(context) {
27
+ const built = buildEach(context);
28
+ const video = built.find((value) => value.key === "export:video");
29
+ const rendered = new Set(context.manifest.pieces
30
+ .filter((one) => one.key === "export:video" && one.piece.state === "done")
31
+ .map((one) => one.fingerprint));
32
+ if (video === undefined || rendered.size === 0 || rendered.has(video.fingerprint))
33
+ return built;
34
+ if (!video.dependsOn.includes(descriptionKey))
35
+ return built;
36
+ const past = context.history ?? context.manifest;
37
+ const fingerprints = new Set(past.pieces.filter((one) => one.key === descriptionKey).map((one) => one.fingerprint));
38
+ const assets = new Set([
39
+ null,
40
+ ...past.outputs.filter((one) => one.workKey === descriptionKey).map((one) => one.assetId),
41
+ ...past.pieces.filter((one) => one.key === descriptionKey).map((one) => one.assetId),
42
+ ]);
43
+ for (const described of fingerprints)
44
+ for (const asset of assets) {
45
+ const kept = buildEach({ ...context, pinnedChapters: [described, asset] }).find((value) => value.key === "export:video");
46
+ if (kept !== undefined && rendered.has(kept.fingerprint))
47
+ return built.map((value) => (value.key === "export:video" ? kept : value));
48
+ }
49
+ return built;
50
+ }
51
+ const descriptionKey = "youtube:description";
52
+ function buildEach(context) {
24
53
  const text = textRecipes(context);
25
54
  const audio = audioRecipes(context, text);
26
55
  const exports = exportRecipes(context, audio);
@@ -49,7 +49,8 @@ export function editPlan(context, exports, youtube, images, cards = []) {
49
49
  values.push(["timing", resourceIdentity(context, timing)]);
50
50
  dependsOn.push(timing.key);
51
51
  if (fromDescription && description !== undefined) {
52
- values.push(["chapters", resourceIdentity(context, description)]);
52
+ // A finished video keeps the description it was drawn from (`recipe-build.ts`).
53
+ values.push(["chapters", context.pinnedChapters ?? resourceIdentity(context, description)]);
53
54
  dependsOn.push(description.key);
54
55
  }
55
56
  else
@@ -83,6 +83,7 @@ export function planRevision(base, edit, prepared = { outputs: [], pieces: [] },
83
83
  config: base.revision.config,
84
84
  content: base.revision.content,
85
85
  manifest,
86
+ history: { outputs: base.outputs, pieces: base.pieces },
86
87
  resolved: {
87
88
  articleMarkdown: base.articleMarkdown,
88
89
  researchNotes: base.revision.config.provided.research ?? null,
@@ -30,6 +30,7 @@ export function planRevisionWork(revision, manifest, catalogue, availableAssetId
30
30
  config: revision.config,
31
31
  content: revision.content,
32
32
  manifest: available,
33
+ history: manifest,
33
34
  resolved: { ...resolved, articleMarkdown: usableArticle ? resolved.articleMarkdown : null },
34
35
  };
35
36
  const logical = buildRecipes(logicalContext);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gentbajko/slopify",
3
- "version": "3.10.1",
3
+ "version": "3.10.2",
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",