Merge remote-tracking branch 'origin/master'

This commit is contained in:
gedoor 2022-01-14 14:44:49 +08:00
commit cbae41bd3b
9 changed files with 223 additions and 48 deletions

View File

@ -219,6 +219,9 @@ dependencies {
// //
implementation('com.github.liuyueyi.quick-chinese-transfer:quick-transfer-core:0.2.3') implementation('com.github.liuyueyi.quick-chinese-transfer:quick-transfer-core:0.2.3')
//
implementation('cn.hutool:hutool-crypto:5.7.19')
//com.github.AmrDeveloper:CodeView已集成到应用内 //com.github.AmrDeveloper:CodeView已集成到应用内
//epubLib集成到应用内 //epubLib集成到应用内

View File

@ -109,6 +109,8 @@ data class BookChapter(
} }
fun getAbsoluteURL(): String { fun getAbsoluteURL(): String {
//二级目录解析的卷链接为空 返回目录页的链接
if (url.startsWith(title) && isVolume) return baseUrl
val urlMatcher = AnalyzeUrl.paramPattern.matcher(url) val urlMatcher = AnalyzeUrl.paramPattern.matcher(url)
val urlBefore = if (urlMatcher.find()) url.substring(0, urlMatcher.start()) else url val urlBefore = if (urlMatcher.find()) url.substring(0, urlMatcher.start()) else url
val urlAbsoluteBefore = NetworkUtils.getAbsoluteURL(baseUrl, urlBefore) val urlAbsoluteBefore = NetworkUtils.getAbsoluteURL(baseUrl, urlBefore)

View File

@ -3,6 +3,9 @@ package io.legado.app.help
import android.net.Uri import android.net.Uri
import android.util.Base64 import android.util.Base64
import androidx.annotation.Keep import androidx.annotation.Keep
import cn.hutool.crypto.digest.DigestUtil
import cn.hutool.crypto.symmetric.AES
import cn.hutool.crypto.symmetric.DESede
import io.legado.app.BuildConfig import io.legado.app.BuildConfig
import io.legado.app.constant.AppConst import io.legado.app.constant.AppConst
import io.legado.app.constant.AppConst.dateFormat import io.legado.app.constant.AppConst.dateFormat
@ -132,23 +135,23 @@ interface JsExtensions {
return cacheFile(urlStr, 0) return cacheFile(urlStr, 0)
} }
/** /**
* 缓存以文本方式保存的文件 .js .txt等 * 缓存以文本方式保存的文件 .js .txt等
* @param urlStr 网络文件的链接 * @param urlStr 网络文件的链接
* @param saveTime 缓存时间单位 * @param saveTime 缓存时间单位
* @return 返回缓存后的文件内容 * @return 返回缓存后的文件内容
*/ */
fun cacheFile(urlStr: String, saveTime: Int = 0): String? { fun cacheFile(urlStr: String, saveTime: Int = 0): String? {
val key = md5Encode16(urlStr) val key = md5Encode16(urlStr)
val cache = CacheManager.getFile(key) val cache = CacheManager.getFile(key)
if (cache.isNullOrBlank()) { if (cache.isNullOrBlank()) {
log("首次下载 $urlStr") log("首次下载 $urlStr")
val value = ajax(urlStr) ?: return null val value = ajax(urlStr) ?: return null
CacheManager.putFile(key, value, saveTime) CacheManager.putFile(key, value, saveTime)
return value return value
} }
return cache return cache
} }
/** /**
*js实现读取cookie *js实现读取cookie
@ -688,4 +691,172 @@ interface JsExtensions {
return AppConst.androidId return AppConst.androidId
} }
/**
* AES解密算法参数经过Base64加密
*
* @param data 加密的字符串
* @param key Base64后的密钥
* @param mode 模式
* @param padding 补码方式
* @param iv Base64后的加盐
* @return 解密后的字符串
*/
fun aesDecodeArgsBase64Str(
data: String,
key: String,
mode: String,
padding: String,
iv: String
): String? {
return AES(
mode,
padding,
Base64.decode(key, Base64.NO_WRAP),
Base64.decode(iv, Base64.NO_WRAP)
).decryptStr(data)
}
/**
* 3DES解密
*
* @param data 加密的字符串
* @param key 密钥
* @param mode 模式
* @param padding 补码方式
* @param iv 加盐
* @return 解密后的字符串
*/
fun tripleDESDecodeStr(
data: String,
key: String,
mode: String,
padding: String,
iv: String
): String? {
return DESede(mode, padding, key.toByteArray(), iv.toByteArray()).decryptStr(data)
}
/**
* 3DES解密算法参数经过Base64加密
*
* @param data 加密的字符串
* @param key Base64后的密钥
* @param mode 模式
* @param padding 补码方式
* @param iv Base64后的加盐
* @return 解密后的字符串
*/
fun tripleDESDecodeArgsBase64Str(
data: String,
key: String,
mode: String,
padding: String,
iv: String
): String? {
return DESede(
mode,
padding,
Base64.decode(key, Base64.NO_WRAP),
Base64.decode(iv, Base64.NO_WRAP)
).decryptStr(data)
}
/**
* AES加密并转为Base64算法参数经过Base64加密
*
* @param data 被加密的字符串
* @param key Base64后的密钥
* @param mode 模式
* @param padding 补码方式
* @param iv Base64后的加盐
* @return 加密后的Base64
*/
fun aesEncodeArgsBase64Str(
data: String,
key: String,
mode: String,
padding: String,
iv: String
): String? {
return AES(
mode,
padding,
Base64.decode(key, Base64.NO_WRAP),
Base64.decode(iv, Base64.NO_WRAP)
).encryptBase64(data)
}
/**
* 3DES加密并转为Base64
*
* @param data 被加密的字符串
* @param key 密钥
* @param mode 模式
* @param padding 补码方式
* @param iv 加盐
* @return 加密后的Base64
*/
fun tripleDESEncodeBase64Str(
data: String,
key: String,
mode: String,
padding: String,
iv: String
): String? {
return DESede(mode, padding, key.toByteArray(), iv.toByteArray()).encryptBase64(data)
}
/**
* 3DES加密并转为Base64算法参数经过Base64加密
*
* @param data 被加密的字符串
* @param key Base64后的密钥
* @param mode 模式
* @param padding 补码方式
* @param iv Base64后的加盐
* @return 加密后的Base64
*/
fun tripleDESEncodeArgsBase64Str(
data: String,
key: String,
mode: String,
padding: String,
iv: String
): String? {
return DESede(
mode,
padding,
Base64.decode(key, Base64.NO_WRAP),
Base64.decode(iv, Base64.NO_WRAP)
).encryptBase64(data)
}
/**
* 生成摘要并转为16进制字符串
*
* @param data 被摘要数据
* @param algorithm 签名算法
* @return 16进制字符串
*/
fun digestHex(
data: String,
algorithm: String,
): String? {
return DigestUtil.digester(algorithm).digestHex(data)
}
/**
* 生成摘要并转为Base64字符串
*
* @param data 被摘要数据
* @param algorithm 签名算法
* @return Base64字符串
*/
fun digestBase64Str(
data: String,
algorithm: String,
): String? {
return Base64.encodeToString(DigestUtil.digester(algorithm).digest(data), Base64.NO_WRAP)
}
} }

View File

@ -193,8 +193,8 @@ object BookChapterList {
} }
if (bookChapter.url.isEmpty()) { if (bookChapter.url.isEmpty()) {
if (bookChapter.isVolume) { if (bookChapter.isVolume) {
bookChapter.url = bookChapter.title bookChapter.url = bookChapter.title + index
Debug.log(bookSource.bookSourceUrl, "一级目录${index}未获取到url,使用章节标题替代") Debug.log(bookSource.bookSourceUrl, "一级目录${index}未获取到url,使用${bookChapter.title}${index}替代")
} else { } else {
bookChapter.url = baseUrl bookChapter.url = baseUrl
Debug.log(bookSource.bookSourceUrl, "目录${index}未获取到url,使用baseUrl替代") Debug.log(bookSource.bookSourceUrl, "目录${index}未获取到url,使用baseUrl替代")

View File

@ -261,10 +261,9 @@ object WebBook {
Debug.log(bookSource.bookSourceUrl, "⇒正文规则为空,使用章节链接:${bookChapter.url}") Debug.log(bookSource.bookSourceUrl, "⇒正文规则为空,使用章节链接:${bookChapter.url}")
return bookChapter.url return bookChapter.url
} }
if(bookChapter.isVolume && bookChapter.url == bookChapter.title) { if(bookChapter.isVolume && bookChapter.url.startsWith(bookChapter.title)) {
//不返回空值,是为了过书源检测 Debug.log(bookSource.bookSourceUrl, "⇒一级目录正文不解析规则")
Debug.log(bookSource.bookSourceUrl, "⇒一级目录正文,使用章节标题:${bookChapter.title}") return bookChapter.tag ?: ""
return bookChapter.title
} }
return if (bookChapter.url == book.bookUrl && !book.tocHtml.isNullOrEmpty()) { return if (bookChapter.url == book.bookUrl && !book.tocHtml.isNullOrEmpty()) {
BookContent.analyzeContent( BookContent.analyzeContent(

View File

@ -144,7 +144,7 @@ class CheckSourceService : BaseService() {
nextChapterUrl = nextChapterUrl, nextChapterUrl = nextChapterUrl,
needSave = false needSave = false
) )
if (content.isBlank()) { if ( !toc.first().isVolume && content.isBlank()) {
throw NoStackTraceException("正文内容为空") throw NoStackTraceException("正文内容为空")
} }
}.timeout(180000L) }.timeout(180000L)

View File

@ -129,7 +129,7 @@ object ChapterProvider {
matcher.appendTail(sb) matcher.appendTail(sb)
text = sb.toString() text = sb.toString()
val isTitle = index == 0 val isTitle = index == 0
val isVolumeTitle = bookChapter.isVolume && isTitle && bookChapter.url == bookChapter.title val isVolumeTitle = bookChapter.isVolume && isTitle && contents.size == 1
val textPaint = if (isTitle) titlePaint else contentPaint val textPaint = if (isTitle) titlePaint else contentPaint
if (!(isTitle && ReadBookConfig.titleMode == 2)) { if (!(isTitle && ReadBookConfig.titleMode == 2)) {
setTypeText( setTypeText(
@ -147,7 +147,7 @@ object ChapterProvider {
val text = content.substring(start, matcher.start()) val text = content.substring(start, matcher.start())
if (text.isNotBlank()) { if (text.isNotBlank()) {
val isTitle = index == 0 val isTitle = index == 0
val isVolumeTitle = bookChapter.isVolume && isTitle && bookChapter.url == bookChapter.title val isVolumeTitle = bookChapter.isVolume && isTitle && contents.size == 1
val textPaint = if (isTitle) titlePaint else contentPaint val textPaint = if (isTitle) titlePaint else contentPaint
if (!(isTitle && ReadBookConfig.titleMode == 2)) { if (!(isTitle && ReadBookConfig.titleMode == 2)) {
setTypeText( setTypeText(
@ -169,7 +169,7 @@ object ChapterProvider {
val text = content.substring(start, content.length) val text = content.substring(start, content.length)
if (text.isNotBlank()) { if (text.isNotBlank()) {
val isTitle = index == 0 val isTitle = index == 0
val isVolumeTitle = bookChapter.isVolume && isTitle && bookChapter.url == bookChapter.title val isVolumeTitle = bookChapter.isVolume && isTitle && contents.size == 1
val textPaint = if (isTitle) titlePaint else contentPaint val textPaint = if (isTitle) titlePaint else contentPaint
if (!(isTitle && ReadBookConfig.titleMode == 2)) { if (!(isTitle && ReadBookConfig.titleMode == 2)) {
setTypeText( setTypeText(
@ -332,7 +332,7 @@ object ChapterProvider {
} }
lineIndex == layout.lineCount - 1 -> { lineIndex == layout.lineCount - 1 -> {
//最后一行 //最后一行
textLine.text = if(isVolumeTitle) "" else "$words\n" textLine.text = "$words\n"
isLastLine = true isLastLine = true
//标题居中 //标题居中
val startX = if (isTitle && ReadBookConfig.titleMode == 1 || isVolumeTitle) val startX = if (isTitle && ReadBookConfig.titleMode == 1 || isVolumeTitle)
@ -349,7 +349,7 @@ object ChapterProvider {
} }
else -> { else -> {
//中间行 //中间行
textLine.text = if(isVolumeTitle) "" else words textLine.text = words
addCharsToLineMiddle( addCharsToLineMiddle(
absStartX, absStartX,
textLine, textLine,
@ -579,7 +579,7 @@ object ChapterProvider {
tPaint.typeface = titleFont tPaint.typeface = titleFont
tPaint.textSize = with(ReadBookConfig) { textSize + titleSize }.sp.toFloat() tPaint.textSize = with(ReadBookConfig) { textSize + titleSize }.sp.toFloat()
tPaint.isAntiAlias = true tPaint.isAntiAlias = true
//to do:卷名的标题排版 //正文
val cPaint = TextPaint() val cPaint = TextPaint()
cPaint.color = ReadBookConfig.textColor cPaint.color = ReadBookConfig.textColor
cPaint.letterSpacing = ReadBookConfig.letterSpacing cPaint.letterSpacing = ReadBookConfig.letterSpacing

View File

@ -7,7 +7,7 @@
<string-array name="group_style"> <string-array name="group_style">
<item>標籤</item> <item>標籤</item>
<item>文件</item> <item>資料</item>
</string-array> </string-array>
<string-array name="text_suffix"> <string-array name="text_suffix">
@ -87,8 +87,8 @@
<string-array name="rule_type"> <string-array name="rule_type">
<item>書源</item> <item>書源</item>
<item></item> <item></item>
<item>替換規則</item> <item>取代規則</item>
</string-array> </string-array>
</resources> </resources>

View File

@ -231,7 +231,7 @@
<string name="intro_show_null">簡介: 暫無簡介</string> <string name="intro_show_null">簡介: 暫無簡介</string>
<string name="open_from_other">打開外部書籍</string> <string name="open_from_other">打開外部書籍</string>
<string name="origin_show">來源: %s</string> <string name="origin_show">來源: %s</string>
<string name="import_replace_rule">匯入替換規則</string> <string name="import_replace_rule">匯入取代規則</string>
<string name="import_replace_rule_on_line">匯入線上規則</string> <string name="import_replace_rule_on_line">匯入線上規則</string>
<string name="check_update_interval">檢查更新間隔</string> <string name="check_update_interval">檢查更新間隔</string>
<string name="bookshelf_px_0">按閱讀時間</string> <string name="bookshelf_px_0">按閱讀時間</string>
@ -634,8 +634,8 @@
<string name="service_start">正在啟動服務\n具體訊息查看通知欄</string> <string name="service_start">正在啟動服務\n具體訊息查看通知欄</string>
<string name="default_path">預設路徑</string> <string name="default_path">預設路徑</string>
<string name="sys_folder_picker">系統資料夾選擇器</string> <string name="sys_folder_picker">系統資料夾選擇器</string>
<string name="app_folder_picker">自帶資料夾選擇器</string> <string name="app_folder_picker">內建資料夾選擇器</string>
<string name="app_file_picker">自帶資料夾選擇器</string> <string name="app_file_picker">內建資料夾選擇器</string>
<string name="a10_permission_toast">Android10以上因權限限制可能無法讀寫文件</string> <string name="a10_permission_toast">Android10以上因權限限制可能無法讀寫文件</string>
<string name="add_to_text_context_menu_s">長按文字在操作選單中顯示閱讀·搜尋</string> <string name="add_to_text_context_menu_s">長按文字在操作選單中顯示閱讀·搜尋</string>
<string name="add_to_text_context_menu_t">文字操作顯示搜尋</string> <string name="add_to_text_context_menu_t">文字操作顯示搜尋</string>
@ -678,7 +678,7 @@
<string name="btn_default_s">預設</string> <string name="btn_default_s">預設</string>
<string name="main_menu">主選單</string> <string name="main_menu">主選單</string>
<string name="request_permission">點擊授予權限</string> <string name="request_permission">點擊授予權限</string>
<string name="tip_local_perm_request_storage">閱讀需要存取記憶卡權限,請點擊下方的"授予權限"按鈕,或前往“設定”—“應用權限”—打開所需權限。如果授予權限後仍然不正常,請點擊右上角的“選擇資料夾”,使用系統資料夾選擇器。</string> <string name="tip_local_perm_request_storage">閱讀需要存取記憶卡權限,請點擊下方的"授予權限"按鈕,或前往「設定」—「應用權限」—打開所需權限。如果授予權限後仍然不正常,請點擊右上角的「選擇資料夾」,使用系統資料夾選擇器。</string>
<string name="alouding_disable">全文朗讀中不能朗讀選中文字</string> <string name="alouding_disable">全文朗讀中不能朗讀選中文字</string>
<string name="read_body_to_lh">擴展到瀏海</string> <string name="read_body_to_lh">擴展到瀏海</string>
<string name="toc_updateing">更新目錄中</string> <string name="toc_updateing">更新目錄中</string>
@ -817,7 +817,7 @@
<string name="background_image">背景圖片</string> <string name="background_image">背景圖片</string>
<string name="background_image_blurring">背景圖片虛化</string> <string name="background_image_blurring">背景圖片虛化</string>
<string name="background_image_blurring_radius">虛化半徑</string> <string name="background_image_blurring_radius">虛化半徑</string>
<string name="background_image_hint">0為停用用範圍1~25\n半徑數值越大虛化效果越高</string> <string name="background_image_hint">0為停用用範圍1~25\n半徑數值越大虛化效果越高</string>
<string name="export_folder">匯出資料夾</string> <string name="export_folder">匯出資料夾</string>
<string name="export_charset">匯出編碼</string> <string name="export_charset">匯出編碼</string>
<string name="export_no_chapter_name">TXT不匯出章節名</string> <string name="export_no_chapter_name">TXT不匯出章節名</string>
@ -837,7 +837,7 @@
<string name="list_src">列表原始碼</string> <string name="list_src">列表原始碼</string>
<string name="url_already">此url已訂閱</string> <string name="url_already">此url已訂閱</string>
<string name="high_brush_title">高刷</string> <string name="high_brush_title">高刷</string>
<string name="high_brush_summary">使用螢幕最高新率</string> <string name="high_brush_summary">使用螢幕最高新率</string>
<string name="export_all">匯出所有</string> <string name="export_all">匯出所有</string>
<string name="complete">完成</string> <string name="complete">完成</string>
<string name="show_unread">顯示未讀標誌</string> <string name="show_unread">顯示未讀標誌</string>
@ -879,8 +879,8 @@
<string name="set_source_variable">設定源變數</string> <string name="set_source_variable">設定源變數</string>
<string name="set_book_variable">設定書籍變數</string> <string name="set_book_variable">設定書籍變數</string>
<string name="summary">注釋</string> <string name="summary">注釋</string>
<string name="cover_config">封面設</string> <string name="cover_config">封面設</string>
<string name="cover_config_summary">置默認封面樣式</string> <string name="cover_config_summary">定預設封面樣式</string>
<string name="cover_show_name">顯示書名</string> <string name="cover_show_name">顯示書名</string>
<string name="cover_show_name_summary">封面上顯示書名</string> <string name="cover_show_name_summary">封面上顯示書名</string>
<string name="cover_show_author">顯示作者</string> <string name="cover_show_author">顯示作者</string>
@ -902,17 +902,17 @@
<string name="use_browser_open">是否使用外部瀏覽器打開?</string> <string name="use_browser_open">是否使用外部瀏覽器打開?</string>
<string name="see">查看</string> <string name="see">查看</string>
<string name="open">打開</string> <string name="open">打開</string>
<string name="del_login_header">刪除登</string> <string name="del_login_header">刪除登</string>
<string name="show_login_header">查看登</string> <string name="show_login_header">查看登</string>
<string name="login_header"></string> <string name="login_header"></string>
<string name="font_scale">字體大小</string> <string name="font_scale">字體大小</string>
<string name="font_scale_summary">前字體大小:%.1f</string> <string name="font_scale_summary">前字體大小:%.1f</string>
<string name="tts_speech_reduce">語速</string> <string name="tts_speech_reduce">語速</string>
<string name="tts_speech_add">語速加</string> <string name="tts_speech_add">語速加</string>
<string name="open_sys_dir_picker_error">开系统文件夹选择器出错,自动打开应用文件夹选择</string> <string name="open_sys_dir_picker_error">開系統資料夾選擇器出錯,自動打開應用程式資料夾選擇</string>
<string name="expand_text_menu">开文本选择菜单</string> <string name="expand_text_menu">開文字選擇選單</string>
<string name="search_content_size">結果</string> <string name="search_content_size">結果</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>
</resources> </resources>