Preload songs only after the song list has loaded

At startup and after resetting the playlist, loading the song list and
preloading the first song started at the same time. When the list
answered last, it cleared the playlist and dropped the preloaded song.
Preloading now starts once the list has loaded, and loading the list is
retried if it fails.
This commit is contained in:
Sansan committed 2026-10-06 08:32:56 +02:00
1 parent ed292877ef
commit 739d0f7af6
5 files changed
+78 -8

No files matched your search

+7 -8
View File
@@ -186,7 +186,6 @@ func _ready() -> void:
get_suggestion_list()
fetch_song_list_at_start()
fetch_song()
search_view.get_list_of_soundtracks()
new_character_select.load_characters()
@@ -240,14 +239,12 @@ func show_answer_pressed() -> void:
Playlist.song_is_answered()
update_song_list()
# 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 fetch_song_list_at_start() -> void:
print("fetch_song_list_at_start")
var fetch_song_list_at_start_done: Callable = func fetch_songs_at_start_done(data) -> void:
Playlist.clear_song_list()
if data == null:
Playlist.update_last_played_song()
update_song_list()
return
if typeof(data) == TYPE_ARRAY:
for d: Dictionary in data:
var new_song_object: SongObject = SongObject.new()
@@ -257,11 +254,14 @@ func fetch_song_list_at_start() -> void:
new_song_object.is_answered = true
new_song_object.has_played = true
Playlist.add_to_playlist(new_song_object)
else:
elif data != null:
print("Unexpected data")
Playlist.update_last_played_song()
update_song_list()
MusicServerClient.fetch_song_list(fetch_song_list_at_start_done)
if !Playlist.is_song_downloading:
fetch_song()
MusicServerClient.fetch_song_list(fetch_song_list_at_start_done,
_retry_later.bind(fetch_song_list_at_start))
func play_next_song() -> void:
print("play_next_song ", Playlist.latest_played_song)
@@ -360,7 +360,6 @@ func reset_playlist() -> void:
var playlist_reset_done: Callable = func playlist_reset_done() -> void:
Playlist.reset_playlist()
fetch_song_list_at_start()
fetch_song()
MusicServerClient.reset_playlist(playlist_reset_done)
+22
View File
@@ -13,6 +13,7 @@ var requested_methods: Array[int] = []
var _responses: Dictionary = {}
var _successes_left: Dictionary = {}
var _held_paths: Dictionary = {}
var _previous_transport: HttpTransport
@@ -49,6 +50,20 @@ func fail_after(path: String, successes: int) -> void:
_successes_left[path] = successes
## Holds back responses to [param path] until [method release] is called, like a slow
## server.
func hold(path: String) -> void:
_held_paths[path] = []
## Delivers the responses held back for [param path] and stops holding it.
func release(path: String) -> void:
var waiting: Array = _held_paths.get(path, [])
_held_paths.erase(path)
for pending: Callable in waiting:
pending.call()
## Returns how many times [param path] has been requested.
func count(path: String) -> int:
return requested_paths.count(path)
@@ -58,6 +73,13 @@ func request(url: String, method: int, on_complete: Callable) -> void:
var path: String = url.trim_prefix(Settings.default_path)
requested_paths.append(path)
requested_methods.append(method)
if _held_paths.has(path):
_held_paths[path].append(_answer.bind(path, on_complete))
return
_answer(path, on_complete)
func _answer(path: String, on_complete: Callable) -> void:
if _successes_left.has(path):
if _successes_left[path] == 0:
on_complete.call(503, PackedByteArray())
+7
View File
@@ -36,12 +36,19 @@ func before_test() -> void:
_server.respond_bytes("/music/reset", PackedByteArray())
_server.respond_bytes("/music/played?song=0", PackedByteArray())
_before_window_starts()
_runner = scene_runner("res://MainWindow.tscn")
_window = _runner.scene()
# The debug build lowers the winning score on startup; keep it out of reach
Settings.winning_score = 20
## Override to change the fake server before the window starts and sends its first
## requests.
func _before_window_starts() -> void:
pass
func after_test() -> void:
# Let nodes queued for deletion by the window be freed before orphans are counted
await await_idle_frame()
@@ -0,0 +1,41 @@
extends MainWindowTestSuite
## Startup with a slow /music/list response.
func _before_window_starts() -> void:
_server.respond_json("/music/list", [
{"SongNo": 0, "Soundtrack": "Chrono Trigger", "Song": "Corridors of Time"},
])
_next_song_is({"SongNo": 1, "Soundtrack": "Final Fantasy VI", "Song": "Dancing Mad"})
_server.hold("/music/list")
func test_preloaded_song_survives_a_slow_song_list() -> void:
_server.release("/music/list")
# The song already on the server, then the preloaded one
assert_int(Playlist.song_object_array.size()).is_equal(2)
assert_str(Playlist.song_object_array[1].song_title).is_equal("Dancing Mad")
assert_int(Playlist.get_preloaded_songs()).is_equal(1)
func test_next_plays_the_preloaded_song_after_a_slow_song_list() -> void:
_server.release("/music/list")
await _play_first_song()
assert_int(Playlist.currently_playing_song).is_equal(1)
func test_failed_song_list_is_retried_before_preloading() -> void:
_window.song_fetch_retry_seconds = 0.05
_server.respond_json("/music/list", [], 503)
_server.release("/music/list")
assert_int(_server.count("/music/rand")).is_equal(0)
_server.respond_json("/music/list", [])
await await_millis(200)
assert_int(_server.count("/music/rand")).is_equal(1)
assert_int(Playlist.get_preloaded_songs()).is_equal(1)
@@ -0,0 +1 @@
uid://sfwrqidmuj04