1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import { fetch } from "https://esm.town/v/std/fetch";
export const YoutubeTranscript = async (url: string, metadata = true) => {
const RE_YOUTUBE =
/(?:youtube\.com\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=)|youtu\.be\/)([^"&?\/\s]{11})/i;
const YouTubeKey = {
apiKey: "INNERTUBE_API_KEY",
serializedShareEntity: "serializedShareEntity",
visitorData: "VISITOR_DATA",
sessionId: "sessionId",
clickTrackingParams: "clickTrackingParams",
} as const;
type ObjectValues<T> = T[keyof T];
type YouTubeKeyRaw = ObjectValues<typeof YouTubeKey>;
class YoutubeTranscriptError extends Error {
constructor(message: string) {
super(`[YoutubeTranscript] 🚨 ${message}`);
}
}
interface TranscriptConfig {
lang?: string;
country?: string;
}
interface TranscriptSegment {
text: string;
duration: number;
offset: number;
}
interface TranscriptData {
responseContext: {
serviceTrackingParams: {
service: string;
params: {
key: string;
value: string;
}[];
}[];
mainAppWebResponseContext: {
loggedOut: boolean;
trackingParam: string;
};
webResponseContextExtensionData: {
hasDecorated: boolean;
};
};
actions: {
clickTrackingParams: string;
updateEngagementPanelAction: {
targetId: string;
content: {
transcriptRenderer: {
body: {
transcriptBodyRenderer: {
cueGroups: {
transcriptCueGroupRenderer: {
formattedStartOffset: {
simpleText: string;
};
cues: {
transcriptCueRenderer: {
cue: {
simpleText: string;
};
startOffsetMs: string;
durationMs: string;
};
}[];
};
}[];
};
};
};
};
};
}[];
}
/**
* An extensible class to fetch a transcript from a given YouTube Video
*/
class YoutubeTranscript {
/**
* Fetch a transcript from a YouTube Video which includes the text and timestamp metadata
* @param videoId Video url or video identifier
* @param config Options for specifying a Country and Language ISO
*/
static async fetchTranscript(
videoId: string,
config?: TranscriptConfig,
): Promise<TranscriptSegment[]> {
const identifier = this.extractVideoId(videoId);
try {
const textResponse = await fetch(
`https://www.youtube.com/watch?v=${identifier}`,
);
const body = await textResponse.text();
const apiKey = this.extractValue(body, YouTubeKey.apiKey);
if (!apiKey || !apiKey.length) {
throw new YoutubeTranscriptError(
`Failed to extract ${YouTubeKey.apiKey}`,
);
Val Town is a social website to write and deploy JavaScript.
Build APIs and schedule functions from your browser.
Comments
Nobody has commented on this val yet: be the first!
October 23, 2023