Files
gh-christianlouis-quizzical…/musicround/templates/admin/system_settings.html
T
Christian Krakau-Louis 03b982e7c2 Initial clean commit
2025-05-13 08:59:02 +00:00

258 lines
13 KiB
HTML

{% extends 'base.html' %}
{% block title %}System Settings{% endblock %}
{% block content %}
<div class="max-w-4xl mx-auto my-8 p-6 bg-white rounded-lg shadow-md">
<h2 class="text-2xl font-bold mb-6 text-navy-800">System Settings</h2>
<form method="POST">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
<!-- TTS Settings Section -->
<div class="mb-8 border-b pb-6">
<h3 class="text-xl font-semibold mb-4 text-navy-700">Text-to-Speech Settings</h3>
<div class="mb-4">
<label class="block font-medium mb-1" for="default_tts_service">Default TTS Service</label>
<select name="default_tts_service" id="default_tts_service" class="border rounded px-3 py-2 w-full">
<option value="">(None)</option>
{% for service in tts_services %}
<option value="{{ service.id }}" {% if settings.get('default_tts_service') == service.id %}selected{% endif %}>
{{ service.name }}
</option>
{% endfor %}
</select>
<p class="text-sm text-gray-500 mt-1">The default text-to-speech service to use for audio generation</p>
</div>
<div class="mb-4">
<label class="block font-medium mb-1" for="default_tts_voice">Default TTS Voice</label>
<select name="default_tts_voice" id="default_tts_voice" class="border rounded px-3 py-2 w-full">
<option value="">(None)</option>
{% for service in tts_services %}
<optgroup label="{{ service.name }}">
{% for voice in service.voices %}
<option value="{{ voice.id }}" {% if settings.get('default_tts_voice') == voice.id %}selected{% endif %}>
{{ voice.name }} {% if voice.gender or voice.language %}({{ voice.gender }}{% if voice.language and voice.gender %}, {{ voice.language }}{% elif voice.language %}{{ voice.language }}{% endif %}){% endif %}
</option>
{% endfor %}
</optgroup>
{% endfor %}
</select>
<p class="text-sm text-gray-500 mt-1">Default voice ID for the selected TTS service</p>
</div>
<div class="mb-4">
<label class="block font-medium mb-1" for="default_tts_model">Default TTS Model</label>
<select name="default_tts_model" id="default_tts_model" class="border rounded px-3 py-2 w-full">
<option value="">(None)</option>
{% for service in tts_services %}
{% if service.models %}
<optgroup label="{{ service.name }} Models">
{% for model in service.models %}
<option value="{{ model.id }}" {% if settings.get('default_tts_model') == model.id %}selected{% endif %}>
{{ model.name }}
</option>
{% endfor %}
</optgroup>
{% endif %}
{% endfor %}
</select>
<p class="text-sm text-gray-500 mt-1">Default model for OpenAI or ElevenLabs TTS</p>
</div>
</div>
<!-- Spotify Integration Settings -->
<div class="mb-8 border-b pb-6">
<h3 class="text-xl font-semibold mb-4 text-navy-700">Spotify Integration</h3>
<div class="mb-4">
<label class="block font-medium mb-1" for="fallback_spotify_refresh_token">Fallback Spotify Refresh Token</label>
<div class="flex">
<input type="password" name="fallback_spotify_refresh_token" id="fallback_spotify_refresh_token"
class="border rounded-l px-3 py-2 flex-grow"
value="{{ settings.get('fallback_spotify_refresh_token', '') }}">
<button type="button" onclick="toggleTokenVisibility()"
class="bg-gray-200 px-3 py-2 rounded-r border-t border-r border-b">
<i class="fas fa-eye"></i>
</button>
</div>
<p class="text-sm text-gray-500 mt-1">Service account refresh token used when users don't have Spotify access</p>
<div class="mt-2">
<a href="{{ url_for('users.spotify_link') }}" class="bg-navy-600 text-white px-4 py-2 rounded inline-flex items-center">
<i class="fab fa-spotify mr-2"></i> Connect Spotify Account
</a>
</div>
</div>
<div class="mb-4">
<label class="block font-medium mb-1" for="spotify_region">Default Spotify Region</label>
<select name="spotify_region" id="spotify_region" class="border rounded px-3 py-2 w-full">
<option value="">(None)</option>
{% for region in spotify_regions %}
<option value="{{ region.code }}" {% if settings.get('spotify_region') == region.code %}selected{% endif %}>
{{ region.name }}
</option>
{% endfor %}
</select>
<p class="text-sm text-gray-500 mt-1">Default region for Spotify API searches and charts</p>
</div>
</div>
<!-- Authentication Settings Section -->
<div class="mb-8 border-b pb-6">
<h3 class="text-xl font-semibold mb-4 text-navy-700">Authentication Settings</h3>
<div class="flex items-center mb-4">
<input type="checkbox" id="allow_signups" name="allow_signups" value="true"
{% if settings.get('allow_signups', 'true') == 'true' %}checked{% endif %}
class="w-4 h-4 text-blue-600 mr-2">
<label for="allow_signups" class="font-medium">Allow New User Registrations</label>
</div>
<p class="text-sm text-gray-600 mb-4">
When disabled, new users cannot create accounts. Existing users can still log in, and OAuth login will still work for existing accounts.
</p>
</div>
<!-- Backup & System Health Section -->
<div class="mb-8 border-b pb-6">
<h3 class="text-xl font-semibold mb-4 text-navy-700">Backup & System Health</h3>
<div class="flex flex-col md:flex-row gap-4">
<a href="{{ url_for('users.backup_manager') }}" class="flex-1 bg-teal-500 hover:bg-teal-600 text-white py-3 px-4 rounded flex items-center justify-center">
<i class="fas fa-database mr-2"></i> Backup Manager
</a>
<a href="{{ url_for('users.system_health') }}" class="flex-1 bg-navy-600 hover:bg-navy-700 text-white py-3 px-4 rounded flex items-center justify-center">
<i class="fas fa-heartbeat mr-2"></i> System Health
</a>
</div>
<p class="text-sm text-gray-600 mt-2">
Manage system backups, restore from previous backups, and monitor system health.
</p>
<div class="mt-4 bg-blue-50 border border-blue-200 rounded-md p-3">
<div class="flex">
<div class="flex-shrink-0">
<i class="fas fa-info-circle text-blue-500"></i>
</div>
<div class="ml-3">
<p class="text-sm text-blue-700">
Regular backups are recommended to prevent data loss. The backup system will save your database, MP3 files, and system configuration.
</p>
</div>
</div>
</div>
</div>
<!-- Additional Settings -->
<div class="mb-4">
<h3 class="text-xl font-semibold mb-4 text-navy-700">Additional Settings</h3>
{% for key, label in editable_settings %}
{% if key not in ['default_tts_service', 'default_tts_voice', 'default_tts_model', 'fallback_spotify_refresh_token', 'spotify_region', 'allow_signups'] %}
<div class="mb-4">
<label class="block font-medium mb-1" for="{{ key }}">{{ label }}</label>
{% if key == 'enable_public_rounds' %}
<select name="{{ key }}" id="{{ key }}" class="border rounded px-3 py-2 w-full">
<option value="true" {% if settings.get(key) == 'true' %}selected{% endif %}>Enabled</option>
<option value="false" {% if settings.get(key) != 'true' %}selected{% endif %}>Disabled</option>
</select>
{% else %}
<input type="text" name="{{ key }}" id="{{ key }}" class="border rounded px-3 py-2 w-full"
value="{{ settings.get(key, '') }}">
{% endif %}
<p class="text-sm text-gray-500 mt-1">
{% if key == 'max_songs_per_round' %}
Maximum number of songs that can be included in a music round
{% elif key == 'enable_public_rounds' %}
Allow users to make their music rounds publicly accessible
{% endif %}
</p>
</div>
{% endif %}
{% endfor %}
</div>
<div class="flex justify-between">
<button type="submit" class="bg-teal-500 text-white px-6 py-2 rounded hover:bg-teal-600">
<i class="fas fa-save mr-2"></i> Save Settings
</button>
<a href="{{ url_for('core.index') }}" class="bg-gray-300 text-gray-700 px-6 py-2 rounded hover:bg-gray-400">Cancel</a>
</div>
</form>
</div>
{% endblock %}
{% block scripts %}
<script>
function toggleTokenVisibility() {
const tokenField = document.getElementById('fallback_spotify_refresh_token');
if (tokenField.type === 'password') {
tokenField.type = 'text';
} else {
tokenField.type = 'password';
}
}
// Dynamic voice selection based on service
document.getElementById('default_tts_service').addEventListener('change', function() {
const selectedService = this.value;
const voiceSelect = document.getElementById('default_tts_voice');
const modelSelect = document.getElementById('default_tts_model');
// Hide all options first
Array.from(voiceSelect.options).forEach(option => {
option.style.display = 'none';
});
Array.from(modelSelect.options).forEach(option => {
option.style.display = 'none';
});
// Show only options for the selected service
Array.from(voiceSelect.options).forEach(option => {
if (option.value === '' || option.parentNode.label.includes(selectedService)) {
option.style.display = '';
}
});
Array.from(modelSelect.options).forEach(option => {
if (option.value === '' || option.parentNode.label.includes(selectedService)) {
option.style.display = '';
}
});
// Reset to empty if current selection is not valid for the service
let validVoice = false;
Array.from(voiceSelect.options).forEach(option => {
if (option.selected && option.style.display !== 'none') {
validVoice = true;
}
});
if (!validVoice) {
voiceSelect.value = '';
}
let validModel = false;
Array.from(modelSelect.options).forEach(option => {
if (option.selected && option.style.display !== 'none') {
validModel = true;
}
});
if (!validModel) {
modelSelect.value = '';
}
});
// Trigger the change event on page load to set up initial state
document.addEventListener('DOMContentLoaded', function() {
document.getElementById('default_tts_service').dispatchEvent(new Event('change'));
});
</script>
{% endblock %}