File Coverage

blib/lib/Video/DVDRip/Base.pm
Criterion Covered Total %
statement 30 225 13.3
branch 0 68 0.0
condition 0 6 0.0
subroutine 10 36 27.7
pod 0 27 0.0
total 40 362 11.0


line stmt bran cond sub pod time code
1             # $Id: Base.pm 2280 2007-03-17 10:56:47Z joern $
2              
3             #-----------------------------------------------------------------------
4             # Copyright (C) 2001-2006 Jörn Reder .
5             # All Rights Reserved. See file COPYRIGHT for details.
6             #
7             # This module 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::Base;
12 1     1   8 use Locale::TextDomain qw (video.dvdrip);
  1         2  
  1         10  
13              
14 1     1   950 use Video::DVDRip::Config;
  1         9  
  1         170  
15 1     1   1614 use Video::DVDRip::FilterList;
  1         3  
  1         54  
16              
17 1     1   7 use Carp;
  1         2  
  1         94  
18 1     1   6 use strict;
  1         2  
  1         44  
19 1     1   7 use FileHandle;
  1         3  
  1         9  
20 1     1   1788 use IO::Pipe;
  1         2746  
  1         50  
21 1     1   11 use Fcntl;
  1         1  
  1         810  
22 1     1   8 use Data::Dumper;
  1         2  
  1         3788  
23              
24             # load preferences ---------------------------------------------------
25             my $CONFIG_OBJECT = Video::DVDRip::Config->new;
26             $Video::DVDRip::PREFERENCE_FILE ||= "$ENV{HOME}/.dvdriprc";
27             $CONFIG_OBJECT->set_filename($Video::DVDRip::PREFERENCE_FILE);
28             $CONFIG_OBJECT->save if not -f $Video::DVDRip::PREFERENCE_FILE;
29             $CONFIG_OBJECT->load;
30              
31             # detect installed tool versions -------------------------------------
32             require Video::DVDRip::Depend;
33             my $DEPEND_OBJECT = Video::DVDRip::Depend->new;
34              
35             # pre load transcode's filter list -----------------------------------
36             Video::DVDRip::FilterList->get_filter_list
37             if $DEPEND_OBJECT->version("transcode") >= 603;
38              
39             # init some config settings ------------------------------------------
40             # (this depends on a loaded Config and Depend, that's why we call it here)
41             $CONFIG_OBJECT->init_settings;
42              
43             sub new {
44 0     0 0 0 my $class = shift;
45 0         0 return bless {}, $class;
46             }
47              
48             sub config {
49 1     1 0 592 my $thingy = shift;
50 1         3 my ($name) = @_;
51 1         14 return $CONFIG_OBJECT->get_value($name);
52             }
53              
54             sub set_config {
55 0     0 0   my $thingy = shift;
56 0           my ( $name, $value ) = @_;
57 0           $CONFIG_OBJECT->set_value( $name, $value );
58 0           return $value;
59             }
60              
61             sub config_object {
62 0     0 0   $CONFIG_OBJECT;
63             }
64              
65             sub depend_object {
66 0     0 0   $DEPEND_OBJECT;
67             }
68              
69             sub has {
70 0     0 0   my $self = shift;
71 0           my ($command) = @_;
72              
73 0           return $self->depend_object->has($command);
74             }
75              
76             sub exists {
77 0     0 0   my $self = shift;
78 0           my ($command) = @_;
79              
80 0           return $self->depend_object->exists($command);
81             }
82              
83             sub version {
84 0     0 0   my $self = shift;
85 0           my ($command) = @_;
86              
87 0           return $self->depend_object->version($command);
88             }
89              
90 0 0   0 0   sub debug_level { $Video::DVDRip::DEBUG || shift->{debug_level} }
91              
92             sub set_debug_level {
93 0     0 0   my $thing = shift;
94 0           my $debug;
95 0 0         if ( ref $thing ) {
96 0 0         $thing->{debug_level} = shift if @_;
97 0           $debug = $thing->{debug_level};
98             }
99             else {
100 0 0         $Video::DVDRip::DEBUG = shift if @_;
101 0           $debug = $Video::DVDRip::DEBUG;
102             }
103              
104 0 0         if ($debug) {
105 0           $Video::DVDRip::DEBUG::TIME = scalar( localtime(time) );
106 0           print STDERR "--- START ------------------------------------\n",
107             "$$: $Video::DVDRip::DEBUG::TIME - DEBUG LEVEL $debug\n";
108             }
109              
110 0           return $debug;
111             }
112              
113             sub dump {
114 0     0 0   my $self = shift;
115 0 0         push @_, $self if not @_;
116              
117 0           my $dd = Data::Dumper->new( \@_ );
118 0           $dd->Indent(1);
119 0           print $dd->Dump;
120              
121 0           1;
122             }
123              
124             sub print_debug {
125 0     0 0   my $self = shift;
126              
127 0           my $debug = $Video::DVDRip::DEBUG;
128 0 0 0       $debug = $self->{debug_level} if ref $self and $self->{debug_level};
129              
130 0 0         if ($debug) {
131 0           print STDERR join( "\n", @_ ), "\n";
132             }
133              
134 0           1;
135             }
136              
137             sub system {
138 0     0 0   my $self = shift;
139 0           my %par = @_;
140 0           my ( $command, $err_ignore, $return_rc )
141             = @par{ 'command', 'err_ignore', 'return_rc' };
142              
143 0           $self->log("Executing command: $command");
144              
145 0           $self->print_debug("executing command: $command");
146              
147 0           my $catch = `($command) 2>&1`;
148 0           my $rc = $?;
149              
150 0           $self->print_debug("got: rc=$rc catch=$catch");
151              
152 0 0         croak "Error executing command $command:\n$catch" if $rc;
153              
154 0 0         return $return_rc ? $? : $catch;
155             }
156              
157             sub popen {
158 0     0 0   my $self = shift;
159 0           my %par = @_;
160 0           my ( $command, $callback ) = @par{ 'command', 'callback' };
161              
162 0 0         return $self->popen_with_callback(@_) if $callback;
163              
164 0           $self->print_debug("executing command: $command");
165 0           $self->log("Executing command: $command");
166              
167 0           my $fh = FileHandle->new;
168 0 0         open( $fh, "($command) 2>&1 |" )
169             or croak "can't fork $command";
170              
171 0           my $flags = '';
172 0 0         fcntl( $fh, F_GETFL, $flags )
173             or die "Can't get flags: $!\n";
174 0           $flags |= O_NONBLOCK;
175 0 0         fcntl( $fh, F_SETFL, $flags )
176             or die "Can't set flags: $!\n";
177              
178 0           return $fh;
179             }
180              
181             sub popen_with_callback {
182 0     0 0   my $self = shift;
183 0           my %par = @_;
184 0           my ( $command, $callback, $catch_output )
185             = @par{ 'command', 'callback', 'catch_output' };
186              
187 0           $self->print_debug("executing command: $command");
188 0           $self->log("Executing command: $command");
189              
190 0           my $fh = FileHandle->new;
191 0 0         open( $fh, "($command) 2>&1 |" )
192             or croak "can't fork $command";
193 0           select $fh;
194 0           $| = 1;
195 0           select STDOUT;
196 0 0         return $fh if not $callback;
197              
198 0           my ( $output, $buffer );
199 0           while ( read( $fh, $buffer, 512 ) ) {
200 0           &$callback($buffer);
201 0 0         $output .= $_ if $catch_output;
202             }
203              
204 0           close $fh;
205              
206 0           return $output;
207             }
208              
209             sub format_time {
210 0     0 0   my $self = shift;
211 0           my %par = @_;
212 0           my ($time) = @par{'time'};
213              
214 0           my ( $h, $m, $s );
215 0           $h = int( $time / 3600 );
216 0           $m = int( ( $time - $h * 3600 ) / 60 );
217 0           $s = $time % 60;
218              
219 0           return sprintf( "%02d:%02d:%02d", $h, $m, $s );
220             }
221              
222             sub stripped_exception {
223 0     0 0   my $text = $@;
224 0           $text =~ s/\s+at\s+[^\s]+\s+line\s+\d+\.?//;
225 0           $text =~ s/^msg:\s*//;
226 0           return $text;
227             }
228              
229             my $logger;
230              
231 0     0 0   sub logger {$logger}
232              
233             sub set_logger {
234 0     0 0   my $self = shift;
235 0           my ($set_logger) = @_;
236 0           return $logger = $set_logger;
237             }
238              
239             sub log {
240 0     0 0   shift;
241 0 0         return if not defined $logger;
242 0           $logger->log(@_);
243 0           1;
244             }
245              
246             sub clone {
247 0     0 0   my $self = shift;
248              
249 0           require Storable;
250 0           return Storable::dclone($self);
251             }
252              
253             sub combine_command_options {
254 0     0 0   my $self = shift;
255 0           my %par = @_;
256 0           my ( $cmd, $cmd_line, $options ) = @par{ 'cmd', 'cmd_line', 'options' };
257              
258             # split command line into separate commands
259 0           $cmd_line =~ s/\s+$//;
260 0 0         $cmd_line .= ";" if $cmd_line !~ /;$/;
261 0           my @parts = grep !/^$/,
262             ( $cmd_line
263             =~ m!(.*?)\s*(\(|\)|;|&&|\|\||\`which nice\`\s+-n\s+[\d-]+|execflow\s+(?:-n\s*\d+)?)\s*!g
264             );
265             # walk through and process requested command
266 0           foreach my $part (@parts) {
267 0 0         next if $part !~ s/^$cmd\s+//;
268 0           my $options_href
269             = $self->get_shell_options( options => $part . " " . $options );
270 0           $part = "$cmd " . join( " ", values %{$options_href} );
  0            
271             }
272              
273             # remove trailing semicolon
274 0           pop @parts;
275              
276             # join parts and return
277 0           $cmd = join( " ", @parts );
278              
279 0           return $cmd;
280             }
281              
282             sub get_shell_options {
283 0     0 0   my $self = shift;
284 0           my %par = @_;
285 0           my ($options) = @par{'options'};
286              
287 0           my %options;
288 0 0         my @words = map { /\s/ ? "'$_'" : $_ } $self->get_shell_words($options);
  0            
289              
290 0           my $opt;
291 0           for ( my $i = 0; $i < @words; ++$i ) {
292 0 0         $words[$i] = "'$words[$i]'" if $words[$i] =~ /\s/;
293 0 0         if ( $words[$i] =~ /^(-+\D.*)/ ) {
294              
295             # why \D? Answer: minus followed by a number is
296             # surley a value, no option.
297 0           $opt = $1;
298 0 0 0       if ( $i + 1 != @words and $words[ $i + 1 ] !~ /^-/ ) {
299 0           $options{$opt} = "$opt $words[$i+1]";
300 0           ++$i;
301             }
302             else {
303 0           $options{$opt} = "$opt";
304             }
305             }
306             else {
307 0           $options{$opt} .= " " . $words[$i];
308             }
309             }
310              
311 0           return \%options;
312             }
313              
314             # This subroutine is taken from "shellwords.pl" (standard Perl
315             # library) and slightly modified (mainly usage of lexical
316             # variables instead of globals).
317              
318             sub get_shell_words {
319 0     0 0   my $thing = shift;
320              
321 0 0         local ($_) = join( '', @_ ) if @_;
322              
323 0           my ( @words, $snippet, $field );
324              
325 0           s/^\s+//;
326 0           while ( $_ ne '' ) {
327 0           $field = '';
328 0           for ( ;; ) {
329 0 0         if (s/^"(([^"\\]|\\.)*)"//) {
    0          
    0          
    0          
    0          
    0          
330 0           ( $snippet = $1 ) =~ s#\\(.)#$1#g;
331             }
332             elsif (/^"/) {
333 0           die "Unmatched double quote: $_\n";
334             }
335             elsif (s/^'(([^'\\]|\\.)*)'//) {
336 0           ( $snippet = $1 ) =~ s#\\(.)#$1#g;
337             }
338             elsif (/^'/) {
339 0           die "Unmatched single quote: $_\n";
340             }
341             elsif (s/^\\(.)//) {
342 0           $snippet = $1;
343             }
344             elsif (s/^([^\s\\'"]+)//) {
345 0           $snippet = $1;
346             }
347             else {
348 0           s/^\s+//;
349 0           last;
350             }
351 0           $field .= $snippet;
352             }
353 0           push( @words, $field );
354             }
355              
356 0           return @words;
357             }
358              
359             sub apply_command_template {
360 0     0 0   my $self = shift;
361 0           my %par = @_;
362 0           my ( $template, $opts ) = @par{ 'template', 'opts' };
363              
364 0           $template =~ s/<(.*?)>/__DVDRIP_REPEATED_GROUP__/;
365 0           my ($group_tmpl) = "$1 ";
366              
367 0           my $opts_href = shift @{$opts};
  0            
368              
369 0           $template = $self->apply_template(
370             template => $template,
371             opts_href => $opts_href,
372             );
373              
374 0           my $group = "";
375              
376 0           foreach my $group_opts_href ( @{$opts} ) {
  0            
377 0           $opts_href->{$_} = $group_opts_href->{$_}
378 0           for keys %{$group_opts_href};
379 0           $group .= $self->apply_template(
380             template => $group_tmpl,
381             opts_href => $opts_href,
382             );
383             }
384              
385 0           $template =~ s/__DVDRIP_REPEATED_GROUP__/$group/;
386              
387 0           return $template;
388             }
389              
390             sub apply_template {
391 0     0 0   my $self = shift;
392 0           my %par = @_;
393 0           my ( $template, $opts_href ) = @par{ 'template', 'opts_href' };
394              
395 0           $template =~ s{\%(\(.*?\)|.)}{
396 0           my $var = $1;
397 0 0         if ( $var =~ s/^\((.*)\)$/$1/ ) {
398 0           $var =~ s/\%(.)/$opts_href->{$1}/g;
399 0           my $eval = $var;
400 0           $var = eval $eval;
401 0 0         if ( $@ ) {
402 0           my $err = $@;
403 0           $err =~ s/at\s+\(.*//;
404 0           warn "Perl expression ( $eval ) => $err";
405             }
406             } else {
407 0           $var = $opts_href->{$var};
408             }
409 0           $var;
410             }eg;
411              
412 0           return $template;
413             }
414              
415             sub search_perl_inc {
416 0     0 0   my $self = shift;
417 0           my %par = @_;
418 0           my ($rel_path) = @par{'rel_path'};
419              
420 0           my $file;
421              
422 0           foreach my $INC (@INC) {
423 0           $file = "$INC/$rel_path";
424 0 0         last if -e $file;
425 0           $file = "";
426             }
427              
428 0           return $file;
429             }
430              
431             1;