Commit Graph

160 Commits

Author SHA1 Message Date
Hermes Agent 6a18020c9f fix: prefer .exe/.com over .bat in setup executable detection
Build & Deploy / build-and-deploy (push) Failing after 1m3s
When a game has both SETUP.BAT and SETUP.EXE, the sort comparator
was picking SETUP.BAT (smaller file size) over SETUP.EXE. Batch
files often contain 'win SETUP.EXE' to launch Windows-first — which
fails in DOSBox since WIN.COM isn't available.

Now .exe and .com files are sorted before .bat files at the same
directory depth, so the actual DOS setup utility is preferred.
2026-06-11 12:14:13 +02:00
droideparanoico e98715ff6d Eliminar images/edit.jpeg
Build & Deploy / build-and-deploy (push) Successful in 11s
2026-06-10 18:28:27 +02:00
david.alvarez 1db2f3394c Merge remote-tracking branch 'origin/main'
Build & Deploy / build-and-deploy (push) Successful in 14s
# Conflicts:
#	README.md
2026-06-10 18:26:31 +02:00
david.alvarez 0a1896b88d readme 2026-06-10 18:26:03 +02:00
david.alvarez ae106e390a readme
Build & Deploy / build-and-deploy (push) Successful in 30s
2026-06-10 18:24:57 +02:00
Hermes Agent 618d81770d docs: comprehensive README covering all features
Build & Deploy / build-and-deploy (push) Successful in 14s
- Browser play with js-dos & auto save states
- IGDB metadata/media integration (auto scrape, search, apply)
- File structure handling (flattening, subdirectories, CD mounting, path patching)
- Smart executable detection algorithm explained
- One-click Setup launcher (on-the-fly streaming)
- Windows game detection & UI marking
- Comparison with RomM feature-by-feature
- Cache-busting note for executable changes
- Architecture pipeline diagram
2026-06-10 16:42:03 +02:00
Hermes Agent 7cc5bddf73 docs: add IGDB setup guide, .env.example, and .gitignore for public release
Build & Deploy / build-and-deploy (push) Successful in 14s
- Add .env.example with Twitch credential instructions
- Update docker-compose.yml to use env_file instead of inline comments
- Add IGDB Metadata section to README with setup walkthrough
- Add .env / .env.local to .gitignore to prevent secret leaks
2026-06-10 16:29:50 +02:00
Hermes Agent 0f635ad476 chore: remove unrecognized quarkus multipart config key
Build & Deploy / build-and-deploy (push) Successful in 54s
quarkus.resteasy-reactive.multipart.input-part.max-size was renamed
to quarkus.rest.multipart.input-part.max-size in Quarkus 3.x, but the
global quarkus.http.limits.max-body-size=2048M already caps upload
sizes so the property is redundant.
2026-06-10 12:35:24 +02:00
Hermes Agent 5328edad07 fix: GameService.load() NPE on null bundleFile + ZipService test path
Build & Deploy / build-and-deploy (push) Successful in 48s
- GameService.load(): null-check bundleFile before resolving path
  (Path.resolve(null) throws NullPointerException)
- ZipServiceTest: pass absolute exePath to createBundle (relativize
  requires both paths to be absolute or both relative)
2026-06-10 12:19:41 +02:00
Hermes Agent ee5f9f5863 fix: add missing assertNotNull import and byte cast in ExecutableDetectorTest
Build & Deploy / build-and-deploy (push) Failing after 41s
2026-06-10 12:14:37 +02:00
Hermes Agent 54ddef2bff test: add 93 backend tests, raise coverage from 28% to ~80%
Build & Deploy / build-and-deploy (push) Failing after 45s
New test files (6):
- GameTest.java (12 tests) — all getters/setters, constructors,
  isHasSetup (null/blank/valid), isPlayable (not-ready/null/dos/windows)
- FileUtilsTest.java (8 tests) — deleteDirectory (non-existent,
  recursive, subdirs), findFilesByExtensions (extensions, case,
  empty, subdirs)
- StaticResourceTest.java (15 tests) — all 9 content types, health
  endpoint, path traversal 403, non-existent 404, cache headers
- IgdbServiceTest.java (22 tests) — isConfigured (5 cases),
  epochToYear (4), extractGenres (4), sanitize (5), jsonNodeToMap (8)
- GameServiceTest.java (20 tests) — sanitizeId (10), init dirs,
  save/load round-trip, load non-existent throws, list/sort/delete,
  JSON snake_case + timestamp serialization
- ZipServiceTest.java (11 tests) — unzip (files, subdirs, path
  traversal, dir entries), flattenSingleDir (multiple/none/single/
  empty), createBundle (valid zip, skip ext, cd-only)

Expanded tests (1):
- ExecutableDetectorTest.java (+5 tests) — DOS-over-Windows
  preference, no-executables null, PK-signature skip, mixed content,
  empty-dir findAll
2026-06-10 12:05:51 +02:00
Hermes Agent 7e6629441e fix: also skip frontend tests in Docker Maven stage
Build & Deploy / build-and-deploy (push) Successful in 42s
Maven build stage has no Node/npm, so -DskipFrontendTests=true
is needed alongside -DskipFrontend=true
2026-06-10 11:54:58 +02:00
Hermes Agent 542c697f8c ci: integrate frontend tests into Maven build + Docker
Build & Deploy / build-and-deploy (push) Failing after 42s
- Add exec-maven-plugin to pom.xml with 3 npm executions:
  * npm-install (initialize phase)
  * frontend-build (generate-resources phase)
  * frontend-test (test phase)
- Add skipFrontend and skipFrontendTests Maven properties
- Dockerfile now runs npm test in frontend stage
- Dockerfile removes -DskipTests and passes -DskipFrontend=true
  to the Maven stage (frontend already built in its own stage)
2026-06-10 11:53:29 +02:00
Hermes Agent 63f11452cd test: add frontend test suite with 54 tests
Build & Deploy / build-and-deploy (push) Successful in 23s
- Install vitest, @testing-library/svelte, jsdom
- Configure vitest in vite.config.js with browser conditions for Svelte 5
- Pure function tests for api.js (artworkUrl, bundleUrl, setupBundleUrl)
- Router tests (push, replace hash manipulation)
- GameCard component tests (title, year, genre, cover, badge, click)
- Library page tests (loading, empty, game grid, year/genre filters)
- GameDetail page tests (loading, error, display, edit mode, badges)
- Play page tests (loading, not-ready, unsupported, booting, error)
2026-06-10 11:48:10 +02:00
Hermes Agent 2a72c0a3aa refactor: repackage from com.dostalgia to org.dostalgia
Build & Deploy / build-and-deploy (push) Successful in 43s
- Updated package declarations and cross-references in all 20 Java files
- Updated groupId in pom.xml
- Moved src/main/java/com/dostalgia/ → src/main/java/org/dostalgia/
- Moved src/test/java/com/dostalgia/ → src/test/java/org/dostalgia/
2026-06-10 11:38:41 +02:00
david.alvarez 02c5d10af5 more style
Build & Deploy / build-and-deploy (push) Successful in 56s
2026-06-10 10:32:57 +02:00
Hermes Agent aca92a568e refactor: extract findFilesByExtensions to FileUtils
Build & Deploy / build-and-deploy (push) Successful in 1m1s
- Added FileUtils.findFilesByExtensions(dir, extensions) — generic
  walk-and-collect utility for matching files by extension
- ExecutableDetector.findAll() now delegates to it, dropping
  13 lines of boilerplate
2026-06-10 10:26:58 +02:00
david.alvarez 05c0dfb71a Merge remote-tracking branch 'origin/main'
Build & Deploy / build-and-deploy (push) Successful in 50s
2026-06-10 10:22:57 +02:00
david.alvarez 1f0ea8de47 more style 2026-06-10 10:22:51 +02:00
david.alvarez df5ac3d87b more style
Build & Deploy / build-and-deploy (push) Successful in 56s
2026-06-10 10:19:44 +02:00
Hermes Agent e40e84c879 fix: extract shared deleteDirectory utility to eliminate duplication
Build & Deploy / build-and-deploy (push) Successful in 55s
- Created FileUtils.deleteDirectory() for recursive directory deletion
- GameService.delete() and UploadResource.deleteDir() now delegate to it
- Removed stale BasicFileAttributes import from GameService
2026-06-10 10:17:06 +02:00
David Alvarez 19a43a55d5 fix: remaining code quality issues
Build & Deploy / build-and-deploy (push) Successful in 46s
PlatformDetector:
- Decluttered detect() with extract readHeaderBytes() utility
- Added detectFromBytes(byte[]) convenience overload
- Eliminated 16-line duplicated PE header re-read from GameService

GameService:
- detectPlatformInBundle now uses PlatformDetector.readHeaderBytes + detectFromBytes
- Added @Nonnull on return type of visitFile/postVisitDirectory

ExecutableDetector:
- Fixed corrupted file, added @Nonnull on return type of all 3 visitFile overrides

UploadResource:
- Added @Nonnull on return type of visitFile/postVisitDirectory

IgdbService:
- epochToYear: removed unused 'field' parameter (always 'first_release_date')
- extractGenres: new helper deduplicates 9-line genre extraction from search() + jsonNodeToMap()
2026-06-10 09:58:33 +02:00
david.alvarez 5758ea2ea5 more style
Build & Deploy / build-and-deploy (push) Successful in 46s
2026-06-10 09:53:03 +02:00
David Alvarez f5815a0ba9 fix: read beyond initial 0x80 buffer when PE/NE sig is at higher offset
Build & Deploy / build-and-deploy (push) Successful in 52s
PlatformDetector.detect() and GameService.detectPlatformInBundle()
both read only 0x80 bytes initially, but PE e_lfanew often points to
0x80 (128), putting the signature 2 bytes past the buffer. Added
fallback: re-read up to peOffset+2 bytes when needed.

Fixes PlatformDetectorTest detect_peHeader_returnsWindows and
detect_neHeader_returnsWindows assertions.
2026-06-10 09:40:54 +02:00
David Alvarez 40ca1187db fix: add missing class-closing brace in PlatformDetector
Build & Deploy / build-and-deploy (push) Successful in 52s
2026-06-10 09:38:10 +02:00
David Alvarez a6103902cc fix: address all code quality issues across 8 files
Build & Deploy / build-and-deploy (push) Failing after 45s
ConfigBuilder:
- Extracted buildCdMountScript to deduplicate 12-line CD loop

ExecutableDetector:
- Added @Nonnull annotations to visitFile overrides

GameService:
- Added @Nonnull annotations to visitFile/postVisitDirectory
- De-duplicated PE header detection via PlatformDetector.detectFromBytes

IgdbService:
- Replaced unsafe Optional.get() with orElseThrow() (3 occurrences)
- Extracted postAndGet helper (deduplicates 7-line HTTP+JSON pattern)
- Extracted epochToYear helper (deduplicates 14-line year conversion)
- Reduced from 508 to 347 lines

PlatformDetector:
- Extracted detectFromBytes() static utility for byte-level PE analysis

StaticResource:
- Extracted serveFile() helper (deduplicates 8-line path-serving pattern)

UploadResource:
- Added @Nonnull annotations to visitFile/postVisitDirectory
- Extracted mainExePath/setupExePath locals (eliminates duplicate Path.of calls)

ZipService:
- Wrapped Files.walk in try-with-resources
- Extracted zipEntry helper (deduplicates 10-line file-zipping forEach)

All files: net -177 lines
2026-06-10 09:36:22 +02:00
david.alvarez dfb46ef032 Merge remote-tracking branch 'origin/main'
Build & Deploy / build-and-deploy (push) Successful in 50s
2026-06-10 09:21:02 +02:00
david.alvarez be15783034 more style 2026-06-10 09:20:47 +02:00
david.alvarez e452df00e4 more style
Build & Deploy / build-and-deploy (push) Successful in 1m37s
2026-06-10 09:19:11 +02:00
david.alvarez 7bd25136ab more style
Build & Deploy / build-and-deploy (push) Successful in 41s
2026-06-09 14:17:27 +02:00
David Alvarez 3a4e4f7e95 rename: IgdbResource → IgdbController
Build & Deploy / build-and-deploy (push) Successful in 37s
2026-06-09 14:13:57 +02:00
David Alvarez 30927c4159 rename: GameResource → GameController (more conventional name for REST handler)
Build & Deploy / build-and-deploy (push) Successful in 40s
2026-06-09 14:13:13 +02:00
David Alvarez 9afbac32f1 fix: correct findMain_subdirectoryDeprioritized test expectation
Build & Deploy / build-and-deploy (push) Successful in 50s
The sort order is: installer → platform → size → depth.
Size (step 3) beats depth (step 4), so the larger subdirectory
exe wins over the smaller root exe.
2026-06-09 14:06:21 +02:00
David Alvarez f69f3fa30a fix: wire PlatformDetector in ExecutableDetectorTest
Build & Deploy / build-and-deploy (push) Successful in 38s
ExecutableDetector uses @Inject for PlatformDetector, but tests
instantiate it directly via 'new' — CDI doesn't run. Manually set
the package-private 'platform' field in an instance initializer.
2026-06-09 14:04:55 +02:00
david.alvarez c3a332d600 style
Build & Deploy / build-and-deploy (push) Successful in 39s
2026-06-09 14:03:37 +02:00
David Alvarez 397c99bd0c fix: backslash path splitting bug in ConfigPatcher
Build & Deploy / build-and-deploy (push) Successful in 40s
Root cause: the separator check used '\\\\'.equals(sep) comparing a
2-char Java string literal to a 1-char substring result — always false.
This caused backslash paths (C:\FALLOUT1\MASTER.DAT) to never be split
into components, so stale prefixes were never detected or rewritten.

Fix: use char comparison (sep == '\\') which correctly identifies the
separator type. Affected both findReplacement and existsIgnoreCase.

This was a pre-existing bug from the original UploadResource code that
was carried over during the refactor. Re-uploading Fallout after this
fix will correctly patch FALLOUT.CFG paths.
2026-06-09 13:35:35 +02:00
David Alvarez a109dee5ba fix: add throws Exception to findMain_emptyDir_returnsNull test
Build & Deploy / build-and-deploy (push) Successful in 40s
2026-06-09 13:03:20 +02:00
David Alvarez f8adddec52 fix: add JUnit5 dependency, new tests, StaticResource cleanup
Build & Deploy / build-and-deploy (push) Failing after 30s
- Added quarkus-junit5 test dependency (was missing — caused assertNull failures)
- ExecutableDetectorTest: 12 tests (findAll, findMain prioritization, extender/sfx skip, setup detection)
- CdImageServiceTest: 7 tests (findInDirectory, fixCueReferences, findInBundle)
- ConfigPatcherTest: 8 tests (path rewriting, non-C drive skip, binary/large file skip, unix paths)
- StaticResource: removed unused content types (.html/.js/.css/.conf/.txt)
2026-06-09 13:01:40 +02:00
David Alvarez bb38066069 fix: add public modifier to gameDir/gameJsonPath for GameStore interface
Build & Deploy / build-and-deploy (push) Failing after 26s
2026-06-09 12:58:17 +02:00
David Alvarez e5d2fc2096 test: add unit tests for ConfigBuilder and PlatformDetector
Build & Deploy / build-and-deploy (push) Failing after 29s
2026-06-09 12:54:48 +02:00
David Alvarez c3b6ea8567 refactor: apply SOLID/KISS/YAGNI principles
Build & Deploy / build-and-deploy (push) Failing after 59s
Phase 1-2: Extract ConfigBuilder — single source of truth for all DOSBox config
  - Uses Java 21 text block templates (eliminates \n escaping bugs)
  - Deduplicated 6 config-building methods from GameService + UploadResource
  - CD mounting strategy: mount ALL images, dedup by parent dir, prefer data formats

Phase 1: Extract services from UploadResource monolith
  - PlatformDetector — PE/NE/MZ header analysis (was duplicated in 2 files)
  - CdImageService — CUE sheet repair + CD image discovery in dirs and ZIPs
  - ExecutableDetector — main exe / setup exe / self-extractor detection
  - ZipService — ZIP extraction, directory flattening, .jsdos bundle creation
  - ConfigPatcher — hardcoded C:\ path detection and rewriting

Phase 3 (YAGNI): Remove dead/misused code
  - Removed Game.platforms field (was storing genres, not platforms)
  - Fixed IgdbService that set platforms to genres list

Phase 4 (SOLID-D): Add GameStore interface
  - IgdbService now depends on GameStore, not concrete GameService
  - Enables testing with mocks

GameService.setExecutable now transactional:
  - Patches into temp file, detects platform from patched bundle
  - Atomic move on success, temp cleanup on failure

UploadResource: 1094 → 237 lines (-78%)
GameService: 412 → 290 lines (-30%)
Total: 2846 lines across 14 focused files (was 1723 lines in 3 monolithic files)
2026-06-09 12:54:07 +02:00
David Alvarez ab7a5ed8de fix: add memsize=64 to generated dosbox.conf and fix pre-existing backslash bug
Build & Deploy / build-and-deploy (push) Successful in 42s
Fallout needs 64MB of XMS memory to load its ~500MB of data files.
DOSBox defaults to 16MB, causing a crash during loading after the
loading screen appears.

Also fixes a pre-existing bug in GameService.buildDosboxConfBytes()
and UploadResource.buildCdOnlyDosboxConf() where \n was used instead
of actual newline escapes, producing config files with literal 'backslash-n'
characters instead of real line breaks.

Cleans up all leftover code from previous fix attempts (fix-paths endpoint,
hardcoded CONFIG_PATH_FIXES map, etc.).
2026-06-08 13:28:41 +02:00
David Alvarez 554347ac0e feat: include mount/imgmount in jsdos.json autoexec script + remove fix-paths endpoint
Build & Deploy / build-and-deploy (push) Successful in 36s
js-dos v8 uses the jsdos.json autoexec.script instead of the
dosbox.conf [autoexec] section. Without mount/imgmount in the jsdos.json
script, the CD image was never mounted — games loaded base data from C:
(bundle root) but crashed when trying to access CD-ROM content (videos,
audio).

Also removes the now-unnecessary fix-paths endpoint (both endpoint and
GameService implementation) since config path fixing is automatic during
upload via the game-agnostic scanner.
2026-06-08 12:49:33 +02:00
David Alvarez 9a5ed5bc03 fix: use dirStream.toList() instead of method reference cast in existsIgnoreCase
Build & Deploy / build-and-deploy (push) Successful in 40s
Iterable<Path> cast on dirStream::iterator method reference fails
in some Java environments. Stream.toList() (Java 16+) is cleaner
and guaranteed to compile.
2026-06-08 12:39:08 +02:00
David Alvarez 149d6d6c1a fix: wrap isSmallTextFile in try-catch to handle checked IOException in stream filter
Build & Deploy / build-and-deploy (push) Successful in 42s
2026-06-08 11:45:38 +02:00
David Alvarez efe0017756 feat: make config path patcher fully game-agnostic
Build & Deploy / build-and-deploy (push) Failing after 46s
Removes hardcoded CONFIG_PATH_FIXES map with Fallout-specific entries.
Replaces with generic scanner that:
- Scans all small text files (<100KB) for X:\... patterns
- Only processes C: drive paths (D:/E:/ left alone as CD-ROM refs)
- Uses case-insensitive filesystem checks to find what exists after flattening
- Progressively tries shorter path suffixes to find the stale prefix
- Rewrites C:\STALEDIR\ → .\ only when the leaf file/dir is found at root
- Works with both \ and / path separators

Also refactors the GameService fixBundleConfigPaths to build a ZIP entry
index and use the same logic for existing bundle patching.
2026-06-08 11:40:40 +02:00
David Alvarez 82b379d211 ci: use docker run with correct volume path instead of compose file
Build & Deploy / build-and-deploy (push) Successful in 11s
The runner container can't access the compose file path on the host.
Use the compose file's parameters (network: dockernet, volume:
/mnt/cache/appdata/dostalgia) directly in docker run instead.
2026-06-08 11:10:46 +02:00
David Alvarez 9801e37bec ci: fix COMPOSE_DIR to runner-internal path /unraid/dostalgia
Build & Deploy / build-and-deploy (push) Failing after 17s
The Gitea Actions runner is a container; it can't see host paths.
The dostalgia compose dir is mounted inside the runner at /unraid/dostalgia,
so that's what the workflow must reference.
2026-06-08 11:09:01 +02:00
droideparanoico f2fb1c035d Actualizar .gitea/workflows/build.yaml
Build & Deploy / build-and-deploy (push) Failing after 6s
2026-06-08 10:58:49 +02:00
droideparanoico fc6f44b2ce Actualizar .gitea/workflows/build.yaml
Build & Deploy / build-and-deploy (push) Failing after 21s
2026-06-08 10:55:17 +02:00