broaden support for different audio file formats

Hunter
Tuesday, December 30th, 2025 at 5:02 PM

resources/script.js+17-1
rip.py+1-1
scan.py+25-26

resources/script.js
 998  	}
 999  }
1000  
1001 +// MIME type mapping for supported audio formats
1002 +const AUDIO_MIME_TYPES = {
1003 +	'.mp3': 'audio/mpeg',
1004 +	'.m4a': 'audio/mp4',
1005 +	'.ogg': 'audio/ogg',
1006 +	'.flac': 'audio/flac',
1007 +	'.wav': 'audio/wav'
1008 +};
1009 +
1010 +// Get MIME type based on file extension
1011 +function getAudioMimeType(filename) {
1012 +	const ext = filename.substring(filename.lastIndexOf('.')).toLowerCase();
1013 +	return AUDIO_MIME_TYPES[ext] || 'audio/mpeg';
1014 +}
1015 +
1016  // Store blob in Cache API for offline access
1017  async function storeBlobInCache(filename, blob) {
1018  	try {
1019  		const cache = await caches.open(CACHE_NAME);
1020 +		const mimeType = getAudioMimeType(filename);
1021  		const response = new Response(blob, {
1022  			headers: {
     -				'Content-Type': 'audio/mpeg',
1023 +				'Content-Type': mimeType,
1024  				'Content-Length': blob.size
1025  			}
1026  		});
rip.py
1  #!/usr/bin/env python3
2  """
  -CD Ripper - Rips audio CDs to MP3 files in /tracks directory
3 +Rips audio CDs to MP3 files in /tracks directory
4  Uses system tools: ffmpeg/ffprobe (no Python dependencies needed)
5  """
6  
scan.py
  1  #!/usr/bin/env python3
  2  """
    -MP3 Scanner - Scans /tracks directory and generates tracks.json with metadata
  3 +Scans /tracks directory and populates tracks.json with metadata
  4 +Supports MP3, M4A, OGG, FLAC, and WAV formats
  5  Automatically manages a virtual environment for dependencies
  6  """
  7  

 61  
 62  
 63  def scan_tracks():
    -	"""Main function to scan MP3 files and generate tracks.json"""
 64 +	"""Main function to scan audio files and generate tracks.json"""
 65  	# Import mutagen here (only after venv is active)
 66  	try:
    -		from mutagen.mp3 import MP3
    -		from mutagen.id3 import ID3
 67 +		from mutagen import File as MutagenFile
 68  	except ImportError:
 69  		print("Error: mutagen library not found. Please check your installation.")
 70  		sys.exit(1)
 71  
 72 +	# Supported audio formats
 73 +	SUPPORTED_EXTENSIONS = ('.mp3', '.m4a', '.ogg', '.flac', '.wav')
 74 +
 75  	# Check if tracks directory exists, create if it doesn't
 76  	if not TRACKS_DIR.exists():
 77  		print(f"Creating {TRACKS_DIR.name} directory...")
 78  		TRACKS_DIR.mkdir(parents=True, exist_ok=True)
 79  		print(f"✓ {TRACKS_DIR.name} directory created.")
    -		print(f"\nPlease add MP3 files to the {TRACKS_DIR.name} directory and run this script again.")
 80 +		print(f"\nPlease add audio files to the {TRACKS_DIR.name} directory and run this script again.")
 81 +		print(f"Supported formats: {', '.join(SUPPORTED_EXTENSIONS)}")
 82  		sys.exit(0)
 83  
 84  	# Check if tracks.json already exists

 88  			print(f"Scan cancelled. {OUTPUT_FILE.name} was not modified.")
 89  			sys.exit(0)
 90  
    -	# Find all MP3 files
    -	mp3_files = list(TRACKS_DIR.glob("*.mp3"))
 91 +	# Find all supported audio files
 92 +	audio_files = [f for f in TRACKS_DIR.iterdir() if f.suffix.lower() in SUPPORTED_EXTENSIONS]
 93  
    -	if not mp3_files:
    -		print(f"No MP3 files found in {TRACKS_DIR}")
    -		print(f"\nPlease add MP3 files to the {TRACKS_DIR.name} directory and run this script again.")
 94 +	if not audio_files:
 95 +		print(f"No audio files found in {TRACKS_DIR}")
 96 +		print(f"\nPlease add audio files to the {TRACKS_DIR.name} directory and run this script again.")
 97 +		print(f"Supported formats: {', '.join(SUPPORTED_EXTENSIONS)}")
 98  		sys.exit(0)
 99  
    -	print(f"Found {len(mp3_files)} MP3 file(s). Extracting metadata...\n")
100 +	print(f"Found {len(audio_files)} audio file(s). Extracting metadata...\n")
101  
102  	tracks = []
103  
    -	for mp3_file in sorted(mp3_files):
104 +	for audio_file in sorted(audio_files):
105  		try:
    -			audio = MP3(mp3_file)
106 +			audio = MutagenFile(audio_file, easy=True)
107  
    -			# Try to get ID3 tags
108  			title = None
109  			artist = None
110  
    -			if audio.tags:
    -				# Try different title tags
    -				if 'TIT2' in audio.tags:  # Title
    -					title = str(audio.tags['TIT2'])
    -
    -				# Try different artist tags
    -				if 'TPE1' in audio.tags:  # Artist
    -					artist = str(audio.tags['TPE1'])
111 +			if audio and audio.tags:
112 +				title = audio.tags.get('title', [None])[0]
113 +				artist = audio.tags.get('artist', [None])[0]
114  
115  			# Fallback to filename for title if not found
116  			if not title:
    -				title = mp3_file.stem  # filename without extension
117 +				title = audio_file.stem  # filename without extension
118  
119  			# Fallback to "Unknown Artist" if not found
120  			if not artist:

123  			track_info = {
124  				"title": title,
125  				"artist": artist,
    -				"filename": mp3_file.name
126 +				"filename": audio_file.name
127  			}
128  
129  			tracks.append(track_info)
130  			print(f"✓ {track_info['artist']} - {track_info['title']}")
131  
132  		except Exception as e:
    -			print(f"✗ Error reading {mp3_file.name}: {e}")
133 +			print(f"✗ Error reading {audio_file.name}: {e}")
134  			continue
135  
136  	# Check if ALL titles start with numbers

153  					print(f"  {original_title} → {cleaned_title}")
154  
155  	if not tracks:
    -		print("\nNo valid MP3 files could be processed.")
156 +		print("\nNo valid audio files could be processed.")
157  		sys.exit(1)
158  
159  	# Write to tracks.json