#!/usr/bin/env python3 """ Consolidates all individual email PDFs into one giant PDF for NotebookLM. Sorted by date (prefix in filename). Supports auto-splitting into parts if size > 180MB. """ import os import sys import fitz # PyMuPDF from pathlib import Path import logging import requests from datetime import datetime # === CONFIG === BASE_DIR = Path(__file__).parent SOURCE_DIR = BASE_DIR / "exported_emails" / "all" OUTPUT_FILE = BASE_DIR / "ALL_EMAILS_CONSOLIDATED.pdf" BOT_TOKEN = "8725618164:AAH1tGalq-pw1l0t4P5c0sdLkCVJdh7IE7M" CHAT_ID = "197957361" PROXY = "socks5h://127.0.0.1:10808" logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s") log = logging.getLogger("Consolidator") def send_tg_alert(count, size_mb, parts_count): url = f"https://api.telegram.org/bot{BOT_TOKEN}/sendMessage" parts_text = f"📦 Частей архива: {parts_count}\n" if parts_count > 1 else "" text = f""" 🔥 СВОДНЫЙ АРХИВ ПОЧТЫ ОБНОВЛЕН! 🔥 📑 Файлы: ALL_EMAILS_CONSOLIDATED.pdf (или части _partX.pdf) 📧 Всего писем в архиве: {count} {parts_text}🐘 Общий размер: {size_mb:.2f} МБ 📅 Обновлено: {datetime.now().strftime('%Y-%m-%d %H:%M')} 🚀 Данные успешно отправлены в Google Drive (Domovoy_AI). """ try: requests.post(url, json={"chat_id": CHAT_ID, "text": text, "parse_mode": "HTML"}, proxies={"https": PROXY}, timeout=20) log.info("✅ Telegram alert sent.") except Exception as e: log.error(f"❌ TG Alert failed: {e}") def consolidate(): log.info("Starting consolidation...") if not SOURCE_DIR.exists(): log.error(f"Source directory {SOURCE_DIR} not found!") return pdf_files = list(SOURCE_DIR.glob("*.pdf")) if not pdf_files: log.warning("No PDF files found to consolidate.") return # Sort by filename (which starts with date YYYY-MM-DD or contains it) pdf_files.sort(key=lambda x: x.name) log.info(f"Found {len(pdf_files)} PDFs. Merging with part splitting (max 180MB)...") # Clean old parts for p in BASE_DIR.glob("ALL_EMAILS_CONSOLIDATED_part*.pdf"): try: os.unlink(p) except Exception as e: log.warning(f"Failed to delete old part {p}: {e}") if OUTPUT_FILE.exists(): try: os.unlink(OUTPUT_FILE) except Exception as e: log.warning(f"Failed to delete old output: {e}") parts = [] current_merger = fitz.open() current_size = 0 part_num = 1 for pdf_path in pdf_files: file_size = pdf_path.stat().st_size # Limit to 195 MB to guarantee fitting in NotebookLM 195MB if current_size + file_size > 195 * 1024 * 1024 and len(current_merger) > 0: part_file = BASE_DIR / f"ALL_EMAILS_CONSOLIDATED_part{part_num}.pdf" current_merger.save(part_file, garbage=3, deflate=True) log.info(f"Saved part {part_num}: {part_file} ({part_file.stat().st_size / (1024*1024):.2f} MB)") parts.append(part_file) current_merger.close() current_merger = fitz.open() current_size = 0 part_num += 1 try: doc = fitz.open(pdf_path) current_merger.insert_pdf(doc) doc.close() current_size += file_size except Exception as e: log.warning(f"Failed to add {pdf_path.name}: {e}") # Save last part if len(current_merger) > 0: if part_num == 1: current_merger.save(OUTPUT_FILE, garbage=3, deflate=True) log.info(f"✅ Consolidated single PDF saved: {OUTPUT_FILE} ({OUTPUT_FILE.stat().st_size / (1024*1024):.2f} MB)") parts.append(OUTPUT_FILE) else: part_file = BASE_DIR / f"ALL_EMAILS_CONSOLIDATED_part{part_num}.pdf" current_merger.save(part_file, garbage=3, deflate=True) log.info(f"Saved part {part_num}: {part_file} ({part_file.stat().st_size / (1024*1024):.2f} MB)") parts.append(part_file) current_merger.close() total_size_mb = sum(p.stat().st_size for p in parts) / (1024 * 1024) send_tg_alert(len(pdf_files), total_size_mb, len(parts)) if __name__ == "__main__": consolidate()