Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions app/Console/Commands/CheckTwitchLiveStatus.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<?php

namespace App\Console\Commands;

use App\Enums\ConnectionType;
use App\Livewire\Actions\Api\Twitch\RefreshToken;
use App\Models\User;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

class CheckTwitchLiveStatus extends Command
{
protected $signature = 'twitch:check-live';
protected $description = 'Check if spacelampsix is live on Twitch and notify Discord';

public function handle(): int
{
$token = User::first()->connections->firstWhere('type_id', ConnectionType::TWITCH->value)->token ?? null;

if (! $token) {
return self::FAILURE;
}

$stream = $this->getStreamData($token);

if (! $stream) {
$this->info('spacelampsix is not currently live.');
return self::SUCCESS;
}

$startedAt = $stream['started_at'];

if ($this->alreadyNotified($startedAt)) {
$this->info('Already notified for this stream session.');
return self::SUCCESS;
}

$this->notifyDiscord($stream);
$this->recordNotification($startedAt);

$this->info('Discord notification sent!');
return self::SUCCESS;
}

private function getStreamData(string $token): ?array
{
$response = Http::withHeaders([
'Client-ID' => config('services.twitch.client_id'),
'Authorization' => 'Bearer ' . $token,
])->get('https://api.twitch.tv/helix/streams', [
'user_login' => 'spacelampsix',
]);

return $response->json('data.0');
}

private function alreadyNotified(string $startedAt): bool
{
return DB::table('twitch_notifications')
->where('stream_started_at', $startedAt)
->exists();
}

private function recordNotification(string $startedAt): void
{
DB::table('twitch_notifications')->insert([
'stream_started_at' => $startedAt,
'notified_at' => now(),
]);
}

private function notifyDiscord(array $stream): void
{
$title = $stream['title'] ?? 'Untitled Stream';
$game = $stream['game_name'] ?? 'Unknown Game';

Http::post(config('services.discord.live_now'), [
'content' => "@everyone 🔴 **spacelampsix is LIVE!**\n\n**{$title}**\nPlaying: {$game}\n\nhttps://twitch.tv/spacelampsix",
'allowed_mentions' => [
'parse' => ['everyone'],
],
]);

Log::channel('discord-internal-updates')->info("Discord notified of live stream successfully. Have a great stream!");
}
}
35 changes: 35 additions & 0 deletions app/Console/Commands/RefreshTwitchAccessToken.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

namespace App\Console\Commands;

use App\Livewire\Actions\Api\Twitch\RefreshToken;
use App\Models\User;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;

class RefreshTwitchAccessToken extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'twitch:refresh-token';

/**
* The console command description.
*
* @var string
*/
protected $description = 'Refreshes Twitch Access Token';

/**
* Execute the console command.
*/
public function handle()
{
(new RefreshToken)->handle(User::first());

Log::channel('discord-internal-updates')->info("Twitch Token updated automatically.");
}
}
25 changes: 25 additions & 0 deletions app/Enums/ConnectionType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

namespace App\Enums;

enum ConnectionType: int
{
case SPOTIFY = 1;
case TWITCH = 2;

public function label()
{
return match($this) {
self::SPOTIFY => 'Spotify',
self::TWITCH => 'Twitch',
};
}

public function slug()
{
return match($this) {
self::SPOTIFY => 'spotify',
self::TWITCH => 'twitch',
};
}
}
6 changes: 3 additions & 3 deletions app/Http/Controllers/ConnectionController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace App\Http\Controllers;

use App\Models\ConnectionType;
use App\Enums\ConnectionType;
use Illuminate\Http\Request;
use Laravel\Socialite\Facades\Socialite;

Expand Down Expand Up @@ -36,8 +36,8 @@ public function processConnection(Request $request)
private function getConnectionTypeId(string $type)
{
return match ($type) {
'twitch' => ConnectionType::TWITCH,
'spotify' => ConnectionType::SPOTIFY
'twitch' => ConnectionType::TWITCH->slug(),
'spotify' => ConnectionType::SPOTIFY->slug()
};
}
}
6 changes: 3 additions & 3 deletions app/Livewire/Actions/Api/SearchSpotify.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace App\Livewire\Actions\Api;

use App\Models\ConnectionType;
use App\Enums\ConnectionType;
use App\Models\Media;
use App\Models\MediaType;
use App\Models\User;
Expand All @@ -19,7 +19,7 @@ public function search(User $user, string $phrase, MediaType $mediaType)
$type = $mediaType->isArtist() ? 'artist' : 'track';

$response = Http::withHeaders([
'Authorization' => 'Bearer '.$user->connections->firstWhere('type_id', ConnectionType::SPOTIFY)->token,
'Authorization' => 'Bearer '.$user->connections->firstWhere('type_id', ConnectionType::SPOTIFY->value)->token,
'Content-Type' => 'application/json',
'Client-Id' => config('services.spotify.client_id'),
])->get('https://api.spotify.com/v1/search', [
Expand Down Expand Up @@ -81,7 +81,7 @@ public function search(User $user, string $phrase, MediaType $mediaType)
public function refreshToken(User $user): bool
{
try {
$spotifyConnection = $user->connections->firstWhere('type_id', ConnectionType::SPOTIFY);
$spotifyConnection = $user->connections->firstWhere('type_id', ConnectionType::SPOTIFY->value);

$response = Http::asForm()->post('https://accounts.spotify.com/api/token', [
'grant_type' => 'refresh_token',
Expand Down
38 changes: 38 additions & 0 deletions app/Livewire/Actions/Api/Twitch/RefreshToken.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

namespace App\Livewire\Actions\Api\Twitch;

use App\Enums\ConnectionType;
use App\Models\User;
use Exception;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

final class RefreshToken
{
public function handle(User $user): bool
{
try {
$twitchConnection = $user->connections->firstWhere('type_id', ConnectionType::TWITCH->value);

$response = Http::asForm()->post('https://id.twitch.tv/oauth2/token', [
'client_id' => config('services.twitch.client_id'),
'client_secret' => config('services.twitch.client_secret'),
'refresh_token' => $twitchConnection->refresh_token,
'grant_type' => 'refresh_token',
]);

if (! $response->successful()) {
return false;
}

$twitchConnection->update(['token' => $response->json()['access_token']]);

return true;
} catch (Exception $e) {
Log::error("Could not refresh user: {$user->name} token: {$e->getMessage()}");

return false;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<?php

namespace App\Livewire\Actions\Api;
namespace App\Livewire\Actions\Api\Twitch;

use App\Models\ConnectionType;
use App\Enums\ConnectionType;
use App\Models\Media;
use App\Models\User;
use Exception;
Expand All @@ -13,10 +13,10 @@ final class SearchCategories
{
public function search(User $user, string $phrase, int $mediaType)
{
$this->refreshToken($user);
(new RefreshToken)->handle($user);

$response = Http::withHeaders([
'Authorization' => 'Bearer '.$user->connections->firstWhere('type_id', ConnectionType::TWITCH)->token,
'Authorization' => 'Bearer '.$user->connections->firstWhere('type_id', ConnectionType::TWITCH->value)->token,
'Content-Type' => 'application/json',
'Client-Id' => config('services.twitch.client_id'),
])->get('https://api.twitch.tv/helix/search/categories', [
Expand All @@ -43,33 +43,7 @@ public function search(User $user, string $phrase, int $mediaType)

return collect();
}

public function refreshToken(User $user): bool
{
try {
$twitchConnection = $user->connections->firstWhere('type_id', ConnectionType::TWITCH);

$response = Http::asForm()->post('https://id.twitch.tv/oauth2/token', [
'client_id' => config('services.twitch.client_id'),
'client_secret' => config('services.twitch.client_secret'),
'refresh_token' => $twitchConnection->refresh_token,
'grant_type' => 'refresh_token',
]);

if (! $response->successful()) {
return false;
}

$twitchConnection->update(['token' => $response->json()['access_token']]);

return true;
} catch (Exception $e) {
Log::error("Could not refresh user: {$user->name} token: {$e->getMessage()}");

return false;
}
}


/* disgusting hack to get high rez images from this endpoint */
private function fix_box_art(string $string): string
{
Expand Down
5 changes: 2 additions & 3 deletions app/Livewire/Forms/LoginForm.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@

namespace App\Livewire\Forms;

use App\Libraries\Helpers;
use App\Livewire\Actions\Api\SearchCategories;
use App\Livewire\Actions\Api\SearchSpotify;
use App\Livewire\Actions\Api\Twitch\RefreshToken;
use Illuminate\Auth\Events\Lockout;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\RateLimiter;
Expand Down Expand Up @@ -46,7 +45,7 @@ public function authenticate(): void
auth()->user()->update(['timezone' => timezone()]);

(new SearchSpotify)->refreshToken(auth()->user());
(new SearchCategories)->refreshToken(auth()->user());
(new RefreshToken)->handle(auth()->user());
}

/**
Expand Down
5 changes: 0 additions & 5 deletions app/Models/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,6 @@ class Connection extends Model
'refresh_token',
];

public function type(): HasOne
{
return $this->hasOne(ConnectionType::class, 'type_id', 'id');
}

public function user(): BelongsTo
{
return $this->belongsTo(User::class);
Expand Down
14 changes: 0 additions & 14 deletions app/Models/ConnectionType.php

This file was deleted.

1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"livewire/flux": "^2.10",
"livewire/flux-pro": "^2.10",
"livewire/livewire": "4.0",
"marvinlabs/laravel-discord-logger": "^1.4",
"prezet/prezet": "^1.1",
"socialiteproviders/spotify": "^4.1",
"socialiteproviders/twitch": "^5.4",
Expand Down
Loading