diff --git a/pikaraoke/app.py b/pikaraoke/app.py index 01e318bf..eba20f53 100644 --- a/pikaraoke/app.py +++ b/pikaraoke/app.py @@ -3,7 +3,6 @@ import hashlib import json import logging -import mimetypes import os import re import signal @@ -41,6 +40,7 @@ from pikaraoke import VERSION, karaoke from pikaraoke.constants import LANGUAGES +from pikaraoke.lib.background_music import create_randomized_playlist from pikaraoke.lib.file_resolver import delete_tmp_dir, get_tmp_dir from pikaraoke.lib.get_platform import get_platform, is_raspberry_pi @@ -453,11 +453,20 @@ def logo(): return send_file(k.logo_path, mimetype="image/png") -@app.route("/background_music") -def background_music(): - music_path = k.bg_music_path - mime_type, _ = mimetypes.guess_type(music_path) - return send_file(k.bg_music_path, mimetype=mime_type) +# Routes for streaming background music +@app.route("/bg_music/", methods=["GET"]) +def bg_music(file): + mp3_path = os.path.join(k.bg_music_path, file) + return send_file(mp3_path, mimetype="audio/mpeg") + + +# Route for getting the randomized background music playlist +@app.route("/bg_playlist", methods=["GET"]) +def bg_playlist(): + if (k.bg_music_path == None) or (not os.path.exists(k.bg_music_path)): + return jsonify([]) + playlist = create_randomized_playlist(k.bg_music_path, "/bg_music") + return jsonify(playlist) @app.route("/end_song", methods=["GET", "POST"]) @@ -1064,7 +1073,7 @@ def main(): parser.add_argument( "--bg-music-path", nargs="+", - help="Path to a custom background music for the splash screen. (.mp3, .wav or .ogg)", + help="Path to a custom directory for the splash screen background music. Directory must contain mp3 files which will be randomized in a playlist.", default=None, required=False, ), diff --git a/pikaraoke/karaoke.py b/pikaraoke/karaoke.py index 721ed879..4aada55f 100644 --- a/pikaraoke/karaoke.py +++ b/pikaraoke/karaoke.py @@ -73,7 +73,7 @@ class Karaoke: volume = None loop_interval = 500 # in milliseconds default_logo_path = os.path.join(base_path, "logo.png") - default_bg_music_path = os.path.join(base_path, "static/sounds/midnight-dorufin.mp3") + default_bg_music_path = os.path.join(base_path, "static/music/") screensaver_timeout = 300 # in seconds ffmpeg_process = None diff --git a/pikaraoke/lib/background_music.py b/pikaraoke/lib/background_music.py new file mode 100644 index 00000000..7a0f4e4c --- /dev/null +++ b/pikaraoke/lib/background_music.py @@ -0,0 +1,20 @@ +import os +import random +import urllib + + +def create_randomized_playlist(input_directory, base_url): + # Get all mp3 files in the given directory + mp3_files = [f for f in os.listdir(input_directory) if f.endswith(".mp3")] + + # Shuffle the list of mp3 files + random.shuffle(mp3_files) + + # Create the playlist + playlist = [] + for mp3 in mp3_files: + mp3 = urllib.parse.quote(mp3.encode("utf8")) + url = f"{base_url}/{mp3}" + playlist.append(f"{url}") + + return playlist diff --git a/pikaraoke/static/sounds/midnight-dorufin.mp3 b/pikaraoke/static/music/midnight-dorufin.mp3 similarity index 100% rename from pikaraoke/static/sounds/midnight-dorufin.mp3 rename to pikaraoke/static/music/midnight-dorufin.mp3 diff --git a/pikaraoke/static/sounds/bg-music-piano.mp3 b/pikaraoke/static/sounds/bg-music-piano.mp3 deleted file mode 100644 index c8be92b9..00000000 Binary files a/pikaraoke/static/sounds/bg-music-piano.mp3 and /dev/null differ diff --git a/pikaraoke/templates/splash.html b/pikaraoke/templates/splash.html index c1b1a483..040162e6 100644 --- a/pikaraoke/templates/splash.html +++ b/pikaraoke/templates/splash.html @@ -105,11 +105,35 @@ return document.getElementById('background-music'); } - // handle background music + // A global array of the paths to mp3s for the background music playlist + // it will be loaded from the /bg_playlist endpoint + var bg_playlist = [] + + // Gets the next song from the playlist, rotating back to the first song if at the end + function getNextBgMusicSong() { + let currentSong = getBackgroundMusicPlayer().getAttribute('src'); + let nextSong = bg_playlist[0]; + if (currentSong) { + let currentIndex = bg_playlist.indexOf(currentSong); + if (currentIndex >= 0 && currentIndex < bg_playlist.length - 1) { + nextSong = bg_playlist[currentIndex + 1]; + } + } + return nextSong; + } + + // Plays or pauses the background music async function playBGMusic(play) { let bgMusicVolume = "{{ bg_music_volume }}" *1 //hack to parse string to float; if ('{{ disable_bg_music }}' == 'False') { let audio = getBackgroundMusicPlayer(); + if (bg_playlist.length == 0) { + console.log('No background music playlist loaded'); + return; + } + if (!audio.getAttribute('src')) { + audio.setAttribute('src', getNextBgMusicSong()); + } if (play == true) { if (isMediaPlaying(audio)) { return; // already playing @@ -307,6 +331,7 @@ }); } + // ** Post page load actions and event handlers ** $(function () { $('#video-container').hide(); @@ -358,6 +383,20 @@ endSong("error while playing"); }); + // Load the background music playlist from server + $.get('{{ url_for("bg_playlist") }}', function (data) { + if (data) bg_playlist = data; + }); + + // Add a listener to the background player to play the next song in the playlist + const bgMusic = getBackgroundMusicPlayer(); + bgMusic.addEventListener("ended", async () => { + bgMusic.setAttribute('src', getNextBgMusicSong()); + await bgMusic.load(); + await setTimeout(() => {}, 2500) // delay between songs + await bgMusic.play(); + }); + //make sure we end the song if the user closes the window or leaves page window.addEventListener( 'beforeunload', @@ -382,9 +421,7 @@ showMenu = true; } }); - }); - document.addEventListener('DOMContentLoaded', (event) => { let params = new URLSearchParams(window.location.search); let dismissConfirmation = params.get('confirm'); @@ -556,10 +593,8 @@ -