Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?
 
PerlMonks  

Comment on

( #3333=superdoc: print w/ replies, xml ) Need Help??

I posted an earlier version of this script to my blog and it worked fine but there was one little problem with it. When we processed the files, namely running eye3D, we did so synchronously. Essentially, the file notification came in from the Linux kernel and we processed the file at that time. This may be an issue of overflowing the inotify queue within the Linux kernel if there are a lot of files to process.

A better solution would be to add the file to an internal queue and process the files in a sub process using POE::Wheel::Run. Of course we will limit the number of sub processes :)

In order to use this, we would start the script and then copy the mp3s into the watched directory in whatever fashion we wished.

#!/usr/bin/perl use strict; use warnings; use File::Basename; use File::Find (); use Getopt::Std; use Linux::Inotify2; use POE qw( Kernel Session Wheel::Run ); $|++; ####################################### ####################################### our @found_dirs; our $max_concurrent_tasks; sub watch_add_dir { my ($heap_ref, $session, $dir_name) = @_; ############## # Watch this directory with a call back # to the watch_hdlr() subroutine via # a message to the POE system ############## $heap_ref->{inotify}->watch($dir_name, IN_CREATE|IN_CLOSE_WRITE, $ses +sion->postback("watch_hdlr")); print " Watching directory $dir_name\n"; } sub watch_hdlr { my ($kernel, $heap, $session, $event) = ( $_[KERNEL], $_[HEAP], $_[SE +SSION], $_[ARG1][0] ); my $name = $event->fullname; my $short_name = $event->name; ############## # We can receive many many notifications # for a file. If we’ve already processed # the file, do nothing. ############## unless ($heap->{inotify}{files}{$name}) { ############## # If a new directory is added, we need # to watch that directory too. ############## if ($event->IN_CREATE && -d $name) { print "New directory: $name\n"; watch_add_dir($heap, $session, $name); } elsif ($event->IN_CLOSE_WRITE) { ############## # When a file descriptor that was opened for # ’writing’ is closed, then process that # file it was being written to. We’re # assuming that the file is complete at this # point as the operation will be a copy into # the watched directory ############## my $ext = ( fileparse($name, ‘\..*’) )[2]; if (lc($ext) eq ‘.mp3&#8242;) { ############## # Add the file to the file process queue ############## push @{ $heap->{task}{task_files} }, $name; ############## # Mark that we have processed the file. If # we don’t we will end up processing the file # in an infinite loop because we are modifying # the files. ############## $heap->{inotify}{files}{$name} = 1; ############## # Yield to "task_next_file" through so # that we can process files in the queue. ############## $kernel->yield("task_next_file"); } $heap->{inotify}{files}{$name} = 1; } } ############## # While possible, it is highly unlikely that we will # overflow the notification buffers within the Linux # kernel. If so, we should report that. ############## print "events for $name have been lost\n" if $event->IN_Q_OVERFLOW; } sub task_next_file { my ($kernel, $heap) = @_[ KERNEL, HEAP ]; ############## # Process the files in the queue up # to the $max_concurrent_tasks at # once. Any extras will be processed # when a file (task) completes. ############## while ( keys( %{ $heap->{task} } ) < $max_concurrent_tasks ) { my $next_task_file = shift @{ $heap->{task}{task_files} }; ############## # If the $next_task_file is empty, then we can safely # ignore it. ############## last unless defined $next_task_file; ############## # Use POE::Wheel::Run to fire off the # file processing using a sub process # to the process_file() subroutine ############## my $task = POE::Wheel::Run->new ( Program => sub { process_file($next_task_file) }, StdoutEvent => "task_output", CloseEvent => "task_done", ); ############## # Update the session with the task # information and the kernel with # the SIG_CHILD handler. These are # necessary for the task to execute. ############## $heap->{task}->{ $task->ID } = $task; $kernel->sig_child( $task->PID, "sig_child"); } } sub process_file { my $file = shift; print " Processed \"$file\"\n"; ############## # Use the eyeD3 package to convert # the mp3 id3v2/3/4 to id3v1. If # eyeD3 fails, we don’t really care. :) ############## my $cmd_output = `eyeD3 –to-v1.1 "$file"`; $cmd_output = `eyeD3 –remove-v2 "$file"`; } sub find_wanted { my $object = $File::Find::name; if (-d $object) { push @found_dirs, $object; } } ####################################### ####################################### ####################################### my %arg_options; my $watch_dir; getopts(‘d:t:’, \%arg_options); if ($arg_options{d} && -d $arg_options{d}) { $watch_dir = $arg_options{d}; if ($arg_options{t} && $arg_options{t} =~ /^\d+/) { $max_concurrent_tasks = $arg_options{t}; } else { $max_concurrent_tasks = 2; } ############## # We need to watch all existing sub directories # so we will find them and add them to the # @found_dirs array to be added to the watched # directories when we create the Inotify object ############## File::Find::find({wanted => \&find_wanted}, $watch_dir); POE::Session->create ( inline_states => { _start => sub { my $inotify_FH; ############## # alias this particular POE session to # ’notify’ so we can easily reference # it later if needed ############## $_[KERNEL]->alias_set(‘notify’); ############## # Create the Linux::INotify object ############## $_[HEAP]{inotify} = new Linux::Inotify2 or die "Unable to create new inotify object: $!"; ############## # Add the preexisting directories to # be watched from the @found_dirs array ############## foreach my $dir (@found_dirs) { watch_add_dir($_[HEAP], $_[SESSION], $dir); } ############## # We need to create a hash in the "notify" # POE session so we can determine if we’ve # processed a file already ############## $_[HEAP]{inotify}{files} = {}; ############## # The Inotify notifications are received # on a file descriptor. We need to read # from it when there is something to be # read ############## open $inotify_FH, "< &=" . $_[HEAP]{inotify}->fileno or die "Can’t fdopen: $!\n"; ############## # Inform POE to poll the file descriptor ############## $_[KERNEL]->select_read( $inotify_FH, "inotify_poll" ); }, inotify_poll => sub { $_[HEAP]{inotify}->poll; }, watch_hdlr => \&watch_hdlr, ############## # Process the next file in the queue ############## task_next_file => \&task_next_file, ############## # print the output of the job ############## task_output => sub { my $result = $_[ARG0]; print "$result\n"; }, ############## # When we are done with a file, go process the # next file if there is one waiting ############## task_done => sub { my ($kernel, $heap, $task_id) = @_[ KERNEL, HEAP, ARG0 ]; delete $heap->{task}{$task_id}; $kernel->yield("task_next_file"); }, sig_child => sub { my ($heap, $pid) = @_[ HEAP, ARG1 ]; my $details = delete $heap->{$pid}; }, }, ); POE::Kernel->run(); } exit 0;

Example output:

ps3_mp3_converter.pl -d /home/jfroebe/j Watching directory /home/jfroebe/j Watching directory /home/jfroebe/j/bin Watching directory /home/jfroebe/j/doc Watching directory /home/jfroebe/j/java Watching directory /home/jfroebe/j/lib Watching directory /home/jfroebe/j/j Watching directory /home/jfroebe/j/j/tmp Watching directory /home/jfroebe/j/sdk Watching directory /home/jfroebe/j/sdk/demo Watching directory /home/jfroebe/j/sdk/include New directory: /home/jfroebe/j/Earth Final Conflict Soundtrack Watching directory /home/jfroebe/j/Earth Final Conflict Soundtrack Processed "/home/jfroebe/j/Earth Final Conflict Soundtrack/01 Main T +itle.mp3" Processed "/home/jfroebe/j/Earth Final Conflict Soundtrack/02 The Sc +ret of Strandhill-Redemption.mp3" Processed "/home/jfroebe/j/Earth Final Conflict Soundtrack/03 Old Fl +ame.mp3" Processed "/home/jfroebe/j/Earth Final Conflict Soundtrack/04 Defect +or.mp3" Processed "/home/jfroebe/j/Earth Final Conflict Soundtrack/05 Decidi +on.mp3" Processed "/home/jfroebe/j/Earth Final Conflict Soundtrack/06 Float +Like a Butterfly.mp3" Processed "/home/jfroebe/j/Earth Final Conflict Soundtrack/07 Sandov +al’s Run.mp3" Processed "/home/jfroebe/j/Earth Final Conflict Soundtrack/08 Bliss. +mp3" Processed "/home/jfroebe/j/Earth Final Conflict Soundtrack/09 If You + Could Read My Mind.mp3" Processed "/home/jfroebe/j/Earth Final Conflict Soundtrack/10 Lilli. +mp3" Processed "/home/jfroebe/j/Earth Final Conflict Soundtrack/11 Law an +d Order.mp3" Processed "/home/jfroebe/j/Earth Final Conflict Soundtrack/12 Atavus +.mp3" Processed "/home/jfroebe/j/Earth Final Conflict Soundtrack/13 Betwee +n Heaven and Hell.mp3" Processed "/home/jfroebe/j/Earth Final Conflict Soundtrack/14 Sleepe +rs.mp3" Processed "/home/jfroebe/j/Earth Final Conflict Soundtrack/15 Dimens +ions.mp3" Processed "/home/jfroebe/j/Earth Final Conflict Soundtrack/16 Moonsc +ape.mp3" Processed "/home/jfroebe/j/Earth Final Conflict Soundtrack/17 Isabel +.mp3" Processed "/home/jfroebe/j/Earth Final Conflict Soundtrack/18 The Ga +untlet.mp3" Processed "/home/jfroebe/j/Earth Final Conflict Soundtrack/19 Second + Chances.mp3" Processed "/home/jfroebe/j/Earth Final Conflict Soundtrack/20 One Ma +n’s Castle.mp3" Processed "/home/jfroebe/j/Earth Final Conflict Soundtrack/21 Paybac +k.mp3" Processed "/home/jfroebe/j/Earth Final Conflict Soundtrack/22 Truth. +mp3" Processed "/home/jfroebe/j/Earth Final Conflict Soundtrack/23 Déjà V +u.mp3" Processed "/home/jfroebe/j/Earth Final Conflict Soundtrack/24 Crossf +ire.mp3" Processed "/home/jfroebe/j/Earth Final Conflict Soundtrack/25 Volunt +eers-End Credits.mp3"

Jason L. Froebe

Blog, Tech Blog


In reply to Howto: Convert your mp3 tags (id3v2 to id3v1) en masse by jfroebe

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • Outside of code tags, you may need to use entities for some characters:
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.
  • Log In?
    Username:
    Password:

    What's my password?
    Create A New User
    Chatterbox?
    and the web crawler heard nothing...

    How do I use this? | Other CB clients
    Other Users?
    Others about the Monastery: (4)
    As of 2014-07-13 18:58 GMT
    Sections?
    Information?
    Find Nodes?
    Leftovers?
      Voting Booth?

      When choosing user names for websites, I prefer to use:








      Results (251 votes), past polls