X-Git-Url: https://git.carlh.net/gitweb/?p=dcpomatic.git;a=blobdiff_plain;f=src%2Flib%2Fkdm_with_metadata.cc;h=bebb5df86d0b44f6af12a2c5f371d2e2620eed6e;hp=e6b283415ed7cbad1fc8aed76239e430c5e682a0;hb=f1b2884943ab6fd1e3ba37b017d41b65645f49dc;hpb=36ce958a516567d8481163692c028a88c6ce0df7 diff --git a/src/lib/kdm_with_metadata.cc b/src/lib/kdm_with_metadata.cc index e6b283415..bebb5df86 100644 --- a/src/lib/kdm_with_metadata.cc +++ b/src/lib/kdm_with_metadata.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2016 Carl Hetherington + Copyright (C) 2013-2021 Carl Hetherington This file is part of DCP-o-matic. @@ -18,31 +18,43 @@ */ -#include "kdm_with_metadata.h" + #include "cinema.h" +#include "config.h" +#include "cross.h" +#include "dcpomatic_log.h" +#include "emailer.h" +#include "kdm_with_metadata.h" #include "screen.h" #include "util.h" -#include +#include "zipper.h" +#include + +#include "i18n.h" + -using std::string; using std::cout; +using std::function; using std::list; -using boost::shared_ptr; +using std::shared_ptr; +using std::string; +using std::vector; +using boost::optional; + int -KDMWithMetadata::write_files ( - list > screen_kdms, +write_files ( + list kdms, boost::filesystem::path directory, dcp::NameFormat name_format, - dcp::NameFormat::Map name_values, - boost::function confirm_overwrite + std::function confirm_overwrite ) { int written = 0; if (directory == "-") { /* Write KDMs to the stdout */ - BOOST_FOREACH (shared_ptr i, screen_kdms) { + for (auto i: kdms) { cout << i->kdm_as_xml (); ++written; } @@ -55,11 +67,8 @@ KDMWithMetadata::write_files ( } /* Write KDMs to the specified directory */ - BOOST_FOREACH (shared_ptr i, screen_kdms) { - name_values['c'] = i->screen->cinema ? i->screen->cinema->name : ""; - name_values['s'] = i->screen->name; - name_values['i'] = i->kdm_id (); - boost::filesystem::path out = directory / careful_string_filter(name_format.get(name_values, ".xml")); + for (auto i: kdms) { + auto out = dcp::fix_long_path(directory / careful_string_filter(name_format.get(i->name_values(), ".xml"))); if (!boost::filesystem::exists (out) || confirm_overwrite (out)) { i->kdm_as_xml (out); ++written; @@ -68,3 +77,222 @@ KDMWithMetadata::write_files ( return written; } + + +optional +KDMWithMetadata::get (char k) const +{ + auto i = _name_values.find (k); + if (i == _name_values.end()) { + return {}; + } + + return i->second; +} + + +void +make_zip_file (list kdms, boost::filesystem::path zip_file, dcp::NameFormat name_format) +{ + Zipper zipper (zip_file); + + for (auto i: kdms) { + auto const name = careful_string_filter(name_format.get(i->name_values(), ".xml")); + zipper.add (name, i->kdm_as_xml()); + } + + zipper.close (); +} + + +/** Collect a list of KDMWithMetadatas into a list of lists so that + * each list contains the KDMs for one list. + */ +list> +collect (list kdms) +{ + list> grouped; + + for (auto i: kdms) { + + auto j = grouped.begin (); + + while (j != grouped.end()) { + if (j->front()->group() == i->group()) { + j->push_back (i); + break; + } + ++j; + } + + if (j == grouped.end()) { + grouped.push_back (list()); + grouped.back().push_back (i); + } + } + + return grouped; +} + + +/** Write one directory per list into another directory */ +int +write_directories ( + list> kdms, + boost::filesystem::path directory, + dcp::NameFormat container_name_format, + dcp::NameFormat filename_format, + function confirm_overwrite + ) +{ + int written = 0; + + for (auto const& kdm: kdms) { + auto path = directory; + path /= container_name_format.get(kdm.front()->name_values(), "", "s"); + if (!boost::filesystem::exists (path) || confirm_overwrite (path)) { + boost::filesystem::create_directories (path); + write_files(kdm, path, filename_format, confirm_overwrite); + } + written += kdm.size(); + } + + return written; +} + + +/** Write one ZIP file per cinema into a directory */ +int +write_zip_files ( + list> kdms, + boost::filesystem::path directory, + dcp::NameFormat container_name_format, + dcp::NameFormat filename_format, + function confirm_overwrite + ) +{ + int written = 0; + + for (auto const& kdm: kdms) { + auto path = directory; + path /= container_name_format.get(kdm.front()->name_values(), ".zip", "s"); + if (!boost::filesystem::exists (path) || confirm_overwrite (path)) { + if (boost::filesystem::exists (path)) { + /* Creating a new zip file over an existing one is an error */ + boost::filesystem::remove (path); + } + make_zip_file(kdm, path, filename_format); + written += kdm.size(); + } + } + + return written; +} + + +/** Email one ZIP file per cinema to the cinema. + * @param kdms KDMs to email. + * @param container_name_format Format of folder / ZIP to use. + * @param filename_format Format of filenames to use. + * @param name_values Values to substitute into \p container_name_format and \p filename_format. + * @param cpl_name Name of the CPL that the KDMs are for. + */ +void +send_emails ( + list> kdms, + dcp::NameFormat container_name_format, + dcp::NameFormat filename_format, + string cpl_name, + vector extra_addresses + ) +{ + auto config = Config::instance (); + + if (config->mail_server().empty()) { + throw NetworkError (_("No mail server configured in preferences")); + } + + if (config->kdm_from().empty()) { + throw NetworkError(_("No KDM from address configured in preferences")); + } + + for (auto const& kdms_for_cinema: kdms) { + + auto first = kdms_for_cinema.front(); + + if (first->emails().empty()) { + continue; + } + + auto zip_file = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); + boost::filesystem::create_directories (zip_file); + zip_file /= container_name_format.get(first->name_values(), ".zip"); + make_zip_file (kdms_for_cinema, zip_file, filename_format); + + auto substitute_variables = [cpl_name, first](string target) { + boost::algorithm::replace_all(target, "$CPL_NAME", cpl_name); + boost::algorithm::replace_all(target, "$START_TIME", first->get('b').get_value_or("")); + boost::algorithm::replace_all(target, "$END_TIME", first->get('e').get_value_or("")); + boost::algorithm::replace_all(target, "$CINEMA_NAME", first->get('c').get_value_or("")); + boost::algorithm::replace_all(target, "$CINEMA_SHORT_NAME", first->get('c').get_value_or("").substr(0, 14)); + return target; + }; + + auto subject = substitute_variables(config->kdm_subject()); + auto body = substitute_variables(config->kdm_email()); + + string screens; + for (auto kdm: kdms_for_cinema) { + auto screen_name = kdm->get('s'); + if (screen_name) { + screens += *screen_name + ", "; + } + } + boost::algorithm::replace_all (body, "$SCREENS", screens.substr (0, screens.length() - 2)); + + Emailer email (config->kdm_from(), first->emails(), subject, body); + + for (auto cc: config->kdm_cc()) { + email.add_cc (cc); + } + if (!config->kdm_bcc().empty()) { + email.add_bcc (config->kdm_bcc()); + } + + email.add_attachment (zip_file, container_name_format.get(first->name_values(), ".zip"), "application/zip"); + + auto log_details = [](Emailer& email) { + dcpomatic_log->log("Email content follows", LogEntry::TYPE_DEBUG_EMAIL); + dcpomatic_log->log(email.email(), LogEntry::TYPE_DEBUG_EMAIL); + dcpomatic_log->log("Email session follows", LogEntry::TYPE_DEBUG_EMAIL); + dcpomatic_log->log(email.notes(), LogEntry::TYPE_DEBUG_EMAIL); + }; + + try { + email.send (config->mail_server(), config->mail_port(), config->mail_protocol(), config->mail_user(), config->mail_password()); + } catch (...) { + boost::filesystem::remove (zip_file); + log_details (email); + throw; + } + + log_details (email); + + for (auto extra: extra_addresses) { + Emailer email (config->kdm_from(), { extra }, subject, body); + email.add_attachment (zip_file, container_name_format.get(first->name_values(), ".zip"), "application/zip"); + + try { + email.send (config->mail_server(), config->mail_port(), config->mail_protocol(), config->mail_user(), config->mail_password()); + } catch (...) { + boost::filesystem::remove (zip_file); + log_details (email); + throw; + } + + log_details (email); + } + + boost::filesystem::remove (zip_file); + } +}