mirror of
https://codeberg.org/Hyperpipe/Hyperpipe
synced 2025-06-27 20:58:01 +02:00
Bug Fixes:
- Fixed Navbar links (closes #8) - Fixed Lyrics not updating
This commit is contained in:
parent
4ac524dcf2
commit
e0bc3c61a2
6 changed files with 93 additions and 46 deletions
16
README.md
16
README.md
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
A Privacy Respecting Frontend for YouTube Music inspired and built with the help [Piped][piped] and YouTube's innertube API.
|
A Privacy Respecting Frontend for YouTube Music inspired and built with the help [Piped][piped] and YouTube's InnerTube API.
|
||||||
|
|
||||||

|

|
||||||

|

|
||||||
|
@ -49,10 +49,18 @@ npm run build
|
||||||
|
|
||||||
Please see [hyperpipe.codeberg.page](https://hyperpipe.codeberg.page)
|
Please see [hyperpipe.codeberg.page](https://hyperpipe.codeberg.page)
|
||||||
|
|
||||||
|
## Extensions
|
||||||
|
|
||||||
|
- [Libredirect](https://codeberg.org/LibRedirect/libredirect) -> For Redirecting YouTube Music links to Hyperpipe.
|
||||||
|
|
||||||
## LICENSE
|
## LICENSE
|
||||||
|
|
||||||
### AGPL-3.0-or-later
|
### AGPL-3.0-or-later
|
||||||
|
|
||||||
|
Hyperpipe
|
||||||
|
|
||||||
|
Copyright (C) 2022 Shiny Nematoda
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU Affero General Public License as
|
it under the terms of the GNU Affero General Public License as
|
||||||
published by the Free Software Foundation, either version 3 of the
|
published by the Free Software Foundation, either version 3 of the
|
||||||
|
@ -63,7 +71,9 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU Affero General Public License for more details.
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
Please refer to [LICENSE][license].
|
You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Please refer to [LICENSE][license] for more details.
|
||||||
|
|
||||||
## Help
|
## Help
|
||||||
|
|
||||||
|
@ -93,6 +103,8 @@ You can reach out to me personally on:
|
||||||
|
|
||||||
- [Cider](https://github.com/ciderapp/Cider) -> Cross-platform Apple Music experience based on Electron and Vue.js
|
- [Cider](https://github.com/ciderapp/Cider) -> Cross-platform Apple Music experience based on Electron and Vue.js
|
||||||
|
|
||||||
|
- [Ossia](https://github.com/shie1/ossia) -> Ossia Music Player is a free, open source alternative to YouTube Music.
|
||||||
|
|
||||||
[hypipe]: https://hyperpipe.surge.sh
|
[hypipe]: https://hyperpipe.surge.sh
|
||||||
[piped]: https://piped.kavin.rocks
|
[piped]: https://piped.kavin.rocks
|
||||||
[license]: https://codeberg.org/Hyperpipe/Hyperpipe/src/branch/main/LICENSE.md
|
[license]: https://codeberg.org/Hyperpipe/Hyperpipe/src/branch/main/LICENSE.md
|
||||||
|
|
23
src/App.vue
23
src/App.vue
|
@ -68,9 +68,17 @@ function parseUrl() {
|
||||||
break;
|
break;
|
||||||
case 'explore':
|
case 'explore':
|
||||||
genreid.value = loc[2];
|
genreid.value = loc[2];
|
||||||
nav.state.page = 'genres';
|
nav.state.page = 'explore';
|
||||||
|
break;
|
||||||
|
case 'library':
|
||||||
|
nav.state.page = 'library';
|
||||||
|
break;
|
||||||
|
case 'prefs':
|
||||||
|
nav.state.page = 'prefs';
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
console.log(loc);
|
console.log(loc);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -336,7 +344,7 @@ onMounted(() => {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<NavBar />
|
<NavBar @explore="getExplore" />
|
||||||
|
|
||||||
<template v-if="artist.state.title && nav.state.page == 'home'">
|
<template v-if="artist.state.title && nav.state.page == 'home'">
|
||||||
<Artist @playall="getAlbum" />
|
<Artist @playall="getAlbum" />
|
||||||
|
@ -365,17 +373,12 @@ onMounted(() => {
|
||||||
|
|
||||||
<KeepAlive>
|
<KeepAlive>
|
||||||
<Genres
|
<Genres
|
||||||
v-if="nav.state.page == 'genres'"
|
v-if="nav.state.page == 'explore'"
|
||||||
:id="genreid"
|
:id="genreid"
|
||||||
@get-album="
|
@get-album="getAlbum" />
|
||||||
e => {
|
|
||||||
getAlbum(e);
|
|
||||||
nav.state.page = 'home';
|
|
||||||
}
|
|
||||||
" />
|
|
||||||
</KeepAlive>
|
</KeepAlive>
|
||||||
|
|
||||||
<NewPlaylist v-if="nav.state.page == 'playlist'" @play-urls="playList" />
|
<NewPlaylist v-if="nav.state.page == 'library'" @play-urls="playList" />
|
||||||
|
|
||||||
<Prefs v-if="nav.state.page == 'prefs'" />
|
<Prefs v-if="nav.state.page == 'prefs'" />
|
||||||
</main>
|
</main>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { reactive, ref, onMounted } from 'vue';
|
import { reactive, ref, onMounted, onUnmounted } from 'vue';
|
||||||
|
|
||||||
import { getJson } from '../scripts/fetch.js';
|
import { getJsonHyp } from '../scripts/fetch.js';
|
||||||
import { useRandColor } from '../scripts/colors.js';
|
import { useRandColor } from '../scripts/colors.js';
|
||||||
import { useRoute } from '../scripts/util.js';
|
import { useRoute } from '../scripts/util.js';
|
||||||
|
|
||||||
|
@ -19,25 +19,28 @@ const data = reactive({
|
||||||
btns = reactive({
|
btns = reactive({
|
||||||
moods: [],
|
moods: [],
|
||||||
genres: [],
|
genres: [],
|
||||||
});
|
}),
|
||||||
|
todo = ['title', 'community', 'spotlight', 'featured'];
|
||||||
|
|
||||||
function get(id) {
|
function get(id) {
|
||||||
if (props.id || id) {
|
if (props.id || typeof id == 'string') {
|
||||||
getJson(
|
getJsonHyp('/genres/' + (props.id || id)).then(res => {
|
||||||
'https://hyperpipeapi.onrender.com/genres/' + (props.id || id),
|
|
||||||
).then(res => {
|
|
||||||
console.log(res);
|
console.log(res);
|
||||||
|
|
||||||
for (let i of ['title', 'community', 'spotlight', 'featured']) {
|
for (let i of todo) {
|
||||||
data[i] = res[i];
|
data[i] = res[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
useRoute('/explore/' + (props.id || id));
|
useRoute('/explore/' + (props.id || id));
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
getJson('https://hyperpipeapi.onrender.com/genres').then(res => {
|
getJsonHyp('/genres').then(res => {
|
||||||
console.log(res);
|
console.log(res);
|
||||||
|
|
||||||
|
for (let i of todo) {
|
||||||
|
data[i] = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
for (let i of ['moods', 'genres']) {
|
for (let i of ['moods', 'genres']) {
|
||||||
btns[i] = res[i];
|
btns[i] = res[i];
|
||||||
}
|
}
|
||||||
|
@ -52,6 +55,8 @@ onMounted(get);
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<template v-if="data.title">
|
<template v-if="data.title">
|
||||||
|
<i class="bi bi-arrow-left back" @click="get"> Back</i>
|
||||||
|
|
||||||
<h2 class="head">{{ data.title }}</h2>
|
<h2 class="head">{{ data.title }}</h2>
|
||||||
|
|
||||||
<template v-for="type in ['featured', 'spotlight', 'community']">
|
<template v-for="type in ['featured', 'spotlight', 'community']">
|
||||||
|
@ -62,7 +67,10 @@ onMounted(get);
|
||||||
:name="i.title"
|
:name="i.title"
|
||||||
:author="i.subtitle"
|
:author="i.subtitle"
|
||||||
:art="'url(' + i.thumbnails[0].url + ')'"
|
:art="'url(' + i.thumbnails[0].url + ')'"
|
||||||
@open-album="$emit('get-album', '/playlist?list=' + i.id)" />
|
@open-album="
|
||||||
|
$emit('get-album', '/playlist?list=' + i.id);
|
||||||
|
nav.state.page = 'home';
|
||||||
|
" />
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -96,6 +104,9 @@ onMounted(get);
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
.back {
|
||||||
|
width: fit-content;
|
||||||
|
}
|
||||||
.btn-grid {
|
.btn-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: calc(100% / 3) calc(100% / 3) calc(100% / 3);
|
grid-template-columns: calc(100% / 3) calc(100% / 3) calc(100% / 3);
|
||||||
|
|
|
@ -14,31 +14,29 @@ const data = useData(),
|
||||||
function get() {
|
function get() {
|
||||||
status.value = false;
|
status.value = false;
|
||||||
|
|
||||||
if (data.state.lyrics && data.state.urls === data.state.urls[0]?.url) {
|
const set = id => {
|
||||||
getJsonHyp('/browse/' + data.state.lyrics).then(res => {
|
getJsonHyp('/browse/' + id).then(res => {
|
||||||
text.value = res.text;
|
text.value = res.text;
|
||||||
source.value = res.source;
|
source.value = res.source;
|
||||||
status.value = true;
|
status.value = true;
|
||||||
});
|
});
|
||||||
} else if (data.state.urls[0]?.url) {
|
};
|
||||||
getJsonHyp(
|
|
||||||
'/next/' + data.state.urls[0]?.url.replace('/watch?v=', ''),
|
if (data.state.lyrics && data.state.urls === data.state.url) {
|
||||||
).then(next => {
|
set(data.state.lyrics);
|
||||||
if (next.lyricsId) {
|
} else if (data.state.url) {
|
||||||
getJsonHyp('/browse/' + next.lyricsId).then(res => {
|
getJsonHyp('/next/' + data.state.url.replace('/watch?v=', '')).then(
|
||||||
text.value = res.text;
|
next => {
|
||||||
source.value = res.source;
|
if (next.lyricsId) set(next.lyricsId);
|
||||||
status.value = true;
|
},
|
||||||
});
|
);
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get();
|
get();
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => data.state.urls[0]?.url,
|
() => data.state.url,
|
||||||
() => {
|
() => {
|
||||||
get();
|
get();
|
||||||
},
|
},
|
||||||
|
|
|
@ -4,7 +4,26 @@ import SearchBar from '../components/SearchBar.vue';
|
||||||
|
|
||||||
import { useNav } from '@/stores/misc.js';
|
import { useNav } from '@/stores/misc.js';
|
||||||
|
|
||||||
|
import { useRoute } from '@/scripts/util.js';
|
||||||
|
|
||||||
|
const emit = defineEmits(['explore']);
|
||||||
|
|
||||||
const nav = useNav();
|
const nav = useNav();
|
||||||
|
|
||||||
|
function home() {
|
||||||
|
useRoute('/');
|
||||||
|
nav.state.page = 'home';
|
||||||
|
emit('explore');
|
||||||
|
}
|
||||||
|
|
||||||
|
function set(page) {
|
||||||
|
nav.state.page = page;
|
||||||
|
if (page == 'home') {
|
||||||
|
useRoute('/');
|
||||||
|
} else {
|
||||||
|
useRoute(`/${page}/`);
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -15,19 +34,19 @@ const nav = useNav();
|
||||||
<span
|
<span
|
||||||
class="nav-ico bi bi-house"
|
class="nav-ico bi bi-house"
|
||||||
:data-active="nav.state.page == 'home'"
|
:data-active="nav.state.page == 'home'"
|
||||||
@click="nav.state.page = 'home'"></span>
|
@click="set('home')"></span>
|
||||||
<span
|
<span
|
||||||
class="nav-ico bi bi-compass"
|
class="nav-ico bi bi-compass"
|
||||||
:data-active="nav.state.page == 'genres'"
|
:data-active="nav.state.page == 'explore'"
|
||||||
@click="nav.state.page = 'genres'"></span>
|
@click="set('explore')"></span>
|
||||||
<span
|
<span
|
||||||
class="nav-ico bi bi-collection"
|
class="nav-ico bi bi-collection"
|
||||||
:data-active="nav.state.page == 'playlist'"
|
:data-active="nav.state.page == 'library'"
|
||||||
@click="nav.state.page = 'playlist'"></span>
|
@click="set('library')"></span>
|
||||||
<span
|
<span
|
||||||
class="nav-ico bi bi-gear"
|
class="nav-ico bi bi-gear"
|
||||||
:data-active="nav.state.page == 'prefs'"
|
:data-active="nav.state.page == 'prefs'"
|
||||||
@click="nav.state.page = 'prefs'"></span>
|
@click="set('prefs')"></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="wrap">
|
<div class="wrap">
|
||||||
|
|
|
@ -30,11 +30,15 @@ const playAlbum = () => {
|
||||||
},
|
},
|
||||||
saveAlbum = () => {
|
saveAlbum = () => {
|
||||||
const urls = results.items?.songs?.items?.map(item => {
|
const urls = results.items?.songs?.items?.map(item => {
|
||||||
return { url: item.url, title: item.title };
|
return { url: item.url, title: item.title };
|
||||||
}),
|
});
|
||||||
title = results.items?.songs?.title;
|
|
||||||
|
let title = results.items?.songs?.title;
|
||||||
|
|
||||||
if (title) {
|
if (title) {
|
||||||
|
if (title == 'Songs')
|
||||||
|
title += ' - ' + results.items.songs.items[0].uploaderName;
|
||||||
|
|
||||||
useCreatePlaylist(title, urls, () => {
|
useCreatePlaylist(title, urls, () => {
|
||||||
alert('Saved!');
|
alert('Saved!');
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue