在线下载章节内容

This commit is contained in:
mwang 2019-04-03 18:09:00 +08:00
parent 9ad85f7c2e
commit 355b7adf63
6 changed files with 143 additions and 39 deletions

View File

@ -11,11 +11,13 @@ import android.view.View;
import android.widget.Toast; import android.widget.Toast;
import com.novelbook.android.adapter.BookListAdapter; import com.novelbook.android.adapter.BookListAdapter;
import com.novelbook.android.db.Chapter;
import com.novelbook.android.db.Novel; import com.novelbook.android.db.Novel;
import com.novelbook.android.netsubscribe.MovieSubscribe; import com.novelbook.android.netsubscribe.MovieSubscribe;
import com.novelbook.android.netutils.HttpMethods; import com.novelbook.android.netutils.HttpMethods;
import com.novelbook.android.netutils.OnSuccessAndFaultListener; import com.novelbook.android.netutils.OnSuccessAndFaultListener;
import com.novelbook.android.netutils.OnSuccessAndFaultSub; import com.novelbook.android.netutils.OnSuccessAndFaultSub;
import com.novelbook.android.utils.BookUtil;
import com.novelbook.android.utils.NovelParseUtil; import com.novelbook.android.utils.NovelParseUtil;
import org.json.JSONException; import org.json.JSONException;
@ -24,6 +26,7 @@ import org.litepal.LitePal;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import butterknife.BindView; import butterknife.BindView;
@ -41,6 +44,7 @@ public class BookActivity extends Activity_base {
// private BookListAdapter mAdapter; // private BookListAdapter mAdapter;
private List<Novel> mData;; private List<Novel> mData;;
private List<Chapter> chapters = new ArrayList<>();
@BindView(R.id.toolbar) @BindView(R.id.toolbar)
Toolbar toolbar; Toolbar toolbar;
@BindView(R.id.rvBooklist) @BindView(R.id.rvBooklist)
@ -143,7 +147,7 @@ public class BookActivity extends Activity_base {
}).setCancelable(true).show(); }).setCancelable(true).show();
return; return;
} }
ReadActivity.openBook(book ,this); ReadActivity.openBook(book ,chapters,this);
} }
@ -201,12 +205,25 @@ void onResponseProcess( String content ,String url){
} }
} }
*/ */
siteJson.put("chapterUrlRegexOnMulu", "<dd> <a[^>]*href=\"(/book/[\\d]+/[\\d]+\\.html)\">([^<]+)</a></dd>"); siteJson.put("chapterUrlRegexOnMulu", "<dd> <a[^>]*href=\"(/book/[\\d]+/[\\d]+\\.html)\">([^<]+)</a></dd>");
String[] chapters2 = NovelParseUtil.getChapters(url, content, siteJson); String[] chapters2 = NovelParseUtil.getChapters(url, content, siteJson);
if (chapters2 != null) { if (chapters2 != null) {
for (int i = 0; i < chapters2.length; i += 2) { for (int i = 0; i < chapters2.length; i += 2) {
Log.d(TAG, String.format("%s-->%s", chapters2[i], chapters2[i + 1])); Log.d(TAG, String.format("%s-->%s", chapters2[i], chapters2[i + 1]));
Chapter chapter = new Chapter();
chapter.setChapterName(chapters2[i + 1]);
chapter.setChapterPath(chapters2[i ]);
chapters.add(chapter);
} }
siteJson.put("chapterContentRegex", "<div id=\"content\">([\\s\\S]+?)</div>"); siteJson.put("chapterContentRegex", "<div id=\"content\">([\\s\\S]+?)</div>");
siteJson.put("chapterContentDumpRegex", "<script>chaptererror();</script>"); siteJson.put("chapterContentDumpRegex", "<script>chaptererror();</script>");
@ -217,7 +234,7 @@ void onResponseProcess( String content ,String url){
// .header("User-Agent", "OkHttp Example") // .header("User-Agent", "OkHttp Example")
.build(); .build();
Response response = HttpMethods.getOkClient().newCall(request).execute(); Response response = HttpMethods.getOkClient().newCall(request).execute();
// Log.d(TAG,String.format("%s-->%s\n%s" , chapters2[i], chapters2[i+1] , NovelParseUtil.getChapterContent(response.body().string(), siteJson))); // Log.d(TAG,String.format("%s-->%s\n%s" , chapters2[i], chapters2[i+1] , NovelParseUtil.getChapterContent(response.body().string(), siteJson)));
} }
} }

View File

@ -35,6 +35,7 @@ import com.baidu.tts.client.SpeechError;
import com.baidu.tts.client.SpeechSynthesizer; import com.baidu.tts.client.SpeechSynthesizer;
import com.baidu.tts.client.SpeechSynthesizerListener; import com.baidu.tts.client.SpeechSynthesizerListener;
import com.baidu.tts.client.TtsMode; import com.baidu.tts.client.TtsMode;
import com.novelbook.android.db.Chapter;
import com.novelbook.android.db.Novel; import com.novelbook.android.db.Novel;
import com.novelbook.android.db.BookMarks; import com.novelbook.android.db.BookMarks;
import com.novelbook.android.dialog.PageModeDialog; import com.novelbook.android.dialog.PageModeDialog;
@ -48,6 +49,7 @@ import org.litepal.LitePal;
import java.io.IOException; import java.io.IOException;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@ -58,6 +60,7 @@ import butterknife.OnClick;
public class ReadActivity extends Activity_base implements SpeechSynthesizerListener { public class ReadActivity extends Activity_base implements SpeechSynthesizerListener {
private static final String TAG = "ReadActivity"; private static final String TAG = "ReadActivity";
private final static String EXTRA_BOOK = "book"; private final static String EXTRA_BOOK = "book";
private final static String EXTRA_CHAPTERS = "chapters";
private final static int MESSAGE_CHANGEPROGRESS = 1; private final static int MESSAGE_CHANGEPROGRESS = 1;
@BindView(R.id.bookpage) @BindView(R.id.bookpage)
@ -103,6 +106,7 @@ public class ReadActivity extends Activity_base implements SpeechSynthesizerLis
private Config config; private Config config;
private WindowManager.LayoutParams lp; private WindowManager.LayoutParams lp;
private Novel book; private Novel book;
private List<Chapter> mChapters;
private PageFactory pageFactory; private PageFactory pageFactory;
private int screenWidth, screenHeight; private int screenWidth, screenHeight;
// popwindow是否显示 // popwindow是否显示
@ -194,12 +198,12 @@ public class ReadActivity extends Activity_base implements SpeechSynthesizerLis
//获取intent中的携带的信息 //获取intent中的携带的信息
Intent intent = getIntent(); Intent intent = getIntent();
book = (Novel) intent.getSerializableExtra(EXTRA_BOOK); book = (Novel) intent.getSerializableExtra(EXTRA_BOOK);
mChapters = (ArrayList<Chapter>) intent.getSerializableExtra(EXTRA_CHAPTERS);
bookpage.setPageMode(config.getPageMode()); bookpage.setPageMode(config.getPageMode());
pageFactory.setPageWidget(bookpage); pageFactory.setPageWidget(bookpage);
try { try {
pageFactory.openBook(book); pageFactory.openBook(book,mChapters);
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
Toast.makeText(this, "打开电子书失败", Toast.LENGTH_SHORT).show(); Toast.makeText(this, "打开电子书失败", Toast.LENGTH_SHORT).show();
@ -523,13 +527,15 @@ public class ReadActivity extends Activity_base implements SpeechSynthesizerLis
} }
public static boolean openBook(final Novel book, Activity context) { public static boolean openBook(final Novel book,List<Chapter> chapters ,Activity context) {
if (book == null){ if (book == null){
throw new NullPointerException("Novel can not be null"); throw new NullPointerException("Novel can not be null");
} }
Intent intent = new Intent(context, ReadActivity.class); Intent intent = new Intent(context, ReadActivity.class);
intent.putExtra(EXTRA_BOOK, book); intent.putExtra(EXTRA_BOOK, book);
// intent.putExtra(EXTRA_CHAPTERS, chapters);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
context.overridePendingTransition(R.anim.in_from_right, R.anim.out_to_left); context.overridePendingTransition(R.anim.in_from_right, R.anim.out_to_left);
context.startActivity(intent); context.startActivity(intent);

View File

@ -14,6 +14,7 @@ public class Chapter extends LitePalSupport {
private int length; private int length;
private String chapterPath; private String chapterPath;
public int getId() { public int getId() {
return id; return id;
} }
@ -79,7 +80,5 @@ public class Chapter extends LitePalSupport {
} }
} }

View File

@ -23,6 +23,10 @@ public class Novel extends LitePalSupport implements Serializable{
private String lastestChapterName; private String lastestChapterName;
private String description; private String description;
private long lastUpateTime; private long lastUpateTime;
private boolean isOnShelf; //是否入书架
private boolean isFinished; //是否完本
public int getId() { public int getId() {
return id; return id;
@ -152,8 +156,19 @@ public class Novel extends LitePalSupport implements Serializable{
this.lastUpateTime = lastUpateTime; this.lastUpateTime = lastUpateTime;
} }
public boolean isOnShelf() {
return isOnShelf;
}
public void setOnShelf(boolean onShelf) {
isOnShelf = onShelf;
}
public boolean isFinished() {
return isFinished;
}
public void setFinished(boolean finished) {
isFinished = finished;
}
} }

View File

@ -10,8 +10,11 @@ import android.util.Log;
import com.novelbook.android.bean.Cache; import com.novelbook.android.bean.Cache;
import com.novelbook.android.db.Chapter; import com.novelbook.android.db.Chapter;
import com.novelbook.android.db.Novel; import com.novelbook.android.db.Novel;
import com.novelbook.android.netutils.HttpMethods;
import org.json.JSONException;
import org.json.JSONObject;
import org.litepal.LitePal; import org.litepal.LitePal;
import java.io.File; import java.io.File;
@ -26,6 +29,9 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import okhttp3.Request;
import okhttp3.Response;
public class BookUtil { public class BookUtil {
public static final String TAG ="BookUtil"; public static final String TAG ="BookUtil";
@ -40,7 +46,16 @@ public class BookUtil {
public static final String lineBreakChar ="\n"; public static final String lineBreakChar ="\n";
protected final ArrayList<Cache> myArray = new ArrayList<>(); protected final ArrayList<Cache> myArray = new ArrayList<>();
//目录 //目录
private List<Chapter> directoryList = new ArrayList<>(); private List<Chapter> mChapters = new ArrayList<>();
public List<Chapter> getChapters() {
return mChapters;
}
public void setChapters(List<Chapter> chapters) {
this.mChapters = chapters;
}
private String m_strCharsetName; private String m_strCharsetName;
private String bookName; private String bookName;
@ -52,7 +67,17 @@ public class BookUtil {
private long bookLen; private long bookLen;
private long position; private long position;
private Novel book; private Novel mNovel;
private Chapter mChapter;
public Chapter getChapter() {
return mChapter;
}
public void setChapter(Chapter chapter) {
this.mChapter = chapter;
}
public void setChapterNo(int chapterNo) { public void setChapterNo(int chapterNo) {
this.chapterNo = chapterNo; this.chapterNo = chapterNo;
@ -83,28 +108,39 @@ public class BookUtil {
} }
} }
public synchronized void openBook(Novel book) throws IOException { public synchronized void openBook(Novel novel) throws IOException {
this.book = book; this.mNovel = novel;
//如果当前缓存不是要打开的书本就缓存书本同时删除缓存 //如果当前缓存不是要打开的书本就缓存书本同时删除缓存
//TODO 构建新的缓存策略几个选项1每本书一个缓存 2控制缓存总大小超过限制删除旧缓存 3网络小说的缓存 //TODO 构建新的缓存策略几个选项1每本书一个缓存 2控制缓存总大小超过限制删除旧缓存 3网络小说的缓存
directoryList = LitePal.where("bookId=?",book.getId()+"").find(Chapter.class); boolean isLocalImport = TextUtils.isEmpty( novel.getNovelId());
boolean isOnShelf = isLocalImport || novel.isOnShelf();
boolean isLoadChaptsFromRemote = !isLocalImport ;// && !novel.isFinished() ; //是否从目标网站下载目录
for(Chapter c :directoryList){
Log.d(TAG, String.format("bookchapter :%s,fileName :%s, chapter Size %s",c.getChapterName(),c.getChapterPath(),c.getLength()));
}
chaptCache = new HashMap<Integer,Cache>();
if(directoryList.isEmpty()) { //1. 首次打开 本地导入的书 2. 首次打开 未缓存的在线小说
if (bookPath == null || !bookPath.equals(book.getNovelPath())) { if(isLocalImport) {
cleanCacheFile();
this.bookPath = book.getNovelPath(); mChapters = LitePal.where("novelId=?", mNovel.getId() + "").find(Chapter.class);
bookName = FileUtils.getFileName(bookPath);
cacheBook(); for (Chapter c : mChapters) {
Log.d(TAG, String.format("bookchapter :%s,fileName :%s, chapter Size %s", c.getChapterName(), c.getChapterPath(), c.getLength()));
}
chaptCache = new HashMap<Integer, Cache>();
if (mChapters.isEmpty()) { //1. 首次打开 本地导入的书 2. 首次打开 未缓存的在线小说
if (bookPath == null || !bookPath.equals(mNovel.getNovelPath())) {
cleanCacheFile();
this.bookPath = mNovel.getNovelPath();
bookName = FileUtils.getFileName(bookPath);
cacheBook();
}
} }
} }
} }
private void cleanCacheFile(){ private void cleanCacheFile(){
@ -236,23 +272,23 @@ public class BookUtil {
//缓存书本 //缓存书本
private void cacheBook() throws IOException { private void cacheBook() throws IOException {
if (TextUtils.isEmpty(book.getCharset())) { if (TextUtils.isEmpty(mNovel.getCharset())) {
m_strCharsetName = FileUtils.getCharset(bookPath); m_strCharsetName = FileUtils.getCharset(bookPath);
if (m_strCharsetName == null) { if (m_strCharsetName == null) {
m_strCharsetName = "utf-8"; m_strCharsetName = "utf-8";
} }
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
values.put("charset",m_strCharsetName); values.put("charset",m_strCharsetName);
LitePal.update(Novel.class,values,book.getId()); LitePal.update(Novel.class,values,mNovel.getId());
}else{ }else{
m_strCharsetName = book.getCharset(); m_strCharsetName = mNovel.getCharset();
} }
File file = new File(bookPath); File file = new File(bookPath);
InputStreamReader reader = new InputStreamReader(new FileInputStream(file),m_strCharsetName); InputStreamReader reader = new InputStreamReader(new FileInputStream(file),m_strCharsetName);
int index = 0; int index = 0;
bookLen = 0; bookLen = 0;
directoryList.clear(); mChapters.clear();
myArray.clear(); myArray.clear();
while (true){ while (true){
char[] buf = new char[cachedSize]; char[] buf = new char[cachedSize];
@ -348,11 +384,11 @@ public class BookUtil {
bookChapter.setLength((int)(size - start)); bookChapter.setLength((int)(size - start));
bookChapter.setChapterPath(fileChapterName(chaptId) ); bookChapter.setChapterPath(fileChapterName(chaptId) );
bookChapter.update(bookChapter.getId()); bookChapter.update(bookChapter.getId());
directoryList.add(bookChapter); mChapters.add(bookChapter);
} }
bookChapter = new Chapter(); bookChapter = new Chapter();
bookChapter.setNovelId(book.getId()); bookChapter.setNovelId(mNovel.getId());
bookChapter.setNovelChapterStartPos(start); bookChapter.setNovelChapterStartPos(start);
bookChapter.setChapterName(str.replaceAll("###","")); bookChapter.setChapterName(str.replaceAll("###",""));
bookChapter.setNovelPath(bookPath); bookChapter.setNovelPath(bookPath);
@ -376,7 +412,7 @@ public class BookUtil {
if(writer==null) { if(writer==null) {
bookChapter = new Chapter(); bookChapter = new Chapter();
bookChapter.setNovelId(book.getId()); bookChapter.setNovelId(mNovel.getId());
bookChapter.setNovelChapterStartPos(start); bookChapter.setNovelChapterStartPos(start);
bookChapter.setChapterName(str.replaceAll("###","")); bookChapter.setChapterName(str.replaceAll("###",""));
bookChapter.setNovelPath(bookPath); bookChapter.setNovelPath(bookPath);
@ -397,7 +433,7 @@ public class BookUtil {
/* /*
Chapter bookChapter = new Chapter(); Chapter bookChapter = new Chapter();
bookChapter.setBookId(book.getId()); bookChapter.setBookId(mNovel.getId());
bookChapter.setBookChapterStartPos(start); bookChapter.setBookChapterStartPos(start);
bookChapter.setChapterName(title.replaceAll("###","")); bookChapter.setChapterName(title.replaceAll("###",""));
@ -406,7 +442,7 @@ public class BookUtil {
bookChapter.save(); bookChapter.save();
int id= bookChapter.getId(); int id= bookChapter.getId();
Log.d(TAG,str + " chaptId is " + id); Log.d(TAG,str + " chaptId is " + id);
directoryList.add(bookChapter); mChapters.add(bookChapter);
*/ */
} }
} }
@ -417,7 +453,7 @@ public class BookUtil {
bookChapter.setLength((int)(size - start)); bookChapter.setLength((int)(size - start));
bookChapter.setChapterPath(fileChapterName(chaptId) ); bookChapter.setChapterPath(fileChapterName(chaptId) );
bookChapter.update(bookChapter.getId()); bookChapter.update(bookChapter.getId());
directoryList.add(bookChapter); mChapters.add(bookChapter);
} }
}catch (Exception e){ }catch (Exception e){
e.printStackTrace(); e.printStackTrace();
@ -429,7 +465,7 @@ public class BookUtil {
} }
public List<Chapter> getDirectoryList(){ public List<Chapter> getDirectoryList(){
return directoryList; return mChapters;
} }
public long getBookLen(){ public long getBookLen(){
@ -445,7 +481,7 @@ public class BookUtil {
} }
String getChapterPath(){ String getChapterPath(){
return chapterPath +book.getId()+"/"; return chapterPath +mNovel.getId()+"/";
} }
//获取书本缓存 //获取书本缓存
@ -493,11 +529,37 @@ public class BookUtil {
try { try {
File file = new File(fileChapterName(index)); File file = new File(fileChapterName(index));
if(!file.exists()){ if(!file.exists()) {
/* 章节内容没有缓存在本地 /* 章节内容没有缓存在本地
1. 根据本地的章节网络地址信息读取章节内容到本地若读取失败则 1. 根据本地的章节网络地址信息读取章节内容到本地若读取失败则
2. 查询主服务器若有地址更新则更新本地信息并重复1若没有更新地址则地址无效返回章节内容正待手打 2. 查询主服务器若有地址更新则更新本地信息并重复1若没有更新地址则地址无效返回章节内容正待手打
*/ */
Chapter chapter = mChapters.get(index);
String url = chapter.getChapterUrl();
JSONObject siteJson = new JSONObject();
siteJson.put("chapterContentRegex", "<div id=\"content\">([\\s\\S]+?)</div>");
siteJson.put("chapterContentDumpRegex", "<script>chaptererror();</script>");
Request request = new Request.Builder()
.url(url)
// .header("User-Agent", "OkHttp Example")
.build();
Response response = HttpMethods.getOkClient().newCall(request).execute();
String content = NovelParseUtil.getChapterContent(response.body().string(), siteJson);
char[] buf = content.toCharArray();
try {
file.createNewFile();
final OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(fileChapterName(index)), "UTF-16LE"); // UTF-16LE utf-8 文件小
writer.write(buf);
writer.close();
} catch (IOException e) {
throw new RuntimeException("Error during writing " + fileName(index));
}
} }
@ -519,6 +581,8 @@ public class BookUtil {
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
throw new RuntimeException("Error during reading " + fileChapterName(index)); throw new RuntimeException("Error during reading " + fileChapterName(index));
} catch (JSONException e) {
e.printStackTrace();
} }
Cache cache = new Cache(); Cache cache = new Cache();
cache.setSize(block.length); cache.setSize(block.length);

View File

@ -137,6 +137,8 @@ public class PageFactory {
//书本名字 //书本名字
private String bookName = ""; private String bookName = "";
private Novel mBook; private Novel mBook;
//书的目录列表
private List<Chapter> mChapters;
//书本章节 //书本章节
private int currentChapter = 0; private int currentChapter = 0;
//当前电量 //当前电量
@ -498,7 +500,7 @@ public class PageFactory {
* 打开书本 * 打开书本
* @throws IOException * @throws IOException
*/ */
public void openBook(Novel book ) throws IOException { public void openBook(Novel book , List<Chapter> chapters ) throws IOException {
//清空数据 //清空数据
currentChapter = 0; currentChapter = 0;
// m_mbBufLen = 0; // m_mbBufLen = 0;
@ -506,8 +508,8 @@ public class PageFactory {
this.mBook = book ; this.mBook = book ;
bookPath = mBook.getNovelPath(); bookPath = mBook.getNovelPath();
bookName = FileUtils.getFileName(bookPath); bookName =mBook.getNovelName();// FileUtils.getFileName(bookPath);
this.mChapters = chapters;
mStatus = Status.OPENING; mStatus = Status.OPENING;
drawStatus(mBookPageWidget.getCurPage()); drawStatus(mBookPageWidget.getCurPage());
drawStatus(mBookPageWidget.getNextPage()); drawStatus(mBookPageWidget.getNextPage());
@ -533,6 +535,7 @@ public class PageFactory {
PageFactory.mStatus = PageFactory.Status.FINISH; PageFactory.mStatus = PageFactory.Status.FINISH;
// m_mbBufLen = mBookUtil.getBookLen(); // m_mbBufLen = mBookUtil.getBookLen();
mBookUtil.setChapterNo((int)chapter); mBookUtil.setChapterNo((int)chapter);
mBookUtil.setChapters(mChapters);
currentChaptPages = loadCurrentChapt((int)chapter); currentChaptPages = loadCurrentChapt((int)chapter);
currentPage = getPageForBegin(begin) ;// currentChaptPages.get(0); currentPage = getPageForBegin(begin) ;// currentChaptPages.get(0);
// currentPage = getPageForBegin(begin); // currentPage = getPageForBegin(begin);