Files
filename-tool/README.md
T
2026-05-25 23:47:06 +02:00

159 lines
5.2 KiB
Markdown

# Filename Tool
TypeScript library for extracting metadata from media filenames, designed for the MetaMesh ecosystem.
Package name: `@metazla/filename-tools` (plural — kept for backwards compatibility).
## Overview
`@metazla/filename-tools` parses media file paths to extract structured metadata: titles, seasons, episodes, movie years, plus file-type classification driven by extension and MIME-type mappings. It is a pure-TS library — no Docker, no service. Used inside meta-sort (`WatchedFileProcessor`) and inside the `metamesh-plugin-filename-parser` container plugin.
## Features
- **Video metadata extraction** — title, season, episode, increment, movie year, `videoType: "movie" | "tvshow"`
- **File-type classification** — by extension and MIME type, into a small set (`video`, `audio`, `subtitle`, `document`, `archive`, `torrent`, `other`, `undefined`)
- **Title heuristics** — combines filename, parent folder, grandparent folder; TV-show pattern detection picks the series name over the episode name
- **Folder helpers** — sibling-file lookup
- **Language helpers** — convert anything (ISO 639-1 / 2 / 3 / full name) to ISO 639-3
- **Configurable** — every pattern set (`episodePatterns`, `seasonAndEpisodePatterns`, `keywordsArray`, …) is exported and overridable
## Installation
In the monorepo:
```json
{
"dependencies": {
"@metazla/filename-tools": "workspace:*"
}
}
```
Build from `packages/filename-tool/`:
```bash
pnpm build
pnpm test # vitest
```
## Public API
The full export list is in `src/lib/index.ts`. The two extractor classes are the main entry points; the rest are tools/configs that the extractors consume but you can use directly.
### `FileNameMetaExtractor`
`extractMetadata(filePath)` is the high-level entry point. It returns a `FileMetadata` (extends `VideoFileMetadata`):
```typescript
import { FileNameMetaExtractor, FileMetadata } from '@metazla/filename-tools';
const watchFolders = ['/files/watch'];
const extractor = new FileNameMetaExtractor(watchFolders);
const metadata: FileMetadata = await extractor.extractMetadata(
'/files/watch/Naruto/Season 01/Naruto.S01E01.1080p.mkv',
);
// metadata fields that may be populated:
// fileName : "Naruto.S01E01.1080p.mkv"
// extension : "mkv"
// fileType : "video"
// tags : string[] (extracted from brackets)
// originalTitle: "Naruto"
// season : "1"
// episode : "1"
// increment : "10001" (season * 10000 + episode)
// movieYear? : string
// videoType : "tvshow" (or "movie")
// extra? : "true" (specials/extras)
```
The optional second constructor arg is a path to a JSON file that overrides any of the default pattern sets (`extensionMappings`, `mimeTypeMappings`, `episodePatterns`, `seasonAndEpisodePatterns`, `seasonPatterns`, `extraEpKeyWords`, `keywordsArray`, `substringArray`, `soloEp`).
### `FileNameVideoMetaExtractor`
Lower-level — only does the video bits (title, season/episode, year, videoType). Requires all pattern arrays as constructor args (see how `metamesh-plugin-filename-parser` constructs it):
```typescript
import {
FileNameVideoMetaExtractor,
episodePatterns,
seasonAndEpisodePatterns,
seasonPatterns,
extraEpKeyWords,
keywordsArray,
substringArray,
soloEp,
VideoFileMetadata,
} from '@metazla/filename-tools';
const extractor = new FileNameVideoMetaExtractor(
[],
episodePatterns,
seasonAndEpisodePatterns,
seasonPatterns,
extraEpKeyWords,
keywordsArray,
substringArray,
soloEp,
);
const meta: VideoFileMetadata = extractor.extractVideoFileMetadata(
'The.Matrix.1999.1080p.BluRay.x264-GROUP.mkv',
);
// { originalTitle: "The Matrix", movieYear: "1999", videoType: "movie" }
```
### `FileType`
Synchronous classifier wrapping `FileTypeConfigurable` with the default mappings:
```typescript
import { FileType, SimpleFileType } from '@metazla/filename-tools';
const ft = new FileType();
const t: SimpleFileType = await ft.getFileType('episode.mkv'); // "video"
```
`SimpleFileType` is the union of all classifications: `'audio' | 'video' | 'document' | 'archive' | 'subtitle' | 'torrent' | 'other' | 'undefined'`.
### Folder helper
```typescript
import { getSiblingFiles } from '@metazla/filename-tools';
// Returns siblings sharing the same basename (any extension).
const siblings = await getSiblingFiles('/media/show/episode.nfo');
```
### Language helper
```typescript
import { anyTo_iso_639_3 } from '@metazla/filename-tools';
anyTo_iso_639_3('en'); // "eng" (ISO 639-1 → 639-3)
anyTo_iso_639_3('english'); // "eng" (name → 639-3)
anyTo_iso_639_3('jpn'); // "jpn" (already 639-3; pass-through)
```
## What `videoType` actually contains
Note this differs from what some older docs claim — the library only emits `"tvshow"` or `"movie"`. There is no `"anime"`/`"documentary"`/`"unknown"` value. Anime-detection happens elsewhere (the `metamesh-plugin-anime-detector` plugin and `AnimeMeta` in `@metazla/meta-interface`).
## Build
Dual-format build via `tsup`:
- `dist/index.js` (ESM)
- `dist/index.cjs` (CommonJS)
- `dist/index.d.ts` (types)
```bash
pnpm build # tsc + tsup
pnpm test # vitest
```
## License
MIT — same as the MetaMesh monorepo.