@liorium/youtube-omni-mcp 0.2.3 → 0.2.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.
- package/CHANGELOG.md +12 -0
- package/dist/src/core/synthesis.d.ts +50 -0
- package/dist/src/core/synthesis.js +143 -0
- package/dist/src/core/synthesis.js.map +1 -0
- package/dist/src/providers/transcript-provider.d.ts +9 -1
- package/dist/src/providers/transcript-provider.js +194 -5
- package/dist/src/providers/transcript-provider.js.map +1 -1
- package/dist/src/tools/comments.d.ts +11 -2
- package/dist/src/tools/comments.js +3 -1
- package/dist/src/tools/comments.js.map +1 -1
- package/dist/src/tools/planning.d.ts +17 -4
- package/dist/src/tools/planning.js +75 -3
- package/dist/src/tools/planning.js.map +1 -1
- package/dist/src/tools/research.d.ts +4 -0
- package/dist/src/tools/research.js +8 -23
- package/dist/src/tools/research.js.map +1 -1
- package/dist/src/tools/safety.js +1 -1
- package/dist/src/tools/safety.js.map +1 -1
- package/dist/src/tools/transcript.d.ts +11 -2
- package/dist/src/tools/transcript.js +3 -1
- package/dist/src/tools/transcript.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.5 - 2026-05-14
|
|
4
|
+
|
|
5
|
+
- Add deeper read-only synthesis for transcript structure, claim-like moments, hook pattern classification, comment themes, and research briefs.
|
|
6
|
+
- Replace mock comment summarization with actual comment-text analysis for questions, requests, themes, and sentiment signals.
|
|
7
|
+
- Feed transcript hooks and comment signals into planning briefs with recommended angles and content opportunities.
|
|
8
|
+
|
|
9
|
+
## 0.2.4 - 2026-05-14
|
|
10
|
+
|
|
11
|
+
- Replace the transcript placeholder provider with a read-only YouTube timedtext provider.
|
|
12
|
+
- Add resilient `yt-dlp` caption metadata fallback when watch-page caption URLs are missing or stale.
|
|
13
|
+
- Keep transcript calls non-destructive and unavailable-safe when captions cannot be fetched.
|
|
14
|
+
|
|
3
15
|
## 0.2.3 - 2026-05-14
|
|
4
16
|
|
|
5
17
|
- Ensure the published `youtube-omni-mcp` CLI bin is executable after build so `npx -y @liorium/youtube-omni-mcp` can launch the MCP stdio server.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export type HookAnalysis = {
|
|
2
|
+
pattern: string;
|
|
3
|
+
reasons: string[];
|
|
4
|
+
};
|
|
5
|
+
export type CommentTheme = {
|
|
6
|
+
theme: string;
|
|
7
|
+
intent: string;
|
|
8
|
+
opportunity: string;
|
|
9
|
+
};
|
|
10
|
+
export declare function splitSentences(text: string): string[];
|
|
11
|
+
export declare function analyzeHookPattern(hook: string): HookAnalysis;
|
|
12
|
+
export declare function extractTranscriptStructure(text: string, includeClaims?: boolean): {
|
|
13
|
+
hook: string;
|
|
14
|
+
cta: string;
|
|
15
|
+
outline: {
|
|
16
|
+
section: string;
|
|
17
|
+
text: string;
|
|
18
|
+
purpose: string;
|
|
19
|
+
}[];
|
|
20
|
+
claims: {
|
|
21
|
+
text: string;
|
|
22
|
+
type: string;
|
|
23
|
+
evidenceStrength: string;
|
|
24
|
+
}[];
|
|
25
|
+
scriptPatterns: string[];
|
|
26
|
+
hookAnalysis: HookAnalysis;
|
|
27
|
+
};
|
|
28
|
+
export declare function classifyComment(text: string): CommentTheme;
|
|
29
|
+
export declare function summarizeCommentSet(comments: Array<{
|
|
30
|
+
text?: string;
|
|
31
|
+
likeCount?: number;
|
|
32
|
+
}>, includeQuestions?: boolean, includeRequests?: boolean): {
|
|
33
|
+
summary: string;
|
|
34
|
+
questions: string[];
|
|
35
|
+
contentRequests: string[];
|
|
36
|
+
themes: {
|
|
37
|
+
theme: string;
|
|
38
|
+
intent: string;
|
|
39
|
+
opportunity: string;
|
|
40
|
+
count: number;
|
|
41
|
+
examples: string[];
|
|
42
|
+
totalLikes: number;
|
|
43
|
+
}[];
|
|
44
|
+
sentimentSignal: {
|
|
45
|
+
positiveCount: number;
|
|
46
|
+
concernCount: number;
|
|
47
|
+
mixed: boolean;
|
|
48
|
+
dominant: string;
|
|
49
|
+
};
|
|
50
|
+
};
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
export function splitSentences(text) {
|
|
2
|
+
return text
|
|
3
|
+
.replace(/\s+/g, ' ')
|
|
4
|
+
.split(/(?<=[.!?])\s+/)
|
|
5
|
+
.map((sentence) => sentence.trim())
|
|
6
|
+
.filter(Boolean);
|
|
7
|
+
}
|
|
8
|
+
export function analyzeHookPattern(hook) {
|
|
9
|
+
const lower = hook.toLowerCase();
|
|
10
|
+
const reasons = [];
|
|
11
|
+
if (/^\s*(what|why|how|can|could|would|is|are|do|does|did)\b/i.test(hook) || hook.includes('?')) {
|
|
12
|
+
reasons.push('opens with a question');
|
|
13
|
+
}
|
|
14
|
+
if (lower.includes('secret') || lower.includes('hidden') || lower.includes('nobody') || lower.includes('what if')) {
|
|
15
|
+
reasons.push('creates a curiosity gap');
|
|
16
|
+
}
|
|
17
|
+
if (/\b(\d+|days?|steps?|experiments?|case study|rebuilt|result)\b/i.test(hook)) {
|
|
18
|
+
reasons.push('promises a concrete result');
|
|
19
|
+
}
|
|
20
|
+
if (lower.includes('but') || lower.includes('cost') || lower.includes('danger') || lower.includes('problem') || lower.includes('failure')) {
|
|
21
|
+
reasons.push('frames conflict or stakes');
|
|
22
|
+
}
|
|
23
|
+
let pattern = 'statement-hook';
|
|
24
|
+
if (reasons.includes('opens with a question') && reasons.includes('creates a curiosity gap'))
|
|
25
|
+
pattern = 'question-hook';
|
|
26
|
+
else if (reasons.includes('promises a concrete result'))
|
|
27
|
+
pattern = 'challenge-result';
|
|
28
|
+
else if (reasons.includes('creates a curiosity gap'))
|
|
29
|
+
pattern = 'curiosity-gap';
|
|
30
|
+
else if (reasons.includes('frames conflict or stakes'))
|
|
31
|
+
pattern = 'conflict-stakes';
|
|
32
|
+
else if (reasons.includes('opens with a question'))
|
|
33
|
+
pattern = 'question-hook';
|
|
34
|
+
return { pattern, reasons: reasons.length ? reasons : ['states the topic directly'] };
|
|
35
|
+
}
|
|
36
|
+
export function extractTranscriptStructure(text, includeClaims = true) {
|
|
37
|
+
const sentences = splitSentences(text);
|
|
38
|
+
const hookText = sentences[0] ?? '';
|
|
39
|
+
const ctaSentence = [...sentences].reverse().find((sentence) => /\b(subscribe|comment|download|share|follow|watch next|checklist|worksheet)\b/i.test(sentence)) ?? '';
|
|
40
|
+
const hookAnalysis = analyzeHookPattern(hookText);
|
|
41
|
+
const midpoint = Math.max(1, Math.floor(sentences.length / 2));
|
|
42
|
+
const outline = [
|
|
43
|
+
{ section: 'hook', text: hookText, purpose: 'capture attention and frame the promise' },
|
|
44
|
+
{ section: 'development', text: sentences.slice(1, midpoint).join(' '), purpose: 'build context and evidence' },
|
|
45
|
+
{ section: 'payoff', text: sentences.slice(midpoint, Math.max(midpoint, sentences.length - 1)).join(' '), purpose: 'deliver insight or framework' },
|
|
46
|
+
{ section: 'cta', text: ctaSentence, purpose: 'ask for the next audience action' }
|
|
47
|
+
].filter((section) => section.text.length > 0);
|
|
48
|
+
const claimPatterns = /\b(claim|found|shows|proves|because|therefore|this matters|the first|the second|researchers|study|data)\b/i;
|
|
49
|
+
const claims = includeClaims
|
|
50
|
+
? sentences
|
|
51
|
+
.filter((sentence) => claimPatterns.test(sentence))
|
|
52
|
+
.slice(0, 8)
|
|
53
|
+
.map((sentence) => ({ text: sentence, type: 'claim', evidenceStrength: /\b(found|researchers|study|data|experiments?)\b/i.test(sentence) ? 'medium' : 'low' }))
|
|
54
|
+
: [];
|
|
55
|
+
const scriptPatterns = [...new Set([
|
|
56
|
+
hookAnalysis.pattern,
|
|
57
|
+
ctaSentence ? 'explicit-cta' : 'soft-cta',
|
|
58
|
+
claims.length > 0 ? 'evidence-led' : 'narrative-led'
|
|
59
|
+
])];
|
|
60
|
+
return {
|
|
61
|
+
hook: hookText,
|
|
62
|
+
cta: ctaSentence,
|
|
63
|
+
outline,
|
|
64
|
+
claims,
|
|
65
|
+
scriptPatterns,
|
|
66
|
+
hookAnalysis
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
export function classifyComment(text) {
|
|
70
|
+
const lower = text.toLowerCase();
|
|
71
|
+
if (/\b(can you|could you|please|make|share|template|examples?|follow-up|more)\b/i.test(text)) {
|
|
72
|
+
return {
|
|
73
|
+
theme: 'content requests',
|
|
74
|
+
intent: 'request',
|
|
75
|
+
opportunity: 'Create a follow-up asset, checklist, or example-driven episode.'
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
if (text.includes('?') || /\b(how|why|what|which|confused|setup|trust|cost|problem)\b/i.test(text)) {
|
|
79
|
+
return {
|
|
80
|
+
theme: 'audience confusion',
|
|
81
|
+
intent: 'confusion',
|
|
82
|
+
opportunity: 'Add a clearer explainer segment that answers setup, cost, and trust questions.'
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
if (/\b(great|excellent|helpful|love|amazing|thanks|good)\b/i.test(text)) {
|
|
86
|
+
return {
|
|
87
|
+
theme: 'positive feedback',
|
|
88
|
+
intent: 'praise',
|
|
89
|
+
opportunity: 'Reuse the praised framing and turn it into a repeatable series format.'
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
if (/\b(wrong|bad|hate|danger|concern|scary|risk)\b/i.test(lower)) {
|
|
93
|
+
return {
|
|
94
|
+
theme: 'concerns and objections',
|
|
95
|
+
intent: 'concern',
|
|
96
|
+
opportunity: 'Address objections directly with evidence and counterexamples.'
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
theme: 'general reaction',
|
|
101
|
+
intent: 'reaction',
|
|
102
|
+
opportunity: 'Mine representative reactions for framing language.'
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
export function summarizeCommentSet(comments, includeQuestions = true, includeRequests = true) {
|
|
106
|
+
const texts = comments.map((comment) => String(comment.text ?? '').trim()).filter(Boolean);
|
|
107
|
+
const grouped = new Map();
|
|
108
|
+
let positiveCount = 0;
|
|
109
|
+
let concernCount = 0;
|
|
110
|
+
for (const comment of comments) {
|
|
111
|
+
const text = String(comment.text ?? '').trim();
|
|
112
|
+
if (!text)
|
|
113
|
+
continue;
|
|
114
|
+
const classification = classifyComment(text);
|
|
115
|
+
if (classification.intent === 'praise')
|
|
116
|
+
positiveCount += 1;
|
|
117
|
+
if (classification.intent === 'concern' || classification.intent === 'confusion')
|
|
118
|
+
concernCount += 1;
|
|
119
|
+
const existing = grouped.get(classification.theme) ?? { ...classification, count: 0, examples: [], totalLikes: 0 };
|
|
120
|
+
existing.count += 1;
|
|
121
|
+
existing.totalLikes += Number(comment.likeCount ?? 0);
|
|
122
|
+
if (existing.examples.length < 3)
|
|
123
|
+
existing.examples.push(text);
|
|
124
|
+
grouped.set(classification.theme, existing);
|
|
125
|
+
}
|
|
126
|
+
const themes = [...grouped.values()].sort((a, b) => b.count - a.count || b.totalLikes - a.totalLikes);
|
|
127
|
+
const questions = includeQuestions ? texts.filter((text) => text.includes('?') || /\b(how|why|what|which)\b/i.test(text)).slice(0, 10) : [];
|
|
128
|
+
const contentRequests = includeRequests ? texts.filter((text) => /\b(can you|could you|please|make|share|template|examples?|follow-up|more)\b/i.test(text)).slice(0, 10) : [];
|
|
129
|
+
const topTheme = themes[0]?.theme ?? 'no clear theme';
|
|
130
|
+
return {
|
|
131
|
+
summary: `${texts.length} comments analyzed. Top signal: ${topTheme}. ${questions.length} questions and ${contentRequests.length} requests detected.`,
|
|
132
|
+
questions,
|
|
133
|
+
contentRequests,
|
|
134
|
+
themes,
|
|
135
|
+
sentimentSignal: {
|
|
136
|
+
positiveCount,
|
|
137
|
+
concernCount,
|
|
138
|
+
mixed: positiveCount > 0 && concernCount > 0,
|
|
139
|
+
dominant: concernCount > positiveCount ? 'concern' : positiveCount > 0 ? 'positive' : 'neutral'
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=synthesis.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"synthesis.js","sourceRoot":"","sources":["../../../src/core/synthesis.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import type { ProviderHealth, YoutubeOmniProvider } from './types.js';
|
|
2
|
+
type FetchLike = typeof fetch;
|
|
3
|
+
type YtDlpMetadataLoader = (videoId: string, lang: string) => Promise<any | undefined>;
|
|
2
4
|
export declare class TranscriptProvider implements YoutubeOmniProvider {
|
|
3
5
|
id: string;
|
|
4
6
|
name: string;
|
|
5
7
|
authTier: "none";
|
|
6
8
|
capabilities: string[];
|
|
9
|
+
private readonly fetchImpl;
|
|
10
|
+
private readonly loadYtDlpMetadata;
|
|
11
|
+
constructor(fetchImpl?: FetchLike, loadYtDlpMetadata?: YtDlpMetadataLoader);
|
|
7
12
|
isConfigured(): boolean;
|
|
8
13
|
healthCheck(): Promise<ProviderHealth>;
|
|
14
|
+
private fetchTrackText;
|
|
15
|
+
private fetchTranscript;
|
|
9
16
|
getTranscriptSegments(input: {
|
|
10
17
|
videoIds: string[];
|
|
11
18
|
lang: string;
|
|
@@ -17,7 +24,7 @@ export declare class TranscriptProvider implements YoutubeOmniProvider {
|
|
|
17
24
|
format: "key_segments";
|
|
18
25
|
intro: string;
|
|
19
26
|
outro: string;
|
|
20
|
-
availability:
|
|
27
|
+
availability: "available" | "unavailable";
|
|
21
28
|
}[];
|
|
22
29
|
}>;
|
|
23
30
|
getTranscriptFullText(input: {
|
|
@@ -31,3 +38,4 @@ export declare class TranscriptProvider implements YoutubeOmniProvider {
|
|
|
31
38
|
truncated: boolean;
|
|
32
39
|
}>;
|
|
33
40
|
}
|
|
41
|
+
export {};
|
|
@@ -1,17 +1,206 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
function normalizeTranscriptText(text) {
|
|
3
|
+
return text
|
|
4
|
+
.replace(/\s+/g, ' ')
|
|
5
|
+
.replace(/\s+([,.!?;:])/g, '$1')
|
|
6
|
+
.trim();
|
|
7
|
+
}
|
|
8
|
+
function stripJsonAssignment(script, marker) {
|
|
9
|
+
const start = script.indexOf(marker);
|
|
10
|
+
if (start < 0)
|
|
11
|
+
return undefined;
|
|
12
|
+
const jsonStart = script.indexOf('{', start + marker.length);
|
|
13
|
+
if (jsonStart < 0)
|
|
14
|
+
return undefined;
|
|
15
|
+
let depth = 0;
|
|
16
|
+
let inString = false;
|
|
17
|
+
let escaped = false;
|
|
18
|
+
for (let i = jsonStart; i < script.length; i += 1) {
|
|
19
|
+
const char = script[i];
|
|
20
|
+
if (inString) {
|
|
21
|
+
if (escaped) {
|
|
22
|
+
escaped = false;
|
|
23
|
+
}
|
|
24
|
+
else if (char === '\\') {
|
|
25
|
+
escaped = true;
|
|
26
|
+
}
|
|
27
|
+
else if (char === '"') {
|
|
28
|
+
inString = false;
|
|
29
|
+
}
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
if (char === '"') {
|
|
33
|
+
inString = true;
|
|
34
|
+
}
|
|
35
|
+
else if (char === '{') {
|
|
36
|
+
depth += 1;
|
|
37
|
+
}
|
|
38
|
+
else if (char === '}') {
|
|
39
|
+
depth -= 1;
|
|
40
|
+
if (depth === 0)
|
|
41
|
+
return script.slice(jsonStart, i + 1);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
function parsePlayerResponse(html) {
|
|
47
|
+
const raw = stripJsonAssignment(html, 'ytInitialPlayerResponse');
|
|
48
|
+
if (!raw)
|
|
49
|
+
return undefined;
|
|
50
|
+
try {
|
|
51
|
+
return JSON.parse(raw);
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function trackLanguageMatches(track, lang) {
|
|
58
|
+
if (track.languageCode === lang)
|
|
59
|
+
return true;
|
|
60
|
+
const base = lang.split('-')[0];
|
|
61
|
+
return track.languageCode === base || track.vssId === `.${lang}` || track.vssId === `a.${lang}` || track.vssId === `.${base}` || track.vssId === `a.${base}`;
|
|
62
|
+
}
|
|
63
|
+
function chooseCaptionTrack(tracks, lang) {
|
|
64
|
+
return tracks.find((track) => trackLanguageMatches(track, lang))
|
|
65
|
+
?? tracks.find((track) => trackLanguageMatches(track, 'en'))
|
|
66
|
+
?? tracks[0];
|
|
67
|
+
}
|
|
68
|
+
function timedTextUrl(baseUrl) {
|
|
69
|
+
const url = new URL(baseUrl);
|
|
70
|
+
url.searchParams.set('fmt', 'json3');
|
|
71
|
+
return url.toString();
|
|
72
|
+
}
|
|
73
|
+
function chooseYtDlpCaption(metadata, lang) {
|
|
74
|
+
const subtitles = metadata?.subtitles ?? {};
|
|
75
|
+
const automaticCaptions = metadata?.automatic_captions ?? {};
|
|
76
|
+
const base = lang.split('-')[0];
|
|
77
|
+
const tracks = subtitles[lang] ?? subtitles[base] ?? automaticCaptions[lang] ?? automaticCaptions[base];
|
|
78
|
+
if (!Array.isArray(tracks))
|
|
79
|
+
return undefined;
|
|
80
|
+
return tracks.find((track) => track?.ext === 'json3') ?? tracks.find((track) => typeof track?.url === 'string');
|
|
81
|
+
}
|
|
82
|
+
async function defaultYtDlpMetadata(videoId, lang) {
|
|
83
|
+
return new Promise((resolve) => {
|
|
84
|
+
const child = execFile('yt-dlp', [
|
|
85
|
+
'--skip-download',
|
|
86
|
+
'--write-auto-subs',
|
|
87
|
+
'--write-subs',
|
|
88
|
+
'--sub-lang', lang,
|
|
89
|
+
'--sub-format', 'json3/vtt/srv3/best',
|
|
90
|
+
'--dump-json',
|
|
91
|
+
`https://www.youtube.com/watch?v=${videoId}`
|
|
92
|
+
], { timeout: 30000, maxBuffer: 8 * 1024 * 1024 }, (error, stdout) => {
|
|
93
|
+
if (error || !stdout.trim()) {
|
|
94
|
+
resolve(undefined);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
try {
|
|
98
|
+
resolve(JSON.parse(stdout));
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
resolve(undefined);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
child.stdin?.end();
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
function textFromJson3(data) {
|
|
108
|
+
const chunks = [];
|
|
109
|
+
for (const event of data?.events ?? []) {
|
|
110
|
+
for (const segment of event?.segs ?? []) {
|
|
111
|
+
if (typeof segment?.utf8 === 'string')
|
|
112
|
+
chunks.push(segment.utf8);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return normalizeTranscriptText(chunks.join(''));
|
|
116
|
+
}
|
|
117
|
+
function truncate(text, maxChars) {
|
|
118
|
+
if (text.length <= maxChars)
|
|
119
|
+
return { text, truncated: false };
|
|
120
|
+
return { text: text.slice(0, maxChars), truncated: true };
|
|
121
|
+
}
|
|
122
|
+
function keySegments(text) {
|
|
123
|
+
if (!text)
|
|
124
|
+
return { intro: '', outro: '' };
|
|
125
|
+
const intro = text.slice(0, 700).trim();
|
|
126
|
+
const outro = text.slice(Math.max(0, text.length - 700)).trim();
|
|
127
|
+
return { intro, outro };
|
|
128
|
+
}
|
|
1
129
|
export class TranscriptProvider {
|
|
2
|
-
id = '
|
|
3
|
-
name = 'Transcript
|
|
130
|
+
id = 'youtube_timedtext';
|
|
131
|
+
name = 'YouTube Timed Text Transcript Provider';
|
|
4
132
|
authTier = 'none';
|
|
5
133
|
capabilities = ['transcript'];
|
|
134
|
+
fetchImpl;
|
|
135
|
+
loadYtDlpMetadata;
|
|
136
|
+
constructor(fetchImpl = fetch, loadYtDlpMetadata = defaultYtDlpMetadata) {
|
|
137
|
+
this.fetchImpl = fetchImpl;
|
|
138
|
+
this.loadYtDlpMetadata = loadYtDlpMetadata;
|
|
139
|
+
}
|
|
6
140
|
isConfigured() { return true; }
|
|
7
141
|
async healthCheck() {
|
|
8
|
-
return { provider: this.id, configured: true, authTier: this.authTier, capabilities: this.capabilities, warnings: [
|
|
142
|
+
return { provider: this.id, configured: true, authTier: this.authTier, capabilities: this.capabilities, warnings: [] };
|
|
143
|
+
}
|
|
144
|
+
async fetchTrackText(trackUrl) {
|
|
145
|
+
const transcriptResponse = await this.fetchImpl(trackUrl);
|
|
146
|
+
if (!transcriptResponse.ok)
|
|
147
|
+
return '';
|
|
148
|
+
const data = await transcriptResponse.json();
|
|
149
|
+
return textFromJson3(data);
|
|
150
|
+
}
|
|
151
|
+
async fetchTranscript(videoId, lang) {
|
|
152
|
+
try {
|
|
153
|
+
const watchUrl = `https://www.youtube.com/watch?v=${encodeURIComponent(videoId)}&hl=${encodeURIComponent(lang)}`;
|
|
154
|
+
const watchResponse = await this.fetchImpl(watchUrl);
|
|
155
|
+
let trackUrl;
|
|
156
|
+
if (watchResponse.ok) {
|
|
157
|
+
const html = await watchResponse.text();
|
|
158
|
+
const playerResponse = parsePlayerResponse(html);
|
|
159
|
+
const tracks = playerResponse?.captions?.playerCaptionsTracklistRenderer?.captionTracks ?? [];
|
|
160
|
+
const track = chooseCaptionTrack(tracks, lang);
|
|
161
|
+
if (track?.baseUrl)
|
|
162
|
+
trackUrl = timedTextUrl(track.baseUrl);
|
|
163
|
+
}
|
|
164
|
+
if (!trackUrl) {
|
|
165
|
+
const metadata = await this.loadYtDlpMetadata(videoId, lang);
|
|
166
|
+
const ytDlpTrack = chooseYtDlpCaption(metadata, lang);
|
|
167
|
+
if (ytDlpTrack?.url)
|
|
168
|
+
trackUrl = timedTextUrl(ytDlpTrack.url);
|
|
169
|
+
}
|
|
170
|
+
if (!trackUrl)
|
|
171
|
+
return { text: '', availability: 'unavailable' };
|
|
172
|
+
let text = await this.fetchTrackText(trackUrl);
|
|
173
|
+
if (!text) {
|
|
174
|
+
const metadata = await this.loadYtDlpMetadata(videoId, lang);
|
|
175
|
+
const ytDlpTrack = chooseYtDlpCaption(metadata, lang);
|
|
176
|
+
if (ytDlpTrack?.url)
|
|
177
|
+
text = await this.fetchTrackText(timedTextUrl(ytDlpTrack.url));
|
|
178
|
+
}
|
|
179
|
+
return { text, availability: text ? 'available' : 'unavailable' };
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
return { text: '', availability: 'unavailable' };
|
|
183
|
+
}
|
|
9
184
|
}
|
|
10
185
|
async getTranscriptSegments(input) {
|
|
11
|
-
|
|
186
|
+
const transcripts = await Promise.all(input.videoIds.map(async (videoId) => {
|
|
187
|
+
const result = await this.fetchTranscript(videoId, input.lang);
|
|
188
|
+
const segments = keySegments(result.text);
|
|
189
|
+
return {
|
|
190
|
+
videoId,
|
|
191
|
+
language: input.lang,
|
|
192
|
+
format: input.format,
|
|
193
|
+
intro: segments.intro,
|
|
194
|
+
outro: segments.outro,
|
|
195
|
+
availability: result.availability
|
|
196
|
+
};
|
|
197
|
+
}));
|
|
198
|
+
return { transcripts };
|
|
12
199
|
}
|
|
13
200
|
async getTranscriptFullText(input) {
|
|
14
|
-
|
|
201
|
+
const result = await this.fetchTranscript(input.videoId, input.lang);
|
|
202
|
+
const capped = truncate(result.text, input.maxChars);
|
|
203
|
+
return { videoId: input.videoId, language: input.lang, text: capped.text, truncated: capped.truncated };
|
|
15
204
|
}
|
|
16
205
|
}
|
|
17
206
|
//# sourceMappingURL=transcript-provider.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transcript-provider.js","sourceRoot":"","sources":["../../../src/providers/transcript-provider.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"transcript-provider.js","sourceRoot":"","sources":["../../../src/providers/transcript-provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,9 +7,18 @@ export declare function summarizeComments(input: unknown, registry: ProviderRegi
|
|
|
7
7
|
summary: string;
|
|
8
8
|
questions: string[];
|
|
9
9
|
contentRequests: string[];
|
|
10
|
+
themes: {
|
|
11
|
+
theme: string;
|
|
12
|
+
intent: string;
|
|
13
|
+
opportunity: string;
|
|
14
|
+
count: number;
|
|
15
|
+
examples: string[];
|
|
16
|
+
totalLikes: number;
|
|
17
|
+
}[];
|
|
10
18
|
sentimentSignal: {
|
|
11
|
-
|
|
12
|
-
|
|
19
|
+
positiveCount: number;
|
|
20
|
+
concernCount: number;
|
|
13
21
|
mixed: boolean;
|
|
22
|
+
dominant: string;
|
|
14
23
|
};
|
|
15
24
|
}>>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { makeEnvelope } from '../core/envelope.js';
|
|
2
|
+
import { summarizeCommentSet } from '../core/synthesis.js';
|
|
2
3
|
import { getCommentsSchema, summarizeCommentsSchema } from '../schemas/comments.js';
|
|
3
4
|
export async function getVideoComments(input, registry) {
|
|
4
5
|
const parsed = getCommentsSchema.parse(input);
|
|
@@ -10,6 +11,7 @@ export async function summarizeComments(input, registry) {
|
|
|
10
11
|
const parsed = summarizeCommentsSchema.parse(input);
|
|
11
12
|
const provider = registry.requireCapability('comments');
|
|
12
13
|
const comments = await provider.getVideoComments({ videoId: parsed.videoId, maxResults: parsed.maxComments, maxReplies: 0 });
|
|
13
|
-
|
|
14
|
+
const data = summarizeCommentSet(comments.comments, parsed.includeQuestions, parsed.includeRequests);
|
|
15
|
+
return makeEnvelope({ tool: 'youtube.comments.summarize', provider: provider.id, authTier: provider.authTier, data, warnings: ['Sentiment and themes are heuristic estimates, not facts.'] });
|
|
14
16
|
}
|
|
15
17
|
//# sourceMappingURL=comments.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"comments.js","sourceRoot":"","sources":["../../../src/tools/comments.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"comments.js","sourceRoot":"","sources":["../../../src/tools/comments.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAE3D,OAAO,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAEpF,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,KAAc,EAAE,QAA0B;IAC/E,MAAM,MAAM,GAAG,iBAAiB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC9C,MAAM,QAAQ,GAAG,QAAQ,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC;IACxD,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,gBAAiB,CAAC,MAAM,CAAC,CAAC;IACtD,OAAO,YAAY,CAAC,EAAE,IAAI,EAAE,sBAAsB,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE,EAAE,QAAQ,EAAE,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,6DAA6D,CAAC,EAAE,CAAC,CAAC;AAC7L,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,KAAc,EAAE,QAA0B;IAChF,MAAM,MAAM,GAAG,uBAAuB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACpD,MAAM,QAAQ,GAAG,QAAQ,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC;IACxD,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,gBAAiB,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,UAAU,EAAE,MAAM,CAAC,WAAW,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC,CAAC;IAC9H,MAAM,IAAI,GAAG,mBAAmB,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,gBAAgB,EAAE,MAAM,CAAC,eAAe,CAAC,CAAC;IACrG,OAAO,YAAY,CAAC,EAAE,IAAI,EAAE,4BAA4B,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE,EAAE,QAAQ,EAAE,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,0DAA0D,CAAC,EAAE,CAAC,CAAC;AAChM,CAAC"}
|
|
@@ -3,11 +3,24 @@ export declare function generateResearchBrief(input: unknown, registry: Provider
|
|
|
3
3
|
brief: {
|
|
4
4
|
topic: string;
|
|
5
5
|
benchmarkVideos: any[];
|
|
6
|
-
benchmarkChannels:
|
|
6
|
+
benchmarkChannels: {
|
|
7
|
+
channelId: any;
|
|
8
|
+
}[];
|
|
7
9
|
titlePatterns: string[];
|
|
8
|
-
hookPatterns:
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
hookPatterns: {
|
|
11
|
+
pattern: string;
|
|
12
|
+
example: string;
|
|
13
|
+
videoId: string;
|
|
14
|
+
reasons: string[];
|
|
15
|
+
}[];
|
|
16
|
+
audienceQuestions: string[];
|
|
17
|
+
contentOpportunities: any[];
|
|
18
|
+
recommendedAngles: {
|
|
19
|
+
angle: string;
|
|
20
|
+
evidence: any[];
|
|
21
|
+
rationale: string;
|
|
22
|
+
}[];
|
|
23
|
+
commentThemes: any[];
|
|
11
24
|
risks: string[];
|
|
12
25
|
};
|
|
13
26
|
}>>;
|
|
@@ -1,9 +1,81 @@
|
|
|
1
1
|
import { makeEnvelope } from '../core/envelope.js';
|
|
2
|
+
import { analyzeHookPattern, summarizeCommentSet } from '../core/synthesis.js';
|
|
2
3
|
import { researchBriefSchema } from '../schemas/planning.js';
|
|
4
|
+
function unique(items) {
|
|
5
|
+
return [...new Set(items)];
|
|
6
|
+
}
|
|
7
|
+
function angleFromTitle(title, topic, index) {
|
|
8
|
+
return title?.trim() || `${topic} angle ${index + 1}`;
|
|
9
|
+
}
|
|
3
10
|
export async function generateResearchBrief(input, registry) {
|
|
4
11
|
const parsed = researchBriefSchema.parse(input);
|
|
5
|
-
const
|
|
6
|
-
const videos = await
|
|
7
|
-
|
|
12
|
+
const searchProvider = registry.requireCapability('search');
|
|
13
|
+
const videos = await searchProvider.searchVideos({ query: parsed.topic, maxResults: parsed.sampleSize });
|
|
14
|
+
const benchmarkVideos = videos.videos;
|
|
15
|
+
const videoIds = benchmarkVideos.map((video) => video.videoId).filter(Boolean).slice(0, 5);
|
|
16
|
+
let hookPatterns = [];
|
|
17
|
+
if (parsed.includeTranscripts && videoIds.length > 0) {
|
|
18
|
+
try {
|
|
19
|
+
const transcriptProvider = registry.requireCapability('transcript');
|
|
20
|
+
const segments = await transcriptProvider.getTranscriptSegments({ videoIds, lang: 'en', format: 'key_segments' });
|
|
21
|
+
hookPatterns = segments.transcripts
|
|
22
|
+
.filter((transcript) => transcript.intro)
|
|
23
|
+
.map((transcript) => {
|
|
24
|
+
const analysis = analyzeHookPattern(transcript.intro);
|
|
25
|
+
return { pattern: analysis.pattern, example: transcript.intro, videoId: transcript.videoId, reasons: analysis.reasons };
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
hookPatterns = [];
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
let audienceQuestions = [];
|
|
33
|
+
let contentRequests = [];
|
|
34
|
+
let commentThemes = [];
|
|
35
|
+
if (parsed.includeComments && videoIds[0]) {
|
|
36
|
+
try {
|
|
37
|
+
const commentsProvider = registry.requireCapability('comments');
|
|
38
|
+
const comments = await commentsProvider.getVideoComments({ videoId: videoIds[0], maxResults: 50, maxReplies: 0 });
|
|
39
|
+
const summary = summarizeCommentSet(comments.comments, true, true);
|
|
40
|
+
audienceQuestions = summary.questions;
|
|
41
|
+
contentRequests = summary.contentRequests;
|
|
42
|
+
commentThemes = summary.themes;
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
audienceQuestions = [];
|
|
46
|
+
contentRequests = [];
|
|
47
|
+
commentThemes = [];
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const recommendedAngles = benchmarkVideos.slice(0, 5).map((video, index) => ({
|
|
51
|
+
angle: angleFromTitle(video.title, parsed.topic, index),
|
|
52
|
+
evidence: [video.videoId].filter(Boolean),
|
|
53
|
+
rationale: index === 0 ? 'Lead with the strongest benchmark title pattern and validate with hooks/comments.' : 'Use as a secondary format test backed by benchmark discovery.'
|
|
54
|
+
}));
|
|
55
|
+
const contentOpportunities = unique([
|
|
56
|
+
...contentRequests.map((request) => `Turn audience request into follow-up: ${request}`),
|
|
57
|
+
...commentThemes.slice(0, 3).map((theme) => theme.opportunity),
|
|
58
|
+
...(hookPatterns[0] ? [`Adapt ${hookPatterns[0].pattern} opening: ${hookPatterns[0].example.slice(0, 120)}`] : [])
|
|
59
|
+
].filter(Boolean));
|
|
60
|
+
return makeEnvelope({
|
|
61
|
+
tool: 'youtube.planning.generate_research_brief',
|
|
62
|
+
provider: searchProvider.id,
|
|
63
|
+
authTier: searchProvider.authTier,
|
|
64
|
+
data: {
|
|
65
|
+
brief: {
|
|
66
|
+
topic: parsed.topic,
|
|
67
|
+
benchmarkVideos,
|
|
68
|
+
benchmarkChannels: unique(benchmarkVideos.map((video) => video.channelId).filter(Boolean)).map((channelId) => ({ channelId })),
|
|
69
|
+
titlePatterns: ['clear promise + concrete payoff', 'specific topic + stakes', 'case-study framing'],
|
|
70
|
+
hookPatterns,
|
|
71
|
+
audienceQuestions,
|
|
72
|
+
contentOpportunities,
|
|
73
|
+
recommendedAngles,
|
|
74
|
+
commentThemes,
|
|
75
|
+
risks: ['Do not copy competitor content verbatim.', 'Verify claims independently before scripting.', 'Treat transcript/comment signals as public audience signals, not private analytics.']
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
warnings: ['Draft only; no upload or publishing action is performed. Transcript/comment synthesis is heuristic.']
|
|
79
|
+
});
|
|
8
80
|
}
|
|
9
81
|
//# sourceMappingURL=planning.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"planning.js","sourceRoot":"","sources":["../../../src/tools/planning.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"planning.js","sourceRoot":"","sources":["../../../src/tools/planning.ts"],"names":[],"mappings":"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"}
|
|
@@ -16,6 +16,7 @@ export declare function compareHooks(input: unknown, registry: ProviderRegistry)
|
|
|
16
16
|
videoId: any;
|
|
17
17
|
hook: any;
|
|
18
18
|
pattern: string;
|
|
19
|
+
reasons: string[];
|
|
19
20
|
availability: any;
|
|
20
21
|
}[];
|
|
21
22
|
}>>;
|
|
@@ -32,8 +33,11 @@ export declare function summarizeCommentPainPoints(input: unknown, registry: Pro
|
|
|
32
33
|
videoId: string;
|
|
33
34
|
painPoints: {
|
|
34
35
|
theme: string;
|
|
36
|
+
intent: string;
|
|
37
|
+
opportunity: string;
|
|
35
38
|
count: number;
|
|
36
39
|
examples: string[];
|
|
40
|
+
totalLikes: number;
|
|
37
41
|
}[];
|
|
38
42
|
}>>;
|
|
39
43
|
export declare function generateVideoAngleMatrix(input: unknown, registry: ProviderRegistry): Promise<import("../core/envelope.js").ToolEnvelope<{
|
|
@@ -1,33 +1,16 @@
|
|
|
1
1
|
import { makeEnvelope } from '../core/envelope.js';
|
|
2
|
+
import { analyzeHookPattern, classifyComment } from '../core/synthesis.js';
|
|
2
3
|
import { commentPainPointsSchema, compareHooksSchema, outlierVideosSchema, topicAnglesSchema, videoAngleMatrixSchema } from '../schemas/research.js';
|
|
3
4
|
function numberFrom(value, fallback = 0) {
|
|
4
5
|
const parsed = Number(value);
|
|
5
6
|
return Number.isFinite(parsed) ? parsed : fallback;
|
|
6
7
|
}
|
|
7
|
-
function patternForHook(hook) {
|
|
8
|
-
const lower = hook.toLowerCase();
|
|
9
|
-
if (lower.includes('?'))
|
|
10
|
-
return 'question';
|
|
11
|
-
if (lower.includes('secret') || lower.includes('hidden'))
|
|
12
|
-
return 'curiosity_gap';
|
|
13
|
-
if (lower.includes('mock') || lower.includes('this is'))
|
|
14
|
-
return 'direct_promise';
|
|
15
|
-
return 'statement';
|
|
16
|
-
}
|
|
17
8
|
function titleAngle(title, topic, index) {
|
|
18
9
|
const cleaned = title.replace(/\s+/g, ' ').trim();
|
|
19
10
|
if (cleaned.length > 0)
|
|
20
11
|
return cleaned;
|
|
21
12
|
return `${topic} angle ${index + 1}`;
|
|
22
13
|
}
|
|
23
|
-
function themeForComment(text) {
|
|
24
|
-
const lower = text.toLowerCase();
|
|
25
|
-
if (lower.includes('follow-up') || lower.includes('make'))
|
|
26
|
-
return 'follow-up requests';
|
|
27
|
-
if (lower.includes('?') || lower.includes('how') || lower.includes('why'))
|
|
28
|
-
return 'audience questions';
|
|
29
|
-
return 'positive feedback';
|
|
30
|
-
}
|
|
31
14
|
export async function findOutlierVideos(input, registry) {
|
|
32
15
|
const parsed = outlierVideosSchema.parse(input);
|
|
33
16
|
const searchProvider = registry.requireCapability('search');
|
|
@@ -68,7 +51,8 @@ export async function compareHooks(input, registry) {
|
|
|
68
51
|
const data = await provider.getTranscriptSegments({ videoIds: parsed.videoIds, lang: parsed.lang, format: 'key_segments' });
|
|
69
52
|
const hooks = data.transcripts.map((transcript) => {
|
|
70
53
|
const hook = transcript.intro || '';
|
|
71
|
-
|
|
54
|
+
const analysis = analyzeHookPattern(hook);
|
|
55
|
+
return { videoId: transcript.videoId, hook, pattern: analysis.pattern, reasons: analysis.reasons, availability: transcript.availability ?? 'unknown' };
|
|
72
56
|
});
|
|
73
57
|
return makeEnvelope({
|
|
74
58
|
tool: 'youtube.research.compare_hooks',
|
|
@@ -103,14 +87,15 @@ export async function summarizeCommentPainPoints(input, registry) {
|
|
|
103
87
|
const grouped = new Map();
|
|
104
88
|
for (const comment of data.comments) {
|
|
105
89
|
const text = String(comment.text ?? '');
|
|
106
|
-
const
|
|
107
|
-
const existing = grouped.get(theme) ?? {
|
|
90
|
+
const classification = classifyComment(text);
|
|
91
|
+
const existing = grouped.get(classification.theme) ?? { ...classification, count: 0, examples: [], totalLikes: 0 };
|
|
108
92
|
existing.count += 1;
|
|
93
|
+
existing.totalLikes += numberFrom(comment.likeCount);
|
|
109
94
|
if (existing.examples.length < 3)
|
|
110
95
|
existing.examples.push(text);
|
|
111
|
-
grouped.set(theme, existing);
|
|
96
|
+
grouped.set(classification.theme, existing);
|
|
112
97
|
}
|
|
113
|
-
const painPoints = [...grouped.values()].sort((a, b) => b.count - a.count);
|
|
98
|
+
const painPoints = [...grouped.values()].sort((a, b) => b.count - a.count || b.totalLikes - a.totalLikes);
|
|
114
99
|
return makeEnvelope({
|
|
115
100
|
tool: 'youtube.research.summarize_comment_pain_points',
|
|
116
101
|
provider: provider.id,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"research.js","sourceRoot":"","sources":["../../../src/tools/research.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"research.js","sourceRoot":"","sources":["../../../src/tools/research.ts"],"names":[],"mappings":"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"}
|
package/dist/src/tools/safety.js
CHANGED
|
@@ -5,6 +5,6 @@ export async function classifyActionRiskTool(input) {
|
|
|
5
5
|
return makeEnvelope({ tool: 'youtube.safety.classify_action_risk', provider: 'core', authTier: 'none', data: risk, warnings: risk.allowedInV0 ? [] : ['This action is part of the full scope but locked in v0.'] });
|
|
6
6
|
}
|
|
7
7
|
export async function listCapabilities(_input) {
|
|
8
|
-
return makeEnvelope({ tool: 'youtube.safety.list_capabilities', provider: 'core', authTier: 'none', data: { version: '0.2.
|
|
8
|
+
return makeEnvelope({ tool: 'youtube.safety.list_capabilities', provider: 'core', authTier: 'none', data: { version: '0.2.5', phase: 'v0.2.5-deeper-readonly-synthesis', enabledNamespaces: ['discovery', 'video', 'channel', 'transcript', 'comments', 'planning', 'research', 'safety'], lockedNamespaces: ['operations', 'community-write', 'analytics-oauth', 'reporting', 'media-download', 'shorts-render', 'music-private'] }, warnings: [] });
|
|
9
9
|
}
|
|
10
10
|
//# sourceMappingURL=safety.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"safety.js","sourceRoot":"","sources":["../../../src/tools/safety.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAErD,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,KAA2D;IACtG,MAAM,IAAI,GAAG,kBAAkB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC9C,OAAO,YAAY,CAAC,EAAE,IAAI,EAAE,qCAAqC,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,yDAAyD,CAAC,EAAE,CAAC,CAAC;AACtN,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,MAA6B;IAClE,OAAO,YAAY,CAAC,EAAE,IAAI,EAAE,kCAAkC,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"safety.js","sourceRoot":"","sources":["../../../src/tools/safety.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAErD,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,KAA2D;IACtG,MAAM,IAAI,GAAG,kBAAkB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC9C,OAAO,YAAY,CAAC,EAAE,IAAI,EAAE,qCAAqC,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,yDAAyD,CAAC,EAAE,CAAC,CAAC;AACtN,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,MAA6B;IAClE,OAAO,YAAY,CAAC,EAAE,IAAI,EAAE,kCAAkC,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,kCAAkC,EAAE,iBAAiB,EAAE,CAAC,WAAW,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,gBAAgB,EAAE,CAAC,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,WAAW,EAAE,gBAAgB,EAAE,eAAe,EAAE,eAAe,CAAC,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC;AACxb,CAAC"}
|
|
@@ -11,7 +11,16 @@ export declare function getTranscriptFullText(input: unknown, registry: Provider
|
|
|
11
11
|
export declare function analyzeTranscriptStructure(input: unknown, registry: ProviderRegistry): Promise<import("../core/envelope.js").ToolEnvelope<{
|
|
12
12
|
hook: string;
|
|
13
13
|
cta: string;
|
|
14
|
-
outline:
|
|
15
|
-
|
|
14
|
+
outline: {
|
|
15
|
+
section: string;
|
|
16
|
+
text: string;
|
|
17
|
+
purpose: string;
|
|
18
|
+
}[];
|
|
19
|
+
claims: {
|
|
20
|
+
text: string;
|
|
21
|
+
type: string;
|
|
22
|
+
evidenceStrength: string;
|
|
23
|
+
}[];
|
|
16
24
|
scriptPatterns: string[];
|
|
25
|
+
hookAnalysis: import("../core/synthesis.js").HookAnalysis;
|
|
17
26
|
}>>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { makeEnvelope } from '../core/envelope.js';
|
|
2
|
+
import { extractTranscriptStructure } from '../core/synthesis.js';
|
|
2
3
|
import { transcriptFullTextSchema, transcriptSegmentsSchema, transcriptStructureSchema } from '../schemas/transcript.js';
|
|
3
4
|
export async function getTranscriptSegments(input, registry) {
|
|
4
5
|
const parsed = transcriptSegmentsSchema.parse(input);
|
|
@@ -16,6 +17,7 @@ export async function analyzeTranscriptStructure(input, registry) {
|
|
|
16
17
|
const parsed = transcriptStructureSchema.parse(input);
|
|
17
18
|
const provider = registry.requireCapability('transcript');
|
|
18
19
|
const full = await provider.getTranscriptFullText({ videoId: parsed.videoId, lang: parsed.lang, maxChars: 20000 });
|
|
19
|
-
|
|
20
|
+
const structure = extractTranscriptStructure(full.text, parsed.includeClaims);
|
|
21
|
+
return makeEnvelope({ tool: 'youtube.transcript.analyze_structure', provider: provider.id, authTier: provider.authTier, data: structure, warnings: ['Structure analysis is heuristic and derived from available transcript text.'] });
|
|
20
22
|
}
|
|
21
23
|
//# sourceMappingURL=transcript.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transcript.js","sourceRoot":"","sources":["../../../src/tools/transcript.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"transcript.js","sourceRoot":"","sources":["../../../src/tools/transcript.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAElE,OAAO,EAAE,wBAAwB,EAAE,wBAAwB,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AAEzH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,KAAc,EAAE,QAA0B;IACpF,MAAM,MAAM,GAAG,wBAAwB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACrD,MAAM,QAAQ,GAAG,QAAQ,CAAC,iBAAiB,CAAC,YAAY,CAAC,CAAC;IAC1D,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,qBAAsB,CAAC,MAAM,CAAC,CAAC;IAC3D,OAAO,YAAY,CAAC,EAAE,IAAI,EAAE,iCAAiC,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE,EAAE,QAAQ,EAAE,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,kEAAkE,CAAC,EAAE,CAAC,CAAC;AAC7M,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,KAAc,EAAE,QAA0B;IACpF,MAAM,MAAM,GAAG,wBAAwB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACrD,MAAM,QAAQ,GAAG,QAAQ,CAAC,iBAAiB,CAAC,YAAY,CAAC,CAAC;IAC1D,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,qBAAsB,CAAC,MAAM,CAAC,CAAC;IAC3D,OAAO,YAAY,CAAC,EAAE,IAAI,EAAE,kCAAkC,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE,EAAE,QAAQ,EAAE,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,mFAAmF,CAAC,EAAE,CAAC,CAAC;AAC/N,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAAC,KAAc,EAAE,QAA0B;IACzF,MAAM,MAAM,GAAG,yBAAyB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACtD,MAAM,QAAQ,GAAG,QAAQ,CAAC,iBAAiB,CAAC,YAAY,CAAC,CAAC;IAC1D,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,qBAAsB,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;IACpH,MAAM,SAAS,GAAG,0BAA0B,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,aAAa,CAAC,CAAC;IAC9E,OAAO,YAAY,CAAC,EAAE,IAAI,EAAE,sCAAsC,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE,EAAE,QAAQ,EAAE,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,6EAA6E,CAAC,EAAE,CAAC,CAAC;AACxO,CAAC"}
|