Extract subtitle language from text content rather than ISDCFMetadata (part of #1516).
[dcpomatic.git] / src / lib / film.cc
index f4745d0995597d2e17a91fee185a26d187d8f2bf..caa95c6be0e0d76d0bef0a5defc163d15929ed5b 100644 (file)
@@ -92,6 +92,7 @@ using std::runtime_error;
 using std::copy;
 using std::back_inserter;
 using std::map;
+using std::exception;
 using boost::shared_ptr;
 using boost::weak_ptr;
 using boost::dynamic_pointer_cast;
@@ -454,6 +455,16 @@ Film::read_metadata (optional<boost::filesystem::path> path)
        _state_version = f.number_child<int> ("Version");
        if (_state_version > current_state_version) {
                throw runtime_error (_("This film was created with a newer version of DCP-o-matic, and it cannot be loaded into this version.  Sorry!"));
+       } else if (_state_version < current_state_version) {
+               /* This is an older version; save a copy (if we haven't already) */
+               boost::filesystem::path const older = path->parent_path() / String::compose("metadata.%1.xml", _state_version);
+               if (!boost::filesystem::is_regular_file(older)) {
+                       try {
+                               boost::filesystem::copy_file(*path, older);
+                       } catch (...) {
+                               /* Never mind; at least we tried */
+                       }
+               }
        }
 
        _name = f.string_child ("Name");
@@ -711,32 +722,35 @@ Film::isdcf_name (bool if_created_now) const
 
        if (!dm.audio_language.empty ()) {
                d += "_" + dm.audio_language;
-               if (!dm.subtitle_language.empty()) {
 
-                       /* I'm not clear on the precise details of the convention for CCAP labelling;
-                          for now I'm just appending -CCAP if we have any closed captions.
-                       */
+               /* I'm not clear on the precise details of the convention for CCAP labelling;
+                  for now I'm just appending -CCAP if we have any closed captions.
+               */
 
-                       bool burnt_in = true;
-                       bool ccap = false;
-                       BOOST_FOREACH (shared_ptr<Content> i, content()) {
-                               BOOST_FOREACH (shared_ptr<TextContent> j, i->text) {
-                                       if (j->type() == TEXT_OPEN_SUBTITLE && j->use() && !j->burn()) {
+               optional<string> subtitle_language;
+               bool burnt_in = true;
+               bool ccap = false;
+               BOOST_FOREACH (shared_ptr<Content> i, content()) {
+                       BOOST_FOREACH (shared_ptr<TextContent> j, i->text) {
+                               if (j->type() == TEXT_OPEN_SUBTITLE && j->use()) {
+                                       subtitle_language = j->language ();
+                                       if (!j->burn()) {
                                                burnt_in = false;
-                                       } else if (j->type() == TEXT_CLOSED_CAPTION) {
-                                               ccap = true;
                                        }
+                               } else if (j->type() == TEXT_CLOSED_CAPTION && j->use()) {
+                                       ccap = true;
                                }
                        }
+               }
 
-                       string language = dm.subtitle_language;
-                       if (burnt_in && language != "XX") {
-                               transform (language.begin(), language.end(), language.begin(), ::tolower);
+               if (subtitle_language) {
+                       if (burnt_in && *subtitle_language != "XX") {
+                               transform (subtitle_language->begin(), subtitle_language->end(), subtitle_language->begin(), ::tolower);
                        } else {
-                               transform (language.begin(), language.end(), language.begin(), ::toupper);
+                               transform (subtitle_language->begin(), subtitle_language->end(), subtitle_language->begin(), ::toupper);
                        }
 
-                       d += "-" + language;
+                       d += "-" + *subtitle_language;
                        if (ccap) {
                                d += "-CCAP";
                        }
@@ -1027,7 +1041,16 @@ Film::j2c_path (int reel, Frame frame, Eyes eyes, bool tmp) const
        return file (p);
 }
 
-/** Find all the DCPs in our directory that can be dcp::DCP::read() and return details of their CPLs */
+static
+bool
+cpl_summary_compare (CPLSummary const & a, CPLSummary const & b)
+{
+       return a.last_write_time > b.last_write_time;
+}
+
+/** Find all the DCPs in our directory that can be dcp::DCP::read() and return details of their CPLs.
+ *  The list will be returned in reverse order of timestamp (i.e. most recent first).
+ */
 vector<CPLSummary>
 Film::cpls () const
 {
@@ -1045,23 +1068,15 @@ Film::cpls () const
                        ) {
 
                        try {
-                               dcp::DCP dcp (*i);
-                               dcp.read ();
-                               DCPOMATIC_ASSERT (dcp.cpls().front()->file());
-                               out.push_back (
-                                       CPLSummary (
-                                               i->path().leaf().string(),
-                                               dcp.cpls().front()->id(),
-                                               dcp.cpls().front()->annotation_text(),
-                                               dcp.cpls().front()->file().get()
-                                               )
-                                       );
+                               out.push_back (CPLSummary(*i));
                        } catch (...) {
 
                        }
                }
        }
 
+       sort (out.begin(), out.end(), cpl_summary_compare);
+
        return out;
 }
 
@@ -1220,6 +1235,31 @@ Film::playlist_change (ChangeType type)
 {
        signal_change (type, CONTENT);
        signal_change (type, NAME);
+
+       if (type == CHANGE_TYPE_DONE) {
+               /* Check that this change hasn't made our settings inconsistent */
+               bool change_made = false;
+               BOOST_FOREACH (shared_ptr<Content> i, content()) {
+                       shared_ptr<DCPContent> d = dynamic_pointer_cast<DCPContent>(i);
+                       if (!d) {
+                               continue;
+                       }
+
+                       string why_not;
+                       if (d->reference_video() && !d->can_reference_video(shared_from_this(), why_not)) {
+                               d->set_reference_video(false);
+                               change_made = true;
+                       }
+                       if (d->reference_audio() && !d->can_reference_audio(shared_from_this(), why_not)) {
+                               d->set_reference_audio(false);
+                               change_made = true;
+                       }
+               }
+
+               if (change_made) {
+                       Message (_("DCP-o-matic had to change your settings for referring to DCPs as OV.  Please review those settings to make sure they are what you want."));
+               }
+       }
 }
 
 void
@@ -1625,7 +1665,7 @@ Film::closed_caption_tracks () const
        list<DCPTextTrack> tt;
        BOOST_FOREACH (shared_ptr<Content> i, content()) {
                BOOST_FOREACH (shared_ptr<TextContent> j, i->text) {
-                       /* XXX: Empty DCPTextTrack ends up being a magic value here */
+                       /* XXX: Empty DCPTextTrack ends up being a magic value here - the "unknown" or "not specified" track */
                        DCPTextTrack dtt = j->dcp_track().get_value_or(DCPTextTrack());
                        if (j->type() == TEXT_CLOSED_CAPTION && find(tt.begin(), tt.end(), dtt) == tt.end()) {
                                tt.push_back (dtt);