File Coverage

blib/lib/AtomicParsley/Command.pm
Criterion Covered Total %
statement 26 141 18.4
branch 1 10 10.0
condition 1 7 14.2
subroutine 8 14 57.1
pod 3 3 100.0
total 39 175 22.2


line stmt bran cond sub pod time code
1 1     1   655 use 5.010;
  1         4  
  1         35  
2 1     1   5 use strict;
  1         2  
  1         28  
3 1     1   5 use warnings;
  1         2  
  1         50  
4              
5             package AtomicParsley::Command;
6             {
7             $AtomicParsley::Command::VERSION = '1.130420';
8             }
9              
10             # ABSTRACT: Interface to the Atomic Parsley command
11              
12 1     1   5 use AtomicParsley::Command::Tags;
  1         2  
  1         5  
13 1     1   1453 use IPC::Cmd '0.76', ();
  1         84804  
  1         158  
14 1     1   25 use File::Spec '3.33';
  1         1  
  1         20  
15 1     1   6 use File::Copy;
  1         2  
  1         7832  
16              
17             sub new {
18 1     1 1 954 my $class = shift;
19 1         3 my $args = shift;
20 1         3 my $self = {};
21              
22             # the path to AtomicParsley
23 1   50     10 my $ap = $args->{'ap'} // 'AtomicParsley';
24 1 50       7 $self->{'ap'} = IPC::Cmd::can_run($ap) or die "Can not run $ap";
25 0   0       $self->{'verbose'} = $args->{'verbose'} // 0;
26              
27 0           $self->{'success'} = undef;
28 0           $self->{'error_message'} = undef;
29 0           $self->{'full_buf'} = undef;
30 0           $self->{'stdout_buf'} = undef;
31 0           $self->{'stderr_buf'} = undef;
32              
33 0           bless( $self, $class );
34 0           return $self;
35             }
36              
37             sub read_tags {
38 0     0 1   my ( $self, $path ) = @_;
39              
40 0           $path = File::Spec->rel2abs($path);
41 0           my ( $volume, $directories, $file ) = File::Spec->splitpath($path);
42              
43 0           my $cmd = [ $self->{ap}, $path, '-t' ];
44              
45             # run the command
46 0           $self->_run($cmd);
47              
48             # parse the output and create new AtomicParsley::Command::Tags object
49 0           my $tags = $self->_parse_tags( $self->{'stdout_buf'}[0] );
50              
51             # $tags
52 0           return $tags;
53             }
54              
55             sub write_tags {
56 0     0 1   my ( $self, $path, $tags, $replace ) = @_;
57              
58 0           my ( $volume, $directories, $file ) = File::Spec->splitpath($path);
59              
60 0           my $cmd = [ $self->{ap}, $path, $tags->prepare ];
61              
62             # run the command
63 0           $self->_run($cmd);
64              
65             # return the temp file
66 0           my $tempfile = $self->_get_temp_file( $directories, $file );
67              
68 0 0         if ($replace) {
69              
70             # move
71 0           move( $tempfile, $path );
72 0           return $path;
73             }
74             else {
75 0           return $tempfile;
76             }
77             }
78              
79             # Run the command
80             sub _run {
81 0     0     my ( $self, $cmd ) = @_;
82              
83 0           local $IPC::Cmd::ALLOW_NULL_ARGS = 1;
84              
85 0           my ( $success, $error_message, $full_buf, $stdout_buf, $stderr_buf ) =
86             IPC::Cmd::run( command => $cmd, verbose => $self->{'verbose'} );
87              
88 0           $self->{'success'} = $success;
89 0           $self->{'error_message'} = $error_message;
90 0           $self->{'full_buf'} = $full_buf;
91 0           $self->{'stdout_buf'} = $stdout_buf;
92 0           $self->{'stderr_buf'} = $stderr_buf;
93             }
94              
95             # Parse the tags from AtomicParsley's output.
96             # Returns a new AtomicParsley::Command::Tags object
97             sub _parse_tags {
98 0     0     my ( $self, $output ) = @_;
99              
100 0           my %tags;
101             my $intag;
102 0           for my $line ( split( /\n/, $output ) ) {
103 0 0 0       if ( $line =~ /^Atom \"(.+)\" contains: (.*)$/ ) {
    0          
104 0           my $key = $1;
105 0           my $value = $2;
106              
107 0           given ($key) {
108 0           when (/alb$/) {
109 0           $tags{'album'} = $value;
110             }
111 0           when ('aART') {
112 0           $tags{'albumArtist'} = $value;
113             }
114 0           when (/ART$/) {
115 0           $tags{'artist'} = $value;
116             }
117 0           when ('catg') {
118 0           $tags{'category'} = $value;
119             }
120 0           when (/cmt$/) {
121 0           my $tag = 'comment';
122 0           $intag = $tag;
123 0           $tags{$tag} = $value;
124             }
125 0           when ('cpil') {
126 0           $tags{'compilation'} = $value;
127             }
128 0           when ('cprt') {
129 0           my $tag = 'copyright';
130 0           $intag = $tag;
131 0           $tags{$tag} = $value;
132             }
133 0           when (/day$/) {
134 0           $tags{'year'} = $value;
135             }
136 0           when ('desc') {
137 0           my $tag = 'description';
138 0           $intag = $tag;
139 0           $tags{$tag} = $value;
140             }
141 0           when ('ldes') {
142 0           my $tag = 'longdesc';
143 0           $intag = $tag;
144 0           $tags{$tag} = $value;
145             }
146 0           when ('disk') {
147 0           $value =~ s/ of /\//;
148 0           $tags{'disk'} = $value;
149             }
150 0           when (/ge?n(|re)$/) {
151 0           $tags{'genre'} = $value;
152             }
153 0           when (/grp$/) {
154 0           $tags{'grouping'} = $value;
155             }
156 0           when ('keyw') {
157 0           $tags{'keyword'} = $value;
158             }
159 0           when (/lyr$/) {
160 0           $tags{'lyrics'} = $value;
161             }
162 0           when (/nam$/) {
163 0           $tags{'title'} = $value;
164             }
165 0           when ('rtng') {
166 0           $tags{'advisory'} = _get_advisory_value($value);
167             }
168 0           when ('stik') {
169 0           $tags{'stik'} = $value;
170             }
171 0           when ('tmpo') {
172 0           $tags{'bpm'} = $value;
173             }
174 0           when ('trkn') {
175 0           $value =~ s/ of /\//;
176 0           $tags{'tracknum'} = $value;
177             }
178 0           when ('tven') {
179 0           $tags{'TVEpisode'} = $value;
180             }
181 0           when ('tves') {
182 0           $tags{'TVEpisodeNum'} = $value;
183             }
184 0           when ('tvsh') {
185 0           $tags{'TVShowName'} = $value;
186             }
187 0           when ('tvnn') {
188 0           $tags{'TVNetwork'} = $value;
189             }
190 0           when ('tvsn') {
191 0           $tags{'TVSeasonNum'} = $value;
192             }
193 0           when (/too$/) {
194 0           $tags{'encodingTool'} = $value;
195             }
196 0           when (/wrt$/) {
197 0           $tags{'composer'} = $value;
198             }
199             }
200             }
201             elsif ( $intag && defined $tags{$intag} ) {
202 0           $tags{$intag} .= "\n$line";
203             }
204             }
205              
206 0           return AtomicParsley::Command::Tags->new(%tags);
207             }
208              
209             # Try our best to get the name of the temp file.
210             # Unfortunately. the temp file contains a random number,
211             # so this is a best guess.
212             sub _get_temp_file {
213 0     0     my ( $self, $directories, $file ) = @_;
214              
215             # remove suffix
216 0           $file =~ s/(\.\w+)$/-temp-/;
217 0           my $suffix = $1;
218              
219             # search directory
220 0           for my $tempfile ( glob("$directories*$suffix") ) {
221              
222             # return the first match
223 0 0         if ( $tempfile =~ /^$directories$file.*$suffix$/ ) {
224 0           return $tempfile;
225             }
226             }
227             }
228              
229             # Get the advisory value of an mp4 file, if present.
230             sub _get_advisory_value {
231 0     0     my $advisory = shift;
232              
233             # TODO: check all values
234 0           given ($advisory) {
235 0           when ('Clean Content') {
236 0           return 'clean';
237             }
238             }
239             }
240              
241             1;
242              
243              
244             __END__