Skip to content

Commit

Permalink
feat: allow randomized background music from user-specified dir
Browse files Browse the repository at this point in the history
  • Loading branch information
vicwomg committed Jan 3, 2025
1 parent 4a38710 commit a9307f1
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 15 deletions.
23 changes: 16 additions & 7 deletions pikaraoke/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import hashlib
import json
import logging
import mimetypes
import os
import re
import signal
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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/<file>", 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"])
Expand Down Expand Up @@ -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,
),
Expand Down
2 changes: 1 addition & 1 deletion pikaraoke/karaoke.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
20 changes: 20 additions & 0 deletions pikaraoke/lib/background_music.py
Original file line number Diff line number Diff line change
@@ -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
File renamed without changes.
Binary file removed pikaraoke/static/sounds/bg-music-piano.mp3
Binary file not shown.
49 changes: 42 additions & 7 deletions pikaraoke/templates/splash.html
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -307,6 +331,7 @@
});
}

// ** Post page load actions and event handlers **
$(function () {
$('#video-container').hide();

Expand Down Expand Up @@ -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',
Expand All @@ -382,9 +421,7 @@
showMenu = true;
}
});
});

document.addEventListener('DOMContentLoaded', (event) => {
let params = new URLSearchParams(window.location.search);
let dismissConfirmation = params.get('confirm');

Expand Down Expand Up @@ -556,10 +593,8 @@
</div>
</div>

<audio id="background-music" loop>
<source src="{{ url_for('background_music') }}" type="audio/mpeg">
<source src="{{ url_for('background_music') }}" type="audio/ogg">
<source src="{{ url_for('background_music') }}" type="audio/wav">
<audio id="background-music">
<source src="" type="audio/mpeg">
</audio>

<audio id="score-drums">
Expand Down

0 comments on commit a9307f1

Please sign in to comment.