### Install maimai.py Source: https://github.com/truerou/maimai.py/blob/main/docs/get-started.md Installs the maimai.py library using pip. This is the initial step to start using the library in your Python projects. ```bash pip install maimai-py ``` -------------------------------- ### Install maimai.py Source: https://github.com/truerou/maimai.py/blob/main/README_EN.md Installs the maimai.py library using pip. Includes instructions for upgrading to the latest version. ```bash pip install maimai-py ``` ```bash pip install -U maimai-py ``` -------------------------------- ### Clash Proxy Configuration Example Source: https://github.com/truerou/maimai.py/blob/main/docs/samples/proxy_updater.md An example configuration for the Clash proxy client, demonstrating how to direct traffic for maimai.py score updates. It specifies ports, modes, and routing rules. ```yaml mixed-port: 7890 mode: rule log-level: info proxies: - name: maimai.py server: 127.0.0.1 port: 8080 type: http rules: - DOMAIN,tgk-wcaime.wahlap.com,maimai.py - MATCH,DIRECT ``` -------------------------------- ### Fetch Songs by ID and Batch (LXNS) Source: https://github.com/truerou/maimai.py/blob/main/docs/examples.md Illustrates fetching song data using the `MaimaiClient` with the `LXNSProvider`. This example shows retrieving a song by its ID and fetching multiple songs efficiently using a batch request. It includes assertions for song existence and tap counts. ```python @pytest.mark.asyncio(scope="session") async def test_songs_fetching_lxns(maimai: MaimaiClient, lxns: LXNSProvider): songs = await maimai.songs(provider=lxns) song1 = await songs.by_id(1231) assert song1 is not None assert song1.difficulties.dx[0].tap_num != 0 many_songs = await songs.get_batch([1231, 1232, 1233]) assert len(many_songs) == 3 ``` -------------------------------- ### Install maimai.py Source: https://github.com/truerou/maimai.py/blob/main/README.md Installs the maimai.py library using pip. The upgrade command ensures the latest version is installed. ```bash pip install maimai-py ``` ```bash pip install -U maimai-py ``` -------------------------------- ### Quickstart: Fetch Maimai Data Source: https://github.com/truerou/maimai.py/blob/main/README_EN.md Demonstrates how to initialize the MaimaiClient, fetch all songs, retrieve player scores and plate information using a specific provider (DivingFish), and access song details. ```python import asyncio from maimai_py import MaimaiClient, MaimaiPlates, MaimaiScores, MaimaiSongs, PlayerIdentifier, DivingFishProvider # Create a global MaimaiClient instance maimai = MaimaiClient() divingfish = DivingFishProvider(developer_token="your_token_here") async def quick_start(): # fetch all songs and their metadata songs: MaimaiSongs = await maimai.songs() # fetch divingfish user turou's scores (b50 scores by default) scores: MaimaiScores = await maimai.scores(PlayerIdentifier(username="turou"), provider=divingfish) # fetch divingfish user turou's 舞将 plate information plates: MaimaiPlates = await maimai.plates(PlayerIdentifier(username="turou"), "舞将", provider=divingfish) song = await songs.by_id(1231) # 生命不詳 by 蜂屋ななし print(f"Song 1231: {song.artist} - {song.title}") print(f"TuRou's rating: {scores.rating}, b15 top rating: {scores.scores_b15[0].dx_rating}") print(f"TuRou's 舞将: {await plates.count_cleared()}/{await plates.count_all()} cleared") asyncio.run(quick_start()) ``` -------------------------------- ### Fetch Player Data (DivingFish Provider) Source: https://github.com/truerou/maimai.py/blob/main/docs/examples.md Tests fetching player profile information using the DivingFish provider. It asserts the player's rating. ```python @pytest.mark.asyncio(scope="session") async def test_players_fetching_divingfish(maimai: MaimaiClient, divingfish: DivingFishProvider, divingfish_player: PlayerIdentifier): player = await maimai.players(divingfish_player, provider=divingfish) assert player.rating > 10000 ``` -------------------------------- ### Call maimai.py API: Get Songs List Source: https://github.com/truerou/maimai.py/blob/main/docs/concepts/client.md Provides examples of how to make an HTTP GET request to the '/songs' endpoint of the maimai.py RESTful API to retrieve a list of songs. Examples are provided for Java, C#, JavaScript, and Go. ```java import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.http.HttpHeaders; public class ApiClient { private static final String BASE_URL = "http://127.0.0.1:8000"; public static void main(String[] args) { // Example: Get songs list HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(BASE_URL + "/songs")) .header("Accept", "application/json") .build(); try { HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); HttpHeaders headers = response.headers(); System.out.println("Status Code: " + response.statusCode()); headers.map().forEach((k, v) -> System.out.println(k + ":" + v)); System.out.println("Response Body: " + response.body()); } catch (Exception e) { e.printStackTrace(); } } } ``` ```csharp using System; using System.Net.Http; using System.Threading.Tasks; public class ApiClient { private static readonly HttpClient client = new HttpClient(); private static readonly string baseUrl = "http://127.0.0.1:8000"; public static async Task Main(string[] args) { // Example: Get songs list client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json")); HttpResponseMessage response = await client.GetAsync(baseUrl + "/songs"); response.EnsureSuccessStatusCode(); string responseBody = await response.Content.ReadAsStringAsync(); Console.WriteLine("Response Body: " + responseBody); } } ``` ```javascript const baseUrl = 'http://127.0.0.1:8000'; // Example: Get songs list async function fetchSongs() { const response = await fetch(`${baseUrl}/songs`, { method: 'GET', headers: { 'Accept': 'application/json' } }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); console.log('Response Body:', data); } fetchSongs().catch(error => { console.error('There was an error!', error); }); ``` ```go package main import ( "encoding/json" "fmt" "io/ioutil" "net/http" ) const baseUrl = "http://127.0.0.1:8000" func main() { // Example: Get songs list url := baseUrl + "/songs" req, err := http.NewRequest("GET", url, nil) if err != nil { fmt.Println("Error creating request:", err) return } req.Header.Set("Accept", "application/json") client := &http.Client{} resp, err := client.Do(req) if err != nil { fmt.Println("Error sending request:", err) return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { fmt.Println("Error reading response body:", err) return } var data interface{} if err := json.Unmarshal(body, &data); err != nil { fmt.Println("Error unmarshalling response body:", err) return } fmt.Println("Response Body:", data) } ``` -------------------------------- ### Fetch Songs by ID, Alias, and Keywords (DivingFish) Source: https://github.com/truerou/maimai.py/blob/main/docs/examples.md Demonstrates fetching song data using the `MaimaiClient` with the `DivingFishProvider`. It shows how to retrieve a song by its ID, by an alias, and how to search for songs using keywords. Includes assertions for song properties and curve data. ```python @pytest.mark.asyncio(scope="session") async def test_songs_fetching_divingfish(maimai: MaimaiClient, divingfish: DivingFishProvider): songs = await maimai.songs(provider=divingfish, curve_provider=divingfish) song1 = await songs.by_id(1231) # 生命不詳 song2 = await songs.by_alias("不知死活") assert song1 is not None and song2 is not None assert song1.title == "生命不詳" assert song1.difficulties.dx[3].note_designer == "はっぴー" assert song1.difficulties.dx[3].curve is not None assert song1.difficulties.dx[3].curve.sample_size > 10000 assert song2.id == song1.id assert any([song.id == 1568 for song in await songs.by_keywords("超天酱")]) ``` -------------------------------- ### Fetch Player Data (LXNS Provider) Source: https://github.com/truerou/maimai.py/blob/main/docs/examples.md Tests fetching player profile information using the LXNS provider. It asserts the player's rating and compares it with data fetched using different player identifiers. ```python @pytest.mark.asyncio(scope="session") async def test_players_fetching_lxns(maimai: MaimaiClient, lxns: LXNSProvider, lxns_player: PlayerIdentifier): player = await maimai.players(PlayerIdentifier(friend_code=664994421382429), provider=lxns) assert player.rating > 10000 player_personal = await maimai.players(lxns_player, provider=lxns) assert player.rating == player_personal.rating ``` -------------------------------- ### Get Partner Names and Image Links Source: https://github.com/truerou/maimai.py/blob/main/docs/modules/items.md This Python example shows how to retrieve all partner items, extract their names, and construct corresponding image URLs using a base resource path and the partner's ID. It utilizes a dictionary comprehension for efficient mapping. ```python resource_base = "https://assets2.lxns.net/maimai/icon/" items = await maimai.items(PlayerPartner) partner_images = {partner.name: resource_base + f"{partner.id}.png" for partner in await items.get_all()} print(partner_images) # {'デフォルト': 'https://assets2.lxns.net/maimai/icon/1.png', ...} ``` -------------------------------- ### Pytest Fixtures for MaimaiClient and Providers Source: https://github.com/truerou/maimai.py/blob/main/docs/examples.md This snippet defines pytest fixtures used for setting up test environments. It initializes the `MaimaiClient` and various data provider clients like `LXNSProvider`, `DivingFishProvider`, and `ArcadeProvider`, along with player identifier fixtures. ```python import pytest import os from maimai import MaimaiClient from maimai.providers import LXNSProvider, DivingFishProvider, ArcadeProvider from maimai.player import PlayerIdentifier @pytest.fixture(scope="session") def maimai(): return MaimaiClient() @pytest.fixture(scope="session") def lxns(): token = os.environ.get("LXNS_DEVELOPER_TOKEN") return LXNSProvider(developer_token=token) @pytest.fixture(scope="session") def divingfish(): token = os.environ.get("DIVINGFISH_DEVELOPER_TOKEN") return DivingFishProvider(developer_token=token) @pytest.fixture(scope="session") def arcade(): return ArcadeProvider() @pytest.fixture(scope="session") def lxns_player(): personal_token = os.environ.get("LXNS_PERSONAL_TOKEN") return PlayerIdentifier(credentials=personal_token) @pytest.fixture(scope="session") def divingfish_player(): username = os.environ.get("DIVINGFISH_USERNAME") password = os.environ.get("DIVINGFISH_PASSWORD") return PlayerIdentifier(username=username, credentials=password) @pytest.fixture(scope="session") def arcade_player(): encrypted_userid = os.environ.get("ARCADE_ENCRYPTED_USERID") return PlayerIdentifier(credentials=encrypted_userid) ``` -------------------------------- ### Update Scores (LXNS Provider) Source: https://github.com/truerou/maimai.py/blob/main/docs/examples.md Tests the functionality to update scores for a player using the LXNS provider. It calls the `updates` method with an empty list of scores. ```python @pytest.mark.asyncio(scope="session") async def test_scores_updating_lxns(maimai: MaimaiClient, lxns: LXNSProvider, lxns_player: PlayerIdentifier): scores = [] await maimai.updates(PlayerIdentifier(friend_code=664994421382429), scores, provider=lxns) await maimai.updates(lxns_player, scores, provider=lxns) ``` -------------------------------- ### Maimai.py Core Functionality Source: https://github.com/truerou/maimai.py/blob/main/docs/samples/proxy_updater.md Demonstrates the core methods provided by the maimai.py library for interacting with game data via WeChat authentication. These methods abstract the complex process of proxy interception and data retrieval. ```APIDOC maimai.wechat() - Description: Initiates the WeChat OAuth authentication flow for score updates. - Usage: Call this function to generate a WeChat verification URL. - Dependencies: Requires a running proxy server configured to intercept traffic. - Returns: A URL string that the user needs to open in their WeChat client. maimai.scores(wx_player, ScoreKind.ALL, WechatProvider()) - Description: Retrieves all scores for a given player using WeChat provider. - Parameters: - wx_player: Player identifier obtained through WeChat authentication. - ScoreKind.ALL: Enum value specifying retrieval of all score types. - WechatProvider(): The provider class for WeChat authentication. - Returns: A list or structure containing the player's scores. - Related: This method is part of the data fetching mechanism after successful WeChat authentication. ``` -------------------------------- ### Update Scores (DivingFish Provider) Source: https://github.com/truerou/maimai.py/blob/main/docs/examples.md Tests the functionality to update scores for a player using the DivingFish provider. It calls the `updates` method with an empty list of scores. ```python @pytest.mark.asyncio(scope="session") async def test_scores_updating_divingfish(maimai: MaimaiClient, divingfish: DivingFishProvider, divingfish_player: PlayerIdentifier): scores = [] await maimai.updates(divingfish_player, scores, provider=divingfish) ``` -------------------------------- ### Fetch Plates and Count Cleared/Remained Source: https://github.com/truerou/maimai.py/blob/main/docs/examples.md Tests fetching a player's plates and verifying counts of cleared and remaining plates. It checks for specific songs and difficulty levels within the plate data. ```python @pytest.mark.asyncio(scope="session") async def test_plate_fetching(maimai: MaimaiClient, lxns: LXNSProvider): my_plate = await maimai.plates(PlayerIdentifier(friend_code=664994421382429), "桃将", provider=lxns) cleared_obj = [obj for obj in await my_plate.get_cleared() if obj.song.id == 411] remained_obj = [obj for obj in await my_plate.get_remained() if obj.song.id == 411] assert len(cleared_obj) == 1 and LevelIndex.MASTER in cleared_obj[0].levels assert len(remained_obj) == 1 and LevelIndex.MASTER not in remained_obj[0].levels assert await my_plate.count_cleared() + await my_plate.count_remained() == await my_plate.count_all() ``` -------------------------------- ### Fetch Scores and Player Data (Arcade Provider) Source: https://github.com/truerou/maimai.py/blob/main/docs/examples.md Tests fetching scores and player data using the Arcade provider. It asserts the player's rating and checks for connection errors, skipping the test if a connection issue occurs. ```python @pytest.mark.asyncio(scope="session") async def test_scores_fetching_arcade(maimai: MaimaiClient, arcade: ArcadeProvider, arcade_player: PlayerIdentifier): try: scores = await maimai.scores(arcade_player, provider=arcade) assert scores.rating > 2000 player: Player = await maimai.players(arcade_player, provider=arcade) assert player.rating == scores.rating except Exception: pytest.skip("Connection error, skipping the test.") ``` -------------------------------- ### Fetch Scores and Best Scores (LXNS Provider) Source: https://github.com/truerou/maimai.py/blob/main/docs/examples.md Tests fetching a player's scores and best scores using the LXNS provider. It asserts rating values, checks specific song scores, and verifies the number of scores in the best list. Includes a check for score mapping consistency. ```python @pytest.mark.asyncio(scope="session") async def test_scores_fetching_lxns(maimai: MaimaiClient, lxns: LXNSProvider, lxns_player: PlayerIdentifier): my_scores = await maimai.scores(lxns_player, provider=lxns) assert my_scores.rating_b35 > 10000 score = my_scores.by_song(1231, level_index=LevelIndex.MASTER)[0] assert score.dx_rating >= 308 if score.dx_rating else True # 生命不詳 MASTER SSS+ bests = await maimai.bests(PlayerIdentifier(friend_code=664994421382429), provider=lxns) assert my_scores.rating == bests.rating bests_fallback = await maimai.bests(lxns_player, provider=lxns) assert my_scores.rating == bests_fallback.rating assert len(bests_fallback.scores_b35) <= 35 preview = await maimai.minfo(1231, PlayerIdentifier(friend_code=664994421382429), provider=lxns) assert preview is not None assert all(score.id == preview.song.id for score in preview.scores) for song, diff, score in await my_scores.get_mapping(): assert song.id == score.id and diff.type == score.type and diff.level_index == score.level_index ``` -------------------------------- ### Quick Start with maimai.py Source: https://github.com/truerou/maimai.py/blob/main/README.md Demonstrates basic usage of the maimai.py library, including creating a client, fetching songs, player scores, and plate information using the DivingFishProvider. It shows how to retrieve song details by ID and access specific score data. ```python import asyncio from maimai_py import MaimaiClient, MaimaiPlates, MaimaiScores, MaimaiSongs, PlayerIdentifier, DivingFishProvider # 全局创建 MaimaiClient 实例 maimai = MaimaiClient() divingfish = DivingFishProvider(developer_token="your_token_here") async def quick_start(): # 获取所有歌曲及其元数据 songs: MaimaiSongs = await maimai.songs() # 获取水鱼查分器用户 turou 的分数 scores: MaimaiScores = await maimai.scores(PlayerIdentifier(username="turou"), provider=divingfish) # 获取水鱼查分器用户 turou 的舞将牌子信息 plates: MaimaiPlates = await maimai.plates(PlayerIdentifier(username="turou"), "舞将", provider=divingfish) song = await songs.by_id(1231) # 生命不詳 by 蜂屋ななし print(f"歌曲 1231 是: {song.artist} - {song.title}") print(f"TuRou 的 Rating 为: {scores.rating}, b15 中最高 Rating 为: {scores.scores_b15[0].dx_rating}") print(f"TuRou 的 舞将 完成度: {await plates.count_cleared()}/{await plates.count_all()}") asyncio.run(quick_start()) ``` -------------------------------- ### Fetch Scores and Best Scores (DivingFish Provider) Source: https://github.com/truerou/maimai.py/blob/main/docs/examples.md Tests fetching a player's scores and best scores using the DivingFish provider. It asserts rating values, checks specific song scores, and verifies the number of scores in the best list. ```python @pytest.mark.asyncio(scope="session") async def test_scores_fetching_divingfish(maimai: MaimaiClient, divingfish: DivingFishProvider, divingfish_player: PlayerIdentifier): my_scores = await maimai.scores(PlayerIdentifier(username="turou"), provider=divingfish) assert my_scores.rating_b35 > 10000 score = my_scores.by_song(1231, level_index=LevelIndex.MASTER)[0] assert score.dx_rating >= 308 if score.dx_rating else True # 生命不詳 MASTER SSS+ bests = await maimai.bests(divingfish_player, provider=divingfish) assert my_scores.rating == bests.rating assert len(bests.scores_b15) <= 15 preview = await maimai.minfo(1231, PlayerIdentifier(username="turou"), provider=divingfish) assert preview is not None assert all(score.id == preview.song.id for score in preview.scores) ``` -------------------------------- ### Upgrade maimai.py Source: https://github.com/truerou/maimai.py/blob/main/docs/get-started.md Upgrades an existing installation of the maimai.py library to the latest version using pip. The -U flag ensures the package is upgraded. ```bash pip install -U maimai-py ``` -------------------------------- ### Test MaimaiClient Singleton Behavior (Python) Source: https://github.com/truerou/maimai.py/blob/main/docs/examples.md This test validates the singleton pattern implementation for `MaimaiClient`, asserting that multiple instantiations return the same object. It also tests `MaimaiClientMultithreading`, confirming that different instances are created and their cache TTLs are correctly set. Dependencies include `pytest`, `warnings`, `MaimaiClient`, and `MaimaiClientMultithreading`. ```python @pytest.mark.asyncio(scope="session") async def test_singleton(maimai: MaimaiClient): with warnings.catch_warnings(): warnings.simplefilter("ignore") m_client2 = MaimaiClient() assert maimai is m_client2 m_client_mt1 = MaimaiClientMultithreading(cache_ttl=114) m_client_mt2 = MaimaiClientMultithreading(cache_ttl=514) assert m_client_mt1 is not m_client_mt2 assert m_client_mt1._cache_ttl == 114 assert m_client_mt2._cache_ttl == 514 ``` -------------------------------- ### Test MaimaiClient Areas Method (Python) Source: https://github.com/truerou/maimai.py/blob/main/docs/examples.md This test checks the `areas` method of the `MaimaiClient`, ensuring that the returned areas contain at least one song. It retrieves all areas and then asserts properties about the song count within each area. Dependencies include `pytest` and `MaimaiClient`. ```python @pytest.mark.asyncio(scope="session") async def test_areas(maimai: MaimaiClient): areas = await maimai.areas() assert len(await areas.get_all()) >= 1 assert all(len(area.songs) >= 1 for area in await areas.get_all()) ``` -------------------------------- ### Test MaimaiClient Regions Method (Python) Source: https://github.com/truerou/maimai.py/blob/main/docs/examples.md This test verifies the functionality of the `regions` method in the `MaimaiClient`. It asserts that the returned list of regions contains a specific region ID (2) and skips the test if a connection error occurs. Dependencies include `pytest`, `MaimaiClient`, and `ArcadeProvider`. ```python @pytest.mark.asyncio(scope="session") async def test_regions(maimai: MaimaiClient, arcade: ArcadeProvider, arcade_player: PlayerIdentifier): try: regions = await maimai.regions(arcade_player, provider=arcade) assert any(region.region_id == 2 for region in regions) except Exception: pytest.skip("Connection error, skipping the test.") ``` -------------------------------- ### MaimaiSongs Object API Reference Source: https://github.com/truerou/maimai.py/blob/main/docs/modules/songs.md Comprehensive API documentation for the MaimaiSongs object, detailing methods for retrieving, filtering, and batch fetching song data by various criteria. This includes methods for getting all songs, songs by ID, title, alias, artist, genre, BPM range, versions, keywords, and general attribute filtering. ```APIDOC MaimaiSongs Object Methods: get_all() - Returns: list[Song] - Description: Retrieves all songs from the cache. Use sparingly; prefer `by_id` or `filter` for specific needs. get_batch(ids: list[int]) - Parameters: - ids: A list of song IDs. - Returns: list[Song] - Description: Fetches songs in batches based on a provided list of IDs. Returns an empty list if no songs are found. by_id(id: int) - Parameters: - id: The song ID (always less than 10000; use modulo 10000 if necessary). - Returns: Song | None - Description: Retrieves a single song by its ID. Returns None if the song does not exist. by_title(title: str) - Parameters: - title: The exact title of the song. - Returns: Song | None - Description: Retrieves a single song by its title. Returns None if no song matches the title. by_alias(alias: str) - Parameters: - alias: A potential alias for the song. - Returns: Song | None - Description: Retrieves a single song using one of its possible aliases. Returns None if no match is found. by_artist(artist: str) - Parameters: - artist: The name of the song's artist (case-sensitive). - Returns: list[Song] - Description: Returns a list of all songs performed by the specified artist. by_genre(genre: Genre) - Parameters: - genre: The genre to filter by (case-sensitive). - Returns: list[Song] - Description: Returns a list of all songs belonging to the specified genre. by_bpm(minimum: int, maximum: int) - Parameters: - minimum: The minimum BPM (inclusive). - maximum: The maximum BPM (inclusive). - Returns: list[Song] - Description: Returns a list of songs whose BPM falls within the specified range. by_versions(versions: Version) - Parameters: - versions: The maimai major version for fuzzy matching. - Returns: list[Song] - Description: Returns a list of songs associated with the specified version. by_keywords(keywords: str) - Parameters: - keywords: A string of keywords to search for. - Returns: list[Song] - Description: Returns a list of songs matching the keywords in their title, artist, or aliases. filter(**kwargs) - Parameters: - kwargs: Arbitrary keyword arguments representing song attributes and their desired values. - Returns: list[Song] - Description: Filters songs based on provided attributes. All conditions are combined with an AND operator. Ensure attribute names and values match song properties. ``` -------------------------------- ### MaimaiClient.wechat: Get PlayerIdentifier via WeChat OAuth Source: https://github.com/truerou/maimai.py/blob/main/docs/providers/wechat.md This method facilitates obtaining a PlayerIdentifier using WeChat service account OAuth2 authentication. It involves a two-step process: first, calling `maimai.wechat()` without arguments to get an authorization URL. This URL must be accessed via a proxy (e.g., mitmproxy) to intercept specific parameters (r, t, code, state) from the WeChat OAuth2 authentication request. These intercepted parameters are then passed to a subsequent call of `maimai.wechat()` to retrieve the PlayerIdentifier. ```APIDOC MaimaiClient.wechat() Description: Initiates the WeChat OAuth2 authentication flow. Returns an authorization URL that needs to be accessed through a proxy. Parameters: None Returns: str - The authorization URL. Dependencies: Requires a proxy (e.g., mitmproxy) to intercept OAuth2 parameters. ``` ```APIDOC MaimaiClient.wechat(r: str, t: str, code: str, state: str) Description: Completes the WeChat OAuth2 authentication flow using intercepted parameters. Retrieves the PlayerIdentifier. Parameters: r (str): The 'r' parameter intercepted from the OAuth2 response. t (str): The 't' parameter intercepted from the OAuth2 response. code (str): The 'code' parameter intercepted from the OAuth2 response. state (str): The 'state' parameter intercepted from the OAuth2 response. Returns: PlayerIdentifier - The identified player's identifier. Dependencies: Requires prior successful execution of `MaimaiClient.wechat()` without arguments and parameter interception. ``` -------------------------------- ### Initialize ArcadeProvider with Proxy Source: https://github.com/truerou/maimai.py/blob/main/docs/providers/arcade.md Demonstrates how to initialize the ArcadeProvider with an HTTP proxy. This is useful for users who need to route network traffic through a proxy server to access the arcade machine servers. ```python from maimai import ArcadeProvider provider = ArcadeProvider(http_proxy="http://127.0.0.1:7890") ``` -------------------------------- ### Get 桃将 Completion Percentage Source: https://github.com/truerou/maimai.py/blob/main/docs/modules/plates.md Demonstrates how to fetch player data for the '桃将' plate and calculate the completion percentage. It retrieves the number of cleared and remaining difficulties to compute the overall progress. ```python my_plate = await maimai.plates(PlayerIdentifier(friend_code=664994421382429), "桃将", provider=lxns) cleared_num = await my_plate.count_cleared() remained_num = await my_plate.count_remained() percentage = cleared_num / (cleared_num + remained_num) * 100 print(f"桃将完成度: {percentage:.2f}%,已完成 {cleared_num} 难度,剩余 {remained_num} 难度") ``` -------------------------------- ### Get 舞将 Remaining Scores Source: https://github.com/truerou/maimai.py/blob/main/docs/modules/plates.md Illustrates fetching all remaining songs and their scores for the '舞将' plate. It iterates through the returned `PlateObject` list to display song titles and difficulty details for uncompleted items. ```python my_plate = await maimai.plates(PlayerIdentifier(friend_code=664994421382429), "舞将", provider=lxns) remained_obj = await my_plate.get_remained() for plate_obj in remained_obj: print(f"歌曲: {plate_obj.song.title}") for score in plate_obj.scores: print(f" - 难度: {score.level_index}, 分数: {score.rate.name}") ``` -------------------------------- ### MaimaiClient Instance and Caching Source: https://github.com/truerou/maimai.py/blob/main/docs/get-started.md Explains the importance of creating a single, global instance of MaimaiClient to leverage its caching mechanism effectively. Repeated calls to methods like `songs()` will hit the cache, improving performance. ```python from maimai_py import MaimaiClient, MaimaiSongs, MaimaiScores # ✅ 全局创建一个 MaimaiClient 实例, 避免缓存失效 maimai = MaimaiClient() async def main(): songs: MaimaiSongs = await maimai.songs() # 填充缓存 songs: MaimaiSongs = await maimai.songs() # 命中缓存 scores: MaimaiScores = await maimai.scores(...) ``` -------------------------------- ### Provider Usage: Fetching Player Info and Songs Source: https://github.com/truerou/maimai.py/blob/main/docs/get-started.md Illustrates how to specify a data source (provider) when fetching player information and songs. It shows fetching player data from DivingFish and songs (which defaults to LXNS if no provider is specified for songs). ```python from maimai_py import MaimaiClient, DivingFishProvider, MaimaiSongs, PlayerIdentifier client = MaimaiClient() divingfish = DivingFishProvider(developer_token="your_token_here") async def main(): # 从水鱼查分器获取用户 turou 的玩家信息 player = await maimai.players(PlayerIdentifier(username="turou"), provider=divingfish) # 获取所有歌曲及其元数据 (因为未提供数据源,默认选择了落雪数据源来缓存歌曲信息) songs: MaimaiSongs = await maimai.songs() ``` -------------------------------- ### Get Best 50 Player Scores Source: https://github.com/truerou/maimai.py/blob/main/docs/modules/scores.md Explains the usage of the `maimai.bests()` method, which is optimized for retrieving only the player's top 50 scores. It returns a `MaimaiScores` object containing just these best performances, saving resources when all scores are not needed. ```python # Example usage for maimai.bests() # my_best_scores = await maimai.bests(PlayerIdentifier(username="turou"), provider=divingfish) # print(f"Player's Best 50 Rating: {my_best_scores.rating}") ``` -------------------------------- ### Maimai.py Client API Documentation Source: https://github.com/truerou/maimai.py/blob/main/README_EN.md Provides access to the RESTful API client for maimai.py, allowing development in any programming language. Documentation is available at openapi.maimai.turou.fun. ```APIDOC MaimaiClient: __init__(base_url: str = "https://api.maimai.turou.fun/v1") base_url: The base URL for the API. songs(provider: Provider = None) -> MaimaiSongs Fetches all songs and their metadata. provider: Optional provider to filter songs. Returns: A MaimaiSongs object containing song data. scores(player_identifier: PlayerIdentifier, provider: Provider, limit: int = 50, offset: int = 0) -> MaimaiScores Fetches player scores. player_identifier: Identifier for the player (e.g., username, WeChat OpenID). provider: The data source provider (e.g., DivingFishProvider). limit: Number of scores to retrieve. offset: Offset for pagination. Returns: A MaimaiScores object containing score data. plates(player_identifier: PlayerIdentifier, plate_name: str, provider: Provider) -> MaimaiPlates Fetches player plate information. player_identifier: Identifier for the player. plate_name: The name of the plate to query. provider: The data source provider. Returns: A MaimaiPlates object containing plate data. PlayerIdentifier: __init__(username: str = None, wechat_openid: str = None) username: Player's username. wechat_openid: Player's WeChat OpenID. Provider: Abstract base class for data providers. DivingFishProvider: __init__(developer_token: str) developer_token: Token for accessing DivingFish API. Example Usage: client = MaimaiClient() divingfish = DivingFishProvider(developer_token="YOUR_TOKEN") player_scores = await client.scores(PlayerIdentifier(username="turou"), provider=divingfish) print(player_scores.rating) ``` -------------------------------- ### Get All Player Scores Source: https://github.com/truerou/maimai.py/blob/main/docs/modules/scores.md Demonstrates fetching all scores for a player using the `maimai.scores()` method. It shows how to access specific score details like achievements and calculate statistics such as the ratio of SSSP to SSS ratings, along with the total rating. ```python divingfish = DivingFishProvider(developer_token="your_token_here") my_scores = await maimai.scores(PlayerIdentifier(username="turou"), provider=divingfish) score = my_scores.by_song(1231, level_index=LevelIndex.MASTER)[0] print("兔肉在 生命不詳(1231) MASTER 的 达成度:", score.achievements) sssp_count = len([s for s in my_scores.scores if s.rate == RateType.SSSP]) sss_count = len([s for s in my_scores.scores if s.rate == RateType.SSS]) all_count = sssp_count + sss_count percentage = sssp_count / all_count if all_count > 0 else 0 print(f"兔肉的 鸟加 / 总鸟 比例: {sssp_count} / {all_count} = {percentage:.2%}, 总 Rating: {my_scores.rating}") ``` -------------------------------- ### Initialize SwaggerUI with OpenAPI Spec Source: https://github.com/truerou/maimai.py/blob/main/docs/swagger.html This snippet initializes SwaggerUI using the provided OpenAPI JSON specification. It configures the UI to load the API documentation and display it within a specified DOM element, setting up presets and layout. ```javascript window.onload = () => { window.ui = SwaggerUIBundle({ url: "https://openapi.maimai.turou.fun/openapi.json", dom_id: "#swagger-ui", presets: [SwaggerUIBundle.presets.apis, SwaggerUIStandalonePreset], layout: "StandaloneLayout" }); }; ``` -------------------------------- ### Get Maimai Area by ID using Python Source: https://github.com/truerou/maimai.py/blob/main/docs/modules/areas.md Fetches a specific Maimai area object using its unique ID. This method is called on the `MaimaiAreas` object obtained from `maimai.areas()`. It returns a single `Area` object or `None` if the ID does not exist. ```python areas = await maimai.areas() heaven4 = await areas.by_id("heaven4") assert heaven4 is not None print(heaven4.name) # 天界ちほー4 print(heaven4.description) # ……この身は穢れ、もう天界には戻れない。 ```