您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Records live Chzzk streams directly from the browser
// ==UserScript== // @name CHZZK - Recorder (HLS) // @name:en CHZZK - Recorder (HLS) // @name:ko 치지직 - 레코더 (HLS) // @namespace https://gf.qytechs.cn/ja/users/941284-ぐらんぴ // @version 2025-08-21 // @description Records live Chzzk streams directly from the browser // @description:en Records live Chzzk streams directly from the browser // @description:ko 브라우저에서 직접 Chzzk 라이브 스트림을 녹화합니다. // @author ぐらんぴ // @match https://*.naver.com/* // @icon https://www.google.com/s2/favicons?sz=64&domain=naver.com // @grant none // @run-at document-start // @license MIT // ==/UserScript== let $S = el => document.querySelector(el), $SA = el => document.querySelectorAll(el), $C = el => document.createElement(el) let recorder, chunks = [], isRecording = false, seconds = 0, timerInterval; function observeUrlChanges(){ let lastUrl = location.href; const observer = new MutationObserver(() => { if(location.href !== lastUrl){ lastUrl = location.href; checkPageChange(); } }); observer.observe(document.body, { subtree: true, childList: true, }); window.addEventListener('hashchange', () => { if(location.href !== lastUrl){ lastUrl = location.href; checkPageChange(); } }); } // ページ変更チェック function checkPageChange(){ record() } // 初期実行 & 監視開始 function record(){ let awaitAddon = setInterval(() => { if(!$S(".video_information_control__UTm8Z")) return; clearInterval(awaitAddon); let addon = $S(".video_information_control__UTm8Z") let btn = $C('button'); btn.textContent = ` [RECORD]`; btn.className = "GRMP"; btn.style.color = "white"; btn.style.cursor = "pointer"; btn.addEventListener("click", () => { const video = $S("video"); if(!video){ alert("Video element not found."); return; } if(video.paused || video.readyState < 3){ video.play().catch(err => console.warn("Video play failed:", err)); } if(!isRecording){ try{ let stream; let recorderStream; if(navigator.userAgent.indexOf('Firefox') > -1){ // Firefox const audioCtx = new AudioContext(); const sourceNode = audioCtx.createMediaElementSource(video); const destinationNode = audioCtx.createMediaStreamDestination(); sourceNode.connect(audioCtx.destination); // keep audio playback sourceNode.connect(destinationNode); // send to recorder stream = video.mozCaptureStream(); recorderStream = new MediaStream([ ...stream.getVideoTracks(), ...destinationNode.stream.getAudioTracks() ]); }else{ // Chrome/Edge recorderStream = video.captureStream(); } if(!recorderStream){ alert("Failed to capture stream"); return; } recorder = new MediaRecorder(recorderStream); chunks = []; recorder.ondataavailable = e => chunks.push(e.data); recorder.onstop = () => { clearInterval(timerInterval); btn.textContent = ` [RECORD]`; const blob = new Blob(chunks, { type: 'video/webm' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; //filename const now = new Date(); const month = String(now.getMonth() + 1).padStart(2, '0'); const day = String(now.getDate()).padStart(2, '0'); try{ let name = $S('.name_text__yQG50').textContent let title = $S('.video_information_title__jrLfG').textContent if(location.pathname.startsWith('/video/')){// archive a.download = name + "_" + title + "_" + location.pathname.slice(7) + ".webm"; }else{// live a.download = name + "_" + title + "_" + month + "/" + day + ".webm"; } }catch(e){ //alert('Could not get filename', e) a.download = location.pathname + "_" + month + "/" + day + ".webm"; }; a.click(); }; recorder.start(); isRecording = true; seconds = 0; btn.textContent = formatTime(seconds); timerInterval = setInterval(() => { seconds++; btn.textContent = formatTime(seconds); }, 1000); }catch(e){ alert("Recording failed: " + e); } }else{ recorder.stop(); isRecording = false; clearInterval(timerInterval); btn.textContent = ` [RECORD]`; } }); if(!$S('.GRMP')) addon.appendChild(btn); function formatTime(sec){ const m = String(Math.floor(sec / 60)).padStart(2, '0'); const s = String(sec % 60).padStart(2, '0'); return ` [${m}:${s}]`; } }, 500); }record() observeUrlChanges();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址