Remove Shikimori API, use AnimeThemes only, switch to WebM format

- Remove ShikimoriService, use AnimeThemes API for search
- Replace shikimori_id with animethemes_slug as primary identifier
- Remove FFmpeg MP3 conversion, download WebM directly
- Add .webm support in storage and upload endpoints
- Update frontend to use animethemes_slug

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-01-12 11:22:46 +03:00
parent 333de65fbd
commit cc11f0b773
12 changed files with 138 additions and 263 deletions

View File

@@ -58,20 +58,20 @@
<div class="results-grid">
<div
v-for="anime in searchResults"
:key="anime.shikimori_id"
:key="anime.animethemes_slug"
class="anime-card"
:class="{ selected: selectedAnime?.shikimori_id === anime.shikimori_id }"
@click="selectAnime(anime.shikimori_id)"
:class="{ selected: selectedAnime?.animethemes_slug === anime.animethemes_slug }"
@click="selectAnime(anime.animethemes_slug)"
>
<img
v-if="anime.poster_url"
:src="anime.poster_url"
:alt="anime.title_russian || anime.title_english"
:alt="anime.title_english"
class="anime-poster"
/>
<div v-else class="anime-poster placeholder">No Image</div>
<div class="anime-info">
<div class="anime-title">{{ anime.title_russian || anime.title_english }}</div>
<div class="anime-title">{{ anime.title_english }}</div>
<div class="anime-year" v-if="anime.year">{{ anime.year }}</div>
</div>
</div>
@@ -94,8 +94,7 @@
class="detail-poster"
/>
<div class="detail-info">
<h2>{{ selectedAnime.title_russian || selectedAnime.title_english }}</h2>
<p v-if="selectedAnime.title_japanese" class="japanese-title">{{ selectedAnime.title_japanese }}</p>
<h2>{{ selectedAnime.title_english }}</h2>
<p v-if="selectedAnime.year" class="year-info">Year: {{ selectedAnime.year }}</p>
</div>
</div>
@@ -247,12 +246,12 @@ async function searchAnime() {
}
}
async function selectAnime(shikimoriId) {
async function selectAnime(slug) {
loadingDetail.value = true
selectedAnime.value = null
try {
const response = await fetch(`/api/downloader/anime/${shikimoriId}`)
const response = await fetch(`/api/downloader/anime/${slug}`)
const data = await response.json()
selectedAnime.value = data
} catch (error) {
@@ -274,7 +273,7 @@ async function addToQueue(themeIds) {
Object.assign(queueStatus, data)
// Refresh selected anime to update statuses
if (selectedAnime.value) {
await selectAnime(selectedAnime.value.shikimori_id)
await selectAnime(selectedAnime.value.animethemes_slug)
}
} else {
alert(data.detail || 'Failed to add to queue')
@@ -296,7 +295,7 @@ async function addAllToQueue() {
const data = await response.json()
if (response.ok) {
Object.assign(queueStatus, data)
await selectAnime(selectedAnime.value.shikimori_id)
await selectAnime(selectedAnime.value.animethemes_slug)
} else {
alert(data.detail || 'Failed to add all to queue')
}
@@ -361,8 +360,8 @@ async function refreshStorage() {
async function refreshAll() {
await Promise.all([refreshQueue(), refreshStorage()])
// Also refresh selected anime if any
if (selectedAnime.value?.shikimori_id) {
const response = await fetch(`/api/downloader/anime/${selectedAnime.value.shikimori_id}`)
if (selectedAnime.value?.animethemes_slug) {
const response = await fetch(`/api/downloader/anime/${selectedAnime.value.animethemes_slug}`)
if (response.ok) {
selectedAnime.value = await response.json()
}