A tag editor with Qt GUI and command-line interface. Supports MP4 (iTunes), ID3, Vorbis, Opus, FLAC and Matroska.
The tag editor can read and write the following tag formats:
Further remarks:
The tag editor can also display technical information such as the ID, format, language, bitrate, duration, size, timestamps, sampling frequency, FPS and other information of the tracks.
It also allows to inspect and validate the element structure of MP4 and Matroska files.
Sometimes the tag editor has to rewrite the entire file in order to apply changes. This leads to the creation
of a temporary file. With the GUI's default settings this is even enforced to be conservative as the temporary files
also serve as a backup in case something goes wrong, e.g. your computer crashes while saving or a bug within the tag
editor breaks particularly structured files. When using the CLI it is therefore also recommend to use --force-rewrite
.
The next section describes how to tweak settings to avoid rewriting at the cost of having no backup, having some padding within the files and/or storing tags at the end of the file.
Nevertheless, it will not always be possible to avoid rewriting a file in all cases anyways. You can configure a
directory for temporary files within the GUI settings or the CLI option --temp-dir
. Then you can easily clean up all
temporary files at some point together. For efficiency the temporary directory should be on the same file system
as the files you are editing. A feature to delete temporary files automatically has not been implemented yet.
The editor allows you to choose whether tags should be placed at the beginning or at the end of an MP4/Matroska file. Placing tags at the end of the file can avoid having to rewrite the entire file to apply changes.
In the CLI, this is controlled via --tag-pos
option.
To enforce a specific --tag-pos
, even if this requires the file to be rewritten, combine with the --force
option.
ID3v2 tags and Vorbis/Opus comments can only be placed at the beginning. ID3v1 tags can only be placed at the end of the file. Hence, this configuration has no effect when dealing with such tags.
It is also possible to control the position of the index/cues. However, this is currently only supported when dealing with Matroska files.
Note: This can not be implemented for MP4 since tags and index are tied to each other. When dealing with MP4 files the index position will always be the same as the tag position.
Putting the index at the beginning of the file is sometimes called faststart.
For forcing faststart via CLI the following options are required:
tageditor set --index-pos front --force
Padding allows adding additional tag information without rewriting the entire file or appending the tag. Usage of padding can be configured:
It is also possible to force rewriting the entire file to enforce the preferred padding is used.
The relevant CLI options are --min-padding
, --max-padding
, --preferred-padding
and --force-rewrite
.
Taking advantage of padding is currently not supported when dealing with Ogg streams (it is supported when dealing with raw FLAC streams).
As explained in the "Backup/temporary files" section, this is not a good idea as the temporary file that is created when rewriting the entire file also serves as backup. However, if you nevertheless want to avoid rewriting the file as much as possible, set the following in the GUI's "File layout" settings:
When using the CLI, you just need to add --max-padding 429496729
to the CLI arguments (and avoid any of the other
arguments mentioned in previous sections).
Editing big files (especially Matroska files) can take some time. To improve the performance, put the index at the
end of the file (CLI option --index-pos back
) because then the size of the index will never have to be recalculated.
Also follow the advice from the "Backup/temporary files" section to force rewriting and to
put the temporary directory on the same filesystem as the file you are editing. Forcing a rewrite can improve the
performance because then the tag editor will not even try to see whether it could be avoided and can thus skip
computations that can take a notable time for big Matroska files.
Of course being able to avoid a rewrite would still be more optimal. Checkout the previous section for how to achieve
that. To improve performance further when avoiding a rewrite, put the tag at the end (CLI option --tag-pos back
).
Then the tag editor will not even try to put tags at the front and can thus skip a few computations. (Avoiding a
rewrite is still not a good idea in general.)
The Matroska container format (and WebM which is based on Matroska) are breaking with common conventions. Therefore not all CLI examples mentioned below make sense to use on such files.
Generally, one Matroska file can have multiple tags and each tag has a "target" which decides to what the fields of the tag apply to, e.g. the song or the whole album. So when using the CLI or the GUI you need to be aware to what tag/target to add fields to.
Matroska also does not use one combined field for the track/disk number and total like other formats do. It instead
uses the separate fields part
and totalparts
which again need to be added to a tag of the desired target (e.g.
50/"ALBUM" for the track number and total).
Checkout the official Matroska documentation on tagging for details. It also contains examples for audio content and video content.
Note that Tag Editor does not support the XML format mentioned on the Matroska documentation. In the GUI you can simply add/remove/edit tags and their targets via the controls at the top of the editor. In the settings you can also specify that tags of certain targets should be added automatically when loading a file. When using the CLI you can specify that a field should be added to a tag of a certain target by specifying the target before that field. You can also explicitly remove tags of certain targets. Examples of the concrete CLI usage can be found below.
See the release section on GitHub.
tageditor-qt6
package if available for your OS.tageditor
from the
official repositorieslibopengl0
is installed on Debian/Ubuntu)QT_QPA_PLATFORM=xcb
to disable
native Wayland support if it does not work on your system)B9E36A7275FC61B464B67907E06FE8F53CDC6A4C
.B9E36A7275FC61B464B67907E06FE8F53CDC6A4C
.The Tag Editor has a Qt-based GUI and a command line interface. For a C++ library interface checkout the underlying tagparser library.
The GUI should be self-explaining - a lot of the UI elements have tooltips with further explanations. The basic workflow is quite simple:
You can set the behaviour of the editor to keep previous values, so you don't have to enter information like album name or artist for all files in an album again and again.
The GUI does not support setting multiple values of the same field (besides covers of different types). If a file already contains fields with multiple values, the additional values are discarded. Use the CLI if support for multiple values per field is required. Not all tag formats support this anyways, though.
The GUI does not support batch processing. I recommend using the CLI for this.
This screenshot shows the experimental MusicBrainz/LyricWiki search.
Checkout the settings dialog. You can
Settings of the GUI do not affect the CLI.
There is also a tool to rename files using the tag information stored in the files. The new name for each file is generated by a small JavaScript which can be customized. An example script is provided. Before any actual changes are made, you will see a preview with the generated file names. As shown in the example script it is also possible to move files into another directory.
The tag editor also features a MusicBrainz, Cover Art Archive and LyricWiki search.
tageditor <operation> [options]
Checkout the available operations and options with --help
. For a list of all available field names, track
attribute names and modifier, use the CLI option --print-field-names
. Not all fields are supported by all
tag/container formats. Most notably, the Matroska container format does not use track
/disk
to store the
track/disk number and total in one field. Instead, the fields part
and totalparts
need to be used on the
desired target.
Note that Windows users must use tageditor-cli.exe
instead of tageditor.exe
or use Mintty as terminal.
Checkout the "Windows-specific issues" section for details.
Here are some Bash examples which illustrate getting and setting tag information:
Displays title, album and artist of all *.m4a files in the specified directory:
tageditor get title album artist --files /some/dir/*.m4a
Displays all supported fields of all *.mkv files in the specified directory:
tageditor get --files /some/dir/*.mkv
Extracts the cover of the specified (Opus) file:
tageditor extract cover --output-file the-cover.jpg --file some-file.opus
--attachment
.Displays technical information about all *.m4a files in the specified directory:
tageditor info --files /some/dir/*.m4a
Sets title, album, artist, cover and track number of all *.m4a files in the specified directory:
tageditor set title="Title of "{1st,2nd,3rd}" file" title="Title of "{4..16}"th file" \
album="The Album" artist="The Artist" \
cover'=/path/to/image' lyrics'>=/path/to/lyrics' track'+=1/16' --files /some/dir/*.m4a
>
after the field name lyrics
causes the tag editor to read the value from the specified file.
This works for other fields as well and is implied for cover
.+
sign after the field name track
indicates that the field value should be increased after a file
has been processed./path/to/image
and the lyrics from the file /path/to/lyrics
.Sets title of both specified files and the album of the second specified file:
tageditor set title0="Title for both files" album1="Album for 2nd file" \
--files file1.ogg file2.mp3
The number after the field name specifies the index of the first file to use the value for. The first index is 0.
Sets the title specifically for the track with the ID 3134325680
and removes
the tags targeting the song/track and the album/movie/episode in general:
tageditor set target-level=30 target-tracks=3134325680 title="Title for track 3134325680" \
--remove-target target-level=50 --remove-target target-level=30 \
--files file.mka
For more information checkout the Matroska specification.
Sets custom fields:
tageditor set mkv:FOO=bar1 mp4:©foo=bar2 -f file.mkv file.m4a
FOO
is set to bar1
in file.mkv and the custom field ©foo
is set to bar2
in file.m4a. So the prefixes tell the tag editor that the specified field
ID is a native field ID of a particular tag format rather than a generic identifier. Native
fields are only applied to the corresponding format of course.mp4
: iTune-style MP4/M4A ID (must be exactly 4 characters)mkv
: Matroska IDid3
: ID3v2 ID (must be exactly 3 or 4 characters depending on the tag version)vorbis
: Vorbis comment ID, also works for Opus (which uses Vorbis comments as well)Removes the "forced" flag from all tracks, flags the track with the ID 2 as "default" and sets its language to "ger":
tageditor set track-id=all forced=no track-id=2 default=yes language=ger
Here is another example, demonstrating the use of arrays and the syntax to auto-increase numeric fields such as the track number:
cd some/dir
# create an empty array
titles=()
# iterate through all music files in the directory
for file in *.m4a; do \
# truncate the first 10 characters
title="${file:10}"; \
# append the title truncating the extension
titles+=("title=${title%.*}"); \
done
# now set the titles and other tag information
tageditor set "${titles[@]}" album="Some Album" track+=1/25 disk=1/1 -f *.m4a
Sets a cover of a special type with a description:
tageditor set cover=":front-cover" cover0="/path/to/back-cover.jpg:back-cover:The description" -f foo.mp3
path:cover-type:description
. The cover type and description are optional. The
delimiter can be changed via --cover-type-delimiter
which is useful if the path includes a :
.0
after the 2nd cover
is required. Otherwise the 2nd cover would only be set in the 2nd file (which
is not even specified in this example).… cover= cover0="/path/to/back-cover.jpg:back-cover"
.:
is absent), all existing covers of the specified type are replaced and
the new cover will have an empty description.
:
.… cover=":back-cover"
.tageditor --print-field-names
.Sets fields by running a script to compute changes dynamically:
tageditor set --pedantic debug --script path/to/script.js -f foo.mp3
main()
function. This function is invoked for every file and
passed an object representing the current file as first argument. The file only modified if
main()
returns a truthy value or undefined
; otherwise the file is skipped completely (and
thus not modified at all, so values passed via --values
are not applied).testfiles/set-tags.js
in this repository for an example that applies basic
fixes and tries to fetch lyrics and cover art when according settings are passed (e.g.
--script-settings addCover=1 addLyrics=1
).--pedantic debug
is very useful. You may also add
--script-settings dryRun=1
and check for that setting within the script as shown in
testfiles/set-tags.js
.testfiles/set-tags.js
.
ArrayBuffer
. Use must also use an ArrayBuffer
to set the value of binary fields such as the cover.String
or Number
. You must also use
one of those types to set the value of those fields. The string-representation of the
assigned content will then be converted automatically to what's needed internally.utility
object exposes useful methods, e.g. for logging and controlling the event loop.testfiles/http.js
in this repository for an example of using XHR and
controlling the event loop.--id3v1-usage
).
So the tags present during script execution don't necessarily represent tags that are actually
present in the file on disk (but rather the tags that will be present after saving the file).--values
) then these values have precedence over values set by the
script.file.rename(newPath)
). This will be done
immediately and also if main()
returns a falsy value (so it is possible to only rename a
file without modifying it by returning a falsy value). If the specified path is relative, it
is interpreted relative to current directory of the file (and not to the current working
directory of the tag editor).utility.openFile(path)
. This makes it possible
to copy tags over from another file, e.g. to insert tags back from original files that have
been lost when converting to a different format. The mentioned example script set-tags.js
also demonstrates this for covers and lyrics when according script settings are passed (e.g.
--script-settings addCover=1 originalDir=… originalExt=…
). Example:
cd '/…/music'
find 'artist/album' -iname '*.m4a' -exec tageditor set \
--pedantic debug \
--script /…/tageditor/testfiles/set-tags.js \
--script-settings dryRun=1 originalDir='../music-lossless' originalExt=.flac addCover=1 addLyrics=1 \
--temp-dir /…/tmp/tageditor \
--files {} \+
tageditor set ... --pedantic warning -f ...
tageditor info --pedantic warning --validate -f ...
--encoding
and in the GUI settings.
The application depends on c++utilities and tagparser and is built the same way as these libraries. For basic instructions checkout the README file of c++utilities. When the Qt GUI is enabled, Qt and qtutilities are required, too.
To avoid building c++utilities/tagparser/qtutilities separately, follow the instructions under "Building this straight". There's also documentation about various build variables which can be passed to CMake to influence the build.
The Qt GUI is enabled by default. The following Qt modules are required (only the latest Qt 5 and Qt 6 version tested): core concurrent gui network widgets declarative/script webenginewidgets/webkitwidgets
Note that old Qt versions lack support for modern JavaScript features. To use the JavaScript-based renaming tool it is recommend to use at least Qt 5.12.
To specify the major Qt version to use, set QT_PACKAGE_PREFIX
(e.g. add -DQT_PACKAGE_PREFIX:STRING=Qt6
to the CMake arguments).
-DWEBVIEW_PROVIDER:STRING=webkit/webengine/none
to the CMake arguments to use either Qt WebKit (works with
'revived' version as well), Qt WebEngine or no web view at all. If no web view is used, the file information can only
be shown using a plain tree view. Otherwise the user can choose between a web page and a tree view.-DJS_PROVIDER:STRING=script/qml/none
to the CMake arguments to use either Qt Script, Qt QML or no JavaScript
engine at all. If no JavaScript engine is used, the renaming utility is disabled.It is possible to build without the GUI if only the CLI is needed. In this case no Qt dependencies (including qtutilities) are required.
To build without GUI, add the following parameters to the CMake call:
-DWIDGETS_GUI=OFF -DQUICK_GUI=OFF
As a small demo for Reflective RapidJSON, the tag editor features an optional
JSON export. To enable it, add -DENABLE_JSON_EXPORT=ON
to the CMake arguments.
When enabled, the following additional dependencies are required (only at build-time): rapidjson, reflective-rapidjson and llvm/clang
cd "$SOURCES"
git config core.symlinks true # only required on Windows
git clone https://github.com/Martchus/cpp-utilities.git c++utilities
git clone https://github.com/Martchus/tagparser.git
git clone https://github.com/Martchus/qtutilities.git # only required for Qt GUI
git clone https://github.com/Martchus/reflective-rapidjson.git # only required for JSON export
git clone https://github.com/Martchus/tageditor.git
git clone https://github.com/Martchus/subdirs.git
Note that git config core.symlinks=true
is only required under Windows to handle symlinks correctly.
This requires a recent Git version and a filesystem which supports symlinks (NTFS works). Additionally,
you need to
enable Windows Developer Mode.
If you run into "not found" errors on symlink creation use git reset --hard
within the repository to
fix this.
cd "$BUILD_DIR"
cmake \
-G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DLANGUAGE_FILE_ISO_639_2="/usr/share/iso-codes/json/iso_639-2.json" \
-DCMAKE_INSTALL_PREFIX="/install/prefix" \
"$SOURCES/subdirs/tageditor"
/install/prefix
with the directory where you want to install./usr/…/iso_639-2.json
with the path for your iso-codes installation.cd "$BUILD_DIR"
ninja install
DESTDIR
to a
writable location (e.g. DESTDIR="temporary/install/dir" ninja install
) and move the files from there to
the desired location afterwards.The following caveats can be worked around by using the CLI-wrapper instead of the main executable. This is the
file that ends with -cli.exe
. Alternatively you may use Mintty (e.g. via MSYS2) which is also not affected by
those issues:
set ENABLE_CP_UTF8=0
if this
is not wanted.set ENABLE_CONSOLE=0
to disable that behavior.Dark mode should work out of the box under Windows 11 and can otherwise be enabled by selecting the Fusion style.
Tag Editor supports PMv2 out of the box as of Qt 6. You may tweak settings according to the Qt documentation.
Copyright © 2015-2024 Marius Kittler
All code is licensed under GPL-2-or-later.