{"id":36629447,"url":"https://github.com/cetteup/pybfbc2stats","last_synced_at":"2026-01-12T09:35:41.905Z","repository":{"id":62578927,"uuid":"421753243","full_name":"cetteup/pybfbc2stats","owner":"cetteup","description":"Python library for retrieving statistics of Battlefield: Bad Company 2 players","archived":false,"fork":false,"pushed_at":"2025-12-31T12:59:26.000Z","size":323,"stargazers_count":10,"open_issues_count":4,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-01-04T19:58:01.966Z","etag":null,"topics":["asyncio","battlefield","bfbc2","fesl","python","python3","statistics","theater"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cetteup.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":["cetteup"]}},"created_at":"2021-10-27T09:20:36.000Z","updated_at":"2025-12-17T07:35:36.000Z","dependencies_parsed_at":"2023-10-12T15:49:51.793Z","dependency_job_id":"e7980422-c9be-4500-baa7-dd9375ef0669","html_url":"https://github.com/cetteup/pybfbc2stats","commit_stats":null,"previous_names":[],"tags_count":50,"template":false,"template_full_name":null,"purl":"pkg:github/cetteup/pybfbc2stats","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cetteup%2Fpybfbc2stats","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cetteup%2Fpybfbc2stats/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cetteup%2Fpybfbc2stats/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cetteup%2Fpybfbc2stats/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cetteup","download_url":"https://codeload.github.com/cetteup/pybfbc2stats/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cetteup%2Fpybfbc2stats/sbom","scorecard":{"id":271633,"data":{"date":"2025-08-11","repo":{"name":"github.com/cetteup/pybfbc2stats","commit":"961aacb26fb03833a33b84743d5d8cfd143cdc55"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4.4,"checks":[{"name":"Code-Review","score":0,"reason":"Found 0/18 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:22: update your workflow using https://app.stepsecurity.io/secureworkflow/cetteup/pybfbc2stats/ci.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:24: update your workflow using https://app.stepsecurity.io/secureworkflow/cetteup/pybfbc2stats/ci.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:51: update your workflow using https://app.stepsecurity.io/secureworkflow/cetteup/pybfbc2stats/ci.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:53: update your workflow using https://app.stepsecurity.io/secureworkflow/cetteup/pybfbc2stats/ci.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/publish.yml:15: update your workflow using https://app.stepsecurity.io/secureworkflow/cetteup/pybfbc2stats/publish.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/publish.yml:17: update your workflow using https://app.stepsecurity.io/secureworkflow/cetteup/pybfbc2stats/publish.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/publish.yml:34: update your workflow using https://app.stepsecurity.io/secureworkflow/cetteup/pybfbc2stats/publish.yml/main?enable=pin","Warn: pipCommand not pinned by hash: .github/workflows/ci.yml:59","Warn: pipCommand not pinned by hash: .github/workflows/ci.yml:60","Warn: pipCommand not pinned by hash: .github/workflows/ci.yml:63","Warn: pipCommand not pinned by hash: .github/workflows/ci.yml:30","Warn: pipCommand not pinned by hash: .github/workflows/ci.yml:31","Warn: pipCommand not pinned by hash: .github/workflows/ci.yml:32","Warn: pipCommand not pinned by hash: .github/workflows/ci.yml:35","Warn: pipCommand not pinned by hash: .github/workflows/publish.yml:22","Info:   0 out of   6 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   1 third-party GitHubAction dependencies pinned","Info:   0 out of   8 pipCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Token-Permissions","score":10,"reason":"GitHub workflow tokens follow principle of least privilege","details":["Info: topLevel 'contents' permission set to 'read': .github/workflows/ci.yml:10","Info: topLevel 'pull-requests' permission set to 'read': .github/workflows/ci.yml:11","Info: topLevel 'contents' permission set to 'read': .github/workflows/publish.yml:8","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE.md:0","Info: FSF or OSI recognized license: MIT License: LICENSE.md:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'main'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 14 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-17T13:33:09.080Z","repository_id":62578927,"created_at":"2025-08-17T13:33:09.081Z","updated_at":"2025-08-17T13:33:09.081Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28337728,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-12T06:09:07.588Z","status":"ssl_error","status_checked_at":"2026-01-12T06:05:18.301Z","response_time":98,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["asyncio","battlefield","bfbc2","fesl","python","python3","statistics","theater"],"created_at":"2026-01-12T09:35:41.830Z","updated_at":"2026-01-12T09:35:41.894Z","avatar_url":"https://github.com/cetteup.png","language":"Python","funding_links":["https://github.com/sponsors/cetteup"],"categories":[],"sub_categories":[],"readme":"# pybfbc2stats\n\n[![ci](https://img.shields.io/github/actions/workflow/status/cetteup/pybfbc2stats/ci.yml?label=ci)](https://github.com/cetteup/pybfbc2stats/actions?query=workflow%3Aci)\n[![License](https://img.shields.io/github/license/cetteup/pybfbc2stats)](/LICENSE)\n[![Package](https://img.shields.io/pypi/v/pybfbc2stats)](https://pypi.org/project/pybfbc2stats/)\n[![Last commit](https://img.shields.io/github/last-commit/cetteup/pybfbc2stats)](https://github.com/cetteup/pybfbc2stats/commits/main)\n\nPython 🐍 library for retrieving statistics of Battlefield: Bad Company 2 players. Possible thanks to previous work by Luigi Auriemma and nemo.\n\n## Features\n\n- lookup players/personas by id or name\n- search for players/personas by name (with wildcard support)\n- retrieve all available player statistics\n- retrieve player dogtag records\n- retrieve player leaderboards\n- retrieve server list\n- retrieve individual game server's details for (including player list)\n- support for all platforms (PC, Xbox 360, PS3)\n- full support for async Python\n\n## Installation\n\nSimply install the package via pip.\n\n```bash\n$ pip install pybfbc2stats\n```\n\n## Usage\n\n### TLS 1.0\n\nThe FESL backend only supports TSL 1.0. So, you can only use this library in an environment that allows Python to use TLS 1.0. The easiest and least intrusive way to enable TLS 1.0 support is to set an `OPENSSL_CONF` environment variable that contains the absolute path to the included `openssl.cnf`. On Linux, you can set it by running this in the project directory:\n\n```bash\nexport OPENSSL_CONF=$(realpath openssl.cnf)\n```\n### Basic example\n\nThe following examples show how to find a player/persona by name and retrieve their stats using the default as well as the async client.\n\n### Retrieve stats using the default FESL client\n\n```python\nfrom urllib.parse import quote\n\nfrom pybfbc2stats import FeslClient, Platform, Namespace\n\n\ndef main():\n    with FeslClient('ea_account_name', 'ea_account_password', Platform.pc) as client:\n        quoted_name = quote('Krut0r')\n        persona = client.lookup_username(quoted_name, Namespace.pc)\n        stats = client.get_stats(int(persona['userId']))\n        print(stats)\n\n\nif __name__ == '__main__':\n    main()\n```\n\n### Retrieve stats using the async FESL client\n\n```python\nimport asyncio\nfrom urllib.parse import quote\n\nfrom pybfbc2stats import AsyncFeslClient, Platform, Namespace\n\n\nasync def main():\n    async with AsyncFeslClient('ea_account_name', 'ea_account_password', Platform.pc) as client:\n        quoted_name = quote('Krut0r')\n        persona = await client.lookup_username(quoted_name, Namespace.pc)\n        stats = await client.get_stats(int(persona['userId']))\n        print(stats)\n\n\nif __name__ == '__main__':\n    asyncio.run(main())\n```\n\n### Retrieve the server list using the default theater client\n\n```python\nfrom pybfbc2stats import FeslClient, TheaterClient, Platform\n\ndef main():\n    # First, get theater details and login key (lkey) from FESL\n    with FeslClient('ea_account_name', 'ea_account_password', Platform.ps3) as feslClient:\n        theater_hostname, theater_port = feslClient.get_theater_details()\n        lkey = feslClient.get_lkey()\n    \n    # Now use the theater client to get the server list\n    with TheaterClient(theater_hostname, theater_port, lkey, Platform.ps3) as theaterClient:\n        lobbies = theaterClient.get_lobbies()\n        servers = []\n        for lobby in lobbies:\n            lobby_servers = theaterClient.get_servers(int(lobby['LID']))\n            servers.extend(lobby_servers)\n        print(servers)\n\nif __name__ == '__main__':\n    main()\n```\n\n### Retrieve the server list using the async theater client\n\n```python\nimport asyncio\nfrom pybfbc2stats import AsyncFeslClient, AsyncTheaterClient, Platform\n\nasync def main():\n    # First, get theater details and login key (lkey) from FESL\n    async with AsyncFeslClient('ea_account_name', 'ea_account_password', Platform.ps3) as feslClient:\n        theater_hostname, theater_port = await feslClient.get_theater_details()\n        lkey = await feslClient.get_lkey()\n    \n    # Now use the theater client to get the server list\n    async with AsyncTheaterClient(theater_hostname, theater_port, lkey, Platform.ps3) as theaterClient:\n        lobbies = await theaterClient.get_lobbies()\n        servers = []\n        for lobby in lobbies:\n            lobby_servers = await theaterClient.get_servers(int(lobby['LID']))\n            servers.extend(lobby_servers)\n        print(servers)\n\nif __name__ == '__main__':\n    asyncio.run(main())\n```\n\n### Client methods\n\nBoth the default and the async clients offer the same methods with the same signatures.\n\n#### \\[Async\\]FeslClient(username, password, platform, timeout)\n\nCreate a new [Async]FeslClient instance.\n\n**Note**: The account has to be valid for Bad Company 2. If your account does not work, you can create a new one using [ealist](https://aluigi.altervista.org/papers.htm#ealist): `.\\ealist.exe -A -a [username] [password] bfbc2-pc` (the created account will work for all platforms).\n\n**Arguments**\n\n| Argument   | Type     | Opt/Required | Note                                                                                                                                                                                                                |\n|------------|----------|--------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| `username` | str      | Required     |                                                                                                                                                                                                                     |\n| `password` | str      | Required     |                                                                                                                                                                                                                     |\n| `platform` | Platform | Required     | One of: `Platform.pc`, `Platform.ps3` (Xbox 360 is not yet supported)                                                                                                                                               |\n| `timeout`  | float    | Optional     | How long to wait for data before raising a timeout exception (timeout is applied **per socket operation**, meaning the timeout is applied to each read from/write to the underlying connection to the FESL backend) |\n\n----\n\n#### \\[Async\\]FeslClient.hello()\n\nSend the initial \"hello\" packet to the FESL server.\n\n---\n\n#### \\[Async\\]FeslClient.memcheck()\n\nSend the response to the FESL server's \"memcheck\" challenge.\n\n----\n\n#### \\[Async\\]FeslClient.login()\n\nSend the login details to the FESL server.\n\n----\n\n#### \\[Async\\]FeslClient.get_lkey()\n\nGet the login key (lkey) used to authenticate on theater backend.\n\n----\n\n#### \\[Async\\]FeslClient.get_theater_details()\n\nGet the hostname and port of the theater backend for the client's platform.\n\n----\n\n#### \\[Async\\]FeslClient.lookup_usernames(usernames, namespace)\n\nLookup a list of **url encoded/quoted** usernames and return any matching personas (only exact name matches are returned).\n\n**Note**: Since this method accepts a `namespace` argument, it can lookup usernames in any namespace (on any platform), regardless of which `Platform` was used to create the client instance.\n\n**Arguments**\n\n| Argument    | Type      | Opt/Required | Note                                                         |\n|-------------|-----------|--------------|--------------------------------------------------------------|\n| `usernames` | List[str] | Required     | List of **url encoded/quoted** usernames                     |\n| `namespace` | Namespace | Required     | One of: `Namespace.pc`, `Namespace.ps3`, `Namespace.xbox360` |\n\n**Example**\n\n```python\nfrom urllib.parse import quote\n\nfrom pybfbc2stats import FeslClient, Platform, Namespace\n\nclient = FeslClient('ea_account_name', 'ea_account_password', Platform.pc)\nnames = ['SickLittleMonkey', '[SuX] DeLuXe']\nquoted = [quote(name) for name in names]\npersona = client.lookup_usernames(quoted, Namespace.pc)\n```\n\n----\n\n#### \\[Async\\]FeslClient.lookup_username(username, namespace)\n\nLookup a single **url encoded/quoted** username and return any matching persona (only exact name matches are returned).\n\n**Note**: Since this method accepts a `namespace` argument, it can lookup usernames in any namespace (on any platform), regardless of which `Platform` was used to create the client instance.\n\n**Arguments**\n\n| Argument    | Type      | Opt/Required | Note                                                         |\n|-------------|-----------|--------------|--------------------------------------------------------------|\n| `username`  | str       | Required     | **Url encoded/quoted** username                              |\n| `namespace` | Namespace | Required     | One of: `Namespace.pc`, `Namespace.ps3`, `Namespace.xbox360` |\n\n**Example**\n\n```python\nfrom urllib.parse import quote\n\nfrom pybfbc2stats import FeslClient, Platform, Namespace\n\nclient = FeslClient('ea_account_name', 'ea_account_password', Platform.ps3)\npersona = client.lookup_username(quote('Major Brainhurt'), Namespace.pc)\n```\n\n----\n\n#### \\[Async\\]FeslClient.lookup_user_ids(user_ids, namespace)\n\nLookup a list of user ids and return any matching personas.\n\n**Note**: Since this method accepts a `namespace` argument, it can lookup user ids in any namespace (on any platform), regardless of which `Platform` was used to create the client instance.\n\n**Arguments**\n\n| Argument    | Type      | Opt/Required | Note                                                         |\n|-------------|-----------|--------------|--------------------------------------------------------------|\n| `user_ids`  | List[int] | Required     |                                                              |\n| `namespace` | Namespace | Required     | One of: `Namespace.pc`, `Namespace.ps3`, `Namespace.xbox360` |\n\n**Example**\n\n```python\nfrom pybfbc2stats import FeslClient, Platform, Namespace\n\nclient = FeslClient('ea_account_name', 'ea_account_password', Platform.pc)\npersona = client.lookup_user_ids([232302860, 233866102], Namespace.xbox360)\n```\n\n----\n\n#### \\[Async\\]FeslClient.lookup_user_id(user_id, namespace)\n\nLookup a single user id and return any matching persona.\n\n**Note**: Since this method accepts a `namespace` argument, it can lookup user ids in any namespace (on any platform), regardless of which `Platform` was used to create the client instance.\n\n**Arguments**\n\n| Argument    | Type      | Opt/Required | Note                                                         |\n|-------------|-----------|--------------|--------------------------------------------------------------|\n| `user_id`   | int       | Required     |                                                              |\n| `namespace` | Namespace | Required     | One of: `Namespace.pc`, `Namespace.ps3`, `Namespace.xbox360` |\n\n**Example**\n\n```python\nfrom pybfbc2stats import FeslClient, Platform, Namespace\n\nclient = FeslClient('ea_account_name', 'ea_account_password', Platform.pc)\npersona = client.lookup_user_id(232302860, Namespace.xbox360)\n```\n\n----\n\n#### \\[Async\\]FeslClient.search_name(screen_name, namespace)\n\nFind personas given a **url encoded/quoted** (partial) name. You can use `*` as a trailing wildcard.\n\n**Note**: The FESL backend returns an error both if a) no matching results were found and b) too many matching results were found. So, be careful with wildcard characters in combination with short partial names.\n\n**Arguments**\n\n| Argument      | Type      | Opt/Required | Note                                                         |\n|---------------|-----------|--------------|--------------------------------------------------------------|\n| `screen_name` | str       | Required     | **Url encoded/quoted** (partial) name                        |\n| `namespace`   | Namespace | Required     | One of: `Namespace.pc`, `Namespace.ps3`, `Namespace.xbox360` |\n\n**Example**\n\n```python\nfrom urllib.parse import quote\n\nfrom pybfbc2stats import FeslClient, Platform\n\nclient = FeslClient('ea_account_name', 'ea_account_password', Platform.pc)\nresults = client.search_name(quote('[=BL=] larryp11'))\n```\n\n----\n\n#### \\[Async\\]FeslClient.get_stats(userid, keys)\n\nRetrieve a given list of stats attributes for a given player id on the client instance's platform.\n\n**Arguments**\n\n| Argument | Type        | Opt/Required | Note                                                                                       |\n|----------|-------------|--------------|--------------------------------------------------------------------------------------------|\n| `userid` | int         | Required     |                                                                                            |\n| `keys`   | List[bytes] | Optional     | By default, all available attributes are retrieved (see `STATS_KEYS` constant for details) |\n\n**Example**\n\n```python\nfrom pybfbc2stats import FeslClient, Platform\n\nclient = FeslClient('ea_account_name', 'ea_account_password', Platform.ps3)\nstats = client.get_stats(223789857, [b'accuracy', b'kills', b'deaths', b'score', b'time'])\n```\n\n----\n\n#### \\[Async\\]FeslClient.get_leaderboard(min_rank, max_rank, sort_by, keys)\n\nRetrieve a given range of players on the leaderboard with the given list of stats, sorted by a given key, on the client instance's platform.\n\n**Note**: There does not seem to be a hard limit to either the rank rage size nor the number of stats keys that can be retrieved for each player. You will, however, need to increase your client-wide timeout if you are planning to retrieve large chunks of the leaderboard or lots of stats attributes.\n\n**Arguments**\n\n| Argument   | Type        | Opt/Required | Note                                                                                                                           |\n|------------|-------------|--------------|--------------------------------------------------------------------------------------------------------------------------------|\n| `min_rank` | int         | Optional     | Minimum placement/rank on the leaderboard (1-250000)                                                                           |\n| `max_rank` | int         | Optional     | Maximum placement/rank on the leaderboard (1-250001)                                                                           |\n| `sort_by`  | bytes       | Optional     | Key to sort leaderboard by, must be one of `deaths`, `elo`, `kills`, `rank`, `score`, `time`, `veteran`                        |\n| `keys`     | List[bytes] | Optional     | By default, only `deaths`, `kills`, `score` and `time` are retrieved (see `STATS_KEYS` constant for additional available keys) |\n\n**Example**\n\n```python\nfrom pybfbc2stats import FeslClient, Platform\n\nclient = FeslClient('ea_account_name', 'ea_account_password', Platform.pc)\nleaderboard = client.get_leaderboard(1, 50, b'time')\n```\n\n----\n\n#### \\[Async\\]FeslClient.get_dogtags(userid)\n\nRetrieve a list of players the given player id has taken dogtags from.\n\n**Note**: The FESL backend returns an error both if a) the given user id does not exist and b) the user has not yet taken any dogtags.\n\n**Arguments**\n\n| Argument | Type | Opt/Required |\n|----------|------|--------------|\n| `userid` | int  | Required     |\n\n**Example**\n\n```python\nfrom pybfbc2stats import FeslClient, Platform\n\nclient = FeslClient('ea_account_name', 'ea_account_password', Platform.ps3)\ndogtags = client.get_dogtags(223789857)\n```\n\n----\n\n#### \\[Async\\]TheaterClient(host, port, lkey, platform, timeout)\n\nCreate a new [Async]TheaterClient instance.\n\n**Arguments**\n\n| Argument   | Type     | Opt/Required | Note                                                                                                                                                                                                                |\n|------------|----------|--------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| `host`     | str      | Required     | IP/hostname of the theater backend for the platform (can be retrieved via FESL)                                                                                                                                     |\n| `port`     | int      | Required     | Port of the theater backend for the platform (can be retrieved via FESL)                                                                                                                                            |\n| `lkey`     | str      | Required     | Login key (lkey) (retrieved via FESL)                                                                                                                                                                               |\n| `platform` | Platform | Required     | One of: `Platform.pc`, `Platform.ps3` (Xbox 360 is not yet supported)                                                                                                                                               |\n| `timeout`  | float    | Optional     | How long to wait for data before raising a timeout exception (timeout is applied **per socket operation**, meaning the timeout is applied to each read from/write to the underlying connection to the FESL backend) |\n\n----\n\n#### \\[Async\\]TheaterClient.connect()\n\nInitialize the connection to the Theater backend by sending the initial CONN/hello packet.\n\n----\n\n#### \\[Async\\]TheaterClient.authenticate()\n\nAuthenticate against/log into the Theater backend using the lkey retrieved via FESL.\n\n----\n\n#### \\[Async\\]TheaterClient.get_lobbies()\n\nRetrieve all available game (server) lobbies.\n\n**Example**\n\n```python\nfrom pybfbc2stats import TheaterClient, Platform\n\nclient = TheaterClient('bfbc2-ps3-server.theater.ea.com', 18336, 'your_lkey', Platform.ps3)\nlobbies = client.get_lobbies()\n```\n\n----\n\n#### \\[Async\\]TheaterClient.get_servers(lobby_id)\n\nRetrieve all available game servers from the given lobby.\n\n**Arguments**\n\n| Argument | Type | Opt/Required | Note                        |\n|----------|------|--------------|-----------------------------|\n| lobby_id | int  | Required     | Id of the game server lobby |\n\n**Example**\n\n```python\nfrom pybfbc2stats import TheaterClient, Platform\n\nclient = TheaterClient('bfbc2-ps3-server.theater.ea.com', 18336, 'your_lkey', Platform.ps3)\nservers = client.get_servers(257)\n```\n\n----\n\n#### \\[Async\\]TheaterClient.get_server_details(lobby_id, game_id)\n\nRetrieve full details and player list for a given server.\n\n**Arguments**\n\n| Argument | Type | Opt/Required | Note                                                |\n|----------|------|--------------|-----------------------------------------------------|\n| lobby_id | int  | Required     | Id of the game server lobby the server is hosted in |\n| game_id  | int  | Required     | Game (server) id                                    |\n\n**Example**\n\n```python\nfrom pybfbc2stats import TheaterClient, Platform\n\nclient = TheaterClient('bfbc2-ps3-server.theater.ea.com', 18336, 'your_lkey', Platform.ps3)\ngeneral, detailed, players = client.get_server_details(257, 120018)\n```\n\n----\n\n#### \\[Async\\]TheaterClient.get_current_server(user_id)\n\nRetrieve full details and player list for a given user's current server (server they are currently playing on, \nraises a PlayerNotFound exception if the player is not currently playing online).\n\n**Arguments**\n\n| Argument | Type | Opt/Required | Note                                       |\n|----------|------|--------------|--------------------------------------------|\n| user_id  | int  | Required     | Id of the user whose current server to get |\n\n**Example**\n\n```python\nfrom pybfbc2stats import TheaterClient, Platform\n\nclient = TheaterClient('bfbc2-ps3-server.theater.ea.com', 18336, 'your_lkey', Platform.ps3)\ngeneral, detailed, players = client.get_current_server(227528903)\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcetteup%2Fpybfbc2stats","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcetteup%2Fpybfbc2stats","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcetteup%2Fpybfbc2stats/lists"}