You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
391 lines
18 KiB
391 lines
18 KiB
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Settings - Reddit Video Maker Bot</title>
|
|
<link rel="stylesheet" href="/static/css/app.css">
|
|
</head>
|
|
<body>
|
|
<nav class="sidebar">
|
|
<div class="logo">
|
|
<h2>Reddit Video Bot</h2>
|
|
</div>
|
|
<ul class="nav-links">
|
|
<li><a href="/">Dashboard</a></li>
|
|
<li><a href="/settings" class="active">Settings</a></li>
|
|
<li><a href="/backgrounds">Backgrounds</a></li>
|
|
<li><a href="/videos">Videos</a></li>
|
|
<li><a href="/progress">Progress</a></li>
|
|
</ul>
|
|
</nav>
|
|
|
|
<main class="content">
|
|
<header>
|
|
<h1>Settings</h1>
|
|
<button id="btn-save" class="btn btn-primary">Save All Settings</button>
|
|
</header>
|
|
|
|
<form id="settings-form">
|
|
<!-- Qwen TTS Settings -->
|
|
<div class="card">
|
|
<h3>Qwen TTS Settings</h3>
|
|
<p class="card-description">Configure your Qwen TTS server connection for text-to-speech generation.</p>
|
|
|
|
<div class="form-group">
|
|
<label for="qwen_api_url">API URL</label>
|
|
<input type="url" id="qwen_api_url" name="qwen_api_url" placeholder="http://localhost:8080">
|
|
<small>The base URL of your Qwen TTS server</small>
|
|
</div>
|
|
|
|
<div class="form-row">
|
|
<div class="form-group">
|
|
<label for="qwen_email">Email</label>
|
|
<input type="email" id="qwen_email" name="qwen_email" placeholder="your@email.com">
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="qwen_password">Password</label>
|
|
<input type="password" id="qwen_password" name="qwen_password" placeholder="Enter password">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-row">
|
|
<div class="form-group">
|
|
<label for="qwen_speaker">Speaker Voice</label>
|
|
<select id="qwen_speaker" name="qwen_speaker">
|
|
<option value="Chelsie">Chelsie</option>
|
|
<option value="Ethan">Ethan</option>
|
|
<option value="Vivian" selected>Vivian</option>
|
|
<option value="Asher">Asher</option>
|
|
<option value="Aria">Aria</option>
|
|
<option value="Oliver">Oliver</option>
|
|
<option value="Emma">Emma</option>
|
|
<option value="Noah">Noah</option>
|
|
<option value="Sophia">Sophia</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="qwen_language">Language</label>
|
|
<select id="qwen_language" name="qwen_language">
|
|
<option value="English" selected>English</option>
|
|
<option value="Chinese">Chinese</option>
|
|
<option value="Spanish">Spanish</option>
|
|
<option value="French">French</option>
|
|
<option value="German">German</option>
|
|
<option value="Japanese">Japanese</option>
|
|
<option value="Korean">Korean</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="qwen_instruct">Voice Style Instructions</label>
|
|
<input type="text" id="qwen_instruct" name="qwen_instruct" placeholder="Warm, friendly, conversational.">
|
|
<small>Describe the speaking style you want</small>
|
|
</div>
|
|
|
|
<button type="button" id="btn-test-tts" class="btn btn-secondary">Test TTS Connection</button>
|
|
<span id="tts-status" class="status-text"></span>
|
|
</div>
|
|
|
|
<!-- Reddit Settings -->
|
|
<div class="card">
|
|
<h3>Reddit Settings</h3>
|
|
<p class="card-description">Configure which subreddits to scrape for content. No API keys required!</p>
|
|
|
|
<div class="form-group">
|
|
<label for="subreddit">Subreddit</label>
|
|
<div class="input-with-prefix">
|
|
<span class="prefix">r/</span>
|
|
<input type="text" id="subreddit" name="subreddit" placeholder="AskReddit">
|
|
</div>
|
|
<small>Enter subreddit name without r/ prefix. Use + for multiple (e.g., AskReddit+nosleep)</small>
|
|
</div>
|
|
|
|
<div class="form-row">
|
|
<div class="form-group">
|
|
<label for="min_comments">Minimum Comments</label>
|
|
<input type="number" id="min_comments" name="min_comments" value="20" min="1">
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="max_comment_length">Max Comment Length</label>
|
|
<input type="number" id="max_comment_length" name="max_comment_length" value="500" min="50">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="post_id">Specific Post ID (Optional)</label>
|
|
<input type="text" id="post_id" name="post_id" placeholder="Leave empty for random">
|
|
<small>Enter a specific Reddit post ID, or leave empty to fetch random posts</small>
|
|
</div>
|
|
|
|
<div class="form-group checkbox-group">
|
|
<label>
|
|
<input type="checkbox" id="random" name="random" checked>
|
|
Pick random posts from subreddit
|
|
</label>
|
|
</div>
|
|
|
|
<div class="form-group checkbox-group">
|
|
<label>
|
|
<input type="checkbox" id="allow_nsfw" name="allow_nsfw">
|
|
Allow NSFW content
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Video Settings -->
|
|
<div class="card">
|
|
<h3>Video Settings</h3>
|
|
<p class="card-description">Configure video output and visual settings.</p>
|
|
|
|
<div class="form-row">
|
|
<div class="form-group">
|
|
<label for="resolution_w">Width</label>
|
|
<input type="number" id="resolution_w" name="resolution_w" value="1080">
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="resolution_h">Height</label>
|
|
<input type="number" id="resolution_h" name="resolution_h" value="1920">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-row">
|
|
<div class="form-group">
|
|
<label for="theme">Screenshot Theme</label>
|
|
<select id="theme" name="theme">
|
|
<option value="dark" selected>Dark</option>
|
|
<option value="light">Light</option>
|
|
<option value="transparent">Transparent</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="opacity">Opacity</label>
|
|
<input type="number" id="opacity" name="opacity" value="0.9" min="0" max="1" step="0.1">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="times_to_run">Videos per Run</label>
|
|
<input type="number" id="times_to_run" name="times_to_run" value="1" min="1" max="10">
|
|
<small>How many videos to generate when you click "Generate"</small>
|
|
</div>
|
|
|
|
<div class="form-group checkbox-group">
|
|
<label>
|
|
<input type="checkbox" id="storymode" name="storymode">
|
|
Story Mode (for narrative subreddits like r/nosleep)
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Background Settings -->
|
|
<div class="card">
|
|
<h3>Background Settings</h3>
|
|
<p class="card-description">Select background video and audio. Upload custom backgrounds in the Backgrounds page.</p>
|
|
|
|
<div class="form-row">
|
|
<div class="form-group">
|
|
<label for="background_video">Background Video</label>
|
|
<select id="background_video" name="background_video">
|
|
<option value="minecraft">Minecraft Parkour</option>
|
|
<option value="gta">GTA V</option>
|
|
<option value="rocket-league">Rocket League</option>
|
|
<option value="subway-surfers">Subway Surfers</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="background_audio">Background Audio</label>
|
|
<select id="background_audio" name="background_audio">
|
|
<option value="lofi">Lo-Fi Beats</option>
|
|
<option value="lofi-2">Lo-Fi Beats 2</option>
|
|
<option value="chill-summer">Chill Summer</option>
|
|
<option value="none">No Background Audio</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="background_audio_volume">Background Audio Volume</label>
|
|
<input type="range" id="background_audio_volume" name="background_audio_volume" min="0" max="1" step="0.05" value="0.15">
|
|
<span id="volume-display">15%</span>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</main>
|
|
|
|
<script src="/static/js/app.js"></script>
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
loadSettings();
|
|
loadCustomBackgrounds();
|
|
|
|
document.getElementById('btn-save').addEventListener('click', saveSettings);
|
|
document.getElementById('btn-test-tts').addEventListener('click', testTTSConnection);
|
|
|
|
// Volume slider display
|
|
const volumeSlider = document.getElementById('background_audio_volume');
|
|
const volumeDisplay = document.getElementById('volume-display');
|
|
volumeSlider.addEventListener('input', () => {
|
|
volumeDisplay.textContent = Math.round(volumeSlider.value * 100) + '%';
|
|
});
|
|
});
|
|
|
|
function loadSettings() {
|
|
fetch('/api/config')
|
|
.then(r => r.json())
|
|
.then(config => {
|
|
if (!config || !config.settings) return;
|
|
|
|
// TTS settings
|
|
const tts = config.settings.tts || {};
|
|
setFieldValue('qwen_api_url', tts.qwen_api_url);
|
|
setFieldValue('qwen_email', tts.qwen_email);
|
|
setFieldValue('qwen_speaker', tts.qwen_speaker);
|
|
setFieldValue('qwen_language', tts.qwen_language);
|
|
setFieldValue('qwen_instruct', tts.qwen_instruct);
|
|
|
|
// Reddit settings
|
|
const thread = config.reddit?.thread || {};
|
|
setFieldValue('subreddit', thread.subreddit);
|
|
setFieldValue('min_comments', thread.min_comments);
|
|
setFieldValue('max_comment_length', thread.max_comment_length);
|
|
setFieldValue('post_id', thread.post_id);
|
|
setCheckbox('random', thread.random);
|
|
setCheckbox('allow_nsfw', config.settings.allow_nsfw);
|
|
|
|
// Video settings
|
|
setFieldValue('resolution_w', config.settings.resolution_w);
|
|
setFieldValue('resolution_h', config.settings.resolution_h);
|
|
setFieldValue('theme', config.settings.theme);
|
|
setFieldValue('opacity', config.settings.opacity);
|
|
setFieldValue('times_to_run', config.settings.times_to_run);
|
|
setCheckbox('storymode', config.settings.storymode);
|
|
|
|
// Background settings
|
|
const bg = config.settings.background || {};
|
|
setFieldValue('background_video', bg.background_video);
|
|
setFieldValue('background_audio', bg.background_audio);
|
|
setFieldValue('background_audio_volume', bg.background_audio_volume);
|
|
|
|
// Update volume display
|
|
const vol = bg.background_audio_volume || 0.15;
|
|
document.getElementById('volume-display').textContent = Math.round(vol * 100) + '%';
|
|
})
|
|
.catch(err => console.error('Error loading settings:', err));
|
|
}
|
|
|
|
function loadCustomBackgrounds() {
|
|
fetch('/api/backgrounds/video')
|
|
.then(r => r.json())
|
|
.then(data => {
|
|
const videoSelect = document.getElementById('background_video');
|
|
|
|
// Add custom videos
|
|
if (data.videos && data.videos.length > 0) {
|
|
const customGroup = document.createElement('optgroup');
|
|
customGroup.label = 'Custom Videos';
|
|
data.videos.forEach(v => {
|
|
const opt = document.createElement('option');
|
|
opt.value = 'custom:' + v.filename;
|
|
opt.textContent = v.name;
|
|
customGroup.appendChild(opt);
|
|
});
|
|
videoSelect.appendChild(customGroup);
|
|
}
|
|
})
|
|
.catch(err => console.error('Error loading backgrounds:', err));
|
|
}
|
|
|
|
function setFieldValue(id, value) {
|
|
const field = document.getElementById(id);
|
|
if (field && value !== undefined && value !== null) {
|
|
field.value = value;
|
|
}
|
|
}
|
|
|
|
function setCheckbox(id, value) {
|
|
const field = document.getElementById(id);
|
|
if (field) {
|
|
field.checked = !!value;
|
|
}
|
|
}
|
|
|
|
function saveSettings() {
|
|
const form = document.getElementById('settings-form');
|
|
const config = {
|
|
subreddit: form.subreddit.value,
|
|
post_id: form.post_id.value,
|
|
min_comments: parseInt(form.min_comments.value),
|
|
max_comment_length: parseInt(form.max_comment_length.value),
|
|
random: form.random.checked,
|
|
allow_nsfw: form.allow_nsfw.checked,
|
|
theme: form.theme.value,
|
|
opacity: parseFloat(form.opacity.value),
|
|
times_to_run: parseInt(form.times_to_run.value),
|
|
storymode: form.storymode.checked,
|
|
resolution_w: parseInt(form.resolution_w.value),
|
|
resolution_h: parseInt(form.resolution_h.value),
|
|
voice_choice: 'qwentts',
|
|
qwen_api_url: form.qwen_api_url.value,
|
|
qwen_email: form.qwen_email.value,
|
|
qwen_password: form.qwen_password.value,
|
|
qwen_speaker: form.qwen_speaker.value,
|
|
qwen_language: form.qwen_language.value,
|
|
qwen_instruct: form.qwen_instruct.value,
|
|
background_video: form.background_video.value,
|
|
background_audio: form.background_audio.value,
|
|
background_audio_volume: parseFloat(form.background_audio_volume.value)
|
|
};
|
|
|
|
fetch('/api/config', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(config)
|
|
})
|
|
.then(r => r.json())
|
|
.then(data => {
|
|
if (data.success) {
|
|
showNotification('Settings saved successfully!', 'success');
|
|
} else {
|
|
showNotification('Failed to save: ' + data.message, 'error');
|
|
}
|
|
})
|
|
.catch(err => showNotification('Error saving settings', 'error'));
|
|
}
|
|
|
|
function testTTSConnection() {
|
|
const statusEl = document.getElementById('tts-status');
|
|
statusEl.textContent = 'Testing...';
|
|
statusEl.className = 'status-text';
|
|
|
|
const config = {
|
|
qwen_api_url: document.getElementById('qwen_api_url').value,
|
|
qwen_email: document.getElementById('qwen_email').value,
|
|
qwen_password: document.getElementById('qwen_password').value
|
|
};
|
|
|
|
fetch('/api/tts/test', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(config)
|
|
})
|
|
.then(r => r.json())
|
|
.then(data => {
|
|
if (data.success) {
|
|
statusEl.textContent = 'Connection successful!';
|
|
statusEl.className = 'status-text success';
|
|
} else {
|
|
statusEl.textContent = 'Failed: ' + data.message;
|
|
statusEl.className = 'status-text error';
|
|
}
|
|
})
|
|
.catch(err => {
|
|
statusEl.textContent = 'Connection error';
|
|
statusEl.className = 'status-text error';
|
|
});
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|