Authentication, show edit forms for Anime

This commit is contained in:
Timothy Warren 2017-01-05 13:41:32 -05:00
parent 239b0c055c
commit 09338e9132
29 changed files with 1074 additions and 965 deletions

View File

@ -121,9 +121,9 @@ return function(array $config_array = []) {
}); });
// Miscellaneous Classes // Miscellaneous Classes
/* $container->set('auth', function($container) { $container->set('auth', function($container) {
return new HummingbirdAuth($container); return new KitsuAuth($container);
}); */ });
$container->set('url-generator', function($container) { $container->set('url-generator', function($container) {
return new UrlGenerator($container); return new UrlGenerator($container);
}); });

View File

@ -33,7 +33,6 @@ return [
), ),
*/ */
'base' => [ 'base' => [
'marx.css',
'base.css' 'base.css'
] ]
]; ];

View File

@ -1,21 +1,20 @@
<main> <main>
<?php /*if ($auth->is_authenticated()): ?> <?php if ($auth->is_authenticated()): ?>
<a class="bracketed" href="<?= $url->generate('anime.add.get') ?>">Add Item</a> <a class="bracketed" href="<?= $url->generate('anime.add.get') ?>">Add Item</a>
<?php endif */ ?> <?php endif ?>
<?php if (empty($sections)): ?> <?php if (empty($sections)): ?>
<h3>There's nothing here!</h3> <h3>There's nothing here!</h3>
<?php else: ?> <?php else: ?>
<?php foreach ($sections as $name => $items): ?> <?php foreach ($sections as $name => $items): ?>
<?php /*<pre><?= print_r($items, TRUE) ?></pre> */ ?>
<section class="status"> <section class="status">
<h2><?= $escape->html($name) ?></h2> <h2><?= $escape->html($name) ?></h2>
<section class="media-wrap"> <section class="media-wrap">
<?php foreach($items as $item): ?> <?php foreach($items as $item): ?>
<?php if ($item['private']/* && ! $auth->is_authenticated()*/) continue; ?> <?php if ($item['private'] && ! $auth->is_authenticated()) continue; ?>
<article class="media" id="<?= $item['anime']['slug'] ?>"> <article class="media" id="<?= $item['anime']['slug'] ?>">
<?php /* if ($auth->is_authenticated()): ?> <?php if ($auth->is_authenticated()): ?>
<button title="Increment episode count" class="plus_one" hidden>+1 Episode</button> <button title="Increment episode count" class="plus_one" hidden>+1 Episode</button>
<?php endif */ ?> <?php endif ?>
<?= $helper->img($item['anime']['image']); ?> <?= $helper->img($item['anime']['image']); ?>
<div class="name"> <div class="name">
<a href="<?= $url->generate('anime.details', ['id' => $item['anime']['slug']]); ?>"> <a href="<?= $url->generate('anime.details', ['id' => $item['anime']['slug']]); ?>">
@ -24,13 +23,13 @@
</a> </a>
</div> </div>
<div class="table"> <div class="table">
<?php /* if ($auth->is_authenticated()): ?> <?php if ($auth->is_authenticated()): ?>
<div class="row"> <div class="row">
<span class="edit"> <span class="edit">
<a class="bracketed" title="Edit information about this anime" href="<?= $urlGenerator->url("anime/edit/{$item['id']}/{$item['watching_status']}") ?>">Edit</a> <a class="bracketed" title="Edit information about this anime" href="<?= $urlGenerator->url("anime/edit/{$item['id']}/{$item['watching_status']}") ?>">Edit</a>
</span> </span>
</div> </div>
<?php endif */ ?> <?php endif ?>
<?php if ($item['private'] || $item['rewatching']): ?> <?php if ($item['private'] || $item['rewatching']): ?>
<div class="row"> <div class="row">
<?php foreach(['private', 'rewatching'] as $attr): ?> <?php foreach(['private', 'rewatching'] as $attr): ?>
@ -65,6 +64,6 @@
<?php endforeach ?> <?php endforeach ?>
<?php endif ?> <?php endif ?>
</main> </main>
<?php /* if ($auth->is_authenticated()): ?> <?php if ($auth->is_authenticated()): ?>
<script src="<?= $urlGenerator->asset_url('js.php/g/edit') ?>"></script> <script src="<?= $urlGenerator->asset_url('js.php/g/edit') ?>"></script>
<?php endif */ ?> <?php endif ?>

View File

@ -1,7 +1,7 @@
<main> <main>
<?php /*if ($auth->is_authenticated()): ?> <?php if ($auth->is_authenticated()): ?>
<a class="bracketed" href="<?= $url->generate('anime.add.get') ?>">Add Item</a> <a class="bracketed" href="<?= $url->generate('anime.add.get') ?>">Add Item</a>
<?php endif */ ?> <?php endif ?>
<?php if (empty($sections)): ?> <?php if (empty($sections)): ?>
<h3>There's nothing here!</h3> <h3>There's nothing here!</h3>
<?php else: ?> <?php else: ?>
@ -10,9 +10,9 @@
<table> <table>
<thead> <thead>
<tr> <tr>
<?php /* if($auth->is_authenticated()): ?> <?php if($auth->is_authenticated()): ?>
<td class="no_border">&nbsp;</td> <td class="no_border">&nbsp;</td>
<?php endif */ ?> <?php endif ?>
<th>Title</th> <th>Title</th>
<th>Airing Status</th> <th>Airing Status</th>
<th>Score</th> <th>Score</th>
@ -26,13 +26,13 @@
</thead> </thead>
<tbody> <tbody>
<?php foreach($items as $item): ?> <?php foreach($items as $item): ?>
<?php if ($item['private']) continue;// && ! $auth->is_authenticated()) continue; ?> <?php if ($item['private']) && ! $auth->is_authenticated()) continue; ?>
<tr id="a-<?= $item['id'] ?>"> <tr id="a-<?= $item['id'] ?>">
<?php /*if ($auth->is_authenticated()): ?> <?php if ($auth->is_authenticated()): ?>
<td> <td>
<a class="bracketed" href="<?= $urlGenerator->url("/anime/edit/{$item['id']}/{$item['watching_status']}") ?>">Edit</a> <a class="bracketed" href="<?= $urlGenerator->url("/anime/edit/{$item['id']}/{$item['watching_status']}") ?>">Edit</a>
</td> </td>
<?php endif*/ ?> <?php endif ?>
<td class="justify"> <td class="justify">
<a href="<?= $url->generate('anime.details', ['id' => $item['anime']['slug']]) ?>"> <a href="<?= $url->generate('anime.details', ['id' => $item['anime']['slug']]) ?>">
<?= $item['anime']['title'] ?> <?= $item['anime']['title'] ?>
@ -73,5 +73,5 @@
<?php endforeach ?> <?php endforeach ?>
<?php endif ?> <?php endif ?>
</main> </main>
<?php $group = /*($auth->is_authenticated()) ? 'table_edit' :*/ 'table' ?> <?php $group = ($auth->is_authenticated()) ? 'table_edit' : 'table' ?>
<script src="<?= $urlGenerator->asset_url("js.php/g/{$group}") ?>"></script> <script src="<?= $urlGenerator->asset_url("js.php/g/{$group}") ?>"></script>

View File

@ -6,7 +6,7 @@
<meta http-equiv="cache-control" content="no-store" /> <meta http-equiv="cache-control" content="no-store" />
<meta http-equiv="Content-Security-Policy" content="script-src 'self'" /> <meta http-equiv="Content-Security-Policy" content="script-src 'self'" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1, user-scalable=0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1, user-scalable=0" />
<link rel="stylesheet" href="<?= $urlGenerator->asset_url('css.php/g/base/debug') ?>" /> <link rel="stylesheet" href="<?= $urlGenerator->asset_url('css.php/g/base') ?>" />
<script src="<?= $urlGenerator->asset_url('js.php/g/base') ?>"></script> <script src="<?= $urlGenerator->asset_url('js.php/g/base') ?>"></script>
</head> </head>
<body class="<?= $escape->attr($url_type) ?> list"> <body class="<?= $escape->attr($url_type) ?> list">

View File

@ -17,7 +17,7 @@
[<a href="<?= $urlGenerator->default_url('manga') ?>">Manga List</a>] [<a href="<?= $urlGenerator->default_url('manga') ?>">Manga List</a>]
<?php endif ?> <?php endif ?>
</span> </span>
<?php /* if ($auth->is_authenticated()): ?> <?php if ($auth->is_authenticated()): ?>
<span class="flex-no-wrap">&nbsp;</span> <span class="flex-no-wrap">&nbsp;</span>
<span class="flex-no-wrap small-font"> <span class="flex-no-wrap small-font">
<button type="button" class="js-clear-cache user-btn">Clear API Cache</button> <button type="button" class="js-clear-cache user-btn">Clear API Cache</button>
@ -29,7 +29,7 @@
<a class="bracketed" href="<?= $url->generate('logout') ?>">Logout</a> <a class="bracketed" href="<?= $url->generate('logout') ?>">Logout</a>
<?php else: ?> <?php else: ?>
[<a href="<?= $url->generate('login'); ?>"><?= $config->get('whose_list') ?>'s Login</a>] [<a href="<?= $url->generate('login'); ?>"><?= $config->get('whose_list') ?>'s Login</a>]
<?php endif */ ?> <?php endif ?>
</span> </span>
</h1> </h1>
<nav> <nav>

View File

@ -1,3 +1,677 @@
:root
{
-ms-text-size-adjust:100%;
-webkit-text-size-adjust:100%;
box-sizing:border-box;
cursor:default;
font-family:'Open Sans', 'Nimbus Sans L', 'Helvetica Neue', Helvetica, 'Lucida Grande', sans-serif;
line-height:1.4;
overflow-y:scroll;
text-size-adjust:100%;
scroll-behavior: smooth;
}
audio:not([controls])
{
display:none;
}
details
{
display:block;
}
input[type=search]
{
-webkit-appearance:textfield;
}
input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration
{
-webkit-appearance:none;
}
main
{
display:block;
margin:0 auto;
padding:0 1.6em 1.6em;
padding:0 16px 16px;
padding:0 1.6rem 1.6rem;
}
summary
{
display:block;
}
pre
{
background:#efefef;
color:#444;
display:block;
font-family:Menlo, Monaco, Consolas, 'Courier New', monospace;
font-size:1.4em;
font-size:14px;
font-size:1.4rem;
margin:1.6em 0;
margin:16px 0;
margin:1.6rem 0;
overflow:auto;
padding:1.6em;
padding:16px;
padding:1.6rem;
word-break:break-all;
word-wrap:break-word;
}
progress
{
display:inline-block;
}
small
{
color:#777;
font-size:75%;
}
big
{
font-size:125%;
}
template
{
display:none;
}
textarea
{
border:1px solid #ccc;
border:.1rem solid #ccc;
border-radius:0;
display:block;
margin-bottom:8px;
margin-bottom:.8rem;
overflow:auto;
padding:8px;
padding:.8rem;
resize:vertical;
vertical-align:middle;
}
[hidden]
{
display:none;
}
[unselectable]
{
-moz-user-select:none;
-ms-user-select:none;
-webkit-user-select:none;
user-select:none;
}
*,::before,::after
{
border-style:solid;
border-width:0;
box-sizing:inherit;
}
*
{
font-size:inherit;
line-height:inherit;
margin:0;
padding:0;
}
::before,::after
{
text-decoration:inherit;
vertical-align:inherit;
}
a
{
-webkit-transition:.25s ease;
color:#1271db;
text-decoration:none;
transition:.25s ease;
}
audio,canvas,iframe,img,svg,video
{
vertical-align:middle;
}
button,input,select,textarea
{
border:1px solid #ccc;
border:.1rem solid #ccc;
color:inherit;
font-family:inherit;
font-style:inherit;
font-weight:inherit;
min-height:1.4em;
}
code,kbd,pre,samp
{
font-family:Menlo, Monaco, Consolas, 'Courier New', monospace, monospace;
}
table
{
border-collapse:collapse;
border-spacing:0;
margin-bottom:16px;
margin-bottom:1.6rem;
}
::-moz-selection
{
background-color:#b3d4fc;
text-shadow:none;
}
::selection
{
background-color:#b3d4fc;
text-shadow:none;
}
button::-moz-focus-inner
{
border:0;
}
body
{
color:#444;
font-family:'Open Sans', 'Nimbus Sans L', 'Helvetica Neue', Helvetica, 'Lucida Grande', sans-serif;
font-size:16px;
font-size:1.6rem;
font-style:normal;
font-weight:400;
padding:0;
}
p
{
margin:0 0 16px;
margin:0 0 1.6rem;
}
h1,h2,h3,h4,h5,h6
{
font-family:Lato, 'Open Sans', 'Nimbus Sans L', 'Helvetica Neue', Helvetica, 'Lucida Grande', sans-serif;
margin:2em 0 1.6em;
margin:20px 0 16px;
margin:2rem 0 1.6rem;
}
h1
{
border-bottom:1px solid rgba(0, 0, 0, .2);
border-bottom:.1rem solid rgba(0, 0, 0, .2);
font-size:3.6em;
font-size:36px;
font-size:3.6rem;
font-style:normal;
font-weight:500;
}
h2
{
font-size:3em;
font-size:30px;
font-size:3rem;
font-style:normal;
font-weight:500;
}
h3
{
font-size:2.4em;
font-size:24px;
font-size:2.4rem;
font-style:normal;
font-weight:500;
margin:16px 0 4px;
margin:1.6rem 0 .4rem;
}
h4
{
font-size:1.8em;
font-size:18px;
font-size:1.8rem;
font-style:normal;
font-weight:600;
margin:16px 0 4px;
margin:1.6rem 0 .4rem;
}
h5
{
font-size:1.6em;
font-size:16px;
font-size:1.6rem;
font-style:normal;
font-weight:600;
margin:16px 0 4px;
margin:1.6rem 0 .4rem;
}
h6
{
color:#777;
font-size:1.4em;
font-size:14px;
font-size:1.4rem;
font-style:normal;
font-weight:600;
margin:16px 0 4px;
margin:1.6rem 0 .4rem;
}
code
{
background:#efefef;
color:#444;
font-family:Menlo, Monaco, Consolas, 'Courier New', monospace;
font-size:14px;
font-size:1.4rem;
word-break:break-all;
word-wrap:break-word;
}
a:hover,a:focus
{
text-decoration:none;
}
dl
{
margin-bottom:16px;
margin-bottom:1.6rem;
}
dd
{
margin-left:40px;
margin-left:4rem;
}
ul,ol
{
margin-bottom:8px;
margin-bottom:.8rem;
padding-left:20px;
padding-left:2rem;
}
blockquote
{
border-left:2px solid #1271db;
border-left:.2rem solid #1271db;
font-family:Georgia, Times, 'Times New Roman', serif;
font-style:italic;
margin:16px 0;
margin:1.6rem 0;
padding-left:16px;
padding-left:1.6rem;
}
figcaption
{
font-family:Georgia, Times, 'Times New Roman', serif;
}
html
{
font-size:62.5%;
}
main,header,footer,article,section,aside,details,summary
{
display:block;
height:auto;
margin:0 auto;
width:100%;
}
footer
{
border-top:1px solid rgba(0, 0, 0, .2);
border-top:.1rem solid rgba(0, 0, 0, .2);
clear:both;
display:inline-block;
float:left;
max-width:100%;
padding:10px 0;
padding:1rem 0;
text-align:center;
}
hr
{
border-top:1px solid rgba(0, 0, 0, .2);
border-top:.1rem solid rgba(0, 0, 0, .2);
display:block;
margin-bottom:16px;
margin-bottom:1.6rem;
width:100%;
}
img
{
height:auto;
max-width:100%;
vertical-align:baseline;
}
input[type=text],input[type=password],input[type=email],input[type=url],input[type=date],input[type=month],input[type=time],input[type=datetime],input[type=datetime-local],input[type=week],input[type=number],input[type=search],input[type=tel],input[type=color],select
{
border:1px solid #ccc;
border:.1rem solid #ccc;
border-radius:0;
display:inline-block;
padding:8px;
padding:.8rem;
vertical-align:middle;
}
input:not([type])
{
-webkit-appearance:none;
background-clip:padding-box;
background-color:#fff;
border:1px solid #ccc;
border:.1rem solid #ccc;
border-radius:0;
color:#444;
display:inline-block;
padding:8px;
padding:.8rem;
text-align:left;
}
input[type=color]
{
padding:8px 16px;
padding:.8rem 1.6rem;
}
input[type=text]:focus,input[type=password]:focus,input[type=email]:focus,input[type=url]:focus,input[type=date]:focus,input[type=month]:focus,input[type=time]:focus,input[type=datetime]:focus,input[type=datetime-local]:focus,input[type=week]:focus,input[type=number]:focus,input[type=search]:focus,input[type=tel]:focus,input[type=color]:focus,select:focus,textarea:focus
{
border-color:#b3d4fc;
}
input:not([type]):focus
{
border-color:#b3d4fc;
}
input[type=radio],input[type=checkbox]
{
vertical-align:middle;
}
input[type=file]:focus,input[type=radio]:focus,input[type=checkbox]:focus
{
outline:1px solid thin #444;
outline:.1rem solid thin #444;
}
input[type=text][disabled],input[type=password][disabled],input[type=email][disabled],input[type=url][disabled],input[type=date][disabled],input[type=month][disabled],input[type=time][disabled],input[type=datetime][disabled],input[type=datetime-local][disabled],input[type=week][disabled],input[type=number][disabled],input[type=search][disabled],input[type=tel][disabled],input[type=color][disabled],select[disabled],textarea[disabled]
{
background-color:#efefef;
color:#777;
cursor:not-allowed;
}
input:not([type])[disabled]
{
background-color:#efefef;
color:#777;
cursor:not-allowed;
}
input[readonly],select[readonly],textarea[readonly]
{
background-color:#efefef;
border-color:#ccc;
color:#777;
}
input:focus:invalid,textarea:focus:invalid,select:focus:invalid
{
border-color:#e9322d;
color:#b94a48;
}
input[type=file]:focus:invalid:focus,input[type=radio]:focus:invalid:focus,input[type=checkbox]:focus:invalid:focus
{
outline-color:#ff4136;
}
select
{
background-color:#fff;
border:1px solid #ccc;
border:.1rem solid #ccc;
}
select[multiple]
{
height:auto;
}
label
{
line-height:2;
}
fieldset
{
border:0;
margin:0;
padding:8px 0;
padding:.8rem 0;
}
legend
{
border-bottom:1px solid #ccc;
border-bottom:.1rem solid #ccc;
color:#444;
display:block;
margin-bottom:8px;
margin-bottom:.8rem;
padding:8px 0;
padding:.8rem 0;
width:100%;
}
input[type=submit],button
{
-moz-user-select:none;
-ms-user-select:none;
-webkit-transition:.25s ease;
-webkit-user-drag:none;
-webkit-user-select:none;
border:2px solid #444;
border:.2rem solid #444;
border-radius:0;
color:#444;
cursor:pointer;
display:inline-block;
margin-bottom:8px;
margin-bottom:.8rem;
margin-right:4px;
margin-right:.4rem;
padding:8px 16px;
padding:.8rem 1.6rem;
text-align:center;
text-decoration:none;
text-transform:uppercase;
transition:.25s ease;
user-select:none;
vertical-align:baseline;
}
input[type=submit] a,button a
{
color:#444;
}
input[type=submit]::-moz-focus-inner,button::-moz-focus-inner
{
padding:0;
}
input[type=submit]:hover,button:hover
{
background:#444;
border-color:#444;
color:#fff;
}
input[type=submit]:hover a,button:hover a
{
color:#fff;
}
input[type=submit]:active,button:active
{
background:#6a6a6a;
border-color:#6a6a6a;
color:#fff;
}
input[type=submit]:active a,button:active a
{
color:#fff;
}
input[type=submit]:disabled,button:disabled
{
box-shadow:none;
cursor:not-allowed;
opacity:.40;
}
nav ul
{
list-style:none;
margin:0;
padding:0;
text-align:center;
}
nav ul li
{
display:inline;
}
nav a
{
-webkit-transition:.25s ease;
border-bottom:2px solid transparent;
border-bottom:.2rem solid transparent;
color:#444;
padding:8px 16px;
padding:.8rem 1.6rem;
text-decoration:none;
transition:.25s ease;
}
nav a:hover,nav li.selected a
{
border-color:rgba(0, 0, 0, .2);
}
nav a:active
{
border-color:rgba(0, 0, 0, .56);
}
caption
{
padding:8px 0;
padding:.8rem 0;
}
thead th
{
background:#efefef;
color:#444;
}
tr
{
background:#fff;
margin-bottom:8px;
margin-bottom:.8rem;
}
th,td
{
border:1px solid #ccc;
border:.1rem solid #ccc;
padding:8px 16px;
padding:.8rem 1.6rem;
text-align:center;
vertical-align:inherit;
}
tfoot tr
{
background:none;
}
tfoot td
{
color:#efefef;
font-size:8px;
font-size:.8rem;
font-style:italic;
padding:16px 4px;
padding:1.6rem .4rem;
}
@media screen {
[hidden~=screen]
{
display:inherit;
}
[hidden~=screen]:not(:active):not(:focus):not(:target)
{
clip:rect(0000)!important;
position:absolute!important;
}
}
@media screen and max-width 40rem {
article,section,aside
{
clear:both;
display:block;
max-width:100%;
}
img
{
margin-right:1.6rem;
}
}
template, [hidden="hidden"], .media[hidden] {display:none} template, [hidden="hidden"], .media[hidden] {display:none}
body {margin: 0.5em;} body {margin: 0.5em;}
@ -14,13 +688,13 @@ table {
td { td {
padding:1em; padding:1em;
padding:16px; padding:10px;
padding:1rem; padding:1rem;
} }
thead td, thead th { thead td, thead th {
padding:0.5em; padding:0.5em;
padding:8px; padding:5px;
padding:0.5rem; padding:0.5rem;
} }
@ -43,32 +717,46 @@ a:hover, a:active {
.bracketed { .bracketed {
color:#12db18; color:#12db18;
} }
.bracketed, h1 a { .bracketed, h1 a {
text-shadow:1px 1px 1px #000; text-shadow:1px 1px 1px #000;
} }
.bracketed:before {content: '[\00a0'} .bracketed:before {content: '[\00a0'}
.bracketed:after {content: '\00a0]'} .bracketed:after {content: '\00a0]'}
.bracketed:hover, .bracketed:active { .bracketed:hover, .bracketed:active {
color:#db7d12 color:#db7d12
} }
.grow-1 {-webkit-box-flex: 1;-ms-flex-positive: 1;flex-grow: 1} .grow-1 {-webkit-box-flex: 1;-ms-flex-positive: 1;flex-grow: 1}
.flex-wrap {-ms-flex-wrap: wrap;flex-wrap: wrap} .flex-wrap {-ms-flex-wrap: wrap;flex-wrap: wrap}
.flex-no-wrap {-ms-flex-wrap: nowrap;flex-wrap: nowrap} .flex-no-wrap {-ms-flex-wrap: nowrap;flex-wrap: nowrap}
.flex-align-end {-webkit-box-align: end;-ms-flex-align: end;align-items: flex-end} .flex-align-end {-webkit-box-align: end;-ms-flex-align: end;align-items: flex-end}
.flex-align-space-around {-ms-flex-line-pack: distribute;align-content: space-around} .flex-align-space-around {-ms-flex-line-pack: distribute;align-content: space-around}
.flex-justify-space-around {-ms-flex-pack: distribute;justify-content: space-around} .flex-justify-space-around {-ms-flex-pack: distribute;justify-content: space-around}
.flex-self-center {-ms-flex-item-align:center;-ms-grid-row-align:center;align-self:center} .flex-self-center {-ms-flex-item-align:center;-ms-grid-row-align:center;align-self:center}
.flex {display: -webkit-box;display: -ms-flexbox;display: flex} .flex {display: -webkit-box;display: -ms-flexbox;display: flex}
.small-font { .small-font {
font-size:25.6px; font-size:16px;
font-size:1.6rem; font-size:1.6rem;
} }
.justify {text-align:justify} .justify {text-align:justify}
.align_center {text-align:center} .align_center {text-align:center}
.align_left {text-align:left} .align_left {text-align:left}
.align_right {text-align:right} .align_right {text-align:right}
.valign_top {vertical-align:top} .valign_top {vertical-align:top}
@ -97,9 +785,10 @@ a:hover, a:active {
color:#12db18; color:#12db18;
text-shadow:1px 1px 1px #000; text-shadow:1px 1px 1px #000;
padding:0 0.5em; padding:0 0.5em;
padding:0 8px; padding:0 5px;
padding:0 0.5rem; padding:0 0.5rem;
} }
.user-btn:hover, .user-btn:active { .user-btn:hover, .user-btn:active {
border-color:#db7d12; border-color:#db7d12;
background-color:#db7d12; background-color:#db7d12;
@ -220,17 +909,21 @@ a:hover, a:active {
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
Table sorting and form styles Table sorting and form styles
------------------------------------------------------------------------------*/ ------------------------------------------------------------------------------*/
.sorting, .sorting,
.sorting_asc, .sorting_asc,
.sorting_desc { .sorting_desc {
vertical-align:text-bottom; vertical-align:text-bottom;
} }
.sorting::before { .sorting::before {
content: " ↕\00a0"; content: " ↕\00a0";
} }
.sorting_asc::before { .sorting_asc::before {
content: " ↑\00a0"; content: " ↑\00a0";
} }
.sorting_desc::before { .sorting_desc::before {
content: " ↓\00a0"; content: " ↓\00a0";
} }
@ -247,6 +940,7 @@ a:hover, a:active {
min-width:25px; min-width:25px;
max-width:30%; max-width:30%;
} }
.form tr > td:nth-child(even) { .form tr > td:nth-child(even) {
text-align:left; text-align:left;
width:70%; width:70%;
@ -255,6 +949,7 @@ a:hover, a:active {
.invisible tbody > tr:nth-child(odd) { .invisible tbody > tr:nth-child(odd) {
background: inherit; background: inherit;
} }
.invisible tr, .invisible td, .invisible th { .invisible tr, .invisible td, .invisible th {
border:0; border:0;
} }
@ -300,7 +995,7 @@ a:hover, a:active {
background: #f3e6e6; background: #f3e6e6;
} }
.message.error .icon::after { .message.error .icon::after {
content: '✘'; content: '✘';
} }
@ -308,7 +1003,8 @@ a:hover, a:active {
border:1px solid #1f8454; border:1px solid #1f8454;
background: #70dda9; background: #70dda9;
} }
.message.success .icon::after {
.message.success .icon::after {
content: '✔' content: '✔'
} }
@ -317,7 +1013,7 @@ a:hover, a:active {
background: #FFFFCC; background: #FFFFCC;
} }
.message.info .icon::after { .message.info .icon::after {
content: '⚠'; content: '⚠';
} }
@ -339,7 +1035,7 @@ a:hover, a:active {
margin:0.5em auto; margin:0.5em auto;
} }
.name, .name,
.media_metadata > div, .media_metadata > div,
.medium_metadata > div, .medium_metadata > div,
.row { .row {
@ -350,28 +1046,28 @@ a:hover, a:active {
text-align:right; text-align:right;
} }
.media_type, .age_rating { .media_type, .age_rating {
text-align:left; text-align:left;
} }
.media > .media_metadata { .media > .media_metadata {
position:absolute; position:absolute;
bottom:0; bottom:0;
right:0; right:0;
} }
.media > .medium_metadata { .media > .medium_metadata {
position:absolute; position:absolute;
bottom: 0; bottom: 0;
left:0; left:0;
} }
.media > .name { .media > .name {
position:absolute; position:absolute;
top: 0; top: 0;
} }
.media:hover > .name, .media:hover > .name,
.media:hover > .media_metadata > div, .media:hover > .media_metadata > div,
.media:hover > .medium_metadata > div, .media:hover > .medium_metadata > div,
.media:hover > .table .row .media:hover > .table .row
@ -381,7 +1077,7 @@ a:hover, a:active {
background:rgba(0, 0, 0, .75); background:rgba(0, 0, 0, .75);
} }
.media:hover > button[hidden], .media:hover > button[hidden],
.media:hover > .edit_buttons[hidden] .media:hover > .edit_buttons[hidden]
{ {
-webkit-transition:.25s ease; -webkit-transition:.25s ease;
@ -389,17 +1085,16 @@ a:hover, a:active {
display:block; display:block;
} }
.media > .name > a { .media > .name > a {
background:none; background:none;
color:#fff; color:#fff;
text-shadow:1px 2px 1px rgba(0, 0, 0, .85); text-shadow:1px 2px 1px rgba(0, 0, 0, .85);
} }
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
Anime-list-specific styles Anime-list-specific styles
------------------------------------------------------------------------------*/ ------------------------------------------------------------------------------*/
.anime .name, .manga .name { .anime .name, .manga .name {
text-align:center; text-align:center;
width:100%; width:100%;
@ -417,7 +1112,6 @@ a:hover, a:active {
text-align:center; text-align:center;
} }
.anime .table, .manga .table { .anime .table, .manga .table {
position:absolute; position:absolute;
bottom:0; bottom:0;
@ -463,6 +1157,7 @@ a:hover, a:active {
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
Manga-list-specific styles Manga-list-specific styles
------------------------------------------------------------------------------*/ ------------------------------------------------------------------------------*/
.manga .row { .manga .row {
padding:1px; padding:1px;
} }
@ -481,10 +1176,10 @@ a:hover, a:active {
left: calc(50% - 95px); left: calc(50% - 95px);
} }
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
Search page styles Search page styles
------------------------------------------------------------------------------*/ ------------------------------------------------------------------------------*/
.media.search > .name { .media.search > .name {
background-color:#555; background-color:#555;
background-color: rgba(0, 0, 0, .35); background-color: rgba(0, 0, 0, .35);
@ -506,7 +1201,7 @@ a:hover, a:active {
.big-check:checked + label:after { .big-check:checked + label:after {
content: '✓'; content: '✓';
font-size: 15em; font-size: 15em;
font-size:240px; font-size:150px;
font-size: 15rem; font-size: 15rem;
text-align:center; text-align:center;
color: greenyellow; color: greenyellow;
@ -520,6 +1215,7 @@ a:hover, a:active {
#series_list article.media { #series_list article.media {
position:relative; position:relative;
} }
#series_list .name, #series_list .name label { #series_list .name, #series_list .name label {
position:absolute; position:absolute;
display:block; display:block;
@ -532,12 +1228,13 @@ a:hover, a:active {
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
Details page styles Details page styles
-----------------------------------------------------------------------------*/ -----------------------------------------------------------------------------*/
.details { .details {
margin:24px auto 0 auto; margin:15px auto 0 auto;
margin: 1.5rem auto 0 auto; margin: 1.5rem auto 0 auto;
max-width:1488px; max-width:930px;
max-width:93rem; max-width:93rem;
padding:16px; padding:10px;
padding:1rem; padding:1rem;
font-size:inherit; font-size:inherit;
} }
@ -552,15 +1249,16 @@ a:hover, a:active {
} }
.details .flex > div { .details .flex > div {
margin:16px; margin:10px;
margin: 1rem; margin: 1rem;
} }
.details table { .details table {
max-width:300px; max-width:300px;
} }
.details td {
padding:0 24px; .details td {
padding:0 15px;
padding:0 1.5rem; padding:0 1.5rem;
} }
@ -573,6 +1271,7 @@ a:hover, a:active {
white-space:nowrap; white-space:nowrap;
text-align:right; text-align:right;
} }
.details td:nth-child(even) { .details td:nth-child(even) {
text-align:left; text-align:left;
} }

View File

@ -1,3 +1,5 @@
@import "./marx.myth.css";
:root { :root {
--link-shadow: 1px 1px 1px #000; --link-shadow: 1px 1px 1px #000;
--shadow: 1px 2px 1px rgba(0, 0, 0, 0.85); --shadow: 1px 2px 1px rgba(0, 0, 0, 0.85);

View File

@ -1,673 +0,0 @@
:root
{
-ms-text-size-adjust:100%;
-webkit-text-size-adjust:100%;
box-sizing:border-box;
cursor:default;
font-family:'Open Sans', 'Nimbus Sans L', 'Helvetica Neue', Helvetica, 'Lucida Grande', sans-serif;
line-height:1.4;
overflow-y:scroll;
text-size-adjust:100%;
scroll-behavior: smooth;
}
audio:not([controls])
{
display:none;
}
details
{
display:block;
}
input[type=search]
{
-webkit-appearance:textfield;
}
input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration
{
-webkit-appearance:none;
}
main
{
display:block;
margin:0 auto;
padding:0 1.6em 1.6em;
padding:0 16px 16px;
padding:0 1.6rem 1.6rem;
}
summary
{
display:block;
}
pre
{
background:#efefef;
color:#444;
display:block;
font-family:Menlo, Monaco, Consolas, 'Courier New', monospace;
font-size:1.4em;
font-size:14px;
font-size:1.4rem;
margin:1.6em 0;
margin:16px 0;
margin:1.6rem 0;
overflow:auto;
padding:1.6em;
padding:16px;
padding:1.6rem;
word-break:break-all;
word-wrap:break-word;
}
progress
{
display:inline-block;
}
small
{
color:#777;
font-size:75%;
}
big
{
font-size:125%;
}
template
{
display:none;
}
textarea
{
border:1px solid #ccc;
border:.1rem solid #ccc;
border-radius:0;
display:block;
margin-bottom:8px;
margin-bottom:.8rem;
overflow:auto;
padding:8px;
padding:.8rem;
resize:vertical;
vertical-align:middle;
}
[hidden]
{
display:none;
}
[unselectable]
{
-moz-user-select:none;
-ms-user-select:none;
-webkit-user-select:none;
user-select:none;
}
*,::before,::after
{
border-style:solid;
border-width:0;
box-sizing:inherit;
}
*
{
font-size:inherit;
line-height:inherit;
margin:0;
padding:0;
}
::before,::after
{
text-decoration:inherit;
vertical-align:inherit;
}
a
{
-webkit-transition:.25s ease;
color:#1271db;
text-decoration:none;
transition:.25s ease;
}
audio,canvas,iframe,img,svg,video
{
vertical-align:middle;
}
button,input,select,textarea
{
border:1px solid #ccc;
border:.1rem solid #ccc;
color:inherit;
font-family:inherit;
font-style:inherit;
font-weight:inherit;
min-height:1.4em;
}
code,kbd,pre,samp
{
font-family:Menlo, Monaco, Consolas, 'Courier New', monospace, monospace;
}
table
{
border-collapse:collapse;
border-spacing:0;
margin-bottom:16px;
margin-bottom:1.6rem;
}
::-moz-selection
{
background-color:#b3d4fc;
text-shadow:none;
}
::selection
{
background-color:#b3d4fc;
text-shadow:none;
}
button::-moz-focus-inner
{
border:0;
}
body
{
color:#444;
font-family:'Open Sans', 'Nimbus Sans L', 'Helvetica Neue', Helvetica, 'Lucida Grande', sans-serif;
font-size:16px;
font-size:1.6rem;
font-style:normal;
font-weight:400;
padding:0;
}
p
{
margin:0 0 16px;
margin:0 0 1.6rem;
}
h1,h2,h3,h4,h5,h6
{
font-family:Lato, 'Open Sans', 'Nimbus Sans L', 'Helvetica Neue', Helvetica, 'Lucida Grande', sans-serif;
margin:2em 0 1.6em;
margin:20px 0 16px;
margin:2rem 0 1.6rem;
}
h1
{
border-bottom:1px solid rgba(0, 0, 0, .2);
border-bottom:.1rem solid rgba(0, 0, 0, .2);
font-size:3.6em;
font-size:36px;
font-size:3.6rem;
font-style:normal;
font-weight:500;
}
h2
{
font-size:3em;
font-size:30px;
font-size:3rem;
font-style:normal;
font-weight:500;
}
h3
{
font-size:2.4em;
font-size:24px;
font-size:2.4rem;
font-style:normal;
font-weight:500;
margin:16px 0 4px;
margin:1.6rem 0 .4rem;
}
h4
{
font-size:1.8em;
font-size:18px;
font-size:1.8rem;
font-style:normal;
font-weight:600;
margin:16px 0 4px;
margin:1.6rem 0 .4rem;
}
h5
{
font-size:1.6em;
font-size:16px;
font-size:1.6rem;
font-style:normal;
font-weight:600;
margin:16px 0 4px;
margin:1.6rem 0 .4rem;
}
h6
{
color:#777;
font-size:1.4em;
font-size:14px;
font-size:1.4rem;
font-style:normal;
font-weight:600;
margin:16px 0 4px;
margin:1.6rem 0 .4rem;
}
code
{
background:#efefef;
color:#444;
font-family:Menlo, Monaco, Consolas, 'Courier New', monospace;
font-size:14px;
font-size:1.4rem;
word-break:break-all;
word-wrap:break-word;
}
a:hover,a:focus
{
text-decoration:none;
}
dl
{
margin-bottom:16px;
margin-bottom:1.6rem;
}
dd
{
margin-left:40px;
margin-left:4rem;
}
ul,ol
{
margin-bottom:8px;
margin-bottom:.8rem;
padding-left:20px;
padding-left:2rem;
}
blockquote
{
border-left:2px solid #1271db;
border-left:.2rem solid #1271db;
font-family:Georgia, Times, 'Times New Roman', serif;
font-style:italic;
margin:16px 0;
margin:1.6rem 0;
padding-left:16px;
padding-left:1.6rem;
}
figcaption
{
font-family:Georgia, Times, 'Times New Roman', serif;
}
html
{
font-size:62.5%;
}
main,header,footer,article,section,aside,details,summary
{
display:block;
height:auto;
margin:0 auto;
width:100%;
}
footer
{
border-top:1px solid rgba(0, 0, 0, .2);
border-top:.1rem solid rgba(0, 0, 0, .2);
clear:both;
display:inline-block;
float:left;
max-width:100%;
padding:10px 0;
padding:1rem 0;
text-align:center;
}
hr
{
border-top:1px solid rgba(0, 0, 0, .2);
border-top:.1rem solid rgba(0, 0, 0, .2);
display:block;
margin-bottom:16px;
margin-bottom:1.6rem;
width:100%;
}
img
{
height:auto;
max-width:100%;
vertical-align:baseline;
}
input[type=text],input[type=password],input[type=email],input[type=url],input[type=date],input[type=month],input[type=time],input[type=datetime],input[type=datetime-local],input[type=week],input[type=number],input[type=search],input[type=tel],input[type=color],select
{
border:1px solid #ccc;
border:.1rem solid #ccc;
border-radius:0;
display:inline-block;
padding:8px;
padding:.8rem;
vertical-align:middle;
}
input:not([type])
{
-webkit-appearance:none;
background-clip:padding-box;
background-color:#fff;
border:1px solid #ccc;
border:.1rem solid #ccc;
border-radius:0;
color:#444;
display:inline-block;
padding:8px;
padding:.8rem;
text-align:left;
}
input[type=color]
{
padding:8px 16px;
padding:.8rem 1.6rem;
}
input[type=text]:focus,input[type=password]:focus,input[type=email]:focus,input[type=url]:focus,input[type=date]:focus,input[type=month]:focus,input[type=time]:focus,input[type=datetime]:focus,input[type=datetime-local]:focus,input[type=week]:focus,input[type=number]:focus,input[type=search]:focus,input[type=tel]:focus,input[type=color]:focus,select:focus,textarea:focus
{
border-color:#b3d4fc;
}
input:not([type]):focus
{
border-color:#b3d4fc;
}
input[type=radio],input[type=checkbox]
{
vertical-align:middle;
}
input[type=file]:focus,input[type=radio]:focus,input[type=checkbox]:focus
{
outline:1px solid thin #444;
outline:.1rem solid thin #444;
}
input[type=text][disabled],input[type=password][disabled],input[type=email][disabled],input[type=url][disabled],input[type=date][disabled],input[type=month][disabled],input[type=time][disabled],input[type=datetime][disabled],input[type=datetime-local][disabled],input[type=week][disabled],input[type=number][disabled],input[type=search][disabled],input[type=tel][disabled],input[type=color][disabled],select[disabled],textarea[disabled]
{
background-color:#efefef;
color:#777;
cursor:not-allowed;
}
input:not([type])[disabled]
{
background-color:#efefef;
color:#777;
cursor:not-allowed;
}
input[readonly],select[readonly],textarea[readonly]
{
background-color:#efefef;
border-color:#ccc;
color:#777;
}
input:focus:invalid,textarea:focus:invalid,select:focus:invalid
{
border-color:#e9322d;
color:#b94a48;
}
input[type=file]:focus:invalid:focus,input[type=radio]:focus:invalid:focus,input[type=checkbox]:focus:invalid:focus
{
outline-color:#ff4136;
}
select
{
background-color:#fff;
border:1px solid #ccc;
border:.1rem solid #ccc;
}
select[multiple]
{
height:auto;
}
label
{
line-height:2;
}
fieldset
{
border:0;
margin:0;
padding:8px 0;
padding:.8rem 0;
}
legend
{
border-bottom:1px solid #ccc;
border-bottom:.1rem solid #ccc;
color:#444;
display:block;
margin-bottom:8px;
margin-bottom:.8rem;
padding:8px 0;
padding:.8rem 0;
width:100%;
}
input[type=submit],button
{
-moz-user-select:none;
-ms-user-select:none;
-webkit-transition:.25s ease;
-webkit-user-drag:none;
-webkit-user-select:none;
border:2px solid #444;
border:.2rem solid #444;
border-radius:0;
color:#444;
cursor:pointer;
display:inline-block;
margin-bottom:8px;
margin-bottom:.8rem;
margin-right:4px;
margin-right:.4rem;
padding:8px 16px;
padding:.8rem 1.6rem;
text-align:center;
text-decoration:none;
text-transform:uppercase;
transition:.25s ease;
user-select:none;
vertical-align:baseline;
}
input[type=submit] a,button a
{
color:#444;
}
input[type=submit]::-moz-focus-inner,button::-moz-focus-inner
{
padding:0;
}
input[type=submit]:hover,button:hover
{
background:#444;
border-color:#444;
color:#fff;
}
input[type=submit]:hover a,button:hover a
{
color:#fff;
}
input[type=submit]:active,button:active
{
background:#6a6a6a;
border-color:#6a6a6a;
color:#fff;
}
input[type=submit]:active a,button:active a
{
color:#fff;
}
input[type=submit]:disabled,button:disabled
{
box-shadow:none;
cursor:not-allowed;
opacity:.40;
}
nav ul
{
list-style:none;
margin:0;
padding:0;
text-align:center;
}
nav ul li
{
display:inline;
}
nav a
{
-webkit-transition:.25s ease;
border-bottom:2px solid transparent;
border-bottom:.2rem solid transparent;
color:#444;
padding:8px 16px;
padding:.8rem 1.6rem;
text-decoration:none;
transition:.25s ease;
}
nav a:hover,nav li.selected a
{
border-color:rgba(0, 0, 0, .2);
}
nav a:active
{
border-color:rgba(0, 0, 0, .56);
}
caption
{
padding:8px 0;
padding:.8rem 0;
}
thead th
{
background:#efefef;
color:#444;
}
tr
{
background:#fff;
margin-bottom:8px;
margin-bottom:.8rem;
}
th,td
{
border:1px solid #ccc;
border:.1rem solid #ccc;
padding:8px 16px;
padding:.8rem 1.6rem;
text-align:center;
vertical-align:inherit;
}
tfoot tr
{
background:none;
}
tfoot td
{
color:#efefef;
font-size:8px;
font-size:.8rem;
font-style:italic;
padding:16px 4px;
padding:1.6rem .4rem;
}
@media screen {
[hidden~=screen]
{
display:inherit;
}
[hidden~=screen]:not(:active):not(:focus):not(:target)
{
clip:rect(0000)!important;
position:absolute!important;
}
}
@media screen and max-width 40rem {
article,section,aside
{
clear:both;
display:block;
max-width:100%;
}
img
{
margin-right:1.6rem;
}
}

View File

@ -118,7 +118,7 @@ class JSMin extends BaseMin {
protected function check_minify_errors($options) protected function check_minify_errors($options)
{ {
$error_res = $this->closure_call($options); $error_res = $this->closure_call($options);
$error_json = $error_res->getBody(); $error_json = (string)$error_res->getBody();
$error_obj = json_decode($error_json) ?: (object)[]; $error_obj = json_decode($error_json) ?: (object)[];
// Show error if exists // Show error if exists
@ -201,7 +201,7 @@ class JSMin extends BaseMin {
// Now actually retrieve the compiled code // Now actually retrieve the compiled code
$options['output_info'] = 'compiled_code'; $options['output_info'] = 'compiled_code';
$res = $this->closure_call($options); $res = $this->closure_call($options);
$json = $res->getBody(); $json = (string)$res->getBody();
$obj = json_decode($json); $obj = json_decode($json);
return $obj->compiledCode; return $obj->compiledCode;

2
public/js/anime_collection.js Executable file → Normal file
View File

@ -10,7 +10,7 @@
// Give mustache a key to iterate over // Give mustache a key to iterate over
searchResults = { searchResults = {
anime: searchResults data: searchResults.data
}; };
Mustache.parse(tempHtml); Mustache.parse(tempHtml);

View File

@ -1,17 +1,14 @@
{ {
"scripts": { "scripts": {
"build": "npm-run-all --parallel build:base build:marx", "build": "postcss -u postcss-import --autoprefixer.browsers \"> 5%\" -u postcss-cssnext -o css/base.css css/base.myth.css",
"build:base": "postcss --autoprefixer.browsers \"> 5%\" --use postcss-cssnext -o css/base.css css/base.myth.css", "watch": "postcss -u postcss-import --autoprefixer.browsers \"> 5%\" -u postcss-cssnext -w -o css/base.css css/base.myth.css"
"build:marx": "postcss --autoprefixer.browsers \"> 5%\" --use postcss-cssnext -o css/marx.css css/marx.myth.css",
"watch": "npm-run-all --parallel watch:base watch:marx",
"watch:base": "postcss --autoprefixer.browsers \"> 5%\" --use postcss-cssnext -w -o css/base.css css/base.myth.css",
"watch:marx": "postcss --autoprefixer.browsers \"> 5%\" --use postcss-cssnext -w -o css/marx.css css/marx.myth.css"
}, },
"devDependencies": { "devDependencies": {
"autoprefixer": "^6.6.1", "autoprefixer": "^6.6.1",
"npm-run-all": "^4.0.0", "npm-run-all": "^4.0.0",
"postcss-cachify": "^1.3.1", "postcss-cachify": "^1.3.1",
"postcss-cli": "^2.6.0", "postcss-cli": "^2.6.0",
"postcss-cssnext": "^2.9.0" "postcss-cssnext": "^2.9.0",
"postcss-import": "^9.0.0"
} }
} }

View File

@ -1,10 +1,15 @@
{{#anime}} {{#data}}
<article class="media search"> <article class="media search">
<div class="name" style="background-image:url({{cover_image}})"> <div class="name" style="background-image:url({{attributes.posterImage.small}})">
<input type="radio" class="big-check" id="{{slug}}" name="id" value="{{id}}" /> <input type="radio" class="big-check" id="{{attributes.slug}}" name="id" value="{{id}}" />
<label for="{{slug}}"> <label for="{{attributes.slug}}">
<span>{{title}}<br />{{alternate_title}}</span> <span class="name">
{{attributes.canonicalTitle}}<br />
{{attributes.titles.en}}<br />
{{attributes.titles.en_jp}}<br />
{{attributes.titles.ja_jp}}
</span>
</label> </label>
</div> </div>
</article> </article>
{{/anime}} {{/data}}

36
src/API/Kitsu.php Normal file
View File

@ -0,0 +1,36 @@
<?php declare(strict_types=1);
/**
* Anime List Client
*
* An API client for Kitsu and MyAnimeList to manage anime and manga watch lists
*
* PHP version 7
*
* @package AnimeListClient
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2015 - 2016 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 4.0
* @link https://github.com/timw4mail/HummingBirdAnimeClient
*/
namespace Aviat\AnimeClient\API;
use Aviat\AnimeClient\API\Kitsu\Enum\AnimeWatchingStatus;
/**
* Constants and mappings for the Kitsu API
*/
class Kitsu {
public static function getStatusToSelectMap()
{
return [
AnimeWatchingStatus::WATCHING => 'Currently Watching',
AnimeWatchingStatus::PLAN_TO_WATCH => 'Plan to Watch',
AnimeWatchingStatus::COMPLETED => 'Completed',
AnimeWatchingStatus::ON_HOLD => 'On Hold',
AnimeWatchingStatus::DROPPED => 'Dropped'
];
}
}

View File

@ -1,19 +1,19 @@
<?php declare(strict_types=1); <?php declare(strict_types=1);
/** /**
* Anime List Client * Anime List Client
* *
* An API client for Kitsu and MyAnimeList to manage anime and manga watch lists * An API client for Kitsu and MyAnimeList to manage anime and manga watch lists
* *
* PHP version 7 * PHP version 7
* *
* @package AnimeListClient * @package AnimeListClient
* @author Timothy J. Warren <tim@timshomepage.net> * @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2015 - 2016 Timothy J. Warren * @copyright 2015 - 2016 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 4.0 * @version 4.0
* @link https://github.com/timw4mail/HummingBirdAnimeClient * @link https://github.com/timw4mail/HummingBirdAnimeClient
*/ */
namespace Aviat\AnimeClient\API\Kitsu; namespace Aviat\AnimeClient\API\Kitsu;
use Aviat\AnimeClient\AnimeClient; use Aviat\AnimeClient\AnimeClient;
@ -62,8 +62,8 @@ class Auth {
*/ */
public function authenticate($password) public function authenticate($password)
{ {
$username = $this->container->get('config') $config = $this->container->get('config');
->get('kitsu_username'); $username = $config->get(['kitsu_username']);
$auth_token = $this->model->authenticate($username, $password); $auth_token = $this->model->authenticate($username, $password);
if (FALSE !== $auth_token) if (FALSE !== $auth_token)

View File

@ -22,10 +22,10 @@ use Aviat\Ion\Enum as BaseEnum;
* Possible values for watching status for the current anime * Possible values for watching status for the current anime
*/ */
class AnimeWatchingStatus extends BaseEnum { class AnimeWatchingStatus extends BaseEnum {
const WATCHING = 1; const WATCHING = 'current';
const PLAN_TO_WATCH = 2; const PLAN_TO_WATCH = 'planned';
const COMPLETED = 3; const COMPLETED = 'completed';
const ON_HOLD = 4; const ON_HOLD = 'on_hold';
const DROPPED = 5; const DROPPED = 'dropped';
} }
// End of AnimeWatchingStatus.php // End of AnimeWatchingStatus.php

View File

@ -20,14 +20,13 @@ use Aviat\AnimeClient\AnimeClient;
use Aviat\AnimeClient\API\Kitsu\Transformer\{ use Aviat\AnimeClient\API\Kitsu\Transformer\{
AnimeTransformer, AnimeListTransformer, MangaTransformer, MangaListTransformer AnimeTransformer, AnimeListTransformer, MangaTransformer, MangaListTransformer
}; };
use Aviat\Ion\Json; use Aviat\Ion\Di\ContainerAware;
use GuzzleHttp\Exception\ClientException;
/** /**
* Kitsu API Model * Kitsu API Model
*/ */
class KitsuModel { class KitsuModel {
use ContainerAware;
use KitsuTrait; use KitsuTrait;
const CLIENT_ID = 'dd031b32d2f56c990b1425efe6c42ad847e7fe3ab46bf1299f05ecd856bdb7dd'; const CLIENT_ID = 'dd031b32d2f56c990b1425efe6c42ad847e7fe3ab46bf1299f05ecd856bdb7dd';
@ -47,6 +46,11 @@ class KitsuModel {
*/ */
protected $animeTransformer; protected $animeTransformer;
/**
* @var MangaTransformer
*/
protected $mangaTransformer;
/** /**
* @var MangaListTransformer * @var MangaListTransformer
*/ */
@ -66,6 +70,19 @@ class KitsuModel {
$this->mangaListTransformer = new MangaListTransformer(); $this->mangaListTransformer = new MangaListTransformer();
} }
public function getUserIdByUsername(string $username)
{
$data = $this->getRequest('users', [
'query' => [
'filter' => [
'name' => $username
]
]
]);
return $data['data'][0]['id'];
}
/** /**
* Get the access token from the Kitsu API * Get the access token from the Kitsu API
* *
@ -76,38 +93,66 @@ class KitsuModel {
public function authenticate(string $username, string $password) public function authenticate(string $username, string $password)
{ {
$data = $this->postRequest(AnimeClient::KITSU_AUTH_URL, [ $data = $this->postRequest(AnimeClient::KITSU_AUTH_URL, [
'body' => http_build_query([ 'form_params' => [
'grant_type' => 'password', 'grant_type' => 'password',
'username' => $username, 'username' => $username,
'password' => $password, 'password' => $password
'client_id' => self::CLIENT_ID, ]
'client_secret' => self::CLIENT_SECRET
])
]); ]);
if (array_key_exists('access_token', $data)) { if (array_key_exists('access_token', $data))
// @TODO save token {
return true; return $data['access_token'];
} }
return false; return false;
} }
/**
* Get information about a particular anime
*
* @param string $animeId
* @return array
*/
public function getAnime(string $animeId): array public function getAnime(string $animeId): array
{ {
$baseData = $this->getRawAnimeData($animeId); $baseData = $this->getRawMediaData('anime', $animeId);
return $this->animeTransformer->transform($baseData); return $this->animeTransformer->transform($baseData);
} }
/**
* Get information about a particular manga
*
* @param string $animeId
* @return array
*/
public function getManga(string $mangaId): array public function getManga(string $mangaId): array
{ {
$baseData = $this->getRawMediaData('manga', $mangaId); $baseData = $this->getRawMediaData('manga', $mangaId);
return $this->mangaTransformer->transform($baseData); return $this->mangaTransformer->transform($baseData);
} }
public function getRawAnimeData($animeId): array public function getListItem(string $listId): array
{ {
return $this->getRawMediaData('anime', $animeId); $baseData = $this->getRequest("library-entries/{$listId}", [
'query' => [
'include' => 'media'
]
]);
switch ($baseData['included'][0]['type'])
{
case 'anime':
$baseData['data']['anime'] = $baseData['included'][0];
return $this->animeListTransformer->transform($baseData['data']);
case 'manga':
$baseData['data']['manga'] = $baseData['included'][0];
return $this->mangaListTransformer->transform($baseData['data']);
default:
return $baseData['data']['attributes'];
}
} }
public function getAnimeList($status): array public function getAnimeList($status): array
@ -115,7 +160,7 @@ class KitsuModel {
$options = [ $options = [
'query' => [ 'query' => [
'filter' => [ 'filter' => [
'user_id' => 2644, 'user_id' => $this->getUserIdByUsername($this->getUsername()),
'media_type' => 'Anime', 'media_type' => 'Anime',
'status' => $status, 'status' => $status,
], ],
@ -145,7 +190,7 @@ class KitsuModel {
$options = [ $options = [
'query' => [ 'query' => [
'filter' => [ 'filter' => [
'user_id' => 2644, 'user_id' => $this->getUserIdByUsername($this->getUsername()),
'media_type' => 'Manga', 'media_type' => 'Manga',
'status' => $status, 'status' => $status,
], ],
@ -170,21 +215,48 @@ class KitsuModel {
return $transformed; return $transformed;
} }
private function getGenres(string $type, string $id): array public function search(string $type, string $query): array
{ {
$data = $this->getRequest("{$type}/{$id}/genres"); $options = [
$rawGenres = array_pluck($data['data'], 'attributes'); 'query' => [
$genres = array_pluck($rawGenres, 'name'); 'filter' => [
'text' => $query
]
],
'include' => 'media'
];
return $genres; $data = $this->getRequest($type, $options);
// @TODO implement search api call
return $data;
} }
private function getRawMediaData(string $type, string $id): array private function getUsername(): string
{ {
$data = $this->getRequest("{$type}/{$id}"); return $this->getContainer()
$baseData = $data['data']['attributes']; ->get('config')
$baseData['genres'] = $this->getGenres($type, $id); ->get(['kitsu_username']);
}
private function getRawMediaData(string $type, string $slug): array
{
$options = [
'query' => [
'filter' => [
'slug' => $slug
],
'include' => 'genres,mappings,streamingLinks',
]
];
$data = $this->getRequest($type, $options);
$baseData = $data['data'][0]['attributes'];
$rawGenres = array_pluck($data['included'], 'attributes');
$genres = array_pluck($rawGenres, 'name');
$baseData['genres'] = $genres;
$baseData['included'] = $data['included'];
return $baseData; return $baseData;
} }
} }

View File

@ -16,6 +16,7 @@
namespace Aviat\AnimeClient\API\Kitsu; namespace Aviat\AnimeClient\API\Kitsu;
use Aviat\AnimeClient\AnimeClient;
use Aviat\AnimeClient\API\GuzzleTrait; use Aviat\AnimeClient\API\GuzzleTrait;
use Aviat\Ion\Di\ContainerAware; use Aviat\Ion\Di\ContainerAware;
use Aviat\Ion\Json; use Aviat\Ion\Json;
@ -25,7 +26,6 @@ use InvalidArgumentException;
use RuntimeException; use RuntimeException;
trait KitsuTrait { trait KitsuTrait {
use ContainerAware;
use GuzzleTrait; use GuzzleTrait;
/** /**
@ -41,21 +41,23 @@ trait KitsuTrait {
*/ */
protected function init() protected function init()
{ {
$defaults = [
'cookies' => $this->cookieJar,
'headers' => [
'User-Agent' => "Tim's Anime Client/4.0",
'Accept-Encoding' => 'application/vnd.api+json',
'Content-Type' => 'application/vnd.api+json'
],
'timeout' => 25,
'connect_timeout' => 25
];
$this->cookieJar = new CookieJar(); $this->cookieJar = new CookieJar();
$this->client = new Client([ $this->client = new Client([
'base_uri' => $this->baseUrl, 'base_uri' => $this->baseUrl,
'cookies' => TRUE, 'cookies' => TRUE,
'http_errors' => TRUE, 'http_errors' => TRUE,
'defaults' => [ 'defaults' => $defaults
'cookies' => $this->cookieJar,
'headers' => [
'User-Agent' => "Tim's Anime Client/4.0",
'Accept-Encoding' => 'application/vnd.api+json',
'Content-Type' => 'application/vnd.api+json'
],
'timeout' => 25,
'connect_timeout' => 25
]
]); ]);
} }
@ -78,11 +80,6 @@ trait KitsuTrait {
$logger = NULL; $logger = NULL;
if ($this->getContainer())
{
$logger = $this->container->getLogger('default');
}
$defaultOptions = [ $defaultOptions = [
'headers' => [ 'headers' => [
'client_id' => 'dd031b32d2f56c990b1425efe6c42ad847e7fe3ab46bf1299f05ecd856bdb7dd', 'client_id' => 'dd031b32d2f56c990b1425efe6c42ad847e7fe3ab46bf1299f05ecd856bdb7dd',
@ -90,6 +87,20 @@ trait KitsuTrait {
] ]
]; ];
if ($this->getContainer())
{
$logger = $this->container->getLogger('default');
$sessionSegment = $this->getContainer()
->get('session')
->getSegment(AnimeClient::SESSION_SEGMENT);
if ($sessionSegment->get('auth_token') !== null)
{
$token = $sessionSegment->get('auth_token');
$defaultOptions['headers']['Authorization'] = "bearer {$token}";
}
}
$options = array_merge($defaultOptions, $options); $options = array_merge($defaultOptions, $options);
$response = $this->client->request($type, $url, $options); $response = $this->client->request($type, $url, $options);

View File

@ -39,8 +39,8 @@ class AnimeListTransformer extends AbstractTransformer {
$rating = (int) 2 * $item['attributes']['rating']; $rating = (int) 2 * $item['attributes']['rating'];
$total_episodes = array_key_exists('episodeCount', $item['anime']) $total_episodes = array_key_exists('episodeCount', $item['anime']['attributes'])
? (int) $anime['episodeCount'] ? (int) $anime['attributes']['episodeCount']
: '-'; : '-';
$alternate_title = NULL; $alternate_title = NULL;
@ -73,7 +73,7 @@ class AnimeListTransformer extends AbstractTransformer {
'age_rating' => $anime['attributes']['ageRating'], 'age_rating' => $anime['attributes']['ageRating'],
'title' => $anime['attributes']['canonicalTitle'], 'title' => $anime['attributes']['canonicalTitle'],
'alternate_title' => $alternate_title, 'alternate_title' => $alternate_title,
'slug' => $item['relationships']['media']['data']['id'],//$anime['slug'], 'slug' => $anime['attributes']['slug'],
'url' => $anime['attributes']['url'] ?? '', 'url' => $anime['attributes']['url'] ?? '',
'type' => $anime['attributes']['showType'], 'type' => $anime['attributes']['showType'],
'image' => $anime['attributes']['posterImage']['small'], 'image' => $anime['attributes']['posterImage']['small'],
@ -94,6 +94,7 @@ class AnimeListTransformer extends AbstractTransformer {
* *
* @param array $item Transformed library item * @param array $item Transformed library item
* @return array API library item * @return array API library item
* @TODO reimplement
*/ */
public function untransform($item) public function untransform($item)
{ {

View File

@ -1,52 +1,55 @@
<?php declare(strict_types=1); <?php declare(strict_types=1);
/** /**
* Anime List Client * Anime List Client
* *
* An API client for Kitsu and MyAnimeList to manage anime and manga watch lists * An API client for Kitsu and MyAnimeList to manage anime and manga watch lists
* *
* PHP version 7 * PHP version 7
* *
* @package AnimeListClient * @package AnimeListClient
* @author Timothy J. Warren <tim@timshomepage.net> * @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2015 - 2016 Timothy J. Warren * @copyright 2015 - 2016 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 4.0 * @version 4.0
* @link https://github.com/timw4mail/HummingBirdAnimeClient * @link https://github.com/timw4mail/HummingBirdAnimeClient
*/ */
namespace Aviat\AnimeClient\API\Kitsu\Transformer; namespace Aviat\AnimeClient\API\Kitsu\Transformer;
use Aviat\Ion\Transformer\AbstractTransformer; use Aviat\Ion\Transformer\AbstractTransformer;
/** /**
* Transformer for anime description page * Transformer for anime description page
*/ */
class AnimeTransformer extends AbstractTransformer { class AnimeTransformer extends AbstractTransformer {
/** /**
* Convert raw api response to a more * Convert raw api response to a more
* logical and workable structure * logical and workable structure
* *
* @param array $item API library item * @param array $item API library item
* @return array * @return array
*/ */
public function transform($item) public function transform($item)
{ {
sort($item['genres']); ?><pre><?= print_r($item, TRUE) ?></pre><?php
return [ $item['genres'] = $item['genres'] ?? [];
'title' => $item['canonicalTitle'], sort($item['genres']);
'en_title' => $item['titles']['en_jp'],
'jp_title' => $item['titles']['ja_jp'], return [
'cover_image' => $item['posterImage']['small'], 'title' => $item['canonicalTitle'],
'show_type' => $item['showType'], 'en_title' => $item['titles']['en_jp'],
'episode_count' => $item['episodeCount'], 'jp_title' => $item['titles']['ja_jp'],
'episode_length' => $item['episodeLength'], 'cover_image' => $item['posterImage']['small'],
'synopsis' => $item['synopsis'], 'show_type' => $item['showType'],
'age_rating' => $item['ageRating'], 'episode_count' => $item['episodeCount'],
'age_rating_guide' => $item['ageRatingGuide'], 'episode_length' => $item['episodeLength'],
'url' => "https://kitsu.io/anime/{$item['slug']}", 'synopsis' => $item['synopsis'],
'genres' => $item['genres'], 'age_rating' => $item['ageRating'],
]; 'age_rating_guide' => $item['ageRatingGuide'],
} 'url' => "https://kitsu.io/anime/{$item['slug']}",
'genres' => $item['genres'],
];
}
} }

View File

@ -25,7 +25,6 @@ define('SRC_DIR', realpath(__DIR__));
*/ */
class AnimeClient { class AnimeClient {
const HUMMINGBIRD_AUTH_URL = 'https://hummingbird.me/api/v1/users/authenticate';
const KITSU_AUTH_URL = 'https://kitsu.io/api/oauth/token'; const KITSU_AUTH_URL = 'https://kitsu.io/api/oauth/token';
const SESSION_SEGMENT = 'Aviat\AnimeClient\Auth'; const SESSION_SEGMENT = 'Aviat\AnimeClient\Auth';
const DEFAULT_CONTROLLER_NAMESPACE = 'Aviat\AnimeClient\Controller'; const DEFAULT_CONTROLLER_NAMESPACE = 'Aviat\AnimeClient\Controller';

View File

@ -97,7 +97,7 @@ class Controller {
$this->response = $container->get('response'); $this->response = $container->get('response');
$this->base_data['url'] = $auraUrlGenerator; $this->base_data['url'] = $auraUrlGenerator;
$this->base_data['urlGenerator'] = $urlGenerator; $this->base_data['urlGenerator'] = $urlGenerator;
// $this->base_data['auth'] = $container->get('auth'); $this->base_data['auth'] = $container->get('auth');
$this->base_data['config'] = $this->config; $this->base_data['config'] = $this->config;
$this->urlGenerator = $urlGenerator; $this->urlGenerator = $urlGenerator;

View File

@ -17,6 +17,7 @@
namespace Aviat\AnimeClient\Controller; namespace Aviat\AnimeClient\Controller;
use Aviat\AnimeClient\Controller as BaseController; use Aviat\AnimeClient\Controller as BaseController;
use Aviat\AnimeClient\API\Kitsu;
use Aviat\AnimeClient\API\Kitsu\Enum\AnimeWatchingStatus; use Aviat\AnimeClient\API\Kitsu\Enum\AnimeWatchingStatus;
use Aviat\AnimeClient\API\Kitsu\Transformer\AnimeListTransformer; use Aviat\AnimeClient\API\Kitsu\Transformer\AnimeListTransformer;
use Aviat\Ion\Di\ContainerInterface; use Aviat\Ion\Di\ContainerInterface;
@ -106,7 +107,7 @@ class Anime extends BaseController {
]; ];
$data = ($type !== 'all') $data = ($type !== 'all')
? $this->model->get_list($model_map[$type]) ? $this->model->getList($model_map[$type])
: $this->model->get_all_lists(); : $this->model->get_all_lists();
$this->outputHTML('anime/' . $view_map[$view], [ $this->outputHTML('anime/' . $view_map[$view], [
@ -122,17 +123,13 @@ class Anime extends BaseController {
*/ */
public function add_form() public function add_form()
{ {
$raw_status_list = AnimeWatchingStatus::getConstList(); $statuses = [
AnimeWatchingStatus::WATCHING => 'Currently Watching',
$statuses = []; AnimeWatchingStatus::PLAN_TO_WATCH => 'Plan to Watch',
AnimeWatchingStatus::ON_HOLD => 'On Hold',
foreach ($raw_status_list as $status_item) AnimeWatchingStatus::DROPPED => 'Dropped',
{ AnimeWatchingStatus::COMPLETED => 'Completed'
$statuses[$status_item] = (string) $this->string($status_item) ];
->underscored()
->humanize()
->titleize();
}
$this->set_session_redirect(); $this->set_session_redirect();
$this->outputHTML('anime/add', [ $this->outputHTML('anime/add', [
@ -180,7 +177,7 @@ class Anime extends BaseController {
*/ */
public function edit($id, $status = "all") public function edit($id, $status = "all")
{ {
$item = $this->model->get_library_item($id, $status); $item = $this->model->getLibraryItem($id, $status);
$raw_status_list = AnimeWatchingStatus::getConstList(); $raw_status_list = AnimeWatchingStatus::getConstList();
$statuses = []; $statuses = [];
@ -199,7 +196,7 @@ class Anime extends BaseController {
'title' => $this->config->get('whose_list') . 'title' => $this->config->get('whose_list') .
"'s Anime List &middot; Edit", "'s Anime List &middot; Edit",
'item' => $item, 'item' => $item,
'statuses' => $statuses, 'statuses' => Kitsu::getStatusToSelectMap(),
'action' => $this->container->get('url-generator') 'action' => $this->container->get('url-generator')
->url('/anime/update_form'), ->url('/anime/update_form'),
]); ]);
@ -293,7 +290,7 @@ class Anime extends BaseController {
*/ */
public function details($anime_id) public function details($anime_id)
{ {
$data = $this->model->get_anime($anime_id); $data = $this->model->getAnime($anime_id);
$this->outputHTML('anime/details', [ $this->outputHTML('anime/details', [
'title' => 'Anime &middot ' . $data['title'], 'title' => 'Anime &middot ' . $data['title'],

View File

@ -86,8 +86,8 @@ class Manga extends Controller {
]; ];
$data = ($status !== 'all') $data = ($status !== 'all')
? [$map[$status] => $this->model->get_list($map[$status]) ] ? [$map[$status] => $this->model->getList($map[$status]) ]
: $this->model->get_list('All'); : $this->model->getList('All');
$this->outputHTML('manga/' . $view_map[$view], [ $this->outputHTML('manga/' . $view_map[$view], [
'title' => $title, 'title' => $title,
@ -261,7 +261,7 @@ class Manga extends Controller {
*/ */
public function details($manga_id) public function details($manga_id)
{ {
$data = $this->model->get_manga($manga_id); $data = $this->model->getManga($manga_id);
$this->outputHTML('manga/details', [ $this->outputHTML('manga/details', [
'title' => 'Manga &middot; ' . $data['title'], 'title' => 'Manga &middot; ' . $data['title'],

View File

@ -63,7 +63,7 @@ class API extends Model {
* @param string $sort_key * @param string $sort_key
* @return void * @return void
*/ */
protected function sort_by_name(array &$array, string $sort_key) protected function sortByName(array &$array, string $sort_key)
{ {
$sort = []; $sort = [];

View File

@ -19,7 +19,6 @@ use Aviat\AnimeClient\API\Kitsu\Enum\AnimeWatchingStatus;
use Aviat\Ion\Di\ContainerInterface; use Aviat\Ion\Di\ContainerInterface;
use Aviat\Ion\Json; use Aviat\Ion\Json;
/** /**
* Model for handling requests dealing with the anime list * Model for handling requests dealing with the anime list
*/ */
@ -60,10 +59,10 @@ class Anime extends API {
* @param string $status * @param string $status
* @return array * @return array
*/ */
public function get_list($status) public function getList($status)
{ {
$data = $this->kitsuModel->getAnimeList($status); $data = $this->kitsuModel->getAnimeList($status);
$this->sort_by_name($data, 'anime'); $this->sortByName($data, 'anime');
$output = []; $output = [];
$output[$this->const_map[$status]] = $data; $output[$this->const_map[$status]] = $data;
@ -77,9 +76,33 @@ class Anime extends API {
* @param string $anime_id * @param string $anime_id
* @return array * @return array
*/ */
public function get_anime($anime_id) public function getAnime($anime_id)
{ {
return $this->kitsuModel->getAnime($anime_id); return $this->kitsuModel->getAnime($anime_id);
}
/**
* Get information about a specific list item
* for editing/updating that item
*
* @param string $itemId
* @return array
*/
public function getLibraryItem(string $itemId): array
{
return $this->kitsuModel->getListItem($itemId);
}
/**
* Search for anime by name
*
* @param string $name
* @return array
*/
public function search($name)
{
$raw = $this->kitsuModel->search('anime', $name);
return $this->kitsuModel->search('anime', $name);
} }
} }
// End of AnimeModel.php // End of AnimeModel.php

View File

@ -18,6 +18,7 @@ namespace Aviat\AnimeClient\Model;
use Aviat\Ion\Di\ContainerInterface; use Aviat\Ion\Di\ContainerInterface;
use Aviat\Ion\Json; use Aviat\Ion\Json;
use PDO;
/** /**
* Model for getting anime collection data * Model for getting anime collection data
@ -76,7 +77,7 @@ class AnimeCollection extends Collection {
->from('media') ->from('media')
->get(); ->get();
foreach ($query->fetchAll(\PDO::FETCH_ASSOC) as $row) foreach ($query->fetchAll(PDO::FETCH_ASSOC) as $row)
{ {
$output[$row['id']] = $row['type']; $output[$row['id']] = $row['type'];
} }
@ -96,7 +97,7 @@ class AnimeCollection extends Collection {
->where('hummingbird_id', (int)$id) ->where('hummingbird_id', (int)$id)
->get(); ->get();
return $query->fetch(\PDO::FETCH_ASSOC); return $query->fetch(PDO::FETCH_ASSOC);
} }
/** /**
@ -119,7 +120,7 @@ class AnimeCollection extends Collection {
->order_by('title') ->order_by('title')
->get(); ->get();
return $query->fetchAll(\PDO::FETCH_ASSOC); return $query->fetchAll(PDO::FETCH_ASSOC);
} }
/** /**
@ -208,7 +209,7 @@ class AnimeCollection extends Collection {
->where('hummingbird_id', $hummingbird_id) ->where('hummingbird_id', $hummingbird_id)
->get(); ->get();
return $query->fetch(\PDO::FETCH_ASSOC); return $query->fetch(PDO::FETCH_ASSOC);
} }
/** /**
@ -313,7 +314,7 @@ class AnimeCollection extends Collection {
$query = $this->db->select('id, genre') $query = $this->db->select('id, genre')
->from('genres') ->from('genres')
->get(); ->get();
foreach ($query->fetchAll(\PDO::FETCH_ASSOC) as $genre) foreach ($query->fetchAll(PDO::FETCH_ASSOC) as $genre)
{ {
$genres[$genre['id']] = $genre['genre']; $genres[$genre['id']] = $genre['genre'];
} }
@ -322,7 +323,7 @@ class AnimeCollection extends Collection {
$query = $this->db->select('hummingbird_id, genre_id') $query = $this->db->select('hummingbird_id, genre_id')
->from('genre_anime_set_link') ->from('genre_anime_set_link')
->get(); ->get();
foreach ($query->fetchAll(\PDO::FETCH_ASSOC) as $link) foreach ($query->fetchAll(PDO::FETCH_ASSOC) as $link)
{ {
if (array_key_exists($link['hummingbird_id'], $links)) if (array_key_exists($link['hummingbird_id'], $links))
{ {

View File

@ -18,6 +18,7 @@ namespace Aviat\AnimeClient\Model;
use Aviat\Ion\Di\ContainerInterface; use Aviat\Ion\Di\ContainerInterface;
use Aviat\Ion\Model\DB; use Aviat\Ion\Model\DB;
use PDOException;
/** /**
* Base model for anime and manga collections * Base model for anime and manga collections
@ -49,7 +50,7 @@ class Collection extends DB {
{ {
$this->db = \Query($this->db_config['collection']); $this->db = \Query($this->db_config['collection']);
} }
catch (\PDOException $e) catch (PDOException $e)
{ {
$this->valid_database = FALSE; $this->valid_database = FALSE;
return FALSE; return FALSE;
@ -102,7 +103,7 @@ class Collection extends DB {
$output = []; $output = [];
foreach ($query->fetchAll(\PDO::FETCH_ASSOC) as $row) foreach ($query->fetchAll(PDO::FETCH_ASSOC) as $row)
{ {
$id = $row['hummingbird_id']; $id = $row['hummingbird_id'];
$genre = $row['genre']; $genre = $row['genre'];

View File

@ -19,14 +19,12 @@ namespace Aviat\AnimeClient\Model;
use Aviat\AnimeClient\API\Kitsu\Enum\MangaReadingStatus; use Aviat\AnimeClient\API\Kitsu\Enum\MangaReadingStatus;
use Aviat\AnimeClient\API\Kitsu\Transformer; use Aviat\AnimeClient\API\Kitsu\Transformer;
use Aviat\Ion\Di\ContainerInterface; use Aviat\Ion\Di\ContainerInterface;
use Aviat\Ion\Json;
use GuzzleHttp\Cookie\SetCookie;
use RuntimeException;
/** /**
* Model for handling requests dealing with the manga list * Model for handling requests dealing with the manga list
*/ */
class Manga extends API { class Manga extends API
{
const READING = 'Reading'; const READING = 'Reading';
const PLAN_TO_READ = 'Plan to Read'; const PLAN_TO_READ = 'Plan to Read';
@ -61,68 +59,26 @@ class Manga extends API {
$this->kitsuModel = $container->get('kitsu-model'); $this->kitsuModel = $container->get('kitsu-model');
} }
/**
* Make an authenticated manga API call
*
* @param string $type - the HTTP verb
* @param string $url
* @param string|null $json
* @return array
*/
protected function _manga_api_call(string $type, string $url, $json = NULL): array
{
$token = $this->container->get('auth')
->get_auth_token();
// Set the token cookie, with the authentication token
// from the auth class.
$cookieJar = $this->cookieJar;
$cookie_data = new SetCookie([
'Name' => 'token',
'Value' => $token,
'Domain' => 'hummingbird.me'
]);
$cookieJar->setCookie($cookie_data);
$config = [
'cookies' => $cookieJar
];
if ( ! is_null($json))
{
$config['json'] = $json;
}
$result = $this->client->request(strtoupper($type), $url, $config);
return [
'statusCode' => $result->getStatusCode(),
'body' => $result->getBody()
];
}
/** /**
* Get a category out of the full list * Get a category out of the full list
* *
* @param string $status * @param string $status
* @return array * @return array
*/ */
public function get_list($status) public function getList($status)
{ {
$APIstatus = array_flip($this->const_map)[$status]; $APIstatus = array_flip($this->const_map)[$status];
$data = $this->kitsuModel->getMangaList($APIstatus); $data = $this->kitsuModel->getMangaList($APIstatus);
return $this->map_by_status($data)[$status]; return $this->mapByStatus($data)[$status];
} }
/** /**
* Get the details of a manga * Get the details of a manga
* *
* @param string $manga_id * @param string $manga_id
* @return array * @return array
*/ */
public function get_manga($manga_id) public function getManga($manga_id)
{ {
return $this->kitsuModel->getManga($manga_id); return $this->kitsuModel->getManga($manga_id);
} }
@ -133,7 +89,7 @@ class Manga extends API {
* @param array $data * @param array $data
* @return array * @return array
*/ */
private function map_by_status($data) private function mapByStatus($data)
{ {
$output = [ $output = [
self::READING => [], self::READING => [],
@ -143,35 +99,16 @@ class Manga extends API {
self::COMPLETED => [], self::COMPLETED => [],
]; ];
$util = $this->container->get('util'); foreach ($data as &$entry) {
foreach ($data as &$entry)
{
/*$entry['manga']['image'] = $util->get_cached_image(
$entry['manga']['image'],
$entry['manga']['slug'],
'manga'
);*/
$key = $this->status_map[$entry['reading_status']]; $key = $this->status_map[$entry['reading_status']];
$output[$key][] = $entry; $output[$key][] = $entry;
} }
foreach($output as &$val) foreach ($output as &$val) {
{ $this->sortByName($val, 'manga');
$this->sort_by_name($val, 'manga');
} }
return $output; return $output;
} }
/**
* Combine the two manga lists into one
* @param array $raw_data
* @return array
*/
private function zipperLists($raw_data)
{
return (new Transformer\MangaListsZipper($raw_data))->transform();
}
} }
// End of MangaModel.php // End of MangaModel.php