Просмотр исходного кода

Merge remote-tracking branch 'origin/master'

gedoor 4 лет назад
Родитель
Сommit
422cc2e442

+ 3 - 0
app/build.gradle

@@ -219,6 +219,9 @@ dependencies {
     //转换繁体
     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已集成到应用内
     //epubLib集成到应用内
 

+ 2 - 0
app/src/main/java/io/legado/app/data/entities/BookChapter.kt

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

+ 185 - 14
app/src/main/java/io/legado/app/help/JsExtensions.kt

@@ -3,6 +3,9 @@ package io.legado.app.help
 import android.net.Uri
 import android.util.Base64
 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.constant.AppConst
 import io.legado.app.constant.AppConst.dateFormat
@@ -132,23 +135,23 @@ interface JsExtensions {
         return cacheFile(urlStr, 0)
     }
 
-     /**
+    /**
      * 缓存以文本方式保存的文件 如.js .txt等
-      * @param urlStr 网络文件的链接
-      * @param saveTime 缓存时间,单位:秒
-      * @return 返回缓存后的文件内容
+     * @param urlStr 网络文件的链接
+     * @param saveTime 缓存时间,单位:秒
+     * @return 返回缓存后的文件内容
      */
     fun cacheFile(urlStr: String, saveTime: Int = 0): String? {
-         val key = md5Encode16(urlStr)
-         val cache = CacheManager.getFile(key)
-         if (cache.isNullOrBlank()) {
-             log("首次下载 $urlStr")
-             val value = ajax(urlStr) ?: return null
-             CacheManager.putFile(key, value, saveTime)
-             return value
-         }
-         return cache
-     }
+        val key = md5Encode16(urlStr)
+        val cache = CacheManager.getFile(key)
+        if (cache.isNullOrBlank()) {
+            log("首次下载 $urlStr")
+            val value = ajax(urlStr) ?: return null
+            CacheManager.putFile(key, value, saveTime)
+            return value
+        }
+        return cache
+    }
 
     /**
      *js实现读取cookie
@@ -688,4 +691,172 @@ interface JsExtensions {
         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)
+    }
+
 }

+ 2 - 2
app/src/main/java/io/legado/app/model/webBook/BookChapterList.kt

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

+ 3 - 4
app/src/main/java/io/legado/app/model/webBook/WebBook.kt

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

+ 1 - 1
app/src/main/java/io/legado/app/service/CheckSourceService.kt

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

+ 6 - 6
app/src/main/java/io/legado/app/ui/book/read/page/provider/ChapterProvider.kt

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

+ 3 - 3
app/src/main/res/values-zh-rTW/arrays.xml

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

+ 18 - 18
app/src/main/res/values-zh-rTW/strings.xml

@@ -231,7 +231,7 @@
     <string name="intro_show_null">簡介: 暫無簡介</string>
     <string name="open_from_other">打開外部書籍</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="check_update_interval">檢查更新間隔</string>
     <string name="bookshelf_px_0">按閱讀時間</string>
@@ -634,8 +634,8 @@
     <string name="service_start">正在啟動服務\n具體訊息查看通知欄</string>
     <string name="default_path">預設路徑</string>
     <string name="sys_folder_picker">系統資料夾選擇器</string>
-    <string name="app_folder_picker">自帶資料夾選擇器</string>
-    <string name="app_file_picker">自帶資料夾選擇器</string>
+    <string name="app_folder_picker">內建資料夾選擇器</string>
+    <string name="app_file_picker">內建資料夾選擇器</string>
     <string name="a10_permission_toast">Android10以上因權限限制可能無法讀寫文件</string>
     <string name="add_to_text_context_menu_s">長按文字在操作選單中顯示閱讀·搜尋</string>
     <string name="add_to_text_context_menu_t">文字操作顯示搜尋</string>
@@ -678,7 +678,7 @@
     <string name="btn_default_s">預設</string>
     <string name="main_menu">主選單</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="read_body_to_lh">擴展到瀏海</string>
     <string name="toc_updateing">更新目錄中</string>
@@ -817,7 +817,7 @@
     <string name="background_image">背景圖片</string>
     <string name="background_image_blurring">背景圖片虛化</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_charset">匯出編碼</string>
     <string name="export_no_chapter_name">TXT不匯出章節名</string>
@@ -837,7 +837,7 @@
     <string name="list_src">列表原始碼</string>
     <string name="url_already">此url已訂閱</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="complete">完成</string>
     <string name="show_unread">顯示未讀標誌</string>
@@ -879,8 +879,8 @@
     <string name="set_source_variable">設定源變數</string>
     <string name="set_book_variable">設定書籍變數</string>
     <string name="summary">注釋</string>
-    <string name="cover_config">封面設置</string>
-    <string name="cover_config_summary">設置默認封面樣式</string>
+    <string name="cover_config">封面設定</string>
+    <string name="cover_config_summary">設定預設封面樣式</string>
     <string name="cover_show_name">顯示書名</string>
     <string name="cover_show_name_summary">封面上顯示書名</string>
     <string name="cover_show_author">顯示作者</string>
@@ -902,17 +902,17 @@
     <string name="use_browser_open">是否使用外部瀏覽器打開?</string>
     <string name="see">查看</string>
     <string name="open">打開</string>
-    <string name="del_login_header">刪除登錄頭</string>
-    <string name="show_login_header">查看登錄頭</string>
-    <string name="login_header">登錄頭</string>
+    <string name="del_login_header">刪除登入頭</string>
+    <string name="show_login_header">查看登入頭</string>
+    <string name="login_header">登入頭</string>
     <string name="font_scale">字體大小</string>
-    <string name="font_scale_summary">當前字體大小:%.1f</string>
-    <string name="tts_speech_reduce">語速减</string>
+    <string name="font_scale_summary">目前字體大小:%.1f</string>
+    <string name="tts_speech_reduce">語速減</string>
     <string name="tts_speech_add">語速加</string>
-    <string name="open_sys_dir_picker_error">打开系统文件夹选择器出错,自动打开应用文件夹选择器</string>
-    <string name="expand_text_menu">展开文本选择菜单</string>
-    <string name="search_content_size">搜索結果</string>
-    <string name="book_tree_uri_t">书籍保存位置</string>
-    <string name="book_tree_uri_s">从其它应用打开的书籍保存位置</string>
+    <string name="open_sys_dir_picker_error">打開系統資料夾選擇器出錯,自動打開應用程式資料夾選擇器</string>
+    <string name="expand_text_menu">展開文字選擇選單</string>
+    <string name="search_content_size">搜尋結果</string>
+    <string name="book_tree_uri_t">書籍儲存位置</string>
+    <string name="book_tree_uri_s">從其它應用程式打開的書籍儲存位置</string>
 
 </resources>