HttpDBlockInterceptor

v4
laoyuyu 2 years ago
parent 4a74e457d5
commit 9a2976827f
  1. 6
      Aria/src/main/java/com/arialyy/aria/core/common/FtpOption.java
  2. 6
      Aria/src/main/java/com/arialyy/aria/core/common/HttpOption.java
  3. 6
      Aria/src/main/java/com/arialyy/aria/core/download/CheckDEntityUtil.java
  4. 4
      Aria/src/main/java/com/arialyy/aria/core/download/CheckDGEntityUtil.java
  5. 4
      Aria/src/main/java/com/arialyy/aria/core/download/CheckFtpDirEntityUtil.java
  6. 16
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java
  7. 4
      Aria/src/main/java/com/arialyy/aria/core/download/m3u8/M3U8LiveOption.java
  8. 8
      Aria/src/main/java/com/arialyy/aria/core/download/m3u8/M3U8Option.java
  9. 4
      Aria/src/main/java/com/arialyy/aria/core/download/m3u8/M3U8VodOption.java
  10. 6
      Aria/src/main/java/com/arialyy/aria/core/upload/CheckUEntityUtil.java
  11. 12
      Aria/src/main/java/com/arialyy/aria/core/upload/UploadReceiver.java
  12. 6
      FtpComponent/src/main/java/com/arialyy/aria/ftp/AbsFtpInfoTask.java
  13. 6
      Http/src/main/java/com/arialyy/aria/http/HttpUtil.kt
  14. 74
      Http/src/main/java/com/arialyy/aria/http/download/HttpDBlockInterceptor.kt
  15. 8
      Http/src/main/java/com/arialyy/aria/http/download/HttpDFileInfoTask.java
  16. 4
      Http/src/main/java/com/arialyy/aria/http/download/HttpDHeaderInterceptor.kt
  17. 4
      M3U8Component/src/main/java/com/arialyy/aria/m3u8/M3U8InfoTask.java
  18. 4
      M3U8Component/src/main/java/com/arialyy/aria/m3u8/M3U8ThreadTaskAdapter.java
  19. 5
      PublicComponent/src/main/java/com/arialyy/aria/core/inf/IBlockManager.java
  20. 32
      PublicComponent/src/main/java/com/arialyy/aria/core/task/BlockState.kt
  21. 38
      PublicComponent/src/main/java/com/arialyy/aria/core/task/BlockUtil.kt
  22. 13
      PublicComponent/src/main/java/com/arialyy/aria/core/task/DBlockManager.kt
  23. 3
      PublicComponent/src/main/java/com/arialyy/aria/core/task/TaskResp.kt
  24. 4
      PublicComponent/src/main/java/com/arialyy/aria/orm/dao/RecordDao.kt
  25. 23
      PublicComponent/src/main/java/com/arialyy/aria/orm/entity/BlockRecord.kt
  26. 83
      PublicComponent/src/main/java/com/arialyy/aria/util/CheckUtil.kt
  27. 70
      PublicComponent/src/main/java/com/arialyy/aria/util/Ext.kt
  28. 1
      PublicComponent/src/main/java/com/arialyy/aria/util/FileUtil.java
  29. 183
      PublicComponent/src/main/java/com/arialyy/aria/util/FileUtils.kt

@ -21,7 +21,7 @@ import com.arialyy.aria.core.IdEntity;
import com.arialyy.aria.core.ProtocolType;
import com.arialyy.aria.core.processor.IFtpUploadInterceptor;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil;
import com.arialyy.aria.util.FileUtils;
import java.text.DateFormatSymbols;
import java.util.Collection;
import java.util.Locale;
@ -158,7 +158,7 @@ public class FtpOption extends BaseOption {
if (uploadInterceptor == null) {
throw new NullPointerException("ftp拦截器为空");
}
CheckUtil.checkMemberClass(uploadInterceptor.getClass());
FileUtils.checkMemberClass(uploadInterceptor.getClass());
this.uploadInterceptor = uploadInterceptor;
return this;
}
@ -212,7 +212,7 @@ public class FtpOption extends BaseOption {
ALog.e(TAG, "ip为空");
return this;
}
if (!CheckUtil.checkIp(ip)) {
if (!FileUtils.checkIp(ip)) {
ALog.e(TAG, "ip地址错误:" + ip);
return this;
}

@ -19,7 +19,7 @@ import android.text.TextUtils;
import com.arialyy.aria.core.processor.IHttpFileLenAdapter;
import com.arialyy.aria.core.processor.IHttpFileNameAdapter;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil;
import com.arialyy.aria.util.FileUtils;
import java.net.Proxy;
import java.util.HashMap;
import java.util.Map;
@ -166,7 +166,7 @@ public class HttpOption extends BaseOption {
if (fileLenAdapter == null) {
throw new IllegalArgumentException("adapter为空");
}
CheckUtil.checkMemberClass(fileLenAdapter.getClass());
FileUtils.checkMemberClass(fileLenAdapter.getClass());
this.fileLenAdapter = fileLenAdapter;
return this;
}
@ -174,7 +174,7 @@ public class HttpOption extends BaseOption {
if (fileNameAdapter == null) {
throw new IllegalArgumentException("adapter为空");
}
CheckUtil.checkMemberClass(fileNameAdapter.getClass());
FileUtils.checkMemberClass(fileNameAdapter.getClass());
this.fileNameAdapter = fileNameAdapter;
return this;
}

@ -23,7 +23,7 @@ import com.arialyy.aria.core.inf.ITargetHandler;
import com.arialyy.aria.core.wrapper.ITaskWrapper;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil;
import com.arialyy.aria.util.FileUtils;
import com.arialyy.aria.util.CommonUtil;
import com.arialyy.aria.util.FileUtil;
import com.arialyy.aria.util.RecordUtil;
@ -154,7 +154,7 @@ public class CheckDEntityUtil implements ICheckEntityUtil {
//设置文件保存路径,如果新文件路径和旧文件路径不同,则修改路径
if (!filePath.equals(mEntity.getFilePath())) {
// 检查路径冲突
if (!CheckUtil.checkDPathConflicts(mWrapper.isIgnoreFilePathOccupy(), filePath,
if (!FileUtils.checkDPathConflicts(mWrapper.isIgnoreFilePathOccupy(), filePath,
mWrapper.getRequestType())) {
return false;
}
@ -189,7 +189,7 @@ public class CheckDEntityUtil implements ICheckEntityUtil {
if (TextUtils.isEmpty(url)) {
ALog.e(TAG, "下载失败,url为null");
return false;
} else if (!CheckUtil.checkUrl(url)) {
} else if (!FileUtils.checkUrl(url)) {
ALog.e(TAG, "下载失败,url【" + url + "】错误");
return false;
}

@ -22,7 +22,7 @@ import com.arialyy.aria.core.inf.ICheckEntityUtil;
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.FileUtils;
import com.arialyy.aria.util.FileUtil;
import com.arialyy.aria.util.RecordUtil;
import java.io.File;
@ -85,7 +85,7 @@ public class CheckDGEntityUtil implements ICheckEntityUtil {
}
// 检查路径冲突
if (mWrapper.isNewTask() && !CheckUtil.checkDGPathConflicts(mWrapper.isIgnoreFilePathOccupy(),
if (mWrapper.isNewTask() && !FileUtils.checkDGPathConflicts(mWrapper.isIgnoreFilePathOccupy(),
dirPath)) {
return false;
}

@ -20,7 +20,7 @@ import com.arialyy.aria.core.FtpUrlEntity;
import com.arialyy.aria.core.inf.ICheckEntityUtil;
import com.arialyy.aria.core.inf.IOptionConstant;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil;
import com.arialyy.aria.util.FileUtils;
import java.io.File;
public class CheckFtpDirEntityUtil implements ICheckEntityUtil {
@ -61,7 +61,7 @@ public class CheckFtpDirEntityUtil implements ICheckEntityUtil {
}
// 检查路径冲突
if (mWrapper.isNewTask() && !CheckUtil.checkDGPathConflicts(mWrapper.isIgnoreFilePathOccupy(),
if (mWrapper.isNewTask() && !FileUtils.checkDGPathConflicts(mWrapper.isIgnoreFilePathOccupy(),
dirPath)) {
return false;
}

@ -45,7 +45,7 @@ import com.arialyy.aria.core.scheduler.TaskSchedulers;
import com.arialyy.aria.core.task.ITask;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil;
import com.arialyy.aria.util.FileUtils;
import com.arialyy.aria.util.CommonUtil;
import com.arialyy.aria.util.ComponentUtil;
import com.arialyy.aria.util.DbDataHelper;
@ -270,7 +270,7 @@ public class DownloadReceiver extends AbsReceiver {
* @return 如果url错误或查找不到数据则返回null
*/
public DownloadEntity getFirstDownloadEntity(String downloadUrl) {
if (!CheckUtil.checkUrl(downloadUrl)) {
if (!FileUtils.checkUrl(downloadUrl)) {
return null;
}
return DbEntity.findFirst(DownloadEntity.class, "url=? and isGroupChild='false'", downloadUrl);
@ -282,7 +282,7 @@ public class DownloadReceiver extends AbsReceiver {
* @return 如果url错误或查找不到数据则返回null
*/
public List<DownloadEntity> getDownloadEntity(String downloadUrl) {
if (!CheckUtil.checkUrl(downloadUrl)) {
if (!FileUtils.checkUrl(downloadUrl)) {
return null;
}
return DbEntity.findDatas(DownloadEntity.class, "url=? and isGroupChild='false'", downloadUrl);
@ -308,7 +308,7 @@ public class DownloadReceiver extends AbsReceiver {
* @return 如果实体不存在返回null
*/
public DownloadGroupEntity getGroupEntity(List<String> urls) {
if (CheckUtil.checkDownloadUrlsIsEmpty(urls)) {
if (FileUtils.checkDownloadUrlsIsEmpty(urls)) {
return null;
}
return DbDataHelper.getDGEntityByHash(CommonUtil.getMd5Code(urls));
@ -321,7 +321,7 @@ public class DownloadReceiver extends AbsReceiver {
* @return 如果实体不存在返回null
*/
public DownloadGroupEntity getFtpDirEntity(String url) {
if (!CheckUtil.checkUrl(url)) {
if (!FileUtils.checkUrl(url)) {
return null;
}
return DbDataHelper.getDGEntityByHash(url);
@ -387,7 +387,7 @@ public class DownloadReceiver extends AbsReceiver {
* @return 如果页数大于总页数返回null
*/
public List<DownloadEntity> getTaskList(int page, int num) {
CheckUtil.checkPageParams(page, num);
FileUtils.checkPageParams(page, num);
return DbEntity.findDatas(DownloadEntity.class, page, num,
"isGroupChild=? and downloadPath!=''", "false");
}
@ -408,7 +408,7 @@ public class DownloadReceiver extends AbsReceiver {
* @return 如果页数大于总页数返回null
*/
public List<DownloadEntity> getAllNotCompleteTask(int page, int num) {
CheckUtil.checkPageParams(page, num);
FileUtils.checkPageParams(page, num);
return DbEntity.findDatas(DownloadEntity.class, page, num,
"isGroupChild=? and downloadPath!='' and isComplete=?", "false", "false");
}
@ -429,7 +429,7 @@ public class DownloadReceiver extends AbsReceiver {
* @return 如果页数大于总页数返回null
*/
public List<DownloadEntity> getAllCompleteTask(int page, int num) {
CheckUtil.checkPageParams(page, num);
FileUtils.checkPageParams(page, num);
return DbEntity.findDatas(DownloadEntity.class,
"isGroupChild=? and downloadPath!='' and isComplete=?", "false", "true");
}

@ -17,7 +17,7 @@ package com.arialyy.aria.core.download.m3u8;
import com.arialyy.aria.core.processor.ILiveTsUrlConverter;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil;
import com.arialyy.aria.util.FileUtils;
/**
* m3u8直播参数设置
@ -38,7 +38,7 @@ public class M3U8LiveOption extends M3U8Option<M3U8LiveOption> {
* @param liveTsUrlConverter {@link ILiveTsUrlConverter}
*/
public M3U8LiveOption setLiveTsUrlConvert(ILiveTsUrlConverter liveTsUrlConverter) {
CheckUtil.checkMemberClass(liveTsUrlConverter.getClass());
FileUtils.checkMemberClass(liveTsUrlConverter.getClass());
this.liveTsUrlConverter = liveTsUrlConverter;
return this;
}

@ -21,7 +21,7 @@ import com.arialyy.aria.core.processor.IBandWidthUrlConverter;
import com.arialyy.aria.core.processor.IKeyUrlConverter;
import com.arialyy.aria.core.processor.ITsMergeHandler;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil;
import com.arialyy.aria.util.FileUtils;
import com.arialyy.aria.util.ComponentUtil;
/**
@ -101,7 +101,7 @@ public class M3U8Option<OP extends M3U8Option> extends BaseOption {
* 需要注意的是只有{@link #merge(boolean)}设置合并ts文件该方法才会生效
*/
public OP setMergeHandler(ITsMergeHandler mergeHandler) {
CheckUtil.checkMemberClass(mergeHandler.getClass());
FileUtils.checkMemberClass(mergeHandler.getClass());
this.mergeHandler = mergeHandler;
return (OP) this;
}
@ -123,7 +123,7 @@ public class M3U8Option<OP extends M3U8Option> extends BaseOption {
* @param bandWidthUrlConverter {@link IBandWidthUrlConverter}
*/
public OP setBandWidthUrlConverter(IBandWidthUrlConverter bandWidthUrlConverter) {
CheckUtil.checkMemberClass(bandWidthUrlConverter.getClass());
FileUtils.checkMemberClass(bandWidthUrlConverter.getClass());
this.bandWidthUrlConverter = bandWidthUrlConverter;
return (OP) this;
}
@ -134,7 +134,7 @@ public class M3U8Option<OP extends M3U8Option> extends BaseOption {
* @param keyUrlConverter {@link IKeyUrlConverter}
*/
public OP setKeyUrlConverter(IKeyUrlConverter keyUrlConverter) {
CheckUtil.checkMemberClass(keyUrlConverter.getClass());
FileUtils.checkMemberClass(keyUrlConverter.getClass());
this.keyUrlConverter = keyUrlConverter;
return (OP) this;
}

@ -17,7 +17,7 @@ package com.arialyy.aria.core.download.m3u8;
import com.arialyy.aria.core.processor.IVodTsUrlConverter;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil;
import com.arialyy.aria.util.FileUtils;
/**
* m3u8点播文件参数设置
@ -39,7 +39,7 @@ public class M3U8VodOption extends M3U8Option<M3U8VodOption> {
* @param vodUrlConverter {@link IVodTsUrlConverter}
*/
public M3U8VodOption setVodTsUrlConvert(IVodTsUrlConverter vodUrlConverter) {
CheckUtil.checkMemberClass(vodUrlConverter.getClass());
FileUtils.checkMemberClass(vodUrlConverter.getClass());
this.vodUrlConverter = vodUrlConverter;
return this;
}

@ -18,7 +18,7 @@ package com.arialyy.aria.core.upload;
import android.text.TextUtils;
import com.arialyy.aria.core.inf.ICheckEntityUtil;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil;
import com.arialyy.aria.util.FileUtils;
import java.io.File;
public class CheckUEntityUtil implements ICheckEntityUtil {
@ -62,7 +62,7 @@ public class CheckUEntityUtil implements ICheckEntityUtil {
}
// 任务是新任务,并且路径冲突就不会继续执行
if (mWrapper.isNewTask()
&& !CheckUtil.checkUPathConflicts(mWrapper.isIgnoreFilePathOccupy(), filePath,
&& !FileUtils.checkUPathConflicts(mWrapper.isIgnoreFilePathOccupy(), filePath,
mWrapper.getRequestType())) {
return false;
}
@ -86,7 +86,7 @@ public class CheckUEntityUtil implements ICheckEntityUtil {
if (TextUtils.isEmpty(url)) {
ALog.e(TAG, "上传失败,url为null");
return false;
} else if (!CheckUtil.checkUrl(url)) {
} else if (!FileUtils.checkUrl(url)) {
ALog.e(TAG, "上传失败,url【" + url + "】错误");
return false;
}

@ -39,7 +39,7 @@ import com.arialyy.aria.core.upload.target.HttpNormalTarget;
import com.arialyy.aria.core.upload.target.UTargetFactory;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil;
import com.arialyy.aria.util.FileUtils;
import com.arialyy.aria.util.ComponentUtil;
import java.util.List;
import java.util.Set;
@ -73,7 +73,7 @@ public class UploadReceiver extends AbsReceiver {
public HttpBuilderTarget load(String filePath) {
ComponentUtil.getInstance().checkComponentExist(ComponentUtil.COMPONENT_TYPE_HTTP);
CheckUtil.checkUploadPathIsEmpty(filePath);
FileUtils.checkUploadPathIsEmpty(filePath);
return UTargetFactory.getInstance()
.generateBuilderTarget(HttpBuilderTarget.class, filePath);
}
@ -99,7 +99,7 @@ public class UploadReceiver extends AbsReceiver {
public FtpBuilderTarget loadFtp(String filePath) {
ComponentUtil.getInstance().checkComponentExist(ComponentUtil.COMPONENT_TYPE_FTP);
CheckUtil.checkUploadPathIsEmpty(filePath);
FileUtils.checkUploadPathIsEmpty(filePath);
return UTargetFactory.getInstance()
.generateBuilderTarget(FtpBuilderTarget.class, filePath);
}
@ -178,7 +178,7 @@ public class UploadReceiver extends AbsReceiver {
* @return 如果页数大于总页数返回null
*/
public List<UploadEntity> getTaskList(int page, int num) {
CheckUtil.checkPageParams(page, num);
FileUtils.checkPageParams(page, num);
return DbEntity.findDatas(UploadEntity.class, page, num,
"isGroupChild=? and downloadPath!=''", "false");
}
@ -199,7 +199,7 @@ public class UploadReceiver extends AbsReceiver {
* @return 如果页数大于总页数返回null
*/
public List<UploadEntity> getAllNotCompleteTask(int page, int num) {
CheckUtil.checkPageParams(page, num);
FileUtils.checkPageParams(page, num);
return DbEntity.findDatas(UploadEntity.class, page, num,
"isGroupChild=? and downloadPath!='' and isComplete=?", "false", "false");
}
@ -220,7 +220,7 @@ public class UploadReceiver extends AbsReceiver {
* @return 如果页数大于总页数返回null
*/
public List<UploadEntity> getAllCompleteTask(int page, int num) {
CheckUtil.checkPageParams(page, num);
FileUtils.checkPageParams(page, num);
return DbEntity.findDatas(UploadEntity.class,
"isGroupChild=? and downloadPath!='' and isComplete=?", "false", "true");
}

@ -34,7 +34,7 @@ import com.arialyy.aria.core.loader.ILoaderVisitor;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.exception.AriaFTPException;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil;
import com.arialyy.aria.util.FileUtils;
import com.arialyy.aria.util.CommonUtil;
import com.arialyy.aria.util.SSLContextUtil;
import java.io.IOException;
@ -140,7 +140,7 @@ public abstract class AbsFtpInfoTask<ENTITY extends AbsEntity, TASK_WRAPPER exte
private FTPClient createFtpClient() throws IOException, InterruptedException {
FTPClient client = null;
final FtpUrlEntity urlEntity = mTaskOption.getUrlEntity();
if (CheckUtil.checkIp(urlEntity.hostName)) {
if (FileUtils.checkIp(urlEntity.hostName)) {
client = newInstanceClient(urlEntity);
client.setConnectTimeout(mConnectTimeOut); // 连接10s超时
InetAddress ip = InetAddress.getByName(urlEntity.hostName);
@ -338,7 +338,7 @@ public abstract class AbsFtpInfoTask<ENTITY extends AbsEntity, TASK_WRAPPER exte
} else {
msg = String.format("%s, code: %s, msg: %s", msg, client.getReplyCode(),
client.getReplyString());
needRetry = needRetry && !CheckUtil.ftpIsBadRequest(client.getReplyCode());
needRetry = needRetry && !FileUtils.ftpIsBadRequest(client.getReplyCode());
}
callback.onFail(mEntity, new AriaFTPException(msg), needRetry);

@ -17,7 +17,7 @@ package com.arialyy.aria.http
import android.text.TextUtils
import com.arialyy.aria.http.download.HttpDTaskOption
import com.arialyy.aria.util.CheckUtil
import com.arialyy.aria.util.FileUtils
import com.arialyy.aria.util.Regular
import timber.log.Timber
import java.io.IOException
@ -83,7 +83,7 @@ internal object HttpUtil {
Timber.e("url is null")
return false
}
if (!CheckUtil.checkUrl(option.sourUrl!!)) {
if (!FileUtils.checkUrl(option.sourUrl!!)) {
Timber.e("invalid url, ${option.sourUrl}")
return false
}
@ -91,7 +91,7 @@ internal object HttpUtil {
Timber.e("save path is null")
return false
}
if (!CheckUtil.checkUri(option.savePathUri)) {
if (!FileUtils.uriEffective(option.savePathUri)) {
Timber.e("invalid uri, ${option.savePathUri}")
return false
}

@ -15,6 +15,8 @@
*/
package com.arialyy.aria.http.download
import android.os.Handler
import android.os.Looper
import com.arialyy.aria.core.DuaContext
import com.arialyy.aria.core.inf.IBlockManager
import com.arialyy.aria.core.task.BlockUtil
@ -22,7 +24,12 @@ import com.arialyy.aria.core.task.ITask
import com.arialyy.aria.core.task.ITaskInterceptor
import com.arialyy.aria.core.task.TaskChain
import com.arialyy.aria.core.task.TaskResp
import com.arialyy.aria.orm.entity.BlockRecord
import com.arialyy.aria.orm.entity.TaskRecord
import com.arialyy.aria.util.FileUri
import com.arialyy.aria.util.FileUtils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import timber.log.Timber
import java.io.File
@ -35,6 +42,7 @@ internal class HttpDBlockInterceptor : ITaskInterceptor {
private lateinit var task: ITask
private lateinit var option: HttpDTaskOption
private lateinit var blockManager: IBlockManager
private lateinit var taskRecord: TaskRecord
override suspend fun interceptor(chain: TaskChain): TaskResp {
task = chain.getTask()
@ -45,16 +53,40 @@ internal class HttpDBlockInterceptor : ITaskInterceptor {
return TaskResp(TaskResp.CODE_GET_FILE_INFO_FAIL)
}
val savePath = FileUri.getPathByUri(task.getTaskOption(HttpDTaskOption::class.java).savePathUri)
if (savePath.isNullOrEmpty()) {
Timber.e("saveUri is null")
return TaskResp(TaskResp.CODE_SAVE_URI_NULL)
}
// if task not support resume, don't save record
if (task.taskState.fileSize == 0L) {
chain.blockManager.setBlockNum(1)
// if block exist, delete the existed block
removeBlock()
return chain.proceed(chain.getTask())
}
val blockNum = checkRecord()
chain.blockManager.setBlockNum(blockNum)
val result = checkBlock()
if (result != TaskResp.CODE_SUCCESS) {
return TaskResp(result)
}
return chain.proceed(chain.getTask())
}
private fun removeBlock() {
val saveUri = task.getTaskOption(HttpDTaskOption::class.java).savePathUri
if (!FileUtils.uriEffective(saveUri)) {
return
}
val blockF = File(BlockUtil.getBlockPathFormUri(saveUri!!, 0))
if (blockF.exists()) {
blockF.delete()
}
}
/**
* check task record, if record no exist, create taskRecord
* @return blockNum
@ -74,21 +106,51 @@ internal class HttpDBlockInterceptor : ITaskInterceptor {
blockNum = blockNumInfo.first,
blockSize = task.taskState.blockSize
)
taskRecord.blockList.addAll(BlockUtil.createBlockRecord(task.taskState.fileSize))
taskRecord.blockList.addAll(
BlockUtil.createBlockRecord(
task.getTaskOption(HttpDTaskOption::class.java).savePathUri!!,
task.taskState.fileSize
)
)
recordDao.insert(taskRecord)
this.taskRecord = taskRecord
return taskRecord.blockNum
}
Timber.d("record existed")
checkBlock(recordWrapper.taskRecord)
taskRecord = recordWrapper.taskRecord
return recordWrapper.taskRecord.blockNum
}
/**ø
/**
* if block already exist, upload progress
*/
private fun checkBlock(record: TaskRecord) {
for (br in record.blockList) {
val block = File()
private suspend fun checkBlock(): Int {
val handler = Handler(Looper.myLooper()!!, blockManager.handlerCallback)
val needUpdateBlockRecord = mutableSetOf<BlockRecord>()
for (br in taskRecord.blockList) {
val blockF = File(br.blockPath)
if (blockF.exists()) {
if (br.curProgress == blockF.length() && !br.isComplete) {
br.isComplete = true
needUpdateBlockRecord.add(br)
}
if (br.curProgress != blockF.length()) {
br.curProgress = blockF.length()
needUpdateBlockRecord.add(br)
blockManager.putUnfinishedBlock(br)
}
// update task progress
handler.obtainMessage(IBlockManager.STATE_UPDATE_PROGRESS, br.curProgress)
}
}
handler.removeCallbacksAndMessages(null)
// update block record
val dao = DuaContext.getServiceManager().getDbService().getDuaDb().getRecordDao()
withContext(Dispatchers.IO) {
dao.updateBlockList(needUpdateBlockRecord.toMutableList())
}
return TaskResp.CODE_SUCCESS
}
}

@ -31,7 +31,7 @@ import com.arialyy.aria.exception.AriaHTTPException;
import com.arialyy.aria.http.ConnectionHelp;
import com.arialyy.aria.http.HttpTaskOption;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil;
import com.arialyy.aria.util.FileUtils;
import com.arialyy.aria.util.CommonUtil;
import com.arialyy.aria.util.FileUtil;
import com.arialyy.aria.util.RecordUtil;
@ -262,7 +262,7 @@ final class HttpDFileInfoTask implements IInfoTask, Runnable {
} else {
failDownload(new AriaHTTPException(
String.format("任务下载失败,errorCode:%s, errorMsg: %s, url: %s", code,
conn.getResponseMessage(), mEntity.getUrl())), !CheckUtil.httpIsBadRequest(code));
conn.getResponseMessage(), mEntity.getUrl())), !FileUtils.httpIsBadRequest(code));
}
if (end) {
doNext(code, isChunked);
@ -324,7 +324,7 @@ final class HttpDFileInfoTask implements IInfoTask, Runnable {
ALog.d(TAG, String.format("文件重命名为:%s", newName));
File oldFile = new File(mEntity.getFilePath());
String newPath = oldFile.getParent() + "/" + newName;
if (!CheckUtil.checkDPathConflicts(false, newPath, mTaskWrapper.getRequestType())) {
if (!FileUtils.checkDPathConflicts(false, newPath, mTaskWrapper.getRequestType())) {
ALog.e(TAG, "文件重命名失败");
return;
}
@ -353,7 +353,7 @@ final class HttpDFileInfoTask implements IInfoTask, Runnable {
newUrl = uri.getHost() + newUrl;
}
if (!CheckUtil.checkUrl(newUrl)) {
if (!FileUtils.checkUrl(newUrl)) {
failDownload(new AriaHTTPException("下载失败,重定向url错误"), false);
return;
}

@ -28,7 +28,7 @@ import com.arialyy.aria.core.task.TaskChain
import com.arialyy.aria.core.task.TaskResp
import com.arialyy.aria.http.HttpUtil
import com.arialyy.aria.http.request.IRequest
import com.arialyy.aria.util.CheckUtil
import com.arialyy.aria.util.FileUtils
import timber.log.Timber
import java.io.BufferedReader
import java.io.IOException
@ -169,7 +169,7 @@ internal class HttpDHeaderInterceptor : ITaskInterceptor {
val uri = Uri.parse(taskOption.sourUrl!!)
tempUrl = uri.host + newUrl
}
if (!CheckUtil.checkUrl(tempUrl)) {
if (!FileUtils.checkUrl(tempUrl)) {
Timber.e("get redirect url fail, $tempUrl")
return -1
}

@ -34,7 +34,7 @@ import com.arialyy.aria.exception.AriaM3U8Exception;
import com.arialyy.aria.http.ConnectionHelp;
import com.arialyy.aria.http.HttpTaskOption;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil;
import com.arialyy.aria.util.FileUtils;
import com.arialyy.aria.util.CommonUtil;
import com.arialyy.aria.util.FileUtil;
import com.arialyy.aria.util.Regular;
@ -327,7 +327,7 @@ final public class M3U8InfoTask implements IInfoTask {
newUrl = uri.getHost() + newUrl;
}
if (!CheckUtil.checkUrl(newUrl)) {
if (!FileUtils.checkUrl(newUrl)) {
failDownload("下载失败,重定向url错误", false);
return;
}

@ -25,7 +25,7 @@ import com.arialyy.aria.exception.AriaM3U8Exception;
import com.arialyy.aria.http.ConnectionHelp;
import com.arialyy.aria.http.HttpTaskOption;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil;
import com.arialyy.aria.util.FileUtils;
import com.arialyy.aria.util.CommonUtil;
import java.io.BufferedInputStream;
import java.io.FileOutputStream;
@ -159,7 +159,7 @@ public final class M3U8ThreadTaskAdapter extends AbsThreadTaskAdapter {
newUrl = uri.getHost() + newUrl;
}
if (!CheckUtil.checkUrl(newUrl)) {
if (!FileUtils.checkUrl(newUrl)) {
fail(new AriaM3U8Exception("下载失败,重定向url错误"), false);
return;
}

@ -18,6 +18,7 @@ package com.arialyy.aria.core.inf;
import android.os.Handler;
import android.os.Looper;
import androidx.annotation.NonNull;
import com.arialyy.aria.orm.entity.BlockRecord;
/**
* 线程任务状态
@ -41,6 +42,10 @@ public interface IBlockManager {
void setBlockNum(int blockNum);
void putUnfinishedBlock(BlockRecord record);
BlockRecord getUnfinishedBlock();
/**
* 是否有失败的快
*

@ -1,32 +0,0 @@
/*
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.arialyy.aria.core.task
import com.arialyy.aria.orm.entity.BlockRecord
class BlockState(val blockState: BlockRecord, val blockPath: String) {
companion object {
/**
* dir/.fileName.blockId
*/
const val BLOCK_PATH = "%s/.%s.%d"
const val BLOCK_SIZE = 1024 * 1024 * 5L
}
var curProgress: Long = 0
}

@ -1,9 +1,11 @@
package com.arialyy.aria.core.task
import android.bluetooth.BluetoothClass
import android.net.Uri
import com.arialyy.aria.orm.entity.BlockRecord
import com.arialyy.aria.orm.entity.TaskRecord
import com.arialyy.aria.util.FileUri
import com.arialyy.aria.util.FileUtil
import com.arialyy.aria.util.FileUtils
import timber.log.Timber
import java.io.File
@ -24,22 +26,35 @@ import java.io.File
*/
object BlockUtil {
fun getBlockPathFormUri(fileSaveUri: Uri, blockId: Int): String {
val filePath = FileUri.getPathByUri(fileSaveUri) ?: "/"
val fileName = FileUtils.getFileNameFromPath(filePath)
val dirPath = FileUtils.getFilePathFromFullPath(filePath)
return BlockRecord.BLOCK_PATH.format(dirPath, fileName, blockId)
}
/**
* create block record
*/
fun createBlockRecord(fileSize: Long): List<BlockRecord> {
fun createBlockRecord(fileSaveUri: Uri, fileSize: Long): List<BlockRecord> {
val filePath = FileUri.getPathByUri(fileSaveUri) ?: "/"
val fileName = FileUtils.getFileNameFromPath(filePath)
val dirPath = FileUtils.getFilePathFromFullPath(filePath)
val blockNumInfo = getBlockNum(fileSize)
val lastIndex = blockNumInfo.first - 1
val brList = mutableListOf<BlockRecord>()
for (bi in 0 until blockNumInfo.first) {
val sl = bi * BlockState.BLOCK_SIZE
val blockSize = if (bi == lastIndex) blockNumInfo.second else BlockState.BLOCK_SIZE
val sl = bi * BlockRecord.BLOCK_SIZE
val blockSize = if (bi == lastIndex) blockNumInfo.second else BlockRecord.BLOCK_SIZE
val el = sl + blockSize
val blockRecord = BlockRecord(
bId = bi,
startLocation = bi * BlockState.BLOCK_SIZE,
startLocation = bi * BlockRecord.BLOCK_SIZE,
endLocation = el,
blockSize = blockSize,
blockPath = BlockRecord.BLOCK_PATH.format(dirPath, fileName, bi)
)
brList.add(blockRecord)
}
@ -51,11 +66,11 @@ object BlockUtil {
* @return pair<blockNum, lastBlockSize>
*/
fun getBlockNum(fileLen: Long): Pair<Int, Long> {
if (fileLen <= BlockState.BLOCK_SIZE) {
if (fileLen <= BlockRecord.BLOCK_SIZE) {
return Pair(1, 0)
}
val blockNum = (fileLen / BlockState.BLOCK_SIZE).toInt()
val lastBlockSize = fileLen % BlockState.BLOCK_SIZE
val blockNum = (fileLen / BlockRecord.BLOCK_SIZE).toInt()
val lastBlockSize = fileLen % BlockRecord.BLOCK_SIZE
return Pair(if (lastBlockSize != 0L) blockNum + 1 else blockNum, lastBlockSize)
}
@ -68,16 +83,16 @@ object BlockUtil {
val fileName = targetF.name
if (record.blockNum == 1) {
// if this task not support blocks or fileSize < 5m, just need rename
return File(BlockState.BLOCK_PATH.format(dir, fileName, 0)).renameTo(targetF)
return File(BlockRecord.BLOCK_PATH.format(dir, fileName, 0)).renameTo(targetF)
}
val blockList = mutableListOf<File>()
for (i in 0 until record.blockNum) {
val subF = File(BlockState.BLOCK_PATH.format(dir, fileName, i))
val subF = File(BlockRecord.BLOCK_PATH.format(dir, fileName, i))
if (!subF.exists()) {
Timber.e("this block: $i not exists")
return false
}
if (subF.length() != BlockState.BLOCK_SIZE.toLong()) {
if (subF.length() != BlockRecord.BLOCK_SIZE.toLong()) {
Timber.e("this block: $i size abnormal, size: ${subF.length()}")
return false
}
@ -85,5 +100,4 @@ object BlockUtil {
}
return FileUtil.mergeFile(record.filePath, blockList)
}
}

@ -20,11 +20,13 @@ import android.os.Looper
import com.arialyy.aria.core.inf.IBlockManager
import com.arialyy.aria.core.listener.IEventListener
import com.arialyy.aria.exception.AriaException
import com.arialyy.aria.orm.entity.BlockRecord
import timber.log.Timber
import java.util.concurrent.LinkedBlockingDeque
import java.util.concurrent.atomic.AtomicInteger
class BlockManager(private val eventListener: IEventListener) : IBlockManager {
private val blockList = mutableListOf<BlockState>()
private val unfinishedBlockQueue = LinkedBlockingDeque<BlockRecord>()
private val canceledNum = AtomicInteger(0) // 已经取消的线程的数
private val stoppedNum = AtomicInteger(0) // 已经停止的线程数
private val failedNum = AtomicInteger(0) // 失败的线程数
@ -88,12 +90,12 @@ class BlockManager(private val eventListener: IEventListener) : IBlockManager {
looper.quit()
}
fun addBlockState(state: BlockState) {
blockList.add(state)
override fun putUnfinishedBlock(record: BlockRecord) {
unfinishedBlockQueue.offer(record)
}
fun getBlockState(): BlockState {
return blockList.removeFirst()
override fun getUnfinishedBlock(): BlockRecord {
return unfinishedBlockQueue.remove()
}
override fun setLopper(looper: Looper) {
@ -138,5 +140,4 @@ class BlockManager(private val eventListener: IEventListener) : IBlockManager {
override fun getHandlerCallback(): Callback {
return callback
}
}

@ -7,9 +7,10 @@ package com.arialyy.aria.core.task
**/
class TaskResp(val code: Int = CODE_DEF) {
companion object {
const val CODE_COMPLETE = 1
const val CODE_SUCCESS = 1
const val CODE_INTERRUPT = 999
const val CODE_DEF = 0
const val CODE_SAVE_URI_NULL = 3
const val CODE_GET_FILE_INFO_FAIL = 2
}

@ -53,6 +53,10 @@ interface RecordDao {
@Update
suspend fun update(record: TaskRecord)
@Transaction
@Update
suspend fun updateBlockList(blockList: List<BlockRecord>)
@Delete
suspend fun deleteTaskRecord(record: TaskRecord)

@ -18,7 +18,7 @@ package com.arialyy.aria.orm.entity
import androidx.room.Entity
import androidx.room.ForeignKey
import androidx.room.ForeignKey.Companion.CASCADE
import androidx.room.PrimaryKey
import androidx.room.Ignore
/**
* @Author laoyuyu
@ -49,5 +49,22 @@ data class BlockRecord(
val blockSize: Long = 0,
val isComplete: Boolean = false
)
/**
* block path
*/
val blockPath: String,
var isComplete: Boolean = false
) {
companion object {
/**
* dir/.fileName.blockId
*/
const val BLOCK_PATH = "%s/.%s.%d"
const val BLOCK_SIZE = 1024 * 1024 * 5L
}
@Ignore
var curProgress = 0L
}

@ -1,83 +0,0 @@
/*
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.arialyy.aria.util
import android.database.Cursor
import android.net.Uri
import com.arialyy.aria.core.DuaContext
import timber.log.Timber
import java.io.InputStream
object CheckUtil {
val HTTP_REGEX =
Regex(
"(https?)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]",
RegexOption.IGNORE_CASE
)
/**
* check if url is correct
*/
fun checkUrl(url: String) = HTTP_REGEX.matches(url)
/**
* 1. Check if Uri is correct
* 2. Whether the file corresponding to Uri exists (may be deleted, or the system db has Uri related records, but the file is invalid or damaged)
*
* https://stackoverflow.com/questions/7645951/how-to-check-if-resource-pointed-by-uri-is-available
*/
fun checkUri(uri: Uri?): Boolean {
if (uri == null) return false
val resolver = DuaContext.context.contentResolver
//1. Check Uri
var cursor: Cursor? = null
val isUriExist: Boolean = try {
cursor = resolver.query(uri, null, null, null, null)
//cursor null: content Uri was invalid or some other error occurred
//cursor.moveToFirst() false: Uri was ok but no entry found.
(cursor != null && cursor.moveToFirst())
} catch (t: Throwable) {
Timber.e("1.Check Uri Error: ${t.message}")
false
} finally {
try {
cursor?.close()
} catch (t: Throwable) {
}
}
//2. Check File Exist
//如果系统 db 存有 Uri 相关记录, 但是文件失效或者损坏 (If the system db has Uri related records, but the file is invalid or damaged)
var ins: InputStream? = null
val isFileExist: Boolean = try {
ins = resolver.openInputStream(uri)
// file exists
true
} catch (t: Throwable) {
// File was not found eg: open failed: ENOENT (No such file or directory)
Timber.e("2. Check File Exist Error: ${t.message}")
false
} finally {
try {
ins?.close()
} catch (t: Throwable) {
}
}
return isUriExist && isFileExist
}
}

@ -0,0 +1,70 @@
/*
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.arialyy.aria.util
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import com.arialyy.aria.core.DuaContext
import timber.log.Timber
internal const val AUTHORITY = ".andoFileProvider"
/**
* @return 传入的Uri是否已具备访问权限 (Whether the incoming Uri has access permission)
*/
fun giveUriPermission(uri: Uri?): Boolean {
return uri?.run {
when (DuaContext.context.checkUriPermission(
this,
android.os.Process.myPid(),
android.os.Process.myUid(),
Intent.FLAG_GRANT_READ_URI_PERMISSION
)) {
PackageManager.PERMISSION_GRANTED -> true
PackageManager.PERMISSION_DENIED -> {
DuaContext.context.grantUriPermission(
DuaContext.context.packageName, this, Intent.FLAG_GRANT_READ_URI_PERMISSION
)
false
}
else -> false
}
} ?: false
}
fun revokeUriPermission(uri: Uri?) {
DuaContext.context.revokeUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION)
}
inline fun <R> Uri.use(block: Uri.() -> R): R {
var isAlreadyHavePermission = false
try {
isAlreadyHavePermission = giveUriPermission(this)
return block()
} catch (t: Throwable) {
Timber.e("giveUriPermission Error ${t.message}")
} finally {
if (!isAlreadyHavePermission) {
try {
revokeUriPermission(this)
} catch (t: Throwable) {
Timber.e("revokeUriPermission Error ${t.message}")
}
}
}
return block()
}

@ -56,6 +56,7 @@ import timber.log.Timber;
/**
* 文件操作工具类
*/
@Deprecated
public class FileUtil {
private static final String TAG = "FileUtil";
private static final Pattern DIR_SEPORATOR = Pattern.compile("/");

@ -0,0 +1,183 @@
/*
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.arialyy.aria.util
import android.content.ContentResolver
import android.database.Cursor
import android.net.Uri
import android.provider.OpenableColumns
import com.arialyy.aria.core.DuaContext
import timber.log.Timber
import java.io.InputStream
import java.util.Locale
object FileUtils {
val HTTP_REGEX =
Regex(
"(https?)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]",
RegexOption.IGNORE_CASE
)
/**
* check if url is correct
*/
fun checkUrl(url: String) = HTTP_REGEX.matches(url)
/**
* https://github.com/javakam/FileOperator/blob/master/library_core/src/main/java/ando/file/core/FileUtils.kt
*
* 1. Check if Uri is correct
* 2. Whether the file corresponding to Uri exists (may be deleted, or the system db has Uri related records, but the file is invalid or damaged)
*
* https://stackoverflow.com/questions/7645951/how-to-check-if-resource-pointed-by-uri-is-available
*/
fun uriEffective(uri: Uri?): Boolean {
if (uri == null) return false
val resolver = DuaContext.context.contentResolver
//1. Check Uri
var cursor: Cursor? = null
val isUriExist: Boolean = try {
cursor = resolver.query(uri, null, null, null, null)
//cursor null: content Uri was invalid or some other error occurred
//cursor.moveToFirst() false: Uri was ok but no entry found.
(cursor != null && cursor.moveToFirst())
} catch (t: Throwable) {
Timber.e("1.Check Uri Error: ${t.message}")
false
} finally {
try {
cursor?.close()
} catch (t: Throwable) {
}
}
//2. Check File Exist
//如果系统 db 存有 Uri 相关记录, 但是文件失效或者损坏 (If the system db has Uri related records, but the file is invalid or damaged)
return isUriExist && checkFileExistByUri(uri, resolver)
}
/**
* check file exist
* @return true exist
*/
fun checkFileExistByUri(uri: Uri, resolver: ContentResolver): Boolean {
var ins: InputStream? = null
val isFileExist: Boolean = try {
ins = resolver.openInputStream(uri)
// file exists
true
} catch (t: Throwable) {
// File was not found eg: open failed: ENOENT (No such file or directory)
Timber.e("2. Check File Exist Error: ${t.message}")
false
} finally {
try {
ins?.close()
} catch (t: Throwable) {
}
}
return isFileExist
}
/**
* ### 路径分割
*
* ```
* eg:
* srcPath=/storage/emulated/0/Movies/myVideo.mp4 path=/storage/emulated/0/Movies name=myVideo suffix=mp4 nameSuffix=myVideo.mp4
*
* /xxx/xxx/note.txt -> path: /xxx/xxx name: note suffix: txt
* ///note.txt -> path: /// name: note suffix: txt
* /note.txt -> path: "" name: note suffix: txt
* note.txt -> path: "" name: note suffix: txt
* ```
*/
fun splitFilePath(
srcPath: String?,
nameSplit: Char = '/',
suffixSplit: Char = '.',
block: ((path: String, name: String, suffix: String, nameSuffix: String) -> Unit)? = null,
) {
if (srcPath.isNullOrBlank()) return
val cut = srcPath.lastIndexOf(nameSplit)
// /xxx/xxx/note.txt +0: /xxx/xxx +1: /xxx/xxx/
val path = if (cut == -1) "" else srcPath.substring(0, cut)
val nameSuffix = if (cut == -1) srcPath else srcPath.substring(cut + 1)
val dot = nameSuffix.lastIndexOf(suffixSplit)
if (dot != -1) {
val suffix = nameSuffix.substring((dot + 1)).lowercase(Locale.getDefault())
val name = nameSuffix.substring(0, dot)
Timber.d("splitFilePath srcPath=$srcPath path=$path name=$name suffix=$suffix nameSuffix=$nameSuffix")
block?.invoke(path, name, suffix, nameSuffix)
}
}
/**
* abc.jpg -> jpg
*/
fun getFileNameSuffix(path: String): String {
var nameSuffix = path
splitFilePath(srcPath = path) { _: String, _: String, suffix: String, _: String ->
nameSuffix = suffix
}
return nameSuffix
}
/**
* /storage/emulated/0/Movies/myVideo.mp4 -> /storage/emulated/0/Movies
*/
fun getFilePathFromFullPath(path: String?, split: Char = '/'): String? {
if (path.isNullOrBlank()) return null
val cut = path.lastIndexOf(split)
// (cut+1): /storage/emulated/0/Movies/
if (cut != -1) return path.substring(0, cut)
return path
}
/**
* /storage/emulated/0/Movies/myVideo.mp4 -> myVideo.mp4
*/
fun getFileNameFromPath(path: String?, split: Char = '/'): String? {
if (path.isNullOrBlank()) return null
val cut = path.lastIndexOf(split)
if (cut != -1) return path.substring(cut + 1)
return path
}
/**
* /storage/emulated/0/Movies/myVideo.mp4 -> myVideo.mp4
*/
fun getFileNameFromUri(uri: Uri?): String? =
uri?.use {
var filename: String? = null
val resolver = DuaContext.context.contentResolver
val mimeType = resolver.getType(uri)
if (mimeType == null) {
filename = getFileNameFromPath(FileUri.getPathByUri(uri))
} else {
resolver.query(uri, null, null, null, null)?.use { c: Cursor ->
val nameIndex = c.getColumnIndex(OpenableColumns.DISPLAY_NAME)
if (c.moveToFirst()) filename = c.getString(nameIndex)
}
}
filename
}
}
Loading…
Cancel
Save