From 994397e71050bb6dc31a9bcd0133b0f1b60007d7 Mon Sep 17 00:00:00 2001 From: "Claude (chzzk-bypass owner)" Date: Thu, 28 May 2026 14:28:43 +0900 Subject: [PATCH] =?UTF-8?q?v1.1.2:=20live-playback-json=20fetch=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0=20+=20=EC=A7=84=EB=8B=A8=20=EB=8D=A4?= =?UTF-8?q?=ED=94=84=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 문제: 사용자 콘솔에서 v1.1.1 의 XHR 후킹은 정상 작동(`forcing timeMachine ON` 로그 확인)했으나 재생바는 안 떴음. 동시에 `live-playback-json` 엔드포인트가 v3.2/v3.1/v3/v2 전부 CORS+404 로 막혀 콘솔에 잡음만 양산했음. 두 플래그 (`timeMachineActive`/`timeMachinePlayback`) 만으로는 플레이어가 UI 를 안 띄우는 것으로 보임 → 다른 트리거 조사 중. 이번 커밋: - 깨진 live-playback-json fetch 호출 코드 제거. 콘솔 잡음 해소. - 진단용 덤프 추가: devtools 에서 localStorage.setItem('chzzk-bypass:debug','1') 후 새로고침하면 live-detail content 와 livePlaybackJson 파싱 결과를 통째로 콘솔에 찍어 어느 필드가 UI 트리거인지 들여다볼 수 있다. 플래그 두 개 set 동작은 유지. 실제 UI 트리거 메커니즘 파악되면 후속 커밋에서 정식 픽스. --- manifest.json | 2 +- timemachine.js | 62 ++++++++++++++++---------------------------------- 2 files changed, 20 insertions(+), 44 deletions(-) diff --git a/manifest.json b/manifest.json index a2487a7..154a95c 100644 --- a/manifest.json +++ b/manifest.json @@ -1,6 +1,6 @@ { "name": "Chzzk Bypass", - "version": "1.1.1", + "version": "1.1.2", "manifest_version": 3, "description": "치지직(CHZZK) 시청 환경 개선: 1) Mac 위장으로 그리드 없이 1080p 시청, 2) 스트리머가 타임머신을 꺼둔 라이브에서도 되감기 UI 강제 표시.", "icons": { diff --git a/timemachine.js b/timemachine.js index 79f9129..6a2b654 100644 --- a/timemachine.js +++ b/timemachine.js @@ -25,8 +25,11 @@ // 치지직은 `service/v3.2/...` 처럼 minor 가 붙은 버전을 쓴다. 점(.) 포함 허용. const LIVE_DETAIL_RE = /^https:\/\/api\.chzzk\.naver\.com\/service\/v[\d.]+\/channels\/([^\/?#]+)\/live-detail/; - // 시점/빌드별로 다른 버전이 응답하므로 순차 시도한다. - const PLAYBACK_JSON_VERSIONS = ['v3.2', 'v3.1', 'v3', 'v2', 'v1']; + // localStorage 'chzzk-bypass:debug' = '1' 로 켜면 응답 본문을 콘솔에 덤프해 디버깅한다. + // (기본은 off. 일반 사용자 콘솔이 더러워지지 않도록.) + function isDebug() { + try { return localStorage.getItem('chzzk-bypass:debug') === '1'; } catch (_) { return false; } + } function log() { try { @@ -50,38 +53,9 @@ } catch (_) { return ''; } } - async function fetchPlaybackJson(channelId) { - for (const ver of PLAYBACK_JSON_VERSIONS) { - try { - const url = `https://api.chzzk.naver.com/service/${ver}/channels/${channelId}/live-playback-json`; - const resp = await originalFetch(url, { credentials: 'include' }); - if (!resp.ok) continue; - const json = await resp.json(); - const playback = json && json.content && json.content.playbackJson; - if (playback) { - log('playback-json hit via', ver); - return playback; - } - } catch (e) { - log('playback-json fetch error on', ver, e); - } - } - return null; - } - - // livePlaybackJson 은 외부에선 JSON 문자열로 들어오지만, 가끔 이미 파싱된 - // 객체 형태로 들어오는 빌드도 있다. 두 경우 모두 처리한다. - function setLivePlaybackJson(content, replacement) { - if (typeof content.livePlaybackJson === 'string') { - content.livePlaybackJson = typeof replacement === 'string' - ? replacement - : JSON.stringify(replacement); - } else { - content.livePlaybackJson = typeof replacement === 'string' - ? JSON.parse(replacement) - : replacement; - } - } + // 별도의 live-playback-json 엔드포인트 fetch 는 이전 버전에서 시도했지만 + // 모든 버전이 CORS+404 로 막혀 더 이상 호출하지 않는다. (실측 확인) + // 매니페스트 URL 갈아끼우기는 별도 메커니즘이 필요하며, 현재 조사 중. // 파싱된 live-detail JSON 객체를 in-place 로 패치. 변경 여부 반환. async function patchLiveDetailData(data, channelIdFromUrl) { @@ -105,15 +79,17 @@ content.timeMachineActive = true; content.timeMachinePlayback = true; - // DVR 매니페스트로 교체 시도. 실패해도 플래그는 살려서 UI 만이라도 노출. - if (channelId) { - const playback = await fetchPlaybackJson(channelId); - if (playback) { - setLivePlaybackJson(content, playback); - log('livePlaybackJson swapped for DVR manifest'); - } else { - log('playback-json unavailable; UI shown but seek may not work'); - } + // 진단용: live-detail content 와 livePlaybackJson 디코딩 결과를 통째로 덤프. + // 플레이어가 어느 필드를 보는지 모를 때 켜서 들여다보는 용도. + // 활성화: devtools 콘솔에서 `localStorage.setItem('chzzk-bypass:debug','1')` 후 새로고침. + if (isDebug()) { + try { + const dump = JSON.parse(JSON.stringify(content)); + if (typeof dump.livePlaybackJson === 'string') { + try { dump.__livePlaybackJsonParsed = JSON.parse(dump.livePlaybackJson); } catch (_) {} + } + log('DEBUG live-detail content after patch:', dump); + } catch (e) { log('debug dump failed', e); } } return true; }