A highly accurate torrent and video filename parser.
Built from a very large collection of real-world torrents. Handles movies, TV series, anime, multi-language releases, and messy international filenames with a very high title accuracy.
Zero dependencies. <2ms per parse. Works everywhere JavaScript runs.
Try it live in your browser with our interactive demo and playground.
- Very high title accuracy: validated against 10K real production filenames
- Auto-detects content type: movies, series, anime, no hints needed
- 80+ languages: VFF, VOSTFR, MULTi, Latino, DL, DualAudio, and more
- Anime-first-class: fansub conventions, absolute episodes, batch ranges
- Position-independent: handles tracker prefixes, noise, mixed separators
- Per-field confidence: know how certain the parser is about each value
- Plugin system: extend with custom extractors without modifying core
- Zero dependencies: pure TypeScript, ESM + CJS, <55KB bundled
npm install parsium-media
# or
pnpm add parsium-media
# or
yarn add parsium-mediaThe package is published as
parsium-media. A scoped alias@nepiraw/parsiumpoints at the identical build if you prefer it:npm install @nepiraw/parsium.
import { parse } from 'parsium-media';
const result = parse("The.Boys.S05E02.REPACK.1080p.WEB.H264-TyHD.mkv");
// {
// title: "The Boys",
// contentType: "series",
// seasons: [5],
// episodes: [2],
// resolution: "1080p",
// source: "WEB-DL",
// codec: "H.264",
// releaseGroup: "TyHD",
// isRepack: true,
// ...
// }# Parse a single filename
npx parsium-media "Movie.2024.2160p.UHD.BluRay.x265-GROUP"
# JSON output (only present fields)
npx parsium-media "filename.mkv" --json
# Full JSON (all fields including false/empty)
npx parsium-media "filename.mkv" --json-full
# Show per-field confidence scores
npx parsium-media "filename.mkv" --confidence
# Show debug explanation (extractor trace)
npx parsium-media "filename.mkv" --explain
# Batch mode from file (one filename per line)
npx parsium-media --file torrents.txt --json --progressParse a single filename into structured metadata.
import { parse } from 'parsium-media';
const result = parse(
"Superman.2025.MULTi.2160p.UHD.BluRay.REMUX.DV.HDR10.HEVC.TrueHD.Atmos.7.1-FRATERNiTY.mkv"
);
result.title // "Superman"
result.year // 2025
result.contentType // "movie"
result.resolution // "2160p"
result.source // "UHD BluRay"
result.codec // "HEVC"
result.hdr // ["DV", "HDR10"]
result.audio // ["TrueHD", "Atmos"]
result.channels // ["7.1"]
result.isMultiLanguage // true
result.isRemux // true
result.releaseGroup // "FRATERNiTY"Options:
| Option | Type | Default | Description |
|---|---|---|---|
explain |
boolean |
false |
Include extractor debug trace in result |
fieldConfidence |
boolean |
false |
Include per-field confidence scores (0-1) |
// With confidence scores
const result = parse("Movie.2024.1080p.BluRay.x264-GROUP", { fieldConfidence: true });
result.fieldConfidence.title // 0.95
result.fieldConfidence.resolution // 1.0
result.fieldConfidence.source // 1.0
// With explain trace
const result = parse("Movie.2024.1080p.BluRay.x264-GROUP", { explain: true });
result.explanation // [{ extractor: "resolution", value: "1080p", range: [10, 15], confidence: 1.0, reason: "..." }, ...]Parse multiple filenames with optional progress reporting.
import { parseBatch } from 'parsium-media';
const results = parseBatch(filenames, {
onProgress: (done, total) => console.log(`${done}/${total}`),
explain: true,
fieldConfidence: true,
});Create a parser with LRU cache for repeated parsing of the same filenames.
import { createCachedParser } from 'parsium-media';
const parser = createCachedParser(10000); // max 10K entries
parser.parse("filename.mkv"); // parsed
parser.parse("filename.mkv"); // instant cache hit
parser.size; // current cache size
parser.clear(); // clear cacheCreate a custom parser with plugins for extending extraction capabilities.
import { createParser } from 'parsium-media';
import type { ParsiumPlugin } from 'parsium-media';
const myPlugin: ParsiumPlugin = {
name: 'my-plugin',
extractors: [myCustomExtractor],
};
const parser = createParser({ plugins: [myPlugin] });
const result = parser.parse("filename.mkv");See PLUGINS.md for the full plugin API.
| Field | Type | Description |
|---|---|---|
title |
string |
Extracted title (always present) |
altTitle |
string |
Alternative title (e.g., original language title) |
year |
number |
Release year |
contentType |
'movie' | 'series' | 'unknown' |
Auto-detected content type |
contentSubtype |
'anime' |
Subtype when anime signals are detected |
| Field | Type | Description |
|---|---|---|
seasons |
number[] |
Season numbers (e.g., [5] or [1,2,3] for packs) |
episodes |
number[] |
Episode numbers (e.g., [2] or [1,2] for multi-ep) |
episodeRange |
{ from, to } |
Episode range (e.g., E01-E12) |
absoluteEpisode |
number |
Anime absolute episode number |
absoluteEpisodeRange |
{ from, to } |
Anime batch range (e.g., 01~25) |
episodeTitle |
string |
Episode title if present |
date |
string |
Date-based episode (YYYY-MM-DD format) |
isSeasonPack |
boolean |
Full season pack |
isCompleteSeries |
boolean |
Complete series release |
isBatchRelease |
boolean |
Batch release (anime) |
| Field | Type | Description |
|---|---|---|
resolution |
string |
2160p, 1080p, 720p, 480p, etc. |
source |
string |
BluRay, UHD BluRay, WEB-DL, WEBRip, HDTV, etc. |
codec |
string |
x264, x265, H.264, H.265, HEVC, AV1, etc. |
bitDepth |
string |
10-bit, 8-bit, 12-bit |
frameRate |
string |
24fps, 60fps, etc. |
hdr |
string[] |
Atomic, ordered: HDR10, DV, HDR10+, HLG, SDR (e.g. ["DV","HDR10"]) |
| Field | Type | Description |
|---|---|---|
audio |
string[] |
Atomic codecs/layers, e.g. ["DD+","Atmos"], ["TrueHD","Atmos"], ["DTS-HD MA"], ["AAC"] |
channels |
string[] |
All channel layouts found, e.g. ["7.1"], ["7.1","5.1"], ["2.0"] |
| Field | Type | Description |
|---|---|---|
languages |
Language[] |
Detected languages with codes and labels |
isMultiLanguage |
boolean |
MULTi / multi-language release |
isDualAudio |
boolean |
Dual audio (DualAudio, DUAL, DL/ML markers) |
subtitleLanguages |
Language[] |
Detected subtitle languages |
isMultiSubtitle |
boolean |
Multiple subtitle tracks (Multi Subs, MSub, M-SUB) |
| Field | Type | Description |
|---|---|---|
releaseGroup |
string |
Release group name |
editions |
string[] |
Edition labels (Director's Cut, Extended, Remastered...) |
streamingService |
string |
Service (Netflix, Amazon, Disney+, etc.) |
isRemux |
boolean |
REMUX release |
isRepack |
boolean |
REPACK release |
isProper |
boolean |
PROPER release |
is3D |
boolean |
3D release |
isHybrid |
boolean |
Hybrid release |
isUpscaled |
boolean |
AI upscale detected |
| Field | Type | Description |
|---|---|---|
container |
string |
File container (mkv, mp4, avi) |
raw |
string |
Original input string |
warnings |
string[] |
Validation warnings (if any) |
parse("Inception.2010.2160p.UHD.BluRay.REMUX.HDR.HEVC.Atmos-GRAIL.mkv");
// title: "Inception", year: 2010, resolution: "2160p", source: "UHD BluRay",
// isRemux: true, hdr: ["HDR"], codec: "HEVC", audio: ["Atmos"]
parse("Le.Comte.de.Monte-Cristo.2024.MULTi.1080p.BluRay.x264-FRATERNiTY");
// title: "Le Comte de Monte-Cristo", year: 2024, isMultiLanguage: trueparse("The.Boys.S05E02.REPACK.1080p.WEB.H264-TyHD.mkv");
// title: "The Boys", seasons: [5], episodes: [2], isRepack: true
parse("Malcolm.In.The.Middle.S02E19.1080p.AMZN.WEB-DL.DD+5.1.H.264-ViSiON");
// title: "Malcolm In The Middle", streamingService: "Amazon Prime Video",
// audio: ["DD+"], channels: ["5.1"]parse("[SubsPlease] Jujutsu Kaisen 2nd Season - 08 (1080p) [ABC12345].mkv");
// title: "Jujutsu Kaisen", contentType: "series", contentSubtype: "anime",
// seasons: [2], episodes: [8], releaseGroup: "SubsPlease"
parse("[Erai-raws] Oshi no Ko - 01~11 [1080p][Multiple Subtitle]");
// title: "Oshi no Ko", contentType: "series", contentSubtype: "anime",
// absoluteEpisodeRange: { from: 1, to: 11 }, isBatchRelease: trueparse("Film.2024.MULTi.VFF.1080p.WEB-DL.H265-GroupName");
// title: "Film", isMultiLanguage: true, languages: [{ label: "French" }]
parse("Movie.2024.DUAL.1080p.BluRay.x264-GROUP");
// title: "Movie", isDualAudio: trueparse("Last.Week.Tonight.2025.01.15.1080p.WEB.H264-GROUPNAME");
// title: "Last Week Tonight", date: "2025-01-15", contentType: "series"Parsium uses a 5-stage pipeline:
Input → Normalizer → Structural Analyzer → Extractor → Classifier → Validator → Result
- Normalizer: Strips noise (tracker prefixes, URLs), normalizes separators, decodes entities
- Structural Analyzer: Identifies bracket groups and dash positions for context
- Extractor: Runs 15 priority-ordered extractors with consumed-range tracking
- Classifier: Weighted scoring determines content type (movie/series/anime)
- Validator: Cross-field validation and normalization
The title extractor runs last (priority 13) and claims whatever ranges weren't consumed by earlier extractors. This "by-elimination" approach gives Parsium its accuracy edge.
A central field registry (src/field-registry.ts) defines all output fields in one place: their types, categories, display behavior, JSON serialization mode, and default values. The CLI, pipeline assembly, and comparison tools are all driven from this registry, so adding a new field requires only a single entry.
| Priority | Extractor | What it detects |
|---|---|---|
| 1 | Resolution | 2160p, 1080p, 720p, 4K |
| 2 | Source | BluRay, WEB-DL, HDTV |
| 3 | Codec / Date / FPS | x265, H.264 / 2025.01.15 / 24fps |
| 4 | Audio | TrueHD, DTS-HD MA, DD+ |
| 5 | HDR | DV, HDR10, HDR10+ |
| 6 | Language | 80+ langs, scene markers |
| 7 | Year | Position-aware scoring |
| 8 | Edition | Director's Cut, Extended |
| 9 | Misc | REPACK, PROPER, streaming services |
| 10 | Season/Episode | S01E02, packs, ranges |
| 11 | Anime Episode | Absolute eps, batches |
| 12 | Release Group | Trailing dash, fansub brackets |
| 13 | Title | Claims unclaimed ranges |
- Node.js 22+ (or Bun/Deno)
- No native dependencies
Parsium also provides an HTTP API for remote parsing. See the API README for endpoints, deployment, and configuration.
Live API demo: https://api.parsium.nepiraw.com
cd api && pnpm install && pnpm dev
# → Parsium API listening on http://localhost:7002curl -X POST http://localhost:7002/v1/parse \
-H "Content-Type: application/json" \
-d '{"filename": "Movie.2024.1080p.BluRay.x264-GROUP.mkv"}'Endpoints: POST /v1/parse, POST /v1/parse/batch, GET /v1/health, GET /v1/version, GET /v1/openapi.json
Options: full, explain, fieldConfidence (passed via options object in request body)
Deployment: Docker, Vercel, or any Node.js host.