{"id":13628900,"url":"https://github.com/sandreas/tone","last_synced_at":"2025-05-16T06:06:46.299Z","repository":{"id":38129042,"uuid":"406651459","full_name":"sandreas/tone","owner":"sandreas","description":"tone is a cross platform audio tagger and metadata editor to dump and modify metadata for a wide variety of formats, including mp3, m4b, flac and more. It has no dependencies and can be downloaded as single binary for Windows, macOS, Linux and other common platforms.","archived":false,"fork":false,"pushed_at":"2025-02-13T03:03:09.000Z","size":614,"stargazers_count":447,"open_issues_count":23,"forks_count":20,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-05-11T05:59:58.714Z","etag":null,"topics":["audio","id3","m4b","metadata","mp3","tagger"],"latest_commit_sha":null,"homepage":"https://pilabor.com","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sandreas.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"sandreas"}},"created_at":"2021-09-15T07:10:43.000Z","updated_at":"2025-05-10T04:02:29.000Z","dependencies_parsed_at":"2024-12-09T21:23:08.480Z","dependency_job_id":"61328bcb-4c67-4852-874a-15d10b0a4bf7","html_url":"https://github.com/sandreas/tone","commit_stats":null,"previous_names":[],"tags_count":25,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sandreas%2Ftone","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sandreas%2Ftone/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sandreas%2Ftone/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sandreas%2Ftone/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sandreas","download_url":"https://codeload.github.com/sandreas/tone/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254478190,"owners_count":22077676,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["audio","id3","m4b","metadata","mp3","tagger"],"created_at":"2024-08-01T22:00:59.200Z","updated_at":"2025-05-16T06:06:41.282Z","avatar_url":"https://github.com/sandreas.png","language":"C#","funding_links":["https://github.com/sponsors/sandreas"],"categories":["C#","C# #"],"sub_categories":[],"readme":"# tone\n\n`tone` is a cross-platform audio tagger and metadata editor to dump and modify metadata for a wide variety of formats, including `mp3`, `m4b`, `flac` and more. It has no dependencies and can be downloaded as single binary for Windows, macOS, Linux and other common platforms.\n\nThe code is written in pure `C#` and utilizes the awesome [atldotnet] library to provide full support for a wide variety of audio and metadata formats.\n\n## Features\nThe main purpose of `tone` is to tag `m4b` audio books for myself. It is planned as a successor to [m4b-tool].\n\n- `dump` metadata of audio files\n  - different metadata formats (e.g. `chptfmtnative`, `ffmetadata`, etc.)\n  - file information (bitrate, channels, duration, etc.)\n  - support for filterable `json` output (similar to `jq`)\n  - extensive list of supported tags (default fields like *album* or *artist as well as *custom fields*, *covers*, *chapters*, etc.)\n- `tag` audio files with different kinds of metadata\n  - different file formats (e.g. `mp3`, `m4b`, and `flac`)\n  - extensive list of supported tags (default fields like *album* or *artist as well as *custom fields*, *covers*, *chapters*, etc.)\n  - filename to tags via `--path-pattern` (see below)\n  - custom javascript taggers via `--script` and `--script-tagger-parameter`\n\n## Support me via GitHub sponsors\n\nIf you are using any of my projects and find them helpful, please consider [donating to support me](https://github.com/sponsors/sandreas). I plan to use the money to support other open source projects or charitable purposes. Thank you!\n\n\u003cp align=\"center\"\u003e\n\u003ca href=\"https://github.com/sponsors/sandreas\"\u003e\u003cimg src=\"./assets/help.svg\" width=\"300\" alt=\"sponsor me and donate\" style=\"margin:auto;\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n## TL;DR\n\n### dump tags\n```bash\n# show help\ntone dump --help\n\n# show all tags for single file (input.mp3)\ntone dump input.mp3\n\n# show title and artiest tag recursively for all files in directory with extension m4b in FFMETADATA format\ntone dump audio-directory/ --include-extension m4b --format ffmetadata --include-property title --include-property artist\n\n# show album only via json format and JSONPath query\ntone dump \"input.mp3\" --format json --query \"$.meta.album\"\n\n# show audio stream information via JSONPath query\ntone dump \"input.mp3\" --format json --query \"$.audio\"\n```\n\n### modify tags\n\n**IMPORTANT:** Because metadata is modified in place without copying the\nfile, changes are only safe on local block storage (like your hard disk, sd card, etc.). Modifying files on\nremote storages (like network shares) may break your files. Please make sure you have a backup.\n\n```bash\n# show help\ntone tag --help\n\n# change title tag\ntone tag input.mp3 --meta-title \"a title\"\n\n# change a custom field, auto-import covers nearby and show debug info on error (--dry-run simulation)\ntone tag --debug --auto-import=covers --meta-additional-field \"©st3=testing\" input.m4b --dry-run\n\n# recursively set tags genre, artist, series, part and title by path pattern (--dry-run simulation)\ntone tag --auto-import=covers --auto-import=chapters --path-pattern=\"audiobooks/%g/%a/%s/%p - %n.m4b\" --path-pattern=\"audiobooks/%g/%a/%z/%n.m4b\" audiobooks/ --dry-run\n\n# write your own custom JavaScript tagger and call this function with parameters to modify metadata on your own\ntone tag \"harry-potter-1.m4b\" --taggers=\"musicbrainz\" --script=\"musicbrainz.js\" --script-tagger-parameter=\"e2310769-2e68-462f-b54f-25ac8e3f1a21\"\n```\n\n\n## Setup\n\n`tone` is a terminal application and deployed as monolithic binary with no dependencies.\nThis means, that downloading a single file from the [releases] page.\n\n### Linux / macOS\n```bash\n\n# linux-arm\nwget https://github.com/sandreas/tone/releases/download/v0.2.5/tone-0.2.5-linux-arm.tar.gz\n\n# linux-arm64\nwget https://github.com/sandreas/tone/releases/download/v0.2.5/tone-0.2.5-linux-arm64.tar.gz\n\n# linux-x64\nwget https://github.com/sandreas/tone/releases/download/v0.2.5/tone-0.2.5-linux-x64.tar.gz\n\n# macos (m1) - not working atm, see issue #6\nwget https://github.com/sandreas/tone/releases/download/v0.2.5/tone-0.2.5-osx-arm64.tar.gz\n\n# macos (intel)\nwget https://github.com/sandreas/tone/releases/download/v0.2.5/tone-0.2.5-osx-x64.tar.gz\n\n# untar \ntar xzf tone-*.tar.gz\n\n# install to your $PATH\nsudo mv tone*/tone /usr/local/bin/\n\n# test if tone is usable\ntone --help\n```\n\n\n### Windows\n\n```bash\n# download for windows (powershell)\niwr -outf tone-0.2.5-win-x64.zip https://github.com/sandreas/tone/releases/download/v0.2.5/tone-0.2.5-win-x64.zip\n\n# extract tone\nExpand-Archive -LiteralPath tone-0.2.5-win-x64.zip -DestinationPath .\n\n# test if tone is usable\n.\\tone --help\n\n# open directory in windows explorer to manually put tone in your %PATH%, e.g. C:\\Windows\nstart .\n```\n\n### Docker\n\nSince `tone` is a monolith, it is probably not necessary to run it via `docker`, but since it is convenient to have a possibility to copy `tone` in your own image, I published an official variant on dockerhub. Since it is a *multiarch*  image, you can use it on `arm6`, `arm7`, `aarch64`, and `x64` images.\n\n```bash\ndocker pull sandreas/tone:v0.2.5\n```\n\n\nOr to use `tone` in your custom `Dockerfile`:\n\n```dockerfile\n# Dockerfile\nFROM sandreas/tone:v0.2.5 as tone\n# ...\nCOPY --from=tone /usr/local/bin/tone /usr/local/bin/\n```\n\n## Reserved fields and supported formats\n\n`tone` already supports some common input and output formats for metadata, as well as a `tone` specific one (`ToneJson`). Moreover `tone` also uses some *reserved metadata fields* to overcome issues when storing specific information. \n\n### Reserved metadata fields\nThe namespace `----:com.pilabor.tone` as well as the following fields are reserved for `tone` in `mp4` / `m4a` / `m4b` based file formats:\n\n- `----:com.pilabor.tone:AUDIBLE_ASIN`: Since there is no official field for storing the audible ASIN, `tone` MAY use this custom field to store this piece information\n- `----:com.pilabor.tone:PART`: Since the movement index is often used for a part of a series but only supports integers (e.g. `1`) it cannot store some series part names (e.g. `2.1` or roman numbers like `IV`)\n  - `tone` supports `--meta-part` parameter being a fallback for storing non integer values while coincidentally storing `--meta-movement` only if it is an integer value\n  - Therefore it is always recommended to use the `--meta-part` parameter instead of `--meta-movement` to set the part number of a series\n\n### ToneJson format\nThe *ToneJson* format is specific for `tone`, can contain all supported metadata (including binary images) and looks similar to this example...\n\n\n**Example**\n\n```json\n{\n  \"audio\": {\n    \"bitrate\": 320,\n    \"format\": \"MPEG Audio (Layer III)\",\n    \"formatShort\": \"MPEG\",\n    \"sampleRate\": 44100.0,\n    \"duration\": 255920.0,\n    \"channels\": {\n      \"count\": 2,\n      \"description\": \"Joint Stereo\"\n    },\n    \"frames\": {\n      \"offset\": 20749,\n      \"length\": 10236864\n    },\n    \"metaFormat\": [\n      \"id3V24\"\n    ]\n  },\n  \"meta\": {\n    \"album\": \"Back in Black\",\n    \"albumArtist\": \"AC/DC\",\n    \"artist\": \"AC/DC\",\n    \"discNumber\": 1,\n    \"discTotal\": 1,\n    \"encodedBy\": \"LAME 3.99.5\",\n    \"genre\": \"Hard Rock\",\n    \"itunesCompilation\": \"no\",\n    \"publisher\": \"Atlantic\",\n    \"recordingDate\": \"1986-01-01T00:00:00\",\n    \"sortArtist\": \"AC/DC\",\n    \"title\": \"Back in Black\",\n    \"trackNumber\": 6,\n    \"trackTotal\": 10,\n    \"embeddedPictures\": [\n      {\n        \"type\": 2,\n        \"code\": 3,\n        \"mimetype\": \"image/jpeg\",\n        \"data\": \"/9j/4AAQSkZJRgA...9k=\"\n      }\n    ],\n    \"additionalFields\": {\n      \"grP1\": \"5\",\n      \"tmed\": \"CD\",\n      \"tlan\": \"eng\",\n      \"tipl\": \"arranger\",\n      \"tdor\": \"1980-07-25\",\n      \"script\": \"Latn\",\n      \"artist Credit\": \"AC/DC\",\n      \"albumartistsort\": \"AC/DC\",\n      \"catalognumber\": \"16018-2\",\n      \"album Artist Credit\": \"AC/DC\",\n      \"musicBrainz Album Type\": \"album\",\n      \"replaygaiN_ALBUM_GAIN\": \"-8.43 dB\",\n      \"replaygaiN_ALBUM_PEAK\": \"1.064363\",\n      \"replaygaiN_TRACK_GAIN\": \"-8.38 dB\",\n      \"replaygaiN_TRACK_PEAK\": \"1.051585\",\n      \"musicBrainz Album Status\": \"Official\",\n      \"musicBrainz Album Release Country\": \"DE\",\n      \"acoustid Id\": \"8b379144-9a9d-4fc1-897a-a7c0771f8ebb\",\n      \"musicBrainz Album Id\": \"fdabb997-b984-4097-bd3b-89fafd5e2e75\",\n      \"ufid\": \"http://musicbrainz.org\\u0000ef71afb6-5e51-41df-999b-9e7c7306063a\",\n      \"musicBrainz Artist Id\": \"66c662b6-6e2f-4930-8610-912e24c63ed1\",\n      \"musicBrainz Album Artist Id\": \"66c662b6-6e2f-4930-8610-912e24c63ed1\",\n      \"musicBrainz Release Group Id\": \"d3bc1a64-7561-3787-b680-0003aa50f8f1\",\n      \"musicBrainz Release Track Id\": \"cf05ab29-27c7-47ed-9450-9f4de676cded\",\n      \"acoustid Fingerprint\": \"AQADtE...oIIYgRUChBhABIEeWAA0AQR4hSDg\",\n      \"iTunNORM\": \" 00001AE7 00001AE7 00004340 00004340 00000000 00000000 0000869A 0000869A 00000000 00000000\"\n    }\n  },\n  \"file\": {\n    \"size\": 10257613,\n    \"created\": \"2019-06-12T18:50:37.5527895+02:00\",\n    \"modified\": \"2019-06-12T18:50:37.5527895+02:00\",\n    \"accessed\": \"2023-02-14T09:21:29.2261032+01:00\",\n    \"path\": \"music/album/AC_DC/Back in Black\",\n    \"name\": \"06 - Back in Black.mp3\"\n  }\n}\n\n```\n\n### ChptFmtNative format (also CHPT_FMT_NATIVE)\nThe *ChptFmtNative* format was initially used in `mp4v2`, but never fully specified. However, there is a loose [spec here](https://github.com/enzo1982/mp4v2/files/8103210/ToolGuide.txt).\n\n**Example**\n\n```\n## artist: Cœur de pirate\n## album: Blonde\n##\n## total-duration: 00:38:37.034\n##\n00:00:00.000 Lève les voiles\n00:01:12.709 Adieu\n00:03:40.346 Danse et danse\n00:06:50.775 Golden Baby\n00:09:57.772 Ava\n00:13:14.657 Loin d'ici\n00:15:58.494 Les amours dévouées\n00:18:26.443 Place de la république\n00:22:37.664 Cap diamant\n00:25:20.925 Verseau\n00:29:14.722 Saint-Laurent\n00:32:29.519 La petite mort\n00:36:19.140 Hôtel amour\n```\n\n### ffmetadata format\nThe *ffmetadata* format was designed for `ffmpeg`, a versatile media encoder and it is [specified here](https://ffmpeg.org/ffmpeg-formats.html#toc-Metadata-1).\n\n**Example**\n\n```\n;FFMETADATA1\ntitle=Back in Black\nartist=AC/DC\ntrack=6/10\nalbum=Back in Black\ndisc=1/1\ndate=1986\ngenre=Hard Rock\nTBPM=0\ncompilation=0\nTMED=CD\nlanguage=eng\nalbum_artist=AC/DC\nartist-sort=AC/DC\npublisher=Atlantic\nTIPL=arranger\nTDOR=1980-07-25\nencoded_by=LAME 3.99.5\nScript=Latn\nArtist Credit=AC/DC\nALBUMARTISTSORT=AC/DC\nCATALOGNUMBER=16018-2\n```\n\n\n## Commands\n\nThe features of `tone` are divided by commands. You can `dump` information or `tag` a file and so on. To do so, run\n\n```bash\ntone \u003ccommand\u003e \u003cparameters\u003e\n```\n\nExample:\n```\ntone dump \"my-audio-file.mp3\"\n```\n\n\n\n**global options**\n\nThere are some global options, that can be used to change the behaviour of the file iterator. These options apply for all commands:\n\n- `--order-by`: Sort files by attribute (defaults to `path`, available options are `path`, `size`, `filename`, `extension`, `created`, `modified`, `accessed`, combine via `,`, descending via `!`), examples:\n  - `--order-by=\"!created\"` - sort by create date descending\n  - `--order-by=\"extension,created\"` - sort by extension, then by created\n  - `--order-by=\"size,!extension,modified\"` - sort by size, then extension descending, then by modification date\n- `--limit`: Limit results\n  - one value (e.g. `--limit=10`) - top `10` results\n  - two values with comma (e.g. `--limit=10,20`) - offset `10` fetch `20` results\n- `--include-extensions`: Filter for these extensions\n- `--debug`: Enable debug mode (for development or issue reporting)\n- `--force`: Try to force action (e.g. overwrite existing files, etc.)\n\n### `dump` - show audio metadata\n\nThe `dump` command can be used to show metadata for a wide variety of audio files. You can either specify a single file or a directory, \nwhich will be traversed recursively. Several output `--format` options are supported. By default a terminal user interface library is used, \nbut it is also possible to use `json` or `ffmetadata`.\n\n\n#### Options reference \n```bash\ntone dump --help           \nUSAGE:\n    tone dump [input] [OPTIONS]\n\nEXAMPLES:\n    tone dump --help\n    tone dump input.mp3\n    tone dump audio-directory/ --include-extension m4b --format ffmetadata --include-property title --include-property artist\n\nARGUMENTS:\n    [input]    Input files or folders\n\nOPTIONS:\n    -h, --help                 Prints help information\n        --debug                                       \n        --force                                       \n        --include-extension                           \n        --order-by                                    \n        --limit                                       \n        --include-property                            \n        --format                                      \n        --query \n```\n\n### `tag` - modify audio metadata\n\nThe `tag` command can be used to modify audio metadata. Besides using predefined parameters like `--meta-album` it is also possible to \nadd or modify custom fields via `--meta-additional-field`, e.g. `--meta-additional-field \"©st3=testing\"` as well as pictures or chapters.\n\n\u003e IMPORTANT: `tone` is meant to be used on local block storage and may cause unwanted side effects when trying to modify tags on network or\n\u003e other remote storage. Please ensure you have a backup or copy files locally to change metadata. See #52 for details.\n\n#### The `--taggers` option\nThe `--taggers` option allows you to specify a custom set or a different order of internal taggers (NOT input formats), which are gonna be applied. In most cases\nchanging the order of the *taggers* does not make a huge difference, but fully understanding this option \nrequires a bit of technical knowledge. Let's go through a use case to see what you can do with it.\n\n\u003e Note: Internal taggers are applied in a sane order by default and not meant for beginners. Most of the time you don't need to change the order and this usually is for very specific experts use cases. So if you don't fully understand this option, just leave it as is.\n\n*Use case: re-tag `sorttitle` / `sortalbum`*\nThe following taggers are relevant for this use case:\n\n- `remove` - Removes metadata fields or sets it to an empty value\n- `m4bfillup` - Fills up missing or relevant special fields for audio books (e.g. `sorttitle` / `sortalbum`)\n- `*` - Represents all remaining taggers, that are not already provided by name\n\nUsually, the `remove` tagger is applied at last. If you provide `--meta-remove-property=sorttitle`, this ensures an existing value will really be \nremoved after all taggers have been applied. The `m4bfillup` tagger will automatically generate `sorttitle` / `sortalbum` from `movementname`,\n`movement` and `title` / `album` if AND ONLY IF the current value is empty. \n\nSo if you change the `movementname` (e.g. `Harray Potter` to `Harry Potter` because of a typo), `sorttitle` / `sortalbum` will not be updated, \nbecause these fields already have a value. If you `remove` the `sorttitle` / `sortalbum`, it will not be auto-updated but only removed, \nsince `remove` is applied after `m4bfillup`.\n\nThis can be solved by reordering the taggers:\n- First apply `remove` tagger to remove `sorttitle` / `sortalbum` completely\n- Then apply `m4bfillup` to rebuild `sorttitle` / `sortalbum`\n\n```bash\ntone tag harry-potter-1.m4b --taggers=\"remove,m4bfillup\" --meta-movement-name=\"Harry Potter\" --meta-remove-property=\"sortalbum\" --meta-remove-property=\"sorttitle\"\n```\n\nAs you see, most of the time, you only care about one special tagger to be applied first or last. This is why `tone` has an option to add all\nremaining taggers to the list using a `*`:\n\n```bash\ntone tag harry-potter-1.m4b --taggers=\"remove,*\" --meta-movement-name=\"Harry Potter\" --meta-remove-property=\"sortalbum\" --meta-remove-property=\"sorttitle\"\n```\n\nThe following taggers are available at the moment (names can be applied case-insensitive):\n\n- `ToneJson` - sets metadata values from `tone.json` file\n- `Metadata` - sets metadata values from input parameters `--meta-...`\n- `Id` - sets metadata values from `--id` (e.g. for fetching from web sources via custom js taggers)\n- `Cover` - sets cover from cover files\n- `PathPattern` - sets metadata values from path pattern\n- `Ffmetadata` - sets metadata values from `ffmetadata.txt` file\n- `ChptFmtNative` - sets chapters from `chapters.txt` file\n- `Equate` - equates 2 or more metadata fields from `--meta-equate` (see below)\n- `M4BFillUp` - auto fill `album`, `title`, `iTunesMediaType` from existing fields if possible\n- `PrependMovementToDescription` - prepends `movement` to all description fields, if set\n- `Remove` - removes metadata values from input parameter `--meta-remove-property` and `--meta-remove-additional-field`\n- `ScriptTagger` - your personal custom JavaScript taggers (see below)\n\n***Equate***\nThe equate tagger can be used to set a field by referencing another, e.g. when you would like to set \nthe `AlbumArtist` equal to the `Artist`, you could use `--meta-equate \"artist,albumartiest\"`.\n\nThe `--meta-equate` works like this:\n\n- Fields to equate are separated by `,`, at least 2 fields are required, but more are allowed\n- The first field contains the value, the latter fields will be overwritten by this value\n- The `--meta-equate` parameter can be used multiple times to equate multiple fields, e.g. `--meta-equate=fieldA,fieldB --meta-equate=fieldC,fieldD,fieldE`\n- The provided field names are treated case-insensitive, see reference below\n\n\n\u003cdetails\u003e\n  \u003csummary\u003eField reference\u003c/summary\u003e\n```\n    Album\n    AlbumArtist\n    Artist\n    Bpm\n    ChaptersTableDescription\n    Composer\n    Comment\n    Conductor\n    Copyright\n    Description\n    DiscNumber\n    DiscTotal\n    EncodedBy\n    EncoderSettings\n    EncodingTool\n    Genre\n    Group\n    ItunesCompilation\n    ItunesMediaType\n    ItunesPlayGap\n    LongDescription\n    Lyrics\n    Part\n    Movement\n    MovementName\n    Narrator\n    OriginalAlbum\n    OriginalArtist\n    Popularity\n    Publisher\n    PublishingDate\n    PurchaseDate\n    RecordingDate\n    SortTitle\n    SortAlbum\n    SortArtist\n    SortAlbumArtist\n    SortComposer\n    Subtitle\n    Title\n    TrackNumber\n    TrackTotal\n```\n\u003c/details\u003e\n\n\n#### Options reference\n```bash\ntone tag --help                                                                                                                                                                     \nUSAGE:\n    tone tag [input] [OPTIONS]\n\nEXAMPLES:\n    tone tag --help\n    tone tag input.mp3 --meta-title \"a title\"\n    tone tag --debug --auto-import=covers --meta-additional-field ©st3=testing input.m4b --dry-run\n    tone tag --auto-import=covers --auto-import=chapters --path-pattern=\"audiobooks/%g/%a/%s/%p - %n.m4b\" --path-pattern=\"audiobooks/%g/%a/%z/%n.m4b\" audiobooks/ --dry-run\n    tone tag input.mp3 --script musicbrainz.js --script-tagger-parameter e2310769-2e68-462f-b54f-25ac8e3f1a21\n\nARGUMENTS:\n    [input]    Input files or folders\n\nOPTIONS:\n    -h, --help                               Prints help information\n        --debug                                                     \n        --force                                                     \n        --include-extension                                         \n        --order-by                                                  \n        --limit                                                     \n    -y, --assume-yes                                                \n        --dry-run                                                   \n        --taggers                                                   \n        --script                                                    \n        --script-tagger-parameter                                   \n        --prepend-movement-to-description                           \n        --meta-artist                                               \n        --meta-album                                                \n        --meta-album-artist                                         \n        --meta-bpm                                                  \n        --meta-chapters-table-description                           \n        --meta-comment                                              \n        --meta-composer                                             \n        --meta-conductor                                            \n        --meta-copyright                                            \n        --meta-description                                          \n        --meta-disc-number                                          \n        --meta-disc-total                                           \n        --meta-encoded-by                                           \n        --meta-encoder-settings                                     \n        --meta-encoding-tool                                        \n        --meta-genre                                                \n        --meta-group                                                \n        --meta-itunes-compilation                                   \n        --meta-itunes-media-type                                    \n        --meta-itunes-play-gap                                      \n        --meta-long-description                                     \n        --meta-part                                                 \n        --meta-movement                                             \n        --meta-movement-name                                        \n        --meta-narrator                                             \n        --meta-original-album                                       \n        --meta-original-artist                                      \n        --meta-popularity                                           \n        --meta-publisher                                            \n        --meta-publishing-date                                      \n        --meta-purchase-date                                        \n        --meta-recording-date                                       \n        --meta-sort-album                                           \n        --meta-sort-album-artist                                    \n        --meta-sort-artist                                          \n        --meta-sort-composer                                        \n        --meta-sort-title                                           \n        --meta-subtitle                                             \n        --meta-title                                                \n        --meta-track-number                                         \n        --meta-track-total                                          \n        --meta-additional-field                                     \n        --auto-import                                               \n        --meta-chapters-file                                        \n        --meta-cover-file                                           \n        --meta-tone-json-file                                       \n    -p, --path-pattern                                              \n        --path-pattern-extension                                    \n        --meta-equate                                               \n        --meta-remove-additional-field                              \n        --meta-remove-property\n```\n\n#### filename to tag via `--path-pattern` / `-p`\n\nIt is possible to use the `tag` subcommand with multiple `--path-pattern` arguments to read metadata from path names. Please note:\n\n- If multiple path patterns are present, the first matching one is preferred\n- Path patterns can be applied recursively for a whole directory tree as well as for single files\n- It is recommended use the `--dry-run` flag to see a diff before changing anything\n  - there is an [issue with flags] like `--dry-run`, that they sometimes not work depending on the position - sometimes shifting them around helps\n- Path pattern matching is based on [grok.net], so all metadata properties could be read from a path name and there are a lot of things yet to be documented\n  - For now it is recommended to use the short hands below\n\n**short hands**\n\nAll short hands are configured to match non-slash (`/`) or part numbers (`[0-9-.IVXLCDM]+`).\n\n- `%a` -  `Artist`\n- `%A` -  `SortArtist`\n- `%c` -  `Comment`\n- `%C` -  `Copyright`\n- `%d` -  `Description`\n- `%D` -  `LongDescription`\n- `%g` -  `Genre`\n- `%m` -  `Album`\n- `%M` -  `SortAlbum`\n- `%n` -  `Title`\n- `%N` -  `SortTitle`\n- `%p` -  `Part` (only matching part numbers)\n- `%s` -  `MovementName`\n- `%t` -  `AlbumArtist`\n- `%w` -  `Composer`\n- `%y` -  `ReleaseDate`\n- `%z` -  `IgnoreDummy`\n- `%Z` -  `IgnoreDummy` (only matching part numbers)\n\n\n#### Custom scripted taggers (experimental)\n\nWith `tone v0.0.4` it is possible to use *scripted taggers*. Long story short: You can now use JavaScript\nto hook into the tagging mechanism and write your own *extensions* for `tone`.\n\n\u003e Note: script support is limited to a specific subset of JavaScript and does not support every feature that is supported in modern browsers. If you would like to know more, take a look at [jint]\n\n##### create a javascript file\n\nLets say you would like to consume an external API to set some tags, in our example we use http://musicbrainz.org to tag the audiobook *Harry Potter and the Philosopher\u0019s Stone* :\n\n```js\n// musicbrainz.js\nfunction musicbrainz(metadata, parameters) {\n  // e2310769-2e68-462f-b54f-25ac8e3f1a21\n  var id = parameters.length \u003e 0 ? parameters[0] : null;\n  if(id === null) {\n    console.log(\"Please provide a valid musicbrainz release id to use this tagger\");\n    return;\n  }\n  var url = \"http://musicbrainz.org/ws/2/release/\" + id + \"?inc=recordings\u0026fmt=json\";\n  console.log(\"fetching url:\", url);\n  \n  // User-Agent header is required for musicbrainz to provide a response\n  var json = tone.Fetch(url, {\n      headers: {\n        'User-Agent': 'Mozilla/5.0 (iPad; U; CPU OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4'\n      }\n  });\n  // you could also read a text file in the base path of the audio file\n  // json = tone.ReadTextFile(metadata.BasePath + \"/musicbrainz.json\");\n  \n  var result = JSON.parse(json);\n  metadata.Title = result.title;\n  console.log(\"new title:\", result.title);\n\n  if('barcode' in result) {\n    metadata.AdditionalFields[\"ISBN\"] = result.barcode;\n    console.log(\"new barcode:\", result.barcode);\n  }\n}\n\n// register your function name as tagger\ntone.RegisterTagger(\"musicbrainz\");\n```\n\n##### run your tagger\n\nNow you can use the `--script` parameter to load your custom `JavaScript` and furthermore\nthe `--script-tagger-parameter` to provide the `parameters` array used in the tagger function.\nIf you would like to prevent the default `tone` taggers to be applied, you can also limit the\nthem to your scripted one via `--taggers=musicbrainz`.\n\n```bash\ntone tag \"harry-potter-1.m4b\" --taggers=\"musicbrainz\" --script=\"musicbrainz.js\" --script-tagger-parameter=\"e2310769-2e68-462f-b54f-25ac8e3f1a21\"\n```\n\n##### Tagger API\n\nTo get an overview of fields, that can be accessed or modified via the `metadata` object, you should take a look at the [`IMetadata` interface](https://github.com/sandreas/tone/blob/main/tone/Metadata/IMetadata.cs). Not all of them are primitive types, but there are API at least some helper methods to overcome this problem (more are planned):\n\n| Method                                                                                                                                    | Description                                                                                                                                                                | Notes                                                                                                                     |\n|-------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------|\n| `tone.RegisterTagger(string functionName):void`                                                                                           | Registers a custom tagger function with `functionName`                                                                                                                     | - |\n| `tone.Fetch(string url [, object? options]):string`                                                                                       | Fetches remote `url` contents using `options` inspired by [original fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch)                     | Only a small subset of options is implemented (mainly `method`, `body` and `headers`)                                     |\n| `tone.Download(string url, string destinationPath [, object options]):bool`                                                               | Downloads a remote `\u003curl\u003e` to `\u003cdestinationFile\u003e` using `options` inspired by [original fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch) | Returns `true` on success, `false` on error\u003cbr/\u003eDirectories will be created recursively\u003cbr/\u003eFiles are not overwritten by default |\n| `tone.ReadTextFile(string path):string`                                                                                                   | Reads a text file completely as string                                                                                                                                     | - |\n| `tone.WriteTextFile(string path, string content):void`                                                                                    | Writes text to a file (create file if not exists, overwrite contents)                                                                                                      | - |\n| `tone.AppendTextFile(string path, string content):void`                                                                                   | Appends text to a file  (create file if not exists, append contents)                                                                                                       | - |\n| `tone.LimitByteLength(string message, int maxLength):string`                                                                              | Limites text to byte length (not char length)                                                                                                                              | - |\n| `tone.CreateDateTime(string dateString):DateTime`                                                                                         | Creates a `DateTime` value from string                                                                                                                                     | e.g. for `metadata.PublishingDate`|\n| `tone.CreateTimeSpan(number milliseconds):TimeSpan`                                                                                       | Creates a `TimeSpan` value from string                                                                                                                                     | e.g. for `metadata.TotalDuration`|  \n| `tone.CreatePicture(string path):PictureInfo`                                                                                             | Creates a `PictureInfo` value from a path (refer to `Download`)                                                                                                            | for `metadata.EmbeddedPictures`|   \n| `tone.CreateChapter(string title, number startMs, number lengthMs [, PictureInfo picture, string subtitle, string uniqueID]):ChapterInfo` | Creates a `ChapterInfo`                                                                                                                                                    | for `metadata.Chapters`|  \n\n# Development\n\n\n## Setup environment\n\nTo build `tone`, you need the `dotnet` SDK with at least version `6.0`. After this you check out the code via git and that's it.\n\n```bash\n# check dotnet version \u003e 6.0\ndotnet --version\n\n# clone git repository\ngit clone https://github.com/sandreas/tone.git\n\n# change into main solution\ncd tone\n\n# restore nuget packages\ndotnet restore\n\n# build solution\ndotnet build\n```\n\n## First test and using an IDE \n\nRun `tone` without params to test your environment\n```bash\n# change to project tone/tone\ncd tone \n\n# run the project\ndotnet run\n\n# output should be something like:\n# USAGE:\n#     tone [OPTIONS] \u003cCOMMAND\u003e\n# ...\n```\n\nIf this works, you can now open the `tone.sln` file in the main directory with your favorite IDE (e.g. Visual Studio, JetBrains Rider or Visual Studio Code)\n\n## Publish a binary\nYou can now also publish `tone` as single binary. Before you build an executable binary, you have to choose a valid runtime identifier (RID) \nfor the operating system and the architecture you would like to build for. \nValid RID values are for example win-x64, linux-x64, osx-x64 and so on \n\nRefer to the official [RID catalog] and please ensure, your RID is supported by the according `dotnet` version (older versions may not support modern runtime ids)\n\nThe most common variants are probably these:\n\n```bash\n# windows (x64)\ndotnet publish tone/tone.csproj --runtime \"win-x64\" --framework net6.0 -c Release -p:PublishSingleFile=true --self-contained true -p:PublishReadyToRun=true -p:PublishTrimmed=true -o \"dist/tone\"\n\n# macOS (x64)\ndotnet publish tone/tone.csproj --runtime \"osx-x64\" --framework net6.0 -c Release -p:PublishSingleFile=true --self-contained true -p:PublishReadyToRun=true -p:PublishTrimmed=true -o \"dist/tone\"\n\n# macOS (arm64)\ndotnet publish tone/tone.csproj --runtime \"osx-arm64\" --framework net6.0 -c Release -p:PublishSingleFile=true --self-contained true -p:PublishReadyToRun=true -p:PublishTrimmed=true -o \"dist/tone\"\n\n# linux (x64)\ndotnet publish tone/tone.csproj --runtime \"linux-x64\" --framework net6.0 -c Release -p:PublishSingleFile=true --self-contained true -p:PublishReadyToRun=true -p:PublishTrimmed=true -o \"dist/tone\"\n```\n\n# Submitting an issue\n\nFound an issue? Here are some helpful commands to create sample audio files without copyright to reproduce the issue:\n\n```\n# create a 5 seconds silent sample\nffmpeg -ar 48000 -ac 1 -f s16le -i /dev/zero -t 5 -y sample.wav\n\n# convert wav to m4b (mp3 would also work)\nffmpeg -i sample.wav -f mp4 sample.m4b\n\n# download a sample cover\nwget -c https://picsum.photos/id/237/500/500 -O cover.jpg\n\n# embed the cover into the sample\nffmpeg -i sample.m4b -i cover.jpg -map 0 -map 1 -c copy -disposition:v:1 attached_pic -f mp4 ready.m4b\n\n# run your tone command to reproduce the issue\ntone tag --meta-genre=Fantasy sample.m4b\n```\n\n# known issues\n\nThe following issues are known, part of an external library and already reported:\n\n- `--meta-*` options cannot be set to empty values ([spectre.console 842])\n  - workaround: use `--meta-remove-property` instead\n\n[atldotnet 155]: https://github.com/Zeugma440/atldotnet/issues/155\n\n[releases]: https://github.com/sandreas/tone/releases\n[atldotnet]: https://github.com/Zeugma440/atldotnet\n[issue with flags]: https://github.com/spectreconsole/spectre.console/issues/825\n[grok.net]: https://github.com/Marusyk/grok.net\n[CliWrap]: https://github.com/Tyrrrz/CliWrap\n[jint]: https://github.com/sebastienros/jint\n[RID catalog]: https://learn.microsoft.com/en-us/dotnet/core/rid-catalog","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsandreas%2Ftone","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsandreas%2Ftone","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsandreas%2Ftone/lists"}