Greasy Fork

Greasy Fork is available in English.

全网VIP视频

全网VIP视频免费,智能选择有效解析链接,支持手动切换解析源

// ==UserScript==
// @name              全网VIP视频
// @namespace        
// @version           2025.9.29
// @description       全网VIP视频免费,智能选择有效解析链接,支持手动切换解析源
// @icon              https://nuaa.tech/zz.svg
// @author            https://pro.gleeze.com/article/46
// @include           *://v.qq.com/*
// @include           *://v.qq.com/x/cover/*
// @include           *://v.qq.com/tv/*
// @include           *://*.iqiyi.com/*
// @include           *://*.iqiyi.com/a_*
// @include           *://*.iqiyi.com/w_*
// @include           *://*.iq.com/play/*
// @include           *://*.youku.com/*
// @include           *://*.youku.com/video*
// @include           *://*.youku.com/*?vid=*
// @include           *://*.mgtv.com/b/*
// @include           *://*.tudou.com/*
// @include           *://*.tudou.com/programs/view/*
// @include           *://*.tudou.com/albumplay/*
// @include           *://film.sohu.com/album/*
// @include           *://tv.sohu.com/*
// @include           *://*.bilibili.com/*
// @include           *://*.bilibili.com/bangumi/play/*
// @include           *://v.pptv.com/show/*
// @include           *://vip.pptv.com/show/*
// @include           *://www.wasu.cn/Play/show/*
// @include           *://*.le.com/ptv/vplay/*
// @include           *://*.acfun.cn/v/*
// @include           *://*.acfun.cn/bangumi/*
// @include           *://*.1905.com/play/*
// @include           *://m.v.qq.com/x/page/*
// @include           *://m.v.qq.com/x/cover/*
// @include           *://m.v.qq.com/*
// @include           *://m.iqiyi.com/*
// @include           *://m.iqiyi.com/kszt/*
// @include           *://m.youku.com/video/*
// @include           *://m.mgtv.com/b/*
// @include           *://m.tv.sohu.com/v/*
// @include           *://m.film.sohu.com/album/*
// @include           *://m.pptv.com/show/*
// @include           *://m.bilibili.com/anime/*
// @include           *://m.bilibili.com/video/*
// @include           *://m.bilibili.com/bangumi/play/*
// @connect           api.bilibili.com
// @grant             unsafeWindow
// @grant             GM_addStyle
// @grant             GM_openInTab
// @grant             GM_getValue
// @grant             GM_setValue
// @grant             GM_xmlhttpRequest
// @grant             GM_notification
// @charset		      UTF-8
// @license           GPL License
// ==/UserScript==

const util = (function () {

    function findTargetElement(targetContainer) {
        const body = window.document;
        let tabContainer;
        let tryTime = 0;
        const maxTryTime = 120;
        return new Promise((resolve, reject) => {
            let interval = setInterval(() => {
                tabContainer = body.querySelector(targetContainer);
                if (tabContainer) {
                    clearInterval(interval);
                    resolve(tabContainer);
                }
                if ((++tryTime) === maxTryTime) {
                    clearInterval(interval);
                    reject();
                }
            }, 500);
        });
    }

    function urlChangeReload() {
        const oldHref = window.location.href;
        let interval = setInterval(() => {
            let newHref = window.location.href;
            if (oldHref !== newHref) {
                clearInterval(interval);
                window.location.reload();
            }
        }, 500);
    }

    function reomveVideo() {
        setInterval(() => {
            for (let video of document.getElementsByTagName("video")) {
                if (video.src) {
                    video.removeAttribute("src");
                    video.muted = true;
                    video.load();
                    video.pause();
                }
            }
        }, 500);
    }

    function syncRequest(option) {
        return new Promise((resolve, reject) => {
            option.onload = (res) => {
                resolve(res);
            };
            option.onerror = (err) => {
                reject(err);
            };
            GM_xmlhttpRequest(option);
        });
    }

    return {
        req: (option) => syncRequest(option),
        findTargetEle: (targetEle) => findTargetElement(targetEle),
        urlChangeReload: () => urlChangeReload(),
        reomveVideo: () => reomveVideo()
    }
})();


const superVip = (function () {

    const _CONFIG_ = {
        isMobile: navigator.userAgent.match(/(Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini)/i),
        currentPlayerNode: null,
        statusBoxId: 'vip_status_box' + Math.ceil(Math.random() * 100000000),
        switchBtnId: 'vip_switch_btn' + Math.ceil(Math.random() * 100000000),
        flag: "flag_vip",
        autoPlayerKey: "auto_player_key" + window.location.host,
        autoPlayerVal: "auto_player_value_" + window.location.host,
        currentParseIndex: "current_parse_index_" + window.location.host,
        successCountKey: "success_count_key_" + window.location.host,
        videoParseList: [
         {"name": "优质A", "type": "1,3", "url": "https://www.ckplayer.vip/jiexi/?url="},
         {"name": "通用无广", "type": "1,3", "url": "https://jx.nnxv.cn/tv.php?url="},
          {"name": "特供解析B", "type": "1,3", "url": "https://jx.77flv.cc/?url="},
            {"name": "特供解析A", "type": "1,3", "url": "https://jx.xmflv.com/?url="},
            {"name": "新1解析", "type": "1,3", "url": "https://jx.m3u8.tv/jiexi/?url="},
            {"name": "极速解析", "type": "1,3", "url": "https://jx.2s0.cn/player/?url="},
            {"name": "冰豆解析", "type": "1,3", "url": "https://bd.jx.cn/?url="},
            {"name": "973解析", "type": "1,3", "url": "https://jx.973973.xyz/?url="},
            {"name": "虾米视频解析", "type": "1,3", "url": "https://jx.xmflv.com/?url="},
            {"name": "CK", "type": "1,3", "url": "https://www.ckplayer.vip/jiexi/?url="},
            {"name": "七哥解析", "type": "1,3", "url": "https://jx.nnxv.cn/tv.php?url="},
            {"name": "夜幕", "type": "1,3", "url": "https://www.yemu.xyz/?url="},
            {"name": "盘古", "type": "1,3", "url": "https://www.pangujiexi.com/jiexi/?url="},
            {"name": "playm3u8", "type": "1,3", "url": "https://www.playm3u8.cn/jiexi.php?url="},
            {"name": "七七云解析", "type": "1,3", "url": "https://jx.77flv.cc/?url="},
            {"name": "芒果TV1", "type": "1,3", "url": "https://video.isyour.love/player/getplayer?url="},
            {"name": "芒果TV2", "type": "1,3","url":"https://im1907.top/?jx="},
            {"name": "HLS解析", "type": "1,3", "url": "https://jx.hls.one/?url="},
        ],
        playerContainers: [
            {
                host: "v.qq.com",
                container: "#mod_player,#player-container,.container-player",
                name: "Default",
                displayNodes: ["#mask_layer", ".mod_vip_popup", "#mask_layer", ".panel-tip-pay"]
            },
            {
                host: "m.v.qq.com",
                container: ".mod_player,#player",
                name: "Default",
                displayNodes: [".mod_vip_popup", "[class^=app_],[class^=app-],[class*=_app_],[class*=-app-],[class$=_app],[class$=-app]", "div[dt-eid=open_app_bottom]", "div.video_function.video_function_new", "a[open-app]", "section.mod_source", "section.mod_box.mod_sideslip_h.mod_multi_figures_h,section.mod_sideslip_privileges,section.mod_game_rec"]
            },

            {host: "w.mgtv.com", container: "#mgtv-player-wrap", name: "Default", displayNodes: []},
            {host: "www.mgtv.com", container: "#mgtv-player-wrap", name: "Default", displayNodes: []},
            {
                host: "m.mgtv.com",
                container: ".video-area",
                name: "Default",
                displayNodes: ["div.adFixedContain,div.ad-banner,div.m-list-graphicxcy.fstp-mark", "div[class^=mg-app],div#comment-id.video-comment div.ft,div.bd.clearfix,div.v-follower-info", "div.ht.mgui-btn.mgui-btn-nowelt", "div.personal", "div[data-v-41c9a64e]"]
            },
            {host: "www.bilibili.com", container: "#player_module,#bilibiliPlayer,#bilibili-player", name: "Default", displayNodes: []},
            {host: "m.bilibili.com", container: ".player-wrapper,.player-container,.mplayer", name: "Default", displayNodes: []},
            {host: "www.iqiyi.com", container: "#outlayer, .iqp-player-videolayer", name: "Default", displayNodes: ["#playerPopup", "#vipCoversBox" ,"div.iqp-player-vipmask", "div.iqp-player-paymask","div.iqp-player-loginmask", "div[class^=qy-header-login-pop]",".covers_cloudCover__ILy8R","#videoContent > div.loading_loading__vzq4j",".iqp-player-guide"]},
            {
                host: "m.iqiyi.com",
                container: ".m-video-player-wrap, .iqp-player-videolayer",
                name: "Default",
                displayNodes: ["div.m-iqyGuide-layer", "a[down-app-android-url]", "div.iqp-player-vipmask", ".loading_loading__vzq4j","[name=m-extendBar]", "[class*=ChannelHomeBanner]", "section.m-hotWords-bottom"]
            },
            {host: "www.iq.com", container: ".intl-video-wrap", name: "Default", displayNodes: []},
            {host: "v.youku.com", container: "#playerMouseWheel", name: "Default", displayNodes: ["#iframaWrapper"]},
            {host: "m.youku.com", container: "#playerMouseWheel,.h5-detail-player", name: "Default", displayNodes: []},
            {host: "tv.sohu.com", container: "#player", name: "Default", displayNodes: []},
            {host: "film.sohu.com", container: "#playerWrap", name: "Default", displayNodes: []},
            {host: "www.le.com", container: "#le_playbox", name: "Default", displayNodes: []},
            {host: "video.tudou.com", container: ".td-playbox", name: "Default", displayNodes: []},
            {host: "v.pptv.com", container: "#pptv_playpage_box", name: "Default", displayNodes: []},
            {host: "vip.pptv.com", container: ".w-video", name: "Default", displayNodes: []},
            {host: "www.wasu.cn", container: "#flashContent", name: "Default", displayNodes: []},
            {host: "www.acfun.cn", container: "#player", name: "Default", displayNodes: []},
            {host: "vip.1905.com", container: "#player,#vodPlayer", name: "Default", displayNodes: []},
            {host: "www.1905.com", container: "#player,#vodPlayer", name: "Default", displayNodes: []},
        ]
    };

    class BaseConsumer {
        constructor() {
            this.currentTryIndex = -1;
            this.autoTryTimer = null;
            this.successCounts = GM_getValue(_CONFIG_.successCountKey, {});
            this.parse = () => {
                util.findTargetEle('body')
                    .then((container) => this.preHandle(container))
                    .then((container) => this.generateStatusBox(container))
                    .then((container) => this.autoPlay(container))
                    .then((container) => this.postHandle(container));
            }
        }

        preHandle(container) {
            _CONFIG_.currentPlayerNode.displayNodes.forEach((item, index) => {
                util.findTargetEle(item)
                    .then((obj) => obj.style.display = 'none')
                    .catch(e => console.warn("不存在元素", e));
            });
            return new Promise((resolve, reject) => resolve(container));
        }

        generateStatusBox(container) {
            GM_addStyle(`
                #${_CONFIG_.statusBoxId} {
                    position: fixed;
                    top: 10px;
                    right: 10px;
                    z-index: 9999999;
                    background: rgba(0,0,0,0.7);
                    color: white;
                    padding: 8px 12px;
                    border-radius: 4px;
                    font-size: 12px;
                    display: flex;
                    align-items: center;
                    box-shadow: 0 2px 10px rgba(0,0,0,0.3);
                }
                #${_CONFIG_.statusBoxId} .status-indicator {
                    width: 8px;
                    height: 8px;
                    border-radius: 50%;
                    display: inline-block;
                    margin-right: 6px;
                }
                #${_CONFIG_.statusBoxId} .status-working {
                    background-color: #4CAF50;
                }
                #${_CONFIG_.statusBoxId} .status-error {
                    background-color: #F44336;
                }
                #${_CONFIG_.statusBoxId} .status-idle {
                    background-color: #FFC107;
                }
                #${_CONFIG_.statusBoxId} .loading-spinner {
                    width: 16px;
                    height: 16px;
                    border: 2px solid #f3f3f3;
                    border-top: 2px solid #3498db;
                    border-radius: 50%;
                    animation: spin 1s linear infinite;
                    margin-right: 6px;
                }
                
                #${_CONFIG_.switchBtnId} {
                    position: fixed;
                    top: 60px;
                    right: 10px;
                    z-index: 9999999;
                    width: 40px;
                    height: 40px;
                    border-radius: 50%;
                    background: #3498db;
                    color: white;
                    display: flex;
                    justify-content: center;
                    align-items: center;
                    cursor: pointer;
                    box-shadow: 0 2px 10px rgba(0,0,0,0.3);
                    transition: all 0.3s ease;
                    border: none;
                    outline: none;
                }
                
                #${_CONFIG_.switchBtnId}:hover {
                    transform: scale(1.1);
                    background: #2980b9;
                }
                
                #${_CONFIG_.switchBtnId}.success {
                    background: #2ecc71;
                }
                
                #${_CONFIG_.switchBtnId}.error {
                    background: #e74c3c;
                }
                
                #${_CONFIG_.switchBtnId}.loading {
                    background: #3498db;
                    animation: pulse 1.5s infinite;
                }
                
                #${_CONFIG_.switchBtnId} svg {
                    width: 24px;
                    height: 24px;
                    fill: white;
                }
                
                @keyframes pulse {
                    0% { transform: scale(1); }
                    50% { transform: scale(1.1); }
                    100% { transform: scale(1); }
                }
                
                @keyframes spin {
                    0% { transform: rotate(0deg); }
                    100% { transform: rotate(360deg); }
                }
            `);

            $(container).append(`
                <div id="${_CONFIG_.statusBoxId}">
                    <div class="loading-spinner"></div>
                    <span id="status-text">正在初始化解析器...</span>
                </div>
            `);
            
            // 添加切换按钮
            $(container).append(`
                <button id="${_CONFIG_.switchBtnId}" class="loading" title="切换解析源">
                    <svg viewBox="0 0 24 24">
                        <path d="M17.65,6.35C16.2,4.9,14.21,4,12,4c-4.42,0-7.99,3.58-7.99,8s3.57,8,7.99,8c3.73,0,6.84-2.55,7.73-6h-2.08 c-0.82,2.33-3.04,4-5.65,4c-3.31,0-6-2.69-6-6s2.69-6,6-6c1.66,0,3.14,0.69,4.22,1.78L13,11h7V4L17.65,6.35z"/>
                    </svg>
                </button>
            `);
            
            // 绑定按钮点击事件
            $(`#${_CONFIG_.switchBtnId}`).on('click', () => {
                this.switchToNextParser();
            });
            
            return new Promise((resolve, reject) => resolve(container));
        }

        updateStatus(text, statusClass) {
            const statusBox = $(`#${_CONFIG_.statusBoxId}`);
            if (statusBox.length) {
                statusBox.find("#status-text").text(text);
                if (statusClass) {
                    statusBox.find(".loading-spinner").remove();
                    statusBox.prepend(`<span class="status-indicator ${statusClass}"></span>`);
                }
            }
        }

        updateSwitchButton(status) {
            const btn = $(`#${_CONFIG_.switchBtnId}`);
            btn.removeClass("loading success error");
            btn.addClass(status);
        }

        autoPlay(container) {
            this.selectPlayer();
            return new Promise((resolve, reject) => resolve(container));
        }

        selectPlayer() {
            // 获取成功率最高的解析源
            let bestIndex = 0;
            let bestSuccessRate = -1;
            
            for (let i = 0; i < _CONFIG_.videoParseList.length; i++) {
                const successCount = this.successCounts[i] || 0;
                const successRate = successCount > 0 ? successCount / (successCount + 1) : 0;
                
                if (successRate > bestSuccessRate) {
                    bestSuccessRate = successRate;
                    bestIndex = i;
                }
            }
            
            let autoObj = _CONFIG_.videoParseList[bestIndex];
            let _th = this;
            if (autoObj.type.includes("1")) {
                setTimeout(function () {
                    _th.showPlayerWindow(autoObj, bestIndex);
                }, 1000);
            }
        }

        showPlayerWindow(videoObj, index) {
            this.currentTryIndex = index;
            this.updateStatus(`正在尝试: ${videoObj.name}`, "status-working");
            this.updateSwitchButton("loading");
            
            util.findTargetEle(_CONFIG_.currentPlayerNode.container)
                .then((container) => {
                    const type = videoObj.type;
                    let url = videoObj.url + window.location.href;
                    if (type.includes("1")) {
                        $(container).empty();
                        util.reomveVideo();
                        let iframeDivCss = "width:100%;height:100%;z-index:999999;position:relative;";
                        if (_CONFIG_.isMobile) {
                            iframeDivCss = "width:100%;height:450px;z-index:999999;position:relative;";
                        }
                        if (_CONFIG_.isMobile && window.location.href.indexOf("iqiyi.com") !== -1) {
                            iframeDivCss = "width:100%;height:450px;z-index:999999;margin-top:-56.25%;position:relative;";
                        }
                        
                        // 添加加载动画
                        $(container).append(`
                            <div style="${iframeDivCss}">
                                <div class="loading-container" style="position:absolute;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.7);z-index:99999999;display:flex;justify-content:center;align-items:center;flex-direction:column;">
                                    <div class="loading-spinner" style="width:40px;height:40px;border:4px solid #f3f3f3;border-top:4px solid #3498db;border-radius:50%;animation:spin 1s linear infinite;"></div>
                                    <div style="color:white;margin-top:10px;">正在尝试解析: ${videoObj.name}</div>
                                </div>
                                <iframe id="iframe-player-4a5b6c" src="${url}" style="border:none;width:100%;height:100%;" allowfullscreen="true"></iframe>
                            </div>
                        `);
                        
                        const iframe = $(container).find("#iframe-player-4a5b6c")[0];
                        const loadingContainer = $(container).find(".loading-container");
                        
                        // 设置超时检测
                        const timeout = setTimeout(() => {
                            loadingContainer.hide();
                            this.handleParseFailure(index, container);
                        }, 10000);
                        
                        // 监听iframe加载完成
                        iframe.onload = () => {
                            clearTimeout(timeout);
                            loadingContainer.hide();
                            
                            // 记录解析成功
                            this.recordParseSuccess(index);
                            
                            // 更新状态
                            this.updateStatus(`解析成功: ${videoObj.name}`, "status-working");
                            this.updateSwitchButton("success");
                        };
                    }
                });
        }
        
        handleParseFailure(currentIndex, container) {
            // 记录解析失败
            this.recordParseFailure(currentIndex);
            
            // 查找下一个可用的解析源
            let nextIndex = -1;
            for (let i = 0; i < _CONFIG_.videoParseList.length; i++) {
                const idx = (currentIndex + i + 1) % _CONFIG_.videoParseList.length;
                if (_CONFIG_.videoParseList[idx].type.includes("1")) {
                    nextIndex = idx;
                    break;
                }
            }
            
            if (nextIndex !== -1) {
                // 显示下一个解析源
                const nextObj = _CONFIG_.videoParseList[nextIndex];
                this.showPlayerWindow(nextObj, nextIndex);
                
                // 更新状态
                this.updateStatus(`解析失败,尝试: ${nextObj.name}`, "status-error");
                this.updateSwitchButton("error");
                
                // 显示错误通知
                GM_notification({
                    text: `解析失败,正在尝试: ${nextObj.name}`,
                    title: "VIP解析",
                    timeout: 3000
                });
            } else {
                // 没有可用的解析源
                this.updateStatus("所有解析源尝试失败", "status-error");
                this.updateSwitchButton("error");
                GM_notification({
                    text: "所有解析源尝试失败,请刷新页面重试",
                    title: "VIP解析",
                    timeout: 5000
                });
            }
        }
        
        recordParseSuccess(index) {
            // 更新成功率统计
            this.successCounts[index] = (this.successCounts[index] || 0) + 1;
            GM_setValue(_CONFIG_.successCountKey, this.successCounts);
        }
        
        recordParseFailure(index) {
            // 更新成功率统计
            this.successCounts[index] = this.successCounts[index] || 0;
            GM_setValue(_CONFIG_.successCountKey, this.successCounts);
        }
        
        switchToNextParser() {
            if (this.currentTryIndex === -1) return;
            
            // 查找下一个可用的解析源
            let nextIndex = -1;
            for (let i = 0; i < _CONFIG_.videoParseList.length; i++) {
                const idx = (this.currentTryIndex + i + 1) % _CONFIG_.videoParseList.length;
                if (_CONFIG_.videoParseList[idx].type.includes("1")) {
                    nextIndex = idx;
                    break;
                }
            }
            
            if (nextIndex !== -1) {
                // 显示下一个解析源
                const nextObj = _CONFIG_.videoParseList[nextIndex];
                this.showPlayerWindow(nextObj, nextIndex);
                
                // 更新状态
                this.updateStatus(`手动切换至: ${nextObj.name}`, "status-working");
                this.updateSwitchButton("loading");
                
                // 显示通知
                GM_notification({
                    text: `已切换到: ${nextObj.name}`,
                    title: "VIP解析",
                    timeout: 2000
                });
            }
        }

        postHandle(container) {
            util.urlChangeReload();
        }

    }

    class DefaultConsumer extends BaseConsumer {
    }

    return {
        start: () => {
            GM_setValue(_CONFIG_.flag, null);
            let mallCase = 'Default';
            let playerNode = _CONFIG_.playerContainers.filter(value => value.host === window.location.host);
            if (playerNode === null || playerNode.length <= 0) {
                console.warn(window.location.host + "该网站暂不支持,请联系作者,作者将会第一时间处理(注意:请记得提供有问题的网址)");
                return;
            }
            _CONFIG_.currentPlayerNode = playerNode[0];
            mallCase = _CONFIG_.currentPlayerNode.name;
            const targetConsumer = eval(`new ${mallCase}Consumer`);
            targetConsumer.parse();
        }
    }

})();

(function () {
    superVip.start();
})();