Skip to content

Commit b58eda5

Browse files
committed
first pass, captions only
0 parents  commit b58eda5

File tree

4 files changed

+1109
-0
lines changed

4 files changed

+1109
-0
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
token.json
2+
credentials.json
3+
node_modules
4+
.DS_Store
5+
captions

index.js

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
import { google } from 'googleapis';
2+
import fs from 'fs';
3+
import express from 'express';
4+
5+
const SCOPES = ['https://www.googleapis.com/auth/youtube.force-ssl'];
6+
const TOKEN_PATH = 'token.json';
7+
const PORT = 3000;
8+
9+
main();
10+
11+
async function main() {
12+
const authClient = await authenticateYouTube();
13+
const youtube = google.youtube({ version: 'v3', auth: authClient });
14+
const channel = await youtube.channels.list({
15+
part: 'contentDetails',
16+
mine: true,
17+
});
18+
19+
// const channelId = channel.data.items[0].id;
20+
const uploadsId =
21+
channel.data.items[0].contentDetails.relatedPlaylists.uploads;
22+
23+
let nextPage;
24+
do {
25+
const videos = await youtube.playlistItems.list({
26+
part: 'snippet',
27+
playlistId: uploadsId,
28+
maxResults: 50,
29+
pageToken: nextPage,
30+
});
31+
32+
for (let item of videos.data.items) {
33+
const id = item.snippet.resourceId.videoId;
34+
const title = item.snippet.title;
35+
await getCaptions(id, title);
36+
}
37+
38+
nextPage = videos.data.nextPageToken;
39+
} while (nextPage);
40+
41+
async function getCaptions(id, title) {
42+
const captionsList = await youtube.captions.list({
43+
part: 'snippet',
44+
videoId: id,
45+
});
46+
const captions = captionsList.data.items;
47+
if (captions.length === 0) {
48+
console.log(`No captions available ${videoId}`);
49+
return;
50+
}
51+
// Just get first captions for now?
52+
const captionId = captions[0].id;
53+
const download = await youtube.captions.download({
54+
id: captionId,
55+
tfmt: 'srt',
56+
});
57+
58+
const dir = 'captions';
59+
if (!fs.existsSync(dir)) fs.mkdirSync(dir);
60+
const fileTitle = title.replace(/[^a-z0-9]+/gi, '_').toLowerCase();
61+
const filename = `${dir}/${fileTitle}_${id}.srt`;
62+
63+
const arrayBuffer = await download.data.arrayBuffer();
64+
const buffer = Buffer.from(arrayBuffer);
65+
fs.writeFileSync(filename, buffer);
66+
console.log(`Captions saved to ${filename}`);
67+
}
68+
}
69+
70+
// First:
71+
// Go to the Google Developers Console.
72+
// Create a new project.
73+
// Enable the YouTube Data API v3 for that project.
74+
// Go to the "Credentials" tab and click "Create Credentials". Choose "OAuth 2.0 Client ID".
75+
// For the application type, choose "Desktop app" (for testing purposes).
76+
// Download the credentials JSON file.
77+
78+
async function authenticateYouTube() {
79+
return new Promise((resolve, reject) => {
80+
let oAuth2Client = createOAuthClient();
81+
82+
const app = express();
83+
84+
app.get('/', async (req, res) => {
85+
if (req.query.code) {
86+
const { tokens } = await oAuth2Client.getToken(req.query.code);
87+
fs.writeFileSync(TOKEN_PATH, JSON.stringify(tokens));
88+
oAuth2Client.setCredentials(tokens);
89+
res.send('Token stored to token.json');
90+
resolve(oAuth2Client);
91+
} else if (!oAuth2Client.credentials.access_token) {
92+
const authUrl = oAuth2Client.generateAuthUrl({
93+
access_type: 'offline',
94+
scope: SCOPES,
95+
});
96+
res.send(
97+
`<a href="${authUrl}">Authorize this app by visiting this link</a>`
98+
);
99+
} else {
100+
res.send('Already authenticated with YouTube.');
101+
resolve(oAuth2Client);
102+
}
103+
});
104+
105+
app.listen(PORT, () => {
106+
if (!oAuth2Client.credentials.access_token) {
107+
console.log(`Authorize app at: http://localhost:${PORT}`);
108+
} else {
109+
console.log(
110+
`App is already authorized. Listening at: http://localhost:${PORT}`
111+
);
112+
resolve(oAuth2Client);
113+
}
114+
});
115+
});
116+
}
117+
118+
function createOAuthClient() {
119+
const content = fs.readFileSync('credentials.json', 'utf-8');
120+
const credentials = JSON.parse(content);
121+
const { client_secret, client_id, redirect_uris } = credentials.installed;
122+
123+
const client = new google.auth.OAuth2(
124+
client_id,
125+
client_secret,
126+
redirect_uris[0]
127+
);
128+
try {
129+
const token = fs.readFileSync(TOKEN_PATH, 'utf-8');
130+
client.setCredentials(JSON.parse(token));
131+
} catch (error) {
132+
console.log('No token found.');
133+
}
134+
return client;
135+
}

0 commit comments

Comments
 (0)