pastebin - collaborative debugging tool
kpaste.net RSS


replaygain, system() without using the shell
Posted by Anonymous on Mon 24th Sep 2012 00:52
raw | new post
view followups (newest first): replaygain, system() without using the shell by Anonymous

  1. #!/usr/bin/perl
  2.  
  3. use 5.14.0;
  4. use strict;
  5. use warnings;
  6. use File::Copy qw(move);
  7. use File::Basename qw(basename dirname);
  8. use File::Path qw(make_path);
  9.  
  10. #my $library = "/home/sir/Music/Songbird Music";
  11. my $library = "/home/sir/Music/Songbird Music";
  12. my (%t, %files, @files, @dirs, @wrong_case);
  13. my $flac_version = '1.2.1';
  14.  
  15. getdirs($library);
  16.  
  17. foreach my $dn (sort(@dirs)) {
  18.         #my $ino = (stat($fn))[1];
  19.         #say "$dn has $ino";
  20.         undef %files;
  21.         undef @files;
  22.         getfiles($dn);
  23.         my $fc = @files;
  24.         if ($fc > 0) {
  25.                 replaygain($dn);
  26.                 for (my $n = 0; $n < $fc; $n++) {
  27.                         my $fn = $files[$n];
  28.                         undef(%t);
  29.                         foreach my $tag (keys($files{$fn})) {
  30.                                 $t{$tag} = $files{$fn}{$tag}->[0];
  31.                                 #say "$tag = $t{$tag}";
  32.                         }
  33.                         vendor($fn);
  34.                         rmtag($fn, 'rating');
  35.                         albumartist($fn, $fc);
  36.                         track($fn);
  37.                         spaces($fn);
  38.                         totaltracks($fn, $fc);
  39.         #               empty($fn);
  40.                         duplicate($fn);
  41.                         discnum($fn, $n, $fc);
  42.                 }
  43.         }
  44. }
  45. # 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).
  46. # This means it won't have to look up the tags again for the albumartist subroutine.
  47.  
  48. sub gettags {
  49.         my $fn = shift;
  50.         my (%alltags, @mflac);
  51.         open(OUTPUT, '-|', 'metaflac', '--no-utf8-convert', '--show-vendor-tag', '--export-tags-to=-', $fn) || die "can't run metaflac: $!";
  52.         chomp(@mflac = (<OUTPUT>));
  53.         foreach (@mflac) {
  54.                 my (@tag, $tagname);
  55.                 if (/^reference/) {
  56.                         @tag = split(' ');
  57.                         $tagname = 'vendor_ref';
  58.                         $tag[1] = $tag[2];
  59.                 } else {
  60.                         @tag = split('=');
  61.                         $tagname = lc($tag[0]) or next;
  62.                 }
  63.  
  64.                 if ($tag[1]) {
  65.                         push(@{$alltags{$tagname}}, $tag[1]); }
  66.                         else { push(@{$alltags{$tagname}}, 'null'); }
  67.         }
  68.         close(OUTPUT) || die "couldn't close metaflac: $!";
  69.         return %alltags;
  70. }
  71.  
  72. sub vendor {
  73.         my $fn = shift;
  74.  
  75.         if ($t{vendor_ref} ne $flac_version) {
  76.                 my $newfn = $fn . '.' . int(rand(10000));
  77.                 say "$fn: old encoder ($t{vendor_ref}), re-encoding...";
  78.                 system('flac', '--silent', '-8', $fn, '--output-name=' . $newfn);
  79.                 if ($? == 0) {
  80.                         move($newfn, $fn) or die "Couldn't rename '$newfn': $!";
  81.                 } elsif ($? == 2) {
  82.                         say "Interrupted by user!";
  83.                         unlink($newfn) if (-f $newfn);
  84.                         exit;
  85.                 }
  86.         }
  87. }
  88.  
  89. sub getdirs {
  90.  
  91.         my $dn = shift;
  92.  
  93.         open(FIND, '-|', 'find', $dn, '-name', '*', '-type', 'd')
  94.         or die "Can't run 'find': $!";
  95.         chomp(@dirs = (<FIND>));
  96.         close(FIND) or die "Can't close 'find': $!";
  97. }
  98.  
  99. sub getfiles {
  100.         my $dn = shift;
  101.         my $fn;
  102.         opendir(my $dh, $dn) or die "Can't open directory '$dn': $!";
  103.         foreach (readdir $dh) {
  104.                 $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 $field (@_) {
  281.                 if ($t{$field}) {
  282.                         say "$fn: removing $field tag";
  283.                         system('metaflac', "--remove-tag=${field}", $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