Completed player

This commit is contained in:
Media
2025-06-30 20:24:59 -05:00
parent 765bf73383
commit 20677f0749
10 changed files with 316 additions and 106 deletions
+73 -60
View File
@@ -1,13 +1,14 @@
import jack # type: ignore
import jack
import time
import numpy as np # type: ignore
from pydub import AudioSegment # type: ignore
import numpy as np
from pydub import AudioSegment
import random
import sys
import json
import os
import paho.mqtt.client as mqtt # type: ignore
from paho.mqtt.client import Client # type: ignore
import yaml
import paho.mqtt.client as mqtt
import threading
import re
# === load and shuffle .m3u playlist ===
@@ -22,7 +23,7 @@ def decode_mp3(path):
song = AudioSegment.from_file(path)
song = song.set_frame_rate(48000).set_channels(2).set_sample_width(4)
samples = np.array(song.get_array_of_samples()).astype(np.float32) / (2**31)
return samples.reshape((-1,2)) #stereo:L R
return samples.reshape((-1, 2)) # stereo: L R
def update_now_playing(playlist_name, song_title):
path = "/home/media/Music/now_playing.json"
@@ -38,8 +39,7 @@ def update_now_playing(playlist_name, song_title):
# MQTT title broadcast
mqtt_topic = f"music/now_playing/{playlist_name.lower()}"
mqtt_payload = os.path.basename(song_title)
mqtt_payload = os.path.splitext(mqtt_payload)[0]
mqtt_payload = os.path.splitext(os.path.basename(song_title))[0]
mqtt_payload = re.sub(r'\s*\[[^\]]+\]$', '', mqtt_payload)
try:
@@ -53,60 +53,73 @@ def update_now_playing(playlist_name, song_title):
except Exception as e:
print(f"[MQTT] failed to publish: {e}")
# === Get playlist name from CLI ===
if len(sys.argv) < 2:
print ("Usage: python3 jack_mp3_player.py Praise|Worship|Instrumental")
sys.exit(1)
# === YAML config ===
def load_config():
with open("config.yaml") as f:
return yaml.safe_load(f)
playlist_name = sys.argv[1]
playlist_file = f"/home/media/Music/{playlist_name}.m3u"
# === JACK + player logic ===
def run_playlist(playlist_name, playlist_file):
client = jack.Client(playlist_name)
out_l = client.outports.register("left")
out_r = client.outports.register("right")
# === jack setup ===
client = jack.Client(playlist_name)
out_l = client.outports.register("left")
out_r = client.outports.register("right")
playlist = load_playlist(playlist_file)
current_index = 0
samples = decode_mp3(playlist[current_index])
buffer_pos = [0]
playlist = load_playlist(playlist_file)
current_index = 0
samples = decode_mp3(playlist[current_index])
buffer_pos = [0]
@client.set_process_callback
def process(frames):
bufsize = frames
end = buffer_pos[0] + bufsize
#zero fills if out of data
if buffer_pos[0] >= len(samples):
out_l.get_buffer()[:] = np.zeros(bufsize, dtype=np.float32)
out_r.get_buffer()[:] = np.zeros(bufsize, dtype=np.float32)
return
chunk = samples[buffer_pos[0]:end]
#pad if last chunk
if len(chunk) < bufsize:
pad = np.zeros((bufsize - len(chunk), 2), dtype=np.float32)
chunk = np.vstack((chunk, pad))
out_l.get_buffer()[:] = chunk[:, 0].copy()
out_r.get_buffer()[:] = chunk[:, 1].copy()
buffer_pos[0] += bufsize
# === Activate jack ===
with client:
print(f"Playing playlist: {playlist_name}")
print(f"Playing song: {playlist[current_index]}")
update_now_playing(playlist_name, playlist[current_index])
while True:
@client.set_process_callback
def process(frames):
bufsize = frames
end = buffer_pos[0] + bufsize
if buffer_pos[0] >= len(samples):
current_index += 1
if current_index >= len(playlist):
playlist = load_playlist(playlist_file)
current_index = 0
out_l.get_buffer()[:] = np.zeros(bufsize, dtype=np.float32)
out_r.get_buffer()[:] = np.zeros(bufsize, dtype=np.float32)
return
chunk = samples[buffer_pos[0]:end]
if len(chunk) < bufsize:
pad = np.zeros((bufsize - len(chunk), 2), dtype=np.float32)
chunk = np.vstack((chunk, pad))
out_l.get_buffer()[:] = chunk[:, 0].copy()
out_r.get_buffer()[:] = chunk[:, 1].copy()
buffer_pos[0] += bufsize
print(f"Playing: {playlist[current_index]}")
update_now_playing(playlist_name, playlist[current_index])
samples = decode_mp3(playlist[current_index])
buffer_pos[0] = 0
time.sleep(0.1)
with client:
print(f"[{playlist_name}] Playing: {playlist[current_index]}")
update_now_playing(playlist_name, playlist[current_index])
while True:
if buffer_pos[0] >= len(samples):
current_index += 1
if current_index >= len(playlist):
playlist = load_playlist(playlist_file)
current_index = 0
print(f"[{playlist_name}] Playing: {playlist[current_index]}")
update_now_playing(playlist_name, playlist[current_index])
samples = decode_mp3(playlist[current_index])
buffer_pos[0] = 0
time.sleep(0.1)
# === Main logic ===
if __name__ == "__main__":
config = load_config()
sources = config.get("sources", {})
if len(sys.argv) > 1:
playlist_name = sys.argv[1]
if playlist_name in sources and sources[playlist_name].get("active", True):
playlist_file = f"/home/media/Music/{playlist_name}.m3u"
run_playlist(playlist_name, playlist_file)
else:
print(f"[!] Source '{playlist_name}' not found or not active.")
else:
threads = []
for playlist_name, source_data in sources.items():
if source_data.get("active", True):
playlist_file = f"/home/media/Music/{playlist_name}.m3u"
t = threading.Thread(target=run_playlist, args=(playlist_name, playlist_file), daemon=True)
t.start()
threads.append(t)
for t in threads:
t.join()