# code/utils.py import os import urllib.request import re from core.constants import FONTS_FOLDER import subprocess def load_api_keys(prefix): try: prefix_lower = prefix.lower() keys = [] for k, v in os.environ.items(): if k.lower().startswith(prefix_lower): clean_key = v.strip().strip('"').strip("'") if clean_key: keys.append(clean_key) if keys: print(f"✅ API Key Check: '{prefix}' के लिए {len(keys)} कीज़ मिलीं।") else: print(f"❌ API Key Check: '{prefix}' के लिए कोई कीज़ नहीं मिलीं!") return keys except Exception as e: print(f"🚨 एनवायरनमेंट वेरिएबल्स लोड करते समय त्रुटि: {e}") return [] def ensure_hindi_font(): font_path = os.path.join(FONTS_FOLDER, 'NotoSansDevanagari-Bold.ttf') if not os.path.exists(font_path): print("-> 📥 Hindi Subtitle Font (Noto Sans) डाउनलोड किया जा रहा है...") url = "https://raw.githubusercontent.com/googlefonts/noto-fonts/main/hinted/ttf/NotoSansDevanagari/NotoSansDevanagari-Bold.ttf" try: urllib.request.urlretrieve(url, font_path) print("-> ✅ फ़ॉन्ट सफलतापूर्वक डाउनलोड हो गया!") except Exception as e: print(f"🚨 फ़ॉन्ट डाउनलोड एरर: {e}") return FONTS_FOLDER, "sans-serif" # Fallback return FONTS_FOLDER, "Noto Sans Devanagari" def smart_text_chunker(text, max_words=150): """ Splits the script into logical chunks of roughly 'max_words' length. It ensures splits only happen at sentence boundaries (. or । or ? or !). """ # Clean up multiple spaces or newlines clean_text = re.sub(r'\s+', ' ', text.strip()) # Split by Hindi and English sentence terminators, keeping the delimiters # We use a regex that splits after the punctuation mark and optional spaces. sentences = re.split(r'(?<=[।\.!\?])\s+', clean_text) chunks = [] current_chunk = [] current_word_count = 0 for sentence in sentences: if not sentence.strip(): continue words = sentence.split() word_count = len(words) # If adding this sentence exceeds the limit AND we already have content, cut the chunk here if current_word_count + word_count > max_words and current_chunk: chunks.append(" ".join(current_chunk)) current_chunk = [sentence] current_word_count = word_count else: current_chunk.append(sentence) current_word_count += word_count # Add the last remaining chunk if current_chunk: chunks.append(" ".join(current_chunk)) return chunks # ============================================================================== # 🕵️‍♂️ THE MATH TEACHER (FFmpeg Pause Detector) # ============================================================================== def get_audio_silences(audio_path, min_silence_len=0.4, silence_thresh=-35): """FFmpeg का उपयोग करके ऑडियो के 100% सटीक सन्नाटे (Pauses) निकालता है।""" cmd = ['ffmpeg', '-i', audio_path, '-af', f'silencedetect=n={silence_thresh}dB:d={min_silence_len}', '-f', 'null', '-'] result = subprocess.run(cmd, capture_output=True, text=True) silences = [] starts = re.findall(r'silence_start:\s+([\d\.]+)', result.stderr) ends = re.findall(r'silence_end:\s+([\d\.]+)', result.stderr) for s, e in zip(starts, ends): silences.append({'start': float(s), 'end': float(e)}) return silences