# oleoo

> 🏴‍☠️✨🎟 Oleoo - Scene/P2P/Warez release name parser

Latest version **3.0.0** (published 2026-09-23) · MIT license · 0 weekly downloads

## Install

```sh
npm install oleoo
pnpm add oleoo
yarn add oleoo
bun add oleoo
```

## Health

**Score 70/100 (B)** — status: active.

Positive: has types; esm support; no vulnerabilities; recently updated; high maintenance score; high quality score.

Warnings: low downloads.

## Facts

| | |
|---|---|
| Version | 3.0.0 |
| Published | 2026-09-23 |
| First published | 2018-04-10 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Dependencies | 0 |
| Unpacked size | 74.4 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 64 |
| Author | thcolin |
| Maintainers | thcolin |
| Keywords | torrent, p2p, scene, release, warez |

## Links

- npm: https://www.npmjs.com/package/oleoo
- Repository: https://github.com/thcolin/oleoo
- Homepage: https://github.com/thcolin/oleoo#readme
- Issues: https://github.com/thcolin/oleoo/issues
- npm.io page: https://npm.io/package/oleoo

## Recent versions

- 3.0.0 (latest) — 2026-09-23
- 2.1.0 — 2026-09-23
- 2.0.4 — 2025-06-18
- 2.0.3 — 2025-05-22
- 2.0.2 — 2025-05-19
- 2.0.1 — 2025-05-15
- 2.0.0 — 2025-05-13
- 1.1.7 — 2024-06-01
- 1.1.6 — 2024-05-15
- 1.1.5 — 2024-05-15
- 1.1.4 — 2024-05-15
- 1.1.3 — 2024-05-15
- 1.1.2 — 2024-05-14
- 1.1.1 — 2024-04-24
- 1.1.0 — 2024-04-24
- … 15 more at https://npm.io/package/oleoo/versions

## README

# Oleoo

[![npm version](https://img.shields.io/npm/v/oleoo.svg)](https://www.npmjs.com/package/oleoo)
[![crates.io](https://img.shields.io/crates/v/oleoo.svg)](https://crates.io/crates/oleoo)
[![Go Reference](https://pkg.go.dev/badge/github.com/thcolin/oleoo/packages/go/v3.svg)](https://pkg.go.dev/github.com/thcolin/oleoo/packages/go/v3)
[![Fixtures](https://img.shields.io/badge/fixtures-6697%20releases-blue.svg)](./tests/fixtures/releases.txt)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE.md)
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/thcolin/oleoo)

<div align="center">
<pre>
  
 ▒█████   ██▓    ▓█████  ▒█████   ▒█████ 
▒██▒  ██▒▓██▒    ▓█   ▀ ▒██▒  ██▒▒██▒  ██▒
▒██░  ██▒▒██░    ▒███   ▒██░  ██▒▒██░  ██▒
▒██   ██░▒██░    ▒▓█  ▄ ▒██   ██░▒██   ██░
░ ████▓▒░░██████▒░▒████▒░ ████▓▒░░ ████▓▒░
░ ▒░▒░▒░ ░ ▒░▓  ░░░ ▒░ ░░ ▒░▒░▒░ ░ ▒░▒░▒░ 

┌─────────────────────────────────────┐
| Scene/P2P/Warez release name parser |
└─────────────────────────────────────┘
</pre>
🏴‍☠️✨🎟 - Named after an old French warez forum <a href="http://www.01net.com/actualites/oleoo-ferme-sa-section-illegale-de-telechargement-de-films-382090.html">closed in 2008</a>
</div>

Oleoo parses media release names (movies and TV shows from scene/P2P sources) and extracts structured metadata: title, year, quality, language, and more, across many common (and uncommon) naming conventions.

It exists in **JavaScript**, **Go** and **Rust**. The three packages read the same [`rules.json`](./rules.json), follow the same [`SPEC.md`](./SPEC.md), and give the same result on the 6697 releases of [`tests/fixtures/`](./tests/fixtures). They share one version number and are released together.

| Language | Package | Directory | Regex engine |
|---|---|---|---|
| JavaScript | [`oleoo`](https://www.npmjs.com/package/oleoo) on npm, zero dependency | [`packages/js`](./packages/js) (reference) | built-in `RegExp` |
| Go | [`github.com/thcolin/oleoo/packages/go/v3`](https://pkg.go.dev/github.com/thcolin/oleoo/packages/go/v3) | [`packages/go`](./packages/go) | [`dlclark/regexp2`](https://github.com/dlclark/regexp2) |
| Rust | [`oleoo`](https://crates.io/crates/oleoo) on crates.io | [`packages/rust`](./packages/rust) | [`fancy-regex`](https://github.com/fancy-regex/fancy-regex) |

## Features

* **Comprehensive Metadata Extraction** identifying:
  * Title (with intelligent cleaning and formatting)
  * Alternative Title (from parentheses, brackets, or after `-`)
  * Year (including ranges like `2001-2003` for `COLLECTION`)
  * Type (**only** `movie` or `tvshow`)
  * Source (BluRay, WEB-DL, HDTV, CAM, etc.)
  * Resolution (1080p, 720p, 4K/2160p, SD, etc.)
  * Encoding (x264, x265/HEVC, XviD, etc.)
  * Audio details (AC3, DTS, AAC, Atmos, channels like 5.1, etc.)
  * Language(s) (MULTi, MULTi-VFF, MULTI-VF2, FRENCH, VOSTFR, VFQ, TRUEFRENCH, ENGLiSH, etc., including combinations)
  * Season and Episode number(s) for TV shows (handles various formats like S01E01, S01E01-E03, 1x01)
  * Release Group
  * Numerous Flags (Extended, Unrated, Director's Cut, Repack, Proper, Collection, Internal, 3D, HDR, Remux, etc.)
* **Robust Parsing:** Handles various delimiters (`.`, ` `, `-`, `_`) and common scene/P2P naming patterns.
* **Flexible Modes:**
    * `parse()`: Strict parsing based on recognized tags.
    * `guess()`: Best-effort parsing that fills in missing year/resolution details.
* **Standardized Output:** Generates a clean, standardized filename based on extracted data.
* **Customizable:** Allows providing default values and custom patterns to erase before parsing.

## Installation

```bash
# JavaScript
yarn add oleoo   # or: npm install oleoo

# Go (1.26 or later)
go get github.com/thcolin/oleoo/packages/go/v3

# Rust
cargo add oleoo
```

## Basic Usage

### JavaScript

```javascript
import oleoo from 'oleoo'

oleoo.parse('Mr.Robot.S01.PROPER.VOSTFR.720p.WEB-DL.DD5.1.H264-ARK01')
// {
//   "original": "Mr.Robot.S01.PROPER.VOSTFR.720p.WEB-DL.DD5.1.H264-ARK01",
//   "language": "VOSTFR",
//   "languages": ["VOSTFR"],
//   "source": "WEB-DL",
//   "encoding": "h264",
//   "resolution": "720p",
//   "dub": null,
//   "year": null,
//   "flags": ["PROPER", "DD5.1"],
//   "season": 1,
//   "episode": null,
//   "episodes": [],
//   "type": "tvshow",
//   "group": "ARK01",
//   "title": "Mr Robot",
//   "generated": "Mr.Robot.S01.PROPER.VOSTFR.720p.WEB-DL.DD5.1.h264-ARK01",
//   "score": 6
// }

oleoo.parse('Zero Dark Thirty (2012) [1080p BluRay HDR] [FR(VFF)-EN] [x265 10-bit AC3] [GWEN]')
// {
//   "original": "Zero Dark Thirty (2012) [1080p BluRay HDR] [FR(VFF)-EN] [x265 10-bit AC3] [GWEN]",
//   "language": "MULTi-VF2",
//   "languages": ["TRUEFRENCH", "FRENCH", "ENGLiSH"],
//   "source": "BLURAY",
//   "encoding": "x265",
//   "resolution": "1080p",
//   "dub": "AC3",
//   "year": "2012",
//   "flags": ["10bit", "HDR"],
//   "season": null,
//   "episode": null,
//   "episodes": [],
//   "type": "movie",
//   "group": "GWEN",
//   "title": "Zero Dark Thirty",
//   "generated": "Zero.Dark.Thirty.2012.MULTi-VF2.1080p.10bit.BLURAY.HDR.x265.AC3-GWEN",
//   "score": 8
// }

oleoo.guess('My Movie (2023)', { defaults: { language: 'ENGLiSH', resolution: 'SD' } })
// {
//   "original": "My Movie (2023)",
//   "language": "ENGLiSH",
//   "languages": [],
//   "source": null,
//   "encoding": null,
//   "resolution": "SD",
//   "dub": null,
//   "year": "2023",
//   "flags": [],
//   "season": null,
//   "episode": null,
//   "episodes": [],
//   "type": "movie",
//   "group": null,
//   "title": "My Movie",
//   "generated": "My.Movie.2023.ENGLiSH-NOTEAM",
//   "score": 1
// }

try {
  oleoo.parse('Not.a.Movie-v28.1-macOS', { strict: true })
} catch (error) {
  console.error(error.message)
  // "Not.a.Movie-v28.1-macOS" does't follow scene release naming rules
}
```

### Go

Options are functions, `Parse` and `Guess` return an `error` instead of throwing, and a `null` field is a `nil` pointer. A `Release` marshals to the same JSON as the JavaScript result.

```go
import "github.com/thcolin/oleoo/packages/go/v3"

release, err := oleoo.Parse("Mr.Robot.S01.PROPER.VOSTFR.720p.WEB-DL.DD5.1.H264-ARK01")
if err != nil {
	log.Fatal(err)
}

fmt.Println(release.Title, *release.Season, *release.Language, *release.Resolution)
// Mr Robot 1 VOSTFR 720p
fmt.Println(release.Generated)
// Mr.Robot.S01.PROPER.VOSTFR.720p.WEB-DL.DD5.1.h264-ARK01

language := "ENGLiSH"
guessed, _ := oleoo.Guess("My Movie (2023)", oleoo.Defaults(oleoo.Release{Language: &language}))
fmt.Println(guessed.Generated)
// My.Movie.2023.ENGLiSH-NOTEAM

_, err = oleoo.Parse("Not.a.Movie-v28.1-macOS", oleoo.Strict(true))
fmt.Println(err)
// "Not.a.Movie-v28.1-macOS" does't follow scene release naming rules
```

The options are `Strict(bool)`, `Flagged(bool)`, `Erase(patterns ...string)`, `Defaults(Release)` and `CurrentYear(int)`.

### Rust

`parse` and `guess` take an `Options` and return a `Result`. `Release` implements `serde::Serialize` and serializes to the same JSON as the JavaScript result.

```rust
use oleoo::{guess, parse, Defaults, Options};

let release = parse("Mr.Robot.S01.PROPER.VOSTFR.720p.WEB-DL.DD5.1.H264-ARK01", &Options::default())?;

println!("{} {:?} {:?} {:?}", release.title, release.season, release.language, release.resolution);
// Mr Robot Some(1) Some("VOSTFR") Some("720p")
println!("{}", release.generated);
// Mr.Robot.S01.PROPER.VOSTFR.720p.WEB-DL.DD5.1.h264-ARK01

let options = Options {
    defaults: Defaults { language: Some("ENGLiSH".into()), ..Defaults::default() },
    ..Options::default()
};
println!("{}", guess("My Movie (2023)", &options)?.generated);
// My.Movie.2023.ENGLiSH-NOTEAM

let strict = Options { strict: true, ..Options::default() };
if let Err(error) = parse("Not.a.Movie-v28.1-macOS", &strict) {
    println!("{error}");
    // "Not.a.Movie-v28.1-macOS" does't follow scene release naming rules
}
```

`Options` holds `strict`, `flagged`, `erase`, `defaults` and `current_year`.

## API Reference

The reference below is the JavaScript one. Go and Rust take the same options under their own names, and return the same fields.

### `oleoo.parse(name, [options])`

Parses the release `name` string and returns an object with extracted metadata.

* `name` (String): The release name to parse.
* `options` (Object, optional):
    * `strict` (Boolean, default: `false`): If `true`, throws an error if essential tags (like source, encoding, resolution, or dub) are not found. If `false`, it attempts to parse as much as possible.
    * `flagged` (Boolean, default: `true`): If `true`, includes detected flags (like `EXTENDED`, `DC`, `PROPER`, etc.) in the `generated` output string, placed according to standard conventions. If `false`, these flags are omitted from the `generated` string (but still present in the `flags` array of the result).
    * `erase` (Array<String|RegExp>, default: `[]`): An array of additional regular expression patterns (as strings or RegExp objects) to remove from the input `name` *before* parsing begins. Useful for removing recurring junk specific to your source.
    * `defaults` (Object, default: `{}`): An object to provide fallback values for specific fields if they cannot be parsed. Supported keys: `language`, `resolution`, `year`.
    * `currentYear` (Number, default: the current system year): The year a release is parsed in. A year is accepted between 1901 and `currentYear + 4`, and `guess` falls back to it. Set it to get the same result on any date.

### `oleoo.guess(name, [options])`

Similar to `parse`, but always uses `strict: false` and attempts to infer missing details:
* If `year` is missing, defaults to `currentYear`, the current system year unless set, as a string like `parse` returns it.
* If `resolution` is missing, infers based on source (e.g., BluRay -> 1080p) or flags (e.g., UHD -> 2160p), otherwise defaults to `SD`.
* Rebuilds `generated` with the guessed `year` and `resolution`.
* Accepts the same `options` object as `parse` (though `strict` is ignored).

### Return Value (Object)

Both `parse` and `guess` return an object with the following structure:

```typescript
{
  original: string | null,      // Input string after basic cleanup (extension removal, erase patterns)
  language: string | null,      // Primary/combined language code (e.g., "FRENCH", "MULTi", "MULTi-VFF")
  languages: Array<string>,     // Array of all detected language codes (e.g., ["FRENCH", "ENGLiSH"])
  source: string | null,        // Standardized source tag (e.g., "BluRay", "WEB-DL", "HDTV")
  encoding: string | null,      // Standardized encoding tag (e.g., "x264", "x265")
  resolution: string | null,    // Standardized resolution tag (e.g., "1080p", "720p", "2160p", "SD")
  dub: string | null,           // Primary detected audio tag (e.g., "AC3", "DTS", "AAC-5.1") - *See Limitations*
  year: string | null,          // Detected year or year range (e.g., "2023", "2001-2003")
  flags: Array<string>,         // Array of detected flags (e.g., ["EXTENDED", "PROPER"]), empty if none
  season: number | null,        // Detected season number for TV shows
  episode: string | null,       // Formatted episode number(s) for TV shows (e.g., "01", "01-03")
  episodes: Array<number|string>, // Array of detected episode numbers (e.g., [1], [1, 2, 3]), or strings for dated episodes (e.g., ["04.02"])
  type: 'movie' | 'tvshow',     // Detected media type
  group: string | null,         // Detected release group
  title: string | null,         // Cleaned and formatted title
  alternativeTitle?: string,    // Optional: Extracted alternative title
  completeTitle?: string,       // Optional: Combined title and alternative title
  generated: string | null,     // Standardized filename generated based on parsed data and `flagged` option
  score: number                 // Parsing score (0-8), higher is better (points for Year, Source, Encoding, Resolution, Dub, Language, Group, Flags)
}
```

## Limitations / Known Issues

While Oleoo aims for broad compatibility, some release name patterns can be challenging:

* **Group Detection:** Can sometimes be confused by tags, alternative titles in parentheses, or multiple hyphenated parts near the end of the filename.
* **Title Boundaries:** Occasionally, tags (especially language tags) might be incorrectly included in the extracted title if the structure is unusual. Filenames without clear separators are difficult.
* **Complex Structures:** Very unconventional filenames, heavy use of nested brackets/parentheses, or ambiguous terms might lead to partial or incorrect parsing.
* **Bounds:** a name longer than 1024 characters, or an episode range of more than 9999 episodes (`E1-10000`), is refused with an error. The longest release of the fixtures holds 205 characters.
* **Characters above U+FFFF** (emoji): the JavaScript and Go packages count them as two UTF-16 code units, the Rust package as one character, so results can differ on such names. See [`SPEC.md`](./SPEC.md#strings-and-positions).

## Help Improve Oleoo! ❤️

The real world has countless release name variations! Help make Oleoo more robust by testing it with *your* own filenames. More diverse test cases lead to a better parser for everyone.

Contributing test cases is easy:

1.  **Get Ready:** Clone the repo (`git clone https://github.com/thcolin/oleoo.git`) and install dependencies (`cd oleoo && yarn install`). The JavaScript package is the reference: fixtures are reviewed against it.

2.  **Add Your Filenames:** Append your movie/TV show filenames (one per line) to the `./tests/fixtures/releases.txt` file.

> [!TIP]
> 
> You can quickly add many names using a command like `ls /path/to/your/movies >> tests/fixtures/releases.txt` (but please review and clean up the added list!).

3.  **Check Parsing & Update Tests:** Run the interactive script:
    ```bash
    yarn fixtures
    ```
    This command parses all names in `releases.txt`. For any new or changed results, it will show the parsed output and ask you to confirm if it's correct (`y`) or incorrect (`n`). If incorrect, add a comment explaining the problem. This updates the `accepted.json` (correct) and `refused.json` (incorrect) fixture files.

    `yarn test` runs the same comparison without prompting: it prints every release whose parsing differs from `accepted.json` or `refused.json`, and exits with code 1 if there is any.

4.  **Share Your Findings (Create a PR):**
    * The best way to contribute your new test cases is to **open a Pull Request** on GitHub.
    * Please include your updated versions of these three files in the PR:
        * `./tests/fixtures/releases.txt`
        * `./tests/fixtures/accepted.json`
        * `./tests/fixtures/refused.json`
    * If you were also able to **fix any parsing issues** you found in `rules.json` or `packages/js/src/index.js`, include those changes in the same PR! **Important:** Modifying the rules (`rules.json`) or the parsing logic (`packages/js/src/index.js`) can easily introduce regressions (breaking previously correct parses). **This is the main challenge!** Run `yarn test` to list every changed entry, then `yarn fixtures` to review them one by one and confirm that your changes only fix the intended issue and do not negatively affect other entries in `accepted.json`. A change to `rules.json` or to the algorithm applies to the three packages: copy `rules.json` into `packages/go` (`go generate`) and `packages/rust`, which embed it, then run `go test ./...` in `packages/go` and `cargo test` in `packages/rust` too, and fix [`SPEC.md`](./SPEC.md) when the algorithm changes.

**Reporting Issues without a PR:**

Found a filename Oleoo doesn't handle correctly? Your bug reports are valuable! If you don't want to create a Pull Request with updated test fixtures, please **open an Issue** on the [project's GitHub Issues page](https://github.com/thcolin/oleoo/issues).

To help fix the issue quickly, please include as much detail as possible in your report:

* **Essential:** The **full original filename** that failed to parse correctly.
* **Highly Recommended:**
    * The **actual JSON output** you got from Oleoo for that filename. You can copy this from the output of the `yarn fixtures` script when you mark the parse as incorrect, or by running `oleoo.parse()` directly. Please format it using Markdown code blocks (\`\`\`json ... \`\`\`).
    * A **description of what's wrong** with the actual output, or what you **expected** the output to be (e.g., "Expected group to be 'XYZ' but got 'ABC'", "Year '2023' was missed", "Flag 'REPACK' should be present").
    * If you used `yarn fixtures` and marked the parse as incorrect, include the **comment** you added explaining the error.

Even just providing the problematic filename is helpful, but more detail makes debugging much faster! Thank you for contributing!

## Porting Oleoo

The Go and Rust packages were written from [`SPEC.md`](./SPEC.md) and [`rules.json`](./rules.json) alone, and another language can follow the same path. Every pattern and list lives in `rules.json`, written in a regex dialect that other engines can read, and `SPEC.md` describes the algorithm step by step, with notes on the engines already used. A port is conformant when it gives the results of `tests/fixtures/accepted.json` and `tests/fixtures/refused.json` for every release of `tests/fixtures/releases.txt`, with `currentYear` set to 2026.

## License

[MIT](./LICENSE.md)

---
_Source: https://npm.io/package/oleoo · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
