CMS集成说明(两种方式任选其一,请先备份原模板文件)

📌 方式一:CMS播放器代码集成(推荐,无需修改模板)

将下方代码粘贴到苹果CMS播放器的「播放器代码」中

不需要修改播放页模板,直接使用 CMS 自带的 MacPlayer.PlayUrl

适合快速部署,无需技术背景

📌 方式二:替换模板代码(完整功能)

将播放页模板中的 {$player_data}{$player_js} 替换为下方完整代码

自包含完整代码,已内含 iframe、选集数据构建、以及所有CMS集成功能

不需要额外添加选集设置代码,一份代码即可完成全部功能

操作步骤:

📌 方式一:CMS播放器代码集成(无需替换模板代码,推荐)

使用方式:登录苹果CMS后台 → 【视频】→【播放器】→ 编辑对应播放器 → 【播放器代码】,将下方代码粘贴进去保存即可。

此方式会直接使用苹果CMS自带的 MacPlayer.PlayUrl 生成播放器,不需要修改播放页模板。完整选集列表依赖当前模板/播放器对象是否暴露播放列表;未暴露时会自动发送当前集信息,CMS集成基础能力仍可使用。

CMS播放器代码 — 粘贴到苹果CMS播放器代码内

复制代码

// ========== WGPlayer CMS player loader start ==========
// 将这段代码粘贴到苹果CMS播放器的代码中.
(function() {
    var s = document.createElement('script');
    s.charset = 'utf-8';
    s.src = "https://player.niaowo.cc/wgart/cms-player.js?base=https%3A%2F%2Fplayer.niaowo.cc%2F&v=20260622-5";
    (document.head || document.documentElement).appendChild(s);
})();
// ========== WGPlayer CMS player loader end ==========

📌 方式二:CMS集成完整代码(替换 {$player_data}{$player_js},自包含完整功能)

CMS集成完整代码 — 替换 {$player_data}{$player_js},包含选集功能

复制代码

<!-- ========== WGPlayer CMS集成完整代码 开始 ========== -->
<!-- 替换 {$player_data}{$player_js},一份代码包含所有功能(选集 + CMS集成),无需额外添加选集设置代码 -->

<div style="width:100%;position:relative;padding-bottom:56.25%;height:0;overflow:hidden;" id="player-wrapper">
    <iframe 
        id="wg-player" 
        data-player-base="aHR0cHM6Ly9wbGF5ZXIubmlhb3dvLmNjLw=="
        width="100%" 
        height="100%" 
        frameborder="0" 
        allowfullscreen
        allow="autoplay; fullscreen; clipboard-write"
        style="border:none;display:block;position:absolute;top:0;left:0;">
    </iframe>
</div>

{php}
    $episodeList = [];
    $urls = $obj['vod_play_list'][$param['sid']]['urls'];
    foreach($urls as $k => $v) {
        $episodeList[] = [
            'name' => $v['name'],
            'url' => $v['url'],
            'index' => $k + 1
        ];
    }
    $episodeListJson = json_encode($episodeList, JSON_UNESCAPED_UNICODE);
    $episodeListBase64 = base64_encode($episodeListJson);
    $episodeListBase64 = str_replace(["\r", "\n"], '', $episodeListBase64);

    // ---- 弹幕库精准匹配所需字段 ----
    // 视频类型(电视剧/电影/动漫等)
    $vodType = $obj['type_name'] ?? (is_array($obj['vod_class'] ?? null) ? ($obj['vod_class']['type_name'] ?? '') : '');
    // 年份
    $vodYear = $obj['vod_year'] ?? '';
    // 季号:优先取自定义字段 vod_season,否则从标题自动提取(如"庆余年 第二季" → 2)
    $vodSeason = intval($obj['vod_season'] ?? 0);
    if ($vodSeason <= 0) {
        if (preg_match('/第\s*([一二三四五六七八九十\d]+)\s*季/u', $obj['vod_name'] ?? '', $m)) {
            $chineseNumMap = ['一'=>1,'二'=>2,'三'=>3,'四'=>4,'五'=>5,'六'=>6,'七'=>7,'八'=>8,'九'=>9,'十'=>10,'十一'=>11,'十二'=>12];
            $vodSeason = $chineseNumMap[$m[1]] ?? intval($m[1]);
        }
    }
{/php}

<script>
window._cmsIntegrationLoaded = true;

(function() {
    var iframe = document.getElementById('wg-player');
    if (!iframe) { console.warn('[CMS集成] 未找到播放器iframe,跳过'); return; }

    // 解密播放器地址并构建完整URL
    var _pBase = atob(iframe.getAttribute('data-player-base'));
    iframe.src = _pBase + "?url={$obj['vod_play_list'][$param['sid']]['urls'][$param['nid']]['url']|urlencode}&name={$obj.vod_name|urlencode}&id={$obj.vod_id}&ep={$param.nid}";

    var currentEp = <?php echo isset($param['nid']) ? $param['nid'] : 1; ?>;
    var totalEps = <?php echo isset($urls) ? count($urls) : 0; ?>;
    var episodeDataBase64 = "{$episodeListBase64}";
    var episodeDataJsonRaw = "{$episodeListJson|addslashes}";
    var videoName = "{$obj.vod_name|addslashes}";
    var videoId = "{$obj.vod_id}";
    var videoType = "{$vodType|addslashes}";
    var videoYear = "{$vodYear}";
    var videoSeason = {$vodSeason};
    var parentPageUrl = window.location.href;

    function sendDataToPlayer() {
        if (iframe && iframe.contentWindow) {
            // 1. 发送选集列表数据 — base64方式(选集功能 + 下一集按钮)
            iframe.contentWindow.postMessage({
                type: 'episodeData',
                data: episodeDataBase64,
                encoding: 'base64'
            }, '*');

            // 2. 发送选集列表数据 — 原始JSON备用(不依赖base64,可靠性更高)
            iframe.contentWindow.postMessage({
                type: 'episodeData',
                data: episodeDataJsonRaw,
                encoding: 'json'
            }, '*');

            // 3. 发送视频基本信息(标题栏 + 弹幕库精准匹配用)
            iframe.contentWindow.postMessage({
                type: 'videoInfo',
                name: videoName,
                id: videoId,
                currentEp: currentEp,
                totalEps: totalEps,
                videoType: videoType,
                year: videoYear,
                season: videoSeason
            }, '*');

            // 4. 发送父页面地址(一起看复制链接用,解决跨域)
            iframe.contentWindow.postMessage({
                type: 'parentPageUrl',
                url: parentPageUrl
            }, '*');

            console.log('[CMS集成] 已发送选集数据、视频信息、父页面地址到播放器');
        }
    }

    if (iframe) {
        iframe.addEventListener('load', function() {
            sendDataToPlayer();
        });
        // 轮询重试发送:播放器端会轮询等待最多3秒,这里每800ms重发一次确保数据送达
        var _cmsRetryCount = 0;
        var _cmsMaxRetries = 4; // 4次 * 800ms = 3.2秒
        var _cmsRetryInterval = setInterval(function() {
            _cmsRetryCount++;
            sendDataToPlayer();
            if (_cmsRetryCount >= _cmsMaxRetries) {
                clearInterval(_cmsRetryInterval);
            }
        }, 800);
    }

    // 监听播放器发送的消息
    window.addEventListener('message', function(event) {
        if (!event.data || !event.data.type) return;

        // 选集切换:同步更新父页面URL
        if (event.data.type === 'episodeChange') {
            var newEp = event.data.index + 1;
            var pageUrl = window.location.href;
            var newUrl = pageUrl;

            // 依次尝试匹配多种CMS常见URL格式,命中即停止
            // 格式1: /nid/数字 或 /episode/数字
            if (/\/nid\/\d+/i.test(pageUrl)) {
                newUrl = pageUrl.replace(/\/nid\/\d+/i, '/nid/' + newEp);
            } else if (/\/episode\/\d+/i.test(pageUrl)) {
                newUrl = pageUrl.replace(/\/episode\/\d+/i, '/episode/' + newEp);
            }
            // 格式2: -ep-数字
            else if (/-ep-\d+/i.test(pageUrl)) {
                newUrl = pageUrl.replace(/-ep-\d+/i, '-ep-' + newEp);
            }
            // 格式3: /vodplay/123-1-数字.html (ID-SID-NID 格式,最后一个数字是集数)
            else if (/\/(\d+)-(\d+)-(\d+)(\.html?)?$/i.test(pageUrl)) {
                newUrl = pageUrl.replace(/-(\d+)(\.html?)?$/i, '-' + newEp + '$2');
            }
            // 格式4: /vod/数字.html 或 /play/数字
            else if (/\/(\d+)(\.html?)?$/i.test(pageUrl)) {
                newUrl = pageUrl.replace(/\/(\d+)(\.html?)?$/i, '/' + newEp + '$2');
            }

            console.log('[CMS集成] URL匹配调试 - 原始:', pageUrl, '→ 新URL:', newUrl, '(第' + newEp + '集)');

            if (newUrl !== pageUrl && window.history && window.history.replaceState) {
                console.log('[CMS集成] 页面跳转到新集数:', newUrl);
                window.location.href = newUrl;
            } else if (newUrl === pageUrl) {
                console.warn('[CMS集成] URL未匹配任何格式,无法同步。当前URL:', pageUrl);
            }
        }

        // 播放器主动请求父页面地址(解决时序竞态)
        if (event.data.type === 'requestParentUrl') {
            iframe.contentWindow.postMessage({
                type: 'parentPageUrl',
                url: parentPageUrl
            }, '*');
            console.log('[CMS集成] 响应播放器请求,发送父页面地址:', parentPageUrl);
        }

        // 网页全屏切换:CSS注入方案,隐藏所有非播放器元素
        if (event.data.type === 'webFullscreenChange') {
            var wrapper = document.getElementById('player-wrapper');
            if (!wrapper) { console.warn('[CMS集成] 未找到 #player-wrapper'); return; }
            if (event.data.state === true) {
                // 构建祖先链:从 wrapper 到 
                var chain = [];
                var el = wrapper;
                while (el && el !== document.documentElement) {
                    chain.push(el);
                    el = el.parentElement;
                }
                chain.push(document.documentElement);
                // 给链上每个元素打标记,供CSS选择器使用
                for (var i = 0; i < chain.length; i++) {
                    chain[i].setAttribute('data-wfs-keep', '1');
                }
                wrapper.style.cssText = 'position:fixed!important;top:0!important;left:0!important;right:0!important;bottom:0!important;width:auto!important;height:auto!important;z-index:2147483647!important;margin:0!important;padding:0!important;padding-bottom:0!important;overflow:hidden!important;background:#000!important;';
                var style = document.createElement('style');
                style.id = 'wfs-hide-style';
                style.textContent = [
                    'html,body{width:100%!important;height:100%!important;position:fixed!important;overflow:hidden!important;-webkit-overflow-scrolling:auto!important;margin:0!important;padding:0!important}',
                    'html body :not([data-wfs-keep]):not(#player-wrapper):not(#player-wrapper *){display:none!important}',
                    '#player-wrapper > iframe,#player-wrapper iframe{position:absolute!important;top:0!important;left:0!important;width:100%!important;height:100%!important;border:none!important;margin:0!important;padding:0!important}'
                ].join('');
                (document.head || document.documentElement).appendChild(style);
                console.log('[CMS集成] 网页全屏进入,CSS已注入,链长度:', chain.length);
            } else {
                var style = document.getElementById('wfs-hide-style');
                if (style) style.parentNode.removeChild(style);
                var kept = document.querySelectorAll('[data-wfs-keep]');
                for (var i = 0; i < kept.length; i++) { kept[i].removeAttribute('data-wfs-keep'); }
                wrapper.style.cssText = 'width:100%;position:relative;padding-bottom:56.25%;height:0;overflow:hidden;';
                console.log('[CMS集成] 网页全屏退出,CSS已移除');
            }
        }
    });
})();
</script>

<!-- ========== WGPlayer CMS集成完整代码 结束 ========== -->

📘 其他 CMS 对接说明

⚡ 集成功能说明

✅ 集成完成

对接完成后,你的网站将拥有:

如有问题,可进入管理后台查看帮助或联系技术支持。