diff --git a/README.md b/README.md index 011a3f4..57f8194 100755 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ repositories { mavenCentral() } dependencies { - implementation("ee.bjarn", "ktify", "0.1.1-hotfix") + implementation("ee.bjarn", "ktify", "0.1.2") } ``` diff --git a/build.gradle.kts b/build.gradle.kts index 9e03a98..efa70d2 100755 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -12,7 +12,7 @@ plugins { } group = "ee.bjarn" -version = "0.1.1-hotfix" +version = "0.1.2" repositories { mavenCentral() diff --git a/src/main/kotlin/ee/bjarn/ktify/Ktify.kt b/src/main/kotlin/ee/bjarn/ktify/Ktify.kt index 91696a2..f4f24ee 100755 --- a/src/main/kotlin/ee/bjarn/ktify/Ktify.kt +++ b/src/main/kotlin/ee/bjarn/ktify/Ktify.kt @@ -23,6 +23,7 @@ import kotlinx.serialization.json.JsonObject import mu.KotlinLogging import java.net.URLEncoder import java.util.UUID +import kotlin.io.encoding.Base64 /** * The main wrapper class @@ -112,14 +113,14 @@ class KtifyBuilder( * @param authorizationCode returned by the request to the user * @return The [Ktify] instance */ - @OptIn(InternalAPI::class) + @OptIn(InternalAPI::class, kotlin.io.encoding.ExperimentalEncodingApi::class) suspend fun build(authorizationCode: String): Ktify { - val clientCredentialsResponse: ClientCredentialsResponse = - ktifyHttpClient.post("https://accounts.spotify.com/api/token") { - header("Content-Type", "application/x-www-form-urlencoded") - body = - "grant_type=authorization_code&client_id=$clientId&client_secret=$clientSecret&redirect_uri=$redirectUri&code=$authorizationCode" - }.body() + val clientCredentialsResponse: ClientCredentialsResponse = ktifyHttpClient.post("https://accounts.spotify.com/api/token") { + header("Content-Type", "application/x-www-form-urlencoded") + header("Authorization", "Basic ${Base64.encode("$clientId:$clientSecret".encodeToByteArray())}") + body = + "grant_type=authorization_code&redirect_uri=${URLEncoder.encode(redirectUri, "UTF-8")}&code=$authorizationCode" + }.body() return Ktify( ClientCredentials( clientId, diff --git a/src/main/kotlin/ee/bjarn/ktify/model/player/CurrentPlayback.kt b/src/main/kotlin/ee/bjarn/ktify/model/player/CurrentPlayback.kt index 98c1235..0e17dff 100755 --- a/src/main/kotlin/ee/bjarn/ktify/model/player/CurrentPlayback.kt +++ b/src/main/kotlin/ee/bjarn/ktify/model/player/CurrentPlayback.kt @@ -2,7 +2,6 @@ package ee.bjarn.ktify.model.player import ee.bjarn.ktify.model.Episode import ee.bjarn.ktify.model.Track -import ee.bjarn.ktify.model.track.TrackActions import ee.bjarn.ktify.model.util.Context import kotlinx.serialization.* import kotlinx.serialization.descriptors.PrimitiveKind @@ -32,6 +31,8 @@ sealed class CurrentPlayback { @SerialName("repeat_state") abstract val repeatState: String? abstract val context: Context? + + abstract val actions: CurrentPlaybackActions } @Serializable @@ -49,8 +50,10 @@ class CurrentPlayingTrack( @SerialName("repeat_state") override val repeatState: String? = null, override val context: Context?, + override val actions: CurrentPlaybackActions, + @SerialName("smart_shuffle") + val smartShuffle: Boolean?, val item: Track? = null, - val actions: TrackActions, val resuming: Boolean? = null ) : CurrentPlayback() @@ -69,8 +72,8 @@ class CurrentPlayingEpisode( @SerialName("repeat_state") override val repeatState: String? = null, override val context: Context?, + override val actions: CurrentPlaybackActions, val item: Episode? = null, - val actions: TrackActions, val resuming: Boolean? = null ) : CurrentPlayback() @@ -90,9 +93,36 @@ class CurrentPlaybackNull( override val shuffleState: Boolean? = null, @SerialName("repeat_state") override val repeatState: String? = null, - override val context: Context? + override val context: Context?, + override val actions: CurrentPlaybackActions, ) : CurrentPlayback() +@Serializable +data class CurrentPlaybackActions( + val disallows: Disallows +) + +@Serializable +data class Disallows( + @SerialName("interrupting_playback") + val interruptingPlayback: Boolean? = null, + val pausing: Boolean? = null, + val resuming: Boolean? = null, + val seeking: Boolean? = null, + @SerialName("skipping_next") + val skippingNext: Boolean? = null, + @SerialName("skipping_prev") + val skippingPrev: Boolean? = null, + @SerialName("toggling_repeat_context") + val togglingRepeatContext: Boolean? = null, + @SerialName("toggling_shuffle") + val togglingShuffle: Boolean? = null, + @SerialName("toggling_repeat_track") + val togglingRepeatTrack: Boolean? = null, + @SerialName("transferring_playback") + val transferringPlayback: Boolean? = null, +) + object CurrentPlaybackSerializer : JsonContentPolymorphicSerializer(CurrentPlayback::class) { override fun selectDeserializer(element: JsonElement): DeserializationStrategy { return when (element.jsonObject["item"]?.jsonObject?.get("type")?.jsonPrimitive?.content) { diff --git a/src/main/kotlin/ee/bjarn/ktify/model/player/Devices.kt b/src/main/kotlin/ee/bjarn/ktify/model/player/Devices.kt index dae4857..1d621f4 100755 --- a/src/main/kotlin/ee/bjarn/ktify/model/player/Devices.kt +++ b/src/main/kotlin/ee/bjarn/ktify/model/player/Devices.kt @@ -20,5 +20,7 @@ data class Device( val name: String, val type: String, @SerialName("volume_percent") - val volumePercent: Int + val volumePercent: Int, + @SerialName("supports_volume") + val supportsVolume: Boolean, ) diff --git a/src/main/kotlin/ee/bjarn/ktify/model/track/Track.kt b/src/main/kotlin/ee/bjarn/ktify/model/track/Track.kt index b732148..8a2b69c 100755 --- a/src/main/kotlin/ee/bjarn/ktify/model/track/Track.kt +++ b/src/main/kotlin/ee/bjarn/ktify/model/track/Track.kt @@ -43,19 +43,6 @@ data class SavedTrack( val track: Track, ) -@Serializable -data class TrackActions( - @SerialName("is_playing") - val isPlaying: Boolean? = null, - val disallows: TrackActionsDisallows -) - -@Serializable -data class TrackActionsDisallows( - val pausing: Boolean? = null, - val resuming: Boolean? = null -) - @Serializable data class TrackRestriction( val reason: RestrictionType diff --git a/src/main/kotlin/ee/bjarn/ktify/model/util/Context.kt b/src/main/kotlin/ee/bjarn/ktify/model/util/Context.kt index 1409bba..11bae05 100755 --- a/src/main/kotlin/ee/bjarn/ktify/model/util/Context.kt +++ b/src/main/kotlin/ee/bjarn/ktify/model/util/Context.kt @@ -35,4 +35,7 @@ enum class ObjectType { @SerialName("user") USER, + + @SerialName("collection") + COLLECTION, } diff --git a/src/main/kotlin/ee/bjarn/ktify/player/KtifyPlayer.kt b/src/main/kotlin/ee/bjarn/ktify/player/KtifyPlayer.kt index 8256b8d..17780ae 100755 --- a/src/main/kotlin/ee/bjarn/ktify/player/KtifyPlayer.kt +++ b/src/main/kotlin/ee/bjarn/ktify/player/KtifyPlayer.kt @@ -112,6 +112,7 @@ class KtifyPlayer internal constructor(val ktify: Ktify) { ) { method = HttpMethod.Put url.takeFrom(ktify.requestHelper.baseUrl + "me/player/play") + header("Content-Type", "application/json") if (deviceId != null) { parameter("device_id", deviceId) } diff --git a/src/main/kotlin/ee/bjarn/ktify/utils/RequestHelper.kt b/src/main/kotlin/ee/bjarn/ktify/utils/RequestHelper.kt index 2759fd3..24bb3fb 100755 --- a/src/main/kotlin/ee/bjarn/ktify/utils/RequestHelper.kt +++ b/src/main/kotlin/ee/bjarn/ktify/utils/RequestHelper.kt @@ -80,7 +80,7 @@ internal class RequestHelper( } if (requiresScope != null) { require(clientCredentials.scopes?.contains(requiresScope) ?: false) } val responseData: HttpResponse = - makeRequest(requiresAuthentication = true, client = ktify.jsonLessHttpClient, builder = builder) + makeRequest(requiresAuthentication = true, builder = builder) return responseData.status }