Skip to content
Snippets Groups Projects
Commit 37ef1809 authored by Nicolas Pomepuy's avatar Nicolas Pomepuy
Browse files

Allow browsing an artist

parent 51fd54f6
No related branches found
No related tags found
1 merge request!1848Remote access:dark theme
......@@ -498,6 +498,25 @@ fun Route.setupRouting(appContext: Context, scope: CoroutineScope) {
val gson = Gson()
call.respondText(gson.toJson(list))
}
// Get an artist details
get("/artist") {
verifyLogin(settings)
if (!settings.serveAudios(appContext)) {
call.respond(HttpStatusCode.Forbidden)
return@get
}
val id = call.request.queryParameters["id"]?.toLong() ?: 0L
val artist = appContext.getFromMl { getArtist(id) }
val list = ArrayList<RemoteAccessServer.PlayQueueItem>()
artist.albums.forEach { album ->
list.add(album.toPlayQueueItem())
}
val result= RemoteAccessServer.ArtistResult(list, listOf(), artist.title)
val gson = Gson()
call.respondText(gson.toJson(result))
}
// List of all the playlists
get("/playlist-list") {
verifyLogin(settings)
......@@ -801,6 +820,12 @@ fun Route.setupRouting(appContext: Context, scope: CoroutineScope) {
folder.media(Folder.TYPE_FOLDER_VIDEO, Medialibrary.SORT_DEFAULT, false, false, false, folder.mediaCount(Folder.TYPE_FOLDER_VIDEO), 0)
}
}
"artist" -> {
id?.let { id ->
val artist = getArtist(id.toLong())
artist.tracks
}
}
else -> getAudio(Medialibrary.SORT_DEFAULT, false, false, false)
}
}
......
......@@ -750,6 +750,7 @@ class RemoteAccessServer(private val context: Context) : PlaybackService.Callbac
data class BreadcrumbItem(val title: String, val path: String)
data class BrowsingResult(val content: List<PlayQueueItem>, val breadcrumb: List<BreadcrumbItem>)
data class VideoListResult(val content: List<PlayQueueItem>, val item: String)
data class ArtistResult(val albums: List<PlayQueueItem>, val tracks: List<PlayQueueItem>, val name: String)
fun getSecureUrl(call: ApplicationCall) = "https://${call.request.host()}:${engine.environment.connectors.first { it.type.name == "HTTPS" }.port}"
......
......@@ -106,7 +106,7 @@ export default {
return (this.mediaType == 'folder' || this.mediaType == 'network' || this.mediaType == 'stream' || this.mediaType == 'new-stream')
},
isOpenable() {
return ['video-group', 'video-folder'].includes(this.mediaType)
return ['video-group', 'video-folder', 'artist'].includes(this.mediaType)
},
getDescription() {
if (this.mediaType == 'video') {
......@@ -117,7 +117,9 @@ export default {
}
},
manageClick() {
if (this.mediaType == 'video-group') {
if (this.mediaType == 'artist') {
this.$router.push({ name: 'ArtistDetails', params: { artistId: this.media.id } })
} else if (this.mediaType == 'video-group') {
this.$router.push({ name: 'VideoGroupList', params: { groupId: this.media.id } })
} else if (this.mediaType == 'video-folder') {
this.$router.push({ name: 'VideoFolderList', params: { folderId: this.media.id } })
......
<template>
<div v-if="loaded && this.albums.length !== 0" class="container">
<div v-if="this.appStore.displayType[this.$route.name]" class="row gx-3 gy-3 media-list">
<template v-for="album in albums" :key="album.id">
<MediaItem :isCard="false" :media="album" :mediaType="'album'" />
</template>
</div>
<div v-else class="row gx-3 gy-3 media-content">
<div class="col-md-3 col-lg-2 col-sm-4 col-6" v-for="album in albums" :key="album.id">
<MediaItem :isCard="true" :media="album" :mediaType="'album'" />
</div>
</div>
</div>
<div v-else-if="loaded" class="empty-view-container">
<EmptyView :message="getEmptyText()" />
</div>
</template>
<script>
import { useAppStore } from '../stores/AppStore'
import { mapStores } from 'pinia'
import http from '../plugins/auth'
import { vlcApi } from '../plugins/api.js'
import MediaItem from '../components/MediaItem.vue'
import EmptyView from '../components/EmptyView.vue'
export default {
computed: {
...mapStores(useAppStore)
},
components: {
MediaItem,
EmptyView,
},
data() {
return {
albums: [],
loaded: false,
forbidden: false,
}
},
methods: {
fetchAlbums() {
let component = this
component.appStore.loading = true
let artistId = this.$route.params.artistId
this.$log.log(`Loading artist: ${artistId}`)
http.get(vlcApi.artistDetails(artistId))
.catch(function (error) {
if (error.response !== undefined && error.response.status == 403) {
component.forbidden = true;
}
})
.then((response) => {
this.loaded = true;
if (response) {
component.forbidden = false;
this.albums = response.data.albums
}
component.appStore.loading = false
component.appStore.title = response.data.name
});
},
getEmptyText() {
if (this.forbidden) return this.$t('FORBIDDEN')
return this.$t('NO_MEDIA')
}
},
created: function () {
this.fetchAlbums();
},
unmounted: function() {
console.log("unmounted")
this.appStore.title = ''
}
}
</script>
<style lang='scss'>
@import '../scss/colors.scss';
</style>
......@@ -76,6 +76,12 @@ export const vlcApi = {
* Retrieve the genre list API URL
*/
genreList: `${API_URL}genre-list`,
/**
* Retrieve the artist details API URL
*/
artistDetails: (artistId) => {
return`${API_URL}artist?id=${artistId}`
},
/**
* Retrieve the playlist list API URL
*/
......
......@@ -46,10 +46,21 @@ export default {
appStore.warning = { type: "warning", message: error.response.data }
}
})
},
}
app.config.globalProperties.$playAll = (route) => {
let type= route.meta.playAllType
let id = (type == "video-group") ? route.params.groupId : (type == "video-folder") ? route.params.folderId : 0
let id
switch (type) {
case "video-group":
id = route.params.groupId
break
case "video-folder": id = route.params.folderId
break
case "artist": id = route.params.artistId
break
default: id = 0
}
let path = (type == "browser") ? route.params.browseId : ""
axios.get(vlcApi.playAll(type, id, path))
.catch(function (error) {
......
......@@ -10,6 +10,7 @@ import BrowseList from './pages/BrowseList'
import SearchList from './pages/SearchList'
import LoginPage from './pages/LoginPage'
import SslPage from './pages/SslPage'
import ArtistDetails from './pages/ArtistDetails'
const routes = [
{ path: '/', redirect: '/videos', name: 'Home' },
......@@ -28,6 +29,7 @@ const routes = [
{ path: 'albums', component: AudioAlbums, name: 'AudioAlbums', meta: { showDisplayBar: true, isAudio: true, showResume: true, showGrouping: false } },
{ path: 'tracks', component: AudioTracks, name: 'AudioTracks', meta: { showDisplayBar: true, isAudio: true, showResume: true, showGrouping: false, showFAB: true, playAllType: "tracks" } },
{ path: 'genres', component: AudioGenres, name: 'AudioGenres', meta: { showDisplayBar: true, isAudio: true, showResume: true, showGrouping: false } },
{ path: 'artist/:artistId', component: ArtistDetails, name: 'ArtistDetails', meta: { showDisplayBar: true, isAudio: false, showResume: false, showGrouping: false, showFAB: true, playAllType: "artist" } },
]
},
{
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment