Parser #1
This commit is contained in:
parent
59ce796db8
commit
e84a6494aa
@ -0,0 +1,194 @@
|
||||
package no.iktdev.mediaprocessing.coordinator.listeners.events
|
||||
|
||||
import no.iktdev.eventi.events.EventListener
|
||||
import no.iktdev.eventi.models.Event
|
||||
import no.iktdev.mediaprocessing.shared.common.event_task_contract.events.StartProcessingEvent
|
||||
import org.springframework.stereotype.Component
|
||||
import java.io.File
|
||||
|
||||
@Component
|
||||
class MediaEventParsedInfoListener : EventListener() {
|
||||
override fun onEvent(
|
||||
event: Event,
|
||||
history: List<Event>
|
||||
): Event? {
|
||||
val started = event as? StartProcessingEvent ?: return null
|
||||
val fileName = File(started.data.fileUri).nameWithoutExtension
|
||||
val cleanedTitle = fileName.getCleanedTitle()
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
fun String.getCleanedTitle(): String {
|
||||
return this
|
||||
.noBrackets()
|
||||
.noParens()
|
||||
.noResolutionAndAfter()
|
||||
.noSourceTags()
|
||||
.noYear()
|
||||
.noDots()
|
||||
.noTrailingOrLeading()
|
||||
.noUnderscores()
|
||||
.noExtraSpaces()
|
||||
.trim()
|
||||
}
|
||||
|
||||
|
||||
fun String.noBrackets() = Regex("\\[.*?]").replace(this, " ")
|
||||
fun String.noParens() = Regex("\\(.*?\\)").replace(this, " ")
|
||||
fun String.noTrailingOrLeading() = Regex("^[^a-zA-Z0-9!,]+|[^a-zA-Z0-9!~,]+\$").replace(this, " ")
|
||||
fun String.noResolutionAndAfter() = Regex("[0-9]+[pk].*", RegexOption.IGNORE_CASE).replace(this, "")
|
||||
fun String.noSourceTags() =
|
||||
Regex("(?i)(bluray|laserdisc|dvd|web|uhd|hd|htds|imax).*", RegexOption.IGNORE_CASE).replace(this, " ")
|
||||
fun String.noUnderscores() = this.replace("_", " ")
|
||||
fun String.noYear() = Regex("\\b\\d{4}\\b").replace(this.takeIf { !it.matches(Regex("^\\d{4}")) } ?: this, "")
|
||||
fun String.noDots() = Regex("(?<!\\b(?:Dr|Mr|Ms|Mrs|Lt|Capt|Prof|St|Ave))\\.").replace(this, " ")
|
||||
fun String.noExtraSpaces() = Regex("\\s{2,}").replace(this, " ")
|
||||
|
||||
enum class MediaType {
|
||||
Movie,
|
||||
Serie
|
||||
}
|
||||
|
||||
fun File.guessMovieOrSeries(): MediaType {
|
||||
val name = this.nameWithoutExtension.lowercase()
|
||||
|
||||
// Serie-mønstre: dekker alle vanlige shorthand og varianter
|
||||
val seriesPatterns = listOf(
|
||||
Regex("s\\d{1,2}e\\d{1,2}"), // S01E03, s1e5
|
||||
Regex("\\d{1,2}x\\d{1,2}"), // 1x03, 2x10
|
||||
Regex("season\\s*\\d+"), // Season 2
|
||||
Regex("episode\\s*\\d+"), // Episode 5
|
||||
Regex("ep\\s*\\d+"), // Ep05, Ep 5
|
||||
Regex("s\\d{1,2}\\s*[- ]\\s*e\\d{1,2}"), // S1 - E5, S01 - E05
|
||||
Regex("s\\d{1,2}\\s*ep\\s*\\d{1,2}"), // S1 Ep05
|
||||
Regex("series\\s*\\d+"), // Series 2 (britisk stil)
|
||||
)
|
||||
|
||||
if (seriesPatterns.any { it.containsMatchIn(name) }) {
|
||||
return MediaType.Serie
|
||||
}
|
||||
|
||||
// Film-mønstre: årstall (1900–2099) etter tittel
|
||||
val moviePattern = Regex("\\b(19|20)\\d{2}\\b")
|
||||
if (moviePattern.containsMatchIn(name)) {
|
||||
return MediaType.Movie
|
||||
}
|
||||
|
||||
// Fallback: hvis ingen mønstre passer, anta film
|
||||
return MediaType.Movie
|
||||
}
|
||||
|
||||
|
||||
fun File.guessDesiredFileName(): String {
|
||||
val type = this.guessMovieOrSeries()
|
||||
return when (type) {
|
||||
MediaType.Movie -> this.guessDesiredMovieTitle()
|
||||
MediaType.Serie -> this.guessDesiredSerieTitle()
|
||||
}
|
||||
}
|
||||
|
||||
fun File.getDesiredCollection(): String {
|
||||
val collection = when (this.guessMovieOrSeries()) {
|
||||
MediaType.Movie -> this.guessDesiredMovieTitle()
|
||||
MediaType.Serie -> this.guessDesiredSerieTitle()
|
||||
}
|
||||
return collection.noParens().noYear().split(" - ").first().trim()
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A fully cleaned title suitable to use for collection
|
||||
*/
|
||||
fun File.guessDesiredMovieTitle(): String {
|
||||
val cleaned = this.nameWithoutExtension.getCleanedTitle()
|
||||
val yearRegex = Regex("\\b(19|20)\\d{2}\\b")
|
||||
val yearMatch = yearRegex.find(cleaned)
|
||||
|
||||
return if (yearMatch != null) {
|
||||
val title = cleaned.replace(yearRegex, "").trim()
|
||||
"${title} (${yearMatch.value})"
|
||||
} else {
|
||||
cleaned
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return A fully cleaned title including season and episode with possible episode title
|
||||
*/
|
||||
fun File.guessDesiredSerieTitle(): String {
|
||||
val raw = this.nameWithoutExtension
|
||||
|
||||
val seasonRegex = Regex("""(?i)(?:S|Season|Series)\s*(\d{1,2})""")
|
||||
val episodeRegex = Regex("""(?i)(?:E|Episode|Ep)\s*(\d{1,3})""")
|
||||
val revisionRegex = Regex("""(?i)\bv(\d+)\b""")
|
||||
|
||||
val seasonMatch = seasonRegex.find(raw)
|
||||
val episodeMatch = episodeRegex.find(raw)
|
||||
val revisionMatch = revisionRegex.find(raw)
|
||||
|
||||
val season = seasonMatch?.groupValues?.get(1)?.toIntOrNull()
|
||||
val episode = episodeMatch?.groupValues?.get(1)?.toIntOrNull()
|
||||
val revision = revisionMatch?.groupValues?.get(1)?.toIntOrNull()
|
||||
|
||||
val baseTitle = if (seasonMatch != null) {
|
||||
raw.substring(0, seasonMatch.range.first).getCleanedTitle()
|
||||
} else raw.getCleanedTitle()
|
||||
|
||||
val episodeTitle = if (episodeMatch != null) {
|
||||
raw.substring(episodeMatch.range.last + 1).getCleanedTitle()
|
||||
} else ""
|
||||
|
||||
val tag = buildString {
|
||||
append("S${(season ?: 1).toString().padStart(2, '0')}")
|
||||
append("E${(episode ?: 1).toString().padStart(2, '0')}")
|
||||
if (revision != null) append(" (v$revision)")
|
||||
}
|
||||
|
||||
return buildString {
|
||||
append(baseTitle)
|
||||
append(" - ")
|
||||
append(tag)
|
||||
if (episodeTitle.isNotEmpty()) {
|
||||
append(" - ")
|
||||
append(episodeTitle)
|
||||
}
|
||||
}.trim()
|
||||
}
|
||||
|
||||
|
||||
|
||||
fun File.guessSearchableTitle(): List<String> {
|
||||
val cleaned = this.guessDesiredFileName().noParens()
|
||||
.let {
|
||||
val regex = "\\((?!\\d{4}\\))(?>[^()]+|\\b)\\)"
|
||||
Regex(regex).replace(it, "")
|
||||
}
|
||||
.noResolutionAndAfter()
|
||||
.noSourceTags()
|
||||
.noDots()
|
||||
.noExtraSpaces()
|
||||
.trim('.', ',', ' ')
|
||||
|
||||
val titles = mutableListOf<String>()
|
||||
|
||||
// 1. Første del før bindestrek
|
||||
val firstPart = cleaned.split(" - ").firstOrNull()?.trim() ?: cleaned
|
||||
titles.add(firstPart)
|
||||
|
||||
// 2. Hele cleaned
|
||||
titles.add(cleaned)
|
||||
|
||||
// 3. Fjern årstall hvis det finnes
|
||||
val yearRegex = Regex("""\b(19|20)\d{2}\b""")
|
||||
val noYear = yearRegex.replace(cleaned, "").trim()
|
||||
if (noYear.isNotEmpty() && noYear != cleaned) {
|
||||
titles.add(noYear)
|
||||
}
|
||||
|
||||
return titles.distinct()
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user