node Puppeteerを使ってYoutubeの他人が作成した再生リストをコピー
Youtubeで他人が作成した再生リストを保存する機能があるが、
実際のところ保存というよりはお気に入りやブックマークに近い。
動画を追加したり消したりすることができない。
また再生リストを複製する機能も用意されていないので、自分で一つ一つ再生リストに保存していく方法しかない(多分ない)と思います。
なのでPuppeteerで再生リストを複製するスクリプトを書いてみました。
作業環境
コード
const fs = require('fs'); const puppeteer = require('puppeteer'); const COOKIES_PATH = 'youtubecookie'; (async () => { const browser = await puppeteer.launch({ headless: false }) const page = await browser.newPage(); //cookieが作られていない場合ログイン画面からログインし、cookieを保存 if (fs.existsSync(COOKIES_PATH) == false) { await page.goto('https://accounts.google.com/signin/v2/identifier?service=youtube&uilel=3&passive=true&continue=https%3A%2F%2Fwww.youtube.com%2Fsignin%3Faction_handle_signin%3Dtrue%26app%3Ddesktop%26hl%3Dja%26next%3D%252F%253Fgl%253DJP%2526hl%253Dja&hl=ja&ec=65620&flowName=GlifWebSignIn&flowEntry=ServiceLogin', { waitUntil: 'domcontentloaded' }); await page.type('input[name="identifier"]', "ログインメールアドレス"); await page.click('#identifierNext'); await page.waitForNavigation({ timeout: 60000, waitUntil: 'domcontentloaded' }); await page.waitFor(1000); await page.type('input[name="password"]', "ログインパスワード"); await page.click('#passwordNext'); await page.waitForNavigation({ timeout: 60000, waitUntil: 'domcontentloaded' }); const afterCookies = await page.cookies(); fs.writeFileSync(COOKIES_PATH, JSON.stringify(afterCookies)); } else { //cookieでログイン const cookies = JSON.parse(fs.readFileSync(COOKIES_PATH, 'utf-8')); for (let cookie of cookies) { await page.setCookie(cookie); } //コピー元プレイリスト(URL) await page.goto('https://www.youtube.com/playlist?list=PL590L5WQmH8dc-kEkuMX3n_EhpMvZxowe', { waitUntil: 'domcontentloaded' }); //動画の数を数える let listSelector = "#contents > ytd-playlist-video-renderer"; var list = await page.$$(listSelector); //保存処理 for (let i = 1; i <= list.length; i++) { console.log(i + '/' + list.length); await page.click('.style-scope:nth-child(' + i + ') > #content > #menu > .style-scope > #button'); await page.click('.style-scope:nth-child(1) > #items > .style-scope:nth-child(3)'); await page.waitFor(4000); //コピー先(上から何番目か 後で見るもこみ nth-child(2)の場合2番目、nth-child(3)の場合3番目) await page.click('#playlists > .style-scope:nth-child(2)'); //await page.waitFor(3000); await page.click('#close-button > button'); await page.waitFor(1000); } } console.log('finish'); await browser.close(); })();
コピー先の上から何番目かっていうのは、動画を再生リストに追加する操作をしたときに
このように表示表示されると思いますが、ここの上から数えて何番目かです。
あと新しくテスト用で作成したGoogleアカウントだとログインができなかったが、普段使いのアカウントならログインできました。
改善点とか妥協点とか
- 少し読み込みが長いところとかをwaitForでごまかしてる。(1動画当たり5秒ほどかかる)
- headlessをtrueにするとエラーを吐いたのでfarseにした。(Chromiumがウィンドウで起動する。メモリは230M前後使用していた。)
- Youtubeのhtmlタグが特殊でよくわからなかったんで、チェックボックスなどの操作をクリックで操作している。
- ↑のせいでコピー先とコピー元に同じ動画があると消えてしまう。
多分改良も改善もしないと思いますが、このコードをパクるならこのように不完全なものなので注意してください。
実際に動かしてみた動画
とりあえずこんな感じでできた
— 【公式】さ さ ざ き (@daruuuuuuuuuui) 2020年3月23日
書き方、処理が冗長で1件あたり5秒かかる
あとすでに追加されている動画だとリストから消えちゃう(チェックボックスをクリックしているので)から改良が必要 pic.twitter.com/ptmYbPxIqr
おわり