# StarPunk v1.4.0 Release

**Status**: Planning
**Codename**: "Media"
**Focus**: Micropub Media Endpoint, Large Image Support, Enhanced Feed Media

## Overview

This minor release significantly enhances StarPunk's media capabilities with three major features:

1. **Micropub Media Endpoint** - W3C-compliant media upload via Micropub clients
2. **Large Image Support** - Accept and resize images larger than 10MB
3. **Enhanced Feed Media** - Multiple image sizes and complete Media RSS implementation

## Features

### 1. Micropub Media Endpoint

Implement the W3C Micropub media endpoint specification, enabling Micropub clients to upload photos, audio, and video files.

#### Specification Compliance (W3C Micropub)

**Endpoint**: `POST /micropub/media`

**Request Format**:
- Content-Type: `multipart/form-data`
- Single file part named `file`
- Authorization: Bearer token with `media` or `create` scope

**Response**:
- `201 Created` with `Location` header containing the file URL
- URL should be unguessable (UUID-based, which we already do)

**Example Request**:
```http
POST /micropub/media HTTP/1.1
Authorization: Bearer xxx
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary

------WebKitFormBoundary
Content-Disposition: form-data; name="file"; filename="photo.jpg"
Content-Type: image/jpeg

[binary data]
------WebKitFormBoundary--
```

**Example Response**:
```http
HTTP/1.1 201 Created
Location: https://example.com/media/2025/01/abc123-def456.jpg
```

#### Configuration Discovery

Update `q=config` response to advertise media endpoint:
```json
{
  "media-endpoint": "https://example.com/micropub/media",
  "syndicate-to": []
}
```

#### Photo Property Support

Enable `photo` property in Micropub create requests:

**URL Reference** (photo already uploaded or external):
```
h=entry&content=Hello&photo=https://example.com/media/2025/01/abc.jpg
```

**JSON with Alt Text**:
```json
{
  "type": ["h-entry"],
  "properties": {
    "content": ["Hello world"],
    "photo": [{
      "value": "https://example.com/media/2025/01/abc.jpg",
      "alt": "A beautiful sunset"
    }]
  }
}
```

**Multiple Photos**:
```json
{
  "type": ["h-entry"],
  "properties": {
    "content": ["Photo gallery"],
    "photo": [
      "https://example.com/media/2025/01/photo1.jpg",
      "https://example.com/media/2025/01/photo2.jpg"
    ]
  }
}
```

#### Implementation Details

**New Route**: `starpunk/routes/micropub.py`
```python
@bp.route('/media', methods=['POST'])
def media_endpoint():
    # Verify bearer token (media or create scope)
    # Extract file from multipart/form-data
    # Call save_media() from media.py
    # Return 201 with Location header
```

**Modified**: `starpunk/micropub.py`
- Update `get_micropub_config()` to return media-endpoint URL
- Add `extract_photos()` function for photo property parsing
- Modify `handle_create()` to process photo URLs and attach to note

**Scope Validation**:
- Media endpoint requires `media` or `create` scope
- Photo property in create requests requires `create` scope

---

### 2. Large Image Support (>10MB)

Remove the 10MB file size rejection and instead automatically resize large images to fit within acceptable limits.

#### Current Behavior (v1.2.0)
- Files >10MB are rejected with error
- Files ≤10MB are accepted and resized if >2048px

#### New Behavior (v1.4.0)
- Files of any reasonable size accepted (new limit: 50MB)
- Images >10MB are automatically resized more aggressively
- Final output always ≤10MB after optimization

#### Resize Strategy

| Input Size | Max Dimension | Quality | Target Output |
|------------|---------------|---------|---------------|
| ≤10MB | 2048px | 95% | ≤5MB typical |
| 10-25MB | 1600px | 90% | ≤5MB target |
| 25-50MB | 1280px | 85% | ≤5MB target |
| >50MB | Rejected | - | Error message |

#### Implementation Details

**Modified**: `starpunk/media.py`

```python
def validate_image(file_data, filename):
    """Updated validation with higher limit."""
    MAX_FILE_SIZE = 50 * 1024 * 1024  # 50MB (was 10MB)
    # ... rest of validation

def optimize_image(image_data, original_size=None):
    """Enhanced optimization based on input size."""
    # Determine resize parameters based on original_size
    # More aggressive resize for larger files
    # Quality reduction for very large files
    # Iterative optimization if output still too large
```

**Quality Iteration**:
If first pass produces >10MB output:
1. Reduce max dimension by 20%
2. Reduce quality by 5%
3. Repeat until ≤10MB or min quality (70%) reached

#### User Experience
- No rejection for reasonable photo sizes
- Transparent optimization (user doesn't need to pre-resize)
- Warning in response if significant quality reduction applied
- Original dimensions preserved in EXIF if possible

---

### 3. Enhanced Feed Media Support

Implement ADR-059 Phase A: Multiple image sizes and complete Media RSS implementation.

#### Multiple Image Sizes (Thumbnails)

Generate multiple renditions on upload:

| Variant | Dimensions | Use Case |
|---------|------------|----------|
| `thumb` | 150×150 (square crop) | Thumbnails, previews |
| `small` | 320px width | Mobile, low bandwidth |
| `medium` | 640px width | Standard display |
| `large` | 1280px width | High-res display |
| `original` | As uploaded (≤2048px) | Full quality |

**Database Schema** (new migration):
```sql
CREATE TABLE media_variants (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    media_id INTEGER NOT NULL,
    variant_type TEXT NOT NULL,  -- 'thumb', 'small', 'medium', 'large', 'original'
    path TEXT NOT NULL,
    width INTEGER NOT NULL,
    height INTEGER NOT NULL,
    size_bytes INTEGER NOT NULL,
    FOREIGN KEY (media_id) REFERENCES media(id) ON DELETE CASCADE,
    UNIQUE(media_id, variant_type)
);

CREATE INDEX idx_media_variants_media ON media_variants(media_id);
```

**Storage Structure**:
```
/media/2025/01/
├── abc123.jpg           # Original/large
├── abc123_medium.jpg    # 640px
├── abc123_small.jpg     # 320px
└── abc123_thumb.jpg     # 150×150
```

#### Complete Media RSS Implementation

Enhance RSS feeds with full Media RSS specification support:

```xml
<item>
  <title>My Photo Post</title>
  <media:group>
    <media:content url="https://.../large.jpg"
                   type="image/jpeg"
                   medium="image"
                   isDefault="true"
                   width="1280" height="960"
                   fileSize="245760"/>
    <media:content url="https://.../medium.jpg"
                   type="image/jpeg"
                   medium="image"
                   width="640" height="480"
                   fileSize="98304"/>
    <media:content url="https://.../small.jpg"
                   type="image/jpeg"
                   medium="image"
                   width="320" height="240"
                   fileSize="32768"/>
  </media:group>
  <media:thumbnail url="https://.../thumb.jpg"
                   width="150" height="150"/>
  <media:title type="plain">Image caption here</media:title>
</item>
```

**New Media RSS Elements**:
- `<media:group>` - Container for multiple renditions
- `<media:content>` with full attributes (width, height, fileSize, medium, isDefault)
- `<media:thumbnail>` with dimensions
- `<media:title>` for captions (type="plain")

#### Enhanced JSON Feed Attachments

```json
{
  "items": [{
    "id": "...",
    "image": "https://.../large.jpg",
    "attachments": [
      {
        "url": "https://.../large.jpg",
        "mime_type": "image/jpeg",
        "title": "Image caption",
        "size_in_bytes": 245760
      }
    ],
    "_starpunk": {
      "media_variants": {
        "thumb": "https://.../thumb.jpg",
        "small": "https://.../small.jpg",
        "medium": "https://.../medium.jpg",
        "large": "https://.../large.jpg"
      }
    }
  }]
}
```

#### ATOM Feed Enclosures

Add proper enclosure links to ATOM entries:
```xml
<entry>
  <link rel="enclosure"
        type="image/jpeg"
        length="245760"
        title="Image caption"
        href="https://.../large.jpg"/>
</entry>
```

---

## Implementation Phases

### Phase 1: Large Image Support (4-6 hours)
- Update `validate_image()` with 50MB limit
- Implement tiered resize strategy in `optimize_image()`
- Add iterative quality reduction
- Update tests for new limits

### Phase 2: Image Variants (8-12 hours)
- Create migration for `media_variants` table
- Implement variant generation in `save_media()`
- Update `get_note_media()` to include variants
- Add variant serving routes
- Update templates for responsive images

### Phase 3: Micropub Media Endpoint (6-8 hours)
- Create `/micropub/media` route
- Update `q=config` response
- Implement `photo` property parsing
- Update `handle_create()` for photo attachment
- Add scope validation for media uploads

### Phase 4: Enhanced Feed Media (6-8 hours)
- Update RSS generator for `<media:group>` and variants
- Update JSON Feed for variants in `_starpunk` extension
- Add ATOM enclosure links
- Update feed tests

### Phase 5: Testing & Documentation (4-6 hours)
- Comprehensive test suite for all new features
- Update API documentation
- Update architecture documentation
- Update CHANGELOG

**Total Estimated Effort**: 28-40 hours

---

## Technical Notes

### Backward Compatibility
- Existing media continues to work (no variants, single size)
- Feeds gracefully handle notes with/without variants
- Micropub clients without media support continue to work

### Performance Considerations
- Variant generation is synchronous on upload (acceptable for single-user)
- Consider background processing for v1.5.0 if needed
- Cache headers on all media variants (1 year immutable)

### Storage Impact
- ~4x storage per image (thumb + small + medium + large)
- Consider cleanup of unused uploaded media
- Document storage requirements in deployment guide

### Security
- Media endpoint requires valid bearer token
- File type validation (images only for v1.4.0)
- UUID filenames prevent enumeration
- Path traversal protection maintained

---

## Out of Scope (Deferred)

### v1.5.0 or Later
- Audio/podcast support (ADR-059 Phase B)
- Video support (ADR-059 Phase C)
- Micropub update/delete operations
- Background media processing
- CDN integration

### Not Planned
- External media hosting (Cloudinary, etc.)
- Media transcoding
- Live photo/HEIC support

---

## Dependencies

- v1.3.x complete (tags feature)
- Pillow library (already installed)
- No new external dependencies

## Success Criteria

1. Micropub clients can upload media via media endpoint
2. Photos attached to notes via Micropub `photo` property
3. Images >10MB accepted and resized appropriately
4. All image variants generated and served
5. Feed readers see proper Media RSS with variants
6. All existing tests continue to pass
7. New comprehensive test coverage for media features

## Related Documentation

- [W3C Micropub Specification](https://www.w3.org/TR/micropub/)
- [Media RSS Specification](https://www.rssboard.org/media-rss)
- ADR-057: Media Attachment Model
- ADR-058: Image Optimization Strategy
- ADR-059: Full Feed Media Standardization
- `docs/architecture/syndication-architecture.md`
