mirror of
https://github.com/mihonapp/mihon.git
synced 2025-06-27 19:47:51 +02:00
Add automatic gallery updating
This commit is contained in:
137
app/src/main/java/exh/eh/EHentaiUpdateHelper.kt
Normal file
137
app/src/main/java/exh/eh/EHentaiUpdateHelper.kt
Normal file
@ -0,0 +1,137 @@
|
||||
package exh.eh
|
||||
|
||||
import android.content.Context
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||
import eu.kanade.tachiyomi.data.database.models.ChapterImpl
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.database.models.MangaCategory
|
||||
import rx.Observable
|
||||
import rx.Single
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.io.File
|
||||
|
||||
data class ChapterChain(val manga: Manga, val chapters: List<Chapter>)
|
||||
|
||||
class EHentaiUpdateHelper(context: Context) {
|
||||
val parentLookupTable =
|
||||
MemAutoFlushingLookupTable(
|
||||
File(context.filesDir, "exh-plt.maftable"),
|
||||
GalleryEntry.Serializer()
|
||||
)
|
||||
private val db: DatabaseHelper by injectLazy()
|
||||
|
||||
/**
|
||||
* @param chapters Cannot be an empty list!
|
||||
*
|
||||
* @return Pair<Accepted, Discarded>
|
||||
*/
|
||||
fun findAcceptedRootAndDiscardOthers(chapters: List<Chapter>): Single<Pair<ChapterChain, List<ChapterChain>>> {
|
||||
// Find other chains
|
||||
val chainsObservable = Observable.merge(chapters.map { chapter ->
|
||||
db.getChapters(chapter.url).asRxSingle().toObservable()
|
||||
}).toList().map { allChapters ->
|
||||
allChapters.flatMap { innerChapters -> innerChapters.map { it.manga_id!! } }.distinct()
|
||||
}.flatMap { mangaIds ->
|
||||
Observable.merge(
|
||||
mangaIds.map { mangaId ->
|
||||
Single.zip(
|
||||
db.getManga(mangaId).asRxSingle(),
|
||||
db.getChaptersByMangaId(mangaId).asRxSingle()
|
||||
) { manga, chapters ->
|
||||
ChapterChain(manga, chapters)
|
||||
}.toObservable()
|
||||
}
|
||||
)
|
||||
}.toList()
|
||||
|
||||
// Accept oldest chain
|
||||
val chainsWithAccepted = chainsObservable.map { chains ->
|
||||
val acceptedChain = chains.minBy { it.manga.id!! }!!
|
||||
|
||||
acceptedChain to chains
|
||||
}
|
||||
|
||||
return chainsWithAccepted.map { (accepted, chains) ->
|
||||
val toDiscard = chains.filter { it.manga.favorite && it.manga.id != accepted.manga.id }
|
||||
|
||||
if(toDiscard.isNotEmpty()) {
|
||||
// Copy chain chapters to curChapters
|
||||
val newChapters = toDiscard
|
||||
.flatMap { it.chapters }
|
||||
.fold(accepted.chapters) { curChapters, chapter ->
|
||||
val existing = curChapters.find { it.url == chapter.url }
|
||||
|
||||
if (existing != null) {
|
||||
existing.read = existing.read || chapter.read
|
||||
existing.last_page_read = existing.last_page_read.coerceAtLeast(chapter.last_page_read)
|
||||
existing.bookmark = existing.bookmark || chapter.bookmark
|
||||
curChapters
|
||||
} else if (chapter.date_upload > 0) { // Ignore chapters using the old system
|
||||
curChapters + ChapterImpl().apply {
|
||||
manga_id = accepted.manga.id
|
||||
url = chapter.url
|
||||
name = chapter.name
|
||||
read = chapter.read
|
||||
bookmark = chapter.bookmark
|
||||
last_page_read = chapter.last_page_read
|
||||
date_fetch = chapter.date_fetch
|
||||
date_upload = chapter.date_upload
|
||||
}
|
||||
} else curChapters
|
||||
}
|
||||
.filter { it.date_upload <= 0 } // Ignore chapters using the old system (filter after to prevent dupes from insert)
|
||||
.sortedBy { it.date_upload }
|
||||
.apply {
|
||||
withIndex().map { (index, chapter) ->
|
||||
chapter.name = "v${index + 1}: " + chapter.name.substringAfter(" ")
|
||||
chapter.chapter_number = index + 1f
|
||||
chapter.source_order = index
|
||||
}
|
||||
}
|
||||
|
||||
toDiscard.forEach { it.manga.favorite = false }
|
||||
accepted.manga.favorite = true
|
||||
|
||||
val newAccepted = ChapterChain(accepted.manga, newChapters)
|
||||
val rootsToMutate = toDiscard + newAccepted
|
||||
|
||||
db.inTransaction {
|
||||
// Apply changes to all manga
|
||||
db.insertMangas(rootsToMutate.map { it.manga }).executeAsBlocking()
|
||||
// Insert new chapters for accepted manga
|
||||
db.insertChapters(newAccepted.chapters)
|
||||
// Copy categories from all chains to accepted manga
|
||||
val newCategories = rootsToMutate.flatMap {
|
||||
db.getCategoriesForManga(it.manga).executeAsBlocking()
|
||||
}.distinctBy { it.id }.map {
|
||||
MangaCategory.create(newAccepted.manga, it)
|
||||
}
|
||||
db.setMangaCategories(newCategories, rootsToMutate.map { it.manga })
|
||||
}
|
||||
|
||||
newAccepted to toDiscard
|
||||
} else accepted to emptyList()
|
||||
}.toSingle()
|
||||
}
|
||||
}
|
||||
|
||||
data class GalleryEntry(val gId: String, val gToken: String) {
|
||||
class Serializer: MemAutoFlushingLookupTable.EntrySerializer<GalleryEntry> {
|
||||
/**
|
||||
* Serialize an entry as a String.
|
||||
*/
|
||||
override fun write(entry: GalleryEntry) = with(entry) { "$gId:$gToken" }
|
||||
|
||||
/**
|
||||
* Read an entry from a String.
|
||||
*/
|
||||
override fun read(string: String): GalleryEntry {
|
||||
val colonIndex = string.indexOf(':')
|
||||
return GalleryEntry(
|
||||
string.substring(0, colonIndex),
|
||||
string.substring(colonIndex + 1, string.length)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user