#!/usr/bin/perl -w # m3udo: a script to iterate on all files in an m3u playlist. There's # no need to retype this whole fingerbusting thing every time, and # getting even a thing as simple as this right takes a lot of error # checking. # # The home of this code on the web is http://gonze.com/m3udo/latest # Contact: Lucas Gonze # Changelog: # # May 17, 2003: # * fix blank item test # * escape shell metacharacters # # May 15, 2003: # * Fix error message when invoked with no arguments # # April 24, 2003: # * added -r flag for recursion # * handle multiple m3u files on command line # * swap position of cmd and m3us # * added support for multiple M3Us # * started changelog use strict; use FileHandle; check_usage(); my $cmd; my $recurse = 0; while( $#ARGV > -1 ){ my $arg = shift(); # -r flag means to recurse into any .m3u files if( $arg eq "-r" ){ $recurse = 1; next; } # the first un-flagged argument is the command string if( !$cmd ){ $cmd = $arg; next; } # remaining arguments are input files. the special filename "-", # meaning stdin, is handled automatically by perl. do_m3u($arg,$recurse,$cmd); } sub escape_shell_metacharacters { my( $str ) = @_; @_ = $str; # this list of dangerous characters is far from exhaustive, but # ultimately the responsibility has to rest on the user to inspect # filenames before passing them to this script. s/([;<>\*\|`&\$!#\(\)\[\]\{\}:'"!# ])/\\$1/g; return $_; } # iterate over an m3u file sub do_m3u { my ($m3u, $recurse, $cmd) = @_; my $fh = new FileHandle; if(! $fh->open("< $m3u")) { print STDERR "Unable to open $m3u\n"; return; } while (<$fh>) { # trim leading and trailing whitespace s/(^\s*)(.*)(\s*$)/$2/g; # trim trailing carriage return caused by windows-unix conversion s/(.*)(\r$)/$1/g; # skip comments if ( /^\#/ ) { next; } # skip blanks if ( ! length($_) ){ next; } chomp(); my $item = escape_shell_metacharacters($_); # if item is a .m3u file, process it recursively if( $recurse && /^.*\.m3u$/ ){ print "$item:\n"; do_m3u($item,$recurse,$cmd); next; } $_ = $cmd; if ( /(.*)(\{\})(.*)/ ) { # if {} exists in the command, replace it with the file name s/\{\}/$item/g; system($_); next; } # append line to command and run it system("$cmd $item"); } $fh->close; } sub check_usage { if( !defined(@ARGV) || ( $#ARGV < 1 && $ARGV[0] ne "-h" && $ARGV[0] ne "--help" && $ARGV[0] ne "-help") ){ print <> cache.m3u" my.m3u will fetch items that are HTTP urls and create a new playlist with local copies. m3udo ls *.m3u will run the ls command on each item in all m3u files. cat my.m3u | m3udo ls - will run the ls command on each item in my.m3u. m3udo -r ls my.m3u will run the ls command on each item in my.m3u, and on each item in any m3u files contained in my.m3u, ad recursivitum. EOF exit 0; }