Metadata-Version: 2.1
Name: spnkr
Version: 0.0.1
Summary: Python API for requesting Halo Infinite multiplayer data.
Author: Andy Curtis
License: Copyright 2022 Andy Curtis
        
        Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Project-URL: Homepage, https://github.com/acurtis166/halo-infinite-api
Keywords: halo,infinite,api
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Provides-Extra: dev
License-File: LICENSE

# [SPNKr](https://www.halopedia.org/M41_SPNKr) Halo Infinite API (Python)

This project provides a Python API for requesting multiplayer data from Halo Infinite servers.

Authentication requires some preliminary work:

1. Sign up for a Microsoft Azure account.
1. Register a new application in [Azure AD](https://portal.azure.com/#blade/Microsoft_AAD_RegisteredApps/ApplicationsListBlade).
1. Add "http://localhost" as a redirect URI of type "web".
1. Go to "Certificates & secrets" for your app to create a client secret.
1. Save your app's client id, client secret, and redirect URI information.


## Dependencies

- Python >= 3.10
- Libraries:
    - requests for making HTTP requests
    - ms_cv for including a correlation vector header for requests to Microsoft
    - dataclass-wizard for mapping JSON responses to dataclasses
    - orjson for speedy JSON deserialization
    - pytest for unit testing


## Getting Started

Install
```
pip install spnkr
```

Example Usage
```python
"""Example usage of the library."""

import pathlib
import requests

from spnkr.api.client import Client
from spnkr.api.enums import PlayerType
from spnkr.authentication.manager import AuthenticationManager
from spnkr.authentication.models import OAuth2TokenResponse


def main():
    # Where the OAuth token should be/is saved
    oauth_token_file = pathlib.Path('path/to/token.json')

    # Azure AD app information
    client_id = 'YOUR CLIENT ID'
    client_secret = 'YOUR CLIENT SECRET'
    redirect_uri = 'http://localhost'

    with requests.session() as sess:
        auth_mgr = AuthenticationManager(sess, client_id, client_secret, redirect_uri)
        client = Client(auth_mgr)

        if oauth_token_file.exists():
            print('Refreshing tokens')
            auth_mgr.oauth = OAuth2TokenResponse.parse_json(oauth_token_file.read_text())
            auth_mgr.refresh_tokens()
        else:
            print('Requesting tokens')
            auth_url = auth_mgr.generate_authorization_url()
            print(auth_url)
            print('Navigate to the above URL and copy the "code" parameter from the query string.')
            code = input('Enter the code...')
            auth_mgr.request_tokens(code)
            oauth_token_file.mkdir(parents=True)

        # Save the token for later
        with oauth_token_file.open('w') as fp:
            fp.write(auth_mgr.oauth.to_json())

        # Get your Xbox Live ID (xuid)
        your_xbox_live_id = auth_mgr.xsts_token.xuid

        # Get your most recent 25 match summaries
        matches = client.stats.get_match_history(your_xbox_live_id)
        match = matches.results[0]  # most recent

        # Get match map/playlist/game variant
        map_variant = client.ugc_discovery.get_map(match.match_info.map_variant.asset_id,
                                                   match.match_info.map_variant.version_id)
        playlist = client.ugc_discovery.get_playlist(match.match_info.playlist.asset_id,
                                                     match.match_info.playlist.version_id)
        game_variant = client.ugc_discovery.get_ugc_game_variant(
            match.match_info.ugc_game_variant.asset_id,
            match.match_info.ugc_game_variant.version_id
        )
        print('Map | Game Type | Playlist')
        print(map_variant.public_name, '|', game_variant.public_name, '|', playlist.public_name)

        # Get match stats
        stats = client.stats.get_match_stats(match.match_id)
        print('Player | Kills | Deaths')
        for player in stats.players:
            core_stats = player.player_team_stats[0].stats.core_stats
            print(player.player_id, '|', core_stats.kills, '|', core_stats.deaths)

        # Get all the human players from the match
        player_ids = [p.player_id for p in stats.players if p.player_type == PlayerType.Human]

        # Get skill info (if applicable)
        try:
            skill = client.skill.get_match_result(match.match_id, player_ids)
        except requests.HTTPError:
            print(f'No skill info available for match {match.match_id}')
            exit()

        # Print out CSRs
        print('Player | Pre-Match CSR | Post-Match CSR')
        for entry in skill.value:
            print(entry.id, '|', entry.result.rank_recap.pre_match_csr, '|',
                  entry.result.rank_recap.post_match_csr)


if __name__ == '__main__':
    main()
```


## Contribute

- Implement/update authorities/endpoints
    - [Source (no auth needed)](https://settings.svc.halowaypoint.com/settings/hipc/e2a0a7c6-6efe-42af-9283-c2ab73250c48)
    - [Endpoints (JSON)](https://github.com/acurtis166/halo-infinite-api/blob/master/api_examples/json/endpoints.json)
    - [Endpoints (XML)](https://github.com/acurtis166/halo-infinite-api/blob/master/api_examples/xml/endpoints.xml)
    - [Script-generated code files](https://github.com/acurtis166/halo-infinite-api/tree/master/unused_authorities))
- Documentation
- Enumerated data type completion/confirmation


## Credits

- Xbox authentication, profile endpoints: [OpenXbox/xbox-webapi-python](https://github.com/OpenXbox/xbox-webapi-python)
- Halo Infinite authentication [Den Delimarsky](https://den.dev/blog/halo-api-authentication)
- Halo Infinite endpoints, schema, enumerated data types [OpenSpartan/grunt](https://github.com/OpenSpartan/grunt)
- Microsoft/343 Industries


## Disclaimer

This software is not endorsed or supported by Microsoft or 343 Industries. It is a personal project with a goal of analyzing Halo Infinite match data.

As the authentication process requires usage of personal credentials, **use at your own risk** of action by Microsoft or 343 Industries.
