add automation to create image-manifest.json
Hunter
Friday, July 11th, 2025 at 6:08 PM
1 +name: Generate Image Manifest
2 +
3 +on:
4 + push:
5 + branches: [ main ]
6 + paths: [ 'images/**' ] # Only run when images are added/changed
7 + workflow_dispatch: # Allow manual trigger
8 +
9 +jobs:
10 + generate-manifest:
11 + runs-on: ubuntu-latest
12 +
13 + steps:
14 + - name: Checkout repository
15 + uses: actions/checkout@v4
16 + with:
17 + token: ${{ secrets.GITHUB_TOKEN }}
18 +
19 + - name: Set up Python
20 + uses: actions/setup-python@v4
21 + with:
22 + python-version: '3.x'
23 +
24 + - name: Generate image manifest
25 + run: python generate_image_manifest.py
26 +
27 + - name: Check for changes
28 + id: verify-changed-files
29 + run: |
30 + if [ -n "$(git status --porcelain)" ]; then
31 + echo "changed=true" >> $GITHUB_OUTPUT
32 + else
33 + echo "changed=false" >> $GITHUB_OUTPUT
34 + fi
35 +
36 + - name: Commit and push changes
37 + if: steps.verify-changed-files.outputs.changed == 'true'
38 + run: |
39 + git config --local user.email "action@github.com"
40 + git config --local user.name "GitHub Action"
41 + git add image-manifest.json
42 + git commit -m "Auto-update image manifest [skip ci]"
43 + git push
1 +#!/usr/bin/env python3
2 +"""
3 +Generate image manifest for PWA caching
4 +Scans the images/ directory and creates a JSON manifest file
5 +"""
6 +
7 +import os
8 +import json
9 +from pathlib import Path
10 +
11 +def generate_image_manifest():
12 + """Generate a JSON manifest of all images in the images/ directory"""
13 +
14 + # Define supported image extensions
15 + image_extensions = {'.png', '.jpg', '.jpeg', '.gif', '.svg', '.webp', '.ico', '.bmp'}
16 +
17 + # Get the directory where this script is located
18 + script_dir = Path(__file__).parent
19 + images_dir = script_dir / 'images'
20 +
21 + # Check if images directory exists
22 + if not images_dir.exists():
23 + print(f"Images directory not found: {images_dir}")
24 + return
25 +
26 + # Collect all image files
27 + image_files = []
28 +
29 + for file_path in images_dir.iterdir():
30 + if file_path.is_file() and file_path.suffix.lower() in image_extensions:
31 + # Create relative path from web root
32 + relative_path = f"/images/{file_path.name}"
33 + image_files.append(relative_path)
34 +
35 + # Sort for consistent output
36 + image_files.sort()
37 +
38 + # Create manifest object
39 + manifest = {
40 + "images": image_files,
41 + "generated_at": "auto-generated by GitHub Actions",
42 + "total_images": len(image_files)
43 + }
44 +
45 + # Write manifest file
46 + manifest_path = script_dir / 'image-manifest.json'
47 + with open(manifest_path, 'w', encoding='utf-8') as f:
48 + json.dump(manifest, f, indent=2, sort_keys=True)
49 +
50 + print(f"Generated manifest with {len(image_files)} images:")
51 + for img in image_files:
52 + print(f" - {img}")
53 +
54 + return manifest
55 +
56 +if __name__ == "__main__":
57 + manifest = generate_image_manifest()
58 + print(f"\nManifest saved to: image-manifest.json")
1 +{
2 + "generated_at": "auto-generated by GitHub Actions",
3 + "images": [
4 + "/images/ceedee.gif",
5 + "/images/floppy.gif",
6 + "/images/mac.png",
7 + "/images/pika_construction.gif",
8 + "/images/pizza.gif",
9 + "/images/rollerskate.png",
10 + "/images/scared_mouse.gif",
11 + "/images/sun.png",
12 + "/images/underconstruction.gif",
13 + "/images/welcome.gif",
14 + "/images/windows.gif"
15 + ],
16 + "total_images": 11
17 +}
-const CACHE_NAME = 'web-workshop-v3';
1 +const CACHE_NAME = 'web-workshop-v4';
2 const urlsToCache = [
3 '/',
4 '/index.html',
44 }
45 }
46
-// Function to programmatically cache all images
47 +// Function to cache all images using the generated manifest
48 async function cacheImages(cache) {
- const imageExtensions = ['png', 'jpg', 'jpeg', 'gif', 'svg', 'webp'];
-
49 try {
- const response = await fetch('/images/');
50 + const response = await fetch('/image-manifest.json');
51 if (response.ok) {
- const html = await response.text();
- const imagePattern = new RegExp(`href="([^"]*\\.(${imageExtensions.join('|')}))"`, 'gi');
- const links = html.match(imagePattern);
52 + const manifest = await response.json();
53 + console.log(`Caching ${manifest.total_images} images from manifest`);
54
- if (links) {
- const imageFiles = links.map(link => {
- const match = link.match(/href="([^"]*)"/);
- return match ? '/images/' + match[1] : null;
- }).filter(Boolean);
-
- for (const imageFile of imageFiles) {
- try {
- await cache.add(imageFile);
- console.log(`Cached image: ${imageFile}`);
- } catch (e) {
- console.log(`Failed to cache image ${imageFile}:`, e);
- }
55 + for (const imagePath of manifest.images) {
56 + try {
57 + await cache.add(imagePath);
58 + console.log(`Cached image: ${imagePath}`);
59 + } catch (e) {
60 + console.log(`Failed to cache image ${imagePath}:`, e);
61 }
62 }
63 + } else {
64 + console.log('No image manifest found, skipping image caching');
65 }
66 } catch (e) {
- console.log('Failed to cache images directory:', e);
67 + console.log('Failed to load image manifest:', e);
68 }
69 }
70