diff --git a/.gitignore b/.gitignore index a697b3b..f3224d7 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,5 @@ partitions/.svelte-kit/ partitions/build/ partitions/node_modules/ partitions/static/pdf.worker.min.js -partitions/.env api/vendor/ api/composer.phar -api/.env diff --git a/api/index.php b/api/index.php index 2216829..0a49395 100644 --- a/api/index.php +++ b/api/index.php @@ -343,6 +343,24 @@ if (preg_match('#^admin/scores/(\d+)$#', $path, $matches) && $method === 'PUT') exit; } +// PUT /admin/scores/:id/pieces - Update pieces +if (preg_match('#^admin/scores/(\d+)/pieces$#', $path, $matches) && $method === 'PUT') { + $scoreId = $matches[1]; + $input = json_decode(file_get_contents('php://input'), true); + + $pieces = $input['pieces'] ?? []; + + $result = $scanner->updatePieces($scoreId, $pieces); + + if ($result['success']) { + echo json_encode(['success' => true]); + } else { + http_response_code(400); + echo json_encode(['error' => $result['error']]); + } + exit; +} + // DELETE /admin/scores/:id - Delete score if (preg_match('#^admin/scores/(\d+)$#', $path, $matches) && $method === 'DELETE') { $scoreId = $matches[1]; diff --git a/api/lib/ScoreScanner.php b/api/lib/ScoreScanner.php index 97438c3..2fd01e2 100644 --- a/api/lib/ScoreScanner.php +++ b/api/lib/ScoreScanner.php @@ -489,6 +489,47 @@ class ScoreScanner { return ['success' => true]; } + public function updatePieces(string $scoreId, array $pieces): array { + $scoreDir = $this->scoresPath . $scoreId; + $iniFile = $scoreDir . '/score.ini'; + + if (!file_exists($iniFile)) { + return ['success' => false, 'error' => 'Score not found']; + } + + $ini = @parse_ini_file($iniFile, true); + if ($ini === false) { + return ['success' => false, 'error' => 'Failed to parse score.ini']; + } + + // Get existing info + $name = $ini['info']['name'] ?? ''; + $compositor = $ini['info']['compositor'] ?? ''; + $ressource = $ini['info']['ressource'] ?? ''; + + // Rebuild ini content with new pieces + $content = "[info]\n"; + $content .= "name = $name\n"; + $content .= "compositor = $compositor\n"; + if ($ressource) { + $content .= "ressource = $ressource\n"; + } + $content .= "\n[pieces]\n"; + $content .= "count = " . count($pieces) . "\n"; + + foreach ($pieces as $piece) { + $num = $piece['number'] ?? $piece['id']; + $pieceName = $piece['name'] ?? ''; + $content .= "$num = $pieceName\n"; + } + + if (file_put_contents($iniFile, $content) === false) { + return ['success' => false, 'error' => 'Failed to write score.ini']; + } + + return ['success' => true]; + } + public function deleteScore(string $scoreId): array { $scoreDir = $this->scoresPath . $scoreId; diff --git a/partitions/src/lib/api.ts b/partitions/src/lib/api.ts index a94ff9f..6553133 100644 --- a/partitions/src/lib/api.ts +++ b/partitions/src/lib/api.ts @@ -136,6 +136,15 @@ export const apiService = { return response.data; }, + async updatePieces(id: string, pieces: { id: string; name: string }[]): Promise<{ success: boolean; error?: string }> { + const formattedPieces = pieces.map((p, i) => ({ + number: i + 1, + name: p.name || `Partie ${i + 1}` + })); + const response = await api.put(`/admin/scores/${id}/pieces`, { pieces: formattedPieces }); + return response.data; + }, + async deleteScore(id: string): Promise<{ success: boolean; error?: string }> { const response = await api.delete(`/admin/scores/${id}`); return response.data; diff --git a/partitions/src/routes/admin/[id]/+page.svelte b/partitions/src/routes/admin/[id]/+page.svelte index 947c37a..cde8f3e 100644 --- a/partitions/src/routes/admin/[id]/+page.svelte +++ b/partitions/src/routes/admin/[id]/+page.svelte @@ -61,6 +61,29 @@ let uploadWatermark = $state(false); let uploadWatermarkPosition = $state<'left' | 'right'>('left'); + // Edit pieces + let editingPieces = $state(false); + let piecesEdit = $state<{id: string; name: string}[]>([]); + let savingPieces = $state(false); + + async function savePieces() { + savingPieces = true; + try { + const result = await apiService.updatePieces(scoreId, piecesEdit); + if (result.success) { + selectedScorePieces = [...piecesEdit]; + editingPieces = false; + } else { + alert('Erreur: ' + result.error); + } + } catch (err) { + console.error(err); + alert('Erreur lors de la sauvegarde'); + } finally { + savingPieces = false; + } + } + // Auto-set default key when instrument changes $effect(() => { if (uploadInstrument) { @@ -375,6 +398,53 @@ + + +
+
+

Parties ({selectedScorePieceCount})

+ {#if !editingPieces} + + {/if} +
+
+ {#if editingPieces} +
+ {#each piecesEdit as piece, i} +
+ #{i + 1} + + +
+ {/each} + +
+ + +
+
+ {:else} +
+ {#each selectedScorePieces as piece} + {piece.name || `Partie ${piece.id}`} + {/each} +
+ {/if} +
+
{#if error}