新增5个书源

pull/5/head
fengyuecanzhu 4 years ago
parent 3be4cf4fa8
commit fdea628154
  1. BIN
      .idea/caches/build_file_checksums.ser
  2. 10
      README.md
  3. 7
      app/build.gradle
  4. 4
      app/src/androidTest/java/xyz/fycz/myreader/ExampleInstrumentedTest.java
  5. 4
      app/src/androidTest/java/xyz/fycz/myreader/TestAudioPlay.java
  6. 2
      app/src/main/AndroidManifest.xml
  7. 6
      app/src/main/assets/updatelog.fy
  8. 53
      app/src/main/java/xyz/fycz/myreader/application/MyApplication.java
  9. 53
      app/src/main/java/xyz/fycz/myreader/application/SysManager.java
  10. 2
      app/src/main/java/xyz/fycz/myreader/common/APPCONST.java
  11. 212
      app/src/main/java/xyz/fycz/myreader/entity/ContactsTree.java
  12. 36
      app/src/main/java/xyz/fycz/myreader/entity/Custom.java
  13. 201
      app/src/main/java/xyz/fycz/myreader/entity/Time.java
  14. 37
      app/src/main/java/xyz/fycz/myreader/entity/UpdateInfo.java
  15. 5
      app/src/main/java/xyz/fycz/myreader/enums/BookSource.java
  16. 200
      app/src/main/java/xyz/fycz/myreader/model/audio/ReadService.java
  17. 2
      app/src/main/java/xyz/fycz/myreader/ui/activity/BookDetailedActivity.java
  18. 2
      app/src/main/java/xyz/fycz/myreader/ui/activity/QRCodeScanActivity.java
  19. 4
      app/src/main/java/xyz/fycz/myreader/ui/activity/ReadActivity.java
  20. 11
      app/src/main/java/xyz/fycz/myreader/ui/activity/SplashActivity.java
  21. 5
      app/src/main/java/xyz/fycz/myreader/ui/dialog/AudioPlayerDialog.java
  22. 6
      app/src/main/java/xyz/fycz/myreader/ui/presenter/BookcasePresenter.java
  23. 44
      app/src/main/java/xyz/fycz/myreader/util/utils/MD5Utils.java
  24. 158
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/read/HongChenReadCrawler.java
  25. 210
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/read/LaoYaoReadCrawler.java
  26. 204
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/read/ShiGuangReadCrawler.java
  27. 1
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/read/TianLaiReadCrawler.java
  28. 166
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/read/XiaGuReadCrawler.java
  29. 158
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/read/XingXingReadCrawler.java
  30. 6
      app/src/main/res/layout/activity_read.xml
  31. 440
      app/src/main/res/layout/layout_about_content.xml
  32. 4
      app/src/main/res/layout/menu_auto_page.xml
  33. 8
      app/src/main/res/layout/menu_brightness_eye.xml
  34. 16
      app/src/main/res/layout/menu_cumtomize_layout.xml
  35. 19
      app/src/main/res/values/strings.xml
  36. 5
      app/src/main/resources/crawler.properties
  37. 4
      app/version_code.properties
  38. 1
      build.gradle

@ -2,16 +2,18 @@
风月读书,一款开源、无广告的小说阅读软件。
成品下载:[https://fycz.lanzoui.com/ib8ZJivckmd](https://fycz.lanzoui.com/ib8ZJivckmd)
成品下载:[https://fycz.lanzoui.com/iqvwqj3kr5e](https://fycz.lanzoui.com/iqvwqj3kr5e)
#### 一、关于书源
* 软件内置了20个书源如下:
* 软件内置了25个书源如下:
* 16个网络小说书源:天籁小说、笔趣阁44、品书网、笔趣阁、
* 21个网络小说书源:天籁小说、笔趣阁44、品书网、笔趣阁、
全本小说、米趣小说、九桃小说、云中书库、
搜小说网、全小说网、奇奇小说、妙笔阁、
丹书铁券、小说旗、读一读网、飘天文学
丹书铁券、小说旗、读一读网、飘天文学、
老幺小说、星星小说、时光小说、峡谷文学、
红尘小说
* 4个实体书书源:超星图书·实体、作品集·实体、99藏书·实体、100本·实体
* 如何自行制作并添加书源.

@ -21,7 +21,7 @@ def getVersionCode() {
}
return versionCode
} else {
throw new GradleException("无法读取version_code.properties文件!")
throw new FileNotFoundException("无法读取version_code.properties文件!")
}
}
def name = "风月读书"
@ -162,6 +162,11 @@ dependencies {
//
implementation 'cn.bingoogolapple:bga-qrcode-zxing:1.3.7'
//Material Dialogs
/*//email
implementation 'com.sun.mail:android-mail:1.6.2'
implementation 'com.sun.mail:android-activation:1.6.2'*/
/*def dialog_version = '3.3.0'
implementation "com.afollestad.material-dialogs:core:$dialog_version"
implementation "com.afollestad.material-dialogs:input:$dialog_version"

@ -9,8 +9,6 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import xyz.fycz.myreader.model.audio.ReadService;
import static org.junit.Assert.assertEquals;
/**
@ -29,7 +27,7 @@ public class ExampleInstrumentedTest {
@Test
public void test() {
ReadService readService = new ReadService();
//ReadService readService = new ReadService();
//readService.initSynthesizer();
//readService.startSynthesizer("科幻电影是我们从小就爱看的电影题材,我们也都梦想过生活在那样的科幻世界里。科幻片,顾名思义即“科学幻想片”,是“以科学幻想为内容的故事片,其基本特点是从今天已知的科学原理和科学成就出发,对未来的世界或遥远的过去的情景作幻想式的描述。”");
}

@ -4,13 +4,11 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.runner.RunWith;
import xyz.fycz.myreader.model.audio.ReadService;
@RunWith(AndroidJUnit4.class)
public class TestAudioPlay {
public void test() {
ReadService readService = new ReadService();
//ReadService readService = new ReadService();
//readService.initSynthesizer();
//readService.startSynthesizer("科幻电影是我们从小就爱看的电影题材,我们也都梦想过生活在那样的科幻世界里。科幻片,顾名思义即“科学幻想片”,是“以科学幻想为内容的故事片,其基本特点是从今天已知的科学原理和科学成就出发,对未来的世界或遥远的过去的情景作幻想式的描述。”");
}

@ -52,7 +52,6 @@
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/shortcuts" />
@ -106,7 +105,6 @@
<receiver android:name=".util.notification.NotificationClickReceiver"/>
<receiver android:name=".ui.presenter.BookcasePresenter$cancelDownloadReceiver"/>
<service android:name=".model.audio.ReadService"/>
<service android:name=".model.audio.ReadAloudService"/>
</application>

@ -1,5 +1,9 @@
2020.12.06
风月读书v1.20.120612
1、新增书架排序设置
2、新增书籍分享(以图片+二维码的形式分享)及扫一扫
2、新增书籍分享(以图片+二维码的形式分享)及扫一扫(书架菜单)
3、新增书源:老幺小说、星星小说、时光小说、峡谷文学、红尘小说
4、修复欢迎页图片概率性未完全加载的bug
2020.11.28
风月读书v1.20.112822

@ -13,18 +13,16 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.Handler;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;
import io.reactivex.internal.functions.Functions;
import io.reactivex.plugins.RxJavaPlugins;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
@ -41,25 +39,28 @@ import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import io.reactivex.internal.functions.Functions;
import io.reactivex.plugins.RxJavaPlugins;
import xyz.fycz.myreader.R;
import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.common.URLCONST;
import xyz.fycz.myreader.model.backup.UserService;
import xyz.fycz.myreader.model.storage.Backup;
import xyz.fycz.myreader.ui.dialog.APPDownloadTip;
import xyz.fycz.myreader.ui.dialog.DialogCreator;
import xyz.fycz.myreader.entity.Setting;
import xyz.fycz.myreader.entity.UpdateInfo;
import xyz.fycz.myreader.ui.activity.MainActivity;
import xyz.fycz.myreader.ui.dialog.APPDownloadTip;
import xyz.fycz.myreader.ui.dialog.DialogCreator;
import xyz.fycz.myreader.ui.fragment.BookcaseFragment;
import xyz.fycz.myreader.util.*;
import xyz.fycz.myreader.util.llog.LLog;
import xyz.fycz.myreader.util.HttpUtil;
import xyz.fycz.myreader.util.SharedPreUtils;
import xyz.fycz.myreader.util.StringHelper;
import xyz.fycz.myreader.util.ToastUtils;
import xyz.fycz.myreader.util.utils.FileUtils;
import xyz.fycz.myreader.util.utils.NetworkUtils;
import xyz.fycz.myreader.webapi.callback.ResultCallback;
import xyz.fycz.myreader.util.utils.OkHttpUtils;
public class MyApplication extends Application {
public static final String TAG = MyApplication.class.getSimpleName();
private static Handler handler = new Handler();
private static MyApplication application;
private ExecutorService mFixedThreadPool;
@ -238,16 +239,18 @@ public class MyApplication extends Application {
}
/**
* 检查更新
* 获取apk包的信息版本号名称图标等
* @param absPath apk包的绝对路径
*/
public static void checkVersion(AppCompatActivity activity) {
UpdateInfo updateInfo = (UpdateInfo) CacheHelper.readObject(APPCONST.FILE_NAME_UPDATE_INFO);
int versionCode = getVersionCode();
if (updateInfo != null) {
if (updateInfo.getNewestVersionCode() > versionCode) {
//updateApp(activity, updateInfo.getDownLoadUrl(), versionCode);
}
public static int apkInfo(String absPath) {
PackageManager pm = application.getPackageManager();
PackageInfo pkgInfo = pm.getPackageArchiveInfo(absPath, PackageManager.GET_ACTIVITIES);
if (pkgInfo != null) {
int versionCode = pkgInfo.versionCode;
Log.i(TAG, String.format("PkgInfo: %s", versionCode));
return versionCode;
}
return 0;
}
@ -257,13 +260,13 @@ public class MyApplication extends Application {
public static void checkVersionByServer(final AppCompatActivity activity, final boolean isManualCheck,
final BookcaseFragment mBookcaseFragment) {
MyApplication.getApplication().newThread(() -> {
Document doc = null;
try {
String url = "https://shimo.im/docs/cqkgjPRRydYYhQKt/read";
if (isApkInDebug(getmContext())) {
url = "https://shimo.im/docs/zfzpda7MUGskOC9v/read";
}
doc = Jsoup.connect(url).get();
String html = OkHttpUtils.getHtml(url);
Document doc = Jsoup.parse(html);
String content = doc.getElementsByClass("ql-editor").text();
if (StringHelper.isEmpty(content)) {
if (isManualCheck || NetworkUtils.isNetWorkAvailable()) {
@ -289,6 +292,7 @@ public class MyApplication extends Application {
spu.putBoolean("needUdSI", !oldSplashTime.equals(newSplashTime));
spu.putString("splashTime", contents[5].substring(contents[5].indexOf(":") + 1));
spu.putString("splashImageUrl", contents[6].substring(contents[6].indexOf(":") + 1));
spu.putString("splashImageMD5", contents[7].substring(contents[7].indexOf(":") + 1));
if (!StringHelper.isEmpty(downloadLink)) {
spu.putString(getmContext().getString(R.string.downloadLink), downloadLink);
@ -354,6 +358,11 @@ public class MyApplication extends Application {
if (activity instanceof MainActivity){
MainActivity mainActivity = (MainActivity) activity;
mainActivity.getViewPagerMain().setCurrentItem(0);
String filePath = APPCONST.UPDATE_APK_FILE_DIR + "FYReader.apk";
if (apkInfo(filePath) == versionCode){
mainActivity.installApk(FileUtils.getFile(filePath), isForceUpdate);
return;
}
}
if (url == null || "".equals(url)) {
ToastUtils.showError("获取链接失败,请前往浏览器下载!");

@ -1,5 +1,7 @@
package xyz.fycz.myreader.application;
import android.util.Log;
import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.enums.BookSource;
import xyz.fycz.myreader.enums.BookcaseStyle;
@ -27,19 +29,21 @@ public class SysManager {
/**
* 获取设置
*
* @return
*/
public static Setting getSetting() {
if (mSetting != null){
if (mSetting != null) {
return mSetting;
}
mSetting = (Setting) CacheHelper.readObject(APPCONST.FILE_NAME_SETTING);
if (mSetting == null){
if (mSetting == null) {
mSetting = getDefaultSetting();
saveSetting(mSetting);
}
return mSetting;
}
public static Setting getNewSetting() {
Setting setting = (Setting) CacheHelper.readObject(APPCONST.FILE_NAME_SETTING);
if (setting == null) {
@ -50,10 +54,11 @@ public class SysManager {
}
/**
* 保存设置
* @param setting
*/
/**
* 保存设置
*
* @param setting
*/
public static void saveSetting(Setting setting) {
CacheHelper.saveObject(setting, APPCONST.FILE_NAME_SETTING);
}
@ -61,9 +66,10 @@ public class SysManager {
/**
* 默认设置
*
* @return
*/
private static Setting getDefaultSetting(){
private static Setting getDefaultSetting() {
Setting setting = new Setting();
setting.setDayStyle(true);
setting.setBookcaseStyle(BookcaseStyle.listMode);
@ -82,7 +88,7 @@ public class SysManager {
return setting;
}
public static void regetmSetting(){
public static void regetmSetting() {
mSetting = (Setting) CacheHelper.readObject(APPCONST.FILE_NAME_SETTING);
}
@ -91,19 +97,36 @@ public class SysManager {
* 重置设置
*/
public static void resetSetting(){
public static void resetSetting() {
Setting setting = getSetting();
setting.initReadStyle();
setting.setCurReadStyleIndex(1);
setting.setSharedLayout(true);
switch (setting.getSettingVersion()) {
case 10:
setting.initReadStyle();
setting.setCurReadStyleIndex(1);
setting.setSharedLayout(true);
Log.d("SettingVersion", "" + 10);
case 11:
Log.d("SettingVersion", "" + 11);
case 12:
Log.d("SettingVersion", "" + 12);
}
setting.setSettingVersion(APPCONST.SETTING_VERSION);
saveSetting(setting);
}
public static void resetSource(){
public static void resetSource() {
Setting setting = getSetting();
ReadCrawlerUtil.addReadCrawler(BookSource.miaobi, BookSource.dstq, BookSource.xs7, BookSource.du1du,BookSource.paiotian);
ReadCrawlerUtil.removeReadCrawler("cangshu99");
switch (setting.getSourceVersion()) {
case 0:
ReadCrawlerUtil.addReadCrawler(BookSource.miaobi, BookSource.dstq, BookSource.xs7, BookSource.du1du, BookSource.paiotian);
ReadCrawlerUtil.removeReadCrawler("cangshu99");
Log.d("SourceVersion", "" + 0);
case 1:
ReadCrawlerUtil.addReadCrawler(BookSource.laoyao, BookSource.xingxing, BookSource.shiguang, BookSource.xiagu, BookSource.hongchen);
Log.d("SourceVersion", "" + 1);
case 2:
Log.d("SourceVersion", "" + 2);
}
setting.setSourceVersion(APPCONST.SOURCE_VERSION);
saveSetting(setting);
}

@ -92,7 +92,7 @@ public class APPCONST {
//设置版本号
public static final int SETTING_VERSION = 11;
public static final int SOURCE_VERSION = 1;
public static final int SOURCE_VERSION = 2;
public static final String FORMAT_FILE_DATE = "yyyy-MM-dd";

@ -1,212 +0,0 @@
package xyz.fycz.myreader.entity;
import java.io.Serializable;
import java.util.ArrayList;
/**
* Created by zhao on 2016/11/9.
* APP通迅录树结构
*
*/
public class ContactsTree implements Serializable {
private static final long serialVersionUID = 7184368467231587092L;
//根节点赋值字段(部门节点)
private String DepartId;//部门id
private String DepartName;//部门名
private String orgCode; //部门编码
private String departOrder; //部门排序
private boolean select;
//叶节点赋值字段(个人信息节点)
private String id;
private String userDepartId;//用户所属部门ID
private String userDepartName;//用户所属部门名
private boolean moreDepartUser;// 用户是否多部门 true是 false不是
private boolean transpondPerson;//是否转发人员 true是 false不是
private String userName;//用户名
private String realName;//姓名
private String wholeSpellName;//姓名全拼
private String firstLetterName;//拼音首字母 eg:hzh
private String mobilePhone;//手机
private String sex;//性别
private String email;//邮箱
private ArrayList<ContactsTree> children;//孩子节点
private ContactsTree parent;//父节点
public boolean isTranspondPerson() {
return transpondPerson;
}
public void setTranspondPerson(boolean transpondPerson) {
this.transpondPerson = transpondPerson;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getDepartOrder() {
return departOrder;
}
public String getOrgCode() {
return orgCode;
}
public void setDepartOrder(String departOrder) {
this.departOrder = departOrder;
}
public void setOrgCode(String orgCode) {
this.orgCode = orgCode;
}
public boolean isMoreDepartUser() {
return moreDepartUser;
}
public void setMoreDepartUser(boolean moreDepartUser) {
this.moreDepartUser = moreDepartUser;
}
public String getUserDepartId() {
return userDepartId;
}
public String getUserDepartName() {
return userDepartName;
}
public void setUserDepartId(String userDepartId) {
this.userDepartId = userDepartId;
}
public void setUserDepartName(String userDepartName) {
this.userDepartName = userDepartName;
}
public boolean isSelect() {
return select;
}
public void setSelect(boolean select) {
this.select = select;
}
public ContactsTree getParent() {
return parent;
}
public void setParent(ContactsTree parent) {
this.parent = parent;
}
public ContactsTree(){
children = new ArrayList<>();
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getMobilePhone() {
return mobilePhone;
}
public void setMobilePhone(String mobilePhone) {
this.mobilePhone = mobilePhone;
}
public ArrayList<ContactsTree> getChildren() {
return children;
}
public String getDepartId() {
return DepartId;
}
public String getDepartName() {
return DepartName;
}
public String getFirstLetterName() {
return firstLetterName;
}
public String getRealName() {
return realName;
}
public String getUserName() {
return userName;
}
public String getWholeSpellName() {
return wholeSpellName;
}
public void setChildren(ArrayList<ContactsTree> children) {
this.children = children;
}
public void setDepartId(String departId) {
DepartId = departId;
}
public void setDepartName(String departName) {
DepartName = departName;
}
public void setFirstLetterName(String firstLetterName) {
this.firstLetterName = firstLetterName;
}
public void setRealName(String realName) {
this.realName = realName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public void setWholeSpellName(String wholeSpellName) {
this.wholeSpellName = wholeSpellName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "ContactsTree{" +
"DepartId='" + DepartId + '\'' +
", DepartName='" + DepartName + '\'' +
", userName='" + userName + '\'' +
", realName='" + realName + '\'' +
", wholeSpellName='" + wholeSpellName + '\'' +
", firstLetterName='" + firstLetterName + '\'' +
", mobilePhone='" + mobilePhone + '\'' +
", sex='" + sex + '\'' +
", email='" + email + '\'' +
", children=" + children +
'}';
}
}

@ -1,36 +0,0 @@
package xyz.fycz.myreader.entity;
import java.io.Serializable;
public class Custom implements Serializable {
private static final long serialVersionUID = 5088810102696918656L;
private String id;
private String type;//类型
public String getId() {
return id;
}
public String getType() {
return type;
}
public void setId(String id) {
this.id = id;
}
public void setType(String type) {
this.type = type;
}
@Override
public String toString() {
return "Custom{" +
"id='" + id + '\'' +
", type='" + type + '\'' +
'}';
}
}

@ -1,201 +0,0 @@
package xyz.fycz.myreader.entity;
import android.os.Parcel;
import android.os.Parcelable;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Time implements Parcelable{
private int year;
private int month;
private int date;
private int hour;
private int minute;
private int second;
public long getLongTime(){
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(year);
if(month < 10){
stringBuilder.append("0"+month);
}else {
stringBuilder.append(month);
}
if(date < 10){
stringBuilder.append("0" + date);
}else {
stringBuilder.append(date);
}
if(hour < 10){
stringBuilder.append("0" + hour);
}else {
stringBuilder.append(hour);
}
if(minute < 10){
stringBuilder.append("0" + minute);
}else {
stringBuilder.append(minute);
}
if(second < 10){
stringBuilder.append("0" + second);
}else {
stringBuilder.append(second);
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
java.util.Date date = null;
try {
date = sdf.parse(stringBuilder.toString());
return date.getTime();
} catch (ParseException e) {
e.printStackTrace();
return 0;
}
}
public void init(Date date){
year = date.getYear() + 1900;
month = date.getMonth() + 1;
this.date = date.getDate();
hour = date.getHours();
minute = date.getMinutes();
second = 0;
}
public void init(xyz.fycz.myreader.entity.Date date){
Date date1 = new Date();
year = date.getYear();
month = date.getMonth();
this.date = date.getDate();
hour = date1.getHours();
minute = date1.getMinutes();
second = 0;
}
public void setToDayZero(){
hour = 0;
minute = 0;
second = 0;
}
public void setToDayLast(){
hour = 23;
minute = 59;
second = 59;
}
public void lastMonth(){
if(month == 1){
month = 12;
year = year - 1;
}else {
month = month - 1;
}
}
public void nextMonth(){
if(month == 12){
month = 1;
year = year + 1;
}else {
month = month + 1;
}
}
public void init(long time){
Date date = new Date(time);
init(date);
}
public int getDate() {
return date;
}
public int getHour() {
return hour;
}
public int getMinute() {
return minute;
}
public int getMonth() {
return month;
}
public int getSecond() {
return second;
}
public int getYear() {
return year;
}
public void setDate(int date) {
this.date = date;
}
public void setHour(int hour) {
this.hour = hour;
}
public void setMinute(int minute) {
this.minute = minute;
}
public void setMonth(int month) {
this.month = month;
}
public void setSecond(int second) {
this.second = second;
}
public void setYear(int year) {
this.year = year;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(this.year);
dest.writeInt(this.month);
dest.writeInt(this.date);
dest.writeInt(this.hour);
dest.writeInt(this.minute);
dest.writeInt(this.second);
}
public Time() {
}
protected Time(Parcel in) {
this.year = in.readInt();
this.month = in.readInt();
this.date = in.readInt();
this.hour = in.readInt();
this.minute = in.readInt();
this.second = in.readInt();
}
public static final Creator<Time> CREATOR = new Creator<Time>() {
@Override
public Time createFromParcel(Parcel source) {
return new Time(source);
}
@Override
public Time[] newArray(int size) {
return new Time[size];
}
};
}

@ -1,37 +0,0 @@
package xyz.fycz.myreader.entity;
import java.io.Serializable;
public class UpdateInfo implements Serializable{
private static final long serialVersionUID = 8136214121542689902L;
private int newestVersionCode;
private String newestVersionName;
private String downLoadUrl;
public int getNewestVersionCode() {
return newestVersionCode;
}
public void setNewestVersionCode(int newestVersionCode) {
this.newestVersionCode = newestVersionCode;
}
public String getNewestVersionName() {
return newestVersionName;
}
public void setNewestVersionName(String newestVersionName) {
this.newestVersionName = newestVersionName;
}
public String getDownLoadUrl() {
return downLoadUrl;
}
public void setDownLoadUrl(String downLoadUrl) {
this.downLoadUrl = downLoadUrl;
}
}

@ -27,6 +27,11 @@ public enum BookSource {
xs7(MyApplication.getApplication().getString(R.string.read_xs7)),
du1du(MyApplication.getApplication().getString(R.string.read_du1du)),
paiotian(MyApplication.getApplication().getString(R.string.read_paiotian)),
laoyao(MyApplication.getApplication().getString(R.string.read_laoyao)),
xingxing(MyApplication.getApplication().getString(R.string.read_xingxing)),
shiguang(MyApplication.getApplication().getString(R.string.read_shiguang)),
xiagu(MyApplication.getApplication().getString(R.string.read_xiagu)),
hongchen(MyApplication.getApplication().getString(R.string.read_hongchen)),
chaoxing(MyApplication.getApplication().getString(R.string.read_chaoxing)),
zuopin(MyApplication.getApplication().getString(R.string.read_zuopin)),
cangshu99(MyApplication.getApplication().getString(R.string.read_cangshu99)),

@ -1,200 +0,0 @@
package xyz.fycz.myreader.model.audio;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.IBinder;
import android.speech.tts.TextToSpeech;
import android.speech.tts.UtteranceProgressListener;
import android.text.TextUtils;
import androidx.annotation.Nullable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import xyz.fycz.myreader.util.ToastUtils;
import static android.text.TextUtils.isEmpty;
public class ReadService extends Service {
private static final String TAG = "ReadService";
public static Boolean running = false;
public static final String ActionNewRead = "newRead";
private Boolean speak = true;
private Boolean pause = false;
private List<String> contentList = new ArrayList<>();
private int nowSpeak;
private int speechRate;
private String title;
private String text;
private int readAloudNumber;
private int progress;
private Boolean ttsInitSuccess = false;
private TextToSpeech textToSpeech;
private HashMap mParams;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null) {
String action = intent.getAction();
if (action != null) {
switch (action) {
case ActionNewRead:
newReadAloud(intent.getStringExtra("content"),
intent.getStringExtra("title"),
intent.getStringExtra("text"),
intent.getIntExtra("progress", 0));
break;
}
}
}
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
}
private void initTTS() {
if (textToSpeech == null)
textToSpeech = new TextToSpeech(this, status -> {
if (status == TextToSpeech.SUCCESS) {
textToSpeech.setLanguage(Locale.CHINA);
textToSpeech.setOnUtteranceProgressListener(new ttsUtteranceListener());
ttsInitSuccess = true;
playTTS();
} else {
ToastUtils.showError("TTS初始化失败!");
ReadService.this.stopSelf();
}
});
if (mParams == null) {
mParams = new HashMap();
mParams.put(TextToSpeech.Engine.KEY_PARAM_STREAM, "3");
}
}
/**
* 朗读监听
*/
private class ttsUtteranceListener extends UtteranceProgressListener {
@Override
public void onStart(String s) {
//updateMediaSessionPlaybackState();
//RxBus.get().post(RxBusTag.READ_ALOUD_START, readAloudNumber + 1);
//RxBus.get().post(RxBusTag.READ_ALOUD_NUMBER, readAloudNumber + 1);
}
@Override
public void onDone(String s) {
readAloudNumber = readAloudNumber + contentList.get(nowSpeak).length() + 1;
nowSpeak = nowSpeak + 1;
if (nowSpeak >= contentList.size()) {
//RxBus.get().post(RxBusTag.ALOUD_STATE, Status.NEXT);
}
}
@Override
public void onError(String s) {
//pauseReadAloud(true);
//RxBus.get().post(RxBusTag.ALOUD_STATE, Status.PAUSE);
}
@Override
public void onRangeStart(String utteranceId, int start, int end, int frame) {
super.onRangeStart(utteranceId, start, end, frame);
//RxBus.get().post(RxBusTag.READ_ALOUD_NUMBER, readAloudNumber + start);
}
}
/**
* 朗读
*/
public static void play(Context context, String content, String title, String text, int progress) {
Intent readAloudIntent = new Intent(context, ReadService.class);
readAloudIntent.setAction(ActionNewRead);
readAloudIntent.putExtra("content", content);
readAloudIntent.putExtra("title", title);
readAloudIntent.putExtra("text", text);
readAloudIntent.putExtra("progress", progress);
context.startService(readAloudIntent);
}
private void newReadAloud(String content, String title, String text, int progress) {
if (TextUtils.isEmpty(content)) {
stopSelf();
return;
}
this.text = text;
this.title = title;
this.progress = progress;
nowSpeak = 0;
readAloudNumber = 0;
contentList.clear();
initTTS();
String[] splitSpeech = content.split("\n");
for (String aSplitSpeech : splitSpeech) {
if (!isEmpty(aSplitSpeech)) {
contentList.add(aSplitSpeech);
}
}
if (speak) {
speak = false;
pause = false;
playTTS();
}
}
private void playTTS() {
if (contentList.size() < 1) {
//RxBus.get().post(RxBusTag.ALOUD_STATE, Status.NEXT);
return;
}
if (ttsInitSuccess && !speak) {
speak = !speak;
//RxBus.get().post(RxBusTag.ALOUD_STATE, Status.PLAY);
//updateNotification();
//initSpeechRate();
HashMap<String, String> map = new HashMap<>();
map.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "content");
for (int i = nowSpeak; i < contentList.size(); i++) {
if (i == 0) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
textToSpeech.speak(contentList.get(i), TextToSpeech.QUEUE_FLUSH, null, "content");
} else {
textToSpeech.speak(contentList.get(i), TextToSpeech.QUEUE_FLUSH, map);
}
} else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
textToSpeech.speak(contentList.get(i), TextToSpeech.QUEUE_ADD, null, "content");
} else {
textToSpeech.speak(contentList.get(i), TextToSpeech.QUEUE_ADD, map);
}
}
}
}
}
public enum Status {
PLAY, STOP, PAUSE, NEXT
}
}

@ -757,7 +757,7 @@ public class BookDetailedActivity extends BaseActivity {
return share;
} catch (Exception e) {
e.printStackTrace();
ToastUtils.showError(Objects.requireNonNull(e.getLocalizedMessage()));
ToastUtils.showError(e.getLocalizedMessage() + "");
return null;
} finally {
IOUtils.close(fos);

@ -254,7 +254,7 @@ public class QRCodeScanActivity extends BaseActivity implements QRCodeView.Deleg
startActivityForResult(intent, REQUEST_QR_IMAGE);
} catch (Exception e) {
e.printStackTrace();
ToastUtils.showError(Objects.requireNonNull(e.getLocalizedMessage()));
ToastUtils.showError(e.getLocalizedMessage() + "");
}
}

@ -230,7 +230,7 @@ public class ReadActivity extends BaseActivity implements ColorPickerDialogListe
mPageLoader.skipToPage(pagePos);
} catch (Exception e) {
ToastUtils.showError("章节跳转失败,请截图联系作者。\n" +
Objects.requireNonNull(e.getMessage()));
e.getMessage());
e.printStackTrace();
}
pbLoading.setVisibility(View.GONE);
@ -733,7 +733,7 @@ public class ReadActivity extends BaseActivity implements ColorPickerDialogListe
skipToChapterAndPage(chapterAndPage[0], chapterAndPage[1]);
} catch (Exception e) {
ToastUtils.showError("章节跳转失败,请截图联系作者。\n" +
Objects.requireNonNull(e.getMessage()));
e.getMessage());
e.printStackTrace();
}
break;

@ -35,6 +35,7 @@ import xyz.fycz.myreader.util.PermissionsChecker;
import xyz.fycz.myreader.util.SharedPreUtils;
import xyz.fycz.myreader.util.ToastUtils;
import xyz.fycz.myreader.util.utils.ImageLoader;
import xyz.fycz.myreader.util.utils.MD5Utils;
import xyz.fycz.myreader.util.utils.OkHttpUtils;
import xyz.fycz.myreader.util.utils.SystemBarUtils;
@ -57,7 +58,7 @@ public class SplashActivity extends BaseActivity {
public void run() {
try {
sleep(WAIT_INTERVAL);//使程序休眠
Intent it = new Intent(getApplicationContext(), MainActivity.class);//启动MainActivity
Intent it = new Intent(SplashActivity.this, MainActivity.class);//启动MainActivity
startActivity(it);
finish();//关闭当前活动
} catch (Exception e) {
@ -95,11 +96,15 @@ public class SplashActivity extends BaseActivity {
private void loadImage() {
File imgFile = getFileStreamPath(APPCONST.FILE_NAME_SPLASH_IMAGE);
if (!imgFile.exists() || SharedPreUtils.getInstance().getBoolean("needUdSI")){
SharedPreUtils preUtils = SharedPreUtils.getInstance();
String splashImageMD5 = preUtils.getString("splashImageMD5");
if (!imgFile.exists() || preUtils.getBoolean("needUdSI") ||
!splashImageMD5.equals(MD5Utils.getFileMD5s(imgFile, 16))){
if ("".equals(splashImageMD5)) return;
downLoadImage();
return;
}
String splashLoadDate = SharedPreUtils.getInstance().getString("splashTime", "");
String splashLoadDate = preUtils.getString("splashTime");
if (splashLoadDate.equals("")) {
return;
}

@ -1,10 +1,8 @@
package xyz.fycz.myreader.ui.dialog;
import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
@ -23,11 +21,8 @@ import butterknife.ButterKnife;
import butterknife.OnClick;
import xyz.fycz.myreader.R;
import xyz.fycz.myreader.application.MyApplication;
import xyz.fycz.myreader.application.SysManager;
import xyz.fycz.myreader.model.audio.ReadAloudService;
import xyz.fycz.myreader.model.audio.ReadService;
import xyz.fycz.myreader.ui.activity.ReadActivity;
import xyz.fycz.myreader.util.DateHelper;
import xyz.fycz.myreader.util.SharedPreUtils;
import xyz.fycz.myreader.util.ToastUtils;
import xyz.fycz.myreader.util.utils.AudioMngHelper;

@ -23,6 +23,7 @@ import android.widget.PopupMenu;
import androidx.appcompat.app.AlertDialog;
import androidx.core.app.ActivityCompat;
import java.text.Collator;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
@ -351,7 +352,10 @@ public class BookcasePresenter implements BasePresenter {
return 0;
});
}else if (mSetting.getSortStyle() == 2){
Collections.sort(mBooks, (o1, o2) -> o2.getName().compareTo(o1.getName()));
Collections.sort(mBooks, (o1, o2) -> {
Collator cmp = Collator.getInstance(java.util.Locale.CHINA);
return cmp.compare(o1.getName(), o2.getName());
});
}
for (int i = 0; i < mBooks.size(); i++) {

@ -1,15 +1,13 @@
package xyz.fycz.myreader.util.utils;
/**
* Created by newbiechen on 2018/1/1.
*/
import java.io.File;
import java.io.FileInputStream;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* 将字符串转化为MD5
*/
import xyz.fycz.myreader.util.IOUtils;
public class MD5Utils {
@ -40,4 +38,36 @@ public class MD5Utils {
}
return reStr;
}
/**
* 获取单个文件的MD5值
* @param file 文件
* @param radix 16 32 64
*
* @return
*/
public static String getFileMD5s(File file, int radix) {
if (!file.isFile()) {
return null;
}
MessageDigest digest = null;
FileInputStream in = null;
byte[] buffer = new byte[1024];
int len;
try {
digest = MessageDigest.getInstance("MD5");
in = new FileInputStream(file);
while ((len = in.read(buffer, 0, 1024)) != -1) {
digest.update(buffer, 0, len);
}
} catch (Exception e) {
e.printStackTrace();
return null;
}finally {
IOUtils.close(in);
}
BigInteger bigInt = new BigInteger(1, digest.digest());
return bigInt.toString(radix);
}
}

@ -0,0 +1,158 @@
package xyz.fycz.myreader.webapi.crawler.read;
import android.text.Html;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.util.ArrayList;
import java.util.Collections;
import xyz.fycz.myreader.entity.SearchBookBean;
import xyz.fycz.myreader.enums.BookSource;
import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.greendao.entity.Chapter;
import xyz.fycz.myreader.model.mulvalmap.ConcurrentMultiValueMap;
import xyz.fycz.myreader.webapi.crawler.base.ReadCrawler;
public class HongChenReadCrawler implements ReadCrawler {
public static final String NAME_SPACE = "https://www.zuxs.net";
public static final String NOVEL_SEARCH = "https://www.zuxs.net/search.php?key={key}";
public static final String CHARSET = "gb2312";
public static final String SEARCH_CHARSET = "gbk";
@Override
public String getSearchLink() {
return NOVEL_SEARCH;
}
@Override
public String getCharset() {
return CHARSET;
}
@Override
public String getNameSpace() {
return NAME_SPACE;
}
@Override
public Boolean isPost() {
return false;
}
@Override
public String getSearchCharset() {
return SEARCH_CHARSET;
}
/**
* 从html中获取章节正文
*
* @param html
* @return
*/
public String getContentFormHtml(String html) {
Document doc = Jsoup.parse(html);
Element divContent = doc.getElementById("txt");
if (divContent != null) {
Elements aDiv = divContent.getElementsByTag("dd");
StringBuilder sb = new StringBuilder();
Collections.sort(aDiv, (o1, o2) -> Integer.parseInt(o1.attr("data-id")) -
Integer.parseInt(o2.attr("data-id")));
for (int i = 0; i < aDiv.size(); i++) {
Element dd = aDiv.get(i);
if (i == aDiv.size() - 1) break;
sb.append(Html.fromHtml(dd.html()).toString());
sb.append("\n");
}
String content = sb.toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ");
return content;
} else {
return "";
}
}
/**
* 从html中获取章节列表
*
* @param html
* @return
*/
public ArrayList<Chapter> getChaptersFromHtml(String html) {
ArrayList<Chapter> chapters = new ArrayList<>();
Document doc = Jsoup.parse(html);
String readUrl = doc.select("meta[property=og:novel:read_url]").attr("content");
Element divList = doc.getElementById("listsss");
Elements elementsByTag = divList.getElementsByTag("a");
int i = 0;
for (int j = 0; j < elementsByTag.size(); j++) {
Element a = elementsByTag.get(j);
String title = a.text();
String url = a.attr("href");
Chapter chapter = new Chapter();
chapter.setNumber(i++);
chapter.setTitle(title);
chapter.setUrl(readUrl + url);
chapters.add(chapter);
}
return chapters;
}
/**
* 从搜索html中得到书列表
*
* @param html
* @return
*/
/*
<dl><dt><a href="/zu/1140.html" target="_blank"><img class="lazyimg" data-original="https://www.zuxs.net/files/article/image/0/29/29s.jpg"></a></dt>
<dd><a href="/zu/1140.html" class="bigpic-book-name" target="_blank">
<font style="font-weight:bold;color:#f00">大主宰</font>
</a>
<p><a href="/author/%CC%EC%B2%CF%CD%C1%B6%B9.html" target="_blank">天蚕土豆</a> | <a href="/top/8_1.html"
target="_blank">其他类型</a> | 连载中</p>
<p class="big-book-info"> 大千世界位面交汇万族林立群雄荟萃一位位来自下位面的天之至尊在这无尽世界演绎着令人向往的传奇追求着那主宰之路
无尽火域炎帝执掌万火焚苍穹
武境之内武祖之威</p>
<p><a href="/zu/1/1140/5284.html" target="_blank" class="red">最近更新 第1598章 邪神陨落大结局</a><span>| 09-06
05:54更新</span></p>
</dd>
</dl>
*/
public ConcurrentMultiValueMap<SearchBookBean, Book> getBooksFromSearchHtml(String html) {
ConcurrentMultiValueMap<SearchBookBean, Book> books = new ConcurrentMultiValueMap<>();
Document doc = Jsoup.parse(html);
// try {
Element div = doc.getElementsByClass("s-b-list").first();
Elements dls = div.getElementsByTag("dl");
for (Element dl : dls){
Elements as = dl.getElementsByTag("a");
Book book = new Book();
book.setName(as.get(1).text());
book.setAuthor(as.get(2).text());
book.setType(as.get(3).text());
book.setNewestChapterTitle(as.get(4).text().replace("最近更新 ", ""));
book.setDesc(dl.getElementsByClass("big-book-info").first().text());
String imgUrl = dl.getElementsByTag("img").attr("data-original");
book.setImgUrl(imgUrl);
//https://www.zuxs.net/zu/1140.html -> https://www.zuxs.net/zu/1/1140/
book.setChapterUrl(NAME_SPACE + as.get(1).attr("href").replace("zu/", "zu/1/").replace(".html", "/"));
book.setSource(BookSource.hongchen.toString());
SearchBookBean sbb = new SearchBookBean(book.getName(), book.getAuthor());
books.add(sbb, book);
}
// } catch (Exception e) {
// e.printStackTrace();
// }
return books;
}
}

@ -0,0 +1,210 @@
package xyz.fycz.myreader.webapi.crawler.read;
import android.text.Html;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import xyz.fycz.myreader.entity.SearchBookBean;
import xyz.fycz.myreader.enums.BookSource;
import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.greendao.entity.Chapter;
import xyz.fycz.myreader.model.mulvalmap.ConcurrentMultiValueMap;
import xyz.fycz.myreader.webapi.crawler.base.ReadCrawler;
public class LaoYaoReadCrawler implements ReadCrawler {
public static final String NAME_SPACE = "https://www.laoyao.org";
public static final String NOVEL_SEARCH = "https://www.laoyao.org/search.php?key={key}";
public static final String CHARSET = "UTF-8";
public static final String SEARCH_CHARSET = "UTF-8";
@Override
public String getSearchLink() {
return NOVEL_SEARCH;
}
@Override
public String getCharset() {
return CHARSET;
}
@Override
public String getNameSpace() {
return NAME_SPACE;
}
@Override
public Boolean isPost() {
return false;
}
@Override
public String getSearchCharset() {
return SEARCH_CHARSET;
}
/**
* 从html中获取章节正文
*
* @param html
* @return
*/
public String getContentFormHtml(String html) {
Document doc = Jsoup.parse(html);
Element divContent = doc.getElementById("txt");
if (divContent != null) {
Elements aDiv = divContent.getElementsByTag("dd");
StringBuilder sb = new StringBuilder();
Collections.sort(aDiv, (o1, o2) -> Integer.parseInt(o1.attr("data-id")) -
Integer.parseInt(o2.attr("data-id")));
for (int i = 0; i < aDiv.size(); i++) {
Element dd = aDiv.get(i);
if (i == aDiv.size() - 1) break;
sb.append(Html.fromHtml(dd.html()).toString());
sb.append("\n");
}
String content = sb.toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ");
return content;
} else {
return "";
}
}
/**
* 从html中获取章节列表
*
* @param html
* @return
*/
public ArrayList<Chapter> getChaptersFromHtml(String html) {
ArrayList<Chapter> chapters = new ArrayList<>();
Document doc = Jsoup.parse(html);
String readUrl = doc.select("meta[property=og:novel:read_url]").attr("content");
Element divList = doc.getElementById("newlist");
Elements elementsByTag = divList.getElementsByTag("a");
int i = 0;
for (int j = 0; j < elementsByTag.size(); j++) {
Element a = elementsByTag.get(j);
String title = a.text();
String url = a.attr("href");
Chapter chapter = new Chapter();
chapter.setNumber(i++);
chapter.setTitle(title);
chapter.setUrl(readUrl + url);
chapters.add(chapter);
}
return chapters;
}
/**
* 从搜索html中得到书列表
*
* @param html
* @return
*/
/*
<li><a href="/info/6690.html" target="_blank" class="book_cov" title="大主宰"><img src="/public/images/default.jpg"
data-original="//www.laoyao.org/files/article/image/0/24/24s.jpg" class="lazyload_book_cover" alt="大主宰" /></a>
<div class="book_inf">
<h3><a href="/info/6690.html" title="大主宰" target="_blank" mod="data_book_name">
<font style="font-weight:bold;color:#f00">大主宰</font>
</a></h3>
<p class="tags"><span>作者<a href="/creator/%E5%A4%A9%E8%9A%95%E5%9C%9F%E8%B1%86.html" title="天蚕土豆">天蚕土豆</a></span><span>分类<a
href="/library/8_0_0_0_0_1.html" target="_blank">名著经典</a></span><span>状态连载中</span><span>总字数2498万字+</span></p>
<p><b>最近更新</b><a href="/list/6690/21939.html" title="第1598章 邪神陨落(大结局)" target="_blank">第1598章 邪神陨落大结局</a></p>
<p class="int"> 大千世界位面交汇万族林立群雄荟萃一位位来自下位面的天之至尊在这无尽世界演绎着令人向往的传奇追求着那主宰之路
无尽火域炎帝执掌万火焚苍穹
武境之内武祖之威震慑乾坤
西天之殿百战之皇</p>
</div>
<div class="right">
<span>更新时间2020-09-06 06:47</span>
<a href="/info/6690.html" target="_blank" class="read_btn btn">立即阅读</a>
<a href="javascript:BookCaseAdd('6690');" class="store_btn btn" btn="book_fav">加入书架</a>
</div>
</li>
*/
public ConcurrentMultiValueMap<SearchBookBean, Book> getBooksFromSearchHtml(String html) {
ConcurrentMultiValueMap<SearchBookBean, Book> books = new ConcurrentMultiValueMap<>();
Document doc = Jsoup.parse(html);
// try {
String urlType = doc.select("meta[property=og:type]").attr("content");
if ("novel".equals(urlType)) {
String readUrl = doc.select("meta[property=og:novel:read_url]").attr("content");
Book book = new Book();
book.setChapterUrl(readUrl);
getBookInfo(doc, book);
SearchBookBean sbb = new SearchBookBean(book.getName(), book.getAuthor());
books.add(sbb, book);
} else {
Element div = doc.getElementsByClass("result").first();
Elements lis = div.getElementsByTag("li");
for (Element li : lis) {
Elements as = li.getElementsByTag("a");
Book book = new Book();
book.setName(as.get(1).text());
book.setAuthor(as.get(2).text());
book.setType(as.get(3).text());
book.setNewestChapterTitle(as.get(4).text().replace("最新章节:", ""));
book.setDesc(li.getElementsByClass("int").first().text());
book.setUpdateDate(li.getElementsByClass("right").first().getElementsByTag("span").text());
String imgUrl = li.getElementsByTag("img").attr("data-original");
book.setImgUrl(!imgUrl.contains("http") ? "https:" + imgUrl : imgUrl);
book.setChapterUrl(NAME_SPACE + as.get(1).attr("href").replace("info", "list").replace(".html", "/"));
book.setSource(BookSource.laoyao.toString());
SearchBookBean sbb = new SearchBookBean(book.getName(), book.getAuthor());
books.add(sbb, book);
}
}
// } catch (Exception e) {
// e.printStackTrace();
// }
return books;
}
public Book getBookInfo(Document doc, Book book) {
//小说源
book.setSource(BookSource.laoyao.toString());
//图片url
String imgUrl = doc.select("meta[property=og:image]").attr("content");
book.setImgUrl(!imgUrl.contains("http") ? "https:" + imgUrl : imgUrl);
//书名
String title = doc.select("meta[property=og:novel:book_name]").attr("content");
book.setName(title);
//作者
String author = doc.select("meta[property=og:novel:author]").attr("content");
book.setAuthor(author);
//更新时间
String updateDate = doc.select("meta[property=og:novel:update_time]").attr("content");
book.setUpdateDate(updateDate);
//最新章节
String newestChapterTitle = doc.select("meta[property=og:novel:latest_chapter_name]").attr("content");
book.setNewestChapterTitle(newestChapterTitle);
//类型
String type = doc.select("meta[property=og:novel:category]").attr("content");
book.setType(type);
//简介
String desc = doc.select("meta[property=og:description]").attr("content");
book.setDesc(desc);
return book;
}
}

@ -0,0 +1,204 @@
package xyz.fycz.myreader.webapi.crawler.read;
import android.text.Html;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.util.ArrayList;
import java.util.Collections;
import xyz.fycz.myreader.entity.SearchBookBean;
import xyz.fycz.myreader.enums.BookSource;
import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.greendao.entity.Chapter;
import xyz.fycz.myreader.model.mulvalmap.ConcurrentMultiValueMap;
import xyz.fycz.myreader.webapi.crawler.base.ReadCrawler;
public class ShiGuangReadCrawler implements ReadCrawler {
public static final String NAME_SPACE = "https://www.youxs.org";
public static final String NOVEL_SEARCH = "https://www.youxs.org/search.php?key={key}";
public static final String CHARSET = "gbk";
public static final String SEARCH_CHARSET = "gbk";
@Override
public String getSearchLink() {
return NOVEL_SEARCH;
}
@Override
public String getCharset() {
return CHARSET;
}
@Override
public String getNameSpace() {
return NAME_SPACE;
}
@Override
public Boolean isPost() {
return false;
}
@Override
public String getSearchCharset() {
return SEARCH_CHARSET;
}
/**
* 从html中获取章节正文
*
* @param html
* @return
*/
public String getContentFormHtml(String html) {
Document doc = Jsoup.parse(html);
Element divContent = doc.getElementById("txt");
if (divContent != null) {
Elements aDiv = divContent.getElementsByTag("dd");
StringBuilder sb = new StringBuilder();
Collections.sort(aDiv, (o1, o2) -> Integer.parseInt(o1.attr("data-id")) -
Integer.parseInt(o2.attr("data-id")));
for (int i = 0; i < aDiv.size(); i++) {
Element dd = aDiv.get(i);
if (i == aDiv.size() - 1) break;
sb.append(Html.fromHtml(dd.html()).toString());
sb.append("\n");
}
String content = sb.toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ");
return content;
} else {
return "";
}
}
/**
* 从html中获取章节列表
*
* @param html
* @return
*/
public ArrayList<Chapter> getChaptersFromHtml(String html) {
ArrayList<Chapter> chapters = new ArrayList<>();
Document doc = Jsoup.parse(html);
Element divList = doc.getElementById("listsss");
Elements elementsByTag = divList.getElementsByTag("a");
int i = 0;
for (int j = 0; j < elementsByTag.size(); j++) {
Element a = elementsByTag.get(j);
String title = a.text();
String url = a.attr("href");
Chapter chapter = new Chapter();
chapter.setNumber(i++);
chapter.setTitle(title);
chapter.setUrl(NAME_SPACE + url);
chapters.add(chapter);
}
return chapters;
}
/**
* 从搜索html中得到书列表
*
* @param html
* @return
*/
/*
<li><a href="/wuxian/4/4473/" target="_blank" class="book_cov" title="大主宰"><img src="/public/images/default.jpg"
data-original="https://www.youxs.org/files/article/image/0/29/29s.jpg" class="lazyload_book_cover" alt="大主宰" /></a>
<div class="book_inf">
<h3><a href="/wuxian/4/4473/" title="大主宰" target="_blank" mod="data_book_name">
<font style="font-weight:bold;color:#f00">大主宰</font>
</a></h3>
<p class="tags"><span>作者<a title="天蚕土豆">天蚕土豆</a></span><span>分类<a href="/liebiao/8_0_0_0_0_1.html" target="_blank">网络文学</a></span><span>状态连载中</span><span>总字数2497万字+</span></p>
<p><b>最近更新</b><a href="/wuxian/4/4473/15283.html" title="第1598章 邪神陨落(大结局)" target="_blank">第1598章 邪神陨落大结局</a></p>
<p class="int"> 大千世界位面交汇万族林立群雄荟萃一位位来自下位面的天之至尊在这无尽世界演绎着令人向往的传奇追求着那主宰之路
无尽火域炎帝执掌万火焚苍穹
武境之内武祖之威</p>
</div>
<div class="right">
<span>更新时间09-06 05:25</span>
<a href="/wuxian/4/4473/" target="_blank" class="read_btn btn">立即阅读</a>
<a href="javascript:BookCaseAdd('4473');" class="store_btn btn" btn="book_fav">加入书架</a>
</div>
</li>
*/
public ConcurrentMultiValueMap<SearchBookBean, Book> getBooksFromSearchHtml(String html) {
ConcurrentMultiValueMap<SearchBookBean, Book> books = new ConcurrentMultiValueMap<>();
Document doc = Jsoup.parse(html);
// try {
String urlType = doc.select("meta[property=og:type]").attr("content");
if ("novel".equals(urlType)) {
String readUrl = doc.select("meta[property=og:novel:read_url]").attr("content");
Book book = new Book();
book.setChapterUrl(readUrl);
getBookInfo(doc, book);
SearchBookBean sbb = new SearchBookBean(book.getName(), book.getAuthor());
books.add(sbb, book);
} else {
Element div = doc.getElementsByClass("result").first();
Elements lis = div.getElementsByTag("li");
for (Element li : lis) {
Elements as = li.getElementsByTag("a");
Book book = new Book();
book.setName(as.get(1).text());
book.setAuthor(as.get(2).text());
book.setType(as.get(3).text());
book.setNewestChapterTitle(as.get(4).text().replace("最新章节:", ""));
book.setDesc(li.getElementsByClass("int").first().text());
book.setUpdateDate(li.getElementsByClass("right").first().getElementsByTag("span").text());
String imgUrl = li.getElementsByTag("img").attr("data-original");
book.setImgUrl(imgUrl);
book.setChapterUrl(NAME_SPACE + as.get(1).attr("href"));
book.setSource(BookSource.shiguang.toString());
SearchBookBean sbb = new SearchBookBean(book.getName(), book.getAuthor());
books.add(sbb, book);
}
}
// } catch (Exception e) {
// e.printStackTrace();
// }
return books;
}
public Book getBookInfo(Document doc, Book book) {
//小说源
book.setSource(BookSource.shiguang.toString());
//图片url
String imgUrl = doc.select("meta[property=og:image]").attr("content");
book.setImgUrl(imgUrl);
//书名
String title = doc.select("meta[property=og:novel:book_name]").attr("content");
book.setName(title);
//作者
String author = doc.select("meta[property=og:novel:author]").attr("content");
book.setAuthor(author);
//更新时间
String updateDate = doc.select("meta[property=og:novel:update_time]").attr("content");
book.setUpdateDate(updateDate);
//最新章节
String newestChapterTitle = doc.select("meta[property=og:novel:latest_chapter_name]").attr("content");
book.setNewestChapterTitle(newestChapterTitle);
//类型
String type = doc.select("meta[property=og:novel:category]").attr("content");
book.setType(type);
//简介
String desc = doc.select("meta[property=og:description]").attr("content");
book.setDesc(desc);
return book;
}
}

@ -18,7 +18,6 @@ import java.util.ArrayList;
/**
* 天籁小说网html解析工具
* Created by zhao on 2017/7/24.
*/
public class TianLaiReadCrawler implements ReadCrawler {

@ -0,0 +1,166 @@
package xyz.fycz.myreader.webapi.crawler.read;
import android.text.Html;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.util.ArrayList;
import java.util.Collections;
import xyz.fycz.myreader.entity.SearchBookBean;
import xyz.fycz.myreader.enums.BookSource;
import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.greendao.entity.Chapter;
import xyz.fycz.myreader.model.mulvalmap.ConcurrentMultiValueMap;
import xyz.fycz.myreader.webapi.crawler.base.ReadCrawler;
public class XiaGuReadCrawler implements ReadCrawler {
public static final String NAME_SPACE = "https://www.xiagu.org";
public static final String NOVEL_SEARCH = "https://www.xiagu.org/search/?keyword={key}&t=0";
public static final String CHARSET = "UTF-8";
public static final String SEARCH_CHARSET = "UTF-8";
@Override
public String getSearchLink() {
return NOVEL_SEARCH;
}
@Override
public String getCharset() {
return CHARSET;
}
@Override
public String getNameSpace() {
return NAME_SPACE;
}
@Override
public Boolean isPost() {
return false;
}
@Override
public String getSearchCharset() {
return SEARCH_CHARSET;
}
/**
* 从html中获取章节正文
*
* @param html
* @return
*/
public String getContentFormHtml(String html) {
Document doc = Jsoup.parse(html);
Element divContent = doc.getElementById("txt");
if (divContent != null) {
Elements aDiv = divContent.getElementsByTag("dd");
StringBuilder sb = new StringBuilder();
Collections.sort(aDiv, (o1, o2) -> Integer.parseInt(o1.attr("data-id")) -
Integer.parseInt(o2.attr("data-id")));
for (int i = 0; i < aDiv.size(); i++) {
Element dd = aDiv.get(i);
if (i == aDiv.size() - 1) break;
sb.append(Html.fromHtml(dd.html()).toString());
sb.append("\n");
}
String content = sb.toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ");
return content;
} else {
return "";
}
}
/**
* 从html中获取章节列表
*
* @param html
* @return
*/
public ArrayList<Chapter> getChaptersFromHtml(String html) {
ArrayList<Chapter> chapters = new ArrayList<>();
Document doc = Jsoup.parse(html);
String readUrl = doc.select("meta[property=og:novel:read_url]").attr("content");
Element divList = doc.getElementById("listsss");
Elements elementsByTag = divList.getElementsByTag("a");
int i = 0;
for (int j = 0; j < elementsByTag.size(); j++) {
Element a = elementsByTag.get(j);
String title = a.text();
String url = a.attr("href");
Chapter chapter = new Chapter();
chapter.setNumber(i++);
chapter.setTitle(title);
chapter.setUrl(readUrl + url);
chapters.add(chapter);
}
return chapters;
}
/**
* 从搜索html中得到书列表
*
* @param html
* @return
*/
/*
<li class="subject-item">
<div class="pic">
<a class="nbg" href="/xs/5584.html" ><img class="" data-original="//www.xiagu.org/files/article/image/0/29/29s.jpg" src="/statics/images/default.jpg" width="90"></a>
</div>
<div class="info">
<h2 class=""><a href="/xs/5584.html"><font style="font-weight:bold;color:#f00">大主宰</font></a></h2>
<div class="pub">作者<a target="_blank" href="/author/id/186.html">天蚕土豆</a> / 类型<a target="_blank" href="/shuku/8_0_0_0_0_1.html">其他类型</a> / 2020-09-06 / 连载中 / 2497.0808万字</div>
<p>内容简介&nbsp;&nbsp;&nbsp;&nbsp;大千世界位面交汇万族林立群雄荟萃一位位来自下位面的天之至尊在这无尽世界演绎着令人向往的传奇追求着那主宰之路<br />
&nbsp;&nbsp;&nbsp;&nbsp;无尽火域炎帝执掌万火焚苍穹<br />
&nbsp;&nbsp;&nbsp;&nbsp;武境之内武祖之威... </p>
<div class="ft">
<div class="pub">角色牧尘唐芊儿红绫牧哥苏凌刘彻柳阳牧锋芊儿柳慕白薛东童哥柳眉唐芊儿蹙姬玄牧哥比那柳阳乐乐凌撇杨柳林修牧尘沉莫师代柳阳</div>
<div class="cart-actions">
<span class="market-info"><a href="/read/5/5584/" target="_blank">最新章节第1598章 邪神陨落大结局</a></span>
</div>
<div class="ebook-link"><a target="_blank" href="/xs/5584.html">详细介绍</a></div>
</div>
</div>
</li>
*/
public ConcurrentMultiValueMap<SearchBookBean, Book> getBooksFromSearchHtml(String html) {
ConcurrentMultiValueMap<SearchBookBean, Book> books = new ConcurrentMultiValueMap<>();
Document doc = Jsoup.parse(html);
// try {
Element div = doc.getElementsByClass("subject-list").first();
Elements lis = div.getElementsByTag("li");
for (Element li : lis){
Elements as = li.getElementsByTag("a");
Book book = new Book();
book.setName(as.get(1).text());
book.setAuthor(as.get(2).text());
book.setType(as.get(3).text());
book.setNewestChapterTitle(as.get(4).text().replace("【最新章节】", ""));
book.setDesc(li.getElementsByTag("p").first().text());
String imgUrl = li.getElementsByTag("img").attr("data-original");
book.setImgUrl(!imgUrl.contains("http") ? "https:" + imgUrl : imgUrl);
//https://www.xiagu.org/xs/5584.html -> https://www.xiagu.org/read/5/5584/
book.setChapterUrl(NAME_SPACE + as.get(1).attr("href").replace("xs", "read/1").replace(".html", "/"));
book.setSource(BookSource.xiagu.toString());
SearchBookBean sbb = new SearchBookBean(book.getName(), book.getAuthor());
books.add(sbb, book);
}
// } catch (Exception e) {
// e.printStackTrace();
// }
return books;
}
}

@ -0,0 +1,158 @@
package xyz.fycz.myreader.webapi.crawler.read;
import android.text.Html;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.util.ArrayList;
import java.util.Collections;
import xyz.fycz.myreader.entity.SearchBookBean;
import xyz.fycz.myreader.enums.BookSource;
import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.greendao.entity.Chapter;
import xyz.fycz.myreader.model.mulvalmap.ConcurrentMultiValueMap;
import xyz.fycz.myreader.webapi.crawler.base.ReadCrawler;
public class XingXingReadCrawler implements ReadCrawler {
public static final String NAME_SPACE = "https://www.hs918.com";
public static final String NOVEL_SEARCH = "https://www.hs918.com/search.php?key={key}";
public static final String CHARSET = "UTF-8";
public static final String SEARCH_CHARSET = "UTF-8";
@Override
public String getSearchLink() {
return NOVEL_SEARCH;
}
@Override
public String getCharset() {
return CHARSET;
}
@Override
public String getNameSpace() {
return NAME_SPACE;
}
@Override
public Boolean isPost() {
return false;
}
@Override
public String getSearchCharset() {
return SEARCH_CHARSET;
}
/**
* 从html中获取章节正文
*
* @param html
* @return
*/
public String getContentFormHtml(String html) {
Document doc = Jsoup.parse(html);
Element divContent = doc.getElementById("txt");
if (divContent != null) {
String content = Html.fromHtml(divContent.html()).toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ");
return content;
} else {
return "";
}
}
/**
* 从html中获取章节列表
*
* @param html
* @return
*/
public ArrayList<Chapter> getChaptersFromHtml(String html) {
ArrayList<Chapter> chapters = new ArrayList<>();
Document doc = Jsoup.parse(html);
String readUrl = doc.select("meta[property=og:novel:read_url]").attr("content");
Element divList = doc.getElementById("newlist");
Elements elementsByTag = divList.getElementsByTag("a");
int i = 0;
for (int j = 0; j < elementsByTag.size(); j++) {
Element a = elementsByTag.get(j);
String title = a.text();
String url = a.attr("href");
Chapter chapter = new Chapter();
chapter.setNumber(i++);
chapter.setTitle(title);
chapter.setUrl(readUrl + url);
chapters.add(chapter);
}
return chapters;
}
/**
* 从搜索html中得到书列表
*
* @param html
* @return
*/
/*
<li>
<div class="sCboxBookParL left"><a href="/xiaoshuo/21351.html"><img data-original="https://www.hs918.com/files/article/image/20/20240/20240s.jpg" /></a></div>
<div class="sCboxBookParR left">
<div class="top clearfix">
<h1><a href="/xiaoshuo/21351.html"><font style="font-weight:bold;color:#f00">大主宰</font>之剑仙</a></h1>
<span class="s2">遗弃的梦 </span>
<span class="s4">95万字</span>
<span class="s6">474人气值</span>
</div>
<div class="tips clearfix"><a href="/fenlei/3_0_0_0_0_1.html" title="浪漫青春" class="tipsa">浪漫青春</a></div>
<div class="c"><strong>内容介绍</strong> 一位少年意外穿越大主宰结识了牧尘新人作家写得不好还请多多包涵
...</div>
<div class="bottom clearfix">
<span class="redTps">最近更新</span>
<a href="/xiaoshuo/21351/43873.html">第57章陷阱</a>
<span class="time2">更新时间2020-12-05 01:45</span>
</div>
</div>
<div class="sCboxBookParS right">
<a href="/xiaoshuo/21351/" class="b1">开始阅读</a>
<a href="javascript:;" onclick="BookCaseAdd('21351');" class="b2 apdBshelf">加入书架</a>
</div>
</li>
*/
public ConcurrentMultiValueMap<SearchBookBean, Book> getBooksFromSearchHtml(String html) {
ConcurrentMultiValueMap<SearchBookBean, Book> books = new ConcurrentMultiValueMap<>();
Document doc = Jsoup.parse(html);
// try {
Element div = doc.getElementsByClass("leftBox").first();
Elements lis = div.getElementsByTag("li");
for (Element li : lis){
Elements as = li.getElementsByTag("a");
Book book = new Book();
book.setName(as.get(1).text());
book.setAuthor(li.getElementsByTag("span").first().text());
book.setType(as.get(2).text());
book.setNewestChapterTitle(as.get(3).text());
book.setDesc(li.getElementsByClass("c").first().text().replace("内容介绍:", ""));
book.setUpdateDate(li.getElementsByClass("time2").first().text().replace("更新时间:", ""));
book.setImgUrl(li.getElementsByTag("img").attr("data-original"));
book.setChapterUrl(NAME_SPACE + as.get(1).attr("href").replace(".html", "/"));
book.setSource(BookSource.xingxing.toString());
SearchBookBean sbb = new SearchBookBean(book.getName(), book.getAuthor());
books.add(sbb, book);
}
// } catch (Exception e) {
// e.printStackTrace();
// }
return books;
}
}

@ -75,7 +75,8 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
tools:visibility="gone" />
tools:visibility="gone"
android:focusable="true" />
<ProgressBar
android:id="@+id/pb_loading"
@ -95,7 +96,8 @@
android:clickable="true"
android:orientation="vertical"
android:visibility="gone"
tools:visibility="visible">
tools:visibility="visible"
android:focusable="true">
<RelativeLayout
android:layout_width="match_parent"

@ -1,316 +1,316 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="@color/colorBackground"
android:scrollbars="vertical">
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorBackground"
android:scrollbars="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="6dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginBottom="6dp">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal"
android:layout_marginTop="24dp"
android:src="@mipmap/ic_launcher"/>
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal"
android:layout_marginTop="24dp"
android:src="@mipmap/ic_launcher" />
<TextView
android:id="@+id/tv_version_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="4dp"
android:layout_marginBottom="4dp"
android:textSize="16sp"
android:textColor="@color/textSecondary"
tools:text="风月读书"/>
android:id="@+id/tv_version_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="4dp"
android:layout_marginBottom="4dp"
android:textColor="@color/textSecondary"
android:textSize="16sp"
tools:text="风月读书" />
</LinearLayout>
<androidx.cardview.widget.CardView
android:id="@+id/vm_author"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_margin="6dp"
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackground"
app:cardBackgroundColor="@color/background_card">
android:id="@+id/vm_author"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_margin="6dp"
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackground"
app:cardBackgroundColor="@color/background_card">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:orientation="vertical">
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="5dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:layout_marginTop="5dp"
android:text="开发者"
android:textColor="@color/textSecondary"
android:textSize="16sp"/>
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:text="开发者"
android:textColor="@color/textSecondary"
android:textSize="16sp" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="6dp">
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="6dp">
<xyz.fycz.myreader.widget.custom.CircleImageView
android:id="@+id/ig_avatar_fycz"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginRight="16dp"
android:src="@mipmap/ic_avatar_fycz"/>
android:id="@+id/ig_avatar_fycz"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginRight="16dp"
android:src="@mipmap/ic_avatar_fycz" />
<TextView
android:id="@+id/fycz"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="@id/ig_avatar_fycz"
android:layout_toEndOf="@id/ig_avatar_fycz"
android:text="ヅ风月の残烛"
android:textColor="@color/textSecondary"
tools:ignore="HardcodedText"/>
android:id="@+id/fycz"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="@id/ig_avatar_fycz"
android:layout_toEndOf="@id/ig_avatar_fycz"
android:text="ヅ风月の残烛"
android:textColor="@color/textSecondary"
tools:ignore="HardcodedText" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/fycz"
android:layout_toEndOf="@id/ig_avatar_fycz"
android:text="@string/email"
android:textColor="@color/textSecondary"/>
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/fycz"
android:layout_toEndOf="@id/ig_avatar_fycz"
android:text="@string/email"
android:textColor="@color/textSecondary" />
</RelativeLayout>
</LinearLayout>
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
android:id="@+id/vw_share"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_margin="6dp"
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackground"
app:cardBackgroundColor="@color/background_card">
android:id="@+id/vw_share"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_margin="6dp"
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackground"
app:cardBackgroundColor="@color/background_card">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp">
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center_vertical"
android:src="@drawable/ic_share"
app:tint="@color/textSecondary"/>
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center_vertical"
android:padding="2dp"
android:src="@drawable/ic_share"
app:tint="@color/textSecondary" />
<TextView
android:id="@+id/tv_share"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="5dp"
android:gravity="center_vertical"
android:textColor="@color/textSecondary"
android:text="@string/share_app"/>
android:id="@+id/tv_share"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="5dp"
android:gravity="center_vertical"
android:text="@string/share_app"
android:textColor="@color/textSecondary" />
</LinearLayout>
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
android:id="@+id/vw_update"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_margin="6dp"
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackground"
app:cardBackgroundColor="@color/background_card">
android:id="@+id/vw_update"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_margin="6dp"
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackground"
app:cardBackgroundColor="@color/background_card">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp">
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center_vertical"
android:src="@drawable/ic_update"
app:tint="@color/textSecondary"/>
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center_vertical"
android:src="@drawable/ic_update"
app:tint="@color/textSecondary" />
<TextView
android:id="@+id/tv_update"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="5dp"
android:gravity="center_vertical"
android:textColor="@color/textSecondary"
android:text="@string/update"/>
android:id="@+id/tv_update"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="5dp"
android:gravity="center_vertical"
android:text="@string/update"
android:textColor="@color/textSecondary" />
</LinearLayout>
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
android:id="@+id/vw_update_log"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_margin="6dp"
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackground"
app:cardBackgroundColor="@color/background_card">
android:id="@+id/vw_update_log"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_margin="6dp"
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackground"
app:cardBackgroundColor="@color/background_card">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp">
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center_vertical"
android:src="@drawable/ic_list"
app:tint="@color/textSecondary"/>
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center_vertical"
android:src="@drawable/ic_list"
app:tint="@color/textSecondary" />
<TextView
android:id="@+id/tv_update_log"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="5dp"
android:gravity="center_vertical"
android:textColor="@color/textSecondary"
android:text="@string/update_log"/>
android:id="@+id/tv_update_log"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="5dp"
android:gravity="center_vertical"
android:text="@string/update_log"
android:textColor="@color/textSecondary" />
</LinearLayout>
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
android:id="@+id/vw_qq"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_margin="6dp"
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackground"
app:cardBackgroundColor="@color/background_card">
android:id="@+id/vw_qq"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_margin="6dp"
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackground"
app:cardBackgroundColor="@color/background_card">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp">
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center_vertical"
android:src="@drawable/ic_qq_group"
app:tint="@color/textSecondary" />
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center_vertical"
android:src="@drawable/ic_qq_group"
app:tint="@color/textSecondary" />
<TextView
android:id="@+id/tv_qq"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="5dp"
android:gravity="center_vertical"
android:textColor="@color/textSecondary"
android:text="@string/join_qq_group" />
android:id="@+id/tv_qq"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="5dp"
android:gravity="center_vertical"
android:text="@string/join_qq_group"
android:textColor="@color/textSecondary" />
</LinearLayout>
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
android:id="@+id/vw_git"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_margin="6dp"
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackground"
app:cardBackgroundColor="@color/background_card">
android:id="@+id/vw_git"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_margin="6dp"
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackground"
app:cardBackgroundColor="@color/background_card">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp">
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center_vertical"
android:src="@drawable/ic_social_github"
app:tint="@color/textSecondary"/>
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center_vertical"
android:src="@drawable/ic_social_github"
app:tint="@color/textSecondary" />
<TextView
android:id="@+id/tv_git"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="5dp"
android:gravity="center_vertical"
android:textColor="@color/textSecondary"
android:text="@string/git_hub"/>
android:id="@+id/tv_git"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="5dp"
android:gravity="center_vertical"
android:text="@string/git_hub"
android:textColor="@color/textSecondary" />
</LinearLayout>
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
android:id="@+id/vw_disclaimer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_margin="6dp"
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackground"
app:cardBackgroundColor="@color/background_card">
android:id="@+id/vw_disclaimer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_margin="6dp"
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackground"
app:cardBackgroundColor="@color/background_card">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp">
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center_vertical"
android:src="@drawable/ic_disclaimer"
app:tint="@color/textSecondary"/>
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center_vertical"
android:src="@drawable/ic_disclaimer"
app:tint="@color/textSecondary" />
<TextView
android:id="@+id/tv_disclaimer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="5dp"
android:gravity="center_vertical"
android:textColor="@color/textSecondary"
android:text="@string/disclaimer"/>
android:id="@+id/tv_disclaimer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="5dp"
android:gravity="center_vertical"
android:text="@string/disclaimer"
android:textColor="@color/textSecondary" />
</LinearLayout>
</androidx.cardview.widget.CardView>

@ -14,7 +14,7 @@
android:paddingEnd="10dp"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:text="翻页速度:50%"
android:text="@string/turn_page_speed"
android:textColor="@color/read_menu_text"
android:textSize="@dimen/text_small_size"
tools:ignore="RtlSymmetry" />
@ -45,7 +45,7 @@
android:layout_height="wrap_content"
android:gravity="center"
android:padding="15dp"
android:text="退出自动翻页"
android:text="@string/exit_auto_page"
android:textColor="@drawable/setting_btn_bg_color"
android:textSize="@dimen/text_small_size" />

@ -26,7 +26,7 @@
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:text="亮度"
android:text="@string/brightness"
android:textColor="@color/read_menu_text"
android:textSize="14sp" />
@ -35,7 +35,7 @@
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="7dp"
android:text="跟随系统"
android:text="@string/follow_sys"
android:textColor="@color/read_menu_text"
android:textSize="14sp" />
@ -111,7 +111,7 @@
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:text="蓝光过滤"
android:text="@string/blue_filter"
android:textColor="@color/read_menu_text"
android:textSize="14sp" />
@ -120,7 +120,7 @@
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="7dp"
android:text="开启护眼"
android:text="@string/open_protect_eye"
android:textColor="@color/read_menu_text"
android:textSize="14sp" />

@ -22,7 +22,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp"
android:text="背景颜色:"
android:text="@string/back_color"
android:textColor="@color/read_menu_text"
android:textSize="@dimen/text_small_size" />
@ -45,7 +45,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp"
android:text="字体颜色:"
android:text="@string/font_color"
android:textColor="@color/read_menu_text"
android:textSize="@dimen/text_small_size" />
@ -70,7 +70,7 @@
app:innerCircleRadius="10dp"
app:showOuterCircle="false"
app:textSize="@dimen/text_small_size"
app:text="共用布局" />
app:text="@string/share_layout" />
</LinearLayout>
@ -87,7 +87,7 @@
android:layout_height="wrap_content"
android:paddingStart="10dp"
android:paddingEnd="10dp"
android:text="背景图片"
android:text="@string/back_picture"
android:textColor="@color/read_menu_text" />
<xyz.fycz.myreader.widget.HorizontalListView
@ -116,7 +116,7 @@
android:layout_height="30dp"
android:background="@drawable/setting_btn_bg"
android:gravity="center"
android:text="保存"
android:text="@string/save"
android:textColor="@drawable/setting_btn_bg_color" />
</LinearLayout>
@ -132,7 +132,7 @@
android:layout_height="30dp"
android:background="@drawable/setting_btn_bg"
android:gravity="center"
android:text="导入"
android:text="@string/import_"
android:textColor="@drawable/setting_btn_bg_color" />
</LinearLayout>
@ -148,7 +148,7 @@
android:layout_height="30dp"
android:background="@drawable/setting_btn_bg"
android:gravity="center"
android:text="导出"
android:text="@string/export"
android:textColor="@drawable/setting_btn_bg_color" />
</LinearLayout>
@ -164,7 +164,7 @@
android:layout_height="30dp"
android:background="@drawable/setting_btn_bg"
android:gravity="center"
android:text="重置布局"
android:text="@string/reset_layout"
android:textColor="@drawable/setting_btn_bg_color" />
</LinearLayout>

@ -202,6 +202,11 @@
<string name="read_xs7">小说旗</string>
<string name="read_du1du">读一读网</string>
<string name="read_paiotian">飘天文学</string>
<string name="read_laoyao">老幺小说</string>
<string name="read_xingxing">星星小说</string>
<string name="read_shiguang">时光小说</string>
<string name="read_xiagu">峡谷文学</string>
<string name="read_hongchen">红尘小说</string>
<string name="read_chaoxing">超星图书·实体</string>
<string name="read_zuopin">作品集·实体</string>
<string name="read_cangshu99">99藏书·实体</string>
@ -259,6 +264,20 @@
<string name="menu_scan">扫一扫</string>
<string name="light_contact">轻触点亮</string>
<string name="close_contact">轻触关闭</string>
<string name="turn_page_speed">翻页速度:%s %%</string>
<string name="exit_auto_page">退出自动翻页</string>
<string name="brightness">亮度</string>
<string name="follow_sys">跟随系统</string>
<string name="blue_filter">蓝光过滤</string>
<string name="open_protect_eye">开启护眼</string>
<string name="back_color">背景颜色:</string>
<string name="font_color">字体颜色:</string>
<string name="share_layout">共用布局</string>
<string name="back_picture">背景图片</string>
<string name="save">保存</string>
<string name="import_">导入</string>
<string name="export">导出</string>
<string name="reset_layout">重置布局</string>
<string-array name="reset_screen_time">
<item>常亮</item>

@ -20,3 +20,8 @@ qiqi=xyz.fycz.myreader.webapi.crawler.read.QiQiReadCrawler
xs7=xyz.fycz.myreader.webapi.crawler.read.XS7ReadCrawler
du1du=xyz.fycz.myreader.webapi.crawler.read.Du1DuReadCrawler
paiotian=xyz.fycz.myreader.webapi.crawler.read.PiaoTianReadCrawler
laoyao=xyz.fycz.myreader.webapi.crawler.read.LaoYaoReadCrawler
xingxing=xyz.fycz.myreader.webapi.crawler.read.XingXingReadCrawler
shiguang=xyz.fycz.myreader.webapi.crawler.read.ShiGuangReadCrawler
xiagu=xyz.fycz.myreader.webapi.crawler.read.XiaGuReadCrawler
hongchen=xyz.fycz.myreader.webapi.crawler.read.HongChenReadCrawler

@ -1,2 +1,2 @@
#Mon Nov 30 10:23:34 CST 2020
VERSION_CODE=174
#Sun Dec 06 12:06:58 CST 2020
VERSION_CODE=175

@ -10,6 +10,7 @@ buildscript {
google()
maven { url 'http://s3.amazonaws.com/fabric-artifacts/public' }
maven { url 'https://plugins.gradle.org/m2/' }
maven { url "https://maven.java.net/content/groups/public/" }
}
dependencies {
classpath 'com.android.tools.build:gradle:3.6.2'

Loading…
Cancel
Save