优化搜索、修复bug

pull/5/head v1.9.1
fengyuecanzhu 4 years ago
parent 9654badccd
commit 2846daff3d
  1. BIN
      .idea/caches/build_file_checksums.ser
  2. 2
      LICENSE
  3. 4
      README.md
  4. 4
      app/build.gradle
  5. 16
      app/src/main/assets/updatelog.fy
  6. 68
      app/src/main/java/xyz/fycz/myreader/entity/SearchBookBean.java
  7. 1
      app/src/main/java/xyz/fycz/myreader/greendao/entity/Book.java
  8. 5
      app/src/main/java/xyz/fycz/myreader/model/source/BookSourceManager.java
  9. 1
      app/src/main/java/xyz/fycz/myreader/model/source/MatcherAnalyzer.java
  10. 51
      app/src/main/java/xyz/fycz/myreader/ui/activity/BookDetailedActivity.java
  11. 46
      app/src/main/java/xyz/fycz/myreader/ui/activity/SearchBookActivity.java
  12. 50
      app/src/main/java/xyz/fycz/myreader/ui/adapter/BookTagAdapter.java
  13. 8
      app/src/main/java/xyz/fycz/myreader/ui/adapter/BookcaseDetailedAdapter.java
  14. 8
      app/src/main/java/xyz/fycz/myreader/ui/adapter/BookcaseDragAdapter.java
  15. 55
      app/src/main/java/xyz/fycz/myreader/ui/adapter/SearchBookAdapter.java
  16. 10
      app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/BookStoreBookHolder.java
  17. 4
      app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/LocalSourceHolder.java
  18. 199
      app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/SearchBookHolder.java
  19. 2
      app/src/main/java/xyz/fycz/myreader/ui/fragment/DIYSourceFragment.java
  20. 11
      app/src/main/java/xyz/fycz/myreader/webapi/CommonApi.java
  21. 76
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/ReadCrawlerUtil.java
  22. 13
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/base/BaseSourceCrawler.java
  23. 5
      app/src/main/java/xyz/fycz/myreader/widget/page/NetPageLoader.java
  24. 8
      app/src/main/res/drawable/tag_blue_shape.xml
  25. 8
      app/src/main/res/drawable/tag_green_shape.xml
  26. 8
      app/src/main/res/drawable/tag_red_shape.xml
  27. 11
      app/src/main/res/layout/item_book_tag.xml
  28. 31
      app/src/main/res/layout/layout_book_detail_header.xml
  29. 139
      app/src/main/res/layout/listview_search_book_item.xml
  30. 6
      app/src/main/res/menu/menu_search.xml
  31. 39
      app/src/test/java/Test.java
  32. 4
      app/version_code.properties

@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2020 fengyuecanzhu
Copyright 2020~2021 fengyuecanzhu
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

@ -2,7 +2,7 @@
风月读书,一款开源、无广告的小说阅读软件。
成品下载(v1.9.0-beta 支持自定义书源):[https://fycz.lanzous.com/ixI19lqnscf](https://fycz.lanzous.com/ixI19lqnscf)
成品下载(v1.9.1 支持自定义书源):[https://fycz.lanzous.com/ijJsnmcfwja](https://fycz.lanzous.com/ijJsnmcfwja)
[更新日志](./app/src/main/assets/updatelog.fy)
@ -39,7 +39,7 @@
## LICENSE
```
Copyright 2020 fengyuecanzhu
Copyright 2020~2021 fengyuecanzhu
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

@ -44,7 +44,7 @@ def getVersionName(){
def hun = (version / 100).toInteger()
def ten = (version / 10).toInteger() % 10
def one = version % 10
return hun + "." + ten + "." + one + "-beta"
return hun + "." + ten + "." + one
}
def versionN = getVersionName()
@ -188,6 +188,8 @@ dependencies {
//
implementation 'com.github.albfernandez:juniversalchardet:2.4.0'
// https://github.com/hongyangAndroid/FlowLayout
implementation 'com.hyman:flowlayout-lib:1.1.2'
}
greendao {

@ -1,3 +1,9 @@
2021.03.01
风月读书v1.9.1
更新内容:
1、优化搜索
2、修复已知bug
2020.02.16
风月读书v1.9.0-beta
更新内容:
@ -17,16 +23,6 @@
4、修复已知bug
5、支持分享本地书籍(txt)
公告:
2021.02.06:
昨天应该是某站打击盗版导致许多小说网站被墙,书籍无法更新或加载,
您可通过科学上网或换源来获取书籍内容,或者等待网站恢复后更新软件。
被墙的书源网站:天籁小说、笔趣阁44、全本小说、米趣小说、九桃小说、
云中书库、小说旗、老幺小说、传奇小说、星星小说
当前已恢复的网站:天籁小说、小说旗(需要更新软件)
2020.02.01
风月读书v1.8.1
1、新增书源:笔尖小说、言情楼、卧龙小说

@ -7,9 +7,15 @@ import java.util.Objects;
* @date 2020/5/19 9:19
*/
public class SearchBookBean {
private String name;//书名
private String author;//作者
private int sourceCount;//书源数量
private String name;
private String author;
private String type;
private String desc;
private String status;
private String wordCount;
private String lastChapter;
private String updateTime;
private String imgUrl;
public SearchBookBean() {
}
@ -35,12 +41,60 @@ public class SearchBookBean {
this.author = author;
}
public int getSourceCount() {
return sourceCount;
public String getType() {
return type;
}
public void setSourceCount(int sourceCount) {
this.sourceCount = sourceCount;
public void setType(String type) {
this.type = type;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getWordCount() {
return wordCount;
}
public void setWordCount(String wordCount) {
this.wordCount = wordCount;
}
public String getLastChapter() {
return lastChapter;
}
public void setLastChapter(String lastChapter) {
this.lastChapter = lastChapter;
}
public String getUpdateTime() {
return updateTime;
}
public void setUpdateTime(String updateTime) {
this.updateTime = updateTime;
}
public String getImgUrl() {
return imgUrl;
}
public void setImgUrl(String imgUrl) {
this.imgUrl = imgUrl;
}
@Override

@ -341,5 +341,4 @@ public class Book implements Serializable {
this.status = status;
}
}

@ -109,12 +109,13 @@ public class BookSourceManager {
*/
@Nullable
public static BookSource getBookSourceByEName(String ename) {
if (ename == null) return getDefaultSource();
if ("local".equals(ename)) return getLocalSource();
return GreenDaoManager.getDaoSession().getBookSourceDao().
BookSource source = GreenDaoManager.getDaoSession().getBookSourceDao().
queryBuilder()
.where(BookSourceDao.Properties.SourceEName.eq(ename))
.unique();
if (source == null) return getDefaultSource();
return source;
}
/**

@ -104,6 +104,7 @@ public class MatcherAnalyzer extends BaseAnalyzer{
rules[1] = rules[1].replace("(*)", ".*");
rMatcher = Pattern.compile(rules[1]).matcher(html);
while ((lIndex = html.indexOf(rules[0], lIndex)) != -1) {
lIndex += rules[0].length();
while (rIndex < lIndex && rMatcher.find()) {
rIndex = rMatcher.start();
}

@ -45,6 +45,7 @@ import xyz.fycz.myreader.base.observer.MySingleObserver;
import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.common.URLCONST;
import xyz.fycz.myreader.databinding.ActivityBookDetailBinding;
import xyz.fycz.myreader.entity.SearchBookBean;
import xyz.fycz.myreader.entity.SharedBook;
import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.greendao.entity.Chapter;
@ -52,6 +53,7 @@ import xyz.fycz.myreader.greendao.entity.rule.BookSource;
import xyz.fycz.myreader.greendao.service.BookService;
import xyz.fycz.myreader.model.source.BookSourceManager;
import xyz.fycz.myreader.greendao.service.ChapterService;
import xyz.fycz.myreader.ui.adapter.BookTagAdapter;
import xyz.fycz.myreader.ui.adapter.DetailCatalogAdapter;
import xyz.fycz.myreader.ui.dialog.BookGroupDialog;
import xyz.fycz.myreader.ui.dialog.DialogCreator;
@ -94,6 +96,7 @@ public class BookDetailedActivity extends BaseActivity {
private SourceExchangeDialog mSourceDialog;
private int sourceIndex;
private BookGroupDialog mBookGroupDia;
private List<String> tagList = new ArrayList<>();
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
@ -146,10 +149,32 @@ public class BookDetailedActivity extends BaseActivity {
if (isCollected) {
mChapters = (ArrayList<Chapter>) mChapterService.findBookAllChapterByBookId(mBook.getId());
}
//Dialog
mSourceDialog = new SourceExchangeDialog(this, mBook);
if (isBookSourceNotExist()){
DialogCreator.createCommonDialog(this, "未知书源",
"当前书籍的书源不存在,是否搜索以切换书源?", false, (dialog, which) -> {
mSourceDialog.show();
}, null);
}
mBookGroupDia = new BookGroupDialog(this);
mReadCrawler = ReadCrawlerUtil.getReadCrawler(mBook.getSource());
}
private void initTagList() {
tagList.clear();
String type = mBook.getType();
if (!StringHelper.isEmpty(type))
tagList.add("0:" + type);
String wordCount = mBook.getWordCount();
if (!StringHelper.isEmpty(wordCount))
tagList.add("1:" + wordCount);
String status = mBook.getStatus();
if (!StringHelper.isEmpty(status))
tagList.add("2:" + status);
binding.ih.tflBookTag.setAdapter(new BookTagAdapter(this, tagList, 13));
}
@Override
protected void setUpToolbar(Toolbar toolbar) {
super.setUpToolbar(toolbar);
@ -182,8 +207,6 @@ public class BookDetailedActivity extends BaseActivity {
binding.ib.bookDetailTvOpen.setText("继续阅读");
}
//Dialog
mSourceDialog = new SourceExchangeDialog(this, mBook);
if (aBooks != null && aBooks.size() > 0) {
if (isCollected) {
for (int i = 0; i < aBooks.size(); i++) {
@ -304,6 +327,11 @@ public class BookDetailedActivity extends BaseActivity {
}
}
private boolean isBookSourceNotExist(){
BookSource source = BookSourceManager.getBookSourceByStr(mBook.getSource());
return source.getSourceEName() != null && "fynovel".equals(source.getSourceEName());
}
/**
* 初始化书籍信息
*/
@ -312,12 +340,8 @@ public class BookDetailedActivity extends BaseActivity {
if (StringHelper.isEmpty(mBook.getImgUrl())) {
mBook.setImgUrl("");
}
initTagList();
binding.ic.bookDetailTvDesc.setText("");
if (mBook.getType() != null) {
binding.ih.bookDetailTvType.setText(mBook.getType());
} else {
binding.ih.bookDetailTvType.setText("");
}
BookSource source = BookSourceManager.getBookSourceByStr(mBook.getSource());
binding.ih.bookDetailSource.setText(String.format("书源:%s", source.getSourceName()));
ReadCrawler rc = ReadCrawlerUtil.getReadCrawler(source);
@ -346,17 +370,10 @@ public class BookDetailedActivity extends BaseActivity {
* 初始化其他书籍信息
*/
private void initOtherInfo() {
binding.ic.bookDetailTvDesc.setText("\t\t\t\t" + mBook.getDesc());
binding.ih.bookDetailTvType.setText(mBook.getType());
binding.ic.bookDetailTvDesc.setText(String.format("\t\t\t\t%s", mBook.getDesc()));
initTagList();
if (!App.isDestroy(this)) {
binding.ih.bookDetailIvCover.load(mBook.getImgUrl(), mBook.getName(), mBook.getAuthor());
/*Glide.with(this)
.load(mBook.getImgUrl())
.transition(DrawableTransitionOptions.withCrossFade(1500))
.thumbnail(defaultCover())
.centerCrop()
.apply(RequestOptions.bitmapTransform(new BlurTransformation(this, 25)))
.into(mIvBlurCover);*/
binding.ih.bookDetailIvCover.load(NetworkUtils.getAbsoluteURL(mReadCrawler.getNameSpace(), mBook.getImgUrl()), mBook.getName(), mBook.getAuthor());
}
}

@ -90,6 +90,8 @@ public class SearchBookActivity extends BaseActivity {
private Menu menu;
private AlertDialog mDisableSourceDia;
private static String[] suggestion = {"第一序列", "大道朝天", "伏天氏", "终极斗罗", "我师兄实在太稳健了", "烂柯棋缘", "诡秘之主"};
private static String[] suggestion2 = {"不朽凡人", "圣墟", "我是至尊", "龙王传说", "太古神王", "一念永恒", "雪鹰领主", "大主宰"};
@ -295,7 +297,10 @@ public class SearchBookActivity extends BaseActivity {
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
if (!showHot) menu.findItem(R.id.action_hot).setVisible(true);
if (!showHot) {
menu.findItem(R.id.action_hot).setVisible(true);
menu.findItem(R.id.action_disable_source).setVisible(true);
}
return super.onPrepareOptionsMenu(menu);
}
@ -304,7 +309,9 @@ public class SearchBookActivity extends BaseActivity {
if (item.getItemId() == R.id.action_hot) {
showHot = !showHot;
initSuggestionList();
} else if (item.getItemId() == R.id.action_source_man) {
}else if (item.getItemId() == R.id.action_disable_source) {
showDisableSourceDia();
}else if (item.getItemId() == R.id.action_source_man) {
startActivityForResult(new Intent(this, BookSourceActivity.class),
APPCONST.REQUEST_BOOK_SOURCE);
} else {
@ -342,7 +349,7 @@ public class SearchBookActivity extends BaseActivity {
MenuItem localItem = menu.add(R.id.source_group, Menu.NONE, Menu.NONE, R.string.local_source);
if ("".equals(searchGroup)) {
item.setChecked(true);
}else if (getString(R.string.local_source).equals(searchGroup)){
} else if (getString(R.string.local_source).equals(searchGroup)) {
localItem.setChecked(true);
}
List<String> groupList = BookSourceManager.getEnableNoLocalGroupList();
@ -353,7 +360,7 @@ public class SearchBookActivity extends BaseActivity {
menu.setGroupCheckable(R.id.source_group, true, true);
}
/*private void showDisableSourceDia() {
private void showDisableSourceDia() {
if (mDisableSourceDia != null) {
mDisableSourceDia.show();
return;
@ -394,7 +401,7 @@ public class SearchBookActivity extends BaseActivity {
}
}
});
}*/
}
/**
* 初始化建议书目
@ -517,28 +524,32 @@ public class SearchBookActivity extends BaseActivity {
*/
private void search() {
binding.rpb.setIsAutoLoading(true);
binding.fabSearchStop.setVisibility(View.VISIBLE);
if (StringHelper.isEmpty(searchKey)) {
stopSearch();
binding.rpb.setIsAutoLoading(false);
binding.rvSearchBooksList.setVisibility(View.GONE);
binding.llSuggestBooksView.setVisibility(View.VISIBLE);
binding.fabSearchStop.setVisibility(View.GONE);
initHistoryList();
binding.rvSearchBooksList.setAdapter(null);
binding.srlSearchBookList.setEnableRefresh(false);
} else {
mSearchBookAdapter = new SearchBookAdapter(mBooks, searchEngine, searchKey);
mSearchBookAdapter = new SearchBookAdapter(this, mBooks, searchEngine, searchKey);
binding.rvSearchBooksList.setAdapter(mSearchBookAdapter);
//进入书籍详情页
mSearchBookAdapter.setOnItemClickListener((view, pos) -> {
SearchBookBean data = mSearchBookAdapter.getItem(pos);
ArrayList<Book> books = (ArrayList<Book>) mBooks.getValues(data);
searchBookBean2Book(data, books.get(0));
Intent intent = new Intent(this, BookDetailedActivity.class);
intent.putExtra(APPCONST.SEARCH_BOOK_BEAN, new ArrayList<>(mBooks.getValues(mSearchBookAdapter.getItem(pos))));
intent.putExtra(APPCONST.SEARCH_BOOK_BEAN, books);
startActivity(intent);
});
binding.srlSearchBookList.setEnableRefresh(true);
binding.rvSearchBooksList.setVisibility(View.VISIBLE);
binding.llSuggestBooksView.setVisibility(View.GONE);
binding.llHistoryView.setVisibility(View.GONE);
binding.fabSearchStop.setVisibility(View.VISIBLE);
getData();
mSearchHistoryService.addOrUpadteHistory(searchKey);
//收起软键盘
@ -570,4 +581,23 @@ public class SearchBookActivity extends BaseActivity {
}
super.onDestroy();
}
private void searchBookBean2Book(SearchBookBean bean, Book book) {
if (StringHelper.isEmpty(book.getType()) && !StringHelper.isEmpty(bean.getType()))
book.setType(bean.getType());
if (StringHelper.isEmpty(book.getType()) && !StringHelper.isEmpty(bean.getType()))
book.setType(bean.getType());
if (StringHelper.isEmpty(book.getDesc()) && !StringHelper.isEmpty(bean.getDesc()))
book.setDesc(bean.getDesc());
if (StringHelper.isEmpty(book.getStatus()) && !StringHelper.isEmpty(bean.getStatus()))
book.setStatus(bean.getStatus());
if (StringHelper.isEmpty(book.getWordCount()) && !StringHelper.isEmpty(bean.getWordCount()))
book.setWordCount(bean.getWordCount());
if (StringHelper.isEmpty(book.getNewestChapterTitle()) && !StringHelper.isEmpty(bean.getLastChapter()))
book.setNewestChapterTitle(bean.getLastChapter());
if (StringHelper.isEmpty(book.getUpdateDate()) && !StringHelper.isEmpty(bean.getUpdateTime()))
book.setUpdateDate(bean.getUpdateTime());
if (StringHelper.isEmpty(book.getImgUrl()) && !StringHelper.isEmpty(bean.getImgUrl()))
book.setImgUrl(bean.getImgUrl());
}
}

@ -0,0 +1,50 @@
package xyz.fycz.myreader.ui.adapter;
import android.content.Context;
import android.view.View;
import android.widget.TextView;
import androidx.core.content.ContextCompat;
import com.zhy.view.flowlayout.FlowLayout;
import com.zhy.view.flowlayout.TagAdapter;
import java.util.List;
import xyz.fycz.myreader.R;
import xyz.fycz.myreader.util.ToastUtils;
/**
* @author fengyue
* @date 2021/2/17 12:55
*/
public class BookTagAdapter extends TagAdapter<String> {
private TextView tvTagName;
private final Context context;
private final int textSize;
public BookTagAdapter(Context context, List<String> datas, int textSize) {
super(datas);
this.context = context;
this.textSize = textSize;
}
@Override
public View getView(FlowLayout parent, int position, String tagName) {
try {
tvTagName = (TextView) View.inflate(context, R.layout.item_book_tag, null);
tvTagName.setTextSize(textSize);
//默认为分类
if (tagName.startsWith("1:")) { //字数
tvTagName.setBackground(ContextCompat.getDrawable(context, R.drawable.tag_green_shape));
} else if (tagName.startsWith("2:")) {//连载状态
tvTagName.setBackground(ContextCompat.getDrawable(context, R.drawable.tag_red_shape));
}
tvTagName.setText(tagName.substring(2));
} catch (Exception e) {
e.printStackTrace();
ToastUtils.showError("" + e.getLocalizedMessage());
}
return tvTagName;
}
}

@ -16,6 +16,8 @@ import java.util.ArrayList;
import xyz.fycz.myreader.R;
import xyz.fycz.myreader.application.App;
import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.greendao.entity.rule.BookSource;
import xyz.fycz.myreader.model.source.BookSourceManager;
import xyz.fycz.myreader.ui.activity.ReadActivity;
import xyz.fycz.myreader.ui.dialog.DialogCreator;
import xyz.fycz.myreader.ui.dialog.MyAlertDialog;
@ -24,6 +26,9 @@ import xyz.fycz.myreader.ui.activity.BookDetailedActivity;
import xyz.fycz.myreader.ui.presenter.BookcasePresenter;
import xyz.fycz.myreader.util.StringHelper;
import xyz.fycz.myreader.util.ToastUtils;
import xyz.fycz.myreader.util.utils.NetworkUtils;
import xyz.fycz.myreader.webapi.crawler.ReadCrawlerUtil;
import xyz.fycz.myreader.webapi.crawler.base.ReadCrawler;
/**
@ -66,7 +71,8 @@ public class BookcaseDetailedAdapter extends BookcaseAdapter {
if (StringHelper.isEmpty(book.getImgUrl())) {
book.setImgUrl("");
}
viewHolder.ivBookImg.load(book.getImgUrl(), book.getName(),book.getAuthor());
ReadCrawler rc = ReadCrawlerUtil.getReadCrawler(book.getSource());
viewHolder.ivBookImg.load(NetworkUtils.getAbsoluteURL(rc.getNameSpace(), book.getImgUrl()), book.getName(),book.getAuthor());
viewHolder.tvBookName.setText(book.getName());

@ -14,6 +14,8 @@ import java.util.ArrayList;
import xyz.fycz.myreader.R;
import xyz.fycz.myreader.application.App;
import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.greendao.entity.rule.BookSource;
import xyz.fycz.myreader.model.source.BookSourceManager;
import xyz.fycz.myreader.ui.activity.ReadActivity;
import xyz.fycz.myreader.ui.dialog.DialogCreator;
import xyz.fycz.myreader.ui.dialog.MyAlertDialog;
@ -22,6 +24,9 @@ import xyz.fycz.myreader.ui.activity.BookDetailedActivity;
import xyz.fycz.myreader.ui.presenter.BookcasePresenter;
import xyz.fycz.myreader.util.StringHelper;
import xyz.fycz.myreader.util.ToastUtils;
import xyz.fycz.myreader.util.utils.NetworkUtils;
import xyz.fycz.myreader.webapi.crawler.ReadCrawlerUtil;
import xyz.fycz.myreader.webapi.crawler.base.ReadCrawler;
public class BookcaseDragAdapter extends BookcaseAdapter {
@ -63,7 +68,8 @@ public class BookcaseDragAdapter extends BookcaseAdapter {
book.setImgUrl("");
}
viewHolder.ivBookImg.load(book.getImgUrl(), book.getName(),book.getAuthor());
ReadCrawler rc = ReadCrawlerUtil.getReadCrawler(book.getSource());
viewHolder.ivBookImg.load(NetworkUtils.getAbsoluteURL(rc.getNameSpace(), book.getImgUrl()), book.getName(),book.getAuthor());
viewHolder.tvBookName.setText(book.getName());

@ -1,5 +1,6 @@
package xyz.fycz.myreader.ui.adapter;
import android.app.Activity;
import android.text.TextUtils;
import xyz.fycz.myreader.application.App;
@ -14,6 +15,7 @@ import xyz.fycz.myreader.ui.adapter.holder.SearchBookHolder;
import xyz.fycz.myreader.util.utils.StringUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
@ -21,11 +23,13 @@ import java.util.List;
* @date 2020/10/2 10:08
*/
public class SearchBookAdapter extends BaseListAdapter<SearchBookBean> {
private Activity activity;
private ConcurrentMultiValueMap<SearchBookBean, Book> mBooks;
private SearchEngine searchEngine;
private String keyWord;
public SearchBookAdapter(ConcurrentMultiValueMap<SearchBookBean, Book> mBooks, SearchEngine searchEngine, String keyWord) {
public SearchBookAdapter(Activity activity, ConcurrentMultiValueMap<SearchBookBean, Book> mBooks, SearchEngine searchEngine, String keyWord) {
this.activity = activity;
this.mBooks = mBooks;
this.searchEngine = searchEngine;
this.keyWord = keyWord;
@ -33,7 +37,7 @@ public class SearchBookAdapter extends BaseListAdapter<SearchBookBean> {
@Override
protected IViewHolder<SearchBookBean> createViewHolder(int viewType) {
return new SearchBookHolder(mBooks, searchEngine, keyWord);
return new SearchBookHolder(activity, mBooks, searchEngine, keyWord);
}
public void addAll(List<SearchBookBean> newDataS, String keyWord) {
@ -63,7 +67,7 @@ public class SearchBookAdapter extends BaseListAdapter<SearchBookBean> {
break;
}
if (filterDataS != null && filterDataS.size() > 0) {
if (filterDataS.size() > 0) {
List<SearchBookBean> searchBookBeansAdd = new ArrayList<>();
if (copyDataS.size() == 0) {
copyDataS.addAll(filterDataS);
@ -79,7 +83,6 @@ public class SearchBookAdapter extends BaseListAdapter<SearchBookBean> {
break;
}
}
if (!hasSame) {
searchBookBeansAdd.add(temp);
}
@ -107,6 +110,7 @@ public class SearchBookAdapter extends BaseListAdapter<SearchBookBean> {
}
}
}
synchronized (this) {
App.runOnUiThread(() -> {
mList = copyDataS;
@ -115,4 +119,47 @@ public class SearchBookAdapter extends BaseListAdapter<SearchBookBean> {
}
}
}
private void sort(List<SearchBookBean> bookBeans) {
//排序,基于最符合关键字的搜书结果应该是最短的
//TODO ;这里只做了简单的比较排序,还需要继续完善
Collections.sort(bookBeans, (o1, o2) -> {
if (o1.getName().equals(keyWord))
return -1;
if (o2.getName().equals(keyWord))
return 1;
if (o1.getAuthor() != null && o1.getAuthor().equals(keyWord))
return -1;
if (o2.getAuthor() != null && o2.getAuthor().equals(keyWord))
return 1;
return Integer.compare(o1.getName().length(), o2.getName().length());
});
}
private int getAddIndex(List<SearchBookBean> beans, SearchBookBean bean) {
int maxWeight = 0;
int index = -1;
if (TextUtils.equals(keyWord, bean.getName())) {
maxWeight = 5;
}else if (TextUtils.equals(keyWord, bean.getAuthor())) {
maxWeight = 3;
}
for (int i = 0; i < beans.size(); i++) {
SearchBookBean searchBook = beans.get(i);
int weight = 0;
if (TextUtils.equals(bean.getName(), searchBook.getName())) {
weight = 4;
} else if (TextUtils.equals(bean.getAuthor(), searchBook.getAuthor())) {
weight = 2;
} else if (bean.getName().length() <= searchBook.getName().length()) {
weight = 1;
}
if (weight > maxWeight) {
index = i;
maxWeight = weight;
}
}
if (maxWeight == 5 || maxWeight == 3) index = 0;
return index;
}
}

@ -8,8 +8,12 @@ import xyz.fycz.myreader.R;
import xyz.fycz.myreader.application.App;
import xyz.fycz.myreader.base.adapter.ViewHolderImpl;
import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.greendao.entity.rule.BookSource;
import xyz.fycz.myreader.model.source.BookSourceManager;
import xyz.fycz.myreader.util.StringHelper;
import xyz.fycz.myreader.util.utils.NetworkUtils;
import xyz.fycz.myreader.webapi.crawler.ReadCrawlerUtil;
import xyz.fycz.myreader.webapi.crawler.base.ReadCrawler;
import xyz.fycz.myreader.widget.CoverImageView;
/**
@ -56,14 +60,16 @@ public class BookStoreBookHolder extends ViewHolderImpl<Book> {
tvBookNewestChapter.setText(StringHelper.isEmpty(data.getNewestChapterTitle()) ?
data.getDesc() : data.getNewestChapterTitle());
tvBookTime.setText(data.getUpdateDate());
BookSource source = BookSourceManager.getBookSourceByStr(data.getSource());
ReadCrawler rc = ReadCrawlerUtil.getReadCrawler(source);
if (hasImg){
tvBookImg.setVisibility(View.VISIBLE);
if (!App.isDestroy(mActivity)) {
tvBookImg.load(data.getImgUrl(), data.getName(), data.getAuthor());
tvBookImg.load(NetworkUtils.getAbsoluteURL(rc.getNameSpace(), data.getImgUrl()), data.getName(), data.getAuthor());
}
}
if (data.getSource() != null) {
tvBookSource.setText(String.format("书源:%s", BookSourceManager.getSourceNameByStr(data.getSource())));
tvBookSource.setText(String.format("书源:%s", source.getSourceName()));
}else {
tvBookSource.setText(data.getNewestChapterId());
}

@ -8,7 +8,9 @@ import java.util.HashMap;
import xyz.fycz.myreader.R;
import xyz.fycz.myreader.base.adapter.ViewHolderImpl;
import xyz.fycz.myreader.greendao.GreenDaoManager;
import xyz.fycz.myreader.greendao.entity.rule.BookSource;
import xyz.fycz.myreader.model.source.BookSourceManager;
import xyz.fycz.myreader.util.StringHelper;
import xyz.fycz.myreader.util.ToastUtils;
@ -47,10 +49,12 @@ public class LocalSourceHolder extends ViewHolderImpl<BookSource> {
tvEnable.setOnClickListener(v -> {
data.setEnable(true);
banOrUse(data);
GreenDaoManager.getDaoSession().getBookSourceDao().insertOrReplace(data);
});
tvDisable.setOnClickListener(v -> {
data.setEnable(false);
banOrUse(data);
GreenDaoManager.getDaoSession().getBookSourceDao().insertOrReplace(data);
});
tvCheck.setOnClickListener(v -> ToastUtils.showInfo("校验功能即将上线"));
}

@ -2,48 +2,66 @@ package xyz.fycz.myreader.ui.adapter.holder;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Handler;
import android.content.Intent;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import androidx.core.content.ContextCompat;
import com.zhy.view.flowlayout.FlowLayout;
import com.zhy.view.flowlayout.TagAdapter;
import com.zhy.view.flowlayout.TagFlowLayout;
import java.util.ArrayList;
import java.util.List;
import xyz.fycz.myreader.R;
import xyz.fycz.myreader.application.App;
import xyz.fycz.myreader.base.adapter.ViewHolderImpl;
import xyz.fycz.myreader.greendao.entity.rule.BookSource;
import xyz.fycz.myreader.model.source.BookSourceManager;
import xyz.fycz.myreader.model.SearchEngine;
import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.entity.SearchBookBean;
import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.greendao.entity.rule.BookSource;
import xyz.fycz.myreader.model.SearchEngine;
import xyz.fycz.myreader.model.mulvalmap.ConcurrentMultiValueMap;
import xyz.fycz.myreader.model.source.BookSourceManager;
import xyz.fycz.myreader.ui.activity.BookDetailedActivity;
import xyz.fycz.myreader.ui.adapter.BookTagAdapter;
import xyz.fycz.myreader.util.StringHelper;
import xyz.fycz.myreader.util.ToastUtils;
import xyz.fycz.myreader.util.utils.KeyWordUtils;
import xyz.fycz.myreader.util.utils.NetworkUtils;
import xyz.fycz.myreader.webapi.crawler.ReadCrawlerUtil;
import xyz.fycz.myreader.webapi.crawler.base.BookInfoCrawler;
import xyz.fycz.myreader.webapi.crawler.base.ReadCrawler;
import xyz.fycz.myreader.widget.CoverImageView;
import java.util.List;
/**
* @author fengyue
* @date 2020/10/2 10:10
*/
public class SearchBookHolder extends ViewHolderImpl<SearchBookBean> {
private Activity activity;
private ConcurrentMultiValueMap<SearchBookBean, Book> mBooks;
private SearchEngine searchEngine;
private String keyWord;
private List<String> tagList = new ArrayList<>();
public SearchBookHolder(ConcurrentMultiValueMap<SearchBookBean, Book> mBooks, SearchEngine searchEngine, String keyWord) {
public SearchBookHolder(Activity activity, ConcurrentMultiValueMap<SearchBookBean, Book> mBooks, SearchEngine searchEngine, String keyWord) {
this.activity = activity;
this.mBooks = mBooks;
this.searchEngine = searchEngine;
this.keyWord = keyWord;
}
private CoverImageView ivBookImg;
private TextView tvBookName;
private TagFlowLayout tflBookTag;
private TextView tvDesc;
private TextView tvAuthor;
private TextView tvType;
private TextView tvSource;
private TextView tvNewestChapter;
@ -56,9 +74,9 @@ public class SearchBookHolder extends ViewHolderImpl<SearchBookBean> {
public void initView() {
ivBookImg = findById(R.id.iv_book_img);
tvBookName = findById(R.id.tv_book_name);
tflBookTag = findById(R.id.tfl_book_tag);
tvAuthor = findById(R.id.tv_book_author);
tvDesc = findById(R.id.tv_book_desc);
tvType = findById(R.id.tv_book_type);
tvSource = findById(R.id.tv_book_source);
tvNewestChapter = findById(R.id.tv_book_newest_chapter);
}
@ -70,64 +88,153 @@ public class SearchBookHolder extends ViewHolderImpl<SearchBookBean> {
List<Book> aBooks = mBooks.getValues(data);
int bookCount = aBooks.size();
Book book = aBooks.get(0);
if (StringHelper.isEmpty(book.getImgUrl())) {
book.setImgUrl("");
}
if (!StringHelper.isEmpty(book.getDesc())) {
tvDesc.setText("简介:" + book.getDesc());
BookSource source = BookSourceManager.getBookSourceByStr(book.getSource());
ReadCrawler rc = ReadCrawlerUtil.getReadCrawler(source);
books2SearchBookBean(data, aBooks);
if (!StringHelper.isEmpty(data.getImgUrl())) {
if (!App.isDestroy((Activity) getContext())) {
ivBookImg.load(NetworkUtils.getAbsoluteURL(rc.getNameSpace(), data.getImgUrl()), data.getName(), data.getAuthor());
}
}
if (!StringHelper.isEmpty(book.getType())) {
tvType.setText(book.getType());
KeyWordUtils.setKeyWord(tvBookName, data.getName(), keyWord);
if (!StringHelper.isEmpty(data.getAuthor())) {
KeyWordUtils.setKeyWord(tvAuthor, data.getAuthor(), keyWord);
}
if (!StringHelper.isEmpty(book.getNewestChapterTitle())) {
tvNewestChapter.setText(getContext().getString(R.string.newest_chapter, book.getNewestChapterTitle()));
initTagList(data);
if (!StringHelper.isEmpty(data.getLastChapter())) {
tvNewestChapter.setText(getContext().getString(R.string.newest_chapter, data.getLastChapter()));
}
if (!StringHelper.isEmpty(book.getAuthor())) {
KeyWordUtils.setKeyWord(tvAuthor, book.getAuthor(), keyWord);
if (!StringHelper.isEmpty(data.getDesc())) {
tvDesc.setText(String.format("简介:%s", data.getDesc()));
}
KeyWordUtils.setKeyWord(tvBookName, book.getName(), keyWord);
BookSource source = BookSourceManager.getBookSourceByStr(book.getSource());
tvSource.setText(getContext().getString(R.string.source_title_num, source.getSourceName(), bookCount));
ReadCrawler rc = ReadCrawlerUtil.getReadCrawler(source);
if (rc instanceof BookInfoCrawler) {
if (tvBookName.getTag() == null || !(Boolean) tvBookName.getTag()) {
tvBookName.setTag(true);
} else {
initOtherInfo(book);
return;
App.getHandler().postDelayed(() -> {
if (needGetInfo(data) && rc instanceof BookInfoCrawler) {
if (tvBookName.getTag() == null || !(Boolean) tvBookName.getTag()) {
tvBookName.setTag(true);
} else {
initOtherInfo(data, rc);
return;
}
Log.i(book.getName(), "initOtherInfo");
BookInfoCrawler bic = (BookInfoCrawler) rc;
searchEngine.getBookInfo(book, bic, isSuccess -> {
if (isSuccess) {
List<Book> books = new ArrayList<>();
books.add(book);
books2SearchBookBean(data, books);
initOtherInfo(data, rc);
} else {
tvBookName.setTag(false);
}
});
}
Log.i(book.getName(), "initOtherInfo");
BookInfoCrawler bic = (BookInfoCrawler) rc;
searchEngine.getBookInfo(book, bic, isSuccess -> {
if (isSuccess)
App.runOnUiThread(() -> initOtherInfo(book));
else
tvBookName.setTag(false);
});
} else {
initOtherInfo(book);
}
}, 1000);
}
private void initOtherInfo(Book book) {
private void initOtherInfo(SearchBookBean book, ReadCrawler rc) {
//简介
if (StringHelper.isEmpty(tvDesc.getText().toString())) {
tvDesc.setText(String.format("简介:%s", book.getDesc()));
}
if (StringHelper.isEmpty(tvType.getText().toString())) {
tvType.setText(book.getType());
}
if (StringHelper.isEmpty(tvNewestChapter.getText().toString())) {
tvNewestChapter.setText(getContext().getString(R.string.newest_chapter, book.getNewestChapterTitle()));
tvNewestChapter.setText(getContext().getString(R.string.newest_chapter, book.getLastChapter()));
}
if (StringHelper.isEmpty(tvAuthor.getText().toString())) {
KeyWordUtils.setKeyWord(tvAuthor, book.getAuthor(), keyWord);
}
//图片
if (!App.isDestroy((Activity) getContext())) {
ivBookImg.load(book.getImgUrl(), book.getName(), book.getAuthor());
ivBookImg.load(NetworkUtils.getAbsoluteURL(rc.getNameSpace(), book.getImgUrl()), book.getName(), book.getAuthor());
}
}
private void initTagList(SearchBookBean data) {
tagList.clear();
String type = data.getType();
if (!StringHelper.isEmpty(type))
tagList.add("0:" + type);
String wordCount = data.getWordCount();
if (!StringHelper.isEmpty(wordCount))
tagList.add("1:" + wordCount);
String status = data.getStatus();
if (!StringHelper.isEmpty(status))
tagList.add("2:" + status);
tflBookTag.setAdapter(new BookTagAdapter(activity, tagList, 11));
}
private void books2SearchBookBean(SearchBookBean bookBean, List<Book> books) {
for (Book book : books) {
if (!StringHelper.isEmpty(bookBean.getAuthor())) break;
String author = book.getAuthor();
if (!StringHelper.isEmpty(author)) {
bookBean.setAuthor(author);
break;
}
}
for (Book book : books) {
if (!StringHelper.isEmpty(bookBean.getType())) break;
String type = book.getType();
if (!StringHelper.isEmpty(type)) {
bookBean.setType(type);
break;
}
}
for (Book book : books) {
if (!StringHelper.isEmpty(bookBean.getDesc())) break;
String desc = book.getDesc();
if (!StringHelper.isEmpty(desc)) {
bookBean.setDesc(desc);
break;
}
}
for (Book book : books) {
if (!StringHelper.isEmpty(bookBean.getStatus())) break;
String status = book.getStatus();
if (!StringHelper.isEmpty(status)) {
bookBean.setStatus(status);
break;
}
}
for (Book book : books) {
if (!StringHelper.isEmpty(bookBean.getWordCount())) break;
String wordCount = book.getWordCount();
if (!StringHelper.isEmpty(wordCount)) {
bookBean.setWordCount(wordCount);
break;
}
}
for (Book book : books) {
if (!StringHelper.isEmpty(bookBean.getLastChapter())) break;
String lastChapter = book.getNewestChapterTitle();
if (!StringHelper.isEmpty(lastChapter)) {
bookBean.setLastChapter(lastChapter);
break;
}
}
for (Book book : books) {
if (!StringHelper.isEmpty(bookBean.getUpdateTime())) break;
String updateTime = book.getUpdateDate();
if (!StringHelper.isEmpty(updateTime)) {
bookBean.setUpdateTime(updateTime);
break;
}
}
for (Book book : books) {
if (!StringHelper.isEmpty(bookBean.getImgUrl())) break;
String imgUrl = book.getImgUrl();
if (!StringHelper.isEmpty(imgUrl)) {
bookBean.setImgUrl(imgUrl);
break;
}
}
}
private boolean needGetInfo(SearchBookBean bookBean) {
if (StringHelper.isEmpty(bookBean.getAuthor())) return true;
if (StringHelper.isEmpty(bookBean.getType())) return true;
if (StringHelper.isEmpty(bookBean.getDesc())) return true;
if (StringHelper.isEmpty(bookBean.getLastChapter())) return true;
return StringHelper.isEmpty(bookBean.getImgUrl());
}
}

@ -392,7 +392,7 @@ public class DIYSourceFragment extends BaseFragment {
for (BookSource source : mBookSources) {
source.setEnable(!source.getEnable());
}
BookSourceManager.saveDatas(mBookSources);
GreenDaoManager.getDaoSession().getBookSourceDao().insertOrReplaceInTx(mBookSources);
mAdapter.notifyDataSetChanged();
}

@ -1,30 +1,23 @@
package xyz.fycz.myreader.webapi;
import android.util.Log;
import java.util.List;
import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.annotations.NonNull;
import okhttp3.MediaType;
import okhttp3.RequestBody;
import xyz.fycz.myreader.common.URLCONST;
import xyz.fycz.myreader.entity.SearchBookBean;
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.util.StringHelper;
import xyz.fycz.myreader.util.utils.NetworkUtils;
import xyz.fycz.myreader.util.utils.OkHttpUtils;
import xyz.fycz.myreader.webapi.callback.ResultCallback;
import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.webapi.crawler.base.BookInfoCrawler;
import xyz.fycz.myreader.webapi.crawler.base.ReadCrawler;
import xyz.fycz.myreader.webapi.crawler.read.FYReadCrawler;
import xyz.fycz.myreader.webapi.crawler.read.TianLaiReadCrawler;
import xyz.fycz.myreader.webapi.crawler.read.YanQingLouReadCrawler;
import java.io.IOException;
import java.util.List;
public class CommonApi extends BaseApi {

@ -52,7 +52,7 @@ public class ReadCrawlerUtil {
sb.deleteCharAt(sb.lastIndexOf(","));
searchSource = sb.toString();
spu.putString(App.getmContext().getString(R.string.searchSource), searchSource);
} else if (!"".equals(searchSource)){
} else if (!"".equals(searchSource)) {
String[] sources = searchSource.split(",");
for (String source : sources) {
readCrawlers.add(getReadCrawler(source));
@ -61,7 +61,7 @@ public class ReadCrawlerUtil {
return readCrawlers;
}
public static List<String> getAllSources(){
public static List<String> getAllSources() {
List<String> sources = new ArrayList<>();
for (LocalBookSource bookSource : LocalBookSource.values()) {
if (bookSource.equals(LocalBookSource.fynovel))
@ -77,14 +77,16 @@ public class ReadCrawlerUtil {
HashMap<CharSequence, Boolean> mSources = new LinkedHashMap<>();
if (searchSource == null) {
for (LocalBookSource bookSource : LocalBookSource.values()) {
if (bookSource.equals(LocalBookSource.fynovel) || bookSource.equals(LocalBookSource.local)) continue;
if (bookSource.equals(LocalBookSource.fynovel) || bookSource.equals(LocalBookSource.local))
continue;
mSources.put(bookSource.text, false);
}
} else {
String[] ableSources = searchSource.split(",");
bookSourceFor:
for (LocalBookSource bookSource : LocalBookSource.values()) {
if (bookSource.equals(LocalBookSource.fynovel) || bookSource.equals(LocalBookSource.local)) continue;
if (bookSource.equals(LocalBookSource.fynovel) || bookSource.equals(LocalBookSource.local))
continue;
for (String ableSource : ableSources) {
if (ableSource.equals(bookSource.toString())) {
mSources.put(bookSource.text, false);
@ -97,7 +99,7 @@ public class ReadCrawlerUtil {
return mSources;
}
public static void resetReadCrawlers(){
public static void resetReadCrawlers() {
StringBuilder sb = new StringBuilder();
for (LocalBookSource bookSource : LocalBookSource.values()) {
if (bookSource.equals(LocalBookSource.fynovel) || bookSource.equals(LocalBookSource.local))
@ -109,22 +111,22 @@ public class ReadCrawlerUtil {
SharedPreUtils.getInstance().putString(App.getmContext().getString(R.string.searchSource), sb.toString());
}
public synchronized static void addReadCrawler(LocalBookSource... bookSources){
public synchronized static void addReadCrawler(LocalBookSource... bookSources) {
SharedPreUtils spu = SharedPreUtils.getInstance();
String searchSource = spu.getString(App.getmContext().getString(R.string.searchSource));
if ("".equals(searchSource)){
if ("".equals(searchSource)) {
resetReadCrawlers();
return;
}
StringBuilder sb = new StringBuilder(searchSource);
for (LocalBookSource bookSource : bookSources){
for (LocalBookSource bookSource : bookSources) {
sb.append(",");
sb.append(bookSource.toString());
}
SharedPreUtils.getInstance().putString(App.getmContext().getString(R.string.searchSource), sb.toString());
}
public synchronized static void removeReadCrawler(String... bookSources){
public synchronized static void removeReadCrawler(String... bookSources) {
SharedPreUtils spu = SharedPreUtils.getInstance();
String searchSource = spu.getString(App.getmContext().getString(R.string.searchSource), null);
if (searchSource == null) {
@ -141,7 +143,7 @@ public class ReadCrawlerUtil {
}
}
StringBuilder sb = new StringBuilder();
for (String ableSource : ableSources){
for (String ableSource : ableSources) {
if ("".equals(ableSource)) continue;
sb.append(ableSource);
sb.append(",");
@ -172,46 +174,48 @@ public class ReadCrawlerUtil {
}
public static ReadCrawler getReadCrawler(BookSource source) {
if (StringHelper.isEmpty(source.getSourceEName())) {
BaseSourceCrawler crawler;
if (source.getSourceType() == null) source.setSourceType(MATCHER);
switch (source.getSourceType()){
case MATCHER: default:
crawler = new MatcherCrawler(source);
break;
case XPATH:
crawler = new XpathCrawler(source);
break;
case JSON_PATH:
crawler = new JsonPathCrawler(source);
break;
}
if (source.getSearchRule().isRelatedWithInfo()) {
return crawler;
try {
if (StringHelper.isEmpty(source.getSourceEName())) {
BaseSourceCrawler crawler;
if (source.getSourceType() == null) source.setSourceType(MATCHER);
switch (source.getSourceType()) {
case MATCHER:
default:
crawler = new MatcherCrawler(source);
break;
case XPATH:
crawler = new XpathCrawler(source);
break;
case JSON_PATH:
crawler = new JsonPathCrawler(source);
break;
}
if (source.getSearchRule().isRelatedWithInfo()) {
return crawler;
} else {
return new BaseSourceCrawlerNoInfo(crawler);
}
} else {
return new BaseSourceCrawlerNoInfo(crawler);
}
}else {
try {
Class clz = Class.forName(source.getSourceUrl());
return (ReadCrawler) clz.newInstance();
} catch (Exception e) {
e.printStackTrace();
return new FYReadCrawler();
}
} catch (Exception e) {
e.printStackTrace();
return new FYReadCrawler();
}
}
public static List<ReadCrawler> getEnableReadCrawlers(){
public static List<ReadCrawler> getEnableReadCrawlers() {
return getEnableReadCrawlers("");
}
public static List<ReadCrawler> getEnableReadCrawlers(String group){
public static List<ReadCrawler> getEnableReadCrawlers(String group) {
List<ReadCrawler> crawlers = new ArrayList<>();
List<BookSource> sources = TextUtils.isEmpty(group) ?
BookSourceManager.getEnabledBookSource() :
BookSourceManager.getEnableSourceByGroup(group);
for (BookSource source : sources){
for (BookSource source : sources) {
crawlers.add(getReadCrawler(source));
}
return crawlers;

@ -97,7 +97,6 @@ public abstract class BaseSourceCrawler implements ReadCrawler, BookInfoCrawler
List<String> imgs = analyzer.getStringList(searchRule.getImgUrl(), obj);
List<String> chapterUrls = analyzer.getStringList(searchRule.getTocUrl(), obj);
List<String> infoUrls = analyzer.getStringList(searchRule.getInfoUrl(), obj);
String baseUrl = getNameSpace();
for (int i = 0; i < names.size(); i++) {
Book book = new Book();
book.setName(names.get(i));
@ -110,11 +109,11 @@ public abstract class BaseSourceCrawler implements ReadCrawler, BookInfoCrawler
if (lastChapters.size() > i) book.setNewestChapterTitle(lastChapters.get(i));
if (updateTimes.size() > i) book.setUpdateDate(updateTimes.get(i));
if (imgs.size() > i)
book.setImgUrl(NetworkUtils.getAbsoluteURL(baseUrl, imgs.get(i)));
book.setImgUrl(imgs.get(i));
if (chapterUrls.size() > i)
book.setChapterUrl(NetworkUtils.getAbsoluteURL(baseUrl, chapterUrls.get(i)));
book.setChapterUrl(chapterUrls.get(i));
if (infoUrls.size() > i)
book.setInfoUrl(NetworkUtils.getAbsoluteURL(baseUrl, infoUrls.get(i)));
book.setInfoUrl(infoUrls.get(i));
SearchBookBean sbb = new SearchBookBean(book.getName(), book.getAuthor());
books.add(sbb, book);
}
@ -161,7 +160,7 @@ public abstract class BaseSourceCrawler implements ReadCrawler, BookInfoCrawler
book.setStatus(status);
book.setNewestChapterTitle(lastChapter);
book.setUpdateDate(updateTime);
book.setImgUrl(NetworkUtils.getAbsoluteURL(getNameSpace(), imgUrl));
book.setImgUrl(imgUrl);
book.setChapterUrl(tocUrl);
book.setInfoUrl(infoUrl);
book.setSource(source.getSourceUrl());
@ -171,6 +170,8 @@ public abstract class BaseSourceCrawler implements ReadCrawler, BookInfoCrawler
}
}
/**
* 获取章节列表
*
@ -332,7 +333,7 @@ public abstract class BaseSourceCrawler implements ReadCrawler, BookInfoCrawler
if (StringHelper.isEmpty(book.getUpdateDate()))
book.setUpdateDate(analyzer.getString(infoRule.getUpdateTime(), obj));
if (StringHelper.isEmpty(book.getImgUrl()))
book.setImgUrl(NetworkUtils.getAbsoluteURL(getNameSpace(), analyzer.getString(infoRule.getImgUrl(), obj)));
book.setImgUrl(analyzer.getString(infoRule.getImgUrl(), obj));
if (StringHelper.isEmpty(book.getChapterUrl()))
book.setChapterUrl(analyzer.getString(infoRule.getTocUrl(), obj));
return book;

@ -15,6 +15,7 @@ import xyz.fycz.myreader.entity.Setting;
import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.greendao.entity.Chapter;
import xyz.fycz.myreader.greendao.service.ChapterService;
import xyz.fycz.myreader.util.StringHelper;
import xyz.fycz.myreader.util.utils.FileUtils;
import xyz.fycz.myreader.webapi.CommonApi;
import xyz.fycz.myreader.webapi.callback.ResultCallback;
@ -225,7 +226,9 @@ public class NetPageLoader extends PageLoader {
@Override
public void onFinish(final Object o, int code) {
loadingChapters.remove(chapter);
mChapterService.saveOrUpdateChapter(chapter, (String) o);
String content = (String) o;
if (StringHelper.isEmpty(content)) content = "章节内容为空";
mChapterService.saveOrUpdateChapter(chapter, content);
if (isClose()) return;
if (getPageStatus() == PageLoader.STATUS_LOADING && mCurChapterPos == chapter.getNumber()) {
App.runOnUiThread(() -> {

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="3dp"/>
<solid android:color="@color/toast_blue"/>
<padding android:left="2dp"
android:right="2dp"/>
</shape>

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="3dp"/>
<solid android:color="@color/toast_green"/>
<padding android:left="2dp"
android:right="2dp"/>
</shape>

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="3dp"/>
<solid android:color="@color/toast_red"/>
<padding android:left="2dp"
android:right="2dp"/>
</shape>

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:text="@string/rule_book_type"
android:background="@drawable/tag_blue_shape"
tools:ignore="RtlSymmetry,SmallSp">
</TextView>

@ -35,34 +35,33 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="@+id/cover"
android:layout_marginLeft="14dp"
android:layout_marginStart="14dp"
android:layout_marginTop="30dp"
android:layout_toRightOf="@+id/cover"
android:layout_toEndOf="@+id/cover"
android:ellipsize="end"
android:maxLines="1"
android:textColor="@color/origin"
tools:text=" 茶叶蛋" />
<TextView
android:id="@+id/book_detail_tv_type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/book_detail_tv_author"
android:layout_alignLeft="@id/book_detail_tv_author"
android:layout_marginTop="6dp"
android:ellipsize="end"
android:maxLines="1"
android:textColor="@color/textSecondaryInverted"
tools:text="仙侠" />
<com.zhy.view.flowlayout.TagFlowLayout
android:id="@+id/tfl_book_tag"
android:layout_below="@+id/book_detail_tv_author"
android:layout_alignStart="@id/book_detail_tv_author"
android:layout_marginTop="2dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:max_select="0"
app:tag_gravity="left" />
<TextView
android:id="@+id/book_detail_source"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/book_detail_tv_type"
android:layout_alignLeft="@id/book_detail_tv_type"
android:layout_marginTop="6dp"
android:layout_below="@id/tfl_book_tag"
android:layout_alignStart="@id/tfl_book_tag"
android:layout_marginTop="2dp"
android:textColor="@color/textSecondaryInverted"
tools:text="书源" />

@ -1,97 +1,92 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content" xmlns:tools="http://schemas.android.com/tools"
android:orientation="horizontal"
android:background="@color/colorBackground"
android:padding="5dp">
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorBackground"
android:orientation="horizontal"
android:padding="5dp">
<xyz.fycz.myreader.widget.CoverImageView
android:id="@+id/iv_book_img"
android:layout_width="64dp"
android:layout_height="88dp"
android:layout_width="76dp"
android:layout_height="104dp"
android:scaleType="fitXY"
app:srcCompat="@mipmap/default_cover" />
<RelativeLayout
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="5dp"
android:padding="3dp">
android:orientation="vertical"
android:paddingStart="3dp"
android:paddingEnd="3dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_book_name"
android:layout_width="wrap_content"
android:layout_height="24dp"
android:layout_marginTop="5dp"
tools:text="bookname"
android:maxLength="12"
android:textSize="16sp"
android:textColor="@color/textPrimary"/>
<TextView
android:id="@+id/tv_book_author"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="5dp"
android:layout_marginTop="6dp"
tools:text="author"
android:maxLines="1"
android:textSize="13sp"
android:textColor="@color/textSecondary"/>
android:layout_height="wrap_content"
android:orientation="horizontal">
</LinearLayout>
<TextView
android:id="@+id/tv_book_newest_chapter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="1dp"
tools:text="newest_chapter"
android:maxLines="1"
android:textSize="13sp"
android:textColor="@color/textSecondary"/>
android:id="@+id/tv_book_name"
android:layout_width="wrap_content"
android:layout_height="24dp"
android:maxLength="12"
android:textColor="@color/textPrimary"
android:textSize="@dimen/text_normal_size"
tools:text="bookname" />
<TextView
android:id="@+id/tv_book_desc"
android:id="@+id/tv_book_author"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="2dp"
tools:text="book desc"
android:ellipsize="end"
android:maxLines="1"
android:textSize="13sp"
android:textColor="@color/textSecondary"/>
android:paddingStart="5dp"
android:textColor="@color/textSecondary"
android:textSize="@dimen/text_default_size"
tools:text="author" />
</LinearLayout>
<com.zhy.view.flowlayout.TagFlowLayout
android:id="@+id/tfl_book_tag"
android:layout_width="match_parent"
android:layout_height="20dp"
android:layout_marginTop="-6dp"
app:max_select="0"
app:tag_gravity="left" />
<TextView
android:id="@+id/tv_book_type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentStart="true"
tools:text="type"
android:maxLines="1"
android:textSize="13sp"
android:textColor="@color/textSecondary"/>
android:id="@+id/tv_book_newest_chapter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="1"
android:paddingTop="2dp"
android:textColor="@color/textSecondary"
android:textSize="@dimen/text_default_size"
tools:text="newest_chapter" />
<TextView
android:id="@+id/tv_book_source"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="3dp"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
tools:text="book source"
android:maxLines="1"
android:textSize="13sp"
android:textColor="@color/textSecondary"/>
</RelativeLayout>
android:id="@+id/tv_book_desc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="2"
android:textColor="@color/textSecondary"
android:textSize="@dimen/text_default_size"
tools:text="book desc" />
<TextView
android:id="@+id/tv_book_source"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="1"
android:textColor="@color/textSecondary"
android:textSize="@dimen/text_default_size"
tools:text="book source" />
</LinearLayout>
</LinearLayout>

@ -5,8 +5,12 @@
android:id="@+id/action_hot"
android:title="@string/hot_search"
android:visible="false"
app:showAsAction="always" />
<item
android:id="@+id/action_disable_source"
android:title="@string/disable_source"
android:visible="false"
app:showAsAction="ifRoom" />
<item
android:id="@+id/action_source_man"
android:title="@string/book_source_man"

@ -46,19 +46,6 @@ public class Test {
System.out.println(sb.toString());
}
@org.junit.Test
public void testRegex() throws UnsupportedEncodingException {
String str = new String(FileUtils.getBytes(new File("D:\\Java\\Project\\FYReader-master\\app\\src\\test\\resources\\html.html")), "GBK");
MatcherAnalyzer analyzer = new MatcherAnalyzer();
String ruleList = "<div id=\"content\"><text><div class=\"footer\">";
String list = analyzer.getInnerText(ruleList, str);
String rule = "(*)<td class=\"odd\"><a href=\".*\"><text></a></td>";
List<String> listStr = analyzer.matcherInnerText(rule, list);
for (String s : listStr) {
System.out.println(s);
}
}
@org.junit.Test
public void testUrl() {
@ -73,4 +60,30 @@ public class Test {
JXDocument jxDoc = JXDocument.create(str);
System.out.println(jxDoc.selNOne("//*[@id=\"intro\"]/p[1]/text()"));
}
@org.junit.Test
public void testBean() {
String[] strings = "type;desc;status;wordCount;lastChapter;updateTime;imgUrl".split(";");
String[] strings1 = new String[strings.length];
for (int i = 0, stringsLength = strings.length; i < stringsLength; i++) {
String s = strings[i];
strings1[i] = s.substring(0, 1).toUpperCase() + s.substring(1);
}
for (int i = 0; i < strings.length; i++) {
String s = strings[i];
/*String str =
" for (Book book : books){\n" +
" String "+ s + " = book.get" + strings1[i] + "();\n" +
" if (!StringHelper.isEmpty(bookBean.get" + strings1[i] + "())) break;\n" +
" if (!StringHelper.isEmpty("+ s + ")){\n" +
" bookBean.set" + strings1[i] + "("+ s + ");\n" +
" break;\n" +
" }\n" +
" }";*/
String str =
" if (StringHelper.isEmpty(book.get" + strings1[i] + "()) && !StringHelper.isEmpty(bean.get" + strings1[i] + "()))\n" +
" book.set" + strings1[i] + "(bean.get" + strings1[i] + "());";
System.out.println(str);
}
}
}

@ -1,2 +1,2 @@
#Tue Feb 16 22:03:51 CST 2021
VERSION_CODE=190
#Mon Mar 01 20:09:11 CST 2021
VERSION_CODE=191

Loading…
Cancel
Save