112 lines
4.5 KiB
Python
112 lines
4.5 KiB
Python
import time
|
|
import random
|
|
from sqlalchemy.sql.expression import func
|
|
from database import SessionLocal, Track, Setting
|
|
|
|
def get_active_profile(db):
|
|
setting = db.query(Setting).filter(Setting.key == "active_profile").first()
|
|
return setting.value if setting else "harmonic"
|
|
|
|
def set_active_profile(profile_name: str):
|
|
db = SessionLocal()
|
|
try:
|
|
setting = db.query(Setting).filter(Setting.key == "active_profile").first()
|
|
if not setting:
|
|
setting = Setting(key="active_profile", value=profile_name)
|
|
db.add(setting)
|
|
else:
|
|
setting.value = profile_name
|
|
db.commit()
|
|
finally:
|
|
db.close()
|
|
|
|
def get_next_track():
|
|
db = SessionLocal()
|
|
try:
|
|
profile = get_active_profile(db)
|
|
track = None
|
|
|
|
# Only select from analyzed tracks
|
|
base_query = db.query(Track).filter(Track.analyzed == True)
|
|
|
|
# Avoid playing tracks that were played in the last hour
|
|
one_hour_ago = int(time.time()) - 3600
|
|
pool_query = base_query.filter(Track.last_played < one_hour_ago)
|
|
|
|
# Artist Separation Logic
|
|
artist_sep_enabled = db.query(Setting).filter(Setting.key == "artist_separation_enabled").first()
|
|
if artist_sep_enabled and artist_sep_enabled.value == "true":
|
|
artist_sep_count_setting = db.query(Setting).filter(Setting.key == "artist_separation_count").first()
|
|
sep_count = int(artist_sep_count_setting.value) if artist_sep_count_setting else 5
|
|
|
|
recent_tracks = db.query(Track).filter(Track.last_played > 0).order_by(Track.last_played.desc()).limit(sep_count).all()
|
|
recent_artists = [t.artist for t in recent_tracks if t.artist]
|
|
|
|
if recent_artists:
|
|
filtered_query = pool_query.filter(~Track.artist.in_(recent_artists))
|
|
if filtered_query.count() > 0:
|
|
pool_query = filtered_query
|
|
|
|
if pool_query.count() == 0:
|
|
# Fallback if all tracks were played recently or no tracks analyzed
|
|
pool_query = base_query
|
|
|
|
if profile == "high_energy":
|
|
# Pick from most energetic tracks
|
|
tracks = pool_query.order_by(Track.energy.desc()).limit(50).all()
|
|
if tracks:
|
|
track = random.choice(tracks)
|
|
elif profile == "chill":
|
|
# Pick from least energetic tracks
|
|
tracks = pool_query.order_by(Track.energy.asc()).limit(50).all()
|
|
if tracks:
|
|
track = random.choice(tracks)
|
|
elif profile == "harmonic":
|
|
# Get last played track to match key/bpm
|
|
last_played = base_query.order_by(Track.last_played.desc()).first()
|
|
if last_played and last_played.key and last_played.bpm:
|
|
# Find matching key and similar BPM (+- 10)
|
|
track = pool_query.filter(Track.key == last_played.key)\
|
|
.filter(Track.bpm.between(last_played.bpm - 10, last_played.bpm + 10))\
|
|
.order_by(func.random()).first()
|
|
|
|
# Fallback to random if no track found for profile or profile is 'random'
|
|
if not track:
|
|
track = pool_query.order_by(func.random()).first()
|
|
|
|
if track:
|
|
# Update last played
|
|
track.last_played = int(time.time())
|
|
track.play_count += 1
|
|
db.commit()
|
|
return {"id": track.id, "lufs": track.lufs}
|
|
return None
|
|
finally:
|
|
db.close()
|
|
|
|
def get_current_track():
|
|
db = SessionLocal()
|
|
try:
|
|
# The currently playing track is approximated as the most recently queued track
|
|
track = db.query(Track).order_by(Track.last_played.desc()).first()
|
|
if track and track.last_played > 0:
|
|
return {
|
|
"id": track.id,
|
|
"title": track.title,
|
|
"artist": track.artist,
|
|
"bpm": track.bpm,
|
|
"energy": track.energy,
|
|
"lufs": track.lufs
|
|
}
|
|
return None
|
|
finally:
|
|
db.close()
|
|
|
|
# Define available profiles for the WebUI
|
|
AVAILABLE_PROFILES = [
|
|
{"id": "harmonic", "name": "Harmonic Mix", "description": "Attempts to match the key and BPM of the previously played track."},
|
|
{"id": "high_energy", "name": "High Energy", "description": "Prioritizes tracks with high RMS energy."},
|
|
{"id": "chill", "name": "Chill", "description": "Prioritizes low-energy, ambient tracks."},
|
|
{"id": "random", "name": "Random", "description": "Plays tracks randomly."}
|
|
]
|