mirror of
https://codeberg.org/Hyperpipe/Hyperpipe
synced 2025-06-27 20:58:01 +02:00
Changes:
- Added Preferences tab - Piped Api Selection - Bug Fixes
This commit is contained in:
parent
19fc65e6c0
commit
0c1bb172b1
16 changed files with 384 additions and 216 deletions
|
@ -1,15 +1,16 @@
|
|||
<script setup>
|
||||
defineProps({
|
||||
import { useRand } from '../scripts/colors.js';
|
||||
|
||||
const rand = useRand();
|
||||
|
||||
const props = defineProps({
|
||||
name: String,
|
||||
author: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
grad: String,
|
||||
art: {
|
||||
type: String,
|
||||
default: 'linear-gradient(45deg, #88c0d0, #5e81ac)',
|
||||
},
|
||||
art: String,
|
||||
});
|
||||
|
||||
defineEmits(['open-album']);
|
||||
|
@ -38,8 +39,8 @@ defineEmits(['open-album']);
|
|||
background-color: var(--color-background);
|
||||
}
|
||||
.card-bg {
|
||||
--art: v-bind('grad || art');
|
||||
background-color: v-bind('grad');
|
||||
--grad: v-bind('grad || rand');
|
||||
--art: v-bind('art || grad || rand');
|
||||
height: 13rem;
|
||||
width: 13rem;
|
||||
}
|
||||
|
|
|
@ -7,12 +7,13 @@ const props = defineProps(['display', 'title', 'n']),
|
|||
|
||||
watch(
|
||||
() => props.display,
|
||||
(n) => {
|
||||
n => {
|
||||
console.log(n, props.display);
|
||||
show.value = n;
|
||||
},
|
||||
);
|
||||
watch(show, (n) => {
|
||||
|
||||
watch(show, n => {
|
||||
emit('show', show.value);
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -3,23 +3,24 @@ import { reactive } from 'vue';
|
|||
import SearchBar from '../components/SearchBar.vue';
|
||||
|
||||
const emit = defineEmits(['update-page', 'update-search']),
|
||||
page = reactive({
|
||||
home: true,
|
||||
playlist: false,
|
||||
prefs: false,
|
||||
});
|
||||
|
||||
page = reactive({
|
||||
home: true,
|
||||
playlist: false,
|
||||
}),
|
||||
const Toggle = p => {
|
||||
for (let pg in page) {
|
||||
page[pg] = false;
|
||||
}
|
||||
page[p] = true;
|
||||
emit('update-page', p);
|
||||
|
||||
Toggle = (p) => {
|
||||
for (let pg in page) {
|
||||
page[pg] = false;
|
||||
}
|
||||
page[p] = true;
|
||||
emit('update-page', p);
|
||||
},
|
||||
|
||||
home = () => {
|
||||
history.pushState('', {}, '/');
|
||||
};
|
||||
console.log(page[p], p);
|
||||
},
|
||||
home = () => {
|
||||
history.pushState('', {}, '/');
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -33,12 +34,15 @@ home = () => {
|
|||
<span
|
||||
:class="'nav-ico bi bi-collection ' + page.playlist"
|
||||
@click="Toggle('playlist')"></span>
|
||||
<span
|
||||
:class="'nav-ico bi bi-gear ' + page.prefs"
|
||||
@click="Toggle('prefs')"></span>
|
||||
</div>
|
||||
|
||||
<div class="wrap">
|
||||
<SearchBar
|
||||
@update-search="
|
||||
(e) => {
|
||||
e => {
|
||||
$emit('update-search', e);
|
||||
}
|
||||
" />
|
||||
|
|
|
@ -12,34 +12,30 @@ import {
|
|||
} from '../scripts/db.js';
|
||||
|
||||
const emit = defineEmits(['play-urls']),
|
||||
|
||||
list = ref([]),
|
||||
list = ref([]),
|
||||
show = ref(false),
|
||||
text = ref(''),
|
||||
Play = key => {
|
||||
console.log(key);
|
||||
|
||||
Play = (key) => {
|
||||
console.log(key);
|
||||
|
||||
useGetPlaylist(key, (res) => {
|
||||
console.log(res);
|
||||
emit('play-urls', res.urls);
|
||||
});
|
||||
},
|
||||
|
||||
List = () => {
|
||||
useListPlaylists((res) => {
|
||||
list.value = res;
|
||||
});
|
||||
},
|
||||
|
||||
Create = () => {
|
||||
if (text.value) {
|
||||
useCreatePlaylist(text.value, [], () => {
|
||||
List();
|
||||
show.value = false;
|
||||
useGetPlaylist(key, res => {
|
||||
console.log(res);
|
||||
emit('play-urls', res.urls);
|
||||
});
|
||||
}
|
||||
};
|
||||
},
|
||||
List = () => {
|
||||
useListPlaylists(res => {
|
||||
list.value = res;
|
||||
});
|
||||
},
|
||||
Create = () => {
|
||||
if (text.value) {
|
||||
useCreatePlaylist(text.value, [], () => {
|
||||
List();
|
||||
show.value = false;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
List();
|
||||
|
@ -53,7 +49,7 @@ onMounted(() => {
|
|||
:display="show"
|
||||
title="Create a new Playlist..."
|
||||
@show="
|
||||
(e) => {
|
||||
e => {
|
||||
show = e;
|
||||
}
|
||||
">
|
||||
|
|
|
@ -11,15 +11,19 @@ defineProps({
|
|||
artistUrl: {
|
||||
type: String,
|
||||
default: '',
|
||||
}
|
||||
},
|
||||
});
|
||||
defineEmits(['get-artist'])
|
||||
defineEmits(['get-artist']);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="title && artist" class="wrap">
|
||||
<h1>{{ title }}</h1>
|
||||
<h3><a :href="artistUrl" @click.prevent="$emit('get-artist', artistUrl)">{{ artist }}</a></h3>
|
||||
<h3>
|
||||
<a :href="artistUrl" @click.prevent="$emit('get-artist', artistUrl)">{{
|
||||
artist
|
||||
}}</a>
|
||||
</h3>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
129
src/components/Prefs.vue
Normal file
129
src/components/Prefs.vue
Normal file
|
@ -0,0 +1,129 @@
|
|||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
|
||||
import { getJson } from '../scripts/fetch.js';
|
||||
|
||||
const instances = ref([]);
|
||||
|
||||
getJson('https://piped-instances.kavin.rocks').then(i => {
|
||||
instances.value = i;
|
||||
|
||||
console.log(i);
|
||||
});
|
||||
|
||||
function bi(val) {
|
||||
return 'bi ' + (val ? 'bi-check2' : 'bi-x-lg');
|
||||
}
|
||||
|
||||
function get(key) {
|
||||
return localStorage.getItem(key);
|
||||
}
|
||||
|
||||
function set(key, value) {
|
||||
console.log(key, value);
|
||||
localStorage.setItem(key, value);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<h2>Piped Instance</h2>
|
||||
<select
|
||||
v-if="instances"
|
||||
:value="get('pipedapi') || 'pipedapi.kavin.rocks'"
|
||||
@change="set('pipedapi', $event.target.value)">
|
||||
<option
|
||||
v-for="i in instances"
|
||||
:key="i.name"
|
||||
:value="i.api_url.replace('https://', '').replace('http://', '')">
|
||||
{{ i.name }}
|
||||
</option>
|
||||
</select>
|
||||
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Locations</th>
|
||||
<th>CDN</th>
|
||||
<th>Up to Date</th>
|
||||
<th>Version</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody v-for="i in instances">
|
||||
<tr>
|
||||
<td>
|
||||
{{ i.name.replaceAll('Official', 'Default') }}
|
||||
</td>
|
||||
<td>
|
||||
{{ i.locations.replaceAll(',', '') }}
|
||||
</td>
|
||||
<td :class="bi(i.cdn)" :data-active="i.cdn"></td>
|
||||
<td :class="bi(i.up_to_date)" :data-active="i.up_to_date"></td>
|
||||
<td>
|
||||
{{ i.version }}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<a
|
||||
class="bi bi-code-slash"
|
||||
target="_blank"
|
||||
rel="noreferrer noopener"
|
||||
href="https://codeberg.org/Hyperpipe/Hyperpipe"></a>
|
||||
</footer>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
h2,
|
||||
footer {
|
||||
text-align: center;
|
||||
}
|
||||
select {
|
||||
font-size: 1rem;
|
||||
margin: 1rem auto;
|
||||
padding: 0.5rem 0.75rem;
|
||||
outline: none;
|
||||
border: none;
|
||||
max-width: 20rem;
|
||||
border-radius: 0.125rem;
|
||||
background-color: var(--color-background-mute);
|
||||
}
|
||||
.table-wrap {
|
||||
overflow-x: auto;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
.table-wrap,
|
||||
table {
|
||||
width: 100%;
|
||||
}
|
||||
th,
|
||||
td {
|
||||
margin: 0.25rem 0.5rem;
|
||||
padding: 0.5rem 0.75rem;
|
||||
border-radius: 0.125rem;
|
||||
background-color: var(--color-background-mute);
|
||||
}
|
||||
th {
|
||||
font-weight: bolder;
|
||||
}
|
||||
td {
|
||||
text-align: center;
|
||||
}
|
||||
td.bi {
|
||||
color: indianred;
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
td.bi[data-active='true'] {
|
||||
color: var(--color-foreground);
|
||||
}
|
||||
footer {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
footer .bi:before {
|
||||
font-size: 1.75rem;
|
||||
}
|
||||
</style>
|
|
@ -8,74 +8,64 @@ import { getJsonPiped, getPipedQuery } from '../scripts/fetch.js';
|
|||
import { useLazyLoad } from '../scripts/util.js';
|
||||
|
||||
const props = defineProps(['search', 'songItems', 'items']),
|
||||
|
||||
emit = defineEmits(['get-album', 'get-artist', 'play-urls', 'add-song']),
|
||||
|
||||
filters = ['music_songs', 'music_albums', 'music_artists'],
|
||||
|
||||
filter = ref('music_songs'),
|
||||
|
||||
isSearch = ref(/search/.test(location.pathname)),
|
||||
|
||||
data = reactive({
|
||||
notes: null,
|
||||
albums: null,
|
||||
albumTitle: null,
|
||||
songs: null,
|
||||
artists: null,
|
||||
recommendedArtists: null,
|
||||
}),
|
||||
|
||||
Reset = () => {
|
||||
isSearch.value = /search/.test(location.pathname);
|
||||
|
||||
for (let i in data) {
|
||||
data[i] = null;
|
||||
}
|
||||
},
|
||||
|
||||
playAlbum = () => {
|
||||
const urls = data.songs.items.map((item) => {
|
||||
return { url: item.url, title: item.title };
|
||||
emit = defineEmits(['get-album', 'get-artist', 'play-urls', 'add-song']),
|
||||
filters = ['music_songs', 'music_albums', 'music_artists'],
|
||||
filter = ref('music_songs'),
|
||||
isSearch = ref(/search/.test(location.pathname)),
|
||||
data = reactive({
|
||||
notes: null,
|
||||
albums: null,
|
||||
albumTitle: null,
|
||||
songs: null,
|
||||
artists: null,
|
||||
recommendedArtists: null,
|
||||
});
|
||||
|
||||
emit('play-urls', urls);
|
||||
},
|
||||
|
||||
getSearch = (q) => {
|
||||
if (q) {
|
||||
const pq = q.split(' ').join('+');
|
||||
|
||||
history.pushState({}, '', `/search/${pq + getPipedQuery()}`);
|
||||
|
||||
document.title = 'Search Results for ' + q;
|
||||
const Reset = () => {
|
||||
isSearch.value = /search/.test(location.pathname);
|
||||
|
||||
getResults(pq);
|
||||
useLazyLoad();
|
||||
} else {
|
||||
Reset();
|
||||
for (let i in data) {
|
||||
data[i] = null;
|
||||
}
|
||||
},
|
||||
playAlbum = () => {
|
||||
const urls = data.songs.items.map(item => {
|
||||
return { url: item.url, title: item.title };
|
||||
});
|
||||
|
||||
history.pushState({}, '', '/');
|
||||
document.title = 'Hyperpipe';
|
||||
emit('play-urls', urls);
|
||||
},
|
||||
getSearch = q => {
|
||||
if (q) {
|
||||
const pq = q.split(' ').join('+');
|
||||
|
||||
console.log('No Search');
|
||||
}
|
||||
},
|
||||
history.pushState({}, '', `/search/${pq + getPipedQuery()}`);
|
||||
|
||||
getResults = async (q) => {
|
||||
document.title = 'Search Results for ' + q;
|
||||
isSearch.value = /search/.test(location.pathname);
|
||||
|
||||
const f = filter.value || 'music_songs',
|
||||
|
||||
json = await getJsonPiped(`/search?q=${q}&filter=${f}`);
|
||||
getResults(pq);
|
||||
useLazyLoad();
|
||||
} else {
|
||||
Reset();
|
||||
|
||||
data[f.split('_')[1]] = json;
|
||||
console.log(json, data);
|
||||
};
|
||||
history.pushState({}, '', '/');
|
||||
document.title = 'Hyperpipe';
|
||||
|
||||
console.log('No Search');
|
||||
}
|
||||
},
|
||||
getResults = async q => {
|
||||
const f = filter.value || 'music_songs',
|
||||
json = await getJsonPiped(`/search?q=${q}&filter=${f}`);
|
||||
|
||||
data[f.split('_')[1]] = json;
|
||||
console.log(json, data);
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.search,
|
||||
(n) => {
|
||||
n => {
|
||||
if (n) {
|
||||
n = n.replace(location.search || '', '');
|
||||
|
||||
|
@ -87,7 +77,7 @@ watch(
|
|||
|
||||
watch(
|
||||
() => props.songItems,
|
||||
(i) => {
|
||||
i => {
|
||||
console.log(i);
|
||||
|
||||
Reset();
|
||||
|
@ -100,7 +90,7 @@ watch(
|
|||
|
||||
watch(
|
||||
() => props.items,
|
||||
(itms) => {
|
||||
itms => {
|
||||
Reset();
|
||||
|
||||
for (let i in itms) {
|
||||
|
@ -125,7 +115,15 @@ watch(
|
|||
</div>
|
||||
|
||||
<div v-if="isSearch" class="filters">
|
||||
<button v-for="f in filters" class="filter caps" @click="filter = f; Reset(); getSearch(search)" :data-active="f == filter">
|
||||
<button
|
||||
v-for="f in filters"
|
||||
class="filter caps"
|
||||
@click="
|
||||
filter = f;
|
||||
Reset();
|
||||
getSearch(search);
|
||||
"
|
||||
:data-active="f == filter">
|
||||
{{ f.split('_')[1] }}
|
||||
</button>
|
||||
</div>
|
||||
|
@ -149,7 +147,7 @@ watch(
|
|||
])
|
||||
"
|
||||
@get-artist="
|
||||
(e) => {
|
||||
e => {
|
||||
$emit('get-artist', e);
|
||||
}
|
||||
" />
|
||||
|
@ -193,16 +191,27 @@ watch(
|
|||
</div>
|
||||
|
||||
<div
|
||||
v-if="( data.recommendedArtists && data.recommendedArtists.items[0] ) || ( data.artists && data.artists.items[0] )"
|
||||
v-if="
|
||||
(data.recommendedArtists && data.recommendedArtists.items[0]) ||
|
||||
(data.artists && data.artists.items[0])
|
||||
"
|
||||
class="search-artists">
|
||||
<h2>{{ data.artists ? 'Artists' : 'Similar Artists' }}</h2>
|
||||
<div class="grid-3 circle">
|
||||
<template v-for="artist in ( data.artists ? data.artists.items : data.recommendedArtists.items)">
|
||||
<template
|
||||
v-for="artist in data.artists
|
||||
? data.artists.items
|
||||
: data.recommendedArtists.items">
|
||||
<AlbumItem
|
||||
:author="artist.subtitle"
|
||||
:name="artist.name || artist.title"
|
||||
:art="'url(' + (artist.thumbnail || artist.thumbnails[0].url) + ')'"
|
||||
@open-album="$emit('get-artist', (artist.id || artist.url.replace('/channel/', '') ) )" />
|
||||
@open-album="
|
||||
$emit(
|
||||
'get-artist',
|
||||
artist.id || artist.url.replace('/channel/', ''),
|
||||
)
|
||||
" />
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -227,22 +236,22 @@ watch(
|
|||
display: flex;
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
margin-bottom: 5rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
.filter {
|
||||
width: calc(80% / v-bind('filters.length'));
|
||||
max-width: 200px;
|
||||
margin: 1rem;
|
||||
padding: .5rem;
|
||||
padding: 0.5rem;
|
||||
font-size: 1.25rem;
|
||||
border-radius: .25rem;
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
.filter:hover {
|
||||
background: var(--color-background-mute);
|
||||
}
|
||||
.filter[data-active=true] {
|
||||
border-bottom: .125rem var(--color-text) solid;
|
||||
border-radius: .25rem .25rem 0 0;
|
||||
.filter[data-active='true'] {
|
||||
border-bottom: 0.125rem var(--color-text) solid;
|
||||
border-radius: 0.25rem 0.25rem 0 0;
|
||||
}
|
||||
.text-full {
|
||||
padding: 1rem;
|
||||
|
|
|
@ -1,48 +1,49 @@
|
|||
<script setup>
|
||||
import { ref, onMounted } from 'vue';
|
||||
|
||||
import { useRand } from '../scripts/colors.js';
|
||||
|
||||
const rand = useRand();
|
||||
|
||||
const props = defineProps({
|
||||
author: String,
|
||||
title: String,
|
||||
channel: String,
|
||||
play: String,
|
||||
art: String,
|
||||
}),
|
||||
author: String,
|
||||
title: String,
|
||||
channel: String,
|
||||
play: String,
|
||||
art: String,
|
||||
}),
|
||||
emit = defineEmits(['get-artist', 'open-song']),
|
||||
show = ref(false);
|
||||
|
||||
emit = defineEmits(['get-artist', 'open-song']),
|
||||
|
||||
show = ref(false),
|
||||
|
||||
openSong = (el) => {
|
||||
if (!el.classList.contains('ign')) {
|
||||
emit('open-song', props.play);
|
||||
}
|
||||
},
|
||||
|
||||
Share = async () => {
|
||||
if ('share' in navigator) {
|
||||
const data = {
|
||||
title: `Listen to ${props.title} by ${props.author} on Hyperpipe`,
|
||||
url: location.origin + props.play,
|
||||
};
|
||||
|
||||
try {
|
||||
await navigator.share(data);
|
||||
console.log('Done Sharing!');
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
const openSong = el => {
|
||||
if (!el.classList.contains('ign')) {
|
||||
emit('open-song', props.play);
|
||||
}
|
||||
} else {
|
||||
navigator.clipboard.writeText(location.host + props.play).then(
|
||||
() => {
|
||||
console.log('Copied to Clipboard');
|
||||
},
|
||||
(err) => {
|
||||
},
|
||||
Share = async () => {
|
||||
if ('share' in navigator) {
|
||||
const data = {
|
||||
title: `Listen to ${props.title} by ${props.author} on Hyperpipe`,
|
||||
url: location.origin + props.play,
|
||||
};
|
||||
|
||||
try {
|
||||
await navigator.share(data);
|
||||
console.log('Done Sharing!');
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
},
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
} else {
|
||||
navigator.clipboard.writeText(location.host + props.play).then(
|
||||
() => {
|
||||
console.log('Copied to Clipboard');
|
||||
},
|
||||
err => {
|
||||
console.log(err);
|
||||
},
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
console.log(props);
|
||||
|
@ -107,7 +108,8 @@ span.bi-three-dots-vertical {
|
|||
padding: 0.5rem;
|
||||
}
|
||||
.song-bg {
|
||||
--art: v-bind('art');
|
||||
--grad: v-bind('rand');
|
||||
--art: v-bind('art || rand');
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ const emit = defineEmits([
|
|||
|
||||
function Save() {
|
||||
showpl.value = true;
|
||||
useListPlaylists((res) => {
|
||||
useListPlaylists(res => {
|
||||
console.log(res);
|
||||
list.value = res;
|
||||
showmenu.value = false;
|
||||
|
@ -42,7 +42,7 @@ function Save() {
|
|||
:display="showpl"
|
||||
title="Select Playlist to Add"
|
||||
@show="
|
||||
(e) => {
|
||||
e => {
|
||||
showpl = e;
|
||||
}
|
||||
">
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue