Merge branch 'main' into patch-ios-stretched-header-fix

This commit is contained in:
Shiny Nematoda 2022-09-23 12:19:41 +02:00
commit c4b27926ed
10 changed files with 441 additions and 260 deletions

View file

@ -4,9 +4,9 @@ defineEmits(['click']);
</script>
<template>
<button
:class="'bi bi-' + (ico ? ico : 'play')"
@click="$emit('click')"></button>
<button :class="'bi bi-' + (ico ? ico : 'play')" @click="$emit('click')">
<slot name="menu"></slot>
</button>
</template>
<style scoped>

View file

@ -6,7 +6,11 @@ import Modal from './Modal.vue';
import { useRand } from '@/scripts/colors.js';
import { useStore } from '@/scripts/util.js';
import { getJsonAuth, getAuthPlaylists } from '@/scripts/fetch.js';
import {
useAuthCreatePlaylist,
getAuthPlaylists,
getJsonAuth,
} from '@/scripts/fetch.js';
import { useI18n } from '@/stores/misc.js';
import {
@ -121,16 +125,7 @@ const Login = async () => {
},
createPlaylist = async () => {
if (text.value) {
const res = await getJsonAuth('/user/playlists/create', {
method: 'POST',
body: JSON.stringify({
name: `Playlist - ${text.value}`,
}),
headers: {
Authorization: store.auth,
'Content-Type': 'application/json',
},
});
const res = await useAuthCreatePlaylist(text.value);
getPlaylists();
show.new = false;

View file

@ -22,9 +22,33 @@ const { t } = useI18n(),
const emit = defineEmits(['play-urls']),
filters = ['music_songs', 'music_albums', 'music_artists'],
filter = ref('music_songs'),
isSearch = ref(/search/.test(location.pathname));
isSearch = ref(/search/.test(location.pathname)),
albumMenu = ref(false);
const saveAlbum = () => {
const shuffleAdd = () => {
const songs = results.items.songs.items.map(i => ({
url: i.url,
title: i.title,
thumbnails: [{ url: i.thumbnail }],
})),
copy = [];
let nos = songs.length;
while (nos) {
const i = Math.floor(Math.random() * nos--);
copy.push(songs[i]);
songs[i] = songs[nos];
delete songs[nos];
}
console.log(songs, copy);
emit('play-urls', copy);
},
saveAlbum = () => {
const urls = results.items?.songs?.items?.map(item => ({
url: item.url,
title: item.title,
@ -112,20 +136,32 @@ onUpdated(() => {
})),
)
" />
<Btn ico="star" @click="saveAlbum" />
<Btn
ico="plus-lg"
@click="
data.state.urls.push(
...results.items.songs.items.map(i => ({
url: i.url,
title: i.title,
thumbnails: [{ url: i.thumbnail }],
})),
)
" />
<span>{{ results.items?.songs?.title }}</span>
<Btn ico="three-dots" @click="albumMenu = !albumMenu">
<template #menu>
<Transition name="fade">
<div v-if="albumMenu" class="alb popup">
<button class="bi bi-bookmark-plus" @click="saveAlbum"></button>
<button
class="bi bi-plus-lg"
@click="
data.state.urls.push(
...results.items.songs.items.map(i => ({
url: i.url,
title: i.title,
thumbnails: [{ url: i.thumbnail }],
})),
)
"></button>
<button class="bi bi-shuffle" @click="shuffleAdd"></button>
</div>
</Transition>
</template>
</Btn>
<span class="ml-auto">{{ results.items?.songs?.title }}</span>
</div>
<div v-if="isSearch" class="filters">
@ -146,8 +182,9 @@ onUpdated(() => {
class="search-songs">
<h2 v-if="!isSearch">{{ t('title.songs') }}</h2>
<div class="grid">
<template v-for="song in results.items.songs.items">
<template v-for="(song, index) in results.items.songs.items">
<SongItem
:index="index"
:author="song.uploaderName || song.subtitle"
:title="song.title || song.name"
:channel="song.uploaderUrl || song.subId"
@ -264,10 +301,18 @@ onUpdated(() => {
margin-right: 0;
}
:deep(.bi-play) {
margin-right: 1rem;
margin-right: 0.75rem;
}
:deep(.bi-plus-lg) {
margin-right: auto;
:deep(.ml-auto) {
margin-left: auto;
}
.alb {
bottom: 2.5rem;
border-radius: 0.25rem;
box-shadow: -0.5rem 0.5rem 1rem var(--color-shadow);
}
.alb .bi {
padding: 0.5rem;
}
.filters {
display: flex;

View file

@ -1,24 +1,28 @@
<script setup>
import { ref, onMounted } from 'vue';
import { getJsonAuth } from '@/scripts/fetch.js';
import { useRand } from '@/scripts/colors.js';
import { useStore } from '@/scripts/util.js';
import { useArtist } from '@/stores/results.js';
import { useArtist, useResults } from '@/stores/results.js';
import { useData, usePlayer } from '@/stores/player.js';
const rand = useRand(),
data = useData(),
player = usePlayer(),
artist = useArtist();
artist = useArtist(),
{ playlistId } = useResults();
const props = defineProps({
index: Number,
author: String,
title: String,
channel: String,
play: String,
art: String,
}),
emit = defineEmits(['open-song']),
emit = defineEmits(['open-song', 'remove']),
show = ref(false);
const openSong = el => {
@ -43,6 +47,24 @@ const openSong = el => {
)
emit('open-song', props.play);
},
Remove = () => {
// WIP
const auth = useStore().getItem('auth');
if (auth) {
getJsonAuth('/user/playlists/remove', {
method: 'POST',
headers: {
Authorization: auth,
},
body: {
index,
playlistId,
},
});
}
},
Share = async () => {
if ('share' in navigator) {
const data = {
@ -59,7 +81,7 @@ const openSong = el => {
} else {
navigator.clipboard.writeText(location.host + props.play).then(
() => {
console.log('Copied to Clipboard');
alert('Copied to Clipboard');
},
err => {
console.log(err);
@ -79,12 +101,8 @@ onMounted(() => {
<span class="flex content">
<h4>{{ title }}</h4>
<a
:href="channel != '[]' ? channel : ''"
@click.prevent="
channel != '[]'
? artist.getArtist(channel.replace('/channel/', ''))
: ''
"
:href="channel"
@click.prevent="artist.getArtist(channel.replace('/channel/', ''))"
class="ign">
<i class="ign">{{ author ? author.replaceAll(' - Topic', '') : '' }}</i>
</a>
@ -96,6 +114,12 @@ onMounted(() => {
@mouseleave="show = false">
<Transition name="fade">
<div v-if="show" class="popup ign">
<!-- TODO: Check if user is admin -->
<span
v-if="useStore().auth && playlistId"
class="bi bi-dash-lg ign"
@click="Remove"></span>
<span class="bi bi-plus-lg ign" @click="addSong"></span>
<span class="bi bi-share ign" @click="Share"></span>
@ -135,4 +159,7 @@ span.bi-three-dots-vertical {
width: 120px;
height: 120px;
}
.bi-dash-lg {
color: indianred;
}
</style>

View file

@ -5,7 +5,11 @@ import Modal from './Modal.vue';
import { useStore } from '@/scripts/util.js';
import { useListPlaylists, useUpdatePlaylist } from '@/scripts/db.js';
import { getAuthPlaylists, getJsonAuth } from '@/scripts/fetch.js';
import {
getAuthPlaylists,
useAuthCreatePlaylist,
useAuthAddToPlaylist,
} from '@/scripts/fetch.js';
import { useData, usePlayer } from '@/stores/player.js';
import { useI18n } from '@/stores/misc.js';
@ -24,7 +28,9 @@ const emit = defineEmits(['save']),
pl = ref(''),
list = ref([]),
remote = ref([]),
plRemote = ref(false);
plRemote = ref(false),
liked = ref(undefined),
liking = ref(false);
function List() {
showme.pl = true;
@ -41,18 +47,7 @@ function List() {
function Save() {
if (pl.value) {
if (plRemote.value == true && store.auth) {
getJsonAuth('/user/playlists/add', {
method: 'POST',
headers: {
Authorization: store.auth,
},
body: JSON.stringify({
playlistId: pl.value,
videoId: new URL(
'https://example.com' + data.state.url,
).searchParams.get('v'),
}),
});
setAuthAddToPlaylist(data.state.url);
} else if (plRemote.value == false) {
useUpdatePlaylist(
pl.value,
@ -69,6 +64,26 @@ function Save() {
}
}
}
async function Like() {
liking.value = true;
remote.value = await getAuthPlaylists();
let fav = remote.value.filter(i => i.name == 'Playlist - Favorites')[0];
if (!fav) {
const { playlistId } = await useAuthCreatePlaylist('Favorites');
fav = { id: playlistId };
}
const { message } = await useAuthAddToPlaylist(fav.id, data.state.url);
if (message == 'ok') liked.value = data.state.url;
liking.value = false;
}
</script>
<template>
<Teleport to="body">
@ -183,12 +198,24 @@ function Save() {
aria-label="Show Information About Song"
:data-active="player.state.info"
@click="player.toggle('info')"></button>
<button
v-if="store.auth"
id="like-btn"
title="Add song to favorites"
class="bi blink"
:class="data.state.url == liked ? 'bi-heart-fill' : 'bi-heart'"
:data-active="data.state.url == liked"
:data-loading="liking"
@click="Like"></button>
<button
id="addToPlaylist"
title="Add Current Song to a Playlist"
aria-label="Add Current Song to a Playlist"
class="bi bi-collection"
@click="List"></button>
<button
id="list-btn"
title="Current Playlist"
@ -196,11 +223,13 @@ function Save() {
class="bi bi-music-note-list"
:data-active="player.state.playlist"
@click="player.toggle('playlist')"></button>
<button
id="btn-lyrics"
class="bi bi-file-music"
:data-active="player.state.lyrics"
@click="player.toggle('lyrics')"></button>
<button
id="loop-btn"
title="Loop"