Greasy Fork

Greasy Fork is available in English.

lck

롤캐 숙제 바로가기

当前为 2025-01-27 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         lck
// @namespace    lck
// @version      1.9
// @description  롤캐 숙제 바로가기
// @match        https://lolcast.kr/*
// @grant        GM_xmlhttpRequest
// @grant        GM_getValue
// @grant        GM_setValue
// ==/UserScript==

(function() {
    'use strict';

    // 기본 설정
    const DEFAULT_SETTINGS = {
        youtube: true,
        chzzk: true,
        afreeca: true,
        flow: true
    };

    // 설정 불러오기
    let settings = JSON.parse(GM_getValue('settings', JSON.stringify(DEFAULT_SETTINGS)));

    // 채널 정보
    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'
        },
        flow: {
            buttonLabel: 'Flow',
            color: '#6A5ACD',
            url: () => '/#/player/flow'
        }
    };

    // 유튜브 라이브 영상 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
            });
        });
    }

    // 설정 패널 생성
    function createSettingsPanel() {
        const modal = document.createElement('div');
        modal.style.position = 'fixed';
        modal.style.top = '50%';
        modal.style.left = '50%';
        modal.style.transform = 'translate(-50%, -50%)';
        modal.style.backgroundColor = 'rgba(255, 255, 255, 0.95)';
        modal.style.padding = '20px';
        modal.style.borderRadius = '8px';
        modal.style.boxShadow = '0 0 10px rgba(0,0,0,0.3)';
        modal.style.zIndex = '10000';
        modal.style.display = 'none';
        modal.id = 'settingsModal';

        const header = document.createElement('div');
        header.style.display = 'flex';
        header.style.justifyContent = 'space-between';
        header.style.alignItems = 'center';
        header.style.marginBottom = '15px';

        const title = document.createElement('h3');
        title.textContent = '채널 설정';
        title.style.margin = '0';

        const closeBtn = document.createElement('button');
        closeBtn.textContent = '×';
        closeBtn.style.background = 'none';
        closeBtn.style.border = 'none';
        closeBtn.style.fontSize = '20px';
        closeBtn.style.cursor = 'pointer';
        closeBtn.onclick = () => modal.style.display = 'none';

        header.appendChild(title);
        header.appendChild(closeBtn);

        const content = document.createElement('div');
        content.style.display = 'flex';
        content.style.flexDirection = 'column';
        content.style.gap = '10px';

        Object.keys(CHANNELS).forEach(channel => {
            const label = document.createElement('label');
            label.style.display = 'flex';
            label.style.alignItems = 'center';
            label.style.gap = '8px';

            const checkbox = document.createElement('input');
            checkbox.type = 'checkbox';
            checkbox.checked = settings[channel];
            checkbox.onchange = (e) => {
                settings[channel] = e.target.checked;
                GM_setValue('settings', JSON.stringify(settings));
                refreshControlPanel();
            };

            const text = document.createTextNode(CHANNELS[channel].buttonLabel);

            label.appendChild(checkbox);
            label.appendChild(text);
            content.appendChild(label);
        });

        modal.appendChild(header);
        modal.appendChild(content);
        document.body.appendChild(modal);

        // 드래그 기능
        let isDragging = false;
        let offsetX, offsetY;

        header.addEventListener('mousedown', (e) => {
            isDragging = true;
            offsetX = e.clientX - modal.offsetLeft;
            offsetY = e.clientY - modal.offsetTop;
        });

        document.addEventListener('mousemove', (e) => {
            if (isDragging) {
                modal.style.left = `${e.clientX - offsetX}px`;
                modal.style.top = `${e.clientY - offsetY}px`;
            }
        });

        document.addEventListener('mouseup', () => {
            isDragging = false;
        });

        return modal;
    }

    // 컨트롤 패널 새로고침
    function refreshControlPanel() {
        const oldPanel = document.getElementById('controlPanel');
        if (oldPanel) oldPanel.remove();
        createControlPanel();
    }

// 컨트롤 패널 생성
function createControlPanel() {
    const controlPanel = document.createElement('div');
    controlPanel.id = 'controlPanel';
    controlPanel.style.position = 'fixed';
    controlPanel.style.top = '380px';
    controlPanel.style.left = '0';
    controlPanel.style.padding = '7px';
    controlPanel.style.borderRadius = '0 4px 4px 0';
    controlPanel.style.zIndex = '9999';
    controlPanel.style.display = 'flex';
    controlPanel.style.flexDirection = 'row';
    controlPanel.style.flexWrap = 'wrap';
    controlPanel.style.gap = '6px';
    controlPanel.style.background = 'transparent';
    controlPanel.style.transition = 'all 0.3s ease';
    controlPanel.style.maxWidth = '200px'; // 컨테이너 최대 너비 설정


    // 위치 불러오기
    const savedPosition = JSON.parse(localStorage.getItem('lckControlPanelPosition'));
    if (savedPosition) {
        controlPanel.style.left = savedPosition.left;
        controlPanel.style.top = savedPosition.top;
    }

    // 드래그 기능
    let isDragging = false;
    let offsetX = 0;
    let offsetY = 0;

    controlPanel.addEventListener('mousedown', (e) => {
        isDragging = true;
        offsetX = e.clientX - controlPanel.offsetLeft;
        offsetY = e.clientY - controlPanel.offsetTop;
    });

    document.addEventListener('mousemove', (e) => {
        if (isDragging) {
            controlPanel.style.left = (e.clientX - offsetX) + 'px';
            controlPanel.style.top = (e.clientY - offsetY) + 'px';
        }
    });

    document.addEventListener('mouseup', () => {
        if (isDragging) {
            isDragging = false;
            localStorage.setItem('lckControlPanelPosition', JSON.stringify({
                left: controlPanel.style.left,
                top: controlPanel.style.top
            }));
        }
    });

    // 버튼 생성 함수
    function createChannelButton(channel) {
        const button = document.createElement('button');
        button.textContent = channel.buttonLabel;
        button.style.padding = '5px 11px';
        button.style.color = channel.color;
        button.style.border = `1px solid ${channel.color}`;
        button.style.borderRadius = '3px';
        button.style.cursor = 'pointer';
        button.style.fontSize = '13px';
        button.style.transition = 'all 0.2s';
        button.style.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.padding = '5px 11px';
        toggleButton.style.color = '#888';
        toggleButton.style.border = '1px solid #888';
        toggleButton.style.borderRadius = '3px';
        toggleButton.style.cursor = 'pointer';
        toggleButton.style.fontSize = '13px';
        toggleButton.style.transition = 'all 0.2s';
        toggleButton.style.background = 'transparent';

        toggleButton.onmouseover = () => {
            toggleButton.style.background = '#888';
            toggleButton.style.color = 'white';
        };
        toggleButton.onmouseout = () => {
            toggleButton.style.background = 'transparent';
            toggleButton.style.color = '#888';
        };
        toggleButton.onclick = () => {
            controlPanel.style.display = 'none';
        };
        return toggleButton;
    }

    // 설정 버튼 생성
    const settingsButton = document.createElement('button');
    settingsButton.textContent = '⚙';
    settingsButton.style.padding = '5px 11px';
    settingsButton.style.color = '#666';
    settingsButton.style.border = '1px solid #666';
    settingsButton.style.borderRadius = '3px';
    settingsButton.style.cursor = 'pointer';
    settingsButton.style.background = 'transparent';
    settingsButton.onclick = () => {
        document.getElementById('settingsModal').style.display = 'block';
    };

    // 버튼 배치
    if (settings.youtube) controlPanel.appendChild(createChannelButton(CHANNELS.youtube));
    if (settings.chzzk) controlPanel.appendChild(createChannelButton(CHANNELS.chzzk));
    if (settings.afreeca) controlPanel.appendChild(createChannelButton(CHANNELS.afreeca));
    if (settings.flow) controlPanel.appendChild(createChannelButton(CHANNELS.flow));
    controlPanel.appendChild(settingsButton);
    controlPanel.appendChild(createToggleButton());

    document.body.appendChild(controlPanel);
}

    // 초기화
    createSettingsPanel();
    createControlPanel();
})();