Files
quixotic/public/script.js
Andrey Kondratev 98787a382e does not work
2025-08-27 18:37:44 +05:00

213 lines
7.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
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.
class QuixoticApp {
constructor() {
this.tg = window.Telegram?.WebApp;
this.init();
this.bindEvents();
}
init() {
if (this.tg) {
this.tg.ready();
this.tg.expand();
this.tg.MainButton.hide();
}
this.searchInput = document.getElementById('searchInput');
this.searchBtn = document.getElementById('searchBtn');
this.loading = document.getElementById('loading');
this.results = document.getElementById('results');
this.noResults = document.getElementById('noResults');
}
bindEvents() {
this.searchBtn.addEventListener('click', () => this.search());
this.searchInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
this.search();
}
});
}
async search() {
const query = this.searchInput.value.trim();
if (!query) return;
this.showLoading();
try {
const response = await fetch('/api/search', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
query,
userId: this.tg?.initDataUnsafe?.user?.id || 'demo'
})
});
if (!response.ok) {
throw new Error('Search failed');
}
const data = await response.json();
this.displayResults(data.videos);
} catch (error) {
console.error('Search error:', error);
this.showNoResults();
}
}
showLoading() {
this.loading.classList.remove('hidden');
this.results.classList.add('hidden');
this.noResults.classList.add('hidden');
this.searchBtn.disabled = true;
}
hideLoading() {
this.loading.classList.add('hidden');
this.searchBtn.disabled = false;
}
displayResults(videos) {
this.hideLoading();
if (!videos || videos.length === 0) {
this.showNoResults();
return;
}
this.results.innerHTML = videos.map(video => `
<div class="video-item" onclick="app.convertVideo('${video.id}', '${this.escapeHtml(video.title)}')">
<img class="video-thumbnail" src="${video.thumbnail}" alt="${this.escapeHtml(video.title)}" loading="lazy">
<div class="video-info">
<div class="video-title">${this.escapeHtml(video.title)}</div>
<div class="video-channel">${this.escapeHtml(video.channel)}</div>
<div class="video-duration">${this.formatDuration(video.duration)}</div>
</div>
</div>
`).join('');
this.results.classList.remove('hidden');
this.noResults.classList.add('hidden');
}
showNoResults() {
this.hideLoading();
this.results.classList.add('hidden');
this.noResults.classList.remove('hidden');
}
async convertVideo(videoId, title) {
console.log('Convert video called:', { videoId, title });
const videoElement = event.currentTarget;
videoElement.classList.add('converting');
try {
console.log('Sending convert request...');
const response = await fetch('/api/convert', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
videoId,
title,
userId: this.tg?.initDataUnsafe?.user?.id || 'demo'
})
});
console.log('Response status:', response.status);
if (!response.ok) {
throw new Error(`Conversion failed with status: ${response.status}`);
}
const data = await response.json();
console.log('Response data:', data);
if (data.audioUrl) {
// MP3 conversion successful!
console.log('MP3 conversion successful:', data.audioUrl);
if (this.tg) {
// Send to Telegram chat
this.tg.sendData(JSON.stringify({
action: 'send_audio',
audioUrl: data.audioUrl,
title: title
}));
this.showMessage('✓ MP3 готов! Отправляем в чат...', 'success');
} else {
// For testing in browser - download file
const link = document.createElement('a');
link.href = data.audioUrl;
link.download = `${title}.mp3`;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
this.showMessage('✓ MP3 скачан!', 'success');
}
} else {
// Should not happen since we removed fallbacks
throw new Error('No audio URL received');
}
} catch (error) {
console.error('Conversion error:', error);
// Show specific error message
let errorMsg = 'Ошибка конвертации. Попробуйте другое видео.';
if (error.message.includes('No audio URL')) {
errorMsg = 'Не удалось получить аудио файл.';
} else if (error.message.includes('410')) {
errorMsg = 'Видео недоступно для скачивания.';
} else if (error.message.includes('403')) {
errorMsg = 'Видео заблокировано для скачивания.';
}
this.showMessage(`${errorMsg}`, 'warning');
} finally {
videoElement.classList.remove('converting');
}
}
formatDuration(seconds) {
if (!seconds) return '';
const mins = Math.floor(seconds / 60);
const secs = seconds % 60;
return `${mins}:${secs.toString().padStart(2, '0')}`;
}
showMessage(message, type = 'info') {
// Remove existing message if any
const existingMessage = document.querySelector('.status-message');
if (existingMessage) {
existingMessage.remove();
}
// Create message element
const messageEl = document.createElement('div');
messageEl.className = `status-message status-${type}`;
messageEl.textContent = message;
// Add to page
const container = document.querySelector('.container');
container.insertBefore(messageEl, container.firstChild);
// Auto-remove after 5 seconds
setTimeout(() => {
if (messageEl.parentNode) {
messageEl.remove();
}
}, 5000);
}
escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
}
const app = new QuixoticApp();