22 Commits

Author SHA1 Message Date
lyy
afa6434664 Update README.md 2021-04-18 21:31:57 +08:00
laoyuyu
00a81220cb 修改上传脚本,将从库从jcenter迁移到mavencentral 2021-04-18 21:30:03 +08:00
laoyuyu
ebbbbee1f8 修改上传脚本,将从库从jcenter迁移到mavencentral 2021-04-18 19:28:29 +08:00
laoyuyu
6eab496b6a Merge branch 'master' of github.com:AriaLyy/Aria 2021-04-14 21:19:30 +08:00
laoyuyu
3679e0cb23 fix bug https://github.com/AriaLyy/Aria/issues/851 2021-04-14 21:19:04 +08:00
lyy
66f9aa9cd5 Update stale.yml 2021-01-11 14:20:15 +08:00
lyy
edb3e66a96 Update stale.yml 2020-12-18 17:34:41 +08:00
laoyuyu
1c0765be02 修复bug 2020-12-09 15:29:40 +08:00
laoyuyu
5853fe9e3e 修复组合任务获取文件信息时,其中子任务失败,状态回调错误的问题 2020-12-09 11:32:51 +08:00
laoyuyu
9db8f1e9c0 修复组合任务在获取子任务信息的过程中,手动停止或删除,没有回调的问题 2020-12-09 10:24:14 +08:00
laoyuyu
35e66caab5 fix bug https://github.com/AriaLyy/Aria/issues/811 2020-12-09 09:09:59 +08:00
laoyuyu
bcfb78109b fixbug https://github.com/AriaLyy/Aria/issues/807 2020-12-09 08:53:53 +08:00
laoyuyu
d7d081ffb1 修复单线程下载时,文件已经完成,重复下载回调下载失败的问题
修复一个重新下载文件时,同名路径文件没有被被删除的问题
2020-11-12 22:35:18 +08:00
laoyuyu
840facd1cc 3.8.15 2020-11-09 20:34:27 +08:00
laoyuyu
f67f829dfc fix bug https://github.com/AriaLyy/Aria/issues/799 https://github.com/AriaLyy/Aria/issues/798 2020-11-09 20:34:05 +08:00
laoyuyu
0152187aa8 修复iv不存在时,索引文件异常的问题, https://github.com/AriaLyy/Aria/issues/780 2020-10-16 09:24:16 +08:00
laoyuyu
68c992962b 修复不支持断点的连接下载失败问题,https://github.com/AriaLyy/Aria/issues/771 2020-09-23 13:46:12 +08:00
laoyuyu
514fa4321d Merge branch 'master' of github.com:AriaLyy/Aria 2020-09-23 10:09:05 +08:00
laoyuyu
313e047d1f v3.1.4 2020-09-23 10:08:38 +08:00
lyy
62ad99e252 Update stale.yml 2020-09-21 08:35:57 +08:00
laoyuyu
8785bb2875 增加路径不可以写的判断,下载时,如果路径不可写,将执行失败回调 https://github.com/AriaLyy/Aria/issues/750 2020-08-28 09:16:31 +08:00
laoyuyu
7be93b38c2 fix bug https://github.com/AriaLyy/Aria/issues/743 2020-08-27 08:45:45 +08:00
105 changed files with 1000 additions and 283 deletions

View File

@@ -11,6 +11,8 @@ about: 提交问题前请先阅读文档和搜索issue
* 系统版本
## 错误的url
## 错误日志
<!-- 请提供详细的错误日志 -->

5
.github/stale.yml vendored
View File

@@ -1,13 +1,14 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 7
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
daysUntilClose: 100
# Issues with these labels will never be considered stale
exemptLabels:
- bug
- adaptation
- new features
- suggest
- pending
# Label to use when marking an issue as stale
staleLabel: wontfix
# Comment to post when marking an issue as stale. Set to `false` to disable
@@ -16,4 +17,4 @@ markComment: >
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false
closeComment: false

View File

@@ -15,6 +15,9 @@ android {
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
debug{
debuggable true
}
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

View File

@@ -12,7 +12,7 @@ import javax.crypto.spec.SecretKeySpec;
/**
* AES加密
*
* @author lyy
* author lyy
*/
public class AESEncryption {
/**

View File

@@ -11,6 +11,9 @@ android {
versionName rootProject.ext.versionName
}
buildTypes {
debug{
debuggable true
}
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
@@ -24,9 +27,13 @@ dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
testImplementation 'junit:junit:4.12'
// implementation "androidx.appcompat:appcompat:${rootProject.ext.XAppcompatVersion}"
api project(':AriaAnnotations')
api project(path: ':AriaAnnotations')
api project(path: ':PublicComponent')
api project(path: ':HttpComponent')
}
apply from: 'bintray-release.gradle'
//apply from: 'bintray-release.gradle'
ext{
PUBLISH_ARTIFACT_ID = 'core'
}
apply from: '../gradle/mavenCentral-release.gradle'

View File

@@ -18,11 +18,10 @@ package com.arialyy.aria.core.common;
import com.arialyy.annotations.TaskEnum;
import com.arialyy.aria.core.download.DownloadGroupTaskListener;
import com.arialyy.aria.core.download.DownloadTaskListener;
import com.arialyy.aria.core.scheduler.TaskInternalListenerInterface;
import com.arialyy.aria.core.scheduler.M3U8PeerTaskListener;
import com.arialyy.aria.core.scheduler.SubTaskListener;
import com.arialyy.aria.core.scheduler.TaskInternalListenerInterface;
import com.arialyy.aria.core.upload.UploadTaskListener;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
@@ -81,7 +80,8 @@ public class ProxyHelper {
return result;
}
result = checkProxyTypeByInterface(clazz);
if (result != null) {
if (result != null && !result.isEmpty()) {
mProxyCache.put(clazz.getName(), result);
return result;
}
result = checkProxyTypeByProxyClass(clazz);

View File

@@ -35,7 +35,7 @@ public class SFtpOption extends BaseOption {
public SFtpOption() {
super();
ComponentUtil.getInstance().checkComponentExist(ComponentUtil.COMPONENT_TYPE_M3U8);
ComponentUtil.getInstance().checkComponentExist(ComponentUtil.COMPONENT_TYPE_SFTP);
}
public SFtpOption charSet(String charSet) {

View File

@@ -110,7 +110,12 @@ public class CheckDEntityUtil implements ICheckEntityUtil {
if (TextUtils.isEmpty(filePath)) {
ALog.e(TAG, "下载失败文件保存路径为null");
return false;
} else if (!filePath.startsWith("/")) {
}
if (!FileUtil.canWrite(new File(filePath).getParent())){
ALog.e(TAG, String.format("路径【%s】不可写", filePath));
return false;
}
if (!filePath.startsWith("/")) {
ALog.e(TAG, String.format("下载失败,文件保存路径【%s】错误", filePath));
return false;
}

View File

@@ -23,6 +23,7 @@ import com.arialyy.aria.core.inf.IOptionConstant;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil;
import com.arialyy.aria.util.FileUtil;
import com.arialyy.aria.util.RecordUtil;
import java.io.File;
import java.util.ArrayList;
@@ -62,33 +63,41 @@ public class CheckDGEntityUtil implements ICheckEntityUtil {
* @return {@code true} 合法
*/
private boolean checkDirPath() {
if (TextUtils.isEmpty(mWrapper.getDirPathTemp())) {
String dirPath = mWrapper.getDirPathTemp();
if (TextUtils.isEmpty(dirPath)) {
ALog.e(TAG, "文件夹路径不能为null");
return false;
} else if (!mWrapper.getDirPathTemp().startsWith("/")) {
ALog.e(TAG, String.format("文件夹路径【%s】错误", mWrapper.getDirPathTemp()));
}
File file = new File(dirPath);
if (!FileUtil.canWrite(file.getParent()) && !FileUtil.canWrite(dirPath)) {
ALog.e(TAG, String.format("路径【%s】不可写", dirPath));
return false;
}
File file = new File(mWrapper.getDirPathTemp());
if (!dirPath.startsWith("/")) {
ALog.e(TAG, String.format("文件夹路径【%s】错误", dirPath));
return false;
}
if (file.isFile()) {
ALog.e(TAG, String.format("路径【%s】是文件请设置文件夹路径", mWrapper.getDirPathTemp()));
ALog.e(TAG, String.format("路径【%s】是文件请设置文件夹路径", dirPath));
return false;
}
// 检查路径冲突
if (mWrapper.isNewTask() && !CheckUtil.checkDGPathConflicts(mWrapper.isIgnoreFilePathOccupy(),
mWrapper.getDirPathTemp())) {
dirPath)) {
return false;
}
if (TextUtils.isEmpty(mEntity.getDirPath()) || !mEntity.getDirPath()
.equals(mWrapper.getDirPathTemp())) {
.equals(dirPath)) {
if (!file.exists()) {
file.mkdirs();
}
needModifyPath = true;
mEntity.setDirPath(mWrapper.getDirPathTemp());
ALog.i(TAG, String.format("文件夹路径改变,将更新文件夹路径为:%s", mWrapper.getDirPathTemp()));
mEntity.setDirPath(dirPath);
ALog.i(TAG, String.format("文件夹路径改变,将更新文件夹路径为:%s", dirPath));
}
return true;
}
@@ -123,8 +132,9 @@ public class CheckDGEntityUtil implements ICheckEntityUtil {
* @return false 任务不再执行true 任务继续执行
*/
private boolean checkGroupHash(boolean isIgnoreTaskOccupy, String groupHash) {
DownloadGroupEntity dge = DbEntity.findFirst(DownloadGroupEntity.class, "groupHash=?", groupHash);
if (dge != null && dge.getGroupHash().equals(mEntity.getGroupHash())){
DownloadGroupEntity dge =
DbEntity.findFirst(DownloadGroupEntity.class, "groupHash=?", groupHash);
if (dge != null && dge.getGroupHash().equals(mEntity.getGroupHash())) {
mEntity.rowID = dge.rowID;
return true;
}

View File

@@ -45,32 +45,34 @@ public class CheckFtpDirEntityUtil implements ICheckEntityUtil {
* @return {@code true} 合法
*/
private boolean checkDirPath() {
if (TextUtils.isEmpty(mWrapper.getDirPathTemp())) {
String dirPath = mWrapper.getDirPathTemp();
if (TextUtils.isEmpty(dirPath)) {
ALog.e(TAG, "文件夹路径不能为null");
return false;
} else if (!mWrapper.getDirPathTemp().startsWith("/")) {
ALog.e(TAG, String.format("文件夹路径【%s】错误", mWrapper.getDirPathTemp()));
}
if (!dirPath.startsWith("/")) {
ALog.e(TAG, String.format("文件夹路径【%s】错误", dirPath));
return false;
}
File file = new File(mWrapper.getDirPathTemp());
File file = new File(dirPath);
if (file.isFile()) {
ALog.e(TAG, String.format("路径【%s】是文件请设置文件夹路径", mWrapper.getDirPathTemp()));
ALog.e(TAG, String.format("路径【%s】是文件请设置文件夹路径", dirPath));
return false;
}
// 检查路径冲突
if (mWrapper.isNewTask() && !CheckUtil.checkDGPathConflicts(mWrapper.isIgnoreFilePathOccupy(),
mWrapper.getDirPathTemp())) {
dirPath)) {
return false;
}
if (TextUtils.isEmpty(mEntity.getDirPath()) || !mEntity.getDirPath()
.equals(mWrapper.getDirPathTemp())) {
.equals(dirPath)) {
if (!file.exists()) {
file.mkdirs();
}
mEntity.setDirPath(mWrapper.getDirPathTemp());
ALog.i(TAG, String.format("文件夹路径改变,将更新文件夹路径为:%s", mWrapper.getDirPathTemp()));
mEntity.setDirPath(dirPath);
ALog.i(TAG, String.format("文件夹路径改变,将更新文件夹路径为:%s", dirPath));
}
return true;
}

View File

@@ -20,7 +20,7 @@ import com.arialyy.aria.core.task.DownloadGroupTask;
/**
* @author ChenFei(chenfei0928 @ gmail.com)
* @date 2020-07-07 14:12
* Date: 2020-07-07 14:12
*/
public interface DownloadGroupTaskListener extends NormalTaskListenerInterface<DownloadGroupTask> {
}

View File

@@ -111,8 +111,8 @@ public class DownloadReceiver extends AbsReceiver {
/**
* 加载组合任务,用于任务停止、删除等操作
*
* @param taskId 任务id可从{@link AbsBuilderTarget#create()}、{@link AbsBuilderTarget#add()}、{@link
* * AbsEntity#getId()}读取任务id
* @param taskId 任务id可从{@link AbsBuilderTarget#create}、{@link AbsBuilderTarget#add}、{@link
* AbsEntity#getId}读取任务id
*/
public GroupNormalTarget loadGroup(long taskId) {
@@ -175,6 +175,7 @@ public class DownloadReceiver extends AbsReceiver {
return;
}
if (obj instanceof TaskInternalListenerInterface){
ProxyHelper.getInstance().checkProxyType(obj.getClass());
if (obj instanceof DownloadTaskListener){
TaskSchedulers.getInstance().register(obj, TaskEnum.DOWNLOAD);
}

View File

@@ -19,8 +19,8 @@ import com.arialyy.aria.core.scheduler.NormalTaskListenerInterface;
import com.arialyy.aria.core.task.DownloadTask;
/**
* @author ChenFei(chenfei0928 @ gmail.com)
* @date 2020-07-07 14:12
* @author ChenFei(chenfei0928@gmail.com)
* Date: 2020-07-07 14:12
*/
public interface DownloadTaskListener extends NormalTaskListenerInterface<DownloadTask> {
}

View File

@@ -20,8 +20,8 @@ import com.arialyy.aria.core.common.AbsNormalTarget;
import java.util.List;
/**
* @Author aria
* @Date 2019-09-05
* @author aria
* Date: 2019-09-05
*/
public class DTargetFactory {

View File

@@ -20,8 +20,8 @@ import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.wrapper.ITaskWrapper;
/**
* @Author aria
* @Date 2019-09-06
* @author aria
* Date: 2019-09-06
*/
public class TcpBuilderTarget extends AbsBuilderTarget<TcpBuilderTarget> {

View File

@@ -21,8 +21,8 @@ import com.arialyy.aria.util.ALog;
import java.nio.charset.Charset;
/**
* @Author aria
* @Date 2019-09-06
* @author aria
* Date: 2019-09-06
*/
public class TcpDelegate extends BaseOption {

View File

@@ -18,8 +18,8 @@ package com.arialyy.aria.core.download.tcp;
/**
* tcp任务配置
*
* @Author aria
* @Date 2019-09-06
* @author aria
* Date: 2019-09-06
*/
public class TcpTaskConfig {

View File

@@ -19,7 +19,7 @@ package com.arialyy.aria.core.scheduler;
* 直接实现监听器回调接口的基类,不对外部直接开放,仅作为内部监听器的父接口使用
*
* @author ChenFei(chenfei0928 @ gmail.com)
* @date 2020-07-07 15:18
* Date: 2020-07-07 15:18
*/
public interface TaskInternalListenerInterface {
}

View File

@@ -272,6 +272,7 @@ public class UploadReceiver extends AbsReceiver {
return;
}
if (obj instanceof TaskInternalListenerInterface){
ProxyHelper.getInstance().checkProxyType(obj.getClass());
if (obj instanceof UploadTaskListener){
TaskSchedulers.getInstance().register(obj, TaskEnum.UPLOAD);
}

View File

@@ -22,7 +22,7 @@ import com.arialyy.aria.core.task.UploadTask;
* 上传任务接口
*
* @author ChenFei(chenfei0928 @ gmail.com)
* @date 2020-07-07 13:23
* Date: 2020-07-07 13:23
*/
public interface UploadTaskListener extends NormalTaskListenerInterface<UploadTask> {
}

View File

@@ -19,8 +19,8 @@ import com.arialyy.aria.core.common.AbsBuilderTarget;
import com.arialyy.aria.core.common.AbsNormalTarget;
/**
* @Author aria
* @Date 2019-09-05
* @author aria
* Date: 2019-09-05
*/
public class UTargetFactory {

View File

@@ -11,4 +11,9 @@ dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
}
apply from: 'bintray-release.gradle'
//apply from: 'bintray-release.gradle'
ext{
PUBLISH_ARTIFACT_ID = 'annotations'
}
apply from: '../gradle/mavenCentral-release.gradle'

View File

@@ -15,4 +15,8 @@ dependencies {
implementation project(':AriaAnnotations')
}
apply from: 'bintray-release.gradle'
//apply from: 'bintray-release.gradle'
ext{
PUBLISH_ARTIFACT_ID = 'compiler'
}
apply from: '../gradle/mavenCentral-release.gradle'

View File

@@ -1,4 +1,19 @@
## 开发日志
+ v_3.8.16 (2021/4/18)
- 修复单线程下载时,文件已经完成,重复下载回调下载失败的问题
- 修复一个重新下载文件时,同名路径文件没有被被删除的问题
- fix bug https://github.com/AriaLyy/Aria/issues/807
- fix bug https://github.com/AriaLyy/Aria/issues/811
- fix bug https://github.com/AriaLyy/Aria/issues/851
- 修复组合任务在获取子任务信息的过程中,手动停止或删除,没有回调的问题
+ v_3.8.15 (2020/11/9)
- 修复不支持断点的连接下载失败问题https://github.com/AriaLyy/Aria/issues/771
- 修复iv不存在时索引文件异常的问题https://github.com/AriaLyy/Aria/issues/780
- fix bug https://github.com/AriaLyy/Aria/issues/799
- fix bug https://github.com/AriaLyy/Aria/issues/798
+ v_3.8.14 (2020/9/23)
- 修复spi机制的兼容问题https://github.com/AriaLyy/Aria/issues/743
- 增加路径不可以写的判断,下载时,如果路径不可写,将执行失败回调 https://github.com/AriaLyy/Aria/issues/750
+ v_3.8.12 (2020/8/15)
- 修复一个正则表达式导致的文件名保存号异常问题 https://github.com/AriaLyy/Aria/issues/715
- 修复一个匿名内部类中的内存溢出的问题 https://github.com/AriaLyy/Aria/issues/705

View File

@@ -15,6 +15,9 @@ android {
}
buildTypes {
debug{
debuggable true
}
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
@@ -32,4 +35,8 @@ dependencies {
implementation project(path: ':PublicComponent')
}
apply from: 'bintray-release.gradle'
//apply from: 'bintray-release.gradle'
ext{
PUBLISH_ARTIFACT_ID = 'ftp'
}
apply from: '../gradle/mavenCentral-release.gradle'

View File

@@ -27,6 +27,7 @@ import aria.apache.commons.net.ftp.FTPSClient;
import com.arialyy.aria.core.AriaConfig;
import com.arialyy.aria.core.FtpUrlEntity;
import com.arialyy.aria.core.common.AbsEntity;
import com.arialyy.aria.core.common.CompleteInfo;
import com.arialyy.aria.core.common.FtpConnectionMode;
import com.arialyy.aria.core.loader.IInfoTask;
import com.arialyy.aria.core.loader.ILoaderVisitor;
@@ -55,7 +56,8 @@ public abstract class AbsFtpInfoTask<ENTITY extends AbsEntity, TASK_WRAPPER exte
private int mConnectTimeOut;
protected long mSize = 0;
protected String charSet = "UTF-8";
protected Callback callback;
private Callback callback;
private boolean isStop = false, isCancel = false;
public AbsFtpInfoTask(TASK_WRAPPER taskWrapper) {
mTaskWrapper = taskWrapper;
@@ -81,6 +83,14 @@ public abstract class AbsFtpInfoTask<ENTITY extends AbsEntity, TASK_WRAPPER exte
protected abstract void handelFileInfo(FTPClient client, FTPFile[] files,
String convertedRemotePath) throws IOException;
@Override public void stop() {
isStop = true;
}
@Override public void cancel() {
isCancel = true;
}
@Override public void setCallback(Callback callback) {
this.callback = callback;
}
@@ -101,10 +111,10 @@ public abstract class AbsFtpInfoTask<ENTITY extends AbsEntity, TASK_WRAPPER exte
handelFileInfo(client, files, convertedRemotePath);
} catch (IOException e) {
e.printStackTrace();
failDownload(client, "FTP错误信息", e, true);
handleFail(client, "FTP错误信息", e, true);
} catch (InterruptedException e) {
e.printStackTrace();
failDownload(client, "FTP错误信息", e, true);
handleFail(client, "FTP错误信息", e, true);
} finally {
closeClient(client);
}
@@ -146,7 +156,7 @@ public abstract class AbsFtpInfoTask<ENTITY extends AbsEntity, TASK_WRAPPER exte
}
if (client == null) {
failDownload(client, String.format("链接失败, url: %s", mTaskOption.getUrlEntity().url), null,
handleFail(client, String.format("链接失败, url: %s", mTaskOption.getUrlEntity().url), null,
true);
return null;
}
@@ -168,14 +178,14 @@ public abstract class AbsFtpInfoTask<ENTITY extends AbsEntity, TASK_WRAPPER exte
}
if (!loginSuccess) {
failDownload(client, "登录失败", null, false);
handleFail(client, "登录失败", null, false);
client.disconnect();
return null;
}
int reply = client.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
failDownload(client, String.format("无法连接到ftp服务器filePath: %s, url: %s", mEntity.getKey(),
handleFail(client, String.format("无法连接到ftp服务器filePath: %s, url: %s", mEntity.getKey(),
mTaskOption.getUrlEntity().url), null, true);
client.disconnect();
return null;
@@ -299,7 +309,7 @@ public abstract class AbsFtpInfoTask<ENTITY extends AbsEntity, TASK_WRAPPER exte
for (FTPFile file : files) {
if (file.isFile()) {
size += file.getSize();
handleFile(path + file.getName(), file);
handleFile(client, path + file.getName(), file);
} else {
String remotePath = CommonUtil.convertFtpChar(charSet, path + file.getName());
size += getFileSize(client.listFiles(remotePath), client, path + file.getName());
@@ -314,10 +324,13 @@ public abstract class AbsFtpInfoTask<ENTITY extends AbsEntity, TASK_WRAPPER exte
* @param remotePath ftp服务器文件夹路径
* @param ftpFile ftp服务器上对应的文件
*/
protected void handleFile(String remotePath, FTPFile ftpFile) {
protected void handleFile(FTPClient client, String remotePath, FTPFile ftpFile) {
}
protected void failDownload(FTPClient client, String msg, Exception e, boolean needRetry) {
protected void handleFail(FTPClient client, String msg, Exception e, boolean needRetry) {
if (isStop || isCancel) {
return;
}
if (callback != null) {
if (client == null) {
msg = "创建ftp客户端失败";
@@ -332,6 +345,10 @@ public abstract class AbsFtpInfoTask<ENTITY extends AbsEntity, TASK_WRAPPER exte
}
}
protected void onSucceed(CompleteInfo info){
callback.onSucceed(mEntity.getKey(), info);
}
@Override public void accept(ILoaderVisitor visitor) {
visitor.addComponent(this);
}

View File

@@ -34,8 +34,8 @@ import java.net.UnknownHostException;
import javax.net.ssl.SSLContext;
/**
* @Author lyy
* @Date 2019-09-18
* @author lyy
* Date: 2019-09-18
*/
public abstract class BaseFtpThreadTaskAdapter extends AbsThreadTaskAdapter {

View File

@@ -38,10 +38,10 @@ final class FtpDFileInfoTask extends AbsFtpInfoTask<DownloadEntity, DTaskWrapper
super(taskEntity);
}
@Override protected void handleFile(String remotePath, FTPFile ftpFile) {
super.handleFile(remotePath, ftpFile);
@Override protected void handleFile(FTPClient client, String remotePath, FTPFile ftpFile) {
super.handleFile(client, remotePath, ftpFile);
if (!FileUtil.checkMemorySpace(mEntity.getFilePath(), ftpFile.getSize())) {
callback.onFail(mEntity, new AriaFTPException(
handleFail(client, "内存空间不足", new AriaFTPException(
String.format("获取ftp文件信息失败内存空间不足, filePath: %s", mEntity.getFilePath())),
false);
}
@@ -72,7 +72,7 @@ final class FtpDFileInfoTask extends AbsFtpInfoTask<DownloadEntity, DTaskWrapper
}
closeClient(client);
failDownload(client,
handleFail(client,
String.format("文件不存在url: %s, remotePath%s", mTaskOption.getUrlEntity().url,
getRemotePath()), null, false);
return;
@@ -90,7 +90,7 @@ final class FtpDFileInfoTask extends AbsFtpInfoTask<DownloadEntity, DTaskWrapper
int reply = client.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
closeClient(client);
failDownload(client, "获取文件信息错误url: " + mTaskOption.getUrlEntity().url, null, true);
handleFail(client, "获取文件信息错误url: " + mTaskOption.getUrlEntity().url, null, true);
return;
}
mTaskWrapper.setCode(reply);
@@ -112,6 +112,6 @@ final class FtpDFileInfoTask extends AbsFtpInfoTask<DownloadEntity, DTaskWrapper
mTaskWrapper.setNewTask(true);
}
mEntity.setFileSize(mSize);
callback.onSucceed(mEntity.getUrl(), new CompleteInfo(code, mTaskWrapper));
onSucceed(new CompleteInfo(code, mTaskWrapper));
}
}

View File

@@ -49,7 +49,7 @@ final class FtpDGInfoTask extends AbsFtpInfoTask<DownloadGroupEntity, DGTaskWrap
@Override public void run() {
if (mTaskWrapper.getEntity().getFileSize() > 1 && checkSubOption()) {
callback.onSucceed(mEntity.getKey(), new CompleteInfo(200, mTaskWrapper));
onSucceed(new CompleteInfo(200, mTaskWrapper));
} else {
super.run();
}
@@ -80,7 +80,7 @@ final class FtpDGInfoTask extends AbsFtpInfoTask<DownloadGroupEntity, DGTaskWrap
}
closeClient(client);
failDownload(client,
handleFail(client,
String.format("文件不存在url: %s, remotePath%s", mTaskOption.getUrlEntity().url,
getRemotePath()), null, false);
return;
@@ -98,7 +98,7 @@ final class FtpDGInfoTask extends AbsFtpInfoTask<DownloadGroupEntity, DGTaskWrap
int reply = client.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
closeClient(client);
failDownload(client, "获取文件信息错误url: " + mTaskOption.getUrlEntity().url, null, true);
handleFail(client, "获取文件信息错误url: " + mTaskOption.getUrlEntity().url, null, true);
return;
}
mTaskWrapper.setCode(reply);
@@ -127,8 +127,8 @@ final class FtpDGInfoTask extends AbsFtpInfoTask<DownloadGroupEntity, DGTaskWrap
return mTaskOption.getUrlEntity().remotePath;
}
@Override protected void handleFile(String remotePath, FTPFile ftpFile) {
super.handleFile(remotePath, ftpFile);
@Override protected void handleFile(FTPClient client, String remotePath, FTPFile ftpFile) {
super.handleFile(client, remotePath, ftpFile);
addEntity(remotePath, ftpFile);
}
@@ -138,7 +138,7 @@ final class FtpDGInfoTask extends AbsFtpInfoTask<DownloadGroupEntity, DGTaskWrap
for (DTaskWrapper wrapper : mTaskWrapper.getSubTaskWrapper()) {
cloneInfo(wrapper);
}
callback.onSucceed(mEntity.getKey(), new CompleteInfo(code, mTaskWrapper));
onSucceed(new CompleteInfo(code, mTaskWrapper));
}
private void cloneInfo(DTaskWrapper subWrapper) {
@@ -234,8 +234,8 @@ final class FtpDGInfoTask extends AbsFtpInfoTask<DownloadGroupEntity, DGTaskWrap
}
@Override
protected void failDownload(FTPClient client, String msg, Exception e, boolean needRetry) {
super.failDownload(client, msg, e, needRetry);
protected void handleFail(FTPClient client, String msg, Exception e, boolean needRetry) {
super.handleFail(client, msg, e, needRetry);
DeleteDGRecord.getInstance().deleteRecord(mTaskWrapper.getEntity(), true, true);
}
}

View File

@@ -25,8 +25,8 @@ import com.arialyy.aria.core.loader.NormalThreadStateManager;
import com.arialyy.aria.ftp.FtpTaskOption;
/**
* @Author lyy
* @Date 2019-09-19
* @author lyy
* Date: 2019-09-19
*/
public final class FtpDLoaderUtil extends AbsNormalLoaderUtil {

View File

@@ -27,8 +27,8 @@ import com.arialyy.aria.util.RecordUtil;
import java.util.ArrayList;
/**
* @Author lyy
* @Date 2019-09-19
* @author lyy
* Date: 2019-09-19
*/
final class FtpDRecordHandler extends RecordHandler {

View File

@@ -32,8 +32,8 @@ import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
/**
* @Author lyy
* @Date 2019-09-18
* @author lyy
* Date: 2019-09-18
*/
final class FtpDThreadTaskAdapter extends BaseFtpThreadTaskAdapter {

View File

@@ -19,13 +19,14 @@ import android.os.Handler;
import com.arialyy.aria.core.download.DTaskWrapper;
import com.arialyy.aria.core.group.AbsSubDLoadUtil;
import com.arialyy.aria.core.group.SubRecordHandler;
import com.arialyy.aria.core.loader.GroupSubThreadStateManager;
import com.arialyy.aria.core.loader.LoaderStructure;
import com.arialyy.aria.core.loader.NormalTTBuilder;
import com.arialyy.aria.core.loader.SubLoader;
/**
* @Author lyy
* @Date 2019-09-28
* @author lyy
* Date: 2019-09-28
*/
final class FtpSubDLoaderUtil extends AbsSubDLoadUtil {
/**
@@ -48,6 +49,7 @@ final class FtpSubDLoaderUtil extends AbsSubDLoadUtil {
@Override protected LoaderStructure buildLoaderStructure() {
LoaderStructure structure = new LoaderStructure();
structure.addComponent(new SubRecordHandler(getWrapper()))
.addComponent(new GroupSubThreadStateManager(getSchedulers(),getKey()))
.addComponent(new NormalTTBuilder(getWrapper(), new FtpDTTBuilderAdapter()))
.addComponent(new FtpDFileInfoTask(getWrapper()));
structure.accept(getLoader());

View File

@@ -60,7 +60,7 @@ final class FtpUFileInfoTask extends AbsFtpInfoTask<UploadEntity, UTaskWrapper>
return;
}
handleFile(getRemotePath(), files.length == 0 ? null : files[0]);
handleFile(client, getRemotePath(), files.length == 0 ? null : files[0]);
int reply = client.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
//服务器上没有该文件路径,表示该任务为新的上传任务
@@ -133,8 +133,8 @@ final class FtpUFileInfoTask extends AbsFtpInfoTask<UploadEntity, UTaskWrapper>
* @param remotePath ftp服务器文件夹路径
* @param ftpFile ftp服务器上对应的文件
*/
@Override protected void handleFile(String remotePath, FTPFile ftpFile) {
super.handleFile(remotePath, ftpFile);
@Override protected void handleFile(FTPClient client,String remotePath, FTPFile ftpFile) {
super.handleFile(client, remotePath, ftpFile);
this.ftpFile = ftpFile;
if (ftpFile != null && ftpFile.getSize() == mEntity.getFileSize()) {
isComplete = true;
@@ -145,6 +145,6 @@ final class FtpUFileInfoTask extends AbsFtpInfoTask<UploadEntity, UTaskWrapper>
super.onPreComplete(code);
CompleteInfo info = new CompleteInfo(isComplete ? CODE_COMPLETE : code, mTaskWrapper);
info.obj = ftpFile;
callback.onSucceed(mEntity.getKey(), info);
onSucceed(info);
}
}

View File

@@ -28,8 +28,8 @@ import com.arialyy.aria.core.upload.UTaskWrapper;
import com.arialyy.aria.ftp.FtpTaskOption;
/**
* @Author lyy
* @Date 2019-09-19
* @author lyy
* Date: 2019-09-19
*/
public final class FtpULoaderUtil extends AbsNormalLoaderUtil {

View File

@@ -0,0 +1,2 @@
Manifest-Version: 1.0

View File

@@ -14,6 +14,9 @@ android {
}
buildTypes {
debug{
debuggable true
}
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
@@ -31,4 +34,8 @@ dependencies {
implementation project(path: ':PublicComponent')
}
apply from: 'bintray-release.gradle'
//apply from: 'bintray-release.gradle'
ext{
PUBLISH_ARTIFACT_ID = 'http'
}
apply from: '../gradle/mavenCentral-release.gradle'

View File

@@ -20,8 +20,8 @@ import com.arialyy.aria.core.common.SubThreadConfig;
import com.arialyy.aria.core.task.AbsThreadTaskAdapter;
/**
* @Author lyy
* @Date 2019-09-22
* @author lyy
* Date: 2019-09-22
*/
public abstract class BaseHttpThreadTaskAdapter extends AbsThreadTaskAdapter {
protected HttpTaskOption mTaskOption;

View File

@@ -48,8 +48,6 @@ public final class ConnectionHelp {
/**
* 处理url参数
*
* @throws MalformedURLException
*/
public static URL handleUrl(String url, HttpTaskOption taskDelegate)
throws MalformedURLException {
@@ -127,8 +125,6 @@ public final class ConnectionHelp {
/**
* 设置头部参数
*
* @throws ProtocolException
*/
public static HttpURLConnection setConnectParam(HttpTaskOption delegate, HttpURLConnection conn) {
if (delegate.getRequestEnum() == RequestEnum.POST) {

View File

@@ -28,8 +28,8 @@ import com.arialyy.aria.util.RecordUtil;
import java.util.ArrayList;
/**
* @Author lyy
* @Date 2019-09-23
* @author lyy
* Date: 2019-09-23
*/
public final class HttpRecordHandler extends RecordHandler {
public HttpRecordHandler(AbsTaskWrapper wrapper) {

View File

@@ -64,6 +64,7 @@ final class HttpDFileInfoTask implements IInfoTask, Runnable {
private int mConnectTimeOut;
private Callback callback;
private HttpTaskOption taskOption;
private boolean isStop = false, isCancel = false;
HttpDFileInfoTask(DTaskWrapper taskWrapper) {
this.mTaskWrapper = taskWrapper;
@@ -81,7 +82,7 @@ final class HttpDFileInfoTask implements IInfoTask, Runnable {
conn = ConnectionHelp.handleConnection(url, taskOption);
ConnectionHelp.setConnectParam(taskOption, conn);
conn.setRequestProperty("Range", "bytes=" + 0 + "-");
if (AriaConfig.getInstance().getDConfig().isUseHeadRequest()){
if (AriaConfig.getInstance().getDConfig().isUseHeadRequest()) {
ALog.d(TAG, "head请求");
conn.setRequestMethod("HEAD");
}
@@ -111,6 +112,14 @@ final class HttpDFileInfoTask implements IInfoTask, Runnable {
this.callback = callback;
}
@Override public void stop() {
isStop = true;
}
@Override public void cancel() {
isCancel = true;
}
private void handleConnect(HttpURLConnection conn) throws IOException {
if (taskOption.getRequestEnum() == RequestEnum.POST) {
Map<String, String> params = taskOption.getParams();
@@ -232,7 +241,7 @@ final class HttpDFileInfoTask implements IInfoTask, Runnable {
|| code == HttpURLConnection.HTTP_CREATED // 201 跳转
|| code == 307) {
handleUrlReTurn(conn, conn.getHeaderField("Location"));
}else if (code == 416){ // 处理0k长度的文件的情况
} else if (code == 416) { // 处理0k长度的文件的情况
ALog.w(TAG, "文件长度为0不支持断点");
mTaskWrapper.setSupportBP(false);
mTaskWrapper.setNewTask(true);
@@ -245,12 +254,13 @@ final class HttpDFileInfoTask implements IInfoTask, Runnable {
String.format("任务下载失败errorCode%s, errorMsg: %s, url: %s", code,
conn.getResponseMessage(), mEntity.getUrl())), !CheckUtil.httpIsBadRequest(code));
}
if (isStop || isCancel) {
return;
}
if (end) {
taskOption.setChunked(isChunked);
if (callback != null) {
CompleteInfo info = new CompleteInfo(code, mTaskWrapper);
callback.onSucceed(mEntity.getUrl(), info);
}
CompleteInfo info = new CompleteInfo(code, mTaskWrapper);
callback.onSucceed(mEntity.getUrl(), info);
mEntity.update();
}
}
@@ -343,7 +353,7 @@ final class HttpDFileInfoTask implements IInfoTask, Runnable {
ConnectionHelp.setConnectParam(taskOption, conn);
conn.setRequestProperty("Cookie", cookies);
conn.setRequestProperty("Range", "bytes=" + 0 + "-");
if (AriaConfig.getInstance().getDConfig().isUseHeadRequest()){
if (AriaConfig.getInstance().getDConfig().isUseHeadRequest()) {
conn.setRequestMethod("HEAD");
}
conn.setConnectTimeout(mConnectTimeOut);
@@ -367,6 +377,9 @@ final class HttpDFileInfoTask implements IInfoTask, Runnable {
}
private void failDownload(AriaHTTPException e, boolean needRetry) {
if (isStop || isCancel) {
return;
}
if (callback != null) {
callback.onFail(mEntity, e, needRetry);
}

View File

@@ -20,7 +20,6 @@ import com.arialyy.aria.core.common.CompleteInfo;
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.listener.DownloadGroupListener;
import com.arialyy.aria.core.loader.IInfoTask;
import com.arialyy.aria.core.loader.ILoaderVisitor;
import com.arialyy.aria.exception.AriaException;
@@ -44,7 +43,20 @@ public final class HttpDGInfoTask implements IInfoTask {
private boolean getLenComplete = false;
private AtomicInteger count = new AtomicInteger();
private AtomicInteger failCount = new AtomicInteger();
private DownloadGroupListener listener;
private boolean isStop = false, isCancel = false;
public interface DGInfoCallback extends Callback {
/**
* 子任务失败
*/
void onSubFail(DownloadEntity subEntity, AriaHTTPException e, boolean needRetry);
/**
* 组合任务停止
*/
void onStop(long len);
}
/**
* 子任务回调
@@ -60,15 +72,32 @@ public final class HttpDGInfoTask implements IInfoTask {
ALog.e(TAG, String.format("获取文件信息失败url%s", ((DownloadEntity) entity).getUrl()));
count.getAndIncrement();
failCount.getAndIncrement();
listener.onSubFail((DownloadEntity) entity, new AriaHTTPException(
String.format("子任务获取文件长度失败url%s", ((DownloadEntity) entity).getUrl())));
((DGInfoCallback) callback).onSubFail((DownloadEntity) entity, new AriaHTTPException(
String.format("子任务获取文件长度失败url%s", ((DownloadEntity) entity).getUrl())), needRetry);
checkGetSizeComplete(count.get(), failCount.get());
}
};
HttpDGInfoTask(DGTaskWrapper wrapper, DownloadGroupListener listener) {
HttpDGInfoTask(DGTaskWrapper wrapper) {
this.wrapper = wrapper;
this.listener = listener;
}
/**
* 停止
*/
@Override
public void stop() {
isStop = true;
if (mPool != null) {
mPool.shutdown();
}
}
@Override public void cancel() {
isCancel = true;
if (mPool != null) {
mPool.shutdown();
}
}
@Override public void run() {
@@ -76,7 +105,7 @@ public final class HttpDGInfoTask implements IInfoTask {
if (mPool != null && !getLenComplete) {
ALog.d(TAG, "获取长度未完成的情况下,停止组合任务");
mPool.shutdown();
listener.onStop(0);
((DGInfoCallback)callback).onStop(0);
return;
}
// 处理组合任务大小未知的情况
@@ -131,6 +160,11 @@ public final class HttpDGInfoTask implements IInfoTask {
* 检查组合任务大小是否获取完成,获取完成后取消阻塞,并设置组合任务大小
*/
private void checkGetSizeComplete(int count, int failCount) {
if (isStop || isCancel) {
ALog.w(TAG, "任务已停止或已取消isStop = " + isStop + ", isCancel = " + isCancel);
notifyLock();
return;
}
if (failCount == wrapper.getSubTaskWrapper().size()) {
callback.onFail(wrapper.getEntity(), new AriaHTTPException("获取子任务长度失败"), false);
notifyLock();

View File

@@ -26,6 +26,7 @@ import com.arialyy.aria.core.listener.DownloadGroupListener;
import com.arialyy.aria.core.loader.IInfoTask;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.exception.AriaException;
import com.arialyy.aria.exception.AriaHTTPException;
import java.io.File;
/**
@@ -64,7 +65,17 @@ final class HttpDGLoader extends AbsGroupLoader {
@Override public void addComponent(IInfoTask infoTask) {
mInfoTask = infoTask;
mInfoTask.setCallback(new IInfoTask.Callback() {
mInfoTask.setCallback(new HttpDGInfoTask.DGInfoCallback() {
@Override
public void onSubFail(DownloadEntity subEntity, AriaHTTPException e, boolean needRetry) {
getState().countFailNum(subEntity.getKey());
}
@Override public void onStop(long len) {
getListener().onStop(len);
}
@Override public void onSucceed(String key, CompleteInfo info) {
startSub();
}

View File

@@ -38,8 +38,7 @@ public final class HttpDGLoaderUtil extends AbsGroupLoaderUtil {
@Override protected LoaderStructure buildLoaderStructure() {
LoaderStructure structure = new LoaderStructure();
structure.addComponent(new HttpDGInfoTask((DGTaskWrapper) getTaskWrapper(),
(DownloadGroupListener) getListener()));
structure.addComponent(new HttpDGInfoTask((DGTaskWrapper) getTaskWrapper()));
structure.accept(getLoader());
return structure;
}

View File

@@ -29,8 +29,8 @@ import com.arialyy.aria.http.HttpRecordHandler;
import com.arialyy.aria.http.HttpTaskOption;
/**
* @Author lyy
* @Date 2019-09-21
* @author lyy
* Date: 2019-09-21
*/
public final class HttpDLoaderUtil extends AbsNormalLoaderUtil {

View File

@@ -35,10 +35,13 @@ final class HttpDTTBuilderAdapter extends AbsNormalTTBuilderAdapter {
BufferedRandomAccessFile file = null;
try {
if (totalThreadNum > 1 && !record.isBlock) {
file = new BufferedRandomAccessFile(new File(getTempFile().getPath()), "rwd", 8192);
file = new BufferedRandomAccessFile(getTempFile().getPath(), "rwd", 8192);
//设置文件长度
file.setLength(getEntity().getFileSize());
}
if (getTempFile().exists()) {
FileUtil.deleteFile(getTempFile());
}
return true;
} catch (IOException e) {
e.printStackTrace();

View File

@@ -25,8 +25,8 @@ import com.arialyy.aria.core.loader.NormalTTBuilder;
import com.arialyy.aria.core.loader.SubLoader;
/**
* @Author lyy
* @Date 2019-09-28
* @author lyy
* Date: 2019-09-28
*/
final class HttpSubDLoaderUtil extends AbsSubDLoadUtil {
/**

View File

@@ -29,8 +29,8 @@ import com.arialyy.aria.http.HttpRecordHandler;
import com.arialyy.aria.http.HttpTaskOption;
/**
* @Author lyy
* @Date 2019-09-19
* @author lyy
* Date: 2019-09-19
*/
public final class HttpULoaderUtil extends AbsNormalLoaderUtil {

View File

@@ -102,7 +102,7 @@ final class HttpUThreadTaskAdapter extends BaseHttpThreadTaskAdapter {
}
uploadFile(writer, mTaskOption.getAttachment(), uploadFile);
getEntity().setResponseStr(finish(writer));
finish(writer);
} catch (Exception e) {
e.printStackTrace();
fail(new AriaHTTPException(
@@ -214,10 +214,12 @@ final class HttpUThreadTaskAdapter extends BaseHttpThreadTaskAdapter {
}
reader.close();
mHttpConn.disconnect();
getEntity().setResponseStr(response.toString());
complete();
} else {
String msg = "response msg: " + mHttpConn.getResponseMessage() + "code: " + status;
ALog.e(TAG, msg);
getEntity().setResponseStr(response.toString());
fail(new AriaHTTPException(msg), false);
response.append(status);
}

View File

@@ -0,0 +1,2 @@
Manifest-Version: 1.0

View File

@@ -15,6 +15,9 @@ android {
}
buildTypes {
debug{
debuggable true
}
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
@@ -33,4 +36,8 @@ dependencies {
implementation project(path: ':PublicComponent')
}
apply from: 'bintray-release.gradle'
//apply from: 'bintray-release.gradle'
ext{
PUBLISH_ARTIFACT_ID = 'm3u8'
}
apply from: '../gradle/mavenCentral-release.gradle'

View File

@@ -95,9 +95,21 @@ public abstract class BaseM3U8Loader extends AbsNormalLoader<DTaskWrapper> {
i++;
} 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"));
StringBuilder sb = new StringBuilder("#EXT-X-KEY:");
sb.append("METHOD=").append(m3U8Entity.method);
sb.append(",URI=\"").append(m3U8Entity.keyPath).append("\"");
if (!TextUtils.isEmpty(m3U8Entity.iv)) {
sb.append(",IV=").append(m3U8Entity.iv);
}
if (!TextUtils.isEmpty(m3U8Entity.keyFormat)) {
sb.append(",KEYFORMAT=\"").append(m3U8Entity.keyFormat).append("\"");
sb.append(",KEYFORMATVERSIONS=\"")
.append(TextUtils.isEmpty(m3U8Entity.keyFormatVersion) ? "1"
: m3U8Entity.keyFormatVersion)
.append("\"");
}
sb.append("\r\n");
bytes = sb.toString().getBytes(Charset.forName("UTF-8"));
} else {
bytes = line.concat("\r\n").getBytes(Charset.forName("UTF-8"));
}

View File

@@ -7,11 +7,8 @@ public final class IdGenerator {
* <p>
* 主要就是三部分: 时间戳进程id序列号 时间戳41id10位序列号12位
*
* @author chiwei
* @param args
* @since JDK 1.6
*/
private static volatile IdGenerator INSTANCE = null;
private final static long beginTs = 1483200000000L;

View File

@@ -115,6 +115,14 @@ final public class M3U8InfoTask implements IInfoTask {
mCallback = callback;
}
@Override public void stop() {
this.isStop = true;
}
@Override public void cancel() {
this.isStop = true;
}
private void handleConnect(String tsListUrl, HttpURLConnection conn) throws IOException {
int code = conn.getResponseCode();
if (code == HttpURLConnection.HTTP_OK) {
@@ -205,8 +213,7 @@ final public class M3U8InfoTask implements IInfoTask {
}
CompleteInfo info = new CompleteInfo();
info.obj = extInf;
mCallback.onSucceed(mEntity.getKey(), info);
onSucceed(info);
if (fos != null) {
fos.close();
}
@@ -223,6 +230,13 @@ final public class M3U8InfoTask implements IInfoTask {
}
}
private void onSucceed(CompleteInfo info) {
if (isStop) {
return;
}
mCallback.onSucceed(mEntity.getKey(), info);
}
/**
* 添加切片信息到索引文件中
* 直播下载的索引只记录头部信息不记录EXTINF中的信息该信息在onGetPeer的方法中添加。
@@ -362,6 +376,9 @@ final public class M3U8InfoTask implements IInfoTask {
}
private void failDownload(String errorInfo, boolean needRetry) {
if (isStop) {
return;
}
mCallback.onFail(mEntity, new AriaM3U8Exception(errorInfo), needRetry);
}

View File

@@ -31,8 +31,8 @@ import java.io.File;
import java.util.ArrayList;
/**
* @Author lyy
* @Date 2019-09-24
* @author lyy
* Date: 2019-09-24
*/
final class VodRecordHandler extends RecordHandler {
private M3U8TaskOption mOption;

View File

@@ -0,0 +1,2 @@
Manifest-Version: 1.0

View File

@@ -15,6 +15,9 @@ android {
}
buildTypes {
debug{
debuggable true
}
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
@@ -32,4 +35,8 @@ dependencies {
testImplementation 'junit:junit:4.12'
}
apply from: 'bintray-release.gradle'
//apply from: 'bintray-release.gradle'
ext{
PUBLISH_ARTIFACT_ID = 'public'
}
apply from: '../gradle/mavenCentral-release.gradle'

View File

@@ -38,8 +38,8 @@ import java.util.Map;
/**
* 任务配置参数
*
* @Author lyy
* @Date 2019-09-10
* @author lyy
* Date: 2019-09-10
*/
public class TaskOptionParams {

View File

@@ -29,8 +29,8 @@ import java.io.IOException;
/**
* 任务记录帮助类,用于处理统一的逻辑
*
* @Author lyy
* @Date 2019-09-19
* @author lyy
* Date: 2019-09-19
*/
public class RecordHelper {
private String TAG = CommonUtil.getClassName(getClass());
@@ -76,7 +76,7 @@ public class RecordHelper {
tr.endLocation = endL;
}
}
mWrapper.setNewTask(false);
//mWrapper.setNewTask(false);
}
/**
@@ -125,8 +125,8 @@ public class RecordHelper {
continue;
}
long realLocation =
tr.threadId * normalRectLen + blockFileLen; //正常情况下该线程的startLocation的位置
//正常情况下该线程的startLocation的位置
long realLocation = tr.threadId * normalRectLen + blockFileLen;
/*
* 检查记录文件
*/
@@ -147,7 +147,7 @@ public class RecordHelper {
}
}
}
mWrapper.setNewTask(false);
//mWrapper.setNewTask(false);
}
/**
@@ -190,7 +190,7 @@ public class RecordHelper {
tr.isComplete = false;
}
}
mWrapper.setNewTask(false);
//mWrapper.setNewTask(false);
}
/**

View File

@@ -31,7 +31,7 @@ import com.arialyy.aria.util.CommonUtil;
* Created by lyy on 2015/12/25.
* 下载实体
*/
public class DownloadEntity extends AbsNormalEntity implements Parcelable {
public class DownloadEntity extends AbsNormalEntity implements Parcelable, Cloneable {
@Unique private String downloadPath; //保存路径
/**

View File

@@ -217,14 +217,24 @@ public abstract class AbsGroupLoader implements ILoaderVisitor, ILoader {
@Override public void cancel() {
isCancel = true;
if (mInfoTask != null){
mInfoTask.cancel();
}
closeTimer();
mSubQueue.removeAllTask();
mListener.onCancel();
}
@Override public void stop() {
if (mInfoTask != null){
mInfoTask.stop();
}
isStop = true;
mSubQueue.stopAllTask();
if (mSubQueue.getExecSize() == 0) {
mListener.onStop(mGTWrapper.getEntity().getCurrentProgress());
} else {
mSubQueue.stopAllTask();
}
closeTimer();
}

View File

@@ -47,7 +47,6 @@ public final class GroupRunState {
* 停止的任务数
*/
private AtomicInteger mStopNum = new AtomicInteger();
;
/**
* 当前进度

View File

@@ -182,7 +182,7 @@ final class SimpleSchedulers implements Handler.Callback {
Log.d(TAG,
String.format("handleComplete, size = %s, completeNum = %s, failNum = %s, stopNum = %s",
mGState.getSubSize(), mGState.getCompleteNum(), mGState.getFailNum(),
mGState.getSubSize()));
mGState.getStopNum()));
TaskRecord record = loader.getRecord();
if (record != null && record.isBlock) {

View File

@@ -43,7 +43,7 @@ final class SimpleSubQueue implements ISubQueue<AbsSubDLoadUtil> {
/**
* 最大执行任务数
*/
private int mExecSize;
private int mMaxExecSize;
/**
* 是否停止任务任务
@@ -51,7 +51,7 @@ final class SimpleSubQueue implements ISubQueue<AbsSubDLoadUtil> {
private boolean isStopAll = false;
private SimpleSubQueue() {
mExecSize = Configuration.getInstance().dGroupCfg.getSubMaxTaskNum();
mMaxExecSize = Configuration.getInstance().dGroupCfg.getSubMaxTaskNum();
}
static SimpleSubQueue newInstance() {
@@ -73,6 +73,10 @@ final class SimpleSubQueue implements ISubQueue<AbsSubDLoadUtil> {
return mCache.size();
}
public int getExecSize(){
return mExec.size();
}
boolean isStopAll() {
return isStopAll;
}
@@ -82,7 +86,7 @@ final class SimpleSubQueue implements ISubQueue<AbsSubDLoadUtil> {
}
@Override public void startTask(AbsSubDLoadUtil fileer) {
if (mExec.size() < mExecSize) {
if (mExec.size() < mMaxExecSize) {
mCache.remove(fileer.getKey());
mExec.put(fileer.getKey(), fileer);
ALog.d(TAG,
@@ -102,6 +106,7 @@ final class SimpleSubQueue implements ISubQueue<AbsSubDLoadUtil> {
@Override public void stopAllTask() {
isStopAll = true;
ALog.d(TAG, "停止组合任务");
mCache.clear();
Set<String> keys = mExec.keySet();
for (String key : keys) {
AbsSubDLoadUtil loader = mExec.get(key);
@@ -117,12 +122,12 @@ final class SimpleSubQueue implements ISubQueue<AbsSubDLoadUtil> {
ALog.e(TAG, String.format("修改组合任务子任务队列数失败num: %s", num));
return;
}
if (num == mExecSize) {
ALog.i(TAG, String.format("忽略此次修改oldSize: %s, num: %s", mExecSize, num));
if (num == mMaxExecSize) {
ALog.i(TAG, String.format("忽略此次修改oldSize: %s, num: %s", mMaxExecSize, num));
return;
}
int oldSize = mExecSize;
mExecSize = num;
int oldSize = mMaxExecSize;
mMaxExecSize = num;
int diff = Math.abs(oldSize - num);
if (oldSize < num) { // 处理队列变小的情况,该情况下将停止队尾任务,并将这些任务添加到缓存队列中

View File

@@ -18,8 +18,8 @@ package com.arialyy.aria.core.inf;
/**
* 事件处理对象
*
* @Author lyy
* @Date 2019-09-10
* @author lyy
* Date: 2019-09-10
*/
public interface IEventHandler {
}

View File

@@ -16,8 +16,8 @@
package com.arialyy.aria.core.inf;
/**
* @Author lyy
* @Date 2019-09-10
* @author lyy
* Date: 2019-09-10
*/
public interface IOptionConstant {
// ftp 任务设置常量

View File

@@ -229,6 +229,9 @@ public abstract class AbsNormalLoader<T extends AbsTaskWrapper> implements ILoad
ALog.d(TAG, String.format("任务【%s】正在删除删除任务失败", mTaskWrapper.getKey()));
return;
}
if (mInfoTask != null){
mInfoTask.cancel();
}
closeTimer();
isCancel = true;
onCancel();
@@ -262,6 +265,9 @@ public abstract class AbsNormalLoader<T extends AbsTaskWrapper> implements ILoad
if (isStop) {
return;
}
if (mInfoTask != null){
mInfoTask.stop();
}
closeTimer();
isStop = true;
onStop();

View File

@@ -34,6 +34,16 @@ public interface IInfoTask extends ILoaderComponent {
*/
void setCallback(Callback callback);
/**
* 任务停止
*/
void stop();
/**
* 任务取消
*/
void cancel();
interface Callback {
/**
* 处理完成

View File

@@ -21,8 +21,8 @@ import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.core.common.SubThreadConfig;
/**
* @Author lyy
* @Date 2019-09-18
* @author lyy
* Date: 2019-09-18
*/
public interface ILoaderAdapter {

View File

@@ -19,8 +19,8 @@ import com.arialyy.aria.core.TaskRecord;
import com.arialyy.aria.core.ThreadRecord;
/**
* @Author lyy
* @Date 2019-09-18
* @author lyy
* Date: 2019-09-18
*/
public interface IRecordHandler extends ILoaderComponent {

View File

@@ -70,12 +70,9 @@ public final class NormalTTBuilder implements IThreadTaskBuilder {
private List<IThreadTask> handleNoSupportBP() {
List<IThreadTask> list = new ArrayList<>();
mStartThreadNum = 1;
mRecord.isBlock = false;
mRecord.update();
IThreadTask task = createSingThreadTask(mRecord.threadRecords.get(0), 1);
if (task == null) {
ALog.e(TAG, "创建线程任务失败");
return null;
}
list.add(task);
return list;
}

View File

@@ -105,16 +105,16 @@ public class NormalThreadStateManager implements IThreadStateManager {
// mergerSFtp();
// mListener.onComplete();
//} else
if (mTaskRecord.isBlock) {
if (mTaskRecord.isBlock || mTaskRecord.threadNum == 1) {
if (mergeFile()) {
mListener.onComplete();
} else {
mListener.onFail(false, null);
}
} else {
mListener.onComplete();
quitLooper();
break;
}
mListener.onComplete();
quitLooper();
}
break;
@@ -248,8 +248,13 @@ public class NormalThreadStateManager implements IThreadStateManager {
*/
private boolean mergeFile() {
if (mTaskRecord.threadNum == 1) {
File targetFile = new File(mTaskRecord.filePath);
if (targetFile.exists() && targetFile.length() == mTaskRecord.fileLength){
return true;
}
FileUtil.deleteFile(targetFile);
File partFile = new File(String.format(IRecordHandler.SUB_PATH, mTaskRecord.filePath, 0));
return partFile.renameTo(new File(mTaskRecord.filePath));
return partFile.renameTo(targetFile);
}
List<String> partPath = new ArrayList<>();

View File

@@ -182,6 +182,9 @@ public final class SubLoader implements ILoader, ILoaderVisitor {
return;
}
isStop = true;
if (infoTask != null){
infoTask.stop();
}
for (IThreadTask iThreadTask : mTask) {
iThreadTask.stop();
}
@@ -203,6 +206,9 @@ public final class SubLoader implements ILoader, ILoaderVisitor {
return;
}
isCancel = true;
if (infoTask != null){
infoTask.cancel();
}
for (IThreadTask iThreadTask : mTask) {
iThreadTask.cancel();
}

View File

@@ -21,8 +21,8 @@ import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @Author lyy
* @Date 2019-10-7
* @author lyy
* Date: 2019-10-7
* 处理器的动态代理
*/
public class ProxyHandler implements InvocationHandler {

View File

@@ -24,8 +24,8 @@ import com.arialyy.aria.util.BandwidthLimiter;
import com.arialyy.aria.util.CommonUtil;
/**
* @Author lyy
* @Date 2019-09-18
* @author lyy
* Date: 2019-09-18
*/
public abstract class AbsThreadTaskAdapter implements IThreadTaskAdapter {

View File

@@ -18,8 +18,8 @@ package com.arialyy.aria.core.task;
import java.util.concurrent.Callable;
/**
* @Author lyy
* @Date 2019-09-18
* @author lyy
* Date: 2019-09-18
*/
public interface IThreadTask extends Callable<IThreadTask> {

View File

@@ -18,8 +18,8 @@ package com.arialyy.aria.core.task;
/**
* 线程适配器
*
* @Author lyy
* @Date 2019-09-18
* @author lyy
* Date: 2019-09-18
*/
public interface IThreadTaskAdapter {

View File

@@ -22,8 +22,8 @@ import com.arialyy.aria.exception.AriaException;
/**
* 线程任务观察者
*
* @Author lyy
* @Date 2019-09-18
* @author lyy
* Date: 2019-09-18
*/
public interface IThreadTaskObserver {

View File

@@ -225,7 +225,7 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver {
File blockFile = mConfig.tempFile;
if (!blockFile.exists() || blockFile.length() != mRecord.blockLen) {
ALog.i(TAG,
String.format("分块【%s】错误blockFileLen: %s, threadRect: %s; 即将重新下载该分块开始位置:%s结束位置%s",
String.format("分块【%s】错误blockFileLen: %s, threadRect: %s; 即将重新下载该分块, 开始位置:%s结束位置%s",
blockFile.getName(), blockFile.length(), mRecord.blockLen, mRecord.startLocation,
mRecord.endLocation));
if (blockFile.exists()) {
@@ -310,7 +310,8 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver {
}
@Override public synchronized void updateCompleteState() {
ALog.i(TAG, String.format("任务【%s】线程__%s__完成", getTaskWrapper().getKey(), mRecord.threadId));
ALog.i(TAG, String.format("任务【%s】线程__%s__完成, blockSize = %s", getTaskWrapper().getKey(),
mRecord.threadId, mConfig.tempFile.length()));
writeConfig(true, mRecord.endLocation);
// 进度发送不是实时的,发送完成任务前,需要更新一次进度
sendRunningState();
@@ -420,7 +421,7 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver {
* 重试ts分片
*/
private void retryM3U8Peer(boolean needRetry) {
if (mConfig.ignoreFailure){
if (mConfig.ignoreFailure) {
ALog.d(TAG, "忽略失败的切片");
sendFailMsg(null, false);
return;
@@ -431,9 +432,10 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver {
sendFailMsg(null, false);
return;
}
if (mFailTimes < RETRY_NUM && needRetry && (NetUtils.isConnected(
AriaConfig.getInstance().getAPP())
|| isNotNetRetry) && !isBreak()) {
if (mFailTimes < RETRY_NUM
&& needRetry
&& (NetUtils.isConnected(AriaConfig.getInstance().getAPP()) || isNotNetRetry)
&& !isBreak()) {
ALog.w(TAG, String.format("ts切片【%s】第%s重试", getFileName(), String.valueOf(mFailTimes)));
mFailTimes++;
FileUtil.deleteFile(mConfig.tempFile);
@@ -455,15 +457,19 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver {
sendFailMsg(null, false);
return;
}
if (mFailTimes < RETRY_NUM && needRetry && (NetUtils.isConnected(
AriaConfig.getInstance().getAPP()) || isNotNetRetry) && !isBreak()) {
if (mFailTimes < RETRY_NUM
&& needRetry
&& (NetUtils.isConnected(AriaConfig.getInstance().getAPP()) || isNotNetRetry)
&& !isBreak()) {
ALog.w(TAG, String.format("分块【%s】第%s次重试", getFileName(), String.valueOf(mFailTimes)));
mFailTimes++;
handleBlockRecord();
ThreadTaskManager.getInstance().retryThread(this);
return;
}
ALog.e(TAG, String.format("任务【%s】执行失败", getFileName()));
ALog.e(TAG,
String.format("重试分开【%s】失败failTimes = %s, needRetry = %s, isBreak = %s",
getFileName(), mFailTimes, needRetry, isBreak()));
sendFailMsg(null, needRetry);
}

View File

@@ -32,7 +32,7 @@ import java.util.ServiceLoader;
* 参考{@link ServiceLoader}
*/
public class AriaServiceLoader<S> {
private static final String TAG = "AriaServiceLoader";
private static final String PREFIX = "META-INF/services/";
// The class or interface representing the service being loaded
@@ -177,6 +177,10 @@ public class AriaServiceLoader<S> {
}
private S loadService(String serviceName) {
if (pending == null){
ALog.e(TAG, "pending为空");
return null;
}
for (String s : pending) {
if (s.equals(serviceName)) {
Class<?> c = null;

View File

@@ -24,16 +24,18 @@ import com.arialyy.aria.core.listener.IEventListener;
import com.arialyy.aria.core.task.AbsTask;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.core.wrapper.ITaskWrapper;
import com.arialyy.aria.exception.AriaComponentException;
import java.lang.ref.SoftReference;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
/**
* 组件工具,用于跨组件创建对应的工具类
*
* @Author lyy
* @Date 2019-09-23
* @author lyy
* Date: 2019-09-23
*/
public class ComponentUtil {
public static final int COMPONENT_TYPE_HTTP = 1;
@@ -43,12 +45,9 @@ public class ComponentUtil {
private String TAG = CommonUtil.getClassName(getClass());
private static volatile ComponentUtil INSTANCE = null;
private AriaServiceLoader<IUtil> utilLoader;
private AriaServiceLoader<IEventListener> listenerLoader;
private ComponentUtil() {
utilLoader = AriaServiceLoader.load(IUtil.class);
listenerLoader = AriaServiceLoader.load(IEventListener.class);
}
public static ComponentUtil getInstance() {
@@ -105,7 +104,8 @@ public class ComponentUtil {
*
* @return 返回任务工具
*/
public synchronized IUtil buildUtil(AbsTaskWrapper wrapper, IEventListener listener) {
public synchronized <T extends IUtil> T buildUtil(AbsTaskWrapper wrapper,
IEventListener listener) {
int requestType = wrapper.getRequestType();
String className = null;
switch (requestType) {
@@ -140,11 +140,30 @@ public class ComponentUtil {
className = "com.arialyy.aria.sftp.upload.SFtpULoaderUtil";
break;
}
IUtil util = utilLoader.getService(className);
if (util == null) {
throw new AriaComponentException("加载工具异常,请求类型:" + wrapper.getRequestType());
if (className == null) {
ALog.e(TAG, "不识别的类名:" + className);
return null;
}
return util.setParams(wrapper, listener);
T util = null;
try {
Class<T> clazz = (Class<T>) getClass().getClassLoader().loadClass(className);
Constructor<T> con = clazz.getConstructor();
util = con.newInstance();
Method method =
CommonUtil.getMethod(clazz, "setParams", AbsTaskWrapper.class, IEventListener.class);
method.invoke(util, wrapper, listener);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return util;
}
/**
@@ -153,7 +172,7 @@ public class ComponentUtil {
* @param wrapperType 任务类型{@link ITaskWrapper}
* @return 返回事件监听如果创建失败返回null
*/
public synchronized IEventListener buildListener(int wrapperType, AbsTask task,
public synchronized <T extends IEventListener> T buildListener(int wrapperType, AbsTask task,
Handler outHandler) {
String className = null, errorStr = "请添加FTP插件";
switch (wrapperType) {
@@ -180,12 +199,26 @@ public class ComponentUtil {
if (className == null) {
return null;
}
IEventListener listener = listenerLoader.getService(className);
if (listener == null) {
throw new AriaComponentException(errorStr);
T listener = null;
try {
Class<T> clazz = (Class<T>) getClass().getClassLoader().loadClass(className);
Constructor<T> con = clazz.getConstructor();
listener = con.newInstance();
Method method =
CommonUtil.getMethod(clazz, "setParams", AbsTask.class, Handler.class);
method.invoke(listener, task, outHandler);
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException(errorStr);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return listener.setParams(task, outHandler);
return listener;
}
/**

View File

@@ -25,6 +25,7 @@ import android.os.StatFs;
import android.os.storage.StorageManager;
import android.os.storage.StorageVolume;
import android.text.TextUtils;
import android.util.Log;
import com.arialyy.aria.core.AriaConfig;
import java.io.BufferedReader;
import java.io.File;
@@ -322,6 +323,7 @@ public class FileUtil {
* @return {@code true} 合并成功,{@code false}合并失败
*/
public static boolean mergeFile(String targetPath, List<String> subPaths) {
Log.d(TAG, "开始合并文件");
File file = new File(targetPath);
FileOutputStream fos = null;
FileChannel foc = null;
@@ -691,7 +693,7 @@ public class FileUtil {
return list;
}
private static boolean canWrite(String dirPath) {
public static boolean canWrite(String dirPath) {
File dir = new File(dirPath);
if (dir.canWrite()) {
return true;

View File

@@ -0,0 +1,2 @@
Manifest-Version: 1.0

View File

@@ -45,19 +45,19 @@ Aria有以下特点
## 引入库
[![license](http://img.shields.io/badge/license-Apache2.0-brightgreen.svg?style=flat)](https://github.com/AriaLyy/Aria/blob/master/LICENSE)
[![Core](https://img.shields.io/badge/Core-3.8.12-blue)](https://github.com/AriaLyy/Aria)
[![Compiler](https://img.shields.io/badge/Compiler-3.8.12-blue)](https://github.com/AriaLyy/Aria)
[![FtpComponent](https://img.shields.io/badge/FtpComponent-3.8.12-orange)](https://github.com/AriaLyy/Aria)
[![FtpComponent](https://img.shields.io/badge/SFtpComponent-3.8.12-orange)](https://github.com/AriaLyy/Aria)
[![M3U8Component](https://img.shields.io/badge/M3U8Component-3.8.12-orange)](https://github.com/AriaLyy/Aria)
[![Core](https://img.shields.io/badge/Core-3.8.16-blue)](https://github.com/AriaLyy/Aria)
[![Compiler](https://img.shields.io/badge/Compiler-3.8.16-blue)](https://github.com/AriaLyy/Aria)
[![FtpComponent](https://img.shields.io/badge/FtpComponent-3.8.16-orange)](https://github.com/AriaLyy/Aria)
[![FtpComponent](https://img.shields.io/badge/SFtpComponent-3.8.16-orange)](https://github.com/AriaLyy/Aria)
[![M3U8Component](https://img.shields.io/badge/M3U8Component-3.8.16-orange)](https://github.com/AriaLyy/Aria)
```java
implementation 'com.arialyy.aria:core:3.8.12'
annotationProcessor 'com.arialyy.aria:compiler:3.8.12'
implementation 'com.arialyy.aria:ftpComponent:3.8.12' # 如果需要使用ftp请增加该组件
implementation 'com.arialyy.aria:sftpComponent:3.8.12' # 如果需要使用ftp请增加该组件
implementation 'com.arialyy.aria:m3u8Component:3.8.12' # 如果需要使用m3u8下载功能请增加该组件
implementation 'me.laoyuyu.aria:core:3.8.16'
annotationProcessor 'me.laoyuyu.aria:compiler:3.8.16'
implementation 'me.laoyuyu.aria:ftp:3.8.16' # 如果需要使用ftp请增加该组件
implementation 'me.laoyuyu.aria:sftp:3.8.16' # 如果需要使用ftp请增加该组件
implementation 'me.laoyuyu.aria:m3u8:3.8.16' # 如果需要使用m3u8下载功能请增加该组件
```
如果你使用的是kotlin请使用kotlin官方提供的方法配置apt[kotlin kapt官方配置传送门](https://www.kotlincn.net/docs/reference/kapt.html)
@@ -138,22 +138,14 @@ protected void onCreate(Bundle savedInstanceState) {
### 版本日志
+ v_3.8.12 (2020/8/15)
- 修复一个正则表达式导致的文件名保存号异常问题 https://github.com/AriaLyy/Aria/issues/715
- 修复一个匿名内部类中的内存溢出的问题 https://github.com/AriaLyy/Aria/issues/705
- 修复同一个url地址的任务提示路径冲突的问题
- 修复m3u8任务地址错误时无法删除实体的问题 https://github.com/AriaLyy/Aria/issues/712
- 修复m3u8gzip的问题https://github.com/AriaLyy/Aria/issues/639
- 修复http表单上传本地md5和上传的服务的的文件md5不一致的问题 https://github.com/AriaLyy/Aria/issues/730
- 修复0kb的文件不可下载的问题 https://github.com/AriaLyy/Aria/issues/711
- 修复加密的m3u8下载并且使用索引模式时key的uri没有使用双引号的问题 https://github.com/AriaLyy/Aria/issues/731
- 修复删除m3u8索引文件后下载完成回调无法触发的问题
- 修复删除加密的m3u8文件时key没有被删除的问题 https://github.com/AriaLyy/Aria/issues/735#issuecomment-673958845
- 增加m3u8密钥下载地址转换器增加ts列表的url地址 https://github.com/AriaLyy/Aria/issues/718
- 增加现在http文件下载将使用HEAD请求获取文件大小配置文件增加 <useHeadRequest value="true"/>。慎用并不是所有服务器都支持head请求
- 增加允许不使用apt直接通过实现监听器来回调下载进度更新该功能由[chenfei0928](https://github.com/chenfei0928)提交感谢他的pr。如果注解不生效只需要实现`DownloadListener`接口便可
- 增加m3u8使用`ignoreFailureTs`后将不会自动重试失败的切片 https://github.com/AriaLyy/Aria/issues/662
+ v_3.8.16
- 修复单线程下载时,文件已经完成,重复下载回调下载失败的问题
- 修复一个重新下载文件时,同名路径文件没有被被删除的问题
- fix bug https://github.com/AriaLyy/Aria/issues/807
- fix bug https://github.com/AriaLyy/Aria/issues/811
- fix bug https://github.com/AriaLyy/Aria/issues/851
- 修复组合任务在获取子任务信息的过程中,手动停止或删除,没有回调的问题
[更多版本记录](https://github.com/AriaLyy/Aria/blob/master/DEV_LOG.md)
## 混淆配置
@@ -181,6 +173,7 @@ 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>
[我的博客](https://www.laoyuyu.me)
## 捐赠
Aria是作业利用业余时间开发的一个项目如果你喜欢我写的软件可以考虑给我捐赠以支持我的工作</br>

View File

@@ -15,6 +15,9 @@ android {
}
buildTypes {
debug{
debuggable true
}
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
@@ -34,4 +37,8 @@ dependencies {
implementation project(path: ':PublicComponent')
}
apply from: 'bintray-release.gradle'
//apply from: 'bintray-release.gradle'
ext{
PUBLISH_ARTIFACT_ID = 'sftp'
}
apply from: '../gradle/mavenCentral-release.gradle'

View File

@@ -16,6 +16,7 @@
package com.arialyy.aria.sftp;
import com.arialyy.aria.core.FtpUrlEntity;
import com.arialyy.aria.core.common.CompleteInfo;
import com.arialyy.aria.core.loader.IInfoTask;
import com.arialyy.aria.core.loader.ILoaderVisitor;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
@@ -32,9 +33,10 @@ import java.io.UnsupportedEncodingException;
*/
public abstract class AbsSFtpInfoTask<WP extends AbsTaskWrapper> implements IInfoTask {
protected String TAG = CommonUtil.getClassName(this);
protected Callback callback;
private Callback callback;
private WP wrapper;
private SFtpTaskOption option;
private boolean isStop = false, isCancel = false;
public AbsSFtpInfoTask(WP wp) {
this.wrapper = wp;
@@ -44,6 +46,28 @@ public abstract class AbsSFtpInfoTask<WP extends AbsTaskWrapper> implements IInf
protected abstract void getFileInfo(Session session)
throws JSchException, UnsupportedEncodingException, SftpException;
@Override public void stop() {
isStop = true;
}
@Override public void cancel() {
isCancel = true;
}
protected void handleFail(AriaException e, boolean needRetry) {
if (isStop || isCancel){
return;
}
callback.onFail(getWrapper().getEntity(), e, needRetry);
}
protected void onSucceed(CompleteInfo info){
if (isStop || isCancel){
return;
}
callback.onSucceed(getWrapper().getKey(), info);
}
@Override public void run() {
try {
FtpUrlEntity entity = option.getUrlEntity();

View File

@@ -39,7 +39,7 @@ final class SFtpDInfoTask extends AbsSFtpInfoTask<DTaskWrapper> {
}
@Override protected void getFileInfo(Session session) throws JSchException,
UnsupportedEncodingException, SftpException {
UnsupportedEncodingException {
SFtpTaskOption option = (SFtpTaskOption) getWrapper().getTaskOption();
ChannelSftp channel = (ChannelSftp) session.openChannel("sftp");
channel.connect(1000);
@@ -60,10 +60,9 @@ final class SFtpDInfoTask extends AbsSFtpInfoTask<DTaskWrapper> {
getWrapper().getEntity().setFileSize(attr.getSize());
CompleteInfo info = new CompleteInfo();
info.code = 200;
callback.onSucceed(getWrapper().getKey(), info);
onSucceed(info);
} else {
callback.onFail(getWrapper().getEntity(),
new AriaSFTPException(String.format("文件不存在remotePath%s", remotePath)), false);
handleFail(new AriaSFTPException(String.format("文件不存在remotePath%s", remotePath)), false);
}
channel.disconnect();
}

View File

@@ -27,8 +27,8 @@ import com.arialyy.aria.util.RecordUtil;
import java.util.ArrayList;
/**
* @Author lyy
* @Date 2019-09-19
* @author lyy
* Date: 2019-09-19
*/
final class SFtpDRecordHandler extends RecordHandler {

View File

@@ -64,6 +64,6 @@ final class SFtpUInfoTask extends AbsSFtpInfoTask<UTaskWrapper> {
info.code = isComplete ? ISCOMPLETE : 200;
info.obj = attr;
channel.disconnect();
callback.onSucceed(getWrapper().getKey(), info);
onSucceed(info);
}
}

View File

@@ -0,0 +1,2 @@
Manifest-Version: 1.0

View File

@@ -30,9 +30,14 @@ android {
}
buildTypes {
debug {
debuggable true
minifyEnabled false //混淆
}
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
zipAlignEnabled true
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
}
}
@@ -43,16 +48,12 @@ android {
packagingOptions {
exclude 'META-INF/services/javax.annotation.processing.Processor'
merge 'META-INF/services/com.arialyy.aria.core.inf.IUtil'
}
lintOptions {
abortOnError false
}
// sourceSets {
// main.kotlin.srcDirs += 'src/main/kotlin'
// main.java.srcDirs += 'src/main/java'
// }
}
dependencies {
@@ -61,6 +62,7 @@ dependencies {
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0'
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'com.google.android.material:material:1.0.0'
@@ -70,16 +72,23 @@ dependencies {
implementation 'com.github.bumptech.glide:glide:3.7.0'
implementation 'com.pddstudio:highlightjs-android:1.5.0'
implementation 'org.greenrobot:eventbus:3.1.1'
implementation project(':AppFrame')
// aria
kapt project(':AriaCompiler')
implementation project(':Aria')
implementation project(':AppFrame')
implementation project(':M3U8Component')
implementation project(':FtpComponent')
implementation project(path: ':AriaAnnotations')
implementation project(path: ':SFtpComponent')
// implementation 'com.arialyy.aria:core:3.8.12'
// kapt 'com.arialyy.aria:compiler:3.8.12'
// implementation 'com.arialyy.aria:ftpComponent:3.8.12' // 如果需要使用ftp请增加该组件
// implementation 'com.arialyy.aria:sftpComponent:3.8.12' // 如果需要使用ftp请增加该组件
// implementation 'com.arialyy.aria:m3u8Component:3.8.12' // 如果需要使用m3u8下载功能请增加该组件
debugImplementation 'com.amitshekhar.android:debug-db:1.0.6'
}
repositories {

135
app/proguard-rules.pro vendored Normal file
View File

@@ -0,0 +1,135 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
################################### 混淆配置 start ###########################################
#指定代码的压缩级别
-optimizationpasses 1
#包明不混合大小写
-dontusemixedcaseclassnames
#不去忽略非公共的库类
-dontskipnonpubliclibraryclasses
#优化 不优化输入的类文件
-dontoptimize
#预校验
-dontpreverify
#混淆时是否记录日志
-verbose
# 混淆时所采用的算法
#-optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/*
-optimizations !code/simplification/cast,!field/*,!class/merging/*
#-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
#忽略警告
#-ignorewarning
################################### 混淆配置 end ############################################
################## 记录生成的日志数据,gradle build时在本项目根目录输出 #################
####### 输出文件夹 build/outputs/mapping
#apk 包内所有 class 的内部结构
-dump build/outputs/mapping/class_files.txt
#未混淆的类和成员
-printseeds build/outputs/mapping/kpa_seeds.txt
#列出从 apk 中删除的代码
-printusage build/outputs/mapping/kpa_unused.txt
#混淆前后的映射
-printmapping build/outputs/mapping/kpa_mapping.txt
################## 记录生成的日志数据gradle build时 在本项目根目录输出-end #################
################## 常用属性配置-start ##################
# 保护注解
-keepattributes *Annotation*
# 保护support v4 包
-dontwarn android.support.v4.app.**
-keep class android.support.v4.app.**{ *; }
# 保护andorid x
-keep class com.google.android.material.** {*;}
-keep class androidx.** {*;}
-keep public class * extends androidx.**
-keep interface androidx.** {*;}
-dontwarn com.google.android.material.**
-dontnote com.google.android.material.**
-dontwarn androidx.**
# 保护一些奇葩的问题
-dontwarn org.xmlpull.v1.XmlPullParser
-dontwarn org.xmlpull.v1.XmlSerializer
-keep class org.xmlpull.v1.* {*;}
# 保护JS接口
-keepclassmembers class * {
@android.webkit.JavascriptInterface <methods>;
}
##保持 native 方法不被混淆
-keepclasseswithmembernames class * {
native <methods>;
}
##保持 Parcelable 不被混淆
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
##保持 Serializable 不被混淆
-keepnames class * implements java.io.Serializable
#
#保持 Serializable 不被混淆并且enum 类也不被混淆
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
#避免混淆泛型 如果混淆报错建议关掉
#keepattributes Signature
# webview + js
-keepattributes *JavascriptInterface*
################## 常用属性配置-end ##################
################## kotlin-start ##################
-keep class kotlin.** { *; }
-keep class kotlin.Metadata { *; }
-dontwarn kotlin.**
-keepclassmembers class **$WhenMappings {
<fields>;
}
-keepclassmembers class kotlin.Metadata {
public <methods>;
}
-assumenosideeffects class kotlin.jvm.internal.Intrinsics {
static void checkParameterIsNotNull(java.lang.Object, java.lang.String);
}
################## kotlin-end ##################
-dontwarn com.arialyy.aria.**
-keep class com.arialyy.aria.**{*;}
-keep class **$$DownloadListenerProxy{ *; }
-keep class **$$UploadListenerProxy{ *; }
-keep class **$$DownloadGroupListenerProxy{ *; }
-keep class **$$DGSubListenerProxy{ *; }
-keepclasseswithmembernames class * {
@Download.* <methods>;
@Upload.* <methods>;
@DownloadGroup.* <methods>;
}
-keep class com.arialyy.aria.ftp.download.FtpDLoaderUtil{*;}
-adaptresourcefilenames **.IUtil
-adaptresourcefilecontents **.IUtil

View File

@@ -44,7 +44,7 @@
3、从3.4.1开始如果线程数为1文件初始化时将不再预占用对应长度的空间下载多少byte则占多大的空间
对于采用多线程的任务或旧任务,依然采用原来的文件空间占用方式;
-->
<threadNum value="3"/>
<threadNum value="1"/>
<!--设置下载队列最大任务数, 默认为2-->
<maxTaskNum value="1"/>

View File

@@ -33,7 +33,7 @@ public class FtpDownloadModule extends BaseViewModule {
private final String FTP_URL_KEY = "FTP_URL_KEY";
private final String FTP_PATH_KEY = "FTP_PATH_KEY";
private final String ftpDefUrl = "ftp://9.9.9.50:2121/Cyberduck-6.9.4.30164.zip";
private final String ftpDefUrl = "ftp://192.168.0.104:2121/qqqq.exe";
private final String ftpDefPath =
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath();
@@ -46,12 +46,12 @@ public class FtpDownloadModule extends BaseViewModule {
LiveData<DownloadEntity> getFtpDownloadInfo(Context context) {
//String url = AppUtil.getConfigValue(context, FTP_URL_KEY, ftpDefUrl);
//String filePath = AppUtil.getConfigValue(context, FTP_PATH_KEY, ftpDefPath);
String url = "ftp://9.9.9.72:2121/Cyberduck-6.9.4.30164.zip";
//String url = "ftp://9.9.9.72:2121/Cyberduck-6.9.4.30164.zip";
singDownloadInfo = Aria.download(context).getFirstDownloadEntity(url);
singDownloadInfo = Aria.download(context).getFirstDownloadEntity(ftpDefUrl);
if (singDownloadInfo == null) {
singDownloadInfo = new DownloadEntity();
singDownloadInfo.setUrl(url);
singDownloadInfo.setUrl(ftpDefUrl);
String name = getFileName(ftpDefUrl);
singDownloadInfo.setFileName(name);
singDownloadInfo.setFilePath(ftpDefPath + name);

View File

@@ -52,8 +52,10 @@ public class HttpDownloadModule extends BaseViewModule {
//String url = "http://fdfs.speedata.cn:9989/group1/M00/00/05/rBGFrl3fdAKAVJwfMtSa9R18wLU139.zip";
//String url = "http://9.9.9.28:8088/files/update.zip";
String url = "https://y.qq.com/download/import/QQMusic-import-1.2.1.zip";
//String url = "https://gitee.com/huang-junhua/iptv/raw/master/guonei.m3u8";
//String url = "http://v.kjjl100.com/kz/zx/cj/2020cjswxdb/1.mp4";
//String url = "https://static.runoob.com/images/demo/demo2.jpg";
String filePath = "/mnt/sdcard/update.zip";
String filePath = "/mnt/sdcard/qq.zip";
singDownloadInfo = Aria.download(context).getFirstDownloadEntity(url);
if (singDownloadInfo == null) {

View File

@@ -35,12 +35,14 @@ import com.arialyy.aria.core.common.AbsEntity;
import com.arialyy.aria.core.common.HttpOption;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadTaskListener;
import com.arialyy.aria.core.download.target.HttpNormalTarget;
import com.arialyy.aria.core.listener.ISchedulers;
import com.arialyy.aria.core.processor.IHttpFileLenAdapter;
import com.arialyy.aria.core.scheduler.NormalTaskListenerInterface;
import com.arialyy.aria.core.task.DownloadTask;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
import com.arialyy.aria.util.FileUtil;
import com.arialyy.frame.util.show.T;
import com.arialyy.simple.R;
import com.arialyy.simple.base.BaseActivity;
@@ -120,6 +122,25 @@ public class SingleTaskActivity extends BaseActivity<ActivitySingleBinding> {
@Override public void cancel(View v, AbsEntity entity) {
Aria.download(this).load(mTaskId).cancel(false);
// //1. 删除本地文件目录
// File localDirFile = new File(mFilePath);
// if (localDirFile.exists()) {
// FileUtil.deleteDir(localDirFile.getParentFile());
// }
//
// //2. 删除记录
// HttpNormalTarget target = Aria.download(SingleTaskActivity.this).load(mTaskId);
// if (target != null) {
// // target.cancel();
// target.removeRecord();
// }
//
// List<DownloadEntity> notCompleteTask = Aria.download(SingleTaskActivity.this).getAllNotCompleteTask();
// if (notCompleteTask == null){
// Log.d(TAG, "未完成的任务数0");
// return;
// }
// Log.d(TAG, "未完成的任务数:" + notCompleteTask.size());
}
});
}
@@ -245,7 +266,7 @@ public class SingleTaskActivity extends BaseActivity<ActivitySingleBinding> {
if (task.getKey().equals(mUrl)) {
Toast.makeText(SingleTaskActivity.this, getString(R.string.download_success),
Toast.LENGTH_SHORT).show();
//ALog.d(TAG, "文件md5: 9886e90f014d462b560dcec9c327bdb7");
ALog.d(TAG, "文件md5: e088677570afe2e9f847cc8159b932dd");
ALog.d(TAG, "下载完成的文件md5: " + CommonUtil.getFileMD5(new File(task.getFilePath())));
getBinding().pl.setInfo(task.getEntity());
getBinding().pl.setProgress(100);

View File

@@ -36,7 +36,7 @@ import com.arialyy.simple.widget.SubStateLinearLayout;
* Created by lyy on 2017/7/6.
*/
public class FTPDirDownloadActivity extends BaseActivity<ActivityDownloadGroupBinding> {
private static final String dir = "ftp://9.9.9.72:2121/upload/测试";
private static final String dir = "ftp://192.168.0.104:2121/aab/你好";
private SubStateLinearLayout mChildList;
private long mTaskId = -1;
@@ -51,8 +51,10 @@ public class FTPDirDownloadActivity extends BaseActivity<ActivityDownloadGroupBi
if (entity != null) {
mTaskId = entity.getId();
mChildList.addData(entity.getSubEntities());
getBinding().pl.setInfo(entity);
}else {
entity = new DownloadGroupEntity();
}
getBinding().pl.setInfo(entity);
getBinding().pl.setBtListener(new ProgressLayout.OnProgressLayoutBtListener() {
@Override public void create(View v, AbsEntity entity) {
mTaskId = Aria.download(this)

View File

@@ -32,9 +32,9 @@ public class GroupModule extends BaseModule {
public List<String> getUrls() {
List<String> urls = new ArrayList<>();
urls.add("http://61.155.99.75:88/sdkdown.muzhiwan.com/openfile/2019/10/26/com.mrxz.mzw_5db3eeef782b1.apk");
urls.add("http://cpsdown.muzhiwan.com/2020/05/07/com.kaihei.wufan.mars_5eb3947b4341b.apk");
urls.add("http://113.143.35.118:88/sdkdown.muzhiwan.com/openfile/2019/11/27/com.droidhang.ad.mzw_5dde4ffe2b2e5.apk");
urls.add("http://storage.jd.com/apk/newchannel/jingdongdaojia-lechuang30.apk");
urls.add("https://appdownload.alicdn.com/publish/cainiao4android/latest/cainiao4android_1598322688221.apk");
urls.add("https://yanxuan-dl.nosdn.127.net/yan/android/yanxuan-aos_out_3547.apk");
return urls;
}
List<String> getUrls1() {
@@ -50,9 +50,9 @@ public class GroupModule extends BaseModule {
List<String> names = new ArrayList<>();
//String[] str = getContext().getResources().getStringArray(R.array.group_names);
//Collections.addAll(names, str);
names.add("末日血战.apk");
names.add("开黑三国.apk");
names.add("放置奇兵.apk");
names.add("京东到家.apk");
names.add("菜鸟.apk");
names.add("网易严选.apk");
//names.add("4.png");
//names.add("5.png");
return names;

View File

@@ -314,7 +314,7 @@ public class M3U8VodDLoadActivity extends BaseActivity<ActivityM3u8VodBinding> {
option.generateIndexFile();
//option.setKeyUrlConverter(new KeyUrlConverter());
//option.setVodTsUrlConvert(new VodTsUrlConverter());
//option.setBandWidthUrlConverter(new BandWidthUrlConverter());
option.setBandWidthUrlConverter(new BandWidthUrlConverter());
//option.setUseDefConvert(true);
return option;
}

View File

@@ -35,7 +35,8 @@ public class M3U8VodModule extends BaseViewModule {
//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://pp3zvsk2n.bkt.clouddn.com/20200806/sd/15967206011811803/38475fadd55e4ecea3.m3u8";
private final String defUrl = "https://5.voooe.cn/cache/youku/4e00b49a6e4f11155967c2cb3385a2ab.m3u8";
//private final String defUrl = "http://pp3zvsk2n.bkt.clouddn.com/20200806/sd/15967206011811803/38475fadd55e4ecea3.m3u8";
//private final String defUrl = "http://youku.cdn7-okzy.com/20200123/16815_fbe419ed/index.m3u8";
//private final String defUrl = "https://cn7.kankia.com/hls/20200108/e1eaec074274c64fe46a3bdb5d2ba487/1578488360/index.m3u8";

Some files were not shown because too many files have changed in this diff Show More