Verified Commit dbbf584a authored by Sebastian Schüpbach's avatar Sebastian Schüpbach
Browse files

create file extension based on MediaFileType



Signed-off-by: Sebastian Schüpbach's avatarSebastian Schüpbach <sebastian.schuepbach@unibas.ch>
parent 70e4e7bc
Pipeline #11942 passed with stages
in 10 minutes and 55 seconds
......@@ -21,6 +21,8 @@ package ch.memobase
import java.io.{ByteArrayOutputStream, FileOutputStream, IOException}
import java.nio.file.{Files, Path, Paths}
import ch.memobase.models.{Conversions, MediaFileType}
import scala.util.{Failure, Success, Try}
/**
......@@ -48,29 +50,17 @@ class DisseminationCopyHandler(audioDestPath: String, imageDestPath: String, vid
}
}
/**
* Creates destination filename
*
* @param id id (signature) of record to which the media resource belongs to
* @param collectionId id of collection to which the media resource belongs to
* @param institutionId id of institution to which the media resource belongs to
* @return generated filename
*/
private def createDestFilename(id: String, collectionId: String, institutionId: String): String = {
// TODO: Create real filename producing function
s"$institutionId-$collectionId-$id"
}
/**
* Creates dissemination copy of audio file
*
* @param data binary data as [[java.io.ByteArrayOutputStream]] instance
* @param destId Filename of dissemination copy without extension
* @param data binary data as [[java.io.ByteArrayOutputStream]] instance
* @param destId Filename of dissemination copy without extension
* @param sourceFileType File type of input data
* @return
*/
def createAudioCopy(data: ByteArrayOutputStream, destId: String): Try[Path] = Try {
val tempFilePath = Files.createTempFile("media-", null)
def createAudioCopy(data: ByteArrayOutputStream, destId: String, sourceFileType: MediaFileType): Try[Path] = Try {
val tempFilePath = Files.createTempFile("media-", "." + Conversions.getFileTypeExtension(sourceFileType).get)
val destFile = Paths.get(audioDestPath, destId + ".mp4")
writeData(data, tempFilePath)
Transformations.audioToMp4(tempFilePath.toString, destFile.toString).get
......@@ -81,13 +71,15 @@ class DisseminationCopyHandler(audioDestPath: String, imageDestPath: String, vid
/**
* Creates dissemination copy of image file
*
* @param data binary data as [[java.io.ByteArrayOutputStream]] instance
* @param destId Filename of dissemination copy without extension
* @param data binary data as [[java.io.ByteArrayOutputStream]] instance
* @param destId Filename of dissemination copy without extension
* @param sourceFileType File type of input data
* @return
*/
def createImageCopy(data: ByteArrayOutputStream, destId: String): Try[Path] = Try {
val tempFilePath = Files.createTempFile("media-", null)
def createImageCopy(data: ByteArrayOutputStream, destId: String, sourceFileType: MediaFileType): Try[Path] = Try {
val tempFilePath = Files.createTempFile("media-", "." + Conversions.getFileTypeExtension(sourceFileType).get)
val destFile = Paths.get(imageDestPath, destId + ".jp2")
writeData(data, tempFilePath)
Transformations.imageToJp2(tempFilePath.toString, destFile.toString).get
Files.delete(tempFilePath)
destFile
......@@ -96,12 +88,13 @@ class DisseminationCopyHandler(audioDestPath: String, imageDestPath: String, vid
/**
* Create dissemination copy of video file
*
* @param data binary data as [[java.io.ByteArrayOutputStream]] instance
* @param destId Filename of dissemination copy without extension
* @param data binary data as [[java.io.ByteArrayOutputStream]] instance
* @param destId Filename of dissemination copy without extension
* @param sourceFileType File type of input data
* @return
*/
def createVideoCopy(data: ByteArrayOutputStream, destId: String): Try[Path] = {
val destFile = Paths.get(videoDestPath, destId + ".mp4")
def createVideoCopy(data: ByteArrayOutputStream, destId: String, sourceFileType: MediaFileType): Try[Path] = {
val destFile = Paths.get(videoDestPath, s"$destId.${Conversions.getFileTypeExtension(sourceFileType).get}")
writeData(data, destFile)
}
......@@ -130,12 +123,13 @@ class DisseminationCopyHandler(audioDestPath: String, imageDestPath: String, vid
/**
* Deletes dissemination copy of video file
*
* @param destId Filename of dissemination copy without extension
* @param destId Filename of dissemination copy without extension
* @param fileType File type of media
* @return
*/
def deleteVideoCopy(destId: String): Try[Boolean] =
def deleteVideoCopy(destId: String, fileType: MediaFileType): Try[Boolean] =
Try {
Paths.get(videoDestPath, destId + ".mp4").toFile.delete()
Paths.get(videoDestPath, s"$destId.${Conversions.getFileTypeExtension(fileType).get}").toFile.delete()
}
}
......@@ -73,14 +73,12 @@ object FedoraClientWrapper {
new FedoraClientWrapper(fc)
}
private def getMediaFileType(mimeType: String): Try[MediaFileType] = mimeType match {
case "audio/mpeg" => Success(Mp3File)
// case "audio/ogg" => OggFile
case "image/jpg" => Success(JpegFile)
case "video/mp4" => Success(VideoMpeg4File)
// TODO: Other filetypes...
case mT => Failure(new UnmanageableMediaFileType(s"Can't handle files of type $mT"))
}
private def getMediaFileType(mimeType: String): Try[MediaFileType] =
Conversions.getMediaFileType(mimeType) match {
case Some(ft) => Success(ft)
case None =>
Failure(new UnmanageableMediaFileType(s"Can't handle files of type $mimeType"))
}
private def copyDataAndCloseResource(binaryResource: BinaryResource): Try[ByteArrayOutputStream] = {
val outputStream: Try[ByteArrayOutputStream] = Try {
......
......@@ -46,15 +46,15 @@ class RecordProcessor(fileHandler: DisseminationCopyHandler, fedoraClientWrapper
fileWithMetadata <- fedoraClientWrapper.fetchBinaryResource(kafkaMsg.filePath)
} yield (kafkaMsg.id, kafkaMsg.eventType, fileWithMetadata.fileType, fileWithMetadata.data) match {
case (id, Create | Update, af: AudioFileType, data) =>
errorHandler(fileHandler.createAudioCopy(data, id), id, af, "Create/Update")
errorHandler(fileHandler.createAudioCopy(data, id, af), id, af, "Create/Update")
case (id, Delete, af: AudioFileType, _) =>
errorHandler(fileHandler.deleteAudioCopy(id), id, af, "Delete")
case (id, Create | Update, vf: VideoFileType, data) =>
errorHandler(fileHandler.createVideoCopy(data, id), id, vf, "Create/Update")
errorHandler(fileHandler.createVideoCopy(data, id, vf), id, vf, "Create/Update")
case (id, Delete, vf: VideoFileType, _) =>
errorHandler(fileHandler.deleteVideoCopy(id), id, vf, "Delete")
errorHandler(fileHandler.deleteVideoCopy(id, vf), id, vf, "Delete")
case (id, Create | Update, i: ImageFileType, data) =>
errorHandler(fileHandler.createImageCopy(data, id), id, i, "Create/Update")
errorHandler(fileHandler.createImageCopy(data, id, i), id, i, "Create/Update")
case (id, Delete, i: ImageFileType, _) =>
errorHandler(fileHandler.deleteImageCopy(id), id, i, "Delete")
case (id, event, ft, _) =>
......
......@@ -48,6 +48,11 @@ case object UnknownFileType extends MediaFileType
*/
case object Mp3File extends AudioFileType
/**
* Represents an OGA file
*/
case object OgaFile extends AudioFileType
/**
* Represents a JPG file
*/
......@@ -57,3 +62,26 @@ case object JpegFile extends ImageFileType
* Represents a MPEG4 video file
*/
case object VideoMpeg4File extends VideoFileType
/**
* Helps with conversions between different representations of file types
*/
object Conversions {
private val fileTypeTuples: List[(MediaFileType, List[String], String)] = List(
(Mp3File, List("audio/mpeg"), "mp3"),
(OgaFile, List("audio/ogg"), "oga"),
(JpegFile, List("image/jpg"), "jpg"),
(VideoMpeg4File, List("video/mp4"), "mp4")
// TODO: Other filetypes...
)
lazy val getMediaFileType: String => Option[MediaFileType] = (mimeType: String) =>
fileTypeTuples.collectFirst {
case (ft, mt, _) if mt.contains(mimeType) => ft
}
lazy val getFileTypeExtension: MediaFileType => Option[String] = (mediaFileType: MediaFileType) =>
fileTypeTuples.collectFirst {
case (ft, _, ex) if ft == mediaFileType => ex
}
}
\ No newline at end of file
......@@ -21,6 +21,7 @@ package ch.memobase
import java.io.{ByteArrayOutputStream, File, FileInputStream}
import java.nio.file.{Files, Path, Paths}
import ch.memobase.models.{JpegFile, MediaFileType, Mp3File, VideoMpeg4File}
import org.scalatest.funsuite.AnyFunSuite
import org.scalatest.{Assertion, BeforeAndAfter}
......@@ -45,7 +46,7 @@ class DisseminationCopyHandlerTest extends AnyFunSuite with BeforeAndAfter {
}
}
private def testCopy(pathToTmpDir: String, sourceFileName: String, destFileName: String, copyFun: (ByteArrayOutputStream, String) => Try[Path]): Assertion = {
private def testCopy(pathToTmpDir: String, sourceFileName: String, destFileName: String, fileType: MediaFileType, copyFun: (ByteArrayOutputStream, String, MediaFileType) => Try[Path]): Assertion = {
val file = Paths.get(pathToTmpDir, sourceFileName).toFile
val data = new ByteArrayOutputStream(file.length().toInt)
val buffer = new Array[Byte](1024)
......@@ -56,7 +57,7 @@ class DisseminationCopyHandlerTest extends AnyFunSuite with BeforeAndAfter {
len = in.read(buffer)
}
Paths.get(pathToTmpDir, destFileName).toFile.deleteOnExit()
copyFun(data, destFileName.split('.')(0))
copyFun(data, destFileName.split('.')(0), fileType)
assert(Paths.get(pathToTmpDir, destFileName).toFile.exists())
}
......@@ -69,17 +70,17 @@ class DisseminationCopyHandlerTest extends AnyFunSuite with BeforeAndAfter {
test("calling the copyAudio function should create temporary file") {
val f = fixture
testCopy(f.resPath, "sample.mp3", "test.mp4", f.fileHandler.createAudioCopy)
testCopy(f.resPath, "sample.mp3", "test.mp4", Mp3File, f.fileHandler.createAudioCopy)
}
test("calling the copyImage function should create temporary file") {
val f = fixture
testCopy(f.resPath, "sample.jpg", "test.jp2", f.fileHandler.createImageCopy)
testCopy(f.resPath, "sample.jpg", "test.jp2", JpegFile, f.fileHandler.createImageCopy)
}
test("calling the copyVideo function should create temporary file") {
val f = fixture
testCopy(f.resPath, "sample.mp4", "test.mp4", f.fileHandler.createVideoCopy)
testCopy(f.resPath, "sample.mp4", "test.mp4", VideoMpeg4File, f.fileHandler.createVideoCopy)
}
}
......@@ -84,7 +84,7 @@ class RecordProcessorTest extends AnyFunSuite with MockFactory {
val mockFCW = f.mockFedoraClientWrapper
val (incomingMessage, baos) = createIncomingMessage(Create, JpegFile)
(mockFCW.fetchBinaryResource _).expects(f.pathToResource).returning(Success(FileWithMetadata(baos, JpegFile)))
(mockDCH.createImageCopy _).expects(baos, f.resourceId)
(mockDCH.createImageCopy _).expects(baos, f.resourceId, JpegFile)
val rP = new RecordProcessor(mockDCH, mockFCW, f.externalBaseUrl)
val cR = new ConsumerRecord[String, String]("_void", 1, 0, "1", incomingMessage)
rP.process(cR)
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment