UNPKG

crunchyroll-toolkit

Version:

Toolkit Node.js complet pour extraire données d'animés, métadonnées et thumbnails depuis Crunchyroll avec techniques anti-détection 2024/2025

227 lines (226 loc) 8.69 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.SeleniumBrowserManager = void 0; const selenium_webdriver_1 = require("selenium-webdriver"); const fs = __importStar(require("fs")); const path = __importStar(require("path")); const child_process = __importStar(require("child_process")); class SeleniumBrowserManager { constructor(options = {}) { this.options = { headless: true, timeout: 30000, maxRetries: 3, userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', locale: 'fr-FR', ...options }; } async initialize() { if (!this.driver) { console.log('🔧 Initialisation Selenium + undetected-chromedriver...'); // 1. Démarrer le script Python undetected-chromedriver await this.startUndetectedDriver(); // 2. Attendre que le driver soit prêt await this.waitForDriverReady(); // 3. Se connecter au driver via Selenium await this.connectToDriver(); console.log('✅ Selenium + undetected-chromedriver initialisé avec succès'); } } async startUndetectedDriver() { return new Promise((resolve, reject) => { console.log('🐍 Démarrage du script Python undetected-chromedriver...'); const pythonArgs = ['undetected_driver.py']; if (this.options.headless) { pythonArgs.push('--headless'); } // Utiliser l'environnement virtuel const pythonPath = path.join(process.cwd(), 'venv', 'bin', 'python'); this.pythonProcess = child_process.spawn(pythonPath, pythonArgs, { cwd: process.cwd(), stdio: ['pipe', 'pipe', 'pipe'] }); this.pythonProcess.stdout?.on('data', (data) => { const output = data.toString(); console.log(`🐍 Python: ${output.trim()}`); if (output.includes('Driver prêt !')) { resolve(); } }); this.pythonProcess.stderr?.on('data', (data) => { console.error(`🐍 Python Error: ${data.toString()}`); }); this.pythonProcess.on('error', (error) => { console.error('❌ Erreur Python process:', error); reject(error); }); this.pythonProcess.on('exit', (code) => { console.log(`🐍 Python process terminé avec le code: ${code}`); }); // Timeout de sécurité setTimeout(() => { if (!this.driver) { reject(new Error('Timeout: Python driver non démarré après 30s')); } }, 30000); }); } async waitForDriverReady() { console.log('⏳ Attente du driver connection info...'); // Attendre que le fichier driver_connection.json soit créé for (let i = 0; i < 30; i++) { if (fs.existsSync('driver_connection.json')) { console.log('📁 Fichier de connexion trouvé'); return; } await new Promise(resolve => setTimeout(resolve, 1000)); } throw new Error('Timeout: fichier driver_connection.json non trouvé'); } async connectToDriver() { // Lire les infos de connexion const connectionInfo = JSON.parse(fs.readFileSync('driver_connection.json', 'utf8')); console.log('🔗 Connexion au driver undetected...'); console.log(`📡 URL: ${connectionInfo.command_executor_url}`); console.log(`🆔 Session: ${connectionInfo.session_id}`); try { // Se connecter au driver existant this.driver = await new selenium_webdriver_1.Builder() .usingServer(connectionInfo.command_executor_url) .build(); // Valider la connexion await this.driver.getTitle(); console.log('✅ Connexion Selenium établie'); } catch (error) { console.error('❌ Erreur connexion Selenium:', error); throw error; } } async navigateTo(url) { if (!this.driver) { throw new Error('Driver not initialized'); } console.log(`🌐 Navigation vers: ${url}`); await this.driver.get(url); } async getDriver() { if (!this.driver) { throw new Error('Driver not initialized'); } return this.driver; } async getPageSource() { if (!this.driver) { throw new Error('Driver not initialized'); } return await this.driver.getPageSource(); } async getTitle() { if (!this.driver) { throw new Error('Driver not initialized'); } return await this.driver.getTitle(); } async getCurrentUrl() { if (!this.driver) { throw new Error('Driver not initialized'); } return await this.driver.getCurrentUrl(); } async waitForElement(selector, timeout = 10000) { if (!this.driver) { throw new Error('Driver not initialized'); } try { return await this.driver.wait(selenium_webdriver_1.until.elementLocated(selenium_webdriver_1.By.css(selector)), timeout); } catch (error) { console.log(`⚠️ Élément non trouvé: ${selector}`); return null; } } async executeScript(script) { if (!this.driver) { throw new Error('Driver not initialized'); } return await this.driver.executeScript(script); } async close() { console.log('🛑 Fermeture du browser manager...'); if (this.driver) { try { await this.driver.quit(); this.driver = undefined; console.log('✅ Driver Selenium fermé'); } catch (error) { console.error('⚠️ Erreur fermeture driver:', error); } } if (this.pythonProcess && !this.pythonProcess.killed) { try { this.pythonProcess.kill('SIGTERM'); console.log('✅ Process Python arrêté'); } catch (error) { console.error('⚠️ Erreur arrêt Python process:', error); } } // Nettoyer le fichier de connexion if (fs.existsSync('driver_connection.json')) { fs.unlinkSync('driver_connection.json'); console.log('🧹 Fichier de connexion nettoyé'); } } async retry(fn) { let lastError; for (let i = 0; i < this.options.maxRetries; i++) { try { return await fn(); } catch (error) { lastError = error; if (i < this.options.maxRetries - 1) { await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1))); } } } throw lastError; } } exports.SeleniumBrowserManager = SeleniumBrowserManager;