Update metadata jobs and player library
This commit is contained in:
@@ -2025,23 +2025,26 @@ document.addEventListener('alpine:init', () => {
|
||||
this._artistsLoadToken = token;
|
||||
try {
|
||||
const mine = filter === 'uploads' ? '&mine=true' : '';
|
||||
const res = await fetch(`/api/player/artists?page=${page}&limit=60${mine}`);
|
||||
const res = await fetch(`/api/player/artists?page=${page}&limit=80${mine}`);
|
||||
if (!res.ok) throw new Error('failed');
|
||||
const data = await res.json();
|
||||
if (token !== this._artistsLoadToken || filter !== this.artistFilter) return;
|
||||
const incoming = Array.isArray(data.items) ? data.items : [];
|
||||
if (page === 1) {
|
||||
this.artists = data.items;
|
||||
this.artists = incoming;
|
||||
} else {
|
||||
this.artists = [...this.artists, ...data.items];
|
||||
const existing = new Set(this.artists.map(artist => artist.id));
|
||||
this.artists = [...this.artists, ...incoming.filter(artist => !existing.has(artist.id))];
|
||||
}
|
||||
this.artistsPage = data.page;
|
||||
this.artistsTotal = data.total;
|
||||
if (this.artists.length >= data.total) {
|
||||
if (data.has_more === false || this.artists.length >= data.total) {
|
||||
this._allLoaded = true;
|
||||
}
|
||||
} catch {}
|
||||
if (token === this._artistsLoadToken) {
|
||||
this.loading = false;
|
||||
this.$nextTick(() => { this._fillArtistViewport(); });
|
||||
}
|
||||
},
|
||||
|
||||
@@ -2400,11 +2403,21 @@ document.addEventListener('alpine:init', () => {
|
||||
if (entries[0].isIntersecting && !this.loading && !this._allLoaded) {
|
||||
this.loadArtists(this.artistsPage + 1);
|
||||
}
|
||||
}, { root: document.getElementById('center-scroll'), threshold: 0.1 });
|
||||
}, { root: document.getElementById('center-scroll'), rootMargin: '900px 0px', threshold: 0.01 });
|
||||
this._observer.observe(sentinel);
|
||||
this._fillArtistViewport();
|
||||
});
|
||||
},
|
||||
|
||||
_fillArtistViewport() {
|
||||
if (!(this.view === 'artists' || this.view === 'my_uploads') || this.loading || this._allLoaded) return;
|
||||
const el = this._scrollElement();
|
||||
if (!el) return;
|
||||
if (el.scrollHeight <= el.clientHeight + 900) {
|
||||
this.loadArtists(this.artistsPage + 1);
|
||||
}
|
||||
},
|
||||
|
||||
$nextTick(fn) {
|
||||
setTimeout(fn, 50);
|
||||
},
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
:class="{ active: $store.library.view === 'artists' }"
|
||||
@click="$store.library.goArtists()">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="8" r="4"/><path d="M20 21a8 8 0 10-16 0"/></svg>
|
||||
{{ t.player_artists }}
|
||||
{{ t.player_global_library }}
|
||||
</div>
|
||||
<div class="sidebar-nav-item"
|
||||
:class="{ active: $store.library.view === 'my_uploads' }"
|
||||
@@ -174,7 +174,7 @@
|
||||
:class="{ active: $store.library.view === 'artists' }"
|
||||
@click="$store.library.goArtists(); $store.mobile.closeLibrary()">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="8" r="4"/><path d="M20 21a8 8 0 10-16 0"/></svg>
|
||||
{{ t.player_artists }}
|
||||
{{ t.player_global_library }}
|
||||
</div>
|
||||
<div class="sidebar-nav-item"
|
||||
:class="{ active: $store.library.view === 'my_uploads' }"
|
||||
@@ -521,7 +521,7 @@
|
||||
<!-- Artists Grid -->
|
||||
<template x-if="$store.library.view === 'artists' || $store.library.view === 'my_uploads'">
|
||||
<div>
|
||||
<h1 class="section-title" x-text="$store.library.view === 'my_uploads' ? '{{ t.player_my_uploads }}' : '{{ t.player_artists }}'"></h1>
|
||||
<h1 class="section-title" x-text="$store.library.view === 'my_uploads' ? '{{ t.player_my_uploads }}' : '{{ t.player_global_library }}'"></h1>
|
||||
<div class="card-grid">
|
||||
<template x-for="artist in $store.library.artists" :key="artist.id">
|
||||
<div class="card" @click="$store.library.openArtist(artist.id)">
|
||||
@@ -554,9 +554,17 @@
|
||||
<p x-text="$store.library.view === 'my_uploads' ? '{{ t.player_no_uploaded_tracks }}' : '{{ t.artists_empty }}'"></p>
|
||||
</div>
|
||||
</template>
|
||||
<template x-if="$store.library.loading">
|
||||
<template x-if="$store.library.loading && $store.library.artists.length === 0">
|
||||
<div class="loading-spinner"><div class="spinner"></div></div>
|
||||
</template>
|
||||
<div class="scroll-load-indicator"
|
||||
x-show="$store.library.loading && $store.library.artists.length > 0"
|
||||
x-cloak
|
||||
role="status"
|
||||
aria-live="polite">
|
||||
<div class="scroll-load-spinner"></div>
|
||||
<span>{{ t.player_loading_more }}</span>
|
||||
</div>
|
||||
<div id="artist-sentinel" style="height:1px"></div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -566,7 +574,7 @@
|
||||
<div>
|
||||
<div class="breadcrumb">
|
||||
<a @click="$store.library.artistFilter === 'uploads' ? $store.library.goMyUploads() : $store.library.goArtists()"
|
||||
x-text="$store.library.artistFilter === 'uploads' ? '{{ t.player_my_uploads }}' : '{{ t.player_artists }}'"></a>
|
||||
x-text="$store.library.artistFilter === 'uploads' ? '{{ t.player_my_uploads }}' : '{{ t.player_global_library }}'"></a>
|
||||
<span>/</span>
|
||||
<span x-text="$store.library.currentArtist.name"></span>
|
||||
</div>
|
||||
@@ -727,7 +735,7 @@
|
||||
<div>
|
||||
<div class="breadcrumb">
|
||||
<a @click="$store.library.artistFilter === 'uploads' ? $store.library.goMyUploads() : $store.library.goArtists()"
|
||||
x-text="$store.library.artistFilter === 'uploads' ? '{{ t.player_my_uploads }}' : '{{ t.player_artists }}'"></a>
|
||||
x-text="$store.library.artistFilter === 'uploads' ? '{{ t.player_my_uploads }}' : '{{ t.player_global_library }}'"></a>
|
||||
<span>/</span>
|
||||
<template x-if="$store.library.currentRelease.artists.length > 0">
|
||||
<a @click="$store.library.openArtist($store.library.currentRelease.artists[0].id)" x-text="$store.library.currentRelease.artists[0].name"></a>
|
||||
|
||||
@@ -1814,6 +1814,26 @@ button.user-stat:hover {
|
||||
animation: spin 0.8s linear infinite;
|
||||
}
|
||||
|
||||
.scroll-load-indicator {
|
||||
min-height: 56px;
|
||||
margin: 18px 0 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
color: var(--text-secondary);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.scroll-load-spinner {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border: 2px solid var(--bg-active);
|
||||
border-top-color: var(--accent);
|
||||
border-radius: 50%;
|
||||
animation: spin 0.8s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin { to { transform: rotate(360deg); } }
|
||||
|
||||
/* Empty state */
|
||||
|
||||
Reference in New Issue
Block a user