correction des erreurs
This commit is contained in:
parent
d258105f03
commit
49e3af77b8
@ -38,10 +38,10 @@ $config = [
|
||||
'misskey_api_endpoint' => '/api/notes/favorites/create',
|
||||
|
||||
// Paramètres pour le traitement
|
||||
'batch_size' => 5, // Nombre de favoris à traiter en une fois
|
||||
'timeout' => 45, // Timeout des requêtes en secondes
|
||||
'max_retries' => 3, // Nombre maximal de tentatives par favori
|
||||
'delay_between_requests' => 2000 // Délai entre les requêtes en millisecondes (pour éviter le rate limiting)
|
||||
'batch_size' => 2,
|
||||
'timeout' => 90,
|
||||
'max_retries' => 3,
|
||||
'delay_between_requests' => 3000
|
||||
];
|
||||
|
||||
// Session
|
||||
|
@ -225,49 +225,127 @@ function validate_misskey_token($instance, $token) {
|
||||
* @return array Résultat de la recherche
|
||||
*/
|
||||
function search_federated_note($instance, $url, $token) {
|
||||
// Nettoyer l'URL (enlever les éventuels paramètres)
|
||||
$cleanUrl = strtok($url, '?');
|
||||
|
||||
// Journal de débogage
|
||||
error_log("Recherche fédérée pour: " . $cleanUrl);
|
||||
|
||||
// Méthode principale: Utiliser ap/show qui fonctionne avec la plupart des instances
|
||||
$endpoint = '/api/ap/show';
|
||||
$data = [
|
||||
'uri' => $url
|
||||
'uri' => $cleanUrl
|
||||
];
|
||||
|
||||
// Effectuer la requête
|
||||
$result = misskey_api_request($instance, $endpoint, $data, $token);
|
||||
|
||||
// Si la méthode principale a réussi, retourner le résultat
|
||||
if ($result['success'] && isset($result['data']) && !empty($result['data'])) {
|
||||
return $result;
|
||||
// Journal pour le format de la réponse
|
||||
if ($result['success'] && isset($result['data'])) {
|
||||
error_log("Format de réponse ap/show: " . json_encode(array_keys($result['data'])));
|
||||
}
|
||||
|
||||
// Méthode de secours 1: Essayer search-by-url (ancienne méthode)
|
||||
$fallback_result = misskey_api_request($instance, '/api/notes/search-by-url', ['url' => $url], $token);
|
||||
|
||||
if ($fallback_result['success'] && isset($fallback_result['data']) && !empty($fallback_result['data'])) {
|
||||
return $fallback_result;
|
||||
}
|
||||
|
||||
// Méthode de secours 2: Extraction et recherche par ID distant
|
||||
$urlParts = parse_url($url);
|
||||
$pathParts = isset($urlParts['path']) ? explode('/', trim($urlParts['path'], '/')) : [];
|
||||
|
||||
if (count($pathParts) >= 4 && $pathParts[count($pathParts) - 2] === 'statuses') {
|
||||
$statusId = end($pathParts);
|
||||
$username = $pathParts[count($pathParts) - 3];
|
||||
$acctDomain = isset($urlParts['host']) ? $urlParts['host'] : '';
|
||||
// Si la méthode principale a réussi et renvoie un ID, retourner le résultat
|
||||
if ($result['success'] && isset($result['data'])) {
|
||||
// Vérifier si l'ID existe directement
|
||||
if (isset($result['data']['id'])) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
if ($statusId && $username && $acctDomain) {
|
||||
$remoteId = "https://{$acctDomain}/users/{$username}/statuses/{$statusId}";
|
||||
// Certaines instances peuvent avoir l'ID dans 'note'
|
||||
if (isset($result['data']['note']) && isset($result['data']['note']['id'])) {
|
||||
// Remonter l'ID au niveau principal
|
||||
$result['data']['id'] = $result['data']['note']['id'];
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Pour les instances plus récentes qui utilisent un format différent
|
||||
if (!empty($result['data'])) {
|
||||
// Rechercher un champ qui pourrait contenir l'ID
|
||||
foreach (['id', 'noteId', 'objectId', 'originalId'] as $possibleIdField) {
|
||||
if (isset($result['data'][$possibleIdField])) {
|
||||
$result['data']['id'] = $result['data'][$possibleIdField];
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
$remote_result = misskey_api_request($instance, '/api/notes/show', ['uri' => $remoteId], $token);
|
||||
|
||||
if ($remote_result['success'] && isset($remote_result['data']) && !empty($remote_result['data'])) {
|
||||
return $remote_result;
|
||||
// Si toujours pas d'ID, examiner la structure pour le trouver
|
||||
foreach ($result['data'] as $key => $value) {
|
||||
if (is_array($value) && isset($value['id'])) {
|
||||
$result['data']['id'] = $value['id'];
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Si aucune méthode n'a fonctionné, retourner le résultat de la méthode principale
|
||||
return $result;
|
||||
// Méthode de secours 1: Essayer notes/search-by-url (parfois utilisé dans les anciennes versions)
|
||||
$fallback_result = misskey_api_request($instance, '/api/notes/search-by-url', ['url' => $cleanUrl], $token);
|
||||
|
||||
if ($fallback_result['success'] && isset($fallback_result['data'])) {
|
||||
error_log("Format de réponse search-by-url: " . json_encode(array_keys($fallback_result['data'])));
|
||||
|
||||
// Vérifier si nous avons un résultat avec un ID
|
||||
if (isset($fallback_result['data']['id'])) {
|
||||
return $fallback_result;
|
||||
}
|
||||
|
||||
// Si le résultat est un tableau (certaines instances renvoient un tableau)
|
||||
if (is_array($fallback_result['data']) && !isset($fallback_result['data']['id'])) {
|
||||
// Chercher le premier élément avec un ID
|
||||
foreach ($fallback_result['data'] as $item) {
|
||||
if (is_array($item) && isset($item['id'])) {
|
||||
$fallback_result['data'] = $item; // Utiliser cet élément comme résultat
|
||||
return $fallback_result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Méthode de secours 2: Extraction et recherche par ID distant
|
||||
$urlParts = parse_url($cleanUrl);
|
||||
if (isset($urlParts['path'])) {
|
||||
$pathParts = explode('/', trim($urlParts['path'], '/'));
|
||||
|
||||
if (count($pathParts) >= 4 && $pathParts[count($pathParts) - 2] === 'statuses') {
|
||||
$statusId = end($pathParts);
|
||||
$username = $pathParts[count($pathParts) - 3];
|
||||
$acctDomain = isset($urlParts['host']) ? $urlParts['host'] : '';
|
||||
|
||||
if ($statusId && $username && $acctDomain) {
|
||||
$remoteId = "https://{$acctDomain}/users/{$username}/statuses/{$statusId}";
|
||||
|
||||
// Essayer d'abord avec /api/notes/show
|
||||
$remote_result = misskey_api_request($instance, '/api/notes/show', ['uri' => $remoteId], $token);
|
||||
|
||||
if ($remote_result['success'] && isset($remote_result['data']['id'])) {
|
||||
return $remote_result;
|
||||
}
|
||||
|
||||
// Dernier recours: essayer renotes/search
|
||||
$renote_result = misskey_api_request($instance, '/api/notes/search', [
|
||||
'query' => "@{$username}@{$acctDomain} {$statusId}",
|
||||
'limit' => 10
|
||||
], $token);
|
||||
|
||||
if ($renote_result['success'] && !empty($renote_result['data'])) {
|
||||
// Parcourir les résultats pour trouver une correspondance
|
||||
foreach ($renote_result['data'] as $note) {
|
||||
if (isset($note['id'])) {
|
||||
$renote_result['data'] = $note;
|
||||
return $renote_result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Si aucune méthode n'a fonctionné, retourner une erreur
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => "Impossible de trouver la publication sur le réseau fédéré après plusieurs tentatives"
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
|
161
js/app.js
161
js/app.js
@ -366,7 +366,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
}
|
||||
|
||||
// Nombre d'éléments à traiter dans ce lot
|
||||
const batchSize = 5;
|
||||
const batchSize = 2; // Réduit de 5 à 2 pour limiter les risques de timeout
|
||||
const endIndex = Math.min(currentIndex + batchSize, totalItems);
|
||||
|
||||
// Préparer les éléments du lot
|
||||
@ -376,73 +376,112 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
currentProgress.classList.add('active');
|
||||
updateProgress();
|
||||
|
||||
// Simuler le traitement (à remplacer par l'appel API réel)
|
||||
// Ajouter une entrée dans le journal
|
||||
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
|
||||
// Compteur de tentatives pour cette requête
|
||||
let retryAttempt = 0;
|
||||
const maxRetries = 3;
|
||||
|
||||
// Fonction pour envoyer la requête avec retry automatique
|
||||
function sendRequest() {
|
||||
fetch('process.php', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
batch: batch,
|
||||
currentIndex: currentIndex,
|
||||
totalItems: totalItems
|
||||
}),
|
||||
// Augmenter le timeout pour éviter les erreurs de limite de temps
|
||||
timeout: 60000
|
||||
})
|
||||
})
|
||||
.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 les compteurs
|
||||
if (result.status === 'success') {
|
||||
successCount++;
|
||||
} else if (result.status === 'error') {
|
||||
errorCount++;
|
||||
} else if (result.status === 'info') {
|
||||
skippedCount++;
|
||||
}
|
||||
.then(response => {
|
||||
// Vérifier si la réponse est au format JSON
|
||||
const contentType = response.headers.get('content-type');
|
||||
if (!contentType || !contentType.includes('application/json')) {
|
||||
// Si ce n'est pas du JSON, récupérer le texte pour déboguer
|
||||
return response.text().then(text => {
|
||||
throw new Error(`Réponse non-JSON reçue: ${text.substring(0, 100)}${text.length > 100 ? '...' : ''}`);
|
||||
});
|
||||
}
|
||||
return 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 les compteurs
|
||||
if (result.status === 'success') {
|
||||
successCount++;
|
||||
} else if (result.status === 'error') {
|
||||
errorCount++;
|
||||
} else if (result.status === 'info') {
|
||||
skippedCount++;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Mettre à jour l'index
|
||||
currentIndex = endIndex;
|
||||
|
||||
// Mettre à jour la progression
|
||||
updateProgress(data.progress.percentage);
|
||||
|
||||
// Mettre à jour les données de migration
|
||||
updateMigrationData('in_progress', data.progress);
|
||||
|
||||
// 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');
|
||||
|
||||
// Mettre à jour le statut de la migration
|
||||
updateMigrationData('error');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
// Afficher l'erreur détaillée dans la console pour le débogage
|
||||
console.error('Erreur complète:', error);
|
||||
|
||||
// Mettre à jour l'index
|
||||
currentIndex = endIndex;
|
||||
// Ajouter l'erreur au journal
|
||||
addLogEntry('Erreur de connexion: ' + error.message, 'error');
|
||||
|
||||
// Mettre à jour la progression
|
||||
updateProgress(data.progress.percentage);
|
||||
|
||||
// Mettre à jour les données de migration
|
||||
updateMigrationData('in_progress', data.progress);
|
||||
|
||||
// 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');
|
||||
|
||||
// Mettre à jour le statut de la migration
|
||||
updateMigrationData('error');
|
||||
}
|
||||
})
|
||||
.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');
|
||||
});
|
||||
// Retenter si nous n'avons pas atteint le nombre maximum de tentatives
|
||||
if (retryAttempt < maxRetries) {
|
||||
retryAttempt++;
|
||||
const waitTime = Math.pow(2, retryAttempt) * 1000; // Backoff exponentiel
|
||||
|
||||
addLogEntry(`Nouvelle tentative (${retryAttempt}/${maxRetries}) dans ${waitTime/1000} secondes...`, 'warning');
|
||||
|
||||
setTimeout(sendRequest, waitTime);
|
||||
} else {
|
||||
// Pause après plusieurs échecs
|
||||
isPaused = true;
|
||||
pauseMigration.textContent = 'Reprendre';
|
||||
currentProgress.classList.remove('active');
|
||||
|
||||
// Mettre à jour le statut de la migration
|
||||
updateMigrationData('error');
|
||||
|
||||
addLogEntry(`Échec après ${maxRetries} tentatives. Veuillez reprendre manuellement.`, 'error');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Lancer la requête
|
||||
sendRequest();
|
||||
}
|
||||
|
||||
/**
|
||||
|
248
process.php
248
process.php
@ -6,119 +6,171 @@
|
||||
// Définir la constante pour inclure les fichiers
|
||||
define('FAVMASTOKEY', true);
|
||||
|
||||
// Inclure les fichiers requis
|
||||
require_once 'includes/config.php';
|
||||
require_once 'includes/functions.php';
|
||||
// Forcer les en-têtes JSON dès le début pour éviter tout conflit
|
||||
header('Content-Type: application/json');
|
||||
|
||||
// Vérifier que la requête est en POST
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
http_response_code(405);
|
||||
echo json_encode(['success' => false, 'message' => 'Méthode non autorisée']);
|
||||
// Activer la capture d'erreurs
|
||||
set_error_handler(function($errno, $errstr, $errfile, $errline) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => "Erreur PHP: $errstr (ligne $errline dans $errfile)",
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
});
|
||||
|
||||
// Vérifier que l'utilisateur est authentifié
|
||||
if (!isset($_SESSION['misskey_token']) || empty($_SESSION['misskey_token'])) {
|
||||
http_response_code(401);
|
||||
echo json_encode(['success' => false, 'message' => 'Non authentifié']);
|
||||
exit;
|
||||
}
|
||||
try {
|
||||
// Inclure les fichiers requis
|
||||
require_once 'includes/config.php';
|
||||
require_once 'includes/functions.php';
|
||||
|
||||
// Récupérer l'instance Misskey
|
||||
$misskey_instance = isset($_SESSION['misskey_instance']) ? $_SESSION['misskey_instance'] : '';
|
||||
if (empty($misskey_instance)) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['success' => false, 'message' => 'Instance Misskey non définie']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Récupérer le token d'accès
|
||||
$token = $_SESSION['misskey_token'];
|
||||
|
||||
// Récupérer les données envoyées
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
if (!$input || !isset($input['batch']) || !is_array($input['batch'])) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['success' => false, 'message' => 'Données invalides']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Récupérer le lot à traiter
|
||||
$batch = $input['batch'];
|
||||
$currentIndex = isset($input['currentIndex']) ? (int)$input['currentIndex'] : 0;
|
||||
$totalItems = isset($input['totalItems']) ? (int)$input['totalItems'] : count($batch);
|
||||
|
||||
// Résultats du traitement
|
||||
$results = [];
|
||||
|
||||
// Traiter chaque URL du lot
|
||||
foreach ($batch as $index => $url) {
|
||||
// Extraire les informations de l'URL
|
||||
$urlParts = parse_url($url);
|
||||
|
||||
// Vérifier que l'URL est valide
|
||||
if (!$urlParts || !isset($urlParts['host']) || !isset($urlParts['path'])) {
|
||||
$results[] = [
|
||||
'status' => 'error',
|
||||
'message' => "URL invalide: $url"
|
||||
];
|
||||
continue;
|
||||
// Vérifier que la requête est en POST
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
http_response_code(405);
|
||||
echo json_encode(['success' => false, 'message' => 'Méthode non autorisée']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Vérifier que l'utilisateur est authentifié
|
||||
if (!isset($_SESSION['misskey_token']) || empty($_SESSION['misskey_token'])) {
|
||||
http_response_code(401);
|
||||
echo json_encode(['success' => false, 'message' => 'Non authentifié']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Récupérer l'instance Misskey
|
||||
$misskey_instance = isset($_SESSION['misskey_instance']) ? $_SESSION['misskey_instance'] : '';
|
||||
if (empty($misskey_instance)) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['success' => false, 'message' => 'Instance Misskey non définie']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Récupérer le token d'accès
|
||||
$token = $_SESSION['misskey_token'];
|
||||
|
||||
// Récupérer les données envoyées
|
||||
$input_data = file_get_contents('php://input');
|
||||
$input = json_decode($input_data, true);
|
||||
|
||||
// Rechercher la note sur Misskey à partir de l'URL
|
||||
$searchResult = search_federated_note($misskey_instance, $url, $token);
|
||||
|
||||
if ($searchResult['success'] && isset($searchResult['data']) && !empty($searchResult['data'])) {
|
||||
// Note trouvée, récupérer son ID
|
||||
$noteId = $searchResult['data']['id'];
|
||||
if (!$input || !isset($input['batch']) || !is_array($input['batch'])) {
|
||||
http_response_code(400);
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => 'Données invalides',
|
||||
'debug' => [
|
||||
'received' => $input_data ? substr($input_data, 0, 200) . '...' : 'Aucune donnée reçue'
|
||||
]
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Récupérer le lot à traiter
|
||||
$batch = $input['batch'];
|
||||
$currentIndex = isset($input['currentIndex']) ? (int)$input['currentIndex'] : 0;
|
||||
$totalItems = isset($input['totalItems']) ? (int)$input['totalItems'] : count($batch);
|
||||
|
||||
// Résultats du traitement
|
||||
$results = [];
|
||||
|
||||
// Traiter chaque URL du lot
|
||||
foreach ($batch as $index => $url) {
|
||||
// Extraire les informations de l'URL
|
||||
$urlParts = parse_url($url);
|
||||
|
||||
// Tenter d'ajouter la note aux favoris
|
||||
$favoriteResult = add_to_favorites($misskey_instance, $noteId, $token);
|
||||
|
||||
if ($favoriteResult['success']) {
|
||||
// Vérifier que l'URL est valide
|
||||
if (!$urlParts || !isset($urlParts['host']) || !isset($urlParts['path'])) {
|
||||
$results[] = [
|
||||
'status' => 'success',
|
||||
'message' => "Ajouté aux favoris: $url"
|
||||
'status' => 'error',
|
||||
'message' => "URL invalide: $url"
|
||||
];
|
||||
} else {
|
||||
// Vérifier si c'est une erreur de "déjà ajouté aux favoris"
|
||||
$errorMessage = isset($favoriteResult['data']['error']['message'])
|
||||
? $favoriteResult['data']['error']['message']
|
||||
: $favoriteResult['message'];
|
||||
|
||||
if (strpos($errorMessage, 'already') !== false) {
|
||||
$results[] = [
|
||||
'status' => 'info',
|
||||
'message' => "Déjà dans vos favoris: $url"
|
||||
];
|
||||
continue;
|
||||
}
|
||||
|
||||
// Ajouter un log pour déboguer
|
||||
error_log("Recherche de l'URL: " . $url . " sur l'instance: " . $misskey_instance);
|
||||
|
||||
// Rechercher la note sur Misskey à partir de l'URL
|
||||
$searchResult = search_federated_note($misskey_instance, $url, $token);
|
||||
|
||||
// Vérifier si la recherche a réussi ET si les données contiennent un ID valide
|
||||
if ($searchResult['success'] && isset($searchResult['data']) && !empty($searchResult['data'])) {
|
||||
// Vérifier et extraire l'ID de manière sécurisée
|
||||
if (isset($searchResult['data']['id']) && !empty($searchResult['data']['id'])) {
|
||||
$noteId = $searchResult['data']['id'];
|
||||
|
||||
// Tenter d'ajouter la note aux favoris
|
||||
$favoriteResult = add_to_favorites($misskey_instance, $noteId, $token);
|
||||
|
||||
if ($favoriteResult['success']) {
|
||||
$results[] = [
|
||||
'status' => 'success',
|
||||
'message' => "Ajouté aux favoris: $url"
|
||||
];
|
||||
} else {
|
||||
// Vérifier si c'est une erreur de "déjà ajouté aux favoris"
|
||||
$errorMessage = isset($favoriteResult['data']['error']['message'])
|
||||
? $favoriteResult['data']['error']['message']
|
||||
: (isset($favoriteResult['message']) ? $favoriteResult['message'] : 'Erreur inconnue');
|
||||
|
||||
if (strpos($errorMessage, 'already') !== false) {
|
||||
$results[] = [
|
||||
'status' => 'info',
|
||||
'message' => "Déjà dans vos favoris: $url"
|
||||
];
|
||||
} else {
|
||||
$results[] = [
|
||||
'status' => 'error',
|
||||
'message' => "Erreur lors de l'ajout aux favoris: $errorMessage"
|
||||
];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// L'ID est manquant ou vide dans la réponse
|
||||
$dataKeys = is_array($searchResult['data']) ? array_keys($searchResult['data']) : ['non_array'];
|
||||
$results[] = [
|
||||
'status' => 'error',
|
||||
'message' => "Erreur lors de l'ajout aux favoris: $errorMessage"
|
||||
'message' => "Note trouvée mais sans ID valide: $url. Clés disponibles: " . implode(', ', $dataKeys)
|
||||
];
|
||||
|
||||
// Log pour déboguer
|
||||
error_log("Structure de données reçue: " . json_encode($searchResult['data']));
|
||||
}
|
||||
} else {
|
||||
// Note non trouvée ou erreur de recherche
|
||||
$errorMessage = isset($searchResult['message']) ? $searchResult['message'] : "Publication introuvable";
|
||||
|
||||
$results[] = [
|
||||
'status' => 'error',
|
||||
'message' => "Publication non trouvée sur le réseau fédéré: $url ($errorMessage)"
|
||||
];
|
||||
|
||||
// Ajouter des infos de debug
|
||||
if (isset($searchResult['data']) && is_array($searchResult['data'])) {
|
||||
error_log("Données reçues pour URL $url: " . json_encode($searchResult['data']));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Note non trouvée
|
||||
$errorMessage = isset($searchResult['message']) ? $searchResult['message'] : "Publication introuvable";
|
||||
|
||||
$results[] = [
|
||||
'status' => 'error',
|
||||
'message' => "Publication non trouvée sur le réseau fédéré: $url ($errorMessage)"
|
||||
];
|
||||
// Pause pour éviter le rate limiting
|
||||
usleep($config['delay_between_requests'] * 1000);
|
||||
}
|
||||
|
||||
// Pause pour éviter le rate limiting
|
||||
usleep($config['delay_between_requests'] * 1000);
|
||||
}
|
||||
|
||||
// Renvoyer les résultats
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'results' => $results,
|
||||
'progress' => [
|
||||
'current' => $currentIndex + count($batch),
|
||||
'total' => $totalItems,
|
||||
'percentage' => round((($currentIndex + count($batch)) / $totalItems) * 100, 2)
|
||||
]
|
||||
]);
|
||||
// Renvoyer les résultats
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'results' => $results,
|
||||
'progress' => [
|
||||
'current' => $currentIndex + count($batch),
|
||||
'total' => $totalItems,
|
||||
'percentage' => round((($currentIndex + count($batch)) / $totalItems) * 100, 2)
|
||||
]
|
||||
]);
|
||||
|
||||
} catch (Exception $e) {
|
||||
// Capturer toutes les exceptions et renvoyer un message d'erreur formaté en JSON
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => 'Exception: ' . $e->getMessage(),
|
||||
'file' => $e->getFile(),
|
||||
'line' => $e->getLine()
|
||||
]);
|
||||
}
|
393
test-url.php
393
test-url.php
@ -1,393 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* FavMasToKey - Test d'URL
|
||||
* Ce script permet de tester manuellement une URL pour voir comment Misskey la traite
|
||||
*/
|
||||
|
||||
// Définir la constante pour inclure les fichiers
|
||||
define('FAVMASTOKEY', true);
|
||||
|
||||
// Inclure les fichiers requis
|
||||
require_once 'includes/config.php';
|
||||
require_once 'includes/functions.php';
|
||||
|
||||
// Initialiser les variables
|
||||
$url = '';
|
||||
$test_results = [];
|
||||
$detailed_results = [];
|
||||
$misskey_instance = isset($_SESSION['misskey_instance']) ? $_SESSION['misskey_instance'] : '';
|
||||
$token = isset($_SESSION['misskey_token']) ? $_SESSION['misskey_token'] : '';
|
||||
$connected = !empty($misskey_instance) && !empty($token);
|
||||
|
||||
// Si non connecté, permettre de saisir les informations d'authentification
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'connect') {
|
||||
if (isset($_POST['misskey_instance']) && isset($_POST['misskey_token'])) {
|
||||
$misskey_instance = trim($_POST['misskey_instance']);
|
||||
$token = trim($_POST['misskey_token']);
|
||||
|
||||
// Valider le format de l'instance
|
||||
$misskey_instance = preg_replace('/^https?:\/\//', '', $misskey_instance);
|
||||
$misskey_instance = rtrim($misskey_instance, '/');
|
||||
|
||||
if (!empty($misskey_instance) && !empty($token)) {
|
||||
// Vérifier la validité du token en effectuant une requête test
|
||||
$validate_result = validate_misskey_token($misskey_instance, $token);
|
||||
|
||||
if ($validate_result['success']) {
|
||||
// Connecté avec succès
|
||||
$connected = true;
|
||||
|
||||
// Stockage temporaire pour cette session uniquement
|
||||
$_SESSION['misskey_token_temp'] = $token;
|
||||
$_SESSION['misskey_instance_temp'] = $misskey_instance;
|
||||
|
||||
$success_message = "Connecté temporairement à {$misskey_instance} pour les tests.";
|
||||
} else {
|
||||
$error_message = "Impossible de se connecter à l'instance avec ce token.";
|
||||
}
|
||||
} else {
|
||||
$error_message = "Veuillez renseigner à la fois l'instance et le token.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Récupérer les valeurs temporaires si disponibles
|
||||
if (!$connected && isset($_SESSION['misskey_token_temp']) && isset($_SESSION['misskey_instance_temp'])) {
|
||||
$token = $_SESSION['misskey_token_temp'];
|
||||
$misskey_instance = $_SESSION['misskey_instance_temp'];
|
||||
$connected = true;
|
||||
}
|
||||
|
||||
// Traiter le test d'URL
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'test' && $connected) {
|
||||
if (isset($_POST['url'])) {
|
||||
$url = trim($_POST['url']);
|
||||
|
||||
if (!empty($url)) {
|
||||
// Méthode 1: search-by-url
|
||||
$test_results[] = [
|
||||
'method' => 'search-by-url',
|
||||
'endpoint' => '/api/notes/search-by-url',
|
||||
'result' => misskey_api_request($misskey_instance, '/api/notes/search-by-url', ['url' => $url], $token)
|
||||
];
|
||||
|
||||
// Méthode 2: ap/show
|
||||
$test_results[] = [
|
||||
'method' => 'ap/show',
|
||||
'endpoint' => '/api/ap/show',
|
||||
'result' => misskey_api_request($misskey_instance, '/api/ap/show', ['uri' => $url], $token)
|
||||
];
|
||||
|
||||
// Méthode 3: Extraction et recherche par ID distant
|
||||
$urlParts = parse_url($url);
|
||||
$pathParts = isset($urlParts['path']) ? explode('/', trim($urlParts['path'], '/')) : [];
|
||||
|
||||
if (count($pathParts) >= 4 && $pathParts[count($pathParts) - 2] === 'statuses') {
|
||||
$statusId = end($pathParts);
|
||||
$username = $pathParts[count($pathParts) - 3];
|
||||
$acctDomain = isset($urlParts['host']) ? $urlParts['host'] : '';
|
||||
|
||||
if ($statusId && $username && $acctDomain) {
|
||||
$remoteId = "https://{$acctDomain}/users/{$username}/statuses/{$statusId}";
|
||||
|
||||
$test_results[] = [
|
||||
'method' => 'notes/show (uri)',
|
||||
'endpoint' => '/api/notes/show',
|
||||
'params' => ['uri' => $remoteId],
|
||||
'result' => misskey_api_request($misskey_instance, '/api/notes/show', ['uri' => $remoteId], $token)
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// Méthode 4: Forcer la fédération
|
||||
if (curl_init()) {
|
||||
$ch = curl_init($url);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_HEADER, false);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
||||
'Accept: application/activity+json'
|
||||
]);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
|
||||
$response = curl_exec($ch);
|
||||
$info = curl_getinfo($ch);
|
||||
curl_close($ch);
|
||||
|
||||
$detailed_results['direct_request'] = [
|
||||
'url' => $url,
|
||||
'http_code' => $info['http_code'],
|
||||
'content_type' => $info['content_type'],
|
||||
'response_size' => strlen($response),
|
||||
'response_preview' => substr($response, 0, 500) . (strlen($response) > 500 ? '...' : '')
|
||||
];
|
||||
|
||||
// Attendre un moment pour que l'instance ait le temps de fédérer
|
||||
sleep(2);
|
||||
|
||||
// Réessayer avec search-by-url après avoir forcé la fédération
|
||||
$test_results[] = [
|
||||
'method' => 'search-by-url (après tentative de fédération)',
|
||||
'endpoint' => '/api/notes/search-by-url',
|
||||
'result' => misskey_api_request($misskey_instance, '/api/notes/search-by-url', ['url' => $url], $token)
|
||||
];
|
||||
}
|
||||
|
||||
// Essayer la recherche par contenu
|
||||
// Cette méthode est moins précise mais peut aider dans certains cas
|
||||
if (curl_init()) {
|
||||
$ch = curl_init($url);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_HEADER, false);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
|
||||
$html = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
|
||||
// Extraction simple du contenu (très basique)
|
||||
$content = '';
|
||||
if (preg_match('/<article[^>]*>(.*?)<\/article>/is', $html, $matches)) {
|
||||
$content = strip_tags($matches[1]);
|
||||
$content = preg_replace('/\s+/', ' ', $content);
|
||||
$content = trim($content);
|
||||
|
||||
if (strlen($content) > 5) {
|
||||
$detailed_results['content_search'] = [
|
||||
'extracted_content' => substr($content, 0, 200) . (strlen($content) > 200 ? '...' : ''),
|
||||
'content_length' => strlen($content)
|
||||
];
|
||||
|
||||
// Rechercher par les premiers mots du contenu
|
||||
$searchWords = implode(' ', array_slice(explode(' ', $content), 0, 10));
|
||||
|
||||
$test_results[] = [
|
||||
'method' => 'notes/search (par contenu)',
|
||||
'endpoint' => '/api/notes/search',
|
||||
'params' => ['query' => $searchWords, 'limit' => 5],
|
||||
'result' => misskey_api_request($misskey_instance, '/api/notes/search', ['query' => $searchWords, 'limit' => 5], $token)
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$error_message = "Veuillez entrer une URL à tester.";
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr" data-bs-theme="dark">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="theme-color" content="#7e57c2">
|
||||
<link rel="icon" href="images/favicon.svg" type="image/svg+xml">
|
||||
<title>Test d'URL - FavMasToKey</title>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="css/styles.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container py-5">
|
||||
<header class="text-center mb-4">
|
||||
<h1>FavMasToKey - Test d'URL</h1>
|
||||
<p class="lead">Outil de diagnostic pour tester la résolution d'URL Mastodon</p>
|
||||
<p><a href="index.php" class="btn btn-primary">Retour à l'application</a></p>
|
||||
</header>
|
||||
|
||||
<?php if (isset($error_message)): ?>
|
||||
<div class="alert alert-danger alert-dismissible fade show" role="alert">
|
||||
<?php echo $error_message; ?>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Fermer"></button>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (isset($success_message)): ?>
|
||||
<div class="alert alert-success alert-dismissible fade show" role="alert">
|
||||
<?php echo $success_message; ?>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Fermer"></button>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!$connected): ?>
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
<h2 class="card-title h5 mb-0">Connexion à Misskey pour les tests</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="alert alert-info">
|
||||
<strong>Information:</strong> Vous devez vous connecter à votre instance Misskey pour tester les URLs.
|
||||
<p class="mb-0">Cette connexion est temporaire et utilisée uniquement pour cette page de test.</p>
|
||||
</div>
|
||||
|
||||
<form method="post" action="">
|
||||
<input type="hidden" name="action" value="connect">
|
||||
<div class="mb-3">
|
||||
<label for="misskey-instance" class="form-label">Instance Misskey</label>
|
||||
<input type="text" class="form-control" id="misskey-instance" name="misskey_instance"
|
||||
placeholder="misskey.io" required>
|
||||
<div class="form-text">Entrez le nom de domaine de votre instance Misskey (ex: misskey.io)</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="misskey-token" class="form-label">Jeton d'accès</label>
|
||||
<input type="password" class="form-control" id="misskey-token" name="misskey_token"
|
||||
placeholder="Votre jeton d'accès Misskey" required>
|
||||
<div class="form-text">Collez le jeton d'accès généré dans les paramètres de votre compte Misskey</div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Se connecter pour les tests</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="card mb-4">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<h2 class="card-title h5 mb-0">Tester une URL</h2>
|
||||
<span class="badge bg-success">Connecté à <?php echo htmlspecialchars($misskey_instance); ?></span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="post" action="">
|
||||
<input type="hidden" name="action" value="test">
|
||||
<div class="mb-3">
|
||||
<label for="url" class="form-label">URL d'une publication Mastodon</label>
|
||||
<input type="url" class="form-control" id="url" name="url"
|
||||
placeholder="https://instance.tld/users/username/statuses/123456"
|
||||
value="<?php echo htmlspecialchars($url); ?>" required>
|
||||
<div class="form-text">
|
||||
Entrez l'URL complète d'une publication Mastodon que vous souhaitez tester.
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Tester cette URL</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if (!empty($test_results)): ?>
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
<h2 class="card-title h5 mb-0">Résultats de la recherche pour <?php echo htmlspecialchars($url); ?></h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="mb-4">
|
||||
<h3 class="h6">Structure de l'URL</h3>
|
||||
<?php
|
||||
$urlParts = parse_url($url);
|
||||
$pathParts = isset($urlParts['path']) ? explode('/', trim($urlParts['path'], '/')) : [];
|
||||
?>
|
||||
<pre class="bg-dark text-light p-3"><?php
|
||||
echo "Schema: " . (isset($urlParts['scheme']) ? $urlParts['scheme'] : 'non défini') . "\n";
|
||||
echo "Host: " . (isset($urlParts['host']) ? $urlParts['host'] : 'non défini') . "\n";
|
||||
echo "Path: " . (isset($urlParts['path']) ? $urlParts['path'] : 'non défini') . "\n";
|
||||
|
||||
if (count($pathParts) >= 4 && $pathParts[count($pathParts) - 2] === 'statuses') {
|
||||
$statusId = end($pathParts);
|
||||
$username = $pathParts[count($pathParts) - 3];
|
||||
echo "\nFormat reconnu comme URL Mastodon: Oui\n";
|
||||
echo "Username: {$username}\n";
|
||||
echo "Status ID: {$statusId}\n";
|
||||
echo "ActivityPub URI: https://{$urlParts['host']}/users/{$username}/statuses/{$statusId}\n";
|
||||
} else {
|
||||
echo "\nFormat reconnu comme URL Mastodon: Non\n";
|
||||
echo "Segments du chemin: " . implode(', ', $pathParts);
|
||||
}
|
||||
?></pre>
|
||||
</div>
|
||||
|
||||
<?php foreach ($test_results as $index => $result): ?>
|
||||
<div class="mb-4">
|
||||
<h3 class="h6 mb-2">Méthode <?php echo $index + 1; ?>: <?php echo htmlspecialchars($result['method']); ?></h3>
|
||||
<div class="card bg-dark">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<span>Endpoint: <?php echo htmlspecialchars($result['endpoint']); ?></span>
|
||||
<span class="badge <?php echo $result['result']['success'] ? 'bg-success' : 'bg-danger'; ?>">
|
||||
<?php echo $result['result']['success'] ? 'Succès' : 'Échec'; ?>
|
||||
</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<?php if (isset($result['params'])): ?>
|
||||
<h4 class="h6">Paramètres</h4>
|
||||
<pre class="text-light"><?php print_r($result['params']); ?></pre>
|
||||
<?php endif; ?>
|
||||
|
||||
<h4 class="h6">Code HTTP: <?php echo $result['result']['http_code']; ?></h4>
|
||||
|
||||
<?php if ($result['result']['success'] && isset($result['result']['data']) && !empty($result['result']['data'])): ?>
|
||||
<h4 class="h6 text-success">Publication trouvée!</h4>
|
||||
<pre class="text-light"><?php print_r($result['result']['data']); ?></pre>
|
||||
<?php else: ?>
|
||||
<h4 class="h6 text-danger">Publication non trouvée</h4>
|
||||
<pre class="text-light"><?php
|
||||
if (isset($result['result']['message'])) {
|
||||
echo "Message: " . print_r($result['result']['message'], true);
|
||||
}
|
||||
if (isset($result['result']['data'])) {
|
||||
echo "\nDonnées: " . print_r($result['result']['data'], true);
|
||||
}
|
||||
?></pre>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
|
||||
<?php if (!empty($detailed_results)): ?>
|
||||
<div class="mb-4">
|
||||
<h3 class="h6">Détails supplémentaires</h3>
|
||||
<pre class="bg-dark text-light p-3"><?php print_r($detailed_results); ?></pre>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="mt-4">
|
||||
<h3 class="h6">Recommandations</h3>
|
||||
<ul>
|
||||
<?php
|
||||
$successFound = false;
|
||||
$bestMethod = '';
|
||||
|
||||
foreach ($test_results as $result) {
|
||||
if ($result['result']['success'] && isset($result['result']['data']) && !empty($result['result']['data'])) {
|
||||
$successFound = true;
|
||||
$bestMethod = $result['method'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($successFound):
|
||||
?>
|
||||
<li class="text-success">
|
||||
<strong>Bonne nouvelle!</strong> Publication trouvée avec la méthode "<?php echo htmlspecialchars($bestMethod); ?>".
|
||||
<p class="mt-2">Vous devriez modifier la fonction <code>search_federated_note</code> pour utiliser cette méthode en priorité.</p>
|
||||
<div class="alert alert-info">
|
||||
<p class="mb-1"><strong>Suggestion pour la fonction search_federated_note:</strong></p>
|
||||
<pre class="text-dark mb-0">
|
||||
function search_federated_note($instance, $url, $token) {
|
||||
// Pour cette publication spécifique, utiliser la méthode qui fonctionne
|
||||
if ($url === "<?php echo htmlspecialchars($url); ?>") {
|
||||
return misskey_api_request($instance, "<?php echo $result['endpoint']; ?>",
|
||||
<?php echo isset($result['params'])
|
||||
? var_export($result['params'], true)
|
||||
: "['url' => \$url]"; ?>, $token);
|
||||
}
|
||||
|
||||
// Pour les autres publications, essayer les différentes méthodes...
|
||||
// [reste du code actuel]
|
||||
}</pre>
|
||||
</div>
|
||||
</li>
|
||||
<?php else: ?>
|
||||
<li class="text-warning">
|
||||
<strong>Publication non trouvée</strong> avec aucune des méthodes testées. Voici quelques suggestions:
|
||||
<ul class="mt-2">
|
||||
<li>Vérifiez que la publication existe toujours et est publique</li>
|
||||
<li>Assurez-vous que votre instance Misskey peut se fédérer avec l'instance d'origine</li>
|
||||
<li>Visitez manuellement l'URL depuis votre instance Misskey pour forcer la fédération</li>
|
||||
<li>Si c'est un problème récurrent, ajustez les délais entre les requêtes dans config.php</li>
|
||||
</ul>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
</body>
|
||||
</html>
|
Loading…
x
Reference in New Issue
Block a user