localhost fix

This commit is contained in:
Andrey Kondratev
2025-08-29 17:33:13 +05:00
parent 9e18de85eb
commit 7cf833af6f
8 changed files with 5791 additions and 193 deletions

View File

@@ -66,12 +66,19 @@ export class QuixoticBot {
// Log all incoming messages for debugging
this.bot.on('message', (msg: any) => {
console.log('📨 Received message type:', msg.web_app ? 'web_app_data' : 'text', 'from user:', msg.from?.id);
console.log('📨 Received message:', {
type: msg.web_app ? 'web_app_data' : (msg.text ? 'text' : 'other'),
from: msg.from?.id,
chat: msg.chat?.id,
hasWebAppData: !!msg.web_app?.data,
webAppDataLength: msg.web_app?.data?.length || 0
});
// Handle web app data in regular message event
if (msg.web_app?.data) {
console.log('🔍 Web app data found in message:', msg.web_app.data);
this.handleWebAppData(msg);
return; // Important: don't process as regular message
}
});
@@ -168,12 +175,36 @@ export class QuixoticBot {
}
});
// Handle web app data (legacy event listener, may not work)
// Handle web app data - primary event handler
this.bot.on('web_app_data', async (msg: Message) => {
console.log('🔍 Web app data received via web_app_data event:', msg.web_app?.data);
this.handleWebAppData(msg);
});
// Additional handler for callback queries (sometimes WebApp data comes here)
this.bot.on('callback_query', async (query: any) => {
console.log('📞 Callback query received:', {
id: query.id,
data: query.data,
from: query.from?.id
});
if (query.data) {
try {
const data = JSON.parse(query.data);
if (data.action === 'send_audio') {
console.log('🎵 Audio action from callback query');
await this.sendAudioFileInternal(query.message.chat.id, data.audioUrl, data.title);
}
} catch (e) {
console.log('Callback query data is not JSON, ignoring');
}
}
// Answer callback query to remove loading state
await this.bot.answerCallbackQuery(query.id);
});
// Handle inline queries for search
this.bot.on('inline_query', async (query: InlineQuery) => {
const queryId = query.id;
@@ -228,6 +259,52 @@ export class QuixoticBot {
}
});
// Add universal event logger for debugging
this.bot.on('edited_message', (msg: any) => {
console.log('✏️ Edited message received, checking for web app data:', !!msg.web_app?.data);
if (msg.web_app?.data) {
this.handleWebAppData(msg);
}
});
this.bot.on('channel_post', (msg: any) => {
console.log('📢 Channel post received, checking for web app data:', !!msg.web_app?.data);
if (msg.web_app?.data) {
this.handleWebAppData(msg);
}
});
// Log all update types
this.bot.on('update', (update: any) => {
const updateTypes = Object.keys(update).filter(key => key !== 'update_id');
console.log('🔄 Update received:', {
types: updateTypes,
update_id: update.update_id
});
// Check for web_app_data in any part of the update
const checkForWebAppData = (obj: any, path = ''): any => {
if (!obj || typeof obj !== 'object') return null;
if (obj.web_app?.data) {
console.log(`🎯 Found web_app_data at ${path}:`, obj.web_app.data);
return obj;
}
for (const [key, value] of Object.entries(obj)) {
const result = checkForWebAppData(value, `${path}.${key}`);
if (result) return result;
}
return null;
};
const msgWithData = checkForWebAppData(update);
if (msgWithData && msgWithData.chat?.id) {
console.log('🚀 Processing web app data found in update');
this.handleWebAppData(msgWithData);
}
});
console.log('✅ Bot handlers setup complete');
}
@@ -235,51 +312,109 @@ export class QuixoticBot {
return this.db.getSearchHistory(userId);
}
private async sendAudioFile(chatId: number, audioUrl: string, title: string): Promise<void> {
// Public method for external API calls
public async sendAudioFile(chatId: number, audioUrl: string, title: string): Promise<void> {
return this.sendAudioFileInternal(chatId, audioUrl, title);
}
private async sendAudioFileInternal(chatId: number, audioUrl: string, title: string): Promise<void> {
try {
console.log(`🎵 Attempting to send audio to chat ${chatId}: ${audioUrl}`);
console.log(`🎵 Starting sendAudioFile to chat ${chatId}`);
console.log(`🔗 Audio URL: ${audioUrl}`);
console.log(`📝 Title: ${title}`);
// Send initial message
await this.bot.sendMessage(chatId, '⏳ Подготавливаю MP3 файл...');
// Send initial status message
const statusMsg = await this.bot.sendMessage(chatId, '⏳ Подготавливаю MP3 файл...');
// Try sending as audio first
// Validate audio URL
if (!audioUrl.startsWith('http')) {
throw new Error(`Invalid audio URL: ${audioUrl}`);
}
// Try sending as audio with proper error handling
try {
await this.bot.sendAudio(chatId, audioUrl, {
console.log('🚀 Attempting sendAudio...');
const audioResult = await this.bot.sendAudio(chatId, audioUrl, {
title: title,
performer: 'Quixotic',
caption: `🎵 ${title}`,
parse_mode: undefined // Explicitly avoid parse mode issues
performer: 'SoundCloud',
caption: `🎵 ${title}\n\n🤖 Загружено через Quixotic`,
parse_mode: undefined,
protect_content: false
});
console.log(`✅ Audio sent successfully to chat ${chatId}`);
console.log(`✅ Audio sent successfully! Message ID: ${audioResult.message_id}`);
// Delete status message after success
try {
await this.bot.deleteMessage(chatId, statusMsg.message_id);
} catch (delError) {
console.log('Could not delete status message (not critical)');
}
return;
} catch (audioError: any) {
console.error('SendAudio failed, trying sendDocument:', audioError.message);
console.error('SendAudio failed:', audioError.message);
console.error('Audio error details:', audioError);
// Update status message
await this.bot.editMessageText('📄 Отправляю как документ...', {
chat_id: chatId,
message_id: statusMsg.message_id
});
// Fallback: try sending as document
try {
await this.bot.sendDocument(chatId, audioUrl, {
caption: `🎵 ${title}`,
console.log('🚀 Attempting sendDocument fallback...');
const docResult = await this.bot.sendDocument(chatId, audioUrl, {
caption: `🎵 ${title}\n\n🤖 Загружено через Quixotic`,
parse_mode: undefined
});
console.log(`✅ Document sent successfully to chat ${chatId}`);
console.log(`✅ Document sent successfully! Message ID: ${docResult.message_id}`);
// Delete status message after success
try {
await this.bot.deleteMessage(chatId, statusMsg.message_id);
} catch (delError) {
console.log('Could not delete status message (not critical)');
}
return;
} catch (documentError: any) {
console.error('SendDocument also failed:', documentError.message);
console.error('SendDocument also failed:', documentError.message);
console.error('Document error details:', documentError);
throw documentError;
}
}
} catch (error: any) {
console.error('Complete send audio failure:', error);
console.error('💥 Complete send audio failure:', error.message);
console.error('Full error object:', error);
// Send fallback message with direct link
try {
await this.bot.sendMessage(chatId,
'Не удалось отправить аудиофайл. Вот прямая ссылка для скачивания:\n\n' +
`🔗 ${audioUrl}`,
{ parse_mode: undefined }
`Не удалось отправить файл автоматически.\n\n` +
`🎵 *${title}*\n\n` +
`📥 Скачайте напрямую: [Ссылка на MP3](${audioUrl})\n\n` +
`_Ошибка: ${error.message}_`,
{
parse_mode: 'Markdown',
disable_web_page_preview: false
}
);
} catch (msgError: any) {
console.error('Failed to send error message:', msgError.message);
console.error('💥 Failed to send error message:', msgError.message);
// Last resort - try without markdown
try {
await this.bot.sendMessage(chatId,
`❌ Ошибка отправки файла.\n🎵 ${title}\n🔗 ${audioUrl}`
);
} catch (lastError) {
console.error('💥 All fallback methods failed:', lastError);
}
}
}
}
@@ -288,29 +423,44 @@ export class QuixoticBot {
const chatId = msg.chat.id;
const userId = msg.from?.id;
console.log('🔧 HandleWebAppData called with:', {
chatId,
userId,
hasWebAppData: !!msg.web_app?.data,
dataLength: msg.web_app?.data?.length || 0
});
if (!msg.web_app?.data) {
console.log('❌ No web app data found');
console.log('❌ No web app data found in message');
await this.bot.sendMessage(chatId, '❌ Данные не получены. Попробуйте еще раз.');
return;
}
try {
console.log('📝 Raw web app data:', msg.web_app.data);
const data: WebAppData = JSON.parse(msg.web_app.data);
console.log('📝 Parsed data:', data);
console.log(' Parsed data successfully:', data);
if (data.action === 'send_audio') {
console.log(`🎵 Processing audio request for user ${userId}, chat ${chatId}: ${data.title}`);
await this.sendAudioFile(chatId, data.audioUrl, data.title);
console.log(`🔗 Audio URL: ${data.audioUrl}`);
// Send immediate confirmation
await this.bot.sendMessage(chatId, '⏳ Получил запрос, отправляю аудио...');
await this.sendAudioFileInternal(chatId, data.audioUrl, data.title);
} else {
console.log('⚠️ Unknown action:', data.action);
await this.bot.sendMessage(chatId, '❌ Неизвестное действие.');
await this.bot.sendMessage(chatId, `❌ Неизвестное действие: ${data.action}`);
}
} catch (parseError: any) {
console.error('Web app data parse error:', parseError.message);
console.error('Raw data:', msg.web_app?.data);
await this.bot.sendMessage(chatId, '❌ Ошибка обработки данных.');
console.error('Web app data parse error:', parseError.message);
console.error('Raw data that failed to parse:', msg.web_app?.data);
await this.bot.sendMessage(chatId, `❌ Ошибка обработки данных: ${parseError.message}`);
}
}
private formatDuration(seconds: number): string {
if (!seconds) return '';
const mins = Math.floor(seconds / 60);

View File

@@ -189,6 +189,43 @@ app.post('/api/convert', async (req: Request, res: Response) => {
}
});
// Fallback API for Telegram notifications when WebApp data doesn't work
app.post('/api/telegram-notify', async (req: Request, res: Response) => {
try {
const { userId, audioUrl, title }: { userId?: string; audioUrl?: string; title?: string } = req.body;
console.log('📡 Fallback Telegram notification received:', { userId, audioUrl, title });
if (!userId || !audioUrl || !title) {
return res.status(400).json({ error: 'Missing required fields' });
}
// Find bot instance and send the audio
// Note: We need to get the bot instance from somewhere
// For now, we'll store a reference to it
if ((global as any).quixoticBot) {
console.log('🤖 Using global bot instance for fallback notification');
const bot = (global as any).quixoticBot;
// Get user's chat ID from database
const user = await db.getUserByTelegramId(userId);
if (user) {
// We need to get chat ID - for now use user's telegram ID as chat ID
await bot.sendAudioFile(parseInt(userId), audioUrl, title);
console.log('✅ Fallback notification sent successfully');
} else {
console.log('❌ User not found for fallback notification');
}
} else {
console.log('❌ No bot instance available for fallback');
}
res.json({ success: true });
} catch (error) {
console.error('Fallback notification error:', error);
res.status(500).json({ error: 'Fallback failed' });
}
});
// Serve download files
app.use('/downloads', express.static(downloadsDir));
@@ -240,8 +277,10 @@ const webAppUrl = process.env.WEB_APP_URL || `http://localhost:${port}`;
if (botToken && botToken.length > 10) {
try {
new QuixoticBot(botToken, webAppUrl);
console.log('🤖 Telegram bot started');
const botInstance = new QuixoticBot(botToken, webAppUrl);
// Store bot instance globally for API access
(global as any).quixoticBot = botInstance;
console.log('🤖 Telegram bot started and stored globally');
} catch (error: any) {
console.error('❌ Bot initialization failed:', error.message);
console.warn('⚠️ Bot disabled due to error');