diff --git a/VERSION b/VERSION index 42e3846..2f29dcd 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.0.119 +0.0.120 diff --git a/frontend/static/app.js b/frontend/static/app.js index 1e902e0..c7e9b51 100644 --- a/frontend/static/app.js +++ b/frontend/static/app.js @@ -1452,20 +1452,20 @@ const Settings = { trRowHtml(pr) { // ряд параметров одного профиля const sel = (f, opts) => ``; - const active = matchPreset(pr); - const presets = `
Пресет:` + - Object.keys(TR_PRESETS).map((k) => - ``).join("") + - `
`; + // «Готовый профиль» SOFT/MEDIUM/HARD — выпадающее меню; выставляет все параметры разом + const qmatch = matchPreset(pr); + const qpresetSel = ``; return ( - presets + `` + `` + `` + `` + - `` + + `` + `` + - `` + `` + + `` ); }, @@ -1493,32 +1493,28 @@ const Settings = { const codec = row.querySelector('[data-f="codec"]'); const prof = row.querySelector('[data-f="profile"]'); const syncCodec = () => { prof.disabled = codec.value === "vp9"; }; - syncCodec(); - // режим контроля битрейта: VBR/CBR → поле «Битрейт», QP → поле «QP» + // QP ↔ битрейт: активен только параметр выбранного режима, второй — неактивен const rcSel = row.querySelector('[data-f="rc"]'); - const brLabel = row.querySelector('[data-f="bitrate"]').closest("label"); - const qpLabel = row.querySelector('[data-f="qp"]').closest("label"); - const syncRc = () => { const isQp = rcSel.value === "qp"; qpLabel.hidden = !isQp; brLabel.hidden = isQp; }; - syncRc(); - // подсветить пресет, совпадающий с текущими значениями - const highlight = () => { - const cur = { codec: codec.value, profile: prof.value, bitrate: row.querySelector('[data-f="bitrate"]').value, - keyint: row.querySelector('[data-f="keyint"]').value, preset: row.querySelector('[data-f="preset"]').value }; - const name = matchPreset(cur); - row.querySelectorAll(".tr-preset").forEach((b) => b.classList.toggle("active", b.dataset.preset === name)); + const brSel = row.querySelector('[data-f="bitrate"]'); + const qpInp = row.querySelector('[data-f="qp"]'); + const syncRc = () => { const isQp = rcSel.value === "qp"; brSel.disabled = isQp; qpInp.disabled = !isQp; }; + // «Готовый профиль» (SOFT/MEDIUM/HARD): меню показывает совпадение или «— свой —» + const qpreset = row.querySelector(".qpreset"); + const syncQuality = () => { + qpreset.value = matchPreset({ codec: codec.value, profile: prof.value, bitrate: brSel.value, + keyint: row.querySelector('[data-f="keyint"]').value, preset: row.querySelector('[data-f="preset"]').value }); }; - // общий пресет — выставить все параметры разом - row.querySelectorAll(".tr-preset").forEach((btn) => { - btn.onclick = () => { - const p = TR_PRESETS[btn.dataset.preset]; - const put = (f, v) => { const s = row.querySelector(`[data-f="${f}"]`); if (s) s.value = String(v); }; - put("codec", p.codec); put("profile", p.profile); put("bitrate", p.bitrate); - put("keyint", p.keyint); put("preset", p.preset); put("rc", "vbr"); - syncCodec(); syncRc(); highlight(); - }; - }); + qpreset.onchange = () => { + const p = TR_PRESETS[qpreset.value]; + if (!p) return; + const put = (f, v) => { const s = row.querySelector(`[data-f="${f}"]`); if (s) s.value = String(v); }; + put("codec", p.codec); put("profile", p.profile); put("bitrate", p.bitrate); + put("keyint", p.keyint); put("preset", p.preset); put("rc", "vbr"); + syncCodec(); syncRc(); + }; + syncCodec(); syncRc(); row.querySelectorAll("select[data-f]").forEach((s) => { - s.addEventListener("change", () => { syncCodec(); syncRc(); highlight(); }); + s.addEventListener("change", () => { syncCodec(); syncRc(); syncQuality(); }); }); }); document.getElementById("prefs-save").onclick = () => { diff --git a/frontend/static/style.css b/frontend/static/style.css index 2de19f9..520ef85 100644 --- a/frontend/static/style.css +++ b/frontend/static/style.css @@ -147,7 +147,7 @@ input[type="checkbox"]:checked { } input[type="checkbox"]:checked::before { transform: translateX(18px); background: var(--ok); } input[type="checkbox"]:focus-visible { outline: 2px solid var(--ok); outline-offset: 2px; } -input[type="date"], select { +input[type="date"], input[type="number"], select { background: var(--panel-2); color: var(--text); border: 1px solid var(--border); padding: 6px 8px; border-radius: 6px; } @@ -340,6 +340,8 @@ input[type="date"], select { .tr-row[hidden] { display: none; } .tr-row label { display: flex; flex-direction: column; gap: 5px; font-size: 12px; color: var(--text-dim); } .tr-row select { display: block; } +.tr-row input[type="number"] { display: block; width: 80px; } +.tr-row select:disabled, .tr-row input:disabled { opacity: .4; cursor: not-allowed; } /* общие пресеты перекодирования (SOFT / MEDIUM / HARD) */ .tr-presets { flex-basis: 100%; display: flex; align-items: center; gap: 8px; padding-left: 28px; } .tr-preset {