Easydown API

API 文档

你可以在自己的后端、脚本或自动化服务里调用 Easydown API,把公开媒体链接解析成统一的数据结构。

生产环境 Endpoint

POST https://api.easydown.org/api/v1/parse

鉴权方式

把私有 API token 放在 Bearer token 中请求。不要把 ed_live token 暴露在浏览器 JavaScript 里。

Authorization

Bearer ed_live_xxx

Content-Type

application/json

请求格式

curl -X POST https://api.easydown.org/api/v1/parse \
  -H "Authorization: Bearer ed_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://www.instagram.com/reel/..."}'
{
  "url": "https://www.instagram.com/reel/..."
}

各平台支持的链接格式

所有平台都使用同一个解析接口。下面这些格式会被识别为公开单条媒体链接;最终是否返回媒体仍取决于内容是否公开且可解析。

TikTok

支持公开单条视频和图文作品。

tiktok.com/@user/video/{id}tiktok.com/@user/photo/{id}tiktok.com/t/{shortCode}vm.tiktok.com/{code} or other TikTok share links

不支持主页、直播页和 TikTok Lite 页面。

Douyin

支持公开视频、图文、分享短链和部分抖音媒体 CDN 直链。

v.douyin.com/{code}douyin.com/video/{id}douyin.com/share/video/{id}douyin.com/note/{id}douyin.com/share/note/{id}douyin.com/shipin/{id}douyin.com/vsdetail/{id}douyinpic.com / douyinvod.com / douyinstatic.com media URLs

不支持主页、搜索、合集、关注页和直播页。

YouTube

支持公开视频、Shorts 和可解析为视频 ID 的 live 回放链接。

youtu.be/{id}youtube.com/watch?v={id}youtube.com/shorts/{id}youtube.com/live/{id}

不支持播放列表、频道页、社区帖子和私密视频。

X / Twitter

支持带 status ID 的公开帖子链接。

x.com/{user}/status/{id}twitter.com/{user}/status/{id}

不支持主页、搜索页、Spaces 和直接媒体 CDN 链接。

Instagram

支持公开帖子、Reels、视频、图片、图集、embed 和 share 跳转链接。

instagram.com/p/{code}instagram.com/reel/{code}instagram.com/reels/{code}instagram.com/tv/{code}instagram.com/{username}/p/{code}instagram.com/{username}/reel/{code}instagram.com/p/{code}/embedinstagram.com/r/{code}instagram.com/share/...

不支持 Stories、Highlights、主页、私信、Explore 页面和私密内容。

Xiaohongshu

支持公开视频笔记和图文笔记链接。

xhslink.com/{code}xiaohongshu.com/explore/{noteId}xiaohongshu.com/discovery/item/{noteId}Share text containing a Xiaohongshu URL

不支持主页、搜索页、合集和私密笔记。

Bilibili

支持公开视频页、短链、带 bvid 的列表播放页和部分可播放页面。

bilibili.com/video/BV...bilibili.com/video/av...b23.tv/{code}bili.im/{code}bilibili.com/list/...?...bvid=BV...bilibili.com/bangumi/play/ep...bilibili.com/bangumi/play/ss...bilibili.com/cheese/play/ss...

不支持稍后再看列表、收藏夹、主页和没有单个视频标识的列表页。

Kuaishou

支持公开单条快手视频链接和分享文案。

kuaishou.com/short-video/{photoId}kuaishou.com/f/{token}v.kuaishou.com/{token}gifshow.com/fw/photo/{photoId}chenzhongtech.com/fw/photo/{photoId}Share text containing a Kuaishou URL

不支持主页、搜索页、合集、直播页和私密视频。

Weibo

支持公开视频、图片或图集微博正文链接。

weibo.com/{uid}/{postId}weibo.com/{uid}/{mblogid}m.weibo.cn/status/{id}weibo.com/tv/show/1034:{id}video.weibo.com/show?fid=1034:{id}t.cn/{code}mapp.api.weibo.cn/fx/...Share text containing a Weibo URL

不支持主页、搜索页、话题、超话、直播、文章页和合集。

API Key 权限

API key 可以设置过期时间,不填写表示永久有效。你也可以把 key 限制为指定平台;选择全平台表示允许所有支持平台。编辑 key 只会修改名称、过期时间和平台权限,不会改变 token 明文。重置会轮换 token 明文,但保留权限设置。

统一返回结构

{
  "status": 200,
  "data": {
    "platform": "instagram",
    "title": "Example title",
    "thumbnail": "https://...",
    "duration": 12,
    "images": [
      {
        "url": "https://...",
        "width": 1080,
        "height": 1350
      }
    ],
    "videos": [
      {
        "url": "https://...",
        "quality": "HD",
        "mimeType": "video/mp4",
        "width": 1080,
        "height": 1920,
        "hasAudio": true,
        "source": "direct"
      }
    ],
    "audios": []
  },
  "msg": "success"
}
{
  "status": 401,
  "data": null,
  "msg": "Unauthorized",
  "code": "missing_token"
}

返回字段说明

FieldTypeDescription
platformstringNormalized platform name such as instagram or youtube.
titlestringMedia title or caption when available.
thumbnailstringPreview image URL when available.
durationnumberDuration in seconds. Images and galleries usually return 0.
images[]arrayDownloadable image items with url, width, and height.
videos[]arrayDownloadable video items with url, quality, mimeType, dimensions, hasAudio, and source.
audios[]arrayDownloadable audio items when the platform exposes audio separately.

媒体直链下载说明

Easydown 会在 images[]、videos[]、audios[] 中返回媒体资源地址。这些地址来自原平台,可能受到链接时效、防盗链、跨域、Cookie、地区限制或音视频分离等因素影响。

为什么浏览器直连会失败

很多平台 CDN 会校验 Origin、Referer、Cookie、IP 地区和请求头。同一个媒体 URL,在服务端请求可能正常,但在浏览器 JavaScript 中可能出现 CORS、CORP、403、404 或空文件。

推荐后端代理下载流程

  1. 从你的服务端调用 Easydown API,拿到媒体 URL 后只做短期使用。
  2. 用户点击下载时,请求你自己的后端代理接口,并传入媒体 URL 和平台类型。
  3. 你的后端按平台补充请求头,流式读取媒体 URL,并把响应 body 转发给浏览器。
  4. 大视频要转发 Range 请求,方便播放器、下载器续传和分段读取。
  5. 如果媒体 URL 过期,重新调用解析接口刷新 URL 后再下载。

通用规则

  • 浏览器前端直接 fetch 或 download 跨域媒体,可能被 CORS、CORP 或 Referer 策略拦截。
  • 更稳定的方式是由你的后端服务端下载,并按平台补充浏览器 User-Agent 和必要 Referer。
  • 大文件建议使用 streaming 或 Range 请求,不要一次性加载到内存。
  • 媒体 URL 可能短期有效;如果地址失效,请重新调用解析接口刷新。
  • 私密、删除、地区限制、直播、DRM 或版权保护内容可能无法下载。

各平台请求头要求

平台建议请求头是否需要 Cookie特殊处理时效说明
DouyinReferer: https://www.douyin.com/;浏览器 User-Agent;有 Range 时继续转发。通常不需要视频和图文媒体建议由服务端流式下载。链接时效较短,遇到 403 或 404 时重新解析。
TikTokReferer: https://www.tiktok.com/;浏览器 User-Agent。有时需要部分 Web 媒体可能需要用户自己访问上下文中的 tt_chain_token 等 Cookie;地区限制内容需要使用可访问地区的服务端。直连失败时重新解析并重试。
BilibiliReferer: https://www.bilibili.com/;浏览器 User-Agent;转发 Range。部分高清或账号限制流需要DASH 结果可能返回独立视频流和音频流,需要分别下载后用 FFmpeg 合并。签名流过期后需要重新解析。
XiaohongshuReferer: https://www.xiaohongshu.com/;浏览器 User-Agent。有时需要图片和视频 CDN 防盗链较严格,建议通过后端下载。CDN 地址失效后重新解析。
WeiboReferer: https://weibo.com/ 或 https://m.weibo.cn/;浏览器 User-Agent。通常不需要返回多个清晰度时,按业务需要选择对应 URL。图片和视频链接可能过期,重新解析可刷新。
YouTubeReferer: https://www.youtube.com/;Origin: https://www.youtube.com;浏览器 User-Agent。受保护或账号限制内容需要高画质常见音视频分离,需要用 FFmpeg 合并独立流。部分流会绑定地区或 IP,需要使用可访问地区服务端并在必要时重新解析。
InstagramReferer: https://www.instagram.com/;浏览器 User-Agent。有时需要浏览器预览容易遇到 CORS 或 CORP,稳定下载建议走后端代理。CDN URL 可能过期,需要重新解析公开帖子。
KuaishouReferer: https://www.kuaishou.com/;浏览器 User-Agent;转发 Range。通常不需要大文件短视频建议服务端流式下载。媒体链接可能过期,重新解析公开作品链接。
X / TwitterReferer: https://x.com/;浏览器 User-Agent。通常不需要视频资源可能返回多码率,按业务场景选择清晰度。选中的媒体 variant 失败时重新解析。

后端流式下载示例

Node.js / Next.js 代理路由

// app/api/media-proxy/route.js
const PLATFORM_HEADERS = {
  douyin: {
    Referer: 'https://www.douyin.com/',
    'User-Agent': 'Mozilla/5.0 AppleWebKit/537.36 Chrome/120 Safari/537.36',
  },
  tiktok: {
    Referer: 'https://www.tiktok.com/',
    'User-Agent': 'Mozilla/5.0 AppleWebKit/537.36 Chrome/120 Safari/537.36',
  },
  bilibili: {
    Referer: 'https://www.bilibili.com/',
    'User-Agent': 'Mozilla/5.0 AppleWebKit/537.36 Chrome/120 Safari/537.36',
  },
  xiaohongshu: {
    Referer: 'https://www.xiaohongshu.com/',
    'User-Agent': 'Mozilla/5.0 AppleWebKit/537.36 Chrome/120 Safari/537.36',
  },
  weibo: {
    Referer: 'https://weibo.com/',
    'User-Agent': 'Mozilla/5.0 AppleWebKit/537.36 Chrome/120 Safari/537.36',
  },
  youtube: {
    Referer: 'https://www.youtube.com/',
    Origin: 'https://www.youtube.com',
    'User-Agent': 'Mozilla/5.0 AppleWebKit/537.36 Chrome/120 Safari/537.36',
  },
  instagram: {
    Referer: 'https://www.instagram.com/',
    'User-Agent': 'Mozilla/5.0 AppleWebKit/537.36 Chrome/120 Safari/537.36',
  },
  kuaishou: {
    Referer: 'https://www.kuaishou.com/',
    'User-Agent': 'Mozilla/5.0 AppleWebKit/537.36 Chrome/120 Safari/537.36',
  },
  twitter: {
    Referer: 'https://x.com/',
    'User-Agent': 'Mozilla/5.0 AppleWebKit/537.36 Chrome/120 Safari/537.36',
  },
};

export async function GET(request) {
  const { searchParams } = new URL(request.url);
  const mediaUrl = searchParams.get('url');
  const platform = searchParams.get('platform');

  if (!mediaUrl || !platform || !PLATFORM_HEADERS[platform]) {
    return Response.json({ error: 'invalid_request' }, { status: 400 });
  }

  const range = request.headers.get('range');
  const headers = { ...PLATFORM_HEADERS[platform] };
  if (range) headers.Range = range;

  const mediaResponse = await fetch(mediaUrl, { headers });
  if (!mediaResponse.ok || !mediaResponse.body) {
    return Response.json(
      { error: 'download_failed', status: mediaResponse.status },
      { status: 502 }
    );
  }

  const responseHeaders = new Headers();
  const contentType = mediaResponse.headers.get('content-type');
  const contentLength = mediaResponse.headers.get('content-length');
  const contentRange = mediaResponse.headers.get('content-range');

  if (contentType) responseHeaders.set('Content-Type', contentType);
  if (contentLength) responseHeaders.set('Content-Length', contentLength);
  if (contentRange) responseHeaders.set('Content-Range', contentRange);
  responseHeaders.set('Accept-Ranges', 'bytes');
  responseHeaders.set('Cache-Control', 'private, max-age=300');

  return new Response(mediaResponse.body, {
    status: mediaResponse.status,
    headers: responseHeaders,
  });
}

浏览器调用方式

// Browser code: call your own backend, not the platform CDN directly.
const downloadUrl = new URL('/api/media-proxy', window.location.origin);
downloadUrl.searchParams.set('platform', media.platform);
downloadUrl.searchParams.set('url', media.videos[0].url);

window.location.href = downloadUrl.toString();

音视频分离合并

# When video and audio are returned separately, download both files first.
ffmpeg -i video.mp4 -i audio.m4a -c copy output.mp4

常见失败排查

  • 403 通常是缺少 Referer、缺少 User-Agent、链接过期、需要 Cookie 或地区限制。
  • 404 多数是媒体 URL 已过期,请重新解析原始作品链接。
  • CORS 或 CORP 错误说明浏览器不适合直接请求平台 CDN,应走你的后端代理。
  • 空文件或文件不完整,通常是 Range 或 streaming 没有正确转发。

支持平台

TikTokDouyinYouTubeX / TwitterInstagramXiaohongshuBilibiliKuaishouWeibo

计费规则

成功解析 1 次扣 1 credit。解析失败、不支持的链接、鉴权失败和平台响应失败都不会扣 credits。

支持内容范围

API 面向公开单条媒体内容。私密内容、已删除内容、地区限制内容、直播、主页、搜索页和合集页不在支持范围内。

常见错误

HTTPCodeMeaning
401missing_token / invalid_tokenAuthorization header is missing or the token is invalid.
401token_expiredThe API token has passed its expiration date. Edit the key or create a new one.
403platform_not_allowedThe API token is not allowed to access the platform detected from the URL.
402insufficient_creditsThe account does not have enough credits for a successful parse.
400302The URL format is unsupported or not a single supported media post.
200304Easydown could not return downloadable media for this public link.

需要接入帮助?加入 Telegram 或 Discord 咨询。