Compare commits

..

97 Commits

Author SHA1 Message Date
Janis
1cac2ca77f change version in auth payload 2023-10-07 15:22:49 +02:00
Janis
f6bf559612 update to version 1.2.3 2023-10-07 15:22:30 +02:00
Janis
15f18ecf31 Merge branch 'main' of https://github.com/DerTyp7/ts5-obs-overlay 2023-10-07 15:20:47 +02:00
Janis
6998f7cbbf add github actions deploy 2023-10-07 15:20:46 +02:00
Janis
bb707b7450 Update README.md 2023-10-07 15:10:26 +02:00
Janis
1afc82ff93 Update dependabot.yml 2023-09-08 11:00:45 +02:00
Janis
9f11fa0241 updated version 2023-08-03 00:14:58 +02:00
Janis
33a6e20e00 updated api version 2023-08-03 00:13:52 +02:00
Janis
5d1b32eda3 updated api version 2023-08-02 23:51:06 +02:00
Janis
2f040b1b59 "@typescript-eslint/parser": "^6.2.1", 2023-08-02 23:44:41 +02:00
Janis
8808785bab Merge pull request #45 from DerTyp7/dependabot/npm_and_yarn/react-router-dom-6.14.2
Bump react-router-dom from 6.14.1 to 6.14.2
2023-08-02 23:42:43 +02:00
Janis
4787124f3f Merge pull request #46 from DerTyp7/dependabot/npm_and_yarn/sass-1.64.1
Bump sass from 1.63.6 to 1.64.1
2023-08-02 23:42:36 +02:00
Janis
6884abb1b8 Merge pull request #49 from DerTyp7/dependabot/npm_and_yarn/vite-4.4.7
Bump vite from 4.4.4 to 4.4.7
2023-08-02 23:42:30 +02:00
Janis
e1d9ff1145 Merge pull request #50 from DerTyp7/dependabot/npm_and_yarn/typescript-eslint/eslint-plugin-6.2.0
Bump @typescript-eslint/eslint-plugin from 5.59.8 to 6.2.0
2023-08-02 23:42:24 +02:00
Janis
d824d5023c Merge pull request #51 from DerTyp7/dependabot/npm_and_yarn/types/node-20.4.5
Bump @types/node from 20.4.2 to 20.4.5
2023-08-02 23:42:16 +02:00
dependabot[bot]
4493a1e97f Bump @types/node from 20.4.2 to 20.4.5
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 20.4.2 to 20.4.5.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-31 01:25:02 +00:00
dependabot[bot]
79f78defbe Bump @typescript-eslint/eslint-plugin from 5.59.8 to 6.2.0
Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 5.59.8 to 6.2.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.2.0/packages/eslint-plugin)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-31 01:23:47 +00:00
dependabot[bot]
074e7b95e9 Bump vite from 4.4.4 to 4.4.7
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 4.4.4 to 4.4.7.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v4.4.7/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-31 01:22:04 +00:00
dependabot[bot]
72c9e8d51e Bump sass from 1.63.6 to 1.64.1
Bumps [sass](https://github.com/sass/dart-sass) from 1.63.6 to 1.64.1.
- [Release notes](https://github.com/sass/dart-sass/releases)
- [Changelog](https://github.com/sass/dart-sass/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sass/dart-sass/compare/1.63.6...1.64.1)

---
updated-dependencies:
- dependency-name: sass
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-24 02:03:13 +00:00
dependabot[bot]
c6b151384f Bump react-router-dom from 6.14.1 to 6.14.2
Bumps [react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom) from 6.14.1 to 6.14.2.
- [Release notes](https://github.com/remix-run/react-router/releases)
- [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/CHANGELOG.md)
- [Commits](https://github.com/remix-run/react-router/commits/react-router-dom@6.14.2/packages/react-router-dom)

---
updated-dependencies:
- dependency-name: react-router-dom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-24 02:03:04 +00:00
Janis
e5aef6eea8 update change version to 1.2.0 2023-07-24 02:35:51 +02:00
Janis
b541edbb58 Merge pull request #43 from DerTyp7/refactor_custom-react-hook
Refactor custom react hook
2023-07-24 02:33:44 +02:00
Janis
8587271283 change version to 1.2.0 2023-07-24 02:33:21 +02:00
Janis
728afd5d1c remove handler from this package and use seperate package 2023-07-24 01:59:57 +02:00
Janis
793ae71186 better readability 2023-07-24 00:50:08 +02:00
Janis
da518bbd1e add searchparams port 2023-07-24 00:47:55 +02:00
Janis
bd5ecc1ab0 outsource to react hook 2023-07-24 00:46:00 +02:00
Janis
04112657e6 change version to 1.1.3 2023-07-24 00:36:58 +02:00
Janis
02a572c316 Merge pull request #38 from DerTyp7/dependabot/npm_and_yarn/types/node-20.4.2
Bump @types/node from 20.4.1 to 20.4.2
2023-07-24 00:33:47 +02:00
Janis
c34c98fe86 Merge pull request #39 from DerTyp7/dependabot/npm_and_yarn/types/react-dom-18.2.7
Bump @types/react-dom from 18.2.4 to 18.2.7
2023-07-24 00:33:42 +02:00
Janis
7e729c2055 Merge pull request #40 from DerTyp7/dependabot/npm_and_yarn/eslint-8.45.0
Bump eslint from 8.44.0 to 8.45.0
2023-07-24 00:33:35 +02:00
Janis
f304133f34 Merge pull request #41 from DerTyp7/dependabot/npm_and_yarn/vite-4.4.4
Bump vite from 4.4.2 to 4.4.4
2023-07-24 00:33:29 +02:00
Janis
989fff4b72 Merge pull request #42 from DerTyp7/dependabot/npm_and_yarn/typescript-eslint/parser-5.62.0
Bump @typescript-eslint/parser from 5.59.8 to 5.62.0
2023-07-24 00:33:20 +02:00
dependabot[bot]
585622cec7 Bump @typescript-eslint/parser from 5.59.8 to 5.62.0
Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 5.59.8 to 5.62.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v5.62.0/packages/parser)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/parser"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-17 01:19:29 +00:00
dependabot[bot]
e89cdb40a2 Bump vite from 4.4.2 to 4.4.4
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 4.4.2 to 4.4.4.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v4.4.4/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-17 01:19:00 +00:00
dependabot[bot]
7f866ae2c1 Bump eslint from 8.44.0 to 8.45.0
Bumps [eslint](https://github.com/eslint/eslint) from 8.44.0 to 8.45.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v8.44.0...v8.45.0)

---
updated-dependencies:
- dependency-name: eslint
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-17 01:18:39 +00:00
dependabot[bot]
e326e93f2f Bump @types/react-dom from 18.2.4 to 18.2.7
Bumps [@types/react-dom](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react-dom) from 18.2.4 to 18.2.7.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react-dom)

---
updated-dependencies:
- dependency-name: "@types/react-dom"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-17 01:18:24 +00:00
dependabot[bot]
767bd39806 Bump @types/node from 20.4.1 to 20.4.2
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 20.4.1 to 20.4.2.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-17 01:18:13 +00:00
Janis
a5432884f0 Merge pull request #32 from DerTyp7/dependabot/npm_and_yarn/vite-4.4.2
Bump vite from 4.3.9 to 4.4.2
2023-07-11 12:36:11 +02:00
dependabot[bot]
4c8f748472 Bump vite from 4.3.9 to 4.4.2
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 4.3.9 to 4.4.2.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v4.4.2/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-11 10:36:01 +00:00
Janis
7ba46e4518 Merge pull request #33 from DerTyp7/dependabot/npm_and_yarn/typescript-5.1.6
Bump typescript from 5.1.3 to 5.1.6
2023-07-11 12:35:15 +02:00
dependabot[bot]
fb17fe7657 Bump typescript from 5.1.3 to 5.1.6
Bumps [typescript](https://github.com/Microsoft/TypeScript) from 5.1.3 to 5.1.6.
- [Release notes](https://github.com/Microsoft/TypeScript/releases)
- [Commits](https://github.com/Microsoft/TypeScript/compare/v5.1.3...v5.1.6)

---
updated-dependencies:
- dependency-name: typescript
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-11 10:34:41 +00:00
Janis
a09212cc21 Merge pull request #34 from DerTyp7/dependabot/npm_and_yarn/eslint-8.44.0
Bump eslint from 8.42.0 to 8.44.0
2023-07-11 12:34:05 +02:00
Janis
6a1c32e6e8 Merge pull request #37 from DerTyp7/dependabot/npm_and_yarn/semver-6.3.1
Bump semver from 6.3.0 to 6.3.1
2023-07-11 12:33:01 +02:00
DerTyp7
2152aa64cb add common issues to readme 2023-07-11 12:32:04 +02:00
dependabot[bot]
1ca70bbabd Bump eslint from 8.42.0 to 8.44.0
Bumps [eslint](https://github.com/eslint/eslint) from 8.42.0 to 8.44.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v8.42.0...v8.44.0)

---
updated-dependencies:
- dependency-name: eslint
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-11 10:19:10 +00:00
Janis
5033753397 Merge pull request #35 from DerTyp7/dependabot/npm_and_yarn/eslint-plugin-react-refresh-0.4.3
Bump eslint-plugin-react-refresh from 0.4.1 to 0.4.3
2023-07-11 12:18:24 +02:00
DerTyp7
bd2611875a Merge branch 'main' into dependabot/npm_and_yarn/eslint-plugin-react-refresh-0.4.3 2023-07-11 11:37:04 +02:00
dependabot[bot]
d7f6aead15 Bump semver from 6.3.0 to 6.3.1
Bumps [semver](https://github.com/npm/node-semver) from 6.3.0 to 6.3.1.
- [Release notes](https://github.com/npm/node-semver/releases)
- [Changelog](https://github.com/npm/node-semver/blob/v6.3.1/CHANGELOG.md)
- [Commits](https://github.com/npm/node-semver/compare/v6.3.0...v6.3.1)

---
updated-dependencies:
- dependency-name: semver
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-11 09:36:40 +00:00
Janis
33fd746f01 Merge pull request #36 from DerTyp7/dependabot/npm_and_yarn/types/node-20.4.1
Bump @types/node from 20.3.2 to 20.4.1
2023-07-11 11:36:12 +02:00
DerTyp7
176cd6b05f change version 2023-07-11 11:34:16 +02:00
dependabot[bot]
f8aee2ab49 Bump @types/node from 20.3.2 to 20.4.1
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 20.3.2 to 20.4.1.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-10 01:28:06 +00:00
dependabot[bot]
900c6c9380 Bump eslint-plugin-react-refresh from 0.4.1 to 0.4.3
Bumps [eslint-plugin-react-refresh](https://github.com/ArnaudBarre/eslint-plugin-react-refresh) from 0.4.1 to 0.4.3.
- [Release notes](https://github.com/ArnaudBarre/eslint-plugin-react-refresh/releases)
- [Changelog](https://github.com/ArnaudBarre/eslint-plugin-react-refresh/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ArnaudBarre/eslint-plugin-react-refresh/compare/v0.4.1...v0.4.3)

---
updated-dependencies:
- dependency-name: eslint-plugin-react-refresh
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-10 01:27:56 +00:00
Janis
a64bf30fd3 update readme 2023-07-08 14:20:03 +02:00
Janis
43dc2f1160 update build options 2023-07-08 14:17:36 +02:00
Janis
810da5173a Merge pull request #31 from DerTyp7/dependabot/npm_and_yarn/eslint-plugin-react-refresh-0.4.1
Bump eslint-plugin-react-refresh from 0.3.5 to 0.4.1
2023-07-08 13:58:12 +02:00
Janis
541514df9a Merge pull request #28 from DerTyp7/dependabot/npm_and_yarn/sass-1.63.6
Bump sass from 1.62.1 to 1.63.6
2023-07-08 13:57:59 +02:00
dependabot[bot]
a3335cb44d Bump sass from 1.62.1 to 1.63.6
Bumps [sass](https://github.com/sass/dart-sass) from 1.62.1 to 1.63.6.
- [Release notes](https://github.com/sass/dart-sass/releases)
- [Changelog](https://github.com/sass/dart-sass/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sass/dart-sass/compare/1.62.1...1.63.6)

---
updated-dependencies:
- dependency-name: sass
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-08 11:56:56 +00:00
Janis
9cdba50155 Merge pull request #30 from DerTyp7/dependabot/npm_and_yarn/jest-29.6.1
Bump jest from 29.5.0 to 29.6.1
2023-07-08 13:56:34 +02:00
dependabot[bot]
ad94353c64 Bump jest from 29.5.0 to 29.6.1
Bumps [jest](https://github.com/facebook/jest/tree/HEAD/packages/jest) from 29.5.0 to 29.6.1.
- [Release notes](https://github.com/facebook/jest/releases)
- [Changelog](https://github.com/jestjs/jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/jest/commits/v29.6.1/packages/jest)

---
updated-dependencies:
- dependency-name: jest
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-08 11:56:23 +00:00
Janis
e18420540f Merge pull request #29 from DerTyp7/dependabot/npm_and_yarn/react-router-dom-6.14.1
Bump react-router-dom from 6.14.0 to 6.14.1
2023-07-08 13:56:17 +02:00
Janis
87d8f628c2 Merge pull request #27 from DerTyp7:dependabot/npm_and_yarn/types/react-18.2.14
Bump @types/react from 18.2.8 to 18.2.14
2023-07-08 13:55:31 +02:00
dependabot[bot]
c962aae1a7 Bump eslint-plugin-react-refresh from 0.3.5 to 0.4.1
Bumps [eslint-plugin-react-refresh](https://github.com/ArnaudBarre/eslint-plugin-react-refresh) from 0.3.5 to 0.4.1.
- [Release notes](https://github.com/ArnaudBarre/eslint-plugin-react-refresh/releases)
- [Changelog](https://github.com/ArnaudBarre/eslint-plugin-react-refresh/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ArnaudBarre/eslint-plugin-react-refresh/compare/v0.3.5...v0.4.1)

---
updated-dependencies:
- dependency-name: eslint-plugin-react-refresh
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-08 11:52:10 +00:00
dependabot[bot]
9ec6d0bc1b Bump react-router-dom from 6.14.0 to 6.14.1
Bumps [react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom) from 6.14.0 to 6.14.1.
- [Release notes](https://github.com/remix-run/react-router/releases)
- [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/CHANGELOG.md)
- [Commits](https://github.com/remix-run/react-router/commits/react-router-dom@6.14.1/packages/react-router-dom)

---
updated-dependencies:
- dependency-name: react-router-dom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-08 11:51:43 +00:00
dependabot[bot]
db1b7153f9 Bump @types/react from 18.2.8 to 18.2.14
Bumps [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) from 18.2.8 to 18.2.14.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

---
updated-dependencies:
- dependency-name: "@types/react"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-08 11:51:20 +00:00
Janis
7da123fb42 Update dependabot.yml package-ecosystem 2023-07-08 13:50:53 +02:00
Janis
e49791cb1e Create dependabot.yml 2023-07-08 13:47:54 +02:00
Janis
e4d6d59d5c Update README.md 2023-07-01 21:33:37 +02:00
Janis
df0e38242c Update bug_report.md 2023-07-01 21:14:56 +02:00
Janis
3864207b6a Update issue templates 2023-07-01 21:14:14 +02:00
Janis
6524b85142 Update README.md 2023-07-01 13:31:13 +02:00
Janis
4677e98bf3 Merge pull request #25 from DerTyp876/19-show-if-a-client-is-hardware-muted
[feature] add hardware muted inputs
2023-06-30 13:59:12 +02:00
Janis Meister
5f81bbf46a [feature] add hardware muted inputs 2023-06-30 13:58:08 +02:00
Janis
3733f7ef79 Merge pull request #24 from DerTyp876/5-show-channel-name
5 show channel name
2023-06-30 13:27:22 +02:00
Janis Meister
14db96d10a [refactor] update readme paramter table 2023-06-30 13:26:58 +02:00
Janis Meister
0d3317802c [refactor] update channel name style 2023-06-30 13:25:44 +02:00
Janis Meister
113fcb28de [feature] get boolean from parameter 2023-06-30 13:22:07 +02:00
Janis
9758520239 Merge pull request #23 from DerTyp876/6-set-a-show-clients-limit
6 set a show clients limit
2023-06-30 13:20:20 +02:00
Janis Meister
d6e0517ddb [refactor] update readme paramter table 2023-06-30 13:19:55 +02:00
Janis Meister
f919b39548 [feature] add client limit 2023-06-30 13:18:37 +02:00
Janis
4ec685bd75 Merge pull request #22 from DerTyp876/16-hide-non-talking-clients
16 hide non talking clients
2023-06-30 13:06:11 +02:00
Janis Meister
7c3b67de4d [feature] update readme parameter table 2023-06-30 13:05:35 +02:00
Janis Meister
c1c9db8f95 [feature] add hideNonTalking boolean 2023-06-30 13:05:24 +02:00
Janis
ba5930cadc [feature] add log tag to logger.log 2023-06-29 21:49:33 +02:00
Janis
afe2376ea0 Merge pull request #21 from DerTyp876/feature_better-logger
Better logger
2023-06-29 21:26:11 +02:00
Janis
f0290bb44d [feature] integrated Logger 2023-06-29 21:17:31 +02:00
Janis
e411c1c126 [feature] integrated Logger 2023-06-29 21:17:30 +02:00
Janis
033cd77e04 [feature] update logger parameters 2023-06-29 21:07:02 +02:00
Janis
619e66375f [feature] created Logger 2023-06-29 18:09:03 +02:00
Janis
c6289ddc0f Merge pull request #20 from DerTyp876/refactor_clean-up
Clean up project
2023-06-29 12:54:11 +02:00
Janis Meister
eb0e005882 [fix] alias imports 2023-06-29 12:53:17 +02:00
Janis Meister
e5f4e7b4fa [fix] aliases 2023-06-29 12:51:58 +02:00
Janis
98deb4db19 [feature] add interfaces for classes 2023-06-29 01:10:08 +02:00
Janis
3d99e206c1 [feature] add interfaces for classes 2023-06-29 01:07:30 +02:00
Janis
70b2506118 [refactor] remove unused interface 2023-06-29 01:03:40 +02:00
Janis
d1dca713aa [refactor] split up handler classes 2023-06-29 00:56:33 +02:00
Janis
9382572bd7 [refactor] split up handler classes 2023-06-29 00:56:30 +02:00
14 changed files with 3624 additions and 1291 deletions

23
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,23 @@
---
name: Bug report
about: Something isn't working for you
title: ''
labels: bug
assignees: ''
---
> Screenshots are welcome
## Describe the bug
A clear and concise description of what the bug is.
## To Reproduce
Example or explanation to reproduce the issue.
## Expected behavior
A clear and concise description of what you expected to happen.
**Your environment:**
- OS: [e.g. Windows 11]
- OBS version: [e.g. 29.1.3]
- Overlay version [e.g. v1.1.0]

10
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,10 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "npm" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "monthly"

31
.github/workflows/deploy.yml vendored Normal file
View File

@@ -0,0 +1,31 @@
name: Deploy to GitHub Pages on Release
on:
release:
types:
- created
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Setup Node.js
uses: actions/setup-node@v2
with:
node-version: '18'
- name: Install dependencies
run: npm install
- name: Build
run: npm run build
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./dist

View File

@@ -1,58 +1,79 @@
# Teamspeak5-OBS-Overlay # Teamspeak5-OBS-Overlay
This is a overlay for OBS to show the current talking clients in your Teamspeak 5 Channel. This is an overlay for OBS to show the current talking clients in your Teamspeak 5 Channel.
This App uses the new "Remote Apps" feature of Teamspeak 5. This App uses the new "Remote Apps" feature of Teamspeak 5.
![image](https://github.com/DerTyp876/ts5-obs-overlay/assets/76851529/d0ab06f2-1a36-479d-826f-bd4bd3d405b7) This overlay uses the [Teamspeak 5 Remote App API](https://github.com/DerTyp7/react-ts5-remote-app-api).
![image](https://github.com/DerTyp7/ts5-obs-overlay/assets/76851529/d0ab06f2-1a36-479d-826f-bd4bd3d405b7)
- [Teamspeak5-OBS-Overlay](#teamspeak5-obs-overlay) - [Teamspeak5-OBS-Overlay](#teamspeak5-obs-overlay)
- [Setup](#setup) - [Setup](#setup)
- [Customization (Parameters)](#customization-parameters) - [Customization (Parameters)](#customization-parameters)
- [Setup (Developer)](#setup-developer) - [Setup (Developer)](#setup-developer)
- [Common Issues](#common-issues)
- [The overlay is empty, but i'm connected to a Teamspeak 5 server](#the-overlay-is-empty-but-im-connected-to-a-teamspeak-5-server)
## Setup ## Setup
1. Download the `index.html` of the latest release from [here](https://github.com/DerTyp876/ts5-obs-overlay/releases/tag/v1.0.0) 1. Download the `ts5-overlay-{version}.html` of the latest release from [here](https://github.com/DerTyp7/ts5-obs-overlay/releases/latest)
![image](https://github.com/DerTyp876/ts5-obs-overlay/assets/76851529/04dc3a66-c493-429b-b4ae-44bade473ad6) ![image](https://github.com/DerTyp7/ts5-obs-overlay/assets/76851529/04dc3a66-c493-429b-b4ae-44bade473ad6)
1.1. (optional) You can rename the file. Just remember using the new file name in the future instead of `index.html` 1.1. (optional) You can rename the file. Just remember using the new file name in the future instead of `ts5-overlay-{version}.html`
2. Go into the Teamspeak 5 Settings and enable "Remote Apps" 2. Go into the Teamspeak 5 Settings and enable "Remote Apps"
![image](https://github.com/DerTyp876/ts5-obs-overlay/assets/76851529/b31bc553-fde2-46ab-b07c-d3c81339cc7d) ![image](https://github.com/DerTyp7/ts5-obs-overlay/assets/76851529/b31bc553-fde2-46ab-b07c-d3c81339cc7d)
3. Add a new Browser Source to your OBS Scene 3. Add a new Browser Source to your OBS Scene
![image](https://github.com/DerTyp876/ts5-obs-overlay/assets/76851529/0198b468-bb96-4b65-bdd4-3d6bb3ef7d25) ![image](https://github.com/DerTyp7/ts5-obs-overlay/assets/76851529/0198b468-bb96-4b65-bdd4-3d6bb3ef7d25)
![image](https://github.com/DerTyp876/ts5-obs-overlay/assets/76851529/58ad399f-5344-456f-b243-6e267b489fd5) ![image](https://github.com/DerTyp7/ts5-obs-overlay/assets/76851529/58ad399f-5344-456f-b243-6e267b489fd5)
4. Tick the checkbox "Local File" and select the downloaded `index.html` 4. Tick the checkbox "Local File" and select the downloaded `ts5-overlay-{version}.html`
4.1. Set the width and height to your desired size (e.g. 1920x1080 OR 1280x720) 4.1. Set the width and height to your desired size (e.g. 1920x1080 OR 1280x720)
![image](https://github.com/DerTyp876/ts5-obs-overlay/assets/76851529/5ad8ce69-645b-45e7-acc3-ce7ba8d7f8ab) ![image](https://github.com/DerTyp7/ts5-obs-overlay/assets/76851529/5ad8ce69-645b-45e7-acc3-ce7ba8d7f8ab)
5. You should now receive a notification in Teamspeak 5 that the app is allowed to connect to your Teamspeak 5 client. Allow it. (If you don't get a notification, restart Teamspeak 5 and OBS -> try again) 5. You should now receive a notification in Teamspeak 5 that the app is allowed to connect to your Teamspeak 5 client. Allow it. (If you don't get a notification, restart Teamspeak 5 and OBS -> try again)
![image](https://github.com/DerTyp876/ts5-obs-overlay/assets/76851529/40faa435-e128-415f-98eb-a9e8809e8f65) ![image](https://github.com/DerTyp7/ts5-obs-overlay/assets/76851529/40faa435-e128-415f-98eb-a9e8809e8f65)
### Customization (Parameters) ### Customization (Parameters)
You can customize the overlay by adding parameters to the URL of the Browser Source. You can customize the overlay by adding parameters to the URL of the Browser Source.
1. Open your Browser Source settings 1. Open your Browser Source settings
2. **Untick** the checkbox "Local File" 2. **Untick** the checkbox "Local File"
3. Add `file://` to the beginning of the URL 3. Add `file://` to the beginning of the URL
![image](https://github.com/DerTyp876/ts5-obs-overlay/assets/76851529/87985b4c-4397-4681-9635-239d1e382c24) ![image](https://github.com/DerTyp7/ts5-obs-overlay/assets/76851529/87985b4c-4397-4681-9635-239d1e382c24)
4. Start adding parameters like discribed below 4. Start adding parameters like discribed below
Start by adding a `?` to the end of the URL and then add the parameters. Start by adding a `?` to the end of the URL and then add the parameters.
To add multiple parameters, you have to seperate them with a `&`. To add multiple parameters, you have to seperate them with a `&`.
Like this: `file://C:/Users/.../index.html?parameter1=value1&parameter2=value2` Like this: `file://C:/Users/.../ts5-overlay-{version}.html?parameter1=value1&parameter2=value2`
Real example: `file://C:/Users/.../index.html?remoteAppPort=5899` Real example: `file://C:/Users/.../ts5-overlay-{version}.html?remoteAppPort=5899&hideNonTalking=true&clientLimit=5`
This is a list of all available parameters (all parameters are optional): This is a list of all available parameters (all parameters are optional):
| Parameter | Description | Default | | Parameter | Description | Type | Default |
| --------------- | -------------------------------------- | ------- | | ----------------- | ---------------------------------------- | ------- | --------------- |
| `remoteAppPort` | The port of the Teamspeak 5 remote app | `5899` | | `remoteAppPort` | The port of the Teamspeak 5 remote app | number | `5899` |
| `hideNonTalking` | Hide all non-talking clients | boolean | `false` |
| `clientLimit` | Count of how many client should be shown | number | `0` (unlimited) |
| `showChannelName` | Display the channel name | boolean | `false` |
## Setup (Developer) ## Setup (Developer)
1. Clone this repository 1. Clone this repository
2. Run `npm install` 2. Run `npm install`
3. To start the development server run `npm run dev` 3. To start the development server run `npm run dev`
## Common Issues
### The overlay is empty, but i'm connected to a Teamspeak 5 server
Sadly TeamSpeak5 does not give us any information about the current active server tab.
So we try currently use a workaround, where the active server tab is determined by looking on which server the your hardware input was unmuted the latest, since the non-active server tabs in TS5 usually mute the clients microphone.
However this workaround is not 100% accurate and can fail in some cases.
Possible fixes:
- Unmute and mute yourself in the active server tab (Just a normal unmute and mute, not the hardware mute)
- Reconnect to the TS5 server while the overlay is open

3704
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
{ {
"name": "ts5-obs-overlay", "name": "ts5-obs-overlay",
"private": true, "private": true,
"version": "0.0.0", "version": "1.2.3",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
@@ -10,22 +10,26 @@
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
"@types/node": "^20.4.5",
"jest": "^29.6.1",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-router-dom": "^6.14.0", "react-router-dom": "^6.14.2",
"sass": "^1.62.1" "react-ts5-remote-app-api": "^1.1.1",
"sass": "^1.64.1"
}, },
"devDependencies": { "devDependencies": {
"@types/react": "^18.0.37", "@types/jest": "^29.5.2",
"@types/react-dom": "^18.0.11", "@types/react": "^18.2.14",
"@typescript-eslint/eslint-plugin": "^5.59.0", "@types/react-dom": "^18.2.7",
"@typescript-eslint/parser": "^5.59.0", "@typescript-eslint/eslint-plugin": "^6.2.0",
"@typescript-eslint/parser": "^6.2.1",
"@vitejs/plugin-react-swc": "^3.0.0", "@vitejs/plugin-react-swc": "^3.0.0",
"eslint": "^8.38.0", "eslint": "^8.45.0",
"eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.3.4", "eslint-plugin-react-refresh": "^0.4.3",
"typescript": "^5.0.2", "typescript": "^5.1.6",
"vite": "^4.3.9", "vite": "^4.4.7",
"vite-plugin-singlefile": "^0.13.5" "vite-plugin-singlefile": "^0.13.5"
} }
} }

View File

@@ -1,60 +1,29 @@
/* eslint-disable react-hooks/exhaustive-deps */ /* eslint-disable react-hooks/exhaustive-deps */
import "@styles/App.scss"; import "@styles/App.scss";
import { TS5Connection } from "./teamspeak5Handler";
import { IChannel, IClient, IConnection } from "interfaces/teamspeak";
import { useEffect, useState } from "react";
import Viewer from "./Viewer";
import { useSearchParams } from "react-router-dom"; import { useSearchParams } from "react-router-dom";
import useTSRemoteApp, { IClient } from "react-ts5-remote-app-api";
import Viewer from "./Viewer";
export default function App() { export default function App() {
const [searchParams] = useSearchParams(); const [searchParams] = useSearchParams();
const { clients, activeConnectionId, currentChannel } = useTSRemoteApp({
const [clients, setClients] = useState<IClient[]>([]); remoteAppPort: parseInt(searchParams.get("remoteAppPort") ?? "5899"),
const [channels, setChannels] = useState<IChannel[]>([]); auth: {
const [connections, setConnections] = useState<IConnection[]>([]); identifier: "de.tealfire.obs",
const [activeConnectionId, setActiveConnectionId] = useState<number>(1); version: "1.2.3",
name: "TS5 OBS Overlay",
const [currentConnection, setCurrentConnection] = useState<IConnection | undefined>(undefined); description: "A OBS overlay for TS5 by DerTyp876",
const [currentChannel, setCurrentChannel] = useState<IChannel | undefined>(undefined); },
const [currentClient, setCurrentClient] = useState<IClient | undefined>(undefined); logging: true,
});
function setCurrentStates() {
const currentConnection = connections.find((connection) => connection.id === activeConnectionId);
setCurrentConnection(currentConnection);
if (currentConnection) {
const currentClient = clients.find((client) => client.id === currentConnection.clientId);
setCurrentClient(currentClient);
if (currentClient) {
const currentChannel = channels.find((channel) => channel.id === currentClient.channel?.id);
setCurrentChannel(currentChannel);
if (currentChannel) {
return currentChannel;
}
}
}
}
useEffect(() => {
const remoteAppPort = searchParams.get("remoteAppPort");
const tsConnection: TS5Connection = new TS5Connection(
parseInt(remoteAppPort ?? "5899"),
setConnections,
setChannels,
setClients,
setActiveConnectionId
);
tsConnection.connect();
}, []);
useEffect(() => {
setCurrentStates();
}, [clients, channels, connections, activeConnectionId]);
return ( return (
<div className="App"> <div className="App">
<Viewer <Viewer
showChannelName={searchParams.get("showChannelName") === "true"}
hideNonTalking={searchParams.get("hideNonTalking") === "true"}
clientLimit={searchParams.get("clientLimit") ? parseInt(searchParams.get("clientLimit") ?? "0") : 0}
clients={ clients={
clients.map((client) => { clients.map((client) => {
if (client.channel?.id === currentChannel?.id && client.channel.connection.id === activeConnectionId) { if (client.channel?.id === currentChannel?.id && client.channel.connection.id === activeConnectionId) {

View File

@@ -1,23 +1,91 @@
import { IChannel, IClient } from "interfaces/teamspeak";
import "@styles/Viewer.scss"; import "@styles/Viewer.scss";
import { IChannel, IClient } from "react-ts5-remote-app-api";
export default function Viewer({ export default function Viewer({
clients, clients,
channel, channel,
showChannelName = false, showChannelName = false,
hideNonTalking = false,
clientLimit = 0,
}: { }: {
clients: IClient[] | undefined; clients: IClient[] | undefined;
channel: IChannel | undefined; channel: IChannel | undefined;
showChannelName?: boolean; showChannelName?: boolean;
hideNonTalking?: boolean;
clientLimit?: number;
}) { }) {
return ( return (
<div className="viewer"> <div className="viewer">
{showChannelName ? <h3>{channel?.properties.name}</h3> : null} {showChannelName ? (
{clients?.map((client) => { <div className="channelNameContainer">
<h3>{channel?.properties.name}</h3>
</div>
) : null}
{clients?.map((client, i) => {
//* Client limit
if (clientLimit != 0 && i >= clientLimit) {
return null;
}
if (client) { if (client) {
//* Non-talking client
if (
hideNonTalking &&
(client.properties.inputMuted || client.properties.outputMuted || client.talkStatus == 0)
) {
return null;
}
//* Normal client
return ( return (
<div className="client" key={`${client.id}-${client.channel?.connection.id}`}> <div className="client" key={`${client.id}-${client.channel?.connection.id}`}>
{client.properties.outputMuted ? ( {client.properties.outputHardware == false ? (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128">
<title>muted_hardware_output</title>
<g id="muted_hardware_output.svg">
<path
d="M116.62,39a4.78,4.78,0,0,1-1.59.3l-6.29,3.63a45.42,45.42,0,0,1-13.33,57.64,49.4,49.4,0,0,1-5.82,3.62c-1.06.57-2.2.92-3.19,1.49-1.7,1-2.77,2.13-2.77,4.18a4.57,4.57,0,0,0,4.54,4.54,5.33,5.33,0,0,0,1.84-.35,54.49,54.49,0,0,0,26.94-75c-.12,0-.22,0-.34,0M88.18,13.58a4.57,4.57,0,0,0-4.54,4.54c0,2.06,1.06,3.19,2.77,4.18,1,.57,2.13.92,3.19,1.49a49.4,49.4,0,0,1,5.82,3.62,45.68,45.68,0,0,1,8.19,7.78l7-4a2.63,2.63,0,0,1,1.11-.34A54.31,54.31,0,0,0,90,13.94a5.33,5.33,0,0,0-1.84-.35"
fill="#d8d8d8"
/>
<path
d="M59.46,71.4,32.77,86.81l19,19a4.51,4.51,0,0,0,3.19,1.35,4.57,4.57,0,0,0,4.54-4.54V71.4M54.92,20.88a4.51,4.51,0,0,0-3.19,1.35L28.12,45.85H9.54A4.57,4.57,0,0,0,5,50.38V77.62a4.57,4.57,0,0,0,4.54,4.54H22.26l37.2-21.48V25.42a4.57,4.57,0,0,0-4.54-4.54"
fill="#d8d8d8"
/>
<path
d="M85.11,56.6l-7.87,4.54A10,10,0,0,1,77.62,64c0,8.58-8.23,7.09-8.23,12.48A4.53,4.53,0,0,0,73.93,81a4,4,0,0,0,1.77-.35A18.13,18.13,0,0,0,86.69,64a18.34,18.34,0,0,0-1.59-7.4M73.93,47a4.52,4.52,0,0,0-4.54,4.54,3.92,3.92,0,0,0,1.08,2.8l8.76-5.06a16.14,16.14,0,0,0-3.52-1.93A4,4,0,0,0,73.93,47"
fill="#d8d8d8"
/>
<path
d="M100.87,47.49,93,52a27.15,27.15,0,0,1-8.36,33.87A36.79,36.79,0,0,1,79.25,89a4.54,4.54,0,0,0,1.84,8.72,5.24,5.24,0,0,0,1.77-.35,36.34,36.34,0,0,0,18-49.91M81,30.25A4.54,4.54,0,0,0,79.25,39a36.82,36.82,0,0,1,5.39,3.12,27,27,0,0,1,2.86,2.4l8.14-4.7A35.37,35.37,0,0,0,82.86,30.6,5.31,5.31,0,0,0,81,30.25"
fill="#d8d8d8"
/>
<path
d="M126.57,43.71,10.42,110.77a2.88,2.88,0,0,1-3.93-1.05L4.33,106A2.88,2.88,0,0,1,5.38,102L121.53,35A2.88,2.88,0,0,1,125.46,36l2.16,3.75A2.88,2.88,0,0,1,126.57,43.71Z"
fill="#c9070a"
/>
</g>
</svg>
) : client.properties.inputHardware == false ? (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128">
<title>muted_hardware_input</title>
<g id="muted_hardware_input.svg">
<path
d="M88.62,54.15V64A24.69,24.69,0,0,1,64,88.62a25.26,25.26,0,0,1-8.38-1.46l-7.39,7.39A34,34,0,0,0,64,98.46,34.5,34.5,0,0,0,98.46,64V54.15a4.92,4.92,0,1,1,9.85,0V64a44.31,44.31,0,0,1-39.38,44v10.15H88.62a4.92,4.92,0,0,1,0,9.85H39.38a4.92,4.92,0,1,1,0-9.85H59.08V108A43.3,43.3,0,0,1,41,101.77L21.46,121.31a2.46,2.46,0,0,1-3.54,0L11.62,115a2.46,2.46,0,0,1,0-3.54l94.92-94.92a2.46,2.46,0,0,1,3.54,0l6.31,6.31a2.46,2.46,0,0,1,0,3.54ZM22.92,80.46A43.3,43.3,0,0,1,19.69,64V54.15a4.92,4.92,0,1,1,9.85,0V64a35.94,35.94,0,0,0,1.15,8.69ZM39.38,64V24.62a24.62,24.62,0,0,1,47.77-8.38Z"
fill="#d8d8d8"
/>
<rect
x="-5.93"
y="61.89"
width="139.87"
height="14.02"
rx="2.87"
ry="2.87"
transform="translate(-29.97 65.43) rotate(-45)"
fill="#c9070a"
/>
</g>
</svg>
) : client.properties.outputMuted ? (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128">
<title>muted_output</title> <title>muted_output</title>
<g id="muted_output"> <g id="muted_output">

View File

@@ -1,299 +0,0 @@
export interface TS5MessageHandlerOptions {
handleAuthMessage?: (data: IAuthMessage) => void;
handleClientMoved?: (data: IClientMovedMessage) => void;
handleClientPropertiesUpdate?: (data: IClientPropertiesUpdatedMessage) => void;
handleTalkStatusChanged?: (data: ITalkStatusChangedMessage) => void;
handleClientSelfPropertyUpdated?: (data: IClientSelfPropertyUpdatedMessage) => void;
}
export interface IAuthSenderPayload {
type: "auth";
payload: {
identifier: string;
version: string;
name: string;
description: string;
content: {
apiKey: string;
};
};
}
export interface IClient {
id: number;
talkStatus: number;
channel: IChannel;
properties: IClientProperties;
}
export interface IChannel {
id: number;
connection: IConnection;
order: string;
parentId: string;
properties: IChannelProperties;
}
export interface IConnection {
channelInfos?: IChannelInfos;
clientId: number;
clientInfos?: IClientInfo[];
id: number;
properties?: IServerProperties;
}
export interface IChannelProperties {
bannerGfxUrl: string;
bannerMode: number;
codec: number;
codecIsUnencrypted: boolean;
codecLatencyFactor: number;
codecQuality: number;
deleteDelay: number;
description: string;
flagAreSubscribed: boolean;
flagDefault: boolean;
flagMaxclientsUnlimited: boolean;
flagMaxfamilyclientsInherited: boolean;
flagMaxfamilyclientsUnlimited: boolean;
flagPassword: boolean;
flagPermanent: boolean;
flagSemiPermanent: boolean;
forcedSilence: boolean;
iconId: number;
maxclients: number;
maxfamilyclients: number;
name: string;
namePhonetic: string;
neededTalkPower: number;
order: string;
permissionHints: number;
storageQuota: number;
topic: string;
uniqueIdentifier: string;
}
export interface IChannelInfos {
rootChannels: IChannel[];
subChannels: { [key: number]: IChannel[] };
}
export interface IClientInfo {
channelId: number;
id: number;
properties: IClientProperties;
}
export interface IClientProperties {
away: boolean;
awayMessage: string;
badges: string;
channelGroupId: string;
channelGroupInheritedChannelId: string;
country: string;
created: number;
databaseId: string;
defaultChannel: string;
defaultChannelPassword: string;
defaultToken: string;
description: string;
flagAvatar: string;
flagTalking: boolean;
iconId: number;
idleTime: number;
inputDeactivated: boolean;
inputHardware: boolean;
inputMuted: boolean;
integrations: string;
isChannelCommander: boolean;
isMuted: boolean;
isPrioritySpeaker: boolean;
isRecording: boolean;
isTalker: boolean;
lastConnected: number;
metaData: string;
monthBytesDownloaded: number;
monthBytesUploaded: number;
myteamspeakAvatar: string;
myteamspeakId: string;
neededServerQueryViewPower: number;
nickname: string;
nicknamePhonetic: string;
outputHardware: boolean;
outputMuted: boolean;
outputOnlyMuted: boolean;
permissionHints: number;
platform: string;
serverGroups: string;
serverPassword: string;
signedBadges: string;
talkPower: number;
talkRequest: number;
talkRequestMsg: string;
totalBytesDownloaded: number;
totalBytesUploaded: number;
totalConnections: number;
type: number;
uniqueIdentifier: string;
unreadMessages: number;
userTag: string;
version: string;
volumeModificator: number;
}
export interface IServerProperties {
antiFloodPointsNeededCommandBlock: number;
antiFloodPointsNeededIpBlock: number;
antiFloodPointsNeededPluginBlock: number;
antiFloodPointsTickReduce: number;
askForPrivilegeKeyAfterNickname: boolean;
askForPrivilegeKeyForChannelCreation: boolean;
askForPrivilegeKeyForModify: boolean;
awayMessage: string;
badges: string;
channelGroupId: string;
channelGroupInheritedChannelId: string;
clientType: number;
connectionBandwidthReceived: number;
connectionBandwidthSent: number;
connectionClientIp: string;
connectionConnectedTime: number;
connectionFiletransferBandwidthReceived: number;
connectionFiletransferBandwidthSent: number;
connectionPacketloss: number;
connectionPing: number;
connectionPacketsReceived: number;
connectionPacketsSent: number;
connectionPort: number;
connectionQueryBandwidthReceived: number;
connectionQueryBandwidthSent: number;
connectionServerIp: string;
connectionServerPort: number;
connectionThrottleBandwidthReceived: number;
connectionThrottleBandwidthSent: number;
country: string;
created: number;
defaultChannel: string;
defaultChannelPassword: string;
defaultServerGroup: string;
defaultToken: string;
flagAvatar: string;
iconId: number;
inputHardware: boolean;
inputMuted: boolean;
isChannelCommander: boolean;
isMuted: boolean;
isPrioritySpeaker: boolean;
isRecording: boolean;
isTalker: boolean;
isTts: boolean;
metaData: string;
monthBytesDownloaded: number;
monthBytesUploaded: number;
myteamspeakAvatar: string;
myteamspeakId: string;
neededServerQueryViewPower: number;
nickname: string;
nicknamePhonetic: string;
outputHardware: boolean;
outputMuted: boolean;
outputOnlyMuted: boolean;
permissionHints: number;
platform: string;
serverPassword: string;
signedBadges: string;
talkPower: number;
talkRequest: number;
talkRequestMsg: string;
totalBytesDownloaded: number;
totalBytesUploaded: number;
totalConnections: number;
type: number;
uniqueIdentifier: string;
unreadMessages: number;
userTag: string;
version: string;
volumeModificator: number;
}
export interface IClientPropertiesUpdatedMessage {
type: "clientPropertiesUpdated";
payload: {
clientId: number;
connectionId: number;
properties: IClientProperties;
};
}
export interface IClientMovedMessage {
type: "clientMoved";
payload: {
properties: IClientProperties;
clientId: number;
connectionId: number;
newChannelId: number;
oldChannelId: number;
type: number;
visibility: number;
};
}
export interface ITalkStatusChangedMessage {
type: "talkStatusChanged";
payload: {
clientId: number;
connectionId: number;
isWhisper: boolean;
status: number;
};
}
export interface IClientSelfPropertyUpdatedMessage {
type: "clientSelfPropertyUpdated";
payload: {
connectionId: number;
flag: string;
newValue: boolean;
oldValue: boolean;
};
}
export interface IAuthMessage {
type: "auth";
payload: {
apiKey: string;
connections: IConnection[];
};
}
export interface IServerPropertiesUpdatedMessage {
type: "serverPropertiesUpdated";
payload: {
connectionId: number;
properties: IServerProperties;
};
}
export interface IConnectStatusChangedMessage {
type: "connectStatusChanged";
payload: {
connectionId: number;
error: number;
info: {
clientId: number;
}
status: number;
};
}
export interface IChannelsMessage {
type: "channels";
payload: {
connectionId: number;
info: IChannelInfos
}
}

View File

@@ -4,10 +4,19 @@
gap: 0 0; gap: 0 0;
padding: 1rem; padding: 1rem;
h3 { .channelNameContainer {
font-size: 1.5rem; display: flex;
font-weight: 500; align-items: center;
margin: 0; margin-bottom: 20px;
h3 {
font-size: 1.7rem;
font-weight: 500;
margin: 0;
background-color: rgba(47, 49, 54, 0.5);
padding: 0.25rem 0.5rem;
border-radius: 0.25rem;
color: white;
}
} }
.client { .client {

View File

@@ -1,544 +0,0 @@
import { IAuthMessage, IAuthSenderPayload, IChannel, IChannelInfos, IChannelsMessage, IClient, IClientInfo, IClientMovedMessage, IClientPropertiesUpdatedMessage, IClientSelfPropertyUpdatedMessage, IConnectStatusChangedMessage, IConnection, IServerPropertiesUpdatedMessage, ITalkStatusChangedMessage } from "interfaces/teamspeak";
// Establish connection to TS5 client
// Main class
export class TS5Connection {
ws: WebSocket; // Websocket connection to TS5 client
authenticated = false; // Is the connection authenticated?
remoteAppPort: number; // Port of TS5 client
dataHandler: TS5DataHandler; // Handles data/lists and states
messageHandler: TS5MessageHandler; // Handles messages received from TS5 client
constructor(
// Port of TS5 client
remoteAppPort: number,
// State setters for dataHandler
setConnections: React.Dispatch<React.SetStateAction<IConnection[]>>,
setChannels: React.Dispatch<React.SetStateAction<IChannel[]>>,
setClients: React.Dispatch<React.SetStateAction<IClient[]>>,
setActiveConnectionStateId: React.Dispatch<React.SetStateAction<number>>,
) {
// Create websocket connection to TS5 client
this.remoteAppPort = remoteAppPort;
this.ws = new WebSocket(`ws://localhost:${this.remoteAppPort}`);
// Create dataHandler and messageHandler
this.dataHandler = new TS5DataHandler(setConnections, setChannels, setClients);
this.messageHandler = new TS5MessageHandler(this.ws, this.dataHandler, setActiveConnectionStateId);
}
reconnect() {
console.log("Reconnecting...")
this.ws.close();
this.ws = new WebSocket(`ws://localhost:${this.remoteAppPort}`);
this.dataHandler.clearAll();
this.authenticated = false;
this.connect();
}
// Connect to TS5 client
connect() {
console.log('Connecting to TS5 client...');
console.log(localStorage.getItem("apiKey"))
// Create authentication payload
const initalPayload: IAuthSenderPayload = {
type: "auth",
payload: {
identifier: "de.tealfire.obs",
version: "1.0.0",
name: "TS5 OBS Overlay",
description: "A OBS overlay for TS5 by DerTyp876",
content: {
apiKey: localStorage.getItem("apiKey") ?? "",
},
},
};
this.ws.onopen = () => {
// Send authentication payload to TS5 client
console.log("Sending auth payload...")
this.ws.send(JSON.stringify(initalPayload));
};
this.ws.onclose = (event) => {
console.log("WebSocket connection closed", event);
// If the connection was closed before authentication, remove the API key from local storage
// OBS weirdly caches the localstorage and is very stubborn about clearing it (even when clicken "Clear Cache")
if (!this.authenticated) {
console.log("WebSocket connection closed before authentication");
localStorage.removeItem("apiKey");
}
setTimeout(() => {
this.reconnect();
}, 2000);
};
// Handle messages received from TS5 client
// See TS5MessageHandler class
this.ws.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log(data)
switch (data.type) {
case "auth":
this.messageHandler.handleAuthMessage(data);
this.authenticated = true;
break;
case "clientMoved":
this.messageHandler.handleClientMovedMessage(data);
break;
case "clientPropertiesUpdated":
this.messageHandler.handleClientPropertiesUpdatedMessage(data);
break;
case "talkStatusChanged":
this.messageHandler.handleTalkStatusChangedMessage(data);
break;
case "serverPropertiesUpdated":
this.messageHandler.handleServerPropertiesUpdatedMessage(data);
//this.ws.close();
break;
case "connectStatusChanged":
this.messageHandler.handleConnectStatusChangedMessage(data);
break;
case "clientSelfPropertyUpdated":
this.messageHandler.handleClientSelfPropertyUpdatedMessage(data);
break;
case "channels":
this.messageHandler.handleChannelsMessage(data);
break;
default:
console.log(`No handler for event type: ${data.type}`);
break;
}
};
}
}
class TS5DataHandler {
// Local lists of connections, channels and clients
// These lists are used to keep track of the data independent of the App.tsx state
localConnections: IConnection[];
localChannels: IChannel[];
localClients: IClient[];
// State setters for App.tsx
setConnections: React.Dispatch<React.SetStateAction<IConnection[]>>;
setChannels: React.Dispatch<React.SetStateAction<IChannel[]>>;
setClients: React.Dispatch<React.SetStateAction<IClient[]>>;
constructor(
// State setters for App.tsx
setConnections: React.Dispatch<React.SetStateAction<IConnection[]>>,
setChannels: React.Dispatch<React.SetStateAction<IChannel[]>>,
setClients: React.Dispatch<React.SetStateAction<IClient[]>>
) {
this.setConnections = setConnections;
this.setChannels = setChannels;
this.setClients = setClients;
this.localConnections = [];
this.localChannels = [];
this.localClients = [];
}
// Update App.tsx states
private updateConnectionsState() {
this.setConnections([...this.localConnections]);
}
private updateChannelsState() {
this.setChannels([...this.localChannels]);
}
private updateClientsState() {
this.setClients([...this.localClients]);
}
// Clear all data
clearAll() {
this.localConnections = [];
this.localChannels = [];
this.localClients = [];
this.updateConnectionsState();
this.updateChannelsState();
this.updateClientsState();
}
// Add data to local lists and update states
addConnection(connection: IConnection) {
console.log("Adding connection...", connection)
const existingConnection: IConnection | undefined = this.localConnections.find((localConnection: IConnection) => localConnection.id === connection.id);
if (existingConnection == undefined) {
this.localConnections.push(connection);
this.updateConnectionsState();
console.log("Connection added")
} else {
console.log("Connection already exists")
}
}
addChannel(channel: IChannel) {
console.log("Adding channel...", channel)
const existingChannel: IChannel | undefined = this.localChannels.find((localChannel: IChannel) => localChannel.id === channel.id && localChannel.connection.id === channel.connection.id);
if (existingChannel == undefined) {
this.localChannels.push(channel);
this.updateChannelsState();
console.log("Channel added")
} else {
console.log("Channel already exists")
}
}
addClient(client: IClient) {
console.log("Adding client...", client)
const existingClient: IClient | undefined = this.localClients.find((localClient: IClient) => localClient.id === client.id && localClient.channel?.connection.id === client.channel?.connection.id);
if (existingClient == undefined) {
this.localClients.push(client);
this.updateClientsState();
console.log("Client added")
} else {
console.log("Client already exists")
}
}
// Update data in local lists and update states
updateConnection(connection: IConnection) {
console.log("Updating connection...", connection)
const existingConnection: IConnection | undefined = this.localConnections.find((localConnection: IConnection) => localConnection.id === connection.id);
if (existingConnection !== undefined) {
this.localConnections[this.localConnections.indexOf(existingConnection)] = connection;
this.updateConnectionsState();
console.log("Connection updated")
} else {
console.log("Connection does not exist")
}
}
updateChannel(channel: IChannel) {
console.log("Updating channel...", channel)
const existingChannel: IChannel | undefined = this.localChannels.find((localChannel: IChannel) => localChannel.id === channel.id && localChannel.connection.id === channel.connection.id);
if (existingChannel !== undefined) {
this.localChannels[this.localChannels.indexOf(existingChannel)] = channel;
this.updateChannelsState();
console.log("Channel updated")
} else {
console.log("Channel does not exist")
}
}
updateClient(client: IClient) {
console.log("Updating client...", client)
const existingClient: IClient | undefined = this.localClients.find((localClient: IClient) => localClient.id === client.id && localClient.channel?.connection.id === client.channel?.connection.id);
if (existingClient !== undefined) {
this.localClients[this.localClients.indexOf(existingClient)] = client;
this.updateClientsState();
console.log("Client updated")
} else {
console.log("Client does not exist")
}
}
// Remove data from local lists and update states
removeConnection(connection: IConnection) {
console.log("Removing connection...", connection)
const existingConnection: IConnection | undefined = this.localConnections.find((localConnection: IConnection) => localConnection.id === connection.id);
if (existingConnection !== undefined) {
this.localConnections.splice(this.localConnections.indexOf(existingConnection), 1);
// Remove all channels and clients associated with the connection
this.localChannels = this.localChannels.filter((localChannel: IChannel) => localChannel.connection.id !== connection.id);
this.localClients = this.localClients.filter((localClient: IClient) => localClient.channel?.connection.id !== connection.id);
this.updateChannelsState();
this.updateClientsState();
this.updateConnectionsState();
console.log("Connection removed")
} else {
console.log("Connection does not exist")
}
}
removeChannel(channel: IChannel) {
console.log("Removing channel...", channel)
const existingChannel: IChannel | undefined = this.localChannels.find((localChannel: IChannel) => localChannel.id === channel.id && localChannel.connection.id === channel.connection.id);
if (existingChannel !== undefined) {
this.localChannels.splice(this.localChannels.indexOf(existingChannel), 1);
// Remove all clients associated with the channel
this.localClients = this.localClients.filter((localClient: IClient) => localClient.channel?.id !== channel.id);
this.updateClientsState();
this.updateChannelsState();
console.log("Channel removed")
} else {
console.log("Channel does not exist")
}
}
removeClient(client: IClient) {
console.log("Removing client...", client)
const existingClient: IClient | undefined = this.localClients.find((localClient: IClient) => localClient.id === client.id && localClient.channel?.connection.id === client.channel?.connection.id);
if (existingClient !== undefined) {
this.localClients.splice(this.localClients.indexOf(existingClient), 1);
this.updateClientsState();
console.log("Client removed")
} else {
console.log("Client does not exist")
}
}
// Helper functions
getConnectionById(id: number): IConnection | undefined {
return this.localConnections.find((connection: IConnection) => connection.id === id);
}
getChannelById(id: number, connectionId: number): IChannel | undefined {
return this.localChannels.find((channel: IChannel) => channel.id === id && channel.connection?.id === connectionId);
}
getClientById(id: number, connectionId: number): IClient | undefined {
return this.localClients.find((client: IClient) => client.id === id && client.channel?.connection.id === connectionId);
}
}
// Handle incoming messages from TS5 client
class TS5MessageHandler {
ws: WebSocket;
dataHandler: TS5DataHandler;
setActiveConnectionStateId: React.Dispatch<React.SetStateAction<number>>;
activeConnectionId = 0;
constructor(ws: WebSocket, dataHandler: TS5DataHandler, setActiveConnectionStateId: React.Dispatch<React.SetStateAction<number>>) {
this.ws = ws;
this.dataHandler = dataHandler;
this.setActiveConnectionStateId = setActiveConnectionStateId;
}
setActiveConnection(connectionId: number) {
this.activeConnectionId = connectionId;
this.setActiveConnectionStateId(connectionId);
}
parseChannelInfos(channelInfos: IChannelInfos, connection: IConnection) {
channelInfos.rootChannels.forEach((channel: IChannel) => {
this.dataHandler.addChannel({ ...channel, connection: connection });
if (channelInfos) {
if (channelInfos.subChannels !== null && channel.id in channelInfos.subChannels) {
channelInfos.subChannels[channel.id].forEach((subChannel: IChannel) => {
this.dataHandler.addChannel({ ...subChannel, connection: connection });
});
}
}
});
}
// This message is sent by the TS5 server when the client is connected
// It contains the initial data
handleAuthMessage(data: IAuthMessage) {
console.log("handleAuthMessage", data);
localStorage.setItem("apiKey", data.payload.apiKey);
// Process auth payload and add initial data
data.payload.connections.forEach((connection: IConnection) => {
this.dataHandler.addConnection(connection);
// Add channels
if (connection.channelInfos !== undefined) {
this.parseChannelInfos(connection.channelInfos, connection);
}
// Add clients
connection.clientInfos?.forEach((clientInfo: IClientInfo) => {
const clientChannel: IChannel | undefined = this.dataHandler.getChannelById(clientInfo.channelId, connection.id);
if (clientChannel !== undefined) {
this.dataHandler.addClient({
id: clientInfo.id,
talkStatus: 0,
channel: { ...clientChannel, connection: connection },
properties: clientInfo.properties,
});
}
});
});
}
// This message is sent by the TS5 server when a client moves a channel OR joins/leaves the server
handleClientMovedMessage(data: IClientMovedMessage) {
console.log("handleClientMoved", data);
const client: IClient | undefined = this.dataHandler.getClientById(data.payload.clientId, data.payload.connectionId);
//* This gets called when we are connecting to the server and the new clients get loaded
if (+data.payload.oldChannelId == 0) { // Create new client(when connecting to server)
//set timout to wait for channels to be created
setTimeout(() => {
console.log("---> New Client created")
const newChannel = this.dataHandler.getChannelById(data.payload.newChannelId, data.payload.connectionId);
if (newChannel !== undefined) {
this.dataHandler.addClient(
{
id: data.payload.clientId,
talkStatus: 0,
channel: newChannel,
properties: data.payload.properties,
});
}
}, 2000);
} else {//* This gets called when a client moves a channel OR joins/leaves the server
const newChannel: IChannel | undefined = this.dataHandler.getChannelById(data.payload.newChannelId, data.payload.connectionId);
if (newChannel === undefined || newChannel.id === 0) {
console.log("---> Client left")
if (client !== undefined) {
this.dataHandler.removeClient(client);
}
return;
}
if (client !== undefined) { // Client already exists
// Client moved
console.log("---> Client moved")
this.dataHandler.updateClient({
...client,
channel: newChannel,
});
} else { // Client does not exist
// Client joined
console.log("---> New Client joined")
this.dataHandler.addClient(
{
id: data.payload.clientId,
talkStatus: 0,
channel: newChannel,
properties: data.payload.properties,
}
);
}
}
}
handleClientPropertiesUpdatedMessage(data: IClientPropertiesUpdatedMessage) {
console.log("handleClientPropertiesUpdate", data);
const client: IClient | undefined = this.dataHandler.getClientById(data.payload.clientId, data.payload.connectionId);
if (client !== undefined) {
this.dataHandler.updateClient({
...client,
properties: data.payload.properties,
});
}
}
handleTalkStatusChangedMessage(data: ITalkStatusChangedMessage) {
console.log("handleTalkStatusChanged", data);
const client: IClient | undefined = this.dataHandler.getClientById(data.payload.clientId, data.payload.connectionId);
if (client !== undefined) {
this.dataHandler.updateClient({
...client,
talkStatus: data.payload.status,
});
}
console.log(this.dataHandler.localConnections)
console.log(this.dataHandler.localChannels)
console.log(this.dataHandler.localClients)
}
handleClientSelfPropertyUpdatedMessage(data: IClientSelfPropertyUpdatedMessage) {
console.log("handleClientSelfPropertyUpdated", data);
const connection: IConnection | undefined = this.dataHandler.getConnectionById(this.activeConnectionId);
if (data.payload.flag == "inputHardware" || connection == undefined) { // sadly thats the only way to detect if a server is active or not
this.setActiveConnection(data.payload.connectionId);
}
}
handleServerPropertiesUpdatedMessage(data: IServerPropertiesUpdatedMessage) {
console.log("handleServerPropertiesUpdated", data);
const connection: IConnection | undefined = this.dataHandler.getConnectionById(data.payload.connectionId);
if (connection !== undefined) { // Update existing connection
this.dataHandler.updateConnection({
...connection,
properties: data.payload.properties,
});
}
}
handleConnectStatusChangedMessage(data: IConnectStatusChangedMessage) {
console.log("handleConnectStatusChanged", data);
if (data.payload.status === 0) { // Disconnected from server
const connection: IConnection | undefined = this.dataHandler.getConnectionById(data.payload.connectionId);
if (connection !== undefined) {
this.dataHandler.removeConnection(connection);
}
}
// Status 1-3 are the connection steps (connecting, authenticating, etc.) (i guess)
if (data.payload.status === 4) { // Connected to server
this.dataHandler.addConnection({
id: data.payload.connectionId,
clientId: data.payload.info.clientId,
});
}
}
handleChannelsMessage(data: IChannelsMessage) {
console.log("handleChannels", data);
// Wait a bit for the connection to be added
setTimeout(() => {
console.log(this.dataHandler.localConnections);
console.log(data.payload.connectionId)
console.log(this.dataHandler.localConnections.filter((connection: IConnection) => connection.id === data.payload.connectionId)[0]);
console.log(this.dataHandler.localConnections.find((connection: IConnection) => connection.id === data.payload.connectionId));
const connection: IConnection | undefined = this.dataHandler.getConnectionById(data.payload.connectionId);
console.log(connection);
if (connection !== undefined) {
this.parseChannelInfos(data.payload.info, connection);
console.log(data.payload.info)
}
}, 1000);
}
}

31
src/utils/logger.tsx Normal file
View File

@@ -0,0 +1,31 @@
export default class Logger {
// Log message to the console
public static log(message: string, data: object | null = null): void {
console.log(`[Log] %c${message}`.trim(), "color: gray", data ?? "");
}
// Log warning to the console
public static warn(message: string, data: object | null = null): void {
console.warn(`%c${message}`.trim(), data ?? "");
}
// Log error to the console
public static error(message: string, data: object | null = null): void {
console.error(`%c${message}`.trim(), data ?? "");
}
// Log message received from the websocket to the console
public static wsReceived(data: object, message: string | undefined = undefined): void {
console.log(`%c[WS Recieved] ${message ?? ""}`.trim(), "color: #8258c7", data);
}
// Log message sent to the websocket to the console
public static wsSent(data: object, message: string | undefined = undefined): void {
console.log(`%c[WS Sent] ${message ?? ""}`.trim(), "color: #4eb570", data);
}
// Log message to the console with a timestamp
public static ts(message: string, data: object | null = null): void {
console.log(`%c[TS] ${message}`.trim(), "color: #2e6bc7", data ?? "");
}
}

View File

@@ -6,15 +6,15 @@
"module": "ESNext", "module": "ESNext",
"skipLibCheck": true, "skipLibCheck": true,
"baseUrl": "./src", "baseUrl": ".",
"paths": { "paths": {
"@/*": ["/src/*"], "@/*": ["src/*"],
"@components/*": ["/src/components/*"], "@components/*": ["src/components/*"],
"@assets/*": ["/src/assets/*"], "@assets/*": ["src/assets/*"],
"@styles/*": ["/src/styles/*"], "@styles/*": ["src/styles/*"],
"@utils/*": ["/src/utils/*"], "@utils/*": ["src/utils/*"],
"@interfaces/*": ["/src/interfaces/*"] "@interfaces/*": ["src/interfaces/*"],
"@handlers/*": ["src/handlers/*"]
}, },
/* Bundler mode */ /* Bundler mode */

View File

@@ -1,19 +1,25 @@
import { defineConfig } from 'vite' import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react-swc' import react from '@vitejs/plugin-react-swc'
import { viteSingleFile } from "vite-plugin-singlefile" import { viteSingleFile } from "vite-plugin-singlefile"
import path from 'path';
// https://vitejs.dev/config/ // https://vitejs.dev/config/
export default defineConfig({ export default defineConfig({
base: "./", base: "./",
resolve: { resolve: {
alias: { alias: {
"@": "/src", '@': path.resolve(__dirname, './src'),
"@components": "/src/components", '@assets': path.resolve(__dirname, './src/assets'),
"@styles": "/src/styles", '@components': path.resolve(__dirname, './src/components'),
"@assets": "/src/assets", '@handlers': path.resolve(__dirname, './src/handlers'),
"@interfaces": "/src/interfaces", '@interfaces': path.resolve(__dirname, './src/interfaces'),
"@utils": "/src/utils", '@utils': path.resolve(__dirname, './src/utils'),
'@styles': path.resolve(__dirname, './src/styles'),
}, },
}, },
build: {
outDir: 'dist',
emptyOutDir: true,
},
plugins: [react(), viteSingleFile({ useRecommendedBuildConfig: false })], plugins: [react(), viteSingleFile({ useRecommendedBuildConfig: false })],
}) })