Compare commits
22 Commits
3.8.12
...
afa6434664
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
afa6434664 | ||
|
|
00a81220cb | ||
|
|
ebbbbee1f8 | ||
|
|
6eab496b6a | ||
|
|
3679e0cb23 | ||
|
|
66f9aa9cd5 | ||
|
|
edb3e66a96 | ||
|
|
1c0765be02 | ||
|
|
5853fe9e3e | ||
|
|
9db8f1e9c0 | ||
|
|
35e66caab5 | ||
|
|
bcfb78109b | ||
|
|
d7d081ffb1 | ||
|
|
840facd1cc | ||
|
|
f67f829dfc | ||
|
|
0152187aa8 | ||
|
|
68c992962b | ||
|
|
514fa4321d | ||
|
|
313e047d1f | ||
|
|
62ad99e252 | ||
|
|
8785bb2875 | ||
|
|
7be93b38c2 |
2
.github/ISSUE_TEMPLATE/Custom.md
vendored
2
.github/ISSUE_TEMPLATE/Custom.md
vendored
@@ -11,6 +11,8 @@ about: 提交问题前,请先阅读文档和搜索issue
|
||||
|
||||
* 系统版本
|
||||
|
||||
## 错误的url
|
||||
|
||||
## 错误日志
|
||||
<!-- 请提供详细的错误日志 -->
|
||||
|
||||
|
||||
5
.github/stale.yml
vendored
5
.github/stale.yml
vendored
@@ -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
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -12,7 +12,7 @@ import javax.crypto.spec.SecretKeySpec;
|
||||
/**
|
||||
* AES加密
|
||||
*
|
||||
* @author lyy
|
||||
* author lyy
|
||||
*/
|
||||
public class AESEncryption {
|
||||
/**
|
||||
|
||||
@@ -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'
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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> {
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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> {
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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> {
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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 {
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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> {
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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'
|
||||
@@ -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'
|
||||
15
DEV_LOG.md
15
DEV_LOG.md
@@ -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
|
||||
|
||||
@@ -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'
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
2
FtpComponent/src/main/resources/META-INF/MANIFEST.MF
Normal file
2
FtpComponent/src/main/resources/META-INF/MANIFEST.MF
Normal file
@@ -0,0 +1,2 @@
|
||||
Manifest-Version: 1.0
|
||||
|
||||
@@ -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'
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 {
|
||||
/**
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
2
HttpComponent/src/main/resources/META-INF/MANIFEST.MF
Normal file
2
HttpComponent/src/main/resources/META-INF/MANIFEST.MF
Normal file
@@ -0,0 +1,2 @@
|
||||
Manifest-Version: 1.0
|
||||
|
||||
@@ -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'
|
||||
@@ -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"));
|
||||
}
|
||||
|
||||
@@ -7,11 +7,8 @@ public final class IdGenerator {
|
||||
* <p>
|
||||
* 主要就是三部分: 时间戳,进程id,序列号 时间戳41,id10位,序列号12位
|
||||
*
|
||||
* @author chiwei
|
||||
* @param args
|
||||
* @since JDK 1.6
|
||||
*/
|
||||
|
||||
private static volatile IdGenerator INSTANCE = null;
|
||||
|
||||
private final static long beginTs = 1483200000000L;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
2
M3U8Component/src/main/resources/META-INF/MANIFEST.MF
Normal file
2
M3U8Component/src/main/resources/META-INF/MANIFEST.MF
Normal file
@@ -0,0 +1,2 @@
|
||||
Manifest-Version: 1.0
|
||||
|
||||
@@ -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'
|
||||
@@ -38,8 +38,8 @@ import java.util.Map;
|
||||
/**
|
||||
* 任务配置参数
|
||||
*
|
||||
* @Author lyy
|
||||
* @Date 2019-09-10
|
||||
* @author lyy
|
||||
* Date: 2019-09-10
|
||||
*/
|
||||
public class TaskOptionParams {
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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; //保存路径
|
||||
|
||||
/**
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,6 @@ public final class GroupRunState {
|
||||
* 停止的任务数
|
||||
*/
|
||||
private AtomicInteger mStopNum = new AtomicInteger();
|
||||
;
|
||||
|
||||
/**
|
||||
* 当前进度
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) { // 处理队列变小的情况,该情况下将停止队尾任务,并将这些任务添加到缓存队列中
|
||||
|
||||
@@ -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 {
|
||||
}
|
||||
|
||||
@@ -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 任务设置常量
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -34,6 +34,16 @@ public interface IInfoTask extends ILoaderComponent {
|
||||
*/
|
||||
void setCallback(Callback callback);
|
||||
|
||||
/**
|
||||
* 任务停止
|
||||
*/
|
||||
void stop();
|
||||
|
||||
/**
|
||||
* 任务取消
|
||||
*/
|
||||
void cancel();
|
||||
|
||||
interface Callback {
|
||||
/**
|
||||
* 处理完成
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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<>();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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> {
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
|
||||
2
PublicComponent/src/main/resources/META-INF/MANIFEST.MF
Normal file
2
PublicComponent/src/main/resources/META-INF/MANIFEST.MF
Normal file
@@ -0,0 +1,2 @@
|
||||
Manifest-Version: 1.0
|
||||
|
||||
45
README.md
45
README.md
@@ -45,19 +45,19 @@ 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)
|
||||
[](https://github.com/AriaLyy/Aria)
|
||||
[](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>
|
||||
|
||||
@@ -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'
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
2
SFtpComponent/src/main/resources/META-INF/MANIFEST.MF
Normal file
2
SFtpComponent/src/main/resources/META-INF/MANIFEST.MF
Normal file
@@ -0,0 +1,2 @@
|
||||
Manifest-Version: 1.0
|
||||
|
||||
@@ -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
135
app/proguard-rules.pro
vendored
Normal 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
|
||||
@@ -44,7 +44,7 @@
|
||||
3、从3.4.1开始,如果线程数为1,文件初始化时将不再预占用对应长度的空间,下载多少byte,则占多大的空间;
|
||||
对于采用多线程的任务或旧任务,依然采用原来的文件空间占用方式;
|
||||
-->
|
||||
<threadNum value="3"/>
|
||||
<threadNum value="1"/>
|
||||
|
||||
<!--设置下载队列最大任务数, 默认为2-->
|
||||
<maxTaskNum value="1"/>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user