Various improvements to dcpomatic_kdm.
[dcpomatic.git] / src / tools / dcpomatic_kdm.cc
1 /*
2     Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include <getopt.h>
21 #include <libdcp/certificates.h>
22 #include "lib/film.h"
23 #include "lib/cinema.h"
24 #include "lib/kdm.h"
25 #include "lib/config.h"
26 #include "lib/exceptions.h"
27
28 using std::string;
29 using std::cout;
30 using std::cerr;
31 using std::list;
32 using boost::shared_ptr;
33
34 static void
35 help (string n)
36 {
37         cerr << "Syntax: " << n << " [OPTION] [<FILM>]\n"
38              << "  -h, --help        show this help\n"
39              << "  -o, --output      output file or directory\n"
40              << "  -f, --valid-from  valid from time (e.g. \"2013-09-28 01:41:51\")\n"
41              << "  -t, --valid-to    valid to time (e.g. \"2014-09-28 01:41:51\")\n"
42              << "  -c, --certificate file containing projector certificate\n"
43              << "  -z, --zip         ZIP each cinema's KDMs into its own file\n"
44              << "      --cinema      specify a cinema, either by name or email address\n"
45              << "      --cinemas     list known cinemas from the DCP-o-matic settings\n";
46 }
47
48 int main (int argc, char* argv[])
49 {
50         boost::filesystem::path output;
51         boost::posix_time::ptime valid_from;
52         boost::posix_time::ptime valid_to;
53         string certificate_file;
54         bool zip = false;
55         string cinema_name;
56         bool cinemas = false;
57         
58         int option_index = 0;
59         while (1) {
60                 static struct option long_options[] = {
61                         { "help", no_argument, 0, 'h'},
62                         { "output", required_argument, 0, 'o'},
63                         { "valid-from", required_argument, 0, 'f'},
64                         { "valid-to", required_argument, 0, 't'},
65                         { "certificate", required_argument, 0, 'c' },
66                         { "cinema", required_argument, 0, 'A' },
67                         { "cinemas", no_argument, 0, 'B' },
68                         { "zip", no_argument, 0, 'z' },
69                         { 0, 0, 0, 0 }
70                 };
71
72                 int c = getopt_long (argc, argv, "ho:f:t:c:A:Bz", long_options, &option_index);
73
74                 if (c == -1) {
75                         break;
76                 }
77
78                 switch (c) {
79                 case 'h':
80                         help (argv[0]);
81                         exit (EXIT_SUCCESS);
82                 case 'o':
83                         output = optarg;
84                         break;
85                 case 'f':
86                         valid_from = boost::posix_time::time_from_string (optarg);
87                         break;
88                 case 't':
89                         valid_to = boost::posix_time::time_from_string (optarg);
90                         break;
91                 case 'c':
92                         certificate_file = optarg;
93                         break;
94                 case 'A':
95                         cinema_name = optarg;
96                         break;
97                 case 'B':
98                         cinemas = true;
99                         break;
100                 case 'z':
101                         zip = true;
102                         break;
103                 }
104         }
105
106         if (cinemas) {
107                 list<boost::shared_ptr<Cinema> > cinemas = Config::instance()->cinemas ();
108                 for (list<boost::shared_ptr<Cinema> >::const_iterator i = cinemas.begin(); i != cinemas.end(); ++i) {
109                         cout << (*i)->name << " (" << (*i)->email << ")\n";
110                 }
111                 exit (EXIT_SUCCESS);
112         }
113
114         if (optind >= argc) {
115                 help (argv[0]);
116                 exit (EXIT_FAILURE);
117         }
118
119         if (cinema_name.empty() && certificate_file.empty()) {
120                 cerr << argv[0] << ": you must specify either a cinema, a screen or a certificate file\n";
121                 exit (EXIT_FAILURE);
122         }
123
124         string const film_dir = argv[optind];
125                         
126         dcpomatic_setup ();
127
128         shared_ptr<Film> film;
129         try {
130                 film.reset (new Film (film_dir));
131                 film->read_metadata ();
132         } catch (std::exception& e) {
133                 cerr << argv[0] << ": error reading film `" << film_dir << "' (" << e.what() << ")\n";
134                 exit (EXIT_FAILURE);
135         }
136
137         if (cinema_name.empty ()) {
138                 shared_ptr<libdcp::Certificate> certificate (new libdcp::Certificate (boost::filesystem::path (certificate_file)));
139                 libdcp::KDM kdm = film->make_kdm (certificate, valid_from, valid_to);
140                 kdm.as_xml (output);
141         } else {
142
143                 list<shared_ptr<Cinema> > cinemas = Config::instance()->cinemas ();
144                 list<shared_ptr<Cinema> >::const_iterator i = cinemas.begin();
145                 while (i != cinemas.end() && (*i)->name != cinema_name && (*i)->email != cinema_name) {
146                         ++i;
147                 }
148
149                 if (i == cinemas.end ()) {
150                         cerr << argv[0] << ": could not find cinema \"" << cinema_name << "\"\n";
151                         exit (EXIT_FAILURE);
152                 }
153
154                 try {
155                         if (zip) {
156                                 write_kdm_zip_files (film, (*i)->screens(), valid_from, valid_to, output);
157                         } else {
158                                 write_kdm_files (film, (*i)->screens(), valid_from, valid_to, output);
159                         }
160                 } catch (FileError& e) {
161                         cerr << argv[0] << ": " << e.what() << " (" << e.file().string() << ")\n";
162                         exit (EXIT_FAILURE);
163                 }
164         }
165
166         return 0;
167 }