# beets_music_videos A [beets](https://beets.io/) plugin that lets you import and manage **music videos** (and other non-audio media) in your library. Beets normally only handles audio formats supported by its `mediafile` layer; this plugin treats selected video extensions as importable items, creates library entries for them, and provides metadata from IMVDB and MusicBrainz for autotagging. --- ## Features - **Import video files** — Treats configured video extensions (e.g. `.mp4`, `.mkv`, `.webm`) as importable media. Files are added as beets `Item`s without going through `MediaFile`, so formats like MKV and WebM that beets doesn’t natively support can still be imported. - **Autotagging** — Supplies track-level candidates from: - **IMVDB** (Internet Music Video Database), via API search by artist + title. - **MusicBrainz** — video recordings search (`video: true`) for artist and title, with rich metadata (artist credits, release date, work/composer/lyricist, ISRC, etc.). - **Resolution probing** — Uses `ffprobe` to read video width/height and exposes them as flexible attributes (`video_width`, `video_height`, `video_resolution`) for path formats and queries. - **Safe tagging** — Writes embedded metadata only for formats that `mediafile` supports (MP4/M4V). For other formats (WebM, MKV, AVI), tags are not written to avoid corruption. - **Import behavior** — When a music video is already inside the library directory, the importer skips deleting the “original” after copy/move so you don’t lose the file. --- ## Installation 1. **Requirements** - Python ≥ 3.12 - beets ≥ 2.6.0, < 3.0.0 - [FFmpeg](https://ffmpeg.org/) (for `ffprobe`) — optional; used only for resolution probing. Without it, resolution fields are left unset. 2. **Install the plugin** (from this repo): ```bash cd beets_music_videos pip install -e . ``` Or add the project as a path dependency in your environment so beets can load `beetsplug.beets_music_videos`. 3. **Enable it** in `config.yaml`: ```yaml plugins: beets_music_videos ``` --- ## Configuration Configure the plugin under the `beets_music_videos:` key in your beets config. | Option | Type | Default | Description | |-------------------|----------|----------------------------------------------|-------------| | `extensions` | list | `[".mp4", ".m4v", ".mkv", ".avi", ".webm"]` | File extensions to treat as importable video. Values are normalized to lowercase with a leading dot (e.g. `mp4` → `.mp4`). | | `imvdb_api_key` | string | `""` | IMVDB API key for video search. If empty, IMVDB search is skipped; MusicBrainz video search still runs. Get a key at [IMVDB](https://imvdb.com/). | ### Example ```yaml plugins: beets_music_videos beets_music_videos: extensions: [".mp4", ".m4v", ".mkv", ".webm"] imvdb_api_key: YOUR_IMVDB_API_KEY ``` --- ## How it works ### Import flow 1. **Discovery** — Beets’ import task factory reads each path. The plugin patches `ImportTaskFactory.read_item` so that when the file extension is in `extensions`, it builds an `Item` directly instead of using `Item.from_path()` / `MediaFile`. That allows unsupported video formats to become library items. 2. **Item creation** — For those paths, the plugin: - Sets `path`, `mtime`, and a default `title` from the filename stem. - Runs `ffprobe` to get video width/height and sets `video_width`, `video_height`, and `video_resolution`. - Sets `media_type` to `"music_video"` so you can query e.g. `media_type:music_video`. - For **MP4/M4V** only, reads embedded tags (title, artist, album, albumartist, length) via `MediaFile` so autotag has better initial metadata. 3. **Autotag** — For each such item, beets calls the plugin’s `item_candidates(item, artist, title)`. The plugin: - Queries **IMVDB** (if `imvdb_api_key` is set) with artist + title. - Queries **MusicBrainz** for video recordings with artist and title. - Returns combined `TrackInfo` candidates; beets then picks the best match and applies metadata. 4. **File operations** — The plugin patches `ImportTask.manipulate_files` so that when writing tags it only calls `item.try_write()` for music videos whose extension is supported by `MediaFile` (MP4/M4V). Other video formats are not written to avoid corruption. It also adjusts behavior when the “original” is already inside the library directory so the file isn’t deleted after move. ### Metadata sources - **IMVDB** — Used only for track-level search. Returns candidates with `data_source="IMVDB"` (song title, artists, year, etc.). Requires `imvdb_api_key`. - **MusicBrainz** — Video recording search with `video: true`. Returns candidates with `data_source="MusicBrainz"` and full track metadata (artist credits, date, work, composer, lyricist, remixer, arranger, ISRC, length, etc.). No API key required. --- ## Item attributes (music videos) Library items created for video files have standard beets fields plus these flexible attributes: | Attribute | Type | Description | |--------------------|--------|-------------| | `media_type` | string | Set to `"music_video"` for all items created by this plugin. Use in queries: `beet list media_type:music_video`. | | `video_width` | int | Video width in pixels (from `ffprobe`). | | `video_height` | int | Video height in pixels (from `ffprobe`). | | `video_resolution` | string | e.g. `"1920x1080"` (from `ffprobe`). | For **MP4/M4V**, initial `title`, `artist`, `album`, `albumartist`, and `length` are filled from embedded tags when available; otherwise title defaults to the filename stem. --- ## Path formats You can use the extra attributes in `paths:` and `path_format:`: ```yaml paths: default: '$albumartist/$album [$year]/$track. $title' singleton: '$artist - $title - $year' ``` Flexible attributes are available as `$video_width`, `$video_height`, `$video_resolution`, and `$media_type` in path formats. --- ## Query examples - List all music videos: `beet list media_type:music_video` - 1080p only: `beet list video_height:1080` - By resolution string: `beet list video_resolution:1920x1080` --- ## Dependencies - **beets** (≥ 2.6.0, < 3.0.0) - **lapidary** (≥ 0.12.3) — used for the IMVDB API client - **typing-extensions** (≥ 4.15.0) - **FFmpeg** — optional; provides `ffprobe` for resolution. If missing, resolution fields are not set. The plugin uses beets’ built-in MusicBrainz integration (`MusicBrainzAPIMixin`) for MusicBrainz video search; no extra MusicBrainz package is required beyond what beets uses. --- ## License Apache 2.0.