ts
This commit is contained in:
@@ -35,6 +35,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="script.js"></script>
|
||||
<script src="dist/script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,34 +1,79 @@
|
||||
interface TelegramWebApp {
|
||||
ready(): void;
|
||||
expand(): void;
|
||||
sendData(data: string): void;
|
||||
MainButton: {
|
||||
show(): void;
|
||||
hide(): void;
|
||||
};
|
||||
initDataUnsafe?: {
|
||||
user?: {
|
||||
id: number;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
interface Window {
|
||||
Telegram?: {
|
||||
WebApp: TelegramWebApp;
|
||||
};
|
||||
}
|
||||
|
||||
interface VideoResult {
|
||||
id: string;
|
||||
title: string;
|
||||
channel: string;
|
||||
thumbnail: string;
|
||||
duration: number;
|
||||
}
|
||||
|
||||
interface SearchResponse {
|
||||
videos: VideoResult[];
|
||||
}
|
||||
|
||||
interface ConvertResponse {
|
||||
audioUrl?: string;
|
||||
title: string;
|
||||
}
|
||||
|
||||
class QuixoticApp {
|
||||
private tg?: TelegramWebApp;
|
||||
private searchInput!: HTMLInputElement;
|
||||
private searchBtn!: HTMLButtonElement;
|
||||
private loading!: HTMLElement;
|
||||
private results!: HTMLElement;
|
||||
private noResults!: HTMLElement;
|
||||
|
||||
constructor() {
|
||||
this.tg = window.Telegram?.WebApp;
|
||||
this.init();
|
||||
this.bindEvents();
|
||||
}
|
||||
|
||||
init() {
|
||||
private init(): void {
|
||||
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');
|
||||
this.searchInput = document.getElementById('searchInput') as HTMLInputElement;
|
||||
this.searchBtn = document.getElementById('searchBtn') as HTMLButtonElement;
|
||||
this.loading = document.getElementById('loading') as HTMLElement;
|
||||
this.results = document.getElementById('results') as HTMLElement;
|
||||
this.noResults = document.getElementById('noResults') as HTMLElement;
|
||||
}
|
||||
|
||||
bindEvents() {
|
||||
private bindEvents(): void {
|
||||
this.searchBtn.addEventListener('click', () => this.search());
|
||||
this.searchInput.addEventListener('keypress', (e) => {
|
||||
this.searchInput.addEventListener('keypress', (e: KeyboardEvent) => {
|
||||
if (e.key === 'Enter') {
|
||||
this.search();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async search() {
|
||||
private async search(): Promise<void> {
|
||||
const query = this.searchInput.value.trim();
|
||||
if (!query) return;
|
||||
|
||||
@@ -50,7 +95,7 @@ class QuixoticApp {
|
||||
throw new Error('Search failed');
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
const data: SearchResponse = await response.json();
|
||||
this.displayResults(data.videos);
|
||||
} catch (error) {
|
||||
console.error('Search error:', error);
|
||||
@@ -58,19 +103,19 @@ class QuixoticApp {
|
||||
}
|
||||
}
|
||||
|
||||
showLoading() {
|
||||
private showLoading(): void {
|
||||
this.loading.classList.remove('hidden');
|
||||
this.results.classList.add('hidden');
|
||||
this.noResults.classList.add('hidden');
|
||||
this.searchBtn.disabled = true;
|
||||
}
|
||||
|
||||
hideLoading() {
|
||||
private hideLoading(): void {
|
||||
this.loading.classList.add('hidden');
|
||||
this.searchBtn.disabled = false;
|
||||
}
|
||||
|
||||
displayResults(videos) {
|
||||
private displayResults(videos: VideoResult[]): void {
|
||||
this.hideLoading();
|
||||
|
||||
if (!videos || videos.length === 0) {
|
||||
@@ -93,16 +138,18 @@ class QuixoticApp {
|
||||
this.noResults.classList.add('hidden');
|
||||
}
|
||||
|
||||
showNoResults() {
|
||||
private showNoResults(): void {
|
||||
this.hideLoading();
|
||||
this.results.classList.add('hidden');
|
||||
this.noResults.classList.remove('hidden');
|
||||
}
|
||||
|
||||
async convertVideo(videoId, title) {
|
||||
public async convertVideo(videoId: string, title: string): Promise<void> {
|
||||
console.log('Convert video called:', { videoId, title });
|
||||
const videoElement = event.currentTarget;
|
||||
videoElement.classList.add('converting');
|
||||
const videoElement = (event as any)?.currentTarget as HTMLElement;
|
||||
if (videoElement) {
|
||||
videoElement.classList.add('converting');
|
||||
}
|
||||
|
||||
try {
|
||||
console.log('Sending convert request...');
|
||||
@@ -123,7 +170,7 @@ class QuixoticApp {
|
||||
throw new Error(`Conversion failed with status: ${response.status}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
const data: ConvertResponse = await response.json();
|
||||
console.log('Response data:', data);
|
||||
|
||||
if (data.audioUrl) {
|
||||
@@ -152,7 +199,7 @@ class QuixoticApp {
|
||||
// Should not happen since we removed fallbacks
|
||||
throw new Error('No audio URL received');
|
||||
}
|
||||
} catch (error) {
|
||||
} catch (error: any) {
|
||||
console.error('Conversion error:', error);
|
||||
|
||||
// Show specific error message
|
||||
@@ -168,18 +215,20 @@ class QuixoticApp {
|
||||
|
||||
this.showMessage(`❌ ${errorMsg}`, 'warning');
|
||||
} finally {
|
||||
videoElement.classList.remove('converting');
|
||||
if (videoElement) {
|
||||
videoElement.classList.remove('converting');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
formatDuration(seconds) {
|
||||
private formatDuration(seconds: number): string {
|
||||
if (!seconds) return '';
|
||||
const mins = Math.floor(seconds / 60);
|
||||
const secs = seconds % 60;
|
||||
return `${mins}:${secs.toString().padStart(2, '0')}`;
|
||||
}
|
||||
|
||||
showMessage(message, type = 'info') {
|
||||
private showMessage(message: string, type: string = 'info'): void {
|
||||
// Remove existing message if any
|
||||
const existingMessage = document.querySelector('.status-message');
|
||||
if (existingMessage) {
|
||||
@@ -193,7 +242,9 @@ class QuixoticApp {
|
||||
|
||||
// Add to page
|
||||
const container = document.querySelector('.container');
|
||||
container.insertBefore(messageEl, container.firstChild);
|
||||
if (container) {
|
||||
container.insertBefore(messageEl, container.firstChild);
|
||||
}
|
||||
|
||||
// Auto-remove after 5 seconds
|
||||
setTimeout(() => {
|
||||
@@ -203,11 +254,12 @@ class QuixoticApp {
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
escapeHtml(text) {
|
||||
private escapeHtml(text: string): string {
|
||||
const div = document.createElement('div');
|
||||
div.textContent = text;
|
||||
return div.innerHTML;
|
||||
}
|
||||
}
|
||||
|
||||
const app = new QuixoticApp();
|
||||
const app = new QuixoticApp();
|
||||
(window as any).app = app;
|
||||
Reference in New Issue
Block a user