package me.bello.viptv.util.down;
import android.content.Context;
import android.os.Build;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.concurrent.atomic.AtomicBoolean;
import me.bello.viptv.util.NotifyTool;
import me.bello.viptv.util.StringTool;
public class Mp4Downloader {
private Context mContext;
private AtomicBoolean canceled; // 取消状态,如果有一个子线程出现异常,则取消整个下载任务
private DownloadFile file; // 下载的文件对象
private String storageLocation;
private final int threadCount = 10; // 线程数量
private long fileSize; // 文件大小
private String title;
private String url;
private int notifyId;
private long beginTime; // 开始时间
private Logger logger;
private NotifyTool notifyTool;
public Mp4Downloader(Context context, String title, String url, int notifyId) {
this.mContext = context;
this.title = title;
this.url = url;
this.notifyId = notifyId;
notifyTool = new NotifyTool(mContext, notifyId);
}
public void start() {
this.canceled = new AtomicBoolean(false);
this.storageLocation = mContext.getExternalCacheDir() + "/mp4/";
File fd = new File(storageLocation);
if (!fd.exists()) {
fd.mkdirs();
}
storageLocation += title + ".mp4";
logger = new Logger(storageLocation + ".log", url, threadCount);
boolean reStart = false;
File f = new File(storageLocation + ".log");
if (f.exists() && f.length() > 0) {
reStart = true;
}
if (reStart) {
logger = new Logger(storageLocation + ".log");
System.out.printf("* 继续上次下载进度[已下载:%.2fMB]:%s\n", logger.getWroteSize() / 1014.0 / 1024, url);
} else {
System.out.println("* 开始下载:" + url);
notifyTool.sendNotify(title + " 开始下载", 0);
}
if (-1 == (this.fileSize = getFileSize())) {
System.out.println("获取下载文件信息异常,下载中断");
notifyTool.sendNotify(title + " 获取下载文件信息异常,下载中断", 0);
return;
}
System.out.printf("* 文件大小:%.2fMB\n", fileSize / 1024.0 / 1024);
this.beginTime = System.currentTimeMillis();
try {
this.file = new DownloadFile(storageLocation, fileSize, logger);
if (reStart) {
file.setWroteSize(logger.getWroteSize());
}
// 分配线程下载
dispatcher(reStart);
// 循环打印进度
printDownloadProgress();
} catch (IOException e) {
System.err.println("x 创建文件失败[" + e.getMessage() + "]");
notifyTool.sendNotify(title + " 创建文件失败", 0);
}
}
/**
* 分配器,决定每个线程下载哪个区间的数据
*/
private void dispatcher(boolean reStart) {
long blockSize = fileSize / threadCount; // 每个线程要下载的数据量
long lowerBound = 0, upperBound = 0;
long[][] bounds = null;
int threadID = 0;
if (reStart) {
bounds = logger.getBounds();
}
for (int i = 0; i < threadCount; i++) {
if (reStart) {
threadID = (int) (bounds[i][0]);
lowerBound = bounds[i][1];
upperBound = bounds[i][2];
} else {
threadID = i;
lowerBound = i * blockSize;
// fileSize-1
upperBound = (i == threadCount - 1) ? fileSize - 1 : lowerBound + blockSize;
}
new DownloadTask(url, lowerBound, upperBound, file, canceled, threadID).start();
}
}
/**
* 循环打印进度,直到下载完毕,或任务被取消
*/
private void printDownloadProgress() {
long downloadedSize = file.getWroteSize();
int i = 0;
long lastSize = 0; // 三秒前的下载量
while (!canceled.get() && downloadedSize < fileSize) {
if (i++ % 4 == 3) { // 每3秒打印一次
String percent = String.format("%.2f", downloadedSize / (double) fileSize * 100);
// System.out.printf("下载进度:%.2f%%, 已下载:%.2fMB,当前速度:%.2fMB/s\n",
// downloadedSize / (double)fileSize * 100 ,
// downloadedSize / 1024.0 / 1024,
// (downloadedSize - lastSize) / 1024.0 / 1024 / 3);
lastSize = downloadedSize;
i = 0;
StringTool.saveDownInfo(mContext, title, url, percent, notifyId);
notifyTool.sendNotify(title, new BigDecimal(percent).intValue());
}
try {
Thread.sleep(1000);
} catch (InterruptedException ignore) {
}
downloadedSize = file.getWroteSize();
}
file.close();
if (canceled.get()) {
try {
File f = new File(storageLocation);
f.delete();
// Files.delete(Paths.get(storageLocation));
} catch (Exception ignore) {
}
// System.err.println("x 下载失败,任务已取消");
notifyTool.sendNotify(title + " 下载失败,请检查网络", 0);
} else {
StringTool.saveDownInfo(mContext, title, url, "100", notifyId);
String pro = "[" + title + "] 下载成功,本次用时" + (System.currentTimeMillis() - beginTime) / 1000 + "秒";
notifyTool.sendNotify(title + " 下载完成", 100);
}
}
/**
* @return 要下载的文件的尺寸
*/
private long getFileSize() {
if (fileSize != 0) {
return fileSize;
}
HttpURLConnection conn = null;
try {
conn = (HttpURLConnection) new URL(url).openConnection();
conn.setConnectTimeout(5000);
conn.setRequestMethod("GET");
conn.connect();
System.out.println("* 连接服务器成功");
notifyTool.sendNotify(title + " 连接服务器成功", 0);
} catch (MalformedURLException e) {
throw new RuntimeException("URL错误");
} catch (IOException e) {
System.err.println("x 连接服务器失败[" + e.getMessage() + "]");
notifyTool.sendNotify(title + " 连接服务器失败", 0);
return -1;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
return conn.getContentLengthLong();
} else {
return conn.getContentLength();
}
}
}