settings: unify transcode param styling and controls
- Style QP <input type=number> like the <select>s (it rendered with the
default white background -> stood out); add a disabled (greyed) style.
- QP vs bitrate are now mutually DISABLED instead of hidden: QP mode
greys the bitrate field, VBR/CBR greys the QP field. Hiding never
worked because .tr-row label{display:flex} overrode [hidden].
- Replace SOFT/MEDIUM/HARD preset buttons with a "Готовый профиль"
dropdown, placed last (rightmost) in the params row.
VERSION -> 0.0.120.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+23
-27
@@ -1452,20 +1452,20 @@ const Settings = {
|
|||||||
trRowHtml(pr) { // ряд параметров одного профиля
|
trRowHtml(pr) { // ряд параметров одного профиля
|
||||||
const sel = (f, opts) => `<select data-f="${f}">` + opts.map(([v, t]) =>
|
const sel = (f, opts) => `<select data-f="${f}">` + opts.map(([v, t]) =>
|
||||||
`<option value="${v}"${String(pr[f]) === String(v) ? " selected" : ""}>${t}</option>`).join("") + `</select>`;
|
`<option value="${v}"${String(pr[f]) === String(v) ? " selected" : ""}>${t}</option>`).join("") + `</select>`;
|
||||||
const active = matchPreset(pr);
|
// «Готовый профиль» SOFT/MEDIUM/HARD — выпадающее меню; выставляет все параметры разом
|
||||||
const presets = `<div class="tr-presets"><span class="muted">Пресет:</span>` +
|
const qmatch = matchPreset(pr);
|
||||||
Object.keys(TR_PRESETS).map((k) =>
|
const qpresetSel = `<select class="qpreset">` +
|
||||||
`<button type="button" class="tr-preset${k === active ? " active" : ""}" data-preset="${k}">${k}</button>`).join("") +
|
[["", "— свой —"]].concat(Object.keys(TR_PRESETS).map((k) => [k, k])).map(([v, t]) =>
|
||||||
`</div>`;
|
`<option value="${v}"${v === qmatch ? " selected" : ""}>${t}</option>`).join("") + `</select>`;
|
||||||
return (
|
return (
|
||||||
presets +
|
|
||||||
`<label>Кодек${sel("codec", [["h264", "H.264"], ["vp9", "VP9"]])}</label>` +
|
`<label>Кодек${sel("codec", [["h264", "H.264"], ["vp9", "VP9"]])}</label>` +
|
||||||
`<label>Профиль H.264${sel("profile", [["baseline", "baseline"], ["main", "main"], ["high", "high"]])}</label>` +
|
`<label>Профиль H.264${sel("profile", [["baseline", "baseline"], ["main", "main"], ["high", "high"]])}</label>` +
|
||||||
`<label>Контроль битрейта${sel("rc", [["vbr", "VBR (переменный)"], ["cbr", "CBR (постоянный)"], ["qp", "QP (постоянный)"]])}</label>` +
|
`<label>Контроль битрейта${sel("rc", [["vbr", "VBR (переменный)"], ["cbr", "CBR (постоянный)"], ["qp", "QP (постоянный)"]])}</label>` +
|
||||||
`<label>Битрейт${sel("bitrate", [["500k", "0,5 Мбит/с"], ["1000k", "1 Мбит/с"], ["2000k", "2 Мбит/с"], ["4000k", "4 Мбит/с"], ["8000k", "8 Мбит/с"], ["10000k", "10 Мбит/с"], ["16000k", "16 Мбит/с"], ["20000k", "20 Мбит/с"], ["24000k", "24 Мбит/с"]])}</label>` +
|
`<label>Битрейт${sel("bitrate", [["500k", "0,5 Мбит/с"], ["1000k", "1 Мбит/с"], ["2000k", "2 Мбит/с"], ["4000k", "4 Мбит/с"], ["8000k", "8 Мбит/с"], ["10000k", "10 Мбит/с"], ["16000k", "16 Мбит/с"], ["20000k", "20 Мбит/с"], ["24000k", "24 Мбит/с"]])}</label>` +
|
||||||
`<label>QP (квантизатор)<input type="number" data-f="qp" min="0" max="51" value="${pr.qp}" style="width:72px"></label>` +
|
`<label>QP (квантизатор)<input type="number" data-f="qp" min="0" max="51" value="${pr.qp}"></label>` +
|
||||||
`<label>Интервал ключевых кадров${sel("keyint", [[1, "1 секунда"], [2, "2 секунды"], [5, "5 секунд"]])}</label>` +
|
`<label>Интервал ключевых кадров${sel("keyint", [[1, "1 секунда"], [2, "2 секунды"], [5, "5 секунд"]])}</label>` +
|
||||||
`<label>Пресет (Preset)${sel("preset", [["ultrafast", "Ultrafast"], ["superfast", "Superfast"], ["veryfast", "Veryfast"], ["faster", "Faster"], ["fast", "Fast"], ["medium", "Medium"]])}</label>`
|
`<label>Пресет (Preset)${sel("preset", [["ultrafast", "Ultrafast"], ["superfast", "Superfast"], ["veryfast", "Veryfast"], ["faster", "Faster"], ["fast", "Fast"], ["medium", "Medium"]])}</label>` +
|
||||||
|
`<label>Готовый профиль${qpresetSel}</label>`
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -1493,32 +1493,28 @@ const Settings = {
|
|||||||
const codec = row.querySelector('[data-f="codec"]');
|
const codec = row.querySelector('[data-f="codec"]');
|
||||||
const prof = row.querySelector('[data-f="profile"]');
|
const prof = row.querySelector('[data-f="profile"]');
|
||||||
const syncCodec = () => { prof.disabled = codec.value === "vp9"; };
|
const syncCodec = () => { prof.disabled = codec.value === "vp9"; };
|
||||||
syncCodec();
|
// QP ↔ битрейт: активен только параметр выбранного режима, второй — неактивен
|
||||||
// режим контроля битрейта: VBR/CBR → поле «Битрейт», QP → поле «QP»
|
|
||||||
const rcSel = row.querySelector('[data-f="rc"]');
|
const rcSel = row.querySelector('[data-f="rc"]');
|
||||||
const brLabel = row.querySelector('[data-f="bitrate"]').closest("label");
|
const brSel = row.querySelector('[data-f="bitrate"]');
|
||||||
const qpLabel = row.querySelector('[data-f="qp"]').closest("label");
|
const qpInp = row.querySelector('[data-f="qp"]');
|
||||||
const syncRc = () => { const isQp = rcSel.value === "qp"; qpLabel.hidden = !isQp; brLabel.hidden = isQp; };
|
const syncRc = () => { const isQp = rcSel.value === "qp"; brSel.disabled = isQp; qpInp.disabled = !isQp; };
|
||||||
syncRc();
|
// «Готовый профиль» (SOFT/MEDIUM/HARD): меню показывает совпадение или «— свой —»
|
||||||
// подсветить пресет, совпадающий с текущими значениями
|
const qpreset = row.querySelector(".qpreset");
|
||||||
const highlight = () => {
|
const syncQuality = () => {
|
||||||
const cur = { codec: codec.value, profile: prof.value, bitrate: row.querySelector('[data-f="bitrate"]').value,
|
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 };
|
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));
|
|
||||||
};
|
};
|
||||||
// общий пресет — выставить все параметры разом
|
qpreset.onchange = () => {
|
||||||
row.querySelectorAll(".tr-preset").forEach((btn) => {
|
const p = TR_PRESETS[qpreset.value];
|
||||||
btn.onclick = () => {
|
if (!p) return;
|
||||||
const p = TR_PRESETS[btn.dataset.preset];
|
|
||||||
const put = (f, v) => { const s = row.querySelector(`[data-f="${f}"]`); if (s) s.value = String(v); };
|
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("codec", p.codec); put("profile", p.profile); put("bitrate", p.bitrate);
|
||||||
put("keyint", p.keyint); put("preset", p.preset); put("rc", "vbr");
|
put("keyint", p.keyint); put("preset", p.preset); put("rc", "vbr");
|
||||||
syncCodec(); syncRc(); highlight();
|
syncCodec(); syncRc();
|
||||||
};
|
};
|
||||||
});
|
syncCodec(); syncRc();
|
||||||
row.querySelectorAll("select[data-f]").forEach((s) => {
|
row.querySelectorAll("select[data-f]").forEach((s) => {
|
||||||
s.addEventListener("change", () => { syncCodec(); syncRc(); highlight(); });
|
s.addEventListener("change", () => { syncCodec(); syncRc(); syncQuality(); });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
document.getElementById("prefs-save").onclick = () => {
|
document.getElementById("prefs-save").onclick = () => {
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ input[type="checkbox"]:checked {
|
|||||||
}
|
}
|
||||||
input[type="checkbox"]:checked::before { transform: translateX(18px); background: var(--ok); }
|
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="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);
|
background: var(--panel-2); color: var(--text); border: 1px solid var(--border);
|
||||||
padding: 6px 8px; border-radius: 6px;
|
padding: 6px 8px; border-radius: 6px;
|
||||||
}
|
}
|
||||||
@@ -340,6 +340,8 @@ input[type="date"], select {
|
|||||||
.tr-row[hidden] { display: none; }
|
.tr-row[hidden] { display: none; }
|
||||||
.tr-row label { display: flex; flex-direction: column; gap: 5px; font-size: 12px; color: var(--text-dim); }
|
.tr-row label { display: flex; flex-direction: column; gap: 5px; font-size: 12px; color: var(--text-dim); }
|
||||||
.tr-row select { display: block; }
|
.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) */
|
/* общие пресеты перекодирования (SOFT / MEDIUM / HARD) */
|
||||||
.tr-presets { flex-basis: 100%; display: flex; align-items: center; gap: 8px; padding-left: 28px; }
|
.tr-presets { flex-basis: 100%; display: flex; align-items: center; gap: 8px; padding-left: 28px; }
|
||||||
.tr-preset {
|
.tr-preset {
|
||||||
|
|||||||
Reference in New Issue
Block a user