403Webshell
Server IP : 3.147.158.171  /  Your IP : 216.73.216.216
Web Server : Apache/2.4.67 (Amazon Linux) OpenSSL/3.5.5
System : Linux ip-172-31-2-178.us-east-2.compute.internal 6.1.172-216.329.amzn2023.x86_64 #1 SMP PREEMPT_DYNAMIC Wed May 20 06:31:34 UTC 2026 x86_64
User : ec2-user ( 1000)
PHP Version : 8.4.21
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : OFF
Directory :  /tsai/www/html/api.johnturman.net/scripts/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /tsai/www/html/api.johnturman.net/scripts/backfill_thumbnails.py
"""
Thumbnail Backfill Script

Walks every configured site's `create/` and `upload/` image directories and
generates any missing thumbnails via ImageService.get_or_create_thumbnail.
Idempotent — the cache check inside get_or_create_thumbnail skips up-to-date
thumbs, so re-running produces zero work.

Usage:
    cd api
    python scripts/backfill_thumbnails.py

Run once locally, and once per production server.
"""

import logging
import os
import sys
from pathlib import Path

API_DIR = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(API_DIR))

from dotenv import load_dotenv
load_dotenv(API_DIR / '.env')

from app.services.image import ImageService
from app.services.site_config_service import SiteConfigService
from app.utilities.path_utils import PathUtils

ALLOWED_EXTENSIONS = {".jpg", ".jpeg", ".png", ".gif", ".webp"}
BACKFILL_TYPES = ("create", "upload")

logging.basicConfig(
    level=logging.INFO,
    format='%(levelname)s %(asctime)s %(message)s',
    datefmt='%m/%d/%Y %I:%M:%S %p',
)
logger = logging.getLogger(__name__)


def backfill_directory(image_service: ImageService, type_dir: str) -> tuple[int, int, int]:
    """Generate missing thumbs under type_dir. Returns (generated, cached, errors)."""
    if not os.path.isdir(type_dir):
        return 0, 0, 0

    generated = 0
    cached = 0
    errors = 0
    for entry in os.scandir(type_dir):
        if not entry.is_file():
            continue
        ext = os.path.splitext(entry.name)[1].lower()
        if ext not in ALLOWED_EXTENSIONS:
            continue

        thumb_dir = os.path.join(type_dir, 'thumb')
        basename = os.path.splitext(entry.name)[0]
        thumb_path = os.path.join(thumb_dir, f"{basename}.jpg")
        had_thumb = (
            os.path.exists(thumb_path)
            and os.path.getmtime(thumb_path) >= entry.stat().st_mtime
        )

        try:
            image_service.get_or_create_thumbnail(entry.path)
        except Exception as e:
            logger.warning(f"Failed to generate thumbnail for {entry.path}: {e}")
            errors += 1
            continue

        if had_thumb:
            cached += 1
        else:
            generated += 1
            logger.info(f"Generated thumb for {entry.path}")
    return generated, cached, errors


def main() -> int:
    image_service = ImageService()
    path_utils = PathUtils()
    sites = SiteConfigService().get_all_sites()

    total_generated = 0
    total_cached = 0
    total_errors = 0

    for site in sites:
        site_dir = path_utils.get_site_files_dir(site)
        if not os.path.isdir(site_dir):
            logger.info(f"[{site.slug}] no files dir at {site_dir} — skipping")
            continue
        site_generated = 0
        site_cached = 0
        site_errors = 0
        for img_type in BACKFILL_TYPES:
            type_dir = os.path.join(site_dir, img_type)
            g, c, e = backfill_directory(image_service, type_dir)
            site_generated += g
            site_cached += c
            site_errors += e
        logger.info(
            f"[{site.slug}] generated={site_generated} cached={site_cached} errors={site_errors}"
        )
        total_generated += site_generated
        total_cached += site_cached
        total_errors += site_errors

    logger.info(
        f"Done. generated={total_generated} cached={total_cached} errors={total_errors}"
    )
    return 0 if total_errors == 0 else 1


if __name__ == '__main__':
    sys.exit(main())

Youez - 2016 - github.com/yon3zu
LinuXploit