2017-05-05 05:38:17 +02:00
|
|
|
package exh
|
|
|
|
|
|
2020-07-16 01:16:21 +02:00
|
|
|
import android.content.Context
|
2020-11-21 22:24:16 +01:00
|
|
|
import androidx.core.net.toUri
|
2022-07-03 05:52:03 +02:00
|
|
|
import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource
|
|
|
|
|
import eu.kanade.domain.manga.interactor.UpdateManga
|
2023-01-22 16:54:28 +01:00
|
|
|
import eu.kanade.domain.manga.model.toSManga
|
2022-09-18 16:36:41 +02:00
|
|
|
import eu.kanade.domain.source.service.SourcePreferences
|
2020-07-16 01:16:21 +02:00
|
|
|
import eu.kanade.tachiyomi.R
|
2019-08-07 16:21:18 +02:00
|
|
|
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
2019-04-15 00:53:34 +02:00
|
|
|
import eu.kanade.tachiyomi.source.online.all.EHentai
|
2021-03-07 06:23:23 +01:00
|
|
|
import exh.log.xLogStack
|
2020-10-28 00:52:32 +01:00
|
|
|
import exh.source.getMainSource
|
2023-02-18 21:14:04 +01:00
|
|
|
import tachiyomi.domain.chapter.interactor.GetChapter
|
2023-01-22 16:54:28 +01:00
|
|
|
import tachiyomi.domain.chapter.model.Chapter
|
2023-02-18 21:14:04 +01:00
|
|
|
import tachiyomi.domain.manga.interactor.GetManga
|
|
|
|
|
import tachiyomi.domain.manga.interactor.NetworkToLocalManga
|
2023-01-22 16:54:28 +01:00
|
|
|
import tachiyomi.domain.manga.model.Manga
|
2023-03-05 18:38:31 +01:00
|
|
|
import tachiyomi.domain.source.service.SourceManager
|
2020-12-20 08:27:58 +01:00
|
|
|
import uy.kohesive.injekt.Injekt
|
|
|
|
|
import uy.kohesive.injekt.api.get
|
2017-05-05 05:38:17 +02:00
|
|
|
|
2022-07-03 05:52:03 +02:00
|
|
|
class GalleryAdder(
|
2022-07-03 19:37:27 +02:00
|
|
|
private val getManga: GetManga = Injekt.get(),
|
2022-07-03 05:52:03 +02:00
|
|
|
private val updateManga: UpdateManga = Injekt.get(),
|
2022-10-27 05:01:21 +02:00
|
|
|
private val networkToLocalManga: NetworkToLocalManga = Injekt.get(),
|
2022-07-03 21:48:13 +02:00
|
|
|
private val getChapter: GetChapter = Injekt.get(),
|
2022-07-03 05:52:03 +02:00
|
|
|
private val syncChaptersWithSource: SyncChaptersWithSource = Injekt.get(),
|
|
|
|
|
private val sourceManager: SourceManager = Injekt.get(),
|
|
|
|
|
) {
|
|
|
|
|
|
2022-09-18 16:36:41 +02:00
|
|
|
private val filters: Pair<Set<String>, Set<Long>> = Injekt.get<SourcePreferences>().run {
|
2022-07-03 05:52:03 +02:00
|
|
|
enabledLanguages().get() to disabledSources().get().map { it.toLong() }.toSet()
|
2020-12-20 08:27:58 +01:00
|
|
|
}
|
|
|
|
|
|
2022-07-24 21:29:48 +02:00
|
|
|
private val Pair<Set<String>, Set<Long>>.enabledLangs
|
|
|
|
|
get() = first
|
|
|
|
|
private val Pair<Set<String>, Set<Long>>.disabledSources
|
|
|
|
|
get() = second
|
|
|
|
|
|
2021-03-07 06:23:23 +01:00
|
|
|
private val logger = xLogStack()
|
2020-11-25 21:57:05 +01:00
|
|
|
|
2020-10-20 00:41:41 +02:00
|
|
|
fun pickSource(url: String): List<UrlImportableSource> {
|
2020-11-21 22:24:16 +01:00
|
|
|
val uri = url.toUri()
|
2020-10-20 00:41:41 +02:00
|
|
|
return sourceManager.getVisibleCatalogueSources()
|
2021-07-25 20:16:16 +02:00
|
|
|
.mapNotNull { it.getMainSource<UrlImportableSource>() }
|
2020-10-20 00:41:41 +02:00
|
|
|
.filter {
|
2022-07-24 21:29:48 +02:00
|
|
|
it.lang in filters.enabledLangs && it.id !in filters.disabledSources && try {
|
2020-10-20 00:41:41 +02:00
|
|
|
it.matchesUri(uri)
|
|
|
|
|
} catch (e: Exception) {
|
|
|
|
|
false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-29 20:29:43 +01:00
|
|
|
suspend fun addGallery(
|
2020-07-16 01:16:21 +02:00
|
|
|
context: Context,
|
2020-04-04 22:30:05 +02:00
|
|
|
url: String,
|
|
|
|
|
fav: Boolean = false,
|
|
|
|
|
forceSource: UrlImportableSource? = null,
|
2022-04-08 21:30:30 +02:00
|
|
|
throttleFunc: suspend () -> Unit = {},
|
2020-04-04 22:30:05 +02:00
|
|
|
): GalleryAddEvent {
|
2022-11-29 23:30:04 +01:00
|
|
|
logger.d(context.getString(R.string.gallery_adder_importing_gallery, url, fav.toString(), forceSource))
|
2017-08-24 18:28:54 +02:00
|
|
|
try {
|
2020-11-21 22:24:16 +01:00
|
|
|
val uri = url.toUri()
|
2019-08-07 16:21:18 +02:00
|
|
|
|
|
|
|
|
// Find matching source
|
2020-04-04 22:30:05 +02:00
|
|
|
val source = if (forceSource != null) {
|
2019-08-07 16:21:18 +02:00
|
|
|
try {
|
2022-09-12 01:43:45 +02:00
|
|
|
if (forceSource.matchesUri(uri)) {
|
|
|
|
|
forceSource
|
|
|
|
|
} else {
|
|
|
|
|
return GalleryAddEvent.Fail.UnknownSource(url, context)
|
|
|
|
|
}
|
2020-04-04 22:30:05 +02:00
|
|
|
} catch (e: Exception) {
|
2020-11-25 21:57:05 +01:00
|
|
|
logger.e(context.getString(R.string.gallery_adder_source_uri_must_match), e)
|
2020-07-16 01:16:21 +02:00
|
|
|
return GalleryAddEvent.Fail.UnknownType(url, context)
|
2017-12-08 04:25:27 +01:00
|
|
|
}
|
2019-08-07 16:21:18 +02:00
|
|
|
} else {
|
|
|
|
|
sourceManager.getVisibleCatalogueSources()
|
2021-07-25 20:16:16 +02:00
|
|
|
.mapNotNull { it.getMainSource<UrlImportableSource>() }
|
2020-06-21 06:44:04 +02:00
|
|
|
.find {
|
2022-07-24 21:29:48 +02:00
|
|
|
it.lang in filters.enabledLangs && it.id !in filters.disabledSources && try {
|
2020-06-21 06:44:04 +02:00
|
|
|
it.matchesUri(uri)
|
|
|
|
|
} catch (e: Exception) {
|
2020-05-02 06:46:24 +02:00
|
|
|
false
|
|
|
|
|
}
|
2021-01-10 23:28:52 +01:00
|
|
|
} ?: return GalleryAddEvent.Fail.UnknownSource(url, context)
|
2017-05-09 02:03:20 +02:00
|
|
|
}
|
|
|
|
|
|
2020-12-26 22:13:55 +01:00
|
|
|
val realChapterUrl = try {
|
|
|
|
|
source.mapUrlToChapterUrl(uri)
|
|
|
|
|
} catch (e: Exception) {
|
|
|
|
|
logger.e(context.getString(R.string.gallery_adder_uri_map_to_chapter_error), e)
|
|
|
|
|
null
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
val cleanedChapterUrl = if (realChapterUrl != null) {
|
|
|
|
|
try {
|
|
|
|
|
source.cleanChapterUrl(realChapterUrl)
|
|
|
|
|
} catch (e: Exception) {
|
|
|
|
|
logger.e(context.getString(R.string.gallery_adder_uri_clean_error), e)
|
|
|
|
|
null
|
|
|
|
|
}
|
2022-09-12 01:43:45 +02:00
|
|
|
} else {
|
|
|
|
|
null
|
|
|
|
|
}
|
2020-12-26 22:13:55 +01:00
|
|
|
|
|
|
|
|
val chapterMangaUrl = if (realChapterUrl != null) {
|
|
|
|
|
source.mapChapterUrlToMangaUrl(realChapterUrl.toUri())
|
2022-09-12 01:43:45 +02:00
|
|
|
} else {
|
|
|
|
|
null
|
|
|
|
|
}
|
2020-12-26 22:13:55 +01:00
|
|
|
|
2019-08-07 16:21:18 +02:00
|
|
|
// Map URL to manga URL
|
2020-12-26 20:22:55 +01:00
|
|
|
val realMangaUrl = try {
|
2020-12-26 22:13:55 +01:00
|
|
|
chapterMangaUrl ?: source.mapUrlToMangaUrl(uri)
|
2020-04-04 22:30:05 +02:00
|
|
|
} catch (e: Exception) {
|
2022-11-29 23:30:04 +01:00
|
|
|
logger.e(context.getString(R.string.gallery_adder_uri_map_to_gallery_error), e)
|
2019-08-07 16:21:18 +02:00
|
|
|
null
|
2020-07-16 01:16:21 +02:00
|
|
|
} ?: return GalleryAddEvent.Fail.UnknownType(url, context)
|
2019-08-07 16:21:18 +02:00
|
|
|
|
|
|
|
|
// Clean URL
|
2020-12-26 20:22:55 +01:00
|
|
|
val cleanedMangaUrl = try {
|
|
|
|
|
source.cleanMangaUrl(realMangaUrl)
|
2020-04-04 22:30:05 +02:00
|
|
|
} catch (e: Exception) {
|
2020-11-25 21:57:05 +01:00
|
|
|
logger.e(context.getString(R.string.gallery_adder_uri_clean_error), e)
|
2019-08-07 16:21:18 +02:00
|
|
|
null
|
2020-07-16 01:16:21 +02:00
|
|
|
} ?: return GalleryAddEvent.Fail.UnknownType(url, context)
|
2017-05-05 05:38:17 +02:00
|
|
|
|
2020-04-04 22:30:05 +02:00
|
|
|
// Use manga in DB if possible, otherwise, make a new manga
|
2022-07-03 19:37:27 +02:00
|
|
|
var manga = getManga.await(cleanedMangaUrl, source.id)
|
2022-10-27 05:01:21 +02:00
|
|
|
?: networkToLocalManga.await(
|
|
|
|
|
Manga.create().copy(
|
|
|
|
|
source = source.id,
|
|
|
|
|
url = cleanedMangaUrl,
|
|
|
|
|
),
|
|
|
|
|
)
|
2019-04-14 15:09:24 +02:00
|
|
|
|
|
|
|
|
// Fetch and copy details
|
2022-08-18 20:07:13 +02:00
|
|
|
val newManga = source.getMangaDetails(manga.toSManga())
|
2022-07-05 03:54:24 +02:00
|
|
|
updateManga.awaitUpdateFromSource(manga, newManga, false)
|
2022-07-03 19:37:27 +02:00
|
|
|
manga = getManga.await(manga.id)!!
|
2017-05-05 05:38:17 +02:00
|
|
|
|
2020-07-10 19:08:21 +02:00
|
|
|
if (fav) {
|
2022-07-03 05:52:03 +02:00
|
|
|
updateManga.awaitUpdateFavorite(manga.id, true)
|
|
|
|
|
manga = manga.copy(favorite = true)
|
2020-07-10 19:08:21 +02:00
|
|
|
}
|
2017-05-05 05:38:17 +02:00
|
|
|
|
2020-04-04 22:30:05 +02:00
|
|
|
// Fetch and copy chapters
|
2017-08-24 18:28:54 +02:00
|
|
|
try {
|
2022-01-23 22:40:15 +01:00
|
|
|
val chapterList = if (source is EHentai) {
|
2022-08-18 20:07:13 +02:00
|
|
|
source.getChapterList(manga.toSManga(), throttleFunc)
|
2022-01-23 22:40:15 +01:00
|
|
|
} else {
|
2022-08-18 20:07:13 +02:00
|
|
|
source.getChapterList(manga.toSManga())
|
|
|
|
|
}
|
2022-01-23 22:40:15 +01:00
|
|
|
|
|
|
|
|
if (chapterList.isNotEmpty()) {
|
2022-07-03 05:52:03 +02:00
|
|
|
syncChaptersWithSource.await(chapterList, manga, source)
|
2019-04-20 04:59:24 +02:00
|
|
|
}
|
2017-08-24 18:28:54 +02:00
|
|
|
} catch (e: Exception) {
|
2020-11-25 21:57:05 +01:00
|
|
|
logger.w(context.getString(R.string.gallery_adder_chapter_fetch_error, manga.title), e)
|
2020-07-16 01:16:21 +02:00
|
|
|
return GalleryAddEvent.Fail.Error(url, context.getString(R.string.gallery_adder_chapter_fetch_error, url))
|
2017-08-24 18:28:54 +02:00
|
|
|
}
|
2017-05-05 05:38:17 +02:00
|
|
|
|
2020-12-26 22:13:55 +01:00
|
|
|
return if (cleanedChapterUrl != null) {
|
2022-07-03 21:48:13 +02:00
|
|
|
val chapter = getChapter.await(cleanedChapterUrl, manga.id)
|
2020-12-26 22:13:55 +01:00
|
|
|
if (chapter != null) {
|
|
|
|
|
GalleryAddEvent.Success(url, manga, context, chapter)
|
|
|
|
|
} else {
|
|
|
|
|
GalleryAddEvent.Fail.Error(url, context.getString(R.string.gallery_adder_could_not_identify_chapter, url))
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
GalleryAddEvent.Success(url, manga, context)
|
|
|
|
|
}
|
2020-04-04 22:30:05 +02:00
|
|
|
} catch (e: Exception) {
|
2022-11-29 23:30:04 +01:00
|
|
|
logger.w(context.getString(R.string.gallery_adder_could_not_add_gallery, url), e)
|
2019-04-15 00:53:34 +02:00
|
|
|
|
2020-04-04 22:30:05 +02:00
|
|
|
if (e is EHentai.GalleryNotFoundException) {
|
2020-07-16 01:16:21 +02:00
|
|
|
return GalleryAddEvent.Fail.NotFound(url, context)
|
2019-04-15 00:53:34 +02:00
|
|
|
}
|
|
|
|
|
|
2020-05-02 06:46:24 +02:00
|
|
|
return GalleryAddEvent.Fail.Error(
|
|
|
|
|
url,
|
2022-04-08 21:30:30 +02:00
|
|
|
((e.message ?: "Unknown error!") + " (Gallery: $url)").trim(),
|
2020-05-02 06:46:24 +02:00
|
|
|
)
|
2017-08-24 18:28:54 +02:00
|
|
|
}
|
2017-05-05 05:38:17 +02:00
|
|
|
}
|
2017-08-24 18:28:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sealed class GalleryAddEvent {
|
|
|
|
|
abstract val logMessage: String
|
|
|
|
|
abstract val galleryUrl: String
|
|
|
|
|
open val galleryTitle: String? = null
|
|
|
|
|
|
2020-04-04 22:30:05 +02:00
|
|
|
class Success(
|
|
|
|
|
override val galleryUrl: String,
|
2020-07-16 01:16:21 +02:00
|
|
|
val manga: Manga,
|
2020-12-26 20:22:55 +01:00
|
|
|
val context: Context,
|
2022-04-08 21:30:30 +02:00
|
|
|
val chapter: Chapter? = null,
|
2020-04-04 22:30:05 +02:00
|
|
|
) : GalleryAddEvent() {
|
2019-08-07 16:21:18 +02:00
|
|
|
override val galleryTitle = manga.title
|
2020-07-16 01:16:21 +02:00
|
|
|
override val logMessage = context.getString(R.string.batch_add_success_log_message, galleryTitle)
|
2017-08-24 18:28:54 +02:00
|
|
|
}
|
|
|
|
|
|
2020-04-04 22:30:05 +02:00
|
|
|
sealed class Fail : GalleryAddEvent() {
|
2020-07-16 01:16:21 +02:00
|
|
|
class UnknownType(override val galleryUrl: String, val context: Context) : Fail() {
|
|
|
|
|
override val logMessage = context.getString(R.string.batch_add_unknown_type_log_message, galleryUrl)
|
2017-08-24 18:28:54 +02:00
|
|
|
}
|
|
|
|
|
|
2020-04-04 22:30:05 +02:00
|
|
|
open class Error(
|
|
|
|
|
override val galleryUrl: String,
|
2022-04-08 21:30:30 +02:00
|
|
|
override val logMessage: String,
|
2020-04-04 22:30:05 +02:00
|
|
|
) : Fail()
|
2019-04-15 00:53:34 +02:00
|
|
|
|
2020-07-16 01:16:21 +02:00
|
|
|
class NotFound(galleryUrl: String, context: Context) :
|
|
|
|
|
Error(galleryUrl, context.getString(R.string.batch_add_not_exist_log_message, galleryUrl))
|
2021-01-10 23:28:52 +01:00
|
|
|
|
|
|
|
|
class UnknownSource(override val galleryUrl: String, val context: Context) : Fail() {
|
|
|
|
|
override val logMessage = context.getString(R.string.batch_add_unknown_source_log_message, galleryUrl)
|
|
|
|
|
}
|
2017-08-24 18:28:54 +02:00
|
|
|
}
|
2020-04-04 22:30:05 +02:00
|
|
|
}
|