Make a backup of configuration when we load in a Version 2 file, and bump our config...
[dcpomatic.git] / src / lib / config.cc
index 983fb69d8d8af2725c5bec70b28a32c298a202e2..ec5b05afaa0a49ec41c84b732b7f1abea08105d2 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2012-2017 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2012-2018 Carl Hetherington <cth@carlh.net>
 
     This file is part of DCP-o-matic.
 
@@ -64,6 +64,7 @@ using boost::algorithm::trim;
 using dcp::raw_convert;
 
 Config* Config::_instance = 0;
+int const Config::_current_version = 3;
 boost::signals2::signal<void ()> Config::FailedToLoad;
 boost::signals2::signal<void (string)> Config::Warning;
 boost::optional<boost::filesystem::path> Config::test_path;
@@ -101,6 +102,7 @@ Config::set_defaults ()
        _default_j2k_bandwidth = 100000000;
        _default_audio_delay = 0;
        _default_interop = true;
+       _default_upload_after_make_dcp = false;
        _mail_server = "";
        _mail_port = 25;
        _mail_user = "";
@@ -128,9 +130,10 @@ Config::set_defaults ()
        for (int i = 0; i < NAG_COUNT; ++i) {
                _nagged[i] = false;
        }
-       _sound = false;
+       _sound = true;
        _sound_output = optional<string> ();
        _last_kdm_write_type = KDM_WRITE_FLAT;
+       _last_dkdm_write_type = DKDM_WRITE_INTERNAL;
 
        /* I think the scaling factor here should be the ratio of the longest frame
           encode time to the shortest; if the thread count is T, longest time is L
@@ -142,6 +145,7 @@ Config::set_defaults ()
           use about 240Mb with 72 encoding threads.
        */
        _frames_in_memory_multiplier = 3;
+       _decode_reduction = optional<int>();
 
        _allowed_dcp_frame_rates.clear ();
        _allowed_dcp_frame_rates.push_back (24);
@@ -177,6 +181,21 @@ Config::create_certificate_chain ()
                );
 }
 
+void
+Config::backup ()
+{
+       /* Make a copy of the configuration */
+       try {
+               int n = 1;
+               while (n < 100 && boost::filesystem::exists(path(String::compose("config.xml.%1", n)))) {
+                       ++n;
+               }
+
+               boost::filesystem::copy_file(path("config.xml", false), path(String::compose("config.xml.%1", n), false));
+               boost::filesystem::copy_file(path("cinemas.xml", false), path(String::compose("cinemas.xml.%1", n), false));
+       } catch (...) {}
+}
+
 void
 Config::read ()
 try
@@ -185,6 +204,10 @@ try
        f.read_file (config_file ());
 
        optional<int> version = f.optional_number_child<int> ("Version");
+       if (version && *version < _current_version) {
+               /* Back up the old config before we re-write it in a back-incompatible way */
+               backup ();
+       }
 
        if (f.optional_number_child<int>("NumLocalEncodingThreads")) {
                _master_encoding_threads = _server_encoding_threads = f.optional_number_child<int>("NumLocalEncodingThreads").get();
@@ -250,11 +273,7 @@ try
                _default_scale_to = Ratio::from_id (c.get ());
        }
 
-       c = f.optional_string_child ("DefaultDCPContentType");
-       if (c) {
-               _default_dcp_content_type = DCPContentType::from_isdcf_name (c.get ());
-       }
-
+       _default_dcp_content_type = DCPContentType::from_isdcf_name(f.optional_string_child("DefaultDCPContentType").get_value_or("FTR"));
        _default_dcp_audio_channels = f.optional_number_child<int>("DefaultDCPAudioChannels").get_value_or (6);
 
        if (f.optional_string_child ("DCPMetadataIssuer")) {
@@ -263,6 +282,7 @@ try
                _dcp_issuer = f.string_child ("DCPIssuer");
        }
 
+       _default_upload_after_make_dcp = f.optional_bool_child("DefaultUploadAfterMakeDCP").get_value_or (false);
        _dcp_creator = f.optional_string_child ("DCPCreator").get_value_or ("");
 
        if (version && version.get() >= 2) {
@@ -307,11 +327,14 @@ try
        _win32_console = f.optional_bool_child ("Win32Console").get_value_or (false);
 #endif
 
-       list<cxml::NodePtr> his = f.node_children ("History");
        BOOST_FOREACH (cxml::ConstNodePtr i, f.node_children("History")) {
                _history.push_back (i->content ());
        }
 
+       BOOST_FOREACH (cxml::ConstNodePtr i, f.node_children("PlayerHistory")) {
+               _player_history.push_back (i->content ());
+       }
+
        cxml::NodePtr signer = f.optional_node_child ("Signer");
        if (signer) {
                shared_ptr<dcp::CertificateChain> c (new dcp::CertificateChain ());
@@ -363,7 +386,7 @@ try
                }
        }
        /* The variable was renamed but not the XML tag */
-       _sound = f.optional_bool_child("PreviewSound").get_value_or (false);
+       _sound = f.optional_bool_child("PreviewSound").get_value_or (true);
        _sound_output = f.optional_string_child("PreviewSoundOutput");
        if (f.optional_string_child("CoverSheet")) {
                _cover_sheet = f.optional_string_child("CoverSheet").get();
@@ -378,7 +401,15 @@ try
                        _last_kdm_write_type = KDM_WRITE_ZIP;
                }
        }
+       if (f.optional_string_child("LastDKDMWriteType")) {
+               if (f.optional_string_child("LastDKDMWriteType").get() == "internal") {
+                       _last_dkdm_write_type = DKDM_WRITE_INTERNAL;
+               } else if (f.optional_string_child("LastDKDMWriteType").get() == "file") {
+                       _last_dkdm_write_type = DKDM_WRITE_FILE;
+               }
+       }
        _frames_in_memory_multiplier = f.optional_number_child<int>("FramesInMemoryMultiplier").get_value_or(3);
+       _decode_reduction = f.optional_number_child<int>("DecodeReduction");
 
        /* Replace any cinemas from config.xml with those from the configured file */
        if (boost::filesystem::exists (_cinemas_file)) {
@@ -389,18 +420,7 @@ try
 }
 catch (...) {
        if (have_existing ("config.xml")) {
-
-               /* Make a copy of the configuration */
-               try {
-                       int n = 1;
-                       while (n < 100 && boost::filesystem::exists(path(String::compose("config.xml.%1", n)))) {
-                               ++n;
-                       }
-
-                       boost::filesystem::copy_file(path("config.xml", false), path(String::compose("config.xml.%1", n), false));
-                       boost::filesystem::copy_file(path("cinemas.xml", false), path(String::compose("cinemas.xml.%1", n), false));
-               } catch (...) {}
-
+               backup ();
                /* We have a config file but it didn't load */
                FailedToLoad ();
        }
@@ -465,8 +485,8 @@ Config::write_config () const
        xmlpp::Document doc;
        xmlpp::Element* root = doc.create_root_node ("Config");
 
-       /* [XML] Version The version number of the configuration file format; currently 2. */
-       root->add_child("Version")->add_child_text ("2");
+       /* [XML] Version The version number of the configuration file format */
+       root->add_child("Version")->add_child_text (String::compose ("%1", _current_version));
        /* [XML] MasterEncodingThreads Number of encoding threads to use when running as master. */
        root->add_child("MasterEncodingThreads")->add_child_text (raw_convert<string> (_master_encoding_threads));
        /* [XML] ServerEncodingThreads Number of encoding threads to use when running as server. */
@@ -539,6 +559,7 @@ Config::write_config () const
        root->add_child("DCPIssuer")->add_child_text (_dcp_issuer);
        /* [XML] DCPIssuer Creator text to write into CPL files. */
        root->add_child("DCPCreator")->add_child_text (_dcp_creator);
+       root->add_child("DefaultUploadAfterMakeDCP")->add_child_text (_default_upload_after_make_dcp ? "1" : "0");
 
        /* [XML] ISDCFMetadata Default ISDCF metadata to use for new films; child tags are <code>&lt;ContentVersion&gt;</code>,
           <code>&lt;AudioLanguage&gt;</code>, <code>&lt;SubtitleLanguage&gt;</code>, <code>&lt;Territory&gt;</code>,
@@ -629,6 +650,10 @@ Config::write_config () const
                root->add_child("History")->add_child_text (i.string ());
        }
 
+       BOOST_FOREACH (boost::filesystem::path i, _player_history) {
+               root->add_child("PlayerHistory")->add_child_text (i.string ());
+       }
+
        /* [XML] DKDMGroup A group of DKDMs, each with a <code>Name</code> attribute, containing other <code>&lt;DKDMGroup&gt;</code>
           or <code>&lt;DKDM&gt;</code> tags.
        */
@@ -681,11 +706,26 @@ Config::write_config () const
                        break;
                }
        }
+       if (_last_dkdm_write_type) {
+               switch (_last_dkdm_write_type.get()) {
+               case DKDM_WRITE_INTERNAL:
+                       root->add_child("LastDKDMWriteType")->add_child_text("internal");
+                       break;
+               case DKDM_WRITE_FILE:
+                       root->add_child("LastDKDMWriteType")->add_child_text("file");
+                       break;
+               }
+       }
        /* [XML] FramesInMemoryMultiplier value to multiply the encoding threads count by to get the maximum number of
           frames to be held in memory at once.
        */
        root->add_child("FramesInMemoryMultiplier")->add_child_text(raw_convert<string>(_frames_in_memory_multiplier));
 
+       /* [XML] DecodeReduction power of 2 to reduce DCP images by before decoding in the player */
+       if (_decode_reduction) {
+               root->add_child("DecodeReduction")->add_child_text(raw_convert<string>(_decode_reduction.get()));
+       }
+
        try {
                doc.write_to_file_formatted(config_file().string());
        } catch (xmlpp::exception& e) {
@@ -795,13 +835,25 @@ Config::set_cover_sheet_to_default ()
 
 void
 Config::add_to_history (boost::filesystem::path p)
+{
+       add_to_history_internal (_history, p);
+}
+
+void
+Config::add_to_player_history (boost::filesystem::path p)
+{
+       add_to_history_internal (_player_history, p);
+}
+
+void
+Config::add_to_history_internal (vector<boost::filesystem::path>& h, boost::filesystem::path p)
 {
        /* Remove existing instances of this path in the history */
-       _history.erase (remove (_history.begin(), _history.end(), p), _history.end ());
+       h.erase (remove (h.begin(), h.end(), p), h.end ());
 
-       _history.insert (_history.begin (), p);
-       if (_history.size() > HISTORY_SIZE) {
-               _history.pop_back ();
+       h.insert (h.begin (), p);
+       if (h.size() > HISTORY_SIZE) {
+               h.pop_back ();
        }
 
        changed ();