メインコンテンツへスキップ
見出し画像

SpotifyのプレイリストをYouTubeに変換するツールを作って無料公開してみた!【Cloudflare】

はじめに

今回は「Spotify のプレイリストを YouTube の再生リストに変換するツール」を作って、Cloudflare で誰でも使えるように公開した話をしていきます!

友達に「このプレイリストいいよ」って送りたいのに、相手が Spotify を使ってない…ってこと、ありませんか?
正直、今までは1曲ずつ YouTube で検索してURLを貼ってました(笑)。曲が30曲とかあると地獄です。

なので、URLを貼るだけで全曲を YouTube のURLにして、そのまま再生リストとして開けるツールを作りました。

実際に動いているのはこちらです👇
https://spotify-to-youtube-80b.pages.dev

  • ログイン不要

  • Spotify の公開プレイリスト / アルバムのURLを貼るだけ

  • 全曲の YouTube URL をコピー・txt・csv で保存できる

  • YouTube の再生リストとして開ける(そのリンクを友達に送ればOK)

画像

この記事は「何か作って公開してみたい中高生・大学生」向けに、仕組みと詰まったところを中心に書いていきます!

1. どうやって動いているか

やっていることはシンプルで、3ステップだけです。

  1. Spotify から曲名とアーティスト名の一覧を取る

  2. 1曲ずつ YouTube で「アーティスト名 曲名」を検索して、一番上の動画を取る

  3. 動画IDをまとめて YouTube の再生リストURLにする

ポイントは、どれも APIキーを使っていないことです。

Spotify の曲一覧は「埋め込みページ」から取る

Spotify の公式 API を使うには、開発者登録をしてキーを作る必要があります。
でも、ブログなどに貼る用の「埋め込みプレーヤー」のページ(open.spotify.com/embed/playlist/...)には、中に曲の一覧が JSON で入っています。

なので、そのページを読み込んで JSON を取り出すだけで曲名がわかります。

const NEXT_DATA_RE = /<script id="__NEXT_DATA__" type="application\/json">([\s\S]*?)<\/script>/;

const entity = JSON.parse(m[1]).props.pageProps.state.data.entity;
// entity.trackList に { title: 曲名, subtitle: アーティスト名 } が並んでいる

ただ、埋め込みページなので長いプレイリストは途中までしか取れません(試した感じだと100曲くらいまで)。全部取りたい場合は公式APIを使う必要があります。

YouTube も検索結果ページから取る

YouTube の公式 API にも検索機能はありますが、1日に使える回数(クォータ)がかなり少なくて、検索だと1日100回くらいで止まってしまいます。

なので、普通の検索結果ページ(youtube.com/results?search_query=...)を読み込んで、最初の動画IDを正規表現で抜き出しています。

const YT_VIDEO_RE = /"videoRenderer":\{"videoId":"([\w-]{11})"/;

YouTube の動画IDは必ず11文字なので、[\w-]{11} で取れます。

再生リストは URL だけで作れる

ここが一番びっくりしたところなんですが、YouTube には

https://www.youtube.com/watch_videos?video_ids=ID1,ID2,ID3,...

という URL があって、動画IDをカンマでつなぐだけで、その順番の再生リストとして開けるんです!
ログインもいらないし、このURLは誰が開いても同じ曲順で再生されるので、そのまま友達に送れます。

1つのURLに入れられるのは50曲までなので、それより多いときは50曲ずつに分けています。

2. 最初はPCで動かすPython版を作った

最初は Python(Flask)で、自分のPCだけで動く版を作りました。

  • core.py:Spotify の取得と YouTube の検索

  • app.py:画面とAPI(Flask)

  • cli.py:コマンドで一発変換する版

画面はHTML1枚で、変換ボタンを押すと4曲ずつ並列で検索して、終わった曲から表に埋まっていくようにしました。間違った動画が当たったときは、表のURLを書き換えればそれが反映されます。

おまけ:自分のYouTubeに「本物の」プレイリストを作る機能

PC版には、Googleでログインして自分の YouTube アカウントに本物のプレイリストを作る機能も付けました(YouTube Data API + Google OAuth)。

ただ、これを公開版に入れるのはやめました。理由は2つです。

  • Google の審査を通していないアプリは「テストモード」になって、自分で登録した人(テストユーザー)しかログインできない

  • YouTube API の上限があって、プレイリストに曲を追加するのは全員合わせて1日200曲くらいまで

みんなに使ってもらうには向いてないので、公開版は「URLで開く再生リスト」だけにしました。

3. Cloudflare で公開する

PC版だと自分しか使えないので、Cloudflare で公開しました。
無料プランでも十分使えて、npx wrangler deploy の一発で公開できるのが楽です。

ただ、Cloudflare では Python の Flask がそのまま動かないので、TypeScript に書き直しました。中身はほぼ同じです。

最終的な構成はこうなりました。

  • Cloudflare Pages:画面(public/index.html)を配信。/api/ へのアクセスだけ下の Worker に渡す

  • Cloudflare Workers(spotify-to-youtube-api):Spotify の取得と YouTube の検索をするAPI本体

  • src/core.ts:Spotify の取得と YouTube の検索

  • src/api.ts:/api/playlist、/api/search などのAPI

なんで2つに分けているかは、下の「詰まったところ」で説明します。

連打対策を入れた

誰でも使える公開サービスにすると、ボタンを連打されたり、大量にアクセスされたりする可能性があります。
そうなると YouTube や Spotify にもアクセスが集中して迷惑なので、Cloudflare の「Rate Limiting」でIPごとに回数制限をかけました。

"ratelimits": [
  { "name": "SEARCH_LIMITER", "namespace_id": "2201", "simple": { "limit": 120, "period": 60 } },
  { "name": "PLAYLIST_LIMITER", "namespace_id": "2202", "simple": { "limit": 10, "period": 60 } }
]

検索は1分に120回、プレイリスト読み込みは1分に10回までです。設定ファイルに書くだけでいいので簡単でした。
実際に30回連打してテストしたら、8回目くらいから「アクセスが多すぎます」が返ってきました(数え方がざっくりなので、ぴったり10回では止まらないみたいです)。

4. 詰まったところ

詰まり1:Cloudflare からだと検索が半分失敗する…と思ったら

公開してテストしたら、10曲中5曲くらい「見つかりませんでした」になりました。
「Cloudflare のサーバーからだと YouTube にブロックされてる?」と思って、デバッグ用のAPIを作って中身を見てみたら…

検索ワードが文字化けしてました。

原因は、テストに使っていた Windows のターミナル(Git Bash)の curl で日本語を送ると、UTF-8 じゃない文字コードで送られていたことでした。
「YOASOBI」みたいに英語だけの曲は成功して、「米津玄師 Lemon」みたいな日本語入りが失敗していたのはそのせいです。

Python の requests(ちゃんと UTF-8 で送る)でテストし直したら、10曲中10曲成功しました。ツールは最初から壊れてなかったです(笑)
テストのやり方が間違ってることもあるので、「おかしいな」と思ったら実際に届いているデータを見るのが大事だと学びました。

詰まり2:hidden にしたボタンが消えない

ボタンに hidden を付けて隠したはずなのに、画面に出っぱなしになっていました。
原因は CSS で .row { display: flex; } を書いていたことで、CSS の display が hidden より強いんです。

[hidden] { display: none !important; }

この1行を足したら直りました。地味だけどハマりやすいです。

詰まり3:直したのに画面が変わらない

JavaScript のエラーを直してデプロイしたのに、ブラウザで開くと前のまま…。
これはブラウザが古いページをキャッシュしていただけでした。URLの後ろに ?v=2 みたいに適当な文字を付けて開き直したら、新しい版が出ました。

詰まり4:URLに自分の名前が出てしまう

最初は Cloudflare Workers だけで公開したんですが、URLが「spotify-to-youtube.(アカウント名).workers.dev」になって、自分の名前がURLに入ってしまいました。
workers.dev のこの部分はアカウント全体で共通なので、変えると他に公開しているツールのURLまで変わってしまいます。

そこで、URLがプロジェクト名だけになる Cloudflare Pages に引っ越すことにしました。
でも今度は、Pages ではさっきの回数制限(ratelimits)が使えないというエラーが…。

Configuration file for Pages projects does not support "ratelimits"

最終的にはこうしました。

  1. APIは今まで通り Worker で動かす(回数制限つき)。ただし workers_dev を false にして、名前入りの公開URLは作らない

  2. 画面は Pages で公開する

  3. Pages の /api/ に来たアクセスは「Service Binding」という機能で Worker に直接渡す

// functions/api/[[path]].ts
export const onRequest: PagesFunction<PagesEnv> = ({ request, env }) => env.API.fetch(request);

これで、URLは名前なしの pages.dev、回数制限もそのまま、という形にできました!
公開するときは、URLに何が出るかも最初に確認しておいた方がいいです(笑)

5. 使い方

  1. https://spotify-to-youtube-80b.pages.dev を開く

  2. Spotify でプレイリストの「共有」→「リンクをコピー」して貼る

  3. 「変換」を押す(1曲ずつ検索していくので少し待つ)

  4. 「YouTubeプレイリストを作る」→「YouTubeで開く」で再生

  5. 「友達に送るリンクをコピー」で LINE などに貼れば、友達もそのまま聴ける

「audio を付けて検索」にチェックを入れると、MVより音源の動画が出やすくなります。

注意点もあります。

  • 非公開のプレイリストは読み込めません

  • 長いプレイリストは途中(100曲くらい)までになります

  • たまに違う動画(カバーやライブ版)が当たるので、表のURLを書き換えて直してください

  • 非公式ツールで、Spotify・YouTube とは関係ありません

最後に

「友達に曲を送るのがめんどくさい」っていう小さい不満から作ったツールですが、公開まで1日でできました!
特に、Python で作ったものを TypeScript に書き直して Cloudflare に載せる流れは、他のツールでも使えるのでおすすめです。

自分が「めんどくさいな」と思ったことは、だいたい他の人もめんどくさいと思ってるので、ぜひ何か作って公開してみてください!
質問があればコメントで聞いてください。ぜひ参考にしてください!

ここから下は、今回作った Cloudflare 版の全部のコードです。コピペでそのまま動かせます!

全部のコードはこちら

フォルダ構成はこうなっています。

あなたへのおすすめ