// ==UserScript== // @name lck // @namespace lck // @version 1.3 // @description 롤캐 숙제 바로가기 // @match https://lolcast.kr/* // @grant GM_xmlhttpRequest // @downloadURL none // ==/UserScript== (function() { 'use strict'; // 채널 정보 const CHANNELS = { youtube: { id: 'UCw1DsweY9b2AKGjV4kGJP1A', buttonLabel: '유튜브', color: '#FF0000', url: (id) => `/#/player/youtube/${id}` }, chzzk: { buttonLabel: '치지직', color: '#00FFA3', url: () => '/#/player/chzzk/9381e7d6816e6d915a44a13c0195b202' }, afreeca: { buttonLabel: '숲', color: '#2970B6', url: () => '/#/player/afreeca/aflol' } }; // YouTube 라이브 영상 ID 가져오기 async function fetchLiveVideoId(channelId) { const YOUTUBE_LIVE_URL = `https://www.youtube.com/channel/${channelId}/live`; return new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: "GET", url: YOUTUBE_LIVE_URL, onload: function(response) { const videoIdMatch = response.responseText.match(/"videoId":"([\w-]+)"/); const isLiveNow = response.responseText.includes('"isLiveNow":true') || response.responseText.includes('"isLive":true'); const liveBroadcastContentMatch = response.responseText.match(/"liveBroadcastContent":"(\w+)"/); const isLiveBroadcast = liveBroadcastContentMatch && liveBroadcastContentMatch[1] === 'live'; if (videoIdMatch && videoIdMatch[1] && (isLiveNow || isLiveBroadcast)) { resolve(videoIdMatch[1]); } else { reject('No live video found.'); } }, onerror: reject }); }); } // 패널 숨김 상태 확인 (localStorage 활용) const HIDE_PANEL_KEY = 'hideLckPanel'; function isPanelHidden() { return localStorage.getItem(HIDE_PANEL_KEY) === 'true'; } function setPanelHidden(hidden) { localStorage.setItem(HIDE_PANEL_KEY, hidden ? 'true' : 'false'); } // 컨트롤 패널 생성 const controlPanel = document.createElement('div'); controlPanel.style.cssText = ` position: fixed; top: 380px; left: 0; padding: 8px; border-radius: 0 4px 4px 0; z-index: 9999; display: flex; gap: 8px; background: transparent !important; transition: all 0.3s ease; `; // 버튼 생성 함수 function createChannelButton(channel) { const button = document.createElement('button'); button.textContent = channel.buttonLabel; button.style.cssText = ` padding: 6px 12px; color: ${channel.color}; border: 2px solid ${channel.color}; border-radius: 4px; cursor: pointer; font-size: 14px; transition: all 0.2s; background: transparent; `; button.onmouseover = () => { button.style.background = channel.color; button.style.color = 'white'; }; button.onmouseout = () => { button.style.background = 'transparent'; button.style.color = channel.color; }; button.onclick = async () => { if (channel.buttonLabel === '유튜브') { try { const liveVideoId = await fetchLiveVideoId(channel.id); window.location.href = channel.url(liveVideoId); } catch { alert('유튜브 라이브 방송이 없습니다.'); } } else { window.location.href = channel.url(); } }; return button; } // 토글 버튼 생성 function createToggleButton() { const toggleButton = document.createElement('button'); toggleButton.textContent = '◀'; toggleButton.style.cssText = ` padding: 6px 10px; background: #555; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 14px; transition: all 0.2s; `; toggleButton.onmouseover = () => { toggleButton.style.background = '#777'; }; toggleButton.onmouseout = () => { toggleButton.style.background = '#555'; }; toggleButton.onclick = () => { controlPanel.style.display = 'none'; setPanelHidden(true); }; return toggleButton; } // 버튼 추가 const youtubeButton = createChannelButton(CHANNELS.youtube); const chzzkButton = createChannelButton(CHANNELS.chzzk); const afreecaButton = createChannelButton(CHANNELS.afreeca); const toggleButton = createToggleButton(); controlPanel.appendChild(youtubeButton); controlPanel.appendChild(chzzkButton); controlPanel.appendChild(afreecaButton); controlPanel.appendChild(toggleButton); document.body.appendChild(controlPanel); // 페이지 로드 시 패널 숨김 여부 확인 if (isPanelHidden()) { controlPanel.style.display = 'none'; } })();