initial commit
This commit is contained in:
34
.gitignore
vendored
Normal file
34
.gitignore
vendored
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# dependencies (bun install)
|
||||||
|
node_modules
|
||||||
|
|
||||||
|
# output
|
||||||
|
out
|
||||||
|
dist
|
||||||
|
*.tgz
|
||||||
|
|
||||||
|
# code coverage
|
||||||
|
coverage
|
||||||
|
*.lcov
|
||||||
|
|
||||||
|
# logs
|
||||||
|
logs
|
||||||
|
_.log
|
||||||
|
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
|
||||||
|
|
||||||
|
# dotenv environment variable files
|
||||||
|
.env
|
||||||
|
.env.development.local
|
||||||
|
.env.test.local
|
||||||
|
.env.production.local
|
||||||
|
.env.local
|
||||||
|
|
||||||
|
# caches
|
||||||
|
.eslintcache
|
||||||
|
.cache
|
||||||
|
*.tsbuildinfo
|
||||||
|
|
||||||
|
# IntelliJ based IDEs
|
||||||
|
.idea
|
||||||
|
|
||||||
|
# Finder (MacOS) folder config
|
||||||
|
.DS_Store
|
BIN
2637354/108051.osr
Normal file
BIN
2637354/108051.osr
Normal file
Binary file not shown.
BIN
2637354/3175608.osr
Normal file
BIN
2637354/3175608.osr
Normal file
Binary file not shown.
BIN
2637354/322849.osr
Normal file
BIN
2637354/322849.osr
Normal file
Binary file not shown.
BIN
2637354/3579210.osr
Normal file
BIN
2637354/3579210.osr
Normal file
Binary file not shown.
BIN
2637354/3712168.osr
Normal file
BIN
2637354/3712168.osr
Normal file
Binary file not shown.
BIN
2637354/3823168.osr
Normal file
BIN
2637354/3823168.osr
Normal file
Binary file not shown.
BIN
2637354/4274784.osr
Normal file
BIN
2637354/4274784.osr
Normal file
Binary file not shown.
BIN
2637354/4331683.osr
Normal file
BIN
2637354/4331683.osr
Normal file
Binary file not shown.
BIN
2637354/4393946.osr
Normal file
BIN
2637354/4393946.osr
Normal file
Binary file not shown.
BIN
2637354/459579.osr
Normal file
BIN
2637354/459579.osr
Normal file
Binary file not shown.
BIN
2637354/4811455.osr
Normal file
BIN
2637354/4811455.osr
Normal file
Binary file not shown.
BIN
2637354/4934795.osr
Normal file
BIN
2637354/4934795.osr
Normal file
Binary file not shown.
BIN
2637354/607421.osr
Normal file
BIN
2637354/607421.osr
Normal file
Binary file not shown.
BIN
2637354/75690.osr
Normal file
BIN
2637354/75690.osr
Normal file
Binary file not shown.
BIN
2637354/89835.osr
Normal file
BIN
2637354/89835.osr
Normal file
Binary file not shown.
45
README.md
Normal file
45
README.md
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
# replay_downloader
|
||||||
|
|
||||||
|
A Tool to mass download EZPPFarm replays from specific leaderboards
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
- [Bun](https://bun.sh)
|
||||||
|
|
||||||
|
## To install bun:
|
||||||
|
|
||||||
|
### Windows:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
powershell -c "irm bun.sh/install.ps1 | iex"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Linux & macOS:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -fsSL https://bun.sh/install | bash
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## To install dependencies:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bun install
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## To debug:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bun run debug
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## To build:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bun run build
|
||||||
|
```
|
158
bun.lock
Normal file
158
bun.lock
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
{
|
||||||
|
"lockfileVersion": 1,
|
||||||
|
"workspaces": {
|
||||||
|
"": {
|
||||||
|
"name": "replay_downloader",
|
||||||
|
"dependencies": {
|
||||||
|
"replay_downloader": ".",
|
||||||
|
"@better-fetch/fetch": "^1.1.18",
|
||||||
|
"chalk": "^5.4.1",
|
||||||
|
"inquirer": "^12.9.0",
|
||||||
|
"ky": "^1.8.2",
|
||||||
|
"ora": "^8.2.0",
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/bun": "latest",
|
||||||
|
"@types/chalk": "^2.2.4",
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"typescript": "^5",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"packages": {
|
||||||
|
"@better-fetch/fetch": ["@better-fetch/fetch@1.1.18", "", {}, "sha512-rEFOE1MYIsBmoMJtQbl32PGHHXuG2hDxvEd7rUHE0vCBoFQVSDqaVs9hkZEtHCxRoY+CljXKFCOuJ8uxqw1LcA=="],
|
||||||
|
|
||||||
|
"@inquirer/checkbox": ["@inquirer/checkbox@4.2.0", "", { "dependencies": { "@inquirer/core": "^10.1.15", "@inquirer/figures": "^1.0.13", "@inquirer/type": "^3.0.8", "ansi-escapes": "^4.3.2", "yoctocolors-cjs": "^2.1.2" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-fdSw07FLJEU5vbpOPzXo5c6xmMGDzbZE2+niuDHX5N6mc6V0Ebso/q3xiHra4D73+PMsC8MJmcaZKuAAoaQsSA=="],
|
||||||
|
|
||||||
|
"@inquirer/confirm": ["@inquirer/confirm@5.1.14", "", { "dependencies": { "@inquirer/core": "^10.1.15", "@inquirer/type": "^3.0.8" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-5yR4IBfe0kXe59r1YCTG8WXkUbl7Z35HK87Sw+WUyGD8wNUx7JvY7laahzeytyE1oLn74bQnL7hstctQxisQ8Q=="],
|
||||||
|
|
||||||
|
"@inquirer/core": ["@inquirer/core@10.1.15", "", { "dependencies": { "@inquirer/figures": "^1.0.13", "@inquirer/type": "^3.0.8", "ansi-escapes": "^4.3.2", "cli-width": "^4.1.0", "mute-stream": "^2.0.0", "signal-exit": "^4.1.0", "wrap-ansi": "^6.2.0", "yoctocolors-cjs": "^2.1.2" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-8xrp836RZvKkpNbVvgWUlxjT4CraKk2q+I3Ksy+seI2zkcE+y6wNs1BVhgcv8VyImFecUhdQrYLdW32pAjwBdA=="],
|
||||||
|
|
||||||
|
"@inquirer/editor": ["@inquirer/editor@4.2.15", "", { "dependencies": { "@inquirer/core": "^10.1.15", "@inquirer/type": "^3.0.8", "external-editor": "^3.1.0" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-wst31XT8DnGOSS4nNJDIklGKnf+8shuauVrWzgKegWUe28zfCftcWZ2vktGdzJgcylWSS2SrDnYUb6alZcwnCQ=="],
|
||||||
|
|
||||||
|
"@inquirer/expand": ["@inquirer/expand@4.0.17", "", { "dependencies": { "@inquirer/core": "^10.1.15", "@inquirer/type": "^3.0.8", "yoctocolors-cjs": "^2.1.2" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-PSqy9VmJx/VbE3CT453yOfNa+PykpKg/0SYP7odez1/NWBGuDXgPhp4AeGYYKjhLn5lUUavVS/JbeYMPdH50Mw=="],
|
||||||
|
|
||||||
|
"@inquirer/figures": ["@inquirer/figures@1.0.13", "", {}, "sha512-lGPVU3yO9ZNqA7vTYz26jny41lE7yoQansmqdMLBEfqaGsmdg7V3W9mK9Pvb5IL4EVZ9GnSDGMO/cJXud5dMaw=="],
|
||||||
|
|
||||||
|
"@inquirer/input": ["@inquirer/input@4.2.1", "", { "dependencies": { "@inquirer/core": "^10.1.15", "@inquirer/type": "^3.0.8" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-tVC+O1rBl0lJpoUZv4xY+WGWY8V5b0zxU1XDsMsIHYregdh7bN5X5QnIONNBAl0K765FYlAfNHS2Bhn7SSOVow=="],
|
||||||
|
|
||||||
|
"@inquirer/number": ["@inquirer/number@3.0.17", "", { "dependencies": { "@inquirer/core": "^10.1.15", "@inquirer/type": "^3.0.8" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-GcvGHkyIgfZgVnnimURdOueMk0CztycfC8NZTiIY9arIAkeOgt6zG57G+7vC59Jns3UX27LMkPKnKWAOF5xEYg=="],
|
||||||
|
|
||||||
|
"@inquirer/password": ["@inquirer/password@4.0.17", "", { "dependencies": { "@inquirer/core": "^10.1.15", "@inquirer/type": "^3.0.8", "ansi-escapes": "^4.3.2" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-DJolTnNeZ00E1+1TW+8614F7rOJJCM4y4BAGQ3Gq6kQIG+OJ4zr3GLjIjVVJCbKsk2jmkmv6v2kQuN/vriHdZA=="],
|
||||||
|
|
||||||
|
"@inquirer/prompts": ["@inquirer/prompts@7.8.0", "", { "dependencies": { "@inquirer/checkbox": "^4.2.0", "@inquirer/confirm": "^5.1.14", "@inquirer/editor": "^4.2.15", "@inquirer/expand": "^4.0.17", "@inquirer/input": "^4.2.1", "@inquirer/number": "^3.0.17", "@inquirer/password": "^4.0.17", "@inquirer/rawlist": "^4.1.5", "@inquirer/search": "^3.1.0", "@inquirer/select": "^4.3.1" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-JHwGbQ6wjf1dxxnalDYpZwZxUEosT+6CPGD9Zh4sm9WXdtUp9XODCQD3NjSTmu+0OAyxWXNOqf0spjIymJa2Tw=="],
|
||||||
|
|
||||||
|
"@inquirer/rawlist": ["@inquirer/rawlist@4.1.5", "", { "dependencies": { "@inquirer/core": "^10.1.15", "@inquirer/type": "^3.0.8", "yoctocolors-cjs": "^2.1.2" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-R5qMyGJqtDdi4Ht521iAkNqyB6p2UPuZUbMifakg1sWtu24gc2Z8CJuw8rP081OckNDMgtDCuLe42Q2Kr3BolA=="],
|
||||||
|
|
||||||
|
"@inquirer/search": ["@inquirer/search@3.1.0", "", { "dependencies": { "@inquirer/core": "^10.1.15", "@inquirer/figures": "^1.0.13", "@inquirer/type": "^3.0.8", "yoctocolors-cjs": "^2.1.2" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-PMk1+O/WBcYJDq2H7foV0aAZSmDdkzZB9Mw2v/DmONRJopwA/128cS9M/TXWLKKdEQKZnKwBzqu2G4x/2Nqx8Q=="],
|
||||||
|
|
||||||
|
"@inquirer/select": ["@inquirer/select@4.3.1", "", { "dependencies": { "@inquirer/core": "^10.1.15", "@inquirer/figures": "^1.0.13", "@inquirer/type": "^3.0.8", "ansi-escapes": "^4.3.2", "yoctocolors-cjs": "^2.1.2" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-Gfl/5sqOF5vS/LIrSndFgOh7jgoe0UXEizDqahFRkq5aJBLegZ6WjuMh/hVEJwlFQjyLq1z9fRtvUMkb7jM1LA=="],
|
||||||
|
|
||||||
|
"@inquirer/type": ["@inquirer/type@3.0.8", "", { "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-lg9Whz8onIHRthWaN1Q9EGLa/0LFJjyM8mEUbL1eTi6yMGvBf8gvyDLtxSXztQsxMvhxxNpJYrwa1YHdq+w4Jw=="],
|
||||||
|
|
||||||
|
"@types/bun": ["@types/bun@1.2.19", "", { "dependencies": { "bun-types": "1.2.19" } }, "sha512-d9ZCmrH3CJ2uYKXQIUuZ/pUnTqIvLDS0SK7pFmbx8ma+ziH/FRMoAq5bYpRG7y+w1gl+HgyNZbtqgMq4W4e2Lg=="],
|
||||||
|
|
||||||
|
"@types/chalk": ["@types/chalk@2.2.4", "", { "dependencies": { "chalk": "*" } }, "sha512-pb/QoGqtCpH2famSp72qEsXkNzcErlVmiXlQ/ww+5AddD8TmmYS7EWg5T20YiNCAiTgs8pMf2G8SJG5h/ER1ZQ=="],
|
||||||
|
|
||||||
|
"@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="],
|
||||||
|
|
||||||
|
"@types/react": ["@types/react@19.1.9", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-WmdoynAX8Stew/36uTSVMcLJJ1KRh6L3IZRx1PZ7qJtBqT3dYTgyDTx8H1qoRghErydW7xw9mSJ3wS//tCRpFA=="],
|
||||||
|
|
||||||
|
"ansi-escapes": ["ansi-escapes@4.3.2", "", { "dependencies": { "type-fest": "^0.21.3" } }, "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ=="],
|
||||||
|
|
||||||
|
"ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="],
|
||||||
|
|
||||||
|
"ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
|
||||||
|
|
||||||
|
"bun-types": ["bun-types@1.2.19", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-uAOTaZSPuYsWIXRpj7o56Let0g/wjihKCkeRqUBhlLVM/Bt+Fj9xTo+LhC1OV1XDaGkz4hNC80et5xgy+9KTHQ=="],
|
||||||
|
|
||||||
|
"chalk": ["chalk@5.4.1", "", {}, "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w=="],
|
||||||
|
|
||||||
|
"chardet": ["chardet@0.7.0", "", {}, "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA=="],
|
||||||
|
|
||||||
|
"cli-cursor": ["cli-cursor@5.0.0", "", { "dependencies": { "restore-cursor": "^5.0.0" } }, "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw=="],
|
||||||
|
|
||||||
|
"cli-spinners": ["cli-spinners@2.9.2", "", {}, "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg=="],
|
||||||
|
|
||||||
|
"cli-width": ["cli-width@4.1.0", "", {}, "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ=="],
|
||||||
|
|
||||||
|
"color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
|
||||||
|
|
||||||
|
"color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
|
||||||
|
|
||||||
|
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
|
||||||
|
|
||||||
|
"emoji-regex": ["emoji-regex@10.4.0", "", {}, "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw=="],
|
||||||
|
|
||||||
|
"external-editor": ["external-editor@3.1.0", "", { "dependencies": { "chardet": "^0.7.0", "iconv-lite": "^0.4.24", "tmp": "^0.0.33" } }, "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew=="],
|
||||||
|
|
||||||
|
"get-east-asian-width": ["get-east-asian-width@1.3.0", "", {}, "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ=="],
|
||||||
|
|
||||||
|
"iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="],
|
||||||
|
|
||||||
|
"inquirer": ["inquirer@12.9.0", "", { "dependencies": { "@inquirer/core": "^10.1.15", "@inquirer/prompts": "^7.8.0", "@inquirer/type": "^3.0.8", "ansi-escapes": "^4.3.2", "mute-stream": "^2.0.0", "run-async": "^4.0.5", "rxjs": "^7.8.2" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-LlFVmvWVCun7uEgPB3vups9NzBrjJn48kRNtFGw3xU1H5UXExTEz/oF1JGLaB0fvlkUB+W6JfgLcSEaSdH7RPA=="],
|
||||||
|
|
||||||
|
"is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="],
|
||||||
|
|
||||||
|
"is-interactive": ["is-interactive@2.0.0", "", {}, "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ=="],
|
||||||
|
|
||||||
|
"is-unicode-supported": ["is-unicode-supported@2.1.0", "", {}, "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ=="],
|
||||||
|
|
||||||
|
"ky": ["ky@1.8.2", "", {}, "sha512-XybQJ3d4Ea1kI27DoelE5ZCT3bSJlibYTtQuMsyzKox3TMyayw1asgQdl54WroAm+fIA3ZCr8zXW2RpR7qWVpA=="],
|
||||||
|
|
||||||
|
"log-symbols": ["log-symbols@6.0.0", "", { "dependencies": { "chalk": "^5.3.0", "is-unicode-supported": "^1.3.0" } }, "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw=="],
|
||||||
|
|
||||||
|
"mimic-function": ["mimic-function@5.0.1", "", {}, "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA=="],
|
||||||
|
|
||||||
|
"mute-stream": ["mute-stream@2.0.0", "", {}, "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA=="],
|
||||||
|
|
||||||
|
"onetime": ["onetime@7.0.0", "", { "dependencies": { "mimic-function": "^5.0.0" } }, "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ=="],
|
||||||
|
|
||||||
|
"ora": ["ora@8.2.0", "", { "dependencies": { "chalk": "^5.3.0", "cli-cursor": "^5.0.0", "cli-spinners": "^2.9.2", "is-interactive": "^2.0.0", "is-unicode-supported": "^2.0.0", "log-symbols": "^6.0.0", "stdin-discarder": "^0.2.2", "string-width": "^7.2.0", "strip-ansi": "^7.1.0" } }, "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw=="],
|
||||||
|
|
||||||
|
"os-tmpdir": ["os-tmpdir@1.0.2", "", {}, "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g=="],
|
||||||
|
|
||||||
|
"replay_downloader": ["replay_downloader@file:", { "dependencies": { "@better-fetch/fetch": "^1.1.18", "chalk": "^5.4.1", "inquirer": "^12.9.0", "ky": "^1.8.2", "ora": "^8.2.0" }, "devDependencies": { "@types/bun": "latest", "@types/chalk": "^2.2.4" }, "peerDependencies": { "typescript": "^5" } }],
|
||||||
|
|
||||||
|
"restore-cursor": ["restore-cursor@5.1.0", "", { "dependencies": { "onetime": "^7.0.0", "signal-exit": "^4.1.0" } }, "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA=="],
|
||||||
|
|
||||||
|
"run-async": ["run-async@4.0.5", "", {}, "sha512-oN9GTgxUNDBumHTTDmQ8dep6VIJbgj9S3dPP+9XylVLIK4xB9XTXtKWROd5pnhdXR9k0EgO1JRcNh0T+Ny2FsA=="],
|
||||||
|
|
||||||
|
"rxjs": ["rxjs@7.8.2", "", { "dependencies": { "tslib": "^2.1.0" } }, "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA=="],
|
||||||
|
|
||||||
|
"safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="],
|
||||||
|
|
||||||
|
"signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="],
|
||||||
|
|
||||||
|
"stdin-discarder": ["stdin-discarder@0.2.2", "", {}, "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ=="],
|
||||||
|
|
||||||
|
"string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="],
|
||||||
|
|
||||||
|
"strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="],
|
||||||
|
|
||||||
|
"tmp": ["tmp@0.0.33", "", { "dependencies": { "os-tmpdir": "~1.0.2" } }, "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw=="],
|
||||||
|
|
||||||
|
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||||
|
|
||||||
|
"type-fest": ["type-fest@0.21.3", "", {}, "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w=="],
|
||||||
|
|
||||||
|
"typescript": ["typescript@5.9.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A=="],
|
||||||
|
|
||||||
|
"undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="],
|
||||||
|
|
||||||
|
"wrap-ansi": ["wrap-ansi@6.2.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA=="],
|
||||||
|
|
||||||
|
"yoctocolors-cjs": ["yoctocolors-cjs@2.1.2", "", {}, "sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA=="],
|
||||||
|
|
||||||
|
"log-symbols/is-unicode-supported": ["is-unicode-supported@1.3.0", "", {}, "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ=="],
|
||||||
|
|
||||||
|
"wrap-ansi/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
|
||||||
|
|
||||||
|
"wrap-ansi/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
|
||||||
|
|
||||||
|
"wrap-ansi/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
|
||||||
|
|
||||||
|
"wrap-ansi/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
||||||
|
}
|
||||||
|
}
|
27
package.json
Normal file
27
package.json
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"name": "replay_downloader",
|
||||||
|
"module": "src/index.ts",
|
||||||
|
"type": "module",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"debug": "bun --watch src/index.ts",
|
||||||
|
"build": "bun run build:win && bun run build:linux && bun run build:mac",
|
||||||
|
"build:win": "bun build ./src/index.ts --compile --target=bun-windows-x64-modern --outfile ./target/replay_downloader-windows-x64",
|
||||||
|
"build:linux": "bun build ./src/index.ts --compile --target=bun-linux-x64-modern --outfile ./target/replay_downloader-linux-x64",
|
||||||
|
"build:mac": "bun build ./src/index.ts --compile --target=bun-darwin-x64 --outfile ./target/replay_downloader-darwin-x64"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/bun": "latest",
|
||||||
|
"@types/chalk": "^2.2.4"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"typescript": "^5"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@better-fetch/fetch": "^1.1.18",
|
||||||
|
"chalk": "^5.4.1",
|
||||||
|
"inquirer": "^12.9.0",
|
||||||
|
"ky": "^1.8.2",
|
||||||
|
"ora": "^8.2.0"
|
||||||
|
}
|
||||||
|
}
|
37
src/api/ezpp.ts
Normal file
37
src/api/ezpp.ts
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import { type Method, createFetch } from '@better-fetch/fetch';
|
||||||
|
import type { HeadersInit } from 'bun';
|
||||||
|
|
||||||
|
const apiClient = createFetch({
|
||||||
|
baseURL: 'https://api.ez-pp.farm/',
|
||||||
|
throw: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
export type ApiResponse<T> = { data: T; error: undefined } | { data: undefined; error: Error };
|
||||||
|
|
||||||
|
export const fetchApi = async <T>(
|
||||||
|
route: string,
|
||||||
|
options?: {
|
||||||
|
query?: Record<string, unknown>;
|
||||||
|
headers?: HeadersInit;
|
||||||
|
method?: Method;
|
||||||
|
params?: Record<string, unknown>;
|
||||||
|
timeout?: number;
|
||||||
|
signal?: AbortSignal;
|
||||||
|
}
|
||||||
|
): Promise<ApiResponse<T>> => {
|
||||||
|
try {
|
||||||
|
const data = await apiClient<T>(route, {
|
||||||
|
query: options?.query,
|
||||||
|
headers: options?.headers ?? {
|
||||||
|
accept: 'application/json',
|
||||||
|
},
|
||||||
|
method: options?.method ?? 'GET',
|
||||||
|
params: options?.params,
|
||||||
|
timeout: options?.timeout,
|
||||||
|
signal: options?.signal,
|
||||||
|
});
|
||||||
|
return { data, error: undefined };
|
||||||
|
} catch (err) {
|
||||||
|
return { data: undefined, error: err as Error };
|
||||||
|
}
|
||||||
|
};
|
108
src/index.ts
Normal file
108
src/index.ts
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
import inquirer from "inquirer";
|
||||||
|
import { fetchApi } from "./api/ezpp";
|
||||||
|
import ora from "ora";
|
||||||
|
import {
|
||||||
|
getGamemodeName,
|
||||||
|
getModeAndTypeFromGamemode,
|
||||||
|
modeIntToStr,
|
||||||
|
typeIntToStr,
|
||||||
|
validModeTypeCombinationsSorted,
|
||||||
|
} from "./util/mode";
|
||||||
|
import type { MapScores } from "./interface/MapScores";
|
||||||
|
import * as path from "node:path";
|
||||||
|
import { betterFetch } from "@better-fetch/fetch";
|
||||||
|
import ky from "ky";
|
||||||
|
import { mkdir } from "node:fs/promises";
|
||||||
|
import { existsSync } from "node:fs";
|
||||||
|
import chalk from "chalk";
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
const modeChoices = validModeTypeCombinationsSorted.map((gamemode) => {
|
||||||
|
const gmode = getModeAndTypeFromGamemode(gamemode);
|
||||||
|
return {
|
||||||
|
value: gamemode,
|
||||||
|
name: getGamemodeName(modeIntToStr(gmode.mode), typeIntToStr(gmode.type)),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const answers: { beatmapId: number; mode: number } = await inquirer.prompt([
|
||||||
|
{
|
||||||
|
message: "Please enter a beatmap ID",
|
||||||
|
name: "beatmapId",
|
||||||
|
type: "number",
|
||||||
|
min: 0,
|
||||||
|
required: true,
|
||||||
|
async validate(value) {
|
||||||
|
const { error } = await fetchApi("v1/get_map_info", {
|
||||||
|
query: {
|
||||||
|
id: value,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (error) return "Beatmap not found!";
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "select",
|
||||||
|
name: "mode",
|
||||||
|
message: "Please select a mode",
|
||||||
|
choices: modeChoices,
|
||||||
|
loop: false,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const leaderboardLoadingSpinner = ora("Loading scores...").start();
|
||||||
|
|
||||||
|
const { error, data } = await fetchApi<MapScores>("v1/get_map_scores", {
|
||||||
|
query: {
|
||||||
|
id: answers.beatmapId,
|
||||||
|
mode: answers.mode,
|
||||||
|
scope: "best",
|
||||||
|
limit: 50,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (error || !data.scores || data.scores.length <= 0) {
|
||||||
|
leaderboardLoadingSpinner.fail("Failed to get map scores.");
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
leaderboardLoadingSpinner.succeed("Scores loaded!");
|
||||||
|
|
||||||
|
const currentFolder = path.join(process.cwd());
|
||||||
|
const downloadFolder = path.join(currentFolder, answers.beatmapId.toFixed());
|
||||||
|
if (!existsSync(downloadFolder)) await mkdir(downloadFolder);
|
||||||
|
|
||||||
|
let downloadedReplaysCount = 0;
|
||||||
|
|
||||||
|
for (const score of data.scores) {
|
||||||
|
const downloadSpinner = ora(
|
||||||
|
`downloading replay ${score.id} (0%)...`
|
||||||
|
).start();
|
||||||
|
try {
|
||||||
|
const replayDownload = await ky(
|
||||||
|
`https://api.ez-pp.farm/v1/get_replay?id=${score.id}&include_headers=true`,
|
||||||
|
{
|
||||||
|
onDownloadProgress(progress) {
|
||||||
|
downloadSpinner.text = `downloading replay ${score.id} (${(progress.percent * 100).toFixed()}%)...`;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const replayData = await replayDownload.arrayBuffer();
|
||||||
|
downloadSpinner.text = `Saving replay ${score.id}...`;
|
||||||
|
await Bun.write(
|
||||||
|
path.join(downloadFolder, `${score.id}.osr`),
|
||||||
|
Buffer.from(replayData)
|
||||||
|
);
|
||||||
|
downloadedReplaysCount += 1;
|
||||||
|
} catch {
|
||||||
|
downloadSpinner.fail(`Failed to download replay ${score.id}.`);
|
||||||
|
}
|
||||||
|
if (downloadSpinner.isSpinning) {
|
||||||
|
downloadSpinner.succeed(`Saved replay ${score.id}!`);
|
||||||
|
}
|
||||||
|
await new Promise((res) => setTimeout(res, 150));
|
||||||
|
}
|
||||||
|
console.log(`${chalk.green("✔")} Downloaded ${downloadedReplaysCount}/${data.scores.length} replay(s)!`);
|
||||||
|
process.exit(0);
|
||||||
|
})();
|
34
src/interface/MapScores.ts
Normal file
34
src/interface/MapScores.ts
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
export type MapScores = {
|
||||||
|
status: string;
|
||||||
|
scores: {
|
||||||
|
id: number;
|
||||||
|
map_md5: string;
|
||||||
|
score: number;
|
||||||
|
pp: number;
|
||||||
|
acc: number;
|
||||||
|
max_combo: number;
|
||||||
|
mods: number;
|
||||||
|
n300: number;
|
||||||
|
n100: number;
|
||||||
|
n50: number;
|
||||||
|
nmiss: number;
|
||||||
|
ngeki: number;
|
||||||
|
nkatu: number;
|
||||||
|
grade: string;
|
||||||
|
status: number;
|
||||||
|
mode: number;
|
||||||
|
play_time: string;
|
||||||
|
time_elapsed: number;
|
||||||
|
userid: number;
|
||||||
|
perfect: number;
|
||||||
|
player_name: string;
|
||||||
|
country: string;
|
||||||
|
username_style: string;
|
||||||
|
priv: number;
|
||||||
|
creation_time: number;
|
||||||
|
latest_activity: number;
|
||||||
|
clan_id: number | null;
|
||||||
|
clan_name: string | null;
|
||||||
|
clan_tag: string | null;
|
||||||
|
}[];
|
||||||
|
};
|
186
src/util/mode.ts
Normal file
186
src/util/mode.ts
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
export enum Gamemodes {
|
||||||
|
VANILLA_OSU = 0,
|
||||||
|
VANILLA_TAIKO = 1,
|
||||||
|
VANILLA_CATCH = 2,
|
||||||
|
VANILLA_MANIA = 3,
|
||||||
|
|
||||||
|
RELAX_OSU = 4,
|
||||||
|
RELAX_TAIKO = 5,
|
||||||
|
RELAX_CATCH = 6,
|
||||||
|
|
||||||
|
AUTOPILOT_OSU = 8,
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum Mode {
|
||||||
|
OSU = 0,
|
||||||
|
TAIKO = 1,
|
||||||
|
CATCH = 2,
|
||||||
|
MANIA = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum Type {
|
||||||
|
VANILLA = 0,
|
||||||
|
RELAX = 4,
|
||||||
|
AUTOPILOT = 8,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const validModes = [Mode.OSU, Mode.TAIKO, Mode.CATCH, Mode.MANIA];
|
||||||
|
export const validTypes = [Type.VANILLA, Type.RELAX, Type.AUTOPILOT];
|
||||||
|
export const validModeTypeCombinations = [0, 1, 2, 3, 4, 5, 6, 8];
|
||||||
|
export const validModeTypeCombinationsSorted = [0, 4, 8, 1, 5, 2, 6, 3];
|
||||||
|
|
||||||
|
export const validMode = (modeStr: string) => modeStrToInt(modeStr) !== undefined;
|
||||||
|
export const validType = (typeStr: string) => typeStrToInt(typeStr) !== undefined;
|
||||||
|
|
||||||
|
export const modeStrToInt = (modeStr: 'osu' | 'taiko' | 'catch' | 'mania' | string) => {
|
||||||
|
switch (modeStr) {
|
||||||
|
case 'taiko':
|
||||||
|
return Mode.TAIKO;
|
||||||
|
case 'catch':
|
||||||
|
return Mode.CATCH;
|
||||||
|
case 'mania':
|
||||||
|
return Mode.MANIA;
|
||||||
|
case 'osu':
|
||||||
|
return Mode.OSU;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const modeIntToStr = (modeInt: number) => {
|
||||||
|
switch (modeInt) {
|
||||||
|
case Mode.TAIKO:
|
||||||
|
return 'taiko';
|
||||||
|
case Mode.CATCH:
|
||||||
|
return 'catch';
|
||||||
|
case Mode.MANIA:
|
||||||
|
return 'mania';
|
||||||
|
case Mode.OSU:
|
||||||
|
return 'osu';
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const typeStrToInt = (typeStr: 'vanilla' | 'relax' | 'autopilot' | string) => {
|
||||||
|
switch (typeStr) {
|
||||||
|
case 'relax':
|
||||||
|
return Type.RELAX;
|
||||||
|
case 'autopilot':
|
||||||
|
return Type.AUTOPILOT;
|
||||||
|
case 'vanilla':
|
||||||
|
return Type.VANILLA;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const typeIntToStr = (typeInt: number) => {
|
||||||
|
switch (typeInt) {
|
||||||
|
case Type.RELAX:
|
||||||
|
return 'relax';
|
||||||
|
case Type.AUTOPILOT:
|
||||||
|
return 'autopilot';
|
||||||
|
case Type.VANILLA:
|
||||||
|
return 'vanilla';
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getGamemodeInt = (
|
||||||
|
mode: 'osu' | 'taiko' | 'catch' | 'mania' | string | undefined,
|
||||||
|
type: 'vanilla' | 'relax' | 'autopilot' | string | undefined
|
||||||
|
) => {
|
||||||
|
let modee = 0;
|
||||||
|
switch (mode) {
|
||||||
|
case 'taiko':
|
||||||
|
modee += Mode.TAIKO;
|
||||||
|
break;
|
||||||
|
case 'catch':
|
||||||
|
modee += Mode.CATCH;
|
||||||
|
break;
|
||||||
|
case 'mania':
|
||||||
|
modee += Mode.MANIA;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case 'relax':
|
||||||
|
modee += Type.RELAX;
|
||||||
|
break;
|
||||||
|
case 'autopilot':
|
||||||
|
modee += Type.AUTOPILOT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return modee;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getGamemodeName = (
|
||||||
|
mode: 'osu' | 'taiko' | 'catch' | 'mania' | string | undefined,
|
||||||
|
type: 'vanilla' | 'relax' | 'autopilot' | string | undefined
|
||||||
|
) => {
|
||||||
|
let modeStr = '';
|
||||||
|
switch (mode) {
|
||||||
|
case 'taiko':
|
||||||
|
modeStr += 'taiko!';
|
||||||
|
break;
|
||||||
|
case 'catch':
|
||||||
|
modeStr += 'catch!';
|
||||||
|
break;
|
||||||
|
case 'mania':
|
||||||
|
modeStr += 'mania!';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
modeStr += 'osu!';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case 'relax':
|
||||||
|
modeStr += 'rx';
|
||||||
|
break;
|
||||||
|
case 'autopilot':
|
||||||
|
modeStr += 'ap';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
modeStr += 'vn';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return modeStr;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getModeAndTypeFromGamemode = (gamemode: number) => {
|
||||||
|
let mode = Mode.OSU;
|
||||||
|
let type = Type.VANILLA;
|
||||||
|
const vanillaMode = gamemode % 4;
|
||||||
|
|
||||||
|
switch (vanillaMode) {
|
||||||
|
case Mode.TAIKO:
|
||||||
|
mode = Mode.TAIKO;
|
||||||
|
break;
|
||||||
|
case Mode.CATCH:
|
||||||
|
mode = Mode.CATCH;
|
||||||
|
break;
|
||||||
|
case Mode.MANIA:
|
||||||
|
mode = Mode.MANIA;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const typee = gamemode - vanillaMode;
|
||||||
|
switch (typee) {
|
||||||
|
case Type.RELAX:
|
||||||
|
type = Type.RELAX;
|
||||||
|
break;
|
||||||
|
case Type.AUTOPILOT:
|
||||||
|
type = Type.AUTOPILOT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
mode,
|
||||||
|
type,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const isValidGamemode = (gamemodeInt: number) => {
|
||||||
|
return validModeTypeCombinations.includes(gamemodeInt);
|
||||||
|
};
|
1
target
Submodule
1
target
Submodule
Submodule target added at 13feb373dc
29
tsconfig.json
Normal file
29
tsconfig.json
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
// Environment setup & latest features
|
||||||
|
"lib": ["ESNext"],
|
||||||
|
"target": "ESNext",
|
||||||
|
"module": "Preserve",
|
||||||
|
"moduleDetection": "force",
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"allowJs": true,
|
||||||
|
|
||||||
|
// Bundler mode
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"allowImportingTsExtensions": true,
|
||||||
|
"verbatimModuleSyntax": true,
|
||||||
|
"noEmit": true,
|
||||||
|
|
||||||
|
// Best practices
|
||||||
|
"strict": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"noUncheckedIndexedAccess": true,
|
||||||
|
"noImplicitOverride": true,
|
||||||
|
|
||||||
|
// Some stricter flags (disabled by default)
|
||||||
|
"noUnusedLocals": false,
|
||||||
|
"noUnusedParameters": false,
|
||||||
|
"noPropertyAccessFromIndexSignature": false
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user