prod: UI Optimisée mise en production
- Documentation archivée et réorganisée - Backend: Ajout tests, migrations, library service, rate limiting - Frontend: Suppression Flutter, focus sur interface web HTML/JS - Tailwind CSS ajouté pour le style - Améliorations UX et corrections bugs Generated with [Claude Code](https://claude.com/claude-code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
This commit is contained in:
+669
-252
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,141 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Diagnostic AudiOhm</title>
|
||||
<style>
|
||||
body { font-family: monospace; padding: 20px; background: #1a1a2e; color: #eee; }
|
||||
.test { margin: 10px 0; padding: 10px; border: 1px solid #444; }
|
||||
.pass { background: #1b4332; }
|
||||
.fail { background: #4a1a1a; }
|
||||
button { padding: 10px 20px; margin: 5px; cursor: pointer; }
|
||||
pre { background: #0d0d1a; padding: 10px; overflow-x: auto; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>🔧 Diagnostic AudiOhm</h1>
|
||||
|
||||
<div class="test" id="test-api">Test API...</div>
|
||||
<div class="test" id="test-auth">Test Auth...</div>
|
||||
<div class="test" id="test-trending">Test Trending...</div>
|
||||
<div class="test" id="test-stream">Test Stream URL...</div>
|
||||
|
||||
<h2>Actions</h2>
|
||||
<button onclick="testAll()">Exécuter tous les tests</button>
|
||||
<button onclick="testLogin()">Test Login</button>
|
||||
|
||||
<h2>Résultats</h2>
|
||||
<pre id="output">Cliquez sur un bouton pour commencer...</pre>
|
||||
|
||||
<script>
|
||||
let authToken = null;
|
||||
|
||||
function log(msg) {
|
||||
const output = document.getElementById('output');
|
||||
output.textContent += msg + '\n';
|
||||
}
|
||||
|
||||
function updateStatus(id, passed, msg) {
|
||||
const el = document.getElementById(id);
|
||||
el.className = 'test ' + (passed ? 'pass' : 'fail');
|
||||
el.textContent = msg;
|
||||
}
|
||||
|
||||
async function testAPI() {
|
||||
try {
|
||||
const response = await fetch('/api/v1/music/trending?limit=1');
|
||||
const data = await response.json();
|
||||
updateStatus('test-api', response.ok, `API: ${response.status} - ${response.statusText}`);
|
||||
log('✅ API accessible');
|
||||
log('Données: ' + JSON.stringify(data[0], null, 2).substring(0, 200) + '...');
|
||||
} catch (error) {
|
||||
updateStatus('test-api', false, 'API: Error - ' + error.message);
|
||||
log('❌ API error: ' + error.message);
|
||||
}
|
||||
}
|
||||
|
||||
async function testLogin() {
|
||||
try {
|
||||
const response = await fetch('/api/v1/auth/login', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
email: 'admin@example.com',
|
||||
password: 'admin123'
|
||||
})
|
||||
});
|
||||
const data = await response.json();
|
||||
if (response.ok && data.access_token) {
|
||||
authToken = data.access_token;
|
||||
updateStatus('test-auth', true, 'Auth: ✅ Connecté');
|
||||
log('✅ Login réussi');
|
||||
log('Token: ' + authToken.substring(0, 20) + '...');
|
||||
} else {
|
||||
updateStatus('test-auth', false, 'Auth: ❌ ' + JSON.stringify(data));
|
||||
log('❌ Login failed: ' + JSON.stringify(data));
|
||||
}
|
||||
} catch (error) {
|
||||
updateStatus('test-auth', false, 'Auth: Error - ' + error.message);
|
||||
log('❌ Auth error: ' + error.message);
|
||||
}
|
||||
}
|
||||
|
||||
async function testTrending() {
|
||||
if (!authToken) {
|
||||
await testLogin();
|
||||
}
|
||||
if (!authToken) {
|
||||
updateStatus('test-trending', false, 'Trending: Pas de token');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/v1/music/trending?limit=2', {
|
||||
headers: { 'Authorization': 'Bearer ' + authToken }
|
||||
});
|
||||
const data = await response.json();
|
||||
updateStatus('test-trending', response.ok, `Trending: ${response.status} - ${data.length} pistes`);
|
||||
log('✅ Trending: ' + data.length + ' pistes trouvées');
|
||||
log('Piste 1: ' + data[0].title);
|
||||
} catch (error) {
|
||||
updateStatus('test-trending', false, 'Trending: Error - ' + error.message);
|
||||
log('❌ Trending error: ' + error.message);
|
||||
}
|
||||
}
|
||||
|
||||
async function testStream() {
|
||||
const youtubeId = 'NqDGkdDh8WE';
|
||||
try {
|
||||
const response = await fetch(`/api/v1/music/youtube/${youtubeId}/stream`);
|
||||
const data = await response.json();
|
||||
if (response.ok && data.stream_url) {
|
||||
updateStatus('test-stream', true, 'Stream: ✅ URL obtenue');
|
||||
log('✅ Stream URL obtenue');
|
||||
log('URL: ' + data.stream_url.substring(0, 100) + '...');
|
||||
} else {
|
||||
updateStatus('test-stream', false, 'Stream: ❌ ' + JSON.stringify(data));
|
||||
log('❌ Stream failed: ' + JSON.stringify(data));
|
||||
}
|
||||
} catch (error) {
|
||||
updateStatus('test-stream', false, 'Stream: Error - ' + error.message);
|
||||
log('❌ Stream error: ' + error.message);
|
||||
}
|
||||
}
|
||||
|
||||
async function testAll() {
|
||||
document.getElementById('output').textContent = '=== Tests en cours ===\n';
|
||||
await testAPI();
|
||||
await testLogin();
|
||||
await testTrending();
|
||||
await testStream();
|
||||
log('\n=== Tests terminés ===');
|
||||
}
|
||||
|
||||
// Auto-run on load
|
||||
window.onload = function() {
|
||||
log('Page chargée - Prêt à tester');
|
||||
log('Date: ' + new Date().toISOString());
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
+3228
-147
File diff suppressed because it is too large
Load Diff
+3781
-382
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,40 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test AudiOhm</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Test API</h1>
|
||||
<button onclick="testTrending()">Test Trending</button>
|
||||
<button onclick="testStream()">Test Stream</button>
|
||||
<pre id="output"></pre>
|
||||
|
||||
<script>
|
||||
async function testTrending() {
|
||||
const output = document.getElementById('output');
|
||||
output.textContent = 'Testing trending...';
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/v1/music/trending?limit=1');
|
||||
const data = await response.json();
|
||||
output.textContent = 'Trending Response:\n' + JSON.stringify(data, null, 2);
|
||||
} catch (error) {
|
||||
output.textContent = 'Error: ' + error.message;
|
||||
}
|
||||
}
|
||||
|
||||
async function testStream() {
|
||||
const output = document.getElementById('output');
|
||||
output.textContent = 'Testing stream...';
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/v1/music/youtube/NqDGkdDh8WE/stream');
|
||||
const data = await response.json();
|
||||
output.textContent = 'Stream Response:\n' + JSON.stringify(data, null, 2);
|
||||
} catch (error) {
|
||||
output.textContent = 'Error: ' + error.message;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,43 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test Functions</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Test des fonctions JavaScript</h1>
|
||||
<div id="results"></div>
|
||||
|
||||
<script src="js/app.js"></script>
|
||||
<script>
|
||||
const results = document.getElementById('results');
|
||||
|
||||
function testFunction(name, exists) {
|
||||
const div = document.createElement('div');
|
||||
div.style.color = exists ? 'green' : 'red';
|
||||
div.textContent = (exists ? '✅' : '❌') + ' ' + name;
|
||||
results.appendChild(div);
|
||||
}
|
||||
|
||||
// Tester les fonctions critiques
|
||||
testFunction('switchLibraryTab', typeof window.switchLibraryTab === 'function');
|
||||
testFunction('loadUserData', typeof window.loadUserData === 'function');
|
||||
testFunction('playPrevious', typeof window.playPrevious === 'function');
|
||||
testFunction('playNext', typeof window.playNext === 'function');
|
||||
testFunction('togglePlayPause', typeof window.togglePlayPause === 'function');
|
||||
testFunction('toggleShuffle', typeof window.toggleShuffle === 'function');
|
||||
testFunction('toggleRepeat', typeof window.toggleRepeat === 'function');
|
||||
testFunction('toggleMute', typeof window.toggleMute === 'function');
|
||||
testFunction('handleSeek', typeof window.handleSeek === 'function');
|
||||
testFunction('handleVolumeChange', typeof window.handleVolumeChange === 'function');
|
||||
testFunction('updateProgress', typeof window.updateProgress === 'function');
|
||||
testFunction('updateDuration', typeof window.updateDuration === 'function');
|
||||
testFunction('handleTrackEnd', typeof window.handleTrackEnd === 'function');
|
||||
testFunction('toggleLike', typeof window.toggleLike === 'function');
|
||||
testFunction('loadPlaylists', typeof window.loadPlaylists === 'function');
|
||||
testFunction('loadLikedTracks', typeof window.loadLikedTracks === 'function');
|
||||
testFunction('loadListeningHistory', typeof window.loadListeningHistory === 'function');
|
||||
testFunction('playTrack', typeof window.playTrack === 'function');
|
||||
testFunction('createPlaylist', typeof window.createPlaylist === 'function');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,99 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test AudiOhm API</title>
|
||||
<style>
|
||||
body { font-family: Arial; padding: 20px; background: #1a1a1a; color: #fff; }
|
||||
.test { margin: 20px 0; padding: 15px; background: #2a2a2a; border-radius: 8px; }
|
||||
.pass { color: #4ade80; }
|
||||
.fail { color: #f87171; }
|
||||
pre { background: #1a1a1a; padding: 10px; overflow-x: auto; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>🧪 Test API AudiOhm</h1>
|
||||
<div id="results"></div>
|
||||
|
||||
<script>
|
||||
const results = document.getElementById('results');
|
||||
|
||||
async function testAPI() {
|
||||
let token = localStorage.getItem('token');
|
||||
|
||||
if (!token) {
|
||||
// Login first
|
||||
addTest('POST /api/v1/auth/login', async () => {
|
||||
const response = await fetch('/api/v1/auth/login', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
email: 'admin@example.com',
|
||||
password: 'admin123'
|
||||
})
|
||||
});
|
||||
const data = await response.json();
|
||||
if (data.access_token) {
|
||||
localStorage.setItem('token', data.access_token);
|
||||
token = data.access_token;
|
||||
return { status: '✅', token: token.substring(0, 20) + '...' };
|
||||
}
|
||||
throw new Error('No token');
|
||||
});
|
||||
}
|
||||
|
||||
// Test Playlists
|
||||
await addTest('GET /api/v1/playlists', async () => {
|
||||
const response = await fetch('/api/v1/playlists', {
|
||||
headers: { 'Authorization': `Bearer ${token}` }
|
||||
});
|
||||
const data = await response.json();
|
||||
return { status: response.ok ? '✅' : '❌', count: data.length, data: data };
|
||||
});
|
||||
|
||||
// Test Trending
|
||||
await addTest('GET /api/v1/music/trending', async () => {
|
||||
const response = await fetch('/api/v1/music/trending', {
|
||||
headers: { 'Authorization': `Bearer ${token}` }
|
||||
});
|
||||
const data = await response.json();
|
||||
return { status: response.ok ? '✅' : '❌', count: data.length };
|
||||
});
|
||||
|
||||
// Test Liked Tracks
|
||||
await addTest('GET /api/v1/library/liked-tracks', async () => {
|
||||
const response = await fetch('/api/v1/library/liked-tracks', {
|
||||
headers: { 'Authorization': `Bearer ${token}` }
|
||||
});
|
||||
const data = await response.json();
|
||||
if (data.detail) throw new Error(data.detail);
|
||||
return { status: response.ok ? '✅' : '❌', count: data.length };
|
||||
});
|
||||
|
||||
// Test History
|
||||
await addTest('GET /api/v1/library/history', async () => {
|
||||
const response = await fetch('/api/v1/library/history', {
|
||||
headers: { 'Authorization': `Bearer ${token}` }
|
||||
});
|
||||
const data = await response.json();
|
||||
if (data.detail) throw new Error(data.detail);
|
||||
return { status: response.ok ? '✅' : '❌', count: data.length };
|
||||
});
|
||||
}
|
||||
|
||||
async function addTest(name, testFn) {
|
||||
const div = document.createElement('div');
|
||||
div.className = 'test';
|
||||
results.appendChild(div);
|
||||
|
||||
try {
|
||||
const result = await testFn();
|
||||
div.innerHTML = `<span class="${result.status === '✅' ? 'pass' : 'fail'}">${result.status}</span> <strong>${name}</strong><br><pre>${JSON.stringify(result, null, 2)}</pre>`;
|
||||
} catch (error) {
|
||||
div.innerHTML = `<span class="fail">❌</span> <strong>${name}</strong><br><pre>${error.message}</pre>`;
|
||||
}
|
||||
}
|
||||
|
||||
testAPI();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user