pull/5/head
fengyuecanzhu 4 years ago
parent 306e30ae70
commit dae4748674
  1. 4
      .idea/assetWizardSettings.xml
  2. 6
      app/src/main/assets/updatelog.fy
  3. 3
      app/src/main/java/xyz/fycz/myreader/application/App.java
  4. 149
      app/src/main/java/xyz/fycz/myreader/application/CrashHandler.java
  5. 1
      app/src/main/java/xyz/fycz/myreader/base/BaseActivity.java
  6. 50
      app/src/main/java/xyz/fycz/myreader/base/BitIntentDataManager.java
  7. 1
      app/src/main/java/xyz/fycz/myreader/common/APPCONST.java
  8. 4
      app/src/main/java/xyz/fycz/myreader/entity/sourceedit/EditEntityUtil.kt
  9. 6
      app/src/main/java/xyz/fycz/myreader/entity/thirdsource/ThirdSourceUtil.java
  10. 54
      app/src/main/java/xyz/fycz/myreader/greendao/entity/Book.java
  11. 14
      app/src/main/java/xyz/fycz/myreader/greendao/entity/rule/FindRule.java
  12. 25
      app/src/main/java/xyz/fycz/myreader/greendao/entity/rule/InfoRule.java
  13. 16
      app/src/main/java/xyz/fycz/myreader/model/sourceAnalyzer/BookSourceManager.java
  14. 33
      app/src/main/java/xyz/fycz/myreader/model/third2/analyzeRule/AnalyzeByRegex.java
  15. 29
      app/src/main/java/xyz/fycz/myreader/model/third2/content/BookInfo.java
  16. 72
      app/src/main/java/xyz/fycz/myreader/model/third2/content/BookList.java
  17. 49
      app/src/main/java/xyz/fycz/myreader/ui/activity/BookDetailedActivity.java
  18. 3
      app/src/main/java/xyz/fycz/myreader/ui/activity/BookstoreActivity.java
  19. 12
      app/src/main/java/xyz/fycz/myreader/ui/activity/ReadActivity.java
  20. 3
      app/src/main/java/xyz/fycz/myreader/ui/activity/SearchBookActivity.java
  21. 1
      app/src/main/java/xyz/fycz/myreader/ui/activity/SourceDebugActivity.java
  22. 18
      app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/SearchBookHolder.java
  23. 4
      app/src/main/java/xyz/fycz/myreader/util/help/JsExtensions.java
  24. 6
      app/src/main/java/xyz/fycz/myreader/util/utils/AdUtils.java
  25. 2
      app/src/main/java/xyz/fycz/myreader/util/utils/MD5Utils.kt
  26. 2
      app/src/main/java/xyz/fycz/myreader/webapi/BookApi.java
  27. 31
      app/src/main/java/xyz/fycz/myreader/webapi/ThirdSourceApi.java
  28. 7
      app/src/main/res/drawable/ic_source.xml
  29. 6
      app/src/main/res/layout/fragment_mine.xml
  30. 5
      app/src/main/res/menu/menu_book_detail.xml
  31. 6
      app/src/main/res/menu/menu_read.xml
  32. 3
      app/src/main/res/values/strings.xml
  33. 4
      app/version_code.properties

@ -14,8 +14,8 @@
<option name="values">
<map>
<entry key="assetSourceType" value="FILE" />
<entry key="outputName" value="ic_edit" />
<entry key="sourceFile" value="F:\SVG图标\编辑.svg" />
<entry key="outputName" value="ic_source" />
<entry key="sourceFile" value="F:\SVG图标\代码.svg" />
</map>
</option>
</PersistentState>

@ -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

@ -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);

@ -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;
}
}

@ -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;

@ -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<String, Object> 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);
}
}

@ -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";

@ -52,6 +52,8 @@ object EditEntityUtil {
fun getInfoEntities(infoRule: InfoRule? = InfoRule()): List<EditEntity> {
val infoEntities: ArrayList<EditEntity> = 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

@ -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;
}

@ -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,6 +77,9 @@ public class Book implements Serializable {
@Transient
private Map<String, String> variableMap;
@Transient
private Map<String, String> catheMap;
@Generated(hash = 1839243756)
public Book() {
}
@ -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);
}
}

@ -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);
}
}

@ -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;

@ -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;
}

@ -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);
}
}

@ -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<Book> 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,6 +43,29 @@ public class BookInfo {
AnalyzeRule analyzer = new AnalyzeRule(book);
analyzer.setContent(s, baseUrl);
// 获取详情页预处理规则
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);
@ -76,9 +100,10 @@ public class BookInfo {
if (isEmpty(bookCatalogUrl)) bookCatalogUrl = baseUrl;
book.setChapterUrl(bookCatalogUrl);
//如果目录页和详情页相同,暂存页面内容供获取目录用
//if (bookCatalogUrl.equals(baseUrl)) bookInfoBean.setChapterListHtml(s);
if (bookCatalogUrl.equals(baseUrl)) book.putCathe("ChapterListHtml", s);
Log.d(tag, "└" + book.getChapterUrl());
Log.d(tag, "-详情页解析完成");
}
e.onNext(book);
e.onComplete();
});

@ -65,7 +65,15 @@ public class BookList {
AnalyzeRule analyzer = new AnalyzeRule(null);
analyzer.setContent(body, baseUrl);
//如果符合详情页url规则
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 {
initRule();
List<Object> collections;
boolean reverse = false;
@ -87,11 +95,11 @@ public class BookList {
//获取列表
Log.d(tag, "┌解析搜索列表");
collections = analyzer.getElements(ruleList);
if (collections.size() == 0) {
if (collections.size() == 0 && isEmpty(bookSource.getInfoRule().getUrlPattern())) {
Log.d(tag, "└搜索列表为空,当做详情页处理");
Book item = getItem(analyzer, baseUrl);
if (item != null) {
//item.setBookInfoHtml(body);
item.putCathe("BookInfoHtml", body);
books.add(item);
}
} else {
@ -102,9 +110,9 @@ public class BookList {
Book item = getItemAllInOne(analyzer, object, baseUrl, i == 0);
if (item != null) {
//如果网址相同则缓存
/*if (baseUrl.equals(item.getNoteUrl())) {
item.setBookInfoHtml(body);
}*/
if (baseUrl.equals(item.getInfoUrl())) {
item.putCathe("BookInfoHtml", body);
}
books.add(item);
}
}
@ -115,9 +123,9 @@ public class BookList {
Book item = getItemInList(analyzer, baseUrl, i == 0);
if (item != null) {
//如果网址相同则缓存
/*if (baseUrl.equals(item.getNoteUrl())) {
item.setBookInfoHtml(body);
}*/
if (baseUrl.equals(item.getInfoUrl())) {
item.putCathe("BookInfoHtml", body);
}
books.add(item);
}
}
@ -127,6 +135,7 @@ public class BookList {
if (books.size() > 1 && reverse) {
Collections.reverse(books);
}
}
if (books.isEmpty()) {
e.onError(new Throwable("未获取到书名"));
return;
@ -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;
@ -218,7 +239,7 @@ public class BookList {
if (printLog) Log.d(tag, "└" + item.getAuthor());
if (printLog) Log.d(tag, "┌获取分类");
item.setType(String.valueOf(nativeObject.get(ruleKind)));
if (printLog) Log.d(tag,"└" + item.getType());
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());
@ -232,8 +253,8 @@ public class BookList {
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;
@ -268,8 +289,8 @@ public class BookList {
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 {

@ -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<String> 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();
if (!isThirdSource()) {
initChapters(true);
mCatalogAdapter.notifyDataSetChanged();
}
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<Book>) getIntent().getSerializableExtra(APPCONST.SEARCH_BOOK_BEAN);
aBooks = (ArrayList<Book>) 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<Chapter>) 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<Book>() {
@ -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;
}
}

@ -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<Book>) mSourceDia.getaBooks());
BitIntentDataManager.getInstance().putData(intent, mSourceDia.getaBooks());
intent.putExtra(APPCONST.SOURCE_INDEX, pos1);
BookstoreActivity.this.startActivity(intent);
mSourceDia.dismiss();

@ -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);
}

@ -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);

@ -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:

@ -78,7 +78,8 @@ public class SearchBookHolder extends ViewHolderImpl<SearchBookBean> {
public void onBind(SearchBookBean data, int pos) {
List<Book> 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<SearchBookBean> {
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<SearchBookBean> {
}
}
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;

@ -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();

@ -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());
}
}

@ -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

@ -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;

@ -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<Book> 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<String, String> headers = rc.getHeaders();
headers.putAll(getCookies(rc.getNameSpace()));
@ -75,13 +78,13 @@ public class ThirdSourceApi {
protected static Observable<List<Chapter>> getBookChaptersByTC(Book book, ThirdCrawler rc) {
BookSource source = rc.getSource();
BookChapterList bookChapterList = new BookChapterList(source.getSourceUrl(), source, true);
/*if (!TextUtils.isEmpty(bookShelfBean.getBookInfoBean().getChapterListHtml())) {
return bookChapterList.analyzeChapterList(bookShelfBean.getBookInfoBean().getChapterListHtml(), bookShelfBean, headerMap);
}*/
try {
Map<String, String> headers = rc.getHeaders();
headers.putAll(getCookies(rc.getNameSpace()));
BookChapterList bookChapterList = new BookChapterList(source.getSourceUrl(), source, true);
if (!TextUtils.isEmpty(book.getCathe("ChapterListHtml"))) {
return bookChapterList.analyzeChapterList(book.getCathe("ChapterListHtml"), book, headers);
}
try {
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<String> getChapterContentByTC(Chapter chapter, Book book, ThirdCrawler rc) {
BookSource source = rc.getSource();
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);
}*/
try {
Map<String, String> headers = rc.getHeaders();
headers.putAll(getCookies(rc.getNameSpace()));
BookContent bookContent = new BookContent(source.getSourceUrl(), source);
if (Objects.equals(chapter.getUrl(), book.getChapterUrl())
&& !TextUtils.isEmpty(book.getCathe("ChapterListHtml"))) {
return bookContent.analyzeBookContent(book.getCathe("ChapterListHtml"), chapter, null, book, headers);
}
try {
AnalyzeUrl analyzeUrl = new AnalyzeUrl(chapter.getUrl(), headers, book.getChapterUrl());
String contentRule = source.getContentRule().getContent();
if (contentRule.startsWith("$") && !contentRule.startsWith("$.")) {

@ -4,9 +4,6 @@
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:fillColor="#FF000000"
android:pathData="M681.1,87.8C717,33.2 766.6,5.9 831.5,14.9c60.6,8.3 102.8,43.6 120.9,101.9 21.1,67.7 -1,123.5 -55.5,167.8 3.7,7.6 7.7,15.5 11.4,23.4 19.5,41.6 32,85.3 37.4,131 8.9,75.6 -0.4,148.9 -29.3,219.4 -30.1,73.3 -76.7,134.1 -139.3,182.6 -36.1,27.9 -75.7,49.5 -118.6,65 -4.1,1.5 -6.2,3.6 -7.8,7.8 -22.4,58.1 -64.2,92.5 -126.2,99.2 -69.5,7.5 -133,-34.2 -155.5,-100.1 -1.1,-3.2 -2.8,-4.8 -5.9,-5.9 -112.8,-41.4 -196.2,-116 -249.5,-223.6 -23.6,-47.7 -37.2,-98.3 -41.7,-151.3 -7.4,-85.9 8.6,-167 48.3,-243.5l1.9,-3.8c-43.9,-33 -66.5,-76.6 -63.7,-131.7 2.3,-43.5 21.2,-79.4 55,-106.9 69.3,-56.4 175.1,-40 223.4,42.1C391.7,64.8 449.2,53.1 509,53c59.7,0 117.1,11.5 172.1,34.8zM656.7,837.8c2.1,-0.8 3.7,-1.5 5.4,-2.2 24.7,-11 48.1,-24.5 69.8,-40.6 56.4,-41.9 98.4,-95.2 125.1,-160.2 24.7,-60.4 33.1,-123.1 25.2,-188 -5.8,-47.5 -20.3,-92.1 -42.9,-134.2 -1.6,-3 -3.4,-3.4 -6.7,-3.3 -13.8,0.4 -27.8,2 -41.3,0.2 -77.8,-10.7 -132.2,-76.6 -129,-155 0.2,-3.8 -1,-5.5 -4.4,-7 -35,-14.9 -71.4,-24.4 -109.3,-28.4 -35.3,-3.7 -70.5,-2.3 -105.5,3.9 -28.6,5.1 -56.2,13.5 -83,24.9 -3.5,1.5 -4.3,3.4 -4.3,7.1 0,9 0.1,18.1 -1.2,26.9 -12,83.2 -86,138.8 -169.2,127.6 -1.6,-0.2 -4.2,1 -5,2.4 -3.7,6.5 -7.2,13.2 -10.3,19.9 -30.6,65.6 -41.9,134.3 -33.2,206.3 5,41.9 16.7,81.8 35.4,119.5 35,70.5 87,125.1 155.7,163.5 11.3,6.3 23,11.6 34.8,17.6 12.5,-75.1 83.1,-126.8 155,-122.6 66.9,3.9 124.7,51.3 138.9,121.7zM292,162c0,-46.7 -38,-84.9 -84.8,-85 -46.7,-0.1 -84.9,37.9 -85.2,84.7 -0.2,46.9 38.2,85.3 85.1,85.3 46.7,-0.1 84.8,-38.2 84.9,-85zM811,247c46.7,0 84.9,-38.1 85,-84.8 0.1,-46.7 -37.9,-84.9 -84.7,-85.1 -46.9,-0.2 -85.3,38.2 -85.3,85.1 0.1,46.7 38.2,84.8 85,84.8zM425,865c0,46.7 38.1,84.9 84.8,85 46.7,0.1 84.9,-37.9 85.1,-84.7 0.2,-46.9 -38.2,-85.3 -85.1,-85.3 -46.7,0.1 -84.8,38.2 -84.8,85z"/>
<path
android:fillColor="#FF000000"
android:pathData="M659,492.9c0,82.3 -66.8,149.1 -149,149.1 -82.3,0 -149.1,-66.9 -149,-149.2 0.1,-82.1 66.7,-148.7 148.8,-148.8 82.3,-0.1 149.1,66.6 149.2,148.9zM595,493.2c0.2,-46.7 -37.9,-85 -84.7,-85.2 -46.7,-0.2 -85,37.7 -85.3,84.5 -0.3,46.9 38,85.4 84.9,85.4 46.7,0.1 84.9,-37.9 85.1,-84.7z"/>
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"/>
</vector>

@ -159,8 +159,8 @@
<ImageView
android:id="@+id/iv_book_source"
android:layout_width="18dp"
android:layout_height="18dp"
android:layout_width="21dp"
android:layout_height="21dp"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:src="@drawable/ic_source"
@ -171,7 +171,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginStart="20dp"
android:layout_marginStart="18dp"
android:layout_toEndOf="@id/iv_book_source"
android:text="@string/book_source_man"
android:textColor="@color/textSecondary"

@ -44,4 +44,9 @@
android:icon="@drawable/ic_group"
android:title="@string/menu_group_setting"
app:showAsAction="never" />
<item
android:id="@+id/action_edit_source"
android:icon="@drawable/ic_source"
android:title="@string/book_source"
app:showAsAction="ifRoom"/>
</menu>

@ -41,4 +41,10 @@
android:title="@string/menu_open_link"
app:showAsAction="never"/>
</group>
<item
android:id="@+id/action_edit_source"
android:icon="@drawable/ic_source"
android:title="@string/book_source"
app:showAsAction="ifRoom"/>
</menu>

@ -388,7 +388,7 @@
<string name="rule_last_chapter">最新章节规则</string>
<string name="rule_word_count">字数规则</string>
<string name="rule_status">连载状态规则</string>
<string name="book_url_pattern">书籍URL正则</string>
<string name="book_url_pattern">书籍详情URL正则</string>
<string name="rule_book_info_init">预处理规则</string>
<string name="rule_toc_url">目录URL规则</string>
<string name="rule_toc_internal">目录列表区间</string>
@ -486,6 +486,7 @@
<string name="success">成功</string>
<string name="check_host_cookie">正在打开首页,成功自动返回主界面</string>
<string name="clear_cookie">清除Cookie</string>
<string name="book_source">编辑书源</string>
<string-array name="reset_screen_time">

@ -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

Loading…
Cancel
Save