EdgeDL

EdgeDL:让 Android Edge 浏览器使用外部下载器下载文件

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(У мене вже є менеджер скриптів, дайте мені встановити його!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         EdgeDL
// @namespace    https://github.com/Chumor/EdgeDL
// @version      1.3.2
// @description  EdgeDL:让 Android Edge 浏览器使用外部下载器下载文件
// @icon         data:image/png;base64,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
// @author       Chumor
// @match        *://*/*
// @grant        GM_registerMenuCommand
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_deleteValue
// @license      Apache-2.0
// @run-at       document-start
// ==/UserScript==


(function () {
    'use strict';

    // 下载器用户配置
    const DOWNLOADERS = {
        IDM: 'idm.internet.download.manager.plus',
        ADM: 'com.dv.adm',
    };

    // 默认下载器
    GM_getValue('edgedl-default-downloader') || DOWNLOADERS.IDM;

    // 下载链接关键字匹配
    const EXTENSIONS = [
        '.apk','.apks','.xapk','.apkm','.ipa','.obb','.aab',
        '.zip','.rar','.7z','.tar','.gz','.tgz','.bz2','.xz',
        '.iso','.cab','.jar','.z',
        '.mp4','.mkv','.avi','.mov','.flv','.wmv','.webm',
        '.m4v','.3gp','.ts','.mpg','.mpeg','.vob',
        '.mp3','.flac','.wav','.ogg','.m4a','.aac','.wma','.ape',
        '.pdf','.epub','.mobi','.azw3','.djvu',
        '.doc','.docx','.xls','.xlsx','.ppt','.pptx',
        '.exe','.msi','.bin','.dat','.dmg','.bat','.sh','.img',
        '.torrent'
    ];

    // 下载链接后缀匹配
    const KEYWORDS = [
        '/down/','/download/','/downloads/','/dl/','/get/','/fetch/',
        '/files/','/file/','/attach/','/attachment/','/media/','/static/',
        '/assets/','/cdn/','/dist/','/repo/','/backup/','/upload/',
        '/releases/download/','/binary/','/pkg/',
        '?file=','&file=','?filename=','&filename=','?f=','&f=',
        'download?','&download=','?download=','&download=',
        'token=','auth_key=','download_token=','sig=','signature=',
        'force_download','response-content-disposition=',
        'content-disposition=attachment'
    ];

    // 下载链接检测
    function isDownloadLink(url){
        if(url?.includes('sourceforge.net/projects/') && url.includes('/files/')) return false;
        if(!url || !url.startsWith('http')) return false;
        const lowerUrl = url.toLowerCase();

        // 排除非下载页面
        if(
            lowerUrl.includes('/login')||lowerUrl.includes('/register')||
            lowerUrl.includes('/signin')||lowerUrl.includes('/signup')||
            lowerUrl.includes('/logout')||
            lowerUrl.includes('/account/')||lowerUrl.includes('/user/')||
            lowerUrl.includes('/blob/')||lowerUrl.includes('/src/')||
            lowerUrl.includes('/tree/')
        ) return false;

        // 后缀匹配
        try{
            const path = new URL(url).pathname.toLowerCase();
            if(EXTENSIONS.some(ext=>path.endsWith(ext))) return true;
        }catch(e){
            const path = lowerUrl.split('?')[0].split('#')[0];
            if(EXTENSIONS.some(ext=>path.endsWith(ext))) return true;
        }

        // 关键字匹配
        return KEYWORDS.some(kw=>lowerUrl.includes(kw));
    }

    function showToast(message, duration = 1500) {
        try {
            const toast = document.createElement('div');
            toast.textContent = message;
            toast.style.cssText = `
            position: fixed;
            bottom: 15%;
            left: 50%;
            transform: translateX(-50%);
            font-weight: 500;
            font-size: 13px;
            padding: 10px 20px;
            border-radius: 12px;
            box-shadow: 0 4px 12px rgba(0,0,0,0.3);
            z-index: 999999;
            pointer-events: none;
            opacity: 0;
            transition: opacity 0.3s ease-in-out;
        `;

            if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
                toast.style.background = 'rgba(255,255,255,0.12)';
                toast.style.color = '#fff';
            } else {
                toast.style.background = 'rgba(0,0,0,0.85)';
                toast.style.color = '#fff';
            }

            document.body.appendChild(toast);

            requestAnimationFrame(() => {
                toast.style.opacity = '1';
            });

            setTimeout(() => {
                toast.style.opacity = '0';
                toast.addEventListener('transitionend', () => toast.remove(), { once: true });
            }, duration);
        } catch (err) {
            console.warn('Toast 创建失败', err);
        }
    }

    const KEY = 'edgedl-blacklist';

    // 获取黑名单数组
    async function getBlacklist() {
        const list = await GM_getValue(KEY, []);
        return Array.isArray(list) ? list : [];
    }

    // 保存黑名单
    async function saveBlacklist(list) {
        const norm = Array.from(
            new Set(list.map(i => (typeof i === 'string' ? i.toLowerCase() : i)))
        );
        await GM_setValue(KEY, norm);
        return norm;
    }

    // 判断当前站点是否在黑名单
    async function isCurrentSiteBlacklisted() {
        const host = location.hostname.toLowerCase();
        const list = await getBlacklist();
        return list.some(item => item.toLowerCase() === host);
    }

    // 切换当前站点黑名单状态
    async function toggleCurrentSite() {
        const host = location.hostname.toLowerCase();
        const list = await getBlacklist();

        let added;
        const index = list.findIndex(item => item.toLowerCase() === host);
        if (index >= 0) {
            list.splice(index, 1);
            added = false;
        } else {
            list.push(host);
            added = true;
        }

        await saveBlacklist(list);
        return added;
    }

    async function openIDM(url, packageName) {
        if (await isCurrentSiteBlacklisted()) { showToast('黑名单:下载已阻止'); return; }
        const scheme = url.startsWith('https') ? 'https' : 'http';
        const cleanLink = url.replace(/^https?:\/\//, '');
        const intentUrl = `intent://${cleanLink}#Intent;scheme=${scheme};package=${packageName};type=*/*;end`;
        window.location.href = intentUrl;
    }

    async function openADM(url) {
        if (await isCurrentSiteBlacklisted()) { showToast('黑名单:下载已阻止'); return; }
        const scheme = url.startsWith('https') ? 'https' : 'http';
        const cleanLink = url.replace(/^https?:\/\//, '');
        const intentUrl = `intent://${cleanLink}#Intent;scheme=${scheme};package=${DOWNLOADERS.ADM};type=*/*;end`;
        window.location.href = intentUrl;
        setTimeout(() => {
            window.location.href = intentUrl;
        }, 200);
    }

    // 调用指定下载器下载
    async function openDownload(url, downloader) {
        if (await isCurrentSiteBlacklisted()) { showToast('黑名单:下载已阻止'); return; }
        switch (downloader) {
            case 'idm.internet.download.manager':
                showToast('⚡ 1DM 正在唤起');
                openIDM(url, 'idm.internet.download.manager');
                break;

            case DOWNLOADERS.IDM:
                showToast('⚡ 1DM+ 正在唤起');
                openIDM(url, DOWNLOADERS.IDM);
                break;

            case DOWNLOADERS.ADM:
                showToast('⚡ ADM 正在唤起');
                openADM(url);
                break;

            case 'edge':
            default:
                showToast('⚡ Edge 内置下载');
                GM_download({ url, saveAs: false });
                break;
        }
    }

    const downloaderIcons = {
        IDM: 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48IS0tIFVwbG9hZGVkIHRvOiBTVkcgUmVwbywgd3d3LnN2Z3JlcG8uY29tLCBHZW5lcmF0b3I6IFNWRyBSZXBvIE1peGVyIFRvb2xzIC0tPg0KPHN2ZyB3aWR0aD0iODAwcHgiIGhlaWdodD0iODAwcHgiIHZpZXdCb3g9IjAgMCAxOTIgMTkyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDE5MiAxOTIiIHhtbDpzcGFjZT0icHJlc2VydmUiPjxwYXRoIGQ9Ik00NS45IDg4LjJjMCAxLjItLjcgMi4xLTEuOSAyLjMtMTMuMiAyLjktMjIuNSAxNC44LTIyIDI4IC4zIDcuNCAzLjggMTQuNCA5LjMgMTkuNCA1LjggNS4yIDEyLjggNyAyMC40IDYuOSAxMC0uMSAyMC4yIDAgMzAuNCAwaDU4LjNjOC43IDAgMTYuMS0yLjMgMjIuMS04LjggNS40LTUuOCA4LjQtMTQgNy4zLTIxLjktMS40LTEwLjUtOS41LTE5LjYtMjAuNC0yMi42LTEuMi0uMy0xLjktMS41LTEuNy0yLjUuNi00LjUgMS4yLTE0LjItNC41LTIzLjktOC4zLTE0LTIyLjctMTYuOS0yNS0xNy4zLTEyLjktMi4zLTIyLjYgMy0yNSA0LjMtOS40IDUuNS0xMy44IDEzLjUtMTUuNyAxOC0uNSAxLjQtMi4xIDEuOS0zLjQgMS4yLTUuNC0zLjMtMTIuMS0zLjctMTcuNy0xLjItNi42IDMtMTAuOCAxMC4zLTEwLjUgMTguMXptNTUuOC03Ljd2MjkuM0wxMTQgOTcuNWwtMTIuMyAxMi4zLTEyLjMtMTIuM20tNS4yIDI3LjdoMzUiIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjEyO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDoxMCIvPjwvc3ZnPg==',
        IDM_PLUS: 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48IS0tIFVwbG9hZGVkIHRvOiBTVkcgUmVwbywgd3d3LnN2Z3JlcG8uY29tLCBHZW5lcmF0b3I6IFNWRyBSZXBvIE1peGVyIFRvb2xzIC0tPg0KPHN2ZyB3aWR0aD0iODAwcHgiIGhlaWdodD0iODAwcHgiIHZpZXdCb3g9IjAgMCAxOTIgMTkyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDE5MiAxOTIiIHhtbDpzcGFjZT0icHJlc2VydmUiPjxwYXRoIGQ9Ik00NC43IDEwMC4zYzAgMS4xLS43IDItMS44IDIuMi0xMi41IDIuNy0yMS40IDE0LjEtMjAuOSAyNi42LjMgNyAzLjYgMTMuNyA4LjggMTguNCA1LjUgNC45IDEyLjEgNi42IDE5LjQgNi41IDkuNS0uMSAxOS4yIDAgMjguOCAwaDU1LjNjOC4yIDAgMTUuMy0yLjIgMjEtOC4zIDUuMS01LjUgNy45LTEzLjMgNi45LTIwLjgtMS4zLTkuOS05LTE4LjYtMTkuNC0yMS41LTEuMS0uMy0xLjgtMS40LTEuNi0yLjQuNi00LjMgMS4xLTEzLjUtNC4zLTIyLjctNy44LTEzLjMtMjEuNi0xNi4xLTIzLjctMTYuNS0xMi4yLTIuMS0yMS40IDIuOS0yMy42IDQuMi04LjkgNS4yLTEzLjEgMTIuOC0xNC45IDE3LjEtLjUgMS4zLTIgMS44LTMuMiAxLjEtNS4xLTMuMS0xMS40LTMuNS0xNi44LTEuMS02LjMgMy0xMC4zIDkuOS0xMCAxNy4yek0xNTQuOSAzOHYzMC4xbS0xNS0xNUgxNzBNOTcuNiA5M3YyNy45bDExLjgtMTEuNy0xMS44IDExLjdMODYgMTA5LjJtLTQuNCAyNi4zaDMyIiBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDoxMjtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6MTAiLz48L3N2Zz4=',
        ADM: 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48IS0tIFVwbG9hZGVkIHRvOiBTVkcgUmVwbywgd3d3LnN2Z3JlcG8uY29tLCBHZW5lcmF0b3I6IFNWRyBSZXBvIE1peGVyIFRvb2xzIC0tPg0KPHN2ZyB3aWR0aD0iODAwcHgiIGhlaWdodD0iODAwcHgiIHZpZXdCb3g9IjAgMCA0OCA0OCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZGVmcz48c3R5bGU+LmF7ZmlsbDpub25lO3N0cm9rZTojMDAwMDAwO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZDt9PC9zdHlsZT48L2RlZnM+PHBvbHlsaW5lIGNsYXNzPSJhIiBwb2ludHM9IjI5LjM0IDMzLjA0IDM0LjU5IDM5Ljc1IDQzLjUgMjguMzcgMzguMjYgMjguMzcgMzguMjYgMTcuMjEgMzAuOTIgMTcuMjEgMzAuOTIgMjMuODQiLz48cG9seWxpbmUgY2xhc3M9ImEiIHBvaW50cz0iMTguOTUgMjEuNTUgMTcuMDggMjEuNTUgMTcuMDggMTAuMzkgOS43NCAxMC4zOSA5Ljc0IDIxLjU1IDQuNSAyMS41NSAxMy40MSAzMi45MyAxNi4wOCAyOS41MiIvPjxwb2x5Z29uIGNsYXNzPSJhIiBwb2ludHM9IjI5LjIyIDIzLjg0IDI5LjIyIDguMjUgMTguOTUgOC4yNSAxOC45NSAyMy44NCAxMS42MyAyMy44NCAyNC4wOSAzOS43NSAzNi41NCAyMy44NCAyOS4yMiAyMy44NCIvPjwvc3ZnPg==',
        EDGE: 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48IS0tIFVwbG9hZGVkIHRvOiBTVkcgUmVwbywgd3d3LnN2Z3JlcG8uY29tLCBHZW5lcmF0b3I6IFNWRyBSZXBvIE1peGVyIFRvb2xzIC0tPgo8c3ZnIHdpZHRoPSI4MDBweCIgaGVpZ2h0PSI4MDBweCIgdmlld0JveD0iMCAwIDI3NjAwIDI3NjAwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIj48bGluZWFyR3JhZGllbnQgaWQ9IkEiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIi8+PGxpbmVhckdyYWRpZW50IGlkPSJCIiB4MT0iNjg3MCIgeDI9IjI0NzA0IiB5MT0iMTg3MDUiIHkyPSIxODcwNSIgeGxpbms6aHJlZj0iI0EiPjxzdG9wIG9mZnNldD0iMCIgc3RvcC1jb2xvcj0iIzBjNTlhNCIvPjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzExNGE4YiIvPjwvbGluZWFyR3JhZGllbnQ+PGxpbmVhckdyYWRpZW50IGlkPSJDIiB4MT0iMTYyNzIiIHgyPSI1MTMzIiB5MT0iMTA5NjgiIHkyPSIyMzEwMiIgeGxpbms6aHJlZj0iI0EiPjxzdG9wIG9mZnNldD0iMCIgc3RvcC1jb2xvcj0iIzFiOWRlMiIvPjxzdG9wIG9mZnNldD0iLjE2IiBzdG9wLWNvbG9yPSIjMTU5NWRmIi8+PHN0b3Agb2Zmc2V0PSIuNjciIHN0b3AtY29sb3I9IiMwNjgwZDciLz48c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiMwMDc4ZDQiLz48L2xpbmVhckdyYWRpZW50PjxyYWRpYWxHcmFkaWVudCBpZD0iRCIgY3g9IjE2NzIwIiBjeT0iMTg3NDciIHI9Ijk1MzgiIHhsaW5rOmhyZWY9IiNBIj48c3RvcCBvZmZzZXQ9Ii43MiIgc3RvcC1vcGFjaXR5PSIwIi8+PHN0b3Agb2Zmc2V0PSIuOTUiIHN0b3Atb3BhY2l0eT0iLjUzIi8+PHN0b3Agb2Zmc2V0PSIxIi8+PC9yYWRpYWxHcmFkaWVudD48cmFkaWFsR3JhZGllbnQgaWQ9IkUiIGN4PSI3MTMwIiBjeT0iMTk4NjYiIHI9IjE0MzI0IiBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KC4xNDg0MyAtLjk4ODkyIC43OTY4OCAuMTE5NiAtODc1OSAyNTU0MikiIHhsaW5rOmhyZWY9IiNBIj48c3RvcCBvZmZzZXQ9Ii43NiIgc3RvcC1vcGFjaXR5PSIwIi8+PHN0b3Agb2Zmc2V0PSIuOTUiIHN0b3Atb3BhY2l0eT0iLjUiLz48c3RvcCBvZmZzZXQ9IjEiLz48L3JhZGlhbEdyYWRpZW50PjxyYWRpYWxHcmFkaWVudCBpZD0iRiIgY3g9IjI1MjMiIGN5PSI0NjgwIiByPSIyMDI0MyIgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgtLjAzNzE1IC45OTkzMSAtMi4xMjgzNiAtLjA3OTEzIDEzNTc5IDM1MzApIiB4bGluazpocmVmPSIjQSI+PHN0b3Agb2Zmc2V0PSIwIiBzdG9wLWNvbG9yPSIjMzVjMWYxIi8+PHN0b3Agb2Zmc2V0PSIuMTEiIHN0b3AtY29sb3I9IiMzNGMxZWQiLz48c3RvcCBvZmZzZXQ9Ii4yMyIgc3RvcC1jb2xvcj0iIzJmYzJkZiIvPjxzdG9wIG9mZnNldD0iLjMxIiBzdG9wLWNvbG9yPSIjMmJjM2QyIi8+PHN0b3Agb2Zmc2V0PSIuNjciIHN0b3AtY29sb3I9IiMzNmM3NTIiLz48L3JhZGlhbEdyYWRpZW50PjxyYWRpYWxHcmFkaWVudCBpZD0iRyIgY3g9IjI0MjQ3IiBjeT0iNzc1OCIgcj0iOTczNCIgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCguMjgxMDkgLjk1OTY4IC0uNzgzNTMgLjIyOTQ5IDI0NTEwIC0xNjI5MikiIHhsaW5rOmhyZWY9IiNBIj48c3RvcCBvZmZzZXQ9IjAiIHN0b3AtY29sb3I9IiM2NmViNmUiLz48c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiM2NmViNmUiIHN0b3Atb3BhY2l0eT0iMCIvPjwvcmFkaWFsR3JhZGllbnQ+PHBhdGggaWQ9IkgiIGQ9Ik0yNDEwNSAyMDA1M2E5MzQ1IDkzNDUgMCAwMS0xMDUzIDQ3MiAxMDIwMiAxMDIwMiAwIDAxLTM1OTAgNjQ2Yy00NzMyIDAtODg1NS0zMjU1LTg4NTUtNzQzMiAwLTExNzUgNjgwLTIxOTMgMTY0My0yNzI5LTQyODAgMTgwLTUzODAgNDY0MC01MzgwIDcyNTMgMCA3Mzg3IDY4MTAgODEzNyA4Mjc2IDgxMzcgNzkxIDAgMTk4NC0yMzAgMjcwNC00NTZsMTMwLTQ0YTEyODM0IDEyODM0IDAgMDA2NjYwLTUyODJjMjIwLTM1MC0xNjgtNzU3LTUzNS01NjV6Ii8+PHBhdGggaWQ9IkkiIGQ9Ik0xMTU3MSAyNTE0MWE3OTEzIDc5MTMgMCAwMS0yMjczLTIxMzcgODE0NSA4MTQ1IDAgMDEtMTUxNC00NzQwIDgwOTMgODA5MyAwIDAxMzA5My02Mzk1IDgwODIgODA4MiAwIDAxMTM3My04NTljMzEyLTE0OCA4NDYtNDE0IDE1NTQtNDA0YTMyMzYgMzIzNiAwIDAxMjU2OSAxMjk3IDMxODQgMzE4NCAwIDAxNjM2IDE4NjZjMC0yMSAyNDQ2LTc5NjAtODAwNS03OTYwLTQzOTAgMC04MDA0IDQxNjYtODAwNCA3ODIwIDAgMjMxOSA1MzggNDE3MCAxMjEyIDU2MDRhMTI4MzMgMTI4MzMgMCAwMDc2ODQgNjc1NyAxMjc5NSAxMjc5NSAwIDAwMzkwOCA2MTBjMTQxNCAwIDI3NzQtMjMzIDQwNDUtNjU2YTc1NzUgNzU3NSAwIDAxLTYyNzgtODAzeiIvPjxwYXRoIGlkPSJKIiBkPSJNMTYyMzEgMTU4ODZjLTgwIDEwNS0zMzAgMjUwLTMzMCA1NjYgMCAyNjAgMTcwIDUxMiA0NzIgNzIzIDE0MzggMTAwMyA0MTQ5IDg2OCA0MTU2IDg2OGE1OTU0IDU5NTQgMCAwMDMwMjctODM5IDYxNDcgNjE0NyAwIDAwMTEzMy04NTAgNjE4MCA2MTgwIDAgMDAxOTEwLTQ0MzdjMjYtMjI0Mi03OTYtMzczMi0xMTMzLTQzOTItMjEyMC00MTQxLTY2OTQtNjUyNS0xMTY2OC02NTI1LTcwMTEgMC0xMjcwMyA1NjM1LTEyNzk4IDEyNjIwIDQ3LTM2NTQgMzY3OS02NjA1IDc5OTYtNjYwNSAzNTAgMCAyMzQ2IDM0IDQyMDAgMTAwNyAxNjM0IDg1OCAyNDkwIDE4OTQgMzA4NiAyOTIxIDYxOCAxMDY3IDcyOCAyNDE1IDcyOCAyOTUycy0yNzEgMTMzMy03ODAgMTk5MHoiLz48dXNlIGZpbGw9InVybCgjQikiIHhsaW5rOmhyZWY9IiNIIi8+PHVzZSBmaWxsPSJ1cmwoI0QpIiBvcGFjaXR5PSIuMzUiIHhsaW5rOmhyZWY9IiNIIi8+PHVzZSBmaWxsPSJ1cmwoI0MpIiB4bGluazpocmVmPSIjSSIvPjx1c2UgZmlsbD0idXJsKCNFKSIgb3BhY2l0eT0iLjQiIHhsaW5rOmhyZWY9IiNJIi8+PHVzZSBmaWxsPSJ1cmwoI0YpIiB4bGluazpocmVmPSIjSiIvPjx1c2UgZmlsbD0idXJsKCNHKSIgeGxpbms6aHJlZj0iI0oiLz48L3N2Zz4='
    };

    const DEFAULT_KEY = 'edgedl-default-downloader';
    const DEFAULT_PENDING_KEY = 'edgedl-default-pending';

    async function showDownloadPicker(url, callback, mode = 'download') {
        if (document.getElementById('edgedl-picker')) return;
        
        if (mode !== 'config' && await isCurrentSiteBlacklisted()) {
            showToast('🚫 当前站点在黑名单中');
            window.open(url, '_blank');
            if (typeof callback === 'function') callback('edge');
            return;
        }

        const idmIcon = downloaderIcons.IDM;
        const idmPlusIcon = downloaderIcons.IDM_PLUS;
        const admIcon = downloaderIcons.ADM;
        const edgeIcon = downloaderIcons.EDGE;

        const picker = document.createElement('div');
        picker.id = 'edgedl-picker';
        picker.innerHTML = `
        <div class="edgedl-bg"></div>
        <div class="edgedl-card">
            <h3>选择下载器</h3>
            <div class="edgedl-options">
                <button data-pkg="${DOWNLOADERS.IDM}">
                    <img src="${idmIcon}" /> 1DM
                </button>
                <button data-pkg="${DOWNLOADERS.IDM_PLUS || DOWNLOADERS.IDM}">
                    <img src="${idmPlusIcon}" /> 1DM+
                </button>
                <button data-pkg="${DOWNLOADERS.ADM}">
                    <img src="${admIcon}" /> ADM
                </button>
                <button data-pkg="edge">
                    <img src="${edgeIcon}" /> Edge
                </button>
            </div>
            <label style="margin-top: 12px; display: flex; align-items: center; gap: 6px; font-size: 13px;">
                <input type="checkbox" id="edgedl-set-default" /> 设为默认下载器
            </label>
        </div>
    `;

        document.documentElement.appendChild(picker);

        const layoutPicker = () => {
            const w = window.visualViewport ? visualViewport.width : document.documentElement.clientWidth;
            const card = picker.querySelector('.edgedl-card');
            if (card) card.style.maxWidth = (w - 32) + 'px';
        };
        layoutPicker();
        if (window.visualViewport) {
            visualViewport.addEventListener('resize', layoutPicker);
            visualViewport.addEventListener('scroll', layoutPicker);
        }
        
        // 注入下载器选择弹窗样式
        const style = document.createElement('style');
        style.textContent = `
        #edgedl-picker { position: fixed; inset: 0; display: flex; justify-content: center; align-items: center; z-index: 2147483647; pointer-events: none; contain: layout style paint; isolation: isolate; }
        #edgedl-picker .edgedl-bg { position: absolute; inset:0; background: rgba(0,0,0,0.45); backdrop-filter: blur(6px); animation: edgedl-fade-in .18s ease-out; pointer-events: auto; }
        #edgedl-picker .edgedl-card { position: relative; background: #fff; border-radius: 24px; padding: 20px; width: 260px; max-width: 100%; box-shadow: 0 10px 28px rgba(0,0,0,0.25); display: flex; flex-direction: column; align-items: center; animation: edgedl-slide-up .22s ease-out; pointer-events: auto; box-sizing: border-box; font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; font-weight: 400; line-height: 1.4; -webkit-font-smoothing: antialiased; }
        #edgedl-picker h3 { margin: 0 0 16px 0; font-weight: 500; font-size: 16px; }
        #edgedl-picker .edgedl-options { display: flex; flex-direction: column; width: 100%; gap: 12px; }
        #edgedl-picker .edgedl-options button { display: flex; align-items: center; gap: 10px; padding: 10px; border: none; border-radius: 12px; background: #f2f2f2; font-weight: 500; cursor: pointer; transition: background 0.2s; }
        #edgedl-picker .edgedl-options button:hover { background: #e0e0e0; }
        #edgedl-picker .edgedl-options img { width: 24px; height: 24px; }

        #edgedl-picker .edgedl-options button.selected {
            outline: 2px solid #4CAF50;
        }

        @media (prefers-color-scheme: dark) {
            #edgedl-picker .edgedl-card { background: #1E1E1E; color: #FFFFFF; box-shadow: 0 4px 16px rgba(0,0,0,0.6); }
            #edgedl-picker .edgedl-options button { background: #2C2C2C; color: #FFFFFF; }
        }

        @keyframes edgedl-fade-in {
            from { opacity: 0; }
            to { opacity: 1; }
        }

        @keyframes edgedl-slide-up {
            from { opacity: 0; transform: translateY(18px) scale(.98); }
            to { opacity: 1; transform: translateY(0) scale(1); }
        }

        @keyframes edgedl-fade-out {
            from { opacity: 1; }
            to { opacity: 0; }
        }

        @keyframes edgedl-slide-down {
            from { opacity: 1; transform: translateY(0) scale(1); }
            to { opacity: 0; transform: translateY(18px) scale(.98); }
        }

        #edgedl-picker.closing .edgedl-bg { animation: edgedl-fade-out .16s ease-in forwards; }
        #edgedl-picker.closing .edgedl-card { animation: edgedl-slide-down .18s ease-in forwards; }
    `;
        document.head.appendChild(style);

        // 读取默认下载器
        const defaultDownloader = await GM_getValue(DEFAULT_KEY, null);
        const defaultCheckbox = picker.querySelector('#edgedl-set-default');

        defaultCheckbox.checked = !!defaultDownloader;

        if (defaultDownloader) {
            // 高亮默认下载器按钮
            const defaultBtn = picker.querySelector(`button[data-pkg="${defaultDownloader}"]`);
            if (defaultBtn) defaultBtn.classList.add('selected');
        }

        // 当复选框变化时立即保存或清除“待设置”标志
        defaultCheckbox.addEventListener('change', async () => {
            if (defaultCheckbox.checked) {
                await GM_setValue(DEFAULT_PENDING_KEY, true);
            } else {
                await GM_deleteValue(DEFAULT_KEY);
                await GM_deleteValue(DEFAULT_PENDING_KEY);
            }
        });

        // 点击唤起
        picker.querySelectorAll('button').forEach(btn => {
            btn.addEventListener('click', async () => {
                const pkg = btn.dataset.pkg;
                const pending = await GM_getValue(DEFAULT_PENDING_KEY, false);

                // 若复选框已勾选或之前标记为“待设置”,保存为默认
                if (pkg === 'edge') {
                    await GM_deleteValue(DEFAULT_PENDING_KEY);
                } else if (defaultCheckbox.checked || pending) {
                    await GM_setValue(DEFAULT_KEY, pkg);
                    await GM_deleteValue(DEFAULT_PENDING_KEY);
                }

                // 调用回调唤起下载器
                switch (pkg) {
                    case DOWNLOADERS.IDM:
                        showToast('⚡ 1DM 正在唤起');
                        openIDM(url, DOWNLOADERS.IDM);
                        break;
                    case DOWNLOADERS.IDM_PLUS:
                        showToast('⚡ 1DM+ 正在唤起');
                        openIDM(url, DOWNLOADERS.IDM_PLUS);
                        break;
                    case DOWNLOADERS.ADM:
                        showToast('⚡ ADM 正在唤起');
                        openADM(url);
                        break;
                    default:
                        showToast('⚡ Edge 内置下载');
                        window.open(url, '_blank');
                }

                if (typeof callback === 'function') callback(pkg);

                picker.classList.add('closing');
                picker.addEventListener('animationend', () => {
                   if (window.visualViewport) {
                        visualViewport.removeEventListener('resize', layoutPicker);
                        visualViewport.removeEventListener('scroll', layoutPicker);
                    }
                    picker.remove();
                    style.remove();
                    window.dispatchEvent(new CustomEvent('edgedl:picker-closed'));
                }, { once: true });

            });
        });

        // 点击背景关闭
        picker.querySelector('.edgedl-bg').addEventListener('click', () => {
            picker.classList.add('closing');
            picker.addEventListener('animationend', () => {
               if (window.visualViewport) {
                    visualViewport.removeEventListener('resize', layoutPicker);
                    visualViewport.removeEventListener('scroll', layoutPicker);
                }
                picker.remove();
                style.remove();
                window.dispatchEvent(new CustomEvent('edgedl:picker-closed'));
            }, { once: true });
        });
    }

    // 从 onclick 中解析下载 URL
    function extractUrlFromOnclick(onclick) {
        if (!onclick) return null;

        const match = onclick.match(
            /(https?:\/\/[^"'()\s]+)/i
        );

        if (match) {
            return match[1];
        }

        return null;
    }

    let menuRegistered = false;

    function registerMenu() {
        if (menuRegistered) return;
        if (typeof GM_registerMenuCommand !== 'function') return;

        // 更改默认下载器
        GM_registerMenuCommand('更改默认下载器', () => {
            showDownloadPicker('', pkg => {
                GM_setValue('edgedl-default-downloader', pkg);
            }, 'config');
        });

        // 加入或移出黑名单
        GM_registerMenuCommand('加入/移出黑名单(下载器接管)', async () => {
            const added = await toggleCurrentSite();
            alert(
                added
                    ? '当前站点已加入黑名单'
                    : '当前站点已移出黑名单'
            );
        });

        menuRegistered = true;
    }

    registerMenu();

    // 读取默认下载器配置
    function getDefaultDownloader() {
        return GM_getValue('edgedl-default-downloader');
    }

    // 拦截点击事件并接管下载
    document.addEventListener('click', e => {
        if (e.defaultPrevented) return;

        if (e.__edgedl_handled__) return;
        e.__edgedl_handled__ = true;

        const link = e.target?.closest?.('a, [onclick]');
        if (!link) return;

        let url = link.href;

        if (
            !url ||
            url === '#' ||
            url === '##' ||
            url.startsWith('javascript:')
        ) {
            const onclick = link.getAttribute('onclick')
                || link.closest('[onclick]')?.getAttribute('onclick');

            if (onclick) {
                url = extractUrlFromOnclick(onclick);
            }
        }

        if (!url || !isDownloadLink(url)) return;

        // 阻止浏览器原生下载与页面跳转
        e.preventDefault();
        e.stopPropagation();
        e.stopImmediatePropagation();

        const defaultDownloader = getDefaultDownloader();
        if (defaultDownloader) {
            openDownload(url, defaultDownloader);
        } else {
            // 无默认配置时弹出下载器选择
            showDownloadPicker(url, selected => {
                openDownload(url, selected);
            });
        }
    }, true);

})();