fix (i hope) all bugs
This commit is contained in:
parent
e8cd664965
commit
201f9d7a7e
11 changed files with 195 additions and 37 deletions
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
const fsp = require('fs').promises
|
||||
const path = require('path')
|
||||
const { DIRS } = require('./paths')
|
||||
const { newGame } = require('./library')
|
||||
const { dedupeDir } = require('./fsutil')
|
||||
const { DIRS, resolvePortablePath } = require('./paths')
|
||||
const { newGame, newGameId, addGame } = require('./library')
|
||||
const { extractIconFromExe } = require('./icons')
|
||||
|
||||
// Directories that typically hold installers/redistributables, not the game.
|
||||
const SKIPPED_DIRS = new Set(['redist', 'directx', '_commonredist', 'support', 'dotnet', 'vc'])
|
||||
|
|
@ -33,21 +33,53 @@ function moveFolder(src, dst, onProgress) {
|
|||
|
||||
async function importGame(srcDir, mode, onProgress) {
|
||||
const name = path.basename(srcDir)
|
||||
// Validate before touching the user's files: refuse an import without any
|
||||
// .exe (and don't half-move a folder we'd then have to roll back).
|
||||
const preExe = await findDefaultExe(srcDir)
|
||||
if (!preExe) return { ok: false, error: 'no-exe-found' }
|
||||
// The id doubles as the imported folder name, so generate it first and
|
||||
// create files/apps/<id> - no dedupe suffixes, ids can never collide.
|
||||
const id = newGameId()
|
||||
let workdir = srcDir
|
||||
if (mode === 'copy' || mode === 'move') {
|
||||
const dst = dedupeDir(DIRS.APPS, name)
|
||||
const dst = path.join(DIRS.APPS, id)
|
||||
if (mode === 'copy') await copyRecursive(srcDir, dst, onProgress)
|
||||
else await moveFolder(srcDir, dst, onProgress)
|
||||
workdir = dst
|
||||
}
|
||||
const exePath = await findDefaultExe(workdir)
|
||||
return newGame({ name, exePath, workdir, mode })
|
||||
const exePath = (await findDefaultExe(workdir)) || preExe
|
||||
if (!exePath) {
|
||||
return { ok: false, error: 'no-exe-found' }
|
||||
}
|
||||
const game = newGame({ id, name, exePath, workdir, mode })
|
||||
game.imported = mode === 'copy' || mode === 'move'
|
||||
// the exe was picked automatically -> grab its icon right away; a missing
|
||||
// icon is not an import failure (game can still get one from config)
|
||||
const icon = path.join(DIRS.DATA, 'icons', id, 'icon.ico')
|
||||
if (extractIconFromExe(resolvePortablePath(exePath), icon).ok) {
|
||||
game.iconSource = icon
|
||||
}
|
||||
return addGame(game)
|
||||
}
|
||||
|
||||
// Largest .exe in the tree, skipping redistributable folders.
|
||||
// Largest .exe in the tree, skipping redistributable folders. Files are
|
||||
// stat'ed in parallel and folders walked breadth-first so big games don't
|
||||
// turn the picker into a sequential crawl.
|
||||
async function findDefaultExe(dir) {
|
||||
let best = ''
|
||||
let bestSize = -1
|
||||
const pending = []
|
||||
const consider = full => {
|
||||
const size = fsp.stat(full).then(st => st.size).catch(() => -1)
|
||||
pending.push(
|
||||
size.then(sz => {
|
||||
if (sz > bestSize) {
|
||||
best = full
|
||||
bestSize = sz
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
const walk = async d => {
|
||||
let entries = []
|
||||
try {
|
||||
|
|
@ -55,20 +87,19 @@ async function findDefaultExe(dir) {
|
|||
} catch {
|
||||
return
|
||||
}
|
||||
const subdirs = []
|
||||
for (const e of entries) {
|
||||
const full = path.join(d, e.name)
|
||||
if (e.isDirectory()) {
|
||||
if (!SKIPPED_DIRS.has(e.name.toLowerCase())) await walk(full)
|
||||
if (!SKIPPED_DIRS.has(e.name.toLowerCase())) subdirs.push(full)
|
||||
} else if (e.name.toLowerCase().endsWith('.exe')) {
|
||||
const size = await fsp.stat(full).then(st => st.size).catch(() => -1)
|
||||
if (size > bestSize) {
|
||||
best = full
|
||||
bestSize = size
|
||||
}
|
||||
consider(full)
|
||||
}
|
||||
}
|
||||
await Promise.all(subdirs.map(walk))
|
||||
}
|
||||
await walk(dir)
|
||||
await Promise.all(pending)
|
||||
return best
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue