- closes #146
- minor cleanup and cosmetic changes
This commit is contained in:
Shiny Nematoda 2023-11-12 14:10:20 +00:00
parent 7e88b8e73a
commit cdded78de8
10 changed files with 653 additions and 598 deletions

1025
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -14,15 +14,15 @@
"dompurify": "^3.0.6",
"mux.js": "^6.3.0",
"peerjs": "^1.5.1",
"pinia": "^2.1.6",
"pinia": "^2.1.7",
"shaka-player": "^4.5.0",
"sortablejs": "^1.15.0",
"vue": "^3.2.38"
},
"devDependencies": {
"@vitejs/plugin-vue": "^4.4.0",
"@vitejs/plugin-vue": "^4.4.1",
"prettier": "^3.0.3",
"vite": "^4.4.11",
"vite-plugin-pwa": "^0.16.5"
"vite": "^4.5.0",
"vite-plugin-pwa": "^0.16.7"
}
}

View file

@ -204,6 +204,7 @@ button {
background: transparent;
color: var(--color-text);
appearance: none;
cursor: pointer;
}
button:focus {
outline: none;
@ -398,6 +399,23 @@ img {
}
}
/* Table */
th,
td {
margin: 0.25rem 0.5rem;
padding: 0.5rem 0.75rem;
border-radius: 0.125rem;
background-color: var(--color-background-mute);
}
th {
font-weight: bolder;
}
td {
text-align: center;
max-width: 40vw;
overflow-wrap: break-word;
}
/* Animations */
.bars-wrap {
flex-shrink: 0;

View file

@ -1,3 +1,3 @@
{
"date": "2023-10-08"
"date": "2023-11-12"
}

View file

@ -488,7 +488,9 @@ onMounted(async () => {
</p>
</form>
<button v-if="auth" @click="Logout" class="logout textbox">{{ t('title.logout') }}</button>
<button v-if="auth" @click="Logout" class="logout textbox">
{{ t('title.logout') }}
</button>
</div>
</template>

View file

@ -66,7 +66,7 @@ function set(page) {
@click="set('library')"
@keydown.enter="set('library')"></span>
<span
role="button"
role="menuitem"
tabindex="0"
class="nav-ico bi bi-gear clickable"
:data-active="nav.state.page == 'prefs'"
@ -104,6 +104,9 @@ h1.bi svg {
text-align: center;
margin-left: auto;
}
[role='menuitem'] {
cursor: pointer;
}
.nav-ico {
margin: 0 0.5rem;
}

View file

@ -29,67 +29,63 @@ function audioCanPlay() {
async function Stream() {
const res = player.state,
shaka = import('shaka-player/dist/shaka-player.compiled.js');
shaka = await import('shaka-player/dist/shaka-player.compiled.js').then(
mod => mod.default,
);
const { url, mime } = await useManifest(res);
if (!window.audioPlayer) {
shaka
.then(shaka => shaka.default)
.then(shaka => {
shaka.polyfill.installAll();
shaka.polyfill.installAll();
if (shaka.Player.isBrowserSupported()) {
const audioPlayer = new shaka.Player(audio.value),
codecs = store.getItem('codec');
if (shaka.Player.isBrowserSupported()) {
const audioPlayer = new shaka.Player(audio.value),
codecs = store.getItem('codec');
audioPlayer
.getNetworkingEngine()
.registerRequestFilter((_type, req) => {
const headers = req.headers;
audioPlayer.getNetworkingEngine().registerRequestFilter((_type, req) => {
const headers = req.headers;
let url = new URL(req.uris[0]);
let url = new URL(req.uris[0]);
if (url.pathname.indexOf('/videoplayback') > -1) {
if (headers.Range) {
url.searchParams.set('range', headers.Range.split('=')[1]);
req.headers = {};
req.uris[0] = url.toString();
}
}
});
window.offline = new shaka.offline.Storage(audioPlayer);
window.offline.configure({
offline: {
progressCallback: ({ appMetadata: { title, artist } }, prog) =>
a.add(`${title} by ${artist}: ${Math.floor(prog * 100)}%`),
trackSelectionCallback: tracks => [
tracks
.sort((a, b) => a.bandwidth - b.bandwidth)
.find(i => i.type == 'variant'),
],
},
});
audioPlayer.configure({
preferredAudioCodecs: codecs ? codecs.split(':') : ['opus', 'mp4a'],
manifest: {
disableVideo: true,
},
streaming: {
segmentPrefetchLimit: 2,
},
});
window.audioPlayer = audioPlayer;
if (url.pathname.indexOf('/videoplayback') > -1) {
if (headers.Range) {
url.searchParams.set('range', headers.Range.split('=')[1]);
req.headers = {};
req.uris[0] = url.toString();
}
}
});
window.offline = new shaka.offline.Storage(audioPlayer);
window.offline.configure({
offline: {
progressCallback: ({ appMetadata: { title, artist } }, prog) =>
a.add(`${title} by ${artist}: ${Math.floor(prog * 100)}%`),
trackSelectionCallback: tracks => [
tracks
.sort((a, b) => a.bandwidth - b.bandwidth)
.find(i => i.type == 'variant'),
],
},
});
audioPlayer.configure({
preferredAudioCodecs: codecs ? codecs.split(':') : ['opus', 'mp4a'],
manifest: {
disableVideo: true,
},
streaming: {
segmentPrefetchLimit: 2,
},
});
window.audioPlayer = audioPlayer;
}
}
const quality = store.getItem('quality');
if (url) {
if (url)
window.audioPlayer
.load(url, 0, mime)
.then(() => {
@ -116,7 +112,6 @@ async function Stream() {
console.error(err);
a.add('Error: ' + err.code);
});
}
}
function destroy() {

View file

@ -46,11 +46,10 @@ const getRestoreUrl = () => {
Object.keys(window.localStorage).forEach(key => {
params.set(key, window.localStorage.getItem(key));
});
restoreUrl.value = window.location.origin + '/restore/?' + params;
params.size == 0 ||
(restoreUrl.value = window.location.origin + '/restore/?' + params);
};
getRestoreUrl();
function getBool(val) {
return 'bi ' + (val ? 'bi-check2' : 'bi-x-lg');
}
@ -61,6 +60,7 @@ function getStore(key) {
function setStore(key, value) {
store.setItem(key, value);
getRestoreUrl();
}
function getTheme() {
@ -125,6 +125,7 @@ const verifyApi = computed(() =>
);
onMounted(() => {
getRestoreUrl();
getStoreBool('next', next, true);
getStoreBool('compact', compact, false);
getStoreBool('prm', prm, false);
@ -377,8 +378,10 @@ onMounted(() => {
</table>
</div>
<h2>{{ t('title.restore_prefs') }}</h2>
<a :href="restoreUrl">{{ restoreUrl }}</a>
<template v-if="restoreUrl">
<h2>{{ t('title.restore_prefs') }}</h2>
<a :href="restoreUrl" class="restore">{{ restoreUrl }}</a>
</template>
<footer>
{{ date }}
@ -402,8 +405,18 @@ h2 {
h2,
h3,
label,
footer {
footer,
.restore {
text-align: center;
word-break: break-word;
}
.restore {
padding: 0.5rem;
margin: 1rem 0;
background: var(--color-background-mute);
border-radius: 0.25rem;
font-weight: bold;
letter-spacing: 0.05rem;
}
input[type='number'] {
width: 4.5rem;
@ -445,21 +458,6 @@ label[for^='pref-chk'] {
table {
width: 100%;
}
th,
td {
margin: 0.25rem 0.5rem;
padding: 0.5rem 0.75rem;
border-radius: 0.125rem;
background-color: var(--color-background-mute);
}
th {
font-weight: bolder;
}
td {
text-align: center;
max-width: 40vw;
overflow-wrap: break-word;
}
td.bi {
color: indianred;
font-size: 1.25rem;
@ -468,7 +466,7 @@ td.bi[data-active='true'] {
color: var(--color-foreground);
}
footer {
margin-bottom: 2rem;
margin: 1rem 0;
}
footer .bi::before {
font-size: 1.75rem;

View file

@ -4,23 +4,18 @@ import { ref, onMounted } from 'vue';
const { t } = useI18n();
const urlParamKeys = ref([]),
urlParamValues = ref([]),
const params = ref({}),
restorePrefs = () => {
for (let i = 0; i < urlParamKeys.value.length; i++) {
window.localStorage.setItem(
urlParamKeys.value[i],
urlParamValues.value[i],
);
}
for (const i in params.value)
window.localStorage.setItem(i, params.value[i]);
window.location.href = '/';
};
onMounted(() => {
const urlParams = new URLSearchParams(window.location.search);
urlParams.forEach((val, key) => {
urlParamKeys.value.push(key);
urlParamValues.value.push(val);
params.value[key] = val
});
});
</script>
@ -28,16 +23,18 @@ onMounted(() => {
<template>
<h2>{{ t('title.restore_prefs') }}</h2>
<div class="table">
<span v-for="(key, index) in urlParamKeys">
<div class="table-row">
<span>{{ key }}</span>
<hr />
<span>{{ urlParamValues[index] }}</span>
</div>
<hr />
</span>
</div>
<table>
<thead>
<th>Key</th>
<th>Value</th>
</thead>
<tbody>
<tr v-for="(val, key) in params">
<td>{{ key }}</td>
<td>{{ val }}</td>
</tr>
</tbody>
</table>
<button @click="restorePrefs" class="input">
{{ t('title.restore_prefs') }}
@ -49,25 +46,11 @@ h2 {
text-align: center;
}
.table {
display: flex;
flex-direction: column;
table {
width: 100%;
margin: 2rem 0;
}
.table-row {
display: flex;
width: 100%;
padding: 0.5rem 0;
}
.table-row > span {
td {
width: 50%;
padding-left: 0.5rem;
}
button {
cursor: pointer;
}
</style>

View file

@ -157,6 +157,7 @@ onMounted(() => {
.card {
margin: 1rem 0;
justify-content: initial;
cursor: pointer;
}
.song h4 {
overflow-wrap: anywhere;