@gentbajko/slopify 3.25.6 → 3.25.8
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.
- package/dist/extension/slopify-studio-chrome.zip +0 -0
- package/dist/extension/slopify-studio-firefox.zip +0 -0
- package/dist/patch-notes/3.25.7.md +5 -0
- package/dist/patch-notes/3.25.8.md +5 -0
- package/dist/patch-notes/index.json +12 -0
- package/dist/slices/rebuild/recipe-save.js +11 -2
- package/dist/slices/rebuild/recipe-shorts.js +18 -6
- package/package.json +1 -1
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# Slopify 3.25.7
|
|
2
|
+
|
|
3
|
+
Released 17 October 2026.
|
|
4
|
+
|
|
5
|
+
- **An older project's shorts can be remade again.** On a project made before an earlier change to how Slopify recognises finished work, Choose what to remake said a short "has an unavailable prerequisite" and a run left the shorts out. Slopify now recognises the shorts it already picked, so they render again without picking new moments.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# Slopify 3.25.8
|
|
2
|
+
|
|
3
|
+
Released 17 October 2026.
|
|
4
|
+
|
|
5
|
+
- **Older projects' shorts follow a changed narration.** On a project made before Slopify kept track of each short's render, saving it again after levelling or softening the narration kept the old shorts as if they were current. Their renders now read out of date and are made again on this computer, with nothing paid.
|
|
@@ -1,4 +1,16 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"id": "3.25.8",
|
|
4
|
+
"title": "Slopify 3.25.8",
|
|
5
|
+
"version": "3.25.8",
|
|
6
|
+
"date": "2026-10-17"
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"id": "3.25.7",
|
|
10
|
+
"title": "Slopify 3.25.7",
|
|
11
|
+
"version": "3.25.7",
|
|
12
|
+
"date": "2026-10-17"
|
|
13
|
+
},
|
|
2
14
|
{
|
|
3
15
|
"id": "3.25.6",
|
|
4
16
|
"title": "Slopify 3.25.6",
|
|
@@ -216,8 +216,8 @@ function planEdit(base, edit, prepared, inspected, keeping) {
|
|
|
216
216
|
const fingerprints = Object.fromEntries(desired.map((row) => [row.key, row.fingerprint]));
|
|
217
217
|
const outputs = proposedManifest.outputs.map((row) => {
|
|
218
218
|
const next = desired.find((value) => value.key === row.workKey);
|
|
219
|
-
const
|
|
220
|
-
|
|
219
|
+
const before = old.find((value) => value.key === row.workKey)?.fingerprint;
|
|
220
|
+
const unchanged = next !== undefined && before === next.fingerprint && !staleRender(base, row, before);
|
|
221
221
|
const state = next === undefined
|
|
222
222
|
? row.state
|
|
223
223
|
: prepared.outputs.includes(row) || (unchanged && row.state === "ready")
|
|
@@ -248,6 +248,15 @@ function planEdit(base, edit, prepared, inspected, keeping) {
|
|
|
248
248
|
shortMoves: [...moves.entries()],
|
|
249
249
|
};
|
|
250
250
|
}
|
|
251
|
+
// A render a version from an older Slopify never recorded, made for another recipe than the
|
|
252
|
+
// one the version asks for: its narration was changed (levelled or softened) since, and saving
|
|
253
|
+
// the version again must not take the old file for the new render. Only renders: they are made
|
|
254
|
+
// on this computer and nothing paid is made from them.
|
|
255
|
+
function staleRender(base, row, before) {
|
|
256
|
+
return ((row.workKey === "export:video" || /^shorts:\d+:render$/.test(row.workKey)) &&
|
|
257
|
+
base.revision.fingerprints[row.workKey] === undefined &&
|
|
258
|
+
row.fingerprint !== before);
|
|
259
|
+
}
|
|
251
260
|
function normalizeImages(content) {
|
|
252
261
|
return {
|
|
253
262
|
...content,
|
|
@@ -9,7 +9,7 @@ import { imagePromptMessages } from "../shorts/prompts.js";
|
|
|
9
9
|
import { lookWait, withLooks } from "./recipe-appearance.js";
|
|
10
10
|
import { castFor } from "./recipe-cast.js";
|
|
11
11
|
import { noMaster } from "./recipe-loudness.js";
|
|
12
|
-
import { recipe, resourceIdentity, selectedReference, } from "./recipe-model.js";
|
|
12
|
+
import { recipe, resourceIdentity, selectedAsset, selectedReference, } from "./recipe-model.js";
|
|
13
13
|
import { castField, imageChoice } from "./recipe-reference.js";
|
|
14
14
|
import { llmInput, renderedPrompt } from "./recipe-text.js";
|
|
15
15
|
// The Shorts step unfolds as its answers land, the way research's chapters unfold from the
|
|
@@ -39,12 +39,12 @@ appearance) {
|
|
|
39
39
|
const timing = exports.find((value) => value.key === "subtitles:timing");
|
|
40
40
|
if (!usesShorts(config) || shorts === undefined || timing === undefined)
|
|
41
41
|
return [];
|
|
42
|
-
const
|
|
42
|
+
const pickFor = (timingIdentity) => recipe(context, shortsPickKey, "video", {
|
|
43
43
|
kind: "local",
|
|
44
44
|
version: 1,
|
|
45
45
|
operation: "shorts-pick-v1",
|
|
46
46
|
values: [
|
|
47
|
-
|
|
47
|
+
timingIdentity,
|
|
48
48
|
config.llm?.provider ?? "",
|
|
49
49
|
config.llm?.model ?? "",
|
|
50
50
|
config.llm?.thinking ?? null,
|
|
@@ -81,7 +81,17 @@ appearance) {
|
|
|
81
81
|
}, [timing.key],
|
|
82
82
|
// A paid LLM call: readiness, the charge warning and the estimate treat it like one.
|
|
83
83
|
{ kind: "provider" });
|
|
84
|
-
const
|
|
84
|
+
const pick = pickFor(resourceIdentity(context, timing));
|
|
85
|
+
// The same pick asked of the finished timing as it was recorded: a run's plan reads the
|
|
86
|
+
// catalogue, which gives the timing another fingerprint than the one the version was saved
|
|
87
|
+
// with, while the timing file is the same.
|
|
88
|
+
const asset = selectedAsset(context, timing.key, timing.fingerprint);
|
|
89
|
+
const recorded = context.manifest.outputs.find((row) => row.workKey === timing.key &&
|
|
90
|
+
row.assetId === asset &&
|
|
91
|
+
asset !== null &&
|
|
92
|
+
row.fingerprint !== timing.fingerprint &&
|
|
93
|
+
selectedReference(row));
|
|
94
|
+
const picked = savedPicked(context, pick, recorded === undefined ? [] : [pickFor([recorded.fingerprint, asset]).fingerprint]);
|
|
85
95
|
const images = config.images ?? { provider: "", model: "" };
|
|
86
96
|
// A shorts image prompt may name `{{Scene}}` like the video's: the prompts call already writes
|
|
87
97
|
// each image's moment from what the clip says, so that line is left out here.
|
|
@@ -219,7 +229,9 @@ export function shortRemakeKey(number) {
|
|
|
219
229
|
return `shorts:${String(number)}`;
|
|
220
230
|
}
|
|
221
231
|
// What the pick saved, when its saved answer is the one this plan asks for.
|
|
222
|
-
export function savedPicked(context, pick
|
|
232
|
+
export function savedPicked(context, pick,
|
|
233
|
+
// Other fingerprints the same pick has (the one recorded with the finished timing).
|
|
234
|
+
also = []) {
|
|
223
235
|
const done = context.manifest.pieces.filter((row) => row.key === pick.key && selectedReference(row) && row.piece.state === "done");
|
|
224
236
|
const piece = done.find((row) => row.fingerprint === pick.fingerprint) ??
|
|
225
237
|
// A project from before an older fingerprint scheme: its output carries the plan's
|
|
@@ -228,7 +240,7 @@ export function savedPicked(context, pick) {
|
|
|
228
240
|
(done.length === 1 &&
|
|
229
241
|
context.manifest.outputs.some((row) => row.workKey === pick.key &&
|
|
230
242
|
selectedReference(row) &&
|
|
231
|
-
row.fingerprint === pick.fingerprint &&
|
|
243
|
+
(row.fingerprint === pick.fingerprint || also.includes(row.fingerprint)) &&
|
|
232
244
|
(row.state === "ready" || row.state === "outdated"))
|
|
233
245
|
? done[0]
|
|
234
246
|
: undefined);
|