Skip to content

Commit

Permalink
Merge pull request kitodo#5504 from markusweigelt/video-editor
Browse files Browse the repository at this point in the history
Add media partials for audio and video
  • Loading branch information
solth authored Jan 25, 2024
2 parents c1e6292 + 04a635d commit 39a881e
Show file tree
Hide file tree
Showing 38 changed files with 1,893 additions and 151 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,12 @@ public enum FunctionalDivision {
/**
* A division whose children are created from this division directly.
*/
CREATE_CHILDREN_FROM_PARENT("createChildrenFromParent");
CREATE_CHILDREN_FROM_PARENT("createChildrenFromParent"),

/**
* Indicate the division for media partial usage.
*/
MEDIA_PARTIAL("mediaPartial");

/**
* With the logger, text can be written to a log file or to the console.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* (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.
*/

package org.kitodo.api.dataformat;

import java.util.Objects;

/**
* MediaPartial is part of a {@link PhysicalDivision} of type
* {@link PhysicalDivision#TYPE_TRACK} and contains additional
* information about the start and length.
*/
public class MediaPartial {

private String begin;

private String extent;

/**
* Constructs a media partial object.
*
* @param begin
* The begin as formatted time in form of
* {@link org.kitodo.production.helper.metadata.MediaPartialHelper#FORMATTED_TIME_PATTERN}
*/
public MediaPartial(String begin) {
this.begin = begin;
}

/**
* Constructs a media partial object.
*
* @param begin
* The begin as formatted time in form of
* {@link org.kitodo.production.helper.metadata.MediaPartialHelper#FORMATTED_TIME_PATTERN}
* @param extent
* The extent as formatted time in form of
* {@link org.kitodo.production.helper.metadata.MediaPartialHelper#FORMATTED_TIME_PATTERN}
*/
public MediaPartial(String begin, String extent) {
this(begin);
this.extent = extent;
}

public void setBegin(String begin) {
this.begin = begin;
}

public String getBegin() {
return begin;
}

public String getExtent() {
return extent;
}

public void setExtent(String extent) {
this.extent = extent;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!getClass().isInstance(o)) {
return false;
}

MediaPartial mediaPartial = (MediaPartial) o;

return (Objects.isNull(begin) && Objects.isNull(mediaPartial.begin)) || begin.equals(mediaPartial.getBegin());
}

@Override
public int hashCode() {
final int prime = 31;
return prime * super.hashCode() + Objects.hash(begin, extent);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ public class PhysicalDivision extends Division<PhysicalDivision> {
*/
private Map<MediaVariant, URI> mediaFiles = new HashMap<>();

private MediaPartial mediaPartial;

/**
* Saves the METS identifier for the division.
*/
Expand Down Expand Up @@ -115,6 +117,34 @@ public List<LogicalDivision> getLogicalDivisions() {
return logicalDivisions;
}

/**
* Set the media partial.
*
* @param mediaPartial
* The media partial
*/
public void setMediaPartial(MediaPartial mediaPartial) {
this.mediaPartial = mediaPartial;
}

/**
* Check if physical division has media partial.
*
* @return True if has media partial
*/
public boolean hasMediaPartial() {
return Objects.nonNull(mediaPartial);
}

/**
* Get the media partial.
*
* @return The media partial.
*/
public MediaPartial getMediaPartial() {
return mediaPartial;
}

@Override
public String toString() {
String fileName = "No file (";
Expand All @@ -141,14 +171,18 @@ public boolean equals(Object o) {
return false;
}
PhysicalDivision physicalDivision = (PhysicalDivision) o;
return Objects.equals(mediaFiles, physicalDivision.mediaFiles);
return Objects.equals(mediaFiles, physicalDivision.mediaFiles) && Objects.equals(mediaPartial,
physicalDivision.mediaPartial);
}

@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + ((mediaFiles == null) ? 0 : mediaFiles.hashCode());
result = prime * result + ((Objects.isNull(mediaPartial) || Objects.isNull(mediaPartial.getBegin()))
? 0
: mediaPartial.getBegin().hashCode());
return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,19 @@
import java.util.Optional;

import org.kitodo.api.MdSec;
import org.kitodo.api.dataformat.MediaPartial;
import org.kitodo.api.dataformat.MediaVariant;
import org.kitodo.api.dataformat.PhysicalDivision;
import org.kitodo.api.dataformat.mets.KitodoUUID;
import org.kitodo.dataformat.metskitodo.AmdSecType;
import org.kitodo.dataformat.metskitodo.AreaType;
import org.kitodo.dataformat.metskitodo.DivType;
import org.kitodo.dataformat.metskitodo.DivType.Fptr;
import org.kitodo.dataformat.metskitodo.FileType;
import org.kitodo.dataformat.metskitodo.MdSecType;
import org.kitodo.dataformat.metskitodo.Mets;
import org.kitodo.dataformat.metskitodo.MetsType;
import org.kitodo.utils.MediaUtil;

public class FileXmlElementAccess {

Expand Down Expand Up @@ -66,13 +69,17 @@ public FileXmlElementAccess() {
Map<MediaVariant, URI> mediaFiles = new HashMap<>();
for (Fptr fptr : div.getFptr()) {
Object fileId = fptr.getFILEID();
if (Objects.nonNull(fptr.getArea())) {
physicalDivision.setMediaPartial(
new MediaPartial(fptr.getArea().getBEGIN(), fptr.getArea().getEXTENT()));
fileId = fptr.getArea().getFILEID();
}
if (fileId instanceof FileType) {
FileType file = (FileType) fileId;
String fileUse = fileUseByFileCache.getOrDefault(file, null);
if (Objects.isNull(fileUse)) {
throw new IllegalArgumentException(
"Corrupt file: file use for <mets:fptr> with id " + file.getID() + " not found in <mets:fileGrp>"
);
"Corrupt file: file use for <mets:fptr> with id " + file.getID() + " not found in <mets:fileGrp>");
}
MediaVariant mediaVariant = useXmlAttributeAccess.get(fileUse);
FLocatXmlElementAccess fLocatXmlElementAccess = new FLocatXmlElementAccess(file);
Expand Down Expand Up @@ -110,6 +117,9 @@ public FileXmlElementAccess() {
this.physicalDivision.setOrder(physicalDivision.getOrder());
this.physicalDivision.setOrderlabel(physicalDivision.getOrderlabel());
this.physicalDivision.setType(physicalDivision.getType());
if (physicalDivision.hasMediaPartial()) {
this.physicalDivision.setMediaPartial(physicalDivision.getMediaPartial());
}
}
}

Expand Down Expand Up @@ -144,14 +154,20 @@ DivType toDiv(Map<URI, FileType> mediaFilesToIDFiles,
div.setTYPE(physicalDivision.getType());
for (Entry<MediaVariant, URI> use : physicalDivision.getMediaFiles().entrySet()) {
Fptr fptr = new Fptr();
fptr.setFILEID(mediaFilesToIDFiles.get(use.getValue()));
FileType fileId = mediaFilesToIDFiles.get(use.getValue());
if (PhysicalDivision.TYPE_TRACK.equals(physicalDivision.getType()) && MediaUtil.isAudioOrVideo(
use.getKey().getMimeType()) && physicalDivision.hasMediaPartial()) {
fptr.setArea(getAreaType(fileId));
} else {
fptr.setFILEID(fileId);
}
div.getFptr().add(fptr);
}
Optional<MdSecType> optionalDmdSec = DivXmlElementAccess.createMdSec(physicalDivision.getMetadata(), MdSec.DMD_SEC);
String metsReferrerId = KitodoUUID.randomUUID();
if (optionalDmdSec.isPresent()) {
MdSecType dmdSec = optionalDmdSec.get();
String name = metsReferrerId + ':' + MdSec.DMD_SEC.toString();
String name = metsReferrerId + ':' + MdSec.DMD_SEC;
dmdSec.setID(KitodoUUID.nameUUIDFromBytes(name.getBytes(StandardCharsets.UTF_8)));
mets.getDmdSec().add(dmdSec);
div.getDMDID().add(dmdSec);
Expand All @@ -164,4 +180,17 @@ DivType toDiv(Map<URI, FileType> mediaFilesToIDFiles,
}
return div;
}

private AreaType getAreaType(FileType fileId) {
MediaPartial mediaPartial = physicalDivision.getMediaPartial();
AreaType areaType = new AreaType();
areaType.setFILEID(fileId);
areaType.setBEGIN(mediaPartial.getBegin());
areaType.setBETYPE("TIME");
if (Objects.nonNull(mediaPartial.getExtent()) && !mediaPartial.getExtent().isEmpty()) {
areaType.setEXTENT(mediaPartial.getExtent());
areaType.setEXTTYPE("TIME");
}
return areaType;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,9 @@ public class AddDocStrucTypeDialog {
private static final Logger logger = LogManager.getLogger(AddDocStrucTypeDialog.class);

private final DataEditorForm dataEditor;
private List<SelectItem> docStructAddTypeSelectionItemsForChildren;
private List<SelectItem> docStructAddTypeSelectionItemsForParent;
private List<SelectItem> docStructAddTypeSelectionItemsForSiblings;
private List<SelectItem> selectionItemsForChildren;
private List<SelectItem> selectionItemsForParent;
private List<SelectItem> selectionItemsForSiblings;
private String docStructAddTypeSelectionSelectedItem;
private List<SelectItem> docStructPositionSelectionItems;
private InsertionPosition selectedDocStructPosition = LAST_CHILD_OF_CURRENT_ELEMENT;
Expand Down Expand Up @@ -209,13 +209,13 @@ public List<SelectItem> getDocStructAddTypeSelectionItems() {
switch (selectedDocStructPosition) {
case AFTER_CURRENT_ELEMENT:
case BEFORE_CURRENT_ELEMENT:
return docStructAddTypeSelectionItemsForSiblings;
return selectionItemsForSiblings;
case CURRENT_POSITION:
case FIRST_CHILD_OF_CURRENT_ELEMENT:
case LAST_CHILD_OF_CURRENT_ELEMENT:
return docStructAddTypeSelectionItemsForChildren;
return selectionItemsForChildren;
case PARENT_OF_CURRENT_ELEMENT:
return docStructAddTypeSelectionItemsForParent;
return selectionItemsForParent;
default:
return Collections.emptyList();
}
Expand Down Expand Up @@ -452,32 +452,30 @@ public void prepareDocStructTypes() {
this.parents = MetadataEditor.getAncestorsOfLogicalDivision(selectedStructure.get(),
dataEditor.getWorkpiece().getLogicalStructure());
if (parents.isEmpty()) {
docStructAddTypeSelectionItemsForParent = Collections.emptyList();
selectionItemsForParent = Collections.emptyList();
} else {
prepareDocStructAddTypeSelectionItemsForParent();
}
prepareDocStructAddTypeSelectionItemsForChildren();
prepareDocStructAddTypeSelectionItemsForSiblings();
} else {
docStructAddTypeSelectionItemsForChildren = Collections.emptyList();
docStructAddTypeSelectionItemsForParent = Collections.emptyList();
docStructAddTypeSelectionItemsForSiblings = Collections.emptyList();
selectionItemsForChildren = Collections.emptyList();
selectionItemsForParent = Collections.emptyList();
selectionItemsForSiblings = Collections.emptyList();
}
}

private void prepareDocStructAddTypeSelectionItemsForChildren() {
docStructAddTypeSelectionItemsForChildren = new ArrayList<>();
StructuralElementViewInterface divisionView = dataEditor.getRulesetManagement().getStructuralElementView(
dataEditor.getSelectedStructure().orElseThrow(IllegalStateException::new).getType(),
dataEditor.getAcquisitionStage(), dataEditor.getPriorityList());
for (Entry<String, String> entry : divisionView.getAllowedSubstructuralElements().entrySet()) {
docStructAddTypeSelectionItemsForChildren.add(new SelectItem(entry.getKey(), entry.getValue()));
}
DataEditorService.sortMetadataList(docStructAddTypeSelectionItemsForChildren, dataEditor.getProcess().getRuleset());
selectionItemsForChildren = DataEditorService.getSortedAllowedSubstructuralElements(
dataEditor.getRulesetManagement()
.getStructuralElementView(
dataEditor.getSelectedStructure().orElseThrow(IllegalStateException::new).getType(),
dataEditor.getAcquisitionStage(), dataEditor.getPriorityList()),
dataEditor.getProcess().getRuleset());
}

private void prepareDocStructAddTypeSelectionItemsForParent() {
docStructAddTypeSelectionItemsForParent = new ArrayList<>();
selectionItemsForParent = new ArrayList<>();
if (!parents.isEmpty()) {
StructuralElementViewInterface parentDivisionView = dataEditor.getRulesetManagement().getStructuralElementView(
parents.getLast().getType(), dataEditor.getAcquisitionStage(), dataEditor.getPriorityList());
Expand All @@ -487,22 +485,21 @@ private void prepareDocStructAddTypeSelectionItemsForParent() {
newParent, dataEditor.getAcquisitionStage(), dataEditor.getPriorityList());
if (newParentDivisionView.getAllowedSubstructuralElements().containsKey(
dataEditor.getSelectedStructure().orElseThrow(IllegalStateException::new).getType())) {
docStructAddTypeSelectionItemsForParent.add(new SelectItem(newParent, entry.getValue()));
selectionItemsForParent.add(new SelectItem(newParent, entry.getValue()));
}
}
DataEditorService.sortMetadataList(docStructAddTypeSelectionItemsForParent, dataEditor.getProcess().getRuleset());
DataEditorService.sortMetadataList(selectionItemsForParent,
dataEditor.getProcess().getRuleset());
}
}

private void prepareDocStructAddTypeSelectionItemsForSiblings() {
docStructAddTypeSelectionItemsForSiblings = new ArrayList<>();
selectionItemsForSiblings = new ArrayList<>();
if (!parents.isEmpty()) {
StructuralElementViewInterface parentDivisionView = dataEditor.getRulesetManagement().getStructuralElementView(
parents.getLast().getType(), dataEditor.getAcquisitionStage(), dataEditor.getPriorityList());
for (Entry<String, String> entry : parentDivisionView.getAllowedSubstructuralElements().entrySet()) {
docStructAddTypeSelectionItemsForSiblings.add(new SelectItem(entry.getKey(), entry.getValue()));
}
DataEditorService.sortMetadataList(docStructAddTypeSelectionItemsForSiblings, dataEditor.getProcess().getRuleset());
selectionItemsForSiblings = DataEditorService.getSortedAllowedSubstructuralElements(
dataEditor.getRulesetManagement().getStructuralElementView(
parents.getLast().getType(), dataEditor.getAcquisitionStage(), dataEditor.getPriorityList()),
dataEditor.getProcess().getRuleset());
}
}

Expand Down
Loading

0 comments on commit 39a881e

Please sign in to comment.