diff --git a/app/views/anime/details.php b/app/views/anime/details.php
index b6fa4150..77fac541 100644
--- a/app/views/anime/details.php
+++ b/app/views/anime/details.php
@@ -50,6 +50,18 @@ use function Aviat\AnimeClient\getLocalImg;
+
+ 0): ?>
+
-
+ = $data['title'] ?>
= $title ?>
diff --git a/app/views/manga/details.php b/app/views/manga/details.php
index 6b21901a..8afe36c4 100644
--- a/app/views/manga/details.php
+++ b/app/views/manga/details.php
@@ -34,6 +34,18 @@
+
+ 0): ?>
+
+ External Links |
+
+ $externalUrl): ?>
+ = $urlName ?>
+
+ |
+
+
+
Genres |
@@ -45,7 +57,7 @@
-
+ = $data['title'] ?>
= $title ?>
diff --git a/app/views/user/details.php b/app/views/user/details.php
index f31d7a79..db0f8a8c 100644
--- a/app/views/user/details.php
+++ b/app/views/user/details.php
@@ -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']
);
?>
|
@@ -59,29 +59,32 @@ use Aviat\AnimeClient\API\Kitsu;
Favorites
= $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"),
);
diff --git a/src/AnimeClient/API/Kitsu.php b/src/AnimeClient/API/Kitsu.php
index 5401baf1..8b21bd90 100644
--- a/src/AnimeClient/API/Kitsu.php
+++ b/src/AnimeClient/API/Kitsu.php
@@ -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
*
diff --git a/src/AnimeClient/API/Kitsu/Model.php b/src/AnimeClient/API/Kitsu/Model.php
index cb339312..ff210c41 100644
--- a/src/AnimeClient/API/Kitsu/Model.php
+++ b/src/AnimeClient/API/Kitsu/Model.php
@@ -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,
]);
}
diff --git a/src/AnimeClient/API/Kitsu/Queries/UserDetails.graphql b/src/AnimeClient/API/Kitsu/Queries/UserDetails.graphql
index bb060bda..dd58d89f 100644
--- a/src/AnimeClient/API/Kitsu/Queries/UserDetails.graphql
+++ b/src/AnimeClient/API/Kitsu/Queries/UserDetails.graphql
@@ -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
diff --git a/src/AnimeClient/API/Kitsu/Transformer/AnimeTransformer.php b/src/AnimeClient/API/Kitsu/Transformer/AnimeTransformer.php
index 40d9dec7..c2f022f7 100644
--- a/src/AnimeClient/API/Kitsu/Transformer/AnimeTransformer.php
+++ b/src/AnimeClient/API/Kitsu/Transformer/AnimeTransformer.php
@@ -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,
diff --git a/src/AnimeClient/API/Kitsu/Transformer/MangaTransformer.php b/src/AnimeClient/API/Kitsu/Transformer/MangaTransformer.php
index 77f2d3b1..d2e82af2 100644
--- a/src/AnimeClient/API/Kitsu/Transformer/MangaTransformer.php
+++ b/src/AnimeClient/API/Kitsu/Transformer/MangaTransformer.php
@@ -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,
diff --git a/src/AnimeClient/API/Kitsu/Transformer/UserTransformer.php b/src/AnimeClient/API/Kitsu/Transformer/UserTransformer.php
index d9df93f3..30fd38b0 100644
--- a/src/AnimeClient/API/Kitsu/Transformer/UserTransformer.php
+++ b/src/AnimeClient/API/Kitsu/Transformer/UserTransformer.php
@@ -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']),
];
}
diff --git a/src/AnimeClient/Types/AnimePage.php b/src/AnimeClient/Types/AnimePage.php
index 9c270a14..1924925d 100644
--- a/src/AnimeClient/Types/AnimePage.php
+++ b/src/AnimeClient/Types/AnimePage.php
@@ -25,6 +25,11 @@ final class AnimePage extends Anime {
*/
public array $characters = [];
+ /**
+ * @var array
+ */
+ public array $links = [];
+
/**
* @var array
*/
diff --git a/src/AnimeClient/Types/MangaPage.php b/src/AnimeClient/Types/MangaPage.php
index 57c49297..f5ccce5c 100644
--- a/src/AnimeClient/Types/MangaPage.php
+++ b/src/AnimeClient/Types/MangaPage.php
@@ -52,6 +52,11 @@ final class MangaPage extends AbstractType {
*/
public array $genres;
+ /**
+ * @var array
+ */
+ public array $links;
+
/**
* @var string
*/