feat: complete download acquisition, publisher catalog browsing, and dependency management - #265
feat: complete download acquisition, publisher catalog browsing, and dependency management#265undead2146 wants to merge 135 commits into
Conversation
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
Docstrings generation was requested by @undead2146. * #265 (comment) The following files were modified: * `GenHub/GenHub.Core/Interfaces/Providers/IPublisherCatalogParser.cs` * `GenHub/GenHub.Core/Interfaces/Providers/IPublisherCatalogRefreshService.cs` * `GenHub/GenHub.Core/Interfaces/Providers/IPublisherSubscriptionStore.cs` * `GenHub/GenHub.Core/Interfaces/Providers/IVersionSelector.cs` * `GenHub/GenHub.Core/Models/Manifest/ManifestIdGenerator.cs` * `GenHub/GenHub/App.axaml.cs` * `GenHub/GenHub/Common/ViewModels/MainViewModel.cs` * `GenHub/GenHub/Common/Views/MainWindow.axaml.cs` * `GenHub/GenHub/Features/Content/Services/Catalog/GenericCatalogDiscoverer.cs` * `GenHub/GenHub/Features/Content/Services/Catalog/GenericCatalogResolver.cs` * `GenHub/GenHub/Features/Content/Services/Catalog/JsonPublisherCatalogParser.cs` * `GenHub/GenHub/Features/Content/Services/Catalog/PublisherCatalogRefreshService.cs` * `GenHub/GenHub/Features/Content/Services/Catalog/PublisherSubscriptionStore.cs` * `GenHub/GenHub/Features/Content/Services/Catalog/VersionSelector.cs` * `GenHub/GenHub/Features/Content/Services/CommunityOutpost/GenPatcherDatCatalogParser.cs` * `GenHub/GenHub/Features/Content/Services/ContentCacheService.cs` * `GenHub/GenHub/Features/Content/Services/ContentDiscoverers/AODMapsDiscoverer.cs` * `GenHub/GenHub/Features/Content/Services/ContentDiscoverers/FileSystemDiscoverer.cs` * `GenHub/GenHub/Features/Content/Services/ContentDiscoverers/ModDBDiscoverer.cs` * `GenHub/GenHub/Features/Content/Services/ContentOrchestrator.cs` * `GenHub/GenHub/Features/Content/Services/ContentResolvers/AODMapsResolver.cs` * `GenHub/GenHub/Features/Content/Services/ContentResolvers/CNCLabsMapResolver.cs` * `GenHub/GenHub/Features/Content/Services/ContentResolvers/ModDBResolver.cs` * `GenHub/GenHub/Features/Content/Services/GeneralsOnline/GeneralsOnlineDiscoverer.cs` * `GenHub/GenHub/Features/Content/Services/GeneralsOnline/GeneralsOnlineJsonCatalogParser.cs` * `GenHub/GenHub/Features/Content/Services/GitHub/GitHubReleasesDiscoverer.cs` * `GenHub/GenHub/Features/Content/Services/IContentCacheService.cs` * `GenHub/GenHub/Features/Content/Services/Parsers/ModDBPageParser.cs` * `GenHub/GenHub/Features/Content/Services/Publishers/ModDBManifestFactory.cs` * `GenHub/GenHub/Features/Content/Services/Tools/PlaywrightService.cs` * `GenHub/GenHub/Features/Content/ViewModels/Catalog/SubscriptionConfirmationViewModel.cs` * `GenHub/GenHub/Features/Downloads/Services/ContentStateService.cs` * `GenHub/GenHub/Features/Downloads/Services/IContentStateService.cs` * `GenHub/GenHub/Features/Downloads/ViewModels/ContentDetailViewModel.cs` * `GenHub/GenHub/Features/Downloads/ViewModels/ContentGridItemViewModel.cs` * `GenHub/GenHub/Features/Downloads/ViewModels/DownloadsBrowserViewModel.InstallationCheck.cs` * `GenHub/GenHub/Features/Downloads/ViewModels/DownloadsBrowserViewModel.cs` * `GenHub/GenHub/Features/Downloads/ViewModels/DownloadsViewModel.cs` * `GenHub/GenHub/Features/Downloads/ViewModels/Filters/AODMapsFilterViewModel.cs` * `GenHub/GenHub/Features/Downloads/ViewModels/Filters/CNCLabsFilterViewModel.cs` * `GenHub/GenHub/Features/Downloads/ViewModels/Filters/CommunityOutpostFilterViewModel.cs` * `GenHub/GenHub/Features/Downloads/ViewModels/Filters/FilterPanelViewModelBase.cs` * `GenHub/GenHub/Features/Downloads/ViewModels/Filters/GitHubFilterViewModel.cs` * `GenHub/GenHub/Features/Downloads/ViewModels/Filters/IFilterPanelViewModel.cs` * `GenHub/GenHub/Features/Downloads/ViewModels/Filters/ModDBFilterViewModel.cs` * `GenHub/GenHub/Features/Downloads/ViewModels/Filters/StaticPublisherFilterViewModel.cs` * `GenHub/GenHub/Features/Downloads/ViewModels/Filters/SuperHackersFilterViewModel.cs` * `GenHub/GenHub/Features/Downloads/ViewModels/ProfileSelectionViewModel.cs` * `GenHub/GenHub/Features/Downloads/Views/ContentCardView.axaml.cs` * `GenHub/GenHub/Features/Downloads/Views/ContentDetailView.axaml.cs` * `GenHub/GenHub/Features/Downloads/Views/DownloadsBrowserView.axaml.cs` * `GenHub/GenHub/Features/Downloads/Views/FilterPanelView.axaml.cs` * `GenHub/GenHub/Features/Downloads/Views/ProfileSelectionView.axaml.cs` * `GenHub/GenHub/Features/Downloads/Views/PublisherSidebarView.axaml.cs` * `GenHub/GenHub/Features/Downloads/Views/SubscriptionConfirmationDialog.axaml.cs` * `GenHub/GenHub/Features/Settings/ViewModels/SettingsViewModel.cs` * `GenHub/GenHub/Features/Settings/Views/SettingsView.axaml.cs` * `GenHub/GenHub/Infrastructure/Converters/ComparisonConverters.cs` * `GenHub/GenHub/Infrastructure/Converters/NotEqualToConverter.cs` * `GenHub/GenHub/Infrastructure/DependencyInjection/ContentPipelineModule.cs` * `GenHub/GenHub/Infrastructure/DependencyInjection/SharedViewModelModule.cs`
This comment was marked as resolved.
This comment was marked as resolved.
6f88379 to
2b6d0bc
Compare
2b6d0bc to
8c2565d
Compare
8c2565d to
0d3ecf4
Compare
This comment was marked as resolved.
This comment was marked as resolved.
0d3ecf4 to
0533be0
Compare
…ngs in download and parser services
… and filter non-downloadable links
…nate silent copy fallback (#416)
…ogressive item loading
…edGroupsAsync for zero-delay async streaming
…d remove unused parameter
…on, and profile rebinding
| Path.Combine(InstallationPath, "gensec.big").FileExistsCaseInsensitive() || | ||
| Path.Combine(InstallationPath, GameClientConstants.SuperHackersGeneralsExecutable).FileExistsCaseInsensitive(); | ||
|
|
||
| if (!isZhNamed || isStrictGeneralsOnlySignature) |
There was a problem hiding this comment.
WARNING: Generals detection is suppressed for Zero-Hour-named directories
The condition !isZhNamed || isStrictGeneralsOnlySignature prevents Generals from being detected in directories whose name contains "Zero Hour" unless they also contain gensec.big or SuperHackersGeneralsExecutable. If a directory named "Zero Hour" contains both generals.exe and INI.big, the old code detected both games; the new code detects only Zero Hour. This behavioral regression affects dual-game directories and should be re-evaluated against the intended detection contract.
Reply with @kilocode-bot fix it to have Kilo Code address this issue.
| } | ||
| } | ||
| } | ||
| catch (IOException) |
There was a problem hiding this comment.
WARNING: .big file scan has incomplete exception handling
The try block around DirectoryInfo.GetFiles("*.big") catches only IOException and UnauthorizedAccessException, but GetFiles can also throw SecurityException, PathTooLongException, and ArgumentException on certain platforms or filesystem configurations. Unhandled exceptions here would crash installation detection instead of falling back gracefully.
Reply with @kilocode-bot fix it to have Kilo Code address this issue.
…sserting publisher switch
|
|
||
| // Act 2: Complete Publisher A's background fetch and allow background task to commit to cache | ||
| tcsA.SetResult(OperationResult<ContentDiscoveryResult>.CreateSuccess(new ContentDiscoveryResult { Items = itemsA, TotalItems = 3 })); | ||
| await Task.Delay(250); |
There was a problem hiding this comment.
WARNING: Fixed 250ms delay replaces robust polling for cache commit
The old implementation polled viewModel.IsLoading with a 5-second timeout, guaranteeing the background task had time to commit to cache before assertions. The new fixed Task.Delay(250) provides no such guarantee and may cause intermittent test failures under CI load or on slower machines where cache commit exceeds 250ms.
Reply with @kilocode-bot fix it to have Kilo Code address this issue.
…ctory scans, and centralize big constants
…ateFiles for archive discovery
| if (Directory.Exists(path)) | ||
| { | ||
| var directoryInfo = new DirectoryInfo(path); | ||
| if (directoryInfo.EnumerateFiles().Any(f => f.Name.EndsWith(GameClientConstants.ZeroHourArchiveExtensionSuffix, StringComparison.OrdinalIgnoreCase))) |
There was a problem hiding this comment.
WARNING: EnumerateFiles() accidentally dropped the "*.big" filter from the Zero Hour archive scan
The previous code used GetFiles("*.big") to restrict enumeration to .big archives before checking for the ZH.big suffix. The new EnumerateFiles() scans every file in the directory, which changes behavior for files like SomethingZH.big.txt (now incorrectly matched), adds unnecessary I/O for large directories, and defeats the intent of scanning only big archives. Restore the filter: EnumerateFiles("*.big").
Reply with @kilocode-bot fix it to have Kilo Code address this issue.
… detection on linux
…te redundant null-forgiving operator
|
| /// <param name="installationPath">The installation path.</param> | ||
| /// <param name="installationType">The installation type.</param> | ||
| /// <param name="logger">Optional logger instance.</param> | ||
| public class GameInstallation( |
There was a problem hiding this comment.
SUGGESTION: Constructor creation log silently dropped in refactor
The removed constructor logged Created GameInstallation: Path={InstallationPath}, Type={InstallationType} at Debug level on every instantiation; the primary-constructor replacement has no equivalent. If creation-time observability still matters, emit it from an initializer or the first Fetch()/SetPaths() call - or confirm the drop was intentional, since the refactor is otherwise behavior-preserving.
Reply with @kilocode-bot fix it to have Kilo Code address this issue.
|
|
||
| foreach (var group in manifestsByPath) | ||
| { | ||
| var sourcePath = group.Key; | ||
| if (string.IsNullOrEmpty(sourcePath)) |
There was a problem hiding this comment.
SUGGESTION: Null guard is unreachable and skips silently
The Where above already filters out manifests with null/empty SourcePath (logging each skip at Debug level), so group.Key can never be null or empty here and this continue is dead code. It works as null-safety for the removed !, but the silent skip is inconsistent with the logged filter - consider logging a warning if it ever fires, or restructuring so the double check is not needed, so a future edit to the filter cannot silently discard groups.
Reply with @kilocode-bot fix it to have Kilo Code address this issue.



Overview
This PR delivers the complete Downloads & Content Acquisition Experience along with robust Publisher Catalog Browsing, Multi-Axis Variant Management, and Profile Content/Dependency Integration for GenHub.
It establishes a modern, responsive UI backed by resilient download coordination, multi-stage progress tracking, image caching with memory & disk bounds, topological dependency resolution, and seamless profile linking via CAS (Content Addressable Storage).
Key Features & Changes
1. 🌐 Downloads Browser & Catalog Navigation
DownloadsBrowserView/DownloadsBrowserViewModel):PublisherSidebarView,SubscriptionConfirmationDialog):2. 📦 Content Detail, Variants & Bundle Components
ContentDetailView/ContentDetailViewModel):VariantSelectionView,VariantAxisGrouping,VariantSwap):3. 🔗 Dependency Resolution & Preview
DependencyResolver,DependencyPreviewView):4. 🎮 Profile Integration & Content State Tracking
ProfileSelectionView,ProfileSelectionViewModel):ContentStateService) reflecting installation status (NotInstalled,Installing,Installed,UpdateAvailable,Broken) across all profiles.ProfileContentService,ProfileEditorFacade):CasPoolManager,CasService,ProfileContentLinkerService) for atomic hardlinking/symlinking into workspace directories.5. ⚡ Infrastructure, Performance & Image Caching
ImageCacheService,ImageLoader):Converters/):DownloadModule,ContentPipelineModule,SharedViewModelModule, andManifestModule.6. 🧪 Testing & Documentation
GenHub.Tests):docs/):docs/FlowCharts/Downloads-Flow.md).docs/features/downloads.md,docs/features/content/).Verification
scripts/build-check.ps1(0 Warnings, 0 Errors).Note
Add publisher catalog browsing, variant-aware download acquisition, and dependency management
DownloadsBrowserViewModel,ContentDetailViewModel,ContentGridItemViewModel) replacing the previousDownloadsViewModel, with per-publisher filter panels, variant axis selection, and bundle component support.JsonPublisherCatalogParser,GenericCatalogDiscoverer,GenericCatalogResolver,GenericCatalogManifestFactory,PublisherSubscriptionStore, andPublisherCatalogRefreshServiceenabling third-party catalogs to be fetched, validated, and browsed.ContentOrchestratoracquisition pipeline with staged, non-regressing progress reporting, optionalIContentDelivererfallback, publisher factory post-processing for multi-variant manifests, and provenance fields (OriginalProviderName/OriginalContentId).ModDBDiscovererto use Playwright for Cloudflare-protected scraping with RSS fallback, challenge detection, richer item parsing, and multi-filter support.ProfileContentServicemulti-item add/create overloads with pairwise conflict validation, dependency acquisition, and publisher-specificGameClientsynthesis.genhub://URI scheme on Windows startup and handles catalog subscription deep-links via drag-and-drop onto the main window or IPC forwarding from secondary instances.ArchivePayloadProcessor,ControlBarPackageProcessor, andPlaywrightService(with managed Chromium provisioning) as shared infrastructure services.Macroscope summarized a53b821.
Greptile Summary
Implements an end-to-end content acquisition and profile integration experience.
Confidence Score: 5/5
The PR appears safe to merge.
No blocking failure remains.
Important Files Changed
Sequence Diagram
sequenceDiagram actor User participant Browser as Downloads Browser participant Catalog as Publisher Catalog participant Pipeline as Acquisition Pipeline participant Manifest as Manifest System participant CAS as CAS Storage participant Profile as Game Profile User->>Browser: Browse and select content Browser->>Catalog: Discover releases and variants Catalog-->>Browser: Content metadata and dependencies User->>Browser: Install selected variant Browser->>Pipeline: Acquire content Pipeline->>Pipeline: Download, validate, and process archive Pipeline->>Manifest: Generate content manifest Manifest->>CAS: Store content files CAS-->>Profile: Link content into profile workspace Profile-->>User: Content available for launchReviews (55): Last reviewed commit: "feat(downloads): complete download acqui..." | Re-trigger Greptile