Skip to content

Commit

Permalink
Upgraded to core 12
Browse files Browse the repository at this point in the history
  • Loading branch information
manami-project committed May 3, 2024
1 parent 8cf228e commit 07a44c6
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 77 deletions.
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ version = project.findProperty("release.version") as String? ?: ""

dependencies {
api(kotlin("stdlib"))
api("io.github.manamiproject:modb-core:11.1.0")
api("io.github.manamiproject:modb-core:12.0.0-rc5")

implementation(platform(kotlin("bom")))

Expand Down
159 changes: 83 additions & 76 deletions src/main/kotlin/io/github/manamiproject/modb/notify/NotifyConverter.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
package io.github.manamiproject.modb.notify

import io.github.manamiproject.modb.core.json.Json
import io.github.manamiproject.modb.core.config.MetaDataProviderConfig
import io.github.manamiproject.modb.core.converter.AnimeConverter
import io.github.manamiproject.modb.core.coroutines.ModbDispatchers.LIMITED_CPU
import io.github.manamiproject.modb.core.extensions.*
import io.github.manamiproject.modb.core.extensions.Directory
import io.github.manamiproject.modb.core.extensions.directoryExists
import io.github.manamiproject.modb.core.extensions.readFile
import io.github.manamiproject.modb.core.extensions.regularFileExists
import io.github.manamiproject.modb.core.extractor.DataExtractor
import io.github.manamiproject.modb.core.extractor.ExtractionResult
import io.github.manamiproject.modb.core.extractor.JsonDataExtractor
import io.github.manamiproject.modb.core.models.*
import io.github.manamiproject.modb.core.models.Anime.Status
import io.github.manamiproject.modb.core.models.Anime.Status.*
Expand All @@ -25,6 +30,7 @@ import java.net.URI
*/
public class NotifyConverter(
private val config: MetaDataProviderConfig = NotifyConfig,
private val extractor: DataExtractor = JsonDataExtractor,
private val relationsDir: Directory,
) : AnimeConverter {

Expand All @@ -33,85 +39,109 @@ public class NotifyConverter(
}

override suspend fun convert(rawContent: String): Anime = withContext(LIMITED_CPU) {
val document = Json.parseJson<NotifyDocument>(rawContent)!!
val data = extractor.extract(rawContent, mapOf(
"title" to "$.title.canonical",
"titles" to "$.title",
"synonyms" to "$.title.synonyms",
"episodes" to "$.episodeCount",
"type" to "$.type",
"id" to "$.id",
"imageExtension" to "$.image.extension",
"episodeLength" to "$.episodeLength",
"status" to "$.status",
"startDate" to "$.startDate",
"genres" to "$.genres",
))

return@withContext Anime(
_title = extractTitle(document),
episodes = extractEpisodes(document),
type = extractType(document),
picture = extractPicture(document),
thumbnail = extractThumbnail(document),
status = extractStatus(document),
duration = extractDuration(document),
animeSeason = extractAnimeSeason(document),
).apply {
addSources(extractSourcesEntry(document))
addSynonyms(extractSynonyms(document))
addRelatedAnime(extractRelatedAnime(document))
addTags(extractTags(document))
}
_title = extractTitle(data),
episodes = extractEpisodes(data),
type = extractType(data),
picture = extractPicture(data),
thumbnail = extractThumbnail(data),
status = extractStatus(data),
duration = extractDuration(data),
animeSeason = extractAnimeSeason(data),
sources = extractSourcesEntry(data),
synonyms = extractSynonyms(data),
relatedAnime = extractRelatedAnime(data),
tags = extractTags(data),
)
}

private fun extractTitle(document: NotifyDocument) = document.title[CANONICAL] as String
private fun extractTitle(data: ExtractionResult) = data.string("title")

private fun extractEpisodes(document: NotifyDocument) = document.episodeCount
private fun extractEpisodes(data: ExtractionResult) = data.int("episodes")

private fun extractType(document: NotifyDocument): Type {
return when(document.type.lowercase()) {
private fun extractType(data: ExtractionResult): Type {
return when(data.string("type").trim().lowercase()) {
"tv" -> TV
"movie" -> MOVIE
"ova" -> OVA
"ona" -> ONA
"special" -> SPECIAL
"music" -> SPECIAL
else -> throw IllegalStateException("Unknown type [${document.type}]")
else -> throw IllegalStateException("Unknown type [${data.string("type")}]")
}
}

private fun extractPicture(document: NotifyDocument) = URI("https://media.notify.moe/images/anime/large/${document.id}${document.image.extension}")

private fun extractThumbnail(document: NotifyDocument) = URI("https://media.notify.moe/images/anime/small/${document.id}${document.image.extension}")
private fun extractPicture(data: ExtractionResult) = URI("https://media.notify.moe/images/anime/large/${data.string("id").trim()}${data.string("imageExtension").trim()}")

private fun extractSynonyms(document: NotifyDocument): List<Title> {
val synonyms: List<String> = (document.title[SYNONYMS] as List<*>?)?.map { it as String } ?: emptyList()
private fun extractThumbnail(data: ExtractionResult) = URI("https://media.notify.moe/images/anime/small/${data.string("id").trim()}${data.string("imageExtension").trim()}")

return document.title.filterNot { it.key == CANONICAL }
.filterNot { it.key == SYNONYMS }
private fun extractSynonyms(data: ExtractionResult): HashSet<Title> {
val titles = data.listNotNull<HashMap<String, Title>>("titles")
.first()
.filterNot { it.key == "canonical" }
.filterNot { it.key == "synonyms" }
.values
.union(synonyms)
.map { it as String }
.filterNot { it == data.string("title") }

val synonyms = if (data.notFound("synonyms")) {
emptyList()
} else {
data.listNotNull<Title>("synonyms")
.filterNot { it == data.string("title") }
}

return titles.union(synonyms).toHashSet()
}

private fun extractSourcesEntry(document: NotifyDocument) = listOf(config.buildAnimeLink(document.id))
private fun extractSourcesEntry(data: ExtractionResult) = hashSetOf(config.buildAnimeLink(data.string("id").trim()))

private suspend fun extractRelatedAnime(document: NotifyDocument): List<URI> = withContext(LIMITED_CPU) {
val relationsFile = relationsDir.resolve("${document.id}.${config.fileSuffix()}")
private suspend fun extractRelatedAnime(data: ExtractionResult): HashSet<URI> = withContext(LIMITED_CPU) {
val relationsFile = relationsDir.resolve("${data.string("id")}.${config.fileSuffix()}")

return@withContext if (relationsFile.regularFileExists()) {
Json.parseJson<NotifyRelations>(relationsFile.readFile())!!.items
?.map { it.animeId }
?.map { config.buildAnimeLink(it) }
?: emptyList()
val relatedAnimeData = extractor.extract(relationsFile.readFile(), mapOf(
"relatedAnimeIds" to "$.items.*.animeId"
))

if (relatedAnimeData.notFound("relatedAnimeIds")) {
hashSetOf()
} else {
relatedAnimeData.listNotNull<URI>("relatedAnimeIds") { config.buildAnimeLink(it.trim()) }.toHashSet()
}
} else {
emptyList()
hashSetOf()
}
}

private fun extractStatus(document: NotifyDocument): Status {
return when(document.status) {
private fun extractStatus(data: ExtractionResult): Status {
return when(data.string("status").trim().lowercase()) {
"finished" -> FINISHED
"current" -> ONGOING
"upcoming" -> UPCOMING
"tba" -> Status.UNKNOWN
else -> throw IllegalStateException("Unknown status [${document.status}]")
else -> throw IllegalStateException("Unknown status [${data.string("status")}]")
}
}

private fun extractDuration(document: NotifyDocument) = Duration(document.episodeLength, MINUTES)
private fun extractDuration(data: ExtractionResult) = Duration(data.int("episodeLength"), MINUTES)

private fun extractAnimeSeason(document: NotifyDocument): AnimeSeason {
val month = Regex("-[0-9]{2}-").findAll(document.startDate).firstOrNull()?.value?.replace("-", "")?.toInt() ?: 0
val year = Regex("[0-9]{4}").findAll(document.startDate).firstOrNull()?.value?.toInt() ?: AnimeSeason.UNKNOWN_YEAR
private fun extractAnimeSeason(data: ExtractionResult): AnimeSeason {
val month = Regex("-[0-9]{2}-").findAll(data.string("startDate")).firstOrNull()?.value?.replace("-", "")?.toInt() ?: 0
val year = Regex("[0-9]{4}").findAll(data.string("startDate")).firstOrNull()?.value?.toInt() ?: AnimeSeason.UNKNOWN_YEAR

val season = when(month) {
1, 2, 3 -> WINTER
Expand All @@ -127,34 +157,11 @@ public class NotifyConverter(
)
}

private fun extractTags(document: NotifyDocument): List<Tag> = document.genres ?: emptyList()

private companion object {
private const val CANONICAL = "canonical"
private const val SYNONYMS = "synonyms"
private fun extractTags(data: ExtractionResult): HashSet<Tag> {
return if (data.notFound("genres")) {
hashSetOf()
} else {
data.listNotNull<Title>("genres").toHashSet()
}
}
}

private data class NotifyDocument(
val id: String,
val type: String,
val title: Map<String, Any>,
val startDate: String,
val status: String,
val episodeCount: Int,
val episodeLength: Int,
val genres: List<String>?,
val image: NotifyImage,
)

private data class NotifyImage(
val extension: String,
)

private data class NotifyRelations(
val items: List<NotifyRelation>?,
)

private data class NotifyRelation(
val animeId: String,
)
}

0 comments on commit 07a44c6

Please sign in to comment.