youtube-automation/microsite/templates/index.html

384 lines
12 KiB
HTML
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>YouTube to Directus | Add Videos</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
}
.container {
background: white;
border-radius: 20px;
box-shadow: 0 20px 40px rgba(0,0,0,0.1);
padding: 40px;
width: 100%;
max-width: 600px;
position: relative;
overflow: hidden;
}
.container::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 5px;
background: linear-gradient(90deg, #ff416c, #ff4b2b, #ff6b6b);
}
h1 {
color: #333;
margin-bottom: 10px;
font-weight: 700;
font-size: 28px;
text-align: center;
}
.subtitle {
color: #666;
text-align: center;
margin-bottom: 30px;
font-size: 16px;
}
.form-group {
margin-bottom: 25px;
}
label {
display: block;
margin-bottom: 8px;
color: #333;
font-weight: 600;
font-size: 14px;
}
input[type="url"], input[type="text"] {
width: 100%;
padding: 15px;
border: 2px solid #e0e0e0;
border-radius: 12px;
font-size: 16px;
transition: all 0.3s ease;
background: #f9f9f9;
}
input[type="url"]:focus, input[type="text"]:focus {
outline: none;
border-color: #667eea;
background: white;
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
}
.btn {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
padding: 15px 30px;
border-radius: 12px;
font-size: 16px;
font-weight: 600;
cursor: pointer;
width: 100%;
transition: all 0.3s ease;
position: relative;
overflow: hidden;
}
.btn:hover {
transform: translateY(-2px);
box-shadow: 0 10px 25px rgba(102, 126, 234, 0.3);
}
.btn:active {
transform: translateY(0);
}
.btn:disabled {
opacity: 0.7;
cursor: not-allowed;
transform: none;
}
.loading {
display: none;
align-items: center;
justify-content: center;
margin-top: 20px;
}
.spinner {
width: 20px;
height: 20px;
border: 2px solid #f3f3f3;
border-top: 2px solid #667eea;
border-radius: 50%;
animation: spin 1s linear infinite;
margin-right: 10px;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.result {
margin-top: 20px;
padding: 15px;
border-radius: 12px;
display: none;
}
.result.success {
background: #d4edda;
border: 1px solid #c3e6cb;
color: #155724;
}
.result.error {
background: #f8d7da;
border: 1px solid #f5c6cb;
color: #721c24;
}
.preview {
background: #f8f9fa;
border: 1px solid #dee2e6;
border-radius: 12px;
padding: 15px;
margin-top: 15px;
display: none;
}
.preview h3 {
margin: 0 0 10px 0;
color: #333;
}
.preview p {
margin: 5px 0;
color: #666;
}
.status-info {
background: #e3f2fd;
border: 1px solid #bbdefb;
border-radius: 12px;
padding: 15px;
margin-top: 20px;
font-size: 14px;
color: #1565c0;
}
.examples {
margin-top: 10px;
font-size: 12px;
color: #888;
}
.examples a {
color: #667eea;
text-decoration: none;
margin-right: 15px;
}
.examples a:hover {
text-decoration: underline;
}
</style>
</head>
<body>
<div class="container">
<h1>🎬 YouTube to Directus</h1>
<p class="subtitle">Add YouTube videos to your media collection</p>
<form id="videoForm">
<div class="form-group">
<label for="youtube_url">YouTube URL *</label>
<input
type="url"
id="youtube_url"
name="youtube_url"
placeholder="https://www.youtube.com/watch?v=dQw4w9WgXcQ"
required
>
<div class="examples">
Quick test:
<a href="#" onclick="setExample('https://www.youtube.com/watch?v=dQw4w9WgXcQ')">Rick Roll</a>
<a href="#" onclick="setExample('https://www.youtube.com/watch?v=zjkBMFhNj_g')">LLM Intro</a>
</div>
</div>
<div class="form-group">
<label for="custom_title">Custom Title (optional)</label>
<input
type="text"
id="custom_title"
name="custom_title"
placeholder="Leave empty to use default title"
>
</div>
<div style="display: flex; gap: 10px;">
<button type="button" class="btn" id="previewBtn" style="flex: 1; background: #6c757d;">
Preview Info
</button>
<button type="submit" class="btn" id="submitBtn" style="flex: 2;">
Add to Directus
</button>
</div>
</form>
<div class="loading" id="loading">
<div class="spinner"></div>
Processing video...
</div>
<div class="result" id="result"></div>
<div class="status-info">
<strong> How it works:</strong><br>
1. Enter any YouTube URL<br>
2. Optionally customize the title<br>
3. Video gets added to Directus media_items<br>
4. Thumbnail is automatically downloaded<br>
5. The watcher service will monitor for any issues
</div>
</div>
<script>
const form = document.getElementById('videoForm');
const loading = document.getElementById('loading');
const result = document.getElementById('result');
const submitBtn = document.getElementById('submitBtn');
const previewBtn = document.getElementById('previewBtn');
function setExample(url) {
document.getElementById('youtube_url').value = url;
}
function showLoading() {
loading.style.display = 'flex';
submitBtn.disabled = true;
previewBtn.disabled = true;
result.style.display = 'none';
}
function hideLoading() {
loading.style.display = 'none';
submitBtn.disabled = false;
previewBtn.disabled = false;
}
function showResult(message, isSuccess = true, data = null) {
if (isSuccess && data) {
// Show rich metadata for successful additions
let content = `${data.message}\n\n`;
content += `📋 Details:\n`;
content += `• Item ID: ${data.item_id}\n`;
content += `• Video ID: ${data.video_id}\n`;
if (data.channel_name) content += `• Channel: ${data.channel_name}\n`;
if (data.duration_formatted) content += `• Duration: ${data.duration_formatted}\n`;
if (data.view_count_formatted) content += `• Views: ${data.view_count_formatted}\n`;
content += `• Thumbnail: ${data.thumbnail_added ? 'Added ✓' : 'Will be added by watcher service'}\n`;
if (data.description) content += `\n📝 Description:\n${data.description}`;
result.textContent = content;
} else {
result.textContent = message;
}
result.className = `result ${isSuccess ? 'success' : 'error'}`;
result.style.display = 'block';
}
// Preview button functionality
previewBtn.addEventListener('click', async () => {
const url = document.getElementById('youtube_url').value.trim();
if (!url) {
showResult('❌ Please enter a YouTube URL first', false);
return;
}
showLoading();
try {
const response = await fetch(`/preview?url=${encodeURIComponent(url)}`);
const data = await response.json();
if (data.success) {
const info = data.video_info;
let content = `🔍 Video Preview:\n\n`;
content += `📺 Title: ${info.title}\n`;
content += `📺 Video ID: ${info.video_id}\n`;
if (info.channel_name) content += `👤 Channel: ${info.channel_name}\n`;
if (info.duration_formatted) content += `⏱️ Duration: ${info.duration_formatted}\n`;
if (info.view_count_formatted) content += `👁️ Views: ${info.view_count_formatted}\n`;
if (info.upload_date) content += `📅 Upload Date: ${info.upload_date.split('T')[0]}\n`;
if (info.description) {
content += `\n📝 Description:\n${info.description.substring(0, 300)}`;
if (info.description.length > 300) content += '...';
}
showResult(content, true);
// Auto-fill title if custom title is empty
const customTitleInput = document.getElementById('custom_title');
if (!customTitleInput.value.trim()) {
customTitleInput.value = info.title;
}
} else {
showResult(`❌ Preview failed: ${data.error}`, false);
}
} catch (error) {
showResult(`❌ Preview error: ${error.message}`, false);
} finally {
hideLoading();
}
});
form.addEventListener('submit', async (e) => {
e.preventDefault();
const formData = new FormData(form);
showLoading();
try {
const response = await fetch('/add_video', {
method: 'POST',
body: formData
});
const data = await response.json();
if (data.success) {
showResult('Success', true, data);
form.reset();
} else {
showResult(`${data.error}`, false);
}
} catch (error) {
showResult(`❌ Network error: ${error.message}`, false);
} finally {
hideLoading();
}
});
</script>
</body>
</html>