mirror of
https://github.com/Dvorinka/swingmusic-extended.git
synced 2026-06-03 20:13:02 +00:00
some bug fixes
- watch route params instead of route object in folderview - move to script setup on album view - use album as a reactive object instead of refs - use axios instead of fetch to get album data - improve clickable areas on songItem - move album requests to POST
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
.b-bar {
|
||||
height: 100%;
|
||||
border-top: solid 1px $gray;
|
||||
background-color: $gray;
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
@@ -36,7 +36,7 @@
|
||||
|
||||
.artists {
|
||||
font-size: 0.8rem;
|
||||
color: $red;
|
||||
color: $white;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,7 +48,6 @@
|
||||
align-items: center;
|
||||
margin: $small;
|
||||
padding: $small;
|
||||
background-color: $gray5;
|
||||
|
||||
.progress-bottom {
|
||||
display: flex;
|
||||
|
||||
@@ -1,18 +1,22 @@
|
||||
<template>
|
||||
<div class="album-h">
|
||||
<div class="a-header rounded">
|
||||
<div
|
||||
class="image art shadow-lg"
|
||||
:style="{ backgroundImage: `url("${encodeURI(props.album_info.image)}")` }"
|
||||
></div>
|
||||
<div class="info">
|
||||
<div class="top">
|
||||
<div class="h">Album</div>
|
||||
<div class="separator no-border"></div>
|
||||
<div class="title">{{ album_info.name }}</div>
|
||||
<div class="artist">{{ album_info.artist }}</div>
|
||||
<div class="title">{{ props.album_info.name }}</div>
|
||||
<div class="artist">{{ props.album_info.artist }}</div>
|
||||
</div>
|
||||
<div class="separator no-border"></div>
|
||||
<div class="bottom">
|
||||
<div class="stats shadow-sm">
|
||||
{{ album_info.count }} Tracks • {{ album_info.duration }} •
|
||||
{{ album_info.date }}
|
||||
{{ props.album_info.count }} Tracks • {{ props.album_info.duration }} •
|
||||
{{ props.album_info.date }}
|
||||
</div>
|
||||
<div class="play rounded" @click="playAlbum">
|
||||
<div class="icon"></div>
|
||||
@@ -24,22 +28,20 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import state from "@/composables/state.js";
|
||||
import perks from "@/composables/perks.js";
|
||||
|
||||
export default {
|
||||
props: ["album_info"],
|
||||
setup() {
|
||||
function playAlbum() {
|
||||
perks.updateQueue(state.album_song_list.value[0], "album");
|
||||
}
|
||||
|
||||
return {
|
||||
playAlbum,
|
||||
};
|
||||
const props = defineProps({
|
||||
album_info: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
function playAlbum() {
|
||||
perks.updateQueue(state.album.tracklist[0], "album");
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@@ -59,7 +61,7 @@ export default {
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: $small;
|
||||
padding: 1rem;
|
||||
height: 100%;
|
||||
background-image: linear-gradient(
|
||||
56deg,
|
||||
@@ -73,12 +75,20 @@ export default {
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
|
||||
.art {
|
||||
position: absolute;
|
||||
width: 12rem;
|
||||
height: 12rem;
|
||||
left: 1rem;
|
||||
}
|
||||
|
||||
.info {
|
||||
width: 100%;
|
||||
height: calc(100%);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-end;
|
||||
margin-left: 13rem;
|
||||
|
||||
.top {
|
||||
.h {
|
||||
@@ -88,6 +98,7 @@ export default {
|
||||
font-size: 2rem;
|
||||
font-weight: 1000;
|
||||
color: white;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.artist {
|
||||
|
||||
@@ -13,6 +13,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="search">
|
||||
<div class="loaderr">
|
||||
<Loader />
|
||||
</div>
|
||||
<input
|
||||
type="text"
|
||||
class="search-input border"
|
||||
@@ -26,11 +29,13 @@
|
||||
|
||||
<script>
|
||||
import perks from "@/composables/perks.js";
|
||||
import { watch } from '@vue/runtime-core';
|
||||
import useDebouncedRef from '@/composables/useDebouncedRef.js';
|
||||
import { watch } from "@vue/runtime-core";
|
||||
import useDebouncedRef from "@/composables/useDebouncedRef.js";
|
||||
import Loader from "../shared/Loader.vue";
|
||||
|
||||
export default {
|
||||
props: ["path", "first_song"],
|
||||
components: { Loader },
|
||||
setup(props, { emit }) {
|
||||
const query = useDebouncedRef("", 400);
|
||||
|
||||
@@ -63,8 +68,13 @@ export default {
|
||||
.folder-top .search {
|
||||
width: 50%;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
place-items: end;
|
||||
|
||||
.loaderr {
|
||||
width: 2rem;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
max-width: 20rem;
|
||||
width: 100%;
|
||||
@@ -123,4 +133,4 @@ export default {
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -69,7 +69,7 @@ import useDebouncedRef from "@/composables/useDebouncedRef";
|
||||
import AlbumGrid from "@/components/Search/AlbumGrid.vue";
|
||||
import ArtistGrid from "@/components/Search/ArtistGrid.vue";
|
||||
import TracksGrid from "@/components/Search/TracksGrid.vue";
|
||||
import Loader from "@/components/Search/Loader.vue";
|
||||
import Loader from "@/components/shared/Loader.vue";
|
||||
import Options from "@/components/Search/Options.vue";
|
||||
import Filters from "@/components/Search/Filters.vue";
|
||||
import "@/assets/css/Search/Search.scss";
|
||||
@@ -138,7 +138,7 @@ export default {
|
||||
}
|
||||
|
||||
function loadMoreTracks(start) {
|
||||
// scrollSearchThing();
|
||||
scrollSearchThing();
|
||||
loadMore.loadMoreTracks(start).then((response) => {
|
||||
tracks.tracks = [...tracks.tracks, ...response.tracks];
|
||||
tracks.more = response.more;
|
||||
|
||||
@@ -4,15 +4,10 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import state from "@/composables/state.js";
|
||||
export default {
|
||||
setup() {
|
||||
return {
|
||||
loading: state.loading,
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
const loading = state.loading
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@@ -1,10 +1,15 @@
|
||||
<template>
|
||||
<tr class="songlist-item" :class="{ current: current.trackid === song.trackid }" @dblclick="emitUpdate(song)">
|
||||
<tr
|
||||
class="songlist-item"
|
||||
:class="{ current: current.trackid === song.trackid }"
|
||||
@dblclick="emitUpdate(song)"
|
||||
>
|
||||
<td class="index">{{ index }}</td>
|
||||
<td class="flex" @click="emitUpdate(song)">
|
||||
<td class="flex">
|
||||
<div
|
||||
class="album-art image"
|
||||
:style="{ backgroundImage: `url("${song.image}"` }"
|
||||
@click="emitUpdate(song)"
|
||||
>
|
||||
<div
|
||||
class="now-playing-track image"
|
||||
@@ -12,8 +17,8 @@
|
||||
:class="{ active: is_playing, not_active: !is_playing }"
|
||||
></div>
|
||||
</div>
|
||||
<div>
|
||||
<span class="ellip">{{ song.title }}</span>
|
||||
<div @click="emitUpdate(song)">
|
||||
<span class="ellip title">{{ song.title }}</span>
|
||||
<div class="artist ellip">
|
||||
<span v-for="artist in putCommas(song.artists)" :key="artist">
|
||||
{{ artist }}
|
||||
@@ -35,7 +40,10 @@
|
||||
</div>
|
||||
</td>
|
||||
<td class="song-album">
|
||||
<div class="ellip" @click="emitLoadAlbum(song.album, song.albumartist)">
|
||||
<div
|
||||
class="album ellip"
|
||||
@click="emitLoadAlbum(song.album, song.albumartist)"
|
||||
>
|
||||
{{ song.album }}
|
||||
</div>
|
||||
</td>
|
||||
@@ -94,12 +102,10 @@ export default {
|
||||
}
|
||||
|
||||
.song-duration {
|
||||
font-size: .8rem;
|
||||
font-size: 0.8rem;
|
||||
width: 5rem !important;
|
||||
}
|
||||
|
||||
cursor: pointer;
|
||||
|
||||
.flex {
|
||||
position: relative;
|
||||
padding-left: 4rem;
|
||||
@@ -113,13 +119,19 @@ export default {
|
||||
margin-right: 1rem;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
border-radius: .5rem;
|
||||
border-radius: 0.5rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.title {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.artist {
|
||||
display: none;
|
||||
font-size: 0.8rem;
|
||||
color: rgba(255, 255, 255, 0.719);
|
||||
cursor: pointer;
|
||||
|
||||
@include phone-only {
|
||||
display: unset;
|
||||
@@ -136,7 +148,7 @@ export default {
|
||||
border-radius: $small 0 0 $small;
|
||||
}
|
||||
|
||||
td:nth-child(2){
|
||||
td:nth-child(2) {
|
||||
border-radius: 0 $small $small 0;
|
||||
|
||||
@include phone-only {
|
||||
@@ -194,12 +206,21 @@ export default {
|
||||
}
|
||||
|
||||
.song-album {
|
||||
.album {
|
||||
cursor: pointer;
|
||||
width: max-content;
|
||||
}
|
||||
|
||||
@include tablet-portrait {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.song-artists {
|
||||
.artist {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@include phone-only {
|
||||
display: none;
|
||||
}
|
||||
|
||||
+31
-30
@@ -1,44 +1,45 @@
|
||||
let base_uri = "http://0.0.0.0:9876";
|
||||
import axios from "axios";
|
||||
import state from "./state";
|
||||
|
||||
const getAlbumTracks = async (name, artist) => {
|
||||
const res = await fetch(
|
||||
base_uri +
|
||||
"/album/" +
|
||||
encodeURIComponent(name) + "/" +
|
||||
encodeURIComponent(artist) +
|
||||
"/tracks"
|
||||
);
|
||||
const getAlbumTracks = async (album, artist) => {
|
||||
let data = {};
|
||||
|
||||
if (!res.ok) {
|
||||
const message = `An error has occurred: ${res.status}`;
|
||||
throw new Error(message);
|
||||
}
|
||||
await axios
|
||||
.post(state.settings.uri + "/album/tracks", {
|
||||
album: album,
|
||||
artist: artist,
|
||||
})
|
||||
.then((res) => {
|
||||
data = res.data;
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
return await res.json();
|
||||
return data;
|
||||
};
|
||||
|
||||
const getAlbumArtists = async (name, artist) => {
|
||||
const res = await fetch(
|
||||
base_uri +
|
||||
"/album/" +
|
||||
encodeURIComponent(name.replaceAll("/", "|")) +
|
||||
"/" +
|
||||
encodeURIComponent(artist.replaceAll("/", "|")) +
|
||||
"/artists"
|
||||
);
|
||||
const getAlbumArtists = async (album, artist) => {
|
||||
let artists = [];
|
||||
|
||||
if (!res.ok) {
|
||||
const message = `An error has occurred: ${res.status}`;
|
||||
throw new Error(message);
|
||||
}
|
||||
await axios
|
||||
.post(state.settings.uri + "/album/artists", {
|
||||
album: album,
|
||||
artist: artist,
|
||||
})
|
||||
.then((res) => {
|
||||
artists = res.data.artists;
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
const data = await res.json();
|
||||
return data.artists;
|
||||
return artists;
|
||||
};
|
||||
|
||||
const getAlbumBio = async (name, artist) => {
|
||||
const res = await fetch(
|
||||
base_uri +
|
||||
state.settings.uri +
|
||||
"/album/" +
|
||||
encodeURIComponent(name.replaceAll("/", "|")) +
|
||||
"/" +
|
||||
|
||||
@@ -89,7 +89,7 @@ const updateQueue = async (song, type) => {
|
||||
list = state.folder_song_list.value;
|
||||
break;
|
||||
case "album":
|
||||
list = state.album_song_list.value;
|
||||
list = state.album.tracklist;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,24 +5,25 @@ import state from "./state.js";
|
||||
|
||||
async function toAlbum(title, artist) {
|
||||
console.log("routing to album");
|
||||
|
||||
state.loading.value = true;
|
||||
await album
|
||||
.getAlbumTracks(title, artist)
|
||||
.then((data) => {
|
||||
state.album_song_list.value = data.songs;
|
||||
state.album_info.value = data.info;
|
||||
state.album.tracklist = data.songs;
|
||||
state.album.info = data.info;
|
||||
})
|
||||
.then(
|
||||
await album.getAlbumArtists(title, artist).then((data) => {
|
||||
state.album_artists.value = data;
|
||||
state.album.artists = data;
|
||||
})
|
||||
)
|
||||
.then(
|
||||
album.getAlbumBio(title, artist).then((data) => {
|
||||
if (data === "None") {
|
||||
state.album_bio.value = null;
|
||||
state.album.bio = null;
|
||||
} else {
|
||||
state.album_bio.value = data;
|
||||
state.album.bio = data;
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
+12
-14
@@ -1,4 +1,5 @@
|
||||
import { ref } from "@vue/reactivity";
|
||||
import { reactive } from "vue";
|
||||
|
||||
const search_query = ref("");
|
||||
|
||||
@@ -33,10 +34,12 @@ const prev = ref({
|
||||
},
|
||||
});
|
||||
|
||||
const album_song_list = ref([]);
|
||||
const album_info = ref([]);
|
||||
const album_artists = ref([]);
|
||||
const album_bio = ref("");
|
||||
const album = reactive({
|
||||
tracklist: [],
|
||||
info: {},
|
||||
artists: [],
|
||||
bio: "",
|
||||
});
|
||||
|
||||
const filters = ref([]);
|
||||
|
||||
@@ -45,9 +48,9 @@ const loading = ref(false);
|
||||
|
||||
const is_playing = ref(false);
|
||||
|
||||
const search_tracks = ref([]);
|
||||
const search_albums = ref([]);
|
||||
const search_artists = ref([]);
|
||||
const settings = reactive({
|
||||
uri: "http://0.0.0.0:9876",
|
||||
})
|
||||
|
||||
export default {
|
||||
search_query,
|
||||
@@ -60,11 +63,6 @@ export default {
|
||||
magic_flag,
|
||||
loading,
|
||||
is_playing,
|
||||
search_tracks,
|
||||
search_albums,
|
||||
search_artists,
|
||||
album_song_list,
|
||||
album_info,
|
||||
album_artists,
|
||||
album_bio,
|
||||
album,
|
||||
settings,
|
||||
};
|
||||
|
||||
@@ -5,11 +5,6 @@ import router from "./router";
|
||||
|
||||
import "../src/assets/css/global.scss";
|
||||
|
||||
import mitt from "mitt";
|
||||
|
||||
const emitter = mitt();
|
||||
|
||||
const app = createApp(App);
|
||||
app.use(router);
|
||||
app.provide('emitter', emitter);
|
||||
app.mount('#app');
|
||||
+18
-45
@@ -1,26 +1,24 @@
|
||||
<template>
|
||||
<div class="al-view rounded">
|
||||
<div>
|
||||
<Header :album_info="album_info" />
|
||||
<Header :album_info="state.album.info" />
|
||||
</div>
|
||||
<div class="separator" id="av-sep"></div>
|
||||
<div class="songs rounded">
|
||||
<SongList :songs="album_songs" />
|
||||
<SongList :songs="state.album.tracklist" />
|
||||
</div>
|
||||
<div class="separator" id="av-sep"></div>
|
||||
<FeaturedArtists :artists="artists" />
|
||||
<div v-if="bio">
|
||||
<FeaturedArtists :artists="state.album.artists" />
|
||||
<div v-if="state.album.bio">
|
||||
<div class="separator" id="av-sep"></div>
|
||||
<AlbumBio :bio="bio" v-if="bio" />
|
||||
<AlbumBio :bio="state.album.bio" v-if="state.album.bio" />
|
||||
</div>
|
||||
<!-- <div class="separator" id="av-sep"></div> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import { useRoute } from "vue-router";
|
||||
import { onMounted } from "@vue/runtime-core";
|
||||
import { onUnmounted } from "@vue/runtime-core";
|
||||
import { watch } from "vue";
|
||||
import Header from "../components/AlbumView/Header.vue";
|
||||
import AlbumBio from "../components/AlbumView/AlbumBio.vue";
|
||||
@@ -31,45 +29,20 @@ import FeaturedArtists from "../components/PlaylistView/FeaturedArtists.vue";
|
||||
import state from "@/composables/state.js";
|
||||
import routeLoader from "@/composables/routeLoader.js";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Header,
|
||||
AlbumBio,
|
||||
SongList,
|
||||
FeaturedArtists,
|
||||
},
|
||||
setup() {
|
||||
const route = useRoute();
|
||||
const route = useRoute();
|
||||
|
||||
watch(
|
||||
() => route.params,
|
||||
() => {
|
||||
if (route.name === "AlbumView") {
|
||||
routeLoader.toAlbum(route.params.album, route.params.artist);
|
||||
}
|
||||
onMounted(() => {
|
||||
routeLoader.toAlbum(route.params.album, route.params.artist);
|
||||
|
||||
watch(
|
||||
() => route.params,
|
||||
() => {
|
||||
if (route.name === "AlbumView") {
|
||||
routeLoader.toAlbum(route.params.album, route.params.artist);
|
||||
}
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
console.log("mounted");
|
||||
routeLoader.toAlbum(route.params.album, route.params.artist);
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
state.album_song_list.value = [];
|
||||
state.album_info.value = {};
|
||||
state.album_artists.value = [];
|
||||
state.album_bio.value = "";
|
||||
});
|
||||
|
||||
return {
|
||||
album_songs: state.album_song_list,
|
||||
album_info: state.album_info,
|
||||
artists: state.album_artists,
|
||||
bio: state.album_bio,
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
@@ -101,13 +101,16 @@ export default {
|
||||
|
||||
getDirData(path.value);
|
||||
|
||||
watch(route, (new_route) => {
|
||||
path.value = new_route.params.path;
|
||||
watch(
|
||||
() => route.params,
|
||||
() => {
|
||||
path.value = route.params.path;
|
||||
|
||||
if (!path.value) return;
|
||||
if (!path.value) return;
|
||||
|
||||
getDirData(path.value);
|
||||
});
|
||||
getDirData(path.value);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
function updateQueryString(value) {
|
||||
|
||||
Reference in New Issue
Block a user