Update profile page to use GraphQL, see #27
All checks were successful
timw4mail/HummingBirdAnimeClient/pipeline/head This commit looks good
All checks were successful
timw4mail/HummingBirdAnimeClient/pipeline/head This commit looks good
This commit is contained in:
parent
26a1c464a1
commit
ba276cc86e
@ -50,6 +50,18 @@ use function Aviat\AnimeClient\getLocalImg;
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if (count($data['links']) > 0): ?>
|
||||
<tr>
|
||||
<td>External Links</td>
|
||||
<td>
|
||||
<?php foreach ($data['links'] as $urlName => $externalUrl): ?>
|
||||
<a rel='external' href="<?= $externalUrl ?>"><?= $urlName ?></a><br />
|
||||
<?php endforeach ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif ?>
|
||||
|
||||
<tr>
|
||||
<td>Genres</td>
|
||||
<td>
|
||||
@ -58,11 +70,13 @@ use function Aviat\AnimeClient\getLocalImg;
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
<br />
|
||||
|
||||
</aside>
|
||||
<article class="text">
|
||||
<h2 class="toph"><a rel="external" href="<?= $data['url'] ?>"><?= $data['title'] ?></a></h2>
|
||||
<h2 class="toph"><?= $data['title'] ?></h2>
|
||||
<?php foreach ($data['titles_more'] as $title): ?>
|
||||
<h3><?= $title ?></h3>
|
||||
<?php endforeach ?>
|
||||
|
@ -34,6 +34,18 @@
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if (count($data['links']) > 0): ?>
|
||||
<tr>
|
||||
<td>External Links</td>
|
||||
<td>
|
||||
<?php foreach ($data['links'] as $urlName => $externalUrl): ?>
|
||||
<a rel='external' href="<?= $externalUrl ?>"><?= $urlName ?></a><br />
|
||||
<?php endforeach ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif ?>
|
||||
|
||||
<tr>
|
||||
<td>Genres</td>
|
||||
<td>
|
||||
@ -45,7 +57,7 @@
|
||||
<br />
|
||||
</aside>
|
||||
<article class="text">
|
||||
<h2 class="toph"><a rel="external" href="<?= $data['url'] ?>"><?= $data['title'] ?></a></h2>
|
||||
<h2 class="toph"><?= $data['title'] ?></h2>
|
||||
<?php foreach ($data['titles_more'] as $title): ?>
|
||||
<h3><?= $title ?></h3>
|
||||
<?php endforeach ?>
|
||||
|
@ -36,7 +36,7 @@ use Aviat\AnimeClient\API\Kitsu;
|
||||
$character = $data['waifu']['character'];
|
||||
echo $helper->a(
|
||||
$url->generate('character', ['slug' => $character['slug']]),
|
||||
$character['canonicalName']
|
||||
$character['names']['canonical']
|
||||
);
|
||||
?>
|
||||
</td>
|
||||
@ -59,29 +59,32 @@ use Aviat\AnimeClient\API\Kitsu;
|
||||
<h3>Favorites</h3>
|
||||
<?= $component->tabs('user-favorites', $data['favorites'], static function ($items, $type) use ($component, $helper, $url) {
|
||||
$rendered = [];
|
||||
if ($type === 'characters')
|
||||
if ($type === 'character')
|
||||
{
|
||||
uasort($items, fn ($a, $b) => $a['canonicalName'] <=> $b['canonicalName']);
|
||||
uasort($items, fn ($a, $b) => $a['names']['canonical'] <=> $b['names']['canonical']);
|
||||
}
|
||||
else
|
||||
{
|
||||
uasort($items, fn ($a, $b) => Kitsu::filterTitles($a)[0] <=> Kitsu::filterTitles($b)[0]);
|
||||
uasort($items, fn ($a, $b) => $a['titles']['canonical'] <=> $b['titles']['canonical']);
|
||||
}
|
||||
|
||||
foreach ($items as $id => $item)
|
||||
{
|
||||
if ($type === 'characters')
|
||||
if ($type === 'character')
|
||||
{
|
||||
$rendered[] = $component->character(
|
||||
$item['canonicalName'],
|
||||
$url->generate('character', ['slug', $item['slug']]),
|
||||
$item['names']['canonical'],
|
||||
$url->generate('character', ['slug' => $item['slug']]),
|
||||
$helper->picture("images/characters/{$item['id']}.webp")
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
$rendered[] = $component->media(
|
||||
Kitsu::filterTitles($item),
|
||||
array_merge(
|
||||
[$item['titles']['canonical']],
|
||||
Kitsu::getFilteredTitles($item['titles']),
|
||||
),
|
||||
$url->generate("{$type}.details", ['id' => $item['slug']]),
|
||||
$helper->picture("images/{$type}/{$item['id']}.webp"),
|
||||
);
|
||||
|
@ -91,6 +91,48 @@ final class Kitsu {
|
||||
return MangaPublishingStatus::NOT_YET_PUBLISHED;
|
||||
}
|
||||
|
||||
public static function mappingsToUrls(array $mappings, string $kitsuLink = ''): array
|
||||
{
|
||||
$output = [];
|
||||
foreach ($mappings as $mapping)
|
||||
{
|
||||
switch ($mapping['externalSite'])
|
||||
{
|
||||
case 'ANIDB':
|
||||
$output['AniDB'] = "https://anidb.net/anime/{$mapping['externalId']}";
|
||||
break;
|
||||
|
||||
case 'ANILIST_ANIME':
|
||||
$output['Anilist'] = "https://anilist.co/anime/{$mapping['externalId']}/";
|
||||
break;
|
||||
|
||||
case 'ANILIST_MANGA':
|
||||
$output['Anilist'] = "https://anilist.co/manga/{$mapping['externalId']}/";
|
||||
break;
|
||||
|
||||
case 'MYANIMELIST_ANIME':
|
||||
$output['MyAnimeList'] = "https://myanimelist.net/anime/{$mapping['externalId']}";
|
||||
break;
|
||||
|
||||
case 'MYANIMELIST_MANGA':
|
||||
$output['MyAnimeList'] = "https://myanimelist.net/manga/{$mapping['externalId']}";
|
||||
break;
|
||||
|
||||
default:
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
|
||||
if ($kitsuLink !== '')
|
||||
{
|
||||
$output['Kitsu'] = $kitsuLink;
|
||||
}
|
||||
|
||||
ksort($output);
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reorganize streaming links
|
||||
*
|
||||
|
@ -231,18 +231,8 @@ final class Model {
|
||||
*/
|
||||
public function getUserData(string $username): array
|
||||
{
|
||||
return $this->requestBuilder->getRequest('users', [
|
||||
'query' => [
|
||||
'filter' => [
|
||||
'name' => $username,
|
||||
],
|
||||
'fields' => [
|
||||
'anime' => 'slug,canonicalTitle,posterImage',
|
||||
'manga' => 'slug,canonicalTitle,posterImage',
|
||||
'characters' => 'slug,canonicalName,image',
|
||||
],
|
||||
'include' => 'waifu,favorites.item,stats'
|
||||
]
|
||||
return $this->requestBuilder->runQuery('UserDetails', [
|
||||
'slug' => $username,
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,7 @@ query ($slug: String!) {
|
||||
}
|
||||
birthday
|
||||
id
|
||||
location
|
||||
name
|
||||
proMessage
|
||||
proTier
|
||||
@ -29,6 +30,89 @@ query ($slug: String!) {
|
||||
url
|
||||
}
|
||||
}
|
||||
favorites {
|
||||
nodes {
|
||||
id
|
||||
item {
|
||||
__typename,
|
||||
...on Anime {
|
||||
id
|
||||
slug
|
||||
posterImage {
|
||||
original {
|
||||
url
|
||||
height
|
||||
width
|
||||
}
|
||||
views {
|
||||
url
|
||||
height
|
||||
width
|
||||
}
|
||||
}
|
||||
titles {
|
||||
canonical
|
||||
localized
|
||||
}
|
||||
}
|
||||
...on Manga {
|
||||
id
|
||||
slug
|
||||
posterImage {
|
||||
original {
|
||||
url
|
||||
height
|
||||
width
|
||||
}
|
||||
views {
|
||||
url
|
||||
height
|
||||
width
|
||||
}
|
||||
}
|
||||
titles {
|
||||
canonical
|
||||
localized
|
||||
}
|
||||
}
|
||||
...on Person {
|
||||
id
|
||||
slug
|
||||
image {
|
||||
original {
|
||||
url
|
||||
}
|
||||
views {
|
||||
url
|
||||
height
|
||||
width
|
||||
}
|
||||
}
|
||||
names {
|
||||
alternatives
|
||||
canonical
|
||||
canonicalLocale
|
||||
localized
|
||||
},
|
||||
}
|
||||
...on Character {
|
||||
id
|
||||
slug
|
||||
image {
|
||||
original {
|
||||
url
|
||||
}
|
||||
}
|
||||
names {
|
||||
alternatives
|
||||
canonical
|
||||
canonicalLocale
|
||||
localized
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stats {
|
||||
animeAmountConsumed {
|
||||
completed
|
||||
|
@ -38,6 +38,7 @@ final class AnimeTransformer extends AbstractTransformer {
|
||||
? $item['data']['findAnimeBySlug']
|
||||
: $item['data']['findAnimeById'];
|
||||
$characters = [];
|
||||
$links = [];
|
||||
$staff = [];
|
||||
$genres = array_map(fn ($genre) => $genre['title']['en'], $base['categories']['nodes']);
|
||||
|
||||
@ -108,6 +109,11 @@ final class AnimeTransformer extends AbstractTransformer {
|
||||
ksort($staff);
|
||||
}
|
||||
|
||||
if (count($base['mappings']['nodes']) > 0)
|
||||
{
|
||||
$links = Kitsu::mappingsToUrls($base['mappings']['nodes'], "https://kitsu.io/anime/{$base['slug']}");
|
||||
}
|
||||
|
||||
return AnimePage::from([
|
||||
'age_rating' => $base['ageRating'],
|
||||
'age_rating_guide' => $base['ageRatingGuide'],
|
||||
@ -116,12 +122,13 @@ final class AnimeTransformer extends AbstractTransformer {
|
||||
'episode_count' => $base['episodeCount'],
|
||||
'episode_length' => $base['episodeLength'],
|
||||
'genres' => $genres,
|
||||
'links' => $links,
|
||||
'id' => $base['id'],
|
||||
'slug' => $base['slug'],
|
||||
'staff' => $staff,
|
||||
'show_type' => $base['subtype'],
|
||||
'status' => Kitsu::getAiringStatus($base['startDate'], $base['endDate']),
|
||||
'streaming_links' => Kitsu::parseStreamingLinks($base['streamingLinks']['nodes']),
|
||||
'streaming_links' => Kitsu::parseStreamingLinks($base['streamingLinks']['nodes'] ?? []),
|
||||
'synopsis' => $base['description']['en'],
|
||||
'title' => $title,
|
||||
'titles' => $titles,
|
||||
|
@ -39,6 +39,7 @@ final class MangaTransformer extends AbstractTransformer {
|
||||
: $item['data']['findMangaById'];
|
||||
|
||||
$characters = [];
|
||||
$links = [];
|
||||
$staff = [];
|
||||
$genres = array_map(fn ($genre) => $genre['title']['en'], $base['categories']['nodes']);
|
||||
sort($genres);
|
||||
@ -108,6 +109,11 @@ final class MangaTransformer extends AbstractTransformer {
|
||||
ksort($staff);
|
||||
}
|
||||
|
||||
if (count($base['mappings']['nodes']) > 0)
|
||||
{
|
||||
$links = Kitsu::mappingsToUrls($base['mappings']['nodes'], "https://kitsu.io/manga/{$base['slug']}");
|
||||
}
|
||||
|
||||
$data = [
|
||||
'age_rating' => $base['ageRating'],
|
||||
'age_rating_guide' => $base['ageRatingGuide'],
|
||||
@ -116,6 +122,7 @@ final class MangaTransformer extends AbstractTransformer {
|
||||
'volume_count' => $base['volumeCount'],
|
||||
'cover_image' => $base['posterImage']['views'][1]['url'],
|
||||
'genres' => $genres,
|
||||
'links' => $links,
|
||||
'manga_type' => $base['subtype'],
|
||||
'id' => $base['id'],
|
||||
'staff' => $staff,
|
||||
|
@ -16,9 +16,9 @@
|
||||
|
||||
namespace Aviat\AnimeClient\API\Kitsu\Transformer;
|
||||
|
||||
use Aviat\AnimeClient\API\Kitsu;
|
||||
use function Aviat\AnimeClient\getLocalImg;
|
||||
|
||||
use Aviat\AnimeClient\API\JsonAPI;
|
||||
use Aviat\AnimeClient\Types\User;
|
||||
use Aviat\Ion\Transformer\AbstractTransformer;
|
||||
|
||||
@ -31,36 +31,24 @@ use Aviat\Ion\Transformer\AbstractTransformer;
|
||||
final class UserTransformer extends AbstractTransformer {
|
||||
public function transform($profileData): User
|
||||
{
|
||||
$orgData = JsonAPI::organizeData($profileData)[0];
|
||||
$attributes = $orgData['attributes'];
|
||||
|
||||
$rels = $orgData['relationships'] ?? [];
|
||||
$favorites = array_key_exists('favorites', $rels) ? $rels['favorites'] : [];
|
||||
|
||||
$stats = [];
|
||||
foreach ($rels['stats'] as $sid => &$item)
|
||||
{
|
||||
$key = $item['attributes']['kind'];
|
||||
$stats[$key] = $item['attributes']['statsData'];
|
||||
unset($item);
|
||||
}
|
||||
unset($item);
|
||||
|
||||
$waifu = (array_key_exists('waifu', $rels)) ? [
|
||||
'label' => $attributes['waifuOrHusbando'],
|
||||
'character' => $rels['waifu']['attributes'],
|
||||
$base = $profileData['data']['findProfileBySlug'] ?? [];
|
||||
$favorites = $base['favorites']['nodes'] ?? [];
|
||||
$stats = $base['stats'] ?? [];
|
||||
$waifu = (array_key_exists('waifu', $base)) ? [
|
||||
'label' => $base['waifuOrHusbando'],
|
||||
'character' => $base['waifu'],
|
||||
] : [];
|
||||
|
||||
return User::from([
|
||||
'about' => $attributes['about'],
|
||||
'avatar' => getLocalImg($attributes['avatar']['original'], FALSE),
|
||||
'about' => $base['about'],
|
||||
'avatar' => getLocalImg($base['avatarImage']['original']['url'], FALSE),
|
||||
'favorites' => $this->organizeFavorites($favorites),
|
||||
'location' => $attributes['location'],
|
||||
'name' => $attributes['name'],
|
||||
'slug' => $attributes['slug'],
|
||||
'stats' => $this->organizeStats($stats, $attributes),
|
||||
'location' => $base['location'],
|
||||
'name' => $base['name'],
|
||||
'slug' => $base['slug'],
|
||||
'stats' => $this->organizeStats($stats),
|
||||
'waifu' => $waifu,
|
||||
'website' => $attributes['website'],
|
||||
'website' => $base['siteLinks']['nodes'][0]['url'],
|
||||
]);
|
||||
}
|
||||
|
||||
@ -74,58 +62,10 @@ final class UserTransformer extends AbstractTransformer {
|
||||
{
|
||||
$output = [];
|
||||
|
||||
unset($rawFavorites['data']);
|
||||
|
||||
foreach ($rawFavorites as $item)
|
||||
{
|
||||
$rank = $item['attributes']['favRank'];
|
||||
foreach ($item['relationships']['item'] as $key => $fav)
|
||||
{
|
||||
$output[$key] = $output[$key] ?? [];
|
||||
foreach ($fav as $id => $data)
|
||||
{
|
||||
$output[$key][$rank] = array_merge(['id' => $id], $data['attributes']);
|
||||
}
|
||||
|
||||
ksort($output[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the time spent on anime in a more readable format
|
||||
*
|
||||
* @param int $seconds
|
||||
* @return string
|
||||
*/
|
||||
private function formatAnimeTime(int $seconds): string
|
||||
{
|
||||
// All the seconds left
|
||||
$remSeconds = $seconds % 60;
|
||||
$minutes = ($seconds - $remSeconds) / 60;
|
||||
|
||||
$minutesPerDay = 1440;
|
||||
$minutesPerYear = $minutesPerDay * 365;
|
||||
|
||||
// Minutes short of a year
|
||||
$years = (int)floor($minutes / $minutesPerYear);
|
||||
$minutes %= $minutesPerYear;
|
||||
|
||||
// Minutes short of a day
|
||||
$extraMinutes = $minutes % $minutesPerDay;
|
||||
$days = ($minutes - $extraMinutes) / $minutesPerDay;
|
||||
|
||||
// Minutes short of an hour
|
||||
$remMinutes = $extraMinutes % 60;
|
||||
$hours = ($extraMinutes - $remMinutes) / 60;
|
||||
|
||||
$output = "{$days} days, {$hours} hours, {$remMinutes} minutes, and {$remSeconds} seconds.";
|
||||
|
||||
if ($years > 0)
|
||||
{
|
||||
$output = "{$years} year(s),{$output}";
|
||||
$type = strtolower($item['item']['__typename']);
|
||||
$output[$type][$item['id']] = $item['item'];
|
||||
}
|
||||
|
||||
return $output;
|
||||
@ -137,20 +77,20 @@ final class UserTransformer extends AbstractTransformer {
|
||||
$mangaStats = [];
|
||||
$otherStats = [];
|
||||
|
||||
if (array_key_exists('anime-amount-consumed', $stats))
|
||||
if (array_key_exists('animeAmountConsumed', $stats))
|
||||
{
|
||||
$animeStats = [
|
||||
'Time spent watching anime:' => $this->formatAnimeTime($stats['anime-amount-consumed']['time']),
|
||||
'Anime series watched:' => number_format($stats['anime-amount-consumed']['media']),
|
||||
'Anime episodes watched:' => number_format($stats['anime-amount-consumed']['units']),
|
||||
'Time spent watching anime:' => Kitsu::friendlyTime($stats['animeAmountConsumed']['time']),
|
||||
'Anime series watched:' => number_format($stats['animeAmountConsumed']['media']),
|
||||
'Anime episodes watched:' => number_format($stats['animeAmountConsumed']['units']),
|
||||
];
|
||||
}
|
||||
|
||||
if (array_key_exists('manga-amount-consumed', $stats))
|
||||
if (array_key_exists('mangaAmountConsumed', $stats))
|
||||
{
|
||||
$mangaStats = [
|
||||
'Manga series read:' => number_format($stats['manga-amount-consumed']['media']),
|
||||
'Manga chapters read:' => number_format($stats['manga-amount-consumed']['units']),
|
||||
'Manga series read:' => number_format($stats['mangaAmountConsumed']['media']),
|
||||
'Manga chapters read:' => number_format($stats['mangaAmountConsumed']['units']),
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,11 @@ final class AnimePage extends Anime {
|
||||
*/
|
||||
public array $characters = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public array $links = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
|
@ -52,6 +52,11 @@ final class MangaPage extends AbstractType {
|
||||
*/
|
||||
public array $genres;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public array $links;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user