尧图精选

基于uni-app的短视频去水印小程序源码实战解析

🕒 发布时间:2026/9/12 8:13:19 📁 来源:尧图网络
简介这份短视频去水印解析客户端源代码基于 uni-app 框架开发面向小程序开发者和工具类应用创业者。代码支持打包为 App并可编译成微信、百度、QQ 等平台小程序覆盖抖音、快手、小红书、微视、秒拍、西瓜视频、今日头条等主流平台解决短视频下载与去水印的核心需求。客户端内置一键保存视频、标题、封面图支持复制解析后的视频或图片链接便于分享与二次转发若个别平台无法解析可在小程序后台配置安全域名如 https://aaaawl.cn以恢复解析功能。压缩包约 27MB以源代码文件为主包含前后端对接字段与域名配置说明便于本地部署和二次修改。目前已有 787 人学习下载适合有一定前端基础、希望快速搭建跨端短视频工具的开发者也是学习 uni-app 多端编译的实用案例。1. 短视频去水印小程序源码到底解决了什么问题做短视频运营或素材整理的人最烦的就是视频画面上挂着别家平台的水印尤其抖音和快手的素材搬到公众号或视频号之前必须去掉原平台 logo。这套优趣短视频去水印解析客户端小程序源码把这件事做成了一套基于 uni-app 的前端工程可以打包成 App也能编译成微信、百度、QQ 等平台的小程序。用户粘贴分享链接点击解析就能拿到无水印视频地址再一键保存到相册或复制链接。源码本身并不复杂但踩坑点不少比如合法域名配置、下载权限、不同平台链接有效期等后面都会一一拆开。对刚接触 uni-app 的开发者来说它也是一份结构清晰、能直接上手的跨端客户端范例对想快速上线 MVP 的团队替换 API 地址即可跑通业务闭环。2. 去水印解析不是 AI 涂抹是顺着分享链接反向拿原片很多人以为去水印是像修图那样把原视频上的 logo 区域用算法抹掉。实际上拿着分享链接去解析时真正在做的是把视频源地址从平台内部接口里重新捞出来水印自然就不存在。大多数平台保存到本地的版本都带水印但 CDN 上其实存在一份无水印原片很多去水印服务就是想办法拿到这份原片的地址。搞清楚这一点再操作这套客户端源码很多疑问都会直接解开。2.1 分享链接背后的视频 ID 与源地址结构不同平台的分享链接格式差别很大但核心逻辑是一致的短链接只是一个入口真正要用的是一串视频 ID 或笔记 ID。抖音的分享链接形如v.douyin.com/xxx快手是v.kuaishou.com/xxx小红书是xhslink.com/xxx。这些短链接会通过 HTTP 302 跳到视频详情页或接口地址详情页 URL 里就藏着作品 ID。常见做法是先展开短链接再从落地页里提取 ID。在命令行里模拟一次展开curl -s -I -A Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) AppleWebKit/605.1.15 \ https://v.douyin.com/example/ | grep -i ^location:-I表示只获取响应头-A用于指定 User-Agent避免平台直接返回异常页grep location则是把跳转后的真实地址过滤出来。展开后的地址里通常包含video/{id}或者?modal_id{id}拿到这个 id 之后再请求平台的 Web 版或 APP 版接口就有机会获得无水印的播放地址。下面是常见平台的分享链接形态与可提取的实体平台分享链接形态展开后实体抖音v.douyin.com/xxx视频详情页含 video_id快手v.kuaishou.com/xxx作品详情接口含 photo_id小红书xhslink.com/xxx笔记详情页含 note_id西瓜视频短链或长链视频详情页含 video_id微视短链作品详情接口注意部分平台的短链展开后页面源码里既有无水印地址也有带水印地址而另一些平台需要模拟 App 的请求头才能拿到。所以真正稳定的做法是放到后端去实现这也是这套小程序源码要把解析请求统一交给一个后端域名的原因。2.2 解析接口如何还原无水印地址这套源码的业务模型很简单客户端把用户粘贴的分享链接发送给统一解析接口接口在服务端完成短链展开、ID 提取、平台接口请求、结果格式化最后返回给前端一份结构化 JSON。服务端之所以优于客户端直接处理是因为微信小程序有合法域名限制而且各平台的风控策略对 Cookie、签名、请求头敏感放在后端更方便统一维护。整个解析流程可以拆成四步用户在小程序页面粘贴分享链接。前端通过uni.request调用解析 API并拼接encodeURIComponent后的链接。后端解析服务对短链接做跳转追踪必要时携带移动端 User-Agent 和 Cookie。后端拿到无水印 URL 后连同标题、封面一起返回前端渲染到页面上。这套源码的价值在于把客户端部分做得很薄不需要处理平台差异也不需要在客户端保存任何密钥。所有平台适配逻辑都被压缩到了服务端前端只维护一套请求代码。2.3 本项目采用的解析请求参数与返回结构以常见写法为例客户端会封装一个utils/parser.js把所有解析请求收敛到同一个函数里。这份源码里的请求参数基本可以按下面的方式组织// utils/parser.js const API_BASE https://aaaawl.cn/api/parse; // 实际源码里注意替换成自己的接口 export function parseVideo(shareUrl) { return new Promise((resolve, reject) { uni.request({ url: ${API_BASE}?url${encodeURIComponent(shareUrl)}, method: GET, timeout: 15000, header: { Content-Type: application/json, X-Client: uni-app, X-Platform: weixin }, success: (res) { if (res.data res.data.code 0) { resolve(res.data.data); } else { reject(new Error((res.data res.data.msg) || 解析失败)); } }, fail: (err) { reject(new Error(网络请求失败)); } }); }); }encodeURIComponent的作用是把链接中的中文、?、等特殊字符转义避免拼到 URL 上被截断timeout建议设为 15 秒因为短链展开和平台接口请求都比较耗时header里的X-Platform是给后端识别来源用的方便后续做数据统计或限流。接口返回的 JSON 结构和字段名各平台解析服务有差异但基本会包含这几个核心字段字段类型含义codenumber0 表示成功非 0 失败msgstring失败原因说明data.titlestring视频标题data.coverstring视频封面图地址data.video_urlstring无水印视频播放地址data.download_urlstring下载直链可能为空拿到这段 JSON 后前端只需要把video_url绑定到video组件再把按钮绑定到保存方法整个去水印客户端的最小闭环就跑通了。3. uni-app 工程怎么把这套解析逻辑落地成小程序页面许多人下载源码后先急着找接口却忽略了工程结构。做小程序开发页面职责如果划分不清楚后期加个“小红书通道”或“历史记录”就会很痛苦。这套源码采用 uni-app 组织项目核心页面集中在pages目录下逻辑代码抽到utils中整体属于轻前端结构。3.1 pages 目录与核心文件职责在 HBuilder X 中导入源码后常见目录结构大致如下路径职责关键点pages/index/index.vue主页包含输入框、解析按钮、结果区绑定shareUrl监听解析结果pages/history/history.vue解析历史记录使用uni.getStorageSync读取本地记录utils/parser.js统一解析接口封装管理 API 地址和请求头utils/platform.js识别平台类型根据链接关键词判断抖音、快手等manifest.json跨端配置微信小程序 AppID、权限声明pages.json页面路由与导航栏配置页面标题和窗口样式在这个结构里parser.js管网络请求index.vue管用户交互页面尽量不堆业务逻辑。这样做的原因是uni-app 编译到微信小程序后页面代码会被重新包装过重的页面逻辑会增大主包体积也更容易在setData时出现性能问题。3.2 输入、解析、播放三段式实现以首页为例核心模板代码大致如下这段代码基本就是这套源码的首页骨架template view classpage view classinput-wrap input classlink-input v-modelshareUrl placeholder粘贴抖音/快手分享链接 / button classparse-btn typeprimary tapstartParse解析/button /view view v-ifloading classloading正在解析.../view view v-else-ifparseResult.video_url classresult video classvideo-box :srcparseResult.video_url controls erroronVideoError /video view classmeta{{ parseResult.title }}/view view classop-row button sizemini tapsaveVideo保存视频/button button sizemini tapcopyLink复制链接/button /view /view /view /templatev-model将输入框内容与shareUrl双向绑定tap在小程序环境里比click更贴近原生触摸事件video组件的controls属性会启用播放控制条error用来捕获播放失败的情况。v-if / v-else-if的渲染逻辑避免了无意义地创建 video 组件防止解析失败时出现黑屏。对应脚本部分的解析方法script import { parseVideo } from /utils/parser.js export default { data() { return { shareUrl: , parseResult: {}, loading: false } }, methods: { async startParse() { if (!/https?:\/\/./.test(this.shareUrl)) { uni.showToast({ title: 请先复制分享链接, icon: none }) return false } this.loading true try { const data await parseVideo(this.shareUrl) this.parseResult data } catch (err) { uni.showToast({ title: err.message || 解析失败, icon: none }) } finally { this.loading false } }, copyLink() { if (!this.parseResult.video_url) return uni.setClipboardData({ data: this.parseResult.video_url }) } } } /script正则https?:\/\/.用来在发起请求前拦截明显非法的输入避免用户拿纯文字或无链接的内容去请求后端。uni.showToast是小程序内的轻提示比alert更符合移动端习惯。copyLink里调用uni.setClipboardData成功后微信会弹出“内容已复制”的提示不需要手动二次 toast。3.3 一键保存视频与相册权限处理保存视频是去水印小程序的核心动作也最容易出问题。实际操作分为两步先用uni.downloadFile将视频下载到临时目录再调用uni.saveVideoToPhotosAlbum写入系统相册。必须注意downloadFile的 URL 域名同样需要在微信公众平台配置为 downloadFile 合法域名否则正式版会直接失败。建议把保存流程写成可复用的方法方便后续在历史页复用async saveVideo() { if (!this.parseResult.video_url) { uni.showToast({ title: 没有可保存的视频地址, icon: none }) return } uni.showLoading({ title: 下载中 }) try { const tempFilePath await this.downloadToTemp(this.parseResult.video_url) await this.saveToAlbum(tempFilePath) uni.showToast({ title: 已保存, icon: success }) } catch (e) { const errMsg e e.errMsg ? e.errMsg : if (errMsg.indexOf(auth) 0) { uni.showToast({ title: 请在设置中允许相册权限, icon: none }) } else { uni.showToast({ title: 保存失败域名或链接可能已失效, icon: none }) } } finally { uni.hideLoading() } }, downloadToTemp(url) { return new Promise((resolve, reject) { uni.downloadFile({ url, success: (res) { if (res.statusCode 200) { resolve(res.tempFilePath) } else { reject(res) } }, fail: reject }) }) }, saveToAlbum(filePath) { return new Promise((resolve, reject) { uni.saveVideoToPhotosAlbum({ filePath, success: resolve, fail: reject }) }) }e.errMsg里如果包含auth deny或auth相关字样基本可以判断是相册权限被拒此时应该引导用户到设置页手动开启。下载返回的状态码不一定总是 200有些 CDN 链接过期后返回 403 或 404这种情况不应该执行保存。还有一点容易被忽略部分平台返回的download_url是带签名的临时链接有效期只有几分钟所以源码里最好在拿到链接后立即下载不要等用户反复观看后再操作。4. 小程序后台域名配置与解析失败排查在 HBuilder X 里运行源码到微信开发者工具很容易真正卡住新手的是小程序后台的域名白名单。很多人在模拟器里点得很顺一到真机预览就“解析失败”多半是合法域名没有配置完整。这套源码用到了https://aaaawl.cn作为解析服务必须把它加到小程序后台。4.1 request、downloadFile、业务域名三处白名单微信小程序在正式环境下会严格校验所有网络请求的域名不支持 IP 地址、不支持端口、不支持http://必须配置 HTTPS 域名。三处配置不能互相替代各自管一段流程域名类型是否必须配置用途request 合法域名必须允许uni.request请求解析 APIdownloadFile 合法域名必须允许uni.downloadFile下载视频uploadFile 合法域名非必须本项目暂不涉及业务域名非必须只有内嵌 web-view 才需要以本项目为例在微信公众平台选择“开发管理 - 开发设置 - 服务器域名”把https://aaaawl.cn同时加到 request 和 downloadFile 合法域名里。操作路径在不同版本后台略有差异但关键词都是“服务器域名”。如果只是本地调试可以在微信开发者工具右上角点击“详情 - 本地设置”勾选“不校验合法域名、web-view、TLS 版本以及 HTTPS 证书”。这个选项只对当前工具窗口生效真机预览不会生效。4.2 解析失败的典型原因与定位步骤结合这套源码最常见的反馈整理一份排查对照表失败现象可能原因处理方法点击解析无反应正则校验未通过或 shareUrl 为空先检查输入框是否有值再确认链接是否有 http 前缀loading 转圈后提示网络请求失败后端接口超时或域名无法访问用浏览器直接访问 API 地址看是否返回 JSON返回“平台不支持”分享链接被截断或该平台未开放解析尽量复制完整的分享口令不要只复制短链解析成功但视频无法播放视频地址带防盗链或签名过期把video_url复制到浏览器访问验证保存视频失败errMsg 包含 auth相册权限未授权引导用户去设置里打开相册权限下载返回 403/404临时链接过期重新解析一次再立即保存需要注意这套源码的解析能力完全依赖后端服务前端看到的“解析失败”很多时候是后端返回了非 0 的code。遇到这种情况优先在 Network 面板里查看响应体而不是反复点按钮。4.3 用开发者工具 Network 面板核对返回数据微信开发者工具自带 Network 面板可以完整看到uni.request发出的请求地址、请求头、返回内容。开启步骤是在开发者工具中点击“调试器 - Network”然后重新点击解析按钮。过滤aaaawl.cn就能找到对应请求点开 Response 标签页可以看到接口返回的 JSON。实际排查中值得关注的是请求头和返回码。如果后端希望区分客户端类型可以在请求中增加自定义 header比如uni.request({ url: API_BASE, data: { url: shareUrl }, method: GET, header: { Content-Type: application/json, X-Platform: weixin, User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) }, success: (res) { console.log([解析返回值], res.data) } })X-Platform字段让后端可以根据平台返回不同的视频清晰度User-Agent可以避免某些风控逻辑直接拦截请求。加上console.log之后即使不用开发者工具逐个点击也能从 Console 面板快速看到返回值结构。这一步对后续修改页面字段非常有帮助因为不同解析服务的 JSON 字段命名可能不同先确认返回字段再绑定前端能省下大量排查时间。5. 把解析客户端扩展成带次数限制和自动校验的商用原型源码规划里有后台管理系统包括用户注册、默认使用次数、用户管理、客服管理等。后台还没开发完之前前端可以先做一层本地次数限制既能防止无节制调用接口又能在后续接入真实用户体系时顺利切换。5.1 在本地预扣次数给后台用户体系留出切换点在startParse方法前加一道额度检查利用uni.getStorageSync读取剩余次数function consumeQuota() { const current uni.getStorageSync(user_quota) if (typeof current ! number || current 0) { uni.showModal({ title: 次数已用完, content: 关注公众号或联系客服获取更多解析次数, showCancel: false }) return false } uni.setStorageSync(user_quota, current - 1) return true }本地次数只是一个临时方案真正的计费应该以后端返回为准。等后台管理系统开发完成把consumeQuota替换为uni.login获取 code再调用后端消费接口即可页面其他部分完全不用改。5.2 用 video 组件错误事件拦截失效链接解析接口返回的播放地址并不保证永远有效带签名的 CDN 地址过几个小时就会过期。与其等用户点保存时报错不如在页面层先捕获播放异常。给video组件绑定的error事件可以这样处理video :srcparseResult.video_url erroronVideoError controls/videoonVideoError() { uni.showToast({ title: 视频流已失效请重新解析, icon: none }) }更严谨的做法是在保存前先用uni.downloadFile做一次试探性下载。如果返回的状态码不是 200说明链接已经失效此时不需要继续向用户展示保存按钮。把校验逻辑放在下载阶段能够同时拦截“域名不合法”和“链接过期”两种情况避免用户反复做无效操作。这一层校验不是多余的生产环境的解析服务往往对应多套 CDN不同平台返回的链接寿命差异极大统一走“下载校验 - 转存相册”的链路最稳妥。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联 返回资讯列表 →