Greasy Fork

YouTube 稍后再看重定向

重定向YouTube稍后再看的视频链接到原始视频链接,并在新标签页中打开视频。

// ==UserScript==
// @name         YouTube 稍后再看重定向
// @name:en      YouTube Watch Later Redirect
// @name:zh-CN   YouTube 稍后再看重定向
// @name:zh-TW   YouTube 稍後再看重定向
// @namespace    http://tampermonkey.net/
// @version      1.1.20250312
// @author       JerryYang
// @description  重定向YouTube稍后再看的视频链接到原始视频链接,并在新标签页中打开视频。
// @description:en  Redirect YouTube Watch Later video links to their original video and open in a new tab.
// @description:zh-CN  重定向YouTube稍后再看的视频链接到原始视频链接,并在新标签页中打开视频。
// @description:zh-TW  重定向YouTube稍後再看的影片連結到原始影片,並在新標籤頁中開啟影片。
// @license      GPL-3.0 License
// @homepage     https://github.com/JerryYang-30/YouTube-Watch-Later-Redirect
// @supportURL   https://github.com/JerryYang-30/YouTube-Watch-Later-Redirect
// @match        https://www.youtube.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=YouTube.com
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_registerMenuCommand
// @run-at       document-idle
// ==/UserScript==

/*
支持多语言
*/

// 语言支持:英语 (en), 简体中文 (zh-CN), 繁体中文 (zh-TW)
const userLanguage = navigator.language || navigator.userLanguage;

// 多语言翻译资源
const translations = {
    "en": {
        "notificationMessage": "All videos have been successfully redirected!",
        "enableNotification": "Enable Notification",
        "disableNotification": "Disable Notification",
        "adjustNotificationStyle": "Adjust Notification Style",
        "resetDefaults": "Reset to Default Settings",
        "confirmSave": "Are you sure you want to save the changes?",
        "confirmReset": "Are you sure you want to reset to default settings? This action cannot be undone!",
        "savedMessage": "Settings saved, click OK to refresh the page.",
        "resetMessage": "Default settings restored, click OK to refresh the page.",
        "enableNotificationMessage": "Notification has been enabled, click OK to refresh for changes to take effect.",
        "disableNotificationMessage": "Notification has been disabled, click OK to refresh for changes to take effect.",
        "adjustPanelH2Title": "Adjust the style of the prompt box(leave blank to not modify)",
        "adjustPanelPosition": "Select prompt box location",
        "adjustPanelWidth": "Prompt box width (can also be auto)",
        "adjustPanelHeight": "Prompt box length (can also be auto)",
        "adjustPanelHideAfter": "The display time of the prompt box (milliseconds, just enter the number)",
        "adjustPanelCustomMessage": "Custom prompt words",
        "adjustPanelSave": "Save",
        "adjustPanelCancel": "Cancel",
        "adjustPanelReset": "Restore default settings",
        "adjustPanelPlaceholder": "Currently ",
        "exportList": "Export Watch Later List",
        "exportSuccess": "Export successful! The file has been saved to your downloads folder.",
        "noVideosFound": "No videos found in the Watch Later list."
    },
    "zh-CN": {
        "notificationMessage": "全部视频已成功重定向!",
        "enableNotification": "启用提示框",
        "disableNotification": "禁用提示框",
        "adjustNotificationStyle": "调整提示框样式",
        "resetDefaults": "恢复默认设置",
        "confirmSave": "确定要保存修改吗?此操作不可撤销!",
        "confirmReset": "确定要恢复默认设置吗?此操作不可撤销!",
        "savedMessage": "设置已保存,点击确定刷新页面以生效。",
        "resetMessage": "默认设置已恢复,点击确定刷新页面以生效。",
        "enableNotificationMessage": "提示框已启用,点击确定刷新后生效。",
        "disableNotificationMessage": "提示框已禁用,点击确定刷新后生效。",
        "adjustPanelH2Title": "调整提示框样式(留空则不修改)",
        "adjustPanelPosition": "选择提示框位置",
        "adjustPanelWidth": "提示框宽度(可以填auto)",
        "adjustPanelHeight": "提示框长度(可以填auto)",
        "adjustPanelHideAfter": "提示框显示时间(毫秒,输入数字即可)",
        "adjustPanelCustomMessage": "自定义提示词",
        "adjustPanelSave": "保存",
        "adjustPanelCancel": "取消",
        "adjustPanelReset": "恢复默认设置",
        "adjustPanelPlaceholder": "当前为",
        "exportList": "导出稍后观看列表",
        "exportSuccess": "导出成功!文件已保存到下载文件夹。",
        "noVideosFound": "稍后观看列表中未找到视频。"
    },
    "zh-TW": {
        "notificationMessage": "全部影片已成功重新導向!",
        "enableNotification": "啟用提示框",
        "disableNotification": "禁用提示框",
        "adjustNotificationStyle": "調整提示框樣式",
        "resetDefaults": "恢復預設設定",
        "confirmSave": "確定要保存修改嗎?此操作不可撤銷!",
        "confirmReset": "確定要恢復預設設定嗎?此操作不可撤銷!",
        "savedMessage": "設定已保存,點擊確定刷新頁面以生效。",
        "resetMessage": "預設設定已恢復,點擊確定刷新頁面以生效。",
        "enableNotificationMessage": "提示框已啟用,點擊確定刷新後生效。",
        "disableNotificationMessage": "提示框已禁用,點擊確定刷新後生效。",
        "adjustPanelH2Title": "调整提示框样式(留空则不修改)",
        "adjustPanelPosition": "選擇提示框位置",
        "adjustPanelWidth": "提示框寬度(可以填auto)",
        "adjustPanelHeight": "提示框長度 (可以填auto)",
        "adjustPanelHideAfter": "提示框顯示時間 (毫秒,輸入數字即可)",
        "adjustPanelCustomMessage": "自定義提示詞",
        "adjustPanelSave": "保存",
        "adjustPanelCancel": "取消",
        "adjustPanelReset": "恢復默認設置",
        "adjustPanelPlaceholder": "當前爲",
        "exportList": "導出稍後觀看列表",
        "exportSuccess": "導出成功!文件已保存到下載文件夾。",
        "noVideosFound": "稍後觀看列表中未找到影片。"
    }
};

// 根据用户语言设置获取翻译
const lang = userLanguage.startsWith('zh-TW') ? 'zh-TW' :
userLanguage.startsWith('zh') ? 'zh-CN' : 'en';
const t = translations[lang];

// 主函数
(function() {
    'use strict';

/*
先判断当前是否为稍后再看页面
*/

    let lastUrl = window.location.href;  // 保存上一次的 URL

    // 初次加载时初始化
    if (window.location.href == "https://www.youtube.com/playlist?list=WL") {
        redirector();
    }

    const observer = new MutationObserver((mutations) => {
        mutations.forEach(mutation => {
            mutation.addedNodes.forEach(node => {
                if (node.nodeType === Node.ELEMENT_NODE) {
                    // 检查 Shadow DOM 中的元素
                    if (node.shadowRoot) {
                        const targetElement = node.shadowRoot.querySelector('yt-formatted-string.title.style-scope.ytd-guide-entry-renderer');
                        if (targetElement) {
                            targetElement.addEventListener('click', () => {
                                //console.log('YouTube稍后再看脚本 - 点击了“稍后观看”按钮');
                                redirector();
                            });
                        }
                    }
                    // 处理非 Shadow DOM 元素
                    if (node.matches('yt-formatted-string.title.style-scope.ytd-guide-entry-renderer')) {
                        node.addEventListener('click', () => {
                            //console.log('YouTube稍后再看脚本 - 点击了“稍后观看”按钮');
                            redirector();
                        });
                    }
                }
            });
        });
    });

    observer.observe(document.body, { childList: true, subtree: true });

    // 监听 URL 变化 (pushState 和 popstate)
    const originalPushState = history.pushState;
    history.pushState = function() {
        originalPushState.apply(this, arguments);
        onUrlChange();
    };

    window.addEventListener('popstate', onUrlChange); // 处理前进和后退按钮

/*
对稍后再看页面作重定向处理
*/

// 重定向
    function redirector() {
        const observer = new MutationObserver((mutationsList, observer) => {
            // 查询稍后再看列表中的视频元素
            const items = document.querySelectorAll('div#content.style-scope.ytd-playlist-video-renderer');

            if (items.length > 0) {
                showNotification(items.length);
                observer.disconnect();

                items.forEach(item => {
                    if (!item.dataset.redirectBound) {
                        item.dataset.redirectBound = true;

                        // 获取缩略图和标题区域
                        const thumbnail = item.querySelector('ytd-thumbnail#thumbnail');
                        const metaArea = item.querySelector('div#meta');

                        if (thumbnail && metaArea) {
                            // 处理缩略图区域
                            const videoTitle = metaArea.querySelector('a#video-title');
                            if (videoTitle) {
                                const href = videoTitle.getAttribute('href');
                                if (href && href.includes('list=WL')) {
                                    const videoId = href.match(/v=([^&]+)/)[1];
                                    const originalUrl = `https://www.youtube.com/watch?v=${videoId}`;
                                    // 存储原始URL到缩略图元素
                                    thumbnail.setAttribute('data-original-url', originalUrl);
                                    
                                    // 为缩略图内的所有可点击元素添加事件处理
                                    thumbnail.querySelectorAll('a, img, .yt-core-image').forEach(element => {
                                        
                                        // 左键点击缩略图
                                        element.addEventListener('click', function(event) {
                                            event.preventDefault();
                                            event.stopPropagation();
                                            window.open(originalUrl, '_blank');
                                            return false;
                                        });

                                        // 中键点击缩略图
                                        element.addEventListener('auxclick', function(event) {
                                            if (event.button === 1) {
                                                event.preventDefault();
                                                event.stopPropagation();
                                                window.open(originalUrl, '_blank');
                                                return false;
                                            }
                                        });
                                    });
                                }
                            }

                            // 处理标题区域
                            metaArea.addEventListener('mouseover', function() {
                                const videoTitle = metaArea.querySelector('a#video-title');
                                if (videoTitle) {
                                    const href = videoTitle.getAttribute('href');
                                    if (href && href.includes('list=WL')) {
                                        const videoId = href.match(/v=([^&]+)/)[1];
                                        const originalUrl = `https://www.youtube.com/watch?v=${videoId}`;
                                        videoTitle.setAttribute('data-original-url', originalUrl);
                                    }
                                }
                            });

                            // 左键点击标题
                            metaArea.addEventListener('click', function(event) {
                                handleLinkClick(event);
                            });

                            // 中键点击标题
                            metaArea.addEventListener('auxclick', function(event) {
                                if (event.button === 1) {
                                    handleLinkClick(event);
                                }
                            });
                        }
                    }
                });
            }
        });

        // 监听 DOM 变化
        observer.observe(document.body, { childList: true, subtree: true });
    }

    function handleLinkClick(event) { // 处理左键和中键点击稍后再看视频的行为
        const target = event.target;
        if (target.hasAttribute('href') && target.getAttribute('href').includes('@')) {
            return; // 点击的是作者主页链接,直接跳转,不重定向
        }

        const linkElement = target.closest('div#meta.style-scope.ytd-playlist-video-renderer').querySelector('a#video-title');
        if (linkElement) {
            const originalUrl = linkElement.getAttribute('data-original-url');
            if (originalUrl) {
                event.preventDefault();  // 阻止默认跳转行为
                event.stopPropagation(); // 阻止事件冒泡
                window.open(originalUrl, '_blank');  // 在新标签页中打开原视频链接
                return false;  // 防止进一步的默认跳转行为
            }
        }
    }

    // 页面跳转或 URL 变化时触发重新初始化脚本
    function onUrlChange() {
        if (window.location.href !== lastUrl) {
            //console.log('YouTube稍后再看脚本 - 检测到 URL 变化: ', window.location.href);
            if (window.location.href == "https://www.youtube.com/playlist?list=WL") {
                redirector();
            }
            lastUrl = window.location.href;  // 更新 lastUrl
        }
    }

/*
提示框及其菜单
*/

    // 默认设置
    const defaultSettings = {
        showNotification: true,
        position: 'bottom-right',
        width: 'auto',
        height: 'auto',
        hideAfter: 3000,
        customMessage: t.notificationMessage  // 默认提示词
    };

    // 注册菜单项
    function registerMenuCommands() {
        if (!getSettings().showNotification) {
            GM_registerMenuCommand(t.enableNotification, toggleNotification);
        } else {
            GM_registerMenuCommand(t.disableNotification, toggleNotification);
            GM_registerMenuCommand(t.adjustNotificationStyle, createStyleAdjustmentPanel);
        }
        
        // 添加导出列表菜单项
        GM_registerMenuCommand(t.exportList, exportWatchLaterList);
    }

    // 打开提示框开关菜单
    function toggleNotification() {
        const settings = getSettings();
        const newShowNotification = !settings.showNotification;
        saveSettings({ ...settings, showNotification: newShowNotification });

        // 更新菜单项显示状态
        updateMenuCommands();
    }

    // 更新菜单项显示状态
    function updateMenuCommands() {
        const settings = getSettings();
        const newShowNotification = !settings.showNotification;
        alert(`${newShowNotification ? t.enableNotificationMessage : t.disableNotificationMessage}`);
        location.reload(); // 刷新页面
    }

    // 初次注册菜单项
    registerMenuCommands();

    // 创建样式调整面板并使用 Shadow DOM
    function createStyleAdjustmentPanel() {
        const settings = getSettings();
        // 创建容器,并为其附加 Shadow DOM
        const panelContainer = document.createElement('div');
        panelContainer.style.position = 'fixed';
        panelContainer.style.top = '0';
        panelContainer.style.left = '0';
        panelContainer.style.width = '100vw';
        panelContainer.style.height = '100vh';
        panelContainer.style.zIndex = '10001';
        panelContainer.style.backgroundColor = 'rgba(0, 0, 0, 0.5)'; // 添加遮罩效果

        const shadowRoot = panelContainer.attachShadow({ mode: 'open' });

        shadowRoot.innerHTML = `
        <style>
            #panel {
                position: fixed;
                top: 50%;
                left: 50%;
                transform: translate(-50%, -50%);
                padding: 20px;
                background-color: #f9f9f9;
                border: 1px solid #ccc;
                box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
                z-index: 10002;
                width: 300px;
                height: auto;
            }
            button {
                margin-top: 15px;
            }
            #reset {
                position: absolute;
                bottom: 10px;
                right: 10px;
            }
        </style>
        <div id="panel">
            <h2>${t.adjustPanelH2Title}</h2>
            <label>
                ${t.adjustPanelPosition}(now at ${settings.position}):<br>
                <select id="position-select">
                    <option value="bottom-right">bottom-right</option>
                    <option value="top-right">top-right</option>
                    <option value="top-left">top-left</option>
                    <option value="bottom-left">bottom-left</option>
                </select>
            </label><br>
            <label>
                ${t.adjustPanelWidth}:<br>
                <input type="text" id="width" placeholder="${t.adjustPanelPlaceholder}${settings.width}">
            </label><br>
            <label>
                ${t.adjustPanelHeight}:<br>
                <input type="text" id="height" placeholder="${t.adjustPanelPlaceholder}${settings.height}">
            </label><br>
            <label>
                ${t.adjustPanelHideAfter}:<br>
                <input type="number" id="hideAfter" placeholder="${t.adjustPanelPlaceholder}${settings.hideAfter}ms">
            </label><br>
            <label>
                ${t.adjustPanelCustomMessage}:<br>
                <input type="text" id="customMessage" placeholder="${t.adjustPanelPlaceholder}“${settings.customMessage}”">
            </label><br>
            <button id="save">${t.adjustPanelSave}</button>
            <button id="cancel">${t.adjustPanelCancel}</button>
            <button id="reset">${t.adjustPanelReset}</button> <!-- 添加恢复默认设置按钮 -->
        </div>
    `;

        // 将面板插入到页面中
        document.documentElement.appendChild(panelContainer);

        const positionSelect = shadowRoot.querySelector('#position-select');
        window.selectedPosition = settings.position;

        // 监听 select 元素的 change 事件
        positionSelect.addEventListener('change', function(event) {
            selectedPosition = event.target.value; // 获取当前选择的值
            console.log('稍后再看Selected position:', selectedPosition);

            // 将选择的值保存到一个变量或状态中
            // 如果需要在点击保存按钮时使用
            window.selectedPosition = selectedPosition;
            //console.log('稍后再看window.selectedPosition为:', window.selectedPosition);
        });

        // 绑定事件到 Shadow DOM 中的元素
        // shadowRoot.getElementById('save').addEventListener('click', () => saveSettingsByPanel(shadowRoot));
        // 使用全局变量
        window.shadowRoot = shadowRoot;
        shadowRoot.getElementById('save').addEventListener('click', () => {
            const confirmed = confirm(t.confirmSave);
            if (!confirmed) {
                return;
            }

            const settings = getSettings();
            const newPosition = window.selectedPosition;
            // 获取其他设置值,如果为空则保持原值
            const shadowRoot = window.shadowRoot;
            const newWidth = shadowRoot.getElementById('width').value || settings.width;
            const newHeight = shadowRoot.getElementById('height').value || settings.height;
            const newHideAfter = parseInt(shadowRoot.getElementById('hideAfter').value, 10) || settings.hideAfter;
            const newCustomMessage = shadowRoot.getElementById('customMessage').value;

            const newSettings = {
                ...settings,
                position: newPosition,
                width: newWidth,
                height: newHeight,
                hideAfter: newHideAfter,
                customMessage: newCustomMessage
            };

            saveSettings(newSettings);

            // 提示并刷新页面
            alert(t.savedMessage);
            location.reload(); // 刷新页面
        });

        shadowRoot.getElementById('cancel').addEventListener('click', () => {
            panelContainer.remove(); // 关闭面板
        });

        // 绑定恢复默认设置按钮的点击事件,并弹出确认框
        shadowRoot.getElementById('reset').addEventListener('click', () => {
            const confirmed = confirm(t.confirmReset);
            if (confirmed) {
                restoreDefaultSettings();
                alert(t.resetMessage);
                location.reload(); // 刷新页面
            }
        });
    }

    // 不想为了传递一个shadowRoot参数,而定义一个函数
    // function saveSettingsByPanel(shadowRoot){
    //     const confirmed = confirm(t.confirmSave);
    //     if (!confirmed) {
    //         return;
    //     }

    //     //console.log("稍后再看selectedPosition为:", window.selectedPosition);
    //     const settings = getSettings();
    //     const newPosition = window.selectedPosition;
    //     // 获取其他设置值,如果为空则保持原值
    //     const newWidth = shadowRoot.getElementById('width').value || settings.width;
    //     const newHeight = shadowRoot.getElementById('height').value || settings.height;
    //     const newHideAfter = parseInt(shadowRoot.getElementById('hideAfter').value, 10) || settings.hideAfter;
    //     const newCustomMessage = shadowRoot.getElementById('customMessage').value || settings.customMessage;

    //     const newSettings = {
    //         ...settings,
    //         position: newPosition,
    //         width: newWidth,
    //         height: newHeight,
    //         hideAfter: newHideAfter,
    //         customMessage: newCustomMessage
    //     };

    //     saveSettings(newSettings);

    //     // 提示并刷新页面
    //     alert(t.savedMessage);
    //     location.reload(); // 刷新页面
    // }

    // 恢复默认设置的函数
    function restoreDefaultSettings() {
        GM_setValue('position', defaultSettings.position);
        GM_setValue('width', defaultSettings.width);
        GM_setValue('height', defaultSettings.height);
        GM_setValue('hideAfter', defaultSettings.hideAfter);
        GM_setValue('customMessage', defaultSettings.customMessage);
    }

    // 从存储中获取设置
    function getSettings() {
        return {
            showNotification: GM_getValue('showNotification', defaultSettings.showNotification),
            position: GM_getValue('position', defaultSettings.position),
            width: GM_getValue('width', defaultSettings.width),
            height: GM_getValue('height', defaultSettings.height),
            hideAfter: GM_getValue('hideAfter', defaultSettings.hideAfter),
            customMessage: GM_getValue('customMessage', defaultSettings.customMessage)
        };
    }

    // 保存设置
    function saveSettings(settings) {
        GM_setValue('showNotification', settings.showNotification);
        GM_setValue('position', settings.position);
        GM_setValue('width', settings.width);
        GM_setValue('height', settings.height);
        GM_setValue('hideAfter', settings.hideAfter);
        GM_setValue('customMessage', settings.customMessage);
    }

    // 创建或更新提示框
    function createNotification() {
        const settings = getSettings();
        const notification = document.getElementById('redirect-notification') || document.createElement('div');
        notification.id = 'redirect-notification';
        notification.style.position = 'fixed';
        notification.style[settings.position.split('-')[0]] = '20px';
        notification.style[settings.position.split('-')[1]] = '20px';
        notification.style.width = settings.width;
        notification.style.height = settings.height;
        notification.style.padding = '10px 20px';
        notification.style.backgroundColor = '#333';
        notification.style.color = '#fff';
        notification.style.fontSize = '16px';
        notification.style.borderRadius = '5px';
        notification.style.boxShadow = '0px 0px 10px rgba(0, 0, 0, 0.5)';
        notification.style.zIndex = '10000';
        notification.style.opacity = '0'; // 初始隐藏
        notification.style.transition = 'opacity 0.5s'; // 动画效果
        document.body.appendChild(notification);
        return notification;
    }

    // 显示提示框,并在规定时间内自动消失
    function showNotification(itemCount) {
        const settings = getSettings();
        if (!settings.showNotification) return;
        const notification = createNotification();
        notification.textContent = settings.customMessage;
        notification.style.opacity = '1'; // 显示提示框

        // 在指定时间后自动隐藏提示框
        setTimeout(() => {
            notification.style.opacity = '0'; // 隐藏提示框
        }, settings.hideAfter);
    }

    // 导出稍后观看列表
    function exportWatchLaterList() {
        // 确保当前页面是稍后观看列表
        if (window.location.href !== "https://www.youtube.com/playlist?list=WL") {
            window.open("https://www.youtube.com/playlist?list=WL", "_blank");
            return;
        }
        
        // 等待页面加载完成
        setTimeout(() => {
            const items = document.querySelectorAll('div#content.style-scope.ytd-playlist-video-renderer');
            
            if (items.length === 0) {
                alert(t.noVideosFound);
                return;
            }
            
            let videoLinks = [];
            let videoTitles = [];
            let videoAuthors = [];
            let authorLinks = [];
            
            items.forEach(item => {
                const metaArea = item.querySelector('div#meta');
                if (metaArea) {
                    // 获取视频标题和链接
                    const videoTitle = metaArea.querySelector('a#video-title');
                    if (videoTitle) {
                        const href = videoTitle.getAttribute('href');
                        if (href && href.includes('list=WL')) {
                            // 获取视频链接及标题
                            const videoId = href.match(/v=([^&]+)/)[1];
                            const originalUrl = `https://www.youtube.com/watch?v=${videoId}`;
                            const title = videoTitle.textContent.trim();
                            videoLinks.push(originalUrl);
                            videoTitles.push(title);
                            
                            // 获取作者信息
                            const authorElement = metaArea.querySelector('a.yt-simple-endpoint.style-scope.yt-formatted-string');
                            if (authorElement) {
                                const authorName = authorElement.textContent.trim();
                                const authorUrl = `https://www.youtube.com${authorElement.getAttribute('href')}`;
                                videoAuthors.push(authorName);
                                authorLinks.push(authorUrl);
                            } else {
                                videoAuthors.push('Unknown Author');
                                authorLinks.push('');
                            }
                        }
                    }
                }
            });
            
            if (videoLinks.length > 0) {
                // 创建导出内容,添加视频总数信息
                let exportContent = `Totally ${videoLinks.length} videos exported!\n\n`;
                
                // 添加带序号的视频信息
                for (let i = 0; i < videoLinks.length; i++) {
                    exportContent += `Video index: ${i + 1}\n${videoTitles[i]}\nauthor: ${videoAuthors[i]}, ${authorLinks[i]}\n${videoLinks[i]}\n\n`;
                }
                
                // 创建下载链接
                const blob = new Blob([exportContent], { type: 'text/plain' });
                const url = URL.createObjectURL(blob);
                const a = document.createElement('a');
                const date = new Date();
                const dateString = `${date.getFullYear()}-${(date.getMonth()+1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')}-${date.getHours().toString().padStart(2, '0')}${date.getMinutes().toString().padStart(2, '0')}${date.getSeconds().toString().padStart(2, '0')}`;
                a.href = url;
                a.download = `YouTube-Watch-Later-List-${dateString}.txt`;
                a.style.display = 'none';
                document.body.appendChild(a);
                a.click();
                document.body.removeChild(a);
                URL.revokeObjectURL(url);
                
                alert(t.exportSuccess);
            } else {
                alert(t.noVideosFound);
            }
        }, 2000); // 给页面加载留出足够时间
    }

})();