Merge remote-tracking branch 'origin/develop'

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

@ -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>

@ -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;

@ -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);
}); });
}; };

@ -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);
}); });
}; };

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

@ -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

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

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

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

@ -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,

@ -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}";

@ -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;

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

@ -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'