# mnamer, a command-line renamer that asks the web what a file actually is

> mnamer is a Python command line utility for organizing media files. It parses filenames for metadata, queries TMDb, OMDb, TVDb or TvMaze to fill in the blanks, and then renames and moves the file according to a template. It also has a Rust rewrite in progress on a v3 branch, with file metadata introspection and hard linking as the new features.

**jkwill87/mnamer** — media file renaming and organizing tool

- Repository: https://github.com/jkwill87/mnamer
- Website: https://pypi.org/project/mnamer
- Stars: 1,158 · Forks: 117
- Language: Python
- License: MIT
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/jkwill87-mnamer

## Parse, look up, then rename

The workflow is the whole point. mnamer is a media renamer and organizer that parses media filenames for metadata, searches the web to fill in the blanks, and then renames and moves them. The name is an expansion of the same idea, media re-namer. The web search is what separates it from a regex-driven batch renamer: the tool does not try to interpret `Some.Show.S01E02.1080p.WEB.x264` with pattern rules alone, it asks a metadata service what that file is, and then applies a template to the result. The integration list is short and specific: TVDb and TvMaze for television episodes, TMDb and OMDb for movies. The default provider for each can be changed with the `--movie-api` and `--episode-api` settings, and the option syntax shows which is the default by the asterisk in the braces, so the default movie provider is TMDb and the default episode provider is TvMaze.

```bash
$ uv tool install mnamer
```

## Templates, and the fields you can put in them

The formatting settings are the four that decide what your library ends up looking like: `episode-directory`, `episode-format`, `movie-directory` and `movie-format`. The rule is that variables wrapped in braces get substituted with parsed values of template field variables, so the template is a small string language rather than a filename prefix convention. The directory settings control where files are moved and the format settings control what they are called, which means the two halves of an organisation scheme are configured separately, and you can keep a movie and an episode layout in the same library without the names fighting each other. Subtitles are handled in the same scheme: the tool supports .srt, .idx and .sub files, and it uses the format pattern used for the movie or episode with the subtitle extension prefixed by its two-letter language code, so a subtitle lands next to its media file with a name that says which language it is.

```bash
$ pip3 install --user mnamer
```

## The parameter list, and what a config file changes

Everything is available as a command line flag, and the long forms can also be set in a `.mnamer-v2.json` config file, in which case command line arguments take precedence. The parameters cover behaviour rather than just output. `--batch` processes automatically without interactive prompts, which is the flag you need in a script. `--recurse` searches nested directories, `--scene` uses dots in place of alphanumeric characters, `--lower` renames using lowercase, and `--no-style` prints to stdout without colour or unicode characters, which matters when you are parsing the output. `--hits` limits the maximum number of hits for each query, `--ignore` takes regular expressions of files to skip, `--mask` restricts processing to given file types, and `--no-guess` disables the best guess behaviour when there are no matches or the network is down. That last one is the safety valve: it turns a wrong guess into a skipped file.

```
  -b, --batch: process automatically without interactive prompts
  -l, --lower: rename files using lowercase characters
  -r, --recurse: search for files within nested directories
  -s, --scene: use dots in place of alphanumeric chars
  --hits=<NUMBER>: limit the maximum number of hits for each query
  --ignore=<PATTERN,...>: ignore files matching these regular expressions
  --no-guess: disable best guess; e.g. when no matches or network down
  --no-overwrite: prevent relocation if it would overwrite a file
```

## Directives are for one-off overrides, not for configuration

Directives are one-off arguments used to perform secondary tasks like overriding media detection, and they cannot be used in the config file, which is a useful separation. Four of them change how a file is identified: `--id-imdb`, `--id-tmdb`, `--id-tvdb` and `--id-tvmaze` each force a specific identifier, and `--media` overrides the movie or episode detection entirely. The rest manage the tool itself: `--test` mocks the renaming and moving of files, `--clear-cache` clears the request cache, `--no-cache` disables it for a session, `--config-dump` prints the current config JSON and exits, `--config-ignore` skips loading the config file, `--config-path` points at a different one, and `-V` prints the version. The identifier overrides are the escape hatch for the failure mode every metadata-driven renamer has, a file whose name genuinely does not match what it contains, where guessing from the filename is hopeless and you already know the answer.

```
  -V, --version: display the running mnamer version number
  --clear-cache: clear request cache
  --config-dump: prints current config JSON to stdout then exits
  --id-imdb=<ID>: specify an IMDb movie id override
  --id-tmdb=<ID>: specify a TMDb movie id override
  --no-cache: disable request cache
  --media={movie,episode}: override media detection
  --test: mocks the renaming and moving of files
```

## Automation in a container, and the Docker image

The project documents a Docker image, which is the shortest path to running this on a schedule. The image is published as `jkwill87/mnamer` and the Dockerfile is small enough to read in full, which is unusual and welcome for something that touches your files. It is a two-stage build on python:alpine, where the builder installs git, copies the source and runs pip wheel to produce a wheel, and the final stage installs that wheel into a fresh alpine image. The security posture is deliberate: a group and a user are created with the build arguments UID and GID, the user is added with a disabled password, and the container runs as that unprivileged user rather than as root. The entrypoint is the module itself and the default command is `--batch` against `/mnt`, which is the shape you want for a container: process the mounted volume without prompting.

```dockerfile
FROM python:alpine
ARG UID=1000
ARG GID=1000
RUN addgroup mnamer -g "$GID"
RUN adduser mnamer -u "$UID" -G mnamer --disabled-password
USER mnamer
ENTRYPOINT ["python", "-m", "mnamer"]
CMD ["--batch", "/mnt"]
```

## A Rust rewrite on a branch, with the Python line still maintained

The project is mid-transition, and the README is upfront about it. A note at the top says mnamer is currently under an early development Rust rewrite available under the v3 branch, that it is a work in progress and extremely subject to change, and that it currently has feature parity with v2 along with new features such as file metadata introspection and hard linking. v2 will continue to be maintained for the foreseeable future, and readers are invited to try v3 and leave feedback in a discussion thread. The practical reading is that there are two products. The default branch is main and carries the Python implementation, with the three most recent releases being 2.7.2 from 2026-05-22, 2.7.1 from 2026-05-19 and 2.7.0 from 2026-05-09, and the last push to the repository was on 2026-10-05. The Rust branch adds hard linking, which is a genuine feature for a media renamer because it lets the tool place a file in a library without doubling the disk usage, and metadata introspection, which lets it read tags from the file itself rather than only the filename.

## The dependency list explains what the tool does

The Python package metadata is a compact map of the design. The runtime dependencies are appdirs for locating configuration directories per platform, babelfish for language code conversions, guessit for parsing media filenames into structured guesses, requests for the web lookups, requests-cache so repeated queries do not hit the API again, setuptools-scm for deriving the version from the repository, and teletype for terminal output. The two that matter are guessit, which is what turns a filename into candidate metadata before the web lookup, and requests-cache, which is what makes the tool usable on a large library rather than a folder of twenty files. The project requires Python 3.12 or newer, uses ruff for linting and formatting with a line length of 88 and a py312 target, and the development group carries pytest with coverage, mocking and rerun plugins, mypy, pylint, codecov, build and twine. The package is published on PyPI under the name mnamer, and the entry point is `mnamer.__main__:main`.

## Conclusion

Adopt mnamer if you have a directory of badly named media files and want a batch renamer that reads the web for authoritative titles rather than guessing from the filename, and skip it if you need something that works purely offline, since the lookup step is at the heart of what it does. Verify three things before you run it on a real library: that you use the `--test` directive first, which mocks the renaming and moving; that you set `--no-overwrite` if you would rather it refused to replace an existing file than decide for you; and which branch you installed, because the Rust rewrite on the v3 branch is work in progress while v2 is the maintained Python line.

## FAQ

### What is mnamer and how does it rename media files?

It is a command line utility for organizing media files that parses filenames for metadata, searches the web to fill in the blanks, and then renames and moves them. It has integration support with TVDb and TvMaze for television episodes and TMDb and OMDb for movies.

### How do I install mnamer?

With `uv tool install mnamer` or `pip3 install --user mnamer`. For automation there is also a Docker image, `jkwill87/mnamer`, whose default command is `--batch` against `/mnt` and which runs as an unprivileged user.

### How do I customize how mnamer names and organizes files?

Through the `episode-directory`, `episode-format`, `movie-directory` and `movie-format` settings, where variables wrapped in braces are substituted with parsed values of template field variables. The same parameters exist as command line flags, and the long forms can also be set in a `.mnamer-v2.json` config file, with command line arguments taking precedence.

### Can I test a renaming run before it touches my files?

Yes. The `--test` directive mocks the renaming and moving of files. The `--no-overwrite` parameter additionally prevents relocation if it would overwrite an existing file, and `--no-guess` disables the best guess behaviour when there are no matches or the network is down.

### What is the difference between mnamer v2 and v3?

v2 is the maintained Python implementation on the main branch, with the recent releases 2.7.2, 2.7.1 and 2.7.0. v3 is an early development Rust rewrite on its own branch, described as a work in progress and extremely subject to change, which currently has feature parity with v2 plus file metadata introspection and hard linking.

## Sources

- [jkwill87/mnamer on GitHub](https://github.com/jkwill87/mnamer)
- [License: MIT](https://github.com/jkwill87/mnamer/blob/main/LICENSE)
- [Project website](https://pypi.org/project/mnamer)
- [README](https://github.com/jkwill87/mnamer/blob/main/README.md)
- [Releases](https://github.com/jkwill87/mnamer/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/jkwill87-mnamer
