Add cumulative selectable Suno track list
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.8
|
// @version 0.8.9
|
||||||
// @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/*
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
(function () {
|
(function () {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const SCRIPT_VERSION = "0.8.8";
|
const SCRIPT_VERSION = "0.8.9";
|
||||||
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");
|
||||||
@@ -115,7 +115,8 @@
|
|||||||
right: 16px;
|
right: 16px;
|
||||||
bottom: 16px;
|
bottom: 16px;
|
||||||
z-index: 2147483647;
|
z-index: 2147483647;
|
||||||
width: min(360px, calc(100vw - 32px));
|
width: min(560px, calc(100vw - 32px));
|
||||||
|
max-height: min(86vh, 860px);
|
||||||
color: #f5f7fb;
|
color: #f5f7fb;
|
||||||
background: rgba(16, 18, 24, 0.94);
|
background: rgba(16, 18, 24, 0.94);
|
||||||
border: 1px solid rgba(255, 255, 255, 0.14);
|
border: 1px solid rgba(255, 255, 255, 0.14);
|
||||||
@@ -124,6 +125,9 @@
|
|||||||
font: 13px/1.45 system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
font: 13px/1.45 system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
#cgs-panel.cgs-suno {
|
||||||
|
width: min(620px, calc(100vw - 32px));
|
||||||
|
}
|
||||||
#cgs-panel.cgs-chatgpt {
|
#cgs-panel.cgs-chatgpt {
|
||||||
right: 18px;
|
right: 18px;
|
||||||
top: 72px;
|
top: 72px;
|
||||||
@@ -144,7 +148,11 @@
|
|||||||
background: rgba(255, 255, 255, 0.06);
|
background: rgba(255, 255, 255, 0.06);
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
}
|
}
|
||||||
.cgs-body { padding: 10px 12px 12px; }
|
.cgs-body {
|
||||||
|
padding: 10px 12px 12px;
|
||||||
|
max-height: calc(min(86vh, 860px) - 48px);
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
.cgs-row {
|
.cgs-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
@@ -197,6 +205,47 @@
|
|||||||
padding: 4px 7px;
|
padding: 4px 7px;
|
||||||
font: inherit;
|
font: inherit;
|
||||||
}
|
}
|
||||||
|
.cgs-track-list {
|
||||||
|
margin-top: 8px;
|
||||||
|
max-height: 300px;
|
||||||
|
overflow: auto;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.14);
|
||||||
|
border-radius: 8px;
|
||||||
|
background: rgba(0, 0, 0, 0.18);
|
||||||
|
}
|
||||||
|
.cgs-track-item {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 28px minmax(0, 1fr) auto;
|
||||||
|
gap: 8px;
|
||||||
|
align-items: center;
|
||||||
|
min-height: 38px;
|
||||||
|
padding: 7px 8px;
|
||||||
|
border-bottom: 1px solid rgba(255, 255, 255, 0.07);
|
||||||
|
cursor: default;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
.cgs-track-item:last-child { border-bottom: 0; }
|
||||||
|
.cgs-track-item:hover { background: rgba(255, 255, 255, 0.08); }
|
||||||
|
.cgs-track-item.cgs-selected {
|
||||||
|
background: rgba(47, 124, 246, 0.28);
|
||||||
|
outline: 1px solid rgba(91, 154, 255, 0.55);
|
||||||
|
outline-offset: -1px;
|
||||||
|
}
|
||||||
|
.cgs-track-index { color: #93a4bd; text-align: right; font-variant-numeric: tabular-nums; }
|
||||||
|
.cgs-track-title {
|
||||||
|
min-width: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
color: #f5f7fb;
|
||||||
|
font-weight: 650;
|
||||||
|
}
|
||||||
|
.cgs-track-meta { color: #94a3b8; font-size: 11px; }
|
||||||
|
.cgs-track-badge {
|
||||||
|
color: #b7c9ff;
|
||||||
|
font-size: 11px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
`);
|
`);
|
||||||
|
|
||||||
function createPanel(title, mode = "") {
|
function createPanel(title, mode = "") {
|
||||||
@@ -718,11 +767,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function trackMatchesVisibleRows(track, rows) {
|
function trackMatchesVisibleRows(track, rows) {
|
||||||
if (!rows.length) return false;
|
return getTrackVisibleIndex(track, rows) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTrackVisibleIndex(track, rows) {
|
||||||
|
if (!rows.length) return -1;
|
||||||
const title = normalizeMatchText(track.title);
|
const title = normalizeMatchText(track.title);
|
||||||
const style = normalizeMatchText(track.style || track.lyrics || "");
|
const style = normalizeMatchText(track.style || track.lyrics || "");
|
||||||
if (!title || title.length > 160) return false;
|
if (!title || title.length > 160) return -1;
|
||||||
return rows.some((row) => {
|
return rows.findIndex((row) => {
|
||||||
if (!row.normalized.includes(title)) return false;
|
if (!row.normalized.includes(title)) return false;
|
||||||
if (!style) return true;
|
if (!style) return true;
|
||||||
const styleNeedle = style.slice(0, Math.min(42, style.length));
|
const styleNeedle = style.slice(0, Math.min(42, style.length));
|
||||||
@@ -772,7 +825,7 @@
|
|||||||
.filter((track) => track.id || track.audioUrl || track.imageUrl)
|
.filter((track) => track.id || track.audioUrl || track.imageUrl)
|
||||||
.filter((track) => trackMatchesCurrentUser(track, currentUser))
|
.filter((track) => trackMatchesCurrentUser(track, currentUser))
|
||||||
.filter((track) => trackMatchesVisibleRows(track, visibleRows))
|
.filter((track) => trackMatchesVisibleRows(track, visibleRows))
|
||||||
.sort((a, b) => String(a.title).localeCompare(String(b.title), "ko"));
|
.sort((a, b) => getTrackVisibleIndex(a, visibleRows) - getTrackVisibleIndex(b, visibleRows));
|
||||||
}
|
}
|
||||||
|
|
||||||
function visibleSunoRowsHint() {
|
function visibleSunoRowsHint() {
|
||||||
@@ -1505,7 +1558,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function bootSuno() {
|
async function bootSuno() {
|
||||||
const body = createPanel("Suno Prompt Paste");
|
const body = createPanel("Suno Prompt Paste", "cgs-suno");
|
||||||
const slots = await readSlots();
|
const slots = await readSlots();
|
||||||
body.innerHTML = `
|
body.innerHTML = `
|
||||||
<div class="cgs-muted" data-cgs-summary></div>
|
<div class="cgs-muted" data-cgs-summary></div>
|
||||||
@@ -1521,13 +1574,16 @@
|
|||||||
<div class="cgs-row">
|
<div class="cgs-row">
|
||||||
<button class="cgs-btn cgs-wide" type="button" data-cgs-scan-library>곡 감지</button>
|
<button class="cgs-btn cgs-wide" type="button" data-cgs-scan-library>곡 감지</button>
|
||||||
</div>
|
</div>
|
||||||
<select class="cgs-select" data-cgs-library-track>
|
<div class="cgs-muted" data-cgs-selection-summary></div>
|
||||||
<option value="">감지된 곡 없음</option>
|
<div class="cgs-track-list" data-cgs-track-list></div>
|
||||||
</select>
|
|
||||||
<div class="cgs-row">
|
<div class="cgs-row">
|
||||||
<button class="cgs-btn cgs-wide" type="button" data-cgs-process-one-mp3>선택 1곡 MP3</button>
|
<button class="cgs-btn cgs-wide" type="button" data-cgs-process-one-mp3>선택 1곡 MP3</button>
|
||||||
<button class="cgs-btn cgs-wide" type="button" data-cgs-process-one-wav>선택 1곡 WAV</button>
|
<button class="cgs-btn cgs-wide" type="button" data-cgs-process-one-wav>선택 1곡 WAV</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="cgs-row">
|
||||||
|
<button class="cgs-btn cgs-primary cgs-wide" type="button" data-cgs-process-selected-mp3>선택항목 MP3</button>
|
||||||
|
<button class="cgs-btn cgs-primary cgs-wide" type="button" data-cgs-process-selected-wav>선택항목 WAV</button>
|
||||||
|
</div>
|
||||||
<div class="cgs-row">
|
<div class="cgs-row">
|
||||||
<button class="cgs-btn cgs-wide" type="button" data-cgs-test-companion>연결 테스트</button>
|
<button class="cgs-btn cgs-wide" type="button" data-cgs-test-companion>연결 테스트</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -1535,27 +1591,81 @@
|
|||||||
<button class="cgs-btn cgs-wide" type="button" data-cgs-copy-diagnostics>진단 복사</button>
|
<button class="cgs-btn cgs-wide" type="button" data-cgs-copy-diagnostics>진단 복사</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="cgs-row">
|
<div class="cgs-row">
|
||||||
<button class="cgs-btn cgs-primary cgs-wide" type="button" data-cgs-process-library-mp3>MP3 일괄 + 메타데이터</button>
|
<button class="cgs-btn cgs-primary cgs-wide" type="button" data-cgs-process-library-mp3>누적 전체 MP3</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="cgs-row">
|
<div class="cgs-row">
|
||||||
<button class="cgs-btn cgs-primary cgs-wide" type="button" data-cgs-process-library-wav>WAV 일괄 + FLAC 메타</button>
|
<button class="cgs-btn cgs-primary cgs-wide" type="button" data-cgs-process-library-wav>누적 전체 WAV</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="cgs-status"></div>
|
<div class="cgs-status"></div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const summary = body.querySelector("[data-cgs-summary]");
|
const summary = body.querySelector("[data-cgs-summary]");
|
||||||
|
const selectionSummary = body.querySelector("[data-cgs-selection-summary]");
|
||||||
const slotSelect = body.querySelector("[data-cgs-slot]");
|
const slotSelect = body.querySelector("[data-cgs-slot]");
|
||||||
const libraryTrackSelect = body.querySelector("[data-cgs-library-track]");
|
const trackList = body.querySelector("[data-cgs-track-list]");
|
||||||
let libraryTracks = [];
|
let libraryTracks = [];
|
||||||
const renderLibraryTrackSelect = () => {
|
const libraryTrackMap = new Map();
|
||||||
|
const selectedTrackIds = new Set();
|
||||||
|
let lastSelectedIndex = -1;
|
||||||
|
let autoScanTimer = 0;
|
||||||
|
|
||||||
|
const getSelectedTracks = () => libraryTracks.filter((track) => selectedTrackIds.has(track.id));
|
||||||
|
const mergeLibraryTracks = (tracks) => {
|
||||||
|
for (const track of tracks) {
|
||||||
|
if (!track.id) continue;
|
||||||
|
if (libraryTrackMap.has(track.id)) {
|
||||||
|
libraryTrackMap.set(track.id, mergeTrack(libraryTrackMap.get(track.id), track));
|
||||||
|
} else {
|
||||||
|
libraryTrackMap.set(track.id, track);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
libraryTracks = [...libraryTrackMap.values()];
|
||||||
|
};
|
||||||
|
const renderLibraryTrackList = () => {
|
||||||
|
const selectedCount = selectedTrackIds.size;
|
||||||
|
selectionSummary.textContent = libraryTracks.length
|
||||||
|
? `누적 ${libraryTracks.length}곡 / 선택 ${selectedCount}곡`
|
||||||
|
: "누적된 곡 없음. 스크롤하면서 곡 감지를 눌러줘.";
|
||||||
if (!libraryTracks.length) {
|
if (!libraryTracks.length) {
|
||||||
libraryTrackSelect.innerHTML = `<option value="">감지된 곡 없음</option>`;
|
trackList.innerHTML = `<div class="cgs-track-item"><div></div><div class="cgs-track-meta">감지된 곡 없음</div><div></div></div>`;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
libraryTrackSelect.innerHTML = libraryTracks
|
trackList.innerHTML = libraryTracks
|
||||||
.map((track, index) => `<option value="${index}">${escapeHtml(trackOptionLabel(track, index))}</option>`)
|
.map((track, index) => {
|
||||||
|
const selected = selectedTrackIds.has(track.id);
|
||||||
|
const badge = [
|
||||||
|
track.audioUrl ? "MP3" : "",
|
||||||
|
track.wavUrl ? "WAV" : "",
|
||||||
|
track.imageUrl ? "IMG" : "",
|
||||||
|
].filter(Boolean).join(" ");
|
||||||
|
return `
|
||||||
|
<div class="cgs-track-item ${selected ? "cgs-selected" : ""}" data-cgs-track-index="${index}" title="${escapeHtml(track.id || "")}">
|
||||||
|
<div class="cgs-track-index">${index + 1}</div>
|
||||||
|
<div>
|
||||||
|
<div class="cgs-track-title">${escapeHtml(track.title || track.id || "제목 없음")}</div>
|
||||||
|
<div class="cgs-track-meta">${escapeHtml((track.style || track.lyrics || track.id || "").slice(0, 110))}</div>
|
||||||
|
</div>
|
||||||
|
<div class="cgs-track-badge">${escapeHtml(badge || "ID")}</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
})
|
||||||
.join("");
|
.join("");
|
||||||
};
|
};
|
||||||
|
const setSelectedRange = (from, to) => {
|
||||||
|
const start = Math.max(0, Math.min(from, to));
|
||||||
|
const end = Math.min(libraryTracks.length - 1, Math.max(from, to));
|
||||||
|
for (let index = start; index <= end; index += 1) {
|
||||||
|
if (libraryTracks[index]?.id) selectedTrackIds.add(libraryTracks[index].id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const scanAndMergeVisibleTracks = () => {
|
||||||
|
const scannedTracks = scanSunoLibraryTracks();
|
||||||
|
const before = libraryTracks.length;
|
||||||
|
mergeLibraryTracks(scannedTracks);
|
||||||
|
renderLibraryTrackList();
|
||||||
|
updateSummary();
|
||||||
|
return { scannedTracks, added: libraryTracks.length - before };
|
||||||
|
};
|
||||||
const updateSummary = () => {
|
const updateSummary = () => {
|
||||||
const payload = slots[Number(slotSelect.value)];
|
const payload = slots[Number(slotSelect.value)];
|
||||||
const track = findCurrentSunoTrack();
|
const track = findCurrentSunoTrack();
|
||||||
@@ -1564,7 +1674,7 @@
|
|||||||
const trackText = track.id || track.audioUrl || track.imageUrl ? ` / 곡 감지: ${track.title || track.id}` : " / 곡 미감지";
|
const trackText = track.id || track.audioUrl || track.imageUrl ? ` / 곡 감지: ${track.title || track.id}` : " / 곡 미감지";
|
||||||
summary.textContent = promptText + trackText + libraryText;
|
summary.textContent = promptText + trackText + libraryText;
|
||||||
};
|
};
|
||||||
renderLibraryTrackSelect();
|
renderLibraryTrackList();
|
||||||
updateSummary();
|
updateSummary();
|
||||||
slotSelect.addEventListener("change", updateSummary);
|
slotSelect.addEventListener("change", updateSummary);
|
||||||
|
|
||||||
@@ -1593,13 +1703,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
body.querySelector("[data-cgs-scan-library]").addEventListener("click", () => {
|
body.querySelector("[data-cgs-scan-library]").addEventListener("click", () => {
|
||||||
libraryTracks = scanSunoLibraryTracks();
|
const { scannedTracks, added } = scanAndMergeVisibleTracks();
|
||||||
renderLibraryTrackSelect();
|
const sample = scannedTracks.slice(0, 3).map((track) => track.title || track.id).join(", ");
|
||||||
updateSummary();
|
if (scannedTracks.length) {
|
||||||
const sample = libraryTracks.slice(0, 3).map((track) => track.title || track.id).join(", ");
|
|
||||||
if (libraryTracks.length) {
|
|
||||||
const visibleCount = getVisibleLibraryRows().length;
|
const visibleCount = getVisibleLibraryRows().length;
|
||||||
setStatus(body, `${libraryTracks.length}곡 감지: ${sample} / 화면 행 ${visibleCount}개 기준`);
|
setStatus(body, `이번 화면 ${scannedTracks.length}곡 감지, 누적 ${libraryTracks.length}곡 (+${added}): ${sample} / 화면 행 ${visibleCount}개 기준`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const visibleHints = visibleSunoRowsHint();
|
const visibleHints = visibleSunoRowsHint();
|
||||||
@@ -1607,14 +1715,46 @@
|
|||||||
setStatus(body, `${networkHint} 목록 새로고침이나 스크롤 후 다시 눌러봐. 화면 텍스트: ${visibleHints.join(", ")}`);
|
setStatus(body, `${networkHint} 목록 새로고침이나 스크롤 후 다시 눌러봐. 화면 텍스트: ${visibleHints.join(", ")}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const scheduleAutoScan = () => {
|
||||||
|
clearTimeout(autoScanTimer);
|
||||||
|
autoScanTimer = setTimeout(() => {
|
||||||
|
const result = scanAndMergeVisibleTracks();
|
||||||
|
if (result.added > 0) {
|
||||||
|
setStatus(body, `스크롤 감지로 ${result.added}곡 추가, 누적 ${libraryTracks.length}곡`);
|
||||||
|
}
|
||||||
|
}, 450);
|
||||||
|
};
|
||||||
|
window.addEventListener("scroll", scheduleAutoScan, { passive: true });
|
||||||
|
document.addEventListener("scroll", scheduleAutoScan, { passive: true, capture: true });
|
||||||
|
|
||||||
|
trackList.addEventListener("click", (event) => {
|
||||||
|
const item = event.target.closest("[data-cgs-track-index]");
|
||||||
|
if (!item) return;
|
||||||
|
const index = Number(item.getAttribute("data-cgs-track-index"));
|
||||||
|
const track = libraryTracks[index];
|
||||||
|
if (!track?.id) return;
|
||||||
|
if (event.shiftKey && lastSelectedIndex >= 0) {
|
||||||
|
setSelectedRange(lastSelectedIndex, index);
|
||||||
|
} else if (event.ctrlKey || event.metaKey) {
|
||||||
|
if (selectedTrackIds.has(track.id)) selectedTrackIds.delete(track.id);
|
||||||
|
else selectedTrackIds.add(track.id);
|
||||||
|
lastSelectedIndex = index;
|
||||||
|
} else {
|
||||||
|
selectedTrackIds.clear();
|
||||||
|
selectedTrackIds.add(track.id);
|
||||||
|
lastSelectedIndex = index;
|
||||||
|
}
|
||||||
|
renderLibraryTrackList();
|
||||||
|
updateSummary();
|
||||||
|
});
|
||||||
|
|
||||||
const processSelectedTrack = async (format) => {
|
const processSelectedTrack = async (format) => {
|
||||||
if (!libraryTracks.length) {
|
if (!libraryTracks.length) {
|
||||||
libraryTracks = scanSunoLibraryTracks();
|
mergeLibraryTracks(scanSunoLibraryTracks());
|
||||||
renderLibraryTrackSelect();
|
renderLibraryTrackList();
|
||||||
}
|
}
|
||||||
updateSummary();
|
updateSummary();
|
||||||
const index = Number(libraryTrackSelect.value || 0);
|
const track = getSelectedTracks()[0] || libraryTracks[0];
|
||||||
const track = libraryTracks[index];
|
|
||||||
if (!track) {
|
if (!track) {
|
||||||
setStatus(body, "선택할 감지 곡이 없어. 곡 감지를 먼저 눌러줘.");
|
setStatus(body, "선택할 감지 곡이 없어. 곡 감지를 먼저 눌러줘.");
|
||||||
return;
|
return;
|
||||||
@@ -1635,10 +1775,18 @@
|
|||||||
await processSelectedTrack("wav");
|
await processSelectedTrack("wav");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
body.querySelector("[data-cgs-process-selected-mp3]").addEventListener("click", async () => {
|
||||||
|
await processSelectedTracks("mp3");
|
||||||
|
});
|
||||||
|
|
||||||
|
body.querySelector("[data-cgs-process-selected-wav]").addEventListener("click", async () => {
|
||||||
|
await processSelectedTracks("wav");
|
||||||
|
});
|
||||||
|
|
||||||
const processLibraryTracks = async (format) => {
|
const processLibraryTracks = async (format) => {
|
||||||
if (!libraryTracks.length) {
|
if (!libraryTracks.length) {
|
||||||
libraryTracks = scanSunoLibraryTracks();
|
mergeLibraryTracks(scanSunoLibraryTracks());
|
||||||
renderLibraryTrackSelect();
|
renderLibraryTrackList();
|
||||||
}
|
}
|
||||||
updateSummary();
|
updateSummary();
|
||||||
try {
|
try {
|
||||||
@@ -1648,6 +1796,24 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const processSelectedTracks = async (format) => {
|
||||||
|
if (!libraryTracks.length) {
|
||||||
|
mergeLibraryTracks(scanSunoLibraryTracks());
|
||||||
|
renderLibraryTrackList();
|
||||||
|
}
|
||||||
|
const tracks = getSelectedTracks();
|
||||||
|
if (!tracks.length) {
|
||||||
|
setStatus(body, "선택된 곡이 없어. 목록에서 Ctrl/Shift로 고른 뒤 눌러줘.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
updateSummary();
|
||||||
|
try {
|
||||||
|
await uploadTracksToCompanion(tracks, body, format);
|
||||||
|
} catch (error) {
|
||||||
|
setStatus(body, `선택항목 ${format.toUpperCase()} 처리 실패: ${error.message || error}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
body.querySelector("[data-cgs-process-library-mp3]").addEventListener("click", async () => {
|
body.querySelector("[data-cgs-process-library-mp3]").addEventListener("click", async () => {
|
||||||
await processLibraryTracks("mp3");
|
await processLibraryTracks("mp3");
|
||||||
});
|
});
|
||||||
@@ -1662,11 +1828,11 @@
|
|||||||
|
|
||||||
body.querySelector("[data-cgs-copy-diagnostics]").addEventListener("click", async () => {
|
body.querySelector("[data-cgs-copy-diagnostics]").addEventListener("click", async () => {
|
||||||
if (!libraryTracks.length) {
|
if (!libraryTracks.length) {
|
||||||
libraryTracks = scanSunoLibraryTracks();
|
mergeLibraryTracks(scanSunoLibraryTracks());
|
||||||
renderLibraryTrackSelect();
|
renderLibraryTrackList();
|
||||||
}
|
}
|
||||||
const selectedIndex = Number(libraryTrackSelect.value || 0);
|
const selectedTracks = getSelectedTracks();
|
||||||
const selectedTrack = libraryTracks[selectedIndex];
|
const selectedTrack = selectedTracks[0] || libraryTracks[0];
|
||||||
let health = {};
|
let health = {};
|
||||||
let healthError = "";
|
let healthError = "";
|
||||||
try {
|
try {
|
||||||
@@ -1679,7 +1845,8 @@
|
|||||||
location: location.href,
|
location: location.href,
|
||||||
detectedTracks: libraryTracks.length,
|
detectedTracks: libraryTracks.length,
|
||||||
visibleRows: getVisibleLibraryRows().length,
|
visibleRows: getVisibleLibraryRows().length,
|
||||||
selectedIndex,
|
selectedCount: selectedTracks.length,
|
||||||
|
selectedIds: selectedTracks.map((track) => track.id),
|
||||||
selectedTrack: selectedTrack ? {
|
selectedTrack: selectedTrack ? {
|
||||||
id: selectedTrack.id || "",
|
id: selectedTrack.id || "",
|
||||||
title: selectedTrack.title || "",
|
title: selectedTrack.title || "",
|
||||||
|
|||||||
Reference in New Issue
Block a user