Fixed projection
This commit is contained in:
parent
ed6bddb95f
commit
438044faaf
@ -6,11 +6,18 @@ import no.iktdev.mediaprocessing.shared.common.event_task_contract.events.*
|
||||
import no.iktdev.mediaprocessing.shared.common.resolveConflict
|
||||
import java.io.File
|
||||
|
||||
open class MigrateContentProject(val events: List<Event>, val storageArea: File) {
|
||||
open class MigrateContentProject(
|
||||
val events: List<Event>,
|
||||
val storageArea: File
|
||||
) {
|
||||
|
||||
val useStore: File? = getDesiredStoreFolder()
|
||||
|
||||
open fun getFoldersInStore(): List<String> {
|
||||
return storageArea.listFiles { file -> file.isDirectory }?.map { it.name }?.toList() ?: emptyList()
|
||||
return storageArea
|
||||
.listFiles { file -> file.isDirectory }
|
||||
?.map { it.name }
|
||||
?: emptyList()
|
||||
}
|
||||
|
||||
internal fun getFileName(): String? {
|
||||
@ -19,75 +26,77 @@ open class MigrateContentProject(val events: List<Event>, val storageArea: File)
|
||||
}
|
||||
|
||||
internal fun getDesiredStoreFolder(): File? {
|
||||
val assuredCollection = getDesiredCollection() ?: return null
|
||||
val assuredStore = storageArea.using(assuredCollection)
|
||||
val existingCollectionNames = getFoldersInStore().ifEmpty {
|
||||
val desiredCollection = getDesiredCollection() ?: return null
|
||||
val assuredStore = storageArea.using(desiredCollection)
|
||||
|
||||
val existingCollectionNames = getFoldersInStore()
|
||||
if (existingCollectionNames.isEmpty()) {
|
||||
return assuredStore
|
||||
}
|
||||
|
||||
val titles = getMetadataTitles()
|
||||
val existingCollection = titles.filter { it in existingCollectionNames }.firstOrNull()?.let {
|
||||
File(it)
|
||||
} ?: assuredStore
|
||||
return existingCollection
|
||||
|
||||
val matchedExisting = titles
|
||||
.firstOrNull { it in existingCollectionNames }
|
||||
?.let { storageArea.using(it) }
|
||||
|
||||
return matchedExisting ?: assuredStore
|
||||
}
|
||||
|
||||
internal fun getMetadataTitles(): List<String> {
|
||||
val metadataEvent = events.filterIsInstance<MetadataSearchResultEvent>().lastOrNull()?.recommended?.metadata
|
||||
val metadataEvent = events
|
||||
.filterIsInstance<MetadataSearchResultEvent>()
|
||||
.lastOrNull()
|
||||
?.recommended
|
||||
?.metadata
|
||||
?: return emptyList()
|
||||
return (metadataEvent.alternateTitles + listOf(metadataEvent.title))
|
||||
|
||||
return metadataEvent.alternateTitles + metadataEvent.title
|
||||
}
|
||||
|
||||
internal fun getDesiredCollection(): String? {
|
||||
val metadataEvent = events.filterIsInstance<MediaParsedInfoEvent>().lastOrNull()?.data
|
||||
return metadataEvent?.parsedCollection
|
||||
return events
|
||||
.filterIsInstance<MediaParsedInfoEvent>()
|
||||
.lastOrNull()
|
||||
?.data
|
||||
?.parsedCollection
|
||||
}
|
||||
|
||||
|
||||
fun getVideoStoreFile(): CachedToStore? {
|
||||
val encoded = events.filterIsInstance<ProcesserEncodeResultEvent>().lastOrNull()
|
||||
val cached = encoded?.data?.cachedOutputFile?.let { File(it) } ?: return null
|
||||
val useFilename = getFileName()?.let { "$it.${cached.extension}" } ?: return null
|
||||
val store = useStore?.using(useFilename) ?: return null
|
||||
return CachedToStore(
|
||||
cachedFile = cached,
|
||||
storeFile = store
|
||||
)
|
||||
val cached = encoded?.data?.cachedOutputFile?.let(::File) ?: return null
|
||||
|
||||
val filename = getFileName()?.let { "$it.${cached.extension}" } ?: return null
|
||||
val store = useStore?.using(filename) ?: return null
|
||||
|
||||
return CachedToStore(cachedFile = cached, storeFile = store)
|
||||
}
|
||||
|
||||
fun getSubtitleStoreFiles(): List<CachedToStoreLanguage>? {
|
||||
val extractedFiles: Map<String, List<File>> = events
|
||||
val extractedFiles = events
|
||||
.filterIsInstance<ProcesserExtractResultEvent>()
|
||||
.mapNotNull { it.data }
|
||||
.map { data -> data.language to File(data.cachedOutputFile) }
|
||||
.map { it.language to File(it.cachedOutputFile) }
|
||||
.groupBy({ it.first }, { it.second })
|
||||
|
||||
val convertedFilesGrouped: Map<String, List<File>> = events
|
||||
val convertedFiles = events
|
||||
.filterIsInstance<ConvertTaskResultEvent>()
|
||||
.mapNotNull { it.data }
|
||||
.map { x -> x.outputFiles.map { x.language to File(it) } }
|
||||
.flatten()
|
||||
.flatMap { d -> d.outputFiles.map { d.language to File(it) } }
|
||||
.groupBy({ it.first }, { it.second })
|
||||
|
||||
|
||||
val byLanguage = mutableMapOf<String, MutableList<File>>()
|
||||
extractedFiles.forEach { (lang, files) ->
|
||||
byLanguage.getOrPut(lang) { mutableListOf() }.addAll(files)
|
||||
}
|
||||
convertedFilesGrouped.forEach { (lang, files) ->
|
||||
byLanguage.getOrPut(lang) { mutableListOf() }.addAll(files)
|
||||
}
|
||||
extractedFiles.forEach { (lang, files) -> byLanguage.getOrPut(lang) { mutableListOf() }.addAll(files) }
|
||||
convertedFiles.forEach { (lang, files) -> byLanguage.getOrPut(lang) { mutableListOf() }.addAll(files) }
|
||||
|
||||
val useFilename = getFileName() ?: return null
|
||||
val baseName = getFileName() ?: return null
|
||||
|
||||
return byLanguage.flatMap { (language, files) ->
|
||||
files.mapNotNull { cached ->
|
||||
val useFilename = "$useFilename.${cached.extension}"
|
||||
val store = useStore?.using(language, useFilename) ?: return@mapNotNull null
|
||||
val filename = "$baseName.${cached.extension}"
|
||||
val store = useStore?.using(language, filename) ?: return@mapNotNull null
|
||||
CachedToStoreLanguage(
|
||||
CachedToStore(
|
||||
cachedFile = cached,
|
||||
storeFile = store
|
||||
),
|
||||
cts = CachedToStore(cachedFile = cached, storeFile = store),
|
||||
language = language
|
||||
)
|
||||
}
|
||||
@ -95,10 +104,11 @@ open class MigrateContentProject(val events: List<Event>, val storageArea: File)
|
||||
}
|
||||
|
||||
fun getCoverStoreFiles(): List<CachedToStore>? {
|
||||
val downloaded = events.filterIsInstance<CoverDownloadResultEvent>()
|
||||
.mapNotNull { event ->
|
||||
val file = event.data?.outputFile?.let(::File) ?: return@mapNotNull null
|
||||
event to file
|
||||
val downloaded = events
|
||||
.filterIsInstance<CoverDownloadResultEvent>()
|
||||
.mapNotNull { e ->
|
||||
val file = e.data?.outputFile?.let(::File) ?: return@mapNotNull null
|
||||
e to file
|
||||
}
|
||||
|
||||
val baseName = getDesiredCollection() ?: return null
|
||||
@ -110,10 +120,7 @@ open class MigrateContentProject(val events: List<Event>, val storageArea: File)
|
||||
val ext = cached.extension
|
||||
val source = event.data?.source ?: "unknown"
|
||||
|
||||
// Bestem om vi skal bruke source i navnet
|
||||
val useSource = multiple || store.using("$baseName.$ext").exists()
|
||||
|
||||
val filename = if (useSource) {
|
||||
val filename = if (multiple || store.using("$baseName.$ext").exists()) {
|
||||
"$baseName-$source.$ext"
|
||||
} else {
|
||||
"$baseName.$ext"
|
||||
@ -121,21 +128,10 @@ open class MigrateContentProject(val events: List<Event>, val storageArea: File)
|
||||
|
||||
val storeFile = store.using(filename).resolveConflict()
|
||||
|
||||
CachedToStore(
|
||||
cachedFile = cached,
|
||||
storeFile = storeFile
|
||||
)
|
||||
CachedToStore(cachedFile = cached, storeFile = storeFile)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
data class CachedToStore(
|
||||
val cachedFile: File,
|
||||
val storeFile: File
|
||||
)
|
||||
|
||||
data class CachedToStoreLanguage(
|
||||
val cts: CachedToStore,
|
||||
val language: String
|
||||
)
|
||||
}
|
||||
data class CachedToStore(val cachedFile: File, val storeFile: File)
|
||||
data class CachedToStoreLanguage(val cts: CachedToStore, val language: String)
|
||||
}
|
||||
|
||||
@ -0,0 +1,119 @@
|
||||
package no.iktdev.mediaprocessing.shared.common.projection
|
||||
|
||||
import no.iktdev.eventi.models.Event
|
||||
import no.iktdev.eventi.models.store.TaskStatus
|
||||
import no.iktdev.mediaprocessing.shared.common.event_task_contract.events.MediaParsedInfoEvent
|
||||
import no.iktdev.mediaprocessing.shared.common.event_task_contract.events.MediaParsedInfoEvent.ParsedData
|
||||
import no.iktdev.mediaprocessing.shared.common.event_task_contract.events.MetadataSearchResultEvent
|
||||
import no.iktdev.mediaprocessing.shared.common.event_task_contract.events.ProcesserEncodeResultEvent
|
||||
import no.iktdev.mediaprocessing.shared.common.model.MediaType
|
||||
import org.junit.jupiter.api.Assertions.*
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import java.io.File
|
||||
|
||||
class MigrateContentProjectPathTest {
|
||||
|
||||
private fun tempDir(): File {
|
||||
val dir = createTempDir(prefix = "store-test-")
|
||||
dir.deleteOnExit()
|
||||
return dir
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName(
|
||||
"""
|
||||
Når projeksjonen beregner video-path
|
||||
Så:
|
||||
Skal pathen alltid ligge under storageArea
|
||||
"""
|
||||
)
|
||||
fun videoPathIsUnderStorageArea() {
|
||||
val storage = tempDir()
|
||||
|
||||
val events = listOf<Event>(
|
||||
MediaParsedInfoEvent(
|
||||
ParsedData(
|
||||
parsedCollection = "Breaking Bad",
|
||||
parsedFileName = "bb.s01e01",
|
||||
parsedSearchTitles = emptyList(),
|
||||
mediaType = MediaType.Serie
|
||||
)
|
||||
),
|
||||
ProcesserEncodeResultEvent(
|
||||
status = TaskStatus.Completed,
|
||||
data = ProcesserEncodeResultEvent.EncodeResult(
|
||||
cachedOutputFile = "/tmp/encoded.mp4"
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val project = MigrateContentProject(events, storage)
|
||||
|
||||
val video = project.getVideoStoreFile()
|
||||
assertNotNull(video)
|
||||
|
||||
val storeFile = video!!.storeFile
|
||||
|
||||
assertTrue(
|
||||
storeFile.absolutePath.startsWith(storage.absolutePath),
|
||||
"Store path must be inside storageArea"
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
File(storage, "Breaking Bad/bb.s01e01.mp4").absolutePath,
|
||||
storeFile.absolutePath
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName(
|
||||
"""
|
||||
Når metadata-titler matcher eksisterende mapper
|
||||
Så:
|
||||
Skal projeksjonen bruke eksisterende mappe
|
||||
"""
|
||||
)
|
||||
fun usesExistingCollectionFolder() {
|
||||
val storage = tempDir()
|
||||
val existing = File(storage, "Breaking Bad")
|
||||
existing.mkdirs()
|
||||
|
||||
val events = listOf<Event>(
|
||||
MediaParsedInfoEvent(
|
||||
ParsedData(
|
||||
parsedCollection = "bb",
|
||||
parsedFileName = "bb.s01e01",
|
||||
parsedSearchTitles = emptyList(),
|
||||
mediaType = MediaType.Serie
|
||||
)
|
||||
),
|
||||
MetadataSearchResultEvent(
|
||||
results = emptyList(),
|
||||
recommended = MetadataSearchResultEvent.SearchResult(
|
||||
simpleScore = 10,
|
||||
prefixScore = 10,
|
||||
advancedScore = 10,
|
||||
sourceWeight = 1f,
|
||||
metadata = MetadataSearchResultEvent.SearchResult.MetadataResult(
|
||||
source = "tmdb",
|
||||
title = "Breaking Bad",
|
||||
alternateTitles = listOf("BB"),
|
||||
cover = "x.jpg",
|
||||
type = MediaType.Serie,
|
||||
summary = emptyList(),
|
||||
genres = emptyList()
|
||||
)
|
||||
),
|
||||
status = TaskStatus.Completed
|
||||
)
|
||||
)
|
||||
|
||||
val project = MigrateContentProject(events, storage)
|
||||
|
||||
assertEquals(
|
||||
existing.absolutePath,
|
||||
project.useStore!!.absolutePath
|
||||
)
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user