normalize responses and add types

This commit is contained in:
Thomas Amland 2020-08-14 19:03:17 +02:00
parent b8db546f64
commit 8fb1f8db78
5 changed files with 113 additions and 71 deletions

View File

@ -14,6 +14,7 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue' import Vue from 'vue'
import AlbumList from '@/library/album/AlbumList.vue' import AlbumList from '@/library/album/AlbumList.vue'
import { Album } from '@/shared/api'
export default Vue.extend({ export default Vue.extend({
components: { components: {
@ -22,10 +23,10 @@
data() { data() {
return { return {
loading: true as boolean, loading: true as boolean,
recent: [], recent: [] as Album[],
newest: [], newest: [] as Album[],
frequent: [], frequent: [] as Album[],
random: [], random: [] as Album[],
} }
}, },
computed: { computed: {

View File

@ -16,7 +16,7 @@
</div> </div>
<div class="row"> <div class="row">
<div class="col"> <div class="col">
<TrackList :tracks="album.song" /> <TrackList :tracks="album.tracks" />
</div> </div>
</div> </div>
</div> </div>
@ -29,6 +29,7 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue' import Vue from 'vue'
import TrackList from '@/library/TrackList.vue' import TrackList from '@/library/TrackList.vue'
import { Album } from '@/shared/api'
export default Vue.extend({ export default Vue.extend({
components: { components: {
@ -39,7 +40,7 @@
}, },
data() { data() {
return { return {
album: null, album: null as null | Album,
} }
}, },
async mounted() { async mounted() {

View File

@ -8,7 +8,7 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue' import Vue from 'vue'
import AlbumList from './AlbumList.vue' import AlbumList from './AlbumList.vue'
import { AlbumSort } from '@/shared/api' import { AlbumSort, Album } from '@/shared/api'
export default Vue.extend({ export default Vue.extend({
components: { components: {
@ -17,7 +17,7 @@
data() { data() {
return { return {
sort: 'newest', sort: 'newest',
albums: null, albums: null as null | Album[],
} }
}, },
computed: { computed: {

View File

@ -4,6 +4,7 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue' import Vue from 'vue'
import ArtistList from './ArtistList.vue' import ArtistList from './ArtistList.vue'
import { Artist } from '@/shared/api'
export default Vue.extend({ export default Vue.extend({
components: { components: {
@ -11,7 +12,7 @@
}, },
data() { data() {
return { return {
items: [] items: [] as Artist[]
} }
}, },
created() { created() {

View File

@ -3,6 +3,50 @@ import { AuthService } from '@/auth/service'
export type AlbumSort = 'alphabeticalByName' | 'newest' | 'recent' | 'frequent' | 'random' export type AlbumSort = 'alphabeticalByName' | 'newest' | 'recent' | 'frequent' | 'random'
export interface Album {
id: string
name: string
artist: string
artistId: string
year: number
starred: boolean
image?: string
tracks?: Track[]
}
export interface Artist {
id: string
name: string
albumCount: number
description?: string
starred: boolean
image?: string
lastFmUrl?: string
musicBrainzUrl?: string
similarArtist?: Artist[]
albums?: Album[]
}
export interface Track {
id: string
title: string
duration: number
starred: boolean
image?: string
url?: string
track?: number
album?: string
albumId?: string
artist?: string
artistId?: string
}
export interface SearchResult {
artists: Artist[]
albums: Album[]
tracks: Track[]
}
export class API { export class API {
readonly http: AxiosInstance; readonly http: AxiosInstance;
readonly get: (path: string, params?: any) => Promise<any>; readonly get: (path: string, params?: any) => Promise<any>;
@ -67,70 +111,41 @@ export class API {
const response = await this.get('rest/getSongsByGenre', params) const response = await this.get('rest/getSongsByGenre', params)
return { return {
name: id, name: id,
tracks: this.normalizeTrackList(response.songsByGenre?.song || []), tracks: (response.songsByGenre?.song || []).map(this.normalizeTrack, this),
} }
} }
async getArtists() { async getArtists(): Promise<Artist[]> {
const response = await this.get('rest/getArtists') const response = await this.get('rest/getArtists')
return (response.artists?.index || []).flatMap((index: any) => index.artist.map((artist: any) => ({ return (response.artists?.index || [])
id: artist.id, .flatMap((index: any) => index.artist)
name: artist.name, .map(this.normalizeArtist, this)
...artist
})))
} }
async getAlbums(sort: AlbumSort, size = 500) { async getAlbums(sort: AlbumSort, size = 500): Promise<Album[]> {
const params = { const params = {
type: sort, type: sort,
offset: '0', offset: '0',
size: size, size: size,
} }
const response = await this.get('rest/getAlbumList2', params) const response = await this.get('rest/getAlbumList2', params)
return (response.albumList2?.album || []).map((item: any) => ({ const albums = response.albumList2?.album || []
...item, return albums.map(this.normalizeAlbum, this)
image: item.coverArt ? this.getCoverArtUrl(item) : undefined,
}))
} }
async getArtistDetails(id: string) { async getArtistDetails(id: string): Promise<Artist> {
const params = { id } const params = { id }
const [info1, info2] = await Promise.all([ const [info1, info2] = await Promise.all([
this.get('rest/getArtist', params).then(r => r.artist), this.get('rest/getArtist', params).then(r => r.artist),
this.get('rest/getArtistInfo2', params).then(r => r.artistInfo2), this.get('rest/getArtistInfo2', params).then(r => r.artistInfo2),
]) ])
return { return this.normalizeArtist({ ...info1, ...info2 })
id: info1.id,
name: info1.name,
description: (info2.biography || '').replace(/<a[^>]*>.*?<\/a>/gm, ''),
image: info2.largeImageUrl || info2.mediumImageUrl || info2.smallImageUrl,
lastFmUrl: info2.lastFmUrl,
musicBrainzUrl: info2.musicBrainzId
? `https://musicbrainz.org/artist/${info2.musicBrainzId}` : null,
albums: info1.album.map((album: any) => this.normalizeAlbum(album)),
similarArtist: (info2.similarArtist || []).map((artist: any) => ({
id: artist.id,
name: artist.name,
...artist
}))
}
} }
async getAlbumDetails(id: string) { async getAlbumDetails(id: string): Promise<Album> {
const params = { id } const params = { id }
const data = await this.get('rest/getAlbum', params) const data = await this.get('rest/getAlbum', params)
const item = data.album return this.normalizeAlbum(data.album)
const image = this.getCoverArtUrl(item)
const trackList = item.song.map((s: any) => ({
...s,
image,
url: this.getStreamUrl(s.id),
}))
return {
...item,
image,
song: trackList,
}
} }
async getPlaylists() { async getPlaylists() {
@ -154,7 +169,7 @@ export class API {
return { return {
...response.playlist, ...response.playlist,
name: response.playlist.name || '(Unnamed)', name: response.playlist.name || '(Unnamed)',
tracks: this.normalizeTrackList(response.playlist.entry || []), tracks: (response.playlist.entry || []).map(this.normalizeTrack, this),
} }
} }
@ -183,12 +198,12 @@ export class API {
await this.get('rest/updatePlaylist', params) await this.get('rest/updatePlaylist', params)
} }
async getRandomSongs() { async getRandomSongs(): Promise<Track[]> {
const params = { const params = {
size: 200, size: 200,
} }
const response = await this.get('rest/getRandomSongs', params) const response = await this.get('rest/getRandomSongs', params)
return this.normalizeTrackList(response.randomSongs?.song || []) return (response.randomSongs?.song || []).map(this.normalizeTrack, this)
} }
async getStarred() { async getStarred() {
@ -196,7 +211,7 @@ export class API {
return { return {
albums: (response.starred2?.album || []).map(this.normalizeAlbum, this), albums: (response.starred2?.album || []).map(this.normalizeAlbum, this),
artists: (response.starred2?.artist || []).map(this.normalizeArtist, this), artists: (response.starred2?.artist || []).map(this.normalizeArtist, this),
tracks: this.normalizeTrackList(response.starred2?.song || []) tracks: (response.starred2?.song || []).map(this.normalizeTrack, this)
} }
} }
@ -218,37 +233,61 @@ export class API {
await this.get('rest/unstar', params) await this.get('rest/unstar', params)
} }
async search(query: string) { async search(query: string): Promise<SearchResult> {
const params = { const params = {
query, query,
} }
const data = await this.get('rest/search3', params) const data = await this.get('rest/search3', params)
return { return {
tracks: this.normalizeTrackList(data.searchResult3.song || []), tracks: (data.searchResult3.song || []).map(this.normalizeTrack, this),
albums: (data.searchResult3.album || []).map((x: any) => this.normalizeAlbum(x)), albums: (data.searchResult3.album || []).map(this.normalizeAlbum, this),
artists: (data.searchResult3.artist || []).map((x: any) => this.normalizeArtist(x)), artists: (data.searchResult3.artist || []).map(this.normalizeArtist, this),
} }
} }
private normalizeTrackList(items: any[]) { private normalizeTrack(item: any): Track {
return items.map(item => ({ return {
...item, id: item.id,
title: item.title,
duration: item.duration,
starred: !!item.starred,
track: item.track,
album: item.album,
albumId: item.albumId,
artist: item.artist,
artistId: item.artistId,
url: this.getStreamUrl(item.id), url: this.getStreamUrl(item.id),
image: this.getCoverArtUrl(item), image: this.getCoverArtUrl(item),
}))
}
private normalizeAlbum(item: any) {
return {
...item,
image: this.getCoverArtUrl(item)
} }
} }
private normalizeArtist(item: any) { private normalizeAlbum(item: any): Album {
return { return {
...item, id: item.id,
image: this.getCoverArtUrl(item) name: item.name,
artist: item.artist,
artistId: item.artistId,
image: this.getCoverArtUrl(item),
year: item.year || 0,
starred: !!item.starred,
tracks: (item.song || []).map(this.normalizeTrack, this)
}
}
private normalizeArtist(item: any): Artist {
return {
id: item.id,
name: item.name,
description: (item.biography || '').replace(/<a[^>]*>.*?<\/a>/gm, ''),
starred: !!item.starred,
image: item.largeImageUrl || item.mediumImageUrl || item.smallImageUrl,
albumCount: item.albumCount,
lastFmUrl: item.lastFmUrl,
musicBrainzUrl: item.musicBrainzId
? `https://musicbrainz.org/artist/${item.musicBrainzId}`
: undefined,
albums: item.album?.map(this.normalizeAlbum, this),
similarArtist: (item.similarArtist || []).map(this.normalizeArtist, this)
} }
} }