Compare commits

..
Author SHA1 Message Date
3f9cc345c5 Update main.py 2026-07-02 09:11:29 +02:00
82d0666d00 add grabbing a player stats 2026-07-02 09:07:37 +02:00
c4fe4f1bf1 fix: add missing function 2026-06-23 06:50:34 +02:00
ca8090d20d update more routes 2026-06-21 23:40:21 +02:00
0b5e56b69b rewrite for new account oauth 2026-06-21 23:37:29 +02:00
c89806fe87 revert 75dca3509e
revert fix this bullshit finally
2026-06-19 04:57:10 +02:00
13afb709c5 revert 2d703c78b3
revert fix: forgot this isn't GitHub
2026-06-19 04:56:59 +02:00
2d703c78b3 fix: forgot this isn't GitHub 2026-06-18 05:22:06 +02:00
75dca3509e fix this bullshit finally 2026-06-18 05:18:58 +02:00
2f59f2f315 Update dependency joi to v18.2.3 2026-06-17 21:41:35 +02:00
e12611b812 Update dependency greenlet to v3.5.2 2026-06-17 21:41:20 +02:00
e013c5930f Update dependency certifi to v2026.6.17 2026-06-17 10:48:51 +00:00
269f9f4058 Update dependency anyio to v4.14.0 2026-06-15 22:04:03 +00:00
40fce749ba chore: disable auto merge 2026-06-15 20:25:06 +02:00
c4b503c208 Update dependency sqlalchemy to v2.0.51 2026-06-15 15:55:56 +00:00
d650edd883 Update dependency multer to v2.2.0 2026-06-15 12:24:49 +00:00
313dfa3cec Update dependency fastapi to v0.137.1 2026-06-15 11:55:28 +00:00
3954801823 Update dependency axios to v1.18.0 2026-06-14 18:09:03 +00:00
2ac86b3fc6 Update dependency fastapi to v0.137.0 2026-06-14 13:08:39 +00:00
fdfde0fb3d Update dependency cryptography to v49 2026-06-12 20:22:20 +00:00
ceeed0dade Update dependency starlette to v1.3.1 2026-06-12 09:35:42 +00:00
aaef1e7ecd Update dependency starlette to v1.3.0 2026-06-11 14:43:58 +00:00
d776c11555 Update dependency cryptography to v48.0.1 2026-06-09 22:40:37 +00:00
53c9ce2653 Merge pull request 'Update dependency python-multipart to v0.0.32' (#41) from renovate/python-multipart-0.x into main 2026-06-04 18:50:43 +02:00
39f0ff2bf9 Update dependency python-multipart to v0.0.32 2026-06-04 16:47:45 +00:00
9d778f39a7 Merge pull request 'Update dependency python-multipart to v0.0.31' (#40) from renovate/python-multipart-0.x into main 2026-06-04 11:06:40 +02:00
1dfa7bccf2 Update dependency python-multipart to v0.0.31 2026-06-04 09:03:41 +00:00
54ceec85fb Merge pull request 'Update dependency uvicorn to v0.49.0' (#39) from renovate/uvicorn-0.x into main 2026-06-04 00:15:05 +02:00
d6c4ddac44 Update dependency uvicorn to v0.49.0 2026-06-03 22:12:09 +00:00
ffe66d1377 Merge pull request 'Update dependency idna to v3.18' (#38) from renovate/idna-3.x into main 2026-06-03 14:33:10 +02:00
cbaa1fa941 Update dependency idna to v3.18 2026-06-03 12:18:34 +00:00
0d91d6a566 Merge pull request 'Update dependency axios to v1.17.0' (#37) from renovate/axios-1.x-lockfile into main 2026-06-03 14:18:18 +02:00
c410aa4074 Update dependency axios to v1.17.0 2026-06-03 12:03:47 +00:00
kittentm
f42880bec2 revert d885899baf
revert ci doesnt run in containers
2026-06-03 13:52:34 +02:00
kittentm
95a022d479 revert 65d2c9dc20
revert wtf is going on with forgejo rn
2026-06-03 13:52:09 +02:00
kittentm
a4ebf2f106 revert 889db3abab
revert consolidate steps
2026-06-03 13:51:57 +02:00
kittentm
bfe7f02099 revert d5819ceec6
revert Update .forgejo/workflows/build.yml
2026-06-03 13:51:46 +02:00
kittentm
78c1c709fb revert 41b0c3297e
revert yo forgejo pmo rn
2026-06-03 13:51:20 +02:00
41b0c3297e yo forgejo pmo rn 2026-06-03 09:12:54 +02:00
d5819ceec6 Update .forgejo/workflows/build.yml 2026-06-03 09:10:54 +02:00
889db3abab consolidate steps 2026-06-03 09:10:09 +02:00
65d2c9dc20 wtf is going on with forgejo rn 2026-06-03 09:08:28 +02:00
d916aaece5 Merge pull request 'chore(deps): update dependency morgan to v1.11.0' (#35) from renovate/morgan-1.x-lockfile into main 2026-06-03 09:05:34 +02:00
d885899baf ci doesnt run in containers 2026-06-03 09:05:28 +02:00
ab469e203f chore(deps): update dependency morgan to v1.11.0 2026-06-02 19:09:29 +00:00
458eddc65f Merge pull request 'fix(deps): update dependency python-multipart to v0.0.30' (#33) from renovate/python-multipart-0.x into main 2026-05-31 21:28:37 +02:00
1e8ebd0f44 fix(deps): update dependency python-multipart to v0.0.30 2026-05-31 19:25:33 +00:00
kittentm
3fe3913aa2 fix: accept submissions if validation failed 2026-05-31 18:22:14 +02:00
kittentm
37f7399edb print errors when checking pid validity 2026-05-31 17:12:57 +02:00
88e7a89f25 Merge pull request 'fix(deps): update dependency starlette to v1.2.1' (#32) from renovate/starlette-1.x into main 2026-05-31 03:35:21 +02:00
027430953b fix(deps): update dependency starlette to v1.2.1 2026-05-31 01:32:04 +00:00
5c23336fcf Merge pull request 'fix(deps): update dependency idna to v3.17' (#31) from renovate/idna-3.x into main 2026-05-28 16:49:54 +02:00
8e528bc0d9 fix(deps): update dependency idna to v3.17 2026-05-28 14:46:52 +00:00
ff8f5e29aa Merge pull request 'fix(deps): update dependency starlette to v1.2.0' (#30) from renovate/starlette-1.x into main 2026-05-28 14:04:56 +02:00
ab391b8997 fix(deps): update dependency starlette to v1.2.0 2026-05-28 12:01:47 +00:00
049d33ea47
feat: check whether fest exists & to skip ranking reset 2026-05-25 21:40:48 +02:00
6e4fb00675 Merge pull request 'fix(deps): update dependency sqlalchemy to v2.0.50' (#29) from renovate/sqlalchemy-2.x into main 2026-05-24 21:47:01 +02:00
4d7b3f9bae fix(deps): update dependency sqlalchemy to v2.0.50 2026-05-24 19:43:54 +00:00
1f146fb558 Merge pull request 'fix(deps): update dependency uvicorn to v0.48.0' (#28) from renovate/uvicorn-0.x into main 2026-05-24 14:39:03 +02:00
54c01fdc54 fix(deps): update dependency uvicorn to v0.48.0 2026-05-24 12:36:02 +00:00
b5eab7ac9e Merge pull request 'fix(deps): update dependency fastapi to v0.136.3' (#27) from renovate/fastapi-0.x into main 2026-05-23 20:58:59 +02:00
953754b537 fix(deps): update dependency fastapi to v0.136.3 2026-05-23 18:55:47 +00:00
37af414473 Merge pull request 'fix(deps): update dependency starlette to v1.1.0' (#26) from renovate/starlette-1.x into main 2026-05-23 19:13:18 +02:00
0f027550e6 fix(deps): update dependency starlette to v1.1.0 2026-05-23 17:10:06 +00:00
ed9dedeef9 Merge pull request 'fix(deps): update dependency click to v8.4.1' (#25) from renovate/click-8.x into main 2026-05-22 06:34:41 +02:00
69cbe960d7 fix(deps): update dependency click to v8.4.1 2026-05-22 04:31:43 +00:00
d557e8c370 Merge pull request 'fix(deps): update dependency idna to v3.16' (#24) from renovate/idna-3.x into main 2026-05-22 02:35:07 +02:00
6890e59809 fix(deps): update dependency idna to v3.16 2026-05-22 00:32:03 +00:00
a43a555a34 Merge pull request 'fix(deps): update dependency starlette to v1.0.1' (#23) from renovate/starlette-1.x into main 2026-05-22 00:05:35 +02:00
0b435e97be fix(deps): update dependency starlette to v1.0.1 2026-05-21 22:02:30 +00:00
d554353008 Merge pull request 'chore(deps): update dependency pg to v8.21.0' (#20) from renovate/pg-8.x-lockfile into main 2026-05-21 11:58:32 +02:00
8a41f1ae93 Merge pull request 'fix(deps): update dependency greenlet to v3.5.1' (#21) from renovate/greenlet-3.x into main 2026-05-21 11:58:30 +02:00
6579f8add6 Merge pull request 'fix(deps): update dependency certifi to v2026.5.20' (#22) from renovate/certifi-2026.x into main 2026-05-21 11:58:29 +02:00
658c2ea006 fix(deps): update dependency certifi to v2026.5.20 2026-05-20 17:03:10 +00:00
e80add0c06 fix(deps): update dependency greenlet to v3.5.1 2026-05-20 17:02:59 +00:00
903318754a chore(deps): update dependency pg to v8.21.0 2026-05-18 12:02:09 +00:00
6c30bf69c3 Merge pull request 'fix(deps): update dependency python-multipart to v0.0.29' (#19) from renovate/python-multipart-0.x into main 2026-05-17 19:48:38 +02:00
9b00783f38 Merge pull request 'fix(deps): update dependency click to v8.4.0' (#18) from renovate/click-8.x into main 2026-05-17 19:48:35 +02:00
33a8f8c315 fix(deps): update dependency python-multipart to v0.0.29 2026-05-17 17:46:46 +00:00
8caf832ba9 fix(deps): update dependency click to v8.4.0 2026-05-17 01:01:39 +00:00
cbb3b4fdad Merge pull request 'fix(deps): update dependency requests to v2.34.2' (#17) from renovate/requests-2.x into main 2026-05-14 21:52:46 +02:00
17a70cac80 fix(deps): update dependency requests to v2.34.2 2026-05-14 19:49:56 +00:00
1aa6fc0371 Merge pull request 'fix(deps): update dependency uvicorn to v0.47.0' (#16) from renovate/uvicorn-0.x into main 2026-05-14 20:38:08 +02:00
0fda25d76c fix(deps): update dependency uvicorn to v0.47.0 2026-05-14 18:35:37 +00:00
38cd3603b9 Merge pull request 'chore(deps): update dependency express-rate-limit to v8.5.2' (#15) from renovate/express-rate-limit-8.x-lockfile into main 2026-05-14 12:34:32 +02:00
c6efe237ed chore(deps): update dependency express-rate-limit to v8.5.2 2026-05-14 10:32:02 +00:00
650741f7e6 Merge pull request 'fix(deps): update dependency requests to v2.34.1' (#14) from renovate/requests-2.x into main 2026-05-13 21:40:11 +02:00
731e95feb5 fix(deps): update dependency requests to v2.34.1 2026-05-13 19:37:05 +00:00
ab10f2e4e5 Merge pull request 'chore(deps): update dependency axios to v1.16.1' (#13) from renovate/axios-1.x-lockfile into main 2026-05-13 18:37:21 +02:00
2adf1f58a0 chore(deps): update dependency axios to v1.16.1 2026-05-13 16:34:34 +00:00
bd9502cf29 Merge pull request 'fix(deps): update dependency idna to v3.15' (#12) from renovate/idna-3.x into main 2026-05-13 00:56:52 +02:00
57df5ce4cc fix(deps): update dependency idna to v3.15 2026-05-12 22:52:10 +00:00
bb9b35e58c Merge pull request 'fix(deps): update dependency requests to v2.34.0' (#11) from renovate/requests-2.x into main 2026-05-11 21:37:30 +02:00
c287dc0d84 fix(deps): update dependency requests to v2.34.0 2026-05-11 19:34:49 +00:00
7c65fb4d31 Merge pull request 'fix(deps): update dependency idna to v3.14' (#10) from renovate/idna-3.x into main 2026-05-10 23:06:46 +02:00
2da6d21979 fix(deps): update dependency idna to v3.14 2026-05-10 21:03:52 +00:00
6e084400db Merge pull request 'fix(deps): update dependency python-multipart to v0.0.28' (#9) from renovate/python-multipart-0.x into main 2026-05-10 13:23:16 +02:00
7e626a1503 fix(deps): update dependency python-multipart to v0.0.28 2026-05-10 11:20:30 +00:00
kittentm
e105f4e0fa fix(deps): update dependency pydantic-core to v2.46.4 2026-05-09 06:45:10 +02:00
Renovate Bot
a30f3eca46 fix(deps): update dependency pydantic to v2.13.4 2026-05-09 06:43:24 +02:00
5b1bafea17 Merge pull request 'fix(deps): update dependency pydantic-settings to v2.14.1' (#8) from renovate/pydantic-settings-2.x into main 2026-05-08 16:05:04 +02:00
15ed13086f fix(deps): update dependency pydantic-settings to v2.14.1 2026-05-08 14:02:34 +00:00
02a14ce457 chore: update badges 2026-05-08 05:53:46 +02:00
d80bf323ac ci: use variables so CI will pass on both mirrors 2026-05-08 05:32:47 +02:00
66d4bc0771 actually checkout code 2026-05-08 00:55:42 +02:00
683057221c i forgot steps 💔 2026-05-08 00:51:50 +02:00
0e082c65d2 i cant read 2026-05-08 00:46:36 +02:00
Renovate Bot
cc30baa5f0 fix(deps): update dependency cryptography to v48 2026-05-08 00:24:24 +02:00
Renovate Bot
5712238297 fix(deps): update dependency greenlet to v3.5.0 2026-05-08 00:23:45 +02:00
581c950261 ci: use multiple deb vers (if possible) 2026-05-08 00:19:12 +02:00
ccd63e713b Merge pull request 'fix(deps): update dependency urllib3 to v2.7.0' (#6) from renovate/urllib3-2.x into main 2026-05-07 18:38:19 +02:00
e265b4e5cd fix(deps): update dependency urllib3 to v2.7.0 2026-05-07 16:35:38 +00:00
995f85a6fa Merge pull request 'chore(deps): update dependency axios to v1.16.0' (#2) from renovate/axios-1.x-lockfile into main 2026-05-07 13:56:51 +02:00
dfdca8fc2a Merge pull request 'chore(deps): update dependency express-rate-limit to v8.5.1' (#4) from renovate/express-rate-limit-8.x-lockfile into main 2026-05-07 13:56:50 +02:00
4b3e128221 Merge pull request 'chore(deps): update dependency joi to v18.2.1' (#5) from renovate/hapijs-monorepo into main 2026-05-07 13:56:49 +02:00
de640f00d6 Merge pull request 'chore(deps): update dependency discord.js to v14.26.4' (#1) from renovate/discord.js-14.x-lockfile into main 2026-05-07 13:56:46 +02:00
b0c4af716a chore(deps): update dependency joi to v18.2.1 2026-05-07 08:06:07 +00:00
27c93f6f5b chore(deps): update dependency express-rate-limit to v8.5.1 2026-05-07 08:05:59 +00:00
cc27b1166f chore(deps): update dependency axios to v1.16.0 2026-05-07 07:50:55 +00:00
91b77c034e chore(deps): update dependency discord.js to v14.26.4 2026-05-07 07:50:46 +00:00
01063d489a
ci: change debian ver 2026-05-07 09:34:33 +02:00
8a846c0880
migration(feat): add repo .md files 2026-05-07 09:33:14 +02:00
18 changed files with 360 additions and 116 deletions

View file

@ -7,11 +7,11 @@ on:
jobs:
docker:
runs-on: debian-bookworm
runs-on: ${{ vars.RUNNER_LABEL }}
steps:
- name: checkout
- name: Checkout
uses: actions/checkout@v6
- name: install docker???
run: |
apt update && apt install wget cmake -y && \

View file

@ -12,12 +12,14 @@
# SplatNet
[![Commits](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fgit.crafterpika.cc%2Fapi%2Fv1%2Frepos%2Fkittentm%2Fsplatnet-backend%2Fcommits&query=%24.length&label=commits&style=for-the-badge&color=blue)](https://git.crafterpika.cc/kittentm/splatnet-backend/commits/branch/main)
![Last Commit](https://img.shields.io/gitea/last-commit/kittentm/splatnet-backend?gitea_url=https://git.crafterpika.cc&style=for-the-badge&color=blue)
[![Build Status](https://git.crafterpika.cc/kittentm/splatnet-backend/badges/workflows/build.yml/badge.svg?style=for-the-badge)](https://git.crafterpika.cc/kittentm/splatnet-backend/actions)
[![Languages](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fgit.crafterpika.cc%2Fapi%2Fv1%2Frepos%2Fkittentm%2Fsplatnet-backend%2Flanguages&query=%24.*~&label=language&style=for-the-badge&color=yellow)](https://git.crafterpika.cc/kittentm/splatnet-backend)
[![Languages](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fgit.crafterpika.cc%2Fapi%2Fv1%2Frepos%2Fkittentm%2Fsplatnet-backend%2Flanguages&query=%24.*~&label=language&style=for-the-badge&color=blue)](https://git.crafterpika.cc/kittentm/splatnet-backend)
[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg?style=for-the-badge&logo=gnu&logoColor=white)](https://git.crafterpika.cc/kittentm/splatnet-backend/src/branch/main/LICENSE)
![L1 Service Status](https://img.shields.io/website?url=https%3A%2F%2Fsplatnet.spbr.net%2F&up_message=online&down_message=offline&style=for-the-badge&up_color=blue&down_color=red&label=Production+Instance)
![T1 Service Status](https://img.shields.io/website?url=https%3A%2F%2Fsplatoon.cubexmine.dev%2F&up_message=online&down_message=offline&style=for-the-badge&up_color=blue&down_color=red&label=Testing+Instance)
This is the backend for the [SplatNet](https://git.crafterpika.cc/kittentm/splatnet) Revival frontend. It is a combination of Python & JS.
This is the backend for the [SplatNet](https://git.crafterpika.cc/kittentm/splatnet) Revival frontend.
</div>

40
code_of_conduct.md Normal file
View file

@ -0,0 +1,40 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [https://contributor-covenant.org/version/1/4][version]
[homepage]: https://contributor-covenant.org
[version]: https://contributor-covenant.org/version/1/4/

View file

@ -18,6 +18,7 @@ class Settings(BaseSettings):
twitter_client_id: str
twitter_client_secret: str
twitter_redirect_uri: str
account_client_secret: str
model_config = SettingsConfigDict(
env_file=[

173
judd/package-lock.json generated
View file

@ -336,6 +336,41 @@
"url": "https://opencollective.com/express"
}
},
"node_modules/agent-base": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
"integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
"license": "MIT",
"dependencies": {
"debug": "4"
},
"engines": {
"node": ">= 6.0.0"
}
},
"node_modules/agent-base/node_modules/debug": {
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/agent-base/node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"license": "MIT"
},
"node_modules/append-field": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz",
@ -349,13 +384,14 @@
"license": "MIT"
},
"node_modules/axios": {
"version": "1.15.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.15.2.tgz",
"integrity": "sha512-wLrXxPtcrPTsNlJmKjkPnNPK2Ihe0hn0wGSaTEiHRPxwjvJwT3hKmXF4dpqxmPO9SoNb2FsYXj/xEo0gHN+D5A==",
"version": "1.18.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.18.0.tgz",
"integrity": "sha512-E32NzpYKp++W7XRe52rHiXV2ehxmh3wbdgO7MHeFM+vqxLBYHzt0ElkiImtOBxtOmyp0yoC8C6uESVV84Y2/hw==",
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.15.11",
"follow-redirects": "^1.16.0",
"form-data": "^4.0.5",
"https-proxy-agent": "^5.0.1",
"proxy-from-env": "^2.1.0"
}
},
@ -631,9 +667,9 @@
]
},
"node_modules/discord.js": {
"version": "14.26.3",
"resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.26.3.tgz",
"integrity": "sha512-XEKtYn28YFsiJ5l4fLRyikdbo6RD5oFyqfVHQlvXz2104JhH/E8slN28dbky05w3DCrJcNVWvhVvcJCTSl/KIg==",
"version": "14.26.4",
"resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.26.4.tgz",
"integrity": "sha512-4oBp8tc6Kf8IDBwAHhbsMaAqx1b5fob9SNasZT7V6yyyUydoO5i5fGuX7TmvRtR+q/WgKRnRViRoAWnG7fNyvA==",
"license": "Apache-2.0",
"dependencies": {
"@discordjs/builders": "^1.14.1",
@ -797,12 +833,12 @@
}
},
"node_modules/express-rate-limit": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.3.2.tgz",
"integrity": "sha512-77VmFeJkO0/rvimEDuUC5H30oqUC4EyOhyGccfqoLebB0oiEYfM7nwPrsDsBL1gsTpwfzX8SFy2MT3TDyRq+bg==",
"version": "8.5.2",
"resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.5.2.tgz",
"integrity": "sha512-5Kb34ipNX694DH48vN9irak1Qx30nb0PLYHXfJgw4YEjiC3ZEmZJhwOp+VfiCYwFzvFTdB9QkArYS5kXa2cx2A==",
"license": "MIT",
"dependencies": {
"ip-address": "10.1.0"
"ip-address": "^10.2.0"
},
"engines": {
"node": ">= 16"
@ -1112,6 +1148,42 @@
"url": "https://opencollective.com/express"
}
},
"node_modules/https-proxy-agent": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
"integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
"license": "MIT",
"dependencies": {
"agent-base": "6",
"debug": "4"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/https-proxy-agent/node_modules/debug": {
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/https-proxy-agent/node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"license": "MIT"
},
"node_modules/iconv-lite": {
"version": "0.7.2",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz",
@ -1144,9 +1216,9 @@
"license": "ISC"
},
"node_modules/ip-address": {
"version": "10.1.0",
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz",
"integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==",
"version": "10.2.0",
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz",
"integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==",
"license": "MIT",
"engines": {
"node": ">= 12"
@ -1168,9 +1240,9 @@
"license": "MIT"
},
"node_modules/joi": {
"version": "18.1.2",
"resolved": "https://registry.npmjs.org/joi/-/joi-18.1.2.tgz",
"integrity": "sha512-rF5MAmps5esSlhCA+N1b6IYHDw9j/btzGaqfgie522jS02Ju/HXBxamlXVlKEHAxoMKQL77HWI8jlqWsFuekZA==",
"version": "18.2.3",
"resolved": "https://registry.npmjs.org/joi/-/joi-18.2.3.tgz",
"integrity": "sha512-N5A3KTWQpPWT4ExxxPlUx7WmykGXRzhNidWhV41d6Abu9YfI2NyWCJuxdPnslJCPWtbRpSVOWSnSS6GakLM/Rg==",
"license": "BSD-3-Clause",
"dependencies": {
"@hapi/address": "^5.1.1",
@ -1276,31 +1348,23 @@
}
},
"node_modules/morgan": {
"version": "1.10.1",
"resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.1.tgz",
"integrity": "sha512-223dMRJtI/l25dJKWpgij2cMtywuG/WiUKXdvwfbhGKBhy1puASqXwFzmWZ7+K73vUPoR7SS2Qz2cI/g9MKw0A==",
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/morgan/-/morgan-1.11.0.tgz",
"integrity": "sha512-zSkVu3t18r39pw4ixfBKvfZi3y2UOqr7d4WYwcj3m8nXpEQK4rPO6GLzs/CExoRgmX3y9EjmmcXqv6jq0SK46g==",
"license": "MIT",
"dependencies": {
"basic-auth": "~2.0.1",
"debug": "2.6.9",
"depd": "~2.0.0",
"on-finished": "~2.3.0",
"on-finished": "~2.4.1",
"on-headers": "~1.1.0"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/morgan/node_modules/on-finished": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
"integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==",
"license": "MIT",
"dependencies": {
"ee-first": "1.1.1"
},
"engines": {
"node": ">= 0.8"
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
},
"node_modules/ms": {
@ -1310,9 +1374,9 @@
"license": "MIT"
},
"node_modules/multer": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/multer/-/multer-2.1.1.tgz",
"integrity": "sha512-mo+QTzKlx8R7E5ylSXxWzGoXoZbOsRMpyitcht8By2KHvMbf3tjwosZ/Mu/XYU6UuJ3VZnODIrak5ZrPiPyB6A==",
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/multer/-/multer-2.2.0.tgz",
"integrity": "sha512-6rdyFg2kLrMh9Jee7/BMPuV9lEAd7lLW2YUpF9/YxR7njyoUwwQ0ZPh3TaIY50Sw6vlyD2HW3wGOkTS4P79xrQ==",
"license": "MIT",
"dependencies": {
"append-field": "^1.0.0",
@ -1399,15 +1463,14 @@
}
},
"node_modules/pg": {
"version": "8.20.0",
"resolved": "https://registry.npmjs.org/pg/-/pg-8.20.0.tgz",
"integrity": "sha512-ldhMxz2r8fl/6QkXnBD3CR9/xg694oT6DZQ2s6c/RI28OjtSOpxnPrUCGOBJ46RCUxcWdx3p6kw/xnDHjKvaRA==",
"version": "8.21.0",
"resolved": "https://registry.npmjs.org/pg/-/pg-8.21.0.tgz",
"integrity": "sha512-AUP1EYJuHraQGsVoCQVIcM7TEJVGtDzxWtGFZd8rds9d+CCXlU5Js1rYgfLNvxy9iJrpHjGrRjoi/3BT9fRyiA==",
"license": "MIT",
"peer": true,
"dependencies": {
"pg-connection-string": "^2.12.0",
"pg-pool": "^3.13.0",
"pg-protocol": "^1.13.0",
"pg-connection-string": "^2.13.0",
"pg-pool": "^3.14.0",
"pg-protocol": "^1.14.0",
"pg-types": "2.2.0",
"pgpass": "1.0.5"
},
@ -1415,7 +1478,7 @@
"node": ">= 16.0.0"
},
"optionalDependencies": {
"pg-cloudflare": "^1.3.0"
"pg-cloudflare": "^1.4.0"
},
"peerDependencies": {
"pg-native": ">=3.0.1"
@ -1427,16 +1490,16 @@
}
},
"node_modules/pg-cloudflare": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.3.0.tgz",
"integrity": "sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ==",
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.4.0.tgz",
"integrity": "sha512-Vo7z/6rrQYxpNRylp4Tlob2elzbh+N/MOQbxFVWCxS7oEx6jF53GTJFxK2WWpKuBRkmiin4Mt+xofFDjx09R0A==",
"license": "MIT",
"optional": true
},
"node_modules/pg-connection-string": {
"version": "2.12.0",
"resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.12.0.tgz",
"integrity": "sha512-U7qg+bpswf3Cs5xLzRqbXbQl85ng0mfSV/J0nnA31MCLgvEaAo7CIhmeyrmJpOr7o+zm0rXK+hNnT5l9RHkCkQ==",
"version": "2.13.0",
"resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.13.0.tgz",
"integrity": "sha512-EMnU9E2fSULdsbErBbMaXJvFeD9B4+nPcM3f+4lsiCR0BHLPrLVjv3DbyM2hgQQviKJaTWIRRTjKjWlHg3p2ig==",
"license": "MIT"
},
"node_modules/pg-hstore": {
@ -1461,18 +1524,18 @@
}
},
"node_modules/pg-pool": {
"version": "3.13.0",
"resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.13.0.tgz",
"integrity": "sha512-gB+R+Xud1gLFuRD/QgOIgGOBE2KCQPaPwkzBBGC9oG69pHTkhQeIuejVIk3/cnDyX39av2AxomQiyPT13WKHQA==",
"version": "3.14.0",
"resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.14.0.tgz",
"integrity": "sha512-gKtPkFdQPU3DksooVLi9LsjZxrsBUZIpa+7aVx+LV5pNh0KzP4Zleud2po+ConrxbuXGBJ6Hfer6hdgpIBpBaw==",
"license": "MIT",
"peerDependencies": {
"pg": ">=8.0"
}
},
"node_modules/pg-protocol": {
"version": "1.13.0",
"resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.13.0.tgz",
"integrity": "sha512-zzdvXfS6v89r6v7OcFCHfHlyG/wvry1ALxZo4LqgUoy7W9xhBDMaqOuMiF3qEV45VqsN6rdlcehHrfDtlCPc8w==",
"version": "1.14.0",
"resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.14.0.tgz",
"integrity": "sha512-n5taZ1kO3s9ngDTVxsEznOqCyToTgz0FLuPq0B33COy5pPpuWJpY3/2oRBVETuOgzdqRXfWpM9HIhp2LBBT1BA==",
"license": "MIT"
},
"node_modules/pg-types": {

View file

@ -39,7 +39,8 @@ router.post('/post', postLimiter, async (request, response, next) => {
isPidValid = false;
}
} catch (err) {
isPidValid = false;
console.error(`Caught error when validating ${pid}:`, err.message || err);
isPidValid = true;
}
if (!isPidValid) {

83
main.py
View file

@ -14,11 +14,13 @@ from routes.equipment import equipment_history
from routes.equipment import equipment
from services.boss_retrieval import process_boss_file
from routes import Ranking
from routes import ranking_grabstats
from routes import twitter_link
from contextlib import asynccontextmanager
from datetime import datetime, timedelta
from datetime import datetime, timedelta, timezone
from sqlalchemy import delete
from config import BASE_DIR
import yaml
import asyncio
import subprocess
import signal
@ -31,6 +33,7 @@ JUDD_SERVER_JS = os.path.join(JUDD_CWD, "server.js")
JUDD_CMD = ["node", JUDD_SERVER_JS]
judd_process = None
skip_upcoming_reset = False
async def boss_worker_loop():
print("background worker started")
@ -43,30 +46,79 @@ async def boss_worker_loop():
await asyncio.sleep(3600)
async def weekly_rank_reset_loop():
global skip_upcoming_reset
print("weekly_rank_reset worker started")
while True:
now = datetime.now()
days_ahead = 6 - now.weekday()
FES_BOSS_PATH = os.path.join(BASE_DIR, "fes_boss.yaml")
def get_next_sunday_reset_time_utc():
now_utc = datetime.now(timezone.utc)
days_ahead = 6 - now_utc.weekday()
if days_ahead <= 0:
days_ahead += 7
next_sunday_utc = now_utc + timedelta(days=days_ahead)
return next_sunday_utc.replace(hour=0, minute=0, second=0, microsecond=0)
async def check_splatfest_schedule_loop():
global skip_upcoming_reset
while True:
try:
target_reset_utc = get_next_sunday_reset_time_utc()
print(f"checking if a splatfest will be active at: {target_reset_utc.isoformat()}")
if os.path.exists(FES_BOSS_PATH):
with open(FES_BOSS_PATH, "r", encoding="utf-8") as f:
fes_data = yaml.safe_load(f)
if fes_data and "Time" in fes_data:
start_time = datetime.fromisoformat(fes_data["Time"]["Start"])
end_time = datetime.fromisoformat(fes_data["Time"]["End"])
start_time_utc = start_time.astimezone(timezone.utc)
end_time_utc = end_time.astimezone(timezone.utc)
print(f"detected splatfest schedule: {start_time_utc.isoformat()} to {end_time_utc.isoformat()}")
if start_time_utc <= target_reset_utc <= end_time_utc:
skip_upcoming_reset = True
print("Splatfest detected in reset window")
else:
skip_upcoming_reset = False
print("No splatfest active in reset window, yay!!!")
else:
print("could not find yaml, defaulted to no fest")
skip_upcoming_reset = False
except Exception as e:
print(f"failed to check fest schedule: {e}")
next_sunday = now + timedelta(days=days_ahead)
next_run = next_sunday.replace(hour=0, minute=0, second=0, microsecond=0)
await asyncio.sleep(7200)
asyncio.create_task(check_splatfest_schedule_loop())
while True:
now_utc = datetime.now(timezone.utc)
next_run_utc = get_next_sunday_reset_time_utc()
wait_seconds = (next_run_utc - now_utc).total_seconds()
wait_seconds = (next_run - now).total_seconds()
print(f"Next ranking reset scheduled for: {next_run} (in {wait_seconds:.0f} seconds)")
print(f"Next ranking reset scheduled for: {next_run_utc.isoformat()} (in {wait_seconds:.0f} seconds)")
try:
await asyncio.sleep(wait_seconds)
print("Executing weekly ranking reset...")
with SessionLocal() as db:
db.execute(delete(PlayerRank))
db.commit()
print("Ranking table cleared successfully.")
await FastAPICache.clear()
print("Cache cleared")
print("ranking reset triggerred!")
if skip_upcoming_reset:
print("Reset skipped due to active splatfest")
else:
print("Executing weekly ranking reset...")
with SessionLocal() as db:
db.execute(delete(PlayerRank))
db.commit()
print("Ranking table cleared successfully.")
await FastAPICache.clear()
print("Cache cleared")
await asyncio.sleep(60)
except asyncio.CancelledError:
@ -136,6 +188,7 @@ app.include_router(equipment_history.router, prefix="/api/v1")
app.include_router(equipment.router, prefix="/api/v1")
app.include_router(Ranking.router, prefix="/api/v1")
app.include_router(twitter_link.router, prefix="/api/v1")
app.include_router(ranking_grabstats.router, prefix="/api/v1")
def start():
uvicorn.run("main:app", host="0.0.0.0", port=settings.port, reload=False)

View file

@ -7,45 +7,45 @@ requires-python = ">=3.11"
dependencies = [
"annotated-doc==0.0.4",
"annotated-types==0.7.0",
"anyio==4.13.0",
"anyio==4.14.0",
"argon2-cffi==25.1.0",
"argon2-cffi-bindings==25.1.0",
"certifi==2026.4.22",
"certifi==2026.6.17",
"cffi==2.0.0",
"charset-normalizer==3.4.7",
"click==8.3.3",
"click==8.4.1",
"colorama==0.4.6",
"cryptography==46.0.7",
"fastapi==0.136.1",
"cryptography==49.0.0",
"fastapi==0.137.1",
"fastapi-cache2==0.2.2",
"greenlet==3.4.0",
"greenlet==3.5.2",
"h11==0.16.0",
"httpcore==1.0.9",
"httpx==0.28.1",
"idna==3.13",
"idna==3.18",
"oauthlib==3.3.1",
"oead==1.2.9.post4",
"pendulum==3.2.0",
"psycopg2-binary==2.9.12",
"pycparser==3.0",
"pydantic==2.13.3",
"pydantic==2.13.4",
"pydantic-core==2.46.4",
"pydantic-settings==2.14.0",
"pydantic-settings==2.14.1",
"python-dateutil==2.9.0.post0",
"python-dotenv==1.2.2",
"python-multipart==0.0.27",
"python-multipart==0.0.32",
"pyyaml==6.0.3",
"requests==2.33.1",
"requests==2.34.2",
"requests-oauthlib==2.0.0",
"six==1.17.0",
"sqlalchemy==2.0.49",
"starlette==1.0.0",
"sqlalchemy==2.0.51",
"starlette==1.3.1",
"tweepy==4.16.0",
"typing-extensions==4.15.0",
"typing-inspection==0.4.2",
"tzdata==2026.2",
"urllib3==2.6.3",
"uvicorn==0.46.0",
"urllib3==2.7.0",
"uvicorn==0.49.0",
"jinja2==3.1.6",
]

View file

@ -4,7 +4,7 @@
"packageRules": [
{
"matchUpdateTypes": ["minor", "patch"],
"automerge": true
"automerge": false
},
{
"matchUpdateTypes": ["major"],

View file

@ -33,7 +33,7 @@ async def get_equipment_composite(request: Request, db: DBSession = Depends(get_
try:
decrypted_pass = cipher.decrypt(user.spfn_pass_enc.encode()).decode()
token_data = auth.get_token(user.username, decrypted_pass)
profile = json.loads(auth.get_profile(token_data["token"]))
profile = auth.get_profile(token_data["access_token"])
pid_val = int(profile.get("pid"))
mii_name = profile.get("name", user.username)

View file

@ -27,7 +27,7 @@ async def get_history(request: Request, db: DBSession = Depends(get_db)):
try:
decrypted_pass = cipher.decrypt(user.spfn_pass_enc.encode()).decode()
token_data = auth.get_token(user.username, decrypted_pass)
profile = json.loads(auth.get_profile(token_data["token"]))
profile = auth.get_profile(token_data["access_token"])
pid_val = int(profile.get("pid"))
print(f"Fetching History for PID: {pid_val}")

View file

@ -33,10 +33,10 @@ async def get_my_profile(request: Request, db: DBSession = Depends(get_db)):
decrypted_pass = cipher.decrypt(user.spfn_pass_enc.encode()).decode()
token_data = auth.get_token(user.username, decrypted_pass)
if not token_data or "token" not in token_data:
if not token_data or "access_token" not in token_data:
return RedirectResponse(url="/sign_in/")
profile_data = auth.get_profile(token_data["token"])
profile_data = auth.get_profile(token_data["access_token"])
if not profile_data:
raise HTTPException(status_code=404, detail="Profile not found")

View file

@ -0,0 +1,72 @@
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session as DBSession
from sqlalchemy import desc
from database import SessionLocal, PlayerRank, EquipmentLast
from fastapi_cache.decorator import cache
router = APIRouter()
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
@router.get("/leaderboard/getplayerstats/{pid}")
@cache(expire=60)
async def get_player_stats(pid: int, mode: int | None = None, db: DBSession = Depends(get_db)):
try:
query = (
db.query(PlayerRank, EquipmentLast)
.outerjoin(EquipmentLast, PlayerRank.PId == EquipmentLast.PId)
.filter(PlayerRank.PId == pid)
)
if mode is not None:
query = query.filter(PlayerRank.GameMode == mode)
result = query.first()
if not result:
raise HTTPException(status_code=404, detail="Player not found")
player, gear = result
player_data = {
"PId": player.PId,
"MiiName": player.MiiName,
"Rank": player.Rank,
"GameMode": player.GameMode,
"WinSum": player.WinSum,
"LoseSum": player.LoseSum,
"RankingScore": round(player.RankingScore, 2),
"weapon": gear.weapon if gear else None,
"headgear": gear.Gear_Head if gear else None,
"clothes": gear.Gear_Clothes if gear else None,
"shoes": gear.Gear_Shoes if gear else None,
}
if player.GameMode == 2:
top_100_query = (
db.query(PlayerRank.PId)
.order_by(desc(PlayerRank.FesPower))
.limit(100)
.all()
)
top_100_tuples = set(top_100_query)
is_top_100 = (player.PId,) in top_100_tuples
player_data["FesPower"] = player.FesPower
player_data["is_top_100_fes"] = is_top_100
else:
player_data["FesPower"] = None
player_data["is_top_100_fes"] = False
return player_data
except HTTPException as http_ex:
raise http_ex
except Exception as e:
print(f"Error fetching stats for player {pid}: {e}")
return {"error": str(e)}

View file

@ -37,7 +37,7 @@ async def login(
try:
print("fetching spfn token")
data = auth.get_token(username, password)
if not data or "token" not in data:
if not data or "access_token" not in data:
print("auth failed")
return RedirectResponse(f"{auth_path}{sep}error=auth&username={username}", 303)

View file

@ -93,7 +93,7 @@ async def confirm_twitter(state: str, code: str, db: DBSession = Depends(get_db)
decrypted_pass = cipher.decrypt(user.spfn_pass_enc.encode()).decode()
profile_auth = auth.get_token(user.username, decrypted_pass)
profile_response = auth.get_profile(profile_auth["token"])
profile_response = auth.get_profile(profile_auth["access_token"])
if isinstance(profile_response, str):
try:
@ -149,7 +149,7 @@ async def get_twitter_status(request: Request, db: DBSession = Depends(get_db)):
try:
decrypted_pass = cipher.decrypt(user.spfn_pass_enc.encode()).decode()
profile_auth = auth.get_token(user.username, decrypted_pass)
profile_res = auth.get_profile(profile_auth["token"])
profile_res = auth.get_profile(profile_auth["access_token"])
if isinstance(profile_res, str):
profile_data = json.loads(profile_res)
@ -183,7 +183,7 @@ async def unlink_twitter(request: Request, db: DBSession = Depends(get_db)):
user = db.query(User).filter(User.username == db_session.username).first()
decrypted_pass = cipher.decrypt(user.spfn_pass_enc.encode()).decode()
profile_auth = auth.get_token(user.username, decrypted_pass)
profile_data = auth.get_profile(profile_auth["token"])
profile_data = auth.get_profile(profile_auth["access_token"])
if isinstance(profile_data, str):
profile_data = json.loads(profile_data)

3
security.md Normal file
View file

@ -0,0 +1,3 @@
# Security Policy
Report security vulnerabilities through the security tab on this repo. Only vulnerabilities on the latest commit of any branch will be considered.

View file

@ -1,35 +1,41 @@
import requests
import base64
from config import settings
from argon2 import PasswordHasher
API_URL = "https://account.spfn.net/api/v2"
CLIENT_ID = "splatnet"
CLIENT_SECRET = settings.account_client_secret
ph = PasswordHasher()
def hash_password(password: str):
return ph.hash(password)
def verify_password(hashed: str, password: str):
try:
return ph.verify(hashed, password)
except Exception:
return False
def get_token(username, password):
creds = f"{username} {password}"
encoded = base64.b64encode(creds.encode()).decode()
url = f"{API_URL}/oauth2/generate_token"
headers = {
"Authorization": f"Basic {encoded}",
"User-Agent": "saturday & allison should lwk kiss..."
payload = {
"grant_type": "password",
"username": username,
"password": password,
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET
}
response = requests.get(f"{API_URL}/oauth2/generate_token", headers=headers, timeout=10)
headers = {
"User-Agent": "chiyo & eri should lwk kiss..."
}
response = requests.post(url, data=payload, headers=headers, timeout=10)
return response.json() if response.ok else None
def get_profile(token):
url = f"{API_URL}/users/@me/profile"
headers = {
"Authorization": f"Bearer {token}",
"User-Agent": "every update im going to change this user agent because im bored!!"
"User-Agent": "lets make the most of the night like were gonna die young!!"
}
response = requests.get(f"{API_URL}/users/@me/profile", headers=headers, timeout=10)
return response.text if response.ok else None
response = requests.get(url, headers=headers, timeout=10)
return response.json() if response.ok else None

3
support.md Normal file
View file

@ -0,0 +1,3 @@
# Support
For support, join [our discord](https://discord.gg/splatfestival).