Compare commits
2 Commits
5b770a965d
...
8184ab211c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8184ab211c | ||
|
|
4e346a83ee |
@@ -4,6 +4,7 @@ import android.content.Context
|
|||||||
import com.acitelight.aether.model.BookMark
|
import com.acitelight.aether.model.BookMark
|
||||||
import com.acitelight.aether.model.Comic
|
import com.acitelight.aether.model.Comic
|
||||||
import com.acitelight.aether.model.Video
|
import com.acitelight.aether.model.Video
|
||||||
|
import com.acitelight.aether.model.VideoDownloadItemState
|
||||||
import com.tonyodev.fetch2.Status
|
import com.tonyodev.fetch2.Status
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
@@ -44,15 +45,34 @@ class MediaManager @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun queryVideo(klass: String, id: String, model: VideoDownloadItemState): Video?
|
||||||
|
{
|
||||||
|
if(model.status == Status.COMPLETED)
|
||||||
|
{
|
||||||
|
val jsonString = File(
|
||||||
|
context.getExternalFilesDir(null),
|
||||||
|
"videos/$klass/$id/summary.json"
|
||||||
|
).readText()
|
||||||
|
return Json.decodeFromString<Video>(jsonString).toLocal(context.getExternalFilesDir(null)?.path!!)
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
val j = ApiClient.api!!.queryVideo(klass, id, token)
|
||||||
|
return Video(klass = klass, id = id, token=token, isLocal = false, localBase = "", video = j)
|
||||||
|
}catch (_: Exception)
|
||||||
|
{
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun queryVideo(klass: String, id: String): Video?
|
suspend fun queryVideo(klass: String, id: String): Video?
|
||||||
{
|
{
|
||||||
val downloaded = fetchManager.getAllDownloadsAsync().filter {
|
val downloaded = fetchManager.getAllDownloadsAsync().filter {
|
||||||
it.status == Status.COMPLETED &&
|
|
||||||
it.extras.getString("id", "") == id &&
|
it.extras.getString("id", "") == id &&
|
||||||
it.extras.getString("class", "") == klass
|
it.extras.getString("class", "") == klass
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!downloaded.isEmpty())
|
if(downloaded.all{ it.status == Status.COMPLETED })
|
||||||
{
|
{
|
||||||
val jsonString = File(
|
val jsonString = File(
|
||||||
context.getExternalFilesDir(null),
|
context.getExternalFilesDir(null),
|
||||||
@@ -72,16 +92,16 @@ class MediaManager @Inject constructor(
|
|||||||
|
|
||||||
suspend fun queryVideoBulk(klass: String, id: List<String>): List<Video>? {
|
suspend fun queryVideoBulk(klass: String, id: List<String>): List<Video>? {
|
||||||
return try {
|
return try {
|
||||||
val completedDownloads = fetchManager.getAllDownloadsAsync()
|
val downloads = fetchManager.getAllDownloadsAsync()
|
||||||
.filter { it.status == Status.COMPLETED }
|
|
||||||
val localIds = mutableSetOf<String>()
|
val localIds = mutableSetOf<String>()
|
||||||
val remoteIds = mutableListOf<String>()
|
val remoteIds = mutableListOf<String>()
|
||||||
|
|
||||||
for (videoId in id) {
|
for (videoId in id) {
|
||||||
if (completedDownloads.any {
|
if (downloads.filter {
|
||||||
it.extras.getString("id", "") == videoId &&
|
it.extras.getString("id", "") == videoId &&
|
||||||
it.extras.getString("class", "") == klass
|
it.extras.getString("class", "") == klass
|
||||||
}) {
|
}.all{ it.status == Status.COMPLETED} ) {
|
||||||
localIds.add(videoId)
|
localIds.add(videoId)
|
||||||
} else {
|
} else {
|
||||||
remoteIds.add(videoId)
|
remoteIds.add(videoId)
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ fun HomeScreen(
|
|||||||
{
|
{
|
||||||
updateRelate(homeScreenViewModel.recentManager.recentVideo, i)
|
updateRelate(homeScreenViewModel.recentManager.recentVideo, i)
|
||||||
|
|
||||||
val playList = mutableListOf("${i.klass}/${i.id}")
|
val playList = mutableListOf<String>()
|
||||||
val fv = homeScreenViewModel.videoLibrary.classesMap.map { it.value }.flatten()
|
val fv = homeScreenViewModel.videoLibrary.classesMap.map { it.value }.flatten()
|
||||||
|
|
||||||
val group = fv.filter { it.klass == i.klass && it.video.group == i.video.group }
|
val group = fv.filter { it.klass == i.klass && it.video.group == i.video.group }
|
||||||
@@ -90,7 +90,7 @@ fun HomeScreen(
|
|||||||
playList.add("${i.klass}/${i.id}")
|
playList.add("${i.klass}/${i.id}")
|
||||||
}
|
}
|
||||||
|
|
||||||
val route = "video_player_route/${playList.joinToString(",").toHex()}"
|
val route = "video_player_route/${(playList.joinToString(",") + "|${i.id}").toHex()}"
|
||||||
navController.navigate(route)
|
navController.navigate(route)
|
||||||
}, homeScreenViewModel.imageLoader!!)
|
}, homeScreenViewModel.imageLoader!!)
|
||||||
HorizontalDivider(Modifier.padding(vertical = 8.dp).alpha(0.4f), 1.dp, DividerDefaults.color)
|
HorizontalDivider(Modifier.padding(vertical = 8.dp).alpha(0.4f), 1.dp, DividerDefaults.color)
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ import androidx.compose.foundation.layout.width
|
|||||||
import androidx.compose.foundation.lazy.LazyRow
|
import androidx.compose.foundation.lazy.LazyRow
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.material3.Card
|
import androidx.compose.material3.Card
|
||||||
|
import androidx.compose.material3.CardDefaults
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
@@ -28,7 +30,9 @@ import kotlinx.coroutines.launch
|
|||||||
@Composable
|
@Composable
|
||||||
fun PlaylistPanel(modifier: Modifier, videoPlayerViewModel: VideoPlayerViewModel)
|
fun PlaylistPanel(modifier: Modifier, videoPlayerViewModel: VideoPlayerViewModel)
|
||||||
{
|
{
|
||||||
|
val colorScheme = MaterialTheme.colorScheme
|
||||||
val name by videoPlayerViewModel.currentName
|
val name by videoPlayerViewModel.currentName
|
||||||
|
val id by videoPlayerViewModel.currentId
|
||||||
|
|
||||||
LazyRow(
|
LazyRow(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
@@ -48,7 +52,13 @@ fun PlaylistPanel(modifier: Modifier, videoPlayerViewModel: VideoPlayerViewModel
|
|||||||
videoPlayerViewModel.viewModelScope.launch {
|
videoPlayerViewModel.viewModelScope.launch {
|
||||||
videoPlayerViewModel.startPlay(it)
|
videoPlayerViewModel.startPlay(it)
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
colors =
|
||||||
|
if (it.id == id)
|
||||||
|
CardDefaults.cardColors(containerColor = colorScheme.primary)
|
||||||
|
else
|
||||||
|
CardDefaults.cardColors()
|
||||||
|
|
||||||
) {
|
) {
|
||||||
Box(Modifier.padding(8.dp).fillMaxSize())
|
Box(Modifier.padding(8.dp).fillMaxSize())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ import kotlinx.coroutines.launch
|
|||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import kotlin.collections.sortedWith
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun TransmissionScreen(
|
fun TransmissionScreen(
|
||||||
@@ -120,9 +121,12 @@ private fun VideoDownloadCard(
|
|||||||
{
|
{
|
||||||
val downloaded = viewModel.fetchManager.getAllDownloadsAsync().filter {
|
val downloaded = viewModel.fetchManager.getAllDownloadsAsync().filter {
|
||||||
it.status == Status.COMPLETED && it.extras.getString(
|
it.status == Status.COMPLETED && it.extras.getString(
|
||||||
"isComic",
|
"class",
|
||||||
""
|
""
|
||||||
) != "true"
|
) != "comic" && it.extras.getString(
|
||||||
|
"type",
|
||||||
|
""
|
||||||
|
) == "main"
|
||||||
}
|
}
|
||||||
|
|
||||||
val jsonQuery = downloaded.map {
|
val jsonQuery = downloaded.map {
|
||||||
@@ -146,18 +150,18 @@ private fun VideoDownloadCard(
|
|||||||
jsonQuery.first { it.id == model.vid && it.klass == model.klass }
|
jsonQuery.first { it.id == model.vid && it.klass == model.klass }
|
||||||
)
|
)
|
||||||
|
|
||||||
val playList = mutableListOf("${model.klass}/${model.vid}")
|
val playList = mutableListOf<String>()
|
||||||
val fv = viewModel.videoLibrary.classesMap.map { it.value }.flatten()
|
val fv = viewModel.videoLibrary.classesMap.map { it.value }.flatten()
|
||||||
val video = fv.firstOrNull { it.klass == model.klass && it.id == model.vid }
|
val video = fv.firstOrNull { it.klass == model.klass && it.id == model.vid }
|
||||||
|
|
||||||
if (video != null) {
|
if (video != null) {
|
||||||
val group = fv.filter { it.klass == video.klass && it.video.group == video.video.group }
|
val group = fv.filter { it.klass == video.klass && it.video.group == video.video.group }
|
||||||
for (i in group) {
|
for (i in group.sortedWith(compareBy(naturalOrder()) { it.video.name })) {
|
||||||
playList.add("${i.klass}/${i.id}")
|
playList.add("${i.klass}/${i.id}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val route = "video_player_route/${playList.joinToString(",").toHex()}"
|
val route = "video_player_route/${(playList.joinToString(",") + "|${model.vid}").toHex()}"
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
navigator.navigate(route)
|
navigator.navigate(route)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ import androidx.compose.ui.unit.dp
|
|||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import androidx.navigation.NavHostController
|
import androidx.navigation.NavHostController
|
||||||
import com.acitelight.aether.Global
|
import com.acitelight.aether.Global
|
||||||
|
import com.acitelight.aether.Global.updateRelate
|
||||||
import com.acitelight.aether.ToggleFullScreen
|
import com.acitelight.aether.ToggleFullScreen
|
||||||
import com.acitelight.aether.viewModel.VideoPlayerViewModel
|
import com.acitelight.aether.viewModel.VideoPlayerViewModel
|
||||||
|
|
||||||
@@ -108,9 +109,11 @@ fun VideoPlayerPortal(
|
|||||||
val duration by videoPlayerViewModel.currentDuration
|
val duration by videoPlayerViewModel.currentDuration
|
||||||
|
|
||||||
ToggleFullScreen(false)
|
ToggleFullScreen(false)
|
||||||
Column(Modifier
|
Column(
|
||||||
|
Modifier
|
||||||
.nestedScroll(nestedScrollConnection)
|
.nestedScroll(nestedScrollConnection)
|
||||||
.fillMaxHeight())
|
.fillMaxHeight()
|
||||||
|
)
|
||||||
{
|
{
|
||||||
Box {
|
Box {
|
||||||
PortalCorePlayer(
|
PortalCorePlayer(
|
||||||
@@ -194,13 +197,15 @@ fun VideoPlayerPortal(
|
|||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Bold,
|
||||||
)
|
)
|
||||||
|
|
||||||
Row(Modifier
|
Row(
|
||||||
|
Modifier
|
||||||
.align(Alignment.Start)
|
.align(Alignment.Start)
|
||||||
.padding(horizontal = 4.dp)
|
.padding(horizontal = 4.dp)
|
||||||
.alpha(0.5f)) {
|
.alpha(0.5f)
|
||||||
|
) {
|
||||||
Text(
|
Text(
|
||||||
modifier = Modifier.padding(horizontal = 8.dp),
|
modifier = Modifier.padding(horizontal = 8.dp),
|
||||||
text = klass,
|
text = "$klass.$id",
|
||||||
fontSize = 14.sp,
|
fontSize = 14.sp,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Bold,
|
||||||
@@ -217,12 +222,18 @@ fun VideoPlayerPortal(
|
|||||||
|
|
||||||
HorizontalDivider(Modifier.padding(vertical = 8.dp), 1.dp, DividerDefaults.color)
|
HorizontalDivider(Modifier.padding(vertical = 8.dp), 1.dp, DividerDefaults.color)
|
||||||
|
|
||||||
|
if (videoPlayerViewModel.videos.size > 1) {
|
||||||
PlaylistPanel(
|
PlaylistPanel(
|
||||||
Modifier,
|
Modifier,
|
||||||
videoPlayerViewModel = videoPlayerViewModel
|
videoPlayerViewModel = videoPlayerViewModel
|
||||||
)
|
)
|
||||||
|
|
||||||
HorizontalDivider(Modifier.padding(vertical = 8.dp), 1.dp, DividerDefaults.color)
|
HorizontalDivider(
|
||||||
|
Modifier.padding(vertical = 8.dp),
|
||||||
|
1.dp,
|
||||||
|
DividerDefaults.color
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
HorizontalGallery(videoPlayerViewModel)
|
HorizontalGallery(videoPlayerViewModel)
|
||||||
HorizontalDivider(Modifier.padding(vertical = 8.dp), 1.dp, DividerDefaults.color)
|
HorizontalDivider(Modifier.padding(vertical = 8.dp), 1.dp, DividerDefaults.color)
|
||||||
@@ -237,7 +248,16 @@ fun VideoPlayerPortal(
|
|||||||
{
|
{
|
||||||
videoPlayerViewModel.isPlaying = false
|
videoPlayerViewModel.isPlaying = false
|
||||||
videoPlayerViewModel.player?.pause()
|
videoPlayerViewModel.player?.pause()
|
||||||
val route = "video_player_route/${"${i.klass}/${i.id}".toHex()}"
|
|
||||||
|
val playList = mutableListOf<String>()
|
||||||
|
val fv = videoPlayerViewModel.videoLibrary.classesMap.map { it.value }.flatten()
|
||||||
|
|
||||||
|
val group = fv.filter { it.klass == i.klass && it.video.group == i.video.group }
|
||||||
|
for (i in group) {
|
||||||
|
playList.add("${i.klass}/${i.id}")
|
||||||
|
}
|
||||||
|
|
||||||
|
val route = "video_player_route/${playList.joinToString(",").toHex()}"
|
||||||
navController.navigate(route)
|
navController.navigate(route)
|
||||||
}, videoPlayerViewModel.imageLoader!!
|
}, videoPlayerViewModel.imageLoader!!
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import com.acitelight.aether.model.Video
|
|||||||
import com.acitelight.aether.model.VideoDownloadItemState
|
import com.acitelight.aether.model.VideoDownloadItemState
|
||||||
import com.acitelight.aether.service.ApiClient.createOkHttp
|
import com.acitelight.aether.service.ApiClient.createOkHttp
|
||||||
import com.acitelight.aether.service.FetchManager
|
import com.acitelight.aether.service.FetchManager
|
||||||
|
import com.acitelight.aether.service.MediaManager
|
||||||
import com.acitelight.aether.service.VideoLibrary
|
import com.acitelight.aether.service.VideoLibrary
|
||||||
import com.tonyodev.fetch2.Download
|
import com.tonyodev.fetch2.Download
|
||||||
import com.tonyodev.fetch2.FetchListener
|
import com.tonyodev.fetch2.FetchListener
|
||||||
@@ -27,6 +28,7 @@ class TransmissionScreenViewModel @Inject constructor(
|
|||||||
val fetchManager: FetchManager,
|
val fetchManager: FetchManager,
|
||||||
@ApplicationContext val context: Context,
|
@ApplicationContext val context: Context,
|
||||||
val videoLibrary: VideoLibrary,
|
val videoLibrary: VideoLibrary,
|
||||||
|
val mediaManager: MediaManager,
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
var imageLoader: ImageLoader? = null
|
var imageLoader: ImageLoader? = null
|
||||||
val downloads: SnapshotStateList<VideoDownloadItemState> = mutableStateListOf()
|
val downloads: SnapshotStateList<VideoDownloadItemState> = mutableStateListOf()
|
||||||
@@ -34,8 +36,7 @@ class TransmissionScreenViewModel @Inject constructor(
|
|||||||
// map id -> state object reference (no index bookkeeping)
|
// map id -> state object reference (no index bookkeeping)
|
||||||
private val idToState: MutableMap<Int, VideoDownloadItemState> = mutableMapOf()
|
private val idToState: MutableMap<Int, VideoDownloadItemState> = mutableMapOf()
|
||||||
|
|
||||||
fun modelToVideo(model: VideoDownloadItemState): Video?
|
fun modelToVideo(model: VideoDownloadItemState): Video? {
|
||||||
{
|
|
||||||
val fv = videoLibrary.classesMap.map { it.value }.flatten()
|
val fv = videoLibrary.classesMap.map { it.value }.flatten()
|
||||||
return fv.firstOrNull { it.klass == model.klass && it.id == model.vid }
|
return fv.firstOrNull { it.klass == model.klass && it.id == model.vid }
|
||||||
}
|
}
|
||||||
@@ -54,9 +55,7 @@ class TransmissionScreenViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onProgress(
|
override fun onProgress(
|
||||||
download: Download,
|
download: Download, etaInMilliSeconds: Long, downloadedBytesPerSecond: Long
|
||||||
etaInMilliSeconds: Long,
|
|
||||||
downloadedBytesPerSecond: Long
|
|
||||||
) {
|
) {
|
||||||
handleUpsert(download)
|
handleUpsert(download)
|
||||||
}
|
}
|
||||||
@@ -73,12 +72,21 @@ class TransmissionScreenViewModel @Inject constructor(
|
|||||||
handleUpsert(download)
|
handleUpsert(download)
|
||||||
|
|
||||||
if (download.extras.getString("type", "") == "main") {
|
if (download.extras.getString("type", "") == "main") {
|
||||||
val ii = videoLibrary.classesMap[download.extras.getString("class", "")]
|
val ii = videoLibrary.classesMap[download.extras.getString(
|
||||||
?.indexOfFirst { it.id == download.extras.getString("id", "") }!!
|
"class",
|
||||||
|
""
|
||||||
|
)]?.indexOfFirst { it.id == download.extras.getString("id", "") }
|
||||||
|
|
||||||
val newi = videoLibrary.classesMap[download.extras.getString("class", "")]!![ii]
|
if (ii != null) {
|
||||||
videoLibrary.classesMap[download.extras.getString("class", "")]!![ii] =
|
val newi =
|
||||||
newi.toLocal(context.getExternalFilesDir(null)!!.path)
|
videoLibrary.classesMap[download.extras.getString("class", "")]?.get(ii)
|
||||||
|
if (newi != null) videoLibrary.classesMap[download.extras.getString(
|
||||||
|
"class",
|
||||||
|
""
|
||||||
|
)]?.set(
|
||||||
|
ii, newi.toLocal(context.getExternalFilesDir(null)!!.path)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,25 +103,19 @@ class TransmissionScreenViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onDownloadBlockUpdated(
|
override fun onDownloadBlockUpdated(
|
||||||
download: Download,
|
download: Download, downloadBlock: DownloadBlock, totalBlocks: Int
|
||||||
downloadBlock: DownloadBlock,
|
|
||||||
totalBlocks: Int
|
|
||||||
) {
|
) {
|
||||||
handleUpsert(download)
|
handleUpsert(download)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStarted(
|
override fun onStarted(
|
||||||
download: Download,
|
download: Download, downloadBlocks: List<DownloadBlock>, totalBlocks: Int
|
||||||
downloadBlocks: List<DownloadBlock>,
|
|
||||||
totalBlocks: Int
|
|
||||||
) {
|
) {
|
||||||
handleUpsert(download)
|
handleUpsert(download)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onError(
|
override fun onError(
|
||||||
download: Download,
|
download: Download, error: com.tonyodev.fetch2.Error, throwable: Throwable?
|
||||||
error: com.tonyodev.fetch2.Error,
|
|
||||||
throwable: Throwable?
|
|
||||||
) {
|
) {
|
||||||
handleUpsert(download)
|
handleUpsert(download)
|
||||||
}
|
}
|
||||||
@@ -123,6 +125,23 @@ class TransmissionScreenViewModel @Inject constructor(
|
|||||||
viewModelScope.launch(Dispatchers.Main) {
|
viewModelScope.launch(Dispatchers.Main) {
|
||||||
upsertOnMain(download)
|
upsertOnMain(download)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val state = downloadToState(download)
|
||||||
|
|
||||||
|
if (videoLibrary.classes.contains(state.klass)) videoLibrary.classes.add(state.klass)
|
||||||
|
|
||||||
|
if (!videoLibrary.classesMap.containsKey(state.klass)) videoLibrary.classesMap[state.klass] =
|
||||||
|
mutableStateListOf()
|
||||||
|
|
||||||
|
if (videoLibrary.classesMap[state.klass]?.any { it.id == state.vid } != true) {
|
||||||
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
val v = mediaManager.queryVideo(state.klass, state.vid, state)
|
||||||
|
if (v != null) {
|
||||||
|
videoLibrary.classesMap[state.klass]?.add(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleRemove(id: Int) {
|
private fun handleRemove(id: Int) {
|
||||||
@@ -198,22 +217,31 @@ class TransmissionScreenViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
imageLoader = ImageLoader.Builder(context)
|
imageLoader = ImageLoader.Builder(context).components {
|
||||||
.components {
|
|
||||||
add(OkHttpNetworkFetcherFactory(createOkHttp()))
|
add(OkHttpNetworkFetcherFactory(createOkHttp()))
|
||||||
}
|
}.build()
|
||||||
.build()
|
|
||||||
|
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
fetchManager.setListener(fetchListener)
|
fetchManager.setListener(fetchListener)
|
||||||
withContext(Dispatchers.Main) {
|
val downloaded = fetchManager.getAllDownloadsAsync()
|
||||||
fetchManager.getAllDownloads { list ->
|
|
||||||
downloads.clear()
|
downloads.clear()
|
||||||
idToState.clear()
|
idToState.clear()
|
||||||
list.sortedBy { it.extras.getString("name", "") }.forEach { d ->
|
downloaded.sortedWith(compareBy(naturalOrder()) { it.extras.getString("name", "") })
|
||||||
|
.forEach { d ->
|
||||||
val s = downloadToState(d)
|
val s = downloadToState(d)
|
||||||
downloads.add(s)
|
downloads.add(s)
|
||||||
idToState[s.id] = s
|
idToState[s.id] = s
|
||||||
|
|
||||||
|
if (videoLibrary.classes.contains(s.klass)) videoLibrary.classes.add(s.klass)
|
||||||
|
|
||||||
|
if (!videoLibrary.classesMap.containsKey(s.klass)) videoLibrary.classesMap[s.klass] =
|
||||||
|
mutableStateListOf()
|
||||||
|
|
||||||
|
if (videoLibrary.classesMap[s.klass]?.any { it.id == s.vid } != true) {
|
||||||
|
val v = mediaManager.queryVideo(s.klass, s.vid, s)
|
||||||
|
if (v != null) {
|
||||||
|
videoLibrary.classesMap[s.klass]?.add(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ import androidx.media3.datasource.DefaultDataSource
|
|||||||
import androidx.media3.exoplayer.trackselection.DefaultTrackSelector
|
import androidx.media3.exoplayer.trackselection.DefaultTrackSelector
|
||||||
import com.acitelight.aether.Global
|
import com.acitelight.aether.Global
|
||||||
import com.acitelight.aether.model.KeyImage
|
import com.acitelight.aether.model.KeyImage
|
||||||
|
import com.acitelight.aether.service.VideoLibrary
|
||||||
import kotlinx.coroutines.flow.filter
|
import kotlinx.coroutines.flow.filter
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
|
|
||||||
@@ -56,7 +57,8 @@ import kotlinx.coroutines.flow.first
|
|||||||
class VideoPlayerViewModel @Inject constructor(
|
class VideoPlayerViewModel @Inject constructor(
|
||||||
@ApplicationContext private val context: Context,
|
@ApplicationContext private val context: Context,
|
||||||
val mediaManager: MediaManager,
|
val mediaManager: MediaManager,
|
||||||
val recentManager: RecentManager
|
val recentManager: RecentManager,
|
||||||
|
val videoLibrary: VideoLibrary,
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
var tabIndex by mutableIntStateOf(0)
|
var tabIndex by mutableIntStateOf(0)
|
||||||
var isPlaying by mutableStateOf(true)
|
var isPlaying by mutableStateOf(true)
|
||||||
@@ -100,7 +102,16 @@ class VideoPlayerViewModel @Inject constructor(
|
|||||||
return
|
return
|
||||||
_init = true
|
_init = true
|
||||||
|
|
||||||
val vs = videoId.hexToString().split(",").map { it.split("/") }.toMutableList()
|
val oId = videoId.hexToString()
|
||||||
|
var spec = "-1"
|
||||||
|
var vs = mutableListOf<List<String>>()
|
||||||
|
|
||||||
|
if(oId.contains("|"))
|
||||||
|
{
|
||||||
|
vs = oId.split("|")[0].split(",").map { it.split("/") }.toMutableList()
|
||||||
|
spec = oId.split("|")[1]
|
||||||
|
}
|
||||||
|
|
||||||
imageLoader = ImageLoader.Builder(context)
|
imageLoader = ImageLoader.Builder(context)
|
||||||
.components {
|
.components {
|
||||||
add(OkHttpNetworkFetcherFactory(createOkHttp()))
|
add(OkHttpNetworkFetcherFactory(createOkHttp()))
|
||||||
@@ -114,7 +125,9 @@ class VideoPlayerViewModel @Inject constructor(
|
|||||||
videos = mediaManager.queryVideoBulk(vs.first()[0], vs.map { it[1] })!!
|
videos = mediaManager.queryVideoBulk(vs.first()[0], vs.map { it[1] })!!
|
||||||
|
|
||||||
startPlay(
|
startPlay(
|
||||||
if (ix != null)
|
if(spec != "-1")
|
||||||
|
videos.first { it.id == spec}
|
||||||
|
else if (ix != null)
|
||||||
videos.first { it.id == ix.id }
|
videos.first { it.id == ix.id }
|
||||||
else videos.first()
|
else videos.first()
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -54,13 +54,16 @@ class VideoScreenViewModel @Inject constructor(
|
|||||||
|
|
||||||
if (Global.loggedIn) {
|
if (Global.loggedIn) {
|
||||||
videoLibrary.classes.addAll(mediaManager.listVideoKlasses())
|
videoLibrary.classes.addAll(mediaManager.listVideoKlasses())
|
||||||
|
videoLibrary.classes.distinct()
|
||||||
|
|
||||||
if(videoLibrary.classes.isEmpty())
|
if(videoLibrary.classes.isEmpty())
|
||||||
return
|
return
|
||||||
|
|
||||||
var i = 0
|
var i = 0
|
||||||
for (it in videoLibrary.classes) {
|
for (it in videoLibrary.classes) {
|
||||||
videoLibrary.updatingMap[i++] = false
|
videoLibrary.updatingMap[i++] = false
|
||||||
videoLibrary.classesMap[it] = mutableStateListOf<Video>()
|
if(!videoLibrary.classesMap.containsKey(it))
|
||||||
|
videoLibrary.classesMap[it] = mutableStateListOf()
|
||||||
}
|
}
|
||||||
videoLibrary.updatingMap[0] = true
|
videoLibrary.updatingMap[0] = true
|
||||||
val vl =
|
val vl =
|
||||||
@@ -69,6 +72,7 @@ class VideoScreenViewModel @Inject constructor(
|
|||||||
if (vl != null) {
|
if (vl != null) {
|
||||||
val r = vl.sortedWith(compareBy(naturalOrder()) { it.video.name })
|
val r = vl.sortedWith(compareBy(naturalOrder()) { it.video.name })
|
||||||
videoLibrary.classesMap[videoLibrary.classes[0]]?.addAll(r)
|
videoLibrary.classesMap[videoLibrary.classes[0]]?.addAll(r)
|
||||||
|
videoLibrary.classesMap[videoLibrary.classes[0]]?.distinctBy { it.id }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -77,7 +81,7 @@ class VideoScreenViewModel @Inject constructor(
|
|||||||
videoLibrary.classesMap["Offline"] = mutableStateListOf<Video>()
|
videoLibrary.classesMap["Offline"] = mutableStateListOf<Video>()
|
||||||
|
|
||||||
val downloaded = fetchManager.getAllDownloadsAsync().filter {
|
val downloaded = fetchManager.getAllDownloadsAsync().filter {
|
||||||
it.status == Status.COMPLETED && it.extras.getString("isComic", "") != "true"
|
it.status == Status.COMPLETED && it.extras.getString("class", "") != "comic"
|
||||||
}
|
}
|
||||||
|
|
||||||
val jsonQuery = downloaded.map{ File(
|
val jsonQuery = downloaded.map{ File(
|
||||||
@@ -107,6 +111,7 @@ class VideoScreenViewModel @Inject constructor(
|
|||||||
if (vl != null) {
|
if (vl != null) {
|
||||||
val r = vl.sortedWith(compareBy(naturalOrder()) { it.video.name })
|
val r = vl.sortedWith(compareBy(naturalOrder()) { it.video.name })
|
||||||
videoLibrary.classesMap[videoLibrary.classes[index]]?.addAll(r)
|
videoLibrary.classesMap[videoLibrary.classes[index]]?.addAll(r)
|
||||||
|
videoLibrary.classesMap[videoLibrary.classes[index]]?.distinctBy { it.id }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user