d8bc00808d
- Add MyMemory translation API to MetadataEnricher (free, no key) - Translate English synopses to French after Kitsu enrichment - Remove synopsis truncation (was 200 chars, now shows full text) - Increase CSS line-clamp from 2 to 4 lines
157 lines
10 KiB
HTML
157 lines
10 KiB
HTML
{% set accent = "#00d9ff" %}
|
|
{% set default_lang = settings.default_lang if settings else 'vostfr' %}
|
|
|
|
{% set _groups = namespace(items={}) %}
|
|
{% for pid, items in (results or {}).items() %}
|
|
{% for item in items %}
|
|
{% set _key = item.title | lower | trim %}
|
|
{% if _key not in _groups.items %}
|
|
{% set _ = _groups.items.update({_key: {
|
|
"title": item.title,
|
|
"cover": item.cover_image or (item.metadata.poster_image if item.metadata else "") or "",
|
|
"synopsis": (item.metadata.synopsis if item.metadata and item.metadata.synopsis else "")[:300],
|
|
"rating": item.metadata.rating if item.metadata and item.metadata.rating else "",
|
|
"genres": item.metadata.genres if item.metadata and item.metadata.genres else [],
|
|
"providers": [{ "id": item.provider_id or pid, "url": item.url }]
|
|
}}) %}
|
|
{% else %}
|
|
{% set _existing = _groups.items[_key] %}
|
|
{% if not _existing.cover and item.cover_image %}
|
|
{% set _ = _existing.update({"cover": item.cover_image}) %}
|
|
{% endif %}
|
|
{% if not _existing.synopsis and item.metadata and item.metadata.synopsis %}
|
|
{% set _ = _existing.update({"synopsis": item.metadata.synopsis[:300]}) %}
|
|
{% endif %}
|
|
{% if not _existing.rating and item.metadata and item.metadata.rating %}
|
|
{% set _ = _existing.update({"rating": item.metadata.rating}) %}
|
|
{% endif %}
|
|
{% set _ = _existing["providers"].append({"id": item.provider_id or pid, "url": item.url}) %}
|
|
{% endif %}
|
|
{% endfor %}
|
|
{% endfor %}
|
|
|
|
<div class="sr-list" x-data="{ openDropdown: null }">
|
|
{% if _groups.items.values() | list | length > 0 %}
|
|
{% for group in _groups.items.values() | list %}
|
|
{% set first_url = group.providers[0].url %}
|
|
<div class="sr-card" style="--sr-accent: {{ accent }};">
|
|
<a class="sr-poster-link" href="{{ first_url }}" target="_blank" rel="noopener">
|
|
<img class="sr-poster-img" src="{{ group.cover or 'https://placehold.co/240x360/161625/00d9ff?text=No+Image' }}"
|
|
alt="{{ group.title }}" loading="lazy" referrerpolicy="no-referrer"
|
|
onerror="this.src='https://placehold.co/240x360/161625/00d9ff?text=Error'; this.onerror=null;">
|
|
</a>
|
|
<div class="sr-body">
|
|
<div class="sr-top">
|
|
<h3 class="sr-title">{{ group.title }}</h3>
|
|
{% if group.rating %}
|
|
<span class="sr-rating"><i class="fas fa-star"></i> {{ group.rating }}</span>
|
|
{% endif %}
|
|
</div>
|
|
|
|
{% if group.synopsis %}
|
|
<p class="sr-synopsis">{{ group.synopsis }}</p>
|
|
{% endif %}
|
|
|
|
{% if group.genres %}
|
|
<div class="sr-tags">
|
|
{% for g in group.genres[:5] %}
|
|
<span class="sr-tag">{{ g }}</span>
|
|
{% endfor %}
|
|
</div>
|
|
{% endif %}
|
|
|
|
<div class="sr-providers">
|
|
{% for p in group.providers %}
|
|
<a class="sr-provider-badge" href="{{ p.url }}" target="_blank" rel="noopener">{{ p.id | upper }}</a>
|
|
{% endfor %}
|
|
</div>
|
|
|
|
<div class="sr-actions">
|
|
<a class="sr-btn sr-btn-watch" href="{{ first_url }}" target="_blank" rel="noopener">
|
|
<i class="fas fa-play"></i> Regarder
|
|
</a>
|
|
<div class="sr-dropdown" @click.outside="openDropdown = null">
|
|
<button class="sr-btn sr-btn-dl" @click="openDropdown = (openDropdown === '{{ first_url | urlencode }}') ? null : '{{ first_url | urlencode }}'">
|
|
<i class="fas fa-download"></i> Telecharger <i class="fas fa-chevron-down" style="font-size:0.6rem;margin-left:4px;"></i>
|
|
</button>
|
|
<div class="sr-dropdown-menu" x-show="openDropdown === '{{ first_url | urlencode }}'" x-transition>
|
|
<button class="sr-dropdown-item"
|
|
hx-post="/api/anime/download-season?url={{ first_url | urlencode }}&lang={{ default_lang }}"
|
|
hx-swap="none"
|
|
hx-on::after-request="openDropdown = null">
|
|
<i class="fas fa-layer-group"></i> Saison complete
|
|
</button>
|
|
<button class="sr-dropdown-item"
|
|
hx-get="/api/anime/episodes?url={{ first_url | urlencode }}&lang={{ default_lang }}"
|
|
hx-target="#dl-episodes-{{ loop.index }}"
|
|
hx-swap="innerHTML"
|
|
hx-on::after-request="openDropdown = null">
|
|
<i class="fas fa-list-ol"></i> Choisir des episodes
|
|
</button>
|
|
<div id="dl-episodes-{{ loop.index }}"></div>
|
|
</div>
|
|
</div>
|
|
<button class="sr-btn sr-btn-follow"
|
|
hx-post="/api/watchlist"
|
|
hx-vals='{"anime_url": "{{ first_url }}", "anime_title": "{{ group.title }}", "provider_id": "{{ group.providers[0].id }}", "lang": "{{ default_lang }}"}'
|
|
hx-swap="none"
|
|
hx-on::after-request="if(event.detail.successful){this.innerHTML='<i class=\'fas fa-check\'></i> Suivi';this.disabled=true;this.classList.add('sr-btn-followed')}">
|
|
<i class="fas fa-plus"></i> Suivre
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
{% else %}
|
|
<div class="sr-empty">
|
|
<i class="fas fa-search"></i>
|
|
<p>Aucun anime trouve pour votre recherche.</p>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<style>
|
|
.sr-list { display: flex; flex-direction: column; gap: 16px; }
|
|
.sr-card {
|
|
display: flex; gap: 20px;
|
|
background: var(--bg-card); border-radius: var(--card-radius);
|
|
padding: 20px; border: 1px solid rgba(255,255,255,0.05);
|
|
transition: var(--transition);
|
|
}
|
|
.sr-card:hover { border-color: var(--sr-accent); box-shadow: 0 4px 24px rgba(0,0,0,0.4); }
|
|
.sr-poster-link { flex-shrink: 0; display: block; width: 120px; aspect-ratio: 2/3; border-radius: 8px; overflow: hidden; background: #000; }
|
|
.sr-poster-img { width: 100%; height: 100%; object-fit: cover; display: block; }
|
|
.sr-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 8px; }
|
|
.sr-top { display: flex; align-items: baseline; gap: 12px; }
|
|
.sr-title { font-size: 1.1rem; font-weight: 700; margin: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
.sr-rating { flex-shrink: 0; font-size: 0.8rem; font-weight: 700; color: #ffcc00; }
|
|
.sr-synopsis { font-size: 0.85rem; color: var(--text-dim); margin: 0; display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden; }
|
|
.sr-tags { display: flex; flex-wrap: wrap; gap: 4px; margin: 0; }
|
|
.sr-tag { font-size: 0.65rem; font-weight: 600; padding: 2px 8px; border-radius: 4px; background: rgba(255,255,255,0.06); color: var(--text-dim); }
|
|
.sr-providers { display: flex; flex-wrap: wrap; gap: 6px; }
|
|
.sr-provider-badge { font-size: 0.7rem; font-weight: 700; text-transform: uppercase; padding: 4px 12px; border-radius: 20px; border: 1px solid var(--sr-accent); color: var(--sr-accent); background: transparent; cursor: pointer; transition: var(--transition); letter-spacing: 0.5px; text-decoration: none; }
|
|
.sr-provider-badge:hover { background: var(--sr-accent); color: var(--bg-dark); }
|
|
.sr-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 4px; }
|
|
.sr-btn { display: inline-flex; align-items: center; gap: 6px; padding: 8px 16px; border-radius: 8px; font-size: 0.8rem; font-weight: 600; border: 1px solid rgba(255,255,255,0.1); cursor: pointer; transition: var(--transition); text-decoration: none; background: transparent; color: var(--text-main); }
|
|
.sr-btn:hover { border-color: rgba(255,255,255,0.2); background: rgba(255,255,255,0.05); }
|
|
.sr-btn-watch { border-color: var(--sr-accent); color: var(--sr-accent); }
|
|
.sr-btn-watch:hover { background: var(--sr-accent); color: var(--bg-dark); }
|
|
.sr-btn-follow { border-color: var(--accent); color: var(--accent); }
|
|
.sr-btn-follow:hover { background: var(--accent); color: var(--bg-dark); }
|
|
.sr-btn-followed { border-color: var(--accent); color: var(--accent); background: rgba(0,255,136,0.1); pointer-events: none; }
|
|
.sr-dropdown { position: relative; }
|
|
.sr-dropdown-menu { position: absolute; top: calc(100% + 6px); left: 0; min-width: 200px; background: var(--bg-card); border: 1px solid rgba(255,255,255,0.1); border-radius: 8px; padding: 4px; z-index: 100; box-shadow: 0 8px 32px rgba(0,0,0,0.6); }
|
|
.sr-dropdown-item { display: flex; align-items: center; gap: 8px; width: 100%; padding: 10px 12px; border: none; background: transparent; color: var(--text-main); font-size: 0.8rem; cursor: pointer; border-radius: 6px; transition: var(--transition); text-align: left; }
|
|
.sr-dropdown-item:hover { background: rgba(255,255,255,0.06); }
|
|
.sr-empty { text-align: center; padding: 100px 20px; color: var(--text-dim); }
|
|
.sr-empty i { font-size: 4rem; margin-bottom: 20px; display: block; opacity: 0.2; }
|
|
@media (max-width: 768px) {
|
|
.sr-card { flex-direction: column; align-items: center; text-align: center; gap: 12px; padding: 16px; }
|
|
.sr-poster-link { width: 160px; }
|
|
.sr-top { justify-content: center; }
|
|
.sr-tags { justify-content: center; }
|
|
.sr-providers { justify-content: center; }
|
|
.sr-actions { justify-content: center; }
|
|
}
|
|
</style>
|