Add albums support, API layer, and Docker improvements

- Add albums browsing and navigation (src/albums.c, src/app.c)
- Extract API calls into dedicated src/api.c module
- Improve display and UI components
- Update CMakeLists.txt to include new source files
- Refactor Dockerfile for better build process

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
nino
2026-10-23 14:11:00 -06:00
co-authored by Claude Sonnet 4.6
parent f4cf235c40
commit 07890191cf
10 changed files with 1070 additions and 44 deletions
+69
View File
@@ -121,6 +121,46 @@ static char g_srv_version[40]; /* "v1.119.0" */
static volatile int g_pause_bg; /* request the sync thread to idle */
static volatile int g_sync_idle; /* sync thread acknowledges it idled */
/* ---- albums (read-only browsing) ------------------------------------ */
/* The album LIST lives in the g_album_* arrays, filled by GET /api/albums on
* a worker thread (the main thread only draws a throbber meanwhile). Each
* entry keeps the server's own ordering.
*
* Opening an album switches the grid to that album's assets, exactly like the
* smart-search result set: g_album_active marks the filter and g_album_idx
* holds indices into the g_asset_* arrays (which only ever grow). The members
* are fetched page by page with /api/search/metadata (withExif, so they carry
* date + aspect and drop straight into month sections).
*
* g_album_state: 0 not fetched yet, 1 ok, -1 failed. g_album_fetching: a
* worker thread is fetching the list right now. */
static char (*g_album_id)[40]; /* album uuid */
static char (*g_album_name)[64]; /* display name */
static char (*g_album_thumb)[40]; /* cover asset id, "" when none */
static int *g_album_nassets; /* assetCount reported by the server */
static unsigned char *g_album_shared; /* shared with other users */
static unsigned char *g_album_has_link; /* has a public share link */
static int g_album_len; /* number of albums fetched */
static int g_album_cap;
static int g_album_state;
static volatile int g_album_fetching;
static int g_album_active; /* grid is showing one album's assets */
static int g_album_open = -1; /* index into g_album_* being shown */
static int *g_album_idx; /* g_asset indices of its members */
static int g_album_idx_count;
static int g_album_idx_cap;
/* open-album fetch (worker thread): done flag, result, members so far */
static volatile int g_album_assets_done;
static volatile int g_album_assets_result;
static volatile int g_album_assets_loaded;
/* each album's cover as a g_asset index (asset_for_id), so the shared
* thumbnail worker loads it into g_thumb[] like any grid thumbnail.
* -1 = no cover (empty album) or not resolved yet. */
static int *g_album_cover;
/* Texture recycling pool. Freeing a texture unmaps its memblock, and the
* GPU side (notably Vita3K's texture cache, which re-reads guest memory of
* cached textures at its own pace) may still touch it afterwards — freeing
@@ -249,6 +289,35 @@ static int grow_gallery(int need)
return 1;
}
/* ensure the album arrays hold at least `need` entries */
static int grow_albums(int need)
{
int c = g_album_cap;
if (need <= c)
return 1;
if (!GROW(g_album_id, c, need) ||
!GROW(g_album_name, c, need) ||
!GROW(g_album_thumb, c, need) ||
!GROW(g_album_nassets, c, need) ||
!GROW(g_album_shared, c, need) ||
!GROW(g_album_has_link, c, need) ||
!(g_album_cap = GROW(g_album_cover, c, need)))
return 0;
return 1;
}
/* ensure an open album's member index array holds at least `need` entries */
static int grow_album_idx(int need)
{
if (need <= g_album_idx_cap)
return 1;
int cap = GROW(g_album_idx, g_album_idx_cap, need);
if (!cap)
return 0;
g_album_idx_cap = cap;
return 1;
}
static void log_line(const char *fmt, ...)
{
FILE *f = fopen(LOG_PATH, "a");