/** * FavMasToKey - Script JavaScript principal */ // Attendre que le DOM soit chargé document.addEventListener('DOMContentLoaded', function() { // Éléments DOM const uploadForm = document.getElementById('upload-form'); const misskeyForm = document.getElementById('misskey-form'); const jsonFileInput = document.getElementById('json-file'); const step1 = document.getElementById('step1'); const step2 = document.getElementById('step2'); const step3 = document.getElementById('step3'); const fileSummary = document.getElementById('file-summary'); const backToStep1 = document.getElementById('back-to-step1'); const startMigration = document.getElementById('start-migration'); const pauseMigration = document.getElementById('pause-migration'); const cancelMigration = document.getElementById('cancel-migration'); const globalProgress = document.getElementById('global-progress'); const currentProgress = document.getElementById('current-progress'); const operationLog = document.getElementById('operation-log'); // Variables globales let favoritesList = []; let currentIndex = 0; let totalItems = 0; let isProcessing = false; let isPaused = false; // Gérer le téléchargement et l'analyse du fichier JSON if (uploadForm) { uploadForm.addEventListener('submit', function(e) { e.preventDefault(); const file = jsonFileInput.files[0]; if (!file) { alert('Veuillez sélectionner un fichier JSON.'); return; } // Vérifier l'extension du fichier if (!file.name.endsWith('.json')) { alert('Le fichier doit être au format JSON.'); return; } // Lire le fichier const reader = new FileReader(); reader.onload = function(event) { try { const json = JSON.parse(event.target.result); // Vérifier la structure du fichier if (!json['@context'] || !json.type || !json.orderedItems) { alert('Le format du fichier JSON n\'est pas celui attendu pour un export de favoris Mastodon.'); return; } favoritesList = json.orderedItems; totalItems = favoritesList.length; // Afficher un résumé fileSummary.innerHTML = ` <strong>${totalItems}</strong> favoris trouvés dans votre fichier Mastodon. `; // Passer à l'étape 2 step1.classList.add('d-none'); step2.classList.remove('d-none'); // Stocker les données dans localStorage pour les conserver localStorage.setItem('favmastokey_favorites', JSON.stringify(favoritesList)); } catch (error) { alert('Erreur lors de l\'analyse du fichier JSON: ' + error.message); } }; reader.onerror = function() { alert('Erreur lors de la lecture du fichier.'); }; reader.readAsText(file); }); } // Gestion du retour à l'étape 1 if (backToStep1) { backToStep1.addEventListener('click', function() { step2.classList.add('d-none'); step1.classList.remove('d-none'); }); } // Gérer la connexion à Misskey if (misskeyForm) { misskeyForm.addEventListener('submit', function(e) { e.preventDefault(); const instanceInput = document.getElementById('misskey-instance'); let instance = instanceInput.value.trim(); // Vérifier que l'instance est valide if (!instance) { alert('Veuillez entrer l\'URL de votre instance Misskey.'); return; } // Supprimer le protocole et les slash de fin si présents instance = instance.replace(/^https?:\/\//, '').replace(/\/$/, ''); // Vérifier que l'URL semble valide if (!/^[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(instance)) { alert('L\'URL de l\'instance Misskey semble invalide.'); return; } // Rediriger vers l'authentification OAuth window.location.href = `oauth.php?instance=${encodeURIComponent(instance)}`; }); } // Gérer le processus de migration if (startMigration) { startMigration.addEventListener('click', function() { if (isProcessing) return; // Récupérer les favoris depuis localStorage si nécessaire if (favoritesList.length === 0 && localStorage.getItem('favmastokey_favorites')) { favoritesList = JSON.parse(localStorage.getItem('favmastokey_favorites')); totalItems = favoritesList.length; } if (favoritesList.length === 0) { addLogEntry('Aucun favori à migrer. Veuillez d\'abord télécharger votre fichier JSON.', 'error'); return; } // Démarrer la migration isProcessing = true; isPaused = false; startMigration.classList.add('d-none'); pauseMigration.classList.remove('d-none'); addLogEntry('Démarrage de la migration...', 'info'); // Lancer le processus de migration processBatch(); }); } // Gérer la pause de la migration if (pauseMigration) { pauseMigration.addEventListener('click', function() { if (!isProcessing) return; isPaused = !isPaused; if (isPaused) { pauseMigration.textContent = 'Reprendre'; addLogEntry('Migration en pause.', 'warning'); currentProgress.classList.remove('active'); } else { pauseMigration.textContent = 'Pause'; addLogEntry('Reprise de la migration...', 'info'); currentProgress.classList.add('active'); processBatch(); } }); } // Gérer l'annulation de la migration if (cancelMigration) { cancelMigration.addEventListener('click', function() { if (!isProcessing && currentIndex === 0) { // Retour à l'étape 1 si rien n'a commencé step3.classList.add('d-none'); step1.classList.remove('d-none'); return; } const confirmCancel = confirm('Êtes-vous sûr de vouloir annuler la migration en cours ?'); if (confirmCancel) { isProcessing = false; isPaused = false; addLogEntry('Migration annulée.', 'error'); // Réinitialiser l'interface startMigration.classList.remove('d-none'); pauseMigration.classList.add('d-none'); pauseMigration.textContent = 'Pause'; currentProgress.classList.remove('active'); } }); } /** * Traite un lot de favoris */ function processBatch() { if (!isProcessing || isPaused || currentIndex >= totalItems) { if (currentIndex >= totalItems) { // Migration terminée isProcessing = false; addLogEntry('Migration terminée avec succès !', 'success'); startMigration.classList.remove('d-none'); startMigration.textContent = 'Terminer'; startMigration.addEventListener('click', function() { // Nettoyer localStorage et retourner à l'étape 1 localStorage.removeItem('favmastokey_favorites'); step3.classList.add('d-none'); step1.classList.remove('d-none'); }); pauseMigration.classList.add('d-none'); // Mettre à jour la progression à 100% updateProgress(100); } return; } // Nombre d'éléments à traiter dans ce lot const batchSize = 5; const endIndex = Math.min(currentIndex + batchSize, totalItems); // Préparer les éléments du lot const batch = favoritesList.slice(currentIndex, endIndex); // Mettre à jour la progression actuelle currentProgress.classList.add('active'); updateProgress(); // Simuler le traitement (à remplacer par l'appel API réel) addLogEntry(`Traitement du lot ${currentIndex + 1} à ${endIndex}...`, 'info'); // Envoyer la requête au serveur fetch('process.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ batch: batch, currentIndex: currentIndex, totalItems: totalItems }) }) .then(response => response.json()) .then(data => { if (data.success) { // Traiter les résultats if (data.results && data.results.length) { data.results.forEach(result => { addLogEntry(result.message, result.status); }); } // Mettre à jour l'index currentIndex = endIndex; // Mettre à jour la progression updateProgress(); // Traiter le lot suivant après un court délai setTimeout(processBatch, 1000); } else { // Gérer l'erreur addLogEntry('Erreur: ' + data.message, 'error'); // Pause en cas d'erreur isPaused = true; pauseMigration.textContent = 'Reprendre'; currentProgress.classList.remove('active'); } }) .catch(error => { // Gérer l'erreur réseau addLogEntry('Erreur de connexion: ' + error.message, 'error'); // Pause en cas d'erreur isPaused = true; pauseMigration.textContent = 'Reprendre'; currentProgress.classList.remove('active'); }); } /** * Met à jour la barre de progression */ function updateProgress(forcedValue = null) { const progress = forcedValue !== null ? forcedValue : (currentIndex / totalItems) * 100; globalProgress.style.width = progress + '%'; globalProgress.textContent = Math.round(progress) + '%'; globalProgress.setAttribute('aria-valuenow', progress); if (forcedValue === null) { // Mettre à jour la progression actuelle const batchProgress = ((currentIndex % 5) / 5) * 100; currentProgress.style.width = batchProgress + '%'; currentProgress.setAttribute('aria-valuenow', batchProgress); } else { currentProgress.style.width = '100%'; currentProgress.setAttribute('aria-valuenow', 100); } } /** * Ajoute une entrée dans le journal des opérations */ function addLogEntry(message, status = 'info') { const entry = document.createElement('div'); entry.className = `log-entry ${status}`; const timestamp = new Date().toLocaleTimeString(); entry.textContent = `[${timestamp}] ${message}`; operationLog.appendChild(entry); // Scroll vers le bas pour voir la dernière entrée const logContainer = document.getElementById('log-container'); logContainer.scrollTop = logContainer.scrollHeight; } });