Last active
July 15, 2025 10:19
-
-
Save tzengyuxio/483388b0eb95d3fb8c81d547e680f354 to your computer and use it in GitHub Desktop.
Extract Song Details from SUNO to JSON
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* v2 bulk-suno.js | |
* 🎼 擷取 React App 中的歌曲資訊(透過 Fiber Tree) | |
* | |
* ✅ 使用方式: | |
* 1. 確保已安裝並啟用 React Developer Tools(Chrome 擴充) | |
* 2. 展開至少一首歌詞(讓歌詞與 metadata 被載入) | |
* 3. 打開開發者工具 Console,貼上此腳本執行 | |
* 4. 成功後會將 JSON 格式資料自動下載並複製至剪貼簿 | |
* | |
* ✅ 每筆歌曲包含欄位: | |
* - id | |
* - title | |
* - styleDescription | |
* - lyrics | |
* - createdAt | |
* - isLiked | |
* - imageUrl | |
* - videoUrl | |
* - duration | |
* - language | |
* - artist | |
*/ | |
((filenamePrefix) => { | |
const lyricsMap = new Map(); | |
function traverseFiber(node) { | |
if (!node) return; | |
const props = node.memoizedProps; | |
if (props && props.clip && props.clip.metadata?.prompt) { | |
const target = props.clip["[[Target]]"] || props.clip; | |
const meta = target.metadata || {}; | |
const id = target.id; | |
const title = target.title; | |
const lyrics = meta.prompt?.trim(); | |
const styleDescription = meta.tags?.trim?.() || meta.tags; | |
const createdAt = target.created_at; | |
const isLiked = target.is_liked; | |
const imageUrl = target.image_url; | |
const videoUrl = target.video_url; | |
const duration = meta.duration; | |
const language = meta.language; | |
const artist = meta.artist; | |
if (id && title && lyrics && !lyricsMap.has(id)) { | |
lyricsMap.set(id, { | |
id, | |
title, | |
styleDescription, | |
lyrics, | |
createdAt, | |
isLiked, | |
imageUrl, | |
videoUrl, | |
duration, | |
language, | |
artist | |
}); | |
console.log("🎯 Found:", id, title); | |
} | |
} | |
traverseFiber(node.child); | |
traverseFiber(node.sibling); | |
} | |
try { | |
const hook = window.__REACT_DEVTOOLS_GLOBAL_HOOK__; | |
const rendererId = hook?.renderers?.keys().next().value; | |
const roots = [...(hook?.getFiberRoots?.(rendererId) || [])]; | |
if (!roots.length) { | |
console.error("❌ 無法取得 Fiber Roots,請先載入 React DevTools"); | |
return; | |
} | |
for (const root of roots) { | |
traverseFiber(root.current); | |
} | |
const results = Array.from(lyricsMap.values()); | |
if (results.length === 0) { | |
console.warn("⚠️ 沒有成功抓取任何歌曲資料"); | |
} else { | |
const json = JSON.stringify(results, null, 2); | |
// ✅ 複製到剪貼簿 | |
navigator.clipboard.writeText(json) | |
.then(() => console.log("📋 已複製至剪貼簿")) | |
.catch(err => console.warn("⚠️ 剪貼簿複製失敗:", err)); | |
// ✅ 自動下載 | |
const blob = new Blob([json], { type: "application/json" }); | |
const url = URL.createObjectURL(blob); | |
const a = document.createElement("a"); | |
a.href = url; | |
const filename = filenamePrefix | |
? `${filenamePrefix}_production_notes.json` | |
: `production_notes_${Date.now()}.json`; | |
a.download = filename; | |
a.click(); | |
URL.revokeObjectURL(url); | |
console.log("✅ 共擷取", results.length, "筆資料,已下載 JSON"); | |
} | |
} catch (err) { | |
console.error("❌ 錯誤:", err); | |
} | |
})("suno"); // 如果你要自訂名稱,把 "suno" 改掉,或傳入空值、刪掉參數使用 timestamp 命名 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment