@gentbajko/slopify 3.10.1 → 3.10.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.
- package/dist/extension/slopify-studio-chrome.zip +0 -0
- package/dist/extension/slopify-studio-firefox.zip +0 -0
- package/dist/patch-notes/3.10.2.md +5 -0
- package/dist/patch-notes/3.10.3.md +5 -0
- package/dist/patch-notes/index.json +12 -0
- package/dist/slices/rebuild/recipe-build.js +29 -0
- package/dist/slices/rebuild/recipe-edit.js +2 -1
- package/dist/slices/rebuild/recipe-save.js +1 -0
- package/dist/slices/rebuild/recipe-work.js +1 -0
- package/dist/slices/youtube/answer.js +2 -2
- package/package.json +1 -1
|
Binary file
|
|
Binary file
|
|
@@ -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.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# Slopify 3.10.3
|
|
2
|
+
|
|
3
|
+
Released 6 October 2026.
|
|
4
|
+
|
|
5
|
+
- **A link your description prompt asks for is kept.** Slopify told the AI model never to put a link in the description's summary or the pinned comment, so a prompt asking for one (each video's own page on your website, say) got a description that mentions the page without its address. The model still never makes a link up, but one your prompt gives or describes is written exactly as asked. Links from Settings → Channel links keep working as before.
|
|
@@ -1,4 +1,16 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"id": "3.10.3",
|
|
4
|
+
"title": "Slopify 3.10.3",
|
|
5
|
+
"version": "3.10.3",
|
|
6
|
+
"date": "2026-10-06"
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"id": "3.10.2",
|
|
10
|
+
"title": "Slopify 3.10.2",
|
|
11
|
+
"version": "3.10.2",
|
|
12
|
+
"date": "2026-10-06"
|
|
13
|
+
},
|
|
2
14
|
{
|
|
3
15
|
"id": "3.10.1",
|
|
4
16
|
"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
|
-
|
|
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);
|
|
@@ -20,8 +20,8 @@ export function descriptionMessages(brief) {
|
|
|
20
20
|
`- Hashtags are single words starting with #, at most ${String(hashtagsMax)}.`,
|
|
21
21
|
`- Tags are plain search terms without # or commas, each at most ${String(tagMaxCharacters)} characters, no tag repeated, and all tags together at most ${String(tagsMaxCharacters)} characters.`,
|
|
22
22
|
"- No < or > anywhere.",
|
|
23
|
-
"- The summary is plain text without chapters
|
|
24
|
-
`- The pinned comment is plain text
|
|
23
|
+
"- The summary is plain text without chapters or hashtags. It has no links, except a link the instructions below ask for: write that one exactly as they give or describe it, and never make up any other.",
|
|
24
|
+
`- The pinned comment is plain text, at most ${String(pinnedCommentMaxCharacters)} characters. It has no links, except a link the instructions below ask for, written exactly as they give or describe it.`,
|
|
25
25
|
`- Titles are exactly ${String(alternativeTitles)} other titles for this video, for YouTube's title A/B test beside the video's own title: each at most ${String(titleMaxCharacters)} characters, one line, different from the video title and from each other.`,
|
|
26
26
|
...(brief.shape === undefined ? [] : [titleShapeRule(brief.shape)]),
|
|
27
27
|
"",
|