Greasy Fork

Greasy Fork is available in English.

🌀VIP视频解析——fatcat

适配手机端与电脑端

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

// ==UserScript==
// @name        🌀VIP视频解析——fatcat
// @namespace   [fatcat]
// @version     2.1
// @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 typeof GM_getValue === 'function' ? GM_getValue(key, defaultVal) : GM.getValue(key, defaultVal);
    }
    async function setUserConfig(key, val) {
        return typeof GM_setValue === 'function' ? 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.opacity = 0; video.style.pointerEvents = 'none'; });
        }, 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();
})();