--- /dev/null
+<?php
+
+namespace App\Console\Commands;
+
+use App\Models\ChatLog;
+use Illuminate\Console\Command;
+
+class EvaluateChatCommand extends Command {
+
+ /**
+ * The name and signature of the console command.
+ *
+ * @var string
+ */
+ protected $signature = 'chat:evaluate {amount=1}';
+
+ /**
+ * The console command description.
+ *
+ * @var string
+ */
+ protected $description = 'Evaluate chat log entries';
+
+ /**
+ * Execute the console command.
+ *
+ * @return int
+ */
+ public function handle() {
+ $amount = $this->argument('amount');
+
+ $logs = ChatLog::whereNull('evaluated_at')->orderBy('created_at')->limit($amount)->get();
+
+ foreach ($logs as $line) {
+ try {
+ $line->evaluate();
+ $line->evaluated_at = now();
+ $line->save();
+ } catch (\Exception $e) {
+ $this->error('unable to evaluate line '.$line->id.': '.$e->getMessage());
+ $line->type = 'error';
+ $line->text_content = $e->getMessage();
+ $line->evaluated_at = now();
+ $line->save();
+ }
+ }
+
+ return Command::SUCCESS;
+ }
+
+}
use HasFactory;
+ public function channel() {
+ return $this->belongsTo(Channel::class);
+ }
+
+ public function user() {
+ return $this->belongsTo(User::class);
+ }
+
+ public function evaluate() {
+ $this->evaluateUser();
+ $this->evaluateChannel();
+
+ if (is_null($this->nick)) {
+ $this->type = 'system';
+ return;
+ }
+ if ($this->nick == 'localhorsttv') {
+ $this->type = 'self';
+ return;
+ }
+
+ if ($this->command == 'PRIVMSG') {
+ if ($this->isKnownBot()) {
+ $this->type = 'bot';
+ } else if (substr($this->params[0], 0, 1) == '#') {
+ $this->type = 'chat';
+ } else {
+ $this->type = 'dm';
+ }
+ $this->text_content = $this->params[1];
+ if ($this->scanForSpam()) {
+ $this->banned = true;
+ }
+ return;
+ }
+
+ throw new \Exception('unidentified message');
+ }
+
+ public function isKnownBot() {
+ return in_array(strtolower($this->nick), [
+ 'funtoon',
+ 'nightbot',
+ 'pokemoncommunitygame',
+ 'streamelements',
+ 'wizebot',
+ 'zockerstuebchen',
+ ]);
+ }
+
+ protected function evaluateUser() {
+ }
+
+ protected function evaluateChannel() {
+ if (empty($this->params)) {
+ $this->channel()->associate(null);
+ return;
+ }
+ $cname = $this->params[0];
+ if (substr($cname, 0, 1) != '#') {
+ $cname = '#'.$cname;
+ }
+ $channel = Channel::firstWhere('twitch_chat', '=', $cname);
+ $this->channel()->associate($channel);
+ }
+
+ protected function scanForSpam() {
+ if (substr($this->text_content, 0, 1) == '!') {
+ return true;
+ }
+ if (strpos($this->text_content, '$') !== false) {
+ return true;
+ }
+ if (strpos($this->text_content, '€') !== false) {
+ return true;
+ }
+ if (strpos($this->text_content, '@') !== false) {
+ return true;
+ }
+ if (strpos($this->text_content, '://') !== false) {
+ return true;
+ }
+ if (is_numeric($this->text_content)) {
+ return true;
+ }
+ if (strpos($this->text_content, 'followers') !== false) {
+ return true;
+ }
+ if (strpos($this->text_content, 'promotion') !== false) {
+ return true;
+ }
+ if (strpos($this->text_content, 'viewers') !== false) {
+ return true;
+ }
+ if (strpos($this->text_content, 'view ers') !== false) {
+ return true;
+ }
+ return false;
+ }
+
protected $casts = [
+ 'banned' => 'boolean',
'params' => 'array',
'tags' => 'array',
+ 'user_id' => 'string',
];
protected $fillable = [
--- /dev/null
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+ /**
+ * Run the migrations.
+ *
+ * @return void
+ */
+ public function up()
+ {
+ Schema::table('chat_logs', function (Blueprint $table) {
+ $table->timestamp('evaluated_at')->nullable()->default(null);
+ $table->foreignId('user_id')->nullable()->default(null)->constrained();
+ $table->foreignId('channel_id')->nullable()->default(null)->constrained();
+ $table->string('type')->default('');
+ $table->text('text_content')->nullable()->default(null);
+ $table->boolean('banned')->default(false);
+ $table->index(['type', 'banned']);
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::table('chat_logs', function (Blueprint $table) {
+ $table->dropColumn('evaluated_at');
+ $table->dropForeign(['user_id']);
+ $table->dropColumn('user_id');
+ $table->dropForeign(['channel_id']);
+ $table->dropColumn('channel_id');
+ $table->dropColumn('type');
+ $table->dropColumn('text_content');
+ $table->dropColumn('banned');
+ });
+ }
+};