diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 0f45a72dae..e604b030a7 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -86,6 +86,17 @@
android:host="mangaplus.shueisha.co.jp"
android:pathPattern="/viewer/..*"
android:scheme="https" />
+
+
+
+
+
diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/SourceManager.kt b/app/src/main/java/eu/kanade/tachiyomi/source/SourceManager.kt
index 9a4e06360f..e7a3825f3b 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/source/SourceManager.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/source/SourceManager.kt
@@ -7,6 +7,7 @@ import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.DelegatedHttpSource
import eu.kanade.tachiyomi.source.online.HttpSource
+import eu.kanade.tachiyomi.source.online.all.Cubari
import eu.kanade.tachiyomi.source.online.all.MangaDex
import eu.kanade.tachiyomi.source.online.english.KireiCake
import eu.kanade.tachiyomi.source.online.english.MangaPlus
@@ -33,6 +34,11 @@ open class SourceManager(private val context: Context) {
"mangaplus.shueisha.co.jp",
1998944621602463790,
MangaPlus()
+ ),
+ DelegatedSource(
+ "cubari.moe",
+ 6338219619148105941,
+ Cubari()
)
).associateBy { it.sourceId }
diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/all/Cubari.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/all/Cubari.kt
new file mode 100644
index 0000000000..bcc3234eda
--- /dev/null
+++ b/app/src/main/java/eu/kanade/tachiyomi/source/online/all/Cubari.kt
@@ -0,0 +1,64 @@
+package eu.kanade.tachiyomi.source.online.all
+
+import android.net.Uri
+import eu.kanade.tachiyomi.R
+import eu.kanade.tachiyomi.data.database.models.Chapter
+import eu.kanade.tachiyomi.data.database.models.Manga
+import eu.kanade.tachiyomi.data.preference.PreferencesHelper
+import eu.kanade.tachiyomi.source.model.SChapter
+import eu.kanade.tachiyomi.source.online.DelegatedHttpSource
+import eu.kanade.tachiyomi.util.system.executeOnIO
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.async
+import kotlinx.coroutines.withContext
+import uy.kohesive.injekt.Injekt
+import uy.kohesive.injekt.api.get
+import java.util.Locale
+
+class Cubari : DelegatedHttpSource() {
+ override val domainName: String = "cubari"
+ override fun canOpenUrl(uri: Uri): Boolean = true
+
+ override fun chapterUrl(uri: Uri): String? = null
+
+ override fun pageNumber(uri: Uri): Int? = uri.pathSegments.getOrNull(4)?.toIntOrNull()
+
+ override suspend fun fetchMangaFromChapterUrl(uri: Uri): Triple>? {
+ val cubariType = uri.pathSegments.getOrNull(1)?.lowercase(Locale.ROOT) ?: return null
+ val cubariPath = uri.pathSegments.getOrNull(2) ?: return null
+ val chapterNumber = uri.pathSegments.getOrNull(3)?.replace("-", ".")?.toFloatOrNull() ?: return null
+ val mangaUrl = "/read/$cubariType/$cubariPath"
+ return withContext(Dispatchers.IO) {
+ val deferredManga = async {
+ db.getManga(mangaUrl, delegate?.id!!).executeAsBlocking() ?: getMangaInfo(mangaUrl)
+ }
+ val deferredChapters = async {
+ db.getManga(mangaUrl, delegate?.id!!).executeAsBlocking()?.let { manga ->
+ val chapters = db.getChapters(manga).executeOnIO()
+ val chapter = findChapter(chapters, cubariType, chapterNumber)
+ if (chapter != null) {
+ return@async chapters
+ }
+ }
+ getChapters(mangaUrl)
+ }
+ val manga = deferredManga.await()
+ val chapters = deferredChapters.await()
+ val context = Injekt.get().context
+ val trueChapter = findChapter(chapters, cubariType, chapterNumber)?.toChapter()
+ ?: error(
+ context.getString(R.string.chapter_not_found)
+ )
+ if (manga != null) {
+ Triple(trueChapter, manga, chapters.orEmpty())
+ } else null
+ }
+ }
+
+ fun findChapter(chapters: List?, cubariType: String, chapterNumber: Float): SChapter? {
+ return when (cubariType) {
+ "imgur" -> chapters?.firstOrNull()
+ else -> chapters?.find { it.chapter_number == chapterNumber }
+ }
+ }
+}