淘呀号解析自营

(注:一同看官网能打开了就不需要用这个了,可能体验没一同看原生好,并且有时候会无法使用)该版本为“淘呀号”自营解析插件的主版本,适用于安卓和电脑设备,该插件将不再依赖于一同看网站(一同看官网打不开的用户可以使用该插件),直接访问http://gv.gv1069.vip即可观看。

// ==UserScript==
// @name         淘呀号解析自营
// @namespace    http://gv1069.vip/
// @version      1.1
// @description  (注:一同看官网能打开了就不需要用这个了,可能体验没一同看原生好,并且有时候会无法使用)该版本为“淘呀号”自营解析插件的主版本,适用于安卓和电脑设备,该插件将不再依赖于一同看网站(一同看官网打不开的用户可以使用该插件),直接访问http://gv.gv1069.vip即可观看。
// @author       淘呀号团队
// @grant        GM.xmlHttpRequest
// @grant        GM.addStyle
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        unsafeWindow
// @grant        GM_xmlhttpRequest
// @grant        GM_setClipboard
// @grant        GM_deleteValue
// @grant        GM_openInTab
// @grant        GM_registerMenuCommand
// @grant        GM_unregisterMenuCommand
// @grant        GM.getValue
// @grant        GM.setValue
// @grant        GM_info
// @grant        GM_notification
// @grant        GM_getResourceText
// @grant        GM_openInTab
// @grant        GM_addStyle
// @grant        GM_download
// @connect      api.gv1069.vip
// @match        *://*/*
// @require      https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/toastr.js/2.1.4/toastr.min.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/jquery.qrcode/1.0/jquery.qrcode.min.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/sweetalert/2.1.2/sweetalert.min.js
// @require      https://greasyfork.org/scripts/469053-jsqr/code/jsQR.js?version=1207999
 
// @require      https://lib.baomitu.com/m3u8-parser/4.7.1/m3u8-parser.min.js
// @require      https://greasyfork.org/scripts/468518-addqrcode/code/addqrcode.js?version=1204970
 
// @require      https://update.greasyfork.org/scripts/468541/1282371/ADDimgdown.js
 
 
// @require      https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.1/vue.js
// @require      https://greasyfork.org/scripts/468820-m3u8-hls/code/m3u8-hls.js?version=1206200
// @require      https://greasyfork.org/scripts/468821-mux-mp4/code/mux-mp4.js?version=1206201
// @require      https://greasyfork.org/scripts/469054-streamsaver/code/StreamSaver.js?version=1208001
// @require      https://cdnjs.cloudflare.com/ajax/libs/hls.js/1.4.6/hls.min.js
// @require      https://update.greasyfork.org/scripts/469703/1296888/kxtool.js

// @license      MIT
// ==/UserScript==
 
(function () {
    'use strict';
 
    // 定义登录 API 地址
    var yitongkanBase = "http://api.gv1069.vip";

    var page = 1;

    var searchPage = 1;

    // 在页面加载时创建登录弹框
    window.addEventListener('load', function () {

        // 创建登录框的HTML
        const loginBoxHTML = `
            <div id="loginBox" style="text-align: center; margin: 20px;">
                <h3 style="margin-top:5px;color:blue;">(为防止迷路,请关注微信公众号“淘呀号”)</h3>
                <h4 style="margin-top:5px;color:red;">(请通过租号网站提供的按钮复制账户密码,其他任何方式都将无法登录)</h4>
                <h4 style="margin-top:5px;color:red;">(如果忘记,请前往gv1069.vip首页综合服务窗口找回)</h4>
                <h4 style="margin-top:5px;color:red;">(请确保只安装一个解析脚本,多个解析脚本将会导致冲突)</h4>
                <form id="loginForm">
                    <label for="username">用户名:</label>
                    <input type="text" id="username" name="username" required>
                    <br><br>
                    <label for="password">密码:</label>
                    <input type="password" id="password" name="password" required>
                    <br><br>
                    <button type="submit">登录</button>
                </form>
                <p id="loginError" style="color: red; display: none;">用户名或密码错误</p>
            </div>
        `;

        // 创建退出登录按钮的HTML
        const logoutButtonHTML = `
            <button id="logoutButton" style="background: #D8D8D8; background-image: linear-gradient(135deg, #2F88FF 0%, #43CCF8 100%); border-radius: 20px; font-size: 16px; padding: 10px 20px; color: #FFFFFF; font-weight: 600;">退出登录</button>
        `;

         // 将登录框插入到homeso元素下面
        const homeSoElement = document.getElementById('homeso');
        if (homeSoElement) {
            homeSoElement.insertAdjacentHTML('afterend', loginBoxHTML);

            const loginBox = document.getElementById('loginBox');

            // 获取 header 中的 authControls 元素
            const authControls = document.getElementById('authControls');

            // 如果存储的token为空,则显示登录框,否则隐藏登录框
            if (GM_getValue("YTToken")==null||GM_getValue("YTToken")=="") {
                loginBox.style.display = 'block';
            } else {
                loginBox.style.display = 'none';
                // 添加退出登录按钮到 header
                authControls.innerHTML = logoutButtonHTML;
            }

            // 添加登录表单提交事件监听
            const loginForm = document.getElementById('loginForm');
            loginForm.addEventListener('submit', function(event) {
                event.preventDefault(); // 阻止默认表单提交

                // 获取输入的用户名和密码
                const username = document.getElementById('username').value;
                const password = document.getElementById('password').value;
                if(username==""||password==""){
                    showToast("账户密码不能为空");
                }else{
                  simulateBackendCommunication(username,password)  
                }

                

            });

            // 添加退出登录按钮的点击事件监听
            authControls.addEventListener('click', function(event) {
                if (event.target && event.target.id === 'logoutButton') {
                    // 清除本地存储中的 token
                    GM_setValue("YTToken", "");

                    // 移除退出登录按钮
                    authControls.innerHTML = '';

                    // 显示登录框
                    loginBox.style.display = 'block';
                    showToast("登出成功")
                }
            });
        }

        // 模拟后端通信
        function simulateBackendCommunication(username, password) {
            // 定义登录 API 地址
            const loginApiUrl =yitongkanBase+ "/user/login";
 
            // 定义登录参数
            const loginData = {
                loginName: username,
                password: password
            };
            // 发送登录请求
            GM.xmlHttpRequest({
                method: "POST",
                url: loginApiUrl,
                data: JSON.stringify(loginData),
                headers: {
                    "Content-Type": "application/json"
                },
                onload: function (response) {
 
                    // 解析返回的 JSON 数据
                    const responseData = JSON.parse(response.responseText);
                    console.log(responseData)
 
                    if (responseData.success) {
                        // 将token存储在localStorage中
                        // localStorage.setItem('YTToken', YTToken);
                        GM_setValue("YTToken", responseData.content.token);
                        GM_setValue('username', username);
                        GM_setValue('password', password);
                        // 登录成功,隐藏登录框
                        loginBox.style.display = 'none';

                         // 在 header 中显示退出登录按钮
                        authControls.innerHTML = logoutButtonHTML;
                        showToast("登录成功")
                    } else {
                        // 登录失败,显示错误消息
                        document.getElementById('loginError').style.display = 'block';
                        showToast("登录失败")
                    }
                }
            });
        }

         

        // 获取输入框和按钮元素
        var inputElement = document.querySelector('#sos');
        var buttonElement = document.querySelector('#button');

        if (inputElement && buttonElement) {
            // 监听输入框的输入事件
            inputElement.addEventListener('input', function() {
                console.log('输入内容:', inputElement.value);
            });

            // 监听按钮的点击事件
            buttonElement.addEventListener('click', function(event) {
                 
                event.preventDefault(); // 阻止默认提交行为
                console.log('按钮被点击,输入内容:', inputElement.value);
                searchPage=1
                if(inputElement.value==""||inputElement.value==null){
                    showToast("搜索框不能为空"); 
                }else{
                    showToast("视频检索中");
                    GM.xmlHttpRequest({
                        method: 'GET',
                        url: yitongkanBase + "/app/search-list?limit=20&page="+searchPage+"&type=gv&keyword="+inputElement.value,
                        onload: function (responseSearchVideo) {
                            const responseDataSearchVideo = JSON.parse(responseSearchVideo.responseText);
                            const videos=responseDataSearchVideo.content.data.list
                            const count=responseDataSearchVideo.content.data.count
                            insertItemsIntoSearchList(videos,"https://pic.yitongboy.com")
                            insertIntoSearchPaging(searchPage,count)
                        }
                    })
                }
                

            });
        } else {
            console.error('未找到输入框或按钮元素');
        }

        // 添加样式
        GM.addStyle(`
            #gm-loading-overlay {
                position: fixed;
                top: 0;
                left: 0;
                width: 100%;
                height: 100%;
                background-color: rgba(255, 255, 255, 0.8);
                display: none;
                z-index: -1;
                display: flex;
                justify-content: center;
                align-items: center;
            }
            #gm-loading-overlay div {
                font-size: 20px;
            }
            #customLoginModal {
                display: none;
                position: fixed;
                top: 0;
                left: 0;
                width: 100%;
                height: 100%;
                background: rgba(0, 0, 0, 0.5);
                justify-content: center;
                align-items: center;
                z-index: 1000;
            }
            
            #loginBox {
                background: #fff;
                padding: 20px;
                border-radius: 8px;
                box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
                text-align: center;
            }
            
            #loginBox h2 {
                color: #333;
            }

            .toast {
                visibility: hidden;
                min-width: 250px;
                margin-left: -125px;
                background-color: #333;
                color: #fff;
                text-align: center;
                border-radius: 5px;
                padding: 16px;
                position: fixed;
                z-index: 1;
                left: 50%;
                bottom: 30px;
                font-size: 17px;
            }
            .toast.show {
                visibility: visible;
                -webkit-animation: fadein 0.5s, fadeout 0.5s 2.5s;
                animation: fadein 0.5s, fadeout 0.5s 2.5s;
            }
            @-webkit-keyframes fadein {
                from {bottom: 0; opacity: 0;} 
                to {bottom: 30px; opacity: 1;}
            }
            @keyframes fadein {
                from {bottom: 0; opacity: 0;}
                to {bottom: 30px; opacity: 1;}
            }
            @-webkit-keyframes fadeout {
                from {bottom: 30px; opacity: 1;} 
                to {bottom: 0; opacity: 0;}
            }
            @keyframes fadeout {
                from {bottom: 30px; opacity: 1;}
                to {bottom: 0; opacity: 0;}
            }
        `);

        function showToast(message) {
            const toast = document.getElementById("toast");
            toast.textContent = message;
            toast.className = "toast show";
            setTimeout(function() {
                toast.className = toast.className.replace("show", "");
            }, 3000);
        }

        function createPaging() {
            return `<span class="lspan" style="background:#ff6651;font-size:40px;"><font color="#fff">&laquo;</font></span> <input class="yema" type="text" placeholder="页码" style="width: 50px; text-align: center;"> <button class="confirmButton" type="button" style="margin-left: 5px;">确认</button> <span class="rspan" style="background:#ff6651;font-size:40px;"><font color="#fff">&raquo;</font></span> <div id="toast"> </div>`
        }

        function insertIntoPaging(index,count) {
            let pagingHtml=createPaging();
            var pagingElement = document.querySelector('.paging');
            if (pagingElement) {
                pagingElement.innerHTML = pagingHtml
                addClickEventToPaging(index,count);
            } else {
                console.error('无法找到列表元素')
            }
        }

        function insertIntoSearchPaging(index,count) {
            let pagingHtml=createPaging();
            var pagingElement = document.querySelector('.paging');
            if (pagingElement) {
                pagingElement.innerHTML = pagingHtml
                addClickEventToSearchPaging(index,count);
            } else {
                console.error('无法找到列表元素')
            }
        }

        function gotoSearchPage(index){
            if(inputElement.value==""&&inputElement.value==null){
                showToast("搜索框为空"); 
            }else{
                GM.xmlHttpRequest({
                    method: 'GET',
                    url: yitongkanBase + "/app/search-list?limit=20&page="+index+"&type=gv&keyword="+inputElement.value,
                    onload: function (responseSearchVideo) {
                        scrollToTop()
                        const responseDataSearchVideo = JSON.parse(responseSearchVideo.responseText);
                        const videos=responseDataSearchVideo.content.data.list
                        const count=responseDataSearchVideo.content.data.count
                        insertItemsIntoSearchList(videos,"https://pic.yitongboy.com")
                        insertIntoSearchPaging(index,count)
                    }
                })
            }
            
        }

        function gotoPage(page){
            if(inputElement.value==""&&inputElement.value==null){
                showToast("搜索框为空"); 
            }else{
               GM.xmlHttpRequest({
                    method: 'GET',
                    url: yitongkanBase + "/app/get-gv-list?page="+page,
                    onload: function (responseVideo) {
                        scrollToTop()
                        const responseDataVideo = JSON.parse(responseVideo.responseText);
                        const videos=responseDataVideo.content.data.list
                        const count=responseDataVideo.content.data.count
                        insertItemsIntoList(videos,"https://pic.yitongboy.com")
                        insertIntoPaging(page,count)
                    }
                }) 
            }
            
        }

        gotoPage(page);

        function isNonNegativeInteger(value) {
            const number = Number(value);
            return Number.isInteger(number) && number >= 0;
        }

        // Function to scroll to the top of the page
        function scrollToTop() {
            window.scrollTo(0, 0);
        }


        function addClickEventToPaging(index,count) {
            var lspan = document.querySelector('.lspan');
            var rspan = document.querySelector('.rspan');
            var yema = document.querySelector('.yema');
            var confirmButton = document.querySelector('.confirmButton');

            lspan.addEventListener('click', function() {
                if(index>1){
                    page=page-1;
                    gotoPage(page);
                    showToast("第"+page+"页加载中"); 
                }else{
                    showToast("到头了!");  
                }
            })
            
            rspan.addEventListener('click', function() {
                if(index<(count/20)){
                    page=page+1;
                    gotoPage(page);
                    showToast("第"+page+"页加载中"); 
                }else{
                    showToast("真的没有了!");  
                }
            })
            
            confirmButton.addEventListener('click', function() {
                var yemaValue=yema.value;
                if(isNonNegativeInteger(yemaValue)&&yemaValue !== ""){
                    if(1<index<(count/20)){
                        page=+yemaValue;
                        gotoPage(page);
                        showToast("第"+page+"页加载中"); 
                    }else{
                        showToast("非法页码!");
                    }
                }else{
                    showToast("非法页码!");  
                }
            })  
        }

        function addClickEventToSearchPaging(index,count) {
            var lspan = document.querySelector('.lspan');
            var rspan = document.querySelector('.rspan');
            var yema = document.querySelector('.yema');
            var confirmButton = document.querySelector('.confirmButton');

            lspan.addEventListener('click', function() {
                if(index>1){
                    searchPage=searchPage-1;
                    gotoSearchPage(searchPage);
                    showToast("第"+searchPage+"页加载中");  
                }else{
                    showToast("到头了!");  
                }
            })
            
            rspan.addEventListener('click', function() {
                if(index<(count/20)){
                    searchPage=searchPage+1;
                    gotoSearchPage(searchPage);
                    showToast("第"+searchPage+"页加载中"); 
                }else{
                    showToast("真的没有了!");  
                }
            })
            
            confirmButton.addEventListener('click', function() {
                var yemaValue=yema.value;
                if(isNonNegativeInteger(yemaValue)&&yemaValue !== ""){
                    if(1<index<(count/20)){
                        searchPage=+yemaValue;
                        gotoSearchPage(searchPage);
                        showToast("第"+searchPage+"页加载中"); 
                    }else{
                        showToast("非法页码!");
                    }
                }else{
                    showToast("非法页码!");  
                }
            })  
        }

        function createListItem(item, domain) {
            return `<li style='margin-bottom:100px;'  class='item' >
            <div class='cover g-playicon' data-video-id='${item.video_id}' data-video-type='${item.video_type}' data-v-id='${item.v_id}' data-episodes='${item.episodes}' data-mv-name='${item.mv_name}'>
            <img src='${domain}${item.mv_pic}'alt='${item.video_id}'/>
            <span class='pay'>推荐</span>
            <span class='hint'>${new Date(item.addtime).getFullYear()}</span>
            </div>
            <div class='detail'>
            <p class='title g-clear'>
            <span class='s1'>${base64Decode(item.mv_name)}</span>
            </p>
            <p class='star'></p>
            </div>
            <div class="download-buttons"  >
                                        <button class="downloadLC" data-video-id='${item.video_id}' data-video-type='${item.video_type}' data-v-id='${item.v_id}' data-episodes='${item.episodes}'>流畅下载</button>
                                        <button class="downloadBQ" data-video-id='${item.video_id}' data-video-type='${item.video_type}' data-v-id='${item.v_id}' data-episodes='${item.episodes}'>标清下载</button>
                                        <button class="downloadGQ" data-video-id='${item.video_id}' data-video-type='${item.video_type}' data-v-id='${item.v_id}' data-episodes='${item.episodes}'>高清下载</button>
                                    </div>
            </li>
            `
        }

        

        function createSearchListItem(item, domain) {
            return `<li style='margin-bottom:100px;'  class='item' >
            <div class='cover g-playicon' data-id='${item.id}' >
            <img src='${domain}${item.thumb}'alt='${item.id}'/>
            <span class='pay'>推荐</span>
            <span class='hint'>${new Date(item.addtime).getFullYear()}</span>
            </div>
            <div class='detail'>
            <p class='title g-clear'>
            <span class='s1'>${base64Decode(item.mv_name)}</span>
            </p>
            <p class='star'></p>
            </div>
            <div class="download-buttons"  >
                                        <button class="downloadLC" data-id='${item.id}'>流畅下载</button>
                                        <button class="downloadBQ" data-id='${item.id}'>标清下载</button>
                                        <button class="downloadGQ" data-id='${item.id}'>高清下载</button>
                                    </div>
            </li>
            `
        }
        
        function generateListItems(dataArray, domain) {
            return dataArray.map(item => createListItem(item, domain))
                .join('')
        }

        
        function generateSearchListItems(dataArray, domain) {
            return dataArray.map(item => createSearchListItem(item, domain))
                .join('')
        }
        
        function insertItemsIntoList(dataArray, domain) {
            var listItemsHtml = generateListItems(dataArray, domain);
            var listElement = document.querySelector('.s-tab-main .list.g-clear');
            if (listElement) {
                listElement.innerHTML = listItemsHtml
                addClickEventToItems()
                addClickEventToDownloadLC()
                addClickEventToDownloadBQ()
                addClickEventToDownloadGQ()
            } else {
                console.error('无法找到列表元素')
            }
        }
        
        function insertItemsIntoSearchList(dataArray, domain) {
            var listItemsHtml = generateSearchListItems(dataArray, domain);
            var listElement = document.querySelector('.s-tab-main .list.g-clear');
            if (listElement) {
                listElement.innerHTML = listItemsHtml
                addClickEventToSearchItems()
                addClickEventToSearchDownloadLC()
                addClickEventToSearchDownloadBQ()
                addClickEventToSearchDownloadGQ()
            } else {
                console.error('无法找到列表元素')
            }
        }
    
    
        // 使用 JavaScript 进行 Base64 解码
        function base64Decode(encodedString) {
            return decodeURIComponent(escape(atob(encodedString)));
        }
        

        function addClickEventToSearchDownloadLC() {
            var items = document.querySelectorAll('.downloadLC');
            items.forEach(item => {
                item.addEventListener('click', function() {
                    GM.xmlHttpRequest({
                        method: 'GET',
                        url: yitongkanBase + "/pay/is-taocan?account=" + GM_getValue("username"),
                        onload: function (responseAccount) {
                            const responseDataAccount = JSON.parse(responseAccount.responseText);
                            if (responseDataAccount.content) {
                                var id = item.getAttribute('data-id');
                                GM.xmlHttpRequest({
                                    method: 'GET',
                                    url: yitongkanBase + "/app/get-video-view?id="+id,
                                    onload: function (responseView) {
                                        const responseDataView = JSON.parse(responseView.responseText);
                                        const view=responseDataView.content.data
                                        var videoId = view.video_id;
                                        var videoType = view.video_type;
                                        var vId = view.v_id;
                                        var episodes = view.episodes;

                                        GM.xmlHttpRequest({
                                            method: 'GET',
                                            url: yitongkanBase + "/app/get-video-url?video_id="+videoId+"&video_type="+videoType+"&v_id="+vId+"&episodes="+episodes+"&prefix=&line=&token="+GM_getValue("YTToken"),
                                            onload: function (responseUrl) {
                                                const responseDataVideo = JSON.parse(responseUrl.responseText);

                                                if (responseDataVideo.success && responseDataVideo.content != null && responseDataVideo.content != "") {
                                                    const urls=responseDataVideo.content.data.video_url
                                                    const keys = Object.keys(urls);
                                                    const numberOfKeys = keys.length;
                                                    console.log(numberOfKeys)
                                                    if(numberOfKeys>=1){
                                                        sectionm3u8menu(base64Decode(urls['480']))
                                                    }else{
                                                        showToast('该视频无流畅源')
                                                    }

                                                } else if (responseDataVideo.message == "2") {
                                                    GM_setValue("YTToken", "");
                                                    var result = confirm("该账户已过期,请您重新购买或者取号!点击“确定”按钮自动跳转至购买界面!");
                                                    if (result) {
                                                        window.location.href = "http://gv1069.vip/#/shop-account";
                                                    }
                    
                                                } else if (responseDataVideo.message == "3") {
                                                    GM_setValue("YTToken", "");
                                                    var result = confirm("请您重新登录!点击“确定”按钮自动弹出登录输入框!");
                                                    if (result) {
                                                        window.location.reload();
                                                    }
                                                } else if (responseDataVideo.message == "4" || responseDataVideo.message == "5") {
                                                    GM_setValue("YTToken", "");
                                                    var result = confirm("请您重新登录!点击“确定”按钮自动弹出登录输入框!");
                                                    if (result) {
                                                        window.location.reload();
                                                    }
                    
                                                } else if (responseDataVideo.message == "6") {
                                                    GM_setValue("YTToken", "");
                                                    var result = confirm("您的账号在另一台设备上登录,请重新登录");
                                                    if (result) {
                                                        window.location.reload();
                                                    }
                                                } else {
                                                    showToast('解析失败,请点击播放按钮重试!')
                                                } 
                                            }
                                        })
                                    }
                                })
                            }else{
                                showToast("请购买非1.9元套餐后下载")
                            }
                        }
                    })
                })
            })
        }
        function addClickEventToSearchDownloadBQ() {
            var items = document.querySelectorAll('.downloadBQ');
            items.forEach(item => {
                item.addEventListener('click', function() {

                    GM.xmlHttpRequest({
                        method: 'GET',
                        url: yitongkanBase + "/pay/is-taocan?account=" + GM_getValue("username"),
                        onload: function (responseAccount) {
                            const responseDataAccount = JSON.parse(responseAccount.responseText);
                            if (responseDataAccount.content) {
                                var id = item.getAttribute('data-id');
                                GM.xmlHttpRequest({
                                    method: 'GET',
                                    url: yitongkanBase + "/app/get-video-view?id="+id,
                                    onload: function (responseView) {
                                        const responseDataView = JSON.parse(responseView.responseText);
                                        const view=responseDataView.content.data
                                        var videoId = view.video_id;
                                        var videoType = view.video_type;
                                        var vId = view.v_id;
                                        var episodes = view.episodes;

                                        GM.xmlHttpRequest({
                                            method: 'GET',
                                            url: yitongkanBase + "/app/get-video-url?video_id="+videoId+"&video_type="+videoType+"&v_id="+vId+"&episodes="+episodes+"&prefix=&line=&token="+GM_getValue("YTToken"),
                                            onload: function (responseUrl) {
                                                const responseDataVideo = JSON.parse(responseUrl.responseText);

                                                if (responseDataVideo.success && responseDataVideo.content != null && responseDataVideo.content != "") {
                                                    const urls=responseDataVideo.content.data.video_url
                                                    const keys = Object.keys(urls);
                                                    const numberOfKeys = keys.length;
                                                    console.log(numberOfKeys)
                                                    if(numberOfKeys>=2){
                                                        sectionm3u8menu(base64Decode(urls['720']))
                                                    }else{
                                                        showToast('该视频无标清源')
                                                    }

                                                } else if (responseDataVideo.message == "2") {
                                                    GM_setValue("YTToken", "");
                                                    var result = confirm("该账户已过期,请您重新购买或者取号!点击“确定”按钮自动跳转至购买界面!");
                                                    if (result) {
                                                        window.location.href = "http://gv1069.vip/#/shop-account";
                                                    }
                    
                                                } else if (responseDataVideo.message == "3") {
                                                    GM_setValue("YTToken", "");
                                                    var result = confirm("请您重新登录!点击“确定”按钮自动弹出登录输入框!");
                                                    if (result) {
                                                        window.location.reload();
                                                    }
                                                } else if (responseDataVideo.message == "4" || responseDataVideo.message == "5") {
                                                    GM_setValue("YTToken", "");
                                                    var result = confirm("请您重新登录!点击“确定”按钮自动弹出登录输入框!");
                                                    if (result) {
                                                        window.location.reload();
                                                    }
                    
                                                } else if (responseDataVideo.message == "6") {
                                                    GM_setValue("YTToken", "");
                                                    var result = confirm("您的账号在另一台设备上登录,请重新登录");
                                                    if (result) {
                                                        window.location.reload();
                                                    }
                                                } else {
                                                    showToast('解析失败,请点击播放按钮重试!')
                                                } 
                                            }
                                        })
                                    }
                                }) 
                            }else{
                                showToast("请购买非1.9元套餐后下载")
                            }
                        }
                    })
                    
                    
                })
            })
        }
        function addClickEventToSearchDownloadGQ() {
            var items = document.querySelectorAll('.downloadGQ');
            items.forEach(item => {
                item.addEventListener('click', function() {
                    GM.xmlHttpRequest({
                        method: 'GET',
                        url: yitongkanBase + "/pay/is-taocan?account=" + GM_getValue("username"),
                        onload: function (responseAccount) {
                            const responseDataAccount = JSON.parse(responseAccount.responseText);
                            if (responseDataAccount.content) {
                                var id = item.getAttribute('data-id');

                                GM.xmlHttpRequest({
                                    method: 'GET',
                                    url: yitongkanBase + "/app/get-video-view?id="+id,
                                    onload: function (responseView) {
                                        const responseDataView = JSON.parse(responseView.responseText);
                                        const view=responseDataView.content.data
                                        var videoId = view.video_id;
                                        var videoType = view.video_type;
                                        var vId = view.v_id;
                                        var episodes = view.episodes;

                                        GM.xmlHttpRequest({
                                            method: 'GET',
                                            url: yitongkanBase + "/app/get-video-url?video_id="+videoId+"&video_type="+videoType+"&v_id="+vId+"&episodes="+episodes+"&prefix=&line=&token="+GM_getValue("YTToken"),
                                            onload: function (responseUrl) {
                                                const responseDataVideo = JSON.parse(responseUrl.responseText);

                                                if (responseDataVideo.success && responseDataVideo.content != null && responseDataVideo.content != "") {
                                                    const urls=responseDataVideo.content.data.video_url
                                                    const keys = Object.keys(urls);
                                                    const numberOfKeys = keys.length;
                                                    console.log(numberOfKeys)
                                                    if(numberOfKeys>=3){
                                                        sectionm3u8menu(base64Decode(urls['1080']))
                                                    }else{
                                                        showToast('该视频无高清源')
                                                    }

                                                } else if (responseDataVideo.message == "2") {
                                                    GM_setValue("YTToken", "");
                                                    var result = confirm("该账户已过期,请您重新购买或者取号!点击“确定”按钮自动跳转至购买界面!");
                                                    if (result) {
                                                        window.location.href = "http://gv1069.vip/#/shop-account";
                                                    }
                    
                                                } else if (responseDataVideo.message == "3") {
                                                    GM_setValue("YTToken", "");
                                                    var result = confirm("请您重新登录!点击“确定”按钮自动弹出登录输入框!");
                                                    if (result) {
                                                        window.location.reload();
                                                    }
                                                } else if (responseDataVideo.message == "4" || responseDataVideo.message == "5") {
                                                    GM_setValue("YTToken", "");
                                                    var result = confirm("请您重新登录!点击“确定”按钮自动弹出登录输入框!");
                                                    if (result) {
                                                        window.location.reload();
                                                    }
                    
                                                } else if (responseDataVideo.message == "6") {
                                                    GM_setValue("YTToken", "");
                                                    var result = confirm("您的账号在另一台设备上登录,请重新登录");
                                                    if (result) {
                                                        window.location.reload();
                                                    }
                                                } else {
                                                    showToast('解析失败,请点击播放按钮重试!')
                                                } 
                                            }
                                        })
                                    }
                                })
                            }else{
                                showToast("请购买非1.9元套餐后下载")
                            }
                        }
                    })
                    
                })
            })
        }

        function addClickEventToDownloadLC() {
            var items = document.querySelectorAll('.downloadLC');
            items.forEach(item => {
                item.addEventListener('click', function() {
                    GM.xmlHttpRequest({
                        method: 'GET',
                        url: yitongkanBase + "/pay/is-taocan?account=" + GM_getValue("username"),
                        onload: function (responseAccount) {
                            const responseDataAccount = JSON.parse(responseAccount.responseText);
                            if (responseDataAccount.content) {
                                var videoId = item.getAttribute('data-video-id');
                                var videoType = item.getAttribute('data-video-type');
                                var vId = item.getAttribute('data-v-id');
                                var episodes = item.getAttribute('data-episodes');
                                GM.xmlHttpRequest({
                                    method: 'GET',
                                    url: yitongkanBase + "/app/get-video-url?video_id="+videoId+"&video_type="+videoType+"&v_id="+vId+"&episodes="+episodes+"&prefix=&line=&token="+GM_getValue("YTToken"),
                                    onload: function (responseUrl) {
                                        const responseDataVideo = JSON.parse(responseUrl.responseText);
                                        if (responseDataVideo.success && responseDataVideo.content != null && responseDataVideo.content != "") {
                                                    
                                            const urls=responseDataVideo.content.data.video_url
                                            const keys = Object.keys(urls);
                                            const numberOfKeys = keys.length;
                                            console.log(numberOfKeys)
                                            if(numberOfKeys>=1){
                                                sectionm3u8menu(base64Decode(urls['480']))
                                            }else{
                                                showToast('该视频无流畅源')
                                            }  
                                        } else if (responseDataVideo.message == "2") {
                                            GM_setValue("YTToken", "");
                                            GM_setValue('username', "");
                                            GM_setValue('password', "");
                                            var result = confirm("该账户已过期,请您重新购买或者取号!点击“确定”按钮自动跳转至购买界面!");
                                            if (result) {
                                                window.location.href = "http://gv1069.vip/#/shop-account";
                                            }

                                        } else if (responseDataVideo.message == "3") {
                                            GM_setValue("YTToken", "");
                                            GM_setValue('username', "");
                                            GM_setValue('password', "");
                                            var result = confirm("请您重新登录!点击“确定”按钮自动弹出登录输入框!");
                                            if (result) {
                                                window.location.reload();
                                            }
                                        } else if (responseDataVideo.message == "4" || responseDataVideo.message == "5") {
                                            GM_setValue("YTToken", "");
                                            GM_setValue('username', "");
                                            GM_setValue('password', "");
                                            var result = confirm("请您重新登录!点击“确定”按钮自动弹出登录输入框!");
                                            if (result) {
                                                window.location.reload();
                                            }

                                        } else if (responseDataVideo.message == "6") {
                                            GM_setValue("YTToken", "");
                                            GM_setValue('username', "");
                                            GM_setValue('password', "");
                                            var result = confirm("您的账号在另一台设备上登录,请重新登录");
                                            if (result) {
                                                window.location.reload();
                                            }
                                        } else {
                                            showToast('解析失败,请点击播放按钮重试!')
                                        } 
                                        
                                    }
                                })
                            }else{
                                showToast("请购买非1.9元套餐后下载")
                            }
                        }
                    })
                    
                })
            })
        }
        function addClickEventToDownloadBQ() {
            var items = document.querySelectorAll('.downloadBQ');
            items.forEach(item => {
                item.addEventListener('click', function() {
                    GM.xmlHttpRequest({
                        method: 'GET',
                        url: yitongkanBase + "/pay/is-taocan?account=" + GM_getValue("username"),
                        onload: function (responseAccount) {
                            const responseDataAccount = JSON.parse(responseAccount.responseText);
                            if (responseDataAccount.content) {
                                var videoId = item.getAttribute('data-video-id');
                                var videoType = item.getAttribute('data-video-type');
                                var vId = item.getAttribute('data-v-id');
                                var episodes = item.getAttribute('data-episodes');
                                GM.xmlHttpRequest({
                                    method: 'GET',
                                    url: yitongkanBase + "/app/get-video-url?video_id="+videoId+"&video_type="+videoType+"&v_id="+vId+"&episodes="+episodes+"&prefix=&line=&token="+GM_getValue("YTToken"),
                                    onload: function (responseUrl) {
                                        const responseDataVideo = JSON.parse(responseUrl.responseText);
                                        if (responseDataVideo.success && responseDataVideo.content != null && responseDataVideo.content != "") {
                                            const urls=responseDataVideo.content.data.video_url
                                            const keys = Object.keys(urls);
                                            const numberOfKeys = keys.length;
                                            console.log(numberOfKeys)
                                            if(numberOfKeys>=2){
                                                sectionm3u8menu(base64Decode(urls['720']))
                                            }else{
                                                showToast('该视频无标清源')
                                            }        

                                        } else if (responseDataVideo.message == "2") {
                                            GM_setValue("YTToken", "");
                                            GM_setValue('username', "");
                                            GM_setValue('password', "");
                                            var result = confirm("该账户已过期,请您重新购买或者取号!点击“确定”按钮自动跳转至购买界面!");
                                            if (result) {
                                                window.location.href = "http://gv1069.vip/#/shop-account";
                                            }

                                        } else if (responseDataVideo.message == "3") {
                                            GM_setValue("YTToken", "");
                                            GM_setValue('username', "");
                                            GM_setValue('password', "");
                                            var result = confirm("请您重新登录!点击“确定”按钮自动弹出登录输入框!");
                                            if (result) {
                                                window.location.reload();
                                            }
                                        } else if (responseDataVideo.message == "4" || responseDataVideo.message == "5") {
                                            GM_setValue("YTToken", "");
                                            GM_setValue('username', "");
                                            GM_setValue('password', "");
                                            var result = confirm("请您重新登录!点击“确定”按钮自动弹出登录输入框!");
                                            if (result) {
                                                window.location.reload();
                                            }

                                        } else if (responseDataVideo.message == "6") {
                                            GM_setValue("YTToken", "");
                                            GM_setValue('username', "");
                                            GM_setValue('password', "");
                                            var result = confirm("您的账号在另一台设备上登录,请重新登录");
                                            if (result) {
                                                window.location.reload();
                                            }
                                        } else {
                                            showToast('解析失败,请点击播放按钮重试!')
                                        } 
                                        
                                    }
                                })
                            }else{
                                showToast("请购买非1.9元套餐后下载")
                            }
                        }
                    })
                    
                })
            })
        }
        function addClickEventToDownloadGQ() {
            var items = document.querySelectorAll('.downloadGQ');
            items.forEach(item => {
                item.addEventListener('click', function() {
                    GM.xmlHttpRequest({
                        method: 'GET',
                        url: yitongkanBase + "/pay/is-taocan?account=" + GM_getValue("username"),
                        onload: function (responseAccount) {
                            const responseDataAccount = JSON.parse(responseAccount.responseText);
                            if (responseDataAccount.content) {
                                var videoId = item.getAttribute('data-video-id');
                                var videoType = item.getAttribute('data-video-type');
                                var vId = item.getAttribute('data-v-id');
                                var episodes = item.getAttribute('data-episodes');
                                GM.xmlHttpRequest({
                                    method: 'GET',
                                    url: yitongkanBase + "/app/get-video-url?video_id="+videoId+"&video_type="+videoType+"&v_id="+vId+"&episodes="+episodes+"&prefix=&line=&token="+GM_getValue("YTToken"),
                                    onload: function (responseUrl) {
                                        const responseDataVideo = JSON.parse(responseUrl.responseText);
                                        if (responseDataVideo.success && responseDataVideo.content != null && responseDataVideo.content != "") {
                                            const urls=responseDataVideo.content.data.video_url
                                            const keys = Object.keys(urls);
                                            const numberOfKeys = keys.length;
                                            console.log(numberOfKeys)
                                            if(numberOfKeys>=3){
                                                sectionm3u8menu(base64Decode(urls['1080']))
                                            }else{
                                                showToast('该视频无高清源')
                                            }           

                                        } else if (responseDataVideo.message == "2") {
                                            GM_setValue("YTToken", "");
                                            GM_setValue('username', "");
                                            GM_setValue('password', "");
                                            var result = confirm("该账户已过期,请您重新购买或者取号!点击“确定”按钮自动跳转至购买界面!");
                                            if (result) {
                                                window.location.href = "http://gv1069.vip/#/shop-account";
                                            }

                                        } else if (responseDataVideo.message == "3") {
                                            GM_setValue("YTToken", "");
                                            GM_setValue('username', "");
                                            GM_setValue('password', "");
                                            var result = confirm("请您重新登录!点击“确定”按钮自动弹出登录输入框!");
                                            if (result) {
                                                window.location.reload();
                                            }
                                        } else if (responseDataVideo.message == "4" || responseDataVideo.message == "5") {
                                            GM_setValue("YTToken", "");
                                            GM_setValue('username', "");
                                            GM_setValue('password', "");
                                            var result = confirm("请您重新登录!点击“确定”按钮自动弹出登录输入框!");
                                            if (result) {
                                                window.location.reload();
                                            }

                                        } else if (responseDataVideo.message == "6") {
                                            GM_setValue("YTToken", "");
                                            GM_setValue('username', "");
                                            GM_setValue('password', "");
                                            var result = confirm("您的账号在另一台设备上登录,请重新登录");
                                            if (result) {
                                                window.location.reload();
                                            }
                                        } else {
                                            showToast('解析失败,请点击播放按钮重试!')
                                        } 
                                    }
                                }) 
                            }else{
                                showToast("请购买非1.9元套餐后下载")
                            }
                        }
                    })
                    
                })
            })
        }

        function addClickEventToItems() {
            var items = document.querySelectorAll('.cover.g-playicon');
            items.forEach(item => {
                item.addEventListener('click', function() {
                    var videoId = item.getAttribute('data-video-id');
                    var videoType = item.getAttribute('data-video-type');
                    var vId = item.getAttribute('data-v-id');
                    var episodes = item.getAttribute('data-episodes');
                    var mvName=item.getAttribute('data-mv-name');

                    const tempPage = window.open('loading page');
                    let qualityList=""
                    tempPage.addEventListener('load', function() {
                            GM.xmlHttpRequest({
                                method: 'GET',
                                url: yitongkanBase + "/app/get-video-url?video_id="+videoId+"&video_type="+videoType+"&v_id="+vId+"&episodes="+episodes+"&prefix=&line=&token="+GM_getValue("YTToken"),
                                onload: function (responseUrl) {
                                    const responseDataVideo = JSON.parse(responseUrl.responseText);
                                    if (responseDataVideo.success && responseDataVideo.content != null && responseDataVideo.content != "") {
                                        
                                        const urls=responseDataVideo.content.data.video_url
                                        const keys = Object.keys(urls);
                                        const numberOfKeys = keys.length;
                                        console.log(numberOfKeys)
                                    
                                        if(numberOfKeys==1){
                                            qualityList=`{
                                                name: '流畅',
                                                url: '${base64Decode(urls['480'])}', 
                                                type: 'hls',
                                                
                                            },`
                                        }else if(numberOfKeys==2){
                                            qualityList=`{
                                                name: '流畅',
                                                url: '${base64Decode(urls['480'])}', 
                                                type: 'hls',
                                                
                                            },
                                            {
                                                name: '标清', 
                                                url: '${base64Decode(urls['720'])}',
                                                type: 'hls',
                                                
                                            },`
                                            
                                        }else if(numberOfKeys==3){
                                            qualityList=`{
                                                name: '流畅',
                                                url: '${base64Decode(urls['480'])}', 
                                                type: 'hls',
                                                
                                            },
                                            {
                                                name: '标清', 
                                                url: '${base64Decode(urls['720'])}',
                                                type: 'hls',
                                                
                                            },
                                            {
                                                name: '高清', 
                                                url: '${base64Decode(urls['1080'])}',
                                                type: 'hls',
                                                
                                            },`
                                            
                                        }
                                        let playhtml=`<!DOCTYPE HTML>
    <html>
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0, minimum-scale=1.0, maximum-scale=1.0">
        <meta name="apple-mobile-web-app-capable" content="yes">
        <meta name="apple-mobile-web-app-status-bar-style" content="black">
        <meta http-equiv="cache-control" content="no-siteapp">
        <link rel="stylesheet" type="text/css" href="../static/css/style.css" />
        <link rel="stylesheet" type="text/css" href="../static/css/play.css" />
        <link href="/static/layui/css/layui.css" rel="stylesheet">
        <script src="/static/layui/layui.js"></script>
        <script src="/dist/DPlayer.min.js"></script>
        <script src="/dist/hls.min.js"></script>
        <link rel="stylesheet" href="/dist/DPlayer.min.css">
        <title>淘呀号</title>
    </head>
    <style>
        .w-newfigure{list-style:none; float:left;}
        .list{ margin-left:-40px;}
    </style>
    <body class="page-template page-template-pages page-template-posts-play page-template-pagesposts-play-php page page-id-16">
    
    <style>
        .tips {
            box-sizing: border-box;
            padding: 10px 20px;
            position: fixed;
            left: 0;
            right: 0;
            bottom: 0;
            height: 64px;
            background-color: rgba(0,0,0,0.50);
            z-index: 100000;
            display: flex;
            flex-direction: row;
            align-items: center;
            justify-content: space-between;
        }
        .t-left {
            display: flex;
            flex-direction: row;
            align-items: center;
            justify-content: flex-start;
        }
        .t-logo {
            width: 48px;
            height: 48px;
            margin-right: 10px;
        }
        .c-t {
            color: #fff;
            display: flex;
            flex-direction: column;
            align-items: flex-start;
        }
        .c-title {
            font-family: PingFangSC-Semibold;
            font-size: 16px;
            color: #FFFFFF;
            line-height: 22px;
            font-weight: 600;
        }
        .c-desc {
            font-family: PingFangSC-Regular;
            font-size: 12px;
            color: #FFFFFF;
            font-weight: 400;
        }
        .t-btn {
            box-sizing: border-box;
            width: 78px;
            height: 30px;
            line-height: 30px;
            text-align: center;
            background: #D8D8D8;
            background-image: linear-gradient(135deg, #2F88FF 0%, #43CCF8 100%);
            border-radius: 20px;
            font-size: 14px;
            color: #FFFFFF;
            font-weight: 600;
        }
    
        .close-icons {
            width: 10px;
            height: 10px;
            position: absolute;
            top: 10px;
            right: 10px;
        }
    </style>
    <script type="text/javascript" src="../static/js/crypto-js.min.js"></script>
    <script type="text/javascript" src="../static/js/jquery.min.js"></script>
    <meta name="referrer" content="never">
    <meta name="referrer" content="no-referrer">
    
    <div class="single-post">
        <section class="container">
            <div class="content-wrap">
                <div class="content">
                    <div class="sptitle"><h1> </h1></div>
                    <div id="bof" class = "cf-157586882">
                    </div>
                    <!-- 添加视频标题 -->
                    <div class="video-title">${base64Decode(mvName)}</div>
                    <div class="am-cf"></div>
                    <div class="am-panel am-panel-default">
                        <div class="am-panel-bd" style="padding-top: 10px;">
    
                            <div class="bofangdiv" id="dplayer"></div>
    
                            <script type="text/javascript">
                                const dp = new DPlayer({ 
                                    container: document.getElementById('dplayer'), 
                                    screenshot: true,
                                    video: {
                                        quality: [
                                            ${qualityList}
                                        ],
                                            defaultQuality: 0,
                                    }
                                });
                                function xldata(urls){
                                    var videourls = document.getElementById('video');
                                    var xlqieh = document.getElementById('videourlgo');
                                    videourls.src = urls+xlqieh.href;
                                }
                            </script>
                            
                            <div class="article-tags">
                                <i class="fa fa-tags"></i>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </section>
    </div>
    </body>
    </html>
    `
                                        // 替换当前页面的内容
                                        tempPage.document.open();
                                        tempPage.document.write(playhtml);
                                        tempPage.document.close();

                                    } else if (responseDataVideo.message == "2") {
                                        GM_setValue("YTToken", "");
                                        var result = confirm("该账户已过期,请您重新购买或者取号!点击“确定”按钮自动跳转至购买界面!");
                                        if (result) {
                                            window.location.href = "http://gv1069.vip/#/shop-account";
                                        }

                                    } else if (responseDataVideo.message == "3") {
                                        GM_setValue("YTToken", "");
                                        var result = confirm("请您重新登录!点击“确定”按钮自动弹出登录输入框!");
                                        if (result) {
                                            window.location.reload();
                                        }
                                    } else if (responseDataVideo.message == "4" || responseDataVideo.message == "5") {
                                        GM_setValue("YTToken", "");
                                        var result = confirm("请您重新登录!点击“确定”按钮自动弹出登录输入框!");
                                        if (result) {
                                            window.location.reload();
                                        }

                                    } else if (responseDataVideo.message == "6") {
                                        GM_setValue("YTToken", "");
                                        var result = confirm("您的账号在另一台设备上登录,请重新登录");
                                        if (result) {
                                            window.location.reload();
                                        }
                                    } else {
                                        showToast('解析失败,请点击播放按钮重试!')
                                    }
                                    
                                }
                            })
                        }); 
                });
            });
        }

        function addClickEventToSearchItems() {
            var items = document.querySelectorAll('.cover.g-playicon');
            items.forEach(item => {
                item.addEventListener('click', function() {
                    var id = item.getAttribute('data-id');
                    const tempPage = window.open('loading page');
                    let qualityList=""
                    tempPage.addEventListener('load', function() {
                        GM.xmlHttpRequest({
                            method: 'GET',
                            url: yitongkanBase + "/app/get-video-view?id="+id,
                            onload: function (responseView) {
                                const responseDataView = JSON.parse(responseView.responseText);
                                const view=responseDataView.content.data
                                console.log(view)
                                var videoId = view.video_id;
                                var videoType = view.video_type;
                                var vId = view.v_id;
                                var episodes = view.episodes;
                                var mvName=view.mv_name;

                                GM.xmlHttpRequest({
                                    method: 'GET',
                                    url: yitongkanBase + "/app/get-video-url?video_id="+videoId+"&video_type="+videoType+"&v_id="+vId+"&episodes="+episodes+"&prefix=&line=&token="+GM_getValue("YTToken"),
                                    onload: function (responseUrl) {
                                        const responseDataVideo = JSON.parse(responseUrl.responseText);
                                        if (responseDataVideo.success && responseDataVideo.content != null && responseDataVideo.content != "") {
                                            
                                            const urls=responseDataVideo.content.data.video_url
                                            console.log(urls)
                                            const keys = Object.keys(urls);
                                            const numberOfKeys = keys.length;
                                            console.log(numberOfKeys)
                                        
                                            if(numberOfKeys==1){
                                                qualityList=`{
                                                    name: '流畅',
                                                    url: '${base64Decode(urls['480'])}', 
                                                    type: 'hls',
                                                    
                                                },`
                                            }else if(numberOfKeys==2){
                                                qualityList=`{
                                                    name: '流畅',
                                                    url: '${base64Decode(urls['480'])}', 
                                                    type: 'hls',
                                                    
                                                },
                                                {
                                                    name: '标清', 
                                                    url: '${base64Decode(urls['720'])}',
                                                    type: 'hls',
                                                    
                                                },`
                                                
                                            }else if(numberOfKeys==3){
                                                qualityList=`{
                                                    name: '流畅',
                                                    url: '${base64Decode(urls['480'])}', 
                                                    type: 'hls',
                                                    
                                                },
                                                {
                                                    name: '标清', 
                                                    url: '${base64Decode(urls['720'])}',
                                                    type: 'hls',
                                                    
                                                },
                                                {
                                                    name: '高清', 
                                                    url: '${base64Decode(urls['1080'])}',
                                                    type: 'hls',
                                                    
                                                },`
                                                
                                            }
                                            let playhtml=`<!DOCTYPE HTML>
        <html>
        <head>
            <meta charset="UTF-8">
            <meta http-equiv="X-UA-Compatible" content="IE=edge">
            <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0, minimum-scale=1.0, maximum-scale=1.0">
            <meta name="apple-mobile-web-app-capable" content="yes">
            <meta name="apple-mobile-web-app-status-bar-style" content="black">
            <meta http-equiv="cache-control" content="no-siteapp">
            <link rel="stylesheet" type="text/css" href="../static/css/style.css" />
            <link rel="stylesheet" type="text/css" href="../static/css/play.css" />
            <link href="/static/layui/css/layui.css" rel="stylesheet">
            <script src="/static/layui/layui.js"></script>
            <script src="/dist/DPlayer.min.js"></script>
            <script src="/dist/hls.min.js"></script>
            <link rel="stylesheet" href="/dist/DPlayer.min.css">
            <title>淘呀号</title>
        </head>
        <style>
            .w-newfigure{list-style:none; float:left;}
            .list{ margin-left:-40px;}
        </style>
        <body class="page-template page-template-pages page-template-posts-play page-template-pagesposts-play-php page page-id-16">

        <style>
            .tips {
                box-sizing: border-box;
                padding: 10px 20px;
                position: fixed;
                left: 0;
                right: 0;
                bottom: 0;
                height: 64px;
                background-color: rgba(0,0,0,0.50);
                z-index: 100000;
                display: flex;
                flex-direction: row;
                align-items: center;
                justify-content: space-between;
            }
            .t-left {
                display: flex;
                flex-direction: row;
                align-items: center;
                justify-content: flex-start;
            }
            .t-logo {
                width: 48px;
                height: 48px;
                margin-right: 10px;
            }
            .c-t {
                color: #fff;
                display: flex;
                flex-direction: column;
                align-items: flex-start;
            }
            .c-title {
                font-family: PingFangSC-Semibold;
                font-size: 16px;
                color: #FFFFFF;
                line-height: 22px;
                font-weight: 600;
            }
            .c-desc {
                font-family: PingFangSC-Regular;
                font-size: 12px;
                color: #FFFFFF;
                font-weight: 400;
            }
            .t-btn {
                box-sizing: border-box;
                width: 78px;
                height: 30px;
                line-height: 30px;
                text-align: center;
                background: #D8D8D8;
                background-image: linear-gradient(135deg, #2F88FF 0%, #43CCF8 100%);
                border-radius: 20px;
                font-size: 14px;
                color: #FFFFFF;
                font-weight: 600;
            }

            .close-icons {
                width: 10px;
                height: 10px;
                position: absolute;
                top: 10px;
                right: 10px;
            }
        </style>
        <script type="text/javascript" src="../static/js/crypto-js.min.js"></script>
        <script type="text/javascript" src="../static/js/jquery.min.js"></script>
        <meta name="referrer" content="never">
        <meta name="referrer" content="no-referrer">

        <div class="single-post">
            <section class="container">
                <div class="content-wrap">
                    <div class="content">
                        <div class="sptitle"><h1> </h1></div>
                        <div id="bof" class = "cf-157586882">
                        </div>
                        <!-- 添加视频标题 -->
                    <div class="video-title">${base64Decode(mvName)}</div>
                        <div class="am-cf"></div>
                        <div class="am-panel am-panel-default">
                            <div class="am-panel-bd" style="padding-top: 10px;">

                                <div class="bofangdiv" id="dplayer"></div>

                                <script type="text/javascript">
                                    const dp = new DPlayer({ 
                                        container: document.getElementById('dplayer'), 
                                        screenshot: true,
                                        video: {
                                            quality: [
                                                ${qualityList}
                                            ],
                                                defaultQuality: 0,
                                        }
                                    });
                                    function xldata(urls){
                                        var videourls = document.getElementById('video');
                                        var xlqieh = document.getElementById('videourlgo');
                                        videourls.src = urls+xlqieh.href;
                                    }
                                </script>
                                
                                <div class="article-tags">
                                    <i class="fa fa-tags"></i>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </section>
        </div>
        </body>
        </html>
        `
                                            // 替换当前页面的内容
                                            tempPage.document.open();
                                            tempPage.document.write(playhtml);
                                            tempPage.document.close();

                                        } else if (responseDataVideo.message == "2") {
                                            GM_setValue("YTToken", "");
                                            GM_setValue('username', "");
                                            GM_setValue('password', "");
                                            var result = confirm("该账户已过期,请您重新购买或者取号!点击“确定”按钮自动跳转至购买界面!");
                                            if (result) {
                                                window.location.href = "http://gv1069.vip/#/shop-account";
                                            }

                                        } else if (responseDataVideo.message == "3") {
                                            GM_setValue("YTToken", "");
                                            GM_setValue('username', "");
                                            GM_setValue('password', "");
                                            var result = confirm("请您重新登录!点击“确定”按钮自动弹出登录输入框!");
                                            if (result) {
                                                window.location.reload();
                                            }
                                        } else if (responseDataVideo.message == "4" || responseDataVideo.message == "5") {
                                            GM_setValue("YTToken", "");
                                            GM_setValue('username', "");
                                            GM_setValue('password', "");
                                            var result = confirm("请您重新登录!点击“确定”按钮自动弹出登录输入框!");
                                            if (result) {
                                                window.location.reload();
                                            }

                                        } else if (responseDataVideo.message == "6") {
                                            GM_setValue("YTToken", "");
                                            GM_setValue('username', "");
                                            GM_setValue('password', "");
                                            var result = confirm("您的账号在另一台设备上登录,请重新登录");
                                            if (result) {
                                                window.location.reload();
                                            }
                                        } else {
                                            showToast('解析失败,请点击播放按钮重试!')
                                        }
                                    }
                                })
                            }
                        })
                            
                        }); 

                    
                });
            });
        }
        function sectionm3u8menu(m3u8url) {
            let $section = document.createElement('section');
            $section.setAttribute('id', 'down-my-section');
            $section.innerHTML = `
   
    <style>
    /*全局设置*/
    html, body {
      margin: 0;
      padding: 0;
    }
    body::-webkit-scrollbar { display: none}
    p {
      margin: 0;
    }
    [v-cloak] {
      display: none;
    }
    #m-app {
      height: 100%;
      display: inherit;
      width: 100%;
      text-align: center;
      padding: 10px 50px 80px;
      box-sizing: border-box;
    }
    .m-p-action {
      margin: 20px auto;
      max-width: 1100px;
      width: 100%;
      font-size: 35px;
      text-align: center;
      font-weight: bold;
      display: block;
    }
    .m-p-other, .m-p-tamper, .m-p-github, .m-p-language, .m-p-mse{
      position: fixed;
      right: 50px;
      background-color: #eff3f6;
      background-image: linear-gradient(-180deg, #fafbfc, #eff3f6 90%);
      color: #24292e;
      border: 1px solid rgba(27, 31, 35, .2);
      border-radius: 3px;
      cursor: pointer;
      display: inline-block;
      font-size: 14px;
      font-weight: 600;
      line-height: 20px;
      padding: 6px 12px;
      z-index: 99;
    }
    
    .m-p-help {
      position: fixed;
      right: 50px;
      top: 50px;
      width: 30px;
      height: 30px;
      color: #666666;
      z-index: 2;
      line-height: 30px;
      font-weight: bolder;
      border-radius: 50%;
      border: 1px solid rgba(27, 31, 35, .2);
      cursor: pointer;
      background-color: #eff3f6;
      background-image: linear-gradient(-180deg, #fafbfc, #eff3f6 90%);
    }
    .m-p-github:hover, .m-p-other:hover, .m-p-tamper:hover, .m-p-help:hover, .m-p-language:hover, .m-p-mse:hover{
      opacity: 0.9;
    }
    .m-p-language {
      bottom: 70px;
    }
    .m-p-other {
      bottom: 150px;
    }
    .m-p-tamper {
      bottom: 30px;
    }
    .m-p-github {
      bottom: 190px;
    }
    .m-p-mse {
      bottom: 110px;
    }
    /*广告*/
    .m-p-refer {
      position: absolute;
      left: 50px;
      bottom: 50px;
    }
    .m-p-refer .text {
      position: absolute;
      top: -80px;
      left: -40px;
      animation-name: upAnimation;
      transform-origin: center bottom;
      animation-duration: 2s;
      animation-fill-mode: both;
      animation-iteration-count: infinite;
      animation-delay: .5s;
    }
    .m-p-refer .close {
      display: block;
      position: absolute;
      top: -110px;
      right: -50px;
      padding: 0;
      margin: 0;
      width: 50px;
      height: 50px;
      border-radius: 50%;
      border: none;
      cursor: pointer;
      z-index: 3;
      transition: 0.3s all;
      background-size: 30px 30px;
      background-repeat: no-repeat;
      background-position: center center;
      background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAMAAABg3Am1AAAAk1BMVEUAAAD////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////ROyVeAAAAMHRSTlMA1Sq7gPribxkJx6Ey8onMsq+GTe10QF8kqJl5WEcvIBDc0sHAkkk1FgO2ZZ+dj1FHfPqwAAACNElEQVRIx6VW6ZqqMAwtFlEW2Rm3EXEfdZa+/9PdBEvbIVXu9835oW1yjiQlTWQE/iYPuTObOTzMNz4bQFRlY2FgnFXRC/o01mytiafP+BPvQZk56bcLSOXem1jpCy4QgXvRtlEVCARfUP65RM/hp29/+0R7eSbhoHlnffZ8h76e6x1tyw9mxXaJ3nfTVLd89hQr9NfGceJxfLIXmONh6eNNYftNSESRmgkHlEOjmhgBbYcEW08FFQN/ro6dvAczjhgXEdQP76xHEYxM+igQq259gLrCSlwbD3iDtTMy+A4Yuk0B6zV8c+BcO2OgFIp/UvJdG4o/Rp1JQYXeZFflPEFMfvugiFGFXN587YtgX7C8lRGFXPCGGYCCzlkoxJ4xqmi/jrIcdYYh5pwxiwI/gt7lDDFrcLiMKhBJ//W78ENsJgVUsV8wKpjZBXshM6cCW0jbRAilICFxIpgGMmmiWGHSIR6ViY+DPFaqSJCbQ5mbxoZLIlU0Al/cBj6N1uXfFI0okLppi69StmumSFQRP6oIKDedFi3vRDn3j6KozCZlu0DdJb3AupJXNLmqkk9+X9FEHLt1Jq8oi1H5n01AtRlvwQZQl9hmtPY4JEjMDs5ftWJN4Xr4lLrV2OHiUDHCPgvA/Tn/hP4zGUBfjZ3eLJ+NIOfHxi8CMoAQtYfmw93v01O0e7VlqqcCsXML3Vsu94cxnb4c7ML5chG8JIP9b38dENGaj3+x+TpiA/AL/fen8In7H8l3ZjdJQt2TAAAAAElFTkSuQmCC);
      background-color: rgba(0, 0, 0, 0.5);
    }
    .m-p-refer .close:hover {
      background-color: rgba(0, 0, 0, 0.8);
    }
    .m-p-refer .link {
      border-radius: 4px;
      text-decoration: none;
      background-color: #4E84E6;
      transition: 0.3s all;
    }
    .m-p-refer .link:hover {
      top: -10px;
      color: #333333;
      border: 1px solid transparent;
      background: rgba(0, 0, 0, 0.6);
      box-shadow: 2px 11px 20px 0 rgba(0, 0, 0, 0.6);
    }
    @keyframes upAnimation {
      0% {
        transform: rotate(0deg);
        transition-timing-function: cubic-bezier(0.215, .61, .355, 1)
      }
   
      10% {
        transform: rotate(-12deg);
        transition-timing-function: cubic-bezier(0.215, .61, .355, 1)
      }
   
      20% {
        transform: rotate(12deg);
        transition-timing-function: cubic-bezier(0.215, .61, .355, 1)
      }
   
      28% {
        transform: rotate(-10deg);
        transition-timing-function: cubic-bezier(0.215, .61, .355, 1)
      }
   
      36% {
        transform: rotate(10deg);
        transition-timing-function: cubic-bezier(0.755, .5, .855, .06)
      }
   
      42% {
        transform: rotate(-8deg);
        transition-timing-function: cubic-bezier(0.755, .5, .855, .06)
      }
   
      48% {
        transform: rotate(8deg);
        transition-timing-function: cubic-bezier(0.755, .5, .855, .06)
      }
   
      52% {
        transform: rotate(-4deg);
        transition-timing-function: cubic-bezier(0.755, .5, .855, .06)
      }
   
      56% {
        transform: rotate(4deg);
        transition-timing-function: cubic-bezier(0.755, .5, .855, .06)
      }
   
      60% {
        transform: rotate(0deg);
        transition-timing-function: cubic-bezier(0.755, .5, .855, .06)
      }
   
      100% {
        transform: rotate(0deg);
        transition-timing-function: cubic-bezier(0.215, .61, .355, 1)
      }
    }
    /*顶部信息录入*/
    .m-p-temp-url {
      padding-top: 10px;
      padding-bottom: 10px;
      width: 100%;
      color: #999999;
      text-align: left;
      font-style: italic;
      word-break: break-all;
  font-size: 12px;
    }
   
    }
    .m-p-input-container input {
      flex: 1;
      margin-bottom: 20px;
      display: block;
      width: 380px;
      padding: 14px;
      font-size: 24px;
      border-radius: 4px;
      box-shadow: none;
      color: #444444;
      border: 1px solid #cccccc;
      min-width: 400px;
    }
    .m-p-input-container .range-input {
      margin-left: 10px;
  margin-bottom: 0;
      width: 100px;
      box-sizing: border-box;
    }
    .m-p-input-container div {
      position: relative;
      display: inline-block;
      margin-left: 10px;
      height: 40px;
      font-size:14px;
      color: white;
      cursor: pointer;
      border-radius: 4px;
      border: 1px solid #eeeeee;
      background-color: #3D8AC7;
      opacity: 1;
      transition: 0.3s all;
    }
    .m-p-input-container div:hover {
      opacity: 0.9;
    }
    .m-p-input-container div {
      width: 200px;
    }
    .m-p-input-container .disable {
      cursor: not-allowed;
      background-color: #dddddd;
    }
    /*下载状态*/
    .m-p-line {
      margin: 20px 0 50px;
      vertical-align: top;
      width: 100%;
      height: 5px;
      border-bottom: dotted;
    }
    .m-p-tips {
      width: 100%;
      color: #999999;
      text-align: left;
      font-style: italic;
      word-break: break-all;
    }
    .m-p-tips p {
      width: 100px;
      display: inline-block;
    }
    .m-p-tips.error-tips{
      color: #DC5350;
    }
    .m-p-segment {
      text-align: left;
    }
    .m-p-segment .item {
      display: inline-block;
      margin: 10px 6px;
      width: 50px;
      height: 40px;
      color: white;
      line-height: 40px;
      text-align: center;
      border-radius: 4px;
      cursor: help;
      border: solid 1px #eeeeee;
      background-color: #dddddd;
      transition: 0.3s all;
    }
    .m-p-segment .finish {
      background-color: #0ACD76;
    }
    .m-p-segment .error {
      cursor: pointer;
      background-color: #DC5350;
    }
    .m-p-segment .error:hover {
      opacity: 0.9;
    }
    .m-p-stream, .m-p-report, .m-p-cross, .m-p-final {
      margin-top: 10px;
      display: inline-block;
      width: 100%;
      height: 30px;
      line-height: 30px;
      font-size: 15px;
      color: white;
      cursor: pointer;
      border-radius: 4px;
      border: 1px solid #eeeeee;
      background-color: #3D8AC7;
      opacity: 1;
      transition: 0.3s all;
    }
    .m-p-stream {
      background-color: #0ACD76 !important;
    }
    .m-p-report {
      background-color: #e74c3c !important;
      text-decoration: none;
    }
    .m-p-final {
      text-decoration: none;
    }
    .m-p-force, .m-p-retry {
      position: absolute;
      right: 50px;
      display: inline-block;
      padding: 6px 12px;
      font-size: 18px;
      color: white;
      cursor: pointer;
      border-radius: 4px;
      border: 1px solid #eeeeee;
      background-color: #3D8AC7;
      opacity: 1;
      transition: 0.3s all;
    }
    .m-p-retry {
      right: 250px;
    }
    .m-p-force:hover, .m-p-retry:hover {
      opacity: 0.9;
    }
            .m-p-input-container {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    padding: 10px;
    box-sizing: border-box;
  }
   
  .m-p-input-container input {
    width: 100%;
    margin-bottom: 10px;
    padding: 12px 10px;
    font-size: 14px;
    border: none;
    border-radius: 4px;
    box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.3);
    box-sizing: border-box;
  }
   
  .m-p-input-container div {
    width: 100%;
    margin-bottom: 10px;
    padding: 10px;
    font-size: 14px;
    color: white;
    background-color: #136fbe;
    text-align: center;
    border-radius: 5px;
    cursor: pointer;
    box-sizing: border-box;
  }
   
  @media screen and (min-width: 768px) {
    .m-p-input-container {
      flex-direction: row;
      justify-content: space-around;
      padding: 20px;
    }
   
    .m-p-input-container input[type="text"] {
      width: calc(65% - 10px);
      margin-bottom: 0;
      margin-right: 10px;
    }
   
    .m-p-input-container div {
      width: calc(20% - 5px);
      margin-bottom: 0;
    }
  }
   
  .close-gobutton {
      position: absolute;
      top: 10px;
      right: 10px;
      background-color: #858585;
      color: #fff;
      border-radius: 50%;
      border: none;
      width: 30px;
      height: 30px;
      cursor: pointer;
      font-size: 20px;
  }
    </style>
   
   
  <div id="m-loading"> 
   
  </div>
  <section id="m-app" v-cloak>
    <!--顶部操作提示-->
    <section class="m-p-action g-box">{{tips}}</section>
   
   
  <button class="close-gobutton">X</button>
   
   
    <!--文件载入-->
    <section class="m-p-input-container">
      <input id="mym3u8val" type="text" v-model="url" :disabled="downloading" placeholder="请输入 m3u8或MP4 链接">
   
      <!--范围查询-->
      <template v-if="!downloading || rangeDownload.isShowRange">
        <div v-if="!rangeDownload.isShowRange" @click="getM3U8(true)">解析下载</div>
        <template v-else>
          <input class="range-input" type="number" v-model="rangeDownload.startSegment" :disabled="downloading" placeholder="起始片段">
          <input class="range-input" type="number" v-model="rangeDownload.endSegment" :disabled="downloading" placeholder="截止片段">
        </template>
      </template>
   
      <!--还未开始下载-->
      <template v-if="!downloading">
        <div @click="getM3U8(false)">原格式下载</div>
        <div @click="getMP4">MP4下载</div>
         <div @click="getPlay">在线播放</div>
      </template>
      <div v-else-if="finishNum === rangeDownload.targetSegment && rangeDownload.targetSegment > 0" class="disable">下载完成</div>
      <div v-else @click="togglePause">{{ isPause ? '恢复下载' : '暂停下载' }}</div>
    </section>
    
   
   
    <template v-if="finishList.length > 0">
      <div class="m-p-line"></div>
      <!-- <div class="m-p-retry" v-if="errorNum && downloadIndex >= rangeDownload.targetSegment" @click="retryAll">重新下载错误片段</div> -->
      <div class="m-p-force" v-if="mediaFileList.length && !streamWriter" @click="forceDownload">强制下载现有片段</div>
      <div class="m-p-tips">待下载碎片总量:{{ rangeDownload.targetSegment }},已下载:{{ finishNum }},错误:{{ errorNum }},进度:{{ (finishNum / rangeDownload.targetSegment * 100).toFixed(2) }}%</div>
      <div class="m-p-tips" :class="[errorNum ? 'error-tips' : '']">若某视频碎片下载发生错误,将标记为红色,可点击相应图标进行重试</div>
      <section class="m-p-segment">
        <div class="item" v-for="(item, index) in finishList" :class="[item.status]" :title="item.title" @click="retry(index)">{{ index + 1 }}</div>
      </section>
    </template>
  </section>
   
   
  `
            $section.style.width = '80%';
            $section.style.height = '80%';
            $section.style.display = 'block';
            $section.style.maxWidth = '900px';
            $section.style.top = '50%';
            $section.style.left = '50%';
            $section.style.position = 'fixed';
            $section.style.zIndex = '999999999991';
            $section.style.backgroundColor = 'white';
            $section.style.transform = 'translate(-50%, -50%)';
            $section.style.borderRadius = '10px';
            $section.style.boxShadow = '0px 0px 20px rgba(0, 0, 0, 0.5)';
            $section.style.overflow = 'auto';
 
            document.body.appendChild($section);
 
 
            //toastr.error('该网站限制了资源加载,已复制该视频链接。请在其他网站页面打开m3u8视频下载菜单进行下载', '', { positionClass: 'toast-top-center', showDuration: 300, hideDuration: 1000, timeOut: 3000, extendedTimeOut: 1000, showEasing: 'swing', hideEasing: 'linear', showMethod: 'fadeIn', hideMethod: 'fadeOut' });
 
 
            var app = new Vue({
                el: '#m-app',
 
                data() {
                    return {
                        url: m3u8url, // 在线链接
                        tips: '日租号套餐用户下载视频VIP通道', // 顶部提示 
                        title: '', // 视频标题
                        isPause: false, // 是否暂停下载
                        isGetMP4: false, // 是否转码为 MP4 下载
                        durationSecond: 0, // 视频持续时长
                        isShowRefer: false, // 是否显示推送
                        downloading: false, // 是否下载中
                        beginTime: '', // 开始下载的时间
                        errorNum: 0, // 错误数
                        finishNum: 0, // 已下载数
                        downloadIndex: 0, // 当前下载片段
                        finishList: [], // 下载完成项目
                        tsUrlList: [], // ts URL数组
                        mediaFileList: [], // 下载的媒体数组
                        isSupperStreamWrite: window.streamSaver && !window.streamSaver.useBlobFallback, // 当前浏览器是否支持流式下载
                        streamWriter: null, // 文件流写入器
                        streamDownloadIndex: 0, // 文件流写入器,正准备写入第几个视频片段
                        rangeDownload: { // 特定范围下载
                            isShowRange: false, // 是否显示范围下载
                            startSegment: '', // 起始片段
                            endSegment: '', // 截止片段
                            targetSegment: 1, // 待下载片段
                        },
                        aesConf: { // AES 视频解密配置
                            method: '', // 加密算法
                            uri: '', // key 所在文件路径
                            iv: '', // 偏移值
                            key: '', // 秘钥
                            decryptor: null, // 解码器对象
 
                            stringToBuffer: function (str) {
                                return new TextEncoder().encode(str)
                            },
                        },
                    }
                },
 
                created() {
                    this.getSource();
                    window.addEventListener('keyup', this.onKeyup)
                    setInterval(this.retryAll.bind(this), 2000) // 每两秒重新下载一遍错误片段,实现错误自动重试
                },
 
                beforeDestroy() {
                    window.removeEventListener('keyup', this.onKeyup)
                },
 
                methods: {
                    // 获取链接中携带的资源链接
                    getSource() {
                        let { href } = location
                        if (href.indexOf('?source=') > -1) {
                            this.url = href.split('?source=')[1]
                        }
                    },
 
                    // 获取顶部 window title,因可能存在跨域问题,故使用 try catch 进行保护
                    getDocumentTitle() {
                        let title = document.title;
                        try {
                            title = window.top.document.title
                        } catch (error) {
                            console.log(error)
                        }
                        return title
                    },
 
                    // 退出弹窗
                    onKeyup(event) {
                        var inputBox = document.querySelector('#mym3u8val');
                        if (inputBox && inputBox.style.display !== 'none' && event.keyCode === 13) {
                            this.getM3U8();
                        }
                    },
 
                    // ajax 请求
                    ajax(options) {
                        options = options || {};
                        let xhr = new XMLHttpRequest();
                        if (options.type === 'file') {
                            xhr.responseType = 'arraybuffer';
                        }
 
                        xhr.onreadystatechange = function () {
                            if (xhr.readyState === 4) {
                                let status = xhr.status;
                                if (status >= 200 && status < 300) {
                                    options.success && options.success(xhr.response);
                                } else {
                                    options.fail && options.fail(status);
                                }
                            }
                        };
 
                        xhr.open("GET", options.url, true);
                        xhr.send(null);
                    },
 
                    // 合成URL
                    applyURL(targetURL, baseURL) {
                        baseURL = baseURL || location.href
                        if (targetURL.indexOf('http') === 0) {
                            // 当前页面使用 https 协议时,强制使 ts 资源也使用 https 协议获取
                            if (location.href.indexOf('https') === 0) {
                                return targetURL.replace('http://', 'https://')
                            }
                            return targetURL
                        } else if (targetURL[0] === '/') {
                            let domain = baseURL.split('/')
                            return domain[0] + '//' + domain[2] + targetURL
                        } else {
                            let domain = baseURL.split('/')
                            domain.pop()
                            return domain.join('/') + '/' + targetURL
                        }
                    },
 
                    // 使用流式下载,边下载边保存,解决大视频文件内存不足的难题 
                    streamDownload(isMp4) {
                        var url = this.url;
                        if (url == "") {
                            toastr.error("请先输入 m3u8 链接才能解析下载", '', { positionClass: 'toast-top-center', showDuration: 300, hideDuration: 1000, timeOut: 3000, extendedTimeOut: 1000, showEasing: 'swing', hideEasing: 'linear', showMethod: 'fadeIn', hideMethod: 'fadeOut' });
                            return
                        }
                        if (url.toLowerCase().indexOf('m3u8') === -1) {
                            alert('链接有误,请重新输入,必须是以.m3u8结尾的链接')
                            return
                        }
                        this.isGetMP4 = isMp4
                        this.title = new URL(this.url).searchParams.get('title') || this.title // 获取视频标题
                        let fileName = this.title || this.formatTime(new Date(), 'YYYY_MM_DD hh_mm_ss')
                        if (document.title !== 'm3u8 downloader') {
                            fileName = this.getDocumentTitle()
                        }
                        this.streamWriter = window.streamSaver.createWriteStream(`${fileName}.${isMp4 ? 'mp4' : 'ts'}`).getWriter()
                        this.getM3U8()
                    },
 
                    // 解析为 mp4 下载
                    getMP4() {
                        this.isGetMP4 = true;
 
                        this.getM3U8();
 
                    },
                    getPlay() {
                        if (this.url == "") {
                            toastr.error("请先输入 m3u8 链接才能解析播放", '', { positionClass: 'toast-top-center', showDuration: 300, hideDuration: 1000, timeOut: 3000, extendedTimeOut: 1000, showEasing: 'swing', hideEasing: 'linear', showMethod: 'fadeIn', hideMethod: 'fadeOut' });
                            return
                        }
 
                        Playm3u8(this.url);
                    },
                    // 获取在线文件
                    getM3U8(onlyGetRange) {
                        if (!this.url) {
                            alert('请输入链接')
                            return
                        }
                        if (this.url.toLowerCase().indexOf('.mp4') > 0) {
                            var mp4url = this.url;
                            toastr.success('正在后台下载,请稍后。', '', { positionClass: 'toast-bottom-right', showDuration: 300, hideDuration: 1000, timeOut: 3000, extendedTimeOut: 1000, showEasing: 'swing', hideEasing: 'linear', showMethod: 'fadeIn', hideMethod: 'fadeOut' });
                            GM_download({
                                url: mp4url,
                                name: getFileNameFromUrl(mp4url),
                                saveAs: false,
                                onload: function () {
                                    toastr.success('下载完成', '', { positionClass: 'toast-bottom-right', showDuration: 300, hideDuration: 1000, timeOut: 3000, extendedTimeOut: 1000, showEasing: 'swing', hideEasing: 'linear', showMethod: 'fadeIn', hideMethod: 'fadeOut' });
 
                                },
                                onerror: function (err) {
                                    console.error('下载失败' + err, err);
                                }
                            });
                            return
                        }
                        if (this.url.toLowerCase().indexOf('m3u8') === -1) {
                            alert('链接有误,请重新输入')
                            return
                        }
                        if (this.downloading) {
                            alert('资源下载中,请稍后')
                            return
                        }
 
                        // 在下载页面才触发,代码注入的页面不需要校验
                        // 当前协议不一致,切换协议
                        if (location.href.indexOf('blog.luckly-mjw.cn') > -1 && this.url.indexOf(location.protocol) === -1) {
                            //alert('当前协议不一致,跳转至正确页面重新下载')
                            location.href = `${this.url.split(':')[0]}://blog.luckly-mjw.cn/tool-show/m3u8-downloader/index.html?source=${this.url}`
                            return
                        }
 
                        // 在下载页面才触发,修改页面 URL,携带下载路径,避免刷新后丢失
                        if (location.href.indexOf('blog.luckly-mjw.cn') > -1) {
                            window.history.replaceState(null, '', `${location.href.split('?')[0]}?source=${this.url}`)
                        }
 
                        this.title = new URL(this.url).searchParams.get('title') || this.title // 获取视频标题
                        this.tips = 'm3u8 文件下载中,请稍后'
                        this.beginTime = new Date()
                        this.ajax({
                            url: this.url,
                            success: (m3u8Str) => {
                                this.tsUrlList = []
                                this.finishList = []
 
                                // 提取 ts 视频片段地址
                                m3u8Str.split('\n').forEach((item) => {
                                    // if (/.(png|image|ts|jpg|mp4|jpeg)/.test(item)) {
                                    // 放开片段后缀限制,下载非 # 开头的链接片段
                                    if (/^[^#]/.test(item)) {
                                        console.log(item)
                                        this.tsUrlList.push(this.applyURL(item, this.url))
                                        this.finishList.push({
                                            title: item,
                                            status: ''
                                        })
                                    }
                                })
 
                                // 仅获取视频片段数
                                if (onlyGetRange) {
                                    this.rangeDownload.isShowRange = true
                                    this.rangeDownload.endSegment = this.tsUrlList.length
                                    this.rangeDownload.targetSegment = this.tsUrlList.length
                                    return
                                } else {
                                    let startSegment = Math.max(this.rangeDownload.startSegment || 1, 1) // 最小为 1
                                    let endSegment = Math.max(this.rangeDownload.endSegment || this.tsUrlList.length, 1)
                                    startSegment = Math.min(startSegment, this.tsUrlList.length) // 最大为 this.tsUrlList.length
                                    endSegment = Math.min(endSegment, this.tsUrlList.length)
                                    this.rangeDownload.startSegment = Math.min(startSegment, endSegment)
                                    this.rangeDownload.endSegment = Math.max(startSegment, endSegment)
                                    this.rangeDownload.targetSegment = this.rangeDownload.endSegment - this.rangeDownload.startSegment + 1
                                    this.downloadIndex = this.rangeDownload.startSegment - 1
                                    this.downloading = true
                                }
 
                                // 获取需要下载的 MP4 视频长度
                                if (this.isGetMP4) {
                                    let infoIndex = 0
                                    m3u8Str.split('\n').forEach(item => {
                                        if (item.toUpperCase().indexOf('#EXTINF:') > -1) { // 计算视频总时长,设置 mp4 信息时使用
                                            infoIndex++
                                            if (this.rangeDownload.startSegment <= infoIndex && infoIndex <= this.rangeDownload.endSegment) {
                                                this.durationSecond += parseFloat(item.split('#EXTINF:')[1])
                                            }
                                        }
                                    })
                                }
 
                                // 检测视频 AES 加密
                                if (m3u8Str.indexOf('#EXT-X-KEY') > -1) {
                                    this.aesConf.method = (m3u8Str.match(/(.*METHOD=([^,\s]+))/) || ['', '', ''])[2]
                                    this.aesConf.uri = (m3u8Str.match(/(.*URI="([^"]+))"/) || ['', '', ''])[2]
                                    this.aesConf.iv = (m3u8Str.match(/(.*IV=([^,\s]+))/) || ['', '', ''])[2]
                                    this.aesConf.iv = this.aesConf.iv ? this.aesConf.stringToBuffer(this.aesConf.iv) : ''
                                    this.aesConf.uri = this.applyURL(this.aesConf.uri, this.url)
 
                                    // let params = m3u8Str.match(/#EXT-X-KEY:([^,]*,?METHOD=([^,]+))?([^,]*,?URI="([^,]+)")?([^,]*,?IV=([^,^\n]+))?/)
                                    // this.aesConf.method = params[2]
                                    // this.aesConf.uri = this.applyURL(params[4], this.url)
                                    // this.aesConf.iv = params[6] ? this.aesConf.stringToBuffer(params[6]) : ''
                                    this.getAES();
                                } else if (this.tsUrlList.length > 0) { // 如果视频没加密,则直接下载片段,否则先下载秘钥
                                    this.downloadTS()
                                } else {
                                    this.alertError('资源为空,请查看链接是否有效')
                                }
                            },
                            fail: () => {
                                this.alertError('链接不正确,请查看链接是否有效')
                            }
                        })
                    },
 
                    // 获取AES配置
                    getAES() {
                        // alert('视频被 AES 加密,点击确认,进行视频解码')
                        this.ajax({
                            type: 'file',
                            url: this.aesConf.uri,
                            success: (key) => {
                                // console.log('getAES', key)
                                // this.aesConf.key = this.aesConf.stringToBuffer(key)
                                this.aesConf.key = key
                                this.aesConf.decryptor = new AESDecryptor()
                                this.aesConf.decryptor.constructor()
                                this.aesConf.decryptor.expandKey(this.aesConf.key);
                                this.downloadTS()
                            },
                            fail: () => {
                                this.alertError('视频已加密,可试用右下角入口的「无差别提取工具」')
                            }
                        })
                    },
 
                    // ts 片段的 AES 解码
                    aesDecrypt(data, index) {
                        let iv = this.aesConf.iv || new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, index])
                        return this.aesConf.decryptor.decrypt(data, 0, iv.buffer || iv, true)
                    },
 
                    // 下载分片
                    downloadTS() {
                        this.tips = 'ts 视频碎片下载中,请稍后'
                        let download = () => {
                            let isPause = this.isPause // 使用另一个变量来保持下载前的暂停状态,避免回调后没修改
                            let index = this.downloadIndex
                            if (index >= this.rangeDownload.endSegment) {
                                return
                            }
                            this.downloadIndex++
                            if (this.finishList[index] && this.finishList[index].status === '') {
                                this.finishList[index].status = 'downloading'
                                this.ajax({
                                    url: this.tsUrlList[index],
                                    type: 'file',
                                    success: (file) => {
                                        this.dealTS(file, index, () => this.downloadIndex < this.rangeDownload.endSegment && !isPause && download())
                                    },
                                    fail: () => {
                                        this.errorNum++
                                        this.finishList[index].status = 'error'
                                        if (this.downloadIndex < this.rangeDownload.endSegment) {
                                            !isPause && download()
                                        }
                                    }
                                })
                            } else if (this.downloadIndex < this.rangeDownload.endSegment) { // 跳过已经成功的片段
                                !isPause && download()
                            }
                        }
 
                        // 建立多少个 ajax 线程
                        for (let i = 0; i < Math.min(6, this.rangeDownload.targetSegment - this.finishNum); i++) {
                            download()
                        }
                    },
 
                    // 处理 ts 片段,AES 解密、mp4 转码
                    dealTS(file, index, callback) {
                        const data = this.aesConf.uri ? this.aesDecrypt(file, index) : file
                        this.conversionMp4(data, index, (afterData) => { // mp4 转码
                            this.mediaFileList[index - this.rangeDownload.startSegment + 1] = afterData // 判断文件是否需要解密
                            this.finishList[index].status = 'finish'
                            this.finishNum++
                            if (this.streamWriter) {
                                for (let index = this.streamDownloadIndex; index < this.mediaFileList.length; index++) {
                                    if (this.mediaFileList[index]) {
                                        this.streamWriter.write(new Uint8Array(this.mediaFileList[index]))
                                        this.mediaFileList[index] = null
                                        this.streamDownloadIndex = index + 1
                                    } else {
                                        break
                                    }
                                }
                                if (this.streamDownloadIndex >= this.rangeDownload.targetSegment) {
                                    this.streamWriter.close()
                                }
                            } else if (this.finishNum === this.rangeDownload.targetSegment) {
                                let fileName = this.title || this.formatTime(this.beginTime, 'YYYY_MM_DD hh_mm_ss')
                                if (document.title !== 'm3u8 downloader') {
                                    fileName = this.getDocumentTitle()
                                }
                                this.downloadFile(this.mediaFileList, fileName)
                            }
                            callback && callback()
                        })
                    },
 
                    // 转码为 mp4
                    conversionMp4(data, index, callback) {
                        if (this.isGetMP4) {
                            let transmuxer = new muxjs.Transmuxer({
                                keepOriginalTimestamps: true,
                                duration: parseInt(this.durationSecond),
                            });
                            transmuxer.on('data', segment => {
                                if (index === this.rangeDownload.startSegment - 1) {
                                    let data = new Uint8Array(segment.initSegment.byteLength + segment.data.byteLength);
                                    data.set(segment.initSegment, 0);
                                    data.set(segment.data, segment.initSegment.byteLength);
                                    callback(data.buffer)
                                } else {
                                    callback(segment.data)
                                }
                            })
                            transmuxer.push(new Uint8Array(data));
                            transmuxer.flush();
                        } else {
                            callback(data)
                        }
                    },
 
                    // 暂停与恢复
                    togglePause() {
                        this.isPause = !this.isPause
                        !this.isPause && this.retryAll(true)
                    },
 
                    // 重新下载某个片段
                    retry(index) {
                        if (this.finishList[index].status === 'error') {
                            this.finishList[index].status = ''
                            this.ajax({
                                url: this.tsUrlList[index],
                                type: 'file',
                                success: (file) => {
                                    this.errorNum--
                                    this.dealTS(file, index)
                                },
                                fail: () => {
                                    this.finishList[index].status = 'error'
                                }
                            })
                        }
                    },
 
                    // 重新下载所有错误片段
                    retryAll(forceRestart) {
 
                        if (!this.finishList.length || this.isPause) {
                            return
                        }
 
                        let firstErrorIndex = this.downloadIndex // 没有错误项目,则每次都递增
                        this.finishList.forEach((item, index) => { // 重置所有错误片段状态
                            if (item.status === 'error') {
                                item.status = ''
                                firstErrorIndex = Math.min(firstErrorIndex, index)
                            }
                        })
                        this.errorNum = 0
                        // 已经全部下载进程都跑完了,则重新启动下载进程
                        if (this.downloadIndex >= this.rangeDownload.endSegment || forceRestart) {
                            this.downloadIndex = firstErrorIndex
                            this.downloadTS()
                        } else { // 否则只是将下载索引,改为最近一个错误的项目,从那里开始遍历
                            this.downloadIndex = firstErrorIndex
                        }
                    },
 
                    // 下载整合后的TS文件
                    downloadFile(fileDataList, fileName) {
                        this.tips = 'ts 碎片整合中,请留意浏览器下载'
                        let fileBlob = null
                        let a = document.createElement('a')
                        if (this.isGetMP4) {
                            fileBlob = new Blob(fileDataList, { type: 'video/mp4' }) // 创建一个Blob对象,并设置文件的 MIME 类型
                            a.download = fileName + '.mp4'
                        } else {
                            fileBlob = new Blob(fileDataList, { type: 'video/MP2T' }) // 创建一个Blob对象,并设置文件的 MIME 类型
                            a.download = fileName + '.ts'
                        }
                        a.href = URL.createObjectURL(fileBlob)
                        a.style.display = 'none'
                        document.body.appendChild(a)
                        a.click()
                        a.remove()
                    },
 
                    // 格式化时间
                    formatTime(date, formatStr) {
                        const formatType = {
                            Y: date.getFullYear(),
                            M: date.getMonth() + 1,
                            D: date.getDate(),
                            h: date.getHours(),
                            m: date.getMinutes(),
                            s: date.getSeconds(),
                        }
                        return formatStr.replace(
                            /Y+|M+|D+|h+|m+|s+/g,
                            target => (new Array(target.length).join('0') + formatType[target[0]]).substr(-target.length)
                        )
                    },
 
                    // 强制下载现有片段
                    forceDownload() {
                        if (this.mediaFileList.length) {
                            let fileName = this.title || this.formatTime(this.beginTime, 'YYYY_MM_DD hh_mm_ss')
                            if (document.title !== 'm3u8 downloader') {
                                fileName = this.getDocumentTitle()
                            }
                            this.downloadFile(this.mediaFileList, fileName)
                        } else {
                            alert('当前无已下载片段')
                        }
                    },
 
                    // 发生错误,进行提示
                    alertError(tips) {
                        alert(tips)
                        this.downloading = false
                        this.tips = '日租号套餐用户下载视频VIP通道';
                    },
 
 
                }
            })
 
 
 
        }
        $("body").on('click', '.close-gobutton', function () {
            $("#down-my-section").remove();
        })
 
        function Playm3u8(url) {
            let videoFormat = url.split('.').pop().toLowerCase();
 
            // 判断视频格式是否是网络常见的在线视频格式
            let supportedFormats = ['mp4', 'm3u8', 'webm', 'ogg'];
            if (!supportedFormats.includes(videoFormat)) {
                toastr.error("不支持的视频格式", '', { positionClass: 'toast-top-center', showDuration: 300, hideDuration: 1000, timeOut: 3000, extendedTimeOut: 1000, showEasing: 'swing', hideEasing: 'linear', showMethod: 'fadeIn', hideMethod: 'fadeOut' });
                return;
            }
 
            $('<div id="floating-video-player"></div>').css({
                position: 'fixed',
                top: '50%',
                left: '50%',
                transform: 'translate(-50%, -50%)',
                width: '80%',
                height: '80%',
                zIndex: 999999999992,
                maxWidth: '800px',
                maxHeight: '600px',
                padding: 0
            }).append(
                $('<video></video>').attr({
                    width: '80%',
                    autoplay: 'autoplay',
                    controls: 'controls',
                    muted: 'muted'
                }).css({
                    position: 'absolute',
                    top: '50%',
                    left: '50%',
                    transform: 'translate(-50%, -50%)',
                    width: 'calc(100% - 2px)',
                    borderRadius: '5px',
                    boxShadow: '0 0 10px rgba(0, 0, 0, 0.3)',
                }).append(
                    $('<source></source>').attr({
                        src: url,
                        type: 'application/x-mpegURL'
                    })
                ),
                $('<button>X</button>').css({ // 关闭按钮
                    position: 'absolute',
                    top: '10px',
                    right: '60px',
                    border: 'none',
                    backgroundColor: '#757575',
                    color: '#ffffff',
                    fontSize: '16px',
                    fontWeight: 'bold',
                    cursor: 'pointer',
                    padding: '5px 10px',
                    borderRadius: '5px',
                    boxShadow: '0 0 5px rgba(0, 0, 0, 0.3)',
                    zIndex: 10000,
                    width: '40px',
                    height: '40px',
                }).click(function () {
                    $('#floating-video-player').hide();
                    $('body').css('overflow', 'auto');
                    $('#floating-video-player').remove();
                }),
                $('<div></div>').css({ // 倍速和画中画按钮容器
                    position: 'absolute',
                    top: '10px',
                    left: '10px',
                    display: 'flex',
                    alignItems: 'center',
                }).append(
                    $('<button>&lt;</button>').css({ // 倍速减少按钮
                        border: 'none',
                        backgroundColor: '#757575',
                        color: '#ffffff',
                        fontSize: '16px',
                        fontWeight: 'bold',
                        cursor: 'pointer',
                        padding: '5px 10px',
                        borderRadius: '5px',
                        boxShadow: '0 0 5px rgba(0, 0, 0, 0.3)',
                        width: '40px',
                        height: '40px',
                        marginRight: '10px',
                    }).click(function () {
                        video.playbackRate -= 0.25;
                        toastr.info("当前倍速:" + video.playbackRate.toFixed(2), '', { positionClass: 'toast-top-center', showDuration: 300, hideDuration: 1000, timeOut: 3000, extendedTimeOut: 1000, showEasing: 'swing', hideEasing: 'linear', showMethod: 'fadeIn', hideMethod: 'fadeOut' });
                    }),
                    $('<button>&gt;</button>').css({ // 倍速增加按钮
                        border: 'none',
                        backgroundColor: '#757575',
                        color: '#ffffff',
                        fontSize: '16px',
                        fontWeight: 'bold',
                        cursor: 'pointer',
                        padding: '5px 10px',
                        borderRadius: '5px',
                        boxShadow: '0 0 5px rgba(0, 0, 0, 0.3)',
                        width: '40px',
                        height: '40px',
                        marginRight: '10px',
                    }).click(function () {
                        video.playbackRate += 0.25;
                        toastr.info("当前倍速:" + video.playbackRate.toFixed(2), '', { positionClass: 'toast-top-center', showDuration: 300, hideDuration: 1000, timeOut: 3000, extendedTimeOut: 1000, showEasing: 'swing', hideEasing: 'linear', showMethod: 'fadeIn', hideMethod: 'fadeOut' });
                    }),
                    $('<button>&#9874; 画中画</button>').css({ // 画中画按钮
                        border: 'none',
                        backgroundColor: '#757575',
                        color: '#ffffff',
                        fontSize: '16px',
                        fontWeight: 'bold',
                        cursor: 'pointer',
                        padding: '5px 10px',
                        borderRadius: '5px',
                        boxShadow: '0 0 5px rgba(0, 0, 0, 0.3)',
                        width: '120px',
                        height: '40px',
                    }).click(function () {
                        if (video !== document.pictureInPictureElement) {
                            video.requestPictureInPicture();
                        } else {
                            document.exitPictureInPicture();
                        }
                    })
                )
            ).appendTo('body');
 
            // 播放器相关样式
            GM_addStyle('#floating-video-player video { display: block; }');
 
            // 监听页面中的链接,自动播放视频
            $(document).one('mousedown touchstart keydown', function () {
                // 取消静音并播放视频
                video.prop('muted', false)[0].play();
            });
 
            var videoContainer = $('#floating-video-player');
            var video = videoContainer.find('video')[0];
 
            // 根据视频格式选择播放器
            if (videoFormat === 'm3u8') {
                // 使用 HLS.js 播放 m3u8 格式的视频
                if (Hls.isSupported()) {
                    var hls = new Hls();
                    hls.loadSource(url);
                    hls.attachMedia(video);
                    hls.on(Hls.Events.MANIFEST_PARSED, function () {
                        video.play();
                        videoContainer.show();
                        $('body').css('overflow', 'hidden');
                    });
                } else {
                    toastr.error("浏览器不受支持", '', { positionClass: 'toast-top-center', showDuration: 300, hideDuration: 1000, timeOut: 3000, extendedTimeOut: 1000, showEasing: 'swing', hideEasing: 'linear', showMethod: 'fadeIn', hideMethod: 'fadeOut' });
                }
            } else if (videoFormat === 'mp4' && video.canPlayType && video.canPlayType('video/mp4')) {
                // 使用原生视频播放器播放 mp4 格式的视频
                video.setAttribute('src', url);
                video.play();
                videoContainer.show();
                $('body').css('overflow', 'hidden');
            }
        }
 
    });
 
 
})();