mirror of
https://codeberg.org/Hyperpipe/Hyperpipe
synced 2025-06-28 21:18:01 +02:00
Merge branch 'main' into ™
This commit is contained in:
commit
0f79b7039d
22 changed files with 7588 additions and 346 deletions
|
@ -119,7 +119,7 @@ You can reach out to me personally on:
|
|||
|
||||
---
|
||||
|
||||
*Hyperpipe does not host any content. All content on Hyperpipe is from YouTube Music. YouTube and YouTube Music are trademarks of Google LLC. Hyperpipe is not affiliated with YouTube or YouTube Music.*
|
||||
*All content on Hyperpipe is from YouTube Music. YouTube and YouTube Music are trademarks of Google LLC. Hyperpipe is not affiliated with YouTube or YouTube Music.*
|
||||
|
||||
[hypipe]: https://hyperpipe.surge.sh
|
||||
[piped]: https://piped.kavin.rocks
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
<link rel="dns-prefetch" href="https://hyperpipe-proxy.onrender.com" />
|
||||
<link rel="dns-prefetch" href="https://piped-instances.kavin.rocks" />
|
||||
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="referrer" content="no-referrer" />
|
||||
|
||||
|
|
7689
package-lock.json
generated
7689
package-lock.json
generated
File diff suppressed because it is too large
Load diff
13
package.json
13
package.json
|
@ -10,20 +10,21 @@
|
|||
"check": "prettier --check ."
|
||||
},
|
||||
"dependencies": {
|
||||
"bootstrap-icons": "^1.10.2",
|
||||
"bootstrap-icons": "^1.10.3",
|
||||
"buffer": "^6.0.3",
|
||||
"dompurify": "^2.4.1",
|
||||
"dompurify": "^2.4.3",
|
||||
"mux.js": "^6.2.0",
|
||||
"peerjs": "^1.4.7",
|
||||
"pinia": "^2.0.28",
|
||||
"shaka-player": "^4.3.1",
|
||||
"pinia": "^2.0.29",
|
||||
"shaka-player": "^4.3.3",
|
||||
"stream-browserify": "^3.0.0",
|
||||
"vue": "^3.2.38",
|
||||
"xml-js": "^1.6.11"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^4.0.0",
|
||||
"prettier": "^2.8.1",
|
||||
"vite": "^4.0.0"
|
||||
"prettier": "^2.8.3",
|
||||
"vite": "^4.0.4",
|
||||
"vite-plugin-pwa": "^0.14.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
{
|
||||
"name": "Hyperpipe",
|
||||
"short_name": "Hyperpipe",
|
||||
"start_url": "/",
|
||||
"display": "standalone",
|
||||
"background_color": "#000",
|
||||
"description": "Privacy respecting YouTube Music Frontend.",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/android-chrome-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/android-maskable.png",
|
||||
"sizes": "1024x1024",
|
||||
"type": "image/png",
|
||||
"purpose": "maskable"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -109,9 +109,8 @@ function playList(a) {
|
|||
/* Lifestyle hooks */
|
||||
onBeforeMount(() => {
|
||||
/* Set the default theme if set */
|
||||
if (store.theme) {
|
||||
document.body.setAttribute('data-theme', store.theme);
|
||||
}
|
||||
if (store.theme) document.body.setAttribute('data-theme', store.theme);
|
||||
if (store.compact == 'true') document.body.setAttribute('data-compact', '');
|
||||
|
||||
/* Set the default locale if set */
|
||||
if (store.locale) setupLocale(store.locale);
|
||||
|
|
|
@ -327,15 +327,26 @@ img {
|
|||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
@media (max-width: 530px) {
|
||||
[data-compact] .grid-3 {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
}
|
||||
@media (min-width: 530px) {
|
||||
.grid-3 {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
[data-compact] .grid-3 {
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
}
|
||||
}
|
||||
@media (min-width: 780px) {
|
||||
.grid-3 {
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
}
|
||||
[data-compact] .grid-3 {
|
||||
grid-template-columns: 1fr 1fr 1fr 1fr;
|
||||
}
|
||||
}
|
||||
@media (min-width: 930px) {
|
||||
.grid {
|
||||
|
@ -347,6 +358,9 @@ img {
|
|||
.grid-3 {
|
||||
grid-template-columns: 1fr 1fr 1fr 1fr;
|
||||
}
|
||||
[data-compact] .grid-3 {
|
||||
grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
/* Animations */
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
{
|
||||
"date": "2023-01-13"
|
||||
"date": "2023-01-24"
|
||||
}
|
||||
|
|
|
@ -45,5 +45,18 @@ defineEmits(['open-album']);
|
|||
}
|
||||
.card-text {
|
||||
margin-top: 0.5rem;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
[data-compact] .card {
|
||||
min-height: 12rem;
|
||||
width: 10rem;
|
||||
}
|
||||
[data-compact] .card-bg {
|
||||
width: 7rem;
|
||||
height: 7rem;
|
||||
}
|
||||
[data-compact] .card-text {
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -14,19 +14,17 @@ const subs = JSON.parse(store.subs ? store.subs : '[]'),
|
|||
isSub = ref(subs.includes(hash));
|
||||
|
||||
function Sub() {
|
||||
if (artist.state.title) {
|
||||
if (isSub.value) {
|
||||
subs.splice(subs.indexOf(hash), 1);
|
||||
store.setItem('subs', JSON.stringify(subs));
|
||||
isSub.value = false;
|
||||
} else {
|
||||
subs.push(hash);
|
||||
store.setItem('subs', JSON.stringify(subs));
|
||||
isSub.value = true;
|
||||
}
|
||||
if (!artist.state.title) return;
|
||||
|
||||
alert(JSON.stringify(subs));
|
||||
if (isSub.value) {
|
||||
subs.splice(subs.indexOf(hash), 1);
|
||||
isSub.value = false;
|
||||
} else {
|
||||
subs.push(hash);
|
||||
isSub.value = true;
|
||||
}
|
||||
|
||||
store.setItem('subs', JSON.stringify(subs));
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -118,6 +118,11 @@ async function Stream() {
|
|||
}
|
||||
}
|
||||
|
||||
function destroy() {
|
||||
window.audioPlayer.destroy();
|
||||
window.audioPlayer = undefined;
|
||||
}
|
||||
|
||||
watch(
|
||||
() => player.state.play,
|
||||
() => {
|
||||
|
@ -150,8 +155,9 @@ onMounted(() => {
|
|||
if ('mediaSession' in navigator) {
|
||||
navigator.mediaSession.setActionHandler('play', () => {
|
||||
player.state.status = 'pause';
|
||||
|
||||
audio.value.play().catch(err => {
|
||||
alert(err);
|
||||
console.log(err);
|
||||
player.state.status = 'play';
|
||||
});
|
||||
});
|
||||
|
@ -163,7 +169,7 @@ onMounted(() => {
|
|||
|
||||
navigator.mediaSession.setActionHandler('previoustrack', () => {
|
||||
if (data.state.urls.length > 2) {
|
||||
const i = data.state.urls.map(s => s.url).indexOf(data.state.url);
|
||||
const i = data.state.urls.findIndex(s => s.url == data.state.url);
|
||||
|
||||
data.getSong(data.state.urls[i - 1].url);
|
||||
}
|
||||
|
@ -171,7 +177,7 @@ onMounted(() => {
|
|||
|
||||
navigator.mediaSession.setActionHandler('nexttrack', () => {
|
||||
if (data.state.urls.length > 2) {
|
||||
const i = data.state.urls.map(s => s.url).indexOf(data.state.url);
|
||||
const i = data.state.urls.findIndex(s => s.url == data.state.url);
|
||||
|
||||
data.getSong(data.state.urls[i + 1].url);
|
||||
}
|
||||
|
@ -188,16 +194,10 @@ onMounted(() => {
|
|||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (window.audioPlayer) {
|
||||
window.audioPlayer.destroy();
|
||||
window.audioPlayer = undefined;
|
||||
}
|
||||
if (window.audioPlayer) destroy();
|
||||
});
|
||||
onUnmounted(() => {
|
||||
if (window.audioPlayer) {
|
||||
window.audioPlayer.destroy();
|
||||
window.audioPlayer = undefined;
|
||||
}
|
||||
if (window.audioPlayer) destroy();
|
||||
});
|
||||
</script>
|
||||
|
||||
|
|
|
@ -19,7 +19,8 @@ import('@/assets/version.json').then(v => {
|
|||
const { t, setupLocale } = useI18n(),
|
||||
instances = ref([]),
|
||||
hypInstances = ref([]),
|
||||
next = ref(false);
|
||||
next = ref(false),
|
||||
compact = ref(false);
|
||||
|
||||
getJson('https://piped-instances.kavin.rocks').then(i => {
|
||||
instances.value = i;
|
||||
|
@ -60,8 +61,14 @@ function setLang(locale) {
|
|||
setStore('locale', locale);
|
||||
}
|
||||
|
||||
function setCodec(codec) {
|
||||
setStore('codec', codec);
|
||||
if (window.audioPlayer)
|
||||
window.audioPlayer.configure('preferredAudioCodecs', codec.split(':'));
|
||||
}
|
||||
|
||||
function getStoreBool(key, ele) {
|
||||
ele.value = getStore(key) || true;
|
||||
ele.value = getStore(key) || ele.value;
|
||||
}
|
||||
|
||||
const verifyApi = computed(() =>
|
||||
|
@ -82,6 +89,7 @@ const verifyApi = computed(() =>
|
|||
|
||||
onMounted(() => {
|
||||
getStoreBool('next', next);
|
||||
getStoreBool('compact', compact);
|
||||
});
|
||||
</script>
|
||||
|
||||
|
@ -100,6 +108,17 @@ onMounted(() => {
|
|||
<option value="nord">{{ t('pref.nord') }}</option>
|
||||
</select>
|
||||
|
||||
<div class="left">
|
||||
<input
|
||||
type="checkbox"
|
||||
name="pref-chk-compact"
|
||||
id="pref-chk-compact"
|
||||
class="input"
|
||||
@change="setStore('compact', $event.target.checked)"
|
||||
v-model="compact" />
|
||||
<label for="pref-chk-compact">{{ t('pref.compact') }}</label>
|
||||
</div>
|
||||
|
||||
<h2>Language</h2>
|
||||
|
||||
<select
|
||||
|
@ -145,7 +164,7 @@ onMounted(() => {
|
|||
name="pref-codec"
|
||||
class="input"
|
||||
:value="getStore('codec') || 'opus:mp4a'"
|
||||
@change="setStore('codec', $event.target.value)">
|
||||
@change="setCodec($event.target.value)">
|
||||
<option value="opus:mp4a">opus, mp4a</option>
|
||||
<option value="mp4a:opus">mp4a, opus</option>
|
||||
<option value="opus">opus</option>
|
||||
|
|
|
@ -173,4 +173,12 @@ span.bi-three-dots-vertical {
|
|||
.bi-dash-lg {
|
||||
color: indianred;
|
||||
}
|
||||
|
||||
[data-compact] .card {
|
||||
margin: 0;
|
||||
}
|
||||
[data-compact] .song-bg {
|
||||
width: 70px;
|
||||
height: 70px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -37,7 +37,8 @@
|
|||
"explore": "Procházet",
|
||||
"charts": "Žebříčky",
|
||||
"home": "Domů",
|
||||
"library": "Knihovna"
|
||||
"library": "Knihovna",
|
||||
"compact": "Kompaktní zobrazení"
|
||||
},
|
||||
"instances": {
|
||||
"name": "Název",
|
||||
|
|
|
@ -56,7 +56,8 @@
|
|||
"library": "Bibliothek",
|
||||
"charts": "Diagramme",
|
||||
"explore": "Erkunden",
|
||||
"home": "Startseite"
|
||||
"home": "Startseite",
|
||||
"compact": "Kompakte Ansicht"
|
||||
},
|
||||
"info": {
|
||||
"no_info": "Keine Informationen verfügbar",
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
"blur_light": "Blur (Light)",
|
||||
"dracula": "Dracula",
|
||||
"nord": "Nord",
|
||||
"compact": "Compact View",
|
||||
"tab": "Default Tab",
|
||||
"player": "Audio Player",
|
||||
"auto_queue": "Automatically Queue Songs",
|
||||
|
|
|
@ -56,7 +56,8 @@
|
|||
"home": "Inicio",
|
||||
"library": "Biblioteca",
|
||||
"charts": "Gráfica",
|
||||
"explore": "Explorar"
|
||||
"explore": "Explorar",
|
||||
"compact": "Vista compacta"
|
||||
},
|
||||
"info": {
|
||||
"see_all": "Ver todo",
|
||||
|
|
|
@ -46,7 +46,8 @@
|
|||
"charts": "Graphiques",
|
||||
"explore": "Explorer",
|
||||
"home": "Accueil",
|
||||
"library": "Bibliothèque"
|
||||
"library": "Bibliothèque",
|
||||
"compact": "Vue compacte"
|
||||
},
|
||||
"info": {
|
||||
"see_all": "Voir tout",
|
||||
|
|
|
@ -19,7 +19,8 @@
|
|||
"library": "Raccolta",
|
||||
"home": "Pagina principale",
|
||||
"charts": "Grafici",
|
||||
"explore": "Esplora"
|
||||
"explore": "Esplora",
|
||||
"compact": "Vista compatta"
|
||||
},
|
||||
"title": {
|
||||
"albums": "Album",
|
||||
|
|
|
@ -56,7 +56,8 @@
|
|||
"charts": "Grafikler",
|
||||
"library": "Kütüphane",
|
||||
"explore": "Keşfet",
|
||||
"home": "Ana sayfa"
|
||||
"home": "Ana sayfa",
|
||||
"compact": "Sıkı Görünüm"
|
||||
},
|
||||
"info": {
|
||||
"see_all": "Hepsini Gör",
|
||||
|
|
|
@ -8,18 +8,17 @@ const store = useStore();
|
|||
|
||||
export const useData = defineStore('data', () => {
|
||||
const state = reactive({
|
||||
title: '',
|
||||
description: '',
|
||||
artist: '',
|
||||
art: '',
|
||||
url: '',
|
||||
artistUrl: '',
|
||||
lyrics: '',
|
||||
src: [],
|
||||
urls: [],
|
||||
});
|
||||
|
||||
const player = usePlayer();
|
||||
title: '',
|
||||
description: '',
|
||||
artist: '',
|
||||
art: '',
|
||||
url: '',
|
||||
artistUrl: '',
|
||||
lyrics: '',
|
||||
src: [],
|
||||
urls: [],
|
||||
}),
|
||||
player = usePlayer();
|
||||
|
||||
async function getSong(e) {
|
||||
console.log(e);
|
||||
|
@ -48,7 +47,7 @@ export const useData = defineStore('data', () => {
|
|||
if (
|
||||
store.getItem('next') !== 'false' &&
|
||||
(!state.urls ||
|
||||
!state.urls.filter(s => s.url == state.url)[0] ||
|
||||
state.urls.findIndex(s => s.url == state.url) < 0 ||
|
||||
state.urls.length == 1)
|
||||
) {
|
||||
const json = await getJsonHyp('/next/' + hash);
|
||||
|
@ -98,8 +97,7 @@ export const useData = defineStore('data', () => {
|
|||
}
|
||||
|
||||
function playNext(u) {
|
||||
const now = state.urls.filter(s => s.url === state.url)[0],
|
||||
i = state.urls.indexOf(now);
|
||||
const i = state.urls.findIndex(s => s.url === state.url);
|
||||
|
||||
if (player.state.loop == 2) getSong(state.url);
|
||||
else if (
|
||||
|
@ -117,8 +115,7 @@ export const useData = defineStore('data', () => {
|
|||
}
|
||||
|
||||
function prevTrack() {
|
||||
const now = state.urls.filter(s => s.url === state.url)[0],
|
||||
i = state.urls.indexOf(now);
|
||||
const i = state.urls.findIndex(s => s.url === state.url);
|
||||
|
||||
if (state.urls[i - 1]) getSong(state.urls[i - 1].url);
|
||||
else if (player.state.loop == 1) {
|
||||
|
@ -130,8 +127,7 @@ export const useData = defineStore('data', () => {
|
|||
}
|
||||
|
||||
function nextTrack() {
|
||||
const now = state.urls.filter(s => s.url === state.url)[0],
|
||||
i = state.urls.indexOf(now);
|
||||
const i = state.urls.findIndex(s => s.url === state.url);
|
||||
|
||||
if (state.urls[i + 1]) getSong(state.urls[i + 1].url);
|
||||
else if (player.state.loop == 1) {
|
||||
|
|
|
@ -2,10 +2,49 @@ import { fileURLToPath, URL } from 'url';
|
|||
|
||||
import { defineConfig } from 'vite';
|
||||
import vue from '@vitejs/plugin-vue';
|
||||
import { VitePWA } from 'vite-plugin-pwa';
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [vue()],
|
||||
plugins: [
|
||||
vue(),
|
||||
VitePWA({
|
||||
registerType: 'autoUpdate',
|
||||
workbox: {
|
||||
globPatterns: [
|
||||
'**/*.{js,css,html,png,svg,woff2}',
|
||||
'manifest.webmanifest',
|
||||
],
|
||||
},
|
||||
manifest: {
|
||||
name: 'Hyperpipe',
|
||||
short_name: 'Hyperpipe',
|
||||
start_url: '/',
|
||||
display: 'standalone',
|
||||
background_color: '#000',
|
||||
theme_color: '#000',
|
||||
description: 'Privacy respecting YouTube Music Frontend.',
|
||||
icons: [
|
||||
{
|
||||
src: '/android-chrome-192x192.png',
|
||||
sizes: '192x192',
|
||||
type: 'image/png',
|
||||
},
|
||||
{
|
||||
src: '/android-chrome-512x512.png',
|
||||
sizes: '512x512',
|
||||
type: 'image/png',
|
||||
},
|
||||
{
|
||||
src: '/android-maskable.png',
|
||||
sizes: '1024x1024',
|
||||
type: 'image/png',
|
||||
purpose: 'maskable',
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': fileURLToPath(new URL('./src', import.meta.url)),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue