@tacone/prosey 0.5.0 → 0.6.0
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/bin/prosey +73 -11
- package/package.json +1 -1
- package/src/default-config.toml +17 -1
- package/src/index.ts +75 -11
package/bin/prosey
CHANGED
|
@@ -103291,7 +103291,7 @@ function openInBrowser(htmlPath) {
|
|
|
103291
103291
|
// package.json
|
|
103292
103292
|
var package_default = {
|
|
103293
103293
|
name: "@tacone/prosey",
|
|
103294
|
-
version: "0.
|
|
103294
|
+
version: "0.6.0",
|
|
103295
103295
|
description: "Download YouTube video transcripts from the CLI",
|
|
103296
103296
|
module: "src/index.ts",
|
|
103297
103297
|
type: "module",
|
|
@@ -122284,10 +122284,12 @@ try {
|
|
|
122284
122284
|
const dir2 = cacheDir(videoId, cacheOpts2);
|
|
122285
122285
|
let segments2 = null;
|
|
122286
122286
|
let summary = null;
|
|
122287
|
+
let cachedInfo = null;
|
|
122287
122288
|
startTimer();
|
|
122288
122289
|
if (!noCache) {
|
|
122289
122290
|
const cachedSegments = await readCache(dir2, "transcript.json");
|
|
122290
122291
|
const cachedSummary = await readCache(dir2, "summary.md");
|
|
122292
|
+
cachedInfo = await readCache(dir2, "info.json");
|
|
122291
122293
|
if (cachedSegments && cachedSummary) {
|
|
122292
122294
|
info("Transcript cached");
|
|
122293
122295
|
debug("Cache hit:", dir2);
|
|
@@ -122299,23 +122301,83 @@ try {
|
|
|
122299
122301
|
} else {
|
|
122300
122302
|
debug("Cache skipped (--no-cache)");
|
|
122301
122303
|
}
|
|
122302
|
-
if (!segments2) {
|
|
122303
|
-
info("Fetching transcript...");
|
|
122304
|
-
segments2 = lang ? await fetchTranscript(videoId, { lang }) : await fetchTranscript(videoId);
|
|
122305
|
-
info(`Transcript: ${segments2.length} segments`);
|
|
122306
|
-
await writeCache(dir2, "transcript.json", JSON.stringify(segments2));
|
|
122307
|
-
debug("Cache written: transcript.json");
|
|
122308
|
-
}
|
|
122309
122304
|
const prompt2 = resolveSummarizePrompt(config) ?? "";
|
|
122310
122305
|
if (!prompt2) {
|
|
122311
122306
|
console.error("Error: no prompt configured. Set a prompt in the [summarize] section of your config.");
|
|
122312
122307
|
exitProcess(1);
|
|
122313
122308
|
}
|
|
122314
|
-
|
|
122309
|
+
let structuredContent;
|
|
122310
|
+
if (!segments2) {
|
|
122311
|
+
info("Fetching transcript...");
|
|
122312
|
+
const opts = lang ? { lang, videoDetails: true } : { videoDetails: true };
|
|
122313
|
+
const result = await fetchTranscript(videoId, opts);
|
|
122314
|
+
segments2 = result.segments;
|
|
122315
|
+
const infoJson = JSON.stringify({
|
|
122316
|
+
title: result.videoDetails.title,
|
|
122317
|
+
channel: result.videoDetails.author,
|
|
122318
|
+
description: result.videoDetails.description
|
|
122319
|
+
});
|
|
122320
|
+
cachedInfo = infoJson;
|
|
122321
|
+
const chapterValue = formatChaptersAsJson(extractChapters(result.videoDetails.description));
|
|
122322
|
+
const truncatedInfo = JSON.stringify({
|
|
122323
|
+
title: result.videoDetails.title,
|
|
122324
|
+
channel: result.videoDetails.author,
|
|
122325
|
+
description: result.videoDetails.description.slice(0, 1000)
|
|
122326
|
+
});
|
|
122327
|
+
const transcriptText = toText(segments2, !noDecode);
|
|
122328
|
+
structuredContent = `INFO:
|
|
122329
|
+
${truncatedInfo}
|
|
122330
|
+
|
|
122331
|
+
TEXT:
|
|
122332
|
+
${transcriptText}`;
|
|
122333
|
+
if (dryRun) {
|
|
122334
|
+
await outputText(`${prompt2}
|
|
122335
|
+
|
|
122336
|
+
${structuredContent}
|
|
122337
|
+
`);
|
|
122338
|
+
exitProcess(0);
|
|
122339
|
+
}
|
|
122340
|
+
info(`Transcript: ${segments2.length} segments`);
|
|
122341
|
+
await writeCache(dir2, "transcript.json", JSON.stringify(segments2));
|
|
122342
|
+
await writeCache(dir2, "info.json", infoJson);
|
|
122343
|
+
await writeCache(dir2, "chapters.json", chapterValue);
|
|
122344
|
+
debug("Cache written: transcript.json, info.json, chapters.json");
|
|
122345
|
+
} else {
|
|
122346
|
+
let chapterValue;
|
|
122347
|
+
if (!cachedInfo) {
|
|
122348
|
+
debug("Cache missing info.json, re-fetching video details");
|
|
122349
|
+
const fallbackOpts = lang ? { lang, videoDetails: true } : { videoDetails: true };
|
|
122350
|
+
const fallbackResult = await fetchTranscript(videoId, fallbackOpts);
|
|
122351
|
+
cachedInfo = JSON.stringify({
|
|
122352
|
+
title: fallbackResult.videoDetails.title,
|
|
122353
|
+
channel: fallbackResult.videoDetails.author,
|
|
122354
|
+
description: fallbackResult.videoDetails.description
|
|
122355
|
+
});
|
|
122356
|
+
await writeCache(dir2, "info.json", cachedInfo);
|
|
122357
|
+
chapterValue = formatChaptersAsJson(extractChapters(fallbackResult.videoDetails.description));
|
|
122358
|
+
await writeCache(dir2, "chapters.json", chapterValue);
|
|
122359
|
+
debug("Cache written: info.json, chapters.json");
|
|
122360
|
+
} else {
|
|
122361
|
+
const cachedChapters = await readCache(dir2, "chapters.json");
|
|
122362
|
+
chapterValue = cachedChapters ?? "not available";
|
|
122363
|
+
}
|
|
122364
|
+
const transcriptText = toText(segments2, !noDecode);
|
|
122365
|
+
const cachedInfoObj = JSON.parse(cachedInfo);
|
|
122366
|
+
const truncatedInfo = JSON.stringify({
|
|
122367
|
+
title: cachedInfoObj.title,
|
|
122368
|
+
channel: cachedInfoObj.channel,
|
|
122369
|
+
description: cachedInfoObj.description.slice(0, 1000)
|
|
122370
|
+
});
|
|
122371
|
+
structuredContent = `INFO:
|
|
122372
|
+
${truncatedInfo}
|
|
122373
|
+
|
|
122374
|
+
TEXT:
|
|
122375
|
+
${transcriptText}`;
|
|
122376
|
+
}
|
|
122315
122377
|
if (dryRun) {
|
|
122316
122378
|
await outputText(`${prompt2}
|
|
122317
122379
|
|
|
122318
|
-
${
|
|
122380
|
+
${structuredContent}
|
|
122319
122381
|
`);
|
|
122320
122382
|
exitProcess(0);
|
|
122321
122383
|
}
|
|
@@ -122324,7 +122386,7 @@ ${transcriptText}
|
|
|
122324
122386
|
summary = await summarize({
|
|
122325
122387
|
prompt: prompt2,
|
|
122326
122388
|
command: sumCmd,
|
|
122327
|
-
transcript:
|
|
122389
|
+
transcript: structuredContent,
|
|
122328
122390
|
cwd: dir2
|
|
122329
122391
|
});
|
|
122330
122392
|
info("Summary ready");
|
package/package.json
CHANGED
package/src/default-config.toml
CHANGED
|
@@ -29,7 +29,23 @@ command = "OPENCODE_PERMISSION='{\"read\":\"allow\",\"write\":\"deny\",\"edit\":
|
|
|
29
29
|
# Customize this to change how transcripts are summarized.
|
|
30
30
|
|
|
31
31
|
prompt = """
|
|
32
|
-
Write a comprehensive summary of the following transcription
|
|
32
|
+
Write a comprehensive summary of the following video transcription:
|
|
33
|
+
|
|
34
|
+
Guidelines:
|
|
35
|
+
- use the INFO section data to correct spellings in the text (e.g. Pi vs Pie)
|
|
36
|
+
- use the INFO title value as the main title (h1 header)
|
|
37
|
+
- use the TIMESTAMPS only to understand the structure, don't output time markers
|
|
38
|
+
- content length: aim to be the same range as the original text or more.
|
|
39
|
+
- section titles should be h2 headers
|
|
40
|
+
|
|
41
|
+
Content considerations:
|
|
42
|
+
|
|
43
|
+
- findings should be presented in lists or table
|
|
44
|
+
- flows should be presented in ordered lists
|
|
45
|
+
- elaborations are better in prose
|
|
46
|
+
- when content mixes types within a section, lead with prose and break out lists only for discrete items
|
|
47
|
+
|
|
48
|
+
Only output the summary text without adding anything.
|
|
33
49
|
"""
|
|
34
50
|
|
|
35
51
|
# Command override for summarize. Uncomment to use a different command
|
package/src/index.ts
CHANGED
|
@@ -443,12 +443,14 @@ try {
|
|
|
443
443
|
const dir = cacheDir(videoId, cacheOpts);
|
|
444
444
|
let segments: TranscriptSegment[] | null = null;
|
|
445
445
|
let summary: string | null = null;
|
|
446
|
+
let cachedInfo: string | null = null;
|
|
446
447
|
|
|
447
448
|
startTimer();
|
|
448
449
|
|
|
449
450
|
if (!noCache) {
|
|
450
451
|
const cachedSegments = await readCache(dir, "transcript.json");
|
|
451
452
|
const cachedSummary = await readCache(dir, "summary.md");
|
|
453
|
+
cachedInfo = await readCache(dir, "info.json");
|
|
452
454
|
if (cachedSegments && cachedSummary) {
|
|
453
455
|
info("Transcript cached");
|
|
454
456
|
debug("Cache hit:", dir);
|
|
@@ -461,14 +463,6 @@ try {
|
|
|
461
463
|
debug("Cache skipped (--no-cache)");
|
|
462
464
|
}
|
|
463
465
|
|
|
464
|
-
if (!segments) {
|
|
465
|
-
info("Fetching transcript...");
|
|
466
|
-
segments = lang ? await fetchTranscript(videoId, { lang }) : await fetchTranscript(videoId);
|
|
467
|
-
info(`Transcript: ${segments.length} segments`);
|
|
468
|
-
await writeCache(dir, "transcript.json", JSON.stringify(segments));
|
|
469
|
-
debug("Cache written: transcript.json");
|
|
470
|
-
}
|
|
471
|
-
|
|
472
466
|
const prompt = resolveSummarizePrompt(config) ?? "";
|
|
473
467
|
if (!prompt) {
|
|
474
468
|
console.error(
|
|
@@ -476,10 +470,80 @@ try {
|
|
|
476
470
|
);
|
|
477
471
|
exitProcess(1);
|
|
478
472
|
}
|
|
479
|
-
|
|
473
|
+
|
|
474
|
+
let structuredContent: string;
|
|
475
|
+
|
|
476
|
+
if (!segments) {
|
|
477
|
+
info("Fetching transcript...");
|
|
478
|
+
const opts = lang ? { lang, videoDetails: true as const } : { videoDetails: true as const };
|
|
479
|
+
const result = (await fetchTranscript(videoId, opts)) as {
|
|
480
|
+
videoDetails: VideoDetails;
|
|
481
|
+
segments: TranscriptSegment[];
|
|
482
|
+
};
|
|
483
|
+
segments = result.segments;
|
|
484
|
+
const infoJson = JSON.stringify({
|
|
485
|
+
title: result.videoDetails.title,
|
|
486
|
+
channel: result.videoDetails.author,
|
|
487
|
+
description: result.videoDetails.description,
|
|
488
|
+
});
|
|
489
|
+
cachedInfo = infoJson;
|
|
490
|
+
const chapterValue = formatChaptersAsJson(extractChapters(result.videoDetails.description));
|
|
491
|
+
const truncatedInfo = JSON.stringify({
|
|
492
|
+
title: result.videoDetails.title,
|
|
493
|
+
channel: result.videoDetails.author,
|
|
494
|
+
description: result.videoDetails.description.slice(0, 1000),
|
|
495
|
+
});
|
|
496
|
+
const transcriptText = toText(segments, !noDecode);
|
|
497
|
+
structuredContent = `INFO:\n${truncatedInfo}\n\nTEXT:\n${transcriptText}`;
|
|
498
|
+
|
|
499
|
+
if (dryRun) {
|
|
500
|
+
await outputText(`${prompt}\n\n${structuredContent}\n`);
|
|
501
|
+
exitProcess(0);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
info(`Transcript: ${segments.length} segments`);
|
|
505
|
+
await writeCache(dir, "transcript.json", JSON.stringify(segments));
|
|
506
|
+
await writeCache(dir, "info.json", infoJson);
|
|
507
|
+
await writeCache(dir, "chapters.json", chapterValue);
|
|
508
|
+
debug("Cache written: transcript.json, info.json, chapters.json");
|
|
509
|
+
} else {
|
|
510
|
+
let chapterValue: string;
|
|
511
|
+
if (!cachedInfo) {
|
|
512
|
+
debug("Cache missing info.json, re-fetching video details");
|
|
513
|
+
const fallbackOpts = lang
|
|
514
|
+
? { lang, videoDetails: true as const }
|
|
515
|
+
: { videoDetails: true as const };
|
|
516
|
+
const fallbackResult = (await fetchTranscript(videoId, fallbackOpts)) as {
|
|
517
|
+
videoDetails: VideoDetails;
|
|
518
|
+
segments: TranscriptSegment[];
|
|
519
|
+
};
|
|
520
|
+
cachedInfo = JSON.stringify({
|
|
521
|
+
title: fallbackResult.videoDetails.title,
|
|
522
|
+
channel: fallbackResult.videoDetails.author,
|
|
523
|
+
description: fallbackResult.videoDetails.description,
|
|
524
|
+
});
|
|
525
|
+
await writeCache(dir, "info.json", cachedInfo);
|
|
526
|
+
chapterValue = formatChaptersAsJson(
|
|
527
|
+
extractChapters(fallbackResult.videoDetails.description),
|
|
528
|
+
);
|
|
529
|
+
await writeCache(dir, "chapters.json", chapterValue);
|
|
530
|
+
debug("Cache written: info.json, chapters.json");
|
|
531
|
+
} else {
|
|
532
|
+
const cachedChapters = await readCache(dir, "chapters.json");
|
|
533
|
+
chapterValue = cachedChapters ?? "not available";
|
|
534
|
+
}
|
|
535
|
+
const transcriptText = toText(segments, !noDecode);
|
|
536
|
+
const cachedInfoObj = JSON.parse(cachedInfo);
|
|
537
|
+
const truncatedInfo = JSON.stringify({
|
|
538
|
+
title: cachedInfoObj.title,
|
|
539
|
+
channel: cachedInfoObj.channel,
|
|
540
|
+
description: cachedInfoObj.description.slice(0, 1000),
|
|
541
|
+
});
|
|
542
|
+
structuredContent = `INFO:\n${truncatedInfo}\n\nTEXT:\n${transcriptText}`;
|
|
543
|
+
}
|
|
480
544
|
|
|
481
545
|
if (dryRun) {
|
|
482
|
-
await outputText(`${prompt}\n\n${
|
|
546
|
+
await outputText(`${prompt}\n\n${structuredContent}\n`);
|
|
483
547
|
exitProcess(0);
|
|
484
548
|
}
|
|
485
549
|
|
|
@@ -488,7 +552,7 @@ try {
|
|
|
488
552
|
summary = await summarize({
|
|
489
553
|
prompt,
|
|
490
554
|
command: sumCmd,
|
|
491
|
-
transcript:
|
|
555
|
+
transcript: structuredContent,
|
|
492
556
|
cwd: dir,
|
|
493
557
|
});
|
|
494
558
|
info("Summary ready");
|