import os import re import argparse import shutil from PIL import Image # --- Konfiguracija skripte --- PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__)) # Predvideva, da je skripta v root direktoriju projekta IMAGES_DIR_NAME = "images" ORIGINAL_IMAGES_SUBDIR_NAME = "original" # Podmapa znotraj IMAGES_DIR_NAME # Mape, v katerih skripta išče datoteke za posodobitev referenc DIRECTORIES_TO_SCAN = ['en', 'si', 'mk', 'css'] # Dodatne datoteke v korenski mapi za preverjanje FILES_IN_ROOT_TO_SCAN = ['main.js'] # Končnice datotek, v katerih iščemo in posodabljamo reference na slike FILE_EXTENSIONS_TO_UPDATE = ['.html', '.css', '.js'] WEBP_QUALITY = 80 # Kakovost kompresije za WebP (0-100). Višja številka = boljša kakovost, večja datoteka. MAX_IMAGE_DIMENSION = 1920 # Maksimalna dimenzija (širina ali višina) za pomanjšanje, če je slika večja. Ohranijo se razmerja. Če je 0, se ne pomanjšuje. IMAGE_EXTENSIONS_TO_OPTIMIZE = ['.jpg', '.jpeg', '.png', '.gif'] # Končnice datotek, ki jih želimo optimizirati EXCLUDE_FILES_FROM_OPTIMIZATION = [ '1-logo.png', # Logotip, ki ga morda ne želimo spreminjati '13-whitelogo.png', # Beli logotip, ki ga morda ne želimo spreminjati 'favicon.ico' # Ikona, ki ni slikovni format, ki ga Pillow lahko enostavno pretvori v WebP # Dodaj še druga imena datotek, ki jih želiš izključiti iz optimizacije ] # --- Pomožne funkcije --- def optimize_image(image_path, output_path, quality, max_dim, dry_run=False): """ Naloži sliko, jo po potrebi pomanjša, optimizira in pretvori v WebP format. """ try: with Image.open(image_path) as img: original_size = img.size if img.mode in ('P', 'LA', 'RGBA'): if img.mode != 'RGBA': img = img.convert("RGBA") if max_dim > 0 and (img.width > max_dim or img.height > max_dim): print(f" Pomanjšujem sliko {os.path.basename(image_path)} iz {img.width}x{img.height} ...", end="") img.thumbnail((max_dim, max_dim), Image.LANCZOS) print(f" na {img.width}x{img.height}") else: print(f" Obdelujem sliko {os.path.basename(image_path)} ({img.width}x{img.height})...", end="") if not dry_run: img.save(output_path, "webp", quality=quality, method=6) print(f" Shrani v {os.path.basename(output_path)} (kvaliteta: {quality}).") else: print(f" DRY RUN: Shranil bi v {os.path.basename(output_path)} (kvaliteta: {quality}).") return True except FileNotFoundError: print(f" Napaka: Izvorna slika '{image_path}' ni najdena.") return False except Exception as e: print(f" Napaka pri optimizaciji slike '{image_path}': {e}") return False def update_file_references(file_path, old_filename_with_ext, new_filename_with_ext, dry_run=False): """ Poišče staro ime slike v datoteki (HTML, CSS, JS) in ga zamenja z novim imenom WebP. """ try: with open(file_path, 'r', encoding='utf-8') as f: content = f.read() except Exception as e: print(f" Napaka pri branju datoteke '{file_path}': {e}") return False original_content = content # Uporabimo preprosto zamenjavo niza, ki je varna, saj zamenjujemo celotno ime datoteke z končnico. # To bo delovalo za poti v narekovajih (HTML, JS) in v url() (CSS). if old_filename_with_ext in content: content = content.replace(old_filename_with_ext, new_filename_with_ext) if content != original_content: if not dry_run: backup_path = file_path + ".bak" try: # Preverimo, ali datoteka obstaja, preden jo kopiramo if os.path.exists(file_path): shutil.copy2(file_path, backup_path) except Exception as e: print(f" Napaka pri ustvarjanju varnostne kopije za '{file_path}': {e}") return False try: with open(file_path, 'w', encoding='utf-8') as f: f.write(content) print(f" Posodobljene reference za '{old_filename_with_ext}' v '{os.path.relpath(file_path, PROJECT_ROOT)}'.") return True except Exception as e: print(f" Napaka pri zapisovanju v datoteko '{file_path}': {e}") return False else: print(f" DRY RUN: Reference za '{old_filename_with_ext}' bi bile posodobljene v '{os.path.relpath(file_path, PROJECT_ROOT)}'.") return True return False def find_files_to_update(scan_dirs, root_files): """ Rekurzivno poišče vse datoteke z ustreznimi končnicami v podanih mapah. """ found_files = [] # Najprej poišči datoteke v navedenih mapah for directory in scan_dirs: dir_path = os.path.join(PROJECT_ROOT, directory) if os.path.isdir(dir_path): for dirpath, _, filenames in os.walk(dir_path): for filename in filenames: if any(filename.endswith(ext) for ext in FILE_EXTENSIONS_TO_UPDATE): found_files.append(os.path.join(dirpath, filename)) else: print(f"Opozorilo: Mapa za skeniranje '{dir_path}' ne obstaja. Preskakujem.") # Nato dodaj posamezne datoteke iz korenske mape for filename in root_files: file_path = os.path.join(PROJECT_ROOT, filename) if os.path.isfile(file_path): found_files.append(file_path) # Vrne unikaten, sortiran seznam poti return sorted(list(set(found_files))) # --- Glavna funkcija --- def main(): parser = argparse.ArgumentParser(description="Skripta za optimizacijo slik (pretvorba v WebP) in posodobitev referenc v HTML, CSS in JS datotekah.") parser.add_argument("--dry-run", action="store_true", help="Izvede operacije, vendar ne spreminja datotek in ne premika originalnih slik.") args = parser.parse_args() images_full_path = os.path.join(PROJECT_ROOT, IMAGES_DIR_NAME) original_images_full_path = os.path.join(images_full_path, ORIGINAL_IMAGES_SUBDIR_NAME) if not os.path.isdir(images_full_path): print(f"Napaka: Mapa s slikami '{images_full_path}' ne obstaja. Preverite konfiguracijo.") return if not args.dry_run: os.makedirs(original_images_full_path, exist_ok=True) print(f"Mapa za originalne slike: '{original_images_full_path}' (ustvarjena, če ni obstajala).") else: print(f"DRY RUN: Mapa za originalne slike bi bila '{original_images_full_path}'.") optimized_images_map = [] print("\n--- ZAČETEK OPTIMIZACIJE SLIK ---") for filename in os.listdir(images_full_path): if filename == ORIGINAL_IMAGES_SUBDIR_NAME: continue file_path = os.path.join(images_full_path, filename) if os.path.isfile(file_path): name, ext = os.path.splitext(filename) ext = ext.lower() if filename in EXCLUDE_FILES_FROM_OPTIMIZATION: print(f" Preskakujem izključeno datoteko: '{filename}'.") continue if ext in IMAGE_EXTENSIONS_TO_OPTIMIZE: new_filename = f"{name}.webp" new_file_path = os.path.join(images_full_path, new_filename) if os.path.exists(new_file_path) and os.path.getmtime(new_file_path) > os.path.getmtime(file_path): print(f" WebP različica '{new_filename}' že obstaja in je novejša od originala. Preskakujem optimizacijo.") optimized_images_map.append({'old_name': filename, 'new_name': new_filename}) continue if optimize_image(file_path, new_file_path, WEBP_QUALITY, MAX_IMAGE_DIMENSION, args.dry_run): optimized_images_map.append({'old_name': filename, 'new_name': new_filename}) if not args.dry_run: try: shutil.move(file_path, os.path.join(original_images_full_path, filename)) print(f" Originalna slika premaknjena: '{filename}' -> '{ORIGINAL_IMAGES_SUBDIR_NAME}/'.") except Exception as e: print(f" Napaka pri premikanju originalne slike '{filename}': {e}") else: print(f" DRY RUN: Originalna slika '{filename}' bi bila premaknjena v '{ORIGINAL_IMAGES_SUBDIR_NAME}/'.") else: print(f" Preskakujem datoteko (ni slika za optimizacijo): '{filename}'.") if not optimized_images_map: print("\nNi slik za optimizacijo ali pa so že optimizirane. Preskakujem posodabljanje referenc.") print("\n--- OPTIMIZACIJA SLIK ZAKLJUČENA ---") return print("\n--- ZAČETEK POSODABLJANJA REFERENC V DATOTEKAH ---") all_files_to_update = find_files_to_update(DIRECTORIES_TO_SCAN, FILES_IN_ROOT_TO_SCAN) if not all_files_to_update: print("Ni najdenih datotek za posodobitev referenc (.html, .css, .js).") print("\n--- OPTIMIZACIJA SLIK ZAKLJUČENA ---") return updated_files_count = 0 processed_files = set() for file_path in all_files_to_update: if file_path in processed_files: continue file_changed_in_this_run = False for img_info in optimized_images_map: if update_file_references(file_path, img_info['old_name'], img_info['new_name'], args.dry_run): file_changed_in_this_run = True if file_changed_in_this_run: updated_files_count += 1 processed_files.add(file_path) print(f"\nPregledanih je bilo {len(all_files_to_update)} datotek.") print(f"Posodobljenih je bilo {updated_files_count} datotek (vključno z DRY RUN).") print("\n--- OPTIMIZACIJA SLIK ZAKLJUČENA ---") if __name__ == "__main__": main()