agentic/code/frameworks/media-curator/skills/export/SKILL.md
Export media collection to platform-specific formats (Plex, Jellyfin, MPD, mobile, archival)
npx skillsauth add jmagly/aiwg exportInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
Security scan pending...
This skill is queued for security scanning. Results will appear when the scan completes.
Export a curated media collection to platform-specific formats with appropriate transcoding, metadata, and directory structures.
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.
Formats:
folder.jpg in album directoryDirectory 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
Formats:
folder.jpg + artist.jpgDirectory 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
Formats:
folder.jpg in album directoryDirectory 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
Formats:
Size Constraints:
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}"
Formats:
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}"
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
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
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
<?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>
When exporting to mobile devices with limited storage:
Calculate Space Budget:
--max-size parameterPrioritize Content:
Transcode to Mobile Formats:
Track Running Total:
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)
Never transcode. Copy files as-is to preserve quality and authenticity.
cd "$album_dir"
find . -type f -not -name "SHA256SUMS" -exec sha256sum {} \; > SHA256SUMS
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}"
}
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"
}
Parse --profile argument. Load corresponding YAML spec.
Based on profile's directory_pattern:
mkdir -p "$output_dir/{artist}/{album}"
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
cp -a "$source" "$destination"
Or move if --move flag set.
Ensure all required metadata is embedded per profile spec.
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
/export --profile plex ~/Music/Archive/Pink\ Floyd /media/plex/Music
/export --profile mobile ~/Music/Archive /sdcard/Music --max-size 32 --transcode
/export --profile archival ~/Music/Curated /backup/Music/Archive
data-ai
Report which research-corpus radar sidecars are overdue for refresh. Computes staleness (days since last refresh vs the cadence window) for every radar, sorted most-overdue-first. Runs via `aiwg corpus radar-status`.
data-ai
Aggregate research-corpus radar sidecars into a corpus or per-cluster freshness report — totals, overdue count, per-cluster / per-GRADE / per-trajectory breakdowns, an overdue table, and per-radar rationale snippets. Runs via `aiwg corpus radar-report`.
testing
Scaffold radar/freshness sidecars for research-corpus REFs. Pulls title/authors from the citation sidecar and GRADE from the analysis doc, defaults the refresh cadence from GRADE and the cluster from a corpus-local map, and stamps documentation/radar/REF-XXX-radar.md. Runs via `aiwg corpus radar-init`.
data-ai
Compute an entity's publication trajectory — per-year paper counts, topic drift, hot-streak detection (≥3 consecutive A-grade years), and career phase. Runs via `aiwg corpus profile-temporal`.