Here you go. This should work for both playlists or folders full of music. I only tested folders full of music because I don’t have any playlists handy.
Just save this as alternate_player.py
then edit the playlist_a_path
and playlist_b_path
run with python3 ./alternate_player.py
.
import os
import random
import subprocess
import sys
import time
# --- Configuration ---
# Option 1: Playlists as directories
playlist_a_path = '/home/alan/Music/The Gripping Adventures of Space Walrus'
playlist_b_path = '/home/alan/Music/Lofi/Lone Wolf'
use_directories = True # Set to True if paths above are directories
# Option 2: Playlists as M3U files
# playlist_a_path = '/path/to/your/playlist_A.m3u'
# playlist_b_path = '/path/to/your/playlist_B.m3u'
# use_directories = False # Set to False if paths above are .m3u files
music_extensions = ('.mp3', '.ogg', '.flac', '.m4a', '.wav', '.opus') # Add others if needed
player_command = 'ffplay' # Or 'mplayer', 'mpv', 'cvlc' etc.
player_options = '-autoexit' # use '--play-and-exit' for cvlc
# --- End Configuration ---
def get_files_from_directory(dir_path):
"""Gets a list of music files from a directory."""
files = []
try:
for filename in os.listdir(dir_path):
if filename.lower().endswith(music_extensions):
files.append(os.path.join(dir_path, filename))
except FileNotFoundError:
print(f"Error: Directory not found: {dir_path}", file=sys.stderr)
return files
def get_files_from_m3u(m3u_path):
"""Gets a list of music files from an M3U playlist file."""
files = []
try:
with open(m3u_path, 'r', encoding='utf-8') as f:
for line in f:
line = line.strip()
# Skip comments and empty lines
if line and not line.startswith('#'):
# Basic check if it looks like a file path and has a valid extension
# M3U can contain URLs, this script assumes local files.
# Might need refinement if your M3U uses relative paths differently.
if os.path.exists(line) and line.lower().endswith(music_extensions):
files.append(line)
elif os.path.exists(os.path.join(os.path.dirname(m3u_path), line)) and line.lower().endswith(music_extensions):
# Handle relative paths relative to the M3U file location
files.append(os.path.join(os.path.dirname(m3u_path), line))
except FileNotFoundError:
print(f"Error: Playlist file not found: {m3u_path}", file=sys.stderr)
except Exception as e:
print(f"Error reading playlist {m3u_path}: {e}", file=sys.stderr)
return files
def play_random_track(file_list, playlist_name):
"""Selects and plays a random track from the list."""
if not file_list:
print(f"Warning: Playlist '{playlist_name}' is empty or contains no valid music files.", file=sys.stderr)
time.sleep(1) # Prevent busy loop if both are empty
return False
track_to_play = random.choice(file_list)
print(f"Playing from {playlist_name}: {os.path.basename(track_to_play)}")
try:
# Use subprocess.run which waits for the command to complete
# Adjust command based on player if needed (e.g., VLC and ffplay needs specific flags)
cmd = [player_command, player_options, track_to_play]
result = subprocess.run(cmd, check=False, stdout=subprocess.DEVNULL, stderr=subprocess.PIPE) # check=False to handle player errors gracefully
if result.returncode != 0:
print(f"Warning: Player exited with error code {result.returncode} for track {track_to_play}.", file=sys.stderr)
print(f"Player stderr: {result.stderr.decode()}", file=sys.stderr)
# Decide if you want to stop on error or just continue
# return False # Uncomment to stop script on player error
except FileNotFoundError:
print(f"Error: Player command '{player_command}' not found. Is it installed and in your PATH?", file=sys.stderr)
sys.exit(1)
except Exception as e:
print(f"Error during playback: {e}", file=sys.stderr)
# return False # Uncomment to stop script on other playback errors
return True
# --- Main Execution ---
print("Loading playlists...")
if use_directories:
playlist_a_files = get_files_from_directory(playlist_a_path)
playlist_b_files = get_files_from_directory(playlist_b_path)
else:
playlist_a_files = get_files_from_m3u(playlist_a_path)
playlist_b_files = get_files_from_m3u(playlist_b_path)
if not playlist_a_files and not playlist_b_files:
print("Error: Both playlists are empty or could not be read. Exiting.", file=sys.stderr)
sys.exit(1)
elif not playlist_a_files:
print("Warning: Playlist A is empty. Will only play from Playlist B.", file=sys.stderr)
elif not playlist_b_files:
print("Warning: Playlist B is empty. Will only play from Playlist A.", file=sys.stderr)
print("Starting playback loop (Press Ctrl+C to stop)...")
try:
while True:
# Play from Playlist A
play_random_track(playlist_a_files, "Playlist A")
# Play from Playlist B
play_random_track(playlist_b_files, "Playlist B")
except KeyboardInterrupt:
print("\nPlayback stopped by user.")
sys.exit(0)
Works here, using ffplay
(part of ffmpeg):
$ python alternate_player.py
Loading playlists...
Starting playback loop (Press Ctrl+C to stop)...
Playing from Playlist A: Diversity Mix.mp3
Playing from Playlist B: 18.The Startup.mp3
Playing from Playlist A: DJ Space Walrus - RoughEdit.mp3
Playing from Playlist B: 04.Breath of Anything.mp3
^C
Playback stopped by user.