102
scripts/regenerate_thumbnails.py
Normal file
102
scripts/regenerate_thumbnails.py
Normal file
@@ -0,0 +1,102 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Regenerate all thumbnails for Fansly attachments."""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
import io
|
||||
from pathlib import Path
|
||||
from PIL import Image
|
||||
|
||||
# Bootstrap PostgreSQL adapter before any sqlite3 imports
|
||||
sys.path.insert(0, '/opt/media-downloader')
|
||||
from modules.db_bootstrap import bootstrap_database
|
||||
bootstrap_database()
|
||||
import sqlite3
|
||||
|
||||
# Database path (routed to PostgreSQL via pgadapter)
|
||||
DB_PATH = '/opt/media-downloader/database/media_downloader.db'
|
||||
THUMB_CACHE = Path('/opt/media-downloader/cache/thumbnails/large')
|
||||
MAX_SIZE = (800, 800)
|
||||
|
||||
|
||||
def generate_thumbnail(file_path, file_type):
|
||||
"""Generate thumbnail for image or video."""
|
||||
try:
|
||||
if file_type == 'image':
|
||||
with Image.open(file_path) as img:
|
||||
img.thumbnail(MAX_SIZE, Image.LANCZOS)
|
||||
if img.mode in ('RGBA', 'P'):
|
||||
img = img.convert('RGB')
|
||||
buffer = io.BytesIO()
|
||||
img.save(buffer, format='JPEG', quality=85)
|
||||
return buffer.getvalue()
|
||||
|
||||
elif file_type == 'video':
|
||||
cmd = [
|
||||
'ffmpeg', '-y', '-ss', '1', '-i', str(file_path),
|
||||
'-vframes', '1', '-f', 'image2pipe', '-vcodec', 'mjpeg', '-'
|
||||
]
|
||||
result = subprocess.run(cmd, capture_output=True, timeout=30)
|
||||
if result.returncode == 0 and result.stdout:
|
||||
with Image.open(io.BytesIO(result.stdout)) as img:
|
||||
img.thumbnail(MAX_SIZE, Image.LANCZOS)
|
||||
if img.mode in ('RGBA', 'P'):
|
||||
img = img.convert('RGB')
|
||||
buffer = io.BytesIO()
|
||||
img.save(buffer, format='JPEG', quality=85)
|
||||
return buffer.getvalue()
|
||||
except Exception as e:
|
||||
print(f" Error: {e}")
|
||||
return None
|
||||
|
||||
|
||||
def main():
|
||||
THUMB_CACHE.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
cursor = conn.execute("""
|
||||
SELECT a.id, a.local_path, a.file_type
|
||||
FROM paid_content_attachments a
|
||||
JOIN paid_content_posts p ON a.post_id = p.id
|
||||
JOIN paid_content_creators c ON p.creator_id = c.id
|
||||
WHERE c.service_id = 'fansly_direct'
|
||||
AND a.status = 'completed'
|
||||
AND a.local_path IS NOT NULL
|
||||
ORDER BY a.id
|
||||
""")
|
||||
attachments = cursor.fetchall()
|
||||
conn.close()
|
||||
|
||||
print(f"Regenerating thumbnails for {len(attachments)} files...")
|
||||
|
||||
generated = 0
|
||||
failed = 0
|
||||
missing = 0
|
||||
|
||||
for i, (att_id, local_path, file_type) in enumerate(attachments):
|
||||
if i % 100 == 0:
|
||||
print(f"Progress: {i}/{len(attachments)} (generated: {generated}, failed: {failed})")
|
||||
|
||||
file_path = Path(local_path)
|
||||
if not file_path.exists():
|
||||
missing += 1
|
||||
continue
|
||||
|
||||
thumb_data = generate_thumbnail(file_path, file_type)
|
||||
if thumb_data:
|
||||
thumb_file = THUMB_CACHE / f"{att_id}.jpg"
|
||||
thumb_file.write_bytes(thumb_data)
|
||||
generated += 1
|
||||
else:
|
||||
failed += 1
|
||||
print(f" Failed: {att_id} - {local_path}")
|
||||
|
||||
print(f"\nDone!")
|
||||
print(f" Generated: {generated}")
|
||||
print(f" Failed: {failed}")
|
||||
print(f" Missing files: {missing}")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user