#!/usr/bin/env python3 """ Asset build script for Kobelly's Base website Handles CSS and JS minification with cache busting """ import os import hashlib import shutil from datetime import datetime from cssmin import cssmin from jsmin import jsmin def get_file_hash(filepath): """Generate MD5 hash of file content for cache busting""" with open(filepath, 'rb') as f: return hashlib.md5(f.read()).hexdigest()[:8] def minify_css(input_file, output_file): """Minify CSS file""" try: with open(input_file, 'r', encoding='utf-8') as f: css_content = f.read() minified_css = cssmin(css_content) with open(output_file, 'w', encoding='utf-8') as f: f.write(minified_css) print(f"✓ CSS minified: {input_file} → {output_file}") return True except Exception as e: print(f"✗ Error minifying CSS {input_file}: {e}") return False def minify_js(input_file, output_file): """Minify JavaScript file""" try: with open(input_file, 'r', encoding='utf-8') as f: js_content = f.read() minified_js = jsmin(js_content) with open(output_file, 'w', encoding='utf-8') as f: f.write(minified_js) print(f"✓ JS minified: {input_file} → {output_file}") return True except Exception as e: print(f"✗ Error minifying JS {input_file}: {e}") return False def create_cache_busted_assets(): """Create cache-busted versions of assets""" static_dir = 'static' css_dir = os.path.join(static_dir, 'css') js_dir = os.path.join(static_dir, 'js') # Ensure directories exist os.makedirs(css_dir, exist_ok=True) os.makedirs(js_dir, exist_ok=True) # CSS files css_files = [ ('main.css', 'main.min.css') ] # JS files js_files = [ ('main.js', 'main.min.js') ] print("🔨 Building assets...") print(f"📅 Build time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") print() # Process CSS files for input_file, output_file in css_files: input_path = os.path.join(css_dir, input_file) output_path = os.path.join(css_dir, output_file) if os.path.exists(input_path): if minify_css(input_path, output_path): # Generate cache-busted filename file_hash = get_file_hash(output_path) cache_busted_name = f"main.{file_hash}.min.css" cache_busted_path = os.path.join(css_dir, cache_busted_name) # Copy minified file to cache-busted version shutil.copy2(output_path, cache_busted_path) print(f"✓ Cache-busted CSS created: {cache_busted_name}") else: print(f"⚠️ CSS file not found: {input_path}") print() # Process JS files for input_file, output_file in js_files: input_path = os.path.join(js_dir, input_file) output_path = os.path.join(js_dir, output_file) if os.path.exists(input_path): if minify_js(input_path, output_path): # Generate cache-busted filename file_hash = get_file_hash(output_path) cache_busted_name = f"main.{file_hash}.min.js" cache_busted_path = os.path.join(js_dir, cache_busted_name) # Copy minified file to cache-busted version shutil.copy2(output_path, cache_busted_path) print(f"✓ Cache-busted JS created: {cache_busted_name}") else: print(f"⚠️ JS file not found: {input_path}") print() print("🎉 Asset build completed!") def clean_old_assets(): """Clean old cache-busted assets""" static_dir = 'static' css_dir = os.path.join(static_dir, 'css') js_dir = os.path.join(static_dir, 'js') # Remove old cache-busted files for directory in [css_dir, js_dir]: if os.path.exists(directory): for filename in os.listdir(directory): if filename.startswith('main.') and filename.endswith('.min.css') or filename.endswith('.min.js'): if not filename in ['main.min.css', 'main.min.js']: # Keep the base minified files filepath = os.path.join(directory, filename) os.remove(filepath) print(f"🗑️ Removed old asset: {filename}") if __name__ == '__main__': import sys if len(sys.argv) > 1 and sys.argv[1] == 'clean': print("🧹 Cleaning old assets...") clean_old_assets() print("✓ Cleanup completed!") else: clean_old_assets() create_cache_busted_assets()