fixes:
- fixed icon saving - slightly improved library layout
This commit is contained in:
parent
096e36a9fa
commit
f8ce9a9945
4 changed files with 35 additions and 13 deletions
|
|
@ -1678,7 +1678,10 @@ function wireEvents() {
|
|||
if (res.ok) refreshConfigIcon()
|
||||
}
|
||||
qs('#gc-icon-auto').addEventListener('click', async () => {
|
||||
applyIconResult(await window.plwl.gamesAutoIcon(state.currentGame.id))
|
||||
// extract from the exe the field shows, not the saved one - the user may
|
||||
// have just pointed the app at another exe and expects its icon
|
||||
const exe = absGamePathInput(qs('#gc-exe').value.trim(), state.currentGame)
|
||||
applyIconResult(await window.plwl.gamesAutoIcon(state.currentGame.id, exe))
|
||||
})
|
||||
qs('#gc-icon-browse').addEventListener('click', async () => {
|
||||
// start in the app's own folder (prefix apps included) - that is where
|
||||
|
|
|
|||
|
|
@ -490,8 +490,8 @@ select {
|
|||
margin: 1rem 0;
|
||||
}
|
||||
.game-card {
|
||||
flex: 1 1 15rem;
|
||||
min-width: 15rem;
|
||||
flex: 1 1 17rem;
|
||||
min-width: 17rem;
|
||||
max-width: 24rem;
|
||||
background: var(--panel-color);
|
||||
border: var(--border-width) solid var(--light-border-color);
|
||||
|
|
|
|||
|
|
@ -25,10 +25,13 @@ function errorResult(err) {
|
|||
|
||||
const iconDir = id => path.join(DIRS.DATA, 'icons', id)
|
||||
|
||||
function clearIconDir(id) {
|
||||
// `keep` spares one file (the icon just written): the icon protocol picks the
|
||||
// LAST icon.* alphabetically, so a leftover icon.png from an earlier pick
|
||||
// would otherwise keep showing the old icon.
|
||||
function clearIconDir(id, keep) {
|
||||
try {
|
||||
for (const f of fs.readdirSync(iconDir(id))) {
|
||||
if (f.startsWith('icon.')) fs.rmSync(path.join(iconDir(id), f), { force: true })
|
||||
if (f.startsWith('icon.') && f !== keep) fs.rmSync(path.join(iconDir(id), f), { force: true })
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
|
|
@ -36,7 +39,11 @@ function clearIconDir(id) {
|
|||
function extractGameIcon(id, exePath) {
|
||||
const out = path.join(iconDir(id), 'icon.ico')
|
||||
const res = extractIconFromExe(exePath, out)
|
||||
if (res.ok) library.updateGame(id, { iconSource: out })
|
||||
// on failure nothing is cleared, so the previous icon survives a wrong exe
|
||||
if (res.ok) {
|
||||
clearIconDir(id, 'icon.ico')
|
||||
library.updateGame(id, { iconSource: out })
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
|
|
@ -152,11 +159,14 @@ function registerIpc({ getWindow, onGamesChanged }) {
|
|||
if (!game || !game.exePath) return { ok: false, error: 'bad-request' }
|
||||
return extractGameIcon(id, game.exePath)
|
||||
})
|
||||
ipcMain.handle('games:autoIcon', (e, id) => {
|
||||
// exePath comes from the config field, which may hold a path the user just
|
||||
// picked but has not saved yet - the icon has to come from THAT exe
|
||||
ipcMain.handle('games:autoIcon', (e, id, exePath) => {
|
||||
const game = library.getGame(id)
|
||||
if (!game || !game.exePath) return { ok: false, error: 'bad-request' }
|
||||
clearIconDir(id)
|
||||
return extractGameIcon(id, game.exePath)
|
||||
if (!game) return { ok: false, error: 'bad-request' }
|
||||
const exe = exePath || game.exePath
|
||||
if (!exe) return { ok: false, error: 'bad-request' }
|
||||
return extractGameIcon(id, exe)
|
||||
})
|
||||
|
||||
// "Open with PLWL" ------------------------------------------------------------------
|
||||
|
|
@ -253,7 +263,7 @@ function registerIpc({ getWindow, onGamesChanged }) {
|
|||
})
|
||||
|
||||
// game icons as a protocol so the renderer can display them safely ---------------------------
|
||||
protocol.handle('plwl-icon', request => {
|
||||
protocol.handle('plwl-icon', async request => {
|
||||
const id = decodeURIComponent(new URL(request.url).hostname)
|
||||
let file = null
|
||||
try {
|
||||
|
|
@ -265,7 +275,16 @@ function registerIpc({ getWindow, onGamesChanged }) {
|
|||
if (pick) file = path.join(iconDir(id), pick)
|
||||
} catch {}
|
||||
if (!file) return new Response('', { status: 404 })
|
||||
return net.fetch('file://' + file)
|
||||
// a new icon lands at the SAME url, so the browser would keep its cached
|
||||
// copy and the library card would only catch up after a restart - never
|
||||
// let the icon request be cached
|
||||
const res = await net.fetch('file://' + file)
|
||||
return new Response(await res.arrayBuffer(), {
|
||||
headers: {
|
||||
'content-type': res.headers.get('content-type') || 'image/x-icon',
|
||||
'cache-control': 'no-store'
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
return { games }
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ contextBridge.exposeInMainWorld('plwl', {
|
|||
gamesClearPlaytime: id => ipcRenderer.invoke('games:clearPlaytime', id),
|
||||
gamesSetIconFile: (id, p) => ipcRenderer.invoke('games:setIconFile', id, p),
|
||||
gamesExtractIcon: id => ipcRenderer.invoke('games:extractIcon', id),
|
||||
gamesAutoIcon: id => ipcRenderer.invoke('games:autoIcon', id),
|
||||
gamesAutoIcon: (id, exePath) => ipcRenderer.invoke('games:autoIcon', id, exePath),
|
||||
gamesIconPath: id => ipcRenderer.invoke('games:iconPath', id),
|
||||
gamesResetIcon: id => ipcRenderer.invoke('games:resetIcon', id),
|
||||
gamesRemove: id => ipcRenderer.invoke('games:remove', id),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue