You can use the verbose output of VLC, but it's a bit complicated. You need verbosity level 2 to even get any file names printed at all (for whatever reason), but that logs tons of other things as well, so you need to filter the output.
Here is an example output of verbosity 2, but only including the file names that tell you the path (vlc --verbose 2 file.mp3 | grep "file.mp3"
):
[00007f1720000c20] main input debug: Creating an input for preparsing 'file.mp3'
[00007f16d0000c80] main input debug: `file:///path/to/file.mp3' gives access `file' demux `any' path `/path/to/file.mp3'
[00007f16c4000fe0] main input source debug: creating demux: access='file' demux='any' location='/path/to/file.mp3' file='/path/to/file.mp3'
[00007f16c4001690] main stream debug: creating access: file:///path/to/file.mp3
[00007f16c4001690] main stream debug: (path: /path/to/file.mp3)
[00007f16c4000fe0] main input source debug: attachment of directory-extractor failed for file:///path/to/file.mp3
[00007f16c4000fe0] main input source debug: creating demux: access='file' demux='any' location='/path/to/file.mp3' file='/path/to/file.mp3'
[00007f16d0000c80] main input debug: `file:///path/to/file.mp3' successfully opened
Here is an example command that prints all played file names to the console (you can redirect that into a file with >> file.txt
at the end):
vlc --verbose 2 file1.mp3 /path/to/file2.m4a 2>&1 | grep -v "ml.xspf" | grep -oP "\/.*\/\K.*(?=\.[a-zA-Z0-9-_]*\' successfully opened)"
Explanation:
vlc … file1.mp3 /path/to/file2.m4a
opens VLC and plays those two tracks. You can also set it to random or whatever on the command line, there are MANY options.
--verbose 2
activates the verbose output. You could also put this into a file with --file-logging --log-verbose 2 --log-file file.log
, but the rest of my command also works with the command line, so this works better.
2>&1 |
redirects the error output (and the standard output) to the next command.
grep -v "ml.xspf"
filters out anything containing "ml.xspf
", because for some reason VLC opens that file (in my case located in ~/.local/share/vlc
) the same way as a regular file. It's not visible anywhere in the GUI, but it looks the same as a regular played file in the log.
| grep -oP
only lets lines through that match a certain Perl-style regex and only displays the matched part of that regex.
- Now the complicated part:
"\/.*\/\K.*(?=\.[a-zA-Z0-9-_]*\' successfully opened)"
is a regular expression that matches lines like the last one in the log example above and only outputs the file name without the ending (remove \.[a-zA-Z0-9-_]*
if you want to keep it) and path (change \/.*\/
to file\:\/\/
if you want to keep it).
Explanation for that regex:
\/.*\/
matches anything between two slashes (/
) and the slashes themselves. That could for example be "/path/to/
".
\K
excludes everything before it from the match, meaning that it has to be there to have any match at all, but it's not in the result.
.*
just matches anything (except newlines etc.).
(?=…)
is a "lookahead", which does essentially the opposite of \K
, it excludes everything after it (or in this case inside the brackets) from the match, but it still needs to be there to have a match.
\.
matches a period (.
).
[a-zA-Z0-9-_]*
matches all letters, numbers, -
and _
an arbitrary number of times, which should hopefully cover all file endings.
\' successfully opened
matches the end of the line from the log example.
- I picked the "successfully opened" line instead of some more easily parseable ones, because it seems to confirm that no errors have happened, so for example if you dumped your entire home folder into it, it would not output the files that it couldn't play because they're not media files.
A special difficulty in this problem was that many commands cannot be used. For example basename
doesn't work with StdIn, sed
only executes once the input ends and so on. VLC has interfaces that are intended for controlling and monitoring it from the outside, but they all seem to be very complicated to use. The simplest one seems to be the HTTP interface, but that cannot be used without a password, which makes using it programmatically much harder.