Files
quixotic/public/script.js
Andrey Kondratev 3d6836dc30 public
2025-08-25 10:39:57 +05:00

161 lines
4.9 KiB
JavaScript
Raw 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.
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) {
const videoElement = event.currentTarget;
videoElement.classList.add('converting');
try {
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'
})
});
if (!response.ok) {
throw new Error('Conversion failed');
}
const data = await response.json();
if (this.tg) {
this.tg.sendData(JSON.stringify({
action: 'send_audio',
audioUrl: data.audioUrl,
title: title
}));
} else {
// Fallback for testing without Telegram
window.open(data.audioUrl, '_blank');
}
} catch (error) {
console.error('Conversion error:', error);
if (this.tg) {
this.tg.showAlert('H81:0 ?@8 :>=25@B0F88. >?@>1C9B5 5I5 @07.');
} else {
alert('H81:0 ?@8 :>=25@B0F88. >?@>1C9B5 5I5 @07.');
}
} 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')}`;
}
escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
}
const app = new QuixoticApp();