Browse Source

Clean up commands a little bit

pull/23/head
Timothy Warren 4 months ago
parent
commit
73488d8244
3 changed files with 1 additions and 257 deletions
  1. 0
    1
      console
  2. 0
    241
      src/Command/MALIDCheck.php
  3. 1
    15
      src/Command/SyncLists.php

+ 0
- 1
console View File

@@ -23,7 +23,6 @@ try
'refresh:thumbnails' => Command\UpdateThumbnails::class,
'regenerate-thumbnails' => Command\UpdateThumbnails::class,
'lists:sync' => Command\SyncLists::class,
'mal_id:check' => Command\MALIDCheck::class,
]))->run();
}
catch (\Exception $e)

+ 0
- 241
src/Command/MALIDCheck.php View File

@@ -1,241 +0,0 @@
<?php declare(strict_types=1);
/**
* Hummingbird Anime List Client
*
* An API client for Kitsu to manage anime and manga watch lists
*
* PHP version 7.1
*
* @package HummingbirdAnimeClient
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2015 - 2018 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 4.1
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
*/

namespace Aviat\AnimeClient\Command;

use const Aviat\AnimeClient\SRC_DIR;

use function Amp\Promise\wait;

use Aviat\AnimeClient\API\{
APIRequestBuilder,
JsonAPI,
ParallelAPIRequest
};

use Aviat\Ion\Json;


final class MALIDCheck extends BaseCommand {

private $kitsuModel;

/**
* Check MAL mapping validity
*
* @param array $args
* @param array $options
* @throws \Aviat\Ion\Di\Exception\ContainerException
* @throws \Aviat\Ion\Di\Exception\NotFoundException
* @throws \Throwable
*/
public function execute(array $args, array $options = []): void
{
$this->setContainer($this->setupContainer());
$this->setCache($this->container->get('cache'));
$this->kitsuModel = $this->container->get('kitsu-model');

$kitsuAnimeIdList = $this->formatKitsuList('anime');
$animeCount = count($kitsuAnimeIdList);
$this->echoBox("{$animeCount} mappings for Anime");
$animeMappings = $this->checkMALIds($kitsuAnimeIdList, 'anime');
$this->mappingStatus($animeMappings, $animeCount, 'anime');

$kitsuMangaIdList = $this->formatKitsuList('manga');
$mangaCount = count($kitsuMangaIdList);
$this->echoBox("{$mangaCount} mappings for Manga");
$mangaMappings = $this->checkMALIds($kitsuMangaIdList, 'manga');
$this->mappingStatus($mangaMappings, $mangaCount, 'manga');

$publicDir = realpath(SRC_DIR . '/../public') . '/';
file_put_contents($publicDir . 'mal_mappings.json', Json::encode([
'anime' => $animeMappings,
'manga' => $mangaMappings,
]));

$this->echoBox('Mapping file saved to "' . $publicDir . 'mal_mappings.json' . '"');
}

/**
* Format a kitsu list for the sake of comparision
*
* @param string $type
* @return array
*/
private function formatKitsuList(string $type = 'anime'): array
{
$options = [
'include' => 'media,media.mappings',
];
$data = $this->kitsuModel->{'getFullRaw' . ucfirst($type) . 'List'}($options);

if (empty($data))
{
return [];
}

$includes = JsonAPI::organizeIncludes($data['included']);

// Only bother with mappings from MAL that are of the specified media type
$includes['mappings'] = array_filter($includes['mappings'], function ($mapping) use ($type) {
return $mapping['externalSite'] === "myanimelist/{$type}";
});

$output = [];

foreach ($data['data'] as $listItem)
{
$id = $listItem['relationships']['media']['data']['id'];
$mediaItem = $includes[$type][$id];

// Set titles
$listItem['titles'] = $mediaItem['titles'];

$potentialMappings = $mediaItem['relationships']['mappings'];
$malId = NULL;

foreach ($potentialMappings as $mappingId)
{
if (array_key_exists($mappingId, $includes['mappings']))
{
$malId = $includes['mappings'][$mappingId]['externalId'];
}
}

// Skip to the next item if there isn't a MAL ID
if ($malId === NULL)
{
continue;
}

// Group by malIds to simplify lookup of media details
// for checking validity of the malId mappings
$output[$malId] = $listItem;
}

ksort($output);

return $output;
}

/**
* Check for valid Kitsu -> MAL mapping
*
* @param array $kitsuList
* @param string $type
* @return array
* @throws \Throwable
*/
private function checkMALIds(array $kitsuList, string $type): array
{
$goodMappings = [];
$badMappings = [];
$suspectMappings = [];

$responses = $this->makeMALRequests(array_keys($kitsuList), $type);

// If the page returns a 404, put it in the bad mappings list
// otherwise, do a search against the titles, to see if the mapping
// seems valid
foreach($responses as $id => $response)
{
$body = wait($response->getBody());
$titles = $kitsuList[$id]['titles'];

if ($response->getStatus() === 404)
{
$badMappings[$id] = $titles;
}
else
{
$titleMatches = FALSE;

// Attempt to determine if the id matches
// By searching for a matching title
foreach($titles as $title)
{
if (empty($title))
{
continue;
}

if (mb_stripos($body, $title) !== FALSE)
{
$titleMatches = TRUE;
$goodMappings[$id] = $title;

// Continue on outer loop
continue 2;
}
}

if ( ! $titleMatches)
{
$suspectMappings[$id] = $titles;
}
else
{
$goodMappings[$id] = $titles;
}
}
}

return [
'good' => $goodMappings,
'bad' => $badMappings,
'suspect' => $suspectMappings,
];
}

private function makeMALRequests(array $ids, string $type): array
{
$baseUrl = "https://myanimelist.net/{$type}/";

$requestChunks = array_chunk($ids, 50, TRUE);
$responses = [];

// Chunk parallel requests so that we don't hit rate
// limiting, and get spurious 404 HTML responses
foreach($requestChunks as $idChunk)
{
$requester = new ParallelAPIRequest();

foreach($idChunk as $id)
{
$request = APIRequestBuilder::simpleRequest($baseUrl . $id);
$requester->addRequest($request, (string)$id);
}

foreach($requester->getResponses() as $id => $response)
{
$responses[$id] = $response;
}
}

return $responses;
}

private function mappingStatus(array $mapping, int $count, string $type): void
{
$good = count($mapping['good']);
$bad = count($mapping['bad']);
$suspect = count($mapping['suspect']);

$uType = ucfirst($type);

$this->echoBox("{$uType} mappings: {$good}/{$count} Good, {$suspect}/{$count} Suspect, {$bad}/{$count} Broken");
}
}

+ 1
- 15
src/Command/SyncLists.php View File

@@ -308,19 +308,9 @@ final class SyncLists extends BaseCommand {
$anilistUpdateItems = [];
$kitsuUpdateItems = [];

/* $malBlackList = ($type === 'anime')
? [
27821, // Fate/stay night: Unlimited Blade Works - Prologue
29317, // Saekano: How to Raise a Boring Girlfriend Prologue
30514, // Nisekoinogatari
] : [
114638, // Cells at Work: Black
]; */

$malIds = array_keys($anilistList);
$kitsuMalIds = array_map('intval', array_column($kitsuList, 'malId'));
$missingMalIds = array_diff($malIds, $kitsuMalIds);
// $missingMalIds = array_diff($missingMalIds, $malBlackList);

// Add items on Anilist, but not Kitsu to Kitsu
foreach($missingMalIds as $mid)
@@ -335,11 +325,6 @@ final class SyncLists extends BaseCommand {
{
$malId = $kitsuItem['malId'];

/* if (\in_array((int)$malId, $malBlackList, TRUE))
{
continue;
} */

if (array_key_exists($malId, $anilistList))
{
$anilistItem = $anilistList[$malId];
@@ -676,6 +661,7 @@ final class SyncLists extends BaseCommand {
}
catch (MissingIdException $e)
{
// Case where there's a MAL mapping from Kitsu, but no equivalent Anlist item
$id = $item['mal_id'];
$this->echoBox("Skipping Anilist ${type} with mal_id: {$id} due to missing mapping");
}

Loading…
Cancel
Save