Remove Outcome class
This commit is contained in:
@@ -1,49 +0,0 @@
|
||||
package it.vfsfitvnm.youtubemusic
|
||||
|
||||
import io.ktor.client.*
|
||||
import io.ktor.client.call.*
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.client.statement.*
|
||||
import io.ktor.util.network.*
|
||||
import io.ktor.utils.io.*
|
||||
|
||||
|
||||
fun <T> Result<T>.recoverIfCancelled(): Result<T>? {
|
||||
return when (exceptionOrNull()) {
|
||||
is CancellationException -> null
|
||||
else -> this
|
||||
}
|
||||
}
|
||||
|
||||
suspend inline fun <reified T> Outcome<HttpResponse>.bodyCatching(): Outcome<T> {
|
||||
return when (this) {
|
||||
is Outcome.Success -> value.bodyCatching()
|
||||
is Outcome.Recovered -> value.bodyCatching()
|
||||
is Outcome.Initial -> this
|
||||
is Outcome.Loading -> this
|
||||
is Outcome.Error -> this
|
||||
}
|
||||
}
|
||||
|
||||
suspend inline fun HttpClient.postCatching(
|
||||
urlString: String,
|
||||
block: HttpRequestBuilder.() -> Unit = {}
|
||||
): Outcome<HttpResponse> {
|
||||
return runCatching {
|
||||
Outcome.Success(post(urlString, block))
|
||||
}.getOrElse { throwable ->
|
||||
when (throwable) {
|
||||
is CancellationException -> Outcome.Loading
|
||||
is UnresolvedAddressException -> Outcome.Error.Network
|
||||
else -> Outcome.Error.Unhandled(throwable)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend inline fun <reified T> HttpResponse.bodyCatching(): Outcome<T> {
|
||||
return runCatching {
|
||||
Outcome.Success(body<T>())
|
||||
}.getOrElse { throwable ->
|
||||
Outcome.Error.Unhandled(throwable)
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
package it.vfsfitvnm.youtubemusic
|
||||
|
||||
|
||||
sealed class Outcome<out T> {
|
||||
val valueOrNull: T?
|
||||
get() = when (this) {
|
||||
is Success -> value
|
||||
is Recovered -> value
|
||||
else -> null
|
||||
}
|
||||
|
||||
fun recoverWith(value: @UnsafeVariance T): Outcome<T> {
|
||||
return when (this) {
|
||||
is Error -> Recovered(value, this)
|
||||
else -> this
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <R> map(block: (T) -> R): Outcome<R> {
|
||||
return when (this) {
|
||||
is Success -> Success(block(value))
|
||||
is Recovered -> Success(block(value))
|
||||
is Initial -> this
|
||||
is Loading -> this
|
||||
is Error -> this
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <R> flatMap(block: (T) -> Outcome<R>): Outcome<R> {
|
||||
return when (this) {
|
||||
is Success -> block(value)
|
||||
is Recovered -> block(value)
|
||||
is Initial -> this
|
||||
is Loading -> this
|
||||
is Error -> this
|
||||
}
|
||||
}
|
||||
|
||||
object Initial : Outcome<Nothing>()
|
||||
|
||||
object Loading : Outcome<Nothing>()
|
||||
|
||||
sealed class Error : Outcome<Nothing>() {
|
||||
object Network : Error()
|
||||
class Unhandled(val throwable: Throwable) : Error()
|
||||
}
|
||||
|
||||
class Recovered<T>(val value: T, val error: Error) : Outcome<T>()
|
||||
|
||||
class Success<T>(val value: T) : Outcome<T>()
|
||||
}
|
||||
|
||||
fun <T> Outcome<T>?.toNotNull(): Outcome<T?> {
|
||||
return when (this) {
|
||||
null -> Outcome.Success(null)
|
||||
else -> this
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> Outcome<T?>.toNullable(error: Outcome.Error? = null): Outcome<T>? {
|
||||
return when (this) {
|
||||
is Outcome.Success -> value?.let { Outcome.Success(it) } ?: error
|
||||
is Outcome.Recovered -> value?.let { Outcome.Success(it) } ?: error
|
||||
is Outcome.Initial -> this
|
||||
is Outcome.Loading -> this
|
||||
is Outcome.Error -> this
|
||||
}
|
||||
}
|
||||
|
||||
val Outcome<*>.isEvaluable: Boolean
|
||||
get() = this !is Outcome.Success && this !is Outcome.Loading
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package it.vfsfitvnm.youtubemusic
|
||||
|
||||
import io.ktor.utils.io.*
|
||||
|
||||
|
||||
internal fun <T> Result<T>.recoverIfCancelled(): Result<T>? {
|
||||
return when (exceptionOrNull()) {
|
||||
is CancellationException -> null
|
||||
else -> this
|
||||
}
|
||||
}
|
||||
@@ -450,77 +450,79 @@ object YouTube {
|
||||
}.recoverIfCancelled()
|
||||
}
|
||||
|
||||
suspend fun player(videoId: String, playlistId: String? = null): Outcome<PlayerResponse> {
|
||||
return client.postCatching("/youtubei/v1/player") {
|
||||
contentType(ContentType.Application.Json)
|
||||
setBody(
|
||||
PlayerBody(
|
||||
context = Context.DefaultAndroid,
|
||||
videoId = videoId,
|
||||
playlistId = playlistId,
|
||||
suspend fun player(videoId: String, playlistId: String? = null): Result<PlayerResponse>? {
|
||||
return runCatching {
|
||||
client.post("/youtubei/v1/player") {
|
||||
contentType(ContentType.Application.Json)
|
||||
setBody(
|
||||
PlayerBody(
|
||||
context = Context.DefaultAndroid,
|
||||
videoId = videoId,
|
||||
playlistId = playlistId,
|
||||
)
|
||||
)
|
||||
)
|
||||
parameter("key", Key)
|
||||
parameter("prettyPrint", false)
|
||||
}.bodyCatching()
|
||||
parameter("key", Key)
|
||||
parameter("prettyPrint", false)
|
||||
}.body<PlayerResponse>()
|
||||
}.recoverIfCancelled()
|
||||
}
|
||||
|
||||
private suspend fun getQueue(body: GetQueueBody): Outcome<List<Item.Song>?> {
|
||||
return client.postCatching("/youtubei/v1/music/get_queue") {
|
||||
contentType(ContentType.Application.Json)
|
||||
setBody(body)
|
||||
parameter("key", Key)
|
||||
parameter("prettyPrint", false)
|
||||
}
|
||||
.bodyCatching<GetQueueResponse>()
|
||||
.map { body ->
|
||||
body.queueDatas?.mapNotNull { queueData ->
|
||||
queueData.content?.playlistPanelVideoRenderer?.let { renderer ->
|
||||
Item.Song(
|
||||
info = Info(
|
||||
name = renderer
|
||||
.title
|
||||
?.text ?: return@let null,
|
||||
endpoint = renderer
|
||||
.navigationEndpoint
|
||||
.watchEndpoint
|
||||
),
|
||||
authors = renderer
|
||||
.longBylineText
|
||||
?.splitBySeparator()
|
||||
?.getOrNull(0)
|
||||
?.map { Info.from(it) }
|
||||
?: emptyList(),
|
||||
album = renderer
|
||||
.longBylineText
|
||||
?.splitBySeparator()
|
||||
?.getOrNull(1)
|
||||
?.getOrNull(0)
|
||||
?.let { Info.from(it) },
|
||||
thumbnail = renderer
|
||||
.thumbnail
|
||||
.thumbnails
|
||||
.getOrNull(0),
|
||||
durationText = renderer
|
||||
.lengthText
|
||||
?.text
|
||||
)
|
||||
}
|
||||
private suspend fun getQueue(body: GetQueueBody): Result<List<Item.Song>?>? {
|
||||
return runCatching {
|
||||
val body = client.post("/youtubei/v1/music/get_queue") {
|
||||
contentType(ContentType.Application.Json)
|
||||
setBody(body)
|
||||
parameter("key", Key)
|
||||
parameter("prettyPrint", false)
|
||||
}.body<GetQueueResponse>()
|
||||
|
||||
body.queueDatas?.mapNotNull { queueData ->
|
||||
queueData.content?.playlistPanelVideoRenderer?.let { renderer ->
|
||||
Item.Song(
|
||||
info = Info(
|
||||
name = renderer
|
||||
.title
|
||||
?.text ?: return@let null,
|
||||
endpoint = renderer
|
||||
.navigationEndpoint
|
||||
.watchEndpoint
|
||||
),
|
||||
authors = renderer
|
||||
.longBylineText
|
||||
?.splitBySeparator()
|
||||
?.getOrNull(0)
|
||||
?.map { Info.from(it) }
|
||||
?: emptyList(),
|
||||
album = renderer
|
||||
.longBylineText
|
||||
?.splitBySeparator()
|
||||
?.getOrNull(1)
|
||||
?.getOrNull(0)
|
||||
?.let { Info.from(it) },
|
||||
thumbnail = renderer
|
||||
.thumbnail
|
||||
.thumbnails
|
||||
.getOrNull(0),
|
||||
durationText = renderer
|
||||
.lengthText
|
||||
?.text
|
||||
)
|
||||
}
|
||||
}
|
||||
}.recoverIfCancelled()
|
||||
}
|
||||
|
||||
suspend fun song(videoId: String): Outcome<Item.Song?> {
|
||||
suspend fun song(videoId: String): Result<Item.Song?>? {
|
||||
return getQueue(
|
||||
GetQueueBody(
|
||||
context = Context.DefaultWeb,
|
||||
videoIds = listOf(videoId),
|
||||
playlistId = null
|
||||
)
|
||||
).map { it?.firstOrNull() }
|
||||
)?.map { it?.firstOrNull() }
|
||||
}
|
||||
|
||||
suspend fun queue(playlistId: String): Outcome<List<Item.Song>?> {
|
||||
suspend fun queue(playlistId: String): Result<List<Item.Song>?>? {
|
||||
return getQueue(
|
||||
GetQueueBody(
|
||||
context = Context.DefaultWeb,
|
||||
@@ -674,7 +676,7 @@ object YouTube {
|
||||
}
|
||||
|
||||
suspend fun browse(browseId: String): Result<BrowseResponse>? {
|
||||
return runCatching<YouTube, BrowseResponse> {
|
||||
return runCatching {
|
||||
client.post("/youtubei/v1/browse") {
|
||||
contentType(ContentType.Application.Json)
|
||||
setBody(
|
||||
@@ -685,7 +687,7 @@ object YouTube {
|
||||
)
|
||||
parameter("key", Key)
|
||||
parameter("prettyPrint", false)
|
||||
}.body()
|
||||
}.body<BrowseResponse>()
|
||||
}.recoverIfCancelled()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user