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

Merge remote-tracking branch 'origin/master'

kunfei 3 лет назад
Родитель
Сommit
ef7d1f6e29

+ 19 - 10
.github/scripts/cronet.sh

@@ -1,14 +1,16 @@
 #!/usr/bin/env bash
 
-echo "fetch release info from https://chromiumdash.appspot.com ..."
-
-branch="Stable"
+branch=$1
+[ -z $1 ] && branch=Stable
+[ -z $GITHUB_ENV ] && echo "Error: Unexpected github workflow environment" && exit
 
+# 获取最新cronet版本
+echo "fetch $branch release info from https://chromiumdash.appspot.com ..."
 lastest_cronet_version=`curl -s "https://chromiumdash.appspot.com/fetch_releases?channel=$branch&platform=Android&num=1&offset=0" | jq .[0].version -r`
 echo "lastest_cronet_version: $lastest_cronet_version"
 #lastest_cronet_version=100.0.4845.0
 lastest_cronet_main_version=${lastest_cronet_version%%\.*}.0.0.0
-
+# 检查版本是否存在
 function checkVersionExit() {
     local jar_url="https://storage.googleapis.com/chromium-cronet/android/$lastest_cronet_version/Release/cronet/cronet_api.jar"
     statusCode=$(curl -s -I -w %{http_code} "$jar_url" -o /dev/null)
@@ -17,18 +19,25 @@ function checkVersionExit() {
         exit
     fi
 }
-
+# 添加变量到github env
+function writeVariableToGithubEnv() {
+    echo "$1=$2" >> $GITHUB_ENV
+}
+# 获取本地cronet版本
 path=$GITHUB_WORKSPACE/gradle.properties
 current_cronet_version=`cat $path | grep CronetVersion | sed s/CronetVersion=//`
 echo "current_cronet_version: $current_cronet_version"
 
 if [[  $current_cronet_version < $lastest_cronet_version ]];then
     checkVersionExit
+    # 更新gradle.properties
     sed -i s/CronetVersion=.*/CronetVersion=$lastest_cronet_version/ $path
     sed -i s/CronetMainVersion=.*/CronetMainVersion=$lastest_cronet_main_version/ $path
+    # 添加更新日志
     sed "15a* 更新cronet: $lastest_cronet_version" -i $GITHUB_WORKSPACE/app/src/main/assets/updateLog.md
-    echo "start download latest cronet"
-    chmod +x gradlew
-    ./gradlew app:downloadCronet
-fi
-
+    # 生成pull request信息
+    writeVariableToGithubEnv PR_TITLE "Bump cronet from $current_cronet_version to $lastest_cronet_version"
+    writeVariableToGithubEnv PR_BODY "Changes in the [Git log](https://chromium.googlesource.com/chromium/src/+log/$current_cronet_version..$lastest_cronet_version)"
+    # 生成cronet flag
+    writeVariableToGithubEnv cronet ok
+fi

+ 9 - 8
.github/workflows/cronet.yml

@@ -11,17 +11,19 @@ jobs:
     if: ${{ github.repository == 'gedoor/legado' }}
     steps:
       - uses: actions/checkout@v3
-      - name: Set up Gradle
-        uses: gradle/gradle-build-action@v2
-
       - name: Check Cronet Updates
+        run: source .github/scripts/cronet.sh
+
+      - uses: gradle/gradle-build-action@v2
+        if: ${{ env.cronet == 'ok' }}
+      - name: Download Cronet
+        if: ${{ env.cronet == 'ok' }}
         run: |
-          echo "获取cronet最新版本"
-          source .github/scripts/cronet.sh
-          echo "PR_TITLE=Bump cronet from $current_cronet_version to $lastest_cronet_version " >> $GITHUB_ENV
-          echo "PR_BODY=Changes in the [Git log](https://chromium.googlesource.com/chromium/src/+log/$current_cronet_version..$lastest_cronet_version)" >> $GITHUB_ENV
+          chmod +x gradlew
+          ./gradlew app:downloadCronet
 
       - name: Create Pull Request
+        if: ${{ env.cronet == 'ok' }}
         uses: peter-evans/create-pull-request@v4
         continue-on-error: true
         with:
@@ -38,4 +40,3 @@ jobs:
             *cronet.json
             *updateLog.md
             gradle.properties
-          

+ 2 - 0
.github/workflows/test.yml

@@ -60,6 +60,8 @@ jobs:
       VERSIONL: ${{ needs.prepare.outputs.versionL }}
     steps:
       - uses: actions/checkout@v3
+        with:
+          fetch-depth: 0
       - name: Clear 18PlusList.txt
         run: |
           echo "清空18PlusList.txt"

+ 2 - 2
app/build.gradle

@@ -172,7 +172,7 @@ dependencies {
     implementation('com.google.code.gson:gson:2.10.1')
 
     //lifecycle
-    def lifecycle_version = '2.5.1'
+    def lifecycle_version = '2.6.0'
     implementation("androidx.lifecycle:lifecycle-common-java8:$lifecycle_version")
     implementation("androidx.lifecycle:lifecycle-service:$lifecycle_version")
 
@@ -246,7 +246,7 @@ dependencies {
 
     //加解密类库,有些书源使用
     //noinspection GradleDependency,GradlePackageUpdate
-    implementation('cn.hutool:hutool-crypto:5.8.14')
+    implementation('cn.hutool:hutool-crypto:5.8.15')
 
     //firebase, 崩溃统计和性能统计, 会导致共存版本崩溃
     //implementation platform('com.google.firebase:firebase-bom:30.0.1')

+ 1 - 0
app/proguard-rules.pro

@@ -392,6 +392,7 @@
 -keep class io.legado.app.lib.cronet.CronetInterceptor{*;}
 -keep class io.legado.app.lib.cronet.CronetLoader{*;}
 -keep class io.legado.app.help.AppUpdateGitHub{*;}
+-keep class io.legado.app.help.AppIntentType{*;}
 # Error Exception 
 -keep class * extends java.lang.Exception
 -keep class * extends java.lang.Error

+ 8 - 0
app/src/main/AndroidManifest.xml

@@ -381,12 +381,20 @@
                 <data android:mimeType="*/*" />
                 <!--TXT-->
                 <data android:pathAdvancedPattern=".*\\.[tT][xX][tT]" />
+                <data android:pathPattern=".*\\.txt" />
+                <data android:pathPattern=".*\\.TXT" />
                 <!--JSON-->
                 <data android:pathAdvancedPattern=".*\\.[jJ][sS][oO][nN]" />
+                <data android:pathPattern=".*\\.json" />
+                <data android:pathPattern=".*\\.JSON" />
                 <!-- EPUB -->
                 <data android:pathAdvancedPattern=".*\\.[eE][pP][uU][bB]" />
+                <data android:pathPattern=".*\\.epub" />
+                <data android:pathPattern=".*\\.EPUB" />
                 <!-- pdf -->
                 <data android:pathAdvancedPattern=".*\\.[pP][dD][fF]" />
+                <data android:pathPattern=".*\\.pdf" />
+                <data android:pathPattern=".*\\.PDF" />
             </intent-filter>
         </activity>
 

+ 2 - 0
app/src/main/java/io/legado/app/help/CrashHandler.kt

@@ -3,6 +3,7 @@ package io.legado.app.help
 import android.annotation.SuppressLint
 import android.content.Context
 import android.os.Build
+import android.webkit.WebSettings
 import io.legado.app.constant.AppConst
 import io.legado.app.model.ReadAloud
 import io.legado.app.utils.FileUtils
@@ -65,6 +66,7 @@ class CrashHandler(val context: Context) : Thread.UncaughtExceptionHandler {
                 map["MODEL"] = Build.MODEL
                 map["SDK_INT"] = Build.VERSION.SDK_INT.toString()
                 map["RELEASE"] = Build.VERSION.RELEASE
+                map["WebViewUserAgent"] = WebSettings.getDefaultUserAgent(appCtx)
                 //获取app版本信息
                 AppConst.appInfo.let {
                     map["versionName"] = it.versionName

+ 4 - 2
app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt

@@ -585,16 +585,18 @@ class AnalyzeUrl(
 
     /**
      * 设置cookie 优先级
-     * urlOption临时cookie > 数据库cookie = okhttp CookieJar保存在内存中的cookie
+     * urlOption临时cookie > 数据库cookie
      */
     private fun setCookie() {
         val cookie = kotlin.run {
+            /* 每次调用getXX cookieJar已经保存过了
             if (enabledCookieJar) {
                 val key = "${domain}_cookieJar"
                 CacheManager.getFromMemory(key)?.let {
                     return@run it
                 }
             }
+            */
             CookieStore.getCookie(domain)
         }
         if (cookie.isNotEmpty()) {
@@ -608,7 +610,7 @@ class AnalyzeUrl(
     }
 
     /**
-     * 保存cookie在访问结束时就保存,不等到下次访问
+     * 保存cookieJar中的cookie在访问结束时就保存,不等到下次访问
      */
     private fun saveCookie() {
         //书源启用保存cookie时 添加内存中的cookie到数据库

+ 1 - 1
app/src/main/java/io/legado/app/model/webBook/BookInfo.kt

@@ -151,7 +151,7 @@ object BookInfo {
             coroutineContext.ensureActive()
             Debug.log(bookSource.bookSourceUrl, "┌获取文件下载链接")
             book.downloadUrls = analyzeRule.getStringList(infoRule.downloadUrls, isUrl = true)
-            if (book.downloadUrls == null) {
+            if (book.downloadUrls.isNullOrEmpty()) {
                 Debug.log(bookSource.bookSourceUrl, "└")
                 throw NoStackTraceException("下载链接为空")
             } else {

+ 1 - 1
app/src/main/java/io/legado/app/ui/book/group/GroupSelectDialog.kt

@@ -45,7 +45,7 @@ class GroupSelectDialog() : BaseDialogFragment(R.layout.dialog_book_group_picker
     private var requestCode: Int = -1
     private val viewModel: GroupViewModel by viewModels()
     private val adapter by lazy { GroupAdapter(requireContext()) }
-    private var callBack = (activity as? CallBack)
+    private val callBack get() = (activity as? CallBack)
     private var groupId: Long = 0
 
     override fun onStart() {

+ 34 - 32
app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt

@@ -52,8 +52,7 @@ class BookInfoActivity :
     VMBaseActivity<ActivityBookInfoBinding, BookInfoViewModel>(toolBarTheme = Theme.Dark),
     GroupSelectDialog.CallBack,
     ChangeBookSourceDialog.CallBack,
-    ChangeCoverDialog.CallBack,
-    BookInfoViewModel.CallBack {
+    ChangeCoverDialog.CallBack {
 
     private val tocActivityResult = registerForActivityResult(TocActivityResult()) {
         it?.let {
@@ -108,10 +107,9 @@ class BookInfoActivity :
         binding.flAction.setBackgroundColor(bottomBackground)
         binding.tvShelf.setTextColor(getPrimaryTextColor(ColorUtils.isColorLight(bottomBackground)))
         binding.tvToc.text = getString(R.string.toc_s, getString(R.string.loading))
-        viewModel.callBack = this
         viewModel.bookData.observe(this) { showBook(it) }
         viewModel.chapterListData.observe(this) { upLoading(false, it) }
-        //viewModel.webFileData.observe(this) { showWebFileDownloadAlert() }
+        viewModel.waitDialogData.observe(this) { upWaitDialogStatus(it) }
         viewModel.initData(intent)
         initViewEvent()
     }
@@ -499,31 +497,34 @@ class BookInfoActivity :
     private fun showWebFileDownloadAlert(
         onClick: ((Book) -> Unit)? = null
     ) {
-        viewModel.webFileData.value?.let {
-            alert(titleResource = R.string.download_and_import_file) {
-                items<BookInfoViewModel.WebFile>(it) { _, webFile, _ ->
-                    if (webFile.isSupported) {
-                        /* import */
-                        viewModel.importOrDownloadWebFile<Book>(webFile) {
-                            onClick?.invoke(it)
-                        }
-                    } else {
-                        alert(
-                            title = getString(R.string.draw),
-                            message = getString(R.string.file_not_supported, webFile.name)
-                        ) {
-                            neutralButton(R.string.open_fun) {
-                                /* download only */
-                                viewModel.importOrDownloadWebFile<Uri>(webFile) { uri ->
-                                    openFileUri(uri, "*/*")
-                                }
+        val webFiles = viewModel.webFiles
+        if (webFiles.isEmpty()) {
+            toastOnUi("Unexpected webFileData")
+            return
+        }
+        alert(titleResource = R.string.download_and_import_file) {
+            items<BookInfoViewModel.WebFile>(webFiles) { _, webFile, _ ->
+                if (webFile.isSupported) {
+                    /* import */
+                    viewModel.importOrDownloadWebFile<Book>(webFile) {
+                        onClick?.invoke(it)
+                    }
+                } else {
+                    alert(
+                        title = getString(R.string.draw),
+                        message = getString(R.string.file_not_supported, webFile.name)
+                    ) {
+                        neutralButton(R.string.open_fun) {
+                            /* download only */
+                            viewModel.importOrDownloadWebFile<Uri>(webFile) { uri ->
+                                openFileUri(uri, "*/*")
                             }
-                            noButton()
                         }
+                        noButton()
                     }
                 }
             }
-        } ?: toastOnUi("Unexpected webFileData")
+        }
     }
 
     private fun readBook(book: Book) {
@@ -588,14 +589,15 @@ class BookInfoActivity :
         }
     }
 
-    override fun onWebFileProcessFinally() {
-        waitDialog.dismiss()
-    }
-
-    override fun onWebFileProcessStart() {
-        waitDialog.run {
-            setText("Loading.....")
-            show()
+    private fun upWaitDialogStatus(isShow: Boolean) {
+        val showText = "Loading....."
+        if (isShow) {
+            waitDialog.run {
+                setText(showText)
+                show()
+            }
+        } else {
+            waitDialog.dismiss()
         }
     }
 

+ 10 - 44
app/src/main/java/io/legado/app/ui/book/info/BookInfoViewModel.kt

@@ -21,8 +21,6 @@ import io.legado.app.help.AppWebDav
 import io.legado.app.help.book.*
 import io.legado.app.help.coroutine.Coroutine
 import io.legado.app.lib.webdav.ObjectNotFoundException
-import io.legado.app.model.analyzeRule.AnalyzeRule
-import io.legado.app.model.analyzeRule.AnalyzeUrl
 import io.legado.app.model.BookCover
 import io.legado.app.model.ReadBook
 import io.legado.app.model.localBook.LocalBook
@@ -30,18 +28,17 @@ import io.legado.app.model.webBook.WebBook
 import io.legado.app.utils.isContentScheme
 import io.legado.app.utils.postEvent
 import io.legado.app.utils.toastOnUi
-import io.legado.app.utils.runOnUI
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers.IO
 
 class BookInfoViewModel(application: Application) : BaseViewModel(application) {
     val bookData = MutableLiveData<Book>()
     val chapterListData = MutableLiveData<List<BookChapter>>()
-    val webFileData = MutableLiveData<List<WebFile>>()
+    val webFiles = mutableListOf<WebFile>()
     var inBookshelf = false
     var bookSource: BookSource? = null
     private var changeSourceCoroutine: Coroutine<*>? = null
-    var callBack: CallBack? = null
+    val waitDialogData = MutableLiveData<Boolean>()
 
     fun initData(intent: Intent) {
         execute {
@@ -241,45 +238,24 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) {
         scope: CoroutineScope = viewModelScope
     ) {
         execute(scope) {
+            webFiles.clear()
             val fileName = "${book.name} 作者:${book.author}"
-            if (book.downloadUrls.isNullOrEmpty()) {
-                val ruleDownloadUrls = bookSource.getBookInfoRule().downloadUrls
-                val content = AnalyzeUrl(book.bookUrl, source = bookSource).getStrResponse().body
-                val analyzeRule = AnalyzeRule(book, bookSource)
-                analyzeRule.setContent(content).setBaseUrl(book.bookUrl)
-                analyzeRule.getStringList(ruleDownloadUrls, isUrl = true)?.let {
-                    parseDownloadUrls(it, fileName)
-                } ?: throw NoStackTraceException("Unexpected ruleDownloadUrls")
-            } else {
-                parseDownloadUrls(book.downloadUrls, fileName)
+            book.downloadUrls!!.map {
+                val mFileName = "${fileName}.${LocalBook.parseFileSuffix(it)}"
+                val isSupportedFile = AppPattern.bookFileRegex.matches(mFileName)
+                WebFile(it, mFileName, isSupportedFile)
             }
         }.onError {
             context.toastOnUi("LoadWebFileError\n${it.localizedMessage}")
         }.onSuccess {
-            webFileData.postValue(it)
-        }
-    }
-
-    private fun parseDownloadUrls(
-        downloadUrls: List<String>?,
-        fileName: String
-    ): List<WebFile>? {
-        val urls = downloadUrls
-        return urls?.map {
-            val mFileName = "${fileName}.${LocalBook.parseFileSuffix(it)}"
-            val isSupportedFile = AppPattern.bookFileRegex.matches(mFileName)
-            WebFile(it, mFileName, isSupportedFile)
+            webFiles.addAll(it)
         }
     }
 
     fun <T> importOrDownloadWebFile(webFile: WebFile, success: ((T) -> Unit)?) {
        bookSource ?: return
        execute {
-           callBack?.run {
-               runOnUI {
-                   onWebFileProcessStart()
-               }
-           }
+           waitDialogData.postValue(true)
            if (webFile.isSupported) {
                val book = LocalBook.importFileOnLine(webFile.url, webFile.name, bookSource)
                changeToLocalBook(book)
@@ -291,12 +267,7 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) {
        }.onError {
            context.toastOnUi("ImportWebFileError\n${it.localizedMessage}")
        }.onFinally {
-           callBack?.run {
-               runOnUI {
-                   onWebFileProcessFinally()
-               }
-           }
-
+           waitDialogData.postValue(false)
        }
     }
 
@@ -433,9 +404,4 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) {
         }
     }
 
-    interface CallBack {
-        fun onWebFileProcessStart()
-        fun onWebFileProcessFinally()
-    }
-
 }

+ 5 - 5
app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt

@@ -34,8 +34,7 @@ import java.net.URLDecoder
 /**
  * rss阅读界面
  */
-class ReadRssActivity : VMBaseActivity<ActivityRssReadBinding, ReadRssViewModel>(false),
-    ReadRssViewModel.CallBack {
+class ReadRssActivity : VMBaseActivity<ActivityRssReadBinding, ReadRssViewModel>(false) {
 
     override val binding by viewBinding(ActivityRssReadBinding::inflate)
     override val viewModel by viewModels<ReadRssViewModel>()
@@ -50,7 +49,8 @@ class ReadRssActivity : VMBaseActivity<ActivityRssReadBinding, ReadRssViewModel>
     }
 
     override fun onActivityCreated(savedInstanceState: Bundle?) {
-        viewModel.callBack = this
+        viewModel.upStarMenuData.observe(this) { upStarMenu() }
+        viewModel.upTtsMenuData.observe(this) { upTtsMenu(it) }
         binding.titleBar.title = intent.getStringExtra("title")
         initWebView()
         initLiveData()
@@ -223,7 +223,7 @@ class ReadRssActivity : VMBaseActivity<ActivityRssReadBinding, ReadRssViewModel>
         }
     }
 
-    override fun upStarMenu() {
+    private fun upStarMenu() {
         starMenuItem?.isVisible = viewModel.rssArticle != null
         if (viewModel.rssStar != null) {
             starMenuItem?.setIcon(R.drawable.ic_star)
@@ -235,7 +235,7 @@ class ReadRssActivity : VMBaseActivity<ActivityRssReadBinding, ReadRssViewModel>
         starMenuItem?.icon?.setTintMutate(primaryTextColor)
     }
 
-    override fun upTtsMenu(isPlaying: Boolean) {
+    private fun upTtsMenu(isPlaying: Boolean) {
         launch {
             if (isPlaying) {
                 ttsMenuItem?.setIcon(R.drawable.ic_stop_black_24dp)

+ 6 - 9
app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt

@@ -27,13 +27,14 @@ import java.util.*
 
 
 class ReadRssViewModel(application: Application) : BaseViewModel(application) {
-    var callBack: CallBack? = null
     var rssSource: RssSource? = null
     var rssArticle: RssArticle? = null
     var tts: TTS? = null
     val contentLiveData = MutableLiveData<String>()
     val urlLiveData = MutableLiveData<AnalyzeUrl>()
     var rssStar: RssStar? = null
+    val upTtsMenuData = MutableLiveData<Boolean>()
+    val upStarMenuData = MutableLiveData<Boolean>()
 
     fun initData(intent: Intent) {
         execute {
@@ -72,7 +73,7 @@ class ReadRssViewModel(application: Application) : BaseViewModel(application) {
                 }
             }
         }.onFinally {
-            callBack?.upStarMenu()
+            upStarMenuData.postValue(true)
         }
     }
 
@@ -126,7 +127,7 @@ class ReadRssViewModel(application: Application) : BaseViewModel(application) {
                 rssStar = it
             }
         }.onSuccess {
-            callBack?.upStarMenu()
+            upStarMenuData.postValue(true)
         }
     }
 
@@ -196,11 +197,11 @@ class ReadRssViewModel(application: Application) : BaseViewModel(application) {
             tts = TTS().apply {
                 setSpeakStateListener(object : TTS.SpeakStateListener {
                     override fun onStart() {
-                        callBack?.upTtsMenu(true)
+                        upTtsMenuData.postValue(true)
                     }
 
                     override fun onDone() {
-                        callBack?.upTtsMenu(false)
+                        upTtsMenuData.postValue(false)
                     }
                 })
             }
@@ -213,8 +214,4 @@ class ReadRssViewModel(application: Application) : BaseViewModel(application) {
         tts?.clearTts()
     }
 
-    interface CallBack {
-        fun upStarMenu()
-        fun upTtsMenu(isPlaying: Boolean)
-    }
 }

+ 2 - 2
app/src/main/java/io/legado/app/utils/CookieManagerExtensions.kt

@@ -11,8 +11,8 @@ fun CookieManager.removeCookie(domain: String) {
         "https://$domain"
     )
     urls.forEach { url ->
-        val cookieGlob = cm.getCookie(url)
-        cookieGlob.splitNotBlank(";").forEach {
+        val cookieGlob: String? = cm.getCookie(url)
+        cookieGlob?.splitNotBlank(";")?.forEach {
             val cookieName = it.substringBefore("=")
             cm.setCookie(url, "$cookieName=; Expires=Wed, 31 Dec 2000 23:59:59 GMT")
         }