File Coverage

blib/lib/Audio/TagLib/Shell.pm
Criterion Covered Total %
statement 27 168 16.0
branch 0 114 0.0
condition 0 17 0.0
subroutine 9 36 25.0
pod n/a
total 36 335 10.7


line stmt bran cond sub pod time code
1             package Audio::TagLib::Shell;
2              
3 1     1   35956 use 5.008003;
  1         3  
  1         43  
4 1     1   5 use strict;
  1         2  
  1         237  
5 1     1   5 use warnings;
  1         6  
  1         43  
6 1     1   4 use Carp q(croak);
  1         1  
  1         81  
7 1     1   28 use Cwd q(chdir);
  1         1  
  1         63  
8              
9             require Exporter;
10 1     1   442582 use AutoLoader qw(AUTOLOAD);
  1         2165  
  1         7  
11              
12             our @ISA = qw(Exporter);
13              
14             # Items to export into callers namespace by default. Note: do not export
15             # names by default without a very good reason. Use EXPORT_OK instead.
16             # Do not simply export all your public functions/methods/constants.
17              
18             our @EXPORT_OK = qw(shell);
19              
20             our @EXPORT = qw(shell);
21              
22             our $VERSION = '1.42';
23              
24             # support encodings
25             our @ENCODING = qw(Latin1 UTF8);
26              
27             # pre-declared subs
28             my @callback = qw(open save close title artist album comment genre
29             year track setTitle setArtist setAlbum setComment
30             setGenre setYear setTrack length bitrate sampleRate
31             channels cd exit pwd ls);
32 1     1   1188 use subs map { "_".$_ } @callback;
  1         24  
  1         7  
  0         0  
33 1     1   36 use subs qw(shell);
  1         2  
  1         5  
34              
35             # global default command callback map
36             #{
37             # no strict 'refs';
38             our %CMD = map { +"$_" => \&{"_".$_}, } @callback;
39             #}
40             # nice alias
41             $CMD{quit} = $CMD{exit};
42             $CMD{bye} = $CMD{exit};
43              
44             # private reference to current openned file
45             # to make sure there is ONLY ONE file openned
46             my $fileref = undef;
47             # PS1 similar to normal shell
48             # change to q(tag:o>) after a successful open action
49             my $ps1 = q(tag:>);
50             # encoding got from locale settings
51             my $encoding = undef;
52              
53             # Preloaded methods go here.
54              
55             # main sub exported
56             # start the shell
57             sub shell() {
58             # check locale first
59             # follow the normal sequence LC_CTYPE -> LC_ALL -> LANG
60 0     0     my $lc;
61 0 0         if (exists $ENV{LC_CTYPE}) {
    0          
    0          
62 0           $lc = $ENV{LC_CTYPE};
63             } elsif (exists $ENV{LC_ALL}) {
64 0           $lc = $ENV{LC_ALL};
65             } elsif (exists $ENV{LANG}) {
66 0           $lc = $ENV{LANG};
67             }
68 0 0 0       if(defined $lc and $lc =~
69             m/^([a-z]{2}_[A-Z]{2})
70             (?:\.(?i:([a-z_\-_0-9]+)))?
71             (?:@(?i:[a-z_0-9]+))?$/xo) {
72 0 0 0       if(defined $2 and lc($2) eq 'utf8' or lc($2) eq 'utf-8') {
    0 0        
      0        
73 0           $encoding = 1;
74 0           binmode STDOUT, ":utf8";
75             } elsif(not defined $2 and $1 eq 'en_US') {
76 0           $encoding = 0;
77             } else {
78 0           croak(sprintf("currently only support %s\n",
79             join(" ", @ENCODING)));
80             }
81             } else {
82 0           croak("no valid locale setting found");
83             }
84            
85             # open shell
86 0           require Term::BashTab;
87 0           local (*Term::BashTab::COMMAND) = \@callback;
88            
89 0           my $term = Term::BashTab->new("TagLib mini shell");
90 0           my $line;
91 0   0       my $OUT = $term->OUT || \*STDOUT;
92 0           select $OUT;
93 0           $| = 1;
94 0           LOOP: while (1) {
95 0           $line = $term->readline($ps1);
96 0           chomp $line;
97 0 0         next LOOP unless $line;
98 0           $line =~ s/\s+$//o;
99             #print "'$line'\n";
100 0           my ($cmd, $file) = split / /, $line, 2;
101 0           foreach (keys %CMD) {
102             # exact match here
103 0 0         if ($cmd eq $_) {
104 1     1   662 no strict 'refs';
  1         2  
  1         2500  
105 0           print &{$CMD{$cmd}}($file);
  0            
106 0           next LOOP;
107             }
108             }
109             # no match command found
110 0           print "no such command!\n";
111 0           next LOOP;
112             }
113             }
114              
115             # evaluate the file permission for specific action
116             # read or write
117             sub __permission {
118 0     0     my $file = $_[0];
119 0 0         my $perm = $_[1] ? 02 : 04;
120 0           my ($mode, $uid, $gid) = (stat $file)[2, 4, 5];
121 0 0         if($uid == $<) {
    0          
122             # the same user
123 0 0         return 0
124             unless(($mode & 00700) >> 6 & $perm);
125             } elsif($gid == $() {
126             # the same group
127 0 0         return 0
128             unless(($mode & 00070) >> 3 & $perm);
129             } else {
130             # the other
131 0 0         return 0
132             unless(($mode & 00007) & $perm);
133             }
134 0           return 1;
135             }
136              
137             sub _open {
138 0 0   0     if (defined $fileref) {
139 0           return << "EOM" ;
140             There is file openned, close or save first.
141             EOM
142             } else {
143             # check before open
144 0 0         my $file = shift or return "no file specified\n";
145 0 0         return "not found\n" unless -e $file;
146 0 0         return "no read permission\n" unless __permission($file);
147 0 0         warn "no write permission\n" unless __permission($file, 1);
148             # open file
149 0           require Audio::TagLib::FileRef;
150 0           $fileref = Audio::TagLib::FileRef->new($file);
151 0           $ps1 = "tag:o>";
152 0           return "file openned successfully\n";
153             }
154             }
155              
156             sub _save {
157 0 0   0     if(defined $fileref) {
158 0 0         if($fileref->save()) {
159 0           undef $fileref;
160 0           $ps1 = "tag:>";
161 0           return "file saved successfully\n";
162             } else {
163 0           return "file could not be saved\n";
164             }
165             } else {
166 0           return "no file openned\n";
167             }
168             }
169              
170             sub _close {
171 0 0   0     undef $fileref if(defined $fileref);
172 0           $ps1 = "tag:>";
173             }
174              
175             sub _title {
176 0 0   0     if(defined $fileref) {
177 0 0         return $fileref->tag()->title()->toCString(
178             $ENCODING[$encoding] eq 'UTF8' ? 1 : 0). "\n";
179             } else {
180 0           return "no file openned\n";
181             }
182             }
183              
184             sub _artist {
185 0 0   0     if(defined $fileref) {
186 0 0         return $fileref->tag()->artist()->toCString(
187             $ENCODING[$encoding] eq 'UTF8' ? 1 : 0). "\n";
188             } else {
189 0           return "no file openned\n";
190             }
191             }
192              
193             sub _album {
194 0 0   0     if(defined $fileref) {
195 0 0         return $fileref->tag()->album()->toCString(
196             $ENCODING[$encoding] eq 'UTF8' ? 1 : 0). "\n";
197             } else {
198 0           return "no file openned\n";
199             }
200             }
201              
202             sub _comment {
203 0 0   0     if(defined $fileref) {
204 0 0         return $fileref->tag()->comment()->toCString(
205             $ENCODING[$encoding] eq 'UTF8' ? 1 : 0). "\n";
206             } else {
207 0           return "no file openned\n";
208             }
209             }
210              
211             sub _genre {
212 0 0   0     if(defined $fileref) {
213 0 0         return $fileref->tag()->genre()->toCString(
214             $ENCODING[$encoding] eq 'UTF8' ? 1 : 0). "\n";
215             } else {
216 0           return "no file openned\n";
217             }
218             }
219              
220             sub _year {
221 0 0   0     if(defined $fileref) {
222 0           return $fileref->tag()->year(). "\n";
223             } else {
224 0           return "no file openned\n";
225             }
226             }
227              
228             sub _track {
229 0 0   0     if(defined $fileref) {
230 0           return $fileref->tag()->track(). "\n";
231             } else {
232 0           return "no file openned\n";
233             }
234             }
235              
236             sub _setTitle {
237 0 0   0     my $title = $_[0] ?
238             Audio::TagLib::String->new($_[0], $ENCODING[$encoding]) :
239             Audio::TagLib::String->null();
240 0 0         if(defined $fileref) {
241 0           $fileref->tag()->setTitle($title);
242 0           return "title set\n";
243             } else {
244 0           return "no file openned\n";
245             }
246             }
247              
248             sub _setArtist {
249 0 0   0     my $artist = $_[0] ?
250             Audio::TagLib::String->new($_[0], $ENCODING[$encoding]) :
251             Audio::TagLib::String->null();
252 0 0         if(defined $fileref) {
253 0           $fileref->tag()->setArtist($artist);
254 0           return "artist set\n";
255             } else {
256 0           return "no file openned\n";
257             }
258             }
259              
260             sub _setAlbum {
261 0 0   0     my $album = $_[0] ?
262             Audio::TagLib::String->new($_[0], $ENCODING[$encoding]) :
263             Audio::TagLib::String->null();
264 0 0         if(defined $fileref) {
265 0           $fileref->tag()->setAlbum($album);
266 0           return "album set\n";
267             } else {
268 0           return "no file openned\n";
269             }
270             }
271              
272             sub _setComment {
273 0 0   0     my $comment = $_[0] ?
274             Audio::TagLib::String->new($_[0], $ENCODING[$encoding]) :
275             Audio::TagLib::String->null();
276 0 0         if(defined $fileref) {
277 0           $fileref->tag()->setComment($comment);
278 0           return "comment set\n";
279             } else {
280 0           return "no file openned\n";
281             }
282             }
283              
284             sub _setGenre {
285 0 0   0     my $genre = $_[0] ?
286             Audio::TagLib::String->new($_[0], $ENCODING[$encoding]) :
287             Audio::TagLib::String->null();
288 0 0         if(defined $fileref) {
289 0           $fileref->tag()->setGenre($genre);
290 0           return "genre set\n";
291             } else {
292 0           return "no file openned\n";
293             }
294             }
295              
296             sub _setYear {
297 0 0   0     my $year = shift or return "no year to set\n";
298 0 0         if(defined $fileref) {
299 0           $fileref->tag()->setYear($year);
300 0           return "year set\n";
301             } else {
302 0           return "no file openned\n";
303             }
304             }
305              
306             sub _setTrack {
307 0 0   0     my $track = shift or return "no track to set\n";
308 0 0         if(defined $fileref) {
309 0           $fileref->tag()->setTrack($track);
310 0           return "track set\n";
311             } else {
312 0           return "no file openned\n";
313             }
314             }
315              
316             sub _length {
317 0 0   0     if(defined $fileref) {
318 0           return $fileref->audioProperties()->length(). "\n";
319             } else {
320 0           return "no file openned\n";
321             }
322             }
323              
324             sub _bitrate {
325 0 0   0     if(defined $fileref) {
326 0           return $fileref->audioProperties()->bitrate(). "\n";
327             } else {
328 0           return "no file openned\n";
329             }
330             }
331              
332             sub _sampleRate {
333 0 0   0     if(defined $fileref) {
334 0           return $fileref->audioProperties()->sampleRate(). "\n";
335             } else {
336 0           return "no file openned\n";
337             }
338             }
339              
340             sub _channels {
341 0 0   0     if(defined $fileref) {
342 0           return $fileref->audioProperties()->channels(). "\n";
343             } else {
344 0           return "no file openned\n";
345             }
346             }
347              
348             sub _cd {
349 0   0 0     my $dir = shift || $ENV{HOME};
350             #print $dir. "\n";
351 0 0         return "not a directory\n" unless -d $dir;
352 0 0         chdir $dir or return "cd: $!\n";
353             }
354              
355             sub _exit {
356 0 0   0     if(defined $fileref) {
357 0           return "there's file openned, save or close first\n";
358             } else {
359 0           exit(0);
360             }
361             }
362              
363             sub _pwd {
364 0     0     return $ENV{PWD}. "\n";
365             }
366              
367             # simply list all the entries in cwd
368             sub _ls {
369 0     0     local (*CWD);
370 0 0         opendir CWD, "." or return "can't open cwd\n";
371 0           my @entry = sort grep { m/^[^.]/ } readdir CWD;
  0            
372 0 0         closedir CWD or warn "closedir: $!\n";
373 0           return join("\t"x2, @entry), "\n";
374             }
375              
376             # Autoload methods go after =cut, and are processed by the autosplit program.
377              
378             1;
379             __END__