"Add soundtrack…" in the statistics toolbar, or a folder dropped anywhere on the window, opens a popup that lists the folder's songs and uploads them to the server, which adds the soundtrack at once (Sansan/MusicServer#33). - The name comes from the folder and can be changed; characters the server refuses are replaced. - Only MP3s are uploaded, as the server takes no other; other song files are listed greyed out as left out. Hidden files are skipped. - Disc folders are flattened with the disc's number first ("1-01 Title.mp3"), as the server wants one folder. With one disc folder, names stay as they are. - Songs are sent one at a time with a progress bar, reading one file at a time. A failed song is sent again twice, then the upload is cancelled and the server's reason shown. Closing the popup cancels it too. - Not offered while the server syncs, offline, or without MP3s. - Afterwards search, the inspiration list and the statistics reload. The API types come from the server's spec (Upload, UploadFile, UploadRequest). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
123 lines
3.7 KiB
GDScript
123 lines
3.7 KiB
GDScript
extends GdUnitTestSuite
|
|
## Reading a folder to upload as a soundtrack: only MP3s are sent, disc folders are
|
|
## flattened with the disc's number first, and other song files are listed as left out.
|
|
|
|
var _dir: String
|
|
|
|
|
|
func before_test() -> void:
|
|
_dir = create_temp_dir("upload_folder_%d" % randi()).path_join("Chrono Trigger")
|
|
DirAccess.make_dir_recursive_absolute(_dir)
|
|
|
|
|
|
func _file(relative: String, size: int = 10) -> void:
|
|
var path: String = _dir.path_join(relative)
|
|
DirAccess.make_dir_recursive_absolute(path.get_base_dir())
|
|
var bytes: PackedByteArray = PackedByteArray()
|
|
bytes.resize(size)
|
|
var file: FileAccess = FileAccess.open(path, FileAccess.WRITE)
|
|
file.store_buffer(bytes)
|
|
file.close()
|
|
|
|
|
|
func _names(folder: UploadFolder) -> Array:
|
|
return folder.songs.map(func(song: Dictionary) -> String: return song.name)
|
|
|
|
|
|
func test_name_comes_from_the_folder() -> void:
|
|
_file("01 Title.mp3")
|
|
|
|
assert_str(UploadFolder.scan(_dir).suggested_name).is_equal("Chrono Trigger")
|
|
assert_str(UploadFolder.scan(_dir + "/").suggested_name).is_equal("Chrono Trigger")
|
|
|
|
|
|
func test_songs_in_natural_order_with_sizes() -> void:
|
|
_file("10 Ending.mp3", 300)
|
|
_file("2 Peaceful Days.MP3", 200)
|
|
_file("1 Title.mp3", 100)
|
|
|
|
var folder: UploadFolder = UploadFolder.scan(_dir)
|
|
|
|
assert_array(_names(folder)).contains_exactly(
|
|
["1 Title.mp3", "2 Peaceful Days.MP3", "10 Ending.mp3"])
|
|
assert_int(folder.songs[0].size).is_equal(100)
|
|
assert_int(folder.total_size).is_equal(600)
|
|
assert_str(folder.songs[0].path).is_equal(_dir.path_join("1 Title.mp3"))
|
|
|
|
|
|
func test_disc_folders_are_flattened_with_their_number() -> void:
|
|
_file("Disc 10/01 Last.mp3")
|
|
_file("Disc 2/01 Middle.mp3")
|
|
_file("Disc 1/01 First.mp3")
|
|
_file("Disc 1/Bonus/01 Extra.mp3")
|
|
|
|
var folder: UploadFolder = UploadFolder.scan(_dir)
|
|
|
|
assert_array(_names(folder)).contains_exactly(
|
|
["1-01 First.mp3", "1-01 Extra.mp3", "2-01 Middle.mp3", "3-01 Last.mp3"])
|
|
|
|
|
|
func test_one_disc_folder_keeps_the_names() -> void:
|
|
_file("CD1/01 Title.mp3")
|
|
_file("CD1/02 Theme.mp3")
|
|
_file("Scans/cover.jpg")
|
|
|
|
assert_array(_names(UploadFolder.scan(_dir))).contains_exactly(
|
|
["01 Title.mp3", "02 Theme.mp3"])
|
|
|
|
|
|
func test_folders_without_songs_are_not_discs() -> void:
|
|
_file("Artwork/front.jpg")
|
|
_file("Disc 1/01 First.mp3")
|
|
_file("Disc 2/01 Second.mp3")
|
|
|
|
assert_array(_names(UploadFolder.scan(_dir))).contains_exactly(
|
|
["1-01 First.mp3", "2-01 Second.mp3"])
|
|
|
|
|
|
func test_other_songs_are_listed_as_left_out_and_the_rest_ignored() -> void:
|
|
_file("01 Title.mp3")
|
|
_file("02 Theme.flac")
|
|
_file("Disc 2/01 Song.ogg")
|
|
_file("cover.jpg")
|
|
_file("notes.txt")
|
|
|
|
var folder: UploadFolder = UploadFolder.scan(_dir)
|
|
|
|
assert_array(_names(folder)).contains_exactly(["01 Title.mp3"])
|
|
assert_array(folder.skipped).contains_exactly(["02 Theme.flac", "Disc 2/01 Song.ogg"])
|
|
|
|
|
|
func test_hidden_files_and_folders_are_left_out() -> void:
|
|
_file("01 Title.mp3")
|
|
_file("._01 Title.mp3")
|
|
_file(".sync/01 Copy.mp3")
|
|
|
|
assert_array(_names(UploadFolder.scan(_dir))).contains_exactly(["01 Title.mp3"])
|
|
|
|
|
|
func test_same_name_twice_gets_a_number() -> void:
|
|
_file("Disc 1/01 Title.mp3")
|
|
_file("Disc 1/Extra/01 Title.mp3")
|
|
|
|
assert_array(_names(UploadFolder.scan(_dir))).contains_exactly(
|
|
["01 Title.mp3", "01 Title (2).mp3"])
|
|
|
|
|
|
func test_empty_folder_has_no_songs() -> void:
|
|
_file("cover.jpg")
|
|
|
|
assert_bool(UploadFolder.scan(_dir).has_songs()).is_false()
|
|
|
|
|
|
@warning_ignore("unused_parameter")
|
|
func test_clean_name(name: String, cleaned: String, test_parameters: Array = [
|
|
["Chrono Trigger", "Chrono Trigger"],
|
|
["Re:Zero", "Re-Zero"],
|
|
["What? <Live>", "What- -Live-"],
|
|
["AC/DC", "AC-DC"],
|
|
[" .hidden name. ", "hidden name"],
|
|
["クロノ・トリガー", "クロノ・トリガー"],
|
|
]) -> void:
|
|
assert_str(UploadFolder.clean_name(name)).is_equal(cleaned)
|