50 個まではこれでいける
const API_KEY = "";
const getYouTube = async (api, query, cooldown = 3000) => {
await new Promise((r) => setTimeout(r, cooldown));
return await (
await fetch(
`https://www.googleapis.com/youtube/v3/${api}${Object.entries(
query
).reduce((p, [k, v]) => `${p}&${k}=${v}`, `?key=${API_KEY}`)}`
)
).json();
};
const getVideos = async (channelId, pageToken = "") => {
const playlistId = (
await getYouTube("channels", {
part: "contentDetails",
id: channelId,
})
).items[0].contentDetails.relatedPlaylists.uploads;
return await getYouTube("playlistItems", {
part: "snippet",
maxResults: 50,
playlistId,
pageToken,
});
};
getVideos(
// https://www.youtube.com/channel/{これ}
"UCsLiV4WJfkTEHH0b9PmRklw"
).then(console.log);
チャンネル動画だけが入ったプレイリストを取得してきて、その動画を取得する。
サーバー負荷とかを考慮して、クールダウン時間を設定できるようにしてある。
動画数は一度のリクエストでは 50 個までなので、
本当に全部取りたいなら nextPageToken
を使って適宜実装する必要がある。
というわけで、全部とる
const getAllVideos = async (channelId) => {
let [all, token] = [[]];
while (1) {
const { items, nextPageToken } = await getVideos(channelId, token);
all = [...all, ...items];
if (!nextPageToken) break;
token = nextPageToken;
}
return all;
};
getAllVideos(
// https://www.youtube.com/channel/{これ}
"UCkvvFbRyfvENnl_G8YHuriQ"
).then(console.log);
これで根こそぎ取ってくれる。
気づいたこと
どうも、チャンネル ID の prefix がUC
になっている場合、
プレイリスト ID はチャンネル ID の prefix をUU
にするだけでいいらしい。
https://www.youtube.com/channel/UCQbL0aAYEmzAbvgBn2PAy4A
↓
U C QbL0aAYEmzAbvgBn2PAy4A
↓
U U QbL0aAYEmzAbvgBn2PAy4A
↓
https://www.youtube.com/playlist?list=UUQbL0aAYEmzAbvgBn2PAy4A
だからこれでもいけちゃうっぽい
const getVideos = async (channelId, pageToken = "") => {
const playlistId = channelId.replace(/^UC/, "UU"); // <--
return await getYouTube("playlistItems", {
part: "snippet",
maxResults: 50,
playlistId,
pageToken,
});
};
こっちのほうがシンプルかもね。
Node.js でデモコードを試す場合の注意点
Node.js では fetch が使えません。
なので、素直に axios や node-fetch を使うなり、deno を使うなりしてください。
面倒くさい人はこれを使えばとりあえず動くんじゃない(適当)
const fetch = (url) =>
new Promise((resolve, reject) => {
const req = require("https").get(url, (res) => {
let buffer = "";
res.on("data", (chunk) => (buffer += chunk));
res.on("end", () => resolve({ json: () => JSON.parse(buffer) }));
});
req.on("error", reject);
req.end();
});