diff --git a/src/main/java/com/adobe/epubcheck/messages/DefaultSeverities.java b/src/main/java/com/adobe/epubcheck/messages/DefaultSeverities.java index f00a64328..65d71c011 100644 --- a/src/main/java/com/adobe/epubcheck/messages/DefaultSeverities.java +++ b/src/main/java/com/adobe/epubcheck/messages/DefaultSeverities.java @@ -153,6 +153,7 @@ private void initialize() severities.put(MessageId.MED_013, Severity.ERROR); severities.put(MessageId.MED_014, Severity.ERROR); severities.put(MessageId.MED_015, Severity.USAGE); + severities.put(MessageId.MED_016, Severity.WARNING); // NAV severities.put(MessageId.NAV_001, Severity.ERROR); diff --git a/src/main/java/com/adobe/epubcheck/messages/MessageId.java b/src/main/java/com/adobe/epubcheck/messages/MessageId.java index 92fbaa60a..e8b9c438d 100644 --- a/src/main/java/com/adobe/epubcheck/messages/MessageId.java +++ b/src/main/java/com/adobe/epubcheck/messages/MessageId.java @@ -147,6 +147,7 @@ public enum MessageId implements Comparable MED_013("MED_013"), MED_014("MED_014"), MED_015("MED_015"), + MED_016("MED_016"), // Epub3 based table of content errors NAV_001("NAV-001"), diff --git a/src/main/java/com/adobe/epubcheck/opf/MetadataSet.java b/src/main/java/com/adobe/epubcheck/opf/MetadataSet.java index 317f85d1e..3b1d1fa6c 100644 --- a/src/main/java/com/adobe/epubcheck/opf/MetadataSet.java +++ b/src/main/java/com/adobe/epubcheck/opf/MetadataSet.java @@ -353,6 +353,15 @@ public Set getRefiners() { return refiners; } + + /** + * Whether this is a primary metadata expression (as opposed to a refining + * expression) + * @return true if and only if this is a primary metadata expression + */ + public boolean isPrimary() { + return !refines.isPresent(); + } @Override public String toString() diff --git a/src/main/java/com/adobe/epubcheck/opf/OPFChecker30.java b/src/main/java/com/adobe/epubcheck/opf/OPFChecker30.java index 8c4d665f5..9c8de1ae4 100644 --- a/src/main/java/com/adobe/epubcheck/opf/OPFChecker30.java +++ b/src/main/java/com/adobe/epubcheck/opf/OPFChecker30.java @@ -34,10 +34,12 @@ import com.adobe.epubcheck.opf.MetadataSet.Metadata; import com.adobe.epubcheck.opf.ResourceCollection.Roles; import com.adobe.epubcheck.overlay.OverlayTextChecker; +import com.adobe.epubcheck.overlay.SmilClock; import com.adobe.epubcheck.util.EPUBVersion; import com.adobe.epubcheck.util.FeatureEnum; import com.adobe.epubcheck.util.PathUtil; import com.adobe.epubcheck.vocab.DCMESVocab; +import com.adobe.epubcheck.vocab.MediaOverlaysVocab; import com.adobe.epubcheck.vocab.PackageVocabs; import com.google.common.base.Optional; import com.google.common.base.Predicate; @@ -77,6 +79,7 @@ protected boolean checkContent() super.checkContent(); checkLinkedResources(); checkCollections(); + checkMediaOverlaysDuration(); return true; } @@ -408,6 +411,36 @@ private void checkLinkedResources() } } } + + // Checks that the total MO duration equals the sum of durations + private void checkMediaOverlaysDuration() { + MetadataSet metadata = ((OPFHandler30) opfHandler).getMetadata(); + // search total durations metadata expressions + Set totalDurationExpressions = metadata.getPrimary(MediaOverlaysVocab.VOCAB.get(MediaOverlaysVocab.PROPERTIES.DURATION)); + if (!totalDurationExpressions.isEmpty()) { + try + { + // the total duration is the first primary duration found + SmilClock totalDuration = new SmilClock(totalDurationExpressions.iterator().next().getValue()); + // sum all the individual durations (non-primary metadata expressions) + SmilClock sumDuration = new SmilClock(); + Set allDurations = metadata.getAny(MediaOverlaysVocab.VOCAB.get(MediaOverlaysVocab.PROPERTIES.DURATION)); + for (Metadata durationExpression : allDurations) + { + if (!durationExpression.isPrimary()) { + sumDuration = sumDuration.addTime(new SmilClock(durationExpression.getValue())); + } + } + // report if the sum and total don't match + if (!totalDuration.equals(sumDuration)) { + report.message(MessageId.MED_016, EPUBLocation.create(path)); + } + } catch (NumberFormatException e) + { + return; // Abort sum check. Invalid values are reported by the schema. + } + } + } private void checkPagination() { diff --git a/src/main/resources/com/adobe/epubcheck/messages/MessageBundle.properties b/src/main/resources/com/adobe/epubcheck/messages/MessageBundle.properties index 9a7e4cfaf..9ce0808e7 100644 --- a/src/main/resources/com/adobe/epubcheck/messages/MessageBundle.properties +++ b/src/main/resources/com/adobe/epubcheck/messages/MessageBundle.properties @@ -140,6 +140,7 @@ MED_012=The "media-overlay" attribute does not match the ID of the Media Overlay MED_013=Media Overlay Document referenced from the "media-overlay" attribute does not contain a reference to this Content Document. MED_014=A non-empty fragment identifier is required. MED_015=Media overlay text references must be in reading order. Text target "%1$s" is before the previous link target in %2$s order. +MED_016=Media Overlays total duration should be the sum of the durations of all Media Overlays documents. #NAV EPUB v3 Table of contents NAV_001=The nav file is not supported for EPUB v2. diff --git a/src/test/resources/epub3/files/package-document/mediaoverlays-duration-single-not-defined-error.opf b/src/test/resources/epub3/files/package-document/mediaoverlays-duration-single-not-defined-error.opf index b5de673ef..4eb85f137 100644 --- a/src/test/resources/epub3/files/package-document/mediaoverlays-duration-single-not-defined-error.opf +++ b/src/test/resources/epub3/files/package-document/mediaoverlays-duration-single-not-defined-error.opf @@ -7,13 +7,17 @@ NOID 2019-01-01T12:00:00Z 10min - + 10min + - - + + + + + diff --git a/src/test/resources/epub3/files/package-document/mediaoverlays-duration-total-not-sum-warning.opf b/src/test/resources/epub3/files/package-document/mediaoverlays-duration-total-not-sum-warning.opf new file mode 100644 index 000000000..42b376cb2 --- /dev/null +++ b/src/test/resources/epub3/files/package-document/mediaoverlays-duration-total-not-sum-warning.opf @@ -0,0 +1,22 @@ + + + + Title + en + NOID + 2019-01-01T12:00:00Z + + 10min + 5min + 0:05:00.200 + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/epub3/files/package-document/mediaoverlays-type-invalid-error.opf b/src/test/resources/epub3/files/package-document/mediaoverlays-type-invalid-error.opf index 9e0f883dc..99ae408fa 100644 --- a/src/test/resources/epub3/files/package-document/mediaoverlays-type-invalid-error.opf +++ b/src/test/resources/epub3/files/package-document/mediaoverlays-type-invalid-error.opf @@ -7,7 +7,7 @@ NOID 2019-01-01T12:00:00Z 0:32:00 - 12min + 32min diff --git a/src/test/resources/epub3/mediaoverlays-package-document.feature b/src/test/resources/epub3/mediaoverlays-package-document.feature index ffa9c6f62..640c518a8 100644 --- a/src/test/resources/epub3/mediaoverlays-package-document.feature +++ b/src/test/resources/epub3/mediaoverlays-package-document.feature @@ -42,7 +42,11 @@ Feature: EPUB 3 ▸ Media Overlays ▸ Package Document Checks Then error RSC-005 is reported And the message contains "item media:duration meta element not set" And no other errors or warnings are reported - + + Scenario: the total duration should be the sum of all Media Overlay durations + When checking file 'mediaoverlays-duration-total-not-sum-warning.opf' + Then warning MED-016 is reported + And no other errors or warnings are reported # C. Media Overlays Metadata Vocabulary