501 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
		
		
			
		
	
	
			501 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
|  | package com.novelbook.android.service; | ||
|  | 
 | ||
|  | import android.app.IntentService; | ||
|  | import android.content.Intent; | ||
|  | import android.os.Handler; | ||
|  | import android.os.Message; | ||
|  | import android.text.TextUtils; | ||
|  | import android.util.Log; | ||
|  | 
 | ||
|  | import com.novelbook.android.db.Chapter; | ||
|  | import com.novelbook.android.db.DownloadTask; | ||
|  | import com.novelbook.android.db.SiteRule; | ||
|  | import com.novelbook.android.netutils.HttpMethods; | ||
|  | import com.novelbook.android.utils.BookUtil; | ||
|  | import com.novelbook.android.utils.NovelParseUtil; | ||
|  | 
 | ||
|  | import org.json.JSONException; | ||
|  | import org.json.JSONObject; | ||
|  | import org.litepal.LitePal; | ||
|  | 
 | ||
|  | import java.io.File; | ||
|  | import java.io.FileOutputStream; | ||
|  | import java.io.IOException; | ||
|  | import java.io.OutputStreamWriter; | ||
|  | import java.util.ArrayList; | ||
|  | import java.util.Date; | ||
|  | import java.util.HashMap; | ||
|  | import java.util.List; | ||
|  | import java.util.Map; | ||
|  | import java.util.concurrent.ConcurrentHashMap; | ||
|  | 
 | ||
|  | import okhttp3.Call; | ||
|  | import okhttp3.Callback; | ||
|  | import okhttp3.Request; | ||
|  | import okhttp3.Response; | ||
|  | import okhttp3.ResponseBody; | ||
|  | 
 | ||
|  | 
 | ||
|  | public class ServiceDownloadIntent extends IntentService { | ||
|  |     private static final String TAG ="ServiceDownload" ; | ||
|  | 
 | ||
|  |     private   final String storagePath = BookUtil.storagePath; | ||
|  |     private   final String cachedPath = BookUtil.cachedPath; | ||
|  |     private   final String chapterPath = BookUtil.chapterPath; | ||
|  | 
 | ||
|  |     public final String EXTR_TASKID ="taskId"; | ||
|  |     public final String EXTR_OFFSET ="offset"; //多线程下载,每个线程取章节偏移数量 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  |    // public ServiceDownload(String name) { | ||
|  |   //      super(name); | ||
|  |   //  } | ||
|  |     public ServiceDownloadIntent() { | ||
|  |         super("ServiceDownload"); | ||
|  |     } | ||
|  | 
 | ||
|  |      private Map<Integer,SiteRule>  siteRuleMap = new HashMap<Integer,SiteRule>()  ;  // key = novelId | ||
|  |      private DownloadTask processingTask  ; | ||
|  |      private int taskIndex=0; | ||
|  |      private int chaptIndex=0; | ||
|  | 
 | ||
|  |     private Map<Integer ,List<Chapter>> tasksMap = new  ConcurrentHashMap<Integer, List<Chapter>>();// key = taskId | ||
|  | 
 | ||
|  |     @Override | ||
|  |     public void onCreate() { | ||
|  |         super.onCreate(); | ||
|  |         Log.d(TAG,"test service onCreate..."); | ||
|  | 
 | ||
|  |         /* | ||
|  |         downloadTasks =LitePal.where("status = ?","0").find(DownloadTask.class); | ||
|  |         for(DownloadTask dt :downloadTasks){ | ||
|  |             List<Chapter> chps =Chapter.getUnCachedChapters(dt.getNovelId(),dt.getDomain()); | ||
|  |             if(chps.size()>0) { | ||
|  |                 SiteRule sr = SiteRule.getSiteRuleByDomain(dt.getDomain()); | ||
|  |                 siteRuleMap.put(dt.getNovelId(), sr); | ||
|  |                 tasksMap.put(dt.getId(), chps); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         for(DownloadTask tmp: downloadTasks){ | ||
|  |             Log.d(TAG, String.format("test service task list : %s",tmp.getId())); | ||
|  |         } | ||
|  |         */ | ||
|  | 
 | ||
|  | 
 | ||
|  |     } | ||
|  |     @Override | ||
|  |     public void onStart(Intent intent, int startId) { | ||
|  |         super.onStart(intent, startId); | ||
|  |         Log.d(TAG,"test service onStart"); | ||
|  |     } | ||
|  | 
 | ||
|  |     @Override | ||
|  |     public int onStartCommand(Intent intent, int flags, int startId) { | ||
|  |         Log.d(TAG,"test service onStartCommand"); | ||
|  |         return super.onStartCommand(intent, flags, startId); | ||
|  | 
 | ||
|  |     } | ||
|  | 
 | ||
|  |     @Override | ||
|  |     public void onDestroy() { | ||
|  |         Log.d(TAG,"test service onDestroy"); | ||
|  |         super.onDestroy(); | ||
|  |     } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  |     private List<DownloadTask> downloadTasks = new ArrayList<DownloadTask>(); | ||
|  | 
 | ||
|  |     int cancelId =0; | ||
|  |     @Override | ||
|  |     protected void onHandleIntent( Intent intent) { | ||
|  |         Log.d(TAG,"test service onHandleIntent...begin"); | ||
|  | 
 | ||
|  |         String key ="taskId"; | ||
|  |         int taskId =0; | ||
|  | 
 | ||
|  |         if(intent.hasExtra(key)){ | ||
|  |             taskId=	intent.getExtras().getInt(key); | ||
|  |             DownloadTask dt = LitePal.find(DownloadTask.class,taskId); | ||
|  | 
 | ||
|  |             if(intent.hasExtra("start")){ | ||
|  |                 if(!intent.getBooleanExtra("start",true)){ | ||
|  |                     cancelId = taskId; | ||
|  |                     stopTask(taskId); | ||
|  |                 }else{ | ||
|  |                     startNewTask(dt); | ||
|  |                 } | ||
|  |             } | ||
|  | 
 | ||
|  | 
 | ||
|  |         } | ||
|  |         else{ | ||
|  |             if(downloadTasks.size()==0) { | ||
|  |                 List<DownloadTask> tmp = LitePal.findAll(DownloadTask.class); | ||
|  |                 taskIndex=0; | ||
|  |                 for(DownloadTask dt :tmp) { | ||
|  |                     startNewTask(dt); | ||
|  |                 } | ||
|  | 
 | ||
|  | 
 | ||
|  |             } | ||
|  | 
 | ||
|  | 
 | ||
|  |           /* | ||
|  |              if(processingTask==null) { | ||
|  |                 startTask(); | ||
|  |             }*/ | ||
|  |         } | ||
|  |         Log.d(TAG,"test service onHandleIntent...over"); | ||
|  |     } | ||
|  | 
 | ||
|  |     private void stopTask(int taskId) { | ||
|  |         for(DownloadTask dt : downloadTasks){ | ||
|  |             if(dt.getId() == taskId){ | ||
|  |                 dt.setDownSatus(DownloadTask.DownStatus.暂停下载); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         startTask(); | ||
|  |     } | ||
|  | 
 | ||
|  |     Handler handler = new Handler()  { | ||
|  |         @Override | ||
|  |         public void handleMessage(Message msg) { | ||
|  |             if(msg.what ==1){ | ||
|  |                 startTask(); | ||
|  |             }else if(msg.what==2){ | ||
|  | 
 | ||
|  |                 if( downloadTasks.get(taskIndex).getDownSatus() == DownloadTask.DownStatus.暂停下载){ | ||
|  |                     return; | ||
|  |                 } | ||
|  |                 if(tasksMap.get(processingTask.getId())==null){ | ||
|  |                     return; | ||
|  |                 } | ||
|  |                 Log.d(TAG,String.format("%s start new chapt download---- taskId :%s, chapter count %s,chaptIndex %s",TAG | ||
|  |                         , processingTask.getId(), | ||
|  |                         tasksMap.get(processingTask.getId()).size(),chaptIndex )); | ||
|  | 
 | ||
|  | 
 | ||
|  |                 Intent broadcastIntent = new Intent(); | ||
|  |                 broadcastIntent.setAction("ServiceDownload.ChapterContent.finished"); | ||
|  |                 broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT); | ||
|  |                 broadcastIntent.putExtra("progress", processingTask.getFinishedChpats()); | ||
|  |                 broadcastIntent.putExtra("novelId", processingTask.getNovelId()); | ||
|  |                 broadcastIntent.putExtra("taskId", processingTask.getId()); | ||
|  |                 sendBroadcast(broadcastIntent); | ||
|  | 
 | ||
|  | 
 | ||
|  |                 if( tasksMap.get(processingTask.getId()).size()-1 > chaptIndex){ | ||
|  | 
 | ||
|  |                     chaptIndex++; | ||
|  | 
 | ||
|  |                 }else{ | ||
|  |                     Log.d(TAG,String.format("%s task done ---- taskId :%s, chapter count %s,chaptIndex %s",TAG , processingTask.getId(), | ||
|  |                             tasksMap.get(processingTask.getId()).size(),chaptIndex )); | ||
|  |                       //章节全部处理完毕了 | ||
|  |                         processingTask.setStatus(1); | ||
|  |                         processingTask.update(processingTask.getId()); | ||
|  | 
 | ||
|  |                         tasksMap.remove(processingTask.getId()); //会不会线程冲突? | ||
|  | 
 | ||
|  |                         startTask(); | ||
|  |                 } | ||
|  | 
 | ||
|  |                 doDownloadContent(); | ||
|  |             } | ||
|  | 
 | ||
|  |         } | ||
|  | 
 | ||
|  |         }; | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  |     private void startTask() { | ||
|  | 
 | ||
|  |         if(processingTask!=null) { | ||
|  |             processingTask.update(processingTask.getId()); | ||
|  |         } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  |         if(downloadTasks.size() <=taskIndex){ | ||
|  |             processingTask =null; | ||
|  |             Log.d(TAG,"No task to download."); | ||
|  |             return; | ||
|  |         } | ||
|  | 
 | ||
|  |         processingTask =    downloadTasks.get(taskIndex); | ||
|  |         if(processingTask.getDownSatus()== DownloadTask.DownStatus.暂停下载){ | ||
|  |             taskIndex++; | ||
|  |             startTask(); | ||
|  |             return; | ||
|  |         } | ||
|  |         processingTask.setDownSatus(DownloadTask.DownStatus.正在下载); | ||
|  |         chaptIndex=0; | ||
|  |         doDownloadContent(); | ||
|  |         if(taskIndex < downloadTasks.size()-1){ | ||
|  |             taskIndex++; | ||
|  |         } | ||
|  | 
 | ||
|  |     } | ||
|  | 
 | ||
|  | 
 | ||
|  |     void doDownloadContent(){ | ||
|  | 
 | ||
|  |         Log.d(TAG, String.format("ServiceDowload--- taskId: %s ",processingTask.getId())); | ||
|  |         List<Chapter> chps = tasksMap.get(processingTask.getId()); | ||
|  |         if(chps!=null && chps.size()>0) { | ||
|  |             Chapter chapter = chps.get(chaptIndex); | ||
|  | 
 | ||
|  |             if (TextUtils.isEmpty(chapter.getChapterPath())) { | ||
|  |                 try { | ||
|  |                     ServiceDownload(chapter); | ||
|  |                 } catch (JSONException e) { | ||
|  |                     e.printStackTrace(); | ||
|  |                 } catch (InterruptedException e) { | ||
|  |                     e.printStackTrace(); | ||
|  |                // } catch (IOException e) { | ||
|  |               //      e.printStackTrace(); | ||
|  |                 } | ||
|  | 
 | ||
|  |             } else { | ||
|  |                 handler.sendEmptyMessage(2); | ||
|  |             } | ||
|  |         }else{ | ||
|  |             handler.sendEmptyMessage(2); | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |       void startNewTask(DownloadTask dt){ | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  |         if(dt!=null){ | ||
|  |             List<Chapter> chps = Chapter.getUnCachedChapters(dt.getId() ); | ||
|  |             if(chps==null || chps.size()==0){ | ||
|  |                 return; | ||
|  |             } | ||
|  |             SiteRule siteRule = SiteRule. getSiteRuleByDomain(dt.getDomain()); | ||
|  |             if(siteRule==null){ | ||
|  |                 //to do get siterule from web | ||
|  |                 Log.d(TAG, String.format("没找到site rule: %s",dt.getDomain())); | ||
|  |             }else { | ||
|  |                 siteRuleMap.put(dt.getNovelId(),siteRule); | ||
|  | 
 | ||
|  |                 downloadTasks.add(dt); | ||
|  | 
 | ||
|  |                 for(DownloadTask tmp: downloadTasks){ | ||
|  |                     Log.d(TAG, String.format("test service task list : %s",tmp.getId())); | ||
|  |                 } | ||
|  | 
 | ||
|  | 
 | ||
|  |                 tasksMap.put(dt.getId(), chps); | ||
|  |                 if(taskIndex==0) { | ||
|  |                     startTask(); | ||
|  |                   //  handler.sendEmptyMessage(1); | ||
|  |                 } | ||
|  |             } | ||
|  |         } | ||
|  |         /* | ||
|  |         new Thread() { | ||
|  | 
 | ||
|  |             @Override | ||
|  |             public void run() { | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  |             } | ||
|  |         }.start(); | ||
|  | 
 | ||
|  |         */ | ||
|  |     } | ||
|  |     private void ServiceDownload( Chapter chapter ) throws JSONException, InterruptedException { | ||
|  | 
 | ||
|  |         int msg =2; | ||
|  | 
 | ||
|  |         String url = chapter.getChapterUrl(); | ||
|  |         if( TextUtils.isEmpty( url)){ | ||
|  |             handler.sendEmptyMessage(msg); | ||
|  |             return ; | ||
|  |         } | ||
|  |         long startTime= new Date().getTime(); | ||
|  |         Log.d(TAG,String.format("ServiceDowload----start download %s from %s",   chapter.getChapterName()  ,url )); | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  |         //  Log.d( "ServiceDowload",String.format("ServiceDowload isDownloadChapt: %s",isDownloadChapt)); | ||
|  |         JSONObject siteJson = new JSONObject(); | ||
|  |         siteJson.put("chapterContentRegex", siteRuleMap.get(chapter.getNovelId()).getChapterContentRegex()); | ||
|  |         siteJson.put("chapterContentDumpRegex",  siteRuleMap.get(chapter.getNovelId()).getChapterContentDumpRegex()); | ||
|  |         Request request = getTagRequest(url); | ||
|  |         HttpMethods.getOkClient().newCall(request).enqueue(new Callback() { | ||
|  |             @Override | ||
|  |             public void onFailure(Call call, IOException e) { | ||
|  | 
 | ||
|  |                 handler.sendEmptyMessage(msg); | ||
|  | 
 | ||
|  |                 //  Log.d( "ServiceDowload",String.format("ServiceDowload 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, "ServiceDowload----network failure returnCode " + response.code()); | ||
|  |                         //  setDownloadFlag(true); | ||
|  |                         //  chaptDownStatus.put(index, BookUtil.DownloadStatus.failure); | ||
|  |                         //   Log.d( "ServiceDowload",String.format("ServiceDowload error %s ,isDownloadChapt: %s",  response.code(),isDownloadChapt)); | ||
|  |                         handler.sendEmptyMessage(msg); | ||
|  |                         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(chapter)); | ||
|  |                         file.createNewFile(); | ||
|  | 
 | ||
|  |                         final OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(fileChapterName(chapter)), "utf-8");//"UTF-16LE"); // UTF-16LE 比 utf-8 文件小 | ||
|  |                         writer.write(buf); | ||
|  |                         writer.close(); | ||
|  |                         Log.d( "ServiceDowload",String.format("ServiceDowload file created:  %s",  file.getPath())); | ||
|  |                         processingTask.setFinishedChpats(processingTask.getFinishedChpats()+1); | ||
|  |                         processingTask.update(processingTask.getId()); | ||
|  |                         Thread.sleep(siteRuleMap.get(chapter.getNovelId()).getMiniInterval4AccessChapter()); | ||
|  |                         //  setDownloadFlag(true); | ||
|  |                     } catch (IOException | JSONException | InterruptedException e) { | ||
|  |                         e.printStackTrace(); | ||
|  |                         //  throw new RuntimeException("Error during writing " + fileChapterName( index)); | ||
|  |                     } | ||
|  |                     finally { | ||
|  |                         body.close(); | ||
|  | 
 | ||
|  | 
 | ||
|  |                         //  setDownloadFlag(true); | ||
|  |                     } | ||
|  | 
 | ||
|  |                     chapter.setChapterPath(fileChapterName(chapter)); | ||
|  |                     chapter.update(chapter.getId()); | ||
|  |                     handler.sendEmptyMessage(msg); | ||
|  | 
 | ||
|  |                     //setDownloadFlag(true); | ||
|  |                     //   chaptDownStatus.put(index, BookUtil.DownloadStatus.success); | ||
|  |                     Log.d(TAG,String.format("ServiceDowload---- finished download %s, cost time %s ,content path %s ",  chapter.getChapterName(),  new Date().getTime() -startTime ,chapter.getChapterPath()   )); | ||
|  | 
 | ||
|  |                 } | ||
|  |             } | ||
|  |         }); | ||
|  | 
 | ||
|  | 
 | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * 直接 | ||
|  |      * @param chapter | ||
|  |      * @throws JSONException | ||
|  |      * @throws InterruptedException | ||
|  | 
 | ||
|  | 
 | ||
|  |     private void ServiceDownload2( Chapter chapter ) throws IOException, JSONException, InterruptedException { | ||
|  | 
 | ||
|  |         int msg = 2; | ||
|  | 
 | ||
|  |         String url = chapter.getChapterUrl(); | ||
|  |         if (TextUtils.isEmpty(url)) { | ||
|  |             handler.sendEmptyMessage(msg); | ||
|  |             return; | ||
|  |         } | ||
|  |         long startTime = new Date().getTime(); | ||
|  |         Log.d(TAG, String.format("ServiceDowload----start download %s from %s", chapter.getChapterName(), url)); | ||
|  | 
 | ||
|  | 
 | ||
|  |         //  Log.d( "ServiceDowload",String.format("ServiceDowload isDownloadChapt: %s",isDownloadChapt)); | ||
|  |         JSONObject siteJson = new JSONObject(); | ||
|  |         siteJson.put("chapterContentRegex", siteRuleMap.get(chapter.getNovelId()).getChapterContentRegex()); | ||
|  |         siteJson.put("chapterContentDumpRegex", siteRuleMap.get(chapter.getNovelId()).getChapterContentDumpRegex()); | ||
|  |         Request request = getTagRequest(url); | ||
|  |         Response response = HttpMethods.getOkClient().newCall(request).execute(); | ||
|  |         ResponseBody body = response.body(); | ||
|  |         if (body != null) { | ||
|  |             if (response.code() != 200) { | ||
|  |                 Log.d(TAG, "ServiceDowload----network failure returnCode " + response.code()); | ||
|  |                 //  setDownloadFlag(true); | ||
|  |                 //  chaptDownStatus.put(index, BookUtil.DownloadStatus.failure); | ||
|  |                 //   Log.d( "ServiceDowload",String.format("ServiceDowload error %s ,isDownloadChapt: %s",  response.code(),isDownloadChapt)); | ||
|  |                 handler.sendEmptyMessage(msg); | ||
|  |                 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(chapter)); | ||
|  |                 file.createNewFile(); | ||
|  | 
 | ||
|  |                 final OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(fileChapterName(chapter)), "utf-8");//"UTF-16LE"); // UTF-16LE 比 utf-8 文件小 | ||
|  |                 writer.write(buf); | ||
|  |                 writer.close(); | ||
|  |                 Log.d("ServiceDowload", String.format("ServiceDowload file created:  %s", file.getPath())); | ||
|  |                 processingTask.setFinishedChpats(processingTask.getFinishedChpats() + 1); | ||
|  |                 processingTask.update(processingTask.getId()); | ||
|  |                 Thread.sleep(siteRuleMap.get(chapter.getNovelId()).getMiniInterval4AccessChapter()); | ||
|  |                 //  setDownloadFlag(true); | ||
|  |             } catch (IOException | JSONException | InterruptedException e) { | ||
|  |                 e.printStackTrace(); | ||
|  |                 //  throw new RuntimeException("Error during writing " + fileChapterName( index)); | ||
|  |             } finally { | ||
|  |                 body.close(); | ||
|  | 
 | ||
|  | 
 | ||
|  |                 //  setDownloadFlag(true); | ||
|  |             } | ||
|  | 
 | ||
|  |             chapter.setChapterPath(fileChapterName(chapter)); | ||
|  |             chapter.update(chapter.getId()); | ||
|  |             handler.sendEmptyMessage(msg); | ||
|  | 
 | ||
|  |             //setDownloadFlag(true); | ||
|  |             //   chaptDownStatus.put(index, BookUtil.DownloadStatus.success); | ||
|  |             Log.d(TAG, String.format("ServiceDowload---- finished download %s, cost time %s ,content path %s ", chapter.getChapterName(), new Date().getTime() - startTime, chapter.getChapterPath())); | ||
|  | 
 | ||
|  |         } | ||
|  | 
 | ||
|  | 
 | ||
|  |     } | ||
|  | */ | ||
|  | 
 | ||
|  |     protected String fileChapterName(Chapter chapter ) { | ||
|  |             return  getChapterPath(chapter.getNovelId()) +chapter.getDomain()+"/"+ chapter.getIndex() ; | ||
|  | 
 | ||
|  |     } | ||
|  |     String getChapterPath(int novelId){ | ||
|  |         File file = new File(chapterPath +novelId); | ||
|  |         if(!file.exists()){ | ||
|  |             file.mkdir(); | ||
|  |         } | ||
|  |         return  chapterPath +novelId+"/"; | ||
|  |     } | ||
|  | 
 | ||
|  |     private Request getTagRequest(String url) { | ||
|  |         return new  Request.Builder() | ||
|  |                 .tag(processingTask.getNovelId()) //标记 | ||
|  |                 .url(url) | ||
|  |                 // .header("User-Agent", "OkHttp Example") | ||
|  |                 .build(); | ||
|  |     } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | } |