feat(p4): brancher media_manager + /game/file sur /sdcard
CI / platformio (pull_request) Failing after 3m39s

- media_manager resolve_play_path : un chemin relatif préfère désormais
  /sdcard/music/<f> quand il existe (asset store SD), fallback LittleFS.
  Les chemins absolus (/sdcard/... | /littlefs/...) passent inchangés.
- /game/file : route le préfixe `sd/<…>` → /sdcard/<…> (≤8 Mio, exige la
  carte montée) en plus de `apps/<…>` → /littlefs/apps/ (≤256 Kio).
- sd_storage.h : include <stdint.h> (uint32_t).

Validé sur Freenove : POST /game/file?path=sd/music/cue440.wav → écrit sur
la microSD ; POST /game/media/play {path:"cue440.wav"} → résolu en
/sdcard/music/cue440.wav, 32000 B streamés en ~1005 ms au MAX98357A.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
clement
2026-06-13 16:28:16 +02:00
parent a8f0210567
commit 8a58c7d92b
4 changed files with 41 additions and 14 deletions
@@ -16,6 +16,7 @@ idf_component_register(
joltwallet__littlefs
puzzle_state
media_manager
sd_storage
PRIV_REQUIRES
local_puzzles
)
@@ -19,6 +19,7 @@
#include "esp_littlefs.h"
#include "esp_log.h"
#include "media_manager.h"
#include "sd_storage.h"
#include "esp_system.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
@@ -1001,22 +1002,36 @@ static esp_err_t handle_file_post(httpd_req_t *req) {
sizeof(path_param)) != ESP_OK) {
return send_error(req, "400 Bad Request", "missing path param");
}
if (strncmp(path_param, "apps/", 5) != 0 || strstr(path_param, "..") ||
// Route: apps/<…> → /littlefs/apps/<…> (display shell tiles, ≤256 KiB);
// sd/<…> → /sdcard/<…> (P4 large assets: audio, images).
const bool to_sd = (strncmp(path_param, "sd/", 3) == 0);
const bool to_apps = (strncmp(path_param, "apps/", 5) == 0);
if ((!to_sd && !to_apps) || strstr(path_param, "..") ||
path_param[strlen(path_param) - 1] == '/') {
return send_error(req, "403 Forbidden", "path must be under apps/");
return send_error(req, "403 Forbidden", "path must be under apps/ or sd/");
}
if (req->content_len <= 0 ||
req->content_len > GAME_ENDPOINT_MAX_FILE_BYTES) {
return send_error(req, "400 Bad Request", "size 1..262144 bytes");
}
if (mount_storage_lazy() != ESP_OK) {
return send_error(req, "503 Service Unavailable", "storage_unavailable");
const long max_bytes = to_sd ? (8L * 1024 * 1024) : GAME_ENDPOINT_MAX_FILE_BYTES;
if (req->content_len <= 0 || (long) req->content_len > max_bytes) {
return send_error(req, "400 Bad Request", "file too large");
}
char full[160];
snprintf(full, sizeof(full), "/littlefs/%s", path_param);
char full[192];
size_t root_len;
if (to_sd) {
if (!sd_storage_ready()) {
return send_error(req, "503 Service Unavailable", "sd_not_mounted");
}
snprintf(full, sizeof(full), "/sdcard/%s", path_param + 3); // strip "sd/"
root_len = strlen("/sdcard/");
} else {
if (mount_storage_lazy() != ESP_OK) {
return send_error(req, "503 Service Unavailable", "storage_unavailable");
}
snprintf(full, sizeof(full), "/littlefs/%s", path_param);
root_len = strlen("/littlefs/");
}
// mkdir -p for intermediate directories.
for (char *p = full + strlen("/littlefs/"); *p; p++) {
for (char *p = full + root_len; *p; p++) {
if (*p == '/') {
*p = '\0';
mkdir(full, 0775); // EEXIST is fine
@@ -158,10 +158,20 @@ static void resolve_play_path(char *out, size_t out_len, const char *path) {
return;
}
if (path[0] == '/') {
copy_text(out, out_len, path);
} else {
snprintf(out, out_len, "%s/%s", s_media.config.music_dir, path);
copy_text(out, out_len, path); // absolute: /sdcard/... or /littlefs/...
return;
}
// Relative cue: prefer the microSD copy when present (P4 — large asset
// store), else fall back to the LittleFS music_dir. file_exists() returns
// false when no card is mounted, so this is transparent without a hard
// dependency on sd_storage.
char sd_try[MEDIA_PATH_MAX];
snprintf(sd_try, sizeof(sd_try), "/sdcard/music/%s", path);
if (file_exists(sd_try)) {
copy_text(out, out_len, sd_try);
return;
}
snprintf(out, out_len, "%s/%s", s_media.config.music_dir, path);
}
static void sanitize_filename(char *out, size_t out_len,
@@ -8,6 +8,7 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include "esp_err.h"
#ifdef __cplusplus