Edna.cz Subtitle Downloader

Gives you the opportunity to download the subtitles or go directly to the original YT video

// ==UserScript==
// @name              Edna.cz Subtitle Downloader
// @name:cs           Edna.cz Stahovač Titulků
// @namespace         https://gf.qytechs.cn/users/30331-setcher
// @author            Setcher
// @description       Gives you the opportunity to download the subtitles or go directly to the original YT video
// @description:cs    Přidává možnost stáhnout titulky nebo přejít na původní YT video
// @include           http*://*edna.cz/*
// @version           1.0.0
// @grant             GM_addStyle
// @grant             GM_getValue
// @grant             GM_setValue
// @grant             GM_registerMenuCommand
// ==/UserScript==

(function() {
    'use strict';

    // Language settings
    const lang = {
        en: {
            downloadSubs: 'Download subtitles',
            noSubs: 'Subtitles not found',
            goToYT: 'Go to YouTube',
            noYT: 'YT link not found',
            menuOption: 'Open YT links in new tab',
            menuTitle: 'Settings',
            settingsTitle: 'Edna.cz Subtitle Downloader Settings',
            settingsAlt: 'Settings',
            closeButton: 'Close'
        },
        cs: {
            downloadSubs: 'Stáhnout titulky',
            noSubs: 'Titulky nenalezeny',
            goToYT: 'Přejít na YouTube',
            noYT: 'YT link nenalezen',
            menuOption: 'Otevírat YT odkazy v novém panelu',
            menuTitle: 'Nastavení',
            settingsTitle: 'Nastavení pro Edna.cz Stahovač Titulků',
            settingsAlt: 'Nastavení',
            closeButton: 'Zavřít'
        }
    };

    // Get current language
    const userLang = (navigator.language.startsWith('cs')) ? 'cs' : 'en';
    const t = lang[userLang];

    // Create settings dialog
    function showSettings() {
        const currentValue = GM_getValue('ytNewTab', false);
        let valueChanged = false;

        // Create dialog container with unique ID
        const dialog = document.createElement('div');
        dialog.id = 'edna-settings-dialog';
        dialog.style.cssText = `
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            padding: 20px;
            border-radius: 5px;
            box-shadow: 0 0 10px rgba(0,0,0,0.5);
            z-index: 9999;
            font-family: Arial, sans-serif;
            min-width: 300px;
            background-color: #252338;
        `;

        // Add title
        const title = document.createElement('h3');
        title.textContent = t.settingsTitle;
        title.style.marginTop = '0';
        title.style.marginBottom = '20px';
        dialog.appendChild(title);

        // Add checkbox
        const label = document.createElement('label');
        label.style.display = 'flex';
        label.style.alignItems = 'center';
        label.style.margin = '15px 0';
        label.style.cursor = 'pointer';

        const checkbox = document.createElement('input');
        checkbox.type = 'checkbox';
        checkbox.checked = currentValue;
        checkbox.style.marginRight = '10px';
        checkbox.addEventListener('change', function() {
            valueChanged = this.checked !== currentValue;
        });

        label.appendChild(checkbox);
        label.appendChild(document.createTextNode(t.menuOption));
        dialog.appendChild(label);

        // Add close button
        const closeButton = document.createElement('button');
        closeButton.textContent = t.closeButton;
        closeButton.style.cssText = `
            padding: 5px 15px;
            margin-top: 20px;
            float: right;
            background-color: #007bff;
            border: none;
            border-radius: 4px;
            color: white;
            cursor: pointer;
        `;
        closeButton.addEventListener('click', function() {
            GM_setValue('ytNewTab', checkbox.checked);
            document.body.removeChild(dialog);
            if (valueChanged) {
                location.reload();
            }
        });
        dialog.appendChild(closeButton);

        // Clear float
        const clearfix = document.createElement('div');
        clearfix.style.clear = 'both';
        dialog.appendChild(clearfix);

        // Add to page
        document.body.appendChild(dialog);
    }

    // Register settings menu
    GM_registerMenuCommand(t.menuTitle, showSettings);

    function addDownloadLinks() {
        const jwplayers = document.getElementsByClassName('video-box');
        if (!jwplayers.length) return;

        for (let i = 0; i < jwplayers.length; i++) {
            let result, youtube;

            // Method 1: Check for data attributes
            const dataSource = jwplayers[i].querySelector('[data-video], [data-subtitles]');
            if (dataSource) {
                const subtitles = dataSource.getAttribute('data-subtitles');
                result = subtitles ? 'http://www.edna.cz/runtime/userfiles/' + subtitles.split("/").pop().replace(/\..+$/, '.srt') : null;
                youtube = dataSource.getAttribute('data-video');
            }
            // Method 2: Fallback to regex
            else {
                const ytMatch = jwplayers[i].innerHTML.match(/video_id:\s"([^"]+)/);
                const srtMatch = jwplayers[i].innerHTML.match(/subtitles:\s*?"([^"]+)/);
                youtube = ytMatch ? ytMatch[1].replace(/\\/g, "") : null;
                result = srtMatch ? srtMatch[1].replace(/\\/g, "") : null;
            }

            // Create container for buttons
            const zNode = document.createElement('div');
            zNode.style.cssText = 'text-align: center; margin: 20px 0; white-space: nowrap;';

            // Subtitle download button
            const srtLink = document.createElement('a');
            srtLink.textContent = result ? t.downloadSubs : t.noSubs;
            srtLink.className = result ? 'light-white btn btn-primary btn-sm' : 'btn btn-sm btn-warning';
            if (result) {
                srtLink.href = result;
                srtLink.download = result.split("/").pop().split("?")[0];
            }
            zNode.appendChild(srtLink);

            // Space between buttons
            zNode.appendChild(document.createTextNode(' '));

            // YouTube link button
            const ytLink = document.createElement('a');
            ytLink.textContent = youtube ? t.goToYT : t.noYT;
            ytLink.className = youtube ? 'light-white btn btn-primary btn-sm' : 'btn btn-sm btn-warning';
            if (youtube) {
                ytLink.href = youtube;
                if (GM_getValue('ytNewTab', false)) {
                    ytLink.target = '_blank';
                    ytLink.rel = 'noopener noreferrer';
                }
            }
            zNode.appendChild(ytLink);

            // Space between buttons
            zNode.appendChild(document.createTextNode(' '));

            // Settings button
            const settingsBtn = document.createElement('button');
            settingsBtn.textContent = '⚙️';
            settingsBtn.className = 'light-white btn btn-primary btn-sm'
            settingsBtn.name = t.settingsAlt;
            settingsBtn.addEventListener('click', showSettings);
            zNode.appendChild(settingsBtn);

            // Insert buttons
            jwplayers[i].parentNode.insertBefore(zNode, jwplayers[i].nextSibling);
        }
    }

    // Run when DOM is ready
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', addDownloadLinks);
    } else {
        addDownloadLinks();
    }

    // CSS for buttons and modal - now properly scoped
    GM_addStyle(`
        .btn {
            display: inline-block !important;
            margin: 0 5px !important;
            white-space: nowrap !important;
            cursor: pointer !important;
        }

        /* Scoped to our dialog only */
        #edna-settings-dialog {
            background-color: #343a40 !important;
            color: #f8f9fa !important;
        }

        #edna-settings-dialog h3 {
            color: inherit !important;
        }
    `);
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址