diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/CheckDEntityUtil.java b/Aria/src/main/java/com/arialyy/aria/core/download/CheckDEntityUtil.java index 7bc96639..141d4f31 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/CheckDEntityUtil.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/CheckDEntityUtil.java @@ -64,7 +64,8 @@ public class CheckDEntityUtil implements ICheckEntityUtil { private void handleM3U8() { File file = new File(mWrapper.getTempFilePath()); - int bandWidth = (int) mWrapper.getM3U8Params().getParam(IOptionConstant.bandWidth); + Object bw = mWrapper.getM3U8Params().getParam(IOptionConstant.bandWidth); + int bandWidth = bw == null ? 0 : (int) bw; // 缓存文件夹格式:问文件夹/.文件名_码率 String cacheDir = String.format("%s/.%s_%s", file.getParent(), file.getName(), bandWidth); @@ -153,8 +154,8 @@ public class CheckDEntityUtil implements ICheckEntityUtil { mEntity.setFileName(newFile.getName()); // 如过使用Content-Disposition中的文件名,将不会执行重命名工作 - if ((boolean) mWrapper.getOptionParams().getParam(IOptionConstant.useServerFileName) - || mWrapper.getRequestType() == ITaskWrapper.M3U8_LIVE) { + Object usf = mWrapper.getOptionParams().getParam(IOptionConstant.useServerFileName); + if ((usf != null && (boolean) usf) || mWrapper.getRequestType() == ITaskWrapper.M3U8_LIVE) { return true; } if (!TextUtils.isEmpty(mEntity.getFilePath())) { diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/CheckDGEntityUtil.java b/Aria/src/main/java/com/arialyy/aria/core/download/CheckDGEntityUtil.java index 8a1b222a..3fd4f450 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/CheckDGEntityUtil.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/CheckDGEntityUtil.java @@ -134,8 +134,7 @@ public class CheckDGEntityUtil implements ICheckEntityUtil { return false; } - if (mWrapper.getOptionParams().getParam(IOptionConstant.requestEnum) - == RequestEnum.POST) { + if (mWrapper.getOptionParams().getParam(IOptionConstant.requestEnum) == RequestEnum.POST) { for (DTaskWrapper subWrapper : mWrapper.getSubTaskWrapper()) { subWrapper.getOptionParams().setParams(IOptionConstant.requestEnum, RequestEnum.POST); } diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/m3u8/M3U8Delegate.java b/Aria/src/main/java/com/arialyy/aria/core/download/m3u8/M3U8Delegate.java index f498d3cb..348cc805 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/m3u8/M3U8Delegate.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/m3u8/M3U8Delegate.java @@ -67,7 +67,7 @@ public class M3U8Delegate extends BaseDelegate */ @CheckResult(suggest = Suggest.TO_CONTROLLER) public M3U8Delegate setMergeHandler(ITsMergeHandler handler) { - mTaskWrapper.getM3U8Params().setParams(IOptionConstant.mergeHandler, handler); + mTaskWrapper.getM3U8Params().setObjs(IOptionConstant.mergeHandler, handler); return this; } @@ -79,7 +79,7 @@ public class M3U8Delegate extends BaseDelegate */ @CheckResult(suggest = Suggest.TO_CONTROLLER) public M3U8Delegate setTsUrlConvert(IVodTsUrlConverter converter) { - mTaskWrapper.getM3U8Params().setParams(IOptionConstant.vodUrlConverter, converter); + mTaskWrapper.getM3U8Params().setObjs(IOptionConstant.vodUrlConverter, converter); return this; } @@ -102,7 +102,7 @@ public class M3U8Delegate extends BaseDelegate */ @CheckResult(suggest = Suggest.TO_CONTROLLER) public M3U8Delegate setBandWidthUrlConverter(IBandWidthUrlConverter converter) { - mTaskWrapper.getM3U8Params().setParams(IOptionConstant.bandWidthUrlConverter, converter); + mTaskWrapper.getM3U8Params().setObjs(IOptionConstant.bandWidthUrlConverter, converter); return this; } diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/m3u8/M3U8LiveDelegate.java b/Aria/src/main/java/com/arialyy/aria/core/download/m3u8/M3U8LiveDelegate.java index 353ce357..70acc618 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/m3u8/M3U8LiveDelegate.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/m3u8/M3U8LiveDelegate.java @@ -44,7 +44,7 @@ public class M3U8LiveDelegate extends BaseDelegate setLiveTsUrlConvert(ILiveTsUrlConverter converter) { ((DTaskWrapper) getTaskWrapper()).getM3U8Params() - .setParams(IOptionConstant.liveTsUrlConverter, converter); + .setObjs(IOptionConstant.liveTsUrlConverter, converter); return this; } diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/target/HttpBuilderTarget.java b/Aria/src/main/java/com/arialyy/aria/core/download/target/HttpBuilderTarget.java index 90112482..556244b1 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/target/HttpBuilderTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/target/HttpBuilderTarget.java @@ -96,7 +96,7 @@ public class HttpBuilderTarget extends AbsBuilderTarget { throw new IllegalArgumentException("adapter为空"); } - getTaskWrapper().getOptionParams().setParams(IOptionConstant.fileLenAdapter, adapter); + getTaskWrapper().getOptionParams().setObjs(IOptionConstant.fileLenAdapter, adapter); return this; } } diff --git a/FtpComponent/src/main/java/com/arialyy/aria/ftp/download/FtpDThreadTaskAdapter.java b/FtpComponent/src/main/java/com/arialyy/aria/ftp/download/FtpDThreadTaskAdapter.java index 544ece5d..976d12e4 100644 --- a/FtpComponent/src/main/java/com/arialyy/aria/ftp/download/FtpDThreadTaskAdapter.java +++ b/FtpComponent/src/main/java/com/arialyy/aria/ftp/download/FtpDThreadTaskAdapter.java @@ -83,16 +83,16 @@ final class FtpDThreadTaskAdapter extends BaseFtpThreadTaskAdapter { return; } - if (getConfig().isOpenDynamicFile) { + if (getThreadConfig().isOpenDynamicFile) { readDynamicFile(is); } else { readNormal(is); handleComplete(); } } catch (IOException e) { - fail(new AriaIOException(TAG, String.format("下载失败【%s】", getConfig().url), e), true); + fail(new AriaIOException(TAG, String.format("下载失败【%s】", getThreadConfig().url), e), true); } catch (Exception e) { - fail(new AriaIOException(TAG, String.format("下载失败【%s】", getConfig().url), e), false); + fail(new AriaIOException(TAG, String.format("下载失败【%s】", getThreadConfig().url), e), false); } finally { try { if (is != null) { @@ -127,7 +127,7 @@ final class FtpDThreadTaskAdapter extends BaseFtpThreadTaskAdapter { ReadableByteChannel fic = null; try { int len; - fos = new FileOutputStream(getConfig().tempFile, true); + fos = new FileOutputStream(getThreadConfig().tempFile, true); foc = fos.getChannel(); fic = Channels.newChannel(is); ByteBuffer bf = ByteBuffer.allocate(getTaskConfig().getBuffSize()); @@ -154,7 +154,7 @@ final class FtpDThreadTaskAdapter extends BaseFtpThreadTaskAdapter { } handleComplete(); } catch (IOException e) { - fail(new AriaIOException(TAG, String.format("下载失败【%s】", getConfig().url), e), true); + fail(new AriaIOException(TAG, String.format("下载失败【%s】", getThreadConfig().url), e), true); } finally { try { if (fos != null) { @@ -179,7 +179,7 @@ final class FtpDThreadTaskAdapter extends BaseFtpThreadTaskAdapter { BufferedRandomAccessFile file = null; try { file = - new BufferedRandomAccessFile(getConfig().tempFile, "rwd", getTaskConfig().getBuffSize()); + new BufferedRandomAccessFile(getThreadConfig().tempFile, "rwd", getTaskConfig().getBuffSize()); file.seek(getThreadRecord().startLocation); byte[] buffer = new byte[getTaskConfig().getBuffSize()]; int len; @@ -201,7 +201,7 @@ final class FtpDThreadTaskAdapter extends BaseFtpThreadTaskAdapter { } } } catch (IOException e) { - fail(new AriaIOException(TAG, String.format("下载失败【%s】", getConfig().url), e), true); + fail(new AriaIOException(TAG, String.format("下载失败【%s】", getThreadConfig().url), e), true); } finally { try { if (file != null) { diff --git a/FtpComponent/src/main/java/com/arialyy/aria/ftp/upload/FtpUThreadTaskAdapter.java b/FtpComponent/src/main/java/com/arialyy/aria/ftp/upload/FtpUThreadTaskAdapter.java index c988d83b..1f1a7ce0 100644 --- a/FtpComponent/src/main/java/com/arialyy/aria/ftp/upload/FtpUThreadTaskAdapter.java +++ b/FtpComponent/src/main/java/com/arialyy/aria/ftp/upload/FtpUThreadTaskAdapter.java @@ -66,9 +66,9 @@ class FtpUThreadTaskAdapter extends BaseFtpThreadTaskAdapter { } file = - new BufferedRandomAccessFile(getConfig().tempFile, "rwd", getTaskConfig().getBuffSize()); + new BufferedRandomAccessFile(getThreadConfig().tempFile, "rwd", getTaskConfig().getBuffSize()); if (getThreadRecord().startLocation != 0) { - //file.skipBytes((int) getConfig().START_LOCATION); + //file.skipBytes((int) getThreadConfig().START_LOCATION); file.seek(getThreadRecord().startLocation); } boolean complete = upload(client, file); @@ -81,7 +81,7 @@ class FtpUThreadTaskAdapter extends BaseFtpThreadTaskAdapter { } catch (IOException e) { fail(new AriaIOException(TAG, String.format("上传失败,filePath: %s, uploadUrl: %s", getEntity().getFilePath(), - getConfig().url)), true); + getThreadConfig().url)), true); } catch (Exception e) { fail(new AriaIOException(TAG, null, e), false); } finally { diff --git a/HttpComponent/src/main/java/com/arialyy/aria/http/download/DGroupLoaderUtil.java b/HttpComponent/src/main/java/com/arialyy/aria/http/download/DGroupLoaderUtil.java index 65229f10..b34fb470 100644 --- a/HttpComponent/src/main/java/com/arialyy/aria/http/download/DGroupLoaderUtil.java +++ b/HttpComponent/src/main/java/com/arialyy/aria/http/download/DGroupLoaderUtil.java @@ -22,6 +22,8 @@ import com.arialyy.aria.core.download.DTaskWrapper; import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.inf.IEntity; import com.arialyy.aria.core.inf.OnFileInfoCallback; +import com.arialyy.aria.core.listener.IEventListener; +import com.arialyy.aria.core.wrapper.AbsTaskWrapper; import com.arialyy.aria.exception.AriaIOException; import com.arialyy.aria.exception.BaseException; import com.arialyy.aria.core.group.AbsGroupUtil; @@ -46,8 +48,8 @@ public class DGroupLoaderUtil extends AbsGroupUtil { private boolean getLenComplete = false; private List mTempWrapper = new ArrayList<>(); - public DGroupLoaderUtil(IDGroupListener listener, DGTaskWrapper taskWrapper) { - super(listener, taskWrapper); + public DGroupLoaderUtil(AbsTaskWrapper taskWrapper, IEventListener listener) { + super(taskWrapper, listener); taskWrapper.generateTaskOption(HttpTaskOption.class); } diff --git a/HttpComponent/src/main/java/com/arialyy/aria/http/download/HttpDThreadTaskAdapter.java b/HttpComponent/src/main/java/com/arialyy/aria/http/download/HttpDThreadTaskAdapter.java index 69b63cb2..bab8b614 100644 --- a/HttpComponent/src/main/java/com/arialyy/aria/http/download/HttpDThreadTaskAdapter.java +++ b/HttpComponent/src/main/java/com/arialyy/aria/http/download/HttpDThreadTaskAdapter.java @@ -61,7 +61,7 @@ final class HttpDThreadTaskAdapter extends BaseHttpThreadTaskAdapter { BufferedInputStream is = null; BufferedRandomAccessFile file = null; try { - URL url = ConnectionHelp.handleUrl(getConfig().url, mTaskOption); + URL url = ConnectionHelp.handleUrl(getThreadConfig().url, mTaskOption); conn = ConnectionHelp.handleConnection(url, mTaskOption); if (mTaskWrapper.isSupportBP()) { ALog.d(TAG, @@ -103,12 +103,12 @@ final class HttpDThreadTaskAdapter extends BaseHttpThreadTaskAdapter { is = new BufferedInputStream(ConnectionHelp.convertInputStream(conn)); if (mTaskOption.isChunked()) { readChunked(is); - } else if (getConfig().isOpenDynamicFile) { + } else if (getThreadConfig().isOpenDynamicFile) { readDynamicFile(is); } else { //创建可设置位置的文件 file = - new BufferedRandomAccessFile(getConfig().tempFile, "rwd", + new BufferedRandomAccessFile(getThreadConfig().tempFile, "rwd", getTaskConfig().getBuffSize()); //设置每条线程写入文件的位置 file.seek(getThreadRecord().startLocation); @@ -150,7 +150,7 @@ final class HttpDThreadTaskAdapter extends BaseHttpThreadTaskAdapter { private void readChunked(InputStream is) { FileOutputStream fos = null; try { - fos = new FileOutputStream(getConfig().tempFile, true); + fos = new FileOutputStream(getThreadConfig().tempFile, true); byte[] buffer = new byte[getTaskConfig().getBuffSize()]; int len; while (getThreadTask().isLive() && (len = is.read(buffer)) != -1) { @@ -167,7 +167,7 @@ final class HttpDThreadTaskAdapter extends BaseHttpThreadTaskAdapter { } catch (IOException e) { fail(new AriaIOException(TAG, String.format("文件下载失败,savePath: %s, url: %s", getEntity().getFilePath(), - getConfig().url)), true); + getThreadConfig().url)), true); } finally { if (fos != null) { try { @@ -188,7 +188,7 @@ final class HttpDThreadTaskAdapter extends BaseHttpThreadTaskAdapter { ReadableByteChannel fic = null; try { int len; - fos = new FileOutputStream(getConfig().tempFile, true); + fos = new FileOutputStream(getThreadConfig().tempFile, true); foc = fos.getChannel(); fic = Channels.newChannel(is); ByteBuffer bf = ByteBuffer.allocate(getTaskConfig().getBuffSize()); @@ -219,7 +219,7 @@ final class HttpDThreadTaskAdapter extends BaseHttpThreadTaskAdapter { } catch (IOException e) { fail(new AriaIOException(TAG, String.format("文件下载失败,savePath: %s, url: %s", getEntity().getFilePath(), - getConfig().url), e), true); + getThreadConfig().url), e), true); } finally { try { if (fos != null) { diff --git a/HttpComponent/src/main/java/com/arialyy/aria/http/upload/HttpUThreadTaskAdapter.java b/HttpComponent/src/main/java/com/arialyy/aria/http/upload/HttpUThreadTaskAdapter.java index 67e3b21d..3b20ba79 100644 --- a/HttpComponent/src/main/java/com/arialyy/aria/http/upload/HttpUThreadTaskAdapter.java +++ b/HttpComponent/src/main/java/com/arialyy/aria/http/upload/HttpUThreadTaskAdapter.java @@ -62,7 +62,7 @@ final class HttpUThreadTaskAdapter extends BaseHttpThreadTaskAdapter { } URL url; try { - url = new URL(CommonUtil.convertUrl(getConfig().url)); + url = new URL(CommonUtil.convertUrl(getThreadConfig().url)); mHttpConn = (HttpURLConnection) url.openConnection(); mHttpConn.setRequestMethod(mTaskOption.getRequestEnum().name); diff --git a/M3U8Component/src/main/java/com/arialyy/aria/m3u8/M3U8Listener.java b/M3U8Component/src/main/java/com/arialyy/aria/m3u8/M3U8Listener.java index c2b97fcb..61cc43ed 100644 --- a/M3U8Component/src/main/java/com/arialyy/aria/m3u8/M3U8Listener.java +++ b/M3U8Component/src/main/java/com/arialyy/aria/m3u8/M3U8Listener.java @@ -24,7 +24,6 @@ import com.arialyy.aria.core.listener.BaseDListener; import com.arialyy.aria.core.listener.IDLoadListener; import com.arialyy.aria.core.listener.ISchedulers; import com.arialyy.aria.core.task.AbsTask; -import com.arialyy.aria.core.task.DownloadTask; import com.arialyy.aria.util.CommonUtil; /** @@ -32,7 +31,7 @@ import com.arialyy.aria.util.CommonUtil; */ public class M3U8Listener extends BaseDListener implements IDLoadListener { - M3U8Listener(AbsTask task, Handler outHandler) { + public M3U8Listener(AbsTask task, Handler outHandler) { super(task, outHandler); } diff --git a/M3U8Component/src/main/java/com/arialyy/aria/m3u8/M3U8TaskOption.java b/M3U8Component/src/main/java/com/arialyy/aria/m3u8/M3U8TaskOption.java index bad1cbfc..ba680258 100644 --- a/M3U8Component/src/main/java/com/arialyy/aria/m3u8/M3U8TaskOption.java +++ b/M3U8Component/src/main/java/com/arialyy/aria/m3u8/M3U8TaskOption.java @@ -15,10 +15,10 @@ */ package com.arialyy.aria.m3u8; -import com.arialyy.aria.core.processor.IBandWidthUrlConverter; import com.arialyy.aria.core.inf.ITaskOption; -import com.arialyy.aria.core.processor.ITsMergeHandler; +import com.arialyy.aria.core.processor.IBandWidthUrlConverter; import com.arialyy.aria.core.processor.ILiveTsUrlConverter; +import com.arialyy.aria.core.processor.ITsMergeHandler; import com.arialyy.aria.core.processor.IVodTsUrlConverter; import java.lang.ref.SoftReference; import java.util.List; @@ -101,7 +101,7 @@ public class M3U8TaskOption implements ITaskOption { /** * 生成索引占位字段 */ - private boolean generateIndexFileTemp; + private boolean generateIndexFileTemp = false; public boolean isGenerateIndexFileTemp() { return generateIndexFileTemp; diff --git a/M3U8Component/src/main/java/com/arialyy/aria/m3u8/M3U8ThreadTaskAdapter.java b/M3U8Component/src/main/java/com/arialyy/aria/m3u8/M3U8ThreadTaskAdapter.java index b4c2e4c6..dee64820 100644 --- a/M3U8Component/src/main/java/com/arialyy/aria/m3u8/M3U8ThreadTaskAdapter.java +++ b/M3U8Component/src/main/java/com/arialyy/aria/m3u8/M3U8ThreadTaskAdapter.java @@ -60,7 +60,7 @@ public class M3U8ThreadTaskAdapter extends AbsThreadTaskAdapter { HttpURLConnection conn = null; BufferedInputStream is = null; try { - URL url = ConnectionHelp.handleUrl(getConfig().url, mHttpTaskOption); + URL url = ConnectionHelp.handleUrl(getThreadConfig().url, mHttpTaskOption); conn = ConnectionHelp.handleConnection(url, mHttpTaskOption); ALog.d(TAG, String.format("分片【%s】开始下载", getThreadRecord().threadId)); ConnectionHelp.setConnectParam(mHttpTaskOption, conn); @@ -92,21 +92,21 @@ public class M3U8ThreadTaskAdapter extends AbsThreadTaskAdapter { is = new BufferedInputStream(ConnectionHelp.convertInputStream(conn)); if (mHttpTaskOption.isChunked()) { readChunked(is); - } else if (getConfig().isOpenDynamicFile) { + } else if (getThreadConfig().isOpenDynamicFile) { readDynamicFile(is); } } catch (MalformedURLException e) { fail(new TaskException(TAG, String.format("分片【%s】下载失败,filePath: %s, url: %s", getThreadRecord().threadId, - getConfig().tempFile.getPath(), getEntity().getUrl()), e), false); + getThreadConfig().tempFile.getPath(), getEntity().getUrl()), e), false); } catch (IOException e) { fail(new TaskException(TAG, String.format("分片【%s】下载失败,filePath: %s, url: %s", getThreadRecord().threadId, - getConfig().tempFile.getPath(), getEntity().getUrl()), e), true); + getThreadConfig().tempFile.getPath(), getEntity().getUrl()), e), true); } catch (Exception e) { fail(new TaskException(TAG, String.format("分片【%s】下载失败,filePath: %s, url: %s", getThreadRecord().threadId, - getConfig().tempFile.getPath(), getEntity().getUrl()), e), false); + getThreadConfig().tempFile.getPath(), getEntity().getUrl()), e), false); } finally { try { if (is != null) { @@ -127,7 +127,7 @@ public class M3U8ThreadTaskAdapter extends AbsThreadTaskAdapter { private void readChunked(InputStream is) { FileOutputStream fos = null; try { - fos = new FileOutputStream(getConfig().tempFile, true); + fos = new FileOutputStream(getThreadConfig().tempFile, true); byte[] buffer = new byte[getTaskConfig().getBuffSize()]; int len; while (getThreadTask().isLive() && (len = is.read(buffer)) != -1) { @@ -143,8 +143,8 @@ public class M3U8ThreadTaskAdapter extends AbsThreadTaskAdapter { handleComplete(); } catch (IOException e) { fail(new AriaIOException(TAG, - String.format("文件下载失败,savePath: %s, url: %s", getConfig().tempFile.getPath(), - getConfig().url), e), true); + String.format("文件下载失败,savePath: %s, url: %s", getThreadConfig().tempFile.getPath(), + getThreadConfig().url), e), true); } finally { if (fos != null) { try { @@ -165,7 +165,7 @@ public class M3U8ThreadTaskAdapter extends AbsThreadTaskAdapter { ReadableByteChannel fic = null; try { int len; - fos = new FileOutputStream(getConfig().tempFile, true); + fos = new FileOutputStream(getThreadConfig().tempFile, true); foc = fos.getChannel(); fic = Channels.newChannel(is); ByteBuffer bf = ByteBuffer.allocate(getTaskConfig().getBuffSize()); @@ -186,8 +186,8 @@ public class M3U8ThreadTaskAdapter extends AbsThreadTaskAdapter { handleComplete(); } catch (IOException e) { fail(new AriaIOException(TAG, - String.format("文件下载失败,savePath: %s, url: %s", getConfig().tempFile.getPath(), - getConfig().url), e), true); + String.format("文件下载失败,savePath: %s, url: %s", getThreadConfig().tempFile.getPath(), + getThreadConfig().url), e), true); } finally { try { if (fos != null) { diff --git a/M3U8Component/src/main/java/com/arialyy/aria/m3u8/live/M3U8LiveUtil.java b/M3U8Component/src/main/java/com/arialyy/aria/m3u8/live/M3U8LiveUtil.java index 29581bc3..04346744 100644 --- a/M3U8Component/src/main/java/com/arialyy/aria/m3u8/live/M3U8LiveUtil.java +++ b/M3U8Component/src/main/java/com/arialyy/aria/m3u8/live/M3U8LiveUtil.java @@ -19,13 +19,15 @@ import android.text.TextUtils; import com.arialyy.aria.core.common.AbsEntity; import com.arialyy.aria.core.common.CompleteInfo; import com.arialyy.aria.core.download.DTaskWrapper; -import com.arialyy.aria.core.download.DownloadEntity; -import com.arialyy.aria.core.processor.ILiveTsUrlConverter; import com.arialyy.aria.core.inf.OnFileInfoCallback; +import com.arialyy.aria.core.listener.IEventListener; import com.arialyy.aria.core.loader.AbsLoader; import com.arialyy.aria.core.loader.AbsNormalLoaderUtil; +import com.arialyy.aria.core.processor.ILiveTsUrlConverter; +import com.arialyy.aria.core.wrapper.AbsTaskWrapper; import com.arialyy.aria.exception.BaseException; import com.arialyy.aria.exception.M3U8Exception; +import com.arialyy.aria.http.HttpTaskOption; import com.arialyy.aria.m3u8.M3U8InfoThread; import com.arialyy.aria.m3u8.M3U8Listener; import com.arialyy.aria.m3u8.M3U8TaskOption; @@ -54,23 +56,28 @@ public class M3U8LiveUtil extends AbsNormalLoaderUtil { private List mPeerUrls = new ArrayList<>(); private M3U8TaskOption mM3U8Option; - protected M3U8LiveUtil(DTaskWrapper wrapper, M3U8Listener listener) { + public M3U8LiveUtil(AbsTaskWrapper wrapper, IEventListener listener) { super(wrapper, listener); - wrapper.generateM3u8Option(M3U8TaskOption.class); - mM3U8Option = (M3U8TaskOption) wrapper.getM3u8Option(); + } + + @Override public DTaskWrapper getTaskWrapper() { + return (DTaskWrapper) super.getTaskWrapper(); } @Override protected AbsLoader createLoader() { - return new M3U8LiveLoader((M3U8Listener) getListener(), (DTaskWrapper) getTaskWrapper()); + getTaskWrapper().generateM3u8Option(M3U8TaskOption.class); + getTaskWrapper().generateTaskOption(HttpTaskOption.class); + mM3U8Option = (M3U8TaskOption) getTaskWrapper().getM3u8Option(); + return new M3U8LiveLoader((M3U8Listener) getListener(), getTaskWrapper()); } @Override protected Runnable createInfoThread() { return null; } - private Runnable createLiveInfoThread(){ + private Runnable createLiveInfoThread() { M3U8InfoThread infoThread = - new M3U8InfoThread((DTaskWrapper) getTaskWrapper(), new OnFileInfoCallback() { + new M3U8InfoThread(getTaskWrapper(), new OnFileInfoCallback() { @Override public void onComplete(String key, CompleteInfo info) { ALog.d(TAG, "更新直播的m3u8文件"); } @@ -88,7 +95,7 @@ public class M3U8LiveUtil extends AbsNormalLoaderUtil { ILiveTsUrlConverter converter = mM3U8Option.getLiveTsUrlConverter(); if (converter != null) { if (TextUtils.isEmpty(mM3U8Option.getBandWidthUrl())) { - url = converter.convert(((DownloadEntity) getTaskWrapper().getEntity()).getUrl(), url); + url = converter.convert(getTaskWrapper().getEntity().getUrl(), url); } else { url = converter.convert(mM3U8Option.getBandWidthUrl(), url); } diff --git a/M3U8Component/src/main/java/com/arialyy/aria/m3u8/vod/M3U8VodUtil.java b/M3U8Component/src/main/java/com/arialyy/aria/m3u8/vod/M3U8VodUtil.java index abb28034..1a7a1ebe 100644 --- a/M3U8Component/src/main/java/com/arialyy/aria/m3u8/vod/M3U8VodUtil.java +++ b/M3U8Component/src/main/java/com/arialyy/aria/m3u8/vod/M3U8VodUtil.java @@ -19,13 +19,15 @@ import android.text.TextUtils; import com.arialyy.aria.core.common.AbsEntity; import com.arialyy.aria.core.common.CompleteInfo; import com.arialyy.aria.core.download.DTaskWrapper; -import com.arialyy.aria.core.download.DownloadEntity; -import com.arialyy.aria.core.processor.IVodTsUrlConverter; import com.arialyy.aria.core.inf.OnFileInfoCallback; +import com.arialyy.aria.core.listener.IEventListener; import com.arialyy.aria.core.loader.AbsLoader; import com.arialyy.aria.core.loader.AbsNormalLoaderUtil; +import com.arialyy.aria.core.processor.IVodTsUrlConverter; +import com.arialyy.aria.core.wrapper.AbsTaskWrapper; import com.arialyy.aria.exception.BaseException; import com.arialyy.aria.exception.M3U8Exception; +import com.arialyy.aria.http.HttpTaskOption; import com.arialyy.aria.m3u8.M3U8InfoThread; import com.arialyy.aria.m3u8.M3U8Listener; import com.arialyy.aria.m3u8.M3U8TaskOption; @@ -43,28 +45,32 @@ import java.util.List; */ public class M3U8VodUtil extends AbsNormalLoaderUtil { - private M3U8Listener mListener; private List mUrls = new ArrayList<>(); private M3U8TaskOption mM3U8Option; - public M3U8VodUtil(DTaskWrapper wrapper, M3U8Listener listener) { + public M3U8VodUtil(AbsTaskWrapper wrapper, IEventListener listener) { super(wrapper, listener); - wrapper.generateM3u8Option(M3U8TaskOption.class); - mListener = listener; - mM3U8Option = (M3U8TaskOption) wrapper.getM3u8Option(); + } + + @Override public DTaskWrapper getTaskWrapper() { + return (DTaskWrapper) super.getTaskWrapper(); } @Override protected AbsLoader createLoader() { - return new M3U8VodLoader((M3U8Listener) getListener(), (DTaskWrapper) getTaskWrapper()); + getTaskWrapper().generateM3u8Option(M3U8TaskOption.class); + getTaskWrapper().generateTaskOption(HttpTaskOption.class); + mM3U8Option = (M3U8TaskOption) getTaskWrapper().getM3u8Option(); + return new M3U8VodLoader((M3U8Listener) getListener(), getTaskWrapper()); } @Override protected Runnable createInfoThread() { - return new M3U8InfoThread((DTaskWrapper) getTaskWrapper(), new OnFileInfoCallback() { + return new M3U8InfoThread(getTaskWrapper(), new OnFileInfoCallback() { @Override public void onComplete(String key, CompleteInfo info) { IVodTsUrlConverter converter = mM3U8Option.getVodUrlConverter(); if (converter != null) { if (TextUtils.isEmpty(mM3U8Option.getBandWidthUrl())) { - mUrls.addAll(converter.convert(getEntity().getUrl(), (List) info.obj)); + mUrls.addAll( + converter.convert(getTaskWrapper().getEntity().getUrl(), (List) info.obj)); } else { mUrls.addAll( converter.convert(mM3U8Option.getBandWidthUrl(), (List) info.obj)); @@ -81,7 +87,7 @@ public class M3U8VodUtil extends AbsNormalLoaderUtil { } mM3U8Option.setUrls(mUrls); if (isStop()) { - getListener().onStop(getEntity().getCurrentProgress()); + getListener().onStop(getTaskWrapper().getEntity().getCurrentProgress()); } else if (isCancel()) { getListener().onCancel(); } else { @@ -94,8 +100,4 @@ public class M3U8VodUtil extends AbsNormalLoaderUtil { } }); } - - private DownloadEntity getEntity() { - return (DownloadEntity) getTaskWrapper().getEntity(); - } } diff --git a/PublicComponent/src/main/java/com/arialyy/aria/core/common/RecordHandler.java b/PublicComponent/src/main/java/com/arialyy/aria/core/common/RecordHandler.java index bef20c95..367f1f71 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/core/common/RecordHandler.java +++ b/PublicComponent/src/main/java/com/arialyy/aria/core/common/RecordHandler.java @@ -78,8 +78,11 @@ public class RecordHandler implements IRecordHandler { if (!file.exists()) { ALog.w(TAG, String.format("文件【%s】不存在,重新分配线程区间", mTaskRecord.filePath)); DbEntity.deleteData(ThreadRecord.class, "taskKey=?", mTaskRecord.filePath); + mTaskRecord.threadRecords.clear(); + mTaskRecord.threadNum = mAdapter.initTaskThreadNum(); initRecord(false); } else if (mTaskRecord.threadRecords == null || mTaskRecord.threadRecords.isEmpty()) { + mTaskRecord.threadNum = mAdapter.initTaskThreadNum(); initRecord(false); } mAdapter.handlerTaskRecord(mTaskRecord); diff --git a/PublicComponent/src/main/java/com/arialyy/aria/core/group/AbsGroupUtil.java b/PublicComponent/src/main/java/com/arialyy/aria/core/group/AbsGroupUtil.java index 8a66e24d..3774e083 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/core/group/AbsGroupUtil.java +++ b/PublicComponent/src/main/java/com/arialyy/aria/core/group/AbsGroupUtil.java @@ -23,6 +23,8 @@ import com.arialyy.aria.core.download.DTaskWrapper; import com.arialyy.aria.core.inf.IEntity; import com.arialyy.aria.core.inf.IUtil; import com.arialyy.aria.core.listener.IDGroupListener; +import com.arialyy.aria.core.listener.IEventListener; +import com.arialyy.aria.core.wrapper.AbsTaskWrapper; import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.CommonUtil; import java.util.Map; @@ -49,12 +51,12 @@ public abstract class AbsGroupUtil implements IUtil, Runnable { private DGTaskWrapper mGTWrapper; private GroupRunState mState; - protected AbsGroupUtil(IDGroupListener listener, DGTaskWrapper groupWrapper) { - mListener = listener; - mGTWrapper = groupWrapper; + protected AbsGroupUtil(AbsTaskWrapper groupWrapper, IEventListener listener) { + mListener = (IDGroupListener) listener; + mGTWrapper = (DGTaskWrapper) groupWrapper; mUpdateInterval = Configuration.getInstance().downloadCfg.getUpdateInterval(); mState = new GroupRunState(groupWrapper.getKey(), mListener, - groupWrapper.getSubTaskWrapper().size(), mSubQueue); + mGTWrapper.getSubTaskWrapper().size(), mSubQueue); mScheduler = new Handler(Looper.getMainLooper(), SimpleSchedulers.newInstance(mState)); initState(); } diff --git a/PublicComponent/src/main/java/com/arialyy/aria/core/listener/DownloadGroupListener.java b/PublicComponent/src/main/java/com/arialyy/aria/core/listener/DownloadGroupListener.java index 6d882148..77db34a3 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/core/listener/DownloadGroupListener.java +++ b/PublicComponent/src/main/java/com/arialyy/aria/core/listener/DownloadGroupListener.java @@ -23,6 +23,7 @@ import com.arialyy.aria.core.group.GroupSendParams; import com.arialyy.aria.core.inf.IEntity; import com.arialyy.aria.core.inf.IRecordHandler; import com.arialyy.aria.core.inf.TaskSchedulerType; +import com.arialyy.aria.core.task.AbsTask; import com.arialyy.aria.core.task.DownloadGroupTask; import com.arialyy.aria.exception.BaseException; import com.arialyy.aria.util.ALog; @@ -34,14 +35,14 @@ import com.arialyy.aria.util.RecordUtil; * Created by Aria.Lao on 2017/7/20. 任务组下载事件 */ public class DownloadGroupListener - extends BaseListener + extends BaseListener> implements IDGroupListener { private GroupSendParams mSeedEntity; - public DownloadGroupListener(DownloadGroupTask task, Handler outHandler) { + public DownloadGroupListener(AbsTask task, Handler outHandler) { super(task, outHandler); mSeedEntity = new GroupSendParams<>(); - mSeedEntity.groupTask = task; + mSeedEntity.groupTask = (DownloadGroupTask) task; } @Override diff --git a/PublicComponent/src/main/java/com/arialyy/aria/core/task/AbsThreadTaskAdapter.java b/PublicComponent/src/main/java/com/arialyy/aria/core/task/AbsThreadTaskAdapter.java index 8e4efe97..f9d9679a 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/core/task/AbsThreadTaskAdapter.java +++ b/PublicComponent/src/main/java/com/arialyy/aria/core/task/AbsThreadTaskAdapter.java @@ -37,7 +37,7 @@ public abstract class AbsThreadTaskAdapter implements IThreadTaskAdapter { /** * 当前线程的下去区间的进度 */ - private long mRangeProgress = 0; + private long mRangeProgress; private ThreadRecord mThreadRecord; private IThreadTaskObserver mObserver; private AbsTaskWrapper mWrapper; @@ -75,9 +75,7 @@ public abstract class AbsThreadTaskAdapter implements IThreadTaskAdapter { return mThreadRecord; } - @Deprecated protected AbsTaskWrapper getTaskWrapper() { - // TODO: 2019-09-18 需要修改方法名称为:getWrapper return mWrapper; } @@ -95,9 +93,7 @@ public abstract class AbsThreadTaskAdapter implements IThreadTaskAdapter { /** * 获取线程配置信息 */ - @Deprecated - protected SubThreadConfig getConfig() { - // TODO: 2019-09-18 需要修改方法名称为:getThreadConfig + protected SubThreadConfig getThreadConfig() { return mThreadConfig; } @@ -108,7 +104,7 @@ public abstract class AbsThreadTaskAdapter implements IThreadTaskAdapter { @Override public void setMaxSpeed(int speed) { if (mSpeedBandUtil == null) { mSpeedBandUtil = - new BandwidthLimiter(getTaskConfig().getMaxSpeed(), getConfig().startThreadNum); + new BandwidthLimiter(getTaskConfig().getMaxSpeed(), getThreadConfig().startThreadNum); } mSpeedBandUtil.setMaxRate(speed); } diff --git a/PublicComponent/src/main/java/com/arialyy/aria/core/task/ThreadTask.java b/PublicComponent/src/main/java/com/arialyy/aria/core/task/ThreadTask.java index d711559a..464b9af6 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/core/task/ThreadTask.java +++ b/PublicComponent/src/main/java/com/arialyy/aria/core/task/ThreadTask.java @@ -25,8 +25,8 @@ import com.arialyy.aria.core.AriaConfig; import com.arialyy.aria.core.ThreadRecord; import com.arialyy.aria.core.common.SubThreadConfig; import com.arialyy.aria.core.inf.IEntity; -import com.arialyy.aria.core.listener.ISchedulers; import com.arialyy.aria.core.inf.IThreadState; +import com.arialyy.aria.core.listener.ISchedulers; import com.arialyy.aria.core.manager.ThreadTaskManager; import com.arialyy.aria.core.wrapper.AbsTaskWrapper; import com.arialyy.aria.core.wrapper.ITaskWrapper; @@ -62,16 +62,16 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver { private Handler mStateHandler; private SubThreadConfig mConfig; /** - * 当前子线程相对于总长度的位置 + * 当前线程的下去区间的进度 */ - protected long mChildCurrentLocation = 0; + private long mRangeProgress; private IThreadTaskAdapter mAdapter; - protected ThreadRecord mRecord; + private ThreadRecord mRecord; private Thread mConfigThread = new Thread(new Runnable() { @Override public void run() { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); - final long currentTemp = mChildCurrentLocation; + final long currentTemp = mRangeProgress; writeConfig(false, currentTemp); } }); @@ -86,7 +86,7 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver { mConfigThreadPool = Executors.newCachedThreadPool(); isNotNetRetry = AriaConfig.getInstance().getAConfig().isNotNetRetry(); - mChildCurrentLocation = mRecord.startLocation; + mRangeProgress = mRecord.startLocation; } /** @@ -94,6 +94,7 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver { */ public void setAdapter(IThreadTaskAdapter adapter) { mAdapter = adapter; + mAdapter.setThreadStateObserver(this); } /** @@ -166,7 +167,7 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver { public void breakTask() { taskBreak = true; if (mTaskWrapper.isSupportBP()) { - final long currentTemp = mChildCurrentLocation; + final long currentTemp = mRangeProgress; updateState(IThreadState.STATE_STOP, null); ALog.d(TAG, String.format("任务【%s】thread__%s__中断【停止位置:%s】", getFileName(), mRecord.threadId, currentTemp)); @@ -239,7 +240,7 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver { ALog.i(TAG, String.format("任务【%s】已停止", getFileName())); } else { if (mTaskWrapper.isSupportBP()) { - final long stopLocation = mChildCurrentLocation; + final long stopLocation = mRangeProgress; ALog.d(TAG, String.format("任务【%s】thread__%s__停止【当前线程停止位置:%s】", getFileName(), mRecord.threadId, stopLocation)); @@ -295,20 +296,20 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver { * * @param needRetry 是否需要重试,一般是网络错误才需要重试 */ - @Override public void updateFailState(@Nullable BaseException e, boolean needRetry) { - + @Override public synchronized void updateFailState(@Nullable BaseException e, boolean needRetry) { + fail(mRangeProgress, e, needRetry); } @Override public synchronized void updateProgress(long len) { - mChildCurrentLocation += len; + mRangeProgress += len; Thread loopThread = mStateHandler.getLooper().getThread(); if (!loopThread.isAlive() || loopThread.isInterrupted()) { return; } mStateHandler.obtainMessage(IThreadState.STATE_RUNNING, len).sendToTarget(); if (System.currentTimeMillis() - mLastSaveTime > 5000 - && mChildCurrentLocation < mRecord.endLocation) { + && mRangeProgress < mRecord.endLocation) { mLastSaveTime = System.currentTimeMillis(); if (!mConfigThreadPool.isShutdown()) { mConfigThreadPool.execute(mConfigThread); @@ -327,16 +328,6 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver { String.format("任务【%s】thread__%s__取消", getFileName(), mRecord.threadId)); } - /** - * 线程任务失败 - * - * @param subCurrentLocation 当前线程下载进度 - * @param ex 异常信息 - */ - protected void fail(long subCurrentLocation, BaseException ex) { - fail(subCurrentLocation, ex, true); - } - /** * 任务失败 * @@ -451,7 +442,7 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver { /** * 发送失败信息 */ - protected void sendFailMsg(@Nullable BaseException e) { + private void sendFailMsg(@Nullable BaseException e) { if (e != null) { Bundle b = new Bundle(); b.putSerializable(IThreadState.KEY_ERROR_INFO, e); @@ -467,7 +458,7 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver { * @param isComplete 当前线程是否完成 {@code true}完成 * @param record 当前下载进度 */ - protected void writeConfig(boolean isComplete, final long record) { + private void writeConfig(boolean isComplete, final long record) { if (mRecord != null) { mRecord.isComplete = isComplete; if (mConfig.isBlock) { @@ -487,6 +478,7 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver { isDestroy = false; Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); TrafficStats.setThreadStatsTag(UUID.randomUUID().toString().hashCode()); + mAdapter.call(this); return this; } } diff --git a/PublicComponent/src/main/java/com/arialyy/aria/util/ComponentUtil.java b/PublicComponent/src/main/java/com/arialyy/aria/util/ComponentUtil.java index 37d93aee..600e6ae1 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/util/ComponentUtil.java +++ b/PublicComponent/src/main/java/com/arialyy/aria/util/ComponentUtil.java @@ -20,10 +20,8 @@ import com.arialyy.aria.core.TaskOptionParams; import com.arialyy.aria.core.inf.IEventHandler; import com.arialyy.aria.core.inf.ITaskOption; import com.arialyy.aria.core.inf.IUtil; -import com.arialyy.aria.core.listener.BaseListener; import com.arialyy.aria.core.listener.IEventListener; import com.arialyy.aria.core.task.AbsTask; -import com.arialyy.aria.core.task.ITask; import com.arialyy.aria.core.wrapper.AbsTaskWrapper; import com.arialyy.aria.core.wrapper.ITaskWrapper; import java.lang.ref.SoftReference; @@ -42,8 +40,8 @@ public class ComponentUtil { public static final int COMPONENT_TYPE_FTP = 2; public static final int COMPONENT_TYPE_M3U8 = 3; - private static volatile ComponentUtil INSTANCE = null; private String TAG = CommonUtil.getClassName(getClass()); + private static volatile ComponentUtil INSTANCE = null; private ComponentUtil() { @@ -99,7 +97,7 @@ public class ComponentUtil { * * @return 返回下载工具,创建失败返回null */ - public T buildUtil(ITaskWrapper wrapper, IEventListener listener) { + public T buildUtil(AbsTaskWrapper wrapper, IEventListener listener) { int requestType = wrapper.getRequestType(); String className = null; switch (requestType) { @@ -122,10 +120,10 @@ public class ComponentUtil { className = "com.arialyy.aria.http.upload.HttpULoaderUtil"; break; case ITaskWrapper.D_FTP_DIR: - className = "com.arialyy.aria.http.download.DGroupLoaderUtil"; + className = "com.arialyy.aria.ftp.download.FtpDirDLoaderUtil"; break; case ITaskWrapper.DG_HTTP: - className = "com.arialyy.aria.ftp.download.FtpDirDLoaderUtil"; + className = "com.arialyy.aria.http.download.DGroupLoaderUtil"; break; } if (className == null) { @@ -158,7 +156,7 @@ public class ComponentUtil { * @param wrapperType 任务类型{@link ITaskWrapper} * @return 返回事件监听,如果创建失败返回null */ - public T buildListener(int wrapperType, ITask task, + public T buildListener(int wrapperType, AbsTask task, Handler outHandler) { String className = null, errorStr = "请添加FTP插件"; switch (wrapperType) { @@ -217,6 +215,7 @@ public class ComponentUtil { try { taskOption = clazz.newInstance(); for (Field field : fields) { + field.setAccessible(true); Class type = field.getType(); String key = field.getName(); if (type != SoftReference.class) { diff --git a/app/build.gradle b/app/build.gradle index 7d4bca30..4ffcbf6a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -73,6 +73,7 @@ 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(path: ':M3U8Component') } repositories { mavenCentral() diff --git a/app/src/main/java/com/arialyy/simple/core/download/m3u8/M3U8VodDLoadActivity.java b/app/src/main/java/com/arialyy/simple/core/download/m3u8/M3U8VodDLoadActivity.java index 60086a2a..a42d1a1a 100644 --- a/app/src/main/java/com/arialyy/simple/core/download/m3u8/M3U8VodDLoadActivity.java +++ b/app/src/main/java/com/arialyy/simple/core/download/m3u8/M3U8VodDLoadActivity.java @@ -291,7 +291,7 @@ public class M3U8VodDLoadActivity extends BaseActivity { @Override public List convert(String m3u8Url, List tsUrls) { Uri uri = Uri.parse(m3u8Url); - String parentUrl = uri.getAuthority() + "://" + uri.getHost(); + String parentUrl = "http://" + uri.getHost(); List newUrls = new ArrayList<>(); for (String url : tsUrls) { newUrls.add(parentUrl + url); @@ -325,12 +325,6 @@ public class M3U8VodDLoadActivity extends BaseActivity { //}) .setTsUrlConvert(new IVodTsUrlConverter() { @Override public List convert(String m3u8Url, List tsUrls) { - //int index = m3u8Url.lastIndexOf("/"); - //String parentUrl = m3u8Url.substring(0, index + 1); - //List newUrls = new ArrayList<>(); - //for (String url : tsUrls) { - // newUrls.add(parentUrl + url); - //} Uri uri = Uri.parse(m3u8Url); String parentUrl = uri.getScheme() + "://" + uri.getHost(); List newUrls = new ArrayList<>(); @@ -350,16 +344,6 @@ public class M3U8VodDLoadActivity extends BaseActivity { .generateIndexFile() .controller(ControllerType.CREATE_CONTROLLER) .create(); - - Aria.download(M3U8VodDLoadActivity.this) - .load(mUrl) - .useServerFileName(true) - .setFilePath(mFilePath, true) - .asM3U8().setTsUrlConvert(new IVodTsUrlConverter() { - @Override public List convert(String m3u8Url, List tsUrls) { - return null; - } - }); } private Class c = BuilderController.class; diff --git a/app/src/main/res/layout/activity_m3u8_vod.xml b/app/src/main/res/layout/activity_m3u8_vod.xml index b8f3ad62..934d2aaf 100644 --- a/app/src/main/res/layout/activity_m3u8_vod.xml +++ b/app/src/main/res/layout/activity_m3u8_vod.xml @@ -77,6 +77,7 @@ />