mulmocast 2.6.15 → 2.6.16
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/lib/actions/index.d.ts +1 -0
- package/lib/actions/index.js +1 -0
- package/lib/actions/viewer.d.ts +3 -0
- package/lib/actions/viewer.js +173 -0
- package/lib/cli/commands/viewer/builder.d.ts +20 -0
- package/lib/cli/commands/viewer/builder.js +6 -0
- package/lib/cli/commands/viewer/handler.d.ts +4 -0
- package/lib/cli/commands/viewer/handler.js +11 -0
- package/lib/cli/commands/viewer/index.d.ts +4 -0
- package/lib/cli/commands/viewer/index.js +4 -0
- package/lib/cli/main.js +2 -0
- package/lib/types/schema.d.ts +1 -0
- package/lib/types/schema.js +1 -0
- package/lib/types/type.d.ts +1 -1
- package/lib/utils/context.d.ts +1 -0
- package/lib/utils/context.js +1 -0
- package/package.json +8 -8
package/lib/actions/index.d.ts
CHANGED
package/lib/actions/index.js
CHANGED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { localizedText } from "../utils/utils.js";
|
|
4
|
+
import { writingMessage } from "../utils/file.js";
|
|
5
|
+
import { MulmoStudioContextMethods } from "../methods/mulmo_studio_context.js";
|
|
6
|
+
import { escapeHtml } from "../slide/utils.js";
|
|
7
|
+
const imageMimeTypes = {
|
|
8
|
+
png: "image/png",
|
|
9
|
+
jpg: "image/jpeg",
|
|
10
|
+
jpeg: "image/jpeg",
|
|
11
|
+
gif: "image/gif",
|
|
12
|
+
webp: "image/webp",
|
|
13
|
+
svg: "image/svg+xml",
|
|
14
|
+
};
|
|
15
|
+
const imageToDataUri = (filePath) => {
|
|
16
|
+
if (!fs.existsSync(filePath)) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
const ext = path.extname(filePath).slice(1).toLowerCase();
|
|
20
|
+
const mime = imageMimeTypes[ext] ?? "image/png";
|
|
21
|
+
const base64 = fs.readFileSync(filePath).toString("base64");
|
|
22
|
+
return `data:${mime};base64,${base64}`;
|
|
23
|
+
};
|
|
24
|
+
const collectSlides = (context) => {
|
|
25
|
+
const { studio, multiLingual, lang = "en" } = context;
|
|
26
|
+
const slides = [];
|
|
27
|
+
studio.script.beats.forEach((beat, index) => {
|
|
28
|
+
const studioBeat = studio.beats[index];
|
|
29
|
+
// Prefer the HTML-rendered frame over the source image, matching pdf.ts / movie.ts.
|
|
30
|
+
const source = studioBeat?.htmlImageFile ?? studioBeat?.imageFile;
|
|
31
|
+
if (!source)
|
|
32
|
+
return;
|
|
33
|
+
const dataUri = imageToDataUri(source);
|
|
34
|
+
if (!dataUri)
|
|
35
|
+
return;
|
|
36
|
+
slides.push({
|
|
37
|
+
dataUri,
|
|
38
|
+
caption: localizedText(beat, multiLingual?.[index], lang),
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
return slides;
|
|
42
|
+
};
|
|
43
|
+
const viewerStyles = `
|
|
44
|
+
html, body { margin: 0; padding: 0; height: 100vh; overflow: hidden; background: #000; }
|
|
45
|
+
#deck { position: relative; width: 100vw; height: 100vh; }
|
|
46
|
+
section.slide {
|
|
47
|
+
position: absolute;
|
|
48
|
+
inset: 0;
|
|
49
|
+
display: flex;
|
|
50
|
+
flex-direction: column;
|
|
51
|
+
align-items: center;
|
|
52
|
+
justify-content: center;
|
|
53
|
+
visibility: hidden;
|
|
54
|
+
padding: 24px;
|
|
55
|
+
box-sizing: border-box;
|
|
56
|
+
}
|
|
57
|
+
section.slide.active { visibility: visible; }
|
|
58
|
+
section.slide img {
|
|
59
|
+
max-width: 100%;
|
|
60
|
+
max-height: 80vh;
|
|
61
|
+
object-fit: contain;
|
|
62
|
+
user-select: none;
|
|
63
|
+
}
|
|
64
|
+
section.slide p.caption {
|
|
65
|
+
color: #eee;
|
|
66
|
+
margin-top: 16px;
|
|
67
|
+
text-align: center;
|
|
68
|
+
font-family: system-ui, -apple-system, sans-serif;
|
|
69
|
+
max-width: 80ch;
|
|
70
|
+
max-height: 15vh;
|
|
71
|
+
overflow: hidden;
|
|
72
|
+
}
|
|
73
|
+
#counter {
|
|
74
|
+
position: fixed;
|
|
75
|
+
right: 16px;
|
|
76
|
+
bottom: 12px;
|
|
77
|
+
color: #aaa;
|
|
78
|
+
font-family: system-ui, -apple-system, sans-serif;
|
|
79
|
+
font-size: 14px;
|
|
80
|
+
user-select: none;
|
|
81
|
+
pointer-events: none;
|
|
82
|
+
}
|
|
83
|
+
`;
|
|
84
|
+
const viewerScript = `
|
|
85
|
+
(function () {
|
|
86
|
+
const slides = document.querySelectorAll("section.slide");
|
|
87
|
+
const counter = document.getElementById("counter");
|
|
88
|
+
if (slides.length === 0) return;
|
|
89
|
+
let current = 0;
|
|
90
|
+
const show = (i) => {
|
|
91
|
+
slides[current].classList.remove("active");
|
|
92
|
+
current = Math.max(0, Math.min(slides.length - 1, i));
|
|
93
|
+
slides[current].classList.add("active");
|
|
94
|
+
counter.textContent = (current + 1) + " / " + slides.length;
|
|
95
|
+
};
|
|
96
|
+
document.addEventListener("keydown", (e) => {
|
|
97
|
+
if (e.key === "ArrowRight" || e.key === " " || e.key === "PageDown") {
|
|
98
|
+
e.preventDefault();
|
|
99
|
+
show(current + 1);
|
|
100
|
+
} else if (e.key === "ArrowLeft" || e.key === "PageUp") {
|
|
101
|
+
e.preventDefault();
|
|
102
|
+
show(current - 1);
|
|
103
|
+
} else if (e.key === "Home") {
|
|
104
|
+
e.preventDefault();
|
|
105
|
+
show(0);
|
|
106
|
+
} else if (e.key === "End") {
|
|
107
|
+
e.preventDefault();
|
|
108
|
+
show(slides.length - 1);
|
|
109
|
+
} else if (e.key === "f" || e.key === "F") {
|
|
110
|
+
if (!document.fullscreenElement) {
|
|
111
|
+
document.documentElement.requestFullscreen && document.documentElement.requestFullscreen();
|
|
112
|
+
} else {
|
|
113
|
+
document.exitFullscreen && document.exitFullscreen();
|
|
114
|
+
}
|
|
115
|
+
} else if (e.key === "Escape") {
|
|
116
|
+
document.exitFullscreen && document.exitFullscreen();
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
document.addEventListener("click", () => show(current + 1));
|
|
120
|
+
show(0);
|
|
121
|
+
})();
|
|
122
|
+
`;
|
|
123
|
+
const generateViewerHtml = (context) => {
|
|
124
|
+
const title = context.studio.script.title || "MulmoCast Viewer";
|
|
125
|
+
const slides = collectSlides(context);
|
|
126
|
+
const slidesHtml = slides
|
|
127
|
+
.map((s, i) => {
|
|
128
|
+
const captionHtml = s.caption.trim() ? `<p class="caption">${escapeHtml(s.caption)}</p>` : "";
|
|
129
|
+
const cls = i === 0 ? "slide active" : "slide";
|
|
130
|
+
return ` <section class="${cls}"><img src="${s.dataUri}" alt="Slide ${i + 1}" />${captionHtml}</section>`;
|
|
131
|
+
})
|
|
132
|
+
.join("\n");
|
|
133
|
+
return `<!doctype html>
|
|
134
|
+
<html lang="en">
|
|
135
|
+
<head>
|
|
136
|
+
<meta charset="UTF-8" />
|
|
137
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
138
|
+
<title>${escapeHtml(title)}</title>
|
|
139
|
+
<style>${viewerStyles}</style>
|
|
140
|
+
</head>
|
|
141
|
+
<body>
|
|
142
|
+
<div id="deck">
|
|
143
|
+
${slidesHtml}
|
|
144
|
+
</div>
|
|
145
|
+
<div id="counter"></div>
|
|
146
|
+
<script>${viewerScript}</script>
|
|
147
|
+
</body>
|
|
148
|
+
</html>
|
|
149
|
+
`;
|
|
150
|
+
};
|
|
151
|
+
export const viewerFilePath = (context) => {
|
|
152
|
+
const { studio, fileDirs, lang = "en" } = context;
|
|
153
|
+
const langSuffix = studio.script.lang !== lang ? `_${lang}` : "";
|
|
154
|
+
const filename = `${studio.filename}${langSuffix}_viewer.html`;
|
|
155
|
+
return path.join(fileDirs.outDirPath, filename);
|
|
156
|
+
};
|
|
157
|
+
const generateViewer = (context) => {
|
|
158
|
+
const outputPath = viewerFilePath(context);
|
|
159
|
+
const htmlContent = generateViewerHtml(context);
|
|
160
|
+
fs.writeFileSync(outputPath, htmlContent, "utf8");
|
|
161
|
+
writingMessage(outputPath);
|
|
162
|
+
};
|
|
163
|
+
export const viewer = async (context) => {
|
|
164
|
+
try {
|
|
165
|
+
MulmoStudioContextMethods.setSessionState(context, "viewer", true);
|
|
166
|
+
generateViewer(context);
|
|
167
|
+
MulmoStudioContextMethods.setSessionState(context, "viewer", false, true);
|
|
168
|
+
}
|
|
169
|
+
catch (error) {
|
|
170
|
+
MulmoStudioContextMethods.setSessionState(context, "viewer", false, false);
|
|
171
|
+
throw error;
|
|
172
|
+
}
|
|
173
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Argv } from "yargs";
|
|
2
|
+
export declare const builder: (yargs: Argv) => Argv<{
|
|
3
|
+
o: string | undefined;
|
|
4
|
+
} & {
|
|
5
|
+
b: string | undefined;
|
|
6
|
+
} & {
|
|
7
|
+
l: string | undefined;
|
|
8
|
+
} & {
|
|
9
|
+
f: boolean;
|
|
10
|
+
} & {
|
|
11
|
+
g: boolean;
|
|
12
|
+
} & {
|
|
13
|
+
backup: boolean;
|
|
14
|
+
} & {
|
|
15
|
+
p: string | undefined;
|
|
16
|
+
} & {
|
|
17
|
+
file: string | undefined;
|
|
18
|
+
} & {
|
|
19
|
+
i: string | undefined;
|
|
20
|
+
}>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { images, viewer } from "../../../actions/index.js";
|
|
2
|
+
import { initializeContext, runTranslateIfNeeded } from "../../helpers.js";
|
|
3
|
+
export const handler = async (argv) => {
|
|
4
|
+
const context = await initializeContext(argv);
|
|
5
|
+
if (!context) {
|
|
6
|
+
process.exit(1);
|
|
7
|
+
}
|
|
8
|
+
await runTranslateIfNeeded(context);
|
|
9
|
+
await images(context);
|
|
10
|
+
await viewer(context);
|
|
11
|
+
};
|
package/lib/cli/main.js
CHANGED
|
@@ -12,6 +12,7 @@ import * as pdfCmd from "./commands/pdf/index.js";
|
|
|
12
12
|
import * as markdownCmd from "./commands/markdown/index.js";
|
|
13
13
|
import * as bundleCmd from "./commands/bundle/index.js";
|
|
14
14
|
import * as htmlCmd from "./commands/html/index.js";
|
|
15
|
+
import * as viewerCmd from "./commands/viewer/index.js";
|
|
15
16
|
import * as toolCmd from "./commands/tool/index.js";
|
|
16
17
|
import { GraphAILogger } from "graphai";
|
|
17
18
|
dotenv.config({ quiet: true });
|
|
@@ -42,6 +43,7 @@ export const cliMain = async () => {
|
|
|
42
43
|
.command(markdownCmd)
|
|
43
44
|
.command(bundleCmd)
|
|
44
45
|
.command(htmlCmd)
|
|
46
|
+
.command(viewerCmd)
|
|
45
47
|
.command(toolCmd)
|
|
46
48
|
.demandCommand()
|
|
47
49
|
.strict()
|
package/lib/types/schema.d.ts
CHANGED
|
@@ -10800,6 +10800,7 @@ export declare const mulmoSessionStateSchema: z.ZodObject<{
|
|
|
10800
10800
|
pdf: z.ZodBoolean;
|
|
10801
10801
|
markdown: z.ZodBoolean;
|
|
10802
10802
|
html: z.ZodBoolean;
|
|
10803
|
+
viewer: z.ZodBoolean;
|
|
10803
10804
|
}, z.core.$strip>;
|
|
10804
10805
|
inBeatSession: z.ZodObject<{
|
|
10805
10806
|
audio: z.ZodRecord<z.ZodString, z.ZodBoolean>;
|
package/lib/types/schema.js
CHANGED
package/lib/types/type.d.ts
CHANGED
|
@@ -104,7 +104,7 @@ export type Text2HtmlAgentInfo = {
|
|
|
104
104
|
};
|
|
105
105
|
export type BeatMediaType = "movie" | "image";
|
|
106
106
|
export type StoryToScriptGenerateMode = (typeof storyToScriptGenerateMode)[keyof typeof storyToScriptGenerateMode];
|
|
107
|
-
export type SessionType = "audio" | "image" | "video" | "multiLingual" | "caption" | "pdf" | "markdown" | "html";
|
|
107
|
+
export type SessionType = "audio" | "image" | "video" | "multiLingual" | "caption" | "pdf" | "markdown" | "html" | "viewer";
|
|
108
108
|
export type BeatSessionType = "audio" | "image" | "multiLingual" | "caption" | "movie" | "html" | "imageReference" | "soundEffect" | "lipSync";
|
|
109
109
|
export type SessionProgressEvent = {
|
|
110
110
|
kind: "session";
|
package/lib/utils/context.d.ts
CHANGED
package/lib/utils/context.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mulmocast",
|
|
3
|
-
"version": "2.6.
|
|
3
|
+
"version": "2.6.16",
|
|
4
4
|
"description": "",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.node.js",
|
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
},
|
|
26
26
|
"resolutions": {
|
|
27
27
|
"minimatch": "^10.2.5",
|
|
28
|
-
"tar": "7.5.
|
|
29
|
-
"yauzl": "^3.3.
|
|
28
|
+
"tar": "7.5.15",
|
|
29
|
+
"yauzl": "^3.3.1"
|
|
30
30
|
},
|
|
31
31
|
"bin": {
|
|
32
32
|
"mulmo": "lib/cli/bin.js",
|
|
@@ -108,12 +108,12 @@
|
|
|
108
108
|
"archiver": "^7.0.1",
|
|
109
109
|
"clipboardy": "^5.3.1",
|
|
110
110
|
"dotenv": "^17.4.2",
|
|
111
|
-
"graphai": "^2.0.
|
|
111
|
+
"graphai": "^2.0.17",
|
|
112
112
|
"jsdom": "^29.1.1",
|
|
113
|
-
"marked": "^18.0.
|
|
113
|
+
"marked": "^18.0.4",
|
|
114
114
|
"mulmocast-vision": "^1.0.10",
|
|
115
115
|
"ora": "^9.4.0",
|
|
116
|
-
"puppeteer": "^25.0.
|
|
116
|
+
"puppeteer": "^25.0.4",
|
|
117
117
|
"replicate": "^1.4.0",
|
|
118
118
|
"yaml": "^2.9.0",
|
|
119
119
|
"yargs": "^18.0.0",
|
|
@@ -133,9 +133,9 @@
|
|
|
133
133
|
"eslint-plugin-sonarjs": "^4.0.3",
|
|
134
134
|
"globals": "^17.6.0",
|
|
135
135
|
"prettier": "^3.8.3",
|
|
136
|
-
"tsx": "^4.22.
|
|
136
|
+
"tsx": "^4.22.3",
|
|
137
137
|
"typescript": "6.0.3",
|
|
138
|
-
"typescript-eslint": "^8.59.
|
|
138
|
+
"typescript-eslint": "^8.59.4"
|
|
139
139
|
},
|
|
140
140
|
"engines": {
|
|
141
141
|
"node": ">=22.0.0"
|