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 siteRuleMap = new HashMap() ; // key = novelId private DownloadTask processingTask ; private int taskIndex=0; private int chaptIndex=0; private Map> tasksMap = new ConcurrentHashMap>();// 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 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 downloadTasks = new ArrayList(); 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 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 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 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(); } }