musikr: refactor model
This commit is contained in:
parent
1d0ad641d5
commit
501c79d23c
12 changed files with 470 additions and 371 deletions
|
@ -29,9 +29,9 @@ import org.oxycblt.musikr.Indexer
|
|||
import org.oxycblt.musikr.IndexingProgress
|
||||
import org.oxycblt.musikr.Library
|
||||
import org.oxycblt.musikr.Music
|
||||
import org.oxycblt.musikr.MutableLibrary
|
||||
import org.oxycblt.musikr.Playlist
|
||||
import org.oxycblt.musikr.Song
|
||||
import org.oxycblt.musikr.model.MutableLibrary
|
||||
import org.oxycblt.musikr.tag.Interpretation
|
||||
import org.oxycblt.musikr.tag.Name
|
||||
import org.oxycblt.musikr.tag.interpret.Separators
|
||||
|
|
|
@ -26,7 +26,6 @@ import kotlinx.coroutines.flow.onCompletion
|
|||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.onStart
|
||||
import org.oxycblt.musikr.fs.MusicLocation
|
||||
import org.oxycblt.musikr.model.MutableLibrary
|
||||
import org.oxycblt.musikr.pipeline.EvaluateStep
|
||||
import org.oxycblt.musikr.pipeline.ExploreStep
|
||||
import org.oxycblt.musikr.pipeline.ExtractStep
|
||||
|
|
|
@ -61,6 +61,18 @@ interface Library {
|
|||
fun findPlaylistByName(name: String): Playlist?
|
||||
}
|
||||
|
||||
interface MutableLibrary : Library {
|
||||
suspend fun createPlaylist(name: String, songs: List<Song>): MutableLibrary
|
||||
|
||||
suspend fun renamePlaylist(playlist: Playlist, name: String): MutableLibrary
|
||||
|
||||
suspend fun addToPlaylist(playlist: Playlist, songs: List<Song>): MutableLibrary
|
||||
|
||||
suspend fun rewritePlaylist(playlist: Playlist, songs: List<Song>): MutableLibrary
|
||||
|
||||
suspend fun deletePlaylist(playlist: Playlist): MutableLibrary
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract music data. This contains universal information about all concrete music
|
||||
* implementations, such as identification information and names.
|
||||
|
|
77
app/src/main/java/org/oxycblt/musikr/model/AlbumImpl.kt
Normal file
77
app/src/main/java/org/oxycblt/musikr/model/AlbumImpl.kt
Normal file
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Auxio Project
|
||||
* AlbumImpl.kt is part of Auxio.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.oxycblt.musikr.model
|
||||
|
||||
import org.oxycblt.auxio.music.MusicType
|
||||
import org.oxycblt.auxio.util.update
|
||||
import org.oxycblt.musikr.Album
|
||||
import org.oxycblt.musikr.Artist
|
||||
import org.oxycblt.musikr.Music
|
||||
import org.oxycblt.musikr.Song
|
||||
import org.oxycblt.musikr.cover.Cover
|
||||
import org.oxycblt.musikr.tag.Date
|
||||
import org.oxycblt.musikr.tag.interpret.PreAlbum
|
||||
|
||||
interface AlbumCore {
|
||||
val preAlbum: PreAlbum
|
||||
val songs: List<Song>
|
||||
|
||||
fun resolveArtists(): List<Artist>
|
||||
}
|
||||
|
||||
/**
|
||||
* Library-backed implementation of [Album].
|
||||
*
|
||||
* @author Alexander Capehart (OxygenCobalt)
|
||||
*/
|
||||
class AlbumImpl(private val core: AlbumCore) : Album {
|
||||
private val preAlbum = core.preAlbum
|
||||
|
||||
override val uid =
|
||||
// Attempt to use a MusicBrainz ID first before falling back to a hashed UID.
|
||||
preAlbum.musicBrainzId?.let { Music.UID.musicBrainz(MusicType.ALBUMS, it) }
|
||||
?: Music.UID.auxio(MusicType.ALBUMS) {
|
||||
// Hash based on only names despite the presence of a date to increase stability.
|
||||
// I don't know if there is any situation where an artist will have two albums with
|
||||
// the exact same name, but if there is, I would love to know.
|
||||
update(preAlbum.rawName)
|
||||
update(preAlbum.preArtists.map { it.rawName })
|
||||
}
|
||||
override val name = preAlbum.name
|
||||
override val releaseType = preAlbum.releaseType
|
||||
override val durationMs = core.songs.sumOf { it.durationMs }
|
||||
override val dateAdded = core.songs.minOf { it.dateAdded }
|
||||
override val cover = Cover.multi(core.songs)
|
||||
override val dates: Date.Range? =
|
||||
core.songs.mapNotNull { it.date }.ifEmpty { null }?.run { Date.Range(min(), max()) }
|
||||
|
||||
override val artists: List<Artist>
|
||||
get() = core.resolveArtists()
|
||||
|
||||
override val songs = core.songs
|
||||
|
||||
private val hashCode = 31 * (31 * uid.hashCode() + preAlbum.hashCode()) + songs.hashCode()
|
||||
|
||||
override fun hashCode() = hashCode
|
||||
|
||||
override fun equals(other: Any?) =
|
||||
other is AlbumImpl && uid == other.uid && preAlbum == other.preAlbum && songs == other.songs
|
||||
|
||||
override fun toString() = "Album(uid=$uid, name=$name)"
|
||||
}
|
73
app/src/main/java/org/oxycblt/musikr/model/ArtistImpl.kt
Normal file
73
app/src/main/java/org/oxycblt/musikr/model/ArtistImpl.kt
Normal file
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Auxio Project
|
||||
* ArtistImpl.kt is part of Auxio.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.oxycblt.musikr.model
|
||||
|
||||
import org.oxycblt.auxio.music.MusicType
|
||||
import org.oxycblt.auxio.util.update
|
||||
import org.oxycblt.musikr.Album
|
||||
import org.oxycblt.musikr.Artist
|
||||
import org.oxycblt.musikr.Genre
|
||||
import org.oxycblt.musikr.Music
|
||||
import org.oxycblt.musikr.Song
|
||||
import org.oxycblt.musikr.cover.Cover
|
||||
import org.oxycblt.musikr.tag.interpret.PreArtist
|
||||
|
||||
interface ArtistCore {
|
||||
val preArtist: PreArtist
|
||||
val songs: Set<Song>
|
||||
val albums: Set<Album>
|
||||
|
||||
fun resolveGenres(): Set<Genre>
|
||||
}
|
||||
|
||||
/**
|
||||
* Library-backed implementation of [Artist].
|
||||
*
|
||||
* @author Alexander Capehart (OxygenCobalt)
|
||||
*/
|
||||
class ArtistImpl(private val core: ArtistCore) : Artist {
|
||||
override val uid =
|
||||
// Attempt to use a MusicBrainz ID first before falling back to a hashed UID.
|
||||
core.preArtist.musicBrainzId?.let { Music.UID.musicBrainz(MusicType.ARTISTS, it) }
|
||||
?: Music.UID.auxio(MusicType.ARTISTS) { update(core.preArtist.rawName) }
|
||||
override val name = core.preArtist.name
|
||||
|
||||
override val songs = core.songs
|
||||
override var explicitAlbums = core.albums
|
||||
override var implicitAlbums = core.songs.mapTo(mutableSetOf()) { it.album } - core.albums
|
||||
|
||||
override val genres: List<Genre>
|
||||
get() = core.resolveGenres().toList()
|
||||
|
||||
override val durationMs = core.songs.sumOf { it.durationMs }
|
||||
override val cover = Cover.multi(core.songs)
|
||||
|
||||
private val hashCode =
|
||||
31 * (31 * uid.hashCode() + core.preArtist.hashCode()) * core.songs.hashCode()
|
||||
|
||||
override fun hashCode() = hashCode
|
||||
|
||||
override fun equals(other: Any?) =
|
||||
other is ArtistImpl &&
|
||||
uid == other.uid &&
|
||||
core.preArtist == other.core.preArtist &&
|
||||
songs == other.songs
|
||||
|
||||
override fun toString() = "Artist(uid=$uid, name=$name)"
|
||||
}
|
|
@ -1,210 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Auxio Project
|
||||
* DeviceMusicImpl.kt is part of Auxio.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.oxycblt.musikr.model
|
||||
|
||||
import org.oxycblt.auxio.music.MusicType
|
||||
import org.oxycblt.auxio.util.update
|
||||
import org.oxycblt.musikr.Album
|
||||
import org.oxycblt.musikr.Artist
|
||||
import org.oxycblt.musikr.Genre
|
||||
import org.oxycblt.musikr.Music
|
||||
import org.oxycblt.musikr.Song
|
||||
import org.oxycblt.musikr.cover.Cover
|
||||
import org.oxycblt.musikr.tag.Date
|
||||
import org.oxycblt.musikr.tag.interpret.PreAlbum
|
||||
import org.oxycblt.musikr.tag.interpret.PreArtist
|
||||
import org.oxycblt.musikr.tag.interpret.PreGenre
|
||||
import org.oxycblt.musikr.tag.interpret.PreSong
|
||||
|
||||
interface SongHandle {
|
||||
val preSong: PreSong
|
||||
|
||||
fun resolveAlbum(): Album
|
||||
|
||||
fun resolveArtists(): List<Artist>
|
||||
|
||||
fun resolveGenres(): List<Genre>
|
||||
}
|
||||
|
||||
/**
|
||||
* Library-backed implementation of [Song].
|
||||
*
|
||||
* @author Alexander Capehart (OxygenCobalt)
|
||||
*/
|
||||
class SongImpl(private val handle: SongHandle) : Song {
|
||||
private val preSong = handle.preSong
|
||||
|
||||
override val uid = preSong.computeUid()
|
||||
override val name = preSong.name
|
||||
override val track = preSong.track
|
||||
override val disc = preSong.disc
|
||||
override val date = preSong.date
|
||||
override val uri = preSong.uri
|
||||
override val path = preSong.path
|
||||
override val mimeType = preSong.mimeType
|
||||
override val size = preSong.size
|
||||
override val durationMs = preSong.durationMs
|
||||
override val replayGainAdjustment = preSong.replayGainAdjustment
|
||||
override val lastModified = preSong.lastModified
|
||||
override val dateAdded = preSong.dateAdded
|
||||
override val cover = Cover.single(this)
|
||||
override val album: Album
|
||||
get() = handle.resolveAlbum()
|
||||
|
||||
override val artists: List<Artist>
|
||||
get() = handle.resolveArtists()
|
||||
|
||||
override val genres: List<Genre>
|
||||
get() = handle.resolveGenres()
|
||||
|
||||
private val hashCode = 31 * uid.hashCode() + preSong.hashCode()
|
||||
|
||||
override fun hashCode() = hashCode
|
||||
|
||||
override fun equals(other: Any?) =
|
||||
other is SongImpl && uid == other.uid && preSong == other.preSong
|
||||
|
||||
override fun toString() = "Song(uid=$uid, name=$name)"
|
||||
}
|
||||
|
||||
interface AlbumHandle {
|
||||
val preAlbum: PreAlbum
|
||||
val songs: List<Song>
|
||||
|
||||
fun resolveArtists(): List<Artist>
|
||||
}
|
||||
|
||||
/**
|
||||
* Library-backed implementation of [Album].
|
||||
*
|
||||
* @author Alexander Capehart (OxygenCobalt)
|
||||
*/
|
||||
class AlbumImpl(private val handle: AlbumHandle) : Album {
|
||||
private val preAlbum = handle.preAlbum
|
||||
|
||||
override val uid =
|
||||
// Attempt to use a MusicBrainz ID first before falling back to a hashed UID.
|
||||
preAlbum.musicBrainzId?.let { Music.UID.musicBrainz(MusicType.ALBUMS, it) }
|
||||
?: Music.UID.auxio(MusicType.ALBUMS) {
|
||||
// Hash based on only names despite the presence of a date to increase stability.
|
||||
// I don't know if there is any situation where an artist will have two albums with
|
||||
// the exact same name, but if there is, I would love to know.
|
||||
update(preAlbum.rawName)
|
||||
update(preAlbum.preArtists.map { it.rawName })
|
||||
}
|
||||
override val name = preAlbum.name
|
||||
override val releaseType = preAlbum.releaseType
|
||||
override val durationMs = handle.songs.sumOf { it.durationMs }
|
||||
override val dateAdded = handle.songs.minOf { it.dateAdded }
|
||||
override val cover = Cover.multi(handle.songs)
|
||||
override val dates: Date.Range? =
|
||||
handle.songs.mapNotNull { it.date }.ifEmpty { null }?.run { Date.Range(min(), max()) }
|
||||
|
||||
override val artists: List<Artist>
|
||||
get() = handle.resolveArtists()
|
||||
|
||||
override val songs = handle.songs
|
||||
|
||||
private val hashCode = 31 * (31 * uid.hashCode() + preAlbum.hashCode()) + songs.hashCode()
|
||||
|
||||
override fun hashCode() = hashCode
|
||||
|
||||
override fun equals(other: Any?) =
|
||||
other is AlbumImpl && uid == other.uid && preAlbum == other.preAlbum && songs == other.songs
|
||||
|
||||
override fun toString() = "Album(uid=$uid, name=$name)"
|
||||
}
|
||||
|
||||
interface ArtistHandle {
|
||||
val preArtist: PreArtist
|
||||
val songs: Set<Song>
|
||||
val albums: Set<Album>
|
||||
|
||||
fun resolveGenres(): Set<Genre>
|
||||
}
|
||||
|
||||
/**
|
||||
* Library-backed implementation of [Artist].
|
||||
*
|
||||
* @author Alexander Capehart (OxygenCobalt)
|
||||
*/
|
||||
class ArtistImpl(private val handle: ArtistHandle) : Artist {
|
||||
override val uid =
|
||||
// Attempt to use a MusicBrainz ID first before falling back to a hashed UID.
|
||||
handle.preArtist.musicBrainzId?.let { Music.UID.musicBrainz(MusicType.ARTISTS, it) }
|
||||
?: Music.UID.auxio(MusicType.ARTISTS) { update(handle.preArtist.rawName) }
|
||||
override val name = handle.preArtist.name
|
||||
|
||||
override val songs = handle.songs
|
||||
override var explicitAlbums = handle.albums
|
||||
override var implicitAlbums = handle.songs.mapTo(mutableSetOf()) { it.album } - handle.albums
|
||||
|
||||
override val genres: List<Genre>
|
||||
get() = handle.resolveGenres().toList()
|
||||
|
||||
override val durationMs = handle.songs.sumOf { it.durationMs }
|
||||
override val cover = Cover.multi(handle.songs)
|
||||
|
||||
private val hashCode =
|
||||
31 * (31 * uid.hashCode() + handle.preArtist.hashCode()) * handle.songs.hashCode()
|
||||
|
||||
override fun hashCode() = hashCode
|
||||
|
||||
override fun equals(other: Any?) =
|
||||
other is ArtistImpl &&
|
||||
uid == other.uid &&
|
||||
handle.preArtist == other.handle.preArtist &&
|
||||
songs == other.songs
|
||||
|
||||
override fun toString() = "Artist(uid=$uid, name=$name)"
|
||||
}
|
||||
|
||||
interface GenreHandle {
|
||||
val preGenre: PreGenre
|
||||
val songs: Set<Song>
|
||||
val artists: Set<Artist>
|
||||
}
|
||||
|
||||
/**
|
||||
* Library-backed implementation of [Genre].
|
||||
*
|
||||
* @author Alexander Capehart (OxygenCobalt)
|
||||
*/
|
||||
class GenreImpl(private val handle: GenreHandle) : Genre {
|
||||
override val uid = Music.UID.auxio(MusicType.GENRES) { update(handle.preGenre.rawName) }
|
||||
override val name = handle.preGenre.name
|
||||
|
||||
override val songs = mutableSetOf<Song>()
|
||||
override val artists = mutableSetOf<Artist>()
|
||||
override val durationMs = handle.songs.sumOf { it.durationMs }
|
||||
override val cover = Cover.multi(handle.songs)
|
||||
|
||||
private val hashCode =
|
||||
31 * (31 * uid.hashCode() + handle.preGenre.hashCode()) + songs.hashCode()
|
||||
|
||||
override fun hashCode() = hashCode
|
||||
|
||||
override fun equals(other: Any?) =
|
||||
other is GenreImpl &&
|
||||
uid == other.uid &&
|
||||
handle.preGenre == other.handle.preGenre &&
|
||||
songs == other.songs
|
||||
|
||||
override fun toString() = "Genre(uid=$uid, name=$name)"
|
||||
}
|
61
app/src/main/java/org/oxycblt/musikr/model/GenreImpl.kt
Normal file
61
app/src/main/java/org/oxycblt/musikr/model/GenreImpl.kt
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Auxio Project
|
||||
* GenreImpl.kt is part of Auxio.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.oxycblt.musikr.model
|
||||
|
||||
import org.oxycblt.auxio.music.MusicType
|
||||
import org.oxycblt.auxio.util.update
|
||||
import org.oxycblt.musikr.Artist
|
||||
import org.oxycblt.musikr.Genre
|
||||
import org.oxycblt.musikr.Music
|
||||
import org.oxycblt.musikr.Song
|
||||
import org.oxycblt.musikr.cover.Cover
|
||||
import org.oxycblt.musikr.tag.interpret.PreGenre
|
||||
|
||||
interface GenreCore {
|
||||
val preGenre: PreGenre
|
||||
val songs: Set<Song>
|
||||
val artists: Set<Artist>
|
||||
}
|
||||
|
||||
/**
|
||||
* Library-backed implementation of [Genre].
|
||||
*
|
||||
* @author Alexander Capehart (OxygenCobalt)
|
||||
*/
|
||||
class GenreImpl(private val core: GenreCore) : Genre {
|
||||
override val uid = Music.UID.auxio(MusicType.GENRES) { update(core.preGenre.rawName) }
|
||||
override val name = core.preGenre.name
|
||||
|
||||
override val songs = mutableSetOf<Song>()
|
||||
override val artists = mutableSetOf<Artist>()
|
||||
override val durationMs = core.songs.sumOf { it.durationMs }
|
||||
override val cover = Cover.multi(core.songs)
|
||||
|
||||
private val hashCode = 31 * (31 * uid.hashCode() + core.preGenre.hashCode()) + songs.hashCode()
|
||||
|
||||
override fun hashCode() = hashCode
|
||||
|
||||
override fun equals(other: Any?) =
|
||||
other is GenreImpl &&
|
||||
uid == other.uid &&
|
||||
core.preGenre == other.core.preGenre &&
|
||||
songs == other.songs
|
||||
|
||||
override fun toString() = "Genre(uid=$uid, name=$name)"
|
||||
}
|
|
@ -1,158 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Auxio Project
|
||||
* Library.kt is part of Auxio.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.oxycblt.musikr.model
|
||||
|
||||
import javax.inject.Inject
|
||||
import org.oxycblt.musikr.Album
|
||||
import org.oxycblt.musikr.Artist
|
||||
import org.oxycblt.musikr.Genre
|
||||
import org.oxycblt.musikr.Library
|
||||
import org.oxycblt.musikr.Music
|
||||
import org.oxycblt.musikr.Playlist
|
||||
import org.oxycblt.musikr.Song
|
||||
import org.oxycblt.musikr.fs.Path
|
||||
import org.oxycblt.musikr.graph.AlbumVertex
|
||||
import org.oxycblt.musikr.graph.ArtistVertex
|
||||
import org.oxycblt.musikr.graph.GenreVertex
|
||||
import org.oxycblt.musikr.graph.MusicGraph
|
||||
import org.oxycblt.musikr.graph.SongVertex
|
||||
|
||||
interface MutableLibrary : Library {
|
||||
suspend fun createPlaylist(name: String, songs: List<Song>): MutableLibrary
|
||||
|
||||
suspend fun renamePlaylist(playlist: Playlist, name: String): MutableLibrary
|
||||
|
||||
suspend fun addToPlaylist(playlist: Playlist, songs: List<Song>): MutableLibrary
|
||||
|
||||
suspend fun rewritePlaylist(playlist: Playlist, songs: List<Song>): MutableLibrary
|
||||
|
||||
suspend fun deletePlaylist(playlist: Playlist): MutableLibrary
|
||||
}
|
||||
|
||||
interface LibraryFactory {
|
||||
fun create(graph: MusicGraph): MutableLibrary
|
||||
}
|
||||
|
||||
class LibraryFactoryImpl @Inject constructor() : LibraryFactory {
|
||||
override fun create(graph: MusicGraph): MutableLibrary {
|
||||
val songs =
|
||||
graph.songVertex.mapTo(mutableSetOf()) { vertex ->
|
||||
SongImpl(SongVertexHandle(vertex)).also { vertex.tag = it }
|
||||
}
|
||||
val albums =
|
||||
graph.albumVertex.mapTo(mutableSetOf()) { vertex ->
|
||||
AlbumImpl(AlbumVertexHandle(vertex)).also { vertex.tag = it }
|
||||
}
|
||||
val artists =
|
||||
graph.artistVertex.mapTo(mutableSetOf()) { vertex ->
|
||||
ArtistImpl(ArtistVertexHandle(vertex)).also { vertex.tag = it }
|
||||
}
|
||||
val genres =
|
||||
graph.genreVertex.mapTo(mutableSetOf()) { vertex ->
|
||||
GenreImpl(GenreVertexHandle(vertex)).also { vertex.tag = it }
|
||||
}
|
||||
return LibraryImpl(songs, albums, artists, genres)
|
||||
}
|
||||
|
||||
private class SongVertexHandle(private val vertex: SongVertex) : SongHandle {
|
||||
override val preSong = vertex.preSong
|
||||
|
||||
override fun resolveAlbum() = vertex.albumVertex.tag as Album
|
||||
|
||||
override fun resolveArtists() = vertex.artistVertices.map { it.tag as Artist }
|
||||
|
||||
override fun resolveGenres() = vertex.genreVertices.map { it.tag as Genre }
|
||||
}
|
||||
|
||||
private class AlbumVertexHandle(private val vertex: AlbumVertex) : AlbumHandle {
|
||||
override val preAlbum = vertex.preAlbum
|
||||
|
||||
override val songs = vertex.songVertices.map { SongImpl(SongVertexHandle(it)) }
|
||||
|
||||
override fun resolveArtists() = vertex.artistVertices.map { it.tag as Artist }
|
||||
}
|
||||
|
||||
private class ArtistVertexHandle(private val vertex: ArtistVertex) : ArtistHandle {
|
||||
override val preArtist = vertex.preArtist
|
||||
|
||||
override val songs = vertex.songVertices.mapTo(mutableSetOf()) { it.tag as Song }
|
||||
|
||||
override val albums = vertex.albumVertices.mapTo(mutableSetOf()) { it.tag as Album }
|
||||
|
||||
override fun resolveGenres() =
|
||||
vertex.genreVertices.mapTo(mutableSetOf()) { it.tag as Genre }
|
||||
}
|
||||
|
||||
private class GenreVertexHandle(vertex: GenreVertex) : GenreHandle {
|
||||
override val preGenre = vertex.preGenre
|
||||
|
||||
override val songs = vertex.songVertices.mapTo(mutableSetOf()) { it.tag as Song }
|
||||
|
||||
override val artists = vertex.artistVertices.mapTo(mutableSetOf()) { it.tag as Artist }
|
||||
}
|
||||
}
|
||||
|
||||
class LibraryImpl(
|
||||
override val songs: Collection<SongImpl>,
|
||||
override val albums: Collection<AlbumImpl>,
|
||||
override val artists: Collection<ArtistImpl>,
|
||||
override val genres: Collection<GenreImpl>
|
||||
) : MutableLibrary {
|
||||
override val playlists = emptySet<Playlist>()
|
||||
|
||||
private val songUidMap = songs.associateBy { it.uid }
|
||||
private val albumUidMap = albums.associateBy { it.uid }
|
||||
private val artistUidMap = artists.associateBy { it.uid }
|
||||
private val genreUidMap = genres.associateBy { it.uid }
|
||||
private val playlistUidMap = playlists.associateBy { it.uid }
|
||||
|
||||
override fun findSong(uid: Music.UID) = songUidMap[uid]
|
||||
|
||||
override fun findSongByPath(path: Path) = songs.find { it.path == path }
|
||||
|
||||
override fun findAlbum(uid: Music.UID) = albumUidMap[uid]
|
||||
|
||||
override fun findArtist(uid: Music.UID) = artistUidMap[uid]
|
||||
|
||||
override fun findGenre(uid: Music.UID) = genreUidMap[uid]
|
||||
|
||||
override fun findPlaylist(uid: Music.UID) = playlistUidMap[uid]
|
||||
|
||||
override fun findPlaylistByName(name: String) = playlists.find { it.name.raw == name }
|
||||
|
||||
override suspend fun createPlaylist(name: String, songs: List<Song>): MutableLibrary {
|
||||
return this
|
||||
}
|
||||
|
||||
override suspend fun renamePlaylist(playlist: Playlist, name: String): MutableLibrary {
|
||||
return this
|
||||
}
|
||||
|
||||
override suspend fun addToPlaylist(playlist: Playlist, songs: List<Song>): MutableLibrary {
|
||||
return this
|
||||
}
|
||||
|
||||
override suspend fun rewritePlaylist(playlist: Playlist, songs: List<Song>): MutableLibrary {
|
||||
return this
|
||||
}
|
||||
|
||||
override suspend fun deletePlaylist(playlist: Playlist): MutableLibrary {
|
||||
return this
|
||||
}
|
||||
}
|
94
app/src/main/java/org/oxycblt/musikr/model/LibraryFactory.kt
Normal file
94
app/src/main/java/org/oxycblt/musikr/model/LibraryFactory.kt
Normal file
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Auxio Project
|
||||
* LibraryFactory.kt is part of Auxio.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.oxycblt.musikr.model
|
||||
|
||||
import javax.inject.Inject
|
||||
import org.oxycblt.musikr.Album
|
||||
import org.oxycblt.musikr.Artist
|
||||
import org.oxycblt.musikr.Genre
|
||||
import org.oxycblt.musikr.MutableLibrary
|
||||
import org.oxycblt.musikr.Song
|
||||
import org.oxycblt.musikr.graph.AlbumVertex
|
||||
import org.oxycblt.musikr.graph.ArtistVertex
|
||||
import org.oxycblt.musikr.graph.GenreVertex
|
||||
import org.oxycblt.musikr.graph.MusicGraph
|
||||
import org.oxycblt.musikr.graph.SongVertex
|
||||
|
||||
interface LibraryFactory {
|
||||
fun create(graph: MusicGraph): MutableLibrary
|
||||
}
|
||||
|
||||
class LibraryFactoryImpl @Inject constructor() : LibraryFactory {
|
||||
override fun create(graph: MusicGraph): MutableLibrary {
|
||||
val songs =
|
||||
graph.songVertex.mapTo(mutableSetOf()) { vertex ->
|
||||
SongImpl(SongVertexCore(vertex)).also { vertex.tag = it }
|
||||
}
|
||||
val albums =
|
||||
graph.albumVertex.mapTo(mutableSetOf()) { vertex ->
|
||||
AlbumImpl(AlbumVertexCore(vertex)).also { vertex.tag = it }
|
||||
}
|
||||
val artists =
|
||||
graph.artistVertex.mapTo(mutableSetOf()) { vertex ->
|
||||
ArtistImpl(ArtistVertexCore(vertex)).also { vertex.tag = it }
|
||||
}
|
||||
val genres =
|
||||
graph.genreVertex.mapTo(mutableSetOf()) { vertex ->
|
||||
GenreImpl(GenreVertexCore(vertex)).also { vertex.tag = it }
|
||||
}
|
||||
return LibraryImpl(songs, albums, artists, genres)
|
||||
}
|
||||
|
||||
private class SongVertexCore(private val vertex: SongVertex) : SongCore {
|
||||
override val preSong = vertex.preSong
|
||||
|
||||
override fun resolveAlbum() = vertex.albumVertex.tag as Album
|
||||
|
||||
override fun resolveArtists() = vertex.artistVertices.map { it.tag as Artist }
|
||||
|
||||
override fun resolveGenres() = vertex.genreVertices.map { it.tag as Genre }
|
||||
}
|
||||
|
||||
private class AlbumVertexCore(private val vertex: AlbumVertex) : AlbumCore {
|
||||
override val preAlbum = vertex.preAlbum
|
||||
|
||||
override val songs = vertex.songVertices.map { SongImpl(SongVertexCore(it)) }
|
||||
|
||||
override fun resolveArtists() = vertex.artistVertices.map { it.tag as Artist }
|
||||
}
|
||||
|
||||
private class ArtistVertexCore(private val vertex: ArtistVertex) : ArtistCore {
|
||||
override val preArtist = vertex.preArtist
|
||||
|
||||
override val songs = vertex.songVertices.mapTo(mutableSetOf()) { it.tag as Song }
|
||||
|
||||
override val albums = vertex.albumVertices.mapTo(mutableSetOf()) { it.tag as Album }
|
||||
|
||||
override fun resolveGenres() =
|
||||
vertex.genreVertices.mapTo(mutableSetOf()) { it.tag as Genre }
|
||||
}
|
||||
|
||||
private class GenreVertexCore(vertex: GenreVertex) : GenreCore {
|
||||
override val preGenre = vertex.preGenre
|
||||
|
||||
override val songs = vertex.songVertices.mapTo(mutableSetOf()) { it.tag as Song }
|
||||
|
||||
override val artists = vertex.artistVertices.mapTo(mutableSetOf()) { it.tag as Artist }
|
||||
}
|
||||
}
|
74
app/src/main/java/org/oxycblt/musikr/model/LibraryImpl.kt
Normal file
74
app/src/main/java/org/oxycblt/musikr/model/LibraryImpl.kt
Normal file
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Auxio Project
|
||||
* LibraryImpl.kt is part of Auxio.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.oxycblt.musikr.model
|
||||
|
||||
import org.oxycblt.musikr.Music
|
||||
import org.oxycblt.musikr.MutableLibrary
|
||||
import org.oxycblt.musikr.Playlist
|
||||
import org.oxycblt.musikr.Song
|
||||
import org.oxycblt.musikr.fs.Path
|
||||
|
||||
class LibraryImpl(
|
||||
override val songs: Collection<SongImpl>,
|
||||
override val albums: Collection<AlbumImpl>,
|
||||
override val artists: Collection<ArtistImpl>,
|
||||
override val genres: Collection<GenreImpl>
|
||||
) : MutableLibrary {
|
||||
override val playlists = emptySet<Playlist>()
|
||||
|
||||
private val songUidMap = songs.associateBy { it.uid }
|
||||
private val albumUidMap = albums.associateBy { it.uid }
|
||||
private val artistUidMap = artists.associateBy { it.uid }
|
||||
private val genreUidMap = genres.associateBy { it.uid }
|
||||
private val playlistUidMap = playlists.associateBy { it.uid }
|
||||
|
||||
override fun findSong(uid: Music.UID) = songUidMap[uid]
|
||||
|
||||
override fun findSongByPath(path: Path) = songs.find { it.path == path }
|
||||
|
||||
override fun findAlbum(uid: Music.UID) = albumUidMap[uid]
|
||||
|
||||
override fun findArtist(uid: Music.UID) = artistUidMap[uid]
|
||||
|
||||
override fun findGenre(uid: Music.UID) = genreUidMap[uid]
|
||||
|
||||
override fun findPlaylist(uid: Music.UID) = playlistUidMap[uid]
|
||||
|
||||
override fun findPlaylistByName(name: String) = playlists.find { it.name.raw == name }
|
||||
|
||||
override suspend fun createPlaylist(name: String, songs: List<Song>): MutableLibrary {
|
||||
return this
|
||||
}
|
||||
|
||||
override suspend fun renamePlaylist(playlist: Playlist, name: String): MutableLibrary {
|
||||
return this
|
||||
}
|
||||
|
||||
override suspend fun addToPlaylist(playlist: Playlist, songs: List<Song>): MutableLibrary {
|
||||
return this
|
||||
}
|
||||
|
||||
override suspend fun rewritePlaylist(playlist: Playlist, songs: List<Song>): MutableLibrary {
|
||||
return this
|
||||
}
|
||||
|
||||
override suspend fun deletePlaylist(playlist: Playlist): MutableLibrary {
|
||||
return this
|
||||
}
|
||||
}
|
77
app/src/main/java/org/oxycblt/musikr/model/SongImpl.kt
Normal file
77
app/src/main/java/org/oxycblt/musikr/model/SongImpl.kt
Normal file
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Auxio Project
|
||||
* SongImpl.kt is part of Auxio.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.oxycblt.musikr.model
|
||||
|
||||
import org.oxycblt.musikr.Album
|
||||
import org.oxycblt.musikr.Artist
|
||||
import org.oxycblt.musikr.Genre
|
||||
import org.oxycblt.musikr.Song
|
||||
import org.oxycblt.musikr.cover.Cover
|
||||
import org.oxycblt.musikr.tag.interpret.PreSong
|
||||
|
||||
interface SongCore {
|
||||
val preSong: PreSong
|
||||
|
||||
fun resolveAlbum(): Album
|
||||
|
||||
fun resolveArtists(): List<Artist>
|
||||
|
||||
fun resolveGenres(): List<Genre>
|
||||
}
|
||||
|
||||
/**
|
||||
* Library-backed implementation of [Song].
|
||||
*
|
||||
* @author Alexander Capehart (OxygenCobalt)
|
||||
*/
|
||||
class SongImpl(private val handle: SongCore) : Song {
|
||||
private val preSong = handle.preSong
|
||||
|
||||
override val uid = preSong.computeUid()
|
||||
override val name = preSong.name
|
||||
override val track = preSong.track
|
||||
override val disc = preSong.disc
|
||||
override val date = preSong.date
|
||||
override val uri = preSong.uri
|
||||
override val path = preSong.path
|
||||
override val mimeType = preSong.mimeType
|
||||
override val size = preSong.size
|
||||
override val durationMs = preSong.durationMs
|
||||
override val replayGainAdjustment = preSong.replayGainAdjustment
|
||||
override val lastModified = preSong.lastModified
|
||||
override val dateAdded = preSong.dateAdded
|
||||
override val cover = Cover.single(this)
|
||||
override val album: Album
|
||||
get() = handle.resolveAlbum()
|
||||
|
||||
override val artists: List<Artist>
|
||||
get() = handle.resolveArtists()
|
||||
|
||||
override val genres: List<Genre>
|
||||
get() = handle.resolveGenres()
|
||||
|
||||
private val hashCode = 31 * uid.hashCode() + preSong.hashCode()
|
||||
|
||||
override fun hashCode() = hashCode
|
||||
|
||||
override fun equals(other: Any?) =
|
||||
other is SongImpl && uid == other.uid && preSong == other.preSong
|
||||
|
||||
override fun toString() = "Song(uid=$uid, name=$name)"
|
||||
}
|
|
@ -26,9 +26,9 @@ import kotlinx.coroutines.flow.buffer
|
|||
import kotlinx.coroutines.flow.filterIsInstance
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import org.oxycblt.musikr.MutableLibrary
|
||||
import org.oxycblt.musikr.graph.MusicGraph
|
||||
import org.oxycblt.musikr.model.LibraryFactory
|
||||
import org.oxycblt.musikr.model.MutableLibrary
|
||||
import org.oxycblt.musikr.tag.Interpretation
|
||||
import org.oxycblt.musikr.tag.interpret.TagInterpreter
|
||||
|
||||
|
|
Loading…
Reference in a new issue