mirror of
https://github.com/denizsafak/abogen.git
synced 2026-07-18 13:40:27 +02:00
feat: Enhance voice selection and settings UI with default voice option and improved layout
This commit is contained in:
+23
-1
@@ -92,6 +92,15 @@ def _build_voice_catalog() -> List[Dict[str, str]]:
|
|||||||
def _template_options() -> Dict[str, Any]:
|
def _template_options() -> Dict[str, Any]:
|
||||||
profiles = serialize_profiles()
|
profiles = serialize_profiles()
|
||||||
ordered_profiles = sorted(profiles.items())
|
ordered_profiles = sorted(profiles.items())
|
||||||
|
profile_options = []
|
||||||
|
for name, entry in ordered_profiles:
|
||||||
|
profile_options.append(
|
||||||
|
{
|
||||||
|
"name": name,
|
||||||
|
"language": (entry or {}).get("language", ""),
|
||||||
|
"formula": _formula_from_profile(entry or {}) or "",
|
||||||
|
}
|
||||||
|
)
|
||||||
return {
|
return {
|
||||||
"languages": LANGUAGE_DESCRIPTIONS,
|
"languages": LANGUAGE_DESCRIPTIONS,
|
||||||
"voices": VOICES_INTERNAL,
|
"voices": VOICES_INTERNAL,
|
||||||
@@ -99,6 +108,7 @@ def _template_options() -> Dict[str, Any]:
|
|||||||
"supported_langs_for_subs": SUPPORTED_LANGUAGES_FOR_SUBTITLE_GENERATION,
|
"supported_langs_for_subs": SUPPORTED_LANGUAGES_FOR_SUBTITLE_GENERATION,
|
||||||
"output_formats": SUPPORTED_SOUND_FORMATS,
|
"output_formats": SUPPORTED_SOUND_FORMATS,
|
||||||
"voice_profiles": ordered_profiles,
|
"voice_profiles": ordered_profiles,
|
||||||
|
"voice_profile_options": profile_options,
|
||||||
"separate_formats": ["wav", "flac", "mp3", "opus"],
|
"separate_formats": ["wav", "flac", "mp3", "opus"],
|
||||||
"voice_catalog": _build_voice_catalog(),
|
"voice_catalog": _build_voice_catalog(),
|
||||||
"sample_voice_texts": SAMPLE_VOICE_TEXTS,
|
"sample_voice_texts": SAMPLE_VOICE_TEXTS,
|
||||||
@@ -136,6 +146,7 @@ def _settings_defaults() -> Dict[str, Any]:
|
|||||||
"output_format": "wav",
|
"output_format": "wav",
|
||||||
"subtitle_format": "srt",
|
"subtitle_format": "srt",
|
||||||
"save_mode": "default_output" if _has_output_override() else "save_next_to_input",
|
"save_mode": "default_output" if _has_output_override() else "save_next_to_input",
|
||||||
|
"default_voice": VOICES_INTERNAL[0] if VOICES_INTERNAL else "",
|
||||||
"replace_single_newlines": False,
|
"replace_single_newlines": False,
|
||||||
"use_gpu": True,
|
"use_gpu": True,
|
||||||
"save_chapters_separately": False,
|
"save_chapters_separately": False,
|
||||||
@@ -201,6 +212,10 @@ def _normalize_setting_value(key: str, value: Any, defaults: Dict[str, Any]) ->
|
|||||||
if normalized in {"wav", "flac", "mp3", "opus"}:
|
if normalized in {"wav", "flac", "mp3", "opus"}:
|
||||||
return normalized
|
return normalized
|
||||||
return defaults[key]
|
return defaults[key]
|
||||||
|
if key == "default_voice":
|
||||||
|
if isinstance(value, str) and value in VOICES_INTERNAL:
|
||||||
|
return value
|
||||||
|
return defaults[key]
|
||||||
return value if value is not None else defaults.get(key)
|
return value if value is not None else defaults.get(key)
|
||||||
|
|
||||||
|
|
||||||
@@ -339,7 +354,11 @@ def datetimeformat(value: float, fmt: str = "%Y-%m-%d %H:%M:%S") -> str:
|
|||||||
|
|
||||||
@web_bp.get("/")
|
@web_bp.get("/")
|
||||||
def index() -> str:
|
def index() -> str:
|
||||||
return render_template("index.html", options=_template_options())
|
return render_template(
|
||||||
|
"index.html",
|
||||||
|
options=_template_options(),
|
||||||
|
settings=_load_settings(),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@web_bp.get("/queue")
|
@web_bp.get("/queue")
|
||||||
@@ -367,6 +386,9 @@ def settings_page() -> Response | str:
|
|||||||
updated["save_mode"] = _normalize_setting_value(
|
updated["save_mode"] = _normalize_setting_value(
|
||||||
"save_mode", form.get("save_mode"), defaults
|
"save_mode", form.get("save_mode"), defaults
|
||||||
)
|
)
|
||||||
|
updated["default_voice"] = _normalize_setting_value(
|
||||||
|
"default_voice", form.get("default_voice"), defaults
|
||||||
|
)
|
||||||
for key in sorted(BOOLEAN_SETTINGS):
|
for key in sorted(BOOLEAN_SETTINGS):
|
||||||
updated[key] = _coerce_bool(form.get(key), False)
|
updated[key] = _coerce_bool(form.get(key), False)
|
||||||
updated["separate_chapters_format"] = _normalize_setting_value(
|
updated["separate_chapters_format"] = _normalize_setting_value(
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ const initDashboard = () => {
|
|||||||
const voiceSelect = document.querySelector('[data-role="voice-select"]');
|
const voiceSelect = document.querySelector('[data-role="voice-select"]');
|
||||||
const formulaField = document.querySelector('[data-role="formula-field"]');
|
const formulaField = document.querySelector('[data-role="formula-field"]');
|
||||||
const formulaInput = document.querySelector('[data-role="voice-formula"]');
|
const formulaInput = document.querySelector('[data-role="voice-formula"]');
|
||||||
|
const languageSelect = document.getElementById("language");
|
||||||
|
|
||||||
const sourceText = document.querySelector('[data-role="source-text"]');
|
const sourceText = document.querySelector('[data-role="source-text"]');
|
||||||
const previewEl = document.querySelector('[data-role="text-preview"]');
|
const previewEl = document.querySelector('[data-role="text-preview"]');
|
||||||
@@ -11,20 +12,45 @@ const initDashboard = () => {
|
|||||||
const charCountEl = document.querySelector('[data-role="char-count"]');
|
const charCountEl = document.querySelector('[data-role="char-count"]');
|
||||||
const wordCountEl = document.querySelector('[data-role="word-count"]');
|
const wordCountEl = document.querySelector('[data-role="word-count"]');
|
||||||
|
|
||||||
|
const hydrateDefaultVoice = () => {
|
||||||
|
if (!voiceSelect) return;
|
||||||
|
const defaultVoice = voiceSelect.dataset.default;
|
||||||
|
if (!defaultVoice) return;
|
||||||
|
const option = voiceSelect.querySelector(`option[value="${defaultVoice}"]`);
|
||||||
|
if (option) {
|
||||||
|
voiceSelect.value = defaultVoice;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const updateVoiceControls = () => {
|
const updateVoiceControls = () => {
|
||||||
if (!profileSelect) {
|
if (!profileSelect) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const value = profileSelect.value;
|
const value = profileSelect.value;
|
||||||
const showVoice = !value || value === "__standard";
|
const isStandard = !value || value === "__standard";
|
||||||
const showFormula = value === "__formula";
|
const isFormula = value === "__formula";
|
||||||
|
const isSavedProfile = Boolean(value && !isStandard && !isFormula);
|
||||||
|
|
||||||
if (voiceField) {
|
if (voiceField) {
|
||||||
voiceField.hidden = !showVoice;
|
voiceField.hidden = false;
|
||||||
voiceField.setAttribute("aria-hidden", showVoice ? "false" : "true");
|
voiceField.setAttribute("aria-hidden", "false");
|
||||||
}
|
}
|
||||||
if (voiceSelect) {
|
if (voiceSelect) {
|
||||||
voiceSelect.disabled = !showVoice;
|
voiceSelect.disabled = !isStandard;
|
||||||
|
voiceSelect.dataset.state = isStandard ? "editable" : "locked";
|
||||||
|
}
|
||||||
|
|
||||||
|
let showFormula = isFormula || isSavedProfile;
|
||||||
|
let presetFormula = "";
|
||||||
|
if (isSavedProfile) {
|
||||||
|
const option = profileSelect.selectedOptions[0];
|
||||||
|
if (option) {
|
||||||
|
presetFormula = option.dataset.formula || "";
|
||||||
|
const profileLang = option.dataset.language || "";
|
||||||
|
if (profileLang && languageSelect) {
|
||||||
|
languageSelect.value = profileLang;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (formulaField) {
|
if (formulaField) {
|
||||||
@@ -33,9 +59,15 @@ const initDashboard = () => {
|
|||||||
}
|
}
|
||||||
if (formulaInput) {
|
if (formulaInput) {
|
||||||
formulaInput.disabled = !showFormula;
|
formulaInput.disabled = !showFormula;
|
||||||
if (!showFormula) {
|
if (showFormula) {
|
||||||
|
if (presetFormula) {
|
||||||
|
formulaInput.value = presetFormula;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
formulaInput.value = formulaInput.value.trim();
|
formulaInput.value = formulaInput.value.trim();
|
||||||
}
|
}
|
||||||
|
formulaInput.dataset.state = isSavedProfile ? "locked" : "editable";
|
||||||
|
formulaInput.readOnly = isSavedProfile;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -74,6 +106,8 @@ const initDashboard = () => {
|
|||||||
updateVoiceControls();
|
updateVoiceControls();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hydrateDefaultVoice();
|
||||||
|
|
||||||
if (sourceText) {
|
if (sourceText) {
|
||||||
sourceText.addEventListener("input", updatePreview);
|
sourceText.addEventListener("input", updatePreview);
|
||||||
updatePreview();
|
updatePreview();
|
||||||
|
|||||||
+125
-14
@@ -138,6 +138,14 @@ body {
|
|||||||
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
|
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.form-grid {
|
||||||
|
align-items: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-grid > .grid {
|
||||||
|
align-items: start;
|
||||||
|
}
|
||||||
|
|
||||||
.button {
|
.button {
|
||||||
appearance: none;
|
appearance: none;
|
||||||
border: none;
|
border: none;
|
||||||
@@ -175,6 +183,20 @@ body {
|
|||||||
gap: 0.4rem;
|
gap: 0.4rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.field--full {
|
||||||
|
max-width: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field--full textarea {
|
||||||
|
min-height: 260px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field--actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
.field label {
|
.field label {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: var(--muted);
|
color: var(--muted);
|
||||||
@@ -194,6 +216,18 @@ body {
|
|||||||
transition: border 0.2s ease, box-shadow 0.2s ease;
|
transition: border 0.2s ease, box-shadow 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.field input[type="text"],
|
||||||
|
.field input[type="file"],
|
||||||
|
.field input[type="number"],
|
||||||
|
.field select {
|
||||||
|
max-width: 420px;
|
||||||
|
width: min(100%, 420px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.field input[type="number"] {
|
||||||
|
max-width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
.field input:focus,
|
.field input:focus,
|
||||||
.field select:focus,
|
.field select:focus,
|
||||||
.field textarea:focus {
|
.field textarea:focus {
|
||||||
@@ -376,19 +410,70 @@ body {
|
|||||||
border-radius: 18px;
|
border-radius: 18px;
|
||||||
padding: 1.25rem 1.4rem;
|
padding: 1.25rem 1.4rem;
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 1rem;
|
gap: 1.1rem 1.4rem;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
||||||
}
|
}
|
||||||
|
|
||||||
.settings__section legend {
|
.settings__section legend {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
padding: 0 0.5rem;
|
padding: 0 0.5rem;
|
||||||
color: var(--muted);
|
color: var(--muted);
|
||||||
|
grid-column: 1 / -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.field--inline {
|
.field--choices {
|
||||||
display: flex;
|
display: grid;
|
||||||
flex-wrap: wrap;
|
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
||||||
gap: 0.5rem;
|
gap: 0.85rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-pill {
|
||||||
|
position: relative;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.65rem;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-pill input {
|
||||||
|
position: absolute;
|
||||||
|
opacity: 0;
|
||||||
|
inset: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-pill span {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
width: 100%;
|
||||||
|
padding: 0.65rem 0.95rem;
|
||||||
|
border-radius: 16px;
|
||||||
|
border: 1px solid rgba(148, 163, 184, 0.25);
|
||||||
|
background: rgba(15, 23, 42, 0.45);
|
||||||
|
color: var(--muted);
|
||||||
|
transition: border 0.2s ease, background 0.2s ease, color 0.2s ease, box-shadow 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-pill:hover span {
|
||||||
|
border-color: var(--accent);
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-pill input:focus-visible + span {
|
||||||
|
box-shadow: 0 0 0 4px rgba(56, 189, 248, 0.18);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-pill input:checked + span {
|
||||||
|
background: rgba(56, 189, 248, 0.15);
|
||||||
|
border-color: rgba(56, 189, 248, 0.4);
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hint {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: var(--muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
.settings__actions {
|
.settings__actions {
|
||||||
@@ -600,23 +685,21 @@ progress.progress::-moz-progress-bar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.voice-editor__identity {
|
.voice-editor__identity {
|
||||||
display: flex;
|
display: grid;
|
||||||
flex-wrap: wrap;
|
grid-template-columns: minmax(0, 1fr) auto;
|
||||||
gap: 0.75rem 1rem;
|
gap: 0.75rem 1rem;
|
||||||
align-items: flex-start;
|
align-items: end;
|
||||||
}
|
}
|
||||||
|
|
||||||
.voice-editor__name-field {
|
.voice-editor__name-field {
|
||||||
flex: 1 1 220px;
|
|
||||||
min-width: 200px;
|
min-width: 200px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.voice-editor__toolbar {
|
.voice-editor__toolbar {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.5rem;
|
justify-content: flex-end;
|
||||||
flex: 0 0 auto;
|
gap: 0.65rem;
|
||||||
margin-left: auto;
|
|
||||||
min-height: 2.6rem;
|
min-height: 2.6rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1033,6 +1116,17 @@ progress.progress::-moz-progress-bar {
|
|||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[data-state="locked"] {
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
select[data-state="locked"],
|
||||||
|
input[data-state="locked"] {
|
||||||
|
background: rgba(15, 23, 42, 0.35);
|
||||||
|
color: rgba(148, 163, 184, 0.8);
|
||||||
|
border-color: rgba(148, 163, 184, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
.icon-button {
|
.icon-button {
|
||||||
appearance: none;
|
appearance: none;
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
@@ -1047,9 +1141,8 @@ progress.progress::-moz-progress-bar {
|
|||||||
transition: color 0.2s ease, border 0.2s ease, background 0.2s ease, box-shadow 0.2s ease;
|
transition: color 0.2s ease, border 0.2s ease, background 0.2s ease, box-shadow 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.voice-editor__identity > .icon-button,
|
|
||||||
.voice-editor__identity > .voice-editor__toolbar {
|
.voice-editor__identity > .voice-editor__toolbar {
|
||||||
align-self: flex-end;
|
align-self: end;
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-button svg {
|
.icon-button svg {
|
||||||
@@ -1178,6 +1271,24 @@ progress.progress::-moz-progress-bar {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (max-width: 720px) {
|
||||||
|
.voice-editor__identity {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.voice-editor__toolbar {
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings__section {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field--choices {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes spin {
|
@keyframes spin {
|
||||||
0% {
|
0% {
|
||||||
transform: rotate(0deg);
|
transform: rotate(0deg);
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
<section class="card">
|
<section class="card">
|
||||||
<h1 class="card__title">Create a new audiobook</h1>
|
<h1 class="card__title">Create a new audiobook</h1>
|
||||||
<form action="{{ url_for('web.enqueue_job') }}" method="post" enctype="multipart/form-data" class="grid grid--two">
|
<form action="{{ url_for('web.enqueue_job') }}" method="post" enctype="multipart/form-data" class="grid grid--two form-grid">
|
||||||
<div class="grid">
|
<div class="grid">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label for="source_file">Source file</label>
|
<label for="source_file">Source file</label>
|
||||||
@@ -21,9 +21,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="field" data-conditional="standard" data-role="voice-field">
|
<div class="field" data-conditional="standard" data-role="voice-field">
|
||||||
<label for="voice">Voice</label>
|
<label for="voice">Voice</label>
|
||||||
<select id="voice" name="voice" data-role="voice-select">
|
<select id="voice" name="voice" data-role="voice-select" data-default="{{ settings.default_voice }}">
|
||||||
{% for voice in options.voices %}
|
{% for voice in options.voices %}
|
||||||
<option value="{{ voice }}">{{ voice }}</option>
|
<option value="{{ voice }}" {% if settings.default_voice == voice %}selected{% endif %}>{{ voice }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
@@ -32,10 +32,10 @@
|
|||||||
<select id="voice_profile" name="voice_profile" data-role="voice-profile">
|
<select id="voice_profile" name="voice_profile" data-role="voice-profile">
|
||||||
<option value="__standard" selected>Standard voice</option>
|
<option value="__standard" selected>Standard voice</option>
|
||||||
<option value="__formula">Formula</option>
|
<option value="__formula">Formula</option>
|
||||||
{% if options.voice_profiles %}
|
{% if options.voice_profile_options %}
|
||||||
<optgroup label="Saved mixes">
|
<optgroup label="Saved mixes">
|
||||||
{% for name, data in options.voice_profiles %}
|
{% for profile in options.voice_profile_options %}
|
||||||
<option value="{{ name }}">{{ name }} ({{ data.language|upper }})</option>
|
<option value="{{ profile.name }}" data-language="{{ profile.language }}" data-formula="{{ profile.formula|e }}">{{ profile.name }} {% if profile.language %}({{ profile.language|upper }}){% endif %}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</optgroup>
|
</optgroup>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -64,7 +64,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid">
|
<div class="grid">
|
||||||
<div class="field">
|
<div class="field field--full">
|
||||||
<label for="source_text">Or paste text directly</label>
|
<label for="source_text">Or paste text directly</label>
|
||||||
<textarea id="source_text" name="source_text" rows="12" placeholder="Drop some text here if you don't have a file handy..." data-role="source-text"></textarea>
|
<textarea id="source_text" name="source_text" rows="12" placeholder="Drop some text here if you don't have a file handy..." data-role="source-text"></textarea>
|
||||||
</div>
|
</div>
|
||||||
@@ -79,7 +79,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<pre class="text-preview__body" data-role="preview-body">Paste text to see a live preview and character count.</pre>
|
<pre class="text-preview__body" data-role="preview-body">Paste text to see a live preview and character count.</pre>
|
||||||
</div>
|
</div>
|
||||||
<div class="field" style="justify-content: flex-end;">
|
<div class="field field--actions">
|
||||||
<button type="submit" class="button">Queue conversion</button>
|
<button type="submit" class="button">Queue conversion</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -30,6 +30,15 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label for="default_voice">Default voice</label>
|
||||||
|
<select id="default_voice" name="default_voice">
|
||||||
|
{% for voice in options.voices %}
|
||||||
|
<option value="{{ voice }}" {% if settings.default_voice == voice %}selected{% endif %}>{{ voice }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
<p class="hint">Used when “Standard voice” is selected on the dashboard.</p>
|
||||||
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label for="save_mode">Save location</label>
|
<label for="save_mode">Save location</label>
|
||||||
<select id="save_mode" name="save_mode">
|
<select id="save_mode" name="save_mode">
|
||||||
@@ -43,14 +52,27 @@
|
|||||||
|
|
||||||
<fieldset class="settings__section">
|
<fieldset class="settings__section">
|
||||||
<legend>Processing</legend>
|
<legend>Processing</legend>
|
||||||
<div class="field field--inline">
|
<div class="field field--choices">
|
||||||
<label class="tag"><input type="checkbox" name="replace_single_newlines" value="true" {% if settings.replace_single_newlines %}checked{% endif %}> Replace single newlines</label>
|
<label class="toggle-pill">
|
||||||
<label class="tag"><input type="checkbox" name="use_gpu" value="true" {% if settings.use_gpu %}checked{% endif %}> Use GPU (when available)</label>
|
<input type="checkbox" name="replace_single_newlines" value="true" {% if settings.replace_single_newlines %}checked{% endif %}>
|
||||||
</div>
|
<span>Replace single newlines</span>
|
||||||
<div class="field field--inline">
|
</label>
|
||||||
<label class="tag"><input type="checkbox" name="save_chapters_separately" value="true" {% if settings.save_chapters_separately %}checked{% endif %}> Save each chapter separately</label>
|
<label class="toggle-pill">
|
||||||
<label class="tag"><input type="checkbox" name="merge_chapters_at_end" value="true" {% if settings.merge_chapters_at_end %}checked{% endif %}> Also create merged audiobook</label>
|
<input type="checkbox" name="use_gpu" value="true" {% if settings.use_gpu %}checked{% endif %}>
|
||||||
<label class="tag"><input type="checkbox" name="save_as_project" value="true" {% if settings.save_as_project %}checked{% endif %}> Save as project with metadata</label>
|
<span>Use GPU (when available)</span>
|
||||||
|
</label>
|
||||||
|
<label class="toggle-pill">
|
||||||
|
<input type="checkbox" name="save_chapters_separately" value="true" {% if settings.save_chapters_separately %}checked{% endif %}>
|
||||||
|
<span>Save each chapter separately</span>
|
||||||
|
</label>
|
||||||
|
<label class="toggle-pill">
|
||||||
|
<input type="checkbox" name="merge_chapters_at_end" value="true" {% if settings.merge_chapters_at_end %}checked{% endif %}>
|
||||||
|
<span>Also create merged audiobook</span>
|
||||||
|
</label>
|
||||||
|
<label class="toggle-pill">
|
||||||
|
<input type="checkbox" name="save_as_project" value="true" {% if settings.save_as_project %}checked{% endif %}>
|
||||||
|
<span>Save as project with metadata</span>
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label for="separate_chapters_format">Separate chapter format</label>
|
<label for="separate_chapters_format">Separate chapter format</label>
|
||||||
|
|||||||
Reference in New Issue
Block a user