]> git.localhorst.tv Git - alttp.git/blob - app/Models/ChatLog.php
3b4df15f2ac9596846729b91fc564c5780ca68b8
[alttp.git] / app / Models / ChatLog.php
1 <?php
2
3 namespace App\Models;
4
5 use Illuminate\Database\Eloquent\Factories\HasFactory;
6 use Illuminate\Database\Eloquent\Model;
7 use Illuminate\Support\Arr;
8 use Illuminate\Support\Str;
9 use LanguageDetection\Language;
10
11 class ChatLog extends Model {
12
13         use HasFactory;
14
15         public function channel() {
16                 return $this->belongsTo(Channel::class);
17         }
18
19         public function user() {
20                 return $this->belongsTo(User::class);
21         }
22
23         public function getTextWithoutEmotes() {
24                 $text = $this->text_content;
25                 if (isset($this->tags['emotes']) && !empty($this->tags['emotes'])) {
26                         $emotes = explode('/', $this->tags['emotes']);
27                         foreach ($emotes as $emote) {
28                                 $set = explode(':', $emote);
29                                 $positions = explode(',', $set[1]);
30                                 foreach ($positions as $position) {
31                                         $coords = explode('-', $position);
32                                         for ($i = intval($coords[0]); $i <= intval($coords[1]); ++$i) {
33                                                 $text[$i] = ' ';
34                                         }
35                                 }
36                         }
37                 }
38                 return trim(preg_replace('/\s+/', ' ', $text));
39         }
40
41         public function evaluate() {
42                 $this->evaluateUser();
43                 $this->evaluateChannel();
44
45                 if (is_null($this->nick)) {
46                         $this->type = 'system';
47                         return;
48                 }
49                 if (in_array($this->nick, ['horstiebot', 'localhorsttv'])) {
50                         $this->type = 'self';
51                         return;
52                 }
53
54                 if ($this->command == 'PRIVMSG') {
55                         if (static::isKnownBot($this->nick)) {
56                                 $this->type = 'bot';
57                         } else if (substr($this->params[0], 0, 1) == '#') {
58                                 $this->type = 'chat';
59                         } else {
60                                 $this->type = 'dm';
61                         }
62                         $this->text_content = $this->params[1];
63                         $this->detectLanguage();
64                         if ($this->scanForSpam()) {
65                                 $this->banned = true;
66                         }
67                         $this->classification = static::classify($this->text_content);
68                         return;
69                 }
70
71                 throw new \Exception('unidentified message');
72         }
73
74         public static function isKnownBot($nick) {
75                 return in_array(strtolower($nick), [
76                         'birrellthesquirrel',
77                         'funtoon',
78                         'nidbot2000',
79                         'nightbot',
80                         'pokemoncommunitygame',
81                         'speedgaming',
82                         'starbase47',
83                         'streamelements',
84                         'wizebot',
85                         'zockerstuebchen',
86                 ]);
87         }
88
89         public static function classify($text) {
90                 if (empty($text)) {
91                         return 'unclassified';
92                 }
93                 if (is_numeric(trim($text))) {
94                         return 'number';
95                 }
96                 $rawText = strtolower(preg_replace('/[^\w]/', '', $text));
97                 $tokenizedText = preg_split('/\s+/', strtolower(trim($text)));
98                 if (Str::startsWith($rawText, 'gg') || Str::endsWith($rawText, 'gg')) {
99                         return 'gg';
100                 }
101                 if (Str::contains($rawText, ['glgl', 'glhf', 'hfgl'])) {
102                         return 'gl';
103                 }
104                 if (Str::contains($rawText, ['haha', 'hehe', 'hihi', 'kekw', 'lol', 'lul', 'xd'])) {
105                         return 'lol';
106                 }
107                 if (Str::startsWith($rawText, ['ahoi', 'hallo', 'hello', 'hi ', 'huhu']) || Str::endsWith($rawText, ['hi', 'wave'])) {
108                         return 'hi';
109                 }
110                 if (Str::contains($rawText, ['pog', 'wow'])) {
111                         return 'pog';
112                 }
113                 if (Str::contains($rawText, ['hype'])) {
114                         return 'hype';
115                 }
116                 if (Str::startsWith($rawText, 'o7') || Str::endsWith($rawText, 'o7') || Str::contains($rawText, 'salut')) {
117                         return 'o7';
118                 }
119                 return 'unclassified';
120         }
121
122         protected function evaluateUser() {
123         }
124
125         protected function evaluateChannel() {
126                 if (empty($this->params)) {
127                         $this->channel()->associate(null);
128                         return;
129                 }
130                 $cname = $this->params[0];
131                 if (substr($cname, 0, 1) != '#') {
132                         $cname = '#'.$cname;
133                 }
134                 $channel = Channel::firstWhere('twitch_chat', '=', $cname);
135                 $this->channel()->associate($channel);
136         }
137
138         protected function detectLanguage() {
139                 $languages = ['de', 'en', 'es', 'fr'];
140                 if (!is_null($this->channel)) {
141                         $languages = array_values($this->channel->languages);
142                         if (!in_array('en', $languages)) {
143                                 $languages[] = 'en';
144                         }
145                 }
146                 $detector = (new Language($languages))->detect($this->getTextWithoutEmotes());
147                 $scores = $detector->close();
148                 $lang = strval($detector);
149                 //var_dump($scores, $lang, $this->text_content);
150                 if (!empty($lang) && $scores[$lang] > 0.4) {
151                         $this->detected_language = $lang;
152                 }
153         }
154
155         public static function spammyText($raw_text) {
156                 $text = strtolower($raw_text);
157                 if (substr($text, 0, 1) == '!') {
158                         return true;
159                 }
160                 if (strpos($text, '$') !== false) {
161                         return true;
162                 }
163                 if (strpos($text, '€') !== false) {
164                         return true;
165                 }
166                 if (strpos($text, '@') !== false) {
167                         return true;
168                 }
169                 if (strpos($text, '://') !== false) {
170                         return true;
171                 }
172                 if (strpos($text, 'followers') !== false) {
173                         return true;
174                 }
175                 if (strpos($text, 'horstie') !== false) {
176                         return true;
177                 }
178                 if (strpos($text, 'promotion') !== false) {
179                         return true;
180                 }
181                 if (strpos($text, 'viewers') !== false) {
182                         return true;
183                 }
184                 if (strpos($text, 'view ers') !== false) {
185                         return true;
186                 }
187                 if (strpos($text, 'vielen dank für den raid') !== false) {
188                         return true;
189                 }
190                 if (strpos($text, 'willkommen auf starbase 47') !== false) {
191                         return true;
192                 }
193                 return false;
194         }
195
196         protected function scanForSpam() {
197                 if (is_numeric($this->text_content)) {
198                         return true;
199                 }
200                 return static::spammyText($this->text_content);
201         }
202
203         protected $casts = [
204                 'banned' => 'boolean',
205                 'params' => 'array',
206                 'tags' => 'array',
207                 'user_id' => 'string',
208         ];
209
210         protected $fillable = [
211                 'command',
212                 'nick',
213                 'params',
214                 'tags',
215         ];
216
217 }