From ac894e49ce5f844d234e08298c8b4b96014a9ee3 Mon Sep 17 00:00:00 2001 From: fengyuecanzhu <1021300691@qq.com> Date: Tue, 2 Aug 2022 10:13:53 +0800 Subject: [PATCH 01/21] fix bug --- dynamic/src/main/java/xyz/fycz/dynamic/fix/App246Fix.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dynamic/src/main/java/xyz/fycz/dynamic/fix/App246Fix.kt b/dynamic/src/main/java/xyz/fycz/dynamic/fix/App246Fix.kt index 67ae22e..77d11f1 100644 --- a/dynamic/src/main/java/xyz/fycz/dynamic/fix/App246Fix.kt +++ b/dynamic/src/main/java/xyz/fycz/dynamic/fix/App246Fix.kt @@ -39,7 +39,7 @@ import xyz.fycz.myreader.util.utils.ScreenUtils * @author fengyue * @date 2022/6/3 15:34 */ -@AppFix([243, 244, 245, 246], ["[设置-缓存设置]新增清除广告文件"], "2022-06-03") +@AppFix([243, 244, 245, 246, 250], ["[设置-缓存设置]新增清除广告文件"], "2022-06-03") class App246Fix : AppFixHandle { override fun onFix(key: String): BooleanArray { From c805ef309c3bd957c496575b669fcbbe5ce5d281 Mon Sep 17 00:00:00 2001 From: fengyuecanzhu <1021300691@qq.com> Date: Tue, 2 Aug 2022 17:54:55 +0800 Subject: [PATCH 02/21] Add back url --- app/src/main/java/xyz/fycz/myreader/common/URLCONST.java | 3 ++- .../main/java/xyz/fycz/myreader/util/utils/OkHttpUtils.java | 4 +++- dynamic/src/main/java/xyz/fycz/dynamic/fix/App246Fix5.kt | 3 ++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/xyz/fycz/myreader/common/URLCONST.java b/app/src/main/java/xyz/fycz/myreader/common/URLCONST.java index bda9661..bc649f3 100644 --- a/app/src/main/java/xyz/fycz/myreader/common/URLCONST.java +++ b/app/src/main/java/xyz/fycz/myreader/common/URLCONST.java @@ -56,7 +56,8 @@ public class URLCONST { public static final String QUOTATION = "https://v1.hitokoto.cn/?encode=json&charset=utf-8"; - public static final String DEFAULT_PLUGIN_CONFIG_URL = "https://gitlab.com/fengyuecanzhu/fyreader-resource/-/raw/main/Plugin/release/config_FYReader.json"; + //public static final String DEFAULT_PLUGIN_CONFIG_URL = "https://gitlab.com/fengyuecanzhu/fyreader-resource/-/raw/main/Plugin/release/config_FYReader.json"; + public static final String DEFAULT_PLUGIN_CONFIG_URL = "http://101.43.83.105:3000/fengyue/FYReader-Res/raw/branch/main/Plugin/release/config_FYReader.json"; public static String getDefaultDomain() { return SharedPreUtils.getInstance().getString("domain", "fycz.me"); diff --git a/app/src/main/java/xyz/fycz/myreader/util/utils/OkHttpUtils.java b/app/src/main/java/xyz/fycz/myreader/util/utils/OkHttpUtils.java index 982c5c6..e484729 100644 --- a/app/src/main/java/xyz/fycz/myreader/util/utils/OkHttpUtils.java +++ b/app/src/main/java/xyz/fycz/myreader/util/utils/OkHttpUtils.java @@ -214,7 +214,9 @@ public class OkHttpUtils { } public static String getBakUpdateInfo() throws IOException { - return OkHttpUtils.getHtml("https://gitlab.com/fengyuecanzhu/fyreader-resource/-/raw/main/FYReader-Update/" + + return OkHttpUtils.getHtml( + //"https://gitlab.com/fengyuecanzhu/fyreader-resource/-/raw/main/FYReader-Update/" + + "http://101.43.83.105:3000/fengyue/FYReader-Res/raw/branch/main/Plugin/" + (App.isDebug() ? "debug" : "release") + "/content.txt"); } diff --git a/dynamic/src/main/java/xyz/fycz/dynamic/fix/App246Fix5.kt b/dynamic/src/main/java/xyz/fycz/dynamic/fix/App246Fix5.kt index 9d626b5..8c85034 100644 --- a/dynamic/src/main/java/xyz/fycz/dynamic/fix/App246Fix5.kt +++ b/dynamic/src/main/java/xyz/fycz/dynamic/fix/App246Fix5.kt @@ -200,7 +200,8 @@ class App246Fix5 : AppFixHandle { @Throws(IOException::class) fun getBakUpdateInfo(): String { return OkHttpUtils.getHtml( - "https://gitlab.com/fengyuecanzhu/fyreader-resource/-/raw/main/FYReader-Update/" + + //"https://gitlab.com/fengyuecanzhu/fyreader-resource/-/raw/main/FYReader-Update/" + + "http://101.43.83.105:3000/fengyue/FYReader-Res/raw/branch/main/Plugin/" + (if (App.isDebug()) "debug" else "release") + "/content.txt" ) From 2c9a5f1bb318f465559984533ffb160e519d17eb Mon Sep 17 00:00:00 2001 From: fengyuecanzhu <1021300691@qq.com> Date: Wed, 3 Aug 2022 13:04:38 +0800 Subject: [PATCH 03/21] Fix JsExtensions' timeFormat function --- .../model/third3/analyzeRule/JsExtensions.kt | 7 +-- .../main/java/xyz/fycz/dynamic/AppLoadImpl.kt | 1 + .../java/xyz/fycz/dynamic/fix/App250Fix.kt | 54 +++++++++++++++++++ 3 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 dynamic/src/main/java/xyz/fycz/dynamic/fix/App250Fix.kt diff --git a/app/src/main/java/xyz/fycz/myreader/model/third3/analyzeRule/JsExtensions.kt b/app/src/main/java/xyz/fycz/myreader/model/third3/analyzeRule/JsExtensions.kt index 82cda80..4080c7c 100644 --- a/app/src/main/java/xyz/fycz/myreader/model/third3/analyzeRule/JsExtensions.kt +++ b/app/src/main/java/xyz/fycz/myreader/model/third3/analyzeRule/JsExtensions.kt @@ -25,7 +25,6 @@ import androidx.annotation.Keep import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.async import kotlinx.coroutines.runBlocking -import nl.siegmann.epublib.epub.PackageDocumentBase.dateFormat import org.jsoup.Connection import org.jsoup.Jsoup import xyz.fycz.myreader.application.App @@ -141,7 +140,9 @@ interface JsExtensions { BackstageWebView( url = url, html = html, - javaScript = js + javaScript = js, + headerMap = getSource()?.getHeaderMap(true), + tag = getSource()?.getKey() ).getStrResponse().body } } @@ -264,7 +265,7 @@ interface JsExtensions { * 时间格式化 */ fun timeFormat(time: Long): String { - return dateFormat.format(Date(time)) + return SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(Date(time)) } /** diff --git a/dynamic/src/main/java/xyz/fycz/dynamic/AppLoadImpl.kt b/dynamic/src/main/java/xyz/fycz/dynamic/AppLoadImpl.kt index 0fed8d4..33cdecd 100644 --- a/dynamic/src/main/java/xyz/fycz/dynamic/AppLoadImpl.kt +++ b/dynamic/src/main/java/xyz/fycz/dynamic/AppLoadImpl.kt @@ -57,6 +57,7 @@ class AppLoadImpl : IAppLoader { App246Fix3::class.java, App246Fix4::class.java, App246Fix5::class.java, + App250Fix::class.java, ) override fun onLoad(appParam: AppParam) { diff --git a/dynamic/src/main/java/xyz/fycz/dynamic/fix/App250Fix.kt b/dynamic/src/main/java/xyz/fycz/dynamic/fix/App250Fix.kt new file mode 100644 index 0000000..4798612 --- /dev/null +++ b/dynamic/src/main/java/xyz/fycz/dynamic/fix/App250Fix.kt @@ -0,0 +1,54 @@ +/* + * This file is part of FYReader. + * FYReader is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * FYReader is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with FYReader. If not, see . + * + * Copyright (C) 2020 - 2022 fengyuecanzhu + */ + +package xyz.fycz.dynamic.fix + +import me.fycz.maple.MapleBridge +import me.fycz.maple.MapleUtils +import me.fycz.maple.MethodReplacement +import xyz.fycz.myreader.model.third3.analyzeRule.JsExtensions +import java.text.SimpleDateFormat +import java.util.* + +/** + * @author fengyue + * @date 2022/8/3 12:57 + */ +@AppFix([243, 244, 245, 246, 250], ["修复书源时间格式化bug"], "2022-08-03") +class App250Fix : AppFixHandle { + override fun onFix(key: String): BooleanArray { + return handleFix( + key, + "timeFormat" to { fixTimeFormat() }, + ) + } + + fun fixTimeFormat() { + MapleUtils.findAndHookMethod( + JsExtensions::class.java, + "timeFormat", + Long::class.java, + object : MethodReplacement() { + override fun replaceHookedMethod(param: MapleBridge.MethodHookParam): Any { + val time = param.args[0] as Long + return SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(Date(time)) + } + } + ) + } +} \ No newline at end of file From 72cb6bf89cf99814d133da714805340e4271834b Mon Sep 17 00:00:00 2001 From: fengyuecanzhu <1021300691@qq.com> Date: Wed, 3 Aug 2022 13:08:43 +0800 Subject: [PATCH 04/21] Rm dynamic change --- .../main/java/xyz/fycz/dynamic/AppLoadImpl.kt | 1 - .../java/xyz/fycz/dynamic/fix/App250Fix.kt | 54 ------------------- 2 files changed, 55 deletions(-) delete mode 100644 dynamic/src/main/java/xyz/fycz/dynamic/fix/App250Fix.kt diff --git a/dynamic/src/main/java/xyz/fycz/dynamic/AppLoadImpl.kt b/dynamic/src/main/java/xyz/fycz/dynamic/AppLoadImpl.kt index 33cdecd..0fed8d4 100644 --- a/dynamic/src/main/java/xyz/fycz/dynamic/AppLoadImpl.kt +++ b/dynamic/src/main/java/xyz/fycz/dynamic/AppLoadImpl.kt @@ -57,7 +57,6 @@ class AppLoadImpl : IAppLoader { App246Fix3::class.java, App246Fix4::class.java, App246Fix5::class.java, - App250Fix::class.java, ) override fun onLoad(appParam: AppParam) { diff --git a/dynamic/src/main/java/xyz/fycz/dynamic/fix/App250Fix.kt b/dynamic/src/main/java/xyz/fycz/dynamic/fix/App250Fix.kt deleted file mode 100644 index 4798612..0000000 --- a/dynamic/src/main/java/xyz/fycz/dynamic/fix/App250Fix.kt +++ /dev/null @@ -1,54 +0,0 @@ -/* - * This file is part of FYReader. - * FYReader is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * FYReader is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with FYReader. If not, see . - * - * Copyright (C) 2020 - 2022 fengyuecanzhu - */ - -package xyz.fycz.dynamic.fix - -import me.fycz.maple.MapleBridge -import me.fycz.maple.MapleUtils -import me.fycz.maple.MethodReplacement -import xyz.fycz.myreader.model.third3.analyzeRule.JsExtensions -import java.text.SimpleDateFormat -import java.util.* - -/** - * @author fengyue - * @date 2022/8/3 12:57 - */ -@AppFix([243, 244, 245, 246, 250], ["修复书源时间格式化bug"], "2022-08-03") -class App250Fix : AppFixHandle { - override fun onFix(key: String): BooleanArray { - return handleFix( - key, - "timeFormat" to { fixTimeFormat() }, - ) - } - - fun fixTimeFormat() { - MapleUtils.findAndHookMethod( - JsExtensions::class.java, - "timeFormat", - Long::class.java, - object : MethodReplacement() { - override fun replaceHookedMethod(param: MapleBridge.MethodHookParam): Any { - val time = param.args[0] as Long - return SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(Date(time)) - } - } - ) - } -} \ No newline at end of file From 2b2999eff7922dae9604bee3ead1a7515374aee8 Mon Sep 17 00:00:00 2001 From: fengyuecanzhu <1021300691@qq.com> Date: Wed, 3 Aug 2022 13:26:05 +0800 Subject: [PATCH 05/21] Fix JsExtensions' timeFormat function --- app/src/main/java/xyz/fycz/myreader/common/APPCONST.java | 7 ++++++- .../fycz/myreader/model/third3/analyzeRule/JsExtensions.kt | 3 ++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/xyz/fycz/myreader/common/APPCONST.java b/app/src/main/java/xyz/fycz/myreader/common/APPCONST.java index 0250f26..28f3340 100644 --- a/app/src/main/java/xyz/fycz/myreader/common/APPCONST.java +++ b/app/src/main/java/xyz/fycz/myreader/common/APPCONST.java @@ -18,6 +18,7 @@ package xyz.fycz.myreader.common; +import android.annotation.SuppressLint; import android.os.Environment; import android.provider.Settings; @@ -31,13 +32,15 @@ import xyz.fycz.myreader.util.utils.FileUtils; import java.io.File; import java.lang.reflect.Type; +import java.text.DateFormat; +import java.text.SimpleDateFormat; import java.util.Map; import java.util.regex.Pattern; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; - +@SuppressLint("SimpleDateFormat") public class APPCONST { public static String publicKey = "fyds2.0";//服务端公钥 @@ -163,6 +166,8 @@ public class APPCONST { public static final String androidId = getAndroidId(); + public static final DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm"); + public static String getAndroidId() { return Settings.System.getString(App.getmContext().getContentResolver(), Settings.Secure.ANDROID_ID); } diff --git a/app/src/main/java/xyz/fycz/myreader/model/third3/analyzeRule/JsExtensions.kt b/app/src/main/java/xyz/fycz/myreader/model/third3/analyzeRule/JsExtensions.kt index 4080c7c..948c090 100644 --- a/app/src/main/java/xyz/fycz/myreader/model/third3/analyzeRule/JsExtensions.kt +++ b/app/src/main/java/xyz/fycz/myreader/model/third3/analyzeRule/JsExtensions.kt @@ -29,6 +29,7 @@ import org.jsoup.Connection import org.jsoup.Jsoup import xyz.fycz.myreader.application.App import xyz.fycz.myreader.common.APPCONST +import xyz.fycz.myreader.common.APPCONST.dateFormat import xyz.fycz.myreader.greendao.service.CacheManager import xyz.fycz.myreader.greendao.service.CookieStore import xyz.fycz.myreader.model.third3.BaseSource @@ -265,7 +266,7 @@ interface JsExtensions { * 时间格式化 */ fun timeFormat(time: Long): String { - return SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(Date(time)) + return dateFormat.format(Date(time)) } /** From 4d40520e6032417d7fabe2bff362360fd425e4c1 Mon Sep 17 00:00:00 2001 From: fengyuecanzhu <1021300691@qq.com> Date: Wed, 3 Aug 2022 14:39:54 +0800 Subject: [PATCH 06/21] Fix Third3FindCrawler --- .../xyz/fycz/myreader/util/utils/ACache.kt | 2 +- .../crawler/source/find/Third3FindCrawler.kt | 84 +++++++++++++++++++ 2 files changed, 85 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/xyz/fycz/myreader/util/utils/ACache.kt b/app/src/main/java/xyz/fycz/myreader/util/utils/ACache.kt index 58d8835..71ed2ad 100644 --- a/app/src/main/java/xyz/fycz/myreader/util/utils/ACache.kt +++ b/app/src/main/java/xyz/fycz/myreader/util/utils/ACache.kt @@ -52,7 +52,7 @@ class ACache private constructor(cacheDir: File, max_size: Long, max_count: Int) @JvmOverloads fun get( - ctx: Context, + ctx: Context = App.getmContext(), cacheName: String = "ACache", maxSize: Long = MAX_SIZE.toLong(), maxCount: Int = MAX_COUNT, diff --git a/app/src/main/java/xyz/fycz/myreader/webapi/crawler/source/find/Third3FindCrawler.kt b/app/src/main/java/xyz/fycz/myreader/webapi/crawler/source/find/Third3FindCrawler.kt index 3875cc8..83d74de 100644 --- a/app/src/main/java/xyz/fycz/myreader/webapi/crawler/source/find/Third3FindCrawler.kt +++ b/app/src/main/java/xyz/fycz/myreader/webapi/crawler/source/find/Third3FindCrawler.kt @@ -18,11 +18,95 @@ package xyz.fycz.myreader.webapi.crawler.source.find +import io.reactivex.Observable +import xyz.fycz.myreader.application.App +import xyz.fycz.myreader.entity.FindKind +import xyz.fycz.myreader.entity.thirdsource.source3.ExploreKind3 import xyz.fycz.myreader.greendao.entity.rule.BookSource +import xyz.fycz.myreader.util.utils.ACache +import xyz.fycz.myreader.util.utils.GSON +import xyz.fycz.myreader.util.utils.fromJsonArray +import xyz.fycz.myreader.util.utils.isJsonArray /** * @author fengyue * @date 2022/1/20 15:33 */ class Third3FindCrawler(source: BookSource) : ThirdFindCrawler(source) { + override fun initData(): Observable { + return Observable.create { emitter -> + val exploreUrl = source.findRule.url + if (exploreUrl.isNullOrBlank()) { + emitter.onNext(false) + emitter.onComplete() + return@create + } + val kinds = arrayListOf() + var ruleStr = exploreUrl + kotlin.runCatching { + if (exploreUrl.startsWith("", false) + || exploreUrl.startsWith("@js:", false) + ) { + val aCache = ACache.get(cacheName = "explore") + ruleStr = aCache.getAsString(source.sourceUrl) ?: "" + if (ruleStr.isBlank()) { + val jsStr = if (exploreUrl.startsWith("@")) { + exploreUrl.substring(4) + } else { + exploreUrl.substring(4, exploreUrl.lastIndexOf("<")) + } + ruleStr = source.evalJS(jsStr).toString().trim() + aCache.put(source.sourceUrl, ruleStr) + } + } + if (ruleStr.isJsonArray()) { + GSON.fromJsonArray(ruleStr)?.let { + kinds.addAll(it) + } + } else { + ruleStr.split("(&&|\n)+".toRegex()).forEach { kindStr -> + val kindCfg = kindStr.split("::") + kinds.add(ExploreKind3(kindCfg.getOrNull(0) ?: "", kindCfg.getOrNull(1))) + } + } + var children = arrayListOf() + var groupName = name + var nameCount = 0 + kinds.forEach { + if (it.title.isBlank()) { + if (children.size > 0) { + nameCount++ + kindsMap[groupName] = children + children = arrayListOf() + } + groupName = "$name[$nameCount]" + } else if (it.url.isNullOrBlank()) { + if (children.size > 0) { + kindsMap[groupName] = children + children = arrayListOf() + } + groupName = it.title.replace("\\s".toRegex(), "") + } else { + val findKindBean = FindKind().apply { + tag = source.sourceUrl + name = it.title.replace("\\s".toRegex(), "") + url = it.url + } + children.add(findKindBean) + } + } + if (children.size > 0) { + kindsMap[groupName] = children + } + emitter.onNext(true) + }.onFailure { + emitter.onNext(false) + kinds.add(ExploreKind3("ERROR:${it.localizedMessage}", it.stackTraceToString())) + if (App.isDebug()) { + it.printStackTrace() + } + } + emitter.onComplete() + } + } } \ No newline at end of file From 130694fa5536f262601830557c87f76d99bd72f2 Mon Sep 17 00:00:00 2001 From: fengyuecanzhu <1021300691@qq.com> Date: Thu, 11 Aug 2022 16:52:48 +0800 Subject: [PATCH 07/21] =?UTF-8?q?[=E4=B9=A6=E7=B1=8D=E8=AF=A6=E6=83=85?= =?UTF-8?q?=E7=95=8C=E9=9D=A2]=E5=8F=96=E6=B6=88=E4=B9=A6=E7=B1=8D?= =?UTF-8?q?=E7=AE=80=E4=BB=8B=E5=B1=95=E5=BC=80=E6=97=B6=E6=9C=80=E5=A4=A7?= =?UTF-8?q?=E8=A1=8C=E6=95=B0=E9=99=90=E5=88=B6(=E6=97=A0=E6=B3=95?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=E5=AE=8C=E5=85=A8)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/misc.xml | 2 + .../ui/activity/BookDetailedActivity.java | 2 +- .../main/java/xyz/fycz/dynamic/AppLoadImpl.kt | 1 + .../java/xyz/fycz/dynamic/fix/App250Fix.kt | 61 +++++++++++++++++++ 4 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 dynamic/src/main/java/xyz/fycz/dynamic/fix/App250Fix.kt diff --git a/.idea/misc.xml b/.idea/misc.xml index ded8613..9f2d6c6 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -5,6 +5,7 @@ + @@ -18,6 +19,7 @@ + diff --git a/app/src/main/java/xyz/fycz/myreader/ui/activity/BookDetailedActivity.java b/app/src/main/java/xyz/fycz/myreader/ui/activity/BookDetailedActivity.java index 9572509..b62a4fb 100644 --- a/app/src/main/java/xyz/fycz/myreader/ui/activity/BookDetailedActivity.java +++ b/app/src/main/java/xyz/fycz/myreader/ui/activity/BookDetailedActivity.java @@ -361,7 +361,7 @@ public class BookDetailedActivity extends BaseActivity. + * + * Copyright (C) 2020 - 2022 fengyuecanzhu + */ + +package xyz.fycz.dynamic.fix + +import android.widget.TextView +import androidx.viewbinding.ViewBinding +import me.fycz.maple.MapleBridge +import me.fycz.maple.MapleUtils +import me.fycz.maple.MethodReplacement +import xyz.fycz.myreader.ui.activity.BookDetailedActivity + +/** + * @author fengyue + * @date 2022/8/11 16:44 + */ +@AppFix([243, 244, 245, 246, 250], ["[书籍详情界面]取消书籍简介展开时最大行数限制(无法显示完全)"], "2022-08-11") +class App250Fix : AppFixHandle { + override fun onFix(key: String): BooleanArray { + return handleFix( + key, + "showMoreDesc" to { fxShowMoreDesc() }, + ) + } + + fun fxShowMoreDesc() { + MapleUtils.findAndHookMethod( + BookDetailedActivity::class.java, + "showMoreDesc", + object : MethodReplacement() { + override fun replaceHookedMethod(param: MapleBridge.MethodHookParam) { + val binding = + MapleUtils.getObjectField(param.thisObject, "binding") as ViewBinding + val icBinding = MapleUtils.getObjectField(binding, "ic") as ViewBinding + val bookDetailTvDesc = + MapleUtils.getObjectField(icBinding, "bookDetailTvDesc") as TextView + if (bookDetailTvDesc.maxLines == 5) { + bookDetailTvDesc.maxLines = Int.MAX_VALUE + } else { + bookDetailTvDesc.maxLines = 5 + } + } + } + ) + } +} \ No newline at end of file From 4b708a978fd85fe35346f274024e6505047b5e0a Mon Sep 17 00:00:00 2001 From: fengyuecanzhu <1021300691@qq.com> Date: Thu, 11 Aug 2022 16:54:14 +0800 Subject: [PATCH 08/21] Update Maple to 2.0 --- app/build.gradle | 2 +- dynamic/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 4adf40e..d971909 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -293,7 +293,7 @@ dependencies { } //https://github.com/fengyuecanzhu/Maple - implementation("me.fycz.maple:maple:1.9") + implementation("me.fycz.maple:maple:2.0") } greendao { diff --git a/dynamic/build.gradle b/dynamic/build.gradle index 0e68753..587053c 100644 --- a/dynamic/build.gradle +++ b/dynamic/build.gradle @@ -152,7 +152,7 @@ dependencies { compileOnly('org.apache.commons:commons-text:1.9') //https://github.com/fengyuecanzhu/Maple - compileOnly("me.fycz.maple:maple:1.9") + compileOnly("me.fycz.maple:maple:2.0") compileOnly project(":app") compileOnly project(":DialogX") } \ No newline at end of file From 7bd5e1d0c46d90f88f9c2d809406aa10b85aa4c5 Mon Sep 17 00:00:00 2001 From: fengyuecanzhu <1021300691@qq.com> Date: Thu, 11 Aug 2022 17:35:20 +0800 Subject: [PATCH 09/21] Fix plugin load bug --- .../xyz/fycz/myreader/entity/PluginConfig.kt | 2 +- .../fycz/myreader/util/utils/PluginUtils.kt | 28 +++++++++++-------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/xyz/fycz/myreader/entity/PluginConfig.kt b/app/src/main/java/xyz/fycz/myreader/entity/PluginConfig.kt index f6f18c4..2ed1685 100644 --- a/app/src/main/java/xyz/fycz/myreader/entity/PluginConfig.kt +++ b/app/src/main/java/xyz/fycz/myreader/entity/PluginConfig.kt @@ -31,5 +31,5 @@ data class PluginConfig( val changelog: String ) { constructor(name: String, versionCode: Int) : - this(name, versionCode, "", "", "", "") + this(name, versionCode, "", "", "", "插件加载失败,当前为默认插件") } diff --git a/app/src/main/java/xyz/fycz/myreader/util/utils/PluginUtils.kt b/app/src/main/java/xyz/fycz/myreader/util/utils/PluginUtils.kt index ba9e704..e6252ad 100644 --- a/app/src/main/java/xyz/fycz/myreader/util/utils/PluginUtils.kt +++ b/app/src/main/java/xyz/fycz/myreader/util/utils/PluginUtils.kt @@ -58,24 +58,27 @@ object PluginUtils { val oldConfig = GSON.fromJsonObject( SharedPreUtils.getInstance().getString("pluginConfig") ) ?: PluginConfig("dynamic.dex", 100) - launch { loadAppLoader(App.getmContext(), config) } - val configJson = getProxyClient().newCallResponseBody { - url(pluginConfigUrl) - }.text() - config = GSON.fromJsonObject(configJson) - if (config != null) { + try { + val configJson = getProxyClient().newCallResponseBody(5) { + url(pluginConfigUrl) + }.text() + config = GSON.fromJsonObject(configJson) if (config!!.versionCode > oldConfig.versionCode) { downloadPlugin(config!!) - SharedPreUtils.getInstance().putString("pluginConfig", configJson) } - } else { + } catch (e: Exception) { config = oldConfig + e.printStackTrace() + errorMsg = e.stackTraceToString() } - if (config!!.md5.lowercase(Locale.getDefault()) - != getPluginMD5(config!!)?.lowercase(Locale.getDefault()) - ) { - downloadPlugin(config!!) + kotlin.runCatching { + if (config!!.md5.lowercase(Locale.getDefault()) + != getPluginMD5(config!!)?.lowercase(Locale.getDefault()) + ) { + downloadPlugin(config!!) + } } + Log.d(TAG, config!!.toString()) }.onSuccess { loadAppLoader(App.getmContext(), config) } @@ -117,6 +120,7 @@ object PluginUtils { hasLoad = true loadSuccess = true } + SharedPreUtils.getInstance().putString("pluginConfig", GSON.toJson(config)) } catch (e: Exception) { e.printStackTrace() errorMsg = e.stackTraceToString() From ab67ab6f1076e31463545dea3f0b3020678c86a9 Mon Sep 17 00:00:00 2001 From: fengyuecanzhu <1021300691@qq.com> Date: Thu, 11 Aug 2022 17:45:16 +0800 Subject: [PATCH 10/21] Add storage permission check --- .../myreader/ui/fragment/MineFragment.java | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/xyz/fycz/myreader/ui/fragment/MineFragment.java b/app/src/main/java/xyz/fycz/myreader/ui/fragment/MineFragment.java index 88a4f1e..6d59dcd 100644 --- a/app/src/main/java/xyz/fycz/myreader/ui/fragment/MineFragment.java +++ b/app/src/main/java/xyz/fycz/myreader/ui/fragment/MineFragment.java @@ -37,6 +37,7 @@ import androidx.activity.result.contract.ActivityResultContract; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.hjq.permissions.OnPermissionCallback; import com.kongzue.dialogx.dialogs.BottomMenu; import org.jetbrains.annotations.NotNull; @@ -45,6 +46,7 @@ import java.io.File; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; +import java.util.List; import io.reactivex.Single; import io.reactivex.SingleOnSubscribe; @@ -84,6 +86,7 @@ import xyz.fycz.myreader.util.ToastUtils; import xyz.fycz.myreader.util.utils.AdUtils; import xyz.fycz.myreader.util.utils.NetworkUtils; import xyz.fycz.myreader.util.utils.RxUtils; +import xyz.fycz.myreader.util.utils.StoragePermissionUtils; /** * @author fengyue @@ -206,13 +209,15 @@ public class MineFragment extends BaseFragment { protected void initClick() { super.initClick(); binding.mineRlUser.setOnClickListener(v -> { - if (isLogin) { - Intent intent = new Intent(getActivity(), UserInfoActivity.class); - startActivityForResult(intent, APPCONST.REQUEST_LOGOUT); - } else { - Intent intent = new Intent(getActivity(), LoginActivity.class); - getActivity().startActivityForResult(intent, APPCONST.REQUEST_LOGIN); - } + StoragePermissionUtils.request(this, (permissions, all) -> { + if (isLogin) { + Intent intent = new Intent(getActivity(), UserInfoActivity.class); + startActivityForResult(intent, APPCONST.REQUEST_LOGOUT); + } else { + Intent intent = new Intent(getActivity(), LoginActivity.class); + getActivity().startActivityForResult(intent, APPCONST.REQUEST_LOGIN); + } + }); }); binding.mineRlSyn.setOnClickListener(v -> { if (!isLogin) { From a8cf25d6f2fb1c8b6b2261a3cf5a3a655983f8d2 Mon Sep 17 00:00:00 2001 From: fengyuecanzhu <1021300691@qq.com> Date: Thu, 11 Aug 2022 17:45:30 +0800 Subject: [PATCH 11/21] Add storage permission check --- .../myreader/ui/fragment/MineFragment.java | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/xyz/fycz/myreader/ui/fragment/MineFragment.java b/app/src/main/java/xyz/fycz/myreader/ui/fragment/MineFragment.java index 6d59dcd..b0cc145 100644 --- a/app/src/main/java/xyz/fycz/myreader/ui/fragment/MineFragment.java +++ b/app/src/main/java/xyz/fycz/myreader/ui/fragment/MineFragment.java @@ -208,17 +208,15 @@ public class MineFragment extends BaseFragment { @Override protected void initClick() { super.initClick(); - binding.mineRlUser.setOnClickListener(v -> { - StoragePermissionUtils.request(this, (permissions, all) -> { - if (isLogin) { - Intent intent = new Intent(getActivity(), UserInfoActivity.class); - startActivityForResult(intent, APPCONST.REQUEST_LOGOUT); - } else { - Intent intent = new Intent(getActivity(), LoginActivity.class); - getActivity().startActivityForResult(intent, APPCONST.REQUEST_LOGIN); - } - }); - }); + binding.mineRlUser.setOnClickListener(v -> StoragePermissionUtils.request(this, (permissions, all) -> { + if (isLogin) { + Intent intent = new Intent(getActivity(), UserInfoActivity.class); + startActivityForResult(intent, APPCONST.REQUEST_LOGOUT); + } else { + Intent intent = new Intent(getActivity(), LoginActivity.class); + getActivity().startActivityForResult(intent, APPCONST.REQUEST_LOGIN); + } + })); binding.mineRlSyn.setOnClickListener(v -> { if (!isLogin) { ToastUtils.showWarring("请先登录!"); From 2546c4fa5b030eec261f4a852e617d57681db92b Mon Sep 17 00:00:00 2001 From: fengyuecanzhu <1021300691@qq.com> Date: Thu, 11 Aug 2022 22:02:06 +0800 Subject: [PATCH 12/21] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BB=8E=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=BA=93=E4=B8=AD=E8=AF=BB=E5=8F=96=E7=AB=A0=E8=8A=82?= =?UTF-8?q?=E6=97=B6=E9=83=A8=E5=88=86=E6=95=B0=E6=8D=AE=E9=A1=B9=E7=BC=BA?= =?UTF-8?q?=E5=A4=B1=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../greendao/service/ChapterService.java | 11 +++++-- .../java/xyz/fycz/dynamic/fix/App250Fix.kt | 33 ++++++++++++++++++- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/xyz/fycz/myreader/greendao/service/ChapterService.java b/app/src/main/java/xyz/fycz/myreader/greendao/service/ChapterService.java index 20e1bbd..2385020 100644 --- a/app/src/main/java/xyz/fycz/myreader/greendao/service/ChapterService.java +++ b/app/src/main/java/xyz/fycz/myreader/greendao/service/ChapterService.java @@ -66,6 +66,7 @@ public class ChapterService extends BaseService { chapter.setContent(cursor.getString(8)); chapter.setStart(cursor.getInt(9)); chapter.setEnd(cursor.getInt(10)); + chapter.setVariable(cursor.getString(11)); chapters.add(chapter); } } catch (Exception e) { @@ -95,10 +96,14 @@ public class ChapterService extends BaseService { if (StringHelper.isEmpty(bookId)) return new ArrayList<>(); + return DbManager.getDaoSession().getChapterDao() + .queryBuilder() + .where(ChapterDao.Properties.BookId.eq(bookId)) + .orderAsc(ChapterDao.Properties.Number) + .list(); + /*String sql = "select * from chapter where book_id = ? order by number"; - String sql = "select * from chapter where book_id = ? order by number"; - - return findChapters(sql, new String[]{bookId}); + return findChapters(sql, new String[]{bookId});*/ } /** diff --git a/dynamic/src/main/java/xyz/fycz/dynamic/fix/App250Fix.kt b/dynamic/src/main/java/xyz/fycz/dynamic/fix/App250Fix.kt index dfc2efb..924e95c 100644 --- a/dynamic/src/main/java/xyz/fycz/dynamic/fix/App250Fix.kt +++ b/dynamic/src/main/java/xyz/fycz/dynamic/fix/App250Fix.kt @@ -23,18 +23,49 @@ import androidx.viewbinding.ViewBinding import me.fycz.maple.MapleBridge import me.fycz.maple.MapleUtils import me.fycz.maple.MethodReplacement +import xyz.fycz.myreader.greendao.DbManager +import xyz.fycz.myreader.greendao.entity.Chapter +import xyz.fycz.myreader.greendao.gen.ChapterDao +import xyz.fycz.myreader.greendao.service.ChapterService import xyz.fycz.myreader.ui.activity.BookDetailedActivity /** * @author fengyue * @date 2022/8/11 16:44 */ -@AppFix([243, 244, 245, 246, 250], ["[书籍详情界面]取消书籍简介展开时最大行数限制(无法显示完全)"], "2022-08-11") +@AppFix( + [243, 244, 245, 246, 250], + ["[书籍详情界面]取消书籍简介展开时最大行数限制(无法显示完全)", + "修复从数据库中读取章节时部分数据项缺失的bug"], + "2022-08-11" +) class App250Fix : AppFixHandle { override fun onFix(key: String): BooleanArray { return handleFix( key, "showMoreDesc" to { fxShowMoreDesc() }, + "findBookAllChapterByBookId" to { fxFindBookAllChapterByBookId() }, + ) + } + + private fun fxFindBookAllChapterByBookId() { + MapleUtils.findAndHookMethod( + ChapterService::class.java, + "findBookAllChapterByBookId", + String::class.java, + object : MethodReplacement() { + override fun replaceHookedMethod(param: MapleBridge.MethodHookParam): Any { + val bookId = param.args[0] as String? + if (bookId.isNullOrBlank()) { + return emptyList() + } + return DbManager.getDaoSession().chapterDao + .queryBuilder() + .where(ChapterDao.Properties.BookId.eq(bookId)) + .orderAsc(ChapterDao.Properties.Number) + .list() + } + } ) } From b45f95ce13b2938f80162920e2f8b899ec88c4f9 Mon Sep 17 00:00:00 2001 From: fengyuecanzhu <1021300691@qq.com> Date: Fri, 12 Aug 2022 09:06:56 +0800 Subject: [PATCH 13/21] =?UTF-8?q?=E7=9B=AE=E5=BD=95=E5=88=97=E8=A1=A8?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=9B=B4=E6=96=B0=E6=97=B6=E9=97=B4=E6=98=BE?= =?UTF-8?q?=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/assetWizardSettings.xml | 32 ++++++++ .idea/misc.xml | 8 ++ .../myreader/ui/adapter/BookMarkAdapter.java | 10 --- .../ui/adapter/ChapterTitleAdapter.java | 27 +++++-- .../ui/adapter/holder/CatalogHolder.java | 7 +- .../ui/adapter/holder/FindBookHolder.java | 9 ++- .../ui/presenter/BookMarkPresenter.java | 3 +- .../ui/presenter/CatalogPresenter.java | 3 +- .../main/res/drawable/ic_cloud_download.xml | 33 ++++++++ app/src/main/res/layout/item_chapter.xml | 79 +++++++++++++++++++ .../res/layout/layout_book_detail_content.xml | 9 ++- .../layout/listview_chapter_title_item.xml | 46 ----------- 12 files changed, 186 insertions(+), 80 deletions(-) create mode 100644 .idea/assetWizardSettings.xml create mode 100644 app/src/main/res/drawable/ic_cloud_download.xml create mode 100644 app/src/main/res/layout/item_chapter.xml delete mode 100644 app/src/main/res/layout/listview_chapter_title_item.xml diff --git a/.idea/assetWizardSettings.xml b/.idea/assetWizardSettings.xml new file mode 100644 index 0000000..5367e8e --- /dev/null +++ b/.idea/assetWizardSettings.xml @@ -0,0 +1,32 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index 9f2d6c6..0ee8e03 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -3,6 +3,10 @@ diff --git a/app/src/main/java/xyz/fycz/myreader/ui/adapter/BookMarkAdapter.java b/app/src/main/java/xyz/fycz/myreader/ui/adapter/BookMarkAdapter.java index dad8fa8..5d567ca 100644 --- a/app/src/main/java/xyz/fycz/myreader/ui/adapter/BookMarkAdapter.java +++ b/app/src/main/java/xyz/fycz/myreader/ui/adapter/BookMarkAdapter.java @@ -67,7 +67,6 @@ public class BookMarkAdapter extends ArrayAdapter { viewHolder = new ViewHolder(); convertView = LayoutInflater.from(getContext()).inflate(mResourceId,null); viewHolder.tvTitle = (TextView) convertView.findViewById(R.id.tv_chapter_title); - viewHolder.vLine = (View) convertView.findViewById(R.id.v_line); convertView.setTag(viewHolder); }else { viewHolder = (ViewHolder) convertView.getTag(); @@ -78,14 +77,7 @@ public class BookMarkAdapter extends ArrayAdapter { private void initView(int postion,final ViewHolder viewHolder){ final BookMark bookMark = getItem(postion); - assert bookMark != null; viewHolder.tvTitle.setText(String.format("%s[%s]", bookMark.getTitle(), bookMark.getBookMarkReadPosition() + 1)); - if (ChapterService.isChapterCached(bookMark)){ - viewHolder.tvTitle.setCompoundDrawablesWithIntrinsicBounds(ContextCompat.getDrawable(getContext(), R.drawable.selector_category_load),null,null,null); - } else { - viewHolder.tvTitle.setCompoundDrawablesWithIntrinsicBounds(ContextCompat.getDrawable(getContext(),R.drawable.selector_category_unload),null,null,null); - } - viewHolder.tvTitle.setTextColor(getContext().getResources().getColor(R.color.textSecondary)); /*if (!setting.isDayStyle()) { viewHolder.tvTitle.setTextColor(getContext().getResources().getColor(R.color.sys_night_word)); viewHolder.vLine.setBackground(getContext().getDrawable(R.color.sys_dialog_setting_line)); @@ -134,9 +126,7 @@ public class BookMarkAdapter extends ArrayAdapter { } class ViewHolder{ - TextView tvTitle; - View vLine; } } diff --git a/app/src/main/java/xyz/fycz/myreader/ui/adapter/ChapterTitleAdapter.java b/app/src/main/java/xyz/fycz/myreader/ui/adapter/ChapterTitleAdapter.java index 8e115b3..40cfa40 100644 --- a/app/src/main/java/xyz/fycz/myreader/ui/adapter/ChapterTitleAdapter.java +++ b/app/src/main/java/xyz/fycz/myreader/ui/adapter/ChapterTitleAdapter.java @@ -19,12 +19,15 @@ package xyz.fycz.myreader.ui.adapter; import android.content.Context; +import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.Filter; +import android.widget.ImageView; import android.widget.TextView; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.core.content.ContextCompat; @@ -37,7 +40,6 @@ import xyz.fycz.myreader.greendao.entity.Chapter; import xyz.fycz.myreader.greendao.service.ChapterService; import java.util.ArrayList; -import java.util.Collections; import java.util.List; @@ -73,7 +75,8 @@ public class ChapterTitleAdapter extends ArrayAdapter { viewHolder = new ViewHolder(); convertView = LayoutInflater.from(getContext()).inflate(mResourceId, null); viewHolder.tvTitle = (TextView) convertView.findViewById(R.id.tv_chapter_title); - viewHolder.vLine = (View) convertView.findViewById(R.id.v_line); + viewHolder.tvTag = (TextView) convertView.findViewById(R.id.tv_tag); + viewHolder.ivIcon = (ImageView) convertView.findViewById(R.id.iv_icon); convertView.setTag(viewHolder); } else { viewHolder = (ViewHolder) convertView.getTag(); @@ -86,21 +89,30 @@ public class ChapterTitleAdapter extends ArrayAdapter { final Chapter chapter = getItem(postion); // viewHolder.tvTitle.setText("【" + chapter.getTitle() + "】"); viewHolder.tvTitle.setText(chapter.getTitle()); + //viewHolder.ivIcon.setImageResource(R.drawable.ic_cloud_download); if (ChapterService.isChapterCached(chapter) || chapter.getEnd() > 0) { - viewHolder.tvTitle.setCompoundDrawablesWithIntrinsicBounds(ContextCompat.getDrawable(getContext(),R.drawable.selector_category_load), null, null, null); + viewHolder.ivIcon.setVisibility(View.GONE); + viewHolder.tvTitle.setTextColor(getContext().getResources().getColor(R.color.textPrimary)); } else { - viewHolder.tvTitle.setCompoundDrawablesWithIntrinsicBounds(ContextCompat.getDrawable(getContext(),R.drawable.selector_category_unload), null, null, null); + viewHolder.ivIcon.setVisibility(View.VISIBLE); + viewHolder.tvTitle.setTextColor(getContext().getResources().getColor(R.color.textSecondary)); } - viewHolder.tvTitle.setTextColor(getContext().getResources().getColor(R.color.textSecondary)); /*if (!setting.isDayStyle()) { viewHolder.tvTitle.setTextColor(getContext().getResources().getColor(R.color.sys_night_word)); viewHolder.vLine.setBackground(getContext().getDrawable(R.color.sys_dialog_setting_line)); }else { viewHolder.tvTitle.setTextColor(getContext().getColor(R.color.title_black)); }*/ - + if (TextUtils.isEmpty(chapter.getUpdateTime())) { + viewHolder.tvTag.setVisibility(View.GONE); + } else { + viewHolder.tvTag.setText(chapter.getUpdateTime()); + viewHolder.tvTag.setVisibility(View.VISIBLE); + } if (chapter.getNumber() == mBook.getHisttoryChapterNum()) { viewHolder.tvTitle.setTextColor(getContext().getResources().getColor(R.color.colorAccent)); + /*viewHolder.ivIcon.setImageResource(R.drawable.ic_check); + viewHolder.ivIcon.setVisibility(View.VISIBLE);*/ } } @@ -152,7 +164,8 @@ public class ChapterTitleAdapter extends ArrayAdapter { class ViewHolder { TextView tvTitle; - View vLine; + TextView tvTag; + ImageView ivIcon; } diff --git a/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/CatalogHolder.java b/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/CatalogHolder.java index d73b67d..23156c0 100644 --- a/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/CatalogHolder.java +++ b/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/CatalogHolder.java @@ -36,7 +36,7 @@ public class CatalogHolder extends ViewHolderImpl { private TextView tvTitle; @Override protected int getItemLayoutId() { - return R.layout.listview_chapter_title_item; + return R.layout.item_chapter; } @Override @@ -46,11 +46,6 @@ public class CatalogHolder extends ViewHolderImpl { @Override public void onBind(RecyclerView.ViewHolder holder, Chapter data, int pos) { - if (ChapterService.isChapterCached(data) || data.getEnd() > 0) { - tvTitle.setCompoundDrawablesWithIntrinsicBounds(ContextCompat.getDrawable(getContext(),R.drawable.selector_category_load), null, null, null); - } else { - tvTitle.setCompoundDrawablesWithIntrinsicBounds(ContextCompat.getDrawable(getContext(),R.drawable.selector_category_unload), null, null, null); - } tvTitle.setText(data.getTitle()); } } diff --git a/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/FindBookHolder.java b/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/FindBookHolder.java index 56c3783..35f5584 100644 --- a/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/FindBookHolder.java +++ b/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/FindBookHolder.java @@ -49,6 +49,7 @@ import xyz.fycz.myreader.webapi.BookApi; import xyz.fycz.myreader.webapi.crawler.ReadCrawlerUtil; import xyz.fycz.myreader.webapi.crawler.base.BookInfoCrawler; import xyz.fycz.myreader.webapi.crawler.base.ReadCrawler; +import xyz.fycz.myreader.webapi.crawler.source.ThirdCrawler; import xyz.fycz.myreader.widget.CoverImageView; /** @@ -96,7 +97,7 @@ public class FindBookHolder extends ViewHolderImpl { tvBookName.setText(data.getName()); if (!StringHelper.isEmpty(data.getAuthor())) { tvAuthor.setText(data.getAuthor()); - }else { + } else { tvAuthor.setText(""); } initTagList(data); @@ -114,7 +115,7 @@ public class FindBookHolder extends ViewHolderImpl { } if (!StringHelper.isEmpty(source.getSourceName()) && !"未知书源".equals(source.getSourceName())) tvSource.setText(String.format("书源:%s", source.getSourceName())); - if (needGetInfo(data) && rc instanceof BookInfoCrawler) { + if (!(rc instanceof ThirdCrawler) && rc instanceof BookInfoCrawler && needGetInfo(data)) { Log.i(data.getName(), "initOtherInfo"); BookInfoCrawler bic = (BookInfoCrawler) rc; BookApi.getBookInfo(data, bic).compose(RxUtils::toSimpleSingle) @@ -163,6 +164,7 @@ public class FindBookHolder extends ViewHolderImpl { tflBookTag.setAdapter(new BookTagAdapter(getContext(), tagList, 11)); } } + private boolean needGetInfo(Book bookBean) { if (StringHelper.isEmpty(bookBean.getAuthor())) return true; if (StringHelper.isEmpty(bookBean.getType())) return true; @@ -170,10 +172,11 @@ public class FindBookHolder extends ViewHolderImpl { if (StringHelper.isEmpty(bookBean.getNewestChapterTitle())) return true; return StringHelper.isEmpty(bookBean.getImgUrl()); } + /** * Here is the key method to apply the animation */ - protected void setAnimation(View viewToAnimate, int position){ + protected void setAnimation(View viewToAnimate, int position) { // If the bound view wasn't previously displayed on screen, it's animated Animation animation = AnimationUtils.loadAnimation(viewToAnimate.getContext(), R.anim.anim_recycle_item); diff --git a/app/src/main/java/xyz/fycz/myreader/ui/presenter/BookMarkPresenter.java b/app/src/main/java/xyz/fycz/myreader/ui/presenter/BookMarkPresenter.java index b3ad661..ed396bc 100644 --- a/app/src/main/java/xyz/fycz/myreader/ui/presenter/BookMarkPresenter.java +++ b/app/src/main/java/xyz/fycz/myreader/ui/presenter/BookMarkPresenter.java @@ -21,7 +21,6 @@ package xyz.fycz.myreader.ui.presenter; import android.app.Activity; import android.content.Intent; import xyz.fycz.myreader.R; -import xyz.fycz.myreader.application.SysManager; import xyz.fycz.myreader.base.BasePresenter; import xyz.fycz.myreader.common.APPCONST; import xyz.fycz.myreader.greendao.entity.Book; @@ -74,7 +73,7 @@ public class BookMarkPresenter implements BasePresenter { private void initBookMarkList() { mBookMarks = (ArrayList) mBookMarkService.findBookAllBookMarkByBookId(mBook.getId()); - mBookMarkAdapter = new BookMarkAdapter(mBookMarkFragment.getActivity(), R.layout.listview_chapter_title_item, mBookMarks); + mBookMarkAdapter = new BookMarkAdapter(mBookMarkFragment.getActivity(), R.layout.item_chapter, mBookMarks); mBookMarkFragment.getLvBookmarkList().setAdapter(mBookMarkAdapter); } diff --git a/app/src/main/java/xyz/fycz/myreader/ui/presenter/CatalogPresenter.java b/app/src/main/java/xyz/fycz/myreader/ui/presenter/CatalogPresenter.java index 07fcba4..ba3123e 100644 --- a/app/src/main/java/xyz/fycz/myreader/ui/presenter/CatalogPresenter.java +++ b/app/src/main/java/xyz/fycz/myreader/ui/presenter/CatalogPresenter.java @@ -24,7 +24,6 @@ import android.view.View; import org.jetbrains.annotations.NotNull; -import io.reactivex.disposables.Disposable; import xyz.fycz.myreader.R; import xyz.fycz.myreader.application.App; import xyz.fycz.myreader.base.BasePresenter; @@ -137,7 +136,7 @@ public class CatalogPresenter implements BasePresenter { //设置布局管理器 int curChapterPosition; curChapterPosition = mBook.getHisttoryChapterNum(); - mChapterTitleAdapter = new ChapterTitleAdapter(mCatalogFragment.getContext(), R.layout.listview_chapter_title_item, mChapters, mBook); + mChapterTitleAdapter = new ChapterTitleAdapter(mCatalogFragment.getContext(), R.layout.item_chapter, mChapters, mBook); mCatalogFragment.getLvChapterList().setAdapter(mChapterTitleAdapter); mCatalogFragment.getLvChapterList().setSelection(curChapterPosition); } diff --git a/app/src/main/res/drawable/ic_cloud_download.xml b/app/src/main/res/drawable/ic_cloud_download.xml new file mode 100644 index 0000000..ffd5f56 --- /dev/null +++ b/app/src/main/res/drawable/ic_cloud_download.xml @@ -0,0 +1,33 @@ + + + + + + + diff --git a/app/src/main/res/layout/item_chapter.xml b/app/src/main/res/layout/item_chapter.xml new file mode 100644 index 0000000..454eb29 --- /dev/null +++ b/app/src/main/res/layout/item_chapter.xml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/layout_book_detail_content.xml b/app/src/main/res/layout/layout_book_detail_content.xml index a1d9970..364323c 100644 --- a/app/src/main/res/layout/layout_book_detail_content.xml +++ b/app/src/main/res/layout/layout_book_detail_content.xml @@ -64,7 +64,7 @@ android:id="@+id/book_detail_tv_catalog" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:padding="15dp" + android:padding="12dp" android:text="最新章节" android:textColor="@color/textPrimary" android:textSize="15sp" /> @@ -73,8 +73,8 @@ android:id="@+id/book_detail_tv_catalog_more" android:layout_width="match_parent" android:layout_height="wrap_content" - android:gravity="right" - android:padding="15dp" + android:gravity="end" + android:padding="12dp" android:text="更多" android:textColor="@color/textSecondary" android:textSize="15sp" /> @@ -84,7 +84,8 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@+id/book_detail_tv_catalog" - android:foregroundGravity="center" /> + android:foregroundGravity="center" + android:paddingHorizontal="4dp" /> - - - - - - - - \ No newline at end of file From f7c47d5783858c3d905cfa7b78feb7e56575c4b7 Mon Sep 17 00:00:00 2001 From: fengyuecanzhu <1021300691@qq.com> Date: Fri, 12 Aug 2022 09:20:13 +0800 Subject: [PATCH 14/21] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=8F=91=E7=8E=B0?= =?UTF-8?q?=E4=B9=A6=E7=B1=8D=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/misc.xml | 1 + .../fycz/myreader/ui/activity/BookDetailedActivity.java | 2 +- .../fycz/myreader/ui/adapter/holder/FindBookHolder.java | 8 ++++++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/.idea/misc.xml b/.idea/misc.xml index 0ee8e03..386286d 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -22,6 +22,7 @@ + diff --git a/app/src/main/java/xyz/fycz/myreader/ui/activity/BookDetailedActivity.java b/app/src/main/java/xyz/fycz/myreader/ui/activity/BookDetailedActivity.java index b62a4fb..eaf53fd 100644 --- a/app/src/main/java/xyz/fycz/myreader/ui/activity/BookDetailedActivity.java +++ b/app/src/main/java/xyz/fycz/myreader/ui/activity/BookDetailedActivity.java @@ -426,7 +426,7 @@ public class BookDetailedActivity extends BaseActivity() { diff --git a/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/FindBookHolder.java b/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/FindBookHolder.java index 35f5584..11a4cf8 100644 --- a/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/FindBookHolder.java +++ b/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/FindBookHolder.java @@ -106,12 +106,14 @@ public class FindBookHolder extends ViewHolderImpl { } else { data.setNewestChapterTitle(""); tvNewestChapter.setText(""); + tvNewestChapter.setVisibility(View.GONE); } if (!StringHelper.isEmpty(data.getDesc())) { tvDesc.setText(String.format("简介:%s", data.getDesc())); } else { data.setDesc(""); tvDesc.setText(""); + tvDesc.setVisibility(View.GONE); } if (!StringHelper.isEmpty(source.getSourceName()) && !"未知书源".equals(source.getSourceName())) tvSource.setText(String.format("书源:%s", source.getSourceName())); @@ -132,10 +134,16 @@ public class FindBookHolder extends ViewHolderImpl { private void initOtherInfo(Book book, ReadCrawler rc) { //简介 if (StringHelper.isEmpty(tvDesc.getText().toString())) { + tvNewestChapter.setVisibility(View.VISIBLE); tvDesc.setText(String.format("简介:%s", book.getDesc())); + } else { + tvNewestChapter.setVisibility(View.GONE); } if (StringHelper.isEmpty(tvNewestChapter.getText().toString())) { + tvNewestChapter.setVisibility(View.VISIBLE); tvNewestChapter.setText(getContext().getString(R.string.newest_chapter, book.getNewestChapterTitle())); + } else { + tvNewestChapter.setVisibility(View.GONE); } if (!StringHelper.isEmpty(book.getAuthor())) { tvAuthor.setText(book.getAuthor()); From cb19cf19f3329a09b834c690abfc3a847a765da5 Mon Sep 17 00:00:00 2001 From: fengyuecanzhu <1021300691@qq.com> Date: Fri, 12 Aug 2022 09:32:27 +0800 Subject: [PATCH 15/21] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=8F=91=E7=8E=B0?= =?UTF-8?q?=E4=B9=A6=E7=B1=8D=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/misc.xml | 1 + .../xyz/fycz/myreader/ui/activity/BookDetailedActivity.java | 2 +- .../xyz/fycz/myreader/ui/adapter/holder/FindBookHolder.java | 6 ++++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.idea/misc.xml b/.idea/misc.xml index 386286d..1b55d4c 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -3,6 +3,7 @@ diff --git a/app/build.gradle b/app/build.gradle index d971909..f7282fc 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -294,6 +294,10 @@ dependencies { //https://github.com/fengyuecanzhu/Maple implementation("me.fycz.maple:maple:2.0") + + //加解密类库,有些书源使用 + //noinspection GradleDependency,GradlePackageUpdate + implementation('cn.hutool:hutool-crypto:5.8.10') } greendao { diff --git a/app/src/main/java/xyz/fycz/myreader/greendao/service/CacheManager.kt b/app/src/main/java/xyz/fycz/myreader/greendao/service/CacheManager.kt index 5b0fa0d..0219964 100644 --- a/app/src/main/java/xyz/fycz/myreader/greendao/service/CacheManager.kt +++ b/app/src/main/java/xyz/fycz/myreader/greendao/service/CacheManager.kt @@ -19,6 +19,7 @@ package xyz.fycz.myreader.greendao.service import android.database.Cursor +import androidx.collection.LruCache import xyz.fycz.myreader.application.App import xyz.fycz.myreader.greendao.DbManager import xyz.fycz.myreader.greendao.entity.Cache @@ -31,6 +32,7 @@ import java.lang.Exception object CacheManager { private val queryTTFMap = hashMapOf>() + private val memoryLruCache = object : LruCache(100) {} /** * saveTime 单位为秒 @@ -49,6 +51,19 @@ object CacheManager { } } + fun putMemory(key: String, value: String) { + memoryLruCache.put(key, value) + } + + //从内存中获取数据 使用lruCache + fun getFromMemory(key: String): String? { + return memoryLruCache.get(key) + } + + fun deleteMemory(key: String) { + memoryLruCache.remove(key) + } + fun get(key: String): String? { var str: String? = null try { @@ -94,6 +109,14 @@ object CacheManager { return null } + fun putFile(key: String, value: String, saveTime: Int = 0) { + ACache.get().put(key, value, saveTime) + } + + fun getFile(key: String): String? { + return ACache.get().getAsString(key) + } + fun delete(key: String) { DbManager.getDaoSession().cacheDao.deleteByKey(key) ACache.get(App.getmContext()).remove(key) diff --git a/app/src/main/java/xyz/fycz/myreader/model/third3/analyzeRule/JsEncodeUtils.kt b/app/src/main/java/xyz/fycz/myreader/model/third3/analyzeRule/JsEncodeUtils.kt new file mode 100644 index 0000000..8d804aa --- /dev/null +++ b/app/src/main/java/xyz/fycz/myreader/model/third3/analyzeRule/JsEncodeUtils.kt @@ -0,0 +1,496 @@ +/* + * This file is part of FYReader. + * FYReader is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * FYReader is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with FYReader. If not, see . + * + * Copyright (C) 2020 - 2022 fengyuecanzhu + */ + +package xyz.fycz.myreader.model.third3.analyzeRule + +import android.util.Base64 +import cn.hutool.crypto.digest.DigestUtil +import cn.hutool.crypto.digest.HMac +import cn.hutool.crypto.symmetric.SymmetricCrypto +import xyz.fycz.myreader.util.utils.MD5Utils + +/** + * js加解密扩展类, 在js中通过java变量调用 + * 添加方法,请更新文档/legado/app/src/main/assets/help/JsHelp.md + */ +interface JsEncodeUtils { + + fun md5Encode(str: String): String { + return MD5Utils.md5Encode(str) + } + + fun md5Encode16(str: String): String { + return MD5Utils.md5Encode16(str) + } + + + //******************对称加密解密************************// + + /** + * 在js中这样使用 + * java.createSymmetricCrypto(transformation, key, iv).decrypt(data) + * java.createSymmetricCrypto(transformation, key, iv).decryptStr(data) + + * java.createSymmetricCrypto(transformation, key, iv).encrypt(data) + * java.createSymmetricCrypto(transformation, key, iv).encryptBase64(data) + * java.createSymmetricCrypto(transformation, key, iv).encryptHex(data) + */ + + /* 调用SymmetricCrypto key为null时使用随机密钥*/ + fun createSymmetricCrypto( + transformation: String, + key: ByteArray?, + iv: ByteArray? + ): SymmetricCrypto { + val symmetricCrypto = SymmetricCrypto(transformation, key) + return if (iv != null && iv.isNotEmpty()) symmetricCrypto.setIv(iv) else symmetricCrypto + } + + fun createSymmetricCrypto( + transformation: String, + key: ByteArray + ): SymmetricCrypto { + return createSymmetricCrypto(transformation, key, null) + } + + fun createSymmetricCrypto( + transformation: String, + key: String + ): SymmetricCrypto { + return createSymmetricCrypto(transformation, key, null) + } + + fun createSymmetricCrypto( + transformation: String, + key: String, + iv: String? + ): SymmetricCrypto { + return createSymmetricCrypto( + transformation, key.encodeToByteArray(), iv?.encodeToByteArray() + ) + } + + //******************对称加密解密old************************// + + /////AES + /** + * AES 解码为 ByteArray + * @param str 传入的AES加密的数据 + * @param key AES 解密的key + * @param transformation AES加密的方式 + * @param iv ECB模式的偏移向量 + */ + @Deprecated( + "过于繁琐弃用", + ReplaceWith("createSymmetricCrypto(transformation, key, iv).decrypt(str)") + ) + fun aesDecodeToByteArray( + str: String, key: String, transformation: String, iv: String + ): ByteArray? { + return createSymmetricCrypto(transformation, key, iv).decrypt(str) + } + + /** + * AES 解码为 String + * @param str 传入的AES加密的数据 + * @param key AES 解密的key + * @param transformation AES加密的方式 + * @param iv ECB模式的偏移向量 + */ + @Deprecated( + "过于繁琐弃用", + ReplaceWith("createSymmetricCrypto(transformation, key, iv).decryptStr(str)") + ) + fun aesDecodeToString( + str: String, key: String, transformation: String, iv: String + ): String? { + return createSymmetricCrypto(transformation, key, iv).decryptStr(str) + } + + /** + * AES解码为String,算法参数经过Base64加密 + * + * @param data 加密的字符串 + * @param key Base64后的密钥 + * @param mode 模式 + * @param padding 补码方式 + * @param iv Base64后的加盐 + * @return 解密后的字符串 + */ + @Deprecated( + "过于繁琐弃用", + ReplaceWith("createSymmetricCrypto(transformation, key, iv).decryptStr(data)") + ) + fun aesDecodeArgsBase64Str( + data: String, + key: String, + mode: String, + padding: String, + iv: String + ): String? { + return createSymmetricCrypto( + "AES/${mode}/${padding}", + Base64.decode(key, Base64.NO_WRAP), + Base64.decode(iv, Base64.NO_WRAP) + ).decryptStr(data) + } + + /** + * 已经base64的AES 解码为 ByteArray + * @param str 传入的AES Base64加密的数据 + * @param key AES 解密的key + * @param transformation AES加密的方式 + * @param iv ECB模式的偏移向量 + */ + @Deprecated( + "过于繁琐弃用", + ReplaceWith("createSymmetricCrypto(transformation, key, iv).decrypt(str)") + ) + fun aesBase64DecodeToByteArray( + str: String, key: String, transformation: String, iv: String + ): ByteArray? { + return createSymmetricCrypto(transformation, key, iv).decrypt(str) + } + + /** + * 已经base64的AES 解码为 String + * @param str 传入的AES Base64加密的数据 + * @param key AES 解密的key + * @param transformation AES加密的方式 + * @param iv ECB模式的偏移向量 + */ + @Deprecated( + "过于繁琐弃用", + ReplaceWith("createSymmetricCrypto(transformation, key, iv).decryptStr(str)") + ) + fun aesBase64DecodeToString( + str: String, key: String, transformation: String, iv: String + ): String? { + return createSymmetricCrypto(transformation, key, iv).decryptStr(str) + } + + /** + * 加密aes为ByteArray + * @param data 传入的原始数据 + * @param key AES加密的key + * @param transformation AES加密的方式 + * @param iv ECB模式的偏移向量 + */ + @Deprecated( + "过于繁琐弃用", + ReplaceWith("createSymmetricCrypto(transformation, key, iv).decrypt(data)") + ) + fun aesEncodeToByteArray( + data: String, key: String, transformation: String, iv: String + ): ByteArray? { + return createSymmetricCrypto(transformation, key, iv).decrypt(data) + } + + /** + * 加密aes为String + * @param data 传入的原始数据 + * @param key AES加密的key + * @param transformation AES加密的方式 + * @param iv ECB模式的偏移向量 + */ + @Deprecated( + "过于繁琐弃用", + ReplaceWith("createSymmetricCrypto(transformation, key, iv).decryptStr(data)") + ) + fun aesEncodeToString( + data: String, key: String, transformation: String, iv: String + ): String? { + return createSymmetricCrypto(transformation, key, iv).decryptStr(data) + } + + /** + * 加密aes后Base64化的ByteArray + * @param data 传入的原始数据 + * @param key AES加密的key + * @param transformation AES加密的方式 + * @param iv ECB模式的偏移向量 + */ + @Deprecated( + "过于繁琐弃用", + ReplaceWith("createSymmetricCrypto(transformation, key, iv).encryptBase64(data).toByteArray()") + ) + fun aesEncodeToBase64ByteArray( + data: String, key: String, transformation: String, iv: String + ): ByteArray? { + return createSymmetricCrypto(transformation, key, iv).encryptBase64(data).toByteArray() + } + + /** + * 加密aes后Base64化的String + * @param data 传入的原始数据 + * @param key AES加密的key + * @param transformation AES加密的方式 + * @param iv ECB模式的偏移向量 + */ + @Deprecated( + "过于繁琐弃用", + ReplaceWith("createSymmetricCrypto(transformation, key, iv).encryptBase64(data)") + ) + fun aesEncodeToBase64String( + data: String, key: String, transformation: String, iv: String + ): String? { + return createSymmetricCrypto(transformation, key, iv).encryptBase64(data) + } + + + /** + * AES加密并转为Base64,算法参数经过Base64加密 + * + * @param data 被加密的字符串 + * @param key Base64后的密钥 + * @param mode 模式 + * @param padding 补码方式 + * @param iv Base64后的加盐 + * @return 加密后的Base64 + */ + @Deprecated( + "过于繁琐弃用", + ReplaceWith("createSymmetricCrypto(transformation, key, iv).encryptBase64(data)") + ) + fun aesEncodeArgsBase64Str( + data: String, + key: String, + mode: String, + padding: String, + iv: String + ): String? { + return createSymmetricCrypto("AES/${mode}/${padding}", key, iv).encryptBase64(data) + } + + /////DES + @Deprecated( + "过于繁琐弃用", + ReplaceWith("createSymmetricCrypto(transformation, key, iv).decryptStr(data)") + ) + fun desDecodeToString( + data: String, key: String, transformation: String, iv: String + ): String? { + return createSymmetricCrypto(transformation, key, iv).decryptStr(data) + } + + @Deprecated( + "过于繁琐弃用", + ReplaceWith("createSymmetricCrypto(transformation, key, iv).decryptStr(data)") + ) + fun desBase64DecodeToString( + data: String, key: String, transformation: String, iv: String + ): String? { + return createSymmetricCrypto(transformation, key, iv).decryptStr(data) + } + + @Deprecated( + "过于繁琐弃用", + ReplaceWith("createSymmetricCrypto(transformation, key, iv).encrypt(data)") + ) + fun desEncodeToString( + data: String, key: String, transformation: String, iv: String + ): String? { + return String(createSymmetricCrypto(transformation, key, iv).encrypt(data)) + } + + @Deprecated( + "过于繁琐弃用", + ReplaceWith("createSymmetricCrypto(transformation, key, iv).encryptBase64(data)") + ) + fun desEncodeToBase64String( + data: String, key: String, transformation: String, iv: String + ): String? { + return createSymmetricCrypto(transformation, key, iv).encryptBase64(data) + } + + //////3DES + /** + * 3DES解密 + * + * @param data 加密的字符串 + * @param key 密钥 + * @param mode 模式 + * @param padding 补码方式 + * @param iv 加盐 + * @return 解密后的字符串 + */ + @Deprecated( + "过于繁琐弃用", + ReplaceWith("createSymmetricCrypto(transformation, key, iv).decryptStr(data)") + ) + fun tripleDESDecodeStr( + data: String, + key: String, + mode: String, + padding: String, + iv: String + ): String? { + return createSymmetricCrypto("DESede/${mode}/${padding}", key, iv).decryptStr(data) + } + + /** + * 3DES解密,算法参数经过Base64加密 + * + * @param data 加密的字符串 + * @param key Base64后的密钥 + * @param mode 模式 + * @param padding 补码方式 + * @param iv Base64后的加盐 + * @return 解密后的字符串 + */ + @Deprecated( + "过于繁琐弃用", + ReplaceWith("createSymmetricCrypto(transformation, key, iv).decryptStr(data)") + ) + fun tripleDESDecodeArgsBase64Str( + data: String, + key: String, + mode: String, + padding: String, + iv: String + ): String? { + return createSymmetricCrypto( + "DESede/${mode}/${padding}", + Base64.decode(key, Base64.NO_WRAP), + iv.encodeToByteArray() + ).decryptStr(data) + } + + + /** + * 3DES加密并转为Base64 + * + * @param data 被加密的字符串 + * @param key 密钥 + * @param mode 模式 + * @param padding 补码方式 + * @param iv 加盐 + * @return 加密后的Base64 + */ + @Deprecated( + "过于繁琐弃用", + ReplaceWith("createSymmetricCrypto(transformation, key, iv).encryptBase64(data)") + ) + fun tripleDESEncodeBase64Str( + data: String, + key: String, + mode: String, + padding: String, + iv: String + ): String? { + return createSymmetricCrypto("DESede/${mode}/${padding}", key, iv) + .encryptBase64(data) + } + + /** + * 3DES加密并转为Base64,算法参数经过Base64加密 + * + * @param data 被加密的字符串 + * @param key Base64后的密钥 + * @param mode 模式 + * @param padding 补码方式 + * @param iv Base64后的加盐 + * @return 加密后的Base64 + */ + @Deprecated( + "过于繁琐弃用", + ReplaceWith("createSymmetricCrypto(transformation, key, iv).encryptBase64(data)") + ) + fun tripleDESEncodeArgsBase64Str( + data: String, + key: String, + mode: String, + padding: String, + iv: String + ): String? { + return createSymmetricCrypto( + "DESede/${mode}/${padding}", + Base64.decode(key, Base64.NO_WRAP), + iv.encodeToByteArray() + ).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) + } + + /** + * 生成散列消息鉴别码,并转为16进制字符串 + * + * @param data 被摘要数据 + * @param algorithm 签名算法 + * @param key 密钥 + * @return 16进制字符串 + */ + @Suppress("FunctionName") + fun HMacHex( + data: String, + algorithm: String, + key: String + ): String { + return HMac(algorithm, key.toByteArray()).digestHex(data) + } + + /** + * 生成散列消息鉴别码,并转为Base64字符串 + * + * @param data 被摘要数据 + * @param algorithm 签名算法 + * @param key 密钥 + * @return Base64字符串 + */ + @Suppress("FunctionName") + fun HMacBase64( + data: String, + algorithm: String, + key: String + ): String { + return Base64.encodeToString( + HMac(algorithm, key.toByteArray()).digest(data), + Base64.NO_WRAP + ) + } + + +} \ No newline at end of file diff --git a/app/src/main/java/xyz/fycz/myreader/model/third3/analyzeRule/JsExtensions.kt b/app/src/main/java/xyz/fycz/myreader/model/third3/analyzeRule/JsExtensions.kt index 948c090..98bd8b9 100644 --- a/app/src/main/java/xyz/fycz/myreader/model/third3/analyzeRule/JsExtensions.kt +++ b/app/src/main/java/xyz/fycz/myreader/model/third3/analyzeRule/JsExtensions.kt @@ -22,6 +22,7 @@ import android.net.Uri import android.util.Base64 import android.util.Log import androidx.annotation.Keep +import cn.hutool.core.util.HexUtil import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.async import kotlinx.coroutines.runBlocking @@ -34,7 +35,9 @@ import xyz.fycz.myreader.greendao.service.CacheManager import xyz.fycz.myreader.greendao.service.CookieStore import xyz.fycz.myreader.model.third3.BaseSource import xyz.fycz.myreader.model.third3.Debug +import xyz.fycz.myreader.model.third3.NoStackTraceException import xyz.fycz.myreader.model.third3.http.* +import xyz.fycz.myreader.util.ToastUtils import xyz.fycz.myreader.util.ZipUtils import xyz.fycz.myreader.util.utils.* import java.io.ByteArrayInputStream @@ -54,7 +57,7 @@ import java.util.zip.ZipInputStream */ @Keep @Suppress("unused") -interface JsExtensions { +interface JsExtensions : JsEncodeUtils { val TAG: String? get() = JsExtensions::class.simpleName @@ -143,11 +146,50 @@ interface JsExtensions { html = html, javaScript = js, headerMap = getSource()?.getHeaderMap(true), - tag = getSource()?.getKey() + tag = getSource()?.getKey() ).getStrResponse().body } } + /** + * 可从网络,本地文件(阅读私有缓存目录和书籍保存位置支持相对路径)导入JavaScript脚本 + */ + fun importScript(path: String): String { + val result = when { + path.startsWith("http") -> cacheFile(path) ?: "" + path.isUri() -> String(DocumentUtil.readBytes(App.getmContext(), Uri.parse(path))) + path.startsWith("/storage") -> FileUtils.readText(path) + else -> readTxtFile(path) + } + if (result.isBlank()) throw NoStackTraceException("$path 内容获取失败或者为空") + return result + } + + /** + * 缓存以文本方式保存的文件 如.js .txt等 + * @param urlStr 网络文件的链接 + * @return 返回缓存后的文件内容 + */ + fun cacheFile(urlStr: String): String? { + return cacheFile(urlStr, 0) + } + + /** + * 缓存以文本方式保存的文件 如.js .txt等 + * @param saveTime 缓存时间,单位:秒 + */ + fun cacheFile(urlStr: String, saveTime: Int): 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 + } + /** * 实现16进制字符串转文件 * @param content 需要转成文件的16进制字符串 @@ -174,20 +216,45 @@ interface JsExtensions { * js实现重定向拦截,网络访问get */ fun get(urlStr: String, headers: Map): Connection.Response { - return Jsoup.connect(urlStr) + val response = Jsoup.connect(urlStr) .sslSocketFactory(SSLHelper.unsafeSSLSocketFactory) .ignoreContentType(true) .followRedirects(false) .headers(headers) .method(Connection.Method.GET) .execute() + val cookies = response.cookies() + CookieStore.mapToCookie(cookies)?.let { + val domain = NetworkUtils.getSubDomain(urlStr) + CacheManager.putMemory("${domain}_cookieJar", it) + } + return response + } + + /** + * js实现重定向拦截,网络访问head,不返回Response Body更省流量 + */ + fun head(urlStr: String, headers: Map): Connection.Response { + val response = Jsoup.connect(urlStr) + .sslSocketFactory(SSLHelper.unsafeSSLSocketFactory) + .ignoreContentType(true) + .followRedirects(false) + .headers(headers) + .method(Connection.Method.HEAD) + .execute() + val cookies = response.cookies() + CookieStore.mapToCookie(cookies)?.let { + val domain = NetworkUtils.getSubDomain(urlStr) + CacheManager.putMemory("${domain}_cookieJar", it) + } + return response } /** * 网络访问post */ fun post(urlStr: String, body: String, headers: Map): Connection.Response { - return Jsoup.connect(urlStr) + val response = Jsoup.connect(urlStr) .sslSocketFactory(SSLHelper.unsafeSSLSocketFactory) .ignoreContentType(true) .followRedirects(false) @@ -195,6 +262,12 @@ interface JsExtensions { .headers(headers) .method(Connection.Method.POST) .execute() + val cookies = response.cookies() + CookieStore.mapToCookie(cookies)?.let { + val domain = NetworkUtils.getSubDomain(urlStr) + CacheManager.putMemory("${domain}_cookieJar", it) + } + return response } /** @@ -243,12 +316,19 @@ interface JsExtensions { return EncoderUtils.base64Encode(str, flags) } - fun md5Encode(str: String): String { - return MD5Utils.md5Encode(str) + /* HexString 解码为字节数组 */ + fun hexDecodeToByteArray(hex: String): ByteArray? { + return HexUtil.decodeHex(hex) + } + + /* hexString 解码为utf8String*/ + fun hexDecodeToString(hex: String): String? { + return HexUtil.decodeHexStr(hex) } - fun md5Encode16(str: String): String { - return MD5Utils.md5Encode16(str) + /* utf8 编码为hexString */ + fun hexEncodeToString(utf8: String): String? { + return HexUtil.encodeHexStr(utf8) } /** @@ -501,174 +581,48 @@ interface JsExtensions { } /** - * 输出调试日志 + * 弹窗提示 */ - fun log(msg: String): String { - getSource()?.let { - Debug.log(it.getKey(), msg) - } ?: Debug.log(msg) - if (App.isDebug()) { - Log.d(TAG + "-" + getSource()?.getKey(), msg) - } - return msg + fun toast(msg: Any?) { + ToastUtils.showInfo("${getSource()?.getTag()}: ${msg.toString()}") } /** - * 生成UUID + * 弹窗提示 停留时间较长 */ - fun randomUUID(): String { - return UUID.randomUUID().toString() + fun longToast(msg: Any?) { + toast(msg) } /** - * AES 解码为 ByteArray - * @param str 传入的AES加密的数据 - * @param key AES 解密的key - * @param transformation AES加密的方式 - * @param iv ECB模式的偏移向量 - */ - fun aesDecodeToByteArray( - str: String, key: String, transformation: String, iv: String - ): ByteArray? { - return try { - EncoderUtils.decryptAES( - data = str.encodeToByteArray(), - key = key.encodeToByteArray(), - transformation, - iv.encodeToByteArray() - ) - } catch (e: Exception) { - Log.e(TAG, e.toString()) - log(e.localizedMessage ?: "aesDecodeToByteArrayERROR") - null - } - } - - /** - * AES 解码为 String - * @param str 传入的AES加密的数据 - * @param key AES 解密的key - * @param transformation AES加密的方式 - * @param iv ECB模式的偏移向量 - */ - - fun aesDecodeToString( - str: String, key: String, transformation: String, iv: String - ): String? { - return aesDecodeToByteArray(str, key, transformation, iv)?.let { String(it) } - } - - /** - * 已经base64的AES 解码为 ByteArray - * @param str 传入的AES Base64加密的数据 - * @param key AES 解密的key - * @param transformation AES加密的方式 - * @param iv ECB模式的偏移向量 - */ - - fun aesBase64DecodeToByteArray( - str: String, key: String, transformation: String, iv: String - ): ByteArray? { - return try { - EncoderUtils.decryptBase64AES( - str.encodeToByteArray(), - key.encodeToByteArray(), - transformation, - iv.encodeToByteArray() - ) - } catch (e: Exception) { - Log.e(TAG, e.toString()) - log(e.localizedMessage ?: "aesDecodeToByteArrayERROR") - null - } - } - - /** - * 已经base64的AES 解码为 String - * @param str 传入的AES Base64加密的数据 - * @param key AES 解密的key - * @param transformation AES加密的方式 - * @param iv ECB模式的偏移向量 - */ - - fun aesBase64DecodeToString( - str: String, key: String, transformation: String, iv: String - ): String? { - return aesBase64DecodeToByteArray(str, key, transformation, iv)?.let { String(it) } - } - - /** - * 加密aes为ByteArray - * @param data 传入的原始数据 - * @param key AES加密的key - * @param transformation AES加密的方式 - * @param iv ECB模式的偏移向量 + * 输出调试日志 */ - fun aesEncodeToByteArray( - data: String, key: String, transformation: String, iv: String - ): ByteArray? { - return try { - EncoderUtils.encryptAES( - data.encodeToByteArray(), - key = key.encodeToByteArray(), - transformation, - iv.encodeToByteArray() - ) - } catch (e: Exception) { - Log.e(TAG, e.toString()) - log(e.localizedMessage ?: "aesEncodeToByteArrayERROR") - null + fun log(msg: String): String { + getSource()?.let { + Debug.log(it.getKey(), msg) + } ?: Debug.log(msg) + if (App.isDebug()) { + Log.d(TAG + "-" + getSource()?.getKey(), msg) } + return msg } /** - * 加密aes为String - * @param data 传入的原始数据 - * @param key AES加密的key - * @param transformation AES加密的方式 - * @param iv ECB模式的偏移向量 - */ - fun aesEncodeToString( - data: String, key: String, transformation: String, iv: String - ): String? { - return aesEncodeToByteArray(data, key, transformation, iv)?.let { String(it) } - } - - /** - * 加密aes后Base64化的ByteArray - * @param data 传入的原始数据 - * @param key AES加密的key - * @param transformation AES加密的方式 - * @param iv ECB模式的偏移向量 + * 输出对象类型 */ - fun aesEncodeToBase64ByteArray( - data: String, key: String, transformation: String, iv: String - ): ByteArray? { - return try { - EncoderUtils.encryptAES2Base64( - data.encodeToByteArray(), - key.encodeToByteArray(), - transformation, - iv.encodeToByteArray() - ) - } catch (e: Exception) { - Log.e(TAG, e.toString()) - log(e.localizedMessage ?: "aesEncodeToBase64ByteArrayERROR") - null + fun logType(any: Any?) { + if (any == null) { + log("null") + } else { + log(any.javaClass.name) } } /** - * 加密aes后Base64化的String - * @param data 传入的原始数据 - * @param key AES加密的key - * @param transformation AES加密的方式 - * @param iv ECB模式的偏移向量 + * 生成UUID */ - fun aesEncodeToBase64String( - data: String, key: String, transformation: String, iv: String - ): String? { - return aesEncodeToBase64ByteArray(data, key, transformation, iv)?.let { String(it) } + fun randomUUID(): String { + return UUID.randomUUID().toString() } fun android(): String { diff --git a/app/src/main/java/xyz/fycz/myreader/util/utils/StringExtensions.kt b/app/src/main/java/xyz/fycz/myreader/util/utils/StringExtensions.kt index 0182804..87d191a 100644 --- a/app/src/main/java/xyz/fycz/myreader/util/utils/StringExtensions.kt +++ b/app/src/main/java/xyz/fycz/myreader/util/utils/StringExtensions.kt @@ -23,6 +23,7 @@ package xyz.fycz.myreader.util.utils import android.icu.text.Collator import android.icu.util.ULocale import android.net.Uri +import android.text.Editable import java.io.File import java.util.* @@ -30,14 +31,19 @@ fun String?.safeTrim() = if (this.isNullOrBlank()) null else this.trim() fun String?.isContentScheme(): Boolean = this?.startsWith("content://") == true +fun String.toEditable(): Editable = Editable.Factory.getInstance().newEditable(this) + fun String.parseToUri(): Uri { - return if (isContentScheme()) { - Uri.parse(this) - } else { + return if (isUri()) Uri.parse(this) else { Uri.fromFile(File(this)) } } +fun String?.isUri(): Boolean { + this ?: return false + return this.startsWith("file://", true) || isContentScheme() +} + fun String?.isAbsUrl() = this?.let { it.startsWith("http://", true) || it.startsWith("https://", true) @@ -65,8 +71,22 @@ fun String?.isJsonArray(): Boolean = str.startsWith("[") && str.endsWith("]") } ?: false -fun String.splitNotBlank(vararg delimiter: String): Array = run { - this.split(*delimiter).map { it.trim() }.filterNot { it.isBlank() }.toTypedArray() +fun String?.isXml(): Boolean = + this?.run { + val str = this.trim() + str.startsWith("<") && str.endsWith(">") + } ?: false + +fun String?.isTrue(nullIsTrue: Boolean = false): Boolean { + if (this.isNullOrBlank() || this == "null") { + return nullIsTrue + } + return !this.trim().matches("(?i)^(false|no|not|0)$".toRegex()) +} + +fun String.splitNotBlank(vararg delimiter: String, limit: Int = 0): Array = run { + this.split(*delimiter, limit = limit).map { it.trim() }.filterNot { it.isBlank() } + .toTypedArray() } fun String.splitNotBlank(regex: Regex, limit: Int = 0): Array = run { @@ -97,3 +117,4 @@ fun String.toStringArray(): Array { } } + From c38bdfd4fe325b784381c72ab718f6930bd53b8e Mon Sep 17 00:00:00 2001 From: fengyuecanzhu <1021300691@qq.com> Date: Wed, 23 Nov 2022 18:35:29 +0800 Subject: [PATCH 19/21] =?UTF-8?q?=E6=9B=B4=E6=96=B0action?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/build.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7c40894..c2d9234 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,10 +10,10 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 # 获取打包秘钥 - name: Checkout Android Keystore - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: repository: fengyuecanzhu/Key token: ${{ secrets.KEY_TOKEN }} # 连接仓库的token,需要单独配置 @@ -27,18 +27,18 @@ jobs: version=$VERSION_CODE versionN=v${version:0:1}.${version:1:1}.${version:2:1} - echo ::set-output name=need_create_release::"$CREATE_RELEASE" - echo ::set-output name=version_name::"$versionN" + echo need_create_release="$CREATE_RELEASE" >> $GITHUB_OUTPUT + echo version_name="$versionN" >> $GITHUB_OUTPUT echo need_create_release=$CREATE_RELEASE echo version_name=$versionN if [ $CREATE_RELEASE == 'true' -a ${{ github.ref }} == 'refs/heads/master' ];then - echo ::set-output name=lanzou_folder_id::"1608604" - echo ::set-output name=lanzou_share_url::"https://fycz.lanzoui.com/b00ngso7e" + echo lanzou_folder_id="1608604" >> $GITHUB_OUTPUT + echo lanzou_share_url="https://fycz.lanzoui.com/b00ngso7e" >> $GITHUB_OUTPUT else - echo ::set-output name=lanzou_folder_id::"2226473" - echo ::set-output name=lanzou_share_url::"https://fycz.lanzoui.com/b00nu1f8d" + echo lanzou_folder_id="2226473" >> $GITHUB_OUTPUT + echo lanzou_share_url="https://fycz.lanzoui.com/b00nu1f8d" >> $GITHUB_OUTPUT fi # 编译打包 - name: Build With Gradle @@ -59,7 +59,7 @@ jobs: if [[ ${{ steps.config.outputs.need_create_release }} != 'true' ]];then path="$GITHUB_WORKSPACE/app/build/outputs/apk/debug" fi - echo ::set-output name=file_path::"$path" + echo file_path="$path" >> $GITHUB_OUTPUT - name: Upload Lanzou run: | echo "上传APP至蓝奏云" From 73bb3011d2a9ea66505903a2ee455c88e1d8ba32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A3=8E=E6=9C=88=E6=AE=8B=E7=83=9B?= <61369261+fengyuecanzhu@users.noreply.github.com> Date: Wed, 23 Nov 2022 18:52:51 +0800 Subject: [PATCH 20/21] =?UTF-8?q?=E6=89=93=E4=B8=AAdebug=E5=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/version_code.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/version_code.properties b/app/version_code.properties index 8a7c6ac..a675b06 100644 --- a/app/version_code.properties +++ b/app/version_code.properties @@ -18,4 +18,4 @@ #Fri Jun 18 21:45:31 CST 2021 VERSION_CODE=250 -CREATE_RELEASE=true +CREATE_RELEASE=false From 513bb03efd1aef380d1c727c69bf4473fd497c13 Mon Sep 17 00:00:00 2001 From: fengyuecanzhu <1021300691@qq.com> Date: Mon, 26 Dec 2022 12:06:54 +0800 Subject: [PATCH 21/21] RELEASE v2.5.1 --- app/release.md | 14 +++++--------- app/src/main/assets/updatelog.fy | 8 ++++++++ app/version_code.properties | 4 ++-- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/app/release.md b/app/release.md index 87aa655..eee13ce 100644 --- a/app/release.md +++ b/app/release.md @@ -1,9 +1,5 @@ -* 1、修复阅读界面概率性闪退的问题 -* 2、关于界面新增插件加载结果 -* 3、修复书源订阅失败的问题 -* 4、修复字体下载失败的问题 -* 5、\[设置-缓存设置\]新增清除广告文件 -* 6、修复检查更新失败的问题 -* 7、修复获取更新链接失败的问题 -* 8、更新订阅书源链接 -* 9、修复其他已知bug \ No newline at end of file +* 1、[书籍详情界面]取消书籍简介展开时最大行数限制 +* 2、修复从数据库中读取章节时部分数据项缺失的bug +* 3、目录列表添加更新时间显示 +* 4、更新部分书源接口 +* 5、修复插件加载bug \ No newline at end of file diff --git a/app/src/main/assets/updatelog.fy b/app/src/main/assets/updatelog.fy index da9e060..eb771b1 100644 --- a/app/src/main/assets/updatelog.fy +++ b/app/src/main/assets/updatelog.fy @@ -1,3 +1,11 @@ +2022.12.26 +风月读书v2.5.1 +1、[书籍详情界面]取消书籍简介展开时最大行数限制 +2、修复从数据库中读取章节时部分数据项缺失的bug +3、目录列表添加更新时间显示 +4、更新部分书源接口 +5、修复插件加载bug + 2022.08.02 风月读书v2.5.0 1、修复阅读界面概率性闪退的问题 diff --git a/app/version_code.properties b/app/version_code.properties index a675b06..7ec427e 100644 --- a/app/version_code.properties +++ b/app/version_code.properties @@ -17,5 +17,5 @@ # #Fri Jun 18 21:45:31 CST 2021 -VERSION_CODE=250 -CREATE_RELEASE=false +VERSION_CODE=251 +CREATE_RELEASE=true