- TypeScript 52.4%
- Python 47.6%
| stodk-py | ||
| stodk-ts | ||
| .gitignore | ||
| LICENSE | ||
| README.md | ||
| RECODE_PLAN.md | ||
███████╗████████╗██████╗ ███████╗ █████╗ ███╗ ███╗███████╗██████╗ ██╗ ██╗
██╔════╝╚══██╔══╝██╔══██╗██╔════╝██╔══██╗████╗ ████║██╔════╝██╔══██╗██║ ██╔╝
███████╗ ██║ ██████╔╝█████╗ ███████║██╔████╔██║███████╗██║ ██║█████╔╝
╚════██║ ██║ ██╔══██╗██╔══╝ ██╔══██║██║╚██╔╝██║╚════██║██║ ██║██╔═██╗
███████║ ██║ ██║ ██║███████╗██║ ██║██║ ╚═╝ ██║███████║██████╔╝██║ ██╗
╚══════╝ ╚═╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═════╝ ╚═╝ ╚═╝
Modern Cross-Platform Streaming & Downloader Engine
Architecture • Sequence • State Machine • Platforms • Resolvers • Quick Start • Terminal UIs • Comparison • Verification • FAQ • Roadmap
🚀 Overview
StreamSDK is a high-performance, cross-platform media discovery and stream downloading engine. It completely supersedes the legacy .NET StoDK by eradicating platform-locked dependencies (Windows WPF, WebView2, COM runtimes) in favor of lightweight, native networking and asynchronous muxing.
StreamSDK is structured as a unified monorepo providing two feature-equivalent, fully tested SDKs:
stodk-ts: Headless TypeScript SDK + interactive React/Ink TSX Terminal UI.stodk-py: Async Python 3.10+ SDK (httpx+pydanticv2) + interactive Rich Terminal UI.
🏗️ System Architecture
flowchart TD
subgraph UI ["🖥️ Interactive Interfaces"]
TUI_TS["TSX TUI (React / Ink)"]
TUI_PY["Python TUI (Rich)"]
CLI["Command Line Interface"]
end
subgraph SDK ["⚡ Core SDK Layer"]
SC_S["SerienStreamClient (serienstream.to / aniworld.to)"]
SC_F["FilmoClient (filmo.to + CSRF /n Minting)"]
end
subgraph RESOLVER ["🔓 Multi-Hoster Stream Resolvers"]
R_VOE["VOE / Byse (ROT13 + Byte-Shift + Base64)"]
R_ST["Streamtape (norobotlink Tokenizer)"]
R_DOOD["Doodstream (pass_md5 + Nonce)"]
R_VID["Vidoza (HTML5 Video Inspector)"]
end
subgraph ENGINE ["🚀 Download & Muxing Pipeline"]
QUEUE["DownloadQueue (Multi-Worker Async Semaphore)"]
FFMPEG["FFmpeg Subprocess Runner (-c copy -stats)"]
PARSER["Real-Time Stderr Progress Parser"]
end
subgraph STORAGE ["💾 Local File System"]
OUT["Sanitized Clean MP4 Files (H.264 / AAC)"]
end
UI --> SDK
SDK --> RESOLVER
RESOLVER --> QUEUE
QUEUE --> FFMPEG
FFMPEG --> PARSER
PARSER -. Progress Stats (FPS / Speed / Bitrate) .-> UI
FFMPEG --> STORAGE
style UI fill:#1e1e2e,stroke:#89b4fa,stroke-width:2px,color:#cdd6f4
style SDK fill:#181825,stroke:#f38ba8,stroke-width:2px,color:#cdd6f4
style RESOLVER fill:#181825,stroke:#a6e3a1,stroke-width:2px,color:#cdd6f4
style ENGINE fill:#181825,stroke:#f9e2af,stroke-width:2px,color:#cdd6f4
style STORAGE fill:#11111b,stroke:#cba6f7,stroke-width:2px,color:#cdd6f4
📡 End-to-End Sequence Diagram
sequenceDiagram
autonumber
actor User
participant App as StreamSDK TUI / Script
participant Site as serienstream.to / filmo.to
participant Hoster as External Hoster (VOE / Byse)
participant FFmpeg as FFmpeg Stream Engine
participant Disk as File Storage
User->>App: Input Title ("Dr. Stone" / "Shutter Island")
App->>Site: Fetch Metadata & Season/Episode List
Site-->>App: Return Titles, Seasons, Available Hoster Chips
User->>App: Select Stream (VOE 720p, German Audio)
App->>Site: Mint Stream URL (POST /n or /redirect/ID)
Site-->>App: Redirect Destination (voe.sx/e/...)
App->>Hoster: Scrape Obfuscated HTML & Scripts
Note over App,Hoster: Multi-Stage Deobfuscation (ROT13, Junk Removal, Reverse B64)
App->>App: Extract Direct HLS Playlist URL (master.m3u8)
App->>FFmpeg: Spawn Subprocess (-i master.m3u8 -c copy -stats)
loop Every 250ms
FFmpeg-->>App: Stderr: frame=... fps=... speed=23.9x size=1.8MB
App-->>User: Live Progress Bar & Stats Update
end
FFmpeg->>Disk: Write Muxed MP4 (Title (Year).mp4)
App-->>User: ✅ Download Completed!
🔄 Download Lifecycle State Machine
stateDiagram-v2
direction TB
[*] --> Idle: Init TUI / CLI SDK
Idle --> Discovering: Input Title or Direct Slug
Discovering --> SeriesView: Discovered TV Show (Seasons & Episodes)
Discovering --> MovieView: Discovered Movie (Direct Video Info)
Discovering --> Error: HTTP 404 / Parse Error
Error --> Idle: Retry Input
SeriesView --> SeasonSelect: Select Season
SeasonSelect --> EpisodeSelect: Select Episode
EpisodeSelect --> LanguageSelect: Select Audio Language
MovieView --> LanguageSelect: Select Audio Language
LanguageSelect --> HosterSelect: Pick Provider (VOE, Streamtape, ...)
HosterSelect --> Resolving: Request Direct Stream
Resolving --> Deobfuscating: Scrape & Deobfuscate Payload
Deobfuscating --> Fallback: Token Expired or Blocked
Fallback --> HosterSelect: Auto-failover to Next Hoster
Deobfuscating --> Muxing: Direct HLS (.m3u8) / MP4
Muxing --> Verifying: FFmpeg Subprocess EOF
Verifying --> Finished: Media Header Verification
Finished --> [*]: Saved Clean MP4 to Disk
🌐 Supported Platforms
Note
Domain Notice:
s.toofficially moved tohttps://serienstream.to. Both SDKs automatically rewrite legacys.torequests to the current endpoint.
🔓 Stream Deobfuscation Engine
StreamSDK resolves streaming endpoints completely headless without launching web browsers.
The VOE Deobfuscator Pipeline
flowchart LR
A["Raw <script> Tag"] --> B["Trim Edge Chars [2:-2]"]
B --> C["ROT13 Letter Shift"]
C --> D["Strip Junk Tokens (@$, ^^, ~@, %?, *~)"]
D --> E["Base64 Decode #1"]
E --> F["Byte Shift: ord(c) - 3"]
F --> G["Reverse String (text[::-1])"]
G --> H["Base64 Decode #2"]
H --> I["Parse JSON: {'source': 'https://...'}"]
style A fill:#313244,stroke:#f38ba8,color:#cdd6f4
style I fill:#313244,stroke:#a6e3a1,color:#cdd6f4
🔍 View Hoster Resolver Specifications
| Hoster | Extraction Technique | Fallback Mechanism |
|---|---|---|
| VOE / Byse | JSON <script type="application/json"> deobfuscation |
Regex search for var a168c Base64 reversed string & 'hls': '...' |
| Streamtape | Regex extracts document.getElementById('norobotlink').innerHTML + token + #ideoooolink |
Direct redirect follow /e/ to /v/ |
| Doodstream | Scrapes /pass_md5/ token, issues authenticated GET with Referer spoofing |
Dynamic random 10-char nonce + timestamp expiration |
| Vidoza | Direct DOM traversal for <video id="player"><source src="..."></video> |
Video tag fallback |
⚡ Interactive Quick Start
🟦 Option A: TypeScript / Node.js (stodk-ts)
1. Installation & Build
cd stodk-ts
npm install
npm run build
2. Launch Interactive TSX Terminal UI
npm run tui
# or directly via npx
npx tsx src/tui/cli.tsx
3. Run Automated Unit Tests
npm test
4. Minimal TypeScript SDK Code Snippet
import {
SerienStreamClient,
FilmoClient,
resolveStreamUrl,
downloadStream
} from 'stodk-ts';
// 1. Discover Series (serienstream.to)
const client = new SerienStreamClient('https://serienstream.to', 'serie/stream');
const series = await client.getSeries('breaking-bad');
console.log(`Discovered ${series.title} (${series.seasonsCount} Seasons)`);
// 2. Fetch Season 1, Episode 1 Streams
const episode = await client.getEpisodeVideoInfo('breaking-bad', 1, 1);
const activeStream = episode.streams[0]!;
// 3. Resolve Direct HLS Stream & Download via FFmpeg
const directUrl = await resolveStreamUrl(activeStream);
await downloadStream({
streamUrl: directUrl,
outputPath: './downloads/BreakingBad_S01E01.mp4',
durationSeconds: 30, // Optional test sample limit
onProgress: (prog) => {
console.log(`Speed: ${prog.speedMultiplier}x | Transferred: ${(prog.outputFileSizeKb / 1024).toFixed(1)} MB`);
}
});
🟨 Option B: Python 3.10+ (stodk-py)
1. Installation & Virtual Environment
cd stodk-py
python -m venv .venv
.\.venv\Scripts\activate # Windows (or source .venv/bin/activate on Linux/macOS)
pip install -e .
2. Launch Interactive Rich Terminal UI
stodk
# or
python -m stodk.tui.cli
3. Run Automated Unit Tests
pytest -v
4. Minimal Python SDK Code Snippet
import asyncio
from stodk import (
FilmoClient,
resolve_stream_url,
download_stream
)
async def main():
# 1. Discover Movie (filmo.to)
client = FilmoClient("https://filmo.to", "movies")
movie = await client.get_filmo_movie_video_info("shutter-island")
print(f"Discovered: {movie.title} ({movie.year}) with {len(movie.streams)} streams")
# 2. Resolve Direct Stream URL
active_stream = movie.streams[0]
direct_hls_url = await resolve_stream_url(active_stream)
print(f"Direct Stream URL: {direct_hls_url[:70]}...")
# 3. Stream & Mux with FFmpeg
def progress_handler(prog):
print(f"Speed: {prog.speed_multiplier:.1f}x | Size: {prog.output_file_size_kb / 1024:.1f} MB")
await download_stream(
stream_url=direct_hls_url,
output_path="./downloads/Shutter_Island_2010.mp4",
duration_seconds=30,
on_progress=progress_handler
)
if __name__ == "__main__":
asyncio.run(main())
🎮 Terminal User Interfaces (TUI)
Both implementations feature keyboard-driven terminal UIs without graphical bloat:
┌─── [ StreamSDK Terminal Interface ] ───────────────────────────────────────────────┐
│ │
│ ? Select Target Platform: › serienstream.to (Series & Anime) │
│ ? Enter Title or Slug : dr-stone │
│ │
│ ✔ Discovered Series: "Dr. Stone" (3 Seasons, 35 Episodes) │
│ │
│ [Season 1: Stone World] ───────────────────────────────────────────────────────── │
│ ▸ S01E01: Stone World [VOE 720p] [Streamtape] [Doodstream] │
│ S01E02: King of the Stone World [VOE 720p] [Streamtape] │
│ S01E03: Weapons of Science [VOE 720p] │
│ │
│ [Active Stream] VOE (German Dub / 720p H.264 AAC) │
│ [Pipeline] Deobfuscating JSON -> Extracted master.m3u8 │
│ │
│ Downloading: Dr. Stone - S01E01 - Stone World.mp4 │
│ [████████████████████████████████████████░░░░░░░░░░] 82.4% (41.2 MB / 50.0 MB) │
│ Speed: 18.4 MB/s (24.2x) | FPS: 576.0 | Bitrate: 4210 kbps | ETA: 00:00:03 │
└────────────────────────────────────────────────────────────────────────────────────┘
⌨️ Interactive Keyboard Controls & Shortcuts
| Key | Context | Action |
|---|---|---|
| ↑ / ↓ | Menu Selection | Move highlighted choice up or down |
| Enter | Input & Menus | Submit text search / Confirm selection |
| q | Download Queue | Gracefully stop queue and exit |
| Ctrl + C | Any | Immediately kill FFmpeg subprocess and clean up partial files |
⚖️ Stack Comparison: TypeScript vs Python
| Feature / Metric | 🟦 TypeScript (stodk-ts) |
🟨 Python (stodk-py) |
|---|---|---|
| Primary Domain | Web integrations, Electron, Node microservices | Data science, background daemons, CLI automation |
| Terminal UI Engine | React + Ink (Component-based reactive TSX) | Rich Console (Thread-safe live renders) |
| Networking Layer | Native fetch with persistent Cookie Jar |
Asynchronous httpx.AsyncClient |
| HTML Parsing Engine | cheerio (Fast v8 jQuery engine) |
beautifulsoup4 (html.parser) |
| Data Validation | Strict TypeScript 5.7 compile-time types | pydantic v2 runtime schema validation |
| Subprocess Runner | execa with asynchronous stderr stream parsing |
asyncio.create_subprocess_exec stream reader |
| Cold Startup Time | ~180 ms (tsx) / ~35 ms compiled bundle |
~110 ms (.venv) |
| Test Suite | 11/11 Vitest unit tests passing | 11/11 Pytest unit tests passing |
🧪 Verification & Benchmarks
All functionality has been verified with live downloads and automated tests:
Test Suite Execution
stodk-ts: 11/11 Vitest unit tests passing (Slug normalization, ROT13/shiftBack, VOE decoder, FFmpeg progress parser).stodk-py: 11/11 Pytest unit tests passing.
Live Download Benchmark (Shutter Island, 2010)
Target URL : https://filmo.to/movies/shutter-island
Hoster : VOE (720p BluRay, English / German tracks)
Resolved URL: https://ugc-cdn-caching-...cloudwindow-route.com/.../master.m3u8
Speed : 23.9x average muxing throughput
Result File : downloads/Shutter Island (2010).mp4 (1.81 MB verified sample)
Video Codec : H.264 (High Profile), 1692x720, 24.0 fps progressive
Audio Codec : AAC (LC), 44.1 kHz, stereo
Exit Code : 0 (Flawless verification via ffprobe)
❓ Frequently Asked Questions & Troubleshooting
1. How do I bypass German ISP DNS blocks (CUII / Clearingstelle)?
Some German ISPs (Vodafone, Telekom, 1&1) poison DNS queries for serienstream.to and aniworld.to. To bypass this without a VPN, configure DNS over HTTPS (DoH) or set your upstream resolver to:
- Cloudflare:
1.1.1.1and1.0.0.1 - Quad9:
9.9.9.9and149.112.112.112
Tip
Both SDK clients work flawlessly over standard DoH proxies and encrypted DNS relays.
2. Why is FFmpeg failing with exit code 4294967274 or 403 Forbidden?
VOE and certain CDN nodes reject custom user agents or malformed -headers parameters sent from FFmpeg subprocesses on Windows.
StreamSDK's built-in downloadStream engine handles header formatting automatically. Ensure you do not inject raw newline characters manually when customizing runner options.
3. Is FFmpeg mandatory? Where do I get it?
Yes, FFmpeg is essential for high-speed multi-threaded stream muxing (-c copy) and combining segmented HLS playlists into continuous MP4 files.
- Windows:
winget install Gyan.FFmpegor download from gyan.dev - Linux:
sudo apt update && sudo apt install -y ffmpeg - macOS:
brew install ffmpeg
4. Can I run StreamSDK completely headless on a Linux server?
Yes! Both SDKs provide zero-dependency library imports that can be incorporated into scripts, Celery task workers, or cron jobs without initiating the Terminal UI.
🗺️ Roadmap
- Ground-up recode of legacy C# .NET StoDK codebase
- Headless TypeScript SDK (
stodk-ts) - Headless Asynchronous Python SDK (
stodk-py) - Multi-platform scrapers (
serienstream.to,aniworld.to,filmo.to) - Direct Hoster deobfuscators (VOE, Streamtape, Doodstream, Vidoza)
- Dual Terminal User Interfaces (Ink TSX & Rich Python)
- Automated Unit Test suites in Vitest and Pytest
- Migration to official
https://serienstream.toendpoint - Direct MP4 fallback worker pool
- Configurable proxy support (SOCKS5 / HTTP)
- Docker container image for automated headless background queues
📁 Repository Structure
StreamSDK/
├── README.md # Interactive Forgejo documentation
├── RECODE_PLAN.md # Master reverse-engineering specification
├── LICENSE # GNU General Public License v3.0
├── .gitignore # Global repository ignores
│
├── stodk-ts/ # TypeScript Implementation
│ ├── src/
│ │ ├── client/ # serienstream.to & filmo.to scrapers
│ │ ├── resolvers/ # VOE, Streamtape, Doodstream, Vidoza
│ │ ├── downloader/ # FFmpeg runner & DownloadQueue
│ │ ├── tui/ # React / Ink TSX Terminal UI
│ │ ├── types/ # Type definitions
│ │ └── utils/ # Crypto, slug, request helpers
│ ├── test/ # Vitest unit & integration tests
│ ├── package.json # Node.js ESM configuration
│ └── tsconfig.json # Strict TypeScript configuration
│
└── stodk-py/ # Python Implementation
├── src/stodk/
│ ├── client/ # Async HTTPX scrapers
│ ├── resolvers/ # Python stream resolvers
│ ├── downloader/ # Async FFmpeg subprocess queue
│ ├── tui/ # Rich interactive Terminal UI
│ ├── types.py # Pydantic v2 data models
│ └── utils/ # Crypto, slug, request helpers
├── tests/ # Pytest unit & integration tests
└── pyproject.toml # Modern Python packaging configuration
⚖️ License & Disclaimer
This project is licensed under the GNU General Public License v3.0 (GPL-3.0). See the LICENSE file for complete details.
Developed and maintained by Maggi (admin@maggi.dev). Built strictly for educational and interoperability research purposes.