# Plan: Standardized Filename Format with EXIF Metadata

## Overview
Standardize filenames across all download platforms to a consistent format while storing descriptive metadata (title, caption, description) in file EXIF/metadata rather than filenames.

### Target Filename Format
```
{source}_{YYYYMMDD}_{HHMMSS}_{media_id}.{ext}
```

### Current vs Target by Platform

| Platform | Current Format | Status |
|----------|---------------|--------|
| Instagram | `evalongoria_20251016_123456_18529350958013602.jpg` | Already correct |
| Snapchat | `evalongoria_20251113_140600_Xr8sJ936p31PrqwxCaDKQ.mp4` | Already correct |
| TikTok | `20251218_title here_7585297468103855391_0.mp4` | Needs change |
| YouTube | `title [video_id].mp4` | Needs change |
| Dailymotion | `title_video_id.mp4` | Needs change |
| Bilibili | `title_video_id.mp4` | Needs change |
| Erome | `title_video_id.mp4` | Needs change |

### User Preferences (Confirmed)
- **Migration**: Migrate existing files to new format
- **Video metadata**: Use ffmpeg remux (fast, no re-encoding)
- **Missing date**: Use existing filesystem timestamp
- **Channel folders**: Organize video downloads by channel subfolder (except TikTok)

### Target Directory Structure

Videos (except TikTok) will be organized by channel:
```
/opt/immich/md/youtube/{channel_name}/{filename}.mp4
/opt/immich/md/dailymotion/{channel_name}/{filename}.mp4
/opt/immich/md/bilibili/{channel_name}/{filename}.mp4
/opt/immich/md/erome/{channel_name}/{filename}.mp4
```

TikTok stays flat (no channel folders):
```
/opt/immich/md/tiktok/{filename}.mp4
```

Example:
- Before: `/opt/immich/md/youtube/20251112_Video Title_abc123.mp4`
- After: `/opt/immich/md/youtube/snapthefamous/snapthefamous_20251112_abc123.mp4`

### Existing Metadata Status

yt-dlp already embeds: `title`, `artist`, `date`, `comment` (URL), `description`, `synopsis`

| Platform | Has Embedded Metadata? | Migration Action |
|----------|----------------------|------------------|
| YouTube | Yes (verified via ffprobe) | Rename only |
| Dailymotion | Yes (yt-dlp) | Rename only |
| Bilibili | Yes (verified via ffprobe) | Rename only |
| Erome | Yes (yt-dlp) | Rename only |
| TikTok | No | Rename + write metadata |
| Instagram | No | Rename + write metadata |
| Snapchat | No | Filename already OK, add metadata |

**Key insight:** Existing files have embedded metadata but the lightbox doesn't READ it.
The lightbox only shows database fields, not actual file metadata.

---

## Phase 1: Create Shared Metadata Utilities

**New file:** `/opt/media-downloader/modules/metadata_utils.py`

### Functions:
- `write_image_metadata(file_path, metadata)` - Write to EXIF via exiftool
- `write_video_metadata(file_path, metadata)` - Write via ffmpeg remux
- `read_file_metadata(file_path)` - Read existing metadata
- `generate_standardized_filename(source, date, media_id, ext)` - Generate standard filename

### EXIF Fields for Images:
- `ImageDescription`: title/caption
- `XPComment`: full description
- `Artist`: source/uploader
- `DateTimeOriginal`: post date
- `UserComment`: source URL

### Video Metadata Fields:
- `title`, `artist`, `description`, `comment`, `date`

---

## Phase 2: Update Instagram Modules (Caption Storage)

Currently caption is extracted but discarded. Store in `downloads.metadata` JSON.

**Files:**
- `/opt/media-downloader/modules/imginn_module.py` - Extract caption in `_download_post()`
- `/opt/media-downloader/modules/fastdl_module.py` - Extract in download methods
- `/opt/media-downloader/modules/toolzu_module.py` - Extract caption if available

---

## Phase 3: Update Universal Video Downloader

**File:** `/opt/media-downloader/modules/universal_video_downloader.py`

**Note:** yt-dlp already embeds metadata via `--add-metadata` (line 1104). We need to:
1. Change the filename format
2. Add channel subfolder to output path

### Changes:

1. **Sanitize channel name** for folder:
```python
def sanitize_channel_name(name: str) -> str:
    """Sanitize channel name for use as folder name."""
    if not name:
        return 'unknown'
    # Remove/replace invalid filesystem characters
    sanitized = re.sub(r'[<>:"/\\|?*]', '', name)
    sanitized = sanitized.strip('. ')
    return sanitized[:50] or 'unknown'  # Limit length
```

2. **Update output template** to include channel folder:
```python
# Get channel name from video info first
info = yt_dlp.YoutubeDL({'quiet': True}).extract_info(url, download=False)
channel = sanitize_channel_name(info.get('uploader') or info.get('channel'))

# Create channel subfolder
channel_dir = Path(output_dir) / channel
channel_dir.mkdir(parents=True, exist_ok=True)

'outtmpl': f'{channel_dir}/%(uploader)s_%(upload_date)s_%(id)s.%(ext)s'
```

**No additional metadata writing needed** - yt-dlp already embeds title, artist, description, date.

---

## Phase 4: Update TikTok Module

**File:** `/opt/media-downloader/modules/tiktok_module.py`

Change filename from:
```python
filename = f"{date_str}_{clean_title}_{video_id}_{idx}.{ext}"
```

To:
```python
filename = f"{username}_{date_str}_{video_id}.{ext}"
```

**TikTok NEEDS metadata writing** - unlike yt-dlp platforms, TikTok downloads don't have embedded metadata.
Call `write_video_metadata()` after download with title, description, username.

---

## Phase 5: Create Migration Script

**New file:** `/opt/media-downloader/scripts/migrate_filenames.py`

### Functionality:
1. Query `file_inventory` for all files
2. Parse current filename to extract components
3. Look up metadata in DB (`downloads`, `video_downloads`)
4. Generate new standardized filename
5. **For videos (except TikTok)**: Create channel subfolder and move file
6. Rename file if needed
7. Update `file_inventory.filename` and `file_inventory.file_path`
8. Write metadata to file EXIF/ffmpeg (for TikTok/Instagram only)
9. Create backup list for rollback

### Video Migration (Channel Folders):
```python
# For YouTube, Dailymotion, Bilibili, Erome videos
if platform in ['youtube', 'dailymotion', 'bilibili', 'erome']:
    # Get channel from video_downloads table
    channel = get_channel_from_db(video_id) or extract_from_embedded_metadata(file_path)
    channel_safe = sanitize_channel_name(channel)

    # New path: /opt/immich/md/youtube/channelname/file.mp4
    new_dir = Path(base_dir) / platform / channel_safe
    new_dir.mkdir(parents=True, exist_ok=True)

    new_path = new_dir / new_filename
    shutil.move(old_path, new_path)
```

### Missing date handling:
- Use file's `mtime` (modification time)
- Format as `YYYYMMDD_HHMMSS`

### Missing channel handling:
- Read from `video_downloads.uploader` in database
- Fall back to reading embedded metadata via ffprobe
- Last resort: use "unknown" folder

---

## Phase 6: Update move_module.py

**File:** `/opt/media-downloader/modules/move_module.py`

After moving file, call metadata writer:
```python
if is_image:
    write_image_metadata(dest, {'title': caption, 'artist': source, ...})
elif is_video:
    write_video_metadata(dest, {...})
```

---

## Phase 7: Add Metadata Display to Lightbox ✅ COMPLETED

**Status:** Implemented on 2025-12-21

The EnhancedLightbox now displays embedded metadata from video files.

### What was implemented:
- **Backend**: `GET /api/media/embedded-metadata` endpoint using ffprobe/exiftool
- **Frontend**: Fetches metadata when Details panel is opened
- **Display**: Shows Title and Description from embedded file metadata

### Files modified:
- `/opt/media-downloader/web/backend/routers/media.py` - Added endpoint
- `/opt/media-downloader/web/frontend/src/components/EnhancedLightbox.tsx` - Added UI

---

## Implementation Order

1. ~~Phase 7: Add metadata display to lightbox~~ ✅ DONE
2. Phase 1: Create `metadata_utils.py` (foundation)
3. Phase 3: Update universal video downloader (filename + channel folders)
4. Phase 4: Update TikTok module (filename only, no channel folders)
5. Phase 2: Update Instagram modules (caption storage)
6. Phase 6: Update move_module.py
7. Phase 5: Create and run migration script (last - after all new code works)

---

## Files Summary

### New files:
- `/opt/media-downloader/modules/metadata_utils.py`
- `/opt/media-downloader/scripts/migrate_filenames.py`

### Modified files:
- `/opt/media-downloader/modules/universal_video_downloader.py`
- `/opt/media-downloader/modules/tiktok_module.py`
- `/opt/media-downloader/modules/imginn_module.py`
- `/opt/media-downloader/modules/fastdl_module.py`
- `/opt/media-downloader/modules/toolzu_module.py`
- `/opt/media-downloader/modules/move_module.py`
- `/opt/media-downloader/web/frontend/src/components/EnhancedLightbox.tsx`
- `/opt/media-downloader/web/backend/routers/media.py`

---

## Pages Using EnhancedLightbox (Automatic Benefits)

These pages use EnhancedLightbox and will automatically get embedded metadata display:
- VideoDownloader.tsx (history section)
- Downloads.tsx
- Media.tsx
- Review.tsx
- RecycleBin.tsx
- Discovery.tsx
- Notifications.tsx
- Dashboard.tsx

**No additional changes needed** - updating EnhancedLightbox updates all pages.

---

## Pages with Custom Video Modals (Need Separate Updates)

**1. DownloadQueue.tsx** (custom Video Player Modal):
- Currently shows: title, channel_name, upload_date from database
- For completed downloads: Add embedded metadata display (title, description)
- For queued items: No file exists yet, keep using DB fields

**2. CelebrityDiscovery.tsx** (inline video elements):
- Consider adding metadata info panel or tooltip
- Lower priority - mainly for browsing/discovery, not viewing downloads

---

## Version
This will be version **11.17.0** (minor release - new feature)
