@@ -24,6 +24,6 @@
|
|||||||
* 校验所选
|
* 校验所选
|
||||||
* 校验书源可批量校验书源,由于网络等原因结果仅限参考
|
* 校验书源可批量校验书源,由于网络等原因结果仅限参考
|
||||||
* "校验成功"是指所选的校验项目全部通过
|
* "校验成功"是指所选的校验项目全部通过
|
||||||
* 可正常识别搜索为空、发现为空、目录为空、正文为空、校验超时导致的失效,其余原因导致的视为规则失效
|
* 可正常识别搜索为空、发现为空、搜索(发现)目录为空、搜索(发现)正文为空、校验超时导致的失效,其余原因(网站异常、源码变动)导致的视为规则失效
|
||||||
* 校验搜索优先使用书源填写的校验关键词,不存在时使用用户输入的关键词
|
* 校验搜索优先使用书源填写的校验关键词,不存在时使用用户输入的关键词
|
||||||
* 校验结束后会自动筛选"失效"书源
|
* 校验结束后会自动筛选"失效"书源
|
||||||
@@ -13,6 +13,11 @@
|
|||||||
|
|
||||||
**2022/02/11**
|
**2022/02/11**
|
||||||
|
|
||||||
|
* 目录正文现在按照搜索发现分别校验
|
||||||
|
* 书源校验的超时校验存在bug
|
||||||
|
|
||||||
|
**2022/02/11**
|
||||||
|
|
||||||
* 可以单独给书籍设置朗读tts
|
* 可以单独给书籍设置朗读tts
|
||||||
* 目录界面菜单添加替换开关,开启替换加载时间会长一些
|
* 目录界面菜单添加替换开关,开启替换加载时间会长一些
|
||||||
* 书源校验添加规则失效分组,更新书源界面帮助文档
|
* 书源校验添加规则失效分组,更新书源界面帮助文档
|
||||||
|
|||||||
@@ -142,6 +142,13 @@ data class BookSource(
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun getInvalidGroupNames(): String? {
|
||||||
|
return bookSourceGroup?.splitNotBlank(AppPattern.splitGroupRegex)?.toHashSet()?.filter {
|
||||||
|
"失效" in it
|
||||||
|
}?.joinToString()
|
||||||
|
}
|
||||||
|
|
||||||
fun equal(source: BookSource) =
|
fun equal(source: BookSource) =
|
||||||
equal(bookSourceName, source.bookSourceName)
|
equal(bookSourceName, source.bookSourceName)
|
||||||
&& equal(bookSourceUrl, source.bookSourceUrl)
|
&& equal(bookSourceUrl, source.bookSourceUrl)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import io.legado.app.constant.EventBus
|
|||||||
import io.legado.app.constant.IntentAction
|
import io.legado.app.constant.IntentAction
|
||||||
import io.legado.app.data.appDb
|
import io.legado.app.data.appDb
|
||||||
import io.legado.app.data.entities.BookSource
|
import io.legado.app.data.entities.BookSource
|
||||||
|
import io.legado.app.data.entities.Book
|
||||||
import io.legado.app.data.entities.SearchBook
|
import io.legado.app.data.entities.SearchBook
|
||||||
import io.legado.app.help.AppConfig
|
import io.legado.app.help.AppConfig
|
||||||
import io.legado.app.help.coroutine.CompositeCoroutine
|
import io.legado.app.help.coroutine.CompositeCoroutine
|
||||||
@@ -34,7 +35,6 @@ class CheckSourceService : BaseService() {
|
|||||||
private val checkedIds = ArrayList<String>()
|
private val checkedIds = ArrayList<String>()
|
||||||
private var processIndex = 0
|
private var processIndex = 0
|
||||||
private var notificationMsg = ""
|
private var notificationMsg = ""
|
||||||
private var books = ArrayList<SearchBook>()
|
|
||||||
|
|
||||||
private val notificationBuilder by lazy {
|
private val notificationBuilder by lazy {
|
||||||
NotificationCompat.Builder(this, AppConst.channelIdReadAloud)
|
NotificationCompat.Builder(this, AppConst.channelIdReadAloud)
|
||||||
@@ -112,7 +112,10 @@ class CheckSourceService : BaseService() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun check(source: BookSource) {
|
/**
|
||||||
|
*校验书源
|
||||||
|
*/
|
||||||
|
private fun check(source: BookSource) {
|
||||||
execute(context = searchCoroutine) {
|
execute(context = searchCoroutine) {
|
||||||
Debug.startChecking(source)
|
Debug.startChecking(source)
|
||||||
var searchWord = CheckSource.keyword
|
var searchWord = CheckSource.keyword
|
||||||
@@ -126,7 +129,7 @@ class CheckSourceService : BaseService() {
|
|||||||
?.filterNot {
|
?.filterNot {
|
||||||
it.startsWith("Error: ")
|
it.startsWith("Error: ")
|
||||||
}?.joinToString("\n")
|
}?.joinToString("\n")
|
||||||
//校验搜索 用户设置校验搜索 并且 搜索链接不为空
|
//校验搜索书籍 用户设置校验搜索 并且 搜索链接不为空
|
||||||
if (CheckSource.checkSearch && !source.searchUrl.isNullOrBlank()) {
|
if (CheckSource.checkSearch && !source.searchUrl.isNullOrBlank()) {
|
||||||
val searchBooks = WebBook.searchBookAwait(this, source, searchWord)
|
val searchBooks = WebBook.searchBookAwait(this, source, searchWord)
|
||||||
if (searchBooks.isEmpty()) {
|
if (searchBooks.isEmpty()) {
|
||||||
@@ -136,10 +139,10 @@ class CheckSourceService : BaseService() {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
source.removeGroup("搜索失效")
|
source.removeGroup("搜索失效")
|
||||||
books = searchBooks
|
checkBook(searchBooks.first().toBook(), source)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//校验发现
|
//校验发现书籍
|
||||||
if (CheckSource.checkDiscovery) {
|
if (CheckSource.checkDiscovery) {
|
||||||
val exs = source.exploreKinds
|
val exs = source.exploreKinds
|
||||||
var url: String? = null
|
var url: String? = null
|
||||||
@@ -164,42 +167,15 @@ class CheckSourceService : BaseService() {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
source.removeGroup("发现失效")
|
source.removeGroup("发现失效")
|
||||||
if (books.isEmpty()) books = exploreBooks
|
checkBook(exploreBooks.first().toBook(), source, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//校验详情
|
val finalCheckMessage = source.getInvalidGroupNames()
|
||||||
if (CheckSource.checkInfo) {
|
if (!finalCheckMessage.isNullOrBlank()) throw NoStackTraceException(finalCheckMessage)
|
||||||
var book = books.first().toBook()
|
|
||||||
if (book.tocUrl.isBlank()) {
|
|
||||||
book = WebBook.getBookInfoAwait(this, source, book)
|
|
||||||
}
|
|
||||||
//校验目录
|
|
||||||
if (CheckSource.checkCategory) {
|
|
||||||
val toc = WebBook.getChapterListAwait(this, source, book)
|
|
||||||
val nextChapterUrl = toc.getOrNull(1)?.url ?: toc.first().url
|
|
||||||
source.removeGroup("目录失效")
|
|
||||||
//校验正文
|
|
||||||
if (CheckSource.checkContent) {
|
|
||||||
WebBook.getContentAwait(
|
|
||||||
this,
|
|
||||||
bookSource = source,
|
|
||||||
book = book,
|
|
||||||
bookChapter = toc.first(),
|
|
||||||
nextChapterUrl = nextChapterUrl,
|
|
||||||
needSave = false
|
|
||||||
)
|
|
||||||
source.removeGroup("正文失效")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (source.hasGroup("搜索失效")) throw NoStackTraceException("搜索失效")
|
|
||||||
if (source.hasGroup("发现失效")) throw NoStackTraceException("发现失效")
|
|
||||||
}.timeout(CheckSource.timeout)
|
}.timeout(CheckSource.timeout)
|
||||||
.onError(searchCoroutine) {
|
.onError(searchCoroutine) {
|
||||||
when(it) {
|
when(it) {
|
||||||
is ContentEmptyException -> source.addGroup("正文失效")
|
|
||||||
is TocEmptyException -> source.addGroup("目录失效")
|
|
||||||
//校验超时不能正常实现 不能识别
|
//校验超时不能正常实现 不能识别
|
||||||
is TimeoutCancellationException -> source.addGroup("校验超时")
|
is TimeoutCancellationException -> source.addGroup("校验超时")
|
||||||
//NoStackTraceException 已经添加了分组,其余的视为规则失效
|
//NoStackTraceException 已经添加了分组,其余的视为规则失效
|
||||||
@@ -221,6 +197,49 @@ class CheckSourceService : BaseService() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*校验书源的详情目录正文
|
||||||
|
*/
|
||||||
|
private suspend fun checkBook(book: Book, source: BookSource, isSearchBook: Boolean = true) {
|
||||||
|
kotlin.runCatching {
|
||||||
|
var mBook = book
|
||||||
|
//校验详情
|
||||||
|
if (CheckSource.checkInfo) {
|
||||||
|
if (mBook.tocUrl.isBlank()) {
|
||||||
|
mBook = WebBook.getBookInfoAwait(this, source, mBook)
|
||||||
|
}
|
||||||
|
//校验目录
|
||||||
|
if (CheckSource.checkCategory) {
|
||||||
|
val toc = WebBook.getChapterListAwait(this, source, mBook)
|
||||||
|
val nextChapterUrl = toc.getOrNull(1)?.url ?: toc.first().url
|
||||||
|
//校验正文
|
||||||
|
if (CheckSource.checkContent) {
|
||||||
|
WebBook.getContentAwait(
|
||||||
|
this,
|
||||||
|
bookSource = source,
|
||||||
|
book = mBook,
|
||||||
|
bookChapter = toc.first(),
|
||||||
|
nextChapterUrl = nextChapterUrl,
|
||||||
|
needSave = false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.onFailure {
|
||||||
|
val bookType = if (isSearchBook) "搜索" else "发现"
|
||||||
|
when (it) {
|
||||||
|
is ContentEmptyException -> source.addGroup("${bookType}正文失效")
|
||||||
|
is TocEmptyException -> source.addGroup("${bookType}目录失效")
|
||||||
|
//超时??js错误
|
||||||
|
else -> throw it
|
||||||
|
}
|
||||||
|
}.onSuccess {
|
||||||
|
val bookType = if (isSearchBook) "搜索" else "发现"
|
||||||
|
source.removeGroup("${bookType}目录失效")
|
||||||
|
source.removeGroup("${bookType}正文失效")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun onNext(sourceUrl: String, sourceName: String) {
|
private fun onNext(sourceUrl: String, sourceName: String) {
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
check()
|
check()
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ class HttpTtsEditViewModel(app: Application) : BaseViewModel(app) {
|
|||||||
id = httpTTS.id
|
id = httpTTS.id
|
||||||
execute {
|
execute {
|
||||||
appDb.httpTTSDao.insert(httpTTS)
|
appDb.httpTTSDao.insert(httpTTS)
|
||||||
|
if (ReadAloud.ttsEngine == httpTTS.id.toString()) ReadAloud.upReadAloudClass()
|
||||||
}.onSuccess {
|
}.onSuccess {
|
||||||
success?.invoke()
|
success?.invoke()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import io.legado.app.lib.theme.primaryColor
|
|||||||
import io.legado.app.model.ReadAloud
|
import io.legado.app.model.ReadAloud
|
||||||
import io.legado.app.model.ReadBook
|
import io.legado.app.model.ReadBook
|
||||||
import io.legado.app.ui.document.HandleFileContract
|
import io.legado.app.ui.document.HandleFileContract
|
||||||
|
import io.legado.app.ui.login.SourceLoginActivity
|
||||||
import io.legado.app.utils.*
|
import io.legado.app.utils.*
|
||||||
import io.legado.app.utils.viewbindingdelegate.viewBinding
|
import io.legado.app.utils.viewbindingdelegate.viewBinding
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@@ -217,7 +218,14 @@ class SpeakEngineDialog(val callBack: CallBack) : BaseDialogFragment(R.layout.di
|
|||||||
binding.run {
|
binding.run {
|
||||||
cbName.setOnClickListener {
|
cbName.setOnClickListener {
|
||||||
getItemByLayoutPosition(holder.layoutPosition)?.let { httpTTS ->
|
getItemByLayoutPosition(holder.layoutPosition)?.let { httpTTS ->
|
||||||
upTts(httpTTS.id.toString())
|
val id = httpTTS.id.toString()
|
||||||
|
upTts(id)
|
||||||
|
if (!httpTTS.loginUrl.isNullOrBlank()) {
|
||||||
|
startActivity<SourceLoginActivity> {
|
||||||
|
putExtra("type", "httpTts")
|
||||||
|
putExtra("key", id)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ivEdit.setOnClickListener {
|
ivEdit.setOnClickListener {
|
||||||
|
|||||||
Reference in New Issue
Block a user