The cache system prevents duplicate downloads using separate DETS files per genre/category.
When you download music by genre, each genre gets its own cache file:
# Downloads are cached per genre automatically
YoutubeAudioDl.Music.download(:lofi)
# Creates: downloads/.cache/lofi
YoutubeAudioDl.Music.download(:jazz)
# Creates: downloads/.cache/jazz
YoutubeAudioDl.Music.download(:rock)
# Creates: downloads/.cache/rockdownloads/
├── .cache/ # Cache directory
│ ├── lofi # DETS file for lofi downloads
│ ├── jazz # DETS file for jazz downloads
│ ├── rock # DETS file for rock downloads
│ └── general # Default category
└── *.mp3 # Your downloaded music files
- Organization - Easy to see which genres you've downloaded
- Performance - Smaller DETS files = faster lookups
- Flexibility - Clear cache for specific genres without affecting others
- Isolation - Same video in different genres won't conflict
# First time - downloads the file
YoutubeAudioDl.Music.download(:lofi)
# => {:ok, "downloads/lofi_hip_hop_beats.mp3"}
# Second time - skips (cached)
YoutubeAudioDl.Music.download(:lofi)
# => {:error, :already_downloaded}# Skip cache check and re-download
YoutubeAudioDl.Music.download(:lofi, force: true)
# => {:ok, "downloads/lofi_hip_hop_beats.mp3"}# Download 5 lofi tracks
YoutubeAudioDl.Music.download_multiple(:lofi, 5)
# First run: Downloads all 5
# Run again immediately
YoutubeAudioDl.Music.download_multiple(:lofi, 5)
# Skips all 5 (already cached)
# Output: "📊 Summary: 0 downloaded, 5 skipped (already cached)"# Direct download with custom category
url = "https://www.youtube.com/watch?v=abc123"
YoutubeAudioDl.download_audio(url, category: "my_playlist")
# Creates: downloads/.cache/my_playlist# Stats for specific genre
YoutubeAudioDl.Cache.stats("lofi")
# => %{
# total_downloads: 42,
# cache_file: "downloads/.cache/lofi",
# category: "lofi"
# }
# Aggregate stats across all genres
YoutubeAudioDl.Cache.all_stats()
# => %{
# total_categories: 5,
# total_downloads: 150,
# categories: [
# %{category: "lofi", total_downloads: 42},
# %{category: "jazz", total_downloads: 35},
# ...
# ]
# }# See what genres you've downloaded
YoutubeAudioDl.Cache.list_categories()
# => ["general", "jazz", "lofi", "rock"]# See all URLs cached for a genre
YoutubeAudioDl.Cache.list_all("lofi")
# => [
# %{url: "https://...", downloaded_at: 1696867200, category: "lofi"},
# ...
# ]# Clear cache for specific genre
YoutubeAudioDl.Cache.clear_all("lofi")
# Remove specific URL from cache
YoutubeAudioDl.Cache.remove("https://youtube.com/watch?v=abc", "lofi")# Check if URL is cached in a genre
YoutubeAudioDl.Cache.downloaded?("https://...", "lofi")
# => true/false
# Manually mark as downloaded
YoutubeAudioDl.Cache.mark_downloaded("https://...", "jazz")
# Get info about cached URL
YoutubeAudioDl.Cache.get_info("https://...", "lofi")
# => {:ok, %{url: "...", downloaded_at: 1696867200, category: "lofi"}}# Download with caching (per genre)
mix run -e 'YoutubeAudioDl.Music.download(:lofi)'
# Force re-download
mix run -e 'YoutubeAudioDl.Music.download(:lofi, force: true)'
# Check cache stats
mix run -e 'IO.inspect(YoutubeAudioDl.Cache.all_stats())'
# Clear lofi cache
mix run -e 'YoutubeAudioDl.Cache.clear_all("lofi")'
# List all categories
mix run -e 'IO.inspect(YoutubeAudioDl.Cache.list_categories())'- Technology: Erlang's DETS (Disk-based Erlang Term Storage)
- Type: Key-value store on disk
- Max size: 2GB per file (way more than you'll need)
- Structure:
{url, timestamp}tuples - Persistence: Automatic, survives restarts
- Lookup speed: O(log n) for most operations
- File size: ~6KB per file with minimal entries
- Concurrent access: Single writer, multiple readers
- Memory footprint: Minimal (only active tables stay in memory)
Each genre's cache is completely isolated:
# Same URL in different genres = different cache entries
YoutubeAudioDl.download_audio(url, category: "lofi") # Cached in lofi
YoutubeAudioDl.download_audio(url, category: "jazz") # NOT cached in jazz# Download from multiple genres
genres = [:lofi, :jazz, :classical, :ambient]
Enum.each(genres, fn genre ->
YoutubeAudioDl.Music.download_multiple(genre, 10)
end)
# Check what you've downloaded
YoutubeAudioDl.Cache.all_stats()# Download 5 lofi tracks today
YoutubeAudioDl.Music.download_multiple(:lofi, 5)
# Download 5 more tomorrow (gets next 5, skips first 5)
YoutubeAudioDl.Music.download_multiple(:lofi, 10)
# Will skip first 5, download next 5# Clear lofi cache to start fresh
YoutubeAudioDl.Cache.clear_all("lofi")
# Now can re-download everything
YoutubeAudioDl.Music.download_multiple(:lofi, 10)Check if you're using the correct category:
# These use DIFFERENT caches
YoutubeAudioDl.download_audio(url, category: "lofi")
YoutubeAudioDl.download_audio(url, category: "jazz")# List all cached URLs for a genre
YoutubeAudioDl.Cache.list_all("lofi")# Remove all cache files
rm -rf downloads/.cache/Or in Elixir:
# Clear each category
YoutubeAudioDl.Cache.list_categories()
|> Enum.each(&YoutubeAudioDl.Cache.clear_all/1)- Cache is stored in
downloads/.cache/directory - Each genre/category gets its own DETS file
- Files are created automatically on first use
- No manual initialization needed - it's automatic!
- Safe to delete cache files if you want a fresh start