AndroidCatVodSpider/app/src/main/java/com/github/catvod/utils/DownloadService.java

169 lines
5.5 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.github.catvod.utils;
import com.github.catvod.crawler.SpiderDebug;
import com.github.catvod.net.OkHttp;
import okhttp3.Response;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;
public class DownloadService {
private static final int THREAD_NUM = 16;
//最小分片,按这个下载
private static final int PER_PIECE = 1024 * 1024;
//按照这个分割视频,每一个部分多线程下载,下载完下载下一个部分
private static final int PER_PART = 1024 * 1024 * THREAD_NUM;
private List<Future<Response>> results = new ArrayList<Future<Response>>();
private RandomAccessFile file = null;
private List<long[]> parts;
private AtomicInteger index = new AtomicInteger(0);
private static class Loader {
static volatile DownloadService INSTANCE = new DownloadService();
}
public static DownloadService get() {
return DownloadService.Loader.INSTANCE;
}
/**
* 下载链接
*/
private String url;
/**
* 下载信息
*/
private DownloadInfo downloadInfo;
public void submitDownload(String url, Map<String, String> headers, long length) {
if (url.equals(this.url)) {
SpiderDebug.log("url相同任务已存在");
} else {
this.url = url;
parts = generatePart(length);
downloadInfo = new DownloadInfo();
downloadInfo.setParts(parts);
downloadInfo.setUrl(url);
new Thread(new Runnable() {
@Override
public void run() {
ExecutorService service = Executors.newFixedThreadPool(THREAD_NUM);
for (long[] part : parts) {
String newRange = "bytes=" + part[0] + "-" + part[1];
SpiderDebug.log("下载开始" + ";newRange:" + newRange);
Map<String, String> headerNew = new HashMap<>(headers);
headerNew.put("range", newRange);
headerNew.put("Range", newRange);
Future<Response> result = service.submit(() -> {
try {
part[2] = 1;
return OkHttp.newCall(url, headerNew);
} catch (Exception e) {
throw new RuntimeException(e);
}
});
results.add(result);
}
try {
file = new RandomAccessFile(Path.tv() + File.separator + Util.MD5(url) + ".mp4", "rw");
} catch (FileNotFoundException e) {
SpiderDebug.log("创建文件失败");
throw new RuntimeException(e);
}
while (index.get() < results.size()) {
Response response = null;
try {
response = results.get(index.get()).get();
file.seek(parts.get(index.get())[0]);
file.write(response.body().bytes());
index.addAndGet(1);
} catch (ExecutionException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
service.shutdown();
}
}).start();
}
}
/**
* 返回信息
*
* @param start 开始
* @return
*/
public Object[] getDownloadBytes(long start) throws ExecutionException, InterruptedException {
long partIndex = start / PER_PART;
while (parts.get((int) partIndex)[2] == 0) {
index.set((int) partIndex);
}
try {
file.seek(start);
byte[] bytes = new byte[Math.toIntExact(parts.get((int) partIndex)[1] - start + 1)];
file.read(bytes);
return new Object[]{bytes,start,parts.get((int) partIndex)[1] };
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* 分割为需要下载的部分
*
* @param total 文件总大小
* @return
*/
private static List<long[]> generatePart(long total) {
SpiderDebug.log("generatePart.total:" + total);
long start = 0;
long end = total - 1;
//分割为多少个部分
long size = total / PER_PART;
SpiderDebug.log("generatePart.size:" + size);
List<long[]> partList = new ArrayList<>();
for (int i = 0; i < size * THREAD_NUM; i++) {
long partEnd = Math.min(start + PER_PIECE, end);
partList.add(new long[]{start, partEnd, 0});
start = partEnd + 1;
}
//最后多出分为一块下载
if (start <= end) {
partList.add(new long[]{start, end, 0});
}
return partList;
}
}