mutt/consolidate_to_mega_pdf.py

114 lines
4.3 KiB
Python
Executable file
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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"📦 <b>Частей архива:</b> {parts_count}\n" if parts_count > 1 else ""
text = f"""
🔥 <b>СВОДНЫЙ АРХИВ ПОЧТЫ ОБНОВЛЕН!</b> 🔥
📑 <b>Файлы:</b> <code>ALL_EMAILS_CONSOLIDATED.pdf</code> (или части _partX.pdf)
📧 <b>Всего писем в архиве:</b> {count}
{parts_text}🐘 <b>Общий размер:</b> {size_mb:.2f} МБ
📅 <b>Обновлено:</b> {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()