PLAYER: Added Jam feature

This commit is contained in:
2026-05-28 23:38:07 +03:00
parent d1113effa5
commit ec7c5c9049
6 changed files with 83 additions and 18 deletions
+1 -1
View File
@@ -472,7 +472,7 @@
</label>
<label class="upload-field upload-field-wide"><span>Notes</span><textarea rows="4" x-model="$store.torrents.uploadReviewDraft.notes"></textarea></label>
<div class="upload-editor-actions">
<button class="modal-btn modal-btn-ghost" @click="$store.torrents.saveUploadReview()" :disabled="$store.torrents.uploadReviewSavingId === $store.torrents.uploadReviewEditId">Save draft</button>
<button class="modal-btn modal-btn-danger" @click="$store.torrents.deleteUploadReview()" :disabled="$store.torrents.uploadReviewSavingId === $store.torrents.uploadReviewEditId">Delete review</button>
<button class="modal-btn modal-btn-primary" @click="$store.torrents.approveUploadReview()" :disabled="$store.torrents.uploadReviewSavingId === $store.torrents.uploadReviewEditId">Approve</button>
</div>
</div>
+20 -9
View File
@@ -411,6 +411,7 @@ document.addEventListener('alpine:init', () => {
duration: 0,
volume: 0.7,
_prevVolume: 0.7,
_volumeCurve: 2.4,
shuffle: false,
repeatMode: 'off', // off, all, one
progress: 0,
@@ -662,10 +663,21 @@ document.addEventListener('alpine:init', () => {
audio.volume = this.volume;
},
volumeSliderPercent() {
if (this.volume <= 0) return 0;
return Math.pow(this.volume, 1 / this._volumeCurve) * 100;
},
_volumeFromSliderPosition(position) {
const pct = Math.max(0, Math.min(1, Number(position || 0)));
if (pct <= 0.002) return 0;
return Math.pow(pct, this._volumeCurve);
},
_setVolumeFromClientX(clientX, bar) {
const rect = bar.getBoundingClientRect();
const pct = rect.width > 0 ? (clientX - rect.left) / rect.width : 0;
this.setVolume(pct);
this.setVolume(this._volumeFromSliderPosition(pct));
},
setVolumeFromClick(event) {
@@ -2706,20 +2718,19 @@ document.addEventListener('alpine:init', () => {
this.uploadReviewDraft = null;
},
async saveUploadReview() {
if (!this.uploadReviewEditId || !this.uploadReviewDraft) return;
async deleteUploadReview() {
if (!this.uploadReviewEditId) return;
const id = this.uploadReviewEditId;
this.uploadReviewSavingId = id;
try {
const res = await fetch(`/api/player/uploads/reviews/${id}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(this.uploadReviewPayload()),
method: 'DELETE',
});
const data = await res.json();
if (!res.ok) throw new Error(data.error || 'Failed to save review');
this.uploadPending = this.uploadPending.map(item => item.id === id ? data : item);
this._setMessage('Pending metadata saved');
if (!res.ok) throw new Error(data.error || 'Failed to delete review');
this.applyUploadPage(data);
this.cancelUploadReviewEdit();
this._setMessage('Review deleted');
} catch (err) {
this._setMessage(err.message || String(err), true);
} finally {
+1 -1
View File
@@ -1050,7 +1050,7 @@
<div class="volume-slider"
@pointerdown.prevent="$store.player.startVolumeDrag($event)"
aria-label="{{ t.player_volume }}">
<div class="volume-slider-fill" :style="'width:' + ($store.player.volume * 100) + '%'">
<div class="volume-slider-fill" :style="'width:' + $store.player.volumeSliderPercent() + '%'">
<div class="volume-slider-thumb"></div>
</div>
</div>
+5 -5
View File
@@ -1287,7 +1287,7 @@ button.user-stat:hover {
.volume-btn svg { width: 18px; height: 18px; }
.volume-slider {
width: 80px;
width: 104px;
height: 4px;
background: var(--bg-active);
border-radius: 2px;
@@ -2920,13 +2920,13 @@ button.user-stat:hover {
z-index: 140;
display: flex;
align-items: center;
justify-content: flex-end;
justify-content: center;
padding: 40px;
background: rgba(0,0,0,0.32);
}
.upload-editor-drawer {
width: min(460px, calc(100vw - 48px));
width: min(680px, calc(100vw - 48px));
max-height: calc(100vh - 80px);
overflow-y: auto;
border: 1px solid var(--border-color);
@@ -3662,7 +3662,7 @@ button.user-stat:hover {
}
.volume-slider {
width: 74px;
width: 88px;
height: 6px;
border-radius: 999px;
}
@@ -4142,7 +4142,7 @@ button.user-stat:hover {
}
.volume-slider {
width: 58px;
width: 72px;
}
.player-btn {