Fix extension progress helper scope
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.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;
|
||||||
|
|||||||
Reference in New Issue
Block a user