Merge remote-tracking branch 'origin/develop'
timw4mail/HummingBirdAnimeClient/pipeline/head This commit looks good Details

This commit is contained in:
Timothy Warren 2021-10-13 17:05:26 -04:00
commit 629f7f1045
19 changed files with 160 additions and 50 deletions

View File

@ -17,6 +17,13 @@ use function Aviat\AnimeClient\getLocalImg;
<td><?= $data['status'] ?></td> <td><?= $data['status'] ?></td>
</tr> </tr>
<?php if ( ! empty($data['airDate'])): ?>
<tr>
<td>Original Airing</td>
<td><?= $data['airDate'] ?></td>
</tr>
<?php endif ?>
<tr> <tr>
<td>Show Type</td> <td>Show Type</td>
<td><?= (strlen($data['show_type']) > 3) ? ucfirst(strtolower($data['show_type'])) : $data['show_type'] ?></td> <td><?= (strlen($data['show_type']) > 3) ? ucfirst(strtolower($data['show_type'])) : $data['show_type'] ?></td>
@ -122,8 +129,8 @@ use function Aviat\AnimeClient\getLocalImg;
&nbsp;&nbsp;<?= $link['meta']['name'] ?> &nbsp;&nbsp;<?= $link['meta']['name'] ?>
<?php endif ?> <?php endif ?>
</td> </td>
<td><?= implode(', ', $link['subs']) ?></td> <td><?= implode(', ', array_map(fn ($sub) => Locale::getDisplayLanguage($sub, 'en'), $link['subs'])) ?></td>
<td><?= implode(', ', $link['dubs']) ?></td> <td><?= implode(', ', array_map(fn ($dub) => Locale::getDisplayLanguage($dub, 'en'), $link['dubs'])) ?></td>
</tr> </tr>
<?php endforeach ?> <?php endforeach ?>
</tbody> </tbody>

View File

@ -628,6 +628,14 @@ picture.cover {
background-size: contain; background-size: contain;
background-repeat: no-repeat; background-repeat: no-repeat;
} }
/* There are two .name elements, just darken them both in this case! */
.media.search.disabled .name {
background-color: #000;
background-color: rgba(0, 0, 0, 0.75);
background-size: cover;
background-size: contain;
background-repeat: no-repeat;
}
.media.search > .row { .media.search > .row {
z-index: 6; z-index: 6;

View File

@ -1,5 +1,5 @@
import _ from './anime-client.js' import _ from './anime-client.js'
import { renderAnimeSearchResults } from './template-helpers.js' import { renderSearchResults } from './template-helpers.js'
const search = (query) => { const search = (query) => {
// Show the loader // Show the loader
@ -13,7 +13,7 @@ const search = (query) => {
_.hide('.cssload-loader'); _.hide('.cssload-loader');
// Show the results // Show the results
_.$('#series-list')[ 0 ].innerHTML = renderAnimeSearchResults(searchResults); _.$('#series-list')[ 0 ].innerHTML = renderSearchResults('anime', searchResults);
}); });
}; };

View File

@ -1,12 +1,12 @@
import _ from './anime-client.js' import _ from './anime-client.js'
import { renderMangaSearchResults } from './template-helpers.js' import { renderSearchResults } from './template-helpers.js'
const search = (query) => { const search = (query) => {
_.show('.cssload-loader'); _.show('.cssload-loader');
return _.get(_.url('/manga/search'), { query }, (searchResults, status) => { return _.get(_.url('/manga/search'), { query }, (searchResults, status) => {
searchResults = JSON.parse(searchResults); searchResults = JSON.parse(searchResults);
_.hide('.cssload-loader'); _.hide('.cssload-loader');
_.$('#series-list')[ 0 ].innerHTML = renderMangaSearchResults(searchResults); _.$('#series-list')[ 0 ].innerHTML = renderSearchResults('manga', searchResults);
}); });
}; };

View File

@ -7,52 +7,55 @@ _.on('main', 'change', '.big-check', (e) => {
document.getElementById(`mal_${id}`).checked = true; document.getElementById(`mal_${id}`).checked = true;
}); });
export function renderAnimeSearchResults (data) { /**
return data.map(item => { * On search results with an existing library entry, this shows that fact, with an edit link for the existing
const titles = item.titles.join('<br />'); * library entry
*
* @param {'anime'|'manga'} type
* @param {Object} item
* @returns {String}
*/
function renderEditLink (type, item) {
if (item.libraryEntry === null) {
return '';
}
return ` return `
<article class="media search"> <div class="row">
<div class="name"> <span class="edit"><big>[ Already in List ]</big></span>
<input type="radio" class="mal-check" id="mal_${item.slug}" name="mal_id" value="${item.mal_id}" /> </div>
<input type="radio" class="big-check" id="${item.slug}" name="id" value="${item.id}" /> <div class="row">
<label for="${item.slug}"> <span class="edit">
<picture width="220"> <a class="bracketed" href="/${type}/edit/${item.libraryEntry.id}/${item.libraryEntry.status}">Edit</a>
<source srcset="/public/images/anime/${item.id}.webp" type="image/webp" /> </span>
<source srcset="/public/images/anime/${item.id}.jpg" type="image/jpeg" /> </div>
<img src="/public/images/anime/${item.id}.jpg" alt="" width="220" /> <div class="row"><span class="edit">&nbsp;</span></div>
</picture> `
<span class="name">
${item.canonicalTitle}<br />
<small>${titles}</small>
</span>
</label>
</div>
<div class="table">
<div class="row">
<span class="edit">
<a class="bracketed" href="/anime/details/${item.slug}">Info Page</a>
</span>
</div>
</div>
</article>
`;
}).join('');
} }
export function renderMangaSearchResults (data) { /**
* Show the search results for a media item
*
* @param {'anime'|'manga'} type
* @param {Object} data
* @returns {String}
*/
export function renderSearchResults (type, data) {
return data.map(item => { return data.map(item => {
const titles = item.titles.join('<br />'); const titles = item.titles.join('<br />');
const disabled = item.libraryEntry !== null ? 'disabled' : '';
const editLink = renderEditLink(type, item);
return ` return `
<article class="media search"> <article class="media search ${disabled}">
<div class="name"> <div class="name">
<input type="radio" id="mal_${item.slug}" name="mal_id" value="${item.mal_id}" /> <input type="radio" class="mal-check" id="mal_${item.slug}" name="mal_id" value="${item.mal_id}" ${disabled} />
<input type="radio" class="big-check" id="${item.slug}" name="id" value="${item.id}" /> <input type="radio" class="big-check" id="${item.slug}" name="id" value="${item.id}" ${disabled} />
<label for="${item.slug}"> <label for="${item.slug}">
<picture width="220"> <picture width="220">
<source srcset="/public/images/manga/${item.id}.webp" type="image/webp" /> <source srcset="/public/images/${type}/${item.id}.webp" type="image/webp" />
<source srcset="/public/images/manga/${item.id}.jpg" type="image/jpeg" /> <source srcset="/public/images/${type}/${item.id}.jpg" type="image/jpeg" />
<img src="/public/images/manga/${item.id}.jpg" alt="" width="220" /> <img src="/public/images/${type}/${item.id}.jpg" alt="" width="220" />
</picture> </picture>
<span class="name"> <span class="name">
${item.canonicalTitle}<br /> ${item.canonicalTitle}<br />
@ -61,9 +64,10 @@ export function renderMangaSearchResults (data) {
</label> </label>
</div> </div>
<div class="table"> <div class="table">
${editLink}
<div class="row"> <div class="row">
<span class="edit"> <span class="edit">
<a class="bracketed" href="/manga/details/${item.slug}">Info Page</a> <a class="bracketed" href="/${type}/details/${item.slug}">Info Page</a>
</span> </span>
</div> </div>
</div> </div>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -535,6 +535,7 @@ final class Model {
'slug' => $item['slug'], 'slug' => $item['slug'],
'canonicalTitle' => $item['titles']['canonical'], 'canonicalTitle' => $item['titles']['canonical'],
'titles' => array_values(K::getTitles($item['titles'])), 'titles' => array_values(K::getTitles($item['titles'])),
'libraryEntry' => $item['myLibraryEntry'],
]; ];
// Search for MAL mapping // Search for MAL mapping

View File

@ -30,6 +30,12 @@ query ($slug: String!) {
canonical canonical
localized localized
} }
...on Anime {
episodeCount
}
...on Manga {
chapterCount
}
} }
updatedAt updatedAt
} }

View File

@ -14,6 +14,10 @@ query ($query: String!) {
localized localized
alternatives alternatives
} }
myLibraryEntry {
id
status
}
} }
} }
} }

View File

@ -14,6 +14,10 @@ query ($query: String!) {
localized localized
alternatives alternatives
} }
myLibraryEntry {
id
status
}
} }
} }
} }

View File

@ -121,6 +121,7 @@ final class AnimeTransformer extends AbstractTransformer {
} }
return AnimePage::from([ return AnimePage::from([
'airDate' => Kitsu::formatAirDates($base['startDate'], $base['endDate']),
'age_rating' => $base['ageRating'], 'age_rating' => $base['ageRating'],
'age_rating_guide' => $base['ageRatingGuide'], 'age_rating_guide' => $base['ageRatingGuide'],
'characters' => $characters, 'characters' => $characters,

View File

@ -65,6 +65,7 @@ abstract class HistoryTransformer {
foreach ($base as $entry) foreach ($base as $entry)
{ {
// Filter out other media types
if (strtolower($entry['media']['__typename']) !== $this->type) if (strtolower($entry['media']['__typename']) !== $this->type)
{ {
continue; continue;
@ -195,6 +196,19 @@ abstract class HistoryTransformer {
return NULL; return NULL;
} }
// Hide the last episode update (Anime)
foreach (['episodeCount', 'chapterCount'] as $count)
{
if ( ! empty($entry['media'][$count]))
{
$update = $entry['changedData']['progress'][1] ?? 0;
if ($update === $entry['media'][$count])
{
return NULL;
}
}
}
$action = ($this->isReconsuming($entry)) $action = ($this->isReconsuming($entry))
? "{$this->reconsumeAction} {$item}" ? "{$this->reconsumeAction} {$item}"
: "{$this->progressAction} {$item}"; : "{$this->progressAction} {$item}";

View File

@ -68,6 +68,57 @@ final class Kitsu {
return AnimeAiringStatus::NOT_YET_AIRED; return AnimeAiringStatus::NOT_YET_AIRED;
} }
/**
* Reformat the airing date range for an Anime
*
* @param string|null $startDate
* @param string|null $endDate
* @return string
*/
public static function formatAirDates(string $startDate = NULL, string $endDate = NULL): string
{
if (empty($startDate))
{
return '';
}
$monthMap = [
'01' => 'Jan',
'02' => 'Feb',
'03' => 'Mar',
'04' => 'Apr',
'05' => 'May',
'06' => 'Jun',
'07' => 'Jul',
'08' => 'Aug',
'09' => 'Sep',
'10' => 'Oct',
'11' => 'Nov',
'12' => 'Dec',
];
[$startYear, $startMonth, $startDay] = explode('-', $startDate);
if ($startDate === $endDate)
{
return "{$monthMap[$startMonth]} $startDay, $startYear";
}
if (empty($endDate))
{
return "{$monthMap[$startMonth]} {$startYear} - ";
}
[$endYear, $endMonth] = explode('-', $endDate);
if ($startYear === $endYear)
{
return "{$monthMap[$startMonth]} - {$monthMap[$endMonth]} $startYear";
}
return "{$monthMap[$startMonth]} {$startYear} - {$monthMap[$endMonth]} {$endYear}";
}
public static function getPublishingStatus(string $kitsuStatus, string $startDate = NULL, string $endDate = NULL): string public static function getPublishingStatus(string $kitsuStatus, string $startDate = NULL, string $endDate = NULL): string
{ {
$startPubDate = new DateTimeImmutable($startDate ?? 'tomorrow'); $startPubDate = new DateTimeImmutable($startDate ?? 'tomorrow');
@ -263,8 +314,15 @@ final class Kitsu {
if (array_key_exists('localized', $titles) && is_array($titles['localized'])) if (array_key_exists('localized', $titles) && is_array($titles['localized']))
{ {
foreach($titles['localized'] as $alternateTitle) foreach($titles['localized'] as $locale => $alternateTitle)
{ {
// Really don't care about languages that aren't english
// or Japanese for titles
if ( ! in_array($locale, ['en', 'en_us', 'en_jp', 'ja_jp']))
{
continue;
}
if (self::titleIsUnique($alternateTitle, $valid)) if (self::titleIsUnique($alternateTitle, $valid))
{ {
$valid[] = $alternateTitle; $valid[] = $alternateTitle;

View File

@ -25,4 +25,6 @@ final class AnimePage extends Anime {
public array $links = []; public array $links = [];
public array $staff = []; public array $staff = [];
public ?string $airDate = '';
} }

View File

@ -43,6 +43,7 @@ staff:
'Theme Song Lyrics, Inserted Song Performance': [{ id: '17751', name: mpi, image: { original: 'https://media.kitsu.io/people/images/17751/original.jpg?1533270888' }, slug: mpi }] 'Theme Song Lyrics, Inserted Song Performance': [{ id: '17751', name: mpi, image: { original: 'https://media.kitsu.io/people/images/17751/original.jpg?1533270888' }, slug: mpi }]
'Theme Song Lyrics, Theme Song Composition, Theme Song Arrangement': [{ id: '17299', name: Revo, image: { original: 'https://media.kitsu.io/people/images/17299/original.jpg?1533270886' }, slug: revo }] 'Theme Song Lyrics, Theme Song Composition, Theme Song Arrangement': [{ id: '17299', name: Revo, image: { original: 'https://media.kitsu.io/people/images/17299/original.jpg?1533270886' }, slug: revo }]
'Theme Song Performance': [{ id: '18196', name: 'Cinema Staff', image: { original: 'https://media.kitsu.io/people/images/18196/original.jpg?1533273064' }, slug: cinema-staff }, { id: '8718', name: 'Linked Horizon', image: { original: 'https://media.kitsu.io/people/images/8718/original.jpg?1416270072' }, slug: linked-horizon }, { id: '6847', name: 'Yoko Hikasa', image: { original: 'https://media.kitsu.io/people/images/6847/original.jpg?1416268029' }, slug: yoko-hikasa }] 'Theme Song Performance': [{ id: '18196', name: 'Cinema Staff', image: { original: 'https://media.kitsu.io/people/images/18196/original.jpg?1533273064' }, slug: cinema-staff }, { id: '8718', name: 'Linked Horizon', image: { original: 'https://media.kitsu.io/people/images/8718/original.jpg?1416270072' }, slug: linked-horizon }, { id: '6847', name: 'Yoko Hikasa', image: { original: 'https://media.kitsu.io/people/images/6847/original.jpg?1416268029' }, slug: yoko-hikasa }]
airDate: 'Apr - Sep 2013'
age_rating: R age_rating: R
age_rating_guide: 'Violence, Profanity' age_rating_guide: 'Violence, Profanity'
cover_image: 'https://media.kitsu.io/anime/poster_images/7442/small.jpg?1597698856' cover_image: 'https://media.kitsu.io/anime/poster_images/7442/small.jpg?1597698856'