diff --git a/.idea/caches/build_file_checksums.ser b/.idea/caches/build_file_checksums.ser index 537dee3..ddc4980 100644 Binary files a/.idea/caches/build_file_checksums.ser and b/.idea/caches/build_file_checksums.ser differ diff --git a/app/build.gradle b/app/build.gradle index f49c48d..d917c47 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -161,12 +161,16 @@ dependencies { //二维码 implementation 'cn.bingoogolapple:bga-qrcode-zxing:1.3.7' - //Material Dialogs + + //编码识别 + implementation 'com.github.albfernandez:juniversalchardet:2.4.0' + /*//email implementation 'com.sun.mail:android-mail:1.6.2' implementation 'com.sun.mail:android-activation:1.6.2'*/ + //Material Dialogs /*def dialog_version = '3.3.0' implementation "com.afollestad.material-dialogs:core:$dialog_version" implementation "com.afollestad.material-dialogs:input:$dialog_version" diff --git a/app/libs/ZHConverter.jar b/app/libs/ZHConverter.jar deleted file mode 100644 index 53a12bb..0000000 Binary files a/app/libs/ZHConverter.jar and /dev/null differ diff --git a/app/libs/antlr-2.7.4.jar b/app/libs/antlr-2.7.4.jar deleted file mode 100644 index 45e45b5..0000000 Binary files a/app/libs/antlr-2.7.4.jar and /dev/null differ diff --git a/app/libs/chardet-1.0.jar b/app/libs/chardet-1.0.jar deleted file mode 100644 index 2e84a8d..0000000 Binary files a/app/libs/chardet-1.0.jar and /dev/null differ diff --git a/app/libs/cpdetector_1.0.10.jar b/app/libs/cpdetector_1.0.10.jar deleted file mode 100644 index 47329f2..0000000 Binary files a/app/libs/cpdetector_1.0.10.jar and /dev/null differ diff --git a/app/libs/jargs-1.0.jar b/app/libs/jargs-1.0.jar deleted file mode 100644 index 92d9b9b..0000000 Binary files a/app/libs/jargs-1.0.jar and /dev/null differ diff --git a/app/src/main/assets/updatelog.fy b/app/src/main/assets/updatelog.fy index 7460a79..e2eadaa 100644 --- a/app/src/main/assets/updatelog.fy +++ b/app/src/main/assets/updatelog.fy @@ -1,9 +1,14 @@ +1、极大地优化本地书籍章节拆分速度 +2、优化本地书籍文件编码识别 +3、修复目录未加载时搜索闪退的bug + 2020.12.06 风月读书v1.20.120612 1、新增书架排序设置 2、新增书籍分享(以图片+二维码的形式分享)及扫一扫(书架菜单) 3、新增书源:老幺小说、星星小说、时光小说、峡谷文学、红尘小说 4、修复欢迎页图片概率性未完全加载的bug +5、修复部分版本更新到最新版本闪退的bug 2020.11.28 风月读书v1.20.112822 diff --git a/app/src/main/java/xyz/fycz/myreader/entity/Setting.java b/app/src/main/java/xyz/fycz/myreader/entity/Setting.java index 8ce9265..91e492a 100644 --- a/app/src/main/java/xyz/fycz/myreader/entity/Setting.java +++ b/app/src/main/java/xyz/fycz/myreader/entity/Setting.java @@ -89,8 +89,7 @@ public class Setting implements Serializable { public ReadStyle getCurReadStyle(){ //Log.d("curReadStyleIndex", String.valueOf(curReadStyleIndex)); - ReadStyle readStyle = readStyles.get(curReadStyleIndex); - if (readStyle == null) { + if (readStyles == null || readStyles.size() == 0) { initReadStyle(); } if (!dayStyle){ diff --git a/app/src/main/java/xyz/fycz/myreader/greendao/entity/Book.java b/app/src/main/java/xyz/fycz/myreader/greendao/entity/Book.java index 9f6f3f5..50245bc 100644 --- a/app/src/main/java/xyz/fycz/myreader/greendao/entity/Book.java +++ b/app/src/main/java/xyz/fycz/myreader/greendao/entity/Book.java @@ -30,7 +30,7 @@ public class Book implements Serializable { private String name;//书名 private String chapterUrl;//书目Url(本地书籍为:本地书籍地址) - private String infoUrl;//书目详情Url + private String infoUrl;//书目详情Url(本地书籍为:文件编码) private String imgUrl;//封面图片url private String desc;//简介 private String author;//作者 diff --git a/app/src/main/java/xyz/fycz/myreader/greendao/entity/Chapter.java b/app/src/main/java/xyz/fycz/myreader/greendao/entity/Chapter.java index 00a1144..4136ce9 100644 --- a/app/src/main/java/xyz/fycz/myreader/greendao/entity/Chapter.java +++ b/app/src/main/java/xyz/fycz/myreader/greendao/entity/Chapter.java @@ -79,6 +79,7 @@ public class Chapter { this.url = url; } public String getContent() { + if (end > 0) return end + ""; String filePath = APPCONST.BOOK_CACHE_PATH + bookId + File.separator + title + FileUtils.SUFFIX_FY; File file = new File(filePath); diff --git a/app/src/main/java/xyz/fycz/myreader/greendao/service/ChapterService.java b/app/src/main/java/xyz/fycz/myreader/greendao/service/ChapterService.java index 50fb66e..4c3d3d3 100644 --- a/app/src/main/java/xyz/fycz/myreader/greendao/service/ChapterService.java +++ b/app/src/main/java/xyz/fycz/myreader/greendao/service/ChapterService.java @@ -42,6 +42,8 @@ public class ChapterService extends BaseService { chapter.setTitle(cursor.getString(3)); chapter.setUrl(cursor.getString(4)); chapter.setContent(cursor.getString(5)); + chapter.setStart(cursor.getInt(6)); + chapter.setEnd(cursor.getInt(7)); chapters.add(chapter); } } catch (Exception e) { @@ -284,6 +286,7 @@ public class ChapterService extends BaseService { return file.exists(); } + private void deleteAllChapterCacheFile(String bookId) { FileUtils.deleteFile(APPCONST.BOOK_CACHE_PATH + bookId); } diff --git a/app/src/main/java/xyz/fycz/myreader/ui/activity/MainActivity.java b/app/src/main/java/xyz/fycz/myreader/ui/activity/MainActivity.java index 36b6ccd..ee8d876 100644 --- a/app/src/main/java/xyz/fycz/myreader/ui/activity/MainActivity.java +++ b/app/src/main/java/xyz/fycz/myreader/ui/activity/MainActivity.java @@ -182,10 +182,10 @@ public class MainActivity extends BaseActivity { } try { int sourceVersion = SysManager.getSetting().getSourceVersion(); - if (sourceVersion < APPCONST.SOURCE_VERSION) { + //if (sourceVersion < APPCONST.SOURCE_VERSION) { SysManager.resetSource(); Log.d(TAG, "resetSource"); - } + //} } catch (Exception e) { ToastUtils.showError(e.getLocalizedMessage()); e.printStackTrace(); diff --git a/app/src/main/java/xyz/fycz/myreader/ui/activity/ReadActivity.java b/app/src/main/java/xyz/fycz/myreader/ui/activity/ReadActivity.java index 887aeaa..cb19859 100644 --- a/app/src/main/java/xyz/fycz/myreader/ui/activity/ReadActivity.java +++ b/app/src/main/java/xyz/fycz/myreader/ui/activity/ReadActivity.java @@ -911,14 +911,18 @@ public class ReadActivity extends BaseActivity implements ColorPickerDialogListe */ private void getData() { mChapters = (ArrayList) mChapterService.findBookAllChapterByBookId(mBook.getId()); - if (!isCollected || mChapters.size() == 0 || ("本地书籍".equals(mBook.getType()) && - !ChapterService.isChapterCached(mBook.getId(), mChapters.get(0).getTitle()))) { + if (!isCollected || mChapters.size() == 0 || ("本地书籍".equals(mBook.getType()) && !ChapterService.isChapterCached(mBook.getId(), mChapters.get(0).getTitle()) + )) { if ("本地书籍".equals(mBook.getType())) { if (!new File(mBook.getChapterUrl()).exists()) { ToastUtils.showWarring("书籍缓存为空且源文件不存在,书籍加载失败!"); finish(); return; } + if (mChapters.size() != 0 && mChapters.get(0).getEnd() > 0){ + initChapters(); + return; + } ((LocalPageLoader) mPageLoader).loadChapters(new ResultCallback() { @Override public void onFinish(Object o, int code) { @@ -935,6 +939,7 @@ public class ReadActivity extends BaseActivity implements ColorPickerDialogListe @Override public void onError(Exception e) { + e.printStackTrace(); mChapters.clear(); initChapters(); mHandler.sendMessage(mHandler.obtainMessage(1)); diff --git a/app/src/main/java/xyz/fycz/myreader/ui/adapter/BookMarkAdapter.java b/app/src/main/java/xyz/fycz/myreader/ui/adapter/BookMarkAdapter.java index e12cdc0..96c3418 100644 --- a/app/src/main/java/xyz/fycz/myreader/ui/adapter/BookMarkAdapter.java +++ b/app/src/main/java/xyz/fycz/myreader/ui/adapter/BookMarkAdapter.java @@ -9,6 +9,8 @@ import android.widget.Filter; import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.core.content.ContextCompat; + import xyz.fycz.myreader.R; import xyz.fycz.myreader.application.SysManager; import xyz.fycz.myreader.entity.Setting; @@ -58,13 +60,14 @@ public class BookMarkAdapter extends ArrayAdapter { private void initView(int postion,final ViewHolder viewHolder){ final BookMark bookMark = getItem(postion); - viewHolder.tvTitle.setText(bookMark.getTitle() + "[" + (bookMark.getBookMarkReadPosition() + 1) + "]"); + assert bookMark != null; + viewHolder.tvTitle.setText(String.format("%s[%s]", bookMark.getTitle(), bookMark.getBookMarkReadPosition() + 1)); if (ChapterService.isChapterCached(bookMark.getBookId(), bookMark.getTitle())){ - viewHolder.tvTitle.setCompoundDrawablesWithIntrinsicBounds(getContext().getResources().getDrawable(R.drawable.selector_category_load),null,null,null); + viewHolder.tvTitle.setCompoundDrawablesWithIntrinsicBounds(ContextCompat.getDrawable(getContext(), R.drawable.selector_category_load),null,null,null); } else { - viewHolder.tvTitle.setCompoundDrawablesWithIntrinsicBounds(getContext().getResources().getDrawable(R.drawable.selector_category_unload),null,null,null); + viewHolder.tvTitle.setCompoundDrawablesWithIntrinsicBounds(ContextCompat.getDrawable(getContext(),R.drawable.selector_category_unload),null,null,null); } - viewHolder.tvTitle.setTextColor(getContext().getColor(R.color.textSecondary)); + viewHolder.tvTitle.setTextColor(getContext().getResources().getColor(R.color.textSecondary)); /*if (!setting.isDayStyle()) { viewHolder.tvTitle.setTextColor(getContext().getResources().getColor(R.color.sys_night_word)); viewHolder.vLine.setBackground(getContext().getDrawable(R.color.sys_dialog_setting_line)); diff --git a/app/src/main/java/xyz/fycz/myreader/ui/adapter/ChapterTitleAdapter.java b/app/src/main/java/xyz/fycz/myreader/ui/adapter/ChapterTitleAdapter.java index 5300840..c07512e 100644 --- a/app/src/main/java/xyz/fycz/myreader/ui/adapter/ChapterTitleAdapter.java +++ b/app/src/main/java/xyz/fycz/myreader/ui/adapter/ChapterTitleAdapter.java @@ -9,6 +9,8 @@ import android.widget.Filter; import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.core.content.ContextCompat; + import xyz.fycz.myreader.R; import xyz.fycz.myreader.application.SysManager; import xyz.fycz.myreader.entity.Setting; @@ -66,10 +68,10 @@ public class ChapterTitleAdapter extends ArrayAdapter { final Chapter chapter = getItem(postion); // viewHolder.tvTitle.setText("【" + chapter.getTitle() + "】"); viewHolder.tvTitle.setText(chapter.getTitle()); - if (ChapterService.isChapterCached(chapter.getBookId(), chapter.getTitle())) { - viewHolder.tvTitle.setCompoundDrawablesWithIntrinsicBounds(getContext().getResources().getDrawable(R.drawable.selector_category_load), null, null, null); + if (ChapterService.isChapterCached(chapter.getBookId(), chapter.getTitle()) || chapter.getEnd() > 0 ) { + viewHolder.tvTitle.setCompoundDrawablesWithIntrinsicBounds(ContextCompat.getDrawable(getContext(),R.drawable.selector_category_load), null, null, null); } else { - viewHolder.tvTitle.setCompoundDrawablesWithIntrinsicBounds(getContext().getResources().getDrawable(R.drawable.selector_category_unload), null, null, null); + viewHolder.tvTitle.setCompoundDrawablesWithIntrinsicBounds(ContextCompat.getDrawable(getContext(),R.drawable.selector_category_unload), null, null, null); } viewHolder.tvTitle.setTextColor(getContext().getResources().getColor(R.color.textSecondary)); /*if (!setting.isDayStyle()) { diff --git a/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/CatalogHolder.java b/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/CatalogHolder.java index 4c097f1..564f5ee 100644 --- a/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/CatalogHolder.java +++ b/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/CatalogHolder.java @@ -1,6 +1,9 @@ package xyz.fycz.myreader.ui.adapter.holder; import android.widget.TextView; + +import androidx.core.content.ContextCompat; + import xyz.fycz.myreader.R; import xyz.fycz.myreader.base.adapter.ViewHolderImpl; import xyz.fycz.myreader.greendao.entity.Chapter; @@ -24,10 +27,10 @@ public class CatalogHolder extends ViewHolderImpl { @Override public void onBind(Chapter data, int pos) { - if (ChapterService.isChapterCached(data.getBookId(), data.getTitle())) { - tvTitle.setCompoundDrawablesWithIntrinsicBounds(getContext().getResources().getDrawable(R.drawable.selector_category_load), null, null, null); + if (ChapterService.isChapterCached(data.getBookId(), data.getTitle()) || data.getEnd() > 0) { + tvTitle.setCompoundDrawablesWithIntrinsicBounds(ContextCompat.getDrawable(getContext(),R.drawable.selector_category_load), null, null, null); } else { - tvTitle.setCompoundDrawablesWithIntrinsicBounds(getContext().getResources().getDrawable(R.drawable.selector_category_unload), null, null, null); + tvTitle.setCompoundDrawablesWithIntrinsicBounds(ContextCompat.getDrawable(getContext(),R.drawable.selector_category_unload), null, null, null); } tvTitle.setText(data.getTitle()); } diff --git a/app/src/main/java/xyz/fycz/myreader/ui/presenter/CatalogPresenter.java b/app/src/main/java/xyz/fycz/myreader/ui/presenter/CatalogPresenter.java index bb039cb..9a08212 100644 --- a/app/src/main/java/xyz/fycz/myreader/ui/presenter/CatalogPresenter.java +++ b/app/src/main/java/xyz/fycz/myreader/ui/presenter/CatalogPresenter.java @@ -146,6 +146,7 @@ public class CatalogPresenter implements BasePresenter { * @param query */ public void startSearch(String query) { + if (mChapters.size() == 0) return; mChapterTitleAdapter.getFilter().filter(query); mCatalogFragment.getLvChapterList().setSelection(0); } diff --git a/app/src/main/java/xyz/fycz/myreader/util/utils/FileUtils.java b/app/src/main/java/xyz/fycz/myreader/util/utils/FileUtils.java index b20995e..d1723c0 100644 --- a/app/src/main/java/xyz/fycz/myreader/util/utils/FileUtils.java +++ b/app/src/main/java/xyz/fycz/myreader/util/utils/FileUtils.java @@ -1,6 +1,5 @@ package xyz.fycz.myreader.util.utils; -import android.app.Application; import android.content.ContentUris; import android.content.Context; import android.database.Cursor; @@ -11,7 +10,25 @@ import android.os.StatFs; import android.provider.DocumentsContract; import android.provider.MediaStore; import android.util.Log; -import info.monitorenter.cpdetector.io.*; + +import org.mozilla.universalchardet.UniversalDetector; + +import java.io.BufferedOutputStream; +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileFilter; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.List; + import io.reactivex.Single; import io.reactivex.SingleEmitter; import io.reactivex.SingleOnSubscribe; @@ -20,11 +37,6 @@ import xyz.fycz.myreader.common.APPCONST; import xyz.fycz.myreader.util.IOUtils; import xyz.fycz.myreader.util.StringHelper; -import java.io.*; -import java.text.DecimalFormat; -import java.util.ArrayList; -import java.util.List; - public class FileUtils { //采用自己的格式去设置文件,防止文件被系统文件查询到 @@ -215,32 +227,42 @@ public class FileUtils { } /** - * 获得文件编码 - * @param filePath + * 获取文件编码 + * @param file * @return - * @throws Exception */ - public static String getFileEncode(String filePath) { - String charsetName = null; + public static String getFileCharset(File file){ + FileInputStream fis = null; + FileInputStream temFis = null; + FileOutputStream fos = null; + File temFile = null; try { - File file = new File(filePath); - CodepageDetectorProxy detector = CodepageDetectorProxy.getInstance(); - detector.add(new ParsingDetector(false)); - detector.add(JChardetFacade.getInstance()); - detector.add(ASCIIDetector.getInstance()); - detector.add(UnicodeDetector.getInstance()); - java.nio.charset.Charset charset = null; - charset = detector.detectCodepage(file.toURI().toURL()); - if (charset != null) { - charsetName = charset.name(); + temFile = getFile(APPCONST.TEM_FILE_DIR + "tem.fy"); + fis = new FileInputStream(file); + fos = new FileOutputStream(temFile); + byte[] bytes = new byte[1024 * 10]; + int len; + if ((len = fis.read(bytes)) != -1){ + fos.write(bytes, 0, len); + } + fos.flush(); + temFis = new FileInputStream(temFile); + String encoding = UniversalDetector.detectCharset(temFis); + if (encoding != null) { + Log.d("encoding", encoding); + return encoding; } else { - charsetName = "UTF-8"; + return "UTF-8"; + } + } catch (IOException e) { + e.printStackTrace(); + return "UTF-8"; + }finally { + IOUtils.close(fis, temFis, fos); + if (temFile != null) { + temFile.delete(); } - } catch (Exception ex) { - ex.printStackTrace(); - return null; } - return charsetName; } public static byte[] getBytes(File file) { diff --git a/app/src/main/java/xyz/fycz/myreader/webapi/crawler/ReadCrawlerUtil.java b/app/src/main/java/xyz/fycz/myreader/webapi/crawler/ReadCrawlerUtil.java index d3b1459..400d305 100644 --- a/app/src/main/java/xyz/fycz/myreader/webapi/crawler/ReadCrawlerUtil.java +++ b/app/src/main/java/xyz/fycz/myreader/webapi/crawler/ReadCrawlerUtil.java @@ -89,7 +89,11 @@ public class ReadCrawlerUtil { public synchronized static void addReadCrawler(BookSource... bookSources){ SharedPreUtils spu = SharedPreUtils.getInstance(); - String searchSource = spu.getString(MyApplication.getmContext().getString(R.string.searchSource), null); + String searchSource = spu.getString(MyApplication.getmContext().getString(R.string.searchSource)); + if ("".equals(searchSource)){ + resetReadCrawlers(); + return; + } StringBuilder sb = new StringBuilder(searchSource); for (BookSource bookSource : bookSources){ sb.append(","); diff --git a/app/src/main/java/xyz/fycz/myreader/widget/page/LocalPageLoader.java b/app/src/main/java/xyz/fycz/myreader/widget/page/LocalPageLoader.java index a0f4cc7..f557861 100644 --- a/app/src/main/java/xyz/fycz/myreader/widget/page/LocalPageLoader.java +++ b/app/src/main/java/xyz/fycz/myreader/widget/page/LocalPageLoader.java @@ -80,11 +80,11 @@ public class LocalPageLoader extends PageLoader { * 1. 序章的添加 * 2. 章节存在的书本的虚拟分章效果 */ - public List loadChapters() throws IOException { + /*public List loadChapters() throws IOException { mBookFile = new File(mCollBook.getChapterUrl()); //获取文件编码 mCharset = FileUtils.getFileEncode(mBookFile.getAbsolutePath()); - List chapters = new ArrayList<>(); + List chapters = new ArrayList<>(); RandomAccessFile bookStream = null; boolean hasChapter = false; //获取文件流 @@ -127,38 +127,38 @@ public class LocalPageLoader extends PageLoader { //如果当前对整个文件的偏移位置为0的话,那么就是序章 if (curOffset == 0) { //创建序章 - BookChapterBean preChapter = new BookChapterBean(); - preChapter.title = "序章"; - preChapter.start = 0; - preChapter.end = chapterContent.getBytes(mCharset).length; //获取String的byte值,作为最终值 + Chapter preChapter = new Chapter(); + preChapter.setTitle("序章"); + preChapter.setStart(0); + preChapter.setEnd(chapterContent.getBytes(mCharset).length); //获取String的byte值,作为最终值 //如果序章大小大于30才添加进去 - if (preChapter.end - preChapter.start > 30) { + if (preChapter.getEnd() - preChapter.getStart() > 30) { chapters.add(preChapter); } //创建当前章节 - BookChapterBean curChapter = new BookChapterBean(); - curChapter.title = matcher.group(); - curChapter.start = preChapter.end; + Chapter curChapter = new Chapter(); + curChapter.setTitle(matcher.group()); + curChapter.setStart(preChapter.getEnd()); chapters.add(curChapter); } //否则就block分割之后,上一个章节的剩余内容 else { //获取上一章节 - BookChapterBean lastChapter = chapters.get(chapters.size() - 1); + Chapter lastChapter = chapters.get(chapters.size() - 1); //将当前段落添加上一章去 - lastChapter.end += chapterContent.getBytes(mCharset).length; + lastChapter.setEnd(lastChapter.getEnd() + chapterContent.getBytes(mCharset).length); //如果章节内容太小,则移除 - if (lastChapter.end - lastChapter.start < 30) { + if (lastChapter.getEnd() - lastChapter.getStart() < 30) { chapters.remove(lastChapter); } //创建当前章节 - BookChapterBean curChapter = new BookChapterBean(); - curChapter.title = matcher.group(); - curChapter.start = lastChapter.end; + Chapter curChapter = new Chapter(); + curChapter.setTitle(matcher.group()); + curChapter.setStart(lastChapter.getEnd()); chapters.add(curChapter); } } else { @@ -169,25 +169,25 @@ public class LocalPageLoader extends PageLoader { seekPos += chapterContent.length(); //获取上一章节 - BookChapterBean lastChapter = chapters.get(chapters.size() - 1); - lastChapter.end = lastChapter.start + chapterContent.getBytes(mCharset).length; + Chapter lastChapter = chapters.get(chapters.size() - 1); + lastChapter.setEnd(lastChapter.getStart() + chapterContent.getBytes(mCharset).length); //如果章节内容太小,则移除 - if (lastChapter.end - lastChapter.start < 30) { + if (lastChapter.getEnd() - lastChapter.getStart() < 30) { chapters.remove(lastChapter); } //创建当前章节 - BookChapterBean curChapter = new BookChapterBean(); - curChapter.title = matcher.group(); - curChapter.start = lastChapter.end; + Chapter curChapter = new Chapter(); + curChapter.setTitle(matcher.group()); + curChapter.setStart(lastChapter.getEnd()); chapters.add(curChapter); } //如果章节不存在则创建章节 else { - BookChapterBean curChapter = new BookChapterBean(); - curChapter.title = matcher.group(); - curChapter.start = 0; + Chapter curChapter = new Chapter(); + curChapter.setTitle(matcher.group()); + curChapter.setStart(0); chapters.add(curChapter); } } @@ -215,20 +215,20 @@ public class LocalPageLoader extends PageLoader { break; } } - BookChapterBean chapter = new BookChapterBean(); - chapter.title = "第" + blockPos + "章" + "(" + chapterPos + ")"; - chapter.start = curOffset + chapterOffset + 1; - chapter.end = curOffset + end; + Chapter chapter = new Chapter(); + chapter.setTitle("第" + blockPos + "章" + "(" + chapterPos + ")"); + chapter.setStart(curOffset + chapterOffset + 1); + chapter.setEnd(curOffset + end); chapters.add(chapter); //减去已经被分配的长度 strLength = strLength - (end - chapterOffset); //设置偏移的位置 chapterOffset = end; } else { - BookChapterBean chapter = new BookChapterBean(); - chapter.title = "第" + blockPos + "章" + "(" + chapterPos + ")"; - chapter.start = curOffset + chapterOffset + 1; - chapter.end = curOffset + length; + Chapter chapter = new Chapter(); + chapter.setTitle("第" + blockPos + "章" + "(" + chapterPos + ")"); + chapter.setStart(curOffset + chapterOffset + 1); + chapter.setEnd(curOffset + length); chapters.add(chapter); strLength = 0; } @@ -240,8 +240,8 @@ public class LocalPageLoader extends PageLoader { if (hasChapter) { //设置上一章的结尾 - BookChapterBean lastChapter = chapters.get(chapters.size() - 1); - lastChapter.end = curOffset; + Chapter lastChapter = chapters.get(chapters.size() - 1); + lastChapter.setEnd(curOffset); } //当添加的block太多的时候,执行GC @@ -255,39 +255,204 @@ public class LocalPageLoader extends PageLoader { System.gc(); System.runFinalization(); return chapters; + }*/ + + /** + * 未完成的部分: + * 1. 序章的添加 + * 2. 章节存在的书本的虚拟分章效果 + */ + private List loadChapters() throws IOException { + mBookFile = new File(mCollBook.getChapterUrl()); + //获取文件编码 + mCharset = FileUtils.getFileCharset(mBookFile); + + Log.d("mCharset", mCharset); + + List mChapterList = new ArrayList<>(); + //获取文件流 + RandomAccessFile bookStream = new RandomAccessFile(mBookFile, "r"); + //寻找匹配文章标题的正则表达式,判断是否存在章节名 + boolean hasChapter = checkChapterType(bookStream); + //加载章节 + byte[] buffer = new byte[BUFFER_SIZE]; + //获取到的块起始点,在文件中的位置 + long curOffset = 0; + //block的个数 + int blockPos = 0; + //读取的长度 + int length; + int allLength = 0; + + //获取文件中的数据到buffer,直到没有数据为止 + while ((length = bookStream.read(buffer, 0, buffer.length)) > 0) { + ++blockPos; + //如果存在Chapter + if (hasChapter) { + //将数据转换成String + String blockContent = new String(buffer, 0, length, mCharset); + int lastN = blockContent.lastIndexOf("\n"); + if (lastN != 0) { + blockContent = blockContent.substring(0, lastN); + length = blockContent.getBytes(mCharset).length; + allLength = allLength + length; + bookStream.seek(allLength); + } + //当前Block下使过的String的指针 + int seekPos = 0; + //进行正则匹配 + Matcher matcher = mChapterPattern.matcher(blockContent); + //如果存在相应章节 + while (matcher.find()) { + //获取匹配到的字符在字符串中的起始位置 + int chapterStart = matcher.start(); + + //如果 seekPos == 0 && nextChapterPos != 0 表示当前block处前面有一段内容 + //第一种情况一定是序章 第二种情况可能是上一个章节的内容 + if (seekPos == 0 && chapterStart != 0) { + //获取当前章节的内容 + String chapterContent = blockContent.substring(seekPos, chapterStart); + //设置指针偏移 + seekPos += chapterContent.length(); + + if (mChapterList.size() == 0) { //如果当前没有章节,那么就是序章 + //加入简介 + mCollBook.setDesc(chapterContent); + //创建当前章节 + Chapter curChapter = new Chapter(); + curChapter.setTitle(matcher.group()); + curChapter.setStart(chapterContent.getBytes(mCharset).length); + mChapterList.add(curChapter); + } else { //否则就block分割之后,上一个章节的剩余内容 + //获取上一章节 + Chapter lastChapter = mChapterList.get(mChapterList.size() - 1); + //将当前段落添加上一章去 + lastChapter.setEnd(lastChapter.getEnd() + chapterContent.getBytes(mCharset).length); + + //创建当前章节 + Chapter curChapter = new Chapter(); + curChapter.setTitle(matcher.group()); + curChapter.setStart(lastChapter.getEnd()); + mChapterList.add(curChapter); + } + } else { + //是否存在章节 + if (mChapterList.size() != 0) { + //获取章节内容 + String chapterContent = blockContent.substring(seekPos, matcher.start()); + seekPos += chapterContent.length(); + + //获取上一章节 + Chapter lastChapter = mChapterList.get(mChapterList.size() - 1); + lastChapter.setEnd(lastChapter.getStart() + chapterContent.getBytes(mCharset).length); + + //创建当前章节 + Chapter curChapter = new Chapter(); + curChapter.setTitle(matcher.group()); + curChapter.setStart(lastChapter.getEnd()); + mChapterList.add(curChapter); + } else { //如果章节不存在则创建章节 + Chapter curChapter = new Chapter(); + curChapter.setTitle(matcher.group()); + curChapter.setStart(0L); + curChapter.setEnd(0L); + mChapterList.add(curChapter); + } + } + } + } else { //进行本地虚拟分章 + //章节在buffer的偏移量 + int chapterOffset = 0; + //当前剩余可分配的长度 + int strLength = length; + //分章的位置 + int chapterPos = 0; + + while (strLength > 0) { + ++chapterPos; + //是否长度超过一章 + if (strLength > MAX_LENGTH_WITH_NO_CHAPTER) { + //在buffer中一章的终止点 + int end = length; + //寻找换行符作为终止点 + for (int i = chapterOffset + MAX_LENGTH_WITH_NO_CHAPTER; i < length; ++i) { + if (buffer[i] == Charset.BLANK) { + end = i; + break; + } + } + Chapter chapter = new Chapter(); + chapter.setTitle("第" + blockPos + "章" + "(" + chapterPos + ")"); + chapter.setStart(curOffset + chapterOffset + 1); + if (chapter.getStart() == 1) chapter.setStart(0); + chapter.setEnd(curOffset + end); + mChapterList.add(chapter); + //减去已经被分配的长度 + strLength = strLength - (end - chapterOffset); + //设置偏移的位置 + chapterOffset = end; + } else { + Chapter chapter = new Chapter(); + chapter.setTitle("第" + blockPos + "章" + "(" + chapterPos + ")"); + chapter.setStart(curOffset + chapterOffset + 1); + if (chapter.getStart() == 1) chapter.setStart(0); + chapter.setEnd(curOffset + length); + mChapterList.add(chapter); + strLength = 0; + } + } + } + + //block的偏移点 + curOffset += length; + + if (hasChapter) { + if (mChapterList.size() != 0) { + //设置上一章的结尾 + Chapter lastChapter = mChapterList.get(mChapterList.size() - 1); + lastChapter.setEnd(curOffset); + } + } + + //当添加的block太多的时候,执行GC + if (blockPos % 15 == 0) { + System.gc(); + System.runFinalization(); + } + } + int i = 0; + for (Chapter chapter : mChapterList) { + chapter.setTitle(chapter.getTitle().trim()); + chapter.setBookId(mCollBook.getId()); + chapter.setId(StringHelper.getStringRandom(25)); + chapter.setNumber(i++); + } + + IOUtils.close(bookStream); + + System.gc(); + System.runFinalization(); + + return mChapterList; } public void loadChapters(final ResultCallback resultCallback) { // 通过RxJava异步处理分章事件 - Single.create((SingleOnSubscribe>) e -> { + Single.create((SingleOnSubscribe>) e -> { e.onSuccess(loadChapters()); - }).compose(RxUtils::toSimpleSingle).subscribe(new SingleObserver>() { + }).compose(RxUtils::toSimpleSingle).subscribe(new SingleObserver>() { @Override public void onSubscribe(Disposable d) { mChapterDisp = d; } @Override - public void onSuccess(List chapters) { + public void onSuccess(List chapters) { mChapterDisp = null; isChapterListPrepare = true; - List mChapters = new ArrayList<>(); - int i = 0; - for (BookChapterBean bookChapterBean : chapters) { - Chapter chapter = new Chapter(); - chapter.setBookId(mCollBook.getId()); - chapter.setTitle(bookChapterBean.getTitle().replace("\n", "").replaceAll("^\\s+|\\s+$", "")); - chapter.setId(StringHelper.getStringRandom(25)); - String content = getChapterContent(bookChapterBean); - if (StringHelper.isEmpty(content)) { - continue; - } - chapter.setNumber(i++); - mChapterService.saveOrUpdateChapter(chapter, content); - mChapters.add(chapter); - } + mCollBook.setInfoUrl(mCharset); if (resultCallback != null) { - resultCallback.onFinish(mChapters, 1); + resultCallback.onFinish(chapters, 1); } } @@ -307,15 +472,15 @@ public class LocalPageLoader extends PageLoader { * @param chapter * @return */ - private String getChapterContent(BookChapterBean chapter) { + private byte[] getContent(Chapter chapter) { RandomAccessFile bookStream = null; try { bookStream = new RandomAccessFile(mBookFile, "r"); - bookStream.seek(chapter.start); - int extent = (int) (chapter.end - chapter.start); + bookStream.seek(chapter.getStart()); + int extent = (int) (chapter.getEnd() - chapter.getStart()); byte[] content = new byte[extent]; bookStream.read(content, 0, extent); - return new String(content, mCharset); + return content; } catch (IOException e) { e.printStackTrace(); } finally { @@ -367,6 +532,8 @@ public class LocalPageLoader extends PageLoader { // 对于文件是否存在,或者为空的判断,不作处理。 ==> 在文件打开前处理过了。 mBookFile = new File(mCollBook.getChapterUrl()); + mCharset = mCollBook.getInfoUrl(); + // 判断文件是否已经加载过,并具有缓存 if (mCollBook.getChapterTotalNum() != 0) { @@ -387,16 +554,25 @@ public class LocalPageLoader extends PageLoader { @Override protected BufferedReader getChapterReader(Chapter chapter) throws Exception { + if (chapter.getEnd() > 0) { + Log.d("getChapterReader", chapter.getTitle()); + //从文件中获取数据 + byte[] content = getContent(chapter); + ByteArrayInputStream bais = new ByteArrayInputStream(content); + BufferedReader br = new BufferedReader(new InputStreamReader(bais, mCharset)); + return br; + } File file = new File(APPCONST.BOOK_CACHE_PATH + mCollBook.getId() + File.separator + chapter.getTitle() + FileUtils.SUFFIX_FY); if (!file.exists()) return null; + Log.d("getChapterReader", file.getPath()); return new BufferedReader(new FileReader(file)); } @Override public boolean hasChapterData(Chapter chapter) { - return ChapterService.isChapterCached(mCollBook.getId(), chapter.getTitle()); + return chapter.getEnd() > 0 || ChapterService.isChapterCached(mCollBook.getId(), chapter.getTitle()); } diff --git a/app/src/main/java/xyz/fycz/myreader/widget/page/PageLoader.java b/app/src/main/java/xyz/fycz/myreader/widget/page/PageLoader.java index 6b700c7..a9097f2 100644 --- a/app/src/main/java/xyz/fycz/myreader/widget/page/PageLoader.java +++ b/app/src/main/java/xyz/fycz/myreader/widget/page/PageLoader.java @@ -1502,10 +1502,15 @@ public abstract class PageLoader { float rHeight = mVisibleHeight; int titleLinesCount = 0; boolean showTitle = true; // 是否展示标题 + boolean firstLine = true; String paragraph = chapter.getTitle();//默认展示标题 paragraph = paragraph.trim() + "\n"; try { while (showTitle || (paragraph = br.readLine()) != null) { + if (firstLine && !showTitle){ + paragraph = paragraph.replace(chapter.getTitle(), ""); + firstLine = false; + } if (mSettingManager.getLanguage() == Language.traditional) { paragraph = ChineseUtils.toTraditional(paragraph); } else if (mSettingManager.getLanguage() == Language.simplified) { diff --git a/app/version_code.properties b/app/version_code.properties index 55d323f..5b94de6 100644 --- a/app/version_code.properties +++ b/app/version_code.properties @@ -1,2 +1,2 @@ -#Sun Dec 06 12:06:58 CST 2020 -VERSION_CODE=175 +#Sun Dec 06 19:19:42 CST 2020 +VERSION_CODE=176