DEV Community

bo zhang
bo zhang

Posted on AI-assisted

Bilibili API for Public Video URLs: Metadata, DASH, and Media Downloads

Disclosure: I am involved with EasyDown, the API used in the examples below. This post is a practical integration note for developers building around supported public Bilibili URLs.

If you are evaluating a Bilibili API for a product workflow, the hard part is usually not the first HTTP request. It is everything around the request: accepting BV links and short b23.tv links, handling DASH video and audio streams, refreshing expired signed URLs, and giving users a clear answer when a public link cannot be parsed.

This post walks through a small backend pattern for parsing public Bilibili video URLs with EasyDown. The goal is a predictable JSON response that your app can turn into a download, review queue, media archive, clipping workflow, or internal content tool.

The platform endpoint is documented here: EasyDown Bilibili API documentation.

What the Bilibili endpoint accepts

The Bilibili parser supports mainland China Bilibili URL families such as:

  • https://www.bilibili.com/video/BV1sW4y197cE/
  • https://www.bilibili.com/video/av45306969/
  • https://b23.tv/INJgdai
  • bilibili.com/bangumi/play/{id}
  • bilibili.com/cheese/play/{id}

The current documented boundary is important: Bilibili support is for mainland China URLs. bilibili.tv and bili.im international links are not supported by this endpoint.

The request is a normal authenticated JSON call:

POST https://api.easydown.org/api/v1/platforms/bilibili/parse
Authorization: Bearer <token>
Content-Type: application/json

{
  "url": "https://www.bilibili.com/video/BV1sW4y197cE/"
}
Enter fullscreen mode Exit fullscreen mode

A minimal Python client

Keep the API token on the server side and send only supported public URLs to the parser.

import os
import sys
import requests


API_URL = "https://api.easydown.org/api/v1/platforms/bilibili/parse"


def parse_bilibili_url(public_url: str) -> dict:
    token = os.environ["EASYDOWN_API_TOKEN"]

    response = requests.post(
        API_URL,
        headers={
            "Authorization": f"Bearer {token}",
            "Content-Type": "application/json",
        },
        json={"url": public_url},
        timeout=60,
    )

    payload = response.json()

    if response.status_code != 200 or payload.get("status") != 200:
        message = payload.get("msg") or "Bilibili parse failed"
        raise RuntimeError(message)

    return payload["data"]


if __name__ == "__main__":
    if len(sys.argv) != 2:
        print("Usage: python bilibili_parse.py <public-bilibili-url>")
        raise SystemExit(2)

    data = parse_bilibili_url(sys.argv[1])
    media = data.get("media", {})
    platform_data = data.get("platformData", {})

    print("title:", media.get("title") or platform_data.get("title"))
    print("thumbnail:", media.get("thumbnail") or platform_data.get("pic"))
    print("duration:", media.get("duration"))

    for video in media.get("videos", []):
        print("video:", video.get("quality"), video.get("mimeType"), video.get("url"))

    for audio in media.get("audios", []):
        print("audio:", audio.get("quality"), audio.get("mimeType"), audio.get("url"))
Enter fullscreen mode Exit fullscreen mode

Run it like this:

export EASYDOWN_API_TOKEN="your_api_token"
python bilibili_parse.py "https://www.bilibili.com/video/BV1sW4y197cE/"
Enter fullscreen mode Exit fullscreen mode

Handling DASH video and audio

Bilibili videos often expose DASH streams, where video and audio can be separate entries. In that case, your backend should choose compatible video and audio renditions, download both streams, and merge them with FFmpeg without re-encoding when possible.

A simple production flow looks like this:

  • parse the original public Bilibili URL
  • select the best video rendition your product needs
  • select a matching audio rendition when the video stream has no embedded audio
  • download with a Bilibili Referer, a browser-like User-Agent, and forwarded Range headers
  • merge separate streams with FFmpeg when needed
  • store only the finished file or the normalized metadata your app actually needs

This is where a Bilibili API saves work. The app code can focus on media policy, storage, retries, and user experience instead of maintaining every Bilibili URL family and stream shape by hand.

Failure handling

Do not treat every parse failure as an outage. For Bilibili, separate predictable product states:

  • the pasted URL is not a supported Bilibili video, bangumi, cheese, or b23.tv link
  • the content is private, deleted, paid, DRM-protected, or region restricted
  • the upstream page is temporarily unavailable
  • a signed media URL expired and the original page needs to be parsed again
  • the request failed validation or authentication

EasyDown documents that a response is charged only after downloadable media is returned. Validation, authentication, unavailable content, no-media, and upstream failures are not charged.

When to use a hosted API

If you are building a public Bilibili downloader page, a content ingestion workflow, a moderation tool, a media archive, or a creator operations dashboard, a hosted API is useful when Bilibili is one platform in a wider pipeline.

For one-off manual downloads, a web tool can be enough. For a product backend, an API gives you a clearer contract: send a public URL, receive normalized media, platform data, and predictable error behavior.

EasyDown publishes credit packs and monthly plans on the API pricing page. At the time I checked the documentation, one successful parse consumed one credit, and failed parses were not charged.

The search intent around this topic is mixed. Some people search for download bilibili video because they need a free tool. Others search for bilibili api because they are deciding how to build a backend workflow. I would keep the article, title, and links aligned with the second group: developers who need predictable parsing for supported public Bilibili URLs.

Top comments (0)