main/ holds the main window and top bar, quiz/ the quiz and its parts, player/ the music player, popups/ every popup and what they share, data/ the songs, players, playlist and settings, server/ the MusicServer client, common/ the list row and GameLog, and themes/ the themes and style boxes.
102 lines
3.8 KiB
GDScript
102 lines
3.8 KiB
GDScript
class_name SongLoader
|
|
extends Node
|
|
## Downloads songs from the server into the Playlist ahead of time, so the next song
|
|
## can start at once.
|
|
##
|
|
## How many songs it keeps ready is the cache size in the settings
|
|
## ([code]Playlist.number_of_tracks_to_preload[/code]).
|
|
|
|
## Emitted when the songs already in the server playlist have been loaded into the
|
|
## Playlist.
|
|
|
|
signal song_list_loaded
|
|
|
|
## Emitted when a new song has been downloaded and added to the Playlist.
|
|
signal song_added
|
|
|
|
## Seconds to wait before retrying a download step that failed.
|
|
var retry_seconds: float = 5.0
|
|
|
|
|
|
## Loads the songs already in the server playlist, then starts preloading new ones.
|
|
## Preloading waits for the list, because loading the list clears the playlist.
|
|
func load_song_list() -> void:
|
|
GameLog.debug("load_song_list")
|
|
var song_list_fetched: Callable = func song_list_fetched(data: Variant) -> void:
|
|
Playlist.clear_song_list()
|
|
if typeof(data) == TYPE_ARRAY:
|
|
for d: Dictionary in data:
|
|
var new_song_object: SongObject = SongObject.new()
|
|
new_song_object.song_number = d.SongNo
|
|
new_song_object.soundtrack_title = d.Soundtrack
|
|
new_song_object.song_title = d.Song
|
|
new_song_object.is_answered = true
|
|
new_song_object.has_played = true
|
|
Playlist.add_to_playlist(new_song_object)
|
|
elif data != null:
|
|
GameLog.warning("Unexpected data")
|
|
Playlist.update_last_played_song()
|
|
song_list_loaded.emit()
|
|
fetch_song_if_idle()
|
|
MusicServerClient.fetch_song_list(song_list_fetched, _retry_later.bind(load_song_list))
|
|
|
|
|
|
## Starts downloading one more song, which keeps downloading until the cache is full.
|
|
func fetch_song() -> void:
|
|
GameLog.debug("fetch_song")
|
|
Playlist.is_song_downloading = true
|
|
_download_random_song(SongObject.new())
|
|
|
|
|
|
## Starts downloading a song unless one is already downloading.
|
|
func fetch_song_if_idle() -> void:
|
|
if !Playlist.is_song_downloading:
|
|
fetch_song()
|
|
|
|
|
|
## Starts downloading if nothing is downloading and the cache is not full, e.g. after
|
|
## the cache size was raised.
|
|
func fill_cache() -> void:
|
|
if !Playlist.is_song_downloading && Playlist.should_preload_more_songs():
|
|
fetch_song()
|
|
|
|
|
|
# Fetching a song takes three requests. If one fails, only that step is retried, so
|
|
# the server and the game keep the same songs in their playlists.
|
|
func _download_random_song(new_song_object: SongObject) -> void:
|
|
var song_downloaded: Callable = func song_downloaded(body: PackedByteArray) -> void:
|
|
GameLog.debug("song_downloaded")
|
|
var sound: AudioStream = AudioStreamMP3.new()
|
|
sound.data = body
|
|
new_song_object.song = sound
|
|
_add_song_to_queue(new_song_object)
|
|
MusicServerClient.fetch_random_song(Settings.use_low_played_mode, song_downloaded,
|
|
_retry_later.bind(_download_random_song.bind(new_song_object)))
|
|
|
|
|
|
func _add_song_to_queue(new_song_object: SongObject) -> void:
|
|
MusicServerClient.add_to_queue(_fetch_song_info.bind(new_song_object),
|
|
_retry_later.bind(_add_song_to_queue.bind(new_song_object)))
|
|
|
|
|
|
func _fetch_song_info(new_song_object: SongObject) -> void:
|
|
var song_info_fetched: Callable = func song_info_fetched(data_received: Dictionary) -> void:
|
|
GameLog.debug("song_info_fetched")
|
|
new_song_object.song_number = data_received.SongNo
|
|
new_song_object.soundtrack_title = data_received.Soundtrack
|
|
new_song_object.song_title = data_received.Song
|
|
GameLog.debug("new_song_object: ", new_song_object.to_string())
|
|
Playlist.add_to_playlist(new_song_object)
|
|
if Playlist.should_preload_more_songs():
|
|
fetch_song()
|
|
else:
|
|
Playlist.is_song_downloading = false
|
|
song_added.emit()
|
|
MusicServerClient.fetch_song_info(song_info_fetched,
|
|
_retry_later.bind(_fetch_song_info.bind(new_song_object)))
|
|
|
|
|
|
func _retry_later(step: Callable) -> void:
|
|
GameLog.warning("Song download failed, retrying in %s seconds" % retry_seconds)
|
|
get_tree().create_timer(retry_seconds).timeout.connect(step)
|