]> git.donarmstrong.com Git - bin.git/blob - rip_movie
add mutt alias which executes neomutt if that exists
[bin.git] / rip_movie
1 #! /usr/bin/perl
2 # rip_movie uses HandBrakeCLI to rip movies, and is released
3 # under the terms of the GPL version 2, or any later version, at your
4 # option. See the file README and COPYING for more information.
5 # Copyright 2011 by Don Armstrong <don@donarmstrong.com>.
6 # $Id: perl_script 1432 2009-04-21 02:42:41Z don $
7
8
9 use warnings;
10 use strict;
11
12 use Getopt::Long;
13 use Pod::Usage;
14
15 =head1 NAME
16
17 rip_movie - Rips Movies using HandBrakeCLI
18
19 =head1 SYNOPSIS
20
21  rip_movie
22
23  Options:
24   --device Device to rip from (default /dev/dvd)
25   --output Output filename
26   --min-duration Minimum duration in minutes for episode
27   --titles Optional titles to rip; overrides title autodetection
28   --debug, -d debugging level (Default 0)
29   --help, -h display this help
30   --man, -m display manual
31
32 =head1 OPTIONS
33
34 =over
35
36 =item B<--device>
37
38 Device to rip from (default /dev/dvd)
39
40 =item B<--output>
41
42 Override the output filename
43
44 =item B<--min-duration>
45
46 Minimum duration in minutes for a track to be considered an episode
47 (Default 25 minutes)
48
49 =item B<--titles>
50
51 Optional titles to rip; overrides title autodetection
52
53 =item B<--debug, -d>
54
55 Debug verbosity. (Default 0)
56
57 =item B<--help, -h>
58
59 Display brief usage information.
60
61 =item B<--man, -m>
62
63 Display this manual.
64
65 =back
66
67 =head1 EXAMPLES
68
69 rip_movie
70
71 =cut
72
73 use List::Util qw(reduce);
74
75 use vars qw($DEBUG);
76
77 my %options = (debug           => 0,
78                help            => 0,
79                man             => 0,
80                min_duration    => 25,
81                device          => '/dev/dvd',
82                );
83
84 GetOptions(\%options,
85            'titles|title|t=i@',
86            'device|D=s',
87            'min_duration|min-duration=i',
88            'debug|d+','help|h|?','man|m');
89
90 pod2usage() if $options{help};
91 pod2usage({verbose=>2}) if $options{man};
92
93 $DEBUG = $options{debug};
94
95 my @titles_to_rip;
96
97 my @USAGE_ERRORS;
98 if (exists $options{min_duration}) {
99     $options{min_duration}*=60;
100 }
101 if (exists $options{titles}) {
102     for my $title (@{$options{titles}}) {
103         if ($title < 1) {
104             push @USAGE_ERRORS,"Title '$title' is not a valid title; must be greater than zero.";
105         }
106         push @titles_to_rip,$title;
107     }
108 }
109
110 pod2usage(join("\n",@USAGE_ERRORS)) if @USAGE_ERRORS;
111
112
113 my $result = qx(HandBrakeCLI -i $options{device} -t 0 -o /dev/null 2>&1);
114
115 #print STDERR $result;
116 my ($title) = $result =~ /^libdvdnav:\s+DVD\s+Title:\s+(.+)/im;
117 die "no title" if not defined $title;
118 my $filename = lc($title);
119 $filename =~ s/[\s_-]+/_/;
120
121 use Data::Printer;
122
123 my @titles;
124 for my $title_bit ($result =~ /\n(\+ title \d+:.+?)(?=\n\+ title\s+|$)/gs) {
125     my %title;
126     # title number
127 #    $title{bit} = $title_bit;
128     $title_bit =~ /^\+ title (\d+):/;
129     $title{num} = $1;
130     my ($duration) = $title_bit =~ /^\s+\+\s+duration:\s+([\d:]+)$/m;
131     # HH:MM:SS, so (HH*60 + MM) * 60 + SS
132     $duration = reduce {defined $a and defined $b ? $a * 60 + $b : undef } split /:/, $duration;
133     $title{duration} = $duration;
134     # figure out audio tracks
135 #    use re qw(debug);
136     $title_bit =~ /(?<leadspace>\ +)\+\ +audio\ +tracks:\s*\n # audio track header
137                    (?<audiotracks>(?:\g{leadspace}\ +\+\ +\d+\,.+\n){0,}) # audio track information
138                   /x;
139     my $at_info = $+{audiotracks};
140 #    $title{at_info} = $at_info;
141     my @at_nums = $at_info =~ /^\s+\+\s+(\d+)\,/mg if defined $at_info;
142     $title{audio_tracks} = [@at_nums];
143     # figure out subtitle tracks
144     $title_bit =~ /(?<leadspace>\ +)\+\ +subtitle\ +tracks:\s*\n # subtitle track header
145                    (?<subtittracks>(?:\g{leadspace}\ +\+\ +\d+\,.+(?:\n|$)){0,}) # subtitle track information
146                   /x;
147     my $st_info = $+{subtittracks};
148 #    $title{st_info} = $st_info;
149     my @st_nums = $st_info =~ /^\s+\+\s+(\d+)\,/mg if defined $st_info;
150     $title{subtitle_tracks} = [@st_nums];
151     $title{pos_num} = @titles;
152     push @titles,\%title;
153 }
154
155 # p @titles;
156
157 #print STDERR Dumper(\@titles);
158
159
160 if (not @titles_to_rip) {
161     my $longest_title;
162     for my $i (0..$#titles) {
163         my $title = $titles[$i];
164         if (not defined $longest_title or
165             $title->{duration} > $titles[$longest_title]{duration}) {
166             $longest_title = $i;
167         }
168         if ($title->{duration} >= $options{min_duration}) {
169             push @titles_to_rip,$i+1;
170         }
171     }
172     if (not @titles_to_rip) {
173         push @titles_to_rip,$longest_title+1;
174     }
175 }
176 # p @titles_to_rip;
177 my $invalid_titles = 0;
178 for my $i (@titles_to_rip) {
179     if ($i > @titles or $i < 1) {
180         print STDERR "Invalid title $i\n";
181         $invalid_titles = 1;
182     }
183 }
184 exit 1 if $invalid_titles;
185
186 my $multiple_titles = @titles_to_rip > 1;
187
188 #print STDERR Dumper(\@titles_to_rip,[@titles[map {$_} @titles_to_rip]]);
189 #exit;
190
191 p @titles_to_rip;
192 p @titles;
193
194 for my $i (@titles_to_rip) {
195     system('HandBrakeCLI','-i',$options{device},'-t',$titles[$i-1]{num},
196            '-o',$filename.($multiple_titles ? '_'.$titles[$i-1]{num} : '').".mkv",
197            '-e','x264','-2','-q','21',
198            '-a',join(',',@{$titles[$i-1]{audio_tracks}}),
199            '-s',join(',',@{$titles[$i-1]{subtitle_tracks}}),
200           );
201 }
202
203
204
205
206
207 __END__