SOOP 라이브 및 클립 창에서 화면 캡쳐시 플레이어 컨트롤러 부분을 보이지 않게 할 수 있도록 컨트롤러 비활성화/캡쳐 버튼을 추가합니다.
当前为
// ==UserScript==
// @name SOOP 클립 및 라이브 깔끔하게 캡쳐
// @namespace http://tampermonkey.net/
// @version 1.31
// @license MIT
// @description SOOP 라이브 및 클립 창에서 화면 캡쳐시 플레이어 컨트롤러 부분을 보이지 않게 할 수 있도록 컨트롤러 비활성화/캡쳐 버튼을 추가합니다.
// @author Linseed, Gemini
// @match https://stbbs.sooplive.co.kr/*
// @match https://play.sooplive.co.kr/*
// @grant GM_addStyle
// ==/UserScript==
(function() {
'use strict';
// --- 스크립트 설정 ---
const CHECK_INTERVAL = 500; // 플레이어 요소를 찾기 위한 반복 확인 간격 (ms)
/**
* 필요한 DOM 요소들이 로드될 때까지 기다립니다.
* videoLayer와 player_ctrlBox가 모두 존재하면 main 함수를 실행합니다.
*/
const waitForElements = setInterval(() => {
const videoLayer = document.getElementById('videoLayer');
const ctrlBox = document.querySelector('.player_ctrlBox');
const titleElement = document.querySelector('.u_clip_title');
const nicknameElement = document.querySelector('.nickname');
if (videoLayer && ctrlBox && (titleElement || nicknameElement)) {
clearInterval(waitForElements);
main(videoLayer, ctrlBox, titleElement, nicknameElement);
}
}, CHECK_INTERVAL);
/**
* 스크립트의 메인 로직을 실행합니다.
* @param {HTMLElement} videoLayer - 캡쳐할 대상이 되는 비디오 레이어 요소
* @param {HTMLElement} ctrlBox - 숨기거나 표시할 컨트롤 박스 요소
* @param {HTMLElement | null} titleElement - 버튼을 추가할 제목 요소
* @param {HTMLElement | null} nicknameElement - 버튼을 추가할 닉네임 요소
*/
function main(videoLayer, ctrlBox, titleElement, nicknameElement) {
// --- 1. 상태 변수 정의 ---
let isLocked = false;
// --- 2. UI 요소 생성 ---
const container = document.createElement('div');
container.id = 'soop-script-container';
if (titleElement) {
// u_clip_title class의 맨 위에 버튼 컨테이너를 추가합니다.
titleElement.after(container);
} else if (nicknameElement) {
// nickname class의 바로 뒤에 버튼 컨테이너를 추가합니다.
nicknameElement.after(container);
}
const lockButton = document.createElement('button');
lockButton.id = 'lockBtn';
lockButton.textContent = '🔓';
lockButton.title = '컨트롤러 잠금/해제';
container.appendChild(lockButton);
const captureButton = document.createElement('button');
captureButton.id = 'captureBtn';
captureButton.textContent = '📷';
captureButton.title = '현재 화면 캡쳐';
container.appendChild(captureButton);
// --- 3. UI 스타일 적용 ---
GM_addStyle(`
#soop-script-container {
display: inline-flex;
gap: 8px;
margin-left: 10px;
vertical-align: middle;
}
#soop-script-container button {
padding: 4px 8px;
font-size: 16px;
border: 1px solid #ccc;
border-radius: 6px;
background-color: rgba(240, 240, 240, 0.85);
cursor: pointer;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
transition: all 0.2s ease-in-out;
line-height: 1;
}
#soop-script-container button:hover {
background-color: rgba(255, 255, 255, 1);
transform: translateY(-1px);
}
`);
// --- 4. 핵심 기능 함수 정의 ---
/**
* 잠금 상태를 설정하고 UI를 업데이트합니다.
* @param {boolean} locked - 설정할 잠금 상태 (true: 잠김, false: 열림)
*/
const setLockState = (locked) => {
isLocked = locked;
lockButton.textContent = isLocked ? '🔒' : '🔓';
// display 속성을 변경하여 컨트롤 박스를 숨기거나 표시합니다.
ctrlBox.style.display = isLocked ? 'none' : '';
};
// --- 5. 이벤트 리스너 등록 ---
// 잠금 버튼 클릭 이벤트
lockButton.addEventListener('click', () => {
setLockState(!isLocked);
});
// 캡쳐 버튼 클릭 이벤트
captureButton.addEventListener('click', async () => {
const originalLockState = isLocked;
// 1. 캡쳐를 위해 컨트롤러를 일시적으로 숨깁니다.
if (!originalLockState) {
setLockState(true);
// UI가 업데이트될 시간을 잠시 기다립니다 (100ms).
await new Promise(resolve => setTimeout(resolve, 100));
}
// 2. 비디오 프레임을 캔버스에 그려서 캡쳐합니다.
try {
const videoElement = videoLayer.querySelector('video');
if (!videoElement) {
throw new Error('플레이어에서 <video> 요소를 찾을 수 없습니다.');
}
// 캡쳐용 캔버스를 생성합니다.
const canvas = document.createElement('canvas');
canvas.width = videoElement.videoWidth;
canvas.height = videoElement.videoHeight;
const ctx = canvas.getContext('2d');
// 캔버스에 비디오의 현재 프레임을 그립니다.
ctx.drawImage(videoElement, 0, 0, canvas.width, canvas.height);
const link = document.createElement('a');
// 파일명에 날짜와 시간을 포함하여 중복을 방지합니다.
const timestamp = new Date().toISOString().slice(0, 19).replace(/[-T:]/g, '');
link.download = `soop-capture-${timestamp}.png`;
link.href = canvas.toDataURL('image/png');
link.click();
} catch (error) {
console.error('스크립트 캡쳐 오류:', error);
alert('화면 캡쳐에 실패했습니다. 비디오가 다른 도메인에서 재생되는 경우(CORS) 캡쳐가 불가능할 수 있습니다. 브라우저 콘솔을 확인해주세요.');
} finally {
// 3. 캡쳐가 끝나면 원래 잠금 상태로 복구합니다.
if (!originalLockState) {
setLockState(false);
}
}
});
}
})();