• Smartideo Pro v3.4.0

    WordPress 视频嵌入插件 · 服务端流式代理 · API 自动探测 · 多清晰度切换 · B2 主题内置适配

Smartideo Pro 二开版本

v3.4.0 基于 Smartideo 二次开发

Smartideo Pro

WordPress 视频嵌入插件 · 服务端流式代理 · API 自动探测 · 多清晰度切换 · B2 主题内置适配

原作者:Fens Liu · 二次开发:纯七(xzbzq.com

为什么要二次开发

原版 Smartideo 的局限性

原版 Smartideo 由纯七开发,通过 iframe 嵌入的方式在 WordPress 中播放各平台视频。这个方案简单可靠,但存在几个核心问题:

问题 1

iframe 嵌入有局限

很多视频平台(抖音、B站等)的 iframe 播放器体验差:无法自定义控件、不支持移动端全屏、广告多、加载慢。用户希望能拿到视频直链用自己的播放器播放,但原版没有 API 解析功能。

问题 2

CDN 直链无法直接播放

即使拿到了视频直链,抖音的 aweme.snssdk.com、B站的 bilivideo.com 等 CDN 域名会检查 Referer 和 CORS。浏览器直接请求这些 URL 会被拒绝,返回 403 或 CORS 错误。原版没有解决这个问题。

问题 3

竖屏视频在 PC 端严重变形

原版用 padding-top 百分比控制容器比例。但 CSS 的 padding-top相对父元素宽度计算的,当 max-width 限制了元素自身宽度后,高度仍按父宽度计算,导致竖屏视频在 PC 上变成一个极窄极长的竖条。

问题 4

API 配置门槛高

部分插件支持 API 解析,但需要用户手动填写 JSON 字段路径(如 data.video.url)。普通用户(小白)根本不知道怎么找这些路径,不同 API 返回格式还不一样,换一个接口就得重新配置。

架构设计

三层架构:oEmbed 拦截 → REST API 解析 → 服务端代理

第一层:oEmbed 拦截层
wp_embed_register_handler() 注册 URL 正则 + the_content 过滤器(优先级 7)
用户把视频链接粘进文章 → 自动匹配正则 → 进入处理流程
第二层:API 解析层
REST API /parse → call_parse_api() → _api_call()
调用第三方解析接口 → 自动探测 JSON 返回 → 提取直链/封面/宽高/多清晰度
第三层:流式代理层
REST API /proxy → rest_proxy_video() → cURL 流式转发
服务端伪装 Referer → 透传 Range 请求 → 浏览器拿到的是同源代理 URL

这三层各司其职:第一层负责拦截 URL,把视频链接从文章内容中识别出来;第二层负责解析,调用第三方 API 拿到视频直链;第三层负责代理,把 CDN 直链包装成同源 URL,绕过浏览器的 CORS 和 Referer 限制。三层之间通过 WordPress REST API 解耦,前端和后端完全分离。

二开原理详解

每个问题的分析、方案和关键实现

原理 1 — CDN 流式代理

问题:浏览器请求 CDN 直链被 403 拒绝

抖音视频存储在 aweme.snssdk.com,B站视频在 bilivideo.com。这些 CDN 服务器会检查请求头中的 RefererOrigin。浏览器发起的请求 Referer 是你的 WordPress 站点域名,不在 CDN 的白名单里,所以直接拒绝。

方案:服务端 cURL 流式代理

在 WordPress 后端起一个 cURL 请求,伪造 Referer: https://www.douyin.com/,CDN 认为请求来自抖音官网,就放行了。然后把这个响应原样流式转发给浏览器。浏览器看到的是 你的域名/wp-json/smartideo-pro/v1/proxy?url=...,同源请求,没有 CORS 问题。

关键实现

// 1. maybe_proxy_url() — 检测 CDN 域名,自动包装代理 URLif ($this->is_proxy_allowed($host)) { return rest_url('smartideo-pro/v1/proxy') . '?url=' . rawurlencode($url); }// 2. rest_proxy_video() — cURL 流式转发// CURLOPT_WRITEFUNCTION: 每收到一段数据就直接 echo 给浏览器// CURLOPT_HEADERFUNCTION: 捕获 Content-Type/Content-Length/Content-Range// Range 请求透传: 用户拖拽进度条 → 浏览器发 Range: bytes=1048576- → 透传给 CDN// Referer 伪装: snssdk → www.douyin.com, bilivideo → www.bilibili.com
原理 2 — API 返回格式自动探测

问题:不同 API 返回的 JSON 结构完全不同

接口 A 返回 {"url":"http://...mp4"},接口 B 返回 {"data":{"play_url":"http://..."}},接口 C 返回 {"result":{"video":"http://..."}}。小白用户不可能知道每个接口的 JSON 字段路径。

方案:三级递归探测算法

不依赖固定路径,而是递归扫描整个 JSON 树,用键名优先级匹配 + URL 特征识别找到视频直链:

优先键名匹配
检查 url、video_url、play_url、download_url 等常见键名,只要值是 http 开头 > 20 字符的 URL 就采用
回退:is_url_like 特征识别
扫描所有字符串值,检查是否含 .mp4/.m3u8/.flv 扩展名或已知 CDN 域名(snssdk、bilivideo 等)
回退:递归嵌套查找
如果当前层级没找到,递归进入子数组继续搜索,最深 8 层

这样不管 API 返回什么格式,只要 JSON 里有视频 URL,就能自动找到。用户只需要填 API 地址,不用碰 JSON 路径配置。

原理 3 — 竖屏视频比例修复

问题:padding-top 百分比的计算基准是父元素宽度

传统 CSS 用 padding-top: 56.25% 实现 16:9 比例。但 CSS 规范中 padding 的百分比是相对包含块(父元素)的宽度计算的,不是元素自身的宽度。

max-width 限制了竖屏视频元素自身宽度为 380px,但父元素是 800px 时,padding-top: 56.25% 计算出来是 800×0.5625 = 450px,而不是 380×0.5625 = 214px。高度按父宽度算,宽度被 max-width 压缩了,结果就是一个比例完全错误的细长矩形。

方案:CSS aspect-ratio + CSS 变量

/* aspect-ratio 基于元素自身宽度计算高度,不受父元素影响 */.spx-video-player { aspect-ratio: 9/16; } /* 竖屏 *//* CSS 变量动态控制 max-width,PC 端高度不超过 75vh */.spx-video-player.spx-vertical { max-width: calc(75vh * var(--vratio, 0.5625)); margin: 0 auto; }/* --vratio 由 PHP 或 JS 设置为 width/height 比值 *//* 例如 1080x1920 → --vratio: 0.5625 → max-width ≈ 380px */

对于 B2 主题,还需要用 padding-top: 0 !important 覆盖主题自带的 !important 规则,并添加 .spx-adjusted 标记类。

原理 4 — B2 主题 Vue 播放器拦截

问题:B2 主题的 post-style-5 用 Vue.js + DPlayer 播放视频

B2 PRO 主题的视频文章(post-style-5)有一个自己的视频播放器,用 Vue.js 管理。它的 lochostVideo() 方法用 iframe 嵌入,getVideoData() 方法返回视频 ID,setIframe() 方法渲染 iframe。我们想用 API 解析的直链替换 iframe,但不能修改主题文件(主题更新会覆盖)。

方案:el.__vue__ 非侵入式方法拦截

Vue.js 2.x 会在每个组件根元素上挂载 __vue__ 属性指向 Vue 实例。插件通过 document.querySelector('.post-style-5-top').__vue__ 获取实例,然后替换它的三个方法:

var vue = el.__vue__;// 1. 拦截 lochostVideo:抖音 URL 返回 false,阻止主题 iframe 嵌入vue.lochostVideo = function(index) { if (isDouyinUrl(this.videos[index].url)) return false; return origLochost.call(this, index); };// 2. 拦截 getVideoData:传完整 URL(不是数字 ID)给后端 APIvue.getVideoData = function(index) { return { type: 'douyin', id: this.videos[index].url }; };// 3. 拦截 setIframe:调 REST API → DPlayer 播直链,失败 → iframe 兜底vue.setIframe = function(index) { fetch(spxProData.restUrl, { method: 'POST', body: 'url=' + data.id }) .then(d => d.video_url ? initDPlayer(...) : makeIframe(...)); };

这种方式的优点是完全非侵入:不动主题一行代码,插件检测到 B2 主题就自动加载拦截脚本。主题更新后插件仍然正常工作,因为只要 Vue 实例还在 .post-style-5-top 元素上,拦截就能生效。

原理 5 — 多清晰度自动探测

问题:API 可能返回多个清晰度的 URL,格式各异

有的 API 返回索引数组 [{"label":"高清","url":"..."},{"label":"标清","url":"..."}],有的返回键名带清晰度标识 {"url_1080p":"...","url_720p":"..."},有的返回带 height 字段的对象数组。需要统一处理。

方案:三级探测 + 智能标签提取 + 排序

模式 1:索引数组检测
JSON 是 [{...},{...}] 格式,每个元素含视频 URL + quality/label/height 字段 → 直接提取
模式 2:键名清晰度标识
键名含 url_1080p、play_720、url_hd、url_sd 等 → 用正则提取清晰度标签
模式 3:递归 + 回退
递归进入子数组查找;最终回退到 find_url() 单 URL 模式

探测到多个 URL 后,按清晰度从高到低排序(原画 > 1080p > 720p > 480p > 360p)。后台可设默认画质,call_parse_api() 会根据设置自动选择对应的 URL 作为 video_url。所有 URL 都经过 maybe_proxy_url() 包装代理地址。播放器上显示下拉框供用户手动切换。

原版 vs Pro 对比

能力Smartideo 原版Smartideo Pro
视频嵌入方式iframe 仅API 直链播放 + iframe 兜底
CDC 直链代理cURL 流式代理 + Range 透传
API 返回格式配置需手动填 JSON 路径自动探测,无需配置
多清晰度切换自动探测 + 后台默认 + 播放器切换
竖屏视频适配padding-top 百分比(PC 端过高)aspect-ratio + CSS 变量
B2 主题适配Vue 拦截,全部内置
解析缓存Transient 12 小时
备用 API首选失效自动切换备用
REST API/parse + /proxy 两个端点

支持的平台

YouTube 哔哩哔哩 抖音 优酷 腾讯视频 搜狐视频 AcFun 56 视频 网易云音乐 QQ 音乐

二次开发声明

本插件由纯七xzbzq.com)基于 Fens Liu 开发的 Smartideo 插件(7yper.com/3633)进行二次开发。

Smartideo Pro 保留了原版的 oEmbed 处理器注册机制和平台 URL 正则匹配,核心逻辑全部重写。新增了服务端流式代理、API 返回格式自动探测、多清晰度画质切换、B2 主题 Vue 拦截、竖屏视频 aspect-ratio 适配等功能。兼容原插件的后台配置数据,可直接升级替换。

感谢原作者 Fens Liu 的出色工作。原版 Smartideo 的 iframe 嵌入方案作为兜底仍保留在 Pro 版中——当 API 解析失败时自动回退到 iframe,保证视频始终可播放。

更新日志

  • v3.4.0多清晰度画质切换(三级探测 + 后台默认 + 播放器手动切换);Bilibili 默认 API 配置;REST /parse 路由数字 ID 兼容
  • v3.3.0B2 主题适配全部移入插件(REST 端点、JS 补丁、CSS 覆盖),不修改主题文件;适配新抖音解析 API v.xzbzq.com
  • v3.2.0抖音解析改为传完整 URL;setIframe 兜底提取视频 ID;extractVid 辅助函数
  • v3.1.0B2 主题 adjustContainer 从 padding-top 改为 aspect-ratio,修复竖屏视频过高
  • v3.0.0核心重构:cURL 流式代理、find_url 自动探测、maybe_proxy_url 自动代理、build_video_player 自适应播放器