Version 5.1 - All the GraphQL #32
5
.gitignore
vendored
5
.gitignore
vendored
@ -25,4 +25,7 @@ app/config/*.toml
|
||||
phinx.yml
|
||||
.idea/
|
||||
Caddyfile
|
||||
build/humbuglog.txt
|
||||
build/humbuglog.txt
|
||||
public/images/anime/**
|
||||
public/images/manga/**
|
||||
public/images/characters/**
|
@ -147,6 +147,16 @@ return [
|
||||
// ---------------------------------------------------------------------
|
||||
// Default / Shared routes
|
||||
// ---------------------------------------------------------------------
|
||||
'image_proxy' => [
|
||||
'path' => '/public/images/{type}/{file}',
|
||||
'action' => 'images',
|
||||
'controller' => DEFAULT_CONTROLLER,
|
||||
'verb' => 'get',
|
||||
'tokens' => [
|
||||
'type' => '[a-z0-9\-]+',
|
||||
'file' => '[a-z0-9\-]+\.[a-z]{3}'
|
||||
]
|
||||
],
|
||||
'cache_purge' => [
|
||||
'path' => '/cache_purge',
|
||||
'action' => 'clearCache',
|
||||
|
@ -1,7 +1,7 @@
|
||||
<main class="details fixed">
|
||||
<section class="flex flex-no-wrap">
|
||||
<div>
|
||||
<img class="cover" width="402" height="284" src="<?= $data['cover_image'] ?>" alt="" />
|
||||
<img class="cover" width="402" height="284" src="<?= $urlGenerator->assetUrl("images/anime/{$data['id']}.jpg") ?>" alt="" />
|
||||
<br />
|
||||
<br />
|
||||
<table class="media_details">
|
||||
@ -80,7 +80,7 @@
|
||||
<?php if (count($characters) > 0): ?>
|
||||
<h2>Characters</h2>
|
||||
<section class="align_left media-wrap">
|
||||
<?php foreach($characters as $char): ?>
|
||||
<?php foreach($characters as $id => $char): ?>
|
||||
<?php if ( ! empty($char['image']['original'])): ?>
|
||||
<article class="character">
|
||||
<?php $link = $url->generate('character', ['slug' => $char['slug']]) ?>
|
||||
@ -88,7 +88,7 @@
|
||||
<?= $helper->a($link, $char['name']); ?>
|
||||
</div>
|
||||
<a href="<?= $link ?>">
|
||||
<?= $helper->img($char['image']['original'], [
|
||||
<?= $helper->img($urlGenerator->assetUrl("images/characters/{$id}.jpg"), [
|
||||
'width' => '225'
|
||||
]) ?>
|
||||
</a>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<main class="details">
|
||||
<section class="flex flex-no-wrap">
|
||||
<div>
|
||||
<img class="cover" width="284" src="<?= $data[0]['attributes']['image']['original'] ?>" alt="" />
|
||||
<img class="cover" width="284" src="<?= $urlGenerator->assetUrl("images/characters/{$data[0]['id']}.jpg") ?>" alt="" />
|
||||
</div>
|
||||
<div>
|
||||
<h2><?= $data[0]['attributes']['name'] ?></h2>
|
||||
@ -18,14 +18,14 @@
|
||||
<div>
|
||||
<h4>Anime</h4>
|
||||
<section class="align_left media-wrap">
|
||||
<?php foreach($data['included']['anime'] as $anime): ?>
|
||||
<?php foreach($data['included']['anime'] as $id => $anime): ?>
|
||||
<article class="media">
|
||||
<?php
|
||||
$link = $url->generate('anime.details', ['id' => $anime['attributes']['slug']]);
|
||||
$titles = Kitsu::filterTitles($anime['attributes']);
|
||||
?>
|
||||
<a href="<?= $link ?>">
|
||||
<img src="<?= $anime['attributes']['posterImage']['small'] ?>" width="220" alt="" />
|
||||
<img src="<?= $urlGenerator->assetUrl("images/anime/{$id}.jpg") ?>" width="220" alt="" />
|
||||
</a>
|
||||
<div class="name">
|
||||
<a href="<?= $link ?>">
|
||||
@ -45,14 +45,14 @@
|
||||
<h4>Manga</h4>
|
||||
<section class="align_left media-wrap">
|
||||
|
||||
<?php foreach($data['included']['manga'] as $manga): ?>
|
||||
<?php foreach($data['included']['manga'] as $id => $manga): ?>
|
||||
<article class="media">
|
||||
<?php
|
||||
$link = $url->generate('manga.details', ['id' => $manga['attributes']['slug']]);
|
||||
$titles = Kitsu::filterTitles($manga['attributes']);
|
||||
?>
|
||||
<a href="<?= $link ?>">
|
||||
<img src="<?= $manga['attributes']['posterImage']['small'] ?>" width="220" alt="" />
|
||||
<img src="<?= $urlGenerator->assetUrl("images/manga/{$id}.jpg") ?>" width="220" alt="" />
|
||||
</a>
|
||||
<div class="name">
|
||||
<a href="<?= $link ?>">
|
||||
|
@ -11,7 +11,7 @@
|
||||
<section class="media-wrap">
|
||||
<?php foreach($items as $item): ?>
|
||||
<article class="media" id="a-<?= $item['hummingbird_id'] ?>">
|
||||
<img src="https://media.kitsu.io/anime/poster_images/<?= $item['hummingbird_id'] ?>/small.jpg"
|
||||
<img src="<?= $urlGenerator->assetUrl("images/anime/{$item['hummingbird_id']}.jpg") ?>"
|
||||
alt="<?= $item['title'] ?> cover image" />
|
||||
<div class="name">
|
||||
<a href="<?= $url->generate('anime.details', ['id' => $item['slug']]) ?>">
|
||||
|
@ -11,10 +11,11 @@ const css = fs.readFileSync('css/base.css', 'utf8');
|
||||
|
||||
postcss()
|
||||
.use(atImport())
|
||||
.use(cssNext({
|
||||
warnForDuplicates: false
|
||||
}))
|
||||
.use(cssNext())
|
||||
.use(cssNano({
|
||||
autoprefixer: false,
|
||||
colormin: false,
|
||||
minifyFontValues: false,
|
||||
options: {
|
||||
sourcemap: false
|
||||
}
|
||||
|
2
public/css/app.min.css
vendored
2
public/css/app.min.css
vendored
File diff suppressed because one or more lines are too long
@ -1,5 +1,5 @@
|
||||
:root {
|
||||
--default-font-list:system-ui,sans-serif;
|
||||
--default-font-list: system-ui,sans-serif;
|
||||
--monospace-font-list:'Anonymous Pro','Fira Code',Menlo,Monaco,Consolas,'Courier New',monospace;
|
||||
--serif-font-list:Georgia,Times,'Times New Roman',serif;
|
||||
-ms-text-size-adjust:100%;
|
||||
|
0
public/images/characters/.gitkeep
Normal file
0
public/images/characters/.gitkeep
Normal file
@ -829,6 +829,7 @@ class Model {
|
||||
}
|
||||
|
||||
$baseData = $data['data']['attributes'];
|
||||
$baseData['id'] = $data['id'];
|
||||
$baseData['included'] = $data['included'];
|
||||
return $baseData;
|
||||
}
|
||||
@ -864,6 +865,7 @@ class Model {
|
||||
}
|
||||
|
||||
$baseData = $data['data'][0]['attributes'];
|
||||
$baseData['id'] = $data['data'][0]['id'];
|
||||
$baseData['included'] = $data['included'];
|
||||
return $baseData;
|
||||
}
|
||||
|
@ -36,10 +36,11 @@ class AnimeTransformer extends AbstractTransformer {
|
||||
$item['included'] = JsonAPI::organizeIncludes($item['included']);
|
||||
$item['genres'] = array_column($item['included']['genres'], 'name') ?? [];
|
||||
sort($item['genres']);
|
||||
|
||||
|
||||
$titles = Kitsu::filterTitles($item);
|
||||
|
||||
return [
|
||||
'id' => $item['id'],
|
||||
'slug' => $item['slug'],
|
||||
'title' => $titles[0],
|
||||
'titles' => $titles,
|
||||
|
@ -16,10 +16,16 @@
|
||||
|
||||
namespace Aviat\AnimeClient\Controller;
|
||||
|
||||
use function Amp\wait;
|
||||
|
||||
use Amp\Artax\Client;
|
||||
use Aviat\AnimeClient\Controller as BaseController;
|
||||
use Aviat\AnimeClient\API\JsonAPI;
|
||||
use Aviat\Ion\View\HtmlView;
|
||||
|
||||
/**
|
||||
* Controller for handling routes that don't fit elsewhere
|
||||
*/
|
||||
class Index extends BaseController {
|
||||
|
||||
/**
|
||||
@ -113,6 +119,44 @@ class Index extends BaseController {
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get image covers from kitsu
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function images($type, $file)
|
||||
{
|
||||
$kitsuUrl = 'https://media.kitsu.io/';
|
||||
list($id, $ext) = explode('.', basename($file));
|
||||
switch ($type)
|
||||
{
|
||||
case 'anime':
|
||||
$kitsuUrl .= "anime/poster_images/{$id}/small.{$ext}";
|
||||
break;
|
||||
|
||||
case 'manga':
|
||||
$kitsuUrl .= "manga/poster_images/{$id}/small.{$ext}";
|
||||
break;
|
||||
|
||||
case 'characters':
|
||||
$kitsuUrl .= "characters/images/{$id}/original.{$ext}";
|
||||
break;
|
||||
|
||||
default:
|
||||
$this->notFound();
|
||||
return;
|
||||
}
|
||||
|
||||
$promise = (new Client)->request($kitsuUrl);
|
||||
$response = wait($promise);
|
||||
$data = (string) $response->getBody();
|
||||
|
||||
$baseSavePath = $this->config->get('img_cache_path');
|
||||
file_put_contents("{$baseSavePath}/{$type}/{$id}.{$ext}", $data);
|
||||
header('Content-type: ' . $response->getHeader('content-type')[0]);
|
||||
echo (string) $response->getBody();
|
||||
}
|
||||
|
||||
private function organizeFavorites(array $rawfavorites): array
|
||||
{
|
||||
// return $rawfavorites;
|
||||
|
@ -22,29 +22,27 @@ use Aviat\Ion\Friend;
|
||||
use Aviat\Ion\Json;
|
||||
|
||||
class AnimeTransformerTest extends AnimeClientTestCase {
|
||||
|
||||
|
||||
protected $dir;
|
||||
protected $beforeTransform;
|
||||
protected $afterTransform;
|
||||
protected $transformer;
|
||||
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
$this->dir = AnimeClientTestCase::TEST_DATA_DIR . '/Kitsu';
|
||||
|
||||
|
||||
$this->beforeTransform = Json::decodeFile("{$this->dir}/animeBeforeTransform.json");
|
||||
$this->afterTransform = Json::decodeFile("{$this->dir}/animeAfterTransform.json");
|
||||
|
||||
|
||||
$this->transformer = new AnimeTransformer();
|
||||
}
|
||||
|
||||
|
||||
public function testTransform()
|
||||
{
|
||||
$expected = $this->afterTransform;
|
||||
$actual = $this->transformer->transform($this->beforeTransform);
|
||||
// Json::encodeFile("{$this->dir}/animeAfterTransform.json", $actual);
|
||||
|
||||
$this->assertEquals($expected, $actual);
|
||||
|
||||
$this->assertMatchesSnapshot($actual);
|
||||
}
|
||||
}
|
@ -0,0 +1,104 @@
|
||||
<?php return array (
|
||||
'id' => 32344,
|
||||
'slug' => 'attack-on-titan',
|
||||
'title' => 'Attack on Titan',
|
||||
'titles' =>
|
||||
array (
|
||||
0 => 'Attack on Titan',
|
||||
1 => 'Shingeki no Kyojin',
|
||||
2 => '進撃の巨人',
|
||||
),
|
||||
'status' => 'Finished Airing',
|
||||
'cover_image' => 'https://media.kitsu.io/anime/poster_images/7442/small.jpg?1418580054',
|
||||
'show_type' => 'TV',
|
||||
'episode_count' => 25,
|
||||
'episode_length' => 24,
|
||||
'synopsis' => 'Several hundred years ago, humans were nearly exterminated by titans. Titans are typically several stories tall, seem to have no intelligence, devour human beings and, worst of all, seem to do it for the pleasure rather than as a food source. A small percentage of humanity survived by enclosing themselves in a city protected by extremely high walls, even taller than the biggest of titans. Flash forward to the present and the city has not seen a titan in over 100 years. Teenage boy Eren and his foster sister Mikasa witness something horrific as the city walls are destroyed by a colossal titan that appears out of thin air. As the smaller titans flood the city, the two kids watch in horror as their mother is eaten alive. Eren vows that he will murder every single titan and take revenge for all of mankind.
|
||||
|
||||
(Source: ANN)',
|
||||
'age_rating' => 'R',
|
||||
'age_rating_guide' => 'Violence, Profanity',
|
||||
'url' => 'https://kitsu.io/anime/attack-on-titan',
|
||||
'genres' =>
|
||||
array (
|
||||
0 => 'Action',
|
||||
1 => 'Drama',
|
||||
2 => 'Fantasy',
|
||||
3 => 'Super Power',
|
||||
),
|
||||
'streaming_links' =>
|
||||
array (
|
||||
0 =>
|
||||
array (
|
||||
'meta' =>
|
||||
array (
|
||||
'name' => 'Crunchyroll',
|
||||
'link' => true,
|
||||
'image' => 'streaming-logos/crunchyroll.svg',
|
||||
),
|
||||
'link' => 'http://www.crunchyroll.com/attack-on-titan',
|
||||
'subs' =>
|
||||
array (
|
||||
0 => 'en',
|
||||
),
|
||||
'dubs' =>
|
||||
array (
|
||||
0 => 'ja',
|
||||
),
|
||||
),
|
||||
1 =>
|
||||
array (
|
||||
'meta' =>
|
||||
array (
|
||||
'name' => 'Hulu',
|
||||
'link' => true,
|
||||
'image' => 'streaming-logos/hulu.svg',
|
||||
),
|
||||
'link' => 'http://www.hulu.com/attack-on-titan',
|
||||
'subs' =>
|
||||
array (
|
||||
0 => 'en',
|
||||
),
|
||||
'dubs' =>
|
||||
array (
|
||||
0 => 'ja',
|
||||
),
|
||||
),
|
||||
2 =>
|
||||
array (
|
||||
'meta' =>
|
||||
array (
|
||||
'name' => 'Funimation',
|
||||
'link' => true,
|
||||
'image' => 'streaming-logos/funimation.svg',
|
||||
),
|
||||
'link' => 'http://www.funimation.com/shows/attack-on-titan/videos/episodes',
|
||||
'subs' =>
|
||||
array (
|
||||
0 => 'en',
|
||||
),
|
||||
'dubs' =>
|
||||
array (
|
||||
0 => 'ja',
|
||||
),
|
||||
),
|
||||
3 =>
|
||||
array (
|
||||
'meta' =>
|
||||
array (
|
||||
'name' => 'Netflix',
|
||||
'link' => false,
|
||||
'image' => 'streaming-logos/netflix.svg',
|
||||
),
|
||||
'link' => 't',
|
||||
'subs' =>
|
||||
array (
|
||||
0 => 'en',
|
||||
),
|
||||
'dubs' =>
|
||||
array (
|
||||
0 => 'ja',
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
@ -1,4 +1,5 @@
|
||||
{
|
||||
"id": 32344,
|
||||
"slug": "attack-on-titan",
|
||||
"synopsis": "Several hundred years ago, humans were nearly exterminated by titans. Titans are typically several stories tall, seem to have no intelligence, devour human beings and, worst of all, seem to do it for the pleasure rather than as a food source. A small percentage of humanity survived by enclosing themselves in a city protected by extremely high walls, even taller than the biggest of titans. Flash forward to the present and the city has not seen a titan in over 100 years. Teenage boy Eren and his foster sister Mikasa witness something horrific as the city walls are destroyed by a colossal titan that appears out of thin air. As the smaller titans flood the city, the two kids watch in horror as their mother is eaten alive. Eren vows that he will murder every single titan and take revenge for all of mankind.\n\n(Source: ANN)",
|
||||
"coverImageTopOffset": 263,
|
||||
|
Loading…
Reference in New Issue
Block a user