Skip to content

Commit

Permalink
Feat: Add a GOG-slug naming scheme and make it the default (#49)
Browse files Browse the repository at this point in the history
  • Loading branch information
RikudouSage authored Feb 9, 2025
1 parent 1fd1ac8 commit 4469f94
Show file tree
Hide file tree
Showing 14 changed files with 103 additions and 8 deletions.
3 changes: 2 additions & 1 deletion src/Command/DownloadCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use App\Enum\Language;
use App\Enum\Setting;
use App\Exception\ExitException;
use App\Exception\InvalidValueException;
use App\Exception\TooManyRetriesException;
use App\Exception\UnreadableFileException;
use App\Service\DownloadManager;
Expand Down Expand Up @@ -240,7 +241,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int

$progress->finish();
$io->newLine();
}, $input->getOption('retry'), $input->getOption('retry-delay'));
}, maxRetries: $input->getOption('retry'), retryDelay: $input->getOption('retry-delay'), ignoreExceptions: [InvalidValueException::class]);
} catch (TooManyRetriesException $e) {
if (!$input->getOption('skip-errors')) {
throw $e;
Expand Down
1 change: 1 addition & 0 deletions src/DTO/GameDetail.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public function __construct(
public string $cdKey,
#[ArrayType(type: DownloadDescription::class)]
public array $downloads,
public string $slug,
) {
}
}
7 changes: 7 additions & 0 deletions src/DTO/GameInfo.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ final class GameInfo implements OwnedItemInfo

public readonly bool $isNew;

public readonly ?string $slug;

public function getId(): int
{
return $this->id;
Expand All @@ -35,4 +37,9 @@ public function hasUpdates(): bool
{
return $this->hasUpdates || $this->isNew;
}

public function getSlug(): string
{
return $this->slug ?? '';
}
}
5 changes: 5 additions & 0 deletions src/DTO/MovieInfo.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,9 @@ public function hasUpdates(): bool
{
return false;
}

public function getSlug(): string
{
return '';
}
}
2 changes: 2 additions & 0 deletions src/DTO/OwnedItemInfo.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,6 @@ public function getTitle(): string;
public function getType(): MediaType;

public function hasUpdates(): bool;

public function getSlug(): string;
}
9 changes: 9 additions & 0 deletions src/Enum/NamingConvention.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

namespace App\Enum;

enum NamingConvention: string
{
case Custom = 'custom';
case GogSlug = 'gog-slug';
}
1 change: 1 addition & 0 deletions src/Enum/Setting.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ enum Setting: string
{
case DownloadPath = 'download-path';
case S3StorageClass = 's3-storage-class';
case NamingConvention = 'naming-convention';
}
6 changes: 6 additions & 0 deletions src/Migration/Migration1.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,19 @@

namespace App\Migration;

use App\Enum\NamingConvention;
use App\Enum\Setting;
use PDO;

final class Migration1 implements Migration
{
public function migrate(PDO $pdo): void
{
$pdo->exec('create table settings (id integer primary key autoincrement, setting text, value text)');
$pdo->prepare("insert into settings (setting, value) values (?, ?)")->execute([
Setting::NamingConvention->value,
json_encode(NamingConvention::GogSlug->value),
]);
}

public function getVersion(): int
Expand Down
36 changes: 36 additions & 0 deletions src/Migration/Migration4.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

namespace App\Migration;

use App\Enum\NamingConvention;
use App\Enum\Setting;
use PDO;

final readonly class Migration4 implements Migration
{

public function migrate(PDO $pdo): void
{
$pdo->exec('alter table games add column slug text default null');
// delete duplicate settings
$pdo->exec('delete from settings where id in (select max(id) from settings group by setting having count(setting) > 1)');
$pdo->exec("alter table settings rename to old_settings");
$pdo->exec('create table settings (id integer primary key autoincrement, setting text, value text, constraint setting_name unique (setting))');
$pdo->exec('insert into settings (setting, value) select setting, value from old_settings');
$pdo->exec('drop table old_settings');

// A new default value has been retroactively added to Migration1.
// The original naming convention is being set here if there isn't one.
// This effectively means that all new installations have the new value while everyone who used the app before
// has the original one.
$pdo->prepare('insert into settings (setting, value) values (?, ?) on conflict(setting) do nothing')->execute([
Setting::NamingConvention->value,
json_encode(NamingConvention::Custom->value),
]);
}

public function getVersion(): int
{
return 4;
}
}
1 change: 1 addition & 0 deletions src/Service/OwnedItemsManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ private function getGameDetail(OwnedItemInfo $item, int $httpTimeout): GameDetai

$detail = $this->serializer->deserialize($response->getContent(), GameDetail::class, [
'id' => $item->getId(),
'slug' => $item->getSlug(),
]);
foreach ($detail->downloads as $download) {
$this->setMd5($download, $detail, $httpTimeout);
Expand Down
9 changes: 6 additions & 3 deletions src/Service/Persistence/PersistenceManagerSqlite.php
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ public function getLocalGameData(): ?array
'title' => $next['title'],
'cdKey' => $next['cd_key'] ?? '',
'downloads' => $downloads,
'slug' => $next['slug'] ?? '',
], GameDetail::class);
}

Expand All @@ -113,16 +114,18 @@ public function storeSingleGameDetail(GameDetail $detail): void
$this->migrationManager->apply($pdo);

$pdo->prepare(
'insert into games (title, cd_key, game_id)
VALUES (?, ?, ?)
'insert into games (title, cd_key, game_id, slug)
VALUES (?, ?, ?, ?)
ON CONFLICT DO UPDATE SET title = excluded.title,
cd_key = excluded.cd_key,
game_id = excluded.game_id
game_id = excluded.game_id,
slug = excluded.slug
'
)->execute([
$detail->title,
$detail->cdKey ?: null,
$detail->id,
$detail->slug,
]);

$query = $pdo->prepare('select id from games where game_id = ?');
Expand Down
5 changes: 4 additions & 1 deletion src/Service/RetryService.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public function __construct(
* @throws TooManyRetriesException
* @throws Throwable
*/
public function retry(callable $callable, int $maxRetries, int $retryDelay, ?array $exceptions = null): void
public function retry(callable $callable, int $maxRetries, int $retryDelay, ?array $exceptions = null, ?array $ignoreExceptions = null): void
{
$retries = 0;
$thrown = [];
Expand All @@ -33,6 +33,9 @@ public function retry(callable $callable, int $maxRetries, int $retryDelay, ?arr
if (!$this->matches($e, $exceptions)) {
throw $e;
}
if ($ignoreExceptions && $this->matches($e, $ignoreExceptions)) {
throw $e;
}
sleep($retryDelay);
}
} while ($retries < $maxRetries);
Expand Down
2 changes: 2 additions & 0 deletions src/Trait/FilteredGamesResolverTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ function (GameDetail $game) use ($englishFallback, $languages) {
title: $game->title,
cdKey: $game->cdKey,
downloads: $downloads,
slug: $game->slug,
);
},
$iterable,
Expand All @@ -163,6 +164,7 @@ function (GameDetail $game) use ($operatingSystems) {
title: $game->title,
cdKey: $game->cdKey,
downloads: $downloads,
slug: $game->slug,
);
},
$iterable,
Expand Down
24 changes: 21 additions & 3 deletions src/Trait/TargetDirectoryTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
namespace App\Trait;

use App\DTO\GameDetail;
use App\Enum\NamingConvention;
use App\Enum\Setting;
use App\Exception\InvalidValueException;
use LogicException;
use Symfony\Component\Console\Input\InputInterface;

trait TargetDirectoryTrait
Expand All @@ -20,9 +24,23 @@ private function getTargetDir(InputInterface $input, GameDetail $game, ?string $
}
}

$title = preg_replace('@[^a-zA-Z-_0-9.]@', '_', $game->title);
$title = preg_replace('@_{2,}@', '_', $title);
$title = trim($title, '.');
$namingScheme = NamingConvention::tryFrom($this->persistence->getSetting(Setting::NamingConvention)) ?? NamingConvention::GogSlug;

switch ($namingScheme) {
case NamingConvention::GogSlug:
if (!$game->slug) {
throw new InvalidValueException("GOG Downloader is configured to use the GOG slug naming scheme, but the game '{$game->title}' does not have a slug. If you migrated from the previous naming scheme, please run the update command first.");
}
$title = $game->slug;
break;
case NamingConvention::Custom:
$title = preg_replace('@[^a-zA-Z-_0-9.]@', '_', $game->title);
$title = preg_replace('@_{2,}@', '_', $title);
$title = trim($title, '.');
break;
default:
throw new LogicException('Unimplemented naming scheme: ' . $namingScheme->value);
}

$dir = "{$dir}/{$title}";
if ($subdirectory !== null) {
Expand Down

0 comments on commit 4469f94

Please sign in to comment.