diff --git a/app/src/main/java/org/koitharu/kotatsu/core/backup/BackupRepository.kt b/app/src/main/java/org/koitharu/kotatsu/core/backup/BackupRepository.kt index c82914ff1..2823b97b9 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/backup/BackupRepository.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/backup/BackupRepository.kt @@ -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) diff --git a/app/src/main/java/org/koitharu/kotatsu/core/backup/RestoreRepository.kt b/app/src/main/java/org/koitharu/kotatsu/core/backup/RestoreRepository.kt index 4a7098c78..4a0e1c368 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/backup/RestoreRepository.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/backup/RestoreRepository.kt @@ -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"), diff --git a/app/src/main/java/org/koitharu/kotatsu/core/db/DatabaseModule.kt b/app/src/main/java/org/koitharu/kotatsu/core/db/DatabaseModule.kt index 44463143f..59906c088 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/db/DatabaseModule.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/db/DatabaseModule.kt @@ -17,7 +17,8 @@ val databaseModule Migration2To3(), Migration3To4(), Migration4To5(), - Migration5To6() + Migration5To6(), + Migration6To7() ).addCallback( DatabasePrePopulateCallback(androidContext().resources) ).build() diff --git a/app/src/main/java/org/koitharu/kotatsu/core/db/MangaDatabase.kt b/app/src/main/java/org/koitharu/kotatsu/core/db/MangaDatabase.kt index b207504f6..0090e416d 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/db/MangaDatabase.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/db/MangaDatabase.kt @@ -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() { diff --git a/app/src/main/java/org/koitharu/kotatsu/core/db/entity/MangaEntity.kt b/app/src/main/java/org/koitharu/kotatsu/core/db/entity/MangaEntity.kt index 064e65795..b4b4152a1 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/db/entity/MangaEntity.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/db/entity/MangaEntity.kt @@ -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, diff --git a/app/src/main/java/org/koitharu/kotatsu/core/db/migrations/Migration6To7.kt b/app/src/main/java/org/koitharu/kotatsu/core/db/migrations/Migration6To7.kt new file mode 100644 index 000000000..08c742853 --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/core/db/migrations/Migration6To7.kt @@ -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 ''") + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/core/model/Manga.kt b/app/src/main/java/org/koitharu/kotatsu/core/model/Manga.kt index b550fdd92..2854df336 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/model/Manga.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/model/Manga.kt @@ -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, diff --git a/app/src/main/java/org/koitharu/kotatsu/core/parser/RemoteMangaRepository.kt b/app/src/main/java/org/koitharu/kotatsu/core/parser/RemoteMangaRepository.kt index 864a14179..ce91c0ddc 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/parser/RemoteMangaRepository.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/parser/RemoteMangaRepository.kt @@ -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) } diff --git a/app/src/main/java/org/koitharu/kotatsu/core/parser/site/ChanRepository.kt b/app/src/main/java/org/koitharu/kotatsu/core/parser/site/ChanRepository.kt index dc293ff87..e5828c154 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/parser/site/ChanRepository.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/parser/site/ChanRepository.kt @@ -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( diff --git a/app/src/main/java/org/koitharu/kotatsu/core/parser/site/DesuMeRepository.kt b/app/src/main/java/org/koitharu/kotatsu/core/parser/site/DesuMeRepository.kt index 21c21ab8c..c09530342 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/parser/site/DesuMeRepository.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/parser/site/DesuMeRepository.kt @@ -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") diff --git a/app/src/main/java/org/koitharu/kotatsu/core/parser/site/GroupleRepository.kt b/app/src/main/java/org/koitharu/kotatsu/core/parser/site/GroupleRepository.kt index cc497999b..b680b5cf0 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/parser/site/GroupleRepository.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/parser/site/GroupleRepository.kt @@ -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(), diff --git a/app/src/main/java/org/koitharu/kotatsu/core/parser/site/MangaLibRepository.kt b/app/src/main/java/org/koitharu/kotatsu/core/parser/site/MangaLibRepository.kt index 27541b2f1..b526944b6 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/parser/site/MangaLibRepository.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/parser/site/MangaLibRepository.kt @@ -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, diff --git a/app/src/main/java/org/koitharu/kotatsu/core/parser/site/MangaTownRepository.kt b/app/src/main/java/org/koitharu/kotatsu/core/parser/site/MangaTownRepository.kt index 4f7df80bd..4fb4085dc 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/parser/site/MangaTownRepository.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/parser/site/MangaTownRepository.kt @@ -77,7 +77,8 @@ class MangaTownRepository(loaderContext: MangaLoaderContext) : source = MangaSource.MANGATOWN ) }.orEmpty(), - url = href + url = href, + publicUrl = href.inContextOf(a) ) } } diff --git a/app/src/main/java/org/koitharu/kotatsu/core/parser/site/MangareadRepository.kt b/app/src/main/java/org/koitharu/kotatsu/core/parser/site/MangareadRepository.kt index 2a07a1b32..e4677e1be 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/parser/site/MangareadRepository.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/parser/site/MangareadRepository.kt @@ -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(), diff --git a/app/src/main/java/org/koitharu/kotatsu/core/parser/site/RemangaRepository.kt b/app/src/main/java/org/koitharu/kotatsu/core/parser/site/RemangaRepository.kt index 4c2630666..79d0d2581 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/parser/site/RemangaRepository.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/parser/site/RemangaRepository.kt @@ -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 { 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(content.length()) for (i in 0 until content.length()) { diff --git a/app/src/main/java/org/koitharu/kotatsu/local/data/MangaIndex.kt b/app/src/main/java/org/koitharu/kotatsu/local/data/MangaIndex.kt index 3edc96ee4..8b0b92033 100644 --- a/app/src/main/java/org/koitharu/kotatsu/local/data/MangaIndex.kt +++ b/app/src/main/java/org/koitharu/kotatsu/local/data/MangaIndex.kt @@ -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"), diff --git a/app/src/main/java/org/koitharu/kotatsu/local/domain/LocalMangaRepository.kt b/app/src/main/java/org/koitharu/kotatsu/local/domain/LocalMangaRepository.kt index 7f0548509..b2674ae1d 100644 --- a/app/src/main/java/org/koitharu/kotatsu/local/domain/LocalMangaRepository.kt +++ b/app/src/main/java/org/koitharu/kotatsu/local/domain/LocalMangaRepository.kt @@ -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 -> diff --git a/app/src/test/java/org/koitharu/kotatsu/parsers/RemoteRepositoryTest.kt b/app/src/test/java/org/koitharu/kotatsu/parsers/RemoteRepositoryTest.kt index dd3bf6c13..e75b6d32e 100644 --- a/app/src/test/java/org/koitharu/kotatsu/parsers/RemoteRepositoryTest.kt +++ b/app/src/test/java/org/koitharu/kotatsu/parsers/RemoteRepositoryTest.kt @@ -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()