fixes
This commit is contained in:
@@ -12,22 +12,36 @@ use Illuminate\Console\Command;
|
|||||||
|
|
||||||
class ImportGamesCommand extends Command
|
class ImportGamesCommand extends Command
|
||||||
{
|
{
|
||||||
protected $signature = 'games:import {--limit=100} {--offset=0} {--popular} {--new}';
|
protected $signature = 'games:import {--limit=100} {--offset=0} {--popular} {--new} {--year=} {--platform=}';
|
||||||
protected $description = 'Import games from IGDB into the local database';
|
protected $description = 'Import games from IGDB into the local database';
|
||||||
|
|
||||||
public function handle(IgdbService $igdb): int
|
public function handle(IgdbService $igdb): int
|
||||||
{
|
{
|
||||||
$limit = (int) $this->option('limit');
|
$limit = (int) $this->option('limit');
|
||||||
$offset = (int) $this->option('offset');
|
$offset = (int) $this->option('offset');
|
||||||
|
$year = $this->option('year') ? (int) $this->option('year') : null;
|
||||||
|
$platform = $this->option('platform') ? (int) $this->option('platform') : null;
|
||||||
|
|
||||||
$this->info("Fetching {$limit} games from IGDB (offset: {$offset})…");
|
if ($year && $platform) {
|
||||||
|
$this->error('Use --year or --platform, not both.');
|
||||||
|
return self::FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
$label = match (true) {
|
||||||
|
$year !== null => "year {$year}",
|
||||||
|
$platform !== null => "platform IGDB ID {$platform}",
|
||||||
|
$this->option('new') => 'new releases',
|
||||||
|
default => "popular (offset: {$offset})",
|
||||||
|
};
|
||||||
|
$this->info("Fetching {$limit} games from IGDB ({$label})…");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if ($this->option('new')) {
|
$results = match (true) {
|
||||||
$results = $igdb->getNewReleases($limit);
|
$year !== null => $igdb->getGamesByYear($year, $limit, $offset),
|
||||||
} else {
|
$platform !== null => $igdb->getGamesByPlatform($platform, $limit, $offset),
|
||||||
$results = $igdb->getPopularGames($limit, $offset);
|
$this->option('new') => $igdb->getNewReleases($limit),
|
||||||
}
|
default => $igdb->getPopularGames($limit, $offset),
|
||||||
|
};
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
$this->error('IGDB request failed: ' . $e->getMessage());
|
$this->error('IGDB request failed: ' . $e->getMessage());
|
||||||
return self::FAILURE;
|
return self::FAILURE;
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ class GameController extends Controller
|
|||||||
if (auth()->check()) {
|
if (auth()->check()) {
|
||||||
$userGame = $game->userGames()->where('user_id', auth()->id())->first();
|
$userGame = $game->userGames()->where('user_id', auth()->id())->first();
|
||||||
$userReview = $game->reviews()->where('user_id', auth()->id())->first();
|
$userReview = $game->reviews()->where('user_id', auth()->id())->first();
|
||||||
$userLists = auth()->user()->lists()->get(['id', 'title']);
|
$userLists = auth()->user()->lists()->get(['id', 'slug', 'title']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$comments = $game->comments()->whereNull('parent_id')
|
$comments = $game->comments()->whereNull('parent_id')
|
||||||
|
|||||||
@@ -139,6 +139,51 @@ class IgdbService
|
|||||||
");
|
");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get games released in a given year.
|
||||||
|
*/
|
||||||
|
public function getGamesByYear(int $year, int $limit = 20, int $offset = 0): array
|
||||||
|
{
|
||||||
|
$from = mktime(0, 0, 0, 1, 1, $year);
|
||||||
|
$to = mktime(23, 59, 59, 12, 31, $year);
|
||||||
|
|
||||||
|
return $this->query('games', "
|
||||||
|
fields id,name,slug,summary,cover.image_id,first_release_date,
|
||||||
|
genres.id,genres.name,genres.slug,
|
||||||
|
platforms.id,platforms.name,platforms.slug,platforms.abbreviation,
|
||||||
|
involved_companies.company.id,involved_companies.company.name,
|
||||||
|
involved_companies.company.slug,involved_companies.developer,
|
||||||
|
involved_companies.publisher,
|
||||||
|
screenshots.image_id,
|
||||||
|
rating,rating_count;
|
||||||
|
where first_release_date >= {$from} & first_release_date <= {$to} & cover != null;
|
||||||
|
sort rating_count desc;
|
||||||
|
limit {$limit};
|
||||||
|
offset {$offset};
|
||||||
|
");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get games for a given platform IGDB ID.
|
||||||
|
*/
|
||||||
|
public function getGamesByPlatform(int $platformIgdbId, int $limit = 20, int $offset = 0): array
|
||||||
|
{
|
||||||
|
return $this->query('games', "
|
||||||
|
fields id,name,slug,summary,cover.image_id,first_release_date,
|
||||||
|
genres.id,genres.name,genres.slug,
|
||||||
|
platforms.id,platforms.name,platforms.slug,platforms.abbreviation,
|
||||||
|
involved_companies.company.id,involved_companies.company.name,
|
||||||
|
involved_companies.company.slug,involved_companies.developer,
|
||||||
|
involved_companies.publisher,
|
||||||
|
screenshots.image_id,
|
||||||
|
rating,rating_count;
|
||||||
|
where platforms = [{$platformIgdbId}] & cover != null & rating != null;
|
||||||
|
sort rating_count desc;
|
||||||
|
limit {$limit};
|
||||||
|
offset {$offset};
|
||||||
|
");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get games by genre.
|
* Get games by genre.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -196,27 +196,28 @@
|
|||||||
<div x-show="open" @click.outside="open = false" x-transition
|
<div x-show="open" @click.outside="open = false" x-transition
|
||||||
class="mt-1 w-56 bg-[#16161d] border border-white/10 rounded-lg shadow-xl overflow-hidden z-10"
|
class="mt-1 w-56 bg-[#16161d] border border-white/10 rounded-lg shadow-xl overflow-hidden z-10"
|
||||||
style="display:none;">
|
style="display:none;">
|
||||||
@if($userLists->isEmpty())
|
<template x-if="lists.length === 0">
|
||||||
<div class="px-4 py-3 text-sm text-slate-500">
|
<div class="px-4 py-3 text-sm text-slate-500">
|
||||||
No lists yet.
|
No lists yet.
|
||||||
<a href="{{ route('lists.index') }}" class="text-purple-400 hover:text-purple-300">Create one</a>
|
<a href="{{ route('lists.index') }}" class="text-purple-400 hover:text-purple-300">Create one</a>
|
||||||
</div>
|
</div>
|
||||||
@else
|
</template>
|
||||||
<template x-for="list in lists" :key="list.id">
|
<template x-for="list in lists" :key="list.slug">
|
||||||
<button type="button" @click="toggleList(list.id)"
|
<button type="button" @click="toggleList(list.slug)"
|
||||||
class="w-full flex items-center gap-2 px-4 py-2.5 text-sm hover:bg-white/5 transition-colors"
|
class="w-full flex items-center gap-2 px-4 py-2.5 text-sm hover:bg-white/5 transition-colors"
|
||||||
:class="added[list.id] ? 'text-purple-400' : 'text-slate-300'">
|
:class="added[list.slug] ? 'text-purple-400' : 'text-slate-300'">
|
||||||
<svg x-show="added[list.id]" class="w-4 h-4 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
|
<svg x-show="added[list.slug]" class="w-4 h-4 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
|
||||||
<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"/>
|
<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"/>
|
||||||
</svg>
|
</svg>
|
||||||
<span x-show="!added[list.id]" class="w-4 h-4 flex-shrink-0"></span>
|
<span x-show="!added[list.slug]" class="w-4 h-4 flex-shrink-0"></span>
|
||||||
<span x-text="list.title" class="truncate"></span>
|
<span x-text="list.title" class="truncate"></span>
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
|
<template x-if="lists.length > 0">
|
||||||
<div class="border-t border-white/5 px-4 py-2">
|
<div class="border-t border-white/5 px-4 py-2">
|
||||||
<a href="{{ route('lists.index') }}" class="text-xs text-slate-500 hover:text-slate-300 transition-colors">Manage lists →</a>
|
<a href="{{ route('lists.index') }}" class="text-xs text-slate-500 hover:text-slate-300 transition-colors">Manage lists →</a>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@else
|
@else
|
||||||
@@ -799,11 +800,11 @@ function addToListWidget(gameId, lists) {
|
|||||||
open: false,
|
open: false,
|
||||||
added: {},
|
added: {},
|
||||||
|
|
||||||
async toggleList(listId) {
|
async toggleList(listSlug) {
|
||||||
const isAdded = this.added[listId];
|
const isAdded = this.added[listSlug];
|
||||||
const url = isAdded
|
const url = isAdded
|
||||||
? `/lists/${listId}/games/${this.gameId}`
|
? `/lists/${listSlug}/games/${this.gameId}`
|
||||||
: `/lists/${listId}/games`;
|
: `/lists/${listSlug}/games`;
|
||||||
const method = isAdded ? 'DELETE' : 'POST';
|
const method = isAdded ? 'DELETE' : 'POST';
|
||||||
|
|
||||||
const res = await fetch(url, {
|
const res = await fetch(url, {
|
||||||
@@ -817,7 +818,7 @@ function addToListWidget(gameId, lists) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
this.added[listId] = !isAdded;
|
this.added[listSlug] = !isAdded;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -56,7 +56,7 @@
|
|||||||
<x-game-card :game="$entry->game" />
|
<x-game-card :game="$entry->game" />
|
||||||
@auth
|
@auth
|
||||||
@if(auth()->id() === $list->user_id)
|
@if(auth()->id() === $list->user_id)
|
||||||
<button onclick="removeGameFromList({{ $list->id }}, {{ $entry->game->id }}, this)"
|
<button onclick="removeGameFromList('{{ $list->slug }}', '{{ $entry->game->slug }}', this)"
|
||||||
class="absolute top-2 right-2 w-6 h-6 bg-red-600 hover:bg-red-700 text-white rounded-full text-xs font-bold opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center leading-none">
|
class="absolute top-2 right-2 w-6 h-6 bg-red-600 hover:bg-red-700 text-white rounded-full text-xs font-bold opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center leading-none">
|
||||||
×
|
×
|
||||||
</button>
|
</button>
|
||||||
@@ -71,9 +71,9 @@
|
|||||||
|
|
||||||
@push('scripts')
|
@push('scripts')
|
||||||
<script>
|
<script>
|
||||||
function removeGameFromList(listId, gameId, btn) {
|
function removeGameFromList(listSlug, gameSlug, btn) {
|
||||||
if (!confirm('Remove from list?')) return;
|
if (!confirm('Remove from list?')) return;
|
||||||
fetch(`/lists/${listId}/games/${gameId}`, {
|
fetch(`/lists/${listSlug}/games/${gameSlug}`, {
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
headers: {
|
headers: {
|
||||||
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content,
|
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content,
|
||||||
|
|||||||
Reference in New Issue
Block a user