Merge branch 'main' into ™

This commit is contained in:
HexagonCDN 2023-01-25 09:10:52 +00:00
commit 0f79b7039d
22 changed files with 7588 additions and 346 deletions

View file

@ -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

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -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"
}
}

View file

@ -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"
}
]
}

View file

@ -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);

View file

@ -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 */

View file

@ -1,3 +1,3 @@
{
"date": "2023-01-13"
"date": "2023-01-24"
}

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -37,7 +37,8 @@
"explore": "Procházet",
"charts": "Žebříčky",
"home": "Domů",
"library": "Knihovna"
"library": "Knihovna",
"compact": "Kompaktní zobrazení"
},
"instances": {
"name": "Název",

View file

@ -56,7 +56,8 @@
"library": "Bibliothek",
"charts": "Diagramme",
"explore": "Erkunden",
"home": "Startseite"
"home": "Startseite",
"compact": "Kompakte Ansicht"
},
"info": {
"no_info": "Keine Informationen verfügbar",

View file

@ -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",

View file

@ -56,7 +56,8 @@
"home": "Inicio",
"library": "Biblioteca",
"charts": "Gráfica",
"explore": "Explorar"
"explore": "Explorar",
"compact": "Vista compacta"
},
"info": {
"see_all": "Ver todo",

View file

@ -46,7 +46,8 @@
"charts": "Graphiques",
"explore": "Explorer",
"home": "Accueil",
"library": "Bibliothèque"
"library": "Bibliothèque",
"compact": "Vue compacte"
},
"info": {
"see_all": "Voir tout",

View file

@ -19,7 +19,8 @@
"library": "Raccolta",
"home": "Pagina principale",
"charts": "Grafici",
"explore": "Esplora"
"explore": "Esplora",
"compact": "Vista compatta"
},
"title": {
"albums": "Album",

View file

@ -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",

View file

@ -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) {

View file

@ -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)),