add readonly List implementation of playlist

This commit is contained in:
Christian Schabesberger 2024-08-22 09:43:03 +02:00
parent a2e8f6c4ad
commit 32075dec73
2 changed files with 159 additions and 1 deletions

View File

@ -31,6 +31,7 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import net.newpipe.newplayer.utils.PlayList
import kotlin.Exception
enum class PlayMode {
@ -57,6 +58,8 @@ interface NewPlayer {
var playBackMode: PlayMode
var playMode: PlayMode?
var playlist: PlayList
// calbacks
interface Listener {
@ -140,9 +143,10 @@ class NewPlayerImpl(
override val duration: Long
get() = internalPlayer.duration
override var playlist = PlayList(internalPlayer)
init {
internalPlayer.addListener(object: Player.Listener {
internalPlayer.addListener(object : Player.Listener {
override fun onPlayerError(error: PlaybackException) {
launchJobAndCollectError {
val item = internalPlayer.currentMediaItem?.mediaId

View File

@ -0,0 +1,154 @@
/* NewPlayer
*
* @author Christian Schabesberger
*
* Copyright (C) NewPipe e.V. 2024 <code(at)newpipe-ev.de>
*
* NewPlayer is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* NewPlayer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with NewPlayer. If not, see <http://www.gnu.org/licenses/>.
*
*/
package net.newpipe.newplayer.utils
import androidx.media3.common.Player
// TODO: This is cool, but it might still contains all raceconditions since two actors are mutating the
// same time.
// Be aware when using this list and this iterator: There can alwas be out of bounds exceptions
// even if the size in a previous query said otherwise, since between the size query and
// a get element query the count of elements might have been changed by exoplayer itself
// due to this reason some functions force the user to handle elements out of bounds exceptions.
class PlayListIterator(
val exoPlayer: Player,
val fromIndex: Int,
val toIndex: Int
) : ListIterator<String> {
var index = fromIndex
override fun hasNext() =
index < minOf(exoPlayer.mediaItemCount, toIndex)
override fun hasPrevious() = fromIndex < index
@Throws(IndexOutOfBoundsException::class)
override fun next(): String {
if (exoPlayer.mediaItemCount <= index)
throw NoSuchElementException("No Stream with index $index in the playlist")
val item = exoPlayer.getMediaItemAt(index).mediaId
index++
return item
}
@Throws(IndexOutOfBoundsException::class)
override fun nextIndex() =
if (exoPlayer.mediaItemCount <= index)
exoPlayer.mediaItemCount - fromIndex
else
(index + 1) - fromIndex
@Throws(IndexOutOfBoundsException::class)
override fun previous(): String {
if (index <= fromIndex)
throw NoSuchElementException("No Stream with index ${index - 1} in the playlist")
index--
val item = exoPlayer.getMediaItemAt(index).mediaId
return item
}
override fun previousIndex() =
if (index <= fromIndex)
0
else
(index - 1) - fromIndex
}
class PlayList(val exoPlayer: Player, val fromIndex: Int = 0, val toIndex: Int = Int.MAX_VALUE) :
List<String> {
override val size: Int
get() = minOf(exoPlayer.mediaItemCount, toIndex) - fromIndex
override fun contains(element: String): Boolean {
for (i in fromIndex..minOf(exoPlayer.mediaItemCount, toIndex)) {
try {
if (exoPlayer.getMediaItemAt(i).mediaId == element)
return true
} catch (e: IndexOutOfBoundsException) {
return false
}
}
return false
}
override fun containsAll(elements: Collection<String>): Boolean {
for (element in elements) {
if (!this.contains(element)) {
return false
}
}
return true
}
@Throws(IndexOutOfBoundsException::class)
override fun get(index: Int) =
if (index < fromIndex || toIndex < index)
throw IndexOutOfBoundsException("Accessed playlist item outside of permitted Playlist ListWindow: $index")
else
exoPlayer.getMediaItemAt(index).mediaId
override fun isEmpty() = exoPlayer.mediaItemCount == 0 || fromIndex == toIndex
override fun iterator() = PlayListIterator(exoPlayer, fromIndex, toIndex)
override fun listIterator() = PlayListIterator(exoPlayer, fromIndex, toIndex)
override fun listIterator(index: Int) = PlayListIterator(exoPlayer, index, toIndex)
override fun subList(fromIndex: Int, toIndex: Int): List<String> =
PlayList(
exoPlayer,
fromIndex = this.fromIndex + fromIndex,
toIndex = this.fromIndex + toIndex
)
override fun lastIndexOf(element: String): Int {
for (i in minOf(toIndex, exoPlayer.mediaItemCount) downTo fromIndex) {
try {
if (exoPlayer.getMediaItemAt(i).mediaId == element) {
return i - fromIndex
}
} catch (e: IndexOutOfBoundsException) {
return -1
}
}
return -1
}
override fun indexOf(element: String): Int {
for (i in fromIndex.. minOf(toIndex, exoPlayer.mediaItemCount)) {
try {
if (exoPlayer.getMediaItemAt(i).mediaId == element) {
return i - fromIndex
}
} catch (e: IndexOutOfBoundsException) {
return -1
}
}
return -1
}
}