X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Ftools%2Fdcpomatic_kdm_cli.cc;h=364835f07401b536d6a2dab441227328f002ecbf;hb=e0932b9de21dcac6d88117437ff19b79d25ac64e;hp=bc7dd60c66b0d5e329a89d3edca8ea93d0714ede;hpb=b36153cbd3e1aae4c6fda35625d5c91ea8b6d29e;p=dcpomatic.git diff --git a/src/tools/dcpomatic_kdm_cli.cc b/src/tools/dcpomatic_kdm_cli.cc index bc7dd60c6..364835f07 100644 --- a/src/tools/dcpomatic_kdm_cli.cc +++ b/src/tools/dcpomatic_kdm_cli.cc @@ -29,7 +29,11 @@ #include "lib/config.h" #include "lib/exceptions.h" #include "lib/emailer.h" +#include "lib/dkdm_wrapper.h" +#include "lib/screen.h" #include +#include +#include #include #include @@ -41,11 +45,12 @@ using std::vector; using boost::shared_ptr; using boost::optional; using boost::bind; +using boost::dynamic_pointer_cast; static void help () { - cerr << "Syntax: " << program_name << " [OPTION] []\n" + cerr << "Syntax: " << program_name << " [OPTION] \n" " -h, --help show this help\n" " -o, --output output file or directory\n" " -f, --valid-from valid from time (in local time zone of the cinema) (e.g. \"2013-09-28 01:41:51\") or \"now\"\n" @@ -55,8 +60,10 @@ help () " -z, --zip ZIP each cinema's KDMs into its own file\n" " -v, --verbose be verbose\n" " -c, --cinema specify a cinema, either by name or email address\n" + " --certificate file containing projector certificate\n" " --cinemas list known cinemas from the DCP-o-matic settings\n" - " --certificate file containing projector certificate\n\n" + " --dkdm-cpls list CPLs for which DCP-o-matic has DKDMs\n\n" + "CPL-ID must be the ID of a CPL that is mentioned in DCP-o-matic's DKDM list.\n\n" "For example:\n\n" "Create KDMs for my_great_movie to play in all of Fred's Cinema's screens for the next two weeks and zip them up.\n" "(Fred's Cinema must have been set up in DCP-o-matic's KDM window)\n\n" @@ -162,15 +169,251 @@ find_cinema (string cinema_name) return *i; } +void +from_film ( + boost::filesystem::path film_dir, + bool verbose, + optional cinema_name, + optional output, + optional certificate_file, + boost::posix_time::ptime valid_from, + boost::posix_time::ptime valid_to, + dcp::Formulation formulation, + bool zip + ) +{ + shared_ptr film; + try { + film.reset (new Film (film_dir)); + film->read_metadata (); + if (verbose) { + cout << "Read film " << film->name () << "\n"; + } + } catch (std::exception& e) { + cerr << program_name << ": error reading film `" << film_dir.string() << "' (" << e.what() << ")\n"; + exit (EXIT_FAILURE); + } + + /* XXX: allow specification of this */ + vector cpls = film->cpls (); + if (cpls.empty ()) { + error ("no CPLs found in film"); + } else if (cpls.size() > 1) { + error ("more than one CPL found in film"); + } + + boost::filesystem::path cpl = cpls.front().cpl_file; + + if (!cinema_name) { + + if (!output) { + error ("you must specify --output"); + } + + dcp::Certificate certificate (dcp::file_to_string (*certificate_file)); + dcp::EncryptedKDM kdm = film->make_kdm ( + certificate, vector(), cpl, dcp::LocalTime (valid_from), dcp::LocalTime (valid_to), formulation + ); + kdm.as_xml (*output); + if (verbose) { + cout << "Generated KDM " << *output << " for certificate.\n"; + } + } else { + + if (!output) { + output = "."; + } + + dcp::NameFormat::Map values; + values['f'] = film->name(); + values['b'] = dcp::LocalTime(valid_from).date() + " " + dcp::LocalTime(valid_from).time_of_day(true, false); + values['e'] = dcp::LocalTime(valid_to).date() + " " + dcp::LocalTime(valid_to).time_of_day(true, false); + + try { + list screen_kdms = film->make_kdms ( + find_cinema(*cinema_name)->screens(), cpl, valid_from, valid_to, formulation + ); + + write_files (screen_kdms, zip, *output, values, verbose); + } catch (FileError& e) { + cerr << program_name << ": " << e.what() << " (" << e.file().string() << ")\n"; + exit (EXIT_FAILURE); + } catch (KDMError& e) { + cerr << program_name << ": " << e.what() << "\n"; + exit (EXIT_FAILURE); + } + } +} + +optional +sub_find_dkdm (shared_ptr group, string cpl_id) +{ + BOOST_FOREACH (shared_ptr i, group->children()) { + shared_ptr g = dynamic_pointer_cast(i); + if (g) { + optional dkdm = sub_find_dkdm (g, cpl_id); + if (dkdm) { + return dkdm; + } + } else { + shared_ptr d = dynamic_pointer_cast(i); + assert (d); + if (d->dkdm().cpl_id() == cpl_id) { + return d->dkdm(); + } + } + } + + return optional(); +} + +optional +find_dkdm (string cpl_id) +{ + return sub_find_dkdm (Config::instance()->dkdms(), cpl_id); +} + +dcp::EncryptedKDM +kdm_from_dkdm ( + dcp::EncryptedKDM dkdm, + dcp::Certificate target, + vector trusted_devices, + dcp::LocalTime valid_from, + dcp::LocalTime valid_to, + dcp::Formulation formulation + ) +{ + /* Decrypted DKDM */ + dcp::DecryptedKDM decrypted_dkdm (dkdm, Config::instance()->decryption_chain()->key().get()); + + /* Signer for new KDM */ + shared_ptr signer = Config::instance()->signer_chain (); + if (!signer->valid ()) { + error ("signing certificate chain is invalid."); + } + + /* Make a new empty KDM and add the keys from the DKDM to it */ + dcp::DecryptedKDM kdm ( + valid_from, + valid_to, + dkdm.annotation_text().get_value_or(""), + dkdm.content_title_text(), + dcp::LocalTime().as_string() + ); + + BOOST_FOREACH (dcp::DecryptedKDMKey const & j, decrypted_dkdm.keys()) { + kdm.add_key(j); + } + + return kdm.encrypt (signer, target, trusted_devices, formulation, true, 0); +} + +void +from_dkdm ( + dcp::EncryptedKDM dkdm, + bool verbose, + optional cinema_name, + optional output, + optional certificate_file, + boost::posix_time::ptime valid_from, + boost::posix_time::ptime valid_to, + dcp::Formulation formulation, + bool zip + ) +{ + if (!cinema_name) { + if (!output) { + error ("you must specify --output"); + } + + dcp::EncryptedKDM kdm = kdm_from_dkdm ( + dkdm, + dcp::Certificate (dcp::file_to_string (*certificate_file)), + vector(), + dcp::LocalTime(valid_from), dcp::LocalTime(valid_to), + formulation + ); + + kdm.as_xml (*output); + if (verbose) { + cout << "Generated KDM " << *output << " for certificate.\n"; + } + } else { + + if (!output) { + output = "."; + } + + dcp::NameFormat::Map values; + values['f'] = dkdm.annotation_text().get_value_or(""); + values['b'] = dcp::LocalTime(valid_from).date() + " " + dcp::LocalTime(valid_from).time_of_day(true, false); + values['e'] = dcp::LocalTime(valid_to).date() + " " + dcp::LocalTime(valid_to).time_of_day(true, false); + + try { + list screen_kdms; + BOOST_FOREACH (shared_ptr i, find_cinema(*cinema_name)->screens()) { + if (!i->recipient) { + continue; + } + screen_kdms.push_back ( + ScreenKDM ( + i, + kdm_from_dkdm ( + dkdm, + i->recipient.get(), + i->trusted_devices, + dcp::LocalTime(valid_from, i->cinema->utc_offset_hour(), i->cinema->utc_offset_minute()), + dcp::LocalTime(valid_to, i->cinema->utc_offset_hour(), i->cinema->utc_offset_minute()), + formulation + ) + ) + ); + } + write_files (screen_kdms, zip, *output, values, verbose); + } catch (FileError& e) { + cerr << program_name << ": " << e.what() << " (" << e.file().string() << ")\n"; + exit (EXIT_FAILURE); + } catch (KDMError& e) { + cerr << program_name << ": " << e.what() << "\n"; + exit (EXIT_FAILURE); + } + } +} + +void +dump_dkdm_group (shared_ptr group, int indent) +{ + if (indent > 0) { + for (int i = 0; i < indent; ++i) { + cout << " "; + } + cout << group->name() << "\n"; + } + BOOST_FOREACH (shared_ptr i, group->children()) { + shared_ptr g = dynamic_pointer_cast(i); + if (g) { + dump_dkdm_group (g, indent + 2); + } else { + for (int j = 0; j < indent; ++j) { + cout << " "; + } + shared_ptr d = dynamic_pointer_cast(i); + assert(d); + cout << d->dkdm().cpl_id() << "\n"; + } + } +} + int main (int argc, char* argv[]) { optional output; optional valid_from; optional valid_to; - optional certificate_file; + optional certificate_file; bool zip = false; optional cinema_name; bool cinemas = false; + bool dkdm_cpls = false; optional duration_string; bool verbose = false; dcp::Formulation formulation = dcp::MODIFIED_TRANSITIONAL_1; @@ -187,6 +430,7 @@ int main (int argc, char* argv[]) { "certificate", required_argument, 0, 'A' }, { "cinema", required_argument, 0, 'c' }, { "cinemas", no_argument, 0, 'B' }, + { "dkdm-cpls", no_argument, 0, 'D' }, { "zip", no_argument, 0, 'z' }, { "duration", required_argument, 0, 'd' }, { "verbose", no_argument, 0, 'v' }, @@ -194,7 +438,7 @@ int main (int argc, char* argv[]) { 0, 0, 0, 0 } }; - int c = getopt_long (argc, argv, "ho:f:t:c:A:Bzd:vC:", long_options, &option_index); + int c = getopt_long (argc, argv, "ho:f:t:c:A:Bzd:vC:D", long_options, &option_index); if (c == -1) { break; @@ -222,6 +466,9 @@ int main (int argc, char* argv[]) case 'B': cinemas = true; break; + case 'D': + dkdm_cpls = true; + break; case 'z': zip = true; break; @@ -252,6 +499,11 @@ int main (int argc, char* argv[]) exit (EXIT_SUCCESS); } + if (dkdm_cpls) { + dump_dkdm_group (Config::instance()->dkdms(), 0); + exit (EXIT_SUCCESS); + } + if (!duration_string && !valid_to) { error ("you must specify a --valid-duration or --valid-to"); } @@ -274,75 +526,22 @@ int main (int argc, char* argv[]) valid_to = valid_from.get() + duration_from_string (*duration_string); } - boost::filesystem::path const film_dir = argv[optind]; - dcpomatic_setup_path_encoding (); dcpomatic_setup (); - shared_ptr film; - try { - film.reset (new Film (film_dir)); - film->read_metadata (); - if (verbose) { - cout << "Read film " << film->name () << "\n"; - } - } catch (std::exception& e) { - cerr << program_name << ": error reading film `" << film_dir.string() << "' (" << e.what() << ")\n"; - exit (EXIT_FAILURE); - } - if (verbose) { cout << "Making KDMs valid from " << valid_from.get() << " to " << valid_to.get() << "\n"; } - /* XXX: allow specification of this */ - vector cpls = film->cpls (); - if (cpls.empty ()) { - error ("no CPLs found in film"); - } else if (cpls.size() > 1) { - error ("more than one CPL found in film"); - } - - boost::filesystem::path cpl = cpls.front().cpl_file; - - if (!cinema_name) { - - if (!output) { - error ("you must specify --output"); - } - - dcp::Certificate certificate (dcp::file_to_string (*certificate_file)); - dcp::EncryptedKDM kdm = film->make_kdm ( - certificate, vector(), cpl, dcp::LocalTime (*valid_from), dcp::LocalTime (*valid_to), formulation - ); - kdm.as_xml (*output); - if (verbose) { - cout << "Generated KDM " << *output << " for certificate.\n"; - } + string const thing = argv[optind]; + if (boost::filesystem::is_directory(thing) && boost::filesystem::is_regular_file(boost::filesystem::path(thing) / "metadata.xml")) { + from_film (thing, verbose, cinema_name, output, certificate_file, *valid_from, *valid_to, formulation, zip); } else { - - if (!output) { - output = "."; - } - - dcp::NameFormat::Map values; - values['f'] = film->name(); - values['b'] = dcp::LocalTime(*valid_from).date() + " " + dcp::LocalTime(*valid_from).time_of_day(true, false); - values['e'] = dcp::LocalTime(*valid_to).date() + " " + dcp::LocalTime(*valid_to).time_of_day(true, false); - - try { - list screen_kdms = film->make_kdms ( - find_cinema(*cinema_name)->screens(), cpl, valid_from.get(), valid_to.get(), formulation - ); - - write_files (screen_kdms, zip, *output, values, verbose); - } catch (FileError& e) { - cerr << argv[0] << ": " << e.what() << " (" << e.file().string() << ")\n"; - exit (EXIT_FAILURE); - } catch (KDMError& e) { - cerr << argv[0] << ": " << e.what() << "\n"; - exit (EXIT_FAILURE); + optional dkdm = find_dkdm (thing); + if (!dkdm) { + error ("could not find film or CPL ID corresponding to " + thing); } + from_dkdm (*dkdm, verbose, cinema_name, output, certificate_file, *valid_from, *valid_to, formulation, zip); } return 0;