xiph / flac

Free Lossless Audio Codec
https://xiph.org/flac/
GNU Free Documentation License v1.3
1.65k stars 279 forks source link

Decrease the default verbosity of metaflac --list #633

Open acc987 opened 1 year ago

acc987 commented 1 year ago

Preface

Let me start by mentioning that I was very happy to read in the release notes for 1.4.3 that metaflac now provides a way to copy certain blocks of meta data via --list --data-format=binary and --append as I needed to write a script that can copy meta data from one file to another last week. Lucky timing indeed.

The problem at hand

While writing that script, there was one thing that irked me, namely that when I manually invoke metaflac --list "$FlacFile" on a FLAC file to get an overview of the number and type of meta data blocks, hex dumps for binary data (such as embedded album art, which can have a size on the order of one hundred kilobyte) are displayed, which makes the output incredibly noisy and at least on Windows Terminal forces me to redirect the output to a file before being able to view it due to Windows Terminal having a very "analogue" scrolling speed...

I thus wanted to ask whether you could please make the hex dumps of any binary blob stored in a meta data block optional and by default skip its output either entirely or only print the first couple of bytes?

An example for where this could improve performance downstream

Making the metaflac --list default output less verbose would also speed up scripts that parse it. In my example I am parsing its output to figure out the block numbers that I need to copy. In PowerShell my code that should copy all meta data except for the STREAMINFO, which you cannot copy, and the SEEKTABLE, which I do not want to copy, from $ReferenceFlac to $TargetFlac looks like this:

# We first transfer the tags from the VORBIS_COMMENT block...
$MetaFile = New-TemporaryFile | Rename-Item -NewName { [System.IO.Path]::ChangeExtension($_.Name, 'txt') } -PassThru
& metaflac.exe --export-tags-to="$MetaFile" "$ReferenceFlac"
& metaflac.exe --import-tags-from="$MetaFile" "$TargetFlac"
# ...and then we append any block that is not of type STREAMINFO, SEEKTABLE, or VORBIS_COMMENT:
& metaflac.exe --list --except-block-type=STREAMINFO,SEEKTABLE,VORBIS_COMMENT "$ReferenceFlac" `
    | Select-String -Pattern '^METADATA block #(\d+)$' | ForEach-Object {
        $BlockNum = $_.Matches.Groups[1].Value
        Start-Process 'metaflac.exe' ('--list', '--data-format=binary', "--block-number=$BlockNum", "$ReferenceFlac") -RedirectStandardOutput "$MetaFile" -NoNewWindow -Wait
        Start-Process 'metaflac.exe' ('--append', "$TargetFlac") -RedirectStandardInput "$MetaFile" -NoNewWindow -Wait
    }
# Clean up temporary file:
Remove-Item "$MetaFile"

So every line of that hex dump output has to go through a regular expression that will effectively discard it anyway and would thus benefit from the output being less verbose.

(As a side note: From what I gather that should be the most effective and efficient way to copy metadata between two FLAC files using the 1.4.3 release. Feel free to let me know if there is a better way to do so. And apologies for creating such a verbose issue, but I figured that understanding what I am trying to do helps you with understanding why this is important for me.)

ktmf01 commented 1 year ago

I think changing current behavior is a very bad idea, as it will break existing scripts. Adding a new option is possible of course. Perhaps something like --list-headers that only displays block type and length?

ktmf01 commented 1 year ago

By the way, wouldn't it be much better if you did this?

metaflac --list --data-format=binary --except-block-type=STREAMINFO,SEEKTABLE | metaflac --append destinationfile.flac

I am unfamiliar with powershell, but I guess that would translate to

Start-Process 'metaflac.exe' ('--list', '--data-format=binary', "--except-block-type=STREAMINFO,SEEKTABLE", "$ReferenceFlac") -RedirectStandardOutput "$MetaFile" -NoNewWindow -Wait
Start-Process 'metaflac.exe' ('--append', "$TargetFlac") -RedirectStandardInput "$MetaFile" -NoNewWindow -Wait

That copies all blocks except streaminfo and seektable

acc987 commented 1 year ago

I think changing current behavior is a very bad idea, as it will break existing scripts. Adding a new option is possible of course. Perhaps something like --list-headers that only displays block type and length?

What I would want is an option to skip the output of the PICTURE data when using --list with --data-format=text. I am not sure whether it would also make sense to also skip the output of the APPLICATION data as I have never seen an example and don't know whether that's binary or text. Note that with data I am referring to the <n> bytes of "Application data (n must be a multiple of 8)" and the <n*8> bytes of "The binary picture data" as per https://xiph.org/flac/format.html.

So I am thinking more of something along the lines of an --omit-hexdumps option that would of course only have an effect with --data-format=text. Would adding such an option be consistent with the philosophy behind the CLI? (Regardless of the title of the issue not changing the default behavior would also be fine for me.)

By the way, wouldn't it be much better if you did this?

Ah! https://xiph.org/flac/documentation_tools_metaflac.html states that --append "[i]nsert[s] a metadata block from a file." I therefore had no reason to assume that it would also accept multiple blocks concatenated into one larger blob. I recommend that you clarify the documentation as this makes scripting much easier, of course.

As for also transferring the VORBIS_COMMENT block via --append: In my case $TargetFlac already has such a block, which contains the vendor string. I assume that removing that block prior to appending would work, however, I cannot expect the vendor string from both blocks to be identical so I chose the --export-tags/--import-tags route.

(As a side-note: The awkward use of Start-Process is due to the fact that you currently cannot pipe binary output between native executables in PowerShell, though https://github.com/PowerShell/PowerShell/issues/1908 seems to be fixed in the upcoming PowerShell 7.4.0.)