Change soundtrack covers from the app and show the cover with the answer
Cover menu in the soundtrack popup ("Change cover"):
- Choose picture uploads a JPEG, PNG or WebP picture (up to 10 MB).
- Pick by ID uses a game's cover on SteamGridDB or an anime's on AniList.
- Remove cover deletes it, so the server searches for a new one.
- The server's reason is shown when it refuses a change.
After a change the new cover time is fetched, and the popup, the
statistics card and the quiz show the new cover.
Quiz: once the answer is shown, the soundtrack's cover shows to the left of
the titles. Cover and titles are centered together, left and right and up
and down, and each title keeps to two lines. Cover times come from the
soundtrack list, and songs keep their soundtrack's UUID, also in saves.
Requests can now send any body with its content type, and every 2xx answer
counts as success. Cover frames are 2:3 like the server's covers. Small
copies of real covers are used by the tests and screenshots.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
ef6ac8f1fd
commit
06421bb63e
33 files changed
+3966
-920
No files matched your search
@@ -6,6 +6,13 @@ extends RefCounted
|
||||
##
|
||||
## Covers are downloaded a few at a time, in the order they are asked for, so opening the
|
||||
## statistics doesn't send a request for every soundtrack at once.
|
||||
##
|
||||
## It also remembers each soundtrack's cover time from the soundtrack lists it is given,
|
||||
## so [method fetch_cover_of] finds a cover by the soundtrack alone, e.g. in the quiz.
|
||||
|
||||
## Emitted when the cover time of a soundtrack is new or changed, e.g. once the soundtrack
|
||||
## list has loaded or a cover was changed.
|
||||
signal cover_times_changed
|
||||
|
||||
const FOLDER_NAME: String = "covers"
|
||||
## How many covers are downloaded at the same time.
|
||||
@@ -18,6 +25,8 @@ var _waiting: Array[Array] = []
|
||||
# Who is waiting for each cover that is asked for or downloading: uuid -> Array[Callable]
|
||||
var _callbacks: Dictionary = {}
|
||||
var _downloading: int = 0
|
||||
# The server's cover time of each soundtrack seen: uuid -> int, 0 for none
|
||||
var _times: Dictionary = {}
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
@@ -32,6 +41,7 @@ static func folder() -> String:
|
||||
## Deletes the covers of soundtracks that are not in [param covers] (UUID -> cover
|
||||
## time), and those whose soundtrack no longer has a cover.
|
||||
func keep_only(covers: Dictionary) -> void:
|
||||
set_cover_times(covers)
|
||||
var kept: Dictionary = {}
|
||||
for uuid: String in covers:
|
||||
if int(covers[uuid]) > 0:
|
||||
@@ -39,6 +49,45 @@ func keep_only(covers: Dictionary) -> void:
|
||||
_files.keep_only(kept)
|
||||
|
||||
|
||||
## Remembers the cover times in [param covers] (UUID -> cover time, 0 for no cover) and
|
||||
## emits [signal cover_times_changed] when any is new or changed.
|
||||
func set_cover_times(covers: Dictionary) -> void:
|
||||
var changed: bool = false
|
||||
for uuid: String in covers:
|
||||
var modified: int = int(covers[uuid])
|
||||
if _times.get(uuid, -1) != modified:
|
||||
_times[uuid] = modified
|
||||
changed = true
|
||||
if changed:
|
||||
cover_times_changed.emit()
|
||||
|
||||
|
||||
## The cover time of the soundtrack [param uuid], 0 when it has no cover or none is known.
|
||||
func cover_time(uuid: String) -> int:
|
||||
return _times.get(uuid, 0)
|
||||
|
||||
|
||||
## Like [method fetch_cover], with the cover time remembered for the soundtrack.
|
||||
func fetch_cover_of(uuid: String, on_done: Callable) -> void:
|
||||
fetch_cover(uuid, cover_time(uuid), on_done)
|
||||
|
||||
|
||||
## Asks the server for the cover time of the soundtrack [param uuid] again, e.g. after
|
||||
## its cover was changed, then calls [param on_done] with the new time, 0 for no cover.
|
||||
## A removed cover is deleted from disk too. When the server doesn't answer, it is called
|
||||
## with the time it had.
|
||||
func refresh(uuid: String, on_done: Callable) -> void:
|
||||
var with_soundtrack: Callable = func with_soundtrack(
|
||||
soundtrack: SoundtrackWithSongList) -> void:
|
||||
if soundtrack.cover_modified <= 0:
|
||||
_files.remove(uuid)
|
||||
set_cover_times({uuid: soundtrack.cover_modified})
|
||||
on_done.call(soundtrack.cover_modified)
|
||||
# Without an answer the cover is left as it was
|
||||
MusicServerClient.fetch_soundtrack(uuid, with_soundtrack,
|
||||
func() -> void: on_done.call(cover_time(uuid)))
|
||||
|
||||
|
||||
## Calls [param on_done] with the cover of the soundtrack [param uuid] as an [Image]:
|
||||
## from disk when the cached one has the server's time [param modified], otherwise once
|
||||
## it has been downloaded. Nothing is called when the soundtrack has no cover
|
||||
|
||||
Reference in new issue
Block a user