透明的“符号链接+二进制补丁”

透明的“符号链接+二进制补丁”

我有一个项目,从一个长期播放的广播节目中收集和组织 mp3 文件。由于起源和来源各不相同,命名约定和 ID2/3 标签无处不在。

我想创建一组规范化文件。为此,我开始保留目录结构和文件名,并将其符号链接到标准化的目录结构和文件名。这样,我可以很容易地知道我拥有什么和缺少什么,但也知道何时遇到我已经拥有的“野外”节目。

但仍然存在 ID2/3 标签的问题。我也想标准化它们,但如果不更改源 mp3,我就无法做到这一点。

我在想,在理想的情况下,我更新 mp3 文件的副本,针对原始文件创建一个二进制补丁,然后以某种方式创建该补丁的符号链接以及原始文件,以创建一个新的规范化虚拟文件这对文件系统是透明的。

对于这个问题有类似的解决方案吗?

答案1

我查看了一些熔断文件系统,最简单的工作方式是连接文件系统作者:彼得·施莱尔。如果不出意外的话,这将是一个很好的起点,因为 C 代码实现很小并且是独立的。

基本上,对于任何文件A您想要“符号链接”到某个任意源目录S你创建一个文件其中仅包含您想要的 id3 标签信息(版本 2),然后是一个魔术文件C文件名在某处包含字符“-concat-”。这个文件C按顺序包含名称A

当您运行 concatfs 程序时,您指定源目录S和第二个任意安装点目录中号。在中号您将看到与中相同的所有文件S,但是当你读取文件时C你会得到一个串联的A,即您的新标签后跟真实的 mp3 数据。显然,只有魔术文件真正需要在S,因为您可以在魔术文件中使用绝对或相对路径。

这并不完美,因为如果你的A文件包含 id3v2 标签(在文件的开头),它们将被添加到您的文件中文件。此外,id3v1 标签(位于文件末尾)仍然存在。然而,通过一些 C 编码,应该可以抑制A。此外,更改魔术字符串“-concat-”也很简单。

以下是我用来测试 concatfs 的命令。安装该fuse-devel包以便您可以编译代码。其余的不需要你成为root。 下载并解压源代码并编译它们:

cd concatfs
gcc -Wall src/concatfs.c $(pkg-config fuse --cflags --libs) -o concatfs

创建 2 个目录,启动命令,然后复制一些要播放的 mp3 文件,删除其中的所有标签:

mkdir -p ~/myfuse/src ~/myfuse/mnt
./concatfs ~/myfuse/src ~/myfuse/mnt  # runs in background
cd ~/myfuse/src
cp ....sometestfile.mp3 try.mp3
id3v2 --delete-v1 try.mp3
id3v2 --delete-v2 try.mp3
id3info try.mp3

创建虚拟文件,即 magic 文件,并向虚拟文件添加一些 id3v2 标签:

echo -e 'dummy.mp3\ntry.mp3' > try.mp3-concat-.mp3
> dummy.mp3
id3v2 -2 -c 'my description:my comment' -a  'my artist' -A 'my album' -y '2010' -T 1/2  dummy.mp3
hexdump -C dummy.mp3 
ls -l

在第二个目录中查找相同的文件,但魔术文件的大小和内容是两个文件的串联:

ls ../mnt/ -l
cat ../mnt/try.mp3-concat-.mp3 | wc -c
id3info ../mnt/try.mp3-concat-.mp3
mediainfo ../mnt/try.mp3-concat-.mp3

当您终止程序时,您可能需要清理安装:

fusermount -u ~/myfuse

答案2

以下是我的案例,说明为什么数据库可能是一个很好的解决方案:

  • id_tag由于 SQL 查询语言非常灵活,因此它允许您通过声明性寻址系统将新旧文件名关联起来。
  • 它可以扩展以提供额外的用途 - 作为示例,我在下面的脚本中添加了一个类别标签。
  • 如果使用 SQLite,它可以从命令行使用,它会生成可以通过管道、重定向等方式输出的 STDOUT。

我的示例基于这样的想法:每个节目都是由唯一记录标识的,在单个表中(比多个表更简单)有关该广播节目的所有信息都将包含在该表中的记录中,使用sqlite

安装sqlite

apt-get install sqlite3

或使用yum, pacman, 从源代码构建或其他

cd 进入数据库目录并创建脚本

文件:music_db.sh

#!/bin/bash

if [ -f music_db ]
then
    rm -v music_db
fi

sqlite3 music_db << 'EOF'
    create table radio_shows(
        original_filename text,
        new_filename      text,
        id_tag            text,
        category_tags     text
    );
EOF

sqlite3 music_db << 'EOF'
    insert into radio_shows 
    (original_filename, new_filename, id_tag, category_tags) values
    ('first_show-001', 'first_show-001--new_naming_scheme', 'id_tag aaa', 'favourite_shows'),
    ('first_show-002', 'first_show-002--new_naming_scheme', 'id_tag aab', 'favourite_shows'),
    ('first_show-003', 'first_show-003--new_naming_scheme', 'id_tag aac', 'crap_shows'),
    ('first_show-004', 'first_show-004--new_naming_scheme', 'id_tag aad', 'favourite_shows');
EOF

然后从命令行使用:例如添加一个新节目

% sqlite3 music_db <<EOF
insert into radio_shows                  
(new_filename, id_tag, category_tags) values 
('a_new_show', 'xyz_123', 'good_show'); 
EOF

检索节目(稍后)并打印到 STDOUT

% sqlite3 music_db <<EOF
select new_filename, id_tag
from radio_shows
where category_tags = "good_show";
EOF

结果

a_new_show|xyz_123

相关内容