1
0
mirror of synced 2024-09-23 19:08:21 +02:00

Integrate bemapi readme and sample client into this repo.

This commit is contained in:
Jennifer Taylor 2022-10-12 22:53:38 +00:00
parent 84f26c9319
commit 695bfd0f7d
3 changed files with 828 additions and 0 deletions

606
bemani/api/README.md Normal file
View File

@ -0,0 +1,606 @@
For the purposes of this specification, the complete API for accessing scores, user data and other information from a remote eAmusement network will be referred to as "the data portability API" or just "the API." The version of this spec is currently "v1". When specifying attribute names or values, the case-sensitive, valid values will be presented either in "quotes" or in ``monospace``.
# Wire Protocol
The API should be implemented as an HTTP service, utilizing only GET requests as it is read-only. Due to buggy client libraries in some languages, such as cURL, the API can also respond to POST requests in an identical fashion to GET requests. Any request parameters will be passed via the request body as a JSON object. The mime type of every request should be "application/json". Requests that have no request parameters should send an empty JSON object ({}). All requests should be authenticated against an API token previously generated by the server, placed in the "Authorization" http header with the type "Token". API tokens can be any arbitrary ASCII string (without spaces or control characters) but should be at least 1 character in length and at most 64 characters in length. All response data will be passed via the response body as a JSON object. The mime type of every response should be "application/json". The content encoding for all requests and responses should be "utf-8". On error, the mime type and content type should still be set and a JSON object with an "error" attribute describing the error should be returned. The API should use HTTPS to protect the authorization token and request/response data. HTTP features such as eTags and compression are optional, and servers should not require clients to support them, or vice versa. It is recommended to leave handling for such features up to the webserver.
An example request and response looks as such:
**Request**
GET / HTTP/1.1
Authorization: Token deadbeef
Content-Type: application/json; charset=utf-8
{}
**Response**
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{"versions":["v1"],"name":"Test Server"}
An example error request and response looks as such:
**Request**
GET /invalid/uri HTTP/1.1
Authorization: Token deadbeef
Content-Type: application/json; charset=utf-8
{}
**Response**
HTTP/1.1 405 Method Not Allowed
Content-Type: application/json; charset=utf-8
{"error": "The URI /invalid/uri was not recognized!"}
Valid status codes are as follows (essentially identical to their meaning in traditional http):
* 200 - Request okay, response follows. Return this when a valid lookup has occurred and response data should be considered valid, even in the case of no data available for the request.
* 401 - Unauthorized token. Return this when the token is not provided, invalid or has been revoked.
* 404 - Game/version combination unsupported. Return this when the requesting URI is valid but the server does not support this game/version, or when a valid object type is requested that isn't supported by this server.
* 405 - URI not allowed. Return this when an invalid URI or invalid method is requested.
* 500 - Uncaught server error. Return this on unexpected server-side problems.
* 501 - Unimplemented. Return this when a client requests a version of the API that the server does not support.
## URI Structure
The URI structure of the API will follow this format:
/<protocol version>/<game series>/<game version>
* Protocol Version - The version of this API spec the server conforms to. Currently this should be hardcoded to "v1". The purpose of this is to allow for non-backwards-compatible changes to the API in the future while not breaking existing clients.
* Game Series - The series this request is for. This works in tandem with the game version below to specify a distinct set of objects to look up (such as valid songs).
* Game Version - The version of the game this request is for. This depends on the game series being requested and is implied to be the final (latest) version of data for that particular game/version combo. Note that this is not an integer, even though in most cases it can be cast to one!
Note that some servers support games that have had songs added back in via hacks, such as IIDX Omnimix. To request data from an omni version of a game, prepend the letter "o" to the version. Servers may treat this how they wish (they may wish to strip the leading o and return only info for the original game or return 404 in the instance they don't support this version).
## Request/Response Format
Each request should have a JSON object that specifies the "ids", "type" and "objects" parameters, as attributes. The "ids" attribute should be a list of zero or more string IDs, as interpreted by the "type" attribute. Note that the ordering for this list is important, objects with more than one part to their ID (such as the 'song' type) will have different meaning for each part of the ID. The "type" attribute should be a string, with valid values documented below. The "objects" attribute should be a list of zero or more string objects being fetched, as documented in the Supported Objects section below. Note that there is only one "type" for all IDs requested, regardless of how many objects are being fetched. This is intentional as the request is constrained to looking up information based on one particular index to keep the response format from getting complicated. If the wrong number of list entries for an ID is requested, the server should return a 405 error code. If an object is requested with an ID that makes no sense (such as requesting a profile based on song ID), a 405 error code should be returned. If an unrecognized object is requested, the server should return a 404 error code. If an unrecognized type is requested, the server should return a 404 error code. If a request is made with zero objects, a 405 error code should be returned. No attempt to return partial data should be made when part of the request makes sense but part doesn't, or when part of the request causes an exception.
The following ID types are supported for retrieving various objects from a remote server:
* ``card`` - 16 character hex string as found when using a slotted or wavepass reader to read an eAmusement card. A client can request a list of one or more card IDs, and the response should include all information for that object type for each card IDs. In most cases, an empty response for card IDs that do not exist on the server being queried is sufficient.
* ``song`` - A game identifier for a particular song (usually an integer when talking to a game). In many cases this only makes sense in the context of a game/version so be sure to take all three into account when looking up objects by song. Optionally, a second value in the list can be provided specifying the chart for a song. Note that while these are normally integers, they should be passed to the server as strings. Unlike "card" lookups, this only allows looking up by one song or song/chart object at a time.
* ``instance`` - A list of three strings specifying the song, chart and card ID for a particular object. Identical restrictions to "card" and "song" apply to this, except for this always requires a list of three strings. Like "song", this only allows looking up by one song/chart/user at a time.
* ``server`` - No ID necessary, fetches all instances of a particular object on the server for a given game/version. An empty list should be given to the "ids" parameter.
On successful lookup, the response JSON object will have an attribute for each requested object type, named after that object request. The value of each attribute will depend on what's being looked up but could be a list (in the case of looking up records, for example) or a JSON object itself. Valid responses for each object type will be documented below in the Supported Objects section.
An example request for profile and records based on a card is as follows:
**Request**
GET /v1/iidx/24 HTTP/1.1
Authorization: Token deadbeef
Content-Type: application/json; charset=utf-8
{"ids":["E0040000DEADBEEF"],"type":"card","objects":["profile","records"]}
**Response**
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{"profile":[],"records":[]}
An example request for records based on a particular song/chart is as follows:
**Request**
GET /v1/iidx/24 HTTP/1.1
Authorization: Token deadbeef
Content-Type: application/json; charset=utf-8
{"ids":["1001", "1"],"type":"song","objects":["records"]}
**Response**
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{"records":[]}
An example request for all records on the server for a game/series is as follows:
**Request**
GET /v1/iidx/24 HTTP/1.1
Authorization: Token deadbeef
Content-Type: application/json; charset=utf-8
{"ids":[],"type":"server","objects":["records"]}
**Response**
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{"records":[]}
## Supported Games
Valid game series and their versions are as follows. Clients and servers should use the following game/version combinations to identify the objects being requested.
* ``beatstream``
* ``1`` - BeatStream
* ``2`` - BeatStream アニムトライヴ
* ``danceevolution``
* ``1`` - DanceEvolution
* ``ddr``
* ``9`` - DanceDanceRevolution SuperNova
* ``10`` - DanceDanceRevolution SuperNova 2
* ``11`` - DanceDanceRevolution X
* ``12`` - DanceDanceRevolution X2
* ``13`` - DanceDanceRevolution X3 VS 2ndMIX
* ``14`` - DanceDanceRevolution 2013
* ``15`` - DanceDanceRevolution 2014
* ``16`` - DanceDanceRevolution Ace
* ``drummania``
* TBD, please fill in logical mapping!
* ``futuretomtom``
* ``1`` - ミライダガッキ FutureTomTom
* ``guitarfreaks``
* TBD, please fill in logical mapping!
* ``iidx``
* ``18`` - IIDX 18 Resort Anthem
* ``19`` - IIDX 19 Lincle
* ``20`` - IIDX 20 Tricoro
* ``21`` - IIDX 21 SPADA
* ``22`` - IIDX 22 PENDUAL
* ``23`` - IIDX 23 copula
* ``24`` - IIDX 24 SINOBUZ
* ``25`` - IIDX 25 CANNON BALLERS
* ``26`` - IIDX 26 ROOTAGE
* ``27`` - IIDX 27 HEROIC VERSE
* ``28`` - IIDX 28 BISTROVER
* ``jubeat``
* ``1`` - Jubeat
* ``2`` - Jubeat Ripples
* ``2a`` - Jubeat Ripples Append
* ``3`` - Jubeat Knit
* ``3a`` - Jubeat Knit Append
* ``4`` - Jubeat Copious
* ``4a`` - Jubeat Copious
* ``5`` - Jubeat Saucer
* ``5a`` - Jubeat Saucer Fulfill
* ``6`` - Jubeat Prop
* ``7`` - Jubeat Qubell
* ``8`` - Jubeat Clan
* ``museca``
* ``1`` - MUSECA
* ``1p`` - MUSECA 1+1/2
* ``nostalgia``
* ``1`` - ノスタルジア
* ``2`` - ノスタルジア FORTE
* ``popnmusic``
* ``19`` - Pop'n Music Tune Street
* ``20`` - Pop'n Music Fantasia
* ``21`` - Pop'n Music Sunny Park
* ``22`` - Pop'n Music Lapistoria
* ``23`` - Pop'n Music Eclale
* ``24`` - Pop'n Music うさぎと猫と少年の夢
* ``reflecbeat``
* ``1`` - REFLEC BEAT
* ``2`` - REFLEC BEAT limelight
* ``3w`` - REFLEC BEAT colette -Winter-
* ``3sp`` - REFLEC BEAT colette -Spring-
* ``3su`` - REFLEC BEAT colette -Summer-
* ``3a`` - REFLEC BEAT colette -Autumn-
* ``3as`` - REFLEC BEAT colette -All Seasons-
* ``4`` - REFLEC BEAT groovin'!!
* ``4u`` - REFLEC BEAT groovin'!! Upper
* ``5`` - REFLEC BEAT VOLZZA
* ``5a`` - REFLEC BEAT VOLZZA 2
* ``6`` - REFLEC BEAT 悠久のリフレシア
* ``soundvoltex``
* ``1`` - Sound Voltex BOOTH
* ``2`` - Sound Voltex II Infinite Infection
* ``3`` - Sound Voltex III Gravity Wars
* ``4`` - Sound Voltex IV Heavenly Haven
## Special URIs
While normal requests will follow the exact pattern above, special URIs documented below should also be supported.
### API Information URI
/
The API Information URI should return information about the server itself. The request JSON should be an empty object. The returned JSON object should contain the following attributes:
* ``versions`` - A list of strings of supported protocol versions that this server supports. Right now, this should be a list of one string, "v1".
* ``name`` - The name of the network that we are talking to. This can be displayed on the admin panel of a client or used in a basic query to verify functionality.
* ``email`` An administrative email used to contact the network if the need arises.
# Supported Objects
The following objects are supported for fetching from the API. As documented above, each request object should be returned as an attribute named after itself in the response JSON, containing either a list of that object type, or a JSON object itself representing the response.
## Records
Identified by the "records" object type, this pulls up high scores based on the object type. For "card", it pulls up all high scores for the game/version associated with the user that owns the card. When multiple card IDs are presented, it pulls up all high scores for each user associated with each card. In the case that the user does not exist, an empty list should be returned to represent that the user does not have any scores on this network. It is expected that there will be at most one high score per song/chart/user, since a single user can only have a single high score on each song/chart. For "song", it pulls up all high scores for a game/version/song. Optionally, if the chart is provided, constrains the search to only that chart instead of returning records for all charts. For "instance", it pulls up the exact high score for a game/version/song/chart/user. If this doesn't exist, an empty list should be returned. For "server", it pulls up the record for each song/chart that the server recognizes for that game/version.
Aside from basics such as the points achieved, each game will have different attributes required, as documented in game-specific sections below. The response to the records request should be a JSON object with a "records" attribute. The "records" attribute should be a list of zero or more record objects that fit the criteria of the object type. Each record object should have the following attributes at minimum:
* ``cards`` A list of 16 character card ID strings associated with the user that owns this record. In many cases, there will be the single card ID that identifies a user on this server. In the case that a user has multiple cards associated with an account, each card ID should be returned. In the case of an anonymous score, this list should be empty.
* ``song`` The game identifier for the song this record belongs to as a string. May be version specific, so parsing it is up to the client based on the requested game/version.
* ``chart`` The game identifier for the chart this record belongs to as a string. May be version specific as above.
* ``points`` The number of points earned for this record as an integer.
* ``timestamp`` The integer UTC unix timestamp when the record was earned.
* ``updated`` The integer UTC unix timestamp when the record was last updated. This includes incrementing the play count, even if everything else stays the same.
Given that a high score, once set, is immutable, records are easily cached on the client. For that reason, it is important that a new record earned on a server change the update timestamp to the time that new record was earned. In that way, clients can request only records earned since a particular update timestamp in order to download incremental changes since last fetch given a particular ID.
### Optional Request Parameters
* ``since`` A UTC unix timestamp to constrain the range of records looked up and returned. If provided, records with an update time greater than or equal to this time should be returned, and records less than this time should be excluded.
* ``until`` A UTC unix timestamp to constrain the range of records looked up and returned. If provided, records with an update time less than this time should be returned, and records greater than or equal to this time should be excluded.
### DDR Additional Attributes and Documentation
Valid charts for DDR according to the game are as follows:
* ``0`` Single beginner
* ``1`` Single basic
* ``2`` Single difficult
* ``3`` Single expert
* ``4`` Single challenge
* ``5`` Double basic
* ``6`` Double difficult
* ``7`` Double expert
* ``8`` Double challenge
The following attribute should be returned (if available) for records belonging to the DDR series.
* ``rank`` The letter grade ranking that the user has earned, as a string enum. Should be one of the following values: "AAA", "AA+", "AA", "AA-", "A+", "A", "A-", "B+", "B", "B-", "C+", "C", "C-", "D+", "D", "E".
* ``halo`` The combo halo that the user has earned, as a string enum. Should be one of the following values:
* ``none`` The user did not earn a halo (no combo).
* ``gfc`` Good full combo.
* ``fc`` Great full combo.
* ``pfc`` Perfect full combo.
* ``mfc`` Marvelous full combo.
* ``combo`` An integer specifying the maximum combo earned.
* ``ghost`` - List of integers representing the integers that the game sends for ghost steps for a song. Note that DDR A changes this format to be a string of single digit integers, so a transformation will need to be done to fulfill this. Note that ghost steps should not be considered compatible across versions of DDR for this reason.
### IIDX Additional Attributes and Documentation
Valid charts for IIDX according to the game are as follows:
* ``0`` Normal 7key
* ``1`` Hyper 7key
* ``2`` Another 7key
* ``3`` Normal 14key
* ``4`` Hyper 14key
* ``5`` Another 14key
* ``6`` Beginner 7key
* ``7`` - Leggendaria 7key
* ``8`` - Beginner 14key
* ``9`` - Leggendaria 14key
Note that in the case of IIDX, "points" above refers to the EX score earned on the song. This is calculated as 2 ✕ pgreats + greats. The following attributes should be returned (if available) for records belonging to the IIDX series.
* ``status`` String enum representing the clear lamp earned on this particular record. Valid values are as follows:
* ``np`` no play/no clear (such as when earning a record during DAN courses).
* ``failed`` Failed song.
* ``ac`` Assist clear.
* ``ec`` Easy clear.
* ``nc`` Normal clear.
* ``hc`` Hard clear.
* ``exhc`` EX hard clear.
* ``fc`` Full combo.
* ``ghost`` List of integers in the range of 0-255, representing the bytes that the game sends for ghost steps for a song.
* ``miss`` The miss count, as an integer number of misses recorded for this record. If the miss count is not available for this song (such as the user failed out early), this should be -1. Otherwise, the valid range goes from 0 to the number of notes in the chart.
* ``pgreat`` - The count of pgreats that the user earned for this particular record. If not available, this should be -1.
* ``great`` - The count of greats that the user earned for this particular record. If not available, this should be -1.
### Jubeat Additional Attributes and Documentation
Valid charts for Jubeat according to the game are as follows:
* ``0`` Basic
* ``1`` Advanced
* ``2`` Extreme
The following attributes should be returned (if available) for records belonging to the Jubeat series.
* ``status`` The clear medal earned by the user for this record, as a string enum. Valid values are as follows:
* ``failed`` The user failed the song.
* ``cleared`` The user cleared the song with no combo.
* ``nfc`` Nearly full combo. The user got almost a full combo.
* ``fc`` Full combo.
* ``nec`` Nearly excellent combo. The user got close to perfect on each note.
* ``exc`` Excellent combo. The user earned an excellent on every note.
* ``combo`` Integer specifying the maximum combo earned when the user earned the record.
* ``ghost`` List of integers representing the ghost data sent by the game for this record.
### Museca Additional Attribute and Documentation
The following chart types are recognized by Museca according to the game:
* ``0`` Green chart.
* ``1`` Orange chart.
* ``2`` Red chart.
The following attributes should be returned (if available) for all records belonging to the Museca series:
* ``status`` String enum representing the clear status of this record. Valid values are as follows:
* ``failed`` The user failed the song for this record.
* ``cleared`` The user cleared the song for this record.
* ``fc`` The user earned a full combo for this record.
* ``rank`` String enum representing the ranking earned during this record. Valid values are as follows. Note that these correspond one-to-one with the kanji rank displayed in the UI, so they are reproduced below to avoid translation errors:
* ``death`` - 没
* ``poor`` - 拙
* ``mediocre`` - 凡
* ``good`` - 佳
* ``great`` - 良
* ``excellent`` - 優
* ``superb`` - 秀
* ``masterpiece`` - 傑
* ``perfect`` - 傑 (Identical to masterpiece kanji but shows up gold in-game).
* ``combo`` - The maximum combo earned when earning this record as an integer.
* ``buttonrate`` The integer button rate according to the game when this score was recorded.
* ``longrate`` The integer hold rate according to the game when this score was recorded.
* ``volrate`` The integer spin rate according to the game when this score was recorded.
### Pop'n Music Additional Attributes and Documentation
The following chart types are recognized by Pop'n Music Fantasia and above:
* ``0`` Easy chart
* ``1`` Normal chart
* ``2`` Hyper chart
* ``3`` EX chart
Pop'n Music Tune Street only had 'cool' timing for a particular mode (Cho Challenge mode), and thus only those scores are compatible going forward. The charts that were available in this mode are the "normal", "hyper" and "EX" chart types. Easy charts were not available, so scores should not be loaded for easy charts for Tune Street.
The following attributes should be returned (if available) for records belonging to the Pop'n Music series:
* ``status`` The clear status when this record was earned, as a string enum. Valid values are as follows:
* ``cf`` Failed, circle marker.
* ``df`` Failed, diamond marker.
* ``sf`` Failed, star marker.
* ``ec`` Easy cleared.
* ``cc`` Cleared, circle marker.
* ``dc`` Cleared, diamond marker.
* ``sc`` Cleared, star marker.
* ``cfc`` Full combo cleared, circle marker.
* ``dfc`` Full combo cleared, diamond marker.
* ``sfc`` Full combo cleared, star marker.
* ``p`` Perfect full combo cleared.
* ``combo`` Integer specifying the maximum combo earned when this record was stored.
### Reflec Beat Additional Attributes and Documentation
The following charts are recognized by Reflec Beat series. Note that special/white hard charts do not appear at all in some older series, so they shouldn't be returned when requesting records for older games.
* ``0`` Basic
* ``1`` Medium
* ``2`` Hard
* ``3`` Special/White Hard
Note that the game went through a complete redesign between Volzza 2 and Reflesia, and thus scores are not compatible across this boundary in either direction.
The following attributes should be returned (if available) for any record belonging to the Reflec Beat series:
* ``rate`` Achievement rate of this record. This should be an integer value where 0 is 0% and 10000 is 100% achievement rate. Essentially, it is the achievement rate percentage multiplied by 100.
* ``status`` Clear status according to the game as a string enum. Note that some versions conflate clear status and combo type, so some separating and combining might need to be done depending on how a network decides to store attributes. Valid values are as follows:
* ``np`` No play. Similar to IIDX, where the record was earned in a mode that does not credit the user for playing the song.
* ``failed`` The user failed the song for this record.
* ``cleared`` The user cleared this song for this record.
* ``hc`` The user hard cleared this song.
* ``shc`` The user S hard cleared the song.
* ``halo`` The combo status that was achieved when earning this record, as a string enum. Valid values are as follows:
* ``none`` The user did not earn any combo marker during this record.
* ``ac`` Almost combo. The user was close to a full combo but missed by up to two.
* ``fc`` Full combo.
* ``fcaj`` Full combo all just reflec. The user was able to full combo the song, and on top of that execute the maximum number of just reflecs available in the song.
* ``miss`` The miss count earned during this song, as an integer. If this is not available (the user earned this song in a mode that doesn't count misses, for instance), this should be set to -1.
* ``combo`` The combo earned during this song as an integer.
### SDVX Additional Attributes and Documentation
The following chart types are recognized by SDVX according to the game:
* ``0`` Novice
* ``1`` Advanced
* ``2`` Exhaust
* ``3`` Infinite
* ``4`` Maximum
The following attributes should be returned (if available) by all records belonging to the SDVX series.
* ``status`` The clear status of this record, as a string enum. Valid values are as follows:
* ``np`` No play/no clear, such as when playing during a mode that does not give you credit for clears but still saves scores (such as skill analyzer).
* ``failed`` User played and failed the chart for this record.
* ``cleared`` User cleared the chart for this record.
* ``hc`` - User hard cleared the chart for this record.
* ``uc`` User full combo'd the chart (ultimate chain) for this record.
* ``puc`` User perfected the chart (perfect ultimate chain) for this record.
* ``rank`` The clear rank that was earned by the user for this record, as a string enum. Valid values are as follows: "E" (failed, no play), "D", "C", "B", "A", "A+", "AA", "AA+", "AAA", "AAA+" and "S".
* ``combo`` The maximum combo earned by the user for this record as an integer.
* ``buttonrate`` The integer button rate according to the game when this score was recorded.
* ``longrate`` The integer hold rate according to the game when this score was recorded.
* ``volrate`` The integer knob volume rate according to the game when this score was recorded.
## Play Statistics
Identified by the "statistics" object type, this pulls up play statistics about songs based on the object type. For "card", it pulls up all play statistics specific to the user that owns the card for the requested game/version. When multiple card IDs are presented, it pulls up all play statistics for each user associated with each card. In the case that the user does not exist, an empty list should be returned to represent that the user does not have any play stats on this network. It is expected that there will be at most one set of statistics per song/chart/user, since the statistics for a song/chart/user represent the aggregate of plays by that user for the song/chart. For "song", it pulls up the aggregate play stats for the game/version/song, returning play stats for each chart recognized by the server for this game/version/song. Optionally, if the chart is provided, constrains the search to only that chart instead of returning aggregate statistics for each chart. For "instance", it pulls up the aggregate play stats for the game/version/song/chart/user. If the user has no statistics for this song/chart, an empty list should be returned. For "server", it pulls up the global play stats for each song/chart that the server recognizes for that game/version.
The response to the statistics request should be a JSON object with a "statistics" attribute. The "statistics" attribute should be a list of zero or more statistics objects that fit the criteria of the object type. Each statistics object should have the following attributes at minimum:
* ``cards`` A list of 16 character card ID strings associated with the user these statistics are for. In the case of "song" and "server" request ID types, this should be an empty list since the statistics are aggregated across multiple users.
* ``song`` The game identifier for the song these play stats belong to as a string. May be version specific, so parsing it is up to the client based on the requested game/version.
* ``chart`` The game identifier for the chart these play stats belong to as a string. May be version specific as above.
* ``updated`` The integer UTC unix timestamp when the play stats were last updated.
* ``plays`` The integer number of plays logged for this song/chart for the given ID. If unavailable, this should be set to -1.
* ``clears`` The integer number of clears logged for this song/chart for the given ID. If unavailable, this should be set to -1.
* ``combos`` The integer number of full combos logged for this song/chart for the given ID. If unavailable, this should be set to -1.
## Profile
Identified by the "profile" object type, this pulls up basic profile information for users. For "card", it pulls up the profile for the game associated with the user that owns the card. The version requested should be preferred, but if no profile exists for that exact game/version a compatible profile for another version of the game should be returned. When multiple card IDs are presented, it pulls up the profile for the user associated with each card. In the case that the user does not exist, an empty list should be returned to represent that the user does not have any profile on this network for this game. If a client is looking up multiple profiles and some are present and others are not, the returned list of profiles should only include present profiles. The client can determine that the profile for a user doesn't exist by the absence of a profile object for that card in the return. For "song" and "instance", a 405 error code should be returned to specify that this is a nonsense request. For "server", it pulls up the profile for each user that the server recognizes for that game/version. Exact matches should be returned only.
The profile request isn't currently meant to allow instantiation of full game profiles across different networks. Instead, it is provided as a way to look up in-game name and statistic information based on card ID so networks can present global scores or allow server-server rivals if desired. Given the amount of information in the profile return for each user, a server may also wish to present to the user a profile migration screen as if the user was coming from an older version of the game. In this way, the name on the profile can be pre-filled from another network as a convenience. The response to the profile request should be a JSON object with a "profile" attribute. The "profile" attribute should be a list of zero or more profile objects that fit the criteria of the object type. Each profile object should have the following attributes at minimum:
* ``cards`` A list of 16 character card ID strings associated with the user that owns this profile. In many cases, there will be the single card ID that identifies a user on this server. In the case that a user has multiple cards associated with an account, each card ID should be returned. If this profile is anonymous, this list should be empty.
* ``name`` The name associated with the profile, as a string.
* ``registered`` The integer UTC unix timestamp of profile registration. If unavailable, this should be set to -1.
* ``updated`` The integer UTC unix timestamp of the last profile update. If unavailable, this should be set to -1.
* ``plays`` The integer total number of plays this user has logged using this profile. If unavailable, this should be set to -1.
* ``match`` - A string enum representing whether this profile was an exact match or a partial match. Valid values are as follows:
* ``exact`` - This profile is for the requested game/version. Additional attributes specified below are for this game/version.
* ``partial`` - This profile is for the requested game, but a different version. If the server is capable of doing so, additional attributes should be converted for correct consumption for the game/version requested by the client. If it is not possible, they should be set to -1 to indicate they are not available for the requested game/version.
### DDR Additional Attributes and Documentation
The following attributes should be returned (if available) by all profiles belonging to the DDR series.
* ``area`` - The integer area code as set when creating a profile on DDR. If unavailable, this should be set to -1.
### IIDX Additional Attributes and Documentation
The following attributes should be returned (if available) by all profiles belonging to the IIDX series.
* ``area`` - The integer prefecture code as set when creating a profile on IIDX. If unavailable, this should be set to -1.
* ``qpro`` - An object representing the player's qpro, with the following attributes:
* ``head`` - The integer representation of the game's current setting for qpro head. If unavailable, this should be set to -1.
* ``hair`` - The integer representation of the game's current setting for qpro hair. If unavailable, this should be set to -1.
* ``face`` - The integer representation of the game's current setting for qpro face. If unavailable, this should be set to -1.
* ``body`` - The integer representation of the game's current setting for qpro body. If unavailable, this should be set to -1.
* ``hand`` - The integer representation of the game's current setting for qpro hand. If unavailable, this should be set to -1.
### Jubeat Additional Attributes and Documentation
Currently Jubeat has no additional attributes that are recognized by the API.
### Museca Additional Attribute and Documentation
Currently Museca has no additional attributes that are recognized by the API.
### Pop'n Music Additional Attributes and Documentation
The following attributes should be returned (if available) by all profiles belonging to the Pop'n Music series.
* ``character`` - The integer character code as set when creating a profile on Pop'n Music. If unavailable, this should be set to -1.
### Reflec Beat Additional Attributes and Documentation
* ``icon`` - The integer icon as set when creating or updating a Reflec Beat profile. If unavailable, this should be set to -1.
### SDVX Additional Attributes and Documentation
Currently SDVX has no additional attributes that are recognized by the API.
## Catalog
Identified by the "catalog" object type, this pulls up the complete item catalog for the requested game/version. Under most circumstances this will be limited to the song catalog, but some games require additional objects such as purchasable cards, items or unlockable characters. The only valid request to this object type uses the `server` ID type. Any request to the catalog object with any `card`, `song` or `instance` ID should return a 405 error code.
The response to the catalog request should be a JSON object with a "catalog" attribute. The "catalog" attribute should be a object, containing at least the "songs" attribute. It may optionally include other, game-specific item types as documented below. For each attribute in the catalog dictionary, there should be a list of objects that conform to that item's type. Each of these types is documented in game-specific sections below. For games that specify extra object types in the catalog response, if these attributes are not available an empty list should be returned. The same goes for the songs item type as well. If songs are not available for a supported game/version, an empty list should be returned. If a game/version combination is entirely unspported by a server, a 404 response should be returned. Only valid object entries should be returned for any catalog object type. For instance, if a game allows four different charts per song but a particular song only has two charts, song objects should only be returned for the two charts that actually exist.
Each song object found in the "songs" list should at minimum contain the following attributes:
* ``song`` - A string specifing the song ID. This is the ID for that song according to that game and version. A song may have a different ID depending on the version of a game for various reasons (for instance: often songs get renumbered). For a given song, this ID should match the ID returned in the "records" or "statistics" object type for records associated with this song if queried with the same game and version. Given a game and version, the ID and chart together make a unique key that allows you to look up song information for a particular record.
* ``chart`` - A string specifying the song chart. This, like the above ID, is game-specific. For a given song, this string should match the chart returned in the "records" or "statistics" object type for records associated with this song if queried with the same game and version. Given a game and version, the ID and chart together make a unique key that allows you to look up song information for a particular record.
* ``title`` - A string specifying the song's title. If this is unavailable for this song, a blank string should be returned.
* ``artist`` - A string specifying the song's artist. If this is unavailable for this song, a blank string should be returned.
* ``genre`` - A string specifying the song's genre. If this is unavailable for this song, a blank string should be returned.
### DDR Additional Attributes and Documentation
The following attributes should be returned (if available) for all songs belonging to the DDR series.
* ``editid`` - A string representing the edit ID for the song.
* ``difficulty`` - An integer representing the in-game difficulty for the song.
* ``bpm_min`` - An integer representing the minimum BPM of the song.
* ``bpm_max`` - An integer representing the maximum BPM of the song.
* ``category`` - A string specifying the song's folder/category. This should be a number specifying the version of the game this song comes from.
* ``groove`` - An object representing the groove stats for this particular song. This object should hold the following attributes:
* ``voltage`` - An integer specifying the voltage of this song.
* ``stream`` - An integer specifying the stream of this song.
* ``air`` - An integer specifying the air of this song.
* ``chaos`` - An integer specifying the chaos of this song.
* ``freeze`` - An integer specifying the freeze of this song.
### IIDX Additional Attributes and Documentation
The following attributes should be returned (if available) for all songs belonging to the IIDX series.
* ``difficulty`` - An integer representing the in-game difficulty for the song.
* ``bpm_min`` - An integer representing the minimum BPM of the song.
* ``bpm_max`` - An integer representing the maximum BPM of the song.
* ``notecount`` - An integer count of the number of notes in the song. This should equal one half the EX score of a 100% (MAX-0) playthrough of the song.
In order to support qpro selecting in the profile, IIDX has a qpro catalog. For every supported IIDX version, the "qpros" attribute should be present inside the catalog object and should be a list of objects containing the following values:
* ``identifier`` - A string representing a stripped down filename for the underlying qpro texture. Useful for if qpro preview is implemented.
* ``id`` - A string representing the index of the qpro according to the game.
* ``name`` - A string representing the name of the qpro according to the game
* ``type`` - A string representing the type of qpro part this is for. Can be any of: body, face, hair, hand, or head.
### Jubeat Additional Attributes and Documentation
The following attributes should be returned (if available) for all songs belonging to the Jubeat series.
* ``difficulty`` - An integer representing the in-game difficulty for the song.
* ``bpm_min`` - An integer representing the minimum BPM of the song.
* ``bpm_max`` - An integer representing the maximum BPM of the song.
Jubeat also requires the emblems catalog. For Jubeat Prop and above, the "emblems" attribute should be present inside the catalog object and should be a list of objects containing the following values:
* ``index`` - A string representing this emblem' entry's index according to the game.
* ``song`` - A string pointing at a particular song as documented above.
* ``layer`` - An integer representing the layer (1-5) where this emblem resides.
* ``evolved`` - An integer representing the emblem's in-game evolved level.
* ``rarity`` - An integer representing the rarity (1-5) of the emblem represented by this object.
* ``name`` - A string representing the text-printable name of this emblem.
### Museca Additional Attribute and Documentation
The following attributes should be returned (if available) for all songs belonging to the Museca series.
* ``difficulty`` - An integer representing the in-game difficulty for the song.
* ``bpm_min`` - An integer representing the minimum BPM of the song.
* ``bpm_max`` - An integer representing the maximum BPM of the song.
* ``limited`` - An integer specifying the limited value of this song, used for determining whether a song is locked, unlocked or purchaseable.
### Pop'n Music Additional Attributes and Documentation
The following attributes should be returned (if available) for all songs belonging to the Pop'n Music series.
* ``category`` - A string specifying the song's folder/category. This should be a number specifying the version of the game this song comes from.
* ``difficulty`` - An integer representing the in-game difficulty for the song.
### Reflec Beat Additional Attributes and Documentation
The following attributes should be returned (if available) for all songs belonging to the Reflec Beat series.
* ``category`` - A string specifying the song's folder/category. This should be a number specifying the version of the game this song comes from.
* ``difficulty`` - An integer representing the in-game difficulty for the song.
* ``musicid`` - A four-character string specifying the music filename prefix for the song.
### SDVX Additional Attributes and Documentation
The following attributes should be returned (if available) for all songs belonging to the SDVX series.
* ``difficulty`` - An integer representing the in-game difficulty for the song.
* ``bpm_min`` - An integer representing the minimum BPM of the song.
* ``bpm_max`` - An integer representing the maximum BPM of the song.
* ``limited`` - An integer specifying the limited value of this song, used for determining whether a song is locked, unlocked or purchaseable.
SDVX also has several other required catalog entries. Namely, for SDVX 1 purchaseable unlocks to work, the purchase catalog must be present. Also, for SDVX 2 and above, the appeal card catalog must be present in order to track and allow purchases. For SDVX 1, the "purchases" attribute should be present inside the catalog object and should be a list of objects containing the following values:
* ``catalogid`` - A string representing this catalog entry's ID according to the game.
* ``song`` - A string pointing at a particular song as documented above. Together with the chart, this provides a unique key to looking up a song which is to be purchased.
* ``chart`` - A string pointing at a particular chart as documented above. Together with the song, this provides a unique key to looking up a song which is to be purchased.
* ``price`` - An integer representing the number of blocks required to purchase this song in-game.
For SDVX 2 and above, appeal cards are introduced. For appeal card purchases to work, the appeal card catalog must be present. The "appealcards" attribute should be present inside the catalog object and should be a list of objects containing the following values:
* ``appealid`` - A string representing this card's ID according to the game.
* ``description`` - A string representing this card's description according to the game.

211
bemani/utils/sampleclient.py Executable file
View File

@ -0,0 +1,211 @@
#! /usr/bin/env python3
import argparse
import json
import requests
import sys
from typing import Dict, List, Any, Optional
class APIClient:
API_VERSION = 'v1'
def __init__(self, base_uri: str, token: str) -> None:
self.base_uri = base_uri
self.token = token
def exchange_data(self, request_uri: str, request_args: Dict[str, Any]) -> Dict[str, Any]:
if self.base_uri[-1:] != '/':
uri = '{}/{}'.format(self.base_uri, request_uri)
else:
uri = '{}{}'.format(self.base_uri, request_uri)
headers = {
'Authorization': 'Token {}'.format(self.token),
'Content-Type': 'application/json; charset=utf-8',
}
data = json.dumps(request_args).encode('utf8')
r = requests.request(
'GET',
uri,
headers=headers,
data=data,
allow_redirects=False,
)
if r.headers['content-type'] != 'application/json; charset=utf-8':
raise Exception('API returned invalid content type \'{}\'!'.format(r.headers['content-type']))
jsondata = r.json()
if r.status_code == 200:
return jsondata
if 'error' not in jsondata:
raise Exception('API returned error code {} but did not include \'error\' attribute in response JSON!'.format(r.status_code))
error = jsondata['error']
if r.status_code == 401:
raise Exception('The API token used is not authorized against the server!')
if r.status_code == 404:
raise Exception('The server does not support this game/version or request object and returned \'{}\''.format(error))
if r.status_code == 405:
raise Exception('The server did not recognize the request and returned \'{}\''.format(error))
if r.status_code == 500:
raise Exception('The server had an error processing the request and returned \'{}\''.format(error))
if r.status_code == 501:
raise Exception('The server does not support this version of the API!')
raise Exception('The server returned an invalid status code {}!'.format(r.status_code))
def info_exchange(self) -> None:
resp = self.exchange_data('', {})
print('Server name: {}'.format(resp['name']))
print('Server admin email: {}'.format(resp['email']))
print('Server supported versions: {}'.format(', '.join(resp['versions'])))
def __id_check(self, idtype: str, ids: List[str]) -> None:
if idtype not in ['card', 'song', 'instance', 'server']:
raise Exception('Invalid ID type provided!')
if idtype == 'card' and len(ids) == 0:
raise Exception('Invalid number of IDs given!')
if idtype == 'song' and len(ids) not in [1, 2]:
raise Exception('Invalid number of IDs given!')
if idtype == 'instance' and len(ids) != 3:
raise Exception('Invalid number of IDs given!')
if idtype == 'server' and len(ids) != 0:
raise Exception('Invalid number of IDs given!')
def records_exchange(self, game: str, version: str, idtype: str, ids: List[str], since: Optional[int], until: Optional[int]) -> None:
self.__id_check(idtype, ids)
params = {
'ids': ids,
'type': idtype,
'objects': ['records'],
} # type: Dict[str, Any]
if since is not None:
params['since'] = since
if until is not None:
params['until'] = until
resp = self.exchange_data(
'{}/{}/{}'.format(self.API_VERSION, game, version),
params,
)
print(json.dumps(resp['records'], indent=4))
def profile_exchange(self, game: str, version: str, idtype: str, ids: List[str]) -> None:
self.__id_check(idtype, ids)
resp = self.exchange_data(
'{}/{}/{}'.format(self.API_VERSION, game, version),
{
'ids': ids,
'type': idtype,
'objects': ['profile'],
},
)
print(json.dumps(resp['profile'], indent=4))
def statistics_exchange(self, game: str, version: str, idtype: str, ids: List[str]) -> None:
self.__id_check(idtype, ids)
resp = self.exchange_data(
'{}/{}/{}'.format(self.API_VERSION, game, version),
{
'ids': ids,
'type': idtype,
'objects': ['statistics'],
},
)
print(json.dumps(resp['statistics'], indent=4))
def catalog_exchange(self, game: str, version: str) -> None:
resp = self.exchange_data(
'{}/{}/{}'.format(self.API_VERSION, game, version),
{
'ids': [],
'type': 'server',
'objects': ['catalog'],
},
)
print(json.dumps(resp['catalog'], indent=4))
def main():
# Global arguments
parser = argparse.ArgumentParser(description='A sample API client for an e-AMUSEMENT API provider.')
parser.add_argument('-t', '--token', type=str, required=True, help='The authorization token for speaing to the API.')
parser.add_argument('-b', '--base', type=str, required=True, help='Base URI to connect to for all requests.')
subparser = parser.add_subparsers(dest='request')
# Info request
subparser.add_parser('info')
# Score request
record_parser = subparser.add_parser('records')
record_parser.add_argument('-g', '--game', type=str, required=True, help='The game we want to look records up for.')
record_parser.add_argument('-v', '--version', type=str, required=True, help='The version we want to look records up for.')
record_parser.add_argument('-t', '--type', type=str, required=True, choices=['card', 'song', 'instance', 'server'], help='The type of ID used to look up records.')
record_parser.add_argument('-s', '--since', metavar='TIMESTAMP', default=None, type=int, help='Only load records updated since TIMESTAMP')
record_parser.add_argument('-u', '--until', metavar='TIMESTAMP', default=None, type=int, help='Only load records updated before TIMESTAMP')
record_parser.add_argument('id', metavar='ID', nargs='*', type=str, help='The ID we will look up records for.')
# Profile request
profile_parser = subparser.add_parser('profile')
profile_parser.add_argument('-g', '--game', type=str, required=True, help='The game we want to look profiles up for.')
profile_parser.add_argument('-v', '--version', type=str, required=True, help='The version we want to look profiles up for.')
profile_parser.add_argument('-t', '--type', type=str, required=True, choices=['card', 'server'], help='The type of ID used to look up profiles.')
profile_parser.add_argument('id', metavar='ID', nargs='*', type=str, help='The ID we will look up profiles for.')
# Statistics request
statistic_parser = subparser.add_parser('statistics')
statistic_parser.add_argument('-g', '--game', type=str, required=True, help='The game we want to look statistics up for.')
statistic_parser.add_argument('-v', '--version', type=str, required=True, help='The version we want to look statistics up for.')
statistic_parser.add_argument('-t', '--type', type=str, required=True, choices=['card', 'song', 'instance', 'server'], help='The type of ID used to look up statistics.')
statistic_parser.add_argument('id', metavar='ID', nargs='*', type=str, help='The ID we will look up statistics for.')
# Catalog request
catalog_parser = subparser.add_parser('catalog')
catalog_parser.add_argument('-g', '--game', type=str, required=True, help='The game we want to look catalog entries up for.')
catalog_parser.add_argument('-v', '--version', type=str, required=True, help='The version we want to look catalog entries up for.')
# Grab args
args = parser.parse_args()
client = APIClient(args.base, args.token)
if args.request == 'info':
client.info_exchange()
elif args.request == 'records':
client.records_exchange(
args.game,
args.version,
args.type,
args.id,
args.since,
args.until,
)
elif args.request == 'profile':
client.profile_exchange(
args.game,
args.version,
args.type,
args.id,
)
elif args.request == 'statistics':
client.statistics_exchange(
args.game,
args.version,
args.type,
args.id,
)
elif args.request == 'catalog':
client.catalog_exchange(
args.game,
args.version,
)
else:
raise Exception('Invalid request type {}!'.format(args.request))
if __name__ == '__main__':
try:
main()
except Exception as e:
print(e, file=sys.stderr)
sys.exit(1)

11
sampleclient Executable file
View File

@ -0,0 +1,11 @@
#! /usr/bin/env python3
if __name__ == "__main__":
import os
path = os.path.abspath(os.path.dirname(__file__))
name = os.path.basename(__file__)
import sys
sys.path.append(path)
import runpy
runpy.run_module(f"bemani.utils.{name}", run_name="__main__")