This commit is contained in:
Horis
2025-04-12 14:53:33 +08:00
parent 866e94a860
commit b33b10bdc7
8 changed files with 53 additions and 23 deletions

View File

@@ -7,6 +7,7 @@ import com.bumptech.glide.load.Options
import com.bumptech.glide.load.data.DataFetcher
import com.bumptech.glide.load.model.GlideUrl
import com.bumptech.glide.util.ContentLengthInputStream
import com.script.rhino.runScriptWithContext
import io.legado.app.data.entities.BaseSource
import io.legado.app.exception.NoStackTraceException
import io.legado.app.help.http.CookieManager.cookieJarHeader
@@ -17,7 +18,6 @@ import io.legado.app.help.source.SourceHelp
import io.legado.app.model.ReadManga
import io.legado.app.utils.ImageUtils
import io.legado.app.utils.isWifiConnect
import com.script.rhino.runScriptWithContext
import kotlinx.coroutines.Job
import okhttp3.Call
import okhttp3.Request
@@ -89,6 +89,7 @@ class OkHttpStreamFetcher(
stream?.close()
}
responseBody?.close()
coroutineContext.cancel()
callback = null
}

View File

@@ -812,7 +812,7 @@ class AnalyzeRule(
if (bookSource == null || book == null) return
runBlocking(coroutineContext) {
withTimeout(1800000) {
WebBook.preciseSearchAwait(this, bookSource, book.name, book.author)
WebBook.preciseSearchAwait(bookSource, book.name, book.author)
.getOrThrow().let {
book.bookUrl = it.bookUrl
it.variableMap.forEach { entry ->

View File

@@ -19,7 +19,7 @@ import io.legado.app.model.analyzeRule.RuleData
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.isActive
import kotlinx.coroutines.ensureActive
import kotlinx.coroutines.sync.Semaphore
import kotlinx.coroutines.sync.withPermit
import kotlin.coroutines.CoroutineContext
@@ -363,7 +363,7 @@ object WebBook {
return Coroutine.async(scope, context) {
for (s in bookSourceParts) {
val source = s.getBookSource() ?: continue
val book = preciseSearchAwait(scope, source, name, author).getOrNull()
val book = preciseSearchAwait(source, name, author).getOrNull()
if (book != null) {
return@async Pair(book, source)
}
@@ -373,24 +373,19 @@ object WebBook {
}
suspend fun preciseSearchAwait(
scope: CoroutineScope,
bookSource: BookSource,
name: String,
author: String,
): Result<Book> {
return kotlin.runCatching {
scope.isActive
coroutineContext.ensureActive()
searchBookAwait(
bookSource, name,
filter = { fName, fAuthor -> fName == name && fAuthor == author },
shouldBreak = { it > 0 }
).firstOrNull()?.let { searchBook ->
scope.isActive
var book = searchBook.toBook()
if (book.tocUrl.isBlank()) {
book = getBookInfoAwait(bookSource, book)
}
return@runCatching book
coroutineContext.ensureActive()
return@runCatching searchBook.toBook()
}
throw NoStackTraceException("未搜索到 $name($author) 书籍")
}

View File

@@ -350,10 +350,11 @@ class BookInfoActivity :
}
private fun showCover(book: Book) {
binding.ivCover.load(book.getDisplayCover(), book.name, book.author, false, book.origin)
if (!AppConfig.isEInkMode) {
BookCover.loadBlur(this, book.getDisplayCover())
.into(binding.bgBook)
binding.ivCover.load(book.getDisplayCover(), book.name, book.author, false, book.origin) {
if (!AppConfig.isEInkMode) {
BookCover.loadBlur(this, book.getDisplayCover(), false, book.origin)
.into(binding.bgBook)
}
}
}

View File

@@ -87,10 +87,18 @@ class BookshelfManageViewModel(application: Application) : BaseViewModel(applica
batchChangeSourceProcessLiveData.postValue("${index + 1} / ${books.size}")
if (book.isLocal) return@forEachIndexed
if (book.origin == source.bookSourceUrl) return@forEachIndexed
val newBook = WebBook.preciseSearchAwait(this, source, book.name, book.author)
val newBook = WebBook.preciseSearchAwait(source, book.name, book.author)
.onFailure {
AppLog.put("获取书籍出错\n${it.localizedMessage}", it, true)
AppLog.put("搜索书籍出错\n${it.localizedMessage}", it, true)
}.getOrNull() ?: return@forEachIndexed
kotlin.runCatching {
if (book.tocUrl.isEmpty()) {
WebBook.getBookInfoAwait(source, book)
}
}.onFailure {
AppLog.put("获取书籍详情出错\n${it.localizedMessage}", it, true)
return@forEachIndexed
}
WebBook.getChapterListAwait(source, newBook)
.onFailure {
AppLog.put("获取目录出错\n${it.localizedMessage}", it, true)

View File

@@ -152,7 +152,7 @@ class ReadMangaViewModel(application: Application) : BaseViewModel(application)
// 自动换源
}.mapParallelSafe(AppConfig.threadCount) { source ->
val book = WebBook.preciseSearchAwait(this, source, name, author).getOrThrow()
val book = WebBook.preciseSearchAwait(source, name, author).getOrThrow()
if (book.tocUrl.isEmpty()) {
WebBook.getBookInfoAwait(source, book)
}

View File

@@ -292,7 +292,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
}.onStart {
ReadBook.upMsg(context.getString(R.string.source_auto_changing))
}.mapParallelSafe(AppConfig.threadCount) { source ->
val book = WebBook.preciseSearchAwait(this, source, name, author).getOrThrow()
val book = WebBook.preciseSearchAwait(source, name, author).getOrThrow()
if (book.tocUrl.isEmpty()) {
WebBook.getBookInfoAwait(source, book)
}

View File

@@ -195,7 +195,8 @@ class CoverImageView @JvmOverloads constructor(
loadOnlyWifi: Boolean = false,
sourceOrigin: String? = null,
fragment: Fragment? = null,
lifecycle: Lifecycle? = null
lifecycle: Lifecycle? = null,
onLoadFinish: (() -> Unit)? = null
) {
this.bitmapPath = path
this.name = name?.replace(AppPattern.bdRegex, "")?.trim()
@@ -210,15 +211,39 @@ class CoverImageView @JvmOverloads constructor(
if (sourceOrigin != null) {
options = options.set(OkHttpModelLoader.sourceOriginOption, sourceOrigin)
}
val builder = if (fragment != null && lifecycle != null) {
var builder = if (fragment != null && lifecycle != null) {
ImageLoader.load(fragment, lifecycle, path)
} else {
ImageLoader.load(context, path)//Glide自动识别http://,content://和file://
}
builder.apply(options)
builder = builder.apply(options)
.placeholder(BookCover.defaultDrawable)
.error(BookCover.defaultDrawable)
.listener(glideListener)
if (onLoadFinish != null) {
builder = builder.addListener(object : RequestListener<Drawable> {
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: Target<Drawable?>,
isFirstResource: Boolean
): Boolean {
return false
}
override fun onResourceReady(
resource: Drawable,
model: Any,
target: Target<Drawable?>?,
dataSource: DataSource,
isFirstResource: Boolean
): Boolean {
onLoadFinish.invoke()
return false
}
})
}
builder
.centerCrop()
.into(this)
}