如何自动记录我在 VLC 播放器窗口中播放的歌曲名称?

如何自动记录我在 VLC 播放器窗口中播放的歌曲名称?

我希望每次用 VLC 打开歌曲时都能保存 .mp3 文件的名称。

编辑:正如你们在评论中提到的;

  1. 我想在播放器窗口中直接打开 VLC。
  2. 我想将正在播放的歌曲名称保存到文本文件中。

我怎样才能实现这个目标?提前谢谢。

答案1

您可以使用以下方式获取当前播放的曲目名称(地址):

lsof -p `pidof -s vlc` | grep -o "/.*\.mp3"

如果您想在双击mp3文件打开 VLC 时保存名称,这是我的想法:

打开 VLC 的桌面文件:

sudo nano /usr/share/applications/vlc.desktop

然后编辑Exec行使其看起来像:

Exec=bash -c "{ /usr/bin/vlc --started-from-file %U; }& sleep 1; lsof -p `pidof -s vlc` | grep -o "/.*\.mp3" > /home/user/list"

它将把文件名保存在/home/user/list

否则,我建议您创建一个简单的键绑定,sh -c 'lsof -p $(pidof -s vlc) | grep -o "/.*\.mp3"'这样无论何时按下该键,它都会保存当前播放的歌曲的名称。

我们还可以创建一个脚本并与 VLC 同时运行它,并使其在后台运行,然后通过该脚本我们可以检查当前正在播放哪个曲目。

答案2

自动记录所有播放过的歌曲,并带有时间戳

或者,无需更改.desktop文件中的任何内容或手动记录歌曲,您可以运行下面的后台脚本。它将played_songs在您的主目录中创建一个名为的日志文件:

在此处输入图片描述

优点是:

  • 全自动记录您播放的所有歌曲
  • 无需更改您的.desktop文件,这意味着当您从命令行启动 VLC 时它也能起作用。

缺点是:

  • 虽然我无法测量或看到任何额外的处理器负载,理论上它补充说一些活动。然而,即使在石器时代的盒子上,这种现象实际上也是不存在的。
  • 有时候(很长一段时间)你需要“清空”或删除日志文件,因为(目前)它没有大小限制。不过,如果你愿意,这个问题很容易解决。

剧本

#!/usr/bin/env python3
import subprocess
import os
import time

home = os.environ["HOME"]
log = os.path.join(home, "played_songs")
def_name = "VLC media player"

def get(cmd):
    try:
        return subprocess.check_output(cmd).decode("utf-8").strip()
    except subprocess.CalledProcessError:
        pass

song1 = None

while True:
    time.sleep(2)
    pid = get(["pgrep", "vlc"])
    if not pid:
        song = None
    else:
        # only do anything at all if vlc runs
        wins = get(["wmctrl", "-lp"])
        if wins:
            wins = wins.splitlines()
            try:
                # check if any of the windows belongs to vlc
                # this will not if it is closed in the meantime
                match = [w.split()[0] for w in wins if pid in w][0]
            except IndexError:
                pass
            else:
                # ...if so, retrieve the song name, only log if there is a new song
                song2 = get(["xdotool", "getwindowname", match])
                if all([song2, song2 != song1, song2 != def_name]):
                    open(log, "a+").write(
                        time.strftime("%H:%M:%S_%d-%m-%Y")+"\n   "+\
                        song2.replace(def_name, "").rstrip(" - ")+"\n"
                        )
                song1 = song2

如何使用

  1. 该脚本需要xdotoolwmctrl

    sudo apt-get install xdotool wmctrl
    
  2. 将脚本复制到一个空文件中,另存为log_vlc.py

  3. 通过以下命令从终端运行它:

    python3 /path/to/log_vlc.py
    

    以任意方式(cli、gui)在 VLC 中打开任何歌曲,都应创建日志文件并显示已记录的歌曲。

  4. 如果一切正常,请将权限添加到启动应用程序:Dash > 启动应用程序 > 添加。添加命令:

    python3 /path/to/log_vlc.py
    

解释

每两秒一次,脚本:

  • 检查 VLC 是否正在运行根本,如果不是,则不执行任何操作

    pid = get(["pgrep", "vlc"])
    if pid:
        # only do anything at all if vlc runs
    
  • 如果 VLC 正在运行,它会找到其窗口并解析歌曲标题

    wins = get(["wmctrl", "-lp"])
    if wins:
        wins = wins.splitlines()
        try:
            # check if any of the windows belongs to vlc
            # this will not be the case if it is closed in the meantime
            match = [w.split()[0] for w in wins if pid in w][0]
        except IndexError:
            pass
        else:
            # ...if so, retrieve the song name, only log if there is a new song
            song2 = get(["xdotool", "getwindowname", match])
    
  • (仅)如果歌曲标题发生变化,显然播放了一首新歌曲,则歌曲名称会记录到日志文件中,并带有时间戳。

            if all([song2, song2 != song1, song2 != def_name]):
                open(log, "a+").write(
                    time.strftime("%H:%M:%S_%d-%m-%Y")+"\n   "+\
                    song2.replace(def_name, "").rstrip(" - ")+"\n"
                    )
                print(song2)
            song1 = song2
    

答案3

您可以使用 VLC 的详细输出,但这有点复杂。您需要详细级别 2 才能打印任何文件名(无论出于何种原因),但这也会记录大量其他内容,因此您需要过滤输出。

以下是详细程度 2 的示例输出,但仅包含告诉您路径的文件名(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

这是一个示例命令,它将所有播放的文件名打印到控制台(您可以>> file.txt在最后将其重定向到文件中):

vlc --verbose 2 file1.mp3 /path/to/file2.m4a 2>&1 | grep -v "ml.xspf" | grep -oP "\/.*\/\K.*(?=\.[a-zA-Z0-9-_]*\' successfully opened)"

解释

  • vlc … file1.mp3 /path/to/file2.m4a打开 VLC 并播放这两个曲目。您还可以在命令行上将其设置为随机或其他任何设置,有很多选项。
  • --verbose 2激活详细输出。您也可以使用 将其放入文件中--file-logging --log-verbose 2 --log-file file.log,但我的其余命令也可以在命令行中使用,因此这样效果更好。
  • 2>&1 |将错误输出(和标准输出)重定向到下一个命令。
  • grep -v "ml.xspf"过滤掉包含“ ml.xspf”的任何内容,因为出于某种原因,VLC 打开该文件(在我的情况下位于~/.local/share/vlc)的方式与打开常规文件的方式相同。它在 GUI 中的任何地方都看不到,但它在日志中看起来与常规播放的文件相同。
  • | grep -oP只让符合特定 Perl 风格正则表达式的行通过,并且只显示该正则表达式的匹配部分。
  • 现在到了复杂的部分:"\/.*\/\K.*(?=\.[a-zA-Z0-9-_]*\' successfully opened)"是一个正则表达式,它匹配上面日志示例中的最后一行,并且只输出文件名,不带结尾(\.[a-zA-Z0-9-_]*如果要保留,请删除)和路径(如果要保留,请更改\/.*\/file\:\/\/)。
    该正则表达式的解释:
    • \/.*\/匹配两个斜杠 ( /) 和斜杠本身之间的任何内容。例如可以是“ /path/to/”。
    • \K将其之前的所有内容从匹配中排除,这意味着它必须存在才能进行任何匹配,但它不在结果中。
    • .*匹配任何内容(除了换行符等)。
    • (?=…)是一种“前瞻”,其作用本质上与相反\K,它将其后面的所有内容(或在本例中是括号内的所有内容)排除在匹配之外,但它仍然需要存在才能进行匹配。
    • \.匹配句点 ( .)。
    • [a-zA-Z0-9-_]*匹配所有字母、数字-_任意次数,希望能够涵盖所有文件结尾。
    • \' successfully opened与日志示例中的行尾匹配。
  • 我选择了“成功打开”这一行,而不是一些更容易解析的行,因为它似乎确认没有发生任何错误,例如,如果你将整个主文件夹转储到其中,它就不会输出它无法播放的文件,因为它们不是媒体文件。

这个问题的一个特殊困难是许多命令无法使用。例如,basename无法与 StdIn 一起使用,sed仅在输入结束后执行等等。VLC 具有用于从外部控制和监视它的接口,但它们似乎都非常复杂。最简单的接口似乎是 HTTP 接口,但如果没有密码就无法使用,这使得以编程方式使用它变得更加困难。

相关内容