From b8ce9645100d8c55f70ce3c0a3dd27e4d115783c Mon Sep 17 00:00:00 2001 From: user01 Date: Sun, 14 Jun 2026 16:36:22 +0900 Subject: [PATCH] =?UTF-8?q?=EB=AA=A9=EB=A1=9D=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80:=20n=ED=99=94=20=EC=9D=B4=ED=9B=84=20/=20=EB=B2=94?= =?UTF-8?q?=EC=9C=84=20=EB=8B=A4=EC=9A=B4=EB=A1=9C=EB=93=9C=20=EB=A9=94?= =?UTF-8?q?=EB=89=B4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - getEpisodesFromList() 공통 헬퍼로 에피소드 추출 로직 분리 - startQueue() 공통 헬퍼로 큐 저장 + 이동 로직 분리 - downloadAfterEpisode(): prompt로 시작 번호 입력받아 필터링 - downloadRangeEpisodes(): prompt로 범위 입력받아 필터링 - 필터링된 결과는 번호 오름차순 정렬 후 다운로드 --- tokimonkeyDownader.js | 75 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 65 insertions(+), 10 deletions(-) diff --git a/tokimonkeyDownader.js b/tokimonkeyDownader.js index 2e8cd7b..0628f80 100644 --- a/tokimonkeyDownader.js +++ b/tokimonkeyDownader.js @@ -72,6 +72,8 @@ const { isListPage, isEpisodePage } = getListPageInfo(); if (isListPage) { menuCmdIds.push(GM_registerMenuCommand('[목록] 전체 에피소드 다운로드', () => downloadAllEpisodes())); + menuCmdIds.push(GM_registerMenuCommand('[목록] n화 이후 다운로드', () => downloadAfterEpisode())); + menuCmdIds.push(GM_registerMenuCommand('[목록] 범위 다운로드', () => downloadRangeEpisodes())); } else if (isEpisodePage) { menuCmdIds.push(GM_registerMenuCommand('현재 에피소드 다운로드', () => downloadCurrentEpisode())); } @@ -347,12 +349,10 @@ } } - async function downloadAllEpisodes() { - log('목록 페이지 처리 시작'); - + // 목록 페이지에서 에피소드 목록 추출 + const getEpisodesFromList = () => { const episodeList = document.querySelector('ul.ep-list-v2'); - if (!episodeList) { alert('에피소드 목록을 찾을 수 없습니다.'); return; } - + if (!episodeList) return null; const episodes = []; episodeList.querySelectorAll('li.ep-row-v2').forEach((li, index) => { const link = li.querySelector('a.ep-row-v2-link'); @@ -369,18 +369,73 @@ }); } }); + return episodes.length > 0 ? episodes : null; + }; - if (episodes.length === 0) { alert('에피소드 링크를 추출할 수 없습니다.'); return; } - - const seriesName = getSeriesName(); + // 큐 저장 후 첫 화로 이동 + const startQueue = (episodes, seriesName) => { log(`${episodes.length}개 에피소드를 큐에 저장, 첫 화로 이동합니다...`); - - // 큐 저장 후 첫 번째 에피소드로 이동 sessionStorage.setItem(QUEUE_KEY, JSON.stringify(episodes)); sessionStorage.setItem(SERIES_KEY, seriesName); sessionStorage.setItem(IDX_KEY, '0'); sessionStorage.setItem(LIST_KEY, window.location.href); window.location.href = episodes[0].url; + }; + + async function downloadAllEpisodes() { + log('목록 페이지 처리 시작'); + const episodes = getEpisodesFromList(); + if (!episodes) { alert('에피소드 목록을 찾을 수 없습니다.'); return; } + const seriesName = getSeriesName(); + startQueue(episodes, seriesName); + } + + // n화 이후 다운로드 + async function downloadAfterEpisode() { + const episodes = getEpisodesFromList(); + if (!episodes) { alert('에피소드 목록을 찾을 수 없습니다.'); return; } + + const input = prompt('어느 에피소드부터 다운로드할까요?\n(번호 입력, 예: 50)'); + if (!input) return; + + const threshold = parseFloat(input.trim()); + if (isNaN(threshold)) { alert('올바른 숫자를 입력하세요.'); return; } + + const filtered = episodes + .filter(ep => parseFloat(ep.number) >= threshold) + .sort((a, b) => parseFloat(a.number) - parseFloat(b.number)); + + if (filtered.length === 0) { alert('조건에 맞는 에피소드가 없습니다.'); return; } + const seriesName = getSeriesName(); + startQueue(filtered, seriesName); + } + + // 범위 다운로드 + async function downloadRangeEpisodes() { + const episodes = getEpisodesFromList(); + if (!episodes) { alert('에피소드 목록을 찾을 수 없습니다.'); return; } + + const input = prompt('범위를 입력하세요.\n(예: 30-50 또는 50-끝)'); + if (!input) return; + + const match = input.trim().match(/^(\d+(?:\.\d+)?)\s*-\s*(?:(\d+(?:\.\d+)?)|(끝|end))?$/); + if (!match) { alert('올바른 형식이 아닙니다. 예: 30-50'); return; } + + const start = parseFloat(match[1]); + const end = match[2] !== undefined ? parseFloat(match[2]) : Infinity; + + if (isNaN(start)) { alert('올바른 숫자를 입력하세요.'); return; } + + const filtered = episodes + .filter(ep => { + const num = parseFloat(ep.number); + return num >= start && num <= end; + }) + .sort((a, b) => parseFloat(a.number) - parseFloat(b.number)); + + if (filtered.length === 0) { alert('조건에 맞는 에피소드가 없습니다.'); return; } + const seriesName = getSeriesName(); + startQueue(filtered, seriesName); } // 자동 큐 처리: sessionStorage에 큐가 있으면 현재 화면을 다운로드 후 다음으로 이동