@liorium/youtube-omni-mcp 0.2.3 → 0.2.6

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.
Files changed (33) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/src/core/synthesis.d.ts +88 -0
  3. package/dist/src/core/synthesis.js +235 -0
  4. package/dist/src/core/synthesis.js.map +1 -0
  5. package/dist/src/providers/transcript-provider.d.ts +9 -1
  6. package/dist/src/providers/transcript-provider.js +194 -5
  7. package/dist/src/providers/transcript-provider.js.map +1 -1
  8. package/dist/src/providers/types.d.ts +4 -0
  9. package/dist/src/schemas/planning.d.ts +8 -0
  10. package/dist/src/schemas/planning.js +7 -0
  11. package/dist/src/schemas/planning.js.map +1 -1
  12. package/dist/src/schemas/research.d.ts +15 -0
  13. package/dist/src/schemas/research.js +12 -0
  14. package/dist/src/schemas/research.js.map +1 -1
  15. package/dist/src/server.d.ts +1 -1
  16. package/dist/src/server.js +29 -2
  17. package/dist/src/server.js.map +1 -1
  18. package/dist/src/tools/comments.d.ts +13 -2
  19. package/dist/src/tools/comments.js +3 -1
  20. package/dist/src/tools/comments.js.map +1 -1
  21. package/dist/src/tools/planning.d.ts +30 -4
  22. package/dist/src/tools/planning.js +103 -4
  23. package/dist/src/tools/planning.js.map +1 -1
  24. package/dist/src/tools/research.d.ts +30 -9
  25. package/dist/src/tools/research.js +78 -29
  26. package/dist/src/tools/research.js.map +1 -1
  27. package/dist/src/tools/safety.js +1 -1
  28. package/dist/src/tools/safety.js.map +1 -1
  29. package/dist/src/tools/transcript.d.ts +11 -2
  30. package/dist/src/tools/transcript.js +3 -1
  31. package/dist/src/tools/transcript.js.map +1 -1
  32. package/docs/superpowers/plans/2026-05-14-v0.2.6-public-readonly-intelligence.md +427 -0
  33. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.2.6 - 2026-05-14
4
+
5
+ - Add channel-level read-only intelligence: positioning analysis, content pillar extraction, and channel comparison.
6
+ - Add planning video idea generation linked to benchmark videos and public comment request signals.
7
+ - Improve outlier ranking with views-to-subscribers ratio, benchmark rank, and explicit rationale fields.
8
+ - Deduplicate comment text before summarization and expose raw/deduped comment counts.
9
+ - Expand the V0 MCP surface to 23 public read-only tools while keeping write/operations locked by default.
10
+
11
+ ## 0.2.5 - 2026-05-14
12
+
13
+ - Add deeper read-only synthesis for transcript structure, claim-like moments, hook pattern classification, comment themes, and research briefs.
14
+ - Replace mock comment summarization with actual comment-text analysis for questions, requests, themes, and sentiment signals.
15
+ - Feed transcript hooks and comment signals into planning briefs with recommended angles and content opportunities.
16
+
17
+ ## 0.2.4 - 2026-05-14
18
+
19
+ - Replace the transcript placeholder provider with a read-only YouTube timedtext provider.
20
+ - Add resilient `yt-dlp` caption metadata fallback when watch-page caption URLs are missing or stale.
21
+ - Keep transcript calls non-destructive and unavailable-safe when captions cannot be fetched.
22
+
3
23
  ## 0.2.3 - 2026-05-14
4
24
 
5
25
  - 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,88 @@
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
+ rawCommentCount: number;
35
+ dedupedCommentCount: number;
36
+ questions: string[];
37
+ contentRequests: string[];
38
+ themes: {
39
+ theme: string;
40
+ intent: string;
41
+ opportunity: string;
42
+ count: number;
43
+ examples: string[];
44
+ totalLikes: number;
45
+ }[];
46
+ sentimentSignal: {
47
+ positiveCount: number;
48
+ concernCount: number;
49
+ mixed: boolean;
50
+ dominant: string;
51
+ };
52
+ };
53
+ export type ChannelPillar = {
54
+ pillar: string;
55
+ count: number;
56
+ evidence: string[];
57
+ };
58
+ export declare function normalizeCommentText(text: string): string;
59
+ export declare function dedupeComments<T extends {
60
+ text?: string;
61
+ }>(comments: T[]): T[];
62
+ export declare function extractChannelPillars(videos: Array<{
63
+ videoId?: string;
64
+ title?: string;
65
+ }>): ChannelPillar[];
66
+ export declare function inferRepeatableFormats(videos: Array<{
67
+ title?: string;
68
+ }>): string[];
69
+ export declare function inferChannelPositioning(channelTitle: string, videos: Array<{
70
+ title?: string;
71
+ }>): {
72
+ channelPositioning: string;
73
+ contentPillars: ChannelPillar[];
74
+ repeatableFormats: string[];
75
+ audiencePromise: string;
76
+ differentiation: string;
77
+ };
78
+ export declare function generateIdeasFromBenchmarks(topic: string, videos: Array<{
79
+ videoId?: string;
80
+ title?: string;
81
+ }>, requests: string[], ideaCount: number): {
82
+ title: string;
83
+ angle: string;
84
+ hook: string;
85
+ evidence: (string | undefined)[];
86
+ rationale: string;
87
+ risk: string;
88
+ }[];
@@ -0,0 +1,235 @@
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 dedupedComments = dedupeComments(comments);
107
+ const texts = dedupedComments.map((comment) => String(comment.text ?? '').trim()).filter(Boolean);
108
+ const grouped = new Map();
109
+ let positiveCount = 0;
110
+ let concernCount = 0;
111
+ for (const comment of dedupedComments) {
112
+ const text = String(comment.text ?? '').trim();
113
+ if (!text)
114
+ continue;
115
+ const classification = classifyComment(text);
116
+ if (classification.intent === 'praise')
117
+ positiveCount += 1;
118
+ if (classification.intent === 'concern' || classification.intent === 'confusion')
119
+ concernCount += 1;
120
+ const existing = grouped.get(classification.theme) ?? { ...classification, count: 0, examples: [], totalLikes: 0 };
121
+ existing.count += 1;
122
+ existing.totalLikes += Number(comment.likeCount ?? 0);
123
+ if (existing.examples.length < 3)
124
+ existing.examples.push(text);
125
+ grouped.set(classification.theme, existing);
126
+ }
127
+ const themes = [...grouped.values()].sort((a, b) => b.count - a.count || b.totalLikes - a.totalLikes);
128
+ const questions = includeQuestions ? texts.filter((text) => text.includes('?') || /\b(how|why|what|which)\b/i.test(text)).slice(0, 10) : [];
129
+ 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) : [];
130
+ const topTheme = themes[0]?.theme ?? 'no clear theme';
131
+ return {
132
+ summary: `${texts.length} comments analyzed. Top signal: ${topTheme}. ${questions.length} questions and ${contentRequests.length} requests detected.`,
133
+ rawCommentCount: comments.length,
134
+ dedupedCommentCount: dedupedComments.length,
135
+ questions,
136
+ contentRequests,
137
+ themes,
138
+ sentimentSignal: {
139
+ positiveCount,
140
+ concernCount,
141
+ mixed: positiveCount > 0 && concernCount > 0,
142
+ dominant: concernCount > positiveCount ? 'concern' : positiveCount > 0 ? 'positive' : 'neutral'
143
+ }
144
+ };
145
+ }
146
+ export function normalizeCommentText(text) {
147
+ return text.normalize('NFKC').toLowerCase().replace(/\s+/g, ' ').replace(/[^\p{L}\p{N} ?!]/gu, '').trim();
148
+ }
149
+ export function dedupeComments(comments) {
150
+ const seen = new Set();
151
+ const deduped = [];
152
+ for (const comment of comments) {
153
+ const key = normalizeCommentText(String(comment.text ?? ''));
154
+ if (!key || seen.has(key))
155
+ continue;
156
+ seen.add(key);
157
+ deduped.push(comment);
158
+ }
159
+ return deduped;
160
+ }
161
+ function classifyPillar(title) {
162
+ const lower = title.toLowerCase();
163
+ if (/\b(tried|days?|case study|experiment|built|rebuilt)\b/i.test(lower))
164
+ return 'case studies';
165
+ if (/\b(guide|how to|tutorial|beginner|step|workflow)\b/i.test(lower))
166
+ return 'tutorials and workflows';
167
+ if (/\b(tool|tools|review|comparison|vs\.?|best)\b/i.test(lower))
168
+ return 'tool reviews';
169
+ if (/\b(hidden|risk|mistake|danger|problem|cost|nobody)\b/i.test(lower))
170
+ return 'mistakes and risks';
171
+ if (/\b(news|trend|update|latest|new)\b/i.test(lower))
172
+ return 'news and trends';
173
+ if (/\b(history|documentary|explained|story|why)\b/i.test(lower))
174
+ return 'documentary explainers';
175
+ return 'general education';
176
+ }
177
+ export function extractChannelPillars(videos) {
178
+ const grouped = new Map();
179
+ for (const video of videos) {
180
+ const pillar = classifyPillar(String(video.title ?? ''));
181
+ const existing = grouped.get(pillar) ?? { pillar, count: 0, evidence: [] };
182
+ existing.count += 1;
183
+ if (video.videoId && existing.evidence.length < 5)
184
+ existing.evidence.push(video.videoId);
185
+ grouped.set(pillar, existing);
186
+ }
187
+ return [...grouped.values()].sort((a, b) => b.count - a.count || a.pillar.localeCompare(b.pillar));
188
+ }
189
+ export function inferRepeatableFormats(videos) {
190
+ const titles = videos.map((video) => String(video.title ?? '')).join(' | ').toLowerCase();
191
+ const formats = [];
192
+ if (/\btried|\b\d+ days?|case study|experiment/.test(titles))
193
+ formats.push('challenge/case-study experiments');
194
+ if (/beginner|guide|how to|workflow|step/.test(titles))
195
+ formats.push('beginner workflow guides');
196
+ if (/hidden|risk|mistake|cost|danger/.test(titles))
197
+ formats.push('hidden-risk explainers');
198
+ if (/tool|review|comparison|best/.test(titles))
199
+ formats.push('tool comparison reviews');
200
+ return formats.length ? formats : ['topic explainers'];
201
+ }
202
+ export function inferChannelPositioning(channelTitle, videos) {
203
+ const pillars = extractChannelPillars(videos);
204
+ const topPillars = pillars.slice(0, 2).map((pillar) => pillar.pillar).join(' + ') || 'general education';
205
+ const repeatableFormats = inferRepeatableFormats(videos);
206
+ return {
207
+ channelPositioning: `${channelTitle || 'This channel'} positions around ${topPillars} using ${repeatableFormats[0]}.`,
208
+ contentPillars: pillars,
209
+ repeatableFormats,
210
+ audiencePromise: `Help viewers understand and act on ${topPillars} with clearer decisions.`,
211
+ differentiation: repeatableFormats.includes('challenge/case-study experiments')
212
+ ? 'Uses lived experiments and concrete workflows rather than generic commentary.'
213
+ : 'Packages public signals into repeatable, evidence-led explainers.'
214
+ };
215
+ }
216
+ export function generateIdeasFromBenchmarks(topic, videos, requests, ideaCount) {
217
+ const seeds = videos.length ? videos : [{ videoId: undefined, title: `${topic}: The Hidden Cost Nobody Mentions` }];
218
+ return Array.from({ length: ideaCount }, (_, index) => {
219
+ const video = seeds[index % seeds.length];
220
+ const titleBase = String(video.title ?? `${topic} angle ${index + 1}`).replace(/\s+/g, ' ').trim();
221
+ const pillar = classifyPillar(titleBase);
222
+ const request = requests[index % Math.max(1, requests.length)] ?? '';
223
+ return {
224
+ title: index === 0 ? `${topic}: The Hidden Cost Nobody Mentions` : titleBase,
225
+ angle: pillar,
226
+ hook: pillar === 'case studies'
227
+ ? `What happens when one creator tests ${topic} under real constraints?`
228
+ : `What if ${topic} has a hidden cost most viewers miss?`,
229
+ evidence: [video.videoId].filter(Boolean),
230
+ rationale: request ? `Combines benchmark title pattern with audience request: ${request}` : 'Combines benchmark discovery with a clear public-data content angle.',
231
+ risk: 'Avoid copying competitor content; verify factual claims before scripting.'
232
+ };
233
+ });
234
+ }
235
+ //# 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: string;
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 = 'transcript_placeholder';
3
- name = 'Transcript Placeholder Provider';
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: ['Transcript provider returns unavailable placeholders until a real transcript adapter is configured'] };
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
- return { transcripts: input.videoIds.map((videoId) => ({ videoId, language: input.lang, format: input.format, intro: '', outro: '', availability: 'unavailable' })) };
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
- return { videoId: input.videoId, language: input.lang, text: '', truncated: false };
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":"AAEA,MAAM,OAAO,kBAAkB;IAC7B,EAAE,GAAG,wBAAwB,CAAC;IAC9B,IAAI,GAAG,iCAAiC,CAAC;IACzC,QAAQ,GAAG,MAAe,CAAC;IAC3B,YAAY,GAAG,CAAC,YAAY,CAAC,CAAC;IAE9B,YAAY,KAAc,OAAO,IAAI,CAAC,CAAC,CAAC;IAExC,KAAK,CAAC,WAAW;QACf,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,YAAY,EAAE,IAAI,CAAC,YAAY,EAAE,QAAQ,EAAE,CAAC,oGAAoG,CAAC,EAAE,CAAC;IAC7N,CAAC;IAED,KAAK,CAAC,qBAAqB,CAAC,KAAmE;QAC7F,OAAO,EAAE,WAAW,EAAE,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,YAAY,EAAE,aAAa,EAAE,CAAC,CAAC,EAAE,CAAC;IACxK,CAAC;IAED,KAAK,CAAC,qBAAqB,CAAC,KAA0D;QACpF,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,QAAQ,EAAE,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IACtF,CAAC;CACF"}
1
+ {"version":3,"file":"transcript-provider.js","sourceRoot":"","sources":["../../../src/providers/transcript-provider.ts"],"names":[],"mappings":"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"}
@@ -16,6 +16,10 @@ export interface YoutubeOmniProvider {
16
16
  searchVideos?(input: {
17
17
  query: string;
18
18
  maxResults: number;
19
+ order?: string;
20
+ videoDuration?: string;
21
+ recency?: string;
22
+ regionCode?: string;
19
23
  }): Promise<{
20
24
  videos: any[];
21
25
  }>;
@@ -7,3 +7,11 @@ export declare const researchBriefSchema: z.ZodObject<{
7
7
  includeTranscripts: z.ZodDefault<z.ZodBoolean>;
8
8
  includeComments: z.ZodDefault<z.ZodBoolean>;
9
9
  }, z.core.$strip>;
10
+ export declare const videoIdeasSchema: z.ZodObject<{
11
+ topic: z.ZodString;
12
+ regionCode: z.ZodDefault<z.ZodString>;
13
+ sampleSize: z.ZodDefault<z.ZodNumber>;
14
+ ideaCount: z.ZodDefault<z.ZodNumber>;
15
+ includeComments: z.ZodDefault<z.ZodBoolean>;
16
+ }, z.core.$strip>;
17
+ export type VideoIdeasInput = z.infer<typeof videoIdeasSchema>;