苹果CMS 详情页播放源Favicon自动加载方案

机器人
摘要
Mxchild
生成中...

一个不起眼的小图标,背后藏着”服务端兜底 + 客户端兜底”双层降级思路。

一、要解决的问题

苹果CMS主题模板中,资源名前面一般都是统一的默认图标,甚至没有图标,所有播放源长得一模一样。我希望实现的:每个播放源前面都有一个小图标——腾讯视频的小企鹅、爱奇艺的绿圆 Q、优酷的 play 三角。这种细节是腾讯视频、爱奇艺那种大站的标配,能极大提升页面的辨识度和”专业感”。

  • 每个播放源前面显示自己官网的 favicon
  • 播放源域名千变万化(采集站、网盘、自建 CDN),不能写死
  • favicon 加载失败必须降级,不能留个裂图
  • 改造要轻量,不能进数据库、不影响采集入库流程
图片[1] - 苹果CMS 详情页播放源Favicon自动加载方案 - 迅维博客网

二、核心设计:服务端拼 URL + 客户端兜底

整个方案拆成两部分:

职责文件
服务端(模板 PHP)从播放地址里解析域名,拼 https://{domain}/favicon.ico,挂在 data-favicon 属性上template/ds3/name/vod/anthology.html 第 9 行
客户端(JS)DOMContentLoaded 后扫所有 [data-favicon] 标签,把里面的 <i> 图标替换成 <img>,加载失败兜底static/ds3/add/player_favicon.js(47 行)

服务端只管”算 URL”(PHP 做这事儿是天然的,不用额外查接口),客户端负责”渲染 + 兜底”(浏览器 DOM 操作、img onerror 都得客户端做)。

为什么不让后端直接 <img src=”…”> 输出?因为采集站的播放 URL 经常是动态地址(带签名 token、CDN 节点等),同一个域名可能挂几十个不同 IP 的 CDN,模板解析时拿到的 URL 只能作为”猜”的依据。真正稳定能加载的,是对方官网 /favicon.ico 这个静态文件。所以服务端只负责”猜域名”,客户端去加载就好。

三、模板改动(服务端拼 URL)

文件:template/ds3/name/vod/anthology.html

3.1 关键的两行 PHP

{maccms:foreach name="obj.vod_play_list" id="vo"}
{php}
$favDomain = isset($vo['urls'][1]['url']) ? parse_url($vo['urls'][1]['url'], PHP_URL_HOST) : '';
$favUrl    = $favDomain ? 'https://'.$favDomain.'/favicon.ico' : '';
{/php}
<a class="swiper-slide" 
   data-favicon="{$favUrl}" 
   rel="nofollow">
    <i class="fa ds-dianying"></i> 
    {$vo.player_info.show}
    {if $vo.url_count > 1}<span class="badge">{$vo.url_count}</span>{/if}
</a>
{/maccms:foreach}

大多数正规网站都会在根目录放 favicon.ico,这是万维网 1999 年就定下来的约定。即使是 SPA、单页应用、纯前端项目,也几乎不会例外。

四、客户端 JS(替换 + 兜底)

文件:static/ds3/add/player_favicon.js,完整 47 行,无依赖。

4.1 完整代码

/**
 * 播放源Favicon自动替换
 * 自动从播放URL提取域名获取favicon图标
 * 支持详情页(anthology.html)和播放页(play_0/1/2.html)
 */
(function() {
    'use strict';

    // 默认favicon(本站图标)
    const defaultFavicon = '/favicon.ico';

    // 处理单个播放源标签
    function processTab(tab, faviconUrl) {
        if (!favIconUrl) return;
        const icon = tab.querySelector('i.fa');
        if (!icon) return;

        const img = document.createElement('img');
        img.className = 'player-favicon';
        img.src = faviconUrl;
        img.alt = '';

        // 加载失败时使用默认图标
        img.onerror = function() {
            this.src = defaultFavicon;
            this.onerror = null;
        };

        icon.parentNode.replaceChild(img, icon);
    }

    // 初始化处理
    function init() {
        // 匹配所有带 data-favicon 属性的资源标签(详情页 + 播放页)
        document.querySelectorAll('.anthology-tab .swiper-slide[data-favicon]').forEach(function(tab) {
            processTab(tab, tab.getAttribute('data-favicon'));
        });
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }
})})();

4.2 三个关键设计

1、选择器带 [data-favicon],过滤无关 <a>
详情页上有大量的 <a class=”swiper-slide”>,导航、推荐位都用这套结构。不加 [data-favicon] 过滤,会把推荐位里的图标也替换掉,覆盖错位。

2、加载失败二次兜底
很多网站没有 /favicon.ico,或者重定向到了奇怪地方

3、不改数据库、不改采集入库流程、不改后台控制器。所有逻辑都在前端层和模板层完成。后期 maccms 升级、其他主题切换都不受影响。

本文仅用于技术学习与个人站点优化参考,请勿用于商业用途。

© 版权声明
THE END
喜欢就支持一下吧
点赞8 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容