@gentbajko/slopify 3.25.3 → 3.25.5

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.25.4
2
+
3
+ Released 17 October 2026.
4
+
5
+ - **The shorts of an older project render after you change it.** On a project made before late September, a saved change (such as turning on Soften breaths) left its shorts waiting forever: they showed as waiting their turn and never started. They now render.
@@ -0,0 +1,5 @@
1
+ # Slopify 3.25.5
2
+
3
+ Released 17 October 2026.
4
+
5
+ - **New videos reach the Upload folder again.** After Delete old versions, Slopify could stop arranging project folders altogether: a remade video, its shorts and everything else new stayed hidden in the project's assets folder while Upload kept the old files. Folders are arranged again, and the newest files take their place in Upload.
@@ -1,4 +1,16 @@
1
1
  [
2
+ {
3
+ "id": "3.25.5",
4
+ "title": "Slopify 3.25.5",
5
+ "version": "3.25.5",
6
+ "date": "2026-10-17"
7
+ },
8
+ {
9
+ "id": "3.25.4",
10
+ "title": "Slopify 3.25.4",
11
+ "version": "3.25.4",
12
+ "date": "2026-10-17"
13
+ },
2
14
  {
3
15
  "id": "3.25.3",
4
16
  "title": "Slopify 3.25.3",
@@ -220,10 +220,18 @@ export function shortRemakeKey(number) {
220
220
  }
221
221
  // What the pick saved, when its saved answer is the one this plan asks for.
222
222
  export function savedPicked(context, pick) {
223
- const piece = context.manifest.pieces.find((row) => row.key === pick.key &&
224
- selectedReference(row) &&
225
- row.piece.state === "done" &&
226
- row.fingerprint === pick.fingerprint);
223
+ const done = context.manifest.pieces.filter((row) => row.key === pick.key && selectedReference(row) && row.piece.state === "done");
224
+ const piece = done.find((row) => row.fingerprint === pick.fingerprint) ??
225
+ // A project from before an older fingerprint scheme: its output carries the plan's
226
+ // fingerprint and its piece another one. The version's one selected pick belongs with its
227
+ // selected output, so that output's fingerprint vouches for it.
228
+ (done.length === 1 &&
229
+ context.manifest.outputs.some((row) => row.workKey === pick.key &&
230
+ selectedReference(row) &&
231
+ row.fingerprint === pick.fingerprint &&
232
+ (row.state === "ready" || row.state === "outdated"))
233
+ ? done[0]
234
+ : undefined);
227
235
  return pickedShortsOf(piece?.piece.payload);
228
236
  }
229
237
  // A clip's saved image prompts, when they answer this plan's request. The request carries
@@ -70,6 +70,12 @@ export function arrangeProject(deps, projectId) {
70
70
  places.moves.folderDone(projectId);
71
71
  }
72
72
  const root = projectDir(paths, projectId);
73
+ // Records of files gone from both their stored path and their place (History that Delete old
74
+ // versions removed, a file deleted by hand) are forgotten, so the names they held are free:
75
+ // otherwise a file moving there is refused and nothing after it is arranged.
76
+ for (const [path, place] of places.placesOf(projectId))
77
+ if (!existsSync(join(root, place)) && !existsSync(join(root, path)))
78
+ places.moves.forget(projectId, path);
73
79
  // 2. Each file to its place. Files leaving for History go first, so the new version takes
74
80
  // the names they free ("video.mp4", not "video (2).mp4").
75
81
  const desired = [...desiredPlaces(db, projectId)].toSorted(([, a], [, b]) => Number(!a.startsWith("History/")) - Number(!b.startsWith("History/")));
@@ -80,16 +86,20 @@ export function arrangeProject(deps, projectId) {
80
86
  if (sameBase(at, base) || !existsSync(join(root, at)))
81
87
  continue;
82
88
  const to = freeName(base, (name) => existsSync(join(root, name)));
83
- places.moves.file(projectId, path, to, placed.get(path));
89
+ let recorded = false;
84
90
  try {
91
+ places.moves.file(projectId, path, to, placed.get(path));
92
+ recorded = true;
85
93
  mkdirSync(dirname(join(root, to)), { recursive: true });
86
94
  renameSync(join(root, at), join(root, to));
87
95
  places.moves.fileDone(projectId, path);
88
96
  moved += 1;
89
97
  }
90
98
  catch {
91
- // In use (a player or download on Windows): it stays and is tried again next time.
92
- places.moves.fileUndone(projectId, path);
99
+ // In use (a player or download on Windows), or its name refused: it stays where it is and
100
+ // is tried again next time, and the files after it are still arranged.
101
+ if (recorded)
102
+ places.moves.fileUndone(projectId, path);
93
103
  }
94
104
  }
95
105
  removeEmptyFolders(root);
@@ -81,6 +81,10 @@ export function createPlaces(db) {
81
81
  if (row !== undefined)
82
82
  setFile(projectId, path, { ...row, state: "placed", previous: undefined });
83
83
  },
84
+ forget(projectId, path) {
85
+ db.prepare("DELETE FROM file_places WHERE project_id=? AND path=?").run(projectId, path);
86
+ setFile(projectId, path, undefined);
87
+ },
84
88
  fileUndone(projectId, path) {
85
89
  const row = files.get(projectId)?.get(path);
86
90
  if (row?.previous === undefined || row.previous === path) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gentbajko/slopify",
3
- "version": "3.25.3",
3
+ "version": "3.25.5",
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",