From dae4748674312501e44c1cccdc97a5e8cd6a7a9c Mon Sep 17 00:00:00 2001 From: fengyuecanzhu <1021300691@qq.com> Date: Sun, 16 May 2021 13:54:30 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dbug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/assetWizardSettings.xml | 4 +- app/src/main/assets/updatelog.fy | 6 + .../xyz/fycz/myreader/application/App.java | 3 +- .../myreader/application/CrashHandler.java | 149 ++++++++++++++++ .../xyz/fycz/myreader/base/BaseActivity.java | 1 + .../myreader/base/BitIntentDataManager.java | 50 ++++++ .../xyz/fycz/myreader/common/APPCONST.java | 1 + .../entity/sourceedit/EditEntityUtil.kt | 4 + .../entity/thirdsource/ThirdSourceUtil.java | 6 +- .../fycz/myreader/greendao/entity/Book.java | 64 ++++++- .../greendao/entity/rule/FindRule.java | 14 +- .../greendao/entity/rule/InfoRule.java | 25 ++- .../sourceAnalyzer/BookSourceManager.java | 16 +- .../third2/analyzeRule/AnalyzeByRegex.java | 33 +++- .../model/third2/content/BookInfo.java | 101 +++++++---- .../model/third2/content/BookList.java | 168 ++++++++++-------- .../ui/activity/BookDetailedActivity.java | 51 ++++-- .../ui/activity/BookstoreActivity.java | 3 +- .../myreader/ui/activity/ReadActivity.java | 12 ++ .../ui/activity/SearchBookActivity.java | 3 +- .../ui/activity/SourceDebugActivity.java | 1 + .../ui/adapter/holder/SearchBookHolder.java | 18 +- .../fycz/myreader/util/help/JsExtensions.java | 4 +- .../xyz/fycz/myreader/util/utils/AdUtils.java | 6 +- .../xyz/fycz/myreader/util/utils/MD5Utils.kt | 2 +- .../xyz/fycz/myreader/webapi/BookApi.java | 2 + .../fycz/myreader/webapi/ThirdSourceApi.java | 31 ++-- app/src/main/res/drawable/ic_source.xml | 7 +- app/src/main/res/layout/fragment_mine.xml | 6 +- app/src/main/res/menu/menu_book_detail.xml | 5 + app/src/main/res/menu/menu_read.xml | 6 + app/src/main/res/values/strings.xml | 3 +- app/version_code.properties | 4 +- 33 files changed, 619 insertions(+), 190 deletions(-) create mode 100644 app/src/main/java/xyz/fycz/myreader/application/CrashHandler.java create mode 100644 app/src/main/java/xyz/fycz/myreader/base/BitIntentDataManager.java diff --git a/.idea/assetWizardSettings.xml b/.idea/assetWizardSettings.xml index d748352..c0f43a2 100644 --- a/.idea/assetWizardSettings.xml +++ b/.idea/assetWizardSettings.xml @@ -14,8 +14,8 @@ diff --git a/app/src/main/assets/updatelog.fy b/app/src/main/assets/updatelog.fy index adc871a..2deae15 100644 --- a/app/src/main/assets/updatelog.fy +++ b/app/src/main/assets/updatelog.fy @@ -1,9 +1,15 @@ +2021.05.15 +风月读书v1.9.8-beta +更新内容: +1、修复搜索闪退的bug + 2021.05.15 风月读书v1.9.7-beta 更新内容: 1、优化书源结构 2、书源带cookie请求 3、第三方书源优化,修复bug +4、书源支持登录 2021.05.14 风月读书v1.9.6-beta diff --git a/app/src/main/java/xyz/fycz/myreader/application/App.java b/app/src/main/java/xyz/fycz/myreader/application/App.java index 514b0ae..39ddf12 100644 --- a/app/src/main/java/xyz/fycz/myreader/application/App.java +++ b/app/src/main/java/xyz/fycz/myreader/application/App.java @@ -76,6 +76,7 @@ public class App extends Application { super.onCreate(); application = this; debug = isApkInDebug(this); + CrashHandler.register(this); firstInit(); SSLSocketClient.trustAllHosts();//信任所有证书 RxJavaPlugins.setErrorHandler(Functions.emptyConsumer()); @@ -283,7 +284,7 @@ public class App extends Application { App.getApplication().newThread(() -> { try { String url = "https://shimo.im/docs/cqkgjPRRydYYhQKt/read"; - if (getApplication().debug) { + if (debug) { url = "https://shimo.im/docs/zfzpda7MUGskOC9v/read"; } String html = OkHttpUtils.getHtml(url); diff --git a/app/src/main/java/xyz/fycz/myreader/application/CrashHandler.java b/app/src/main/java/xyz/fycz/myreader/application/CrashHandler.java new file mode 100644 index 0000000..277d1d7 --- /dev/null +++ b/app/src/main/java/xyz/fycz/myreader/application/CrashHandler.java @@ -0,0 +1,149 @@ +package xyz.fycz.myreader.application; + +import android.Manifest; +import android.annotation.SuppressLint; +import android.app.Application; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.os.Build; +import android.util.DisplayMetrics; +import android.util.Log; + +import androidx.annotation.NonNull; + +import org.jetbrains.annotations.NotNull; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.Locale; + +import xyz.fycz.myreader.common.APPCONST; +import xyz.fycz.myreader.ui.activity.SplashActivity; +import xyz.fycz.myreader.util.utils.FileUtils; + +/** + * @author fengyue + * @date 2021/5/16 11:01 + */ +public final class CrashHandler implements Thread.UncaughtExceptionHandler { + + private DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss"); + /** + * 注册 Crash 监听 + */ + public static void register(Application application) { + Thread.setDefaultUncaughtExceptionHandler(new CrashHandler(application)); + } + + private final Application mApplication; + private final Thread.UncaughtExceptionHandler mNextHandler; + + private CrashHandler(Application application) { + mApplication = application; + mNextHandler = Thread.getDefaultUncaughtExceptionHandler(); + if (getClass().getName().equals(mNextHandler.getClass().getName())) { + // 请不要重复注册 Crash 监听 + throw new IllegalStateException("are you ok?"); + } + } + + @SuppressLint("ApplySharedPref") + @Override + public void uncaughtException(@NonNull Thread thread, @NonNull Throwable throwable) { + + saveCrashLog(throwable); + + // 不去触发系统的崩溃处理(com.android.internal.os.RuntimeInit$KillApplicationHandler) + if (mNextHandler != null && !mNextHandler.getClass().getName().startsWith("com.android.internal.os")) { + mNextHandler.uncaughtException(thread, throwable); + } + + // 杀死进程(这个事应该是系统干的,但是它会多弹出一个崩溃对话框,所以需要我们自己手动杀死进程) + android.os.Process.killProcess(android.os.Process.myPid()); + System.exit(10); + } + + private void saveCrashLog(Throwable throwable) { + StringWriter stringWriter = new StringWriter(); + PrintWriter printWriter = new PrintWriter(stringWriter); + throwable.printStackTrace(printWriter); + Throwable cause = throwable.getCause(); + if (cause != null) { + cause.printStackTrace(printWriter); + } + String mStackTrace = stringWriter.toString(); + + Resources res = mApplication.getResources(); + DisplayMetrics displayMetrics = res.getDisplayMetrics(); + int screenWidth = displayMetrics.widthPixels; + int screenHeight = displayMetrics.heightPixels; + + String targetResource; + if (displayMetrics.densityDpi > 480) { + targetResource = "xxxhdpi"; + } else if (displayMetrics.densityDpi > 320) { + targetResource = "xxhdpi"; + } else if (displayMetrics.densityDpi > 240) { + targetResource = "xhdpi"; + } else if (displayMetrics.densityDpi > 160) { + targetResource = "hdpi"; + } else if (displayMetrics.densityDpi > 120) { + targetResource = "mdpi"; + } else { + targetResource = "ldpi"; + } + + StringBuilder builder = new StringBuilder(); + builder.append("设备品牌:\t").append(Build.BRAND) + .append("\n设备型号:\t").append(Build.MODEL) + .append("\n设备类型:\t").append(isTablet() ? "平板" : "手机"); + + builder.append("\n屏幕宽高:\t").append(screenWidth).append(" x ").append(screenHeight) + .append("\n屏幕密度:\t").append(displayMetrics.densityDpi) + .append("\n目标资源:\t").append(targetResource); + + builder.append("\n安卓版本:\t").append(Build.VERSION.RELEASE) + .append("\nAPI 版本:\t").append(Build.VERSION.SDK_INT) + .append("\nCPU 架构:\t").append(Build.SUPPORTED_ABIS[0]); + + builder.append("\n应用版本:\t").append(App.getStrVersionName()) + .append("\n版本代码:\t").append(App.getVersionCode()); + + try { + SimpleDateFormat dateFormat = new SimpleDateFormat("MM-dd HH:mm", Locale.getDefault()); + PackageInfo packageInfo = mApplication.getPackageManager().getPackageInfo(mApplication.getPackageName(), PackageManager.GET_PERMISSIONS); + builder.append("\n首次安装:\t").append(dateFormat.format(new Date(packageInfo.firstInstallTime))) + .append("\n最近安装:\t").append(dateFormat.format(new Date(packageInfo.lastUpdateTime))) + .append("\n崩溃时间:\t").append(dateFormat.format(new Date())); + } catch (PackageManager.NameNotFoundException ignored) { + } + String mPhoneInfo = builder.toString(); + + long timestamp = System.currentTimeMillis(); + String time = formatter.format(new Date()); + String fileName = "crash-" + time + "-" + timestamp + ".log"; + String path = APPCONST.LOG_DIR + fileName; + FileUtils.writeText(mPhoneInfo + "\n\n" + mStackTrace, FileUtils.getFile(path)); + } + + /** + * 判断当前设备是否是平板 + */ + public boolean isTablet() { + return (mApplication.getResources().getConfiguration().screenLayout + & Configuration.SCREENLAYOUT_SIZE_MASK) + >= Configuration.SCREENLAYOUT_SIZE_LARGE; + } +} diff --git a/app/src/main/java/xyz/fycz/myreader/base/BaseActivity.java b/app/src/main/java/xyz/fycz/myreader/base/BaseActivity.java index b97fddb..88876d0 100644 --- a/app/src/main/java/xyz/fycz/myreader/base/BaseActivity.java +++ b/app/src/main/java/xyz/fycz/myreader/base/BaseActivity.java @@ -23,6 +23,7 @@ import me.imid.swipebacklayout.lib.app.SwipeBackActivity; import xyz.fycz.myreader.ActivityManage; import xyz.fycz.myreader.R; import xyz.fycz.myreader.application.App; +import xyz.fycz.myreader.application.CrashHandler; import xyz.fycz.myreader.application.SysManager; import xyz.fycz.myreader.entity.Setting; import xyz.fycz.myreader.util.StatusBarUtil; diff --git a/app/src/main/java/xyz/fycz/myreader/base/BitIntentDataManager.java b/app/src/main/java/xyz/fycz/myreader/base/BitIntentDataManager.java new file mode 100644 index 0000000..3926a28 --- /dev/null +++ b/app/src/main/java/xyz/fycz/myreader/base/BitIntentDataManager.java @@ -0,0 +1,50 @@ +package xyz.fycz.myreader.base; + +import android.content.Intent; + +import java.util.HashMap; +import java.util.Map; + +import xyz.fycz.myreader.common.APPCONST; + +public class BitIntentDataManager { + private static Map bigData; + + private static BitIntentDataManager instance = null; + + private BitIntentDataManager() { + bigData = new HashMap<>(); + } + + public static BitIntentDataManager getInstance() { + if (instance == null) { + synchronized (BitIntentDataManager.class) { + if (instance == null) { + instance = new BitIntentDataManager(); + } + } + } + return instance; + } + + public Object getData(String key) { + Object object = bigData.get(key); + bigData.remove(key); + return object; + } + + public Object getData(Intent intent){ + String dataKey = intent.getStringExtra(APPCONST.DATA_KEY); + return getData(dataKey); + } + + public void putData(String key, Object data) { + bigData.put(key, data); + } + + public void putData(Intent intent, Object data){ + String dataKey = String.valueOf(System.currentTimeMillis()); + intent.putExtra(APPCONST.DATA_KEY, dataKey); + putData(dataKey, data); + } +} 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 6e6b8c8..8392c3b 100644 --- a/app/src/main/java/xyz/fycz/myreader/common/APPCONST.java +++ b/app/src/main/java/xyz/fycz/myreader/common/APPCONST.java @@ -46,6 +46,7 @@ public class APPCONST { public static final String JSON_PATH = "JsonPath"; public static final String THIRD_SOURCE = "ThirdSource"; + public static final String DATA_KEY = "data_key"; public static final String BOOK = "book"; public static final String TITLE = "title"; public static final String FIND_CRAWLER = "findCrawler"; diff --git a/app/src/main/java/xyz/fycz/myreader/entity/sourceedit/EditEntityUtil.kt b/app/src/main/java/xyz/fycz/myreader/entity/sourceedit/EditEntityUtil.kt index 33077a6..11b781a 100644 --- a/app/src/main/java/xyz/fycz/myreader/entity/sourceedit/EditEntityUtil.kt +++ b/app/src/main/java/xyz/fycz/myreader/entity/sourceedit/EditEntityUtil.kt @@ -52,6 +52,8 @@ object EditEntityUtil { fun getInfoEntities(infoRule: InfoRule? = InfoRule()): List { val infoEntities: ArrayList = ArrayList() infoEntities.apply { + add(EditEntity("urlPattern", infoRule?.urlPattern, R.string.book_url_pattern, "")) + add(EditEntity("init", infoRule?.init, R.string.rule_book_info_init)) add(EditEntity("name", infoRule?.name, R.string.r_book_name)) add(EditEntity("author", infoRule?.author, R.string.r_author)) add(EditEntity("type", infoRule?.type, R.string.rule_book_type)) @@ -142,6 +144,8 @@ object EditEntityUtil { val infoRule = InfoRule() infoRuleEntities.forEach { when (it.key) { + "urlPattern" -> infoRule.urlPattern = it.value + "init" -> infoRule.init = it.value "name" -> infoRule.name = it.value "author" -> infoRule.author = it.value "type" -> infoRule.type = it.value diff --git a/app/src/main/java/xyz/fycz/myreader/entity/thirdsource/ThirdSourceUtil.java b/app/src/main/java/xyz/fycz/myreader/entity/thirdsource/ThirdSourceUtil.java index c7f2ad2..26ce800 100644 --- a/app/src/main/java/xyz/fycz/myreader/entity/thirdsource/ThirdSourceUtil.java +++ b/app/src/main/java/xyz/fycz/myreader/entity/thirdsource/ThirdSourceUtil.java @@ -37,11 +37,13 @@ public class ThirdSourceUtil { searchRule.setDesc(bean.getRuleSearchIntroduce()); searchRule.setLastChapter(bean.getRuleSearchLastChapter()); searchRule.setImgUrl(bean.getRuleSearchCoverUrl()); - searchRule.setTocUrl(bean.getRuleSearchNoteUrl()); + searchRule.setInfoUrl(bean.getRuleSearchNoteUrl()); searchRule.setRelatedWithInfo(true); bookSource.setSearchRule(searchRule); InfoRule infoRule = new InfoRule(); + infoRule.setUrlPattern(bean.getRuleBookUrlPattern()); + infoRule.setInit(bean.getRuleBookInfoInit()); infoRule.setName(bean.getRuleBookName()); infoRule.setAuthor(bean.getRuleBookAuthor()); infoRule.setType(bean.getRuleBookKind()); @@ -72,7 +74,7 @@ public class ThirdSourceUtil { findRule.setDesc(bean.getRuleFindIntroduce()); findRule.setLastChapter(bean.getRuleFindLastChapter()); findRule.setImgUrl(bean.getRuleFindCoverUrl()); - findRule.setTocUrl(bean.getRuleFindNoteUrl()); + findRule.setInfoUrl(bean.getRuleFindNoteUrl()); bookSource.setFindRule(findRule); return bookSource; } diff --git a/app/src/main/java/xyz/fycz/myreader/greendao/entity/Book.java b/app/src/main/java/xyz/fycz/myreader/greendao/entity/Book.java index 456f414..2d2a43d 100644 --- a/app/src/main/java/xyz/fycz/myreader/greendao/entity/Book.java +++ b/app/src/main/java/xyz/fycz/myreader/greendao/entity/Book.java @@ -11,6 +11,7 @@ import org.greenrobot.greendao.annotation.Entity; import org.greenrobot.greendao.annotation.Generated; import org.greenrobot.greendao.annotation.Id; import org.greenrobot.greendao.annotation.Transient; + import xyz.fycz.myreader.greendao.service.BookService; import xyz.fycz.myreader.util.SharedPreUtils; import xyz.fycz.myreader.util.StringHelper; @@ -76,17 +77,20 @@ public class Book implements Serializable { @Transient private Map variableMap; + @Transient + private Map catheMap; + @Generated(hash = 1839243756) public Book() { } @Generated(hash = 1910282685) public Book(String id, String name, String chapterUrl, String infoUrl, String imgUrl, String desc, - String author, String type, String updateDate, String wordCount, String status, - String newestChapterId, String newestChapterTitle, String historyChapterId, int histtoryChapterNum, - int sortCode, int noReadNum, int chapterTotalNum, int lastReadPosition, String source, - boolean isCloseUpdate, boolean isDownLoadAll, String groupId, int groupSort, String tag, - Boolean replaceEnable, long lastReadTime, String variable) { + String author, String type, String updateDate, String wordCount, String status, + String newestChapterId, String newestChapterTitle, String historyChapterId, int histtoryChapterNum, + int sortCode, int noReadNum, int chapterTotalNum, int lastReadPosition, String source, + boolean isCloseUpdate, boolean isDownLoadAll, String groupId, int groupSort, String tag, + Boolean replaceEnable, long lastReadTime, String variable) { this.id = id; this.name = name; this.chapterUrl = chapterUrl; @@ -131,96 +135,127 @@ public class Book implements Serializable { public String getId() { return this.id; } + public void setId(String id) { this.id = id; } + public String getName() { return this.name; } + public void setName(String name) { this.name = name; } + public String getChapterUrl() { return this.chapterUrl; } + public void setChapterUrl(String chapterUrl) { this.chapterUrl = chapterUrl; } + public String getImgUrl() { return this.imgUrl; } + public void setImgUrl(String imgUrl) { this.imgUrl = imgUrl; } + public String getDesc() { return this.desc; } + public void setDesc(String desc) { this.desc = desc; } + public String getAuthor() { return this.author; } + public void setAuthor(String author) { this.author = BookService.formatAuthor(author); } + public String getType() { return this.type; } + public void setType(String type) { this.type = type; } + public String getUpdateDate() { return this.updateDate; } + public void setUpdateDate(String updateDate) { this.updateDate = updateDate; } + public String getNewestChapterId() { return this.newestChapterId; } + public void setNewestChapterId(String newestChapterId) { this.newestChapterId = newestChapterId; } + public String getNewestChapterTitle() { return this.newestChapterTitle; } + public void setNewestChapterTitle(String newestChapterTitle) { this.newestChapterTitle = newestChapterTitle; } + public String getHistoryChapterId() { return this.historyChapterId; } + public void setHistoryChapterId(String historyChapterId) { this.historyChapterId = historyChapterId; } + public int getHisttoryChapterNum() { return this.histtoryChapterNum; } + public void setHisttoryChapterNum(int histtoryChapterNum) { this.histtoryChapterNum = histtoryChapterNum; } + public int getSortCode() { return this.sortCode; } + public void setSortCode(int sortCode) { this.sortCode = sortCode; } + public int getNoReadNum() { return this.noReadNum; } + public void setNoReadNum(int noReadNum) { this.noReadNum = noReadNum; } + public int getChapterTotalNum() { return this.chapterTotalNum; } + public void setChapterTotalNum(int chapterTotalNum) { this.chapterTotalNum = chapterTotalNum; } + public int getLastReadPosition() { return this.lastReadPosition; } + public void setLastReadPosition(int lastReadPosition) { this.lastReadPosition = lastReadPosition; } @@ -249,6 +284,7 @@ public class Book implements Serializable { public void setIsDownLoadAll(boolean isDownLoadAll) { this.isDownLoadAll = isDownLoadAll; } + public String getGroupId() { return this.groupId; } @@ -283,9 +319,6 @@ public class Book implements Serializable { } public String getInfoUrl() { - if (StringHelper.isEmpty(infoUrl)){ - return chapterUrl; - } return this.infoUrl; } @@ -342,6 +375,7 @@ public class Book implements Serializable { public void setStatus(String status) { this.status = status; } + public void putVariable(String key, String value) { if (variableMap == null) { variableMap = new HashMap<>(); @@ -366,4 +400,18 @@ public class Book implements Serializable { public void setVariable(String variable) { this.variable = variable; } + + public void putCathe(String key, String value) { + if (catheMap == null) { + catheMap = new HashMap<>(); + } + catheMap.put(key, value); + } + + public String getCathe(String key){ + if (catheMap == null){ + return ""; + } + return catheMap.get(key); + } } diff --git a/app/src/main/java/xyz/fycz/myreader/greendao/entity/rule/FindRule.java b/app/src/main/java/xyz/fycz/myreader/greendao/entity/rule/FindRule.java index a9b21be..6e33326 100644 --- a/app/src/main/java/xyz/fycz/myreader/greendao/entity/rule/FindRule.java +++ b/app/src/main/java/xyz/fycz/myreader/greendao/entity/rule/FindRule.java @@ -26,6 +26,7 @@ public class FindRule implements Parcelable { private String updateTime; private String imgUrl; private String tocUrl; + private String infoUrl; public FindRule() { } @@ -43,6 +44,7 @@ public class FindRule implements Parcelable { updateTime = in.readString(); imgUrl = in.readString(); tocUrl = in.readString(); + infoUrl = in.readString(); } @Override @@ -59,6 +61,7 @@ public class FindRule implements Parcelable { dest.writeString(updateTime); dest.writeString(imgUrl); dest.writeString(tocUrl); + dest.writeString(infoUrl); } @Override @@ -174,6 +177,14 @@ public class FindRule implements Parcelable { this.tocUrl = tocUrl; } + public String getInfoUrl() { + return infoUrl; + } + + public void setInfoUrl(String infoUrl) { + this.infoUrl = infoUrl; + } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -191,7 +202,8 @@ public class FindRule implements Parcelable { stringEquals(lastChapter, findRule.lastChapter) && stringEquals(updateTime, findRule.updateTime) && stringEquals(imgUrl, findRule.imgUrl) && - stringEquals(tocUrl, findRule.tocUrl); + stringEquals(tocUrl, findRule.tocUrl) && + stringEquals(infoUrl, findRule.infoUrl); } } diff --git a/app/src/main/java/xyz/fycz/myreader/greendao/entity/rule/InfoRule.java b/app/src/main/java/xyz/fycz/myreader/greendao/entity/rule/InfoRule.java index 06b7612..b8029c3 100644 --- a/app/src/main/java/xyz/fycz/myreader/greendao/entity/rule/InfoRule.java +++ b/app/src/main/java/xyz/fycz/myreader/greendao/entity/rule/InfoRule.java @@ -16,6 +16,8 @@ import static xyz.fycz.myreader.util.utils.StringUtils.stringEquals; * @date 2021/2/8 17:53 */ public class InfoRule implements Parcelable { + private String urlPattern; + private String init; private String name; private String author; private String type; @@ -31,6 +33,8 @@ public class InfoRule implements Parcelable { } protected InfoRule(Parcel in) { + urlPattern = in.readString(); + init = in.readString(); name = in.readString(); author = in.readString(); type = in.readString(); @@ -45,6 +49,8 @@ public class InfoRule implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { + dest.writeString(urlPattern); + dest.writeString(init); dest.writeString(name); dest.writeString(author); dest.writeString(type); @@ -80,7 +86,9 @@ public class InfoRule implements Parcelable { if (o == null) o = new InfoRule(); if (getClass() != o.getClass()) return false; InfoRule infoRule = (InfoRule) o; - return stringEquals(name, infoRule.name) && + return stringEquals(urlPattern, infoRule.urlPattern) && + stringEquals(init, infoRule.init) && + stringEquals(name, infoRule.name) && stringEquals(author, infoRule.author) && stringEquals(type, infoRule.type) && stringEquals(desc, infoRule.desc) && @@ -92,6 +100,21 @@ public class InfoRule implements Parcelable { stringEquals(tocUrl, infoRule.tocUrl); } + public String getUrlPattern() { + return urlPattern; + } + + public void setUrlPattern(String urlPattern) { + this.urlPattern = urlPattern; + } + + public String getInit() { + return init; + } + + public void setInit(String init) { + this.init = init; + } public String getName() { return name; diff --git a/app/src/main/java/xyz/fycz/myreader/model/sourceAnalyzer/BookSourceManager.java b/app/src/main/java/xyz/fycz/myreader/model/sourceAnalyzer/BookSourceManager.java index 9dfcc8e..9c80f5e 100644 --- a/app/src/main/java/xyz/fycz/myreader/model/sourceAnalyzer/BookSourceManager.java +++ b/app/src/main/java/xyz/fycz/myreader/model/sourceAnalyzer/BookSourceManager.java @@ -81,11 +81,9 @@ public class BookSourceManager { * @return */ public static BookSource getBookSourceByStr(String str) { - if (NetworkUtils.isUrl(str)) { - return getBookSourceByUrl(str); - } else { - return getBookSourceByEName(str); - } + BookSource source = getBookSourceByEName(str); + if (source == null) source = getBookSourceByUrl(str); + return source; } /** @@ -94,7 +92,7 @@ public class BookSourceManager { * @param url * @return */ - public static BookSource getBookSourceByUrl(String url) { + private static BookSource getBookSourceByUrl(String url) { if (url == null) return getDefaultSource(); BookSource source = DbManager.getDaoSession().getBookSourceDao().load(url); if (source == null) return getDefaultSource(); @@ -107,15 +105,13 @@ public class BookSourceManager { * @param ename * @return */ - @Nullable - public static BookSource getBookSourceByEName(String ename) { - if (ename == null) return getDefaultSource(); + private static BookSource getBookSourceByEName(String ename) { + if (ename == null) return null; if ("local".equals(ename)) return getLocalSource(); BookSource source = DbManager.getDaoSession().getBookSourceDao(). queryBuilder() .where(BookSourceDao.Properties.SourceEName.eq(ename)) .unique(); - if (source == null) return getDefaultSource(); return source; } diff --git a/app/src/main/java/xyz/fycz/myreader/model/third2/analyzeRule/AnalyzeByRegex.java b/app/src/main/java/xyz/fycz/myreader/model/third2/analyzeRule/AnalyzeByRegex.java index 5484626..922d9fc 100644 --- a/app/src/main/java/xyz/fycz/myreader/model/third2/analyzeRule/AnalyzeByRegex.java +++ b/app/src/main/java/xyz/fycz/myreader/model/third2/analyzeRule/AnalyzeByRegex.java @@ -2,6 +2,7 @@ package xyz.fycz.myreader.model.third2.analyzeRule; import android.os.Build; import android.text.TextUtils; +import android.util.Log; import java.util.ArrayList; import java.util.HashMap; @@ -21,11 +22,16 @@ public class AnalyzeByRegex { // 纯java模式正则表达式获取书籍详情信息 public static void getInfoOfRegex(String res, String[] regs, int index, - Book book, AnalyzeRule analyzer, BookSource source, String baseUrl, String tag) throws Exception { + Book book, AnalyzeRule analyzer, BookSource source, String tag) throws Exception { Matcher resM = Pattern.compile(regs[index]).matcher(res); + String baseUrl = book.getInfoUrl(); // 判断规则是否有效,当搜索列表规则无效时跳过详情页处理 if (!resM.find()) { + Log.d(tag, "└详情预处理失败,跳过详情页解析"); + Log.d(tag, "┌获取目录网址"); book.setChapterUrl(baseUrl); + book.putCathe("ChapterListHtml", res); + Log.d(tag, "└" + baseUrl); return; } // 判断索引的规则是最后一个规则 @@ -78,18 +84,37 @@ public class AnalyzeByRegex { book.setName(StringUtils.formatHtml(ruleVal.get("BookName"))); if (!isEmpty(ruleVal.get("BookAuthor"))) book.setAuthor(StringUtils.formatHtml(ruleVal.get("BookAuthor"))); - if (!isEmpty(ruleVal.get("LastChapter"))) book.setNewestChapterTitle(ruleVal.get("LastChapter")); + if (!isEmpty(ruleVal.get("LastChapter"))) + book.setNewestChapterTitle(ruleVal.get("LastChapter")); if (!isEmpty(ruleVal.get("Introduce"))) book.setDesc(StringUtils.formatHtml(ruleVal.get("Introduce"))); if (!isEmpty(ruleVal.get("CoverUrl"))) book.setImgUrl(ruleVal.get("CoverUrl")); - if (!isEmpty(ruleVal.get("ChapterUrl"))) book.setChapterUrl(NetworkUtils.getAbsoluteURL(baseUrl, ruleVal.get("ChapterUrl"))); + if (!isEmpty(ruleVal.get("ChapterUrl"))) + book.setChapterUrl(NetworkUtils.getAbsoluteURL(baseUrl, ruleVal.get("ChapterUrl"))); else book.setChapterUrl(baseUrl); + //如果目录页和详情页相同,暂存页面内容供获取目录用 + if (book.getChapterUrl().equals(baseUrl)) book.putCathe("ChapterListHtml", res); + // 输出调试信息 + Log.d(tag, "└详情预处理完成"); + Log.d(tag, "┌获取书籍名称"); + Log.d(tag, "└" + book.getName()); + Log.d(tag, "┌获取作者名称"); + Log.d(tag, "└" + book.getAuthor()); + Log.d(tag, "┌获取最新章节"); + Log.d(tag, "└" + book.getNewestChapterTitle()); + Log.d(tag, "┌获取简介内容"); + Log.d(tag, "└" + book.getDesc()); + Log.d(tag, "┌获取封面网址"); + Log.d(tag, "└" + book.getImgUrl()); + Log.d(tag, "┌获取目录网址"); + Log.d(tag, "└" + book.getChapterUrl()); + Log.d(tag, "-详情页解析完成"); } else { StringBuilder result = new StringBuilder(); do { result.append(resM.group()); } while (resM.find()); - getInfoOfRegex(result.toString(), regs, ++index, book, analyzer, source, baseUrl, tag); + getInfoOfRegex(result.toString(), regs, ++index, book, analyzer, source, tag); } } diff --git a/app/src/main/java/xyz/fycz/myreader/model/third2/content/BookInfo.java b/app/src/main/java/xyz/fycz/myreader/model/third2/content/BookInfo.java index 99d8437..a01a2c7 100644 --- a/app/src/main/java/xyz/fycz/myreader/model/third2/content/BookInfo.java +++ b/app/src/main/java/xyz/fycz/myreader/model/third2/content/BookInfo.java @@ -8,6 +8,7 @@ import io.reactivex.Observable; import xyz.fycz.myreader.greendao.entity.Book; import xyz.fycz.myreader.greendao.entity.rule.BookSource; import xyz.fycz.myreader.greendao.entity.rule.InfoRule; +import xyz.fycz.myreader.model.third2.analyzeRule.AnalyzeByRegex; import xyz.fycz.myreader.model.third2.analyzeRule.AnalyzeRule; import xyz.fycz.myreader.util.utils.StringUtils; @@ -27,7 +28,7 @@ public class BookInfo { public Observable analyzeBookInfo(String s, final Book book) { return Observable.create(e -> { String baseUrl = book.getInfoUrl(); - book.setInfoUrl(baseUrl); + InfoRule infoRule = source.getInfoRule(); if (TextUtils.isEmpty(s)) { e.onError(new Throwable("书籍信息获取失败" + baseUrl)); @@ -42,43 +43,67 @@ public class BookInfo { AnalyzeRule analyzer = new AnalyzeRule(book); analyzer.setContent(s, baseUrl); - Log.d(tag, "┌获取书名"); - String bookName = StringUtils.formatHtml(analyzer.getString(infoRule.getName())); - if (!isEmpty(bookName)) book.setName(bookName); - Log.d(tag, "└" + bookName); - - Log.d(tag, "┌获取作者"); - String bookAuthor = StringUtils.formatHtml(analyzer.getString(infoRule.getAuthor())); - if (!isEmpty(bookAuthor)) book.setAuthor(bookAuthor); - Log.d(tag, "└" + bookAuthor); - - Log.d(tag, "┌获取分类"); - String bookKind = analyzer.getString(infoRule.getType()); - Log.d(tag, "└" + bookKind); - - Log.d(tag, "┌获取最新章节"); - String bookLastChapter = analyzer.getString(infoRule.getLastChapter()); - if (!isEmpty(bookLastChapter)) book.setNewestChapterTitle(bookLastChapter); - Log.d(tag, "└" + bookLastChapter); - - Log.d(tag, "┌获取简介"); - String bookIntroduce = analyzer.getString(infoRule.getDesc()); - if (!isEmpty(bookIntroduce)) book.setDesc(bookIntroduce); - Log.d(tag, "└" + bookIntroduce); - - Log.d(tag, "┌获取封面"); - String bookCoverUrl = analyzer.getString(infoRule.getImgUrl(), true); - if (!isEmpty(bookCoverUrl)) book.setImgUrl(bookCoverUrl); - Log.d(tag, "└" + bookCoverUrl); - - Log.d(tag, "┌获取目录网址"); - String bookCatalogUrl = analyzer.getString(infoRule.getTocUrl(), true); - if (isEmpty(bookCatalogUrl)) bookCatalogUrl = baseUrl; - book.setChapterUrl(bookCatalogUrl); - //如果目录页和详情页相同,暂存页面内容供获取目录用 - //if (bookCatalogUrl.equals(baseUrl)) bookInfoBean.setChapterListHtml(s); - Log.d(tag, "└" + book.getChapterUrl()); - Log.d(tag, "-详情页解析完成"); + // 获取详情页预处理规则 + String ruleInfoInit = infoRule.getInit(); + boolean isRegex = false; + if (!isEmpty(ruleInfoInit)) { + // 仅使用java正则表达式提取书籍详情 + if (ruleInfoInit.startsWith(":")) { + isRegex = true; + ruleInfoInit = ruleInfoInit.substring(1); + Log.d(tag, "┌详情信息预处理"); + AnalyzeByRegex.getInfoOfRegex(s, ruleInfoInit.split("&&"), 0, book, analyzer, source, tag); + } else { + Object object = analyzer.getElement(ruleInfoInit); + if (object != null) { + analyzer.setContent(object); + } + } + } + if (!isRegex) { + Log.d(tag, "┌详情信息预处理"); + Object object = analyzer.getElement(ruleInfoInit); + if (object != null) analyzer.setContent(object); + Log.d(tag, "└详情预处理完成"); + + Log.d(tag, "┌获取书名"); + String bookName = StringUtils.formatHtml(analyzer.getString(infoRule.getName())); + if (!isEmpty(bookName)) book.setName(bookName); + Log.d(tag, "└" + bookName); + + Log.d(tag, "┌获取作者"); + String bookAuthor = StringUtils.formatHtml(analyzer.getString(infoRule.getAuthor())); + if (!isEmpty(bookAuthor)) book.setAuthor(bookAuthor); + Log.d(tag, "└" + bookAuthor); + + Log.d(tag, "┌获取分类"); + String bookKind = analyzer.getString(infoRule.getType()); + Log.d(tag, "└" + bookKind); + + Log.d(tag, "┌获取最新章节"); + String bookLastChapter = analyzer.getString(infoRule.getLastChapter()); + if (!isEmpty(bookLastChapter)) book.setNewestChapterTitle(bookLastChapter); + Log.d(tag, "└" + bookLastChapter); + + Log.d(tag, "┌获取简介"); + String bookIntroduce = analyzer.getString(infoRule.getDesc()); + if (!isEmpty(bookIntroduce)) book.setDesc(bookIntroduce); + Log.d(tag, "└" + bookIntroduce); + + Log.d(tag, "┌获取封面"); + String bookCoverUrl = analyzer.getString(infoRule.getImgUrl(), true); + if (!isEmpty(bookCoverUrl)) book.setImgUrl(bookCoverUrl); + Log.d(tag, "└" + bookCoverUrl); + + Log.d(tag, "┌获取目录网址"); + String bookCatalogUrl = analyzer.getString(infoRule.getTocUrl(), true); + if (isEmpty(bookCatalogUrl)) bookCatalogUrl = baseUrl; + book.setChapterUrl(bookCatalogUrl); + //如果目录页和详情页相同,暂存页面内容供获取目录用 + if (bookCatalogUrl.equals(baseUrl)) book.putCathe("ChapterListHtml", s); + Log.d(tag, "└" + book.getChapterUrl()); + Log.d(tag, "-详情页解析完成"); + } e.onNext(book); e.onComplete(); }); diff --git a/app/src/main/java/xyz/fycz/myreader/model/third2/content/BookList.java b/app/src/main/java/xyz/fycz/myreader/model/third2/content/BookList.java index fd9286d..dff9157 100644 --- a/app/src/main/java/xyz/fycz/myreader/model/third2/content/BookList.java +++ b/app/src/main/java/xyz/fycz/myreader/model/third2/content/BookList.java @@ -65,67 +65,76 @@ public class BookList { AnalyzeRule analyzer = new AnalyzeRule(null); analyzer.setContent(body, baseUrl); //如果符合详情页url规则 - - initRule(); - List collections; - boolean reverse = false; - boolean allInOne = false; - if (ruleList.startsWith("-")) { - reverse = true; - ruleList = ruleList.substring(1); - } - // 仅使用java正则表达式提取书籍列表 - if (ruleList.startsWith(":")) { - ruleList = ruleList.substring(1); - Log.d(tag, "┌解析搜索列表"); - getBooksOfRegex(body, ruleList.split("&&"), 0, analyzer, books); + if (!isEmpty(bookSource.getInfoRule().getUrlPattern()) + && baseUrl.matches(bookSource.getInfoRule().getUrlPattern())) { + Log.d(tag, ">搜索结果为详情页"); + Book item = getItem(analyzer, baseUrl); + if (item != null) { + item.putCathe("BookInfoHtml", body); + books.add(item); + } } else { - if (ruleList.startsWith("+")) { - allInOne = true; + initRule(); + List collections; + boolean reverse = false; + boolean allInOne = false; + if (ruleList.startsWith("-")) { + reverse = true; ruleList = ruleList.substring(1); } - //获取列表 - Log.d(tag, "┌解析搜索列表"); - collections = analyzer.getElements(ruleList); - if (collections.size() == 0) { - Log.d(tag, "└搜索列表为空,当做详情页处理"); - Book item = getItem(analyzer, baseUrl); - if (item != null) { - //item.setBookInfoHtml(body); - books.add(item); - } + // 仅使用java正则表达式提取书籍列表 + if (ruleList.startsWith(":")) { + ruleList = ruleList.substring(1); + Log.d(tag, "┌解析搜索列表"); + getBooksOfRegex(body, ruleList.split("&&"), 0, analyzer, books); } else { - Log.d(tag, "└找到 " + collections.size() + " 个匹配的结果"); - if (allInOne) { - for (int i = 0; i < collections.size(); i++) { - Object object = collections.get(i); - Book item = getItemAllInOne(analyzer, object, baseUrl, i == 0); - if (item != null) { - //如果网址相同则缓存 - /*if (baseUrl.equals(item.getNoteUrl())) { - item.setBookInfoHtml(body); - }*/ - books.add(item); - } + if (ruleList.startsWith("+")) { + allInOne = true; + ruleList = ruleList.substring(1); + } + //获取列表 + Log.d(tag, "┌解析搜索列表"); + collections = analyzer.getElements(ruleList); + if (collections.size() == 0 && isEmpty(bookSource.getInfoRule().getUrlPattern())) { + Log.d(tag, "└搜索列表为空,当做详情页处理"); + Book item = getItem(analyzer, baseUrl); + if (item != null) { + item.putCathe("BookInfoHtml", body); + books.add(item); } } else { - for (int i = 0; i < collections.size(); i++) { - Object object = collections.get(i); - analyzer.setContent(object, baseUrl); - Book item = getItemInList(analyzer, baseUrl, i == 0); - if (item != null) { - //如果网址相同则缓存 - /*if (baseUrl.equals(item.getNoteUrl())) { - item.setBookInfoHtml(body); - }*/ - books.add(item); + Log.d(tag, "└找到 " + collections.size() + " 个匹配的结果"); + if (allInOne) { + for (int i = 0; i < collections.size(); i++) { + Object object = collections.get(i); + Book item = getItemAllInOne(analyzer, object, baseUrl, i == 0); + if (item != null) { + //如果网址相同则缓存 + if (baseUrl.equals(item.getInfoUrl())) { + item.putCathe("BookInfoHtml", body); + } + books.add(item); + } + } + } else { + for (int i = 0; i < collections.size(); i++) { + Object object = collections.get(i); + analyzer.setContent(object, baseUrl); + Book item = getItemInList(analyzer, baseUrl, i == 0); + if (item != null) { + //如果网址相同则缓存 + if (baseUrl.equals(item.getInfoUrl())) { + item.putCathe("BookInfoHtml", body); + } + books.add(item); + } } } } } - } - if (books.size() > 1 && reverse) { - Collections.reverse(books); + if (books.size() > 1 && reverse) { + Collections.reverse(books); + } } if (books.isEmpty()) { e.onError(new Throwable("未获取到书名")); @@ -147,7 +156,7 @@ public class BookList { ruleIntroduce = findRule.getDesc(); ruleCoverUrl = findRule.getImgUrl(); ruleLastChapter = findRule.getLastChapter(); - ruleNoteUrl = findRule.getTocUrl(); + ruleNoteUrl = findRule.getInfoUrl(); } else { SearchRule searchRule = bookSource.getSearchRule(); ruleList = searchRule.getList(); @@ -157,7 +166,7 @@ public class BookList { ruleIntroduce = searchRule.getDesc(); ruleCoverUrl = searchRule.getImgUrl(); ruleLastChapter = searchRule.getLastChapter(); - ruleNoteUrl = searchRule.getTocUrl(); + ruleNoteUrl = searchRule.getInfoUrl(); } } @@ -170,8 +179,24 @@ public class BookList { analyzer.setBook(item); item.setTag(tag); item.setSource(bookSource.getSourceUrl()); - item.setChapterUrl(baseUrl); item.setInfoUrl(baseUrl); + // 获取详情页预处理规则 + String ruleInfoInit = infoRule.getInit(); + if (!isEmpty(ruleInfoInit)) { + // 仅使用java正则表达式提取书籍详情 + if (ruleInfoInit.startsWith(":")) { + ruleInfoInit = ruleInfoInit.substring(1); + Log.d(tag, "┌详情信息预处理"); + AnalyzeByRegex.getInfoOfRegex(String.valueOf(analyzer.getContent()), ruleInfoInit.split("&&"), 0, item, analyzer, bookSource, tag); + if (isEmpty(item.getName())) return null; + return item; + } else { + Object object = analyzer.getElement(ruleInfoInit); + if (object != null) { + analyzer.setContent(object); + } + } + } Log.d(tag, ">书籍网址:" + baseUrl); Log.d(tag, "┌获取书名"); String bookName = StringUtils.formatHtml(analyzer.getString(infoRule.getName())); @@ -193,10 +218,6 @@ public class BookList { Log.d(tag, "┌获取封面"); item.setImgUrl(analyzer.getString(infoRule.getImgUrl(), true)); Log.d(tag, "└" + item.getImgUrl()); - Log.d(tag, "┌获取目录网址"); - String bookCatalogUrl = analyzer.getString(infoRule.getTocUrl(), true); - if (!isEmpty(bookCatalogUrl)) item.setChapterUrl(bookCatalogUrl);; - Log.d(tag, "└" + item.getChapterUrl()); return item; } return null; @@ -206,7 +227,7 @@ public class BookList { Book item = new Book(); analyzer.setBook(item); NativeObject nativeObject = (NativeObject) object; - if (printLog) Log.d(tag, "┌获取书名"); + if (printLog) Log.d(tag, "┌获取书名"); String bookName = StringUtils.formatHtml(String.valueOf(nativeObject.get(ruleName))); if (printLog) Log.d(tag, "└" + bookName); if (!isEmpty(bookName)) { @@ -216,24 +237,24 @@ public class BookList { if (printLog) Log.d(tag, "┌获取作者"); item.setAuthor(StringUtils.formatHtml(String.valueOf(nativeObject.get(ruleAuthor)))); if (printLog) Log.d(tag, "└" + item.getAuthor()); - if (printLog) Log.d(tag, "┌获取分类"); + if (printLog) Log.d(tag, "┌获取分类"); item.setType(String.valueOf(nativeObject.get(ruleKind))); - if (printLog) Log.d(tag,"└" + item.getType()); - if (printLog) Log.d(tag, "┌获取最新章节"); + if (printLog) Log.d(tag, "└" + item.getType()); + if (printLog) Log.d(tag, "┌获取最新章节"); item.setNewestChapterTitle(String.valueOf(nativeObject.get(ruleLastChapter))); if (printLog) Log.d(tag, "└" + item.getNewestChapterTitle()); - if (printLog) Log.d(tag, "┌获取简介"); + if (printLog) Log.d(tag, "┌获取简介"); item.setDesc(String.valueOf(nativeObject.get(ruleIntroduce))); if (printLog) Log.d(tag, "└" + item.getDesc()); - if (printLog) Log.d(tag, "┌获取封面"); + if (printLog) Log.d(tag, "┌获取封面"); if (!isEmpty(ruleCoverUrl)) item.setImgUrl(NetworkUtils.getAbsoluteURL(baseUrl, String.valueOf(nativeObject.get(ruleCoverUrl)))); if (printLog) Log.d(tag, "└" + item.getImgUrl()); if (printLog) Log.d(tag, "┌获取书籍网址"); String resultUrl = String.valueOf(nativeObject.get(ruleNoteUrl)); if (isEmpty(resultUrl)) resultUrl = baseUrl; - item.setChapterUrl(resultUrl); - if (printLog) Log.d(tag, "└" + item.getChapterUrl()); + item.setInfoUrl(resultUrl); + if (printLog) Log.d(tag, "└" + item.getInfoUrl()); return item; } return null; @@ -264,12 +285,12 @@ public class BookList { if (printLog) Log.d(tag, "└" + item.getDesc()); if (printLog) Log.d(tag, "┌获取封面"); item.setImgUrl(analyzer.getString(ruleCoverUrl, true)); - if (printLog) Log.d(tag, "└" + item.getImgUrl()); + if (printLog) Log.d(tag, "└" + item.getImgUrl()); Log.d(tag, "┌获取书籍网址"); String resultUrl = analyzer.getString(ruleNoteUrl, true); if (isEmpty(resultUrl)) resultUrl = baseUrl; - item.setChapterUrl(resultUrl); - if (printLog) Log.d(tag, "└" + item.getChapterUrl()); + item.setInfoUrl(resultUrl); + if (printLog) Log.d(tag, "└" + item.getInfoUrl()); return item; } return null; @@ -344,12 +365,13 @@ public class BookList { item.setNewestChapterTitle(ruleVal.get("ruleLastChapter")); item.setDesc(ruleVal.get("ruleIntroduce")); item.setImgUrl(ruleVal.get("ruleCoverUrl")); - item.setChapterUrl(NetworkUtils.getAbsoluteURL(baseUrl, ruleVal.get("ruleNoteUrl"))); + item.setInfoUrl(NetworkUtils.getAbsoluteURL(baseUrl, ruleVal.get("ruleNoteUrl"))); books.add(item); // 判断搜索结果是否为详情页 if (books.size() == 1 && (isEmpty(ruleVal.get("ruleNoteUrl")) || ruleVal.get("ruleNoteUrl").equals(baseUrl))) { - books.get(0).setChapterUrl(baseUrl); - //books.get(0).setBookInfoHtml(res); + books.get(0).setInfoUrl(baseUrl); + books.get(0).putCathe("BookInfoHtml", res); + ; return; } } while (resM.find()); @@ -368,7 +390,7 @@ public class BookList { Log.d(tag, "┌获取封面"); Log.d(tag, "└" + books.get(0).getImgUrl()); Log.d(tag, "┌获取书籍"); - Log.d(tag, "└" + books.get(0).getChapterUrl()); + Log.d(tag, "└" + books.get(0).getInfoUrl()); } else { StringBuilder result = new StringBuilder(); do { 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 b96b56a..848dee4 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 @@ -47,6 +47,7 @@ import xyz.fycz.myreader.R; import xyz.fycz.myreader.application.App; import xyz.fycz.myreader.application.SysManager; import xyz.fycz.myreader.base.BaseActivity; +import xyz.fycz.myreader.base.BitIntentDataManager; import xyz.fycz.myreader.base.observer.MyObserver; import xyz.fycz.myreader.base.observer.MySingleObserver; import xyz.fycz.myreader.common.APPCONST; @@ -106,7 +107,6 @@ public class BookDetailedActivity extends BaseActivity { private BookGroupDialog mBookGroupDia; private List tagList = new ArrayList<>(); private Disposable chaptersDis; - private boolean thirdSource; @SuppressLint("HandlerLeak") private Handler mHandler = new Handler() { @@ -115,11 +115,13 @@ public class BookDetailedActivity extends BaseActivity { switch (msg.what) { case 1: if (!"本地书籍".equals(mBook.getType())) { + initBookInfo(); mChapters.clear(); mNewestChapters.clear(); - initBookInfo(); - initChapters(true); - mCatalogAdapter.notifyDataSetChanged(); + if (!isThirdSource()) { + initChapters(true); + } + mCatalogAdapter.clear(); } break; case 2: @@ -154,16 +156,20 @@ public class BookDetailedActivity extends BaseActivity { super.initData(savedInstanceState); mBookService = BookService.getInstance(); mChapterService = ChapterService.getInstance(); - aBooks = (ArrayList) getIntent().getSerializableExtra(APPCONST.SEARCH_BOOK_BEAN); + aBooks = (ArrayList) BitIntentDataManager.getInstance().getData(getIntent()); sourceIndex = getIntent().getIntExtra(APPCONST.SOURCE_INDEX, 0); if (aBooks != null) { mBook = aBooks.get(sourceIndex); } else { mBook = (Book) getIntent().getSerializableExtra(APPCONST.BOOK); } + if (mBook == null) { + ToastUtils.showError("无法获取书籍!"); + finish(); + } isCollected = isBookCollected(); if (isCollected) { - mChapters = (ArrayList) mChapterService.findBookAllChapterByBookId(mBook.getId()); + mChapters = mChapterService.findBookAllChapterByBookId(mBook.getId()); } //Dialog mSourceDialog = new SourceExchangeDialog(this, mBook); @@ -175,7 +181,6 @@ public class BookDetailedActivity extends BaseActivity { } mBookGroupDia = new BookGroupDialog(this); mReadCrawler = ReadCrawlerUtil.getReadCrawler(mBook.getSource()); - thirdSource = mReadCrawler instanceof ThirdCrawler; } private void initTagList() { @@ -210,7 +215,7 @@ public class BookDetailedActivity extends BaseActivity { binding.ic.bookDetailRvCatalog.setLayoutManager(new LinearLayoutManager(this)); binding.ic.bookDetailRvCatalog.setAdapter(mCatalogAdapter); - if (!thirdSource) initChapters(false); + if (!isThirdSource()) initChapters(false); mCatalogAdapter.setOnItemClickListener((view, pos) -> { mBook.setHisttoryChapterNum(mChapters.size() - pos - 1); @@ -328,13 +333,13 @@ public class BookDetailedActivity extends BaseActivity { if (!StringHelper.isEmpty(bean.getDesc())) { bookTem.setDesc(bean.getDesc()); } - if (!StringHelper.isEmpty(bean.getUpdateDate())){ + if (!StringHelper.isEmpty(bean.getUpdateDate())) { bookTem.setUpdateDate(bean.getUpdateDate()); } - if (!StringHelper.isEmpty(bean.getWordCount())){ + if (!StringHelper.isEmpty(bean.getWordCount())) { bookTem.setWordCount(bean.getWordCount()); } - if (!StringHelper.isEmpty(bean.getStatus())){ + if (!StringHelper.isEmpty(bean.getStatus())) { bookTem.setStatus(bean.getStatus()); } bookTem.setSource(bean.getSource()); @@ -372,6 +377,7 @@ public class BookDetailedActivity extends BaseActivity { public void goToMoreChapter() { Intent intent = new Intent(this, CatalogActivity.class); intent.putExtra(APPCONST.BOOK, mBook); + //BitIntentDataManager.getInstance().putData(intent, mBook); startActivityForResult(intent, APPCONST.REQUEST_CHAPTER_PAGE); } @@ -420,7 +426,7 @@ public class BookDetailedActivity extends BaseActivity { BookSource source = BookSourceManager.getBookSourceByStr(mBook.getSource()); binding.ih.bookDetailSource.setText(String.format("书源:%s", source.getSourceName())); ReadCrawler rc = ReadCrawlerUtil.getReadCrawler(source); - if ((rc instanceof BookInfoCrawler && StringHelper.isEmpty(mBook.getImgUrl())) || thirdSource) { + if ((rc instanceof BookInfoCrawler && StringHelper.isEmpty(mBook.getImgUrl())) || isThirdSource()) { binding.pbLoading.setVisibility(View.VISIBLE); BookInfoCrawler bic = (BookInfoCrawler) rc; BookApi.getBookInfo(mBook, bic).compose(RxUtils::toSimpleSingle).subscribe(new MyObserver() { @@ -428,7 +434,7 @@ public class BookDetailedActivity extends BaseActivity { public void onNext(@NotNull Book book) { if (!App.isDestroy(BookDetailedActivity.this)) { mHandler.sendMessage(mHandler.obtainMessage(4)); - if (thirdSource) { + if (isThirdSource()) { initChapters(false); } } @@ -439,7 +445,7 @@ public class BookDetailedActivity extends BaseActivity { public void onError(Throwable e) { if (!App.isDestroy(BookDetailedActivity.this)) { ToastUtils.showError("书籍详情加载失败!"); - if (thirdSource) { + if (isThirdSource()) { initChapters(false); } binding.pbLoading.setVisibility(View.GONE); @@ -507,8 +513,8 @@ public class BookDetailedActivity extends BaseActivity { public void onError(Throwable e) { binding.pbLoading.setVisibility(View.GONE); mCatalogAdapter.clear(); - ToastUtils.showError("最新章节加载失败!"); if (App.isDebug()) e.printStackTrace(); + ToastUtils.showError("最新章节加载失败!\n" + e.getLocalizedMessage()); } }); } else { @@ -650,6 +656,16 @@ public class BookDetailedActivity extends BaseActivity { } }); break; + case R.id.action_edit_source: + BookSource source = BookSourceManager.getBookSourceByStr(mBook.getSource()); + if (!TextUtils.isEmpty(source.getSourceEName())) { + ToastUtils.showWarring("内置书源无法编辑!"); + } else { + Intent sourceIntent = new Intent(this, SourceEditActivity.class); + sourceIntent.putExtra(APPCONST.BOOK_SOURCE, source); + startActivity(sourceIntent); + } + break; default: break; } @@ -803,7 +819,6 @@ public class BookDetailedActivity extends BaseActivity { textPaint.setColor(Color.BLACK); cv.drawText(mBook.getType() == null ? "" : mBook.getType(), margin + marginTop + img.getWidth(), margin + marginTop * 8, textPaint); - assert mBook.getSource() != null; cv.drawText("书源:" + BookSourceManager.getSourceNameByStr(mBook.getSource()), margin + marginTop + img.getWidth(), margin + marginTop * 10, textPaint); int textSize = 35; @@ -892,4 +907,8 @@ public class BookDetailedActivity extends BaseActivity { return lines; } + private boolean isThirdSource() { + return mReadCrawler instanceof ThirdCrawler; + } + } diff --git a/app/src/main/java/xyz/fycz/myreader/ui/activity/BookstoreActivity.java b/app/src/main/java/xyz/fycz/myreader/ui/activity/BookstoreActivity.java index 640ad3e..1317eab 100644 --- a/app/src/main/java/xyz/fycz/myreader/ui/activity/BookstoreActivity.java +++ b/app/src/main/java/xyz/fycz/myreader/ui/activity/BookstoreActivity.java @@ -19,6 +19,7 @@ import java.util.List; import xyz.fycz.myreader.R; import xyz.fycz.myreader.application.App; import xyz.fycz.myreader.base.BaseActivity; +import xyz.fycz.myreader.base.BitIntentDataManager; import xyz.fycz.myreader.common.APPCONST; import xyz.fycz.myreader.databinding.ActiityBookstoreBinding; import xyz.fycz.myreader.entity.bookstore.BookType; @@ -159,7 +160,7 @@ public class BookstoreActivity extends BaseActivity { mSourceDia = new SourceExchangeDialog(this, book); mSourceDia.setOnSourceChangeListener((bean, pos1) -> { Intent intent = new Intent(this, BookDetailedActivity.class); - intent.putExtra(APPCONST.SEARCH_BOOK_BEAN, (ArrayList) mSourceDia.getaBooks()); + BitIntentDataManager.getInstance().putData(intent, mSourceDia.getaBooks()); intent.putExtra(APPCONST.SOURCE_INDEX, pos1); BookstoreActivity.this.startActivity(intent); mSourceDia.dismiss(); diff --git a/app/src/main/java/xyz/fycz/myreader/ui/activity/ReadActivity.java b/app/src/main/java/xyz/fycz/myreader/ui/activity/ReadActivity.java index 62ecf91..d57421c 100644 --- a/app/src/main/java/xyz/fycz/myreader/ui/activity/ReadActivity.java +++ b/app/src/main/java/xyz/fycz/myreader/ui/activity/ReadActivity.java @@ -17,6 +17,7 @@ import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.speech.tts.TextToSpeech; +import android.text.TextUtils; import android.util.Log; import android.view.KeyEvent; import android.view.Menu; @@ -64,11 +65,13 @@ import xyz.fycz.myreader.greendao.entity.Book; import xyz.fycz.myreader.greendao.entity.BookMark; import xyz.fycz.myreader.greendao.entity.Chapter; import xyz.fycz.myreader.greendao.entity.ReplaceRuleBean; +import xyz.fycz.myreader.greendao.entity.rule.BookSource; import xyz.fycz.myreader.greendao.service.BookGroupService; import xyz.fycz.myreader.greendao.service.BookMarkService; import xyz.fycz.myreader.greendao.service.BookService; import xyz.fycz.myreader.greendao.service.ChapterService; import xyz.fycz.myreader.model.audio.ReadAloudService; +import xyz.fycz.myreader.model.sourceAnalyzer.BookSourceManager; import xyz.fycz.myreader.model.storage.Backup; import xyz.fycz.myreader.ui.dialog.AudioPlayerDialog; import xyz.fycz.myreader.ui.dialog.CopyContentDialog; @@ -752,6 +755,15 @@ public class ReadActivity extends BaseActivity implements ColorPickerDialogListe startActivity(intent); } else if (itemId == R.id.action_download) { download(); + } else if (itemId == R.id.action_edit_source) { + BookSource source = BookSourceManager.getBookSourceByStr(mBook.getSource()); + if (!TextUtils.isEmpty(source.getSourceEName())) { + ToastUtils.showWarring("内置书源无法编辑!"); + } else { + Intent sourceIntent = new Intent(this, SourceEditActivity.class); + sourceIntent.putExtra(APPCONST.BOOK_SOURCE, source); + startActivity(sourceIntent); + } } return super.onOptionsItemSelected(item); } diff --git a/app/src/main/java/xyz/fycz/myreader/ui/activity/SearchBookActivity.java b/app/src/main/java/xyz/fycz/myreader/ui/activity/SearchBookActivity.java index 90a2ce5..cca3b60 100644 --- a/app/src/main/java/xyz/fycz/myreader/ui/activity/SearchBookActivity.java +++ b/app/src/main/java/xyz/fycz/myreader/ui/activity/SearchBookActivity.java @@ -38,6 +38,7 @@ import xyz.fycz.myreader.R; import xyz.fycz.myreader.application.App; import xyz.fycz.myreader.application.SysManager; import xyz.fycz.myreader.base.BaseActivity; +import xyz.fycz.myreader.base.BitIntentDataManager; import xyz.fycz.myreader.base.observer.MySingleObserver; import xyz.fycz.myreader.common.APPCONST; import xyz.fycz.myreader.databinding.ActivitySearchBookBinding; @@ -546,7 +547,7 @@ public class SearchBookActivity extends BaseActivity { if (books == null || books.size() == 0) return; searchBookBean2Book(data, books.get(0)); Intent intent = new Intent(this, BookDetailedActivity.class); - intent.putExtra(APPCONST.SEARCH_BOOK_BEAN, books); + BitIntentDataManager.getInstance().putData(intent, books); startActivity(intent); }); binding.srlSearchBookList.setEnableRefresh(true); diff --git a/app/src/main/java/xyz/fycz/myreader/ui/activity/SourceDebugActivity.java b/app/src/main/java/xyz/fycz/myreader/ui/activity/SourceDebugActivity.java index fdb6f06..cead3f2 100644 --- a/app/src/main/java/xyz/fycz/myreader/ui/activity/SourceDebugActivity.java +++ b/app/src/main/java/xyz/fycz/myreader/ui/activity/SourceDebugActivity.java @@ -258,6 +258,7 @@ public class SourceDebugActivity extends BaseActivity { ListResult listResult = new ListResult(); Book book = new Book(); book.setChapterUrl(debugEntity.getUrl()); + book.setInfoUrl(debugEntity.getUrl()); switch (debugEntity.getDebugMode()) { case DebugEntity.SEARCH: default: diff --git a/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/SearchBookHolder.java b/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/SearchBookHolder.java index 2b55bc7..afc24c1 100644 --- a/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/SearchBookHolder.java +++ b/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/SearchBookHolder.java @@ -78,7 +78,8 @@ public class SearchBookHolder extends ViewHolderImpl { public void onBind(SearchBookBean data, int pos) { List aBooks = mBooks.getValues(data); if (aBooks == null || aBooks.size() == 0){ - return; + aBooks = new ArrayList<>(); + aBooks.add(searchBookBean2Book(data)); } int bookCount = aBooks.size(); Book book = aBooks.get(0); @@ -116,7 +117,7 @@ public class SearchBookHolder extends ViewHolderImpl { initOtherInfo(data, rc); return; } - Log.i(book.getName(), "initOtherInfo"); + Log.i(data.getName(), "initOtherInfo"); BookInfoCrawler bic = (BookInfoCrawler) rc; searchEngine.getBookInfo(book, bic, isSuccess -> { if (isSuccess) { @@ -230,6 +231,19 @@ public class SearchBookHolder extends ViewHolderImpl { } } + private Book searchBookBean2Book(SearchBookBean bean){ + Book book = new Book(); + book.setName(bean.getName()); + book.setAuthor(bean.getAuthor()); + book.setType(bean.getType()); + book.setDesc(bean.getDesc()); + book.setStatus(bean.getStatus()); + book.setUpdateDate(bean.getUpdateTime()); + book.setNewestChapterTitle(bean.getLastChapter()); + book.setWordCount(bean.getWordCount()); + return book; + } + private boolean needGetInfo(SearchBookBean bookBean) { if (StringHelper.isEmpty(bookBean.getAuthor())) return true; if (StringHelper.isEmpty(bookBean.getType())) return true; diff --git a/app/src/main/java/xyz/fycz/myreader/util/help/JsExtensions.java b/app/src/main/java/xyz/fycz/myreader/util/help/JsExtensions.java index 46daad0..e6972b4 100644 --- a/app/src/main/java/xyz/fycz/myreader/util/help/JsExtensions.java +++ b/app/src/main/java/xyz/fycz/myreader/util/help/JsExtensions.java @@ -5,6 +5,8 @@ import android.text.TextUtils; import android.util.Base64; import android.util.Log; +import androidx.annotation.Keep; + import org.jsoup.Connection; import org.jsoup.Jsoup; @@ -30,7 +32,7 @@ import xyz.fycz.myreader.util.utils.MD5Utils; import xyz.fycz.myreader.util.utils.OkHttpUtils; import xyz.fycz.myreader.util.utils.StringUtils; -@SuppressWarnings({"unused", "WeakerAccess"}) +@SuppressWarnings({"unused"}) public interface JsExtensions { String TAG = JsExtensions.class.getSimpleName(); diff --git a/app/src/main/java/xyz/fycz/myreader/util/utils/AdUtils.java b/app/src/main/java/xyz/fycz/myreader/util/utils/AdUtils.java index 427b4f8..456713e 100644 --- a/app/src/main/java/xyz/fycz/myreader/util/utils/AdUtils.java +++ b/app/src/main/java/xyz/fycz/myreader/util/utils/AdUtils.java @@ -123,9 +123,9 @@ public class AdUtils { public static void initAd() { if (!hasInitAd) { hasInitAd = true; - DdSdkHelper.init("", "", "", - "", "", - "", "", + DdSdkHelper.init("1234", "216", "51716a16fbdf50905704b6575b1b3b60", + "142364", "35ce0efe5f3cc960b116db227498e238", + "8167", "85bd159309c3da1b", App.getApplication(), App.isDebug()); } } diff --git a/app/src/main/java/xyz/fycz/myreader/util/utils/MD5Utils.kt b/app/src/main/java/xyz/fycz/myreader/util/utils/MD5Utils.kt index 5bd98fa..74c4e5c 100644 --- a/app/src/main/java/xyz/fycz/myreader/util/utils/MD5Utils.kt +++ b/app/src/main/java/xyz/fycz/myreader/util/utils/MD5Utils.kt @@ -54,7 +54,7 @@ object MD5Utils { if (!file.isFile) { return null } - var digest: MessageDigest? = null + val digest: MessageDigest? var `in`: FileInputStream? = null val buffer = ByteArray(1024) var len: Int diff --git a/app/src/main/java/xyz/fycz/myreader/webapi/BookApi.java b/app/src/main/java/xyz/fycz/myreader/webapi/BookApi.java index 0bb4ad5..c534803 100644 --- a/app/src/main/java/xyz/fycz/myreader/webapi/BookApi.java +++ b/app/src/main/java/xyz/fycz/myreader/webapi/BookApi.java @@ -19,6 +19,7 @@ import xyz.fycz.myreader.entity.StrResponse; import xyz.fycz.myreader.greendao.entity.Book; import xyz.fycz.myreader.greendao.entity.Chapter; import xyz.fycz.myreader.model.mulvalmap.ConMVMap; +import xyz.fycz.myreader.util.StringHelper; import xyz.fycz.myreader.util.utils.NetworkUtils; import xyz.fycz.myreader.util.utils.OkHttpUtils; import xyz.fycz.myreader.webapi.crawler.base.BookInfoCrawler; @@ -108,6 +109,7 @@ public class BookApi { return ThirdSourceApi.getBookChaptersByTC(book, (ThirdCrawler) rc); } String url = book.getChapterUrl(); + if (StringHelper.isEmpty(url)) url = book.getInfoUrl(); String charset = rc.getCharset(); url = NetworkUtils.getAbsoluteURL(rc.getNameSpace(), url); String finalUrl = url; diff --git a/app/src/main/java/xyz/fycz/myreader/webapi/ThirdSourceApi.java b/app/src/main/java/xyz/fycz/myreader/webapi/ThirdSourceApi.java index 4c2d053..12ddadc 100644 --- a/app/src/main/java/xyz/fycz/myreader/webapi/ThirdSourceApi.java +++ b/app/src/main/java/xyz/fycz/myreader/webapi/ThirdSourceApi.java @@ -1,7 +1,10 @@ package xyz.fycz.myreader.webapi; +import android.text.TextUtils; + import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.regex.Matcher; import io.reactivex.Observable; @@ -58,9 +61,9 @@ public class ThirdSourceApi { protected static Observable getBookInfoByTC(Book book, ThirdCrawler rc) { BookSource source = rc.getSource(); BookInfo bookInfo = new BookInfo(source.getSourceUrl(), source.getSourceName(), source); - /*if (!TextUtils.isEmpty(book.getBookInfoBean().getBookInfoHtml())) { - return bookInfo.analyzeBookInfo(book.getBookInfoBean().getBookInfoHtml(), bookShelfBean); - }*/ + if (!TextUtils.isEmpty(book.getCathe("BookInfoHtml"))) { + return bookInfo.analyzeBookInfo(book.getCathe("BookInfoHtml"), book); + } try { Map headers = rc.getHeaders(); headers.putAll(getCookies(rc.getNameSpace())); @@ -75,13 +78,13 @@ public class ThirdSourceApi { protected static Observable> getBookChaptersByTC(Book book, ThirdCrawler rc) { BookSource source = rc.getSource(); + Map headers = rc.getHeaders(); + headers.putAll(getCookies(rc.getNameSpace())); BookChapterList bookChapterList = new BookChapterList(source.getSourceUrl(), source, true); - /*if (!TextUtils.isEmpty(bookShelfBean.getBookInfoBean().getChapterListHtml())) { - return bookChapterList.analyzeChapterList(bookShelfBean.getBookInfoBean().getChapterListHtml(), bookShelfBean, headerMap); - }*/ + if (!TextUtils.isEmpty(book.getCathe("ChapterListHtml"))) { + return bookChapterList.analyzeChapterList(book.getCathe("ChapterListHtml"), book, headers); + } try { - Map headers = rc.getHeaders(); - headers.putAll(getCookies(rc.getNameSpace())); AnalyzeUrl analyzeUrl = new AnalyzeUrl(book.getChapterUrl(), headers, book.getInfoUrl()); return OkHttpUtils.getStrResponse(analyzeUrl) .flatMap(response -> OkHttpUtils.setCookie(response, source.getSourceUrl())) @@ -101,14 +104,14 @@ public class ThirdSourceApi { protected static Observable getChapterContentByTC(Chapter chapter, Book book, ThirdCrawler rc) { BookSource source = rc.getSource(); + Map headers = rc.getHeaders(); + headers.putAll(getCookies(rc.getNameSpace())); BookContent bookContent = new BookContent(source.getSourceUrl(), source); - /*if (Objects.equals(chapterBean.getDurChapterUrl(), bookShelfBean.getBookInfoBean().getChapterUrl()) - && !TextUtils.isEmpty(bookShelfBean.getBookInfoBean().getChapterListHtml())) { - return bookContent.analyzeBookContent(bookShelfBean.getBookInfoBean().getChapterListHtml(), chapterBean, nextChapterBean, bookShelfBean, headerMap); - }*/ + if (Objects.equals(chapter.getUrl(), book.getChapterUrl()) + && !TextUtils.isEmpty(book.getCathe("ChapterListHtml"))) { + return bookContent.analyzeBookContent(book.getCathe("ChapterListHtml"), chapter, null, book, headers); + } try { - Map headers = rc.getHeaders(); - headers.putAll(getCookies(rc.getNameSpace())); AnalyzeUrl analyzeUrl = new AnalyzeUrl(chapter.getUrl(), headers, book.getChapterUrl()); String contentRule = source.getContentRule().getContent(); if (contentRule.startsWith("$") && !contentRule.startsWith("$.")) { diff --git a/app/src/main/res/drawable/ic_source.xml b/app/src/main/res/drawable/ic_source.xml index 788d51f..fb4667c 100644 --- a/app/src/main/res/drawable/ic_source.xml +++ b/app/src/main/res/drawable/ic_source.xml @@ -4,9 +4,6 @@ android:viewportWidth="1024" android:viewportHeight="1024"> - + android:pathData="M438.4,849.1l222.7,-646.7c0.2,-0.5 0.3,-1.1 0.4,-1.6L438.4,849.1zM661.2,168.7h-67.5c-3.4,0 -6.5,2.2 -7.6,5.4L354.7,846c-0.3,0.8 -0.4,1.7 -0.4,2.6 0,4.4 3.6,8 8,8h67.8c3.4,0 6.5,-2.2 7.6,-5.4l0.7,-2.1 223.1,-648.3 7.4,-21.4c0.3,-0.8 0.4,-1.7 0.4,-2.6 -0.1,-4.5 -3.6,-8.1 -8.1,-8.1zM954.6,502.1c-0.8,-1 -1.7,-1.9 -2.7,-2.7l-219,-171.3c-3.5,-2.7 -8.5,-2.1 -11.2,1.4 -1.1,1.4 -1.7,3.1 -1.7,4.9v81.3c0,2.5 1.1,4.8 3.1,6.3l115,90 -115,90c-1.9,1.5 -3.1,3.8 -3.1,6.3v81.3c0,4.4 3.6,8 8,8 1.8,0 3.5,-0.6 4.9,-1.7l219,-171.3c6.9,-5.4 8.2,-15.5 2.7,-22.5zM291.1,328.1l-219,171.3c-1,0.8 -1.9,1.7 -2.7,2.7 -5.4,7 -4.2,17 2.7,22.5l219,171.3c1.4,1.1 3.1,1.7 4.9,1.7 4.4,0 8,-3.6 8,-8v-81.3c0,-2.5 -1.1,-4.8 -3.1,-6.3l-115,-90 115,-90c1.9,-1.5 3.1,-3.8 3.1,-6.3v-81.3c0,-1.8 -0.6,-3.5 -1.7,-4.9 -2.7,-3.5 -7.7,-4.1 -11.2,-1.4z" + android:fillColor="#ffffff"/> diff --git a/app/src/main/res/layout/fragment_mine.xml b/app/src/main/res/layout/fragment_mine.xml index f88df7a..2efd68b 100644 --- a/app/src/main/res/layout/fragment_mine.xml +++ b/app/src/main/res/layout/fragment_mine.xml @@ -159,8 +159,8 @@ + diff --git a/app/src/main/res/menu/menu_read.xml b/app/src/main/res/menu/menu_read.xml index e9f545c..d275cfc 100644 --- a/app/src/main/res/menu/menu_read.xml +++ b/app/src/main/res/menu/menu_read.xml @@ -41,4 +41,10 @@ android:title="@string/menu_open_link" app:showAsAction="never"/> + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index fae682f..3ba626b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -388,7 +388,7 @@ 最新章节规则 字数规则 连载状态规则 - 书籍URL正则 + 书籍详情URL正则 预处理规则 目录URL规则 目录列表区间 @@ -486,6 +486,7 @@ 成功 正在打开首页,成功自动返回主界面 清除Cookie + 编辑书源 diff --git a/app/version_code.properties b/app/version_code.properties index d773913..7922af9 100644 --- a/app/version_code.properties +++ b/app/version_code.properties @@ -1,2 +1,2 @@ -#Fri May 14 22:41:02 CST 2021 -VERSION_CODE=196 +#Sat May 15 22:50:54 CST 2021 +VERSION_CODE=199