// 无限的 debugger 兼容性好 // setInterval(function () { // debuggerCheck(); // }, 1000); // var debuggerCheck = function () { // function doCheck(a) { // if (('' + a / a)['length'] !== 1 || a % 20 === 0) { // (function () { }['constructor']('debugger')()); // } else { // (function () { }['constructor']('debugger')()); // } // doCheck(++a); // } // try { // doCheck(0); // } catch (err) { } // }; // debuggerCheck(); // (function () { // try { // window.history.pushState(null, ''); // window.addEventListener( // 'popstate', // function () { // window.location.href = atob('aHR0cHM6Ly9zczQwLnNnY2l6dC5jb206MTA4My80MC8='); // }, // false // ); // } catch (err) { } // })(); function formatVideoUrl(strPinYin, intVId) { return strVideoUrlTemp .replace('{strPinYin}', encodeURIComponent(strPinYin)) .replace('{intVId}', intVId); } function formatVideoPlayUrl(strPinYin, intVId, strPlayType = 'defualt', intPlayIndex = 1) { return strVideoPlayUrlTemp .replace('{strPinYin}', encodeURIComponent(strPinYin)) .replace('{intVId}', intVId) .replace('{strPlayType}', strPlayType) .replace('{intPlayIndex}', intPlayIndex); } function formatSearchUrl(strKey, intPage = 1) { return strSearchUrlTemp .replace('{strSearchKeywords}', strKey) .replace('{intPage}', intPage); } /** * 获取当前页面的顶级域名 * @returns {string} - 顶级域名(如 'video.com', 'example.org'),若无法解析则返回空字符串 */ function getTopLevelDomain() { try { const hostname = window.location.hostname; // 获取完整域名,如 'sub.video.com' const parts = hostname.split('.'); // 按点号分割域名 // 返回最后两部分作为顶级域名(适用于大多数情况,如 'video.com') return parts.length >= 2 ? `${parts[parts.length - 2]}.${parts[parts.length - 1]}` : ''; } catch (error) { console.error('获取顶级域名失败:', error.message); return ''; } } function isMobile() { const ua = navigator.userAgent || navigator.vendor || window.opera; // 常见移动端关键词 const mobileRegex = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|Windows Phone/i; // 微信/QQ/支付宝内置浏览器也算移动端 const isMiniBrowser = /MicroMessenger|QQ\/|AlipayClient/i.test(ua); // 判断触控点(Touch device) const isTouchDevice = ('maxTouchPoints' in navigator && navigator.maxTouchPoints > 0) || ('ontouchstart' in window); return mobileRegex.test(ua) || isMiniBrowser || isTouchDevice; } // 懒加载 document.addEventListener("DOMContentLoaded", function () { // 通用懒加载函数 function lazyLoad(elements, callback) { const observer = new IntersectionObserver((entries, observer) => { entries.forEach(entry => { if (entry.isIntersecting) { const element = entry.target; callback(element); observer.unobserve(element); } }); }, { rootMargin: '100px' // 提前 100px 开始加载 }); elements.forEach(element => observer.observe(element)); } // 背景封面懒加载 const lazyBackgrounds = document.querySelectorAll(".lazyload-bg"); lazyLoad(lazyBackgrounds, (element) => { const src = element.getAttribute("data-src"); if (src) { const img = new Image(); img.src = src; img.onload = () => { element.style.backgroundImage = `url(${src})`; element.classList.remove("lazyload-bg"); }; img.onerror = () => { // console.error(`Failed to load background image: ${src}`); // 可选:设置默认背景或错误提示 }; } }); // 章节图片懒加载 const lazyImages = document.querySelectorAll(".lazyload-img"); lazyLoad(lazyImages, (element) => { const src = element.getAttribute("data-src"); if (src) { const img = new Image(); img.src = src; img.onload = () => { element.setAttribute("src", src); element.classList.remove("lazyload-img"); }; img.onerror = () => { // console.error(`Failed to load image: ${src}`); // 可选:设置占位图或错误提示 }; } }); }); function handleRedirect() { const { pathname, origin, search } = window.location; // 规范化路径名,将多个斜杠替换为单个斜杠 const normalizedPath = pathname.replace(/\/+/g, '/'); var strCurrentPath = normalizedPath || '/index.html'; const arrPcPathUrl = ['/pc', '/web', '/desktop', '/index', '/shouye', '/zhuomian', '/windows']; // 所有模板的 PC 目录 // 构建URL,确保斜杠正确 const buildUrl = (path) => { const cleanPath = `/${path.replace(/\/+/g, '/')}`.replace(/^\/+/, '/'); return `${origin}${cleanPath}${search}`; }; // 获取当前路径的第一个目录 var firstSegment = strCurrentPath.split('/')[1] || ''; // 判断当前路径的第一个目录是否在其它模板的 PC 目录中 const isInPcPathArray = arrPcPathUrl.some(pcPath => firstSegment.startsWith(pcPath.replace('/', ''))); if (isMobile()) { // 如果第一个目录 在pc 模板里面 则删除替换成空 if (isInPcPathArray) { const newPath = strCurrentPath.replace(firstSegment, ''); window.location.href = buildUrl(newPath); } } else { if (!isInPcPathArray) { const newPath = strCurrentPath === '/' ? `/` : `${strCurrentPath}`; window.location.href = buildUrl(newPath); } else { // 如果包含,则先判断是不是当前模板的 url,如果不是 则替换成当前模板的 url if (firstSegment != strPcPath.replace('/', '')) { strCurrentPath = strCurrentPath.replace(firstSegment, strPcPath.replace('/', '')); window.location.href = buildUrl(strCurrentPath); } } } } // handleRedirect(); function layerPopup(strContent, intTime) { layer.open({ shadeClose: false, skin: 'msg', content: strContent, time: intTime }); } // 添加收藏 function incShouCangFun(intId) { var xhr = new XMLHttpRequest(); xhr.open('GET', "/sc?intId=" + intId, true); xhr.setRequestHeader('accept', 'application/x.hubserver.admin+json'); xhr.send(); xhr.onreadystatechange = function () { if (xhr.readyState == 4 && xhr.status == 200) { layerPopup('收藏成功', 3) } if (xhr.readyState == 4 && xhr.status == 0) { layerPopup('操作太频繁,稍后再试', 3) } } } const strBookshelfKey = window.location.hostname + 'strBookshelfKey'; const strHistoryKey = window.location.hostname + 'strHistoryKey'; // 加入书架 function addBookshelfFun(NovelInfo) { if (!NovelInfo) { NovelInfo = arrNovel } let arrBookshelf = JSON.parse(localStorage.getItem(strBookshelfKey)) || []; // 检查书籍是否已存在 const index = arrBookshelf.findIndex(item => item.n_id === NovelInfo.n_id); if (index !== -1) { // 如果存在,更新该书籍的信息 arrBookshelf[index] = { ...arrBookshelf[index], ...NovelInfo }; layerPopup('已存在书架中!', 3) } else { // 如果不存在,添加到历史记录 arrBookshelf.push(NovelInfo); layerPopup('已成功加入书架!', 3) } // 更新本地存储 localStorage.setItem(strBookshelfKey, JSON.stringify(arrBookshelf)); } function displayShujia() { // 获取书架数据 const shujia = JSON.parse(localStorage.getItem(strBookshelfKey)) || []; if (shujia.length === 0) { console.log('书架为空'); return; } // 渲染书籍列表 const shujiaContainer = document.getElementById('shujiaContainer'); shujiaContainer.innerHTML = ''; // 清空原内容 shujia.forEach(book => { const bookElement = document.createElement('div'); let strNovelUrl = formatNovelUrl(book.n_name_pinyin, book.n_id) let strNovelChapterUrl = formatNovelChapterUrl(book.n_name_pinyin, book.n_id, book.c_sort_num) let strSearchUrl = formatSearchUrl(book.n_author, 1) if (isMobile()) { bookElement.innerHTML = `

${book.n_name}

作者: ${book.n_author}

${book.c_name}

`; } else { bookElement.innerHTML = `
${book.n_name}
${book.n_author} ${book.n_name}
${book.c_name}
`; } shujiaContainer.appendChild(bookElement); }); } // 加入阅读记录 function addHistoryFun(VideoInfo) { // 如果没有传入 VideoInfo arrVideo 并补充字段 if (!VideoInfo) { VideoInfo = arrVideo } // 获取本地存储中的历史记录 let arrHistory = JSON.parse(localStorage.getItem(strHistoryKey)) || []; // 检查书籍是否已存在 const index = arrHistory.findIndex(item => item.v_id == VideoInfo.v_id); if (index !== -1) { // 如果存在,更新该书籍的信息 arrHistory[index] = { ...arrHistory[index], ...VideoInfo }; } else { // 如果不存在,添加到历史记录 arrHistory.push(VideoInfo); } // 更新本地存储 localStorage.setItem(strHistoryKey, JSON.stringify(arrHistory)); } const defaultTemplate = `
  • {{videoRemarks}}

    {{videoName}}

    简介: {{videoDescription}}

    类型: {{videoCategory}}

    立即播放    查看详情

  • `; // 渲染历史记录函数,接受自定义模板参数 function displayHistory(template = defaultTemplate) { // 获取数据 const arrHistory = JSON.parse(localStorage.getItem(strHistoryKey)) || []; if (arrHistory.length === 0) { console.log('记录为空'); return; } // 渲染列表 const historyContainer = document.getElementById('historyContainer'); if (!historyContainer) { console.error('历史记录容器未找到'); return; } historyContainer.innerHTML = ''; // 清空原内容 arrHistory.forEach((video) => { // 生成URL const strVideoUrl = formatVideoUrl(video.v_name_en, video.v_id); const strVideoPlayUrl = formatVideoPlayUrl(video.v_name_en, video.v_id, 'default', 1); const strSearchUrl = formatSearchUrl(video.v_name, 1); // 替换模板中的占位符 const renderedTemplate = template .replace(/{{videoUrl}}/g, strVideoUrl) .replace(/{{videoName}}/g, escapeHtml(video.v_name)) // 防止XSS .replace(/{{videoPic}}/g, escapeHtml(video.v_pic)) .replace(/{{videoRemarks}}/g, escapeHtml(video.v_remarks)) .replace(/{{videoDescription}}/g, escapeHtml(video.v_description)) .replace(/{{videoCategory}}/g, escapeHtml(video.v_category)) .replace(/{{videoParentCategory}}/g, escapeHtml(video.v_parent_category)) .replace(/{{videoYear}}/g, escapeHtml(video.v_year)) .replace(/{{videoActor}}/g, escapeHtml(video.v_area)) .replace(/{{videoPlayUrl}}/g, strVideoPlayUrl) .replace(/{{searchUrl}}/g, strSearchUrl); // 创建元素并添加到容器 const videoElement = document.createElement('li'); videoElement.innerHTML = renderedTemplate; historyContainer.appendChild(videoElement); }); } // 防止XSS攻击的转义函数 function escapeHtml(str) { if (!str) return ''; return str.replace(/[&<>"']/g, (match) => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[match])); } async function reportStats(data) { try { const response = await fetch(strPushApi + '/publishv', { method: 'POST', // mode: 'no-cors', // 添加这行 headers: { 'Content-Type': 'application/json', // 如果需要认证可以添加 'Authorization': 'Bearer your-token' }, body: JSON.stringify(data) }); if (!response.ok) { throw new Error('上报失败'); } } catch (error) { console.error('上报错误:', error); } } function initDPlayer(strPlayUrl) { let DomDPlayer = document.getElementById('dplayer') videoPlayer = new DPlayer({ container: DomDPlayer, autoplay: true, screenshot: false, //logo: dplayerLogo, video: { url: strPlayUrl, type: 'hls', }, pluginOptions: { hls: { maxBufferLength: 600, }, }, }); videoPlayer.play() // 监听全屏进入事件 videoPlayer.on('fullscreen', function () { DomDPlayer.classList.add("dp-fullscreen"); // 设置视频元素的样式,取消 max-height document.querySelector("video").style.maxHeight = "none"; document.querySelector(".video-play-page .dplayer-video-wrap").style.maxHeight = "none"; }); // 监听全屏退出事件 videoPlayer.on('fullscreen_cancel', function () { DomDPlayer.classList.remove("dp-fullscreen"); // 恢复 max-height 为 480px if (isMobile()) { document.querySelector("video").style.maxHeight = "218px"; document.querySelector(".video-play-page .dplayer-video-wrap").style.maxHeight = "218px"; } else { document.querySelector("video").style.maxHeight = strMaxPlayHeight ?? '480px'; document.querySelector(".video-play-page .dplayer-video-wrap").style.maxHeight = strMaxPlayHeight ?? '480px'; } }); videoPlayer.on('error', function () { }); videoPlayer.on('play', function () { }); // 监听当前播放时间 videoPlayer.on('timeupdate', function () { }); } function findFirstUrl(obj) { // 优先取 默认 // if (Array.isArray(obj?.douban) && obj.douban.length > 0 && obj.douban[0].url) { // return obj.douban[0].url; // } // 如果没有 douban,尝试取对象中第一个数组的第一个 url for (const key in obj) { if (Array.isArray(obj[key]) && obj[key].length > 0 && obj[key][0].url) { return obj[key]; // return obj[key][0].url; } } return null; } // 切换播放线路 // 切换播放线路 function checkLine(val) { // 构造 ID let strLineHeadId = `line_head_${val}`; let strLineListId = `playlist_${val}`; // 获取目标元素 let headElement = document.getElementById(strLineHeadId); let listElement = document.getElementById(strLineListId); // 获取所有头部导航和播放列表 let navItems = document.querySelectorAll('.play-group-head'); let tabPanes = document.querySelectorAll('.play-group-list'); // ✅ 如果目标元素不存在,则默认选中第一个 if (!headElement || !listElement) { if (navItems.length > 0 && tabPanes.length > 0) { headElement = navItems[0]; listElement = tabPanes[0]; } else { console.warn('没有可用的播放线路元素'); return; } } // 1. 更新头部导航 active 状态 navItems.forEach(item => { item.classList.toggle('active', item === headElement); }); // 2. 更新播放列表 active 状态 tabPanes.forEach(pane => { pane.classList.toggle('active', pane === listElement); }); } function reorderObj(obj) { if (!obj || typeof obj !== 'object') return obj; let newObj = {}; if (obj.hasOwnProperty('douban')) { newObj['douban'] = obj['douban']; } for (let key in obj) { if (key !== 'douban' && obj.hasOwnProperty(key)) { newObj[key] = obj[key]; } } return newObj; } document.addEventListener("DOMContentLoaded", function () { if (typeof strVideoId !== "undefined") { // if (typeof arrPlayUrl !== "undefined" && arrPlayUrl) { // arrPlayUrl = reorderObj(arrPlayUrl); // } // 使用示例 const statsData = { v_id: strVideoId, }; // 调用方法1 reportStats(statsData); // if (typeof strPlayType !== "undefined" && boolIsPlayPage) { // if (strPlayType == 'default') { // strPlayUrl = findFirstUrl(arrPlayUrl) // checkLine('douban'); // } else { // var ActivePlayUrl = arrPlayUrl[strPlayType][intPlayUrlIndex - 1] // strPlayUrl = ActivePlayUrl.url // checkLine(strPlayType); // } // initDPlayer(strPlayUrl) // }else if(strPlayType == "default" && !boolIsPlayPage){ // checkLine('douban'); // } if (typeof strPlayType !== "undefined" && boolIsPlayPage) { // 用户指定线路 if (strPlayType !== "default") { const activeUrl = arrPlayUrl[strPlayType][intPlayUrlIndex - 1]; strPlayUrl = activeUrl.url; checkLine(strPlayType); // 默认播放第一个线路的第一个 URL } else { const defaultLine = getDefaultLine(); strPlayUrl = getFirstPlayUrl(defaultLine); checkLine(defaultLine); } initDPlayer(strPlayUrl); } else if (strPlayType == "default" && !boolIsPlayPage) { const defaultLine = getDefaultLine(); checkLine(defaultLine); } addHistoryFun(); } // 获取第一个线路 key function getDefaultLine() { return Object.keys(arrPlayUrl)[0]; // 后端已经排序,第一位永远是默认线路 } // 获取某个线路的第一个 url function getFirstPlayUrl(playLine) { return arrPlayUrl[playLine][0].url; } })