diff --git a/src/src/app/common/components/logo/logo.component.ts b/src/src/app/common/components/logo/logo.component.ts index f9b1c68..7539aaf 100644 --- a/src/src/app/common/components/logo/logo.component.ts +++ b/src/src/app/common/components/logo/logo.component.ts @@ -1,5 +1,5 @@ -import { Component, Input } from '@angular/core'; -import { Router } from '@angular/router'; +import {Component, Input} from '@angular/core'; +import {Router} from '@angular/router'; @Component({ selector: 'app-logo', @@ -11,7 +11,7 @@ import { Router } from '@angular/router'; export class LogoComponent { @Input() height: number = 50; @Input() fontSize: number = 35; - @Input() words: string[] = ['inside ;', 'tests ;', 'inside ;', 'quality ;']; + @Input() words: string[] = ['inside ;', 'tests ;', 'inside ;', 'quality ;']; constructor(private router: Router) { } diff --git a/src/src/app/common/components/success-snack-bar/success-snack-bar.component.html b/src/src/app/common/components/success-snack-bar/success-snack-bar.component.html new file mode 100644 index 0000000..9e3eca8 --- /dev/null +++ b/src/src/app/common/components/success-snack-bar/success-snack-bar.component.html @@ -0,0 +1,3 @@ + + 'hi' + diff --git a/src/src/app/common/components/success-snack-bar/success-snack-bar.component.scss b/src/src/app/common/components/success-snack-bar/success-snack-bar.component.scss new file mode 100644 index 0000000..1eb9d6b --- /dev/null +++ b/src/src/app/common/components/success-snack-bar/success-snack-bar.component.scss @@ -0,0 +1,3 @@ +.success { + color: green; +} diff --git a/src/src/app/common/components/success-snack-bar/success-snack-bar.component.spec.ts b/src/src/app/common/components/success-snack-bar/success-snack-bar.component.spec.ts new file mode 100644 index 0000000..ea0a957 --- /dev/null +++ b/src/src/app/common/components/success-snack-bar/success-snack-bar.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SuccessSnackBarComponent } from './success-snack-bar.component'; + +describe('SuccessSnackBarComponent', () => { + let component: SuccessSnackBarComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [SuccessSnackBarComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(SuccessSnackBarComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/src/app/common/components/success-snack-bar/success-snack-bar.component.ts b/src/src/app/common/components/success-snack-bar/success-snack-bar.component.ts new file mode 100644 index 0000000..cf9fad9 --- /dev/null +++ b/src/src/app/common/components/success-snack-bar/success-snack-bar.component.ts @@ -0,0 +1,12 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-success-snack-bar', + standalone: true, + imports: [], + templateUrl: './success-snack-bar.component.html', + styleUrl: './success-snack-bar.component.scss' +}) +export class SuccessSnackBarComponent { + +} diff --git a/src/src/app/common/interface/twitch-bot-config.ts b/src/src/app/common/interface/twitch-bot-config.ts new file mode 100644 index 0000000..d0dfc0e --- /dev/null +++ b/src/src/app/common/interface/twitch-bot-config.ts @@ -0,0 +1,4 @@ +export interface TwitchBotConfig { + isEnabled: boolean; + banKnownBots: boolean; +} diff --git a/src/src/app/common/interface/twitch-bot-is-mod-response.ts b/src/src/app/common/interface/twitch-bot-is-mod-response.ts new file mode 100644 index 0000000..643c5b5 --- /dev/null +++ b/src/src/app/common/interface/twitch-bot-is-mod-response.ts @@ -0,0 +1,3 @@ +export interface TwitchBotIsModResponse { + isMod: boolean; +} diff --git a/src/src/app/middleware/bearer-token-interceptor.ts b/src/src/app/middleware/bearer-token-interceptor.ts index 7ec68de..04673cf 100644 --- a/src/src/app/middleware/bearer-token-interceptor.ts +++ b/src/src/app/middleware/bearer-token-interceptor.ts @@ -1,15 +1,16 @@ -import { Injectable } from '@angular/core'; -import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http'; +import {Injectable} from '@angular/core'; +import {HttpEvent, HttpHandler, HttpInterceptor, HttpRequest} from '@angular/common/http'; -import { Observable } from 'rxjs'; -import { environment } from "../../environments/environment"; +import {Observable} from 'rxjs'; +import {environment} from "../../environments/environment"; @Injectable() export class BearerTokenInterceptor implements HttpInterceptor { // eslint-disable-next-line @typescript-eslint/no-explicit-any intercept(req: HttpRequest, next: HttpHandler): Observable> { const url = req.url.toLowerCase().replace('https://www.', 'https://'); - if (!url.startsWith(`${environment.apiUrl}/`) && !url.startsWith(`${environment.nullApiUrl}/`)) { + if (!url.startsWith(`${environment.apiUrl}/`) && !url.startsWith(`${environment.nullApiUrl}/`) && + !url.startsWith(`${environment.twitchBotApiUrl}/`)) { return next.handle(req); } diff --git a/src/src/app/service/nullinside-null.service.spec.ts b/src/src/app/service/nullinside-null.service.spec.ts index d15f987..8dfc1f6 100644 --- a/src/src/app/service/nullinside-null.service.spec.ts +++ b/src/src/app/service/nullinside-null.service.spec.ts @@ -1,17 +1,17 @@ -import { TestBed } from '@angular/core/testing'; +import {TestBed} from '@angular/core/testing'; -import { NullinsideNullService } from './nullinside-null.service'; -import { provideHttpClientTesting } from "@angular/common/http/testing"; -import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; +import {NullinsideNullService} from './nullinside-null.service'; +import {provideHttpClientTesting} from "@angular/common/http/testing"; +import {provideHttpClient, withInterceptorsFromDi} from '@angular/common/http'; describe('NullinsideNullService', () => { let service: NullinsideNullService; beforeEach(() => { - TestBed.configureTestingModule({ - imports: [], - providers: [provideHttpClient(withInterceptorsFromDi()), provideHttpClientTesting()] -}); + TestBed.configureTestingModule({ + imports: [], + providers: [provideHttpClient(withInterceptorsFromDi()), provideHttpClientTesting()] + }); service = TestBed.inject(NullinsideNullService); }); diff --git a/src/src/app/service/nullinside-twitch-bot.service.spec.ts b/src/src/app/service/nullinside-twitch-bot.service.spec.ts new file mode 100644 index 0000000..58bd778 --- /dev/null +++ b/src/src/app/service/nullinside-twitch-bot.service.spec.ts @@ -0,0 +1,21 @@ +import {TestBed} from '@angular/core/testing'; + +import {NullinsideTwitchBotService} from './nullinside-twitch-bot.service'; +import {provideHttpClientTesting} from "@angular/common/http/testing"; +import {provideHttpClient, withInterceptorsFromDi} from '@angular/common/http'; + +describe('NullinsideTwitchBotService', () => { + let service: NullinsideTwitchBotService; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [], + providers: [provideHttpClient(withInterceptorsFromDi()), provideHttpClientTesting()] + }); + service = TestBed.inject(NullinsideTwitchBotService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/src/src/app/service/nullinside-twitch-bot.service.ts b/src/src/app/service/nullinside-twitch-bot.service.ts new file mode 100644 index 0000000..0118a02 --- /dev/null +++ b/src/src/app/service/nullinside-twitch-bot.service.ts @@ -0,0 +1,30 @@ +import {Injectable} from '@angular/core'; +import {HttpClient} from "@angular/common/http"; +import {Observable} from "rxjs"; +import {environment} from "../../environments/environment"; +import {TwitchBotIsModResponse} from "../common/interface/twitch-bot-is-mod-response"; +import {TwitchBotConfig} from "../common/interface/twitch-bot-config"; + +@Injectable({ + providedIn: 'root' +}) +export class NullinsideTwitchBotService { + constructor(private httpClient: HttpClient) { + } + + getIsMod(): Observable { + return this.httpClient.get(`${environment.twitchBotApiUrl}/bot/mod`); + } + + modBot(): Observable { + return this.httpClient.post(`${environment.twitchBotApiUrl}/bot/mod`, {}); + } + + getConfig(): Observable { + return this.httpClient.get(`${environment.twitchBotApiUrl}/bot/config`); + } + + setConfig(config: TwitchBotConfig): Observable { + return this.httpClient.post(`${environment.twitchBotApiUrl}/bot/config`, config); + } +} diff --git a/src/src/app/service/nullinside.service.spec.ts b/src/src/app/service/nullinside.service.spec.ts index 11b7d41..cfe0037 100644 --- a/src/src/app/service/nullinside.service.spec.ts +++ b/src/src/app/service/nullinside.service.spec.ts @@ -1,17 +1,17 @@ -import { TestBed } from '@angular/core/testing'; +import {TestBed} from '@angular/core/testing'; -import { NullinsideService } from './nullinside.service'; -import { provideHttpClientTesting } from '@angular/common/http/testing'; -import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; +import {NullinsideService} from './nullinside.service'; +import {provideHttpClientTesting} from '@angular/common/http/testing'; +import {provideHttpClient, withInterceptorsFromDi} from '@angular/common/http'; describe('NullinsideService', () => { let service: NullinsideService; beforeEach(() => { - TestBed.configureTestingModule({ - imports: [], - providers: [provideHttpClient(withInterceptorsFromDi()), provideHttpClientTesting()] -}); + TestBed.configureTestingModule({ + imports: [], + providers: [provideHttpClient(withInterceptorsFromDi()), provideHttpClientTesting()] + }); service = TestBed.inject(NullinsideService); }); diff --git a/src/src/app/view/twitch/twitch-bot-config/twitch-bot-config.component.html b/src/src/app/view/twitch/twitch-bot-config/twitch-bot-config.component.html index cd49e3e..6407eaa 100644 --- a/src/src/app/view/twitch/twitch-bot-config/twitch-bot-config.component.html +++ b/src/src/app/view/twitch/twitch-bot-config/twitch-bot-config.component.html @@ -1,5 +1,46 @@
- +
-

IT FUCKING WORKED BECKY!

+@if (false === botIsMod) { +
nullinside is not a mod in your channel + @if (!waitingForModReply) { + + } @else { + + } +
+} @else if (null === botIsMod) { +
+ Checking nullinside mod status... +
+} + +
+

Twitch Bot

+ +
+
+ + Enabled + +
+
+ + Ban Known Bots + +
+
+
+ @if (!waitingForSave) { + + } @else { + + } +
+
+ + diff --git a/src/src/app/view/twitch/twitch-bot-config/twitch-bot-config.component.scss b/src/src/app/view/twitch/twitch-bot-config/twitch-bot-config.component.scss index e69de29..723f951 100644 --- a/src/src/app/view/twitch/twitch-bot-config/twitch-bot-config.component.scss +++ b/src/src/app/view/twitch/twitch-bot-config/twitch-bot-config.component.scss @@ -0,0 +1,21 @@ +@import "../../../common/constants"; + +.text-box { + max-width: 300px; + margin-left: auto; + margin-right: auto; + border-color: $font-color; + border-width: 1px; + border-radius: 10px; + border-style: solid; + padding: 20px; +} + +.save { + text-align: right; +} + +.snack-bar-error { + --mdc-snackbar-container-color: green; + --mat-mdc-snack-bar-button-color: white; +} diff --git a/src/src/app/view/twitch/twitch-bot-config/twitch-bot-config.component.spec.ts b/src/src/app/view/twitch/twitch-bot-config/twitch-bot-config.component.spec.ts index 831c546..e389d46 100644 --- a/src/src/app/view/twitch/twitch-bot-config/twitch-bot-config.component.spec.ts +++ b/src/src/app/view/twitch/twitch-bot-config/twitch-bot-config.component.spec.ts @@ -1,6 +1,9 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import {ComponentFixture, TestBed} from '@angular/core/testing'; -import { TwitchBotConfigComponent } from './twitch-bot-config.component'; +import {TwitchBotConfigComponent} from './twitch-bot-config.component'; +import {provideHttpClient, withInterceptorsFromDi} from "@angular/common/http"; +import {provideHttpClientTesting} from "@angular/common/http/testing"; +import {RouterModule} from "@angular/router"; describe('TwitchBotConfigComponent', () => { let component: TwitchBotConfigComponent; @@ -8,7 +11,8 @@ describe('TwitchBotConfigComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [TwitchBotConfigComponent] + imports: [TwitchBotConfigComponent, RouterModule.forRoot([])], + providers: [provideHttpClient(withInterceptorsFromDi()), provideHttpClientTesting()] }) .compileComponents(); diff --git a/src/src/app/view/twitch/twitch-bot-config/twitch-bot-config.component.ts b/src/src/app/view/twitch/twitch-bot-config/twitch-bot-config.component.ts index ec19a13..0d356bf 100644 --- a/src/src/app/view/twitch/twitch-bot-config/twitch-bot-config.component.ts +++ b/src/src/app/view/twitch/twitch-bot-config/twitch-bot-config.component.ts @@ -1,17 +1,158 @@ -import { Component } from '@angular/core'; -import { LogoComponent } from '../../../common/components/logo/logo.component'; -import { MatButton } from '@angular/material/button'; +import {Component, OnDestroy, OnInit} from '@angular/core'; +import {LogoComponent} from '../../../common/components/logo/logo.component'; +import {MatButton} from '@angular/material/button'; +import {NullinsideTwitchBotService} from "../../../service/nullinside-twitch-bot.service"; +import {ActivatedRoute, ParamMap} from "@angular/router"; +import {Errors} from "../../login-landing/errors"; +import {HttpErrorResponse} from "@angular/common/http"; +import {NullinsideService} from "../../../service/nullinside.service"; +import {environment} from "../../../../environments/environment"; +import {LoadingIconComponent} from "../../../common/components/loading-icon/loading-icon.component"; +import {MatSlideToggle} from "@angular/material/slide-toggle"; +import {MatCheckbox} from "@angular/material/checkbox"; +import {TwitchBotFaqComponent} from "../twitch-bot-faq/twitch-bot-faq.component"; +import {MatSnackBar} from "@angular/material/snack-bar"; +import {FormsModule} from "@angular/forms"; @Component({ selector: 'app-twitch-bot-config', standalone: true, imports: [ LogoComponent, - MatButton + MatButton, + LoadingIconComponent, + MatSlideToggle, + MatCheckbox, + TwitchBotFaqComponent, + FormsModule ], templateUrl: './twitch-bot-config.component.html', styleUrl: './twitch-bot-config.component.scss' }) -export class TwitchBotConfigComponent { +export class TwitchBotConfigComponent implements OnInit, OnDestroy { + public botIsMod: boolean | null = null; + public timerId: number = -1; + public error: string = ''; + public waitingForModReply = false; + public botEnabled = true; + public banKnownBots = true; + public waitingForSave = false; + constructor(private twitchBotApi: NullinsideTwitchBotService, + private api: NullinsideService, + private snackBar: MatSnackBar, + private route: ActivatedRoute) { + } + + ngOnDestroy(): void { + if (this.timerId !== -1) { + clearTimeout(this.timerId); + } + } + + ngOnInit(): void { + this.route.queryParamMap.subscribe({ + next: (params: ParamMap) => { + const error = params.get('error'); + if (null !== error) { + const errorNum = +error; + if (Errors.TwitchAccountHasNoEmail === errorNum) { + this.onLoginFailed('Your Twitch account must have a valid e-mail address, please add one and try again', false) + } else if (Errors.TwitchErrorWithToken === errorNum) { + this.onLoginFailed('Twitch failed to give us a valid token, please add one and try again', false) + } else { + this.onLoginFailed('Sorry we did something wrong trying to log you in, please add one and try again', false) + } + + return; + } + + const token = params.get('token'); + if (token) { + localStorage.setItem('auth-token', token); + this.api.validateToken(token).subscribe({ + error: (_: HttpErrorResponse) => { + this.onLoginFailed(); + } + }); + } + + this.twitchBotApi.getIsMod().subscribe({ + next: response => { + this.botIsMod = response.isMod; + }, + error: err => { + this.botIsMod = false; + this.error = 'Unable to determine if nullinside is a mod in your channel'; + console.log(err); + } + }); + + this.twitchBotApi.getConfig().subscribe({ + next: response => { + this.botEnabled = response.isEnabled; + this.banKnownBots = response.banKnownBots; + }, + error: err => console.error(err) + }); + }, + error: (_: HttpErrorResponse) => { + this.onLoginFailed(); + } + }); + } + + onLoginFailed(message = ':( Failed to login, please try again', redirect = true): void { + localStorage.removeItem('auth-token'); + this.error = message; + + if (redirect) { + this.timerId = setTimeout(() => { + // Need to use window.location here instead of the router because otherwise the external javascript from Google + // doesn't reload on the login page, and you can't retry your login until you refresh. + // + // @ts-expect-error: The expected usage of window.location is to set it directly as a string but due to typing + // issues that have changed over time the linting complains about it. + window.location = environment.siteUrl; + }, 5000); + } + } + + modBot() { + this.waitingForModReply = true; + this.twitchBotApi.modBot().subscribe({ + next: success => { + this.botIsMod = success; + }, + error: err => { + console.error(err); + } + }).add(() => this.waitingForModReply = false); + } + + saveConfig() { + this.waitingForSave = true; + console.log({ + isEnabled: this.botEnabled, + banKnownBots: this.banKnownBots + }) + this.twitchBotApi.setConfig({ + isEnabled: this.botEnabled, + banKnownBots: this.banKnownBots + }).subscribe({ + next: config => { + this.botEnabled = config.isEnabled; + this.banKnownBots = config.banKnownBots; + this.snackBar.open('Save successful', undefined, { + panelClass: ['snackbar-success'] + }); + }, + error: err => { + console.error(err); + this.snackBar.open('Failed to save config, please try again...', undefined, { + panelClass: ['snackbar-failure'] + }); + } + }).add(() => this.waitingForSave = false); + } } diff --git a/src/src/app/view/twitch/twitch-bot-faq/twitch-bot-faq.component.html b/src/src/app/view/twitch/twitch-bot-faq/twitch-bot-faq.component.html new file mode 100644 index 0000000..4a55aa4 --- /dev/null +++ b/src/src/app/view/twitch/twitch-bot-faq/twitch-bot-faq.component.html @@ -0,0 +1,58 @@ +
+
+ What is the nullinside bot? nullinside is a bot that joins your Twitch chat to automatically detect, block, + and ban other bots from your channel. These banned bots have a variety of goals including, but not limited to: +
    +
  • Typing spam messages
  • +
  • Advertising services in your channel
  • +
  • Posting links to malicious sites
  • +
  • Posting offensive messages
  • +
  • Executing Hate Raids
  • +
+
+
+ What features does nullinside support? nullinside has a variety of features that allow you to have more + control + over your channel and keep it safe from unwanted behaviours. She currently supports the following: +
    +
  • + Ban Known Bots: Bans known bot accounts sourced from a variety of sources. These are bots + that enter a twitch chat uninvited. They may seek to gather information from you chat logs, post + messages and/or links, or advertise services. +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ So this is the only bot I need? No. nullinside is meant to help moderate your channel. Its always a + good idea to use a variety of tools to keep yourself and your community safe. Twitch has a variety of + moderation tools built-in that you should explore and configure. In addition, there are other bots available + that can also help secure your channel, such as Sery_Bot. +
+
diff --git a/src/src/app/view/twitch/twitch-bot-faq/twitch-bot-faq.component.scss b/src/src/app/view/twitch/twitch-bot-faq/twitch-bot-faq.component.scss new file mode 100644 index 0000000..b1b7a5a --- /dev/null +++ b/src/src/app/view/twitch/twitch-bot-faq/twitch-bot-faq.component.scss @@ -0,0 +1,11 @@ +@import "../../../common/constants"; + +.faq { + margin-top: 20px; +} + +.text-box { + max-width: 800px; + margin-left: auto; + margin-right: auto; +} diff --git a/src/src/app/view/twitch/twitch-bot-faq/twitch-bot-faq.component.spec.ts b/src/src/app/view/twitch/twitch-bot-faq/twitch-bot-faq.component.spec.ts new file mode 100644 index 0000000..da3169d --- /dev/null +++ b/src/src/app/view/twitch/twitch-bot-faq/twitch-bot-faq.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { TwitchBotFaqComponent } from './twitch-bot-faq.component'; + +describe('TwitchBotFaqComponent', () => { + let component: TwitchBotFaqComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [TwitchBotFaqComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(TwitchBotFaqComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/src/app/view/twitch/twitch-bot-faq/twitch-bot-faq.component.ts b/src/src/app/view/twitch/twitch-bot-faq/twitch-bot-faq.component.ts new file mode 100644 index 0000000..430cd87 --- /dev/null +++ b/src/src/app/view/twitch/twitch-bot-faq/twitch-bot-faq.component.ts @@ -0,0 +1,12 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-twitch-bot-faq', + standalone: true, + imports: [], + templateUrl: './twitch-bot-faq.component.html', + styleUrl: './twitch-bot-faq.component.scss' +}) +export class TwitchBotFaqComponent { + +} diff --git a/src/src/app/view/twitch/twitch-bot-index/twitch-bot-index.component.html b/src/src/app/view/twitch/twitch-bot-index/twitch-bot-index.component.html index 72e4b54..6d63269 100644 --- a/src/src/app/view/twitch/twitch-bot-index/twitch-bot-index.component.html +++ b/src/src/app/view/twitch/twitch-bot-index/twitch-bot-index.component.html @@ -1,62 +1,5 @@ - + - + -
-
- What is the nullinside bot? nullinside is a bot that joins your Twitch chat to automatically detect, block, - and ban other bots from your channel. These banned bots have a variety of goals including, but not limited to: -
    -
  • Typing spam messages
  • -
  • Advertising services in your channel
  • -
  • Posting links to malicious sites
  • -
  • Posting offensive messages
  • -
  • Executing Hate Raids
  • -
-
-
- What features does nullinside support? nullinside has a variety of features that allow you to have more - control - over your channel and keep it safe from unwanted behaviours. She currently supports the following: -
    -
  • - Ban Known Bots: Bans known bot accounts sourced from a variety of sources. These are bots - that enter a twitch chat uninvited. They may seek to gather information from you chat logs, post - messages and/or links, or advertise services. -
  • -
  • - Ban Hate Follows: Hate Follows, or Hate Raids, are when hundreds or thousands of bot accounts - follow you at the same time in order to overwhelm your stream notifications. Imagine your follower - notification being backed up with 1000+ new follows, going off over and over again. Twitch does not - give us integration points that allow us to prevent this behavior. However, we can reactive to the - behavior after the fact. With this setting turned on nullinside will ban all Hate Follow/Hate Raid accounts - after an attack. -
  • -
  • - Ban Accounts Less than 24 Hours Old: Detects that age of accounts that follow you. If the - account is less than 24 hours old, it bans the account from your channel. This setting can be desirable - to prevent malicious individuals from creating new accounts in order to spam or type hateful messages - in your chat. -
  • -
  • - Put Chat in Emote Only When I Go Offline: A malicious method of getting accounts banned is to - type hateful messages into a streamer's chat once they go offline when there are no moderators to take - action. A way of preventing this is to automatically put your chat into emote-only mode when your - channel goes offline. With this setting, nullinside will take care of putting your channel into emote-only - mode when you go offline and removing emote-only mode when you go online. It typically takes ~1 minute - for nullinside to notice you've gone online once you hit the start stream button. -
  • -
  • - Put Chat in Sub Only When I Go Offline: This is the same as the above setting except it places - your chat into Sub Only mode instead. This can be desirable if you and your subs like chatting in - offline chat. -
  • -
-
-
- So this is the only bot I need? No. nullinside is meant to help moderate your channel. Its always a - good idea to use a variety of tools to keep yourself and your community safe. Twitch has a variety of - moderation tools built-in that you should explore and configure. In addition, there are other bots available - that can also help secure your channel, such as Sery_Bot. -
-
+ diff --git a/src/src/app/view/twitch/twitch-bot-index/twitch-bot-index.component.scss b/src/src/app/view/twitch/twitch-bot-index/twitch-bot-index.component.scss index b1b7a5a..e69de29 100644 --- a/src/src/app/view/twitch/twitch-bot-index/twitch-bot-index.component.scss +++ b/src/src/app/view/twitch/twitch-bot-index/twitch-bot-index.component.scss @@ -1,11 +0,0 @@ -@import "../../../common/constants"; - -.faq { - margin-top: 20px; -} - -.text-box { - max-width: 800px; - margin-left: auto; - margin-right: auto; -} diff --git a/src/src/app/view/twitch/twitch-bot-index/twitch-bot-index.component.ts b/src/src/app/view/twitch/twitch-bot-index/twitch-bot-index.component.ts index 2b39266..bb25dba 100644 --- a/src/src/app/view/twitch/twitch-bot-index/twitch-bot-index.component.ts +++ b/src/src/app/view/twitch/twitch-bot-index/twitch-bot-index.component.ts @@ -1,9 +1,10 @@ -import { Component } from '@angular/core'; -import { NgOptimizedImage } from '@angular/common'; -import { LogoComponent } from '../../../common/components/logo/logo.component'; -import { MatButton } from '@angular/material/button'; -import { StandardBannerComponent } from '../../../common/components/standard-banner/standard-banner.component'; -import { TwitchLoginComponent } from '../../../common/components/twitch-login/twitch-login.component'; +import {Component} from '@angular/core'; +import {NgOptimizedImage} from '@angular/common'; +import {LogoComponent} from '../../../common/components/logo/logo.component'; +import {MatButton} from '@angular/material/button'; +import {StandardBannerComponent} from '../../../common/components/standard-banner/standard-banner.component'; +import {TwitchLoginComponent} from '../../../common/components/twitch-login/twitch-login.component'; +import {TwitchBotFaqComponent} from "../twitch-bot-faq/twitch-bot-faq.component"; @Component({ selector: 'app-twitch-bot-index', @@ -13,7 +14,8 @@ import { TwitchLoginComponent } from '../../../common/components/twitch-login/tw LogoComponent, MatButton, StandardBannerComponent, - TwitchLoginComponent + TwitchLoginComponent, + TwitchBotFaqComponent ], templateUrl: './twitch-bot-index.component.html', styleUrl: './twitch-bot-index.component.scss' diff --git a/src/src/environments/environment.development.ts b/src/src/environments/environment.development.ts index d0ecd3c..81ca5b2 100644 --- a/src/src/environments/environment.development.ts +++ b/src/src/environments/environment.development.ts @@ -1,9 +1,10 @@ -import { allEnvironments } from "./environments-all"; +import {allEnvironments} from "./environments-all"; export const environment = { siteUrl: 'http://localhost:4200', apiUrl: 'http://localhost:5036/api/v1', nullApiUrl: 'http://localhost:5219/null/v1', + twitchBotApiUrl: 'http://localhost:5941/twitch-bot/v1', twitchClientId: 'cvipqhi9y6ri8yhv0w8ryxokxh0ebd', ...allEnvironments }; diff --git a/src/src/environments/environment.ts b/src/src/environments/environment.ts index 6d295c7..43d8404 100644 --- a/src/src/environments/environment.ts +++ b/src/src/environments/environment.ts @@ -1,9 +1,10 @@ -import { allEnvironments } from "./environments-all" +import {allEnvironments} from "./environments-all" export const environment = { siteUrl: 'https://nullinside.com', apiUrl: 'https://nullinside.com/api/v1', nullApiUrl: 'https://nullinside.com/null/v1', + twitchBotApiUrl: 'https://nullinside.com/twitch-bot/v1', twitchClientId: 'gi1eu8xu9tl6vkjqz4tjqkdzfmcq5h', ...allEnvironments }; diff --git a/src/src/environments/environments-all.ts b/src/src/environments/environments-all.ts index 46dc0b6..9506f08 100644 --- a/src/src/environments/environments-all.ts +++ b/src/src/environments/environments-all.ts @@ -8,7 +8,9 @@ export const allEnvironments = { [ 'user:read:email', // Get their email address (they have to have one associated to the account) 'moderator:read:chatters', // Reads your chat and the chats of those you moderate - 'moderator:manage:banned_users' // Allow you to ban in your chat and those you moderate + 'moderator:manage:banned_users', // Allow you to ban in your chat and those you moderate + 'channel:manage:moderators', // Allows us to make the bot account a moderator for them + 'moderation:read' // Allows us to check who is a moderator ] ] } diff --git a/src/src/styles.scss b/src/src/styles.scss index 7e7e265..9432695 100644 --- a/src/src/styles.scss +++ b/src/src/styles.scss @@ -84,6 +84,10 @@ h1 { border-bottom: 1px solid $font-color; } +.mdc-form-field { + color: $font-color !important; +} + .mat-body, .mat-body-2, .mat-typography .mat-body, @@ -207,3 +211,19 @@ body { margin-left: auto; margin-right: auto; } + +.no-select { + user-select: none; +} + +.snackbar-success { + --mdc-snackbar-container-color: rgba(0, 109, 0, 0.48); + --mat-mdc-snack-bar-button-color: $font-color; + --mdc-snackbar-supporting-text-color: $font-color; +} + +.snackbar-failure { + --mdc-snackbar-container-color: rgba(109, 0, 0, 0.48); + --mat-mdc-snack-bar-button-color: $font-color; + --mdc-snackbar-supporting-text-color: $font-color; +}