feat(autodj): configurable overlap cap (auto or 2–30 s) (#1173)

This commit is contained in:
cucadmuh
2026-06-24 22:00:35 +03:00
committed by GitHub
parent c3e6be537c
commit 58e6efc68c
29 changed files with 250 additions and 17 deletions
@@ -2,6 +2,10 @@ import React from 'react';
import type { TFunction } from 'i18next';
import { useAuthStore } from '../../../store/authStore';
import { useOrbitStore } from '../../../store/orbitStore';
import {
AUTODJ_OVERLAP_CAP_MAX_SEC,
AUTODJ_OVERLAP_CAP_MIN_SEC,
} from '../../../utils/playback/autodjOverlapCap';
import {
getTransitionMode,
setTransitionMode,
@@ -21,8 +25,7 @@ interface Props {
* transition-mode helper.
*
* Classic crossfade exposes the seconds slider; AutoDJ is content-driven and
* has no duration to configure (just a short explainer + the smooth-skip
* toggle).
* exposes an optional overlap cap (auto vs manual limit).
*
* Rendered as its own top-level "Track transitions" category in the Audio tab,
* so the boxed `SettingsGroup` is title-less — the `SettingsSubSection` header
@@ -89,6 +92,50 @@ export function TrackTransitionsBlock({ t }: Props) {
<div style={{ paddingLeft: '1rem', fontSize: 12, color: 'var(--text-muted)', marginTop: '0.7rem' }}>
{t('settings.autoDjDesc')}
</div>
<div style={{ paddingLeft: '1rem', marginTop: '0.9rem' }}>
<p className="settings-row-label" style={{ marginBottom: '0.45rem' }}>
{t('settings.autodjOverlapCapTitle')}
</p>
<p className="settings-row-desc" style={{ marginBottom: '0.6rem' }}>
{t('settings.autodjOverlapCapDesc')}
</p>
<div className="settings-segmented" style={{ marginBottom: auth.autodjOverlapCapMode === 'limit' ? '0.65rem' : 0 }}>
<button
type="button"
className={`btn ${auth.autodjOverlapCapMode === 'auto' ? 'btn-primary' : 'btn-ghost'}`}
disabled={hostControlled}
onClick={() => auth.setAutodjOverlapCapMode('auto')}
>
{t('settings.autodjOverlapCapAuto')}
</button>
<button
type="button"
className={`btn ${auth.autodjOverlapCapMode === 'limit' ? 'btn-primary' : 'btn-ghost'}`}
disabled={hostControlled}
onClick={() => auth.setAutodjOverlapCapMode('limit')}
>
{t('settings.autodjOverlapCapLimit')}
</button>
</div>
{auth.autodjOverlapCapMode === 'limit' && (
<div style={{ display: 'flex', alignItems: 'center', gap: '0.75rem', flexWrap: 'wrap' }}>
<input
type="range"
min={AUTODJ_OVERLAP_CAP_MIN_SEC}
max={AUTODJ_OVERLAP_CAP_MAX_SEC}
step={1}
value={auth.autodjOverlapCapSec}
disabled={hostControlled}
onChange={e => auth.setAutodjOverlapCapSec(parseInt(e.target.value, 10))}
style={{ flex: 1, minWidth: 80, maxWidth: 200 }}
id="autodj-overlap-cap-slider"
/>
<span style={{ fontSize: 13, color: 'var(--text-secondary)', minWidth: 48 }}>
{t('settings.autodjOverlapCapSecs', { n: auth.autodjOverlapCapSec })}
</span>
</div>
)}
</div>
<div style={{ paddingLeft: '1rem', marginTop: '0.7rem' }}>
<SettingsToggle
label={t('settings.autodjSmoothSkip')}