diff --git a/bemani/backend/hellopopn/__init__.py b/bemani/backend/hellopopn/__init__.py index 1c6a8aa..b1d2729 100644 --- a/bemani/backend/hellopopn/__init__.py +++ b/bemani/backend/hellopopn/__init__.py @@ -4,4 +4,4 @@ from bemani.backend.hellopopn.base import HelloPopnBase __all__ = [ "HelloPopnFactory", "HelloPopnBase", -] \ No newline at end of file +] diff --git a/bemani/backend/hellopopn/base.py b/bemani/backend/hellopopn/base.py index b01c99f..7251be1 100644 --- a/bemani/backend/hellopopn/base.py +++ b/bemani/backend/hellopopn/base.py @@ -1,9 +1,7 @@ -from typing import Optional from typing_extensions import Final from bemani.backend.base import Base from bemani.backend.core import CoreHandler, CardManagerHandler, PASELIHandler -from bemani.common import GameConstants, ValidatedDict -from bemani.protocol import Node +from bemani.common import GameConstants class HelloPopnBase(CoreHandler, CardManagerHandler, PASELIHandler, Base): diff --git a/bemani/backend/hellopopn/factory.py b/bemani/backend/hellopopn/factory.py index 1738a49..d0dfc5c 100644 --- a/bemani/backend/hellopopn/factory.py +++ b/bemani/backend/hellopopn/factory.py @@ -24,4 +24,4 @@ class HelloPopnFactory(Factory): return HelloPopnMusic(data, config, model) # Unknown game version - return None \ No newline at end of file + return None diff --git a/bemani/backend/hellopopn/hellopopn.py b/bemani/backend/hellopopn/hellopopn.py index b24e647..7207c01 100644 --- a/bemani/backend/hellopopn/hellopopn.py +++ b/bemani/backend/hellopopn/hellopopn.py @@ -5,9 +5,10 @@ from typing import Any, Dict from bemani.backend.hellopopn.base import HelloPopnBase from bemani.backend.ess import EventLogHandler from bemani.common import ValidatedDict, VersionConstants, Profile -from bemani.data import Score +from bemani.data import Score from bemani.protocol import Node + class HelloPopnMusic( EventLogHandler, HelloPopnBase, @@ -16,14 +17,11 @@ class HelloPopnMusic( version = VersionConstants.HELLO_POPN_MUSIC @classmethod - def get_settings(cls) -> Dict[str, Any]: """ Return all of our front-end modifiably settings. """ return { - "ints": [ - ], 'bools': [ { 'name': 'Force Song Unlock', @@ -46,18 +44,18 @@ class HelloPopnMusic( flag.set_attribute("t", '1') root.add_child(Node.u32("cnt_music", 36)) - + return root - + def handle_game_shop_request(self, request: Node) -> Node: root = Node.void('game') return root def handle_game_new_request(self, request: Node) -> Node: - #profile creation + # profile creation root = Node.void('game') - + userid = self.data.remote.user.from_refid(self.game, self.version, request.attribute('refid')) defaultprofile = Profile( @@ -66,12 +64,12 @@ class HelloPopnMusic( request.attribute('refid'), 0, { - 'name': "なし", - 'chara': "0", - 'music_id': "0", - 'level': "0", - 'style': "0", - 'love': "0" + 'name': "なし", + 'chara': "0", + 'music_id': "0", + 'level': "0", + 'style': "0", + 'love': "0" }, ) self.put_profile(userid, defaultprofile) @@ -79,33 +77,31 @@ class HelloPopnMusic( return root def handle_game_load_request(self, request: Node) -> Node: - #Load profile values + # Load profile values root = Node.void('game') - userid = self.data.remote.user.from_refid(self.game, self.version, request.attribute('refid')) profile = self.get_profile(userid) - + achievements = self.data.local.user.get_achievements(self.game, self.version, userid) game_config = self.get_game_config() force_unlock_songs = game_config.get_bool("force_unlock_songs") - #if we send all chara love as max, all songs will be unlocked + # if we send all chara love as max, all songs will be unlocked if force_unlock_songs: - for n in range(12): - chara = Node.void('chara') - chara.set_attribute('id', str(n)) - chara.set_attribute('love', "5") - root.add_child(chara) + for n in range(12): + chara = Node.void('chara') + chara.set_attribute('id', str(n)) + chara.set_attribute('love', "5") + root.add_child(chara) else: - #load chara love progress - for achievement in achievements: - if achievement.type == 'toki_love': - chara = Node.void('chara') - chara.set_attribute('id', str(achievement.id)) - chara.set_attribute('love', achievement.data.get_str('love')) - root.add_child(chara) - + # load chara love progress + for achievement in achievements: + if achievement.type == 'toki_love': + chara = Node.void('chara') + chara.set_attribute('id', str(achievement.id)) + chara.set_attribute('love', achievement.data.get_str('love')) + root.add_child(chara) last = Node.void('last') root.add_child(last) @@ -115,11 +111,11 @@ class HelloPopnMusic( last.set_attribute('style', profile.get_str('style')) self.update_play_statistics(userid) - + return root def handle_game_load_m_request(self, request: Node) -> Node: - #Load scores + # Load scores userid = self.data.remote.user.from_refid(self.game, self.version, request.attribute('refid')) scores = self.data.remote.music.get_scores(self.game, self.version, userid) @@ -129,7 +125,7 @@ class HelloPopnMusic( if score.id not in sortedscores: sortedscores[score.id] = {} sortedscores[score.id][score.chart] = score - + for song in sortedscores: for chart in sortedscores[song]: score = sortedscores[song][chart] @@ -152,7 +148,7 @@ class HelloPopnMusic( return root def handle_game_save_request(self, request: Node) -> Node: - #Save profile data + # Save profile data root = Node.void('game') userid = self.data.remote.user.from_refid(self.game, self.version, request.attribute('refid')) @@ -169,35 +165,32 @@ class HelloPopnMusic( self.put_profile(userid, newprofile) - game_config = self.get_game_config() force_unlock_songs = game_config.get_bool("force_unlock_songs") - #if we were on force unlock mode, achievements will not be modified + # if we were on force unlock mode, achievements will not be modified if force_unlock_songs is False: - achievements = self.data.local.user.get_achievements(self.game, self.version, userid) - love = last.attribute('love') - for achievement in achievements: - if achievement.type == 'toki_love' and achievement.id == int(last.attribute('chara')): - love = str(int(achievement.data["love"]) + 1) - if achievement.data["love"] == "5": - love = "5" - - - self.data.local.user.put_achievement( - self.game, - self.version, - userid, - int(last.attribute('chara')), - 'toki_love', - { - 'love': love, - }, - ) + achievements = self.data.local.user.get_achievements(self.game, self.version, userid) + chara = int(last.attribute('chara')) + for achievement in achievements: + if achievement.type == 'toki_love' and achievement.id == chara: + love = int(achievement.data["love"]) + if love > 5: + self.data.local.user.put_achievement( + self.game, + self.version, + userid, + chara, + 'toki_love', + { + 'love': str(love + 1), + }, + ) + break return root def handle_game_save_m_request(self, request: Node) -> Node: - #Score saving + # Score saving clear_type = int(request.attribute('clear_type')) level = int(request.attribute('level')) @@ -206,8 +199,8 @@ class HelloPopnMusic( points = int(request.attribute('score')) userid = self.data.remote.user.from_refid(self.game, self.version, refid) - - #pull old score + + # Pull old score oldscore = self.data.local.music.get_score( self.game, self.version, @@ -227,15 +220,14 @@ class HelloPopnMusic( highscore = points >= oldscore.points points = max(oldscore.points, points) scoredata = oldscore.data - - #Clear type + + # Clear type scoredata.replace_int('clear_type', max(scoredata.get_int('clear_type'), clear_type)) history.replace_int('clear_type', clear_type) # Look up where this score was earned lid = self.get_machine_id() - # Write the new score back self.data.local.music.put_score( self.game, @@ -261,7 +253,7 @@ class HelloPopnMusic( history, highscore, ) - + root = Node.void('game') - return root \ No newline at end of file + return root diff --git a/bemani/client/hellopopn/__init__.py b/bemani/client/hellopopn/__init__.py index 16e4724..d4f6cb2 100644 --- a/bemani/client/hellopopn/__init__.py +++ b/bemani/client/hellopopn/__init__.py @@ -3,4 +3,4 @@ from bemani.client.hellopopn.hellopopn import HelloPopnMuiscClient __all__ = [ "HelloPopnMuiscClient", -] \ No newline at end of file +] diff --git a/bemani/client/hellopopn/hellopopn.py b/bemani/client/hellopopn/hellopopn.py index 800e39c..f892d13 100644 --- a/bemani/client/hellopopn/hellopopn.py +++ b/bemani/client/hellopopn/hellopopn.py @@ -1,6 +1,6 @@ -import base64 +import random import time -from typing import Optional +from typing import Any, Dict, Optional from bemani.client.base import BaseClient from bemani.protocol import Node @@ -8,9 +8,7 @@ from bemani.protocol import Node class HelloPopnMuiscClient(BaseClient): - NAME = "TEST" - - def verify_game_shop(self)->None: + def verify_game_shop(self) -> None: call = self.call_node() game = Node.void("game") call.add_child(game) @@ -46,8 +44,7 @@ class HelloPopnMuiscClient(BaseClient): # Verify that response is correct self.assert_path(resp, "response/game/@status") - - def verify_game_common(self)->None: + def verify_game_common(self) -> None: call = self.call_node() game = Node.void("game") call.add_child(game) @@ -57,16 +54,21 @@ class HelloPopnMuiscClient(BaseClient): resp = self.exchange("", call) # Verify that response is correct - #self.__verify_profile(resp) + self.assert_path(resp, "response/game/@status") + self.assert_path(resp, "response/game/flag/@id") + self.assert_path(resp, "response/game/flag/@s1") + self.assert_path(resp, "response/game/flag/@s2") + self.assert_path(resp, "response/game/flag/@t") + self.assert_path(resp, "response/game/cnt_music") - def verify_game_new(self, loc: str, refid: str)->None: + def verify_game_new(self, loc: str, refid: str) -> None: call = self.call_node() game = Node.void("game") call.add_child(game) game.set_attribute("locid", loc) game.set_attribute("method", "new") game.set_attribute("refid", refid) - game.set_attribute("ver", "0") + game.set_attribute("ver", "0") # Swap with server resp = self.exchange("", call) @@ -74,13 +76,13 @@ class HelloPopnMuiscClient(BaseClient): # Verify that response is correct self.assert_path(resp, "response/game/@status") - def verify_game_load(self, refid: str)->None: + def verify_game_load(self, refid: str) -> None: call = self.call_node() game = Node.void("game") call.add_child(game) game.set_attribute("method", "load") game.set_attribute("refid", refid) - game.set_attribute("ver", "0") + game.set_attribute("ver", "0") # Swap with server resp = self.exchange("", call) @@ -90,14 +92,14 @@ class HelloPopnMuiscClient(BaseClient): self.assert_path(resp, "response/game/last/@level") self.assert_path(resp, "response/game/last/@music_id") self.assert_path(resp, "response/game/last/@style") - - def verify_game_load_m(self, refid: str)->None: + + def verify_game_load_m(self, refid: str) -> None: call = self.call_node() game = Node.void("game") call.add_child(game) game.set_attribute("method", "load_m") game.set_attribute("refid", refid) - game.set_attribute("ver", "0") + game.set_attribute("ver", "0") # Swap with server resp = self.exchange("", call) @@ -105,40 +107,65 @@ class HelloPopnMuiscClient(BaseClient): # Verify that response is correct self.assert_path(resp, "response/game/@status") - def verify_game_save_m(self, refid: str)->None: + # Grab scores + scores: Dict[int, Dict[int, int]] = {} + clears: Dict[int, Dict[int, int]] = {} + for child in resp.child("game").children: + if child.name != "music": + continue + score_data = child.child("style").child("level") + musicid = child.attribute("music_id") + chart = score_data.attribute("id") + score = score_data.attribute("score") + clear_type = score_data.attribute("clear_type") + + if musicid not in scores: + scores[musicid] = {} + if musicid not in clears: + clears[musicid] = {} + + scores[musicid][chart] = score + clears[musicid][chart] = clear_type + + return { + "scores": scores, + "clears": clears, + } + + def verify_game_save_m(self, refid: str, score: Dict[str, Any]) -> None: call = self.call_node() + + # Construct node game = Node.void("game") call.add_child(game) - game.set_attribute("clear_type", "2") - game.set_attribute("level", "1") - game.set_attribute("method", "save_m") - game.set_attribute("music_id", "1") - game.set_attribute("refid", refid) - game.set_attribute("score", "736000") - game.set_attribute("style", "0") - game.set_attribute("ver", "0") + game.set_attribute("clear_type", score["clear_type"]) + game.set_attribute("level", score["chart"]) + game.set_attribute("method", "save_m") + game.set_attribute("music_id", score["id"]) + game.set_attribute("refid", refid) + game.set_attribute("score", score["score"]) + game.set_attribute("style", "0") + game.set_attribute("ver", "0") # Swap with server resp = self.exchange("", call) - - # Verify that response is correct self.assert_path(resp, "response/game/@status") - def verify_game_save(self, loc: str , refid: str)->None: + def verify_game_save(self, loc: str , refid: str) -> None: call = self.call_node() game = Node.void("game") call.add_child(game) game.set_attribute("locid", loc) game.set_attribute("method", "save") game.set_attribute("refid", refid) - game.set_attribute("ver", "0") + game.set_attribute("ver", "0") last = Node.void("last") game.add_child(last) last.set_attribute("chara", "1") last.set_attribute("level", "1") last.set_attribute("love", "1") last.set_attribute("music_id", "1") - last.set_attribute("style", "0") + last.set_attribute("style", "0") # Swap with server resp = self.exchange("", call) @@ -146,7 +173,6 @@ class HelloPopnMuiscClient(BaseClient): # Verify that response is correct self.assert_path(resp, "response/game/@status") - def verify(self, cardid: Optional[str]) -> None: # Verify boot sequence is okay self.verify_services_get( @@ -181,7 +207,7 @@ class HelloPopnMuiscClient(BaseClient): else: card = self.random_card() print(f"Generated random card ID {card} for use.") - + if cardid is None: self.verify_cardmng_inquire(card, msg_type='unregistered', paseli_enabled=paseli_enabled) self.verify_pcbevent_put() @@ -190,12 +216,12 @@ class HelloPopnMuiscClient(BaseClient): raise Exception(f'Invalid refid \'{ref_id}\' returned when registering card') if ref_id != self.verify_cardmng_inquire(card, msg_type='new', paseli_enabled=paseli_enabled): raise Exception(f'Invalid refid \'{ref_id}\' returned when querying card') - #New profile creation - self.verify_game_new(location,ref_id) + # New profile creation + self.verify_game_new(location, ref_id) else: print("Skipping new card checks for existing card") ref_id = self.verify_cardmng_inquire(card, msg_type='query', paseli_enabled=paseli_enabled) - + # Verify pin handling and return card handling self.verify_cardmng_authpass(ref_id, correct=True) self.verify_cardmng_authpass(ref_id, correct=False) @@ -204,8 +230,99 @@ class HelloPopnMuiscClient(BaseClient): raise Exception(f'Invalid refid \'{ref_id}\' returned when querying card') self.verify_game_load(ref_id) self.verify_game_load_m(ref_id) - self.verify_game_save_m(ref_id) - self.verify_game_save(location,ref_id) + if cardid is None: + # verify score saving + for phase in [1, 2]: + if phase == 1: + dummyscores = [ + # An okay score on a chart + { + "id": "1", + "chart": "1", + "clear_type": "1", + "score": "813144", + }, + # A good score on an easier chart of the same song + { + "id": "1", + "chart": "0", + "clear_type": "4", + "score": "1000000", + }, + # A bad score on a hard chart + { + "id": "35", + "chart": "2", + "clear_type": "1", + "score": "590523", + }, + # A terrible score on an easy chart + { + "id": "28", + "chart": "0", + "clear_type": "1", + "score": "1", + }, + ] + # Random score to add in + songid = str(random.randint(1, 35)) + chartid = str(random.randint(0, 2)) + clear_type = str(random.randint(1, 4)) + score = str(random.randint(0, 1000000)) + dummyscores.append( + { + "id": songid, + "chart": chartid, + "clear_type": clear_type, + "score": score, + } + ) + if phase == 2: + dummyscores = [ + # A better score on the same chart + { + "id": "1", + "chart": "1", + "clear_type": "3", + "score": "950144", + }, + # A worse score on another same chart + { + "id": "1", + "chart": "0", + "clear_type": "1", + "score": "672381", + "expected_score": "1000000", + "expected_clear": "4", + }, + ] + for dummyscore in dummyscores: + self.verify_game_save_m(ref_id, dummyscore) + # Sleep so we don't end up putting in score history on the same second + time.sleep(1) + scores = self.verify_game_load_m(ref_id) + for expected in dummyscores: + newscore = scores["scores"][expected["id"]][expected["chart"]] + newclear = scores["clears"][expected["id"]][expected["chart"]] + if "expected_score" in expected: + expected_score = expected["expected_score"] + else: + expected_score = expected["score"] + if "expected_clear" in expected: + expected_clear = expected["expected_clear"] + else: + expected_clear = expected["clear_type"] + if newscore != expected_score: + raise Exception( + f'Expected a score of \'{expected_score}\' for song \'{expected["id"]}\' chart \'{expected["chart"]}\' but got score \'{newscore}\'' + ) + if newclear != expected_clear: + raise Exception( + f'Expected a medal of \'{expected_clear}\' for song \'{expected["id"]}\' chart \'{expected["chart"]}\' but got medal \'{newclear}\'' + ) + else: + print("Skipping score checks for existing card") + self.verify_game_save(location, ref_id) diff --git a/bemani/frontend/hellopopn/__init__.py b/bemani/frontend/hellopopn/__init__.py index 6223eb9..004b986 100644 --- a/bemani/frontend/hellopopn/__init__.py +++ b/bemani/frontend/hellopopn/__init__.py @@ -5,4 +5,4 @@ from bemani.frontend.hellopopn.cache import HelloPopnMusicCache __all__ = [ "HelloPopnMusicCache", "hpnm_pages", -] \ No newline at end of file +] diff --git a/bemani/frontend/hellopopn/cache.py b/bemani/frontend/hellopopn/cache.py index 4ec54e1..04f0dcd 100644 --- a/bemani/frontend/hellopopn/cache.py +++ b/bemani/frontend/hellopopn/cache.py @@ -1,19 +1,12 @@ from bemani.data import Config, Data -from flask_caching import Cache -from bemani.frontend.app import app +from bemani.common import cache from bemani.frontend.hellopopn.hellopopn import HelloPopnMusicFrontend + class HelloPopnMusicCache: @classmethod def preload(cls, data: Data, config: Config) -> None: - cache = Cache( - app, - config={ - "CACHE_TYPE": "filesystem", - "CACHE_DIR": config.cache_dir, - }, - ) frontend = HelloPopnMusicFrontend(data, config, cache) - frontend.get_all_songs(force_db_load=True) \ No newline at end of file + frontend.get_all_songs(force_db_load=True) diff --git a/bemani/frontend/hellopopn/endpoints.py b/bemani/frontend/hellopopn/endpoints.py index a055f5f..d9bbfff 100644 --- a/bemani/frontend/hellopopn/endpoints.py +++ b/bemani/frontend/hellopopn/endpoints.py @@ -1,5 +1,4 @@ import re -from flask import Blueprint from bemani.frontend.templates import templates_location from bemani.frontend.static import static_location from bemani.data import UserID @@ -29,7 +28,6 @@ def viewnetworkscores() -> Response: if len(network_scores["attempts"]) > 10: network_scores["attempts"] = frontend.round_to_ten(network_scores["attempts"]) - return render_react( "Global Hello Pop'n Music Scores", "hpnm/scores.react.js", @@ -47,6 +45,7 @@ def viewnetworkscores() -> Response: }, ) + @hpnm_pages.route("/scores/list") @jsonify @loginrequired @@ -54,6 +53,7 @@ def listnetworkscores() -> Dict[str, Any]: frontend = HelloPopnMusicFrontend(g.data, g.config, g.cache) return frontend.get_network_scores() + @hpnm_pages.route('/scores/') @loginrequired def viewscores(userid: UserID) -> Response: @@ -61,7 +61,7 @@ def viewscores(userid: UserID) -> Response: info = frontend.get_latest_player_info([userid]).get(userid) if info is None: abort(404) - scores = frontend.get_scores(userid,limit=100) + scores = frontend.get_scores(userid, limit=100) if len(scores) > 10: scores = frontend.round_to_ten(scores) @@ -83,6 +83,7 @@ def viewscores(userid: UserID) -> Response: }, ) + @hpnm_pages.route("/scores//list") @jsonify @loginrequired @@ -93,6 +94,7 @@ def listscores(userid: UserID) -> Dict[str, Any]: "players": {}, } + @hpnm_pages.route("/topscores/") @loginrequired def viewtopscores(musicid: int) -> Response: @@ -106,13 +108,13 @@ def viewtopscores(musicid: int) -> Response: artist = None for version in versions: - for chart in [0, 1, 2]: - details = g.data.local.music.get_song(GameConstants.HELLO_POPN, version, musicid, chart) - if details is not None: - if name is None: - name = details.name - if artist is None: - artist = details.artist + for chart in [0, 1, 2]: + details = g.data.local.music.get_song(GameConstants.HELLO_POPN, version, musicid, chart) + if details is not None: + if name is None: + name = details.name + if artist is None: + artist = details.artist if name is None: # Not a real song! @@ -161,6 +163,7 @@ def viewplayers() -> Response: }, ) + @hpnm_pages.route('/players/list') @jsonify @loginrequired @@ -208,6 +211,7 @@ def listplayer(userid: UserID) -> Dict[str, Any]: "player": info, } + @hpnm_pages.route("/options") @loginrequired def viewsettings() -> Response: @@ -270,6 +274,7 @@ def updatename() -> Dict[str, Any]: "name": name, } + @hpnm_pages.route("/records") @loginrequired def viewnetworkrecords() -> Response: diff --git a/bemani/frontend/hellopopn/hellopopn.py b/bemani/frontend/hellopopn/hellopopn.py index c6c9f70..a43d878 100644 --- a/bemani/frontend/hellopopn/hellopopn.py +++ b/bemani/frontend/hellopopn/hellopopn.py @@ -1,11 +1,11 @@ -import copy from typing import Any, Dict, Iterator, List, Tuple from flask_caching import Cache # type: ignore -from bemani.backend.hellopopn import HelloPopnFactory,HelloPopnBase +from bemani.backend.hellopopn import HelloPopnFactory, HelloPopnBase from bemani.common import Profile, ValidatedDict, GameConstants -from bemani.data import Data,UserID,Attempt, Song +from bemani.data import Data, UserID, Attempt, Song from bemani.frontend.base import FrontendBase + class HelloPopnMusicFrontend(FrontendBase): game = GameConstants.HELLO_POPN @@ -31,7 +31,7 @@ class HelloPopnMusicFrontend(FrontendBase): formatted_profile["love"] = profile.get_str("love") formatted_profile["level"] = profile.get_str("level") return formatted_profile - + def format_attempt(self, userid: UserID, attempt: Attempt) -> Dict[str, Any]: formatted_attempt = super().format_attempt(userid, attempt) formatted_attempt["clear_type"] = attempt.data.get_int("clear_type") @@ -55,4 +55,4 @@ class HelloPopnMusicFrontend(FrontendBase): new_song = super().merge_song(existing, new) if existing["difficulties"][new.chart] == 0: new_song["difficulties"][new.chart] = new.data.get_int("difficulty", 1) - return new_song \ No newline at end of file + return new_song diff --git a/bemani/utils/config.py b/bemani/utils/config.py index cf2eeed..8745c64 100644 --- a/bemani/utils/config.py +++ b/bemani/utils/config.py @@ -16,7 +16,6 @@ from bemani.common import GameConstants, cache from bemani.data import Config, Data - def load_config(filename: str, config: Config) -> None: config.update(yaml.safe_load(open(filename))) config["database"]["engine"] = Data.create_engine(config) diff --git a/bemani/utils/read.py b/bemani/utils/read.py index c7d4e7b..d8c8d53 100644 --- a/bemani/utils/read.py +++ b/bemani/utils/read.py @@ -4591,9 +4591,9 @@ class ImportHelloPopn(ImportBase): 'artist': song.artist, 'genre': song.genre, 'difficulty': { - 'easy': 0, - 'normal': 1, - 'hard': 2, + 'easy': 1, + 'normal': 10, + 'hard': 100, }, 'category': self.version } @@ -4602,10 +4602,9 @@ class ImportHelloPopn(ImportBase): # Reassemble the data reassembled_songs = [val for _, val in lut.items()] - return reassembled_songs - def import_music_db(self, songs: List[Dict[str, Any]],version: int) -> None: + def import_music_db(self, songs: List[Dict[str, Any]], version: int) -> None: if self.version is None: raise Exception('Can\'t import database for \'all\' version!') @@ -5391,9 +5390,9 @@ def main() -> None: 'No TSV provided and no remote server specified! Please ' + 'provide either a --tsv or a --server and --token option!' ) - hellopopn.import_music_db(songs,args.version) + hellopopn.import_music_db(songs, args.version) hellopopn.close() - + else: raise CLIException("Unsupported game series!")