mirror of
https://github.com/tcsenpai/swingmusic.git
synced 2025-06-09 12:37:22 +00:00
attach artist page link to ArtistName component
+ separate fetching artist albums with fetching artist info + include limit when fetching artist albums + refactor interfaces
This commit is contained in:
parent
e54fea2d4d
commit
580dce1da9
@ -25,10 +25,10 @@ import { isLight } from "@/composables/colors/album";
|
|||||||
|
|
||||||
const album = useAlbumStore();
|
const album = useAlbumStore();
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(async () => {
|
||||||
// onMounted, fetch data to be used in the component below this one.
|
// onMounted, fetch data to be used in the component below this one.
|
||||||
const album = useAlbumStore();
|
const album = useAlbumStore();
|
||||||
album.fetchArtistAlbums();
|
await album.fetchArtistAlbums();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -40,11 +40,10 @@
|
|||||||
<div class="stats ellip">
|
<div class="stats ellip">
|
||||||
<div class="border rounded-sm pad-sm">
|
<div class="border rounded-sm pad-sm">
|
||||||
<ArtistName
|
<ArtistName
|
||||||
:artists="album.albumartists.map((a) => a.name)"
|
:artists="album.albumartists"
|
||||||
:albumartists="''"
|
:albumartists="''"
|
||||||
:small="true"
|
:small="true"
|
||||||
/>
|
/> • {{ album.date }} • {{ album.count }}
|
||||||
• {{ album.date }} • {{ album.count }}
|
|
||||||
{{ album.count === 1 ? "Track" : "Tracks" }} •
|
{{ album.count === 1 ? "Track" : "Tracks" }} •
|
||||||
{{ formatSeconds(album.duration, true) }}
|
{{ formatSeconds(album.duration, true) }}
|
||||||
</div>
|
</div>
|
||||||
@ -57,7 +56,7 @@
|
|||||||
v-for="a in album.albumartists"
|
v-for="a in album.albumartists"
|
||||||
:to="{
|
:to="{
|
||||||
name: Routes.artist,
|
name: Routes.artist,
|
||||||
params: { hash: a.hash },
|
params: { hash: a.artisthash },
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
@ -130,6 +129,21 @@ useVisibility(albumheaderthing, handleVisibilityState);
|
|||||||
background-color: $black;
|
background-color: $black;
|
||||||
align-items: flex-end;
|
align-items: flex-end;
|
||||||
|
|
||||||
|
// .albumartists {
|
||||||
|
// outline: solid 1px;
|
||||||
|
// // display: flex;
|
||||||
|
// // width: 100%;
|
||||||
|
// // flex-wrap: nowrap;
|
||||||
|
// // height: 1rem;
|
||||||
|
// // overflow: hidden;
|
||||||
|
|
||||||
|
// span {
|
||||||
|
// // white-space: nowrap;
|
||||||
|
// // overflow: hidden;
|
||||||
|
// // text-overflow: ellipsis;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
.big-img {
|
.big-img {
|
||||||
height: calc(100%);
|
height: calc(100%);
|
||||||
width: 16rem;
|
width: 16rem;
|
||||||
@ -204,6 +218,7 @@ useVisibility(albumheaderthing, handleVisibilityState);
|
|||||||
|
|
||||||
.artist {
|
.artist {
|
||||||
font-size: 1.15rem;
|
font-size: 1.15rem;
|
||||||
|
background-color: red;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,11 +230,20 @@ useVisibility(albumheaderthing, handleVisibilityState);
|
|||||||
margin-bottom: 0.75rem;
|
margin-bottom: 0.75rem;
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
|
|
||||||
|
.artistname {
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
div {
|
div {
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
width: fit-content;
|
flex-wrap: wrap;
|
||||||
cursor: text;
|
// width: fit-content;
|
||||||
|
// cursor: text;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,30 +1,55 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
v-tooltip
|
|
||||||
style="width: fit-content"
|
style="width: fit-content"
|
||||||
class="ellip"
|
v-tooltip
|
||||||
|
class="artistname ellip"
|
||||||
:style="{
|
:style="{
|
||||||
|
width: 'fit-content',
|
||||||
fontSize: small ? '0.85rem' : smaller ? 'small' : '',
|
fontSize: small ? '0.85rem' : smaller ? 'small' : '',
|
||||||
}"
|
}"
|
||||||
|
@click.stop="() => {}"
|
||||||
>
|
>
|
||||||
<div v-if="artists === null || artists.length === 0">
|
<div v-if="artists === null || artists.length === 0">
|
||||||
<span>{{ albumartists }}</span>
|
<span>{{ albumartists }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<span v-for="artist in putCommas(artists)" :key="artist">{{
|
<template v-for="(artist, index) in artists" :key="artist.artisthash">
|
||||||
artist
|
<RouterLink
|
||||||
}}</span>
|
class="artist"
|
||||||
|
:to="{
|
||||||
|
name: Routes.artist,
|
||||||
|
params: { hash: artist.artisthash },
|
||||||
|
}"
|
||||||
|
>{{ `${artist.name}` }}</RouterLink
|
||||||
|
>
|
||||||
|
{{ index === artists.length - 1 ? "" : ", " }}
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { Artist } from "@/interfaces";
|
||||||
import { putCommas } from "@/utils";
|
import { putCommas } from "@/utils";
|
||||||
|
import { Routes } from "@/composables/enums";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
artists: string[] | null;
|
artists: Artist[] | null;
|
||||||
albumartists: string | null;
|
albumartists: string | null;
|
||||||
small?: boolean;
|
small?: boolean;
|
||||||
smaller?: boolean;
|
smaller?: boolean;
|
||||||
}>();
|
}>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.artistname {
|
||||||
|
a {
|
||||||
|
color: inherit;
|
||||||
|
cursor: pointer !important;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@ -131,6 +131,7 @@ function showMenu(e: MouseEvent) {
|
|||||||
|
|
||||||
.song-album {
|
.song-album {
|
||||||
max-width: max-content;
|
max-width: max-content;
|
||||||
|
|
||||||
cursor: pointer !important;
|
cursor: pointer !important;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
|
@ -5,22 +5,32 @@ import { Artist, Track, Album } from "@/interfaces";
|
|||||||
const getArtistData = async (hash: string) => {
|
const getArtistData = async (hash: string) => {
|
||||||
interface ArtistData {
|
interface ArtistData {
|
||||||
artist: Artist;
|
artist: Artist;
|
||||||
albums: Album[];
|
|
||||||
tracks: Track[];
|
tracks: Track[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const { data, error } = await useAxios({
|
const { data, error } = await useAxios({
|
||||||
get: true,
|
get: true,
|
||||||
url: paths.api.artist + `/${hash}?limit=6`,
|
url: paths.api.artist + `/${hash}`,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(data);
|
|
||||||
|
|
||||||
return data as ArtistData;
|
return data as ArtistData;
|
||||||
};
|
};
|
||||||
|
|
||||||
export { getArtistData };
|
const getArtistAlbums = async (hash: string, limit = 6) => {
|
||||||
|
const { data, error } = await useAxios({
|
||||||
|
get: true,
|
||||||
|
url: paths.api.artist + `/${hash}/albums?limit=${limit}`,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return data.albums as Album[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export { getArtistData, getArtistAlbums };
|
||||||
|
@ -6,11 +6,16 @@ export default () => {
|
|||||||
if ("mediaSession" in navigator) {
|
if ("mediaSession" in navigator) {
|
||||||
const queue = useQueueStore();
|
const queue = useQueueStore();
|
||||||
const { currenttrack: track } = queue;
|
const { currenttrack: track } = queue;
|
||||||
const url = paths.images.thumb.large
|
|
||||||
|
if (track === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = paths.images.thumb.large;
|
||||||
|
|
||||||
navigator.mediaSession.metadata = new window.MediaMetadata({
|
navigator.mediaSession.metadata = new window.MediaMetadata({
|
||||||
title: track.title,
|
title: track.title,
|
||||||
artist: track.artist.join(", "),
|
artist: track.artist.map((a) => a.name).join(", "),
|
||||||
artwork: [
|
artwork: [
|
||||||
{
|
{
|
||||||
src: url + track.image,
|
src: url + track.image,
|
||||||
|
@ -20,7 +20,6 @@ const imageRoutes = {
|
|||||||
large: "/t/",
|
large: "/t/",
|
||||||
small: "/t/s/",
|
small: "/t/s/",
|
||||||
},
|
},
|
||||||
// artist: "/a/",
|
|
||||||
artist: {
|
artist: {
|
||||||
large: "/a/",
|
large: "/a/",
|
||||||
small: "/a/s/",
|
small: "/a/s/",
|
||||||
|
@ -9,7 +9,7 @@ export interface Track extends AlbumDisc {
|
|||||||
id: string;
|
id: string;
|
||||||
title: string;
|
title: string;
|
||||||
album?: string;
|
album?: string;
|
||||||
artist: string[];
|
artist: Artist[];
|
||||||
albumartist: string;
|
albumartist: string;
|
||||||
albumhash?: string;
|
albumhash?: string;
|
||||||
folder?: string;
|
folder?: string;
|
||||||
@ -37,11 +37,7 @@ export interface Folder {
|
|||||||
export interface Album {
|
export interface Album {
|
||||||
albumid: string;
|
albumid: string;
|
||||||
title: string;
|
title: string;
|
||||||
albumartists: {
|
albumartists: Artist[];
|
||||||
name: string;
|
|
||||||
hash: string;
|
|
||||||
image: string;
|
|
||||||
}[];
|
|
||||||
count: number;
|
count: number;
|
||||||
duration: number;
|
duration: number;
|
||||||
date: string;
|
date: string;
|
||||||
|
@ -21,5 +21,17 @@ const isMedium = computed(() => {
|
|||||||
const albumHeaderSmall = computed(() => {
|
const albumHeaderSmall = computed(() => {
|
||||||
return content_width.value <= brk.album_header_small;
|
return content_width.value <= brk.album_header_small;
|
||||||
});
|
});
|
||||||
|
const album_card_with = 10 * 16;
|
||||||
|
|
||||||
export { content_width, window_width, isSmall, isMedium, albumHeaderSmall };
|
const maxAbumCards = computed(() => {
|
||||||
|
return Math.floor(content_width.value / album_card_with);
|
||||||
|
});
|
||||||
|
|
||||||
|
export {
|
||||||
|
content_width,
|
||||||
|
window_width,
|
||||||
|
isSmall,
|
||||||
|
isMedium,
|
||||||
|
albumHeaderSmall,
|
||||||
|
maxAbumCards,
|
||||||
|
};
|
||||||
|
@ -4,11 +4,11 @@ import { ComputedRef } from "vue";
|
|||||||
import { AlbumDisc } from "./../../interfaces";
|
import { AlbumDisc } from "./../../interfaces";
|
||||||
|
|
||||||
import { FuseTrackOptions } from "@/composables/enums";
|
import { FuseTrackOptions } from "@/composables/enums";
|
||||||
import { content_width } from "@/stores/content-width";
|
import { maxAbumCards } from "@/stores/content-width";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
getAlbumsFromArtist,
|
getAlbumsFromArtist,
|
||||||
getAlbumTracks
|
getAlbumTracks,
|
||||||
} from "../../composables/fetch/album";
|
} from "../../composables/fetch/album";
|
||||||
import { Album, Artist, FuseResult, Track } from "../../interfaces";
|
import { Album, Artist, FuseResult, Track } from "../../interfaces";
|
||||||
import { useNotifStore } from "../notification";
|
import { useNotifStore } from "../notification";
|
||||||
@ -27,11 +27,11 @@ function sortByTrackNumber(tracks: Track[]) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function albumHasNoDiscs(album: Album) {
|
// function albumHasNoDiscs(album: Album) {
|
||||||
if (album.is_single) return true;
|
// if (album.is_single) return true;
|
||||||
|
|
||||||
return false;
|
// return false;
|
||||||
}
|
// }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -68,13 +68,12 @@ export default defineStore("album", {
|
|||||||
},
|
},
|
||||||
async fetchArtistAlbums() {
|
async fetchArtistAlbums() {
|
||||||
const albumartists = this.info.albumartists;
|
const albumartists = this.info.albumartists;
|
||||||
const cardWidth = 10 * 16;
|
|
||||||
const visible_cards = Math.floor(content_width.value / cardWidth);
|
const albumartisthashes = albumartists.map((artist) => artist.artisthash);
|
||||||
const albumartisthashes = albumartists.map((artist) => artist.hash);
|
|
||||||
|
|
||||||
this.albumArtists = await getAlbumsFromArtist(
|
this.albumArtists = await getAlbumsFromArtist(
|
||||||
albumartisthashes.join(),
|
albumartisthashes.join(),
|
||||||
visible_cards,
|
maxAbumCards.value,
|
||||||
this.info.albumhash
|
this.info.albumhash
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
|
|
||||||
import { Artist, Album, Track } from "@/interfaces";
|
import { Artist, Album, Track } from "@/interfaces";
|
||||||
import { getArtistData } from "@/composables/fetch/artists";
|
import { getArtistData, getArtistAlbums } from "@/composables/fetch/artists";
|
||||||
|
import { maxAbumCards } from "@/stores/content-width";
|
||||||
|
|
||||||
export default defineStore("artistPage", {
|
export default defineStore("artistPage", {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
@ -11,11 +12,23 @@ export default defineStore("artistPage", {
|
|||||||
}),
|
}),
|
||||||
actions: {
|
actions: {
|
||||||
async getData(hash: string) {
|
async getData(hash: string) {
|
||||||
const { artist, albums, tracks } = await getArtistData(hash);
|
const { artist, tracks } = await getArtistData(hash);
|
||||||
|
|
||||||
this.info = artist;
|
this.info = artist;
|
||||||
this.tracks = tracks;
|
this.tracks = tracks;
|
||||||
|
},
|
||||||
|
async getArtistAlbums() {
|
||||||
|
const albums = await getArtistAlbums(
|
||||||
|
this.info.artisthash,
|
||||||
|
maxAbumCards.value
|
||||||
|
);
|
||||||
|
|
||||||
|
if (albums.length > 0) {
|
||||||
this.albums = albums;
|
this.albums = albums;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
resetAlbums() {
|
||||||
|
this.albums = [];
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -86,7 +86,7 @@ function getSongItems() {
|
|||||||
function getArtistAlbumComponents(): ScrollerItem[] {
|
function getArtistAlbumComponents(): ScrollerItem[] {
|
||||||
return album.albumArtists.map((artist) => {
|
return album.albumArtists.map((artist) => {
|
||||||
const artist_name = album.info.albumartists.find(
|
const artist_name = album.info.albumartists.find(
|
||||||
(a) => a.hash === artist.artisthash
|
(a) => a.artisthash === artist.artisthash
|
||||||
)?.name;
|
)?.name;
|
||||||
return {
|
return {
|
||||||
id: Math.random().toString(),
|
id: Math.random().toString(),
|
||||||
@ -121,7 +121,7 @@ function playFromAlbum(index: number) {
|
|||||||
queue.play(index);
|
queue.play(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
onBeforeRouteUpdate(async (to: RouteLocationNormalized) => {
|
onBeforeRouteUpdate(async (to) => {
|
||||||
await album.fetchTracksAndArtists(to.params.hash.toString()).then(() => {
|
await album.fetchTracksAndArtists(to.params.hash.toString()).then(() => {
|
||||||
album.resetQuery();
|
album.resetQuery();
|
||||||
album.resetAlbumArtists();
|
album.resetAlbumArtists();
|
||||||
|
18
src/views/ArtistView/ArtistAlbumsFetcher.vue
Normal file
18
src/views/ArtistView/ArtistAlbumsFetcher.vue
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<template><div style="height: 1px;"></div></template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { onMounted } from "vue";
|
||||||
|
import useArtistPageStore from "@/stores/pages/artist";
|
||||||
|
import { onBeforeRouteUpdate } from "vue-router";
|
||||||
|
|
||||||
|
const store = useArtistPageStore();
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
await store.getArtistAlbums();
|
||||||
|
});
|
||||||
|
|
||||||
|
onBeforeRouteUpdate(async (to) => {
|
||||||
|
store.resetAlbums();
|
||||||
|
await store.getArtistAlbums();
|
||||||
|
});
|
||||||
|
</script>
|
@ -34,14 +34,13 @@ import { isMedium, isSmall } from "@/stores/content-width";
|
|||||||
|
|
||||||
import Header from "@/components/ArtistView/Header.vue";
|
import Header from "@/components/ArtistView/Header.vue";
|
||||||
import TopTracks from "@/components/ArtistView/TopTracks.vue";
|
import TopTracks from "@/components/ArtistView/TopTracks.vue";
|
||||||
// import Albums from "@/components/ArtistView/Albums.vue";
|
|
||||||
import useArtistPageStore from "@/stores/pages/artist";
|
import useArtistPageStore from "@/stores/pages/artist";
|
||||||
import ArtistAlbums from "@/components/AlbumView/ArtistAlbums.vue";
|
import ArtistAlbums from "@/components/AlbumView/ArtistAlbums.vue";
|
||||||
|
import ArtistAlbumsFetcher from "./ArtistAlbumsFetcher.vue";
|
||||||
import { computed } from "vue";
|
import { computed } from "vue";
|
||||||
import { onBeforeRouteUpdate } from "vue-router";
|
import { onBeforeRouteUpdate } from "vue-router";
|
||||||
|
|
||||||
const artistStore = useArtistPageStore();
|
const store = useArtistPageStore();
|
||||||
|
|
||||||
interface ScrollerItem {
|
interface ScrollerItem {
|
||||||
id: string | number;
|
id: string | number;
|
||||||
@ -59,18 +58,25 @@ const top_tracks: ScrollerItem = {
|
|||||||
component: TopTracks,
|
component: TopTracks,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const artist_albums_fetcher: ScrollerItem = {
|
||||||
|
id: "artist-albums-fetcher",
|
||||||
|
component: ArtistAlbumsFetcher,
|
||||||
|
};
|
||||||
|
|
||||||
const scrollerItems = computed(() => {
|
const scrollerItems = computed(() => {
|
||||||
let components = [header];
|
let components = [header];
|
||||||
|
|
||||||
if (artistStore.tracks.length > 0) {
|
if (store.tracks.length > 0) {
|
||||||
components.push(top_tracks);
|
components.push(top_tracks);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (artistStore.albums.length > 0) {
|
components = [...components, artist_albums_fetcher];
|
||||||
|
|
||||||
|
if (store.albums.length > 0) {
|
||||||
const artistAlbums: ScrollerItem = {
|
const artistAlbums: ScrollerItem = {
|
||||||
id: "artist-albums",
|
id: "artist-albums",
|
||||||
component: ArtistAlbums,
|
component: ArtistAlbums,
|
||||||
props: { title: "Albums", albums: artistStore.albums },
|
props: { title: "Albums", albums: store.albums },
|
||||||
};
|
};
|
||||||
|
|
||||||
components.push(artistAlbums);
|
components.push(artistAlbums);
|
||||||
@ -79,8 +85,9 @@ const scrollerItems = computed(() => {
|
|||||||
return components;
|
return components;
|
||||||
});
|
});
|
||||||
|
|
||||||
onBeforeRouteUpdate((to, from, next) => {
|
onBeforeRouteUpdate(async (to) => {
|
||||||
artistStore.getData(to.params.hash as string);
|
|
||||||
|
await store.getData(to.params.hash as string);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user