Aiwg export
Export media collection to platform-specific formats (Plex, Jellyfin, MPD, mobile, archival)
git clone https://github.com/jmagly/aiwg
T=$(mktemp -d) && git clone --depth=1 https://github.com/jmagly/aiwg "$T" && mkdir -p ~/.claude/skills && cp -r "$T/.agents/skills/export" ~/.claude/skills/jmagly-aiwg-export && rm -rf "$T"
.agents/skills/export/SKILL.mdExport Media Collection
Export a curated media collection to platform-specific formats with appropriate transcoding, metadata, and directory structures.
Purpose
Users consume media across diverse platforms, each with different format requirements, metadata standards, and organizational conventions. This command transforms a curated collection into the optimal structure for each target platform.
Platform Profiles
Plex Profile
Formats:
- Audio: FLAC (preferred), MP3 (320kbps), M4A (AAC)
- Video: MP4 (H.264/H.265), MKV
- Artwork: Embedded +
in album directoryfolder.jpg
Directory Structure:
Music/ ├── Artist Name/ │ ├── Album Name (Year)/ │ │ ├── folder.jpg │ │ ├── 01 - Track Title.flac │ │ ├── 02 - Track Title.flac │ │ └── ... │ └── Videos/ │ └── Video Title.mp4
YAML Spec:
profile: plex audio_formats: [flac, mp3, m4a] video_formats: [mp4, mkv] artwork: embedded: true folder_jpg: true max_resolution: 1500x1500 directory_pattern: "{artist}/{album} ({year})/{track:02d} - {title}.{ext}" video_directory: "{artist}/Videos/{title}.{ext}" metadata: prefer_embedded: true id3v2_version: 2.4
Jellyfin Profile
Formats:
- Audio: FLAC (preferred), Opus, MP3
- Video: MP4, MKV, WebM
- Artwork: Embedded +
+folder.jpgartist.jpg - NFO: Supported for rich metadata
Directory Structure:
Music/ ├── Artist Name/ │ ├── artist.jpg │ ├── artist.nfo │ ├── Album Name (Year)/ │ │ ├── folder.jpg │ │ ├── album.nfo │ │ ├── 01 - Track Title.flac │ │ └── ... │ └── Videos/ │ ├── Video Title.mp4 │ └── Video Title.nfo
YAML Spec:
profile: jellyfin audio_formats: [flac, opus, mp3] video_formats: [mp4, mkv, webm] artwork: embedded: true folder_jpg: true artist_jpg: true max_resolution: 1500x1500 nfo_files: album: true artist: true video: true directory_pattern: "{artist}/{album} ({year})/{track:02d} - {title}.{ext}" video_directory: "{artist}/Videos/{title}.{ext}" metadata: prefer_embedded: true id3v2_version: 2.4
MPD Profile
Formats:
- Audio: FLAC (preferred), Opus, MP3
- Artwork:
in album directoryfolder.jpg
Directory Structure:
Music/ ├── Artist Name/ │ └── Album Name/ │ ├── folder.jpg │ ├── 01 - Track Title.flac │ └── ...
YAML Spec:
profile: mpd audio_formats: [flac, opus, mp3] artwork: embedded: true folder_jpg: true max_resolution: 1000x1000 directory_pattern: "{artist}/{album}/{track:02d} - {title}.{ext}" metadata: prefer_embedded: true id3v2_version: 2.4 scanning: auto_rescan: true watch_mode: inotify
Mobile Profile
Formats:
- Audio: Opus (preferred, 128-192kbps), M4A (AAC), MP3
- Video: MP4 (H.264, max 720p)
- Artwork: Embedded, max 500x500
Size Constraints:
- Transcode high-res audio to save space
- Limit video resolution
- Budget-aware export (stop when size limit reached)
YAML Spec:
profile: mobile audio_formats: [opus, m4a, mp3] audio_quality: opus: 128k m4a: 192k mp3: 192k video_formats: [mp4] video_quality: max_resolution: 720p codec: h264 bitrate: 1500k artwork: embedded: true max_resolution: 500x500 transcode: always: true source_formats: [flac, wav, alac] size_budget: enabled: true prioritize_by: importance directory_pattern: "{artist}/{album}/{track:02d} - {title}.{ext}"
Archival Profile
Formats:
- Audio: FLAC, WAV (no lossy formats)
- Video: MKV (preserve original quality)
- Checksums: SHA256SUMS
- Provenance: PROVENANCE.jsonld
Directory Structure:
Archive/ ├── Artist Name/ │ ├── Album Name (Year)/ │ │ ├── 01 - Track Title.flac │ │ ├── ... │ │ ├── SHA256SUMS │ │ ├── PROVENANCE.jsonld │ │ └── folder.jpg │ └── MANIFEST.json
YAML Spec:
profile: archival audio_formats: [flac, wav] video_formats: [mkv] preserve: original_filenames: true source_metadata: true acquisition_dates: true checksums: algorithm: sha256 filename: SHA256SUMS provenance: format: jsonld filename: PROVENANCE.jsonld include_source_urls: true include_timestamps: true manifest: per_album: false per_artist: true format: json directory_pattern: "{artist}/{album} ({year})/{original_filename}"
Transcoding Commands
Audio Transcoding
FLAC to Opus:
ffmpeg -i input.flac -c:a libopus -b:a 128k -vn output.opus
FLAC to MP3:
ffmpeg -i input.flac -c:a libmp3lame -b:a 320k -id3v2_version 4 output.mp3
Opus to MP3:
ffmpeg -i input.opus -c:a libmp3lame -b:a 192k -id3v2_version 4 output.mp3
Preserve Metadata:
ffmpeg -i input.flac -c:a libopus -b:a 128k -vn -map_metadata 0 output.opus
Video Transcoding
4K to 1080p:
ffmpeg -i input.mkv -vf scale=1920:1080 -c:v libx264 -crf 23 -c:a copy output.mp4
1080p to 720p (mobile):
ffmpeg -i input.mp4 -vf scale=1280:720 -c:v libx264 -crf 23 -b:v 1500k -c:a aac -b:a 128k output.mp4
Extract Audio Only:
ffmpeg -i video.mp4 -vn -c:a libopus -b:a 192k audio.opus
Artwork Processing
Resize Artwork:
ffmpeg -i folder.jpg -vf scale=500:500:force_original_aspect_ratio=decrease -q:v 2 folder_mobile.jpg
Extract Artwork from Audio:
ffmpeg -i track.flac -an -vcodec copy folder.jpg
Embed Artwork into Audio:
ffmpeg -i track.flac -i folder.jpg -map 0:a -map 1:v -c:a copy -id3v2_version 4 -metadata:s:v title="Album cover" -metadata:s:v comment="Cover (front)" output.flac
NFO File Generation
Album NFO Template (Jellyfin/Kodi)
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <album> <title>{album_title}</title> <artist>{artist_name}</artist> <year>{release_year}</year> <genre>{genre}</genre> <style>{style}</style> <mood>{mood}</mood> <label>{label}</label> <releasedate>{release_date}</releasedate> <rating>{rating}</rating> <userrating>{user_rating}</userrating> <review>{review}</review> <musicbrainzalbumid>{mbid}</musicbrainzalbumid> <thumb aspect="thumb">{artwork_url}</thumb> </album>
Size-Budgeted Export (Mobile)
When exporting to mobile devices with limited storage:
-
Calculate Space Budget:
- Parse
parameter--max-size - Convert to bytes
- Reserve 10% buffer for filesystem overhead
- Parse
-
Prioritize Content:
- Sort by importance score (frequency * rating * recency)
- Essential albums first
- Deep cuts last
-
Transcode to Mobile Formats:
- FLAC → Opus 128kbps
- High-res video → 720p H.264
- Resize artwork to 500x500
-
Track Running Total:
- Sum file sizes as files are added
- Stop when budget exhausted
- Generate report of included/excluded content
-
Export Algorithm:
budget_bytes=$(( max_size_gb * 1024 * 1024 * 1024 * 9 / 10 )) total_bytes=0 while read -r file importance; do file_size=$(stat -f%z "$file" 2>/dev/null || stat -c%s "$file") if (( total_bytes + file_size > budget_bytes )); then echo "Budget exhausted. Stopping export." >&2 break fi # Transcode and copy transcode_and_copy "$file" "$output_dir" total_bytes=$(( total_bytes + file_size )) done < <(prioritized_file_list)
Archival Export
Preserve Original Formats
Never transcode. Copy files as-is to preserve quality and authenticity.
Generate SHA-256 Checksums
cd "$album_dir" find . -type f -not -name "SHA256SUMS" -exec sha256sum {} \; > SHA256SUMS
Record Provenance
Create
PROVENANCE.jsonld per W3C PROV standard:
{ "@context": "https://www.w3.org/ns/prov", "entity": "urn:aiwg:media:album:{mbid}", "wasGeneratedBy": { "activity": "urn:aiwg:activity:acquisition:{timestamp}", "time": "{iso8601_timestamp}", "wasAssociatedWith": "urn:aiwg:agent:media-curator" }, "wasDerivedFrom": [ { "entity": "{source_url}", "type": "download", "time": "{acquisition_date}" } ], "atLocation": "{file_path}", "hadPrimarySource": "{authoritative_source}" }
Generate Manifest
Per-artist
MANIFEST.json listing all albums, tracks, formats, and checksums:
{ "artist": "Artist Name", "albums": [ { "title": "Album Name", "year": 1973, "tracks": [ { "number": 1, "title": "Track Title", "file": "01 - Track Title.flac", "format": "flac", "checksum": "sha256:abc123..." } ] } ], "export_date": "{iso8601_timestamp}", "profile": "archival" }
Workflow
1. Select Profile
Parse
--profile argument. Load corresponding YAML spec.
2. Validate Source Collection
- Scan collection directory
- Verify files exist and are readable
- Check format compatibility with target profile
3. Create Output Directory Structure
Based on profile's
directory_pattern:
mkdir -p "$output_dir/{artist}/{album}"
4. Transcode If Needed
Check if source format matches target profile. If not, transcode:
if [[ "$source_ext" == "flac" ]] && [[ "$target_profile" == "mobile" ]]; then ffmpeg -i "$source" -c:a libopus -b:a 128k -map_metadata 0 "$target" fi
5. Copy/Move Files
cp -a "$source" "$destination"
Or move if
--move flag set.
6. Embed Metadata
Ensure all required metadata is embedded per profile spec.
7. Generate Supplementary Files
- NFO files (Jellyfin profile)
- SHA256SUMS (archival profile)
- PROVENANCE.jsonld (archival profile)
- folder.jpg, artist.jpg (Plex/Jellyfin profiles)
8. Report
Export complete: Plex profile Source: /media/source/Artist Name Destination: /media/plex/Music/Artist Name Files exported: 142 Total size: 3.2 GB Transcoded: 0 Copied: 142
Examples
Export to Plex
/export --profile plex ~/Music/Archive/Pink\ Floyd /media/plex/Music
Export to Mobile with Size Limit
/export --profile mobile ~/Music/Archive /sdcard/Music --max-size 32 --transcode
Archival Export
/export --profile archival ~/Music/Curated /backup/Music/Archive
Error Handling
- Missing source files: Report and skip
- Insufficient disk space: Abort with clear message
- Transcode failures: Log error, optionally skip or abort
- Permission denied: Report file path and required permissions
Performance Considerations
- Parallel transcoding: Use GNU parallel or xargs -P for multi-core systems
- Progress reporting: Update every N files or every M seconds
- Disk I/O: Batch operations to minimize seeks
- Memory: Stream large files instead of loading into memory
References
- @$AIWG_ROOT/agentic/code/addons/aiwg-utils/rules/human-authorization.md — Seek explicit authorization before overwriting existing export targets
- @$AIWG_ROOT/agentic/code/frameworks/media-curator/skills/curate/SKILL.md — Orchestration skill that invokes export as the final curation phase
- @$AIWG_ROOT/agentic/code/frameworks/media-curator/skills/assemble/SKILL.md — Assembly skill used before export to prepare media collections
- @$AIWG_ROOT/agentic/code/frameworks/media-curator/skills/integrity-verification/SKILL.md — Verify exported files match source checksums