SubAlchemy ๐งโโ๏ธ
Universal SRT subtitle converter & aggregator for Stremio โ built specifically for Samsung TVs running Tizen 9.
โก๏ธ Install: open the addon in Stremio and click Install. The "Configure" button lets you add optional API keys and pick up to 3 preferred languages.
๐บ Why SubAlchemy?
Samsung Tizen 9 (and several other smart TV platforms) does not support WebVTT (.vtt) or Advanced SubStation Alpha (.ass/.ssa) subtitles inside Stremio. Since 90% of community subtitle uploads โ especially for anime โ are in one of those formats, the TV ends up showing nothing when the user opens the subtitles panel.
SubAlchemy fixes this transparently: it intercepts every /subtitles request, fetches from multiple sources in parallel, converts every format to plain SRT on the fly, and serves the result back to Stremio from its own HTTPS endpoint with the headers Tizen 9 needs (Content-Type: application/x-subrip, Content-Disposition: attachment; filename="...", full CORS, immutable cache).
๐ 5 Subtitle Sources (parallel aggregation)
SubAlchemy queries all 5 providers simultaneously with a per-provider 10s deadline race. Any provider that fails or times out is logged and skipped โ the batch never aborts.
| Provider | Auth required? | Best for |
|---|---|---|
| OpenSubtitles | โ No (keyless, via WARP) | Movies & series |
| AnimeTosho | โ No (HTML scraping) | Anime (Erai-raws, ToonsHub, etc.) |
| SubDL | โ Free API key | Movies & series |
| SubSource | โ Free API key | Community-driven catalog |
| Wyzie | โ Free API key | Anime |
Get free API keys (all optional โ the addon works out-of-the-box without any):
- SubDL โ https://subdl.com/panel/api
- SubSource โ https://subsource.net/ (My Profile)
- Wyzie โ https://store.wyzie.io/redeem
๐ Universal Format Conversion
Every non-SRT subtitle is converted in-memory to clean SRT before being served to Stremio:
| Input format | Source | Conversion |
|---|---|---|
VTT (.vtt) |
Wyzie, SubSource | Regex pipeline: strips WEBVTT header, fixes timestamps (. โ ,), removes cue indices |
ASS / SSA (.ass, .ssa) |
AnimeTosho, SubSource | ass-compiler parses dialogues/slices/fragments โ subsrt-ts builds SRT body |
ZIP (.zip) |
SubSource, SubDL, OpenSubtitles | adm-zip extracts inner file (.srt first, then .ass/.ssa with on-the-fly conversion, then .vtt) |
XZ (.xz) |
AnimeTosho | lzma-native decompresses the .xz-compressed ASS file before conversion |
GZ (.gz) |
OpenSubtitles | zlib.gunzipSync decompresses before UTF-8 normalization |
Smart encoding detection: chardet + BOM sniffing + iconv-lite automatically normalize Shift-JIS, Big5, GBK, EUC-KR, KOI8-R, Windows-1250/1252 โ UTF-8. Accents in PT-BR/ES/FR always render correctly.
Magic-byte format detection: since AnimeTosho URLs end in a numeric file ID (no extension), the converter inspects the first 4 bytes of every download to identify the actual format.
Ad removal: promotional lines and leftover ASS style tags are stripped automatically.
๐ Language Priority Fallback
Pick up to 3 preferred languages in priority order on the configure page. The addon supports 12 languages out of the box:
๐ง๐ท Portuguese (Brazil) ยท ๐ฌ๐ง English ยท ๐ช๐ธ Spanish ยท ๐ซ๐ท French ยท ๐ฉ๐ช German ยท ๐ฎ๐น Italian ยท ๐ฏ๐ต Japanese ยท ๐จ๐ณ Chinese (Simplified + Traditional) ยท ๐ท๐บ Russian ยท ๐ธ๐ฆ Arabic ยท ๐ฎ๐ณ Hindi ยท ๐ฐ๐ท Korean
Fan-sub variants like Brazilian_CR (Erai-raws) and POR-BR (Ironclad) are auto-recognized.
Flow:
- Try each user language in priority order. Stop at the first one with matching subtitles.
- If none match โ fall back to English (tagged
(Fallback)in the UI). - If English also missing โ return empty (no placeholder).
Candidate iteration: if the first subtitle of a language fails to download/convert (e.g. OpenSubtitles .gz returns 401), the handler automatically tries the next one, up to 30 candidates per language โ so you always get a working subtitle even when one source is flaky.
๐ก๏ธ Bypassing Cloud IP Blocks
Cloud-hosted Stremio addons (Render, Heroku, Railway, etc.) often get 403 Forbidden from OpenSubtitles because their IPs are flagged as datacenters.
SubAlchemy solves this with a Docker container running Cloudflare WARP โ all OpenSubtitles traffic is routed through a local SOCKS5 proxy at 127.0.0.1:40000, making the requests appear as legitimate residential traffic. The legacy rest.opensubtitles.org REST API is used with the public VLSub 0.10.3 X-User-Agent header (keyless). On HTTP 401, the provider attempts a one-shot token refresh via the new api.opensubtitles.com/api/v1/login endpoint.
๐บ Tizen 9 Compatibility
The /srt/:subId.srt proxy endpoint sends everything Samsung's player needs:
- โ
Content-Type: application/x-subrip; charset=utf-8 - โ
Content-Disposition: attachment; filename="<id>.srt"(some Tizen firmware refuses to load without an explicit filename) - โ
Full CORS headers (
Access-Control-Allow-Origin: *+ methods + headers + max-age) - โ
OPTIONSpreflight handler returning204 No Content(some Tizen firmware sends a preflight before the GET) - โ
Cache-Control: public, max-age=31536000, immutable(subId is content-addressed โ player can re-fetch on timeline scrub)
๐ Self-Hosting
Option A โ Deploy to Render (recommended, free tier)
- Fork the repository on GitHub.
- Go to https://render.com/ and create a new Web Service.
- Connect your forked repository.
- Runtime: select Docker (not Node) โ Render will detect the
Dockerfileautomatically. - Environment variables (all optional):
ENCRYPTION_KEYโ 64-char hex string for AES-256-GCM config encryption. Generate with:node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"OS_API_KEYโ for OpenSubtitles v2 API fallback (get one at https://www.opensubtitles.com/api)
- Deploy. You'll get a URL like
https://<your-service>.onrender.com. - Share
https://<your-service>.onrender.com/configurewith your users.
โ ๏ธ Since v2.3.2 the addon depends on
lzma-native(native C addon). If the Render build fails with a compile error, add this line to theDockerfilebeforenpm install:RUN apt-get update && apt-get install -y python3 make g++
Option B โ Local development (no Docker)
git clone https://github.com/texugo7badger/subalchemy.git
cd subalchemy
npm install
npm start
Then open http://localhost:7000/configure and add http://localhost:7000/manifest.json to Stremio.
โ ๏ธ Without Docker+WARP, the OpenSubtitles provider may receive
403from cloud-flagged IPs. All other providers work normally.lzma-nativerequires a C/C++ toolchain โ installbuild-essential(Linux) or Xcode CLI tools (macOS).
.env reference (all optional)
PORT=7000
LOG_LEVEL=info
# OpenSubtitles v2 fallback (only used if legacy REST returns 401)
OS_API_KEY=
# Default API keys pre-filled in the UI
SUBDL_API_KEY=
SUBSOURCE_API_KEY=
WYZIE_API_KEY=
# AES-256-GCM encryption for user config in install URL
ENCRYPTION_KEY=
๐๏ธ Architecture
Stremio client โโGET /subtitles/:type/:idโโโถ SubAlchemy (Express)
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 1. Resolve title (Cinemeta / Kitsu) โ
โ 2. Query 5 providers in parallel โ
โ (Promise.all + per-provider 10s) โ
โ 3. Pick best sub by user priority โ
โ 4. Iterate candidates on failure โ
โ 5. Download โ detect compression โ โ
โ decompress .xz/.gz/.zip โ โ
โ convert ASS/VTT/ZIP โ SRT โ
โ 6. Clean ads, store in memory โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
Stremio client โโโHTTPS SRTโโ /srt/<id>.srt
(CORS + Content-Disposition + immutable)
Repository structure
subalchemy/
โโโ addon.js # Express server entrypoint
โโโ manifest.js # Stremio addon manifest
โโโ Dockerfile # node:20-slim + Cloudflare WARP
โโโ entrypoint.sh # Starts dbus + warp-svc + warp-cli + node
โโโ src/
โโโ handlers/subtitles.js # โญ Priority fallback + candidate iteration
โโโ providers/ # 5 subtitle providers (BaseProvider interface)
โโโ converters/ # ASS/VTT/ZIP/XZ/GZ โ SRT pipeline
โโโ cache/ # InflightCache + SubtitleStore (in-memory)
โโโ routes/ # Express routers (stremio/proxy/configure/etc.)
โโโ meta/ # Cinemeta + Kitsu title resolution
โโโ ui/ # /configure HTML page (component-based)
๐ ๏ธ Tech Stack
- Runtime: Node.js 20 (Docker
node:20-slim) - Web server: Express 4
- HTTP client: Axios 1.18
- Proxy:
socks-proxy-agent8 + Cloudflare WARP daemon - HTML scraping: Cheerio 1.2 (AnimeTosho)
- ASS parsing:
ass-compiler0.1 +subsrt-ts2.1 - ZIP extraction:
adm-zip0.5 - XZ decompression:
lzma-native8.0 - GZ decompression: Node.js built-in
zlib - Encoding detection:
chardet2.1 +iconv-lite0.7
๐ค Recommended Companion Addon: SubSense
For the best experience across all your devices, use SubSense alongside SubAlchemy:
- SubSense โ great for PC and Mobile. Fast access to modern formats (VTT/ASS) without conversion overhead.
- SubAlchemy โ essential for Samsung TVs and TV sticks. Fetches the same sources but transmutes them into SRT.
When watching on your TV, just select the subtitle labeled SubAlchemy [...] โ it will load flawlessly.
๐ Support
If SubAlchemy solved your TV's subtitle problem, consider buying the developer a coffee:
๐ https://ko-fi.com/G4H521S5GK
๐ License
MIT โ feel free to fork, modify, and self-host. Pull requests welcome!
