diff --git a/chatgpt-suno-tampermonkey.user.js b/chatgpt-suno-tampermonkey.user.js index 15ee523..ce0dd26 100644 --- a/chatgpt-suno-tampermonkey.user.js +++ b/chatgpt-suno-tampermonkey.user.js @@ -1,7 +1,7 @@ // ==UserScript== // @name ChatGPT to Suno Prompt Copier // @namespace local.suno-helper -// @version 0.9.9 +// @version 0.10.0 // @description Copy structured ChatGPT song prompt versions into Suno fields. // @author local // @match https://chatgpt.com/* @@ -30,7 +30,7 @@ (function () { "use strict"; - const SCRIPT_VERSION = "0.9.9"; + const SCRIPT_VERSION = "0.10.0"; const STORAGE_KEY = "chatgptSunoPromptSlots"; const SLOT_COUNT = 2; const isChatGPT = location.hostname.includes("chatgpt.com") || location.hostname.includes("chat.openai.com"); @@ -972,7 +972,7 @@ }) || null; } - function findTrackRowElement(track) { + function findTrackRowElementNow(track) { const rows = getVisibleLibraryRows(); const index = getTrackVisibleIndex(track, rows); if (index >= 0) return rows[index].element; @@ -981,6 +981,42 @@ return rows.find((row) => row.normalized.includes(title))?.element || null; } + function getPageScroller() { + return document.scrollingElement || document.documentElement || document.body; + } + + async function findTrackRowElement(track, statusTarget) { + const current = findTrackRowElementNow(track); + if (current) return current; + + const scroller = getPageScroller(); + const originalTop = scroller.scrollTop || window.scrollY || 0; + const maxSteps = 50; + const step = Math.max(260, Math.floor(window.innerHeight * 0.72)); + + setStatus(statusTarget, `SUNO 화면에서 곡 행 찾는 중: ${track.title || track.id}`); + scroller.scrollTop = 0; + window.scrollTo?.(0, 0); + await sleep(450); + + for (let stepIndex = 0; stepIndex <= maxSteps; stepIndex += 1) { + const found = findTrackRowElementNow(track); + if (found) return found; + + const before = scroller.scrollTop || window.scrollY || 0; + scroller.scrollTop = before + step; + window.scrollTo?.(0, before + step); + await sleep(260); + const after = scroller.scrollTop || window.scrollY || 0; + if (Math.abs(after - before) < 4) break; + } + + scroller.scrollTop = originalTop; + window.scrollTo?.(0, originalTop); + await sleep(200); + return null; + } + function findMoreButtonInRow(row) { if (!row) return null; const buttons = [...row.querySelectorAll("button, [role='button']")]; @@ -1004,8 +1040,8 @@ } async function clickSunoUiDownload(track, format, statusTarget) { - const row = findTrackRowElement(track); - if (!row) throw new Error("현재 화면에서 곡 행을 못 찾았어. SUNO 목록에서 그 곡이 보이게 스크롤한 뒤 다시 눌러줘."); + const row = await findTrackRowElement(track, statusTarget); + if (!row) throw new Error("SUNO 화면을 훑어도 곡 행을 못 찾았어. 필터/검색 때문에 목록에 안 보이는지 확인해줘."); const moreButton = findMoreButtonInRow(row); if (!moreButton) throw new Error("곡의 ... 메뉴 버튼을 못 찾았어.");