├── .dockerignore ├── .gitignore ├── .vscode ├── launch.json ├── settings.json └── tasks.json ├── Dockerfile ├── README.md ├── bin ├── client.ts └── index.ts ├── docker-compose.yml ├── package-lock.json ├── package.json ├── src ├── Client.ts ├── audio │ ├── AudioError.ts │ ├── BroadcastStream.ts │ ├── Broadcasts.ts │ ├── DestinationStore.ts │ ├── Sources.ts │ ├── Track.ts │ └── sources │ │ ├── AudioSource.ts │ │ └── Mixer.ts ├── commands │ ├── eval.ts │ ├── help.ts │ ├── invite.ts │ ├── join.ts │ └── leave.ts ├── listeners │ ├── client │ │ ├── debug.ts │ │ ├── error.ts │ │ └── ready.ts │ └── twitch │ │ ├── error.ts │ │ └── message.ts ├── logger.ts └── typings │ ├── javelin.d.ts │ └── m3u8-parser.d.ts └── tsconfig.json /.dockerignore: -------------------------------------------------------------------------------- 1 | /lavalink* 2 | /node_modules* 3 | /dist* 4 | .env 5 | .git* 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | /typings/ 3 | /dist/ 4 | /data/ 5 | .env 6 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "request": "launch", 10 | "name": "Launch Program", 11 | "program": "${workspaceFolder}\\dist\\bin\\client.js", 12 | "outFiles": [ 13 | "${workspaceFolder}/dist/**/*.map.js" 14 | ], 15 | "sourceMaps": true, 16 | "envFile": "${workspaceFolder}/.env", 17 | "preLaunchTask": "build" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "typescript.tsdk": "node_modules\\typescript\\lib" 3 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "type": "typescript", 8 | "tsconfig": "tsconfig.json", 9 | "problemMatcher": [ 10 | "$tsc" 11 | ], 12 | "label": "build" 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:12-alpine 2 | 3 | WORKDIR /usr/src/monstercat 4 | COPY package.json package-lock.json ./ 5 | 6 | RUN apk add --update \ 7 | && apk add --no-cache --virtual .build-deps git build-base g++ python \ 8 | && apk add --no-cache --virtual .npm-deps opus ffmpeg 9 | 10 | RUN npm install \ 11 | && apk del .build-deps 12 | 13 | COPY . . 14 | 15 | RUN npm run prepare 16 | CMD [ "npm", "start" ] 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Monstercat bot 2 | 3 | A simple Discord bot for streaming Monstercat music. [Add Me.](https://discordapp.com/oauth2/authorize?permissions=3165184&scope=bot&client_id=251253454826110977) 4 | 5 | ## Commands 6 | 7 | - help 8 | - invite - get the invite to share 9 | - join - join voice 10 | - leave - leave voice 11 | -------------------------------------------------------------------------------- /bin/client.ts: -------------------------------------------------------------------------------- 1 | import Client from '../src/Client'; 2 | 3 | if (!process.env.TWITCH_OAUTH_PASSWORD) throw new Error('Twitch OAuth password not specified'); 4 | if (!process.env.TWITCH_USERNAME) throw new Error('Twitch username not specified'); 5 | if (!process.env.DISCORD_TOKEN) throw new Error('No Discord token specified'); 6 | if (!process.env.TWITCH_CLIENT_ID) throw new Error('Twitch client ID not specified'); 7 | 8 | const client = new Client({ 9 | ownerID: process.env.OWNER || '116690352584392704', 10 | clientID: process.env.DISCORD_CLIENT_ID || '251253454826110977', 11 | twitch: { 12 | oauth: process.env.TWITCH_OAUTH_PASSWORD, 13 | username: process.env.TWITCH_USERNAME, 14 | }, 15 | redis: process.env.REDIS_URL || 'redis://redis:6379', 16 | }); 17 | client.logger.info(`shard ${client.shard && client.shard.ids}`); 18 | client.login(process.env.DISCORD_TOKEN).then(() => client.logger.info(`shard ${client.shard && client.shard.ids} ready`)); 19 | -------------------------------------------------------------------------------- /bin/index.ts: -------------------------------------------------------------------------------- 1 | #!/bin/env/node 2 | import { ShardingManager } from 'discord.js'; 3 | import * as path from 'path'; 4 | 5 | const manager = new ShardingManager(path.resolve(__dirname, 'client.js'), { token: process.env.DISCORD_TOKEN }); 6 | manager.spawn(); 7 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | services: 3 | bot: 4 | build: . 5 | env_file: .env 6 | volumes: 7 | - ./data:/usr/src/monstercat/data 8 | redis: 9 | image: redis:alpine 10 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "monstercat", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@types/backoff": { 8 | "version": "2.5.1", 9 | "resolved": "https://registry.npmjs.org/@types/backoff/-/backoff-2.5.1.tgz", 10 | "integrity": "sha512-eUNAT0dGCma0K35XcScxCP5usgCyxFypkVUN1TiHLhqGzbLnb/fVhz5yoXzj/SYLuXxE9SK6k4m+FQZQqQ4QaQ==", 11 | "dev": true, 12 | "requires": { 13 | "@types/node": "*" 14 | } 15 | }, 16 | "@types/events": { 17 | "version": "1.2.0", 18 | "resolved": "https://registry.npmjs.org/@types/events/-/events-1.2.0.tgz", 19 | "integrity": "sha512-KEIlhXnIutzKwRbQkGWb/I4HFqBuUykAdHgDED6xqwXJfONCjF5VoE0cXEiurh3XauygxzeDzgtXUqvLkxFzzA==", 20 | "dev": true 21 | }, 22 | "@types/ioredis": { 23 | "version": "4.0.11", 24 | "resolved": "https://registry.npmjs.org/@types/ioredis/-/ioredis-4.0.11.tgz", 25 | "integrity": "sha512-spuEM4/UxlFH95NCrMojH9FTP3SLm8N2Itb9f0z0pca1IVdlPHobjps+KccEiUuYdfhzpdKOox8yGoqO9vahaw==", 26 | "dev": true, 27 | "requires": { 28 | "@types/node": "*" 29 | } 30 | }, 31 | "@types/node": { 32 | "version": "12.0.2", 33 | "resolved": "https://registry.npmjs.org/@types/node/-/node-12.0.2.tgz", 34 | "integrity": "sha512-5tabW/i+9mhrfEOUcLDu2xBPsHJ+X5Orqy9FKpale3SjDA17j5AEpYq5vfy3oAeAHGcvANRCO3NV3d2D6q3NiA==", 35 | "dev": true 36 | }, 37 | "@types/ws": { 38 | "version": "6.0.1", 39 | "resolved": "https://registry.npmjs.org/@types/ws/-/ws-6.0.1.tgz", 40 | "integrity": "sha512-EzH8k1gyZ4xih/MaZTXwT2xOkPiIMSrhQ9b8wrlX88L0T02eYsddatQlwVFlEPyEqV0ChpdpNnE51QPH6NVT4Q==", 41 | "dev": true, 42 | "requires": { 43 | "@types/events": "*", 44 | "@types/node": "*" 45 | } 46 | }, 47 | "ansi-regex": { 48 | "version": "2.1.1", 49 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", 50 | "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", 51 | "optional": true 52 | }, 53 | "aproba": { 54 | "version": "1.2.0", 55 | "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", 56 | "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", 57 | "optional": true 58 | }, 59 | "are-we-there-yet": { 60 | "version": "1.1.4", 61 | "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz", 62 | "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", 63 | "optional": true, 64 | "requires": { 65 | "delegates": "^1.0.0", 66 | "readable-stream": "^2.0.6" 67 | } 68 | }, 69 | "async": { 70 | "version": "2.6.2", 71 | "resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz", 72 | "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==", 73 | "requires": { 74 | "lodash": "^4.17.11" 75 | } 76 | }, 77 | "async-limiter": { 78 | "version": "1.0.0", 79 | "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", 80 | "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" 81 | }, 82 | "asynckit": { 83 | "version": "0.4.0", 84 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 85 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" 86 | }, 87 | "axios": { 88 | "version": "0.18.1", 89 | "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.1.tgz", 90 | "integrity": "sha512-0BfJq4NSfQXd+SkFdrvFbG7addhYSBA2mQwISr46pD6E5iqkWg02RAs8vyTT/j0RTnoYmeXauBuSv1qKwR179g==", 91 | "requires": { 92 | "follow-redirects": "1.5.10", 93 | "is-buffer": "^2.0.2" 94 | } 95 | }, 96 | "balanced-match": { 97 | "version": "1.0.0", 98 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 99 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 100 | "dev": true 101 | }, 102 | "bindings": { 103 | "version": "1.2.1", 104 | "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.2.1.tgz", 105 | "integrity": "sha1-FK1hE4EtLTfXLme0ystLtyZQXxE=", 106 | "optional": true 107 | }, 108 | "bl": { 109 | "version": "1.2.1", 110 | "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.1.tgz", 111 | "integrity": "sha1-ysMo977kVzDUBLaSID/LWQ4XLV4=", 112 | "optional": true, 113 | "requires": { 114 | "readable-stream": "^2.0.5" 115 | } 116 | }, 117 | "brace-expansion": { 118 | "version": "1.1.11", 119 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 120 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 121 | "dev": true, 122 | "requires": { 123 | "balanced-match": "^1.0.0", 124 | "concat-map": "0.0.1" 125 | } 126 | }, 127 | "bufferutil": { 128 | "version": "3.0.2", 129 | "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-3.0.2.tgz", 130 | "integrity": "sha512-CGk0C62APhIdbcKwP6Pr293Pba/u9xvrC/X4D6YQZzxhSjb+/rHFYSCorEWIxLo6HbwTuy7SEsgTmsvBCn3dKw==", 131 | "optional": true, 132 | "requires": { 133 | "bindings": "~1.2.1", 134 | "nan": "~2.6.0", 135 | "prebuild-install": "~2.2.0" 136 | } 137 | }, 138 | "chownr": { 139 | "version": "1.0.1", 140 | "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.0.1.tgz", 141 | "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=", 142 | "optional": true 143 | }, 144 | "cluster-key-slot": { 145 | "version": "1.0.12", 146 | "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.0.12.tgz", 147 | "integrity": "sha512-21O0kGmvED5OJ7ZTdqQ5lQQ+sjuez33R+d35jZKLwqUb5mqcPHUsxOSzj61+LHVtxGZd1kShbQM3MjB/gBJkVg==" 148 | }, 149 | "code-point-at": { 150 | "version": "1.1.0", 151 | "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", 152 | "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", 153 | "optional": true 154 | }, 155 | "color": { 156 | "version": "3.0.0", 157 | "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz", 158 | "integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==", 159 | "requires": { 160 | "color-convert": "^1.9.1", 161 | "color-string": "^1.5.2" 162 | } 163 | }, 164 | "color-convert": { 165 | "version": "1.9.3", 166 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 167 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 168 | "requires": { 169 | "color-name": "1.1.3" 170 | } 171 | }, 172 | "color-name": { 173 | "version": "1.1.3", 174 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 175 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" 176 | }, 177 | "color-string": { 178 | "version": "1.5.3", 179 | "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.3.tgz", 180 | "integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==", 181 | "requires": { 182 | "color-name": "^1.0.0", 183 | "simple-swizzle": "^0.2.2" 184 | } 185 | }, 186 | "colornames": { 187 | "version": "1.1.1", 188 | "resolved": "https://registry.npmjs.org/colornames/-/colornames-1.1.1.tgz", 189 | "integrity": "sha1-+IiQMGhcfE/54qVZ9Qd+t2qBb5Y=" 190 | }, 191 | "colors": { 192 | "version": "1.3.3", 193 | "resolved": "https://registry.npmjs.org/colors/-/colors-1.3.3.tgz", 194 | "integrity": "sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg==" 195 | }, 196 | "colorspace": { 197 | "version": "1.1.2", 198 | "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.2.tgz", 199 | "integrity": "sha512-vt+OoIP2d76xLhjwbBaucYlNSpPsrJWPlBTtwCpQKIu6/CSMutyzX93O/Do0qzpH3YoHEes8YEFXyZ797rEhzQ==", 200 | "requires": { 201 | "color": "3.0.x", 202 | "text-hex": "1.0.x" 203 | } 204 | }, 205 | "combined-stream": { 206 | "version": "1.0.8", 207 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", 208 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", 209 | "requires": { 210 | "delayed-stream": "~1.0.0" 211 | } 212 | }, 213 | "commander": { 214 | "version": "2.20.0", 215 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", 216 | "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==" 217 | }, 218 | "concat-map": { 219 | "version": "0.0.1", 220 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 221 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 222 | "dev": true 223 | }, 224 | "console-control-strings": { 225 | "version": "1.1.0", 226 | "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", 227 | "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", 228 | "optional": true 229 | }, 230 | "core-util-is": { 231 | "version": "1.0.2", 232 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 233 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" 234 | }, 235 | "cross-spawn": { 236 | "version": "6.0.5", 237 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", 238 | "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", 239 | "dev": true, 240 | "requires": { 241 | "nice-try": "^1.0.4", 242 | "path-key": "^2.0.1", 243 | "semver": "^5.5.0", 244 | "shebang-command": "^1.2.0", 245 | "which": "^1.2.9" 246 | } 247 | }, 248 | "debug": { 249 | "version": "3.2.6", 250 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", 251 | "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", 252 | "requires": { 253 | "ms": "^2.1.1" 254 | } 255 | }, 256 | "deep-extend": { 257 | "version": "0.4.2", 258 | "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.2.tgz", 259 | "integrity": "sha1-SLaZwn4zS/ifEIkr5DL25MfTSn8=", 260 | "optional": true 261 | }, 262 | "delayed-stream": { 263 | "version": "1.0.0", 264 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 265 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" 266 | }, 267 | "delegates": { 268 | "version": "1.0.0", 269 | "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", 270 | "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", 271 | "optional": true 272 | }, 273 | "denque": { 274 | "version": "1.4.1", 275 | "resolved": "https://registry.npmjs.org/denque/-/denque-1.4.1.tgz", 276 | "integrity": "sha512-OfzPuSZKGcgr96rf1oODnfjqBFmr1DVoc/TrItj3Ohe0Ah1C5WX5Baquw/9U9KovnQ88EqmJbD66rKYUQYN1tQ==" 277 | }, 278 | "diagnostics": { 279 | "version": "1.1.1", 280 | "resolved": "https://registry.npmjs.org/diagnostics/-/diagnostics-1.1.1.tgz", 281 | "integrity": "sha512-8wn1PmdunLJ9Tqbx+Fx/ZEuHfJf4NKSN2ZBj7SJC/OWRWha843+WsTjqMe1B5E3p28jqBlp+mJ2fPVxPyNgYKQ==", 282 | "requires": { 283 | "colorspace": "1.1.x", 284 | "enabled": "1.0.x", 285 | "kuler": "1.0.x" 286 | } 287 | }, 288 | "discord-akairo": { 289 | "version": "8.0.0-beta.8", 290 | "resolved": "https://registry.npmjs.org/discord-akairo/-/discord-akairo-8.0.0-beta.8.tgz", 291 | "integrity": "sha512-aT64C1vvntCoSV/i/yAVAHrYyz1Y+5IAWagUaDsrv8M2zKmakcOvT62Iqhz5oK89k8UgVU23aIsLiq01U1bJDQ==" 292 | }, 293 | "discord.js": { 294 | "version": "github:discordjs/discord.js#d1c4d423e9c7d9c8af9f9b562d1aeac1a29df317", 295 | "from": "github:discordjs/discord.js#d1c4d423e9c7d9c8af9f9b562d1aeac1a29df317", 296 | "requires": { 297 | "form-data": "^2.3.3", 298 | "node-fetch": "^2.3.0", 299 | "pako": "^1.0.8", 300 | "prism-media": "github:amishshah/prism-media", 301 | "setimmediate": "^1.0.5", 302 | "tweetnacl": "^1.0.1", 303 | "ws": "^6.1.3" 304 | }, 305 | "dependencies": { 306 | "ws": { 307 | "version": "6.2.1", 308 | "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", 309 | "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", 310 | "requires": { 311 | "async-limiter": "~1.0.0" 312 | } 313 | } 314 | } 315 | }, 316 | "dom-walk": { 317 | "version": "0.1.1", 318 | "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.1.tgz", 319 | "integrity": "sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg=" 320 | }, 321 | "enabled": { 322 | "version": "1.0.2", 323 | "resolved": "https://registry.npmjs.org/enabled/-/enabled-1.0.2.tgz", 324 | "integrity": "sha1-ll9lE9LC0cX0ZStkouM5ZGf8L5M=", 325 | "requires": { 326 | "env-variable": "0.0.x" 327 | } 328 | }, 329 | "end-of-stream": { 330 | "version": "1.4.0", 331 | "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.0.tgz", 332 | "integrity": "sha1-epDYM+/abPpurA9JSduw+tOmMgY=", 333 | "optional": true, 334 | "requires": { 335 | "once": "^1.4.0" 336 | } 337 | }, 338 | "env-cmd": { 339 | "version": "9.0.1", 340 | "resolved": "https://registry.npmjs.org/env-cmd/-/env-cmd-9.0.1.tgz", 341 | "integrity": "sha512-zFKkksLGn+JClAKd/McvT+K45K4ZbmFdaILPdvG86q2SxJ7/6v45RpP4/VbyACCRgeXz0f9Gt3Yr8klzKLq3gw==", 342 | "dev": true, 343 | "requires": { 344 | "commander": "^2.20.0", 345 | "cross-spawn": "6.0.5" 346 | } 347 | }, 348 | "env-variable": { 349 | "version": "0.0.5", 350 | "resolved": "https://registry.npmjs.org/env-variable/-/env-variable-0.0.5.tgz", 351 | "integrity": "sha512-zoB603vQReOFvTg5xMl9I1P2PnHsHQQKTEowsKKD7nseUfJq6UWzK+4YtlWUO1nhiQUxe6XMkk+JleSZD1NZFA==" 352 | }, 353 | "expand-template": { 354 | "version": "1.1.0", 355 | "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-1.1.0.tgz", 356 | "integrity": "sha512-kkjwkMqj0h4w/sb32ERCDxCQkREMCAgS39DscDnSwDsbxnwwM1BTZySdC3Bn1lhY7vL08n9GoO/fVTynjDgRyQ==", 357 | "optional": true 358 | }, 359 | "fast-safe-stringify": { 360 | "version": "2.0.6", 361 | "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.6.tgz", 362 | "integrity": "sha512-q8BZ89jjc+mz08rSxROs8VsrBBcn1SIw1kq9NjolL509tkABRk9io01RAjSaEv1Xb2uFLt8VtRiZbGp5H8iDtg==" 363 | }, 364 | "fecha": { 365 | "version": "2.3.3", 366 | "resolved": "https://registry.npmjs.org/fecha/-/fecha-2.3.3.tgz", 367 | "integrity": "sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg==" 368 | }, 369 | "follow-redirects": { 370 | "version": "1.5.10", 371 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", 372 | "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", 373 | "requires": { 374 | "debug": "=3.1.0" 375 | }, 376 | "dependencies": { 377 | "debug": { 378 | "version": "3.1.0", 379 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 380 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 381 | "requires": { 382 | "ms": "2.0.0" 383 | } 384 | }, 385 | "ms": { 386 | "version": "2.0.0", 387 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 388 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 389 | } 390 | } 391 | }, 392 | "form-data": { 393 | "version": "2.3.3", 394 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", 395 | "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", 396 | "requires": { 397 | "asynckit": "^0.4.0", 398 | "combined-stream": "^1.0.6", 399 | "mime-types": "^2.1.12" 400 | } 401 | }, 402 | "fs.realpath": { 403 | "version": "1.0.0", 404 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 405 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 406 | "dev": true 407 | }, 408 | "gauge": { 409 | "version": "2.7.4", 410 | "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", 411 | "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", 412 | "optional": true, 413 | "requires": { 414 | "aproba": "^1.0.3", 415 | "console-control-strings": "^1.0.0", 416 | "has-unicode": "^2.0.0", 417 | "object-assign": "^4.1.0", 418 | "signal-exit": "^3.0.0", 419 | "string-width": "^1.0.1", 420 | "strip-ansi": "^3.0.1", 421 | "wide-align": "^1.1.0" 422 | } 423 | }, 424 | "github-from-package": { 425 | "version": "0.0.0", 426 | "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", 427 | "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=", 428 | "optional": true 429 | }, 430 | "glob": { 431 | "version": "7.1.4", 432 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", 433 | "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", 434 | "dev": true, 435 | "requires": { 436 | "fs.realpath": "^1.0.0", 437 | "inflight": "^1.0.4", 438 | "inherits": "2", 439 | "minimatch": "^3.0.4", 440 | "once": "^1.3.0", 441 | "path-is-absolute": "^1.0.0" 442 | } 443 | }, 444 | "global": { 445 | "version": "4.3.2", 446 | "resolved": "https://registry.npmjs.org/global/-/global-4.3.2.tgz", 447 | "integrity": "sha1-52mJJopsdMOJCLEwWxD8DjlOnQ8=", 448 | "requires": { 449 | "min-document": "^2.19.0", 450 | "process": "~0.5.1" 451 | } 452 | }, 453 | "has-unicode": { 454 | "version": "2.0.1", 455 | "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", 456 | "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", 457 | "optional": true 458 | }, 459 | "inflight": { 460 | "version": "1.0.6", 461 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 462 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 463 | "dev": true, 464 | "requires": { 465 | "once": "^1.3.0", 466 | "wrappy": "1" 467 | } 468 | }, 469 | "inherits": { 470 | "version": "2.0.3", 471 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 472 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 473 | }, 474 | "ini": { 475 | "version": "1.3.4", 476 | "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz", 477 | "integrity": "sha1-BTfLedr1m1mhpRff9wbIbsA5Fi4=", 478 | "optional": true 479 | }, 480 | "ioredis": { 481 | "version": "4.9.5", 482 | "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-4.9.5.tgz", 483 | "integrity": "sha512-L9MVfvX4F3LScTMEgriCGixzqinJsYy7Mt0NPX8RyuOTmx5JW0744pM4Ze2KVQcP3J0zvKYZ1LywAB6KIq7PYg==", 484 | "requires": { 485 | "cluster-key-slot": "^1.0.6", 486 | "debug": "^3.1.0", 487 | "denque": "^1.1.0", 488 | "lodash.defaults": "^4.2.0", 489 | "lodash.flatten": "^4.4.0", 490 | "redis-commands": "1.4.0", 491 | "redis-errors": "^1.2.0", 492 | "redis-parser": "^3.0.0", 493 | "standard-as-callback": "^2.0.1" 494 | }, 495 | "dependencies": { 496 | "redis-commands": { 497 | "version": "1.4.0", 498 | "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.4.0.tgz", 499 | "integrity": "sha512-cu8EF+MtkwI4DLIT0x9P8qNTLFhQD4jLfxLR0cCNkeGzs87FN6879JOJwNQR/1zD7aSYNbU0hgsV9zGY71Itvw==" 500 | }, 501 | "redis-parser": { 502 | "version": "3.0.0", 503 | "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", 504 | "integrity": "sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ=", 505 | "requires": { 506 | "redis-errors": "^1.0.0" 507 | } 508 | } 509 | } 510 | }, 511 | "is-buffer": { 512 | "version": "2.0.4", 513 | "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", 514 | "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==" 515 | }, 516 | "is-fullwidth-code-point": { 517 | "version": "1.0.0", 518 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", 519 | "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", 520 | "optional": true, 521 | "requires": { 522 | "number-is-nan": "^1.0.0" 523 | } 524 | }, 525 | "is-stream": { 526 | "version": "1.1.0", 527 | "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", 528 | "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" 529 | }, 530 | "isarray": { 531 | "version": "1.0.0", 532 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 533 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" 534 | }, 535 | "isexe": { 536 | "version": "2.0.0", 537 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 538 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", 539 | "dev": true 540 | }, 541 | "javelin": { 542 | "version": "0.3.3", 543 | "resolved": "https://registry.npmjs.org/javelin/-/javelin-0.3.3.tgz", 544 | "integrity": "sha512-OqmIazCMQbOB+o04CkflcfkA3wETB/SKwFTxSosZ4CYjhL71w7D3o43EtdYIJtgpxwLhH6rXuQNe7mYkliIW/A==", 545 | "requires": { 546 | "ws": "^6.0.0" 547 | } 548 | }, 549 | "kuler": { 550 | "version": "1.0.1", 551 | "resolved": "https://registry.npmjs.org/kuler/-/kuler-1.0.1.tgz", 552 | "integrity": "sha512-J9nVUucG1p/skKul6DU3PUZrhs0LPulNaeUOox0IyXDi8S4CztTHs1gQphhuZmzXG7VOQSf6NJfKuzteQLv9gQ==", 553 | "requires": { 554 | "colornames": "^1.1.1" 555 | } 556 | }, 557 | "lodash": { 558 | "version": "4.17.19", 559 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", 560 | "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==" 561 | }, 562 | "lodash.defaults": { 563 | "version": "4.2.0", 564 | "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", 565 | "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=" 566 | }, 567 | "lodash.flatten": { 568 | "version": "4.4.0", 569 | "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", 570 | "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=" 571 | }, 572 | "logform": { 573 | "version": "2.1.2", 574 | "resolved": "https://registry.npmjs.org/logform/-/logform-2.1.2.tgz", 575 | "integrity": "sha512-+lZh4OpERDBLqjiwDLpAWNQu6KMjnlXH2ByZwCuSqVPJletw0kTWJf5CgSNAUKn1KUkv3m2cUz/LK8zyEy7wzQ==", 576 | "requires": { 577 | "colors": "^1.2.1", 578 | "fast-safe-stringify": "^2.0.4", 579 | "fecha": "^2.3.3", 580 | "ms": "^2.1.1", 581 | "triple-beam": "^1.3.0" 582 | } 583 | }, 584 | "m3u8-parser": { 585 | "version": "4.3.0", 586 | "resolved": "https://registry.npmjs.org/m3u8-parser/-/m3u8-parser-4.3.0.tgz", 587 | "integrity": "sha512-bVbjuBMoVIgFL1vpXVIxjeaoB5TPDJRb0m5qiTdM738SGqv/LAmsnVVPlKjM4fulm/rr1XZsKM+owHm+zvqxYA==", 588 | "requires": { 589 | "global": "^4.3.2" 590 | } 591 | }, 592 | "mime-db": { 593 | "version": "1.40.0", 594 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", 595 | "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==" 596 | }, 597 | "mime-types": { 598 | "version": "2.1.24", 599 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", 600 | "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", 601 | "requires": { 602 | "mime-db": "1.40.0" 603 | } 604 | }, 605 | "min-document": { 606 | "version": "2.19.0", 607 | "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", 608 | "integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=", 609 | "requires": { 610 | "dom-walk": "^0.1.0" 611 | } 612 | }, 613 | "minimatch": { 614 | "version": "3.0.4", 615 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 616 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 617 | "dev": true, 618 | "requires": { 619 | "brace-expansion": "^1.1.7" 620 | } 621 | }, 622 | "minimist": { 623 | "version": "1.2.0", 624 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", 625 | "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", 626 | "optional": true 627 | }, 628 | "mkdirp": { 629 | "version": "0.5.1", 630 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 631 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 632 | "optional": true, 633 | "requires": { 634 | "minimist": "0.0.8" 635 | }, 636 | "dependencies": { 637 | "minimist": { 638 | "version": "0.0.8", 639 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", 640 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", 641 | "optional": true 642 | } 643 | } 644 | }, 645 | "ms": { 646 | "version": "2.1.1", 647 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", 648 | "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" 649 | }, 650 | "nan": { 651 | "version": "2.6.2", 652 | "resolved": "https://registry.npmjs.org/nan/-/nan-2.6.2.tgz", 653 | "integrity": "sha1-5P805slf37WuzAjeZZb0NgWn20U=", 654 | "optional": true 655 | }, 656 | "nice-try": { 657 | "version": "1.0.5", 658 | "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", 659 | "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", 660 | "dev": true 661 | }, 662 | "node-abi": { 663 | "version": "2.1.1", 664 | "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.1.1.tgz", 665 | "integrity": "sha512-6oxV13poCOv7TfGvhsSz6XZWpXeKkdGVh72++cs33OfMh3KAX8lN84dCvmqSETyDXAFcUHtV7eJrgFBoOqZbNQ==", 666 | "optional": true 667 | }, 668 | "node-fetch": { 669 | "version": "2.6.0", 670 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", 671 | "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" 672 | }, 673 | "node-gyp-build": { 674 | "version": "3.7.0", 675 | "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-3.7.0.tgz", 676 | "integrity": "sha512-L/Eg02Epx6Si2NXmedx+Okg+4UHqmaf3TNcxd50SF9NQGcJaON3AtU++kax69XV7YWz4tUspqZSAsVofhFKG2w==", 677 | "optional": true 678 | }, 679 | "node-opus": { 680 | "version": "0.3.2", 681 | "resolved": "https://registry.npmjs.org/node-opus/-/node-opus-0.3.2.tgz", 682 | "integrity": "sha512-o7hKgNncfbgF1j25lCK7cPqs9DEMroP3LWW0BMb/Ismc33cXo7LcaLqS0+/VV+NOotIy43fb7juLg6akflzBEw==", 683 | "optional": true, 684 | "requires": { 685 | "bindings": "~1.2.1", 686 | "commander": "^2.9.0", 687 | "nan": "^2.14.0", 688 | "ogg-packet": "^1.0.0" 689 | }, 690 | "dependencies": { 691 | "nan": { 692 | "version": "2.14.0", 693 | "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", 694 | "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", 695 | "optional": true 696 | } 697 | } 698 | }, 699 | "noop-logger": { 700 | "version": "0.1.1", 701 | "resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz", 702 | "integrity": "sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI=", 703 | "optional": true 704 | }, 705 | "npmlog": { 706 | "version": "4.1.2", 707 | "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", 708 | "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", 709 | "optional": true, 710 | "requires": { 711 | "are-we-there-yet": "~1.1.2", 712 | "console-control-strings": "~1.1.0", 713 | "gauge": "~2.7.3", 714 | "set-blocking": "~2.0.0" 715 | } 716 | }, 717 | "number-is-nan": { 718 | "version": "1.0.1", 719 | "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", 720 | "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", 721 | "optional": true 722 | }, 723 | "object-assign": { 724 | "version": "4.1.1", 725 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 726 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", 727 | "optional": true 728 | }, 729 | "ogg-packet": { 730 | "version": "1.0.1", 731 | "resolved": "https://registry.npmjs.org/ogg-packet/-/ogg-packet-1.0.1.tgz", 732 | "integrity": "sha512-dW1ok3BMnMikyXGDIgVEckWnlViW8JLWQV4qj9aN/rNRVqHlDYSlcIEtSIMH7tpuUOiIxAhY3+OxNdIOm6s17A==", 733 | "optional": true, 734 | "requires": { 735 | "ref-struct": "*" 736 | } 737 | }, 738 | "once": { 739 | "version": "1.4.0", 740 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 741 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 742 | "requires": { 743 | "wrappy": "1" 744 | } 745 | }, 746 | "one-time": { 747 | "version": "0.0.4", 748 | "resolved": "https://registry.npmjs.org/one-time/-/one-time-0.0.4.tgz", 749 | "integrity": "sha1-+M33eISCb+Tf+T46nMN7HkSAdC4=" 750 | }, 751 | "os-homedir": { 752 | "version": "1.0.2", 753 | "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", 754 | "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", 755 | "optional": true 756 | }, 757 | "pako": { 758 | "version": "1.0.10", 759 | "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz", 760 | "integrity": "sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==" 761 | }, 762 | "path-is-absolute": { 763 | "version": "1.0.1", 764 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 765 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 766 | "dev": true 767 | }, 768 | "path-key": { 769 | "version": "2.0.1", 770 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", 771 | "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", 772 | "dev": true 773 | }, 774 | "prebuild-install": { 775 | "version": "2.2.2", 776 | "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-2.2.2.tgz", 777 | "integrity": "sha512-F46pcvDxtQhbV3B+dm+exHuKxIyJK26fVNiJRmbTW/5D7o0Z2yzc8CKeu7UWbo9XxQZoVOC88aKgySAsza+cWw==", 778 | "optional": true, 779 | "requires": { 780 | "expand-template": "^1.0.2", 781 | "github-from-package": "0.0.0", 782 | "minimist": "^1.2.0", 783 | "mkdirp": "^0.5.1", 784 | "node-abi": "^2.0.0", 785 | "noop-logger": "^0.1.1", 786 | "npmlog": "^4.0.1", 787 | "os-homedir": "^1.0.1", 788 | "pump": "^1.0.1", 789 | "rc": "^1.1.6", 790 | "simple-get": "^1.4.2", 791 | "tar-fs": "^1.13.0", 792 | "tunnel-agent": "^0.6.0", 793 | "xtend": "4.0.1" 794 | } 795 | }, 796 | "prism-media": { 797 | "version": "github:amishshah/prism-media#c91ddeb27d3ccc9952feb2d6546d3098f7d3a6cb", 798 | "from": "github:amishshah/prism-media" 799 | }, 800 | "process": { 801 | "version": "0.5.2", 802 | "resolved": "https://registry.npmjs.org/process/-/process-0.5.2.tgz", 803 | "integrity": "sha1-FjjYqONML0QKkduVq5rrZ3/Bhc8=" 804 | }, 805 | "process-nextick-args": { 806 | "version": "1.0.7", 807 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", 808 | "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", 809 | "optional": true 810 | }, 811 | "pump": { 812 | "version": "1.0.2", 813 | "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.2.tgz", 814 | "integrity": "sha1-Oz7mUS+U8OV1U4wXmV+fFpkKXVE=", 815 | "optional": true, 816 | "requires": { 817 | "end-of-stream": "^1.1.0", 818 | "once": "^1.3.1" 819 | } 820 | }, 821 | "rc": { 822 | "version": "1.2.2", 823 | "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.2.tgz", 824 | "integrity": "sha1-2M6ctX6NZNnHut2YdsfDTL48cHc=", 825 | "optional": true, 826 | "requires": { 827 | "deep-extend": "~0.4.0", 828 | "ini": "~1.3.0", 829 | "minimist": "^1.2.0", 830 | "strip-json-comments": "~2.0.1" 831 | } 832 | }, 833 | "readable-stream": { 834 | "version": "2.3.3", 835 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", 836 | "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", 837 | "optional": true, 838 | "requires": { 839 | "core-util-is": "~1.0.0", 840 | "inherits": "~2.0.3", 841 | "isarray": "~1.0.0", 842 | "process-nextick-args": "~1.0.6", 843 | "safe-buffer": "~5.1.1", 844 | "string_decoder": "~1.0.3", 845 | "util-deprecate": "~1.0.1" 846 | } 847 | }, 848 | "redis-errors": { 849 | "version": "1.2.0", 850 | "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", 851 | "integrity": "sha1-62LSrbFeTq9GEMBK/hUpOEJQq60=" 852 | }, 853 | "ref": { 854 | "version": "1.3.5", 855 | "resolved": "https://registry.npmjs.org/ref/-/ref-1.3.5.tgz", 856 | "integrity": "sha512-2cBCniTtxcGUjDpvFfVpw323a83/0RLSGJJY5l5lcomZWhYpU2cuLdsvYqMixvsdLJ9+sTdzEkju8J8ZHDM2nA==", 857 | "optional": true, 858 | "requires": { 859 | "bindings": "1", 860 | "debug": "2", 861 | "nan": "2" 862 | }, 863 | "dependencies": { 864 | "debug": { 865 | "version": "2.6.9", 866 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 867 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 868 | "optional": true, 869 | "requires": { 870 | "ms": "2.0.0" 871 | } 872 | }, 873 | "ms": { 874 | "version": "2.0.0", 875 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 876 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", 877 | "optional": true 878 | } 879 | } 880 | }, 881 | "ref-struct": { 882 | "version": "1.1.0", 883 | "resolved": "https://registry.npmjs.org/ref-struct/-/ref-struct-1.1.0.tgz", 884 | "integrity": "sha1-XV7mWtQc78Olxf60BYcmHkee3BM=", 885 | "optional": true, 886 | "requires": { 887 | "debug": "2", 888 | "ref": "1" 889 | }, 890 | "dependencies": { 891 | "debug": { 892 | "version": "2.6.9", 893 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 894 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 895 | "optional": true, 896 | "requires": { 897 | "ms": "2.0.0" 898 | } 899 | }, 900 | "ms": { 901 | "version": "2.0.0", 902 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 903 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", 904 | "optional": true 905 | } 906 | } 907 | }, 908 | "rimraf": { 909 | "version": "2.6.3", 910 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", 911 | "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", 912 | "dev": true, 913 | "requires": { 914 | "glob": "^7.1.3" 915 | } 916 | }, 917 | "safe-buffer": { 918 | "version": "5.1.1", 919 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", 920 | "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" 921 | }, 922 | "semver": { 923 | "version": "5.7.0", 924 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", 925 | "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", 926 | "dev": true 927 | }, 928 | "set-blocking": { 929 | "version": "2.0.0", 930 | "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", 931 | "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", 932 | "optional": true 933 | }, 934 | "setimmediate": { 935 | "version": "1.0.5", 936 | "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", 937 | "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" 938 | }, 939 | "shebang-command": { 940 | "version": "1.2.0", 941 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", 942 | "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", 943 | "dev": true, 944 | "requires": { 945 | "shebang-regex": "^1.0.0" 946 | } 947 | }, 948 | "shebang-regex": { 949 | "version": "1.0.0", 950 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", 951 | "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", 952 | "dev": true 953 | }, 954 | "signal-exit": { 955 | "version": "3.0.2", 956 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", 957 | "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", 958 | "optional": true 959 | }, 960 | "simple-get": { 961 | "version": "1.4.3", 962 | "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-1.4.3.tgz", 963 | "integrity": "sha1-6XVe2kB+ltpAxeUVjJ6jezO+y+s=", 964 | "optional": true, 965 | "requires": { 966 | "once": "^1.3.1", 967 | "unzip-response": "^1.0.0", 968 | "xtend": "^4.0.0" 969 | } 970 | }, 971 | "simple-swizzle": { 972 | "version": "0.2.2", 973 | "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", 974 | "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", 975 | "requires": { 976 | "is-arrayish": "^0.3.1" 977 | }, 978 | "dependencies": { 979 | "is-arrayish": { 980 | "version": "0.3.2", 981 | "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", 982 | "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" 983 | } 984 | } 985 | }, 986 | "stack-trace": { 987 | "version": "0.0.10", 988 | "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", 989 | "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" 990 | }, 991 | "standard-as-callback": { 992 | "version": "2.0.1", 993 | "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.0.1.tgz", 994 | "integrity": "sha512-NQOxSeB8gOI5WjSaxjBgog2QFw55FV8TkS6Y07BiB3VJ8xNTvUYm0wl0s8ObgQ5NhdpnNfigMIKjgPESzgr4tg==" 995 | }, 996 | "string-width": { 997 | "version": "1.0.2", 998 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", 999 | "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", 1000 | "optional": true, 1001 | "requires": { 1002 | "code-point-at": "^1.0.0", 1003 | "is-fullwidth-code-point": "^1.0.0", 1004 | "strip-ansi": "^3.0.0" 1005 | } 1006 | }, 1007 | "string_decoder": { 1008 | "version": "1.0.3", 1009 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", 1010 | "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", 1011 | "optional": true, 1012 | "requires": { 1013 | "safe-buffer": "~5.1.0" 1014 | } 1015 | }, 1016 | "strip-ansi": { 1017 | "version": "3.0.1", 1018 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", 1019 | "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", 1020 | "optional": true, 1021 | "requires": { 1022 | "ansi-regex": "^2.0.0" 1023 | } 1024 | }, 1025 | "strip-json-comments": { 1026 | "version": "2.0.1", 1027 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", 1028 | "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", 1029 | "optional": true 1030 | }, 1031 | "tar-fs": { 1032 | "version": "1.16.3", 1033 | "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.3.tgz", 1034 | "integrity": "sha512-NvCeXpYx7OsmOh8zIOP/ebG55zZmxLE0etfWRbWok+q2Qo8x/vOR/IJT1taADXPe+jsiu9axDb3X4B+iIgNlKw==", 1035 | "optional": true, 1036 | "requires": { 1037 | "chownr": "^1.0.1", 1038 | "mkdirp": "^0.5.1", 1039 | "pump": "^1.0.0", 1040 | "tar-stream": "^1.1.2" 1041 | } 1042 | }, 1043 | "tar-stream": { 1044 | "version": "1.5.4", 1045 | "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.5.4.tgz", 1046 | "integrity": "sha1-NlSc8E7RrumyowwBQyUiONr5QBY=", 1047 | "optional": true, 1048 | "requires": { 1049 | "bl": "^1.0.0", 1050 | "end-of-stream": "^1.0.0", 1051 | "readable-stream": "^2.0.0", 1052 | "xtend": "^4.0.0" 1053 | } 1054 | }, 1055 | "text-hex": { 1056 | "version": "1.0.0", 1057 | "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", 1058 | "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" 1059 | }, 1060 | "triple-beam": { 1061 | "version": "1.3.0", 1062 | "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", 1063 | "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" 1064 | }, 1065 | "tunnel-agent": { 1066 | "version": "0.6.0", 1067 | "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", 1068 | "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", 1069 | "optional": true, 1070 | "requires": { 1071 | "safe-buffer": "^5.0.1" 1072 | } 1073 | }, 1074 | "tweetnacl": { 1075 | "version": "1.0.1", 1076 | "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.1.tgz", 1077 | "integrity": "sha512-kcoMoKTPYnoeS50tzoqjPY3Uv9axeuuFAZY9M/9zFnhoVvRfxz9K29IMPD7jGmt2c8SW7i3gT9WqDl2+nV7p4A==" 1078 | }, 1079 | "typescript": { 1080 | "version": "3.4.5", 1081 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.4.5.tgz", 1082 | "integrity": "sha512-YycBxUb49UUhdNMU5aJ7z5Ej2XGmaIBL0x34vZ82fn3hGvD+bgrMrVDpatgz2f7YxUMJxMkbWxJZeAvDxVe7Vw==", 1083 | "dev": true 1084 | }, 1085 | "unzip-response": { 1086 | "version": "1.0.2", 1087 | "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-1.0.2.tgz", 1088 | "integrity": "sha1-uYTwh3/AqJwsdzzB73tbIytbBv4=", 1089 | "optional": true 1090 | }, 1091 | "utf-8-validate": { 1092 | "version": "5.0.2", 1093 | "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.2.tgz", 1094 | "integrity": "sha512-SwV++i2gTD5qh2XqaPzBnNX88N6HdyhQrNNRykvcS0QKvItV9u3vPEJr+X5Hhfb1JC0r0e1alL0iB09rY8+nmw==", 1095 | "optional": true, 1096 | "requires": { 1097 | "node-gyp-build": "~3.7.0" 1098 | } 1099 | }, 1100 | "util-deprecate": { 1101 | "version": "1.0.2", 1102 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 1103 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" 1104 | }, 1105 | "which": { 1106 | "version": "1.3.1", 1107 | "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", 1108 | "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", 1109 | "dev": true, 1110 | "requires": { 1111 | "isexe": "^2.0.0" 1112 | } 1113 | }, 1114 | "wide-align": { 1115 | "version": "1.1.2", 1116 | "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz", 1117 | "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", 1118 | "optional": true, 1119 | "requires": { 1120 | "string-width": "^1.0.2" 1121 | } 1122 | }, 1123 | "winston": { 1124 | "version": "3.2.1", 1125 | "resolved": "https://registry.npmjs.org/winston/-/winston-3.2.1.tgz", 1126 | "integrity": "sha512-zU6vgnS9dAWCEKg/QYigd6cgMVVNwyTzKs81XZtTFuRwJOcDdBg7AU0mXVyNbs7O5RH2zdv+BdNZUlx7mXPuOw==", 1127 | "requires": { 1128 | "async": "^2.6.1", 1129 | "diagnostics": "^1.1.1", 1130 | "is-stream": "^1.1.0", 1131 | "logform": "^2.1.1", 1132 | "one-time": "0.0.4", 1133 | "readable-stream": "^3.1.1", 1134 | "stack-trace": "0.0.x", 1135 | "triple-beam": "^1.3.0", 1136 | "winston-transport": "^4.3.0" 1137 | }, 1138 | "dependencies": { 1139 | "readable-stream": { 1140 | "version": "3.4.0", 1141 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", 1142 | "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", 1143 | "requires": { 1144 | "inherits": "^2.0.3", 1145 | "string_decoder": "^1.1.1", 1146 | "util-deprecate": "^1.0.1" 1147 | } 1148 | }, 1149 | "string_decoder": { 1150 | "version": "1.2.0", 1151 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.2.0.tgz", 1152 | "integrity": "sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w==", 1153 | "requires": { 1154 | "safe-buffer": "~5.1.0" 1155 | } 1156 | } 1157 | } 1158 | }, 1159 | "winston-transport": { 1160 | "version": "4.3.0", 1161 | "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.3.0.tgz", 1162 | "integrity": "sha512-B2wPuwUi3vhzn/51Uukcao4dIduEiPOcOt9HJ3QeaXgkJ5Z7UwpBzxS4ZGNHtrxrUvTwemsQiSys0ihOf8Mp1A==", 1163 | "requires": { 1164 | "readable-stream": "^2.3.6", 1165 | "triple-beam": "^1.2.0" 1166 | }, 1167 | "dependencies": { 1168 | "process-nextick-args": { 1169 | "version": "2.0.0", 1170 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", 1171 | "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" 1172 | }, 1173 | "readable-stream": { 1174 | "version": "2.3.6", 1175 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", 1176 | "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", 1177 | "requires": { 1178 | "core-util-is": "~1.0.0", 1179 | "inherits": "~2.0.3", 1180 | "isarray": "~1.0.0", 1181 | "process-nextick-args": "~2.0.0", 1182 | "safe-buffer": "~5.1.1", 1183 | "string_decoder": "~1.1.1", 1184 | "util-deprecate": "~1.0.1" 1185 | } 1186 | }, 1187 | "string_decoder": { 1188 | "version": "1.1.1", 1189 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", 1190 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", 1191 | "requires": { 1192 | "safe-buffer": "~5.1.0" 1193 | } 1194 | } 1195 | } 1196 | }, 1197 | "wrappy": { 1198 | "version": "1.0.2", 1199 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1200 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" 1201 | }, 1202 | "ws": { 1203 | "version": "6.1.0", 1204 | "resolved": "https://registry.npmjs.org/ws/-/ws-6.1.0.tgz", 1205 | "integrity": "sha512-H3dGVdGvW2H8bnYpIDc3u3LH8Wue3Qh+Zto6aXXFzvESkTVT6rAfKR6tR/+coaUvxs8yHtmNV0uioBF62ZGSTg==", 1206 | "requires": { 1207 | "async-limiter": "~1.0.0" 1208 | } 1209 | }, 1210 | "xtend": { 1211 | "version": "4.0.1", 1212 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", 1213 | "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", 1214 | "optional": true 1215 | } 1216 | } 1217 | } 1218 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "monstercat", 3 | "version": "1.0.0", 4 | "description": "Monstercat bot.", 5 | "main": "dist/src/index.js", 6 | "bin": "dist/bin/index.js", 7 | "dependencies": { 8 | "axios": "^0.18.1", 9 | "discord-akairo": "^8.0.0-beta.8", 10 | "discord.js": "github:discordjs/discord.js#d1c4d423e9c7d9c8af9f9b562d1aeac1a29df317", 11 | "ioredis": "^4.9.5", 12 | "javelin": "^0.3.3", 13 | "m3u8-parser": "^4.3.0", 14 | "winston": "^3.2.1" 15 | }, 16 | "devDependencies": { 17 | "@types/backoff": "^2.5.1", 18 | "@types/ioredis": "^4.0.11", 19 | "@types/node": "^12.0.2", 20 | "@types/ws": "^6.0.1", 21 | "env-cmd": "^9.0.1", 22 | "rimraf": "^2.6.3", 23 | "typescript": "^3.4.5" 24 | }, 25 | "scripts": { 26 | "test": "echo \"Error: no test specified\" && exit 1", 27 | "start": "node dist/bin/index.js", 28 | "prepare": "rimraf dist/* && tsc", 29 | "dev": "npm run prepare && env-cmd node --trace-warnings dist/bin/index.js" 30 | }, 31 | "repository": { 32 | "type": "git", 33 | "url": "git+https://github.com/appellation/monstercat.git" 34 | }, 35 | "author": "Will Nelson ", 36 | "license": "UNLICENSED", 37 | "private": true, 38 | "bugs": { 39 | "url": "https://github.com/appellation/monstercat/issues" 40 | }, 41 | "homepage": "https://github.com/appellation/monstercat#readme", 42 | "optionalDependencies": { 43 | "bufferutil": "^3.0.2", 44 | "node-opus": "^0.3.2", 45 | "utf-8-validate": "^5.0.2" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Client.ts: -------------------------------------------------------------------------------- 1 | import { Client as Javelin } from 'javelin'; 2 | import { AkairoClient, CommandHandler, ListenerHandler } from 'discord-akairo'; 3 | import path = require('path'); 4 | import { Logger } from 'winston'; 5 | import Sources from './audio/Sources'; 6 | import Broadcasts from './audio/Broadcasts'; 7 | import logger from './logger'; 8 | import Redis = require('ioredis'); 9 | import DestinationStore from './audio/DestinationStore'; 10 | 11 | declare module 'discord-akairo' { 12 | interface AkairoClient { 13 | commandHandler: CommandHandler; 14 | listenerHandler: ListenerHandler; 15 | 16 | logger: Logger; 17 | twitch: Javelin; 18 | sources: Sources; 19 | broadcasts: Broadcasts; 20 | redis: Redis.Redis; 21 | destinations: DestinationStore; 22 | } 23 | } 24 | 25 | export default class MonstercatClient extends AkairoClient { 26 | public commandHandler: CommandHandler; 27 | public listenerHandler: ListenerHandler; 28 | public readonly logger: Logger; 29 | public twitch: Javelin; 30 | public sources: Sources; 31 | public broadcasts: Broadcasts; 32 | public redis: Redis.Redis; 33 | public destinations: DestinationStore; 34 | 35 | constructor(options: { 36 | ownerID: string, 37 | clientID: string, 38 | twitch: { oauth: string, username: string }, 39 | redis: string, 40 | }) { 41 | super({ 42 | ownerID: options.ownerID, 43 | }, { 44 | disableEveryone: true, 45 | disabledEvents: [ 46 | 'TYPING_START', 47 | ], 48 | }); 49 | 50 | this.logger = logger; 51 | 52 | this.commandHandler = new CommandHandler(this, { 53 | directory: path.resolve(__dirname, 'commands'), 54 | prefix: ['mc!', 'mc.'], 55 | handleEdits: true, 56 | commandUtil: true, 57 | }); 58 | 59 | this.listenerHandler = new ListenerHandler(this, { 60 | directory: path.resolve(__dirname, 'listeners'), 61 | }); 62 | this.commandHandler.useListenerHandler(this.listenerHandler); 63 | 64 | this.twitch = new Javelin({ 65 | oauth: options.twitch.oauth, 66 | username: options.twitch.username, 67 | channels: ['#monstercat'], 68 | }); 69 | 70 | this.sources = new Sources(); 71 | this.broadcasts = new Broadcasts(this.voice!, this.sources); 72 | this.redis = new Redis(options.redis); 73 | this.destinations = new DestinationStore(this.redis); 74 | 75 | this.listenerHandler.setEmitters({ twitch: this.twitch }); 76 | 77 | this.listenerHandler.loadAll(); 78 | this.commandHandler.loadAll(); 79 | } 80 | 81 | public async login(token: string) { 82 | const loggedin = await super.login(token); 83 | this.twitch.login(); 84 | return loggedin; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/audio/AudioError.ts: -------------------------------------------------------------------------------- 1 | import { format } from 'util'; 2 | 3 | export enum AudioErrorCode { 4 | UNKNOWN_ERROR = 'An unknown error occurred: `%s`.', 5 | MISSING_PERMISSIONS = 'Unable to %s; please check your permissions.', 6 | NO_VC = 'You\'re not in a voice channel; please join one before trying to %s.', 7 | } 8 | 9 | export default class AudioError extends Error { 10 | constructor(code: AudioErrorCode, ...args: any[]) { 11 | super(format(code, ...args)); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/audio/BroadcastStream.ts: -------------------------------------------------------------------------------- 1 | import { BroadcastDispatcher, StreamDispatcher, VoiceBroadcast, VoiceConnection, VoiceChannel } from 'discord.js'; 2 | import { Logger } from 'winston'; 3 | import Track from './Track'; 4 | import { Streamable } from './sources/AudioSource'; 5 | import logger from '../logger'; 6 | 7 | export default class BroadcastStream { 8 | public readonly logger: Logger = logger.child({ service: this.constructor.name }); 9 | 10 | protected _stream?: Streamable; 11 | protected _dispatcher?: BroadcastDispatcher; 12 | protected _listeners = { 13 | error: (error: Error) => { 14 | this.logger.warn(error); 15 | this.start(); 16 | }, 17 | finish: () => { 18 | this.logger.info('closed'); 19 | this.start(); 20 | }, 21 | debug: (info: string) => { 22 | this.logger.debug(info); 23 | }, 24 | }; 25 | 26 | constructor(public readonly broadcast: VoiceBroadcast, public readonly track: Track) { 27 | this.start().catch(e => this.logger.error(e)); 28 | } 29 | 30 | public async start(): Promise { 31 | if (this._dispatcher) this._removeListeners(); 32 | 33 | if (this._stream && typeof this._stream === 'object') this._stream.destroy(); 34 | this._stream = await this.track.stream(); 35 | 36 | this._dispatcher = this.broadcast.play(this._stream, { highWaterMark: 50, volume: false }); 37 | this._registerListeners(); 38 | 39 | this.logger.info('started track %s', this.track.url); 40 | } 41 | 42 | public to(vc: VoiceConnection): StreamDispatcher { 43 | const dispatcher = vc.play(this.broadcast); 44 | this.logger.debug('playing on %s', vc.channel.id); 45 | return dispatcher; 46 | } 47 | 48 | protected _registerListeners() { 49 | if (!this._dispatcher) return; 50 | 51 | for (const [evt, listener] of Object.entries(this._listeners)) { 52 | if (!this._dispatcher.listeners(evt).includes(listener)) this._dispatcher.on(evt, listener); 53 | } 54 | } 55 | 56 | protected _removeListeners() { 57 | if (!this._dispatcher) return; 58 | 59 | for (const [evt, listener] of Object.entries(this._listeners)) { 60 | this._dispatcher.off(evt, listener); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/audio/Broadcasts.ts: -------------------------------------------------------------------------------- 1 | import { ClientVoiceManager } from 'discord.js'; 2 | import BroadcastStream from "./BroadcastStream"; 3 | import Track from './Track'; 4 | import Sources from './Sources'; 5 | 6 | export enum Broadcast { 7 | UNCAGED, 8 | } 9 | 10 | export default class Broadcasts extends Map { 11 | constructor(public voice: ClientVoiceManager, public sources: Sources) { 12 | super(); 13 | this.set(Broadcast.UNCAGED, this.createStream('https://mixer.com/monstercat')); 14 | } 15 | 16 | public get(key: Broadcast): BroadcastStream { 17 | return super.get(key)!; 18 | } 19 | 20 | public createStream(query: string): BroadcastStream { 21 | return new BroadcastStream(this.voice.createBroadcast(), Track.resolve(this.sources, query)); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/audio/DestinationStore.ts: -------------------------------------------------------------------------------- 1 | import { ChannelStore, DiscordAPIError, Guild, GuildMember, VoiceChannel, VoiceConnection } from 'discord.js'; 2 | import { Redis } from 'ioredis'; 3 | import logger from '../logger'; 4 | import AudioError, { AudioErrorCode } from './AudioError'; 5 | 6 | export default class DestinationStore { 7 | public static readonly KEY = 'streams'; 8 | 9 | constructor(public readonly redis: Redis) {} 10 | 11 | public async join(memberOrChan: GuildMember | VoiceChannel): Promise { 12 | const me = memberOrChan.guild.me || await memberOrChan.guild.members.fetch(memberOrChan.client.user!); 13 | const chan = memberOrChan instanceof GuildMember ? memberOrChan.voice.channel : memberOrChan; 14 | 15 | if (!chan) throw new AudioError(AudioErrorCode.NO_VC, 'play music'); 16 | if (!chan.joinable) throw new AudioError(AudioErrorCode.MISSING_PERMISSIONS, 'join your channel'); 17 | let vc: VoiceConnection; 18 | try { 19 | vc = await chan.join(); 20 | } catch (e) { 21 | if (e instanceof DiscordAPIError) { 22 | switch (e.code) { 23 | case 50013: 24 | throw new AudioError(AudioErrorCode.MISSING_PERMISSIONS, 'join your channel'); 25 | } 26 | } 27 | 28 | throw e; 29 | } 30 | 31 | await this.set(chan); 32 | return vc; 33 | } 34 | 35 | public async leave(guild: Guild) { 36 | const me = guild.me || await guild.members.fetch(guild.client.user!); 37 | const conn = me.voice.connection; 38 | if (!conn) return; 39 | 40 | conn.dispatcher.end(); 41 | conn.channel.leave(); 42 | 43 | await this.delete(guild); 44 | } 45 | 46 | public set(channel: VoiceChannel): Promise<0 | 1> { 47 | return this.redis.hset(DestinationStore.KEY, channel.guild.id, channel.id); 48 | } 49 | 50 | public delete(guild: Guild | string): Promise { 51 | const id = typeof guild === 'string' ? guild : guild.id; 52 | return this.redis.hdel(DestinationStore.KEY, id); 53 | } 54 | 55 | public async *joinAll(channels: ChannelStore): AsyncIterableIterator { 56 | const ids: { [guildID: string]: string } = await this.redis.hgetall(DestinationStore.KEY); 57 | const iter = Object.entries(ids).map(async ([guildID, id]) => { 58 | const chan = channels.get(id); 59 | if (!chan || !(chan instanceof VoiceChannel)) { 60 | await this.delete(guildID); 61 | return; 62 | } 63 | 64 | try { 65 | return await this.join(chan); 66 | } catch (e) { 67 | logger.warn('failed to stream to saved channel %s (%s): removing', id, e); 68 | await this.delete(guildID); 69 | } 70 | }); 71 | 72 | for await (const vc of iter) { 73 | if (vc) yield vc; 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/audio/Sources.ts: -------------------------------------------------------------------------------- 1 | import AudioSource from './sources/AudioSource'; 2 | import MixerAudioSource from './sources/Mixer'; 3 | 4 | export interface SourcesOptions { 5 | twitch: { clientID: string }; 6 | } 7 | 8 | export enum SourceType { 9 | MIXER, 10 | } 11 | 12 | export default class Sources extends Map { 13 | constructor() { 14 | super([ 15 | [SourceType.MIXER, new MixerAudioSource()], 16 | ]); 17 | } 18 | 19 | public get(key: SourceType): AudioSource { 20 | return super.get(key)!; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/audio/Track.ts: -------------------------------------------------------------------------------- 1 | import { URL } from "url"; 2 | import AudioSource, { Streamable } from "./sources/AudioSource"; 3 | import Sources, { SourceType } from "./Sources"; 4 | 5 | export default class Track { 6 | public static resolve(sources: Sources, query: string): Track { 7 | const url = new URL(query); 8 | switch (url.hostname) { 9 | // case 'twitch.tv': 10 | // return new this(sources.get(SourceType.TWITCH), url); 11 | case 'mixer.com': 12 | return new this(sources.get(SourceType.MIXER), url); 13 | } 14 | 15 | throw new Error('unresolvable track'); 16 | } 17 | 18 | public readonly url: URL; 19 | public readonly source: AudioSource; 20 | 21 | constructor(source: AudioSource, url: URL) { 22 | this.source = source; 23 | this.url = url; 24 | } 25 | 26 | public async stream(): Promise { 27 | return this.source.stream(this); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/audio/sources/AudioSource.ts: -------------------------------------------------------------------------------- 1 | import Track from "../Track"; 2 | import { Readable } from "stream"; 3 | 4 | export type Streamable = Readable | string; 5 | 6 | export default interface AudioSource { 7 | stream(track: Track): Promise; 8 | } 9 | -------------------------------------------------------------------------------- /src/audio/sources/Mixer.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import { Parser } from 'm3u8-parser'; 3 | import AudioSource from './AudioSource'; 4 | import Track from '../Track'; 5 | 6 | export default class MixerAudioSource implements AudioSource { 7 | public async stream(track: Track): Promise { 8 | const { data: { id } } = await axios(`https://mixer.com/api/v1/channels${track.url.pathname}?fields=id`); 9 | const parser = new Parser(); 10 | const manifest = await axios(`https://mixer.com/api/v1/channels/${id}/manifest.m3u8?showAudioOnly=2`); 11 | parser.push(manifest.data); 12 | parser.end(); 13 | 14 | const playlist = parser.manifest.playlists[0]; 15 | if (!playlist) throw new Error('unable to find stream'); 16 | return playlist.uri; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/commands/eval.ts: -------------------------------------------------------------------------------- 1 | import { inspect } from 'util'; 2 | import { Command } from 'discord-akairo'; 3 | import { Message } from 'discord.js'; 4 | import axios from 'axios'; 5 | 6 | export default class EvalCommand extends Command { 7 | constructor() { 8 | super('eval', { 9 | aliases: ['eval'], 10 | args: [{ 11 | id: 'code', 12 | type: 'string', 13 | match: 'rest', 14 | }], 15 | ownerOnly: true, 16 | }); 17 | } 18 | 19 | public async exec(message: Message, args: any) { 20 | let result: any; 21 | try { 22 | result = await eval(args.code); 23 | } catch (e) { 24 | result = e; 25 | } 26 | 27 | let text = inspect(result, { depth: 1 }); 28 | if (text.length > 1990) { 29 | let key: string; 30 | try { 31 | ({ data: { key } } = await axios.post('https://paste.nomsy.net/documents', text)); 32 | } catch { 33 | return message.util!.reply('Unable to display error or upload to Hastebin.'); 34 | } 35 | 36 | return message.util!.reply(`https://paste.nomsy.net/${key}.js`); 37 | } 38 | 39 | return message.util!.reply(text, { code: 'js' }); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/commands/help.ts: -------------------------------------------------------------------------------- 1 | import { Command } from 'discord-akairo'; 2 | import { Message } from 'discord.js'; 3 | 4 | module.exports = class Help extends Command { 5 | constructor() { 6 | super('help', { 7 | aliases: ['help'], 8 | }); 9 | } 10 | 11 | public async exec(message: Message) { 12 | return message.util!.send('available commands: **join**, **leave**, **invite**'); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/commands/invite.ts: -------------------------------------------------------------------------------- 1 | import { Command } from 'discord-akairo'; 2 | import { Message } from 'discord.js'; 3 | 4 | module.exports = class Help extends Command { 5 | constructor() { 6 | super('invite', { 7 | aliases: ['invite'], 8 | }); 9 | } 10 | 11 | public async exec(message: Message) { 12 | return message.util!.reply(''); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/commands/join.ts: -------------------------------------------------------------------------------- 1 | import { Command } from 'discord-akairo'; 2 | import { DiscordAPIError, Message, VoiceConnection } from 'discord.js'; 3 | import { Broadcast } from '../audio/Broadcasts'; 4 | 5 | module.exports = class JoinCommand extends Command { 6 | constructor() { 7 | super('join', { 8 | aliases: ['join'], 9 | clientPermissions: ['CONNECT', 'SPEAK'], 10 | channel: 'guild' 11 | }); 12 | } 13 | 14 | public async exec(message: Message) { 15 | const member = message.member || await message.guild!.members.fetch(message.author!.id); 16 | if (!member.voice.channel) return message.util!.reply('You\'re not in a voice channel. Please join one before using this command.'); 17 | 18 | let vc: VoiceConnection; 19 | try { 20 | vc = await this.client.destinations.join(member); 21 | } catch (e) { 22 | return message.util!.reply(`${e && e.message}`); 23 | } 24 | 25 | this.client.broadcasts.get(Broadcast.UNCAGED)!.to(vc); 26 | 27 | const station = `<:monstercat:256205225554214913> Uncaged`; 28 | return message.util!.reply(`now streaming ${station} to \`🔊 ${member.voice.channel.name}\``); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/commands/leave.ts: -------------------------------------------------------------------------------- 1 | import { Command } from 'discord-akairo'; 2 | import { Message, VoiceConnection } from 'discord.js'; 3 | 4 | module.exports = class extends Command { 5 | constructor() { 6 | super('leave', { 7 | aliases: ['leave'], 8 | channel: 'guild', 9 | }); 10 | } 11 | 12 | public async exec(message: Message) { 13 | await this.client.destinations.leave(message.guild!); 14 | return message.util!.reply('stopped streaming'); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/listeners/client/debug.ts: -------------------------------------------------------------------------------- 1 | import { Listener, ListenerHandler } from 'discord-akairo'; 2 | 3 | export default class ClientReadyListener extends Listener { 4 | constructor(handler: ListenerHandler) { 5 | super('client-debug', { 6 | emitter: 'client', 7 | event: 'debug', 8 | }); 9 | 10 | this.client = handler.client; 11 | } 12 | 13 | exec(msg: string) { 14 | if (msg.includes('VOICE')) this.client.logger.debug(msg); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/listeners/client/error.ts: -------------------------------------------------------------------------------- 1 | import { Listener, ListenerHandler } from 'discord-akairo'; 2 | 3 | export default class ClientReadyListener extends Listener { 4 | constructor(handler: ListenerHandler) { 5 | super('client-error', { 6 | emitter: 'client', 7 | event: 'error', 8 | }); 9 | 10 | this.client = handler.client; 11 | } 12 | 13 | exec(error: any) { 14 | this.client.logger.error(error); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/listeners/client/ready.ts: -------------------------------------------------------------------------------- 1 | import { Listener } from 'discord-akairo'; 2 | import { Broadcast } from '../../audio/Broadcasts'; 3 | 4 | export default class ClientReadyListener extends Listener { 5 | constructor() { 6 | super('ready', { 7 | emitter: 'client', 8 | event: 'ready', 9 | }); 10 | } 11 | 12 | async exec() { 13 | this.client.user!.setActivity('Monstercat', { 14 | type: 'STREAMING', 15 | url: 'https://twitch.tv/monstercat' 16 | }); 17 | 18 | const vcs = this.client.destinations.joinAll(this.client.channels); 19 | for await (const vc of vcs) { 20 | this.client.broadcasts.get(Broadcast.UNCAGED).to(vc); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/listeners/twitch/error.ts: -------------------------------------------------------------------------------- 1 | import { Listener, ListenerHandler } from 'discord-akairo'; 2 | import { Logger } from 'winston'; 3 | 4 | export default class TwitchErrorListener extends Listener { 5 | public logger: Logger; 6 | 7 | constructor(handler: ListenerHandler) { 8 | super('twitch-error', { 9 | event: 'error', 10 | emitter: 'twitch', 11 | }); 12 | 13 | this.client = handler.client; 14 | this.logger = this.client.logger.child({ service: 'javelin' }); 15 | } 16 | 17 | exec(pk: any) { 18 | this.logger.error(pk); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/listeners/twitch/message.ts: -------------------------------------------------------------------------------- 1 | import { Listener } from 'discord-akairo'; 2 | import { Message } from 'javelin'; 3 | 4 | export default class TwitchMessageListener extends Listener { 5 | constructor() { 6 | super('twitch-message', { 7 | emitter: 'twitch', 8 | event: 'message', 9 | }); 10 | } 11 | 12 | exec(message: Message) { 13 | if (message.user.username !== 'monstercat') return; 14 | 15 | const status = message.content.match(/^Now playing (.+) by (.+)\s+monstercat\.com.*$/i); 16 | if (!status) return; 17 | 18 | const game = `${status[2]} - ${status[1]}`; 19 | this.client.logger.debug('setting game to %s', game); 20 | this.client.user!.setActivity(game, { 21 | type: 'STREAMING', 22 | url: 'https://twitch.tv/monstercat' 23 | }); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/logger.ts: -------------------------------------------------------------------------------- 1 | import { createLogger, format, transports } from 'winston'; 2 | export default createLogger({ 3 | format: format.combine( 4 | format.timestamp(), 5 | format.splat(), 6 | format.simple(), 7 | ), 8 | transports: [ 9 | new transports.Console(), 10 | ], 11 | }); 12 | -------------------------------------------------------------------------------- /src/typings/javelin.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'javelin' { 2 | import { EventEmitter } from 'events'; 3 | 4 | interface ClientOptions { 5 | oauth: string; 6 | username: string; 7 | channels?: string[]; 8 | } 9 | 10 | class Message { 11 | constructor(client: Client, data: any); 12 | public readonly client: Client; 13 | public id: string; 14 | public content: string; 15 | public timestamp: number; 16 | public channel: Channel; 17 | public user: User; 18 | public readonly createdAt: Date; 19 | public readonly emotes: string[]; 20 | public _emotes: string[]; 21 | } 22 | 23 | class Channel { 24 | constructor(client: Client, data: any); 25 | public readonly client: Client; 26 | public id: number; 27 | public name: string; 28 | public emoteOnly: boolean; 29 | public followersOnly: number; 30 | public r9k: boolean; 31 | public rituals: boolean; 32 | public slowMode: number; 33 | public subsOnly: boolean; 34 | public send(message: string): void; 35 | public leave(): void; 36 | } 37 | 38 | class User { 39 | constructor(client: Client, data: any); 40 | public readonly client: Client; 41 | public id: number; 42 | public username: string; 43 | public displayName: string; 44 | public color: string; 45 | public badges: string[]; 46 | public admin: boolean; 47 | public broadcaster: boolean; 48 | public globalMod: boolean; 49 | public moderator: boolean; 50 | public subscriber: boolean; 51 | public staff: boolean; 52 | public turbo: boolean; 53 | public prime: boolean; 54 | } 55 | 56 | class Client extends EventEmitter { 57 | constructor(options?: ClientOptions); 58 | public joinChannel(channel: string): void; 59 | public leaveChannel(channel: string): void; 60 | public login(): void; 61 | public destroy(): void; 62 | 63 | public on(event: 'debug', listener: (info: string) => void): this; 64 | public on(event: 'warn', listener: (info: string) => void): this; 65 | public on(event: 'error', listener: (error: Error) => void): this; 66 | public on(event: 'disconnect', listener: (error: Error) => void): this; 67 | public on(event: 'message', listener: (message: Message) => void): this; 68 | public on(event: 'channel_join', listener: (channel: Channel) => void): this; 69 | public on(event: 'channel_leave', listener: (channel: Channel) => void): this; 70 | public on(event: 'user_join', listener: (user: User, channel: Channel) => void): this; 71 | public on(event: 'user_leave', listener: (user: User, channel: Channel) => void): this; 72 | public on(event: string | symbol, listener: (...args: any[]) => void): this; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/typings/m3u8-parser.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'm3u8-parser' { 2 | export interface Playlist { 3 | attributes: any; 4 | uri: string; 5 | timeline: number; 6 | } 7 | 8 | export interface Manifest { 9 | allowCache: boolean; 10 | endList: boolean; 11 | mediaSequence: number; 12 | discontinuitySequence: number; 13 | playlists: Playlist[]; 14 | } 15 | 16 | export class Parser { 17 | public manifest: Manifest; 18 | public push(manifest: string): void; 19 | public end(): void; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "target": "es2017", 7 | "lib": ["es2017"], 8 | "declaration": false, 9 | "sourceMap": true, 10 | "removeComments": true, 11 | "outDir": "./dist" 12 | }, 13 | "include": ["./src/", "./bin/"], 14 | } 15 | --------------------------------------------------------------------------------