Expose Suno MP3 candidate diagnostics
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
// ==UserScript==
|
// ==UserScript==
|
||||||
// @name ChatGPT to Suno Prompt Copier
|
// @name ChatGPT to Suno Prompt Copier
|
||||||
// @namespace local.suno-helper
|
// @namespace local.suno-helper
|
||||||
// @version 0.8.1
|
// @version 0.8.2
|
||||||
// @description Copy structured ChatGPT song prompt versions into Suno fields.
|
// @description Copy structured ChatGPT song prompt versions into Suno fields.
|
||||||
// @author local
|
// @author local
|
||||||
// @match https://chatgpt.com/*
|
// @match https://chatgpt.com/*
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
(function () {
|
(function () {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const SCRIPT_VERSION = "0.8.1";
|
const SCRIPT_VERSION = "0.8.2";
|
||||||
const STORAGE_KEY = "chatgptSunoPromptSlots";
|
const STORAGE_KEY = "chatgptSunoPromptSlots";
|
||||||
const SLOT_COUNT = 2;
|
const SLOT_COUNT = 2;
|
||||||
const isChatGPT = location.hostname.includes("chatgpt.com") || location.hostname.includes("chat.openai.com");
|
const isChatGPT = location.hostname.includes("chatgpt.com") || location.hostname.includes("chat.openai.com");
|
||||||
@@ -551,6 +551,30 @@
|
|||||||
return unique([...String(text || "").matchAll(pattern)].map((match) => match[0].replace(/\\u002F/g, "/")));
|
return unique([...String(text || "").matchAll(pattern)].map((match) => match[0].replace(/\\u002F/g, "/")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function collectStringValues(value, output = []) {
|
||||||
|
if (value == null) return output;
|
||||||
|
if (typeof value === "string") {
|
||||||
|
output.push(value);
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
for (const item of value) collectStringValues(item, output);
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
if (typeof value === "object") {
|
||||||
|
for (const item of Object.values(value)) collectStringValues(item, output);
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractAudioUrlsFromValue(value) {
|
||||||
|
const text = collectStringValues(value).join("\n");
|
||||||
|
return unique([
|
||||||
|
...extractUrls(text, /https?:\\?\/\\?\/cdn[0-9]*\.suno\.ai\\?\/[^"' <>)]+?\.(?:mp3|m4a|oga|ogg)(?:\?[^"' <>)]+)?/gi),
|
||||||
|
...extractUrls(text, /https?:\/\/[^"' <>)]+?\.(?:mp3|m4a|oga|ogg)(?:\?[^"' <>)]+)?/gi),
|
||||||
|
].map((url) => normalizeSunoMediaUrl(url.replace(/\\\//g, "/"))));
|
||||||
|
}
|
||||||
|
|
||||||
function readJsonScripts() {
|
function readJsonScripts() {
|
||||||
const results = [];
|
const results = [];
|
||||||
for (const script of document.querySelectorAll("script")) {
|
for (const script of document.querySelectorAll("script")) {
|
||||||
@@ -604,7 +628,8 @@
|
|||||||
const title = String(firstValue(object, ["title", "name"]) || id || "suno-track").trim();
|
const title = String(firstValue(object, ["title", "name"]) || id || "suno-track").trim();
|
||||||
const imageUrl = firstValue(object, ["image_url", "imageUrl", "image_large_url", "imageLargeUrl", "cover_url", "coverUrl"]);
|
const imageUrl = firstValue(object, ["image_url", "imageUrl", "image_large_url", "imageLargeUrl", "cover_url", "coverUrl"]);
|
||||||
const audioPath = firstValue(object, ["audio_url", "audioUrl", "stream_audio_url", "streamAudioUrl", "play_url", "playUrl", "play_path", "playPath", "mp3_url", "mp3Url", "video_url", "videoUrl"]);
|
const audioPath = firstValue(object, ["audio_url", "audioUrl", "stream_audio_url", "streamAudioUrl", "play_url", "playUrl", "play_path", "playPath", "mp3_url", "mp3Url", "video_url", "videoUrl"]);
|
||||||
const audioUrl = normalizeSunoMediaUrl(audioPath);
|
const audioUrls = extractAudioUrlsFromValue(object);
|
||||||
|
const audioUrl = normalizeSunoMediaUrl(audioPath) || audioUrls[0] || "";
|
||||||
const wavPath = firstValue(object, ["wav_url", "wavUrl", "download_url", "downloadUrl"]);
|
const wavPath = firstValue(object, ["wav_url", "wavUrl", "download_url", "downloadUrl"]);
|
||||||
const wavUrl = normalizeSunoMediaUrl(wavPath);
|
const wavUrl = normalizeSunoMediaUrl(wavPath);
|
||||||
const lyrics = firstValue(object, ["prompt", "lyrics", "lyric", "text"]);
|
const lyrics = firstValue(object, ["prompt", "lyrics", "lyric", "text"]);
|
||||||
@@ -624,6 +649,7 @@
|
|||||||
createdAt,
|
createdAt,
|
||||||
owner: owner || ownerFromUser,
|
owner: owner || ownerFromUser,
|
||||||
audioUrl,
|
audioUrl,
|
||||||
|
detectedAudioUrls: audioUrls,
|
||||||
wavUrl,
|
wavUrl,
|
||||||
imageUrl,
|
imageUrl,
|
||||||
pageUrl: location.href,
|
pageUrl: location.href,
|
||||||
@@ -637,6 +663,7 @@
|
|||||||
for (const key of ["title", "lyrics", "style", "model", "createdAt", "audioUrl", "wavUrl", "imageUrl", "pageUrl"]) {
|
for (const key of ["title", "lyrics", "style", "model", "createdAt", "audioUrl", "wavUrl", "imageUrl", "pageUrl"]) {
|
||||||
if (!target[key] && source[key]) target[key] = source[key];
|
if (!target[key] && source[key]) target[key] = source[key];
|
||||||
}
|
}
|
||||||
|
target.detectedAudioUrls = unique([...(target.detectedAudioUrls || []), ...(source.detectedAudioUrls || [])]);
|
||||||
target.metadata = target.metadata && Object.keys(target.metadata).length ? target.metadata : source.metadata;
|
target.metadata = target.metadata && Object.keys(target.metadata).length ? target.metadata : source.metadata;
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
@@ -1098,7 +1125,13 @@
|
|||||||
function getMp3Candidates(track) {
|
function getMp3Candidates(track) {
|
||||||
const candidates = [];
|
const candidates = [];
|
||||||
if (track.audioUrl && !/\.wav(?:\?|$)/i.test(track.audioUrl)) candidates.push(track.audioUrl);
|
if (track.audioUrl && !/\.wav(?:\?|$)/i.test(track.audioUrl)) candidates.push(track.audioUrl);
|
||||||
|
for (const url of track.detectedAudioUrls || []) {
|
||||||
|
if (url && !/\.wav(?:\?|$)/i.test(url)) candidates.push(url);
|
||||||
|
}
|
||||||
const metadata = track.metadata || {};
|
const metadata = track.metadata || {};
|
||||||
|
for (const url of extractAudioUrlsFromValue(metadata)) {
|
||||||
|
if (url && !/\.wav(?:\?|$)/i.test(url)) candidates.push(url);
|
||||||
|
}
|
||||||
for (const value of [
|
for (const value of [
|
||||||
metadata.audio_url,
|
metadata.audio_url,
|
||||||
metadata.audioUrl,
|
metadata.audioUrl,
|
||||||
@@ -1556,9 +1589,11 @@
|
|||||||
selectedTrack: selectedTrack ? {
|
selectedTrack: selectedTrack ? {
|
||||||
id: selectedTrack.id || "",
|
id: selectedTrack.id || "",
|
||||||
title: selectedTrack.title || "",
|
title: selectedTrack.title || "",
|
||||||
|
audioUrl: selectedTrack.audioUrl || "",
|
||||||
hasWavUrl: Boolean(selectedTrack.wavUrl),
|
hasWavUrl: Boolean(selectedTrack.wavUrl),
|
||||||
hasImageUrl: Boolean(selectedTrack.imageUrl),
|
hasImageUrl: Boolean(selectedTrack.imageUrl),
|
||||||
hasLyrics: Boolean(selectedTrack.lyrics),
|
hasLyrics: Boolean(selectedTrack.lyrics),
|
||||||
|
mp3Candidates: getMp3Candidates(selectedTrack).slice(0, 10),
|
||||||
} : null,
|
} : null,
|
||||||
capturedSunoResponses: capturedSunoResponses.length,
|
capturedSunoResponses: capturedSunoResponses.length,
|
||||||
companion: healthError ? { ok: false, error: healthError } : health,
|
companion: healthError ? { ok: false, error: healthError } : health,
|
||||||
|
|||||||
Reference in New Issue
Block a user