Renamed events to simplify, updated ui

This commit is contained in:
bskjon 2025-03-10 22:58:11 +01:00
parent ac4f79ff7a
commit 3c7532ba17
42 changed files with 241 additions and 188 deletions

View File

@ -64,7 +64,7 @@ class Coordinator(
}
fun permitWorkToProceedOn(referenceId: String, events: List<Event>, message: String) {
val defaultRequiredBy = listOf(Events.ParameterEncodeCreated, Events.ParameterExtractCreated)
val defaultRequiredBy = listOf(Events.EncodeParameterCreated, Events.ExtractParameterCreated)
val eventToAttachTo = if (events.any { it.eventType in defaultRequiredBy }) {
events.findLast { it.eventType in defaultRequiredBy }
} else events.find { it.eventType == Events.ProcessStarted }

View File

@ -53,6 +53,23 @@ class RequestEventController(@Autowired var coordinator: Coordinator) {
return ResponseEntity.ok(referenceId)
}
@PostMapping("/encode")
@ResponseStatus(HttpStatus.OK)
fun requestEncode(@RequestBody payload: EventRequest): ResponseEntity<String> {
var referenceId: String?
try {
val file = File(payload.file)
if (!file.exists()) {
return ResponseEntity.status(HttpStatus.NO_CONTENT).body(Gson().toJson(payload))
}
referenceId = coordinator.startProcess(file, payload.mode, listOf(OperationEvents.ENCODE)).toString()
} catch (e: Exception) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(Gson().toJson(payload))
}
return ResponseEntity.ok(referenceId)
}
@PostMapping("/all")
@ResponseStatus(HttpStatus.OK)
fun requestAll(@RequestBody payload: EventRequest): ResponseEntity<String> {

View File

@ -23,7 +23,7 @@ class BaseInfoFromFileTaskListener() : CoordinatorEventListener() {
val log = KotlinLogging.logger {}
override val produceEvent: Events = Events.ReadBaseInfoPerformed
override val produceEvent: Events = Events.BaseInfoRead
override val listensForEvents: List<Events> = listOf(Events.ProcessStarted)
override fun getProducerName(): String {

View File

@ -46,11 +46,11 @@ class CompletedTaskListener : CoordinatorEventListener() {
override val produceEvent: Events = Events.ProcessCompleted
override val listensForEvents: List<Events> = listOf(
Events.WorkDownloadCoverPerformed,
Events.WorkConvertPerformed,
Events.WorkEncodePerformed,
Events.WorkExtractPerformed,
Events.PersistContentPerformed
Events.CoverDownloaded,
Events.ConvertTaskCompleted,
Events.EncodeTaskCompleted,
Events.ExtractTaskCompleted,
Events.PersistContent
)
@ -83,7 +83,7 @@ class CompletedTaskListener : CoordinatorEventListener() {
fun getVideo(events: List<Event>): VideoDetails? {
val mediaInfo = events.find { it.eventType == Events.ReadOutNameAndType }?.az<MediaOutInformationConstructedEvent>()
val encoded = events.find { it.eventType == Events.WorkEncodePerformed }?.dataAs<EncodedData>()?.outputFile
val encoded = events.find { it.eventType == Events.EncodeTaskCompleted }?.dataAs<EncodedData>()?.outputFile
if (encoded == null) {
log.warn { "No encode no video details!" }
return null
@ -108,7 +108,7 @@ class CompletedTaskListener : CoordinatorEventListener() {
override fun shouldIProcessAndHandleEvent(incomingEvent: Event, events: List<Event>): Boolean {
val result = super.shouldIProcessAndHandleEvent(incomingEvent, events)
return result && incomingEvent.eventType == Events.PersistContentPerformed
return result && incomingEvent.eventType == Events.PersistContent
}
override fun onEventsReceived(incomingEvent: ConsumableEvent<Event>, events: List<Event>) {
@ -130,7 +130,7 @@ class CompletedTaskListener : CoordinatorEventListener() {
val genreIdsForCatalog = ContentGenresStore.storeAndGetIds(mediaInfo.genres)
val persistedContent: PersistedContent? = events.find { it.eventType == Events.PersistContentPerformed }?.az<PersistedContentEvent>()?.data
val persistedContent: PersistedContent? = events.find { it.eventType == Events.PersistContent }?.az<PersistedContentEvent>()?.data
if (persistedContent == null) {
log.error { "PersistedContent is null! can't continue" }
return
@ -226,10 +226,10 @@ class CompletedTaskListener : CoordinatorEventListener() {
private fun composeMediaInfo(events: List<Event>): ComposedMediaInfo? {
val baseInfo =
events.find { it.eventType == Events.ReadBaseInfoPerformed }?.az<BaseInfoEvent>()?.let {
events.find { it.eventType == Events.BaseInfoRead }?.az<BaseInfoEvent>()?.let {
it.data
} ?: run {
log.info { "Cant find BaseInfoEvent on ${Events.ReadBaseInfoPerformed}" }
log.info { "Cant find BaseInfoEvent on ${Events.BaseInfoRead}" }
return null
}
val metadataInfo = getMetadata(events)

View File

@ -26,9 +26,9 @@ class ConvertWorkTaskListener: WorkTaskListener() {
@Autowired
override var coordinator: Coordinator? = null
override val produceEvent: Events = Events.WorkConvertCreated
override val produceEvent: Events = Events.ConvertTaskCreated
override val listensForEvents: List<Events> = listOf(
Events.WorkExtractPerformed
Events.ExtractTaskCompleted
)
override fun canProduceMultipleEvents(): Boolean {
@ -63,7 +63,7 @@ class ConvertWorkTaskListener: WorkTaskListener() {
var storeAsFile: String? = null
val file = if (event.eventType == Events.WorkExtractPerformed) {
val file = if (event.eventType == Events.ExtractTaskCompleted) {
val foundEvent = event.az<ExtractWorkPerformedEvent>()?.data
language = foundEvent?.language
storeAsFile = foundEvent?.storeFileName
@ -74,7 +74,7 @@ class ConvertWorkTaskListener: WorkTaskListener() {
startEvent.file
} else null
} else {
events.find { it.eventType == Events.WorkExtractPerformed }
events.find { it.eventType == Events.ExtractTaskCompleted }
?.az<ExtractWorkPerformedEvent>()?.data?.outputFile
}

View File

@ -24,7 +24,7 @@ class CoverDownloadTaskListener : CoordinatorEventListener() {
@Autowired
override var coordinator: Coordinator? = null
override val produceEvent: Events = Events.WorkDownloadCoverPerformed
override val produceEvent: Events = Events.CoverDownloaded
override val listensForEvents: List<Events> = listOf(Events.ReadOutCover)
override fun onEventsReceived(incomingEvent: ConsumableEvent<Event>, events: List<Event>) {
val event = incomingEvent.consume()

View File

@ -52,7 +52,7 @@ class CoverFromMetadataTaskListener: CoordinatorEventListener() {
}
active = true
val baseInfo = events.find { it.eventType == Events.ReadBaseInfoPerformed }?.az<BaseInfoEvent>()?.data
val baseInfo = events.find { it.eventType == Events.BaseInfoRead }?.az<BaseInfoEvent>()?.data
if (baseInfo == null) {
log.info { "No base info" }
active = false

View File

@ -25,10 +25,10 @@ class EncodeWorkArgumentsTaskListener: CoordinatorEventListener() {
@Autowired
override var coordinator: Coordinator? = null
override val produceEvent: Events = Events.ParameterEncodeCreated
override val produceEvent: Events = Events.EncodeParameterCreated
override val listensForEvents: List<Events> = listOf(
Events.ParseStreamPerformed,
Events.StreamParsed,
Events.ReadOutNameAndType
)
val preference = Preference.getPreference()
@ -55,7 +55,7 @@ class EncodeWorkArgumentsTaskListener: CoordinatorEventListener() {
active = false
return
}
val streams = events.find { it.eventType == Events.ParseStreamPerformed }?.az<MediaFileStreamsParsedEvent>()?.data
val streams = events.find { it.eventType == Events.StreamParsed }?.az<MediaFileStreamsParsedEvent>()?.data
if (streams == null) {
active = false
return

View File

@ -26,9 +26,9 @@ class EncodeWorkTaskListener : WorkTaskListener() {
@Autowired
override var coordinator: Coordinator? = null
override val produceEvent: Events = Events.WorkEncodeCreated
override val produceEvent: Events = Events.EncodeTaskCreated
override val listensForEvents: List<Events> = listOf(
Events.ParameterEncodeCreated,
Events.EncodeParameterCreated,
Events.WorkProceedPermitted
)
@ -43,10 +43,10 @@ class EncodeWorkTaskListener : WorkTaskListener() {
}
active = true
val encodeArguments = if (event.eventType == Events.ParameterEncodeCreated) {
val encodeArguments = if (event.eventType == Events.EncodeParameterCreated) {
event.az<EncodeArgumentCreatedEvent>()?.data
} else {
events.find { it.eventType == Events.ParameterEncodeCreated }
events.find { it.eventType == Events.EncodeParameterCreated }
?.az<EncodeArgumentCreatedEvent>()?.data
}
if (encodeArguments == null) {

View File

@ -23,9 +23,9 @@ class ExtractWorkArgumentsTaskListener: CoordinatorEventListener() {
@Autowired
override var coordinator: Coordinator? = null
override val produceEvent: Events = Events.ParameterExtractCreated
override val produceEvent: Events = Events.ExtractParameterCreated
override val listensForEvents: List<Events> = listOf(
Events.ParseStreamPerformed,
Events.StreamParsed,
Events.ReadOutNameAndType
)
@ -47,7 +47,7 @@ class ExtractWorkArgumentsTaskListener: CoordinatorEventListener() {
active = false
return
}
val streams = events.find { it.eventType == Events.ParseStreamPerformed }?.az<MediaFileStreamsParsedEvent>()?.data
val streams = events.find { it.eventType == Events.StreamParsed }?.az<MediaFileStreamsParsedEvent>()?.data
if (streams == null) {
active = false
return

View File

@ -26,9 +26,9 @@ class ExtractWorkTaskListener: WorkTaskListener() {
@Autowired
override var coordinator: Coordinator? = null
override val produceEvent: Events = Events.WorkExtractCreated
override val produceEvent: Events = Events.ExtractTaskCreated
override val listensForEvents: List<Events> = listOf(
Events.ParameterExtractCreated,
Events.ExtractParameterCreated,
Events.WorkProceedPermitted
)
@ -45,10 +45,10 @@ class ExtractWorkTaskListener: WorkTaskListener() {
}
active = true
val arguments = if (event.eventType == Events.ParameterExtractCreated) {
val arguments = if (event.eventType == Events.ExtractParameterCreated) {
event.az<ExtractArgumentCreatedEvent>()?.data
} else {
events.find { it.eventType == Events.ParameterExtractCreated }
events.find { it.eventType == Events.ExtractParameterCreated }
?.az<ExtractArgumentCreatedEvent>()?.data
}
if (arguments == null) {

View File

@ -48,9 +48,9 @@ class MediaOutInformationTaskListener: CoordinatorEventListener() {
active = true
val metadataResult = event.az<MediaMetadataReceivedEvent>()
val mediaBaseInfo = events.findLast { it.eventType == Events.ReadBaseInfoPerformed }?.az<BaseInfoEvent>()?.data
val mediaBaseInfo = events.findLast { it.eventType == Events.BaseInfoRead }?.az<BaseInfoEvent>()?.data
if (mediaBaseInfo == null) {
log.error { "Required event ${Events.ReadBaseInfoPerformed} is not present" }
log.error { "Required event ${Events.BaseInfoRead} is not present" }
coordinator?.produceNewEvent(
MediaOutInformationConstructedEvent(
metadata = event.makeDerivedEventInfo(EventStatus.Failed, getProducerName())

View File

@ -42,7 +42,7 @@ class MetadataWaitOrDefaultTaskListener() : CoordinatorEventListener() {
override val produceEvent: Events = Events.MetadataSearchPerformed
override val listensForEvents: List<Events> = listOf(
Events.ReadBaseInfoPerformed,
Events.BaseInfoRead,
Events.MetadataSearchPerformed
)
@ -58,7 +58,7 @@ class MetadataWaitOrDefaultTaskListener() : CoordinatorEventListener() {
if (metadataTimeoutMinutes <= 0) {
return
}
val hasReadBaseInfo = events.any { it.eventType == Events.ReadBaseInfoPerformed && it.isSuccessful() }
val hasReadBaseInfo = events.any { it.eventType == Events.BaseInfoRead && it.isSuccessful() }
val hasMetadataSearched = events.any { it.eventType == Events.MetadataSearchPerformed }
val hasPollerForMetadataEvent = waitingProcessesForMeta.containsKey(incomingEvent.metadata().referenceId)
@ -76,7 +76,7 @@ class MetadataWaitOrDefaultTaskListener() : CoordinatorEventListener() {
return
}
val baseInfo = events.find { it.eventType == Events.ReadBaseInfoPerformed}?.az<BaseInfoEvent>()?.data
val baseInfo = events.find { it.eventType == Events.BaseInfoRead}?.az<BaseInfoEvent>()?.data
if (baseInfo == null) {
log.error { "BaseInfoEvent is null for referenceId: ${consumedIncoming.metadata.referenceId} on eventId: ${consumedIncoming.metadata.eventId}" }
return

View File

@ -31,9 +31,9 @@ class ParseMediaFileStreamsTaskListener() : CoordinatorEventListener() {
override var coordinator: Coordinator? = null
override val produceEvent: Events = Events.ParseStreamPerformed
override val produceEvent: Events = Events.StreamParsed
override val listensForEvents: List<Events> = listOf(
Events.ReadStreamPerformed
Events.StreamRead
)
override fun shouldIProcessAndHandleEvent(incomingEvent: Event, events: List<Event>): Boolean {

View File

@ -39,12 +39,12 @@ class PersistContentTaskListener : CoordinatorEventListener() {
@Autowired
override var coordinator: Coordinator? = null
override val produceEvent: Events = Events.PersistContentPerformed
override val produceEvent: Events = Events.PersistContent
override val listensForEvents: List<Events> = listOf(
Events.WorkDownloadCoverPerformed,
Events.WorkConvertPerformed,
Events.WorkEncodePerformed,
Events.WorkExtractPerformed
Events.CoverDownloaded,
Events.ConvertTaskCompleted,
Events.EncodeTaskCompleted,
Events.ExtractTaskCompleted
)
@ -130,10 +130,10 @@ class PersistContentTaskListener : CoordinatorEventListener() {
private fun composeMediaInfo(events: List<Event>): ComposedMediaInfo? {
val baseInfo =
events.find { it.eventType == Events.ReadBaseInfoPerformed }?.az<BaseInfoEvent>()?.let {
events.find { it.eventType == Events.BaseInfoRead }?.az<BaseInfoEvent>()?.let {
it.data
} ?: run {
log.info { "Cant find BaseInfoEvent on ${Events.ReadBaseInfoPerformed}" }
log.info { "Cant find BaseInfoEvent on ${Events.BaseInfoRead}" }
return null
}
val metadataInfo =

View File

@ -35,7 +35,7 @@ class ReadMediaFileStreamsTaskListener() : CoordinatorEventListener() {
val log = KotlinLogging.logger {}
val requiredOperations = listOf(OperationEvents.ENCODE, OperationEvents.EXTRACT)
override val produceEvent: Events = Events.ReadStreamPerformed
override val produceEvent: Events = Events.StreamRead
override val listensForEvents: List<Events> = listOf(Events.ProcessStarted)
override fun shouldIProcessAndHandleEvent(incomingEvent: Event, events: List<Event>): Boolean {

View File

@ -33,26 +33,26 @@ class EventsSummaryMapping {
}
fun isEncodedSuccessful(events: List<Event>) = events.filter { it.eventType == Events.WorkEncodePerformed }.any { it.isSuccessful() }
fun isExtractedSuccessful(events: List<Event>) = events.filter { it.eventType == Events.WorkExtractPerformed }.any { it.isSuccessful() }
fun isConvertedSuccessful(events: List<Event>) = events.filter { it.eventType == Events.WorkConvertPerformed }.any { it.isSuccessful() }
fun isEncodedSuccessful(events: List<Event>) = events.filter { it.eventType == Events.EncodeTaskCompleted }.any { it.isSuccessful() }
fun isExtractedSuccessful(events: List<Event>) = events.filter { it.eventType == Events.ExtractTaskCompleted }.any { it.isSuccessful() }
fun isConvertedSuccessful(events: List<Event>) = events.filter { it.eventType == Events.ConvertTaskCompleted }.any { it.isSuccessful() }
fun getProducesFiles(events: List<Event>): OutputFiles {
val encoded = if (isEncodedSuccessful(events)) {
events.filter { it.eventType == Events.WorkEncodePerformed }
events.filter { it.eventType == Events.EncodeTaskCompleted }
.filter { it.isSuccessful() }
.mapNotNull { it.dataAs<EncodedData>()?.outputFile }
} else emptyList()
val extracted = if (isExtractedSuccessful(events)) {
events.filter { it.eventType == Events.WorkExtractPerformed }
events.filter { it.eventType == Events.ExtractTaskCompleted }
.filter { it.isSuccessful() }
.mapNotNull { it.dataAs<ExtractedData>() }
.map { it.outputFile }
} else emptyList()
val converted = if (isConvertedSuccessful(events)) {
events.filter { it.eventType == Events.WorkConvertPerformed }
events.filter { it.eventType == Events.ConvertTaskCompleted }
.filter { it.isSuccessful() }
.mapNotNull { it.dataAs<ConvertedData>() }
.flatMap { it.outputFiles }

View File

@ -27,7 +27,7 @@ class ContentCompletionMover(val collection: String, val events: List<Event>) {
* @return Pair<OldPath, NewPath> or null if no file found
*/
fun moveVideo(): Pair<String, String>? {
val encodedFile = events.find { it.eventType == Events.WorkEncodePerformed }?.dataAs<EncodedData>()?.outputFile?.let {
val encodedFile = events.find { it.eventType == Events.EncodeTaskCompleted }?.dataAs<EncodedData>()?.outputFile?.let {
File(it)
} ?: return null
if (!encodedFile.exists()) {
@ -44,7 +44,7 @@ class ContentCompletionMover(val collection: String, val events: List<Event>) {
}
fun moveCover(): Pair<String, String>? {
val coverFile = events.find { it.eventType == Events.WorkDownloadCoverPerformed }?.
val coverFile = events.find { it.eventType == Events.CoverDownloaded }?.
az<MediaCoverDownloadedEvent>()?.data?.absoluteFilePath?.let {
File(it)
} ?: return null
@ -74,9 +74,9 @@ class ContentCompletionMover(val collection: String, val events: List<Event>) {
fun getMovableSubtitles(): List<MovableSubtitle> {
val extracted =
events.filter { it.eventType == Events.WorkExtractPerformed }.mapNotNull { it.dataAs<ExtractedData>() }
events.filter { it.eventType == Events.ExtractTaskCompleted }.mapNotNull { it.dataAs<ExtractedData>() }
val converted =
events.filter { it.eventType == Events.WorkConvertPerformed }.mapNotNull { it.dataAs<ConvertedData>() }
events.filter { it.eventType == Events.ConvertTaskCompleted }.mapNotNull { it.dataAs<ConvertedData>() }
val items = mutableListOf<MovableSubtitle>()

View File

@ -19,11 +19,11 @@ object CompletionValidator {
*/
fun req1(started: MediaProcessStartEvent, events: List<Event>): Boolean {
val encodeFulfilledOrSkipped = if (started.data?.operations?.contains(OperationEvents.ENCODE) == true) {
events.any { it.eventType == Events.ParameterEncodeCreated }
events.any { it.eventType == Events.EncodeParameterCreated }
} else true
val extractFulfilledOrSkipped = if (started.data?.operations?.contains(OperationEvents.EXTRACT) == true) {
events.any { it.eventType == Events.ParameterExtractCreated }
events.any { it.eventType == Events.ExtractParameterCreated }
} else true
if (!encodeFulfilledOrSkipped || !extractFulfilledOrSkipped) {
@ -37,21 +37,21 @@ object CompletionValidator {
*/
fun req2(operations: List<OperationEvents>, events: List<Event>): Boolean {
if (OperationEvents.ENCODE in operations) {
val encodeParamter = events.find { it.eventType == Events.ParameterEncodeCreated }?.az<EncodeArgumentCreatedEvent>()
val encodeWork = events.find { it.eventType == Events.WorkEncodeCreated }
val encodeParamter = events.find { it.eventType == Events.EncodeParameterCreated }?.az<EncodeArgumentCreatedEvent>()
val encodeWork = events.find { it.eventType == Events.EncodeTaskCreated }
if (encodeParamter?.isSuccessful() == true && (encodeWork == null))
return false
}
val extractParamter = events.find { it.eventType == Events.ParameterExtractCreated }?.az<ExtractArgumentCreatedEvent>()
val extractWork = events.filter { it.eventType == Events.WorkExtractCreated }
val extractParamter = events.find { it.eventType == Events.ExtractParameterCreated }?.az<ExtractArgumentCreatedEvent>()
val extractWork = events.filter { it.eventType == Events.ExtractTaskCreated }
if (OperationEvents.EXTRACT in operations) {
if (extractParamter?.isSuccessful() == true && extractParamter.data?.size != extractWork.size)
return false
}
if (OperationEvents.CONVERT in operations) {
val convertWork = events.filter { it.eventType == Events.WorkConvertCreated }
val convertWork = events.filter { it.eventType == Events.ConvertTaskCreated }
val supportedSubtitleFormats = SubtitleFormats.entries.map { it.name }
val eventsSupportsConvert = extractWork.filter { it.data is ExtractArgumentData }
@ -69,22 +69,22 @@ object CompletionValidator {
*/
fun req3(operations: List<OperationEvents>, events: List<Event>): Boolean {
if (OperationEvents.ENCODE in operations) {
val encodeWork = events.filter { it.eventType == Events.WorkEncodeCreated }
val encodePerformed = events.filter { it.eventType == Events.WorkEncodePerformed }
val encodeWork = events.filter { it.eventType == Events.EncodeTaskCreated }
val encodePerformed = events.filter { it.eventType == Events.EncodeTaskCompleted }
if (encodePerformed.size < encodeWork.size)
return false
}
if (OperationEvents.EXTRACT in operations) {
val extractWork = events.filter { it.eventType == Events.WorkExtractCreated }
val extractPerformed = events.filter { it.eventType == Events.WorkExtractPerformed }
val extractWork = events.filter { it.eventType == Events.ExtractTaskCreated }
val extractPerformed = events.filter { it.eventType == Events.ExtractTaskCompleted }
if (extractPerformed.size < extractWork.size)
return false
}
if (OperationEvents.CONVERT in operations) {
val convertWork = events.filter { it.eventType == Events.WorkConvertCreated }
val convertPerformed = events.filter { it.eventType == Events.WorkConvertPerformed }
val convertWork = events.filter { it.eventType == Events.ConvertTaskCreated }
val convertPerformed = events.filter { it.eventType == Events.ConvertTaskCompleted }
if (convertPerformed.size < convertWork.size)
return false
}
@ -110,7 +110,7 @@ object CompletionValidator {
return true
}
if (events.any { it.eventType == Events.ReadOutCover } && events.any { it.eventType == Events.WorkDownloadCoverPerformed }) {
if (events.any { it.eventType == Events.ReadOutCover } && events.any { it.eventType == Events.CoverDownloaded }) {
return true
}
return false

View File

@ -21,7 +21,7 @@ class ConvertWorkTaskListenerTest {
@Test
fun validateCreationOfConvertTasks() {
val listener: ConvertWorkTaskListener = ConvertWorkTaskListener()
val content = Files.MultipleLanguageBased.databaseJsonToEvents().filter { it.eventType in listOf( Events.WorkExtractPerformed, Events.ProcessStarted, Events.WorkConvertCreated, Events.WorkConvertPerformed) }
val content = Files.MultipleLanguageBased.databaseJsonToEvents().filter { it.eventType in listOf( Events.ExtractTaskCompleted, Events.ProcessStarted, Events.ConvertTaskCreated, Events.ConvertTaskCompleted) }
assertThat(listener).isNotNull()
val success = content.map { listener.shouldIProcessAndHandleEvent(it, content) to it }
assertThat(success.filter { it.first }.size).isGreaterThan(3)

View File

@ -11,7 +11,7 @@ class ParseMediaFileStreamsTaskListenerTest {
@Test
fun testParse() {
val event = data.jsonToEvent(Events.ReadStreamPerformed.event).dataAs<JsonObject>()
val event = data.jsonToEvent(Events.StreamRead.name).dataAs<JsonObject>()
val parser = ParseMediaFileStreamsTaskListener()
val result = parser.parseStreams(event)

View File

@ -13,7 +13,7 @@ class EncodeWorkArgumentsMappingTest {
@Test
fun parse() {
val event = data.jsonToEvent(Events.ParseStreamPerformed.event)
val event = data.jsonToEvent(Events.StreamParsed.name)
val parser = EncodeWorkArgumentsMapping(
"potato.mkv",
"potato.mp4",

View File

@ -21,7 +21,7 @@ class SubtitleArgumentsTest {
val data = Gson().fromJson<List<SubtitleStream>>(multipleSubtitleStreamsWithSameLanguage, type)
val args = SubtitleArguments(data)
val selectable = args.excludeLowFrameCount(data)
assertThat(selectable).hasSize(2)
assertThat(selectable).hasSize(3)
assertThat(selectable.find { it.index == 4 })
assertThat(selectable.find { it.index == 5 })
}

View File

@ -3,21 +3,21 @@
{"type":"database","name":"eventsV4"},
{"type":"table","name":"events","database":"eventsV4","data":
[
{"id":"15349","referenceId":"7aed4397-e286-4787-966e-7d375f43b1e5","eventId":"8ca447c5-aad9-40cc-a561-6669e1248d77","event":"event:media-process:started","data":"{\"metadata\":{\"eventId\":\"8ca447c5-aad9-40cc-a561-6669e1248d77\",\"referenceId\":\"7aed4397-e286-4787-966e-7d375f43b1e5\",\"status\":\"Success\",\"created\":\"2025-02-26T22:26:46.029447375\",\"source\":\"Coordinator\"},\"data\":{\"type\":\"FLOW\",\"operations\":[\"ENCODE\",\"EXTRACT\",\"CONVERT\"],\"file\":\"\/src\/input\/completed\/standalone\/Potetmos\/Potetmos.mkv\"},\"eventType\":\"ProcessStarted\"}","created":"2025-02-26 22:26:46.047704"},
{"id":"15359","referenceId":"7aed4397-e286-4787-966e-7d375f43b1e5","eventId":"fc1d6871-b5e3-47ad-96ef-6e63e611dec2","event":"event:work-extract:created","data":"{\"metadata\":{\"derivedFromEventId\":\"17f5ba56-7155-4fac-b787-3371480a08ac\",\"eventId\":\"fc1d6871-b5e3-47ad-96ef-6e63e611dec2\",\"referenceId\":\"7aed4397-e286-4787-966e-7d375f43b1e5\",\"status\":\"Success\",\"created\":\"2025-02-26T22:26:57.668593271\",\"source\":\"ExtractWorkTaskListener\"},\"eventType\":\"WorkExtractCreated\",\"data\":{\"arguments\":[\"-c:s\",\"copy\",\"-map\",\"0:s:0\"],\"language\":\"eng\",\"storeFileName\":\"Potetmos\",\"outputFileName\":\"Potetmos.eng.srt\",\"inputFile\":\"\/src\/input\/completed\/standalone\/Potetmos\/Potetmos.mkv\"}}","created":"2025-02-26 22:26:57.695234"},
{"id":"15360","referenceId":"7aed4397-e286-4787-966e-7d375f43b1e5","eventId":"11abadee-73f5-4b7a-ad28-5ec76ae5e095","event":"event:work-extract:created","data":"{\"metadata\":{\"derivedFromEventId\":\"17f5ba56-7155-4fac-b787-3371480a08ac\",\"eventId\":\"11abadee-73f5-4b7a-ad28-5ec76ae5e095\",\"referenceId\":\"7aed4397-e286-4787-966e-7d375f43b1e5\",\"status\":\"Success\",\"created\":\"2025-02-26T22:26:57.668599001\",\"source\":\"ExtractWorkTaskListener\"},\"eventType\":\"WorkExtractCreated\",\"data\":{\"arguments\":[\"-c:s\",\"copy\",\"-map\",\"0:s:1\"],\"language\":\"dan\",\"storeFileName\":\"Potetmos\",\"outputFileName\":\"Potetmos.dan.srt\",\"inputFile\":\"\/src\/input\/completed\/standalone\/Potetmos\/Potetmos.mkv\"}}","created":"2025-02-26 22:26:57.727437"},
{"id":"15361","referenceId":"7aed4397-e286-4787-966e-7d375f43b1e5","eventId":"9f929171-91be-460f-b6db-0243603eb222","event":"event:work-extract:created","data":"{\"metadata\":{\"derivedFromEventId\":\"17f5ba56-7155-4fac-b787-3371480a08ac\",\"eventId\":\"9f929171-91be-460f-b6db-0243603eb222\",\"referenceId\":\"7aed4397-e286-4787-966e-7d375f43b1e5\",\"status\":\"Success\",\"created\":\"2025-02-26T22:26:57.668600721\",\"source\":\"ExtractWorkTaskListener\"},\"eventType\":\"WorkExtractCreated\",\"data\":{\"arguments\":[\"-c:s\",\"copy\",\"-map\",\"0:s:2\"],\"language\":\"swe\",\"storeFileName\":\"Potetmos\",\"outputFileName\":\"Potetmos.swe.srt\",\"inputFile\":\"\/src\/input\/completed\/standalone\/Potetmos\/Potetmos.mkv\"}}","created":"2025-02-26 22:26:57.762233"},
{"id":"15362","referenceId":"7aed4397-e286-4787-966e-7d375f43b1e5","eventId":"abbba9e0-0491-48a1-bf48-dd0f201cef7f","event":"event:work-extract:created","data":"{\"metadata\":{\"derivedFromEventId\":\"17f5ba56-7155-4fac-b787-3371480a08ac\",\"eventId\":\"abbba9e0-0491-48a1-bf48-dd0f201cef7f\",\"referenceId\":\"7aed4397-e286-4787-966e-7d375f43b1e5\",\"status\":\"Success\",\"created\":\"2025-02-26T22:26:57.668602091\",\"source\":\"ExtractWorkTaskListener\"},\"eventType\":\"WorkExtractCreated\",\"data\":{\"arguments\":[\"-c:s\",\"copy\",\"-map\",\"0:s:3\"],\"language\":\"nob\",\"storeFileName\":\"Potetmos\",\"outputFileName\":\"Potetmos.nob.srt\",\"inputFile\":\"\/src\/input\/completed\/standalone\/Potetmos\/Potetmos.mkv\"}}","created":"2025-02-26 22:26:57.792813"},
{"id":"15363","referenceId":"7aed4397-e286-4787-966e-7d375f43b1e5","eventId":"fe594289-b2c5-4e3e-8827-4ba2988184b6","event":"event:work-extract:created","data":"{\"metadata\":{\"derivedFromEventId\":\"17f5ba56-7155-4fac-b787-3371480a08ac\",\"eventId\":\"fe594289-b2c5-4e3e-8827-4ba2988184b6\",\"referenceId\":\"7aed4397-e286-4787-966e-7d375f43b1e5\",\"status\":\"Success\",\"created\":\"2025-02-26T22:26:57.668603331\",\"source\":\"ExtractWorkTaskListener\"},\"eventType\":\"WorkExtractCreated\",\"data\":{\"arguments\":[\"-c:s\",\"copy\",\"-map\",\"0:s:4\"],\"language\":\"fin\",\"storeFileName\":\"Potetmos\",\"outputFileName\":\"Potetmos.fin.srt\",\"inputFile\":\"\/src\/input\/completed\/standalone\/Potetmos\/Potetmos.mkv\"}}","created":"2025-02-26 22:26:57.827601"},
{"id":"15364","referenceId":"7aed4397-e286-4787-966e-7d375f43b1e5","eventId":"99692869-ba77-4976-8544-02fdc841a06a","event":"event:work-encode:created","data":"{\"metadata\":{\"derivedFromEventId\":\"fb06297e-e5ab-4e2f-bf20-b624d37c2f8b\",\"eventId\":\"99692869-ba77-4976-8544-02fdc841a06a\",\"referenceId\":\"7aed4397-e286-4787-966e-7d375f43b1e5\",\"status\":\"Success\",\"created\":\"2025-02-26T22:26:57.842844507\",\"source\":\"EncodeWorkTaskListener\"},\"eventType\":\"WorkEncodeCreated\",\"data\":{\"arguments\":[\"-c:v\",\"copy\",\"-vbsf\",\"hevc_mp4toannexb\",\"-acodec\",\"copy\",\"-map\",\"0:v:0\",\"-map\",\"0:a:0\"],\"outputFileName\":\"Potetmos.mp4\",\"inputFile\":\"\/src\/input\/completed\/standalone\/Potetmos\/Potetmos.mkv\"}}","created":"2025-02-26 22:26:57.871043"},
{"id":"15365","referenceId":"7aed4397-e286-4787-966e-7d375f43b1e5","eventId":"59d1bcda-0a34-48fc-83e3-34547d63abb5","event":"event:work-extract:performed","data":"{\"metadata\":{\"derivedFromEventId\":\"fc1d6871-b5e3-47ad-96ef-6e63e611dec2\",\"eventId\":\"59d1bcda-0a34-48fc-83e3-34547d63abb5\",\"referenceId\":\"7aed4397-e286-4787-966e-7d375f43b1e5\",\"status\":\"Success\",\"created\":\"2025-02-26T22:27:15.577829445\",\"source\":\"ExtractService\"},\"eventType\":\"WorkExtractPerformed\",\"data\":{\"language\":\"eng\",\"storeFileName\":\"Potetmos\",\"outputFile\":\"\/src\/cache\/Potetmos.eng.srt\"}}","created":"2025-02-26 22:27:15.581941"},
{"id":"15366","referenceId":"7aed4397-e286-4787-966e-7d375f43b1e5","eventId":"5a0419e6-572f-4b73-95b8-11af31e6002e","event":"event:work-encode:performed","data":"{\"metadata\":{\"derivedFromEventId\":\"99692869-ba77-4976-8544-02fdc841a06a\",\"eventId\":\"5a0419e6-572f-4b73-95b8-11af31e6002e\",\"referenceId\":\"7aed4397-e286-4787-966e-7d375f43b1e5\",\"status\":\"Success\",\"created\":\"2025-02-26T22:27:15.598866765\",\"source\":\"EncodeService\"},\"eventType\":\"WorkEncodePerformed\",\"data\":{\"outputFile\":\"\/src\/cache\/Potetmos.mp4\"}}","created":"2025-02-26 22:27:15.603074"},
{"id":"15367","referenceId":"7aed4397-e286-4787-966e-7d375f43b1e5","eventId":"4191b02e-1d85-49f3-8cd3-2ca3a424e645","event":"event:work-convert:created","data":"{\"metadata\":{\"derivedFromEventId\":\"59d1bcda-0a34-48fc-83e3-34547d63abb5\",\"eventId\":\"4191b02e-1d85-49f3-8cd3-2ca3a424e645\",\"referenceId\":\"7aed4397-e286-4787-966e-7d375f43b1e5\",\"status\":\"Success\",\"created\":\"2025-02-26T22:27:16.058203558\",\"source\":\"ConvertWorkTaskListener\"},\"eventType\":\"WorkConvertCreated\",\"data\":{\"inputFile\":\"\/src\/cache\/Potetmos.eng.srt\",\"language\":\"eng\",\"outputDirectory\":\"\/src\/cache\",\"outputFileName\":\"Potetmos.eng\",\"storeFileName\":\"Potetmos\",\"formats\":[],\"allowOverwrite\":true}}","created":"2025-02-26 22:27:16.091175"},
{"id":"15368","referenceId":"7aed4397-e286-4787-966e-7d375f43b1e5","eventId":"79f23190-8696-4b4f-b037-98c0a9cd6314","event":"event:work-extract:performed","data":"{\"metadata\":{\"derivedFromEventId\":\"11abadee-73f5-4b7a-ad28-5ec76ae5e095\",\"eventId\":\"79f23190-8696-4b4f-b037-98c0a9cd6314\",\"referenceId\":\"7aed4397-e286-4787-966e-7d375f43b1e5\",\"status\":\"Success\",\"created\":\"2025-02-26T22:27:21.73082975\",\"source\":\"ExtractService\"},\"eventType\":\"WorkExtractPerformed\",\"data\":{\"language\":\"dan\",\"storeFileName\":\"Potetmos\",\"outputFile\":\"\/src\/cache\/Potetmos.dan.srt\"}}","created":"2025-02-26 22:27:21.734862"},
{"id":"15369","referenceId":"7aed4397-e286-4787-966e-7d375f43b1e5","eventId":"aa66dda3-dbb0-4738-9b38-0f10ec6e3c07","event":"event:work-convert:performed","data":"{\"metadata\":{\"derivedFromEventId\":\"4191b02e-1d85-49f3-8cd3-2ca3a424e645\",\"eventId\":\"aa66dda3-dbb0-4738-9b38-0f10ec6e3c07\",\"referenceId\":\"7aed4397-e286-4787-966e-7d375f43b1e5\",\"status\":\"Success\",\"created\":\"2025-02-26T22:27:22.029604937\",\"source\":\"ConvertService\"},\"eventType\":\"WorkConvertPerformed\",\"data\":{\"language\":\"eng\",\"baseName\":\"Potetmos\",\"outputFiles\":[\"\/src\/cache\/Potetmos.eng.vtt\",\"\/src\/cache\/Potetmos.eng.smi\"]}}","created":"2025-02-26 22:27:22.033352"},
{"id":"15370","referenceId":"7aed4397-e286-4787-966e-7d375f43b1e5","eventId":"ec07bb50-1cc1-45b2-a5d7-73b84bfd29d4","event":"event:work-extract:performed","data":"{\"metadata\":{\"derivedFromEventId\":\"9f929171-91be-460f-b6db-0243603eb222\",\"eventId\":\"ec07bb50-1cc1-45b2-a5d7-73b84bfd29d4\",\"referenceId\":\"7aed4397-e286-4787-966e-7d375f43b1e5\",\"status\":\"Success\",\"created\":\"2025-02-26T22:27:26.803119861\",\"source\":\"ExtractService\"},\"eventType\":\"WorkExtractPerformed\",\"data\":{\"language\":\"swe\",\"storeFileName\":\"Potetmos\",\"outputFile\":\"\/src\/cache\/Potetmos.swe.srt\"}}","created":"2025-02-26 22:27:26.807279"},
{"id":"15371","referenceId":"7aed4397-e286-4787-966e-7d375f43b1e5","eventId":"7b6663e4-cc38-4b5e-b0af-32bd1ed3039d","event":"event:work-extract:performed","data":"{\"metadata\":{\"derivedFromEventId\":\"abbba9e0-0491-48a1-bf48-dd0f201cef7f\",\"eventId\":\"7b6663e4-cc38-4b5e-b0af-32bd1ed3039d\",\"referenceId\":\"7aed4397-e286-4787-966e-7d375f43b1e5\",\"status\":\"Success\",\"created\":\"2025-02-26T22:27:31.834864505\",\"source\":\"ExtractService\"},\"eventType\":\"WorkExtractPerformed\",\"data\":{\"language\":\"nob\",\"storeFileName\":\"Potetmos\",\"outputFile\":\"\/src\/cache\/Potetmos.nob.srt\"}}","created":"2025-02-26 22:27:31.839143"},
{"id":"15372","referenceId":"7aed4397-e286-4787-966e-7d375f43b1e5","eventId":"4b3c17b8-c624-40fb-94ca-33e3657bc6d3","event":"event:work-extract:performed","data":"{\"metadata\":{\"derivedFromEventId\":\"fe594289-b2c5-4e3e-8827-4ba2988184b6\",\"eventId\":\"4b3c17b8-c624-40fb-94ca-33e3657bc6d3\",\"referenceId\":\"7aed4397-e286-4787-966e-7d375f43b1e5\",\"status\":\"Success\",\"created\":\"2025-02-26T22:27:37.017421899\",\"source\":\"ExtractService\"},\"eventType\":\"WorkExtractPerformed\",\"data\":{\"language\":\"fin\",\"storeFileName\":\"Potetmos\",\"outputFile\":\"\/src\/cache\/Potetmos.fin.srt\"}}","created":"2025-02-26 22:27:37.021717"}
{"id":"15349","referenceId":"7aed4397-e286-4787-966e-7d375f43b1e5","eventId":"8ca447c5-aad9-40cc-a561-6669e1248d77","event":"ProcessStarted","data":"{\"metadata\":{\"eventId\":\"8ca447c5-aad9-40cc-a561-6669e1248d77\",\"referenceId\":\"7aed4397-e286-4787-966e-7d375f43b1e5\",\"status\":\"Success\",\"created\":\"2025-02-26T22:26:46.029447375\",\"source\":\"Coordinator\"},\"data\":{\"type\":\"FLOW\",\"operations\":[\"ENCODE\",\"EXTRACT\",\"CONVERT\"],\"file\":\"\/src\/input\/completed\/standalone\/Potetmos\/Potetmos.mkv\"},\"eventType\":\"ProcessStarted\"}","created":"2025-02-26 22:26:46.047704"},
{"id":"15359","referenceId":"7aed4397-e286-4787-966e-7d375f43b1e5","eventId":"fc1d6871-b5e3-47ad-96ef-6e63e611dec2","event":"ExtractTaskCreated","data":"{\"metadata\":{\"derivedFromEventId\":\"17f5ba56-7155-4fac-b787-3371480a08ac\",\"eventId\":\"fc1d6871-b5e3-47ad-96ef-6e63e611dec2\",\"referenceId\":\"7aed4397-e286-4787-966e-7d375f43b1e5\",\"status\":\"Success\",\"created\":\"2025-02-26T22:26:57.668593271\",\"source\":\"ExtractWorkTaskListener\"},\"eventType\":\"WorkExtractCreated\",\"data\":{\"arguments\":[\"-c:s\",\"copy\",\"-map\",\"0:s:0\"],\"language\":\"eng\",\"storeFileName\":\"Potetmos\",\"outputFileName\":\"Potetmos.eng.srt\",\"inputFile\":\"\/src\/input\/completed\/standalone\/Potetmos\/Potetmos.mkv\"}}","created":"2025-02-26 22:26:57.695234"},
{"id":"15360","referenceId":"7aed4397-e286-4787-966e-7d375f43b1e5","eventId":"11abadee-73f5-4b7a-ad28-5ec76ae5e095","event":"ExtractTaskCreated","data":"{\"metadata\":{\"derivedFromEventId\":\"17f5ba56-7155-4fac-b787-3371480a08ac\",\"eventId\":\"11abadee-73f5-4b7a-ad28-5ec76ae5e095\",\"referenceId\":\"7aed4397-e286-4787-966e-7d375f43b1e5\",\"status\":\"Success\",\"created\":\"2025-02-26T22:26:57.668599001\",\"source\":\"ExtractWorkTaskListener\"},\"eventType\":\"WorkExtractCreated\",\"data\":{\"arguments\":[\"-c:s\",\"copy\",\"-map\",\"0:s:1\"],\"language\":\"dan\",\"storeFileName\":\"Potetmos\",\"outputFileName\":\"Potetmos.dan.srt\",\"inputFile\":\"\/src\/input\/completed\/standalone\/Potetmos\/Potetmos.mkv\"}}","created":"2025-02-26 22:26:57.727437"},
{"id":"15361","referenceId":"7aed4397-e286-4787-966e-7d375f43b1e5","eventId":"9f929171-91be-460f-b6db-0243603eb222","event":"ExtractTaskCreated","data":"{\"metadata\":{\"derivedFromEventId\":\"17f5ba56-7155-4fac-b787-3371480a08ac\",\"eventId\":\"9f929171-91be-460f-b6db-0243603eb222\",\"referenceId\":\"7aed4397-e286-4787-966e-7d375f43b1e5\",\"status\":\"Success\",\"created\":\"2025-02-26T22:26:57.668600721\",\"source\":\"ExtractWorkTaskListener\"},\"eventType\":\"WorkExtractCreated\",\"data\":{\"arguments\":[\"-c:s\",\"copy\",\"-map\",\"0:s:2\"],\"language\":\"swe\",\"storeFileName\":\"Potetmos\",\"outputFileName\":\"Potetmos.swe.srt\",\"inputFile\":\"\/src\/input\/completed\/standalone\/Potetmos\/Potetmos.mkv\"}}","created":"2025-02-26 22:26:57.762233"},
{"id":"15362","referenceId":"7aed4397-e286-4787-966e-7d375f43b1e5","eventId":"abbba9e0-0491-48a1-bf48-dd0f201cef7f","event":"ExtractTaskCreated","data":"{\"metadata\":{\"derivedFromEventId\":\"17f5ba56-7155-4fac-b787-3371480a08ac\",\"eventId\":\"abbba9e0-0491-48a1-bf48-dd0f201cef7f\",\"referenceId\":\"7aed4397-e286-4787-966e-7d375f43b1e5\",\"status\":\"Success\",\"created\":\"2025-02-26T22:26:57.668602091\",\"source\":\"ExtractWorkTaskListener\"},\"eventType\":\"WorkExtractCreated\",\"data\":{\"arguments\":[\"-c:s\",\"copy\",\"-map\",\"0:s:3\"],\"language\":\"nob\",\"storeFileName\":\"Potetmos\",\"outputFileName\":\"Potetmos.nob.srt\",\"inputFile\":\"\/src\/input\/completed\/standalone\/Potetmos\/Potetmos.mkv\"}}","created":"2025-02-26 22:26:57.792813"},
{"id":"15363","referenceId":"7aed4397-e286-4787-966e-7d375f43b1e5","eventId":"fe594289-b2c5-4e3e-8827-4ba2988184b6","event":"ExtractTaskCreated","data":"{\"metadata\":{\"derivedFromEventId\":\"17f5ba56-7155-4fac-b787-3371480a08ac\",\"eventId\":\"fe594289-b2c5-4e3e-8827-4ba2988184b6\",\"referenceId\":\"7aed4397-e286-4787-966e-7d375f43b1e5\",\"status\":\"Success\",\"created\":\"2025-02-26T22:26:57.668603331\",\"source\":\"ExtractWorkTaskListener\"},\"eventType\":\"WorkExtractCreated\",\"data\":{\"arguments\":[\"-c:s\",\"copy\",\"-map\",\"0:s:4\"],\"language\":\"fin\",\"storeFileName\":\"Potetmos\",\"outputFileName\":\"Potetmos.fin.srt\",\"inputFile\":\"\/src\/input\/completed\/standalone\/Potetmos\/Potetmos.mkv\"}}","created":"2025-02-26 22:26:57.827601"},
{"id":"15364","referenceId":"7aed4397-e286-4787-966e-7d375f43b1e5","eventId":"99692869-ba77-4976-8544-02fdc841a06a","event":"EncodeTaskCreated","data":"{\"metadata\":{\"derivedFromEventId\":\"fb06297e-e5ab-4e2f-bf20-b624d37c2f8b\",\"eventId\":\"99692869-ba77-4976-8544-02fdc841a06a\",\"referenceId\":\"7aed4397-e286-4787-966e-7d375f43b1e5\",\"status\":\"Success\",\"created\":\"2025-02-26T22:26:57.842844507\",\"source\":\"EncodeWorkTaskListener\"},\"eventType\":\"WorkEncodeCreated\",\"data\":{\"arguments\":[\"-c:v\",\"copy\",\"-vbsf\",\"hevc_mp4toannexb\",\"-acodec\",\"copy\",\"-map\",\"0:v:0\",\"-map\",\"0:a:0\"],\"outputFileName\":\"Potetmos.mp4\",\"inputFile\":\"\/src\/input\/completed\/standalone\/Potetmos\/Potetmos.mkv\"}}","created":"2025-02-26 22:26:57.871043"},
{"id":"15365","referenceId":"7aed4397-e286-4787-966e-7d375f43b1e5","eventId":"59d1bcda-0a34-48fc-83e3-34547d63abb5","event":"ExtractTaskCompleted","data":"{\"metadata\":{\"derivedFromEventId\":\"fc1d6871-b5e3-47ad-96ef-6e63e611dec2\",\"eventId\":\"59d1bcda-0a34-48fc-83e3-34547d63abb5\",\"referenceId\":\"7aed4397-e286-4787-966e-7d375f43b1e5\",\"status\":\"Success\",\"created\":\"2025-02-26T22:27:15.577829445\",\"source\":\"ExtractService\"},\"eventType\":\"WorkExtractPerformed\",\"data\":{\"language\":\"eng\",\"storeFileName\":\"Potetmos\",\"outputFile\":\"\/src\/cache\/Potetmos.eng.srt\"}}","created":"2025-02-26 22:27:15.581941"},
{"id":"15366","referenceId":"7aed4397-e286-4787-966e-7d375f43b1e5","eventId":"5a0419e6-572f-4b73-95b8-11af31e6002e","event":"EncodeTaskCompleted","data":"{\"metadata\":{\"derivedFromEventId\":\"99692869-ba77-4976-8544-02fdc841a06a\",\"eventId\":\"5a0419e6-572f-4b73-95b8-11af31e6002e\",\"referenceId\":\"7aed4397-e286-4787-966e-7d375f43b1e5\",\"status\":\"Success\",\"created\":\"2025-02-26T22:27:15.598866765\",\"source\":\"EncodeService\"},\"eventType\":\"WorkEncodePerformed\",\"data\":{\"outputFile\":\"\/src\/cache\/Potetmos.mp4\"}}","created":"2025-02-26 22:27:15.603074"},
{"id":"15367","referenceId":"7aed4397-e286-4787-966e-7d375f43b1e5","eventId":"4191b02e-1d85-49f3-8cd3-2ca3a424e645","event":"ConvertTaskCreated","data":"{\"metadata\":{\"derivedFromEventId\":\"59d1bcda-0a34-48fc-83e3-34547d63abb5\",\"eventId\":\"4191b02e-1d85-49f3-8cd3-2ca3a424e645\",\"referenceId\":\"7aed4397-e286-4787-966e-7d375f43b1e5\",\"status\":\"Success\",\"created\":\"2025-02-26T22:27:16.058203558\",\"source\":\"ConvertWorkTaskListener\"},\"eventType\":\"WorkConvertCreated\",\"data\":{\"inputFile\":\"\/src\/cache\/Potetmos.eng.srt\",\"language\":\"eng\",\"outputDirectory\":\"\/src\/cache\",\"outputFileName\":\"Potetmos.eng\",\"storeFileName\":\"Potetmos\",\"formats\":[],\"allowOverwrite\":true}}","created":"2025-02-26 22:27:16.091175"},
{"id":"15368","referenceId":"7aed4397-e286-4787-966e-7d375f43b1e5","eventId":"79f23190-8696-4b4f-b037-98c0a9cd6314","event":"ExtractTaskCompleted","data":"{\"metadata\":{\"derivedFromEventId\":\"11abadee-73f5-4b7a-ad28-5ec76ae5e095\",\"eventId\":\"79f23190-8696-4b4f-b037-98c0a9cd6314\",\"referenceId\":\"7aed4397-e286-4787-966e-7d375f43b1e5\",\"status\":\"Success\",\"created\":\"2025-02-26T22:27:21.73082975\",\"source\":\"ExtractService\"},\"eventType\":\"WorkExtractPerformed\",\"data\":{\"language\":\"dan\",\"storeFileName\":\"Potetmos\",\"outputFile\":\"\/src\/cache\/Potetmos.dan.srt\"}}","created":"2025-02-26 22:27:21.734862"},
{"id":"15369","referenceId":"7aed4397-e286-4787-966e-7d375f43b1e5","eventId":"aa66dda3-dbb0-4738-9b38-0f10ec6e3c07","event":"ConvertTaskCompleted","data":"{\"metadata\":{\"derivedFromEventId\":\"4191b02e-1d85-49f3-8cd3-2ca3a424e645\",\"eventId\":\"aa66dda3-dbb0-4738-9b38-0f10ec6e3c07\",\"referenceId\":\"7aed4397-e286-4787-966e-7d375f43b1e5\",\"status\":\"Success\",\"created\":\"2025-02-26T22:27:22.029604937\",\"source\":\"ConvertService\"},\"eventType\":\"WorkConvertPerformed\",\"data\":{\"language\":\"eng\",\"baseName\":\"Potetmos\",\"outputFiles\":[\"\/src\/cache\/Potetmos.eng.vtt\",\"\/src\/cache\/Potetmos.eng.smi\"]}}","created":"2025-02-26 22:27:22.033352"},
{"id":"15370","referenceId":"7aed4397-e286-4787-966e-7d375f43b1e5","eventId":"ec07bb50-1cc1-45b2-a5d7-73b84bfd29d4","event":"ExtractTaskCompleted","data":"{\"metadata\":{\"derivedFromEventId\":\"9f929171-91be-460f-b6db-0243603eb222\",\"eventId\":\"ec07bb50-1cc1-45b2-a5d7-73b84bfd29d4\",\"referenceId\":\"7aed4397-e286-4787-966e-7d375f43b1e5\",\"status\":\"Success\",\"created\":\"2025-02-26T22:27:26.803119861\",\"source\":\"ExtractService\"},\"eventType\":\"WorkExtractPerformed\",\"data\":{\"language\":\"swe\",\"storeFileName\":\"Potetmos\",\"outputFile\":\"\/src\/cache\/Potetmos.swe.srt\"}}","created":"2025-02-26 22:27:26.807279"},
{"id":"15371","referenceId":"7aed4397-e286-4787-966e-7d375f43b1e5","eventId":"7b6663e4-cc38-4b5e-b0af-32bd1ed3039d","event":"ExtractTaskCompleted","data":"{\"metadata\":{\"derivedFromEventId\":\"abbba9e0-0491-48a1-bf48-dd0f201cef7f\",\"eventId\":\"7b6663e4-cc38-4b5e-b0af-32bd1ed3039d\",\"referenceId\":\"7aed4397-e286-4787-966e-7d375f43b1e5\",\"status\":\"Success\",\"created\":\"2025-02-26T22:27:31.834864505\",\"source\":\"ExtractService\"},\"eventType\":\"WorkExtractPerformed\",\"data\":{\"language\":\"nob\",\"storeFileName\":\"Potetmos\",\"outputFile\":\"\/src\/cache\/Potetmos.nob.srt\"}}","created":"2025-02-26 22:27:31.839143"},
{"id":"15372","referenceId":"7aed4397-e286-4787-966e-7d375f43b1e5","eventId":"4b3c17b8-c624-40fb-94ca-33e3657bc6d3","event":"ExtractTaskCompleted","data":"{\"metadata\":{\"derivedFromEventId\":\"fe594289-b2c5-4e3e-8827-4ba2988184b6\",\"eventId\":\"4b3c17b8-c624-40fb-94ca-33e3657bc6d3\",\"referenceId\":\"7aed4397-e286-4787-966e-7d375f43b1e5\",\"status\":\"Success\",\"created\":\"2025-02-26T22:27:37.017421899\",\"source\":\"ExtractService\"},\"eventType\":\"WorkExtractPerformed\",\"data\":{\"language\":\"fin\",\"storeFileName\":\"Potetmos\",\"outputFile\":\"\/src\/cache\/Potetmos.fin.srt\"}}","created":"2025-02-26 22:27:37.021717"}
]
}
]

View File

@ -35,9 +35,21 @@ class ExplorerTopic(
}
}
@MessageMapping("/request/encode")
fun requestEncode(@Payload data: EventRequest) {
val req = coordinatorTemplate.postForEntity("/request/encode", data, String::class.java)
log.info { req }
}
@MessageMapping("/request/extract")
fun requestExtract(@Payload data: EventRequest) {
val req = coordinatorTemplate.postForEntity("/request/extract", data, String::class.java)
log.info { req }
}
@MessageMapping("/request/convert")
fun requestConvert(@Payload data: EventRequest) {
val req = coordinatorTemplate.postForEntity(UIEnv.coordinatorUrl, data, String.javaClass)
val req = coordinatorTemplate.postForEntity("/request/convert", data, String::class.java)
log.info { req }
}

View File

@ -124,6 +124,13 @@ function getContextMenuFileActionMenuItems(row: ExplorerItem | null): ContextMen
return items;
}
interface ExplorerOperationRequest {
destination: string;
file: string;
source: string;
mode: "FLOW" | "MANUAL";
}
export default function ExplorePage() {
const muiTheme = useTheme();
const dispatch = useDispatch();
@ -168,39 +175,51 @@ export default function ExplorePage() {
if (!value) {
return;
}
const payload = (() => {
switch(actionIndex) {
case 0: {
console.log("All");
const request = {
return {
destination: "request/all",
file: value.path,
source: `Web UI @ ${window.location.href}`,
mode: "FLOW"
}
client?.publish({
destination: "/app/request/all",
body: JSON.stringify(request)
})
break;
} as ExplorerOperationRequest
}
case 1: {
console.log("Encode")
break;
return {
destination: "request/encode",
file: value.path,
source: `Web UI @ ${window.location.href}`,
mode: "FLOW"
} as ExplorerOperationRequest
}
case 2: {
console.log("Extract")
break;
return {
destination: "request/extract",
file: value.path,
source: `Web UI @ ${window.location.href}`,
mode: "FLOW"
} as ExplorerOperationRequest
}
case 3: {
console.log("Convert")
break;
return {
destination: "request/convert",
file: value.path,
source: `Web UI @ ${window.location.href}`,
mode: "FLOW"
} as ExplorerOperationRequest
}
default: {
return null;
}
}
})();
if (payload) {
client?.publish({
destination: "/app/"+payload.destination,
body: JSON.stringify(payload)
})
}
}
}

View File

@ -1,10 +1,8 @@
package no.iktdev.mediaprocessing.shared.common.contract
import com.google.gson.*
import com.google.gson.reflect.TypeToken
import mu.KotlinLogging
import no.iktdev.eventi.core.LocalDateTimeAdapter
import no.iktdev.eventi.core.WGson
import no.iktdev.mediaprocessing.shared.common.contract.data.*
import java.lang.reflect.Type
import java.time.LocalDateTime
@ -12,64 +10,63 @@ import java.time.LocalDateTime
private val log = KotlinLogging.logger {}
enum class Events(val event: String) {
ProcessStarted ("event:media-process:started"),
enum class Events {
ProcessStarted,
StreamRead,
StreamParsed,
BaseInfoRead,
MetadataSearchPerformed,
ReadOutNameAndType,
ReadOutCover,
EncodeParameterCreated,
ExtractParameterCreated,
WorkProceedPermitted,
EncodeTaskCreated,
ExtractTaskCreated,
ConvertTaskCreated,
EncodeTaskCompleted,
ExtractTaskCompleted,
ConvertTaskCompleted,
CoverDownloaded,
PersistContent,
ProcessCompleted,
ReadStreamPerformed ("event:media-read-stream:performed" ),
ParseStreamPerformed ("event:media-parse-stream:performed" ),
ReadBaseInfoPerformed ("event:media-read-base-info:performed" ),
MetadataSearchPerformed ("event:media-metadata-search:performed" ),
ReadOutNameAndType ("event:media-read-out-name-and-type:performed" ),
ReadOutCover ("event:media-read-out-cover:performed" ),
ParameterEncodeCreated ("event:media-encode-parameter:created" ),
ParameterExtractCreated ("event:media-extract-parameter:created" ),
WorkProceedPermitted ("event:media-work-proceed:permitted" ),
WorkEncodeCreated ("event:work-encode:created" ),
WorkExtractCreated ("event:work-extract:created" ),
WorkConvertCreated ("event:work-convert:created" ),
WorkEncodePerformed ("event:work-encode:performed" ),
WorkExtractPerformed ("event:work-extract:performed" ),
WorkConvertPerformed ("event:work-convert:performed" ),
WorkDownloadCoverPerformed ("event:work-download-cover:performed" ),
PersistContentPerformed ("event:media-persist:completed" ),
ProcessCompleted ("event:media-process:completed" ),
Unknown ("")
Unknown
;
companion object {
fun toEvent(event: String): Events {
return Events.entries.find { it.event == event } ?: Unknown
return Events.entries.find { it.name == event } ?: Unknown
}
}
}
fun Events.toEventClass(): Class<out Event> {
return when(this) {
return when (this) {
Events.ProcessStarted -> MediaProcessStartEvent::class.java
Events.ReadStreamPerformed -> MediaFileStreamsReadEvent::class.java
Events.ParseStreamPerformed -> MediaFileStreamsParsedEvent::class.java
Events.ReadBaseInfoPerformed -> BaseInfoEvent::class.java
Events.StreamRead -> MediaFileStreamsReadEvent::class.java
Events.StreamParsed -> MediaFileStreamsParsedEvent::class.java
Events.BaseInfoRead -> BaseInfoEvent::class.java
Events.MetadataSearchPerformed -> MediaMetadataReceivedEvent::class.java
Events.ReadOutNameAndType -> MediaOutInformationConstructedEvent::class.java
Events.ReadOutCover -> MediaCoverInfoReceivedEvent::class.java
Events.ParameterEncodeCreated -> EncodeArgumentCreatedEvent::class.java
Events.ParameterExtractCreated -> ExtractArgumentCreatedEvent::class.java
Events.EncodeParameterCreated -> EncodeArgumentCreatedEvent::class.java
Events.ExtractParameterCreated -> ExtractArgumentCreatedEvent::class.java
Events.WorkProceedPermitted -> PermitWorkCreationEvent::class.java
Events.WorkEncodeCreated -> EncodeWorkCreatedEvent::class.java
Events.WorkExtractCreated -> ExtractWorkCreatedEvent::class.java
Events.WorkConvertCreated -> ConvertWorkCreatedEvent::class.java
Events.EncodeTaskCreated -> EncodeWorkCreatedEvent::class.java
Events.ExtractTaskCreated -> ExtractWorkCreatedEvent::class.java
Events.ConvertTaskCreated -> ConvertWorkCreatedEvent::class.java
Events.WorkEncodePerformed -> EncodeWorkPerformedEvent::class.java
Events.WorkExtractPerformed -> ExtractWorkPerformedEvent::class.java
Events.WorkConvertPerformed -> ConvertWorkPerformed::class.java
Events.WorkDownloadCoverPerformed -> MediaCoverDownloadedEvent::class.java
Events.EncodeTaskCompleted -> EncodeWorkPerformedEvent::class.java
Events.ExtractTaskCompleted -> ExtractWorkPerformedEvent::class.java
Events.ConvertTaskCompleted -> ConvertWorkPerformed::class.java
Events.CoverDownloaded -> MediaCoverDownloadedEvent::class.java
Events.PersistContentPerformed -> PersistedContentEvent::class.java
Events.PersistContent -> PersistedContentEvent::class.java
Events.ProcessCompleted -> MediaProcessCompletedEvent::class.java
else -> Event::class.java
}
@ -106,6 +103,7 @@ object EventJson {
private val gson = GsonBuilder()
.registerTypeAdapter(LocalDateTime::class.java, LocalDateTimeAdapter())
.create()
fun fromJson(json: String, event: Events): Event {
val gson = GsonBuilder()
.registerTypeAdapter(LocalDateTime::class.java, LocalDateTimeAdapter())
@ -123,6 +121,13 @@ object EventJson {
// 🔥 Finn riktig klasse basert på eventType (som kommer eksternt fra databasen)
val eventClass = eventType.toEventClass()
if (eventClass.simpleName == Event::class.java.simpleName || eventType == Events.Unknown) {
val fallbackGson = GsonBuilder()
.registerTypeAdapter(LocalDateTime::class.java, LocalDateTimeAdapter())
.create()
return fallbackGson.fromJson(json, eventClass)
}
// Deserialiser objektet til riktig klasse
val event = context.deserialize<Event>(json, eventClass)

View File

@ -5,7 +5,7 @@ import no.iktdev.mediaprocessing.shared.common.contract.Events
data class BaseInfoEvent(
override val metadata: EventMetadata,
override val eventType: Events = Events.ReadBaseInfoPerformed,
override val eventType: Events = Events.BaseInfoRead,
override val data: BaseInfo? = null
) : Event()

View File

@ -7,7 +7,7 @@ import no.iktdev.mediaprocessing.shared.common.contract.dto.tasks.TaskData
data class ConvertWorkCreatedEvent(
override val metadata: EventMetadata,
override val eventType: Events = Events.WorkConvertCreated,
override val eventType: Events = Events.ConvertTaskCreated,
override val data: ConvertData? = null
) : Event() {
}

View File

@ -5,7 +5,7 @@ import no.iktdev.mediaprocessing.shared.common.contract.Events
class ConvertWorkPerformed(
override val metadata: EventMetadata,
override val eventType: Events = Events.WorkConvertPerformed,
override val eventType: Events = Events.ConvertTaskCompleted,
override val data: ConvertedData? = null,
val message: String? = null
) : Event() {

View File

@ -6,7 +6,7 @@ import no.iktdev.mediaprocessing.shared.common.contract.dto.tasks.TaskData
data class EncodeArgumentCreatedEvent(
override val metadata: EventMetadata,
override val eventType: Events = Events.ParameterEncodeCreated,
override val eventType: Events = Events.EncodeParameterCreated,
override val data: EncodeArgumentData? = null
) : Event() {

View File

@ -5,6 +5,6 @@ import no.iktdev.mediaprocessing.shared.common.contract.Events
data class EncodeWorkCreatedEvent(
override val metadata: EventMetadata,
override val eventType: Events = Events.WorkEncodeCreated,
override val eventType: Events = Events.EncodeTaskCreated,
override val data: EncodeArgumentData? = null
) : Event()

View File

@ -5,7 +5,7 @@ import no.iktdev.mediaprocessing.shared.common.contract.Events
data class EncodeWorkPerformedEvent(
override val metadata: EventMetadata,
override val eventType: Events = Events.WorkEncodePerformed,
override val eventType: Events = Events.EncodeTaskCompleted,
override val data: EncodedData? = null,
val message: String? = null
) : Event() {

View File

@ -6,7 +6,7 @@ import no.iktdev.mediaprocessing.shared.common.contract.dto.tasks.TaskData
data class ExtractArgumentCreatedEvent(
override val metadata: EventMetadata,
override val eventType: Events = Events.ParameterExtractCreated,
override val eventType: Events = Events.ExtractParameterCreated,
override val data: List<ExtractArgumentData>? = null
): Event()

View File

@ -5,7 +5,7 @@ import no.iktdev.mediaprocessing.shared.common.contract.Events
data class ExtractWorkCreatedEvent(
override val metadata: EventMetadata,
override val eventType: Events = Events.WorkExtractCreated,
override val eventType: Events = Events.ExtractTaskCreated,
override val data: ExtractArgumentData? = null
) : Event() {
}

View File

@ -5,7 +5,7 @@ import no.iktdev.mediaprocessing.shared.common.contract.Events
data class ExtractWorkPerformedEvent(
override val metadata: EventMetadata,
override val eventType: Events = Events.WorkExtractPerformed,
override val eventType: Events = Events.ExtractTaskCompleted,
override val data: ExtractedData? = null,
val message: String? = null
) : Event() {

View File

@ -5,7 +5,7 @@ import no.iktdev.mediaprocessing.shared.common.contract.Events
data class MediaCoverDownloadedEvent(
override val metadata: EventMetadata,
override val eventType: Events = Events.WorkDownloadCoverPerformed,
override val eventType: Events = Events.CoverDownloaded,
override val data: DownloadedCover? = null
) : Event() {
}

View File

@ -7,6 +7,6 @@ import no.iktdev.mediaprocessing.shared.common.contract.ffmpeg.ParsedMediaStream
class MediaFileStreamsParsedEvent(
override val metadata: EventMetadata,
override val data: ParsedMediaStreams? = null,
override val eventType: Events = Events.ParseStreamPerformed
override val eventType: Events = Events.StreamParsed
) : Event()

View File

@ -7,5 +7,5 @@ import no.iktdev.mediaprocessing.shared.common.contract.Events
class MediaFileStreamsReadEvent(
override val metadata: EventMetadata,
override val data: JsonObject? = null,
override val eventType: Events = Events.ReadStreamPerformed
override val eventType: Events = Events.StreamRead
) : Event()

View File

@ -4,7 +4,7 @@ import no.iktdev.eventi.data.EventMetadata
import no.iktdev.mediaprocessing.shared.common.contract.Events
data class PersistedContentEvent(
override val eventType: Events = Events.PersistContentPerformed,
override val eventType: Events = Events.PersistContent,
override val metadata: EventMetadata,
override val data: PersistedContent?

View File

@ -28,7 +28,7 @@ class EventsManager(dataSource: DataSource) : EventsManagerContract(dataSource)
allEvents.insert {
it[referenceId] = event.referenceId()
it[eventId] = event.eventId()
it[events.event] = event.eventType.event
it[events.event] = event.eventType.name
it[data] = event.toJson()
}
}
@ -49,7 +49,7 @@ class EventsManager(dataSource: DataSource) : EventsManagerContract(dataSource)
events.insert {
it[referenceId] = event.referenceId()
it[eventId] = event.eventId()
it[events.event] = event.eventType.event
it[events.event] = event.eventType.name
it[data] = event.toJson()
}
}
@ -80,10 +80,10 @@ class EventsManager(dataSource: DataSource) : EventsManagerContract(dataSource)
private val exemptedFromSingleEvent = listOf(
Events.WorkConvertCreated,
Events.WorkExtractCreated,
Events.WorkConvertPerformed,
Events.WorkExtractPerformed
Events.ConvertTaskCreated,
Events.ExtractTaskCreated,
Events.ConvertTaskCompleted,
Events.ExtractTaskCompleted
)
private fun isExempted(event: Events): Boolean {
@ -94,7 +94,7 @@ class EventsManager(dataSource: DataSource) : EventsManagerContract(dataSource)
return withDirtyRead(dataSource.database) {
val completedEvents = events
.slice(events.referenceId)
.select { events.event eq Events.ProcessCompleted.event }
.select { events.event eq Events.ProcessCompleted.name }
events
.slice(events.referenceId)
@ -173,7 +173,7 @@ class EventsManager(dataSource: DataSource) : EventsManagerContract(dataSource)
events.deleteWhere {
(referenceId eq duplicate.referenceId()) and
(eventId eq duplicate.eventId()) and
(event eq duplicate.eventType.event)
(event eq duplicate.eventType.name)
}
}
}

View File

@ -150,7 +150,7 @@ class TasksManager(private val dataSource: DataSource) {
events.insert {
it[referenceId] = event.referenceId()
it[eventId] = event.eventId()
it[events.event] = event.eventType.event
it[events.event] = event.eventType.name
it[data] = event.toJson()
}
}