artryazanov / laravel-gog-scanner
Laravel 12 package to scan GOG.com games using queues and a fully normalized DB schema.
Installs: 65
Dependents: 0
Suggesters: 0
Security: 0
Stars: 1
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/artryazanov/laravel-gog-scanner
Requires
- php: ^8.1
- illuminate/database: ^11.0|^12.0
- illuminate/http: ^11.0|^12.0
- illuminate/queue: ^11.0|^12.0
- illuminate/support: ^11.0|^12.0
Requires (Dev)
- laravel/pint: ^1.24
- orchestra/testbench: ^9.0
- phpunit/phpunit: ^10.5 || ^11.0
README
A Laravel 11/12 package that scans the GOG catalog using queues and stores a fully normalized product schema (games and related data) in your database. It ships with an Artisan command and queued jobs that paginate through the public listing API and then fetch detailed product information per game.
- Framework: Laravel 11/12
- PHP: 8.1+
- Transport: Laravel HTTP Client (no SDK or API key required)
Features
- Queue-first design: paginated listing scan, then per-product detail scan.
- Fully normalized schema for prices, availability, sales visibility, OS support, genres, languages, companies, categories, gallery, screenshots, and artifacts.
- Sensible defaults with publishable config.
- Package migrations are auto-loaded by the service provider.
Installation
- Require the package in your application
composer require artryazanov/laravel-gog-scanner
- (Optional) Publish the configuration
php artisan vendor:publish --provider="Artryazanov\\GogScanner\\GogScannerServiceProvider" --tag=config
- Run your migrations
The package automatically loads its migrations. If you want to explicitly run them:
php artisan migrate
Configuration
See config/gogscanner.php (publish to override):
api_base: Base URL for Galaxy API (details), defaulthttps://api.gog.com.embed_base: Base URL for embed API (listing), defaulthttps://embed.gog.com.list_endpoint: Listing endpoint, default/games/ajax/filtered.detail_endpoint: Detail endpoint template, default/products/{id}.expand_fields: Comma-separated sections for details (downloads, description, screenshots, videos, etc.).default_listing_params: Default query params for listing (e.g.,mediaType => game,limit,search,sort, etc.).http_timeout: HTTP timeout in seconds, default30.queue.connection/queue.queue: Optional queue connection and name for dispatching jobs.
Example override in config/gogscanner.php (after publishing):
return [ 'default_listing_params' => [ 'mediaType' => 'game', 'limit' => 48, 'sort' => 'popularity', ], 'queue' => [ 'connection' => 'redis', 'queue' => 'gog-scanner', ], ];
Usage
Kick off a scan with the built-in Artisan command to enqueue the first page of the listing scan:
php artisan gog:scan # starts from page 1
php artisan gog:scan 5 # starts from page 5
- The command dispatches
ScanPageJobfor the requested page. ScanPageJobfetches the listing page, upserts games and listing data, enqueues aScanGameDetailJobper product, and (if more pages are available) enqueues the next page.ScanGameDetailJobfetches the product detail JSON and writes 1:1 and 1:N relations (compatibility, links, languages, images, descriptions, downloads/artifacts, screenshots, etc.).
Make sure your queue worker is running:
php artisan queue:work
HTTP Endpoints used
- Listing (embed API):
GET {embed_base}/games/ajax/filtered- Common params:
mediaType, page, search, category, system, limit, sort, ...
- Common params:
- Details (Galaxy API):
GET {api_base}/products/{id}?expand=downloads,expanded_dlcs,description,screenshots,videos,related_products,changelog
No authentication is required for the endpoints above.
Database Schema
The package includes migrations for a normalized schema starting with gog_games (non-auto-incrementing primary key equals GOG product id). Most 1:1 fields are stored directly on gog_games (availability, works-on flags, content compatibility, links, description, in-development flags). Related tables include:
- 1:1:
gog_game_prices,gog_game_sales_visibilities,gog_game_images. - 1:N:
gog_game_galleries,gog_game_dlcs,gog_game_artifacts(+gog_game_artifact_files),gog_game_screenshots(+gog_game_screenshot_images),gog_game_videos. - Dictionary + pivot:
gog_game_genres+gog_game_genre(genres) andgog_game_languages+gog_game_language(languages). - Dictionary + pivot:
gog_game_supported_systems+gog_game_supported_system(supported OS). - Dictionary:
gog_game_companies. - Pivots:
gog_game_developersandgog_game_publishers(allow multiple companies per role). - Dictionary:
gog_game_categorieswithgog_games.category_idandgog_games.original_category_idreferencing it.
Data Mapping
- Developers/Publishers: listing fields
developerandpublishermay contain multiple companies separated by commas. They are split, normalized togog_game_companies, and linked viagog_game_developersandgog_game_publishers. - Categories: listing
categoryandoriginalCategorymap togog_game_categoriesand are referenced bygog_games.category_idandgog_games.original_category_id. - OS support: listing
worksOnbooleans are kept ongog_games(works_on_windows/mac/linux). The arraysupportedOperatingSystemsis normalized to dictionarygog_game_supported_systemsand linked via pivot. - Languages: detail
languagesmap to dictionarygog_game_languagesand togog_game_languagepivot. - Genres: listing
genresmap to dictionarygog_game_genresand togog_game_genrepivot.
See database/migrations/*create_gog_schema.php for exact columns and constraints.
Extending & Customizing
- Tweak HTTP behavior via
http_timeoutandexpand_fields. - Adjust default listing filters with
default_listing_params. - Route jobs to a dedicated connection/queue using
queue.connection/queue.queue. - Wrap calls with your own rate limiting or retries by extending the jobs.
Testing
This repository includes a Testbench-based test suite:
- Unit/feature tests for service provider, console command, and jobs.
- HTTP calls are stubbed with
Http::fake(); queued work is asserted viaBus::fake().
Run the tests:
composer install
composer test
Production Tips
- Run queue workers with sufficient concurrency to process listing and detail jobs efficiently.
- Consider rate-limiting (e.g., Laravel middleware or external proxies) if you scan large portions of the catalog.
- Use a persistent queue (e.g., Redis) for resilience.
License
Unlicense — see LICENSE for details.
Credits
- Author: Artem Ryazanov artryazanov@gmail.com