Add "public url" field to manga

This commit is contained in:
Koitharu
2021-02-02 08:01:30 +02:00
parent 1f2f40f077
commit 3357c00578
18 changed files with 63 additions and 15 deletions

View File

@@ -81,6 +81,7 @@ class BackupRepository(private val db: MangaDatabase) {
jo.put("title", title)
jo.put("alt_title", altTitle)
jo.put("url", url)
jo.put("public_url", publicUrl)
jo.put("rating", rating)
jo.put("cover_url", coverUrl)
jo.put("large_cover_url", largeCoverUrl)

View File

@@ -70,6 +70,7 @@ class RestoreRepository(private val db: MangaDatabase) {
title = json.getString("title"),
altTitle = json.getStringOrNull("alt_title"),
url = json.getString("url"),
publicUrl = json.getStringOrNull("public_url").orEmpty(),
rating = json.getDouble("rating").toFloat(),
coverUrl = json.getString("cover_url"),
largeCoverUrl = json.getStringOrNull("large_cover_url"),

View File

@@ -17,7 +17,8 @@ val databaseModule
Migration2To3(),
Migration3To4(),
Migration4To5(),
Migration5To6()
Migration5To6(),
Migration6To7()
).addCallback(
DatabasePrePopulateCallback(androidContext().resources)
).build()

View File

@@ -16,7 +16,7 @@ import org.koitharu.kotatsu.history.data.HistoryEntity
MangaEntity::class, TagEntity::class, HistoryEntity::class, MangaTagsEntity::class,
FavouriteCategoryEntity::class, FavouriteEntity::class, MangaPrefsEntity::class,
TrackEntity::class, TrackLogEntity::class
], version = 6
], version = 7
)
abstract class MangaDatabase : RoomDatabase() {

View File

@@ -15,6 +15,7 @@ data class MangaEntity(
@ColumnInfo(name = "title") val title: String,
@ColumnInfo(name = "alt_title") val altTitle: String? = null,
@ColumnInfo(name = "url") val url: String,
@ColumnInfo(name = "public_url") val publicUrl: String,
@ColumnInfo(name = "rating") val rating: Float = Manga.NO_RATING, //normalized value [0..1] or -1
@ColumnInfo(name = "cover_url") val coverUrl: String,
@ColumnInfo(name = "large_cover_url") val largeCoverUrl: String? = null,
@@ -30,6 +31,7 @@ data class MangaEntity(
state = this.state?.let { MangaState.valueOf(it) },
rating = this.rating,
url = this.url,
publicUrl = this.publicUrl,
coverUrl = this.coverUrl,
largeCoverUrl = this.largeCoverUrl,
author = this.author,
@@ -42,6 +44,7 @@ data class MangaEntity(
fun from(manga: Manga) = MangaEntity(
id = manga.id,
url = manga.url,
publicUrl = manga.publicUrl,
source = manga.source.name,
largeCoverUrl = manga.largeCoverUrl,
coverUrl = manga.coverUrl,

View File

@@ -0,0 +1,11 @@
package org.koitharu.kotatsu.core.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
class Migration6To7 : Migration(6, 7) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE manga ADD COLUMN public_url TEXT NOT NULL DEFAULT ''")
}
}

View File

@@ -8,7 +8,8 @@ data class Manga(
val id: Long,
val title: String,
val altTitle: String? = null,
val url: String,
val url: String, // relative url for internal use
val publicUrl: String,
val rating: Float = NO_RATING, //normalized value [0..1] or -1
val coverUrl: String,
val largeCoverUrl: String? = null,

View File

@@ -31,7 +31,7 @@ abstract class RemoteMangaRepository(
protected fun getDomain() = conf.getDomain(defaultDomain)
protected fun String.withDomain() = when {
protected fun String.withDomain(subdomain: String? = null) = when {
this.startsWith("//") -> buildString {
append("http")
if (conf.isUseSsl(true)) {
@@ -46,6 +46,10 @@ abstract class RemoteMangaRepository(
append('s')
}
append("://")
if (subdomain != null) {
append(subdomain)
append('.')
}
append(conf.getDomain(defaultDomain))
append(this@withDomain)
}

View File

@@ -44,6 +44,7 @@ abstract class ChanRepository(loaderContext: MangaLoaderContext) : RemoteMangaRe
Manga(
id = generateUid(href),
url = href,
publicUrl = href.inContextOf(a),
altTitle = a.attr("title"),
title = a.text().substringAfterLast('(').substringBeforeLast(')'),
author = row.getElementsByAttributeValueStarting(

View File

@@ -57,6 +57,7 @@ class DesuMeRepository(loaderContext: MangaLoaderContext) : RemoteMangaRepositor
val id = jo.getLong("id")
list += Manga(
url = "/manga/api/$id",
publicUrl = jo.getString("url"),
source = MangaSource.DESUME,
title = jo.getString("russian"),
altTitle = jo.getString("name"),
@@ -89,6 +90,7 @@ class DesuMeRepository(loaderContext: MangaLoaderContext) : RemoteMangaRepositor
source = manga.source
)
},
publicUrl = json.getString("url"),
description = json.getString("description"),
chapters = chaptersList.mapIndexed { i, it ->
val chid = it.getLong("id")

View File

@@ -1,12 +1,10 @@
package org.koitharu.kotatsu.core.parser.site
import androidx.collection.arraySetOf
import okhttp3.HttpUrl.Companion.toHttpUrl
import org.koitharu.kotatsu.base.domain.MangaLoaderContext
import org.koitharu.kotatsu.core.exceptions.ParseException
import org.koitharu.kotatsu.core.model.*
import org.koitharu.kotatsu.core.parser.RemoteMangaRepository
import org.koitharu.kotatsu.core.prefs.SourceSettings
import org.koitharu.kotatsu.utils.ext.*
import java.util.*
@@ -70,6 +68,7 @@ abstract class GroupleRepository(loaderContext: MangaLoaderContext) :
Manga(
id = generateUid(relUrl),
url = relUrl,
publicUrl = href,
title = title,
altTitle = descDiv.selectFirst("h4")?.text(),
coverUrl = imgDiv.selectFirst("img.lazy")?.attr("data-original").orEmpty(),

View File

@@ -1,7 +1,6 @@
package org.koitharu.kotatsu.core.parser.site
import androidx.collection.ArraySet
import androidx.collection.arraySetOf
import org.json.JSONArray
import org.json.JSONObject
import org.koitharu.kotatsu.base.domain.MangaLoaderContext
@@ -9,7 +8,6 @@ import org.koitharu.kotatsu.core.exceptions.AuthRequiredException
import org.koitharu.kotatsu.core.exceptions.ParseException
import org.koitharu.kotatsu.core.model.*
import org.koitharu.kotatsu.core.parser.RemoteMangaRepository
import org.koitharu.kotatsu.core.prefs.SourceSettings
import org.koitharu.kotatsu.utils.ext.*
import java.util.*
import kotlin.collections.ArrayList
@@ -65,6 +63,7 @@ open class MangaLibRepository(loaderContext: MangaLoaderContext) :
author = null,
rating = Manga.NO_RATING,
url = href,
publicUrl = href.inContextOf(a),
tags = emptySet(),
state = null,
source = source
@@ -218,11 +217,12 @@ open class MangaLibRepository(loaderContext: MangaLoaderContext) :
.parseJsonArray()
return json.map { jo ->
val slug = jo.getString("slug")
val url = "https://$domain/$slug"
val url = "/$slug"
val covers = jo.getJSONObject("covers")
Manga(
id = generateUid(slug),
id = generateUid(url),
url = url,
publicUrl = "https://$domain/$slug",
title = jo.getString("rus_name"),
altTitle = jo.getString("name"),
author = null,

View File

@@ -77,7 +77,8 @@ class MangaTownRepository(loaderContext: MangaLoaderContext) :
source = MangaSource.MANGATOWN
)
}.orEmpty(),
url = href
url = href,
publicUrl = href.inContextOf(a)
)
}
}

View File

@@ -1,11 +1,9 @@
package org.koitharu.kotatsu.core.parser.site
import androidx.collection.arraySetOf
import org.koitharu.kotatsu.base.domain.MangaLoaderContext
import org.koitharu.kotatsu.core.exceptions.ParseException
import org.koitharu.kotatsu.core.model.*
import org.koitharu.kotatsu.core.parser.RemoteMangaRepository
import org.koitharu.kotatsu.core.prefs.SourceSettings
import org.koitharu.kotatsu.utils.ext.*
import java.util.*
@@ -50,6 +48,7 @@ class MangareadRepository(
Manga(
id = generateUid(href),
url = href,
publicUrl = href.inContextOf(div),
coverUrl = div.selectFirst("img").attr("data-srcset")
.split(',').firstOrNull()?.substringBeforeLast(' ').orEmpty(),
title = summary.selectFirst("h3").text(),

View File

@@ -58,6 +58,7 @@ class RemangaRepository(loaderContext: MangaLoaderContext) : RemoteMangaReposito
Manga(
id = generateUid(url),
url = url,
publicUrl = "https://$domain$url",
title = jo.getString("rus_name"),
altTitle = jo.getString("en_name"),
rating = jo.getString("avg_rating").toFloatOrNull()?.div(10f) ?: Manga.NO_RATING,
@@ -112,7 +113,7 @@ class RemangaRepository(loaderContext: MangaLoaderContext) : RemoteMangaReposito
val name = jo.getString("name")
MangaChapter(
id = generateUid(id),
url = "https://api.$domain/api/titles/chapters/$id/",
url = "/api/titles/chapters/$id/",
number = chapters.length() - i,
name = buildString {
append("Глава ")
@@ -130,7 +131,7 @@ class RemangaRepository(loaderContext: MangaLoaderContext) : RemoteMangaReposito
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
val referer = "https://${getDomain()}/"
val content = loaderContext.httpGet(chapter.url.withDomain()).parseJson()
val content = loaderContext.httpGet(chapter.url.withDomain(subdomain = "api")).parseJson()
.getJSONObject("content").getJSONArray("pages")
val pages = ArrayList<MangaPage>(content.length())
for (i in 0 until content.length()) {

View File

@@ -19,6 +19,7 @@ class MangaIndex(source: String?) {
json.put("title", manga.title)
json.put("title_alt", manga.altTitle)
json.put("url", manga.url)
json.put("public_url", manga.publicUrl)
json.put("cover", manga.coverUrl)
json.put("description", manga.description)
json.put("rating", manga.rating)
@@ -46,6 +47,7 @@ class MangaIndex(source: String?) {
title = json.getString("title"),
altTitle = json.getStringOrNull("title_alt"),
url = json.getString("url"),
publicUrl = json.getStringOrNull("public_url").orEmpty(),
source = source,
rating = json.getDouble("rating").toFloat(),
coverUrl = json.getString("cover"),

View File

@@ -112,6 +112,7 @@ class LocalMangaRepository(private val context: Context) : MangaRepository {
id = file.absolutePath.longHashCode(),
title = title,
url = fileUri,
publicUrl = fileUri,
source = MangaSource.LOCAL,
coverUrl = zipUri(file, findFirstEntry(zip.entries(), isImage = true)?.name.orEmpty()),
chapters = chapters.sortedWith(AlphanumComparator()).mapIndexed { i, s ->

View File

@@ -40,6 +40,11 @@ class RemoteRepositoryTest(source: MangaSource) : KoinTest {
AssertX.assertUrlRelative("Url is not relative", item.url)
AssertX.assertUrlAbsolute("Url is not absolute", item.coverUrl)
AssertX.assertContentType("Bad cover at ${item.url}", item.coverUrl, "image/*")
AssertX.assertContentType(
"invalid public url ${item.publicUrl}",
item.publicUrl,
"text/html"
)
Assert.assertFalse("Title is blank at ${item.url}", item.title.isBlank())
}
@@ -51,6 +56,11 @@ class RemoteRepositoryTest(source: MangaSource) : KoinTest {
val item = list.random()
AssertX.assertUrlRelative("Url is not relative", item.url)
AssertX.assertContentType("Bad cover at ${item.url}", item.coverUrl, "image/*")
AssertX.assertContentType(
"invalid public url ${item.publicUrl}",
item.publicUrl,
"text/html"
)
Assert.assertFalse("Title is blank at ${item.url}", item.title.isBlank())
}
@@ -66,6 +76,11 @@ class RemoteRepositoryTest(source: MangaSource) : KoinTest {
val item = list.random()
AssertX.assertUrlRelative("Url is not relative", item.url)
AssertX.assertContentType("Bad cover at ${item.coverUrl}", item.coverUrl, "image/*")
AssertX.assertContentType(
"invalid public url ${item.publicUrl}",
item.publicUrl,
"text/html"
)
Assert.assertFalse("Title is blank at ${item.url}", item.title.isBlank())
}
@@ -74,6 +89,11 @@ class RemoteRepositoryTest(source: MangaSource) : KoinTest {
val manga = runBlocking { repo.getList(0) }.random()
val details = runBlocking { repo.getDetails(manga) }
Assert.assertFalse("No chapters at ${details.url}", details.chapters.isNullOrEmpty())
AssertX.assertContentType(
"invalid public url ${details.publicUrl}",
details.publicUrl,
"text/html"
)
Assert.assertFalse(
"Description is empty at ${details.url}",
details.description.isNullOrEmpty()