fall back gracefully if optional packages not available

Hunter
Tuesday, March 10th, 2026 at 10:28 AM

build.py+18-17
host.py+8-9
requirements.txtdeleted

build.py
 15  VENV_DIR = SCRIPT_DIR / "venv"
 16  MIX_DIR = SCRIPT_DIR / "mix"
 17  OUTPUT_FILE = MIX_DIR / "tracks.json"
    -REQUIREMENTS_FILE = SCRIPT_DIR / "requirements.txt"
 18  
 19  
 20  def setup_venv():
    -	"""Create and setup virtual environment if it doesn't exist"""
 21 +	"""Create and set up virtual environment if it doesn't exist"""
 22  	# Determine the path to pip and python in the venv
 23  	if sys.platform == "win32":
 24  		pip_path = VENV_DIR / "Scripts" / "pip"

 52  			print(f"Error ensuring pip: {e}")
 53  			sys.exit(1)
 54  
    -	# Install requirements if requirements.txt exists
    -	if REQUIREMENTS_FILE.exists():
    -		print("Installing dependencies from requirements.txt...")
 55 +	check = subprocess.run(
 56 +		[str(python_path), "-c", "import mutagen"],
 57 +		capture_output=True
 58 +	)
 59 +	if check.returncode != 0:
 60  		try:
    -			subprocess.check_call([str(python_path), "-m", "pip", "install", "-q", "-r", str(REQUIREMENTS_FILE)])
    -			print("Dependencies installed successfully.")
    -		except subprocess.CalledProcessError as e:
    -			print(f"Error installing dependencies: {e}")
    -			sys.exit(1)
 61 +			subprocess.check_call([str(python_path), "-m", "pip", "install", "-q", "mutagen"])
 62 +		except subprocess.CalledProcessError:
 63 +			print("Note: Could not install mutagen (offline?). Metadata will be derived from filenames.\n")
 64  
 65  	return python_path
 66  

 80  	# Import mutagen here (only after venv is active)
 81  	try:
 82  		from mutagen import File as MutagenFile
 83 +		has_mutagen = True
 84  	except ImportError:
    -		print("Error: mutagen library not found. Please check your installation.")
    -		sys.exit(1)
 85 +		MutagenFile = None
 86 +		has_mutagen = False
 87 +		print("Mutagen not available. Metadata will be derived from filenames.\n")
 88  
 89  	# Supported audio formats
 90  	SUPPORTED_EXTENSIONS = ('.mp3', '.m4a', '.ogg', '.flac', '.wav')

113  
114  	for audio_file in sorted(audio_files):
115  		try:
    -			audio = MutagenFile(audio_file, easy=True)
    -
116  			title = None
117  			artist = None
118  
    -			if audio and audio.tags:
    -				title = audio.tags.get('title', [None])[0]
    -				artist = audio.tags.get('artist', [None])[0]
119 +			if has_mutagen:
120 +				audio = MutagenFile(audio_file, easy=True)
121 +				if audio and audio.tags:
122 +					title = audio.tags.get('title', [None])[0]
123 +					artist = audio.tags.get('artist', [None])[0]
124  
125  			# Fallback to filename for title if not found
126  			if not title:
host.py
15  DEFAULT_PORT = 8000
16  SCRIPT_DIR = Path(__file__).parent.absolute()
17  VENV_DIR = SCRIPT_DIR / "venv"
   -REQUIREMENTS_FILE = SCRIPT_DIR / "requirements.txt"
18  
19  
20  def setup_venv():

52  			print(f"Error ensuring pip: {e}")
53  			sys.exit(1)
54  
   -	# Install requirements if requirements.txt exists
   -	if REQUIREMENTS_FILE.exists():
   -		print("Installing dependencies from requirements.txt...")
55 +	check = subprocess.run(
56 +		[str(python_path), "-c", "import qrcode"],
57 +		capture_output=True
58 +	)
59 +	if check.returncode != 0:
60  		try:
   -			subprocess.check_call([str(python_path), "-m", "pip", "install", "-q", "-r", str(REQUIREMENTS_FILE)])
   -			print("Dependencies installed successfully.\n")
   -		except subprocess.CalledProcessError as e:
   -			print(f"Error installing dependencies: {e}")
   -			sys.exit(1)
61 +			subprocess.check_call([str(python_path), "-m", "pip", "install", "-q", "qrcode"])
62 +		except subprocess.CalledProcessError:
63 +			print("Note: Could not install qrcode (offline?). QR codes will be unavailable.\n")
64  
65  	return python_path
66  
requirements.txt
  -mutagen
  -qrcode