diff --git a/lib/enhanced-screenshot.ts b/lib/enhanced-screenshot.ts index e6b349e..492b4ba 100644 --- a/lib/enhanced-screenshot.ts +++ b/lib/enhanced-screenshot.ts @@ -83,6 +83,8 @@ export class EnhancedScreenshotService { // Check login status and login if needed const isLoggedIn = await layoutSession.checkLoginStatus() + console.log(`🔍 ${layout.toUpperCase()}: Login status check result: ${isLoggedIn}`) + if (!isLoggedIn) { console.log(`🔐 Logging in to ${layout} session...`) if (sessionId && index === 0) { @@ -102,55 +104,12 @@ export class EnhancedScreenshotService { progressTracker.updateStep(sessionId, 'navigation', 'active', `Navigating to ${config.symbol} chart...`) } - // Navigate directly to the specific layout URL with symbol and timeframe - const directUrl = `https://www.tradingview.com/chart/${layoutUrl}/?symbol=${config.symbol}&interval=${config.timeframe}` - console.log(`🌐 ${layout.toUpperCase()}: Navigating directly to ${directUrl}`) - - // Get page from the session - const page = (layoutSession as any).page - if (!page) { - throw new Error(`Failed to get page for ${layout} session`) - } - - // Navigate directly to the layout URL with retries and progressive timeout strategy - let navigationSuccess = false - for (let attempt = 1; attempt <= 3; attempt++) { - try { - console.log(`🔄 ${layout.toUpperCase()}: Navigation attempt ${attempt}/3`) - - // Progressive waiting strategy: first try domcontentloaded, then networkidle if that fails - const waitUntilStrategy = attempt === 1 ? 'domcontentloaded' : 'networkidle0' - const timeoutDuration = attempt === 1 ? 30000 : (60000 + (attempt - 1) * 30000) - - console.log(`📋 ${layout.toUpperCase()}: Using waitUntil: ${waitUntilStrategy}, timeout: ${timeoutDuration}ms`) - - await page.goto(directUrl, { - waitUntil: waitUntilStrategy, - timeout: timeoutDuration - }) - - // If we used domcontentloaded, wait a bit more for dynamic content - if (waitUntilStrategy === 'domcontentloaded') { - console.log(`⏳ ${layout.toUpperCase()}: Waiting additional 5s for dynamic content...`) - await new Promise(resolve => setTimeout(resolve, 5000)) - } - - navigationSuccess = true - break - } catch (navError: any) { - console.warn(`⚠️ ${layout.toUpperCase()}: Navigation attempt ${attempt} failed:`, navError?.message || navError) - if (attempt === 3) { - throw new Error(`Failed to navigate to ${layout} layout after 3 attempts: ${navError?.message || navError}`) - } - // Progressive backoff - const waitTime = 2000 * attempt - console.log(`⏳ ${layout.toUpperCase()}: Waiting ${waitTime}ms before retry...`) - await new Promise(resolve => setTimeout(resolve, waitTime)) - } - } + // Use the new navigateToLayout method instead of manual URL construction + console.log(`🌐 ${layout.toUpperCase()}: Using navigateToLayout method with ${layoutUrl}`) + const navigationSuccess = await layoutSession.navigateToLayout(layoutUrl, config.symbol, config.timeframe) if (!navigationSuccess) { - throw new Error(`Failed to navigate to ${layout} layout`) + throw new Error(`Failed to navigate to ${layout} layout ${layoutUrl}`) } console.log(`✅ ${layout.toUpperCase()}: Successfully navigated to layout`) @@ -183,9 +142,12 @@ export class EnhancedScreenshotService { // Strategy 2: Look for chart elements manually try { console.log(`🔍 ${layout.toUpperCase()}: Checking for chart elements manually...`) - await page.waitForSelector('.layout__area--center', { timeout: 15000 }) - console.log(`✅ ${layout.toUpperCase()}: Chart area found via selector`) - chartLoadSuccess = true + const page = (layoutSession as any).page + if (page) { + await page.waitForSelector('.layout__area--center', { timeout: 15000 }) + console.log(`✅ ${layout.toUpperCase()}: Chart area found via selector`) + chartLoadSuccess = true + } } catch (selectorError: any) { console.warn(`⚠️ ${layout.toUpperCase()}: Chart selector check failed:`, selectorError?.message || selectorError) } diff --git a/lib/tradingview-automation.ts b/lib/tradingview-automation.ts index 226e18a..0417bc9 100644 --- a/lib/tradingview-automation.ts +++ b/lib/tradingview-automation.ts @@ -190,62 +190,89 @@ export class TradingViewAutomation { } async checkLoginStatus(): Promise { - if (!this.page) throw new Error('Page not initialized') - - console.log('CHECKING: Login status with 6 detection strategies...') + if (!this.page) return false try { - // Strategy 1: Check JavaScript authentication variables (most reliable) - console.log('CHECKING: Strategy 1: Checking JavaScript authentication variables...') + console.log('🔍 CHECKING LOGIN STATUS - Starting comprehensive authentication detection...') + + // Strategy 1: Check JavaScript authentication variables + console.log('CHECKING: Strategy 1: JavaScript authentication variables...') const authStatus = await this.page.evaluate(() => { - // Check if window.is_authenticated exists and is true - const w = window as any + console.log('EVAL: Starting JavaScript authentication check...') - // Enhanced debugging - capture all relevant variables - const result = { - is_authenticated: w.is_authenticated, - user: w.user, - hasUser: typeof w.user === 'object' && w.user !== null, - authType: typeof w.is_authenticated, - userType: typeof w.user + // Check window.is_authenticated + console.log('EVAL: Checking window.is_authenticated...') + const isAuthVar = (window as any).is_authenticated + console.log('EVAL: window.is_authenticated =', isAuthVar, typeof isAuthVar) + + // Check window.user + console.log('EVAL: Checking window.user...') + const userVar = (window as any).user + console.log('EVAL: window.user =', userVar, typeof userVar) + + // Check if user object has meaningful data + if (userVar && typeof userVar === 'object') { + console.log('EVAL: User object keys:', Object.keys(userVar)) + console.log('EVAL: User object values preview:', JSON.stringify(userVar).substring(0, 200)) } - console.log('🔍 JavaScript auth detection:', { - is_authenticated: result.is_authenticated, - authType: result.authType, - hasUser: result.hasUser, - userType: result.userType, - userExists: !!w.user, - username: w.user?.username || 'N/A' - }) - - if (typeof w.is_authenticated === 'boolean') { - return { - isAuthenticated: w.is_authenticated, - hasUser: typeof w.user === 'object' && w.user !== null, - username: w.user?.username || null - } - } - return null + // Return authentication status + const result = isAuthVar === true || (userVar && typeof userVar === 'object' && Object.keys(userVar).length > 0) + console.log('EVAL: Final Strategy 1 result:', result) + return result }) - console.log('🔍 Auth status result:', authStatus) - + console.log('CHECKING: Strategy 1 JavaScript result:', authStatus) if (authStatus) { - if (authStatus.isAuthenticated && authStatus.hasUser) { - console.log(`SUCCESS: JavaScript indicates user is authenticated as "${authStatus.username}"`) - return true - } else { - console.log('INFO: JavaScript indicates user is not authenticated') - console.log('🔍 Auth details:', { - isAuthenticated: authStatus.isAuthenticated, - hasUser: authStatus.hasUser, - username: authStatus.username - }) - return false - } - } else { - console.log('INFO: No JavaScript authentication variables found') + console.log('✅ Strategy 1: Authenticated via JavaScript variables') + return true + } + + // Strategy 1.5: Check for user avatar/profile elements (indicates logged in state) + console.log('CHECKING: Strategy 1.5: User interface elements...') + const userElements = await this.page.$$eval('[data-testid="header-user-menu"], .tv-header__user-menu, [class*="user-menu"], [class*="avatar"], [data-name="header-user-menu"]', elements => { + console.log('EVAL: Found', elements.length, 'potential user elements') + return elements.length > 0 + }).catch(() => false) + + if (userElements) { + console.log('Strategy 1.5: Found user interface elements - likely authenticated') + return true + } + + // Strategy 2: Check for absence of login forms (indicates already logged in) + console.log('CHECKING: Strategy 2: Absence of login forms...') + const pageUrl = this.page.url() + console.log('CHECKING: Current URL:', pageUrl) + + // If we're not on a login page and no login forms exist, we're likely logged in + const hasLoginForms = await this.page.$('input[type="email"], input[name="username"], input[name="email"], input[type="password"]').then(el => !!el).catch(() => false) + const isOnLoginPage = pageUrl.includes('/signin') || pageUrl.includes('/login') || pageUrl.includes('/accounts/signin') + + console.log('CHECKING: Has login forms:', hasLoginForms) + console.log('CHECKING: Is on login page:', isOnLoginPage) + + if (!hasLoginForms && !isOnLoginPage) { + console.log('Strategy 2: No login forms and not on login page - likely authenticated') + return true + } + + // Strategy 3: Check for "Sign In" vs "User Menu" buttons + console.log('CHECKING: Strategy 3: Page action buttons...') + const hasSignInButton = await this.page.$('[data-testid="header-signin-button"], a[href*="signin"], button:has-text("Sign in")').then(el => !!el).catch(() => false) + const hasUserMenu = await this.page.$('[data-testid="header-user-menu"], .tv-header__user-menu, [class*="user-menu"]').then(el => !!el).catch(() => false) + + console.log('CHECKING: Has sign in button:', hasSignInButton) + console.log('CHECKING: Has user menu:', hasUserMenu) + + if (!hasSignInButton && hasUserMenu) { + console.log('Strategy 3: User menu present, no sign in button - authenticated') + return true + } + + if (!hasSignInButton && !isOnLoginPage) { + console.log('Strategy 3: No sign in button and not on login page - likely authenticated') + return true } // Strategy 2: Check for user account indicators (positive indicators) @@ -300,8 +327,8 @@ export class TradingViewAutomation { // Strategy 4: Check URL patterns console.log('CHECKING: Strategy 4: Checking URL patterns...') - const currentUrl = this.page.url() - if (currentUrl.includes('/signin') || currentUrl.includes('/login')) { + const urlCheck = this.page.url() + if (urlCheck.includes('/signin') || urlCheck.includes('/login')) { console.log('ERROR: On login page - not logged in') return false } @@ -338,6 +365,20 @@ export class TradingViewAutomation { } } + // Strategy 7: Check for absence of login interface (final check) + console.log('CHECKING: Strategy 7: Final absence of login interface check...') + const finalUrlCheck = this.page.url() + const hasAnyLoginElements = await this.page.$('input[type="email"], input[name="username"], input[name="email"], input[type="password"], [href*="signin"], [href*="login"], button:has-text("Sign in")').then(el => !!el).catch(() => false) + const isOnMainTradingViewDomain = finalUrlCheck.includes('tradingview.com') && !finalUrlCheck.includes('/signin') && !finalUrlCheck.includes('/login') + + console.log('CHECKING: Has any login elements:', hasAnyLoginElements) + console.log('CHECKING: Is on main TradingView domain (not login page):', isOnMainTradingViewDomain) + + if (isOnMainTradingViewDomain && !hasAnyLoginElements) { + console.log('✅ Strategy 7: On main TradingView domain with no login elements - authenticated') + return true + } + // If we can't determine status clearly, assume not logged in to be safe console.log('WARNING: Could not determine login status clearly, assuming not logged in') return false @@ -405,9 +446,7 @@ export class TradingViewAutomation { const elem = el as HTMLElement return elem.textContent || elem.getAttribute('title') || elem.getAttribute('href') || '' }) - console.log(`🎯 Found signin element: ${selector} with text: "${text}"`) - - // Check if this looks like a sign in button + console.log(`Found signin element: ${selector} with text: "${text}"`) // Check if this looks like a sign in button const lowerText = text.toLowerCase() if (lowerText.includes('sign in') || lowerText.includes('login') || lowerText.includes('signin') || selector.includes('signin') || @@ -910,6 +949,38 @@ export class TradingViewAutomation { } } + async navigateToLayout(layoutId: string, symbol: string, timeframe?: string): Promise { + if (!this.page) throw new Error('Page not initialized') + + try { + console.log(`🎯 Navigating to layout ${layoutId} with symbol: ${symbol}`) + + // Construct direct layout URL - this bypasses the generic chart URL issue + const directUrl = `https://www.tradingview.com/chart/${layoutId}/?symbol=${symbol}${timeframe ? `&interval=${timeframe}` : ''}` + console.log(`📍 Direct layout navigation to: ${directUrl}`) + + await this.page.goto(directUrl, { + waitUntil: 'domcontentloaded', + timeout: 30000 + }) + + // Wait for chart to load + await sleep(5000) + + // Wait for chart container + await this.page.waitForSelector('.chart-container, #chart-container, [data-name="chart"]', { + timeout: 30000 + }) + + console.log(`✅ Successfully navigated to layout ${layoutId}`) + return true + + } catch (error) { + console.error(`❌ Failed to navigate to layout ${layoutId}:`, error) + return false + } + } + async navigateToSymbol(symbol: string, timeframe?: string): Promise { if (!this.page) throw new Error('Page not initialized')