Parse, preview, and download public media from 39 social platforms in one place.
Paste a link or complete app share text, inspect normalized media metadata, process batches, and download supported videos from a clean bilingual web interface.
Live Demo · Quick Start · API Examples · 简体中文
![]() |
![]() |
| Unified parsing workbench | Media preview and normalized metadata |
- Paste a public post URL or the complete share text copied from an app.
- Parse media metadata into one consistent result format.
- Switch to creator-profile mode to browse public posts and profile metadata.
- Preview playable videos and covers directly in the browser.
- Queue up to 40 links in the web interface while preserving result order.
- Download supported media through the server instead of relying on fragile source links.
- Use the Chrome/Edge extension to parse the current tab or a pasted link from the toolbar.
- Switch between English and Simplified Chinese, light and dark themes, on desktop or mobile.
- Includes optional Clerk authentication and a PayPal digital-service checkout with account-linked order history.
The /pricing/ page exposes the complete flow: Clerk sign-in → PayPal Order creation → official PayPal checkout → server-side capture → /billing/success/. Orders are bound to the Clerk user and stored in SQLite; mount a Railway Volume at /data in production. See docs/paypal-review.md for the PayPal review walkthrough and required variables.
| TikTok | Douyin | Telegram | |
| YouTube | Twitter / X | Bilibili | |
| Dailymotion | Twitch | ||
| AcFun | Youku | Tencent Video | |
| SoundCloud | VK | Niconico | Streamable |
| Loom | Kick | BitChute | Bandcamp |
| Odysee | Internet Archive | Imgur | |
| Snapchat | PeerTube | Gab | Truth Social |
| Medal.tv | RuTube | Coub | Odnoklassniki |
| Bluesky | Dropbox | Google Drive |
OmniMedia works with public, login-free media. Paid, private, login-required, geo-restricted, deleted, or DRM-protected content may not be available, and the project does not attempt to bypass those restrictions. Platform behavior can also change without notice. Telegram's public web page may omit the download address for larger media; when that happens, open the post in Telegram instead.
Open the live demo, then paste any supported link or share text into the workbench.
7.43 pda:/ A copied Douyin caption... https://v.douyin.com/xxxxx/ Copy this link...
https://www.tiktok.com/@creator/video/1234567890
https://www.youtube.com/watch?v=xxxxxxxxxxx
https://www.instagram.com/reel/xxxxxxxxxxx/
https://www.bilibili.com/video/BVxxxxxxxxxx
Paste one link per line in the Batch Center. The web interface accepts up to 40 links at a time and processes them in bounded groups.
Switch the workbench to Creator profile, then paste a supported public profile URL. OmniMedia shows the creator's available avatar, bio, verification and public statistics together with a paginated media grid. Each request returns up to 12 public posts; private and login-only profiles are not supported.
The included Chrome/Edge Manifest V3 extension can parse a pasted public link or the active tab URL, then hand downloads off to the full OmniMedia workbench. It does not read page content, browsing history, cookies, credentials, personal messages, or clipboard data. See browser-extension/README.md for local installation and packaging instructions.
Docker is the simplest way to run the complete web application:
git clone https://github.com/xubaoer19940428-creator/omni-media.git
cd omni-media
docker build -t omnimedia .
docker run --rm -p 7860:7860 omnimediaOpen http://localhost:7860.
Requirements: Python 3.10+, Node.js 22+, pnpm, and ffmpeg.
git clone https://github.com/xubaoer19940428-creator/omni-media.git
cd omni-media
corepack enable
cd frontend && pnpm install && pnpm run build && cd ..
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
python app.pyOpen http://localhost:7860. Windows users can activate the environment with
venv\Scripts\activate.
For optional configuration, see .env.example.
The service intentionally supports public, login-free media by default. If
Instagram reports This content may be private, or Instagram may require an active Chrome login, the parser did not receive a valid Instagram session (or
the post is genuinely private).
For a local run, sign in to Instagram in Chrome, fully quit Chrome, then set
YTDLP_COOKIES_FROM_BROWSER=auto explicitly. The app will try Chrome cookies
for Instagram. Browser-cookie forwarding is disabled by default because the
API has no user authentication; only enable it on a private, trusted machine.
If Chrome is still open or the app runs under another OS user, cookie access may
fail; set YTDLP_COOKIES_FROM_BROWSER=off to disable it.
If Instagram reports The platform is rate-limiting this IP, the Instagram
egress address used by the server has been throttled. Waiting may clear a
temporary limit, but retries do not change the egress address. For a deployed
instance, configure YTDLP_PROXY with an HTTP(S) or SOCKS proxy that you
control, then restart the service. The proxy is passed to yt-dlp parsing and
downloads, plus resolved-media direct fetches; it is unset by default.
For Docker, a remote server, or a service account, the host's Chrome profile is
not available inside the container. Export a Netscape-format cookies.txt
from a browser profile you control, mount it read-only, and set for example:
docker run --rm -p 7860:7860 \
-v "$PWD/cookies.txt:/run/secrets/omnimedia-cookies.txt:ro" \
-e YTDLP_COOKIE_FILE=/run/secrets/omnimedia-cookies.txt \
omnimediaTreat this file like a password: never commit it, paste it into chat, or expose it in logs. Cookies only grant the access already held by that account, and private posts still require that account to be authorized to view them.
Railway does not provide a file mount for a normal service. In that case,
base64-encode the same cookies.txt locally and add the result as a Secret
variable named YTDLP_COOKIE_DATA_B64 (not a plain variable):
base64 < cookies.txt | tr -d '\n' | pbcopy # macOS
# Linux: base64 -w 0 cookies.txt | xclip -selection clipboardAfter saving the variable, redeploy the service. The app writes it to a mode- 0600 temporary file for yt-dlp and removes that file when the process exits. Only use this on a private/authenticated deployment: a public unauthenticated API with your Instagram session configured would let anyone request media that your account can view. Rotate the session and remove the variable when you no longer need login-required downloads.
The browser interface uses the same API. All examples below assume a local
server at http://localhost:7860. Replace the example URL with a public link
that you own or are authorized to use.
curl -X POST http://localhost:7860/api/parse \
-H "Content-Type: application/json" \
-d '{"url":"https://www.youtube.com/watch?v=xxxxxxxxxxx"}'The API accepts up to 10 URLs per request.
curl -X POST http://localhost:7860/api/batch-parse \
-H "Content-Type: application/json" \
-d '{"urls":["https://v.douyin.com/xxxxx/","https://www.tiktok.com/@creator/video/1234567890"]}'The profile endpoint returns up to 12 public posts per request. Pass the returned
next_cursor as cursor to load the next page when has_more is true.
curl -X POST http://localhost:7860/api/profile/parse \
-H "Content-Type: application/json" \
-d '{"url":"https://www.tiktok.com/@creator","limit":12,"cursor":0}'Use the original public URL returned by the parse flow:
curl -X POST http://localhost:7860/api/download \
-H "Content-Type: application/json" \
-d '{"original_url":"https://www.youtube.com/watch?v=xxxxxxxxxxx"}'The response contains a download_url. Depending on the deployment, it can be
a local application route or a short-lived absolute URL.
To request a format returned by the parse response, pass its format_id as
format_selector. Video-only formats can be merged with audio using a selector
such as 137+bestaudio/137. To extract a 192 kbps MP3 instead, pass
"audio_only": true; it cannot be combined with format_selector.
Other useful endpoints:
GET /api/health— service healthGET /api/platforms— supported platform registryGET /api/proxy-image?url=...— bounded cover-image proxyPOST /api/gallery/resolve— optional gallery-dl public gallery URL extraction (no API key)
The gallery enhancement uses a locally installed gallery-dl process. If it is not
installed, the endpoint returns 503 without affecting the primary parser or downloader.
Enable it with pip install -r requirements-optional.txt.
Only download content that you own or are authorized to use. You are responsible for complying with platform terms, copyright rules, privacy laws, and local regulations. This project is intended for lawful interoperability, personal tooling, research, and development; it does not provide a right to copy or redistribute third-party content.
The production website records aggregate, query-free page-view analytics to
improve reliability and product usability. Analytics are enabled only on
useomnimedia.com; the browser extension contains no analytics or cross-site
tracking.
Issues and pull requests are welcome. Platform sites change frequently, so a useful bug report should include the platform, a public example URL, the error message, and the time the failure occurred. Never include cookies, credentials, signed download URLs, or other secrets.
OmniMedia is released under the MIT License. Third-party components and their notices are listed in THIRD_PARTY_NOTICES.md.

