添加校验设置;fix:直链规则错误提示不显示

pull/1560/head
Xwite 3 years ago
parent da53666811
commit 51e669d09a
  1. 2
      app/src/main/java/io/legado/app/constant/PreferKey.kt
  2. 17
      app/src/main/java/io/legado/app/model/CheckSource.kt
  3. 84
      app/src/main/java/io/legado/app/service/CheckSourceService.kt
  4. 71
      app/src/main/java/io/legado/app/ui/config/CheckSourceConfig.kt
  5. 4
      app/src/main/java/io/legado/app/ui/config/DirectLinkUploadConfig.kt
  6. 9
      app/src/main/java/io/legado/app/ui/config/OtherConfigFragment.kt
  7. 94
      app/src/main/res/layout/dialog_check_source_config.xml
  8. 2
      app/src/main/res/layout/dialog_direct_link_upload_config.xml
  9. 16
      app/src/main/res/values/strings.xml
  10. 6
      app/src/main/res/xml/pref_config_other.xml

@ -91,6 +91,8 @@ object PreferKey {
const val doublePageHorizontal = "doublePageHorizontal" const val doublePageHorizontal = "doublePageHorizontal"
const val readUrlOpenInBrowser = "readUrlInBrowser" const val readUrlOpenInBrowser = "readUrlInBrowser"
const val defaultBookTreeUri = "defaultBookTreeUri" const val defaultBookTreeUri = "defaultBookTreeUri"
const val checkSource = "checkSource"
const val uploadRule = "uploadRule"
const val cPrimary = "colorPrimary" const val cPrimary = "colorPrimary"
const val cAccent = "colorAccent" const val cAccent = "colorAccent"

@ -7,9 +7,17 @@ import io.legado.app.data.entities.BookSource
import io.legado.app.service.CheckSourceService import io.legado.app.service.CheckSourceService
import io.legado.app.utils.startService import io.legado.app.utils.startService
import io.legado.app.utils.toastOnUi import io.legado.app.utils.toastOnUi
import io.legado.app.help.CacheManager
object CheckSource { object CheckSource {
var keyword = "我的" var keyword = "我的"
//校验设置
var timeout = CacheManager.getLong("checkSourceTimeout") ?: 180000L
var checkSearch = CacheManager.get("checkSearch")?.toBoolean() ?: true
var checkDiscovery = CacheManager.get("checkDiscovery")?.toBoolean() ?: true
var checkInfo = CacheManager.get("checkInfo")?.toBoolean() ?: true
var checkCategory = CacheManager.get("checkCategory")?.toBoolean() ?: true
var checkContent = CacheManager.get("checkContent")?.toBoolean() ?: true
fun start(context: Context, sources: List<BookSource>) { fun start(context: Context, sources: List<BookSource>) {
if (sources.isEmpty()) { if (sources.isEmpty()) {
@ -31,4 +39,13 @@ object CheckSource {
action = IntentAction.stop action = IntentAction.stop
} }
} }
fun putConfig() {
CacheManager.put("checkSourceTimeout", timeout * 1000)
CacheManager.put("checkSearch", checkSearch)
CacheManager.put("checkDiscovery", checkDiscovery)
CacheManager.put("checkInfo", checkInfo)
CacheManager.put("checkCategory", checkCategory)
CacheManager.put("checkContent", checkContent)
}
} }

@ -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.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
import io.legado.app.model.CheckSource import io.legado.app.model.CheckSource
@ -33,6 +34,8 @@ 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)
.setSmallIcon(R.drawable.ic_network_check) .setSmallIcon(R.drawable.ic_network_check)
@ -118,45 +121,58 @@ class CheckSourceService : BaseService() {
searchWord = it searchWord = it
} }
} }
var books = WebBook.searchBookAwait(this, source, searchWord) //校验搜索
if (books.isEmpty()) { if (CheckSource.checkSearch) {
source.addGroup("搜索失效") books = WebBook.searchBookAwait(this, source, searchWord)
val exs = source.exploreKinds if (books.isEmpty()) source.addGroup("搜索失效") else source.removeGroup("搜索失效")
var url: String? = null }
for (ex in exs) { //校验发现
url = ex.url if (CheckSource.checkDiscovery) {
if (!url.isNullOrBlank()) { if (books.isEmpty()) {
break val exs = source.exploreKinds
var url: String? = null
for (ex in exs) {
url = ex.url
if (!url.isNullOrBlank()) {
break
}
}
if (url.isNullOrBlank()) {
throw NoStackTraceException("搜索内容为空并且没有发现")
}
books = WebBook.exploreBookAwait(this, source, url)
if (books.isEmpty()) {
throw NoStackTraceException("发现书籍为空")
} }
} }
if (url.isNullOrBlank()) { }
throw NoStackTraceException("搜索内容为空并且没有发现") //校验详情
if (CheckSource.checkInfo) {
var book = books.first().toBook()
if (book.tocUrl.isBlank()) {
book = WebBook.getBookInfoAwait(this, source, book)
} }
books = WebBook.exploreBookAwait(this, source, url) //校验目录
if (books.isEmpty()) { if (CheckSource.checkCategory) {
throw NoStackTraceException("发现书籍为空") val toc = WebBook.getChapterListAwait(this, source, book)
val nextChapterUrl = toc.getOrNull(1)?.url ?: toc.first().url
//校验正文
if (CheckSource.checkContent) {
val content = WebBook.getContentAwait(
this,
bookSource = source,
book = book,
bookChapter = toc.first(),
nextChapterUrl = nextChapterUrl,
needSave = false
)
if ( !toc.first().isVolume && content.isBlank()) {
throw NoStackTraceException("正文内容为空")
}
}
} }
} else {
source.removeGroup("搜索失效")
}
var book = books.first().toBook()
if (book.tocUrl.isBlank()) {
book = WebBook.getBookInfoAwait(this, source, book)
}
val toc = WebBook.getChapterListAwait(this, source, book)
val nextChapterUrl = toc.getOrNull(1)?.url ?: toc.first().url
val content = WebBook.getContentAwait(
this,
bookSource = source,
book = book,
bookChapter = toc.first(),
nextChapterUrl = nextChapterUrl,
needSave = false
)
if ( !toc.first().isVolume && content.isBlank()) {
throw NoStackTraceException("正文内容为空")
} }
}.timeout(180000L) }.timeout(CheckSource.timeout)
.onError(searchCoroutine) { .onError(searchCoroutine) {
source.addGroup("失效") source.addGroup("失效")
if (source.bookSourceComment?.contains("Error: ") == false) { if (source.bookSourceComment?.contains("Error: ") == false) {

@ -0,0 +1,71 @@
package io.legado.app.ui.config
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import io.legado.app.R
import io.legado.app.base.BaseDialogFragment
import io.legado.app.databinding.DialogCheckSourceConfigBinding
import io.legado.app.model.CheckSource
import io.legado.app.lib.theme.primaryColor
import io.legado.app.utils.setLayout
import io.legado.app.utils.viewbindingdelegate.viewBinding
import io.legado.app.utils.toastOnUi
import splitties.views.onClick
class CheckSourceConfig : BaseDialogFragment(R.layout.dialog_check_source_config) {
private val binding by viewBinding(DialogCheckSourceConfigBinding::bind)
//允许的最小超时时间,秒
private val minTimeout = 60L
override fun onStart() {
super.onStart()
setLayout(
0.9f,
ViewGroup.LayoutParams.WRAP_CONTENT
)
}
override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) {
binding.toolBar.setBackgroundColor(primaryColor)
CheckSource.run {
binding.checkSourceTimeout.setText((timeout / 1000).toString())
binding.checkSearch?.isChecked = checkSearch
binding.checkDiscovery?.isChecked = checkDiscovery
binding.checkInfo?.isChecked = checkInfo
binding.checkCategory?.isChecked = checkCategory
binding.checkContent?.isChecked = checkContent
binding.tvCancel.onClick {
dismiss()
}
binding.tvOk.onClick {
val text = binding.checkSourceTimeout.text.toString()
when {
text.isBlank() -> {
toastOnUi("${getString(R.string.timeout)}${getString(R.string.cannot_empty)}")
return@onClick
}
text.toLong() < minTimeout -> {
toastOnUi("${getString(R.string.timeout)}${getString(R.string.less_than)}${minTimeout}${getString(R.string.seconds)}")
return@onClick
}
else -> timeout = text.toLong() * 1000
}
val _checkSearch = binding.checkSearch?.isChecked
val _checkDiscovery = binding.checkDiscovery?.isChecked
if (!_checkSearch && !_checkDiscovery) {
toastOnUi(getString(R.string.error_check_source_config))
return@onClick
}
checkSearch = _checkSearch
checkDiscovery = _checkDiscovery
checkInfo = binding.checkInfo?.isChecked
checkCategory = binding.checkCategory?.isChecked
checkContent = binding.checkContent?.isChecked
putConfig()
dismiss()
}
}
}
}

@ -41,11 +41,11 @@ class DirectLinkUploadConfig : BaseDialogFragment(R.layout.dialog_direct_link_up
val uploadUrl = binding.editUploadUrl.text?.toString() val uploadUrl = binding.editUploadUrl.text?.toString()
val downloadUrlRule = binding.editDownloadUrlRule.text?.toString() val downloadUrlRule = binding.editDownloadUrlRule.text?.toString()
val summary = binding.editSummary.text?.toString() val summary = binding.editSummary.text?.toString()
uploadUrl ?: let { if (uploadUrl.isNullOrBlank()) {
toastOnUi("上传Url不能为空") toastOnUi("上传Url不能为空")
return@onClick return@onClick
} }
downloadUrlRule ?: let { if (downloadUrlRule.isNullOrBlank()) {
toastOnUi("下载Url规则不能为空") toastOnUi("下载Url规则不能为空")
return@onClick return@onClick
} }

@ -70,7 +70,7 @@ class OtherConfigFragment : BasePreferenceFragment(),
when (preference?.key) { when (preference?.key) {
PreferKey.userAgent -> showUserAgentDialog() PreferKey.userAgent -> showUserAgentDialog()
PreferKey.defaultBookTreeUri -> localBookTreeSelect.launch { PreferKey.defaultBookTreeUri -> localBookTreeSelect.launch {
title = "选择保存书籍的文件夹" title = getString(R.string.select_book_folder)
mode = HandleFileContract.DIR_SYS mode = HandleFileContract.DIR_SYS
} }
PreferKey.preDownloadNum -> NumberPickerDialog(requireContext()) PreferKey.preDownloadNum -> NumberPickerDialog(requireContext())
@ -98,7 +98,8 @@ class OtherConfigFragment : BasePreferenceFragment(),
AppConfig.webPort = it AppConfig.webPort = it
} }
PreferKey.cleanCache -> clearCache() PreferKey.cleanCache -> clearCache()
"uploadRule" -> DirectLinkUploadConfig().show(childFragmentManager, "uploadRuleConfig") PreferKey.uploadRule -> showDialogFragment<DirectLinkUploadConfig>()
PreferKey.checkSource -> showDialogFragment<CheckSourceConfig>()
} }
return super.onPreferenceTreeClick(preference) return super.onPreferenceTreeClick(preference)
} }
@ -155,9 +156,9 @@ class OtherConfigFragment : BasePreferenceFragment(),
@SuppressLint("InflateParams") @SuppressLint("InflateParams")
private fun showUserAgentDialog() { private fun showUserAgentDialog() {
alert("UserAgent") { alert(getString(R.string.user_agent)) {
val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply { val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply {
editView.hint = "UserAgent" editView.hint = getString(R.string.user_agent)
editView.setText(AppConfig.userAgent) editView.setText(AppConfig.userAgent)
} }
customView { alertBinding.root } customView { alertBinding.root }

@ -0,0 +1,94 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<androidx.appcompat.widget.Toolbar
android:id="@+id/tool_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="?attr/actionBarStyle"
app:title="@string/check_source_config"
app:popupTheme="@style/AppTheme.PopupOverlay"
app:titleTextAppearance="@style/ToolbarTitle" />
<io.legado.app.ui.widget.text.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="3dp">
<io.legado.app.lib.theme.view.ThemeEditText
android:id="@+id/check_source_timeout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/check_source_timeout"
tools:ignore="SpeakableTextPresentCheck,TouchTargetSizeCheck" />
</io.legado.app.ui.widget.text.TextInputLayout>
<com.google.android.flexbox.FlexboxLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="12dp"
android:paddingRight="12dp"
app:flexWrap="wrap"
app:justifyContent="space_between">
<io.legado.app.lib.theme.view.ThemeCheckBox
android:id="@+id/check_search"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/check_search" />
<io.legado.app.lib.theme.view.ThemeCheckBox
android:id="@+id/check_discovery"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/check_discovery" />
<io.legado.app.lib.theme.view.ThemeCheckBox
android:id="@+id/check_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_wrapBefore="true"
android:text="@string/check_info" />
<io.legado.app.lib.theme.view.ThemeCheckBox
android:id="@+id/check_category"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/check_category" />
<io.legado.app.lib.theme.view.ThemeCheckBox
android:id="@+id/check_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/check_content" />
</com.google.android.flexbox.FlexboxLayout>
<com.google.android.flexbox.FlexboxLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="12dp"
android:paddingRight="12dp"
app:flexWrap="wrap"
app:justifyContent="flex_end">
<io.legado.app.ui.widget.text.AccentTextView
android:id="@+id/tv_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="12dp"
android:text="@string/cancel"
tools:ignore="RtlHardcoded" />
<io.legado.app.ui.widget.text.AccentTextView
android:id="@+id/tv_ok"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="12dp"
android:text="@string/ok"
tools:ignore="RtlHardcoded" />
</com.google.android.flexbox.FlexboxLayout>
</LinearLayout>

@ -11,7 +11,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:theme="?attr/actionBarStyle" android:theme="?attr/actionBarStyle"
app:title="直链上传配置" app:title="@string/direct_link_upload_config"
app:popupTheme="@style/AppTheme.PopupOverlay" app:popupTheme="@style/AppTheme.PopupOverlay"
app:titleTextAppearance="@style/ToolbarTitle" /> app:titleTextAppearance="@style/ToolbarTitle" />

@ -877,6 +877,7 @@
<string name="path">path</string> <string name="path">path</string>
<string name="direct_link_upload_rule">直链上传规则</string> <string name="direct_link_upload_rule">直链上传规则</string>
<string name="direct_link_upload_rule_summary">用于导出书源书单时生成直链url</string> <string name="direct_link_upload_rule_summary">用于导出书源书单时生成直链url</string>
<string name="direct_link_upload_config">直链上传配置</string>
<string name="copy_play_url">拷贝播放Url</string> <string name="copy_play_url">拷贝播放Url</string>
<string name="set_source_variable">设置源变量</string> <string name="set_source_variable">设置源变量</string>
<string name="set_book_variable">设置书籍变量</string> <string name="set_book_variable">设置书籍变量</string>
@ -916,5 +917,20 @@
<string name="expand_text_menu">展开文本选择菜单</string> <string name="expand_text_menu">展开文本选择菜单</string>
<string name="book_tree_uri_t">书籍保存位置</string> <string name="book_tree_uri_t">书籍保存位置</string>
<string name="book_tree_uri_s">从其它应用打开的书籍保存位置</string> <string name="book_tree_uri_s">从其它应用打开的书籍保存位置</string>
<string name="select_book_folder">选择保存书籍的文件夹</string>
<string name="user_agent">用户代理</string>
<!-- check source config string -->
<string name="check_source_config">校验设置</string>
<string name="check_source_timeout">单个书源校验超时(秒)</string>
<string name="timeout">超时</string>
<string name="seconds"></string>
<string name="less_than">小于</string>
<string name="check_search">校验搜索</string>
<string name="check_discovery">校验发现</string>
<string name="check_info">校验详情</string>
<string name="check_category">校验目录</string>
<string name="check_content">校验正文</string>
<string name="error_check_source_config">搜索发现至少校验一个</string>
<!-- string end -->
</resources> </resources>

@ -54,13 +54,17 @@
<io.legado.app.ui.widget.prefs.Preference <io.legado.app.ui.widget.prefs.Preference
android:key="userAgent" android:key="userAgent"
android:title="UserAgent" /> android:title="@string/user_agent" />
<io.legado.app.ui.widget.prefs.Preference <io.legado.app.ui.widget.prefs.Preference
android:key="defaultBookTreeUri" android:key="defaultBookTreeUri"
android:title="@string/book_tree_uri_t" android:title="@string/book_tree_uri_t"
android:summary="@string/book_tree_uri_s" /> android:summary="@string/book_tree_uri_s" />
<io.legado.app.ui.widget.prefs.Preference
android:key="checkSource"
android:title="@string/check_source_config" />
<io.legado.app.ui.widget.prefs.Preference <io.legado.app.ui.widget.prefs.Preference
android:key="uploadRule" android:key="uploadRule"
android:title="@string/direct_link_upload_rule" android:title="@string/direct_link_upload_rule"

Loading…
Cancel
Save