Merge branch 'main' into ™

This commit is contained in:
HexagonCDN 2023-01-14 10:23:22 +00:00
commit 9d7033d728
14 changed files with 185 additions and 58 deletions

1
.gitignore vendored
View file

@ -6,6 +6,7 @@ yarn-debug.log*
yarn-error.log* yarn-error.log*
pnpm-debug.log* pnpm-debug.log*
lerna-debug.log* lerna-debug.log*
log.txt
node_modules node_modules
.DS_Store .DS_Store

View file

@ -1,4 +1,4 @@
FROM --platform=$BUILDPLATFORM node:lts AS build FROM --platform=$BUILDPLATFORM node:lts-alpine AS build
WORKDIR /app/ WORKDIR /app/
@ -9,7 +9,7 @@ RUN --mount=type=cache,target=/root/.cache/node \
npm install --prefer-offline && \ npm install --prefer-offline && \
npm run build npm run build
FROM --platform=$BUILDPLATFORM nginx:stable FROM --platform=$BUILDPLATFORM nginx:stable-alpine
COPY --from=build /app/dist/ /usr/share/nginx/html/ COPY --from=build /app/dist/ /usr/share/nginx/html/
COPY docker/nginx.conf /etc/nginx/conf.d/default.conf COPY docker/nginx.conf /etc/nginx/conf.d/default.conf

View file

@ -1,3 +1,3 @@
{ {
"date": "2022-12-31" "date": "2023-01-13"
} }

View file

@ -36,8 +36,11 @@ const list = ref([]),
show = reactive({ show = reactive({
new: false, new: false,
sync: false, sync: false,
import: false,
}), }),
text = ref(''), text = ref(''),
isImport = ref(false),
importFile = ref(''),
sync = reactive({ sync = reactive({
type: 'send', type: 'send',
id: 'Please Wait...', id: 'Please Wait...',
@ -82,6 +85,59 @@ const Open = key => {
}); });
} }
}, },
Import = async (data = importFile.value) => {
if (data?.type == 'application/json')
data = await data.text().then(txt => JSON.parse(txt).local);
if (!data) {
alert('No data to import');
return;
}
List();
for (let i of data) {
const pl = list.value.filter(p => p.name == i.name)[0];
if (pl) {
for (let u of i.urls) {
if (!pl.urls.filter(r => r.url === u.url)[0]) {
useUpdatePlaylist(i.name, u, () => {
console.log('Added: ' + u.name);
});
}
}
} else {
useCreatePlaylist(i.name, i.urls);
}
List();
}
show.import = false;
},
Export = () => {
List();
const base = JSON.stringify(
{
format: 'Hyperpipe',
version: 0,
local: list.value,
playlists: [], // TODO?
},
null,
2,
),
file = new Blob([base], { type: 'application/json' }),
ele = document.createElement('a');
ele.href = URL.createObjectURL(file);
ele.download = 'hyperpipe.json';
ele.click();
ele.remove();
},
Send = () => { Send = () => {
const conn = sync.peer.connect(sync.to); const conn = sync.peer.connect(sync.to);
@ -183,29 +239,9 @@ watch(
if (sync.type == 'rec') { if (sync.type == 'rec') {
console.log(data); console.log(data);
List(); Import(data);
for (let i of data) { show.sync = false;
const pl = list.value.filter(p => p.name == i.name)[0];
if (pl) {
for (let u of i.urls) {
if (!pl.urls.filter(r => r.url === u.url)[0]) {
useUpdatePlaylist(i.name, u, () => {
console.log('Added: ' + u.name);
});
}
}
} else {
useCreatePlaylist(i.name, i.urls);
}
List();
if (data.indexOf(i) == data.length - 1) {
show.sync = false;
}
}
} }
}); });
}); });
@ -300,6 +336,43 @@ onMounted(async () => {
</template> </template>
</Modal> </Modal>
<Modal
n="2"
:display="show.import"
:title="t('action.import')"
@show="
e => {
show.import = e;
}
">
<template #content>
<div class="tabs">
<button :data-active="isImport" @click="isImport = true">
{{ t('action.import') }}
</button>
<button :data-active="!isImport" @click="isImport = false">
{{ t('action.export') }}
</button>
</div>
<div v-if="isImport">
<input
type="file"
class="textbox"
name="import"
accept="application/json"
@change="importFile = $event.target.files[0]" />
</div>
</template>
<template #buttons>
<button @click="show.import = false">{{ t('action.cancel') }}</button>
<button @click="isImport ? Import() : Export()">
{{ isImport ? t('action.import') : t('action.export') }}
</button>
</template>
</Modal>
<div class="grid"> <div class="grid">
<div class="npl-box bi bi-plus-lg pop" @click="show.new = true"></div> <div class="npl-box bi bi-plus-lg pop" @click="show.new = true"></div>
@ -308,6 +381,8 @@ onMounted(async () => {
@click="show.sync = true"></div> @click="show.sync = true"></div>
<div class="npl-box bi bi-tag pop" @click="getFeeds"></div> <div class="npl-box bi bi-tag pop" @click="getFeeds"></div>
<div class="npl-box bi bi-arrow-up pop" @click="show.import = true"></div>
</div> </div>
<h2 v-if="list.length > 0">{{ t('playlist.local') }}</h2> <h2 v-if="list.length > 0">{{ t('playlist.local') }}</h2>
@ -329,6 +404,7 @@ onMounted(async () => {
v-for="i in user.playlists" v-for="i in user.playlists"
:key="i.id" :key="i.id"
:name="i.name.replace('Playlist - ', '')" :name="i.name.replace('Playlist - ', '')"
:author="t('title.songs') + ' • ' + i.videos"
:art="pathname(i.thumbnail) != '/' ? i.thumbnail : undefined" :art="pathname(i.thumbnail) != '/' ? i.thumbnail : undefined"
@open-album="$emit('open-playlist', '/playlists?list=' + i.id)" /> @open-album="$emit('open-playlist', '/playlists?list=' + i.id)" />
</div> </div>
@ -419,6 +495,20 @@ button.logout {
display: block; display: block;
background: linear-gradient(135deg, indianred, #bf616a); background: linear-gradient(135deg, indianred, #bf616a);
} }
input[type='file'] {
display: block;
}
input[type='file']::file-selector-button {
font-weight: bold;
appearance: inherit;
outline: inherit;
border: inherit;
border-radius: 0.25rem;
padding: 0.5rem;
margin: 0.1rem 0.5rem 0.1rem 0.1rem;
color: var(--color-background);
background: linear-gradient(135deg, cornflowerblue, #88c0d0);
}
.tabs button:first-child { .tabs button:first-child {
border-radius: 0.25rem 0 0 0.25rem; border-radius: 0.25rem 0 0 0.25rem;
} }

View file

@ -119,10 +119,10 @@ onMounted(() => {
class="input" class="input"
:value="getStore('page') || 'home'" :value="getStore('page') || 'home'"
@change="setStore('page', $event.target.value)"> @change="setStore('page', $event.target.value)">
<option value="home">Home</option> <option value="home">{{ t('pref.home') }}</option>
<option value="explore">Explore</option> <option value="explore">{{ t('pref.explore') }}</option>
<option value="charts">Charts</option> <option value="charts">{{ t('pref.charts') }}</option>
<option value="library">Library</option> <option value="library">{{ t('pref.library') }}</option>
</select> </select>
<h2>{{ t('pref.player') }}</h2> <h2>{{ t('pref.player') }}</h2>

View file

@ -134,7 +134,8 @@ async function Like() {
plRemote = true; plRemote = true;
" "
:data-active="pl == i.id && plRemote == true"> :data-active="pl == i.id && plRemote == true">
<span>{{ i.name }}</span> <span>{{ i.name }}</span
><span class="ml-auto">{{ i.videos }}</span>
</div> </div>
</template> </template>
<template #buttons> <template #buttons>
@ -424,11 +425,6 @@ input[type='range']::-webkit-slider-thumb {
background-color: var(--color-foreground); background-color: var(--color-foreground);
-webkit-appearance: none; -webkit-appearance: none;
appearance: none; appearance: none;
opacity: 0;
transition: opacity 0.4s ease;
}
input[type='range']:hover::-webkit-slider-thumb,
#vol input[type='range']::-webkit-slider-thumb {
opacity: 1; opacity: 1;
height: 1rem; height: 1rem;
width: 1rem; width: 1rem;
@ -447,13 +443,8 @@ input[type='range']::-webkit-slider-runnable-track {
input[type='range']::-moz-range-thumb { input[type='range']::-moz-range-thumb {
-moz-appearance: none; -moz-appearance: none;
appearance: none; appearance: none;
opacity: 0;
border: none; border: none;
outline: none; outline: none;
transition: opacity 0.4s ease;
}
input[type='range']:hover::-moz-range-thumb,
#vol input[type='range']::-moz-range-thumb {
background-color: var(--color-foreground); background-color: var(--color-foreground);
opacity: 1; opacity: 1;
height: 1rem; height: 1rem;

View file

@ -33,7 +33,11 @@
"blur": "Rozmazání", "blur": "Rozmazání",
"blur_light": "Rozmazaný (světlý)", "blur_light": "Rozmazaný (světlý)",
"dracula": "Drákula", "dracula": "Drákula",
"nord": "Nord" "nord": "Nord",
"explore": "Procházet",
"charts": "Žebříčky",
"home": "Domů",
"library": "Knihovna"
}, },
"instances": { "instances": {
"name": "Název", "name": "Název",
@ -55,7 +59,9 @@
"add": "Přidat", "add": "Přidat",
"cancel": "Zrušit", "cancel": "Zrušit",
"send": "Poslat", "send": "Poslat",
"receive": "Obdržet" "receive": "Obdržet",
"import": "Importovat",
"export": "Exportovat"
}, },
"playlist": { "playlist": {
"local": "Místní playlisty", "local": "Místní playlisty",

View file

@ -3,8 +3,8 @@
"moods": "Stimmungen", "moods": "Stimmungen",
"songs": "Lieder", "songs": "Lieder",
"albums": "Alben", "albums": "Alben",
"genres": "Genres", "genres": "Kategorien",
"singles": "Singles", "singles": "Einzeltitel",
"artists": "Künstler/innen", "artists": "Künstler/innen",
"similar_artists": "Ähnliche Künstler/innen", "similar_artists": "Ähnliche Künstler/innen",
"featured": "Ausgewählt", "featured": "Ausgewählt",
@ -23,7 +23,9 @@
"create": "Erstellen", "create": "Erstellen",
"add": "Hinzufügen", "add": "Hinzufügen",
"cancel": "Abbrechen", "cancel": "Abbrechen",
"receive": "Empfangen" "receive": "Empfangen",
"import": "Importieren",
"export": "Exportieren"
}, },
"playlist": { "playlist": {
"local": "Lokale Wiedergabelisten", "local": "Lokale Wiedergabelisten",
@ -49,8 +51,12 @@
"light": "Hell", "light": "Hell",
"blur": "Unschärfe", "blur": "Unschärfe",
"blur_light": "Unschärfe (hell)", "blur_light": "Unschärfe (hell)",
"dracula": "Dracula", "dracula": "Drakula",
"nord": "Nord" "nord": "Nord",
"library": "Bibliothek",
"charts": "Diagramme",
"explore": "Erkunden",
"home": "Startseite"
}, },
"info": { "info": {
"no_info": "Keine Informationen verfügbar", "no_info": "Keine Informationen verfügbar",

View file

@ -23,7 +23,9 @@
"create": "Create", "create": "Create",
"cancel": "Cancel", "cancel": "Cancel",
"send": "Send", "send": "Send",
"receive": "Receive" "receive": "Receive",
"import": "Import",
"export": "Export"
}, },
"playlist": { "playlist": {
"local": "Local Playlists", "local": "Local Playlists",
@ -50,7 +52,11 @@
"auto": "auto", "auto": "auto",
"best": "best", "best": "best",
"worst": "worst", "worst": "worst",
"volume": "Default Volume" "volume": "Default Volume",
"home": "Home",
"explore": "Explore",
"charts": "Charts",
"library": "Library"
}, },
"info": { "info": {
"see_all": "See All", "see_all": "See All",

View file

@ -23,7 +23,9 @@
"create": "Crear", "create": "Crear",
"send": "Enviar", "send": "Enviar",
"receive": "Recibir", "receive": "Recibir",
"cancel": "Cancelar" "cancel": "Cancelar",
"import": "Importar",
"export": "Exportar"
}, },
"playlist": { "playlist": {
"local": "Listas de reproducción locales", "local": "Listas de reproducción locales",
@ -50,7 +52,11 @@
"light": "Claro", "light": "Claro",
"blur_light": "Desenfoque (Luz)", "blur_light": "Desenfoque (Luz)",
"dracula": "Drácula", "dracula": "Drácula",
"nord": "Nord" "nord": "Nord",
"home": "Inicio",
"library": "Biblioteca",
"charts": "Gráfica",
"explore": "Explorar"
}, },
"info": { "info": {
"see_all": "Ver todo", "see_all": "Ver todo",

View file

@ -42,7 +42,11 @@
"blur": "Flou", "blur": "Flou",
"blur_light": "Flou (clair)", "blur_light": "Flou (clair)",
"dracula": "Dracula", "dracula": "Dracula",
"nord": "Nord" "nord": "Nord",
"charts": "Graphiques",
"explore": "Explorer",
"home": "Accueil",
"library": "Bibliothèque"
}, },
"info": { "info": {
"see_all": "Voir tout", "see_all": "Voir tout",
@ -55,7 +59,9 @@
"add": "Ajouter", "add": "Ajouter",
"create": "Créer", "create": "Créer",
"cancel": "Annuler", "cancel": "Annuler",
"receive": "Recevoir" "receive": "Recevoir",
"import": "Importer",
"export": "Exporter"
}, },
"instances": { "instances": {
"up_to_date": "À jour", "up_to_date": "À jour",

View file

@ -15,7 +15,11 @@
"blur": "Sfocatura", "blur": "Sfocatura",
"blur_light": "Sfocatura (chiaro)", "blur_light": "Sfocatura (chiaro)",
"dracula": "Dracula", "dracula": "Dracula",
"nord": "Nord" "nord": "Nord",
"library": "Raccolta",
"home": "Pagina principale",
"charts": "Grafici",
"explore": "Esplora"
}, },
"title": { "title": {
"albums": "Album", "albums": "Album",
@ -40,7 +44,9 @@
"back": "Indietro", "back": "Indietro",
"create": "Crea", "create": "Crea",
"send": "Invia", "send": "Invia",
"cancel": "Annulla" "cancel": "Annulla",
"import": "Importa",
"export": "Esporta"
}, },
"info": { "info": {
"see_all": "Vedi tutto", "see_all": "Vedi tutto",

View file

@ -23,7 +23,9 @@
"create": "Oluştur", "create": "Oluştur",
"cancel": "İptal", "cancel": "İptal",
"receive": "Al", "receive": "Al",
"send": "Gönder" "send": "Gönder",
"export": "Dışa aktar",
"import": "İçe aktar"
}, },
"playlist": { "playlist": {
"local": "Yerel Oynatma Listeleri", "local": "Yerel Oynatma Listeleri",
@ -50,7 +52,11 @@
"blur": "Bulanıklaştır", "blur": "Bulanıklaştır",
"blur_light": "Bulanıklaştır (Açık)", "blur_light": "Bulanıklaştır (Açık)",
"dracula": "Dracula", "dracula": "Dracula",
"nord": "Nord" "nord": "Nord",
"charts": "Grafikler",
"library": "Kütüphane",
"explore": "Keşfet",
"home": "Ana sayfa"
}, },
"info": { "info": {
"see_all": "Hepsini Gör", "see_all": "Hepsini Gör",

View file

@ -30,7 +30,10 @@
"nord": "Nord", "nord": "Nord",
"dracula": "Dracula", "dracula": "Dracula",
"auto_queue": "Tự động xếp hàng các bài hát", "auto_queue": "Tự động xếp hàng các bài hát",
"tab": "Thẻ mặc định" "tab": "Thẻ mặc định",
"library": "Thư viện",
"explore": "Khám phá",
"home": "Trang chủ"
}, },
"action": { "action": {
"cancel": "Hủy", "cancel": "Hủy",