Team Ai
Apppublic

sourcecode6687/Gupshup

sourceHugging Faceupdated 8mo agoView on Hugging Face
0likes
main.py130 linesDownload Raw Back to root
1import asyncio2import os3import socket4import dns.resolver5import yt_dlp6import logging7import random8import nest_asyncio9 10# Apply nest_asyncio to prevent event loop issues11nest_asyncio.apply()12 13# Logger14logging.basicConfig(level=logging.INFO)15logger = logging.getLogger("AudioEngine")16 17# --- 0. PREPARE RESOLVER ---18resolver = dns.resolver.Resolver()19resolver.nameservers = ['8.8.8.8', '8.8.4.4']20_original_getaddrinfo = socket.getaddrinfo21 22# --- 1. NETWORK PATCH: FORCE IPv4 ---23def patched_getaddrinfo(host, port, family=0, type=0, proto=0, flags=0):24    try:25        answers = resolver.resolve(host, 'A') 26        ip = answers[0].to_text()27        return _original_getaddrinfo(ip, port, socket.AF_INET, type, proto, flags)28    except Exception:29        try:30            res = _original_getaddrinfo(host, port, family, type, proto, flags)31            return [r for r in res if r[0] == socket.AF_INET]32        except Exception:33            return []34 35socket.getaddrinfo = patched_getaddrinfo36 37class AudioEngine:38    def __init__(self, icecast_url):39        self.icecast_url = icecast_url40        self.process = None41 42    def get_ytdlp_opts(self):43        """44        ANDROID CLIENT CONFIGURATION45        Using 'android' bypasses the 'n-sig' JS challenges that fail on servers.46        """47        if not os.path.exists('cookies.txt'):48            logger.error("โŒ CRITICAL: cookies.txt not found!")49        50        opts = {51            'format': 'bestaudio/best',52            'noplaylist': True,53            'quiet': True,54            'force_ipv4': True,55            'source_address': '0.0.0.0',56            'cookiefile': 'cookies.txt', 57            58            # --- BYPASS CONFIGURATION ---59            'nocheckcertificate': True,60            'extractor_args': {61                'youtube': {62                    # PRIORITIZE ANDROID to fix "Signature solving failed"63                    'player_client': ['android', 'web'], 64                    'skip': ['ios'] 65                }66            }67        }68        return opts69 70    async def get_stream_url(self, query):71        loop = asyncio.get_event_loop()72        try:73            with yt_dlp.YoutubeDL(self.get_ytdlp_opts()) as ydl:74                if not query.startswith("http"):75                    search_query = f"ytsearch1:{query}"76                else:77                    search_query = query78                79                logger.info(f"๐Ÿ” Searching: {query}")80                info = await loop.run_in_executor(None, lambda: ydl.extract_info(search_query, download=False))81                82                if 'entries' in info:83                    info = info['entries'][0]84                85                if not info or 'url' not in info:86                    return None87 88                logger.info(f"โœ… Found: {info.get('title')}")89                return {90                    'url': info['url'], 91                    'title': info.get('title', 'Unknown'),92                    'duration': info.get('duration', 0)93                }94        except Exception as e:95            logger.error(f"โš ๏ธ YTDLP Error: {e}")96            return None97 98    async def stream(self, input_url, is_silence=False):99        self.stop() 100        command = ['ffmpeg', '-re', '-4', '-y'] 101        102        if is_silence:103            command.extend(['-f', 'lavfi', '-i', 'anullsrc=r=44100:cl=stereo'])104        else:105            command.extend([106                '-headers', 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)',107                '-i', input_url108            ])109 110        command.extend([111            '-c:a', 'libmp3lame', '-b:a', '128k', '-ar', '44100', '-ac', '2',112            '-content_type', 'audio/mpeg', '-f', 'mp3',113            self.icecast_url114        ])115 116        try:117            self.process = await asyncio.create_subprocess_exec(118                *command,119                stdout=asyncio.subprocess.DEVNULL,120                stderr=asyncio.subprocess.DEVNULL121            )122            await self.process.wait()123        except Exception as e:124            logger.error(f"Stream Error: {e}")125 126    def stop(self):127        if self.process:128            try: self.process.terminate()129            except: pass130