mirror of
https://github.com/AnimeThemes/animethemes-server.git
synced 2026-07-11 01:24:46 +02:00
fix(admin): add missing constraints to resource queries in backfill anime actions (#396)
This commit is contained in:
@@ -9,6 +9,7 @@ use App\Models\Auth\User;
|
||||
use App\Models\Wiki\ExternalResource;
|
||||
use App\Pivots\AnimeResource;
|
||||
use Closure;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Http\Client\RequestException;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
@@ -60,9 +61,9 @@ abstract class BackfillAnimeResource extends BackfillAnimePipe
|
||||
protected function getOrCreateResource(int $id, string $slug = null): ExternalResource
|
||||
{
|
||||
$resource = ExternalResource::query()
|
||||
->select([ExternalResource::ATTRIBUTE_ID, ExternalResource::ATTRIBUTE_LINK])
|
||||
->where(ExternalResource::ATTRIBUTE_SITE, $this->getSite()->value)
|
||||
->where(ExternalResource::ATTRIBUTE_EXTERNAL_ID, $id)
|
||||
->whereHas(ExternalResource::RELATION_ANIME, fn (Builder $animeQuery) => $animeQuery->whereKey($this->anime->getKey()))
|
||||
->first();
|
||||
|
||||
if ($resource === null) {
|
||||
|
||||
@@ -11,6 +11,7 @@ use App\Models\Wiki\Studio;
|
||||
use App\Pipes\Wiki\Anime\BackfillAnimePipe;
|
||||
use App\Pivots\StudioResource;
|
||||
use Closure;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Http\Client\RequestException;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
@@ -335,6 +336,7 @@ class BackfillAnimeStudios extends BackfillAnimePipe
|
||||
$studioResource = ExternalResource::query()
|
||||
->where(ExternalResource::ATTRIBUTE_SITE, $site->value)
|
||||
->where(ExternalResource::ATTRIBUTE_EXTERNAL_ID, $id)
|
||||
->whereHas(ExternalResource::RELATION_STUDIOS, fn (Builder $studioQuery) => $studioQuery->whereKey($studio))
|
||||
->first();
|
||||
|
||||
if (! $studioResource instanceof ExternalResource) {
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Enums\Models\Wiki\ResourceSite;
|
||||
use App\Models\Wiki\Anime;
|
||||
use App\Models\Wiki\ExternalResource;
|
||||
use App\Pivots\AnimeResource;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Http\Client\RequestException;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Class AniDbResourceSeeder.
|
||||
*/
|
||||
class AniDbResourceSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
// Get anime that have MAL resource but do not have AniDB resource
|
||||
$animes = Anime::query()
|
||||
->select([Anime::ATTRIBUTE_ID, Anime::ATTRIBUTE_NAME])
|
||||
->whereHas(Anime::RELATION_RESOURCES, function (Builder $resourceQuery) {
|
||||
$resourceQuery->where(ExternalResource::ATTRIBUTE_SITE, ResourceSite::MAL);
|
||||
})->whereDoesntHave(Anime::RELATION_RESOURCES, function (Builder $resourceQuery) {
|
||||
$resourceQuery->where(ExternalResource::ATTRIBUTE_SITE, ResourceSite::ANIDB);
|
||||
})
|
||||
->get();
|
||||
|
||||
foreach ($animes as $anime) {
|
||||
if (! $anime instanceof Anime) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$malResource = $anime->resources()->firstWhere(ExternalResource::ATTRIBUTE_SITE, ResourceSite::MAL);
|
||||
if ($malResource instanceof ExternalResource && $malResource->external_id !== null) {
|
||||
// Try not to upset Yuna
|
||||
sleep(rand(2, 5));
|
||||
|
||||
// Yuna api call
|
||||
try {
|
||||
$response = Http::get('https://relations.yuna.moe/api/ids', [
|
||||
'source' => 'myanimelist',
|
||||
'id' => $malResource->external_id,
|
||||
])
|
||||
->throw()
|
||||
->json();
|
||||
|
||||
$anidbId = Arr::get($response, 'anidb');
|
||||
|
||||
// Only proceed if we have a match
|
||||
if ($anidbId !== null) {
|
||||
// Check if AniDB resource already exists
|
||||
$anidbResource = ExternalResource::query()
|
||||
->select([ExternalResource::ATTRIBUTE_ID, ExternalResource::ATTRIBUTE_LINK])
|
||||
->where(ExternalResource::ATTRIBUTE_SITE, ResourceSite::ANIDB)
|
||||
->where(ExternalResource::ATTRIBUTE_EXTERNAL_ID, $anidbId)
|
||||
->first();
|
||||
|
||||
// Create AniDB resource if it doesn't already exist
|
||||
if ($anidbResource === null) {
|
||||
Log::info("Creating anidb resource '$anidbId' for anime '$anime->name'");
|
||||
|
||||
$anidbResource = ExternalResource::factory()->createOne([
|
||||
ExternalResource::ATTRIBUTE_EXTERNAL_ID => $anidbId,
|
||||
ExternalResource::ATTRIBUTE_LINK => "https://anidb.net/anime/$anidbId",
|
||||
ExternalResource::ATTRIBUTE_SITE => ResourceSite::ANIDB,
|
||||
]);
|
||||
}
|
||||
|
||||
// Attach AniDB resource to anime
|
||||
if (AnimeResource::query()
|
||||
->where($anime->getKeyName(), $anime->getKey())
|
||||
->where($anidbResource->getKeyName(), $anidbResource->getKey())
|
||||
->doesntExist()
|
||||
) {
|
||||
Log::info("Attaching resource '$anidbResource->link' to anime '$anime->name'");
|
||||
$anidbResource->anime()->attach($anime);
|
||||
}
|
||||
}
|
||||
} catch (RequestException $e) {
|
||||
Log::info($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Enums\Models\Wiki\ResourceSite;
|
||||
use App\Models\Wiki\Anime;
|
||||
use App\Models\Wiki\ExternalResource;
|
||||
use App\Pivots\AnimeResource;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Http\Client\RequestException;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Class AnilistAnimeResourceSeeder.
|
||||
*/
|
||||
class AnilistAnimeResourceSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
// Get anime that have MAL resource but do not have Anilist resource
|
||||
$animes = Anime::query()
|
||||
->select([Anime::ATTRIBUTE_ID, Anime::ATTRIBUTE_NAME])
|
||||
->whereHas(Anime::RELATION_RESOURCES, function (Builder $resourceQuery) {
|
||||
$resourceQuery->where(ExternalResource::ATTRIBUTE_SITE, ResourceSite::MAL);
|
||||
})->whereDoesntHave(Anime::RELATION_RESOURCES, function (Builder $resourceQuery) {
|
||||
$resourceQuery->where(ExternalResource::ATTRIBUTE_SITE, ResourceSite::ANILIST);
|
||||
})
|
||||
->get();
|
||||
|
||||
foreach ($animes as $anime) {
|
||||
if (! $anime instanceof Anime) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$malResource = $anime->resources()->firstWhere(ExternalResource::ATTRIBUTE_SITE, ResourceSite::MAL);
|
||||
if ($malResource instanceof ExternalResource && $malResource->external_id !== null) {
|
||||
// Try not to upset Anilist
|
||||
sleep(rand(2, 5));
|
||||
|
||||
// Anilist graphql query
|
||||
$query = '
|
||||
query ($id: Int) {
|
||||
Media (idMal: $id, type: ANIME) {
|
||||
id
|
||||
}
|
||||
}
|
||||
';
|
||||
|
||||
// Anilist graphql variables
|
||||
$variables = [
|
||||
'id' => $malResource->external_id,
|
||||
];
|
||||
|
||||
// Anilist graphql api call
|
||||
try {
|
||||
$response = Http::post('https://graphql.anilist.co', [
|
||||
'query' => $query,
|
||||
'variables' => $variables,
|
||||
])
|
||||
->throw()
|
||||
->json();
|
||||
|
||||
$anilistId = Arr::get($response, 'data.Media.id');
|
||||
|
||||
// Check if Anilist resource already exists
|
||||
$anilistResource = ExternalResource::query()
|
||||
->select([ExternalResource::ATTRIBUTE_ID, ExternalResource::ATTRIBUTE_LINK])
|
||||
->where(ExternalResource::ATTRIBUTE_SITE, ResourceSite::ANILIST)
|
||||
->where(ExternalResource::ATTRIBUTE_EXTERNAL_ID, $anilistId)
|
||||
->first();
|
||||
|
||||
// Create Anilist resource if it doesn't already exist
|
||||
if ($anilistResource === null) {
|
||||
Log::info("Creating anilist resource '$anilistId' for anime '$anime->name'");
|
||||
|
||||
$anilistResource = ExternalResource::factory()->createOne([
|
||||
ExternalResource::ATTRIBUTE_EXTERNAL_ID => $anilistId,
|
||||
ExternalResource::ATTRIBUTE_LINK => "https://anilist.co/anime/$anilistId/",
|
||||
ExternalResource::ATTRIBUTE_SITE => ResourceSite::ANILIST,
|
||||
]);
|
||||
}
|
||||
|
||||
// Attach Anilist resource to anime
|
||||
if (
|
||||
AnimeResource::query()
|
||||
->where($anime->getKeyName(), $anime->getKey())
|
||||
->where($anilistResource->getKeyName(), $anilistResource->getKey())
|
||||
->doesntExist()
|
||||
) {
|
||||
Log::info("Attaching resource '$anilistResource->link' to anime '$anime->name'");
|
||||
$anilistResource->anime()->attach($anime);
|
||||
}
|
||||
} catch (RequestException $e) {
|
||||
Log::info($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Enums\Models\Wiki\ResourceSite;
|
||||
use App\Models\Wiki\Artist;
|
||||
use App\Models\Wiki\ExternalResource;
|
||||
use App\Pivots\ArtistResource;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Http\Client\RequestException;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Class AnilistArtistResourceSeeder.
|
||||
*/
|
||||
class AnilistArtistResourceSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
// Get artists that have MAL resource but do not have Anilist resource
|
||||
$artists = Artist::query()
|
||||
->select([Artist::ATTRIBUTE_ID, Artist::ATTRIBUTE_NAME])
|
||||
->whereDoesntHave(Artist::RELATION_RESOURCES, function (Builder $resourceQuery) {
|
||||
$resourceQuery->where(ExternalResource::ATTRIBUTE_SITE, ResourceSite::ANILIST);
|
||||
})
|
||||
->get();
|
||||
|
||||
foreach ($artists as $artist) {
|
||||
if (! $artist instanceof Artist) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Try not to upset Anilist
|
||||
sleep(rand(2, 5));
|
||||
|
||||
// Anilist graphql query
|
||||
$query = '
|
||||
query ($artistQuery: String) {
|
||||
Staff (search: $artistQuery) {
|
||||
id
|
||||
}
|
||||
}
|
||||
';
|
||||
|
||||
// Anilist graphql variables
|
||||
$variables = [
|
||||
'artistQuery' => $artist->name,
|
||||
];
|
||||
|
||||
// Anilist graphql api call
|
||||
try {
|
||||
$response = Http::post('https://graphql.anilist.co', [
|
||||
'query' => $query,
|
||||
'variables' => $variables,
|
||||
])
|
||||
->throw()
|
||||
->json();
|
||||
|
||||
$anilistId = Arr::get($response, 'data.Staff.id');
|
||||
|
||||
// Check if Anilist resource already exists
|
||||
$anilistResource = ExternalResource::query()
|
||||
->select([ExternalResource::ATTRIBUTE_ID, ExternalResource::ATTRIBUTE_LINK])
|
||||
->where(ExternalResource::ATTRIBUTE_SITE, ResourceSite::ANILIST)
|
||||
->where(ExternalResource::ATTRIBUTE_EXTERNAL_ID, $anilistId)
|
||||
->first();
|
||||
|
||||
// Create Anilist resource if it doesn't already exist
|
||||
if ($anilistResource === null) {
|
||||
Log::info("Creating anilist resource '$anilistId' for artist '$artist->name'");
|
||||
|
||||
$anilistResource = ExternalResource::factory()->createOne([
|
||||
ExternalResource::ATTRIBUTE_EXTERNAL_ID => $anilistId,
|
||||
ExternalResource::ATTRIBUTE_LINK => "https://anilist.co/staff/$anilistId/",
|
||||
ExternalResource::ATTRIBUTE_SITE => ResourceSite::ANILIST,
|
||||
]);
|
||||
}
|
||||
|
||||
// Attach Anilist resource to artist
|
||||
if (
|
||||
ArtistResource::query()
|
||||
->where($artist->getKeyName(), $artist->getKey())
|
||||
->where($anilistResource->getKeyName(), $anilistResource->getKey())
|
||||
->doesntExist()
|
||||
) {
|
||||
Log::info("Attaching resource '$anilistResource->link' to artist '$artist->name'");
|
||||
$anilistResource->artists()->attach($artist);
|
||||
}
|
||||
} catch (RequestException $e) {
|
||||
Log::info($e->getMessage());
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Enums\Models\Wiki\ImageFacet;
|
||||
use App\Enums\Models\Wiki\ResourceSite;
|
||||
use App\Models\Wiki\Artist;
|
||||
use App\Models\Wiki\ExternalResource;
|
||||
use App\Models\Wiki\Image;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Http\Client\RequestException;
|
||||
use Illuminate\Http\Testing\File;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
/**
|
||||
* Class ArtistCoverSeeder.
|
||||
*/
|
||||
class ArtistCoverSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
// Get artists that have MAL resource but not both cover images
|
||||
$artists = Artist::query()
|
||||
->select([Artist::ATTRIBUTE_ID, Artist::ATTRIBUTE_NAME])
|
||||
->whereHas(Artist::RELATION_RESOURCES, function (Builder $resourceQuery) {
|
||||
$resourceQuery->where(ExternalResource::ATTRIBUTE_SITE, ResourceSite::ANILIST);
|
||||
})->whereDoesntHave(Artist::RELATION_IMAGES, function (Builder $imageQuery) {
|
||||
$imageQuery->whereIn(Image::ATTRIBUTE_FACET, [ImageFacet::COVER_LARGE, ImageFacet::COVER_SMALL]);
|
||||
})
|
||||
->get();
|
||||
|
||||
$fs = Storage::disk('images');
|
||||
|
||||
foreach ($artists as $artist) {
|
||||
if (! $artist instanceof Artist) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$anilistResource = $artist->resources()->firstWhere(ExternalResource::ATTRIBUTE_SITE, ResourceSite::ANILIST);
|
||||
if ($anilistResource instanceof ExternalResource && $anilistResource->external_id !== null) {
|
||||
$artistCoverLarge = $artist->images()->where(Image::ATTRIBUTE_FACET, ImageFacet::COVER_LARGE)->first();
|
||||
$artistCoverSmall = $artist->images()->where(Image::ATTRIBUTE_FACET, ImageFacet::COVER_SMALL)->first();
|
||||
|
||||
// Try not to upset Anilist
|
||||
sleep(rand(2, 5));
|
||||
|
||||
// Anilist graphql query
|
||||
$query = '
|
||||
query ($id: Int) {
|
||||
Staff (id: $id) {
|
||||
image {
|
||||
large
|
||||
medium
|
||||
}
|
||||
}
|
||||
}
|
||||
';
|
||||
|
||||
// Anilist graphql variables
|
||||
$variables = [
|
||||
'id' => $anilistResource->external_id,
|
||||
];
|
||||
|
||||
// Anilist graphql api call
|
||||
try {
|
||||
$response = Http::post('https://graphql.anilist.co', [
|
||||
'query' => $query,
|
||||
'variables' => $variables,
|
||||
])
|
||||
->throw()
|
||||
->json();
|
||||
|
||||
$anilistCoverLarge = Arr::get($response, 'data.Staff.image.large');
|
||||
$anilistCoverSmall = Arr::get($response, 'data.Staff.image.medium');
|
||||
|
||||
// Create large cover image
|
||||
if ($anilistCoverLarge !== null && $artistCoverLarge === null) {
|
||||
$coverImageResponse = Http::get($anilistCoverLarge);
|
||||
$coverImage = $coverImageResponse->body();
|
||||
$coverFile = File::createWithContent(basename($anilistCoverLarge), $coverImage);
|
||||
$coverLarge = $fs->putFile('', $coverFile);
|
||||
|
||||
$coverLargeImage = Image::factory()->createOne([
|
||||
Image::ATTRIBUTE_FACET => ImageFacet::COVER_LARGE,
|
||||
Image::ATTRIBUTE_PATH => $coverLarge,
|
||||
]);
|
||||
|
||||
// Attach large cover to artist
|
||||
Log::info("Attaching image '$coverLargeImage->path' to artist '$artist->name'");
|
||||
$coverLargeImage->artists()->attach($artist);
|
||||
}
|
||||
|
||||
// Create small cover image
|
||||
if ($anilistCoverSmall !== null && $artistCoverSmall === null) {
|
||||
$coverImageResponse = Http::get($anilistCoverSmall);
|
||||
$coverImage = $coverImageResponse->body();
|
||||
$coverFile = File::createWithContent(basename($anilistCoverSmall), $coverImage);
|
||||
$coverSmall = $fs->putFile('', $coverFile);
|
||||
|
||||
$coverSmallImage = Image::factory()->createOne([
|
||||
Image::ATTRIBUTE_FACET => ImageFacet::COVER_SMALL,
|
||||
Image::ATTRIBUTE_PATH => $coverSmall,
|
||||
]);
|
||||
|
||||
// Attach large cover to artist
|
||||
Log::info("Attaching image '$coverSmallImage->path' to artist '$artist->name'");
|
||||
$coverSmallImage->artists()->attach($artist);
|
||||
}
|
||||
} catch (RequestException $e) {
|
||||
Log::info($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,13 +18,8 @@ class DatabaseSeeder extends Seeder
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
$this->call(DigitalOceanTransactionSeeder::class);
|
||||
$this->call(PermissionSeeder::class);
|
||||
$this->call(VideoSeeder::class);
|
||||
$this->call(AnilistAnimeResourceSeeder::class);
|
||||
$this->call(SynopsisCoverSeeder::class);
|
||||
$this->call(AniDbResourceSeeder::class);
|
||||
$this->call(AnilistArtistResourceSeeder::class);
|
||||
$this->call(ArtistCoverSeeder::class);
|
||||
$this->call(KitsuResourceSeeder::class);
|
||||
$this->call(StudioSeeder::class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Enums\Models\Wiki\ResourceSite;
|
||||
use App\Models\Wiki\Anime;
|
||||
use App\Models\Wiki\ExternalResource;
|
||||
use App\Pivots\AnimeResource;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Http\Client\RequestException;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Class KitsuResourceSeeder.
|
||||
*/
|
||||
class KitsuResourceSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
// Get anime that have MAL resource but do not have Kitsu resource
|
||||
$animes = Anime::query()
|
||||
->select([Anime::ATTRIBUTE_ID, Anime::ATTRIBUTE_NAME])
|
||||
->whereHas(Anime::RELATION_RESOURCES, function (Builder $resourceQuery) {
|
||||
$resourceQuery->where(ExternalResource::ATTRIBUTE_SITE, ResourceSite::MAL);
|
||||
})->whereDoesntHave(Anime::RELATION_RESOURCES, function (Builder $resourceQuery) {
|
||||
$resourceQuery->where(ExternalResource::ATTRIBUTE_SITE, ResourceSite::KITSU);
|
||||
})
|
||||
->get();
|
||||
|
||||
foreach ($animes as $anime) {
|
||||
if (! $anime instanceof Anime) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$malResource = $anime->resources()->firstWhere(ExternalResource::ATTRIBUTE_SITE, ResourceSite::MAL);
|
||||
if ($malResource instanceof ExternalResource && $malResource->external_id !== null) {
|
||||
// Try not to upset Kitsu
|
||||
sleep(rand(2, 5));
|
||||
|
||||
// Kitsu api call
|
||||
try {
|
||||
$response = Http::contentType('application/vnd.api+json')
|
||||
->accept('application/vnd.api+json')
|
||||
->get('https://kitsu.io/api/edge/mappings', [
|
||||
'include' => 'item',
|
||||
'filter' => [
|
||||
'externalSite' => 'myanimelist/anime',
|
||||
'externalId' => $malResource->external_id,
|
||||
],
|
||||
])
|
||||
->throw()
|
||||
->json();
|
||||
|
||||
$kitsuResourceData = Arr::get($response, 'data', []);
|
||||
$kitsuResourceIncluded = Arr::get($response, 'included', []);
|
||||
|
||||
// Only proceed if we have a single match
|
||||
if (count($kitsuResourceData) === 1 && count($kitsuResourceIncluded) === 1) {
|
||||
$kitsuId = $kitsuResourceIncluded[0]['id'];
|
||||
$kitsuSlug = $kitsuResourceIncluded[0]['attributes']['slug'];
|
||||
|
||||
// Check if Kitsu resource already exists
|
||||
$kitsuResource = ExternalResource::query()
|
||||
->select([ExternalResource::ATTRIBUTE_ID, ExternalResource::ATTRIBUTE_LINK])
|
||||
->where(ExternalResource::ATTRIBUTE_SITE, ResourceSite::KITSU)
|
||||
->where(ExternalResource::ATTRIBUTE_EXTERNAL_ID, $kitsuId)
|
||||
->first();
|
||||
|
||||
// Create Kitsu resource if it doesn't already exist
|
||||
if ($kitsuResource === null) {
|
||||
Log::info("Creating kitsu resource '$kitsuId' for anime '$anime->name'");
|
||||
|
||||
$kitsuResource = ExternalResource::factory()->createOne([
|
||||
ExternalResource::ATTRIBUTE_EXTERNAL_ID => $kitsuId,
|
||||
ExternalResource::ATTRIBUTE_LINK => "https://kitsu.io/anime/$kitsuSlug",
|
||||
ExternalResource::ATTRIBUTE_SITE => ResourceSite::KITSU,
|
||||
]);
|
||||
}
|
||||
|
||||
// Attach Kitsu resource to anime
|
||||
if (AnimeResource::query()
|
||||
->where($anime->getKeyName(), $anime->getKey())
|
||||
->where($kitsuResource->getKeyName(), $kitsuResource->getKey())
|
||||
->doesntExist()
|
||||
) {
|
||||
Log::info("Attaching resource '$kitsuResource->link' to anime '$anime->name'");
|
||||
$kitsuResource->anime()->attach($anime);
|
||||
}
|
||||
}
|
||||
} catch (RequestException $e) {
|
||||
Log::info($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,6 @@ namespace Database\Seeders;
|
||||
use App\Models\Auth\Permission;
|
||||
use App\Models\Auth\Role;
|
||||
use Illuminate\Database\Seeder;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* Class PermissionSeeder.
|
||||
@@ -21,15 +20,14 @@ class PermissionSeeder extends Seeder
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
// Roles
|
||||
/** @var Role */
|
||||
$admin = Role::findOrCreate('Admin');
|
||||
$wikiEditor = Role::findOrCreate('Wiki Editor');
|
||||
$wikiViewer = Role::findOrCreate('Wiki Viewer');
|
||||
|
||||
// Spatie pls.
|
||||
if (! $admin instanceof Role || ! $wikiEditor instanceof Role || ! $wikiViewer instanceof Role) {
|
||||
throw new RuntimeException('Could not create roles');
|
||||
}
|
||||
/** @var Role */
|
||||
$wikiEditor = Role::findOrCreate('Wiki Editor');
|
||||
|
||||
/** @var Role */
|
||||
$wikiViewer = Role::findOrCreate('Wiki Viewer');
|
||||
|
||||
// Admin Resources
|
||||
$this->configureAdminResourcePermissions($admin, 'announcement', true);
|
||||
|
||||
@@ -1,128 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Enums\Http\Api\Filter\ComparisonOperator;
|
||||
use App\Enums\Models\Wiki\ResourceSite;
|
||||
use App\Models\Wiki\Anime;
|
||||
use App\Models\Wiki\ExternalResource;
|
||||
use App\Models\Wiki\Studio;
|
||||
use App\Pivots\AnimeStudio;
|
||||
use App\Pivots\StudioResource;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Http\Client\RequestException;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* Class StudioSeeder.
|
||||
*/
|
||||
class StudioSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
// Do not proceed if we do not have authorization to the MAL API
|
||||
$malClientID = Config::get('services.mal.client');
|
||||
if ($malClientID === null) {
|
||||
Log::error('MAL_CLIENT_ID must be configured in your env file.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$animes = Anime::query()
|
||||
->select([Anime::ATTRIBUTE_ID, Anime::ATTRIBUTE_NAME])
|
||||
->whereDoesntHave(Anime::RELATION_STUDIOS)
|
||||
->whereHas(Anime::RELATION_RESOURCES, function (Builder $resourceQuery) {
|
||||
$resourceQuery->where(ExternalResource::ATTRIBUTE_SITE, ResourceSite::MAL);
|
||||
})
|
||||
->get();
|
||||
|
||||
foreach ($animes as $anime) {
|
||||
if (! $anime instanceof Anime) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$malResource = $anime->resources()->firstWhere(ExternalResource::ATTRIBUTE_SITE, ResourceSite::MAL);
|
||||
if ($malResource instanceof ExternalResource && $malResource->external_id !== null) {
|
||||
// Try not to upset MAL
|
||||
sleep(rand(2, 5));
|
||||
|
||||
try {
|
||||
$response = Http::withHeaders(['X-MAL-CLIENT-ID' => $malClientID])
|
||||
->get("https://api.myanimelist.net/v2/anime/$malResource->external_id", [
|
||||
'fields' => 'studios',
|
||||
])
|
||||
->throw()
|
||||
->json();
|
||||
|
||||
$malStudios = Arr::get($response, 'studios', []);
|
||||
|
||||
foreach ($malStudios as $malStudio) {
|
||||
$name = Arr::get($malStudio, 'name');
|
||||
$id = Arr::get($malStudio, 'id');
|
||||
if (empty($name) || empty($id)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$studio = Studio::query()->firstWhere(Studio::ATTRIBUTE_NAME, $name);
|
||||
if (! $studio instanceof Studio) {
|
||||
Log::info("Creating studio '$name'");
|
||||
|
||||
$studio = Studio::factory()->createOne([
|
||||
Studio::ATTRIBUTE_NAME => $name,
|
||||
Studio::ATTRIBUTE_SLUG => Str::slug($name, '_'),
|
||||
]);
|
||||
}
|
||||
|
||||
$studioResource = ExternalResource::query()
|
||||
->where(ExternalResource::ATTRIBUTE_SITE, ResourceSite::MAL)
|
||||
->where(ExternalResource::ATTRIBUTE_EXTERNAL_ID, $id)
|
||||
->where(ExternalResource::ATTRIBUTE_LINK, ComparisonOperator::LIKE, 'https://myanimelist.net/anime/producer/%')
|
||||
->first();
|
||||
|
||||
if (! $studioResource instanceof ExternalResource) {
|
||||
Log::info("Creating studio resource with id '$id' and name '$name'");
|
||||
|
||||
$studioResource = ExternalResource::factory()->createOne([
|
||||
ExternalResource::ATTRIBUTE_EXTERNAL_ID => $id,
|
||||
ExternalResource::ATTRIBUTE_LINK => "https://myanimelist.net/anime/producer/$id/",
|
||||
ExternalResource::ATTRIBUTE_SITE => ResourceSite::MAL,
|
||||
]);
|
||||
}
|
||||
|
||||
if (StudioResource::query()
|
||||
->where($studio->getKeyName(), $studio->getKey())
|
||||
->where($studioResource->getKeyName(), $studioResource->getKey())
|
||||
->doesntExist()
|
||||
) {
|
||||
Log::info("Attaching resource '$studioResource->link' to studio '{$studio->getName()}'");
|
||||
$studioResource->studios()->attach($studio);
|
||||
}
|
||||
|
||||
if (AnimeStudio::query()
|
||||
->where($anime->getKeyName(), $anime->getKey())
|
||||
->where($studio->getKeyName(), $studio->getKey())
|
||||
->doesntExist()
|
||||
) {
|
||||
Log::info("Attaching studio '$name' to anime '{$anime->getName()}'");
|
||||
$anime->studios()->attach($studio);
|
||||
}
|
||||
}
|
||||
} catch (RequestException $e) {
|
||||
Log::info($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,135 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Enums\Models\Wiki\ImageFacet;
|
||||
use App\Enums\Models\Wiki\ResourceSite;
|
||||
use App\Models\Wiki\Anime;
|
||||
use App\Models\Wiki\ExternalResource;
|
||||
use App\Models\Wiki\Image;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Http\Client\RequestException;
|
||||
use Illuminate\Http\Testing\File;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
/**
|
||||
* Class SynopsisCoverSeeder.
|
||||
*/
|
||||
class SynopsisCoverSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
// Get anime that have MAL resource but not both cover images
|
||||
$animes = Anime::query()
|
||||
->select([Anime::ATTRIBUTE_ID, Anime::ATTRIBUTE_NAME, Anime::ATTRIBUTE_SYNOPSIS])
|
||||
->whereHas(Anime::RELATION_RESOURCES, function (Builder $resourceQuery) {
|
||||
$resourceQuery->where(ExternalResource::ATTRIBUTE_SITE, ResourceSite::ANILIST);
|
||||
})->whereDoesntHave(Anime::RELATION_IMAGES, function (Builder $imageQuery) {
|
||||
$imageQuery->whereIn(Image::ATTRIBUTE_FACET, [ImageFacet::COVER_LARGE, ImageFacet::COVER_SMALL]);
|
||||
})
|
||||
->get();
|
||||
|
||||
$fs = Storage::disk('images');
|
||||
|
||||
foreach ($animes as $anime) {
|
||||
if (! $anime instanceof Anime) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$anilistResource = $anime->resources()->firstWhere(ExternalResource::ATTRIBUTE_SITE, ResourceSite::ANILIST);
|
||||
if ($anilistResource instanceof ExternalResource && $anilistResource->external_id !== null) {
|
||||
$animeCoverLarge = $anime->images()->where(Image::ATTRIBUTE_FACET, ImageFacet::COVER_LARGE)->first();
|
||||
$animeCoverSmall = $anime->images()->where(Image::ATTRIBUTE_FACET, ImageFacet::COVER_SMALL)->first();
|
||||
|
||||
// Try not to upset Anilist
|
||||
sleep(rand(2, 5));
|
||||
|
||||
// Anilist graphql query
|
||||
$query = '
|
||||
query ($id: Int) {
|
||||
Media (id: $id, type: ANIME) {
|
||||
description
|
||||
coverImage {
|
||||
extraLarge
|
||||
medium
|
||||
}
|
||||
}
|
||||
}
|
||||
';
|
||||
|
||||
// Anilist graphql variables
|
||||
$variables = [
|
||||
'id' => $anilistResource->external_id,
|
||||
];
|
||||
|
||||
// Anilist graphql api call
|
||||
try {
|
||||
$response = Http::post('https://graphql.anilist.co', [
|
||||
'query' => $query,
|
||||
'variables' => $variables,
|
||||
])
|
||||
->throw()
|
||||
->json();
|
||||
|
||||
$anilistSynopsis = Arr::get($response, 'data.Media.description');
|
||||
$anilistCoverLarge = Arr::get($response, 'data.Media.coverImage.extraLarge');
|
||||
$anilistCoverSmall = Arr::get($response, 'data.Media.coverImage.medium');
|
||||
|
||||
// Set Anime synopsis
|
||||
if ($anilistSynopsis !== null && $anime->synopsis === null) {
|
||||
Log::info("Setting synopsis for anime '$anime->name'");
|
||||
$anime->synopsis = $anilistSynopsis;
|
||||
$anime->save();
|
||||
}
|
||||
|
||||
// Create large cover image
|
||||
if ($anilistCoverLarge !== null && $animeCoverLarge === null) {
|
||||
$coverImageResponse = Http::get($anilistCoverLarge);
|
||||
$coverImage = $coverImageResponse->body();
|
||||
$coverFile = File::createWithContent(basename($anilistCoverLarge), $coverImage);
|
||||
$coverLarge = $fs->putFile('', $coverFile);
|
||||
|
||||
$coverLargeImage = Image::factory()->createOne([
|
||||
Image::ATTRIBUTE_FACET => ImageFacet::COVER_LARGE,
|
||||
Image::ATTRIBUTE_PATH => $coverLarge,
|
||||
]);
|
||||
|
||||
// Attach large cover to anime
|
||||
Log::info("Attaching image '$coverLargeImage->path' to anime '$anime->name'");
|
||||
$coverLargeImage->anime()->attach($anime);
|
||||
}
|
||||
|
||||
// Create small cover image
|
||||
if ($anilistCoverSmall !== null && $animeCoverSmall === null) {
|
||||
$coverImageResponse = Http::get($anilistCoverSmall);
|
||||
$coverImage = $coverImageResponse->body();
|
||||
$coverFile = File::createWithContent(basename($anilistCoverSmall), $coverImage);
|
||||
$coverSmall = $fs->putFile('', $coverFile);
|
||||
|
||||
$coverSmallImage = Image::factory()->createOne([
|
||||
Image::ATTRIBUTE_FACET => ImageFacet::COVER_SMALL,
|
||||
Image::ATTRIBUTE_PATH => $coverSmall,
|
||||
]);
|
||||
|
||||
// Attach large cover to anime
|
||||
Log::info("Attaching image '$coverSmallImage->path' to anime '$anime->name'");
|
||||
$coverSmallImage->anime()->attach($anime);
|
||||
}
|
||||
} catch (RequestException $e) {
|
||||
Log::info($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user