我正在尝试编写一个读取我的MP3文件名的Python脚本,当它找到缺少的Artist标签时,它将从文件名的第一部分开始。我的大多数MP3标题为#34;艺术家 - 标题.mp3"。
但是没有一个ID3标签阅读器在Python中运行良好。 ID3不会读取1.1之后的任何标签,自2002年以来它还没有开发出来。当文件缺少标签时,Mutagen会引发异常。 Eye3D需要安装二进制文件以使库工作,与pylibid3同上。
我使用的是错误的语言吗?我听说Perl有一些很棒的ID3标签库。我是一个新手所以切换语言(因为我已经读过Perl的书已经有一段时间了)意味着从头开始。但如果Python是错误的语言,我愿意这样做。
有什么想法吗?
答案 0 :(得分:6)
使用mutagen处理异常非常容易:
from mutagen.id3 import ID3, TPE1, ID3NoHeaderError
try:
audio = ID3(filename)
except ID3NoHeaderError:
audio = ID3()
audio.add(TPE1(encoding=3, text=u'Artist'))
audio.save(filename)
答案 1 :(得分:2)
这是一个执行您想要的Perl脚本。我经常用这个。它甚至可以在制作之前预览这些变化。
您确实需要安装一些Perl模块(MP3 :: Info和MP4 :: Info),尽管您可以从代码中删除MP4行并跳过该模块。
#!/usr/bin/perl
use strict;
use warnings;
use Cwd;
use File::Copy;
use File::Basename;
# Load MP3/MP4 modules and set them up to use UTF-8 characters
# (Unicode-like support, to see accents, etc.).
use MP3::Info qw(:all);
use_mp3_utf8(1);
use MP4::Info qw(:all);
use_mp4_utf8(1);
my @ARGS;
################################################################################
# Subroutine: RemoveIllegalFilenameCharacters
# Inputs: $filename
# Outputs: $filename
################################################################################
sub RemoveIllegalFilenameCharacters {
my $filename = shift;
if ($filename =~ m/\\/) { $filename =~ s/\\//g }
if ($filename =~ m/\//) { $filename =~ s/ \/ / - /g }
if ($filename =~ m/\//) { $filename =~ s/\///g }
if ($filename =~ m/:/) { $filename =~ s/://g }
if ($filename =~ m/\*/) { $filename =~ s/\*//g }
if ($filename =~ m/\?/) { $filename =~ s/\?//g }
if ($filename =~ m/"/) { $filename =~ s/"//g }
if ($filename =~ m/</) { $filename =~ s/<//g }
if ($filename =~ m/>/) { $filename =~ s/>//g }
if ($filename =~ m/\|/) { $filename =~ s/\|//g }
return $filename;
}
################################################################################
# Subroutine: Rename
# Inputs: $test (indicates test mode)
# Outputs: number of files to be changed (in test mode)
################################################################################
sub Rename {
my $test = shift;
my $destDir = ""; # hard-coded permanent destination, if desired
my @tests;
foreach my $file (@ARGS) {
# Get rid of the Mac OS resource fork files.
if ($file =~ m/^\._/) {
unlink "$file";
next;
}
if (! -f $file) {
warn "'$file' does not exist!\n";
}
else {
# If $destDir wasn't set above, then that means it should be
# set to the original dir of each file.
if (!($destDir)) {
$destDir = dirname($file);
}
my $extension = $file;
$extension =~ s/.*\.//;
my $tag;
if ($extension =~ m/^mp3$/i) {
($tag = get_mp3tag($file)) || warn "'$file' does not contain ID3 tags (it may not even be an MP3 file!)\n";
}
else {
# If it's not MP3, try MP4
($tag = get_mp4tag($file)) || warn "'$file' does not contain ID3 tags (it may not even be an AAC/M4A/M4P file!)\n";
}
if (!($tag)) {
# No $tag was returned. Go to the next $file.
next;
}
# DEBUG! Show all the tag names. Could be modifed to show all the tag values too.
if (0) {
print join("\n", keys %{$tag}) . "\n";
}
# Set the rename format depending on if we're under the $DOWNLOAD_DIR or not.
my $newFile = $$tag{"ARTIST"} . " - " . $$tag{"TITLE"} . ".$extension";
if (($$tag{"ARTIST"} eq "") || ($$tag{"TITLE"} eq "")) { warn "\n*** WARNING! This track is missing some info:\n\tOriginal Name: $file\n\tNew Name: $newFile\n\n" }
$newFile = RemoveIllegalFilenameCharacters($newFile);
# If current filename ($file) already matches the new filename ($newFile),
# don't bother continuing (filename is already in the correct format).
if ($file eq $newFile) {
# If we're not choosing to move all files,
# and if the filename is already in the correct format,
# go to the next $file.
next;
}
if ($destDir ne ".") { $newFile = $destDir . "/" . $newFile }
if (!($test) && -f $newFile) {
die "Unable to move '$file' to '$newFile',\nsince there's already a file named '$newFile'!\nStopped";
}
if ($test) {
push @tests, $newFile;
} else {
print "Moving '$file' to '$newFile'\n";
move($file, $newFile) || die "Unable to move file!\n";
}
} # End of if-then-else checking if file exists
} # End of FOR loop looping through files in @ARGS.
if ($test && scalar(@tests)) {
print "Test run - new filenames: \n ";
print join("\n ", sort(@tests));
}
return scalar(@tests);
}
################################################################################
# MAIN ROUTINE
if (scalar(@ARGV) == 0) {
# If no args, use every music file in current directory.
opendir(DIR, ".");
@ARGS = sort(grep(/\.mp3$|\.aac$|\.m4a$|\.m4p$/i, readdir(DIR)));
closedir(DIR);
if (scalar(@ARGS) == 0) {
print "USAGE: " . basename($0) . " <music-files>\n\n";
print "If no filenames are specified, any music files (MP3/AAC/M4A/M4P) in the current directory will be used.\n";
exit 1;
}
}
else { @ARGS = @ARGV }
if (Rename(1)) {
print "\n\nDo the test results look good?\n";
print " n - No they don't. Do not rename the files!\n";
print "[y] - Yes they do. Rename the files and leave them in their original folder(s).\n";
print " ";
my $choice = <STDIN>;
chomp $choice;
# Only do the move if we're in the $DOWNLOAD_DIR area.
# This allows us to use the default (null) response to process renames in a non-download dir.
if (("$choice" eq "") || ("$choice" eq "y")) {
Rename(0);
}
}
else {
print "No actions needed.\n";
}