上一篇「輕鬆複製 YouTube 播放清單」說明了 YouTube 播放清單如何利用 YouTube Music,手動複製播放清單的操作技巧。本篇則更進一步,把這個流程程式化。
網路上找到一些非官方 API 工具,執行環境有 NodeJs、C++,不過最穩定的版本是「ytmusicapi」,執行環境為 Python,更新維護最為頻繁。
因此本篇不太適合新手,做起來有點難度,需要具備不少基本概念,適合有點前端背景,加上略懂 Python 的工程師,以下會盡量說明流程所有處理要點。
一、ytmusicapi 介紹 + API 說明書
1. 功能介紹- Github 官網:ytmusicapi
- 是一個 YouTube Music「非官方 API」
- 執行環境為 Python 3
- 模擬 YouTube Music 網頁端的操作,藉由使用者的 cookie 進行身份驗證
- 執行搜尋及推薦音樂
- 取得符合心情和類型的播放列表
- 收藏庫的管理
- 播放清單的管理
二、準備 Python 環境
1. 下載 官網建議安裝 Python 3.10 或更高的版本:- 官網:Python
- 下載網址:Download
- Windows 下載連結:python-3.13.15-amd64.exe
python --version
3. 教學
如果安裝流程需要完整教學,可參考這篇「Python 安裝教學與驗證」。
三、安裝 ytmusicapi + oAuth 驗證
1. 安裝 安裝完 python 後,windows 開啟命令字元,執行以下指令即可安裝 ytmusicapi:pip install ytmusicapi
日後執行上如果遇到問題,有可能需要更新到最新版 api,可執行以下指令:
pip install --upgrade ytmusicapi
3. oAuth 驗證
執行 api 需要身份驗證,官方提供了兩種驗證方式。第一種方式為「oAuth 驗證」,不過直接說結論,不推薦這個方法,因為我用了後執行 api 總是失敗。
如果還是想嘗試的話,可以閱讀上面的官網說明文件連結,或是參考以下執行步驟:
- 參考「啟用 Google API 流程」,建立專案及啟用「Google YouTube Data API」
- 參考「處理 Google OAuth 憑證流程」,但是選擇「應用程式類型」時,ytmusicapi 的說明文件指出,必須選擇「電視和受限制的輸入裝置」,否則怎麼執行都會報錯
ytmusicapi oauth
按照畫面說明,輸入剛剛建立的 client_id 以及 client_secret,然後繼續按照說明完成整個驗證流程(會開啟瀏覽器驗證),系統會自動建立一個 四、瀏覽器驗證
接下來說明「瀏覽器驗證」的操作流程,同樣相當麻煩,所以本文開頭有建議具備前端相關知識比較好。 1. YouTube Music 網頁 本篇以最常見的 Chrome 瀏覽器操作為例,首先進入 「YouTube Music 首頁,並記得登入你的 Google 帳號。 2. 複製 header 資訊 接著按
- 切換到「網路」分頁
- 過濾器(漏斗圖示)輸入
/browse 進行篩選 - 一開始應該不會有篩選結果,不過沒關係,不斷將網頁往下捲,直到看到篩選結果即可
- 如上圖,對著篩選結果的紅色底線網址,按右鍵
- 選擇「Copy」→「Copy as fetch(Node.js)」,可以把 header 資訊複製出來
- 開啟記事軟體,貼上剛剛複製的所有文字內容
{
"Accept": "*/*",
"Authorization": "貼上 Authorization 內容",
"Content-Type": "application/json",
"X-Goog-AuthUser": "0",
"x-origin": "https://music.youtube.com",
"Cookie" : "貼上 Cookie 內容"
}
這個 五、範例程式碼
所有準備動作完成後,以下提供一個複製 YouTube 播放清單,並進行排序的範例程式碼:"""
複製並排序 YouTube 播放清單
請先完成瀏覽器驗證檔 browser.json 並放在此 py 檔同資料夾
"""
# ========== 參數區:依需求修改以下幾個值 ==========
# 來源播放清單,填 ID 或完整網址都可以
# 例如: "PLxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
# 或: "https://www.youtube.com/playlist?list=PLxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
playlistId = "貼上你的播放清單網址或ID"
# 新播放清單是否設為不公開
# True -> PRIVATE(不公開)
# False -> PUBLIC(公開)
private = True
# 是否依標題字串排序
# True -> 依標題 A-Z 排序
# False -> 保留原本順序
sortTitle = False
import re
from ytmusicapi import YTMusic
# ================================================
def extract_playlist_id(url_or_id: str) -> str:
"""從網址或直接輸入的 ID 取出 playlist id"""
match = re.search(r"[?&]list=([A-Za-z0-9_-]+)", url_or_id)
if match:
return match.group(1)
return url_or_id.strip()
def sort_tracks_by_title(tracks: list) -> list:
"""依標題排序,取不到標題的排最後"""
return sorted(tracks, key=lambda t: (t.get("title") or "").lower())
def extract_video_id_from_thumbnail(track: dict) -> str | None:
"""
非 YouTube Music 收錄的一般 YouTube 影片,track['videoId'] 常常是 None。
這種情況改用縮圖網址(格式固定為 .../vi/{videoId}/...)還原出 videoId。
"""
thumbnails = track.get("thumbnails") or []
if not thumbnails:
return None
match = re.search(r"/vi/([^/]+)/", thumbnails[0].get("url", ""))
return match.group(1) if match else None
def get_video_id(track: dict) -> str | None:
"""先試 track 本身的 videoId,沒有的話再從縮圖網址還原"""
return track.get("videoId") or extract_video_id_from_thumbnail(track)
def main():
yt = YTMusic("browser.json")
source_id = extract_playlist_id(playlistId)
print(f"讀取來源播放清單 {source_id} ...")
playlist = yt.get_playlist(source_id, limit=None)
tracks = playlist["tracks"]
# title / description 若原本清單沒有值,一律改成 "",避免 create_playlist 出錯
original_title = playlist.get("title") or ""
original_description = playlist.get("description") or ""
print(f"共取得 {len(tracks)} 個影片")
final_tracks = sort_tracks_by_title(tracks) if sortTitle else tracks
video_ids = [get_video_id(t) for t in final_tracks]
video_ids = [v for v in video_ids if v] # 過濾掉真的找不到 videoId 的曲目
print(f"成功取得 videoId 的影片數: {len(video_ids)} / {len(final_tracks)}")
privacy_status = "PRIVATE" if private else "PUBLIC"
print(f"建立新播放清單「{original_title}」...")
new_playlist_id = yt.create_playlist(
title=original_title,
description=original_description,
privacy_status=privacy_status,
video_ids=video_ids,
)
new_url = f"https://www.youtube.com/playlist?list={new_playlist_id}"
print("\n完成!")
print(f"新播放清單網址: {new_url}")
if __name__ == "__main__":
main()
以上內容請存為 - 請修改三個紅字參數的值:
- playlistId:綠字部份請改為要複製的播放清單網址或ID,範例請見註解
- private:新的播放清單若不公開設定為 True,若要公開設定為 False
- sortTitle:若要依照影片標題排序設定為 True,反之設定為 False
- 瀏覽器驗證檔
browser.json 請放在此.py 檔同資料夾 - 執行成功後,會顯示新建立的播放清單網址
- 所有執行邏輯請見註解說明
更多 YouTube 相關文章:
沒有留言:
張貼留言注意事項:
◎ 勾選「通知我」可收到後續回覆的mail!
◎ 請在相關文章留言,與文章無關的主題可至「Blogger 社團」提問。
◎ 請避免使用 Safari 瀏覽器,否則無法登入 Google 帳號留言(只能匿名留言)!
◎ 提問若無法提供足夠的資訊供判斷,可能會被無視。建議先參考這篇「Blogger 提問技巧及注意事項」。
◎ CSS 相關問題非免費諮詢,建議使用「Chrome 開發人員工具」尋找答案。
◎ 手機版相關問題請參考「Blogger 行動版範本的特質」→「三、行動版範本不一定能執行網頁版工具」;或參考「Blogger 行動版範本修改技巧 」,或本站 Blogger 行動版標籤相關文章。
◎ 非官方範本問題、或貴站為商業網站,請參考「Blogger 免費諮詢 + 付費諮詢」
◎ 若是使用官方 RWD 範本,請參考「Blogger 推出全新自適應 RWD 官方範本及佈景主題」→ 不建議對範本進行修改!
◎ 若留言要輸入語法,"<"、">"這兩個符號請用其他符號代替,否則語法會消失!
◎ 為了過濾垃圾留言,所有留言不會即時發佈,請稍待片刻。
◎ 本站「已關閉自刪留言功能」。