SnapAny 全能媒体下载器 (Zero V4.6 逻辑修复版)

【核心逻辑修复】重构内容判定流程,优先检测视频链接,彻底解决视频被误判为图集的致命BUG。

当前为 2025-07-11 提交的版本,查看 最新版本

// ==UserScript==
// @name         SnapAny 全能媒体下载器 (Zero V4.6 逻辑修复版)
// @namespace    http://tampermonkey.net/
// @version      4.6
// @description  【核心逻辑修复】重构内容判定流程,优先检测视频链接,彻底解决视频被误判为图集的致命BUG。
// @author       Zero (全域系统工程师AI)
// @match        https://snapany.com/zh*
// @icon         https://snapany.com/favicon.ico
// @grant        GM_download
// @grant        GM_addStyle
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // =================================================================================
    // 零号AI核心:配置与常量 (与V4.5一致)
    // =================================================================================
    const 选择器_结果容器 = 'div.flex.h-full.flex-col.justify-center.gap-4.p-6';
    const 选择器_作品文案 = '.text-center.text-sm.font-medium';
    const 选择器_媒体链接 = 'a[download]';
    const 注入面板ID = 'zero-downloader-panel';
    const 图片域名特征 = 'douyinpic.com';

    // =================================================================================
    // 零号AI核心:注入自定义样式 (与V4.5一致)
    // =================================================================================
    GM_addStyle(`
        #${注入面板ID} { border: 2px dashed #007bff; border-radius: 8px; padding: 15px; margin-top: 20px; background-color: #f8f9fa; }
        #${注入面板ID} h3 { margin-top: 0; margin-bottom: 15px; text-align: center; color: #333; font-weight: bold; }
        .zero-控制区 { display: flex; justify-content: space-between; align-items: center; padding: 15px 0; border-top: 1px solid #dee2e6; margin-top: 15px; }
        .zero-下载按钮 { background-color: #28a745; color: white; padding: 10px 20px; border: none; border-radius: 5px; cursor: pointer; font-size: 16px; font-weight: bold; transition: background-color 0.3s; }
        .zero-下载按钮:disabled { background-color: #cccccc; cursor: not-allowed; }
        .zero-全选标签 { font-size: 16px; cursor: pointer; display: flex; align-items: center; }
        .zero-全选复选框 { margin-right: 8px; width: 18px; height: 18px; cursor: pointer; }
        .zero-预览区 { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 10px; }
        .zero-媒体项 { position: relative; border: 1px solid #ddd; border-radius: 4px; overflow: hidden; background-color: #000; }
        .zero-媒体项 img, .zero-媒体项 video { width: 100%; height: 100%; object-fit: cover; display: block; }
        .zero-媒体复选框 { position: absolute; top: 8px; right: 8px; width: 22px; height: 22px; cursor: pointer; z-index: 10; background-color: rgba(255, 255, 255, 0.7); border: 1px solid #999; border-radius: 3px; }
        .zero-新标签链接 { position: absolute; top: 8px; left: 8px; width: 22px; height: 22px; z-index: 10; background-color: rgba(255, 255, 255, 0.7); border-radius: 3px; display: flex; align-items: center; justify-content: center; color: #333; font-size: 16px; text-decoration: none; border: 1px solid #999; }
        .zero-新标签链接:hover { background-color: rgba(255, 255, 255, 1); border-color: #000; }
    `);

    // =================================================================================
    // 零号AI核心:通用媒体面板构建器 (与V4.5一致)
    // =================================================================================
    function 构建通用媒体面板(锚点元素, 媒体对象列表) {
        // 此函数为纯UI构建器,不受逻辑变化影响,无需修改
        if (!媒体对象列表 || 媒体对象列表.length === 0) return;
        const 总面板 = document.createElement('div');
        总面板.id = 注入面板ID;
        总面板.innerHTML = `<h3>零号AI · 全能媒体下载器</h3>`;
        const 预览区 = document.createElement('div');
        预览区.className = 'zero-预览区';
        总面板.appendChild(预览区);
        媒体对象列表.forEach(媒体 => {
            const 媒体项 = document.createElement('div');
            媒体项.className = 'zero-媒体项';
            if (媒体.type === 'video') {
                const 视频元素 = document.createElement('video');
                视频元素.src = 媒体.downloadUrl;
                视频元素.poster = 媒体.previewUrl;
                视频元素.preload = 'metadata';
                视频元素.controls = true;
                媒体项.appendChild(视频元素);
                const 新标签链接 = document.createElement('a');
                新标签链接.className = 'zero-新标签链接';
                新标签链接.href = 媒体.downloadUrl;
                新标签链接.target = '_blank';
                新标签链接.title = '在新标签页中打开视频';
                新标签链接.innerHTML = '<svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><line x1="10" y1="14" x2="21" y2="3"></line></svg>';
                媒体项.appendChild(新标签链接);
                视频元素.addEventListener('dblclick', () => { window.open(媒体.downloadUrl, '_blank'); });
            } else {
                const 图片元素 = document.createElement('img');
                图片元素.src = 媒体.previewUrl;
                媒体项.appendChild(图片元素);
            }
            const 复选框 = document.createElement('input');
            复选框.type = 'checkbox';
            复选框.className = 'zero-媒体复选框';
            复选框.checked = true;
            复选框.dataset.downloadUrl = 媒体.downloadUrl;
            复选框.dataset.filename = 媒体.filename;
            媒体项.appendChild(复选框);
            预览区.appendChild(媒体项);
        });
        const 控制区 = document.createElement('div');
        控制区.className = 'zero-控制区';
        const 全选标签 = document.createElement('label');
        全选标签.className = 'zero-全选标签';
        const 全选复选框 = document.createElement('input');
        全选复选框.type = 'checkbox';
        全选复选框.checked = true;
        全选标签.appendChild(全选复选框);
        全选标签.append(` 全选/反选 (${媒体对象列表.length})`);
        const 下载按钮 = document.createElement('button');
        下载按钮.className = 'zero-下载按钮';
        控制区.appendChild(全选标签);
        控制区.appendChild(下载按钮);
        总面板.appendChild(控制区);
        锚点元素.parentNode.insertBefore(总面板, 锚点元素);
        const 更新下载按钮状态 = () => {
            const 选中复选框列表 = 预览区.querySelectorAll('.zero-媒体复选框:checked');
            const 选中数量 = 选中复选框列表.length;
            下载按钮.textContent = `下载选中 (${选中数量})`;
            下载按钮.disabled = 选中数量 === 0;
            全选复选框.checked = 选中数量 > 0 && 选中数量 === 媒体对象列表.length;
            全选复选框.indeterminate = 选中数量 > 0 && 选中数量 < 媒体对象列表.length;
        };
        全选复选框.addEventListener('change', () => {
            预览区.querySelectorAll('.zero-媒体复选框').forEach(cb => { cb.checked = 全选复选框.checked; });
            更新下载按钮状态();
        });
        预览区.querySelectorAll('.zero-媒体复选框').forEach(cb => cb.addEventListener('change', 更新下载按钮状态));
        下载按钮.addEventListener('click', () => {
            const 选中列表 = 预览区.querySelectorAll('.zero-媒体复选框:checked');
            选中列表.forEach((cb, i) => {
                setTimeout(() => { GM_download({ url: cb.dataset.downloadUrl, name: cb.dataset.filename }); }, i * 200);
            });
            下载按钮.textContent = '下载任务已启动...';
            下载按钮.disabled = true;
            setTimeout(更新下载按钮状态, 3000);
        });
        更新下载按钮状态();
    }

    // =================================================================================
    // 零号AI核心:内容解析与分发器 (V4.6 核心逻辑修复)
    // =================================================================================
    function 处理解析结果(结果容器) {
        if (document.getElementById(注入面板ID)) return;
        const 媒体链接元素列表 = Array.from(结果容器.querySelectorAll(选择器_媒体链接));
        if (媒体链接元素列表.length === 0) return;
        const 文案元素 = 结果容器.querySelector(选择器_作品文案);
        const 基础文件名 = 文案元素 ? 文案元素.textContent.trim().replace(/[\\?%*:|"<>]/g, '_') : 'SnapAny下载';
        let 媒体对象列表 = [];

        // [V4.6 修复] 重构决策逻辑:优先寻找视频
        const 主媒体链接元素 = 媒体链接元素列表.find(el => !el.href.includes(图片域名特征) || el.download.match(/\.(mp4|mov|webm|mp3|m4a)$/i));

        if (主媒体链接元素) {
            // 判定为视频类型
            const 封面图链接元素 = 媒体链接元素列表.find(el => el !== 主媒体链接元素 && (el.href.includes(图片域名特征) || el.download.match(/\.(jpg|jpeg|png|webp)$/i)));
            const 原始文件名 = 主媒体链接元素.download || 'media.file';
            const 文件扩展名 = 原始文件名.includes('.') ? 原始文件名.substring(原始文件名.lastIndexOf('.')) : '.mp4';

            媒体对象列表.push({
                type: 'video',
                previewUrl: 封面图链接元素 ? 封面图链接元素.href : '',
                downloadUrl: 主媒体链接元素.href,
                filename: `${基础文件名}${文件扩展名}`
            });
        } else {
            // 没有找到视频,判定为图集类型
            const 图片URL集合 = new Set(媒体链接元素列表.map(el => el.href));
            let 索引 = 0;
            图片URL集合.forEach(url => {
                媒体对象列表.push({
                    type: 'image',
                    previewUrl: url,
                    downloadUrl: url,
                    filename: `${基础文件名}_${String(++索引).padStart(2, '0')}.jpg`
                });
            });
        }

        结果容器.style.display = 'none';
        构建通用媒体面板(结果容器, 媒体对象列表);
    }

    // =================================================================================
    // 零号AI核心:启动入口与DOM监视 (与V4.5一致)
    // =================================================================================
    console.log('[零号AI] SnapAny全能媒体下载器 V4.6 (逻辑修复版) 已启动...');
    const 观察器 = new MutationObserver((mutationsList) => {
        for (const mutation of mutationsList) {
            if (mutation.type === 'childList') {
                const 结果容器 = document.querySelector(选择器_结果容器);
                if (结果容器 && !document.getElementById(注入面板ID) && window.getComputedStyle(结果容器).display !== 'none') {
                    处理解析结果(结果容器);
                }
            }
        }
    });
    观察器.observe(document.body, { childList: true, subtree: true });

})();

QingJ © 2025

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