diff --git a/.github/scripts/cronet.sh b/.github/scripts/cronet.sh index 95e471f83..2a6b865d2 100644 --- a/.github/scripts/cronet.sh +++ b/.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 \ No newline at end of file diff --git a/.github/workflows/cronet.yml b/.github/workflows/cronet.yml index 341c3afae..3280eb0cc 100644 --- a/.github/workflows/cronet.yml +++ b/.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 - diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f20d04360..8fe406da8 100644 --- a/.github/workflows/test.yml +++ b/.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" diff --git a/app/build.gradle b/app/build.gradle index 38a6294a3..0be48cbec 100644 --- a/app/build.gradle +++ b/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') diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index d775b2ee4..a02240357 100644 --- a/app/proguard-rules.pro +++ b/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 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 7c8235082..1436fb3b0 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -381,12 +381,20 @@ + + + + + + + + diff --git a/app/src/main/java/io/legado/app/help/CrashHandler.kt b/app/src/main/java/io/legado/app/help/CrashHandler.kt index b72d9c944..684bac9d4 100644 --- a/app/src/main/java/io/legado/app/help/CrashHandler.kt +++ b/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 diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt index 525d7d935..0033213be 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt +++ b/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到数据库 diff --git a/app/src/main/java/io/legado/app/model/webBook/BookInfo.kt b/app/src/main/java/io/legado/app/model/webBook/BookInfo.kt index a98c76562..4660928da 100644 --- a/app/src/main/java/io/legado/app/model/webBook/BookInfo.kt +++ b/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 { diff --git a/app/src/main/java/io/legado/app/ui/book/group/GroupSelectDialog.kt b/app/src/main/java/io/legado/app/ui/book/group/GroupSelectDialog.kt index 722856ddb..ebbf1a98c 100644 --- a/app/src/main/java/io/legado/app/ui/book/group/GroupSelectDialog.kt +++ b/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() { diff --git a/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt index e5691959e..8e6a3d188 100644 --- a/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt @@ -52,8 +52,7 @@ class BookInfoActivity : VMBaseActivity(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(it) { _, webFile, _ -> - if (webFile.isSupported) { - /* import */ - viewModel.importOrDownloadWebFile(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(webFile) { uri -> - openFileUri(uri, "*/*") - } + val webFiles = viewModel.webFiles + if (webFiles.isEmpty()) { + toastOnUi("Unexpected webFileData") + return + } + alert(titleResource = R.string.download_and_import_file) { + items(webFiles) { _, webFile, _ -> + if (webFile.isSupported) { + /* import */ + viewModel.importOrDownloadWebFile(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(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() } } diff --git a/app/src/main/java/io/legado/app/ui/book/info/BookInfoViewModel.kt b/app/src/main/java/io/legado/app/ui/book/info/BookInfoViewModel.kt index ba8546c68..633105d7e 100644 --- a/app/src/main/java/io/legado/app/ui/book/info/BookInfoViewModel.kt +++ b/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() val chapterListData = MutableLiveData>() - val webFileData = MutableLiveData>() + val webFiles = mutableListOf() var inBookshelf = false var bookSource: BookSource? = null private var changeSourceCoroutine: Coroutine<*>? = null - var callBack: CallBack? = null + val waitDialogData = MutableLiveData() 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?, - fileName: String - ): List? { - 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 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() - } - } diff --git a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt index 1d409cb1d..75184a3c0 100644 --- a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt @@ -34,8 +34,7 @@ import java.net.URLDecoder /** * rss阅读界面 */ -class ReadRssActivity : VMBaseActivity(false), - ReadRssViewModel.CallBack { +class ReadRssActivity : VMBaseActivity(false) { override val binding by viewBinding(ActivityRssReadBinding::inflate) override val viewModel by viewModels() @@ -50,7 +49,8 @@ class ReadRssActivity : VMBaseActivity } 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 } } - 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 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) diff --git a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt index 193e601fa..274117165 100644 --- a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt +++ b/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() val urlLiveData = MutableLiveData() var rssStar: RssStar? = null + val upTtsMenuData = MutableLiveData() + val upStarMenuData = MutableLiveData() 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) - } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/utils/CookieManagerExtensions.kt b/app/src/main/java/io/legado/app/utils/CookieManagerExtensions.kt index f9d0b9b84..f93e299b8 100644 --- a/app/src/main/java/io/legado/app/utils/CookieManagerExtensions.kt +++ b/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") }