diff --git a/build.gradle.kts b/build.gradle.kts index b1205f6..d46cad3 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -28,6 +28,7 @@ dependencies { implementation("io.ktor:ktor-server-content-negotiation:$ktor_version") implementation("io.ktor:ktor-client-content-negotiation:$ktor_version") implementation("io.ktor:ktor-server-call-logging-jvm:$ktor_version") + implementation("io.ktor:ktor-server-cors:$ktor_version") implementation("io.ktor:ktor-serialization-kotlinx-json-jvm:$ktor_version") implementation("io.ktor:ktor-server-netty-jvm:$ktor_version") implementation("io.ktor:ktor-client-core:$ktor_version") @@ -40,6 +41,7 @@ dependencies { implementation("io.insert-koin:koin-ktor:$koin_version") implementation("io.insert-koin:koin-logger-slf4j:$koin_version") implementation("ch.qos.logback:logback-classic:$logback_version") + implementation("io.ktor:ktor-server-cors-jvm:2.1.3") testImplementation("io.ktor:ktor-server-tests-jvm:$ktor_version") testImplementation("org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version") diff --git a/src/main/kotlin/dev/fyloz/musicplayer/core/Application.kt b/src/main/kotlin/dev/fyloz/musicplayer/core/Application.kt index 0e5be07..df8be0f 100644 --- a/src/main/kotlin/dev/fyloz/musicplayer/core/Application.kt +++ b/src/main/kotlin/dev/fyloz/musicplayer/core/Application.kt @@ -2,13 +2,13 @@ package dev.fyloz.musicplayer.core import com.typesafe.config.ConfigFactory import dev.fyloz.musicplayer.core.data.RepositoryInjection -import dev.fyloz.musicplayer.core.factory.TrackFactoryProxy +import dev.fyloz.musicplayer.core.factory.SongFactoryProxy import dev.fyloz.musicplayer.core.http.auth.AuthorizationData -import dev.fyloz.musicplayer.core.http.configureTrackRoutes -import dev.fyloz.musicplayer.core.logic.TrackLogic +import dev.fyloz.musicplayer.core.http.configureSongRoutes +import dev.fyloz.musicplayer.core.logic.SongLogic import dev.fyloz.musicplayer.modules.Module import io.ktor.client.* -import io.ktor.client.plugins.logging.* +import io.ktor.http.* import io.ktor.serialization.kotlinx.json.* import io.ktor.server.application.* import io.ktor.server.config.* @@ -16,6 +16,7 @@ import io.ktor.server.engine.* import io.ktor.server.netty.* import io.ktor.server.plugins.callloging.* import io.ktor.server.plugins.contentnegotiation.* +import io.ktor.server.plugins.cors.routing.* import io.ktor.server.routing.* import kotlinx.serialization.json.Json import org.koin.dsl.module @@ -50,8 +51,8 @@ fun Application.module() { RepositoryInjection.koinBeans, module { - single { TrackFactoryProxy() } - single { TrackLogic() } + single { SongFactoryProxy() } + single { SongLogic() } single { HttpClient { install(io.ktor.client.plugins.contentnegotiation.ContentNegotiation) { @@ -60,10 +61,10 @@ fun Application.module() { }) } - install(Logging) { - level = LogLevel.ALL -// filter { call -> call.request.path().startsWith("/") } - } +// install(Logging) { +// level = LogLevel.ALL +//// filter { call -> call.request.path().startsWith("/") } +// } } } @@ -79,9 +80,19 @@ fun Application.module() { registeredModules.values.forEach { it.configureRoutes(this) } route("/api/v1") { - configureTrackRoutes() + configureSongRoutes() } } + + install(CORS) { + allowMethod(HttpMethod.Options) + allowMethod(HttpMethod.Put) + allowMethod(HttpMethod.Delete) + allowMethod(HttpMethod.Patch) + allowHeader(HttpHeaders.Authorization) + allowHeader("MyCustomHeader") + anyHost() // @TODO: Don't do this in production if possible. Try to limit it. + } } private val registeredModules = mutableMapOf() diff --git a/src/main/kotlin/dev/fyloz/musicplayer/core/data/RepositoryInjection.kt b/src/main/kotlin/dev/fyloz/musicplayer/core/data/RepositoryInjection.kt index 50ae9e2..614704c 100644 --- a/src/main/kotlin/dev/fyloz/musicplayer/core/data/RepositoryInjection.kt +++ b/src/main/kotlin/dev/fyloz/musicplayer/core/data/RepositoryInjection.kt @@ -1,10 +1,10 @@ package dev.fyloz.musicplayer.core.data -import dev.fyloz.musicplayer.core.data.memory.TrackMemoryRepository +import dev.fyloz.musicplayer.core.data.memory.SongMemoryRepository import org.koin.dsl.module object RepositoryInjection { val koinBeans = module { - single { TrackMemoryRepository() } + single { SongMemoryRepository() } } } diff --git a/src/main/kotlin/dev/fyloz/musicplayer/core/data/SongRepository.kt b/src/main/kotlin/dev/fyloz/musicplayer/core/data/SongRepository.kt new file mode 100644 index 0000000..1267585 --- /dev/null +++ b/src/main/kotlin/dev/fyloz/musicplayer/core/data/SongRepository.kt @@ -0,0 +1,5 @@ +package dev.fyloz.musicplayer.core.data + +import dev.fyloz.musicplayer.core.model.Song + +interface SongRepository : Repository diff --git a/src/main/kotlin/dev/fyloz/musicplayer/core/data/TrackRepository.kt b/src/main/kotlin/dev/fyloz/musicplayer/core/data/TrackRepository.kt deleted file mode 100644 index 86141a7..0000000 --- a/src/main/kotlin/dev/fyloz/musicplayer/core/data/TrackRepository.kt +++ /dev/null @@ -1,5 +0,0 @@ -package dev.fyloz.musicplayer.core.data - -import dev.fyloz.musicplayer.core.model.Track - -interface TrackRepository : Repository diff --git a/src/main/kotlin/dev/fyloz/musicplayer/core/data/memory/SongMemoryRepository.kt b/src/main/kotlin/dev/fyloz/musicplayer/core/data/memory/SongMemoryRepository.kt new file mode 100644 index 0000000..5005182 --- /dev/null +++ b/src/main/kotlin/dev/fyloz/musicplayer/core/data/memory/SongMemoryRepository.kt @@ -0,0 +1,8 @@ +package dev.fyloz.musicplayer.core.data.memory + +import dev.fyloz.musicplayer.core.data.SongRepository +import dev.fyloz.musicplayer.core.model.Song + +class SongMemoryRepository : BaseMemoryRepository(), SongRepository { + override fun getId(t: Song) = t.id +} diff --git a/src/main/kotlin/dev/fyloz/musicplayer/core/data/memory/TrackMemoryRepository.kt b/src/main/kotlin/dev/fyloz/musicplayer/core/data/memory/TrackMemoryRepository.kt deleted file mode 100644 index be81fb4..0000000 --- a/src/main/kotlin/dev/fyloz/musicplayer/core/data/memory/TrackMemoryRepository.kt +++ /dev/null @@ -1,8 +0,0 @@ -package dev.fyloz.musicplayer.core.data.memory - -import dev.fyloz.musicplayer.core.data.TrackRepository -import dev.fyloz.musicplayer.core.model.Track - -class TrackMemoryRepository : BaseMemoryRepository(), TrackRepository { - override fun getId(t: Track) = t.id -} diff --git a/src/main/kotlin/dev/fyloz/musicplayer/core/factory/SongFactory.kt b/src/main/kotlin/dev/fyloz/musicplayer/core/factory/SongFactory.kt new file mode 100644 index 0000000..a1c0391 --- /dev/null +++ b/src/main/kotlin/dev/fyloz/musicplayer/core/factory/SongFactory.kt @@ -0,0 +1,10 @@ +package dev.fyloz.musicplayer.core.factory + +import dev.fyloz.musicplayer.core.http.auth.AuthorizationData +import dev.fyloz.musicplayer.core.model.SearchResultItem +import dev.fyloz.musicplayer.core.model.Song + +interface SongFactory { + suspend fun search(query: String, auth: AuthorizationData): Collection + suspend fun create(id: String, songId: String, auth: AuthorizationData): Song +} diff --git a/src/main/kotlin/dev/fyloz/musicplayer/core/factory/SongFactoryProxy.kt b/src/main/kotlin/dev/fyloz/musicplayer/core/factory/SongFactoryProxy.kt new file mode 100644 index 0000000..9d0b304 --- /dev/null +++ b/src/main/kotlin/dev/fyloz/musicplayer/core/factory/SongFactoryProxy.kt @@ -0,0 +1,29 @@ +package dev.fyloz.musicplayer.core.factory + +import dev.fyloz.musicplayer.core.http.auth.AuthorizationData +import dev.fyloz.musicplayer.core.model.SearchResult +import dev.fyloz.musicplayer.core.model.SearchResultItem +import dev.fyloz.musicplayer.core.model.Song + +typealias STR = String + +class SongFactoryProxy { + private val factories = mutableMapOf() + + fun registerFactory(type: String, factory: SongFactory) { + factories[type] = factory; + } + + suspend fun search(query: String, auth: AuthorizationData): SearchResult { + val results = mutableMapOf>() + factories.forEach { (type, factory) -> + results[type] = factory.search(query, auth) + } + return results.toMap() + } + + suspend fun create(type: String, id: String, songId: String, auth: AuthorizationData): Song = + getFactory(type).create(id, songId, auth) + + private fun getFactory(type: String) = factories[type]!!; +} diff --git a/src/main/kotlin/dev/fyloz/musicplayer/core/factory/TrackFactory.kt b/src/main/kotlin/dev/fyloz/musicplayer/core/factory/TrackFactory.kt deleted file mode 100644 index 764efb4..0000000 --- a/src/main/kotlin/dev/fyloz/musicplayer/core/factory/TrackFactory.kt +++ /dev/null @@ -1,9 +0,0 @@ -package dev.fyloz.musicplayer.core.factory - -import dev.fyloz.musicplayer.core.http.auth.AuthorizationData -import dev.fyloz.musicplayer.core.model.Track - -interface TrackFactory { - suspend fun searchTrack(query: String, auth: AuthorizationData): Collection - suspend fun createTrack(id: String, trackId: String, auth: AuthorizationData): Track -} diff --git a/src/main/kotlin/dev/fyloz/musicplayer/core/factory/TrackFactoryProxy.kt b/src/main/kotlin/dev/fyloz/musicplayer/core/factory/TrackFactoryProxy.kt deleted file mode 100644 index 5b4579a..0000000 --- a/src/main/kotlin/dev/fyloz/musicplayer/core/factory/TrackFactoryProxy.kt +++ /dev/null @@ -1,20 +0,0 @@ -package dev.fyloz.musicplayer.core.factory - -import dev.fyloz.musicplayer.core.http.auth.AuthorizationData -import dev.fyloz.musicplayer.core.model.Track - -class TrackFactoryProxy { - private val factories = mutableMapOf() - - fun registerFactory(type: String, factory: TrackFactory) { - factories[type] = factory; - } - - suspend fun search(query: String, auth: AuthorizationData) = - factories.values.map { it.searchTrack(query, auth) }.flatten() - - suspend fun createTrack(type: String, id: String, trackId: String, auth: AuthorizationData): Track = - getFactory(type).createTrack(id, trackId, auth) - - private fun getFactory(type: String) = factories[type]!!; -} diff --git a/src/main/kotlin/dev/fyloz/musicplayer/core/http/HttpProvider.kt b/src/main/kotlin/dev/fyloz/musicplayer/core/http/HttpProvider.kt new file mode 100644 index 0000000..596b583 --- /dev/null +++ b/src/main/kotlin/dev/fyloz/musicplayer/core/http/HttpProvider.kt @@ -0,0 +1,53 @@ +package dev.fyloz.musicplayer.core.http + +import io.ktor.client.* +import io.ktor.client.call.* +import io.ktor.client.request.* +import io.ktor.client.statement.* +import io.ktor.http.* +import org.koin.core.component.KoinComponent +import org.koin.core.component.inject + +abstract class HttpProvider(private val baseUrl: String) : KoinComponent { + protected val httpClient by inject() + protected open val acceptContentType = ContentType.Application.Json + + protected suspend inline fun get( + path: String, + bearer: String? = null, + block: HttpRequestBuilder.() -> Unit = {} + ): T = + httpClient.get(path.toUrl()) { + accept(acceptContentType) + + headers { + if (bearer != null) { + append(HttpHeaders.Authorization, bearer.toBearer()) + } + } + + block() + }.process() + + protected suspend inline fun HttpResponse.process(): T { + if (this.status.isSuccess()) { + return this.body() + } + + throw IllegalStateException("TODO: Unsuccessful HTTP request: ${this.body()}") + } + + protected fun String.toUrl(): String { + if (baseUrl.endsWith('/') && this.startsWith('/')) { + return baseUrl + this.substring(1, this.length) + } + + if (!this.startsWith('/')) { + return "$baseUrl/$this" + } + + return baseUrl + this + } + + protected fun String.toBearer() = "Bearer $this" +} \ No newline at end of file diff --git a/src/main/kotlin/dev/fyloz/musicplayer/core/http/SongRoutes.kt b/src/main/kotlin/dev/fyloz/musicplayer/core/http/SongRoutes.kt new file mode 100644 index 0000000..ca63724 --- /dev/null +++ b/src/main/kotlin/dev/fyloz/musicplayer/core/http/SongRoutes.kt @@ -0,0 +1,32 @@ +package dev.fyloz.musicplayer.core.http + +import dev.fyloz.musicplayer.core.getAuthorizationData +import dev.fyloz.musicplayer.core.http.requests.CreateSongRequest +import dev.fyloz.musicplayer.core.logic.SongLogic +import io.ktor.server.application.* +import io.ktor.server.request.* +import io.ktor.server.response.* +import io.ktor.server.routing.* +import org.koin.ktor.ext.inject + +fun Route.configureSongRoutes() { + val logic by inject() + + route("/song") { + get("/") { + call.respond(logic.getAll().toList()) + } + + get("/search") { + val query = call.request.queryParameters["q"]!! + val songs = logic.search(query, call.getAuthorizationData()) + call.respond(songs) + } + + post { + val request = call.receive() + val song = logic.save(request.type, request.songId, call.getAuthorizationData()) + call.respond(song) + } + } +} diff --git a/src/main/kotlin/dev/fyloz/musicplayer/core/http/TrackRoutes.kt b/src/main/kotlin/dev/fyloz/musicplayer/core/http/TrackRoutes.kt deleted file mode 100644 index a798203..0000000 --- a/src/main/kotlin/dev/fyloz/musicplayer/core/http/TrackRoutes.kt +++ /dev/null @@ -1,32 +0,0 @@ -package dev.fyloz.musicplayer.core.http - -import dev.fyloz.musicplayer.core.getAuthorizationData -import dev.fyloz.musicplayer.core.http.requests.CreateTrackRequest -import dev.fyloz.musicplayer.core.logic.TrackLogic -import io.ktor.server.application.* -import io.ktor.server.request.* -import io.ktor.server.response.* -import io.ktor.server.routing.* -import org.koin.ktor.ext.inject - -fun Route.configureTrackRoutes() { - val logic by inject() - - route("/track") { - get("/") { - call.respond(logic.getAll().toList()) - } - - get("/search") { - val query = call.request.queryParameters["q"]!! - val tracks = logic.search(query, call.getAuthorizationData()) - call.respond(tracks) - } - - post { - val request = call.receive() - val track = logic.save(request.type, request.trackId, call.getAuthorizationData()) - call.respond(track) - } - } -} diff --git a/src/main/kotlin/dev/fyloz/musicplayer/core/http/requests/CreateTrackRequest.kt b/src/main/kotlin/dev/fyloz/musicplayer/core/http/requests/CreateSongRequest.kt similarity index 60% rename from src/main/kotlin/dev/fyloz/musicplayer/core/http/requests/CreateTrackRequest.kt rename to src/main/kotlin/dev/fyloz/musicplayer/core/http/requests/CreateSongRequest.kt index 315c746..c065b8d 100644 --- a/src/main/kotlin/dev/fyloz/musicplayer/core/http/requests/CreateTrackRequest.kt +++ b/src/main/kotlin/dev/fyloz/musicplayer/core/http/requests/CreateSongRequest.kt @@ -3,4 +3,4 @@ package dev.fyloz.musicplayer.core.http.requests import kotlinx.serialization.Serializable @Serializable -data class CreateTrackRequest(val type: String, val trackId: String) +data class CreateSongRequest(val type: String, val songId: String) diff --git a/src/main/kotlin/dev/fyloz/musicplayer/core/logic/SongLogic.kt b/src/main/kotlin/dev/fyloz/musicplayer/core/logic/SongLogic.kt new file mode 100644 index 0000000..8f1bb50 --- /dev/null +++ b/src/main/kotlin/dev/fyloz/musicplayer/core/logic/SongLogic.kt @@ -0,0 +1,31 @@ +package dev.fyloz.musicplayer.core.logic + +import dev.fyloz.musicplayer.core.data.SongRepository +import dev.fyloz.musicplayer.core.factory.SongFactoryProxy +import dev.fyloz.musicplayer.core.http.auth.AuthorizationData +import dev.fyloz.musicplayer.core.model.SearchResult +import dev.fyloz.musicplayer.core.model.Song +import org.koin.core.component.KoinComponent +import org.koin.core.component.inject +import java.util.UUID + +class SongLogic : KoinComponent { + private val repository by inject() + private val songFactory by inject() + + fun getAll() = repository.findAll() + fun getById(id: String) = repository.findById(id) + + suspend fun search(query: String, auth: AuthorizationData): SearchResult { + return songFactory.search(query, auth) + } + + suspend fun save(type: String, songId: String, auth: AuthorizationData): Song { + val id = generateId() + val song = songFactory.create(type, id, songId, auth) + repository.save(song) + return song + } + + private fun generateId() = UUID.randomUUID().toString() +} diff --git a/src/main/kotlin/dev/fyloz/musicplayer/core/logic/TrackLogic.kt b/src/main/kotlin/dev/fyloz/musicplayer/core/logic/TrackLogic.kt deleted file mode 100644 index af96ca5..0000000 --- a/src/main/kotlin/dev/fyloz/musicplayer/core/logic/TrackLogic.kt +++ /dev/null @@ -1,30 +0,0 @@ -package dev.fyloz.musicplayer.core.logic - -import dev.fyloz.musicplayer.core.data.TrackRepository -import dev.fyloz.musicplayer.core.factory.TrackFactoryProxy -import dev.fyloz.musicplayer.core.http.auth.AuthorizationData -import dev.fyloz.musicplayer.core.model.Track -import org.koin.core.component.KoinComponent -import org.koin.core.component.inject -import java.util.UUID - -class TrackLogic : KoinComponent { - private val repository by inject() - private val trackFactory by inject() - - fun getAll() = repository.findAll() - fun getById(id: String) = repository.findById(id) - - suspend fun search(query: String, auth: AuthorizationData): Collection { - return trackFactory.search(query, auth) - } - - suspend fun save(type: String, trackId: String, auth: AuthorizationData): Track { - val id = generateId() - val track = trackFactory.createTrack(type, id, trackId, auth) - repository.save(track) - return track - } - - private fun generateId() = UUID.randomUUID().toString() -} diff --git a/src/main/kotlin/dev/fyloz/musicplayer/core/model/SearchResult.kt b/src/main/kotlin/dev/fyloz/musicplayer/core/model/SearchResult.kt new file mode 100644 index 0000000..c620318 --- /dev/null +++ b/src/main/kotlin/dev/fyloz/musicplayer/core/model/SearchResult.kt @@ -0,0 +1,12 @@ +package dev.fyloz.musicplayer.core.model + +import kotlinx.serialization.Serializable + +typealias SearchResult = Map> + +@Serializable +data class SearchResultItem( + val songId: String, + val name: String, + val authors: Collection +) \ No newline at end of file diff --git a/src/main/kotlin/dev/fyloz/musicplayer/core/model/Song.kt b/src/main/kotlin/dev/fyloz/musicplayer/core/model/Song.kt new file mode 100644 index 0000000..0fcfded --- /dev/null +++ b/src/main/kotlin/dev/fyloz/musicplayer/core/model/Song.kt @@ -0,0 +1,18 @@ +package dev.fyloz.musicplayer.core.model + +/** + * A generic song. + */ +abstract class Song { + /** The id of the song in the local system. **/ + abstract val id: String + + /** The id of the song in the remote service. **/ + abstract val songId: String + + /** The name of the song. **/ + abstract val name: String + + /** The name of the authors of the song. **/ + abstract val authors: Collection +} diff --git a/src/main/kotlin/dev/fyloz/musicplayer/core/model/Track.kt b/src/main/kotlin/dev/fyloz/musicplayer/core/model/Track.kt deleted file mode 100644 index f9e742a..0000000 --- a/src/main/kotlin/dev/fyloz/musicplayer/core/model/Track.kt +++ /dev/null @@ -1,15 +0,0 @@ -package dev.fyloz.musicplayer.core.model - -/** - * A generic track. - */ -abstract class Track { - /** The id of the track in the local system. **/ - abstract val id: String - - /** The id of the track in the remote service. **/ - abstract val trackId: String - - /** The name of the track. **/ - abstract val name: String -} diff --git a/src/main/kotlin/dev/fyloz/musicplayer/modules/Module.kt b/src/main/kotlin/dev/fyloz/musicplayer/modules/Module.kt index 769a7bb..2d911e4 100644 --- a/src/main/kotlin/dev/fyloz/musicplayer/modules/Module.kt +++ b/src/main/kotlin/dev/fyloz/musicplayer/modules/Module.kt @@ -1,8 +1,8 @@ package dev.fyloz.musicplayer.modules import dev.fyloz.musicplayer.core.KoinModule -import dev.fyloz.musicplayer.core.factory.TrackFactory -import dev.fyloz.musicplayer.core.factory.TrackFactoryProxy +import dev.fyloz.musicplayer.core.factory.SongFactory +import dev.fyloz.musicplayer.core.factory.SongFactoryProxy import io.ktor.server.application.* import io.ktor.server.config.* import io.ktor.server.routing.* @@ -14,8 +14,8 @@ abstract class Module(private val moduleName: String) { open fun configure(app: Application) { with(app) { - val trackFactoryProxy by inject() - trackFactoryProxy.registerFactory(moduleName, getTrackFactory()) + val songFactoryProxy by inject() + songFactoryProxy.registerFactory(moduleName, getSongFactory()) } } @@ -39,5 +39,5 @@ abstract class Module(private val moduleName: String) { protected open fun Route.configureModuleRoutes() { } - protected abstract fun getTrackFactory(): TrackFactory + protected abstract fun getSongFactory(): SongFactory } diff --git a/src/main/kotlin/dev/fyloz/musicplayer/modules/spotify/SpotifyApiProvider.kt b/src/main/kotlin/dev/fyloz/musicplayer/modules/spotify/SpotifyApiProvider.kt index 1a75ffe..52acfaf 100644 --- a/src/main/kotlin/dev/fyloz/musicplayer/modules/spotify/SpotifyApiProvider.kt +++ b/src/main/kotlin/dev/fyloz/musicplayer/modules/spotify/SpotifyApiProvider.kt @@ -1,26 +1,12 @@ package dev.fyloz.musicplayer.modules.spotify -import dev.fyloz.musicplayer.modules.spotify.api.SearchRequest +import dev.fyloz.musicplayer.core.http.HttpProvider import dev.fyloz.musicplayer.modules.spotify.api.SearchResponse import dev.fyloz.musicplayer.modules.spotify.api.Track -import io.ktor.client.* -import io.ktor.client.call.* -import io.ktor.client.request.* -import io.ktor.http.* -import org.koin.core.component.KoinComponent -import org.koin.core.component.inject -class SpotifyApiProvider : KoinComponent { - private val client by inject() - - suspend fun search(query: String, type: String, accessToken: String): Collection { - val requestBody = SearchRequest(query, type, "audio", 50, 0) - val response = client.get("https://api.spotify.com/v1/search") { - accept(ContentType.Application.Json) - headers { - append(HttpHeaders.Authorization, "Bearer $accessToken") - } -// setBody(requestBody) +class SpotifyApiProvider : HttpProvider("https://api.spotify.com/v1") { + suspend fun search(query: String, type: String, accessToken: String): Collection = + get("search", accessToken) { url { parameters.append("q", query) parameters.append("type", type) @@ -28,19 +14,8 @@ class SpotifyApiProvider : KoinComponent { parameters.append("limit", "50") parameters.append("offset", "0") } - }.body() + }.tracks.items - return response.tracks.items - } - - suspend fun getTrackById(trackId: String, accessToken: String): Track { - val response = client.get("https://api.spotify.com/v1/tracks/$trackId") { - accept(ContentType.Application.Json) - headers { - append(HttpHeaders.Authorization, "Bearer $accessToken") - } - } - - return response.body() - } + suspend fun getSongById(songId: String, accessToken: String): Track = + get("tracks/$songId", accessToken) } diff --git a/src/main/kotlin/dev/fyloz/musicplayer/modules/spotify/SpotifyInjection.kt b/src/main/kotlin/dev/fyloz/musicplayer/modules/spotify/SpotifyInjection.kt index eba679a..9090eb8 100644 --- a/src/main/kotlin/dev/fyloz/musicplayer/modules/spotify/SpotifyInjection.kt +++ b/src/main/kotlin/dev/fyloz/musicplayer/modules/spotify/SpotifyInjection.kt @@ -4,6 +4,6 @@ import org.koin.dsl.module object SpotifyInjection { val koinBeans = module { - single { SpotifyTrackFactory() } + single { SpotifySongFactory() } } } diff --git a/src/main/kotlin/dev/fyloz/musicplayer/modules/spotify/SpotifyModule.kt b/src/main/kotlin/dev/fyloz/musicplayer/modules/spotify/SpotifyModule.kt index 661313e..8b8f1d7 100644 --- a/src/main/kotlin/dev/fyloz/musicplayer/modules/spotify/SpotifyModule.kt +++ b/src/main/kotlin/dev/fyloz/musicplayer/modules/spotify/SpotifyModule.kt @@ -59,15 +59,15 @@ class SpotifyModule : Module(moduleName) { get("/login-callback") { call.principal()?.let { with(call.response.cookies) { - append("Spotify-Access-Token", it.accessToken, maxAge = it.expiresIn) - append("Spotify-Refresh-Token", it.refreshToken!!) + append("Spotify-Access-Token", it.accessToken, maxAge = it.expiresIn, path = "/api/v1") + append("Spotify-Refresh-Token", it.refreshToken!!, path = "/api/v1") } } } } } - override fun getTrackFactory() = SpotifyTrackFactory() + override fun getSongFactory() = SpotifySongFactory() companion object { const val moduleName = "spotify" diff --git a/src/main/kotlin/dev/fyloz/musicplayer/modules/spotify/SpotifySong.kt b/src/main/kotlin/dev/fyloz/musicplayer/modules/spotify/SpotifySong.kt new file mode 100644 index 0000000..5846d07 --- /dev/null +++ b/src/main/kotlin/dev/fyloz/musicplayer/modules/spotify/SpotifySong.kt @@ -0,0 +1,12 @@ +package dev.fyloz.musicplayer.modules.spotify + +import dev.fyloz.musicplayer.core.model.Song +import kotlinx.serialization.Serializable + +@Serializable +data class SpotifySong( + override val id: String, + override val songId: String, + override val name: String, + override val authors: Collection +) : Song() diff --git a/src/main/kotlin/dev/fyloz/musicplayer/modules/spotify/SpotifySongFactory.kt b/src/main/kotlin/dev/fyloz/musicplayer/modules/spotify/SpotifySongFactory.kt new file mode 100644 index 0000000..59036f0 --- /dev/null +++ b/src/main/kotlin/dev/fyloz/musicplayer/modules/spotify/SpotifySongFactory.kt @@ -0,0 +1,23 @@ +package dev.fyloz.musicplayer.modules.spotify + +import dev.fyloz.musicplayer.core.factory.SongFactory +import dev.fyloz.musicplayer.core.http.auth.AuthorizationData +import dev.fyloz.musicplayer.core.model.SearchResultItem +import dev.fyloz.musicplayer.core.model.Song + +class SpotifySongFactory : SongFactory { + private val apiProvider = SpotifyApiProvider() + + override suspend fun search(query: String, auth: AuthorizationData): Collection { + val apiSongs = apiProvider.search(query, "track", auth.accessToken) + return apiSongs.map { SearchResultItem(it.id, it.name, it.artists.map { a -> a.name }) } + } + + override suspend fun create(id: String, songId: String, auth: AuthorizationData): Song { + val spotifyApiSong = apiProvider.getSongById(songId, auth.accessToken); + return SpotifySong(id, songId, spotifyApiSong.name, spotifyApiSong.artists.map { it.name }) + } + + private val AuthorizationData.accessToken + get() = getModuleData(SpotifyModule.moduleName).accessToken +} diff --git a/src/main/kotlin/dev/fyloz/musicplayer/modules/spotify/SpotifyTrack.kt b/src/main/kotlin/dev/fyloz/musicplayer/modules/spotify/SpotifyTrack.kt deleted file mode 100644 index 65a8d16..0000000 --- a/src/main/kotlin/dev/fyloz/musicplayer/modules/spotify/SpotifyTrack.kt +++ /dev/null @@ -1,11 +0,0 @@ -package dev.fyloz.musicplayer.modules.spotify - -import dev.fyloz.musicplayer.core.model.Track -import kotlinx.serialization.Serializable - -@Serializable -data class SpotifyTrack( - override val id: String, - override val trackId: String, - override val name: String -) : Track() diff --git a/src/main/kotlin/dev/fyloz/musicplayer/modules/spotify/SpotifyTrackFactory.kt b/src/main/kotlin/dev/fyloz/musicplayer/modules/spotify/SpotifyTrackFactory.kt deleted file mode 100644 index 738692a..0000000 --- a/src/main/kotlin/dev/fyloz/musicplayer/modules/spotify/SpotifyTrackFactory.kt +++ /dev/null @@ -1,22 +0,0 @@ -package dev.fyloz.musicplayer.modules.spotify - -import dev.fyloz.musicplayer.core.factory.TrackFactory -import dev.fyloz.musicplayer.core.http.auth.AuthorizationData -import dev.fyloz.musicplayer.core.model.Track - -class SpotifyTrackFactory : TrackFactory { - private val apiProvider = SpotifyApiProvider() - - override suspend fun searchTrack(query: String, auth: AuthorizationData): Collection { - val apiTracks = apiProvider.search(query, "track", auth.accessToken) - return apiTracks.map { SpotifyTrack("not-an-id", it.id, it.name) } - } - - override suspend fun createTrack(id: String, trackId: String, auth: AuthorizationData): Track { - val spotifyApiTrack = apiProvider.getTrackById(trackId, auth.accessToken); - return SpotifyTrack(id, trackId, spotifyApiTrack.name) - } - - private val AuthorizationData.accessToken - get() = getModuleData(SpotifyModule.moduleName).accessToken -} diff --git a/src/main/kotlin/dev/fyloz/musicplayer/modules/spotify/api/SearchRequest.kt b/src/main/kotlin/dev/fyloz/musicplayer/modules/spotify/api/SearchRequest.kt deleted file mode 100644 index a29008c..0000000 --- a/src/main/kotlin/dev/fyloz/musicplayer/modules/spotify/api/SearchRequest.kt +++ /dev/null @@ -1,19 +0,0 @@ -package dev.fyloz.musicplayer.modules.spotify.api - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -@Serializable -data class SearchRequest( - @SerialName("q") - val query: String, - - val type: String, - - @SerialName("include_external") - val includeExternal: String, - - val limit: Int, - - val offset: Int -) diff --git a/src/main/kotlin/dev/fyloz/musicplayer/modules/spotify/api/SearchResponse.kt b/src/main/kotlin/dev/fyloz/musicplayer/modules/spotify/api/SearchResponse.kt index 8f28bdd..4e7a8a4 100644 --- a/src/main/kotlin/dev/fyloz/musicplayer/modules/spotify/api/SearchResponse.kt +++ b/src/main/kotlin/dev/fyloz/musicplayer/modules/spotify/api/SearchResponse.kt @@ -1,6 +1,5 @@ package dev.fyloz.musicplayer.modules.spotify.api -import dev.fyloz.musicplayer.modules.spotify.SpotifyTrack import kotlinx.serialization.Serializable @Serializable