(function () { if (typeof window.domClosest !== "function") { window.domClosest = function (from, selector) { var el = from; if (!el) return null; if (el.nodeType !== 1) el = el.parentElement || el.parentNode; if (!el || el.nodeType !== 1 || typeof el.closest !== "function") return null; return el.closest(selector); }; } // 参考 jha-1043:绝对地址直播,相对路径走同域 /h5/m3u8/ 代理。 function isHttpOrHttps(url) { return /^https?:\/\//i.test(url || ""); } function resolvePlayUrl(videoUrl) { if (!videoUrl) return ""; var raw = String(videoUrl).trim(); if (!raw) return ""; if (isHttpOrHttps(raw)) return raw; var path = raw.replace(/^\/+/, ""); if (path.indexOf("h5/m3u8/") === 0) { return "/" + path; } return "/h5/m3u8/" + path; } var HLS_CONFIG = { maxBufferLength: 30, maxMaxBufferLength: 60, liveSyncDurationCount: 3, fragLoadingTimeOut: 20000, manifestLoadingTimeOut: 10000, }; function forceCustomPlayer() { var bc = window.BrowserCompat; if (bc && bc.forceCustomPlayer) return true; var ua = (window.navigator && window.navigator.userAgent) || ""; return /Quark|MQQBrowser|QQ\/|UCBrowser|UCWEB|MicroMessenger|baidubrowser|bdbrowser|BaiduHD|MiuiBrowser|HuaweiBrowser|HONORBrowser|HBPC|SogouMobileBrowser|VivoBrowser|HeyTapBrowser|OPPOBrowser|HeyTap|QihooBrowser|360Browser|360SE|360EE/i.test( ua ); } function isIOSLike() { var nav = window.navigator || {}; var ua = nav.userAgent || ""; return ( /iPhone|iPad|iPod/i.test(ua) || (/Macintosh/i.test(ua) && Number(nav.maxTouchPoints) > 1) ); } function canPlayNativeHls() { var video = document.createElement("video"); return !!( video && typeof video.canPlayType === "function" && (video.canPlayType("application/vnd.apple.mpegurl") || video.canPlayType("application/x-mpegURL")) ); } function isAppleNativeHlsBrowser() { // 真 Safari / iOS Safari:原生 HLS 最稳。国产壳即便报告 mpegurl 也不走这条(易被系统播放器劫持) if (forceCustomPlayer()) return false; var ua = (window.navigator && window.navigator.userAgent) || ""; var isSafari = /Safari/i.test(ua) && !/Chrome|Chromium|CriOS|FxiOS|EdgiOS|OPiOS|Android|Quark|MQQBrowser|UCBrowser|MicroMessenger|baidubrowser|MiuiBrowser|HuaweiBrowser|HONORBrowser|Sogou/i.test( ua ); if (!isIOSLike() && !isSafari) return false; return canPlayNativeHls(); } function canUseHlsJs() { if (isAppleNativeHlsBrowser()) return false; return ( typeof window.Hls === "function" && typeof window.Hls.isSupported === "function" && window.Hls.isSupported() ); } /** 非真 Safari 时等 hls.js 脚本就绪,避免 Android 国产壳误走原生 HLS */ function needsHlsScript() { return !isAppleNativeHlsBrowser(); } function attachHlsJs(video, player) { var hlsOk = typeof window.Hls === "function" && typeof window.Hls.isSupported === "function" && window.Hls.isSupported(); if (!hlsOk) return; if (isAppleNativeHlsBrowser()) return; if ( player.plugins && player.plugins.hls && typeof player.plugins.hls.destroy === "function" ) { try { player.plugins.hls.destroy(); } catch (err) {} } // DPlayer 会先把 m3u8 写进 video.src;夸克/X5 识别后会外跳系统播放器。 // 先清掉原生 src,仅通过 hls.js(MSE/blob) 喂流。 var src = (video && (video.getAttribute("src") || video.src)) || (player && player.options && player.options.video && player.options.video.url) || ""; src = resolvePlayUrl(src); try { video.removeAttribute("src"); video.src = ""; if (typeof video.removeAttribute === "function") { video.removeAttribute("src"); } if (typeof video.load === "function") video.load(); } catch (e0) {} applyInlineAttrs(video); var hls = new window.Hls(HLS_CONFIG); player.plugins = player.plugins || {}; player.plugins.hls = hls; var recoverCount = 0; hls.on(window.Hls.Events.ERROR, function (_evt, data) { if (!data || !data.fatal) return; if (recoverCount >= 3) return; recoverCount += 1; try { if (data.type === window.Hls.ErrorTypes.NETWORK_ERROR) { hls.startLoad(); } else if (data.type === window.Hls.ErrorTypes.MEDIA_ERROR) { hls.recoverMediaError(); } } catch (e) {} }); if (src) hls.loadSource(src); hls.attachMedia(video); patchVideoInlinePlayback(player); } function buildVideoOption(url, pic) { var option = { url: url, type: "hls" }; if (canUseHlsJs()) { // Android / 桌面 / 支持 MSE 的壳:hls.js,避免系统播放器接管 option.type = "hlsjs"; option.customType = { hlsjs: attachHlsJs }; } else if (canPlayNativeHls()) { // iOS 夸克/微信等无 MSE:只能原生 HLS,配合内联属性尽量页内播放 option.type = "hls"; } else { option.type = "auto"; } if (pic) option.pic = pic; return option; } var videoPatchObserver = null; var videoPatchedEl = null; function stopVideoPatchWatch() { if (videoPatchObserver) { try { videoPatchObserver.disconnect(); } catch (e) {} videoPatchObserver = null; } videoPatchedEl = null; } /** * 只盯 controls 被壳层写回的情况。 * 注意:不可在 Observer 里无条件 setAttribute(会再次触发回调,卡死页面)。 */ function watchVideoNativeHijack(video) { if (!video || !window.MutationObserver) return; if (videoPatchedEl === video && videoPatchObserver) return; stopVideoPatchWatch(); videoPatchedEl = video; videoPatchObserver = new MutationObserver(function () { if (video.controls || video.hasAttribute("controls")) { try { video.controls = false; video.removeAttribute("controls"); } catch (err) {} } // 同层关键属性被清掉时再补一次(先 disconnect,避免自触发死循环) if (video.getAttribute("x5-video-player-type") !== "h5") { try { videoPatchObserver.disconnect(); } catch (e1) {} applyInlineAttrs(video); try { videoPatchObserver.observe(video, { attributes: true, attributeFilter: ["controls", "x5-video-player-type"], }); } catch (e2) {} } }); try { videoPatchObserver.observe(video, { attributes: true, attributeFilter: ["controls", "x5-video-player-type"], }); } catch (e3) {} } function applyInlineAttrs(video) { if (!video || !video.setAttribute) return; // 同层播放关键属性:尽量在 video 创建前写好 video.setAttribute("playsinline", "true"); video.setAttribute("webkit-playsinline", "true"); video.setAttribute("x5-playsinline", "true"); video.setAttribute("t7-video-player-type", "inline"); video.setAttribute("x5-video-player-type", "h5"); // true = X5/夸克同层页内全屏;false 反而容易外跳系统播放器 video.setAttribute("x5-video-player-fullscreen", "true"); video.setAttribute("x5-video-orientation", "portrait"); video.setAttribute("controlslist", "nodownload noplaybackrate noremoteplayback"); video.setAttribute("disablepictureinpicture", "true"); video.setAttribute("webkit-airplay", "deny"); video.setAttribute("x-webkit-airplay", "deny"); video.removeAttribute("controls"); video.controls = false; try { video.playsInline = true; } catch (e) {} try { video.disablePictureInPicture = true; } catch (e2) {} try { if (video.disableRemotePlayback !== undefined) { video.disableRemotePlayback = true; } } catch (e3) {} } /** 在 createElement('video') 时就打上同层属性,避免入 DOM 后再补已太晚 */ function installVideoCreateHook() { if (document.__jhaVideoInlineHooked) return; document.__jhaVideoInlineHooked = true; var rawCreate = document.createElement.bind(document); document.createElement = function (tagName, options) { var el = rawCreate(tagName, options); try { if (String(tagName).toLowerCase() === "video") { applyInlineAttrs(el); } } catch (err) {} return el; }; } function exitNativeFullscreen(video) { if (!video) return; try { if (typeof video.webkitExitFullscreen === "function") { video.webkitExitFullscreen(); } } catch (err) {} try { if (typeof video.exitFullscreen === "function") { video.exitFullscreen(); } } catch (err2) {} } function requestWebFullscreen(dp) { if (!dp) return; try { if (dp.fullScreen && typeof dp.fullScreen.request === "function") { dp.fullScreen.request("web"); return; } } catch (e) {} try { if (dp.container) { dp.container.classList.add("dplayer-fulled"); document.body.classList.add("dplayer-web-fullscreen-fix"); } } catch (e2) {} } /** 拦截 webkitEnterFullscreen,避免夸克/X5 调起系统播放器 */ function patchNativeFullscreenHooks(dp) { var video = dp && dp.video; if (!video || video.__fsHooked) return; video.__fsHooked = true; if (forceCustomPlayer()) { var entering = false; var blockNative = function () { if (entering) return; entering = true; try { exitNativeFullscreen(video); requestWebFullscreen(dp); applyInlineAttrs(video); } finally { entering = false; } }; try { video.webkitEnterFullscreen = blockNative; } catch (e) {} try { video.webkitEnterFullScreen = blockNative; } catch (e2) {} } if (!video.__playHooked) { video.__playHooked = true; var nativePlay = video.play.bind(video); video.play = function () { applyInlineAttrs(video); try { return nativePlay(); } catch (err) { return Promise.reject(err); } }; } } // QQ / 夸克 / UC / 百度等:页内同层播放,避免被系统播放器全屏接管 function patchVideoInlinePlayback(dp) { var video = dp && dp.video; if (!video) return; applyInlineAttrs(video); watchVideoNativeHijack(video); patchNativeFullscreenHooks(dp); if (!video.__cnPlayerBound) { video.__cnPlayerBound = true; var reapply = function () { applyInlineAttrs(video); }; video.addEventListener("play", reapply); video.addEventListener("playing", reapply); video.addEventListener("loadedmetadata", reapply); video.addEventListener("x5videoenterfullscreen", reapply); video.addEventListener("x5videoexitfullscreen", reapply); video.addEventListener("webkitbeginfullscreen", function () { if (forceCustomPlayer()) { exitNativeFullscreen(video); requestWebFullscreen(dp); } reapply(); }); } } /** * 启用控制条原生播放/暂停,并补绑移动端被跳过的音量按钮。 * (插件在 isMobile 时不 initVolumeButton;我们已去掉 dplayer-mobile) */ function enableBarPlayControls(dp) { if (!dp || !dp.container) return; var el = dp.container; function apply() { el.classList.remove("dplayer-mobile"); if (el.offsetWidth <= 500) { el.classList.add("dplayer-arrow"); } } apply(); if (typeof MutationObserver === "function" && !el.__barControlsObs) { var obs = new MutationObserver(function () { if (el.classList.contains("dplayer-mobile")) apply(); }); obs.observe(el, { attributes: true, attributeFilter: ["class"] }); el.__barControlsObs = obs; } if (!dp.__volumeInited) { try { if (dp.controller && typeof dp.controller.initVolumeButton === "function") { dp.controller.initVolumeButton(); dp.__volumeInited = true; } else { bindVolumeMuteFallback(dp); } } catch (e) { bindVolumeMuteFallback(dp); } } } function bindVolumeMuteFallback(dp) { if (!dp || dp.__volumeInited) return; var icon = (dp.template && dp.template.volumeButtonIcon) || (dp.container && dp.container.querySelector(".dplayer-volume-icon")); if (!icon || icon.__muteBound) return; icon.__muteBound = true; dp.__volumeInited = true; icon.addEventListener("click", function (event) { event.preventDefault(); event.stopPropagation(); try { if (!dp.video) return; dp.video.muted = !dp.video.muted; if (typeof dp.switchVolumeIcon === "function") dp.switchVolumeIcon(); } catch (err) {} }); } /** 包装 DPlayer:任意实例都启用可操作的控制条按钮 */ function wrapDPlayerCtor() { var Ctor = window.DPlayer; if (!Ctor || Ctor.__barPlayWrapped) return; installVideoCreateHook(); function Wrapped(options) { installVideoCreateHook(); var dp = new Ctor(options); enableBarPlayControls(dp); patchVideoInlinePlayback(dp); return dp; } Wrapped.prototype = Ctor.prototype; Object.keys(Ctor).forEach(function (k) { try { Wrapped[k] = Ctor[k]; } catch (e) {} }); Wrapped.__barPlayWrapped = true; window.DPlayer = Wrapped; } function safePlay(dp) { if (!dp) return; try { var result = dp.play(); if (result && typeof result.then === "function") { result.catch(function () { // 部分夸克/QQ 需再次用户手势;保留封面按钮可重试 }); } } catch (e) {} } var playDp = null; var currentPlayMode = "main"; var mainBadgePC = ""; var mainBadgeH5 = ""; var mainCtaLabel = ""; function playerRoot() { return document.querySelector("[data-play-player]"); } function isPreviewMode() { var root = playerRoot(); return !!( root && (root.getAttribute("data-play-mode") === "preview" || root.classList.contains("play-player--preview") || currentPlayMode === "preview") ); } function canWatchMain() { var root = playerRoot(); return !!(root && root.getAttribute("data-can-watch") === "1"); } function mainPlayURL() { var root = playerRoot(); var container = document.querySelector(".dplayer-video"); var fromRoot = root && root.getAttribute("data-main-url"); var fromBox = container && container.getAttribute("data-main-url"); return resolvePlayUrl(fromRoot || fromBox || ""); } function previewPlayURL() { var root = playerRoot(); var container = document.querySelector(".dplayer-video"); var fromRoot = root && root.getAttribute("data-preview-url"); var fromBox = container && container.getAttribute("data-preview-url"); return resolvePlayUrl(fromRoot || fromBox || ""); } function syncMainCta(mode) { var cta = document.querySelector("[data-play-main-cta]"); if (!cta) return; var label = cta.querySelector("[data-play-cta-label]"); if (!mainCtaLabel && label) mainCtaLabel = label.textContent || ""; if (mode === "preview") { cta.removeAttribute("data-play-coin-open"); cta.setAttribute("data-play-poster-play", ""); if (label) label.textContent = "播放预告片"; return; } if (!canWatchMain()) { cta.removeAttribute("data-play-poster-play"); cta.setAttribute("data-play-coin-open", ""); if (label) label.textContent = "解锁播放"; return; } cta.removeAttribute("data-play-coin-open"); cta.setAttribute("data-play-poster-play", ""); if (label) label.textContent = mainCtaLabel || "立即播放"; } function hidePosterOverlay() { var root = document.querySelector("[data-play-player]"); if (root) root.classList.add("is-playing"); var poster = document.querySelector("[data-play-poster]"); if (poster) poster.classList.add("play-player__cover--hidden"); var playBtn = document.querySelector("[data-play-poster-play]"); if (playBtn) playBtn.style.display = "none"; } function showPosterOverlay() { var root = document.querySelector("[data-play-player]"); if (root) root.classList.remove("is-playing"); var poster = document.querySelector("[data-play-poster]"); if (poster) poster.classList.remove("play-player__cover--hidden"); var playBtn = document.querySelector("[data-play-poster-play]"); if (playBtn) playBtn.style.display = ""; } function ensurePosterDecrypt() { var poster = document.querySelector(".play-player__cover.lazy[data-src]"); if (!poster) return; if (typeof window.loadLazyNode === "function") { window.loadLazyNode(poster); return; } if (typeof window.initLazyImages === "function") { window.initLazyImages(poster.parentNode || document, { eager: true }); } } function initDPlayer(initialURL) { if (typeof window.DPlayer === "undefined") return null; var container = document.querySelector(".dplayer-video"); if (!container) return null; var url = resolvePlayUrl(initialURL || container.getAttribute("data-url") || ""); if (!url) return null; try { if (playDp && typeof playDp.destroy === "function") { try { playDp.destroy(); } catch (err) {} playDp = null; stopVideoPatchWatch(); container.innerHTML = ""; } container.setAttribute("data-url", url); installVideoCreateHook(); playDp = new window.DPlayer({ container: container, autoplay: false, preload: "metadata", screenshot: false, airplay: false, chromecast: false, hotkey: true, mutex: true, contextmenu: [], video: buildVideoOption(url, ""), }); // DPlayer 无 mobile 开关:去掉 dplayer-mobile,使用带播放/暂停的控制条 enableBarPlayControls(playDp); patchVideoInlinePlayback(playDp); if (typeof playDp.on === "function") { playDp.on("loadedmetadata", function () { patchVideoInlinePlayback(playDp); }); playDp.on("play", function () { patchVideoInlinePlayback(playDp); hidePosterOverlay(); }); } return playDp; } catch (e) { return null; } } function switchPlayerSource(url) { url = resolvePlayUrl(url || ""); if (!url) return null; var container = document.querySelector(".dplayer-video"); if (container) container.setAttribute("data-url", url); if (playDp && typeof playDp.switchVideo === "function") { try { playDp.switchVideo(buildVideoOption(url, "")); patchVideoInlinePlayback(playDp); return playDp; } catch (e) {} } return initDPlayer(url); } function updatePlayBadge(mode) { var pc = document.querySelector("[data-play-badge-pc]"); var h5 = document.querySelector("[data-play-badge-h5]"); if (!mainBadgePC && pc) mainBadgePC = pc.textContent || ""; if (!mainBadgeH5 && h5) mainBadgeH5 = h5.textContent || ""; if (mode === "preview") { if (pc) pc.textContent = "预告片 免费"; if (h5) h5.textContent = "预告片"; return; } if (pc) pc.textContent = mainBadgePC; if (h5) h5.textContent = mainBadgeH5; } function setPlayMode(mode, options) { options = options || {}; var root = playerRoot(); if (!root) return; var next = mode === "preview" ? "preview" : "main"; currentPlayMode = next; root.setAttribute("data-play-mode", next); root.classList.toggle("play-player--preview", next === "preview"); var tabs = document.querySelectorAll("[data-play-tab]"); Array.prototype.forEach.call(tabs, function (tab) { tab.classList.toggle("is-active", tab.getAttribute("data-play-tab") === next); }); var centerBtn = document.querySelector(".play-player__center"); updatePlayBadge(next); syncMainCta(next); if (next === "preview") { if (centerBtn) centerBtn.removeAttribute("data-play-coin-open"); var previewURL = previewPlayURL(); if (!previewURL) return; var dp = switchPlayerSource(previewURL); bindPosterPlay(dp); showPosterOverlay(); if (options.autoplay) { patchVideoInlinePlayback(dp); safePlay(dp); hidePosterOverlay(); } return; } // 正片 if (!canWatchMain()) { if (centerBtn) centerBtn.setAttribute("data-play-coin-open", ""); if (playDp) { try { playDp.pause(); } catch (e) {} } showPosterOverlay(); return; } if (centerBtn) centerBtn.removeAttribute("data-play-coin-open"); var mainURL = mainPlayURL(); if (!mainURL) return; var mainDp = switchPlayerSource(mainURL); bindPosterPlay(mainDp); showPosterOverlay(); if (options.autoplay) { patchVideoInlinePlayback(mainDp); safePlay(mainDp); hidePosterOverlay(); } } function bindPlayTabs() { var tabs = document.querySelectorAll("[data-play-tab]"); if (!tabs.length) return; Array.prototype.forEach.call(tabs, function (tab) { tab.addEventListener("click", function (event) { event.preventDefault(); var mode = tab.getAttribute("data-play-tab") || "main"; if (mode === currentPlayMode) { if (mode === "preview") { setPlayMode("preview", { autoplay: true }); } return; } setPlayMode(mode, { autoplay: mode === "preview" }); }); }); } function bindPosterPlay(dp) { var buttons = document.querySelectorAll("[data-play-poster-play]"); Array.prototype.forEach.call(buttons, function (btn) { if (btn.getAttribute("data-play-bound") === "1") return; btn.setAttribute("data-play-bound", "1"); btn.addEventListener("click", function (event) { // 预告片免登录 / 免解锁;仅正片未解锁时拦充值 if ( btn.hasAttribute("data-play-coin-open") && !isPreviewMode() ) { return; } if (btn.tagName === "A") { event.preventDefault(); } var mode = isPreviewMode() ? "preview" : "main"; var active = playDp || dp; if (mode === "preview") { if (!active) active = switchPlayerSource(previewPlayURL()); } else if (!canWatchMain()) { return; } else if (!active) { active = switchPlayerSource(mainPlayURL()); } if (!active) return; patchVideoInlinePlayback(active); safePlay(active); hidePosterOverlay(); }); }); } function tryAutoplayPreview() { if (!isPreviewMode() || !previewPlayURL()) return; setPlayMode("preview", { autoplay: true }); } function bootPlayer() { var root = playerRoot(); if (!root) return; // 等 DPlayer(及非 Safari 场景下的 hls.js)就绪,避免误走原生 HLS / 未包装构造器 var libsPending = typeof window.DPlayer === "undefined" || (needsHlsScript() && typeof window.Hls === "undefined"); if (libsPending) { if (!bootPlayer._retries) bootPlayer._retries = 0; if (bootPlayer._retries < 40) { bootPlayer._retries += 1; window.setTimeout(bootPlayer, 50); } return; } wrapDPlayerCtor(); ensurePosterDecrypt(); bindPlayTabs(); var pc = document.querySelector("[data-play-badge-pc]"); var h5 = document.querySelector("[data-play-badge-h5]"); if (pc) mainBadgePC = pc.textContent || ""; if (h5) mainBadgeH5 = h5.textContent || ""; var ctaLabel = document.querySelector("[data-play-cta-label]"); if (ctaLabel) mainCtaLabel = ctaLabel.textContent || ""; currentPlayMode = root.getAttribute("data-play-mode") || "main"; // 预告片:无需登录 / 解锁,可直接初始化并播放 if (currentPlayMode === "preview" && previewPlayURL()) { var previewDp = initDPlayer(previewPlayURL()); bindPosterPlay(previewDp); syncMainCta("preview"); showPosterOverlay(); document.addEventListener("eighteen:closed", tryAutoplayPreview, { once: true, }); if ( document.documentElement.classList.contains("eighteen-ok") || !document.querySelector("[data-eighteen].is-open") ) { // 已过年龄门时不强制自动播,等用户点击即可 } return; } if (canWatchMain() && mainPlayURL()) { var dp = initDPlayer(mainPlayURL()); bindPosterPlay(dp); if (!dp) showPosterOverlay(); return; } // 正片未解锁但有预告:切到预告片模式 if (previewPlayURL()) { setPlayMode("preview", { autoplay: false }); document.addEventListener("eighteen:closed", tryAutoplayPreview, { once: true, }); return; } // 正片未解锁:仅绑定 tab / 封面 bindPosterPlay(null); showPosterOverlay(); } if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", bootPlayer); } else { bootPlayer(); } })(); (function () { var root = document.querySelector("[data-play-coin]"); if (!root) return; var openers = document.querySelectorAll("[data-play-coin-open]"); var closers = root.querySelectorAll("[data-play-coin-close]"); var previousOverflow = ""; function open() { root.classList.add("is-open"); previousOverflow = document.body.style.overflow; document.body.style.overflow = "hidden"; } function close() { root.classList.remove("is-open"); document.body.style.overflow = previousOverflow; } function isPreviewPlayingSurface() { var player = document.querySelector("[data-play-player]"); return !!( player && (player.getAttribute("data-play-mode") === "preview" || player.classList.contains("play-player--preview")) ); } Array.prototype.forEach.call(openers, function (btn) { btn.addEventListener("click", function () { // 预告片模式不弹下载提示;属性被临时移除时也不弹。 if (!btn.hasAttribute("data-play-coin-open")) return; if (isPreviewPlayingSurface()) return; open(); }); }); Array.prototype.forEach.call(closers, function (el) { el.addEventListener("click", close); }); document.addEventListener("keydown", function (event) { if (event.key === "Escape" && root.classList.contains("is-open")) { close(); } }); })(); (function () { var btn = document.querySelector("[data-guess-refresh]"); var grid = document.querySelector("[data-guess-grid]"); if (!btn || !grid) return; var loading = false; var PLACEHOLDER = "/static/images/placeholder.png?v=2"; function toInt(v, fallback) { var n = parseInt(v, 10); return isNaN(n) ? fallback : n; } var videoId = toInt(btn.getAttribute("data-video-id"), 0); var playletId = toInt(btn.getAttribute("data-playlet-id"), 0); function nextPage(pageNum, pageSize, totalCount) { var totalPages = pageSize > 0 && totalCount > 0 ? Math.ceil(totalCount / pageSize) : 0; if (totalPages <= 1) return 1; if (pageNum < 1) pageNum = 1; var next = pageNum + 1; return next > totalPages ? 1 : next; } function playURL(slug, id) { var seg = String(slug || "").trim(); if (!seg && id > 0) seg = String(id); if (!seg) return "#"; return "/play/" + encodeURIComponent(seg); } function videoPlayURL(slug, id) { var seg = String(slug || "").trim(); if (!seg && id > 0) seg = String(id); if (!seg) return "/series"; return "/series-play/" + encodeURIComponent(seg); } function tagPageURL(slug, id) { var seg = String(slug || "").trim(); if (!seg && id > 0) seg = String(id); if (!seg) return ""; return "/tags/" + encodeURIComponent(seg); } function themeListURL(slug, id) { var seg = String(slug || "").trim(); if (!seg && id > 0) seg = String(id); if (!seg) return "/list"; return "/list/" + encodeURIComponent(seg); } function pushNamed(out, seen, names, ids, slugs, asTag) { names = names || []; ids = ids || []; slugs = slugs || []; for (var i = 0; i < names.length && out.length < 3; i++) { var name = String(names[i] || "").trim(); if (!name) continue; var key = name.toLowerCase(); if (seen[key]) continue; seen[key] = true; var id = ids[i] > 0 ? ids[i] : 0; var slug = String(slugs[i] || "").trim(); out.push({ name: name, url: asTag ? tagPageURL(slug, id) : themeListURL(slug, id), }); } } function cardTags(item) { var out = []; var seen = {}; pushNamed(out, seen, item.tagNames, item.tagIds, item.tagSlugs, true); if (out.length < 3) { pushNamed(out, seen, item.themeNames, item.themeIds, item.themeSlugs, false); } return out; } function displayName(item) { return String((item && (item.playName || item.title)) || "").trim() || "短剧"; } function updateStatusText(status) { return Number(status) === 2 ? "已完结" : "连载中"; } function escapeHtml(s) { return String(s == null ? "" : s) .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """) .replace(/'/g, "'"); } function renderMeta(item) { var tags = cardTags(item); return tags .map(function (tag, i) { var sep = i ? " " : ""; var name = escapeHtml(tag.name); if (tag.url) { return sep + '' + name + ""; } return sep + name; }) .join(""); } function renderVideoMeta(item) { var keys = (item && item.keyworld) || []; var parts = []; for (var i = 0; i < keys.length && parts.length < 3; i++) { var k = String(keys[i] || "").trim(); if (k) parts.push(escapeHtml(k)); } if (parts.length) return parts.join(" "); return escapeHtml((item && item.creatorName) || ""); } function renderList(list) { if (!list || !list.length) { grid.innerHTML = '

暂无推荐

'; return; } var html = list .map(function (item) { var href = playURL(item.slug, item.id); var name = escapeHtml(displayName(item)); var meta = renderMeta(item); var ep = item.totalEpisode > 0 ? "全 " + item.totalEpisode + " 集" : updateStatusText(item.updateStatus); var cover = escapeHtml(item.cover || ""); return ( '
' + '' + '' + escapeHtml(ep) + "" + "" + '

' + name + "

" + '

' + meta + "

" + "
" ); }) .join(""); grid.innerHTML = html; if (typeof window.initLazyImages === "function") { window.initLazyImages(grid); } } function renderVideoList(list) { if (!list || !list.length) { grid.innerHTML = '

暂无推荐

'; return; } var html = list .map(function (item) { var href = videoPlayURL(item.slug, item.id); var name = escapeHtml(String((item && item.title) || "").trim() || "视频"); var meta = renderVideoMeta(item); var ep = item.videoTime > 0 ? String(item.videoTime) + " 分钟" : ""; var cover = escapeHtml(item.coverImg || ""); return ( '
' + '' + (ep ? '' + escapeHtml(ep) + "" : "") + "" + '

' + name + "

" + '

' + meta + "

" + "
" ); }) .join(""); grid.innerHTML = html; if (typeof window.initLazyImages === "function") { window.initLazyImages(grid); } } function readVideoRecommendAll() { var el = document.getElementById("video-guess-like-data"); if (!el) return []; try { var raw = JSON.parse(el.textContent || "[]"); return Array.isArray(raw) ? raw : []; } catch (err) { return []; } } function slicePage(list, pageNum, pageSize) { var total = list.length; if (!total) return { list: [], pageNum: 1, totalCount: 0 }; if (pageNum < 1) pageNum = 1; var start = (pageNum - 1) * pageSize; if (start >= total) { pageNum = 1; start = 0; } return { list: list.slice(start, start + pageSize), pageNum: pageNum, totalCount: total, }; } function setBusy(on) { loading = on; btn.disabled = !!on; btn.classList.toggle("is-loading", !!on); } btn.addEventListener("click", function () { if (loading) return; var page = toInt(btn.getAttribute("data-page"), 1); var pageSize = toInt(btn.getAttribute("data-page-size"), 6); var total = toInt(btn.getAttribute("data-total"), 0); // 视频播放页:详情 recommendVideos 客户端换一批(结构对齐短剧猜你喜欢) if (videoId > 0) { var all = readVideoRecommendAll(); var targetPage = nextPage(page, pageSize, all.length || total); setBusy(true); try { var sliced = slicePage(all, targetPage, pageSize); btn.setAttribute("data-page", String(sliced.pageNum)); btn.setAttribute("data-page-size", String(pageSize)); btn.setAttribute("data-total", String(sliced.totalCount)); renderVideoList(sliced.list); } finally { setBusy(false); } return; } if (!window.HttpRequest || typeof window.HttpRequest.get !== "function") { return; } if (playletId <= 0) return; var targetPage = nextPage(page, pageSize, total); setBusy(true); window.HttpRequest.get("/api/playlet/guess-like/list", { params: { playletId: playletId, pageNum: targetPage, pageSize: pageSize, }, }) .then(function (res) { if (!res || Number(res.code) !== 200 || !res.data) { throw new Error((res && res.msg) || "guess-like failed"); } var data = res.data; var list = data.list || []; var pageNum = toInt(data.pageNum, targetPage); var size = toInt(data.pageSize, pageSize); var totalCount = toInt(data.totalCount, total); if (!list.length && pageNum > 1) { return window.HttpRequest.get("/api/playlet/guess-like/list", { params: { playletId: playletId, pageNum: 1, pageSize: size, }, }).then(function (retry) { if (!retry || Number(retry.code) !== 200 || !retry.data) { throw new Error((retry && retry.msg) || "guess-like failed"); } return retry.data; }); } return data; }) .then(function (data) { btn.setAttribute("data-page", String(toInt(data.pageNum, 1))); btn.setAttribute("data-page-size", String(toInt(data.pageSize, pageSize))); btn.setAttribute("data-total", String(toInt(data.totalCount, total))); renderList(data.list || []); }) .catch(function () {}) .finally(function () { setBusy(false); }); }); })(); // 简介展开:PC 超过 1 行、H5 超过 2 行才显示展开按钮 (function () { var root = document.querySelector("[data-play-synopsis]"); if (!root) return; var textEl = root.querySelector("[data-play-synopsis-text]"); var moreBtn = root.querySelector("[data-play-synopsis-more]"); var moreLabel = root.querySelector("[data-play-synopsis-more-label]"); if (!textEl || !moreBtn) return; function isOverflowing() { var expanded = root.classList.contains("is-expanded"); if (expanded) root.classList.remove("is-expanded"); var needs = textEl.scrollHeight > textEl.clientHeight + 1; if (expanded) root.classList.add("is-expanded"); return needs; } function syncMoreVisibility() { var needs = isOverflowing(); moreBtn.hidden = !needs; if (!needs && root.classList.contains("is-expanded")) { root.classList.remove("is-expanded"); if (moreLabel) moreLabel.textContent = "展开"; moreBtn.setAttribute("aria-expanded", "false"); } } moreBtn.addEventListener("click", function () { var expanded = root.classList.toggle("is-expanded"); if (moreLabel) moreLabel.textContent = expanded ? "收起" : "展开"; moreBtn.setAttribute("aria-expanded", expanded ? "true" : "false"); }); syncMoreVisibility(); window.addEventListener("resize", syncMoreVisibility); if (document.fonts && document.fonts.ready) { document.fonts.ready.then(syncMoreVisibility).catch(function () {}); } })(); // 选集:正序 / 倒序(PC tabs + H5 切换共用) (function () { var grid = document.querySelector("[data-play-episodes-grid]"); if (!grid) return; var h5Btn = document.querySelector("[data-play-episodes-order]"); var h5Label = h5Btn && h5Btn.querySelector("[data-play-episodes-order-label]"); var sortItems = document.querySelectorAll("[data-play-episodes-sort-item]"); var desc = false; function reverseGrid() { var nodes = Array.prototype.slice.call(grid.children); if (nodes.length < 2) return; nodes.reverse().forEach(function (node) { grid.appendChild(node); }); } function syncUI() { if (h5Btn) { h5Btn.setAttribute("aria-pressed", desc ? "true" : "false"); h5Btn.classList.toggle("is-desc", desc); if (h5Label) h5Label.textContent = desc ? "正序" : "倒序"; } Array.prototype.forEach.call(sortItems, function (item) { var isDesc = item.getAttribute("data-play-episodes-sort-item") === "desc"; var active = isDesc === desc; item.classList.toggle("is-active", active); item.setAttribute("aria-pressed", active ? "true" : "false"); }); } function setOrder(nextDesc) { nextDesc = !!nextDesc; if (nextDesc === desc) return; desc = nextDesc; reverseGrid(); syncUI(); } if (h5Btn) { h5Btn.addEventListener("click", function () { setOrder(!desc); }); } Array.prototype.forEach.call(sortItems, function (item) { item.addEventListener("click", function () { setOrder(item.getAttribute("data-play-episodes-sort-item") === "desc"); }); }); syncUI(); })();