Initial commit - Navi.FM v3

This commit is contained in:
Collin Kasbergen
2026-07-22 13:23:22 +02:00
commit badafc91e3
55 changed files with 6384 additions and 0 deletions
+111
View File
@@ -0,0 +1,111 @@
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."}
]