feat(db): seed anime planet resources (#442)

* feat(db): seed anime planet resources

* style: fix StyleCI findings
This commit is contained in:
paranarimasu
2022-08-17 23:04:37 -05:00
committed by GitHub
parent 06ee91f968
commit bb667d0b45
3 changed files with 257 additions and 1 deletions
+1
View File
@@ -35,6 +35,7 @@
"cyrildewit/eloquent-viewable": "^6.1",
"fakerphp/faker": "^1.17",
"guzzlehttp/guzzle": "^7.4",
"halaxa/json-machine": "^1.1",
"laravel-notification-channels/discord": "^1.3",
"laravel/framework": "^9.19",
"laravel/horizon": "^5.8",
Generated
+59 -1
View File
@@ -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": "952c5568316bf16552f2ad3f834987d4",
"content-hash": "4b8addca4c6a5b9919c947f1613cbfc9",
"packages": [
{
"name": "aws/aws-crt-php",
@@ -3072,6 +3072,64 @@
],
"time": "2022-06-20T21:43:11+00:00"
},
{
"name": "halaxa/json-machine",
"version": "1.1.1",
"source": {
"type": "git",
"url": "https://github.com/halaxa/json-machine.git",
"reference": "b4086dfe72670df060d2bd481f01bc9e450a5640"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/halaxa/json-machine/zipball/b4086dfe72670df060d2bd481f01bc9e450a5640",
"reference": "b4086dfe72670df060d2bd481f01bc9e450a5640",
"shasum": ""
},
"require": {
"php": ">=7.0"
},
"require-dev": {
"ext-json": "*",
"friendsofphp/php-cs-fixer": "^3.0",
"phpunit/phpunit": "^8.0"
},
"suggest": {
"ext-json": "To run JSON Machine out of the box without custom decoders.",
"guzzlehttp/guzzle": "To run example with GuzzleHttp"
},
"type": "library",
"autoload": {
"psr-4": {
"JsonMachine\\": "src/"
},
"exclude-from-classmap": [
"src/autoloader.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache-2.0"
],
"authors": [
{
"name": "Filip Halaxa",
"email": "filip@halaxa.cz"
}
],
"description": "Efficient, easy-to-use and fast JSON pull parser",
"support": {
"issues": "https://github.com/halaxa/json-machine/issues",
"source": "https://github.com/halaxa/json-machine/tree/1.1.1"
},
"funding": [
{
"url": "https://ko-fi.com/G2G57KTE4",
"type": "other"
}
],
"time": "2022-03-03T11:02:11+00:00"
},
{
"name": "inertiajs/inertia-laravel",
"version": "v0.6.3",
@@ -0,0 +1,197 @@
<?php
declare(strict_types=1);
namespace Database\Seeders;
use App\Enums\Models\Wiki\AnimeSeason;
use App\Enums\Models\Wiki\ResourceSite;
use App\Models\Wiki\Anime;
use App\Models\Wiki\Anime\AnimeSynonym;
use App\Models\Wiki\ExternalResource;
use Exception;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Seeder;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use JsonMachine\Exception\InvalidArgumentException;
use JsonMachine\Items;
use JsonMachine\JsonDecoder\ExtJsonDecoder;
/**
* Class AnimePlanetResourceSeeder.
*/
class AnimePlanetResourceSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*
* @throws InvalidArgumentException
*/
public function run(): void
{
$path = storage_path('app/anime-offline-database.json');
$data = Items::fromFile($path, [
'decoder' => new ExtJsonDecoder(true),
'pointer' => '/data',
]);
foreach ($data as $animeData) {
$anime = $this->getAnime($animeData);
if ($anime === null) {
continue;
}
$animePlanetResource = $anime->resources->firstWhere(fn (ExternalResource $resource) => ResourceSite::ANIME_PLANET()->is($resource->site));
if ($animePlanetResource !== null) {
continue;
}
$animePlanetLinks = $this->getAnimePlanetSources($animeData);
foreach ($animePlanetLinks as $animePlanetLink) {
$resource = $this->getOrCreateResource($animePlanetLink);
Log::info("Attaching Resource '{$resource->getName()}' to Anime '{$anime->getName()}'");
$anime->resources()->attach($resource);
}
}
}
/**
* Resolve anime from data entry.
* Here we will funnel query criteria to account for year and season mismatches.
*
* @param array $animeData
* @return Anime|null
*/
protected function getAnime(array $animeData): ?Anime
{
$builder = Anime::query();
$builder = $builder->with(Anime::RELATION_RESOURCES);
$title = Arr::get($animeData, 'title');
$synonyms = Arr::get($animeData, 'synonyms');
if (is_string($title) && is_array($synonyms)) {
$builder->where(function (Builder $query) use ($title, $synonyms) {
$query->orWhere(Anime::ATTRIBUTE_NAME, $title)
->orWhereHas(
Anime::RELATION_SYNONYMS,
fn (Builder $synonymBuilder) => $synonymBuilder->whereIn(AnimeSynonym::ATTRIBUTE_TEXT, $synonyms)
);
});
}
$anime = $builder->get();
if ($anime->containsOneItem()) {
return $anime->first();
}
$year = Arr::get($animeData, 'animeSeason.year');
if (is_numeric($year)) {
$builder = $builder->where(Anime::ATTRIBUTE_YEAR, $year);
}
$anime = $builder->get();
if ($anime->containsOneItem()) {
return $anime->first();
}
try {
$season = AnimeSeason::getValue(Arr::get($animeData, 'animeSeason.season'));
if (is_numeric($season)) {
$builder = $builder->where(Anime::ATTRIBUTE_SEASON, $season);
}
} catch (Exception) {
$season = Arr::get($animeData, 'animeSeason.season');
Log::error("Invalid season key $season");
}
$anime = $builder->get();
if ($anime->containsOneItem()) {
return $anime->first();
}
return null;
}
/**
* Get the Anime Planet source links.
*
* @param array $animeData
* @return array
*/
protected function getAnimePlanetSources(array $animeData): array
{
$sources = Arr::get($animeData, 'sources');
if (is_array($sources)) {
return Arr::where($sources, fn (string $link) => ResourceSite::ANIME_PLANET()->is(ResourceSite::valueOf($link)));
}
return [];
}
/**
* Get or Create Resource from link.
*
* @param string $animePlanetLink
* @return ExternalResource
*/
protected function getOrCreateResource(string $animePlanetLink): ExternalResource
{
$resource = ExternalResource::query()
->where(ExternalResource::ATTRIBUTE_LINK, $animePlanetLink)
->first();
if ($resource == null) {
$site = ResourceSite::ANIME_PLANET();
Log::info("Creating $site->description Resource '$animePlanetLink'");
$resource = ExternalResource::query()->create([
ExternalResource::ATTRIBUTE_LINK => $animePlanetLink,
ExternalResource::ATTRIBUTE_SITE => $site->value,
ExternalResource::ATTRIBUTE_EXTERNAL_ID => $this->getAnimePlanetExternalId($animePlanetLink),
]);
}
return $resource;
}
/**
* Attempt to retrieve Anime Planet ID from webpage.
*
* @param string $animePlanetLink
* @return int|null
*/
protected function getAnimePlanetExternalId(string $animePlanetLink): ?int
{
try {
// Try not to upset Anime Planet
sleep(rand(1, 3));
$response = Http::get($animePlanetLink)
->throw()
->body();
$animePlanetId = Str::match(
'/["\']?ENTRY_INFO["\']? *: *{.*id["\']? *: *["\']?(\d+)["\']? *,/s',
$response
);
if (is_numeric($animePlanetId)) {
return intval($animePlanetId);
}
} catch (Exception $e) {
Log::error($e->getMessage());
}
return null;
}
}