├── .dockerignore ├── .eslintignore ├── .eslintrc.yml ├── .gitignore ├── .vscode └── launch.json ├── CMDLIST.md ├── Dockerfile ├── LICENSE ├── README.md ├── TODO.md ├── config ├── default.json ├── log_cli.json ├── log_cli_verbose.json ├── log_discord.json ├── log_mocha.json └── log_mocha_verbose.json ├── dist ├── IIrcClient.js ├── IIrcClient.js.map ├── Lobby.js ├── Lobby.js.map ├── Loggers.js ├── Loggers.js.map ├── Modes.js ├── Modes.js.map ├── Player.js ├── Player.js.map ├── TypedConfig.js ├── TypedConfig.js.map ├── cli │ ├── LogServer.js │ ├── LogServer.js.map │ ├── OahrBase.js │ ├── OahrBase.js.map │ ├── OahrCli.js │ ├── OahrCli.js.map │ ├── OahrHeadless.js │ ├── OahrHeadless.js.map │ ├── index.js │ └── index.js.map ├── discord │ ├── BotCommand.js │ ├── BotCommand.js.map │ ├── DiscordAppender.js │ ├── DiscordAppender.js.map │ ├── DiscordBot.js │ ├── DiscordBot.js.map │ ├── OahrDiscord.js │ ├── OahrDiscord.js.map │ ├── index.js │ └── index.js.map ├── dummies │ ├── DummyHistoryFetcher.js │ ├── DummyHistoryFetcher.js.map │ ├── DummyIrcClient.js │ ├── DummyIrcClient.js.map │ ├── DummyLobbyPlugin.js │ ├── DummyLobbyPlugin.js.map │ ├── FakeBeatmapFetcher.js │ └── FakeBeatmapFetcher.js.map ├── libs │ ├── ChatLimiter.js │ ├── ChatLimiter.js.map │ ├── DeferredAction.js │ ├── DeferredAction.js.map │ ├── OptionValidator.js │ ├── OptionValidator.js.map │ ├── TypedEvent.js │ ├── TypedEvent.js.map │ ├── irc.js │ └── irc.js.map ├── parsers │ ├── CommandParser.js │ ├── CommandParser.js.map │ ├── MpSettingsParser.js │ ├── MpSettingsParser.js.map │ ├── StatParser.js │ └── StatParser.js.map ├── plugins │ ├── AfkKicker.js │ ├── AfkKicker.js.map │ ├── AutoHostSelector.js │ ├── AutoHostSelector.js.map │ ├── AutoStartTimer.js │ ├── AutoStartTimer.js.map │ ├── CacheCleaner.js │ ├── CacheCleaner.js.map │ ├── HistoryLoader.js │ ├── HistoryLoader.js.map │ ├── HostSkipper.js │ ├── HostSkipper.js.map │ ├── InOutLogger.js │ ├── InOutLogger.js.map │ ├── LobbyKeeper.js │ ├── LobbyKeeper.js.map │ ├── LobbyPlugin.js │ ├── LobbyPlugin.js.map │ ├── LobbyTerminator.js │ ├── LobbyTerminator.js.map │ ├── MapChecker.js │ ├── MapChecker.js.map │ ├── MapRecaster.js │ ├── MapRecaster.js.map │ ├── MatchAborter.js │ ├── MatchAborter.js.map │ ├── MatchStarter.js │ ├── MatchStarter.js.map │ ├── MiscLoader.js │ ├── MiscLoader.js.map │ ├── ProfileFecher.js │ ├── ProfileFecher.js.map │ ├── VoteCounter.js │ ├── VoteCounter.js.map │ ├── WordCounter.js │ └── WordCounter.js.map ├── tests │ ├── AfkKickerTest.js │ ├── AfkKickerTest.js.map │ ├── AutoHostSelectorTest.js │ ├── AutoHostSelectorTest.js.map │ ├── AutoStartTimerTest.js │ ├── AutoStartTimerTest.js.map │ ├── BeatmapRepositoryTest.js │ ├── BeatmapRepositoryTest.js.map │ ├── CommandParserTest.js │ ├── CommandParserTest.js.map │ ├── DummyIrcClientTest.js │ ├── DummyIrcClientTest.js.map │ ├── HistoryRepositryTest.js │ ├── HistoryRepositryTest.js.map │ ├── HostSkipperTest.js │ ├── HostSkipperTest.js.map │ ├── InOutLoggerTest.js │ ├── InOutLoggerTest.js.map │ ├── IntegratedPluginsTest.js │ ├── IntegratedPluginsTest.js.map │ ├── LobbyKeeperTest.js │ ├── LobbyKeeperTest.js.map │ ├── LobbyTerminatorTest.js │ ├── LobbyTerminatorTest.js.map │ ├── LobbyTest.js │ ├── LobbyTest.js.map │ ├── MapCheckerTest.js │ ├── MapCheckerTest.js.map │ ├── MapRecasterTest.js │ ├── MapRecasterTest.js.map │ ├── MatchAborterTest.js │ ├── MatchAborterTest.js.map │ ├── MatchStarterTest.js │ ├── MatchStarterTest.js.map │ ├── MpSettingsParserTest.js │ ├── MpSettingsParserTest.js.map │ ├── StatParserTest.js │ ├── StatParserTest.js.map │ ├── TestUtils.js │ ├── TestUtils.js.map │ ├── TypedConfigTest.js │ ├── TypedConfigTest.js.map │ ├── WordCounterTest.js │ ├── WordCounterTest.js.map │ └── cases │ │ ├── MpSettingsCases.js │ │ └── MpSettingsCases.js.map ├── trials │ ├── AppendersTrial.js │ ├── AppendersTrial.js.map │ ├── BanchoIrcTrial.js │ ├── BanchoIrcTrial.js.map │ ├── DiscordTrial.js │ ├── DiscordTrial.js.map │ ├── HistryTrial.js │ ├── HistryTrial.js.map │ ├── IrcTrial.js │ ├── IrcTrial.js.map │ ├── LobbynameTrial.js │ ├── LobbynameTrial.js.map │ ├── TypedEventTrials.js │ ├── TypedEventTrials.js.map │ ├── WebApiTrial.js │ ├── WebApiTrial.js.map │ ├── WebServerTrial.js │ ├── WebServerTrial.js.map │ ├── cases │ │ └── history_84468237.json │ ├── index.js │ └── index.js.map ├── web │ ├── LogServer.js │ ├── LogServer.js.map │ ├── OahrWeb.js │ ├── OahrWeb.js.map │ ├── index.js │ ├── index.js.map │ └── statics │ │ ├── main.js │ │ └── main.js.map └── webapi │ ├── BeatmapRepository.js │ ├── BeatmapRepository.js.map │ ├── Beatmapsets.js │ ├── Beatmapsets.js.map │ ├── HistoryFetcher.js │ ├── HistoryFetcher.js.map │ ├── HistoryRepository.js │ ├── HistoryRepository.js.map │ ├── HistoryTypes.js │ ├── HistoryTypes.js.map │ ├── ProfileRepository.js │ ├── ProfileRepository.js.map │ ├── UserProfile.js │ ├── UserProfile.js.map │ ├── WebApiClient.js │ └── WebApiClient.js.map ├── memo.md ├── package-lock.json ├── package.json ├── src ├── IIrcClient.ts ├── Lobby.ts ├── Loggers.ts ├── Modes.ts ├── Player.ts ├── TypedConfig.ts ├── cli │ ├── LogServer.ts │ ├── OahrBase.ts │ ├── OahrCli.ts │ ├── OahrHeadless.ts │ └── index.ts ├── discord │ ├── BotCommand.ts │ ├── DiscordAppender.ts │ ├── DiscordBot.ts │ ├── OahrDiscord.ts │ └── index.ts ├── dummies │ ├── DummyHistoryFetcher.ts │ ├── DummyIrcClient.ts │ ├── DummyLobbyPlugin.ts │ └── FakeBeatmapFetcher.ts ├── libs │ ├── ChatLimiter.ts │ ├── DeferredAction.ts │ ├── OptionValidator.ts │ ├── TypedEvent.ts │ ├── irc.d.ts │ └── irc.js ├── parsers │ ├── CommandParser.ts │ ├── MpSettingsParser.ts │ └── StatParser.ts ├── plugins │ ├── AfkKicker.ts │ ├── AutoHostSelector.ts │ ├── AutoStartTimer.ts │ ├── CacheCleaner.ts │ ├── HistoryLoader.ts │ ├── HostSkipper.ts │ ├── InOutLogger.ts │ ├── LobbyKeeper.ts │ ├── LobbyPlugin.ts │ ├── LobbyTerminator.ts │ ├── MapChecker.ts │ ├── MapRecaster.ts │ ├── MatchAborter.ts │ ├── MatchStarter.ts │ ├── MiscLoader.ts │ ├── ProfileFecher.ts │ ├── VoteCounter.ts │ └── WordCounter.ts ├── tests │ ├── AfkKickerTest.ts │ ├── AutoHostSelectorTest.ts │ ├── AutoStartTimerTest.ts │ ├── BeatmapRepositoryTest.ts │ ├── CommandParserTest.ts │ ├── DummyIrcClientTest.ts │ ├── HistoryRepositryTest.ts │ ├── HostSkipperTest.ts │ ├── InOutLoggerTest.ts │ ├── IntegratedPluginsTest.ts │ ├── LobbyKeeperTest.ts │ ├── LobbyTerminatorTest.ts │ ├── LobbyTest.ts │ ├── MapCheckerTest.ts │ ├── MapRecasterTest.ts │ ├── MatchAborterTest.ts │ ├── MatchStarterTest.ts │ ├── MpSettingsParserTest.ts │ ├── StatParserTest.ts │ ├── TestUtils.ts │ ├── TypedConfigTest.ts │ ├── WordCounterTest.ts │ └── cases │ │ ├── 3182198.html │ │ ├── MpSettingsCases.ts │ │ ├── beatmap_1323207.json │ │ ├── beatmap_848345.json │ │ ├── beatmap_fruits_2578171.json │ │ ├── beatmapset_1323207.json │ │ ├── player_v1.nedb │ │ └── player_v2.nedb ├── trials │ ├── AppendersTrial.ts │ ├── BanchoIrcTrial.ts │ ├── DiscordTrial.ts │ ├── HistryTrial.ts │ ├── IrcTrial.ts │ ├── LobbynameTrial.ts │ ├── TypedEventTrials.ts │ ├── WebApiTrial.ts │ ├── WebServerTrial.ts │ ├── cases │ │ └── history_84468237.json │ ├── index.html │ └── index.ts ├── web │ ├── LogServer.ts │ ├── OahrWeb.ts │ ├── index.ts │ └── statics │ │ ├── index.html │ │ ├── main.css │ │ └── main.js └── webapi │ ├── BeatmapRepository.ts │ ├── Beatmapsets.ts │ ├── HistoryFetcher.ts │ ├── HistoryRepository.ts │ ├── HistoryTypes.ts │ ├── ProfileRepository.ts │ ├── UserProfile.ts │ └── WebApiClient.ts └── tsconfig.json /.dockerignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | data 3 | logs 4 | node_modules -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | dist 2 | irc.js 3 | irc.d.ts 4 | -------------------------------------------------------------------------------- /.eslintrc.yml: -------------------------------------------------------------------------------- 1 | --- 2 | env: 3 | browser: true 4 | es2021: true 5 | node: true 6 | extends: 7 | - eslint:recommended 8 | - plugin:@typescript-eslint/eslint-recommended 9 | - plugin:@typescript-eslint/recommended 10 | parser: "@typescript-eslint/parser" 11 | parserOptions: 12 | ecmaVersion: latest 13 | project: ./tsconfig.json 14 | sourceType: module 15 | plugins: 16 | - "@typescript-eslint" 17 | rules: 18 | "@typescript-eslint/ban-types": 19 | - error 20 | "@typescript-eslint/no-empty-function": 21 | - error 22 | "@typescript-eslint/no-empty-interface": 23 | - error 24 | "@typescript-eslint/no-explicit-any": 25 | - "off" 26 | "@typescript-eslint/no-inferrable-types": 27 | - "off" 28 | "@typescript-eslint/no-namespace": 29 | - "off" 30 | "@typescript-eslint/no-unused-vars": 31 | - "off" 32 | "@typescript-eslint/no-var-requires": 33 | - "off" 34 | brace-style: 35 | - "off" 36 | - 1tbs 37 | - allowSingleLine: true 38 | camelcase: 39 | - "off" 40 | comma-style: 41 | - error 42 | curly: 43 | - "off" 44 | - multi-line 45 | - consistent 46 | eqeqeq: 47 | - error 48 | indent: 49 | - error 50 | - 2 51 | - SwitchCase: 1 52 | no-case-declarations: 53 | - "off" 54 | no-console: 55 | - "off" 56 | no-constant-condition: 57 | - error 58 | - checkLoops: false 59 | no-control-regex: 60 | - "off" 61 | no-duplicate-imports: 62 | - error 63 | - includeExports: true 64 | no-empty: 65 | - error 66 | no-extra-parens: 67 | - "off" 68 | - all 69 | no-fallthrough: 70 | - error 71 | no-inline-comments: 72 | - "off" 73 | no-irregular-whitespace: 74 | - error 75 | no-multiple-empty-lines: 76 | - error 77 | no-trailing-spaces: 78 | - error 79 | no-undef: 80 | - "off" 81 | no-unused-vars: 82 | - "off" 83 | no-use-before-define: 84 | - "off" 85 | no-useless-catch: 86 | - "off" 87 | no-useless-concat: 88 | - error 89 | no-useless-escape: 90 | - error 91 | no-var: 92 | - error 93 | padded-blocks: 94 | - "off" 95 | prefer-const: 96 | - error 97 | prefer-template: 98 | - error 99 | quotes: 100 | - error 101 | - single 102 | semi: 103 | - error 104 | - always 105 | space-before-function-paren: 106 | - "off" 107 | template-curly-spacing: 108 | - error 109 | yoda: 110 | - error 111 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Optional REPL history 57 | .node_repl_history 58 | 59 | # Output of 'npm pack' 60 | *.tgz 61 | 62 | # Yarn Integrity file 63 | .yarn-integrity 64 | 65 | # dotenv environment variables file 66 | .env 67 | .env.test 68 | 69 | # parcel-bundler cache (https://parceljs.org/) 70 | .cache 71 | 72 | # next.js build output 73 | .next 74 | 75 | # nuxt.js build output 76 | .nuxt 77 | 78 | # vuepress build output 79 | .vuepress/dist 80 | 81 | # Serverless directories 82 | .serverless/ 83 | 84 | # FuseBox cache 85 | .fusebox/ 86 | 87 | # DynamoDB Local files 88 | .dynamodb/ 89 | 90 | # custom settings 91 | data/ 92 | irc-log/ 93 | config/development.json 94 | config/production.json 95 | config/local* 96 | nohup.out 97 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // IntelliSense を使用して利用可能な属性を学べます。 3 | // 既存の属性の説明をホバーして表示します。 4 | // 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | 8 | { 9 | "type": "node", 10 | "request": "launch", 11 | "name": "mocha", 12 | "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha", 13 | "args": [ 14 | "-r", 15 | "ts-node/register", 16 | "--timeout", 17 | "999999", 18 | "--colors", 19 | "${workspaceFolder}/src/tests/*Test.ts", 20 | ], 21 | "console": "integratedTerminal", 22 | "internalConsoleOptions": "neverOpen", 23 | "protocol": "inspector" 24 | }, 25 | 26 | { 27 | "type": "node", 28 | "request": "launch", 29 | "name": "cli debug", 30 | "runtimeArgs": ["--nolazy", "-r", "ts-node/register"], 31 | "args": [ 32 | "${workspaceFolder}/src/cli/index.ts", 33 | ], 34 | "sourceMaps": true, 35 | "env": { 36 | "NODE_ENV": "development", 37 | }, 38 | "console": "integratedTerminal", 39 | "internalConsoleOptions": "neverOpen", 40 | "protocol": "inspector" 41 | }, 42 | 43 | { 44 | "type": "node", 45 | "request": "launch", 46 | "name": "discord debug", 47 | "runtimeArgs": ["--nolazy", "-r", "ts-node/register"], 48 | "args": [ 49 | "${workspaceFolder}/src/discord/index.ts", 50 | ], 51 | "sourceMaps": true, 52 | "env": { 53 | "NODE_ENV": "development", 54 | }, 55 | "console": "integratedTerminal", 56 | "internalConsoleOptions": "neverOpen", 57 | "protocol": "inspector" 58 | }, 59 | 60 | { 61 | "type": "node", 62 | "request": "launch", 63 | "name": "nohup debug", 64 | "runtimeArgs": ["--nolazy", "-r", "ts-node/register"], 65 | "args": [ 66 | "${workspaceFolder}/src/cli/index.ts", 67 | "e", 68 | "54450418" 69 | ], 70 | "sourceMaps": true, 71 | "env": { 72 | "NODE_ENV": "development", 73 | }, 74 | "console": "integratedTerminal", 75 | "internalConsoleOptions": "neverOpen", 76 | "protocol": "inspector" 77 | }, 78 | 79 | { 80 | "type": "node", 81 | "request": "launch", 82 | "name": "trial debug", 83 | "runtimeArgs": ["--nolazy", "-r", "ts-node/register"], 84 | "args": [ 85 | "${workspaceFolder}/src/trials/index.ts", 86 | "e", 87 | "54450418" 88 | ], 89 | "sourceMaps": true, 90 | "env": { 91 | "NODE_ENV": "development", 92 | }, 93 | "console": "integratedTerminal", 94 | "internalConsoleOptions": "neverOpen", 95 | "protocol": "inspector" 96 | } 97 | ] 98 | } -------------------------------------------------------------------------------- /CMDLIST.md: -------------------------------------------------------------------------------- 1 | # osu-ahr 2 | irc bot for [osu!](https://osu.ppy.sh/home) multi lobby auto host rotation. 3 | The host rotation is managed by a list. Player is queued at the bottom when joining lobby or when his map pick was played. 4 | 5 | # Command List 6 | |for player|desc| 7 | |:--|:--| 8 | |`!queue`| Shows host queue.| 9 | |`!skip `| Triggers vote to skip current host.| 10 | |`!start`| Triggers vote start the match.| 11 | |`!abort`| Triggers vote abort the match. Use when the match is stuck.| 12 | |`!update`| Updates current selected map to the latest version. Use when host pick an outdated map.| 13 | |`!regulation`| Shows current regulation.| 14 | |`!rank`| Show player rank.| 15 | 16 | |for host|desc|ex| 17 | |:--|:--|:--| 18 | |`!skip`| Transfers host to next player.|| 19 | |`!start [secs]`| Begins start timer.|`!start 30`| 20 | |`!stop`| Stops current start timer.|| 21 | 22 | You can get the bot source code from [here](https://github.com/Meowhal/osu-ahr). 23 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:latest 2 | 3 | WORKDIR /opt/osuahr 4 | COPY package.json package-lock.json tsconfig.json ./ 5 | RUN npm install 6 | 7 | COPY src/ src/ 8 | RUN npm run build 9 | COPY config/ config/ 10 | EXPOSE 3115 11 | ENTRYPOINT /bin/bash -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Meowhal 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /config/log_cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "appenders": { 3 | "console": { 4 | "type": "console", 5 | "layout": { 6 | "type": "pattern", 7 | "pattern": "%[[%d{hh:mm:ss.SSS}][%p] %c -%] %m" 8 | } 9 | }, 10 | "console_f": { 11 | "type": "logLevelFilter", 12 | "level": "info", 13 | "appender": "console" 14 | }, 15 | "file_irc": { 16 | "type": "file", 17 | "maxLogSize": "2M", 18 | "filename": "logs/irc.log" 19 | }, 20 | "file_ahr_f": { 21 | "type": "logLevelFilter", 22 | "level": "info", 23 | "appender": "file_ahr" 24 | }, 25 | "file_ch": { 26 | "type": "multiFile", 27 | "base": "logs/channels", 28 | "property": "channel", 29 | "extension": ".log" 30 | }, 31 | "file_ch_f": { 32 | "type": "logLevelFilter", 33 | "level": "info", 34 | "appender": "file_ch" 35 | }, 36 | "file_chat": { 37 | "type": "multiFile", 38 | "base": "logs/channels", 39 | "property": "channel", 40 | "extension": "_chat.log" 41 | }, 42 | "file_chat_f": { 43 | "type": "logLevelFilter", 44 | "level": "info", 45 | "appender": "file_chat" 46 | }, 47 | "file_pm": { 48 | "type": "file", 49 | "filename": "logs/pm.log" 50 | }, 51 | "file_counter": { 52 | "type": "file", 53 | "filename": "logs/ct.log" 54 | }, 55 | "file_webapi": { 56 | "type": "file", 57 | "filename": "logs/webapi.log" 58 | } 59 | }, 60 | "categories": { 61 | "default": { 62 | "appenders": [ 63 | "console_f", 64 | "file_ch" 65 | ], 66 | "level": "all" 67 | }, 68 | "irc": { 69 | "appenders": [ 70 | "console_f", 71 | "file_irc" 72 | ], 73 | "level": "all" 74 | }, 75 | "chat": { 76 | "appenders": [ 77 | "console_f", 78 | "file_chat" 79 | ], 80 | "level": "all" 81 | }, 82 | "inout": { 83 | "appenders": [ 84 | "console", 85 | "file_chat" 86 | ], 87 | "level": "all" 88 | }, 89 | "pm": { 90 | "appenders": [ 91 | "console_f", 92 | "file_pm" 93 | ], 94 | "level": "all" 95 | }, 96 | "wcounter": { 97 | "appenders": [ 98 | "file_counter" 99 | ], 100 | "level": "off" 101 | }, 102 | "webapi": { 103 | "appenders": [ 104 | "file_webapi" 105 | ], 106 | "level": "off" 107 | } 108 | } 109 | } -------------------------------------------------------------------------------- /config/log_cli_verbose.json: -------------------------------------------------------------------------------- 1 | { 2 | "appenders": { 3 | "console": { 4 | "type": "console", 5 | "layout": { 6 | "type": "pattern", 7 | "pattern": "%[[%d{hh:mm:ss.SSS}][%p] %c -%] %m" 8 | } 9 | }, 10 | "console_f": { 11 | "type": "logLevelFilter", 12 | "level": "info", 13 | "appender": "console" 14 | }, 15 | "file_irc": { 16 | "type": "file", 17 | "maxLogSize": "2M", 18 | "filename": "logs/irc.log" 19 | }, 20 | "file_ahr_f": { 21 | "type": "logLevelFilter", 22 | "level": "info", 23 | "appender": "file_ahr" 24 | }, 25 | "file_ch": { 26 | "type": "multiFile", 27 | "base": "logs/channels", 28 | "property": "channel", 29 | "extension": ".log" 30 | }, 31 | "file_ch_f": { 32 | "type": "logLevelFilter", 33 | "level": "info", 34 | "appender": "file_ch" 35 | }, 36 | "file_chat": { 37 | "type": "multiFile", 38 | "base": "logs/channels", 39 | "property": "channel", 40 | "extension": "_chat.log" 41 | }, 42 | "file_chat_f": { 43 | "type": "logLevelFilter", 44 | "level": "info", 45 | "appender": "file_chat" 46 | }, 47 | "file_pm": { 48 | "type": "file", 49 | "filename": "logs/pm.log" 50 | }, 51 | "file_counter": { 52 | "type": "file", 53 | "filename": "logs/ct.log" 54 | }, 55 | "file_webapi": { 56 | "type": "file", 57 | "filename": "logs/webapi.log" 58 | } 59 | }, 60 | "categories": { 61 | "default": { 62 | "appenders": [ 63 | "console_f", 64 | "file_ch" 65 | ], 66 | "level": "all" 67 | }, 68 | "irc": { 69 | "appenders": [ 70 | "console_f", 71 | "file_irc" 72 | ], 73 | "level": "all" 74 | }, 75 | "chat": { 76 | "appenders": [ 77 | "console_f", 78 | "file_ch", 79 | "file_chat" 80 | ], 81 | "level": "all" 82 | }, 83 | "inout": { 84 | "appenders": [ 85 | "console", 86 | "file_ch", 87 | "file_chat" 88 | ], 89 | "level": "all" 90 | }, 91 | "pm": { 92 | "appenders": [ 93 | "console_f", 94 | "file_pm" 95 | ], 96 | "level": "all" 97 | }, 98 | "wcounter": { 99 | "appenders": [ 100 | "file_counter" 101 | ], 102 | "level": "all" 103 | }, 104 | "webapi": { 105 | "appenders": [ 106 | "file_webapi" 107 | ], 108 | "level": "all" 109 | } 110 | } 111 | } -------------------------------------------------------------------------------- /config/log_mocha.json: -------------------------------------------------------------------------------- 1 | { 2 | "appenders": { 3 | "console": { 4 | "type": "console" 5 | } 6 | }, 7 | "categories": { 8 | "default": { 9 | "appenders": [ 10 | "console" 11 | ], 12 | "level": "off" 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /config/log_mocha_verbose.json: -------------------------------------------------------------------------------- 1 | { 2 | "appenders": { 3 | "console": { 4 | "type": "console" 5 | } 6 | }, 7 | "categories": { 8 | "default": { 9 | "appenders": [ 10 | "console" 11 | ], 12 | "level": "trace" 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /dist/IIrcClient.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.logPrivateMessage = exports.logIrcEvent = void 0; 4 | const StatParser_1 = require("./parsers/StatParser"); 5 | const Loggers_1 = require("./Loggers"); 6 | const ircLogger = (0, Loggers_1.getLogger)('irc'); 7 | const pmLogger = (0, Loggers_1.getLogger)('pm'); 8 | function logIrcEvent(client) { 9 | client.on('error', function (message) { 10 | ircLogger.error(`@NodeIRC#error\n${message instanceof Error ? `${message.message}\n${message.stack}\n` : ''}${message instanceof Object && JSON.stringify(message) !== '{}' ? `${JSON.stringify(message, null, 2)}\n` : ''}message =`, message); 11 | }); 12 | client.on('registered', function (message) { 13 | const args = message.args; 14 | ircLogger.debug(`@NodeIRC#registered ${args?.join(', ')}`); 15 | }); 16 | client.on('message', function (from, to, message) { 17 | ircLogger.debug(`@NodeIRC#message ${from} => ${to}: ${message}`); 18 | }); 19 | client.on('pm', function (nick, message) { 20 | ircLogger.debug(`@NodeIRC#pm ${nick}: ${message}`); 21 | }); 22 | client.on('join', function (channel, who) { 23 | ircLogger.debug(`@NodeIRC#join ${who} has joined ${channel}`); 24 | }); 25 | client.on('part', function (channel, who, reason) { 26 | ircLogger.debug(`@NodeIRC#part ${who} has left ${channel}: ${reason}`); 27 | }); 28 | client.on('kick', function (channel, who, by, reason) { 29 | ircLogger.debug(`@NodeIRC#kick ${who} was kicked from ${channel} by ${by}: ${reason}`); 30 | }); 31 | client.on('invite', (channel, from) => { 32 | ircLogger.debug(`@NodeIRC#invite ${from} invited you to ${channel}`); 33 | }); 34 | client.on('notice', function (from, to, message) { 35 | ircLogger.debug(`@NodeIRC#notice ${from} => ${to}: ${message}`); 36 | }); 37 | client.on('action', function (from, to, text, message) { 38 | ircLogger.debug(`@NodeIRC#action ${from} => ${to}: ${text}`); 39 | }); 40 | client.on('selfMessage', (target, toSend) => { 41 | ircLogger.debug(`@NodeIRC#selfMessage Bot => ${target}: ${toSend}`); 42 | }); 43 | } 44 | exports.logIrcEvent = logIrcEvent; 45 | function logPrivateMessage(client) { 46 | client.on('message', (from, to, message) => { 47 | if (to === client.nick) { 48 | if ((0, StatParser_1.IsStatResponse)(message)) { 49 | pmLogger.trace(`@NodeIRC#message PM: ${from} -> ${message}`); 50 | } 51 | else { 52 | pmLogger.info(`@NodeIRC#message PM: ${from} -> ${message}`); 53 | } 54 | } 55 | }); 56 | } 57 | exports.logPrivateMessage = logPrivateMessage; 58 | //# sourceMappingURL=IIrcClient.js.map -------------------------------------------------------------------------------- /dist/IIrcClient.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"IIrcClient.js","sourceRoot":"","sources":["../src/IIrcClient.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /dist/Loggers.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | exports.getLogger = void 0; 7 | const log4js_1 = __importDefault(require("log4js")); 8 | function selectConfigPath() { 9 | const proc = process.argv[0]; 10 | const exeFile = process.argv[1]; 11 | const hasVerboseFlag = process.argv.some(v => v === '--verbose' || v === '-v'); 12 | if (exeFile.includes('discord')) { 13 | return './config/log_discord.json'; 14 | } 15 | else if (exeFile.includes('mocha')) { 16 | if (hasVerboseFlag) { 17 | return './config/log_mocha_verbose.json'; 18 | } 19 | else { 20 | return './config/log_mocha.json'; 21 | } 22 | } 23 | else if (proc.includes('ts-node') || hasVerboseFlag) { 24 | return './config/log_cli_verbose.json'; 25 | } 26 | else { 27 | return './config/log_cli.json'; 28 | } 29 | } 30 | const path = selectConfigPath(); 31 | console.log(`Loading log4js configuration from ${path}`); 32 | log4js_1.default.configure(path); 33 | function getLogger(category) { 34 | const l = log4js_1.default.getLogger(category); 35 | l.addContext('channel', 'ahr'); // set default channel 36 | return l; 37 | } 38 | exports.getLogger = getLogger; 39 | //# sourceMappingURL=Loggers.js.map -------------------------------------------------------------------------------- /dist/Loggers.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"Loggers.js","sourceRoot":"","sources":["../src/Loggers.ts"],"names":[],"mappings":";;;;;;AAAA,oDAA4B;AAG5B,SAAS,gBAAgB;IACvB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC7B,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAChC,MAAM,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,WAAW,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC;IAE/E,IAAI,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE;QAC/B,OAAO,2BAA2B,CAAC;KACpC;SAAM,IAAI,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE;QACpC,IAAI,cAAc,EAAE;YAClB,OAAO,iCAAiC,CAAC;SAC1C;aAAM;YACL,OAAO,yBAAyB,CAAC;SAClC;KACF;SAAM,IAAI,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,cAAc,EAAE;QACrD,OAAO,+BAA+B,CAAC;KACxC;SAAM;QACL,OAAO,uBAAuB,CAAC;KAChC;AACH,CAAC;AAED,MAAM,IAAI,GAAG,gBAAgB,EAAE,CAAC;AAChC,OAAO,CAAC,GAAG,CAAC,qCAAqC,IAAI,EAAE,CAAC,CAAC;AACzD,gBAAM,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;AAEvB,SAAgB,SAAS,CAAC,QAA6B;IACrD,MAAM,CAAC,GAAG,gBAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IACrC,CAAC,CAAC,UAAU,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC,sBAAsB;IACtD,OAAO,CAAC,CAAC;AACX,CAAC;AAJD,8BAIC"} -------------------------------------------------------------------------------- /dist/Player.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.revealUserName = exports.disguiseUserName = exports.escapeUserName = exports.MpStatuses = exports.Teams = exports.Roles = exports.Player = void 0; 4 | class Player { 5 | constructor(name) { 6 | this.id = 0; 7 | this.role = Roles.Player; 8 | this.team = Teams.None; // いつteammodeに変更されたか検知する方法がないので、正確な情報ではない 9 | this.slot = 0; 10 | this.mpstatus = MpStatuses.None; 11 | this.laststat = null; 12 | this.profile = null; 13 | this.name = name; 14 | this.escaped_name = escapeUserName(name); 15 | } 16 | is(r) { 17 | return (this.role & r) !== 0; 18 | } 19 | get isPlayer() { 20 | return this.is(Roles.Player); 21 | } 22 | get isHost() { 23 | return this.is(Roles.Host); 24 | } 25 | get isAuthorized() { 26 | return this.is(Roles.Authorized); 27 | } 28 | get isReferee() { 29 | return this.is(Roles.Referee); 30 | } 31 | get isCreator() { 32 | return this.is(Roles.Creator); 33 | } 34 | setRole(r) { 35 | this.role |= r; 36 | } 37 | removeRole(r) { 38 | this.role &= ~r; 39 | } 40 | toString() { 41 | return `Player{id:${this.name}, slot:${this.slot}, role:${this.role}}`; 42 | } 43 | } 44 | exports.Player = Player; 45 | var Roles; 46 | (function (Roles) { 47 | Roles[Roles["None"] = 0] = "None"; 48 | Roles[Roles["Player"] = 1] = "Player"; 49 | Roles[Roles["Host"] = 2] = "Host"; 50 | Roles[Roles["Authorized"] = 4] = "Authorized"; 51 | Roles[Roles["Referee"] = 8] = "Referee"; 52 | Roles[Roles["Creator"] = 16] = "Creator"; 53 | })(Roles = exports.Roles || (exports.Roles = {})); 54 | var Teams; 55 | (function (Teams) { 56 | Teams[Teams["None"] = 0] = "None"; 57 | Teams[Teams["Blue"] = 1] = "Blue"; 58 | Teams[Teams["Red"] = 2] = "Red"; 59 | })(Teams = exports.Teams || (exports.Teams = {})); 60 | var MpStatuses; 61 | (function (MpStatuses) { 62 | MpStatuses[MpStatuses["None"] = 0] = "None"; 63 | MpStatuses[MpStatuses["InLobby"] = 1] = "InLobby"; 64 | MpStatuses[MpStatuses["Playing"] = 2] = "Playing"; 65 | MpStatuses[MpStatuses["Finished"] = 3] = "Finished"; 66 | })(MpStatuses = exports.MpStatuses || (exports.MpStatuses = {})); 67 | /** 68 | * Nameの表記ゆれを統一する 69 | * @param name 70 | */ 71 | function escapeUserName(name) { 72 | return name.toLowerCase().replace(/ /g, '_'); 73 | } 74 | exports.escapeUserName = escapeUserName; 75 | /** 76 | * UserNameを表示するときhighlightされないように名前を変更する 77 | * @param username 78 | */ 79 | function disguiseUserName(username) { 80 | return `${username[0]}\u{200B}${username.substring(1)}`; 81 | } 82 | exports.disguiseUserName = disguiseUserName; 83 | /** 84 | * disguiseUserNameで変更を加えた文字列をもとに戻す 85 | * @param disguisedName 86 | */ 87 | function revealUserName(disguisedName) { 88 | return disguisedName.replace(/\u200B/g, ''); 89 | } 90 | exports.revealUserName = revealUserName; 91 | //# sourceMappingURL=Player.js.map -------------------------------------------------------------------------------- /dist/Player.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"Player.js","sourceRoot":"","sources":["../src/Player.ts"],"names":[],"mappings":";;;AAGA,MAAa,MAAM;IAWjB,YAAY,IAAY;QAVxB,OAAE,GAAW,CAAC,CAAC;QAGf,SAAI,GAAU,KAAK,CAAC,MAAM,CAAC;QAC3B,SAAI,GAAU,KAAK,CAAC,IAAI,CAAC,CAAC,yCAAyC;QACnE,SAAI,GAAW,CAAC,CAAC;QACjB,aAAQ,GAAe,UAAU,CAAC,IAAI,CAAC;QACvC,aAAQ,GAAsB,IAAI,CAAC;QACnC,YAAO,GAAuB,IAAI,CAAC;QAGjC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,YAAY,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;IAC3C,CAAC;IACD,EAAE,CAAC,CAAQ;QACT,OAAO,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;IAC/B,CAAC;IACD,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC/B,CAAC;IACD,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;IACD,IAAI,YAAY;QACd,OAAO,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACnC,CAAC;IACD,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAChC,CAAC;IACD,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAChC,CAAC;IACD,OAAO,CAAC,CAAQ;QACd,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC;IACjB,CAAC;IACD,UAAU,CAAC,CAAQ;QACjB,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,QAAQ;QACN,OAAO,aAAa,IAAI,CAAC,IAAI,UAAU,IAAI,CAAC,IAAI,UAAU,IAAI,CAAC,IAAI,GAAG,CAAC;IACzE,CAAC;CACF;AA1CD,wBA0CC;AAED,IAAY,KAOX;AAPD,WAAY,KAAK;IACf,iCAAQ,CAAA;IACR,qCAAU,CAAA;IACV,iCAAQ,CAAA;IACR,6CAAc,CAAA;IACd,uCAAW,CAAA;IACX,wCAAY,CAAA;AACd,CAAC,EAPW,KAAK,GAAL,aAAK,KAAL,aAAK,QAOhB;AAED,IAAY,KAIX;AAJD,WAAY,KAAK;IACf,iCAAI,CAAA;IACJ,iCAAI,CAAA;IACJ,+BAAG,CAAA;AACL,CAAC,EAJW,KAAK,GAAL,aAAK,KAAL,aAAK,QAIhB;AAED,IAAY,UAKX;AALD,WAAY,UAAU;IACpB,2CAAI,CAAA;IACJ,iDAAO,CAAA;IACP,iDAAO,CAAA;IACP,mDAAQ,CAAA;AACV,CAAC,EALW,UAAU,GAAV,kBAAU,KAAV,kBAAU,QAKrB;AAED;;;GAGG;AACH,SAAgB,cAAc,CAAC,IAAY;IACzC,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;AAC/C,CAAC;AAFD,wCAEC;AAED;;;GAGG;AACH,SAAgB,gBAAgB,CAAC,QAAgB;IAC/C,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAC,WAAW,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;AAC1D,CAAC;AAFD,4CAEC;AAED;;;GAGG;AACH,SAAgB,cAAc,CAAC,aAAqB;IAClD,OAAO,aAAa,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;AAC9C,CAAC;AAFD,wCAEC"} -------------------------------------------------------------------------------- /dist/cli/LogServer.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | const LogServer_1 = require("../web/LogServer"); 7 | const config_1 = __importDefault(require("config")); 8 | const options = config_1.default.get('LogServer'); 9 | (0, LogServer_1.startLogServer)(options.port); 10 | //# sourceMappingURL=LogServer.js.map -------------------------------------------------------------------------------- /dist/cli/LogServer.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"LogServer.js","sourceRoot":"","sources":["../../src/cli/LogServer.ts"],"names":[],"mappings":";;;;;AAAA,gDAAkD;AAClD,oDAA4B;AAM5B,MAAM,OAAO,GAAG,gBAAM,CAAC,GAAG,CAAkB,WAAW,CAAC,CAAC;AAEzD,IAAA,0BAAc,EAAC,OAAO,CAAC,IAAI,CAAC,CAAC"} -------------------------------------------------------------------------------- /dist/cli/OahrBase.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"OahrBase.js","sourceRoot":"","sources":["../../src/cli/OahrBase.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /dist/cli/OahrHeadless.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.OahrHeadless = void 0; 4 | const Loggers_1 = require("../Loggers"); 5 | const OahrBase_1 = require("./OahrBase"); 6 | const logger = (0, Loggers_1.getLogger)('hl'); 7 | class OahrHeadless extends OahrBase_1.OahrBase { 8 | constructor(client) { 9 | super(client); 10 | client.once('part', () => { 11 | logger.info('Part event detected. Closing...'); 12 | process.exit(0); 13 | }); 14 | } 15 | start(command, arg) { 16 | try { 17 | switch (command) { 18 | case 'm': 19 | this.makeLobbyAsync(arg); 20 | break; 21 | case 'e': 22 | this.enterLobbyAsync(arg); 23 | break; 24 | default: 25 | process.exit(1); 26 | } 27 | } 28 | catch (e) { 29 | logger.error(`@OahrHeadless#start\n${e}`); 30 | process.exit(1); 31 | } 32 | } 33 | } 34 | exports.OahrHeadless = OahrHeadless; 35 | //# sourceMappingURL=OahrHeadless.js.map -------------------------------------------------------------------------------- /dist/cli/OahrHeadless.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"OahrHeadless.js","sourceRoot":"","sources":["../../src/cli/OahrHeadless.ts"],"names":[],"mappings":";;;AACA,wCAAuC;AACvC,yCAAsC;AAEtC,MAAM,MAAM,GAAG,IAAA,mBAAS,EAAC,IAAI,CAAC,CAAC;AAE/B,MAAa,YAAa,SAAQ,mBAAQ;IAExC,YAAY,MAAkB;QAC5B,KAAK,CAAC,MAAM,CAAC,CAAC;QACd,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE;YACvB,MAAM,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;YAC/C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,OAAe,EAAE,GAAW;QAChC,IAAI;YACF,QAAQ,OAAO,EAAE;gBACf,KAAK,GAAG;oBACN,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC;oBACzB,MAAM;gBACR,KAAK,GAAG;oBACN,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;oBAC1B,MAAM;gBACR;oBACE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;aACnB;SACF;QAAC,OAAO,CAAM,EAAE;YACf,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,EAAE,CAAC,CAAC;YAC1C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;SACjB;IAEH,CAAC;CACF;AA5BD,oCA4BC"} -------------------------------------------------------------------------------- /dist/cli/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 3 | if (k2 === undefined) k2 = k; 4 | Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); 5 | }) : (function(o, m, k, k2) { 6 | if (k2 === undefined) k2 = k; 7 | o[k2] = m[k]; 8 | })); 9 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { 10 | Object.defineProperty(o, "default", { enumerable: true, value: v }); 11 | }) : function(o, v) { 12 | o["default"] = v; 13 | }); 14 | var __importStar = (this && this.__importStar) || function (mod) { 15 | if (mod && mod.__esModule) return mod; 16 | var result = {}; 17 | if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); 18 | __setModuleDefault(result, mod); 19 | return result; 20 | }; 21 | Object.defineProperty(exports, "__esModule", { value: true }); 22 | const Loggers_1 = require("../Loggers"); 23 | const irc = __importStar(require("../libs/irc")); 24 | const OahrCli_1 = require("./OahrCli"); 25 | const OahrHeadless_1 = require("./OahrHeadless"); 26 | const IIrcClient_1 = require("../IIrcClient"); 27 | const TypedConfig_1 = require("../TypedConfig"); 28 | const ChatLimiter_1 = require("../libs/ChatLimiter"); 29 | const logger = (0, Loggers_1.getLogger)('pre'); 30 | logger.info('Starting up...'); 31 | try { 32 | TypedConfig_1.CONFIG_OPTION.USE_ENV = true; 33 | const c = (0, TypedConfig_1.getIrcConfig)(); 34 | if (c.nick === 'your account id' || c.opt.password === 'you can get password from \'https://osu.ppy.sh/p/irc\'') { 35 | logger.error('You must enter your account ID and IRC password in the config file.'); 36 | logger.error('You can get your IRC password in \'https://osu.ppy.sh/p/irc\' '); 37 | logger.error('Copy config/default.json to config/local.json, and then enter your account ID and IRC password.'); 38 | process.exit(1); 39 | } 40 | const client = new irc.Client(c.server, c.nick, c.opt); 41 | client.on('error', err => { 42 | if (err.command === 'err_passwdmismatch') { 43 | logger.error(`${err.command}: ${err.args.join(' ')}`); 44 | logger.error('Check your account ID and IRC password.'); 45 | process.exit(1); 46 | } 47 | }); 48 | (0, ChatLimiter_1.applySpeedLimit)(client, 10, 5000); 49 | (0, IIrcClient_1.logIrcEvent)(client); 50 | (0, IIrcClient_1.logPrivateMessage)(client); 51 | if (process.argv.length > 2) { 52 | const command = process.argv[2]; 53 | const oahr = new OahrHeadless_1.OahrHeadless(client); 54 | const arg = process.argv.slice(3).join(' '); 55 | oahr.start(command, arg); 56 | } 57 | else { 58 | const oahr = new OahrCli_1.OahrCli(client); 59 | oahr.start(null); 60 | } 61 | } 62 | catch (e) { 63 | logger.error(`@cli-index\n${e}`); 64 | process.exit(1); 65 | } 66 | //# sourceMappingURL=index.js.map -------------------------------------------------------------------------------- /dist/cli/index.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA,wCAAuC;AAEvC,iDAAmC;AACnC,uCAAoC;AACpC,iDAA8C;AAC9C,8CAA+D;AAC/D,gDAA6D;AAC7D,qDAAsD;AAEtD,MAAM,MAAM,GAAG,IAAA,mBAAS,EAAC,KAAK,CAAC,CAAC;AAChC,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;AAE9B,IAAI;IACF,2BAAa,CAAC,OAAO,GAAG,IAAI,CAAC;IAC7B,MAAM,CAAC,GAAG,IAAA,0BAAY,GAAE,CAAC;IACzB,IAAI,CAAC,CAAC,IAAI,KAAK,iBAAiB,IAAI,CAAC,CAAC,GAAG,CAAC,QAAQ,KAAK,wDAAwD,EAAE;QAC/G,MAAM,CAAC,KAAK,CAAC,qEAAqE,CAAC,CAAC;QACpF,MAAM,CAAC,KAAK,CAAC,gEAAgE,CAAC,CAAC;QAC/E,MAAM,CAAC,KAAK,CAAC,iGAAiG,CAAC,CAAC;QAChH,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;KACjB;IAED,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;IACvD,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,EAAE;QACvB,IAAI,GAAG,CAAC,OAAO,KAAK,oBAAoB,EAAE;YACxC,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,OAAO,KAAK,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACtD,MAAM,CAAC,KAAK,CAAC,yCAAyC,CAAC,CAAC;YACxD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;SACjB;IACH,CAAC,CAAC,CAAC;IAEH,IAAA,6BAAe,EAAC,MAAM,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;IAElC,IAAA,wBAAW,EAAC,MAAM,CAAC,CAAC;IACpB,IAAA,8BAAiB,EAAC,MAAM,CAAC,CAAC;IAE1B,IAAI,OAAO,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE;QAC3B,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAChC,MAAM,IAAI,GAAG,IAAI,2BAAY,CAAC,MAAM,CAAC,CAAC;QACtC,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC5C,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;KAC1B;SAAM;QACL,MAAM,IAAI,GAAG,IAAI,iBAAO,CAAC,MAAM,CAAC,CAAC;QACjC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;KAClB;CACF;AAAC,OAAO,CAAM,EAAE;IACf,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;IACjC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;CACjB"} -------------------------------------------------------------------------------- /dist/discord/BotCommand.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"BotCommand.js","sourceRoot":"","sources":["../../src/discord/BotCommand.ts"],"names":[],"mappings":";;;AAEA,+DAA+D;AAClD,QAAA,WAAW,GAA6B;IACnD;QACE,IAAI,EAAE,MAAM;QACZ,WAAW,EAAE,0BAA0B;QACvC,iBAAiB,EAAE,KAAK;QACxB,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,CAAC;gBACP,IAAI,EAAE,YAAY;gBAClB,WAAW,EAAE,8EAA8E;gBAC3F,QAAQ,EAAE,IAAI;aACf;SACF;KACF;IACD;QACE,IAAI,EAAE,OAAO;QACb,WAAW,EAAE,gBAAgB;QAC7B,iBAAiB,EAAE,KAAK;QACxB,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,CAAC;gBACP,IAAI,EAAE,UAAU;gBAChB,WAAW,EAAE,gDAAgD;gBAC7D,QAAQ,EAAE,KAAK;aAChB;SACF;KACF;IACD;QACE,IAAI,EAAE,MAAM;QACZ,WAAW,EAAE,6BAA6B;QAC1C,iBAAiB,EAAE,KAAK;QACxB,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,CAAC;gBACP,IAAI,EAAE,UAAU;gBAChB,WAAW,EAAE,4DAA4D;gBACzE,QAAQ,EAAE,KAAK;aAChB;SACF;KACF;IACD;QACE,IAAI,EAAE,KAAK;QACX,WAAW,EAAE,4BAA4B;QACzC,iBAAiB,EAAE,KAAK;QACxB,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,CAAC;gBACP,IAAI,EAAE,SAAS;gBACf,WAAW,EAAE,sBAAsB;gBACnC,QAAQ,EAAE,IAAI;aACf;YACD;gBACE,IAAI,EAAE,CAAC;gBACP,IAAI,EAAE,UAAU;gBAChB,WAAW,EAAE,0DAA0D;gBACvE,QAAQ,EAAE,KAAK;aAChB;SACF;KACF;IACD;QACE,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,uCAAuC;QACpD,iBAAiB,EAAE,KAAK;QACxB,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,CAAC;gBACP,IAAI,EAAE,SAAS;gBACf,WAAW,EAAE,oCAAoC;gBACjD,QAAQ,EAAE,IAAI;aACf;YACD;gBACE,IAAI,EAAE,CAAC;gBACP,IAAI,EAAE,MAAM;gBACZ,WAAW,EAAE,iCAAiC;gBAC9C,QAAQ,EAAE,IAAI;aACf;YACD;gBACE,IAAI,EAAE,CAAC;gBACP,IAAI,EAAE,OAAO;gBACb,WAAW,EAAE,qCAAqC;gBAClD,QAAQ,EAAE,IAAI;aACf;SACF;KACF;IACD;QACE,IAAI,EAAE,OAAO;QACb,WAAW,EAAE,gBAAgB;QAC7B,iBAAiB,EAAE,KAAK;QACxB,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,CAAC;gBACP,IAAI,EAAE,UAAU;gBAChB,WAAW,EAAE,8CAA8C;gBAC3D,QAAQ,EAAE,KAAK;aAChB;SACF;KACF;IACD;QACE,IAAI,EAAE,MAAM;QACZ,WAAW,EAAE,wBAAwB;QACrC,iBAAiB,EAAE,KAAK;QACxB,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,CAAC;gBACP,IAAI,EAAE,UAAU;gBAChB,WAAW,EAAE,sDAAsD;gBACnE,QAAQ,EAAE,KAAK;aAChB;SACF;KACF;CACF,CAAC"} -------------------------------------------------------------------------------- /dist/discord/DiscordAppender.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"DiscordAppender.js","sourceRoot":"","sources":["../../src/discord/DiscordAppender.ts"],"names":[],"mappings":";;;;;;AAAA,2CAAqG;AACrG,oDAA4B;AAC5B,wCAAuC;AAGvC,IAAI,aAAiC,CAAC;AACtC,IAAI,IAAsC,CAAC;AAE3C,SAAgB,UAAU,CAAC,MAAc,EAAE,KAAuC;IAChF,aAAa,GAAG,MAAM,CAAC;IACvB,IAAI,GAAG,KAAK,CAAC;AACf,CAAC;AAHD,gCAGC;AAED,MAAM,SAAS,GAAuC;IACpD,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,oBAAoB;IAC/D,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IAChD,SAAS,EAAE,qBAAqB,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ;CACnE,CAAC;AAEF,SAAgB,SAAS,CAAC,MAAW,EAAE,OAAY;IACjD,IAAI,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IACpC,IAAI,MAAM,CAAC,MAAM,EAAE;QACjB,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;KAC5D;IAED,gCAAgC;IAChC;;;;;;yDAMqD;IACrD,OAAO,KAAK,EAAE,YAAiC,EAAE,EAAE;QACjD,IAAI,aAAa,EAAE;YACjB,IAAI;gBACF,MAAM,EAAE,GAAG,iBAAiB,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;gBACnD,IAAI,EAAE,EAAE;oBACN,MAAM,GAAG,GAAG,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,cAAc,CAAC,CAAC;oBACxD,MAAM,OAAO,GAAG,aAAa,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC;oBACjD,MAAM,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;iBACxB;aACF;YAAC,OAAO,CAAM,EAAE;gBACf,MAAM,MAAM,GAAG,IAAA,mBAAS,EAAC,aAAa,CAAC,CAAC;gBACxC,MAAM,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;gBACrE,MAAM,GAAG,GAAG,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;gBACjD,IAAI,GAAG,EAAE;oBACP,GAAG,CAAC,eAAe,EAAE,CAAC;iBACvB;aACF;SACF;IACH,CAAC,CAAC;AACJ,CAAC;AAjCD,8BAiCC;AAED,SAAS,iBAAiB,CAAC,OAAY;IACrC,IAAI,aAAa,IAAI,OAAO,IAAI,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,SAAS,EAAE;QACxF,MAAM,KAAK,GAAG,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAC9D,MAAM,EAAE,GAAG,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QACxD,IAAI,EAAE,IAAI,EAAE,CAAC,MAAM,EAAE,EAAE;YACrB,OAAO,EAAE,CAAC;SACX;KACF;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,aAAa,CAAC,EAAuB,EAAE,GAAW;IACzD,MAAM,KAAK,GAAG,SAAS,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,SAAS,CAAC;IACtD,QAAQ,EAAE,CAAC,YAAY,EAAE;QACvB,KAAK,MAAM;YACT,IAAI,EAAE,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE;gBACxB,OAAO,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;aAC7C;iBAAM;gBACL,OAAO,KAAK,GAAG,EAAE,CAAC;aACnB;QACH,KAAK,OAAO;YACV,MAAM,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC;YACpD,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAC;YACpD,IAAI,GAAG,IAAI,IAAI,EAAE;gBACf,IAAI,GAAG,GAAG,EAAE,CAAC;gBACb,IAAI,GAAG,EAAE;oBACP,GAAG,IAAI,UAAU,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;iBAC5B;gBACD,IAAI,IAAI,EAAE;oBACR,GAAG,IAAI,WAAW,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;iBAC7B;gBACD,OAAO,EAAE,MAAM,EAAE,CAAC,IAAI,yBAAY,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;aAC7E;YACD,MAAM;KACT;IACD,IAAI,gBAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,EAAE;QAC9C,OAAO,EAAE,MAAM,EAAE,CAAC,IAAI,yBAAY,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;KAC7E;IACD,OAAO,KAAK,EAAE,CAAC,YAAY,MAAM,GAAG,EAAE,CAAC;AACzC,CAAC"} -------------------------------------------------------------------------------- /dist/discord/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 3 | if (k2 === undefined) k2 = k; 4 | Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); 5 | }) : (function(o, m, k, k2) { 6 | if (k2 === undefined) k2 = k; 7 | o[k2] = m[k]; 8 | })); 9 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { 10 | Object.defineProperty(o, "default", { enumerable: true, value: v }); 11 | }) : function(o, v) { 12 | o["default"] = v; 13 | }); 14 | var __importStar = (this && this.__importStar) || function (mod) { 15 | if (mod && mod.__esModule) return mod; 16 | var result = {}; 17 | if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); 18 | __setModuleDefault(result, mod); 19 | return result; 20 | }; 21 | Object.defineProperty(exports, "__esModule", { value: true }); 22 | const Loggers_1 = require("../Loggers"); 23 | const irc = __importStar(require("../libs/irc")); 24 | const discord_js_1 = require("discord.js"); 25 | const DiscordBot_1 = require("./DiscordBot"); 26 | const IIrcClient_1 = require("../IIrcClient"); 27 | const TypedConfig_1 = require("../TypedConfig"); 28 | const ChatLimiter_1 = require("../libs/ChatLimiter"); 29 | const logger = (0, Loggers_1.getLogger)('pre'); 30 | logger.info('Starting up...'); 31 | try { 32 | TypedConfig_1.CONFIG_OPTION.USE_ENV = true; 33 | const c = (0, TypedConfig_1.getIrcConfig)(); 34 | if (c.nick === 'your account id' || c.opt.password === 'you can get password from \'https://osu.ppy.sh/p/irc\'') { 35 | logger.error('You must enter your account ID and IRC password in the config file.'); 36 | logger.error('You can get your IRC password in \'https://osu.ppy.sh/p/irc\' '); 37 | logger.error('Copy config/default.json to config/local.json, and then enter your account ID and IRC password.'); 38 | process.exit(1); 39 | } 40 | const ircClient = new irc.Client(c.server, c.nick, c.opt); 41 | ircClient.on('error', err => { 42 | if (err.command === 'err_passwdmismatch') { 43 | logger.error(`${err.command}: ${err.args.join(' ')}`); 44 | logger.error('Check your account ID and IRC password.'); 45 | process.exit(1); 46 | } 47 | }); 48 | (0, ChatLimiter_1.applySpeedLimit)(ircClient, 10, 5000); 49 | (0, IIrcClient_1.logIrcEvent)(ircClient); 50 | (0, IIrcClient_1.logPrivateMessage)(ircClient); 51 | const discordClient = new discord_js_1.Client({ intents: [discord_js_1.Intents.FLAGS.GUILDS, discord_js_1.Intents.FLAGS.GUILD_INTEGRATIONS, discord_js_1.Intents.FLAGS.GUILD_MEMBERS, discord_js_1.Intents.FLAGS.GUILD_MESSAGES] }); 52 | const bot = new DiscordBot_1.DiscordBot(ircClient, discordClient); 53 | bot.start(); 54 | } 55 | catch (e) { 56 | logger.error(`@discord-index\n${e}`); 57 | process.exit(1); 58 | } 59 | //# sourceMappingURL=index.js.map -------------------------------------------------------------------------------- /dist/discord/index.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/discord/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA,wCAAuC;AAEvC,iDAAmC;AACnC,2CAA6C;AAC7C,6CAA0C;AAC1C,8CAA+D;AAC/D,gDAA6D;AAC7D,qDAAsD;AAEtD,MAAM,MAAM,GAAG,IAAA,mBAAS,EAAC,KAAK,CAAC,CAAC;AAChC,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;AAE9B,IAAI;IACF,2BAAa,CAAC,OAAO,GAAG,IAAI,CAAC;IAC7B,MAAM,CAAC,GAAG,IAAA,0BAAY,GAAE,CAAC;IACzB,IAAI,CAAC,CAAC,IAAI,KAAK,iBAAiB,IAAI,CAAC,CAAC,GAAG,CAAC,QAAQ,KAAK,wDAAwD,EAAE;QAC/G,MAAM,CAAC,KAAK,CAAC,qEAAqE,CAAC,CAAC;QACpF,MAAM,CAAC,KAAK,CAAC,gEAAgE,CAAC,CAAC;QAC/E,MAAM,CAAC,KAAK,CAAC,iGAAiG,CAAC,CAAC;QAChH,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;KACjB;IAED,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;IAC1D,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,EAAE;QAC1B,IAAI,GAAG,CAAC,OAAO,KAAK,oBAAoB,EAAE;YACxC,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,OAAO,KAAK,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACtD,MAAM,CAAC,KAAK,CAAC,yCAAyC,CAAC,CAAC;YACxD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;SACjB;IACH,CAAC,CAAC,CAAC;IACH,IAAA,6BAAe,EAAC,SAAS,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;IACrC,IAAA,wBAAW,EAAC,SAAS,CAAC,CAAC;IACvB,IAAA,8BAAiB,EAAC,SAAS,CAAC,CAAC;IAE7B,MAAM,aAAa,GAAG,IAAI,mBAAM,CAAC,EAAE,OAAO,EAAE,CAAC,oBAAO,CAAC,KAAK,CAAC,MAAM,EAAE,oBAAO,CAAC,KAAK,CAAC,kBAAkB,EAAE,oBAAO,CAAC,KAAK,CAAC,aAAa,EAAE,oBAAO,CAAC,KAAK,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC;IAEnK,MAAM,GAAG,GAAG,IAAI,uBAAU,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;IACrD,GAAG,CAAC,KAAK,EAAE,CAAC;CACb;AAAC,OAAO,CAAM,EAAE;IACf,MAAM,CAAC,KAAK,CAAC,mBAAmB,CAAC,EAAE,CAAC,CAAC;IACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;CACjB"} -------------------------------------------------------------------------------- /dist/dummies/DummyLobbyPlugin.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.DummyLobbyPlugin = void 0; 4 | const LobbyPlugin_1 = require("../plugins/LobbyPlugin"); 5 | class DummyLobbyPlugin extends LobbyPlugin_1.LobbyPlugin { 6 | constructor(lobby) { 7 | super(lobby, 'dummy'); 8 | } 9 | GetPluginStatus() { 10 | return `-- Dummy Lobby Plugin -- 11 | this is dummy lobby info 12 | `; 13 | } 14 | } 15 | exports.DummyLobbyPlugin = DummyLobbyPlugin; 16 | //# sourceMappingURL=DummyLobbyPlugin.js.map -------------------------------------------------------------------------------- /dist/dummies/DummyLobbyPlugin.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"DummyLobbyPlugin.js","sourceRoot":"","sources":["../../src/dummies/DummyLobbyPlugin.ts"],"names":[],"mappings":";;;AACA,wDAAqD;AAErD,MAAa,gBAAiB,SAAQ,yBAAW;IAE/C,YAAY,KAAY;QACtB,KAAK,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IACxB,CAAC;IAED,eAAe;QACb,OAAO;;KAEN,CAAC;IACJ,CAAC;CACF;AAXD,4CAWC"} -------------------------------------------------------------------------------- /dist/libs/ChatLimiter.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.applySpeedLimit = void 0; 4 | function applySpeedLimit(ircClient, tokens = 10, periodMs = 5000) { 5 | const queue = []; 6 | const waitTime = periodMs / tokens; 7 | let lastChatAt = 0; 8 | let timeId; 9 | const originalSay = ircClient.say.bind(ircClient); 10 | const sayWrapper = (target, message) => { 11 | message.split(/\r?\n/).filter(l => l.length > 0).forEach(l => queueMessage(target, l)); 12 | }; 13 | const queueMessage = (target, message) => { 14 | if (timeId) { 15 | queue.push({ target, message }); 16 | return; 17 | } 18 | if (Date.now() < lastChatAt + waitTime) { 19 | queue.push({ target, message }); 20 | waitAndSay(); 21 | return; 22 | } 23 | originalSay(target, message); 24 | lastChatAt = Date.now(); 25 | }; 26 | const waitAndSay = () => { 27 | if (queue.length === 0) 28 | return; 29 | let wt = lastChatAt + waitTime - Date.now(); 30 | if (wt < 0) 31 | wt = 0; 32 | timeId = setTimeout(() => { 33 | timeId = undefined; 34 | const task = queue.shift(); 35 | if (task) { 36 | originalSay(task.target, task.message); 37 | lastChatAt = Date.now(); 38 | waitAndSay(); 39 | } 40 | }, wt); 41 | }; 42 | ircClient.say = sayWrapper; 43 | return { 44 | dispose: () => { 45 | if (timeId) { 46 | clearTimeout(timeId); 47 | } 48 | queue.length = 0; 49 | } 50 | }; 51 | } 52 | exports.applySpeedLimit = applySpeedLimit; 53 | //# sourceMappingURL=ChatLimiter.js.map -------------------------------------------------------------------------------- /dist/libs/ChatLimiter.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"ChatLimiter.js","sourceRoot":"","sources":["../../src/libs/ChatLimiter.ts"],"names":[],"mappings":";;;AAEA,SAAgB,eAAe,CAAC,SAAqB,EAAE,SAAiB,EAAE,EAAE,WAAmB,IAAI;IACjG,MAAM,KAAK,GAA0C,EAAE,CAAC;IACxD,MAAM,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAC;IACnC,IAAI,UAAU,GAAW,CAAC,CAAC;IAC3B,IAAI,MAAkC,CAAC;IACvC,MAAM,WAAW,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAElD,MAAM,UAAU,GAAG,CAAC,MAAc,EAAE,OAAe,EAAE,EAAE;QACrD,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC;IACzF,CAAC,CAAC;IAEF,MAAM,YAAY,GAAG,CAAC,MAAc,EAAE,OAAe,EAAE,EAAE;QACvD,IAAI,MAAM,EAAE;YACV,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;YAChC,OAAO;SACR;QAED,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,UAAU,GAAG,QAAQ,EAAE;YACtC,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;YAChC,UAAU,EAAE,CAAC;YACb,OAAO;SACR;QAED,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC7B,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC1B,CAAC,CAAC;IAEF,MAAM,UAAU,GAAG,GAAG,EAAE;QACtB,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAC/B,IAAI,EAAE,GAAG,UAAU,GAAG,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC5C,IAAI,EAAE,GAAG,CAAC;YAAE,EAAE,GAAG,CAAC,CAAC;QACnB,MAAM,GAAG,UAAU,CAAC,GAAG,EAAE;YACvB,MAAM,GAAG,SAAS,CAAC;YACnB,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC;YAC3B,IAAI,IAAI,EAAE;gBACR,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;gBACvC,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;gBACxB,UAAU,EAAE,CAAC;aACd;QACH,CAAC,EAAE,EAAE,CAAC,CAAC;IACT,CAAC,CAAC;IAEF,SAAS,CAAC,GAAG,GAAG,UAAU,CAAC;IAE3B,OAAO;QACL,OAAO,EAAE,GAAG,EAAE;YACZ,IAAI,MAAM,EAAE;gBACV,YAAY,CAAC,MAAM,CAAC,CAAC;aACtB;YACD,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;QACnB,CAAC;KACF,CAAC;AACJ,CAAC;AApDD,0CAoDC"} -------------------------------------------------------------------------------- /dist/libs/DeferredAction.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.DeferredAction = void 0; 4 | /** 5 | * 延期可能な遅延実行アクションを表現するクラス。 6 | */ 7 | class DeferredAction { 8 | constructor(action) { 9 | this.timeId = null; 10 | this.action = action; 11 | } 12 | /** 13 | * アクションの遅延実行を開始する 14 | * @param delay 遅延時間 ms 15 | * @param param アクションに渡されるパラメータ 16 | * @param resetTimer 現在の遅延時間をリセットするか 17 | */ 18 | start(delay, param = undefined, resetTimer = false) { 19 | if (this.timeId !== null && resetTimer) { 20 | clearTimeout(this.timeId); 21 | this.timeId = null; 22 | } 23 | this.param = param; 24 | if (this.timeId === null) { 25 | this.timeId = setTimeout(() => { 26 | this.timeId = null; 27 | this.action(this.param); 28 | this.param = undefined; 29 | }, delay); 30 | this.timeId.unref(); 31 | } 32 | } 33 | /** 遅延実行をキャンセルする。*/ 34 | cancel() { 35 | if (this.timeId !== null) { 36 | clearTimeout(this.timeId); 37 | this.timeId = null; 38 | this.param = undefined; 39 | } 40 | } 41 | /** 遅延実行が完了しているか */ 42 | get done() { 43 | return this.timeId === null; 44 | } 45 | } 46 | exports.DeferredAction = DeferredAction; 47 | //# sourceMappingURL=DeferredAction.js.map -------------------------------------------------------------------------------- /dist/libs/DeferredAction.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"DeferredAction.js","sourceRoot":"","sources":["../../src/libs/DeferredAction.ts"],"names":[],"mappings":";;;AAAA;;GAEG;AACH,MAAa,cAAc;IAMzB,YAAY,MAAsB;QAD1B,WAAM,GAA0B,IAAI,CAAC;QAE3C,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,KAAa,EAAE,QAAuB,SAAS,EAAE,aAAsB,KAAK;QAChF,IAAI,IAAI,CAAC,MAAM,KAAK,IAAI,IAAI,UAAU,EAAE;YACtC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAC1B,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;SACpB;QACD,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,IAAI,CAAC,MAAM,KAAK,IAAI,EAAE;YACxB,IAAI,CAAC,MAAM,GAAG,UAAU,CAAC,GAAG,EAAE;gBAC5B,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;gBACnB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAU,CAAC,CAAC;gBAC7B,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC;YACzB,CAAC,EAAE,KAAK,CAAC,CAAC;YACV,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;SACrB;IACH,CAAC;IAED,mBAAmB;IACnB,MAAM;QACJ,IAAI,IAAI,CAAC,MAAM,KAAK,IAAI,EAAE;YACxB,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAC1B,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;YACnB,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC;SACxB;IACH,CAAC;IAED,mBAAmB;IACnB,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC;IAC9B,CAAC;CACF;AA7CD,wCA6CC"} -------------------------------------------------------------------------------- /dist/libs/OptionValidator.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.validateOption = void 0; 4 | exports.validateOption = { 5 | number: function (name, value, min, max) { 6 | let v = value; 7 | if (typeof v !== 'number') { 8 | v = parseFloat(v); 9 | } 10 | if (isNaN(v)) { 11 | throw new Error(`Invalid number option @${name}. ${value} is not a number`); 12 | } 13 | if (min !== undefined && v < min) { 14 | throw new Error(`Invalid number option. @${name} must be at least ${min}`); 15 | } 16 | if (max !== undefined && max < v) { 17 | throw new Error(`Invalid number option. @${name} must be at most ${max}`); 18 | } 19 | return v; 20 | }, 21 | bool: function (name, value) { 22 | let v = value; 23 | if (typeof v === 'string') { 24 | v = v.toLocaleLowerCase().trim(); 25 | if (v === 'false') { 26 | v = false; 27 | } 28 | else if (v === 'true') { 29 | v = true; 30 | } 31 | else { 32 | throw new Error(`${name} (${value}) is not a boolean`); 33 | } 34 | } 35 | return !!v; 36 | } 37 | }; 38 | //# sourceMappingURL=OptionValidator.js.map -------------------------------------------------------------------------------- /dist/libs/OptionValidator.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"OptionValidator.js","sourceRoot":"","sources":["../../src/libs/OptionValidator.ts"],"names":[],"mappings":";;;AAAa,QAAA,cAAc,GAAG;IAC5B,MAAM,EAAE,UAAU,IAAY,EAAE,KAAU,EAAE,GAAY,EAAE,GAAY;QACpE,IAAI,CAAC,GAAG,KAAK,CAAC;QACd,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE;YACzB,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;SACnB;QACD,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE;YACZ,MAAM,IAAI,KAAK,CAAC,0BAA0B,IAAI,KAAK,KAAK,kBAAkB,CAAC,CAAC;SAC7E;QACD,IAAI,GAAG,KAAK,SAAS,IAAI,CAAC,GAAG,GAAG,EAAE;YAChC,MAAM,IAAI,KAAK,CAAC,2BAA2B,IAAI,qBAAqB,GAAG,EAAE,CAAC,CAAC;SAC5E;QACD,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,GAAG,CAAC,EAAE;YAChC,MAAM,IAAI,KAAK,CAAC,2BAA2B,IAAI,oBAAoB,GAAG,EAAE,CAAC,CAAC;SAC3E;QACD,OAAO,CAAC,CAAC;IACX,CAAC;IAED,IAAI,EAAE,UAAU,IAAY,EAAE,KAAU;QACtC,IAAI,CAAC,GAAG,KAAK,CAAC;QACd,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE;YACzB,CAAC,GAAG,CAAC,CAAC,iBAAiB,EAAE,CAAC,IAAI,EAAE,CAAC;YACjC,IAAI,CAAC,KAAK,OAAO,EAAE;gBACjB,CAAC,GAAG,KAAK,CAAC;aACX;iBAAM,IAAI,CAAC,KAAK,MAAM,EAAE;gBACvB,CAAC,GAAG,IAAI,CAAC;aACV;iBAAM;gBACL,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,KAAK,KAAK,oBAAoB,CAAC,CAAC;aACxD;SACF;QAED,OAAO,CAAC,CAAC,CAAC,CAAC;IACb,CAAC;CACF,CAAC"} -------------------------------------------------------------------------------- /dist/libs/TypedEvent.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // code from https://typescript-jp.gitbook.io/deep-dive/main-1/typed-event 3 | Object.defineProperty(exports, "__esModule", { value: true }); 4 | exports.TypedEvent = void 0; 5 | /** passes through events as they happen. You will not get events from before you start listening */ 6 | class TypedEvent { 7 | constructor() { 8 | this.listeners = []; 9 | this.listenersOncer = []; 10 | } 11 | on(listener) { 12 | this.listeners.push(listener); 13 | return { 14 | dispose: () => this.off(listener) 15 | }; 16 | } 17 | once(listener) { 18 | this.listenersOncer.push(listener); 19 | } 20 | async() { 21 | return new Promise(resolve => { 22 | this.listenersOncer.push(a => { 23 | resolve(a); 24 | }); 25 | }); 26 | } 27 | off(listener) { 28 | const callbackIndex = this.listeners.indexOf(listener); 29 | if (callbackIndex > -1) 30 | this.listeners.splice(callbackIndex, 1); 31 | } 32 | emit(event) { 33 | /** Update any general listeners */ 34 | this.listeners.forEach((listener) => listener(event)); 35 | /** Clear the `once` queue */ 36 | if (this.listenersOncer.length > 0) { 37 | this.listenersOncer.forEach((listener) => listener(event)); 38 | this.listenersOncer = []; 39 | } 40 | } 41 | pipe(te) { 42 | return this.on((e) => te.emit(e)); 43 | } 44 | } 45 | exports.TypedEvent = TypedEvent; 46 | //# sourceMappingURL=TypedEvent.js.map -------------------------------------------------------------------------------- /dist/libs/TypedEvent.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"TypedEvent.js","sourceRoot":"","sources":["../../src/libs/TypedEvent.ts"],"names":[],"mappings":";AAAA,0EAA0E;;;AAU1E,oGAAoG;AACpG,MAAa,UAAU;IAAvB;QACU,cAAS,GAAkB,EAAE,CAAC;QAC9B,mBAAc,GAAkB,EAAE,CAAC;IAwC7C,CAAC;IAtCC,EAAE,CAAC,QAAqB;QACtB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC9B,OAAO;YACL,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC;SAClC,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,QAAqB;QACxB,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACrC,CAAC;IAED,KAAK;QACH,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE;YAC3B,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;gBAC3B,OAAO,CAAC,CAAC,CAAC,CAAC;YACb,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAED,GAAG,CAAC,QAAqB;QACvB,MAAM,aAAa,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACvD,IAAI,aAAa,GAAG,CAAC,CAAC;YAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC;IAClE,CAAC;IAED,IAAI,CAAC,KAAQ;QACX,mCAAmC;QACnC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;QAEtD,6BAA6B;QAC7B,IAAI,IAAI,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE;YAClC,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;YAC3D,IAAI,CAAC,cAAc,GAAG,EAAE,CAAC;SAC1B;IACH,CAAC;IAED,IAAI,CAAC,EAAiB;QACpB,OAAO,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACpC,CAAC;CACF;AA1CD,gCA0CC"} -------------------------------------------------------------------------------- /dist/parsers/MpSettingsParser.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.MpSettingsParser = void 0; 4 | const Player_1 = require("../Player"); 5 | class MpSettingsParser { 6 | constructor() { 7 | this.result = null; 8 | this.isParsing = false; 9 | } 10 | get isParsed() { 11 | return !this.isParsing && this.result !== null; 12 | } 13 | feedLine(line) { 14 | let m = line.match(/Room name: (.+), History: (.+?(\d+))/); 15 | if (m) { 16 | this.result = { 17 | name: m[1], 18 | id: parseInt(m[3]), 19 | history: m[2], 20 | beatmapUrl: '', 21 | beatmapId: 0, 22 | beatmapTitle: '', 23 | teamMode: '', 24 | winCondition: '', 25 | activeMods: '', 26 | numPlayers: 0, 27 | players: [], 28 | }; 29 | this.isParsing = true; 30 | return true; 31 | } 32 | if (this.result === null) 33 | return false; 34 | m = line.match(/Beatmap: (\S+?(\d+)) (.+)/); 35 | if (m) { 36 | this.result.beatmapUrl = m[1]; 37 | this.result.beatmapId = parseInt(m[2]); 38 | this.result.beatmapTitle = m[3]; 39 | return true; 40 | } 41 | m = line.match(/Team mode: (.+), Win condition: (.+)/); 42 | if (m) { 43 | this.result.teamMode = m[1]; 44 | this.result.winCondition = m[2]; 45 | return true; 46 | } 47 | m = line.match(/Active mods: (.+)/); 48 | if (m) { 49 | this.result.activeMods = m[1]; 50 | return true; 51 | } 52 | m = line.match(/Players: (\d+)/); 53 | if (m) { 54 | this.result.numPlayers = parseInt(m[1]); 55 | this.isParsing = this.result.numPlayers !== 0; 56 | return true; 57 | } 58 | m = line.match(/^Slot (\d+)\s+(.+) https:\/\/osu\.ppy\.sh\/u\/(\d+) (.{15})\s*(\[(.+)\])?$/); 59 | if (m) { 60 | const team = m[6] === undefined || !m[6].includes('Team') ? Player_1.Teams.None 61 | : m[6].includes('Blue') ? Player_1.Teams.Blue : Player_1.Teams.Red; 62 | const p = { 63 | slot: parseInt(m[1]), 64 | ready: m[2].trim(), 65 | id: parseInt(m[3]), 66 | profile: `https://osu.ppy.sh/u/${m[3]}`, 67 | name: m[4].trim(), 68 | isHost: m[6] === undefined ? false : m[6].includes('Host'), 69 | team: team, 70 | options: m[6] === undefined ? '' : m[6].trim() 71 | }; 72 | this.result.players.push(p); 73 | this.isParsing = this.result.players.length !== this.result.numPlayers; 74 | return true; 75 | } 76 | return false; 77 | } 78 | } 79 | exports.MpSettingsParser = MpSettingsParser; 80 | //# sourceMappingURL=MpSettingsParser.js.map -------------------------------------------------------------------------------- /dist/parsers/MpSettingsParser.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"MpSettingsParser.js","sourceRoot":"","sources":["../../src/parsers/MpSettingsParser.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /dist/parsers/StatParser.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"StatParser.js","sourceRoot":"","sources":["../../src/parsers/StatParser.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /dist/plugins/AutoStartTimer.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"AutoStartTimer.js","sourceRoot":"","sources":["../../src/plugins/AutoStartTimer.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /dist/plugins/CacheCleaner.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"CacheCleaner.js","sourceRoot":"","sources":["../../src/plugins/CacheCleaner.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /dist/plugins/HistoryLoader.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"HistoryLoader.js","sourceRoot":"","sources":["../../src/plugins/HistoryLoader.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /dist/plugins/LobbyPlugin.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.regSwitch = exports.LobbyPlugin = void 0; 4 | const Loggers_1 = require("../Loggers"); 5 | const TypedConfig_1 = require("../TypedConfig"); 6 | /** 7 | * ロビーのイベントに反応して処理を行うプラグインのベースクラス。 8 | */ 9 | class LobbyPlugin { 10 | constructor(lobby, pluginName, loggerTag = 'default') { 11 | this.lobby = lobby; 12 | this.lobby.plugins.push(this); 13 | this.pluginName = pluginName; 14 | this.logger = (0, Loggers_1.getLogger)(loggerTag); 15 | } 16 | /** 17 | * 他のプラグインにメッセージを送信する。 18 | * @param type 19 | * @param args 20 | */ 21 | SendPluginMessage(type, args = []) { 22 | this.lobby.PluginMessage.emit({ type, args, src: this }); 23 | } 24 | /** 25 | * コンソール上で[i]nfo コマンドを実行した際に表示される、 26 | * プラグインごとのステータスメッセージを取得する 27 | */ 28 | GetPluginStatus() { 29 | return ''; 30 | } 31 | /** 32 | * すべてのプラグインが読み込まれたあとに実行される 33 | */ 34 | OnLoaded() { 35 | /* do nothing. */ 36 | } 37 | OnConfig(target, name, value) { 38 | /* do nothing. */ 39 | } 40 | loadEnvSettings(option) { 41 | try { 42 | (0, TypedConfig_1.loadEnvConfig)(this.pluginName, option); 43 | } 44 | catch (e) { 45 | this.logger.error(`\n${e.message}\n${e.stack}`); 46 | process.exit(1); 47 | } 48 | } 49 | } 50 | exports.LobbyPlugin = LobbyPlugin; 51 | function regSwitch(val, cases) { 52 | for (const c of cases) { 53 | const ea = c.case.exec(val); 54 | if (ea) { 55 | c.action(ea); 56 | return; 57 | } 58 | } 59 | } 60 | exports.regSwitch = regSwitch; 61 | //# sourceMappingURL=LobbyPlugin.js.map -------------------------------------------------------------------------------- /dist/plugins/LobbyPlugin.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"LobbyPlugin.js","sourceRoot":"","sources":["../../src/plugins/LobbyPlugin.ts"],"names":[],"mappings":";;;AACA,wCAA+C;AAC/C,gDAA+C;AAE/C;;GAEG;AACH,MAAa,WAAW;IAKtB,YAAY,KAAY,EAAE,UAAkB,EAAE,YAAoB,SAAS;QACzE,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9B,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,MAAM,GAAG,IAAA,mBAAS,EAAC,SAAS,CAAC,CAAC;IACrC,CAAC;IAED;;;;OAIG;IACH,iBAAiB,CAAC,IAAY,EAAE,OAAiB,EAAE;QACjD,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3D,CAAC;IAED;;;OAGG;IACH,eAAe;QACb,OAAO,EAAE,CAAC;IACZ,CAAC;IAED;;OAEG;IACH,QAAQ;QACN,iBAAiB;IACnB,CAAC;IAED,QAAQ,CAAC,MAAc,EAAE,IAAY,EAAE,KAAa;QAClD,iBAAiB;IACnB,CAAC;IAED,eAAe,CAAC,MAAW;QACzB,IAAI;YACF,IAAA,2BAAa,EAAC,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;SACxC;QAAC,OAAO,CAAM,EAAE;YACf,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;YAChD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;SACjB;IACH,CAAC;CACF;AAhDD,kCAgDC;AAED,SAAgB,SAAS,CAAC,GAAW,EAAE,KAA+D;IACpG,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE;QACrB,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC5B,IAAI,EAAE,EAAE;YACN,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACb,OAAO;SACR;KACF;AACH,CAAC;AARD,8BAQC"} -------------------------------------------------------------------------------- /dist/plugins/LobbyTerminator.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"LobbyTerminator.js","sourceRoot":"","sources":["../../src/plugins/LobbyTerminator.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /dist/plugins/MapRecaster.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.MapRecaster = void 0; 4 | const LobbyPlugin_1 = require("./LobbyPlugin"); 5 | const CommandParser_1 = require("../parsers/CommandParser"); 6 | /** 7 | * ホストが古いバージョンのマップを選択した際に、コマンドでマップを貼り直して最新版にする。 8 | * !updateコマンドなどで発動。マップ選択後に1度だけ実行できる。 9 | */ 10 | class MapRecaster extends LobbyPlugin_1.LobbyPlugin { 11 | constructor(lobby) { 12 | super(lobby, 'MapRecaster', 'recaster'); 13 | this.canRecast = true; 14 | this.registerEvents(); 15 | } 16 | registerEvents() { 17 | this.lobby.ReceivedChatCommand.on(a => this.onReceivedChatCommand(a.command, a.param, a.player)); 18 | this.lobby.ReceivedBanchoResponse.on(a => { 19 | if (a.response.type === CommandParser_1.BanchoResponseType.BeatmapChanged) { 20 | this.canRecast = true; 21 | } 22 | }); 23 | } 24 | onReceivedChatCommand(command, param, player) { 25 | if (command === '!update') { 26 | if (this.canRecast) { 27 | this.canRecast = false; 28 | this.lobby.SendMessage(`!mp map ${this.lobby.mapId}`); 29 | } 30 | } 31 | } 32 | } 33 | exports.MapRecaster = MapRecaster; 34 | //# sourceMappingURL=MapRecaster.js.map -------------------------------------------------------------------------------- /dist/plugins/MapRecaster.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"MapRecaster.js","sourceRoot":"","sources":["../../src/plugins/MapRecaster.ts"],"names":[],"mappings":";;;AAEA,+CAA4C;AAC5C,4DAA8D;AAE9D;;;GAGG;AACH,MAAa,WAAY,SAAQ,yBAAW;IAE1C,YAAY,KAAY;QACtB,KAAK,CAAC,KAAK,EAAE,aAAa,EAAE,UAAU,CAAC,CAAC;QAF1C,cAAS,GAAY,IAAI,CAAC;QAGxB,IAAI,CAAC,cAAc,EAAE,CAAC;IACxB,CAAC;IAEO,cAAc;QACpB,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;QACjG,IAAI,CAAC,KAAK,CAAC,sBAAsB,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;YACvC,IAAI,CAAC,CAAC,QAAQ,CAAC,IAAI,KAAK,kCAAkB,CAAC,cAAc,EAAE;gBACzD,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;aACvB;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,qBAAqB,CAAC,OAAe,EAAE,KAAa,EAAE,MAAc;QAC1E,IAAI,OAAO,KAAK,SAAS,EAAE;YACzB,IAAI,IAAI,CAAC,SAAS,EAAE;gBAClB,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;gBACvB,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,WAAW,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;aACvD;SACF;IACH,CAAC;CACF;AAxBD,kCAwBC"} -------------------------------------------------------------------------------- /dist/plugins/ProfileFecher.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.ProfileFecher = void 0; 4 | const LobbyPlugin_1 = require("./LobbyPlugin"); 5 | const WebApiClient_1 = require("../webapi/WebApiClient"); 6 | const TypedConfig_1 = require("../TypedConfig"); 7 | class ProfileFecher extends LobbyPlugin_1.LobbyPlugin { 8 | constructor(lobby, option = {}) { 9 | super(lobby, 'profile', 'profile'); 10 | this.hasError = false; 11 | this.option = (0, TypedConfig_1.getConfig)(this.pluginName, option); 12 | this.profileMap = new Map(); 13 | this.pendingNames = new Set(); 14 | this.task = this.initializeAsync(); 15 | this.registerEvents(); 16 | } 17 | async initializeAsync() { 18 | await WebApiClient_1.WebApiClient.updateToken(); 19 | } 20 | registerEvents() { 21 | this.lobby.PlayerJoined.on(a => this.onPlayerJoined(a.player)); 22 | } 23 | onPlayerJoined(player) { 24 | if (this.hasError) 25 | return; 26 | this.addTaskQueueIfNeeded(player); 27 | } 28 | addTaskQueueIfNeeded(player) { 29 | if (player.id !== 0) 30 | return false; 31 | const profile = this.profileMap.get(player.name); 32 | if (profile && !this.isExpiredProfile(profile)) { 33 | player.id = profile.id; 34 | player.profile = profile; 35 | return true; 36 | } 37 | if (this.pendingNames.has(player.name)) { 38 | return false; 39 | } 40 | this.pendingNames.add(player.name); 41 | this.task = this.task.then(async () => { 42 | try { 43 | const profile = await this.getProfileFromWebApi(player); 44 | if (profile !== null) { 45 | player.id = profile.id; 46 | player.profile = profile; 47 | this.logger.info(`Fetching player profile: ${player.name}`); 48 | } 49 | else { 50 | this.logger.warn(`Player cannot be found: ${player.name}`); 51 | } 52 | this.pendingNames.delete(player.name); 53 | } 54 | catch (e) { 55 | this.logger.error(`@ProfileFecher#addTaskQueueIfNeeded\n${e.message}\n${e.stack}`); 56 | } 57 | }); 58 | return true; 59 | } 60 | getProfileFromWebApi(player) { 61 | return WebApiClient_1.WebApiClient.getUser(player.name); 62 | } 63 | isExpiredProfile(profile) { 64 | return Date.now() < this.option.profile_expired_day * 24 * 60 * 60 * 1000 + profile.get_time; 65 | } 66 | } 67 | exports.ProfileFecher = ProfileFecher; 68 | //# sourceMappingURL=ProfileFecher.js.map -------------------------------------------------------------------------------- /dist/plugins/ProfileFecher.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"ProfileFecher.js","sourceRoot":"","sources":["../../src/plugins/ProfileFecher.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /dist/plugins/VoteCounter.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.VoteCounter = void 0; 4 | class VoteCounter { 5 | constructor(requiredRate, requiredMin) { 6 | this.requiredRate = requiredRate; 7 | this.requiredMin = requiredMin; 8 | this._passed = false; 9 | this.voters = new Map(); 10 | } 11 | Vote(player) { 12 | if (!this.voters.has(player)) 13 | return false; 14 | if (this.voters.get(player)) 15 | return false; 16 | this.voters.set(player, true); 17 | this.checkPassed(); 18 | return true; 19 | } 20 | AddVoter(player) { 21 | if (!this.voters.has(player)) { 22 | this.voters.set(player, false); 23 | } 24 | } 25 | RemoveVoter(player) { 26 | this.voters.delete(player); 27 | this.checkPassed(); 28 | } 29 | Clear() { 30 | for (const k of this.voters.keys()) { 31 | this.voters.set(k, false); 32 | } 33 | this._passed = false; 34 | } 35 | RemoveAllVoters() { 36 | this.voters.clear(); 37 | this._passed = false; 38 | } 39 | get required() { 40 | return Math.ceil(Math.max(this.voters.size * this.requiredRate, this.requiredMin)); 41 | } 42 | get count() { 43 | let c = 0; 44 | this.voters.forEach((v, k) => v ? c++ : 0); 45 | return c; 46 | } 47 | get passed() { 48 | return this._passed; 49 | } 50 | checkPassed() { 51 | if (this.required <= this.count) { 52 | this._passed = true; 53 | } 54 | } 55 | toString() { 56 | return `${this.count} / ${this.required}`; 57 | } 58 | } 59 | exports.VoteCounter = VoteCounter; 60 | //# sourceMappingURL=VoteCounter.js.map -------------------------------------------------------------------------------- /dist/plugins/VoteCounter.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"VoteCounter.js","sourceRoot":"","sources":["../../src/plugins/VoteCounter.ts"],"names":[],"mappings":";;;AAEA,MAAa,WAAW;IAMtB,YAAY,YAAoB,EAAE,WAAmB;QACnD,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;QACjC,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,IAAI,GAAG,EAAmB,CAAC;IAC3C,CAAC;IAEM,IAAI,CAAC,MAAc;QACxB,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC;YAAE,OAAO,KAAK,CAAC;QAC3C,IAAI,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC;YAAE,OAAO,KAAK,CAAC;QAC1C,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC9B,IAAI,CAAC,WAAW,EAAE,CAAC;QACnB,OAAO,IAAI,CAAC;IACd,CAAC;IAEM,QAAQ,CAAC,MAAc;QAC5B,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;YAC5B,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;SAChC;IACH,CAAC;IAEM,WAAW,CAAC,MAAc;QAC/B,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC3B,IAAI,CAAC,WAAW,EAAE,CAAC;IACrB,CAAC;IAEM,KAAK;QACV,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE;YAClC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;SAC3B;QACD,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;IACvB,CAAC;IAEM,eAAe;QACpB,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QACpB,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;IACvB,CAAC;IAED,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CACvB,IAAI,CAAC,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC,YAAY,EACpC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;IACvB,CAAC;IAED,IAAI,KAAK;QACP,IAAI,CAAC,GAAG,CAAC,CAAC;QACV,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3C,OAAO,CAAC,CAAC;IACX,CAAC;IAED,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAEO,WAAW;QACjB,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,KAAK,EAAE;YAC/B,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;SACrB;IACH,CAAC;IAED,QAAQ;QACN,OAAO,GAAG,IAAI,CAAC,KAAK,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;IAC5C,CAAC;CACF;AArED,kCAqEC"} -------------------------------------------------------------------------------- /dist/tests/InOutLoggerTest.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | const InOutLogger_1 = require("../plugins/InOutLogger"); 7 | const TestUtils_1 = __importDefault(require("./TestUtils")); 8 | describe.skip('In Out Logger Tests', function () { 9 | before(function () { 10 | TestUtils_1.default.configMochaVerbosely(); 11 | }); 12 | it('test', async () => { 13 | const { lobby, ircClient } = await TestUtils_1.default.SetupLobbyAsync(); 14 | const logger = new InOutLogger_1.InOutLogger(lobby); 15 | const players = await TestUtils_1.default.AddPlayersAsync(5, ircClient); 16 | await ircClient.emulateMatchAsync(); 17 | await ircClient.emulateMatchAsync(); 18 | await ircClient.emulateRemovePlayerAsync(players[0]); 19 | await ircClient.emulateRemovePlayerAsync(players[1]); 20 | await ircClient.emulateRemovePlayerAsync(players[2]); 21 | await ircClient.emulateAddPlayerAsync('a'); 22 | await ircClient.emulateAddPlayerAsync('b'); 23 | await ircClient.emulateAddPlayerAsync('c'); 24 | const t = ircClient.emulateMatchAsync(10); 25 | await TestUtils_1.default.delayAsync(1); 26 | await ircClient.emulateRemovePlayerAsync('a'); 27 | await ircClient.emulateAddPlayerAsync('d'); 28 | await t; 29 | await ircClient.emulateAddPlayerAsync('e'); 30 | await ircClient.emulateMatchAsync(); 31 | await ircClient.emulateRemovePlayerAsync('e'); 32 | await ircClient.emulateMatchAsync(); 33 | logger.logger.info(logger.GetPluginStatus()); 34 | }); 35 | }); 36 | //# sourceMappingURL=InOutLoggerTest.js.map -------------------------------------------------------------------------------- /dist/tests/InOutLoggerTest.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"InOutLoggerTest.js","sourceRoot":"","sources":["../../src/tests/InOutLoggerTest.ts"],"names":[],"mappings":";;;;;AAAA,wDAAqD;AACrD,4DAA6B;AAE7B,QAAQ,CAAC,IAAI,CAAC,qBAAqB,EAAE;IACnC,MAAM,CAAC;QACL,mBAAE,CAAC,oBAAoB,EAAE,CAAC;IAC5B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,MAAM,EAAE,KAAK,IAAI,EAAE;QACpB,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,MAAM,mBAAE,CAAC,eAAe,EAAE,CAAC;QACxD,MAAM,MAAM,GAAG,IAAI,yBAAW,CAAC,KAAK,CAAC,CAAC;QACtC,MAAM,OAAO,GAAG,MAAM,mBAAE,CAAC,eAAe,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;QACvD,MAAM,SAAS,CAAC,iBAAiB,EAAE,CAAC;QACpC,MAAM,SAAS,CAAC,iBAAiB,EAAE,CAAC;QACpC,MAAM,SAAS,CAAC,wBAAwB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;QACrD,MAAM,SAAS,CAAC,wBAAwB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;QACrD,MAAM,SAAS,CAAC,wBAAwB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;QACrD,MAAM,SAAS,CAAC,qBAAqB,CAAC,GAAG,CAAC,CAAC;QAC3C,MAAM,SAAS,CAAC,qBAAqB,CAAC,GAAG,CAAC,CAAC;QAC3C,MAAM,SAAS,CAAC,qBAAqB,CAAC,GAAG,CAAC,CAAC;QAC3C,MAAM,CAAC,GAAG,SAAS,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC;QAC1C,MAAM,mBAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QACvB,MAAM,SAAS,CAAC,wBAAwB,CAAC,GAAG,CAAC,CAAC;QAC9C,MAAM,SAAS,CAAC,qBAAqB,CAAC,GAAG,CAAC,CAAC;QAC3C,MAAM,CAAC,CAAC;QACR,MAAM,SAAS,CAAC,qBAAqB,CAAC,GAAG,CAAC,CAAC;QAC3C,MAAM,SAAS,CAAC,iBAAiB,EAAE,CAAC;QACpC,MAAM,SAAS,CAAC,wBAAwB,CAAC,GAAG,CAAC,CAAC;QAC9C,MAAM,SAAS,CAAC,iBAAiB,EAAE,CAAC;QACpC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,eAAe,EAAE,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"} -------------------------------------------------------------------------------- /dist/tests/IntegratedPluginsTest.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | const chai_1 = require("chai"); 7 | const CommandParser_1 = require("../parsers/CommandParser"); 8 | const AutoHostSelector_1 = require("../plugins/AutoHostSelector"); 9 | const HostSkipper_1 = require("../plugins/HostSkipper"); 10 | const TestUtils_1 = __importDefault(require("./TestUtils")); 11 | describe('Integrated Plugins Tests', function () { 12 | before(function () { 13 | TestUtils_1.default.configMochaAsSilent(); 14 | }); 15 | describe('selector and skipper tests', function () { 16 | async function setup(selectorOption = {}, skipperOption = { afk_check_interval_ms: 0 }) { 17 | const li = await TestUtils_1.default.SetupLobbyAsync(); 18 | const selector = new AutoHostSelector_1.AutoHostSelector(li.lobby, selectorOption); 19 | const skipper = new HostSkipper_1.HostSkipper(li.lobby, skipperOption); 20 | return { selector, skipper, ...li }; 21 | } 22 | it('skip to test', async () => { 23 | const { selector, skipper, lobby, ircClient } = await setup(); 24 | const ownerId = TestUtils_1.default.ownerNickname; 25 | await TestUtils_1.default.AddPlayersAsync([ownerId, 'p2', 'p3', 'p4'], ircClient); 26 | let owner = lobby.GetPlayer(ownerId); 27 | chai_1.assert.isNotNull(owner); 28 | owner = owner; 29 | chai_1.assert.isTrue(owner.isCreator); 30 | chai_1.assert.isTrue(owner.isAuthorized); 31 | chai_1.assert.isTrue(owner.isHost); 32 | await ircClient.emulateMatchAsync(0); 33 | TestUtils_1.default.assertHost('p2', lobby); 34 | let m = '*skipto p4'; 35 | chai_1.assert.isTrue(CommandParser_1.parser.IsChatCommand(m)); 36 | lobby.RaiseReceivedChatCommand(owner, m); 37 | await TestUtils_1.default.delayAsync(10); 38 | TestUtils_1.default.assertHost('p4', lobby); 39 | m = `*skipto ${owner.name}`; 40 | chai_1.assert.isTrue(CommandParser_1.parser.IsChatCommand(m)); 41 | lobby.RaiseReceivedChatCommand(owner, m); 42 | await TestUtils_1.default.delayAsync(10); 43 | TestUtils_1.default.assertHost(ownerId, lobby); 44 | skipper.StopTimer(); 45 | }); 46 | }); 47 | }); 48 | //# sourceMappingURL=IntegratedPluginsTest.js.map -------------------------------------------------------------------------------- /dist/tests/IntegratedPluginsTest.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"IntegratedPluginsTest.js","sourceRoot":"","sources":["../../src/tests/IntegratedPluginsTest.ts"],"names":[],"mappings":";;;;;AAAA,+BAA8B;AAI9B,4DAAkD;AAClD,kEAAuF;AACvF,wDAAwE;AAExE,4DAA6B;AAE7B,QAAQ,CAAC,0BAA0B,EAAE;IACnC,MAAM,CAAC;QACL,mBAAE,CAAC,mBAAmB,EAAE,CAAC;IAC3B,CAAC,CAAC,CAAC;IACH,QAAQ,CAAC,4BAA4B,EAAE;QACrC,KAAK,UAAU,KAAK,CAAC,iBAAkD,EAAE,EAAE,gBAA4C,EAAE,qBAAqB,EAAE,CAAC,EAAE;YAEjJ,MAAM,EAAE,GAAG,MAAM,mBAAE,CAAC,eAAe,EAAE,CAAC;YACtC,MAAM,QAAQ,GAAG,IAAI,mCAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC;YAChE,MAAM,OAAO,GAAG,IAAI,yBAAW,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;YACzD,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,EAAE,EAAE,CAAC;QACtC,CAAC;QAED,EAAE,CAAC,cAAc,EAAE,KAAK,IAAI,EAAE;YAC5B,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,MAAM,KAAK,EAAE,CAAC;YAC9D,MAAM,OAAO,GAAG,mBAAE,CAAC,aAAa,CAAC;YACjC,MAAM,mBAAE,CAAC,eAAe,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,SAAS,CAAC,CAAC;YACjE,IAAI,KAAK,GAAG,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;YACrC,aAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;YACxB,KAAK,GAAG,KAAe,CAAC;YACxB,aAAM,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;YAC/B,aAAM,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;YAClC,aAAM,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YAE5B,MAAM,SAAS,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC;YAErC,mBAAE,CAAC,UAAU,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YAC3B,IAAI,CAAC,GAAG,YAAY,CAAC;YACrB,aAAM,CAAC,MAAM,CAAC,sBAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;YACvC,KAAK,CAAC,wBAAwB,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;YACzC,MAAM,mBAAE,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;YACxB,mBAAE,CAAC,UAAU,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YAE3B,CAAC,GAAG,WAAW,KAAK,CAAC,IAAI,EAAE,CAAC;YAC5B,aAAM,CAAC,MAAM,CAAC,sBAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;YACvC,KAAK,CAAC,wBAAwB,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;YACzC,MAAM,mBAAE,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;YACxB,mBAAE,CAAC,UAAU,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YAC9B,OAAO,CAAC,SAAS,EAAE,CAAC;QACtB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"} -------------------------------------------------------------------------------- /dist/tests/LobbyTerminatorTest.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | const LobbyTerminator_1 = require("../plugins/LobbyTerminator"); 7 | const TestUtils_1 = __importDefault(require("./TestUtils")); 8 | describe.skip('Lobby Terminator Tests', function () { 9 | before(function () { 10 | TestUtils_1.default.configMochaVerbosely(); 11 | }); 12 | async function setupAsync(interval = 10) { 13 | const { lobby, ircClient } = await TestUtils_1.default.SetupLobbyAsync(); 14 | const terminator = new LobbyTerminator_1.LobbyTerminator(lobby); 15 | terminator.multilimeMessageInterval = interval; 16 | return { terminator, lobby, ircClient }; 17 | } 18 | it('CloseLobby time', async () => { 19 | const { terminator, lobby, ircClient } = await setupAsync(); 20 | terminator.CloseLobby(100); 21 | }); 22 | }); 23 | //# sourceMappingURL=LobbyTerminatorTest.js.map -------------------------------------------------------------------------------- /dist/tests/LobbyTerminatorTest.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"LobbyTerminatorTest.js","sourceRoot":"","sources":["../../src/tests/LobbyTerminatorTest.ts"],"names":[],"mappings":";;;;;AAEA,gEAA6D;AAC7D,4DAA6B;AAE7B,QAAQ,CAAC,IAAI,CAAC,wBAAwB,EAAE;IACtC,MAAM,CAAC;QACL,mBAAE,CAAC,oBAAoB,EAAE,CAAC;IAC5B,CAAC,CAAC,CAAC;IACH,KAAK,UAAU,UAAU,CAAC,WAAmB,EAAE;QAC7C,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,MAAM,mBAAE,CAAC,eAAe,EAAE,CAAC;QACxD,MAAM,UAAU,GAAG,IAAI,iCAAe,CAAC,KAAK,CAAC,CAAC;QAC9C,UAAU,CAAC,wBAAwB,GAAG,QAAQ,CAAC;QAC/C,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;IAC1C,CAAC;IACD,EAAE,CAAC,iBAAiB,EAAE,KAAK,IAAI,EAAE;QAC/B,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,MAAM,UAAU,EAAE,CAAC;QAC5D,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"} -------------------------------------------------------------------------------- /dist/tests/MapRecasterTest.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"MapRecasterTest.js","sourceRoot":"","sources":["../../src/tests/MapRecasterTest.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /dist/tests/StatParserTest.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const chai_1 = require("chai"); 4 | const StatParser_1 = require("../parsers/StatParser"); 5 | const testTexts = [ 6 | 'Stats for (Jason)[https://osu.ppy.sh/u/7342098] is Multiplaying:', 7 | 'Score: 18,163,888,782 (#1631)', 8 | 'Plays: 78245 (lv100)', 9 | 'Accuracy: 97.36%', 10 | 'Stats for (horcrux18)[https://osu.ppy.sh/u/8778911] is Afk:', 11 | 'Score: 584,565,786 (#260177)', 12 | 'Plays: 5695 (lv64)', 13 | 'Accuracy: 86.94%', 14 | 'Stats for (gviz)[https://osu.ppy.sh/u/15145414] is Multiplayer:', 15 | 'Score: 00 (#0)', 16 | 'Plays: 7 (lv2)', 17 | 'Accuracy: 0%', 18 | 'Stats for (Angel Arrow)[https://osu.ppy.sh/u/1970239] is Testing:', 19 | 'Score: 59,315,895,109 (#1006)', 20 | 'Plays: 104962 (lv102)', 21 | 'Accuracy: 98.16%', 22 | 'Stats for (Foreskin)[https://osu.ppy.sh/u/3760263]:', 23 | 'Score: 00 (#0)', 24 | 'Plays: 1 (lv1)', 25 | 'Accuracy: 0.00%' 26 | ]; 27 | const expectedResults = [ 28 | new StatParser_1.StatResult('Jason', 7342098, StatParser_1.StatStatuses.Multiplaying, 18163888782, 1631, 78245, 100, 97.36), 29 | new StatParser_1.StatResult('horcrux18', 8778911, StatParser_1.StatStatuses.Afk, 584565786, 260177, 5695, 64, 86.94), 30 | new StatParser_1.StatResult('gviz', 15145414, StatParser_1.StatStatuses.Multiplayer, 0, 0, 7, 2, 0), 31 | new StatParser_1.StatResult('Angel Arrow', 1970239, StatParser_1.StatStatuses.Testing, 59315895109, 1006, 104962, 102, 98.16), 32 | new StatParser_1.StatResult('Foreskin', 3760263, StatParser_1.StatStatuses.None, 0, 0, 1, 1, 0), 33 | ]; 34 | it('StatParser Test', function () { 35 | chai_1.assert.equal(testTexts.length, expectedResults.length * 4); 36 | const parser = new StatParser_1.StatParser(); 37 | chai_1.assert.isFalse(parser.isParsed); 38 | chai_1.assert.isFalse(parser.isParsing); 39 | chai_1.assert.isNull(parser.result); 40 | for (let i = 0; i < expectedResults.length; i++) { 41 | chai_1.assert.isFalse(parser.isParsing); 42 | for (let j = 0; j < 4; j++) { 43 | chai_1.assert.isTrue(parser.feedLine(testTexts[i * 4 + j])); 44 | if (j !== 3) { 45 | chai_1.assert.isTrue(parser.isParsing); 46 | chai_1.assert.isFalse(parser.isParsed); 47 | } 48 | } 49 | chai_1.assert.isFalse(parser.isParsing); 50 | chai_1.assert.isTrue(parser.isParsed); 51 | if (parser.result !== null) 52 | parser.result.date = 0; 53 | chai_1.assert.deepEqual(parser.result, expectedResults[i]); 54 | } 55 | }); 56 | //# sourceMappingURL=StatParserTest.js.map -------------------------------------------------------------------------------- /dist/tests/StatParserTest.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"StatParserTest.js","sourceRoot":"","sources":["../../src/tests/StatParserTest.ts"],"names":[],"mappings":";;AAAA,+BAA8B;AAC9B,sDAA6E;AAE7E,MAAM,SAAS,GAAG;IAChB,kEAAkE;IAClE,kCAAkC;IAClC,yBAAyB;IACzB,kBAAkB;IAClB,6DAA6D;IAC7D,iCAAiC;IACjC,uBAAuB;IACvB,kBAAkB;IAClB,iEAAiE;IACjE,mBAAmB;IACnB,mBAAmB;IACnB,cAAc;IACd,mEAAmE;IACnE,kCAAkC;IAClC,0BAA0B;IAC1B,kBAAkB;IAClB,qDAAqD;IACrD,mBAAmB;IACnB,mBAAmB;IACnB,iBAAiB;CAClB,CAAC;AAEF,MAAM,eAAe,GAAG;IACtB,IAAI,uBAAU,CAAE,OAAO,EAAE,OAAO,EAAE,yBAAY,CAAC,YAAY,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,CAAC;IAClG,IAAI,uBAAU,CAAC,WAAW,EAAE,OAAO,EAAE,yBAAY,CAAC,GAAG,EAAE,SAAW,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,CAAC;IAC5F,IAAI,uBAAU,CAAC,MAAM,EAAE,QAAQ,EAAE,yBAAY,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IACzE,IAAI,uBAAU,CAAC,aAAa,EAAE,OAAO,EAAE,yBAAY,CAAC,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,CAAC;IACnG,IAAI,uBAAU,CAAC,UAAU,EAAE,OAAO,EAAE,yBAAY,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;CACtE,CAAC;AAEF,EAAE,CAAC,iBAAiB,EAAE;IACpB,aAAM,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,EAAE,eAAe,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC3D,MAAM,MAAM,GAAG,IAAI,uBAAU,EAAE,CAAC;IAChC,aAAM,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAChC,aAAM,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACjC,aAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAE7B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,eAAe,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;QAC/C,aAAM,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QACjC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;YAC1B,aAAM,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YACrD,IAAI,CAAC,KAAK,CAAC,EAAE;gBACX,aAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;gBAChC,aAAM,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;aACjC;SACF;QACD,aAAM,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QACjC,aAAM,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC/B,IAAI,MAAM,CAAC,MAAM,KAAK,IAAI;YAAE,MAAM,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,CAAC;QACnD,aAAM,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC;KACrD;AACH,CAAC,CAAC,CAAC"} -------------------------------------------------------------------------------- /dist/trials/AppendersTrial.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"AppendersTrial.js","sourceRoot":"","sources":["../../src/trials/AppendersTrial.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /dist/trials/BanchoIrcTrial.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"BanchoIrcTrial.js","sourceRoot":"","sources":["../../src/trials/BanchoIrcTrial.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /dist/trials/HistryTrial.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | exports.trial = void 0; 7 | const axios_1 = __importDefault(require("axios")); 8 | const fs_1 = require("fs"); 9 | const HistoryFetcher_1 = require("../webapi/HistoryFetcher"); 10 | const HistoryRepository_1 = require("../webapi/HistoryRepository"); 11 | async function trial() { 12 | await GetOrderTrial(); 13 | } 14 | exports.trial = trial; 15 | async function GetHistryTrial() { 16 | // 67261609 17 | // 67268731 18 | const matchId = 76714773; 19 | // https://osu.ppy.sh/community/matches/${matchId}/history?before=1509690736&limit=100 20 | const url = `https://osu.ppy.sh/community/matches/${matchId}/`; 21 | const params = { 22 | 'limit': 100, 23 | 'before': 1695874063 24 | }; 25 | const response = await axios_1.default.get(url, { params }) 26 | .catch(err => { 27 | return err.response; 28 | }); 29 | console.log(JSON.stringify(response.data)); 30 | fs_1.promises.writeFile('data/arc/history_76714773_joinleftsametime.json', JSON.stringify(response.data)); 31 | } 32 | async function GetOrderTrial() { 33 | const matchId = 76714773; 34 | const repo = new HistoryRepository_1.HistoryRepository(matchId); 35 | const res = await repo.calcCurrentOrderAsName(); 36 | console.log(res); 37 | } 38 | async function GetLobbyNameChanger() { 39 | const hr = new HistoryRepository_1.HistoryRepository(67719013, new HistoryFetcher_1.HistoryFecher()); 40 | let ln = ''; 41 | hr.changedLobbyName.on(e => { 42 | console.log(`${e.oldName}->${e.newName} `); 43 | ln = e.newName; 44 | }); 45 | while (!ln.startsWith('4-5*')) { 46 | await hr.fetch(true); 47 | } 48 | } 49 | async function promiseTrial() { 50 | let task = delayAsync(100).then(() => 1); 51 | setImmediate(async () => { 52 | const n = await task; 53 | console.log(`i1 ${n}`); 54 | }); 55 | setImmediate(async () => { 56 | task = task.then(() => 2); 57 | const n = await task; 58 | console.log(`i2 ${n}`); 59 | }); 60 | setImmediate(async () => { 61 | task = task.then(() => 3); 62 | const n = await task; 63 | console.log(`i3 ${n}`); 64 | }); 65 | setImmediate(async () => { 66 | const n = await task; 67 | console.log(`i4 ${n}`); 68 | }); 69 | } 70 | async function delayAsync(ms) { 71 | if (ms === 0) 72 | return Promise.resolve(); 73 | return new Promise(resolve => setTimeout(resolve, ms)); 74 | } 75 | //# sourceMappingURL=HistryTrial.js.map -------------------------------------------------------------------------------- /dist/trials/HistryTrial.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"HistryTrial.js","sourceRoot":"","sources":["../../src/trials/HistryTrial.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /dist/trials/IrcTrial.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"IrcTrial.js","sourceRoot":"","sources":["../../src/trials/IrcTrial.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /dist/trials/LobbynameTrial.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.trial = void 0; 4 | function trial() { 5 | const cases = ['a', 'asdflkj', ' $% BN |~=', '4-5 | alt | test @join', 'あいうおaaa', 'aa\n\raa']; 6 | for (const c of cases) { 7 | console.log(`${c} => ${rep(c)}`); 8 | } 9 | } 10 | exports.trial = trial; 11 | function rep(text) { 12 | text = text.replace(/[^ -~]/g, ''); 13 | return text; 14 | } 15 | //# sourceMappingURL=LobbynameTrial.js.map -------------------------------------------------------------------------------- /dist/trials/LobbynameTrial.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"LobbynameTrial.js","sourceRoot":"","sources":["../../src/trials/LobbynameTrial.ts"],"names":[],"mappings":";;;AAAA,SAAgB,KAAK;IACnB,MAAM,KAAK,GAAG,CAAC,GAAG,EAAE,SAAS,EAAE,YAAY,EAAE,wBAAwB,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;IAC9F,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE;QACrB,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;KAClC;AACH,CAAC;AALD,sBAKC;AAED,SAAS,GAAG,CAAC,IAAY;IACvB,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IACnC,OAAO,IAAI,CAAC;AACd,CAAC"} -------------------------------------------------------------------------------- /dist/trials/TypedEventTrials.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.trial = void 0; 4 | const TypedEvent_1 = require("../libs/TypedEvent"); 5 | function trial() { 6 | const e1 = new TypedEvent_1.TypedEvent(); 7 | e1.once(n => console.log(`fired e1 arg = ${n}`)); 8 | e1.emit(1); 9 | const e2 = new TypedEvent_1.TypedEvent(); 10 | e2.once((t) => console.log(`fired e2 arg1 = ${t[0]} arg2 = ${t[1]}`)); 11 | e2.emit([1, 'x']); 12 | const e3 = new TypedEvent_1.TypedEvent(); 13 | e3.once((t) => console.log(`fired e2 a = ${t.a} b = ${t.b}`)); 14 | const a = 1; 15 | const b = 'x'; 16 | const c = 'c'; 17 | e3.emit({ a, b }); 18 | } 19 | exports.trial = trial; 20 | //# sourceMappingURL=TypedEventTrials.js.map -------------------------------------------------------------------------------- /dist/trials/TypedEventTrials.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"TypedEventTrials.js","sourceRoot":"","sources":["../../src/trials/TypedEventTrials.ts"],"names":[],"mappings":";;;AAAA,mDAAgD;AAEhD,SAAgB,KAAK;IACnB,MAAM,EAAE,GAAG,IAAI,uBAAU,EAAU,CAAC;IACpC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC,CAAC;IACjD,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAEX,MAAM,EAAE,GAAG,IAAI,uBAAU,EAAoB,CAAC;IAC9C,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACtE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;IAElB,MAAM,EAAE,GAAG,IAAI,uBAAU,EAA4B,CAAC;IACtD,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC9D,MAAM,CAAC,GAAG,CAAC,CAAC;IACZ,MAAM,CAAC,GAAG,GAAG,CAAC;IACd,MAAM,CAAC,GAAG,GAAG,CAAC;IACd,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AACpB,CAAC;AAfD,sBAeC"} -------------------------------------------------------------------------------- /dist/trials/WebApiTrial.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | exports.fetchUpdateTrial = exports.getTokenTrial = exports.getGuestTokenTrial = exports.trial = void 0; 7 | const axios_1 = __importDefault(require("axios")); 8 | const config_1 = __importDefault(require("config")); 9 | const WebApiClient_1 = require("../webapi/WebApiClient"); 10 | const oAuthConfig = config_1.default.get('WebApi'); 11 | async function trial() { 12 | //getTokenTrial(); 13 | const client = WebApiClient_1.WebApiClient; 14 | const user = await client.lookupBeatmapset(2647589); 15 | console.log(JSON.stringify(user)); 16 | } 17 | exports.trial = trial; 18 | async function getGuestTokenTrial() { 19 | try { 20 | const response = await axios_1.default.post('https://osu.ppy.sh/oauth/token', { 21 | 'grant_type': 'client_credentials', 22 | 'client_id': `${oAuthConfig.client_id}`, 23 | 'client_secret': oAuthConfig.client_secret, 24 | 'scope': 'public' 25 | }); 26 | const c = response.data; 27 | console.log(c); 28 | } 29 | catch (e) { 30 | console.error(`\n${e.message}\n${e.stack}`); 31 | } 32 | } 33 | exports.getGuestTokenTrial = getGuestTokenTrial; 34 | async function getTokenTrial() { 35 | try { 36 | const response = await axios_1.default.post('https://osu.ppy.sh/oauth/token', { 37 | 'grant_type': 'authorization_code', 38 | 'client_id': `${oAuthConfig.client_id}`, 39 | 'client_secret': oAuthConfig.client_secret, 40 | 'code': oAuthConfig.code, 41 | 'redirect_uri': oAuthConfig.callback 42 | }); 43 | const c = response.data; 44 | console.log(c); 45 | } 46 | catch (e) { 47 | console.error(`\n${e.message}\n${e.stack}`); 48 | } 49 | } 50 | exports.getTokenTrial = getTokenTrial; 51 | function objectToURLSearchParams(obj) { 52 | const param = new URLSearchParams(); 53 | for (const key in obj) { 54 | param.append(key, obj[key]); 55 | } 56 | return obj; 57 | } 58 | async function fetchUpdateTrial() { 59 | try { 60 | const r = await axios_1.default.get('https://osu.ppy.sh/community/chat/updates?since=2065115911'); 61 | const c = r.data; 62 | console.log(c); 63 | } 64 | catch (e) { 65 | console.error(`\n${e.message}\n${e.stack}`); 66 | } 67 | } 68 | exports.fetchUpdateTrial = fetchUpdateTrial; 69 | //# sourceMappingURL=WebApiTrial.js.map -------------------------------------------------------------------------------- /dist/trials/WebApiTrial.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"WebApiTrial.js","sourceRoot":"","sources":["../../src/trials/WebApiTrial.ts"],"names":[],"mappings":";;;;;;AAAA,kDAA0B;AAC1B,oDAA4B;AAC5B,yDAAsD;AAQtD,MAAM,WAAW,GAAG,gBAAM,CAAC,GAAG,CAAoB,QAAQ,CAAC,CAAC;AAErD,KAAK,UAAU,KAAK;IACzB,kBAAkB;IAElB,MAAM,MAAM,GAAG,2BAAY,CAAC;IAE5B,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;IACpD,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;AACpC,CAAC;AAPD,sBAOC;AAEM,KAAK,UAAU,kBAAkB;IACtC,IAAI;QACF,MAAM,QAAQ,GAAG,MAAM,eAAK,CAAC,IAAI,CAAC,gCAAgC,EAAE;YAClE,YAAY,EAAE,oBAAoB;YAClC,WAAW,EAAE,GAAG,WAAW,CAAC,SAAS,EAAE;YACvC,eAAe,EAAE,WAAW,CAAC,aAAa;YAC1C,OAAO,EAAE,QAAQ;SAClB,CAAC,CAAC;QACH,MAAM,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC;QACxB,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;KAChB;IAAC,OAAO,CAAM,EAAE;QACf,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;KAC7C;AACH,CAAC;AAbD,gDAaC;AAEM,KAAK,UAAU,aAAa;IACjC,IAAI;QACF,MAAM,QAAQ,GAAG,MAAM,eAAK,CAAC,IAAI,CAAC,gCAAgC,EAAE;YAClE,YAAY,EAAE,oBAAoB;YAClC,WAAW,EAAE,GAAG,WAAW,CAAC,SAAS,EAAE;YACvC,eAAe,EAAE,WAAW,CAAC,aAAa;YAC1C,MAAM,EAAE,WAAW,CAAC,IAAI;YACxB,cAAc,EAAE,WAAW,CAAC,QAAQ;SACrC,CAAC,CAAC;QACH,MAAM,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC;QACxB,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;KAChB;IAAC,OAAO,CAAM,EAAE;QACf,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;KAC7C;AACH,CAAC;AAdD,sCAcC;AAED,SAAS,uBAAuB,CAAC,GAAQ;IACvC,MAAM,KAAK,GAAG,IAAI,eAAe,EAAE,CAAC;IACpC,KAAK,MAAM,GAAG,IAAI,GAAG,EAAE;QACrB,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;KAC7B;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAEM,KAAK,UAAU,gBAAgB;IACpC,IAAI;QACF,MAAM,CAAC,GAAG,MAAM,eAAK,CAAC,GAAG,CAAC,4DAA4D,CAAC,CAAC;QACxF,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;QACjB,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;KAChB;IAAC,OAAO,CAAM,EAAE;QACf,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;KAC7C;AACH,CAAC;AARD,4CAQC"} -------------------------------------------------------------------------------- /dist/trials/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | //import * as trial from './WebServerTrial.js'; 3 | //trial.webServerTrial(); 4 | Object.defineProperty(exports, "__esModule", { value: true }); 5 | const DiscordTrial_1 = require("./DiscordTrial"); 6 | (0, DiscordTrial_1.trial)(); 7 | //# sourceMappingURL=index.js.map -------------------------------------------------------------------------------- /dist/trials/index.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/trials/index.ts"],"names":[],"mappings":";AAAA,+CAA+C;AAC/C,yBAAyB;;AAEzB,iDAAuC;AACvC,IAAA,oBAAK,GAAE,CAAC"} -------------------------------------------------------------------------------- /dist/web/LogServer.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | exports.startLogServer = void 0; 7 | const express_1 = __importDefault(require("express")); 8 | const fs_1 = __importDefault(require("fs")); 9 | const readline_1 = __importDefault(require("readline")); 10 | function startLogServer(port) { 11 | const app = (0, express_1.default)(); 12 | app.use('', express_1.default.static('src/web/statics')); 13 | app.use('/logs', express_1.default.static('logs/cli')); 14 | app.get('/api/clilog', (req, res, next) => { 15 | fs_1.default.readdir('logs/cli', (err, files) => { 16 | if (err) 17 | throw err; 18 | const r = []; 19 | for (const f of files) { 20 | const m = f.match(/(\d+)\.log/); 21 | if (m) { 22 | r.push(parseInt(m[1])); 23 | } 24 | } 25 | res.json(r); 26 | }); 27 | }); 28 | app.get('/api/clilog/:id', (req, res, next) => { 29 | const p = `logs/cli/${req.params.id}.log`; 30 | let frm = 0; 31 | if (req.query.from) { 32 | frm = parseInt(`${req.query.from}`); 33 | } 34 | const stream = fs_1.default.createReadStream(p, { start: frm }); 35 | const reader = readline_1.default.createInterface({ input: stream }); 36 | const result = { 37 | lines: [], 38 | end: 0 39 | }; 40 | reader.on('line', (data) => { 41 | result.lines.push(data); 42 | }); 43 | reader.on('close', () => { 44 | result.end = stream.bytesRead + frm; 45 | res.json(result); 46 | }); 47 | stream.on('error', (e) => { 48 | console.log('cought error'); 49 | next(e); 50 | }); 51 | }); 52 | app.get('/api/clilog/size/:id', (req, res, next) => { 53 | const p = `logs/cli/${req.params.id}.log`; 54 | let frm = 0; 55 | if (req.query.from) { 56 | frm = parseInt(`${req.query.from}`); 57 | } 58 | fs_1.default.stat(p, (e, stats) => { 59 | if (e) { 60 | next(e); 61 | } 62 | else { 63 | res.json(stats.size); 64 | } 65 | }); 66 | }); 67 | app.get('/api/close', (req, res, next) => { 68 | server.close(); 69 | }); 70 | const server = app.listen(port, () => { 71 | console.log(`Server running at http://${'localhost'}:${port}/`); 72 | }); 73 | process.on('exit', (code) => { 74 | server.close(); 75 | }); 76 | return server; 77 | } 78 | exports.startLogServer = startLogServer; 79 | //startLogServer(); 80 | //# sourceMappingURL=LogServer.js.map -------------------------------------------------------------------------------- /dist/web/LogServer.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"LogServer.js","sourceRoot":"","sources":["../../src/web/LogServer.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /dist/web/OahrWeb.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | exports.OahrWeb = void 0; 7 | const config_1 = __importDefault(require("config")); 8 | const express_1 = __importDefault(require("express")); 9 | const OahrWebDefaultOption = config_1.default.get('OahrWeb'); 10 | class OahrWeb { 11 | constructor() { 12 | this.config = OahrWebDefaultOption; 13 | this.app = (0, express_1.default)(); 14 | this.app.use(express_1.default.static(this.config.staticDir)); 15 | this.server = this.app.listen(this.config.port, this.config.hostname, () => { 16 | console.log(`Server running at http://${this.config.hostname}:${this.config.port}/`); 17 | }); 18 | this.app.get('/api/test/:id', (req, res, next) => { 19 | const re = { 20 | test: 'hello', 21 | id: req.params.id 22 | }; 23 | res.json(re); 24 | }); 25 | } 26 | } 27 | exports.OahrWeb = OahrWeb; 28 | //# sourceMappingURL=OahrWeb.js.map -------------------------------------------------------------------------------- /dist/web/OahrWeb.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"OahrWeb.js","sourceRoot":"","sources":["../../src/web/OahrWeb.ts"],"names":[],"mappings":";;;;;;AAAA,oDAA4B;AAC5B,sDAA2C;AAS3C,MAAM,oBAAoB,GAAG,gBAAM,CAAC,GAAG,CAAgB,SAAS,CAAC,CAAC;AAElE,MAAa,OAAO;IAKlB;QACE,IAAI,CAAC,MAAM,GAAG,oBAAoB,CAAC;QACnC,IAAI,CAAC,GAAG,GAAG,IAAA,iBAAO,GAAE,CAAC;QACrB,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,iBAAO,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;QACpD,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,GAAG,EAAE;YACzE,OAAO,CAAC,GAAG,CAAC,4BAA4B,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,CAAC;QACvF,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,eAAe,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;YAC/C,MAAM,EAAE,GAAG;gBACT,IAAI,EAAC,OAAO;gBACZ,EAAE,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE;aAClB,CAAC;YACF,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,CAAC,CAAC,CAAC;IACL,CAAC;CACF;AArBD,0BAqBC"} -------------------------------------------------------------------------------- /dist/web/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const LogServer_1 = require("./LogServer"); 4 | (0, LogServer_1.startLogServer)(3112); 5 | //# sourceMappingURL=index.js.map -------------------------------------------------------------------------------- /dist/web/index.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/web/index.ts"],"names":[],"mappings":";;AAAA,2CAA6C;AAE7C,IAAA,0BAAc,EAAC,IAAI,CAAC,CAAC"} -------------------------------------------------------------------------------- /dist/webapi/Beatmapsets.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | //# sourceMappingURL=Beatmapsets.js.map -------------------------------------------------------------------------------- /dist/webapi/Beatmapsets.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"Beatmapsets.js","sourceRoot":"","sources":["../../src/webapi/Beatmapsets.ts"],"names":[],"mappings":""} -------------------------------------------------------------------------------- /dist/webapi/HistoryFetcher.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | exports.HistoryFecher = void 0; 7 | const axios_1 = __importDefault(require("axios")); 8 | class HistoryFecher { 9 | async fetchHistory(limit, before, after, matchId) { 10 | const url = `https://osu.ppy.sh/community/matches/${matchId}`; 11 | const params = { 12 | 'limit': limit, 13 | }; 14 | if (before) { 15 | params.before = before; 16 | } 17 | if (after) { 18 | params.after = after; 19 | } 20 | return (await axios_1.default.get(url, { params })).data; 21 | } 22 | } 23 | exports.HistoryFecher = HistoryFecher; 24 | //# sourceMappingURL=HistoryFetcher.js.map -------------------------------------------------------------------------------- /dist/webapi/HistoryFetcher.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"HistoryFetcher.js","sourceRoot":"","sources":["../../src/webapi/HistoryFetcher.ts"],"names":[],"mappings":";;;;;;AAAA,kDAA0B;AAe1B,MAAa,aAAa;IACxB,KAAK,CAAC,YAAY,CAAC,KAAa,EAAE,MAAqB,EAAE,KAAoB,EAAE,OAAe;QAC5F,MAAM,GAAG,GAAG,wCAAwC,OAAO,EAAE,CAAC;QAC9D,MAAM,MAAM,GAAQ;YAClB,OAAO,EAAE,KAAK;SACf,CAAC;QACF,IAAI,MAAM,EAAE;YACV,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;SACxB;QAED,IAAI,KAAK,EAAE;YACT,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;SACtB;QAED,OAAO,CAAC,MAAM,eAAK,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IACjD,CAAC;CACF;AAhBD,sCAgBC"} -------------------------------------------------------------------------------- /dist/webapi/HistoryTypes.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | //# sourceMappingURL=HistoryTypes.js.map -------------------------------------------------------------------------------- /dist/webapi/HistoryTypes.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"HistoryTypes.js","sourceRoot":"","sources":["../../src/webapi/HistoryTypes.ts"],"names":[],"mappings":""} -------------------------------------------------------------------------------- /dist/webapi/UserProfile.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.trimProfile = void 0; 4 | /** 5 | * データ容量節約のため、余計なデータを取り除く 6 | */ 7 | function trimProfile(data) { 8 | return { 9 | avatar_url: data.avatar_url, 10 | country_code: data.country_code, 11 | default_group: data.default_group, 12 | id: data.id, 13 | is_active: data.is_active, 14 | is_bot: data.is_bot, 15 | is_online: data.is_online, 16 | is_supporter: data.is_supporter, 17 | last_visit: data.last_visit, 18 | pm_friends_only: data.pm_friends_only, 19 | username: data.username, 20 | join_date: data.join_date, 21 | country: { code: data.country.code, name: data.country.name }, 22 | previous_usernames: data.previous_usernames, 23 | statistics: data.statistics, 24 | support_level: data.support_level, 25 | get_time: data.get_time 26 | }; 27 | } 28 | exports.trimProfile = trimProfile; 29 | //# sourceMappingURL=UserProfile.js.map -------------------------------------------------------------------------------- /dist/webapi/UserProfile.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"UserProfile.js","sourceRoot":"","sources":["../../src/webapi/UserProfile.ts"],"names":[],"mappings":";;;AAwFA;;GAEG;AACH,SAAgB,WAAW,CAAC,IAAiB;IAC3C,OAAO;QACL,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,YAAY,EAAE,IAAI,CAAC,YAAY;QAC/B,aAAa,EAAE,IAAI,CAAC,aAAa;QACjC,EAAE,EAAE,IAAI,CAAC,EAAE;QACX,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,YAAY,EAAE,IAAI,CAAC,YAAY;QAC/B,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,eAAe,EAAE,IAAI,CAAC,eAAe;QACrC,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE;QAC7D,kBAAkB,EAAE,IAAI,CAAC,kBAAkB;QAC3C,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,aAAa,EAAE,IAAI,CAAC,aAAa;QACjC,QAAQ,EAAE,IAAI,CAAC,QAAQ;KACT,CAAC;AACnB,CAAC;AApBD,kCAoBC"} -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "osu-ahr", 3 | "version": "1.6.1", 4 | "description": "irc bot for osu! multi lobby auto host rotation.", 5 | "main": "dist/cli/index.js", 6 | "homepage": "https://github.com/Meowhal/osu-ahr", 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/Meowhal/osu-ahr.git" 10 | }, 11 | "scripts": { 12 | "dist": "rimraf dist && tsc", 13 | "clean": "rimraf dist", 14 | "build": "tsc", 15 | "lint": "eslint src", 16 | "lint:fix": "eslint src --fix", 17 | "start": "node dist/cli/index.js", 18 | "start:discord": "node dist/discord/index.js", 19 | "node:cli": "node dist/cli/index.js", 20 | "node:discord": "node dist/discord/index.js", 21 | "dev:cli": "ts-node src/cli/index.ts", 22 | "dev:discord": "ts-node src/discord/index.ts", 23 | "test": "mocha -r ts-node/register src/tests/*Test.ts", 24 | "test:watch": "mocha -r ts-node/register src/tests/*Test.ts --watch --watch-files src/**/*.ts", 25 | "trial": "ts-node src/trials/index.ts", 26 | "dev:web": "ts-node src/web/index.ts", 27 | "dev:log": "ts-node src/cli/LogServer.ts" 28 | }, 29 | "author": "meowhal", 30 | "license": "MIT", 31 | "dependencies": { 32 | "@discordjs/builders": "^0.12.0", 33 | "axios": "^0.25.0", 34 | "config": "^3.3.7", 35 | "discord.js": "^13.6.0", 36 | "dotenv": "^16.0.1", 37 | "express": "^4.17.2", 38 | "irc-upd": "^0.11.0", 39 | "log4js": "^6.4.1", 40 | "open": "^8.4.0" 41 | }, 42 | "devDependencies": { 43 | "@types/chai": "^4.3.0", 44 | "@types/config": "^0.0.39", 45 | "@types/express": "^4.17.13", 46 | "@types/mocha": "^9.1.0", 47 | "@types/node": "^16.11.21", 48 | "@types/sinon": "^10.0.9", 49 | "@typescript-eslint/eslint-plugin": "^5.22.0", 50 | "@typescript-eslint/parser": "^5.22.0", 51 | "chai": "^4.3.6", 52 | "cross-env": "^7.0.3", 53 | "eslint": "^8.14.0", 54 | "eslint-config-standard": "^17.0.0", 55 | "eslint-plugin-import": "^2.26.0", 56 | "eslint-plugin-n": "^15.2.0", 57 | "eslint-plugin-promise": "^6.0.0", 58 | "mocha": "^9.2.0", 59 | "rimraf": "^3.0.2", 60 | "sinon": "^11.1.2", 61 | "ts-node": "^10.4.0", 62 | "typescript": "^4.5.5" 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/IIrcClient.ts: -------------------------------------------------------------------------------- 1 | import * as irc from './libs/irc'; 2 | import { IsStatResponse } from './parsers/StatParser'; 3 | import { EventEmitter } from 'events'; 4 | import { getLogger } from './Loggers'; 5 | 6 | const ircLogger = getLogger('irc'); 7 | const pmLogger = getLogger('pm'); 8 | 9 | // テスト用に使用する部分をインターフェースとして定義する 10 | // typescriptのインターフェースはダックタイピング可能なので、 11 | // このインターフェースで宣言しておけばダミーと本物どちらも取り扱える(はず 12 | export interface IIrcClient extends EventEmitter { 13 | hostMask: string; 14 | nick: string; 15 | conn: any; 16 | join(channel: string, callback?: irc.handlers.IJoinChannel | undefined): void; 17 | part(channel: string, message: string, callback: irc.handlers.IPartChannel): void; 18 | say(target: string, message: string): void; 19 | connect(retryCount?: number | irc.handlers.IRaw | undefined, callback?: irc.handlers.IRaw | undefined): void; 20 | disconnect(message: string, callback: () => void): void; 21 | } 22 | 23 | export function logIrcEvent(client: IIrcClient) { 24 | client.on('error', function (message) { 25 | ircLogger.error(`@NodeIRC#error\n${message instanceof Error ? `${message.message}\n${message.stack}\n` : ''}${message instanceof Object && JSON.stringify(message) !== '{}' ? `${JSON.stringify(message, null, 2)}\n` : ''}message =`, message); 26 | }); 27 | client.on('registered', function (message) { 28 | const args = message.args as string[] | undefined; 29 | ircLogger.debug(`@NodeIRC#registered ${args?.join(', ')}`); 30 | }); 31 | client.on('message', function (from, to, message) { 32 | ircLogger.debug(`@NodeIRC#message ${from} => ${to}: ${message}`); 33 | }); 34 | client.on('pm', function (nick, message) { 35 | ircLogger.debug(`@NodeIRC#pm ${nick}: ${message}`); 36 | }); 37 | client.on('join', function (channel, who) { 38 | ircLogger.debug(`@NodeIRC#join ${who} has joined ${channel}`); 39 | }); 40 | client.on('part', function (channel, who, reason) { 41 | ircLogger.debug(`@NodeIRC#part ${who} has left ${channel}: ${reason}`); 42 | }); 43 | client.on('kick', function (channel, who, by, reason) { 44 | ircLogger.debug(`@NodeIRC#kick ${who} was kicked from ${channel} by ${by}: ${reason}`); 45 | }); 46 | client.on('invite', (channel, from) => { 47 | ircLogger.debug(`@NodeIRC#invite ${from} invited you to ${channel}`); 48 | }); 49 | client.on('notice', function (from, to, message) { 50 | ircLogger.debug(`@NodeIRC#notice ${from} => ${to}: ${message}`); 51 | }); 52 | client.on('action', function (from, to, text, message) { 53 | ircLogger.debug(`@NodeIRC#action ${from} => ${to}: ${text}`); 54 | }); 55 | client.on('selfMessage', (target: string, toSend) => { 56 | ircLogger.debug(`@NodeIRC#selfMessage Bot => ${target}: ${toSend}`); 57 | }); 58 | } 59 | 60 | export function logPrivateMessage(client: IIrcClient) { 61 | client.on('message', (from, to, message) => { 62 | if (to === client.nick) { 63 | if (IsStatResponse(message)) { 64 | pmLogger.trace(`@NodeIRC#message PM: ${from} -> ${message}`); 65 | } else { 66 | pmLogger.info(`@NodeIRC#message PM: ${from} -> ${message}`); 67 | } 68 | } 69 | }); 70 | } 71 | -------------------------------------------------------------------------------- /src/Loggers.ts: -------------------------------------------------------------------------------- 1 | import log4js from 'log4js'; 2 | export type Logger = log4js.Logger; 3 | 4 | function selectConfigPath() { 5 | const proc = process.argv[0]; 6 | const exeFile = process.argv[1]; 7 | const hasVerboseFlag = process.argv.some(v => v === '--verbose' || v === '-v'); 8 | 9 | if (exeFile.includes('discord')) { 10 | return './config/log_discord.json'; 11 | } else if (exeFile.includes('mocha')) { 12 | if (hasVerboseFlag) { 13 | return './config/log_mocha_verbose.json'; 14 | } else { 15 | return './config/log_mocha.json'; 16 | } 17 | } else if (proc.includes('ts-node') || hasVerboseFlag) { 18 | return './config/log_cli_verbose.json'; 19 | } else { 20 | return './config/log_cli.json'; 21 | } 22 | } 23 | 24 | const path = selectConfigPath(); 25 | console.log(`Loading log4js configuration from ${path}`); 26 | log4js.configure(path); 27 | 28 | export function getLogger(category?: string | undefined): Logger { 29 | const l = log4js.getLogger(category); 30 | l.addContext('channel', 'ahr'); // set default channel 31 | return l; 32 | } -------------------------------------------------------------------------------- /src/Player.ts: -------------------------------------------------------------------------------- 1 | import { StatResult } from './parsers/StatParser'; 2 | import { UserProfile } from './webapi/UserProfile'; 3 | 4 | export class Player { 5 | id: number = 0; 6 | name: string; 7 | escaped_name: string; 8 | role: Roles = Roles.Player; 9 | team: Teams = Teams.None; // いつteammodeに変更されたか検知する方法がないので、正確な情報ではない 10 | slot: number = 0; 11 | mpstatus: MpStatuses = MpStatuses.None; 12 | laststat: StatResult | null = null; 13 | profile: UserProfile | null = null; 14 | 15 | constructor(name: string) { 16 | this.name = name; 17 | this.escaped_name = escapeUserName(name); 18 | } 19 | is(r: Roles): boolean { 20 | return (this.role & r) !== 0; 21 | } 22 | get isPlayer(): boolean { 23 | return this.is(Roles.Player); 24 | } 25 | get isHost(): boolean { 26 | return this.is(Roles.Host); 27 | } 28 | get isAuthorized(): boolean { 29 | return this.is(Roles.Authorized); 30 | } 31 | get isReferee(): boolean { 32 | return this.is(Roles.Referee); 33 | } 34 | get isCreator(): boolean { 35 | return this.is(Roles.Creator); 36 | } 37 | setRole(r: Roles): void { 38 | this.role |= r; 39 | } 40 | removeRole(r: Roles): void { 41 | this.role &= ~r; 42 | } 43 | toString(): string { 44 | return `Player{id:${this.name}, slot:${this.slot}, role:${this.role}}`; 45 | } 46 | } 47 | 48 | export enum Roles { 49 | None = 0, 50 | Player = 1, 51 | Host = 2, 52 | Authorized = 4, 53 | Referee = 8, 54 | Creator = 16 55 | } 56 | 57 | export enum Teams { 58 | None, 59 | Blue, 60 | Red, 61 | } 62 | 63 | export enum MpStatuses { 64 | None, 65 | InLobby, 66 | Playing, 67 | Finished, 68 | } 69 | 70 | /** 71 | * Nameの表記ゆれを統一する 72 | * @param name 73 | */ 74 | export function escapeUserName(name: string): string { 75 | return name.toLowerCase().replace(/ /g, '_'); 76 | } 77 | 78 | /** 79 | * UserNameを表示するときhighlightされないように名前を変更する 80 | * @param username 81 | */ 82 | export function disguiseUserName(username: string): string { 83 | return `${username[0]}\u{200B}${username.substring(1)}`; 84 | } 85 | 86 | /** 87 | * disguiseUserNameで変更を加えた文字列をもとに戻す 88 | * @param disguisedName 89 | */ 90 | export function revealUserName(disguisedName: string): string { 91 | return disguisedName.replace(/\u200B/g, ''); 92 | } 93 | -------------------------------------------------------------------------------- /src/cli/LogServer.ts: -------------------------------------------------------------------------------- 1 | import { startLogServer } from '../web/LogServer'; 2 | import config from 'config'; 3 | 4 | export interface LogServerOption { 5 | port: number; 6 | } 7 | 8 | const options = config.get('LogServer'); 9 | 10 | startLogServer(options.port); 11 | -------------------------------------------------------------------------------- /src/cli/OahrHeadless.ts: -------------------------------------------------------------------------------- 1 | import { IIrcClient } from '../IIrcClient'; 2 | import { getLogger } from '../Loggers'; 3 | import { OahrBase } from './OahrBase'; 4 | 5 | const logger = getLogger('hl'); 6 | 7 | export class OahrHeadless extends OahrBase { 8 | 9 | constructor(client: IIrcClient) { 10 | super(client); 11 | client.once('part', () => { 12 | logger.info('Part event detected. Closing...'); 13 | process.exit(0); 14 | }); 15 | } 16 | 17 | start(command: string, arg: string): void { 18 | try { 19 | switch (command) { 20 | case 'm': 21 | this.makeLobbyAsync(arg); 22 | break; 23 | case 'e': 24 | this.enterLobbyAsync(arg); 25 | break; 26 | default: 27 | process.exit(1); 28 | } 29 | } catch (e: any) { 30 | logger.error(`@OahrHeadless#start\n${e}`); 31 | process.exit(1); 32 | } 33 | 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/cli/index.ts: -------------------------------------------------------------------------------- 1 | import { getLogger } from '../Loggers'; 2 | 3 | import * as irc from '../libs/irc'; 4 | import { OahrCli } from './OahrCli'; 5 | import { OahrHeadless } from './OahrHeadless'; 6 | import { logIrcEvent, logPrivateMessage } from '../IIrcClient'; 7 | import { CONFIG_OPTION, getIrcConfig } from '../TypedConfig'; 8 | import { applySpeedLimit } from '../libs/ChatLimiter'; 9 | 10 | const logger = getLogger('pre'); 11 | logger.info('Starting up...'); 12 | 13 | try { 14 | CONFIG_OPTION.USE_ENV = true; 15 | const c = getIrcConfig(); 16 | if (c.nick === 'your account id' || c.opt.password === 'you can get password from \'https://osu.ppy.sh/p/irc\'') { 17 | logger.error('You must enter your account ID and IRC password in the config file.'); 18 | logger.error('You can get your IRC password in \'https://osu.ppy.sh/p/irc\' '); 19 | logger.error('Copy config/default.json to config/local.json, and then enter your account ID and IRC password.'); 20 | process.exit(1); 21 | } 22 | 23 | const client = new irc.Client(c.server, c.nick, c.opt); 24 | client.on('error', err => { 25 | if (err.command === 'err_passwdmismatch') { 26 | logger.error(`${err.command}: ${err.args.join(' ')}`); 27 | logger.error('Check your account ID and IRC password.'); 28 | process.exit(1); 29 | } 30 | }); 31 | 32 | applySpeedLimit(client, 10, 5000); 33 | 34 | logIrcEvent(client); 35 | logPrivateMessage(client); 36 | 37 | if (process.argv.length > 2) { 38 | const command = process.argv[2]; 39 | const oahr = new OahrHeadless(client); 40 | const arg = process.argv.slice(3).join(' '); 41 | oahr.start(command, arg); 42 | } else { 43 | const oahr = new OahrCli(client); 44 | oahr.start(null); 45 | } 46 | } catch (e: any) { 47 | logger.error(`@cli-index\n${e}`); 48 | process.exit(1); 49 | } 50 | -------------------------------------------------------------------------------- /src/discord/BotCommand.ts: -------------------------------------------------------------------------------- 1 | import { ApplicationCommandData } from 'discord.js'; 2 | 3 | // coded by https://autocode.com/tools/discord/command-builder/ 4 | export const BotCommands: ApplicationCommandData[] = [ 5 | { 6 | name: 'make', 7 | description: 'Make a tournament lobby.', 8 | defaultPermission: false, 9 | options: [ 10 | { 11 | type: 3, 12 | name: 'lobby_name', 13 | description: 'The initial lobby name that\'ll be set, e.g., "4.00-5.99 auto host rotation"', 14 | required: true 15 | } 16 | ] 17 | }, 18 | { 19 | name: 'enter', 20 | description: 'Enter a lobby.', 21 | defaultPermission: false, 22 | options: [ 23 | { 24 | type: 4, 25 | name: 'lobby_id', 26 | description: 'The tournament lobby ID of the lobby to enter.', 27 | required: false 28 | } 29 | ] 30 | }, 31 | { 32 | name: 'info', 33 | description: 'Show the status of a lobby.', 34 | defaultPermission: false, 35 | options: [ 36 | { 37 | type: 4, 38 | name: 'lobby_id', 39 | description: 'The tournament lobby ID of the lobby to show it\'s status.', 40 | required: false 41 | } 42 | ] 43 | }, 44 | { 45 | name: 'say', 46 | description: 'Send a message to a lobby.', 47 | defaultPermission: false, 48 | options: [ 49 | { 50 | type: 3, 51 | name: 'message', 52 | description: 'The message to send.', 53 | required: true 54 | }, 55 | { 56 | type: 4, 57 | name: 'lobby_id', 58 | description: 'The tournament lobby ID of a lobby to send a message to.', 59 | required: false 60 | } 61 | ] 62 | }, 63 | { 64 | name: 'config', 65 | description: 'Configure the auto host rotation bot.', 66 | defaultPermission: false, 67 | options: [ 68 | { 69 | type: 3, 70 | name: 'section', 71 | description: 'The configuration section to edit.', 72 | required: true 73 | }, 74 | { 75 | type: 3, 76 | name: 'name', 77 | description: 'The configuration name to edit.', 78 | required: true 79 | }, 80 | { 81 | type: 3, 82 | name: 'value', 83 | description: 'The new configuration value to set.', 84 | required: true 85 | } 86 | ] 87 | }, 88 | { 89 | name: 'close', 90 | description: 'Close a lobby.', 91 | defaultPermission: false, 92 | options: [ 93 | { 94 | type: 4, 95 | name: 'lobby_id', 96 | description: 'The tournament lobby ID of a lobby to close.', 97 | required: false 98 | } 99 | ] 100 | }, 101 | { 102 | name: 'quit', 103 | description: 'Quit managing a lobby.', 104 | defaultPermission: false, 105 | options: [ 106 | { 107 | type: 4, 108 | name: 'lobby_id', 109 | description: 'The tournament lobby ID of a lobby to quit managing.', 110 | required: false 111 | } 112 | ] 113 | } 114 | ]; 115 | -------------------------------------------------------------------------------- /src/discord/index.ts: -------------------------------------------------------------------------------- 1 | import { getLogger } from '../Loggers'; 2 | 3 | import * as irc from '../libs/irc'; 4 | import { Client, Intents } from 'discord.js'; 5 | import { DiscordBot } from './DiscordBot'; 6 | import { logIrcEvent, logPrivateMessage } from '../IIrcClient'; 7 | import { CONFIG_OPTION, getIrcConfig } from '../TypedConfig'; 8 | import { applySpeedLimit } from '../libs/ChatLimiter'; 9 | 10 | const logger = getLogger('pre'); 11 | logger.info('Starting up...'); 12 | 13 | try { 14 | CONFIG_OPTION.USE_ENV = true; 15 | const c = getIrcConfig(); 16 | if (c.nick === 'your account id' || c.opt.password === 'you can get password from \'https://osu.ppy.sh/p/irc\'') { 17 | logger.error('You must enter your account ID and IRC password in the config file.'); 18 | logger.error('You can get your IRC password in \'https://osu.ppy.sh/p/irc\' '); 19 | logger.error('Copy config/default.json to config/local.json, and then enter your account ID and IRC password.'); 20 | process.exit(1); 21 | } 22 | 23 | const ircClient = new irc.Client(c.server, c.nick, c.opt); 24 | ircClient.on('error', err => { 25 | if (err.command === 'err_passwdmismatch') { 26 | logger.error(`${err.command}: ${err.args.join(' ')}`); 27 | logger.error('Check your account ID and IRC password.'); 28 | process.exit(1); 29 | } 30 | }); 31 | applySpeedLimit(ircClient, 10, 5000); 32 | logIrcEvent(ircClient); 33 | logPrivateMessage(ircClient); 34 | 35 | const discordClient = new Client({ intents: [Intents.FLAGS.GUILDS, Intents.FLAGS.GUILD_INTEGRATIONS, Intents.FLAGS.GUILD_MEMBERS, Intents.FLAGS.GUILD_MESSAGES] }); 36 | 37 | const bot = new DiscordBot(ircClient, discordClient); 38 | bot.start(); 39 | } catch (e: any) { 40 | logger.error(`@discord-index\n${e}`); 41 | process.exit(1); 42 | } 43 | -------------------------------------------------------------------------------- /src/dummies/DummyLobbyPlugin.ts: -------------------------------------------------------------------------------- 1 | import { Lobby } from '../Lobby'; 2 | import { LobbyPlugin } from '../plugins/LobbyPlugin'; 3 | 4 | export class DummyLobbyPlugin extends LobbyPlugin { 5 | 6 | constructor(lobby: Lobby) { 7 | super(lobby, 'dummy'); 8 | } 9 | 10 | GetPluginStatus(): string { 11 | return `-- Dummy Lobby Plugin -- 12 | this is dummy lobby info 13 | `; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/libs/ChatLimiter.ts: -------------------------------------------------------------------------------- 1 | import { IIrcClient } from '../IIrcClient'; 2 | 3 | export function applySpeedLimit(ircClient: IIrcClient, tokens: number = 10, periodMs: number = 5000): { dispose: () => void } { 4 | const queue: { target: string, message: string }[] = []; 5 | const waitTime = periodMs / tokens; 6 | let lastChatAt: number = 0; 7 | let timeId: NodeJS.Timeout | undefined; 8 | const originalSay = ircClient.say.bind(ircClient); 9 | 10 | const sayWrapper = (target: string, message: string) => { 11 | message.split(/\r?\n/).filter(l => l.length > 0).forEach(l => queueMessage(target, l)); 12 | }; 13 | 14 | const queueMessage = (target: string, message: string) => { 15 | if (timeId) { 16 | queue.push({ target, message }); 17 | return; 18 | } 19 | 20 | if (Date.now() < lastChatAt + waitTime) { 21 | queue.push({ target, message }); 22 | waitAndSay(); 23 | return; 24 | } 25 | 26 | originalSay(target, message); 27 | lastChatAt = Date.now(); 28 | }; 29 | 30 | const waitAndSay = () => { 31 | if (queue.length === 0) return; 32 | let wt = lastChatAt + waitTime - Date.now(); 33 | if (wt < 0) wt = 0; 34 | timeId = setTimeout(() => { 35 | timeId = undefined; 36 | const task = queue.shift(); 37 | if (task) { 38 | originalSay(task.target, task.message); 39 | lastChatAt = Date.now(); 40 | waitAndSay(); 41 | } 42 | }, wt); 43 | }; 44 | 45 | ircClient.say = sayWrapper; 46 | 47 | return { 48 | dispose: () => { 49 | if (timeId) { 50 | clearTimeout(timeId); 51 | } 52 | queue.length = 0; 53 | } 54 | }; 55 | } 56 | -------------------------------------------------------------------------------- /src/libs/DeferredAction.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 延期可能な遅延実行アクションを表現するクラス。 3 | */ 4 | export class DeferredAction { 5 | /** actionに渡されるパラメタ */ 6 | param: T | undefined; 7 | /** 遅延実行される関数 */ 8 | action: (p: T) => void; 9 | private timeId: NodeJS.Timeout | null = null; 10 | constructor(action: (p: T) => void) { 11 | this.action = action; 12 | } 13 | 14 | /** 15 | * アクションの遅延実行を開始する 16 | * @param delay 遅延時間 ms 17 | * @param param アクションに渡されるパラメータ 18 | * @param resetTimer 現在の遅延時間をリセットするか 19 | */ 20 | start(delay: number, param: T | undefined = undefined, resetTimer: boolean = false) { 21 | if (this.timeId !== null && resetTimer) { 22 | clearTimeout(this.timeId); 23 | this.timeId = null; 24 | } 25 | this.param = param; 26 | if (this.timeId === null) { 27 | this.timeId = setTimeout(() => { 28 | this.timeId = null; 29 | this.action(this.param as T); 30 | this.param = undefined; 31 | }, delay); 32 | this.timeId.unref(); 33 | } 34 | } 35 | 36 | /** 遅延実行をキャンセルする。*/ 37 | cancel(): void { 38 | if (this.timeId !== null) { 39 | clearTimeout(this.timeId); 40 | this.timeId = null; 41 | this.param = undefined; 42 | } 43 | } 44 | 45 | /** 遅延実行が完了しているか */ 46 | get done(): boolean { 47 | return this.timeId === null; 48 | } 49 | } -------------------------------------------------------------------------------- /src/libs/OptionValidator.ts: -------------------------------------------------------------------------------- 1 | export const validateOption = { 2 | number: function (name: string, value: any, min?: number, max?: number) { 3 | let v = value; 4 | if (typeof v !== 'number') { 5 | v = parseFloat(v); 6 | } 7 | if (isNaN(v)) { 8 | throw new Error(`Invalid number option @${name}. ${value} is not a number`); 9 | } 10 | if (min !== undefined && v < min) { 11 | throw new Error(`Invalid number option. @${name} must be at least ${min}`); 12 | } 13 | if (max !== undefined && max < v) { 14 | throw new Error(`Invalid number option. @${name} must be at most ${max}`); 15 | } 16 | return v; 17 | }, 18 | 19 | bool: function (name: string, value: any) { 20 | let v = value; 21 | if (typeof v === 'string') { 22 | v = v.toLocaleLowerCase().trim(); 23 | if (v === 'false') { 24 | v = false; 25 | } else if (v === 'true') { 26 | v = true; 27 | } else { 28 | throw new Error(`${name} (${value}) is not a boolean`); 29 | } 30 | } 31 | 32 | return !!v; 33 | } 34 | }; -------------------------------------------------------------------------------- /src/libs/TypedEvent.ts: -------------------------------------------------------------------------------- 1 | // code from https://typescript-jp.gitbook.io/deep-dive/main-1/typed-event 2 | 3 | export interface Listener { 4 | (event: T): any; 5 | } 6 | 7 | export interface Disposable { 8 | dispose(): void; 9 | } 10 | 11 | /** passes through events as they happen. You will not get events from before you start listening */ 12 | export class TypedEvent { 13 | private listeners: Listener[] = []; 14 | private listenersOncer: Listener[] = []; 15 | 16 | on(listener: Listener): Disposable { 17 | this.listeners.push(listener); 18 | return { 19 | dispose: () => this.off(listener) 20 | }; 21 | } 22 | 23 | once(listener: Listener): void { 24 | this.listenersOncer.push(listener); 25 | } 26 | 27 | async(): Promise { 28 | return new Promise(resolve => { 29 | this.listenersOncer.push(a => { 30 | resolve(a); 31 | }); 32 | }); 33 | } 34 | 35 | off(listener: Listener): void { 36 | const callbackIndex = this.listeners.indexOf(listener); 37 | if (callbackIndex > -1) this.listeners.splice(callbackIndex, 1); 38 | } 39 | 40 | emit(event: T): void { 41 | /** Update any general listeners */ 42 | this.listeners.forEach((listener) => listener(event)); 43 | 44 | /** Clear the `once` queue */ 45 | if (this.listenersOncer.length > 0) { 46 | this.listenersOncer.forEach((listener) => listener(event)); 47 | this.listenersOncer = []; 48 | } 49 | } 50 | 51 | pipe(te: TypedEvent): Disposable { 52 | return this.on((e) => te.emit(e)); 53 | } 54 | } -------------------------------------------------------------------------------- /src/parsers/MpSettingsParser.ts: -------------------------------------------------------------------------------- 1 | import { Teams } from '../Player'; 2 | export interface MpSettingsResult { 3 | name: string; 4 | id: number; 5 | history: string; 6 | beatmapUrl: string; 7 | beatmapId: number; 8 | beatmapTitle: string; 9 | teamMode: string; 10 | winCondition: string; 11 | activeMods: string; 12 | players: PlayerSettings[]; 13 | numPlayers: number; 14 | } 15 | 16 | export interface PlayerSettings { 17 | slot: number; 18 | ready: string; 19 | profile: string; 20 | id: number; 21 | name: string; 22 | isHost: boolean; 23 | options: string; 24 | team: Teams; 25 | } 26 | 27 | export class MpSettingsParser { 28 | result: MpSettingsResult | null = null; 29 | isParsing: boolean = false; 30 | get isParsed(): boolean { 31 | return !this.isParsing && this.result !== null; 32 | } 33 | 34 | feedLine(line: string): boolean { 35 | let m = line.match(/Room name: (.+), History: (.+?(\d+))/); 36 | if (m) { 37 | this.result = { 38 | name: m[1], 39 | id: parseInt(m[3]), 40 | history: m[2], 41 | beatmapUrl: '', 42 | beatmapId: 0, 43 | beatmapTitle: '', 44 | teamMode: '', 45 | winCondition: '', 46 | activeMods: '', 47 | numPlayers: 0, 48 | players: [], 49 | }; 50 | this.isParsing = true; 51 | return true; 52 | } 53 | if (this.result === null) return false; 54 | 55 | m = line.match(/Beatmap: (\S+?(\d+)) (.+)/); 56 | if (m) { 57 | this.result.beatmapUrl = m[1]; 58 | this.result.beatmapId = parseInt(m[2]); 59 | this.result.beatmapTitle = m[3]; 60 | return true; 61 | } 62 | m = line.match(/Team mode: (.+), Win condition: (.+)/); 63 | if (m) { 64 | this.result.teamMode = m[1]; 65 | this.result.winCondition = m[2]; 66 | return true; 67 | } 68 | m = line.match(/Active mods: (.+)/); 69 | if (m) { 70 | this.result.activeMods = m[1]; 71 | return true; 72 | } 73 | m = line.match(/Players: (\d+)/); 74 | if (m) { 75 | this.result.numPlayers = parseInt(m[1]); 76 | this.isParsing = this.result.numPlayers !== 0; 77 | return true; 78 | } 79 | m = line.match(/^Slot (\d+)\s+(.+) https:\/\/osu\.ppy\.sh\/u\/(\d+) (.{15})\s*(\[(.+)\])?$/); 80 | if (m) { 81 | const team = m[6] === undefined || !m[6].includes('Team') ? Teams.None 82 | : m[6].includes('Blue') ? Teams.Blue : Teams.Red; 83 | 84 | const p: PlayerSettings = { 85 | slot: parseInt(m[1]), 86 | ready: m[2].trim(), 87 | id: parseInt(m[3]), 88 | profile: `https://osu.ppy.sh/u/${m[3]}`, 89 | name: m[4].trim(), 90 | isHost: m[6] === undefined ? false : m[6].includes('Host'), 91 | team: team, 92 | options: m[6] === undefined ? '' : m[6].trim() 93 | }; 94 | this.result.players.push(p); 95 | this.isParsing = this.result.players.length !== this.result.numPlayers; 96 | return true; 97 | } 98 | return false; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/parsers/StatParser.ts: -------------------------------------------------------------------------------- 1 | export class StatResult { 2 | name: string; 3 | id: number; 4 | status: StatStatuses; 5 | score: number; 6 | rank: number; 7 | plays: number; 8 | level: number; 9 | accuracy: number; 10 | date: number; 11 | constructor(name: string, id: number, status: StatStatuses, score: number = 0, rank: number = 0, plays: number = 0, level: number = 0, accuracy: number = 0, date: number = 0) { 12 | this.name = name; 13 | this.id = id; 14 | this.status = status; 15 | this.score = score; 16 | this.rank = rank; 17 | this.plays = plays; 18 | this.level = level; 19 | this.accuracy = accuracy; 20 | this.date = date; 21 | } 22 | toString(): string { 23 | return `Stats for (${this.name})[https://osu.ppy.sh/u/${this.id}]${this.status === StatStatuses.None ? '' : ` is ${StatStatuses[this.status]}`}: 24 | Score: ${this.score} (#${this.rank}) 25 | Plays: ${this.plays} (lv${this.level}) 26 | Accuracy: ${this.accuracy}%`; 27 | } 28 | } 29 | 30 | export enum StatStatuses { 31 | None = 0, 32 | Idle, 33 | Playing, 34 | Watching, 35 | Editing, 36 | Testing, 37 | Submitting, 38 | Modding, 39 | Multiplayer, 40 | Multiplaying, 41 | Afk, 42 | Unknown, 43 | } 44 | 45 | export class StatParser { 46 | result: StatResult | null = null; 47 | isParsing: boolean = false; 48 | get isParsed(): boolean { 49 | return !this.isParsing && this.result !== null; 50 | } 51 | 52 | feedLine(message: string): boolean { 53 | const line1 = message.match(/Stats for \((.+)\)\[https:\/\/osu\.ppy\.sh\/u\/(\d+)\]( is (.+))?:/); 54 | if (line1) { 55 | this.result = new StatResult(line1[1], parseInt(line1[2]), StatStatuses.None); 56 | const statStr = line1[4]; 57 | for (let i = 0; i in StatStatuses; i++) { 58 | const st = i as StatStatuses; 59 | if (statStr === StatStatuses[st]) { 60 | this.result.status = st; 61 | break; 62 | } 63 | } 64 | this.isParsing = true; 65 | return true; 66 | } 67 | if (this.result === null) return false; 68 | 69 | const line2 = message.match(/Score:\s+([\d,]+)\s+\(#(\d+)\)/); 70 | if (line2) { 71 | this.result.score = parseInt(line2[1].replace(/,/g, '')); 72 | this.result.rank = parseInt(line2[2]); 73 | return true; 74 | } 75 | 76 | const line3 = message.match(/Plays:\s+(\d+)\s+\(lv(\d+)\)/); 77 | if (line3) { 78 | this.result.plays = parseInt(line3[1]); 79 | this.result.level = parseInt(line3[2]); 80 | return true; 81 | } 82 | 83 | const line4 = message.match(/Accuracy: ([\d.]+)%/); 84 | if (line4) { 85 | this.result.accuracy = parseFloat(line4[1]); 86 | this.result.date = Date.now(); 87 | this.isParsing = false; 88 | return true; 89 | } 90 | 91 | return false; 92 | } 93 | } 94 | 95 | export function IsStatResponse(message: string) { 96 | return message.match(/^Stats for \(|Score:|Plays:|Accuracy:/); 97 | } 98 | -------------------------------------------------------------------------------- /src/plugins/LobbyPlugin.ts: -------------------------------------------------------------------------------- 1 | import { Lobby } from '../Lobby'; 2 | import { getLogger, Logger } from '../Loggers'; 3 | import { loadEnvConfig } from '../TypedConfig'; 4 | 5 | /** 6 | * ロビーのイベントに反応して処理を行うプラグインのベースクラス。 7 | */ 8 | export class LobbyPlugin { 9 | lobby: Lobby; 10 | logger: Logger; 11 | pluginName: string; 12 | 13 | constructor(lobby: Lobby, pluginName: string, loggerTag: string = 'default') { 14 | this.lobby = lobby; 15 | this.lobby.plugins.push(this); 16 | this.pluginName = pluginName; 17 | this.logger = getLogger(loggerTag); 18 | } 19 | 20 | /** 21 | * 他のプラグインにメッセージを送信する。 22 | * @param type 23 | * @param args 24 | */ 25 | SendPluginMessage(type: string, args: string[] = []): void { 26 | this.lobby.PluginMessage.emit({ type, args, src: this }); 27 | } 28 | 29 | /** 30 | * コンソール上で[i]nfo コマンドを実行した際に表示される、 31 | * プラグインごとのステータスメッセージを取得する 32 | */ 33 | GetPluginStatus(): string { 34 | return ''; 35 | } 36 | 37 | /** 38 | * すべてのプラグインが読み込まれたあとに実行される 39 | */ 40 | OnLoaded(): void { 41 | /* do nothing. */ 42 | } 43 | 44 | OnConfig(target: string, name: string, value: string): void { 45 | /* do nothing. */ 46 | } 47 | 48 | loadEnvSettings(option: any) { 49 | try { 50 | loadEnvConfig(this.pluginName, option); 51 | } catch (e: any) { 52 | this.logger.error(`\n${e.message}\n${e.stack}`); 53 | process.exit(1); 54 | } 55 | } 56 | } 57 | 58 | export function regSwitch(val: string, cases: { case: RegExp, action: (m: RegExpExecArray) => void }[]) { 59 | for (const c of cases) { 60 | const ea = c.case.exec(val); 61 | if (ea) { 62 | c.action(ea); 63 | return; 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/plugins/LobbyTerminator.ts: -------------------------------------------------------------------------------- 1 | import { LobbyPlugin } from './LobbyPlugin'; 2 | import { Lobby } from '../Lobby'; 3 | import { Player } from '../Player'; 4 | import { getConfig } from '../TypedConfig'; 5 | 6 | export interface LobbyTerminatorOption { 7 | terminate_time_ms: number; 8 | } 9 | 10 | export class LobbyTerminator extends LobbyPlugin { 11 | option: LobbyTerminatorOption; 12 | terminateTimer: NodeJS.Timer | undefined; 13 | multilimeMessageInterval: number = 1000; 14 | 15 | constructor(lobby: Lobby, option: Partial = {}) { 16 | super(lobby, 'LobbyTerminator', 'terminator'); 17 | this.option = getConfig(this.pluginName, option) as LobbyTerminatorOption; 18 | this.registerEvents(); 19 | } 20 | 21 | private registerEvents(): void { 22 | this.lobby.PlayerLeft.on(p => this.onPlayerLeft(p.player)); 23 | this.lobby.PlayerJoined.on(p => this.onPlayerJoined(p.player, p.slot)); 24 | this.lobby.LeftChannel.on(p => { 25 | if (this.terminateTimer) { 26 | clearTimeout(this.terminateTimer); 27 | } 28 | }); 29 | } 30 | 31 | private onPlayerJoined(player: Player, slot: number): void { 32 | if (this.terminateTimer) { 33 | clearTimeout(this.terminateTimer); 34 | this.terminateTimer = undefined; 35 | this.logger.trace('Cleared the lobby terminator timer.'); 36 | } 37 | } 38 | 39 | private onPlayerLeft(p: Player): void { 40 | if (this.lobby.players.size === 0) { 41 | if (this.terminateTimer) { 42 | clearTimeout(this.terminateTimer); 43 | } 44 | this.logger.trace('Started the lobby terminator timer.'); 45 | this.terminateTimer = setTimeout(() => { 46 | this.logger.info('Terminated the lobby.'); 47 | this.lobby.CloseLobbyAsync(); 48 | }, this.option.terminate_time_ms); 49 | } 50 | } 51 | 52 | CloseLobby(time_ms: number = 0): void { 53 | if (time_ms === 0) { 54 | if (this.lobby.players.size === 0) { 55 | this.logger.info('Terminated the lobby.'); 56 | this.lobby.CloseLobbyAsync(); 57 | } else { 58 | this.lobby.SendMultilineMessageWithInterval([ 59 | '!mp password closed', 60 | 'This lobby will be closed when everyone leaves.', 61 | 'Thank you for playing with the auto host rotation lobby.' 62 | ], this.multilimeMessageInterval, 'close lobby announcement', 100000); 63 | this.option.terminate_time_ms = 1000; 64 | } 65 | } else { 66 | this.lobby.SendMultilineMessageWithInterval([ 67 | '!mp password closed', 68 | `This lobby will be closed in ${(time_ms / 1000).toFixed(0)}sec(s).`, 69 | 'Thank you for playing with the auto host rotation lobby.' 70 | ], this.multilimeMessageInterval, 'close lobby announcement', 100000) 71 | .then(() => this.sendMessageWithDelay('!mp close', time_ms)); 72 | } 73 | } 74 | 75 | private sendMessageWithDelay(message: string, delay: number): Promise { 76 | return new Promise(resolve => { 77 | setTimeout(() => { 78 | this.lobby.SendMessage(message); 79 | resolve(); 80 | }, delay); 81 | }); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/plugins/MapRecaster.ts: -------------------------------------------------------------------------------- 1 | import { Lobby } from '../Lobby'; 2 | import { Player } from '../Player'; 3 | import { LobbyPlugin } from './LobbyPlugin'; 4 | import { BanchoResponseType } from '../parsers/CommandParser'; 5 | 6 | /** 7 | * ホストが古いバージョンのマップを選択した際に、コマンドでマップを貼り直して最新版にする。 8 | * !updateコマンドなどで発動。マップ選択後に1度だけ実行できる。 9 | */ 10 | export class MapRecaster extends LobbyPlugin { 11 | canRecast: boolean = true; 12 | constructor(lobby: Lobby) { 13 | super(lobby, 'MapRecaster', 'recaster'); 14 | this.registerEvents(); 15 | } 16 | 17 | private registerEvents(): void { 18 | this.lobby.ReceivedChatCommand.on(a => this.onReceivedChatCommand(a.command, a.param, a.player)); 19 | this.lobby.ReceivedBanchoResponse.on(a => { 20 | if (a.response.type === BanchoResponseType.BeatmapChanged) { 21 | this.canRecast = true; 22 | } 23 | }); 24 | } 25 | 26 | private onReceivedChatCommand(command: string, param: string, player: Player): void { 27 | if (command === '!update') { 28 | if (this.canRecast) { 29 | this.canRecast = false; 30 | this.lobby.SendMessage(`!mp map ${this.lobby.mapId}`); 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/plugins/ProfileFecher.ts: -------------------------------------------------------------------------------- 1 | import { Lobby } from '../Lobby'; 2 | import { Player } from '../Player'; 3 | import { LobbyPlugin } from './LobbyPlugin'; 4 | import { WebApiClient } from '../webapi/WebApiClient'; 5 | import { UserProfile } from '../webapi/UserProfile'; 6 | import { getConfig } from '../TypedConfig'; 7 | 8 | export interface ProfileFecherOption { 9 | profile_expired_day: number 10 | } 11 | 12 | 13 | export class ProfileFecher extends LobbyPlugin { 14 | option: ProfileFecherOption; 15 | hasError: boolean = false; 16 | profileMap: Map; 17 | pendingNames: Set; 18 | task: Promise; 19 | 20 | constructor(lobby: Lobby, option: Partial = {}) { 21 | super(lobby, 'profile', 'profile'); 22 | this.option = getConfig(this.pluginName, option) as ProfileFecherOption; 23 | this.profileMap = new Map(); 24 | this.pendingNames = new Set(); 25 | this.task = this.initializeAsync(); 26 | this.registerEvents(); 27 | } 28 | 29 | private async initializeAsync(): Promise { 30 | await WebApiClient.updateToken(); 31 | } 32 | 33 | private registerEvents(): void { 34 | this.lobby.PlayerJoined.on(a => this.onPlayerJoined(a.player)); 35 | } 36 | 37 | private onPlayerJoined(player: Player): void { 38 | if (this.hasError) return; 39 | this.addTaskQueueIfNeeded(player); 40 | } 41 | 42 | private addTaskQueueIfNeeded(player: Player): boolean { 43 | 44 | if (player.id !== 0) return false; 45 | const profile = this.profileMap.get(player.name); 46 | if (profile && !this.isExpiredProfile(profile)) { 47 | player.id = profile.id; 48 | player.profile = profile; 49 | return true; 50 | } 51 | 52 | if (this.pendingNames.has(player.name)) { 53 | return false; 54 | } 55 | this.pendingNames.add(player.name); 56 | 57 | this.task = this.task.then(async () => { 58 | try { 59 | const profile = await this.getProfileFromWebApi(player); 60 | 61 | if (profile !== null) { 62 | player.id = profile.id; 63 | player.profile = profile; 64 | this.logger.info(`Fetching player profile: ${player.name}`); 65 | } else { 66 | this.logger.warn(`Player cannot be found: ${player.name}`); 67 | } 68 | this.pendingNames.delete(player.name); 69 | } catch (e: any) { 70 | this.logger.error(`@ProfileFecher#addTaskQueueIfNeeded\n${e.message}\n${e.stack}`); 71 | } 72 | 73 | }); 74 | 75 | return true; 76 | } 77 | 78 | private getProfileFromWebApi(player: Player): Promise { 79 | return WebApiClient.getUser(player.name); 80 | } 81 | 82 | private isExpiredProfile(profile: UserProfile): boolean { 83 | return Date.now() < this.option.profile_expired_day * 24 * 60 * 60 * 1000 + profile.get_time; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/plugins/VoteCounter.ts: -------------------------------------------------------------------------------- 1 | import { Player } from '../Player'; 2 | 3 | export class VoteCounter { 4 | readonly requiredRate: number; 5 | readonly requiredMin: number; 6 | private _passed: boolean; 7 | voters: Map; 8 | 9 | constructor(requiredRate: number, requiredMin: number) { 10 | this.requiredRate = requiredRate; 11 | this.requiredMin = requiredMin; 12 | this._passed = false; 13 | this.voters = new Map(); 14 | } 15 | 16 | public Vote(player: Player): boolean { 17 | if (!this.voters.has(player)) return false; 18 | if (this.voters.get(player)) return false; 19 | this.voters.set(player, true); 20 | this.checkPassed(); 21 | return true; 22 | } 23 | 24 | public AddVoter(player: Player): void { 25 | if (!this.voters.has(player)) { 26 | this.voters.set(player, false); 27 | } 28 | } 29 | 30 | public RemoveVoter(player: Player): void { 31 | this.voters.delete(player); 32 | this.checkPassed(); 33 | } 34 | 35 | public Clear(): void { 36 | for (const k of this.voters.keys()) { 37 | this.voters.set(k, false); 38 | } 39 | this._passed = false; 40 | } 41 | 42 | public RemoveAllVoters(): void { 43 | this.voters.clear(); 44 | this._passed = false; 45 | } 46 | 47 | get required(): number { 48 | return Math.ceil(Math.max( 49 | this.voters.size * this.requiredRate, 50 | this.requiredMin)); 51 | } 52 | 53 | get count(): number { 54 | let c = 0; 55 | this.voters.forEach((v, k) => v ? c++ : 0); 56 | return c; 57 | } 58 | 59 | get passed(): boolean { 60 | return this._passed; 61 | } 62 | 63 | private checkPassed(): void { 64 | if (this.required <= this.count) { 65 | this._passed = true; 66 | } 67 | } 68 | 69 | toString(): string { 70 | return `${this.count} / ${this.required}`; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/tests/InOutLoggerTest.ts: -------------------------------------------------------------------------------- 1 | import { InOutLogger } from '../plugins/InOutLogger'; 2 | import tu from './TestUtils'; 3 | 4 | describe.skip('In Out Logger Tests', function () { 5 | before(function () { 6 | tu.configMochaVerbosely(); 7 | }); 8 | 9 | it('test', async () => { 10 | const { lobby, ircClient } = await tu.SetupLobbyAsync(); 11 | const logger = new InOutLogger(lobby); 12 | const players = await tu.AddPlayersAsync(5, ircClient); 13 | await ircClient.emulateMatchAsync(); 14 | await ircClient.emulateMatchAsync(); 15 | await ircClient.emulateRemovePlayerAsync(players[0]); 16 | await ircClient.emulateRemovePlayerAsync(players[1]); 17 | await ircClient.emulateRemovePlayerAsync(players[2]); 18 | await ircClient.emulateAddPlayerAsync('a'); 19 | await ircClient.emulateAddPlayerAsync('b'); 20 | await ircClient.emulateAddPlayerAsync('c'); 21 | const t = ircClient.emulateMatchAsync(10); 22 | await tu.delayAsync(1); 23 | await ircClient.emulateRemovePlayerAsync('a'); 24 | await ircClient.emulateAddPlayerAsync('d'); 25 | await t; 26 | await ircClient.emulateAddPlayerAsync('e'); 27 | await ircClient.emulateMatchAsync(); 28 | await ircClient.emulateRemovePlayerAsync('e'); 29 | await ircClient.emulateMatchAsync(); 30 | logger.logger.info(logger.GetPluginStatus()); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /src/tests/IntegratedPluginsTest.ts: -------------------------------------------------------------------------------- 1 | import { assert } from 'chai'; 2 | import { Lobby } from '../Lobby'; 3 | import { Player } from '../Player'; 4 | import { DummyIrcClient } from '../dummies/DummyIrcClient'; 5 | import { parser } from '../parsers/CommandParser'; 6 | import { AutoHostSelector, AutoHostSelectorOption } from '../plugins/AutoHostSelector'; 7 | import { HostSkipper, HostSkipperOption } from '../plugins/HostSkipper'; 8 | 9 | import tu from './TestUtils'; 10 | 11 | describe('Integrated Plugins Tests', function () { 12 | before(function () { 13 | tu.configMochaAsSilent(); 14 | }); 15 | describe('selector and skipper tests', function () { 16 | async function setup(selectorOption: Partial = {}, skipperOption: Partial = { afk_check_interval_ms: 0 }): 17 | Promise<{ selector: AutoHostSelector, skipper: HostSkipper, lobby: Lobby, ircClient: DummyIrcClient }> { 18 | const li = await tu.SetupLobbyAsync(); 19 | const selector = new AutoHostSelector(li.lobby, selectorOption); 20 | const skipper = new HostSkipper(li.lobby, skipperOption); 21 | return { selector, skipper, ...li }; 22 | } 23 | 24 | it('skip to test', async () => { 25 | const { selector, skipper, lobby, ircClient } = await setup(); 26 | const ownerId = tu.ownerNickname; 27 | await tu.AddPlayersAsync([ownerId, 'p2', 'p3', 'p4'], ircClient); 28 | let owner = lobby.GetPlayer(ownerId); 29 | assert.isNotNull(owner); 30 | owner = owner as Player; 31 | assert.isTrue(owner.isCreator); 32 | assert.isTrue(owner.isAuthorized); 33 | assert.isTrue(owner.isHost); 34 | 35 | await ircClient.emulateMatchAsync(0); 36 | 37 | tu.assertHost('p2', lobby); 38 | let m = '*skipto p4'; 39 | assert.isTrue(parser.IsChatCommand(m)); 40 | lobby.RaiseReceivedChatCommand(owner, m); 41 | await tu.delayAsync(10); 42 | tu.assertHost('p4', lobby); 43 | 44 | m = `*skipto ${owner.name}`; 45 | assert.isTrue(parser.IsChatCommand(m)); 46 | lobby.RaiseReceivedChatCommand(owner, m); 47 | await tu.delayAsync(10); 48 | tu.assertHost(ownerId, lobby); 49 | skipper.StopTimer(); 50 | }); 51 | }); 52 | }); 53 | -------------------------------------------------------------------------------- /src/tests/LobbyTerminatorTest.ts: -------------------------------------------------------------------------------- 1 | import { Lobby } from '../Lobby'; 2 | import { DummyIrcClient } from '../dummies/DummyIrcClient'; 3 | import { LobbyTerminator } from '../plugins/LobbyTerminator'; 4 | import tu from './TestUtils'; 5 | 6 | describe.skip('Lobby Terminator Tests', function () { 7 | before(function () { 8 | tu.configMochaVerbosely(); 9 | }); 10 | async function setupAsync(interval: number = 10): Promise<{ terminator: LobbyTerminator, lobby: Lobby, ircClient: DummyIrcClient }> { 11 | const { lobby, ircClient } = await tu.SetupLobbyAsync(); 12 | const terminator = new LobbyTerminator(lobby); 13 | terminator.multilimeMessageInterval = interval; 14 | return { terminator, lobby, ircClient }; 15 | } 16 | it('CloseLobby time', async () => { 17 | const { terminator, lobby, ircClient } = await setupAsync(); 18 | terminator.CloseLobby(100); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /src/tests/MapRecasterTest.ts: -------------------------------------------------------------------------------- 1 | import { Lobby } from '../Lobby'; 2 | import { DummyIrcClient } from '../dummies/DummyIrcClient'; 3 | import { MapRecaster } from '../plugins/MapRecaster'; 4 | import tu from './TestUtils'; 5 | import { BanchoResponseType } from '../parsers/CommandParser'; 6 | 7 | describe('Map Recaster Tests', function () { 8 | before(function () { 9 | tu.configMochaAsSilent(); 10 | }); 11 | 12 | async function setupAsync(): 13 | Promise<{ recaster: MapRecaster, lobby: Lobby, ircClient: DummyIrcClient }> { 14 | const li = await tu.SetupLobbyAsync(); 15 | const ma = new MapRecaster(li.lobby); 16 | return { recaster: ma, ...li }; 17 | } 18 | it('recast test', async () => { 19 | const { recaster, lobby, ircClient } = await setupAsync(); 20 | const players = await tu.AddPlayersAsync(3, ircClient); 21 | await ircClient.emulateChangeMapAsync(0); 22 | const mapid = lobby.mapId; 23 | const t1 = tu.assertBanchoRespond(lobby, BanchoResponseType.MpBeatmapChanged, (b => b.params[0] === mapid), 10); 24 | ircClient.emulateMessage(players[0], ircClient.channel, '!update'); 25 | await t1; 26 | }); 27 | 28 | it('request twice test', async () => { 29 | const { recaster, lobby, ircClient } = await setupAsync(); 30 | const players = await tu.AddPlayersAsync(3, ircClient); 31 | await ircClient.emulateChangeMapAsync(0); 32 | const mapid = lobby.mapId; 33 | const t1 = tu.assertBanchoRespond(lobby, BanchoResponseType.MpBeatmapChanged, (b => b.params[0] === mapid), 10); 34 | ircClient.emulateMessage(players[0], ircClient.channel, '!update'); 35 | await t1; 36 | 37 | const t2 = tu.assertBanchoNotRespond(lobby, BanchoResponseType.MpBeatmapChanged, (b => b.params[0] === mapid), 10); 38 | ircClient.emulateMessage(players[1], ircClient.channel, '!update'); 39 | await t2; 40 | }); 41 | 42 | it('can update every time player changes map', async () => { 43 | const { recaster, lobby, ircClient } = await setupAsync(); 44 | const players = await tu.AddPlayersAsync(3, ircClient); 45 | await ircClient.emulateChangeMapAsync(0); 46 | let mapid = lobby.mapId; 47 | const t1 = tu.assertBanchoRespond(lobby, BanchoResponseType.MpBeatmapChanged, (b => b.params[0] === mapid), 10); 48 | ircClient.emulateMessage(players[0], ircClient.channel, '!update'); 49 | await t1; 50 | await ircClient.emulateChangeMapAsync(0); 51 | mapid = lobby.mapId; 52 | const t2 = tu.assertBanchoRespond(lobby, BanchoResponseType.MpBeatmapChanged, (b => b.params[0] === mapid), 10); 53 | ircClient.emulateMessage(players[1], ircClient.channel, '!update'); 54 | await t2; 55 | await ircClient.emulateChangeMapAsync(0); 56 | mapid = lobby.mapId; 57 | const t3 = tu.assertBanchoRespond(lobby, BanchoResponseType.MpBeatmapChanged, (b => b.params[0] === mapid), 10); 58 | ircClient.emulateMessage(players[1], ircClient.channel, '!update'); 59 | await t3; 60 | }); 61 | }); 62 | -------------------------------------------------------------------------------- /src/tests/StatParserTest.ts: -------------------------------------------------------------------------------- 1 | import { assert } from 'chai'; 2 | import { StatParser, StatStatuses, StatResult } from '../parsers/StatParser'; 3 | 4 | const testTexts = [ 5 | 'Stats for (Jason)[https://osu.ppy.sh/u/7342098] is Multiplaying:', 6 | 'Score: 18,163,888,782 (#1631)', 7 | 'Plays: 78245 (lv100)', 8 | 'Accuracy: 97.36%', 9 | 'Stats for (horcrux18)[https://osu.ppy.sh/u/8778911] is Afk:', 10 | 'Score: 584,565,786 (#260177)', 11 | 'Plays: 5695 (lv64)', 12 | 'Accuracy: 86.94%', 13 | 'Stats for (gviz)[https://osu.ppy.sh/u/15145414] is Multiplayer:', 14 | 'Score: 00 (#0)', 15 | 'Plays: 7 (lv2)', 16 | 'Accuracy: 0%', 17 | 'Stats for (Angel Arrow)[https://osu.ppy.sh/u/1970239] is Testing:', 18 | 'Score: 59,315,895,109 (#1006)', 19 | 'Plays: 104962 (lv102)', 20 | 'Accuracy: 98.16%', 21 | 'Stats for (Foreskin)[https://osu.ppy.sh/u/3760263]:', 22 | 'Score: 00 (#0)', 23 | 'Plays: 1 (lv1)', 24 | 'Accuracy: 0.00%' 25 | ]; 26 | 27 | const expectedResults = [ 28 | new StatResult ('Jason', 7342098, StatStatuses.Multiplaying, 18163888782, 1631, 78245, 100, 97.36), 29 | new StatResult('horcrux18', 8778911, StatStatuses.Afk, 584_565_786, 260177, 5695, 64, 86.94), 30 | new StatResult('gviz', 15145414, StatStatuses.Multiplayer, 0, 0, 7, 2, 0), 31 | new StatResult('Angel Arrow', 1970239, StatStatuses.Testing, 59315895109, 1006, 104962, 102, 98.16), 32 | new StatResult('Foreskin', 3760263, StatStatuses.None, 0, 0, 1, 1, 0), 33 | ]; 34 | 35 | it('StatParser Test', function () { 36 | assert.equal(testTexts.length, expectedResults.length * 4); 37 | const parser = new StatParser(); 38 | assert.isFalse(parser.isParsed); 39 | assert.isFalse(parser.isParsing); 40 | assert.isNull(parser.result); 41 | 42 | for (let i = 0; i < expectedResults.length; i++) { 43 | assert.isFalse(parser.isParsing); 44 | for (let j = 0; j < 4; j++) { 45 | assert.isTrue(parser.feedLine(testTexts[i * 4 + j])); 46 | if (j !== 3) { 47 | assert.isTrue(parser.isParsing); 48 | assert.isFalse(parser.isParsed); 49 | } 50 | } 51 | assert.isFalse(parser.isParsing); 52 | assert.isTrue(parser.isParsed); 53 | if (parser.result !== null) parser.result.date = 0; 54 | assert.deepEqual(parser.result, expectedResults[i]); 55 | } 56 | }); 57 | -------------------------------------------------------------------------------- /src/tests/cases/player_v1.nedb: -------------------------------------------------------------------------------- 1 | {"_id":"00Q1CpqPjiZoX06z","eid":"p1","playCount":1,"stayTime":153046,"lastVisit":1583391308615,"visitCount":1,"seenInfo":false} 2 | {"_id":"00xV806CHAtfkNFR","eid":"p2","playCount":2,"stayTime":589607,"lastVisit":1583383474722,"visitCount":5,"seenInfo":false} 3 | {"_id":"00xWOEbLZ8kLWja8","eid":"p3","playCount":0,"stayTime":41195,"lastVisit":1568132245292,"visitCount":1,"seenInfo":false} 4 | {"_id":"00ykIYYLuEedO99O","eid":"p4","playCount":7,"stayTime":1553331,"lastVisit":1588559288277,"visitCount":1,"seenInfo":false} 5 | {"_id":"01KF4ijuYHGxY1cl","eid":"p5","playCount":1,"stayTime":205333,"lastVisit":1567875926129,"visitCount":1,"seenInfo":false} 6 | {"_id":"01NpU04JXWlCWoLK","eid":"p6","playCount":12,"stayTime":4256154,"lastVisit":1583460299288,"visitCount":3,"seenInfo":false} 7 | -------------------------------------------------------------------------------- /src/tests/cases/player_v2.nedb: -------------------------------------------------------------------------------- 1 | {"_id":"00Q1CpqPjiZoX06z","playCount":1,"stayTime":153046,"lastVisit":1583391308615,"visitCount":1,"seenInfo":false,"escaped_name":"p1"} 2 | {"_id":"00xV806CHAtfkNFR","playCount":2,"stayTime":589607,"lastVisit":1583383474722,"visitCount":5,"seenInfo":false,"escaped_name":"p2"} 3 | {"_id":"00xWOEbLZ8kLWja8","playCount":0,"stayTime":41195,"lastVisit":1568132245292,"visitCount":1,"seenInfo":false,"escaped_name":"p3"} 4 | {"_id":"00ykIYYLuEedO99O","playCount":7,"stayTime":1553331,"lastVisit":1588559288277,"visitCount":1,"seenInfo":false,"escaped_name":"p4"} 5 | {"_id":"01KF4ijuYHGxY1cl","playCount":1,"stayTime":205333,"lastVisit":1567875926129,"visitCount":1,"seenInfo":false,"escaped_name":"p5"} 6 | {"_id":"01NpU04JXWlCWoLK","playCount":12,"stayTime":4256154,"lastVisit":1583460299288,"visitCount":3,"seenInfo":false,"escaped_name":"p6"} 7 | {"version":2,"_id":"6w71SbURxHLLZEru"} 8 | -------------------------------------------------------------------------------- /src/trials/BanchoIrcTrial.ts: -------------------------------------------------------------------------------- 1 | import * as irc from '../libs/irc'; 2 | import { logIrcEvent } from '../IIrcClient'; 3 | import { parser } from '../parsers/CommandParser'; 4 | import { getIrcConfig } from '../TypedConfig'; 5 | 6 | export function trial() { 7 | const c = getIrcConfig(); 8 | const bot = new irc.Client(c.server, c.nick, c.opt); 9 | 10 | bot.on('error', function (message) { 11 | console.error(`ERROR: ${message.command}: ${message.args.join(' ')}`); 12 | }); 13 | 14 | bot.on('message', function (from, to, message) { 15 | console.log(`${from} => ${to}: ${message}`); 16 | }); 17 | 18 | bot.on('pm', function (nick, message) { 19 | console.log(`Got private message from ${nick}: ${message}`); 20 | const v = parser.ParseMpMakeResponse(nick, message); 21 | if (v !== null) { 22 | console.log(`--- parsed pm id=${v.id} title=${v.title}`); 23 | } 24 | }); 25 | 26 | let is_joined = false; 27 | bot.on('join', function (channel, who) { 28 | console.log(`${who} has joined ${channel}`); 29 | if (!is_joined) { 30 | is_joined = true; 31 | //bot.say(channel, "!mp password"); 32 | //bot.say(channel, "!mp invite gnsksz"); 33 | setTimeout(() => { 34 | //bot.say(channel, "!mp close"); 35 | }, 30000); 36 | } 37 | 38 | }); 39 | bot.on('part', function (channel, who, reason) { 40 | console.log(`${who} has left ${channel}: ${reason}`); 41 | }); 42 | bot.on('kick', function (channel, who, by, reason) { 43 | console.log(`${who} was kicked from ${channel} by ${by}: ${reason}`); 44 | }); 45 | bot.on('invite', (channel, from) => { 46 | console.log(`${from} invite you to ${channel}`); 47 | }); 48 | 49 | bot.addListener('registered', function (message) { 50 | console.log(`registered ${message}`); 51 | //bot.say("BanchoBot", "!mp make irc test lobby4"); 52 | bot.join('#lobby'); 53 | }); 54 | } 55 | 56 | export function ConnectionServerTrial() { 57 | const c = getIrcConfig(); 58 | const bot = new irc.Client(c.server, c.nick, c.opt); 59 | 60 | logIrcEvent(bot); 61 | 62 | console.log(`hostmask => ${bot.hostMask}`); 63 | 64 | bot.connect(); 65 | 66 | bot.addListener('registered', function (message) { 67 | console.log(`hostmask => ${bot.hostMask}`); 68 | bot.disconnect('goodby', () => { console.log('disconnected'); }); 69 | }); 70 | } 71 | -------------------------------------------------------------------------------- /src/trials/HistryTrial.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import { promises as fs } from 'fs'; 3 | import { HistoryFecher } from '../webapi/HistoryFetcher'; 4 | import { HistoryRepository } from '../webapi/HistoryRepository'; 5 | 6 | export async function trial() { 7 | await GetOrderTrial(); 8 | } 9 | 10 | async function GetHistryTrial() { 11 | 12 | // 67261609 13 | // 67268731 14 | const matchId = 76714773; 15 | // https://osu.ppy.sh/community/matches/${matchId}/history?before=1509690736&limit=100 16 | const url = `https://osu.ppy.sh/community/matches/${matchId}/`; 17 | const params = { 18 | 'limit': 100, 19 | 'before': 1695874063 20 | }; 21 | 22 | const response = await axios.get(url, { params }) 23 | .catch(err => { 24 | return err.response; 25 | }); 26 | console.log(JSON.stringify(response.data)); 27 | 28 | 29 | fs.writeFile('data/arc/history_76714773_joinleftsametime.json', JSON.stringify(response.data)); 30 | } 31 | 32 | async function GetOrderTrial() { 33 | const matchId = 76714773; 34 | const repo = new HistoryRepository(matchId); 35 | const res = await repo.calcCurrentOrderAsName(); 36 | console.log(res); 37 | } 38 | 39 | async function GetLobbyNameChanger() { 40 | const hr = new HistoryRepository(67719013, new HistoryFecher()); 41 | let ln = ''; 42 | hr.changedLobbyName.on(e => { 43 | console.log(`${e.oldName}->${e.newName} `); 44 | ln = e.newName; 45 | }); 46 | while (!ln.startsWith('4-5*')) { 47 | await hr.fetch(true); 48 | } 49 | } 50 | 51 | async function promiseTrial() { 52 | let task = delayAsync(100).then(() => 1); 53 | setImmediate(async () => { 54 | const n = await task; 55 | console.log(`i1 ${n}`); 56 | }); 57 | setImmediate(async () => { 58 | task = task.then(() => 2); 59 | const n = await task; 60 | console.log(`i2 ${n}`); 61 | }); 62 | setImmediate(async () => { 63 | task = task.then(() => 3); 64 | const n = await task; 65 | console.log(`i3 ${n}`); 66 | }); 67 | setImmediate(async () => { 68 | const n = await task; 69 | console.log(`i4 ${n}`); 70 | }); 71 | } 72 | 73 | async function delayAsync(ms: number): Promise { 74 | if (ms === 0) return Promise.resolve(); 75 | return new Promise(resolve => setTimeout(resolve, ms)); 76 | } 77 | -------------------------------------------------------------------------------- /src/trials/IrcTrial.ts: -------------------------------------------------------------------------------- 1 | import * as irc from '../libs/irc'; 2 | 3 | const IrcTestSettings = { 4 | server: 'irc.dollyfish.net.nz', 5 | nick: 'ohr', 6 | channel: '#test' 7 | }; 8 | 9 | export function trial() { 10 | const bot = new irc.Client(IrcTestSettings.server, IrcTestSettings.nick, { 11 | autoConnect: true, 12 | debug: true 13 | }); 14 | 15 | //bot.join(IrcTestSettings.channel); 16 | 17 | bot.addListener('error', function (message) { 18 | console.error(`ERROR: ${message.command}: ${message.args.join(' ')}`); 19 | }); 20 | 21 | bot.addListener('message#blah', function (from, message) { 22 | console.log(`<${from}> ${message}`); 23 | }); 24 | 25 | bot.addListener('message', function (from, to, message) { 26 | console.log(`${from} => ${to}: ${message}`); 27 | 28 | if (to.match(/^[#&]/)) { 29 | // channel message 30 | if (message.match(/hello/i)) { 31 | bot.say(to, `Hello there ${from}`); 32 | } 33 | if (message.match(/dance/)) { 34 | setTimeout(function () { bot.say(to, '\u0001ACTION dances: :D\\-<\u0001'); }, 1000); 35 | setTimeout(function () { bot.say(to, '\u0001ACTION dances: :D|-<\u0001'); }, 2000); 36 | setTimeout(function () { bot.say(to, '\u0001ACTION dances: :D/-<\u0001'); }, 3000); 37 | setTimeout(function () { bot.say(to, '\u0001ACTION dances: :D|-<\u0001'); }, 4000); 38 | } 39 | } 40 | else { 41 | // private message 42 | console.log('private message'); 43 | } 44 | }); 45 | bot.addListener('pm', function (nick, message) { 46 | console.log(`Got private message from ${nick}: ${message}`); 47 | }); 48 | bot.addListener('join', function (channel, who) { 49 | console.log(`${who} has joined ${channel}`); 50 | }); 51 | bot.addListener('part', function (channel, who, reason) { 52 | console.log(`${who} has left ${channel}: ${reason}`); 53 | }); 54 | bot.addListener('kick', function (channel, who, by, reason) { 55 | console.log(`${who} was kicked from ${channel} by ${by}: ${reason}`); 56 | }); 57 | 58 | bot.addListener('registered', function (message) { 59 | console.log(`registered ${message}`); 60 | bot.join('#test'); 61 | }); 62 | } 63 | -------------------------------------------------------------------------------- /src/trials/LobbynameTrial.ts: -------------------------------------------------------------------------------- 1 | export function trial() { 2 | const cases = ['a', 'asdflkj', ' $% BN |~=', '4-5 | alt | test @join', 'あいうおaaa', 'aa\n\raa']; 3 | for (const c of cases) { 4 | console.log(`${c} => ${rep(c)}`); 5 | } 6 | } 7 | 8 | function rep(text: string): string { 9 | text = text.replace(/[^ -~]/g, ''); 10 | return text; 11 | } -------------------------------------------------------------------------------- /src/trials/TypedEventTrials.ts: -------------------------------------------------------------------------------- 1 | import { TypedEvent } from '../libs/TypedEvent'; 2 | 3 | export function trial() { 4 | const e1 = new TypedEvent(); 5 | e1.once(n => console.log(`fired e1 arg = ${n}`)); 6 | e1.emit(1); 7 | 8 | const e2 = new TypedEvent<[number, string]>(); 9 | e2.once((t) => console.log(`fired e2 arg1 = ${t[0]} arg2 = ${t[1]}`)); 10 | e2.emit([1, 'x']); 11 | 12 | const e3 = new TypedEvent<{ a: number, b: string }>(); 13 | e3.once((t) => console.log(`fired e2 a = ${t.a} b = ${t.b}`)); 14 | const a = 1; 15 | const b = 'x'; 16 | const c = 'c'; 17 | e3.emit({ a, b }); 18 | } 19 | -------------------------------------------------------------------------------- /src/trials/WebApiTrial.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import config from 'config'; 3 | import { WebApiClient } from '../webapi/WebApiClient'; 4 | export interface WebApiTrialOption { 5 | client_id: number, 6 | client_secret: string, 7 | callback: string, 8 | code: string, 9 | } 10 | 11 | const oAuthConfig = config.get('WebApi'); 12 | 13 | export async function trial() { 14 | //getTokenTrial(); 15 | 16 | const client = WebApiClient; 17 | 18 | const user = await client.lookupBeatmapset(2647589); 19 | console.log(JSON.stringify(user)); 20 | } 21 | 22 | export async function getGuestTokenTrial(): Promise { 23 | try { 24 | const response = await axios.post('https://osu.ppy.sh/oauth/token', { 25 | 'grant_type': 'client_credentials', 26 | 'client_id': `${oAuthConfig.client_id}`, 27 | 'client_secret': oAuthConfig.client_secret, 28 | 'scope': 'public' 29 | }); 30 | const c = response.data; 31 | console.log(c); 32 | } catch (e: any) { 33 | console.error(`\n${e.message}\n${e.stack}`); 34 | } 35 | } 36 | 37 | export async function getTokenTrial(): Promise { 38 | try { 39 | const response = await axios.post('https://osu.ppy.sh/oauth/token', { 40 | 'grant_type': 'authorization_code', 41 | 'client_id': `${oAuthConfig.client_id}`, 42 | 'client_secret': oAuthConfig.client_secret, 43 | 'code': oAuthConfig.code, 44 | 'redirect_uri': oAuthConfig.callback 45 | }); 46 | const c = response.data; 47 | console.log(c); 48 | } catch (e: any) { 49 | console.error(`\n${e.message}\n${e.stack}`); 50 | } 51 | } 52 | 53 | function objectToURLSearchParams(obj: any): URLSearchParams { 54 | const param = new URLSearchParams(); 55 | for (const key in obj) { 56 | param.append(key, obj[key]); 57 | } 58 | return obj; 59 | } 60 | 61 | export async function fetchUpdateTrial(): Promise { 62 | try { 63 | const r = await axios.get('https://osu.ppy.sh/community/chat/updates?since=2065115911'); 64 | const c = r.data; 65 | console.log(c); 66 | } catch (e: any) { 67 | console.error(`\n${e.message}\n${e.stack}`); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/trials/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | hello world 8 | 9 | 10 |

hello world

11 | 12 | -------------------------------------------------------------------------------- /src/trials/index.ts: -------------------------------------------------------------------------------- 1 | //import * as trial from './WebServerTrial.js'; 2 | //trial.webServerTrial(); 3 | 4 | import { trial } from './DiscordTrial'; 5 | trial(); 6 | -------------------------------------------------------------------------------- /src/web/LogServer.ts: -------------------------------------------------------------------------------- 1 | import express from 'express'; 2 | import fs from 'fs'; 3 | import readline from 'readline'; 4 | import { Server } from 'http'; 5 | 6 | export function startLogServer(port: number): Server { 7 | const app = express(); 8 | app.use('', express.static('src/web/statics')); 9 | app.use('/logs', express.static('logs/cli')); 10 | app.get('/api/clilog', (req, res, next) => { 11 | fs.readdir('logs/cli', (err, files) => { 12 | if (err) throw err; 13 | const r = []; 14 | for (const f of files) { 15 | const m = f.match(/(\d+)\.log/); 16 | if (m) { 17 | r.push(parseInt(m[1])); 18 | } 19 | } 20 | res.json(r); 21 | }); 22 | }); 23 | app.get('/api/clilog/:id', (req, res, next) => { 24 | const p = `logs/cli/${req.params.id}.log`; 25 | let frm = 0; 26 | if (req.query.from) { 27 | frm = parseInt(`${req.query.from}`); 28 | } 29 | const stream = fs.createReadStream(p, { start: frm }); 30 | const reader = readline.createInterface({ input: stream }); 31 | const result: { lines: string[], end: number } = { 32 | lines: [], 33 | end: 0 34 | }; 35 | reader.on('line', (data) => { 36 | result.lines.push(data); 37 | }); 38 | reader.on('close', () => { 39 | result.end = stream.bytesRead + frm; 40 | res.json(result); 41 | }); 42 | stream.on('error', (e) => { 43 | console.log('cought error'); 44 | next(e); 45 | }); 46 | }); 47 | 48 | app.get('/api/clilog/size/:id', (req, res, next) => { 49 | const p = `logs/cli/${req.params.id}.log`; 50 | let frm = 0; 51 | if (req.query.from) { 52 | frm = parseInt(`${req.query.from}`); 53 | } 54 | fs.stat(p, (e, stats) => { 55 | if (e) { 56 | next(e); 57 | } else { 58 | res.json(stats.size); 59 | } 60 | }); 61 | }); 62 | 63 | app.get('/api/close', (req, res, next) => { 64 | server.close(); 65 | }); 66 | 67 | const server = app.listen(port, () => { 68 | console.log(`Server running at http://${'localhost'}:${port}/`); 69 | }); 70 | 71 | process.on('exit', (code) => { 72 | server.close(); 73 | }); 74 | 75 | return server; 76 | } 77 | 78 | //startLogServer(); 79 | -------------------------------------------------------------------------------- /src/web/OahrWeb.ts: -------------------------------------------------------------------------------- 1 | import config from 'config'; 2 | import express, { Express } from 'express'; 3 | import { Server } from 'http'; 4 | 5 | export interface OahrWebOption { 6 | port: number; 7 | staticDir:string; 8 | hostname: string; 9 | } 10 | 11 | const OahrWebDefaultOption = config.get('OahrWeb'); 12 | 13 | export class OahrWeb { 14 | config: OahrWebOption; 15 | app: Express; 16 | server: Server; 17 | 18 | constructor() { 19 | this.config = OahrWebDefaultOption; 20 | this.app = express(); 21 | this.app.use(express.static(this.config.staticDir)); 22 | this.server = this.app.listen(this.config.port, this.config.hostname, () => { 23 | console.log(`Server running at http://${this.config.hostname}:${this.config.port}/`); 24 | }); 25 | 26 | this.app.get('/api/test/:id', (req, res, next) => { 27 | const re = { 28 | test:'hello', 29 | id: req.params.id 30 | }; 31 | res.json(re); 32 | }); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/web/index.ts: -------------------------------------------------------------------------------- 1 | import { startLogServer } from './LogServer'; 2 | 3 | startLogServer(3112); 4 | -------------------------------------------------------------------------------- /src/web/statics/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Osu! Auto Host Rotation Log Viewer 8 | 10 | 11 | 12 | 13 | 14 |
15 |

Osu! Auto Host Rotation Log Viewer

16 | 17 | 18 | 19 | 20 | 21 | * 22 | 23 |
24 |
25 |
    26 |
    27 |
    28 |
    29 | 30 | 31 |
    32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/web/statics/main.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: 'Roboto Mono', monospace; 3 | background-color: rgb(40, 40, 40); 4 | color: white; 5 | } 6 | 7 | a { 8 | color: #77b2e3; 9 | font-size: smaller; 10 | } 11 | 12 | .date { 13 | color: gray; 14 | font-size: x-small; 15 | padding-right: 5px; 16 | } 17 | 18 | .level { 19 | color: gray; 20 | font-size: x-small; 21 | padding-right: 5px; 22 | } 23 | 24 | .tag { 25 | color: gray; 26 | font-size: x-small; 27 | padding-right: 5px; 28 | } 29 | 30 | .message { 31 | font-size: small; 32 | padding-right: 5px; 33 | } 34 | 35 | #list { 36 | list-style-type: none; 37 | padding-left: 0; 38 | white-space: nowrap; 39 | } 40 | 41 | .sender { 42 | text-align: right; 43 | 44 | min-width: 120px; 45 | display: inline-block; 46 | margin-right: 5px; 47 | } 48 | 49 | div.message { 50 | display: inline-block; 51 | } 52 | 53 | .sender.bot { 54 | color: #e285ee; 55 | } 56 | 57 | .sender.user { 58 | color: #ecee85; 59 | } 60 | 61 | .sender.system { 62 | color: #85bfee; 63 | } 64 | 65 | .fg30 { 66 | color: #000; 67 | } 68 | 69 | .fg31 { 70 | color: #cd3131; 71 | } 72 | 73 | .fg32 { 74 | color: #0dbc79; 75 | } 76 | 77 | .fg33 { 78 | color: #e5e510; 79 | } 80 | 81 | .fg34 { 82 | color: #2472c8; 83 | } 84 | 85 | .fg35 { 86 | color: #bc3fbc; 87 | } 88 | 89 | .fg36 { 90 | color: #11a8cd; 91 | } 92 | 93 | .fg37 { 94 | color: #e5e5e5; 95 | } -------------------------------------------------------------------------------- /src/webapi/Beatmapsets.ts: -------------------------------------------------------------------------------- 1 | 2 | export type Beatmapset = { 3 | 'artist': string, 4 | 'artist_unicode': string, 5 | 'covers': Covers, 6 | 'creator': string, 7 | 'favourite_count': number, 8 | 'id': number, 9 | 'nsfw': boolean, 10 | 'play_count': number, 11 | 'preview_url': string, 12 | 'source': string, 13 | 'status': string, 14 | 'title': string, 15 | 'title_unicode': string, 16 | 'track_id': number, 17 | 'user_id': number, 18 | 'video': boolean, 19 | 'availability': { 20 | 'download_disabled': boolean, 21 | 'more_information': any 22 | }, 23 | 'bpm': number, 24 | 'can_be_hyped': boolean, 25 | 'discussion_enabled': boolean, 26 | 'discussion_locked': boolean, 27 | 'hype': { 28 | 'current': number, 29 | 'required': number 30 | } | null, 31 | 'is_scoreable': boolean, 32 | 'last_updated': string, 33 | 'legacy_thread_url': string, 34 | 'nominations_summary': { 35 | 'current': number, 36 | 'required': number 37 | } | null, 38 | 'ranked': number, 39 | 'ranked_date': string, 40 | 'storyboard': boolean, 41 | 'submitted_date': string, 42 | 'tags': string, 43 | 'has_favourited'?: boolean, 44 | 'beatmaps'?: Beatmap[], 45 | 'converts'?: Beatmap[], 46 | 'current_user_attributes'?: { 47 | 'can_delete': false, 48 | 'can_edit_metadata': false, 49 | 'can_hype': true, 50 | 'can_hype_reason': null, 51 | 'can_love': false, 52 | 'is_watching': false, 53 | 'new_hype_time': null, 54 | 'remaining_hype': 10 55 | }, 56 | 'description'?: { 57 | 'description': string 58 | }, 59 | 'genre'?: { 60 | 'id': number, 61 | 'name': string 62 | }, 63 | 'language'?: { 64 | 'id': number, 65 | 'name': string 66 | }, 67 | 'ratings': number[], 68 | 'recent_favourites'?: any[], 69 | } 70 | 71 | export type Covers = { 72 | 'cover': string, 73 | 'cover@2x': string, 74 | 'card': string, 75 | 'card@2x': string, 76 | 'list': string, 77 | 'list@2x': string, 78 | 'slimcover': string, 79 | 'slimcover@2x': string 80 | } 81 | 82 | export type Beatmap = { 83 | 'difficulty_rating': number, 84 | 'id': number, 85 | 'mode': string, 86 | 'version': string, 87 | 'accuracy': number, 88 | 'ar': number, 89 | 'beatmapset_id': number, 90 | 'bpm': number, 91 | 'convert': boolean, 92 | 'count_circles': number, 93 | 'count_sliders': number, 94 | 'count_spinners': number, 95 | 'cs': number, 96 | 'deleted_at': any, 97 | 'drain': number, 98 | 'hit_length': number, 99 | 'is_scoreable': boolean, 100 | 'last_updated': string, 101 | 'mode_int': number, 102 | 'passcount': number, 103 | 'playcount': number, 104 | 'ranked': number, 105 | 'status': string, 106 | 'total_length': number, 107 | 'url': string, 108 | 'failtimes': { 109 | 'fail': number[], 110 | 'exit': number[] 111 | }, 112 | 'max_combo': number, 113 | 'beatmapset'?: Beatmapset 114 | } -------------------------------------------------------------------------------- /src/webapi/HistoryFetcher.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import { History } from './HistoryTypes'; 3 | 4 | export interface IHistoryFetcher { 5 | /** 6 | * パラメータに沿ったヒストリーを取得する 7 | * 通信エラーの場合は例外が発生する 8 | * @param limit 9 | * @param before 10 | * @param after 11 | * @param matchId 12 | */ 13 | fetchHistory(limit: number, before: number | null, after: number | null, matchId: number): Promise; 14 | } 15 | 16 | export class HistoryFecher implements IHistoryFetcher { 17 | async fetchHistory(limit: number, before: number | null, after: number | null, matchId: number): Promise { 18 | const url = `https://osu.ppy.sh/community/matches/${matchId}`; 19 | const params: any = { 20 | 'limit': limit, 21 | }; 22 | if (before) { 23 | params.before = before; 24 | } 25 | 26 | if (after) { 27 | params.after = after; 28 | } 29 | 30 | return (await axios.get(url, { params })).data; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/webapi/HistoryTypes.ts: -------------------------------------------------------------------------------- 1 | export type History = { 2 | 'match': Match, 3 | 'events': Event[], 4 | 'users': User[], 5 | 'latest_event_id': number, 6 | 'current_game_id': number | null 7 | } 8 | 9 | export type Match = { 10 | 'id': number, 11 | 'start_time': string, 12 | 'end_time': string | null, 13 | 'name': string 14 | } 15 | 16 | export type Event = { 17 | 'id': number, 18 | 'detail': { 19 | 'type': EventType, 20 | 'text'?: string 21 | }, 22 | 'game'?: Game, 23 | 'timestamp': string, 24 | 'user_id': number | null 25 | } 26 | 27 | export type EventType = 'match-created' | 'match-disbanded' | 28 | 'host-changed' | 'player-joined' | 'player-left' | 'player-kicked' | 29 | 'other'; 30 | 31 | export type User = { 32 | 'avatar_url': string | null, 33 | 'country_code': string, 34 | 'default_group': string, 35 | 'id': number, 36 | 'is_active': boolean, 37 | 'is_bot': boolean, 38 | 'is_online': boolean, 39 | 'is_supporter': boolean, 40 | 'last_visit': string, 41 | 'pm_friends_only': boolean, 42 | 'profile_colour': string | null, 43 | 'username': string, 44 | 'country': { 45 | 'code': string, 46 | 'name': string 47 | } 48 | } 49 | 50 | export type Game = { 51 | 'id': number 52 | 'start_time': string, 53 | 'end_time': string | null, 54 | 'mode': 'osu' | 'taiko' | 'fruits' | 'mania' | string, 55 | /** 56 | * 0 = osu, 1 = taiko, 2 = fruits, 3 = mania 57 | */ 58 | 'mode_int': number, 59 | 'scoring_type': 'score' | 'accuracy' | 'combo' | 'scorev2' | string, 60 | 'team_type': 'head-to-head' | 'tag-coop' | 'team-vs' | 'tag-team-vs' | string, 61 | 'mods': string[], 62 | 'beatmap': any, 63 | 'scores': Score[] 64 | } 65 | 66 | export type Score = { 67 | 'id': null, 68 | 'user_id': number, 69 | 'accuracy': number, 70 | 'mods': string[], 71 | 'score': number, 72 | 'max_combo': number, 73 | 'perfect': number, 74 | 'statistics': { 75 | 'count_50': number, 76 | 'count_100': number, 77 | 'count_300': number, 78 | 'count_geki': number, 79 | 'count_katu': number, 80 | 'count_miss': number 81 | }, 82 | 'rank': null, 83 | 'created_at': null, 84 | 'best_id': null, 85 | 'pp': number | null, 86 | 'match': { 87 | 'slot': number, 88 | 'team': 'none' | 'red' | 'blue', 89 | 'pass': number 90 | } 91 | } --------------------------------------------------------------------------------