+ _last_ccap = period;
+}
+
+
+void
+Hints::open_subtitle (PlayerText text, DCPTimePeriod period)
+{
+ if (period.from < DCPTime::from_seconds(4) && !_early_subtitle) {
+ _early_subtitle = true;
+ hint (_("It is advisable to put your first subtitle at least 4 seconds after the start of the DCP to make sure it is seen."));
+ }
+
+ int const vfr = film()->video_frame_rate ();
+
+ if (period.duration().frames_round(vfr) < 15 && !_short_subtitle) {
+ _short_subtitle = true;
+ hint (_("At least one of your subtitles lasts less than 15 frames. It is advisable to make each subtitle at least 15 frames long."));
+ }
+
+ if (_last_subtitle && DCPTime(period.from - _last_subtitle->to).frames_round(vfr) < 2 && !_subtitles_too_close) {
+ _subtitles_too_close = true;
+ hint (_("At least one of your subtitles starts less than 2 frames after the previous one. It is advisable to make the gap between subtitles at least 2 frames."));
+ }
+
+ if (text.string.size() > 3 && !_too_many_subtitle_lines) {
+ _too_many_subtitle_lines = true;
+ hint (_("At least one of your subtitles has more than 3 lines. It is advisable to use no more than 3 lines."));
+ }
+
+ size_t longest_line = 0;
+ for (auto const& i: text.string) {
+ longest_line = max (longest_line, i.text().length());
+ }
+
+ if (longest_line > 52) {
+ _long_subtitle = true;
+ }
+
+ if (longest_line > 79) {
+ _very_long_subtitle = true;
+ }
+
+ _last_subtitle = period;
+}
+
+
+void
+Hints::check_ffec_and_ffmc_in_smpte_feature ()
+{
+ auto f = film();
+ if (!f->interop() && f->dcp_content_type()->libdcp_kind() == dcp::ContentKind::FEATURE && (!f->marker(dcp::Marker::FFEC) || !f->marker(dcp::Marker::FFMC))) {
+ hint (_("SMPTE DCPs with the type FTR (feature) should have markers for the first frame of end credits (FFEC) and the first frame of moving credits (FFMC). You should add these markers using the 'Markers' button in the \"DCP\" tab."));
+ }
+}
+
+
+void
+Hints::join ()
+{
+ _thread.join ();
+}
+
+
+void
+Hints::check_text_languages ()
+{
+ for (auto i: film()->content()) {
+ for (auto j: i->text) {
+ if (j->use() && !j->language()) {
+ hint (_("At least one piece of subtitle or closed caption content has no specified language. "
+ "It is advisable to set the language for each piece of subtitle or closed caption content "
+ "in the \"Content→Timed text\", \"Content→Open subtitles\" or \"Content→Closed captions\" tab."));
+ return;
+ }
+ }
+ }
+}
+
+
+void
+Hints::check_audio_language ()
+{
+ auto content = film()->content();
+ auto mapped_audio =
+ std::find_if(content.begin(), content.end(), [](shared_ptr<const Content> c) {
+ return c->audio && !c->audio->mapping().mapped_output_channels().empty();
+ });
+
+ if (mapped_audio != content.end() && !film()->audio_language()) {
+ hint (_("Some of your content has audio but you have not set the audio language. It is advisable to set the audio language "
+ "in the \"DCP\" tab unless your audio has no spoken parts."));
+ }
+}
+
+
+void
+Hints::check_certificates ()
+{
+ auto bad = Config::instance()->check_certificates();
+ if (!bad) {
+ return;
+ }
+
+ switch (*bad) {
+ case Config::BAD_SIGNER_UTF8_STRINGS:
+ hint(_("The certificate chain that DCP-o-matic uses for signing DCPs and KDMs contains a small error "
+ "which will prevent DCPs from being validated correctly on some systems. You are advised to "
+ "re-create the signing certificate chain by clicking the \"Re-make certificates and key...\" "
+ "button in the Keys page of Preferences."));
+ break;
+ case Config::BAD_SIGNER_VALIDITY_TOO_LONG:
+ hint(_("The certificate chain that DCP-o-matic uses for signing DCPs and KDMs has a validity period "
+ "that is too long. This will cause problems playing back DCPs on some systems. "
+ "You are advised to re-create the signing certificate chain by clicking the "
+ "\"Re-make certificates and key...\" button in the Keys page of Preferences."));
+ break;
+ default:
+ /* Some bad situations can't happen here as DCP-o-matic would have refused to start until they are fixed */
+ break;
+ }