平均响应时间 < 500ms,高并发稳定运行
解析成功率 > 95%,持续优化更新
7x24小时运行,专业运维保障
10 次
次数套餐,约 ¥0.0100/次
30,000 次
包月套餐,约 ¥0.0008/次
180,000 次
包月套餐,约 ¥0.0005/次
2,920,000 次
包月套餐,约 ¥0.0001/次
100 次
次数套餐,约 ¥0.0100/次
1,000 次
次数套餐,约 ¥0.0080/次
5,000 次
次数套餐,约 ¥0.0050/次
10,000 次
次数套餐,约 ¥0.0045/次
50,000 次
次数套餐,约 ¥0.0030/次
100,000 次
次数套餐,约 ¥0.0026/次
需要更多次数?请联系客服获取定制方案
AppID / Key 调用接口,但不要把 AppSecret 写进小程序源码。
需要签名认证时,请放到你自己的后端完成签名后再请求接口。
登录微信公众平台小程序后台,进入 开发管理 / 开发设置 / 服务器域名,添加下面域名。 生产环境必须使用已备案、证书有效的 HTTPS 域名;开发者工具里的“不校验合法域名”只适合本地调试。
| 配置项 | 填写内容 | 用途 |
|---|---|---|
request合法域名 |
https://ck.og1.top |
调用解析接口、余额接口、平台列表接口,例如 /open-api/parse |
downloadFile合法域名 |
https://ck.og1.top直连优先下载时,再添加下方“常见源站 CDN 域名”。 |
优先下载解析结果里的源站直连;直连失败时,再用本站资源代理兜底,例如 /api/resource/preview 或 /d/{id}/download |
uploadFile合法域名 |
不使用上传可不填 | 只有你的小程序需要上传文件到接口域名时才配置 |
socket合法域名 |
不使用 WebSocket 可不填 | 本接口普通解析不需要 WebSocket |
业务域名 |
如果用 web-view 打开 H5 页面,填对应 H5 域名 |
仅 web-view 跳转网页时需要;纯接口调用不需要 |
注意:小程序后台填写的是域名,不要带接口路径;例如填 https://ck.og1.top,不要填 https://ck.og1.top/open-api/parse。
downloadFile合法域名;
如果某个平台直连域名没配置或临时防盗链失败,再自动回退到 https://ck.og1.top 的本站代理下载。
B站视频直链通常要求 Referer: https://www.bilibili.com/,小程序端无法给源站补这个请求头,建议 B站视频保存时代理优先。
downloadFile合法域名)
微信后台只填域名,不填路径和参数。下面是本接口常见返回域名;平台 CDN 会按地区和时间变化,最终以接口实际返回的 video_url、images、resources[].url 的 host 为准。
| 平台 | 常见源站 CDN 域名 |
|---|---|
| 抖音 / 西瓜 / 头条 / 火山 / 皮皮虾 |
https://v3-web.douyinvod.com;
https://v5-dy-o-abtest.zjcdn.com;
https://v26-web.douyinvod.com;
https://v3-default.365yg.com;
https://v9-default.365yg.com;
https://v11-default.365yg.com;
https://p3-sign.douyinpic.com;
https://p6-sign.douyinpic.com;
https://p9-sign.douyinpic.com;
https://p3-sign.toutiaoimg.com;
https://i.snssdk.com;
https://ib.365yg.com;
|
| 快手 |
https://ali2.a.kwimgs.com;
https://tx2.a.kwimgs.com;
https://js2.a.kwimgs.com;
https://p1.a.yximgs.com;
https://p2.a.yximgs.com;
https://p3.a.yximgs.com;
https://kimg1.yximgs.com;
|
| 小红书 |
https://sns-video-bd.xhscdn.com;
https://sns-video-hw.xhscdn.com;
https://sns-video-qc.xhscdn.com;
https://sns-video-v2.xhscdn.com;
https://sns-img-bd.xhscdn.com;
https://sns-img-hw.xhscdn.com;
https://sns-img-qc.xhscdn.com;
https://sns-webpic-qc.xhscdn.com;
https://ci.xiaohongshu.com;
https://qimg.xiaohongshu.com;
|
| 视频号 / 公众号文章 |
https://finder.video.qq.com;
https://findermp.video.qq.com;
https://wxapp.tc.qq.com;
https://vweixinftc.tc.qq.com;
https://mpvideo.qpic.cn;
https://mmbiz.qpic.cn;
https://mmbiz.qlogo.cn;
https://wx.qlogo.cn;
https://ugcws.video.gtimg.com;
https://szextshort.weixin.qq.com;
|
| B站 |
https://upos-sz-mirrorcos.bilivideo.com;
https://upos-sz-mirrorali.bilivideo.com;
https://upos-sz-mirrorhw.bilivideo.com;
https://upos-sz-mirror08c.bilivideo.com;
https://upos-sz-estghw.bilivideo.com;
https://upos-sz-estgoss.bilivideo.com;
https://upos-hz-mirrorakam.akamaized.net;
https://i0.hdslb.com;
https://i1.hdslb.com;
https://i2.hdslb.com;
|
| 微博 |
https://f.video.weibocdn.com;
https://gslb.miaopai.com;
https://wx1.sinaimg.cn;
https://wx2.sinaimg.cn;
https://wx3.sinaimg.cn;
https://wx4.sinaimg.cn;
https://tvax1.sinaimg.cn;
https://tvax2.sinaimg.cn;
|
| 豆包 / 即梦AI |
https://dreamina-sign.byteimg.com;
https://heycan-hgt-sign.byteimg.com;
https://p3-flow-imagex-sign.byteimg.com;
https://p6-flow-imagex-sign.byteimg.com;
https://vcs.zijieapi.com;
https://lf3-static.bytednsdoc.com;
|
推荐用 POST 调用,返回 code = 200 表示成功。
const API_BASE = 'https://ck.og1.top'
const API_KEY = 'YOUR_APP_ID'
function parseVideo(shareUrl) {
return new Promise((resolve, reject) => {
wx.request({
url: API_BASE + '/open-api/parse',
method: 'POST',
header: {
'content-type': 'application/json'
},
data: {
key: API_KEY,
url: shareUrl
},
success(res) {
const body = res.data || {}
if (body.code === 200) {
resolve(body.data)
return
}
reject(new Error(body.msg || body.message || '解析失败'))
},
fail(err) {
reject(err)
}
})
})
}
parseVideo(inputUrl).then(data => {
// 视频直链
const videoUrl = data.video_url || ''
// 图文/图集
const imageUrls = data.image_urls || data.images || []
// 复制文案
const copyText = data.copy_text || data.caption || data.title || ''
this.setData({
result: data,
videoUrl,
imageUrls,
copyText
})
})
保存视频或图片时,推荐先下载解析结果里的原始直连地址;如果直连域名未配置、返回 403 或下载失败,再自动切换到本站代理地址。 这样源站 CDN 能直连时速度最快,不能直连时也不会直接失败。
function toProxyUrl(rawUrl) {
if (!rawUrl) return ''
if (rawUrl.indexOf(API_BASE + '/api/resource/preview') === 0) return rawUrl
return API_BASE + '/api/resource/preview?url=' + encodeURIComponent(rawUrl)
}
function uniqueUrls(urls) {
const result = []
urls.forEach(url => {
url = url ? String(url).trim() : ''
if (url && result.indexOf(url) === -1) result.push(url)
})
return result
}
function isBilibiliProtectedUrl(url) {
return /\/\/[^/]*(?:bilivideo\.com|hdslb\.com|bilibili\.com)(?:[/:?#]|$)/i.test(url || '')
}
function saveByDirectFirst(rawUrl, type = 'video') {
const proxyUrl = toProxyUrl(rawUrl)
const urls = type === 'video' && isBilibiliProtectedUrl(rawUrl)
? uniqueUrls([proxyUrl, rawUrl])
: uniqueUrls([rawUrl, proxyUrl])
const saveApi = type === 'image' ? wx.saveImageToPhotosAlbum : wx.saveVideoToPhotosAlbum
function tryDownload(index) {
const downloadUrl = urls[index]
if (!downloadUrl) {
wx.hideLoading()
wx.showToast({ title: '没有可下载资源', icon: 'none' })
return
}
wx.downloadFile({
url: downloadUrl,
success(res) {
if (res.statusCode === 200 && res.tempFilePath) {
saveApi({
filePath: res.tempFilePath,
success() {
wx.hideLoading()
wx.showToast({ title: '已保存' })
},
fail() {
wx.hideLoading()
wx.showToast({ title: '请先授权相册权限', icon: 'none' })
}
})
return
}
if (index + 1 < urls.length) {
tryDownload(index + 1)
return
}
wx.hideLoading()
wx.showToast({ title: '下载失败', icon: 'none' })
},
fail() {
if (index + 1 < urls.length) {
tryDownload(index + 1)
return
}
wx.hideLoading()
wx.showToast({ title: '下载域名未配置或网络异常', icon: 'none' })
}
})
}
wx.showLoading({ title: '下载中' })
tryDownload(0)
}
如果你的小程序源码现在只下载 video_url 或 image_urls,建议改成“直连优先、本站代理兜底”。
不懂代码也可以按下面步骤操作。
wx.downloadFile
uni.downloadFile
saveVideoToPhotosAlbum
saveImageToPhotosAlbum
video_url
image_urls
downloadUrl
download_url
常见旧代码一般类似这样,只拿短视频平台直链下载:
// 旧写法:只有直连,没有代理兜底
// 直连域名没填到 downloadFile合法域名,或源站临时防盗链,就会保存失败
wx.downloadFile({
url: result.video_url,
success(res) {
wx.saveVideoToPhotosAlbum({
filePath: res.tempFilePath
})
}
})
第二步:新建一个下载工具文件。原生微信小程序可放到 utils/download.js:
const API_BASE = 'https://ck.og1.top'
function toProxyUrl(rawUrl) {
if (!rawUrl) return ''
// 已经是本站代理地址时,不重复套代理
if (rawUrl.indexOf(API_BASE + '/api/resource/preview') === 0) {
return rawUrl
}
const proxyUrl = API_BASE + '/api/resource/preview?url=' + encodeURIComponent(rawUrl)
return proxyUrl
}
function uniqueUrls(urls) {
const result = []
urls.forEach(url => {
url = url ? String(url).trim() : ''
if (url && result.indexOf(url) === -1) {
result.push(url)
}
})
return result
}
function isBilibiliProtectedUrl(url) {
return /\/\/[^/]*(?:bilivideo\.com|hdslb\.com|bilibili\.com)(?:[/:?#]|$)/i.test(url || '')
}
function downloadFileByDirectFirst(rawUrl) {
const proxyUrl = toProxyUrl(rawUrl)
const urls = isBilibiliProtectedUrl(rawUrl)
? uniqueUrls([proxyUrl, rawUrl])
: uniqueUrls([rawUrl, proxyUrl])
return new Promise((resolve, reject) => {
function tryDownload(index) {
const downloadUrl = urls[index]
if (!downloadUrl) {
reject(new Error('没有可下载资源'))
return
}
wx.downloadFile({
url: downloadUrl,
success(res) {
if (res.statusCode === 200 && res.tempFilePath) {
resolve(res.tempFilePath)
return
}
if (index + 1 < urls.length) {
tryDownload(index + 1)
return
}
reject(new Error('下载失败'))
},
fail() {
if (index + 1 < urls.length) {
tryDownload(index + 1)
return
}
reject(new Error('下载域名未配置或网络异常'))
}
})
}
tryDownload(0)
})
}
function saveByDirectFirst(rawUrl, type) {
wx.showLoading({ title: '下载中' })
downloadFileByDirectFirst(rawUrl)
.then(tempFilePath => {
const saveApi = type === 'image' ? wx.saveImageToPhotosAlbum : wx.saveVideoToPhotosAlbum
saveApi({
filePath: tempFilePath,
success() {
wx.hideLoading()
wx.showToast({ title: '保存成功' })
},
fail() {
wx.hideLoading()
wx.showToast({ title: '请授权相册权限', icon: 'none' })
}
})
})
.catch(err => {
wx.hideLoading()
wx.showToast({ title: err.message || '下载失败', icon: 'none' })
})
}
module.exports = {
toProxyUrl,
downloadFileByDirectFirst,
saveByDirectFirst
}
第三步:把页面里原来的直接下载代码替换成下面这样:
const downloader = require('../../utils/download')
// 保存视频:先下载 video_url,失败后自动走本站代理
downloader.saveByDirectFirst(result.video_url, 'video')
// 保存单张图片
const firstImage = (result.image_urls || result.images || [])[0]
downloader.saveByDirectFirst(firstImage, 'image')
如果是图集,需要批量保存图片,可以这样写:
const downloader = require('../../utils/download')
function saveImages(result) {
const images = result.image_urls || result.images || []
if (!images.length) {
wx.showToast({ title: '没有图片', icon: 'none' })
return
}
let index = 0
function saveNext() {
if (index >= images.length) {
wx.showToast({ title: '全部保存完成' })
return
}
const current = images[index]
index += 1
downloader.downloadFileByDirectFirst(current)
.then(tempFilePath => {
wx.saveImageToPhotosAlbum({
filePath: tempFilePath,
complete: saveNext
})
})
.catch(() => {
saveNext()
})
}
saveNext()
}
uni-app 项目可以用下面这版,放到 utils/download.js:
const API_BASE = 'https://ck.og1.top'
export function toProxyUrl(rawUrl) {
if (!rawUrl) return ''
if (rawUrl.indexOf(API_BASE + '/api/resource/preview') === 0) return rawUrl
return API_BASE + '/api/resource/preview?url=' + encodeURIComponent(rawUrl)
}
function uniqueUrls(urls) {
const result = []
urls.forEach(url => {
url = url ? String(url).trim() : ''
if (url && result.indexOf(url) === -1) result.push(url)
})
return result
}
function isBilibiliProtectedUrl(url) {
return /\/\/[^/]*(?:bilivideo\.com|hdslb\.com|bilibili\.com)(?:[/:?#]|$)/i.test(url || '')
}
export function downloadFileByDirectFirst(rawUrl) {
const proxyUrl = toProxyUrl(rawUrl)
const urls = isBilibiliProtectedUrl(rawUrl)
? uniqueUrls([proxyUrl, rawUrl])
: uniqueUrls([rawUrl, proxyUrl])
return new Promise((resolve, reject) => {
function tryDownload(index) {
const downloadUrl = urls[index]
if (!downloadUrl) {
reject(new Error('没有可下载资源'))
return
}
uni.downloadFile({
url: downloadUrl,
success(res) {
if (res.statusCode === 200 && res.tempFilePath) {
resolve(res.tempFilePath)
return
}
if (index + 1 < urls.length) {
tryDownload(index + 1)
return
}
reject(new Error('下载失败'))
},
fail() {
if (index + 1 < urls.length) {
tryDownload(index + 1)
return
}
reject(new Error('下载域名未配置或网络异常'))
}
})
}
tryDownload(0)
})
}
export function saveByDirectFirst(rawUrl, type = 'video') {
uni.showLoading({ title: '下载中' })
downloadFileByDirectFirst(rawUrl)
.then(tempFilePath => {
if (type === 'image') {
uni.saveImageToPhotosAlbum({
filePath: tempFilePath,
success: () => {
uni.hideLoading()
uni.showToast({ title: '保存成功' })
},
fail: () => {
uni.hideLoading()
uni.showToast({ title: '请授权相册权限', icon: 'none' })
}
})
return
}
uni.saveVideoToPhotosAlbum({
filePath: tempFilePath,
success: () => {
uni.hideLoading()
uni.showToast({ title: '保存成功' })
},
fail: () => {
uni.hideLoading()
uni.showToast({ title: '请授权相册权限', icon: 'none' })
}
})
})
.catch(err => {
uni.hideLoading()
uni.showToast({ title: err.message || '下载失败', icon: 'none' })
})
}
uni-app 页面里这样调用:
import { saveByDirectFirst } from '@/utils/download.js'
// 保存视频
saveByDirectFirst(this.result.video_url, 'video')
// 保存图片
saveByDirectFirst(this.result.image_urls[0], 'image')
https://ck.og1.top 都填到 downloadFile合法域名。
如果只填 https://ck.og1.top,也能通过本站代理兜底下载,但速度会受本站服务器带宽影响。
wx.request({
url: 'https://ck.og1.top/open-api/balance',
method: 'GET',
data: {
key: API_KEY
},
success(res) {
if ((res.data || {}).code === 200) {
console.log('余额信息', res.data.data)
}
}
})
| 报错/现象 | 处理方法 |
|---|---|
url not in domain list |
把 https://ck.og1.top 加到小程序后台的 request合法域名,保存后在开发者工具刷新域名信息并重新编译。 |
downloadFile:fail url not in domain list |
如果失败的是源站直连地址,把该 URL 的域名补到 downloadFile合法域名;同时保留 https://ck.og1.top,让 https://ck.og1.top/api/resource/preview 作为代理兜底。 |
request:fail timeout |
检查服务器 HTTPS 证书、接口域名是否能公网访问、服务器防火墙和 Nginx/PHP 超时时间。 |
| 开发工具能请求,真机不行 | 开发工具可能勾选了“不校验合法域名”。真机必须按微信后台的服务器域名配置走。 |
| 图片可以显示但保存失败 | 保存图片/视频前先下载到临时文件;直连保存失败时,检查源站 CDN 域名是否已配置,并确认代码是否已经自动回退到本站代理。 |
接口地址: POST /open-api/parse
请求方式: POST (application/x-www-form-urlencoded 或 JSON)
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| app_id | string | 是 | 应用ID |
| url | string | 是 | 要解析的视频链接 |
| timestamp | int | 是 | 当前时间戳(秒) |
| sign | string | 是 | 签名 |
1. 将参数按key升序排列(不含sign)
2. 拼接成 key1=value1&key2=value2&key=YOUR_APP_SECRET
3. 对拼接字符串进行MD5加密并转大写
示例:
params = {app_id: "WM123456", url: "https://...", timestamp: 1234567890}
signStr = "app_id=WM123456×tamp=1234567890&url=https://...&key=YOUR_APP_SECRET"
sign = MD5(signStr).toUpperCase()
{
"code": 200,
"msg": "success",
"data": {
"type": "video",
"platform": "douyin",
"title": "视频标题",
"author": "作者名称",
"avatar": "作者头像URL",
"cover": "封面图URL",
"video_url": "无水印视频URL",
"music_url": "背景音乐URL",
"images": [],
"live_photos": [
{
"type": "live_photo",
"image_url": "实况静态图片URL",
"video_url": "实况动态视频URL"
}
],
"resources": [
{"type": "video|image|live_photo", "url": "资源URL"}
]
},
"time": "123ms"
}
接口地址: POST /open-api/balance
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| app_id | string | 是 | 应用ID |
| timestamp | int | 是 | 当前时间戳 |
| sign | string | 是 | 签名 |
{
"code": 200,
"msg": "success",
"data": {
"balance": 99.50,
"total_calls": 1000,
"today_calls": 50,
"daily_limit": 0
}
}
| 错误码 | 说明 |
|---|---|
| 200 | 成功 |
| 400 | 参数错误 |
| 401 | 认证失败(app_id无效/签名错误/请求过期) |
| 403 | 权限不足(余额不足/IP限制/平台未授权) |
| 429 | 请求过于频繁 |
| 500 | 解析失败 |