Things
This commit is contained in:
parent
a73ba4cd77
commit
71cb4abae9
|
@ -2,10 +2,10 @@ package dev.fyloz.musicplayer.core
|
||||||
|
|
||||||
import com.typesafe.config.ConfigFactory
|
import com.typesafe.config.ConfigFactory
|
||||||
import dev.fyloz.musicplayer.core.data.RepositoryInjection
|
import dev.fyloz.musicplayer.core.data.RepositoryInjection
|
||||||
import dev.fyloz.musicplayer.core.factory.SongFactoryProxy
|
import dev.fyloz.musicplayer.core.factory.TrackFactoryProxy
|
||||||
import dev.fyloz.musicplayer.core.http.auth.AuthorizationData
|
import dev.fyloz.musicplayer.core.http.auth.AuthorizationData
|
||||||
import dev.fyloz.musicplayer.core.http.configureSongRoutes
|
import dev.fyloz.musicplayer.core.http.configureTrackRoutes
|
||||||
import dev.fyloz.musicplayer.core.logic.SongLogic
|
import dev.fyloz.musicplayer.core.logic.TrackLogic
|
||||||
import dev.fyloz.musicplayer.modules.Module
|
import dev.fyloz.musicplayer.modules.Module
|
||||||
import io.ktor.client.*
|
import io.ktor.client.*
|
||||||
import io.ktor.http.*
|
import io.ktor.http.*
|
||||||
|
@ -51,8 +51,8 @@ fun Application.module() {
|
||||||
RepositoryInjection.koinBeans,
|
RepositoryInjection.koinBeans,
|
||||||
|
|
||||||
module {
|
module {
|
||||||
single { SongFactoryProxy() }
|
single { TrackFactoryProxy() }
|
||||||
single { SongLogic() }
|
single { TrackLogic() }
|
||||||
single {
|
single {
|
||||||
HttpClient {
|
HttpClient {
|
||||||
install(io.ktor.client.plugins.contentnegotiation.ContentNegotiation) {
|
install(io.ktor.client.plugins.contentnegotiation.ContentNegotiation) {
|
||||||
|
@ -80,18 +80,19 @@ fun Application.module() {
|
||||||
registeredModules.values.forEach { it.configureRoutes(this) }
|
registeredModules.values.forEach { it.configureRoutes(this) }
|
||||||
|
|
||||||
route("/api/v1") {
|
route("/api/v1") {
|
||||||
configureSongRoutes()
|
configureTrackRoutes()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
install(CORS) {
|
install(CORS) {
|
||||||
allowMethod(HttpMethod.Options)
|
allowMethod(HttpMethod.Options)
|
||||||
|
allowMethod(HttpMethod.Post)
|
||||||
allowMethod(HttpMethod.Put)
|
allowMethod(HttpMethod.Put)
|
||||||
allowMethod(HttpMethod.Delete)
|
allowMethod(HttpMethod.Delete)
|
||||||
allowMethod(HttpMethod.Patch)
|
allowHeader(HttpHeaders.AccessControlAllowOrigin)
|
||||||
allowHeader(HttpHeaders.Authorization)
|
allowHeader(HttpHeaders.ContentType)
|
||||||
allowHeader("MyCustomHeader")
|
|
||||||
anyHost() // @TODO: Don't do this in production if possible. Try to limit it.
|
anyHost() // @TODO: Don't do this in production if possible. Try to limit it.
|
||||||
|
allowCredentials = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
package dev.fyloz.musicplayer.core
|
||||||
|
|
||||||
|
fun <K, V> MutableMap<K, V>.removeIf(predicate: (V) -> Boolean) {
|
||||||
|
this.filterValues(predicate).map { it.key }.forEach(this::remove)
|
||||||
|
}
|
|
@ -1,10 +1,10 @@
|
||||||
package dev.fyloz.musicplayer.core.data
|
package dev.fyloz.musicplayer.core.data
|
||||||
|
|
||||||
import dev.fyloz.musicplayer.core.data.memory.SongMemoryRepository
|
import dev.fyloz.musicplayer.core.data.memory.TrackMemoryRepository
|
||||||
import org.koin.dsl.module
|
import org.koin.dsl.module
|
||||||
|
|
||||||
object RepositoryInjection {
|
object RepositoryInjection {
|
||||||
val koinBeans = module {
|
val koinBeans = module {
|
||||||
single<SongRepository> { SongMemoryRepository() }
|
single<TrackRepository> { TrackMemoryRepository() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
package dev.fyloz.musicplayer.core.data
|
|
||||||
|
|
||||||
import dev.fyloz.musicplayer.core.model.Song
|
|
||||||
|
|
||||||
interface SongRepository : Repository<Song>
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
package dev.fyloz.musicplayer.core.data
|
||||||
|
|
||||||
|
import dev.fyloz.musicplayer.core.model.Track
|
||||||
|
|
||||||
|
interface TrackRepository : Repository<Track> {
|
||||||
|
fun deleteByTrackId(trackId: String, source: String)
|
||||||
|
}
|
|
@ -3,7 +3,7 @@ package dev.fyloz.musicplayer.core.data.memory
|
||||||
import dev.fyloz.musicplayer.core.data.Repository
|
import dev.fyloz.musicplayer.core.data.Repository
|
||||||
|
|
||||||
abstract class BaseMemoryRepository<T> : Repository<T> {
|
abstract class BaseMemoryRepository<T> : Repository<T> {
|
||||||
private val memoryCache = mutableMapOf<String, T>()
|
protected val memoryCache = mutableMapOf<String, T>()
|
||||||
|
|
||||||
override fun findAll() = memoryCache.values
|
override fun findAll() = memoryCache.values
|
||||||
override fun findById(id: String) = memoryCache[id]
|
override fun findById(id: String) = memoryCache[id]
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
package dev.fyloz.musicplayer.core.data.memory
|
|
||||||
|
|
||||||
import dev.fyloz.musicplayer.core.data.SongRepository
|
|
||||||
import dev.fyloz.musicplayer.core.model.Song
|
|
||||||
|
|
||||||
class SongMemoryRepository : BaseMemoryRepository<Song>(), SongRepository {
|
|
||||||
override fun getId(t: Song) = t.id
|
|
||||||
}
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
package dev.fyloz.musicplayer.core.data.memory
|
||||||
|
|
||||||
|
import dev.fyloz.musicplayer.core.data.TrackRepository
|
||||||
|
import dev.fyloz.musicplayer.core.model.Track
|
||||||
|
import dev.fyloz.musicplayer.core.removeIf
|
||||||
|
|
||||||
|
class TrackMemoryRepository : BaseMemoryRepository<Track>(), TrackRepository {
|
||||||
|
override fun deleteByTrackId(trackId: String, source: String) {
|
||||||
|
memoryCache.removeIf { it.source == source && it.trackId == trackId }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getId(t: Track) = t.id
|
||||||
|
}
|
|
@ -1,10 +0,0 @@
|
||||||
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<SearchResultItem>
|
|
||||||
suspend fun create(id: String, songId: String, auth: AuthorizationData): Song
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
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<String, SongFactory>()
|
|
||||||
|
|
||||||
fun registerFactory(type: String, factory: SongFactory) {
|
|
||||||
factories[type] = factory;
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun search(query: String, auth: AuthorizationData): SearchResult {
|
|
||||||
val results = mutableMapOf<String, Collection<SearchResultItem>>()
|
|
||||||
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]!!;
|
|
||||||
}
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
package dev.fyloz.musicplayer.core.factory
|
||||||
|
|
||||||
|
import dev.fyloz.musicplayer.core.http.auth.AuthorizationData
|
||||||
|
import dev.fyloz.musicplayer.core.model.ExternalTrack
|
||||||
|
import dev.fyloz.musicplayer.core.model.Track
|
||||||
|
|
||||||
|
interface TrackFactory {
|
||||||
|
suspend fun search(query: String, auth: AuthorizationData): Collection<ExternalTrack>
|
||||||
|
suspend fun create(id: String, trackId: String, auth: AuthorizationData): Track
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
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.ExternalTrack
|
||||||
|
import dev.fyloz.musicplayer.core.model.Track
|
||||||
|
|
||||||
|
class TrackFactoryProxy {
|
||||||
|
private val factories = mutableMapOf<String, TrackFactory>()
|
||||||
|
|
||||||
|
fun registerFactory(source: String, factory: TrackFactory) {
|
||||||
|
factories[source] = factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun search(query: String, auth: AuthorizationData): SearchResult {
|
||||||
|
val results = mutableMapOf<String, Collection<ExternalTrack>>()
|
||||||
|
factories.forEach { (source, factory) ->
|
||||||
|
results[source] = factory.search(query, auth)
|
||||||
|
}
|
||||||
|
return results.toMap()
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun create(source: String, id: String, trackId: String, auth: AuthorizationData): Track =
|
||||||
|
getFactory(source).create(id, trackId, auth)
|
||||||
|
|
||||||
|
private fun getFactory(source: String) = factories[source]!!;
|
||||||
|
}
|
|
@ -1,32 +0,0 @@
|
||||||
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<SongLogic>()
|
|
||||||
|
|
||||||
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<CreateSongRequest>()
|
|
||||||
val song = logic.save(request.type, request.songId, call.getAuthorizationData())
|
|
||||||
call.respond(song)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
package dev.fyloz.musicplayer.core.http
|
||||||
|
|
||||||
|
import dev.fyloz.musicplayer.core.getAuthorizationData
|
||||||
|
import dev.fyloz.musicplayer.core.http.requests.ImportTrackRequest
|
||||||
|
import dev.fyloz.musicplayer.core.logic.TrackLogic
|
||||||
|
import io.ktor.http.*
|
||||||
|
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<TrackLogic>()
|
||||||
|
|
||||||
|
route("/tracks") {
|
||||||
|
get("/") {
|
||||||
|
call.respond(logic.getAll().toList())
|
||||||
|
}
|
||||||
|
|
||||||
|
get("/trackIds/") {
|
||||||
|
call.respond(logic.getAllTrackIdsBySource())
|
||||||
|
}
|
||||||
|
|
||||||
|
get("/search") {
|
||||||
|
val query = call.request.queryParameters["q"]!!
|
||||||
|
val tracks = logic.search(query, call.getAuthorizationData())
|
||||||
|
call.respond(tracks)
|
||||||
|
}
|
||||||
|
|
||||||
|
post("/") {
|
||||||
|
val request = call.receive<ImportTrackRequest>()
|
||||||
|
val track = logic.save(request.source, request.trackId, call.getAuthorizationData())
|
||||||
|
call.respond(HttpStatusCode.Created, track)
|
||||||
|
}
|
||||||
|
|
||||||
|
delete("/trackId/{source}/{trackId}") {
|
||||||
|
val source = call.parameters["source"]
|
||||||
|
val trackId = call.parameters["trackId"]
|
||||||
|
|
||||||
|
if (source != null && trackId != null) {
|
||||||
|
logic.deleteByTrackId(trackId, source)
|
||||||
|
call.respond(HttpStatusCode.NoContent)
|
||||||
|
} else {
|
||||||
|
call.respond(HttpStatusCode.BadRequest)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,4 +3,4 @@ package dev.fyloz.musicplayer.core.http.requests
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class CreateSongRequest(val type: String, val songId: String)
|
data class ImportTrackRequest(val source: String, val trackId: String)
|
|
@ -1,31 +0,0 @@
|
||||||
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<SongRepository>()
|
|
||||||
private val songFactory by inject<SongFactoryProxy>()
|
|
||||||
|
|
||||||
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()
|
|
||||||
}
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
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.SearchResult
|
||||||
|
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<TrackRepository>()
|
||||||
|
private val trackFactory by inject<TrackFactoryProxy>()
|
||||||
|
|
||||||
|
fun getAll() = repository.findAll()
|
||||||
|
fun getAllTrackIdsBySource() = getAll()
|
||||||
|
.groupBy { it.source }
|
||||||
|
.mapValues { it.value.map { track -> track.trackId } }
|
||||||
|
|
||||||
|
fun getById(id: String) = repository.findById(id)
|
||||||
|
|
||||||
|
suspend fun search(query: String, auth: AuthorizationData): SearchResult {
|
||||||
|
return trackFactory.search(query, auth)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun save(source: String, trackId: String, auth: AuthorizationData): Track {
|
||||||
|
val id = generateId()
|
||||||
|
val track = trackFactory.create(source, id, trackId, auth)
|
||||||
|
repository.save(track)
|
||||||
|
return track
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deleteByTrackId(trackId: String, source: String) {
|
||||||
|
repository.deleteByTrackId(trackId, source)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateId() = UUID.randomUUID().toString()
|
||||||
|
}
|
|
@ -2,11 +2,14 @@ package dev.fyloz.musicplayer.core.model
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
typealias SearchResult = Map<String, Collection<SearchResultItem>>
|
typealias SearchResult = Map<String, Collection<ExternalTrack>>
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class SearchResultItem(
|
data class ExternalTrack(
|
||||||
val songId: String,
|
val trackId: String,
|
||||||
val name: String,
|
val name: String,
|
||||||
val authors: Collection<String>
|
val albumName: String,
|
||||||
|
val authors: Collection<String>,
|
||||||
|
val thumbnailUrl: String,
|
||||||
|
val previewUrl: String
|
||||||
)
|
)
|
|
@ -1,18 +0,0 @@
|
||||||
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<String>
|
|
||||||
}
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
package dev.fyloz.musicplayer.core.model
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
|
||||||
|
/** The name of the authors of the track. **/
|
||||||
|
abstract val authors: Collection<String>
|
||||||
|
|
||||||
|
/** The name of the source module of the track. **/
|
||||||
|
abstract val source: String
|
||||||
|
|
||||||
|
/** The URLs to the track images. **/
|
||||||
|
abstract val imagesUrls: TrackImagesUrls
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class TrackImagesUrls(
|
||||||
|
/** The URL of the track icon. **/
|
||||||
|
val icon: String,
|
||||||
|
|
||||||
|
/** The URL of the track thumbnail. **/
|
||||||
|
val thumbnail: String,
|
||||||
|
|
||||||
|
/** The URL of the track's full resolution image. **/
|
||||||
|
val fullRes: String
|
||||||
|
)
|
|
@ -1,8 +1,8 @@
|
||||||
package dev.fyloz.musicplayer.modules
|
package dev.fyloz.musicplayer.modules
|
||||||
|
|
||||||
import dev.fyloz.musicplayer.core.KoinModule
|
import dev.fyloz.musicplayer.core.KoinModule
|
||||||
import dev.fyloz.musicplayer.core.factory.SongFactory
|
import dev.fyloz.musicplayer.core.factory.TrackFactory
|
||||||
import dev.fyloz.musicplayer.core.factory.SongFactoryProxy
|
import dev.fyloz.musicplayer.core.factory.TrackFactoryProxy
|
||||||
import io.ktor.server.application.*
|
import io.ktor.server.application.*
|
||||||
import io.ktor.server.config.*
|
import io.ktor.server.config.*
|
||||||
import io.ktor.server.routing.*
|
import io.ktor.server.routing.*
|
||||||
|
@ -14,8 +14,8 @@ abstract class Module(private val moduleName: String) {
|
||||||
|
|
||||||
open fun configure(app: Application) {
|
open fun configure(app: Application) {
|
||||||
with(app) {
|
with(app) {
|
||||||
val songFactoryProxy by inject<SongFactoryProxy>()
|
val trackFactoryProxy by inject<TrackFactoryProxy>()
|
||||||
songFactoryProxy.registerFactory(moduleName, getSongFactory())
|
trackFactoryProxy.registerFactory(moduleName, getTrackFactory())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,5 +39,5 @@ abstract class Module(private val moduleName: String) {
|
||||||
protected open fun Route.configureModuleRoutes() {
|
protected open fun Route.configureModuleRoutes() {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract fun getSongFactory(): SongFactory
|
protected abstract fun getTrackFactory(): TrackFactory
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,6 @@ class SpotifyApiProvider : HttpProvider("https://api.spotify.com/v1") {
|
||||||
}
|
}
|
||||||
}.tracks.items
|
}.tracks.items
|
||||||
|
|
||||||
suspend fun getSongById(songId: String, accessToken: String): Track =
|
suspend fun getTrackById(trackId: String, accessToken: String): Track =
|
||||||
get("tracks/$songId", accessToken)
|
get("tracks/$trackId", accessToken)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,6 @@ import org.koin.dsl.module
|
||||||
|
|
||||||
object SpotifyInjection {
|
object SpotifyInjection {
|
||||||
val koinBeans = module {
|
val koinBeans = module {
|
||||||
single<SpotifySongFactory> { SpotifySongFactory() }
|
single<SpotifyTrackFactory> { SpotifyTrackFactory() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,8 @@ class SpotifyModule : Module(moduleName) {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getAuthorizationData(call: ApplicationCall) = SpotifyAuthorizationData(
|
override fun getAuthorizationData(call: ApplicationCall) = SpotifyAuthorizationData(
|
||||||
call.request.cookies["Spotify-Access-Token"]!!
|
// call.request.cookies["Spotify-Access-Token"]!!
|
||||||
|
"BQA5jMFjiPuGgPJ8ogizGh3lR82HIGnkGAZQWFcUSOzIeoGonRleiJ1VUueUlfRpBPBjczBzNZY3EWEHC8kU21SzSyz__DPcZouA2Geyy1obEmbTar8OhQn640JU8VoszpsDFoZTyEAQATbKHVlq6n7Vb51S_nqFHcYww_rUfwObuVRumydpU8rHqWqr"
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun Route.configureModuleRoutes() {
|
override fun Route.configureModuleRoutes() {
|
||||||
|
@ -67,7 +68,7 @@ class SpotifyModule : Module(moduleName) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getSongFactory() = SpotifySongFactory()
|
override fun getTrackFactory() = SpotifyTrackFactory()
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val moduleName = "spotify"
|
const val moduleName = "spotify"
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
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<String>
|
|
||||||
) : Song()
|
|
|
@ -1,23 +0,0 @@
|
||||||
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<SearchResultItem> {
|
|
||||||
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<SpotifyAuthorizationData>(SpotifyModule.moduleName).accessToken
|
|
||||||
}
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
package dev.fyloz.musicplayer.modules.spotify
|
||||||
|
|
||||||
|
import dev.fyloz.musicplayer.core.model.Track
|
||||||
|
import dev.fyloz.musicplayer.core.model.TrackImagesUrls
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class SpotifyTrack(
|
||||||
|
override val id: String,
|
||||||
|
override val trackId: String,
|
||||||
|
override val name: String,
|
||||||
|
override val authors: Collection<String>,
|
||||||
|
override val imagesUrls: TrackImagesUrls
|
||||||
|
) : Track() {
|
||||||
|
override val source = SpotifyModule.moduleName
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
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.ExternalTrack
|
||||||
|
import dev.fyloz.musicplayer.core.model.Track
|
||||||
|
import dev.fyloz.musicplayer.core.model.TrackImagesUrls
|
||||||
|
|
||||||
|
class SpotifyTrackFactory : TrackFactory {
|
||||||
|
private val apiProvider = SpotifyApiProvider()
|
||||||
|
|
||||||
|
override suspend fun search(query: String, auth: AuthorizationData): Collection<ExternalTrack> {
|
||||||
|
val tracks = apiProvider.search(query, "track", auth.accessToken)
|
||||||
|
|
||||||
|
return tracks.map {
|
||||||
|
val artists = it.artists.map { artist -> artist.name }
|
||||||
|
val thumbnailUrl = it.album.images.first { image -> image.width == 300 }.url
|
||||||
|
|
||||||
|
ExternalTrack(it.id, it.name, it.album.name, artists, thumbnailUrl, it.previewUrl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun create(id: String, trackId: String, auth: AuthorizationData): Track {
|
||||||
|
val spotifyApiTrack = apiProvider.getTrackById(trackId, auth.accessToken)
|
||||||
|
val artists = spotifyApiTrack.artists.map { it.name }
|
||||||
|
val imagesUrls = TrackImagesUrls(
|
||||||
|
spotifyApiTrack.album.images.first { it.width == 64 }.url,
|
||||||
|
spotifyApiTrack.album.images.first { it.width == 300 }.url,
|
||||||
|
spotifyApiTrack.album.images.first { it.width == 640 }.url
|
||||||
|
)
|
||||||
|
|
||||||
|
return SpotifyTrack(id, trackId, spotifyApiTrack.name, artists, imagesUrls)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val AuthorizationData.accessToken
|
||||||
|
get() = getModuleData<SpotifyAuthorizationData>(SpotifyModule.moduleName).accessToken
|
||||||
|
}
|
Loading…
Reference in New Issue