Added option to customize the messages sent when the users starts streaming
This commit is contained in:
@@ -2,24 +2,24 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\DiscordWebhookMessage;
|
||||
use App\TwitchWebhook;
|
||||
use App\WebhookAction;
|
||||
use App\Http\Requests\AddWebhookAction;
|
||||
use App\Http\Requests\CreateDiscordWebhookMessage;
|
||||
use App\Http\Requests\SubscribeWebhook;
|
||||
use App\Http\Requests\TestWebhookAction;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use romanzipp\Twitch\Facades\Twitch;
|
||||
use Woeler\DiscordPhp\Webhook\DiscordWebhook;
|
||||
use Woeler\DiscordPhp\Message\DiscordEmbedMessage;
|
||||
use Woeler\DiscordPhp\Message\DiscordTextMessage;
|
||||
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
// TODO: document all the methods/constants
|
||||
class WebhookController extends Controller
|
||||
{
|
||||
class WebhookController extends Controller {
|
||||
// 10 days
|
||||
const MAX_LEASE_SECONDS = 864000;
|
||||
const TOPIC_STREAM_CHANGED = "https://api.twitch.tv/helix/streams";
|
||||
@@ -57,26 +57,41 @@ class WebhookController extends Controller
|
||||
}
|
||||
|
||||
// TODO: implement in a future more than one action per hook
|
||||
public function addAction(AddWebhookAction $request) {
|
||||
public function addAction(CreateDiscordWebhookMessage $request) {
|
||||
$hook = Auth::user()->twitchWebhooks()->where("type", $request->type)->firstOrFail();
|
||||
|
||||
// TODO: currently hardcoded, allow only one action
|
||||
$actions = $hook->webhookActions();
|
||||
// currently hardcoded, allow only one action
|
||||
$discordWebhookMessage = $hook->discordWebhookMessage();
|
||||
|
||||
// add
|
||||
if (count($actions->get()) == 0) {
|
||||
$action = $actions->create([
|
||||
"discord_hook_url" => $request->discord_hook_url
|
||||
]);
|
||||
if (count($discordWebhookMessage->get()) == 0) {
|
||||
$action = $discordWebhookMessage->create($request->all());
|
||||
|
||||
// edit the existing one
|
||||
} else {
|
||||
$action = $actions->first();
|
||||
$action->discord_hook_url = $request->discord_hook_url;
|
||||
$action = $discordWebhookMessage->first();
|
||||
$action->fill($request->all());
|
||||
$action->save();
|
||||
}
|
||||
|
||||
return response()->json(["action_id" => $action->id]);
|
||||
if ($request->hasFile("avatar")) {
|
||||
if (!$request->file("avatar")->isValid()) {
|
||||
// TODO display error message
|
||||
abort(400);
|
||||
return;
|
||||
}
|
||||
|
||||
$avatarPath = $request->avatar->storeAs("discordWebhookMessages", Auth::user()->twitch_uid . "." . $request->avatar->extension(), "public");
|
||||
$action->avatar = $avatarPath;
|
||||
$action->save();
|
||||
|
||||
} else if ($request->delete_avatar && $action->avatar) {
|
||||
Storage::disk("public")->delete($action->avatar);
|
||||
$action->avatar = null;
|
||||
$action->save();
|
||||
}
|
||||
|
||||
return response()->json(["action_id" => $action->id, "avatar" => $action->avatar ? Storage::disk("public")->url($action->avatar) : '']);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -84,11 +99,11 @@ class WebhookController extends Controller
|
||||
*/
|
||||
public function testWebhook(TestWebhookAction $request) {
|
||||
$message = new DiscordTextMessage();
|
||||
$message->setContent("Test message.")
|
||||
->setUsername(config("app.name"))
|
||||
->setAvatar(asset("img/twitch-icon.png"));
|
||||
$message->setContent($request->content ?? "Test message.")
|
||||
->setUsername($request->username ?? config("app.name"))
|
||||
->setAvatar($request->avatar ?? asset("img/twitch-icon.png"));
|
||||
|
||||
$webhook = new DiscordWebhook($request->discord_hook_url);
|
||||
$webhook = new DiscordWebhook($request->discord_webhook_url);
|
||||
$webhook->send($message);
|
||||
|
||||
return response()->json($webhook);
|
||||
@@ -165,25 +180,13 @@ class WebhookController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Stream change hook gets here, executes the user configured hook actions
|
||||
* Know the stream update type sent by Twitch, returns "start", "update", or "end"
|
||||
*/
|
||||
// TODO: test this, separate the 3 cases: start, update, end
|
||||
public function streamUpdate(Request $request) {
|
||||
$twitchWebhook = TwitchWebhook::findOrFail($request->hook_id);
|
||||
|
||||
if (!$this->verifySecret()) {
|
||||
abort(403);
|
||||
|
||||
} else if ($twitchWebhook->disabled) {
|
||||
return response("Webhook disabled", 200);
|
||||
}
|
||||
|
||||
$eventType = null;
|
||||
private function streamUpdateType(TwitchWebhook $twitchWebhook, Request $request) {
|
||||
$data = $request->all()["data"];
|
||||
Storage::put("stream_hook.json", json_encode($data));
|
||||
|
||||
if ($data) {
|
||||
|
||||
$data = $data[0];
|
||||
|
||||
if (empty($twitchWebhook->live_since)) {
|
||||
@@ -203,10 +206,30 @@ class WebhookController extends Controller
|
||||
$twitchWebhook->save();
|
||||
}
|
||||
|
||||
return $eventType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stream change hook gets here, executes the user configured hook actions
|
||||
*/
|
||||
public function streamUpdate(Request $request) {
|
||||
$twitchWebhook = TwitchWebhook::findOrFail($request->hook_id);
|
||||
|
||||
if (!$this->verifySecret()) {
|
||||
abort(403);
|
||||
|
||||
} else if ($twitchWebhook->disabled) {
|
||||
return response("Webhook disabled", 200);
|
||||
}
|
||||
|
||||
$eventType = $this->streamUpdateType($twitchWebhook, $request);
|
||||
|
||||
if (
|
||||
($eventType === "start" && $twitchWebhook->webhookActions) ||
|
||||
(config("app.env") !== "production" && $twitchWebhook->webhookActions && $eventType !== "end")
|
||||
) {
|
||||
($eventType === "start" && $twitchWebhook->discordWebhookMessage) ||
|
||||
(config("app.env") !== "production" && $twitchWebhook->discordWebhookMessage && $eventType !== "end")
|
||||
) {
|
||||
$data = $request->all()["data"][0];
|
||||
|
||||
// TODO: move this (generation of the message embed) to a separate method
|
||||
$userInfo = Twitch::getUserById(intval($data["user_id"]))->data[0];
|
||||
$gameInfo = null;
|
||||
@@ -215,24 +238,8 @@ class WebhookController extends Controller
|
||||
$gameInfo = Twitch::getGameById(intval($data["game_id"]))->data[0];
|
||||
}
|
||||
|
||||
$embed = new DiscordEmbedMessage();
|
||||
$embed->setUsername(config("app.name"))
|
||||
->setAvatar(asset("img/twitch-icon.png"))
|
||||
->setContent("¡Hola @everyone! " . $data["user_name"] . " está ahora en directo https://twitch.tv/" . $userInfo->login . " ! Ven a verle :wink:!")
|
||||
// embed
|
||||
->setColor(hexdec(substr("#9147ff", 1)))
|
||||
->setAuthorName($userInfo->display_name)
|
||||
->setAuthorIcon($userInfo->profile_image_url)
|
||||
->setThumbnail($userInfo->profile_image_url)
|
||||
->setImage(str_replace(["{width}", "{height}"], [1280, 720], $data["thumbnail_url"]) . "?cache=" . Carbon::now()->timestamp)
|
||||
->setTitle($data["title"])
|
||||
->setUrl("https://twitch.tv/$userInfo->login")
|
||||
->addField("Juego", $gameInfo ? $gameInfo->name : "─", true)
|
||||
->addField("Espectadores", $data["viewer_count"], true);
|
||||
|
||||
foreach($twitchWebhook->webhookActions as $hookAction) {
|
||||
$webhook = new DiscordWebhook($hookAction->discord_hook_url);
|
||||
$webhook->send($embed);
|
||||
foreach($twitchWebhook->discordWebhookMessage as $msg) {
|
||||
$this->sendDiscordWebhookMessage($msg, $data, $userInfo, $gameInfo);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -240,6 +247,52 @@ class WebhookController extends Controller
|
||||
return response("Ok", 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a message to using the DiscordWebhookMessage preferences and the given data
|
||||
*/
|
||||
private function sendDiscordWebhookMessage(DiscordWebhookMessage $msg, $data, $userInfo, $gameInfo) {
|
||||
$hasEmbed = $msg->has_embed;
|
||||
if ($hasEmbed) {
|
||||
$discordMessage = new DiscordEmbedMessage();
|
||||
} else {
|
||||
$discordMessage = new DiscordTextMessage();
|
||||
}
|
||||
|
||||
$discordMessage->setUsername($msg->username ?? config("app.name"))
|
||||
->setAvatar($msg->avatar ? Storage::disk("public")->url($msg->avatar) . "?cache=" . Carbon::now()->timestamp : asset("img/twitch-icon.png"))
|
||||
->setContent($msg->content ?? "¡Hola @everyone! " . $userInfo->display_name . " está ahora en directo https://twitch.tv/" . $userInfo->login . " ! Ven a verle :wink:!");
|
||||
|
||||
if ($hasEmbed) {
|
||||
$discordMessage->setColor(hexdec(substr($msg->embed_color ?? "#9147ff", 1)))
|
||||
->setAuthorName($msg->embed_author_name ? $userInfo->display_name : "")
|
||||
->setAuthorIcon($msg->embed_author_icon ? $userInfo->profile_image_url : "")
|
||||
->setAuthorUrl($msg->embed_author_url ? "https://twitch.tv/$userInfo->login" : "")
|
||||
->setThumbnail($msg->embed_thumbnail ? $userInfo->profile_image_url : "")
|
||||
->setImage($msg->embed_image ? str_replace(["{width}", "{height}"], [1280, 720], $data["thumbnail_url"]) . "?cache=" . Carbon::now()->timestamp : "")
|
||||
->setTitle($msg->embed_title ?? $data["title"])
|
||||
->setDescription($msg->embed_description ?? "")
|
||||
->setUrl($msg->embed_url ?? "https://twitch.tv/$userInfo->login");
|
||||
|
||||
foreach(json_decode($msg->embed_fields) as $field) {
|
||||
$value;
|
||||
switch($field->value) {
|
||||
case "%game%":
|
||||
$value = $gameInfo ? $gameInfo->name : "─";
|
||||
break;
|
||||
case "%viewer_count%":
|
||||
$value = $data["viewer_count"];
|
||||
break;
|
||||
default:
|
||||
$value = $field->value;
|
||||
}
|
||||
$discordMessage->addField($field->name, $value, $field->inline);
|
||||
}
|
||||
}
|
||||
|
||||
$webhook = new DiscordWebhook($msg->discord_webhook_url);
|
||||
$webhook->send($discordMessage);
|
||||
}
|
||||
|
||||
// TODO: implement the method
|
||||
public function subscription(Request $request) {
|
||||
if (!$this->verifySecret()) {
|
||||
|
50
app/Http/Requests/CreateDiscordWebhookMessage.php
Normal file
50
app/Http/Requests/CreateDiscordWebhookMessage.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class CreateDiscordWebhookMessage extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return Auth::check();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
"enabled" => "required|boolean",
|
||||
"discord_webhook_url" => "required|url|starts_with:https://discordapp.com/api/webhooks/,https://discord.com/api/webhooks/",
|
||||
"username" => "nullable|string|max:50",
|
||||
"avatar" => "nullable|file|image",
|
||||
"delete_avatar" => "nullable|in:true,1",
|
||||
"content" => "nullable|string|max:2000",
|
||||
"embed_color" => [
|
||||
"nullable",
|
||||
"string",
|
||||
"regex:/^#[0-9A-F]{6}$/i"
|
||||
],
|
||||
"embed_author_name" => "nullable|boolean",
|
||||
"embed_author_url" => "nullable|boolean",
|
||||
"embed_author_icon" => "nullable|boolean",
|
||||
"embed_thumbnail" => "nullable|boolean",
|
||||
"embed_title" => "nullable|string|max:191",
|
||||
"embed_description" => "nullable|string|max:2000",
|
||||
"embed_url" => "nullable|url|max:191",
|
||||
"embed_image" => "nullable|boolean",
|
||||
"embed_fields" => "nullable|json"
|
||||
];
|
||||
}
|
||||
}
|
@@ -25,7 +25,10 @@ class TestWebhookAction extends FormRequest
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
"discord_hook_url" => "required|url|starts_with:https://discordapp.com/api/webhooks/,https://discord.com/api/webhooks/"
|
||||
"discord_webhook_url" => "required|url|starts_with:https://discordapp.com/api/webhooks/,https://discord.com/api/webhooks/",
|
||||
"username" => "nullable|string|max:50",
|
||||
"avatar" => "nullable|url",
|
||||
"content" => "nullable|string|max:2000"
|
||||
];
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user