Merge pull request #2926 from Bnyro/master

Playlist importing bug fixes and performance imporvents
This commit is contained in:
Bnyro 2023-01-31 16:36:19 +01:00 committed by GitHub
commit e03ca65182
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 54 additions and 49 deletions

View File

@ -19,6 +19,7 @@ import com.github.libretube.extensions.toastFromMainThread
import com.github.libretube.obj.ImportPlaylist import com.github.libretube.obj.ImportPlaylist
import com.github.libretube.util.PreferenceHelper import com.github.libretube.util.PreferenceHelper
import com.github.libretube.util.ProxyHelper import com.github.libretube.util.ProxyHelper
import gen._base._base_java__assetres.srcjar.R.id.async
import java.io.IOException import java.io.IOException
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async import kotlinx.coroutines.async
@ -68,30 +69,25 @@ object PlaylistsHelper {
} }
} }
suspend fun createPlaylist( suspend fun createPlaylist(playlistName: String, appContext: Context?): String? {
playlistName: String,
appContext: Context
): String? {
if (!loggedIn) { if (!loggedIn) {
val playlist = LocalPlaylist(name = playlistName, thumbnailUrl = "") val playlist = LocalPlaylist(name = playlistName, thumbnailUrl = "")
DatabaseHolder.Database.localPlaylistsDao().createPlaylist(playlist) DatabaseHolder.Database.localPlaylistsDao().createPlaylist(playlist)
return DatabaseHolder.Database.localPlaylistsDao().getAll() return DatabaseHolder.Database.localPlaylistsDao().getAll()
.last().playlist.id.toString() .last().playlist.id.toString()
} else { } else {
val response = try { return try {
RetrofitInstance.authApi.createPlaylist(token, Playlists(name = playlistName)) RetrofitInstance.authApi.createPlaylist(token, Playlists(name = playlistName))
} catch (e: IOException) { } catch (e: IOException) {
appContext.toastFromMainThread(R.string.unknown_error) appContext?.toastFromMainThread(R.string.unknown_error)
return null return null
} catch (e: HttpException) { } catch (e: HttpException) {
Log.e(TAG(), e.toString()) Log.e(TAG(), e.toString())
appContext.toastFromMainThread(R.string.server_error) appContext?.toastFromMainThread(R.string.server_error)
return null return null
}.playlistId.also {
appContext?.toastFromMainThread(R.string.playlistCreated)
} }
if (response.playlistId != null) {
appContext.toastFromMainThread(R.string.playlistCreated)
}
return response.playlistId
} }
} }
@ -138,36 +134,34 @@ object PlaylistsHelper {
} }
} }
suspend fun removeFromPlaylist(playlistId: String, index: Int) { suspend fun removeFromPlaylist(playlistId: String, index: Int): Boolean {
if (!loggedIn) { return if (!loggedIn) {
val transaction = DatabaseHolder.Database.localPlaylistsDao().getAll() val transaction = DatabaseHolder.Database.localPlaylistsDao().getAll()
.first { it.playlist.id.toString() == playlistId } .first { it.playlist.id.toString() == playlistId }
DatabaseHolder.Database.localPlaylistsDao().removePlaylistVideo( DatabaseHolder.Database.localPlaylistsDao().removePlaylistVideo(
transaction.videos[index] transaction.videos[index]
) )
if (transaction.videos.size > 1) { // set a new playlist thumbnail if the first video got removed
if (index == 0) { if (index == 0) {
transaction.videos[1].thumbnailUrl?.let { transaction.playlist.thumbnailUrl = transaction.videos.getOrNull(1)?.thumbnailUrl ?: ""
transaction.playlist.thumbnailUrl = it
} }
DatabaseHolder.Database.localPlaylistsDao().updatePlaylist(transaction.playlist) DatabaseHolder.Database.localPlaylistsDao().updatePlaylist(transaction.playlist)
} true
return
}
// remove thumbnail if playlist now empty
transaction.playlist.thumbnailUrl = ""
DatabaseHolder.Database.localPlaylistsDao().updatePlaylist(transaction.playlist)
} else { } else {
val playlist = PlaylistId(playlistId = playlistId, index = index) RetrofitInstance.authApi.removeFromPlaylist(
RetrofitInstance.authApi.removeFromPlaylist(PreferenceHelper.getToken(), playlist) PreferenceHelper.getToken(),
PlaylistId(playlistId = playlistId, index = index)
).message == "ok"
} }
} }
suspend fun importPlaylists(appContext: Context, playlists: List<ImportPlaylist>) { suspend fun importPlaylists(playlists: List<ImportPlaylist>) = withContext(Dispatchers.IO) {
for (playlist in playlists) { playlists.map { playlist ->
val playlistId = createPlaylist(playlist.name!!, appContext) ?: continue val playlistId = createPlaylist(playlist.name!!, null)
async {
playlistId ?: return@async
// if logged in, add the playlists by their ID via an api call // if logged in, add the playlists by their ID via an api call
val success: Boolean = if (loggedIn) { if (loggedIn) {
addToPlaylist( addToPlaylist(
playlistId, playlistId,
*playlist.videos.map { *playlist.videos.map {
@ -176,19 +170,24 @@ object PlaylistsHelper {
) )
} else { } else {
// if not logged in, all video information needs to become fetched manually // if not logged in, all video information needs to become fetched manually
try { runCatching {
val streamItems = playlist.videos.map { val streamItems = playlist.videos.map {
async {
try {
RetrofitInstance.api.getStreams(it).toStreamItem(it) RetrofitInstance.api.getStreams(it).toStreamItem(it)
}
addToPlaylist(playlistId, *streamItems.toTypedArray())
} catch (e: Exception) { } catch (e: Exception) {
false null
} }
} }
appContext.toastFromMainThread(
if (success) R.string.importsuccess else R.string.server_error
)
} }
.awaitAll()
.filterNotNull()
addToPlaylist(playlistId, *streamItems.toTypedArray())
}
}
}
}.awaitAll()
} }
suspend fun exportPlaylists(): List<ImportPlaylist> = withContext(Dispatchers.IO) { suspend fun exportPlaylists(): List<ImportPlaylist> = withContext(Dispatchers.IO) {

View File

@ -19,6 +19,7 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.json.decodeFromStream import kotlinx.serialization.json.decodeFromStream
import kotlinx.serialization.json.encodeToStream import kotlinx.serialization.json.encodeToStream
import okio.use import okio.use
@ -109,6 +110,7 @@ class ImportHelper(
/** /**
* Import Playlists * Import Playlists
*/ */
@OptIn(ExperimentalSerializationApi::class)
fun importPlaylists(uri: Uri?) { fun importPlaylists(uri: Uri?) {
if (uri == null) return if (uri == null) return
@ -141,9 +143,13 @@ class ImportHelper(
} }
} }
// convert the YouTube URLs to videoIds
importPlaylists.forEach { playlist ->
playlist.videos = playlist.videos.map { it.takeLast(11) }
}
CoroutineScope(Dispatchers.IO).launch { CoroutineScope(Dispatchers.IO).launch {
try { try {
PlaylistsHelper.importPlaylists(activity, importPlaylists) PlaylistsHelper.importPlaylists(importPlaylists)
activity.applicationContext.toastFromMainThread(R.string.success) activity.applicationContext.toastFromMainThread(R.string.success)
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG(), e.toString()) Log.e(TAG(), e.toString())