pastebin - collaborative debugging tool
kpaste.net RSS


replaygain
Posted by Anonymous on Sun 16th Sep 2012 16:40
raw | new post
view followups (newest first): replaygain by Anonymous

  1. #!/usr/bin/perl
  2.  
  3. use 5.14.0;
  4. use strict;
  5. use warnings;
  6. #use File::Find qw(finddepth);
  7. use File::Copy qw(move);
  8. use File::Basename qw(basename dirname);
  9. use File::Path qw(make_path);
  10.  
  11. #my $library = "/home/sir/Music/Songbird Music";
  12. my $library = "/home/sir/Music/Songbird Music";
  13. my (%t, %files, @files, @dirs);
  14. my $flac_version = '1.2.1';
  15.  
  16. getdirs($library);
  17.  
  18. foreach my $dn (sort(@dirs)) {
  19.         #my $ino = (stat($fn))[1];
  20.         #say "$dn has $ino";
  21.         undef %files;
  22.         undef @files;
  23.         getfiles($dn);
  24.         my $fc = @files;
  25.         if ($fc > 0) {
  26.                 replaygain($dn);
  27.                 for (my $n = 0; $n < $fc; $n++) {
  28.                         my $fn = $files[$n];
  29.                         undef(%t);
  30.                         foreach my $tag (keys($files{$fn})) {
  31.                                 $t{$tag} = $files{$fn}{$tag}->[0];
  32.                                 #say "$tag = $t{$tag}";
  33.                         }
  34.                         vendor($fn);
  35.                         rmtag($fn, 'rating');
  36.                         albumartist($fn, $fc);
  37.                         track($fn);
  38.                         spaces($fn);
  39.                         totaltracks($fn, $fc);
  40.         #               empty($fn);
  41.                         duplicate($fn);
  42.                         discnum($fn, $n, $fc);
  43.                 }
  44.         }
  45. }
  46. # Make this subroutine and the whole script so that each file name is stored in a hash and that each member contains an anonymous hash with the tags (the alltags hash).
  47. # This means it won't have to look up the tags again for the albumartist subroutine.
  48.  
  49. sub gettags {
  50.         my $fn = quotemeta(shift);
  51.         my (%alltags, @mflac);
  52.         open(OUTPUT, '-|', qq{metaflac --no-utf8-convert --show-vendor-tag --export-tags-to=- $fn}) || die "can't run metaflac: $!";
  53.         chomp(@mflac = (<OUTPUT>));
  54.         foreach (@mflac) {
  55.                 my (@tag, $tagname);
  56.                 if (/^reference/) {
  57.                         @tag = split(' ');
  58.                         $tagname = 'vendor_ref';
  59.                         $tag[1] = $tag[2];
  60.                 } else {
  61.                         @tag = split('=');
  62.                         $tagname = lc($tag[0]) or say $fn;
  63.                 }
  64.  
  65.                 if ($tag[1]) {
  66.                         push(@{$alltags{$tagname}}, $tag[1]); }
  67.                         else { push(@{$alltags{$tagname}}, 'null'); }
  68.         }
  69.         close(OUTPUT) || die "couldn't close metaflac: $!";
  70.         return %alltags;
  71. }
  72.  
  73. sub vendor {
  74.         my $fn = shift;
  75.  
  76.         if ($t{vendor_ref} ne $flac_version) {
  77.                 my $newfn = $fn . '.' . int(rand(10000));
  78.                 say "$fn: old encoder ($t{vendor_ref}), re-encoding...";
  79.                 system('flac', '--silent', '-8', $fn, '--output-name=' . $newfn);
  80.                 if ($? == 0) {
  81.                         move($newfn, $fn) or die "Couldn't rename '$newfn': $!";
  82.                 } elsif ($? == 2) {
  83.                         say "Interrupted by user!";
  84.                         unlink($newfn) if (-f $newfn);
  85.                         exit;
  86.                 }
  87.         }
  88. }
  89.  
  90. sub getdirs {
  91.  
  92.         my $dn = shift;
  93.  
  94.         open(FIND, '-|', qq(find -L "$dn" -name "*" -type d))
  95.         or die "Can't run 'find': $!";
  96.         chomp(@dirs = (<FIND>));
  97.         close(FIND) or die "Can't close 'find': $!";
  98. }
  99.  
  100. sub getfiles {
  101.         my $dn = shift;
  102.         opendir(my $dh, $dn) or die "Can't open directory '$dn': $!";
  103.         foreach (readdir $dh) {
  104.                 my $fn = "$dn/$_";
  105.                 if (/.flac$/ && -f $fn) {
  106.                         push(@files, $fn);
  107.                         $files{$fn} = { gettags($fn) };
  108.                 }
  109.         }
  110.         closedir $dh or die "Can't close directory '$dn': $!";
  111. }
  112.  
  113. sub replaygain {
  114.         my $dn = shift;
  115.         my %replaygain;
  116.  
  117.         #foreach ('REFERENCE_LOUDNESS', 'TRACK_GAIN', 'TRACK_PEAK', 'ALBUM_GAIN', 'ALBUM_PEAK') {
  118.         #       my $tag = 'REPLAYGAIN_' . $_;
  119.         #       system('metaflac', '--remove-tag=' . $tag, keys(%files));
  120.         #}
  121.  
  122.         foreach my $fn (sort(keys %files)) {
  123.                         if ($files{$fn}{replaygain_album_gain}) {
  124.                                 $replaygain{$files{$fn}{replaygain_album_gain}->[0]}++;
  125.                         }
  126.         }
  127.  
  128.         if (keys(%replaygain) != 1) {
  129.                 print "$dn: adding ReplayGain...";
  130.                 system('metaflac', '--add-replay-gain', keys(%files));
  131.                 say " done";
  132.         }
  133. }
  134.  
  135. sub albumartist {
  136.         my $fn = shift;
  137.         my $tracks = shift;
  138.  
  139.         if (! $t{albumartist} || $t{albumartist} eq 'null') {
  140.                 my %artist;
  141.                 my $max;
  142.                 if ($tracks == 1) { $max = $tracks } else { $max = $tracks / 2 }
  143.                 foreach my $fn (sort(keys(%files))) {
  144.                         $artist{$t{artist}} = 1;
  145.                 }
  146.                 if (keys(%artist) > $max) {
  147.                         $t{albumartist} = 'Various Artists';
  148.                 } else { $t{albumartist} = $t{artist} };
  149.  
  150.                 say "$fn: adding albumartist tag";
  151.                 system('metaflac', '--remove-tag=ALBUMARTIST', '--set-tag=ALBUMARTIST=' . $t{albumartist}, $fn);
  152.         }
  153. }
  154.  
  155. sub empty {
  156.         my $fn = shift;
  157.         foreach my $tag (sort(keys(%{$files{$fn}}))) {
  158.                 foreach (@{$files{$fn}{$tag}}) {
  159.                         if ($_ eq 'null') {
  160.                                 say "$fn: WARNING: empty $tag tag";
  161.                         }
  162.                 }
  163.         }
  164. }
  165.  
  166. sub duplicate {
  167.                 my $fn = shift;
  168.                 my %exists;
  169.                 foreach my $field (sort(keys(%{$files{$fn}}))) {
  170.                         foreach my $tag (@{$files{$fn}{$field}}) {
  171.                                 if ($exists{$field} && $exists{$field} eq $tag) {
  172.                                         say "$fn: removing duplicate $field tag";
  173.                                         system('metaflac', '--remove-tag=' . $field, '--set-tag=' . $field . '=' . $tag, $fn);
  174.                                 } else {
  175.                                         $exists{$field} = $tag;
  176.                                 }
  177.                         }
  178.                 }
  179. }
  180.  
  181. sub track {
  182.         my $fn = shift;
  183.         if (!$t{tracknumber}) {
  184.                 say "$fn: doesn't have any tracknumber tag"
  185.         }
  186.         elsif ($t{tracknumber} =~ m/^0/ && $t{tracknumber} != 0) {
  187.                 say "$fn: fixing tracknumber tag";
  188.                 $t{tracknumber} =~ s/^0+//;
  189.                 system('metaflac', '--remove-tag=TRACKNUMBER', '--set-tag=TRACKNUMBER=' . $t{tracknumber}, $fn);
  190.         }
  191. }
  192.  
  193. sub spaces {
  194.         my $fn = shift;
  195.         my %temp;
  196.  
  197.         foreach my $tag (sort(keys(%t))) {
  198.                 $temp{$tag} = $t{$tag};
  199.                 $temp{$tag} =~ s/(^\s*)|(\s*$)//g;
  200.         }
  201.  
  202.         foreach my $tag (sort(keys(%t))) {
  203.                 if ($temp{$tag} ne $t{$tag} && "$temp{$tag}") {
  204.                         say "$fn: removing leading and trailing whitespaces from tags";
  205.                         #say $temp{$tag};
  206.                         my $ufield = uc($tag);
  207.                         system('metaflac', '--remove-tag=' . $ufield, '--set-tag=' . $ufield . '=' . $temp{$tag}, $fn);
  208.                 }
  209.         }
  210. }
  211.  
  212. sub totaltracks {
  213.         my $fn = shift;
  214.         my $tracks = shift;
  215.         if (
  216.         !$t{totaltracks} &&
  217.         !$t{tracktotal}
  218.         ) {
  219.                 say "$fn: adding totaltracks tag";
  220.                 system('metaflac', '--set-tag=TOTALTRACKS=' . $tracks, $fn);
  221.         }
  222.         elsif (
  223.         $t{tracktotal} &&
  224.         !$t{totaltracks}
  225.         ) {
  226.                 say "$fn: replacing tracktotal tag with totaltracks";
  227.                 system('metaflac', '--remove-tag=TRACKTOTAL', '--set-tag=TOTALTRACKS=' . $t{tracktotal}, $fn);
  228.         }      
  229. }
  230.  
  231. sub discnum {
  232.         my $fn = shift;
  233.         my $n = shift;
  234.         my $fc = shift;
  235.  
  236.         my $dn = dirname($fn);
  237.         my ($match, $newfn);
  238.         my $regex = '[[:punct:]]?(cd|disc) ?[0-9]+[[:punct:]]?$';
  239.  
  240.         if ($t{album} =~ /$regex/i) {
  241.                 $t{album} =~ s/.?(${^MATCH}).?//;
  242.                 system('metaflac', '--remove-tag=ALBUM', '--set-tag=ALBUM=' . $t{album}, $fn);
  243.         }
  244.  
  245.         if (!$t{discnumber}) {
  246.                 if (basename($fn) =~ /^[0-9]+-/) {
  247.                         $match = ${^MATCH};
  248.                         ${^MATCH} =~ /([0-9]+)/;
  249.                         $t{discnumber} = eval { $1 =~ s/^0+//; };
  250.                 }
  251.                 elsif ($dn =~ /$regex/i) {
  252.                         $match = ${^MATCH};
  253.                         ${^MATCH} =~ /([0-9]+)/;
  254.                         $t{discnumber} = eval { $1 =~ s/^0+//; };
  255.  
  256.                         $dn =~ s/ .?($match).?//;
  257.  
  258.                         make_path($dn) if (! -d $dn);
  259.                         $newfn = "${dn}/" . $t{discnumber} . '-' . basename($fn);
  260.                         unless (-f $newfn) {
  261.                                 move($fn, $newfn) or die "Couldn't rename '$fn': $!";
  262.                         }
  263.                 }
  264.                 else {
  265.                         $t{discnumber} = 1;
  266.                         $newfn = "${dn}/" . $t{discnumber} . '-' . basename($fn);
  267.                         unless (-f $newfn) {
  268.                                 move($fn, $newfn) or die "Couldn't rename '$fn': $!";
  269.                         }
  270.                 }
  271.  
  272.                 if (!$newfn) { $newfn = $fn }
  273.                 say "$newfn: adding discnumber tag";
  274.                 system('metaflac', '--set-tag=DISCNUMBER=' . $t{discnumber}, $newfn);
  275.         }
  276. }
  277.  
  278. sub rmtag {
  279.         my $fn = shift;
  280.         foreach my $tag (@_) {
  281.                 if ($t{$tag}) {
  282.                         say "$fn: removing $tag tag";
  283.                         system('metaflac', '--remove-tag=' . $tag, $fn);
  284.                 }
  285.         }
  286. }

Submit a correction or amendment below (click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.

Syntax highlighting:

To highlight particular lines, prefix each line with {%HIGHLIGHT}




All content is user-submitted.
The administrators of this site (kpaste.net) are not responsible for their content.
Abuse reports should be emailed to us at