Skip to content
Conduit

mcp server

omnisaver

๐Ÿ—ƒ๏ธ Self-hosted content archiver for Twitter/X, YouTube, XiaoHongShu, WeChat, Reddit, Zhihu & more โ€” no API keys required

yelosheng/omnisavercommunitylistedunreviewed

Set up

Runs on your computer. Pick your agent and operating system.

This project does not publish an install method we can turn into a config. Follow the README instead.

README

synced Oct 25, 2026

OmniSaver โ€” Multi-Platform Content Archiver

A self-hosted content saver for your NAS, home server, or Raspberry Pi. Archive tweets, YouTube videos, XiaoHongShu (ๅฐ็บขไนฆ) posts, WeChat articles, and any webpage โ€” including images and videos โ€” to local storage with one click.

Python License No API Key

ไธญๆ–‡ๆ–‡ๆกฃ


โœจ Features

  • Self-hosted โ€” runs on any Linux box, NAS, or Raspberry Pi
  • No Twitter API key required โ€” uses Playwright browser automation
  • Multi-platform support:
    • Twitter/X โ€” save tweets, full threads, long-form articles, and videos
    • Reddit โ€” save posts, galleries, inline images, videos, and author metadata
    • YouTube โ€” save video metadata, subtitles, and channel info
    • Bilibili (ๅ“”ๅ“ฉๅ“”ๅ“ฉ) โ€” save video metadata and high-quality videos
    • Kuaishou (ๅฟซๆ‰‹) โ€” save videos via Playwright (no cookies needed)
    • Instagram โ€” save reels, image posts, and carousels (with multiple images) via yt-dlp and Playwright
    • Douyin (ๆŠ–้Ÿณ) / TikTok โ€” save videos without watermarks via Playwright (no cookies needed)
    • Weibo (ๅพฎๅš) โ€” save posts, images, and videos via Playwright (no cookies needed)
    • XiaoHongShu (ๅฐ็บขไนฆ) โ€” save image posts and videos via Telegram bot or REST API
    • WeChat articles (ๅพฎไฟกๅ…ฌไผ—ๅท) โ€” save articles with images and formatting
    • Any webpage โ€” Pocket-style read-it-later for any http/https URL; uses Firefox Reader Mode algorithm (Mozilla Readability.js) to extract clean article content with images
  • Full Twitter thread fetching โ€” when Twitter credentials are configured, entire reply chains are saved as a single archive with all media embedded inline
  • Twitter long-form articles โ€” automatically detects and saves full article content from /status/ URLs
  • Twitter video downloads โ€” downloads videos via yt-dlp; authenticated downloads supported when credentials are configured
  • Douyin/TikTok Native Scraper โ€” uses Playwright to bypass API restrictions and fetch unwatermarked videos directly from the original source
  • Unified URL input โ€” paste any supported URL on the homepage; content type is auto-detected
  • Tampermonkey userscript adds save buttons on Twitter/X tweets and YouTube video pages/thumbnails
  • Saves content in multiple formats: plain text, Markdown, Reader-mode HTML
  • Saves complete metadata (author, timestamp, stats) as JSON
  • Built-in task queue with automatic retry on failure (exponential backoff)
  • Redownload tasks โ€” manually trigger a full redownload for any task directly from the Tasks page
  • Web UI with real-time log streaming, task monitoring, and content browsing
  • Saved page shows a platform badge (X, YouTube, Douyin, ๅฐ็บขไนฆ, WeChat, or ๐ŸŒ Web) on each card
  • YouTube descriptions with clickable links โ€” bare URLs in video descriptions are automatically rendered as hyperlinks in the viewer
  • Enhanced search: full-text search across content and article titles; filter by platform (multi-select), date range (quick presets or custom); all filters combine
  • Supports infinite scroll and pagination (toggle per preference)
  • Each archived post gets a unique public share link (/view/<slug>)
  • Change password via the in-app user menu
  • Optional: Android App โ€” native companion client for one-tap sharing via Android share menu (omnisaver-android)
  • Optional: Telegram bot โ€” save content from any supported platform by forwarding links
  • Optional: AI-powered tag generation via Gemini API
  • Optional: video thumbnails via FFmpeg

๐Ÿš€ Quick Start

Prerequisites: Python 3.7+.

  • yt-dlp โ€” required for Twitter/X and XiaoHongShu video downloads: pip install yt-dlp or follow yt-dlp install guide
  • FFmpeg โ€” optional, for video thumbnails
# 1. Clone the repository
git clone https://github.com/yelosheng/omnisaver.git
cd omnisaver

# 2. Install Python dependencies
pip install -r requirements.txt

# 3. Install Playwright browser (required)
python -m playwright install chromium

# 4. Copy and edit the config file
cp config.ini.example config.ini

Web UI

python run_web.py

Open http://localhost:6201 in your browser. Default login: admin / admin.

Change the default password immediately after first login: click the user menu (top-right) โ†’ Change Password.

Docker (Recommended for NAS / Home Server)

Docker is the easiest deployment method. yt-dlp and FFmpeg are included in the image.

The pre-built image is available on Docker Hub โ€” no local build required. docker pull irritable0971/omnisaver:latest

# 1. Clone the repository
git clone https://github.com/yelosheng/omnisaver.git
cd omnisaver

# 2. Copy config
cp config.ini.example config.ini

# 3. Start
docker compose up -d

# 4. Open http://localhost:6201

All data (database, saved content, user credentials) is stored in ./docker-data/ on your host machine and persists across container restarts and rebuilds.

Note: The first build takes several minutes โ€” Playwright downloads Chromium (~200 MB) and yt-dlp is fetched during the build.

Custom port or save path โ€” edit docker-compose.yml before starting:

ports:
  - "8080:6201"          # change left side to use a different host port
volumes:
  - /mnt/nas/twitter:/app/saved_tweets  # point to your NAS or external drive

๐Ÿ–ฑ๏ธ Browser Extension (Tampermonkey) โ€” Best for Desktop

The most convenient way to save content on a desktop browser. A Tampermonkey userscript injects a save button directly below each tweet on Twitter/X and on YouTube video pages. On the YouTube homepage, a save icon appears on video thumbnails on hover.

Install:

  1. Install the Tampermonkey browser extension (Chrome, Firefox, Edge, or Safari)
  2. Start the web UI: python run_web.py
  3. Visit http://localhost:6201/help and click the install link โ€” Tampermonkey will open a confirmation dialog
  4. Click Install โ€” the save button now appears on every tweet automatically

Configure the backend URL (required the first time, or when your server address changes):

  • Click the Tampermonkey icon in your browser toolbar
  • Find the Twitter/X Archiver Save Button script and click the settings icon
  • Click โš™๏ธ ่ฎพ็ฝฎๅŽ็ซฏๅœฐๅ€, then enter your server address

If the server runs on the same machine as your browser, the default http://localhost:6201 works out of the box. For a home server or NAS, use its local IP, e.g. http://192.168.1.100:6201.

The script file is at tampermonkey/twitter-saver.user.js.


๐Ÿ”‘ Twitter/X Credentials (Optional โ€” Enables Full Thread Fetching)

By default, the tool uses Playwright browser automation for scraping. Configuring Twitter cookies enables xreach โ€” a faster scraper that fetches complete reply threads and supports authenticated video downloads.

What credentials unlock:

  • Full thread fetching โ€” entire self-reply chains saved as a single archive
  • Authenticated video downloads via yt-dlp
  • Faster scraping for single tweets
  • Long-form Articles โ€” without cookies X serves only a card preview behind a login wall

Setup (via web UI):

  1. Log in to x.com in your browser
  2. Install Cookie-Editor browser extension
  3. On x.com, click the Cookie-Editor icon โ†’ Export โ†’ Export as JSON โ†’ copy
  4. In the web UI, go to Settings โ†’ Twitter/X Credentials โ†’ paste the JSON โ†’ Save

The tool extracts auth_token and ct0 from the JSON and stores them in config.ini. Credentials persist across restarts.

Note: Twitter sessions expire after weeks or months. If thread fetching stops working, repeat the cookie export and re-paste in Settings.


๐Ÿ‘ฝ Reddit Credentials (Optional but Recommended)

Reddit posts can often be fetched anonymously, but cookies improve share-link resolution and reduce failures on media and profile requests.

What Reddit cookies help with:

  • Resolving reddit.com/r/.../s/... share links to canonical post URLs
  • More reliable image, gallery, and thumbnail downloads
  • Fewer anonymous-access failures when Reddit blocks public JSON endpoints

Setup (via web UI):

  1. Log in to reddit.com in your browser
  2. Install Cookie-Editor browser extension
  3. On reddit.com, click the Cookie-Editor icon โ†’ Export โ†’ Export as JSON โ†’ copy
  4. In the web UI, go to Settings โ†’ Reddit Cookie โ†’ paste the JSON โ†’ Save

The cookie export must include reddit_session. It is stored locally at ~/.agent-reach/reddit/cookies.json.

Optional OAuth fallback: if Reddit starts blocking anonymous JSON access in your environment, set REDDIT_CLIENT_ID and REDDIT_CLIENT_SECRET in the environment before starting OmniSaver.


๐Ÿค– Telegram Bot โ€” Best for Mobile

The most convenient way to save tweets on a phone or tablet. Share any tweet directly to your private Telegram bot using the native Twitter/X share sheet โ€” no URL copying, no app switching.

Setup:

  1. Open @BotFather on Telegram, send /newbot, follow the prompts, and copy the bot token
  2. In the web UI, go to /telegram, paste the token, and click Save & Start Bot
  3. Open your new bot in Telegram and send /start โ€” the first person to do this becomes the permanent owner; only the owner can trigger saves
  4. The bot is now ready โ€” send or forward any twitter.com / x.com link to it and it will reply with a task ID and start saving immediately

On mobile (the main use case):

  1. Open a tweet in the Twitter/X app
  2. Tap the Share icon โ†’ Share via... โ†’ select your Telegram bot from the contact list
  3. The bot receives the link and queues the download โ€” you get a confirmation reply

Bot commands:

  • Any message containing a Twitter/X URL โ†’ queued for archiving
  • Any message containing a YouTube URL โ†’ queued for archiving
  • Any message containing a XiaoHongShu URL โ†’ saved immediately (see XHS section below)
  • Any message containing a WeChat article URL โ†’ queued for archiving
  • /status โ€” shows current queue size

๐Ÿ“ฑ Android App โ€” Mobile Companion Client

For Android users, a dedicated companion mobile application is available:

  • Repository: https://github.com/yelosheng/omnisaver-android
  • Highlights:
    • One-tap sharing from any app (Twitter/X, YouTube, Bilibili, ๅฐ็บขไนฆ, WeChat, Chrome, etc.) directly into your OmniSaver instance via the system Share sheet
    • Real-time task progress tracking and saved archives browsing
    • Configurable server address and API Key authentication

๐Ÿ“• XiaoHongShu (ๅฐ็บขไนฆ) Integration

XHS support is powered by agent-reach and its xiaohongshu-mcp Docker container. Once configured, you can save any XHS post by forwarding the link to the Telegram bot or calling the REST API.

Prerequisites

  • Docker
  • Node.js (for mcporter and yt-dlp via npm)

Setup

1. Install agent-reach

npm install -g agent-reach
agent-reach install

2. Start the XiaoHongShu MCP server

# Pull and start the container (cookies volume-mounted for persistence)
mkdir -p ~/.agent-reach/xhs
docker run -d --name xiaohongshu-mcp \
  -p 18060:18060 \
  -v ~/.agent-reach/xhs/cookies.json:/app/cookies.json \
  xpzouying/xiaohongshu-mcp

3. Configure cookies (login required)

Log in to xiaohongshu.com in your browser, export cookies using Cookie-Editor (JSON format), then:

agent-reach configure xhs-cookies
# Paste the JSON cookie string when prompted
# Then copy it into the container's expected path:
docker exec xiaohongshu-mcp cp /cookies.json /app/cookies.json

4. Register the server globally

Add to ~/.mcporter/mcporter.json:

{
  "mcpServers": {
    "xiaohongshu": { "baseUrl": "http://localhost:18060/mcp" }
  }
}

5. Verify

mcporter call 'xiaohongshu.search_feeds(keyword: "test")'

Saving XHS Posts

Via Telegram bot โ€” forward or paste any XiaoHongShu link. Supported formats:

  • Full URL: https://www.xiaohongshu.com/explore/<id>?xsec_token=...
  • App share text: Title~ http://xhslink.cn/xxx Copy and open in XiaoHongShu! (the short link is extracted and resolved automatically; both xhslink.cn and the older xhslink.com work)

The bot replies with the title, type, file count, and a /view/<slug> link.

Via REST API:

curl -X POST http://localhost:6201/api/submit/xhs \
  -H "Content-Type: application/json" \
  -d '{"url": "https://www.xiaohongshu.com/explore/<id>?xsec_token=<token>"}'

XHS Output Structure

saved_xhs/
โ””โ”€โ”€ 2024-01-15_Post-Title_feedid/
    โ”œโ”€โ”€ content.txt        # Plain text description
    โ”œโ”€โ”€ content.md         # Markdown with author info and stats
    โ”œโ”€โ”€ metadata.json      # Full API response (no comments)
    โ”œโ”€โ”€ avatar.jpg         # Author profile picture
    โ”œโ”€โ”€ images/            # Image posts: 01.webp, 02.webp, โ€ฆ
    โ”œโ”€โ”€ videos/            # Video posts: <title>.mp4
    โ””โ”€โ”€ thumbnails/        # Video cover image

Note: Cookies expire periodically. Re-run the configure step and restart the container when XHS calls start failing.


๐ŸŽฌ YouTube Integration

Save YouTube videos โ€” metadata, subtitles, and channel info are archived automatically.

Saving YouTube Videos

Via Web UI โ€” paste any YouTube URL into the homepage input field. Supported formats:

https://www.youtube.com/watch?v=VIDEO_ID
https://youtu.be/VIDEO_ID
https://www.youtube.com/shorts/VIDEO_ID

Via Tampermonkey userscript โ€” on any YouTube watch page, a save button appears in the action bar. On the homepage, a save icon appears on each video thumbnail on hover.

Via Telegram bot โ€” send or forward any YouTube link.

Via REST API:

curl -X POST http://localhost:6201/api/submit/youtube \
  -H "Content-Type: application/json" \
  -d '{"url": "https://www.youtube.com/watch?v=VIDEO_ID"}'

YouTube Settings

Go to /settings in the web UI to configure an optional YouTube Data API key (used for fetching channel avatars). Get a free key at Google Cloud Console โ†’ Enable "YouTube Data API v3" โ†’ Credentials โ†’ API Key.


๐ŸŒ Web Page Read-It-Later

Save any article or webpage for offline reading โ€” works like Pocket or Instapaper.

Saving Web Pages

Via Web UI โ€” paste any http:// or https:// URL into the homepage input field.

Via Telegram bot โ€” send any webpage link that isn't XHS/WeChat/YouTube/Twitter.

Via REST API:

curl -X POST http://localhost:6201/api/submit \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/article"}'

How It Works

Uses Playwright to render the page (executes JavaScript, triggers lazy-loaded images), then runs Mozilla Readability.js โ€” the same algorithm as Firefox Reader Mode โ€” to extract clean article content. Images are downloaded locally.

Web Page Output Structure

saved_tweets/
โ””โ”€โ”€ YYYY/MM/YYYY-MM-DD_title_hash/
    โ”œโ”€โ”€ content.html       # Reader-mode HTML with inline images
    โ”œโ”€โ”€ content.txt        # Plain text
    โ”œโ”€โ”€ content.md         # Markdown with metadata header
    โ”œโ”€โ”€ metadata.json      # Title, author, sitename, published date, source URL
    โ””โ”€โ”€ images/            # Downloaded images

๐Ÿ“ฐ WeChat Article Integration

Save WeChat public account articles (ๅพฎไฟกๅ…ฌไผ—ๅทๆ–‡็ซ ) with full text, images, and formatting.

Saving WeChat Articles

Via Web UI โ€” paste any WeChat article URL into the homepage input field.

Via Telegram bot โ€” send or forward any mp.weixin.qq.com link.

Via REST API:

curl -X POST http://localhost:6201/api/submit/wechat \
  -H "Content-Type: application/json" \
  -d '{"url": "https://mp.weixin.qq.com/s/ARTICLE_ID"}'

WeChat Output Structure

saved_wechat/
โ””โ”€โ”€ YYYY/MM/YYYY-MM-DD_article_id/
    โ”œโ”€โ”€ content.txt        # Plain text
    โ”œโ”€โ”€ content.md         # Markdown with title, author, publish time
    โ”œโ”€โ”€ metadata.json      # Article metadata
    โ”œโ”€โ”€ images/            # Embedded images
    โ””โ”€โ”€ videos/            # Embedded videos (if any)

โš™๏ธ Configuration

Copy config.ini.example to config.ini and edit as needed.

OptionDescriptionDefault
[storage] base_pathDirectory where tweets are saved./saved_tweets
[storage] create_date_foldersCreate date-based subfolderstrue
[download] max_retriesMax retry attempts on download failure3
[download] timeout_secondsRequest timeout in seconds30
[scraper] use_playwrightUse Playwright browser automation (recommended)true
[scraper] headlessRun browser in headless modetrue
[scraper] debug_modeSave screenshots on errorsfalse
[twitter] auth_tokenTwitter auth_token cookie (optional, enables xreach thread fetching and long-form Articles)unset
[twitter] ct0Twitter ct0 cookie (required together with auth_token)unset
[ai] gemini_api_keyGemini API key (optional, for AI tags)unset
[ai] youtube_api_keyYouTube Data API v3 key (optional, for channel avatars)unset
[telegram] bot_tokenTelegram bot token (optional, for Telegram integration)unset

Environment variable overrides:

VariableDescription
SAVE_PATHOverride save path
USE_PLAYWRIGHTOverride Playwright toggle
PLAYWRIGHT_HEADLESSOverride headless mode
PLAYWRIGHT_DEBUGSet to true to enable debug screenshots
SSL_CERT_PATH / SSL_KEY_PATHEnable HTTPS

๐Ÿ“– Usage

Web Interface

Visit http://localhost:6201 after starting.

RoutePurpose
/Submit any supported URL to start archiving (auto-detects platform)
/tasksView task queue status
/savedBrowse and search all archived content (Twitter, YouTube, XHS, WeChat, Web)
/tagsManage AI-generated tags
/retriesView failed tasks and retry manually
/view/<slug>View any archived post via share link
/debugSystem status and stuck task reset
/telegramTelegram bot configuration
/settingsYouTube API key and XHS auto-save configuration
/helpTampermonkey script installation guide
POST /api/submitSubmit any URL โ€” platform is auto-detected (JSON body: {"url": "..."})
POST /api/submit/xhsSubmit a XiaoHongShu URL (JSON body: {"url": "..."})
POST /api/submit/youtubeSubmit a YouTube URL (JSON body: {"url": "..."})
POST /api/submit/wechatSubmit a WeChat article URL (JSON body: {"url": "..."})

CLI

# Archive a single tweet
python main.py https://x.com/username/status/1234567890

# Skip media downloads
python main.py https://x.com/username/status/1234567890 --no-media

# Specify output directory
python main.py https://x.com/username/status/1234567890 --output /path/to/save

# Show verbose output
python main.py https://x.com/username/status/1234567890 --verbose

Supported URL formats:

https://twitter.com/username/status/1234567890
https://x.com/username/status/1234567890
https://mobile.twitter.com/username/status/1234567890
https://m.twitter.com/username/status/1234567890

๐Ÿ“ Output Structure

saved_tweets/
โ””โ”€โ”€ 2024-01-15_1234567890123456789/
    โ”œโ”€โ”€ content.txt        # Plain text
    โ”œโ”€โ”€ content.html       # Reader-mode HTML
    โ”œโ”€โ”€ content.md         # Markdown
    โ”œโ”€โ”€ metadata.json      # Full metadata (author, timestamp, etc.)
    โ”œโ”€โ”€ avatar.jpg         # Author avatar
    โ”œโ”€โ”€ images/
    โ”œโ”€โ”€ videos/
    โ””โ”€โ”€ thumbnails/        # Video thumbnails (requires FFmpeg)

๐Ÿท๏ธ AI Tag Generation (Optional)

Automatically generates semantic tags after each successful archive to aid categorization and search. Priority order:

  1. Gemini API โ€” set gemini_api_key in config.ini (recommended; generous free tier).
  2. Rule-based โ€” no API key required; uses built-in keyword rules for basic tagging.

Manage tags on the /tags page, or trigger generation for individual items on the /saved page.


๐Ÿ”ง Troubleshooting

Tweet not found โ€” The tweet may have been deleted or made private. Verify the URL is correct and accessible in a regular browser.

Playwright browser not installed โ€” Run python -m playwright install chromium.

Network issues โ€” Check your connection and firewall. If Twitter/X is blocked in your region, configure a proxy before using this tool.

File permission errors โ€” Ensure write permission on the base_path directory and that sufficient disk space is available.

Tasks stuck in processing โ€” Visit /debug in the web UI and use the "Reset Stuck Tasks" function.

Enable debug mode โ€” Set debug_mode = true in config.ini or PLAYWRIGHT_DEBUG=true. Error screenshots will be saved in the project root.


โš ๏ธ Disclaimer

  • For personal archival use only. This tool is intended for saving publicly available content for offline reading and personal research.
  • Comply with platform Terms of Service. Users are solely responsible for their usage and its legal compliance. See Twitter/X ToS, YouTube ToS, and respective platform terms.
  • No commercial use or mass scraping. Do not use this tool for commercial purposes, bulk data collection, ML training, or any form of mass scraping.
  • Respect copyright. All content belongs to its original authors. Do not republish or redistribute without authorization.
  • No liability for misuse. The author accepts no liability for any legal issues, account suspensions, or other consequences arising from misuse.

๐Ÿ“„ License

MIT โ€” see LICENSE.


๐Ÿค Contributing

Bug reports, feature requests, and pull requests are welcome. Please ensure existing tests pass before submitting:

python -m pytest tests/
โ†‘โ†“ navigate openesc close