// ==UserScript== // @name chzzk Ad Block Auto Quality Change // @version 1.0.2 // @match https://chzzk.naver.com/* // @description 치지직 광고 차단 감지 스크립트를 우회합니다. // @run-at document-start // @grant none // @author k22pr // @namespace k22pr/chzzk-ad-block-auto-quality-change // @license MIT // @downloadURL none // ==/UserScript== var qualityInterval = null; (function () { const SLIDER_SEL = "div.pzp-pc-progress-slider"; const BTN_SEL = "button.pzp-pc-setting-button"; const VIDEO_SEL = "video.webplayer-internal-video"; const QUALITY_SEL = "li.pzp-ui-setting-quality-item"; let isHighQuality = false; let qualityButtonList = document.querySelectorAll( `${SLIDER_SEL} > ${BTN_SEL}` ); let videoEl = document.querySelector(VIDEO_SEL); async function hoverThenClickOnce() { const enterEvent = new KeyboardEvent("keydown", { bubbles: true, cancelable: true, key: "Enter", code: "Enter", keyCode: 13, which: 13, }); const qualityOption = document.querySelector(QUALITY_SEL); console.log(qualityOption); if (!qualityOption) return false; qualityOption.dispatchEvent(enterEvent); } // SPA URL Change (function () { clearInterval(qualityInterval); qualityInterval = null; const fireLoc = () => setTimeout(() => { done = false; setQualityInterval(); startQualityInterval(); forceStopInterval(); }, 0); const _ps = history.pushState, _rs = history.replaceState; history.pushState = function () { console.log("pushState"); const r = _ps.apply(this, arguments); fireLoc(); return r; }; history.replaceState = function () { console.log("replaceState"); const r = _rs.apply(this, arguments); fireLoc(); return r; }; window.addEventListener("popstate", fireLoc); })(); // test: Alt+H window.addEventListener("keydown", (e) => { if (e.altKey && e.key.toLowerCase() === "h") { done = false; hoverThenClickOnce(); } }); function setQualityInterval() { qualityInterval = setInterval(() => { const hasLive = location.pathname.includes("/live/"); qualityButtonList = document.querySelectorAll(QUALITY_SEL); videoEl = document.querySelector(VIDEO_SEL); if (qualityButtonList.length != 0) { isHighQuality = qualityButtonList[0].classList.contains( "pzp-ui-setting-pane-item--checked" ); } console.log("setQualityInterval", videoEl, hasLive, isHighQuality); if (!hasLive) { clearInterval(qualityInterval); qualityInterval = null; } if (videoEl && hasLive && !isHighQuality) { hoverThenClickOnce(); } if (isHighQuality && videoEl.paused === true) { videoEl.play(); } if (isHighQuality && videoEl.paused !== false) { clearInterval(qualityInterval); qualityInterval = null; } }, 100); } function startQualityInterval() { const hasLive = location.pathname.includes("/live/"); qualityButtonList = document.querySelectorAll(QUALITY_SEL); videoEl = document.querySelector(VIDEO_SEL); console.log("startQualityInterval", videoEl, hasLive, isHighQuality); if (qualityButtonList.length != 0) { isHighQuality = qualityButtonList[0].classList.contains( "pzp-ui-setting-pane-item--checked" ); } if (videoEl && hasLive && !isHighQuality) { setQualityInterval(); } } function forceStopInterval() { setTimeout(() => { clearInterval(qualityInterval); qualityInterval = null; }, 3000); } setQualityInterval(); startQualityInterval(); forceStopInterval(); })(); (function () { const MSG = "광고 차단 프로그램을 사용 중이신가요?"; const isPopupContents = (el) => el instanceof Element && (el.className + "").includes("popup_contents__") && el.textContent && el.textContent.includes(MSG); const removePopup = (el) => { const container = el.closest( '[role="dialog"], [class*="popup"], [class*="modal"], [class*="layer"]' ) || el; container.parentElement.remove(); console.log("[userscript] adblock popup removed"); }; const scan = (root) => { if (!root) return; const candidates = root.querySelectorAll?.('[class*="popup_contents__"]') ?? []; candidates.forEach((el) => { if (isPopupContents(el)) removePopup(el); }); const all = root.querySelectorAll?.("*") ?? []; all.forEach((n) => { if (n.shadowRoot) scan(n.shadowRoot); }); if (root.shadowRoot) scan(root.shadowRoot); }; const ready = () => scan(document); if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", ready); } else { ready(); } const mo = new MutationObserver((mutations) => { for (const m of mutations) { m.addedNodes.forEach((node) => { if (node.nodeType === 1) scan(node); // Element }); if (m.type === "characterData" && m.target?.parentElement) { const el = m.target.parentElement.closest?.( '[class*="popup_contents__"]' ); if (el && isPopupContents(el)) removePopup(el); } } }); mo.observe(document.documentElement, { childList: true, subtree: true, characterData: true, }); })();