chore: update watchlist features and fixes
This commit is contained in:
@@ -242,6 +242,16 @@ function switchTab(tabName) {
|
||||
loadHomeContent();
|
||||
}
|
||||
}
|
||||
|
||||
// Load watchlist content when switching to watchlist tab
|
||||
if (tabName === 'watchlist') {
|
||||
if (typeof loadSchedulerStatus === 'function') {
|
||||
loadSchedulerStatus();
|
||||
}
|
||||
if (typeof displayWatchlist === 'function') {
|
||||
displayWatchlist();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+38
-16
@@ -2,6 +2,16 @@
|
||||
* Watchlist UI functions
|
||||
*/
|
||||
|
||||
/**
|
||||
* Escape HTML to prevent XSS
|
||||
*/
|
||||
function escapeHtml(text) {
|
||||
if (!text) return '';
|
||||
const div = document.createElement('div');
|
||||
div.textContent = text;
|
||||
return div.innerHTML;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display watchlist items
|
||||
*/
|
||||
@@ -21,8 +31,6 @@ async function displayWatchlist(status = null) {
|
||||
<div style="text-align: center; padding: 60px 20px;">
|
||||
<svg style="width:80px;height:80px;margin:0 auto 20px;opacity:0.3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path>
|
||||
</svg>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1" d="M15 17h5l-1.405-1.405A2.032 2.032 0 018.138 7.702 10.78 1.478 1.482-1.478-10.78-1.478 1.478-8.138 1.478-1.478 1.478-1.478-8.138 1.478-1.478 1.478-8.138 1.478z"></path>
|
||||
</svg>
|
||||
<h3 style="color: #666; margin-bottom: 10px;">Aucun anime dans votre watchlist</h3>
|
||||
<p style="color: #999;">Ajoutez des animes depuis la recherche pour commencer le suivi automatique</p>
|
||||
@@ -103,7 +111,7 @@ async function displayWatchlist(status = null) {
|
||||
</button>
|
||||
` : ''}
|
||||
|
||||
<button class="btn-secondary btn-small" onclick="handleCheckItem('${item.id}')" style="padding: 6px 12px; font-size: 12px;" title="Vérifier maintenant">
|
||||
<button class="btn-secondary btn-small" onclick="handleCheckItem.call(this, '${item.id}')" style="padding: 6px 12px; font-size: 12px;" title="Vérifier maintenant">
|
||||
🔍 Vérifier
|
||||
</button>
|
||||
|
||||
@@ -166,8 +174,16 @@ function getStatusBadge(status) {
|
||||
*/
|
||||
async function handleAddToWatchlist(animeUrl, providerId) {
|
||||
try {
|
||||
// Decode URL if it's encoded - always work with decoded URL
|
||||
let decodedUrl = animeUrl;
|
||||
try {
|
||||
decodedUrl = decodeURIComponent(animeUrl);
|
||||
} catch (e) {
|
||||
// URL might already be decoded
|
||||
}
|
||||
|
||||
// Get anime details from the DOM or API
|
||||
const response = await fetch(`${API_BASE}/anime/metadata?url=${encodeURIComponent(animeUrl)}`);
|
||||
const response = await fetch(`${API_BASE}/anime/metadata?url=${encodeURIComponent(decodedUrl)}`);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch anime details');
|
||||
@@ -179,12 +195,6 @@ async function handleAddToWatchlist(animeUrl, providerId) {
|
||||
// Extract anime title from URL if not in metadata
|
||||
let animeTitle = metadata.title || 'Unknown Anime';
|
||||
if (animeTitle === 'Unknown Anime' || !animeTitle) {
|
||||
// Decode URL first if it's encoded
|
||||
let decodedUrl = animeUrl;
|
||||
try {
|
||||
decodedUrl = decodeURIComponent(animeUrl);
|
||||
} catch (e) {}
|
||||
|
||||
// Try to extract title from URL
|
||||
try {
|
||||
const urlParts = decodedUrl.split('/');
|
||||
@@ -204,10 +214,16 @@ async function handleAddToWatchlist(animeUrl, providerId) {
|
||||
}
|
||||
}
|
||||
|
||||
// Normalize provider_id to use dash format (anime-sama not animesama)
|
||||
let normalizedProviderId = providerId;
|
||||
if (providerId === 'animesama') {
|
||||
normalizedProviderId = 'anime-sama';
|
||||
}
|
||||
|
||||
const itemData = {
|
||||
anime_title: animeTitle,
|
||||
anime_url: animeUrl,
|
||||
provider_id: providerId,
|
||||
anime_url: decodedUrl, // Always use decoded URL
|
||||
provider_id: normalizedProviderId,
|
||||
lang: 'vostfr',
|
||||
auto_download: true,
|
||||
quality_preference: 'auto',
|
||||
@@ -255,8 +271,14 @@ async function handleAddToWatchlist(animeUrl, providerId) {
|
||||
* Update add button state
|
||||
*/
|
||||
function updateAddButton(animeUrl, isInWatchlist) {
|
||||
// Find all buttons for this anime
|
||||
const buttons = document.querySelectorAll(`[data-watchlist-url="${encodeURIComponent(animeUrl)}"]`);
|
||||
// Decode URL for matching
|
||||
let decodedUrl = animeUrl;
|
||||
try {
|
||||
decodedUrl = decodeURIComponent(animeUrl);
|
||||
} catch (e) {}
|
||||
|
||||
// Find all buttons for this anime (try both encoded and decoded)
|
||||
const buttons = document.querySelectorAll(`[data-watchlist-url="${encodeURIComponent(decodedUrl)}"], [data-watchlist-url="${decodedUrl}"]`);
|
||||
|
||||
buttons.forEach(button => {
|
||||
if (isInWatchlist) {
|
||||
@@ -303,7 +325,7 @@ async function handleResumeWatchlist(itemId) {
|
||||
* Check specific item
|
||||
*/
|
||||
async function handleCheckItem(itemId) {
|
||||
const button = event.target;
|
||||
const button = this;
|
||||
const originalText = button.innerHTML;
|
||||
|
||||
try {
|
||||
@@ -351,7 +373,7 @@ async function handleDeleteWatchlist(itemId) {
|
||||
* Check all items
|
||||
*/
|
||||
async function handleCheckAll() {
|
||||
const button = event.target;
|
||||
const button = this;
|
||||
const originalText = button.innerHTML;
|
||||
|
||||
try {
|
||||
|
||||
+15
-5
@@ -425,19 +425,29 @@ function updateSchedulerUI(status) {
|
||||
const stopBtn = document.getElementById('stopSchedulerBtn');
|
||||
const nextRunInfo = document.getElementById('nextRunInfo');
|
||||
|
||||
if (!startBtn || !stopBtn || !nextRunInfo) return;
|
||||
// nextRunInfo is required, but buttons are optional
|
||||
if (!nextRunInfo) {
|
||||
console.warn('nextRunInfo element not found');
|
||||
return;
|
||||
}
|
||||
|
||||
if (status.running) {
|
||||
startBtn.style.display = 'none';
|
||||
stopBtn.style.display = 'inline-block';
|
||||
// Update buttons if they exist
|
||||
if (startBtn) startBtn.style.display = 'none';
|
||||
if (stopBtn) stopBtn.style.display = 'inline-block';
|
||||
|
||||
if (status.next_run) {
|
||||
const nextRun = new Date(status.next_run);
|
||||
nextRunInfo.innerHTML = `✓ En cours<br>Prochaine vérification: ${nextRun.toLocaleString('fr-FR')}`;
|
||||
} else {
|
||||
// Scheduler running but no next_run yet (just started)
|
||||
const interval = status.settings?.check_interval_hours || 6;
|
||||
nextRunInfo.innerHTML = `✓ En cours<br>Vérification toutes les ${interval}h`;
|
||||
}
|
||||
} else {
|
||||
startBtn.style.display = 'inline-block';
|
||||
stopBtn.style.display = 'none';
|
||||
// Update buttons if they exist
|
||||
if (startBtn) startBtn.style.display = 'inline-block';
|
||||
if (stopBtn) stopBtn.style.display = 'none';
|
||||
nextRunInfo.innerHTML = '⏸️ Arrêté';
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user