diff --git a/lang.h b/lang.h index af4f771..afb5892 100644 --- a/lang.h +++ b/lang.h @@ -132,7 +132,9 @@ typedef enum { LS_EMUS = 120, LS_UPDATE_EMUS = 121, LS_EMUS_PATH = 122, - LS_COUNT = 123 + LS_GAMES = 123, + LS_IMAGES = 124, + LS_COUNT = 125 } LangStrId; static int ui_lang = LANG_EN; @@ -262,6 +264,8 @@ static const char *lang_table[LANG_COUNT][LS_COUNT] = { "Emulatoren", "Emulatoren aus Ordner aktualisieren", "Emulator-Ordner", + "Spiele", + "Images", }, /* EN */ { "running", @@ -386,6 +390,8 @@ static const char *lang_table[LANG_COUNT][LS_COUNT] = { "Emulators", "Update emulators from folder", "Emulators path", + "Games", + "Images", }, /* FR */ { "actif", @@ -511,6 +517,8 @@ static const char *lang_table[LANG_COUNT][LS_COUNT] = { "\u00c9mulateurs", "Mettre \u00e0 jour les \u00e9mulateurs depuis le dossier", "Dossier des \u00e9mulateurs", + "Jeux", + "Images", }, /* ES */ { "activo", @@ -636,6 +644,8 @@ static const char *lang_table[LANG_COUNT][LS_COUNT] = { "Emuladores", "Actualizar emuladores desde la carpeta", "Ruta de emuladores", + "Juegos", + "Im\u00e1genes", } }; diff --git a/main.c b/main.c index 3ef5850..ea2441e 100644 --- a/main.c +++ b/main.c @@ -886,6 +886,33 @@ static int send_elf_to_elfldr(const char *path) { return err ? -3 : 0; } +/* Proxy POST to SM API on port 10101; caller must free() returned string */ +static char *sm_api_post(const char *path, const char *body) { + int sock=socket(AF_INET,SOCK_STREAM,0); if(sock<0) return NULL; + struct timeval tv={3,0}; + setsockopt(sock,SOL_SOCKET,SO_RCVTIMEO,&tv,sizeof(tv)); + setsockopt(sock,SOL_SOCKET,SO_SNDTIMEO,&tv,sizeof(tv)); + struct sockaddr_in addr; memset(&addr,0,sizeof(addr)); + addr.sin_family=AF_INET; addr.sin_port=htons(10101); + addr.sin_addr.s_addr=inet_addr("127.0.0.1"); + if(connect(sock,(struct sockaddr*)&addr,sizeof(addr))!=0){close(sock);return NULL;} + char req[512]; + snprintf(req,sizeof(req),"POST %s HTTP/1.0\r\nHost: 127.0.0.1\r\n" + "Content-Type: application/json\r\nContent-Length: %zu\r\n\r\n%s", + path,strlen(body),body); + send(sock,req,strlen(req),0); + char *buf=malloc(131072); if(!buf){close(sock);return NULL;} + size_t total=0; ssize_t n; + while((n=recv(sock,buf+total,131071-total,0))>0) total+=n; + buf[total]=0; close(sock); + char *bs=strstr(buf,"\r\n\r\n"); + if(!bs){free(buf);return NULL;} bs+=4; + size_t bl=total-(size_t)(bs-buf); + char *result=malloc(bl+1); if(!result){free(buf);return NULL;} + memcpy(result,bs,bl); result[bl]=0; + free(buf); return result; +} + static void fn(struct mg_connection *c, int ev, void *ev_data) { if(ev!=MG_EV_HTTP_MSG) return; struct mg_http_message *hm=(struct mg_http_message*)ev_data; @@ -1107,6 +1134,8 @@ static void fn(struct mg_connection *c, int ev, void *ev_data) { H(""); H("",L(LS_IMG_OVERRIDES)); H("",L(LS_MANUAL)); + H("",L(LS_GAMES)); + H("",L(LS_IMAGES)); H("",L(LS_NOTIFS)); H(""); /* raw panel accessible via button in backup section, no sidebar tab */ @@ -1591,6 +1620,28 @@ static void fn(struct mg_connection *c, int ev, void *ev_data) { H("",L(LS_ADD_ENTRY)); H(""); + /* Panel: Spiele */ + H("
"); + H("
%s
",L(LS_GAMES)); + if(!has_api) H("

ab 1.7alpha3

"); + H("
" + "
"); + H("

%s

",L(LS_LOADING)); + H("
"); + + /* Panel: Images */ + H("
"); + H("
%s
",L(LS_IMAGES)); + if(!has_api) H("

ab 1.7alpha3

"); + H("
" + "
"); + H("

%s

",L(LS_LOADING)); + H("
"); + /* Panel: Debug Log */ H("
"); H("
Log
"); @@ -1697,6 +1748,8 @@ static void fn(struct mg_connection *c, int ev, void *ev_data) { "sessionStorage.setItem('panel',el.getAttribute('data-p'));" "if(el.getAttribute('data-p')==='log')refreshLog();" "if(el.getAttribute('data-p')==='raw'){rawLoad();}" + "if(el.getAttribute('data-p')==='spl')loadGames();" + "if(el.getAttribute('data-p')==='img')loadImages();" "var ct=document.querySelector('.content');if(ct)ct.scrollTop=0;}" /* restore panel after USB-triggered reload */ "var _rp=sessionStorage.getItem('panel');" "if(_rp){var _rb=document.querySelector('.nav-item[data-p=\"'+_rp+'\"]');if(_rb)showP(_rb);}" @@ -1751,7 +1804,56 @@ static void fn(struct mg_connection *c, int ev, void *ev_data) { "if(l){l.textContent=nm;l.title=path;l.style.display='inline';}if(b)b.style.display='inline';}" "setTimeout(refreshStatus,2000);})" ".catch(function(){if(btn)btn.disabled=false;});}""function showElfPicker(btn,paths,cb){var old=document.getElementById('sm-elf-picker');if(old)old.remove();var picker=document.createElement('div');picker.id='sm-elf-picker';picker.style.cssText='position:fixed;top:0;left:0;width:100%%;height:100%%;background:rgba(0,0,0,.75);display:flex;align-items:center;justify-content:center;z-index:9999;';var box=document.createElement('div');box.style.cssText='background:#0d111a;border:1px solid #1e2a42;border-radius:14px;padding:36px;min-width:500px;max-width:800px;';var title=document.createElement('p');title.style.cssText='margin:0 0 20px;font-size:.7rem;text-transform:uppercase;letter-spacing:.12em;color:#64748b;font-family:monospace;';title.textContent=_t.sel_sm;box.appendChild(title);paths.forEach(function(p){var b=document.createElement('button');b.style.cssText='display:block;width:100%%;margin-bottom:10px;padding:16px 18px;border-radius:8px;border:1px solid #1e2a42;background:#131927;color:#e2e8f0;cursor:pointer;text-align:left;font-family:monospace;font-size:.75rem;word-break:break-all;';b.textContent=p;b.onclick=function(){picker.remove();if(cb)cb(p);else launchElf(btn,p);};box.appendChild(b);});var cancel=document.createElement('button');cancel.style.cssText='display:block;width:100%%;padding:14px;border-radius:8px;border:1px solid #1e2a42;background:transparent;color:#64748b;cursor:pointer;font-family:monospace;font-size:.75rem;margin-top:6px;';cancel.textContent=_t.cancel;cancel.onclick=function(){picker.remove();};box.appendChild(cancel);picker.appendChild(box);document.body.appendChild(picker);}""document.querySelector('form').addEventListener('keydown',function(e){""if(e.key==='Enter'&&e.target.tagName!=='BUTTON')e.preventDefault();""});" -"function addPath(){" +"function loadGames(){" + "var el=document.getElementById('games-list');if(!el)return;" + "el.innerHTML='

Lade...

';" + "fetch('/api/sm/games',{method:'POST'}).then(function(r){return r.json();})" + ".then(function(d){" + "if(!d.games||!d.games.length){el.innerHTML='

Keine Spiele gefunden

';return;}" + "var h='';" + "h+='';" + "h+='';" + "h+='';" + "h+='';" + "h+='';" + "d.games.forEach(function(g){" + "var mn=g.mounted?'●':'○';" + "var ba=g.mounted" + "?''" + ":'';" + "h+='';" + "h+='';" + "h+='';" + "h+='';" + "h+='';" + "});h+='
TitelIDMount
'+g.title_name+''+g.title_id+''+mn+''+ba+'
';el.innerHTML=h;})" + ".catch(function(){el.innerHTML='

SM API nicht erreichbar

';});}" + "function mountGame(tid){fetch('/api/sm/games/mount?title_id='+encodeURIComponent(tid),{method:'POST'})" + ".then(function(){setTimeout(loadGames,1500);}).catch(function(){alert(_t.err);});}" + "function unmountGame(tid){fetch('/api/sm/games/unmount?title_id='+encodeURIComponent(tid),{method:'POST'})" + ".then(function(){setTimeout(loadGames,1500);}).catch(function(){alert(_t.err);});}" + "function loadImages(){" + "var el=document.getElementById('images-list');if(!el)return;" + "el.innerHTML='

Lade...

';" + "fetch('/api/sm/images',{method:'POST'}).then(function(r){return r.json();})" + ".then(function(d){" + "if(!d.images||!d.images.length){el.innerHTML='

Keine Images gefunden

';return;}" + "var h='';" + "h+='';" + "h+='';" + "h+='';" + "h+='';" + "d.images.forEach(function(img){" + "var fn=img.path?img.path.split('/').pop():'';" + "var sz=img.size?(img.size>1073741824?(img.size/1073741824).toFixed(1)+' GB':(img.size/1048576).toFixed(0)+' MB'):'?';" + "var st=img.mounted?'●':'○';" + "h+='';" + "h+='';" + "h+='';" + "h+='';" + "});h+='
DateiGr\\u00f6\\u00dfeMount
'+fn+''+sz+''+st+'
';el.innerHTML=h;})" + ".catch(function(){el.innerHTML='

SM API nicht erreichbar

';});}" + "function addPath(){" "var c=document.getElementById('paths-list');" "var d=document.createElement('div');d.className='path-row';" "d.innerHTML='