diff --git a/docs/projectplan/BACKLOG.md b/docs/projectplan/BACKLOG.md index 2d90b87..3942f59 100644 --- a/docs/projectplan/BACKLOG.md +++ b/docs/projectplan/BACKLOG.md @@ -29,7 +29,7 @@ ## High -### Enhanced Feed Media Support +### Enhanced Feed Media Support *(Scheduled: v1.4.0)* - Multiple image sizes/thumbnails (150px, 320px, 640px, 1280px) - Full Media RSS implementation (media:group, all attributes) - Enhanced JSON Feed attachments diff --git a/docs/projectplan/v1.4.0/RELEASE.md b/docs/projectplan/v1.4.0/RELEASE.md new file mode 100644 index 0000000..a8ba6b1 --- /dev/null +++ b/docs/projectplan/v1.4.0/RELEASE.md @@ -0,0 +1,401 @@ +# 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 + + My Photo Post + + + + + + + Image caption here + +``` + +**New Media RSS Elements**: +- `` - Container for multiple renditions +- `` with full attributes (width, height, fileSize, medium, isDefault) +- `` with dimensions +- `` 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 + + + +``` + +--- + +## 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 `` 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`