mirror of
https://github.com/AnimeThemes/animethemes-server.git
synced 2026-07-11 01:24:46 +02:00
feat(db): seed anime planet resources (#442)
* feat(db): seed anime planet resources * style: fix StyleCI findings
This commit is contained in:
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user