mirror of
https://github.com/libre-tube/LibreTube.git
synced 2025-04-28 16:00:31 +05:30
refactor: bind playlist repositories to interfaces
This commit is contained in:
parent
f54d0fd8a0
commit
2698368aee
@ -1,16 +1,16 @@
|
||||
package com.github.libretube.api
|
||||
|
||||
import androidx.core.text.isDigitsOnly
|
||||
import com.github.libretube.api.obj.EditPlaylistBody
|
||||
import com.github.libretube.api.obj.Message
|
||||
import com.github.libretube.api.obj.Playlist
|
||||
import com.github.libretube.api.obj.Playlists
|
||||
import com.github.libretube.api.obj.StreamItem
|
||||
import com.github.libretube.constants.PreferenceKeys
|
||||
import com.github.libretube.enums.PlaylistType
|
||||
import com.github.libretube.extensions.toID
|
||||
import com.github.libretube.helpers.PreferenceHelper
|
||||
import com.github.libretube.obj.PipedImportPlaylist
|
||||
import com.github.libretube.repo.LocalPlaylistsRepository
|
||||
import com.github.libretube.repo.PipedPlaylistRepository
|
||||
import com.github.libretube.repo.PlaylistRepository
|
||||
import com.github.libretube.util.deArrow
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
@ -24,14 +24,14 @@ object PlaylistsHelper {
|
||||
|
||||
private val token get() = PreferenceHelper.getToken()
|
||||
val loggedIn: Boolean get() = token.isNotEmpty()
|
||||
private fun Message.isOk() = this.message == "ok"
|
||||
private val playlistsRepository: PlaylistRepository
|
||||
get() = when {
|
||||
loggedIn -> PipedPlaylistRepository()
|
||||
else -> LocalPlaylistsRepository()
|
||||
}
|
||||
|
||||
suspend fun getPlaylists(): List<Playlists> = withContext(Dispatchers.IO) {
|
||||
val playlists = if (loggedIn) {
|
||||
RetrofitInstance.authApi.getUserPlaylists(token)
|
||||
} else {
|
||||
LocalPlaylistsRepository.getPlaylists()
|
||||
}
|
||||
val playlists = playlistsRepository.getPlaylists()
|
||||
sortPlaylists(playlists)
|
||||
}
|
||||
|
||||
@ -52,109 +52,41 @@ object PlaylistsHelper {
|
||||
suspend fun getPlaylist(playlistId: String): Playlist {
|
||||
// load locally stored playlists with the auth api
|
||||
return when (getPrivatePlaylistType(playlistId)) {
|
||||
PlaylistType.PRIVATE -> RetrofitInstance.authApi.getPlaylist(playlistId)
|
||||
PlaylistType.PUBLIC -> RetrofitInstance.api.getPlaylist(playlistId)
|
||||
PlaylistType.LOCAL -> LocalPlaylistsRepository.getPlaylist(playlistId)
|
||||
else -> playlistsRepository.getPlaylist(playlistId)
|
||||
}.apply {
|
||||
relatedStreams = relatedStreams.deArrow()
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun createPlaylist(playlistName: String): String? {
|
||||
return if (!loggedIn) {
|
||||
LocalPlaylistsRepository.createPlaylist(playlistName)
|
||||
} else {
|
||||
RetrofitInstance.authApi.createPlaylist(
|
||||
token,
|
||||
Playlists(name = playlistName)
|
||||
).playlistId
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun addToPlaylist(playlistId: String, vararg videos: StreamItem): Boolean {
|
||||
if (!loggedIn) {
|
||||
LocalPlaylistsRepository.addToPlaylist(playlistId, *videos)
|
||||
return true
|
||||
}
|
||||
|
||||
val playlist = EditPlaylistBody(playlistId, videoIds = videos.map { it.url!!.toID() })
|
||||
return RetrofitInstance.authApi.addToPlaylist(token, playlist).isOk()
|
||||
}
|
||||
|
||||
suspend fun renamePlaylist(playlistId: String, newName: String): Boolean {
|
||||
if (!loggedIn) {
|
||||
LocalPlaylistsRepository.renamePlaylist(playlistId, newName)
|
||||
return true
|
||||
}
|
||||
|
||||
val playlist = EditPlaylistBody(playlistId, newName = newName)
|
||||
return RetrofitInstance.authApi.renamePlaylist(token, playlist).isOk()
|
||||
}
|
||||
|
||||
suspend fun changePlaylistDescription(playlistId: String, newDescription: String): Boolean {
|
||||
if (!loggedIn) {
|
||||
LocalPlaylistsRepository.changePlaylistDescription(playlistId, newDescription)
|
||||
return true
|
||||
}
|
||||
|
||||
val playlist = EditPlaylistBody(playlistId, description = newDescription)
|
||||
return RetrofitInstance.authApi.changePlaylistDescription(token, playlist).isOk()
|
||||
}
|
||||
|
||||
suspend fun removeFromPlaylist(playlistId: String, index: Int): Boolean {
|
||||
if (!loggedIn) {
|
||||
LocalPlaylistsRepository.removeFromPlaylist(playlistId, index)
|
||||
return true
|
||||
}
|
||||
|
||||
return RetrofitInstance.authApi.removeFromPlaylist(
|
||||
PreferenceHelper.getToken(),
|
||||
EditPlaylistBody(playlistId = playlistId, index = index)
|
||||
).isOk()
|
||||
}
|
||||
|
||||
suspend fun importPlaylists(playlists: List<PipedImportPlaylist>) =
|
||||
withContext(Dispatchers.IO) {
|
||||
if (!loggedIn) return@withContext LocalPlaylistsRepository.importPlaylists(playlists)
|
||||
|
||||
for (playlist in playlists) {
|
||||
val playlistId = createPlaylist(playlist.name!!) ?: return@withContext
|
||||
val streams = playlist.videos.map { StreamItem(url = it) }
|
||||
addToPlaylist(playlistId, *streams.toTypedArray())
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getAllPlaylistsWithVideos(playlistIds: List<String>? = null): List<Playlist> =
|
||||
withContext(Dispatchers.IO) {
|
||||
suspend fun getAllPlaylistsWithVideos(playlistIds: List<String>? = null): List<Playlist> {
|
||||
return withContext(Dispatchers.IO) {
|
||||
(playlistIds ?: getPlaylists().map { it.id!! })
|
||||
.map { async { getPlaylist(it) } }
|
||||
.awaitAll()
|
||||
}
|
||||
|
||||
suspend fun clonePlaylist(playlistId: String): String? {
|
||||
if (!loggedIn) {
|
||||
return LocalPlaylistsRepository.clonePlaylist(playlistId)
|
||||
}
|
||||
|
||||
return RetrofitInstance.authApi.clonePlaylist(
|
||||
token,
|
||||
EditPlaylistBody(playlistId)
|
||||
).playlistId
|
||||
}
|
||||
suspend fun createPlaylist(playlistName: String) =
|
||||
playlistsRepository.createPlaylist(playlistName)
|
||||
|
||||
suspend fun deletePlaylist(playlistId: String, playlistType: PlaylistType): Boolean {
|
||||
if (playlistType == PlaylistType.LOCAL) {
|
||||
LocalPlaylistsRepository.deletePlaylist(playlistId)
|
||||
return true
|
||||
}
|
||||
suspend fun addToPlaylist(playlistId: String, vararg videos: StreamItem) =
|
||||
playlistsRepository.addToPlaylist(playlistId, *videos)
|
||||
|
||||
return runCatching {
|
||||
RetrofitInstance.authApi.deletePlaylist(
|
||||
PreferenceHelper.getToken(),
|
||||
EditPlaylistBody(playlistId)
|
||||
).isOk()
|
||||
}.getOrDefault(false)
|
||||
}
|
||||
suspend fun renamePlaylist(playlistId: String, newName: String) =
|
||||
playlistsRepository.renamePlaylist(playlistId, newName)
|
||||
|
||||
suspend fun changePlaylistDescription(playlistId: String, newDescription: String) =
|
||||
playlistsRepository.changePlaylistDescription(playlistId, newDescription)
|
||||
|
||||
suspend fun removeFromPlaylist(playlistId: String, index: Int) =
|
||||
playlistsRepository.removeFromPlaylist(playlistId, index)
|
||||
|
||||
suspend fun importPlaylists(playlists: List<PipedImportPlaylist>) =
|
||||
playlistsRepository.importPlaylists(playlists)
|
||||
|
||||
suspend fun clonePlaylist(playlistId: String) = playlistsRepository.clonePlaylist(playlistId)
|
||||
suspend fun deletePlaylist(playlistId: String) = playlistsRepository.deletePlaylist(playlistId)
|
||||
|
||||
fun getPrivatePlaylistType(): PlaylistType {
|
||||
return if (loggedIn) PlaylistType.PRIVATE else PlaylistType.LOCAL
|
||||
|
@ -1,6 +1,9 @@
|
||||
package com.github.libretube.api
|
||||
package com.github.libretube.repo
|
||||
|
||||
import com.github.libretube.api.PlaylistsHelper
|
||||
import com.github.libretube.api.PlaylistsHelper.MAX_CONCURRENT_IMPORT_CALLS
|
||||
import com.github.libretube.api.RetrofitInstance
|
||||
import com.github.libretube.api.StreamsExtractor
|
||||
import com.github.libretube.api.obj.Playlist
|
||||
import com.github.libretube.api.obj.Playlists
|
||||
import com.github.libretube.api.obj.StreamItem
|
||||
@ -10,8 +13,8 @@ import com.github.libretube.extensions.parallelMap
|
||||
import com.github.libretube.helpers.ProxyHelper
|
||||
import com.github.libretube.obj.PipedImportPlaylist
|
||||
|
||||
object LocalPlaylistsRepository {
|
||||
suspend fun getPlaylist(playlistId: String): Playlist {
|
||||
class LocalPlaylistsRepository: PlaylistRepository {
|
||||
override suspend fun getPlaylist(playlistId: String): Playlist {
|
||||
val relation = DatabaseHolder.Database.localPlaylistsDao().getAll()
|
||||
.first { it.playlist.id.toString() == playlistId }
|
||||
|
||||
@ -24,7 +27,7 @@ object LocalPlaylistsRepository {
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun getPlaylists(): List<Playlists> {
|
||||
override suspend fun getPlaylists(): List<Playlists> {
|
||||
return DatabaseHolder.Database.localPlaylistsDao().getAll()
|
||||
.map {
|
||||
Playlists(
|
||||
@ -37,7 +40,7 @@ object LocalPlaylistsRepository {
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun addToPlaylist(playlistId: String, vararg videos: StreamItem) {
|
||||
override suspend fun addToPlaylist(playlistId: String, vararg videos: StreamItem): Boolean {
|
||||
val localPlaylist = DatabaseHolder.Database.localPlaylistsDao().getAll()
|
||||
.first { it.playlist.id.toString() == playlistId }
|
||||
|
||||
@ -59,25 +62,31 @@ object LocalPlaylistsRepository {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
suspend fun renamePlaylist(playlistId: String, newName: String) {
|
||||
override suspend fun renamePlaylist(playlistId: String, newName: String): Boolean {
|
||||
val playlist = DatabaseHolder.Database.localPlaylistsDao().getAll()
|
||||
.first { it.playlist.id.toString() == playlistId }.playlist
|
||||
playlist.name = newName
|
||||
DatabaseHolder.Database.localPlaylistsDao().updatePlaylist(playlist)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
suspend fun changePlaylistDescription(playlistId: String, newDescription: String) {
|
||||
override suspend fun changePlaylistDescription(playlistId: String, newDescription: String): Boolean {
|
||||
val playlist = DatabaseHolder.Database.localPlaylistsDao().getAll()
|
||||
.first { it.playlist.id.toString() == playlistId }.playlist
|
||||
playlist.description = newDescription
|
||||
DatabaseHolder.Database.localPlaylistsDao().updatePlaylist(playlist)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
suspend fun clonePlaylist(playlistId: String): String? {
|
||||
override suspend fun clonePlaylist(playlistId: String): String {
|
||||
val playlist = RetrofitInstance.api.getPlaylist(playlistId)
|
||||
val newPlaylist = createPlaylist(playlist.name ?: "Unknown name") ?: return null
|
||||
val newPlaylist = createPlaylist(playlist.name ?: "Unknown name")
|
||||
|
||||
PlaylistsHelper.addToPlaylist(newPlaylist, *playlist.relatedStreams.toTypedArray())
|
||||
|
||||
@ -93,7 +102,7 @@ object LocalPlaylistsRepository {
|
||||
return playlistId
|
||||
}
|
||||
|
||||
suspend fun removeFromPlaylist(playlistId: String, index: Int) {
|
||||
override suspend fun removeFromPlaylist(playlistId: String, index: Int): Boolean {
|
||||
val transaction = DatabaseHolder.Database.localPlaylistsDao().getAll()
|
||||
.first { it.playlist.id.toString() == playlistId }
|
||||
DatabaseHolder.Database.localPlaylistsDao().removePlaylistVideo(
|
||||
@ -105,11 +114,13 @@ object LocalPlaylistsRepository {
|
||||
transaction.videos.getOrNull(1)?.thumbnailUrl.orEmpty()
|
||||
}
|
||||
DatabaseHolder.Database.localPlaylistsDao().updatePlaylist(transaction.playlist)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
suspend fun importPlaylists(playlists: List<PipedImportPlaylist>) {
|
||||
override suspend fun importPlaylists(playlists: List<PipedImportPlaylist>) {
|
||||
for (playlist in playlists) {
|
||||
val playlistId = createPlaylist(playlist.name!!) ?: return
|
||||
val playlistId = createPlaylist(playlist.name!!)
|
||||
|
||||
// if not logged in, all video information needs to become fetched manually
|
||||
// Only do so with `MAX_CONCURRENT_IMPORT_CALLS` videos at once to prevent performance issues
|
||||
@ -125,13 +136,15 @@ object LocalPlaylistsRepository {
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun createPlaylist(playlistName: String): String {
|
||||
override suspend fun createPlaylist(playlistName: String): String {
|
||||
val playlist = LocalPlaylist(name = playlistName, thumbnailUrl = "")
|
||||
return DatabaseHolder.Database.localPlaylistsDao().createPlaylist(playlist).toString()
|
||||
}
|
||||
|
||||
suspend fun deletePlaylist(playlistId: String) {
|
||||
override suspend fun deletePlaylist(playlistId: String): Boolean {
|
||||
DatabaseHolder.Database.localPlaylistsDao().deletePlaylistById(playlistId)
|
||||
DatabaseHolder.Database.localPlaylistsDao().deletePlaylistItemsByPlaylistId(playlistId)
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
package com.github.libretube.repo
|
||||
|
||||
import com.github.libretube.api.PlaylistsHelper
|
||||
import com.github.libretube.api.RetrofitInstance
|
||||
import com.github.libretube.api.obj.EditPlaylistBody
|
||||
import com.github.libretube.api.obj.Message
|
||||
import com.github.libretube.api.obj.Playlist
|
||||
import com.github.libretube.api.obj.Playlists
|
||||
import com.github.libretube.api.obj.StreamItem
|
||||
import com.github.libretube.extensions.toID
|
||||
import com.github.libretube.helpers.PreferenceHelper
|
||||
import com.github.libretube.obj.PipedImportPlaylist
|
||||
|
||||
class PipedPlaylistRepository: PlaylistRepository {
|
||||
private fun Message.isOk() = this.message == "ok"
|
||||
private val token get() = PreferenceHelper.getToken()
|
||||
|
||||
override suspend fun getPlaylist(playlistId: String): Playlist {
|
||||
return RetrofitInstance.authApi.getPlaylist(playlistId)
|
||||
}
|
||||
|
||||
override suspend fun getPlaylists(): List<Playlists> {
|
||||
return RetrofitInstance.authApi.getUserPlaylists(token)
|
||||
}
|
||||
|
||||
override suspend fun addToPlaylist(playlistId: String, vararg videos: StreamItem): Boolean {
|
||||
val playlist = EditPlaylistBody(playlistId, videoIds = videos.map { it.url!!.toID() })
|
||||
|
||||
return RetrofitInstance.authApi.addToPlaylist(token, playlist).isOk()
|
||||
}
|
||||
|
||||
override suspend fun renamePlaylist(playlistId: String, newName: String): Boolean {
|
||||
val playlist = EditPlaylistBody(playlistId, newName = newName)
|
||||
|
||||
return RetrofitInstance.authApi.renamePlaylist(token, playlist).isOk()
|
||||
}
|
||||
|
||||
override suspend fun changePlaylistDescription(playlistId: String, newDescription: String): Boolean {
|
||||
val playlist = EditPlaylistBody(playlistId, description = newDescription)
|
||||
|
||||
return RetrofitInstance.authApi.changePlaylistDescription(token, playlist).isOk()
|
||||
}
|
||||
|
||||
override suspend fun clonePlaylist(playlistId: String): String? {
|
||||
return RetrofitInstance.authApi.clonePlaylist(
|
||||
token,
|
||||
EditPlaylistBody(playlistId)
|
||||
).playlistId
|
||||
}
|
||||
|
||||
override suspend fun removeFromPlaylist(playlistId: String, index: Int): Boolean {
|
||||
return RetrofitInstance.authApi.removeFromPlaylist(
|
||||
PreferenceHelper.getToken(),
|
||||
EditPlaylistBody(playlistId = playlistId, index = index)
|
||||
).isOk()
|
||||
}
|
||||
|
||||
override suspend fun importPlaylists(playlists: List<PipedImportPlaylist>) {
|
||||
for (playlist in playlists) {
|
||||
val playlistId = PlaylistsHelper.createPlaylist(playlist.name!!) ?: return
|
||||
val streams = playlist.videos.map { StreamItem(url = it) }
|
||||
PlaylistsHelper.addToPlaylist(playlistId, *streams.toTypedArray())
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun createPlaylist(playlistName: String): String? {
|
||||
return RetrofitInstance.authApi.createPlaylist(
|
||||
token,
|
||||
Playlists(name = playlistName)
|
||||
).playlistId
|
||||
}
|
||||
|
||||
override suspend fun deletePlaylist(playlistId: String): Boolean {
|
||||
return runCatching {
|
||||
RetrofitInstance.authApi.deletePlaylist(
|
||||
PreferenceHelper.getToken(),
|
||||
EditPlaylistBody(playlistId)
|
||||
).isOk()
|
||||
}.getOrDefault(false)
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package com.github.libretube.repo
|
||||
|
||||
import com.github.libretube.api.obj.Playlist
|
||||
import com.github.libretube.api.obj.Playlists
|
||||
import com.github.libretube.api.obj.StreamItem
|
||||
import com.github.libretube.obj.PipedImportPlaylist
|
||||
|
||||
interface PlaylistRepository {
|
||||
suspend fun getPlaylist(playlistId: String): Playlist
|
||||
suspend fun getPlaylists(): List<Playlists>
|
||||
suspend fun addToPlaylist(playlistId: String, vararg videos: StreamItem): Boolean
|
||||
suspend fun renamePlaylist(playlistId: String, newName: String): Boolean
|
||||
suspend fun changePlaylistDescription(playlistId: String, newDescription: String): Boolean
|
||||
suspend fun clonePlaylist(playlistId: String): String?
|
||||
suspend fun removeFromPlaylist(playlistId: String, index: Int): Boolean
|
||||
suspend fun importPlaylists(playlists: List<PipedImportPlaylist>)
|
||||
suspend fun createPlaylist(playlistName: String): String?
|
||||
suspend fun deletePlaylist(playlistId: String): Boolean
|
||||
}
|
@ -10,8 +10,6 @@ import androidx.lifecycle.lifecycleScope
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.api.PlaylistsHelper
|
||||
import com.github.libretube.constants.IntentData
|
||||
import com.github.libretube.enums.PlaylistType
|
||||
import com.github.libretube.extensions.serializable
|
||||
import com.github.libretube.extensions.toastFromMainDispatcher
|
||||
import com.github.libretube.ui.sheets.PlaylistOptionsBottomSheet
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
@ -21,14 +19,14 @@ import kotlinx.coroutines.withContext
|
||||
|
||||
class DeletePlaylistDialog : DialogFragment() {
|
||||
private lateinit var playlistId: String
|
||||
private lateinit var playlistType: PlaylistType
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
arguments?.let {
|
||||
playlistId = it.getString(IntentData.playlistId)!!
|
||||
playlistType = it.serializable(IntentData.playlistType)!!
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
return MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(R.string.deletePlaylist)
|
||||
@ -39,7 +37,7 @@ class DeletePlaylistDialog : DialogFragment() {
|
||||
.apply {
|
||||
getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
val success = PlaylistsHelper.deletePlaylist(playlistId, playlistType)
|
||||
val success = PlaylistsHelper.deletePlaylist(playlistId)
|
||||
context.toastFromMainDispatcher(
|
||||
if (success) R.string.success else R.string.fail
|
||||
)
|
||||
|
@ -123,8 +123,7 @@ class PlaylistOptionsBottomSheet : BaseBottomSheet() {
|
||||
R.string.deletePlaylist -> {
|
||||
val newDeletePlaylistDialog = DeletePlaylistDialog()
|
||||
newDeletePlaylistDialog.arguments = bundleOf(
|
||||
IntentData.playlistId to playlistId,
|
||||
IntentData.playlistType to playlistType
|
||||
IntentData.playlistId to playlistId
|
||||
)
|
||||
newDeletePlaylistDialog.show(mFragmentManager, null)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user