完全に自己満足の世界だけど、ブログのサイドバーに今期もしくは現在視聴しているアニメの一覧を表示させてみました。視聴作品の管理にはAnnictを利用しています。
コード自体はGeminiに書かせたのだけれども、ハルシネーションがひどく、勝手に関数を捏造するし、存在しないAPIを叩き続けるしで、ハルシネーションがなくなって完成するまでに半日を要しました。これで課金しているPROモードなのだから、無料の高速モードだったら何日かかった事やら。
全話数のうち何話まで視聴したのかを表示させています。また、視聴済みの作品は話数を表示せずに、視聴済みのブロックに追い出しています。
以下のコードで動かしているので誰かの参考になれば。
function get_annict_status_rebuilt_from_zero() {
// キャッシュキーの定義
$cache_key = 'annict_status_display_html';
// 1. キャッシュの取得を試行
$cached_html = get_transient($cache_key);
if ($cached_html !== false) {
return $cached_html;
}
// 【警告】このアクセストークンは外部に公開しないでください
$access_token = 'ここにアクセストークンを書く';
$url = 'https://api.annict.com/graphql';
$query = '
query {
viewer {
watching: libraryEntries(states: [WATCHING]) {
nodes {
work {
annictId
title
episodesCount
episodes {
nodes {
viewerDidTrack
}
}
}
}
}
watched: libraryEntries(states: [WATCHED]) {
nodes {
work {
annictId
title
episodesCount
episodes {
nodes {
viewerDidTrack
}
}
}
}
}
}
}';
$response = wp_remote_post($url, [
'headers' => [
'Authorization' => 'Bearer ' . $access_token,
'Content-Type' => 'application/json',
],
'body' => json_encode(['query' => $query]),
'timeout' => 30,
]);
// エラー時はキャッシュせず空文字を返す
if (is_wp_error($response)) return '';
$body = json_decode(wp_remote_retrieve_body($response), true);
if (isset($body['errors']) || !isset($body['data']['viewer'])) return '';
$data = $body['data']['viewer'];
$html = '<div class="annict-container" style="font-family: sans-serif; max-width: 100%;">';
foreach (['watching' => '視聴中', 'watched' => '視聴済み'] as $key => $label) {
$header_bg = ($key === 'watching') ? '#2b4b91' : '#546e7a';
$border_color = ($key === 'watching') ? '#2b4b91' : '#546e7a';
$html .= sprintf(
'<div class="annict-section" style="margin-bottom: 20px; border: 1px solid %s; border-radius: 12px; overflow: hidden; background: #fff; box-shadow: 0 2px 5px rgba(0,0,0,0.05);">',
$border_color
);
$html .= sprintf(
'<h3 style="margin: 0; padding: 12px 16px; background-color: %s; color: #fff; font-size: 1rem; border: none;">%s</h3>',
$header_bg,
$label
);
$html .= '<ul style="list-style: none; padding: 10px 16px; margin: 0;">';
$nodes = $data[$key]['nodes'] ?? [];
if (empty($nodes)) {
$html .= '<li style="padding: 8px 0; color: #666;">該当なし</li>';
} else {
foreach ($nodes as $node) {
$work = $node['work'];
$title = esc_html($work['title']);
$total = (int)$work['episodesCount'];
$episode_nodes = $work['episodes']['nodes'] ?? [];
$watched_count = 0;
foreach ($episode_nodes as $ep) {
if (!empty($ep['viewerDidTrack'])) {
$watched_count++;
}
}
$display_count = "";
if ($key === 'watching') {
$display_count = ($total > 0) ? " ({$watched_count}/{$total})" : " ({$watched_count})";
}
$html .= sprintf(
'<li style="padding: 8px 0; border-bottom: 1px solid #eee;">' .
'<a href="https://annict.com/works/%d" target="_blank" rel="noopener" style="text-decoration: none; color: #0066cc; font-weight: bold;">%s%s</a>' .
'</li>',
(int)$work['annictId'],
$title,
esc_html($display_count)
);
}
}
$html .= '</ul></div>';
}
$html .= '</div>';
// 2. 生成されたHTMLをキャッシュに保存(ここでは1時間 = 3600秒)
set_transient($cache_key, $html, HOUR_IN_SECONDS);
return $html;
}
add_shortcode('annict_status', 'get_annict_status_rebuilt_from_zero');


ひとことコメント コメント欄以外は任意入力です