去水印解析 API

支持抖音、快手、小红书、微博、B站、视频号、公众号文章等主流平台

免费注册 登录控制台 接口文档

为什么选择我们

极速响应

平均响应时间 < 500ms,高并发稳定运行

高成功率

解析成功率 > 95%,持续优化更新

🛡️
稳定可靠

7x24小时运行,专业运维保障

套餐价格

测试
¥0

10 次

次数套餐,约 ¥0.0100/次

包月基础版
¥25

30,000 次

包月套餐,约 ¥0.0008/次

至尊年卡
¥399

2,920,000 次

包月套餐,约 ¥0.0001/次

体验套餐
¥1

100 次

次数套餐,约 ¥0.0100/次

基础套餐
¥8

1,000 次

次数套餐,约 ¥0.0080/次

标准套餐
¥25

5,000 次

次数套餐,约 ¥0.0050/次

高级套餐
¥45

10,000 次

次数套餐,约 ¥0.0045/次

企业套餐
¥150

50,000 次

次数套餐,约 ¥0.0030/次

旗舰套餐
¥255

100,000 次

次数套餐,约 ¥0.0026/次

需要更多次数?请联系客服获取定制方案

接口文档

小程序对接教程
安全建议:小程序前端可以使用 AppID / Key 调用接口,但不要把 AppSecret 写进小程序源码。 需要签名认证时,请放到你自己的后端完成签名后再请求接口。
1微信小程序后台配置域名

登录微信公众平台小程序后台,进入 开发管理 / 开发设置 / 服务器域名,添加下面域名。 生产环境必须使用已备案、证书有效的 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

下载建议:现在推荐小程序保存资源时“源站直连优先、本站代理兜底”。 直连速度最快,但必须把解析结果里返回的源站 CDN 域名加入 downloadFile合法域名; 如果某个平台直连域名没配置或临时防盗链失败,再自动回退到 https://ck.og1.top 的本站代理下载。 B站视频直链通常要求 Referer: https://www.bilibili.com/,小程序端无法给源站补这个请求头,建议 B站视频保存时代理优先。
常见源站 CDN 域名(填到 downloadFile合法域名

微信后台只填域名,不填路径和参数。下面是本接口常见返回域名;平台 CDN 会按地区和时间变化,最终以接口实际返回的 video_urlimagesresources[].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;
2小程序请求解析接口

推荐用 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)
      }
    })
  })
}
3展示视频、图集和文案
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
  })
})
4下载资源

保存视频或图片时,推荐先下载解析结果里的原始直连地址;如果直连域名未配置、返回 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)
}
5现有小程序怎么改源码

如果你的小程序源码现在只下载 video_urlimage_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')
改完后的域名配置: 想要下载速度最快,就把上面的常见源站 CDN 域名和 https://ck.og1.top 都填到 downloadFile合法域名。 如果只填 https://ck.og1.top,也能通过本站代理兜底下载,但速度会受本站服务器带宽影响。
6查询余额/套餐状态
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)
    }
  }
})
7常见问题
报错/现象 处理方法
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 域名是否已配置,并确认代码是否已经自动回退到本站代理。
1. 视频解析接口

接口地址: POST /open-api/parse

请求方式: POST (application/x-www-form-urlencoded 或 JSON)

请求参数
参数类型必填说明
app_idstring应用ID
urlstring要解析的视频链接
timestampint当前时间戳(秒)
signstring签名
签名算法
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"
}
2. 余额查询接口

接口地址: POST /open-api/balance

请求参数
参数类型必填说明
app_idstring应用ID
timestampint当前时间戳
signstring签名
返回示例
{
    "code": 200,
    "msg": "success",
    "data": {
        "balance": 99.50,
        "total_calls": 1000,
        "today_calls": 50,
        "daily_limit": 0
    }
}
3. 错误码说明
错误码说明
200成功
400参数错误
401认证失败(app_id无效/签名错误/请求过期)
403权限不足(余额不足/IP限制/平台未授权)
429请求过于频繁
500解析失败

支持平台

抖音
快手
小红书
微博
B站
视频号
公众号文章