Update parsers and adjust database
This commit is contained in:
@@ -28,15 +28,16 @@ class JsonDeserializer(private val json: JSONObject) {
|
||||
fun toMangaEntity() = MangaEntity(
|
||||
id = json.getLong("id"),
|
||||
title = json.getString("title"),
|
||||
altTitle = json.getStringOrNull("alt_title"),
|
||||
altTitles = json.getStringOrNull("alt_title"),
|
||||
url = json.getString("url"),
|
||||
publicUrl = json.getStringOrNull("public_url").orEmpty(),
|
||||
rating = json.getDouble("rating").toFloat(),
|
||||
isNsfw = json.getBooleanOrDefault("nsfw", false),
|
||||
contentRating = json.getStringOrNull("content_rating"),
|
||||
coverUrl = json.getString("cover_url"),
|
||||
largeCoverUrl = json.getStringOrNull("large_cover_url"),
|
||||
state = json.getStringOrNull("state"),
|
||||
author = json.getStringOrNull("author"),
|
||||
authors = json.getStringOrNull("author"),
|
||||
source = json.getString("source"),
|
||||
)
|
||||
|
||||
|
||||
@@ -58,15 +58,16 @@ class JsonSerializer private constructor(private val json: JSONObject) {
|
||||
JSONObject().apply {
|
||||
put("id", e.id)
|
||||
put("title", e.title)
|
||||
put("alt_title", e.altTitle)
|
||||
put("alt_title", e.altTitles)
|
||||
put("url", e.url)
|
||||
put("public_url", e.publicUrl)
|
||||
put("rating", e.rating)
|
||||
put("nsfw", e.isNsfw)
|
||||
put("content_rating", e.contentRating)
|
||||
put("cover_url", e.coverUrl)
|
||||
put("large_cover_url", e.largeCoverUrl)
|
||||
put("state", e.state)
|
||||
put("author", e.author)
|
||||
put("author", e.authors)
|
||||
put("source", e.source)
|
||||
},
|
||||
)
|
||||
|
||||
@@ -40,6 +40,7 @@ import org.koitharu.kotatsu.core.db.migrations.Migration21To22
|
||||
import org.koitharu.kotatsu.core.db.migrations.Migration22To23
|
||||
import org.koitharu.kotatsu.core.db.migrations.Migration23To24
|
||||
import org.koitharu.kotatsu.core.db.migrations.Migration24To23
|
||||
import org.koitharu.kotatsu.core.db.migrations.Migration24To25
|
||||
import org.koitharu.kotatsu.core.db.migrations.Migration2To3
|
||||
import org.koitharu.kotatsu.core.db.migrations.Migration3To4
|
||||
import org.koitharu.kotatsu.core.db.migrations.Migration4To5
|
||||
@@ -67,7 +68,7 @@ import org.koitharu.kotatsu.tracker.data.TrackEntity
|
||||
import org.koitharu.kotatsu.tracker.data.TrackLogEntity
|
||||
import org.koitharu.kotatsu.tracker.data.TracksDao
|
||||
|
||||
const val DATABASE_VERSION = 24
|
||||
const val DATABASE_VERSION = 25
|
||||
|
||||
@Database(
|
||||
entities = [
|
||||
@@ -136,6 +137,7 @@ fun getDatabaseMigrations(context: Context): Array<Migration> = arrayOf(
|
||||
Migration22To23(),
|
||||
Migration23To24(),
|
||||
Migration24To23(),
|
||||
Migration24To25(),
|
||||
)
|
||||
|
||||
fun MangaDatabase(context: Context): MangaDatabase = Room
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.koitharu.kotatsu.core.db.entity
|
||||
|
||||
import org.koitharu.kotatsu.core.model.MangaSource
|
||||
import org.koitharu.kotatsu.parsers.model.ContentRating
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.parsers.model.MangaChapter
|
||||
import org.koitharu.kotatsu.parsers.model.MangaState
|
||||
@@ -8,8 +9,11 @@ import org.koitharu.kotatsu.parsers.model.MangaTag
|
||||
import org.koitharu.kotatsu.parsers.model.SortOrder
|
||||
import org.koitharu.kotatsu.parsers.util.longHashCode
|
||||
import org.koitharu.kotatsu.parsers.util.mapToSet
|
||||
import org.koitharu.kotatsu.parsers.util.toArraySet
|
||||
import org.koitharu.kotatsu.parsers.util.toTitleCase
|
||||
|
||||
private const val VALUES_DIVIDER = '\n'
|
||||
|
||||
// Entity to model
|
||||
|
||||
fun TagEntity.toMangaTag() = MangaTag(
|
||||
@@ -22,18 +26,19 @@ fun Collection<TagEntity>.toMangaTags() = mapToSet(TagEntity::toMangaTag)
|
||||
|
||||
fun Collection<TagEntity>.toMangaTagsList() = map(TagEntity::toMangaTag)
|
||||
|
||||
fun MangaEntity.toManga(tags: Set<MangaTag>, chapters: List<ChapterEntity>?) = Manga( // TODO
|
||||
fun MangaEntity.toManga(tags: Set<MangaTag>, chapters: List<ChapterEntity>?) = Manga(
|
||||
id = this.id,
|
||||
title = this.title,
|
||||
altTitle = this.altTitle,
|
||||
altTitles = this.altTitles?.split(VALUES_DIVIDER)?.toArraySet().orEmpty(),
|
||||
state = this.state?.let { MangaState(it) },
|
||||
rating = this.rating,
|
||||
isNsfw = this.isNsfw,
|
||||
contentRating = ContentRating(this.contentRating)
|
||||
?: if (isNsfw) ContentRating.ADULT else null,
|
||||
url = this.url,
|
||||
publicUrl = this.publicUrl,
|
||||
coverUrl = this.coverUrl,
|
||||
largeCoverUrl = this.largeCoverUrl,
|
||||
author = this.author,
|
||||
authors = this.authors?.split(VALUES_DIVIDER)?.toArraySet().orEmpty(),
|
||||
source = MangaSource(this.source),
|
||||
tags = tags,
|
||||
chapters = chapters?.toMangaChapters(),
|
||||
@@ -66,12 +71,13 @@ fun Manga.toEntity() = MangaEntity(
|
||||
source = source.name,
|
||||
largeCoverUrl = largeCoverUrl,
|
||||
coverUrl = coverUrl.orEmpty(),
|
||||
altTitle = altTitle,
|
||||
altTitles = altTitles.joinToString(VALUES_DIVIDER.toString()),
|
||||
rating = rating,
|
||||
isNsfw = isNsfw,
|
||||
contentRating = contentRating?.name,
|
||||
state = state?.name,
|
||||
title = title,
|
||||
author = author,
|
||||
authors = authors.joinToString(VALUES_DIVIDER.toString()),
|
||||
)
|
||||
|
||||
fun MangaTag.toEntity() = TagEntity(
|
||||
@@ -108,3 +114,7 @@ fun SortOrder(name: String, fallback: SortOrder): SortOrder = runCatching {
|
||||
fun MangaState(name: String): MangaState? = runCatching {
|
||||
MangaState.valueOf(name)
|
||||
}.getOrNull()
|
||||
|
||||
fun ContentRating(name: String?): ContentRating? = runCatching {
|
||||
ContentRating.valueOf(name ?: return@runCatching null)
|
||||
}.getOrNull()
|
||||
|
||||
@@ -10,14 +10,15 @@ data class MangaEntity(
|
||||
@PrimaryKey(autoGenerate = false)
|
||||
@ColumnInfo(name = "manga_id") val id: Long,
|
||||
@ColumnInfo(name = "title") val title: String,
|
||||
@ColumnInfo(name = "alt_title") val altTitle: String?,
|
||||
@ColumnInfo(name = "alt_title") val altTitles: String?,
|
||||
@ColumnInfo(name = "url") val url: String,
|
||||
@ColumnInfo(name = "public_url") val publicUrl: String,
|
||||
@ColumnInfo(name = "rating") val rating: Float, // normalized value [0..1] or -1
|
||||
@ColumnInfo(name = "nsfw") val isNsfw: Boolean, // TODO change to contentRating
|
||||
@ColumnInfo(name = "nsfw") val isNsfw: Boolean,
|
||||
@ColumnInfo(name = "content_rating") val contentRating: String?,
|
||||
@ColumnInfo(name = "cover_url") val coverUrl: String,
|
||||
@ColumnInfo(name = "large_cover_url") val largeCoverUrl: String?,
|
||||
@ColumnInfo(name = "state") val state: String?,
|
||||
@ColumnInfo(name = "author") val author: String?,
|
||||
@ColumnInfo(name = "author") val authors: String?,
|
||||
@ColumnInfo(name = "source") val source: String,
|
||||
)
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package org.koitharu.kotatsu.core.db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
class Migration24To25 : Migration(24, 25) {
|
||||
|
||||
override fun migrate(db: SupportSQLiteDatabase) {
|
||||
db.execSQL("ALTER TABLE manga ADD COLUMN content_rating TEXT DEFAULT NULL")
|
||||
db.execSQL("UPDATE manga SET content_rating = (SELECT IIF(m.nsfw, 'ADULT', NULL) FROM manga AS m WHERE manga.manga_id = m.manga_id)")
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,8 @@ import kotlinx.parcelize.Parcelize
|
||||
import org.koitharu.kotatsu.core.model.MangaSource
|
||||
import org.koitharu.kotatsu.core.util.ext.readParcelableCompat
|
||||
import org.koitharu.kotatsu.core.util.ext.readSerializableCompat
|
||||
import org.koitharu.kotatsu.core.util.ext.readStringSet
|
||||
import org.koitharu.kotatsu.core.util.ext.writeStringSet
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
|
||||
@Parcelize
|
||||
@@ -20,7 +22,7 @@ data class ParcelableManga(
|
||||
override fun ParcelableManga.write(parcel: Parcel, flags: Int) = with(manga) {
|
||||
parcel.writeLong(id)
|
||||
parcel.writeString(title)
|
||||
parcel.writeString(altTitle)
|
||||
parcel.writeStringSet(altTitles)
|
||||
parcel.writeString(url)
|
||||
parcel.writeString(publicUrl)
|
||||
parcel.writeFloat(rating)
|
||||
@@ -30,7 +32,7 @@ data class ParcelableManga(
|
||||
parcel.writeString(description.takeIf { withDescription })
|
||||
parcel.writeParcelable(ParcelableMangaTags(tags), flags)
|
||||
parcel.writeSerializable(state)
|
||||
parcel.writeString(author)
|
||||
parcel.writeStringSet(authors)
|
||||
parcel.writeString(source.name)
|
||||
}
|
||||
|
||||
@@ -38,7 +40,7 @@ data class ParcelableManga(
|
||||
Manga(
|
||||
id = parcel.readLong(),
|
||||
title = requireNotNull(parcel.readString()),
|
||||
altTitle = parcel.readString(),
|
||||
altTitles = parcel.readStringSet(),
|
||||
url = requireNotNull(parcel.readString()),
|
||||
publicUrl = requireNotNull(parcel.readString()),
|
||||
rating = parcel.readFloat(),
|
||||
@@ -48,7 +50,7 @@ data class ParcelableManga(
|
||||
description = parcel.readString(),
|
||||
tags = requireNotNull(parcel.readParcelableCompat<ParcelableMangaTags>()).tags,
|
||||
state = parcel.readSerializableCompat(),
|
||||
author = parcel.readString(),
|
||||
authors = parcel.readStringSet(),
|
||||
chapters = null,
|
||||
source = MangaSource(parcel.readString()),
|
||||
),
|
||||
|
||||
@@ -2,22 +2,22 @@ package org.koitharu.kotatsu.core.parser
|
||||
|
||||
import org.koitharu.kotatsu.core.exceptions.UnsupportedSourceException
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.MangaParser
|
||||
import org.koitharu.kotatsu.parsers.config.ConfigKey
|
||||
import org.koitharu.kotatsu.parsers.core.AbstractMangaParser
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.parsers.model.MangaChapter
|
||||
import org.koitharu.kotatsu.parsers.model.MangaListFilter
|
||||
import org.koitharu.kotatsu.parsers.model.MangaListFilterCapabilities
|
||||
import org.koitharu.kotatsu.parsers.model.MangaListFilterOptions
|
||||
import org.koitharu.kotatsu.parsers.model.MangaPage
|
||||
import org.koitharu.kotatsu.parsers.model.MangaParserSource
|
||||
import org.koitharu.kotatsu.parsers.model.SortOrder
|
||||
import org.koitharu.kotatsu.parsers.model.search.MangaSearchQuery
|
||||
import org.koitharu.kotatsu.parsers.model.search.MangaSearchQueryCapabilities
|
||||
import java.util.EnumSet
|
||||
|
||||
/**
|
||||
* This parser is just for parser development, it should not be used in releases
|
||||
*/
|
||||
class DummyParser(context: MangaLoaderContext) : MangaParser(context, MangaParserSource.DUMMY) {
|
||||
class DummyParser(context: MangaLoaderContext) : AbstractMangaParser(context, MangaParserSource.DUMMY) {
|
||||
|
||||
override val configKeyDomain: ConfigKey.Domain
|
||||
get() = ConfigKey.Domain("localhost")
|
||||
@@ -25,14 +25,14 @@ class DummyParser(context: MangaLoaderContext) : MangaParser(context, MangaParse
|
||||
override val availableSortOrders: Set<SortOrder>
|
||||
get() = EnumSet.allOf(SortOrder::class.java)
|
||||
|
||||
override val filterCapabilities: MangaListFilterCapabilities
|
||||
get() = MangaListFilterCapabilities()
|
||||
|
||||
override suspend fun getFilterOptions(): MangaListFilterOptions = stub(null)
|
||||
override val searchQueryCapabilities: MangaSearchQueryCapabilities
|
||||
get() = MangaSearchQueryCapabilities()
|
||||
|
||||
override suspend fun getDetails(manga: Manga): Manga = stub(manga)
|
||||
|
||||
override suspend fun getList(offset: Int, order: SortOrder, filter: MangaListFilter): List<Manga> = stub(null)
|
||||
override suspend fun getFilterOptions(): MangaListFilterOptions = stub(null)
|
||||
|
||||
override suspend fun getList(query: MangaSearchQuery): List<Manga> = stub(null)
|
||||
|
||||
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> = stub(null)
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import androidx.core.content.IntentCompat
|
||||
import androidx.core.os.BundleCompat
|
||||
import androidx.core.os.ParcelCompat
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import org.koitharu.kotatsu.parsers.util.toArraySet
|
||||
import java.io.Serializable
|
||||
import java.util.EnumSet
|
||||
|
||||
@@ -84,6 +85,14 @@ fun <E : Enum<E>> Parcel.readEnumSet(cls: Class<E>): Set<E>? {
|
||||
return set
|
||||
}
|
||||
|
||||
fun Parcel.writeStringSet(set: Set<String>?) {
|
||||
writeStringArray(set?.toTypedArray().orEmpty())
|
||||
}
|
||||
|
||||
fun Parcel.readStringSet(): Set<String> {
|
||||
return this.createStringArray()?.toArraySet().orEmpty()
|
||||
}
|
||||
|
||||
fun <T> SavedStateHandle.require(key: String): T {
|
||||
return checkNotNull(get(key)) {
|
||||
"Value $key not found in SavedStateHandle or has a wrong type"
|
||||
|
||||
@@ -31,6 +31,7 @@ class FavouritesContainerViewModel @Inject constructor(
|
||||
val onActionDone = MutableEventFlow<ReversibleAction>()
|
||||
|
||||
private val categoriesStateFlow = favouritesRepository.observeCategoriesForLibrary()
|
||||
.withErrorHandling()
|
||||
.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, null)
|
||||
|
||||
val categories = combine(
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.koitharu.kotatsu.parsers.util.json.getIntOrDefault
|
||||
import org.koitharu.kotatsu.parsers.util.json.getLongOrDefault
|
||||
import org.koitharu.kotatsu.parsers.util.json.getStringOrNull
|
||||
import org.koitharu.kotatsu.parsers.util.json.mapJSONToSet
|
||||
import org.koitharu.kotatsu.parsers.util.json.toStringSet
|
||||
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
|
||||
import org.koitharu.kotatsu.parsers.util.toTitleCase
|
||||
import java.io.File
|
||||
@@ -38,10 +39,12 @@ class MangaIndex(source: String?) {
|
||||
require(!manga.isLocal) { "Local manga information cannot be stored" }
|
||||
json.put(KEY_ID, manga.id)
|
||||
json.put(KEY_TITLE, manga.title)
|
||||
json.put(KEY_TITLE_ALT, manga.altTitle)
|
||||
json.put(KEY_TITLE_ALT, manga.altTitle) // for backward compatibility
|
||||
json.put(KEY_ALT_TITLES, JSONArray(manga.altTitles))
|
||||
json.put(KEY_URL, manga.url)
|
||||
json.put(KEY_PUBLIC_URL, manga.publicUrl)
|
||||
json.put(KEY_AUTHOR, manga.author)
|
||||
json.put(KEY_AUTHOR, manga.author) // for backward compatibility
|
||||
json.put(KEY_AUTHORS, JSONArray(manga.authors))
|
||||
json.put(KEY_COVER, manga.coverUrl)
|
||||
json.put(KEY_DESCRIPTION, manga.description)
|
||||
json.put(KEY_RATING, manga.rating)
|
||||
@@ -73,10 +76,12 @@ class MangaIndex(source: String?) {
|
||||
Manga(
|
||||
id = json.getLong(KEY_ID),
|
||||
title = json.getString(KEY_TITLE),
|
||||
altTitle = json.getStringOrNull(KEY_TITLE_ALT),
|
||||
altTitles = json.optJSONArray(KEY_ALT_TITLES)?.toStringSet()
|
||||
?: setOfNotNull(json.getStringOrNull(KEY_TITLE_ALT)),
|
||||
url = json.getString(KEY_URL),
|
||||
publicUrl = json.getStringOrNull(KEY_PUBLIC_URL).orEmpty(),
|
||||
author = json.getStringOrNull(KEY_AUTHOR),
|
||||
authors = json.optJSONArray(KEY_AUTHORS)?.toStringSet()
|
||||
?: setOfNotNull(json.getStringOrNull(KEY_AUTHOR)),
|
||||
largeCoverUrl = json.getStringOrNull(KEY_COVER_LARGE),
|
||||
source = source,
|
||||
rating = json.getFloatOrDefault(KEY_RATING, RATING_UNKNOWN),
|
||||
@@ -198,9 +203,11 @@ class MangaIndex(source: String?) {
|
||||
private const val KEY_ID = "id"
|
||||
private const val KEY_TITLE = "title"
|
||||
private const val KEY_TITLE_ALT = "title_alt"
|
||||
private const val KEY_ALT_TITLES = "alt_titles"
|
||||
private const val KEY_URL = "url"
|
||||
private const val KEY_PUBLIC_URL = "public_url"
|
||||
private const val KEY_AUTHOR = "author"
|
||||
private const val KEY_AUTHORS = "authors"
|
||||
private const val KEY_COVER = "cover"
|
||||
private const val KEY_DESCRIPTION = "description"
|
||||
private const val KEY_RATING = "rating"
|
||||
|
||||
@@ -126,12 +126,12 @@ class LocalMangaParser(private val uri: Uri) {
|
||||
} else {
|
||||
null
|
||||
},
|
||||
altTitle = null,
|
||||
altTitles = emptySet(),
|
||||
rating = -1f,
|
||||
contentRating = null,
|
||||
tags = setOf(),
|
||||
tags = emptySet(),
|
||||
state = null,
|
||||
author = null,
|
||||
authors = emptySet(),
|
||||
largeCoverUrl = null,
|
||||
description = null,
|
||||
)
|
||||
|
||||
@@ -31,7 +31,7 @@ material = "1.13.0-alpha10"
|
||||
moshi = "1.15.2"
|
||||
okhttp = "4.12.0"
|
||||
okio = "3.10.2"
|
||||
parsers = "1.6"
|
||||
parsers = "ddb9b13df7"
|
||||
preference = "1.2.1"
|
||||
recyclerview = "1.4.0"
|
||||
room = "2.6.1"
|
||||
|
||||
Reference in New Issue
Block a user