This commit is contained in:
Andrey Kondratev
2025-08-29 18:26:00 +05:00
parent 9bdf522f59
commit 82d2713d15
6 changed files with 36 additions and 8 deletions

View File

@@ -0,0 +1,14 @@
# Instructions Read - Progress Note
## Action Taken
Read and understood project instructions and key memory files for the Quixotic project.
## Key Findings
- Project is a YouTube music search/MP3 conversion Telegram miniapp
- Tech stack: Node.js/Express, SQLite, FFmpeg, Telegram Bot API
- Development workflow: yarn dev for development, symbolic code editing preferred
- Must save progress notes automatically after major actions
- Currently viewing /Users/andrew/stuff/quixotic/src/bot.ts in IDE
## Next Steps
Ready to assist with any development tasks for the Quixotic project.

View File

@@ -46,6 +46,7 @@ class QuixoticApp {
private noResults!: HTMLElement; private noResults!: HTMLElement;
private welcomePlaceholder!: HTMLElement; private welcomePlaceholder!: HTMLElement;
private searchTimeout?: NodeJS.Timeout; private searchTimeout?: NodeJS.Timeout;
private currentVideos: VideoResult[] = [];
constructor() { constructor() {
this.tg = (window as WindowWithTelegram).Telegram?.WebApp; this.tg = (window as WindowWithTelegram).Telegram?.WebApp;
@@ -194,6 +195,9 @@ class QuixoticApp {
return; return;
} }
// Store current videos for metadata access
this.currentVideos = videos;
// Hide welcome and no results // Hide welcome and no results
this.welcomePlaceholder.classList.add('tg-hidden'); this.welcomePlaceholder.classList.add('tg-hidden');
this.welcomePlaceholder.style.display = 'none'; this.welcomePlaceholder.style.display = 'none';
@@ -255,6 +259,11 @@ class QuixoticApp {
public async convertVideo(videoId: string, title: string, url: string): Promise<void> { public async convertVideo(videoId: string, title: string, url: string): Promise<void> {
console.log('🎵 Converting:', title); console.log('🎵 Converting:', title);
// Find video metadata from current search results
const video = this.currentVideos.find(v => v.id.toString() === videoId);
const performer = video?.channel || 'Unknown Artist';
const thumbnail = video?.thumbnail || '';
// Find the clicked element by looking for the one that contains this videoId // Find the clicked element by looking for the one that contains this videoId
const videoElement = document.querySelector(`[onclick*="${videoId}"]`) as HTMLElement; const videoElement = document.querySelector(`[onclick*="${videoId}"]`) as HTMLElement;
if (videoElement) { if (videoElement) {
@@ -304,7 +313,9 @@ class QuixoticApp {
body: JSON.stringify({ body: JSON.stringify({
userId: userId, userId: userId,
audioUrl: data.audioUrl, audioUrl: data.audioUrl,
title: title title: title,
performer: performer,
thumbnail: thumbnail
}) })
}); });

View File

@@ -250,11 +250,11 @@ export class QuixoticBot {
} }
// Public method for external API calls // Public method for external API calls
public async sendAudioFile(chatId: number, audioUrl: string, title: string): Promise<void> { public async sendAudioFile(chatId: number, audioUrl: string, title: string, performer?: string, thumbnail?: string): Promise<void> {
return this.sendAudioFileInternal(chatId, audioUrl, title); return this.sendAudioFileInternal(chatId, audioUrl, title, performer, thumbnail);
} }
private async sendAudioFileInternal(chatId: number, audioUrl: string, title: string): Promise<void> { private async sendAudioFileInternal(chatId: number, audioUrl: string, title: string, performer?: string, thumbnail?: string): Promise<void> {
try { try {
console.log(`📤 Sending: ${title} to chat ${chatId}`); console.log(`📤 Sending: ${title} to chat ${chatId}`);
@@ -262,8 +262,9 @@ export class QuixoticBot {
try { try {
await this.bot.sendAudio(chatId, audioUrl, { await this.bot.sendAudio(chatId, audioUrl, {
title: title, title: title,
performer: 'SoundCloud', performer: performer || 'SoundCloud',
caption: `🎵 ${title}`, caption: `🎵 ${title}`,
thumbnail: thumbnail,
parse_mode: undefined parse_mode: undefined
}); });
console.log(`✅ Audio sent: ${title}`); console.log(`✅ Audio sent: ${title}`);

View File

@@ -219,7 +219,7 @@ app.post('/api/telegram-send', async (req: Request, res: Response) => {
console.log('🚀 Telegram send request received'); console.log('🚀 Telegram send request received');
try { try {
const { userId, audioUrl, title }: { userId?: string; audioUrl?: string; title?: string } = req.body; const { userId, audioUrl, title, performer, thumbnail }: { userId?: string; audioUrl?: string; title?: string; performer?: string; thumbnail?: string } = req.body;
console.log(`📤 Sending to user ${userId}: ${title}`); console.log(`📤 Sending to user ${userId}: ${title}`);
if (!userId || !audioUrl || !title) { if (!userId || !audioUrl || !title) {
@@ -233,7 +233,7 @@ app.post('/api/telegram-send', async (req: Request, res: Response) => {
} }
const chatId = parseInt(userId); const chatId = parseInt(userId);
await botInstance.sendAudioFile(chatId, audioUrl, title); await botInstance.sendAudioFile(chatId, audioUrl, title, performer, thumbnail);
console.log('✅ Audio sent successfully'); console.log('✅ Audio sent successfully');
res.json({ success: true, message: 'Audio sent successfully' }); res.json({ success: true, message: 'Audio sent successfully' });

View File

@@ -31,6 +31,7 @@ interface TrackInfo {
author: string; author: string;
length: number; length: number;
available: boolean; available: boolean;
thumbnail?: string;
} }
export class SoundCloudService { export class SoundCloudService {
@@ -131,7 +132,8 @@ export class SoundCloudService {
title: track.title, title: track.title,
author: track.user?.username || 'Unknown', author: track.user?.username || 'Unknown',
length: Math.floor(track.duration / 1000), length: Math.floor(track.duration / 1000),
available: track.streamable available: track.streamable,
thumbnail: this.getHighQualityThumbnail(track.artwork_url || track.user?.avatar_url || '')
}; };
} catch (error) { } catch (error) {
console.error('Error getting track info:', error); console.error('Error getting track info:', error);