2025-11-13 11:08:49 +10:00
2025-11-12 11:12:29 +10:00
2025-11-13 11:08:49 +10:00
2025-11-13 11:08:49 +10:00
🐳 docker
2025-11-06 22:30:56 +10:00
2025-11-07 16:37:10 +10:00
2025-11-06 22:08:29 +10:00
2025-11-13 11:08:49 +10:00
2025-11-13 11:08:49 +10:00
🐳 docker
2025-11-06 22:30:56 +10:00
🐳 docker
2025-11-06 22:30:56 +10:00
2025-11-12 11:23:05 +10:00
2025-11-12 10:48:35 +10:00

Sunday Comics - Webcomic Flask App

A Flask-based webcomic website with server-side rendering using Jinja2 templates.

Features

  • Comic viewer with navigation (First, Previous, Next, Latest)
  • Client-side navigation using JSON API (no page reloads)
  • Archive page with thumbnail grid
  • RSS feed support
  • JSON API for programmatic access
  • Open Graph and Twitter Card metadata for social sharing
  • Responsive design
  • Server-side rendering with Jinja2
  • Clean, comic-focused layout

Project Structure

sunday/
├── app.py                    # Main Flask application
├── comics_data.py            # Comic data (edit this to add comics)
├── requirements.txt          # Python dependencies
├── Dockerfile                # Production Docker image
├── docker-compose.yml        # Docker Compose configuration
├── .dockerignore             # Docker build exclusions
├── scripts/                  # Utility scripts
│   ├── add_comic.py         # Script to add new comic entries
│   └── generate_rss.py      # Script to generate RSS feed
├── templates/                # Jinja2 templates
│   ├── base.html            # Base template with navigation
│   ├── index.html           # Latest comic page
│   ├── comic.html           # Individual comic viewer
│   ├── archive.html         # Archive grid
│   ├── about.html           # About page
│   └── 404.html             # Error page
└── static/                  # Static files
    ├── css/
    │   └── style.css        # Main stylesheet
    ├── js/
    │   └── comic-nav.js     # Client-side navigation
    ├── images/              # Image directory
    │   ├── comics/          # Comic images
    │   └── thumbs/          # Thumbnail images for archive
    └── feed.rss             # RSS feed (generated)

Setup

  1. Install dependencies:
pip install -r requirements.txt
  1. Run the application:
python app.py
  1. Visit http://127.0.0.1:3000 in your browser

Environment Variables

The app can be configured via environment variables:

  • SECRET_KEY - Flask secret key (defaults to 'your-secret-key')
  • PORT - Port to run on (defaults to 3000)
  • DEBUG - Enable debug mode (defaults to False)

Development:

export DEBUG=True
python app.py

Production:

export SECRET_KEY="your-secure-random-secret-key"
export PORT=3000
python app.py

Adding Comics

Comics are stored in the COMICS list in comics_data.py. Each comic entry:

{
    'number': 1,                           # Comic number (required, sequential)
    'filename': 'comic-001.png',           # Image filename (required)
    'date': '2025-01-01',                  # Publication date (required)
    'alt_text': 'Alt text for comic',      # Accessibility text (required)
    'title': 'Comic Title',                # Title (optional, shows #X if absent)
    'author_note': 'Optional note'         # Author note (optional)
}

Adding a New Comic

Option 1: Use the script (recommended)

# Add comic entry only
python scripts/add_comic.py

# Add comic entry AND create markdown file for author notes
python scripts/add_comic.py -m

This will automatically add a new entry with defaults. The -m flag creates a markdown file in content/author_notes/{date}.md with a template. Then edit comics_data.py to customize.

Option 2: Manual

  1. Save your comic image in static/images/comics/ (e.g., comic-001.png)
  2. Optionally, create a thumbnail in static/images/thumbs/ with the same filename
  3. Add the comic entry to the COMICS list in comics_data.py

Generating RSS Feed

After adding comics, regenerate the RSS feed:

python scripts/generate_rss.py

This creates/updates static/feed.rss

Production Deployment

For production, you should NOT use Flask's built-in development server. Choose one of the following deployment methods:

1. Generate a secure secret key:

python -c "import secrets; print(secrets.token_hex(32))"

2. Create a .env file:

SECRET_KEY=your-generated-secret-key-here

3. Build and run with Docker Compose:

docker-compose up -d

Or build and run manually:

# Build the image
docker build -t sunday-comics .

# Run the container
docker run -d \
  -p 3000:3000 \
  -e SECRET_KEY="your-secret-key" \
  -v $(pwd)/comics_data.py:/app/comics_data.py:ro \
  -v $(pwd)/static/images:/app/static/images:ro \
  --name sunday-comics \
  sunday-comics

View logs:

docker-compose logs -f

Option 2: Manual Deployment with Gunicorn

1. Generate a Secure Secret Key

python -c "import secrets; print(secrets.token_hex(32))"

2. Set Environment Variables

export SECRET_KEY="generated-secret-key-from-above"
export DEBUG=False
export PORT=3000

3. Use a Production WSGI Server

Install Gunicorn:

pip install gunicorn

Run with Gunicorn:

gunicorn app:app --bind 0.0.0.0:3000 --workers 4

Set up Nginx or another reverse proxy in front of your app for:

  • HTTPS/SSL termination
  • Static file serving
  • Load balancing
  • Better security

Additional Production Considerations

  • Use a process manager (systemd, supervisor) for non-Docker deployments
  • Set appropriate file permissions
  • Enable HTTPS with Let's Encrypt
  • Consider using a CDN for static assets
  • Monitor logs and performance
  • Set up automated backups of comics_data.py

Upgrading to a Database

For larger comic archives, consider replacing the COMICS list with a database:

  • SQLite for simple setups
  • PostgreSQL/MySQL for production
  • Use Flask-SQLAlchemy for ORM support

Customization

Branding

  • Update "Sunday Comics" references in templates/base.html
  • Update site title and footer text

Styling

  • Modify static/css/style.css to change colors, fonts, and layout
  • Current color scheme uses blue (#3498db) and dark blue-gray (#2c3e50)

About Page

  • Edit templates/about.html to add your bio and comic information

Pages

  • / - Shows the latest comic
  • /comic/<id> - View a specific comic by number
  • /archive - Browse all comics in a grid
  • /about - About the comic and author
  • /static/feed.rss - RSS feed

API Endpoints

The app exposes a JSON API for programmatic access:

  • GET /api/comics - Returns all comics as a JSON array

    [
      {
        "number": 1,
        "title": "First Comic",
        "filename": "comic-001.png",
        "date": "2025-01-01",
        "alt_text": "The very first comic",
        "author_note": "This is where your comic journey begins!"
      }
    ]
    
  • GET /api/comics/<id> - Returns a specific comic as JSON

    {
      "number": 1,
      "title": "First Comic",
      "filename": "comic-001.png",
      "date": "2025-01-01",
      "alt_text": "The very first comic",
      "author_note": "This is where your comic journey begins!"
    }
    

    Returns 404 with {"error": "Comic not found"} if the comic doesn't exist.

Credits

License

[Add your license here]

Description
Simple, stylish, and snappy template for hosting comics.
Readme MIT 2.2 MiB
Languages
Python 31.7%
HTML 23.7%
JavaScript 23.5%
CSS 20.3%
Dockerfile 0.8%