Merge branch 'master' into master

pull/1576/head
kunfei 3 years ago committed by GitHub
commit c24e26fccd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 12
      app/src/main/assets/help/jsHelp.md
  2. 10
      app/src/main/assets/updateLog.md
  3. 12
      app/src/main/java/io/legado/app/help/JsExtensions.kt
  4. 38
      app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt
  5. 2
      app/src/main/java/io/legado/app/model/localBook/TextFile.kt
  6. 8
      app/src/main/java/io/legado/app/model/webBook/BookChapterList.kt
  7. 10
      app/src/main/java/io/legado/app/model/webBook/BookContent.kt
  8. 8
      app/src/main/java/io/legado/app/model/webBook/BookInfo.kt
  9. 18
      app/src/main/java/io/legado/app/model/webBook/WebBook.kt
  10. 14
      app/src/main/java/io/legado/app/ui/association/FileAssociationActivity.kt
  11. 4
      app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt
  12. 8
      app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt
  13. 2
      app/src/main/java/io/legado/app/ui/widget/code/CodeView.kt
  14. 8
      app/src/main/java/io/legado/app/utils/ToastUtils.kt

@ -82,8 +82,16 @@ java.base64Encode(str: String, flags: Int)
* 文件
> 所有对于文件的读写删操作都是相对路径,只能操作阅读缓存/android/data/{package}/cache/内的文件
```
java.readTxtFile(path: String): String
java.deleteFile(path: String)
//文件下载,content为十六进制字符串,url用于生成文件名,返回文件路径
downloadFile(content: String, url: String): String
//文件解压,zipPath为压缩文件路径,返回解压路径
unzipFile(zipPath: String): String
//文件夹内所有文件读取
getTxtInFolder(unzipPath: String): String
//读取文本文件
readTxtFile(path: String): String
//删除文件
deleteFile(path: String)
```
****
> [常见加密解密算法介绍](https://www.yijiyong.com/algorithm/encryption/01-intro.html)

@ -11,6 +11,16 @@
* 正文出现缺字漏字、内容缺失、排版错乱等情况,有可能是净化规则或简繁转换出现问题。
* 漫画源看书显示乱码,**阅读与其他软件的源并不通用**,请导入阅读的支持的漫画源!
**2022/02/02**
* 字符串大于1024时禁用代码高亮
* 修复baseUrl丢失参数的bug
* 添加更新bookUrl和更新tocUrl函数
* 标题单独净化,防止出现正文标题没了的问题
* 修复一个null报错
* 按返回键关闭搜索界面 by Xwite
* 其它一些优化 by Xwite
**2022/01/28**
* 阅读背景添加透明度调节

@ -9,6 +9,7 @@ import cn.hutool.crypto.symmetric.DESede
import io.legado.app.BuildConfig
import io.legado.app.constant.AppConst
import io.legado.app.constant.AppConst.dateFormat
import io.legado.app.constant.AppLog
import io.legado.app.data.entities.BaseSource
import io.legado.app.help.http.*
import io.legado.app.model.Debug
@ -513,13 +514,14 @@ interface JsExtensions {
/**
* 输出调试日志
*/
fun log(msg: String): String {
fun log(msg: Any?): Any? {
getSource()?.let {
Debug.log(it.getKey(), msg)
} ?: Debug.log(msg)
Debug.log(it.getKey(), msg.toString())
} ?: Debug.log(msg.toString())
if (BuildConfig.DEBUG) {
Timber.d(msg)
Timber.d(msg.toString())
}
AppLog.put(msg.toString())
return msg
}
@ -692,7 +694,7 @@ interface JsExtensions {
return aesEncodeToBase64ByteArray(data, key, transformation, iv)?.let { String(it) }
}
fun android(): String {
fun androidId(): String {
return AppConst.androidId
}

@ -4,12 +4,11 @@ import android.text.TextUtils
import androidx.annotation.Keep
import io.legado.app.constant.AppConst.SCRIPT_ENGINE
import io.legado.app.constant.AppPattern.JS_PATTERN
import io.legado.app.data.entities.BaseBook
import io.legado.app.data.entities.BaseSource
import io.legado.app.data.entities.BookChapter
import io.legado.app.data.entities.*
import io.legado.app.help.CacheManager
import io.legado.app.help.JsExtensions
import io.legado.app.help.http.CookieStore
import io.legado.app.model.webBook.WebBook
import io.legado.app.utils.*
import kotlinx.coroutines.runBlocking
import org.jsoup.nodes.Entities
@ -684,6 +683,39 @@ class AnalyzeRule(
return s
}
/**
* 更新BookUrl,如果搜索结果有tocUrl也会更新,有些书源bookUrl定期更新,可以在js内调用更新
*/
fun refreshBookUrl() {
runBlocking {
val bookSource = source as? BookSource
val book = book as? Book
if (bookSource == null || book == null) return@runBlocking
val books = WebBook.searchBookAwait(this, bookSource, book.name)
books.forEach {
if (it.name == book.name && it.author == book.author) {
book.bookUrl = it.bookUrl
if (it.tocUrl.isNotBlank()) {
book.tocUrl = it.tocUrl
}
return@runBlocking
}
}
}
}
/**
* 更新tocUrl,有些书源目录url定期更新,可以在js调用更新
*/
fun refreshTocUrl() {
runBlocking {
val bookSource = source as? BookSource
val book = book as? Book
if (bookSource == null || book == null) return@runBlocking
WebBook.getBookInfoAwait(this, bookSource, book)
}
}
companion object {
private val putPattern = Pattern.compile("@put:(\\{[^}]+?\\})", Pattern.CASE_INSENSITIVE)
private val evalPattern =

@ -126,7 +126,7 @@ class TextFile(private val book: Book) {
val chapterContent = blockContent.substring(seekPos, chapterStart)
val chapterLength = chapterContent.toByteArray(charset).size
val lastStart = toc.lastOrNull()?.start ?: curOffset
if (curOffset + chapterLength - lastStart > 50000) {
if (curOffset + chapterLength - lastStart > 102400) {
bis.close()
return analyze()
}

@ -28,8 +28,8 @@ object BookChapterList {
scope: CoroutineScope,
bookSource: BookSource,
book: Book,
redirectUrl: String,
baseUrl: String,
redirectUrl: String,
body: String?
): List<BookChapter> {
body ?: throw NoStackTraceException(
@ -39,7 +39,7 @@ object BookChapterList {
Debug.log(bookSource.bookSourceUrl, "≡获取成功:${baseUrl}")
Debug.log(bookSource.bookSourceUrl, body, state = 30)
val tocRule = bookSource.getTocRule()
val nextUrlList = arrayListOf(baseUrl)
val nextUrlList = arrayListOf(redirectUrl)
var reverse = false
var listRule = tocRule.chapterList ?: ""
if (listRule.startsWith("-")) {
@ -157,7 +157,7 @@ object BookChapterList {
Debug.log(bookSource.bookSourceUrl, "┌获取目录下一页列表", log)
analyzeRule.getStringList(nextTocRule, isUrl = true)?.let {
for (item in it) {
if (item != baseUrl) {
if (item != redirectUrl) {
nextUrlList.add(item)
}
}
@ -180,7 +180,7 @@ object BookChapterList {
elements.forEachIndexed { index, item ->
scope.ensureActive()
analyzeRule.setContent(item)
val bookChapter = BookChapter(bookUrl = book.bookUrl, baseUrl = baseUrl)
val bookChapter = BookChapter(bookUrl = book.bookUrl, baseUrl = redirectUrl)
analyzeRule.chapter = bookChapter
bookChapter.title = analyzeRule.getString(nameRule)
bookChapter.url = analyzeRule.getString(urlRule)

@ -32,8 +32,8 @@ object BookContent {
bookSource: BookSource,
book: Book,
bookChapter: BookChapter,
redirectUrl: String,
baseUrl: String,
redirectUrl: String,
body: String?,
nextChapterUrl: String?,
needSave: Boolean = true
@ -50,10 +50,10 @@ object BookContent {
nextChapterUrl
}
val content = StringBuilder()
val nextUrlList = arrayListOf(baseUrl)
val nextUrlList = arrayListOf(redirectUrl)
val contentRule = bookSource.getContentRule()
val analyzeRule = AnalyzeRule(book, bookSource).setContent(body, baseUrl)
analyzeRule.setRedirectUrl(baseUrl)
analyzeRule.setRedirectUrl(redirectUrl)
analyzeRule.nextChapterUrl = mNextChapterUrl
scope.ensureActive()
var contentData = analyzeContent(
@ -64,8 +64,8 @@ object BookContent {
var nextUrl = contentData.second[0]
while (nextUrl.isNotEmpty() && !nextUrlList.contains(nextUrl)) {
if (!mNextChapterUrl.isNullOrEmpty()
&& NetworkUtils.getAbsoluteURL(baseUrl, nextUrl)
== NetworkUtils.getAbsoluteURL(baseUrl, mNextChapterUrl)
&& NetworkUtils.getAbsoluteURL(redirectUrl, nextUrl)
== NetworkUtils.getAbsoluteURL(redirectUrl, mNextChapterUrl)
) break
nextUrlList.add(nextUrl)
scope.ensureActive()

@ -25,8 +25,8 @@ object BookInfo {
scope: CoroutineScope,
bookSource: BookSource,
book: Book,
redirectUrl: String,
baseUrl: String,
redirectUrl: String,
body: String?,
canReName: Boolean,
) {
@ -126,7 +126,7 @@ object BookInfo {
Debug.log(bookSource.bookSourceUrl, "┌获取封面链接")
try {
analyzeRule.getString(infoRule.coverUrl).let {
if (it.isNotEmpty()) book.coverUrl = NetworkUtils.getAbsoluteURL(baseUrl, it)
if (it.isNotEmpty()) book.coverUrl = NetworkUtils.getAbsoluteURL(redirectUrl, it)
Debug.log(bookSource.bookSourceUrl, "${it}")
}
} catch (e: Exception) {
@ -136,8 +136,8 @@ object BookInfo {
scope.ensureActive()
Debug.log(bookSource.bookSourceUrl, "┌获取目录链接")
book.tocUrl = analyzeRule.getString(infoRule.tocUrl, isUrl = true)
if (book.tocUrl.isEmpty()) book.tocUrl = redirectUrl
if (book.tocUrl == redirectUrl) {
if (book.tocUrl.isEmpty()) book.tocUrl = baseUrl
if (book.tocUrl == baseUrl) {
book.tocHtml = body
}
Debug.log(bookSource.bookSourceUrl, "${book.tocUrl}")

@ -144,8 +144,8 @@ object WebBook {
scope = scope,
bookSource = bookSource,
book = book,
redirectUrl = book.bookUrl,
baseUrl = book.bookUrl,
redirectUrl = book.bookUrl,
body = book.infoHtml,
canReName = canReName
)
@ -168,8 +168,8 @@ object WebBook {
scope = scope,
bookSource = bookSource,
book = book,
redirectUrl = book.bookUrl,
baseUrl = res.url,
baseUrl = book.bookUrl,
redirectUrl = res.url,
body = res.body,
canReName = canReName
)
@ -202,8 +202,8 @@ object WebBook {
scope = scope,
bookSource = bookSource,
book = book,
redirectUrl = book.tocUrl,
baseUrl = book.tocUrl,
redirectUrl = book.tocUrl,
body = book.tocHtml
)
} else {
@ -225,8 +225,8 @@ object WebBook {
scope = scope,
bookSource = bookSource,
book = book,
redirectUrl = book.tocUrl,
baseUrl = res.url,
baseUrl = book.tocUrl,
redirectUrl = res.url,
body = res.body
)
}
@ -271,8 +271,8 @@ object WebBook {
bookSource = bookSource,
book = book,
bookChapter = bookChapter,
redirectUrl = bookChapter.getAbsoluteURL(),
baseUrl = bookChapter.getAbsoluteURL(),
redirectUrl = bookChapter.getAbsoluteURL(),
body = book.tocHtml,
nextChapterUrl = nextChapterUrl,
needSave = needSave
@ -301,8 +301,8 @@ object WebBook {
bookSource = bookSource,
book = book,
bookChapter = bookChapter,
redirectUrl = bookChapter.getAbsoluteURL(),
baseUrl = res.url,
baseUrl = bookChapter.getAbsoluteURL(),
redirectUrl = res.url,
body = res.body,
nextChapterUrl = nextChapterUrl,
needSave = needSave

@ -18,6 +18,7 @@ import io.legado.app.utils.viewbindingdelegate.viewBinding
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import timber.log.Timber
import java.io.File
import java.io.FileOutputStream
@ -108,7 +109,8 @@ class FileAssociationActivity :
var doc = treeDoc!!.findFile(name)
if (doc == null || bookDoc.lastModified() > doc.lastModified()) {
if (doc == null) {
doc = treeDoc.createFile(FileUtils.getMimeType(name), name)!!
doc = treeDoc.createFile(FileUtils.getMimeType(name), name)
?: throw SecurityException("Permission Denial")
}
contentResolver.openOutputStream(doc.uri)!!.use { oStream ->
contentResolver.openInputStream(bookDoc.uri)!!.use { iStream ->
@ -137,7 +139,17 @@ class FileAssociationActivity :
}
}
}.onFailure {
when (it) {
is SecurityException -> localBookTreeSelect.launch {
title = "选择保存书籍的文件夹"
mode = HandleFileContract.DIR_SYS
}
else -> {
Timber.e(it, "导入书籍失败")
toastOnUi(it.localizedMessage)
finish()
}
}
}
}
}

@ -91,7 +91,9 @@ class ReadRssActivity : VMBaseActivity<ActivityRssReadBinding, ReadRssViewModel>
override fun onCompatOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.menu_rss_refresh -> viewModel.refresh()
R.id.menu_rss_refresh -> viewModel.refresh {
binding.webView.reload()
}
R.id.menu_rss_star -> viewModel.favorite()
R.id.menu_share_it -> viewModel.rssArticle?.let {
share(it.link)

@ -104,17 +104,17 @@ class ReadRssViewModel(application: Application) : BaseViewModel(application),
}
}
fun refresh() {
fun refresh(finish: () -> Unit) {
rssArticle?.let { rssArticle ->
rssSource?.let {
val ruleContent = it.ruleContent
if (!ruleContent.isNullOrBlank()) {
loadContent(rssArticle, ruleContent)
} else {
loadUrl(rssArticle.link, rssArticle.origin)
}
} ?: loadUrl(rssArticle.link, rssArticle.origin)
finish.invoke()
}
} ?: finish.invoke()
} ?: finish.invoke()
}
fun favorite() {

@ -169,7 +169,7 @@ class CodeView : AppCompatMultiAutoCompleteTextView {
}
private fun highlight(editable: Editable): Editable {
if (editable.isEmpty()) return editable
if (editable.isEmpty() || editable.length > 1024) return editable
try {
clearSpans(editable)
highlightErrorLines(editable)

@ -10,6 +10,7 @@ private var toast: Toast? = null
fun Context.toastOnUi(message: Int) {
runOnUI {
kotlin.runCatching {
if (toast == null) {
toast = Toast.makeText(this, message, Toast.LENGTH_SHORT)
} else {
@ -19,9 +20,11 @@ fun Context.toastOnUi(message: Int) {
toast?.show()
}
}
}
fun Context.toastOnUi(message: CharSequence?) {
runOnUI {
kotlin.runCatching {
if (toast == null) {
toast = Toast.makeText(this, message, Toast.LENGTH_SHORT)
} else {
@ -31,9 +34,11 @@ fun Context.toastOnUi(message: CharSequence?) {
toast?.show()
}
}
}
fun Context.longToastOnUi(message: Int) {
runOnUI {
kotlin.runCatching {
if (toast == null) {
toast = Toast.makeText(this, message, Toast.LENGTH_LONG)
} else {
@ -43,9 +48,11 @@ fun Context.longToastOnUi(message: Int) {
toast?.show()
}
}
}
fun Context.longToastOnUi(message: CharSequence?) {
runOnUI {
kotlin.runCatching {
if (toast == null) {
toast = Toast.makeText(this, message, Toast.LENGTH_LONG)
} else {
@ -55,6 +62,7 @@ fun Context.longToastOnUi(message: CharSequence?) {
toast?.show()
}
}
}
fun Fragment.toastOnUi(message: Int) = requireActivity().toastOnUi(message)

Loading…
Cancel
Save