├── .env.example ├── .gitattributes ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ ├── config.yml │ └── feature_request.yml └── workflows │ ├── build_cs_plugins.yml │ ├── download_translations.yml │ ├── publish.yml │ ├── stale_issues.yml │ ├── upload_translations.yml │ └── validate.yml ├── .gitignore ├── .gitmodules ├── .node-version ├── .npmrc ├── .prettierignore ├── .vscode ├── c_cpp_properties.json ├── extensions.json ├── launch.json └── settings.json ├── LICENSE ├── README.md ├── build-assets ├── bin │ ├── csdm.cmd │ ├── csdm.sh │ └── csdm_darwin.sh ├── icon.icns ├── icon.ico ├── installer.nsh └── x86-unicode │ ├── EnVar.dll │ └── README.md ├── crowdin.yml ├── cs2-server-plugin ├── .gitignore ├── README.md ├── cs2-server-plugin.sln └── cs2-server-plugin │ ├── Makefile │ ├── cdll_interfaces.h │ ├── cs2-server-plugin.vcxproj │ ├── cs2-server-plugin.vcxproj.filters │ └── main.cpp ├── csgo-server-plugin ├── .gitignore ├── README.md ├── csgo-server-plugin.sln └── csgo-server-plugin │ ├── Makefile │ ├── cdll_int.h │ ├── csgo-server-plugin.vcxproj │ ├── csgo-server-plugin.vcxproj.filters │ ├── game_ui.h │ ├── main.cpp │ ├── plugin.h │ ├── utils.cpp │ └── utils.h ├── docker ├── .env.example ├── docker-compose.yml ├── start.sh └── stop.sh ├── electron-builder.config.js ├── eslint-local-rules.js ├── eslint.config.mjs ├── knip.ts ├── lingui.config.ts ├── linter ├── lingui-js-usage.ts └── no-react-redux-import.ts ├── package-lock.json ├── package.json ├── postcss.config.js ├── prettier.config.mjs ├── preview.png ├── scripts ├── build-linter-rules.mjs ├── build.mjs ├── cli.bat ├── cli.sh ├── cli_darwin.sh ├── develop-cli.mjs ├── develop.mjs ├── electron-vendors.mjs ├── esbuild-native-node-modules-plugin.mjs ├── install-deps.mjs ├── load-dot-env-variables.mjs └── postinstall.mjs ├── src ├── cli │ ├── cli.ts │ ├── commands.ts │ └── commands │ │ ├── analyze-command.ts │ │ ├── command.ts │ │ ├── download-base-command.ts │ │ ├── download-faceit-command.ts │ │ ├── download-valve-command.ts │ │ ├── export-command.ts │ │ ├── help-command.ts │ │ ├── json-command.ts │ │ └── xlsx-command.ts ├── common │ ├── argument │ │ ├── argument-name.ts │ │ └── start-path.ts │ ├── array │ │ ├── are-arrays-values-the-same.ts │ │ └── unique-array.ts │ ├── assert-never.ts │ ├── assert-soft-never.ts │ ├── date │ │ ├── add-date-days.ts │ │ ├── date-range.ts │ │ ├── date-to-unix-timestamp.ts │ │ ├── get-date-days-ago.ts │ │ ├── get-date-first-day.ts │ │ ├── get-date-first-month.ts │ │ ├── get-date-timestamp-at-midnight.ts │ │ ├── get-formatted-date-for-filename.ts │ │ ├── subtract-date-days.ts │ │ └── unix-timestamp-to-date.ts │ ├── download │ │ ├── build-download-from-valve-match.ts │ │ └── download-types.ts │ ├── error-code.ts │ ├── get-locale-folder-name.ts │ ├── install-source-map-support.ts │ ├── ipc-channel.ts │ ├── is-error-code.ts │ ├── math │ │ ├── round-number-percentage.ts │ │ └── round-number.ts │ ├── on-window-error.ts │ ├── sleep.ts │ ├── string │ │ ├── is-empty-string.ts │ │ ├── path-contains-invalid-csgo-chars.ts │ │ └── string-contains-only-basic-latin-chars.ts │ ├── types │ │ ├── 5eplay-account.ts │ │ ├── 5eplay-match.ts │ │ ├── analysis-status-filter.ts │ │ ├── analysis-status.ts │ │ ├── analysis.ts │ │ ├── argument.ts │ │ ├── ban-filter.ts │ │ ├── ban-stats.ts │ │ ├── banned-steam-account.ts │ │ ├── base-event.ts │ │ ├── bomb-defuse-start.ts │ │ ├── bomb-defused.ts │ │ ├── bomb-exploded.ts │ │ ├── bomb-plant-start.ts │ │ ├── bomb-planted.ts │ │ ├── camera-focus.ts │ │ ├── charts │ │ │ ├── competitive-rank-history.ts │ │ │ ├── player-charts-data.ts │ │ │ └── premier-rank-history.ts │ │ ├── chat-message.ts │ │ ├── chicken-death.ts │ │ ├── chicken-position.ts │ │ ├── clutch.ts │ │ ├── column-id.ts │ │ ├── counter-strike.ts │ │ ├── damage.ts │ │ ├── decoy-start.ts │ │ ├── demo.ts │ │ ├── download-status.ts │ │ ├── duel-matrix-row.ts │ │ ├── encoder-software.ts │ │ ├── faceit-account.ts │ │ ├── faceit-match.ts │ │ ├── flashbang-explode.ts │ │ ├── flashbang-matrix-row.ts │ │ ├── grenade-bounce.ts │ │ ├── grenade-position.ts │ │ ├── grenade-projectile-destroy.ts │ │ ├── grenade-throw.ts │ │ ├── he-grenade-explode.ts │ │ ├── heatmap-event.ts │ │ ├── heatmap-filters.ts │ │ ├── hostage-pick-up-start.ts │ │ ├── hostage-picked-up.ts │ │ ├── hostage-position.ts │ │ ├── ignored-steam-account.ts │ │ ├── inferno-position.ts │ │ ├── kill.ts │ │ ├── last-match.ts │ │ ├── map-stats.ts │ │ ├── map.ts │ │ ├── match-player.ts │ │ ├── match-table.ts │ │ ├── match.ts │ │ ├── opening-duel-result.ts │ │ ├── perspective.ts │ │ ├── player-blind.ts │ │ ├── player-economy.ts │ │ ├── player-position.ts │ │ ├── player-profile.ts │ │ ├── player-table.ts │ │ ├── player-watch-info.ts │ │ ├── player.ts │ │ ├── point.ts │ │ ├── ranking-filter.ts │ │ ├── recording-output.ts │ │ ├── recording-system.ts │ │ ├── round.ts │ │ ├── search │ │ │ ├── clutch-result.ts │ │ │ ├── collateral-kill-result.ts │ │ │ ├── kill-result.ts │ │ │ ├── map-names-filter.ts │ │ │ ├── multi-kill-result.ts │ │ │ ├── ninja-defuse-result.ts │ │ │ ├── no-scope-kill-result.ts │ │ │ ├── player-result.ts │ │ │ ├── players-filter.ts │ │ │ ├── round-result.ts │ │ │ ├── search-event.ts │ │ │ ├── search-filter.ts │ │ │ ├── search-result.ts │ │ │ ├── through-smoke-kill-result.ts │ │ │ └── wallbang-kill-result.ts │ │ ├── sequence-player-options.ts │ │ ├── sequence.ts │ │ ├── shot.ts │ │ ├── smoke-start.ts │ │ ├── startup-behavior.ts │ │ ├── status.ts │ │ ├── tag.ts │ │ ├── team-bombs-stats.ts │ │ ├── team-economy-stats.ts │ │ ├── team-match-side-stats.ts │ │ ├── team-profile.ts │ │ ├── team-table.ts │ │ ├── team.ts │ │ ├── theme-name.ts │ │ ├── valve-match.ts │ │ ├── video-container.ts │ │ ├── video-status.ts │ │ ├── video.ts │ │ ├── watch-player-options.ts │ │ ├── watch-type.ts │ │ └── xlsx.ts │ └── video │ │ └── sort-sequences-by-start-tick.ts ├── electron-main │ ├── auto-updater.ts │ ├── create-application-menu.ts │ ├── create-tray-menu.ts │ ├── create-tray.ts │ ├── create-web-socket-server-process.ts │ ├── get-argument-value-from-array.ts │ ├── inject-path-variable-into-process.ts │ ├── install-dev-tools.ts │ ├── lingui.config.ts │ ├── listen-for-context-menu.ts │ ├── load-i18n.ts │ ├── main.ts │ ├── register-main-process-listeners.ts │ ├── show-new-banned-players-notification.ts │ ├── system-startup-behavior.ts │ ├── translations │ │ ├── de │ │ │ └── messages.json │ │ ├── en │ │ │ └── messages.json │ │ ├── es │ │ │ └── messages.json │ │ ├── fr │ │ │ └── messages.json │ │ ├── pt-BR │ │ │ └── messages.json │ │ ├── zh-CN │ │ │ └── messages.json │ │ └── zh-TW │ │ │ └── messages.json │ ├── web-socket │ │ ├── create-web-socket-client.ts │ │ ├── listeners │ │ │ ├── on-download-faceit-demos-started.ts │ │ │ ├── on-download-valve-demos-started.ts │ │ │ ├── on-new-banned-accounts-error.ts │ │ │ └── on-new-banned-accounts.ts │ │ └── web-socket-client.ts │ └── window-manager.ts ├── node │ ├── 5eplay │ │ ├── download-last-5eplay-matches.ts │ │ ├── errors │ │ │ ├── 5eplay-api-error.ts │ │ │ ├── 5eplay-invalid-request.ts │ │ │ └── 5eplay-resource-not-found.ts │ │ ├── fetch-5eplay-match.ts │ │ ├── fetch-5eplay-player-account-from-domain.ts │ │ └── fetch-last-5eplay-matches.ts │ ├── boiler │ │ ├── errors │ │ │ ├── already-connected.ts │ │ │ ├── boiler-steam-not-running.ts │ │ │ ├── boiler-unknown-error.ts │ │ │ ├── invalid-args.ts │ │ │ ├── matches-info-file-not-found.ts │ │ │ ├── no-matches-found.ts │ │ │ ├── steam-communication-error.ts │ │ │ ├── steam-restart-required.ts │ │ │ ├── user-not-connected.ts │ │ │ └── write-file-error.ts │ │ └── start-boiler.ts │ ├── chat-messages │ │ ├── export-match-chat-messages.ts │ │ ├── export-matches-chat-messages.ts │ │ └── write-chat-messages-to-file.ts │ ├── counter-strike │ │ ├── get-counter-strike-executable-path.ts │ │ ├── get-counter-strike-process-names.ts │ │ ├── get-csgo-folder-path.ts │ │ ├── get-default-counter-strike-folders.ts │ │ ├── get-steam-folder-path.ts │ │ ├── is-counter-strike-running.ts │ │ ├── is-steam-running.ts │ │ ├── json-actions-file │ │ │ ├── __snapshots__ │ │ │ │ ├── generate-player-highlights-json-file.test.ts.snap │ │ │ │ ├── generate-player-lowlights-json-file.test.ts.snap │ │ │ │ └── generate-player-rounds-json-file.test.ts.snap │ │ │ ├── delete-json-actions-file.ts │ │ │ ├── generate-player-highlights-json-file.test.ts │ │ │ ├── generate-player-highlights-json-file.ts │ │ │ ├── generate-player-lowlights-json-file.test.ts │ │ │ ├── generate-player-lowlights-json-file.ts │ │ │ ├── generate-player-rounds-json-file.test.ts │ │ │ ├── generate-player-rounds-json-file.ts │ │ │ ├── json-actions-file-generator.ts │ │ │ └── output │ │ │ │ ├── cs2-player-highlights.dem.json │ │ │ │ ├── cs2-player-lowlights.dem.json │ │ │ │ ├── cs2-player-rounds.dem.json │ │ │ │ ├── csgo-player-highlights.dem.json │ │ │ │ ├── csgo-player-lowlights.dem.json │ │ │ │ └── csgo-player-rounds.dem.json │ │ ├── kill-counter-strike-processes.ts │ │ └── launcher │ │ │ ├── assert-demo-exists.ts │ │ │ ├── assert-demo-path-is-valid.ts │ │ │ ├── assert-players-slots-are-defined.ts │ │ │ ├── assert-steam-is-running.ts │ │ │ ├── cs-server-plugin.ts │ │ │ ├── cs2-server-plugin.ts │ │ │ ├── csgo-server-plugin.ts │ │ │ ├── define-cfg-folder-location.ts │ │ │ ├── detect-demo-game.ts │ │ │ ├── errors │ │ │ ├── access-denied-error.ts │ │ │ ├── counter-strike-executable-not-found.ts │ │ │ ├── demo-not-found.ts │ │ │ ├── game-error.ts │ │ │ ├── hlae-error.ts │ │ │ ├── invalid-demo-path.ts │ │ │ ├── missing-player-slot-error.ts │ │ │ ├── no-deaths-found.ts │ │ │ ├── no-kills-found.ts │ │ │ ├── not-rounds-found.ts │ │ │ ├── start-counter-strike-error.ts │ │ │ ├── steam-not-running.ts │ │ │ └── unsupported-game.ts │ │ │ ├── generate-player-voices-values.ts │ │ │ ├── start-counter-strike.ts │ │ │ ├── try-starting-demo-through-web-socket.ts │ │ │ ├── watch-demo-with-hlae.ts │ │ │ ├── watch-demo.ts │ │ │ ├── watch-player-as-suspect.ts │ │ │ ├── watch-player-highlights.ts │ │ │ ├── watch-player-lowlights.ts │ │ │ └── watch-player-rounds.ts │ ├── csgo-voice-extractor │ │ ├── errors │ │ │ ├── audio-decoding-error.ts │ │ │ ├── bad-cpu-type-error.ts │ │ │ ├── create-audio-file-error.ts │ │ │ ├── csgo-voice-extractor-unknown-error.ts │ │ │ ├── demo-parsing-error.ts │ │ │ ├── invalid-args.ts │ │ │ ├── load-csgo-lib-error.ts │ │ │ ├── missing-library-files.ts │ │ │ ├── no-voice-data-found.ts │ │ │ ├── open-demo-error.ts │ │ │ ├── unsupported-audio-codec.ts │ │ │ └── unsupported-demo-format.ts │ │ ├── export-voice-mode.ts │ │ └── start-csgo-voice-extractor.ts │ ├── database │ │ ├── 5play-account │ │ │ ├── 5eplay-account-row-to-5eplay-account.ts │ │ │ ├── 5eplay-account-row.ts │ │ │ ├── add-5eplay-account.ts │ │ │ ├── delete-5eplay-account.ts │ │ │ ├── fetch-5eplay-accounts.ts │ │ │ ├── fetch-current-5eplay-account.ts │ │ │ └── update-current-5eplay-account.ts │ │ ├── bans │ │ │ ├── fetch-ban-stats.ts │ │ │ └── player-ban-per-match-table.ts │ │ ├── bomb-defuse-start │ │ │ ├── bomb-defuse-start-row-to-bomb-defuse-start.ts │ │ │ ├── bomb-defuse-start-table.ts │ │ │ └── fetch-bombs-defuse-start.ts │ │ ├── bomb-defused │ │ │ ├── bomb-defused-row-to-bomb-defused.ts │ │ │ ├── bomb-defused-table.ts │ │ │ ├── fetch-bomb-defused.ts │ │ │ └── fetch-bombs-defused.ts │ │ ├── bomb-exploded │ │ │ ├── bomb-exploded-row-to-bomb-exploded.ts │ │ │ ├── bomb-exploded-table.ts │ │ │ ├── fetch-bomb-exploded.ts │ │ │ └── fetch-bombs-exploded.ts │ │ ├── bomb-plant-start │ │ │ ├── bomb-plant-start-row-to-bomb-plant-start.ts │ │ │ ├── bomb-plant-start-table.ts │ │ │ └── fetch-bombs-plant-start.ts │ │ ├── bomb-planted │ │ │ ├── bomb-planted-row-to-bomb-planted.ts │ │ │ ├── bomb-planted-table.ts │ │ │ ├── fetch-bomb-planted.ts │ │ │ └── fetch-bombs-planted.ts │ │ ├── chat-messages │ │ │ ├── chat-message-row-to-chat-message.ts │ │ │ ├── chat-message-table.ts │ │ │ └── fetch-chat-messages.ts │ │ ├── chicken-death │ │ │ ├── chicken-death-row-to-chicken-death.ts │ │ │ ├── chicken-death-table.ts │ │ │ └── fetch-chicken-deaths.ts │ │ ├── chicken-position │ │ │ ├── chicken-position-row-to-chicken-position.ts │ │ │ ├── chicken-position-table.ts │ │ │ └── fetch-chicken-positions.ts │ │ ├── clutches │ │ │ ├── clutch-row-to-clutch.ts │ │ │ ├── clutch-table.ts │ │ │ └── fetch-cluches.ts │ │ ├── comments │ │ │ ├── comment-table.ts │ │ │ ├── fetch-comments.ts │ │ │ ├── insert-or-update-comment.ts │ │ │ ├── insert-or-update-player-comment.ts │ │ │ └── player-comments-table.ts │ │ ├── connect-database.ts │ │ ├── create-database.ts │ │ ├── damages │ │ │ ├── damage-row-to-damage.ts │ │ │ ├── damage-table.ts │ │ │ └── fetch-damages.ts │ │ ├── database-schema-version-mismatch-error.ts │ │ ├── database.ts │ │ ├── database │ │ │ ├── errors │ │ │ │ └── invalid-backup-file.ts │ │ │ └── import-data-from-v2-backup.ts │ │ ├── decoy-started │ │ │ ├── decoy-start-row-to-decoy-start.ts │ │ │ ├── decoy-start-table.ts │ │ │ └── fetch-decoys-start.ts │ │ ├── delete-positions.ts │ │ ├── demos │ │ │ ├── delete-demos.ts │ │ │ ├── delete-orphan-demos.ts │ │ │ ├── demo-path-table.ts │ │ │ ├── demo-row-to-demo.ts │ │ │ ├── demo-table.ts │ │ │ ├── demo-to-demo-row.ts │ │ │ ├── demos-table-filter.ts │ │ │ ├── errors │ │ │ │ └── invalid-demo-name.ts │ │ │ ├── fetch-demo-by-checksum.ts │ │ │ ├── fetch-demos-by-file-paths.ts │ │ │ ├── fetch-demos-table.ts │ │ │ ├── insert-demos.ts │ │ │ ├── is-demo-by-path-in-database.ts │ │ │ ├── rename-demo.ts │ │ │ ├── update-demo.ts │ │ │ ├── update-demos-source.ts │ │ │ └── update-demos-type.ts │ │ ├── download-history │ │ │ ├── delete-old-download-histories.ts │ │ │ ├── download-history-table.ts │ │ │ ├── fetch-download-histories.ts │ │ │ └── insert-download-history.ts │ │ ├── faceit-account │ │ │ ├── add-faceit-account.ts │ │ │ ├── delete-faceit-account.ts │ │ │ ├── faceit-account-row-to-faceit-account.ts │ │ │ ├── faceit-account-row.ts │ │ │ ├── fetch-current-faceit-account.ts │ │ │ ├── fetch-faceit-accounts.ts │ │ │ └── update-current-faceit-account.ts │ │ ├── faceit-matches │ │ │ ├── faceit-match-player-table.ts │ │ │ ├── faceit-match-row-to-faceit-match.ts │ │ │ ├── faceit-match-table.ts │ │ │ ├── faceit-match-team-table.ts │ │ │ ├── fetch-faceit-matches.ts │ │ │ └── insert-faceit-match.ts │ │ ├── flashbang-exploded │ │ │ ├── fetch-flashbangs-explode.ts │ │ │ ├── flashbang-explode-row-to-flashbang-explode.ts │ │ │ └── flashbang-explode-table.ts │ │ ├── get-database-size.ts │ │ ├── grenade-bounce │ │ │ ├── fetch-grenade-bounces.ts │ │ │ ├── grenade-bounce-row-to-grenade-bounce.ts │ │ │ └── grenade-bounce-table.ts │ │ ├── grenade-position │ │ │ ├── fetch-grenade-positions.ts │ │ │ ├── grenade-position-row-to-grenade-position.ts │ │ │ └── grenade-position-table.ts │ │ ├── grenade-projectile-destroy │ │ │ ├── fetch-grenade-projectiles-destroy.ts │ │ │ ├── grenade-projectile-destroy-row-to-grenade-projectile-destroy.ts │ │ │ └── grenade-projectile-destroy-table.ts │ │ ├── he-grenade-exploded │ │ │ ├── fetch-he-grenades-explode.ts │ │ │ ├── he-grenade-explode-row-to-he-grenade-explode.ts │ │ │ └── he-grenade-explode-table.ts │ │ ├── heatmap │ │ │ ├── fetch-match-grenade-points.ts │ │ │ ├── fetch-match-kills-points.ts │ │ │ ├── fetch-match-shots-points.ts │ │ │ ├── fetch-team-grenade-points.ts │ │ │ ├── fetch-team-kills-points.ts │ │ │ └── fetch-team-shots-points.ts │ │ ├── hostage-pick-up-start │ │ │ ├── fetch-hostages-pick-up-start.ts │ │ │ ├── hostage-pick-up-start-row-to-hostage-pick-up-start.ts │ │ │ └── hostage-pick-up-start-table.ts │ │ ├── hostage-picked-up │ │ │ ├── fetch-hostages-picked-up.ts │ │ │ ├── hostage-picked-up-row-to-hostage-picked-up.ts │ │ │ └── hostage-picked-up-table.ts │ │ ├── hostage-position │ │ │ ├── fetch-hostage-positions.ts │ │ │ ├── hostage-position-row-to-hostage-position.ts │ │ │ └── hostage-position-table.ts │ │ ├── hostage-rescued │ │ │ └── hostage-rescued-table.ts │ │ ├── inferno-position │ │ │ ├── fetch-inferno-positions.ts │ │ │ ├── inferno-position-row-to-inferno-position.ts │ │ │ └── inferno-position-table.ts │ │ ├── json │ │ │ └── fetch-matches-for-json-export.ts │ │ ├── kills │ │ │ ├── fetch-kills.ts │ │ │ ├── kill-row-to-kill.ts │ │ │ └── kill-table.ts │ │ ├── maps │ │ │ ├── default-maps.ts │ │ │ ├── delete-map.ts │ │ │ ├── errors │ │ │ │ └── map-already-exists.ts │ │ │ ├── fetch-maps.ts │ │ │ ├── insert-default-maps.ts │ │ │ ├── insert-maps.ts │ │ │ ├── map-row-to-map.ts │ │ │ ├── map-table.ts │ │ │ ├── reset-default-maps.ts │ │ │ └── update-map.ts │ │ ├── match-players │ │ │ ├── fetch-match-players.ts │ │ │ └── match-player-table.ts │ │ ├── match │ │ │ ├── apply-match-filters.ts │ │ │ ├── fetch-match-duels-matrix-rows.ts │ │ │ ├── fetch-match-flashbang-matrix-rows.ts │ │ │ ├── fetch-match-players-slots.ts │ │ │ └── fetch-match-teams-economy-stats.ts │ │ ├── matches │ │ │ ├── delete-matches-by-checksums.ts │ │ │ ├── errors │ │ │ │ ├── checksums-mismatch.ts │ │ │ │ ├── duplicated-match-checksum.ts │ │ │ │ ├── insert-rounds-error.ts │ │ │ │ └── match-not-found.ts │ │ │ ├── fetch-collateral-kill-count-per-match.ts │ │ │ ├── fetch-match-checksums.ts │ │ │ ├── fetch-match-count.ts │ │ │ ├── fetch-match-table.ts │ │ │ ├── fetch-match-team-a.ts │ │ │ ├── fetch-match-team-b.ts │ │ │ ├── fetch-matches-by-checksums.ts │ │ │ ├── fetch-matches-table.ts │ │ │ ├── fetch-team-names-per-checksum.ts │ │ │ ├── generate-match-positions.ts │ │ │ ├── insert-match-positions.ts │ │ │ ├── insert-match.ts │ │ │ ├── match-insertion.ts │ │ │ ├── match-row-to-match.ts │ │ │ ├── match-table-row-to-match-table.ts │ │ │ ├── match-table-row.ts │ │ │ ├── match-table.ts │ │ │ ├── process-match-insertion.ts │ │ │ ├── update-match-demo-location.ts │ │ │ ├── update-matches-teams-names.ts │ │ │ └── update-matches-type.ts │ │ ├── migrations │ │ │ ├── ensure-migrations-table-exists.ts │ │ │ ├── fetch-migrations.ts │ │ │ ├── get-all-migrations.ts │ │ │ ├── introspection.ts │ │ │ ├── migrate-database.ts │ │ │ ├── migration-table.ts │ │ │ ├── migration.ts │ │ │ ├── v1 │ │ │ │ ├── create-bombs-defuse-start-table.ts │ │ │ │ ├── create-bombs-defused-table.ts │ │ │ │ ├── create-bombs-exploded-table.ts │ │ │ │ ├── create-bombs-plant-start-table.ts │ │ │ │ ├── create-bombs-planted-table.ts │ │ │ │ ├── create-chat-messages-table.ts │ │ │ │ ├── create-checksum-tags-table.ts │ │ │ │ ├── create-chicken-deaths-table.ts │ │ │ │ ├── create-chicken-positions-table.ts │ │ │ │ ├── create-clutches-table.ts │ │ │ │ ├── create-comments-table.ts │ │ │ │ ├── create-damages-table.ts │ │ │ │ ├── create-decoys-start-table.ts │ │ │ │ ├── create-demo-paths-table.ts │ │ │ │ ├── create-demos-table.ts │ │ │ │ ├── create-downloads-history-table.ts │ │ │ │ ├── create-faceit-accounts-table.ts │ │ │ │ ├── create-faceit-match-players-table.ts │ │ │ │ ├── create-faceit-match-teams-table.ts │ │ │ │ ├── create-faceit-matches-table.ts │ │ │ │ ├── create-flashbangs-explode-table.ts │ │ │ │ ├── create-grenade-bounces-table.ts │ │ │ │ ├── create-grenade-positions-table.ts │ │ │ │ ├── create-grenade-projectiles-destroy-table.ts │ │ │ │ ├── create-he-grenades-explode-table.ts │ │ │ │ ├── create-hostage-pick-up-start-table.ts │ │ │ │ ├── create-hostage-picked-up-table.ts │ │ │ │ ├── create-hostage-positions-table.ts │ │ │ │ ├── create-hostage-rescued-table.ts │ │ │ │ ├── create-ignored-steam-accounts-table.ts │ │ │ │ ├── create-inferno-positions-table.ts │ │ │ │ ├── create-kills-table.ts │ │ │ │ ├── create-maps-table.ts │ │ │ │ ├── create-matches-table.ts │ │ │ │ ├── create-player-blinds-table.ts │ │ │ │ ├── create-player-buys-table.ts │ │ │ │ ├── create-player-comments-table.ts │ │ │ │ ├── create-player-economies-table.ts │ │ │ │ ├── create-player-positions-table.ts │ │ │ │ ├── create-players-table.ts │ │ │ │ ├── create-rounds-table.ts │ │ │ │ ├── create-shots-table.ts │ │ │ │ ├── create-smokes-start-table.ts │ │ │ │ ├── create-steam-accounts-table.ts │ │ │ │ ├── create-tags-table.ts │ │ │ │ ├── create-teams-table.ts │ │ │ │ └── create-timestamps-table.ts │ │ │ ├── v2 │ │ │ │ └── create-round-tags-table.ts │ │ │ ├── v3.ts │ │ │ ├── v4.ts │ │ │ ├── v5.ts │ │ │ ├── v6.ts │ │ │ ├── v7.ts │ │ │ └── v8.ts │ │ ├── player-blinds │ │ │ ├── fetch-player-blinds.ts │ │ │ ├── player-blind-row-to-player-blind.ts │ │ │ └── player-blind-table.ts │ │ ├── player-buy │ │ │ └── player-buy-table.ts │ │ ├── player-economies │ │ │ ├── fetch-player-economies.ts │ │ │ ├── player-economy-row-to-player-economy.ts │ │ │ └── player-economy-table.ts │ │ ├── player-position │ │ │ ├── fetch-players-positions.ts │ │ │ ├── player-position-row-to-player-position.ts │ │ │ └── player-position-table.ts │ │ ├── player │ │ │ ├── fetch-collateral-kill-count-per-steam-ids.ts │ │ │ ├── fetch-last-player-data.ts │ │ │ ├── fetch-player-charts-data.ts │ │ │ ├── fetch-player-clutches.ts │ │ │ ├── fetch-player-collateral-kill-count.ts │ │ │ ├── fetch-player-competitive-rank-history.ts │ │ │ ├── fetch-player-enemy-count-per-rank.ts │ │ │ ├── fetch-player-last-competitive-rank.ts │ │ │ ├── fetch-player-last-matches.ts │ │ │ ├── fetch-player-last-premier-rank.ts │ │ │ ├── fetch-player-maps-stats.ts │ │ │ ├── fetch-player-match-count-stats.ts │ │ │ ├── fetch-player-opening-duels-stats.ts │ │ │ ├── fetch-player-premier-rank-history.ts │ │ │ ├── fetch-player-profile.ts │ │ │ ├── fetch-player-round-count-stats.ts │ │ │ ├── fetch-player-utility-stats.ts │ │ │ └── fetch-player.ts │ │ ├── players │ │ │ ├── fetch-last-players-data.ts │ │ │ ├── fetch-player-steam-ids-in-match.ts │ │ │ ├── fetch-players-clutch-stats.ts │ │ │ ├── fetch-players-economy-stats.ts │ │ │ ├── fetch-players-maps-stats.ts │ │ │ ├── fetch-players-round-count-stats.ts │ │ │ ├── fetch-players-table.ts │ │ │ ├── fetch-players-utility-stats.ts │ │ │ └── players-table-filter.ts │ │ ├── postgresql-error-code.ts │ │ ├── psql │ │ │ ├── ensure-psql-is-installed.ts │ │ │ ├── errors │ │ │ │ └── psql-timeout.ts │ │ │ ├── execute-psql.ts │ │ │ └── psql-error.ts │ │ ├── reset-database.ts │ │ ├── rounds │ │ │ ├── errors │ │ │ │ └── round-not-found.ts │ │ │ ├── fetch-round.ts │ │ │ ├── fetch-rounds.ts │ │ │ ├── round-row-to-round.ts │ │ │ └── round-table.ts │ │ ├── schema.ts │ │ ├── search │ │ │ ├── search-clutches.ts │ │ │ ├── search-collateral-kills.ts │ │ │ ├── search-jump-kills.ts │ │ │ ├── search-knife-kills.ts │ │ │ ├── search-map-names.ts │ │ │ ├── search-multi-kills.ts │ │ │ ├── search-ninja-defuse.ts │ │ │ ├── search-no-scope-kills.ts │ │ │ ├── search-players.ts │ │ │ ├── search-rounds.ts │ │ │ ├── search-team-kills.ts │ │ │ ├── search-through-smoke-kills.ts │ │ │ └── search-wallbang-kills.ts │ │ ├── shots │ │ │ ├── fetch-shots.ts │ │ │ ├── shot-row-to-shot.ts │ │ │ └── shot-table.ts │ │ ├── smoke-started │ │ │ ├── fetch-smokes-start.ts │ │ │ ├── smoke-start-row-to-smoke-start.ts │ │ │ └── smoke-start-table.ts │ │ ├── steam-accounts │ │ │ ├── add-ignored-steam-account.ts │ │ │ ├── build-steam-accounts-from-steam-ids.ts │ │ │ ├── delete-ignored-steam-account.ts │ │ │ ├── errors │ │ │ │ ├── invalid-steam-community-url.ts │ │ │ │ ├── steam-account-already-ignored.ts │ │ │ │ ├── steam-account-name-too-long.ts │ │ │ │ └── steam-account-not-found.ts │ │ │ ├── fetch-banned-account-age-stats.ts │ │ │ ├── fetch-banned-steam-accounts.ts │ │ │ ├── fetch-ignored-steam-accounts.ts │ │ │ ├── fetch-steam-accounts.ts │ │ │ ├── ignored-steam-account-table.ts │ │ │ ├── insert-steam-accounts.ts │ │ │ ├── steam-account-overrides-table.ts │ │ │ ├── steam-account-table.ts │ │ │ ├── sync-steam-accounts-with-players.ts │ │ │ ├── update-steam-account-name.ts │ │ │ └── update-steam-accounts-from-steam.ts │ │ ├── tags │ │ │ ├── assert-valid-tag.ts │ │ │ ├── checksum-tag-table.ts │ │ │ ├── delete-tag.ts │ │ │ ├── errors │ │ │ │ ├── invalid-tag-color.ts │ │ │ │ ├── tag-name-already-taken.ts │ │ │ │ ├── tag-name-too-long.ts │ │ │ │ ├── tag-name-too-short.ts │ │ │ │ └── tag-not-found.ts │ │ │ ├── fetch-checksum-tag-ids.ts │ │ │ ├── fetch-checksum-tags.ts │ │ │ ├── fetch-players-tag-ids.ts │ │ │ ├── fetch-players-tags.ts │ │ │ ├── fetch-round-tags.ts │ │ │ ├── fetch-tags.ts │ │ │ ├── insert-default-tags.ts │ │ │ ├── insert-tag.ts │ │ │ ├── round-tag-table.ts │ │ │ ├── steam-account-tag-table.ts │ │ │ ├── tag-row-to-tag.ts │ │ │ ├── tag-table.ts │ │ │ ├── update-checksums-tags.ts │ │ │ ├── update-players-tags.ts │ │ │ ├── update-round-tags.ts │ │ │ └── update-tag.ts │ │ ├── team │ │ │ ├── error │ │ │ │ └── team-not-found.ts │ │ │ ├── fetch-team-bombs-stats.ts │ │ │ ├── fetch-team-clutches.ts │ │ │ ├── fetch-team-collateral-kill-count.ts │ │ │ ├── fetch-team-economy-stats.ts │ │ │ ├── fetch-team-last-matches.ts │ │ │ ├── fetch-team-maps-stats.ts │ │ │ ├── fetch-team-match-count-stats.ts │ │ │ ├── fetch-team-match-side-stats.ts │ │ │ ├── fetch-team-rounds-count.ts │ │ │ ├── fetch-team.ts │ │ │ ├── fetch-teams-economy-stats.ts │ │ │ └── team-filters.ts │ │ ├── teams │ │ │ ├── errors │ │ │ │ ├── duplicate-team-name-error.ts │ │ │ │ └── teams-not-found.ts │ │ │ ├── fetch-teams-table.ts │ │ │ ├── team-row-to-team.ts │ │ │ ├── team-table.ts │ │ │ └── teams-table-filter.ts │ │ ├── timestamps │ │ │ ├── is-timestamp-expired.ts │ │ │ ├── timestamp-name.ts │ │ │ ├── timestamp-table.ts │ │ │ └── update-timestamp.ts │ │ ├── watch │ │ │ └── get-match-playback.ts │ │ └── xlsx │ │ │ ├── fetch-clutches-rows.ts │ │ │ ├── fetch-kills-rows.ts │ │ │ ├── fetch-matches-rows.ts │ │ │ ├── fetch-players-rows.ts │ │ │ ├── fetch-rounds-rows.ts │ │ │ └── fetch-weapons-rows.ts │ ├── demo-analyzer │ │ ├── corrupted-demo-error.ts │ │ ├── player-color-to-string.ts │ │ └── run-demo-analyzer.ts │ ├── demo │ │ ├── __snapshots__ │ │ │ └── get-demo-header.test.ts.snap │ │ ├── analyze-demo.ts │ │ ├── delete-demos.ts │ │ ├── errors │ │ │ └── invalid-demo-header.ts │ │ ├── find-demos-in-folders.ts │ │ ├── fixtures │ │ │ ├── source_1_1.dem.data │ │ │ ├── source_1_2.dem.data │ │ │ ├── source_1_3.dem.data │ │ │ ├── source_1_4.dem.data │ │ │ ├── source_2_1.dem.data │ │ │ ├── source_2_2.dem.data │ │ │ ├── source_2_3.dem.data │ │ │ ├── source_2_4.dem.data │ │ │ ├── source_2_5.dem.data │ │ │ ├── source_2_6.dem.data │ │ │ ├── source_2_7.dem.data │ │ │ ├── source_2_8.dem.data │ │ │ └── source_2_9.dem.data │ │ ├── get-demo-checksum-from-demo-path.ts │ │ ├── get-demo-checksum-from-file-stats.ts │ │ ├── get-demo-from-file-path.ts │ │ ├── get-demo-header.test.ts │ │ ├── get-demo-header.ts │ │ ├── get-demo-info-file-path.ts │ │ ├── get-demos-file-paths-to-load.ts │ │ └── load-demo-by-path.ts │ ├── download │ │ ├── assert-download-folder-is-valid.ts │ │ ├── build-download-from-share-code.ts │ │ ├── errors │ │ │ ├── decode-sharecode-error.ts │ │ │ ├── download-folder-not-defined.ts │ │ │ ├── download-folder-not-exists.ts │ │ │ ├── download-link-expired.ts │ │ │ ├── invalid-share-code.ts │ │ │ ├── match-already-downloaded.ts │ │ │ ├── match-already-in-download-queue.ts │ │ │ └── write-info-file-error.ts │ │ ├── get-download-status.ts │ │ └── is-download-link-expired.ts │ ├── errors │ │ ├── abort-error.ts │ │ ├── base-error.ts │ │ ├── network-error.ts │ │ └── player-not-found.ts │ ├── faceit-web-api │ │ ├── errors │ │ │ ├── faceit-api-error.ts │ │ │ ├── faceit-forbidden-error.ts │ │ │ ├── faceit-invalid-request.ts │ │ │ ├── faceit-resource-not-found.ts │ │ │ └── faceit-unauthorized.ts │ │ ├── faceit-game-id.ts │ │ ├── faceit-result.ts │ │ ├── fetch-faceit-account.ts │ │ ├── fetch-match-stats.ts │ │ ├── fetch-match.ts │ │ ├── fetch-player-last-matches.ts │ │ └── get-faceit-api-key.ts │ ├── faceit │ │ ├── download-last-faceit-matches.ts │ │ ├── fetch-faceit-match.ts │ │ └── fetch-last-faceit-matches.ts │ ├── filesystem │ │ ├── download-and-extract-xz-archive.ts │ │ ├── download-and-extract-zip-archive.ts │ │ ├── errors │ │ │ └── file-not-found.ts │ │ ├── get-app-folder-path.ts │ │ ├── get-images-folder-path.ts │ │ ├── get-png-information.ts │ │ ├── get-premier-rank-image-src.ts │ │ ├── get-rank-image-src.ts │ │ ├── get-static-folder-path.ts │ │ ├── get-user-images-folder-path.ts │ │ ├── glob.ts │ │ ├── is-path-writable.ts │ │ ├── is-png-base64-string.ts │ │ ├── maps │ │ │ ├── delete-map-image-files.ts │ │ │ ├── ensure-maps-images-folders-exist.ts │ │ │ ├── get-game-maps-images-folder-path.ts │ │ │ ├── get-map-lower-radar-base64.ts │ │ │ ├── get-map-lower-radar-file-path.ts │ │ │ ├── get-map-radar-base64.ts │ │ │ ├── get-map-radar-file-path.ts │ │ │ ├── get-map-thumbnail-base64.ts │ │ │ ├── get-map-thumbnail-file-path.ts │ │ │ ├── get-maps-images-folder-path.ts │ │ │ ├── get-maps-radars-folder-path.ts │ │ │ ├── get-maps-thumbnails-folder-path.ts │ │ │ ├── get-unknown-map-thumbnail-file-path.ts │ │ │ ├── get-user-maps-images-folder-path.ts │ │ │ ├── get-user-maps-radars-folder-path.ts │ │ │ ├── get-user-maps-thumbnails-folder-path.ts │ │ │ ├── write-map-lower-radar-file-from-base64.ts │ │ │ ├── write-map-radar-image-from-base64.ts │ │ │ └── write-map-thumbnail-file.ts │ │ ├── move-files.ts │ │ ├── windows-to-unix-path-separator.ts │ │ └── write-base64-file.ts │ ├── get-app-information.ts │ ├── json │ │ ├── export-matches-to-json.ts │ │ └── match-json.ts │ ├── logger.ts │ ├── os │ │ ├── are-processes-running.ts │ │ ├── get-running-process-exit-code │ │ │ ├── binding.gyp │ │ │ ├── build │ │ │ │ └── Release │ │ │ │ │ └── get_running_process_exit_code.node │ │ │ ├── get-running-process-exit-code.cpp │ │ │ ├── get-running-process-exit-code.ts │ │ │ ├── package-lock.json │ │ │ └── package.json │ │ ├── is-linux.ts │ │ ├── is-mac.ts │ │ ├── is-windows.ts │ │ ├── kill-processes-by-names.ts │ │ └── windows-registry.ts │ ├── settings │ │ ├── default-settings.ts │ │ ├── get-all-migrations.ts │ │ ├── get-settings-file-path.ts │ │ ├── get-settings.ts │ │ ├── initialize-settings.ts │ │ ├── migrate-settings.ts │ │ ├── migration.ts │ │ ├── migrations │ │ │ ├── initialize-locale.ts │ │ │ ├── v2.ts │ │ │ ├── v3.ts │ │ │ ├── v4.ts │ │ │ ├── v5.ts │ │ │ ├── v6.ts │ │ │ ├── v7.ts │ │ │ └── v8.ts │ │ ├── page.ts │ │ ├── remove-tag-id-from-settings.ts │ │ ├── reset-settings.ts │ │ ├── schema-version.ts │ │ ├── settings.ts │ │ ├── table │ │ │ ├── column-state.ts │ │ │ ├── get-table-state-file-path.ts │ │ │ ├── read-table-state.ts │ │ │ ├── reset-tables-state.ts │ │ │ ├── table-name.ts │ │ │ └── write-table-state.ts │ │ ├── update-settings.ts │ │ └── write-settings.ts │ ├── steam-web-api │ │ ├── get-player-steam-id-from-steam-url.ts │ │ ├── get-players-bans.ts │ │ ├── get-steam-api-key.ts │ │ ├── get-users-summary.ts │ │ ├── steam-api-forbidden-error.ts │ │ ├── steam-constants.ts │ │ ├── steam-too-many-requests.ts │ │ └── steamapi-error.ts │ ├── valve-match │ │ ├── __snapshots__ │ │ │ ├── get-match-info-from-match-info-protobuf-message.test.ts.snap │ │ │ └── get-valve-match-from-match-info-protobuf-message.test.ts.snap │ │ ├── fetch-last-valve-matches.ts │ │ ├── fixtures │ │ │ ├── match730_003028590839392632871_1662707805_136.dem.info │ │ │ ├── match730_003189280594026561777_1796106830_900.dem.info │ │ │ ├── match730_003189870870709403769_1988138084_900.dem.info │ │ │ ├── match730_003496718345246343373_0093428724_190.dem.info │ │ │ ├── match730_003498492722937856210_1557600280_214.dem.info │ │ │ ├── match730_003668313874395824202_1729175012_271.dem.info │ │ │ └── match730_003668537425296097309_2104686856_273.dem.info │ │ ├── get-map-name.ts │ │ ├── get-match-demo-path.ts │ │ ├── get-valve-match-from-match-info-protobuf-message.test.ts │ │ ├── get-valve-match-from-match-info-protobuf-message.ts │ │ └── update-valve-players-from-steam.ts │ ├── video │ │ ├── errors │ │ │ ├── command-error.ts │ │ │ ├── ffmpeg-error.ts │ │ │ ├── ffmpeg-not-installed.ts │ │ │ ├── hlae-not-installed.ts │ │ │ ├── invalid-ffmpeg-executable.ts │ │ │ ├── invalid-hlae-executable.ts │ │ │ ├── no-sequences-found.ts │ │ │ ├── raw-files-not-found.ts │ │ │ ├── virtual-dub-error.ts │ │ │ ├── virtual-dub-not-installed.ts │ │ │ └── wav-file-not-found.ts │ │ ├── ffmpeg │ │ │ ├── check-for-ffmpeg-update.ts │ │ │ ├── execute-ffmpeg.ts │ │ │ ├── fetch-last-ffmpeg-version.ts │ │ │ ├── ffmpeg-location.ts │ │ │ ├── get-ffmpeg-version-from-executable.ts │ │ │ ├── get-installed-ffmpeg-version.ts │ │ │ ├── install-ffmpeg.ts │ │ │ ├── is-ffmpeg-installed.ts │ │ │ ├── is-ffmpeg-update-available.ts │ │ │ └── kill-ffmpeg-process.ts │ │ ├── generation │ │ │ ├── assert-video-generation-is-possible.ts │ │ │ ├── concatenate-videos-from-sequences.ts │ │ │ ├── create-cs2-json-actions-file-for-recording.ts │ │ │ ├── create-csgo-json-file-for-recording.ts │ │ │ ├── delete-sequences-raw-files.ts │ │ │ ├── generate-video-with-ffmpeg.ts │ │ │ ├── generate-video-with-virtual-dub.ts │ │ │ ├── generate-video.ts │ │ │ ├── get-sequence-name.ts │ │ │ ├── get-sequence-output-file-path.ts │ │ │ ├── get-sequence-output-folder-path.ts │ │ │ ├── get-sequence-raw-files.ts │ │ │ ├── move-hlae-files-to-output-folder.ts │ │ │ └── move-startmovie-files-to-output-folder.ts │ │ ├── get-output-folder-path.ts │ │ ├── hlae │ │ │ ├── check-for-hlae-update.ts │ │ │ ├── download-hlae.ts │ │ │ ├── fetch-last-hlae-release.ts │ │ │ ├── get-hlae-version-from-executable.ts │ │ │ ├── get-installed-hlae-version.ts │ │ │ ├── hlae-location.ts │ │ │ ├── is-hlae-installed.ts │ │ │ ├── is-hlae-update-available.ts │ │ │ └── kill-hlae-process.ts │ │ └── virtual-dub │ │ │ ├── download-and-extract-virtual-dub.ts │ │ │ ├── get-installed-virtual-dub-version.ts │ │ │ ├── get-virtual-dub-executable-path.ts │ │ │ ├── get-virtual-dub-folder-path.ts │ │ │ ├── get-virtual-dub-version-file-path.ts │ │ │ ├── is-virtual-dub-installed.ts │ │ │ ├── kill-virtual-dub-process.ts │ │ │ └── virtual-dub-version.ts │ └── xlsx │ │ ├── cell-value.ts │ │ ├── column.ts │ │ ├── match-export │ │ ├── clutches-sheet.ts │ │ ├── general-sheet.ts │ │ ├── kills-sheet.ts │ │ ├── players-flashbang-matrix-sheet.ts │ │ ├── players-sheet.ts │ │ ├── rounds-sheet.ts │ │ ├── single-match-export-sheet.ts │ │ └── weapons-sheet.ts │ │ ├── match-xlsx-export.ts │ │ ├── matches-export │ │ ├── clutches-sheet.ts │ │ ├── kills-sheet.ts │ │ ├── matches-sheet.ts │ │ ├── multiple-match-export-sheet.ts │ │ ├── players-sheet.ts │ │ ├── rounds-sheet.ts │ │ └── weapons-sheet.ts │ │ ├── matches-xlsx-export.ts │ │ ├── player-export │ │ ├── clutch-sheet.ts │ │ ├── economy-sheet.ts │ │ ├── general-sheet.ts │ │ ├── maps-sheet.ts │ │ ├── player-export.ts │ │ ├── single-player-export-sheet.ts │ │ └── utility-sheet.ts │ │ ├── player-sheet-name.ts │ │ ├── players-export │ │ ├── clutch-sheet.ts │ │ ├── economy-sheet.ts │ │ ├── maps-sheet.ts │ │ ├── multiple-player-export-sheet.ts │ │ ├── players-sheet.ts │ │ ├── players-xlsx-export.ts │ │ ├── rounds-sheet.ts │ │ └── utility-sheet.ts │ │ ├── sheet-name.ts │ │ ├── sheet.ts │ │ ├── workbook.ts │ │ └── xlsx-output.ts ├── preload │ ├── element-to-image.ts │ └── preload.ts ├── server │ ├── abort-controller.ts │ ├── analyses-listener.ts │ ├── dev-preload.ts │ ├── dev.html │ ├── download-queue.ts │ ├── game-client-message-name.ts │ ├── game-server-message-name.ts │ ├── get-error-code-from-error.ts │ ├── handler.ts │ ├── handlers │ │ ├── handle-error.ts │ │ ├── main-handlers-mapping.ts │ │ ├── main-process │ │ │ ├── has-pending-analyses-handler.ts │ │ │ └── start-minimized-mode-handler.ts │ │ ├── renderer-handlers-mapping.ts │ │ └── renderer-process │ │ │ ├── 5eplay │ │ │ ├── add-5eplay-account-handler.ts │ │ │ ├── delete-5eplay-account-handler.ts │ │ │ ├── fetch-last-5eplay-matches-handler.ts │ │ │ └── update-current-5eplay-account-handler.ts │ │ │ ├── abort-current-task-handler.ts │ │ │ ├── bans │ │ │ └── fetch-ban-stats-handler.ts │ │ │ ├── counter-strike │ │ │ ├── counter-strike.ts │ │ │ ├── is-counter-strike-running-handler.ts │ │ │ ├── is-cs2-connected-to-server-handler.ts │ │ │ ├── watch-demo-handler.ts │ │ │ ├── watch-player-as-suspect-handler.ts │ │ │ ├── watch-player-highlights-handler.ts │ │ │ ├── watch-player-lowlights-handler.ts │ │ │ └── watch-player-rounds-handler.ts │ │ │ ├── database │ │ │ ├── connect-database-handler.ts │ │ │ ├── disconnect-database-connection-handler.ts │ │ │ ├── get-database-size-handler.ts │ │ │ ├── import-data-from-v2-backup-handler.ts │ │ │ ├── optimize-database-handler.ts │ │ │ └── reset-database-handler.ts │ │ │ ├── demo │ │ │ ├── add-demos-to-analyses-handler.ts │ │ │ ├── delete-demos-from-database-handler.ts │ │ │ ├── delete-demos-handler.ts │ │ │ ├── export-demo-players-voice-handler.ts │ │ │ ├── fetch-demos-table-handler.ts │ │ │ ├── load-demo-handler.ts │ │ │ ├── remove-demos-from-analyses-handler.ts │ │ │ ├── rename-demo-handler.ts │ │ │ ├── update-demos-source-handler.ts │ │ │ └── update-demos-type-handler.ts │ │ │ ├── download │ │ │ ├── abort-download-handler.ts │ │ │ ├── abort-downloads-handler.ts │ │ │ ├── add-download-from-share-code-handler.ts │ │ │ ├── add-download-handler.ts │ │ │ ├── add-downloads-handler.ts │ │ │ └── fetch-last-valve-matches-handler.ts │ │ │ ├── faceit │ │ │ ├── add-faceit-account-handler.ts │ │ │ ├── delete-faceit-account-handler.ts │ │ │ ├── fetch-last-faceit-matches-handler.ts │ │ │ └── update-current-faceit-account-handler.ts │ │ │ ├── filesystem │ │ │ └── write-base64-file-handler.ts │ │ │ ├── initialize-application-handler.ts │ │ │ ├── map │ │ │ ├── add-map-handler.ts │ │ │ ├── delete-map-handler.ts │ │ │ ├── map-payload.ts │ │ │ ├── reset-maps-handler.ts │ │ │ └── update-map-handler.ts │ │ │ ├── match │ │ │ ├── delete-matches-handler.ts │ │ │ ├── export-match-chat-messages-handler.ts │ │ │ ├── export-matches-chat-messages-handler.ts │ │ │ ├── export-matches-to-json-handler.ts │ │ │ ├── export-matches-to-xlsx-handler.ts │ │ │ ├── fetch-2d-viewer-data-handler.ts │ │ │ ├── fetch-match-by-checksum-handler.ts │ │ │ ├── fetch-match-duels-matrix-rows-handler.ts │ │ │ ├── fetch-match-flashbang-matrix-rows-handler.ts │ │ │ ├── fetch-match-grenades-throw-handler.ts │ │ │ ├── fetch-match-heatmap-points-handler.ts │ │ │ ├── fetch-matches-table-handler.ts │ │ │ ├── generate-match-positions-handler.ts │ │ │ ├── update-comment-handler.ts │ │ │ ├── update-match-demo-location-handler.ts │ │ │ ├── update-matches-team-names-handler.ts │ │ │ └── update-matches-type-handler.ts │ │ │ ├── migrations │ │ │ └── fetch-migrations-handler.ts │ │ │ ├── navigate-to-demo-or-match-handler.ts │ │ │ ├── player │ │ │ ├── export-players-to-xlsx-handler.ts │ │ │ ├── fetch-player-handler.ts │ │ │ ├── fetch-players-table-handler.ts │ │ │ └── update-player-comment-handler.ts │ │ │ ├── search │ │ │ ├── search-handler.ts │ │ │ ├── search-map-names-handler.ts │ │ │ └── search-players-handler.ts │ │ │ ├── settings │ │ │ ├── disable-ffmpeg-custom-location-handler.ts │ │ │ ├── disable-hlae-custom-location-handler.ts │ │ │ ├── enable-ffmpeg-custom-location-handler.ts │ │ │ ├── enable-hlae-custom-location-handler.ts │ │ │ ├── ffmpeg-version-changed-payload.ts │ │ │ ├── hlae-version-changed-payload.ts │ │ │ └── reset-tables-state-handler.ts │ │ │ ├── steam-accounts │ │ │ ├── add-ignored-steam-account-handler.ts │ │ │ ├── delete-ignored-steam-account-handler.ts │ │ │ └── update-steam-account-name-handler.ts │ │ │ ├── tags │ │ │ ├── delete-tag-handler.ts │ │ │ ├── insert-tag-handler.ts │ │ │ ├── update-checksums-tags-handler.ts │ │ │ ├── update-players-tags-handler.ts │ │ │ ├── update-round-tags-handler.ts │ │ │ └── update-tag-handler.ts │ │ │ ├── team │ │ │ ├── fetch-team-handler.ts │ │ │ ├── fetch-team-heatmap-points-handler.ts │ │ │ └── fetch-teams-table-handler.ts │ │ │ └── video │ │ │ ├── add-video-to-queue-handler.ts │ │ │ ├── initialize-video-handler.ts │ │ │ ├── install-ffmpeg-handler.ts │ │ │ ├── install-hlae-handler.ts │ │ │ ├── install-virtual-dub-handler.ts │ │ │ ├── pause-video-queue-handler.ts │ │ │ ├── remove-videos-from-queue-handler.ts │ │ │ ├── resume-video-queue-handler.ts │ │ │ ├── update-ffmpeg-handler.ts │ │ │ └── update-hlae-handler.ts │ ├── identifiable-client-message.ts │ ├── main-client-message-name.ts │ ├── main-server-message-name.ts │ ├── port.ts │ ├── renderer-client-message-name.ts │ ├── renderer-server-message-name.ts │ ├── server.ts │ ├── shared-server-message-name.ts │ ├── start-background-tasks.ts │ ├── tasks │ │ ├── check-for-new-banned-steam-accounts.ts │ │ ├── download-last-matches-if-necessary.ts │ │ ├── download-last-valve-matches.ts │ │ └── listen-for-counter-strike-closed.ts │ ├── update-settings-and-notify-renderer-process.ts │ └── video-queue.ts └── ui │ ├── analyses │ ├── action-bar │ │ ├── action-bar.tsx │ │ ├── remove-all-analyses-button.tsx │ │ └── remove-analyses-succeed-button.tsx │ ├── analyses-actions.ts │ ├── analyses-reducer.ts │ ├── analyses.tsx │ ├── analysis-logs.tsx │ ├── analysis-status.ts │ ├── no-analysis.tsx │ ├── table │ │ ├── analyses-table.tsx │ │ ├── context-menu │ │ │ ├── analyses-context-menu.tsx │ │ │ ├── remove-demo-from-analyses-item.tsx │ │ │ ├── see-demo-item.tsx │ │ │ └── see-match-item.tsx │ │ ├── status-cell.tsx │ │ └── use-analyses-columns.ts │ ├── use-analyses-state.ts │ ├── use-analyses.ts │ ├── use-get-demo-analysis-status.ts │ ├── use-is-demo-analysis-in-progress.ts │ └── use-selected-analysis-demo-id.ts │ ├── ban │ ├── ban-actions.ts │ ├── ban-reducer.ts │ ├── stats │ │ ├── ban-per-competitive-rank-chart.tsx │ │ ├── ban-per-date-chart.tsx │ │ ├── ban-per-premier-rank-chart.tsx │ │ ├── ban-stats.tsx │ │ ├── last-bans.tsx │ │ ├── no-ban-message.tsx │ │ └── no-stats.tsx │ ├── use-ban-state.ts │ └── use-ignored-steam-accounts.ts │ ├── bootstrap │ ├── app-content.tsx │ ├── app-loader.tsx │ ├── app-wrapper.tsx │ ├── app.tsx │ ├── arguments-provider.tsx │ ├── bootstrap-actions.ts │ ├── bootstrap-reducer.ts │ ├── connect-database │ │ ├── connect-database-button.tsx │ │ ├── connect-database.tsx │ │ └── help-link.tsx │ ├── database-loader.tsx │ ├── database-status.ts │ ├── drop-zone.tsx │ ├── initial-route-redirector.tsx │ ├── loading-error.tsx │ ├── loading.tsx │ ├── locale-provider.tsx │ ├── navigation-listener.tsx │ ├── root.tsx │ ├── settings-provider.tsx │ ├── use-argument.ts │ ├── use-arguments-context.ts │ ├── use-bootstrap-state.ts │ ├── use-database-status.ts │ ├── use-register-web-socket-listeners.ts │ ├── web-socket-listeners │ │ ├── use-register-analyses-listeners.ts │ │ ├── use-register-ban-listeners.tsx │ │ ├── use-register-downloads-listeners.ts │ │ ├── use-register-settings-listeners.ts │ │ └── use-register-video-queue-listeners.ts │ └── web-socket-provider.tsx │ ├── cache │ ├── cache-reducer.ts │ ├── use-cache.ts │ └── use-match-checksums.ts │ ├── changelog │ └── changelog-dialog.tsx │ ├── comment │ ├── comment-actions.ts │ └── use-update-comment.tsx │ ├── components │ ├── action-bar.tsx │ ├── avatar.tsx │ ├── buttons │ │ ├── analyze-button.tsx │ │ ├── apply-button.tsx │ │ ├── button.tsx │ │ ├── cancel-button.tsx │ │ ├── change-button.tsx │ │ ├── close-button.tsx │ │ ├── confirm-button.tsx │ │ ├── copy-button.tsx │ │ ├── copy-demo-link-button.tsx │ │ ├── copy-share-code-button.tsx │ │ ├── copy-steamid-button.tsx │ │ ├── delete-button.tsx │ │ ├── details-button.tsx │ │ ├── export-html-element-as-image-button.tsx │ │ ├── install-button.tsx │ │ ├── refresh-button.tsx │ │ ├── remove-button.tsx │ │ ├── reset-button.tsx │ │ ├── retry-button.tsx │ │ ├── reveal-button.tsx │ │ ├── reveal-demo-in-explorer-button.tsx │ │ ├── reveal-file-in-explorer-button.tsx │ │ ├── reveal-folder-in-explorer-button.tsx │ │ ├── reveal-log-file-button.tsx │ │ ├── save-button.tsx │ │ ├── see-demo-button.tsx │ │ ├── see-match-button.tsx │ │ ├── spinnable-button.tsx │ │ ├── update-button.tsx │ │ ├── watch-button.tsx │ │ └── xlsx-export-button.tsx │ ├── card.tsx │ ├── collapse-panel │ │ └── collapse-panel.tsx │ ├── content.tsx │ ├── context-menu │ │ ├── context-menu-item.tsx │ │ ├── context-menu-provider.tsx │ │ ├── context-menu.tsx │ │ ├── items │ │ │ ├── add-to-video-sequences-item.tsx │ │ │ ├── analyze-item.tsx │ │ │ ├── change-matches-type-item.tsx │ │ │ ├── change-source-item.tsx │ │ │ ├── comment-item.tsx │ │ │ ├── copy-checksums-item.tsx │ │ │ ├── copy-filepath-item.tsx │ │ │ ├── copy-item.tsx │ │ │ ├── copy-name-item.tsx │ │ │ ├── copy-sharecode-item.tsx │ │ │ ├── copy-steamid-item.tsx │ │ │ ├── delete-item.tsx │ │ │ ├── details-item.tsx │ │ │ ├── export-chat-messages-item.tsx │ │ │ ├── export-matches-item.tsx │ │ │ ├── export-matches-to-json-item.tsx │ │ │ ├── export-players-voice-item.tsx │ │ │ ├── export-to-xlsx-item.tsx │ │ │ ├── ignore-steam-account-ban-item.tsx │ │ │ ├── navigate-to-demo-item.tsx │ │ │ ├── navigate-to-match-item.tsx │ │ │ ├── navigate-to-matches-demo-item.tsx │ │ │ ├── navigate-to-player-item.tsx │ │ │ ├── navigate-to-team-item.tsx │ │ │ ├── open-faceit-profile-item.tsx │ │ │ ├── open-steam-profile-item.tsx │ │ │ ├── pin-player-item.tsx │ │ │ ├── rename-item.tsx │ │ │ ├── reveal-demo-in-explorer-item.tsx │ │ │ ├── reveal-file-in-explorer-item.tsx │ │ │ ├── see-player-profile-item.tsx │ │ │ ├── show-player-matches-item.tsx │ │ │ ├── tags-item.tsx │ │ │ ├── update-match-demo-location-item.tsx │ │ │ ├── update-name-item.tsx │ │ │ ├── watch-item.tsx │ │ │ ├── watch-player-as-suspect-item.tsx │ │ │ ├── watch-player-highlights-item.tsx │ │ │ ├── watch-player-item.tsx │ │ │ ├── watch-player-lowlights-item.tsx │ │ │ └── watch-player-rounds-item.tsx │ │ ├── separator.tsx │ │ ├── sub-context-menu.tsx │ │ └── use-context-menu.ts │ ├── date-picker.tsx │ ├── dialogs │ │ ├── analyze-demos-dialog.tsx │ │ ├── change-demos-source-dialog.tsx │ │ ├── counter-strike-running-dialog.tsx │ │ ├── delete-demos-dialog.tsx │ │ ├── delete-demos-from-database-dialog.tsx │ │ ├── delete-matches-dialog.tsx │ │ ├── demo-not-found-dialog.tsx │ │ ├── dialog-provider.tsx │ │ ├── export-matches-to-json-dialog.tsx │ │ ├── export-matches-xlsx-dialog.tsx │ │ ├── export-xlsx-options-dialog.tsx │ │ ├── exporting-to-xlsx-dialog.tsx │ │ ├── rename-dialog.tsx │ │ ├── select-actions-pov-dialog.tsx │ │ ├── select-pov-dialog.tsx │ │ └── use-dialog.ts │ ├── donate.tsx │ ├── dropdown-filter │ │ ├── active-filter-indicator.tsx │ │ ├── analysis-status-select.tsx │ │ ├── demo-types-filter.tsx │ │ ├── dropdown-filter.tsx │ │ ├── filter-category.tsx │ │ ├── filter-selection.tsx │ │ ├── filter-separator.tsx │ │ ├── filter-value.tsx │ │ ├── game-filter.tsx │ │ ├── game-modes-filter.tsx │ │ ├── match-length-filter.tsx │ │ ├── period-filter.tsx │ │ ├── ranking-select.tsx │ │ ├── sources-filter.tsx │ │ ├── tags-filter.tsx │ │ └── weapons-filter.tsx │ ├── dropdown.tsx │ ├── error-message.tsx │ ├── external-link.tsx │ ├── heatmap │ │ ├── export-heatmap-button.tsx │ │ ├── heatmap-context.ts │ │ ├── heatmap-filters.tsx │ │ ├── heatmap-provider.tsx │ │ ├── heatmap-select-event.tsx │ │ ├── heatmap-select-map.tsx │ │ ├── heatmap-side-select.tsx │ │ ├── heatmap.tsx │ │ ├── input-blur.tsx │ │ ├── input-opacity.tsx │ │ └── input-radius.tsx │ ├── inputs │ │ ├── checkbox.tsx │ │ ├── color-picker.tsx │ │ ├── comment-input.tsx │ │ ├── database-name-input.tsx │ │ ├── file-or-directory-input.tsx │ │ ├── hostname-input.tsx │ │ ├── input-label.tsx │ │ ├── markdown-editor.tsx │ │ ├── number-input.tsx │ │ ├── password-input.tsx │ │ ├── port-input.tsx │ │ ├── radio-input.tsx │ │ ├── search-input.tsx │ │ ├── seconds-input.tsx │ │ ├── select.tsx │ │ ├── select │ │ │ ├── opening-duel-result-select.tsx │ │ │ ├── perspective-select.tsx │ │ │ ├── players-select.tsx │ │ │ ├── radar-level-select.tsx │ │ │ ├── rounds-select.tsx │ │ │ ├── side-select.tsx │ │ │ ├── teams-select.tsx │ │ │ └── weapon-types-filter.tsx │ │ ├── switch.tsx │ │ ├── text-area.tsx │ │ ├── text-input-filter.tsx │ │ ├── text-input.tsx │ │ └── username-input.tsx │ ├── kill-feed-entry.tsx │ ├── last-match.tsx │ ├── last-matches.tsx │ ├── links.tsx │ ├── links │ │ ├── link.tsx │ │ └── see-round-link.tsx │ ├── maps-stats.tsx │ ├── match │ │ ├── team-indicator.tsx │ │ └── team-score.tsx │ ├── matches │ │ ├── bans-cell.tsx │ │ ├── match-comment-widget.tsx │ │ ├── team-a-score-cell.tsx │ │ ├── team-b-score-cell.tsx │ │ └── use-matches-columns.tsx │ ├── message.tsx │ ├── messages │ │ └── hlae-error.tsx │ ├── number-badge.tsx │ ├── panel.tsx │ ├── panels │ │ ├── average-damages-per-round-panel.tsx │ │ ├── average-deaths-per-round-panel.tsx │ │ ├── average-kills-per-round-panel.tsx │ │ ├── clutches.tsx │ │ ├── headshot-panel.tsx │ │ ├── hltv-rating-2-panel.tsx │ │ ├── hltv-rating-panel.tsx │ │ ├── kast-panel.tsx │ │ ├── kill-death-ratio-panel.tsx │ │ ├── kills-panel.tsx │ │ ├── multi-kills-panel.tsx │ │ ├── objectives-panel.tsx │ │ ├── rounds-panel.tsx │ │ ├── utilities-panel.tsx │ │ ├── win-rate-panel.tsx │ │ └── win-rate.tsx │ ├── premier-rank.tsx │ ├── progress.tsx │ ├── section.tsx │ ├── spinner.tsx │ ├── table │ │ ├── build-rows.ts │ │ ├── cells │ │ │ ├── avatar-cell.tsx │ │ │ ├── bans-cell.tsx │ │ │ ├── comment-cell.tsx │ │ │ ├── kill-attributes-cell.tsx │ │ │ ├── kill-death-diff-cell.tsx │ │ │ ├── rank-cell.tsx │ │ │ ├── source-cell.tsx │ │ │ └── tags-cell.tsx │ │ ├── column-visibility.tsx │ │ ├── columns-visibility-dropdown.tsx │ │ ├── comment-widget.tsx │ │ ├── date-sort-function.ts │ │ ├── get-table-row-height.ts │ │ ├── kill-death-diff-sort-function.ts │ │ ├── status-bar │ │ │ ├── table-status-bar-legend.tsx │ │ │ ├── table-status-bar-rectangle.tsx │ │ │ ├── table-status-bar-separator.tsx │ │ │ └── table-status-bar.tsx │ │ ├── table-types.ts │ │ ├── table.tsx │ │ ├── use-table-comment-widget-visibility.ts │ │ └── use-table.ts │ ├── tabs │ │ ├── tab-link-number-badge.tsx │ │ ├── tab-link.tsx │ │ └── tab-links.tsx │ ├── tags │ │ ├── tag-indicator.tsx │ │ ├── tag.tsx │ │ └── tags.tsx │ ├── team-text.tsx │ ├── timeline │ │ ├── timestamp-item.tsx │ │ └── use-timeline.tsx │ ├── toasts │ │ ├── toasts-context.ts │ │ ├── toasts-provider.tsx │ │ └── use-show-toast.ts │ ├── tooltip.tsx │ ├── transitions │ │ └── collapse-transition.tsx │ ├── unsupported-map.tsx │ ├── valve-match │ │ ├── avatar-cell.tsx │ │ ├── player-performance │ │ │ ├── performance-timeline-bar.tsx │ │ │ ├── performance-timeline.tsx │ │ │ └── round-context-menu.tsx │ │ ├── use-valve-scoreboard-columns.ts │ │ ├── valve-match-overview.tsx │ │ ├── valve-match-scoreboard.tsx │ │ └── valve-scoreboard-context-menu.tsx │ └── weapons-icons.ts │ ├── demo │ ├── demo-actions.ts │ ├── demo-comment-input.tsx │ ├── demo-date.tsx │ ├── demo-duration.tsx │ ├── demo-field.tsx │ ├── demo-information.tsx │ ├── demo-loader.tsx │ ├── demo-map.tsx │ ├── demo-match-status.tsx │ ├── demo-name-input.tsx │ ├── demo-reducer.ts │ ├── demo-source.tsx │ ├── demo-tags.tsx │ ├── demo-with-valve-match.tsx │ ├── demo-without-valve-match.tsx │ ├── demo.tsx │ ├── next-demo-link.tsx │ ├── previous-demo-link.tsx │ ├── reveal-demo-in-explorer-button.tsx │ ├── see-match-button.tsx │ ├── use-current-demo.ts │ ├── use-demo-state.ts │ ├── use-is-demo-in-database.ts │ ├── use-selected-player.ts │ └── watch-demo-button.tsx │ ├── demos │ ├── action-bar │ │ ├── action-bar.tsx │ │ ├── analyze-demos-button.tsx │ │ ├── demo-details-button.tsx │ │ ├── demos-filter-dropdown.tsx │ │ ├── fuzzy-search-text-input.tsx │ │ ├── refresh-demos-button.tsx │ │ ├── reveal-demos-in-explorer-button.tsx │ │ └── watch-demo-button.tsx │ ├── current-folder-select.tsx │ ├── demos-actions.ts │ ├── demos-reducer.ts │ ├── demos.tsx │ ├── table │ │ ├── delete-demos-from-database-item.tsx │ │ ├── demo-comment-widget.tsx │ │ ├── demo-context-menu.tsx │ │ ├── demo-status-cell.tsx │ │ ├── demos-columns-visibility.tsx │ │ ├── demos-count.tsx │ │ ├── demos-table-context.ts │ │ ├── demos-table-provider.tsx │ │ ├── demos-table-status-bar.tsx │ │ ├── demos-table.tsx │ │ ├── export-demos-items.tsx │ │ ├── loading-demos-message.tsx │ │ ├── no-demos.tsx │ │ ├── rename-demo-dialog.tsx │ │ ├── selected-demo-count.tsx │ │ ├── tags-dialog.tsx │ │ ├── update-demos-type-item.tsx │ │ ├── use-demos-columns.ts │ │ └── use-demos-table.ts │ ├── use-active-demos-filters.ts │ ├── use-demo-sources.ts │ ├── use-demos-loaded.ts │ ├── use-demos-state.ts │ ├── use-demos-status.ts │ ├── use-demos.ts │ ├── use-fetch-demos.ts │ ├── use-fuzzy-search-text.ts │ ├── use-selected-demos-paths.ts │ └── use-selected-demos.ts │ ├── dialogs │ ├── checksums-tags-dialog.tsx │ ├── confirm-dialog.tsx │ ├── dialog.tsx │ ├── full-screen-dialog.tsx │ ├── tags-dialog.tsx │ ├── update-demo-location-dialog.tsx │ └── update-player-name-dialog.tsx │ ├── downloads │ ├── dowload-required-tooltip.tsx │ ├── download-demo-button.tsx │ ├── download-demo-from-share-code-button.tsx │ ├── download-demos-button.tsx │ ├── downloads-actions.ts │ ├── downloads-folder-required.tsx │ ├── downloads-reducer.ts │ ├── downloads.tsx │ ├── faceit │ │ ├── action-bar.tsx │ │ ├── avatar-cell.tsx │ │ ├── current-match.tsx │ │ ├── faceit-actions.ts │ │ ├── faceit-reducer.ts │ │ ├── faceit-scoreboard-context-menu.tsx │ │ ├── last-matches-loader.tsx │ │ ├── last-matches.tsx │ │ ├── match.tsx │ │ ├── no-faceit-account.tsx │ │ ├── scoreboard.tsx │ │ ├── sidebar.tsx │ │ ├── use-current-faceit-account.ts │ │ ├── use-current-match.ts │ │ ├── use-faceit-accounts.ts │ │ ├── use-faceit-matches.ts │ │ ├── use-faceit-scoreboard-columns.ts │ │ ├── use-faceit-state.ts │ │ ├── use-faceit-status.ts │ │ ├── use-fetch-last-faceit-matches.ts │ │ ├── use-selected-match-id.ts │ │ └── use-update-current-faceit-account.tsx │ ├── five-eplay │ │ ├── 5eplay-action-bar.tsx │ │ ├── 5eplay-actions.ts │ │ ├── 5eplay-avatar-cell.tsx │ │ ├── 5eplay-current-match.tsx │ │ ├── 5eplay-download-sidebar.tsx │ │ ├── 5eplay-last-matches-loader.tsx │ │ ├── 5eplay-last-matches.tsx │ │ ├── 5eplay-match.tsx │ │ ├── 5eplay-reducer.ts │ │ ├── 5eplay-scoreboard-context-menu.tsx │ │ ├── 5eplay-scoreboard.tsx │ │ ├── five-eplay-account-instructions.tsx │ │ ├── no-5eplay-account.tsx │ │ ├── use-5eplay-accounts.ts │ │ ├── use-5eplay-scoreboard-columns.ts │ │ ├── use-5eplay-state.ts │ │ ├── use-current-5eplay-account.ts │ │ ├── use-current-5eplay-match.ts │ │ ├── use-fetch-last-5eplay-matches.ts │ │ └── use-update-current-5eplay-account.tsx │ ├── match-result.ts │ ├── pending-downloads-link.tsx │ ├── pending │ │ ├── action-bar.tsx │ │ ├── download-actions.tsx │ │ ├── download-entry.tsx │ │ ├── pending-actions.ts │ │ ├── pending-downloads-list.tsx │ │ ├── pending-downloads-reducer.ts │ │ ├── pending-downloads.tsx │ │ ├── remove-download-button.tsx │ │ ├── remove-downloads-button.tsx │ │ ├── use-download-progress.ts │ │ ├── use-download-status.ts │ │ ├── use-downloads.ts │ │ ├── use-pending-download-count.ts │ │ └── use-pending-downloads-state.ts │ ├── reveal-demo-in-explorer-button.tsx │ ├── reveal-download-folder-in-explorer-button.tsx │ ├── see-demo-button.tsx │ ├── sidebar │ │ ├── match-date.tsx │ │ ├── match-download-status.tsx │ │ ├── match-entry.tsx │ │ ├── match-result-text.tsx │ │ └── match-score.tsx │ ├── use-downloads-state.ts │ ├── use-get-boiler-error-message-from-error-code.ts │ ├── use-get-downloaded-demo-path.ts │ ├── valve │ │ ├── action-bar.tsx │ │ ├── current-match.tsx │ │ ├── download-demo-button.tsx │ │ ├── fetch-matches-confirmation.tsx │ │ ├── fetch-matches-error.tsx │ │ ├── last-matches-loader.tsx │ │ ├── last-matches.tsx │ │ ├── no-matches-found.tsx │ │ ├── sidebar.tsx │ │ ├── use-current-steamid.ts │ │ ├── use-error-code.ts │ │ ├── use-matches.ts │ │ ├── use-selected-match-id.ts │ │ ├── use-selected-match.ts │ │ ├── use-selected-player.ts │ │ ├── use-selected-steam-id.ts │ │ ├── use-status.ts │ │ ├── use-valve-state.ts │ │ ├── valve-actions.ts │ │ └── valve-reducer.ts │ └── watch-demo-button.tsx │ ├── error-boundary.tsx │ ├── hooks │ ├── chart │ │ ├── use-match-result-pie.tsx │ │ └── use-team-side-pie.tsx │ ├── drawing │ │ └── use-draw-player-death.ts │ ├── navigation │ │ └── use-navigate-to-match-player.ts │ ├── use-add-demos-to-analyses.ts │ ├── use-block-navigation.ts │ ├── use-boolean-to-human.ts │ ├── use-chart.ts │ ├── use-charts-colors.ts │ ├── use-clipboard.tsx │ ├── use-counter-strike.tsx │ ├── use-css-variable-value.ts │ ├── use-export-match-chat-messages.tsx │ ├── use-focus-last-active-element.ts │ ├── use-format-date.ts │ ├── use-format-money.ts │ ├── use-game-options.ts │ ├── use-get-game-mode-translation.ts │ ├── use-get-rank-name.ts │ ├── use-get-rank-tier-name.ts │ ├── use-interactive-map-canvas.ts │ ├── use-is-cs-running.ts │ ├── use-map-canvas.ts │ ├── use-navigate-to-demo.ts │ ├── use-navigate-to-match.ts │ ├── use-navigate-to-player.ts │ ├── use-navigate-to-team.ts │ ├── use-outside-click.ts │ ├── use-path-exists.ts │ ├── use-process-demos-to-analyze.tsx │ ├── use-seconds-to-formatted-minutes.ts │ ├── use-translate-economy-ban.ts │ ├── use-translate-team-number.ts │ ├── use-unix-timestamp-to-humanized-date.ts │ ├── use-update-demo-location.ts │ └── use-web-socket-client.ts │ ├── icons │ ├── airborne-kill-icon.svg │ ├── airborne-kill-icon.tsx │ ├── armor-icon.svg │ ├── armor-icon.tsx │ ├── armor-with-helmet-icon.svg │ ├── armor-with-helmet-icon.tsx │ ├── arrow-down-long-icon.svg │ ├── arrow-down-long-icon.tsx │ ├── arrow-up-long-icon.svg │ ├── arrow-up-long-icon.tsx │ ├── bars-icon.svg │ ├── bars-icon.tsx │ ├── blind-icon.svg │ ├── blind-icon.tsx │ ├── calendar-icon.svg │ ├── calendar-icon.tsx │ ├── check-circle-icon.svg │ ├── check-circle-icon.tsx │ ├── check-icon.svg │ ├── check-icon.tsx │ ├── chevron-down-icon.svg │ ├── chevron-down-icon.tsx │ ├── chicken.svg │ ├── clock-icon.svg │ ├── clock-icon.tsx │ ├── cogs-icon.svg │ ├── cogs-icon.tsx │ ├── comment-dots-icon.svg │ ├── comment-dots-icon.tsx │ ├── counter-terrorist-icon.svg │ ├── counter-terrorist-icon.tsx │ ├── database-search-icon.svg │ ├── database-search-icon.tsx │ ├── dem-file-icon.svg │ ├── dem-file-icon.tsx │ ├── download-icon.svg │ ├── download-icon.tsx │ ├── drag-icon.svg │ ├── drag-icon.tsx │ ├── elimination-headshot-icon.svg │ ├── elimination-headshot-icon.tsx │ ├── elimination-icon.svg │ ├── elimination-icon.tsx │ ├── exclamation-triangle-icon.svg │ ├── exclamation-triangle-icon.tsx │ ├── expired-icon.svg │ ├── expired-icon.tsx │ ├── explosion-icon.svg │ ├── explosion-icon.tsx │ ├── file-corrupted-icon.tsx │ ├── file-corrupted.svg │ ├── flag-icon.svg │ ├── flag-icon.tsx │ ├── flashbang-assist-icon.svg │ ├── flashbang-assist-icon.tsx │ ├── focus-icon.svg │ ├── focus-icon.tsx │ ├── folder-icon.svg │ ├── folder-icon.tsx │ ├── headshot-icon.svg │ ├── headshot-icon.tsx │ ├── jump-icon.svg │ ├── jump-icon.tsx │ ├── left-arrow-icon.svg │ ├── left-arrow-icon.tsx │ ├── map-icon.svg │ ├── map-icon.tsx │ ├── maximize-icon.svg │ ├── maximize-icon.tsx │ ├── minimize-icon.svg │ ├── minimize-icon.tsx │ ├── noscope-icon.svg │ ├── noscope-icon.tsx │ ├── pause-icon.svg │ ├── pause-icon.tsx │ ├── pending-icon.svg │ ├── pending-icon.tsx │ ├── penetrate-icon.svg │ ├── penetrate-icon.tsx │ ├── perfect-world-icon.svg │ ├── play-circle-icon.svg │ ├── play-circle-icon.tsx │ ├── play-icon.svg │ ├── play-icon.tsx │ ├── player-icon.svg │ ├── player-icon.tsx │ ├── question-icon.svg │ ├── question-icon.tsx │ ├── revenge-icon.svg │ ├── revenge-icon.tsx │ ├── right-arrow-icon.svg │ ├── right-arrow-icon.tsx │ ├── round-end-reason-icon.tsx │ ├── shield-icon.svg │ ├── shield-icon.tsx │ ├── star-icon.svg │ ├── star-icon.tsx │ ├── step-backward-icon.svg │ ├── step-backward-icon.tsx │ ├── step-forward-icon.svg │ ├── step-forward-icon.tsx │ ├── sync-icon.svg │ ├── sync-icon.tsx │ ├── tag-icon.svg │ ├── tag-icon.tsx │ ├── team-icon.svg │ ├── team-icon.tsx │ ├── terrorist-icon.svg │ ├── terrorist-icon.tsx │ ├── through-smoke-kill-icon.svg │ ├── through-smoke-kill-icon.tsx │ ├── thumbs-down-icon.svg │ ├── thumbs-up-icon.svg │ ├── times-circle.svg │ ├── times-circle.tsx │ ├── update-icon.svg │ ├── update-icon.tsx │ ├── user-icon.svg │ ├── user-icon.tsx │ ├── video-icon.tsx │ ├── video.svg │ └── weapons │ │ ├── ak47-icon.svg │ │ ├── ak47-icon.tsx │ │ ├── aug-icon.svg │ │ ├── aug-icon.tsx │ │ ├── awp-icon.svg │ │ ├── awp-icon.tsx │ │ ├── bizon-icon.svg │ │ ├── bizon-icon.tsx │ │ ├── bomb-icon.svg │ │ ├── bomb-icon.tsx │ │ ├── cz75a-icon.svg │ │ ├── cz75a-icon.tsx │ │ ├── deagle-icon.svg │ │ ├── deagle-icon.tsx │ │ ├── decoy-icon.svg │ │ ├── decoy-icon.tsx │ │ ├── defuser-icon.svg │ │ ├── defuser-icon.tsx │ │ ├── dual-elite-icon.svg │ │ ├── dual-elite-icon.tsx │ │ ├── famas-icon.svg │ │ ├── famas-icon.tsx │ │ ├── five-seven-icon.svg │ │ ├── five-seven-icon.tsx │ │ ├── flashbang-icon.svg │ │ ├── flashbang-icon.tsx │ │ ├── g3sg1-icon.svg │ │ ├── g3sg1-icon.tsx │ │ ├── galilar-icon.svg │ │ ├── galilar-icon.tsx │ │ ├── glock-icon.svg │ │ ├── glock-icon.tsx │ │ ├── he-grenade-icon.svg │ │ ├── he-grenade-icon.tsx │ │ ├── helmet-icon.svg │ │ ├── helmet-icon.tsx │ │ ├── incendiary-grenade-icon.svg │ │ ├── incendiary-grenade-icon.tsx │ │ ├── kevlar-icon.svg │ │ ├── kevlar-icon.tsx │ │ ├── knife-icon.svg │ │ ├── knife-icon.tsx │ │ ├── m249-icon.svg │ │ ├── m249-icon.tsx │ │ ├── m4a1-icon.svg │ │ ├── m4a1-icon.tsx │ │ ├── m4a1-silencer-off-icon.svg │ │ ├── m4a4-icon.svg │ │ ├── m4a4-icon.tsx │ │ ├── mac10-icon.svg │ │ ├── mac10-icon.tsx │ │ ├── mag7-icon.svg │ │ ├── mag7-icon.tsx │ │ ├── molotov-icon.svg │ │ ├── molotov-icon.tsx │ │ ├── mp5sd-icon.svg │ │ ├── mp5sd-icon.tsx │ │ ├── mp7-icon.svg │ │ ├── mp7-icon.tsx │ │ ├── mp9-icon.svg │ │ ├── mp9-icon.tsx │ │ ├── negev-icon.svg │ │ ├── negev-icon.tsx │ │ ├── nova-icon.svg │ │ ├── nova-icon.tsx │ │ ├── p2000-icon.svg │ │ ├── p2000-icon.tsx │ │ ├── p250-icon.svg │ │ ├── p250-icon.tsx │ │ ├── p90-icon.svg │ │ ├── p90-icon.tsx │ │ ├── revolver-icon.svg │ │ ├── revolver-icon.tsx │ │ ├── sawed-off-icon.svg │ │ ├── sawed-off-icon.tsx │ │ ├── scar20-icon.svg │ │ ├── scar20-icon.tsx │ │ ├── sg553-icon.svg │ │ ├── sg553-icon.tsx │ │ ├── smoke-grenade-icon.svg │ │ ├── smoke-grenade-icon.tsx │ │ ├── ssg08-icon.svg │ │ ├── ssg08-icon.tsx │ │ ├── tec9-icon.svg │ │ ├── tec9-icon.tsx │ │ ├── ump45-icon.svg │ │ ├── ump45-icon.tsx │ │ ├── usps-icon.svg │ │ ├── usps-icon.tsx │ │ ├── usps-silencer-off-icon.svg │ │ ├── world-icon.svg │ │ ├── world-icon.tsx │ │ ├── xm1014-icon.svg │ │ ├── xm1014-icon.tsx │ │ ├── zeus-icon.svg │ │ └── zeus-icon.tsx │ ├── index.css │ ├── index.html │ ├── keyboard │ ├── keyboard-shortcut.ts │ └── keyboard.ts │ ├── left-bar │ ├── analyses-link.tsx │ ├── bans-link.tsx │ ├── demos-link.tsx │ ├── downloads-link.tsx │ ├── left-bar-badge.tsx │ ├── left-bar-link.tsx │ ├── left-bar-tooltip.tsx │ ├── left-bar.tsx │ ├── matches-link.tsx │ ├── pending-analyses-badge.tsx │ ├── pending-downloads-badge.tsx │ ├── pending-videos-badge.tsx │ ├── pinned-player-link.tsx │ ├── players-link.tsx │ ├── search-link.tsx │ ├── settings-button.tsx │ ├── teams-link.tsx │ └── video-queue-link.tsx │ ├── maps │ ├── get-scaled-coordinate-x.ts │ ├── get-scaled-coordinate-y.ts │ ├── maps-actions.ts │ ├── maps-reducer.ts │ ├── radar-level.ts │ ├── use-get-map-radar-src.ts │ ├── use-get-map-thumbnail-src.ts │ ├── use-maps-state.ts │ └── use-maps.ts │ ├── match │ ├── chat-messages │ │ ├── chat-message.tsx │ │ ├── chat-messages-list.tsx │ │ ├── chat-messages.tsx │ │ ├── empty-chat-messages.tsx │ │ └── export-chat-messages-button.tsx │ ├── duels │ │ ├── match-duels.tsx │ │ ├── opening-duels-map │ │ │ ├── opening-duel-context-menu.tsx │ │ │ ├── opening-duels-map-loader.tsx │ │ │ ├── opening-duels-map.tsx │ │ │ └── use-opening-duels-map-columns.ts │ │ ├── opening-duels-stats │ │ │ ├── opening-duels-round-breakdown.tsx │ │ │ └── opening-duels-stats.tsx │ │ └── players-duels-matrix.tsx │ ├── economy │ │ ├── economy.tsx │ │ ├── match-teams-economy-types-chart.tsx │ │ ├── team-economy-advantage-chart.tsx │ │ ├── team-economy-breakdown │ │ │ ├── get-economy-type-color.ts │ │ │ ├── team-economy-breakdown-chart.tsx │ │ │ ├── team-economy-cards.tsx │ │ │ └── use-translate-economy-type.ts │ │ └── team-equipment-values-chart.tsx │ ├── entity-reducer.ts │ ├── grenades │ │ ├── finder │ │ │ ├── context-menu.tsx │ │ │ ├── drawing │ │ │ │ ├── build-grenade-drawings.ts │ │ │ │ ├── draw-grenade-drawings.ts │ │ │ │ ├── draw-map-radar.ts │ │ │ │ ├── grenade-drawing.ts │ │ │ │ └── use-get-grenade-image.ts │ │ │ ├── grenade-name-select.tsx │ │ │ ├── grenades-finder-actions.ts │ │ │ ├── grenades-finder-loader.tsx │ │ │ ├── grenades-finder-reducer.ts │ │ │ ├── grenades-finder.tsx │ │ │ ├── players-select.tsx │ │ │ ├── radar-level-select.tsx │ │ │ ├── rounds-select.tsx │ │ │ ├── side-select.tsx │ │ │ ├── use-filtered-grenades-throw.ts │ │ │ ├── use-grenades-finder-columns.ts │ │ │ ├── use-grenades-finder-state.ts │ │ │ ├── use-selected-grenade-name.ts │ │ │ ├── use-selected-radar-level.ts │ │ │ ├── use-selected-rounds.ts │ │ │ ├── use-selected-sides.ts │ │ │ └── use-selected-steamids.ts │ │ ├── grenades-reducer.ts │ │ ├── grenades-tabs.tsx │ │ ├── match-grenades.tsx │ │ ├── stats │ │ │ ├── cells │ │ │ │ ├── cell-text.tsx │ │ │ │ ├── cell.tsx │ │ │ │ ├── fire-cells.tsx │ │ │ │ ├── flashbang-cells.tsx │ │ │ │ ├── he-grenade-cells.tsx │ │ │ │ └── smoke-cells.tsx │ │ │ ├── grenade-option.ts │ │ │ ├── grenade-select.tsx │ │ │ ├── grenades-stats.tsx │ │ │ ├── labels │ │ │ │ ├── fire-labels.tsx │ │ │ │ ├── flashbang-labels.tsx │ │ │ │ ├── he-grenade-labels.tsx │ │ │ │ └── label.tsx │ │ │ ├── players-flashbang-matrix.tsx │ │ │ ├── players-stats-grid.tsx │ │ │ └── stats-label.tsx │ │ └── use-grenades-state.ts │ ├── heatmap │ │ ├── heatmap-reducer.ts │ │ ├── match-heatmap-actions.ts │ │ ├── match-heatmap-filters.tsx │ │ ├── match-heatmap.tsx │ │ └── use-heatmap-state.ts │ ├── match-actions.ts │ ├── match-comment-input.tsx │ ├── match-loader.tsx │ ├── match-reducer.ts │ ├── match-tabs.tsx │ ├── overview │ │ ├── action-bar │ │ │ ├── action-bar.tsx │ │ │ ├── copy-match-share-code.tsx │ │ │ ├── export-match-as-xlsx-button.tsx │ │ │ ├── export-match-to-json-button.tsx │ │ │ ├── reveal-match-demo-in-explorer-button.tsx │ │ │ ├── scoreboard-columns-visibility.tsx │ │ │ ├── see-demo-button.tsx │ │ │ ├── watch-match-at-tick-button.tsx │ │ │ └── watch-match-button.tsx │ │ ├── match-overview-context.ts │ │ ├── match-overview-provider.tsx │ │ ├── match-overview.tsx │ │ ├── scoreboard │ │ │ ├── bans-cell.tsx │ │ │ ├── context-menu │ │ │ │ ├── copy-crosshair-config-item.tsx │ │ │ │ ├── copy-crosshair-share-code-item.tsx │ │ │ │ ├── copy-player-data-item.tsx │ │ │ │ ├── generate-player-deaths-video-item.tsx │ │ │ │ ├── generate-player-events-dialog.tsx │ │ │ │ ├── generate-player-kills-video-item.tsx │ │ │ │ ├── generate-player-rounds-video-item.tsx │ │ │ │ ├── generate-player-video-item.tsx │ │ │ │ └── scoreboard-context-menu.tsx │ │ │ ├── match-information.tsx │ │ │ ├── rounds-timeline.tsx │ │ │ ├── scoreboard-avatar-cell.tsx │ │ │ ├── scoreboard.tsx │ │ │ └── use-scoreboard-columns.ts │ │ └── use-match-overview.ts │ ├── players │ │ ├── clutches-panel.tsx │ │ ├── kills-panel.tsx │ │ ├── match-players-loader.tsx │ │ ├── match-players.tsx │ │ ├── player-action-bar.tsx │ │ ├── utilities-panel.tsx │ │ └── weapons-panel.tsx │ ├── rounds │ │ ├── overview │ │ │ ├── round-entry.tsx │ │ │ ├── rounds-entries.tsx │ │ │ ├── rounds-history.tsx │ │ │ └── rounds.tsx │ │ ├── play-demo-at-tick-button.tsx │ │ ├── round │ │ │ ├── clutches.tsx │ │ │ ├── end-reason.tsx │ │ │ ├── kill-feed.tsx │ │ │ ├── players-economy-chart.tsx │ │ │ ├── players-information.tsx │ │ │ ├── round-tags.tsx │ │ │ ├── round-top-bar.tsx │ │ │ ├── round.tsx │ │ │ └── use-current-round.ts │ │ └── rounds-navigation-bar.tsx │ ├── use-current-match-checksum.ts │ ├── use-current-match-map.ts │ ├── use-current-match.ts │ ├── use-time-elapsed-between-frames.ts │ ├── use-unsafe-current-match.ts │ ├── video │ │ ├── add-video-to-queue-button.tsx │ │ ├── add-video-to-queue-error-dialog.tsx │ │ ├── cfg-input.tsx │ │ ├── close-game-after-recording-checkbox.tsx │ │ ├── concatenate-sequences-checkbox.tsx │ │ ├── death-notices-duration-input.tsx │ │ ├── encoder-software-select.tsx │ │ ├── ffmpeg │ │ │ ├── audio-codec-input.tsx │ │ │ ├── constant-rate-factor-input.tsx │ │ │ ├── ffmpeg-actions.ts │ │ │ ├── ffmpeg-audio-bitrate-select.tsx │ │ │ ├── ffmpeg-browse-button.tsx │ │ │ ├── ffmpeg-input-parameters-input.tsx │ │ │ ├── ffmpeg-install-button.tsx │ │ │ ├── ffmpeg-output-parameters-input.tsx │ │ │ ├── ffmpeg-reducer.ts │ │ │ ├── ffmpeg-update-button.tsx │ │ │ ├── ffmpeg.tsx │ │ │ ├── use-ffmpeg-state.ts │ │ │ ├── use-installed-ffmpeg-version.ts │ │ │ ├── use-is-ffmpeg-installed.ts │ │ │ ├── use-is-ffmpeg-update-available.ts │ │ │ ├── video-codec-input.tsx │ │ │ └── video-container-select.tsx │ │ ├── focus-camera-player-select.tsx │ │ ├── framerate-input.tsx │ │ ├── generate-player-sequences-button.tsx │ │ ├── get-video-error-from-error-code.tsx │ │ ├── height-resolution-input.tsx │ │ ├── hlae │ │ │ ├── hlae-actions.ts │ │ │ ├── hlae-browse-button.tsx │ │ │ ├── hlae-config-folder-path.tsx │ │ │ ├── hlae-install-button.tsx │ │ │ ├── hlae-parameters.tsx │ │ │ ├── hlae-reducer.ts │ │ │ ├── hlae-update-button.tsx │ │ │ ├── hlae.tsx │ │ │ ├── use-hlae-state.ts │ │ │ ├── use-installed-hlae-version.ts │ │ │ ├── use-is-hlae-installed.ts │ │ │ └── use-is-hlae-update-available.ts │ │ ├── output-folder-path.tsx │ │ ├── player-voices-checkbox.tsx │ │ ├── recording-output-select.tsx │ │ ├── recording-output.tsx │ │ ├── recording-system-select.tsx │ │ ├── reset-settings-button.tsx │ │ ├── sequence │ │ │ ├── cameras │ │ │ │ ├── focus-camera-kill-pov-input.tsx │ │ │ │ ├── generate-cameras-dialog.tsx │ │ │ │ ├── generate-cameras-form.ts │ │ │ │ ├── manage-cameras-buttons.tsx │ │ │ │ └── sequence-cameras-table.tsx │ │ │ ├── copy-steamid-button.tsx │ │ │ ├── edit-sequence-dialog.tsx │ │ │ ├── enable-player-voices-checkbox.tsx │ │ │ ├── end-tick-input.tsx │ │ │ ├── get-sequence-player-color.ts │ │ │ ├── highlight-player-kills-checkbox.tsx │ │ │ ├── match-timeline │ │ │ │ ├── bomb-defused-item.tsx │ │ │ │ ├── bomb-exploded-item.tsx │ │ │ │ ├── bomb-planted-item.tsx │ │ │ │ ├── camera-item.tsx │ │ │ │ ├── camera-marker.tsx │ │ │ │ ├── focus-camera-on-event-sub-context-menu.tsx │ │ │ │ ├── kill-item.tsx │ │ │ │ ├── match-timeline.tsx │ │ │ │ ├── round-item.tsx │ │ │ │ ├── select-seconds-dialog.tsx │ │ │ │ ├── tick-context-menu.tsx │ │ │ │ ├── tick.tsx │ │ │ │ └── time-marker.tsx │ │ │ ├── player-name-input.tsx │ │ │ ├── players-colors.tsx │ │ │ ├── save-sequence-button.tsx │ │ │ ├── sequence-cfg-input.tsx │ │ │ ├── sequence-death-notices-duration-input.tsx │ │ │ ├── sequence-dialog.tsx │ │ │ ├── sequence-disk-space.tsx │ │ │ ├── sequence-duration.tsx │ │ │ ├── sequence-form-provider.tsx │ │ │ ├── sequence-form.ts │ │ │ ├── sequence-player-voices-checkbox.tsx │ │ │ ├── sequence-players.tsx │ │ │ ├── sequence-x-ray-checkbox.tsx │ │ │ ├── show-only-death-notices-checkbox.tsx │ │ │ ├── show-player-kills-checkbox.tsx │ │ │ ├── start-tick-input.tsx │ │ │ └── use-sequence-form.ts │ │ ├── sequences-summary.tsx │ │ ├── sequences │ │ │ ├── add-new-sequence-button.tsx │ │ │ ├── add-sequence-dialog.tsx │ │ │ ├── build-player-event-sequences.test.ts │ │ │ ├── build-player-event-sequences.ts │ │ │ ├── build-player-rounds-sequences.ts │ │ │ ├── delete-sequences-button.tsx │ │ │ ├── edit-sequences │ │ │ │ ├── edit-sequences-settings-button.tsx │ │ │ │ ├── edit-sequences-settings-dialog.tsx │ │ │ │ └── player-options │ │ │ │ │ ├── enable-player-voices-checkbox.tsx │ │ │ │ │ ├── highlight-player-kills-checkbox.tsx │ │ │ │ │ ├── player-name-input.tsx │ │ │ │ │ ├── players-options-provider.tsx │ │ │ │ │ ├── sequence-players-options.tsx │ │ │ │ │ ├── show-player-kills-checkbox.tsx │ │ │ │ │ └── use-players-options.ts │ │ │ ├── get-sequences-duration.ts │ │ │ ├── player-sequence-event.ts │ │ │ ├── required-disk-space.tsx │ │ │ ├── sequences-actions.ts │ │ │ ├── sequences-disk-space.tsx │ │ │ ├── sequences-duration.tsx │ │ │ ├── sequences-reducer.ts │ │ │ ├── sequences-timelines │ │ │ │ ├── sequence-item.tsx │ │ │ │ └── sequences-timeline.tsx │ │ │ ├── use-compute-require-bytes.ts │ │ │ ├── use-current-match-sequences.ts │ │ │ ├── use-get-sequences-required-disk-space.ts │ │ │ ├── use-sequences-by-demo-file-path.ts │ │ │ └── use-sequences-required-disk-space.ts │ │ ├── show-only-death-notices-checkbox.tsx │ │ ├── software-browse-button.tsx │ │ ├── software.tsx │ │ ├── update-demo-location.tsx │ │ ├── use-can-edit-video-players-options.ts │ │ ├── use-video-state.ts │ │ ├── video-actions.ts │ │ ├── video-documentation-link.tsx │ │ ├── video-loader.tsx │ │ ├── video-reducer.ts │ │ ├── video.tsx │ │ ├── virtualdub │ │ │ ├── use-is-virtual-dub-installed.ts │ │ │ ├── use-virtual-dub-state.ts │ │ │ ├── virtual-dub-actions.ts │ │ │ ├── virtual-dub-browse-button.tsx │ │ │ ├── virtual-dub-install-button.tsx │ │ │ ├── virtual-dub-reducer.ts │ │ │ └── virtual-dub.tsx │ │ ├── width-resolution-input.tsx │ │ └── x-ray-checkbox.tsx │ ├── viewer-2d │ │ ├── build-player-id.ts │ │ ├── drawing │ │ │ ├── degrees-to-radians.ts │ │ │ ├── get-grenade-color.ts │ │ │ ├── use-bomb-explosion-image.ts │ │ │ ├── use-bomb-image.ts │ │ │ ├── use-chicken-image.ts │ │ │ ├── use-draw-bombs.ts │ │ │ ├── use-draw-chickens.ts │ │ │ ├── use-draw-deaths.ts │ │ │ ├── use-draw-grenades.ts │ │ │ ├── use-draw-hostages.ts │ │ │ ├── use-draw-infernos.ts │ │ │ ├── use-draw-map-radar.ts │ │ │ ├── use-draw-players.ts │ │ │ └── use-draw-shots.ts │ │ ├── fullscreen-provider.tsx │ │ ├── kills-feed.tsx │ │ ├── no-positions-found.tsx │ │ ├── playback-bar │ │ │ ├── bomb-exploded-indicator.tsx │ │ │ ├── bomb-planted-indicator.tsx │ │ │ ├── freezetime-end-indicator.tsx │ │ │ ├── fullscreen-button.tsx │ │ │ ├── indicator.tsx │ │ │ ├── kill-indicator.tsx │ │ │ ├── next-round-button.tsx │ │ │ ├── play-pause-button.tsx │ │ │ ├── playback-bar-button.tsx │ │ │ ├── playback-bar.tsx │ │ │ ├── previous-round-button.tsx │ │ │ ├── radar-level-button.tsx │ │ │ ├── speed-button.tsx │ │ │ ├── timeline.tsx │ │ │ └── vertical-slider.tsx │ │ ├── rounds-bar │ │ │ ├── round-button.tsx │ │ │ └── rounds-bar.tsx │ │ ├── teams-panel │ │ │ ├── armor-indicator.tsx │ │ │ ├── bomb-indicator.tsx │ │ │ ├── current-weapon.tsx │ │ │ ├── health-armor-state.tsx │ │ │ ├── player-row.tsx │ │ │ ├── team-panel.tsx │ │ │ └── weapons.tsx │ │ ├── timer.tsx │ │ ├── use-fullscreen.ts │ │ ├── use-viewer-context.ts │ │ ├── use-viewer-state.ts │ │ ├── viewer-2d-loader.tsx │ │ ├── viewer-2d-reducer.ts │ │ ├── viewer-2d.tsx │ │ ├── viewer-actions.ts │ │ └── viewer-context.tsx │ └── weapons │ │ ├── body.tsx │ │ ├── weapons-accuracy.tsx │ │ └── weapons.tsx │ ├── matches │ ├── actionbar │ │ ├── action-bar.tsx │ │ ├── fuzzy-search-text-input.tsx │ │ ├── match-details-button.tsx │ │ ├── matches-columns-visibility.tsx │ │ ├── matches-filter-dropdown.tsx │ │ ├── reveal-matches-in-explorer-button.tsx │ │ └── watch-match-button.tsx │ ├── dialogs │ │ ├── rename-match-dialog.tsx │ │ ├── tags-dialog.tsx │ │ └── update-team-names-dialog.tsx │ ├── matches-actions.ts │ ├── matches-reducer.ts │ ├── matches-table-provider.tsx │ ├── matches.tsx │ ├── table │ │ ├── match-context-menu.tsx │ │ ├── match-count.tsx │ │ ├── match-with-cheater-indicator.tsx │ │ ├── matches-status-bar.tsx │ │ ├── matches-table-context.ts │ │ ├── matches-table.tsx │ │ ├── no-matches.tsx │ │ ├── selected-match-count.tsx │ │ └── use-matches-table.ts │ ├── use-active-matches-filters.ts │ ├── use-fetch-matches.ts │ ├── use-fuzzy-search-text.ts │ ├── use-matches-loaded.ts │ ├── use-matches-state.ts │ ├── use-matches-status.ts │ ├── use-matches.ts │ ├── use-selected-match-checksums.ts │ └── use-selected-matches.ts │ ├── player │ ├── charts │ │ ├── average-damage-per-round-chart.tsx │ │ ├── build-average-player-chart-data.ts │ │ ├── clutch-won-percentage-chart.tsx │ │ ├── competitive-rank-repartition-chart.tsx │ │ ├── headshot-percentage-chart.tsx │ │ ├── kill-death-ratio-chart.tsx │ │ ├── match-count-chart.tsx │ │ ├── player-charts.tsx │ │ ├── premier-rank-repartition-chart.tsx │ │ ├── use-player-chart-options.ts │ │ └── x-axis.tsx │ ├── export-player-as-xlsx-button.tsx │ ├── load-player-error.tsx │ ├── maps │ │ └── player-maps.tsx │ ├── matches │ │ ├── player-delete-matches-dialog.tsx │ │ ├── player-match-context-menu.tsx │ │ ├── player-matches-table.tsx │ │ └── use-selected-match-checksums.ts │ ├── overview │ │ ├── matchmaking-panel.tsx │ │ ├── player-clutches.tsx │ │ ├── player-comment-input.tsx │ │ ├── player-last-matches.tsx │ │ ├── player-multi-kills-panel.tsx │ │ ├── player-objectives-panel.tsx │ │ ├── player-opening-duels-panel.tsx │ │ ├── player-overview.tsx │ │ ├── player-utilities-panel.tsx │ │ ├── player-win-rate-panel.tsx │ │ └── vac-panel.tsx │ ├── pinned-player.tsx │ ├── player-action-bar.tsx │ ├── player-actions.ts │ ├── player-filter-dropdown.tsx │ ├── player-loader.tsx │ ├── player-reducer.ts │ ├── player-steam-link.tsx │ ├── player-tabs.tsx │ ├── player.tsx │ ├── rank │ │ ├── player-competitive-rank-history.tsx │ │ ├── player-premier-rank-history.tsx │ │ ├── player-rank.tsx │ │ └── use-get-win-count-translation.ts │ ├── use-active-player-filters.ts │ ├── use-current-player-steam-id.ts │ ├── use-fetch-player.ts │ ├── use-player-state.ts │ ├── use-player.ts │ ├── use-unsafe-player.ts │ └── use-update-player-comment.tsx │ ├── players │ ├── action-bar.tsx │ ├── action-bar │ │ ├── ban-filter.tsx │ │ ├── columns-visibility.tsx │ │ ├── fuzzy-search-text-input.tsx │ │ ├── player-details-button.tsx │ │ ├── players-filter-dropdown.tsx │ │ └── refresh-button.tsx │ ├── no-players.tsx │ ├── players-actions.ts │ ├── players-reducer.ts │ ├── players-table.tsx │ ├── players-tags-dialogs.tsx │ ├── players.tsx │ ├── table │ │ ├── bans-cell.tsx │ │ ├── bans-indicators.tsx │ │ ├── export-players-item.tsx │ │ ├── export-players-to-xlsx-dialog.tsx │ │ ├── player-avatar-cell.tsx │ │ ├── player-comment-widget.tsx │ │ ├── player-context-menu.tsx │ │ ├── player-count.tsx │ │ ├── players-table-context.ts │ │ ├── players-table-provider.tsx │ │ ├── players-table-status-bar.tsx │ │ ├── selected-player-count.tsx │ │ ├── use-players-columns.ts │ │ └── use-players-table.ts │ ├── use-active-players-filters.ts │ ├── use-fetch-players.ts │ ├── use-fuzzy-search-text.ts │ ├── use-players-state.ts │ ├── use-players-status.ts │ ├── use-players.ts │ └── use-selected-players-steamids.ts │ ├── renderer.tsx │ ├── router.tsx │ ├── routes-paths.ts │ ├── search │ ├── filters │ │ ├── search-event-input.tsx │ │ ├── search-maps-input.tsx │ │ └── search-players-input.tsx │ ├── results │ │ ├── clutches-results.tsx │ │ ├── collateral-kills-results.tsx │ │ ├── dot-separator.tsx │ │ ├── kills-results.tsx │ │ ├── multi-kills-results.tsx │ │ ├── ninja-defuse-results.tsx │ │ ├── result-row.tsx │ │ ├── rounds-result.tsx │ │ ├── virtual-list-results.tsx │ │ └── wallbang-kills-results.tsx │ ├── search-actions.ts │ ├── search-reducer.ts │ ├── search-results.tsx │ ├── search.tsx │ └── use-search-state.ts │ ├── settings │ ├── about │ │ ├── about.tsx │ │ ├── clear-logs-button.tsx │ │ ├── reset-settings-button.tsx │ │ └── see-changelog-button.tsx │ ├── analyze │ │ ├── analyze-settings.tsx │ │ ├── ignore-ban-before-first-seen.tsx │ │ ├── toggle-analyze-positions.tsx │ │ └── use-analyze-settings.ts │ ├── bans │ │ ├── add-ignored-steam-account-dialog.tsx │ │ ├── ban-settings.tsx │ │ ├── ignored-steam-accounts.tsx │ │ ├── use-ban-settings.ts │ │ └── use-ignored-steam-account.tsx │ ├── close-settings-button.tsx │ ├── database │ │ ├── database-settings.tsx │ │ ├── database-size.tsx │ │ ├── database.tsx │ │ ├── disconnect-database-button.tsx │ │ ├── import-v2-data-button.tsx │ │ ├── optimize-database-button.tsx │ │ ├── reset-database-button.tsx │ │ └── use-database-settings.ts │ ├── downloads │ │ ├── 5eplay-accounts.tsx │ │ ├── 5eplay-settings.tsx │ │ ├── auto-download-5eplay-demos-background.tsx │ │ ├── auto-download-5eplay-demos.tsx │ │ ├── auto-download-faceit-demos-background.tsx │ │ ├── auto-download-faceit-demos.tsx │ │ ├── auto-download-valve-demos-background.tsx │ │ ├── auto-download-valve-demos.tsx │ │ ├── download-folder-path.tsx │ │ ├── download-view.tsx │ │ ├── faceit-accounts.tsx │ │ ├── faceit-downloads-warning.tsx │ │ ├── faceit-settings.tsx │ │ ├── use-add-5eplay-account.tsx │ │ ├── use-add-faceit-account.tsx │ │ ├── use-download-folder-path-or-throw-error.ts │ │ ├── use-download-folder-path.ts │ │ ├── use-show-download-folder-dialog.ts │ │ └── valve-settings.tsx │ ├── folders │ │ ├── add-folder-button.tsx │ │ ├── folder-actions.ts │ │ ├── folder-row.tsx │ │ ├── folders-list.tsx │ │ ├── folders-settings.tsx │ │ ├── include-sub-folders-switch.tsx │ │ ├── remove-folder-button.tsx │ │ ├── use-add-folder.tsx │ │ ├── use-current-demo-folder.ts │ │ ├── use-demos-settings.ts │ │ ├── use-folders.ts │ │ └── use-toggle-folder-sub-folders-inclusion.ts │ ├── integrations │ │ ├── faceit-api-key.tsx │ │ ├── integrations-settings.tsx │ │ └── steam-api-key.tsx │ ├── maps │ │ ├── add-map-button.tsx │ │ ├── add-map-dialog.tsx │ │ ├── delete-map-dialog.tsx │ │ ├── edit-map-dialog.tsx │ │ ├── map-dialog │ │ │ ├── coordinate-x-input.tsx │ │ │ ├── coordinate-y-input.tsx │ │ │ ├── field-error.tsx │ │ │ ├── image-drop-zone.tsx │ │ │ ├── lower-radar-input.tsx │ │ │ ├── map-form-dialog.tsx │ │ │ ├── map-form-provider.tsx │ │ │ ├── name-input.tsx │ │ │ ├── radar-input.tsx │ │ │ ├── scale-input.tsx │ │ │ ├── threshold-z-input.tsx │ │ │ ├── thumbnail-input.tsx │ │ │ ├── use-map-form-field.ts │ │ │ └── use-map-form.ts │ │ ├── map-entry.tsx │ │ ├── maps-settings.tsx │ │ ├── maps.tsx │ │ └── reset-default-maps-button.tsx │ ├── playback │ │ ├── cs2-highlights-warning.tsx │ │ ├── custom-highlights.tsx │ │ ├── custom-lowlights.tsx │ │ ├── game-fullscreen.tsx │ │ ├── game-height.tsx │ │ ├── game-width.tsx │ │ ├── highlights-include-damages.tsx │ │ ├── highlights-watch-after-kill-delay.tsx │ │ ├── highlights-watch-before-kill-delay.tsx │ │ ├── launch-parameters.tsx │ │ ├── lowlights-include-damages.tsx │ │ ├── lowlights-watch-after-kill-delay.tsx │ │ ├── lowlights-watch-before-kill-delay.tsx │ │ ├── playback-settings.tsx │ │ ├── player-voices.tsx │ │ ├── use-hlae.tsx │ │ ├── use-watch-settings.ts │ │ ├── watch-before-kill-delay.tsx │ │ ├── watch-round-after-delay.tsx │ │ └── watch-round-before-delay.tsx │ ├── settings-actions.ts │ ├── settings-category-button.tsx │ ├── settings-category.ts │ ├── settings-entry.tsx │ ├── settings-overlay-provider.tsx │ ├── settings-overlay.tsx │ ├── settings-reducer.ts │ ├── settings-tabs.tsx │ ├── settings-view.tsx │ ├── settings.tsx │ ├── shared │ │ ├── game-height-input.tsx │ │ └── game-width-input.tsx │ ├── tags │ │ ├── add-tag.tsx │ │ ├── tag-entry.tsx │ │ ├── tags-settings.tsx │ │ └── use-get-tag-error-message-from-error.ts │ ├── ui │ │ ├── initial-page-select.tsx │ │ ├── language-select.tsx │ │ ├── redirect-demo-to-match.tsx │ │ ├── reset-tables-state.tsx │ │ ├── system-startup-behavior.tsx │ │ ├── theme-select.tsx │ │ ├── ui-settings.tsx │ │ ├── use-locale.ts │ │ ├── use-theme-name.ts │ │ └── use-ui-settings.ts │ ├── use-demos-settings.ts │ ├── use-matches-settings.ts │ ├── use-pinned-player-steamid.ts │ ├── use-player-profile-settings.ts │ ├── use-players-settings.ts │ ├── use-settings-overlay.ts │ ├── use-settings.ts │ ├── use-team-profile-settings.ts │ ├── use-teams-settings.ts │ ├── use-update-settings.ts │ └── video │ │ ├── ffmpeg │ │ ├── ffmpeg-location.tsx │ │ └── use-ffmpeg-settings.ts │ │ ├── hlae │ │ ├── hlae-config-folder-path.tsx │ │ ├── hlae-location.tsx │ │ └── use-hlae-settings.ts │ │ ├── recording │ │ ├── default-video-recording-settings.tsx │ │ ├── recording-death-notices-duration.tsx │ │ ├── recording-game-height.tsx │ │ ├── recording-game-width.tsx │ │ ├── recording-player-voices.tsx │ │ ├── recording-show-only-death-notices.tsx │ │ └── recording-x-ray.tsx │ │ ├── use-video-settings.ts │ │ └── video-settings.tsx │ ├── shared │ ├── build-player-steam-profile-url.ts │ ├── colors.ts │ ├── element-ids.ts │ ├── format-milliseconds-to-timer.ts │ ├── get-css-variable-value.ts │ ├── get-premier-rank-tier.ts │ ├── heatmap-renderer.ts │ ├── inert.ts │ ├── load-image-from-file-path.ts │ └── supported-demo-sources.ts │ ├── store │ ├── reducers.ts │ ├── store.ts │ ├── use-dispatch.ts │ └── use-selector.ts │ ├── styles │ ├── InterVariable.woff2 │ ├── base.css │ ├── fonts.css │ ├── get-player-color-border-class-name.ts │ ├── get-team-color.ts │ ├── get-team-score-class-name.ts │ ├── milkdown.css │ ├── react-day-picker.css │ ├── third-parties.css │ ├── utilities.css │ └── variables.css │ ├── tags │ ├── tags-actions.ts │ ├── tags-reducer.ts │ └── use-tags.ts │ ├── team │ ├── economy │ │ └── teams-round-outcomes-by-economy-type-chart.tsx │ ├── heatmap │ │ ├── team-heatmap-actions.ts │ │ ├── team-heatmap-filters.tsx │ │ ├── team-heatmap.tsx │ │ └── use-heatmap-state.ts │ ├── load-team-error.tsx │ ├── maps │ │ └── team-maps.tsx │ ├── matches │ │ ├── team-delete-matches-dialog.tsx │ │ ├── team-match-context-menu.tsx │ │ ├── team-matches-table.tsx │ │ └── use-selected-match-checksums.ts │ ├── overview │ │ ├── team-clutches.tsx │ │ ├── team-last-matches.tsx │ │ ├── team-multi-kills-panel.tsx │ │ ├── team-objectives-panel.tsx │ │ ├── team-overview.tsx │ │ └── team-win-rate-panel.tsx │ ├── performance │ │ ├── bombs │ │ │ ├── team-bomb-plant-chart.tsx │ │ │ ├── team-bomb-round-outcome-chart.tsx │ │ │ └── team-bombs-stats.tsx │ │ ├── side │ │ │ ├── team-match-result-ct-chart.tsx │ │ │ ├── team-match-result-terro-chart.tsx │ │ │ ├── team-side-match-stats.tsx │ │ │ └── team-side-stats.tsx │ │ ├── team-chart-panel.tsx │ │ └── team-performance.tsx │ ├── team-action-bar.tsx │ ├── team-actions.ts │ ├── team-filter-dropdown.tsx │ ├── team-loader.tsx │ ├── team-name.tsx │ ├── team-reducer.ts │ ├── team-tabs.tsx │ ├── team.tsx │ ├── use-active-team-filters.ts │ ├── use-current-team-name.ts │ ├── use-fetch-team.ts │ ├── use-team-state.ts │ ├── use-team.ts │ └── use-unsafe-team.ts │ ├── teams │ ├── action-bar │ │ ├── fuzzy-search-text-input.tsx │ │ ├── refresh-teams-button.tsx │ │ ├── team-details-button.tsx │ │ ├── teams-columns-visibility.tsx │ │ └── teams-filter-dropdown.tsx │ ├── no-teams.tsx │ ├── table │ │ ├── selected-team-count.tsx │ │ ├── team-context-menu.tsx │ │ ├── team-count.tsx │ │ ├── teams-table-context.ts │ │ ├── teams-table-provider.tsx │ │ ├── teams-table-status-bar.tsx │ │ ├── use-teams-columns.ts │ │ └── use-teams-table.ts │ ├── teams-action-bar.tsx │ ├── teams-actions.ts │ ├── teams-reducer.ts │ ├── teams-table.tsx │ ├── teams.tsx │ ├── use-active-teams-filters.ts │ ├── use-fetch-teams.ts │ ├── use-fuzzy-search-text.ts │ ├── use-selected-team-names.ts │ ├── use-teams-state.ts │ ├── use-teams-status.ts │ └── use-teams.ts │ ├── title-bar │ ├── history │ │ ├── history-back-button.tsx │ │ ├── history-button.tsx │ │ ├── history-forward-button.tsx │ │ └── history-navigation.tsx │ ├── menu-button.tsx │ ├── title-bar.tsx │ ├── update-available-button.tsx │ └── window-controls │ │ ├── close-control.tsx │ │ ├── close-icon.tsx │ │ ├── control.tsx │ │ ├── maximize-control.tsx │ │ ├── maximize-icon.tsx │ │ ├── minimize-control.tsx │ │ ├── minimize-icon.tsx │ │ ├── unmaximize-icon.tsx │ │ └── window-controls.tsx │ ├── translations │ ├── de │ │ └── messages.po │ ├── en │ │ └── messages.po │ ├── es │ │ └── messages.po │ ├── fr │ │ └── messages.po │ ├── pt-BR │ │ └── messages.po │ ├── zh-CN │ │ └── messages.po │ └── zh-TW │ │ └── messages.po │ ├── videos │ ├── remove-all-videos-button.tsx │ ├── remove-completed-videos-button.tsx │ ├── resume-or-pause-video-queue-button.tsx │ ├── use-is-video-queue-paused.ts │ ├── use-remove-videos.tsx │ ├── use-videos-state.ts │ ├── use-videos.ts │ ├── video-entry.tsx │ ├── videos-actions.ts │ ├── videos-reducer.ts │ └── videos.tsx │ ├── web-socket-client.ts │ └── xlsx │ └── xlsx-sheet-translations.ts ├── static ├── csdm.dll ├── csdm.dylib ├── csdm.vdf ├── csdm_client.so ├── images │ ├── avatar.jpg │ ├── grenades │ │ ├── decoy-detonate.png │ │ ├── flashbang-detonate.png │ │ ├── he-detonate.png │ │ ├── molotov-detonate.png │ │ ├── smoke-detonate.png │ │ └── unknown-grenade.png │ ├── maps │ │ ├── cs2 │ │ │ ├── radars │ │ │ │ ├── cs_agency.png │ │ │ │ ├── cs_assault.png │ │ │ │ ├── cs_italy.png │ │ │ │ ├── cs_militia.png │ │ │ │ ├── cs_militia_lower.png │ │ │ │ ├── cs_office.png │ │ │ │ ├── de_ancient.png │ │ │ │ ├── de_anubis.png │ │ │ │ ├── de_assembly.png │ │ │ │ ├── de_aztec.png │ │ │ │ ├── de_basalt.png │ │ │ │ ├── de_brewery.png │ │ │ │ ├── de_cache.png │ │ │ │ ├── de_canals.png │ │ │ │ ├── de_cbble.png │ │ │ │ ├── de_dogtown.png │ │ │ │ ├── de_dust.png │ │ │ │ ├── de_dust2.png │ │ │ │ ├── de_edin.png │ │ │ │ ├── de_grail.png │ │ │ │ ├── de_inferno.png │ │ │ │ ├── de_jura.png │ │ │ │ ├── de_memento.png │ │ │ │ ├── de_mills.png │ │ │ │ ├── de_mirage.png │ │ │ │ ├── de_nuke.png │ │ │ │ ├── de_nuke_lower.png │ │ │ │ ├── de_overpass.png │ │ │ │ ├── de_palais.png │ │ │ │ ├── de_palais_lower.png │ │ │ │ ├── de_thera.png │ │ │ │ ├── de_thera_lower.png │ │ │ │ ├── de_train.png │ │ │ │ ├── de_train_lower.png │ │ │ │ ├── de_vertigo.png │ │ │ │ ├── de_vertigo_lower.png │ │ │ │ └── de_whistle.png │ │ │ └── thumbnails │ │ │ │ ├── cs_agency.png │ │ │ │ ├── cs_assault.png │ │ │ │ ├── cs_italy.png │ │ │ │ ├── cs_militia.png │ │ │ │ ├── cs_office.png │ │ │ │ ├── de_ancient.png │ │ │ │ ├── de_anubis.png │ │ │ │ ├── de_assembly.png │ │ │ │ ├── de_aztec.png │ │ │ │ ├── de_basalt.png │ │ │ │ ├── de_brewery.png │ │ │ │ ├── de_cache.png │ │ │ │ ├── de_canals.png │ │ │ │ ├── de_cbble.png │ │ │ │ ├── de_dogtown.png │ │ │ │ ├── de_dust.png │ │ │ │ ├── de_dust2.png │ │ │ │ ├── de_edin.png │ │ │ │ ├── de_grail.png │ │ │ │ ├── de_inferno.png │ │ │ │ ├── de_jura.png │ │ │ │ ├── de_memento.png │ │ │ │ ├── de_mills.png │ │ │ │ ├── de_mirage.png │ │ │ │ ├── de_nuke.png │ │ │ │ ├── de_overpass.png │ │ │ │ ├── de_palais.png │ │ │ │ ├── de_thera.png │ │ │ │ ├── de_train.png │ │ │ │ ├── de_vertigo.png │ │ │ │ └── de_whistle.png │ │ ├── csgo │ │ │ ├── radars │ │ │ │ ├── cs_assault.png │ │ │ │ ├── cs_italy.png │ │ │ │ ├── cs_militia.png │ │ │ │ ├── cs_militia_lower.png │ │ │ │ ├── cs_office.png │ │ │ │ ├── de_ancient.png │ │ │ │ ├── de_anubis.png │ │ │ │ ├── de_aztec.png │ │ │ │ ├── de_cache.png │ │ │ │ ├── de_canals.png │ │ │ │ ├── de_cbble.png │ │ │ │ ├── de_dust.png │ │ │ │ ├── de_dust2.png │ │ │ │ ├── de_inferno.png │ │ │ │ ├── de_mirage.png │ │ │ │ ├── de_nuke.png │ │ │ │ ├── de_nuke_lower.png │ │ │ │ ├── de_overpass.png │ │ │ │ ├── de_train.png │ │ │ │ ├── de_vertigo.png │ │ │ │ └── de_vertigo_lower.png │ │ │ └── thumbnails │ │ │ │ ├── cs_assault.png │ │ │ │ ├── cs_italy.png │ │ │ │ ├── cs_militia.png │ │ │ │ ├── cs_office.png │ │ │ │ ├── de_ancient.png │ │ │ │ ├── de_anubis.png │ │ │ │ ├── de_aztec.png │ │ │ │ ├── de_cache.png │ │ │ │ ├── de_canals.png │ │ │ │ ├── de_cbble.png │ │ │ │ ├── de_dust.png │ │ │ │ ├── de_dust2.png │ │ │ │ ├── de_inferno.png │ │ │ │ ├── de_mirage.png │ │ │ │ ├── de_nuke.png │ │ │ │ ├── de_overpass.png │ │ │ │ ├── de_train.png │ │ │ │ └── de_vertigo.png │ │ └── thumbnail_unknown.png │ ├── ranks │ │ ├── competitive │ │ │ ├── 0.png │ │ │ ├── 1.png │ │ │ ├── 10.png │ │ │ ├── 11.png │ │ │ ├── 12.png │ │ │ ├── 13.png │ │ │ ├── 14.png │ │ │ ├── 15.png │ │ │ ├── 16.png │ │ │ ├── 17.png │ │ │ ├── 18.png │ │ │ ├── 2.png │ │ │ ├── 3.png │ │ │ ├── 4.png │ │ │ ├── 5.png │ │ │ ├── 6.png │ │ │ ├── 7.png │ │ │ ├── 8.png │ │ │ └── 9.png │ │ └── premier │ │ │ ├── tier-0.png │ │ │ ├── tier-1.png │ │ │ ├── tier-2.png │ │ │ ├── tier-3.png │ │ │ ├── tier-4.png │ │ │ ├── tier-5.png │ │ │ └── tier-6.png │ ├── sources │ │ ├── 5eplay.png │ │ ├── cevo-back.png │ │ ├── cevo-white.png │ │ ├── challengermode.png │ │ ├── ebot.png │ │ ├── esea-black.png │ │ ├── esea-white.png │ │ ├── esl-black.png │ │ ├── esl-white.png │ │ ├── esplay.png │ │ ├── esportal-black.png │ │ ├── esportal-white.png │ │ ├── faceit-black.png │ │ ├── faceit-white.png │ │ ├── fastcup-black.png │ │ ├── fastcup-white.png │ │ ├── gamersclub-black.png │ │ ├── gamersclub-white.png │ │ ├── matchzy.png │ │ ├── perfectworld-black.png │ │ ├── perfectworld-white.png │ │ ├── popflash-black.png │ │ ├── popflash-white.png │ │ ├── renown-black.png │ │ ├── renown-white.png │ │ ├── unknown.png │ │ ├── valve-black.png │ │ └── valve-white.png │ └── tray │ │ ├── tray.ico │ │ ├── tray.png │ │ ├── tray@2x.png │ │ ├── trayTemplate.png │ │ └── trayTemplate@2x.png ├── libserver.so └── server.dll ├── test.sql ├── tsconfig.json ├── types ├── ambient.d.ts ├── css.d.ts ├── deep-partial.d.ts ├── github.d.ts ├── global.d.ts ├── image.d.ts ├── paths.d.ts ├── po.d.ts ├── process.d.ts ├── window-preload.d.ts └── window.d.ts └── vite.config.mts /.env.example: -------------------------------------------------------------------------------- 1 | LOG_DATABASE_QUERIES=false 2 | STEAM_API_KEYS=KEY_1,KEY_2 3 | FACEIT_API_KEY=FACEIT_API_KEY_GOES_HERE 4 | REACT_STRICT_MODE_ENABLED=false 5 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: akiver 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Question 4 | url: https://github.com/akiver/cs-demo-manager/discussions 5 | about: Ask and answer questions here 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | thumbs.db 4 | dist 5 | out 6 | .env 7 | *.dem 8 | *.vdm 9 | *.pdb 10 | *.exp 11 | *.lib 12 | linter/*.js 13 | static/*.exe 14 | static/csda 15 | static/boiler-writter 16 | static/csgove 17 | static/changelog 18 | build 19 | !build/Release/*.node 20 | -------------------------------------------------------------------------------- /.node-version: -------------------------------------------------------------------------------- 1 | 22 -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | legacy-peer-deps=true -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode", "bradlc.vscode-tailwindcss"] 3 | } 4 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "typescript.tsdk": "node_modules/typescript/lib", 3 | "files.associations": { 4 | "*.css": "tailwindcss" 5 | }, 6 | "tailwindCSS.rootFontSize": 14, 7 | "search.exclude": { 8 | "cs2-server-plugin/cs2-server-plugin/deps": true, 9 | "csgo-server-plugin/csgo-server-plugin/deps": true 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /build-assets/bin/csdm.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | set ELECTRON_RUN_AS_NODE=1 4 | "%~dp0\cs-demo-manager.exe" "%~dp0\resources\app.asar\cli.js" %* 5 | endlocal 6 | -------------------------------------------------------------------------------- /build-assets/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/build-assets/icon.icns -------------------------------------------------------------------------------- /build-assets/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/build-assets/icon.ico -------------------------------------------------------------------------------- /build-assets/x86-unicode/EnVar.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/build-assets/x86-unicode/EnVar.dll -------------------------------------------------------------------------------- /cs2-server-plugin/.gitignore: -------------------------------------------------------------------------------- 1 | .vs 2 | *.user 3 | Debug/ 4 | Release/ 5 | *.dll 6 | -------------------------------------------------------------------------------- /cs2-server-plugin/README.md: -------------------------------------------------------------------------------- 1 | [Documentation](https://cs-demo-manager.com/docs/development/cs-server-plugin) -------------------------------------------------------------------------------- /csgo-server-plugin/.gitignore: -------------------------------------------------------------------------------- 1 | .vs 2 | *.user 3 | Debug/ 4 | Release/ 5 | *.dll 6 | -------------------------------------------------------------------------------- /csgo-server-plugin/README.md: -------------------------------------------------------------------------------- 1 | [Documentation](https://cs-demo-manager.com/docs/development/cs-server-plugin) -------------------------------------------------------------------------------- /docker/.env.example: -------------------------------------------------------------------------------- 1 | POSTGRES_DB=csdm_dev 2 | POSTGRES_PASSWORD=password 3 | POSTGRES_PORT=5432 4 | -------------------------------------------------------------------------------- /docker/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | db: 3 | image: postgres:17 4 | restart: always 5 | container_name: csdm-postgresql 6 | environment: 7 | POSTGRES_DB: ${POSTGRES_DB:-csdm_dev} 8 | POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-password} 9 | ports: 10 | - '${POSTGRES_PORT:-5432}:5432' 11 | -------------------------------------------------------------------------------- /docker/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | docker compose -f docker-compose.yml -p csdm up -d 4 | -------------------------------------------------------------------------------- /docker/stop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | docker compose -f docker-compose.yml stop 4 | -------------------------------------------------------------------------------- /eslint-local-rules.js: -------------------------------------------------------------------------------- 1 | const { rule: noReactReduxImport } = require('./linter/no-react-redux-import'); 2 | const { rule: linguiJsUsage } = require('./linter/lingui-js-usage'); 3 | 4 | module.exports = { 5 | 'no-react-redux-import': noReactReduxImport, 6 | 'lingui-js-usage': linguiJsUsage, 7 | }; 8 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | '@tailwindcss/postcss': {}, 4 | }, 5 | }; 6 | -------------------------------------------------------------------------------- /prettier.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import("prettier").Config} */ 2 | const config = { 3 | singleQuote: true, 4 | printWidth: 120, 5 | overrides: [ 6 | { 7 | files: '*.svg', 8 | options: { 9 | parser: 'html', 10 | }, 11 | }, 12 | ], 13 | }; 14 | 15 | export default config; 16 | -------------------------------------------------------------------------------- /preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/preview.png -------------------------------------------------------------------------------- /scripts/cli.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | 4 | for %%A in ("%~dp0.") do set PROJECT_PATH=%%~dpA 5 | set PROJECT_PATH=%PROJECT_PATH:~0,-1% 6 | 7 | set ELECTRON="%PROJECT_PATH%\node_modules\electron\dist\electron.exe" 8 | 9 | set ELECTRON_RUN_AS_NODE=1 10 | 11 | %ELECTRON% out\cli.js %* 12 | 13 | endlocal -------------------------------------------------------------------------------- /scripts/cli.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | PROJECT_PATH=$(dirname $(dirname $(readlink -f $0))) 4 | ELECTRON="$PROJECT_PATH/node_modules/electron/dist/electron" 5 | CLI="$PROJECT_PATH/out/cli.js" 6 | ELECTRON_RUN_AS_NODE=1 "$ELECTRON" "$CLI" "$@" 7 | exit $? -------------------------------------------------------------------------------- /scripts/electron-vendors.mjs: -------------------------------------------------------------------------------- 1 | // ! These values must be updated when upgrading Electron, they are available from process.versions. 2 | export const chrome = '136'; 3 | export const node = '22'; 4 | -------------------------------------------------------------------------------- /scripts/postinstall.mjs: -------------------------------------------------------------------------------- 1 | import { installDemoAnalyzer, installCounterStrikeVoiceExtractor, installBoilerWritter } from './install-deps.mjs'; 2 | 3 | await Promise.all([installDemoAnalyzer(), installCounterStrikeVoiceExtractor(), installBoilerWritter()]); 4 | -------------------------------------------------------------------------------- /src/common/argument/argument-name.ts: -------------------------------------------------------------------------------- 1 | export const ArgumentName = { 2 | StartPath: 'start-path', 3 | DemoPath: 'demo-path', 4 | AppOpenedAtLogin: 'app-opened-at-login', // Used to know when the app was opened automatically by the system at login 5 | } as const; 6 | 7 | export type ArgumentName = (typeof ArgumentName)[keyof typeof ArgumentName]; 8 | -------------------------------------------------------------------------------- /src/common/argument/start-path.ts: -------------------------------------------------------------------------------- 1 | export const StartPath = { 2 | Players: 'players', 3 | Bans: 'bans', 4 | Downloads: 'downloads', 5 | Settings: 'settings', 6 | } as const; 7 | export type StartPath = (typeof StartPath)[keyof typeof StartPath]; 8 | -------------------------------------------------------------------------------- /src/common/array/are-arrays-values-the-same.ts: -------------------------------------------------------------------------------- 1 | export function areArraysValuesTheSame(a: unknown[], b: unknown[]) { 2 | if (a.length !== b.length) { 3 | return false; 4 | } 5 | 6 | const difference = a.filter((value) => { 7 | return !b.includes(value); 8 | }); 9 | 10 | return difference.length === 0; 11 | } 12 | -------------------------------------------------------------------------------- /src/common/array/unique-array.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Return the unique values found in the passed array. 3 | */ 4 | export function uniqueArray(values: Array) { 5 | return [...new Set(values)]; 6 | } 7 | -------------------------------------------------------------------------------- /src/common/assert-never.ts: -------------------------------------------------------------------------------- 1 | export function assertNever(value: never, message: string): never { 2 | throw new Error(message); 3 | } 4 | -------------------------------------------------------------------------------- /src/common/assert-soft-never.ts: -------------------------------------------------------------------------------- 1 | export function assertSoftNever(shouldBeNever: never, fallback: unknown): never { 2 | return fallback as never; 3 | } 4 | -------------------------------------------------------------------------------- /src/common/date/add-date-days.ts: -------------------------------------------------------------------------------- 1 | export function addDateDays(date: Date, days: number) { 2 | const newDate = new Date(); 3 | newDate.setDate(date.getDate() + days); 4 | 5 | return newDate; 6 | } 7 | -------------------------------------------------------------------------------- /src/common/date/date-range.ts: -------------------------------------------------------------------------------- 1 | export type DateRange = { 2 | from: Date | undefined; 3 | to?: Date | undefined; 4 | }; 5 | 6 | export function formatDate(date: Date | undefined): string | undefined { 7 | return date?.toLocaleDateString('fr-CA'); 8 | } 9 | -------------------------------------------------------------------------------- /src/common/date/date-to-unix-timestamp.ts: -------------------------------------------------------------------------------- 1 | export function dateToUnixTimestamp(date: Date) { 2 | return Number.parseInt((date.getTime() / 1000).toFixed(0)); 3 | } 4 | -------------------------------------------------------------------------------- /src/common/date/get-date-days-ago.ts: -------------------------------------------------------------------------------- 1 | export function getDateDaysAgo(days: number) { 2 | const date = new Date(); 3 | date.setDate(date.getDate() - days); 4 | 5 | return date; 6 | } 7 | -------------------------------------------------------------------------------- /src/common/date/get-date-first-day.ts: -------------------------------------------------------------------------------- 1 | export function getDateFirstDay(date: Date) { 2 | return new Date(date.getFullYear(), date.getMonth(), 1); 3 | } 4 | -------------------------------------------------------------------------------- /src/common/date/get-date-first-month.ts: -------------------------------------------------------------------------------- 1 | export function getDateFirstMonth(date: Date) { 2 | return new Date(date.getFullYear(), 0, 1); 3 | } 4 | -------------------------------------------------------------------------------- /src/common/date/get-date-timestamp-at-midnight.ts: -------------------------------------------------------------------------------- 1 | export function getDateTimestampAtMidnight(date: Date) { 2 | return Number.parseInt((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() / 1000).toFixed(0)); 3 | } 4 | -------------------------------------------------------------------------------- /src/common/date/subtract-date-days.ts: -------------------------------------------------------------------------------- 1 | export function subtractDateDays(date: Date, days: number) { 2 | const newDate = new Date(); 3 | newDate.setDate(date.getDate() - days); 4 | 5 | return newDate; 6 | } 7 | -------------------------------------------------------------------------------- /src/common/date/unix-timestamp-to-date.ts: -------------------------------------------------------------------------------- 1 | export function unixTimestampToDate(timesteamp: number) { 2 | return new Date(timesteamp * 1000); 3 | } 4 | -------------------------------------------------------------------------------- /src/common/is-error-code.ts: -------------------------------------------------------------------------------- 1 | import { ErrorCode } from './error-code'; 2 | 3 | export function isErrorCode(error: unknown): error is ErrorCode { 4 | return typeof error === 'number' && Object.values(ErrorCode).includes(error as ErrorCode); 5 | } 6 | -------------------------------------------------------------------------------- /src/common/math/round-number-percentage.ts: -------------------------------------------------------------------------------- 1 | import { roundNumber } from './round-number'; 2 | 3 | export function roundNumberPercentage(number: number, places?: number) { 4 | if (Number.isNaN(number)) { 5 | return 0; 6 | } 7 | 8 | return roundNumber(number * 100, places); 9 | } 10 | -------------------------------------------------------------------------------- /src/common/sleep.ts: -------------------------------------------------------------------------------- 1 | export function sleep(ms: number) { 2 | return new Promise((resolve) => { 3 | return setTimeout(resolve, ms); 4 | }); 5 | } 6 | -------------------------------------------------------------------------------- /src/common/string/is-empty-string.ts: -------------------------------------------------------------------------------- 1 | export function isEmptyString(value: string) { 2 | return !/\S/.test(value); 3 | } 4 | -------------------------------------------------------------------------------- /src/common/string/path-contains-invalid-csgo-chars.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * If a path contains unsupported CSGO chars, the playback will not start and the game will be stuck on the home screen. 3 | * CS2 is not affected by this issue. 4 | */ 5 | export function pathContainsInvalidCsgoChars(path: string) { 6 | return /[&;@^]/g.test(path); 7 | } 8 | -------------------------------------------------------------------------------- /src/common/string/string-contains-only-basic-latin-chars.ts: -------------------------------------------------------------------------------- 1 | export function stringContainsOnlyBasicLatinChars(str: string) { 2 | // eslint-disable-next-line no-control-regex 3 | return /^[\x00-\x7F]*$/.test(str); 4 | } 5 | -------------------------------------------------------------------------------- /src/common/types/5eplay-account.ts: -------------------------------------------------------------------------------- 1 | export type FiveEPlayAccount = { 2 | id: string; 3 | domainId: string; 4 | nickname: string; 5 | avatarUrl: string; 6 | isCurrent: boolean; 7 | }; 8 | -------------------------------------------------------------------------------- /src/common/types/argument.ts: -------------------------------------------------------------------------------- 1 | import type { ArgumentName } from '../argument/argument-name'; 2 | 3 | export type Argument = { 4 | name: ArgumentName; 5 | value: string; 6 | }; 7 | -------------------------------------------------------------------------------- /src/common/types/ban-filter.ts: -------------------------------------------------------------------------------- 1 | export const BanFilter = { 2 | None: 'none', 3 | VacBanned: 'vacBanned', 4 | GameBanned: 'gameBanned', 5 | CommunityBanned: 'communityBanned', 6 | } as const; 7 | 8 | export type BanFilter = (typeof BanFilter)[keyof typeof BanFilter]; 9 | -------------------------------------------------------------------------------- /src/common/types/banned-steam-account.ts: -------------------------------------------------------------------------------- 1 | import type { Rank } from 'csdm/common/types/counter-strike'; 2 | 3 | export type BannedSteamAccount = { 4 | steamId: string; 5 | name: string; 6 | avatar: string; 7 | lastBanDate: string; 8 | rank: Rank; 9 | }; 10 | -------------------------------------------------------------------------------- /src/common/types/base-event.ts: -------------------------------------------------------------------------------- 1 | import type { ColumnID } from 'csdm/common/types/column-id'; 2 | 3 | export type BaseEvent = { 4 | id: ColumnID; 5 | matchChecksum: string; 6 | tick: number; 7 | frame: number; 8 | roundNumber: number; 9 | }; 10 | -------------------------------------------------------------------------------- /src/common/types/bomb-defuse-start.ts: -------------------------------------------------------------------------------- 1 | import type { BaseEvent } from './base-event'; 2 | 3 | export type BombDefuseStart = BaseEvent & { 4 | x: number; 5 | y: number; 6 | z: number; 7 | defuserSteamId: string; 8 | defuserName: string; 9 | isDefuserControllingBot: boolean; 10 | }; 11 | -------------------------------------------------------------------------------- /src/common/types/bomb-exploded.ts: -------------------------------------------------------------------------------- 1 | import type { BaseEvent } from 'csdm/common/types/base-event'; 2 | 3 | export type BombExploded = BaseEvent & { 4 | x: number; 5 | y: number; 6 | z: number; 7 | site: string; 8 | planterSteamId: string; 9 | planterName: string; 10 | isPlanterControllingBot: boolean; 11 | }; 12 | -------------------------------------------------------------------------------- /src/common/types/bomb-plant-start.ts: -------------------------------------------------------------------------------- 1 | import type { BaseEvent } from 'csdm/common/types/base-event'; 2 | 3 | export type BombPlantStart = BaseEvent & { 4 | x: number; 5 | y: number; 6 | z: number; 7 | site: string; 8 | planterSteamId: string; 9 | planterName: string; 10 | isPlanterControllingBot: boolean; 11 | }; 12 | -------------------------------------------------------------------------------- /src/common/types/bomb-planted.ts: -------------------------------------------------------------------------------- 1 | import type { BaseEvent } from 'csdm/common/types/base-event'; 2 | 3 | export type BombPlanted = BaseEvent & { 4 | site: string; 5 | planterSteamId: string; 6 | planterName: string; 7 | isPlanterControllingBot: boolean; 8 | x: number; 9 | y: number; 10 | z: number; 11 | }; 12 | -------------------------------------------------------------------------------- /src/common/types/camera-focus.ts: -------------------------------------------------------------------------------- 1 | export type CameraFocus = { 2 | tick: number; 3 | playerSteamId: string; 4 | playerName: string; 5 | }; 6 | -------------------------------------------------------------------------------- /src/common/types/charts/competitive-rank-history.ts: -------------------------------------------------------------------------------- 1 | import type { CompetitiveRank } from 'csdm/common/types/counter-strike'; 2 | 3 | export type CompetitiveRankHistory = { 4 | matchDate: string; 5 | oldRank: CompetitiveRank; 6 | rank: CompetitiveRank; 7 | winCount: number; 8 | }; 9 | -------------------------------------------------------------------------------- /src/common/types/charts/player-charts-data.ts: -------------------------------------------------------------------------------- 1 | export type PlayerChartsData = { 2 | headshotPercentage: number; 3 | killDeathRatio: number; 4 | averageDamagePerRound: number; 5 | clutchWonPercentage: number; 6 | matchDate: string; 7 | }; 8 | 9 | export type PlayerChartDataField = keyof Omit; 10 | -------------------------------------------------------------------------------- /src/common/types/charts/premier-rank-history.ts: -------------------------------------------------------------------------------- 1 | import type { PremierRank } from 'csdm/common/types/counter-strike'; 2 | 3 | export type PremierRankHistory = { 4 | matchDate: string; 5 | rank: PremierRank; 6 | winCount: number; 7 | }; 8 | -------------------------------------------------------------------------------- /src/common/types/chicken-death.ts: -------------------------------------------------------------------------------- 1 | import type { ColumnID } from 'csdm/common/types/column-id'; 2 | 3 | export type ChickenDeath = { 4 | id: ColumnID; 5 | matchChecksum: string; 6 | tick: number; 7 | frame: number; 8 | roundNumber: number; 9 | weaponName: string; 10 | killerSteamId: string; 11 | }; 12 | -------------------------------------------------------------------------------- /src/common/types/chicken-position.ts: -------------------------------------------------------------------------------- 1 | import type { BaseEvent } from 'csdm/common/types/base-event'; 2 | 3 | export type ChickenPosition = BaseEvent & { 4 | x: number; 5 | y: number; 6 | z: number; 7 | }; 8 | -------------------------------------------------------------------------------- /src/common/types/column-id.ts: -------------------------------------------------------------------------------- 1 | // Type for the primary key column ID of tables (int8/BIGSERIAL Postgres type). 2 | // It may be a string if the value is too big to be represented as a safe JS number, see database.ts for details. 3 | export type ColumnID = number | string; 4 | -------------------------------------------------------------------------------- /src/common/types/encoder-software.ts: -------------------------------------------------------------------------------- 1 | export const EncoderSoftware = { 2 | VirtualDub: 'VirtualDub', 3 | FFmpeg: 'FFmpeg', 4 | } as const; 5 | 6 | export type EncoderSoftware = (typeof EncoderSoftware)[keyof typeof EncoderSoftware]; 7 | -------------------------------------------------------------------------------- /src/common/types/faceit-account.ts: -------------------------------------------------------------------------------- 1 | export type FaceitAccount = { 2 | id: string; 3 | nickname: string; 4 | avatarUrl: string; 5 | isCurrent: boolean; 6 | }; 7 | -------------------------------------------------------------------------------- /src/common/types/hostage-pick-up-start.ts: -------------------------------------------------------------------------------- 1 | import type { BaseEvent } from 'csdm/common/types/base-event'; 2 | 3 | export type HostagePickUpStart = BaseEvent & { 4 | x: number; 5 | y: number; 6 | z: number; 7 | playerSteamId: string; 8 | isPlayerControllingBot: boolean; 9 | hostageEntityId: number; 10 | }; 11 | -------------------------------------------------------------------------------- /src/common/types/hostage-picked-up.ts: -------------------------------------------------------------------------------- 1 | import type { BaseEvent } from 'csdm/common/types/base-event'; 2 | 3 | export type HostagePickedUp = BaseEvent & { 4 | x: number; 5 | y: number; 6 | z: number; 7 | hostageEntityId: number; 8 | playerSteamId: string; 9 | isPlayerControllingBot: boolean; 10 | }; 11 | -------------------------------------------------------------------------------- /src/common/types/hostage-position.ts: -------------------------------------------------------------------------------- 1 | import type { HostageState } from 'csdm/common/types/counter-strike'; 2 | import type { BaseEvent } from 'csdm/common/types/base-event'; 3 | 4 | export type HostagePosition = BaseEvent & { 5 | x: number; 6 | y: number; 7 | z: number; 8 | state: HostageState; 9 | }; 10 | -------------------------------------------------------------------------------- /src/common/types/ignored-steam-account.ts: -------------------------------------------------------------------------------- 1 | export type IgnoredSteamAccount = { 2 | steamId: string; 3 | name: string; 4 | avatar: string; 5 | lastBanDate: string | null; 6 | }; 7 | -------------------------------------------------------------------------------- /src/common/types/inferno-position.ts: -------------------------------------------------------------------------------- 1 | import type { BaseEvent } from 'csdm/common/types/base-event'; 2 | 3 | export type InfernoPosition = BaseEvent & { 4 | x: number; 5 | y: number; 6 | z: number; 7 | throwerSteamId: string; 8 | uniqueId: string; 9 | convexHell2D: number[]; 10 | }; 11 | -------------------------------------------------------------------------------- /src/common/types/last-match.ts: -------------------------------------------------------------------------------- 1 | import type { Game } from 'csdm/common/types/counter-strike'; 2 | 3 | export type LastMatch = { 4 | checksum: string; 5 | game: Game; 6 | date: string; 7 | scoreTeamA: number; 8 | scoreTeamB: number; 9 | mapName: string; 10 | winnerName: string; 11 | focusTeamName: string; 12 | }; 13 | -------------------------------------------------------------------------------- /src/common/types/opening-duel-result.ts: -------------------------------------------------------------------------------- 1 | export const OpeningDuelResult = { 2 | Won: 'won', 3 | Lost: 'lost', 4 | } as const; 5 | 6 | export type OpeningDuelResult = (typeof OpeningDuelResult)[keyof typeof OpeningDuelResult]; 7 | -------------------------------------------------------------------------------- /src/common/types/perspective.ts: -------------------------------------------------------------------------------- 1 | export const Perspective = { 2 | Player: 'player', 3 | Enemy: 'enemy', 4 | } as const; 5 | 6 | export type Perspective = (typeof Perspective)[keyof typeof Perspective]; 7 | -------------------------------------------------------------------------------- /src/common/types/player-watch-info.ts: -------------------------------------------------------------------------------- 1 | import type { TeamNumber } from './counter-strike'; 2 | 3 | export type PlayerWatchInfo = { 4 | steamId: string; 5 | slot: number; 6 | userId: number; 7 | side: TeamNumber; 8 | }; 9 | -------------------------------------------------------------------------------- /src/common/types/point.ts: -------------------------------------------------------------------------------- 1 | export type Point = { 2 | x: number; 3 | y: number; 4 | }; 5 | -------------------------------------------------------------------------------- /src/common/types/ranking-filter.ts: -------------------------------------------------------------------------------- 1 | export const RankingFilter = { 2 | All: 'all', 3 | Ranked: 'ranked', 4 | Unranked: 'unranked', 5 | } as const; 6 | 7 | export type RankingFilter = (typeof RankingFilter)[keyof typeof RankingFilter]; 8 | -------------------------------------------------------------------------------- /src/common/types/recording-output.ts: -------------------------------------------------------------------------------- 1 | export const RecordingOutput = { 2 | Images: 'images', 3 | ImagesAndVideo: 'images-and-video', 4 | Video: 'video', 5 | } as const; 6 | 7 | export type RecordingOutput = (typeof RecordingOutput)[keyof typeof RecordingOutput]; 8 | -------------------------------------------------------------------------------- /src/common/types/recording-system.ts: -------------------------------------------------------------------------------- 1 | export const RecordingSystem = { 2 | CounterStrike: 'CS', 3 | HLAE: 'HLAE', 4 | } as const; 5 | 6 | export type RecordingSystem = (typeof RecordingSystem)[keyof typeof RecordingSystem]; 7 | -------------------------------------------------------------------------------- /src/common/types/search/clutch-result.ts: -------------------------------------------------------------------------------- 1 | import type { Clutch } from '../clutch'; 2 | import type { Game } from '../counter-strike'; 3 | 4 | export type ClutchResult = Clutch & { 5 | game: Game; 6 | mapName: string; 7 | date: string; 8 | demoPath: string; 9 | }; 10 | -------------------------------------------------------------------------------- /src/common/types/search/kill-result.ts: -------------------------------------------------------------------------------- 1 | import type { Kill } from 'csdm/common/types/kill'; 2 | import type { Game } from '../counter-strike'; 3 | 4 | export type KillResult = Kill & { 5 | mapName: string; 6 | date: string; 7 | demoPath: string; 8 | game: Game; 9 | }; 10 | -------------------------------------------------------------------------------- /src/common/types/search/map-names-filter.ts: -------------------------------------------------------------------------------- 1 | export type MapNamesFilter = { 2 | name: string; 3 | ignoredNames: string[]; 4 | }; 5 | -------------------------------------------------------------------------------- /src/common/types/search/ninja-defuse-result.ts: -------------------------------------------------------------------------------- 1 | import type { BombDefused } from 'csdm/common/types/bomb-defused'; 2 | import type { Game } from '../counter-strike'; 3 | 4 | export type NinjaDefuseResult = BombDefused & { 5 | mapName: string; 6 | date: string; 7 | demoPath: string; 8 | game: Game; 9 | }; 10 | -------------------------------------------------------------------------------- /src/common/types/search/no-scope-kill-result.ts: -------------------------------------------------------------------------------- 1 | import type { Kill } from 'csdm/common/types/kill'; 2 | import type { Game } from '../counter-strike'; 3 | 4 | export type NoScopeKillResult = Kill & { 5 | mapName: string; 6 | date: string; 7 | demoPath: string; 8 | game: Game; 9 | }; 10 | -------------------------------------------------------------------------------- /src/common/types/search/player-result.ts: -------------------------------------------------------------------------------- 1 | export type PlayerResult = { 2 | steamId: string; 3 | name: string; 4 | }; 5 | -------------------------------------------------------------------------------- /src/common/types/search/players-filter.ts: -------------------------------------------------------------------------------- 1 | export type PlayersFilter = { 2 | steamIdOrName: string; 3 | ignoredSteamIds: string[]; 4 | }; 5 | -------------------------------------------------------------------------------- /src/common/types/search/round-result.ts: -------------------------------------------------------------------------------- 1 | import type { Round } from '../round'; 2 | import type { Game } from '../counter-strike'; 3 | 4 | export type RoundResult = Round & { 5 | mapName: string; 6 | date: string; 7 | demoPath: string; 8 | game: Game; 9 | }; 10 | -------------------------------------------------------------------------------- /src/common/types/search/through-smoke-kill-result.ts: -------------------------------------------------------------------------------- 1 | import type { Kill } from 'csdm/common/types/kill'; 2 | import type { Game } from '../counter-strike'; 3 | 4 | export type ThroughSmokeKillResult = Kill & { 5 | mapName: string; 6 | date: string; 7 | demoPath: string; 8 | game: Game; 9 | }; 10 | -------------------------------------------------------------------------------- /src/common/types/search/wallbang-kill-result.ts: -------------------------------------------------------------------------------- 1 | import type { Kill } from 'csdm/common/types/kill'; 2 | import type { Game } from '../counter-strike'; 3 | 4 | export type WallbangKillResult = Kill & { 5 | mapName: string; 6 | date: string; 7 | demoPath: string; 8 | game: Game; 9 | }; 10 | -------------------------------------------------------------------------------- /src/common/types/sequence-player-options.ts: -------------------------------------------------------------------------------- 1 | export type SequencePlayerOptions = { 2 | // @platform win32 Requires HLAE 3 | playerName: string; 4 | steamId: string; 5 | // @platform win32 Requires HLAE 6 | showKill: boolean; 7 | // @platform win32 Requires HLAE 8 | highlightKill: boolean; 9 | isVoiceEnabled: boolean; 10 | }; 11 | -------------------------------------------------------------------------------- /src/common/types/startup-behavior.ts: -------------------------------------------------------------------------------- 1 | export const StartupBehavior = { 2 | Minimized: 'minimized', 3 | On: 'on', 4 | Off: 'off', 5 | } as const; 6 | 7 | export type StartupBehavior = (typeof StartupBehavior)[keyof typeof StartupBehavior]; 8 | -------------------------------------------------------------------------------- /src/common/types/status.ts: -------------------------------------------------------------------------------- 1 | export const Status = { 2 | Idle: 'idle', 3 | Loading: 'loading', 4 | Success: 'success', 5 | Error: 'error', 6 | } as const; 7 | 8 | export type Status = (typeof Status)[keyof typeof Status]; 9 | -------------------------------------------------------------------------------- /src/common/types/tag.ts: -------------------------------------------------------------------------------- 1 | export type Tag = { 2 | id: string; 3 | name: string; 4 | color: string; 5 | }; 6 | -------------------------------------------------------------------------------- /src/common/types/team-match-side-stats.ts: -------------------------------------------------------------------------------- 1 | export type TeamMatchSideStats = { 2 | matchCount: number; 3 | matchCountStartedAsT: number; 4 | matchCountStartedAsCt: number; 5 | matchWonCountStartedAsT: number; 6 | matchWonCountStartedAsCt: number; 7 | matchTieCountStartedAsT: number; 8 | matchTieCountStartedAsCt: number; 9 | }; 10 | -------------------------------------------------------------------------------- /src/common/types/theme-name.ts: -------------------------------------------------------------------------------- 1 | export const ThemeName = { 2 | Dark: 'dark', 3 | Light: 'light', 4 | } as const; 5 | 6 | export type ThemeName = (typeof ThemeName)[keyof typeof ThemeName]; 7 | -------------------------------------------------------------------------------- /src/common/types/video-container.ts: -------------------------------------------------------------------------------- 1 | export const VideoContainer = { 2 | AVI: 'avi', 3 | MP4: 'mp4', 4 | MKV: 'mkv', 5 | } as const; 6 | 7 | export type VideoContainer = (typeof VideoContainer)[keyof typeof VideoContainer]; 8 | -------------------------------------------------------------------------------- /src/common/types/watch-player-options.ts: -------------------------------------------------------------------------------- 1 | import type { Perspective } from './perspective'; 2 | 3 | export type WatchPlayerOptions = { 4 | demoPath: string; 5 | steamId: string; 6 | perspective: Perspective; 7 | onGameStart: () => void; 8 | }; 9 | -------------------------------------------------------------------------------- /src/common/types/watch-type.ts: -------------------------------------------------------------------------------- 1 | export const WatchType = { 2 | Lowlights: 'lowlights', 3 | Highlights: 'highlights', 4 | } as const; 5 | 6 | export type WatchType = (typeof WatchType)[keyof typeof WatchType]; 7 | -------------------------------------------------------------------------------- /src/common/types/xlsx.ts: -------------------------------------------------------------------------------- 1 | export type ExportToXlsxProgressPayload = { 2 | count: number; 3 | totalCount: number; 4 | }; 5 | 6 | export type ExportToXlsxSuccessPayload = { 7 | outputType: 'file' | 'folder'; 8 | outputPath: string; 9 | }; 10 | -------------------------------------------------------------------------------- /src/node/boiler/errors/invalid-args.ts: -------------------------------------------------------------------------------- 1 | import { BaseError } from 'csdm/node/errors/base-error'; 2 | import { ErrorCode } from 'csdm/common/error-code'; 3 | 4 | export class InvalidArgs extends BaseError { 5 | public constructor() { 6 | super(ErrorCode.BoilerInvalidArgs); 7 | this.message = 'Invalid arguments'; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/node/boiler/errors/no-matches-found.ts: -------------------------------------------------------------------------------- 1 | import { BaseError } from 'csdm/node/errors/base-error'; 2 | import { ErrorCode } from 'csdm/common/error-code'; 3 | 4 | export class NoMatchesFound extends BaseError { 5 | public constructor() { 6 | super(ErrorCode.BoilerNoMatchesFound); 7 | this.message = 'No matches found'; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/node/counter-strike/json-actions-file/delete-json-actions-file.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs-extra'; 2 | 3 | export async function deleteJsonActionsFile(demoPath: string) { 4 | await fs.remove(`${demoPath}.json`); 5 | } 6 | -------------------------------------------------------------------------------- /src/node/counter-strike/launcher/assert-demo-exists.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs-extra'; 2 | import { DemoNotFound } from './errors/demo-not-found'; 3 | 4 | export async function assertDemoExists(demoPath: string) { 5 | const fileExists = await fs.pathExists(demoPath); 6 | if (!fileExists) { 7 | throw new DemoNotFound(); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/node/counter-strike/launcher/errors/demo-not-found.ts: -------------------------------------------------------------------------------- 1 | import { BaseError } from 'csdm/node/errors/base-error'; 2 | import { ErrorCode } from 'csdm/common/error-code'; 3 | 4 | export class DemoNotFound extends BaseError { 5 | public constructor() { 6 | super(ErrorCode.DemoNotFound); 7 | this.message = 'Demo not found'; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/node/counter-strike/launcher/errors/game-error.ts: -------------------------------------------------------------------------------- 1 | import { BaseError } from 'csdm/node/errors/base-error'; 2 | import { ErrorCode } from 'csdm/common/error-code'; 3 | 4 | export class GameError extends BaseError { 5 | public constructor() { 6 | super(ErrorCode.GameError); 7 | this.message = 'Game error'; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/node/counter-strike/launcher/errors/hlae-error.ts: -------------------------------------------------------------------------------- 1 | import { BaseError } from 'csdm/node/errors/base-error'; 2 | import { ErrorCode } from 'csdm/common/error-code'; 3 | 4 | export class HlaeError extends BaseError { 5 | public constructor() { 6 | super(ErrorCode.HlaeError); 7 | this.message = 'HLAE error'; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/node/counter-strike/launcher/errors/no-kills-found.ts: -------------------------------------------------------------------------------- 1 | import { BaseError } from 'csdm/node/errors/base-error'; 2 | import { ErrorCode } from 'csdm/common/error-code'; 3 | 4 | export class NoKillsFound extends BaseError { 5 | public constructor() { 6 | super(ErrorCode.NoKillsFound); 7 | this.message = 'No kills found'; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/node/csgo-voice-extractor/errors/bad-cpu-type-error.ts: -------------------------------------------------------------------------------- 1 | import { BaseError } from 'csdm/node/errors/base-error'; 2 | import { ErrorCode } from 'csdm/common/error-code'; 3 | 4 | export class BadCpuTypeError extends BaseError { 5 | public constructor() { 6 | super(ErrorCode.BadCpuType); 7 | this.message = 'Bad CPU type'; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/node/csgo-voice-extractor/export-voice-mode.ts: -------------------------------------------------------------------------------- 1 | export const ExportVoiceMode = { 2 | SplitCompact: 'split-compact', 3 | SplitFull: 'split-full', 4 | SingleFull: 'single-full', 5 | } as const; 6 | 7 | export type ExportVoiceMode = (typeof ExportVoiceMode)[keyof typeof ExportVoiceMode]; 8 | -------------------------------------------------------------------------------- /src/node/database/5play-account/5eplay-account-row.ts: -------------------------------------------------------------------------------- 1 | import type { Selectable } from 'kysely'; 2 | 3 | export type FiveEPlayAccountTable = { 4 | id: string; 5 | domain_id: string; 6 | nickname: string; 7 | avatar_url: string; 8 | is_current: boolean; 9 | }; 10 | 11 | export type FiveEPlayAccountRow = Selectable; 12 | -------------------------------------------------------------------------------- /src/node/database/bans/player-ban-per-match-table.ts: -------------------------------------------------------------------------------- 1 | export type PlayerBanPerMatchTable = { 2 | match_checksum: string; 3 | player_ban_count: number; 4 | }; 5 | -------------------------------------------------------------------------------- /src/node/database/comments/comment-table.ts: -------------------------------------------------------------------------------- 1 | import type { Selectable } from 'kysely'; 2 | 3 | export type CommentTable = { 4 | checksum: string; 5 | comment: string; 6 | }; 7 | 8 | export type CommentRow = Selectable; 9 | -------------------------------------------------------------------------------- /src/node/database/comments/fetch-comments.ts: -------------------------------------------------------------------------------- 1 | import { db } from 'csdm/node/database/database'; 2 | import type { CommentRow } from './comment-table'; 3 | 4 | export async function fetchComments() { 5 | const rows: CommentRow[] = await db.selectFrom('comments').selectAll().execute(); 6 | 7 | return rows; 8 | } 9 | -------------------------------------------------------------------------------- /src/node/database/comments/player-comments-table.ts: -------------------------------------------------------------------------------- 1 | export type PlayerCommentTable = { 2 | steam_id: string; 3 | comment: string; 4 | }; 5 | -------------------------------------------------------------------------------- /src/node/database/demos/demo-path-table.ts: -------------------------------------------------------------------------------- 1 | import type { Selectable } from 'kysely'; 2 | 3 | export type DemoPathTable = { 4 | checksum: string; 5 | file_path: string; 6 | }; 7 | 8 | export type DemoPathRow = Selectable; 9 | -------------------------------------------------------------------------------- /src/node/database/demos/is-demo-by-path-in-database.ts: -------------------------------------------------------------------------------- 1 | import { db } from 'csdm/node/database/database'; 2 | 3 | export async function isDemoByPathInDatabase(filePath: string) { 4 | const row = await db.selectFrom('matches').select('checksum').where('demo_path', '=', filePath).executeTakeFirst(); 5 | 6 | return row !== undefined; 7 | } 8 | -------------------------------------------------------------------------------- /src/node/database/download-history/fetch-download-histories.ts: -------------------------------------------------------------------------------- 1 | import { db } from '../database'; 2 | 3 | export async function fetchDownloadHistories() { 4 | const rows = await db.selectFrom('download_history').selectAll().execute(); 5 | 6 | return rows; 7 | } 8 | -------------------------------------------------------------------------------- /src/node/database/faceit-account/faceit-account-row.ts: -------------------------------------------------------------------------------- 1 | import type { Selectable } from 'kysely'; 2 | 3 | export type FaceitAccountTable = { 4 | id: string; 5 | nickname: string; 6 | avatar_url: string; 7 | is_current: boolean; 8 | }; 9 | 10 | export type FaceitAccountRow = Selectable; 11 | -------------------------------------------------------------------------------- /src/node/database/matches/errors/match-not-found.ts: -------------------------------------------------------------------------------- 1 | import { BaseError } from 'csdm/node/errors/base-error'; 2 | import { ErrorCode } from 'csdm/common/error-code'; 3 | 4 | export class MatchNotFound extends BaseError { 5 | public constructor() { 6 | super(ErrorCode.MatchNotFound); 7 | this.message = 'Match not found'; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/node/database/matches/fetch-match-checksums.ts: -------------------------------------------------------------------------------- 1 | import { db } from 'csdm/node/database/database'; 2 | 3 | export async function fetchMatchChecksums(): Promise { 4 | const rows = await db.selectFrom('matches').select('checksum').execute(); 5 | 6 | return rows.map((row) => row.checksum); 7 | } 8 | -------------------------------------------------------------------------------- /src/node/database/migrations/migration-table.ts: -------------------------------------------------------------------------------- 1 | export type MigrationTable = { 2 | schema_version: number; 3 | run_at: Date; 4 | }; 5 | -------------------------------------------------------------------------------- /src/node/database/migrations/migration.ts: -------------------------------------------------------------------------------- 1 | import type { Transaction } from 'kysely'; 2 | import type { Database } from '../schema'; 3 | 4 | export interface Migration { 5 | schemaVersion: number; 6 | run(transaction: Transaction): Promise; 7 | } 8 | -------------------------------------------------------------------------------- /src/node/database/players/players-table-filter.ts: -------------------------------------------------------------------------------- 1 | import type { BanFilter } from 'csdm/common/types/ban-filter'; 2 | 3 | export type PlayersTableFilter = { 4 | bans: BanFilter[]; 5 | startDate: string | undefined; 6 | endDate: string | undefined; 7 | tagIds: string[]; 8 | }; 9 | -------------------------------------------------------------------------------- /src/node/database/postgresql-error-code.ts: -------------------------------------------------------------------------------- 1 | // https://www.postgresql.org/docs/current/errcodes-appendix.html 2 | export const PostgresqlErrorCode = { 3 | UniqueViolation: '23505', 4 | UndefinedTable: '42P01', 5 | } as const; 6 | 7 | export type PostgresqlErrorCode = (typeof PostgresqlErrorCode)[keyof typeof PostgresqlErrorCode]; 8 | -------------------------------------------------------------------------------- /src/node/database/psql/errors/psql-timeout.ts: -------------------------------------------------------------------------------- 1 | import { BaseError } from 'csdm/node/errors/base-error'; 2 | import { ErrorCode } from 'csdm/common/error-code'; 3 | 4 | export class PsqlTimeout extends BaseError { 5 | public constructor() { 6 | super(ErrorCode.PsqlTimeout); 7 | this.message = 'PSQL timeout'; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/node/database/psql/psql-error.ts: -------------------------------------------------------------------------------- 1 | import { BaseError } from 'csdm/node/errors/base-error'; 2 | import { ErrorCode } from 'csdm/common/error-code'; 3 | 4 | export class PsqlNotFound extends BaseError { 5 | public constructor() { 6 | super(ErrorCode.PsqlNotFound); 7 | this.message = 'PSQL binary not found'; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/node/database/rounds/errors/round-not-found.ts: -------------------------------------------------------------------------------- 1 | import { BaseError } from 'csdm/node/errors/base-error'; 2 | import { ErrorCode } from 'csdm/common/error-code'; 3 | 4 | export class RoundNotFound extends BaseError { 5 | public constructor() { 6 | super(ErrorCode.RoundNotFound); 7 | this.message = 'Round not found'; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/node/database/steam-accounts/delete-ignored-steam-account.ts: -------------------------------------------------------------------------------- 1 | import { db } from 'csdm/node/database/database'; 2 | 3 | export async function deleteIgnoredSteamAccount(steamId: string) { 4 | await db.deleteFrom('ignored_steam_accounts').where('steam_id', '=', steamId).execute(); 5 | } 6 | -------------------------------------------------------------------------------- /src/node/database/steam-accounts/fetch-steam-accounts.ts: -------------------------------------------------------------------------------- 1 | import { db } from 'csdm/node/database/database'; 2 | 3 | export async function fetchSteamAccounts(steamIds: string[]) { 4 | const accounts = await db.selectFrom('steam_accounts').selectAll().where('steam_id', 'in', steamIds).execute(); 5 | 6 | return accounts; 7 | } 8 | -------------------------------------------------------------------------------- /src/node/database/steam-accounts/ignored-steam-account-table.ts: -------------------------------------------------------------------------------- 1 | import type { Selectable } from 'kysely'; 2 | 3 | export type IgnoredSteamAccountTable = { 4 | steam_id: string; 5 | }; 6 | 7 | export type IgnoredSteamAccountRow = Selectable; 8 | -------------------------------------------------------------------------------- /src/node/database/steam-accounts/steam-account-overrides-table.ts: -------------------------------------------------------------------------------- 1 | export type SteamAccountOverridesTable = { 2 | steam_id: string; 3 | name: string; 4 | }; 5 | -------------------------------------------------------------------------------- /src/node/database/tags/checksum-tag-table.ts: -------------------------------------------------------------------------------- 1 | import type { Selectable } from 'kysely'; 2 | import type { ColumnID } from 'csdm/common/types/column-id'; 3 | 4 | export type ChecksumTagTable = { 5 | checksum: string; 6 | tag_id: ColumnID; 7 | }; 8 | 9 | export type ChecksumTagRow = Selectable; 10 | -------------------------------------------------------------------------------- /src/node/database/tags/delete-tag.ts: -------------------------------------------------------------------------------- 1 | import { db } from 'csdm/node/database/database'; 2 | 3 | export async function deleteTag(tagId: string) { 4 | await db.deleteFrom('tags').where('id', '=', tagId).execute(); 5 | } 6 | -------------------------------------------------------------------------------- /src/node/database/tags/errors/tag-name-too-long.ts: -------------------------------------------------------------------------------- 1 | import { BaseError } from 'csdm/node/errors/base-error'; 2 | import { ErrorCode } from 'csdm/common/error-code'; 3 | 4 | export class TagNameTooLong extends BaseError { 5 | public constructor() { 6 | super(ErrorCode.TagNameTooLong); 7 | this.message = 'Tag name too long'; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/node/database/tags/errors/tag-not-found.ts: -------------------------------------------------------------------------------- 1 | import { BaseError } from 'csdm/node/errors/base-error'; 2 | import { ErrorCode } from 'csdm/common/error-code'; 3 | 4 | export class TagNotFound extends BaseError { 5 | public constructor() { 6 | super(ErrorCode.TagNotFound); 7 | this.message = 'Tag not found'; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/node/database/tags/fetch-checksum-tags.ts: -------------------------------------------------------------------------------- 1 | import { db } from 'csdm/node/database/database'; 2 | import type { ChecksumTagRow } from './checksum-tag-table'; 3 | 4 | export async function fetchChecksumTags() { 5 | const rows: ChecksumTagRow[] = await db.selectFrom('checksum_tags').selectAll().execute(); 6 | 7 | return rows; 8 | } 9 | -------------------------------------------------------------------------------- /src/node/database/tags/fetch-players-tags.ts: -------------------------------------------------------------------------------- 1 | import { db } from 'csdm/node/database/database'; 2 | 3 | export async function fetchPlayersTags() { 4 | const rows = await db.selectFrom('steam_account_tags').selectAll().execute(); 5 | 6 | return rows; 7 | } 8 | -------------------------------------------------------------------------------- /src/node/database/tags/round-tag-table.ts: -------------------------------------------------------------------------------- 1 | import type { Selectable } from 'kysely'; 2 | import type { ColumnID } from 'csdm/common/types/column-id'; 3 | 4 | export type RoundTagTable = { 5 | checksum: string; 6 | round_number: number; 7 | tag_id: ColumnID; 8 | }; 9 | 10 | export type RoundTagRow = Selectable; 11 | -------------------------------------------------------------------------------- /src/node/database/tags/steam-account-tag-table.ts: -------------------------------------------------------------------------------- 1 | import type { Selectable } from 'kysely'; 2 | import type { ColumnID } from 'csdm/common/types/column-id'; 3 | 4 | export type SteamAccountTagTable = { 5 | steam_id: string; 6 | tag_id: ColumnID; 7 | }; 8 | 9 | export type SteamAccountTagRow = Selectable; 10 | -------------------------------------------------------------------------------- /src/node/database/tags/tag-row-to-tag.ts: -------------------------------------------------------------------------------- 1 | import type { Tag } from '../../../common/types/tag'; 2 | import type { TagRow } from './tag-table'; 3 | 4 | export function tagRowToTag(row: TagRow): Tag { 5 | return { 6 | id: String(row.id), 7 | name: row.name, 8 | color: row.color, 9 | }; 10 | } 11 | -------------------------------------------------------------------------------- /src/node/database/team/error/team-not-found.ts: -------------------------------------------------------------------------------- 1 | import { BaseError } from 'csdm/node/errors/base-error'; 2 | import { ErrorCode } from 'csdm/common/error-code'; 3 | 4 | export class TeamNotFound extends BaseError { 5 | public constructor() { 6 | super(ErrorCode.TeamNotFound); 7 | this.message = 'Team not found'; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/node/database/team/team-filters.ts: -------------------------------------------------------------------------------- 1 | import type { MatchFilters } from '../match/apply-match-filters'; 2 | 3 | export type TeamFilters = MatchFilters & { 4 | name: string; 5 | }; 6 | -------------------------------------------------------------------------------- /src/node/database/teams/errors/teams-not-found.ts: -------------------------------------------------------------------------------- 1 | import { BaseError } from 'csdm/node/errors/base-error'; 2 | import { ErrorCode } from 'csdm/common/error-code'; 3 | 4 | export class TeamsNotFound extends BaseError { 5 | public constructor() { 6 | super(ErrorCode.TeamsNotFound); 7 | this.message = 'Teams not found'; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/node/database/teams/teams-table-filter.ts: -------------------------------------------------------------------------------- 1 | export type TeamsTableFilter = { 2 | startDate: string | undefined; 3 | endDate: string | undefined; 4 | }; 5 | -------------------------------------------------------------------------------- /src/node/database/timestamps/timestamp-name.ts: -------------------------------------------------------------------------------- 1 | export const TimestampName = { 2 | SyncWithSteam: 'SyncWithSteam', 3 | FfmpegUpdate: 'FfmpegUpdate', 4 | HlaeUpdate: 'HlaeUpdate', 5 | } as const; 6 | 7 | export type TimestampName = (typeof TimestampName)[keyof typeof TimestampName]; 8 | -------------------------------------------------------------------------------- /src/node/database/timestamps/timestamp-table.ts: -------------------------------------------------------------------------------- 1 | import type { Generated } from 'kysely'; 2 | import type { TimestampName } from './timestamp-name'; 3 | 4 | export type TimestampTable = { 5 | name: TimestampName; 6 | date: Generated; 7 | }; 8 | -------------------------------------------------------------------------------- /src/node/demo-analyzer/corrupted-demo-error.ts: -------------------------------------------------------------------------------- 1 | import { ErrorCode } from 'csdm/common/error-code'; 2 | import { BaseError } from '../errors/base-error'; 3 | 4 | export class CorruptedDemoError extends BaseError { 5 | public constructor() { 6 | super(ErrorCode.AnalyzeCorruptedDemo); 7 | this.message = 'Corrupted demo'; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/node/demo/fixtures/source_2_1.dem.data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/src/node/demo/fixtures/source_2_1.dem.data -------------------------------------------------------------------------------- /src/node/demo/fixtures/source_2_2.dem.data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/src/node/demo/fixtures/source_2_2.dem.data -------------------------------------------------------------------------------- /src/node/demo/fixtures/source_2_3.dem.data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/src/node/demo/fixtures/source_2_3.dem.data -------------------------------------------------------------------------------- /src/node/demo/fixtures/source_2_4.dem.data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/src/node/demo/fixtures/source_2_4.dem.data -------------------------------------------------------------------------------- /src/node/demo/fixtures/source_2_5.dem.data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/src/node/demo/fixtures/source_2_5.dem.data -------------------------------------------------------------------------------- /src/node/demo/fixtures/source_2_6.dem.data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/src/node/demo/fixtures/source_2_6.dem.data -------------------------------------------------------------------------------- /src/node/demo/fixtures/source_2_7.dem.data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/src/node/demo/fixtures/source_2_7.dem.data -------------------------------------------------------------------------------- /src/node/demo/fixtures/source_2_8.dem.data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/src/node/demo/fixtures/source_2_8.dem.data -------------------------------------------------------------------------------- /src/node/demo/fixtures/source_2_9.dem.data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/src/node/demo/fixtures/source_2_9.dem.data -------------------------------------------------------------------------------- /src/node/demo/get-demo-info-file-path.ts: -------------------------------------------------------------------------------- 1 | export function getDemoInfoFilePath(demoPath: string) { 2 | return `${demoPath}.info`; 3 | } 4 | -------------------------------------------------------------------------------- /src/node/errors/abort-error.ts: -------------------------------------------------------------------------------- 1 | export class AbortError extends Error { 2 | constructor() { 3 | super(); 4 | this.name = 'AbortError'; 5 | } 6 | } 7 | 8 | export const abortError = new AbortError(); 9 | 10 | export function throwIfAborted(signal?: AbortSignal) { 11 | if (signal?.aborted) { 12 | throw abortError; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/node/errors/base-error.ts: -------------------------------------------------------------------------------- 1 | import type { ErrorCode } from 'csdm/common/error-code'; 2 | 3 | export class BaseError extends Error { 4 | public code: ErrorCode; 5 | 6 | public constructor(code: ErrorCode, cause?: unknown) { 7 | super(); 8 | this.code = code; 9 | this.cause = cause; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/node/errors/network-error.ts: -------------------------------------------------------------------------------- 1 | import { BaseError } from 'csdm/node/errors/base-error'; 2 | import { ErrorCode } from 'csdm/common/error-code'; 3 | 4 | export class NetworkError extends BaseError { 5 | public constructor() { 6 | super(ErrorCode.NetworkError); 7 | this.message = 'Network error'; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/node/errors/player-not-found.ts: -------------------------------------------------------------------------------- 1 | import { BaseError } from 'csdm/node/errors/base-error'; 2 | import { ErrorCode } from 'csdm/common/error-code'; 3 | 4 | export class PlayerNotFound extends BaseError { 5 | public constructor() { 6 | super(ErrorCode.PlayerNotFound); 7 | this.message = 'Player not found'; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/node/faceit-web-api/faceit-game-id.ts: -------------------------------------------------------------------------------- 1 | export type FaceitGameId = 'csgo' | 'cs2'; 2 | -------------------------------------------------------------------------------- /src/node/faceit-web-api/faceit-result.ts: -------------------------------------------------------------------------------- 1 | export type FaceitResultDTO = { 2 | score: { 3 | faction1: number; 4 | faction2: number; 5 | }; 6 | winner: string; 7 | }; 8 | -------------------------------------------------------------------------------- /src/node/filesystem/get-images-folder-path.ts: -------------------------------------------------------------------------------- 1 | import path from 'node:path'; 2 | import { getStaticFolderPath } from './get-static-folder-path'; 3 | 4 | export function getImagesFolderPath(): string { 5 | return path.join(getStaticFolderPath(), 'images'); 6 | } 7 | -------------------------------------------------------------------------------- /src/node/filesystem/get-static-folder-path.ts: -------------------------------------------------------------------------------- 1 | import path from 'node:path'; 2 | 3 | export function getStaticFolderPath() { 4 | // We are in the "out" folder in dev mode and "app.asar" when the app is packaged, so we need to go up one level. 5 | return path.join(__dirname, '..', 'static'); 6 | } 7 | -------------------------------------------------------------------------------- /src/node/filesystem/get-user-images-folder-path.ts: -------------------------------------------------------------------------------- 1 | import path from 'node:path'; 2 | import { getAppFolderPath } from 'csdm/node/filesystem/get-app-folder-path'; 3 | 4 | export function getUserImagesFolderPath(): string { 5 | return path.join(getAppFolderPath(), 'images'); 6 | } 7 | -------------------------------------------------------------------------------- /src/node/filesystem/glob.ts: -------------------------------------------------------------------------------- 1 | import { glob as tinyGlobby, type GlobOptions } from 'tinyglobby'; 2 | 3 | export function glob(patterns: string | string[], options?: Omit) { 4 | return tinyGlobby(patterns, options); 5 | } 6 | -------------------------------------------------------------------------------- /src/node/filesystem/is-path-writable.ts: -------------------------------------------------------------------------------- 1 | import fs from 'node:fs/promises'; 2 | import { constants } from 'node:fs'; 3 | 4 | export async function isPathWritable(path: string) { 5 | try { 6 | await fs.access(path, constants.W_OK); 7 | return true; 8 | } catch (error) { 9 | return false; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/node/filesystem/is-png-base64-string.ts: -------------------------------------------------------------------------------- 1 | export function isPngBase64String(value: string): boolean { 2 | return value.startsWith('data:image/png;base64,'); 3 | } 4 | -------------------------------------------------------------------------------- /src/node/filesystem/maps/get-maps-images-folder-path.ts: -------------------------------------------------------------------------------- 1 | import path from 'node:path'; 2 | import { getImagesFolderPath } from 'csdm/node/filesystem/get-images-folder-path'; 3 | 4 | export function getMapsImagesFolderPath() { 5 | const imagesFolderPath = getImagesFolderPath(); 6 | 7 | return path.join(imagesFolderPath, 'maps'); 8 | } 9 | -------------------------------------------------------------------------------- /src/node/filesystem/move-files.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs-extra'; 2 | import path from 'node:path'; 3 | 4 | export async function moveFiles(files: string[], outputFolderPath: string) { 5 | await Promise.all( 6 | files.map((file) => { 7 | return fs.move(file, path.join(outputFolderPath, path.basename(file))); 8 | }), 9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /src/node/filesystem/windows-to-unix-path-separator.ts: -------------------------------------------------------------------------------- 1 | export function windowsToUnixPathSeparator(path: string) { 2 | return path.replaceAll('\\', '/'); 3 | } 4 | -------------------------------------------------------------------------------- /src/node/filesystem/write-base64-file.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs-extra'; 2 | 3 | export async function writeBase64File(filePath: string, data: string) { 4 | await fs.writeFile(filePath, data, 'base64'); 5 | } 6 | -------------------------------------------------------------------------------- /src/node/json/match-json.ts: -------------------------------------------------------------------------------- 1 | import type { GrenadeProjectileDestroy } from 'csdm/common/types/grenade-projectile-destroy'; 2 | import type { Match } from 'csdm/common/types/match'; 3 | 4 | export type MatchJson = Match & { 5 | grenadeDestroyed: GrenadeProjectileDestroy[]; 6 | }; 7 | -------------------------------------------------------------------------------- /src/node/os/get-running-process-exit-code/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "get_running_process_exit_code", 5 | "conditions": [ 6 | ['OS=="win"', { 7 | "sources": ["get-running-process-exit-code.cpp"] 8 | }] 9 | ] 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /src/node/os/get-running-process-exit-code/build/Release/get_running_process_exit_code.node: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/src/node/os/get-running-process-exit-code/build/Release/get_running_process_exit_code.node -------------------------------------------------------------------------------- /src/node/os/get-running-process-exit-code/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "get-running-process-exit-code", 3 | "scripts": { 4 | "node-gyp": "node-gyp", 5 | "build": "node-gyp build" 6 | }, 7 | "devDependencies": { 8 | "node-gyp": "11.2.0" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/node/os/is-linux.ts: -------------------------------------------------------------------------------- 1 | import { isMac } from './is-mac'; 2 | import { isWindows } from './is-windows'; 3 | 4 | export const isLinux = !isMac && !isWindows; 5 | -------------------------------------------------------------------------------- /src/node/os/is-mac.ts: -------------------------------------------------------------------------------- 1 | export const isMac = process.platform === 'darwin'; 2 | -------------------------------------------------------------------------------- /src/node/os/is-windows.ts: -------------------------------------------------------------------------------- 1 | export const isWindows = process.platform === 'win32'; 2 | -------------------------------------------------------------------------------- /src/node/settings/get-settings-file-path.ts: -------------------------------------------------------------------------------- 1 | import path from 'node:path'; 2 | import { getAppFolderPath } from 'csdm/node/filesystem/get-app-folder-path'; 3 | 4 | export function getSettingsFilePath() { 5 | const settingsFilePath = path.resolve(getAppFolderPath(), 'settings.json'); 6 | return settingsFilePath; 7 | } 8 | -------------------------------------------------------------------------------- /src/node/settings/migration.ts: -------------------------------------------------------------------------------- 1 | import type { Settings } from './settings'; 2 | 3 | export interface Migration { 4 | schemaVersion: number; 5 | run(currentSettings: Settings): Promise; 6 | } 7 | -------------------------------------------------------------------------------- /src/node/settings/page.ts: -------------------------------------------------------------------------------- 1 | export const Page = { 2 | Matches: 'matches', 3 | Demos: 'demos', 4 | Players: 'players', 5 | Download: 'download', 6 | } as const; 7 | 8 | export type Page = (typeof Page)[keyof typeof Page]; 9 | -------------------------------------------------------------------------------- /src/node/settings/table/column-state.ts: -------------------------------------------------------------------------------- 1 | import type { SortDirection } from 'csdm/ui/components/table/table-types'; 2 | 3 | export type ColumnState = { 4 | id: string; 5 | isVisible: boolean; 6 | width: number; 7 | sortDirection?: SortDirection; 8 | }; 9 | -------------------------------------------------------------------------------- /src/node/settings/table/table-name.ts: -------------------------------------------------------------------------------- 1 | export const TableName = { 2 | Matches: 'matches', 3 | Demos: 'demos', 4 | MatchScoreboard: 'match-scoreboard', 5 | Players: 'players', 6 | Teams: 'teams', 7 | } as const; 8 | 9 | export type TableName = (typeof TableName)[keyof typeof TableName]; 10 | -------------------------------------------------------------------------------- /src/node/steam-web-api/steam-constants.ts: -------------------------------------------------------------------------------- 1 | export const MAX_STEAM_IDS_PER_REQUEST = 100; 2 | 3 | export const EconomyBan = { 4 | None: 'none', 5 | Probation: 'probation', 6 | Banned: 'banned', 7 | } as const; 8 | 9 | export type EconomyBan = (typeof EconomyBan)[keyof typeof EconomyBan]; 10 | -------------------------------------------------------------------------------- /src/node/steam-web-api/steamapi-error.ts: -------------------------------------------------------------------------------- 1 | import { BaseError } from 'csdm/node/errors/base-error'; 2 | import { ErrorCode } from 'csdm/common/error-code'; 3 | 4 | export class SteamApiError extends BaseError { 5 | public constructor() { 6 | super(ErrorCode.SteamApiError); 7 | this.message = 'Steam API error'; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/node/valve-match/fixtures/match730_003028590839392632871_1662707805_136.dem.info: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/src/node/valve-match/fixtures/match730_003028590839392632871_1662707805_136.dem.info -------------------------------------------------------------------------------- /src/node/valve-match/fixtures/match730_003189280594026561777_1796106830_900.dem.info: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/src/node/valve-match/fixtures/match730_003189280594026561777_1796106830_900.dem.info -------------------------------------------------------------------------------- /src/node/valve-match/fixtures/match730_003189870870709403769_1988138084_900.dem.info: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/src/node/valve-match/fixtures/match730_003189870870709403769_1988138084_900.dem.info -------------------------------------------------------------------------------- /src/node/valve-match/fixtures/match730_003496718345246343373_0093428724_190.dem.info: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/src/node/valve-match/fixtures/match730_003496718345246343373_0093428724_190.dem.info -------------------------------------------------------------------------------- /src/node/valve-match/fixtures/match730_003498492722937856210_1557600280_214.dem.info: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/src/node/valve-match/fixtures/match730_003498492722937856210_1557600280_214.dem.info -------------------------------------------------------------------------------- /src/node/valve-match/fixtures/match730_003668313874395824202_1729175012_271.dem.info: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/src/node/valve-match/fixtures/match730_003668313874395824202_1729175012_271.dem.info -------------------------------------------------------------------------------- /src/node/valve-match/fixtures/match730_003668537425296097309_2104686856_273.dem.info: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/src/node/valve-match/fixtures/match730_003668537425296097309_2104686856_273.dem.info -------------------------------------------------------------------------------- /src/node/valve-match/get-match-demo-path.ts: -------------------------------------------------------------------------------- 1 | import path from 'node:path'; 2 | import type { ValveMatch } from 'csdm/common/types/valve-match'; 3 | 4 | export function getMatchDemoPath(downloadFolderPath: string, match: ValveMatch): string { 5 | return `${downloadFolderPath}${path.sep}${match.name}.dem`; 6 | } 7 | -------------------------------------------------------------------------------- /src/node/video/errors/ffmpeg-error.ts: -------------------------------------------------------------------------------- 1 | import { ErrorCode } from 'csdm/common/error-code'; 2 | import { CommandError } from './command-error'; 3 | 4 | export class FFmpegError extends CommandError { 5 | public constructor(output: string) { 6 | super(ErrorCode.FfmpegError, 'FFmpeg error', output); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/node/video/errors/hlae-not-installed.ts: -------------------------------------------------------------------------------- 1 | import { BaseError } from 'csdm/node/errors/base-error'; 2 | import { ErrorCode } from 'csdm/common/error-code'; 3 | 4 | export class HlaeNotInstalled extends BaseError { 5 | public constructor() { 6 | super(ErrorCode.HlaeNotInstalled); 7 | this.message = 'HLAE is not installed'; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/node/video/errors/no-sequences-found.ts: -------------------------------------------------------------------------------- 1 | import { BaseError } from 'csdm/node/errors/base-error'; 2 | import { ErrorCode } from 'csdm/common/error-code'; 3 | 4 | export class NoSequencesFound extends BaseError { 5 | public constructor() { 6 | super(ErrorCode.NoSequencesFound); 7 | this.message = 'No sequences found'; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/node/video/errors/virtual-dub-error.ts: -------------------------------------------------------------------------------- 1 | import { BaseError } from 'csdm/node/errors/base-error'; 2 | import { ErrorCode } from 'csdm/common/error-code'; 3 | 4 | export class VirtualDubError extends BaseError { 5 | public constructor() { 6 | super(ErrorCode.VirtualDubError); 7 | this.message = 'VirtualDub error'; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/node/video/errors/wav-file-not-found.ts: -------------------------------------------------------------------------------- 1 | import { BaseError } from 'csdm/node/errors/base-error'; 2 | import { ErrorCode } from 'csdm/common/error-code'; 3 | 4 | export class WavFileNotFound extends BaseError { 5 | public constructor() { 6 | super(ErrorCode.WavFileNotFound); 7 | this.message = 'WAV file not found'; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/node/video/ffmpeg/kill-ffmpeg-process.ts: -------------------------------------------------------------------------------- 1 | import { killProcessesByNames } from 'csdm/node/os/kill-processes-by-names'; 2 | import { isWindows } from 'csdm/node/os/is-windows'; 3 | 4 | export async function killFfmpegProcess() { 5 | await killProcessesByNames([isWindows ? 'ffmpeg.exe' : 'ffmpeg']); 6 | } 7 | -------------------------------------------------------------------------------- /src/node/video/generation/get-sequence-name.ts: -------------------------------------------------------------------------------- 1 | import type { Sequence } from 'csdm/common/types/sequence'; 2 | 3 | export function getSequenceName(sequence: Sequence) { 4 | return `${sequence.number}-sequence`; 5 | } 6 | -------------------------------------------------------------------------------- /src/node/video/hlae/kill-hlae-process.ts: -------------------------------------------------------------------------------- 1 | import { killProcessesByNames } from 'csdm/node/os/kill-processes-by-names'; 2 | 3 | export async function killHlaeProcess() { 4 | await killProcessesByNames(['hlae.exe']); 5 | } 6 | -------------------------------------------------------------------------------- /src/node/video/virtual-dub/get-virtual-dub-folder-path.ts: -------------------------------------------------------------------------------- 1 | import path from 'node:path'; 2 | import { getAppFolderPath } from 'csdm/node/filesystem/get-app-folder-path'; 3 | 4 | export function getVirtualDubFolderPath(): string { 5 | return path.join(getAppFolderPath(), 'virtualdub'); 6 | } 7 | -------------------------------------------------------------------------------- /src/node/video/virtual-dub/is-virtual-dub-installed.ts: -------------------------------------------------------------------------------- 1 | import { getInstalledVirtualDubVersion } from './get-installed-virtual-dub-version'; 2 | 3 | export async function isVirtualDubInstalled() { 4 | const installedVirtualDubVersion = await getInstalledVirtualDubVersion(); 5 | 6 | return installedVirtualDubVersion !== undefined; 7 | } 8 | -------------------------------------------------------------------------------- /src/node/video/virtual-dub/kill-virtual-dub-process.ts: -------------------------------------------------------------------------------- 1 | import { killProcessesByNames } from 'csdm/node/os/kill-processes-by-names'; 2 | 3 | export async function killVirtualDubProcess() { 4 | const processName = process.arch === 'x64' ? 'Veedub64.exe' : 'VirtualDub.exe'; 5 | 6 | await killProcessesByNames([processName]); 7 | } 8 | -------------------------------------------------------------------------------- /src/node/video/virtual-dub/virtual-dub-version.ts: -------------------------------------------------------------------------------- 1 | export const VIRTUALDUB_VERSION = '1.10.4'; 2 | -------------------------------------------------------------------------------- /src/node/xlsx/cell-value.ts: -------------------------------------------------------------------------------- 1 | export type CellValue = string | number | boolean | Date; 2 | -------------------------------------------------------------------------------- /src/node/xlsx/column.ts: -------------------------------------------------------------------------------- 1 | import type { CellValue } from './cell-value'; 2 | 3 | export type Column = { 4 | name: string; 5 | cellFormatter: (row: RowType) => CellValue; 6 | }; 7 | -------------------------------------------------------------------------------- /src/node/xlsx/xlsx-output.ts: -------------------------------------------------------------------------------- 1 | export const XlsxOutputType = { 2 | SingleFile: 'single-file', 3 | MultipleFiles: 'multiple-files', 4 | } as const; 5 | export type XlsxOutputType = (typeof XlsxOutputType)[keyof typeof XlsxOutputType]; 6 | 7 | export type XlsxOutput = { 8 | type: 'file' | 'folder'; 9 | path: string; 10 | }; 11 | -------------------------------------------------------------------------------- /src/server/dev-preload.ts: -------------------------------------------------------------------------------- 1 | import { ipcRenderer } from 'electron'; 2 | import { IPCChannel } from 'csdm/common/ipc-channel'; 3 | 4 | window.addEventListener('beforeunload', () => { 5 | ipcRenderer.invoke(IPCChannel.ReloadWindow); 6 | }); 7 | -------------------------------------------------------------------------------- /src/server/dev.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/server/get-error-code-from-error.ts: -------------------------------------------------------------------------------- 1 | import { BaseError } from 'csdm/node/errors/base-error'; 2 | import { ErrorCode } from 'csdm/common/error-code'; 3 | 4 | export function getErrorCodeFromError(error: unknown) { 5 | return error instanceof BaseError ? error.code : ErrorCode.UnknownError; 6 | } 7 | -------------------------------------------------------------------------------- /src/server/handlers/main-process/has-pending-analyses-handler.ts: -------------------------------------------------------------------------------- 1 | import { analysesListener } from 'csdm/server/analyses-listener'; 2 | 3 | export async function hasPendingAnalysesHandler() { 4 | return Promise.resolve(analysesListener.hasAnalysesInProgress()); 5 | } 6 | -------------------------------------------------------------------------------- /src/server/handlers/renderer-process/abort-current-task-handler.ts: -------------------------------------------------------------------------------- 1 | import { abortRendererController } from 'csdm/server/abort-controller'; 2 | 3 | export async function abortCurrentTaskHandler() { 4 | abortRendererController(); 5 | 6 | return Promise.resolve(); 7 | } 8 | -------------------------------------------------------------------------------- /src/server/handlers/renderer-process/counter-strike/is-counter-strike-running-handler.ts: -------------------------------------------------------------------------------- 1 | import { isCounterStrikeRunning } from 'csdm/node/counter-strike/is-counter-strike-running'; 2 | 3 | export async function isCounterStrikeRunningHandler() { 4 | const isRunning = await isCounterStrikeRunning(); 5 | 6 | return isRunning; 7 | } 8 | -------------------------------------------------------------------------------- /src/server/handlers/renderer-process/counter-strike/is-cs2-connected-to-server-handler.ts: -------------------------------------------------------------------------------- 1 | import { server } from 'csdm/server/server'; 2 | 3 | export async function isCs2ConnectedToServerHandler() { 4 | return Promise.resolve(server.isGameConnected()); 5 | } 6 | -------------------------------------------------------------------------------- /src/server/handlers/renderer-process/demo/add-demos-to-analyses-handler.ts: -------------------------------------------------------------------------------- 1 | import { analysesListener } from 'csdm/server/analyses-listener'; 2 | import type { Demo } from 'csdm/common/types/demo'; 3 | 4 | export async function addDemosToAnalysesHandler(demos: Demo[]) { 5 | await analysesListener.addDemosToAnalyses(demos); 6 | } 7 | -------------------------------------------------------------------------------- /src/server/handlers/renderer-process/migrations/fetch-migrations-handler.ts: -------------------------------------------------------------------------------- 1 | import { fetchMigrations } from 'csdm/node/database/migrations/fetch-migrations'; 2 | 3 | export async function fetchMigrationsHandler() { 4 | const migrations = await fetchMigrations(5); 5 | 6 | return migrations; 7 | } 8 | -------------------------------------------------------------------------------- /src/server/handlers/renderer-process/settings/ffmpeg-version-changed-payload.ts: -------------------------------------------------------------------------------- 1 | import type { ErrorCode } from 'csdm/common/error-code'; 2 | 3 | export type FfmpegVersionChangedPayload = { 4 | errorCode: ErrorCode | undefined; 5 | version: string | undefined; 6 | isUpdateAvailable: boolean; 7 | }; 8 | -------------------------------------------------------------------------------- /src/server/handlers/renderer-process/settings/hlae-version-changed-payload.ts: -------------------------------------------------------------------------------- 1 | import type { ErrorCode } from 'csdm/common/error-code'; 2 | 3 | export type HlaeVersionChangedPayload = { 4 | errorCode: ErrorCode | undefined; 5 | version: string | undefined; 6 | isUpdateAvailable: boolean; 7 | }; 8 | -------------------------------------------------------------------------------- /src/server/handlers/renderer-process/video/pause-video-queue-handler.ts: -------------------------------------------------------------------------------- 1 | import { videoQueue } from 'csdm/server/video-queue'; 2 | 3 | export async function pauseVideoQueueHandler() { 4 | videoQueue.pause(); 5 | 6 | return Promise.resolve(); 7 | } 8 | -------------------------------------------------------------------------------- /src/server/handlers/renderer-process/video/remove-videos-from-queue-handler.ts: -------------------------------------------------------------------------------- 1 | import { videoQueue } from 'csdm/server/video-queue'; 2 | 3 | export async function removeVideosFromQueueHandler(videoIds: string[]) { 4 | videoQueue.removeVideos(videoIds); 5 | 6 | return Promise.resolve(); 7 | } 8 | -------------------------------------------------------------------------------- /src/server/handlers/renderer-process/video/resume-video-queue-handler.ts: -------------------------------------------------------------------------------- 1 | import { videoQueue } from 'csdm/server/video-queue'; 2 | 3 | export async function resumeVideoQueueHandler() { 4 | videoQueue.resume(); 5 | 6 | return Promise.resolve(); 7 | } 8 | -------------------------------------------------------------------------------- /src/server/identifiable-client-message.ts: -------------------------------------------------------------------------------- 1 | export type IdentifiableClientMessage = { 2 | name: MessageName; 3 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 4 | payload?: any; 5 | uuid: string; 6 | }; 7 | -------------------------------------------------------------------------------- /src/server/port.ts: -------------------------------------------------------------------------------- 1 | export const WEB_SOCKET_SERVER_PORT = 4574; 2 | -------------------------------------------------------------------------------- /src/ui/analyses/analyses.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { AnalysesTable } from './table/analyses-table'; 3 | import { AnalysisLogs } from './analysis-logs'; 4 | 5 | export function Analyses() { 6 | return ( 7 | <> 8 | 9 | 10 | 11 | ); 12 | } 13 | -------------------------------------------------------------------------------- /src/ui/analyses/no-analysis.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Trans } from '@lingui/react/macro'; 3 | import { Message } from 'csdm/ui/components/message'; 4 | 5 | export function NoAnalysis() { 6 | return No demo analysis in progress.} />; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/analyses/use-analyses-state.ts: -------------------------------------------------------------------------------- 1 | import { useSelector } from 'csdm/ui/store/use-selector'; 2 | import type { AnalysesState } from './analyses-reducer'; 3 | 4 | export function useAnalysesState(): AnalysesState { 5 | const analysesState = useSelector((state) => state.analyses); 6 | 7 | return analysesState; 8 | } 9 | -------------------------------------------------------------------------------- /src/ui/analyses/use-analyses.ts: -------------------------------------------------------------------------------- 1 | import { useAnalysesState } from './use-analyses-state'; 2 | 3 | export function useAnalyses() { 4 | const analysesState = useAnalysesState(); 5 | 6 | return analysesState.analyses; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/analyses/use-selected-analysis-demo-id.ts: -------------------------------------------------------------------------------- 1 | import { useAnalysesState } from './use-analyses-state'; 2 | 3 | export function useSelectedAnalysis() { 4 | const state = useAnalysesState(); 5 | 6 | return state.analyses.find((analysis) => analysis.demoPath === state.selectedDemoPath); 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/ban/stats/no-ban-message.tsx: -------------------------------------------------------------------------------- 1 | import { Trans } from '@lingui/react/macro'; 2 | import React from 'react'; 3 | 4 | export function NoBanMessage() { 5 | return ( 6 |

7 | No bans yet 8 |

9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /src/ui/ban/use-ban-state.ts: -------------------------------------------------------------------------------- 1 | import { useSelector } from 'csdm/ui/store/use-selector'; 2 | import type { BanState } from './ban-reducer'; 3 | 4 | export function useBanState(): BanState { 5 | return useSelector((state) => state.ban); 6 | } 7 | -------------------------------------------------------------------------------- /src/ui/ban/use-ignored-steam-accounts.ts: -------------------------------------------------------------------------------- 1 | import { useBanState } from './use-ban-state'; 2 | 3 | export function useIgnoredSteamAccounts() { 4 | const state = useBanState(); 5 | 6 | return state.ignoredAccounts; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/bootstrap/app-content.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import type { ReactNode } from 'react'; 3 | 4 | type Props = { 5 | children: ReactNode; 6 | }; 7 | 8 | export function AppContent({ children }: Props) { 9 | return
{children}
; 10 | } 11 | -------------------------------------------------------------------------------- /src/ui/bootstrap/app-wrapper.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import type { ReactNode } from 'react'; 3 | 4 | type Props = { 5 | children: ReactNode; 6 | }; 7 | 8 | export function AppWrapper({ children }: Props) { 9 | return
{children}
; 10 | } 11 | -------------------------------------------------------------------------------- /src/ui/bootstrap/database-status.ts: -------------------------------------------------------------------------------- 1 | export const DatabaseStatus = { 2 | Idle: 'idle', 3 | Connected: 'connected', 4 | Disconnected: 'disconnected', 5 | Error: 'error', 6 | } as const; 7 | 8 | export type DatabaseStatus = (typeof DatabaseStatus)[keyof typeof DatabaseStatus]; 9 | -------------------------------------------------------------------------------- /src/ui/bootstrap/loading.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Spinner } from '../components/spinner'; 3 | 4 | export function Loading() { 5 | return ( 6 |
7 | 8 |
9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /src/ui/bootstrap/use-arguments-context.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { ArgumentsContext } from './arguments-provider'; 3 | 4 | export function useArgumentsContext() { 5 | const context = useContext(ArgumentsContext); 6 | 7 | return context; 8 | } 9 | -------------------------------------------------------------------------------- /src/ui/bootstrap/use-bootstrap-state.ts: -------------------------------------------------------------------------------- 1 | import { useSelector } from 'csdm/ui/store/use-selector'; 2 | import type { BootstrapState } from './bootstrap-reducer'; 3 | 4 | export function useBootstrapState(): BootstrapState { 5 | const bootstrapState = useSelector((state) => state.bootstrap); 6 | 7 | return bootstrapState; 8 | } 9 | -------------------------------------------------------------------------------- /src/ui/bootstrap/use-database-status.ts: -------------------------------------------------------------------------------- 1 | import type { DatabaseStatus } from './database-status'; 2 | import { useBootstrapState } from './use-bootstrap-state'; 3 | 4 | export function useDatabaseStatus(): DatabaseStatus { 5 | const state = useBootstrapState(); 6 | 7 | return state.databaseStatus; 8 | } 9 | -------------------------------------------------------------------------------- /src/ui/cache/use-cache.ts: -------------------------------------------------------------------------------- 1 | import { useSelector } from 'csdm/ui/store/use-selector'; 2 | 3 | export function useCache() { 4 | const cache = useSelector((state) => state.cache); 5 | 6 | return cache; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/cache/use-match-checksums.ts: -------------------------------------------------------------------------------- 1 | import { useCache } from './use-cache'; 2 | 3 | export function useMatchChecksums() { 4 | const cache = useCache(); 5 | 6 | return cache.matchChecksums; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/comment/comment-actions.ts: -------------------------------------------------------------------------------- 1 | import { createAction } from '@reduxjs/toolkit'; 2 | 3 | export const commentUpdated = createAction<{ checksum: string; comment: string }>('comment/commentUpdated'); 4 | -------------------------------------------------------------------------------- /src/ui/components/card.tsx: -------------------------------------------------------------------------------- 1 | import React, { type ReactNode } from 'react'; 2 | 3 | type Props = { 4 | children: ReactNode; 5 | }; 6 | 7 | export function Card({ children }: Props) { 8 | return
{children}
; 9 | } 10 | -------------------------------------------------------------------------------- /src/ui/components/context-menu/separator.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export function Separator() { 4 | return
; 5 | } 6 | -------------------------------------------------------------------------------- /src/ui/components/context-menu/use-context-menu.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { ContextMenuContext } from './context-menu-provider'; 3 | 4 | export function useContextMenu() { 5 | const contextMenu = useContext(ContextMenuContext); 6 | 7 | return contextMenu; 8 | } 9 | -------------------------------------------------------------------------------- /src/ui/components/dialogs/use-dialog.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { DialogContext } from './dialog-provider'; 3 | 4 | export function useDialog() { 5 | return useContext(DialogContext); 6 | } 7 | -------------------------------------------------------------------------------- /src/ui/components/dropdown-filter/active-filter-indicator.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export function ActiveFilterIndicator() { 4 | return
; 5 | } 6 | -------------------------------------------------------------------------------- /src/ui/components/dropdown-filter/filter-separator.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export function FilterSeparator() { 4 | return
; 5 | } 6 | -------------------------------------------------------------------------------- /src/ui/components/heatmap/heatmap-filters.tsx: -------------------------------------------------------------------------------- 1 | import React, { type ReactNode } from 'react'; 2 | 3 | type Props = { 4 | children: ReactNode; 5 | }; 6 | 7 | export function HeatmapFilters({ children }: Props) { 8 | return
{children}
; 9 | } 10 | -------------------------------------------------------------------------------- /src/ui/components/inputs/color-picker.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export function ColorPicker(props: React.HTMLProps) { 4 | return ; 5 | } 6 | -------------------------------------------------------------------------------- /src/ui/components/progress.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | type Props = { 4 | max?: number; 5 | value: number; 6 | }; 7 | 8 | export function Progress({ max = 100, value }: Props) { 9 | return ( 10 | 11 | {`${value}%`} 12 | 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /src/ui/components/table/get-table-row-height.ts: -------------------------------------------------------------------------------- 1 | import { getCssVariableValue } from 'csdm/ui/shared/get-css-variable-value'; 2 | 3 | export function getTableRowHeight() { 4 | return Number.parseFloat(getCssVariableValue('--table-row-height')); 5 | } 6 | -------------------------------------------------------------------------------- /src/ui/components/table/status-bar/table-status-bar-rectangle.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | type Props = { 4 | className: string; 5 | }; 6 | 7 | export function TableStatusBarRectangle({ className }: Props) { 8 | return
; 9 | } 10 | -------------------------------------------------------------------------------- /src/ui/components/table/status-bar/table-status-bar-separator.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export function TableStatusBarSeparator() { 4 | return
|
; 5 | } 6 | -------------------------------------------------------------------------------- /src/ui/components/toasts/use-show-toast.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { ToastsContext } from './toasts-context'; 3 | 4 | export function useShowToast() { 5 | return useContext(ToastsContext); 6 | } 7 | -------------------------------------------------------------------------------- /src/ui/demo/use-demo-state.ts: -------------------------------------------------------------------------------- 1 | import { useSelector } from 'csdm/ui/store/use-selector'; 2 | import type { DemoState } from './demo-reducer'; 3 | 4 | export function useDemoState(): DemoState { 5 | const demoState = useSelector((state) => state.demo); 6 | 7 | return demoState; 8 | } 9 | -------------------------------------------------------------------------------- /src/ui/demo/use-is-demo-in-database.ts: -------------------------------------------------------------------------------- 1 | import { useMatchChecksums } from 'csdm/ui/cache/use-match-checksums'; 2 | 3 | export function useIsDemoInDatabase() { 4 | const matchChecksums = useMatchChecksums(); 5 | 6 | return (demoChecksum: string) => { 7 | return matchChecksums.includes(demoChecksum); 8 | }; 9 | } 10 | -------------------------------------------------------------------------------- /src/ui/demos/table/demos-table-context.ts: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react'; 2 | import type { Demo } from 'csdm/common/types/demo'; 3 | import type { TableInstance } from 'csdm/ui/components/table/table-types'; 4 | 5 | export const DemosTableContext = createContext | null>(null); 6 | -------------------------------------------------------------------------------- /src/ui/demos/use-demos-loaded.ts: -------------------------------------------------------------------------------- 1 | import { Status } from 'csdm/common/types/status'; 2 | import { useDemosStatus } from './use-demos-status'; 3 | 4 | export function useDemosLoaded() { 5 | const status = useDemosStatus(); 6 | 7 | return status !== Status.Idle && status !== Status.Loading; 8 | } 9 | -------------------------------------------------------------------------------- /src/ui/demos/use-demos-state.ts: -------------------------------------------------------------------------------- 1 | import { useSelector } from 'csdm/ui/store/use-selector'; 2 | import type { DemosState } from './demos-reducer'; 3 | 4 | export function useDemosState(): DemosState { 5 | const demosState = useSelector((state) => state.demos); 6 | return demosState; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/demos/use-demos-status.ts: -------------------------------------------------------------------------------- 1 | import { useDemosState } from './use-demos-state'; 2 | 3 | export function useDemosStatus() { 4 | const demosState = useDemosState(); 5 | 6 | return demosState.status; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/demos/use-fuzzy-search-text.ts: -------------------------------------------------------------------------------- 1 | import { useDemosState } from './use-demos-state'; 2 | 3 | export function useFuzzySearchText(): string { 4 | const state = useDemosState(); 5 | 6 | return state.fuzzySearchText; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/demos/use-selected-demos-paths.ts: -------------------------------------------------------------------------------- 1 | import { useDemosTable } from './table/use-demos-table'; 2 | 3 | export function useSelectedDemosPaths() { 4 | const table = useDemosTable(); 5 | 6 | return table.getSelectedRowIds(); 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/demos/use-selected-demos.ts: -------------------------------------------------------------------------------- 1 | import { useDemosTable } from './table/use-demos-table'; 2 | 3 | export function useSelectedDemos() { 4 | const table = useDemosTable(); 5 | 6 | return table.getSelectedRows(); 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/downloads/faceit/last-matches.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { ActionBar } from './action-bar'; 3 | import { LastMatchesLoader } from './last-matches-loader'; 4 | 5 | export function LastMatches() { 6 | return ( 7 | <> 8 | 9 | 10 | 11 | ); 12 | } 13 | -------------------------------------------------------------------------------- /src/ui/downloads/faceit/use-current-faceit-account.ts: -------------------------------------------------------------------------------- 1 | import { useFaceitAccounts } from './use-faceit-accounts'; 2 | 3 | export function useCurrentFaceitAccount() { 4 | const accounts = useFaceitAccounts(); 5 | 6 | return accounts.find((account) => account.isCurrent); 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/downloads/faceit/use-faceit-accounts.ts: -------------------------------------------------------------------------------- 1 | import { useFaceitState } from './use-faceit-state'; 2 | 3 | export function useFaceitAccounts() { 4 | const state = useFaceitState(); 5 | 6 | return state.accounts; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/downloads/faceit/use-faceit-matches.ts: -------------------------------------------------------------------------------- 1 | import { useFaceitState } from './use-faceit-state'; 2 | 3 | export function useFaceitMatches() { 4 | const state = useFaceitState(); 5 | 6 | return state.matches; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/downloads/faceit/use-faceit-state.ts: -------------------------------------------------------------------------------- 1 | import { useDownloadsState } from 'csdm/ui/downloads/use-downloads-state'; 2 | 3 | export function useFaceitState() { 4 | const state = useDownloadsState(); 5 | 6 | return state.faceit; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/downloads/faceit/use-faceit-status.ts: -------------------------------------------------------------------------------- 1 | import { useFaceitState } from './use-faceit-state'; 2 | 3 | export function useFaceitStatus() { 4 | const state = useFaceitState(); 5 | 6 | return state.status; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/downloads/faceit/use-selected-match-id.ts: -------------------------------------------------------------------------------- 1 | import { useFaceitState } from './use-faceit-state'; 2 | 3 | export function useSelectedMatchId() { 4 | const state = useFaceitState(); 5 | 6 | return state.selectedMatchId; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/downloads/five-eplay/use-5eplay-accounts.ts: -------------------------------------------------------------------------------- 1 | import { use5EPlayState } from './use-5eplay-state'; 2 | 3 | export function use5EPlayAccounts() { 4 | const state = use5EPlayState(); 5 | 6 | return state.accounts; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/downloads/five-eplay/use-5eplay-state.ts: -------------------------------------------------------------------------------- 1 | import { useDownloadsState } from 'csdm/ui/downloads/use-downloads-state'; 2 | 3 | export function use5EPlayState() { 4 | const state = useDownloadsState(); 5 | 6 | return state['5eplay']; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/downloads/five-eplay/use-current-5eplay-account.ts: -------------------------------------------------------------------------------- 1 | import { use5EPlayAccounts } from './use-5eplay-accounts'; 2 | 3 | export function useCurrent5EPlayAccount() { 4 | const accounts = use5EPlayAccounts(); 5 | 6 | return accounts.find((account) => account.isCurrent); 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/downloads/match-result.ts: -------------------------------------------------------------------------------- 1 | export const MatchResult = { 2 | Unplayed: 'unplayed', // The current Steam/third party provider account is not in the match 3 | Defeat: 'defeat', 4 | Victory: 'victory', 5 | Tied: 'tied', 6 | } as const; 7 | 8 | export type MatchResult = (typeof MatchResult)[keyof typeof MatchResult]; 9 | -------------------------------------------------------------------------------- /src/ui/downloads/pending/pending-actions.ts: -------------------------------------------------------------------------------- 1 | import { createAction } from '@reduxjs/toolkit'; 2 | 3 | export const abortDownload = createAction<{ matchId: string }>('downloads/pending/abortDemoDownload'); 4 | export const abortDownloads = createAction('downloads/pending/abortDownloads'); 5 | -------------------------------------------------------------------------------- /src/ui/downloads/pending/use-download-progress.ts: -------------------------------------------------------------------------------- 1 | import { usePendingDownloadsState } from './use-pending-downloads-state'; 2 | 3 | export function useDownloadProgress() { 4 | const downloadState = usePendingDownloadsState(); 5 | 6 | return downloadState.progress; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/downloads/pending/use-download-status.ts: -------------------------------------------------------------------------------- 1 | import { usePendingDownloadsState } from './use-pending-downloads-state'; 2 | 3 | export function useDownloadStatus() { 4 | const downloadStatus = usePendingDownloadsState(); 5 | 6 | return downloadStatus.status; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/downloads/pending/use-downloads.ts: -------------------------------------------------------------------------------- 1 | import { usePendingDownloadsState } from './use-pending-downloads-state'; 2 | 3 | export function useDownloads() { 4 | const downloadsState = usePendingDownloadsState(); 5 | 6 | return downloadsState.downloads; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/downloads/use-downloads-state.ts: -------------------------------------------------------------------------------- 1 | import { useSelector } from 'csdm/ui/store/use-selector'; 2 | 3 | export function useDownloadsState() { 4 | const state = useSelector((state) => state.downloads); 5 | 6 | return state; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/downloads/valve/use-error-code.ts: -------------------------------------------------------------------------------- 1 | import { useValveState } from './use-valve-state'; 2 | 3 | export function useErrorCode() { 4 | const state = useValveState(); 5 | 6 | return state.errorCode; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/downloads/valve/use-matches.ts: -------------------------------------------------------------------------------- 1 | import { useValveState } from './use-valve-state'; 2 | 3 | export function useMatches() { 4 | const state = useValveState(); 5 | 6 | return state.matches; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/downloads/valve/use-status.ts: -------------------------------------------------------------------------------- 1 | import { useValveState } from './use-valve-state'; 2 | 3 | export function useStatus() { 4 | const state = useValveState(); 5 | 6 | return state.status; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/downloads/valve/use-valve-state.ts: -------------------------------------------------------------------------------- 1 | import { useDownloadsState } from '../use-downloads-state'; 2 | 3 | export function useValveState() { 4 | const state = useDownloadsState(); 5 | 6 | return state.valve; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/hooks/use-block-navigation.ts: -------------------------------------------------------------------------------- 1 | import { useBlocker } from 'react-router'; 2 | 3 | export function useBlockNavigation(isNavigationBlocked: boolean) { 4 | const blocker = useBlocker(isNavigationBlocked); 5 | 6 | return blocker; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/hooks/use-boolean-to-human.ts: -------------------------------------------------------------------------------- 1 | import { useLingui } from '@lingui/react/macro'; 2 | 3 | export function useBooleanHuman() { 4 | const { t } = useLingui(); 5 | 6 | return (bool: boolean) => { 7 | return bool ? t({ id: 'yes', message: 'Yes' }) : t({ id: 'no', message: 'No' }); 8 | }; 9 | } 10 | -------------------------------------------------------------------------------- /src/ui/hooks/use-navigate-to-player.ts: -------------------------------------------------------------------------------- 1 | import { useNavigate } from 'react-router'; 2 | import { buildPlayerPath } from 'csdm/ui/routes-paths'; 3 | 4 | export function useNavigateToPlayer() { 5 | const navigate = useNavigate(); 6 | 7 | return (steamId: string) => { 8 | navigate(buildPlayerPath(steamId)); 9 | }; 10 | } 11 | -------------------------------------------------------------------------------- /src/ui/hooks/use-navigate-to-team.ts: -------------------------------------------------------------------------------- 1 | import { useNavigate } from 'react-router'; 2 | import { buildTeamPath } from 'csdm/ui/routes-paths'; 3 | 4 | export function useNavigateToTeam() { 5 | const navigate = useNavigate(); 6 | 7 | return (name: string) => { 8 | navigate(buildTeamPath(name)); 9 | }; 10 | } 11 | -------------------------------------------------------------------------------- /src/ui/icons/armor-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | -------------------------------------------------------------------------------- /src/ui/icons/flag-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/ui/icons/folder-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /src/ui/icons/pause-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/ui/icons/play-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /src/ui/icons/star-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /src/ui/icons/step-backward-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /src/ui/icons/step-forward-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /src/ui/icons/video.svg: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /src/ui/index.css: -------------------------------------------------------------------------------- 1 | @import 'tailwindcss'; 2 | @import './styles/variables.css'; 3 | @import './styles/fonts.css'; 4 | @import './styles/utilities.css'; 5 | @import './styles/base.css'; 6 | @import './styles/third-parties.css'; 7 | -------------------------------------------------------------------------------- /src/ui/keyboard/keyboard-shortcut.ts: -------------------------------------------------------------------------------- 1 | import { msg } from '@lingui/core/macro'; 2 | 3 | const KEY_C = { 4 | key: 'C', 5 | label: msg({ 6 | context: 'Keyboard shortcut', 7 | message: 'C', 8 | }), 9 | }; 10 | 11 | export const SHOW_COMMENT_SHORTCUT = KEY_C; 12 | -------------------------------------------------------------------------------- /src/ui/left-bar/left-bar-badge.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import type { ReactNode } from 'react'; 3 | 4 | type Props = { 5 | children: ReactNode; 6 | }; 7 | 8 | export function LeftBarBadge({ children }: Props) { 9 | return
{children}
; 10 | } 11 | -------------------------------------------------------------------------------- /src/ui/maps/get-scaled-coordinate-x.ts: -------------------------------------------------------------------------------- 1 | import type { Map } from 'csdm/common/types/map'; 2 | 3 | export function getScaledCoordinateX(map: Map, imageSize: number, xFromDemo: number) { 4 | const xForDefaultRadarWidth = (xFromDemo - map.posX) / map.scale; 5 | const scaledX = (xForDefaultRadarWidth * imageSize) / map.radarSize; 6 | return scaledX; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/maps/radar-level.ts: -------------------------------------------------------------------------------- 1 | export const RadarLevel = { 2 | Upper: 'upper', 3 | Lower: 'lower', 4 | } as const; 5 | 6 | export type RadarLevel = (typeof RadarLevel)[keyof typeof RadarLevel]; 7 | -------------------------------------------------------------------------------- /src/ui/maps/use-maps-state.ts: -------------------------------------------------------------------------------- 1 | import { useSelector } from 'csdm/ui/store/use-selector'; 2 | 3 | export function useMapsState() { 4 | const state = useSelector((state) => state.maps); 5 | 6 | return state; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/maps/use-maps.ts: -------------------------------------------------------------------------------- 1 | import { useMemo } from 'react'; 2 | import { useMapsState } from './use-maps-state'; 3 | 4 | export function useMaps() { 5 | const state = useMapsState(); 6 | 7 | return useMemo(() => { 8 | return state.entities; 9 | }, [state]); 10 | } 11 | -------------------------------------------------------------------------------- /src/ui/match/grenades/finder/drawing/grenade-drawing.ts: -------------------------------------------------------------------------------- 1 | export type GrenadeDrawing = { 2 | id: string; 3 | image: HTMLImageElement; 4 | imageX: number; 5 | imageY: number; 6 | path: Path2D; 7 | }; 8 | -------------------------------------------------------------------------------- /src/ui/match/grenades/finder/use-grenades-finder-state.ts: -------------------------------------------------------------------------------- 1 | import { useGrenadesState } from '../use-grenades-state'; 2 | import type { GrenadesFinderState } from './grenades-finder-reducer'; 3 | 4 | export function useGrenadesFinderState(): GrenadesFinderState { 5 | const state = useGrenadesState(); 6 | 7 | return state.finder; 8 | } 9 | -------------------------------------------------------------------------------- /src/ui/match/grenades/finder/use-selected-grenade-name.ts: -------------------------------------------------------------------------------- 1 | import { useGrenadesFinderState } from './use-grenades-finder-state'; 2 | 3 | export function useSelectedGrenadeName() { 4 | const state = useGrenadesFinderState(); 5 | 6 | return state.grenadeName; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/match/grenades/finder/use-selected-radar-level.ts: -------------------------------------------------------------------------------- 1 | import { useGrenadesFinderState } from './use-grenades-finder-state'; 2 | 3 | export function useSelectedRadarLevel() { 4 | const state = useGrenadesFinderState(); 5 | 6 | return state.radarLevel; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/match/grenades/finder/use-selected-rounds.ts: -------------------------------------------------------------------------------- 1 | import { useGrenadesFinderState } from './use-grenades-finder-state'; 2 | 3 | export function useSelectedRounds() { 4 | const state = useGrenadesFinderState(); 5 | 6 | return state.rounds; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/match/grenades/finder/use-selected-sides.ts: -------------------------------------------------------------------------------- 1 | import { useGrenadesFinderState } from './use-grenades-finder-state'; 2 | 3 | export function useSelectedSides() { 4 | const state = useGrenadesFinderState(); 5 | 6 | return state.sides; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/match/grenades/finder/use-selected-steamids.ts: -------------------------------------------------------------------------------- 1 | import { useGrenadesFinderState } from './use-grenades-finder-state'; 2 | 3 | export function useSelectedSteamIds() { 4 | const state = useGrenadesFinderState(); 5 | 6 | return state.steamIds; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/match/grenades/grenades-reducer.ts: -------------------------------------------------------------------------------- 1 | import { combineReducers } from '@reduxjs/toolkit'; 2 | import { grenadesFinderReducer } from './finder/grenades-finder-reducer'; 3 | 4 | export const grenadesReducer = combineReducers({ 5 | finder: grenadesFinderReducer, 6 | }); 7 | -------------------------------------------------------------------------------- /src/ui/match/grenades/match-grenades.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { GrenadesTabs } from './grenades-tabs'; 3 | import { Outlet } from 'react-router'; 4 | 5 | export function MatchGrenades() { 6 | return ( 7 | <> 8 | 9 | 10 | 11 | ); 12 | } 13 | -------------------------------------------------------------------------------- /src/ui/match/grenades/stats/cells/cell-text.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import type { ReactNode } from 'react'; 3 | 4 | type Props = { 5 | children: ReactNode; 6 | }; 7 | 8 | export function CellText({ children }: Props) { 9 | return

{children}

; 10 | } 11 | -------------------------------------------------------------------------------- /src/ui/match/grenades/stats/grenade-option.ts: -------------------------------------------------------------------------------- 1 | export const GrenadeOption = { 2 | Flashbang: 'flashbang', 3 | HE: 'he', 4 | Fire: 'fire', 5 | Smoke: 'smoke', 6 | } as const; 7 | 8 | export type GrenadeOption = (typeof GrenadeOption)[keyof typeof GrenadeOption]; 9 | -------------------------------------------------------------------------------- /src/ui/match/grenades/use-grenades-state.ts: -------------------------------------------------------------------------------- 1 | import { useSelector } from 'csdm/ui/store/use-selector'; 2 | 3 | export function useGrenadesState() { 4 | const state = useSelector((state) => state.match.grenades); 5 | 6 | return state; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/match/heatmap/use-heatmap-state.ts: -------------------------------------------------------------------------------- 1 | import { useSelector } from 'csdm/ui/store/use-selector'; 2 | import type { MatchHeatmapState } from './heatmap-reducer'; 3 | 4 | export function useHeatmapState(): MatchHeatmapState { 5 | return useSelector((state) => state.match.heatmap); 6 | } 7 | -------------------------------------------------------------------------------- /src/ui/match/use-current-match-checksum.ts: -------------------------------------------------------------------------------- 1 | import { useCurrentMatch } from './use-current-match'; 2 | 3 | export function useCurrentMatchChecksum(): string { 4 | const match = useCurrentMatch(); 5 | 6 | return match.checksum; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/match/use-current-match.ts: -------------------------------------------------------------------------------- 1 | import { useUnsafeCurrentMatch } from './use-unsafe-current-match'; 2 | 3 | export function useCurrentMatch() { 4 | const match = useUnsafeCurrentMatch(); 5 | 6 | if (match === null) { 7 | throw new Error('Current match not defined'); 8 | } 9 | 10 | return match; 11 | } 12 | -------------------------------------------------------------------------------- /src/ui/match/use-unsafe-current-match.ts: -------------------------------------------------------------------------------- 1 | import { useSelector } from 'csdm/ui/store/use-selector'; 2 | 3 | export function useUnsafeCurrentMatch() { 4 | const match = useSelector((state) => state.match.entity); 5 | 6 | return match; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/match/video/ffmpeg/ffmpeg-actions.ts: -------------------------------------------------------------------------------- 1 | import { createAction } from '@reduxjs/toolkit'; 2 | 3 | export const installFfmpegSuccess = createAction<{ version: string }>('match/video/ffmpeg/installSuccess'); 4 | export const updateFfmpegSuccess = createAction<{ version: string }>('match/video/ffmpeg/updateSuccess'); 5 | -------------------------------------------------------------------------------- /src/ui/match/video/ffmpeg/use-ffmpeg-state.ts: -------------------------------------------------------------------------------- 1 | import { useVideoState } from 'csdm/ui/match/video/use-video-state'; 2 | import type { FfmpegState } from './ffmpeg-reducer'; 3 | 4 | export function useFfmpegState(): FfmpegState { 5 | const videoState = useVideoState(); 6 | 7 | return videoState.ffmpeg; 8 | } 9 | -------------------------------------------------------------------------------- /src/ui/match/video/ffmpeg/use-installed-ffmpeg-version.ts: -------------------------------------------------------------------------------- 1 | import { useFfmpegState } from './use-ffmpeg-state'; 2 | 3 | export function useInstalledFfmpegVersion(): string | undefined { 4 | const ffmpegState = useFfmpegState(); 5 | 6 | return ffmpegState.version; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/match/video/ffmpeg/use-is-ffmpeg-installed.ts: -------------------------------------------------------------------------------- 1 | import { useFfmpegState } from 'csdm/ui/match/video/ffmpeg/use-ffmpeg-state'; 2 | 3 | export function useIsFfmpegInstalled(): boolean { 4 | const ffmpegState = useFfmpegState(); 5 | 6 | return ffmpegState.version !== undefined; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/match/video/ffmpeg/use-is-ffmpeg-update-available.ts: -------------------------------------------------------------------------------- 1 | import { useFfmpegState } from 'csdm/ui/match/video/ffmpeg/use-ffmpeg-state'; 2 | 3 | export function useIsFfmpegUpdateAvailable(): boolean { 4 | const ffmpegState = useFfmpegState(); 5 | 6 | return ffmpegState.isUpdateAvailable; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/match/video/hlae/hlae-actions.ts: -------------------------------------------------------------------------------- 1 | import { createAction } from '@reduxjs/toolkit'; 2 | 3 | export const installHlaeSuccess = createAction<{ version: string }>('match/video/hlae/installSuccess'); 4 | export const updateHlaeSuccess = createAction<{ version: string }>('match/video/hlae/updateSuccess'); 5 | -------------------------------------------------------------------------------- /src/ui/match/video/hlae/use-hlae-state.ts: -------------------------------------------------------------------------------- 1 | import type { HlaeState } from 'csdm/ui/match/video/hlae/hlae-reducer'; 2 | import { useVideoState } from 'csdm/ui/match/video/use-video-state'; 3 | 4 | export function useHlaeState(): HlaeState { 5 | const video = useVideoState(); 6 | 7 | return video.hlae; 8 | } 9 | -------------------------------------------------------------------------------- /src/ui/match/video/hlae/use-installed-hlae-version.ts: -------------------------------------------------------------------------------- 1 | import { useHlaeState } from 'csdm/ui/match/video/hlae/use-hlae-state'; 2 | 3 | export function useInstalledHlaeVersion(): string | undefined { 4 | const hlaeState = useHlaeState(); 5 | 6 | return hlaeState.version; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/match/video/hlae/use-is-hlae-installed.ts: -------------------------------------------------------------------------------- 1 | import { useHlaeState } from 'csdm/ui/match/video/hlae/use-hlae-state'; 2 | 3 | export function useIsHlaeInstalled(): boolean { 4 | const hlaeState = useHlaeState(); 5 | 6 | return hlaeState.version !== undefined; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/match/video/hlae/use-is-hlae-update-available.ts: -------------------------------------------------------------------------------- 1 | import { useHlaeState } from 'csdm/ui/match/video/hlae/use-hlae-state'; 2 | 3 | export function useIsHlaeUpdateAvailable(): boolean { 4 | const hlaeState = useHlaeState(); 5 | 6 | return hlaeState.isUpdateAvailable; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/match/video/sequence/cameras/generate-cameras-form.ts: -------------------------------------------------------------------------------- 1 | export type KillCameraPov = 'killer' | 'victim'; 2 | 3 | export type GenerateCamerasForm = { 4 | playerFocusSteamId: string | undefined; 5 | killCameraPov: KillCameraPov | undefined; 6 | beforeKillDelaySeconds: number; 7 | }; 8 | -------------------------------------------------------------------------------- /src/ui/match/video/sequence/use-sequence-form.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { SequenceFormContext } from './sequence-form-provider'; 3 | 4 | export function useSequenceForm() { 5 | const form = useContext(SequenceFormContext); 6 | 7 | return form; 8 | } 9 | -------------------------------------------------------------------------------- /src/ui/match/video/sequences/edit-sequences/player-options/use-players-options.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { SequencePlayersOptionsContext } from './players-options-provider'; 3 | 4 | export function usePlayersOptions() { 5 | return useContext(SequencePlayersOptionsContext); 6 | } 7 | -------------------------------------------------------------------------------- /src/ui/match/video/sequences/player-sequence-event.ts: -------------------------------------------------------------------------------- 1 | export const PlayerSequenceEvent = { 2 | Kills: 'kills', 3 | Deaths: 'deaths', 4 | Rounds: 'rounds', 5 | } as const; 6 | export type PlayerSequenceEvent = (typeof PlayerSequenceEvent)[keyof typeof PlayerSequenceEvent]; 7 | -------------------------------------------------------------------------------- /src/ui/match/video/use-can-edit-video-players-options.ts: -------------------------------------------------------------------------------- 1 | import { Game } from 'csdm/common/types/counter-strike'; 2 | import { useCurrentMatch } from '../use-current-match'; 3 | 4 | export function useCanEditVideoPlayersOptions() { 5 | const match = useCurrentMatch(); 6 | 7 | return match.game !== Game.CSGO || window.csdm.isWindows; 8 | } 9 | -------------------------------------------------------------------------------- /src/ui/match/video/use-video-state.ts: -------------------------------------------------------------------------------- 1 | import { useSelector } from 'csdm/ui/store/use-selector'; 2 | 3 | export function useVideoState() { 4 | const videoState = useSelector((state) => state.match.video); 5 | 6 | return videoState; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/match/video/virtualdub/use-is-virtual-dub-installed.ts: -------------------------------------------------------------------------------- 1 | import { useVirtualDubState } from 'csdm/ui/match/video/virtualdub/use-virtual-dub-state'; 2 | 3 | export function useIsVirtualDubInstalled() { 4 | const virtualDubState = useVirtualDubState(); 5 | 6 | return virtualDubState.version !== undefined; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/match/video/virtualdub/use-virtual-dub-state.ts: -------------------------------------------------------------------------------- 1 | import { useVideoState } from 'csdm/ui/match/video/use-video-state'; 2 | 3 | export function useVirtualDubState() { 4 | const videoState = useVideoState(); 5 | 6 | return videoState.virtualDub; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/match/video/virtualdub/virtual-dub-actions.ts: -------------------------------------------------------------------------------- 1 | import { createAction } from '@reduxjs/toolkit'; 2 | 3 | export const installVirtualDubSuccess = createAction<{ version: string }>('match/video/virtualDub/installSuccess'); 4 | -------------------------------------------------------------------------------- /src/ui/match/viewer-2d/build-player-id.ts: -------------------------------------------------------------------------------- 1 | // We don't use only the SteamID because it's not unique with BOTs (always 0). 2 | export function buildPlayerId(playerSteamId: string, playerName: string) { 3 | return `${playerSteamId}-${playerName}`; 4 | } 5 | -------------------------------------------------------------------------------- /src/ui/match/viewer-2d/drawing/degrees-to-radians.ts: -------------------------------------------------------------------------------- 1 | export function degreesToRadians(degrees: number) { 2 | return degrees * (Math.PI / 180); 3 | } 4 | -------------------------------------------------------------------------------- /src/ui/match/viewer-2d/use-fullscreen.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { FullscreenContext } from './fullscreen-provider'; 3 | 4 | export function useFullscreen() { 5 | return useContext(FullscreenContext); 6 | } 7 | -------------------------------------------------------------------------------- /src/ui/match/viewer-2d/use-viewer-state.ts: -------------------------------------------------------------------------------- 1 | import { useSelector } from 'csdm/ui/store/use-selector'; 2 | import type { Viewer2DState } from './viewer-2d-reducer'; 3 | 4 | export function useViewer2DState(): Viewer2DState { 5 | return useSelector((state) => state.match.viewer2D); 6 | } 7 | -------------------------------------------------------------------------------- /src/ui/match/viewer-2d/viewer-actions.ts: -------------------------------------------------------------------------------- 1 | import { createAction } from '@reduxjs/toolkit'; 2 | 3 | export const focusedPlayerChanged = createAction<{ focusedPlayerId: string | undefined }>( 4 | 'match/viewer/focusedPlayerChanged', 5 | ); 6 | export const speedChanged = createAction<{ speed: number }>('match/viewer/speedChanged'); 7 | -------------------------------------------------------------------------------- /src/ui/match/weapons/weapons.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Content } from 'csdm/ui/components/content'; 3 | import { WeaponsAccuracy } from './weapons-accuracy'; 4 | 5 | export function Weapons() { 6 | return ( 7 | 8 | 9 | 10 | ); 11 | } 12 | -------------------------------------------------------------------------------- /src/ui/matches/table/matches-table-context.ts: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react'; 2 | import type { MatchTable } from 'csdm/common/types/match-table'; 3 | import type { TableInstance } from 'csdm/ui/components/table/table-types'; 4 | 5 | export const MatchesTableContext = createContext | null>(null); 6 | -------------------------------------------------------------------------------- /src/ui/matches/use-fuzzy-search-text.ts: -------------------------------------------------------------------------------- 1 | import { useMatchesState } from './use-matches-state'; 2 | 3 | export function useFuzzySearchText() { 4 | const state = useMatchesState(); 5 | 6 | return state.fuzzySearchText; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/matches/use-matches-loaded.ts: -------------------------------------------------------------------------------- 1 | import { Status } from 'csdm/common/types/status'; 2 | import { useMatchesStatus } from './use-matches-status'; 3 | 4 | export function useMatchesLoaded() { 5 | const status = useMatchesStatus(); 6 | 7 | return status === Status.Success; 8 | } 9 | -------------------------------------------------------------------------------- /src/ui/matches/use-matches-state.ts: -------------------------------------------------------------------------------- 1 | import { useSelector } from 'csdm/ui/store/use-selector'; 2 | 3 | export function useMatchesState() { 4 | const matchesState = useSelector((state) => state.matches); 5 | 6 | return matchesState; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/matches/use-matches-status.ts: -------------------------------------------------------------------------------- 1 | import { useMatchesState } from './use-matches-state'; 2 | 3 | export function useMatchesStatus() { 4 | const state = useMatchesState(); 5 | 6 | return state.status; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/matches/use-matches.ts: -------------------------------------------------------------------------------- 1 | import { useMatchesState } from './use-matches-state'; 2 | 3 | export function useMatches() { 4 | const state = useMatchesState(); 5 | 6 | return state.entities; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/matches/use-selected-match-checksums.ts: -------------------------------------------------------------------------------- 1 | import { useMatchesState } from './use-matches-state'; 2 | 3 | export function useSelectedMatchChecksums() { 4 | const state = useMatchesState(); 5 | 6 | return state.selectedChecksums; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/matches/use-selected-matches.ts: -------------------------------------------------------------------------------- 1 | import { useMatchesState } from './use-matches-state'; 2 | 3 | export function useSelectedMatches() { 4 | const state = useMatchesState(); 5 | 6 | return state.entities.filter((match) => state.selectedChecksums.includes(match.checksum)); 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/player/maps/player-maps.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { usePlayer } from '../use-player'; 3 | import { MapsStats } from 'csdm/ui/components/maps-stats'; 4 | 5 | export function PlayerMaps() { 6 | const { mapsStats } = usePlayer(); 7 | 8 | return ; 9 | } 10 | -------------------------------------------------------------------------------- /src/ui/player/matches/use-selected-match-checksums.ts: -------------------------------------------------------------------------------- 1 | import { usePlayerState } from '../use-player-state'; 2 | 3 | export function useSelectedMatchChecksums() { 4 | const { selectedMatchChecksums } = usePlayerState(); 5 | 6 | return selectedMatchChecksums; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/player/overview/player-clutches.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Clutches } from 'csdm/ui/components/panels/clutches'; 3 | import { usePlayer } from '../use-player'; 4 | 5 | export function PlayerClutches() { 6 | const { clutches } = usePlayer(); 7 | 8 | return ; 9 | } 10 | -------------------------------------------------------------------------------- /src/ui/player/overview/player-last-matches.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { usePlayer } from '../use-player'; 3 | import { LastMatches } from 'csdm/ui/components/last-matches'; 4 | 5 | export function PlayerLastMatches() { 6 | const { lastMatches } = usePlayer(); 7 | 8 | return ; 9 | } 10 | -------------------------------------------------------------------------------- /src/ui/player/rank/use-get-win-count-translation.ts: -------------------------------------------------------------------------------- 1 | import { useLingui } from '@lingui/react/macro'; 2 | 3 | export function useGetWinCountTranslation() { 4 | const { t } = useLingui(); 5 | 6 | return (winCount: number) => { 7 | return t`Win count: ${winCount}`; 8 | }; 9 | } 10 | -------------------------------------------------------------------------------- /src/ui/player/use-current-player-steam-id.ts: -------------------------------------------------------------------------------- 1 | import { useParams } from 'react-router'; 2 | 3 | export function useCurrentPlayerSteamId() { 4 | const { steamId } = useParams<'steamId'>(); 5 | if (typeof steamId !== 'string') { 6 | throw new TypeError('steamId is not a string'); 7 | } 8 | 9 | return steamId; 10 | } 11 | -------------------------------------------------------------------------------- /src/ui/player/use-player-state.ts: -------------------------------------------------------------------------------- 1 | import { useSelector } from 'csdm/ui/store/use-selector'; 2 | 3 | export function usePlayerState() { 4 | const playerState = useSelector((state) => state.player); 5 | 6 | return playerState; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/player/use-player.ts: -------------------------------------------------------------------------------- 1 | import { usePlayerState } from './use-player-state'; 2 | 3 | export function usePlayer() { 4 | const { player } = usePlayerState(); 5 | 6 | if (player === undefined) { 7 | throw new Error('player not defined'); 8 | } 9 | 10 | return player; 11 | } 12 | -------------------------------------------------------------------------------- /src/ui/player/use-unsafe-player.ts: -------------------------------------------------------------------------------- 1 | import { usePlayerState } from './use-player-state'; 2 | 3 | export function useUnsafePlayer() { 4 | const { player } = usePlayerState(); 5 | 6 | return player; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/players/table/players-table-context.ts: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react'; 2 | import type { PlayerTable } from 'csdm/common/types/player-table'; 3 | import type { TableInstance } from 'csdm/ui/components/table/table-types'; 4 | 5 | export const PlayersTableContext = createContext | null>(null); 6 | -------------------------------------------------------------------------------- /src/ui/players/use-fuzzy-search-text.ts: -------------------------------------------------------------------------------- 1 | import { usePlayersState } from './use-players-state'; 2 | 3 | export function useFuzzySearchText() { 4 | const state = usePlayersState(); 5 | 6 | return state.fuzzySearchText; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/players/use-players-state.ts: -------------------------------------------------------------------------------- 1 | import { useSelector } from 'csdm/ui/store/use-selector'; 2 | import type { PlayersState } from './players-reducer'; 3 | 4 | export function usePlayersState(): PlayersState { 5 | const state = useSelector((state) => state.players); 6 | 7 | return state; 8 | } 9 | -------------------------------------------------------------------------------- /src/ui/players/use-players-status.ts: -------------------------------------------------------------------------------- 1 | import { usePlayersState } from './use-players-state'; 2 | 3 | export function usePlayersStatus() { 4 | const state = usePlayersState(); 5 | 6 | return state.status; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/players/use-players.ts: -------------------------------------------------------------------------------- 1 | import { usePlayersState } from './use-players-state'; 2 | 3 | export function usePlayers() { 4 | const state = usePlayersState(); 5 | 6 | return state.entities; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/players/use-selected-players-steamids.ts: -------------------------------------------------------------------------------- 1 | import { usePlayersState } from './use-players-state'; 2 | 3 | export function useSelectedPlayerSteamIds(): string[] { 4 | const state = usePlayersState(); 5 | 6 | return state.selectedPlayerSteamIds; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/search/results/dot-separator.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export function DotSeparator() { 4 | return ; 5 | } 6 | -------------------------------------------------------------------------------- /src/ui/search/use-search-state.ts: -------------------------------------------------------------------------------- 1 | import { useSelector } from 'csdm/ui/store/use-selector'; 2 | 3 | export function useSearchState() { 4 | const state = useSelector((state) => state.search); 5 | 6 | return state; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/settings/analyze/use-analyze-settings.ts: -------------------------------------------------------------------------------- 1 | import { useSettings } from '../use-settings'; 2 | 3 | export function useAnalyzeSettings() { 4 | const settings = useSettings(); 5 | 6 | return settings.analyze; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/settings/bans/use-ban-settings.ts: -------------------------------------------------------------------------------- 1 | import { defaultSettings } from 'csdm/node/settings/default-settings'; 2 | import { useSettings } from 'csdm/ui/settings/use-settings'; 3 | 4 | export function useBanSettings() { 5 | const settings = useSettings(); 6 | 7 | return settings.ban ?? defaultSettings.ban; 8 | } 9 | -------------------------------------------------------------------------------- /src/ui/settings/database/use-database-settings.ts: -------------------------------------------------------------------------------- 1 | import { useSettings } from '../use-settings'; 2 | 3 | export function useDatabaseSettings() { 4 | const settings = useSettings(); 5 | 6 | return settings.database; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/settings/downloads/use-download-folder-path.ts: -------------------------------------------------------------------------------- 1 | import { useSettings } from '../use-settings'; 2 | 3 | export function useDownloadFolderPath() { 4 | const settings = useSettings(); 5 | 6 | return settings.download.folderPath; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/settings/folders/folder-actions.ts: -------------------------------------------------------------------------------- 1 | import { createAction } from '@reduxjs/toolkit'; 2 | 3 | export const folderAdded = createAction('settings/folders/added'); 4 | export const folderRemoved = createAction('settings/folders/removed'); 5 | export const folderUpdated = createAction('settings/folders/updated'); 6 | -------------------------------------------------------------------------------- /src/ui/settings/folders/use-current-demo-folder.ts: -------------------------------------------------------------------------------- 1 | import { useDemosSettings } from './use-demos-settings'; 2 | 3 | export function useCurrentDemoFolder() { 4 | const demosSettings = useDemosSettings(); 5 | 6 | return demosSettings.currentFolderPath; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/settings/folders/use-demos-settings.ts: -------------------------------------------------------------------------------- 1 | import { useSettings } from '../use-settings'; 2 | 3 | export function useDemosSettings() { 4 | const settings = useSettings(); 5 | 6 | return settings.demos; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/settings/folders/use-folders.ts: -------------------------------------------------------------------------------- 1 | import { useSettings } from '../use-settings'; 2 | 3 | export function useFolders() { 4 | const settings = useSettings(); 5 | 6 | return settings.folders; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/settings/maps/map-dialog/field-error.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | type Props = { 4 | error?: string | undefined; 5 | }; 6 | 7 | export function FieldError({ error }: Props) { 8 | if (error === undefined) { 9 | return null; 10 | } 11 | 12 | return

{error}

; 13 | } 14 | -------------------------------------------------------------------------------- /src/ui/settings/maps/map-dialog/use-map-form.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { MapFormContext } from 'csdm/ui/settings/maps/map-dialog/map-form-provider'; 3 | 4 | export function useMapForm() { 5 | const form = useContext(MapFormContext); 6 | 7 | return form; 8 | } 9 | -------------------------------------------------------------------------------- /src/ui/settings/playback/use-watch-settings.ts: -------------------------------------------------------------------------------- 1 | import { useSettings } from '../use-settings'; 2 | 3 | export function useWatchSettings() { 4 | const settings = useSettings(); 5 | 6 | return settings.playback; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/settings/ui/use-locale.ts: -------------------------------------------------------------------------------- 1 | import { useUiSettings } from './use-ui-settings'; 2 | 3 | export function useLocale() { 4 | const ui = useUiSettings(); 5 | 6 | return ui.locale; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/settings/ui/use-theme-name.ts: -------------------------------------------------------------------------------- 1 | import { useUiSettings } from './use-ui-settings'; 2 | 3 | export function useThemeName() { 4 | const ui = useUiSettings(); 5 | 6 | return ui.theme; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/settings/ui/use-ui-settings.ts: -------------------------------------------------------------------------------- 1 | import { useSettings } from '../use-settings'; 2 | 3 | export function useUiSettings() { 4 | const settings = useSettings(); 5 | 6 | return settings.ui; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/settings/use-pinned-player-steamid.ts: -------------------------------------------------------------------------------- 1 | import { useSettings } from './use-settings'; 2 | 3 | export function usePinnedPlayerSteamId() { 4 | const settings = useSettings(); 5 | 6 | return settings.pinnedPlayerSteamId; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/settings/use-settings.ts: -------------------------------------------------------------------------------- 1 | import { useSelector } from 'csdm/ui/store/use-selector'; 2 | 3 | export function useSettings() { 4 | const settings = useSelector((state) => state.settings); 5 | 6 | return settings; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/settings/video/ffmpeg/use-ffmpeg-settings.ts: -------------------------------------------------------------------------------- 1 | import { useVideoSettings } from '../use-video-settings'; 2 | 3 | export function useFfmpegSettings() { 4 | const { settings } = useVideoSettings(); 5 | 6 | return settings.ffmpegSettings; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/shared/build-player-steam-profile-url.ts: -------------------------------------------------------------------------------- 1 | export function buildPlayerSteamProfileUrl(steamId: string) { 2 | return `https://steamcommunity.com/profiles/${steamId}`; 3 | } 4 | -------------------------------------------------------------------------------- /src/ui/shared/element-ids.ts: -------------------------------------------------------------------------------- 1 | export const APP_ELEMENT_ID = 'app'; 2 | export const SETTINGS_ELEMENT_ID = 'settings'; 3 | -------------------------------------------------------------------------------- /src/ui/shared/get-css-variable-value.ts: -------------------------------------------------------------------------------- 1 | export function getCssVariableValue(variableName: string) { 2 | return window.getComputedStyle(document.documentElement).getPropertyValue(variableName).trim(); 3 | } 4 | -------------------------------------------------------------------------------- /src/ui/shared/get-premier-rank-tier.ts: -------------------------------------------------------------------------------- 1 | import type { PremierRank } from 'csdm/common/types/counter-strike'; 2 | 3 | export function getPremierRankTier(rank: PremierRank) { 4 | const remappedRating = Math.floor(rank / 1000.0 / 5); 5 | const clampedRating = Math.max(0, Math.min(remappedRating, 6)); 6 | 7 | return clampedRating; 8 | } 9 | -------------------------------------------------------------------------------- /src/ui/store/use-dispatch.ts: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line 2 | import { useDispatch as useDispatchRedux } from 'react-redux'; 3 | import type { store } from './store'; 4 | 5 | type AppDispatch = typeof store.dispatch; 6 | 7 | export const useDispatch = useDispatchRedux.withTypes(); 8 | -------------------------------------------------------------------------------- /src/ui/store/use-selector.ts: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line 2 | import { useSelector as useSelectorRedux } from 'react-redux'; 3 | import type { RootState } from './reducers'; 4 | 5 | export const useSelector = useSelectorRedux.withTypes(); 6 | -------------------------------------------------------------------------------- /src/ui/styles/InterVariable.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/src/ui/styles/InterVariable.woff2 -------------------------------------------------------------------------------- /src/ui/styles/fonts.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Inter var'; 3 | font-style: normal; 4 | font-weight: 100 900; 5 | font-display: swap; 6 | src: url('./InterVariable.woff2') format('woff2'); 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/styles/get-team-color.ts: -------------------------------------------------------------------------------- 1 | import { TeamNumber } from 'csdm/common/types/counter-strike'; 2 | 3 | export function getTeamColor(teamNumber: TeamNumber) { 4 | return teamNumber === TeamNumber.CT ? '#378ef0' : '#f29423'; 5 | } 6 | -------------------------------------------------------------------------------- /src/ui/styles/get-team-score-class-name.ts: -------------------------------------------------------------------------------- 1 | export function getTeamScoreClassName(score: number, oppositeScore: number) { 2 | if (score === oppositeScore) { 3 | return 'text-blue-400'; 4 | } 5 | 6 | return score > oppositeScore ? 'text-green-400' : 'text-red-400'; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/styles/third-parties.css: -------------------------------------------------------------------------------- 1 | @import './react-day-picker.css'; 2 | @import './milkdown.css'; 3 | -------------------------------------------------------------------------------- /src/ui/tags/use-tags.ts: -------------------------------------------------------------------------------- 1 | import { useSelector } from 'csdm/ui/store/use-selector'; 2 | 3 | export function useTags() { 4 | const tags = useSelector((state) => state.tags); 5 | 6 | return tags; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/team/heatmap/use-heatmap-state.ts: -------------------------------------------------------------------------------- 1 | import { useSelector } from 'csdm/ui/store/use-selector'; 2 | 3 | export function useHeatmapState() { 4 | return useSelector((state) => state.team.heatmap); 5 | } 6 | -------------------------------------------------------------------------------- /src/ui/team/maps/team-maps.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { useTeam } from '../use-team'; 3 | import { MapsStats } from 'csdm/ui/components/maps-stats'; 4 | 5 | export function TeamMaps() { 6 | const { mapsStats } = useTeam(); 7 | 8 | return ; 9 | } 10 | -------------------------------------------------------------------------------- /src/ui/team/matches/use-selected-match-checksums.ts: -------------------------------------------------------------------------------- 1 | import { useTeamState } from '../use-team-state'; 2 | 3 | export function useSelectedMatchChecksums() { 4 | const { selectedMatchChecksums } = useTeamState(); 5 | 6 | return selectedMatchChecksums; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/team/overview/team-clutches.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Clutches } from 'csdm/ui/components/panels/clutches'; 3 | import { useTeam } from '../use-team'; 4 | 5 | export function TeamClutches() { 6 | const { clutches } = useTeam(); 7 | 8 | return ; 9 | } 10 | -------------------------------------------------------------------------------- /src/ui/team/overview/team-last-matches.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { useTeam } from '../use-team'; 3 | import { LastMatches } from 'csdm/ui/components/last-matches'; 4 | 5 | export function TeamLastMatches() { 6 | const { lastMatches } = useTeam(); 7 | 8 | return ; 9 | } 10 | -------------------------------------------------------------------------------- /src/ui/team/team-action-bar.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { ActionBar } from 'csdm/ui/components/action-bar'; 3 | import { TeamFilterDropdown } from './team-filter-dropdown'; 4 | import { TeamName } from './team-name'; 5 | 6 | export function TeamActionBar() { 7 | return } right={} />; 8 | } 9 | -------------------------------------------------------------------------------- /src/ui/team/use-current-team-name.ts: -------------------------------------------------------------------------------- 1 | import { useParams } from 'react-router'; 2 | 3 | export function useCurrentTeamName() { 4 | const { name } = useParams<'name'>(); 5 | if (typeof name !== 'string') { 6 | throw new TypeError('team name is not a string'); 7 | } 8 | 9 | return name; 10 | } 11 | -------------------------------------------------------------------------------- /src/ui/team/use-team-state.ts: -------------------------------------------------------------------------------- 1 | import { useSelector } from 'csdm/ui/store/use-selector'; 2 | 3 | export function useTeamState() { 4 | const state = useSelector((state) => state.team); 5 | 6 | return state; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/team/use-team.ts: -------------------------------------------------------------------------------- 1 | import { useTeamState } from './use-team-state'; 2 | 3 | export function useTeam() { 4 | const { team } = useTeamState(); 5 | 6 | if (!team) { 7 | throw new Error('team not defined'); 8 | } 9 | 10 | return team; 11 | } 12 | -------------------------------------------------------------------------------- /src/ui/team/use-unsafe-team.ts: -------------------------------------------------------------------------------- 1 | import { useTeamState } from './use-team-state'; 2 | 3 | export function useUnsafeTeam() { 4 | const { team } = useTeamState(); 5 | 6 | return team; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/teams/table/teams-table-context.ts: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react'; 2 | import type { TableInstance } from 'csdm/ui/components/table/table-types'; 3 | import type { TeamTable } from 'csdm/common/types/team-table'; 4 | 5 | export const TeamsTableContext = createContext | null>(null); 6 | -------------------------------------------------------------------------------- /src/ui/teams/use-fuzzy-search-text.ts: -------------------------------------------------------------------------------- 1 | import { useTeamsState } from './use-teams-state'; 2 | 3 | export function useFuzzySearchText() { 4 | const state = useTeamsState(); 5 | 6 | return state.fuzzySearchText; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/teams/use-selected-team-names.ts: -------------------------------------------------------------------------------- 1 | import { useTeamsState } from './use-teams-state'; 2 | 3 | export function useSelectedTeamNames() { 4 | const state = useTeamsState(); 5 | 6 | return state.selectedTeamNames; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/teams/use-teams-state.ts: -------------------------------------------------------------------------------- 1 | import { useSelector } from 'csdm/ui/store/use-selector'; 2 | 3 | export function useTeamsState() { 4 | const state = useSelector((state) => state.teams); 5 | 6 | return state; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/teams/use-teams-status.ts: -------------------------------------------------------------------------------- 1 | import { useTeamsState } from './use-teams-state'; 2 | 3 | export function useTeamsStatus() { 4 | const state = useTeamsState(); 5 | 6 | return state.status; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/teams/use-teams.ts: -------------------------------------------------------------------------------- 1 | import { useTeamsState } from './use-teams-state'; 2 | 3 | export function useTeams() { 4 | const state = useTeamsState(); 5 | 6 | return state.entities; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/title-bar/window-controls/close-icon.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export function CloseIcon() { 4 | return ( 5 | 8 | ); 9 | } 10 | -------------------------------------------------------------------------------- /src/ui/title-bar/window-controls/maximize-icon.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export function MaximizeIcon() { 4 | return ( 5 | 8 | ); 9 | } 10 | -------------------------------------------------------------------------------- /src/ui/title-bar/window-controls/minimize-icon.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export function MinimizeIcon() { 4 | return ( 5 | 8 | ); 9 | } 10 | -------------------------------------------------------------------------------- /src/ui/videos/use-is-video-queue-paused.ts: -------------------------------------------------------------------------------- 1 | import { useVideosState } from './use-videos-state'; 2 | 3 | export function useVideoQueuePaused() { 4 | const state = useVideosState(); 5 | 6 | return state.isPaused; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/videos/use-videos-state.ts: -------------------------------------------------------------------------------- 1 | import { useSelector } from 'csdm/ui/store/use-selector'; 2 | import type { VideosState } from './videos-reducer'; 3 | 4 | export function useVideosState(): VideosState { 5 | const state = useSelector((state) => state.videos); 6 | 7 | return state; 8 | } 9 | -------------------------------------------------------------------------------- /src/ui/videos/use-videos.ts: -------------------------------------------------------------------------------- 1 | import { useVideosState } from './use-videos-state'; 2 | 3 | export function useVideos() { 4 | const state = useVideosState(); 5 | 6 | return [...state.videos].sort((videoA, videoB) => { 7 | return new Date(videoA.date).getTime() - new Date(videoB.date).getTime(); 8 | }); 9 | } 10 | -------------------------------------------------------------------------------- /static/csdm.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/csdm.dll -------------------------------------------------------------------------------- /static/csdm.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/csdm.dylib -------------------------------------------------------------------------------- /static/csdm.vdf: -------------------------------------------------------------------------------- 1 | "plugin" 2 | { 3 | "file" "addons/csdm" 4 | } 5 | -------------------------------------------------------------------------------- /static/csdm_client.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/csdm_client.so -------------------------------------------------------------------------------- /static/images/avatar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/avatar.jpg -------------------------------------------------------------------------------- /static/images/grenades/decoy-detonate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/grenades/decoy-detonate.png -------------------------------------------------------------------------------- /static/images/grenades/flashbang-detonate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/grenades/flashbang-detonate.png -------------------------------------------------------------------------------- /static/images/grenades/he-detonate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/grenades/he-detonate.png -------------------------------------------------------------------------------- /static/images/grenades/molotov-detonate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/grenades/molotov-detonate.png -------------------------------------------------------------------------------- /static/images/grenades/smoke-detonate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/grenades/smoke-detonate.png -------------------------------------------------------------------------------- /static/images/grenades/unknown-grenade.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/grenades/unknown-grenade.png -------------------------------------------------------------------------------- /static/images/maps/cs2/radars/cs_agency.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/radars/cs_agency.png -------------------------------------------------------------------------------- /static/images/maps/cs2/radars/cs_assault.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/radars/cs_assault.png -------------------------------------------------------------------------------- /static/images/maps/cs2/radars/cs_italy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/radars/cs_italy.png -------------------------------------------------------------------------------- /static/images/maps/cs2/radars/cs_militia.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/radars/cs_militia.png -------------------------------------------------------------------------------- /static/images/maps/cs2/radars/cs_militia_lower.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/radars/cs_militia_lower.png -------------------------------------------------------------------------------- /static/images/maps/cs2/radars/cs_office.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/radars/cs_office.png -------------------------------------------------------------------------------- /static/images/maps/cs2/radars/de_ancient.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/radars/de_ancient.png -------------------------------------------------------------------------------- /static/images/maps/cs2/radars/de_anubis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/radars/de_anubis.png -------------------------------------------------------------------------------- /static/images/maps/cs2/radars/de_assembly.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/radars/de_assembly.png -------------------------------------------------------------------------------- /static/images/maps/cs2/radars/de_aztec.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/radars/de_aztec.png -------------------------------------------------------------------------------- /static/images/maps/cs2/radars/de_basalt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/radars/de_basalt.png -------------------------------------------------------------------------------- /static/images/maps/cs2/radars/de_brewery.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/radars/de_brewery.png -------------------------------------------------------------------------------- /static/images/maps/cs2/radars/de_cache.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/radars/de_cache.png -------------------------------------------------------------------------------- /static/images/maps/cs2/radars/de_canals.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/radars/de_canals.png -------------------------------------------------------------------------------- /static/images/maps/cs2/radars/de_cbble.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/radars/de_cbble.png -------------------------------------------------------------------------------- /static/images/maps/cs2/radars/de_dogtown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/radars/de_dogtown.png -------------------------------------------------------------------------------- /static/images/maps/cs2/radars/de_dust.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/radars/de_dust.png -------------------------------------------------------------------------------- /static/images/maps/cs2/radars/de_dust2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/radars/de_dust2.png -------------------------------------------------------------------------------- /static/images/maps/cs2/radars/de_edin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/radars/de_edin.png -------------------------------------------------------------------------------- /static/images/maps/cs2/radars/de_grail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/radars/de_grail.png -------------------------------------------------------------------------------- /static/images/maps/cs2/radars/de_inferno.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/radars/de_inferno.png -------------------------------------------------------------------------------- /static/images/maps/cs2/radars/de_jura.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/radars/de_jura.png -------------------------------------------------------------------------------- /static/images/maps/cs2/radars/de_memento.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/radars/de_memento.png -------------------------------------------------------------------------------- /static/images/maps/cs2/radars/de_mills.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/radars/de_mills.png -------------------------------------------------------------------------------- /static/images/maps/cs2/radars/de_mirage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/radars/de_mirage.png -------------------------------------------------------------------------------- /static/images/maps/cs2/radars/de_nuke.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/radars/de_nuke.png -------------------------------------------------------------------------------- /static/images/maps/cs2/radars/de_nuke_lower.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/radars/de_nuke_lower.png -------------------------------------------------------------------------------- /static/images/maps/cs2/radars/de_overpass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/radars/de_overpass.png -------------------------------------------------------------------------------- /static/images/maps/cs2/radars/de_palais.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/radars/de_palais.png -------------------------------------------------------------------------------- /static/images/maps/cs2/radars/de_palais_lower.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/radars/de_palais_lower.png -------------------------------------------------------------------------------- /static/images/maps/cs2/radars/de_thera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/radars/de_thera.png -------------------------------------------------------------------------------- /static/images/maps/cs2/radars/de_thera_lower.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/radars/de_thera_lower.png -------------------------------------------------------------------------------- /static/images/maps/cs2/radars/de_train.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/radars/de_train.png -------------------------------------------------------------------------------- /static/images/maps/cs2/radars/de_train_lower.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/radars/de_train_lower.png -------------------------------------------------------------------------------- /static/images/maps/cs2/radars/de_vertigo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/radars/de_vertigo.png -------------------------------------------------------------------------------- /static/images/maps/cs2/radars/de_vertigo_lower.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/radars/de_vertigo_lower.png -------------------------------------------------------------------------------- /static/images/maps/cs2/radars/de_whistle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/radars/de_whistle.png -------------------------------------------------------------------------------- /static/images/maps/cs2/thumbnails/cs_agency.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/thumbnails/cs_agency.png -------------------------------------------------------------------------------- /static/images/maps/cs2/thumbnails/cs_assault.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/thumbnails/cs_assault.png -------------------------------------------------------------------------------- /static/images/maps/cs2/thumbnails/cs_italy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/thumbnails/cs_italy.png -------------------------------------------------------------------------------- /static/images/maps/cs2/thumbnails/cs_militia.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/thumbnails/cs_militia.png -------------------------------------------------------------------------------- /static/images/maps/cs2/thumbnails/cs_office.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/thumbnails/cs_office.png -------------------------------------------------------------------------------- /static/images/maps/cs2/thumbnails/de_ancient.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/thumbnails/de_ancient.png -------------------------------------------------------------------------------- /static/images/maps/cs2/thumbnails/de_anubis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/thumbnails/de_anubis.png -------------------------------------------------------------------------------- /static/images/maps/cs2/thumbnails/de_assembly.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/thumbnails/de_assembly.png -------------------------------------------------------------------------------- /static/images/maps/cs2/thumbnails/de_aztec.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/thumbnails/de_aztec.png -------------------------------------------------------------------------------- /static/images/maps/cs2/thumbnails/de_basalt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/thumbnails/de_basalt.png -------------------------------------------------------------------------------- /static/images/maps/cs2/thumbnails/de_brewery.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/thumbnails/de_brewery.png -------------------------------------------------------------------------------- /static/images/maps/cs2/thumbnails/de_cache.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/thumbnails/de_cache.png -------------------------------------------------------------------------------- /static/images/maps/cs2/thumbnails/de_canals.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/thumbnails/de_canals.png -------------------------------------------------------------------------------- /static/images/maps/cs2/thumbnails/de_cbble.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/thumbnails/de_cbble.png -------------------------------------------------------------------------------- /static/images/maps/cs2/thumbnails/de_dogtown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/thumbnails/de_dogtown.png -------------------------------------------------------------------------------- /static/images/maps/cs2/thumbnails/de_dust.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/thumbnails/de_dust.png -------------------------------------------------------------------------------- /static/images/maps/cs2/thumbnails/de_dust2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/thumbnails/de_dust2.png -------------------------------------------------------------------------------- /static/images/maps/cs2/thumbnails/de_edin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/thumbnails/de_edin.png -------------------------------------------------------------------------------- /static/images/maps/cs2/thumbnails/de_grail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/thumbnails/de_grail.png -------------------------------------------------------------------------------- /static/images/maps/cs2/thumbnails/de_inferno.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/thumbnails/de_inferno.png -------------------------------------------------------------------------------- /static/images/maps/cs2/thumbnails/de_jura.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/thumbnails/de_jura.png -------------------------------------------------------------------------------- /static/images/maps/cs2/thumbnails/de_memento.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/thumbnails/de_memento.png -------------------------------------------------------------------------------- /static/images/maps/cs2/thumbnails/de_mills.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/thumbnails/de_mills.png -------------------------------------------------------------------------------- /static/images/maps/cs2/thumbnails/de_mirage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/thumbnails/de_mirage.png -------------------------------------------------------------------------------- /static/images/maps/cs2/thumbnails/de_nuke.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/thumbnails/de_nuke.png -------------------------------------------------------------------------------- /static/images/maps/cs2/thumbnails/de_overpass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/thumbnails/de_overpass.png -------------------------------------------------------------------------------- /static/images/maps/cs2/thumbnails/de_palais.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/thumbnails/de_palais.png -------------------------------------------------------------------------------- /static/images/maps/cs2/thumbnails/de_thera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/thumbnails/de_thera.png -------------------------------------------------------------------------------- /static/images/maps/cs2/thumbnails/de_train.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/thumbnails/de_train.png -------------------------------------------------------------------------------- /static/images/maps/cs2/thumbnails/de_vertigo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/thumbnails/de_vertigo.png -------------------------------------------------------------------------------- /static/images/maps/cs2/thumbnails/de_whistle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/cs2/thumbnails/de_whistle.png -------------------------------------------------------------------------------- /static/images/maps/csgo/radars/cs_assault.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/csgo/radars/cs_assault.png -------------------------------------------------------------------------------- /static/images/maps/csgo/radars/cs_italy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/csgo/radars/cs_italy.png -------------------------------------------------------------------------------- /static/images/maps/csgo/radars/cs_militia.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/csgo/radars/cs_militia.png -------------------------------------------------------------------------------- /static/images/maps/csgo/radars/cs_militia_lower.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/csgo/radars/cs_militia_lower.png -------------------------------------------------------------------------------- /static/images/maps/csgo/radars/cs_office.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/csgo/radars/cs_office.png -------------------------------------------------------------------------------- /static/images/maps/csgo/radars/de_ancient.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/csgo/radars/de_ancient.png -------------------------------------------------------------------------------- /static/images/maps/csgo/radars/de_anubis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/csgo/radars/de_anubis.png -------------------------------------------------------------------------------- /static/images/maps/csgo/radars/de_aztec.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/csgo/radars/de_aztec.png -------------------------------------------------------------------------------- /static/images/maps/csgo/radars/de_cache.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/csgo/radars/de_cache.png -------------------------------------------------------------------------------- /static/images/maps/csgo/radars/de_canals.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/csgo/radars/de_canals.png -------------------------------------------------------------------------------- /static/images/maps/csgo/radars/de_cbble.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/csgo/radars/de_cbble.png -------------------------------------------------------------------------------- /static/images/maps/csgo/radars/de_dust.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/csgo/radars/de_dust.png -------------------------------------------------------------------------------- /static/images/maps/csgo/radars/de_dust2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/csgo/radars/de_dust2.png -------------------------------------------------------------------------------- /static/images/maps/csgo/radars/de_inferno.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/csgo/radars/de_inferno.png -------------------------------------------------------------------------------- /static/images/maps/csgo/radars/de_mirage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/csgo/radars/de_mirage.png -------------------------------------------------------------------------------- /static/images/maps/csgo/radars/de_nuke.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/csgo/radars/de_nuke.png -------------------------------------------------------------------------------- /static/images/maps/csgo/radars/de_nuke_lower.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/csgo/radars/de_nuke_lower.png -------------------------------------------------------------------------------- /static/images/maps/csgo/radars/de_overpass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/csgo/radars/de_overpass.png -------------------------------------------------------------------------------- /static/images/maps/csgo/radars/de_train.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/csgo/radars/de_train.png -------------------------------------------------------------------------------- /static/images/maps/csgo/radars/de_vertigo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/csgo/radars/de_vertigo.png -------------------------------------------------------------------------------- /static/images/maps/csgo/radars/de_vertigo_lower.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/csgo/radars/de_vertigo_lower.png -------------------------------------------------------------------------------- /static/images/maps/csgo/thumbnails/cs_assault.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/csgo/thumbnails/cs_assault.png -------------------------------------------------------------------------------- /static/images/maps/csgo/thumbnails/cs_italy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/csgo/thumbnails/cs_italy.png -------------------------------------------------------------------------------- /static/images/maps/csgo/thumbnails/cs_militia.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/csgo/thumbnails/cs_militia.png -------------------------------------------------------------------------------- /static/images/maps/csgo/thumbnails/cs_office.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/csgo/thumbnails/cs_office.png -------------------------------------------------------------------------------- /static/images/maps/csgo/thumbnails/de_ancient.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/csgo/thumbnails/de_ancient.png -------------------------------------------------------------------------------- /static/images/maps/csgo/thumbnails/de_anubis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/csgo/thumbnails/de_anubis.png -------------------------------------------------------------------------------- /static/images/maps/csgo/thumbnails/de_aztec.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/csgo/thumbnails/de_aztec.png -------------------------------------------------------------------------------- /static/images/maps/csgo/thumbnails/de_cache.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/csgo/thumbnails/de_cache.png -------------------------------------------------------------------------------- /static/images/maps/csgo/thumbnails/de_canals.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/csgo/thumbnails/de_canals.png -------------------------------------------------------------------------------- /static/images/maps/csgo/thumbnails/de_cbble.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/csgo/thumbnails/de_cbble.png -------------------------------------------------------------------------------- /static/images/maps/csgo/thumbnails/de_dust.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/csgo/thumbnails/de_dust.png -------------------------------------------------------------------------------- /static/images/maps/csgo/thumbnails/de_dust2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/csgo/thumbnails/de_dust2.png -------------------------------------------------------------------------------- /static/images/maps/csgo/thumbnails/de_inferno.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/csgo/thumbnails/de_inferno.png -------------------------------------------------------------------------------- /static/images/maps/csgo/thumbnails/de_mirage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/csgo/thumbnails/de_mirage.png -------------------------------------------------------------------------------- /static/images/maps/csgo/thumbnails/de_nuke.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/csgo/thumbnails/de_nuke.png -------------------------------------------------------------------------------- /static/images/maps/csgo/thumbnails/de_overpass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/csgo/thumbnails/de_overpass.png -------------------------------------------------------------------------------- /static/images/maps/csgo/thumbnails/de_train.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/csgo/thumbnails/de_train.png -------------------------------------------------------------------------------- /static/images/maps/csgo/thumbnails/de_vertigo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/csgo/thumbnails/de_vertigo.png -------------------------------------------------------------------------------- /static/images/maps/thumbnail_unknown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/maps/thumbnail_unknown.png -------------------------------------------------------------------------------- /static/images/ranks/competitive/0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/ranks/competitive/0.png -------------------------------------------------------------------------------- /static/images/ranks/competitive/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/ranks/competitive/1.png -------------------------------------------------------------------------------- /static/images/ranks/competitive/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/ranks/competitive/10.png -------------------------------------------------------------------------------- /static/images/ranks/competitive/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/ranks/competitive/11.png -------------------------------------------------------------------------------- /static/images/ranks/competitive/12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/ranks/competitive/12.png -------------------------------------------------------------------------------- /static/images/ranks/competitive/13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/ranks/competitive/13.png -------------------------------------------------------------------------------- /static/images/ranks/competitive/14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/ranks/competitive/14.png -------------------------------------------------------------------------------- /static/images/ranks/competitive/15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/ranks/competitive/15.png -------------------------------------------------------------------------------- /static/images/ranks/competitive/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/ranks/competitive/16.png -------------------------------------------------------------------------------- /static/images/ranks/competitive/17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/ranks/competitive/17.png -------------------------------------------------------------------------------- /static/images/ranks/competitive/18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/ranks/competitive/18.png -------------------------------------------------------------------------------- /static/images/ranks/competitive/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/ranks/competitive/2.png -------------------------------------------------------------------------------- /static/images/ranks/competitive/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/ranks/competitive/3.png -------------------------------------------------------------------------------- /static/images/ranks/competitive/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/ranks/competitive/4.png -------------------------------------------------------------------------------- /static/images/ranks/competitive/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/ranks/competitive/5.png -------------------------------------------------------------------------------- /static/images/ranks/competitive/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/ranks/competitive/6.png -------------------------------------------------------------------------------- /static/images/ranks/competitive/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/ranks/competitive/7.png -------------------------------------------------------------------------------- /static/images/ranks/competitive/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/ranks/competitive/8.png -------------------------------------------------------------------------------- /static/images/ranks/competitive/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/ranks/competitive/9.png -------------------------------------------------------------------------------- /static/images/ranks/premier/tier-0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/ranks/premier/tier-0.png -------------------------------------------------------------------------------- /static/images/ranks/premier/tier-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/ranks/premier/tier-1.png -------------------------------------------------------------------------------- /static/images/ranks/premier/tier-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/ranks/premier/tier-2.png -------------------------------------------------------------------------------- /static/images/ranks/premier/tier-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/ranks/premier/tier-3.png -------------------------------------------------------------------------------- /static/images/ranks/premier/tier-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/ranks/premier/tier-4.png -------------------------------------------------------------------------------- /static/images/ranks/premier/tier-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/ranks/premier/tier-5.png -------------------------------------------------------------------------------- /static/images/ranks/premier/tier-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/ranks/premier/tier-6.png -------------------------------------------------------------------------------- /static/images/sources/5eplay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/sources/5eplay.png -------------------------------------------------------------------------------- /static/images/sources/cevo-back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/sources/cevo-back.png -------------------------------------------------------------------------------- /static/images/sources/cevo-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/sources/cevo-white.png -------------------------------------------------------------------------------- /static/images/sources/challengermode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/sources/challengermode.png -------------------------------------------------------------------------------- /static/images/sources/ebot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/sources/ebot.png -------------------------------------------------------------------------------- /static/images/sources/esea-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/sources/esea-black.png -------------------------------------------------------------------------------- /static/images/sources/esea-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/sources/esea-white.png -------------------------------------------------------------------------------- /static/images/sources/esl-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/sources/esl-black.png -------------------------------------------------------------------------------- /static/images/sources/esl-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/sources/esl-white.png -------------------------------------------------------------------------------- /static/images/sources/esplay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/sources/esplay.png -------------------------------------------------------------------------------- /static/images/sources/esportal-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/sources/esportal-black.png -------------------------------------------------------------------------------- /static/images/sources/esportal-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/sources/esportal-white.png -------------------------------------------------------------------------------- /static/images/sources/faceit-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/sources/faceit-black.png -------------------------------------------------------------------------------- /static/images/sources/faceit-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/sources/faceit-white.png -------------------------------------------------------------------------------- /static/images/sources/fastcup-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/sources/fastcup-black.png -------------------------------------------------------------------------------- /static/images/sources/fastcup-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/sources/fastcup-white.png -------------------------------------------------------------------------------- /static/images/sources/gamersclub-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/sources/gamersclub-black.png -------------------------------------------------------------------------------- /static/images/sources/gamersclub-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/sources/gamersclub-white.png -------------------------------------------------------------------------------- /static/images/sources/matchzy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/sources/matchzy.png -------------------------------------------------------------------------------- /static/images/sources/perfectworld-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/sources/perfectworld-black.png -------------------------------------------------------------------------------- /static/images/sources/perfectworld-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/sources/perfectworld-white.png -------------------------------------------------------------------------------- /static/images/sources/popflash-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/sources/popflash-black.png -------------------------------------------------------------------------------- /static/images/sources/popflash-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/sources/popflash-white.png -------------------------------------------------------------------------------- /static/images/sources/renown-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/sources/renown-black.png -------------------------------------------------------------------------------- /static/images/sources/renown-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/sources/renown-white.png -------------------------------------------------------------------------------- /static/images/sources/unknown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/sources/unknown.png -------------------------------------------------------------------------------- /static/images/sources/valve-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/sources/valve-black.png -------------------------------------------------------------------------------- /static/images/sources/valve-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/sources/valve-white.png -------------------------------------------------------------------------------- /static/images/tray/tray.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/tray/tray.ico -------------------------------------------------------------------------------- /static/images/tray/tray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/tray/tray.png -------------------------------------------------------------------------------- /static/images/tray/tray@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/tray/tray@2x.png -------------------------------------------------------------------------------- /static/images/tray/trayTemplate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/tray/trayTemplate.png -------------------------------------------------------------------------------- /static/images/tray/trayTemplate@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/images/tray/trayTemplate@2x.png -------------------------------------------------------------------------------- /static/libserver.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/libserver.so -------------------------------------------------------------------------------- /static/server.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akiver/cs-demo-manager/357ef485ada9e9fc6ffa4f7fb7ede7d9785604a9/static/server.dll -------------------------------------------------------------------------------- /types/ambient.d.ts: -------------------------------------------------------------------------------- 1 | // ambient type declarations for module that does not have type definitions 2 | declare module 'unbzip2-stream'; 3 | declare module 'source-map-support'; 4 | -------------------------------------------------------------------------------- /types/css.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.css'; 2 | -------------------------------------------------------------------------------- /types/deep-partial.d.ts: -------------------------------------------------------------------------------- 1 | type DeepPartial = { 2 | [P in keyof T]?: DeepPartial; 3 | }; 4 | -------------------------------------------------------------------------------- /types/github.d.ts: -------------------------------------------------------------------------------- 1 | interface GitHubAssetResponse { 2 | name: string; 3 | browser_download_url: string; 4 | } 5 | 6 | interface GitHubReleaseResponse { 7 | assets: GitHubAssetResponse[]; 8 | tag_name: string; 9 | prerelease: boolean; 10 | } 11 | -------------------------------------------------------------------------------- /types/image.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.jpg'; 2 | declare module '*.png'; 3 | declare module '*.gif'; 4 | -------------------------------------------------------------------------------- /types/po.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.po'; 2 | -------------------------------------------------------------------------------- /types/process.d.ts: -------------------------------------------------------------------------------- 1 | declare global { 2 | namespace NodeJS { 3 | interface ProcessEnv { 4 | LOG_DATABASE_QUERIES: string; 5 | PROCESS_NAME: string; 6 | STEAM_API_KEYS: string; 7 | FACEIT_API_KEY: string; 8 | VITE_DEV_SERVER_URL: string; 9 | } 10 | } 11 | } 12 | 13 | export {}; 14 | -------------------------------------------------------------------------------- /types/window.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | declare global { 4 | interface Window { 5 | crypto: { 6 | randomUUID: () => string; 7 | }; 8 | } 9 | } 10 | 11 | export {}; 12 | --------------------------------------------------------------------------------