-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathm3u
executable file
·142 lines (128 loc) · 4.89 KB
/
m3u
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
#!/usr/bin/env perl
#
# stupid little script that writes album.m3u, which (at least Zinf mp3 player)
# interprets as a playlist.
#
# File format, "Basic M3U", is absurdly simple, but it works, so who's
# complaining? (extended/expanded M3U formats offer nothing I need)
#
# 20060508 klg wrote
#
# Well, one thing I need is a RECURSIVE version, maybe on that generates a
# randomized list. Why? Well, because I have a tree "Kevins_Singles" which
# contains, more or less, one file per directory, and I'd like to "queue up" all
# of the files (in random order). So, each time I want to listen to these songs,
# I'd run 'm3u -r' in the root dir of this tree, then invoke the player on the
# generated m3u file. Sounds like a job for File::Find (UPDT: glob can now
# handle recursive searches!!!?).
#
# 20071204 kgoodwin added -r option to do this
#
# glob is NOT the way to go! It only APPEARS to handle recursive searches.
# Now/again using File::Find.
#
# Now takes cmdline args, generally expected to be dir names (supplied via Total
# Commander selection via %S) whose contents are to be incorporated into a
# playlist.
#
# 20071205 kgoodwin
#
# generate m3u files in each directory either containing, or containing
# directories which contain (directories which contain ...) >1 playable files.
#
# 20170118 kgoodwin
#
use strict;
use warnings;
use feature 'signatures';
use English;
use File::Find;
use Cwd;
use Getopt::Std;
our ($opt_n,$opt_r,$opt_s);
getopts( "n:rs" );
my $startDir = cwd(); # print "startDir=$startDir\n";
my $startDirRe = '^' . quotemeta($startDir) . '/';
my @playablefiles;
# $m3u_filename = $opt_n || ($opt_r or scalar @ARGV) && "playlist.m3u" || "00.m3u";
my $m3u_filename = $opt_s && "playlist.m3u" || "00.m3u";
# { local $LIST_SEPARATOR = "\n"; print "\@ARGV=@ARGV\n"; }
my @args = @ARGV;
@args = ($startDir) unless @args;
my ($reRename,$reM3u) = do {
my @playableExts = qw( mp3 mp4 mpg m4a m4b wmv flac f4v flv );
my @playAssistExts = qw( srt vtt );
sub extRE {
my $rv = '\.(?i)(?:' . join('|', @_) . ')$'; # print "\npat=$rv\n";
return qr($rv);
}
( extRE( @playableExts, @playAssistExts )
, extRE( @playableExts )
)
};
my @renames;
my %eachdir;
sub eachFile { # even if this appears nasty, GLOB is NOT a better alternative!
my $thisDir = $File::Find::dir; # print "D0=$thisDir\n"; # NB !!! WE ARE CD'D INTO $thisDir !!!
++$eachdir{$thisDir}; # we will generate a m3u file in eachdir PROVIDED it or any of its child dirs contain @playablefiles
return unless -f $_; # print "F0=$_\n"; # sanspath i.e. leaf name: might be a dir; ignore these
my $fullnm = $File::Find::name; print "F1=$fullnm\n"; # "$File::Find::dir/$_"
if( $_ =~ $reRename ) {
my $newfnm = $_ =~ s!\s*\-\s*!-!gr; # print "F1newfnm=$newfnm\n";
$newfnm =~ s!(^(?:\d+\.)?\d+)[-\s\.]+([^-\.\s].*)$!$1-$2!;
if( $newfnm ne $_ ) {
my $newfnmFull = "$thisDir/$newfnm";
my $newfnmSd = $newfnmFull =~ s!$startDirRe!!r;
my $fileSd = $fullnm =~ s!$startDirRe!!r;
# print "rename\n'$fileSd'\n'$newfnmSd'\n";
push @renames, [ $fileSd, $newfnmSd ];
$fullnm = $newfnmFull;
}
push( @playablefiles, $fullnm ) if $_ =~ $reM3u;
}
}
for my $arg ( @args ) {
# print "arg=$arg\n";
if( -f $arg ) { push( @playablefiles, $arg ); }
elsif( -d $arg ) { # print "a=$arg\n";
find( \&eachFile, $arg );
print "scan done\n";
}
else { push( @playablefiles, glob( $arg ) ); }
}
for my $ar ( @renames ) {
my($fileSd, $newfnmSd) = @$ar;
print "mv\n '$fileSd'\n '$newfnmSd'\n";
rename $fileSd, $newfnmSd or die "rename of $fileSd -> $newfnmSd FAILED\n";
}
if( ! %eachdir ) {
++$eachdir{$startDir}
}
if( $opt_s ) {
use List::Util 'shuffle';
@playablefiles = shuffle(@playablefiles);
}
else {
@playablefiles = sort @playablefiles;
}
sub wr_array { my ($ofnm,$aref) = @_;
print "writing $ofnm\n";
open my $ofh, ">", $ofnm or die "can't open $ofnm for writing: $!\n";
local $LIST_SEPARATOR = "\n";
print $ofh "@$aref";
}
sub write_m3u ($destdir, $aref) { # print "F0=$destdir\n";
my @results;
my $ddre = quotemeta($destdir);
for my $fnm ( @$aref ) {
if( my ($fnm_rel) = $fnm =~ m|^$ddre[\\/](.+)$| ) { # print "F1=$fnm_rel\n";
$fnm_rel =~ s!/+!\\!g; # print "F2=$fnm_rel\n";
$fnm_rel =~ s!\\+!\\!g; # print "F3=$fnm_rel\n";
$fnm_rel =~ s!^\.\\!!; # print "F4=$fnm_rel\n";
push @results, $fnm_rel;
}
}
wr_array( "$destdir/$m3u_filename", \@results ) if @results > 1; # no playlist file needed for single playable file
}
write_m3u( $_, \@playablefiles ) for ( sort keys %eachdir );
exit( scalar @playablefiles > 0 ? 0 : 1 );