diff --git a/.env.example b/.env.example index 6a18842..ed5b9be 100644 --- a/.env.example +++ b/.env.example @@ -63,6 +63,6 @@ AWS_USE_PATH_STYLE_ENDPOINT=false VITE_APP_NAME="${APP_NAME}" -MIX_TWITCH_BOT_USERNAME= -MIX_TWITCH_BOT_OAUTH_TOKEN= -MIX_TWITCH_CHANNEL= \ No newline at end of file +TWITCH_BOT_USERNAME=your_bot_name +TWITCH_BOT_OAUTH_TOKEN=oauth:your_oauth_token +TWITCH_CHANNEL=yourchannel diff --git a/app/Helpers/TwitchHelper b/app/Helpers/TwitchHelper new file mode 100644 index 0000000..b179a12 --- /dev/null +++ b/app/Helpers/TwitchHelper @@ -0,0 +1,32 @@ + 'place', + 'x' => $matches[1], + 'y' => $matches[2], + 'color' => $matches[3] + ]; + } + + if (preg_match($shortCommandPattern, $message, $matches)) { + return [ + 'command' => 'place', + 'x' => $matches[1], + 'y' => $matches[2], + 'color' => $matches[3] + ]; + } + + return null; + } +} diff --git a/app/Http/Controllers/TwitchController.php b/app/Http/Controllers/TwitchController.php new file mode 100644 index 0000000..650096b --- /dev/null +++ b/app/Http/Controllers/TwitchController.php @@ -0,0 +1,26 @@ +input('message'); + + if (!$message) { + return response()->json(['error' => 'No message provided'], 400); + } + + $parsedCommand = TwitchHelper::parseMessage($message); + + if ($parsedCommand) { + return response()->json($parsedCommand); + } + + return response()->json(['error' => 'Invalid command'], 400); + } +} diff --git a/composer.json b/composer.json index 591369b..aaf80a1 100644 --- a/composer.json +++ b/composer.json @@ -7,7 +7,9 @@ "require": { "php": "^8.2", "laravel/framework": "^11.9", - "laravel/tinker": "^2.9" + "laravel/tinker": "^2.9", + "ratchet/pawl": "^0.4.1", + "react/socket": "^1.15" }, "require-dev": { "fakerphp/faker": "^1.23", diff --git a/composer.lock b/composer.lock index f3fde6f..bdb0423 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "58ef83953920e06181ea84f65f0b2635", + "content-hash": "87e4eebaf8ce7add2dd886e4161db1f1", "packages": [ { "name": "brick/math", @@ -506,6 +506,53 @@ ], "time": "2023-10-06T06:47:41+00:00" }, + { + "name": "evenement/evenement", + "version": "v3.0.2", + "source": { + "type": "git", + "url": "https://github.com/igorw/evenement.git", + "reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/igorw/evenement/zipball/0a16b0d71ab13284339abb99d9d2bd813640efbc", + "reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc", + "shasum": "" + }, + "require": { + "php": ">=7.0" + }, + "require-dev": { + "phpunit/phpunit": "^9 || ^6" + }, + "type": "library", + "autoload": { + "psr-4": { + "Evenement\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Igor Wiedler", + "email": "igor@wiedler.ch" + } + ], + "description": "Événement is a very simple event dispatching library for PHP", + "keywords": [ + "event-dispatcher", + "event-emitter" + ], + "support": { + "issues": "https://github.com/igorw/evenement/issues", + "source": "https://github.com/igorw/evenement/tree/v3.0.2" + }, + "time": "2023-08-08T05:53:35+00:00" + }, { "name": "fruitcake/php-cors", "version": "v1.3.0", @@ -3108,6 +3155,568 @@ ], "time": "2024-04-27T21:32:50+00:00" }, + { + "name": "ratchet/pawl", + "version": "v0.4.1", + "source": { + "type": "git", + "url": "https://github.com/ratchetphp/Pawl.git", + "reference": "af70198bab77a582b31169d3cc3982bed25c161f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ratchetphp/Pawl/zipball/af70198bab77a582b31169d3cc3982bed25c161f", + "reference": "af70198bab77a582b31169d3cc3982bed25c161f", + "shasum": "" + }, + "require": { + "evenement/evenement": "^3.0 || ^2.0", + "guzzlehttp/psr7": "^2.0 || ^1.7", + "php": ">=5.4", + "ratchet/rfc6455": "^0.3.1", + "react/socket": "^1.9" + }, + "require-dev": { + "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8" + }, + "suggest": { + "reactivex/rxphp": "~2.0" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "Ratchet\\Client\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Asynchronous WebSocket client", + "keywords": [ + "Ratchet", + "async", + "client", + "websocket", + "websocket client" + ], + "support": { + "issues": "https://github.com/ratchetphp/Pawl/issues", + "source": "https://github.com/ratchetphp/Pawl/tree/v0.4.1" + }, + "time": "2021-12-10T14:32:34+00:00" + }, + { + "name": "ratchet/rfc6455", + "version": "v0.3.1", + "source": { + "type": "git", + "url": "https://github.com/ratchetphp/RFC6455.git", + "reference": "7c964514e93456a52a99a20fcfa0de242a43ccdb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ratchetphp/RFC6455/zipball/7c964514e93456a52a99a20fcfa0de242a43ccdb", + "reference": "7c964514e93456a52a99a20fcfa0de242a43ccdb", + "shasum": "" + }, + "require": { + "guzzlehttp/psr7": "^2 || ^1.7", + "php": ">=5.4.2" + }, + "require-dev": { + "phpunit/phpunit": "^5.7", + "react/socket": "^1.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Ratchet\\RFC6455\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "role": "Developer" + }, + { + "name": "Matt Bonneau", + "role": "Developer" + } + ], + "description": "RFC6455 WebSocket protocol handler", + "homepage": "http://socketo.me", + "keywords": [ + "WebSockets", + "rfc6455", + "websocket" + ], + "support": { + "chat": "https://gitter.im/reactphp/reactphp", + "issues": "https://github.com/ratchetphp/RFC6455/issues", + "source": "https://github.com/ratchetphp/RFC6455/tree/v0.3.1" + }, + "time": "2021-12-09T23:20:49+00:00" + }, + { + "name": "react/cache", + "version": "v1.2.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/cache.git", + "reference": "d47c472b64aa5608225f47965a484b75c7817d5b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/cache/zipball/d47c472b64aa5608225f47965a484b75c7817d5b", + "reference": "d47c472b64aa5608225f47965a484b75c7817d5b", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "react/promise": "^3.0 || ^2.0 || ^1.1" + }, + "require-dev": { + "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.35" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "Async, Promise-based cache interface for ReactPHP", + "keywords": [ + "cache", + "caching", + "promise", + "reactphp" + ], + "support": { + "issues": "https://github.com/reactphp/cache/issues", + "source": "https://github.com/reactphp/cache/tree/v1.2.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2022-11-30T15:59:55+00:00" + }, + { + "name": "react/dns", + "version": "v1.13.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/dns.git", + "reference": "eb8ae001b5a455665c89c1df97f6fb682f8fb0f5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/dns/zipball/eb8ae001b5a455665c89c1df97f6fb682f8fb0f5", + "reference": "eb8ae001b5a455665c89c1df97f6fb682f8fb0f5", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "react/cache": "^1.0 || ^0.6 || ^0.5", + "react/event-loop": "^1.2", + "react/promise": "^3.2 || ^2.7 || ^1.2.1" + }, + "require-dev": { + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36", + "react/async": "^4.3 || ^3 || ^2", + "react/promise-timer": "^1.11" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Dns\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "Async DNS resolver for ReactPHP", + "keywords": [ + "async", + "dns", + "dns-resolver", + "reactphp" + ], + "support": { + "issues": "https://github.com/reactphp/dns/issues", + "source": "https://github.com/reactphp/dns/tree/v1.13.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2024-06-13T14:18:03+00:00" + }, + { + "name": "react/event-loop", + "version": "v1.5.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/event-loop.git", + "reference": "bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/event-loop/zipball/bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354", + "reference": "bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36" + }, + "suggest": { + "ext-pcntl": "For signal handling support when using the StreamSelectLoop" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\EventLoop\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "ReactPHP's core reactor event loop that libraries can use for evented I/O.", + "keywords": [ + "asynchronous", + "event-loop" + ], + "support": { + "issues": "https://github.com/reactphp/event-loop/issues", + "source": "https://github.com/reactphp/event-loop/tree/v1.5.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2023-11-13T13:48:05+00:00" + }, + { + "name": "react/promise", + "version": "v3.2.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/promise.git", + "reference": "8a164643313c71354582dc850b42b33fa12a4b63" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/promise/zipball/8a164643313c71354582dc850b42b33fa12a4b63", + "reference": "8a164643313c71354582dc850b42b33fa12a4b63", + "shasum": "" + }, + "require": { + "php": ">=7.1.0" + }, + "require-dev": { + "phpstan/phpstan": "1.10.39 || 1.4.10", + "phpunit/phpunit": "^9.6 || ^7.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "React\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "A lightweight implementation of CommonJS Promises/A for PHP", + "keywords": [ + "promise", + "promises" + ], + "support": { + "issues": "https://github.com/reactphp/promise/issues", + "source": "https://github.com/reactphp/promise/tree/v3.2.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2024-05-24T10:39:05+00:00" + }, + { + "name": "react/socket", + "version": "v1.15.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/socket.git", + "reference": "216d3aec0b87f04a40ca04f481e6af01bdd1d038" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/socket/zipball/216d3aec0b87f04a40ca04f481e6af01bdd1d038", + "reference": "216d3aec0b87f04a40ca04f481e6af01bdd1d038", + "shasum": "" + }, + "require": { + "evenement/evenement": "^3.0 || ^2.0 || ^1.0", + "php": ">=5.3.0", + "react/dns": "^1.11", + "react/event-loop": "^1.2", + "react/promise": "^3 || ^2.6 || ^1.2.1", + "react/stream": "^1.2" + }, + "require-dev": { + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36", + "react/async": "^4 || ^3 || ^2", + "react/promise-stream": "^1.4", + "react/promise-timer": "^1.10" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Socket\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "Async, streaming plaintext TCP/IP and secure TLS socket server and client connections for ReactPHP", + "keywords": [ + "Connection", + "Socket", + "async", + "reactphp", + "stream" + ], + "support": { + "issues": "https://github.com/reactphp/socket/issues", + "source": "https://github.com/reactphp/socket/tree/v1.15.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2023-12-15T11:02:10+00:00" + }, + { + "name": "react/stream", + "version": "v1.4.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/stream.git", + "reference": "1e5b0acb8fe55143b5b426817155190eb6f5b18d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/stream/zipball/1e5b0acb8fe55143b5b426817155190eb6f5b18d", + "reference": "1e5b0acb8fe55143b5b426817155190eb6f5b18d", + "shasum": "" + }, + "require": { + "evenement/evenement": "^3.0 || ^2.0 || ^1.0", + "php": ">=5.3.8", + "react/event-loop": "^1.2" + }, + "require-dev": { + "clue/stream-filter": "~1.2", + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Stream\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "Event-driven readable and writable streams for non-blocking I/O in ReactPHP", + "keywords": [ + "event-driven", + "io", + "non-blocking", + "pipe", + "reactphp", + "readable", + "stream", + "writable" + ], + "support": { + "issues": "https://github.com/reactphp/stream/issues", + "source": "https://github.com/reactphp/stream/tree/v1.4.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2024-06-11T12:45:25+00:00" + }, { "name": "symfony/clock", "version": "v7.1.1", diff --git a/package-lock.json b/package-lock.json index e0d9de9..8a4ab4b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,7 +5,8 @@ "packages": { "": { "dependencies": { - "tmi.js": "^1.8.5" + "tmi.js": "^1.8.5", + "ws": "^8.18.0" }, "devDependencies": { "@tailwindcss/forms": "^0.5.2", @@ -1000,6 +1001,21 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/bufferutil": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.8.tgz", + "integrity": "sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, "node_modules/camelcase-css": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", @@ -1709,6 +1725,19 @@ } } }, + "node_modules/node-gyp-build": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.1.tgz", + "integrity": "sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==", + "license": "MIT", + "optional": true, + "peer": true, + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, "node_modules/node-releases": { "version": "2.0.17", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.17.tgz", @@ -2457,6 +2486,21 @@ "browserslist": ">= 4.21.0" } }, + "node_modules/utf-8-validate": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", + "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", diff --git a/package.json b/package.json index 30b8ef2..e6d4d28 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "private": true, "type": "module", "scripts": { - "dev": "vite", + "dev": "vite build", "build": "vite build" }, "devDependencies": { @@ -16,6 +16,7 @@ "vite": "^5.0" }, "dependencies": { - "tmi.js": "^1.8.5" + "tmi.js": "^1.8.5", + "ws": "^8.18.0" } } diff --git a/public/Prototype/index.php b/public/Prototype/index.php deleted file mode 100644 index 3945484..0000000 --- a/public/Prototype/index.php +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - Dynamic Grid - - - -
- - - - diff --git a/resources/js/client.js b/resources/js/client.js index 8cc6109..5745275 100644 --- a/resources/js/client.js +++ b/resources/js/client.js @@ -1,22 +1,101 @@ -import tmi from 'tmi.js'; +const ws = new WebSocket('wss://irc-ws.chat.twitch.tv:443'); -const client = new tmi.Client({ - options: { debug: true }, - identity: { - username: process.env.MIX_TWITCH_BOT_USERNAME, - password: process.env.MIX_TWITCH_BOT_OAUTH_TOKEN - }, - channels: [ process.env.MIX_TWITCH_CHANNEL ] -}); +ws.onopen = () => { + console.log('Connected to Twitch chat'); -client.connect().catch(console.error); + const oauthToken = import.meta.env.VITE_TWITCH_BOT_OAUTH_TOKEN; + const username = import.meta.env.VITE_TWITCH_BOT_USERNAME; + const channel = import.meta.env.VITE_TWITCH_CHANNEL; -client.on('message', (channel, tags, message, self) => { - if(self) return; + console.log('OAuth Token:', oauthToken ? 'Loaded' : 'Missing'); + console.log('Username:', username ? username : 'Missing'); + console.log('Channel:', channel ? channel : 'Missing'); - if(message.toLowerCase() === '!roll') { - const num = Math.floor(Math.random() * 6) + 1; - client.say(channel, `@${tags.username} rolled a ${num}`); + if (!oauthToken || !username || !channel) { + console.error('Missing required environment variables'); + return; } -}); + ws.send(`PASS ${oauthToken}`); + ws.send(`NICK ${username}`); + ws.send(`JOIN #${channel}`); +}; + +ws.onmessage = (event) => { + console.log('Received:', event.data); + + const parsedMessage = parseTwitchMessage(event.data); + console.log('Parsed Message:', parsedMessage); + + if (parsedMessage && parsedMessage.command === 'PRIVMSG') { + const chatMessage = parsedMessage.params.slice(1).join(' ').trim(); + const username = parsedMessage.tags['display-name'] || parsedMessage.prefix.split('!')[0]; + console.log('Chat Message:', chatMessage); + console.log('Username:', username); + + window.dispatchEvent(new CustomEvent('chat-message', { detail: { user: username, message: chatMessage } })); + + // Process !place command + fetch('/twitch/parse', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content') + }, + body: JSON.stringify({ message: chatMessage }) + }) + .then(response => response.json()) + .then(data => { + if (data && data.command === 'place') { + console.log('Parsed Command:', data); + // Call the existing API with parsed coordinates and color + // Example API call: /api/place/{x}/{y}/{color} + fetch(`/api/place/${data.x}/${data.y}/${data.color}`, { method: 'POST' }) + .then(response => response.json()) + .then(result => { + console.log('API Result:', result); + }) + .catch(error => { + console.error('API Error:', error); + }); + } + }) + .catch(error => { + console.error('Parsing Error:', error); + }); + } +}; + +ws.onerror = (error) => { + console.error('WebSocket Error:', error); +}; + +ws.onclose = () => { + console.log('WebSocket connection closed'); +}; + +function parseTwitchMessage(message) { + console.log('Raw Message:', message); + + const prefixEnd = message.indexOf(' '); + const prefix = message.substring(1, prefixEnd); + + const commandEnd = message.indexOf(' ', prefixEnd + 1); + const command = message.substring(prefixEnd + 1, commandEnd); + + const params = message.substring(commandEnd + 1).split(' :'); + const tagsStart = message.indexOf('@'); + const tagsEnd = message.indexOf(' ', tagsStart + 1); + const tagsRaw = message.substring(tagsStart + 1, tagsEnd); + const tags = tagsRaw.split(';').reduce((acc, tag) => { + const [key, value] = tag.split('='); + acc[key] = value; + return acc; + }, {}); + + console.log('Parsed Tags:', tags); + console.log('Parsed Command:', command); + console.log('Parsed Params:', params); + + return { prefix, command, params, tags }; +} diff --git a/resources/views/dashboard.blade.php b/resources/views/dashboard.blade.php index 66028f2..2a10b97 100644 --- a/resources/views/dashboard.blade.php +++ b/resources/views/dashboard.blade.php @@ -9,9 +9,35 @@
- {{ __("You're logged in!") }} +
+
+
+ + diff --git a/resources/views/layouts/app.blade.php b/resources/views/layouts/app.blade.php index c5ff315..0086a4d 100644 --- a/resources/views/layouts/app.blade.php +++ b/resources/views/layouts/app.blade.php @@ -12,7 +12,7 @@ - @vite(['resources/css/app.css', 'resources/js/app.js']) + @vite(['resources/css/app.css', 'resources/js/app.js', 'resources/js/client.js' ])
diff --git a/public/Prototype/scripts.js b/resources/views/prototype.blade.php old mode 100644 new mode 100755 similarity index 62% rename from public/Prototype/scripts.js rename to resources/views/prototype.blade.php index 59ce9ac..5ed721d --- a/public/Prototype/scripts.js +++ b/resources/views/prototype.blade.php @@ -1,4 +1,49 @@ -const gridSize = parseInt(getComputedStyle(document.documentElement).getPropertyValue('--grid-size').trim()); + + + + + + Dynamic Grid + + + +
+ + + + diff --git a/resources/views/testing.blade.php b/resources/views/testing.blade.php new file mode 100644 index 0000000..c749673 --- /dev/null +++ b/resources/views/testing.blade.php @@ -0,0 +1,44 @@ + + +

+ {{ __('Testing') }} +

+
+ +
+
+
+
+ {{ __("You're logged in!") }} +
+
+
+
+
+
+
+
+ + diff --git a/routes/web.php b/routes/web.php index 74bb7ca..4006031 100644 --- a/routes/web.php +++ b/routes/web.php @@ -2,15 +2,26 @@ use App\Http\Controllers\ProfileController; use Illuminate\Support\Facades\Route; +use App\Http\Controllers\TwitchController; + +Route::post('/twitch/parse', [TwitchController::class, 'parseChatMessage']); Route::get('/', function () { return view('welcome'); }); +Route::get('/prototype', function () { + return view('prototype'); +}); + Route::get('/dashboard', function () { return view('dashboard'); })->middleware(['auth', 'verified'])->name('dashboard'); +Route::get('/testing', function () { + return view('testing'); +})->middleware(['auth', 'verified'])->name('testing'); + Route::middleware('auth')->group(function () { Route::get('/profile', [ProfileController::class, 'edit'])->name('profile.edit'); Route::patch('/profile', [ProfileController::class, 'update'])->name('profile.update'); diff --git a/vite.config.js b/vite.config.js index 89f26f5..dea2f36 100644 --- a/vite.config.js +++ b/vite.config.js @@ -1,14 +1,18 @@ -import { defineConfig } from 'vite'; +import { defineConfig, loadEnv } from 'vite'; import laravel from 'laravel-vite-plugin'; -export default defineConfig({ - plugins: [ - laravel({ - input: [ - 'resources/css/app.css', - 'resources/js/app.js', - ], - refresh: true, - }), - ], +export default defineConfig(({ mode }) => { + const env = loadEnv(mode, process.cwd(), ''); + + return { + plugins: [ + laravel({ + input: ['resources/css/app.css', 'resources/js/app.js', 'resources/js/client.js'], + refresh: true, + }), + ], + define: { + 'process.env': env, + } + }; });