@scenar/cli 0.0.2 → 0.0.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/package.json +2 -2
- package/src/__tests__/narrate-command.test.ts +150 -51
- package/src/commands/narrate.d.ts +0 -12
- package/src/commands/narrate.d.ts.map +1 -1
- package/src/commands/narrate.js +164 -49
- package/src/commands/narrate.js.map +1 -1
- package/src/commands/narrate.ts +260 -58
- package/src/index.js +1 -1
- package/src/index.js.map +1 -1
- package/src/index.ts +1 -1
- package/src/tts/types.d.ts +5 -1
- package/src/tts/types.d.ts.map +1 -1
- package/src/tts/types.ts +5 -1
- package/src/util/discover-scenarios.d.ts +12 -0
- package/src/util/discover-scenarios.d.ts.map +1 -0
- package/src/util/discover-scenarios.js +28 -0
- package/src/util/discover-scenarios.js.map +1 -0
- package/src/util/discover-scenarios.ts +30 -0
- package/src/util/load-ts.d.ts +20 -0
- package/src/util/load-ts.d.ts.map +1 -0
- package/src/util/load-ts.js +25 -0
- package/src/util/load-ts.js.map +1 -0
- package/src/util/load-ts.ts +39 -0
- package/src/util/narration-cache.d.ts +24 -0
- package/src/util/narration-cache.d.ts.map +1 -0
- package/src/util/narration-cache.js +51 -0
- package/src/util/narration-cache.js.map +1 -0
- package/src/util/narration-cache.ts +86 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { readFile, writeFile, access } from "node:fs/promises";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
const CACHE_FILENAME = ".narration-cache.json";
|
|
5
|
+
export function computeHash(narration, voice) {
|
|
6
|
+
return createHash("sha256")
|
|
7
|
+
.update(`${voice}\0${narration}`)
|
|
8
|
+
.digest("hex");
|
|
9
|
+
}
|
|
10
|
+
export async function loadCache(outputDir) {
|
|
11
|
+
try {
|
|
12
|
+
const raw = await readFile(join(outputDir, CACHE_FILENAME), "utf-8");
|
|
13
|
+
return JSON.parse(raw);
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export async function saveCache(outputDir, cache) {
|
|
20
|
+
await writeFile(join(outputDir, CACHE_FILENAME), JSON.stringify(cache, null, 2) + "\n");
|
|
21
|
+
}
|
|
22
|
+
export async function fileExists(filePath) {
|
|
23
|
+
try {
|
|
24
|
+
await access(filePath);
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Check whether a step's narration is already cached (matching hash
|
|
33
|
+
* and the MP3 file still exists on disk).
|
|
34
|
+
*/
|
|
35
|
+
export function isCached(cache, stepIndex, hash, voice) {
|
|
36
|
+
if (!cache || cache.voice !== voice)
|
|
37
|
+
return false;
|
|
38
|
+
const entry = cache.steps[stepIndex];
|
|
39
|
+
return entry !== null && entry !== undefined && entry.hash === hash;
|
|
40
|
+
}
|
|
41
|
+
export function getCachedDuration(cache, stepIndex) {
|
|
42
|
+
return cache.steps[stepIndex].durationMs;
|
|
43
|
+
}
|
|
44
|
+
export function buildCacheFile(voice, totalSteps, entries) {
|
|
45
|
+
const steps = Array.from({ length: totalSteps }, () => null);
|
|
46
|
+
for (const [idx, entry] of entries) {
|
|
47
|
+
steps[idx] = entry;
|
|
48
|
+
}
|
|
49
|
+
return { voice, steps };
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=narration-cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"narration-cache.js","sourceRoot":"","sources":["../../../src/util/narration-cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAYjC,MAAM,cAAc,GAAG,uBAAuB,CAAC;AAE/C,MAAM,UAAU,WAAW,CAAC,SAAiB,EAAE,KAAa;IAC1D,OAAO,UAAU,CAAC,QAAQ,CAAC;SACxB,MAAM,CAAC,GAAG,KAAK,KAAK,SAAS,EAAE,CAAC;SAChC,MAAM,CAAC,KAAK,CAAC,CAAC;AACnB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,SAAiB;IAC/C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,EAAE,OAAO,CAAC,CAAC;QACrE,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAc,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,SAAiB,EACjB,KAAgB;IAEhB,MAAM,SAAS,CACb,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,EAC/B,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CACtC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,QAAgB;IAC/C,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC;QACvB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,QAAQ,CACtB,KAAuB,EACvB,SAAiB,EACjB,IAAY,EACZ,KAAa;IAEb,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,KAAK,KAAK;QAAE,OAAO,KAAK,CAAC;IAClD,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IACrC,OAAO,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC;AACtE,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,KAAgB,EAChB,SAAiB;IAEjB,OAAO,KAAK,CAAC,KAAK,CAAC,SAAS,CAAE,CAAC,UAAU,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,cAAc,CAC5B,KAAa,EACb,UAAkB,EAClB,OAA0D;IAE1D,MAAM,KAAK,GAA0B,KAAK,CAAC,IAAI,CAC7C,EAAE,MAAM,EAAE,UAAU,EAAE,EACtB,GAAG,EAAE,CAAC,IAAI,CACX,CAAC;IACF,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,OAAO,EAAE,CAAC;QACnC,KAAK,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IACrB,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;AAC1B,CAAC"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { readFile, writeFile, access } from "node:fs/promises";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
|
|
5
|
+
interface CacheEntry {
|
|
6
|
+
hash: string;
|
|
7
|
+
durationMs: number;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface CacheFile {
|
|
11
|
+
voice: string;
|
|
12
|
+
steps: (CacheEntry | null)[];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const CACHE_FILENAME = ".narration-cache.json";
|
|
16
|
+
|
|
17
|
+
export function computeHash(narration: string, voice: string): string {
|
|
18
|
+
return createHash("sha256")
|
|
19
|
+
.update(`${voice}\0${narration}`)
|
|
20
|
+
.digest("hex");
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function loadCache(outputDir: string): Promise<CacheFile | null> {
|
|
24
|
+
try {
|
|
25
|
+
const raw = await readFile(join(outputDir, CACHE_FILENAME), "utf-8");
|
|
26
|
+
return JSON.parse(raw) as CacheFile;
|
|
27
|
+
} catch {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export async function saveCache(
|
|
33
|
+
outputDir: string,
|
|
34
|
+
cache: CacheFile,
|
|
35
|
+
): Promise<void> {
|
|
36
|
+
await writeFile(
|
|
37
|
+
join(outputDir, CACHE_FILENAME),
|
|
38
|
+
JSON.stringify(cache, null, 2) + "\n",
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export async function fileExists(filePath: string): Promise<boolean> {
|
|
43
|
+
try {
|
|
44
|
+
await access(filePath);
|
|
45
|
+
return true;
|
|
46
|
+
} catch {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Check whether a step's narration is already cached (matching hash
|
|
53
|
+
* and the MP3 file still exists on disk).
|
|
54
|
+
*/
|
|
55
|
+
export function isCached(
|
|
56
|
+
cache: CacheFile | null,
|
|
57
|
+
stepIndex: number,
|
|
58
|
+
hash: string,
|
|
59
|
+
voice: string,
|
|
60
|
+
): boolean {
|
|
61
|
+
if (!cache || cache.voice !== voice) return false;
|
|
62
|
+
const entry = cache.steps[stepIndex];
|
|
63
|
+
return entry !== null && entry !== undefined && entry.hash === hash;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function getCachedDuration(
|
|
67
|
+
cache: CacheFile,
|
|
68
|
+
stepIndex: number,
|
|
69
|
+
): number {
|
|
70
|
+
return cache.steps[stepIndex]!.durationMs;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function buildCacheFile(
|
|
74
|
+
voice: string,
|
|
75
|
+
totalSteps: number,
|
|
76
|
+
entries: Map<number, { hash: string; durationMs: number }>,
|
|
77
|
+
): CacheFile {
|
|
78
|
+
const steps: (CacheEntry | null)[] = Array.from(
|
|
79
|
+
{ length: totalSteps },
|
|
80
|
+
() => null,
|
|
81
|
+
);
|
|
82
|
+
for (const [idx, entry] of entries) {
|
|
83
|
+
steps[idx] = entry;
|
|
84
|
+
}
|
|
85
|
+
return { voice, steps };
|
|
86
|
+
}
|