mirror of
https://codeberg.org/Hyperpipe/Hyperpipe
synced 2025-06-27 20:58:01 +02:00
Created AddToPlaylist Modal
This commit is contained in:
parent
0144f1ee4e
commit
d0245c273e
10 changed files with 565 additions and 457 deletions
708
package-lock.json
generated
708
package-lock.json
generated
File diff suppressed because it is too large
Load diff
12
package.json
12
package.json
|
@ -6,23 +6,23 @@
|
||||||
"host": "vite --host",
|
"host": "vite --host",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"preview": "vite preview --port 5050",
|
"preview": "vite preview --port 5050",
|
||||||
"pretty": "prettier --write .",
|
"format": "prettier --write .",
|
||||||
"check": "prettier --check ."
|
"lint": "prettier --check ."
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bootstrap-icons": "^1.10.5",
|
"bootstrap-icons": "^1.10.5",
|
||||||
"dompurify": "^3.0.3",
|
"dompurify": "^3.0.5",
|
||||||
"mux.js": "^6.3.0",
|
"mux.js": "^6.3.0",
|
||||||
"peerjs": "^1.4.7",
|
"peerjs": "^1.4.7",
|
||||||
"pinia": "^2.1.4",
|
"pinia": "^2.1.4",
|
||||||
"shaka-player": "^4.3.6",
|
"shaka-player": "^4.3.7",
|
||||||
"sortablejs": "^1.15.0",
|
"sortablejs": "^1.15.0",
|
||||||
"vue": "^3.2.38"
|
"vue": "^3.2.38"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vitejs/plugin-vue": "^4.2.3",
|
"@vitejs/plugin-vue": "^4.2.3",
|
||||||
"prettier": "^2.8.8",
|
"prettier": "^3.0.0",
|
||||||
"vite": "^4.3.9",
|
"vite": "^4.4.4",
|
||||||
"vite-plugin-pwa": "^0.16.4"
|
"vite-plugin-pwa": "^0.16.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ import Search from '@/components/Search.vue';
|
||||||
import Playlists from '@/components/Playlists.vue';
|
import Playlists from '@/components/Playlists.vue';
|
||||||
import Lyrics from '@/components/Lyrics.vue';
|
import Lyrics from '@/components/Lyrics.vue';
|
||||||
import Info from '@/components/Info.vue';
|
import Info from '@/components/Info.vue';
|
||||||
|
import AddToPlaylist from '@/components/AddToPlaylist.vue';
|
||||||
import Artist from '@/components/Artist.vue';
|
import Artist from '@/components/Artist.vue';
|
||||||
|
|
||||||
/* Async Components */
|
/* Async Components */
|
||||||
|
@ -193,6 +194,8 @@ onMounted(() => {
|
||||||
</div>
|
</div>
|
||||||
</Transition>
|
</Transition>
|
||||||
|
|
||||||
|
<AddToPlaylist />
|
||||||
|
|
||||||
<StatusBar />
|
<StatusBar />
|
||||||
|
|
||||||
<Player />
|
<Player />
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
{
|
{
|
||||||
"date": "2023-06-20"
|
"date": "2023-07-16"
|
||||||
}
|
}
|
||||||
|
|
141
src/components/AddToPlaylist.vue
Normal file
141
src/components/AddToPlaylist.vue
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
<script setup>
|
||||||
|
import { ref, watch, onMounted, onActivated } from 'vue';
|
||||||
|
|
||||||
|
import Modal from './Modal.vue';
|
||||||
|
|
||||||
|
import { getAuthPlaylists, useAuthAddToPlaylist } from '@/scripts/fetch.js';
|
||||||
|
import { useListPlaylists, useUpdatePlaylist } from '@/scripts/db.js';
|
||||||
|
import { useStore } from '@/scripts/util.js';
|
||||||
|
|
||||||
|
import { useData, usePlayer } from '@/stores/player.js';
|
||||||
|
import { useI18n } from '@/stores/misc.js';
|
||||||
|
|
||||||
|
const { t } = useI18n(),
|
||||||
|
data = useData(),
|
||||||
|
player = usePlayer(),
|
||||||
|
store = useStore();
|
||||||
|
|
||||||
|
const pl = ref(''),
|
||||||
|
list = ref([]),
|
||||||
|
remote = ref([]),
|
||||||
|
plRemote = ref(false);
|
||||||
|
|
||||||
|
function Save() {
|
||||||
|
if (pl.value) {
|
||||||
|
if (plRemote.value == true && store.auth) {
|
||||||
|
useAuthAddToPlaylist(pl.value, data.state.url);
|
||||||
|
} else if (plRemote.value == false) {
|
||||||
|
useUpdatePlaylist(
|
||||||
|
pl.value,
|
||||||
|
{
|
||||||
|
url: data.state.url,
|
||||||
|
title: data.state.title,
|
||||||
|
},
|
||||||
|
e => {
|
||||||
|
if (e === true) console.log('Added Song');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function List() {
|
||||||
|
player.state.add = true;
|
||||||
|
useListPlaylists(res => {
|
||||||
|
list.value = res;
|
||||||
|
});
|
||||||
|
getAuthPlaylists().then(res => {
|
||||||
|
remote.value = res;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => player.state.add,
|
||||||
|
e => e == true && List(),
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Teleport to="body">
|
||||||
|
<Transition name="fade">
|
||||||
|
<Modal
|
||||||
|
n="2"
|
||||||
|
:display="player.state.add"
|
||||||
|
:title="t('playlist.select')"
|
||||||
|
@show="
|
||||||
|
e => {
|
||||||
|
player.state.add = e;
|
||||||
|
}
|
||||||
|
">
|
||||||
|
<template #content>
|
||||||
|
<div
|
||||||
|
v-for="i in list"
|
||||||
|
:key="i.name"
|
||||||
|
class="flex item"
|
||||||
|
@click="
|
||||||
|
pl = i.name;
|
||||||
|
plRemote = false;
|
||||||
|
"
|
||||||
|
:data-active="pl == i.name && plRemote == false">
|
||||||
|
<span>{{ i.name }}</span
|
||||||
|
><span class="ml-auto">{{ i.urls.length || '' }}</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-for="i in remote"
|
||||||
|
:key="i.id"
|
||||||
|
class="flex item remote"
|
||||||
|
@click="
|
||||||
|
pl = i.id;
|
||||||
|
plRemote = true;
|
||||||
|
"
|
||||||
|
:data-active="pl == i.id && plRemote == true">
|
||||||
|
<span>{{ i.name.replace('Playlist -', '') }}</span
|
||||||
|
><span class="ml-auto">{{ i.videos }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #buttons>
|
||||||
|
<button aria-label="Cancel" @click="player.state.add = false">
|
||||||
|
{{ t('action.cancel') }}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
aria-label="Add Song"
|
||||||
|
@click="
|
||||||
|
Save();
|
||||||
|
player.state.add = false;
|
||||||
|
">
|
||||||
|
{{ t('action.add') }}
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
</Modal>
|
||||||
|
</Transition>
|
||||||
|
</Teleport>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.ml-auto {
|
||||||
|
margin-left: auto;
|
||||||
|
width: min-content;
|
||||||
|
}
|
||||||
|
.item {
|
||||||
|
background: var(--color-background);
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
margin: 0.5rem 0;
|
||||||
|
transition: background-color 0.1s ease;
|
||||||
|
}
|
||||||
|
.item:hover {
|
||||||
|
background: var(--color-background-mute);
|
||||||
|
}
|
||||||
|
.item:active {
|
||||||
|
background: var(--color-border);
|
||||||
|
}
|
||||||
|
.item[data-active='true'] {
|
||||||
|
color: var(--color-background);
|
||||||
|
background: linear-gradient(135deg, cornflowerblue, #88c0d0);
|
||||||
|
}
|
||||||
|
.remote.item::before {
|
||||||
|
content: '\F4E1';
|
||||||
|
font-family: bootstrap-icons;
|
||||||
|
font-size: 1.25rem;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -95,7 +95,7 @@ const setProxy = async () => {
|
||||||
...i.appMetadata,
|
...i.appMetadata,
|
||||||
offlineUri: i.offlineUri,
|
offlineUri: i.offlineUri,
|
||||||
thumbnail: parseThumb(i.appMetadata.url, proxy.value),
|
thumbnail: parseThumb(i.appMetadata.url, proxy.value),
|
||||||
duration: i.duration
|
duration: i.duration,
|
||||||
})),
|
})),
|
||||||
});
|
});
|
||||||
nav.state.page = 'home';
|
nav.state.page = 'home';
|
||||||
|
|
|
@ -60,17 +60,17 @@ async function Stream() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
window.offline = new shaka.offline.Storage(audioPlayer);
|
window.offline = new shaka.offline.Storage(audioPlayer);
|
||||||
window.offline.configure({
|
window.offline.configure({
|
||||||
offline: {
|
offline: {
|
||||||
progressCallback: (data, prog) => console.log(data, prog),
|
progressCallback: (data, prog) => console.log(data, prog),
|
||||||
trackSelectionCallback: tracks => [
|
trackSelectionCallback: tracks => [
|
||||||
tracks
|
tracks
|
||||||
.sort((a, b) => a.bandwidth - b.bandwidth)
|
.sort((a, b) => a.bandwidth - b.bandwidth)
|
||||||
.find(i => i.type == 'variant'),
|
.find(i => i.type == 'variant'),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
audioPlayer.configure({
|
audioPlayer.configure({
|
||||||
preferredAudioCodecs: codecs ? codecs.split(':') : ['opus', 'mp4a'],
|
preferredAudioCodecs: codecs ? codecs.split(':') : ['opus', 'mp4a'],
|
||||||
|
|
|
@ -36,7 +36,7 @@ const shuffleAdd = () => {
|
||||||
thumbnails: [{ url: i.thumbnail }],
|
thumbnails: [{ url: i.thumbnail }],
|
||||||
thumbnail: i.thumbnail,
|
thumbnail: i.thumbnail,
|
||||||
offlineUri: i.offlineUri,
|
offlineUri: i.offlineUri,
|
||||||
duration: i.duration
|
duration: i.duration,
|
||||||
})),
|
})),
|
||||||
copy = [];
|
copy = [];
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ const shuffleAdd = () => {
|
||||||
thumbnails: [{ url: i.thumbnail }],
|
thumbnails: [{ url: i.thumbnail }],
|
||||||
thumbnail: i.thumbnail,
|
thumbnail: i.thumbnail,
|
||||||
offlineUri: i.offlineUri,
|
offlineUri: i.offlineUri,
|
||||||
duration: i.duration
|
duration: i.duration,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
song.url = song.url || '/watch?v=' + song.id;
|
song.url = song.url || '/watch?v=' + song.id;
|
||||||
|
@ -254,7 +254,7 @@ onDeactivated(() => {
|
||||||
thumbnails: [{ url: item.thumbnail }],
|
thumbnails: [{ url: item.thumbnail }],
|
||||||
thumbnail: item.thumbnail,
|
thumbnail: item.thumbnail,
|
||||||
offlineUri: item.offlineUri,
|
offlineUri: item.offlineUri,
|
||||||
duration: item.duration
|
duration: item.duration,
|
||||||
})),
|
})),
|
||||||
)
|
)
|
||||||
" />
|
" />
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, reactive } from 'vue';
|
import { ref, reactive } from 'vue';
|
||||||
|
|
||||||
import Modal from './Modal.vue';
|
|
||||||
|
|
||||||
import { useStore } from '@/scripts/util.js';
|
import { useStore } from '@/scripts/util.js';
|
||||||
import { useListPlaylists, useUpdatePlaylist } from '@/scripts/db.js';
|
|
||||||
import {
|
import {
|
||||||
getAuthPlaylists,
|
getAuthPlaylists,
|
||||||
useAuthCreatePlaylist,
|
useAuthCreatePlaylist,
|
||||||
|
@ -21,13 +18,8 @@ const { t } = useI18n(),
|
||||||
|
|
||||||
const showme = reactive({
|
const showme = reactive({
|
||||||
menu: false,
|
menu: false,
|
||||||
pl: false,
|
|
||||||
vol: false,
|
vol: false,
|
||||||
}),
|
}),
|
||||||
pl = ref(''),
|
|
||||||
list = ref([]),
|
|
||||||
remote = ref([]),
|
|
||||||
plRemote = ref(false),
|
|
||||||
liked = ref(undefined),
|
liked = ref(undefined),
|
||||||
liking = ref(false);
|
liking = ref(false);
|
||||||
|
|
||||||
|
@ -45,36 +37,6 @@ function getFormattedTime(sec) {
|
||||||
).padStart(2, '0')}`;
|
).padStart(2, '0')}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function List() {
|
|
||||||
showme.pl = true;
|
|
||||||
useListPlaylists(res => {
|
|
||||||
list.value = res;
|
|
||||||
showme.menu = false;
|
|
||||||
});
|
|
||||||
getAuthPlaylists().then(res => {
|
|
||||||
remote.value = res;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function Save() {
|
|
||||||
if (pl.value) {
|
|
||||||
if (plRemote.value == true && store.auth) {
|
|
||||||
useAuthAddToPlaylist(pl.value, data.state.url);
|
|
||||||
} else if (plRemote.value == false) {
|
|
||||||
useUpdatePlaylist(
|
|
||||||
pl.value,
|
|
||||||
{
|
|
||||||
url: data.state.url,
|
|
||||||
title: data.state.title,
|
|
||||||
},
|
|
||||||
e => {
|
|
||||||
if (e === true) console.log('Added Song');
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function Offline() {
|
async function Offline() {
|
||||||
if (window.offline && data.state.url) {
|
if (window.offline && data.state.url) {
|
||||||
window.offline.store(window.audioPlayer.getAssetUri(), {
|
window.offline.store(window.audioPlayer.getAssetUri(), {
|
||||||
|
@ -107,61 +69,6 @@ async function Like() {
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<Teleport to="body">
|
|
||||||
<Transition name="fade">
|
|
||||||
<Modal
|
|
||||||
n="2"
|
|
||||||
:display="showme.pl"
|
|
||||||
:title="t('playlist.select')"
|
|
||||||
@show="
|
|
||||||
e => {
|
|
||||||
showme.pl = e;
|
|
||||||
}
|
|
||||||
">
|
|
||||||
<template #content>
|
|
||||||
<div
|
|
||||||
v-for="i in list"
|
|
||||||
:key="i.name"
|
|
||||||
class="flex item"
|
|
||||||
@click="
|
|
||||||
pl = i.name;
|
|
||||||
plRemote = false;
|
|
||||||
"
|
|
||||||
:data-active="pl == i.name && plRemote == false">
|
|
||||||
<span>{{ i.name }}</span
|
|
||||||
><span class="ml-auto">{{ i.urls.length || '' }}</span>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
v-for="i in remote"
|
|
||||||
:key="i.id"
|
|
||||||
class="flex item remote"
|
|
||||||
@click="
|
|
||||||
pl = i.id;
|
|
||||||
plRemote = true;
|
|
||||||
"
|
|
||||||
:data-active="pl == i.id && plRemote == true">
|
|
||||||
<span>{{ i.name.replace('Playlist -', '') }}</span
|
|
||||||
><span class="ml-auto">{{ i.videos }}</span>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<template #buttons>
|
|
||||||
<button aria-label="Cancel" @click="showme.pl = false">
|
|
||||||
{{ t('action.cancel') }}
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
aria-label="Add Song"
|
|
||||||
@click="
|
|
||||||
Save();
|
|
||||||
showme.pl = false;
|
|
||||||
">
|
|
||||||
{{ t('action.add') }}
|
|
||||||
</button>
|
|
||||||
</template>
|
|
||||||
</Modal>
|
|
||||||
</Transition>
|
|
||||||
</Teleport>
|
|
||||||
|
|
||||||
<div id="statusbar" class="flex">
|
<div id="statusbar" class="flex">
|
||||||
<div class="flex statusbar-progress-container">
|
<div class="flex statusbar-progress-container">
|
||||||
<span>{{ getFormattedTime(player.state.realTime) }}</span>
|
<span>{{ getFormattedTime(player.state.realTime) }}</span>
|
||||||
|
@ -301,7 +208,10 @@ async function Like() {
|
||||||
title="Add Current Song to a Playlist"
|
title="Add Current Song to a Playlist"
|
||||||
aria-label="Add Current Song to a Playlist"
|
aria-label="Add Current Song to a Playlist"
|
||||||
class="bi bi-collection clickable"
|
class="bi bi-collection clickable"
|
||||||
@click="List"></button>
|
@click="
|
||||||
|
player.toggle('add');
|
||||||
|
showme.menu = false;
|
||||||
|
"></button>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
id="btn-lyrics"
|
id="btn-lyrics"
|
||||||
|
@ -479,31 +389,6 @@ input[type='range']::-moz-range-track {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Playlist addition */
|
/* Playlist addition */
|
||||||
.ml-auto {
|
|
||||||
margin-left: auto;
|
|
||||||
width: min-content;
|
|
||||||
}
|
|
||||||
.item {
|
|
||||||
background: var(--color-background);
|
|
||||||
border-radius: 0.5rem;
|
|
||||||
margin: 0.5rem 0;
|
|
||||||
transition: background-color 0.1s ease;
|
|
||||||
}
|
|
||||||
.item:hover {
|
|
||||||
background: var(--color-background-mute);
|
|
||||||
}
|
|
||||||
.item:active {
|
|
||||||
background: var(--color-border);
|
|
||||||
}
|
|
||||||
.item[data-active='true'] {
|
|
||||||
color: var(--color-background);
|
|
||||||
background: linear-gradient(135deg, cornflowerblue, #88c0d0);
|
|
||||||
}
|
|
||||||
.remote.item::before {
|
|
||||||
content: '\F4E1';
|
|
||||||
font-family: bootstrap-icons;
|
|
||||||
font-size: 1.25rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 500px) {
|
@media (max-width: 500px) {
|
||||||
.statusbar-progress-container {
|
.statusbar-progress-container {
|
||||||
|
|
|
@ -42,7 +42,7 @@ export const useData = defineStore('data', () => {
|
||||||
async function play(song) {
|
async function play(song) {
|
||||||
if (song.offlineUri) {
|
if (song.offlineUri) {
|
||||||
state.art = song.thumbnail;
|
state.art = song.thumbnail;
|
||||||
player.state.duration = song.duration
|
player.state.duration = song.duration;
|
||||||
for (let i of ['title', 'artist', 'artistUrl', 'url']) state[i] = song[i];
|
for (let i of ['title', 'artist', 'artistUrl', 'url']) state[i] = song[i];
|
||||||
window.audioPlayer.load(song.offlineUri);
|
window.audioPlayer.load(song.offlineUri);
|
||||||
} else await getSong(song.url);
|
} else await getSong(song.url);
|
||||||
|
@ -150,6 +150,7 @@ export const usePlayer = defineStore('player', () => {
|
||||||
playlist: false,
|
playlist: false,
|
||||||
lyrics: false,
|
lyrics: false,
|
||||||
info: false,
|
info: false,
|
||||||
|
add: false,
|
||||||
vol: store.vol ? store.vol / 100 : 1,
|
vol: store.vol ? store.vol / 100 : 1,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue