*/ public function getAnimeList(string $letter = '', string $animeTitle = ''): array { $rsql = $tsql = ''; if ($letter !== '') { if ($letter === '0-9') { $letter = '[0-9]'; } $rsql .= sprintf('AND at.title REGEXP %s', escapeString('^'.$letter)); } if ($animeTitle !== '') { $tsql .= sprintf('AND at.title LIKE %s', escapeString('%'.$animeTitle.'%')); } return DB::select( sprintf( ' SELECT at.anidbid, at.title, ai.type, ai.categories, ai.rating, ai.startdate, ai.enddate FROM anidb_titles at LEFT JOIN anidb_info ai USING (anidbid) STRAIGHT_JOIN releases r ON at.anidbid = r.anidbid WHERE at.anidbid > 0 %s %s AND r.categories_id = %d GROUP BY at.anidbid ORDER BY at.title ASC', $rsql, $tsql, Category::TV_ANIME ) ); } /** * Retrieves a range of Anime titles for site display. */ public function getAnimeRange(string $animeTitle = ''): LengthAwarePaginator // @phpstan-ignore missingType.generics { $query = AnidbTitle::query() ->where('at.lang', '=', 'en'); if ($animeTitle !== '') { $query->where('at.title', 'like', '%'.$animeTitle.'%'); } $query->select(['at.anidbid', DB::raw("GROUP_CONCAT(at.title SEPARATOR ', ') AS title"), 'ai.description']) ->from('anidb_titles as at') ->leftJoin('anidb_info as ai', 'ai.anidbid', '=', 'at.anidbid') ->groupBy('at.anidbid') ->orderByDesc('at.anidbid'); return $query->paginate(config('nntmux.items_per_page')); } /** * Retrieves all info for a specific AniDB ID. * Note: AniList doesn't support episodes, so episode data is not included. */ public function getAnimeInfo(?int $anidbID): mixed { if ($anidbID === null || $anidbID <= 0) { return null; } // Get main info with primary title (prefer English, fallback to any) $animeInfo = DB::select( sprintf( ' SELECT at.anidbid, at.lang, at.title, ai.anilist_id, ai.mal_id, ai.country, ai.media_type, ai.episodes, ai.duration, ai.status, ai.source, ai.hashtag, ai.startdate, ai.enddate, ai.updated, ai.related, ai.creators, ai.description, ai.rating, ai.picture, ai.categories, ai.characters, ai.type, ai.similar FROM anidb_titles AS at LEFT JOIN anidb_info AS ai USING (anidbid) WHERE at.anidbid = %d ORDER BY CASE WHEN at.lang = "en" THEN 1 WHEN at.lang = "x-jat" THEN 2 ELSE 3 END LIMIT 1', $anidbID ) ); $result = $animeInfo[0] ?? false; if ($result) { // Get English title separately $englishTitle = DB::selectOne( sprintf( ' SELECT title FROM anidb_titles WHERE anidbid = %d AND lang = "en" LIMIT 1', $anidbID ) ); // Get native title (prefer ja, then x-jat, then any non-English title) $nativeTitle = DB::selectOne( sprintf( ' SELECT title, lang FROM anidb_titles WHERE anidbid = %d AND lang NOT IN ("en") ORDER BY CASE WHEN lang = "ja" THEN 1 WHEN lang = "x-jat" THEN 2 ELSE 3 END LIMIT 1', $anidbID ) ); // Get romaji title separately $romajiTitle = DB::selectOne( sprintf( ' SELECT title, lang FROM anidb_titles WHERE anidbid = %d AND lang = "x-jat" LIMIT 1', $anidbID ) ); // If we found a native title, use it; otherwise use romaji as original $originalTitle = $nativeTitle; if (! $originalTitle && $romajiTitle) { $originalTitle = $romajiTitle; } // Add titles to result if ($englishTitle && isset($englishTitle->title)) { $result->english_title = $englishTitle->title; } else { $result->english_title = null; } if ($originalTitle && isset($originalTitle->title)) { $result->original_title = $originalTitle->title; $result->original_lang = $originalTitle->lang; } else { $result->original_title = null; $result->original_lang = null; } // Add romaji title separately (even if it's also the original) if ($romajiTitle && isset($romajiTitle->title)) { $result->romaji_title = $romajiTitle->title; } else { $result->romaji_title = null; } } return $result; } }