1875 lines
		
	
	
		
			72 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
			
		
		
	
	
			1875 lines
		
	
	
		
			72 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
| package com.novelbook.android.utils;
 | ||
| 
 | ||
| import android.app.ProgressDialog;
 | ||
| import android.content.ContentValues;
 | ||
| import android.content.Context;
 | ||
| 
 | ||
| 
 | ||
| import android.os.AsyncTask;
 | ||
| import android.os.Bundle;
 | ||
| import android.os.Handler;
 | ||
| import android.os.Message;
 | ||
| import android.text.TextUtils;
 | ||
| import android.util.Log;
 | ||
| import android.widget.TextView;
 | ||
| import android.widget.Toast;
 | ||
| 
 | ||
| import com.google.gson.Gson;
 | ||
| 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.NetUtil;
 | ||
| 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 org.w3c.dom.Text;
 | ||
| 
 | ||
| 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.nio.charset.Charset;
 | ||
| import java.security.KeyManagementException;
 | ||
| import java.security.NoSuchAlgorithmException;
 | ||
| import java.security.cert.CertificateException;
 | ||
| import java.util.ArrayList;
 | ||
| import java.util.Date;
 | ||
| import java.util.HashMap;
 | ||
| import java.util.List;
 | ||
| import java.util.Map;
 | ||
| import java.util.Random;
 | ||
| 
 | ||
| import javax.net.ssl.HostnameVerifier;
 | ||
| import javax.net.ssl.SSLContext;
 | ||
| import javax.net.ssl.SSLSession;
 | ||
| import javax.net.ssl.TrustManager;
 | ||
| import javax.net.ssl.X509TrustManager;
 | ||
| 
 | ||
| import okhttp3.Call;
 | ||
| import okhttp3.Callback;
 | ||
| import okhttp3.Request;
 | ||
| import okhttp3.Response;
 | ||
| import okhttp3.ResponseBody;
 | ||
| 
 | ||
| 
 | ||
| public class BookUtil {
 | ||
|     public static final  String TAG ="BookUtil";
 | ||
|     public static final String storagePath =  FileUtils.getDiskCacheDir(MyApp.applicationContext);//Environment.getExternalStorageDirectory() + "/zhuike";
 | ||
|     public static final String cachedPath = storagePath + "/cache/";
 | ||
|     public static final String chapterPath = storagePath + "/chapter/";
 | ||
|     private static final String charachterType = "utf-8";//"UTF-16LE";
 | ||
|     private Context mContext;
 | ||
|     private ProgressDialog progressDialog;
 | ||
|     MuluStatus mMuluStatus; //目录是否下载完成
 | ||
|     private Gson gson = new Gson();
 | ||
|     public void setContext(Context context) {
 | ||
|         this.mContext = context;
 | ||
|     }
 | ||
| 
 | ||
|     public boolean  isReadingCatalogs() {
 | ||
|         return mMuluStatus == MuluStatus.isDownloading;
 | ||
|     }
 | ||
| 
 | ||
|     //存储的字符数
 | ||
|     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 final int MSG_FILLCONTENTDONE=1;
 | ||
|     private final int MSG_READCHAPTER_FAIL=2;
 | ||
|     private final int MSG_READCHAPTER_SUCCESS=3;
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|     private String m_strCharsetName;
 | ||
|     private String bookName;
 | ||
|     private String bookPath;
 | ||
| 
 | ||
|     public void setChapterLen(long chapterLen) {
 | ||
|         this.chapterLen = chapterLen;
 | ||
|     }
 | ||
|     private long bookLen;
 | ||
|     private long chapterLen;
 | ||
|    // private long position;
 | ||
|     private Map<Integer,Long> charPosition = new HashMap<Integer,Long>();
 | ||
| 
 | ||
|     private Novel mNovel;
 | ||
| 
 | ||
|     public void setNovel(Novel novel) {
 | ||
|         this.mNovel = novel;
 | ||
|     }
 | ||
|     public Novel getNovel( ) {
 | ||
|        return mNovel  ;
 | ||
|     }
 | ||
|     //当前目录网站列表
 | ||
|     private NovelSites mNovelSites;
 | ||
|     //当前目录网站
 | ||
|     private Site mSite;
 | ||
|     private SiteRule mSiteRule;
 | ||
| 
 | ||
|     private Map<Integer,Cache> chaptCache = new HashMap<Integer,Cache>();
 | ||
|     private   Map<Integer,DownloadStatus> chaptDownStatus = new HashMap<Integer, DownloadStatus>();
 | ||
|     DownloadStatus downloadStatus = DownloadStatus.notStart;
 | ||
| 
 | ||
|      
 | ||
|     public Chapter getChapter(int chapId){
 | ||
|         chapId = chapId >0 ?chapId : 1;
 | ||
| 
 | ||
|         Log.d(TAG, String.format("prepare book getChapter: chaptId %s,mChapters.size() %s ",chapId,mChapters.size()));
 | ||
|         if(chapId > mChapters.size() || mChapters.size() ==0){
 | ||
|             return Chapter.getChapter(mNovel.getId(), mNovel.getDomain()==null?"":mNovel.getDomain(),chapId);
 | ||
|         }else{
 | ||
|             return mChapters.get(chapId-1);
 | ||
|         }
 | ||
|     }
 | ||
| 
 | ||
| 
 | ||
|     public NovelSites getmNovelSites() {
 | ||
|         return mNovelSites;
 | ||
|     }
 | ||
| 
 | ||
|     public synchronized void openBook(Novel novel, long chapter) throws IOException, InterruptedException {
 | ||
|         this.mNovel = novel;
 | ||
|         //如果当前缓存不是要打开的书本就缓存书本同时删除缓存
 | ||
| 
 | ||
|         //TODO 构建新的缓存策略,几个选项,1:每本书一个缓存 2:控制缓存总大小,超过限制删除旧缓存 3:网络小说的缓存
 | ||
| 
 | ||
|         boolean isLocalImport = novel.isLocalBook();
 | ||
|         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{ //读取目录列表
 | ||
|             Log.d(TAG, String.format("prepare book %s open chapter %s  in background....  mMuluStatus %s,mSiteRule %s,thread %s",mNovel.getName(),chapter,mMuluStatus,mSiteRule,Thread.currentThread().getName()) );
 | ||
| 
 | ||
|             File file =new File(fileChapterName((int)chapter));
 | ||
| 
 | ||
|             if( file.exists()){
 | ||
|                 Log.d(TAG, String.format("prepare book  open chapter file %s, exist,not waiting more...to open file...",fileChapterName((int)chapter)  ));
 | ||
| 
 | ||
| 
 | ||
|                 return;
 | ||
|             }
 | ||
| 
 | ||
|             MuluStatus m = mMuluStatus;
 | ||
| 
 | ||
|             //  Log.d(TAG,String.format("mulu on Site %s download status %s",mSite.getDomain(),mMuluStatus));
 | ||
|             Log.d(TAG, String.format("prepare book %s open book in background....  mMuluStatus %s,mSiteRule %s,thread %s",mNovel.getName(),mMuluStatus,mSiteRule,Thread.currentThread().getName()) );
 | ||
| 
 | ||
|             int sleptTime =0;
 | ||
|             while( mSiteRule ==null || mMuluStatus==null || mMuluStatus == MuluStatus.isDownloading){
 | ||
| 
 | ||
|                 sleptTime++;
 | ||
|                 if(sleptTime >400  || sleptTime >30  && !NetUtil.isNetworkConnected()){
 | ||
|                     break;
 | ||
|                 }
 | ||
| 
 | ||
|                 Thread.sleep(50);
 | ||
|                 if(mMuluStatus == MuluStatus.failed){
 | ||
|                     Log.d(TAG,String.format("prepare book %s failed ,mMuluStatus %s,msiteRule %s,slept %s" ,mNovel.getName(),mMuluStatus,mSiteRule,sleptTime*50));
 | ||
|                  //   throw new RuntimeException("读取资源失败,请检查网络");
 | ||
|                 }
 | ||
|             }
 | ||
|             Log.d(TAG,String.format("prepare book %s waiting for mulu downloading ,mMuluStatus %s,msiteRule %s,slept %s" ,mNovel.getName(),mMuluStatus,mSiteRule,sleptTime*50));
 | ||
| 
 | ||
|         }
 | ||
|         //  dismissProgressDialog();
 | ||
|     }
 | ||
| 
 | ||
| 
 | ||
|     public void setNovelSites(NovelSites nvs) {
 | ||
| 
 | ||
|         this.mNovelSites = nvs;
 | ||
| 
 | ||
|         Log.d(TAG, String.format("prepare book %s get novel sites count %s .",mNovel.getName(), nvs.getSites().length) );
 | ||
|         if(nvs.getSites().length ==0){
 | ||
|             throw new RuntimeException("书本错误 code 001"); //无目标网站
 | ||
|            // return;
 | ||
|         }
 | ||
| 
 | ||
|         if(nvs.getSites().length > 0){
 | ||
|             for (Site site:nvs.getSites() ) {
 | ||
|                 if(!TextUtils.isEmpty(mNovel.getDomain()) && site.getDomain().equals(mNovel.getDomain())){
 | ||
|                     mSite = site;
 | ||
|                     break;
 | ||
|                 }
 | ||
|             }
 | ||
| 
 | ||
|             if(mSite ==null)
 | ||
|                 for (Site site:nvs.getSites() ) {
 | ||
|                     if(site.getSelectedByDefault()){
 | ||
|                         mSite = site;
 | ||
|                         break;
 | ||
|                     }
 | ||
|                 }
 | ||
|             if(mSite ==null)
 | ||
|                 mSite =nvs.getSites()[0];
 | ||
|         }
 | ||
|          getSiteRule();
 | ||
|     }
 | ||
| 
 | ||
|     private void setSiteInfo() {
 | ||
| 
 | ||
|         File file = new File(getChapterPath() +mSite.getDomain());
 | ||
|         if(!file.exists()){
 | ||
|             file.mkdir();
 | ||
|         }
 | ||
|         mNovel.setDomain(mSite.getDomain());
 | ||
|         mNovel.setDomainName(mSite.getName());
 | ||
|         mNovel.setMuluUrl(mSite.getMuluUrl());
 | ||
|         mNovel.update(mNovel.getId());
 | ||
|     }
 | ||
| 
 | ||
|    public void getTargetSites(){
 | ||
|        Log.d(TAG, "prepare book:   getTargetSites"  );
 | ||
|         BookSubscribe.getNovelSites(mNovel.getNovelId(),new OnSuccessAndFaultSub(new OnSuccessAndFaultListener() {
 | ||
|             @Override
 | ||
|             public void onSuccess(String result) {
 | ||
|                 //成功
 | ||
|                 try {
 | ||
|                     Log.d(TAG, String.format("prepare book %s get target sites done.thread %s",mNovel.getName(),Thread.currentThread().getName()) );
 | ||
| 
 | ||
|                     NovelSites nvs = (NovelSites) gson.fromJson(result,NovelSites.class);
 | ||
|                     //pageFactory.prepareBook(mNovel,nvs, BookActivity.this);
 | ||
|                     setNovelSites(nvs);
 | ||
| 
 | ||
| 
 | ||
|                 } catch ( Exception e) {
 | ||
|                     Log.d(TAG, String.format("prepare book %s get target sites fail.thread %s ,msg %s",mNovel.getName(),Thread.currentThread().getName(),e.getMessage()) );
 | ||
|                     Log.e(TAG, "prepare book fail", e);
 | ||
|                     e.printStackTrace();
 | ||
|                 }
 | ||
| 
 | ||
|               //  Toast.makeText(mContext,"getMuluInfo 请求成功 "  ,Toast.LENGTH_SHORT).show();
 | ||
|             }
 | ||
| 
 | ||
|             @Override
 | ||
|             public void onFault(String errorMsg) {
 | ||
|                 Log.d(TAG, String.format("prepare book %s get target sites fail.thread %s ,msg %s",mNovel.getName(),Thread.currentThread().getName(),errorMsg) );
 | ||
| 
 | ||
|                 //失败
 | ||
|               //  Toast.makeText(mContext,"getMuluInfo 请求失败"+errorMsg,Toast.LENGTH_SHORT).show();
 | ||
|             }
 | ||
|         },null));
 | ||
|     }
 | ||
| 
 | ||
|     int siteRuleRetryCnt =0;
 | ||
|     public void getSiteRule() {
 | ||
|         mSiteRule = null;
 | ||
|         if(mSite==null){
 | ||
|             return;
 | ||
|         }
 | ||
|         BookSubscribe.getSiteRule(mSite.getDomain(),new OnSuccessAndFaultSub(new OnSuccessAndFaultListener() {
 | ||
|             @Override
 | ||
|             public void onSuccess(String result) {
 | ||
|                 siteRuleRetryCnt =0;
 | ||
|                 Log.d(TAG, "prepare book siteRule:" +result);
 | ||
|                 //成功
 | ||
|                 SiteRule sr= new SiteRule();
 | ||
|                 try {
 | ||
|                     sr = (SiteRule) gson.fromJson(result, SiteRule.class);
 | ||
|                 }catch (Exception e){
 | ||
|                     Log.e(TAG, "prepare book error on gson: ", e);
 | ||
|                 }
 | ||
| 
 | ||
|                 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;
 | ||
|                 if(TextUtils.isEmpty(mSite.getName())){
 | ||
|                     mSite.setName(sr.getName());
 | ||
|                 };
 | ||
|                 setSiteInfo();
 | ||
|                 Log.d(TAG, String.format("prepare book %s 目录正则表达式下载完成,开始读章节信息. muluRegex size %s, thread %s ",mNovel.getName(),mSiteRule.getChapterUrlRegexOnMulu().length, Thread.currentThread().getName()) );
 | ||
| 
 | ||
|                 Log.d(TAG, String.format("目录正则表达式下载完成,开始读取章节信息") );
 | ||
| 
 | ||
|                 if(mSiteRule.getChapterUrlRegexOnMulu().length>0) {
 | ||
|                     mMuluStatus = MuluStatus.isDownloading;
 | ||
|                     long startTime= new Date().getTime();
 | ||
|                     Log.d(TAG,String.format("prepare book loadChapts----start download %s,maxAge %s,  目录 from %s",  mNovel.getName() ,mNovel.getMaxAge() ,mSite.getMuluUrl() ));
 | ||
|                     new Thread(){
 | ||
|                         @Override
 | ||
|                         public void run() {
 | ||
|                             Log.d(TAG, "to get chaps............................>");
 | ||
|                             Log.d(TAG, "to get chaps siteRule:" +result);
 | ||
|                             Log.d(TAG, "to get chaps mulu:" + mSite.getMuluUrl() );
 | ||
|                             String[] chaps = new String[0];
 | ||
|                             try {
 | ||
|                                 JSONObject siteJson = new JSONObject(result);
 | ||
| 
 | ||
|                                 mChapters = NovelParseUtil.getChapters(mSite.getMuluUrl(), siteJson,mSite.getDomain(),mNovel.getMaxAge(),mSiteRule);
 | ||
| 
 | ||
|                                /* if (mChapters != null){
 | ||
|                                     for (Chapter chapter:mChapters) {
 | ||
|                                         Log.i(TAG,   String.format("prepare book to get chaps readChaptersAsync %s-->%s",chapter.getChapterUrl(), chapter.getChapterName()));
 | ||
|                                     }
 | ||
|                                 }*/
 | ||
| 
 | ||
| 
 | ||
|                             } catch (JSONException e) {
 | ||
|                                 Log.e(TAG, "prepare book error on parese :", e);
 | ||
|                             }
 | ||
| 
 | ||
|                             if (mChapters == null ||mChapters.size()== 0) {
 | ||
|                                 readChaptersAsync();
 | ||
|                             }else
 | ||
|                             {
 | ||
|                                 handler.sendEmptyMessage(MSG_READCHAPTER_SUCCESS);
 | ||
|                                 Log.d(TAG,String.format("prepare book loadChapts----end download %s  目录, 目录数量 %s, cost %s",  mNovel.getName()  , mChapters.size(),   new Date().getTime() -startTime ));
 | ||
|                                 mMuluStatus = MuluStatus.isDone;
 | ||
|                                 Log.d(TAG, String.format("prepare book %s 章节信息完成.",mNovel.getName()) );
 | ||
|                             }
 | ||
| 
 | ||
| 
 | ||
|                         }
 | ||
|                     }.start();
 | ||
| 
 | ||
| 
 | ||
|                 }else{
 | ||
|                      readChaptersAsync();
 | ||
|                  }
 | ||
|             }
 | ||
| 
 | ||
|             @Override
 | ||
|             public void onFault(String errorMsg) {
 | ||
|                 //失败
 | ||
|             Log.e(TAG,"error on get sitRule: "+errorMsg);
 | ||
|                 siteRuleRetryCnt++;
 | ||
|                 if(siteRuleRetryCnt <Constants.retryCnt){
 | ||
|                     getSiteRule();
 | ||
|                 }
 | ||
|             }
 | ||
|         },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;
 | ||
|        /*
 | ||
|         if(chapterNo <= mChapters.size()) {
 | ||
|             this.chapterNo = chapterNo;
 | ||
|         }else{
 | ||
|             Log.d(TAG, String.format("setChapterNo: wrong chapno for book %s,site %s,total chapts %s,chaptNo %s" ,mNovel.getName(),mNovel.getDomain(),getChapters().size(),chapterNo));
 | ||
|         }
 | ||
|         */
 | ||
|     }
 | ||
| 
 | ||
|     public int getChapterNo() {
 | ||
| 
 | ||
|         if(chapterNo  > mChapters.size()){
 | ||
|           //  Log.d(TAG, String.format(" prepare book  getChapterNo ,chapterNo %s,  getChapters().size() %s ,mChangeChapId %s" ,chapterNo , mChapters.size(),mChangeChapId)  );
 | ||
|             if(mChangeChapId>0){
 | ||
|                 return  mChangeChapId;
 | ||
|             }
 | ||
|           //  chapterNo=1;
 | ||
|         }
 | ||
|         chapterNo =   chapterNo<=0 ?1 :chapterNo;
 | ||
| 
 | ||
|        //         Log.d(TAG, String.format(" prepare book  getChapterNo ,chapterNo %s,  getChapters().size() %s " ,chapterNo , mChapters.size()) );
 | ||
|         return chapterNo;
 | ||
|     }
 | ||
| 
 | ||
|     private int chapterNo;//当前章节
 | ||
| 
 | ||
| 
 | ||
|     public String getLineBreakChar(){
 | ||
|         return "\n";
 | ||
|     }
 | ||
| 
 | ||
|     public BookUtil(){
 | ||
|         checkAndCreateDir(storagePath);
 | ||
|         checkAndCreateDir(chapterPath);
 | ||
|         checkAndCreateDir(cachedPath);
 | ||
| 
 | ||
| 
 | ||
|     }
 | ||
| 
 | ||
|     public boolean isBusy() {
 | ||
|         return  false;
 | ||
| 
 | ||
|     }
 | ||
|     private long tmpChaptLen=0;
 | ||
| 
 | ||
|     public void setTmpChaptLen(long tmpChaptLen) {
 | ||
|         this.tmpChaptLen = tmpChaptLen;
 | ||
|     }
 | ||
| 
 | ||
|     private boolean isChangeSource =false;
 | ||
|     private int mChangeChapId;
 | ||
|     private String mChangeTitle;
 | ||
| 
 | ||
|     public void changeSite(String domain){
 | ||
|         for (Site site:mNovelSites.getSites() ) {
 | ||
|             if(site.getDomain().equals(domain)){
 | ||
|                 mSite = site;
 | ||
|                 break;
 | ||
|             }
 | ||
|         }
 | ||
|         setSiteInfo();
 | ||
| 
 | ||
| 
 | ||
|         isChangeSource = true;
 | ||
|         mChapters.clear();
 | ||
|         getSiteRule();
 | ||
|     }
 | ||
|     public void changeSource(String domain,int chapId,String chapTitle) {
 | ||
|         Log.d(TAG, String.format("changing Source: target domain %s chaptId %s, chapt title %s ",domain,chapId,chapTitle)  );
 | ||
| 
 | ||
|        clearBook();
 | ||
|        // isDownloadChapt =false;
 | ||
|         mChangeChapId = chapId;
 | ||
|         mChangeTitle =chapTitle;
 | ||
|         changeSite(domain);
 | ||
| 
 | ||
|         BookTask btsk = new BookTask();
 | ||
|         btsk.execute( domain,  chapId+"",  chapTitle);
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|     }
 | ||
| 
 | ||
|     private void clearBook() {
 | ||
|         charPosition.clear();
 | ||
|         this.muluRetryCount=0;
 | ||
|         this.downloadStatus = DownloadStatus.notStart;
 | ||
|         chaptDownStatus.clear();
 | ||
|         chaptCache.clear();
 | ||
|         fileRetryCnt.clear();
 | ||
|         siteRuleRetryCnt=0;
 | ||
|         caprint.clear();
 | ||
|     }
 | ||
| 
 | ||
|     public Site getSite() {
 | ||
|         return mSite !=null? mSite :new Site();
 | ||
|     }
 | ||
| 
 | ||
|     public boolean chaptCached(int num) {
 | ||
|         File f = new File(fileChapterName(num));
 | ||
|         return  f.exists();
 | ||
|     }
 | ||
| 
 | ||
|     public boolean retryDownLoadContent(int chaptId) {
 | ||
|         if(chaptDownStatus.containsKey(chaptId)){
 | ||
|            if( chaptDownStatus.get(chaptId) == DownloadStatus.failure){
 | ||
|                if(fileRetryCnt.containsKey(chaptId)){
 | ||
|                    if(fileRetryCnt.get(chaptId) < Constants.retryCnt){
 | ||
|                        fileRetryCnt.put(chaptId,fileRetryCnt.get(chaptId)+1 );
 | ||
| 
 | ||
|                    }else{
 | ||
|                        return false;
 | ||
|                    }
 | ||
|                }else {
 | ||
|                    fileRetryCnt.put(chaptId, 1 );
 | ||
|                }
 | ||
| 
 | ||
|            }else{
 | ||
|                return false;
 | ||
|            }
 | ||
|         }else{
 | ||
|             chaptDownStatus.put(chaptId,DownloadStatus.downloading);
 | ||
|             fileRetryCnt.put(chaptId,11 );
 | ||
|         }
 | ||
| 
 | ||
|         if(fileRetryCnt.get(chaptId) < Constants.retryCnt) {
 | ||
|             try {
 | ||
|                 loadChaptContent(chaptId);
 | ||
|                 chaptDownStatus.put(chaptId,DownloadStatus.downloading);
 | ||
|             } catch (JSONException e) {
 | ||
|                 e.printStackTrace();
 | ||
|             } catch (InterruptedException e) {
 | ||
|                 e.printStackTrace();
 | ||
|             }
 | ||
| 
 | ||
|             return  true;
 | ||
|         }
 | ||
| 
 | ||
|         return false;
 | ||
| 
 | ||
|     }
 | ||
| 
 | ||
|     /**
 | ||
|      * delete cache chapter file
 | ||
|      * and reload the chapter
 | ||
|      */
 | ||
|     public void refreshChapter() {
 | ||
|         File file = new File(fileChapterName(chapterNo));
 | ||
|         if(file.exists()){
 | ||
|             file.delete();
 | ||
|         }
 | ||
|         if(chaptCache.containsKey(chapterNo)){
 | ||
|             chaptCache.remove(chapterNo);
 | ||
|         }
 | ||
|         if(pagefactory!=null) {
 | ||
|             pagefactory.changeChapter(chapterNo);
 | ||
|         }
 | ||
|     }
 | ||
| 
 | ||
| 
 | ||
|     private class BookTask extends AsyncTask<String,Void,Boolean> {
 | ||
|        private String domain;
 | ||
|        private  int chapId;
 | ||
|        private String chapTitle;
 | ||
|         @Override
 | ||
|         protected void onPostExecute(Boolean result) {
 | ||
|             super.onPostExecute(result);
 | ||
|             Log.d("onPostExecute",isCancelled() + "");
 | ||
|             if (isCancelled()){
 | ||
|                 return;
 | ||
|             }
 | ||
|             if (result) {
 | ||
|                 Log.d(TAG, String.format("changing Source: target domain %s chaptId %s, chapt title %s,mChangeChapId %s "
 | ||
|                         ,domain,chapId,chapTitle,mChangeChapId)  );
 | ||
| 
 | ||
|                 int chId=chapId;//chapterNo;
 | ||
|                 String title ="";
 | ||
|                 mChangeChapId = mChangeChapId >=1 ?mChangeChapId :1;//TODO: mChangeChapId 换源时不要变
 | ||
|                 if( mChapters.size() >= mChangeChapId && mChapters.get(mChangeChapId-1)!=null ){
 | ||
|                     title= mChapters.get(mChangeChapId-1).getChapterName();
 | ||
|                     Log.d(TAG, "changing Source:chapter name in new site " + title );
 | ||
|                 }
 | ||
|                 if(title.equals(mChangeTitle) || title.contains(mChangeTitle) || mChangeTitle.contains(title)) {
 | ||
|                         Log.d(TAG, "changing Source:successed find chapter by original chaptId  " + mChangeChapId + ":" + mChangeTitle);
 | ||
|                         chId = mChangeChapId;
 | ||
|                     }
 | ||
|                 else {
 | ||
|                     int i = 1;
 | ||
|                     for (Chapter chapter : mChapters) {
 | ||
|                       //  Log.d(TAG, "changing Source: finding chapter   " + i + ":" + chapter.getChapterName());
 | ||
|                         if (chapter.getChapterName().equals(mChangeTitle)) {
 | ||
|                             Log.d(TAG, "changing Source:successed find chapter by original title  " + i + ":" + mChangeTitle);
 | ||
|                             chId = i;
 | ||
|                             title = mChangeTitle;
 | ||
|                             break;
 | ||
|                         }
 | ||
|                         i++;
 | ||
|                     }
 | ||
| 
 | ||
|                     if (!title.equals(mChangeTitle)) {
 | ||
|                         i = 1;
 | ||
|                         for (Chapter chapter : mChapters) {
 | ||
|                         //    Log.d(TAG, "changing Source: finding chapter   " + i + ":" + chapter.getChapterName());
 | ||
|                             if (   mChangeTitle.contains(chapter.getChapterName())
 | ||
|                                     ||chapter.getChapterName().contains(mChangeTitle)
 | ||
|                             ){
 | ||
|                                 Log.d(TAG, "changing Source:successed find chapter by original title  " + i + ":" + mChangeTitle);
 | ||
|                                 chId = i;
 | ||
|                                 title = chapter.getChapterName();
 | ||
|                                 break;
 | ||
|                             }
 | ||
| 
 | ||
|                             i++;
 | ||
|                         }
 | ||
| 
 | ||
|                         i = 1;
 | ||
|                         for (Chapter chapter : mChapters) {
 | ||
|                             //    Log.d(TAG, "changing Source: finding chapter   " + i + ":" + chapter.getChapterName());
 | ||
|                             if ( chapter.getChapterName().startsWith(mChangeTitle)
 | ||
|                                     ||mChangeTitle.startsWith(chapter.getChapterName()  )
 | ||
| 
 | ||
|                             ){
 | ||
|                                 Log.d(TAG, "changing Source:successed find chapter by original title  " + i + ":" + mChangeTitle);
 | ||
|                                 chId = i;
 | ||
|                                 title = chapter.getChapterName();
 | ||
|                                 break;
 | ||
|                             }
 | ||
| 
 | ||
|                             i++;
 | ||
|                         }
 | ||
|                     }
 | ||
| 
 | ||
|                    /* if (!title.contains(mChangeTitle)) {
 | ||
|                         i = 1;
 | ||
|                         for (Chapter chapter : mChapters) {
 | ||
|                           //  Log.d(TAG, "changing Source: finding chapter   " + i + ":" + chapter.getChapterName());
 | ||
|                             if (mChangeTitle.contains(chapter.getChapterName())) {
 | ||
|                                 Log.d(TAG, "changing Source:successed find chapter by original title  " + i + ":" + mChangeTitle);
 | ||
|                                 chId = i;
 | ||
|                                 title = chapter.getChapterName();
 | ||
|                                 break;
 | ||
|                             }
 | ||
|                             i++;
 | ||
|                         }
 | ||
|                     }*/
 | ||
| 
 | ||
| 
 | ||
|                 }
 | ||
|                 chId = chId <= mChapters.size() ? chId: mChapters.size();
 | ||
|                 Log.d(TAG, "changing Source: to open chapter with new site source  "  + chId + " : "+ mChangeTitle );
 | ||
|                 if(pagefactory!=null)
 | ||
|                     pagefactory.changeChapter(chId);
 | ||
|               //  mChangeChapId=0;
 | ||
|                // Toast.makeText(mContext,"换源成功",Toast.LENGTH_LONG).show();
 | ||
|             }else{
 | ||
|                 Log.d(TAG, "changing Source:  failed "    );
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
|         @Override
 | ||
|         protected Boolean doInBackground(String... params) {
 | ||
|             domain = params[0];
 | ||
|             chapId = Integer.parseInt( params[1]);
 | ||
|             chapTitle = params[2];
 | ||
| 
 | ||
|             int splet =0;
 | ||
|             while(isChangeSource){
 | ||
|                 try {
 | ||
|                     Thread.sleep(50);
 | ||
|                     splet++;
 | ||
|                     Log.d(TAG, String.format("changing Source slept %s,isChangeSource %s ", splet, isChangeSource ));
 | ||
|                 } catch (InterruptedException e) {
 | ||
|                     e.printStackTrace();
 | ||
|                 }
 | ||
|             }
 | ||
|             return true;
 | ||
|         }
 | ||
| 
 | ||
|         @Override
 | ||
|         protected void onPreExecute() {
 | ||
|             super.onPreExecute();
 | ||
| 
 | ||
|         }
 | ||
| 
 | ||
|         @Override
 | ||
|         protected void onProgressUpdate(Void... values) {
 | ||
|             super.onProgressUpdate(values);
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|     }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|     /**
 | ||
|      * 新线程换源 ,handler 有问题
 | ||
| 
 | ||
|      */
 | ||
|  /*   public void changeSourceNewThread(String domain,int chapId,String chapTitle) {
 | ||
|           Log.d(TAG, String.format("changing Source: target domain %s chaptId %s, chapt title %s ",domain,chapId,chapTitle)  );
 | ||
|         if(mSite.getDomain().equals(domain)){ //当前源
 | ||
|             Log.d(TAG, "changing Source: same site with original " + domain);
 | ||
|           //  return;
 | ||
|         }
 | ||
|           mChangeChapId = chapId;
 | ||
|           mChangeTitle =chapTitle;
 | ||
|           for (Site site:mNovelSites.getSites() ) {
 | ||
|               if(site.getDomain().equals(domain)){
 | ||
|                   mSite = site;
 | ||
|                   break;
 | ||
|               }
 | ||
|           }
 | ||
|         setSiteInfo();
 | ||
| 
 | ||
|        // showProgressDialog();
 | ||
|         isChangeSource = true;
 | ||
|         new Thread(){
 | ||
|             @Override
 | ||
|             public void run() {
 | ||
|                 Log.d(TAG, "changing Source: to get site rule"  );
 | ||
|                 getSiteRule();
 | ||
|             }
 | ||
|         }.start();
 | ||
| 
 | ||
| 
 | ||
|   *//*
 | ||
|         while(isChangeSource){
 | ||
|             try {
 | ||
|                 Thread.sleep(50);
 | ||
|             } catch (InterruptedException e) {
 | ||
|                 e.printStackTrace();
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
|         new Thread(){
 | ||
|               @Override
 | ||
|               public void run() {
 | ||
|                   Log.d(TAG, "changing Source: to get site rule"  );
 | ||
|                   getSiteRule();
 | ||
|               }
 | ||
|           }.start();*//*
 | ||
| 
 | ||
|     }
 | ||
| */
 | ||
|     enum MuluStatus{
 | ||
|         isDownloading,
 | ||
|         isDone,
 | ||
|         failed
 | ||
|     }
 | ||
|     /*private void showProgressDialog(String title,boolean canBreak) {
 | ||
|         if (  null == progressDialog) {
 | ||
|             progressDialog =new ProgressDialog(mContext);
 | ||
| 
 | ||
|         }
 | ||
|         progressDialog.setMessage(title);
 | ||
|         progressDialog.setCancelable(canBreak);
 | ||
|         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();
 | ||
|         }
 | ||
|     }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| int muluRetryCount =0;
 | ||
| 
 | ||
|     void readChaptersAsync( ) {
 | ||
|         if(mSite==null ||mSiteRule ==null){
 | ||
|             Log.d(TAG,String.format("prepare book loadChapts failed---- %s ,mSite is null? %s ,mSiteRule ==null ? %s",  mNovel.getName()  ,mSite==null,mSiteRule ==null  ));
 | ||
|             return;
 | ||
|         }
 | ||
|         String url = mSite.getMuluUrl();
 | ||
|         Request request = getTagRequest(url,REUtil.getDomain(url), mNovel.getMaxAge());
 | ||
| 
 | ||
|         mMuluStatus = MuluStatus.isDownloading;
 | ||
|         long startTime= new Date().getTime();
 | ||
|         Log.d(TAG,String.format("prepare book loadChapts----start download %s,maxAge %s,  目录 from %s",  mNovel.getName() ,mNovel.getMaxAge() ,url ));
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|      /*   if(muluRetryCount<3){
 | ||
|             muluRetryCount++;
 | ||
|             return;
 | ||
|         }
 | ||
| 
 | ||
|         if(muluRetryCount>=3) {
 | ||
|          return;
 | ||
|         }*/
 | ||
| 
 | ||
|         HttpMethods.getOkClient().newCall(request).enqueue(new Callback() {
 | ||
|             @Override
 | ||
|             public void onFailure(Call call, IOException e) {
 | ||
|                 // Log.d(TAG, "onFailure: " + e.getMessage());
 | ||
|                 Log.e(TAG, "prepare book loadChapts---- failed: ", e);
 | ||
|                 Log.d(TAG, String.format("prepare book loadChapts---- failed %s  目录 from %s", mNovel.getName(), url));
 | ||
| 
 | ||
|                // handler.sendEmptyMessage(3);
 | ||
| 
 | ||
|                 //TODO 如果是取消了访问,则返回
 | ||
| 
 | ||
|                 if (e.toString()!=null && e.toString().contains("closed") || e.getMessage()!=null && e.getMessage().contains("Canceled")) {
 | ||
|                     Log.d(TAG, String.format("prepare book loadChapts---- canceled %s  目录 from %s", mNovel.getName(), url));
 | ||
| 
 | ||
| 
 | ||
|                     return;
 | ||
|                 }
 | ||
|                 mMuluStatus = MuluStatus.failed;
 | ||
| 
 | ||
|                 if (muluRetryCount <  Constants.muluRetryCnt) {
 | ||
|                     try {
 | ||
|                         long sleeptime =100;
 | ||
|                      if(mSiteRule!=null)   {
 | ||
|                       sleeptime = mSiteRule.getMiniInterval4AccessChapter();
 | ||
|                      }
 | ||
|                          Thread.sleep(sleeptime);
 | ||
| 
 | ||
|                     } catch (InterruptedException e1) {
 | ||
|                         e1.printStackTrace();
 | ||
|                     }
 | ||
|                     muluRetryCount++;
 | ||
|                     Log.d(TAG,String.format("prepare book loadChapts----failed,  retrying count %s",muluRetryCount ));
 | ||
|                     readChaptersAsync();
 | ||
|                     return;
 | ||
|                 }
 | ||
| 
 | ||
|                 Log.d(TAG,String.format("prepare book loadChapts----failed,  site count %s",mNovelSites.getSites().length  ));
 | ||
|                 if (mNovelSites.getSites().length == 1) { //仅有一个rule,且失败了
 | ||
| 
 | ||
|                   //  mMuluStatus = MuluStatus.failed;
 | ||
| 
 | ||
|                     return;
 | ||
|                 }
 | ||
| 
 | ||
|                 //try next site
 | ||
|                 Message msg =Message.obtain();
 | ||
|                 msg.what =MSG_READCHAPTER_FAIL;
 | ||
|                 msg.arg1 =chapterNo;
 | ||
|                 Bundle bundleData = new Bundle();
 | ||
| 
 | ||
|                     for (Site st : mNovelSites.getSites()) {
 | ||
|                         if (!st.getDomain().equals(mSite.getDomain())) {
 | ||
|                             //mSite = st;
 | ||
|                             mNovel.setDomain(st.getDomain());
 | ||
|                             mNovel.setDomainName(mSite.getName());
 | ||
|                             bundleData.putString("siteName", st.getName());
 | ||
|                             msg.setData(bundleData);
 | ||
|                             break;
 | ||
|                         }
 | ||
|                     }
 | ||
|                    //  mNovel.setDomain(mSite.getDomain());
 | ||
|                      muluRetryCount=0;
 | ||
|                     fileRetryCnt.clear();
 | ||
|                     siteRuleRetryCnt=0;
 | ||
|                     chaptCache.clear();
 | ||
| 
 | ||
| 
 | ||
|                     handler.sendMessage(msg);
 | ||
|                   //  handler.sendEmptyMessage(MSG_READCHAPTER_FAIL);
 | ||
|                     //  readChaptersAsync();
 | ||
| 
 | ||
| 
 | ||
|                 }
 | ||
| 
 | ||
| 
 | ||
|             @Override
 | ||
|             public void onResponse(Call call, Response response){
 | ||
|                 ResponseBody body = response.body();
 | ||
| 
 | ||
|                 if(response.code()!=200){
 | ||
|                     Log.d(TAG,String.format("prepare book loadChapts----failed,  %s  目录 from %s,return code %s",  mNovel.getName()  ,url,response.code() ));
 | ||
|                   //  handler.sendEmptyMessage(3);
 | ||
|                     mMuluStatus = MuluStatus.failed;
 | ||
|                     if(muluRetryCount <Constants.retryCnt){
 | ||
|                         Log.d(TAG,String.format("prepare book loadChapts----failed, response code %s  retrying count %s",response.code(), muluRetryCount ));
 | ||
|                         muluRetryCount++;
 | ||
|                         readChaptersAsync();
 | ||
|                     }
 | ||
|                     return;
 | ||
|                 }
 | ||
| 
 | ||
|               //  mChangeChapId =0;
 | ||
|                 muluRetryCount =0;
 | ||
|                 if (body != null) {
 | ||
|                     Log.d(TAG, String.format("prepare book %s 章节信息读取成功.thread %s",mNovel.getName(),Thread.currentThread().getName()) );
 | ||
|                     try {
 | ||
|                       //  String bodyStr = body.string();
 | ||
|                         String   bodyStr =NovelParseUtil.enconding(body ,mSiteRule.getEncoding());
 | ||
| 
 | ||
|                       //  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();
 | ||
|                         buildChapters(bodyStr,url);
 | ||
|                         Log.d(TAG,String.format("prepare book loadChapts----end download %s  目录, 目录数量 %s, cost %s",  mNovel.getName()  , mChapters.size(),   new Date().getTime() -startTime ));
 | ||
|                         mMuluStatus = MuluStatus.isDone;
 | ||
|                         Log.d(TAG, String.format("prepare book %s 章节信息完成.",mNovel.getName()) );
 | ||
|                         handler.sendEmptyMessage(MSG_READCHAPTER_SUCCESS); //通知换源过程已读到目录
 | ||
|                     } catch (IOException e) {
 | ||
|                         e.printStackTrace();
 | ||
|                     }finally {
 | ||
|                         body.close();
 | ||
| 
 | ||
|                     }
 | ||
| 
 | ||
|                 }
 | ||
| 
 | ||
|             }
 | ||
|         });
 | ||
|     }
 | ||
|     void buildChapters( String content ,String url){
 | ||
| 
 | ||
|         Log.d(TAG, "buildChapters: " +content);
 | ||
|         if(mSite==null ||mSiteRule ==null){
 | ||
|             Log.d(TAG,String.format("prepare book buildChapters failed---- %s ,mSite is null? %s ,mSiteRule ==null ? %s",  mNovel.getName()  ,mSite==null,mSiteRule ==null  ));
 | ||
|             return;
 | ||
|         }
 | ||
|         try {
 | ||
|             JSONObject siteJson = new JSONObject();
 | ||
| 
 | ||
|             siteJson.put("chapterUrlPattern", mSiteRule.getChapterUrlPattern());
 | ||
|            /* if(mSiteRule.getDomain().equals("qu.la")){
 | ||
|                 siteJson.put("chapterUrlRegexOnMulu", "<dd> <a[^>]*href=\"(/book/[\\d]+/[\\d]+\\.html)\">([^<]+)</a></dd>");
 | ||
|             }else{
 | ||
|                 siteJson.put("chapterUrlRegexOnMulu", mSiteRule.getChapterUrlRegexOnMulu());
 | ||
|             }*/
 | ||
|              siteJson.put("chapterUrlRegexOnMulu", "");
 | ||
|          //
 | ||
| 
 | ||
|             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.size()> mNovel.getChaptCnt()){
 | ||
|                mNovel.setChaptCnt(mChapters.size());
 | ||
|                mNovel.update(mNovel.getId());
 | ||
|            }
 | ||
| 
 | ||
|         } catch (JSONException e) {
 | ||
|             // } catch (JSONException | IOException e) {
 | ||
|             Log.e(TAG,String.format("prepare book, mulu on Site %s download status %s",mSite.getDomain(),mMuluStatus),e);
 | ||
|             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,int chaptId){
 | ||
|       //  Log.d(TAG, String.format(" loadchapt  next(), back %s, chaptId %s, position %s, tmpChaptLen %s",back,chaptId,charPosition.get(chaptId),tmpChaptLen ));
 | ||
|         charPosition.put(chaptId,charPosition.get(chaptId)+1) ;
 | ||
|         if (charPosition.get(chaptId) > tmpChaptLen){
 | ||
|             charPosition.put(chaptId,tmpChaptLen) ;
 | ||
|             return -1;
 | ||
|         }
 | ||
| 
 | ||
|         char result = chaptCurrent(chaptId); //current();
 | ||
|         if (back) {
 | ||
|             charPosition.put(chaptId,charPosition.get(chaptId)-1) ;
 | ||
|         }
 | ||
|         return result;
 | ||
|     }
 | ||
| 
 | ||
|     /*public char[] nextLine(){
 | ||
|         if (position >= tmpChaptLen){
 | ||
|             return null;
 | ||
|         }
 | ||
|         String line = "";
 | ||
|         while (position < tmpChaptLen){
 | ||
|             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(int chaptId){
 | ||
|       //  chapterNo = mChapters.size() < chapterNo ? 1 : chapterNo;
 | ||
|     //    Log.d(TAG, String.format(" loadchapt   chaptCurrent() ,chapterNo %s,  getChapters().size() %s " ,chaptId , mChapters.size()) );
 | ||
|         char[] charArray = chaptChars(chaptId);
 | ||
| 
 | ||
| 
 | ||
|         int i = (int) (charPosition.get(chaptId) -1);//(int)position-1;
 | ||
|         i =i>0?i:0;
 | ||
|         i = i< charArray.length? i:charArray.length-1;
 | ||
| 
 | ||
|         // Log.d(TAG, String.format(" loadchapt  chaptCurrent(), char position %s - %s, char  '%s'  " ,i,charPosition.get(chaptId) -1,charArray[i]) );
 | ||
|         return charArray[i];
 | ||
|     }
 | ||
|     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 >= charPosition.get(chaptId) ){
 | ||
|                 cachePos = i;
 | ||
|                 pos = (int) (charPosition.get(chaptId) - 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(int chaptId){
 | ||
|         return charPosition.get(chaptId);
 | ||
|     }
 | ||
| 
 | ||
|     public void setPostition(int chaptId,long position){
 | ||
|         charPosition.put(chaptId,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.setIndex(chaptId+1);
 | ||
|                           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 getChapterLen(){
 | ||
|         return chapterLen;
 | ||
|     }
 | ||
| 
 | ||
|     protected String fileName(int index) {
 | ||
|         return cachedPath + mNovel.getName() + index ;
 | ||
|     }
 | ||
|     public String fileChapterName(int chaptId ) {
 | ||
|         if(mNovel!=null && !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(TAG,String.format("set download flat",isDownloadChapt) );
 | ||
|     }*/
 | ||
|     public ChangeSource pagefactory;
 | ||
|      Handler handler = new Handler() {
 | ||
|         @Override
 | ||
|         public void handleMessage(Message msg) {
 | ||
| 
 | ||
|             int wt = msg.what;
 | ||
|             Log.d(TAG, String.format("prepare book get message what %s ,obj %s",msg.what,msg.obj));
 | ||
|             handlerMsg(msg);
 | ||
| 
 | ||
|         }
 | ||
|     };
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|      void handlerMsg(Message msg){
 | ||
|          if (msg.what == MSG_FILLCONTENTDONE) {
 | ||
|           //   isDownloadChapt =true;
 | ||
|              Log.d(TAG,String.format("handler msg, download %s",true) );
 | ||
|          }else if(msg.what==MSG_READCHAPTER_FAIL){
 | ||
|              try {
 | ||
|                  Toast.makeText(mContext, "网络拥堵,已帮您切换其它源", Toast.LENGTH_LONG).show();
 | ||
|              }catch (Exception e){
 | ||
|                  Log.e(TAG, "handlerMsg:toast error ", e);
 | ||
|              }
 | ||
|            //  getSiteRule();
 | ||
|                // pagefactory   .changeChapter(getChapterNo());
 | ||
| 
 | ||
| 
 | ||
|             String targetSiteName = msg.getData().getString("siteName");
 | ||
|              Log.d(TAG, String.format("prepare book changing Source:target %s -- %s to open chapter %s"
 | ||
|                      ,mNovel.getDomain(),targetSiteName,msg.arg1));
 | ||
|              if(pagefactory!=null)
 | ||
|              pagefactory.changeSource(targetSiteName, mNovel.getDomain(),msg.arg1,getChapter(msg.arg1).getChapterName());
 | ||
| 
 | ||
| 
 | ||
|              //  isDownloadChapt =true;
 | ||
|              // Toast.makeText(mContext,"网络错误",Toast.LENGTH_LONG).show();
 | ||
|          }else if(msg.what==MSG_READCHAPTER_SUCCESS){ //change source
 | ||
|              isChangeSource =false;
 | ||
|              Log.d(TAG, "prepare book changing Source:successed get chapters for " + mSite.getDomain() );
 | ||
|              /*if(isChangeSource){
 | ||
|                  Log.d(TAG, "changing Source:successed get chapters for " + mSite.getDomain() );
 | ||
|                  isChangeSource =false;
 | ||
|                  int chapId=chapterNo;
 | ||
|                  if( mChapters.size() >= mChangeChapId && mChapters.get(mChangeChapId-1)!=null ){
 | ||
|                      String title = mChapters.get(mChangeChapId-1).getChapterName();
 | ||
|                      Log.d(TAG, "changing Source:chapter name in new site " + title );
 | ||
|                      if(title.equals(mChangeTitle)) {
 | ||
|                          Log.d(TAG, "changing Source:successed find chapter by original chaptId  " + mChangeChapId + ":" + mChangeTitle);
 | ||
|                          chapId = mChangeChapId;
 | ||
|                      }
 | ||
|                  }else{
 | ||
|                      int i =1;
 | ||
|                      for (Chapter chapter : mChapters) {
 | ||
| 
 | ||
|                          if (chapter.getChapterName().equals(mChangeTitle)) {
 | ||
|                              Log.d(TAG, "changing Source:successed find chapter by original title  " +i + ":"+ mChangeTitle );
 | ||
|                              chapId = i;
 | ||
|                              break;
 | ||
|                          }
 | ||
|                          i++;
 | ||
|                      }
 | ||
|                  }
 | ||
|                  chapId = chapId <= mChapters.size() ? chapId: mChapters.size();
 | ||
|                  Log.d(TAG, "changing Source: to open chapter with new site source  "  + chapId + " : "+ mChangeTitle );
 | ||
|                  pagefactory.changeChapter(chapId);
 | ||
| 
 | ||
|              }
 | ||
|              */
 | ||
|          }
 | ||
|      }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|  private enum DownloadStatus{
 | ||
|      notStart,
 | ||
|      downloading,
 | ||
|      failure,
 | ||
|      success
 | ||
|  }
 | ||
| 
 | ||
|  public boolean isChapterContentExist(int index) {
 | ||
|      char[] block = null;
 | ||
|      if (chaptCache.containsKey(Integer.valueOf(index))) {
 | ||
|          block = chaptCache.get(index).getData().get();
 | ||
|      }
 | ||
|      if (block == null) {
 | ||
|          //       cleanCacheFile(); //to remove
 | ||
| 
 | ||
|              File file = new File(fileChapterName(index));
 | ||
| 
 | ||
|              if (!file.exists()) {
 | ||
| 
 | ||
|                  new Thread(){
 | ||
|                      @Override
 | ||
|                      public void run() {
 | ||
|                          try {
 | ||
|                              loadChaptContent(index);
 | ||
|                          } catch (JSONException e) {
 | ||
|                              e.printStackTrace();
 | ||
|                          } catch (InterruptedException e) {
 | ||
|                              e.printStackTrace();
 | ||
|                          }
 | ||
| 
 | ||
|                      }
 | ||
|                  }.start();
 | ||
|                  return  false;
 | ||
|              }
 | ||
| 
 | ||
|      }
 | ||
| 
 | ||
|      return  true;
 | ||
|  }
 | ||
| 
 | ||
|     List<Integer> caprint = new ArrayList<Integer>();
 | ||
| 
 | ||
|     //获取chapter 缓存
 | ||
|     public char[] chaptChars(final int index) {
 | ||
|       //  Log.d(TAG, String.format("prepare book  begin to load content for chapter %s ------------------------------------------------------------------------->", index));
 | ||
|         char[] block=null;
 | ||
|         if(chaptCache.containsKey(Integer.valueOf(index))) {
 | ||
|             block = chaptCache .get(index).getData().get();
 | ||
|          //   Log.d(TAG, String.format("chaptChars  get block in cache, chapter: %s", index));
 | ||
| 
 | ||
|             if(!caprint.contains(index)) {
 | ||
|                 caprint.add(index);
 | ||
|              //   Log.d(TAG, String.format("chaptChars: load from cache chaptId %s,--->%s", index, new String(block)));
 | ||
|             }
 | ||
|         }
 | ||
|       //  Log.d(TAG, String.format("prepare book  begin to load content for chapter %s", index));
 | ||
|         if (block == null) {
 | ||
|      //       cleanCacheFile(); //to remove
 | ||
|             try {
 | ||
|                 File file = new File(fileChapterName(index));
 | ||
|                 Log.d(TAG, String.format("prepare book  begin to load content for chapter %s,file exists?%s", index,file.exists()));
 | ||
|                 if ( !file.exists()) {
 | ||
|                     if(getNovel().isLocalBook()){
 | ||
|                         return  "".toCharArray();
 | ||
|                     }
 | ||
|                     Log.d(TAG, String.format("prepare book loadChapts----  %s, 目录数量 %s, MuluStatus %s , mChapters.size() %s,    thread %s", mNovel.getName(), mChapters.size(), mMuluStatus
 | ||
|                             , mChapters.size()
 | ||
|                             , Thread.currentThread().getName()));
 | ||
| 
 | ||
|                     if (mMuluStatus == null) {
 | ||
|                         Log.e(TAG, String.format("prepare book loadChapts---- 还未有目录信息,出错了 %s  目录, 目录数量 %s, MuluStatus %s ,thread %s", mNovel.getName(), mChapters.size(), mMuluStatus, Thread.currentThread().getName()));
 | ||
|                             getTargetSites();
 | ||
|                     }
 | ||
|                     if( mChapters.size() ==0) {
 | ||
|                         if (mMuluStatus != MuluStatus.isDownloading){
 | ||
|                             getSiteRule();
 | ||
|                         }
 | ||
|                     }
 | ||
|                     int slept = 0;
 | ||
|                     while (NetUtil.isNetworkConnected() && slept < 50 &&(mMuluStatus ==null || mMuluStatus == MuluStatus.isDownloading)) {
 | ||
|                         try {
 | ||
|                             Thread.sleep(50);
 | ||
|                             slept++;
 | ||
|                             Log.d(TAG, String.format("prepare book loadChapts----等待中 %s  目录, 目录数量 %s, slept %s, MuluStatus %s", mNovel.getName(), mChapters.size(), slept, mMuluStatus));
 | ||
| 
 | ||
|                         } catch (InterruptedException e) {
 | ||
|                             e.printStackTrace();
 | ||
|                         }
 | ||
|                     }
 | ||
| 
 | ||
|                     if (!NetUtil.isNetworkConnected() || muluRetryCount >= Constants.retryCnt && (mChapters == null || mChapters.size() == 0)) {
 | ||
|                         Log.d(TAG, String.format("prepare book loadChapts----超时。。。或出错了 %s  目录, 目录数量 %s, slept %s, MuluStatus %s,thread %s", mNovel.getName(), mChapters.size(), slept, mMuluStatus, Thread.currentThread().getName()));
 | ||
|                         String error = "网络不给力";
 | ||
|                         return error.toCharArray();
 | ||
|                     }
 | ||
| 
 | ||
|                     Log.d(TAG, String.format("prepare book loadChaptContent----start %s", new Date().toString()));
 | ||
|                     Log.d(TAG, String.format("prepare book chaptDownStatus.containsKey %s ? %s", Integer.valueOf(index),chaptDownStatus.containsKey(Integer.valueOf(index))));
 | ||
| 
 | ||
| 
 | ||
|                     if (!chaptDownStatus.containsKey(Integer.valueOf(index))) {
 | ||
|                         chaptDownStatus.put(index, DownloadStatus.downloading);
 | ||
|                         Log.d(TAG, String.format("prepare book put chaptDownStatus index %s,start to load chapcontent", index));
 | ||
|                         loadChaptContent(index);
 | ||
|                     }else{
 | ||
|                         Log.d(TAG, String.format("prepare book chaptDownStatus for chapt %s status %s", Integer.valueOf(index),chaptDownStatus.get(Integer.valueOf(index))));
 | ||
|                     }
 | ||
|                     Log.d(TAG, String.format(" prepare book  loadChaptContent %s  for downloading, chaptDownStatus %s, thread %s  ",
 | ||
|                             index, chaptDownStatus.get(Integer.valueOf(index)), Thread.currentThread().getName()));
 | ||
| 
 | ||
| 
 | ||
|                     int maxSleep = 2500;
 | ||
|                     int slepttime = 0;
 | ||
|                     //  while(!file.exists() && !getDownloadStatus()){//&& slepttime <maxSleep){
 | ||
|                     //   while( !getDownloadStatus()  && slepttime <maxSleep){
 | ||
| 
 | ||
|                /*     while (NetUtil.isNetworkConnected() && !getDownloadStatus() && chaptDownStatus.get(Integer.valueOf(index)) == DownloadStatus.downloading && slepttime < maxSleep) {
 | ||
|                         Thread.sleep(50);
 | ||
|                         slepttime += 50;
 | ||
|                         Log.d(TAG, String.format(" prepare book  loadChaptContent slept %s for downloading,isDownload %s ,thread %s  ", slepttime, getDownloadStatus(), Thread.currentThread().getName()));
 | ||
|                     }*/
 | ||
|                     while (!file.exists() && NetUtil.isNetworkConnected() && chaptDownStatus.get(Integer.valueOf(index)) == DownloadStatus.downloading && slepttime < maxSleep) {
 | ||
|                         Thread.sleep(50);
 | ||
|                         slepttime += 50;
 | ||
|                         Log.d(TAG, String.format(" prepare book  loadChaptContent %s , slept %s for downloading, thread %s  ",index, slepttime,   Thread.currentThread().getName()));
 | ||
|                     }
 | ||
|                     Log.d(TAG, String.format("prepare book loadChaptContent slept %s for downloading  ", slepttime));
 | ||
| 
 | ||
|                     if (chaptDownStatus.get(Integer.valueOf(index)) == DownloadStatus.failure) {
 | ||
|                         if (fileRetryCnt.containsKey(index)) {
 | ||
|                             fileRetryCnt.put(index, fileRetryCnt.get(index) + 1);
 | ||
|                         } else {
 | ||
|                             fileRetryCnt.put(index, 1);
 | ||
|                         }
 | ||
|                         Log.d(TAG, String.format("prepare book loadChaptContent %s, rertying count %s  ",index, fileRetryCnt.get(index)));
 | ||
|                         if (fileRetryCnt.get(index) < Constants.retryCnt) {
 | ||
|                             Log.d(TAG, String.format("prepare book loadChaptContent ,rertying to download chapt %s  ", index));
 | ||
| 
 | ||
|                             loadChaptContent(index);
 | ||
|                             if(mSiteRule!=null) {
 | ||
|                                 Thread.sleep(mSiteRule.getMiniInterval4AccessChapter());
 | ||
|                             }
 | ||
|                         }
 | ||
|                     }
 | ||
|                 }
 | ||
| 
 | ||
|                 Log.d(TAG, String.format(" prepare book %s, file.exists()? %s", file.getPath(), file.exists()));
 | ||
|                 if (!file.exists()) {
 | ||
|                     String error = "下载内容失败";
 | ||
|                     if(  !NetUtil.isNetworkConnected()){
 | ||
|                         error = "连不上网络";
 | ||
| 
 | ||
|                     }
 | ||
|                    // loadChaptContent(index);
 | ||
|                     chaptDownStatus.put( index , DownloadStatus.failure);
 | ||
| 
 | ||
|                     Log.d(TAG, String.format("prepare book loadChaptContent retrying     " ));
 | ||
|                //  return    chaptChars( index);
 | ||
| 
 | ||
| 
 | ||
|                     return error.toCharArray();
 | ||
|                 }
 | ||
|                 if( Constants.PRE_LOAD_CHAPT) {
 | ||
| 
 | ||
| 
 | ||
|                     if (mChapters.size() > index && NetUtil.isNetworkConnected()) {
 | ||
| 
 | ||
|                         if (!chaptDownStatus.containsKey(index + 1) || chaptDownStatus.get(index + 1).equals(DownloadStatus.failure)) {
 | ||
| 
 | ||
| 
 | ||
|                             File file2 = new File(fileChapterName(index + 1));
 | ||
| 
 | ||
|                             if (!file2.exists()) {
 | ||
|                                 Log.d(TAG, String.format(" prepare book to load next chapt %s,down status %s ", index + 1, chaptDownStatus.get(index + 1)));
 | ||
|                                 chaptDownStatus.put(index + 1, DownloadStatus.downloading);
 | ||
|                                 loadChaptContent(index + 1);
 | ||
|                             }
 | ||
|                         }
 | ||
|                     }
 | ||
|                     if (index > 1 && index - 1 < mChapters.size() && NetUtil.isNetworkConnected()) {
 | ||
| 
 | ||
|                         if (!chaptDownStatus.containsKey(index - 1) || chaptDownStatus.get(index - 1).equals(DownloadStatus.failure)) {
 | ||
|                             File file2 = new File(fileChapterName(index - 1));
 | ||
| 
 | ||
|                             if (!file2.exists()) {
 | ||
|                                 Log.d(TAG, String.format(" prepare book to load pre chapt %s,down status  %s ", index - 1, chaptDownStatus.get(index - 1)));
 | ||
|                                 chaptDownStatus.put(index - 1, DownloadStatus.downloading);
 | ||
|                                 loadChaptContent(index - 1);
 | ||
|                             }
 | ||
| 
 | ||
|                         }
 | ||
|                     }
 | ||
|                 }
 | ||
|              //   mChangeChapId =0;
 | ||
|                 int size = (int) file.length();
 | ||
|                 if (size < 0) {
 | ||
|                     Log.e(TAG, "prepare book chaptChars: Error during reading"+ fileChapterName(index) );
 | ||
|                    // throw new RuntimeException("Error during reading " + fileChapterName(index));
 | ||
|                 }
 | ||
|                 block = new char[size / 2];
 | ||
|                 InputStreamReader reader = null;
 | ||
|                 try {
 | ||
|                     reader =
 | ||
|                             new InputStreamReader(
 | ||
|                                     new FileInputStream(file),
 | ||
|                                     charachterType
 | ||
|                                   //  mSiteRule.getEncoding()
 | ||
|                             );
 | ||
| 
 | ||
|                     long l = reader.read(block);
 | ||
| 
 | ||
|                   //  Log.d(TAG, String.format("loadchapt: load from file chaptId %s,--->%s",index,  new String(block )));
 | ||
|                    /* for (char c :block
 | ||
|                          ) {
 | ||
|                         Log.d(TAG, String.valueOf(c));
 | ||
|                     }*/
 | ||
|                     if (reader.read(block) != block.length) {
 | ||
|                         //   throw new RuntimeException("Error during reading " + fileChapterName(index));
 | ||
|                     }
 | ||
|                 } catch (IOException e) {
 | ||
|                     e.printStackTrace();
 | ||
|                 } finally {
 | ||
|                     if (reader != null) {
 | ||
|                         reader.close();
 | ||
|                     }
 | ||
|                 }
 | ||
| 
 | ||
|             } catch (JSONException | IOException e) {
 | ||
|                 e.printStackTrace();
 | ||
|             } catch (InterruptedException e) {
 | ||
|                 e.printStackTrace();
 | ||
|             }
 | ||
|             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));
 | ||
|             Log.d(TAG, String.format("prepare book content reading finish, chapter %s", index));
 | ||
|         }
 | ||
|         return block;
 | ||
|     }
 | ||
| 
 | ||
|     Map<Integer,Integer> fileRetryCnt = new HashMap<Integer,Integer>();
 | ||
| private void loadChaptContent(final int chapterIndex) throws JSONException, InterruptedException {
 | ||
|          /* 章节内容没有缓存在本地
 | ||
|                         1. 根据本地的章节网络地址信息,读取章节内容到本地,若读取失败则
 | ||
|                         2. 查询主服务器,若有地址更新则更新本地信息,并重复1,若没有更新地址,则地址无效,返回章节内容正待手打
 | ||
|                     */
 | ||
|     //
 | ||
|     if(!NetUtil.isNetworkConnected() || mChapters.size()==0||mSite ==null){
 | ||
|         handler.sendEmptyMessage(1);
 | ||
|         return ;
 | ||
|     }
 | ||
| 
 | ||
|     final int index = mChapters.size() < chapterIndex ? 1 : chapterIndex;
 | ||
|     if(mChapters.size() <chapterIndex){
 | ||
|         Log.d(TAG,String.format("loadChaptContent----wrong index, chapter size %s,load index %s,bookname %s",   mChapters.size(),index,mNovel.getName()   ));
 | ||
| 
 | ||
|     }
 | ||
|     Chapter chapter = mChapters.get(index -1);
 | ||
|     String refUrl=mSite.getMuluUrl();
 | ||
|     if(index>1){
 | ||
|         refUrl = mChapters.get(index -2).getChapterUrl();
 | ||
|     }
 | ||
|     String url = chapter.getChapterUrl();
 | ||
|     if( TextUtils.isEmpty( url)){
 | ||
|         handler.sendEmptyMessage(1);
 | ||
|         return ;
 | ||
|     }
 | ||
|     long startTime= new Date().getTime();
 | ||
|     Log.d(TAG,String.format("prepare book loadChaptContent----start download %s from %s",   chapter.getChapterName()  ,url ));
 | ||
| 
 | ||
|   //  setDownloadFlag(false);
 | ||
| 
 | ||
| 
 | ||
|     JSONObject siteJson = new JSONObject();
 | ||
|     siteJson.put("chapterContentRegex", mSiteRule.getChapterContentRegex());
 | ||
|     siteJson.put("chapterContentDumpRegex", mSiteRule.getChapterContentDumpRegex());
 | ||
|     Request request = getTagRequest(url, refUrl,-1);
 | ||
|     HttpMethods.getOkClient().newCall(request).enqueue(new Callback() {
 | ||
|         @Override
 | ||
|         public void onFailure(Call call, IOException e) {
 | ||
|            /* if(e.toString().contains("closed") ||e.getMessage().contains("Canceled"))
 | ||
|             {
 | ||
|                // return;
 | ||
|             }*/
 | ||
| 
 | ||
|          //   handler.sendEmptyMessage(MSG_FILLCONTENTDONE);
 | ||
|         //    handler.sendEmptyMessage(1);
 | ||
| 
 | ||
| 
 | ||
|             chaptDownStatus.put(index,DownloadStatus.failure);
 | ||
|           //  setDownloadFlag(true);
 | ||
|             Log.d( TAG,String.format("prepare book loadChaptContent %s fail, isDownloadChapt: %s",index,false));
 | ||
|            // 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, "prepare book loadChaptContent----network failure returnCode " + response.code());
 | ||
|                  //   setDownloadFlag(true);
 | ||
|                     chaptDownStatus.put(index,DownloadStatus.failure);
 | ||
|                     Log.d( TAG,String.format("prepare book loadChaptContent error %s ,isDownloadChapt: %s",  response.code(),false));
 | ||
|                    handler.sendEmptyMessage(1);
 | ||
|                     return;
 | ||
|                 }
 | ||
| 
 | ||
|                 try {
 | ||
| 
 | ||
|                     if(mSiteRule==null){
 | ||
|                         return;
 | ||
|                     }
 | ||
|                  /* Charset charset = body.contentType().charset();
 | ||
|                   if(charset!=null){
 | ||
|                       String name = charset.displayName();
 | ||
|                   }*/
 | ||
|                   //  String bodyStr = body.string();
 | ||
|                    // bodyStr =NovelParseUtil.enconding(bodyStr,mSiteRule.getEncoding());
 | ||
|                     String   bodyStr =NovelParseUtil.enconding(body,mSiteRule.getEncoding());
 | ||
|                   if(TextUtils.isEmpty(bodyStr)){
 | ||
|                       Log.d( TAG,String.format("prepare book  loadChaptContent %s isEmpty,retry....", index,   Thread.currentThread().getName()));
 | ||
|                       chaptDownStatus.put(index,DownloadStatus.failure);
 | ||
|                       return;
 | ||
|                   }
 | ||
|                     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 文件小
 | ||
|                   //  final OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(fileChapterName(index)), mSiteRule.getEncoding()  );//charachterType);//"UTF-16LE"); // UTF-16LE 比 utf-8 文件小
 | ||
|                     writer.write(buf);
 | ||
|                     writer.close();
 | ||
|                     Log.d( TAG,String.format("prepare book  loadChaptContent file created:  %s, thread %s",  file.getPath(), Thread.currentThread().getName()));
 | ||
|                     handler.sendEmptyMessage(MSG_FILLCONTENTDONE);
 | ||
|                   //  setDownloadFlag(true);
 | ||
|                 } catch (IOException | JSONException e) {
 | ||
|                     e.printStackTrace();
 | ||
|                     Log.e(TAG, "onResponse: prepare book error ",e );
 | ||
|                     chaptDownStatus.put(index,DownloadStatus.failure);
 | ||
|                     return;
 | ||
|                    // throw new RuntimeException("Error during writing " + fileChapterName( index));
 | ||
|                 }
 | ||
|                 finally {
 | ||
|                     body.close();
 | ||
| 
 | ||
|                     handler.sendEmptyMessage(MSG_FILLCONTENTDONE);
 | ||
|                     // setDownloadFlag(true);
 | ||
|                 }
 | ||
|                 chapter.setNovelId(mNovel.getId());
 | ||
|                 chapter.setChapterPath(fileChapterName(index));
 | ||
|                 chapter.setDomain(mSite.getDomain());
 | ||
|                if(chapter.getId()>0) {
 | ||
|                   chapter.update(chapter.getId());
 | ||
|                }else{
 | ||
|                    chapter.save();
 | ||
|                }
 | ||
|                 //setDownloadFlag(true);
 | ||
|                 chaptDownStatus.put(index,DownloadStatus.success);
 | ||
|                Log.d(TAG,String.format(" prepare book loadChaptContent---- finished download %s, cost time %s ,content path %s ,thread %s",  chapter.getChapterName(),  new Date().getTime() -startTime ,chapter.getChapterPath() , Thread.currentThread().getName()  ));
 | ||
| 
 | ||
|             }
 | ||
|         }
 | ||
|     });
 | ||
| 
 | ||
| 
 | ||
| }
 | ||
| 
 | ||
|     /***
 | ||
|      *
 | ||
|      * @param url
 | ||
|      * @param maxAge
 | ||
|      * @return
 | ||
|      */
 | ||
|     private Request getTagRequest(String url, String refUrl ,int maxAge) {
 | ||
| 
 | ||
|         Request.Builder builder = new Request.Builder()
 | ||
|                 .tag(mNovel.getNovelId()) //标记 请求的tag,切换小说或离开小说界面(BookActivity) 时 取消未执行完毕的 此tag的所有请求
 | ||
|                 .url(url)
 | ||
|                 .removeHeader("Pragma");
 | ||
| 
 | ||
|         if(!TextUtils.isEmpty(refUrl)){
 | ||
|             builder.header("Referer",refUrl);
 | ||
|         }
 | ||
| 
 | ||
|         for (int i = 0; i < mSiteRule.getHeaders().length; i += 2) {
 | ||
|             builder.header(mSiteRule.getHeaders()[i], mSiteRule.getHeaders()[i + 1]);
 | ||
| 
 | ||
|         }
 | ||
| 
 | ||
|         if(mSiteRule.getUserAgents()!=null && mSiteRule.getUserAgents().length>0){
 | ||
|             String siteAgent =mSiteRule.getUserAgents()[new Random().nextInt( mSiteRule.getUserAgents().length-1)];
 | ||
| 
 | ||
|             Log.d(TAG, "prepare book on getTagRequest:add site user agent " + siteAgent);
 | ||
|             builder.removeHeader("User-Agent").addHeader("User-Agent",siteAgent ); //加 随机agent
 | ||
| 
 | ||
|         }else{
 | ||
|             builder.removeHeader("User-Agent").addHeader("User-Agent",  HttpMethods.USERAGENT);
 | ||
|         }
 | ||
| 
 | ||
| //                .header( "Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8")
 | ||
| //                .header( "Upgrade-Insecure-Requests", "1")
 | ||
|         //   .header("content-type", "text/html; charset=utf-8")
 | ||
|         //   .header("Content-Type", "text/plain; charset=utf-8")
 | ||
|         //   .header( "Accept", "*/*")
 | ||
|         ;
 | ||
|        /* if(mSiteRule!=null && !TextUtils.isEmpty(mSiteRule.getEncoding())  ){
 | ||
|             builder.header("Accept-Encoding",mSiteRule.getEncoding());
 | ||
|         }
 | ||
| */
 | ||
|         if (maxAge > 0) {
 | ||
|             builder.header("Cache-Control", "public, max-age=" + maxAge);
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|         return builder.build();
 | ||
| 
 | ||
|     }
 | ||
| 
 | ||
| 
 | ||
|     public boolean isChapterTitle(String line){
 | ||
|         return (line.length() <= 30 && (line.matches(".*第.{1,8}章.*") || line.matches(".*第.{1,8}节.*")))  ;
 | ||
|     }
 | ||
| 
 | ||
| 
 | ||
| }
 |