Compare commits

...

9 Commits

Author SHA1 Message Date
Timothy Warren 629f7f1045 Merge remote-tracking branch 'origin/develop'
timw4mail/HummingBirdAnimeClient/pipeline/head This commit looks good Details
2021-10-13 17:05:26 -04:00
Timothy Warren f9eb3e137d Remove redundant updates on finishing a media item
timw4mail/HummingBirdAnimeClient/pipeline/head This commit looks good Details
2021-10-08 22:55:54 -04:00
Timothy Warren 81cffb9f4c Update test snapshot for anime detail page with new info
timw4mail/HummingBirdAnimeClient/pipeline/head This commit looks good Details
2021-10-08 19:33:25 -04:00
Timothy Warren 099c7af0d8 Show full Language names on streaming info for anime detail pages 2021-10-08 19:32:10 -04:00
Timothy Warren cfc6324971 Add airing date range to anime detail pages 2021-10-08 19:31:40 -04:00
Timothy Warren 1cb880f785 Filter out titles not in English or Japanese from media cards
timw4mail/HummingBirdAnimeClient/pipeline/head This commit looks good Details
2021-10-08 18:28:30 -04:00
Timothy Warren 6c5dbe886b Show when a media item is already in the list when searching on the /add pages, resolves #38
timw4mail/HummingBirdAnimeClient/pipeline/head This commit looks good Details
2021-10-08 12:16:59 -04:00
Timothy Warren 52d6cd797a Refactor media search rendering to be less redundant 2021-10-08 12:15:34 -04:00
Timothy Warren 1de4580ee7 Check user library when searching for new media 2021-10-08 12:06:08 -04:00
19 changed files with 160 additions and 50 deletions

View File

@ -17,6 +17,13 @@ use function Aviat\AnimeClient\getLocalImg;
<td><?= $data['status'] ?></td>
</tr>
<?php if ( ! empty($data['airDate'])): ?>
<tr>
<td>Original Airing</td>
<td><?= $data['airDate'] ?></td>
</tr>
<?php endif ?>
<tr>
<td>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'] ?>
<?php endif ?>
</td>
<td><?= implode(', ', $link['subs']) ?></td>
<td><?= implode(', ', $link['dubs']) ?></td>
<td><?= implode(', ', array_map(fn ($sub) => Locale::getDisplayLanguage($sub, 'en'), $link['subs'])) ?></td>
<td><?= implode(', ', array_map(fn ($dub) => Locale::getDisplayLanguage($dub, 'en'), $link['dubs'])) ?></td>
</tr>
<?php endforeach ?>
</tbody>

View File

@ -628,6 +628,14 @@ picture.cover {
background-size: contain;
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 {
z-index: 6;

View File

@ -1,5 +1,5 @@
import _ from './anime-client.js'
import { renderAnimeSearchResults } from './template-helpers.js'
import { renderSearchResults } from './template-helpers.js'
const search = (query) => {
// Show the loader
@ -13,7 +13,7 @@ const search = (query) => {
_.hide('.cssload-loader');
// 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 { renderMangaSearchResults } from './template-helpers.js'
import { renderSearchResults } from './template-helpers.js'
const search = (query) => {
_.show('.cssload-loader');
return _.get(_.url('/manga/search'), { query }, (searchResults, status) => {
searchResults = JSON.parse(searchResults);
_.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;
});
export function renderAnimeSearchResults (data) {
return data.map(item => {
const titles = item.titles.join('<br />');
/**
* 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 `
<article class="media search">
<div class="name">
<input type="radio" class="mal-check" 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/anime/${item.id}.webp" type="image/webp" />
<source srcset="/public/images/anime/${item.id}.jpg" type="image/jpeg" />
<img src="/public/images/anime/${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="/anime/details/${item.slug}">Info Page</a>
</span>
</div>
</div>
</article>
`;
}).join('');
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>
`
}
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 => {
const titles = item.titles.join('<br />');
const disabled = item.libraryEntry !== null ? 'disabled' : '';
const editLink = renderEditLink(type, item);
return `
<article class="media search">
<article class="media search ${disabled}">
<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}" />
<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}" ${disabled} />
<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" />
<source srcset="/public/images/${type}/${item.id}.webp" type="image/webp" />
<source srcset="/public/images/${type}/${item.id}.jpg" type="image/jpeg" />
<img src="/public/images/${type}/${item.id}.jpg" alt="" width="220" />
</picture>
<span class="name">
${item.canonicalTitle}<br />
@ -61,9 +64,10 @@ export function renderMangaSearchResults (data) {
</label>
</div>
<div class="table">
${editLink}
<div class="row">
<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>
</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'],
'canonicalTitle' => $item['titles']['canonical'],
'titles' => array_values(K::getTitles($item['titles'])),
'libraryEntry' => $item['myLibraryEntry'],
];
// Search for MAL mapping

View File

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

View File

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

View File

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

View File

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

View File

@ -65,6 +65,7 @@ abstract class HistoryTransformer {
foreach ($base as $entry)
{
// Filter out other media types
if (strtolower($entry['media']['__typename']) !== $this->type)
{
continue;
@ -195,6 +196,19 @@ abstract class HistoryTransformer {
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))
? "{$this->reconsumeAction} {$item}"
: "{$this->progressAction} {$item}";

View File

@ -68,6 +68,57 @@ final class Kitsu {
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
{
$startPubDate = new DateTimeImmutable($startDate ?? 'tomorrow');
@ -263,8 +314,15 @@ final class Kitsu {
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))
{
$valid[] = $alternateTitle;

View File

@ -25,4 +25,6 @@ final class AnimePage extends Anime {
public array $links = [];
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, 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 }]
airDate: 'Apr - Sep 2013'
age_rating: R
age_rating_guide: 'Violence, Profanity'
cover_image: 'https://media.kitsu.io/anime/poster_images/7442/small.jpg?1597698856'