1030 lines
36 KiB
Java
1030 lines
36 KiB
Java
package com.novelbook.android.utils;
|
||
|
||
import android.app.ProgressDialog;
|
||
import android.content.ContentValues;
|
||
import android.content.Context;
|
||
|
||
|
||
import android.os.Handler;
|
||
import android.os.Looper;
|
||
import android.os.Message;
|
||
import android.text.TextUtils;
|
||
import android.util.Log;
|
||
import android.widget.Toast;
|
||
|
||
import com.google.gson.Gson;
|
||
import com.novelbook.android.BookActivity;
|
||
import com.novelbook.android.MyApp;
|
||
import com.novelbook.android.bean.Cache;
|
||
import com.novelbook.android.bean.NovelSites;
|
||
import com.novelbook.android.bean.Site;
|
||
import com.novelbook.android.db.SiteRule;
|
||
import com.novelbook.android.db.Chapter;
|
||
import com.novelbook.android.db.Novel;
|
||
import com.novelbook.android.netsubscribe.BookSubscribe;
|
||
import com.novelbook.android.netutils.HttpMethods;
|
||
import com.novelbook.android.netutils.OnSuccessAndFaultListener;
|
||
import com.novelbook.android.netutils.OnSuccessAndFaultSub;
|
||
|
||
|
||
import org.json.JSONException;
|
||
import org.json.JSONObject;
|
||
import org.litepal.LitePal;
|
||
|
||
import java.io.Console;
|
||
import java.io.File;
|
||
import java.io.FileInputStream;
|
||
import java.io.FileOutputStream;
|
||
import java.io.IOException;
|
||
import java.io.InputStreamReader;
|
||
import java.io.OutputStreamWriter;
|
||
import java.lang.ref.WeakReference;
|
||
import java.util.ArrayList;
|
||
import java.util.Date;
|
||
import java.util.HashMap;
|
||
import java.util.List;
|
||
import java.util.Map;
|
||
|
||
import okhttp3.Call;
|
||
import okhttp3.Callback;
|
||
import okhttp3.Request;
|
||
import okhttp3.Response;
|
||
import okhttp3.ResponseBody;
|
||
|
||
|
||
public class BookUtil {
|
||
public static final String TAG ="BookUtil";
|
||
private static final String storagePath = FileUtils.getDiskCacheDir(MyApp.applicationContext);//Environment.getExternalStorageDirectory() + "/zhuike";
|
||
private static final String cachedPath = storagePath + "/cache/";
|
||
private static final String chapterPath = storagePath + "/chapter/";
|
||
private static final String charachterType = "utf-8";//"UTF-16LE";
|
||
private Context mContext;
|
||
private ProgressDialog progressDialog;
|
||
private MuluStatus mMuluStatus; //目录是否下载完成
|
||
private Gson gson = new Gson();
|
||
public void setContext(Context context) {
|
||
this.mContext = context;
|
||
}
|
||
|
||
//存储的字符数
|
||
public static final int cachedSize = 30000;
|
||
// protected final ArrayList<WeakReference<char[]>> myArray = new ArrayList<>();
|
||
|
||
public static final String lineBreakChar ="\n";
|
||
protected final ArrayList<Cache> myArray = new ArrayList<>();
|
||
//目录
|
||
private List<Chapter> mChapters = new ArrayList<>();
|
||
//当前章节
|
||
// private Chapter mCurrentChapter;
|
||
|
||
public List<Chapter> getChapters() {
|
||
return mChapters;
|
||
}
|
||
|
||
public void setChapters(List<Chapter> chapters) {
|
||
this.mChapters = chapters;
|
||
}
|
||
|
||
|
||
|
||
private String m_strCharsetName;
|
||
private String bookName;
|
||
private String bookPath;
|
||
|
||
public void setBookLen(long bookLen) {
|
||
this.bookLen = bookLen;
|
||
}
|
||
|
||
private long bookLen;
|
||
private long position;
|
||
private Novel mNovel;
|
||
|
||
public void setNovel(Novel novel) {
|
||
this.mNovel = novel;
|
||
}
|
||
|
||
//当前目录网站列表
|
||
private NovelSites mNovelSites;
|
||
//当前目录网站
|
||
private Site mSite;
|
||
private SiteRule mSiteRule;
|
||
public void setNovelSites(NovelSites nvs) {
|
||
|
||
this.mNovelSites = nvs;
|
||
if(nvs.getSites().length ==0){
|
||
return;
|
||
}
|
||
mSite =nvs.getSites()[0];
|
||
if(nvs.getSites().length > 0)
|
||
for (Site site:nvs.getSites() ) {
|
||
if(site.getSelectedByDefault()){
|
||
mSite = site;
|
||
break;
|
||
}
|
||
}
|
||
getSiteRule();
|
||
}
|
||
|
||
private void setSiteInfo() {
|
||
|
||
File file = new File(getChapterPath() +mSite.getDomain());
|
||
if(!file.exists()){
|
||
file.mkdir();
|
||
}
|
||
mNovel.setDomain(mSite.getDomain());
|
||
mNovel.setMuluUrl(mSite.getMuluUrl());
|
||
mNovel.update(mNovel.getId());
|
||
}
|
||
|
||
public void getTargetSites(){
|
||
BookSubscribe.getNovelSites(mNovel.getNovelId(),new OnSuccessAndFaultSub(new OnSuccessAndFaultListener() {
|
||
@Override
|
||
public void onSuccess(String result) {
|
||
//成功
|
||
try {
|
||
|
||
NovelSites nvs = (NovelSites) gson.fromJson(result,NovelSites.class);
|
||
//pageFactory.prepareBook(mNovel,nvs, BookActivity.this);
|
||
setNovelSites(nvs);
|
||
|
||
} catch ( Exception e) {
|
||
e.printStackTrace();
|
||
}
|
||
|
||
// Toast.makeText(mContext,"getMuluInfo 请求成功 " ,Toast.LENGTH_SHORT).show();
|
||
}
|
||
|
||
@Override
|
||
public void onFault(String errorMsg) {
|
||
//失败
|
||
// Toast.makeText(mContext,"getMuluInfo 请求失败"+errorMsg,Toast.LENGTH_SHORT).show();
|
||
}
|
||
},null));
|
||
}
|
||
private void getSiteRule() {
|
||
mSiteRule = null;
|
||
BookSubscribe.getSiteRule(mSite.getDomain(),new OnSuccessAndFaultSub(new OnSuccessAndFaultListener() {
|
||
@Override
|
||
public void onSuccess(String result) {
|
||
//成功
|
||
SiteRule sr = (SiteRule)gson.fromJson(result,SiteRule.class);
|
||
|
||
List<SiteRule> srs = LitePal.where("domain=?",sr.getDomain()).limit(1).find(SiteRule.class);
|
||
long id = srs.size()==1 ?srs.get(0).getId() :0;
|
||
if(id>0 ){
|
||
sr.update(id);
|
||
// mSiteRule =LitePal.find(SiteRule.class,id);
|
||
}else
|
||
{
|
||
sr.save();
|
||
}
|
||
mSiteRule =sr;
|
||
setSiteInfo();
|
||
readChaptersAsync();
|
||
|
||
|
||
}
|
||
|
||
@Override
|
||
public void onFault(String errorMsg) {
|
||
//失败
|
||
Log.d(TAG,"error on get sitRule: "+errorMsg);
|
||
}
|
||
},mContext));
|
||
|
||
/*
|
||
if(mSiteRule==null && mSite!=null) {
|
||
List<SiteRule> srs = LitePal.where("domain=?", mSite.getDomain()).find(SiteRule.class);
|
||
if (srs.size() > 0) {
|
||
mSiteRule = srs.get(0);
|
||
}
|
||
}*/
|
||
|
||
}
|
||
|
||
public void setChapterNo(int chapterNo) {
|
||
this.chapterNo = chapterNo;
|
||
}
|
||
|
||
public int getChapterNo() {
|
||
return chapterNo;
|
||
}
|
||
|
||
private int chapterNo;//当前章节
|
||
|
||
|
||
public String getLineBreakChar(){
|
||
return "\n";
|
||
}
|
||
|
||
public BookUtil(){
|
||
checkAndCreateDir(storagePath);
|
||
checkAndCreateDir(chapterPath);
|
||
checkAndCreateDir(cachedPath);
|
||
|
||
|
||
}
|
||
|
||
enum MuluStatus{
|
||
isDownloading,
|
||
isDone,
|
||
failed
|
||
}
|
||
private void showProgressDialog() {
|
||
if ( null == progressDialog) {
|
||
progressDialog =new ProgressDialog(mContext);
|
||
}
|
||
progressDialog.show();
|
||
// progressDialog.show(mContext,"网络不给力","正努力加载",false,true);
|
||
}
|
||
|
||
|
||
private void dismissProgressDialog() {
|
||
if ( null != progressDialog) {
|
||
progressDialog.dismiss();
|
||
}
|
||
}
|
||
|
||
private void checkAndCreateDir(String path){
|
||
File file = new File(path);
|
||
if (!file.exists()){
|
||
file.mkdir();
|
||
}
|
||
}
|
||
|
||
public synchronized void openBook(Novel novel) throws IOException, InterruptedException {
|
||
this.mNovel = novel;
|
||
//如果当前缓存不是要打开的书本就缓存书本同时删除缓存
|
||
|
||
//TODO 构建新的缓存策略,几个选项,1:每本书一个缓存 2:控制缓存总大小,超过限制删除旧缓存 3:网络小说的缓存
|
||
|
||
boolean isLocalImport = TextUtils.isEmpty( novel.getNovelId());
|
||
boolean isOnShelf = isLocalImport || novel.isOnShelf();
|
||
boolean isLoadChaptsFromRemote = !isLocalImport ;// && !novel.isFinished() ; //是否从目标网站下载目录
|
||
// showProgressDialog();
|
||
if(isLocalImport) {
|
||
|
||
mChapters = LitePal.where("novelId=?", mNovel.getId() + "").find(Chapter.class);
|
||
|
||
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. 首次打开 本地导入的书
|
||
|
||
if (bookPath == null || !bookPath.equals(mNovel.getNovelPath())) {
|
||
cleanCacheFile();
|
||
this.bookPath = mNovel.getNovelPath();
|
||
bookName = FileUtils.getFileName(bookPath);
|
||
cacheBook();
|
||
}
|
||
}
|
||
}else{ //读取目录列表
|
||
MuluStatus m = mMuluStatus;
|
||
// Log.d(TAG,String.format("mulu on Site %s download status %s",mSite.getDomain(),mMuluStatus));
|
||
|
||
while(mMuluStatus == MuluStatus.isDownloading){
|
||
Thread.sleep(50);
|
||
Log.d(TAG,String.format("waiting for mulu downloading ,mMuluStatus %s" ,mMuluStatus));
|
||
if(mMuluStatus == MuluStatus.failed){
|
||
dismissProgressDialog();
|
||
throw new RuntimeException("读取资源失败,请检查网络");
|
||
}
|
||
}
|
||
|
||
}
|
||
// dismissProgressDialog();
|
||
}
|
||
|
||
// String getMuluUrl() {
|
||
// return "https://www.qu.la/book/390/";
|
||
// }
|
||
/* void readChapters( String url){
|
||
Request request = getTagRequest(url);
|
||
|
||
ResponseBody body =null;
|
||
try {
|
||
|
||
long startTime= new Date().getTime();
|
||
Log.d(TAG,String.format("loadChaptContent----start download %s 目录 from %s", mNovel.getName() ,url ));
|
||
|
||
|
||
Response response = HttpMethods.getOkClient().newCall(request).execute();
|
||
Log.d(TAG,String.format("loadChaptContent----end download %s 目录, 目录数量 %s, cost %s", mNovel.getName() , mChapters.size(), new Date().getTime() -startTime ));
|
||
startTime= new Date().getTime();
|
||
body = response.body();
|
||
String bodyStr = body.string();
|
||
Log.d(TAG, "onResponse: " +bodyStr);
|
||
|
||
buildCharacters(bodyStr,url);
|
||
Log.d(TAG,String.format("loadChaptContent----end build %s 目录, 目录数量 %s, cost %s", mNovel.getName() , mChapters.size(), new Date().getTime() -startTime ));
|
||
|
||
} catch (IOException e) {
|
||
e.printStackTrace();
|
||
}finally {
|
||
if(body!=null){
|
||
body.close();;
|
||
}
|
||
}
|
||
|
||
}*/
|
||
|
||
void readChaptersAsync( ) {
|
||
String url = mSite.getMuluUrl();
|
||
Request request = getTagRequest(url);
|
||
mMuluStatus = MuluStatus.isDownloading;
|
||
long startTime= new Date().getTime();
|
||
Log.d(TAG,String.format("loadChaptContent----start download %s 目录 from %s", mNovel.getName() ,url ));
|
||
|
||
|
||
HttpMethods.getOkClient().newCall(request).enqueue(new Callback() {
|
||
@Override
|
||
public void onFailure(Call call, IOException e) {
|
||
Log.d(TAG, "onFailure: " + e.getMessage());
|
||
if( mNovelSites.getSites().length ==1){ //仅有一个rule,且失败了
|
||
mMuluStatus = MuluStatus.failed;
|
||
return;
|
||
}
|
||
|
||
//try next site
|
||
for(Site st : mNovelSites.getSites() ){
|
||
if(!st.getDomain().equals(mSite.getDomain())){
|
||
mSite =st;
|
||
break;
|
||
}
|
||
}
|
||
// readChaptersAsync();
|
||
getSiteRule();
|
||
}
|
||
|
||
@Override
|
||
public void onResponse(Call call, Response response){
|
||
ResponseBody body = response.body();
|
||
if(response.code()!=200){
|
||
mMuluStatus = MuluStatus.failed;
|
||
return;
|
||
}
|
||
if (body != null) {
|
||
|
||
try {
|
||
String bodyStr = body.string();
|
||
Log.d(TAG, "onResponse: " +bodyStr);
|
||
Log.d(TAG,String.format("loadChaptContent----end download %s 目录, 目录数量 %s, cost %s", mNovel.getName() , mChapters.size(), new Date().getTime() -startTime ));
|
||
long startTime2= new Date().getTime();
|
||
buildCharacters(bodyStr,url);
|
||
Log.d(TAG,String.format("loadChaptContent----end download %s 目录, 目录数量 %s, cost %s", mNovel.getName() , mChapters.size(), new Date().getTime() -startTime2 ));
|
||
mMuluStatus = MuluStatus.isDone;
|
||
|
||
|
||
} catch (IOException e) {
|
||
e.printStackTrace();
|
||
}finally {
|
||
body.close();
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
});
|
||
}
|
||
void buildCharacters( String content ,String url){
|
||
|
||
try {
|
||
JSONObject siteJson = new JSONObject();
|
||
|
||
siteJson.put("chapterUrlPattern", mSiteRule.getChapterUrlPattern());
|
||
siteJson.put("chapterUrlRegexOnMulu", mSiteRule.getChapterUrlRegexOnMulu());//示例接口表达式有问题
|
||
siteJson.put("chapterUrlRegexOnMulu", "<dd> <a[^>]*href=\"(/book/[\\d]+/[\\d]+\\.html)\">([^<]+)</a></dd>");
|
||
|
||
mChapters = NovelParseUtil.getChapters(mSite.getDomain(),url, content, siteJson);
|
||
Log.d(TAG,String.format("mulu on Site %s download status %s",mSite.getDomain(),mMuluStatus));
|
||
/* if (mChapters != null) {
|
||
int lastReadChapt = mNovel.getLastReadChapt();
|
||
// int index =lastReadChapt*2-2;
|
||
|
||
lastReadChapt = lastReadChapt >=mChapters.size() ? mChapters.size() -1:lastReadChapt;
|
||
lastReadChapt = lastReadChapt <=0 ? 1:lastReadChapt;
|
||
mCurrentChapter =mChapters.get(lastReadChapt-1);
|
||
|
||
}*/
|
||
} catch (JSONException e) {
|
||
// } catch (JSONException | IOException e) {
|
||
Log.d(TAG,String.format("mulu on Site %s download status %s",mSite.getDomain(),mMuluStatus));
|
||
e.printStackTrace();
|
||
} finally {
|
||
// result.close();
|
||
// if (result2 != null) result2.close();
|
||
}
|
||
}
|
||
|
||
|
||
private void cleanCacheFile(){
|
||
|
||
|
||
File file = new File(cachedPath );
|
||
if (!file.exists()){
|
||
file.mkdir();
|
||
}else{
|
||
File[] files = file.listFiles();
|
||
for (int i = 0; i < files.length;i++){
|
||
files[i].delete();
|
||
}
|
||
}
|
||
|
||
file = new File(getChapterPath());
|
||
|
||
if (!file.exists()){
|
||
file.mkdir();
|
||
}else{
|
||
File[] files = file.listFiles();
|
||
for (int i = 0; i < files.length;i++){
|
||
files[i].delete();
|
||
}
|
||
}
|
||
|
||
|
||
}
|
||
|
||
public int next(boolean back){
|
||
position += 1;
|
||
if (position > bookLen){
|
||
position = bookLen;
|
||
return -1;
|
||
}
|
||
char result = chaptCurrent(); //current();
|
||
if (back) {
|
||
position -= 1;
|
||
}
|
||
return result;
|
||
}
|
||
|
||
public char[] nextLine(){
|
||
if (position >= bookLen){
|
||
return null;
|
||
}
|
||
String line = "";
|
||
while (position < bookLen){
|
||
int word = next(false);
|
||
if (word == -1){
|
||
break;
|
||
}
|
||
char wordChar = (char) word;
|
||
if ((wordChar + "").equals("\n") ){// if ((wordChar + "").equals("\r") && (((char)next(true)) + "").equals("\n")){
|
||
// next(false);
|
||
break;
|
||
}
|
||
line += wordChar;
|
||
}
|
||
return line.toCharArray();
|
||
}
|
||
|
||
public char[] preLine(){
|
||
if (position <= 0){
|
||
return null;
|
||
}
|
||
String line = "";
|
||
while (position >= 0){
|
||
int word = pre(false);
|
||
if (word == -1){
|
||
break;
|
||
}
|
||
char wordChar = (char) word;
|
||
if ((wordChar + "").equals("\n") ){ // if ((wordChar + "").equals("\n") && (((char)pre(true)) + "").equals("\r")){
|
||
// pre(false); // /r/n ->/n 不需要再往前读一个字符了
|
||
// line = "\r\n" + line;
|
||
break;
|
||
}
|
||
line = wordChar + line;
|
||
}
|
||
|
||
return line.toCharArray();
|
||
}
|
||
public char chaptCurrent(){
|
||
|
||
|
||
char[] charArray = chaptChars(chapterNo);
|
||
|
||
|
||
|
||
|
||
return charArray[(int)position-1];
|
||
}
|
||
public char current(){
|
||
// int pos = (int) (position % cachedSize);
|
||
// int cachePos = (int) (position / cachedSize);
|
||
int cachePos = 0;
|
||
int pos = 0;
|
||
int len = 0;
|
||
for (int i = 0;i < myArray.size();i++){
|
||
long size = myArray.get(i).getSize();
|
||
if (size + len - 1 >= position){
|
||
cachePos = i;
|
||
pos = (int) (position - len);
|
||
break;
|
||
}
|
||
len += size;
|
||
}
|
||
|
||
char[] charArray = block(cachePos);
|
||
return charArray[pos];
|
||
}
|
||
|
||
public int pre(boolean back){
|
||
position -= 1;
|
||
if (position < 0){
|
||
position = 0;
|
||
return -1;
|
||
}
|
||
char result = current();
|
||
if (back) {
|
||
position += 1;
|
||
}
|
||
return result;
|
||
}
|
||
|
||
public long getPosition(){
|
||
return position;
|
||
}
|
||
|
||
public void setPostition(long position){
|
||
this.position = position;
|
||
}
|
||
|
||
//缓存书本
|
||
private void cacheBook() throws IOException {
|
||
if (TextUtils.isEmpty(mNovel.getCharset())) {
|
||
m_strCharsetName = FileUtils.getCharset(bookPath);
|
||
if (m_strCharsetName == null) {
|
||
m_strCharsetName = "utf-8";
|
||
}
|
||
ContentValues values = new ContentValues();
|
||
values.put("charset",m_strCharsetName);
|
||
LitePal.update(Novel.class,values,mNovel.getId());
|
||
}else{
|
||
m_strCharsetName = mNovel.getCharset();
|
||
}
|
||
|
||
File file = new File(bookPath);
|
||
InputStreamReader reader = new InputStreamReader(new FileInputStream(file),m_strCharsetName);
|
||
int index = 0;
|
||
bookLen = 0;
|
||
mChapters.clear();
|
||
myArray.clear();
|
||
while (true){
|
||
char[] buf = new char[cachedSize];
|
||
int result = reader.read(buf);
|
||
if (result == -1){
|
||
reader.close();
|
||
break;
|
||
}
|
||
|
||
String bufStr = new String(buf);
|
||
|
||
// Log.e(TAG,String.format("缓存的内容是\n %s",bufStr));
|
||
bufStr = bufStr.replaceAll("\r\n","\n");
|
||
// bufStr = bufStr.replaceAll("\u3000\u3000+[ ]*","\u3000\u3000");
|
||
bufStr = bufStr.replaceAll("\n+\\s*","\n\u3000\u3000");// bufStr = bufStr.replaceAll("\r\n+\\s*","\r\n\u3000\u3000");
|
||
// bufStr = bufStr.replaceAll("\r\n[ {0,}]","\r\n\u3000\u3000");
|
||
// bufStr = bufStr.replaceAll(" ","");
|
||
bufStr = bufStr.replaceAll("\u0000","");
|
||
buf = bufStr.toCharArray();
|
||
bookLen += buf.length;
|
||
// Log.e(TAG,String.format("缓存的内容脱空格处理后\n %s",bufStr));
|
||
Cache cache = new Cache();
|
||
cache.setSize(buf.length);
|
||
cache.setData(new WeakReference<char[]>(buf));
|
||
|
||
// bookLen += result;
|
||
myArray.add(cache);
|
||
// myArray.add(new WeakReference<char[]>(buf));
|
||
// myArray.set(index,);
|
||
Log.e(TAG,String.format("缓存的内容写入文件\n %s",fileName(index)));
|
||
Log.e(TAG,"---------------------------------------------------------------------------------------------------------");
|
||
|
||
try {
|
||
File cacheBook = new File(fileName(index));
|
||
if (!cacheBook.exists()){
|
||
cacheBook.createNewFile();
|
||
}
|
||
final OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(fileName(index)), "UTF-16LE"); // UTF-16LE 比 utf-8 文件小
|
||
writer.write(buf);
|
||
writer.close();
|
||
} catch (IOException e) {
|
||
throw new RuntimeException("Error during writing " + fileName(index));
|
||
}
|
||
index ++;
|
||
|
||
}
|
||
|
||
chaptId =0; //初始化导入的chapid
|
||
int endchp = myArray.size()>3 ?3:myArray.size();
|
||
getChapter(1,3); //先导入2个部分 立即进行阅读
|
||
new Thread(){
|
||
@Override
|
||
public void run() {
|
||
getChapter(4,myArray.size()); //剩余部分后台导入
|
||
}
|
||
}.start();
|
||
|
||
}
|
||
int chaptId =0;
|
||
//获取章节
|
||
public synchronized void getChapter(int startblk,int endblk){
|
||
if(endblk <startblk) return;
|
||
try {
|
||
long size = 0;
|
||
String title ="";
|
||
long start =0;
|
||
int chaptFileId=0;
|
||
|
||
Chapter bookChapter = null;
|
||
OutputStreamWriter writer = null;
|
||
for (int i = startblk-1; i < endblk; i++) {
|
||
char[] buf = block(i);
|
||
String bufStr = new String(buf);
|
||
String[] paragraphs = bufStr.split(lineBreakChar); // String[] paragraphs = bufStr.split("\r\n");
|
||
|
||
for (String str : paragraphs) {
|
||
|
||
// if (str.length() <= 30 && (str.matches(".*第.{1,8}章.*") || str.matches(".*第.{1,8}节.*"))) {
|
||
if(isChapterTitle(str)) {
|
||
|
||
if(title.length()==0) {
|
||
|
||
title = str;
|
||
start =0;
|
||
|
||
}else {
|
||
|
||
|
||
start = size;
|
||
title = str;
|
||
}
|
||
if(bookChapter!=null) {
|
||
bookChapter.setLength((int)(size - start));
|
||
bookChapter.setChapterPath(fileChapterName(chaptId) );
|
||
bookChapter.update(bookChapter.getId());
|
||
mChapters.add(bookChapter);
|
||
}
|
||
|
||
bookChapter = new Chapter();
|
||
bookChapter.setNovelId(mNovel.getId());
|
||
bookChapter.setNovelChapterStartPos(start);
|
||
bookChapter.setChapterName(str.replaceAll("###",""));
|
||
bookChapter.setNovelPath(bookPath);
|
||
bookChapter.save();
|
||
int id= bookChapter.getId();
|
||
Log.d(TAG,str + " chaptId is " + id);
|
||
|
||
|
||
File chapter = new File(fileChapterName(++chaptId));
|
||
if (!chapter.exists()){
|
||
chapter.createNewFile();
|
||
}
|
||
if(writer!=null) {
|
||
writer.close();
|
||
}
|
||
writer = new OutputStreamWriter(new FileOutputStream(fileChapterName(chaptId)), charachterType);
|
||
|
||
|
||
|
||
}
|
||
|
||
if(writer==null) {
|
||
bookChapter = new Chapter();
|
||
bookChapter.setNovelId(mNovel.getId());
|
||
bookChapter.setNovelChapterStartPos(start);
|
||
bookChapter.setChapterName(str.replaceAll("###",""));
|
||
bookChapter.setNovelPath(bookPath);
|
||
bookChapter.save();
|
||
writer = new OutputStreamWriter(new FileOutputStream(fileChapterName(++chaptId)), charachterType); //序
|
||
}
|
||
str+=lineBreakChar;
|
||
writer.write(str);
|
||
|
||
// Log.e(TAG,String.format("当前行\n %s",str));
|
||
if (str.contains("\u3000\u3000")) {
|
||
size += str.length() + 2;
|
||
}else if (str.contains("\u3000")){
|
||
size += str.length() + 1;
|
||
}else {
|
||
size += str.length();
|
||
}
|
||
|
||
/*
|
||
Chapter bookChapter = new Chapter();
|
||
bookChapter.setBookId(mNovel.getId());
|
||
|
||
bookChapter.setBookChapterStartPos(start);
|
||
bookChapter.setChapterName(title.replaceAll("###",""));
|
||
bookChapter.setBookpath(bookPath);
|
||
bookChapter.setLength((int)(size - start));
|
||
bookChapter.save();
|
||
int id= bookChapter.getId();
|
||
Log.d(TAG,str + " chaptId is " + id);
|
||
mChapters.add(bookChapter);
|
||
*/
|
||
}
|
||
}
|
||
if(writer!=null) {
|
||
writer.close();
|
||
}
|
||
if(bookChapter!=null) {
|
||
bookChapter.setLength((int)(size - start));
|
||
bookChapter.setChapterPath(fileChapterName(chaptId) );
|
||
bookChapter.update(bookChapter.getId());
|
||
mChapters.add(bookChapter);
|
||
}
|
||
}catch (Exception e){
|
||
e.printStackTrace();
|
||
}
|
||
}
|
||
|
||
void createChapContent(){
|
||
|
||
}
|
||
|
||
public List<Chapter> getmChapters(){
|
||
return mChapters;
|
||
}
|
||
|
||
public long getBookLen(){
|
||
return bookLen;
|
||
}
|
||
|
||
protected String fileName(int index) {
|
||
return cachedPath + mNovel.getName() + index ;
|
||
}
|
||
protected String fileChapterName(int chaptId ) {
|
||
if(!TextUtils.isEmpty(mNovel.getDomain())){
|
||
|
||
return getChapterPath() +mNovel.getDomain()+"/"+ chaptId ;
|
||
}
|
||
return getChapterPath() + chaptId ;
|
||
}
|
||
|
||
String getChapterPath(){
|
||
File file = new File(chapterPath +mNovel.getId());
|
||
if(!file.exists()){
|
||
file.mkdir();
|
||
}
|
||
return chapterPath +mNovel.getId()+"/";
|
||
}
|
||
|
||
//获取书本缓存
|
||
public char[] block(int index) {
|
||
if (myArray.size() == 0){
|
||
return new char[1];
|
||
}
|
||
char[] block = myArray.get(index).getData().get();
|
||
if (block == null) {
|
||
try {
|
||
File file = new File(fileName(index));
|
||
int size = (int)file.length();
|
||
if (size < 0) {
|
||
throw new RuntimeException("Error during reading " + fileName(index));
|
||
}
|
||
block = new char[size / 2];
|
||
InputStreamReader reader =
|
||
new InputStreamReader(
|
||
new FileInputStream(file),
|
||
"UTF-16LE"
|
||
);
|
||
if (reader.read(block) != block.length) {
|
||
throw new RuntimeException("Error during reading " + fileName(index));
|
||
}
|
||
reader.close();
|
||
} catch (IOException e) {
|
||
throw new RuntimeException("Error during reading " + fileName(index));
|
||
}
|
||
Cache cache = myArray.get(index);
|
||
cache.setData(new WeakReference<char[]>(block));
|
||
// myArray.set(index, new WeakReference<char[]>(block));
|
||
}
|
||
return block;
|
||
}
|
||
|
||
boolean isDownloadChapt =false;
|
||
synchronized boolean getDownloadStatus(){
|
||
return isDownloadChapt;
|
||
}
|
||
synchronized void setDownloadFlag(boolean flag){
|
||
isDownloadChapt = flag;
|
||
Log.d("loadChaptContent",String.format("set download flat",isDownloadChapt) );
|
||
}
|
||
|
||
final Handler handler = new Handler() {
|
||
@Override
|
||
public void handleMessage(Message msg) {
|
||
|
||
int wt = msg.what;
|
||
|
||
dismissProgressDialog();
|
||
|
||
if (msg.what == 123) {
|
||
isDownloadChapt =true;
|
||
Log.d("loadChaptContent",String.format("handler msg, download %s",isDownloadChapt) );
|
||
}else if(msg.what==1){
|
||
isDownloadChapt =true;
|
||
Toast.makeText(mContext,"网络错误",Toast.LENGTH_LONG).show();
|
||
}
|
||
|
||
}
|
||
};
|
||
|
||
private Map<Integer,Cache> chaptCache = new HashMap<Integer,Cache>();
|
||
|
||
//获取chapter 缓存
|
||
public char[] chaptChars(int index) {
|
||
char[] block=null;
|
||
if(chaptCache.containsKey(Integer.valueOf(index))) {
|
||
block = chaptCache .get(index).getData().get();
|
||
}
|
||
if (block == null) {
|
||
// cleanCacheFile(); //to remove
|
||
try {
|
||
File file = new File(fileChapterName(index));
|
||
|
||
if(!file.exists()) {
|
||
|
||
if(mChapters ==null || mChapters.size() ==0){
|
||
String error = "网络错误";
|
||
return error.toCharArray();
|
||
}
|
||
|
||
Log.d(TAG,String.format("loadChaptContent----start %s" ,new Date().toString() ));
|
||
|
||
//showProgressDialog();//why not show
|
||
|
||
Log.d( "loadChaptContent",String.format("begin to load content for chapter %s",index));
|
||
Log.d( "loadChaptContent",String.format("isDownloadChapt: %s",isDownloadChapt));
|
||
|
||
if(getDownloadStatus() ) {
|
||
loadChaptContent(index);
|
||
}
|
||
|
||
Log.d( "loadChaptContent",String.format("showing dialog " ));
|
||
// Log.d(TAG,String.format("showing progress diaglog......"));
|
||
int maxSleep =6000;
|
||
int slepttime =0;
|
||
// while(!file.exists() && !getDownloadStatus()){//&& slepttime <maxSleep){
|
||
while( !getDownloadStatus() && slepttime <maxSleep){
|
||
Thread.sleep(50);
|
||
slepttime+=50;
|
||
Log.d("loadChaptContent",String.format("loadChaptContent slept %s for downloading,isDownload %s ",slepttime,getDownloadStatus() ) );
|
||
}
|
||
Log.d("loadChaptContent",String.format("loadChaptContent slept %s for downloading ",slepttime ) );
|
||
Log.d( "loadChaptContent",String.format("dismissing dialog " ));
|
||
dismissProgressDialog();
|
||
Log.d(TAG,String.format("loadChaptContent slept %s for downloading chaptercontent ",slepttime ));
|
||
}
|
||
Log.d( "loadChaptContent",String.format(" %s, file.exists()? %s", file.getPath(),file.exists()));
|
||
if(!file.exists()) {
|
||
|
||
String error = "万里长城";
|
||
return error.toCharArray();
|
||
}
|
||
if(mChapters.size() > index ) {
|
||
|
||
File file2 = new File(fileChapterName(index+1));
|
||
|
||
if(!file2.exists()) {
|
||
loadChaptContent(index + 1);
|
||
}
|
||
|
||
}
|
||
|
||
|
||
int size = (int)file.length();
|
||
if (size < 0) {
|
||
throw new RuntimeException("Error during reading " + fileChapterName(index));
|
||
}
|
||
block = new char[size / 2];
|
||
InputStreamReader reader =
|
||
new InputStreamReader(
|
||
new FileInputStream(file),
|
||
charachterType
|
||
);
|
||
long l = reader.read(block);
|
||
if (reader.read(block) != block.length) {
|
||
// throw new RuntimeException("Error during reading " + fileChapterName(index));
|
||
}
|
||
reader.close();
|
||
} catch (IOException e) {
|
||
e.printStackTrace();
|
||
throw new RuntimeException("Error during reading " + fileChapterName(index));
|
||
} catch (JSONException e) {
|
||
e.printStackTrace();
|
||
} catch (InterruptedException e) {
|
||
e.printStackTrace();
|
||
}finally {
|
||
dismissProgressDialog();
|
||
}
|
||
Cache cache = new Cache();
|
||
cache.setSize(block.length);
|
||
cache.setData(new WeakReference<char[]>(block));
|
||
chaptCache.put(index, cache);
|
||
// myArray.set(index, new WeakReference<char[]>(block));
|
||
}
|
||
return block;
|
||
}
|
||
|
||
private void loadChaptContent(int index) throws JSONException, InterruptedException {
|
||
/* 章节内容没有缓存在本地
|
||
1. 根据本地的章节网络地址信息,读取章节内容到本地,若读取失败则
|
||
2. 查询主服务器,若有地址更新则更新本地信息,并重复1,若没有更新地址,则地址无效,返回章节内容正待手打
|
||
*/
|
||
//
|
||
|
||
Chapter chapter = mChapters.get(index -1);
|
||
String url = chapter.getChapterUrl();
|
||
if( TextUtils.isEmpty( url)){
|
||
return ;
|
||
}
|
||
long startTime= new Date().getTime();
|
||
Log.d(TAG,String.format("loadChaptContent----start download %s from %s", chapter.getChapterName() ,url ));
|
||
|
||
setDownloadFlag(false);
|
||
|
||
Log.d( "loadChaptContent",String.format("loadChaptContent isDownloadChapt: %s",isDownloadChapt));
|
||
JSONObject siteJson = new JSONObject();
|
||
siteJson.put("chapterContentRegex", mSiteRule.getChapterContentRegex());
|
||
siteJson.put("chapterContentDumpRegex", mSiteRule.getChapterContentDumpRegex());
|
||
Request request = getTagRequest(url);
|
||
HttpMethods.getOkClient().newCall(request).enqueue(new Callback() {
|
||
@Override
|
||
public void onFailure(Call call, IOException e) {
|
||
handler.sendEmptyMessage(123);
|
||
handler.sendEmptyMessage(1);
|
||
setDownloadFlag(true);
|
||
Log.d( "loadChaptContent",String.format("loadChaptContent fail, isDownloadChapt: %s",isDownloadChapt));
|
||
e.printStackTrace();
|
||
// throw new RuntimeException("Error during writing " + fileChapterName( index));
|
||
}
|
||
|
||
@Override
|
||
public void onResponse(Call call, Response response){
|
||
ResponseBody body = response.body();
|
||
if (body != null ) {
|
||
if(response.code()!=200){
|
||
Log.d(TAG, "loadChaptContent----network failure returnCode " + response.code());
|
||
setDownloadFlag(true);
|
||
Log.d( "loadChaptContent",String.format("loadChaptContent error %s ,isDownloadChapt: %s", response.code(),isDownloadChapt));
|
||
handler.sendEmptyMessage(1);
|
||
return;
|
||
}
|
||
|
||
try {
|
||
String bodyStr = body.string();
|
||
String title = chapter.getChapterName();
|
||
String chapterContent = title+ "\n" + NovelParseUtil.getChapterContent(bodyStr, siteJson);
|
||
char[] buf = chapterContent.toCharArray();
|
||
File file = new File(fileChapterName(index));
|
||
file.createNewFile();
|
||
|
||
final OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(fileChapterName(index)), charachterType);//"UTF-16LE"); // UTF-16LE 比 utf-8 文件小
|
||
writer.write(buf);
|
||
writer.close();
|
||
Log.d( "loadChaptContent",String.format("loadChaptContent file created: %s", file.getPath()));
|
||
handler.sendEmptyMessage(123);
|
||
setDownloadFlag(true);
|
||
} catch (IOException | JSONException e) {
|
||
e.printStackTrace();
|
||
throw new RuntimeException("Error during writing " + fileChapterName( index));
|
||
}
|
||
finally {
|
||
body.close();
|
||
|
||
handler.sendEmptyMessage(123);
|
||
setDownloadFlag(true);
|
||
}
|
||
chapter.setNovelId(mNovel.getId());
|
||
chapter.setChapterPath(fileChapterName(index));
|
||
chapter.save();
|
||
setDownloadFlag(true);
|
||
Log.d(TAG,String.format("loadChaptContent---- finished download %s, cost time %s ,content path %s ", chapter.getChapterName(), new Date().getTime() -startTime ,chapter.getChapterPath() ));
|
||
|
||
}
|
||
}
|
||
});
|
||
|
||
|
||
}
|
||
|
||
private Request getTagRequest(String url) {
|
||
return new Request.Builder()
|
||
.tag(mNovel.getNovelId()) //标记 请求的tag,切换小说或离开小说界面(BookActivity) 时 取消未执行完毕的 此tag的所有请求
|
||
.url(url)
|
||
// .header("User-Agent", "OkHttp Example")
|
||
.build();
|
||
}
|
||
|
||
|
||
public boolean isChapterTitle(String line){
|
||
return (line.length() <= 30 && (line.matches(".*第.{1,8}章.*") || line.matches(".*第.{1,8}节.*"))) ;
|
||
}
|
||
|
||
|
||
}
|