Compare commits
11 Commits
3.7.4
...
3.7.8-pre-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c9c00c38c6 | ||
|
|
846235a826 | ||
|
|
06dd6b35e0 | ||
|
|
944d69a1af | ||
|
|
1ee36e0bc1 | ||
|
|
0765ab67f7 | ||
|
|
1b54bfc4ac | ||
|
|
846e6c0720 | ||
|
|
5ad485890c | ||
|
|
012f94511b | ||
|
|
e41d2f8578 |
26
.github/ISSUE_TEMPLATE/Custom.md
vendored
26
.github/ISSUE_TEMPLATE/Custom.md
vendored
@@ -4,14 +4,32 @@ about: 请详细描述你遇到的问题
|
||||
|
||||
---
|
||||
|
||||
## Aria版本
|
||||
<!-- 请详细描述以下信息,即使是一个简单的bug,没有充足的信息,作者却需要花费大量的时间去查找可能的原因!! -->
|
||||
|
||||
## 预期行为
|
||||
|
||||
|
||||
## 什么问题
|
||||
## 当前行为
|
||||
|
||||
|
||||
## 如何复现此问题
|
||||
## 可能的解决方案
|
||||
<!-- 不是强制性的,针对该错误的修复/原因的建议-->
|
||||
|
||||
|
||||
## 控制台日志
|
||||
## 重现步骤
|
||||
<!-- 请提供明确的步骤 -->
|
||||
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
4.
|
||||
|
||||
|
||||
## 错误日志
|
||||
|
||||
|
||||
## 版本
|
||||
* 框架版本
|
||||
|
||||
* 系统版本
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ public class CommandManager {
|
||||
EventMsgUtil.getDefault().register(this);
|
||||
}
|
||||
|
||||
public static CommandManager init() {
|
||||
public static void init() {
|
||||
if (instance == null) {
|
||||
synchronized (CommandManager.class) {
|
||||
if (instance == null) {
|
||||
@@ -38,7 +38,6 @@ public class CommandManager {
|
||||
}
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Event
|
||||
@@ -51,9 +50,6 @@ public class CommandManager {
|
||||
|
||||
@Event
|
||||
public void start(StartCmd cmd) {
|
||||
if (CommonUtil.isFastDoubleClick()) {
|
||||
return;
|
||||
}
|
||||
cmd.executeCmd();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.arialyy.aria.core.command;
|
||||
|
||||
import com.arialyy.aria.core.AriaManager;
|
||||
import com.arialyy.aria.core.download.DGTaskWrapper;
|
||||
import com.arialyy.aria.core.download.DTaskWrapper;
|
||||
import com.arialyy.aria.core.download.DownloadEntity;
|
||||
import com.arialyy.aria.core.download.DownloadGroupEntity;
|
||||
import com.arialyy.aria.core.common.AbsEntity;
|
||||
import com.arialyy.aria.core.task.AbsTask;
|
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
import com.arialyy.aria.core.inf.IEntity;
|
||||
import com.arialyy.aria.core.manager.TaskWrapperManager;
|
||||
import com.arialyy.aria.core.queue.DGroupTaskQueue;
|
||||
import com.arialyy.aria.core.queue.DTaskQueue;
|
||||
import com.arialyy.aria.core.queue.UTaskQueue;
|
||||
import com.arialyy.aria.core.upload.UTaskWrapper;
|
||||
import com.arialyy.aria.core.upload.UploadEntity;
|
||||
import com.arialyy.aria.orm.DbEntity;
|
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.NetUtils;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by AriaL on 2017/6/13.
|
||||
@@ -30,7 +30,6 @@ import java.util.List;
|
||||
* 4.恢复下载的任务规则是,停止时间越晚的任务启动越早,按照DESC来进行排序
|
||||
*/
|
||||
final class ResumeAllCmd<T extends AbsTaskWrapper> extends AbsNormalCmd<T> {
|
||||
private List<AbsTaskWrapper> mWaitList = new ArrayList<>();
|
||||
|
||||
ResumeAllCmd(T entity, int taskType) {
|
||||
super(entity, taskType);
|
||||
@@ -41,94 +40,7 @@ final class ResumeAllCmd<T extends AbsTaskWrapper> extends AbsNormalCmd<T> {
|
||||
ALog.w(TAG, "恢复任务失败,网络未连接");
|
||||
return;
|
||||
}
|
||||
if (isDownloadCmd) {
|
||||
findTaskData(1);
|
||||
findTaskData(2);
|
||||
} else {
|
||||
findTaskData(3);
|
||||
}
|
||||
resumeWaitTask();
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找数据库中的所有任务数据
|
||||
*
|
||||
* @param type {@code 1}单任务下载任务;{@code 2}任务组下载任务;{@code 3} 单任务上传任务
|
||||
*/
|
||||
private void findTaskData(int type) {
|
||||
if (type == 1) {
|
||||
List<DownloadEntity> entities =
|
||||
DbEntity.findDatas(DownloadEntity.class,
|
||||
"isGroupChild=? AND state!=? ORDER BY stopTime DESC", "false", "1");
|
||||
if (entities != null && !entities.isEmpty()) {
|
||||
for (DownloadEntity entity : entities) {
|
||||
addResumeEntity(TaskWrapperManager.getInstance()
|
||||
.getNormalTaskWrapper(DTaskWrapper.class, entity.getId()));
|
||||
}
|
||||
}
|
||||
} else if (type == 2) {
|
||||
List<DownloadGroupEntity> entities =
|
||||
DbEntity.findDatas(DownloadGroupEntity.class, "state!=? ORDER BY stopTime DESC", "1");
|
||||
if (entities != null && !entities.isEmpty()) {
|
||||
for (DownloadGroupEntity entity : entities) {
|
||||
addResumeEntity(
|
||||
TaskWrapperManager.getInstance()
|
||||
.getGroupWrapper(DGTaskWrapper.class, entity.getId()));
|
||||
}
|
||||
}
|
||||
} else if (type == 3) {
|
||||
List<UploadEntity> entities =
|
||||
DbEntity.findDatas(UploadEntity.class, "state!=? ORDER BY stopTime DESC", "1");
|
||||
if (entities != null && !entities.isEmpty()) {
|
||||
for (UploadEntity entity : entities) {
|
||||
addResumeEntity(TaskWrapperManager.getInstance()
|
||||
.getNormalTaskWrapper(UTaskWrapper.class, entity.getId()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加恢复实体
|
||||
*/
|
||||
private void addResumeEntity(AbsTaskWrapper te) {
|
||||
if (te == null || te.getEntity() == null) {
|
||||
return;
|
||||
}
|
||||
if (!mQueue.taskExists(te.getKey())) {
|
||||
mWaitList.add(te);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理等待状态的任务
|
||||
*/
|
||||
private void resumeWaitTask() {
|
||||
int maxTaskNum = mQueue.getMaxTaskNum();
|
||||
if (mWaitList == null || mWaitList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
List<AbsEntity> resumeEntities = new ArrayList<>();
|
||||
|
||||
for (AbsTaskWrapper te : mWaitList) {
|
||||
if (te instanceof DTaskWrapper) {
|
||||
mQueue = DTaskQueue.getInstance();
|
||||
} else if (te instanceof UTaskWrapper) {
|
||||
mQueue = UTaskQueue.getInstance();
|
||||
} else if (te instanceof DGTaskWrapper) {
|
||||
mQueue = DGroupTaskQueue.getInstance();
|
||||
}
|
||||
if (mQueue.getCurrentExePoolNum() < maxTaskNum) {
|
||||
startTask(createTask(te));
|
||||
} else {
|
||||
te.getEntity().setState(IEntity.STATE_WAIT);
|
||||
AbsTask task = createTask(te);
|
||||
sendWaitState(task);
|
||||
resumeEntities.add(te.getEntity());
|
||||
}
|
||||
}
|
||||
if (!resumeEntities.isEmpty()) {
|
||||
DbEntity.updateManyData(resumeEntities);
|
||||
}
|
||||
new Thread(new ResumeThread(isDownloadCmd,
|
||||
String.format("state!=%s", IEntity.STATE_COMPLETE))).start();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.arialyy.aria.core.command;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import com.arialyy.aria.core.common.AbsEntity;
|
||||
import com.arialyy.aria.core.download.DGTaskWrapper;
|
||||
import com.arialyy.aria.core.download.DTaskWrapper;
|
||||
import com.arialyy.aria.core.download.DownloadEntity;
|
||||
import com.arialyy.aria.core.download.DownloadGroupEntity;
|
||||
import com.arialyy.aria.core.inf.IEntity;
|
||||
import com.arialyy.aria.core.inf.IOptionConstant;
|
||||
import com.arialyy.aria.core.listener.ISchedulers;
|
||||
import com.arialyy.aria.core.manager.TaskWrapperManager;
|
||||
import com.arialyy.aria.core.queue.AbsTaskQueue;
|
||||
import com.arialyy.aria.core.queue.DGroupTaskQueue;
|
||||
import com.arialyy.aria.core.queue.DTaskQueue;
|
||||
import com.arialyy.aria.core.queue.UTaskQueue;
|
||||
import com.arialyy.aria.core.task.AbsTask;
|
||||
import com.arialyy.aria.core.upload.UTaskWrapper;
|
||||
import com.arialyy.aria.core.upload.UploadEntity;
|
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
import com.arialyy.aria.core.wrapper.ITaskWrapper;
|
||||
import com.arialyy.aria.orm.DbEntity;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 恢复任务工具
|
||||
*/
|
||||
public class ResumeThread implements Runnable {
|
||||
private String TAG = CommonUtil.getClassName(getClass());
|
||||
private List<AbsTaskWrapper> mWaitList = new ArrayList<>();
|
||||
private boolean isDownloadCmd;
|
||||
private String sqlCondition;
|
||||
|
||||
ResumeThread(boolean isDownload, String sqlCondition) {
|
||||
this.isDownloadCmd = isDownload;
|
||||
this.sqlCondition = sqlCondition;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找数据库中的所有任务数据
|
||||
*
|
||||
* @param type {@code 1}单任务下载任务;{@code 2}任务组下载任务;{@code 3} 单任务上传任务
|
||||
*/
|
||||
private void findTaskData(int type) {
|
||||
if (type == 1) {
|
||||
List<DownloadEntity> entities =
|
||||
DbEntity.findDatas(DownloadEntity.class,
|
||||
String.format("NOT(isGroupChild) AND NOT(isComplete) AND %s ORDER BY stopTime DESC",
|
||||
sqlCondition));
|
||||
if (entities != null && !entities.isEmpty()) {
|
||||
for (DownloadEntity entity : entities) {
|
||||
addResumeEntity(TaskWrapperManager.getInstance()
|
||||
.getNormalTaskWrapper(DTaskWrapper.class, entity.getId()));
|
||||
}
|
||||
}
|
||||
} else if (type == 2) {
|
||||
List<DownloadGroupEntity> entities =
|
||||
DbEntity.findDatas(DownloadGroupEntity.class,
|
||||
String.format("NOT(isComplete) AND %s ORDER BY stopTime DESC",
|
||||
sqlCondition));
|
||||
if (entities != null && !entities.isEmpty()) {
|
||||
for (DownloadGroupEntity entity : entities) {
|
||||
addResumeEntity(
|
||||
TaskWrapperManager.getInstance()
|
||||
.getGroupWrapper(DGTaskWrapper.class, entity.getId()));
|
||||
}
|
||||
}
|
||||
} else if (type == 3) {
|
||||
List<UploadEntity> entities =
|
||||
DbEntity.findDatas(UploadEntity.class,
|
||||
String.format("NOT(isComplete) AND %s ORDER BY stopTime DESC",
|
||||
sqlCondition));
|
||||
if (entities != null && !entities.isEmpty()) {
|
||||
for (UploadEntity entity : entities) {
|
||||
addResumeEntity(TaskWrapperManager.getInstance()
|
||||
.getNormalTaskWrapper(UTaskWrapper.class, entity.getId()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加恢复实体
|
||||
*/
|
||||
private void addResumeEntity(AbsTaskWrapper te) {
|
||||
if (te == null || te.getEntity() == null || TextUtils.isEmpty(te.getKey())) {
|
||||
return;
|
||||
}
|
||||
mWaitList.add(te);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理等待状态的任务
|
||||
*/
|
||||
private void resumeWaitTask() {
|
||||
|
||||
if (mWaitList == null || mWaitList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
List<AbsEntity> resumeEntities = new ArrayList<>();
|
||||
|
||||
for (AbsTaskWrapper wrapper : mWaitList) {
|
||||
AbsTaskQueue queue = null;
|
||||
if (wrapper instanceof DTaskWrapper) {
|
||||
queue = DTaskQueue.getInstance();
|
||||
} else if (wrapper instanceof UTaskWrapper) {
|
||||
queue = UTaskQueue.getInstance();
|
||||
} else if (wrapper instanceof DGTaskWrapper) {
|
||||
queue = DGroupTaskQueue.getInstance();
|
||||
}
|
||||
|
||||
if (queue == null) {
|
||||
ALog.e(TAG, "任务类型错误");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (wrapper.getEntity() == null || TextUtils.isEmpty(wrapper.getKey())) {
|
||||
ALog.e(TAG, "任务实体为空或key为空");
|
||||
continue;
|
||||
}
|
||||
|
||||
AbsTask task = queue.getTask(wrapper.getKey());
|
||||
if (task != null) {
|
||||
ALog.w(TAG, "任务已存在");
|
||||
continue;
|
||||
}
|
||||
|
||||
int maxTaskNum = queue.getMaxTaskNum();
|
||||
task = queue.createTask(wrapper);
|
||||
if (task == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
handleWrapper(wrapper);
|
||||
|
||||
if (queue.getCurrentExePoolNum() < maxTaskNum) {
|
||||
queue.startTask(task);
|
||||
} else {
|
||||
wrapper.getEntity().setState(IEntity.STATE_WAIT);
|
||||
sendWaitState(task);
|
||||
resumeEntities.add(wrapper.getEntity());
|
||||
}
|
||||
}
|
||||
if (!resumeEntities.isEmpty()) {
|
||||
DbEntity.updateManyData(resumeEntities);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理ftp的wrapper
|
||||
*/
|
||||
private void handleWrapper(AbsTaskWrapper wrapper) {
|
||||
int requestType = wrapper.getRequestType();
|
||||
if (requestType == ITaskWrapper.D_FTP
|
||||
|| requestType == ITaskWrapper.U_FTP
|
||||
|| requestType == ITaskWrapper.D_FTP_DIR) {
|
||||
wrapper.getOptionParams()
|
||||
.setParams(IOptionConstant.ftpUrlEntity,
|
||||
CommonUtil.getFtpUrlInfo(wrapper.getEntity().getKey()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送等待状态
|
||||
*/
|
||||
private void sendWaitState(AbsTask task) {
|
||||
if (task != null) {
|
||||
task.getTaskWrapper().setState(IEntity.STATE_WAIT);
|
||||
task.getOutHandler().obtainMessage(ISchedulers.WAIT, task).sendToTarget();
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void run() {
|
||||
if (isDownloadCmd) {
|
||||
findTaskData(1);
|
||||
findTaskData(2);
|
||||
} else {
|
||||
findTaskData(3);
|
||||
}
|
||||
resumeWaitTask();
|
||||
}
|
||||
}
|
||||
@@ -18,27 +18,11 @@ package com.arialyy.aria.core.command;
|
||||
|
||||
import com.arialyy.aria.core.AriaManager;
|
||||
import com.arialyy.aria.core.common.QueueMod;
|
||||
import com.arialyy.aria.core.download.DGTaskWrapper;
|
||||
import com.arialyy.aria.core.download.DTaskWrapper;
|
||||
import com.arialyy.aria.core.download.DownloadEntity;
|
||||
import com.arialyy.aria.core.download.DownloadGroupEntity;
|
||||
import com.arialyy.aria.core.inf.IEntity;
|
||||
import com.arialyy.aria.core.task.AbsTask;
|
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
import com.arialyy.aria.core.inf.IEntity;
|
||||
import com.arialyy.aria.core.inf.IOptionConstant;
|
||||
import com.arialyy.aria.core.manager.TaskWrapperManager;
|
||||
import com.arialyy.aria.core.queue.DGroupTaskQueue;
|
||||
import com.arialyy.aria.core.queue.DTaskQueue;
|
||||
import com.arialyy.aria.core.queue.UTaskQueue;
|
||||
import com.arialyy.aria.core.upload.UTaskWrapper;
|
||||
import com.arialyy.aria.core.upload.UploadEntity;
|
||||
import com.arialyy.aria.core.wrapper.ITaskWrapper;
|
||||
import com.arialyy.aria.orm.DbEntity;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import com.arialyy.aria.util.NetUtils;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by lyy on 2016/8/22. 开始命令 队列模型{@link QueueMod#NOW}、{@link QueueMod#WAIT}
|
||||
@@ -107,75 +91,7 @@ final class StartCmd<T extends AbsTaskWrapper> extends AbsNormalCmd<T> {
|
||||
* 当缓冲队列为null时,查找数据库中所有等待中的任务
|
||||
*/
|
||||
private void findAllWaitTask() {
|
||||
new Thread(new WaitTaskThread()).start();
|
||||
}
|
||||
|
||||
private class WaitTaskThread implements Runnable {
|
||||
|
||||
@Override public void run() {
|
||||
if (isDownloadCmd) {
|
||||
handleTask(findWaitData(1));
|
||||
handleTask(findWaitData(2));
|
||||
} else {
|
||||
handleTask(findWaitData(3));
|
||||
}
|
||||
}
|
||||
|
||||
private List<AbsTaskWrapper> findWaitData(int type) {
|
||||
List<AbsTaskWrapper> waitList = new ArrayList<>();
|
||||
TaskWrapperManager tManager = TaskWrapperManager.getInstance();
|
||||
if (type == 1) { // 普通下载任务
|
||||
List<DownloadEntity> dEntities = DbEntity.findDatas(DownloadEntity.class,
|
||||
"isGroupChild=? and state=?", "false", "3");
|
||||
if (dEntities != null && !dEntities.isEmpty()) {
|
||||
for (DownloadEntity e : dEntities) {
|
||||
waitList.add(tManager.getNormalTaskWrapper(DTaskWrapper.class, e.getId()));
|
||||
}
|
||||
}
|
||||
} else if (type == 2) { // 组合任务
|
||||
List<DownloadGroupEntity> dEntities =
|
||||
DbEntity.findDatas(DownloadGroupEntity.class, "state=?", "3");
|
||||
if (dEntities != null && !dEntities.isEmpty()) {
|
||||
for (DownloadGroupEntity e : dEntities) {
|
||||
if (e.getTaskType() == ITaskWrapper.DG_HTTP) {
|
||||
waitList.add(tManager.getGroupWrapper(DGTaskWrapper.class, e.getId()));
|
||||
} else if (e.getTaskType() == ITaskWrapper.D_FTP_DIR) {
|
||||
waitList.add(tManager.getGroupWrapper(DGTaskWrapper.class, e.getId()));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (type == 3) { //普通上传任务
|
||||
List<UploadEntity> dEntities = DbEntity.findDatas(UploadEntity.class, "state=?", "3");
|
||||
|
||||
if (dEntities != null && !dEntities.isEmpty()) {
|
||||
for (UploadEntity e : dEntities) {
|
||||
waitList.add(tManager.getNormalTaskWrapper(UTaskWrapper.class, e.getId()));
|
||||
}
|
||||
}
|
||||
}
|
||||
return waitList;
|
||||
}
|
||||
|
||||
private void handleTask(List<AbsTaskWrapper> waitList) {
|
||||
for (AbsTaskWrapper wrapper : waitList) {
|
||||
if (wrapper.getEntity() == null) continue;
|
||||
AbsTask task = getTask(wrapper.getKey());
|
||||
if (task != null) continue;
|
||||
if (wrapper instanceof DTaskWrapper) {
|
||||
if (wrapper.getRequestType() == ITaskWrapper.D_FTP
|
||||
|| wrapper.getRequestType() == ITaskWrapper.U_FTP) {
|
||||
wrapper.getOptionParams()
|
||||
.setParams(IOptionConstant.ftpUrlEntity,
|
||||
CommonUtil.getFtpUrlInfo(wrapper.getEntity().getKey()));
|
||||
}
|
||||
mQueue = DTaskQueue.getInstance();
|
||||
} else if (wrapper instanceof UTaskWrapper) {
|
||||
mQueue = UTaskQueue.getInstance();
|
||||
} else if (wrapper instanceof DGTaskWrapper) {
|
||||
mQueue = DGroupTaskQueue.getInstance();
|
||||
}
|
||||
createTask(wrapper);
|
||||
}
|
||||
}
|
||||
new Thread(
|
||||
new ResumeThread(isDownloadCmd, String.format("state=%s", IEntity.STATE_WAIT))).start();
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ import com.arialyy.aria.core.command.NormalCmdFactory;
|
||||
import com.arialyy.aria.core.event.EventMsgUtil;
|
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
import com.arialyy.aria.core.command.CmdHelper;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
|
||||
/**
|
||||
* 创建任务时使用的控制器
|
||||
|
||||
@@ -16,13 +16,10 @@
|
||||
package com.arialyy.aria.core.download;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import com.arialyy.aria.core.common.ErrorCode;
|
||||
import com.arialyy.aria.core.inf.ICheckEntityUtil;
|
||||
import com.arialyy.aria.core.inf.IOptionConstant;
|
||||
import com.arialyy.aria.core.inf.IRecordHandler;
|
||||
import com.arialyy.aria.core.inf.ITargetHandler;
|
||||
import com.arialyy.aria.core.wrapper.ITaskWrapper;
|
||||
import com.arialyy.aria.orm.DbEntity;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.CheckUtil;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
@@ -74,17 +71,13 @@ public class CheckDEntityUtil implements ICheckEntityUtil {
|
||||
mWrapper.getM3U8Params().setParams(IOptionConstant.cacheDir, cacheDir);
|
||||
M3U8Entity m3U8Entity = mEntity.getM3U8Entity();
|
||||
|
||||
Object temp = mWrapper.getM3U8Params().getParam(IOptionConstant.generateIndexFileTemp);
|
||||
boolean generateIndexFileTemp = temp != null && (boolean) temp;
|
||||
if (m3U8Entity == null) {
|
||||
m3U8Entity = new M3U8Entity();
|
||||
m3U8Entity.setFilePath(mEntity.getFilePath());
|
||||
m3U8Entity.setPeerIndex(0);
|
||||
m3U8Entity.setCacheDir(cacheDir);
|
||||
m3U8Entity.setGenerateIndexFile(generateIndexFileTemp);
|
||||
m3U8Entity.insert();
|
||||
} else {
|
||||
m3U8Entity.setGenerateIndexFile(generateIndexFileTemp);
|
||||
m3U8Entity.update();
|
||||
}
|
||||
if (mWrapper.getRequestType() == ITaskWrapper.M3U8_VOD) {
|
||||
@@ -141,14 +134,8 @@ public class CheckDEntityUtil implements ICheckEntityUtil {
|
||||
//设置文件保存路径,如果新文件路径和旧文件路径不同,则修改路径
|
||||
if (!filePath.equals(mEntity.getFilePath())) {
|
||||
// 检查路径冲突
|
||||
if (DbEntity.checkDataExist(DownloadEntity.class, "downloadPath=?", filePath)) {
|
||||
if (!mWrapper.isForceDownload()) {
|
||||
ALog.e(TAG, String.format("下载失败,保存路径【%s】已经被其它任务占用,请设置其它保存路径", filePath));
|
||||
return false;
|
||||
} else {
|
||||
ALog.w(TAG, String.format("保存路径【%s】已经被其它任务占用,当前任务将覆盖该路径的文件", filePath));
|
||||
RecordUtil.delTaskRecord(filePath, IRecordHandler.TYPE_DOWNLOAD);
|
||||
}
|
||||
if (!CheckUtil.checkDownloadPathConflicts(mWrapper.isForceDownload(), filePath)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
File newFile = new File(filePath);
|
||||
|
||||
@@ -170,9 +170,8 @@ public class CheckDGEntityUtil implements ICheckEntityUtil {
|
||||
if (!newName.equals(entity.getFileName())) {
|
||||
String oldPath = mEntity.getDirPath() + "/" + entity.getFileName();
|
||||
String newPath = mEntity.getDirPath() + "/" + newName;
|
||||
if (DbEntity.checkDataExist(DownloadEntity.class, "downloadPath=? or isComplete='true'",
|
||||
newPath)) {
|
||||
ALog.w(TAG, String.format("更新文件名失败,路径【%s】已存在或文件已下载", newPath));
|
||||
if (DbEntity.checkDataExist(DownloadEntity.class, "downloadPath=?", newPath)) {
|
||||
ALog.w(TAG, String.format("更新文件名失败,路径【%s】被其它任务占用", newPath));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ package com.arialyy.aria.core.download.m3u8;
|
||||
import com.arialyy.aria.core.common.BaseOption;
|
||||
import com.arialyy.aria.core.processor.IBandWidthUrlConverter;
|
||||
import com.arialyy.aria.core.processor.ITsMergeHandler;
|
||||
import com.arialyy.aria.core.processor.IVodTsUrlConverter;
|
||||
import com.arialyy.aria.util.CheckUtil;
|
||||
import com.arialyy.aria.util.ComponentUtil;
|
||||
|
||||
@@ -27,8 +26,8 @@ import com.arialyy.aria.util.ComponentUtil;
|
||||
*/
|
||||
public class M3U8Option<OP extends M3U8Option> extends BaseOption {
|
||||
|
||||
private boolean generateIndexFileTemp = false;
|
||||
private boolean mergeFile = false;
|
||||
private boolean generateIndexFile = false;
|
||||
private boolean mergeFile = true;
|
||||
private int bandWidth;
|
||||
private ITsMergeHandler mergeHandler;
|
||||
private IBandWidthUrlConverter bandWidthUrlConverter;
|
||||
@@ -41,9 +40,10 @@ public class M3U8Option<OP extends M3U8Option> extends BaseOption {
|
||||
/**
|
||||
* 生成m3u8索引文件
|
||||
* 注意:创建索引文件,{@link #merge(boolean)}方法设置与否都不再合并文件
|
||||
* 如果是直播文件下载,创建索引文件的操作将导致只能同时下载一个切片!!
|
||||
*/
|
||||
public OP generateIndexFile() {
|
||||
this.generateIndexFileTemp = true;
|
||||
this.generateIndexFile = true;
|
||||
return (OP) this;
|
||||
}
|
||||
|
||||
|
||||
@@ -42,14 +42,17 @@ class DGTaskWrapperFactory implements IGroupWrapperFactory<DownloadGroupEntity,
|
||||
}
|
||||
|
||||
@Override public DGTaskWrapper getGroupWrapper(long taskId) {
|
||||
DGTaskWrapper wrapper;
|
||||
if (taskId == -1) {
|
||||
return new DGTaskWrapper(new DownloadGroupEntity());
|
||||
}
|
||||
DownloadGroupEntity entity = getOrCreateHttpDGEntity(taskId);
|
||||
DGTaskWrapper wrapper = new DGTaskWrapper(entity);
|
||||
if (entity.getSubEntities() != null && !entity.getSubEntities().isEmpty()) {
|
||||
wrapper.setSubTaskWrapper(DbDataHelper.createDGSubTaskWrapper(entity));
|
||||
wrapper = new DGTaskWrapper(new DownloadGroupEntity());
|
||||
}else {
|
||||
DownloadGroupEntity entity = getOrCreateHttpDGEntity(taskId);
|
||||
wrapper = new DGTaskWrapper(entity);
|
||||
if (entity.getSubEntities() != null && !entity.getSubEntities().isEmpty()) {
|
||||
wrapper.setSubTaskWrapper(DbDataHelper.createDGSubTaskWrapper(entity));
|
||||
}
|
||||
}
|
||||
wrapper.setRequestType(wrapper.getEntity().getTaskType());
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
|
||||
@@ -45,11 +45,14 @@ class DTaskWrapperFactory implements INormalTEFactory<DownloadEntity, DTaskWrapp
|
||||
* 通过下载地址创建任务实体
|
||||
*/
|
||||
@Override public DTaskWrapper create(long taskId) {
|
||||
DTaskWrapper wrapper;
|
||||
if (taskId == -1) {
|
||||
return new DTaskWrapper(new DownloadEntity());
|
||||
wrapper = new DTaskWrapper(new DownloadEntity());
|
||||
} else {
|
||||
wrapper = new DTaskWrapper(getEntity(taskId));
|
||||
}
|
||||
|
||||
return new DTaskWrapper(getEntity(taskId));
|
||||
wrapper.setRequestType(wrapper.getEntity().getTaskType());
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,6 +17,7 @@ package com.arialyy.aria.core.manager;
|
||||
|
||||
import com.arialyy.aria.core.upload.UTaskWrapper;
|
||||
import com.arialyy.aria.core.upload.UploadEntity;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
|
||||
/**
|
||||
* Created by Aria.Lao on 2017/11/1. 任务实体工厂
|
||||
@@ -38,10 +39,15 @@ class UTaskWrapperFactory implements INormalTEFactory<UploadEntity, UTaskWrapper
|
||||
}
|
||||
|
||||
@Override public UTaskWrapper create(long taskId) {
|
||||
UTaskWrapper wrapper;
|
||||
if (taskId == -1) {
|
||||
return new UTaskWrapper(new UploadEntity());
|
||||
wrapper = new UTaskWrapper(new UploadEntity());
|
||||
} else {
|
||||
wrapper = new UTaskWrapper(getUploadEntity(taskId));
|
||||
}
|
||||
return new UTaskWrapper(getUploadEntity(taskId));
|
||||
|
||||
wrapper.setRequestType(wrapper.getEntity().getTaskType());
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
package com.arialyy.aria.core.upload;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import com.arialyy.aria.core.common.ErrorCode;
|
||||
import com.arialyy.aria.core.inf.ICheckEntityUtil;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.CheckUtil;
|
||||
@@ -60,6 +59,11 @@ public class CheckUEntityUtil implements ICheckEntityUtil {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查路径冲突
|
||||
if (!CheckUtil.checkUploadPathConflicts(mWrapper.isForceUpload(), filePath)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
File file = new File(mEntity.getFilePath());
|
||||
if (!file.exists()) {
|
||||
ALog.e(TAG, "上传失败,文件【" + filePath + "】不存在");
|
||||
@@ -69,6 +73,7 @@ public class CheckUEntityUtil implements ICheckEntityUtil {
|
||||
ALog.e(TAG, "上传失败,文件【" + filePath + "】不能是文件夹");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,8 @@ import androidx.annotation.CheckResult;
|
||||
import com.arialyy.aria.core.common.AbsBuilderTarget;
|
||||
import com.arialyy.aria.core.common.FtpOption;
|
||||
import com.arialyy.aria.core.inf.Suggest;
|
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
import com.arialyy.aria.core.upload.UTaskWrapper;
|
||||
import com.arialyy.aria.core.wrapper.ITaskWrapper;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
|
||||
/**
|
||||
@@ -33,7 +34,8 @@ public class FtpBuilderTarget extends AbsBuilderTarget<FtpBuilderTarget> {
|
||||
FtpBuilderTarget(String filePath) {
|
||||
mConfigHandler = new UNormalConfigHandler<>(this, -1);
|
||||
mConfigHandler.setFilePath(filePath);
|
||||
getTaskWrapper().setRequestType(AbsTaskWrapper.U_FTP);
|
||||
getTaskWrapper().setRequestType(ITaskWrapper.U_FTP);
|
||||
getTaskWrapper().setNewTask(true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -48,6 +50,14 @@ public class FtpBuilderTarget extends AbsBuilderTarget<FtpBuilderTarget> {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果文件路径被其它任务占用,删除其它任务
|
||||
*/
|
||||
public FtpBuilderTarget forceUpload() {
|
||||
((UTaskWrapper)getTaskWrapper()).setForceUpload(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置登陆、字符串编码、ftps等参数
|
||||
*/
|
||||
|
||||
@@ -20,7 +20,7 @@ import com.arialyy.aria.core.common.AbsNormalTarget;
|
||||
import com.arialyy.aria.core.common.FtpOption;
|
||||
import com.arialyy.aria.core.inf.Suggest;
|
||||
import com.arialyy.aria.core.upload.UploadEntity;
|
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
import com.arialyy.aria.core.wrapper.ITaskWrapper;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
|
||||
/**
|
||||
@@ -32,7 +32,7 @@ public class FtpNormalTarget extends AbsNormalTarget<FtpNormalTarget> {
|
||||
|
||||
FtpNormalTarget(long taskId) {
|
||||
mConfigHandler = new UNormalConfigHandler<>(this, taskId);
|
||||
getTaskWrapper().setRequestType(AbsTaskWrapper.U_FTP);
|
||||
getTaskWrapper().setRequestType(ITaskWrapper.U_FTP);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -19,6 +19,7 @@ import androidx.annotation.CheckResult;
|
||||
import com.arialyy.aria.core.common.AbsBuilderTarget;
|
||||
import com.arialyy.aria.core.common.HttpOption;
|
||||
import com.arialyy.aria.core.inf.Suggest;
|
||||
import com.arialyy.aria.core.upload.UTaskWrapper;
|
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
|
||||
/**
|
||||
@@ -60,4 +61,12 @@ public class HttpBuilderTarget extends AbsBuilderTarget<HttpBuilderTarget> {
|
||||
getTaskWrapper().getOptionParams().setParams(option);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果文件路径被其它任务占用,删除其它任务
|
||||
*/
|
||||
public HttpBuilderTarget forceUpload() {
|
||||
((UTaskWrapper) getTaskWrapper()).setForceUpload(true);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
18
DEV_LOG.md
18
DEV_LOG.md
@@ -1,4 +1,22 @@
|
||||
## 开发日志
|
||||
+ v_3.7.8-pre-1(2019/11/20)
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/526
|
||||
+ v_3.7.7 (2019/11/20)
|
||||
- 修复ftp无法完成下载的问题
|
||||
- 修复一个http下载崩溃的问题
|
||||
+ v_3.7.6 (2019/11/19)
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/505
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/516
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/515
|
||||
- 增加强制上传的api`forceUpload()`
|
||||
- 修复for循环上传文件出现的问题
|
||||
- 移除创建任务的500ms间隔限制
|
||||
- 修复多线程读写时可能出现的`database is locked`的问题
|
||||
+ v_3.7.5 (2019/11/10)
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/500
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/508
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/503
|
||||
- 修复m3u8创建索引不成功的问题
|
||||
+ v_3.7.4 (2019/11/2)
|
||||
- 修复一个class被莫名改变的问题
|
||||
- 修复非分块模式下导致的一个下载失败问题
|
||||
|
||||
@@ -25,6 +25,7 @@ import com.arialyy.aria.core.download.DownloadGroupEntity;
|
||||
import com.arialyy.aria.core.inf.OnFileInfoCallback;
|
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
import com.arialyy.aria.exception.BaseException;
|
||||
import com.arialyy.aria.util.CheckUtil;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import com.arialyy.aria.util.RecordUtil;
|
||||
import java.nio.charset.Charset;
|
||||
@@ -72,6 +73,9 @@ public class FtpDirInfoThread extends AbsFtpInfoThread<DownloadGroupEntity, DGTa
|
||||
entity.setGroupChild(true);
|
||||
entity.setConvertFileSize(CommonUtil.formatFileSize(ftpFile.getSize()));
|
||||
entity.setFileSize(ftpFile.getSize());
|
||||
|
||||
//if(CheckUtil.checkDownloadPathConflicts(mTaskWrapper.is))
|
||||
|
||||
entity.insert();
|
||||
|
||||
DTaskWrapper subWrapper = new DTaskWrapper(entity);
|
||||
|
||||
@@ -43,7 +43,7 @@ public class FtpRecordAdapter extends AbsRecordHandlerAdapter {
|
||||
if (record.isBlock) {
|
||||
helper.handleBlockRecord();
|
||||
} else {
|
||||
helper.handleMutilRecord();
|
||||
helper.handleMultiRecord();
|
||||
}
|
||||
} else if (record.threadNum == 1) {
|
||||
helper.handleSingleThreadRecord();
|
||||
@@ -77,9 +77,7 @@ public class FtpRecordAdapter extends AbsRecordHandlerAdapter {
|
||||
|
||||
int requestType = getWrapper().getRequestType();
|
||||
if (requestType == ITaskWrapper.D_FTP || requestType == ITaskWrapper.D_FTP_DIR) {
|
||||
record.isBlock = threadNum > 1 && Configuration.getInstance().downloadCfg.isUseBlock();
|
||||
// 线程数为1,或者使用了分块,则认为是使用动态长度文件
|
||||
record.isOpenDynamicFile = threadNum == 1 || record.isBlock;
|
||||
record.isBlock = Configuration.getInstance().downloadCfg.isUseBlock();
|
||||
} else {
|
||||
record.isBlock = false;
|
||||
}
|
||||
|
||||
@@ -16,32 +16,33 @@
|
||||
package com.arialyy.aria.ftp.download;
|
||||
|
||||
import com.arialyy.aria.core.TaskRecord;
|
||||
import com.arialyy.aria.core.task.AbsNormalLoaderAdapter;
|
||||
import com.arialyy.aria.core.common.RecordHandler;
|
||||
import com.arialyy.aria.core.common.SubThreadConfig;
|
||||
import com.arialyy.aria.core.inf.IRecordHandler;
|
||||
import com.arialyy.aria.core.task.AbsNormalLoaderAdapter;
|
||||
import com.arialyy.aria.core.task.IThreadTask;
|
||||
import com.arialyy.aria.core.task.ThreadTask;
|
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
import com.arialyy.aria.core.inf.IRecordHandler;
|
||||
import com.arialyy.aria.core.task.IThreadTask;
|
||||
import com.arialyy.aria.core.wrapper.ITaskWrapper;
|
||||
import com.arialyy.aria.ftp.FtpRecordAdapter;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.FileUtil;
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* @Author lyy
|
||||
* @Date 2019-09-19
|
||||
*/
|
||||
final class FtpDLoaderAdapter extends AbsNormalLoaderAdapter {
|
||||
public class FtpDLoaderAdapter extends AbsNormalLoaderAdapter {
|
||||
|
||||
FtpDLoaderAdapter(ITaskWrapper wrapper) {
|
||||
public FtpDLoaderAdapter(ITaskWrapper wrapper) {
|
||||
super(wrapper);
|
||||
}
|
||||
|
||||
@Override public boolean handleNewTask(TaskRecord record, int totalThreadNum) {
|
||||
if (!record.isBlock) {
|
||||
if (getTempFile().exists()) {
|
||||
getTempFile().delete();
|
||||
FileUtil.deleteFile(getTempFile());
|
||||
}
|
||||
//CommonUtil.createFile(mTempFile.getPath());
|
||||
} else {
|
||||
@@ -50,7 +51,7 @@ final class FtpDLoaderAdapter extends AbsNormalLoaderAdapter {
|
||||
new File(String.format(IRecordHandler.SUB_PATH, getTempFile().getPath(), i));
|
||||
if (blockFile.exists()) {
|
||||
ALog.d(TAG, String.format("分块【%s】已经存在,将删除该分块", i));
|
||||
blockFile.delete();
|
||||
FileUtil.deleteFile(blockFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ final class FtpDThreadTaskAdapter extends BaseFtpThreadTaskAdapter {
|
||||
return;
|
||||
}
|
||||
|
||||
if (getThreadConfig().isOpenDynamicFile) {
|
||||
if (getThreadConfig().isBlock) {
|
||||
readDynamicFile(is);
|
||||
} else {
|
||||
readNormal(is);
|
||||
|
||||
@@ -85,13 +85,14 @@ public class FtpDirDLoaderUtil extends AbsGroupUtil {
|
||||
* @param needCloneInfo 第一次下载,信息已经在{@link FtpDirInfoThread}中clone了
|
||||
*/
|
||||
private void startDownload(boolean needCloneInfo) {
|
||||
// ftp需要获取完成只任务信息才更新只任务数量
|
||||
getState().setSubSize(getWrapper().getSubTaskWrapper().size());
|
||||
try {
|
||||
LOCK.lock();
|
||||
condition.signalAll();
|
||||
} finally {
|
||||
LOCK.unlock();
|
||||
}
|
||||
initState();
|
||||
for (DTaskWrapper wrapper : getWrapper().getSubTaskWrapper()) {
|
||||
if (needCloneInfo) {
|
||||
cloneInfo(wrapper);
|
||||
|
||||
@@ -60,6 +60,7 @@ class FtpUFileInfoThread extends AbsFtpInfoThread<UploadEntity, UTaskWrapper> {
|
||||
@Override protected boolean onInterceptor(FTPClient client, FTPFile[] ftpFiles) {
|
||||
// 旧任务将不做处理,否则断点续传上传将失效
|
||||
if (!mTaskWrapper.isNewTask()) {
|
||||
ALog.d(TAG, "任务是旧任务,忽略该拦截器");
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
|
||||
@@ -49,7 +49,7 @@ public class HttpRecordAdapter extends AbsRecordHandlerAdapter {
|
||||
if (record.isBlock) {
|
||||
helper.handleBlockRecord();
|
||||
} else {
|
||||
helper.handleMutilRecord();
|
||||
helper.handleMultiRecord();
|
||||
}
|
||||
} else if (!getWrapper().isSupportBP()) {
|
||||
helper.handleNoSupportBPRecord();
|
||||
@@ -87,9 +87,7 @@ public class HttpRecordAdapter extends AbsRecordHandlerAdapter {
|
||||
int requestType = getWrapper().getRequestType();
|
||||
if (requestType == ITaskWrapper.D_FTP || requestType == ITaskWrapper.D_FTP_DIR
|
||||
|| requestType == ITaskWrapper.D_HTTP || requestType == ITaskWrapper.DG_HTTP) {
|
||||
record.isBlock = threadNum > 1 && Configuration.getInstance().downloadCfg.isUseBlock();
|
||||
// 线程数为1,或者使用了分块,则认为是使用动态长度文件
|
||||
record.isOpenDynamicFile = threadNum == 1 || record.isBlock;
|
||||
record.isBlock = Configuration.getInstance().downloadCfg.isUseBlock();
|
||||
} else {
|
||||
record.isBlock = false;
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ public class DGroupLoaderUtil extends AbsGroupUtil {
|
||||
|
||||
@Override protected boolean onStart() {
|
||||
super.onStart();
|
||||
initState();
|
||||
getState().setSubSize(getWrapper().getSubTaskWrapper().size());
|
||||
if (getState().getCompleteNum() == getState().getSubSize()) {
|
||||
mListener.onComplete();
|
||||
} else {
|
||||
@@ -91,6 +91,7 @@ public class DGroupLoaderUtil extends AbsGroupUtil {
|
||||
return getLenComplete;
|
||||
} else {
|
||||
for (DTaskWrapper wrapper : getWrapper().getSubTaskWrapper()) {
|
||||
cloneHeader(wrapper);
|
||||
if (wrapper.getState() != IEntity.STATE_COMPLETE) {
|
||||
startSubLoader(createSubLoader(wrapper, true));
|
||||
}
|
||||
@@ -179,7 +180,7 @@ public class DGroupLoaderUtil extends AbsGroupUtil {
|
||||
*/
|
||||
private void cloneHeader(DTaskWrapper taskWrapper) {
|
||||
HttpTaskOption groupOption = (HttpTaskOption) getWrapper().getTaskOption();
|
||||
HttpTaskOption subOption = (HttpTaskOption) taskWrapper.getTaskOption();
|
||||
HttpTaskOption subOption = new HttpTaskOption();
|
||||
|
||||
// 设置属性
|
||||
subOption.setFileLenAdapter(groupOption.getFileLenAdapter());
|
||||
@@ -187,5 +188,6 @@ public class DGroupLoaderUtil extends AbsGroupUtil {
|
||||
subOption.setHeaders(groupOption.getHeaders());
|
||||
subOption.setProxy(groupOption.getProxy());
|
||||
subOption.setParams(groupOption.getParams());
|
||||
taskWrapper.setTaskOption(subOption);
|
||||
}
|
||||
}
|
||||
@@ -103,7 +103,7 @@ final class HttpDThreadTaskAdapter extends BaseHttpThreadTaskAdapter {
|
||||
is = new BufferedInputStream(ConnectionHelp.convertInputStream(conn));
|
||||
if (mTaskOption.isChunked()) {
|
||||
readChunked(is);
|
||||
} else if (getThreadConfig().isOpenDynamicFile) {
|
||||
} else if (getThreadConfig().isBlock) {
|
||||
readDynamicFile(is);
|
||||
} else {
|
||||
//创建可设置位置的文件
|
||||
|
||||
@@ -68,8 +68,9 @@ public abstract class BaseM3U8Loader extends AbsLoader {
|
||||
/**
|
||||
* 创建索引文件
|
||||
*/
|
||||
protected boolean generateIndexFile() {
|
||||
File tempFile = new File(M3U8InfoThread.M3U8_INDEX_FORMAT, getEntity().getFilePath());
|
||||
public boolean generateIndexFile(boolean isLive) {
|
||||
File tempFile =
|
||||
new File(String.format(M3U8InfoThread.M3U8_INDEX_FORMAT, getEntity().getFilePath()));
|
||||
if (!tempFile.exists()) {
|
||||
ALog.e(TAG, "源索引文件不存在");
|
||||
return false;
|
||||
@@ -85,21 +86,29 @@ public abstract class BaseM3U8Loader extends AbsLoader {
|
||||
int i = 0;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
byte[] bytes;
|
||||
if (line.startsWith("EXTINF")) {
|
||||
if (line.startsWith("#EXTINF")) {
|
||||
fos.write(line.concat("\r\n").getBytes(Charset.forName("UTF-8")));
|
||||
String tsPath = getTsFilePath(cacheDir, mRecord.threadRecords.get(i).threadId);
|
||||
bytes = tsPath.concat("\r\n").getBytes(Charset.forName("UTF-8"));
|
||||
reader.readLine(); // 继续读一行,避免写入源索引文件的切片地址
|
||||
i++;
|
||||
} else if (line.startsWith("EXT-X-KEY")) {
|
||||
} else if (line.startsWith("#EXT-X-KEY")) {
|
||||
M3U8Entity m3U8Entity = getEntity().getM3U8Entity();
|
||||
String keyInfo = String.format("#EXT-X-KEY:METHOD=%s,URI=%s,IV=%s\r\n", m3U8Entity.method,
|
||||
m3U8Entity.keyPath, m3U8Entity.iv);
|
||||
bytes = keyInfo.getBytes(Charset.forName("UTF-8"));
|
||||
} else {
|
||||
bytes = line.getBytes(Charset.forName("UTF-8"));
|
||||
bytes = line.concat("\r\n").getBytes(Charset.forName("UTF-8"));
|
||||
}
|
||||
fos.write(bytes, 0, bytes.length);
|
||||
}
|
||||
// 直播的索引文件需要在结束的时候才写入结束标志
|
||||
if (isLive) {
|
||||
fos.write("#EXT-X-ENDLIST".concat("\r\n").getBytes(Charset.forName("UTF-8")));
|
||||
}
|
||||
|
||||
fos.flush();
|
||||
return true;
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
|
||||
@@ -24,8 +24,8 @@ import com.arialyy.aria.core.common.CompleteInfo;
|
||||
import com.arialyy.aria.core.download.DTaskWrapper;
|
||||
import com.arialyy.aria.core.download.DownloadEntity;
|
||||
import com.arialyy.aria.core.download.M3U8Entity;
|
||||
import com.arialyy.aria.core.processor.IBandWidthUrlConverter;
|
||||
import com.arialyy.aria.core.inf.OnFileInfoCallback;
|
||||
import com.arialyy.aria.core.processor.IBandWidthUrlConverter;
|
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
import com.arialyy.aria.core.wrapper.ITaskWrapper;
|
||||
import com.arialyy.aria.exception.M3U8Exception;
|
||||
@@ -39,7 +39,6 @@ import com.arialyy.aria.util.FileUtil;
|
||||
import com.arialyy.aria.util.Regular;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@@ -55,6 +54,7 @@ import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* 解析url中获取到到m3u8文件信息
|
||||
* 协议地址:https://tools.ietf.org/html/rfc8216
|
||||
* https://www.cnblogs.com/renhui/p/10351870.html
|
||||
* https://blog.csdn.net/Guofengpu/article/details/54922865
|
||||
*/
|
||||
@@ -72,13 +72,9 @@ final public class M3U8InfoThread implements Runnable {
|
||||
* 是否停止获取切片信息,{@code true}停止获取切片信息
|
||||
*/
|
||||
private boolean isStop = false;
|
||||
/**
|
||||
* m3u8文件信息
|
||||
*/
|
||||
private List<String> mInfos = new ArrayList<>();
|
||||
|
||||
public interface OnGetLivePeerCallback {
|
||||
void onGetPeer(String url);
|
||||
void onGetPeer(String url, String extInf);
|
||||
}
|
||||
|
||||
public M3U8InfoThread(DTaskWrapper taskWrapper, OnFileInfoCallback callback) {
|
||||
@@ -122,38 +118,51 @@ final public class M3U8InfoThread implements Runnable {
|
||||
}
|
||||
List<String> extInf = new ArrayList<>();
|
||||
boolean isLive = mTaskWrapper.getRequestType() == ITaskWrapper.M3U8_LIVE;
|
||||
boolean isGenerateIndexFile = mTaskWrapper.getEntity().getM3U8Entity().isGenerateIndexFile();
|
||||
boolean isGenerateIndexFile =
|
||||
((M3U8TaskOption) mTaskWrapper.getM3u8Option()).isGenerateIndexFile();
|
||||
// 写入索引信息的流
|
||||
FileOutputStream fos = null;
|
||||
if (isGenerateIndexFile) {
|
||||
mInfos.add(line);
|
||||
String indexPath = String.format(M3U8_INDEX_FORMAT, mEntity.getFilePath());
|
||||
File indexFile = new File(indexPath);
|
||||
if (!indexFile.exists()) {
|
||||
FileUtil.createFile(indexPath);
|
||||
}else {
|
||||
//FileUtil.deleteFile(indexPath);
|
||||
}
|
||||
fos = new FileOutputStream(indexFile);
|
||||
ALog.d(TAG, line);
|
||||
addIndexInfo(isGenerateIndexFile, fos, line);
|
||||
}
|
||||
while ((line = reader.readLine()) != null) {
|
||||
if (isStop) {
|
||||
break;
|
||||
}
|
||||
if (isGenerateIndexFile) {
|
||||
mInfos.add(line);
|
||||
}
|
||||
if (line.startsWith("#EXT-X-ENDLIST")) {
|
||||
break;
|
||||
}
|
||||
ALog.d(TAG, line);
|
||||
if (line.startsWith("#EXTINF")) {
|
||||
String info = reader.readLine();
|
||||
mInfos.add(info);
|
||||
if (line.startsWith("#EXT-X-ENDLIST")) {
|
||||
// 点播文件的下载写入结束标志,直播文件的下载在停止时才写入结束标志
|
||||
addIndexInfo(isGenerateIndexFile && !isLive, fos, line);
|
||||
break;
|
||||
} else if (line.startsWith("#EXTINF")) {
|
||||
String url = reader.readLine();
|
||||
if (isLive) {
|
||||
if (onGetPeerCallback != null) {
|
||||
onGetPeerCallback.onGetPeer(info);
|
||||
onGetPeerCallback.onGetPeer(url, line);
|
||||
}
|
||||
} else {
|
||||
extInf.add(info);
|
||||
extInf.add(url);
|
||||
}
|
||||
ALog.d(TAG, url);
|
||||
addIndexInfo(isGenerateIndexFile && !isLive, fos, line);
|
||||
addIndexInfo(isGenerateIndexFile && !isLive, fos, url);
|
||||
} else if (line.startsWith("#EXT-X-STREAM-INF")) {
|
||||
addIndexInfo(isGenerateIndexFile, fos, line);
|
||||
int setBand = mM3U8Option.getBandWidth();
|
||||
int bandWidth = getBandWidth(line);
|
||||
// 多码率的m3u8配置文件,清空信息
|
||||
if (isGenerateIndexFile && mInfos != null) {
|
||||
mInfos.clear();
|
||||
}
|
||||
//if (isGenerateIndexFile && mInfos != null) {
|
||||
// mInfos.clear();
|
||||
//}
|
||||
if (setBand == 0) {
|
||||
handleBandWidth(conn, reader.readLine());
|
||||
} else if (bandWidth == setBand) {
|
||||
@@ -162,8 +171,11 @@ final public class M3U8InfoThread implements Runnable {
|
||||
failDownload(String.format("【%s】码率不存在", bandWidth), false);
|
||||
}
|
||||
return;
|
||||
} else if (line.startsWith("EXT-X-KEY")) {
|
||||
} else if (line.startsWith("#EXT-X-KEY")) {
|
||||
addIndexInfo(isGenerateIndexFile, fos, line);
|
||||
getKeyInfo(line);
|
||||
} else {
|
||||
addIndexInfo(isGenerateIndexFile, fos, line);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,8 +189,11 @@ final public class M3U8InfoThread implements Runnable {
|
||||
}
|
||||
CompleteInfo info = new CompleteInfo();
|
||||
info.obj = extInf;
|
||||
generateIndexFile();
|
||||
|
||||
onFileInfoCallback.onComplete(mEntity.getKey(), info);
|
||||
if (fos != null) {
|
||||
fos.close();
|
||||
}
|
||||
} else if (code == HttpURLConnection.HTTP_MOVED_TEMP
|
||||
|| code == HttpURLConnection.HTTP_MOVED_PERM
|
||||
|| code == HttpURLConnection.HTTP_SEE_OTHER
|
||||
@@ -193,40 +208,19 @@ final public class M3U8InfoThread implements Runnable {
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建索引文件
|
||||
* 添加切片信息到索引文件中
|
||||
* 直播下载的索引只记录头部信息,不记录EXTINF中的信息,该信息在onGetPeer的方法中添加。
|
||||
* 点播下载记录所有信息
|
||||
*
|
||||
* @param write true 将信息写入文件
|
||||
* @param info 切片信息
|
||||
*/
|
||||
private void generateIndexFile() {
|
||||
if (mTaskWrapper.getEntity().getM3U8Entity().isGenerateIndexFile()) {
|
||||
|
||||
String indexPath = String.format(M3U8_INDEX_FORMAT, mEntity.getFilePath());
|
||||
File indexFile = new File(indexPath);
|
||||
if (indexFile.exists()) {
|
||||
FileUtil.deleteFile(indexPath);
|
||||
}
|
||||
FileUtil.createFile(indexPath);
|
||||
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
fos = new FileOutputStream(indexFile);
|
||||
for (String str : mInfos) {
|
||||
byte[] by = str.concat("\r\n").getBytes(Charset.forName("UTF-8"));
|
||||
fos.write(by, 0, by.length);
|
||||
}
|
||||
fos.flush();
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (fos != null) {
|
||||
try {
|
||||
fos.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
private void addIndexInfo(boolean write, FileOutputStream fos, String info)
|
||||
throws IOException {
|
||||
if (!write) {
|
||||
return;
|
||||
}
|
||||
fos.write(info.concat("\r\n").getBytes(Charset.forName("UTF-8")));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.arialyy.aria.core.download.M3U8Entity;
|
||||
import com.arialyy.aria.core.inf.IRecordHandler;
|
||||
import com.arialyy.aria.core.wrapper.ITaskWrapper;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.FileUtil;
|
||||
import com.arialyy.aria.util.RecordUtil;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
@@ -42,7 +43,7 @@ public class M3U8RecordAdapter extends AbsRecordHandlerAdapter {
|
||||
|
||||
@Override public void onPre() {
|
||||
super.onPre();
|
||||
if (getWrapper().getRequestType() == ITaskWrapper.M3U8_LIVE){
|
||||
if (getWrapper().getRequestType() == ITaskWrapper.M3U8_LIVE) {
|
||||
RecordUtil.delTaskRecord(getEntity().getFilePath(), IRecordHandler.TYPE_DOWNLOAD);
|
||||
}
|
||||
}
|
||||
@@ -54,18 +55,22 @@ public class M3U8RecordAdapter extends AbsRecordHandlerAdapter {
|
||||
String cacheDir = mOption.getCacheDir();
|
||||
long currentProgress = 0;
|
||||
int completeNum = 0;
|
||||
File targetFile = new File(mTaskRecord.filePath);
|
||||
if (!targetFile.exists()) {
|
||||
FileUtil.createFile(targetFile);
|
||||
}
|
||||
|
||||
M3U8Entity m3U8Entity = ((DownloadEntity) getEntity()).getM3U8Entity();
|
||||
// 重新下载所有切片
|
||||
boolean reDownload =
|
||||
(m3U8Entity.getPeerNum() <= 0 || (m3U8Entity.isGenerateIndexFile() && !new File(
|
||||
(m3U8Entity.getPeerNum() <= 0 || (mOption.isGenerateIndexFile() && !new File(
|
||||
String.format(M3U8InfoThread.M3U8_INDEX_FORMAT, getEntity().getFilePath())).exists()));
|
||||
|
||||
for (ThreadRecord record : mTaskRecord.threadRecords) {
|
||||
File temp = new File(BaseM3U8Loader.getTsFilePath(cacheDir, record.threadId));
|
||||
if (!record.isComplete || reDownload) {
|
||||
if (temp.exists()) {
|
||||
temp.delete();
|
||||
FileUtil.deleteFile(temp);
|
||||
}
|
||||
record.startLocation = 0;
|
||||
//ALog.d(TAG, String.format("分片【%s】未完成,将重新下载该分片", record.threadId));
|
||||
@@ -112,17 +117,15 @@ public class M3U8RecordAdapter extends AbsRecordHandlerAdapter {
|
||||
record.filePath = getEntity().getFilePath();
|
||||
record.threadRecords = new ArrayList<>();
|
||||
record.threadNum = threadNum;
|
||||
record.isBlock = true;
|
||||
|
||||
int requestType = getWrapper().getRequestType();
|
||||
if (requestType == ITaskWrapper.M3U8_VOD) {
|
||||
record.taskType = TaskRecord.TYPE_M3U8_VOD;
|
||||
record.isOpenDynamicFile = true;
|
||||
record.bandWidth = mOption.getBandWidth();
|
||||
} else if (requestType == ITaskWrapper.M3U8_LIVE) {
|
||||
record.taskType = TaskRecord.TYPE_M3U8_LIVE;
|
||||
record.isOpenDynamicFile = true;
|
||||
record.bandWidth = mOption.getBandWidth();
|
||||
}
|
||||
record.bandWidth = mOption.getBandWidth();
|
||||
return record;
|
||||
}
|
||||
|
||||
|
||||
@@ -101,14 +101,14 @@ public class M3U8TaskOption implements ITaskOption {
|
||||
/**
|
||||
* 生成索引占位字段
|
||||
*/
|
||||
private boolean generateIndexFileTemp = false;
|
||||
private boolean generateIndexFile = false;
|
||||
|
||||
public boolean isGenerateIndexFileTemp() {
|
||||
return generateIndexFileTemp;
|
||||
public boolean isGenerateIndexFile() {
|
||||
return generateIndexFile;
|
||||
}
|
||||
|
||||
public void setGenerateIndexFileTemp(boolean generateIndexFileTemp) {
|
||||
this.generateIndexFileTemp = generateIndexFileTemp;
|
||||
public void setGenerateIndexFile(boolean generateIndexFile) {
|
||||
this.generateIndexFile = generateIndexFile;
|
||||
}
|
||||
|
||||
public int getJumpIndex() {
|
||||
|
||||
@@ -89,10 +89,18 @@ public class M3U8ThreadTaskAdapter extends AbsThreadTaskAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
int code = conn.getResponseCode();
|
||||
if (code != HttpURLConnection.HTTP_OK) {
|
||||
fail(new TaskException(TAG,
|
||||
String.format("连接错误,http错误码:%s,url:%s", code, getThreadConfig().url)),
|
||||
false);
|
||||
return;
|
||||
}
|
||||
|
||||
is = new BufferedInputStream(ConnectionHelp.convertInputStream(conn));
|
||||
if (mHttpTaskOption.isChunked()) {
|
||||
readChunked(is);
|
||||
} else if (getThreadConfig().isOpenDynamicFile) {
|
||||
} else if (getThreadConfig().isBlock) {
|
||||
readDynamicFile(is);
|
||||
}
|
||||
} catch (MalformedURLException e) {
|
||||
|
||||
@@ -24,17 +24,22 @@ import com.arialyy.aria.core.common.SubThreadConfig;
|
||||
import com.arialyy.aria.core.download.DTaskWrapper;
|
||||
import com.arialyy.aria.core.inf.IThreadState;
|
||||
import com.arialyy.aria.core.listener.IEventListener;
|
||||
import com.arialyy.aria.core.listener.ISchedulers;
|
||||
import com.arialyy.aria.core.manager.ThreadTaskManager;
|
||||
import com.arialyy.aria.core.processor.ITsMergeHandler;
|
||||
import com.arialyy.aria.core.task.ThreadTask;
|
||||
import com.arialyy.aria.m3u8.BaseM3U8Loader;
|
||||
import com.arialyy.aria.core.processor.ITsMergeHandler;
|
||||
import com.arialyy.aria.m3u8.IdGenerator;
|
||||
import com.arialyy.aria.m3u8.M3U8Listener;
|
||||
import com.arialyy.aria.m3u8.M3U8TaskOption;
|
||||
import com.arialyy.aria.m3u8.M3U8ThreadTaskAdapter;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.FileUtil;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
@@ -42,6 +47,8 @@ import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import static com.arialyy.aria.m3u8.M3U8InfoThread.M3U8_INDEX_FORMAT;
|
||||
|
||||
/**
|
||||
* M3U8点播文件下载器
|
||||
*/
|
||||
@@ -49,15 +56,21 @@ public class M3U8LiveLoader extends BaseM3U8Loader {
|
||||
/**
|
||||
* 最大执行数
|
||||
*/
|
||||
private static final int EXEC_MAX_NUM = 4;
|
||||
private static int EXEC_MAX_NUM = 4;
|
||||
private Handler mStateHandler;
|
||||
private ArrayBlockingQueue<Long> mFlagQueue = new ArrayBlockingQueue<>(EXEC_MAX_NUM);
|
||||
private ReentrantLock LOCK = new ReentrantLock();
|
||||
private Condition mCondition = LOCK.newCondition();
|
||||
private LinkedBlockingQueue<String> mPeerQueue = new LinkedBlockingQueue<>();
|
||||
private LinkedBlockingQueue<ExtInfo> mPeerQueue = new LinkedBlockingQueue<>();
|
||||
private ExtInfo mCurExtInfo;
|
||||
private FileOutputStream mIndexFos;
|
||||
|
||||
M3U8LiveLoader(M3U8Listener listener, DTaskWrapper wrapper) {
|
||||
super(listener, wrapper);
|
||||
if (((M3U8TaskOption) wrapper.getM3u8Option()).isGenerateIndexFile()) {
|
||||
ALog.i(TAG, "直播文件下载,创建索引文件的操作将导致只能同时下载一个切片");
|
||||
EXEC_MAX_NUM = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@Override protected IThreadState createStateManager(Looper looper) {
|
||||
@@ -66,8 +79,8 @@ public class M3U8LiveLoader extends BaseM3U8Loader {
|
||||
return manager;
|
||||
}
|
||||
|
||||
void offerPeer(String peerUrl) {
|
||||
mPeerQueue.offer(peerUrl);
|
||||
void offerPeer(ExtInfo extInfo) {
|
||||
mPeerQueue.offer(extInfo);
|
||||
}
|
||||
|
||||
@Override protected void handleTask() {
|
||||
@@ -80,13 +93,14 @@ public class M3U8LiveLoader extends BaseM3U8Loader {
|
||||
try {
|
||||
LOCK.lock();
|
||||
while (mFlagQueue.size() < EXEC_MAX_NUM) {
|
||||
String url = mPeerQueue.poll();
|
||||
if (url == null) {
|
||||
ExtInfo extInfo = mPeerQueue.poll();
|
||||
if (extInfo == null) {
|
||||
break;
|
||||
}
|
||||
ThreadTask task = createThreadTask(cacheDir, index, url);
|
||||
mCurExtInfo = extInfo;
|
||||
ThreadTask task = createThreadTask(cacheDir, index, extInfo.url);
|
||||
getTaskList().put(index, task);
|
||||
mFlagQueue.offer(startThreadTask(task));
|
||||
mFlagQueue.offer(startThreadTask(task, task.getConfig().peerIndex));
|
||||
index++;
|
||||
}
|
||||
if (mFlagQueue.size() > 0) {
|
||||
@@ -106,11 +120,15 @@ public class M3U8LiveLoader extends BaseM3U8Loader {
|
||||
return mTempFile.length();
|
||||
}
|
||||
|
||||
private void notifyLock() {
|
||||
private void notifyLock(boolean success, int peerId) {
|
||||
try {
|
||||
LOCK.lock();
|
||||
long id = mFlagQueue.take();
|
||||
ALog.d(TAG, String.format("线程【%s】完成", id));
|
||||
if (success) {
|
||||
ALog.d(TAG, String.format("切片【%s】下载成功", peerId));
|
||||
} else {
|
||||
ALog.e(TAG, String.format("切片【%s】下载失败", peerId));
|
||||
}
|
||||
mCondition.signalAll();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
@@ -119,13 +137,27 @@ public class M3U8LiveLoader extends BaseM3U8Loader {
|
||||
}
|
||||
}
|
||||
|
||||
@Override protected void onPostStop() {
|
||||
super.onPostStop();
|
||||
if (mIndexFos != null) {
|
||||
try {
|
||||
mIndexFos.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动线程任务
|
||||
*
|
||||
* @return 线程唯一id标志
|
||||
*/
|
||||
private long startThreadTask(ThreadTask task) {
|
||||
private long startThreadTask(ThreadTask task, int indexId) {
|
||||
ThreadTaskManager.getInstance().startThread(mTaskWrapper.getKey(), task);
|
||||
((M3U8Listener) mListener).onPeerStart(mTaskWrapper.getKey(),
|
||||
task.getConfig().tempFile.getPath(),
|
||||
indexId);
|
||||
return IdGenerator.getInstance().nextId();
|
||||
}
|
||||
|
||||
@@ -139,15 +171,16 @@ public class M3U8LiveLoader extends BaseM3U8Loader {
|
||||
record.tsUrl = tsUrl;
|
||||
record.threadType = TaskRecord.TYPE_M3U8_LIVE;
|
||||
record.threadId = indexId;
|
||||
mRecord.threadRecords.add(record);
|
||||
|
||||
SubThreadConfig config = new SubThreadConfig();
|
||||
config.url = tsUrl;
|
||||
config.tempFile = new File(getTsFilePath(cacheDir, indexId));
|
||||
config.isBlock = mRecord.isBlock;
|
||||
config.isOpenDynamicFile = mRecord.isOpenDynamicFile;
|
||||
config.taskWrapper = mTaskWrapper;
|
||||
config.record = record;
|
||||
config.stateHandler = mStateHandler;
|
||||
config.peerIndex = indexId;
|
||||
|
||||
if (!config.tempFile.exists()) {
|
||||
FileUtil.createFile(config.tempFile);
|
||||
@@ -163,10 +196,7 @@ public class M3U8LiveLoader extends BaseM3U8Loader {
|
||||
*
|
||||
* @return {@code true} 合并成功,{@code false}合并失败
|
||||
*/
|
||||
public boolean mergeFile() {
|
||||
if (getEntity().getM3U8Entity().isGenerateIndexFile()) {
|
||||
return generateIndexFile();
|
||||
}
|
||||
boolean mergeFile() {
|
||||
ITsMergeHandler mergeHandler = mM3U8Option.getMergeHandler();
|
||||
String cacheDir = getCacheDir();
|
||||
List<String> partPath = new ArrayList<>();
|
||||
@@ -213,7 +243,7 @@ public class M3U8LiveLoader extends BaseM3U8Loader {
|
||||
/**
|
||||
* 任务状态回调
|
||||
*/
|
||||
private IEventListener mListener;
|
||||
private M3U8Listener mListener;
|
||||
private long mProgress; //当前总进度
|
||||
private Looper mLooper;
|
||||
|
||||
@@ -222,7 +252,7 @@ public class M3U8LiveLoader extends BaseM3U8Loader {
|
||||
*/
|
||||
LiveStateManager(Looper looper, IEventListener listener) {
|
||||
mLooper = looper;
|
||||
mListener = listener;
|
||||
mListener = (M3U8Listener) listener;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -234,6 +264,7 @@ public class M3U8LiveLoader extends BaseM3U8Loader {
|
||||
}
|
||||
|
||||
@Override public boolean handleMessage(Message msg) {
|
||||
int peerIndex = msg.getData().getInt(ISchedulers.DATA_M3U8_PEER_INDEX);
|
||||
switch (msg.what) {
|
||||
case STATE_STOP:
|
||||
if (isBreak()) {
|
||||
@@ -248,15 +279,46 @@ public class M3U8LiveLoader extends BaseM3U8Loader {
|
||||
}
|
||||
break;
|
||||
case STATE_COMPLETE:
|
||||
notifyLock();
|
||||
notifyLock(true, peerIndex);
|
||||
if (mM3U8Option.isGenerateIndexFile() && !isBreak()) {
|
||||
addExtInf(mCurExtInfo.url, mCurExtInfo.extInf);
|
||||
}
|
||||
mListener.onPeerComplete(mTaskWrapper.getKey(),
|
||||
msg.getData().getString(ISchedulers.DATA_M3U8_PEER_PATH), peerIndex);
|
||||
break;
|
||||
case STATE_RUNNING:
|
||||
mProgress += (long) msg.obj;
|
||||
break;
|
||||
case STATE_FAIL:
|
||||
notifyLock(false, peerIndex);
|
||||
mListener.onPeerFail(mTaskWrapper.getKey(),
|
||||
msg.getData().getString(ISchedulers.DATA_M3U8_PEER_PATH), peerIndex);
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 给索引文件添加extInfo信息
|
||||
*/
|
||||
private void addExtInf(String url, String extInf) {
|
||||
File indexFile =
|
||||
new File(String.format(M3U8_INDEX_FORMAT, getEntity().getFilePath()));
|
||||
if (!indexFile.exists()) {
|
||||
ALog.e(TAG, String.format("索引文件【%s】不存在,添加peer的extInf失败", indexFile.getPath()));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (mIndexFos == null) {
|
||||
mIndexFos = new FileOutputStream(indexFile, true);
|
||||
}
|
||||
mIndexFos.write(extInf.concat("\r\n").getBytes(Charset.forName("UTF-8")));
|
||||
mIndexFos.write(url.concat("\r\n").getBytes(Charset.forName("UTF-8")));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override public boolean isFail() {
|
||||
return false;
|
||||
}
|
||||
@@ -269,4 +331,14 @@ public class M3U8LiveLoader extends BaseM3U8Loader {
|
||||
return mProgress;
|
||||
}
|
||||
}
|
||||
|
||||
static class ExtInfo {
|
||||
String url;
|
||||
String extInf;
|
||||
|
||||
ExtInfo(String url, String extInf) {
|
||||
this.url = url;
|
||||
this.extInf = extInf;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import com.arialyy.aria.core.processor.ILiveTsUrlConverter;
|
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
import com.arialyy.aria.exception.BaseException;
|
||||
import com.arialyy.aria.exception.M3U8Exception;
|
||||
import com.arialyy.aria.exception.TaskException;
|
||||
import com.arialyy.aria.http.HttpTaskOption;
|
||||
import com.arialyy.aria.m3u8.M3U8InfoThread;
|
||||
import com.arialyy.aria.m3u8.M3U8Listener;
|
||||
@@ -87,7 +88,7 @@ public class M3U8LiveUtil extends AbsNormalLoaderUtil {
|
||||
}
|
||||
});
|
||||
infoThread.setOnGetPeerCallback(new M3U8InfoThread.OnGetLivePeerCallback() {
|
||||
@Override public void onGetPeer(String url) {
|
||||
@Override public void onGetPeer(String url, String extInf) {
|
||||
if (mPeerUrls.contains(url)) {
|
||||
return;
|
||||
}
|
||||
@@ -104,7 +105,7 @@ public class M3U8LiveUtil extends AbsNormalLoaderUtil {
|
||||
fail(new M3U8Exception(TAG, String.format("ts地址错误,url:%s", url)), false);
|
||||
return;
|
||||
}
|
||||
getLoader().offerPeer(url);
|
||||
getLoader().offerPeer(new M3U8LiveLoader.ExtInfo(url, extInf));
|
||||
}
|
||||
});
|
||||
return infoThread;
|
||||
@@ -129,7 +130,13 @@ public class M3U8LiveUtil extends AbsNormalLoaderUtil {
|
||||
if (mInfoThread != null) {
|
||||
mInfoThread.setStop(true);
|
||||
closeTimer();
|
||||
if (mM3U8Option.isMergeFile()) {
|
||||
if (((M3U8TaskOption) getTaskWrapper().getM3u8Option()).isGenerateIndexFile()) {
|
||||
if (getLoader().generateIndexFile(true)) {
|
||||
getListener().onComplete();
|
||||
} else {
|
||||
getListener().onFail(false, new TaskException(TAG, "创建索引文件失败"));
|
||||
}
|
||||
} else if (mM3U8Option.isMergeFile()) {
|
||||
if (getLoader().mergeFile()) {
|
||||
getListener().onComplete();
|
||||
} else {
|
||||
|
||||
@@ -31,14 +31,16 @@ import com.arialyy.aria.core.inf.IThreadState;
|
||||
import com.arialyy.aria.core.listener.IEventListener;
|
||||
import com.arialyy.aria.core.listener.ISchedulers;
|
||||
import com.arialyy.aria.core.manager.ThreadTaskManager;
|
||||
import com.arialyy.aria.core.processor.ITsMergeHandler;
|
||||
import com.arialyy.aria.core.task.ThreadTask;
|
||||
import com.arialyy.aria.exception.BaseException;
|
||||
import com.arialyy.aria.exception.TaskException;
|
||||
import com.arialyy.aria.m3u8.BaseM3U8Loader;
|
||||
import com.arialyy.aria.core.processor.ITsMergeHandler;
|
||||
import com.arialyy.aria.m3u8.M3U8Listener;
|
||||
import com.arialyy.aria.m3u8.M3U8TaskOption;
|
||||
import com.arialyy.aria.m3u8.M3U8ThreadTaskAdapter;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import com.arialyy.aria.util.FileUtil;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
@@ -219,6 +221,12 @@ public class M3U8VodLoader extends BaseM3U8Loader {
|
||||
}
|
||||
}
|
||||
mManager.updateStateCount();
|
||||
if (mCompleteNum <= 0){
|
||||
mListener.onStart(0);
|
||||
}else {
|
||||
int percent = mCompleteNum * 100 / mRecord.threadRecords.size();
|
||||
mListener.onResume(percent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -428,7 +436,6 @@ public class M3U8VodLoader extends BaseM3U8Loader {
|
||||
config.url = record.tsUrl;
|
||||
config.tempFile = new File(BaseM3U8Loader.getTsFilePath(cacheDir, record.threadId));
|
||||
config.isBlock = mRecord.isBlock;
|
||||
config.isOpenDynamicFile = mRecord.isOpenDynamicFile;
|
||||
config.taskWrapper = mTaskWrapper;
|
||||
config.record = record;
|
||||
config.stateHandler = mStateHandler;
|
||||
@@ -446,7 +453,7 @@ public class M3U8VodLoader extends BaseM3U8Loader {
|
||||
* M3U8线程状态管理
|
||||
*/
|
||||
private class VodStateManager implements IThreadState {
|
||||
private final String TAG = "M3U8ThreadStateManager";
|
||||
private final String TAG = CommonUtil.getClassName(VodStateManager.class);
|
||||
|
||||
/**
|
||||
* 任务状态回调
|
||||
@@ -456,7 +463,8 @@ public class M3U8VodLoader extends BaseM3U8Loader {
|
||||
private int cancelNum = 0; // 已经取消的线程的数
|
||||
private int stopNum = 0; // 已经停止的线程数
|
||||
private int failNum = 0; // 失败的线程数
|
||||
private long progress; //当前总进度
|
||||
private long percent; //当前总进度,百分比进度
|
||||
private long progress;
|
||||
private TaskRecord taskRecord; // 任务记录
|
||||
private Looper looper;
|
||||
|
||||
@@ -473,6 +481,7 @@ public class M3U8VodLoader extends BaseM3U8Loader {
|
||||
}
|
||||
}
|
||||
this.listener = listener;
|
||||
progress = getEntity().getCurrentProgress();
|
||||
}
|
||||
|
||||
private void updateStateCount() {
|
||||
@@ -559,7 +568,14 @@ public class M3U8VodLoader extends BaseM3U8Loader {
|
||||
"startThreadNum = %s, stopNum = %s, cancelNum = %s, failNum = %s, completeNum = %s, flagQueueSize = %s",
|
||||
startThreadNum, stopNum, cancelNum, failNum, mCompleteNum, mFlagQueue.size()));
|
||||
ALog.d(TAG, String.format("vod任务【%s】完成", mTempFile.getName()));
|
||||
if (mM3U8Option.isMergeFile()) {
|
||||
|
||||
if (mM3U8Option.isGenerateIndexFile()) {
|
||||
if (generateIndexFile(false)){
|
||||
listener.onComplete();
|
||||
}else {
|
||||
listener.onFail(false, new TaskException(TAG, "创建索引文件失败"));
|
||||
}
|
||||
} else if (mM3U8Option.isMergeFile()) {
|
||||
if (mergeFile()) {
|
||||
listener.onComplete();
|
||||
} else {
|
||||
@@ -596,6 +612,7 @@ public class M3U8VodLoader extends BaseM3U8Loader {
|
||||
int percent = completeNum * 100 / taskRecord.threadRecords.size();
|
||||
getEntity().setPercent(percent);
|
||||
getEntity().update();
|
||||
this.percent = percent;
|
||||
}
|
||||
|
||||
@Override public boolean isFail() {
|
||||
@@ -625,9 +642,6 @@ public class M3U8VodLoader extends BaseM3U8Loader {
|
||||
* @return {@code true} 合并成功,{@code false}合并失败
|
||||
*/
|
||||
private boolean mergeFile() {
|
||||
if (getEntity().getM3U8Entity().isGenerateIndexFile()) {
|
||||
return generateIndexFile();
|
||||
}
|
||||
ITsMergeHandler mergeHandler = mM3U8Option.getMergeHandler();
|
||||
String cacheDir = getCacheDir();
|
||||
List<String> partPath = new ArrayList<>();
|
||||
|
||||
@@ -78,12 +78,6 @@ public class TaskRecord extends DbEntity {
|
||||
*/
|
||||
public boolean isBlock = false;
|
||||
|
||||
/**
|
||||
* 是否是使用虚拟文件下载的
|
||||
* {@code true}是,{@code false}不是
|
||||
*/
|
||||
public boolean isOpenDynamicFile = false;
|
||||
|
||||
/**
|
||||
* 线程类型
|
||||
* {@link #TYPE_HTTP_FTP}、{@link #TYPE_M3U8_VOD}
|
||||
|
||||
@@ -125,7 +125,6 @@ public class RecordHandler implements IRecordHandler {
|
||||
}
|
||||
mTaskWrapper.setNewTask(false);
|
||||
mTaskRecord = mAdapter.createTaskRecord(threadNum);
|
||||
mTaskRecord.isOpenDynamicFile = false;
|
||||
mTaskRecord.isBlock = false;
|
||||
File tempFile = new File(getFilePath());
|
||||
for (int i = 0; i < threadNum; i++) {
|
||||
|
||||
@@ -45,13 +45,13 @@ public class RecordHelper {
|
||||
/**
|
||||
* 处理非分块的,多线程任务
|
||||
*/
|
||||
public void handleMutilRecord() {
|
||||
public void handleMultiRecord() {
|
||||
// 默认线程分块长度
|
||||
long blockSize = mWrapper.getEntity().getFileSize() / mTaskRecord.threadRecords.size();
|
||||
File temp = new File(mTaskRecord.filePath);
|
||||
boolean fileExists = false;
|
||||
if (!temp.exists()) {
|
||||
BufferedRandomAccessFile tempFile = null;
|
||||
BufferedRandomAccessFile tempFile;
|
||||
try {
|
||||
tempFile = new BufferedRandomAccessFile(temp, "rw");
|
||||
tempFile.setLength(mWrapper.getEntity().getFileSize());
|
||||
@@ -145,10 +145,10 @@ public class RecordHelper {
|
||||
tr.startLocation = 0;
|
||||
tr.isComplete = false;
|
||||
tr.endLocation = mWrapper.getEntity().getFileSize();
|
||||
} else if (mTaskRecord.isOpenDynamicFile) {
|
||||
} else if (mTaskRecord.isBlock) {
|
||||
if (file.length() > mWrapper.getEntity().getFileSize()) {
|
||||
ALog.i(TAG, String.format("文件【%s】错误,任务重新开始", file.getPath()));
|
||||
file.delete();
|
||||
FileUtil.deleteFile(file);
|
||||
tr.startLocation = 0;
|
||||
tr.isComplete = false;
|
||||
tr.endLocation = mWrapper.getEntity().getFileSize();
|
||||
|
||||
@@ -35,8 +35,6 @@ public class SubThreadConfig {
|
||||
public ThreadRecord record;
|
||||
// 状态处理器
|
||||
public Handler stateHandler;
|
||||
// 动态文件
|
||||
public boolean isOpenDynamicFile;
|
||||
// m3u8切片索引
|
||||
public int peerIndex;
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
package com.arialyy.aria.core.download;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.text.TextUtils;
|
||||
import com.arialyy.aria.core.common.AbsGroupEntity;
|
||||
import com.arialyy.aria.core.wrapper.ITaskWrapper;
|
||||
import com.arialyy.aria.orm.annotation.Ignore;
|
||||
@@ -48,7 +49,12 @@ public class DownloadGroupEntity extends AbsGroupEntity {
|
||||
}
|
||||
|
||||
@Override public int getTaskType() {
|
||||
return getKey().startsWith("ftp") ? ITaskWrapper.D_FTP_DIR : ITaskWrapper.DG_HTTP;
|
||||
if (getSubEntities() == null || getSubEntities().isEmpty() || TextUtils.isEmpty(
|
||||
getSubEntities().get(0).getUrl())) {
|
||||
return ITaskWrapper.ERROR;
|
||||
}
|
||||
return getSubEntities().get(0).getUrl().startsWith("ftp") ? ITaskWrapper.D_FTP_DIR
|
||||
: ITaskWrapper.DG_HTTP;
|
||||
}
|
||||
|
||||
public DownloadGroupEntity() {
|
||||
|
||||
@@ -58,11 +58,6 @@ public class M3U8Entity extends DbEntity implements Parcelable {
|
||||
*/
|
||||
private String cacheDir;
|
||||
|
||||
/**
|
||||
* 生成索引
|
||||
*/
|
||||
private boolean generateIndexFile;
|
||||
|
||||
/**
|
||||
* 加密key保存地址
|
||||
*/
|
||||
@@ -115,14 +110,6 @@ public class M3U8Entity extends DbEntity implements Parcelable {
|
||||
this.iv = iv;
|
||||
}
|
||||
|
||||
public boolean isGenerateIndexFile() {
|
||||
return generateIndexFile;
|
||||
}
|
||||
|
||||
public void setGenerateIndexFile(boolean generateIndexFile) {
|
||||
this.generateIndexFile = generateIndexFile;
|
||||
}
|
||||
|
||||
public boolean isLive() {
|
||||
return isLive;
|
||||
}
|
||||
@@ -248,7 +235,6 @@ public class M3U8Entity extends DbEntity implements Parcelable {
|
||||
dest.writeInt(this.peerNum);
|
||||
dest.writeByte(this.isLive ? (byte) 1 : (byte) 0);
|
||||
dest.writeString(this.cacheDir);
|
||||
dest.writeByte(this.generateIndexFile ? (byte) 1 : (byte) 0);
|
||||
dest.writeString(this.keyPath);
|
||||
dest.writeString(this.keyUrl);
|
||||
dest.writeString(this.method);
|
||||
@@ -261,7 +247,6 @@ public class M3U8Entity extends DbEntity implements Parcelable {
|
||||
this.peerNum = in.readInt();
|
||||
this.isLive = in.readByte() != 0;
|
||||
this.cacheDir = in.readString();
|
||||
this.generateIndexFile = in.readByte() != 0;
|
||||
this.keyPath = in.readString();
|
||||
this.keyUrl = in.readString();
|
||||
this.method = in.readString();
|
||||
|
||||
@@ -80,9 +80,8 @@ public abstract class AbsGroupUtil implements IUtil, Runnable {
|
||||
/**
|
||||
* 初始化组合任务状态
|
||||
*/
|
||||
protected void initState() {
|
||||
mState = new GroupRunState(getWrapper().getKey(), mListener,
|
||||
mGTWrapper.getSubTaskWrapper().size(), mSubQueue);
|
||||
private void initState() {
|
||||
mState = new GroupRunState(getWrapper().getKey(), mListener, mSubQueue);
|
||||
for (DTaskWrapper wrapper : mGTWrapper.getSubTaskWrapper()) {
|
||||
if (wrapper.getEntity().getState() == IEntity.STATE_COMPLETE) {
|
||||
mState.updateCompleteNum();
|
||||
|
||||
@@ -112,30 +112,4 @@ public abstract class AbsSubDLoadUtil implements IUtil {
|
||||
mSchedulers.obtainMessage(ISchedulers.STOP, this).sendToTarget();
|
||||
}
|
||||
}
|
||||
|
||||
//@Override public void start() {
|
||||
// if (mWrapper.getRequestType() == ITaskWrapper.D_HTTP) {
|
||||
// if (needGetInfo) {
|
||||
// new Thread(new HttpFileInfoThread(mWrapper, new OnFileInfoCallback() {
|
||||
//
|
||||
// @Override public void onComplete(String url, CompleteInfo info) {
|
||||
// mDLoader = new Downloader(mListener, mWrapper);
|
||||
// mDLoader.start();
|
||||
// }
|
||||
//
|
||||
// @Override public void onFail(AbsEntity entity, BaseException e, boolean needRetry) {
|
||||
// mSchedulers.obtainMessage(ISchedulers.FAIL, SubDLoadUtil.this).sendToTarget();
|
||||
// }
|
||||
// })).start();
|
||||
// } else {
|
||||
// mDLoader = new Downloader(mListener, mWrapper);
|
||||
// mDLoader.start();
|
||||
// }
|
||||
// } else if (mWrapper.getRequestType() == ITaskWrapper.D_FTP) {
|
||||
// mDLoader = new Downloader(mListener, mWrapper);
|
||||
// mDLoader.start();
|
||||
// } else {
|
||||
// ALog.w(TAG, String.format("不识别的类型,requestType:%s", mWrapper.getRequestType()));
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
@@ -72,14 +72,16 @@ public class GroupRunState {
|
||||
|
||||
private String mGroupHash;
|
||||
|
||||
GroupRunState(String groupHash, IDGroupListener listener, int subSize,
|
||||
SimpleSubQueue queue) {
|
||||
GroupRunState(String groupHash, IDGroupListener listener, SimpleSubQueue queue) {
|
||||
this.listener = listener;
|
||||
this.queue = queue;
|
||||
mSubSize = subSize;
|
||||
mGroupHash = groupHash;
|
||||
}
|
||||
|
||||
public void setSubSize(int subSize){
|
||||
mSubSize = subSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* 组合任务是否正在自行
|
||||
*
|
||||
|
||||
@@ -142,7 +142,6 @@ public class NormalLoader extends AbsLoader {
|
||||
String.format(IRecordHandler.SUB_PATH, mTempFile.getPath(), record.threadId))
|
||||
: mTempFile;
|
||||
config.isBlock = mRecord.isBlock;
|
||||
config.isOpenDynamicFile = mRecord.isOpenDynamicFile;
|
||||
config.startThreadNum = startNum;
|
||||
config.taskWrapper = mTaskWrapper;
|
||||
config.record = record;
|
||||
@@ -200,8 +199,7 @@ public class NormalLoader extends AbsLoader {
|
||||
ALog.d(TAG, String.format("进度修正,当前进度:%s", currentProgress));
|
||||
getEntity().setCurrentProgress(currentProgress);
|
||||
}
|
||||
mStateHandler.obtainMessage(IThreadState.STATE_UPDATE_PROGRESS, currentProgress)
|
||||
.sendToTarget();
|
||||
mStateManager.updateProgress(currentProgress);
|
||||
startThreadTask();
|
||||
}
|
||||
|
||||
|
||||
@@ -19,9 +19,9 @@ import android.os.Bundle;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import com.arialyy.aria.core.TaskRecord;
|
||||
import com.arialyy.aria.core.listener.IEventListener;
|
||||
import com.arialyy.aria.core.inf.IRecordHandler;
|
||||
import com.arialyy.aria.core.inf.IThreadState;
|
||||
import com.arialyy.aria.core.listener.IEventListener;
|
||||
import com.arialyy.aria.exception.BaseException;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.FileUtil;
|
||||
@@ -59,6 +59,13 @@ public class ThreadStateManager implements IThreadState {
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* 不要使用handle更新启动线程的进度,因为有延迟
|
||||
*/
|
||||
void updateProgress(long curProgress) {
|
||||
mProgress = curProgress;
|
||||
}
|
||||
|
||||
@Override public boolean handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case STATE_STOP:
|
||||
|
||||
@@ -22,7 +22,7 @@ import com.arialyy.aria.util.CommonUtil;
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* 但文件任务适配器
|
||||
* 单文件任务适配器
|
||||
*
|
||||
* @Author lyy
|
||||
* @Date 2019-09-19
|
||||
|
||||
@@ -34,10 +34,6 @@ public abstract class AbsThreadTaskAdapter implements IThreadTaskAdapter {
|
||||
* 速度限制工具
|
||||
*/
|
||||
protected BandwidthLimiter mSpeedBandUtil;
|
||||
/**
|
||||
* 当前线程的下去区间的进度
|
||||
*/
|
||||
private long mRangeProgress;
|
||||
private ThreadRecord mThreadRecord;
|
||||
private IThreadTaskObserver mObserver;
|
||||
private AbsTaskWrapper mWrapper;
|
||||
@@ -48,7 +44,6 @@ public abstract class AbsThreadTaskAdapter implements IThreadTaskAdapter {
|
||||
mThreadRecord = config.record;
|
||||
mWrapper = config.taskWrapper;
|
||||
mThreadConfig = config;
|
||||
mRangeProgress = mThreadRecord.startLocation;
|
||||
if (getTaskConfig().getMaxSpeed() > 0) {
|
||||
mSpeedBandUtil = new BandwidthLimiter(getTaskConfig().getMaxSpeed(), config.startThreadNum);
|
||||
}
|
||||
@@ -68,7 +63,7 @@ public abstract class AbsThreadTaskAdapter implements IThreadTaskAdapter {
|
||||
* 当前线程的下去区间的进度
|
||||
*/
|
||||
protected long getRangeProgress() {
|
||||
return mRangeProgress;
|
||||
return mObserver.getThreadProgress();
|
||||
}
|
||||
|
||||
protected ThreadRecord getThreadRecord() {
|
||||
@@ -97,7 +92,7 @@ public abstract class AbsThreadTaskAdapter implements IThreadTaskAdapter {
|
||||
return mThreadConfig;
|
||||
}
|
||||
|
||||
@Override public void setThreadStateObserver(IThreadTaskObserver observer) {
|
||||
@Override public void attach(IThreadTaskObserver observer) {
|
||||
mObserver = observer;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ public interface IThreadTaskAdapter {
|
||||
void setMaxSpeed(int speed);
|
||||
|
||||
/**
|
||||
* 设置线程任务状态观察者
|
||||
* 注册观察者
|
||||
*/
|
||||
void setThreadStateObserver(IThreadTaskObserver observer);
|
||||
void attach(IThreadTaskObserver observer);
|
||||
}
|
||||
|
||||
@@ -53,4 +53,9 @@ public interface IThreadTaskObserver {
|
||||
* @param len 新增的长度
|
||||
*/
|
||||
void updateProgress(long len);
|
||||
|
||||
/**
|
||||
* 获取线程当前进度
|
||||
*/
|
||||
long getThreadProgress();
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import com.arialyy.aria.core.wrapper.ITaskWrapper;
|
||||
import com.arialyy.aria.exception.BaseException;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.BufferedRandomAccessFile;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import com.arialyy.aria.util.ErrorHelp;
|
||||
import com.arialyy.aria.util.FileUtil;
|
||||
import com.arialyy.aria.util.NetUtils;
|
||||
@@ -49,7 +50,7 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver {
|
||||
* 线程重试次数
|
||||
*/
|
||||
private final int RETRY_NUM = 2;
|
||||
private final String TAG = "AbsThreadTask";
|
||||
private final String TAG = CommonUtil.getClassName(getClass());
|
||||
private IEntity mEntity;
|
||||
protected AbsTaskWrapper mTaskWrapper;
|
||||
private int mFailTimes = 0;
|
||||
@@ -94,7 +95,7 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver {
|
||||
*/
|
||||
public void setAdapter(IThreadTaskAdapter adapter) {
|
||||
mAdapter = adapter;
|
||||
mAdapter.setThreadStateObserver(this);
|
||||
mAdapter.attach(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -317,6 +318,11 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getThreadProgress() {
|
||||
return mRangeProgress;
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消任务
|
||||
*/
|
||||
@@ -335,7 +341,7 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver {
|
||||
*/
|
||||
protected void fail(final long subCurrentLocation, BaseException ex, boolean needRetry) {
|
||||
if (ex != null) {
|
||||
ALog.e(TAG, ALog.getExceptionString(ex));
|
||||
ex.printStackTrace();
|
||||
}
|
||||
if (mTaskWrapper.getRequestType() == ITaskWrapper.M3U8_VOD) {
|
||||
writeConfig(false, 0);
|
||||
@@ -462,8 +468,6 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver {
|
||||
if (mRecord != null) {
|
||||
mRecord.isComplete = isComplete;
|
||||
if (mConfig.isBlock) {
|
||||
mRecord.startLocation = record;
|
||||
} else if (mConfig.isOpenDynamicFile) {
|
||||
mRecord.startLocation = mConfig.tempFile.length();
|
||||
} else {
|
||||
if (0 < record && record < mRecord.endLocation) {
|
||||
|
||||
@@ -29,6 +29,11 @@ public class UTaskWrapper extends AbsTaskWrapper<UploadEntity> {
|
||||
*/
|
||||
private String tempUrl;
|
||||
|
||||
/**
|
||||
* 如果文件路径被其它任务占用,设置为true时,删除其它任务
|
||||
*/
|
||||
private boolean forceUpload = false;
|
||||
|
||||
public UTaskWrapper(UploadEntity entity) {
|
||||
super(entity);
|
||||
}
|
||||
@@ -48,6 +53,14 @@ public class UTaskWrapper extends AbsTaskWrapper<UploadEntity> {
|
||||
return getEntity().getKey();
|
||||
}
|
||||
|
||||
public boolean isForceUpload() {
|
||||
return forceUpload;
|
||||
}
|
||||
|
||||
public void setForceUpload(boolean forceUpload) {
|
||||
this.forceUpload = forceUpload;
|
||||
}
|
||||
|
||||
@Override public UploadConfig getConfig() {
|
||||
return Configuration.getInstance().uploadCfg;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ package com.arialyy.aria.core.upload;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.text.TextUtils;
|
||||
import com.arialyy.aria.core.common.AbsNormalEntity;
|
||||
import com.arialyy.aria.core.wrapper.ITaskWrapper;
|
||||
import com.arialyy.aria.orm.annotation.Primary;
|
||||
@@ -58,7 +59,10 @@ public class UploadEntity extends AbsNormalEntity implements Parcelable {
|
||||
}
|
||||
|
||||
@Override public int getTaskType() {
|
||||
return getUrl().startsWith("ftp") ? ITaskWrapper.D_FTP : ITaskWrapper.D_HTTP;
|
||||
if (TextUtils.isEmpty(getUrl())){
|
||||
return ITaskWrapper.ERROR;
|
||||
}
|
||||
return getUrl().startsWith("ftp") ? ITaskWrapper.U_FTP : ITaskWrapper.U_HTTP;
|
||||
}
|
||||
|
||||
public UploadEntity() {
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.arialyy.aria.core.event.ErrorEvent;
|
||||
import com.arialyy.aria.core.inf.IEntity;
|
||||
import com.arialyy.aria.core.inf.ITaskOption;
|
||||
import com.arialyy.aria.core.upload.UploadEntity;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.ComponentUtil;
|
||||
|
||||
/**
|
||||
|
||||
@@ -34,7 +34,7 @@ class DBConfig {
|
||||
static boolean DEBUG = false;
|
||||
static Map<String, Class> mapping = new LinkedHashMap<>();
|
||||
static String DB_NAME;
|
||||
static int VERSION = 55;
|
||||
static int VERSION = 56;
|
||||
|
||||
/**
|
||||
* 是否将数据库保存在Sd卡,{@code true} 是
|
||||
|
||||
@@ -76,9 +76,6 @@ final class SqlHelper extends SQLiteOpenHelper {
|
||||
// 需要使用如下语句:
|
||||
db.execSQL("PRAGMA foreign_keys=ON;");
|
||||
}
|
||||
if (DBConfig.DEBUG) {
|
||||
db.enableWriteAheadLogging();
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void onCreate(SQLiteDatabase db) {
|
||||
@@ -139,6 +136,7 @@ final class SqlHelper extends SQLiteOpenHelper {
|
||||
SQLiteDatabase.CREATE_IF_NECESSARY);
|
||||
}
|
||||
}
|
||||
db.enableWriteAheadLogging();
|
||||
return db;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,10 @@
|
||||
package com.arialyy.aria.util;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import com.arialyy.aria.core.download.DownloadEntity;
|
||||
import com.arialyy.aria.core.inf.IRecordHandler;
|
||||
import com.arialyy.aria.core.upload.UploadEntity;
|
||||
import com.arialyy.aria.orm.DbEntity;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.List;
|
||||
|
||||
@@ -27,6 +31,48 @@ import java.util.List;
|
||||
public class CheckUtil {
|
||||
private static final String TAG = "CheckUtil";
|
||||
|
||||
/**
|
||||
* 检查和处理路径冲突
|
||||
*
|
||||
* @param isForceDownload true,如果路径冲突,将删除其它任务的记录的
|
||||
* @param filePath 文件保存路径
|
||||
* @return false 任务不再执行,true 任务继续执行
|
||||
*/
|
||||
public static boolean checkDownloadPathConflicts(boolean isForceDownload, String filePath) {
|
||||
if (DbEntity.checkDataExist(DownloadEntity.class, "downloadPath=?", filePath)) {
|
||||
if (!isForceDownload) {
|
||||
ALog.e(TAG, String.format("下载失败,保存路径【%s】已经被其它任务占用,请设置其它保存路径", filePath));
|
||||
return false;
|
||||
} else {
|
||||
ALog.w(TAG, String.format("保存路径【%s】已经被其它任务占用,当前任务将覆盖该路径的文件", filePath));
|
||||
RecordUtil.delTaskRecord(filePath, IRecordHandler.TYPE_DOWNLOAD);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查和处理路径冲突
|
||||
*
|
||||
* @param isForceUpload true,如果路径冲突,将删除其它任务的记录的
|
||||
* @param filePath 文件保存路径
|
||||
* @return false 任务不再执行,true 任务继续执行
|
||||
*/
|
||||
public static boolean checkUploadPathConflicts(boolean isForceUpload, String filePath) {
|
||||
if (DbEntity.checkDataExist(UploadEntity.class, "filePath=?", filePath)) {
|
||||
if (!isForceUpload) {
|
||||
ALog.e(TAG, String.format("上传失败,文件路径【%s】已经被其它任务占用,请设置其它保存路径", filePath));
|
||||
return false;
|
||||
} else {
|
||||
ALog.w(TAG, String.format("文件路径【%s】已经被其它任务占用,当前任务将覆盖该路径的文件", filePath));
|
||||
RecordUtil.delTaskRecord(filePath, IRecordHandler.TYPE_UPLOAD);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查成员类是否是静态和public
|
||||
*/
|
||||
|
||||
@@ -50,17 +50,7 @@ public class ErrorHelp {
|
||||
CommonUtil.getAppPath(AriaConfig.getInstance().getAPP()),
|
||||
getData("yyyy-MM-dd_HH_mm_ss"));
|
||||
|
||||
File log = new File(path);
|
||||
if (!log.getParentFile().exists()) {
|
||||
log.getParentFile().mkdirs();
|
||||
}
|
||||
if (!log.exists()) {
|
||||
try {
|
||||
log.createNewFile();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
FileUtil.createFile(path);
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
@@ -128,7 +128,7 @@ public class RecordUtil {
|
||||
filePath = ((DownloadEntity) entity).getDownloadPath();
|
||||
} else if (entity instanceof UploadEntity) {
|
||||
type = IRecordHandler.TYPE_UPLOAD;
|
||||
filePath = ((UploadEntity) entity).getFilePath();
|
||||
filePath = entity.getFilePath();
|
||||
} else {
|
||||
ALog.w(TAG, "删除记录失败,未知类型");
|
||||
return;
|
||||
@@ -295,7 +295,7 @@ public class RecordUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除ts文件
|
||||
* 删除ts文件,和索引文件(如果有的话)
|
||||
*/
|
||||
private static void removeTsCache(File targetFile, long bandWidth) {
|
||||
|
||||
@@ -321,6 +321,12 @@ public class RecordUtil {
|
||||
cDir.delete();
|
||||
}
|
||||
}
|
||||
|
||||
File indexFile = new File(String.format("%s.index", targetFile.getPath()));
|
||||
|
||||
if (indexFile.exists()) {
|
||||
indexFile.delete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
33
README.md
33
README.md
@@ -23,7 +23,7 @@ Aria有以下特点:
|
||||
|
||||
[怎样使用Aria?](#使用)
|
||||
|
||||
如果你觉得Aria对你有帮助,您的star和issues将是对我最大支持.`^_^`
|
||||
如果你觉得Aria对你有帮助,你的star和issues将是对我最大支持,当然,也非常欢迎你能PR,[PR方法](https://www.zhihu.com/question/21682976/answer/79489643)`^_^`
|
||||
|
||||
## 示例
|
||||
* 多任务下载
|
||||
@@ -44,20 +44,20 @@ Aria有以下特点:
|
||||
|
||||
## 引入库
|
||||
[](https://github.com/AriaLyy/Aria/blob/master/LICENSE)
|
||||
[](https://github.com/AriaLyy/Aria)
|
||||
[](https://github.com/AriaLyy/Aria)
|
||||
[](https://github.com/AriaLyy/Aria)
|
||||
[](https://github.com/AriaLyy/Aria)
|
||||
[](https://github.com/AriaLyy/Aria)
|
||||
[](https://github.com/AriaLyy/Aria)
|
||||
[](https://github.com/AriaLyy/Aria)
|
||||
[](https://github.com/AriaLyy/Aria)
|
||||
|
||||
```java
|
||||
implementation 'com.arialyy.aria:core:3.7.4'
|
||||
annotationProcessor 'com.arialyy.aria:compiler:3.7.4'
|
||||
implementation 'com.arialyy.aria:ftpComponent:3.7.4' # 如果需要使用ftp,请增加该组件
|
||||
implementation 'com.arialyy.aria:m3u8Component:3.7.4' # 如果需要使用m3u8下载功能,请增加该组件
|
||||
implementation 'com.arialyy.aria:core:3.7.8-pre-3'
|
||||
annotationProcessor 'com.arialyy.aria:compiler:3.7.8-pre-3'
|
||||
implementation 'com.arialyy.aria:ftpComponent:3.7.8-pre-3' # 如果需要使用ftp,请增加该组件
|
||||
implementation 'com.arialyy.aria:m3u8Component:3.7.8-pre-3' # 如果需要使用m3u8下载功能,请增加该组件
|
||||
```
|
||||
如果出现android support依赖错误,请将 `compile 'com.arialyy.aria:core:<last-version>'`替换为
|
||||
```
|
||||
api('com.arialyy.aria:aria-core:<last-version>'){
|
||||
api('com.arialyy.aria:core:<last-version>'){
|
||||
exclude group: 'androidx.appcompat.app'
|
||||
}
|
||||
```
|
||||
@@ -65,7 +65,7 @@ api('com.arialyy.aria:aria-core:<last-version>'){
|
||||
|
||||
__⚠️注意:3.5.4以下版本升级时,需要更新[配置文件](https://aria.laoyuyu.me/aria_doc/start/config.html)!!__
|
||||
|
||||
__⚠️注意:3.7 以上版本已经适配了AndroidX__
|
||||
__⚠️注意:3.7 以上版本已经适配了AndroidX,如果是使用support库的,可使用[老版本](https://github.com/AriaLyy/Aria/tree/v3.6.6)__
|
||||
|
||||
***
|
||||
## 使用
|
||||
@@ -137,10 +137,8 @@ protected void onCreate(Bundle savedInstanceState) {
|
||||
|
||||
|
||||
### 版本日志
|
||||
+ v_3.7.4 (2019/11/2)
|
||||
- 修复一个class被莫名改变的问题
|
||||
- 修复非分块模式下导致的一个下载失败问题
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/493
|
||||
+ v_3.7.8-pre-1 (2019/11/20)
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/526
|
||||
|
||||
[更多版本记录](https://github.com/AriaLyy/Aria/blob/master/DEV_LOG.md)
|
||||
|
||||
@@ -163,6 +161,11 @@ protected void onCreate(Bundle savedInstanceState) {
|
||||
有任何问题,可以在[issues](https://github.com/AriaLyy/Aria/issues)给我留言反馈。</br>
|
||||
在提交问题前,希望你已经查看过[wiki](https://aria.laoyuyu.me/aria_doc/)或搜索过[issues](https://github.com/AriaLyy/Aria/issues)。</br>
|
||||
|
||||
## 打赏
|
||||
如果觉得框架写的不错并且帮助到了你,可以请我喝杯热茶。`^_^`</br>
|
||||
<img src="https://raw.githubusercontent.com/AriaLyy/Aria/master/img/ali_pay.png" width=336 height=336/>
|
||||
<img src="https://raw.githubusercontent.com/AriaLyy/Aria/master/img/wx_pay.png" width=336 height=336/>
|
||||
|
||||
***
|
||||
|
||||
License
|
||||
|
||||
@@ -29,5 +29,5 @@ dependencies {
|
||||
implementation "com.jcraft:jsch:0.1.55"
|
||||
implementation "com.jcraft:jzlib:1.1.3"
|
||||
implementation project(path: ':FtpComponent')
|
||||
compile project(path: ':PublicComponent')
|
||||
implementation project(path: ':PublicComponent')
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.arialyy.aria.sftp;
|
||||
|
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* sftp文件信息适配器
|
||||
*/
|
||||
public abstract class BaseInfoThreadAdapter<WRAPPER extends AbsTaskWrapper> {
|
||||
|
||||
private WRAPPER mWrapper;
|
||||
|
||||
public BaseInfoThreadAdapter(WRAPPER taskWrapper) {
|
||||
mWrapper = taskWrapper;
|
||||
}
|
||||
|
||||
public WRAPPER getWrapper() {
|
||||
return mWrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理文件
|
||||
*
|
||||
* @return true 处理文件成功,false 处理文件失败,结束任务
|
||||
*/
|
||||
protected abstract boolean handlerFile(Vector vector);
|
||||
}
|
||||
@@ -16,19 +16,25 @@
|
||||
package com.arialyy.aria.sftp;
|
||||
|
||||
import com.arialyy.aria.core.AriaConfig;
|
||||
import com.arialyy.aria.core.common.AbsEntity;
|
||||
import com.arialyy.aria.core.FtpUrlEntity;
|
||||
import com.arialyy.aria.core.common.AbsNormalEntity;
|
||||
import com.arialyy.aria.core.inf.OnFileInfoCallback;
|
||||
import com.arialyy.aria.core.upload.UploadEntity;
|
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
import com.arialyy.aria.ftp.FtpTaskOption;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import com.jcraft.jsch.ChannelSftp;
|
||||
import com.jcraft.jsch.JSchException;
|
||||
import com.jcraft.jsch.SftpException;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
*
|
||||
* https://cloud.tencent.com/developer/article/1354612
|
||||
*
|
||||
* @author lyy
|
||||
*/
|
||||
public class AbsSFtpInfoThread<ENTITY extends AbsEntity, TASK_WRAPPER extends AbsTaskWrapper<ENTITY>>
|
||||
public class SFtpInfoThread<ENTITY extends AbsNormalEntity, TASK_WRAPPER extends AbsTaskWrapper<ENTITY>>
|
||||
implements Runnable {
|
||||
|
||||
private final String TAG = CommonUtil.getClassName(getClass());
|
||||
@@ -40,8 +46,12 @@ public class AbsSFtpInfoThread<ENTITY extends AbsEntity, TASK_WRAPPER extends Ab
|
||||
protected long mSize = 0;
|
||||
protected String charSet = "UTF-8";
|
||||
private boolean isUpload = false;
|
||||
private SFtpUtil mSFtpUtil;
|
||||
private BaseInfoThreadAdapter mAdapter;
|
||||
|
||||
public AbsSFtpInfoThread(TASK_WRAPPER taskWrapper, OnFileInfoCallback callback) {
|
||||
public SFtpInfoThread(SFtpUtil ftpUtil, TASK_WRAPPER taskWrapper,
|
||||
OnFileInfoCallback callback) {
|
||||
mSFtpUtil = ftpUtil;
|
||||
mTaskWrapper = taskWrapper;
|
||||
mEntity = taskWrapper.getEntity();
|
||||
mTaskOption = (FtpTaskOption) taskWrapper.getTaskOption();
|
||||
@@ -52,7 +62,39 @@ public class AbsSFtpInfoThread<ENTITY extends AbsEntity, TASK_WRAPPER extends Ab
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void run() {
|
||||
public void setAdapter(BaseInfoThreadAdapter adapter) {
|
||||
mAdapter = adapter;
|
||||
}
|
||||
|
||||
@Override public void run() {
|
||||
if (mAdapter == null) {
|
||||
ALog.e(TAG, "adapter为空");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
ChannelSftp channelSftp =
|
||||
(ChannelSftp) mSFtpUtil.getSession().openChannel(SFtpUtil.CMD_TYPE_SFTP);
|
||||
Vector files = channelSftp.ls(getUrlEntity().remotePath);
|
||||
|
||||
if (files.isEmpty()) {
|
||||
ALog.e(TAG, String.format("路径【%s】没有文件", getUrlEntity().remotePath));
|
||||
mCallback.onFail(mEntity, null, false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mAdapter.handlerFile(files)) {
|
||||
ALog.e(TAG, "文件处理失败");
|
||||
mCallback.onFail(mEntity, null, false);
|
||||
return;
|
||||
}
|
||||
} catch (JSchException ex) {
|
||||
ex.printStackTrace();
|
||||
} catch (SftpException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private FtpUrlEntity getUrlEntity() {
|
||||
return mTaskOption.getUrlEntity();
|
||||
}
|
||||
}
|
||||
@@ -16,24 +16,39 @@
|
||||
package com.arialyy.aria.sftp;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import com.jcraft.jsch.ChannelExec;
|
||||
import com.jcraft.jsch.JSch;
|
||||
import com.jcraft.jsch.JSchException;
|
||||
import com.jcraft.jsch.Session;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* sftp登录
|
||||
* sftp工具类
|
||||
*
|
||||
* @author lyy
|
||||
*/
|
||||
public class SFtpLogin {
|
||||
|
||||
public class SFtpUtil {
|
||||
private final String TAG = CommonUtil.getClassName(getClass());
|
||||
/**
|
||||
* 用于执行命令
|
||||
*/
|
||||
public static final String CMD_TYPE_EXEC = "exec";
|
||||
/**
|
||||
* 用于处理文件
|
||||
*/
|
||||
public static final String CMD_TYPE_SFTP = "sftp";
|
||||
private String ip, userName, password;
|
||||
private int port;
|
||||
private Session session;
|
||||
private boolean isLogin = false;
|
||||
|
||||
private SFtpLogin() {
|
||||
private SFtpUtil() {
|
||||
createClient();
|
||||
}
|
||||
|
||||
@@ -55,6 +70,7 @@ public class SFtpLogin {
|
||||
config.put("StrictHostKeyChecking", "no");
|
||||
session.setConfig(config);// 为Session对象设置properties
|
||||
session.setTimeout(3000);// 设置超时
|
||||
login();
|
||||
isLogin = true;
|
||||
} catch (JSchException e) {
|
||||
e.printStackTrace();
|
||||
@@ -83,6 +99,65 @@ public class SFtpLogin {
|
||||
isLogin = false;
|
||||
}
|
||||
|
||||
public Session getSession() {
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行命令
|
||||
*
|
||||
* @param cmd sftp命令
|
||||
*/
|
||||
public void execCommand(String cmd) {
|
||||
if (TextUtils.isEmpty(cmd)) {
|
||||
ALog.e(TAG, "命令为空");
|
||||
return;
|
||||
}
|
||||
if (!isLogin) {
|
||||
ALog.e(TAG, "没有登录");
|
||||
return;
|
||||
}
|
||||
ChannelExec channel = null;
|
||||
try {
|
||||
channel = (ChannelExec) session.openChannel(CMD_TYPE_EXEC);
|
||||
channel.setCommand(cmd);
|
||||
channel.connect();
|
||||
String rst = getResult(channel.getInputStream());
|
||||
|
||||
ALog.i(TAG, String.format("result: %s", rst));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} catch (JSchException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (channel != null) {
|
||||
channel.disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行命令后,获取服务器端返回的数据
|
||||
*
|
||||
* @return 服务器端返回的数据
|
||||
*/
|
||||
private String getResult(InputStream in) throws IOException {
|
||||
if (in == null){
|
||||
ALog.e(TAG, "输入流为空");
|
||||
return null;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
BufferedReader isr = new BufferedReader(new InputStreamReader(in));
|
||||
String line;
|
||||
while ((line = isr.readLine()) != null) {
|
||||
sb.append(line);
|
||||
}
|
||||
in.close();
|
||||
isr.close();
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private String ip, userName, password;
|
||||
private int port = 22;
|
||||
@@ -107,8 +182,8 @@ public class SFtpLogin {
|
||||
return this;
|
||||
}
|
||||
|
||||
public SFtpLogin build() {
|
||||
SFtpLogin login = new SFtpLogin();
|
||||
public SFtpUtil build() {
|
||||
SFtpUtil login = new SFtpUtil();
|
||||
login.ip = ip;
|
||||
login.userName = userName;
|
||||
login.password = password;
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.arialyy.aria.sftp.download;
|
||||
|
||||
import com.arialyy.aria.core.download.DTaskWrapper;
|
||||
import com.arialyy.aria.sftp.BaseInfoThreadAdapter;
|
||||
import java.util.Vector;
|
||||
|
||||
final class DSFtpInfoThreadAdapter extends BaseInfoThreadAdapter<DTaskWrapper> {
|
||||
|
||||
DSFtpInfoThreadAdapter(DTaskWrapper taskWrapper) {
|
||||
super(taskWrapper);
|
||||
}
|
||||
|
||||
@Override protected boolean handlerFile(Vector vector) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.arialyy.aria.sftp.download;
|
||||
|
||||
import com.arialyy.aria.core.common.SubThreadConfig;
|
||||
import com.arialyy.aria.core.task.IThreadTask;
|
||||
import com.arialyy.aria.core.task.ThreadTask;
|
||||
import com.arialyy.aria.core.wrapper.ITaskWrapper;
|
||||
import com.arialyy.aria.ftp.download.FtpDLoaderAdapter;
|
||||
|
||||
/**
|
||||
* sftp下载适配器
|
||||
*
|
||||
* @author lyy
|
||||
*/
|
||||
final class SFtpDLoaderAdapter extends FtpDLoaderAdapter {
|
||||
SFtpDLoaderAdapter(ITaskWrapper wrapper) {
|
||||
super(wrapper);
|
||||
}
|
||||
|
||||
@Override public IThreadTask createThreadTask(SubThreadConfig config) {
|
||||
ThreadTask threadTask = new ThreadTask(config);
|
||||
SFtpDThreadTaskAdapter adapter = new SFtpDThreadTaskAdapter(config);
|
||||
threadTask.setAdapter(adapter);
|
||||
return threadTask;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.arialyy.aria.sftp.download;
|
||||
|
||||
import com.arialyy.aria.core.common.AbsEntity;
|
||||
import com.arialyy.aria.core.common.CompleteInfo;
|
||||
import com.arialyy.aria.core.download.DTaskWrapper;
|
||||
import com.arialyy.aria.core.inf.OnFileInfoCallback;
|
||||
import com.arialyy.aria.core.listener.IEventListener;
|
||||
import com.arialyy.aria.core.loader.AbsLoader;
|
||||
import com.arialyy.aria.core.loader.AbsNormalLoaderUtil;
|
||||
import com.arialyy.aria.core.loader.NormalLoader;
|
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
import com.arialyy.aria.exception.BaseException;
|
||||
import com.arialyy.aria.ftp.FtpTaskOption;
|
||||
import com.arialyy.aria.sftp.SFtpInfoThread;
|
||||
import com.arialyy.aria.sftp.SFtpUtil;
|
||||
|
||||
/**
|
||||
* sftp下载工具
|
||||
*
|
||||
* @author lyy
|
||||
*/
|
||||
public class SFtpDLoaderUtil extends AbsNormalLoaderUtil {
|
||||
|
||||
private SFtpUtil mSftpUtil;
|
||||
|
||||
protected SFtpDLoaderUtil(AbsTaskWrapper wrapper, IEventListener listener) {
|
||||
super(wrapper, listener);
|
||||
wrapper.generateTaskOption(FtpTaskOption.class);
|
||||
FtpTaskOption option = (FtpTaskOption) wrapper.getTaskOption();
|
||||
mSftpUtil = new SFtpUtil.Builder()
|
||||
.setIp(option.getUrlEntity().hostName)
|
||||
.setPort(Integer.parseInt(option.getUrlEntity().port))
|
||||
.setUserName(option.getUrlEntity().user)
|
||||
.setPassword(option.getUrlEntity().password)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override protected AbsLoader createLoader() {
|
||||
NormalLoader loader = new NormalLoader(getListener(), getTaskWrapper());
|
||||
loader.setAdapter(new SFtpDLoaderAdapter(getTaskWrapper()));
|
||||
return loader;
|
||||
}
|
||||
|
||||
@Override protected Runnable createInfoThread() {
|
||||
DSFtpInfoThreadAdapter adapter = new DSFtpInfoThreadAdapter((DTaskWrapper) getTaskWrapper());
|
||||
SFtpInfoThread infoThread = new SFtpInfoThread<>(mSftpUtil, (DTaskWrapper) getTaskWrapper(),
|
||||
new OnFileInfoCallback() {
|
||||
@Override public void onComplete(String key, CompleteInfo info) {
|
||||
|
||||
}
|
||||
|
||||
@Override public void onFail(AbsEntity entity, BaseException e, boolean needRetry) {
|
||||
|
||||
}
|
||||
});
|
||||
infoThread.setAdapter(adapter);
|
||||
|
||||
return infoThread;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.arialyy.aria.sftp.download;
|
||||
|
||||
import com.arialyy.aria.core.common.SubThreadConfig;
|
||||
import com.arialyy.aria.core.task.AbsThreadTaskAdapter;
|
||||
|
||||
/**
|
||||
* sftp 线程任务适配器
|
||||
*
|
||||
* @author lyy
|
||||
*/
|
||||
public class SFtpDThreadTaskAdapter extends AbsThreadTaskAdapter {
|
||||
|
||||
SFtpDThreadTaskAdapter(SubThreadConfig config) {
|
||||
super(config);
|
||||
}
|
||||
|
||||
@Override protected void handlerThreadTask() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:sharedUserId="com.arialyy"
|
||||
package="com.arialyy.simple">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
|
||||
@@ -71,6 +71,29 @@ public class DownloadModule extends BaseModule {
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建m3u8下载地址
|
||||
*/
|
||||
public List<FileListEntity> createM3u8TestList(){
|
||||
String[] names = new String[]{"m3u8test1.ts", "m3u8test2.ts"};
|
||||
String[] urls = new String[]{
|
||||
"http://qn.shytong.cn/b83137769ff6b555/11b0c9970f9a3fa0.mp4.m3u8",
|
||||
"http://qn.shytong.cn/8f4011f2a31bd347da42b54fe37a7ba8-transcode.m3u8"
|
||||
};
|
||||
List<FileListEntity> list = new ArrayList<>();
|
||||
int i = 0;
|
||||
for (String name : names) {
|
||||
FileListEntity entity = new FileListEntity();
|
||||
entity.name = name;
|
||||
entity.key = urls[i];
|
||||
entity.type = 2;
|
||||
entity.downloadPath = Environment.getExternalStorageDirectory() + "/Download/" + name;
|
||||
list.add(entity);
|
||||
i++;
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private String[] getStringArray(int array) {
|
||||
return getContext().getResources().getStringArray(array);
|
||||
}
|
||||
@@ -91,7 +114,7 @@ public class DownloadModule extends BaseModule {
|
||||
FileListEntity entity = new FileListEntity();
|
||||
entity.urls = getStringArray(urls);
|
||||
entity.names = getStringArray(names);
|
||||
entity.isGroup = true;
|
||||
entity.type = 1;
|
||||
entity.name = alias;
|
||||
entity.key = CommonUtil.getMd5Code(Arrays.asList(entity.urls));
|
||||
entity.downloadPath = Environment.getExternalStorageDirectory() + "/Download/" + alias;
|
||||
|
||||
@@ -34,11 +34,12 @@ public class HttpDownloadModule extends BaseViewModule {
|
||||
|
||||
private final String defUrl =
|
||||
"http://hzdown.muzhiwan.com/2017/05/08/nl.noio.kingdom_59104935e56f0.apk";
|
||||
//"https://ss1.baidu.com/-4o3dSag_xI4khGko9WTAnF6hhy/image/h%3D300/sign=a9e671b9a551f3dedcb2bf64a4eff0ec/4610b912c8fcc3cef70d70409845d688d53f20f7.jpg";
|
||||
//"http://9.9.9.205:5000/download/Cyberduck-6.9.4.30164.zip";
|
||||
//"http://202.98.201.103:7000/vrs/TPK/ZTC440402001Z.tpk";
|
||||
private final String defFilePath =
|
||||
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath()
|
||||
+ "/TOTWOO-v3.5.6.apk";
|
||||
+ "/tttt.apk";
|
||||
|
||||
private MutableLiveData<DownloadEntity> liveData = new MutableLiveData<>();
|
||||
private DownloadEntity singDownloadInfo;
|
||||
@@ -50,7 +51,9 @@ public class HttpDownloadModule extends BaseViewModule {
|
||||
//String url = AppUtil.getConfigValue(context, HTTP_URL_KEY, defUrl);
|
||||
//String url =
|
||||
// "http://sdkdown.muzhiwan.com/openfile/2019/05/21/com.netease.tom.mzw_5ce3ef8754d05.apk";
|
||||
String url = "http://image.totwoo.com/totwoo-TOTWOO-v3.5.6.apk";
|
||||
//String url = "http://image.totwoo.com/totwoo-TOTWOO-v3.5.6.apk";
|
||||
String url = "https://imtt.dd.qq.com/16891/apk/70BFFDB05AB8686F2A4CF3E07588A377.apk?fsname=com.tencent.tmgp.speedmobile_1.16.0.33877_1160033877.apk&csr=1bbd";
|
||||
//String url = "https://ss1.baidu.com/-4o3dSag_xI4khGko9WTAnF6hhy/image/h%3D300/sign=a9e671b9a551f3dedcb2bf64a4eff0ec/4610b912c8fcc3cef70d70409845d688d53f20f7.jpg";
|
||||
String filePath = AppUtil.getConfigValue(context, HTTP_PATH_KEY, defFilePath);
|
||||
|
||||
singDownloadInfo = Aria.download(context).getFirstDownloadEntity(url);
|
||||
|
||||
@@ -215,6 +215,7 @@ public class SingleTaskActivity extends BaseActivity<ActivitySingleBinding> {
|
||||
|
||||
@Download.onTaskResume
|
||||
void taskResume(DownloadTask task) {
|
||||
ALog.d(TAG, "resume");
|
||||
if (task.getKey().equals(mUrl)) {
|
||||
getBinding().setStateStr(getString(R.string.stop));
|
||||
}
|
||||
@@ -276,7 +277,7 @@ public class SingleTaskActivity extends BaseActivity<ActivitySingleBinding> {
|
||||
Aria.download(this).load(mTaskId).stop();
|
||||
} else {
|
||||
Aria.download(this).load(mTaskId)
|
||||
//.updateUrl("http://sdkdown.muzhiwan.com/openfile/2019/07/11/com.netease.syfz.mzw_5d26f8d9cee27.apk")
|
||||
.updateUrl("http://sdkdown.muzhiwan.com/openfile/2019/07/11/com.netease.syfz.mzw_5d26f8d9cee27.apk")
|
||||
.resume();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -95,13 +95,13 @@ public class DownloadGroupActivity extends BaseActivity<ActivityDownloadGroupBin
|
||||
mTaskId = Aria.download(this)
|
||||
.loadGroup(mUrls)
|
||||
.setDirPath(
|
||||
Environment.getExternalStorageDirectory().getPath() + "/Download/group_test_2")
|
||||
.setGroupAlias("任务组测试")
|
||||
Environment.getExternalStorageDirectory().getPath() + "/Download/group_imgs")
|
||||
.setGroupAlias("图片测试")
|
||||
//.setSubFileName(getModule(GroupModule.class).getSubName2())
|
||||
.setSubFileName(getModule(GroupModule.class).getSubName())
|
||||
//.setSubFileName(getModule(GroupModule.class).getSubName())
|
||||
.unknownSize()
|
||||
.option(getHttpOption())
|
||||
.setFileSize(114981416)
|
||||
//.setFileSize(114981416)
|
||||
//.updateUrls(temp)
|
||||
.create();
|
||||
getBinding().setStateStr(getString(R.string.stop));
|
||||
|
||||
@@ -24,12 +24,14 @@ import com.arialyy.aria.core.common.FtpOption;
|
||||
import com.arialyy.aria.core.download.DownloadGroupEntity;
|
||||
import com.arialyy.aria.core.inf.IEntity;
|
||||
import com.arialyy.aria.core.task.DownloadGroupTask;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.frame.util.show.L;
|
||||
import com.arialyy.frame.util.show.T;
|
||||
import com.arialyy.simple.R;
|
||||
import com.arialyy.simple.base.BaseActivity;
|
||||
import com.arialyy.simple.databinding.ActivityDownloadGroupBinding;
|
||||
import com.arialyy.simple.widget.SubStateLinearLayout;
|
||||
import java.security.AlgorithmConstraints;
|
||||
|
||||
/**
|
||||
* Created by lyy on 2017/7/6.
|
||||
@@ -128,6 +130,7 @@ public class FTPDirDownloadActivity extends BaseActivity<ActivityDownloadGroupBi
|
||||
}
|
||||
|
||||
@DownloadGroup.onTaskResume() void taskResume(DownloadGroupTask task) {
|
||||
ALog.d(TAG, "ftp dir resume");
|
||||
}
|
||||
|
||||
@DownloadGroup.onTaskStop() void taskStop(DownloadGroupTask task) {
|
||||
|
||||
@@ -32,6 +32,8 @@ public class GroupModule extends BaseModule {
|
||||
|
||||
public List<String> getUrls() {
|
||||
List<String> urls = new ArrayList<>();
|
||||
//urls.add("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1574141924275&di=a7ea1497a4a2528a45ce7103bf61adf4&imgtype=0&src=http%3A%2F%2Fg.hiphotos.baidu.com%2Fimage%2Fpic%2Fitem%2Fc2cec3fdfc03924590b2a9b58d94a4c27d1e2500.jpg");
|
||||
//urls.add("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1574141924272&di=7861479e7cb3cea98d585eaf108f056f&imgtype=0&src=http%3A%2F%2Fd.hiphotos.baidu.com%2Fimage%2Fpic%2Fitem%2F562c11dfa9ec8a13c0741f5afd03918fa0ecc01a.jpg");
|
||||
String[] str = getContext().getResources().getStringArray(R.array.group_urls_1);
|
||||
Collections.addAll(urls, str);
|
||||
return urls;
|
||||
|
||||
@@ -213,17 +213,10 @@ public class M3U8LiveDLoadActivity extends BaseActivity<ActivityM3u8LiveBinding>
|
||||
public void onClick(View view) {
|
||||
switch (view.getId()) {
|
||||
case R.id.start:
|
||||
startD();
|
||||
if (!AppUtil.chekEntityValid(mEntity)) {
|
||||
startD();
|
||||
break;
|
||||
}
|
||||
if (Aria.download(this).load(mEntity.getId()).isRunning()) {
|
||||
Aria.download(this).load(mEntity.getId()).stop();
|
||||
} else {
|
||||
Aria.download(this).load(mEntity.getId())
|
||||
.m3u8LiveOption(getLiveoption())
|
||||
.resume();
|
||||
startD();
|
||||
}
|
||||
break;
|
||||
case R.id.cancel:
|
||||
@@ -245,6 +238,7 @@ public class M3U8LiveDLoadActivity extends BaseActivity<ActivityM3u8LiveBinding>
|
||||
private M3U8LiveOption getLiveoption() {
|
||||
M3U8LiveOption option = new M3U8LiveOption();
|
||||
option
|
||||
//.generateIndexFile()
|
||||
.setLiveTsUrlConvert(new LiveTsUrlConverter());
|
||||
//.setBandWidthUrlConverter(new BandWidthUrlConverter(mUrl));
|
||||
return option;
|
||||
|
||||
@@ -90,10 +90,10 @@ public class M3U8VodDLoadActivity extends BaseActivity<ActivityM3u8VodBinding> {
|
||||
getBinding().setFilePath(entity.getFilePath());
|
||||
mUrl = entity.getUrl();
|
||||
mFilePath = entity.getFilePath();
|
||||
mVideoFragment = new VideoPlayerFragment(0, entity);
|
||||
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
|
||||
ft.add(R.id.video_content, mVideoFragment);
|
||||
ft.commit();
|
||||
//mVideoFragment = new VideoPlayerFragment(0, entity);
|
||||
//FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
|
||||
//ft.add(R.id.video_content, mVideoFragment);
|
||||
//ft.commit();
|
||||
}
|
||||
});
|
||||
getBinding().setViewModel(this);
|
||||
@@ -176,7 +176,7 @@ public class M3U8VodDLoadActivity extends BaseActivity<ActivityM3u8VodBinding> {
|
||||
@M3U8.onPeerComplete
|
||||
void onPeerComplete(String m3u8Url, String peerPath, int peerIndex) {
|
||||
//ALog.d(TAG, "peer complete, path: " + peerPath + ", index: " + peerIndex);
|
||||
mVideoFragment.addPlayer(peerIndex, peerPath);
|
||||
//mVideoFragment.addPlayer(peerIndex, peerPath);
|
||||
}
|
||||
|
||||
@M3U8.onPeerFail
|
||||
@@ -217,6 +217,7 @@ public class M3U8VodDLoadActivity extends BaseActivity<ActivityM3u8VodBinding> {
|
||||
|
||||
@Download.onTaskResume
|
||||
void taskResume(DownloadTask task) {
|
||||
ALog.d(TAG, "m3u8 vod resume");
|
||||
if (task.getKey().equals(mUrl)) {
|
||||
getBinding().setStateStr(getString(R.string.stop));
|
||||
}
|
||||
@@ -303,10 +304,11 @@ public class M3U8VodDLoadActivity extends BaseActivity<ActivityM3u8VodBinding> {
|
||||
private M3U8VodOption getM3U8Option() {
|
||||
M3U8VodOption option = new M3U8VodOption();
|
||||
option
|
||||
.generateIndexFile()
|
||||
.setVodTsUrlConvert(new VodTsUrlConverter())
|
||||
.setMergeHandler(new TsMergeHandler());
|
||||
//.setBandWidthUrlConverter(new BandWidthUrlConverter(mUrl));
|
||||
//.generateIndexFile()
|
||||
//.merge(true)
|
||||
.setVodTsUrlConvert(new VodTsUrlConverter());
|
||||
//.setMergeHandler(new TsMergeHandler());
|
||||
option.setBandWidthUrlConverter(new BandWidthUrlConverter(mUrl));
|
||||
return option;
|
||||
}
|
||||
|
||||
@@ -322,7 +324,10 @@ public class M3U8VodDLoadActivity extends BaseActivity<ActivityM3u8VodBinding> {
|
||||
static class VodTsUrlConverter implements IVodTsUrlConverter {
|
||||
@Override public List<String> convert(String m3u8Url, List<String> tsUrls) {
|
||||
Uri uri = Uri.parse(m3u8Url);
|
||||
String parentUrl = "http://" + uri.getHost();
|
||||
//String parentUrl = "http://" + uri.getHost() + "/gear1/";
|
||||
int index = m3u8Url.lastIndexOf("/");
|
||||
String parentUrl = m3u8Url.substring(0, index + 1);
|
||||
//String parentUrl = "http://" + uri.getHost() + "/";
|
||||
List<String> newUrls = new ArrayList<>();
|
||||
for (String url : tsUrls) {
|
||||
newUrls.add(parentUrl + url);
|
||||
|
||||
@@ -34,11 +34,12 @@ public class M3U8VodModule extends BaseViewModule {
|
||||
// m3u8测试集合:http://www.voidcn.com/article/p-snaliarm-ct.html
|
||||
//private final String defUrl = "https://www.gaoya123.cn/2019/1557993797897.m3u8";
|
||||
// 多码率地址:
|
||||
//private final String defUrl = "http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8";
|
||||
private final String defUrl = "http://cn1.fa1244.cn/hls/20190516/6d271eaa73b2e4cb51d13831b0c1ab4c/1557976262/index.m3u8";
|
||||
private final String defUrl = "http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8";
|
||||
//private final String defUrl = "http://qn.shytong.cn/b83137769ff6b555/11b0c9970f9a3fa0.mp4.m3u8";
|
||||
private final String filePath =
|
||||
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath()
|
||||
+ "/道士下山.ts";
|
||||
//+ "/道士下山.ts";
|
||||
+ "/bb1.ts";
|
||||
|
||||
private MutableLiveData<DownloadEntity> liveData = new MutableLiveData<>();
|
||||
private DownloadEntity singDownloadInfo;
|
||||
|
||||
@@ -28,7 +28,7 @@ import com.arialyy.aria.core.common.AbsEntity;
|
||||
import com.arialyy.aria.core.download.DownloadEntity;
|
||||
import com.arialyy.aria.core.download.DownloadGroupEntity;
|
||||
import com.arialyy.aria.core.inf.IEntity;
|
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
import com.arialyy.aria.core.wrapper.ITaskWrapper;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import com.arialyy.simple.R;
|
||||
import com.arialyy.simple.base.adapter.AbsHolder;
|
||||
@@ -152,12 +152,19 @@ public class DownloadAdapter extends AbsRVAdapter<AbsEntity, DownloadAdapter.Sim
|
||||
* 只更新速度
|
||||
*/
|
||||
private void updateSpeed(SimpleHolder holder, final AbsEntity entity) {
|
||||
long size = entity.getFileSize();
|
||||
long progress = entity.getCurrentProgress();
|
||||
int current = size == 0 ? 0 : (int) (progress * 100 / size);
|
||||
|
||||
holder.speed.setText(entity.getConvertSpeed());
|
||||
holder.fileSize.setText(covertCurrentSize(progress) + "/" + CommonUtil.formatFileSize(size));
|
||||
holder.progress.setProgress(current);
|
||||
if (entity.getTaskType() == ITaskWrapper.M3U8_VOD
|
||||
|| entity.getTaskType() == ITaskWrapper.M3U8_LIVE) {
|
||||
holder.progress.setProgress(entity.getPercent());
|
||||
holder.fileSize.setVisibility(View.GONE);
|
||||
} else {
|
||||
long size = entity.getFileSize();
|
||||
long progress = entity.getCurrentProgress();
|
||||
int current = size == 0 ? 0 : (int) (progress * 100 / size);
|
||||
holder.fileSize.setText(covertCurrentSize(progress) + "/" + CommonUtil.formatFileSize(size));
|
||||
holder.progress.setProgress(current);
|
||||
}
|
||||
//if (holder instanceof GroupHolder){
|
||||
// handleSubChild((GroupHolder) holder, entity);
|
||||
//}
|
||||
@@ -257,9 +264,9 @@ public class DownloadAdapter extends AbsRVAdapter<AbsEntity, DownloadAdapter.Sim
|
||||
case IEntity.STATE_STOP:
|
||||
case IEntity.STATE_PRE:
|
||||
case IEntity.STATE_POST_PRE:
|
||||
if (entity.getId() < 0){
|
||||
if (entity.getId() < 0) {
|
||||
start(entity);
|
||||
}else {
|
||||
} else {
|
||||
resume(entity);
|
||||
}
|
||||
break;
|
||||
@@ -278,36 +285,38 @@ public class DownloadAdapter extends AbsRVAdapter<AbsEntity, DownloadAdapter.Sim
|
||||
return;
|
||||
}
|
||||
switch (entity.getTaskType()) {
|
||||
case AbsTaskWrapper.D_FTP:
|
||||
case ITaskWrapper.D_FTP:
|
||||
Aria.download(getContext())
|
||||
.loadFtp(entity.getId())
|
||||
//.login("lao", "123456")
|
||||
.cancel(true);
|
||||
break;
|
||||
case AbsTaskWrapper.D_FTP_DIR:
|
||||
case ITaskWrapper.D_FTP_DIR:
|
||||
break;
|
||||
case AbsTaskWrapper.D_HTTP:
|
||||
case ITaskWrapper.D_HTTP:
|
||||
case ITaskWrapper.M3U8_VOD:
|
||||
Aria.download(getContext()).load(entity.getId()).cancel(true);
|
||||
break;
|
||||
case AbsTaskWrapper.DG_HTTP:
|
||||
case ITaskWrapper.DG_HTTP:
|
||||
Aria.download(getContext()).load(entity.getId()).cancel(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void resume(AbsEntity entity){
|
||||
private void resume(AbsEntity entity) {
|
||||
switch (entity.getTaskType()) {
|
||||
case AbsTaskWrapper.D_FTP:
|
||||
case ITaskWrapper.D_FTP:
|
||||
//Aria.download(getContext()).loadFtp((DownloadEntity) entity).login("lao", "123456").create();
|
||||
Aria.download(getContext()).loadFtp(entity.getId()).resume();
|
||||
break;
|
||||
case AbsTaskWrapper.D_FTP_DIR:
|
||||
case ITaskWrapper.D_FTP_DIR:
|
||||
Aria.download(getContext()).loadFtpDir(entity.getId()).resume();
|
||||
break;
|
||||
case AbsTaskWrapper.D_HTTP:
|
||||
case ITaskWrapper.D_HTTP:
|
||||
case ITaskWrapper.M3U8_VOD:
|
||||
Aria.download(getContext()).load(entity.getId()).resume();
|
||||
break;
|
||||
case AbsTaskWrapper.DG_HTTP:
|
||||
case ITaskWrapper.DG_HTTP:
|
||||
Aria.download(getContext()).loadGroup(entity.getId()).resume();
|
||||
break;
|
||||
}
|
||||
@@ -315,16 +324,17 @@ public class DownloadAdapter extends AbsRVAdapter<AbsEntity, DownloadAdapter.Sim
|
||||
|
||||
private void start(AbsEntity entity) {
|
||||
switch (entity.getTaskType()) {
|
||||
case AbsTaskWrapper.D_FTP:
|
||||
case ITaskWrapper.D_FTP:
|
||||
//Aria.download(getContext()).loadFtp((DownloadEntity) entity).login("lao", "123456").create();
|
||||
Aria.download(getContext()).loadFtp(entity.getKey()).create();
|
||||
break;
|
||||
case AbsTaskWrapper.D_FTP_DIR:
|
||||
case ITaskWrapper.D_FTP_DIR:
|
||||
break;
|
||||
case AbsTaskWrapper.D_HTTP:
|
||||
case ITaskWrapper.D_HTTP:
|
||||
case ITaskWrapper.M3U8_VOD:
|
||||
Aria.download(getContext()).load(entity.getKey()).create();
|
||||
break;
|
||||
case AbsTaskWrapper.DG_HTTP:
|
||||
case ITaskWrapper.DG_HTTP:
|
||||
Aria.download(getContext()).loadGroup(((DownloadGroupEntity) entity).getUrls()).create();
|
||||
break;
|
||||
}
|
||||
@@ -336,15 +346,16 @@ public class DownloadAdapter extends AbsRVAdapter<AbsEntity, DownloadAdapter.Sim
|
||||
}
|
||||
|
||||
switch (entity.getTaskType()) {
|
||||
case AbsTaskWrapper.D_FTP:
|
||||
case ITaskWrapper.D_FTP:
|
||||
Aria.download(getContext()).loadFtp(entity.getId()).stop();
|
||||
break;
|
||||
case AbsTaskWrapper.D_FTP_DIR:
|
||||
case ITaskWrapper.D_FTP_DIR:
|
||||
break;
|
||||
case AbsTaskWrapper.D_HTTP:
|
||||
case ITaskWrapper.D_HTTP:
|
||||
case ITaskWrapper.M3U8_VOD:
|
||||
Aria.download(getContext()).load(entity.getId()).stop();
|
||||
break;
|
||||
case AbsTaskWrapper.DG_HTTP:
|
||||
case ITaskWrapper.DG_HTTP:
|
||||
Aria.download(getContext()).loadGroup(entity.getId()).stop();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -22,9 +22,13 @@ import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import com.arialyy.aria.core.Aria;
|
||||
import com.arialyy.aria.core.download.m3u8.M3U8VodOption;
|
||||
import com.arialyy.aria.core.processor.IVodTsUrlConverter;
|
||||
import com.arialyy.simple.R;
|
||||
import com.arialyy.simple.base.adapter.AbsHolder;
|
||||
import com.arialyy.simple.base.adapter.AbsRVAdapter;
|
||||
import com.arialyy.simple.core.download.m3u8.M3U8VodDLoadActivity;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -60,27 +64,44 @@ final class FileListAdapter extends AbsRVAdapter<FileListEntity, FileListAdapter
|
||||
protected void bindData(FileListHolder holder, int position, final FileListEntity item) {
|
||||
holder.name.setText("文件名:" + item.name);
|
||||
holder.url.setText("下载地址:" + item.key);
|
||||
holder.url.setVisibility(item.isGroup ? View.GONE : View.VISIBLE);
|
||||
if (item.type == 1) {
|
||||
holder.url.setVisibility(View.GONE);
|
||||
}
|
||||
holder.path.setText("保存路径:" + item.downloadPath);
|
||||
if (mBtStates.get(item.key)) {
|
||||
holder.bt.setEnabled(true);
|
||||
holder.bt.setOnClickListener(new View.OnClickListener() {
|
||||
@Override public void onClick(View v) {
|
||||
Toast.makeText(getContext(), "开始下载:" + item.name, Toast.LENGTH_SHORT).show();
|
||||
if (item.isGroup) {
|
||||
Aria.download(getContext())
|
||||
.loadGroup(Arrays.asList(item.urls))
|
||||
.setSubFileName(Arrays.asList(item.names))
|
||||
.setDirPath(item.downloadPath)
|
||||
.setGroupAlias(item.name)
|
||||
.unknownSize()
|
||||
.create();
|
||||
} else {
|
||||
Aria.download(getContext())
|
||||
.load(item.key)
|
||||
.setFilePath(item.downloadPath)
|
||||
.create();
|
||||
switch (item.type) {
|
||||
case 0:
|
||||
Aria.download(getContext())
|
||||
.load(item.key)
|
||||
.setFilePath(item.downloadPath)
|
||||
.create();
|
||||
break;
|
||||
case 1:
|
||||
Aria.download(getContext())
|
||||
.loadGroup(Arrays.asList(item.urls))
|
||||
.setSubFileName(Arrays.asList(item.names))
|
||||
.setDirPath(item.downloadPath)
|
||||
.setGroupAlias(item.name)
|
||||
.unknownSize()
|
||||
.create();
|
||||
break;
|
||||
case 2:
|
||||
M3U8VodOption option = new M3U8VodOption();
|
||||
option.setVodTsUrlConvert(new IVodTs());
|
||||
option.generateIndexFile();
|
||||
|
||||
Aria.download(getContext())
|
||||
.load(item.key)
|
||||
.setFilePath(item.downloadPath, true)
|
||||
.m3u8VodOption(option)
|
||||
.create();
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
} else {
|
||||
@@ -125,4 +146,15 @@ final class FileListAdapter extends AbsRVAdapter<FileListEntity, FileListAdapter
|
||||
bt = findViewById(R.id.bt);
|
||||
}
|
||||
}
|
||||
static class IVodTs implements IVodTsUrlConverter{
|
||||
|
||||
@Override public List<String> convert(String m3u8Url, List<String> tsUrls) {
|
||||
List<String> temp = new ArrayList<>();
|
||||
for (String tsUrl : tsUrls){
|
||||
temp.add("http://qn.shytong.cn" + tsUrl);
|
||||
}
|
||||
|
||||
return temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,13 @@ package com.arialyy.simple.core.download.mutil;
|
||||
|
||||
public class FileListEntity {
|
||||
public String name, key, downloadPath;
|
||||
public boolean isGroup = false;
|
||||
|
||||
/**
|
||||
* 0:普通任务
|
||||
* 1:组合任务
|
||||
* 2:m3u8任务
|
||||
*/
|
||||
public int type = 0;
|
||||
|
||||
public String[] urls, names;
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ public class MultiDownloadActivity extends BaseActivity<ActivityMultiDownloadBin
|
||||
mAdapter.updateState(task.getEntity());
|
||||
}
|
||||
|
||||
@Download.onTaskRunning() void taskRunning(DownloadTask task) {
|
||||
@Download.onTaskRunning void taskRunning(DownloadTask task) {
|
||||
mAdapter.setProgress(task.getEntity());
|
||||
}
|
||||
|
||||
|
||||
@@ -57,6 +57,7 @@ public class MultiTaskActivity extends BaseActivity<ActivityMultiBinding> {
|
||||
setTitle("多任务下载");
|
||||
mData.addAll(getModule(DownloadModule.class).createGroupTestList());
|
||||
mData.addAll(getModule(DownloadModule.class).createMultiTestList());
|
||||
mData.addAll(getModule(DownloadModule.class).createM3u8TestList());
|
||||
mAdapter = new FileListAdapter(this, mData);
|
||||
mList = getBinding().list;
|
||||
mBar = findViewById(R.id.toolbar);
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.arialyy.simple.core.upload;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import androidx.annotation.Nullable;
|
||||
@@ -27,6 +28,8 @@ import com.arialyy.annotations.Upload;
|
||||
import com.arialyy.aria.core.Aria;
|
||||
import com.arialyy.aria.core.common.FtpOption;
|
||||
import com.arialyy.aria.core.inf.IEntity;
|
||||
import com.arialyy.aria.core.processor.FtpInterceptHandler;
|
||||
import com.arialyy.aria.core.processor.IFtpUploadInterceptor;
|
||||
import com.arialyy.aria.core.task.UploadTask;
|
||||
import com.arialyy.aria.core.upload.UploadEntity;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
@@ -40,6 +43,8 @@ import com.arialyy.simple.databinding.ActivityFtpUploadBinding;
|
||||
import com.arialyy.simple.util.AppUtil;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by lyy on 2017/7/28. Ftp 文件上传demo
|
||||
@@ -116,6 +121,7 @@ public class FtpUploadActivity extends BaseActivity<ActivityFtpUploadBinding> {
|
||||
.loadFtp(mFilePath)
|
||||
.setUploadUrl(mUrl)
|
||||
.option(getOption())
|
||||
.forceUpload()
|
||||
.create();
|
||||
getBinding().setStateStr(getString(R.string.stop));
|
||||
break;
|
||||
@@ -130,7 +136,7 @@ public class FtpUploadActivity extends BaseActivity<ActivityFtpUploadBinding> {
|
||||
.resume();
|
||||
getBinding().setStateStr(getString(R.string.stop));
|
||||
}
|
||||
|
||||
//upload();
|
||||
break;
|
||||
case R.id.cancel:
|
||||
Aria.upload(this).loadFtp(mTaskId).cancel();
|
||||
@@ -140,9 +146,32 @@ public class FtpUploadActivity extends BaseActivity<ActivityFtpUploadBinding> {
|
||||
}
|
||||
}
|
||||
|
||||
private void upload() {
|
||||
List<String> paths = new ArrayList<>();
|
||||
paths.add(Environment.getExternalStorageDirectory().getPath() + "/Download/img/img/1.jpg");
|
||||
paths.add(Environment.getExternalStorageDirectory().getPath() + "/Download/img/img/2.jpg");
|
||||
paths.add(Environment.getExternalStorageDirectory().getPath() + "/Download/img/img/3.jpg");
|
||||
paths.add(Environment.getExternalStorageDirectory().getPath() + "/Download/img/img/4.jpg");
|
||||
paths.add(Environment.getExternalStorageDirectory().getPath() + "/Download/img/img/5.jpg");
|
||||
paths.add(Environment.getExternalStorageDirectory().getPath() + "/Download/img/img/6.jpg");
|
||||
paths.add(Environment.getExternalStorageDirectory().getPath() + "/Download/img/img/7.jpg");
|
||||
paths.add(Environment.getExternalStorageDirectory().getPath() + "/Download/img/img/8.jpg");
|
||||
paths.add(Environment.getExternalStorageDirectory().getPath() + "/Download/img/img/9.jpg");
|
||||
paths.add(Environment.getExternalStorageDirectory().getPath() + "/Download/img/img/10.jpg");
|
||||
for (String path : paths) {
|
||||
Aria.upload(this)
|
||||
.loadFtp(path)
|
||||
.setUploadUrl(mUrl)
|
||||
.option(getOption())
|
||||
.forceUpload()
|
||||
.create();
|
||||
}
|
||||
}
|
||||
|
||||
private FtpOption getOption() {
|
||||
FtpOption option = new FtpOption();
|
||||
option.login(user, pwd);
|
||||
option.setUploadInterceptor(new FtpUploadInterceptor());
|
||||
return option;
|
||||
}
|
||||
|
||||
@@ -211,4 +240,13 @@ public class FtpUploadActivity extends BaseActivity<ActivityFtpUploadBinding> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class FtpUploadInterceptor implements IFtpUploadInterceptor {
|
||||
@Override public FtpInterceptHandler onIntercept(UploadEntity entity, List<String> fileList) {
|
||||
FtpInterceptHandler.Builder builder = new FtpInterceptHandler.Builder();
|
||||
//builder.coverServerFile(); // 覆盖远端同名文件
|
||||
builder.resetFileName("test.zip"); //修改上传到远端服务器的文件名
|
||||
return builder.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ public class UploadModule extends BaseViewModule {
|
||||
LiveData<UploadEntity> getFtpInfo(Context context) {
|
||||
String url = AppUtil.getConfigValue(context, FTP_URL_KEY, "ftp://9.9.9.50:2121/aa/你好");
|
||||
String filePath = AppUtil.getConfigValue(context, FTP_PATH_KEY,
|
||||
Environment.getExternalStorageDirectory().getPath() + "/Download/PaNTFS15562.zip");
|
||||
Environment.getExternalStorageDirectory().getPath() + "/Download/Folx P58.zip");
|
||||
|
||||
UploadEntity entity = Aria.upload(context).getFirstUploadEntity(filePath);
|
||||
if (entity != null) {
|
||||
|
||||
@@ -44,8 +44,8 @@ task clean(type: Delete) {
|
||||
}
|
||||
|
||||
ext {
|
||||
versionCode = 374
|
||||
versionName = '3.7.4'
|
||||
versionCode = 378
|
||||
versionName = '3.7.8-pre-3'
|
||||
userOrg = 'arialyy'
|
||||
groupId = 'com.arialyy.aria'
|
||||
publishVersion = versionName
|
||||
|
||||
BIN
img/ali_pay.png
Normal file
BIN
img/ali_pay.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 40 KiB |
BIN
img/wx_pay.png
Normal file
BIN
img/wx_pay.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 27 KiB |
Reference in New Issue
Block a user