Fix extension progress helper scope

This commit is contained in:
DESKTOP-KSVGT20\shkim
2026-05-02 01:50:39 +09:00
parent c79d11aa47
commit 5566988cd1
+38 -36
View File
@@ -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.9.3 // @version 0.9.4
// @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.9.3"; const SCRIPT_VERSION = "0.9.4";
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");
@@ -306,6 +306,35 @@
if (status) status.textContent = text; if (status) status.textContent = text;
} }
function updateProgress(body, done, total, label = "진행") {
const progressLabel = body?.querySelector?.("[data-cgs-progress-label]");
const progressFill = body?.querySelector?.("[data-cgs-progress-fill]");
if (!progressLabel || !progressFill) return;
const safeTotal = Math.max(0, Number(total || 0));
const safeDone = Math.max(0, Math.min(Number(done || 0), safeTotal || Number(done || 0)));
const percent = safeTotal ? Math.round((safeDone / safeTotal) * 1000) / 10 : 0;
progressLabel.textContent = `${label} ${safeDone}/${safeTotal}${safeTotal ? ` (${percent}%)` : ""}`;
progressFill.style.width = `${safeTotal ? percent : 0}%`;
}
function formatSyncSummary(data, fallbackRequested = 0) {
const requested = Number(data?.requested ?? data?.received ?? fallbackRequested ?? 0);
const existing = Number(data?.existingRequested ?? data?.existing ?? 0);
const missing = Number(data?.missingRequested ?? data?.missing ?? 0);
const invalid = Number(data?.invalidRequested ?? 0);
return `로컬 확인: 요청 ${requested}곡 / 이미 있음 ${existing}곡 / 새로 필요 ${missing}${invalid ? ` / ID 없음 ${invalid}` : ""}`;
}
function showSyncSummary(body, data, fallbackRequested = 0) {
const syncSummary = body?.querySelector?.("[data-cgs-sync-summary]");
const text = formatSyncSummary(data, fallbackRequested);
const requested = Number(data?.requested ?? data?.received ?? fallbackRequested ?? 0);
const existing = Number(data?.existingRequested ?? data?.existing ?? 0);
updateProgress(body, existing, requested, "로컬 확인");
if (syncSummary) syncSummary.textContent = text;
return text;
}
function escapeHtml(value) { function escapeHtml(value) {
return String(value ?? "") return String(value ?? "")
.replaceAll("&", "&") .replaceAll("&", "&")
@@ -1434,7 +1463,7 @@
throw new Error(syncText || `${syncResponse.status} ${syncResponse.statusText}`); throw new Error(syncText || `${syncResponse.status} ${syncResponse.statusText}`);
} }
const syncData = tryParseJson(syncText) || {}; const syncData = tryParseJson(syncText) || {};
const syncTextSummary = showSyncSummary(syncData, tracks.length); const syncTextSummary = showSyncSummary(statusTarget, syncData, tracks.length);
const missingTracks = Array.isArray(syncData.tracks) ? syncData.tracks : []; const missingTracks = Array.isArray(syncData.tracks) ? syncData.tracks : [];
if (!missingTracks.length) { if (!missingTracks.length) {
setStatus(statusTarget, `동기화 완료. ${syncTextSummary}`); setStatus(statusTarget, `동기화 완료. ${syncTextSummary}`);
@@ -1447,7 +1476,7 @@
const syncTotal = Number(syncData.requested ?? syncData.received ?? tracks.length); const syncTotal = Number(syncData.requested ?? syncData.received ?? tracks.length);
for (let index = 0; index < missingTracks.length; index += 1) { for (let index = 0; index < missingTracks.length; index += 1) {
const track = { ...missingTracks[index] }; const track = { ...missingTracks[index] };
updateProgress(syncExisting + enqueued, syncTotal, "WAV 큐 준비"); updateProgress(statusTarget, syncExisting + enqueued, syncTotal, "WAV 큐 준비");
setStatus(statusTarget, `${index + 1}/${missingTracks.length} 없는 곡 WAV 변환 요청 중: ${track.title || track.id}`); setStatus(statusTarget, `${index + 1}/${missingTracks.length} 없는 곡 WAV 변환 요청 중: ${track.title || track.id}`);
track.wavUrl = await prepareSunoWavCandidate(track); track.wavUrl = await prepareSunoWavCandidate(track);
if (!track.wavUrl) { if (!track.wavUrl) {
@@ -1471,7 +1500,7 @@
throw new Error(text || `${response.status} ${response.statusText}`); throw new Error(text || `${response.status} ${response.statusText}`);
} }
enqueued += 1; enqueued += 1;
updateProgress(syncExisting + enqueued, syncTotal, "WAV 큐 준비"); updateProgress(statusTarget, syncExisting + enqueued, syncTotal, "WAV 큐 준비");
const data = tryParseJson(text) || {}; const data = tryParseJson(text) || {};
setStatus(statusTarget, `${enqueued}/${missingTracks.length}곡 큐 추가: ${track.title || track.id} / 대기 ${data.queued ?? "?"}`); setStatus(statusTarget, `${enqueued}/${missingTracks.length}곡 큐 추가: ${track.title || track.id} / 대기 ${data.queued ?? "?"}`);
} }
@@ -1498,7 +1527,7 @@
const syncText = await syncResponse.text(); const syncText = await syncResponse.text();
if (!syncResponse.ok) throw new Error(syncText || `${syncResponse.status} ${syncResponse.statusText}`); if (!syncResponse.ok) throw new Error(syncText || `${syncResponse.status} ${syncResponse.statusText}`);
const syncData = tryParseJson(syncText) || {}; const syncData = tryParseJson(syncText) || {};
const syncTextSummary = showSyncSummary(syncData, 1); const syncTextSummary = showSyncSummary(statusTarget, syncData, 1);
const missingTracks = Array.isArray(syncData.tracks) ? syncData.tracks : []; const missingTracks = Array.isArray(syncData.tracks) ? syncData.tracks : [];
if (!missingTracks.length) { if (!missingTracks.length) {
setStatus(statusTarget, `이미 로컬에 있음, SUNO 다운로드 생략: ${track.title || track.id}. ${syncTextSummary}`); setStatus(statusTarget, `이미 로컬에 있음, SUNO 다운로드 생략: ${track.title || track.id}. ${syncTextSummary}`);
@@ -1557,7 +1586,7 @@
const syncText = await syncResponse.text(); const syncText = await syncResponse.text();
if (!syncResponse.ok) throw new Error(syncText || `${syncResponse.status} ${syncResponse.statusText}`); if (!syncResponse.ok) throw new Error(syncText || `${syncResponse.status} ${syncResponse.statusText}`);
const syncData = tryParseJson(syncText) || {}; const syncData = tryParseJson(syncText) || {};
const syncTextSummary = showSyncSummary(syncData, tracks.length); const syncTextSummary = showSyncSummary(statusTarget, syncData, tracks.length);
const missingTracks = Array.isArray(syncData.tracks) ? syncData.tracks : []; const missingTracks = Array.isArray(syncData.tracks) ? syncData.tracks : [];
if (!missingTracks.length) { if (!missingTracks.length) {
setStatus(statusTarget, `동기화 완료. ${syncTextSummary}`); setStatus(statusTarget, `동기화 완료. ${syncTextSummary}`);
@@ -1571,7 +1600,7 @@
for (let index = 0; index < missingTracks.length; index += 1) { for (let index = 0; index < missingTracks.length; index += 1) {
const track = { ...missingTracks[index] }; const track = { ...missingTracks[index] };
try { try {
updateProgress(syncExisting + uploaded + failed, syncTotal, `${format.toUpperCase()} 다운로드`); updateProgress(statusTarget, syncExisting + uploaded + failed, syncTotal, `${format.toUpperCase()} 다운로드`);
setStatus(statusTarget, `${index + 1}/${missingTracks.length} ${format.toUpperCase()} 처리 중: ${track.title || track.id}`); setStatus(statusTarget, `${index + 1}/${missingTracks.length} ${format.toUpperCase()} 처리 중: ${track.title || track.id}`);
await uploadTrackToCompanion(track, statusTarget, format); await uploadTrackToCompanion(track, statusTarget, format);
uploaded += 1; uploaded += 1;
@@ -1580,7 +1609,7 @@
console.warn("[ChatGPT to Suno] upload failed", track, error); console.warn("[ChatGPT to Suno] upload failed", track, error);
setStatus(statusTarget, `${track.title || track.id} 실패: ${error.message || error}`); setStatus(statusTarget, `${track.title || track.id} 실패: ${error.message || error}`);
} }
updateProgress(syncExisting + uploaded + failed, syncTotal, `${format.toUpperCase()} 다운로드`); updateProgress(statusTarget, syncExisting + uploaded + failed, syncTotal, `${format.toUpperCase()} 다운로드`);
await new Promise((resolve) => setTimeout(resolve, 400)); await new Promise((resolve) => setTimeout(resolve, 400));
} }
let healthText = ""; let healthText = "";
@@ -1708,9 +1737,6 @@
const summary = body.querySelector("[data-cgs-summary]"); const summary = body.querySelector("[data-cgs-summary]");
const selectionSummary = body.querySelector("[data-cgs-selection-summary]"); const selectionSummary = body.querySelector("[data-cgs-selection-summary]");
const syncSummary = body.querySelector("[data-cgs-sync-summary]");
const progressLabel = body.querySelector("[data-cgs-progress-label]");
const progressFill = body.querySelector("[data-cgs-progress-fill]");
const slotSelect = body.querySelector("[data-cgs-slot]"); const slotSelect = body.querySelector("[data-cgs-slot]");
const trackList = body.querySelector("[data-cgs-track-list]"); const trackList = body.querySelector("[data-cgs-track-list]");
let libraryTracks = []; let libraryTracks = [];
@@ -1718,32 +1744,8 @@
const selectedTrackIds = new Set(); const selectedTrackIds = new Set();
let lastSelectedIndex = -1; let lastSelectedIndex = -1;
let autoScanTimer = 0; let autoScanTimer = 0;
let progressState = { total: 0, done: 0, label: "진행" };
const getSelectedTracks = () => libraryTracks.filter((track) => selectedTrackIds.has(track.id)); const getSelectedTracks = () => libraryTracks.filter((track) => selectedTrackIds.has(track.id));
const updateProgress = (done, total, label = "진행") => {
const safeTotal = Math.max(0, Number(total || 0));
const safeDone = Math.max(0, Math.min(Number(done || 0), safeTotal || Number(done || 0)));
progressState = { total: safeTotal, done: safeDone, label };
const percent = safeTotal ? Math.round((safeDone / safeTotal) * 1000) / 10 : 0;
progressLabel.textContent = `${label} ${safeDone}/${safeTotal}${safeTotal ? ` (${percent}%)` : ""}`;
progressFill.style.width = `${safeTotal ? percent : 0}%`;
};
const formatSyncSummary = (data, fallbackRequested = 0) => {
const requested = Number(data.requested ?? data.received ?? fallbackRequested ?? 0);
const existing = Number(data.existingRequested ?? data.existing ?? 0);
const missing = Number(data.missingRequested ?? data.missing ?? 0);
const invalid = Number(data.invalidRequested ?? 0);
return `로컬 확인: 요청 ${requested}곡 / 이미 있음 ${existing}곡 / 새로 필요 ${missing}${invalid ? ` / ID 없음 ${invalid}` : ""}`;
};
const showSyncSummary = (data, fallbackRequested = 0) => {
const text = formatSyncSummary(data, fallbackRequested);
const requested = Number(data.requested ?? data.received ?? fallbackRequested ?? 0);
const existing = Number(data.existingRequested ?? data.existing ?? 0);
updateProgress(existing, requested, "로컬 확인");
syncSummary.textContent = text;
return text;
};
const mergeLibraryTracks = (tracks) => { const mergeLibraryTracks = (tracks) => {
for (const track of tracks) { for (const track of tracks) {
if (!track.id) continue; if (!track.id) continue;