/usr/bin/abcde-musicbrainz-tool is in abcde 2.5.4-1.
This file is owned by root:root, with mode 0o755.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 | #!/usr/bin/perl
# Copyright (c) 2012 Steve McIntyre <93sam@debian.org>
# This code is hereby licensed for public consumption under either the
# GNU GPL v2 or greater, or Larry Wall's Artistic license - your choice.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# abcde-musicbrainz-tool
#
# Helper script for abcde to work with the MusicBrainz WS API (v2)
use strict;
use encoding "utf8";
use POSIX qw(ceil);
use Digest::SHA;
use MusicBrainz::DiscID;
use WebService::MusicBrainz::Release;
use WebService::MusicBrainz::Artist;
use WebService::MusicBrainz::Response::Track;
use WebService::MusicBrainz::Response::TrackList;
use Getopt::Long;
my $FRAMES_PER_SEC = 75;
my ($device, $command, $discid, @discinfo, $workdir);
Getopt::Long::Configure ('no_ignore_case');
Getopt::Long::Configure ('no_auto_abbrev');
GetOptions ("device=s" => \$device,
"command=s" => \$command,
"discid=s" => \$discid,
"discinfo=i{5,}" => \@discinfo,
"workdir=s" => \$workdir);
if (!defined($device)) {
$device = "/dev/cdrom";
}
if (!defined($command)) {
$command = "id";
}
if (!defined($workdir)) {
$workdir = "/tmp";
}
sub calc_sha1($) {
my $filename = shift;
my $s = Digest::SHA->new(1);
$s->addfile($filename);
return $s->hexdigest;
}
if ($command =~ m/^id/) {
my $disc = new MusicBrainz::DiscID($device);
# read the disc in the default disc drive */
if ( $disc->read() == 0 ) {
printf STDERR "Error: %s\n", $disc->error_msg();
exit(1);
}
printf("%s ", $disc->id());
printf("%d ", $disc->last_track_num() + 1 - $disc->first_track_num());
for ( my $i = $disc->first_track_num;
$i <= $disc->last_track_num; $i++ ) {
printf("%d ", $disc->track_offset($i));
}
printf("%d\n", $disc->sectors() / $FRAMES_PER_SEC);
undef $disc;
} elsif ($command =~ m/data/) {
my $ws = WebService::MusicBrainz::Release->new();
my $response = $ws->search({ DISCID => $discid });
my @releases = $response->release_list();
my $releasenum = 0;
my @sums;
foreach my $release (@releases) {
my $a_artist = $release->artist()->name();
my $va = 0;
if ($a_artist =~ /Various Artists/) {
$va = 1;
}
$releasenum++;
open (OUT, "> $workdir/cddbread.$releasenum");
binmode OUT, ":utf8";
print OUT "# xmcd style database file\n";
print OUT "#\n";
print OUT "# Track frame offsets:\n";
# Assume standard pregap
my $total_len = 2000;
my @tracks = @{$release->track_list()->tracks()};
for (my $i = 0; $i < scalar(@tracks); $i++) {
printf OUT "# %d\n", ceil($total_len * $FRAMES_PER_SEC / 1000.0);
$total_len += $tracks[$i]->duration();
}
print OUT "#\n";
printf OUT "# Disc length: %d seconds\n", $total_len / 1000.0;
print OUT "#\n";
print OUT "# Submitted via: XXXXXX\n";
print OUT "#\n";
print OUT "#blues,classical,country,data,folk,jazz,newage,reggae,rock,soundtrack,misc\n";
print OUT "#CATEGORY=none\n";
print OUT "DISCID=" . $discid . "\n";
print OUT "DTITLE=" . $a_artist. " / " . $release->title() . "\n";
print OUT "DYEAR=\n";
print OUT "DGENRE=\n";
my @tracks = @{$release->track_list()->tracks()};
for (my $i = 0; $i < scalar(@tracks); $i++) {
my $track = $tracks[$i];
my $t_name = $track->title;
if ($va) {
my $t_artist = $track->artist->name;
printf OUT "TTITLE%d=%s / %s\n", $i, $t_artist, $t_name;
} else {
printf OUT "TTITLE%d=%s\n", $i, $t_name;
}
}
print OUT "EXTD=\n";
for (my $i = 0; $i < scalar(@tracks); $i++) {
printf OUT "EXTT%d=\n", $i;
}
print OUT "PLAYORDER=\n";
print OUT ".\n";
close OUT;
# Check to see that this entry is unique; generate a checksum
# and compare to any previous checksums
my $checksum = calc_sha1("$workdir/cddbread.$releasenum");
foreach my $sum (@sums) {
if ($checksum eq $sum) {
unlink("$workdir/cddbread.$releasenum");
$releasenum--;
last;
}
}
push (@sums, $checksum);
}
} elsif ($command =~ m/calcid/) {
# Calculate MusicBrainz ID from disc offsets; see
# http://musicbrainz.org/doc/DiscIDCalculation
my ($first, $last, $leadin, $leadout, @offsets) = @discinfo;
my $s = Digest::SHA->new(1);
$s->add(sprintf "%02X", int($first));
$s->add(sprintf "%02X", int($last));
my @a;
for (my $i = 0; $i < 100; $i++) {
$a[$i] = 0;
}
my $i = 0;
foreach my $o ($leadout, @offsets) {
$a[$i++] = int($o) + int($leadin);
}
for (my $i = 0; $i < 100; $i++) {
$s->add(sprintf "%08X", $a[$i]);
}
my $id = $s->b64digest;
# CPAN Digest modules do not pad their Base64 output, so we have to do it.
while (length($id) % 4) {
$id .= '=';
}
$id =~ tr#+#.#;
$id =~ tr#/#_#;
$id =~ tr#=#-#;
print $id;
}
|