Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,13 @@ This first version intentionally does **not** silently skip codecs or folders.
It ranks and labels items, but leaves the final decision in the manifest and
review loop.

The checked-in video defaults are intentionally operator-taste defaults, not a
near-transparent archival preset. The baseline AV1 policy targets VMAF 85 with
an 80 floor and source resolution (`max_height = 0`) so measured samples pursue
small, visually acceptable TV encodes first. Raise the VMAF targets or add a
folder override when a class needs a more conservative pass; use an explicit
scale request when downsampling is desired.

`report`, `encode`, and `validate` all surface source-vs-staged size deltas so
you can see the storage win before promotion.

Expand Down
8 changes: 4 additions & 4 deletions config/defaults.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ encoder = "libsvtav1"
pixel_format = "yuv420p10le"
preset = 4
crf_search = true
quality_metric = "auto"
target_vmaf = 95.0
quality_metric = "vmaf"
target_vmaf = 85.0
target_xpsnr = 41.0
min_target_vmaf = 93.0
min_target_vmaf = 80.0
min_target_xpsnr = 35.0
target_relax_step_vmaf = 0.5
target_relax_step_xpsnr = 1.0
Expand All @@ -41,7 +41,7 @@ max_encoded_percent = 80
default_grain = 8
grain_denoise = 0
thorough = true
max_height = 0
max_height = 1080
downsample_algorithm = "lanczos"
black_bar_handling = "off"
black_bar_detect_samples = 3
Expand Down
8 changes: 4 additions & 4 deletions config/web-smoke.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ encoder = "libsvtav1"
pixel_format = "yuv420p10le"
preset = 4
crf_search = true
quality_metric = "auto"
target_vmaf = 95.0
quality_metric = "vmaf"
target_vmaf = 85.0
target_xpsnr = 41.0
min_target_vmaf = 93.0
min_target_vmaf = 80.0
min_target_xpsnr = 35.0
target_relax_step_vmaf = 0.5
target_relax_step_xpsnr = 1.0
Expand All @@ -39,7 +39,7 @@ max_encoded_percent = 80
default_grain = 8
grain_denoise = 0
thorough = true
max_height = 0
max_height = 1080
downsample_algorithm = "lanczos"
black_bar_handling = "off"
black_bar_detect_samples = 3
Expand Down
2 changes: 1 addition & 1 deletion docs/development/browser-qa-matrix.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ that a single live machine state happens to render.
- Full route and fixture smoke:
`npm --prefix frontend run smoke:web`
- Existing live app smoke:
`npm --prefix frontend run smoke:web -- --base-url http://127.0.0.1:5555`
`npm --prefix frontend run smoke:web -- --base-url http://127.0.0.1:8777`
- Skip narrow checks only for non-UI diagnostics:
`npm --prefix frontend run smoke:web -- --skip-narrow`

Expand Down
10 changes: 10 additions & 0 deletions frontend/src/lib/api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,16 @@ export interface SettingsPayload {
libraries: SettingsLibrary[];
remote_hosts: SettingsHost[];
transcode_root: string;
video_defaults: {
quality_metric: string;
target_vmaf: string;
min_target_vmaf: string;
target_xpsnr: string;
min_target_xpsnr: string;
max_height: string;
default_grain: string;
max_encoded_percent: string;
};
encode_queue_scheduler: {
mode: string;
start_hour: number;
Expand Down
161 changes: 160 additions & 1 deletion frontend/src/lib/components/settings/SettingsEditor.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,16 @@
libraries: [],
remote_hosts: [],
transcode_root: '',
video_defaults: {
quality_metric: 'vmaf',
target_vmaf: '85',
min_target_vmaf: '80',
target_xpsnr: '41',
min_target_xpsnr: '35',
max_height: '1080',
default_grain: '8',
max_encoded_percent: '80'
},
schedule_profiles: []
};

Expand Down Expand Up @@ -113,6 +123,7 @@
const archiveCleanup = $derived(savedSettings?.archive_cleanup ?? null);
const dirty = $derived(savedSettings ? settingsDraftIsDirty(draft, savedSettings) : false);
const savedArchiveRootCopy = $derived(savedSettings?.archive_root || 'unset');
const defaultMetricCopy = $derived(metricDefaultsCopy(draft.video_defaults));
const cleanupTargetDirty = $derived(
savedSettings ? archiveCleanupTargetDirty(draft, savedSettings) : false
);
Expand Down Expand Up @@ -157,6 +168,7 @@
}
]);
const footerSignals = $derived([
{ label: 'Assistant defaults', value: defaultMetricCopy, tone: 'ready' as BadgeTone },
{
label: 'Runtime',
value: savedSettings?.runtime_settings_path ?? 'unavailable',
Expand Down Expand Up @@ -228,6 +240,19 @@
);
}

function updateVideoDefault(key: keyof SettingsPayload['video_defaults'], value: string) {
draft.video_defaults = { ...draft.video_defaults, [key]: value };
}

function metricDefaultsCopy(defaults: SettingsPayload['video_defaults']) {
const metric = defaults.quality_metric.trim().toLowerCase();
if (metric === 'xpsnr')
return `XPSNR ${defaults.target_xpsnr} / floor ${defaults.min_target_xpsnr}`;
if (metric === 'auto')
return `Auto · VMAF ${defaults.target_vmaf} · XPSNR ${defaults.target_xpsnr}`;
return `VMAF ${defaults.target_vmaf} / floor ${defaults.min_target_vmaf}`;
}

function toggleScheduleDay(
index: number,
dayKey: ScheduleDayKey,
Expand Down Expand Up @@ -397,6 +422,10 @@
<span>Storage</span>
<strong>{draft.transcode_root.trim() ? 'Set' : 'Missing'}</strong>
</a>
<a href="#settings-assistant-defaults">
<span>Assistant defaults</span>
<strong>{defaultMetricCopy}</strong>
</a>
<a href="#settings-schedules">
<span>Work windows</span>
<strong>{(configuredProfiles.length + 2).toLocaleString('en-US')}</strong>
Expand Down Expand Up @@ -537,6 +566,119 @@
</div>
</WorkstationPanel>
</div>

<div id="settings-assistant-defaults" class="settings-anchor">
<WorkstationPanel eyebrow="Assistant defaults" title="Encode defaults">
<div class="encode-defaults-grid">
<label class="stacked-field">
<span>Quality metric</span>
<select
class="field"
bind:value={draft.video_defaults.quality_metric}
onchange={(event) => updateVideoDefault('quality_metric', selectValue(event))}
>
<option value="vmaf">VMAF</option>
<option value="auto">Auto</option>
<option value="xpsnr">XPSNR</option>
</select>
</label>
<label class="stacked-field">
<span>VMAF target</span>
<input
class="field field--number"
type="number"
min="1"
max="100"
step="0.1"
value={draft.video_defaults.target_vmaf}
oninput={(event) => updateVideoDefault('target_vmaf', inputValue(event))}
/>
</label>
<label class="stacked-field">
<span>VMAF floor</span>
<input
class="field field--number"
type="number"
min="1"
max="100"
step="0.1"
value={draft.video_defaults.min_target_vmaf}
oninput={(event) => updateVideoDefault('min_target_vmaf', inputValue(event))}
/>
</label>
<label class="stacked-field">
<span>XPSNR target</span>
<input
class="field field--number"
type="number"
min="1"
max="100"
step="0.1"
value={draft.video_defaults.target_xpsnr}
oninput={(event) => updateVideoDefault('target_xpsnr', inputValue(event))}
/>
</label>
<label class="stacked-field">
<span>XPSNR floor</span>
<input
class="field field--number"
type="number"
min="1"
max="100"
step="0.1"
value={draft.video_defaults.min_target_xpsnr}
oninput={(event) => updateVideoDefault('min_target_xpsnr', inputValue(event))}
/>
</label>
<label class="stacked-field">
<span>Max height</span>
<input
class="field field--number"
type="number"
min="0"
max="4320"
step="1"
value={draft.video_defaults.max_height}
oninput={(event) => updateVideoDefault('max_height', inputValue(event))}
/>
</label>
<label class="stacked-field">
<span>Grain</span>
<input
class="field field--number"
type="number"
min="0"
max="50"
step="1"
value={draft.video_defaults.default_grain}
oninput={(event) => updateVideoDefault('default_grain', inputValue(event))}
/>
</label>
<label class="stacked-field">
<span>Safety ceiling %</span>
<input
class="field field--number"
type="number"
min="1"
max="100"
step="0.1"
value={draft.video_defaults.max_encoded_percent}
oninput={(event) =>
updateVideoDefault('max_encoded_percent', inputValue(event))}
/>
</label>
<div class="encode-defaults-readout">
<span>Resolution</span>
<strong
>{Number(draft.video_defaults.max_height) > 0
? `max ${draft.video_defaults.max_height}p`
: 'source resolution'}</strong
>
<small>Used when the assistant note does not request a resolution change.</small>
</div>
</div>
</WorkstationPanel>
</div>
</section>

<section class="settings-section" aria-labelledby="settings-advanced-title">
Expand Down Expand Up @@ -1023,6 +1165,7 @@
<span class="mf-eyebrow">Sections</span>
<a href="#settings-libraries">Libraries</a>
<a href="#settings-storage">Storage</a>
<a href="#settings-assistant-defaults">Assistant defaults</a>
<a href="#settings-schedules">Work windows</a>
<a href="#settings-workers">Workers</a>
<a href="#settings-danger">Cleanup</a>
Expand Down Expand Up @@ -1156,7 +1299,7 @@
.settings-overview {
display: grid;
gap: var(--mf-space-3);
grid-template-columns: repeat(5, minmax(0, 1fr));
grid-template-columns: repeat(6, minmax(0, 1fr));
}

.settings-overview a {
Expand Down Expand Up @@ -1393,6 +1536,7 @@
.host-grid label span,
.schedule-row__fields label span,
.storage-readout span,
.encode-defaults-readout span,
.danger-zone > div > span,
.option-label,
.rail-row span {
Expand All @@ -1410,7 +1554,20 @@
padding: var(--mf-space-5);
}

.encode-defaults-grid {
align-items: end;
display: grid;
gap: var(--mf-space-4);
grid-template-columns: minmax(150px, 1.1fr) repeat(5, minmax(88px, 0.65fr)) minmax(170px, 1.2fr);
padding: var(--mf-space-5);
}

.encode-defaults-grid .field--number {
max-width: none;
}

.storage-readout,
.encode-defaults-readout,
.danger-zone > div,
.rail-row {
display: grid;
Expand All @@ -1419,6 +1576,7 @@
}

.storage-readout strong,
.encode-defaults-readout strong,
.danger-zone strong,
.rail-row strong,
.host-editor__head strong,
Expand All @@ -1429,6 +1587,7 @@
}

.storage-readout small,
.encode-defaults-readout small,
.danger-zone small,
.rail-row small,
.option-hint,
Expand Down
Loading