Demlo
A dynamic and extensible music library organizer
About
Demlo organizes your music library automatically and dynamically. It runs a chain of user-defined Lua scripts using variables such as tags and file properties. This way it yields virtually unlimited customization power to the user.
Preview
Here follows a sample output showing the “before-after” differences.
$ demlo fantasie_impromptu.flac :: Load config: /home/johndoe/.config/demlo/demlorc :: Load script: /usr/share/demlo/scripts/tag.lua :: Load script: /usr/share/demlo/scripts/sub.lua :: Load script: /usr/share/demlo/scripts/case.lua :: Load script: /usr/share/demlo/scripts/punctuation.lua :: Load script: /usr/share/demlo/scripts/encoding.lua :: Load script: /usr/share/demlo/scripts/path.lua :: Load script: /usr/share/demlo/scripts/cover.lua :: Load script: /home/johndoe/.config/demlo/scripts/lossy.lua ==> fantasie_impromptu.flac === FILE === [/home/johndoe/fantasie_impromptu.flac] | path | [/home/johndoe/music/Chopin/The Best Ever Piano ] | | [Classics (John Doe, 2014)/Fantasie-Impromptu in] | | [ C Sharp Minor, Op. 66.ogg] [flac] | format | [ogg] [bitrate=320000] | parameters | [[-c:a libvorbis -q:a 10]] === TAGS === [john doe's classical collection II] | album | [John Doe's Classical Collection II] [] | album_artist | [Chopin] [] | artist | [Chopin] [chopin] | composer | [] [02/13/2014] | date | [2014] [Classics] | genre | [Classical] [John_Doe ] | performer | [John Doe] [Fantasie-Impromptu in c sharp MInor , Op.66] | title | [Fantasie-Impromptu in C Sharp Minor, Op. 66] === COVERS === ['cover.jpg' [500x500] <jpeg>] | external | [/home/johndoe/music/Chopin/The Best Ever Piano ] | | [Classics (John Doe, 2014)/Cover.jpg]
Scenario
Demlo can address any of these recurring music library issues (and much more):
- Lack of folder structure.
- Tags are not homogeneous, case is wrong, some entries are filled and other not.
- Bad audio quality.
- Audio codecs are not always consistent. (Lossless/lossy…)
- mp3’s id3tags hell…
- Multiple covers, embedded and/or external, bad quality, etc.
Features
A few scripts are provided by default. They give a good example of the possibilities offered by Demlo. Pick which one to load by default, rewrite some of them, or write new ones from scratch. You can preview changes to make sure everything looks satisfactory.
Call Demlo over a complete music library and it will process everything in one single run.
Scripts can be chained: this feature makes Demlo extremely flexible and powerful.
Move all files according to a unique, yet dynamic folder hierarchy. For instance, setting
output.path = table.concat {library, '/', o.artist, '/', o.album ~= nil and (o.date ~= nil and o.album .. '/' or o.date .. ' - ' .. o.album .. '/') or '', track_padded ~= nil and '' or track_padded .. ' - ', o.title}
will move
john doe - 1. intro.ogg
to~/music/John Doe/2013 - Great Album/01 - Intro.ogg
if there is an album and a date,~/music/John Doe/Great Album/01 - Intro.ogg
if there is an album but no date,~/music/John Doe/01 - Intro.ogg
if there is no album.
- Case checking: the default script
case.lua
will turn everything to title case or sentence case. It supports special cases such as Roman numerals, McDonald, etc. It also supports a list of exceptions, e.g. “DJ” and “feat”. - Encoding: the file format and codec is exposed to user scripts so that you can conditionally re-encode any file. The encoding is performed by FFmpeg. The encoding parameters can be fully customized. (Format, codec, bitrate, etc.)
- Covers: Demlo makes it possible to automatically remove embedded covers, skip duplicates, skip covers below a quality threshold, resize big covers down, etc.
- Different kinds of music: classical, soundtrack, and band music usually have different types of tags and different folder structures. It is possible to manage different music libraries easily by setting the desired root folder from command-line.
- Demlo supports both external and embedded cuesheets. It is also able to parse “non-standard” sheets, which are not so uncommon.
- Demlo can be interfaced with any other program, both ways. (X calls Demlo or Demlo calls X.) For instance you can edit tags with your favorite text editor.
- Demlo has MusicBrainz and Cover Archive support for online tagging and cover fetching.
Installation
See the development page.
Usage
See demlo -h
and the manual.
License
See the LICENSE
file in the source code.
The Go rewrite
Demlo used to be written in pure Lua. This has led to numerous issues, such as poor parallelism, slow processing, unreliable dependencies, race conditions, clunky network support and broken unicode support.
Starting from version 2 onward, the core has been rewritten in Go to address all these issues. Many changes have been undertaken in the process:
- Performance: Faster JSON (un)marshaling, faster checksums (no subprocess, partial checksums), better parallelization.
- CLI flags: Reduced the number of flags and made them simpler. Some flags can be used more than once, which makes it possible to call scripts with spaces in their names.
- Portability: Core detection now works on all OSes.
- Race conditions: Remove all race conditions (cache, screen output, file access, temp files).
tags
are no longer stripped away frominput.streams[i].tags
norinput.format.tags
.- Cuesheet: Multi-file support.
- Preview: Changes in path, format, parameters and covers are displayed using the same formatting than tags. Long lines are wrapped. Formatted preview is off when stdout is redirected, JSON formatting is used instead.
- Full unicode support in scripts (
string.len
,string.gsub
, etc.). Fix issues with[XY]
regexps where X and Y are non-ASCII. - Scripts can be parameterized through global variables.
- Config file is defined from the
DEMLORC
environment variable or default path, no more from a CLI flag. It greatly alleviates the complexity of flag parsing. - Sandboxes accept more functions from the Lua standard library, such as
os.getenv
. input
andoutput
structures have changed. (See compatibility notice.)- Lua patterns have been replaced by Go regexps. (See compatibility notice.)
- Extra audio streams and non-cover streams are stripped out.
- Misc. fixes: Index creation for multi-track files, non-integer cover resolution, etc.
- MusicBrainz: Clean queries, improved heuristic. The official artist name is used instead of the official album artist name. (It enforces homogeneity.)
- The
titlecase
function has been moved to the script side and split into ’setcase’ and ’punctuation’. - Support for in-place tagging. This dramatically speeds up the process when the
-rmsrc
option is active.
Compatibility notice
User scripts still rely on input
and output
only. These structures have
remained identical but for a few elements:
filename
has been renamed topath
.output.bitrate
has been replaced by theoutput.parameters
array. Use it to pass arbitrary arguments to FFmpeg (codec, bitrate, etc.).- Cover options have been fully ravamped.
The Lua patterns of the string library have been replaced by Go regexps.