mirror of
https://codeberg.org/Hyperpipe/Hyperpipe
synced 2025-06-27 20:58:01 +02:00
Changes:
- Added support for unauthenticated feeds #42 - Added support for Romanian - Closes #66 - Closes #81 - Closes #82 - Closes #84
This commit is contained in:
parent
599e024afa
commit
29eb3d0c35
9 changed files with 92 additions and 29 deletions
|
@ -117,6 +117,10 @@ 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
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*YouTube Music is a trademark of Google LLC.*
|
||||||
|
|
||||||
[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
|
||||||
|
|
|
@ -2,10 +2,24 @@
|
||||||
import { ref, onUpdated } from 'vue';
|
import { ref, onUpdated } from 'vue';
|
||||||
import Btn from './Btn.vue';
|
import Btn from './Btn.vue';
|
||||||
|
|
||||||
|
import { useStore } from '@/scripts/util.js';
|
||||||
import { useResults, useArtist } from '@/stores/results.js';
|
import { useResults, useArtist } from '@/stores/results.js';
|
||||||
|
|
||||||
const artist = useArtist(),
|
const artist = useArtist(),
|
||||||
results = useResults();
|
results = useResults(),
|
||||||
|
store = useStore();
|
||||||
|
|
||||||
|
const subs = JSON.parse(store.subs ? store.subs : '[]'),
|
||||||
|
hash = artist.state.hash,
|
||||||
|
isSub = ref(subs.includes(hash));
|
||||||
|
|
||||||
|
function addSub() {
|
||||||
|
if (artist.state.title && !isSub.value) {
|
||||||
|
subs.push(hash);
|
||||||
|
store.setItem('subs', JSON.stringify(subs));
|
||||||
|
isSub.value = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -21,7 +35,9 @@ const artist = useArtist(),
|
||||||
@click="
|
@click="
|
||||||
results.getAlbum('/playlist?list=' + artist.state.playlistId)
|
results.getAlbum('/playlist?list=' + artist.state.playlistId)
|
||||||
" />
|
" />
|
||||||
<span class="us-box subs">{{ artist.state.subscriberCount || 0 }}</span>
|
<span class="us-box subs" :data-active="isSub" @click="addSub">{{
|
||||||
|
artist.state.subscriberCount || 0
|
||||||
|
}}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -79,10 +95,19 @@ p.more {
|
||||||
color: var(--color-foreground);
|
color: var(--color-foreground);
|
||||||
box-shadow: 0 0 1rem var(--color-background-mute);
|
box-shadow: 0 0 1rem var(--color-background-mute);
|
||||||
}
|
}
|
||||||
|
.subs {
|
||||||
|
transition: background-color 0.4s ease, color 0.4s ease;
|
||||||
|
}
|
||||||
.subs::after {
|
.subs::after {
|
||||||
content: ' Subscribers';
|
content: ' Subscribers';
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
.subs:hover,
|
||||||
|
.subs[data-active='true'] {
|
||||||
|
background-color: var(--color-foreground);
|
||||||
|
color: var(--color-background);
|
||||||
|
background-clip: border-box;
|
||||||
|
}
|
||||||
@media (max-width: 400px) {
|
@media (max-width: 400px) {
|
||||||
.subs::after {
|
.subs::after {
|
||||||
content: ' Subs';
|
content: ' Subs';
|
||||||
|
|
|
@ -18,6 +18,7 @@ import {
|
||||||
useAuthCreatePlaylist,
|
useAuthCreatePlaylist,
|
||||||
getAuthPlaylists,
|
getAuthPlaylists,
|
||||||
getJsonAuth,
|
getJsonAuth,
|
||||||
|
getJsonPiped,
|
||||||
} from '@/scripts/fetch.js';
|
} from '@/scripts/fetch.js';
|
||||||
|
|
||||||
import { useResults } from '@/stores/results.js';
|
import { useResults } from '@/stores/results.js';
|
||||||
|
@ -25,7 +26,9 @@ import { useI18n, useNav } from '@/stores/misc.js';
|
||||||
|
|
||||||
const { t } = useI18n(),
|
const { t } = useI18n(),
|
||||||
store = useStore(),
|
store = useStore(),
|
||||||
auth = ref(!!store.auth);
|
auth = ref(!!store.auth),
|
||||||
|
results = useResults(),
|
||||||
|
nav = useNav();
|
||||||
|
|
||||||
const emit = defineEmits(['play-urls', 'open-playlist']),
|
const emit = defineEmits(['play-urls', 'open-playlist']),
|
||||||
list = ref([]),
|
list = ref([]),
|
||||||
|
@ -55,12 +58,13 @@ const Open = key => {
|
||||||
useGetPlaylist(key, res => {
|
useGetPlaylist(key, res => {
|
||||||
console.log(res);
|
console.log(res);
|
||||||
if (res.urls.length > 0) {
|
if (res.urls.length > 0) {
|
||||||
useResults().items.songs = {
|
results.resetItems();
|
||||||
|
results.setItem('songs', {
|
||||||
title: 'Local • ' + key,
|
title: 'Local • ' + key,
|
||||||
items: res.urls.map(i => ({ ...i, ...{ thumbnail: '/1x1.png' } })),
|
items: res.urls.map(i => ({ ...i, ...{ thumbnail: '/1x1.png' } })),
|
||||||
};
|
});
|
||||||
|
|
||||||
useNav().state.page = 'home';
|
nav.state.page = 'home';
|
||||||
} else alert('No songs to play!');
|
} else alert('No songs to play!');
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -140,6 +144,23 @@ const Login = async () => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getFeeds = async () => {
|
||||||
|
const subs = JSON.parse(store.subs ? store.subs : '[]');
|
||||||
|
|
||||||
|
if (subs.length > 0) {
|
||||||
|
const json = await getJsonPiped(
|
||||||
|
'/feed/unauthenticated?channels=' + subs.join(','),
|
||||||
|
);
|
||||||
|
|
||||||
|
results.resetItems();
|
||||||
|
results.setItem('songs', {
|
||||||
|
title: t('title.feeds'),
|
||||||
|
items: json,
|
||||||
|
});
|
||||||
|
|
||||||
|
nav.state.page = 'home';
|
||||||
|
}
|
||||||
|
};
|
||||||
watch(
|
watch(
|
||||||
() => show.sync,
|
() => show.sync,
|
||||||
async () => {
|
async () => {
|
||||||
|
@ -284,6 +305,8 @@ onMounted(async () => {
|
||||||
<div
|
<div
|
||||||
class="npl-box bi bi-arrow-repeat pop"
|
class="npl-box bi bi-arrow-repeat pop"
|
||||||
@click="show.sync = true"></div>
|
@click="show.sync = true"></div>
|
||||||
|
|
||||||
|
<div class="npl-box bi bi-tag pop" @click="getFeeds"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2 v-if="list.length > 0">{{ t('playlist.local') }}</h2>
|
<h2 v-if="list.length > 0">{{ t('playlist.local') }}</h2>
|
||||||
|
@ -341,6 +364,13 @@ onMounted(async () => {
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
.grid {
|
||||||
|
display: grid;
|
||||||
|
width: fit-content;
|
||||||
|
gap: 2rem;
|
||||||
|
grid-auto-rows: 10rem;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
h2 {
|
h2 {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin: 2rem;
|
margin: 2rem;
|
||||||
|
@ -350,7 +380,6 @@ h2 {
|
||||||
}
|
}
|
||||||
.npl-box {
|
.npl-box {
|
||||||
--background: var(--color-background-mute);
|
--background: var(--color-background-mute);
|
||||||
margin: 0 auto 2rem auto;
|
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
padding: 2rem 3rem;
|
padding: 2rem 3rem;
|
||||||
font-size: 4rem;
|
font-size: 4rem;
|
||||||
|
@ -404,12 +433,4 @@ button.logout {
|
||||||
display: block;
|
display: block;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
@media (min-width: 1024px) {
|
|
||||||
.npl-box:first-child {
|
|
||||||
margin: 0 1rem 0 auto;
|
|
||||||
}
|
|
||||||
.npl-box:last-child {
|
|
||||||
margin: 0 auto 0 1rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -92,12 +92,12 @@ onMounted(() => {
|
||||||
class="input"
|
class="input"
|
||||||
:value="getTheme()"
|
:value="getTheme()"
|
||||||
@change="setTheme($event.target.value)">
|
@change="setTheme($event.target.value)">
|
||||||
<option value="dark">Dark (Default)</option>
|
<option value="dark">{{ t('pref.dark') }}</option>
|
||||||
<option value="light">Light</option>
|
<option value="light">{{ t('pref.light') }}</option>
|
||||||
<option value="blur">Blur</option>
|
<option value="blur">{{ t('pref.blur') }}</option>
|
||||||
<option value="light blur">Blur (Light)</option>
|
<option value="light blur">{{ t('pref.blur_light') }}</option>
|
||||||
<option value="dracula">Dracula</option>
|
<option value="dracula">{{ t('pref.dracula') }}</option>
|
||||||
<option value="nord">Nord</option>
|
<option value="nord">{{ t('pref.nord') }}</option>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<h2>Language</h2>
|
<h2>Language</h2>
|
||||||
|
|
|
@ -103,6 +103,7 @@ const shuffleAdd = () => {
|
||||||
if (
|
if (
|
||||||
(!isSearch.value && !results.items?.songs?.title) ||
|
(!isSearch.value && !results.items?.songs?.title) ||
|
||||||
loading.value ||
|
loading.value ||
|
||||||
|
results.next == 'null' ||
|
||||||
!results.next
|
!results.next
|
||||||
)
|
)
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -256,11 +256,7 @@ async function Like() {
|
||||||
<button
|
<button
|
||||||
class="bi bi-three-dots clickable"
|
class="bi bi-three-dots clickable"
|
||||||
aria-label="More Controls"
|
aria-label="More Controls"
|
||||||
@click="
|
@click="showme.menu = !showme.menu"></button>
|
||||||
showme.menu = !showme.menu;
|
|
||||||
player.state.lyrics ? player.toggle('lyrics') : '';
|
|
||||||
player.state.info ? player.toggle('info') : '';
|
|
||||||
"></button>
|
|
||||||
<Transition name="fade">
|
<Transition name="fade">
|
||||||
<div id="menu" v-if="showme.menu" class="popup">
|
<div id="menu" v-if="showme.menu" class="popup">
|
||||||
<button
|
<button
|
||||||
|
|
|
@ -14,7 +14,8 @@
|
||||||
"login": "Login",
|
"login": "Login",
|
||||||
"local": "Local",
|
"local": "Local",
|
||||||
"remote": "Remote",
|
"remote": "Remote",
|
||||||
"search": "Search"
|
"search": "Search",
|
||||||
|
"feeds": "Feeds"
|
||||||
},
|
},
|
||||||
"action": {
|
"action": {
|
||||||
"back": "Back",
|
"back": "Back",
|
||||||
|
@ -35,6 +36,12 @@
|
||||||
},
|
},
|
||||||
"pref": {
|
"pref": {
|
||||||
"theme": "Theme",
|
"theme": "Theme",
|
||||||
|
"dark": "Dark (Default)",
|
||||||
|
"light": "Light",
|
||||||
|
"blur": "Blur",
|
||||||
|
"blur_light": "Blur (Light)",
|
||||||
|
"dracula": "Dracula",
|
||||||
|
"nord": "Nord",
|
||||||
"tab": "Default Tab",
|
"tab": "Default Tab",
|
||||||
"player": "Audio Player",
|
"player": "Audio Player",
|
||||||
"auto_queue": "Automatically Queue Songs",
|
"auto_queue": "Automatically Queue Songs",
|
||||||
|
|
|
@ -68,6 +68,10 @@ export const SUPPORTED_LOCALES = [
|
||||||
code: 'nl',
|
code: 'nl',
|
||||||
name: 'Nederlands',
|
name: 'Nederlands',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
code: 'ro',
|
||||||
|
name: 'Română',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
code: 'ru',
|
code: 'ru',
|
||||||
name: 'Pусский ',
|
name: 'Pусский ',
|
||||||
|
|
|
@ -67,7 +67,10 @@ export const useResults = defineStore('results', () => {
|
||||||
useRoute(e);
|
useRoute(e);
|
||||||
useNav().state.page = 'home';
|
useNav().state.page = 'home';
|
||||||
|
|
||||||
next.value = hash + '?nextpage=' + encodeURIComponent(json.nextpage);
|
next.value =
|
||||||
|
json.nextpage || json.nextpage != 'null'
|
||||||
|
? hash + '?nextpage=' + encodeURIComponent(json.nextpage)
|
||||||
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -88,6 +91,7 @@ export const useArtist = defineStore('artist', () => {
|
||||||
title: null,
|
title: null,
|
||||||
description: null,
|
description: null,
|
||||||
subscriberCount: 0,
|
subscriberCount: 0,
|
||||||
|
hash: null,
|
||||||
thumbnails: [],
|
thumbnails: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -99,7 +103,7 @@ export const useArtist = defineStore('artist', () => {
|
||||||
|
|
||||||
function set(obj) {
|
function set(obj) {
|
||||||
for (let i in obj) {
|
for (let i in obj) {
|
||||||
state[i] = obj[i];
|
if (i in state) state[i] = obj[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,6 +126,7 @@ export const useArtist = defineStore('artist', () => {
|
||||||
console.log(results.items);
|
console.log(results.items);
|
||||||
|
|
||||||
json.items = undefined;
|
json.items = undefined;
|
||||||
|
json.hash = e;
|
||||||
|
|
||||||
reset();
|
reset();
|
||||||
set(json);
|
set(json);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue