Skip to content

Commit 28be25b

Browse files
添加说明
1 parent 3301747 commit 28be25b

File tree

11 files changed

+1452
-31
lines changed

11 files changed

+1452
-31
lines changed

README.md

+1,391
Large diffs are not rendered by default.

app/src/main/java/top/xuqingquan/m3u8downloader/demo/MainActivity.kt

+4-2
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,11 @@ class MainActivity : AppCompatActivity() {
3131
setContentView(R.layout.activity_main)
3232
initListView()
3333
initListWithPermissionCheck()
34+
//接收进度通知
3435
FileDownloader.downloadCallback.observe(this, Observer {
3536
onProgress(it)
3637
})
38+
//新建下载
3739
add.setOnClickListener {
3840
newDownload()
3941
}
@@ -50,7 +52,7 @@ class MainActivity : AppCompatActivity() {
5052
Manifest.permission.WRITE_EXTERNAL_STORAGE
5153
)
5254
fun initList() {
53-
thread {
55+
thread {//在线程中处理,防止ANR
5456
FileDownloader.getBaseDownloadPath().listFiles().forEach {
5557
val file = File(it, "video.config")
5658
if (file.exists()) {
@@ -76,7 +78,7 @@ class MainActivity : AppCompatActivity() {
7678
adapter.notifyDataSetChanged()
7779
}
7880
videoList.sort()
79-
81+
//依次添加下载队列
8082
videoList.filter { it.status == DOWNLOADING }.forEach {
8183
FileDownloader.downloadVideo(it)
8284
}

app/src/main/java/top/xuqingquan/m3u8downloader/demo/VideoDownloadAdapter.kt

+10
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ class VideoDownloadAdapter(private val list: MutableList<VideoDownloadEntity>) :
2828

2929
override fun getItemCount() = list.size
3030

31+
/**
32+
* 避免出现整个item闪烁
33+
*/
3134
override fun onBindViewHolder(holder: ViewHolder, position: Int, payloads: MutableList<Any>) {
3235
if (payloads.isNullOrEmpty()) {
3336
super.onBindViewHolder(holder, position, payloads)
@@ -47,6 +50,9 @@ class VideoDownloadAdapter(private val list: MutableList<VideoDownloadEntity>) :
4750
private val url = view.findViewById<TextView>(R.id.url)
4851
private val download = view.findViewById<TextView>(R.id.download)
4952

53+
/**
54+
* 设置数据
55+
*/
5056
@SuppressLint("SetTextI18n")
5157
fun setData(data: VideoDownloadEntity?) {
5258
if (data == null) {
@@ -71,6 +77,9 @@ class VideoDownloadAdapter(private val list: MutableList<VideoDownloadEntity>) :
7177
updateProgress(data)
7278
}
7379

80+
/**
81+
* 进度更新
82+
*/
7483
@SuppressLint("SetTextI18n")
7584
fun updateProgress(data: VideoDownloadEntity) {
7685
if (data.originalUrl.endsWith(".m3u8") || data.status == COMPLETE) {
@@ -85,6 +94,7 @@ class VideoDownloadAdapter(private val list: MutableList<VideoDownloadEntity>) :
8594
speed.text =
8695
"${DecimalFormat("#.##%").format(data.currentProgress)}|${data.currentSpeed}"
8796
val context = view.context
97+
//状态逻辑处理
8898
when (data.status) {
8999
NO_START -> {
90100
download.setTextColor(ContextCompat.getColor(context, R.color.blue))

art/m3u8Downloader_0.png

53.8 KB
Loading

art/m3u8Downloader_1.png

9.38 KB
Loading

art/m3u8Downloader_2.mp4

2.73 MB
Binary file not shown.

m3u8downloader/src/main/java/top/xuqingquan/m3u8downloader/FileDownloader.kt

+32-22
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,14 @@ object FileDownloader {
2525
get() {
2626
if (field == -1) {
2727
field = Runtime.getRuntime().availableProcessors() / 2//可用线程数的一半
28-
if (Build.VERSION.SDK_INT < 23) {
28+
if (Build.VERSION.SDK_INT < 23) {//如果小于Android6的,可用线程数再减2
2929
field -= 2
3030
}
3131
}
32-
if (field > 5) {
32+
if (field > 5) {//最多只能有5个并行
3333
field = 5
3434
}
35-
if (field <= 0) {
35+
if (field <= 0) {//最少也要有1个任务
3636
field = 1
3737
}
3838
return field
@@ -46,14 +46,13 @@ object FileDownloader {
4646
}
4747
private var downloadingList = arrayListOf<String>()//下载中的列表,为统计线程使用
4848
private var waitDownloadList = arrayListOf<String>()//等待下载的url列表
49-
//排队列表
50-
private val downloadList = arrayListOf<VideoDownloadEntity>()
51-
//等待下载的队列
52-
private val waitList = arrayListOf<VideoDownloadEntity>()
53-
private var wait = false//等待状态
54-
var hasShowWifiTips = false
55-
var hasToastWifiTips = false
49+
private val downloadList = arrayListOf<VideoDownloadEntity>()//排队列表
50+
private val waitList = arrayListOf<VideoDownloadEntity>()//等待下载的队列
51+
private var wait = false//m3u8等待状态
5652

53+
/**
54+
* 停止全部任务
55+
*/
5756
fun clearAllDownload() {
5857
OkDownload.with().downloadDispatcher().cancelAll()
5958
downloadingList.clear()
@@ -106,7 +105,7 @@ object FileDownloader {
106105
}
107106

108107
/**
109-
* 获取根据链接得到的url
108+
* 获取根据链接得到的下载存储路径
110109
*/
111110
@JvmStatic
112111
fun getDownloadPath(url: String): File {
@@ -126,11 +125,17 @@ object FileDownloader {
126125
return File(path, "video.config")
127126
}
128127

128+
/**
129+
* 获取相关配置文件
130+
*/
129131
@JvmStatic
130132
fun getConfigFile(path: File): File {
131133
return File(path, "video.config")
132134
}
133135

136+
/**
137+
* 下载的入口
138+
*/
134139
@JvmStatic
135140
fun downloadVideo(entity: VideoDownloadEntity) {
136141
if (entity.status == DELETE) {
@@ -143,17 +148,20 @@ object FileDownloader {
143148
}
144149
}
145150

151+
/**
152+
* 下载但文件入口
153+
*/
146154
@JvmStatic
147155
private fun downloadSingleVideo(entity: VideoDownloadEntity) {
148-
if (entity.status == DELETE) {
156+
if (entity.status == DELETE) {//删除状态的忽略
149157
Log.d(TAG, "downloadSingleVideo---DELETE")
150158
return
151159
}
152160
if (useProgress < MAX_PROGRESS) {//还有可用的线程数
153-
SingleVideoDownloader.fileDownloader(entity)
161+
SingleVideoDownloader.fileDownloader(entity)//进入下载
154162
Log.d(TAG, "-----useProgress===>$useProgress")
155163
} else {//没有可用线程的时候就添加到等待队列
156-
SingleVideoDownloader.initConfig(entity)
164+
SingleVideoDownloader.initConfig(entity)//初始化一下下载任务
157165
//不是下载中的内容,且没有在等待
158166
if (!downloadingList.contains(entity.originalUrl) && !waitDownloadList.contains(entity.originalUrl)) {
159167
downloadList.add(entity)
@@ -163,6 +171,7 @@ object FileDownloader {
163171
downloadCallback.postValue(entity)
164172
} else {
165173
if (entity.status == NO_START || entity.status == ERROR || entity.status == PAUSE) {
174+
//如果要下载的内容是等待中的,但是状态还没有修正过来,则修正状态
166175
entity.status = PREPARE
167176
downloadCallback.postValue(entity)
168177
}
@@ -173,19 +182,19 @@ object FileDownloader {
173182

174183
@JvmStatic
175184
private fun downloadM3U8File(entity: VideoDownloadEntity) {
176-
if (entity.status == DELETE) {
185+
if (entity.status == DELETE) {//删除状态的忽略
177186
Log.d(TAG, "downloadM3U8File---DELETE")
178187
return
179188
}
180189
Log.d(TAG, "$wait--downloadM3U8File--${entity.originalUrl}")
181190
thread {
182-
if (wait) {
191+
if (wait) {//如果有在获取真实ts的内容则添加到等待队列
183192
Log.d(TAG, "addWaiting")
184193
waitList.add(entity)
185194
return@thread
186195
}
187196
wait = true
188-
val file = M3U8ConfigDownloader.start(entity)
197+
val file = M3U8ConfigDownloader.start(entity)//准备下载列表
189198
if (useProgress < MAX_PROGRESS) {//还有可用的线程数
190199
if (file != null) {//需要下载
191200
var times = 50
@@ -195,7 +204,7 @@ object FileDownloader {
195204
Thread.sleep(100)
196205
times--
197206
}
198-
if (file.exists()) {
207+
if (file.exists()) {//如果文件存在了则开始下载
199208
M3U8Downloader.bunchDownload(getDownloadPath(entity.originalUrl))
200209
}
201210
Log.d(TAG, "${file.exists()}-----useProgress===>$useProgress")
@@ -204,10 +213,9 @@ object FileDownloader {
204213
}
205214
} else {//没有可用线程的时候就添加到等待队列
206215
//不是下载中的内容,且没有在等待
207-
if (!downloadingList.contains(entity.originalUrl) && !waitDownloadList.contains(
208-
entity.originalUrl
209-
)
210-
) {
216+
if (!downloadingList.contains(entity.originalUrl) &&
217+
!waitDownloadList.contains(entity.originalUrl)
218+
) {//添加到任务队列
211219
downloadList.add(entity)
212220
waitDownloadList.add(entity.originalUrl)
213221
Log.d(TAG, "addDownloadList---${entity.originalUrl}")
@@ -216,13 +224,15 @@ object FileDownloader {
216224
} else {
217225
Log.d(TAG, "下载中或等待中的文件")
218226
if (entity.status == NO_START || entity.status == ERROR || entity.status == PAUSE) {
227+
//如果要下载的内容是等待中的,但是状态还没有修正过来,则修正状态
219228
entity.status = PREPARE
220229
downloadCallback.postValue(entity)
221230
}
222231
}
223232
}
224233
wait = false
225234
if (waitList.isNotEmpty()) {
235+
//有等待获取真实ts流的则继续回调
226236
Log.d(TAG, "removeWaiting")
227237
downloadM3U8File(waitList.removeAt(0))
228238
}

m3u8downloader/src/main/java/top/xuqingquan/m3u8downloader/M3U8ConfigDownloader.kt

+2-1
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,12 @@ import java.io.File
1313
/**
1414
* Created by 许清泉 on 2019-10-15 22:13
1515
*/
16-
object M3U8ConfigDownloader {
16+
internal object M3U8ConfigDownloader {
1717

1818
private val downloadList = arrayListOf<String>()
1919
private val TAG = "M3U8ConfigDownloader"
2020

21+
//清楚所有任务
2122
fun clear() {
2223
downloadList.clear()
2324
}

m3u8downloader/src/main/java/top/xuqingquan/m3u8downloader/M3U8Downloader.kt

+6-2
Original file line numberDiff line numberDiff line change
@@ -15,26 +15,30 @@ import java.io.File
1515
/**
1616
* Created by 许清泉 on 2019-10-14 16:51
1717
*/
18-
object M3U8Downloader {
18+
internal object M3U8Downloader {
1919
private val downloadList = arrayListOf<String>()
2020
private const val TAG = "---M3U8Downloader---"
2121

22+
//清楚所有任务
2223
fun clear() {
2324
downloadList.clear()
2425
}
2526

27+
//批下载
2628
fun bunchDownload(path: File) {
2729
val config = FileDownloader.getConfigFile(path)
2830
Log.d(TAG, "config==>${config.readText()}")
2931
val entity = parseJsonToVideoDownloadEntity(config.readText())
30-
if (entity == null) {
32+
if (entity == null) {//获取到的实体类为空的忽略
3133
Log.d(TAG, "entity==null${config.readText()}")
3234
return
3335
}
36+
//如果状态是删除的就忽略
3437
if (entity.status == DELETE) {
3538
path.deleteRecursively()
3639
return
3740
}
41+
//避免重复进入下载
3842
if (downloadList.contains(entity.originalUrl)) {
3943
Log.d(TAG, "contains")
4044
return

m3u8downloader/src/main/java/top/xuqingquan/m3u8downloader/SingleVideoDownloader.kt

+6-3
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,16 @@ import java.io.File
1313
/**
1414
* Created by 许清泉 on 2019-10-16 09:54
1515
*/
16-
object SingleVideoDownloader {
16+
internal object SingleVideoDownloader {
1717
private val downloadList = arrayListOf<String>()
1818
private const val TAG = "SingleVideoDownloader"
1919

20+
//清理所有任务
2021
fun clear() {
2122
downloadList.clear()
2223
}
2324

25+
//下载任务的初始化
2426
fun initConfig(entity: VideoDownloadEntity): File {
2527
val config = FileDownloader.getConfigFile(entity.originalUrl)
2628
if (!config.exists()) {
@@ -37,13 +39,14 @@ object SingleVideoDownloader {
3739
return config
3840
}
3941

42+
//下载任务的入口
4043
fun fileDownloader(entity: VideoDownloadEntity) {
4144
val path = FileDownloader.getDownloadPath(entity.originalUrl)
42-
if (entity.status == DELETE) {
45+
if (entity.status == DELETE) {//如果是删除状态的则忽略
4346
path.deleteRecursively()
4447
return
4548
}
46-
if (downloadList.contains(entity.originalUrl)) {
49+
if (downloadList.contains(entity.originalUrl)) {//避免重复下载
4750
Log.d(TAG, "contains---${entity.originalUrl},${entity.name}")
4851
return
4952
}

m3u8downloader/src/main/java/top/xuqingquan/m3u8downloader/utils/MD5Utils.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import java.security.MessageDigest
66
/**
77
* Created by 许清泉 on 2019-10-14 15:23
88
*/
9-
fun md5(plainText: String): String {
9+
internal fun md5(plainText: String): String {
1010
//定义一个字节数组
1111
lateinit var secretBytes: ByteArray
1212
try {

0 commit comments

Comments
 (0)