mirror of
https://codeberg.org/Hyperpipe/Hyperpipe
synced 2025-06-27 20:58:01 +02:00
187 lines
4.4 KiB
Vue
187 lines
4.4 KiB
Vue
<script setup>
|
|
import { ref, onMounted } from 'vue';
|
|
|
|
import { getJsonAuth } from '@/scripts/fetch.js';
|
|
import { useRand } from '@/scripts/colors.js';
|
|
import { useStore, useShare } from '@/scripts/util.js';
|
|
import { useUpdatePlaylist } from '@/scripts/db.js';
|
|
|
|
import { useResults, useArtist } from '@/stores/results.js';
|
|
import { useData, usePlayer } from '@/stores/player.js';
|
|
import { useI18n } from '@/stores/misc.js';
|
|
|
|
const rand = useRand(),
|
|
data = useData(),
|
|
results = useResults(),
|
|
player = usePlayer(),
|
|
artist = useArtist(),
|
|
{ t } = useI18n();
|
|
|
|
const props = defineProps({
|
|
index: Number,
|
|
author: String,
|
|
title: String,
|
|
channel: String,
|
|
play: String,
|
|
art: String,
|
|
playlistId: String,
|
|
}),
|
|
emit = defineEmits(['open-song', 'nxt-song', 'remove']);
|
|
|
|
const show = ref(false);
|
|
|
|
const openSong = el => {
|
|
if (!el.classList.contains('ign')) {
|
|
emit('open-song', props.play);
|
|
}
|
|
},
|
|
addSong = () => {
|
|
data.state.urls.push({
|
|
url: props.play,
|
|
title: props.title,
|
|
thumbnails: [{ url: props.art }],
|
|
});
|
|
|
|
const index = data.state.urls.findIndex(s => s.url == data.state.url);
|
|
|
|
if (
|
|
(index == data.state.urls.length - 1 && player.state.time > 98) ||
|
|
data.state.urls.length == 1
|
|
)
|
|
emit('open-song', props.play);
|
|
},
|
|
appendSong = () => {
|
|
const index = data.state.urls.findIndex(s => s.url == data.state.url);
|
|
|
|
data.state.urls.splice(index + 1, 0, {
|
|
url: props.play,
|
|
title: props.title,
|
|
thumbnails: [{ url: props.art }],
|
|
});
|
|
},
|
|
Remove = () => {
|
|
const auth = useStore().getItem('auth'),
|
|
isRemote = results.items?.songs?.title?.startsWith('Playlist - ');
|
|
|
|
if (!confirm('Are you sure?')) return;
|
|
|
|
if (isRemote && auth) {
|
|
getJsonAuth('/user/playlists/remove', {
|
|
method: 'POST',
|
|
headers: {
|
|
Authorization: auth,
|
|
},
|
|
body: JSON.stringify({
|
|
index: props.index,
|
|
playlistId: props.playlistId,
|
|
}),
|
|
}).then(json => {
|
|
console.log(json);
|
|
|
|
if (!json.error) {
|
|
if (json.message == 'ok') emit('remove', props.index);
|
|
} else alert(json.error);
|
|
});
|
|
} else
|
|
useUpdatePlaylist(props.playlistId, props.index, () =>
|
|
emit('remove', props.index),
|
|
);
|
|
},
|
|
Share = () => {
|
|
const data = {
|
|
title: `Listen to ${props.title} by ${props.author} on Hyperpipe`,
|
|
url: location.origin + props.play,
|
|
};
|
|
|
|
useShare(data);
|
|
};
|
|
|
|
onMounted(() => {
|
|
console.log(props.channel, artist.state.playlistId);
|
|
});
|
|
</script>
|
|
<template>
|
|
<div class="song card flex pop" @click="openSong($event.target)">
|
|
<img class="pop-2 bg-img song-bg" loading="lazy" :src="art" alt />
|
|
|
|
<span class="flex content">
|
|
<h4>{{ title }}</h4>
|
|
<a
|
|
class="ign"
|
|
:href="channel"
|
|
@click.prevent="artist.getArtist(channel.replace('/channel/', ''))">
|
|
<i class="ign">{{ author ? author.replaceAll(' - Topic', '') : '' }}</i>
|
|
</a>
|
|
</span>
|
|
|
|
<span
|
|
class="bi bi-three-dots-vertical popup-wrap ign"
|
|
@mouseenter="show = true"
|
|
@mouseleave="show = false">
|
|
<Transition name="fade">
|
|
<div v-if="show" class="popup ign">
|
|
<span
|
|
v-if="playlistId"
|
|
class="bi bi-dash-lg clickable ign"
|
|
@click="Remove"></span>
|
|
<span
|
|
class="bi bi-chevron-bar-right clickable ign"
|
|
@click="appendSong"></span>
|
|
<span
|
|
class="bi bi-broadcast clickable ign"
|
|
@click="$emit('nxt-song')"></span>
|
|
<span class="bi bi-plus-lg clickable ign" @click="addSong"></span>
|
|
<span class="bi bi-share clickable ign" @click="Share"></span>
|
|
</div>
|
|
</Transition>
|
|
</span>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.card {
|
|
margin: 1rem 0;
|
|
justify-content: initial;
|
|
}
|
|
span.content {
|
|
padding: 1rem;
|
|
flex-direction: column;
|
|
align-items: flex-start;
|
|
flex-basis: calc(calc(100% - 120px) - 4rem);
|
|
}
|
|
span.bi-three-dots-vertical {
|
|
margin: 2rem;
|
|
}
|
|
.popup {
|
|
line-height: auto;
|
|
height: auto;
|
|
right: 0;
|
|
bottom: 0;
|
|
box-shadow: var(--shadow);
|
|
border-radius: 0.25rem;
|
|
}
|
|
.popup span {
|
|
padding: 0.5rem;
|
|
}
|
|
.song-bg {
|
|
--grad: v-bind('rand');
|
|
width: 120px;
|
|
height: 120px;
|
|
}
|
|
.bi-dash-lg {
|
|
color: indianred;
|
|
}
|
|
|
|
[data-compact] .card {
|
|
margin: 0;
|
|
}
|
|
[data-compact] .song-bg {
|
|
width: 70px;
|
|
height: 70px;
|
|
}
|
|
|
|
.prm .card {
|
|
margin: 0;
|
|
padding: 0.5rem;
|
|
}
|
|
</style>
|