From eebd3a700fd849a3d38c79d1131ac3d16b1cff18 Mon Sep 17 00:00:00 2001 From: KarnerF Date: Sun, 30 Aug 2026 12:54:52 +0200 Subject: [PATCH] Add /api/local/games filesystem scan fallback; extract renderGamesList(); title_id from /data/homebrew/ symlinks --- main.c | 104 ++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 80 insertions(+), 24 deletions(-) diff --git a/main.c b/main.c index 0560de1..87433bd 100644 --- a/main.c +++ b/main.c @@ -1780,32 +1780,17 @@ static void fn(struct mg_connection *c, int ev, void *ev_data) { "if(!gd||gd.error||gd.status){" "gl.innerHTML='

SM API nicht erreichbar — l\\u00e4uft ShadowMountPlus?

';}" "else if(!gd.games||!gd.games.length){" - "if(_gpR<3){" - "gl.innerHTML='

Warte auf SM... ('+(_gpR+1)+'/3)

';" - "setTimeout(function(){loadGamePanel(_gpR+1);},5000);" + "if(_gpR<2){" + "gl.innerHTML='

Warte auf SM... ('+(_gpR+1)+'/2)

';" + "setTimeout(function(){loadGamePanel(_gpR+1);},4000);" "}else{" - "gl.innerHTML='

Keine Spiele — SM scan noch aktiv?

';" + "fetch('/api/local/games').then(function(r){return r.json();})" + ".then(function(ld){" + "if(ld.games&&ld.games.length)renderGamesList(gl,ld.games);" + "else gl.innerHTML='

Keine Spiele — noch nichts gemountet?

';" + "}).catch(function(){gl.innerHTML='

Keine Spiele gefunden

';});" "}}" - "else{_gpR=0;var h='';" - "gd.games.forEach(function(g){" - "var tid=g.title_id||'';" - "var mn=g.mounted" - "?'● aktiv'" - ":'○ inaktiv';" - "var ba=g.mounted" - "?''" - ":'';" - "var ip2=g.image_path?'
'+g.image_path+'
':'';" - "h+='
';" - "h+='';" - "h+='
';" - "h+='
'+(g.title_name||tid)+'
';" - "h+='
'+tid+'
';" - "h+=ip2+'
';" - "h+='
'+mn+ba+'
';" - "});gl.innerHTML=h;}" + "else{_gpR=0;renderGamesList(gl,gd.games);}" "if(!il)return;" "if(!id||id.error||id.status){" "il.innerHTML='

'+(id&&id.error?id.error:'nicht erreichbar')+'

';return;}" @@ -1836,6 +1821,29 @@ static void fn(struct mg_connection *c, int ev, void *ev_data) { "ih+=''+iba+'';" "});ih+='';il.innerHTML=ih;});}" "function loadGames(){loadGamePanel(0);}" + "function renderGamesList(el,games){" + "if(!el||!games||!games.length){if(el)el.innerHTML='

Keine Spiele gefunden

';return;}" + "var h='';" + "games.forEach(function(g){" + "var tid=g.title_id||'';" + "var mn=g.mounted" + "?'● aktiv'" + ":'○ inaktiv';" + "var ba=g.mounted" + "?''" + ":'';" + "var sp=g.source_path||g.image_path||'';" + "var ip2=sp?'
'+sp+'
':'';" + "h+='
';" + "h+='';" + "h+='
';" + "h+='
'+(g.title_name||tid)+'
';" + "h+='
'+tid+'
';" + "h+=ip2+'
';" + "h+='
'+mn+ba+'
';" + "});el.innerHTML=h;}" "function mountGame(tid){" "var el=document.getElementById('games-list');" "if(el)el.innerHTML='

Mounting '+tid+'...

';" @@ -2867,6 +2875,54 @@ static void fn(struct mg_connection *c, int ev, void *ev_data) { write_prefs(&p); mg_http_reply(c,200,"Content-Type: application/json\r\n","{\"ok\":true}"); } + else if(mg_match(hm->uri,mg_str("/api/local/games"),NULL)){ + /* filesystem scan: /data/homebrew/ entries whose names are PS5 title IDs */ + char *out=malloc(65536); if(!out){mg_http_reply(c,500,"","");return;} + int pos=0; + #define AP(fmt,...) pos+=snprintf(out+pos,65535-pos,fmt,##__VA_ARGS__) + AP("{\"games\":["); + int first=1; + static const char *scan_dirs[]= + {"/data/homebrew","/data/etaHEN/games","/mnt/ext0/homebrew",NULL}; + /* track which title_ids we've already emitted */ + char seen[64][10]; int nseen=0; + for(int di=0;scan_dirs[di]&&pos<60000;di++){ + DIR *d=opendir(scan_dirs[di]); if(!d) continue; + struct dirent *de; + while((de=readdir(d))!=NULL&&pos<60000){ + const char *nm=de->d_name; + /* PS5 title ID: exactly 9 alnum chars, first 4 alpha, last 5 digit */ + if(strlen(nm)!=9) continue; + int ok=1; + for(int i=0;i<4;i++) if(!isalpha((unsigned char)nm[i])){ok=0;break;} + for(int i=4;i<9;i++) if(!isdigit((unsigned char)nm[i])){ok=0;break;} + if(!ok) continue; + /* dedup across directories */ + int dup=0; + for(int s=0;suri,mg_str("/api/game/icon"),NULL)){ char tid[64]={0}; mg_http_get_var(&hm->query,"title_id",tid,sizeof(tid)); /* sanitise: only alphanumeric title IDs allowed */