Greasy Fork

Greasy Fork is available in English.

🌀VIP视频解析——fatcat

适配手机端与电脑端

当前为 2024-06-09 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name        🌀VIP视频解析——fatcat
// @namespace   [fatcat]
// @version     2.0
// @description 适配手机端与电脑端
// @author      暴走的肥猫
// @license     MIT, Sign after modification
// @include     /^http[^http]*youku\.com\/.+$/
// @include     /^http[^http]*iqiyi\.com\/.+$/
// @include     /^http[^http]*v\.qq\.com\/.+$/
// @include     /^http[^http]*le\.com\/.+$/
// @include     /^http[^http]*mgtv\.com\/.+$/
// @include     /^http[^http]*tv\.sohu\.com\/.+$/
// @compatible  safari
// @compatible  chrome
// @compatible  edge
// @grant       GM_getValue
// @grant       GM_setValue
// @grant       GM.getValue
// @grant       GM.setValue
// @run-at      document-idle
// @noframes
// ==/UserScript==
/*jshint esversion: 11 */
(async function () {
    const ACCESS_POINT = [
        { "name": "夜幕", "url": "https://www.yemu.xyz/?url=" },
        { "name": "综合", "url": "https://jx.jsonplayer.com/player/?url=" },
        { "name": "CK", "url": "https://www.ckplayer.vip/jiexi/?url=" },
        { "name": "YT", "url": "https://jx.yangtu.top/?url=" },
        { "name": "Player-JY", "url": "https://jx.playerjy.com/?url=" },
        { "name": "yparse", "url": "https://jx.yparse.com/index.php?url=" },
        { "name": "8090", "url": "https://www.8090g.cn/?url=" },
        { "name": "剖元", "url": "https://www.pouyun.com/?url=" },
        { "name": "虾米", "url": "https://jx.xmflv.com/?url=" },
        { "name": "全民", "url": "https://43.240.74.102:4433?url=" },
        { "name": "爱豆", "url": "https://jx.aidouer.net/?url=" },
        { "name": "m1907", "url": "https://im1907.top/?jx=" },
        { "name": "M3U8TV", "url": "https://jx.m3u8.tv/jiexi/?url=" },
        { "name": "冰豆", "url": "https://bd.jx.cn/?url=" },
        { "name": "playm3u8", "url": "https://www.playm3u8.cn/jiexi.php?url=" },
    ];
    async function getUserConfig(key, defaultVal) {
        return GM_getValue ? GM_getValue(key, defaultVal) : GM.getValue(key, defaultVal);
    }
    async function setUserConfig(key, val) {
        return GM_setValue ? GM_setValue(key, val) : GM.setValue(key, val);
    }
    async function pauseAllVideos() {
        let i = 0;
        let interval = setInterval(function () {
            i++;
            if (i > 1200) clearInterval(interval);
            document.querySelectorAll('video').forEach(video => { video.pause(); video.style.visibility = 'hidden'; });
        }, 100);
    }
    function seekSameSizeParentNode(node) {
        let parentSize = node.parentElement.getBoundingClientRect();
        let nodeSize = node.getBoundingClientRect();
        if (parentSize.width - nodeSize.width < 1 && parentSize.height - nodeSize.height < 1) return seekSameSizeParentNode(node.parentElement);
        return node
    }
    function useInterval(fn, intervalTime, maxTime) {
        return new Promise((resolve) => {
            let totalTime = 0;
            let interval = setInterval(() => {
                totalTime += intervalTime;
                if (totalTime >= maxTime || fn()) { clearInterval(interval); resolve(); }
            }, intervalTime)
        })
    }
    async function findVideoWrapper() {
        await useInterval(() => Array.from(document.querySelectorAll('video')).find(videoNode => {
            videoNode.style.display = 'revert';
            return videoNode.getBoundingClientRect().width > 100 && videoNode.getBoundingClientRect().height > 100
        }), 200, Infinity);
        let videoNodes = Array.from(document.querySelectorAll('video'));
        return videoNodes.map(videoNode => seekSameSizeParentNode(videoNode)).reduce((pre, cur) => {
            let preW = pre?.getBoundingClientRect().width || 0;
            let curW = cur.getBoundingClientRect().width;
            if (curW > preW) return cur;
            return pre;
        })
    }
    async function createVideoFrame(videoWrapper, lastAccessPoint) {
        videoWrapper.style.overflow = 'hidden';
        let iframeWrapper = document.createElement('div');
        iframeWrapper.innerHTML = `<iframe src="${lastAccessPoint.url}${window.location.href}" width="100%" height="100%" allowfullscreen id="fatcat_video_vip_iframe" style="border:none;"/>`;
        iframeWrapper.style = `position:absolute; inset:0; z-index: 99999999;`
        videoWrapper.appendChild(iframeWrapper);
        return;
    }
    async function createMenu(accessPoints, lastAccessPoint) {
        if (document.querySelector('#fatcat_video_vip')) return;
        let wrapper = document.createElement('div');
        wrapper.innerHTML = `
            <div id="fatcat_video_vip">
    <style>
        #fatcat_video_vip {
            position: fixed;
            bottom: 0;
            right: 0;
            z-index: 99999998;
            font-size: 17px;
        }
        #fatcat_video_vip_link button{
            cursor: pointer;
            border-radius: 12px 0 0 0;
            padding: 20px;
            font-weight: bolder;
            background: linear-gradient(to top right, rgba(129, 215, 14, 1) 0%, rgba(46, 159, 248, 1) 100%);
            color: white;
        }
    </style>
    <select id="fatcat_video_vip_select">
        ${accessPoints.map(({ name, url }) => `<option value="${url}" ${name == lastAccessPoint.name ? 'selected' : ''}>${name}</option>`).join()}
    </select>
    <a href="${lastAccessPoint.url}${window.location.href}" target="_blank" id="fatcat_video_vip_link"><button>外部播放</button></a>
</div>
        `;
        let selects = wrapper.querySelector('#fatcat_video_vip_select');
        let aTag = wrapper.querySelector('#fatcat_video_vip_link');
        function updateLink() {
            let val = selects.value;
            aTag.href = val + window.location.href;
            let iframe = document.querySelector('#fatcat_video_vip_iframe');
            if (iframe.src != (val + window.location.href)) {
                iframe.src = val + window.location.href;
                setUserConfig('lastAccessPoint', accessPoints.find(({ url }) => url == val));
                return true;
            }
        }
        window.addEventListener('mousedown', (e) => {
            if (!(e.target.matches("#fatcat_video_vip *") || e.target.matches("#fatcat_video_vip_iframe"))) {
                useInterval(updateLink, 100, 10000);
            }
        });
        selects.onchange = updateLink;
        document.body.appendChild(wrapper);
    }
    async function inject() {
        let accessPoints = await getUserConfig('accessPoints');
        if (!accessPoints) { setUserConfig('accessPoints', ACCESS_POINT); accessPoints = ACCESS_POINT; }
        let lastAccessPoint = await getUserConfig('lastAccessPoint');
        if (!lastAccessPoint) { setUserConfig('lastAccessPoint', ACCESS_POINT[0]); lastAccessPoint = ACCESS_POINT[0]; }
        let videoWrapper = await findVideoWrapper();
        await new Promise(resolve => { document.readyState == 'complete' ? resolve() : window.addEventListener('load', resolve) });
        pauseAllVideos();
        createVideoFrame(videoWrapper, lastAccessPoint);
        createMenu(accessPoints, lastAccessPoint);
    }
    inject();
})();