From 9099a4af7ef7a4aa75769ffcac1a09bee4994ca2 Mon Sep 17 00:00:00 2001 From: 10miaomiao <1033607264@qq.com> Date: Sun, 23 Jul 2023 00:29:57 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84=E4=B8=8B=E8=BD=BD=E6=A8=A1?= =?UTF-8?q?=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../download/DownloadVideoCreateFragment.kt | 18 +- .../download/DownloadVideoCreateViewModel.kt | 11 +- .../pages/download/DownloadDetailPage.kt | 18 +- .../commponents/DownloadDetailItem.kt | 6 +- .../download/commponents/DownloadListItem.kt | 3 +- .../compose/pages/user/UserFollowPage.kt | 2 +- .../bilimiao/download/DownloadManager.kt | 42 ++-- .../bilimiao/download/DownloadNotify.kt | 32 ++- .../bilimiao/download/DownloadService.kt | 199 ++++++++++++------ .../bilimiao/download/LocalPlayerSource.kt | 6 +- .../download/entry/BiliDownloadEntryInfo.kt | 3 +- .../download/entry/CurrentDownloadInfo.kt | 6 + .../res/drawable/ic_baseline_error_24.xml | 5 + .../ic_baseline_file_download_done_24.xml | 5 + 14 files changed, 243 insertions(+), 113 deletions(-) create mode 100644 bilimiao-download/src/main/res/drawable/ic_baseline_error_24.xml create mode 100644 bilimiao-download/src/main/res/drawable/ic_baseline_file_download_done_24.xml diff --git a/app/src/main/java/com/a10miaomiao/bilimiao/page/download/DownloadVideoCreateFragment.kt b/app/src/main/java/com/a10miaomiao/bilimiao/page/download/DownloadVideoCreateFragment.kt index a2e6593e..541a580f 100644 --- a/app/src/main/java/com/a10miaomiao/bilimiao/page/download/DownloadVideoCreateFragment.kt +++ b/app/src/main/java/com/a10miaomiao/bilimiao/page/download/DownloadVideoCreateFragment.kt @@ -6,6 +6,7 @@ import android.view.Gravity import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.AdapterView import android.widget.ArrayAdapter import androidx.core.os.bundleOf import androidx.fragment.app.Fragment @@ -92,6 +93,15 @@ class DownloadVideoCreateFragment : Fragment(), DIAware, MyPage { viewModel.selectedItem(item) } + val handleItemSelectedListener = object : AdapterView.OnItemSelectedListener { + override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { + viewModel.selectedQuality(viewModel.acceptQuality[position]) + } + override fun onNothingSelected(parent: AdapterView<*>?) { + + } + } + val itemUi = miaoBindingItemUi { item, index -> frameLayout { setBackgroundResource(R.drawable.shape_corner) @@ -167,10 +177,10 @@ class DownloadVideoCreateFragment : Fragment(), DIAware, MyPage { mAdapter.clear() mAdapter.addAll(viewModel.acceptDescription) } -// miaoEffect(viewModel.spinnerSelected) { -// setSelection(it) -// } -// onItemChanged(viewModel::changedSpinnerItem) + miaoEffect(viewModel.qualityIndex) { + setSelection(it) + } + onItemSelectedListener = handleItemSelectedListener }..lParams(width = wrapContent) } } diff --git a/app/src/main/java/com/a10miaomiao/bilimiao/page/download/DownloadVideoCreateViewModel.kt b/app/src/main/java/com/a10miaomiao/bilimiao/page/download/DownloadVideoCreateViewModel.kt index 658f4920..f6547181 100644 --- a/app/src/main/java/com/a10miaomiao/bilimiao/page/download/DownloadVideoCreateViewModel.kt +++ b/app/src/main/java/com/a10miaomiao/bilimiao/page/download/DownloadVideoCreateViewModel.kt @@ -31,6 +31,8 @@ class DownloadVideoCreateViewModel( var acceptDescription = listOf() var acceptQuality = listOf() var quality = 64 + val qualityIndex get() = acceptQuality.indexOf(quality) + val qualityDescription get() = acceptDescription[qualityIndex] ?: "未知" val selectedList = mutableListOf() var downloadedList = mutableListOf() @@ -76,6 +78,12 @@ class DownloadVideoCreateViewModel( } } + fun selectedQuality(value: Int) { + ui.setState { + quality = value + } + } + fun startDownload () { if (selectedList.size == 0) { context.toast("请选择分P") @@ -91,7 +99,7 @@ class DownloadVideoCreateViewModel( selectedList.clear() } - fun selectedItem (item: DownloadVideoCreateParam.Page) { + fun selectedItem(item: DownloadVideoCreateParam.Page) { val index = selectedList.indexOf(item.cid) ui.setState { if (index == -1) { @@ -128,6 +136,7 @@ class DownloadVideoCreateViewModel( type_tag = quality.toString(), cover = video.pic, prefered_video_quality = quality, + quality_pithy_description = qualityDescription, guessed_total_bytes = 0, total_time_milli = 0, danmaku_count = 1000, diff --git a/bilimiao-compose/src/main/java/cn/a10miaomiao/bilimiao/compose/pages/download/DownloadDetailPage.kt b/bilimiao-compose/src/main/java/cn/a10miaomiao/bilimiao/compose/pages/download/DownloadDetailPage.kt index bd442b5c..ac83b558 100644 --- a/bilimiao-compose/src/main/java/cn/a10miaomiao/bilimiao/compose/pages/download/DownloadDetailPage.kt +++ b/bilimiao-compose/src/main/java/cn/a10miaomiao/bilimiao/compose/pages/download/DownloadDetailPage.kt @@ -178,13 +178,13 @@ class DownloadDetailPageViewModel( downloadService?.startDownload(item.dir_path) } - fun pauseClick(item: DownloadItemInfo) { - downloadService?.cancelDownload() + fun pauseClick(item: DownloadItemInfo, taskId: Long) { + downloadService?.cancelDownload(taskId) } fun deleteDownload( - dirPath: String, item: DownloadItemInfo, + dirPath: String, ) { val info = downloadInfo?.value ?: return viewModelScope.launch { @@ -237,21 +237,21 @@ fun DownloadDetailPage( items( downloadItems, key = { it.cid }, - ) { + ) { item -> DownloadDetailItem( curDownload = curDownload, - item = it, + item = item, onClick = { - viewModel.itemClick(it) + viewModel.itemClick(item) }, onStartClick = { - viewModel.startClick(it) + viewModel.startClick(item) }, onPauseClick = { - viewModel.pauseClick(it) + viewModel.pauseClick(item, it) }, onDeleteClick = { - viewModel.deleteDownload(dirPath, it) + viewModel.deleteDownload(item, dirPath) } ) } diff --git a/bilimiao-compose/src/main/java/cn/a10miaomiao/bilimiao/compose/pages/download/commponents/DownloadDetailItem.kt b/bilimiao-compose/src/main/java/cn/a10miaomiao/bilimiao/compose/pages/download/commponents/DownloadDetailItem.kt index 44b32535..eefcc8f4 100644 --- a/bilimiao-compose/src/main/java/cn/a10miaomiao/bilimiao/compose/pages/download/commponents/DownloadDetailItem.kt +++ b/bilimiao-compose/src/main/java/cn/a10miaomiao/bilimiao/compose/pages/download/commponents/DownloadDetailItem.kt @@ -28,7 +28,7 @@ fun DownloadDetailItem( item: DownloadItemInfo, onClick: () -> Unit, onStartClick: () -> Unit, - onPauseClick: () -> Unit, + onPauseClick: (taskId: Long) -> Unit, onDeleteClick: () -> Unit, ) { var expandedMoreMenu by remember { mutableStateOf(false) } @@ -48,7 +48,7 @@ fun DownloadDetailItem( verticalAlignment = Alignment.CenterVertically, ) { GlideImage( - imageModel = UrlUtil.autoHttps(item.cover), + imageModel = UrlUtil.autoHttps(item.cover) + "@672w_378h_1c_", modifier = Modifier .size(width = 60.dp, height = 40.dp) .clip(RoundedCornerShape(5.dp)) @@ -79,7 +79,7 @@ fun DownloadDetailItem( } if (!item.is_completed) { if (item.cid == curDownload?.id && curDownload.status in 100 until 200) { - IconButton(onClick = onPauseClick) { + IconButton(onClick = { onPauseClick(curDownload.taskId) }) { Icon(Icons.Filled.Pause, null) } } else { diff --git a/bilimiao-compose/src/main/java/cn/a10miaomiao/bilimiao/compose/pages/download/commponents/DownloadListItem.kt b/bilimiao-compose/src/main/java/cn/a10miaomiao/bilimiao/compose/pages/download/commponents/DownloadListItem.kt index 83f5e740..9083d9d1 100644 --- a/bilimiao-compose/src/main/java/cn/a10miaomiao/bilimiao/compose/pages/download/commponents/DownloadListItem.kt +++ b/bilimiao-compose/src/main/java/cn/a10miaomiao/bilimiao/compose/pages/download/commponents/DownloadListItem.kt @@ -28,7 +28,6 @@ fun DownloadListItem( item: DownloadInfo, onClick: () -> Unit ) { - val nav = localNavController() Box( modifier = Modifier.padding(5.dp), ) { @@ -46,7 +45,7 @@ fun DownloadListItem( verticalAlignment = Alignment.CenterVertically, ) { GlideImage( - imageModel = UrlUtil.autoHttps(item.cover), + imageModel = UrlUtil.autoHttps(item.cover) + "@672w_378h_1c_", modifier = Modifier .size(width = 120.dp, height = 80.dp) .clip(RoundedCornerShape(5.dp)) diff --git a/bilimiao-compose/src/main/java/cn/a10miaomiao/bilimiao/compose/pages/user/UserFollowPage.kt b/bilimiao-compose/src/main/java/cn/a10miaomiao/bilimiao/compose/pages/user/UserFollowPage.kt index 9dfef6dd..6a189050 100644 --- a/bilimiao-compose/src/main/java/cn/a10miaomiao/bilimiao/compose/pages/user/UserFollowPage.kt +++ b/bilimiao-compose/src/main/java/cn/a10miaomiao/bilimiao/compose/pages/user/UserFollowPage.kt @@ -309,7 +309,7 @@ fun UserFollowPage( verticalAlignment = Alignment.CenterVertically, ) { GlideImage( - imageModel = UrlUtil.autoHttps(item.face), + imageModel = UrlUtil.autoHttps(item.face) + "@200w_200h", modifier = Modifier .size(50.dp) .clip(CircleShape) diff --git a/bilimiao-download/src/main/java/cn/a10miaomiao/bilimiao/download/DownloadManager.kt b/bilimiao-download/src/main/java/cn/a10miaomiao/bilimiao/download/DownloadManager.kt index 68ec6ab8..b0ec5880 100644 --- a/bilimiao-download/src/main/java/cn/a10miaomiao/bilimiao/download/DownloadManager.kt +++ b/bilimiao-download/src/main/java/cn/a10miaomiao/bilimiao/download/DownloadManager.kt @@ -3,8 +3,10 @@ package cn.a10miaomiao.bilimiao.download import bilibili.app.view.v1.ViewOuterClass.DM import cn.a10miaomiao.bilimiao.download.entry.CurrentDownloadInfo import com.a10miaomiao.bilimiao.comm.utils.DebugMiao +import com.a10miaomiao.bilimiao.comm.utils.UrlUtil import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.* +import kotlinx.coroutines.launch import okhttp3.Call import okhttp3.OkHttpClient import okhttp3.Request @@ -26,20 +28,22 @@ class DownloadManager( .writeTimeout(120, TimeUnit.SECONDS) .build() - suspend fun start(file: File, downloadedLength: Long = 0) { - create(downloadInfo, file, downloadedLength).run { - throttleFirst(200) - }.catch { e -> - callback.onTaskError( - downloadInfo.copy(status = CurrentDownloadInfo.STATUS_FAIL_DOWNLOAD), - e, - ) - }.onCompletion { - callback.onTaskComplete( - downloadInfo.copy(status = CurrentDownloadInfo.STATUS_COMPLETED), - ) - }.collect { - callback.onTaskRunning(it) + fun start(file: File, downloadedLength: Long = 0) { + scope.launch { + create(downloadInfo, file, downloadedLength).run { + throttleFirst(200) + }.catch { e -> + downloadInfo.status = CurrentDownloadInfo.STATUS_FAIL_DOWNLOAD + callback.onTaskError(downloadInfo, e) + }.onCompletion { + if (downloadInfo.status == CurrentDownloadInfo.STATUS_COMPLETED) { + callback.onTaskComplete(downloadInfo) + } + }.collect { + if (it.status == CurrentDownloadInfo.STATUS_DOWNLOADING) { + callback.onTaskRunning(it) + } + } } } @@ -69,10 +73,12 @@ class DownloadManager( } var downloadLength = info.progress //已经下载好的长度 val request = Request.Builder() - .url(info.url.replace("http://", "https://")) - DebugMiao.log("addHeader", "RANGE", "bytes=$downloadLength-${info.size}") + .url(UrlUtil.autoHttps(info.url)) if (downloadLength > 0 && info.size != 0L) { - DebugMiao.log("addHeader2", "RANGE", "bytes=$downloadLength-${info.size}") + if (info.size == downloadLength) { + downloadInfo.status = CurrentDownloadInfo.STATUS_COMPLETED + return@flow + } request.addHeader("RANGE", "bytes=$downloadLength-${info.size}") } downloadLength += downloadedLength @@ -104,6 +110,8 @@ class DownloadManager( } if (downloadInfo.status == CurrentDownloadInfo.STATUS_PAUSE) { call.cancel() + } else { + downloadInfo.status = CurrentDownloadInfo.STATUS_COMPLETED } fileOutputStream.flush() } diff --git a/bilimiao-download/src/main/java/cn/a10miaomiao/bilimiao/download/DownloadNotify.kt b/bilimiao-download/src/main/java/cn/a10miaomiao/bilimiao/download/DownloadNotify.kt index d228f200..8a63e026 100644 --- a/bilimiao-download/src/main/java/cn/a10miaomiao/bilimiao/download/DownloadNotify.kt +++ b/bilimiao-download/src/main/java/cn/a10miaomiao/bilimiao/download/DownloadNotify.kt @@ -7,10 +7,11 @@ import android.os.Build import androidx.appcompat.app.AppCompatActivity import androidx.core.app.NotificationCompat import cn.a10miaomiao.bilimiao.download.entry.CurrentDownloadInfo +import okhttp3.internal.notify class DownloadNotify(val context: Context) { val ACTION_CMD = "cn.a10miaomiao.bilimiao.download.DownloadNotify" - val notificationID = 1010 + val notificationID = 10000 val channelId = "cn.a10miaomiao.bilimiao.download.DownloadNotify.control" val manager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager val builder = NotificationBuilder(context, channelId) @@ -24,8 +25,7 @@ class DownloadNotify(val context: Context) { fun notifyData(info: CurrentDownloadInfo) { // val builder = NotificationCompat.Builder(context, channelId) - if (builder.info?.id == info.id - && builder.info?.parentId == info.parentId) { + if (builder.taskId == info.taskId) { builder.setContentText(info.statusText) builder.setProgress(info.size.toInt(), info.progress.toInt(), false) } else { @@ -36,12 +36,34 @@ class DownloadNotify(val context: Context) { builder.priority = NotificationCompat.PRIORITY_DEFAULT builder.setOnlyAlertOnce(true) builder.setOngoing(true) - builder.info = info + builder.taskId = info.taskId } val notification = builder.build() manager.notify(notificationID, notification) } + fun showCompletedStatusNotify(info: CurrentDownloadInfo) { + manager.notify( + notificationID + info.taskId.toInt(), + NotificationCompat.Builder(context, channelId).apply { + setContentTitle(info.name) + setContentText("下载完成") + setSmallIcon(R.drawable.ic_baseline_file_download_done_24) + }.build() + ) + } + + fun showErrorStatusNotify(info: CurrentDownloadInfo) { + manager.notify( + notificationID + info.taskId.toInt(), + NotificationCompat.Builder(context, channelId).apply { + setContentTitle(info.name) + setContentText("下载出错") + setSmallIcon(R.drawable.ic_baseline_error_24) + }.build() + ) + } + fun cancel() { manager.cancel(notificationID) } @@ -50,7 +72,7 @@ class DownloadNotify(val context: Context) { context: Context, channelId: String, ) : NotificationCompat.Builder(context, channelId) { - var info: CurrentDownloadInfo? = null + var taskId = 0L } } \ No newline at end of file diff --git a/bilimiao-download/src/main/java/cn/a10miaomiao/bilimiao/download/DownloadService.kt b/bilimiao-download/src/main/java/cn/a10miaomiao/bilimiao/download/DownloadService.kt index 1a544a68..8748eb70 100644 --- a/bilimiao-download/src/main/java/cn/a10miaomiao/bilimiao/download/DownloadService.kt +++ b/bilimiao-download/src/main/java/cn/a10miaomiao/bilimiao/download/DownloadService.kt @@ -9,15 +9,14 @@ import cn.a10miaomiao.bilimiao.download.entry.BiliDownloadEntryInfo import cn.a10miaomiao.bilimiao.download.entry.BiliDownloadMediaFileInfo import cn.a10miaomiao.bilimiao.download.entry.CurrentDownloadInfo import com.a10miaomiao.bilimiao.comm.network.MiaoHttp +import com.a10miaomiao.bilimiao.comm.utils.CompressionTools import com.a10miaomiao.bilimiao.comm.utils.DebugMiao import com.google.gson.Gson import kotlinx.coroutines.* import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.MutableStateFlow -import java.io.File -import java.io.FileOutputStream -import java.io.IOException -import java.io.InputStream +import kotlinx.coroutines.flow.collect +import java.io.* import kotlin.coroutines.CoroutineContext class DownloadService: Service(), CoroutineScope, DownloadManager.Callback { @@ -45,26 +44,34 @@ class DownloadService: Service(), CoroutineScope, DownloadManager.Callback { private var job: Job = Job() override val coroutineContext: CoroutineContext get() = Dispatchers.IO + job - private var downloadNotify: DownloadNotify? = null + private val downloadNotify by lazy { DownloadNotify(this) } private var downloadManager: DownloadManager? = null private var audioDownloadManager: DownloadManager? = null + private var currentTaskId = 1L + private var idCounter = 1L + private var audioDownloadManagerCallback = object : DownloadManager.Callback { override fun onTaskRunning(info: CurrentDownloadInfo) { -// TODO("Not yet implemented") } override fun onTaskComplete(info: CurrentDownloadInfo) { -// TODO("Not yet implemented") + if (downloadManager?.downloadInfo?.status == CurrentDownloadInfo.STATUS_COMPLETED) { + downloadNotify.showCompletedStatusNotify(info) + completeDownload() + } } override fun onTaskError(info: CurrentDownloadInfo, error: Throwable) { -// TODO("Not yet implemented") + if (downloadManager?.downloadInfo?.status == CurrentDownloadInfo.STATUS_COMPLETED) { + + } } } var downloadList = mutableListOf() var downloadListVersion = MutableStateFlow(0) + var waitDownloadQueue = mutableListOf() val curDownload = MutableStateFlow(null) private val curBiliDownloadEntryAndPathInfo: BiliDownloadEntryAndPathInfo? get() = curDownload.value?.let { cur -> @@ -81,7 +88,15 @@ class DownloadService: Service(), CoroutineScope, DownloadManager.Callback { readDownloadList() channel.send(this@DownloadService) } - downloadNotify = DownloadNotify(this) + launch { + curDownload.collect { info -> + if (info == null) { + downloadNotify.cancel() + } else { + downloadNotify.notifyData(info) + } + } + } } override fun onDestroy() { @@ -120,6 +135,13 @@ class DownloadService: Service(), CoroutineScope, DownloadManager.Callback { } } + /** + * 是否处于等待下载队列中 + */ + fun isInWaitDownloadQueue(dirPath: String): Boolean { + return waitDownloadQueue.indexOfFirst { it.entryDirPath == dirPath } > 0 + } + /** * 创建任务 */ @@ -147,6 +169,8 @@ class DownloadService: Service(), CoroutineScope, DownloadManager.Callback { downloadListVersion.value++ if (curDownload.value == null) { startDownload(biliDownInfo) + } else { + waitDownloadQueue.add(biliDownInfo) } } @@ -157,10 +181,10 @@ class DownloadService: Service(), CoroutineScope, DownloadManager.Callback { if (biliDownInfo != null) { startDownload(biliDownInfo) } else { - val entryFile = File(entryDirPath, "entry.json") - if (entryFile.exists()) { - - } +// val entryFile = File(entryDirPath, "entry.json") +// if (entryFile.exists()) { +// +// } } } /** @@ -178,14 +202,17 @@ class DownloadService: Service(), CoroutineScope, DownloadManager.Callback { val entry = biliDownInfo.entry val parentId = entry.season_id ?: entry.avid?.toString() ?: "" val id = entry.page_data?.cid ?: entry.ep?.episode_id ?: 0L + currentTaskId = idCounter++ val currentDownloadInfo = CurrentDownloadInfo( + taskId = currentTaskId, parentId = parentId, id = id, name = entry.name, url = "", header = mapOf(), - size = 0, - length = 0 + size = entry.total_bytes, + progress = entry.downloaded_bytes, + length = entry.total_time_milli, ) if (!danmakuXMLFile.exists()) { try { @@ -196,8 +223,8 @@ class DownloadService: Service(), CoroutineScope, DownloadManager.Callback { val res = MiaoHttp.request { url = BiliPalyUrlHelper.danmakuXMLUrl(biliDownInfo.entry) }.awaitCall() - val inputStream = res.body!!.byteStream() - inputStream.inputStreamToFile(danmakuXMLFile) + val xmlBytes = CompressionTools.decompressXML(res.body!!.bytes()) + danmakuXMLFile.writeBytes(xmlBytes) } catch (e: Exception){ curDownload.value = currentDownloadInfo.copy( status = CurrentDownloadInfo.STATUS_FAIL_DANMAKU, @@ -213,6 +240,9 @@ class DownloadService: Service(), CoroutineScope, DownloadManager.Callback { currentDownloadInfo: CurrentDownloadInfo, biliDownInfo: BiliDownloadEntryAndPathInfo, ) { + if (currentDownloadInfo.taskId != currentTaskId) { + return + } val entry = biliDownInfo.entry val entryDir = File(biliDownInfo.entryDirPath) val videoDir = File(entryDir, entry.type_tag) @@ -230,6 +260,10 @@ class DownloadService: Service(), CoroutineScope, DownloadManager.Callback { val mediaJsonStr = Gson().toJson(mediaFileInfo) mediaJsonFile.writeText(mediaJsonStr) + if (currentDownloadInfo.taskId != currentTaskId) { + return + } + curMediaFile = mediaJsonFile curMediaFileInfo = mediaFileInfo when(mediaFileInfo) { @@ -251,11 +285,12 @@ class DownloadService: Service(), CoroutineScope, DownloadManager.Callback { size = entry.total_bytes, length = mediaFileInfo.duration ), this) - downloadManager?.start(File(videoDir, "video.m4s")) curDownload.value = currentDownloadInfo + downloadManager?.start(File(videoDir, "video.m4s")) val audio = mediaFileInfo.audio if (audio != null && audio.isNotEmpty()) { audioDownloadManager = DownloadManager(this, CurrentDownloadInfo( + taskId = currentDownloadInfo.taskId, parentId = currentDownloadInfo.parentId, id = currentDownloadInfo.id, name = entry.name, @@ -279,13 +314,15 @@ class DownloadService: Service(), CoroutineScope, DownloadManager.Callback { } } - fun cancelDownload() { - DebugMiao.log("cancelDownload", curDownload.value) - downloadManager?.cancel() - audioDownloadManager?.cancel() - downloadManager = null - audioDownloadManager = null - stopDownload() + fun cancelDownload(taskId: Long) { + if (taskId == currentTaskId) { + downloadManager?.cancel() + audioDownloadManager?.cancel() + downloadManager = null + audioDownloadManager = null + currentTaskId = 0L + stopDownload() + } } /** @@ -299,17 +336,18 @@ class DownloadService: Service(), CoroutineScope, DownloadManager.Callback { if (entryAndPathInfo != null) { entryAndPathInfo.entry.total_bytes = cur.size entryAndPathInfo.entry.downloaded_bytes = cur.progress - val entryJsonFile = File(entryAndPathInfo.entryDirPath, "entry.json") - val entryJsonStr = Gson().toJson(entryAndPathInfo.entry) - entryJsonFile.writeText(entryJsonStr) - downloadManager?.cancel()?.let { - curDownload.value = it - } + updateBiliDownloadEntryJson( + entryAndPathInfo.entryDirPath, + entryAndPathInfo.entry, + ) + downloadListVersion.value++ + downloadManager?.cancel() } } curDownload.value = null curMediaFile = null curMediaFileInfo = null + nextDownload() } /** @@ -326,7 +364,7 @@ class DownloadService: Service(), CoroutineScope, DownloadManager.Callback { // 如果为当前下载任务则先停止任务 val entryAndPathInfo = downloadList[index] if (curDownload.value?.id == entryAndPathInfo.entry.key) { - cancelDownload() + cancelDownload(currentTaskId) } } val downloadDir = File(pageDirPath) @@ -346,12 +384,33 @@ class DownloadService: Service(), CoroutineScope, DownloadManager.Callback { } } + /** + * 完成下载 + */ + private fun completeDownload() { + val (_, entryDirPath, entry) = curBiliDownloadEntryAndPathInfo ?: return + entry.downloaded_bytes = entry.total_bytes + entry.total_bytes = entry.total_bytes + entry.is_completed = true + entry.total_time_milli = (curDownload.value?.length ?: 0L) * 1000 + updateBiliDownloadEntryJson(entryDirPath, entry) + downloadListVersion.value++ + curDownload.value = null + curMediaFile = null + curMediaFileInfo = null + downloadManager = null + audioDownloadManager = null + nextDownload() + } + + /** + * 完成下载 + */ private fun nextDownload() { - downloadList.find { -// !it.entry.is_completed - it.entry.total_bytes == 0L - }?.let { - startDownload(it) + if (waitDownloadQueue.isNotEmpty()) { + val next = waitDownloadQueue[0] + waitDownloadQueue.removeAt(0) + startDownload(next) } } @@ -371,35 +430,48 @@ class DownloadService: Service(), CoroutineScope, DownloadManager.Callback { } } curDownload.value = info.copy() - downloadNotify?.notifyData(info) } override fun onTaskComplete(info: CurrentDownloadInfo) { - if (info.size != 0L && info.size == info.progress) { - val (_, entryDirPath, entry) = curBiliDownloadEntryAndPathInfo ?: return - entry.downloaded_bytes = info.progress - entry.total_bytes = info.size - entry.is_completed = true - val entryJsonFile = File(entryDirPath, "entry.json") - val entryJsonStr = Gson().toJson(entry) - entryJsonFile.writeText(entryJsonStr) -// downloadList.removeAt(index) - downloadListVersion.value++ - curDownload.value = null - curMediaFile = null - curMediaFileInfo = null - } else { - + if (info.size == 0L || info.size != info.progress) { + // TODO: 未知错误 + return + } + when (audioDownloadManager?.downloadInfo?.status) { + CurrentDownloadInfo.STATUS_DOWNLOADING -> { + // 等待音频下载完成 + curDownload.value = info.copy( + status = CurrentDownloadInfo.STATUS_AUDIO_DOWNLOADING + ) + } + CurrentDownloadInfo.STATUS_FAIL_DOWNLOAD -> { + // 重新下载音频 + curBiliDownloadEntryAndPathInfo?.let(::startDownload) + } + CurrentDownloadInfo.STATUS_COMPLETED, null -> { + // 完成下载 + downloadNotify.showCompletedStatusNotify(info) + completeDownload() + } } - // TODO: 视频下载完成,但音频未完成的情况 - downloadNotify?.notifyData(info) - nextDownload() } override fun onTaskError(info: CurrentDownloadInfo, error: Throwable) { - DebugMiao.log(TAG, "onTaskError", info) error.printStackTrace() - downloadNotify?.notifyData(info) + curDownload.value = info.copy( + status = CurrentDownloadInfo.STATUS_FAIL_DOWNLOAD + ) + downloadNotify.showErrorStatusNotify(info) + } + + private fun updateBiliDownloadEntryJson( + entryDirPath: String, + entry: BiliDownloadEntryInfo, + ) { + // 保存视频信息 + val entryJsonFile = File(entryDirPath, "entry.json") + val entryJsonStr = Gson().toJson(entry) + entryJsonFile.writeText(entryJsonStr) } private fun getDownloadPath(): String { @@ -435,15 +507,4 @@ class DownloadService: Service(), CoroutineScope, DownloadManager.Callback { return pageDir } - @Throws(IOException::class) - private fun InputStream.inputStreamToFile(file: File) { - val outputStream = FileOutputStream(file) - var read = -1 - outputStream.use { - while (read().also { read = it } != -1) { - it.write(read) - } - } - } - } \ No newline at end of file diff --git a/bilimiao-download/src/main/java/cn/a10miaomiao/bilimiao/download/LocalPlayerSource.kt b/bilimiao-download/src/main/java/cn/a10miaomiao/bilimiao/download/LocalPlayerSource.kt index 6fe7e105..14fe40b9 100644 --- a/bilimiao-download/src/main/java/cn/a10miaomiao/bilimiao/download/LocalPlayerSource.kt +++ b/bilimiao-download/src/main/java/cn/a10miaomiao/bilimiao/download/LocalPlayerSource.kt @@ -69,7 +69,7 @@ class LocalPlayerSource( return emptyPlayerSourceInfo } } else { -// val mediaInfo = Gson().fromJson(videoIndexJson, BiliDownloadMediaFileInfo.Type2::class.java) + val mediaInfo = Gson().fromJson(videoIndexJson, BiliDownloadMediaFileInfo.Type2::class.java) val videoFile = File(videoDir, "video.m4s") val audioFile = File(videoDir, "audio.m4s") val url = Uri.fromFile(videoFile).toString() @@ -77,6 +77,8 @@ class LocalPlayerSource( val audioUrl = Uri.fromFile(audioFile).toString() val mergingUrl = "[local-merging]\n$url\n$audioUrl" return PlayerSourceInfo().also { + it.height = mediaInfo.video[0].height + it.width = mediaInfo.video[0].width it.url = mergingUrl it.quality = 0 it.acceptList = acceptList @@ -84,6 +86,8 @@ class LocalPlayerSource( } } else { return PlayerSourceInfo().also { + it.height = mediaInfo.video[0].height + it.width = mediaInfo.video[0].width it.url = url it.quality = 0 it.acceptList = acceptList diff --git a/bilimiao-download/src/main/java/cn/a10miaomiao/bilimiao/download/entry/BiliDownloadEntryInfo.kt b/bilimiao-download/src/main/java/cn/a10miaomiao/bilimiao/download/entry/BiliDownloadEntryInfo.kt index d32add88..88b54988 100644 --- a/bilimiao-download/src/main/java/cn/a10miaomiao/bilimiao/download/entry/BiliDownloadEntryInfo.kt +++ b/bilimiao-download/src/main/java/cn/a10miaomiao/bilimiao/download/entry/BiliDownloadEntryInfo.kt @@ -10,8 +10,9 @@ data class BiliDownloadEntryInfo( val type_tag: String, val cover: String, val prefered_video_quality: Int, + val quality_pithy_description: String, val guessed_total_bytes: Int, - val total_time_milli: Long, + var total_time_milli: Long, val danmaku_count: Int, val time_update_stamp: Long, val time_create_stamp: Long, diff --git a/bilimiao-download/src/main/java/cn/a10miaomiao/bilimiao/download/entry/CurrentDownloadInfo.kt b/bilimiao-download/src/main/java/cn/a10miaomiao/bilimiao/download/entry/CurrentDownloadInfo.kt index 9a21b92e..5c943e92 100644 --- a/bilimiao-download/src/main/java/cn/a10miaomiao/bilimiao/download/entry/CurrentDownloadInfo.kt +++ b/bilimiao-download/src/main/java/cn/a10miaomiao/bilimiao/download/entry/CurrentDownloadInfo.kt @@ -1,8 +1,10 @@ package cn.a10miaomiao.bilimiao.download.entry +import com.a10miaomiao.bilimiao.comm.utils.DebugMiao import java.text.DecimalFormat data class CurrentDownloadInfo( + val taskId: Long, val parentId: String, val id: Long, val name: String, @@ -21,6 +23,9 @@ data class CurrentDownloadInfo( val fnum = DecimalFormat("##0.00") "正在下载 ${fnum.format(progress * 1.0 / size * 100.0)}%" } + STATUS_AUDIO_DOWNLOADING -> { + "正在下载音频" + } STATUS_COMPLETED -> "下载完成" STATUS_PAUSE -> "暂停中" STATUS_GET_DANMAKU -> "获取弹幕" @@ -33,6 +38,7 @@ data class CurrentDownloadInfo( companion object { const val STATUS_DOWNLOADING = 100 + const val STATUS_AUDIO_DOWNLOADING = 101 const val STATUS_COMPLETED = 200 const val STATUS_PAUSE = 201 const val STATUS_GET_DANMAKU = 102 diff --git a/bilimiao-download/src/main/res/drawable/ic_baseline_error_24.xml b/bilimiao-download/src/main/res/drawable/ic_baseline_error_24.xml new file mode 100644 index 00000000..391e8b4c --- /dev/null +++ b/bilimiao-download/src/main/res/drawable/ic_baseline_error_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/bilimiao-download/src/main/res/drawable/ic_baseline_file_download_done_24.xml b/bilimiao-download/src/main/res/drawable/ic_baseline_file_download_done_24.xml new file mode 100644 index 00000000..3341ed20 --- /dev/null +++ b/bilimiao-download/src/main/res/drawable/ic_baseline_file_download_done_24.xml @@ -0,0 +1,5 @@ + + +