Skip to content

Commit

Permalink
Merge pull request #5942 from markusweigelt/improvements-media-partials
Browse files Browse the repository at this point in the history
Improvements media partials
  • Loading branch information
solth authored Mar 1, 2024
2 parents 92e7f32 + 17dd43e commit 7b1d685
Show file tree
Hide file tree
Showing 8 changed files with 151 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.kitodo.api.dataformat.MediaPartial;
import org.kitodo.api.dataformat.View;
import org.kitodo.production.enums.MediaContentType;
import org.kitodo.production.services.ServiceManager;
Expand Down Expand Up @@ -215,6 +216,18 @@ public boolean isMediaPartial() {
.hasMediaPartial();
}

/**
* Get the media partial of physical division.
*
* @return The media partial or null
*/
public MediaPartial getMediaPartial() {
if (isMediaPartial()) {
return view.getPhysicalDivision().getMediaPartial();
}
return null;
}

/**
* Returns the type of gallery media content object.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import static org.kitodo.production.helper.metadata.MediaPartialHelper.addMediaPartialToMediaSelection;
import static org.kitodo.production.helper.metadata.MediaPartialHelper.calculateExtentAndSortMediaPartials;
import static org.kitodo.production.helper.metadata.MediaPartialHelper.convertFormattedTimeToMilliseconds;
import static org.kitodo.production.helper.metadata.MediaPartialHelper.convertTimeToFormattedTime;

import java.io.Serializable;
import java.util.Map;
Expand Down Expand Up @@ -166,6 +167,7 @@ protected boolean valid() {
validationError = "mediaPartialFormStartEmpty";
return false;
}
setBegin(convertTimeToFormattedTime(getBegin()));
if (!MediaPartialHelper.FORMATTED_TIME_PATTERN.matcher(getBegin()).matches()) {
validationError = "mediaPartialFormStartWrongTimeFormat";
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,20 @@
package org.kitodo.production.helper.metadata;

import java.net.URI;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.LocalTime;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Objects;
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.kitodo.api.dataformat.LogicalDivision;
import org.kitodo.api.dataformat.MediaPartial;
Expand All @@ -47,6 +52,33 @@ public static Long convertFormattedTimeToMilliseconds(String formattedTime) {
return Duration.between(LocalTime.MIN, LocalTime.parse(formattedTime)).toMillis();
}

/**
* Convert various time input formats to formatted time.
*
* @param time
* The time input.
* @return The formatted time
*/
public static String convertTimeToFormattedTime(String time) {
if (FORMATTED_TIME_PATTERN.matcher(time).matches()) {
return time;
}

String[] separatedMilliseconds = time.split("\\.");
Date date;
try {
date = DateUtils.parseDate(separatedMilliseconds[0], "HH:mm:ss", "mm:ss", "ss");
if (separatedMilliseconds.length == 2) {
String filledMilliseconds = StringUtils.rightPad(separatedMilliseconds[1], 3, "0");
date = new Date(date.getTime() + Integer.parseInt(filledMilliseconds));
}
} catch (ParseException | NumberFormatException e) {
return time;
}

return new SimpleDateFormat("HH:mm:ss.SSS").format(date);
}

/**
* Convert milliseconds to formatted time.
*
Expand Down
41 changes: 31 additions & 10 deletions Kitodo/src/main/webapp/WEB-INF/resources/css/kitodo.css
Original file line number Diff line number Diff line change
Expand Up @@ -2528,6 +2528,18 @@ form#metadata div label,
color: var(--medium-gray);
}

.columnHeadingWrapper .columnHeading {
color: var(--medium-gray);
}

.columnHeadingWrapper .columnHeading.icon-media-partial {
margin-right: 5px;
}

.columnHeadingWrapper .columnHeading.mediaPartialHeading {
margin-left: 5px;
}

.collapsibleWrapper > .columnExpandButton + .columnHeadingWrapper .columnHeading {
color: var(--carbon-blue);
}
Expand Down Expand Up @@ -3189,6 +3201,12 @@ Column content
min-width: 60px;
}

#imagePreviewForm\:mediaDetailMediaPartial .icon-media-partial {
top: 50px;
left: 10px;
position: absolute;
}

#imagePreviewForm\:mediaPartialList {
height: 100%;
overflow-y: scroll;
Expand Down Expand Up @@ -3465,25 +3483,28 @@ Column content
width: 100%;
}


.thumbnail-container .icon-media-partial {
top: 5px;
color: var(--carbon-blue);
left: 5px;
position: absolute;
background: rgb(from var(--pure-white) r g b / 0.8);
.icon-media-partial {
width: 18px;
display: block;
text-align: center;
padding: 3px;
border-radius: 18px;

}

.thumbnail-container .icon-media-partial::before {
.icon-media-partial::before {
content: "\f08d";
font-family: FontAwesome;
}

.thumbnail-container .icon-media-partial {
color: var(--carbon-blue);
top: 5px;
left: 5px;
position: absolute;
display: block;
border-radius: 18px;
background: rgb(from var(--pure-white) r g b / 0.8);
}

.thumbnail-container .assigned-several-times {
bottom: 5px;
color: var(--pure-white);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**
* (c) Kitodo. Key to digital objects e. V. <[email protected]>
*
* This file is part of the Kitodo project.
*
* It is licensed under GNU General Public License version 3 or later.
*
* For the full copyright and license information, please read the
* GPL3-License.txt file that was distributed with this source code.
*/
/* globals metadataEditor */

let initMediaPartial = function () {
let mediaElement = document.querySelector('#imagePreviewForm\\:mediaDetailMediaContainer video, #imagePreviewForm\\:mediaDetailMediaContainer audio');
let mediaPartial = document.querySelector('#metadataEditorWrapper .columnHeading.mediaPartialHeading');
if (mediaElement && mediaPartial) {
let durationTime = metadataEditor.gallery.mediaPartial.convertFormattedTimeToMilliseconds(mediaPartial.dataset.mediaPartialDuration);
let startTime = metadataEditor.gallery.mediaPartial.convertFormattedTimeToMilliseconds(mediaPartial.dataset.mediaPartialStart);
let stopTime = (startTime + durationTime) / 1000;

mediaElement.addEventListener("timeupdate", function () {
if (mediaElement.currentTime >= stopTime) {
mediaElement.currentTime = stopTime;
mediaElement.pause();
}
});

let onCanPlay = function () {
mediaElement.currentTime = startTime / 1000;
};

mediaElement.addEventListener("play", function () {
mediaElement.removeEventListener("canplay", onCanPlay);
mediaElement.currentTime = startTime / 1000;
});

mediaElement.addEventListener("canplay", onCanPlay);
}
};

initMediaPartial();

document.addEventListener("kitodo-metadataditor-mediaview-update", initMediaPartial);
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
rendered="#{fn:startsWith(selectedGalleryMediaContent.mediaViewMimeType, 'audio') and DataEditorForm.galleryPanel.isAudioMediaViewWaveform()}"/>
<h:outputScript a:type="module" name="js/modules/media_detail_audio_waveform.js"
rendered="#{fn:startsWith(selectedGalleryMediaContent.mediaViewMimeType, 'audio') and DataEditorForm.galleryPanel.isAudioMediaViewWaveform()}"/>

<h:outputScript a:type="module" name="js/modules/media_detail_media_partial.js" rendered="#{selectedGalleryMediaContent.isMediaPartial()}"/>
</p:outputPanel>

<ui:include src="/WEB-INF/templates/includes/metadataEditor/partials/media-detail-media-partial-list.xhtml"/>
Expand Down
19 changes: 15 additions & 4 deletions Kitodo/src/main/webapp/pages/metadataEditor.xhtml
Original file line number Diff line number Diff line change
Expand Up @@ -208,23 +208,34 @@
<h:outputText styleClass="columnHeading" value="#{msgs.gallery}"/>
</ui:fragment>
<ui:fragment rendered="#{DataEditorForm.galleryPanel.galleryViewMode eq 'preview'}">
<ui:param name="selectedGalleryMediaContent"
value="#{DataEditorForm.galleryPanel.getGalleryMediaContent(DataEditorForm.galleryPanel.lastSelection.key)}"/>
<h:outputText styleClass="columnHeading icon-media-partial"
rendered="#{selectedGalleryMediaContent.isMediaPartial()}"/>
<h:outputText styleClass="columnHeading"
rendered="#{DataEditorForm.galleryPanel.hasMediaViewMimeTypePrefix('audio')}"
value="#{msgs.audio}
#{DataEditorForm.galleryPanel.getGalleryMediaContent(DataEditorForm.galleryPanel.lastSelection.key).shortId}"/>
#{selectedGalleryMediaContent.shortId}"/>
<h:outputText styleClass="columnHeading"
rendered="#{DataEditorForm.galleryPanel.hasMediaViewMimeTypePrefix('video')}"
value="#{msgs.video}
#{DataEditorForm.galleryPanel.getGalleryMediaContent(DataEditorForm.galleryPanel.lastSelection.key).shortId}"/>
#{selectedGalleryMediaContent.shortId}"/>
<h:outputText styleClass="columnHeading"
rendered="#{DataEditorForm.galleryPanel.hasMediaViewMimeTypePrefix('image')}"
value="#{msgs.image}
#{DataEditorForm.galleryPanel.getGalleryMediaContent(DataEditorForm.galleryPanel.lastSelection.key).shortId},
#{selectedGalleryMediaContent.shortId},
#{msgs.page}
#{DataEditorForm.galleryPanel.getGalleryMediaContent(DataEditorForm.galleryPanel.lastSelection.key).orderlabel}"/>
#{selectedGalleryMediaContent.orderlabel}"/>
<h:outputText styleClass="columnHeading"
rendered="#{DataEditorForm.galleryPanel.lastSelection eq null}"
value="#{msgs.notSelected}"/>
<ui:param name="mediaPartial"
value="#{selectedGalleryMediaContent.getMediaPartial()}"/>
<h:outputText styleClass="columnHeading mediaPartialHeading"
value="(#{msgs.start}:#{mediaPartial.begin}, #{msgs.duration}:#{mediaPartial.extent})"
rendered="#{selectedGalleryMediaContent.isMediaPartial() and mediaPartial ne null}"
a:data-media-partial-start="#{mediaPartial.begin}"
a:data-media-partial-duration="#{mediaPartial.extent}"/>
</ui:fragment>
</h:panelGroup>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import org.kitodo.api.dataformat.PhysicalDivision;
import org.kitodo.api.dataformat.View;
import org.kitodo.api.dataformat.Workpiece;
import org.kitodo.production.helper.metadata.MediaPartialHelper;
import org.kitodo.production.metadata.MetadataEditor;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
Expand Down Expand Up @@ -179,6 +180,19 @@ public void testValidation() throws NoSuchFieldException, IllegalAccessException
assertTrue(mediaPartialForm.valid());
}

/**
* Test time to formatted time conversion.
*/
@Test
public void testTimeToFormattedTimeConversion() {
assertEquals("00:00:01.000", MediaPartialHelper.convertTimeToFormattedTime("1"));
assertEquals("00:01:01.000", MediaPartialHelper.convertTimeToFormattedTime("1:1"));
assertEquals("01:01:01.000", MediaPartialHelper.convertTimeToFormattedTime("1:1:1"));
assertEquals("00:00:01.100", MediaPartialHelper.convertTimeToFormattedTime("1.1"));
assertEquals("00:01:01.110", MediaPartialHelper.convertTimeToFormattedTime("1:1.11"));
assertEquals("01:01:01.111", MediaPartialHelper.convertTimeToFormattedTime("1:1:1.111"));
}

private static String getValidationError(MediaPartialForm mediaPartialForm)
throws NoSuchFieldException, IllegalAccessException {
Field validationErrorField = mediaPartialForm.getClass().getDeclaredField("validationError");
Expand Down

0 comments on commit 7b1d685

Please sign in to comment.