File Coverage

blib/lib/App/MP4Meta/TV.pm
Criterion Covered Total %
statement 28 83 33.7
branch 0 26 0.0
condition 1 42 2.3
subroutine 10 12 83.3
pod 2 2 100.0
total 41 165 24.8


line stmt bran cond sub pod time code
1 1     1   2956 use 5.010;
  1         4  
2 1     1   6 use strict;
  1         1  
  1         20  
3 1     1   5 use warnings;
  1         1  
  1         51  
4              
5             package App::MP4Meta::TV;
6             {
7             $App::MP4Meta::TV::VERSION = '1.153340';
8             }
9              
10             # ABSTRACT: Add metadata to a TV Series
11              
12 1     1   5 use App::MP4Meta::Base;
  1         2  
  1         44  
13             our @ISA = 'App::MP4Meta::Base';
14              
15 1     1   5 use File::Spec '3.33';
  1         2  
  1         18  
16 1     1   6 use AtomicParsley::Command::Tags;
  1         1  
  1         7  
17              
18 1     1   26 use App::MP4Meta::Source::Data::TVEpisode;
  1         2  
  1         10  
19              
20             # a list of regexes to try to parse the file
21             my @file_regexes = (
22             qr/^S(?\d)-E(?\d)\s+-\s+(?.*)$/,
23             qr/^S(?\d)-E(?\d)\s*-\s*E(?\d)\s+-\s+(?.*)$/,
24             qr/^(?.*)\s+S(?\d\d)(\s|)E(?\d\d)$/,
25             qr/^(?.*)\s+S(?\d\d)(\s|)E(?\d\d)\s*-\s*E(?\d\d)$/,
26             qr/^(?.*)\.S(?\d\d)E(?\d\d)/i,
27             qr/^(?.*)\.S(?\d\d)E(?\d\d)\s*-\s*E(?\d\d)/i,
28             qr/^(?.*)\s*-?\s*S(?\d\d?)E(?\d\d?)/i,
29             qr/^(?.*)\s*-?\s*S(?\d\d?)E(?\d\d?)\s*-\s*E(?\d\d)/i,
30             qr/^(?.*)-S(?\d\d?)E(?\d\d?)/,
31             qr/^(?.*)-S(?\d\d?)E(?\d\d?)\s*-\s*E(?\d\d)/,
32             qr/^(?.*)-S(?\d\d?)E(?\d\d?)/i,
33             qr/^(?.*)-S(?\d\d?)E(?\d\d?)\s*-\s*E(?\d\d)/i,
34             qr/S(?\d\d?)E(?\d\d?)/i,
35             qr/S(?\d\d?)E(?\d\d?)\s*-\s*E(?\d\d?)/i,
36             qr/^(?.*)\s*-?\s*(?\d\d?)x(?\d\d?)/,
37             );
38              
39             sub new {
40 4     4 1 9234 my $class = shift;
41 4         9 my $args = shift;
42              
43 4         28 my $self = $class->SUPER::new($args);
44              
45             # args for skipping
46 0         0 $self->{'continue_without_any'} = $args->{'continue_without_any'};
47 0         0 $self->{'continue_without_overview'} = $args->{'continue_without_overview'};
48 0         0 $self->{'continue_without_genre'} = $args->{'continue_without_genre'};
49 0         0 $self->{'continue_without_year'} = $args->{'continue_without_year'};
50 0         0 $self->{'continue_without_cover'} = $args->{'continue_without_cover'};
51              
52             # attributes
53 0         0 $self->{'season'} = $args->{'season'};
54 0         0 $self->{'episode'} = $args->{'episode'};
55 0         0 $self->{'overview'} = $args->{'overview'};
56 0         0 $self->{'year'} = $args->{'year'};
57 0         0 $self->{'cover'} = $args->{'cover'};
58              
59             # we are a TV Show
60 0         0 $self->{'media_type'} = 'TV Show';
61              
62 0         0 return $self;
63             }
64              
65             sub apply_meta {
66 0     0 1 0 my ( $self, $path ) = @_;
67             my %tags = (
68             show_title => $self->{'title'},
69             season => $self->{'season'},
70 0         0 episode => $self->{'episode'},
71             );
72              
73             # get the file name
74 0         0 my ( $volume, $directories, $file ) = File::Spec->splitpath($path);
75              
76 0 0 0     0 unless ( $tags{show_title} && $tags{season} && $tags{episode} ) {
      0        
77              
78             # parse the filename for the title, season and episode
79 0         0 ( $tags{show_title}, $tags{season}, $tags{episode} ) =
80             $self->_parse_filename($file, $directories);
81 0 0 0     0 unless ( $tags{show_title} && $tags{season} && $tags{episode} ) {
      0        
82 0         0 return "Error: could not parse the filename for $path";
83             }
84             }
85              
86             my $episode = App::MP4Meta::Source::Data::TVEpisode->new(
87             genre => $self->{'genre'},
88             cover => $self->{'cover'},
89             overview => $self->{'overview'},
90 0         0 year => $self->{'year'},
91             );
92 0 0       0 unless ( _episode_is_complete($episode) ) {
93 0         0 for my $source ( @{ $self->{'sources_objects'} } ) {
  0         0  
94             say sprintf( "trying source '%s'", $source->name )
95 0 0       0 if $self->{verbose};
96              
97             # merge new epiosde into previous
98 0         0 $episode->merge( $source->get_tv_episode( \%tags ) );
99              
100             # last if we have everything
101             last
102 0 0       0 if ( _episode_is_complete($episode) );
103             }
104             }
105              
106             # check what we have
107 0 0       0 unless ( $episode->overview ) {
108 0 0 0     0 if ( $self->{'continue_without_any'}
109             || $self->{'continue_without_overview'} )
110             {
111 0         0 say 'no overview found; continuing';
112             }
113             else {
114             return sprintf( 'no overview found for %s, season %d, episode %d',
115 0         0 $tags{show_title}, $tags{season}, $tags{episode} );
116             }
117             }
118              
119 0   0     0 my $show_title = $episode->show_title // $tags{show_title};
120             my $apTags = AtomicParsley::Command::Tags->new(
121             artist => $show_title,
122             albumArtist => $show_title,
123             title => $episode->title,
124             album => sprintf( "%s, Season %s", $show_title, $tags{season} ),
125             tracknum => $tags{episode},
126             TVShowName => $show_title,
127             TVEpisode => $tags{episode},
128             TVEpisodeNum => $tags{episode},
129             TVSeasonNum => $tags{season},
130 0         0 stik => $self->{'media_type'},
131             description => $episode->overview,
132             longdesc => $episode->overview,
133             genre => $episode->genre,
134             year => $episode->year,
135             artwork => $episode->cover
136             );
137              
138 0 0       0 say 'writing tags' if $self->{verbose};
139 0         0 my $error = $self->_write_tags( $path, $apTags );
140 0 0       0 return $error if $error;
141              
142 0         0 return $self->_add_to_itunes( File::Spec->rel2abs($path) );
143             }
144              
145             # Parse the filename in order to get the series title the and season and episode number.
146             sub _parse_filename {
147 0     0   0 my ( $self, $file, $directories ) = @_;
148              
149 0         0 my $show = '';
150 0         0 my $season = '';
151 0         0 my $episode = '';
152              
153             # strip suffix
154 0         0 $file = $self->_strip_suffix($file);
155              
156             # see if we have a regex that matches
157 0         0 for my $r (@file_regexes) {
158 0 0       0 if ( $file =~ $r ) {
159 1   0 1   1946 $show = $self->{title} // $+{show};
  1         432  
  1         247  
  0         0  
160 0   0     0 $season = $self->{season} // $+{season};
161 0   0     0 $episode = $self->{episode} // $+{episode};
162              
163 0 0 0     0 if ( $show && $season && $episode ) {
      0        
164              
165 0         0 return ( $self->_clean_title($show), int $season,
166             int $episode );
167             }
168             }
169             }
170              
171 0 0       0 if ( $directories )
172             {
173             #-- remove Season N
174 0         0 $directories =~ s{/season\s+(\d+)$/?}{}i;
175 0         0 my @parts = (split /\//, $directories);
176 0         0 $show = $parts[$#parts];
177             }
178            
179 0 0 0     0 if ( $show && $season && $episode ) {
      0        
180 0         0 return ( $self->_clean_title($show), int $season, int $episode );
181             }
182 0         0 return;
183             }
184              
185             # true if we have all we need in an episode
186             sub _episode_is_complete {
187 2     2   4970 my $episode = shift;
188 2   33     133 return ( $episode->overview
189             && $episode->genre
190             && $episode->year
191             && $episode->cover );
192             }
193              
194             1;
195              
196             __END__