File Coverage

blib/lib/Video/DVDRip/Depend.pm
Criterion Covered Total %
statement 96 138 69.5
branch 31 64 48.4
condition 11 22 50.0
subroutine 11 17 64.7
pod 0 14 0.0
total 149 255 58.4


line stmt bran cond sub pod time code
1             # $Id: Depend.pm 2377 2009-02-22 18:49:50Z joern $
2              
3             #-----------------------------------------------------------------------
4             # Copyright (C) 2001-2006 Jörn Reder .
5             # All Rights Reserved. See file COPYRIGHT for details.
6             #
7             # This program is part of Video::DVDRip, which is free software; you can
8             # redistribute it and/or modify it under the same terms as Perl itself.
9             #-----------------------------------------------------------------------
10              
11             package Video::DVDRip::Depend;
12 1     1   11 use Locale::TextDomain qw (video.dvdrip);
  1         2  
  1         29  
13              
14             @ISA = qw ( Video::DVDRip::Base );
15              
16             my $DEBUG = 0;
17              
18 1     1   625 use Carp;
  1         6  
  1         130  
19 1     1   10 use strict;
  1         2  
  1         4931  
20              
21             my @DVDRIP_BIN_FILES = qw (
22             dvdrip execflow
23             dvdrip-master dvdrip-multitee
24             dvdrip-progress dvdrip-splitpipe
25             dvdrip-subpng
26             );
27              
28             my @DVDRIP_MASTER_BIN_FILES = qw (
29             execflow
30             dvdrip-master
31             );
32              
33             my $OBJECT;
34              
35             my $ORDER = 0;
36             my %TOOLS = (
37             "dvd::rip" => {
38             order => ++$ORDER,
39             command => "dvdrip",
40             comment => __ "All internal command files",
41             optional => 0,
42             dont_cache => 1,
43             exists => 1,
44             get_version => sub {
45             my $missing_file_cnt = 0;
46             my @files = $Video::DVDRip::ISMASTER ?
47             @DVDRIP_MASTER_BIN_FILES : @DVDRIP_BIN_FILES;
48             foreach my $dvdrip_file ( @files ) {
49             if ( !__PACKAGE__->get_full_path($dvdrip_file) ) {
50             ++$missing_file_cnt;
51             print STDERR __x( "ERROR: '{file}' not found in PATH\n",
52             file => $dvdrip_file )
53             unless $Video::DVDRip::MAKE_TEST;
54             }
55             }
56             return $missing_file_cnt == @DVDRIP_BIN_FILES ? ""
57             : $missing_file_cnt == 0 ? $Video::DVDRip::VERSION
58             : "incomplete";
59             },
60             convert => 'default',
61             __convert => sub {
62             my ($version) = @_;
63             return $version eq '' ? 0
64             : $version eq 'incomplete' ? 0
65             : $Video::DVDRip::VERSION;
66             },
67             min => $Video::DVDRip::VERSION,
68             suggested => $Video::DVDRip::VERSION,
69             installed => undef, # set by ->new
70             installed_num => undef, # set by ->new
71             min_num => undef, # set by ->new
72             suggested_num => undef, # set by ->new
73             installed_ok => undef, # set by ->new
74             },
75             transcode => {
76             order => ++$ORDER,
77             command => "transcode",
78             comment => __ "dvd::rip is nothing without transcode",
79             optional => 0,
80             version_cmd => "transcode -v",
81             get_version => sub {
82             my ($cmd) = @_;
83             qx[$cmd 2>&1] =~ /v(\d+\.\d+\.\d+(\.\d+)?)/i;
84             return $1;
85             },
86             convert => 'default',
87             min => "0.6.14",
88             max => undef,
89             suggested => "1.0.2",
90             installed => undef, # set by ->new
91             installed_num => undef, # set by ->new
92             min_num => undef, # set by ->new
93             suggested_num => undef, # set by ->new
94             installed_ok => undef, # set by ->new
95             cluster => 1,
96             },
97             ImageMagick => {
98             order => ++$ORDER,
99             command => "convert",
100             comment => __ "Needed for preview image processing",
101             optional => 0,
102             version_cmd => "convert -version",
103             get_version => sub {
104             my ($cmd) = @_;
105             my ($output) = qx[$cmd 2>&1];
106             #-- GraphicsMagick is compatible with ImageMagick 5.5.2.
107             return "5.5.2" if $output =~ /GraphicsMagick\s+(\d+\.\d+(\.\d+)?)/i;
108             $output =~ /ImageMagick\s+(\d+\.\d+(\.\d+)?)/i;
109             return $1;
110             },
111             convert => 'default',
112             min => "4.0.0",
113             suggested => "6.2.3",
114             },
115             ffmpeg => {
116             order => ++$ORDER,
117             command => "ffmpeg",
118             comment => __ "FFmpeg video converter command line program",
119             optional => 1,
120             version_cmd => "ffmpeg -version",
121             get_version => sub {
122             my ($cmd) = @_;
123             qx[$cmd 2>&1] =~ /version ([^\s]+)/i;
124             return $1;
125             },
126             convert => 'default',
127             min => "0.4.10",
128             },
129             xvid4conf => {
130             order => ++$ORDER,
131             command => "xvid4conf",
132             comment => __ "xvid4 configuration tool",
133             optional => 1,
134             version_cmd => "xvid4conf -v",
135             get_version => sub {
136             my ($cmd) = @_;
137             qx[$cmd 2>&1] =~ /(\d+\.\d+(\.\d+)?)/i;
138             return $1;
139             },
140             convert => 'default',
141             min => "1.6",
142             suggested => "1.12",
143             },
144             subtitle2pgm => {
145             order => ++$ORDER,
146             command => "subtitle2pgm",
147             comment => __ "Needed for subtitles",
148             optional => 1,
149             version_cmd => "subtitle2pgm -h",
150             get_version => sub {
151             my ($cmd) = @_;
152             qx[$cmd 2>&1] =~ /version\s+(\d+\.\d+(\.\d+)?)/i;
153             return $1;
154             },
155             convert => 'default',
156             min => "0.3",
157             suggested => "0.3",
158             },
159             lsdvd => {
160             order => ++$ORDER,
161             command => "lsdvd",
162             comment => __ "Needed for faster DVD TOC reading",
163             optional => 1,
164             version_cmd => "lsdvd -V",
165             get_version => sub {
166             my ($cmd) = @_;
167             qx[lsdvd -V 2>&1] =~ /lsdvd\s+(\d+\.\d+(\.\d+)?)/i;
168             return $1;
169             },
170             convert => 'default',
171             min => "0.15",
172             suggested => "0.15",
173             },
174             rar => {
175             order => ++$ORDER,
176             command => Video::DVDRip::Depend->config('rar_command'),
177             comment => __ "Needed for compressed vobsub subtitles",
178             optional => 1,
179             version_cmd => "",
180             get_version => sub {
181             my $cmd = Video::DVDRip::Depend->config('rar_command')." '-?'";
182             qx[$cmd 2>&1] =~ /rar\s+(\d+\.\d+(\.\d+)?)/i;
183             return $1;
184             },
185             convert => 'default',
186             min => "2.71",
187             max => "2.99",
188             suggested => "2.71",
189             },
190             mplayer => {
191             order => ++$ORDER,
192             command => "mplayer",
193             comment => __ "Needed for subtitle vobsub viewing",
194             optional => 1,
195             version_cmd => "mplayer --help",
196             get_version => sub {
197             my ($cmd) = @_;
198             my $out = qx[$cmd 2>&1];
199             if ( $out =~ /CVS|SVN/i ) {
200             return "cvs";
201             }
202             else {
203             $out =~ /MPlayer.*?(\d+\.\d+(\.\d+)?)/i;
204             return $1;
205             }
206             },
207             convert => 'default',
208             min => "0.90",
209             suggested => "1.00",
210             },
211             ogmtools => {
212             order => ++$ORDER,
213             command => "ogmmerge",
214             comment => __ "Needed for OGG/Vorbis",
215             optional => 1,
216             version_cmd => "ogmmerge -V",
217             get_version => sub {
218             my ($cmd) = @_;
219             qx[$cmd 2>&1] =~ /v(\d+\.\d+(\.\d+)?)/i;
220             return $1;
221             },
222             convert => 'default',
223             min => "1.0.0",
224             suggested => "1.5",
225             cluster => 1,
226             },
227             dvdxchap => {
228             order => ++$ORDER,
229             command => "dvdxchap",
230             comment => __ "For chapter progress bar (ogmtools)",
231             optional => 1,
232             version_cmd => "dvdxchap -V",
233             get_version => sub {
234             my ($cmd) = @_;
235             qx[$cmd 2>&1] =~ /v(\d+\.\d+(\.\d+)?)/i;
236             return $1;
237             },
238             convert => 'default',
239             min => "1.0.0",
240             suggested => "1.5",
241             },
242             mjpegtools => {
243             order => ++$ORDER,
244             command => "mplex",
245             comment => __ "Needed for (S)VCD encoding",
246             optional => 1,
247             version_cmd => "mplex --help",
248             get_version => sub {
249             my ($cmd) = @_;
250             qx[$cmd 2>&1] =~ /version\s+(\d+\.\d+(\.\d+)?)/i;
251             return $1;
252             },
253             convert => 'default',
254             min => "1.6.0",
255             suggested => "1.6.2",
256             },
257             xine => {
258             order => ++$ORDER,
259             command => "xine",
260             comment => __ "Can be used to view DVD's/files",
261             optional => 1,
262             version_cmd => "xine -version",
263             get_version => sub {
264             my ($cmd) = @_;
265             qx[$cmd 2>&1] =~ /v(\d+\.\d+(\.\d+)?)/i;
266             return $1;
267             },
268             convert => 'default',
269             min => "0.9.13",
270             suggested => "0.9.15",
271             },
272             fping => {
273             order => ++$ORDER,
274             command => "fping",
275             comment => __ "Only for cluster mode master",
276             optional => 1,
277             version_cmd => "fping -v",
278             get_version => sub {
279             my ($cmd) = @_;
280             qx[$cmd 2>&1] =~ /Version\s+(\d+\.\d+(\.\d+)?)/i;
281             return $1;
282             },
283             convert => 'default',
284             min => "2.2",
285             suggested => "2.4",
286             },
287             hal => {
288             order => ++$ORDER,
289             command => "lshal",
290             comment => __"Used for DVD device scanning",
291             optional => 1,
292             version_cmd => "lshal -v",
293             get_version => sub {
294             my ($cmd) = @_;
295             qx[$cmd 2>&1] =~ /version\s+(\d+\.\d+(\.\d+)?)/i;
296             return $1;
297             },
298             convert => 'default',
299             min => "0.5",
300             suggested => "0.5.7",
301             },
302             );
303              
304             sub convert_default {
305 45     45 0 67 my ($ver) = @_;
306 45 50       157 return 990000 if $ver =~ /cvs|svn/i;
307 45         136 $ver =~ m/(\d+)(\.(\d+))?(\.(\d+))?(\.\d+)?/;
308 45         184 $ver = $1 * 10000 + $3 * 100 + $5;
309 45 50       98 $ver = $ver - 1 + $6 if $6;
310 45         132 return $ver;
311             }
312              
313             sub convert_none {
314 0     0 0 0 return $_[0];
315             }
316              
317             sub new {
318 1     1 0 3 my $class = shift;
319              
320 1 50       4 return $OBJECT if $OBJECT;
321              
322 1         4 my $OBJECT = bless {}, $class;
323              
324 1         4 $OBJECT->load_tool_version_cache;
325              
326 1         3 my $dependencies_ok = 1;
327              
328 1         3 my ( $tool, $def );
329 1         9 while ( ( $tool, $def ) = each %TOOLS ) {
330 15         29 my $get_version = $def->{get_version};
331 15         24 my $convert = $def->{convert};
332 15 50       35 if ( $convert eq 'default' ) {
    0          
333 15         27 $convert = \&convert_default;
334             }
335             elsif ( $convert eq 'none' ) {
336 0         0 $convert = \&convert_none;
337             }
338              
339 15 50       37 $DEBUG && print "[depend] $tool => ";
340              
341 15   66     37 my $version = $OBJECT->get_cached_version($def)
342             || &$get_version($def->{version_cmd});
343              
344 15 100       48 if ( $version ne '' ) {
345 14 50       34 $DEBUG && print "$version ";
346 14         28 $def->{installed} = $version;
347 14         32 $def->{installed_num} = &$convert($version);
348 14 50       38 $DEBUG && print "=> $def->{installed_num}\n";
349             }
350             else {
351 1 50       5 $DEBUG && print "NOT INSTALLED\n";
352 1         10 $def->{installed} = __ "not installed";
353             }
354              
355 15 100       132 $def->{max_num} = &$convert( $def->{max} ) if defined $def->{max};
356 15         36 $def->{min_num} = &$convert( $def->{min} );
357 15         33 $def->{suggested_num} = &$convert( $def->{suggested} );
358 15   66     56 $def->{installed_ok} = $def->{exists} && ($def->{installed_num} >= $def->{min_num});
359 15 50 66     50 $def->{installed_ok} = 0
360             if defined $def->{max}
361             and $def->{installed_num} > $def->{max_num};
362 15 100 66     121 $dependencies_ok = 0
363             if not $def->{optional}
364             and not $def->{installed_ok};
365             }
366              
367 1         17 $OBJECT->{ok} = $dependencies_ok;
368              
369 1         5 $OBJECT->update_tool_version_cache;
370              
371 1         6 return $OBJECT;
372             }
373              
374             sub load_tool_version_cache {
375 1     1 0 3 my $self = shift;
376              
377 1         3 my $dir = "$ENV{HOME}/.dvdrip";
378 1         3 my $filename = "$dir/tool_version_cache";
379              
380 1 50       47 return unless -f $filename;
381              
382 1 50       59 open( IN, $filename ) or die "can't read $filename";
383 1         11682 while () {
384 16         24 chomp;
385 16 50 66     69 if ( /LD_ASSUME_KERNEL=(.*)/
386             && $1 ne $ENV{LD_ASSUME_KERNEL} ) {
387              
388             #-- discard cache if LD_ASSUME_KERNEL changed
389             #-- in the meantime
390 0         0 unlink $filename;
391 0         0 last;
392             }
393 16         66 my ( $tool, $path, $mtime, $size, $version ) = split( /\t/, $_ );
394 16         39 my $def = $self->tools->{$tool};
395 16         44 $def->{path} = $path;
396 16         29 $def->{mtime} = $mtime;
397 16         30 $def->{size} = $size;
398 16         75 $def->{cached_version} = $version;
399             }
400 1         25 close IN;
401              
402 1         4 1;
403             }
404              
405             sub update_tool_version_cache {
406 1     1 0 3 my $self = shift;
407              
408 1         5 my $dir = "$ENV{HOME}/.dvdrip";
409 1         4 my $filename = "$dir/tool_version_cache";
410              
411 1 50 0     27 mkdir $dir, 0755 or die "can't create $dir" if not -d $dir;
412              
413 1 50       141 open( OUT, ">$filename" ) or die "can't write $filename";
414 1         21 print OUT "LD_ASSUME_KERNEL=$ENV{LD_ASSUME_KERNEL}\n";
415 1         2 while ( my ( $tool, $def ) = each %{ $self->tools } ) {
  16         33  
416 15         54 print OUT $tool . "\t"
417             . $def->{path} . "\t"
418             . $def->{mtime} . "\t"
419             . $def->{size} . "\t"
420             . $def->{installed} . "\n";
421             }
422 1         55 close OUT;
423              
424 1         4 1;
425             }
426              
427             sub get_cached_version {
428 15     15 0 21 my $self = shift;
429 15         18 my ($tool_def) = @_;
430              
431 15 100       43 return if $tool_def->{dont_cache};
432              
433 14         23 my $version = $tool_def->{cached_version};
434              
435 14         37 my $path = $self->get_full_path( $tool_def->{command} );
436 14 50       44 if ( $path ne $tool_def->{path} ) {
437 0         0 $tool_def->{path} = $path;
438 0         0 $version = undef;
439             }
440              
441 14         31 $tool_def->{exists} = $path ne '';
442              
443 14         50 my $size = -s $path;
444 14 50       61 if ( $size != $tool_def->{size} ) {
445 0         0 $tool_def->{size} = $size;
446 0         0 $version = undef;
447             }
448              
449 14         65 my $mtime = ( stat $path )[9];
450 14 50       47 if ( $mtime != $tool_def->{mtime} ) {
451 0         0 $tool_def->{mtime} = $mtime;
452 0         0 $version = undef;
453             }
454              
455             #-- Don't cache the version number if the tool
456             #-- is found on the harddrive but cached as
457             #-- missing, otherwise dvd::rip doesn't check
458             #-- tools that crashed due to NPTL issues in
459             #-- the last run but the NPTL settings may have
460             #-- changed in the meantime.
461 14 50 33     70 $version = undef if -x $path && $version eq 'missing';
462              
463 14         53 return $version;
464             }
465              
466             sub get_full_path {
467 21     21 0 36 my $self = shift, my ($file) = @_;
468              
469 21 50       55 return $file if $file =~ m!^/!;
470              
471 21 50       223 if ( not -x $file ) {
472 21         103 foreach my $p ( split( /:/, $ENV{PATH} ) ) {
473 147 50       2792 $file = "$p/$file", last if -x "$p/$file";
474             }
475             }
476              
477 21 50       169 return $file if -x $file;
478 21         52 return;
479             }
480              
481 0     0 0 0 sub ok { shift->{ok} }
482 32     32 0 90 sub tools { \%TOOLS }
483              
484             sub has {
485 0     0 0 0 my $self = shift;
486 0         0 my ($command) = @_;
487 0 0       0 return 0 if not exists $TOOLS{$command};
488 0         0 return $TOOLS{$command}->{installed_ok};
489             }
490              
491             sub exists {
492 0     0 0 0 my $self = shift;
493 0         0 my ($command) = @_;
494 0 0       0 return 0 if not exists $TOOLS{$command};
495 0         0 return $TOOLS{$command}->{exists};
496             }
497              
498             sub version {
499 1     1 0 3 my $self = shift;
500 1         7 my ($command) = @_;
501 1 50       6 return if not exists $TOOLS{$command};
502 1         8 return $TOOLS{$command}->{installed_num};
503             }
504              
505             sub gen_depend_table {
506 0     0 0   my $tools = \%TOOLS;
507              
508 0           print <<__EOF;
509            
510            
511             Tool
512             Comment
513             Mandatory
514             Suggested
515             Minimum
516             Maximum
517            
518             __EOF
519              
520 0           foreach my $tool (
  0            
521 0           sort { $tools->{$a}->{order} <=> $tools->{$b}->{order} }
522             keys %{$tools}
523             ) {
524 0 0         next if $tool eq 'dvd::rip';
525 0           my $def = $tools->{$tool};
526 0   0       $def->{max} ||= "-";
527 0 0         $def->{mandatory} = !$def->{optional} ? "Yes" : "No";
528 0           print <<__EOF;
529            
530             $tool
531             $def->{comment}
532             $def->{mandatory}
533             $def->{suggested}
534             $def->{min}
535             $def->{max}
536            
537             __EOF
538             }
539              
540 0           print "
\n";
541             }
542              
543             sub installed_tools_as_text {
544 0     0 0   my $self = shift;
545              
546 0           my $tools = \%TOOLS;
547              
548 0           my $format = " %-20s %-10s\n";
549 0           my $text = "\n" . sprintf( $format, __ "Program", __ "Version" );
550              
551 0           $text .= " " . ( "-" x 31 ) . "\n";
552              
553 0           foreach my $tool (
  0            
554 0           sort { $tools->{$a}->{order} <=> $tools->{$b}->{order} }
555             keys %{$tools}
556             ) {
557 0           my $def = $tools->{$tool};
558 0           $text .= sprintf( $format, $tool, $def->{installed} );
559             }
560              
561 0           $text .= " " . ( "-" x 31 ) . "\n";
562              
563 0           return $text;
564             }
565              
566             1;