Skip to content

Commit

Permalink
Merge pull request #585 from arabcoders/dev
Browse files Browse the repository at this point in the history
Implement per user servers.yaml, and support mark as unplayed for all users
  • Loading branch information
arabcoders authored Jan 21, 2025
2 parents c50c9be + de37955 commit 4144c65
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 15 deletions.
45 changes: 44 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ on:
env:
DOCKERHUB_SLUG: arabcoders/watchstate
GHCR_SLUG: ghcr.io/arabcoders/watchstate
PLATFORMS: linux/amd64,linux/arm64,linux/arm
PLATFORMS: linux/amd64,linux/arm64

jobs:
unit-tests:
Expand Down Expand Up @@ -90,6 +90,49 @@ jobs:
- run: composer install --prefer-dist --no-interaction --no-progress
- run: composer run test

pr_build_test:
needs: unit-tests
if: github.event_name == 'pull_request'
runs-on: "ubuntu-latest"
steps:
- name: Checkout
uses: actions/checkout@v4

- uses: bahmutov/npm-install@v1
with:
working-directory: frontend
install-command: yarn --production --prefer-offline --frozen-lockfile

- uses: bahmutov/npm-install@v1
with:
working-directory: frontend
install-command: yarn run generate

- name: Update Version File
uses: arabcoders/write-version-to-file@master
with:
filename: "/config/config.php"
placeholder: "$(version_via_ci)"
with_date: "true"
with_branch: "true"

- name: Set up QEMU
uses: docker/setup-qemu-action@v3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Build and push
uses: docker/build-push-action@v5
with:
platforms: ${{ env.PLATFORMS }}
context: .
push: false
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha, scope=pr_${{ github.workflow }}
cache-to: type=gha, scope=pr_${{ github.workflow }}

publish_docker_images:
needs: unit-tests
if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && github.event.inputs.build == 'true')
Expand Down
75 changes: 63 additions & 12 deletions src/Commands/State/SyncCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ protected function configure(): void
->addOption('force-full', 'f', InputOption::VALUE_NONE, 'Force full export. Ignore last export date.')
->addOption('dry-run', null, InputOption::VALUE_NONE, 'Do not commit changes to backends.')
->addOption('timeout', null, InputOption::VALUE_REQUIRED, 'Set request timeout in seconds.')
->addOption('test', null, InputOption::VALUE_NONE, 'Run on one user only.')
->addOption(
'select-backend',
's',
Expand Down Expand Up @@ -102,10 +103,9 @@ protected function configure(): void
<question>Known limitations</question>
We have some known limitations:
* Cannot be used with plex users that have PIN enabled.
* Can Only sync played status.
* Cannot sync play progress.
Known limitations:
* Cannot be used with plex users that have PIN enabled.
* Cannot sync play progress.
Some or all of these limitations will be fixed in future releases.
Expand Down Expand Up @@ -193,6 +193,13 @@ protected function process(iInput $input, iOutput $output): int
continue;
}

if (true !== (bool)ag($backend, 'import.enabled')) {
$this->logger->info("SYSTEM: Ignoring '{backend}' as the backend has import disabled.", [
'backend' => $backendName
]);
continue;
}

if (true !== (bool)ag($backend, 'export.enabled')) {
$this->logger->info("SYSTEM: Ignoring '{backend}' as the backend has export disabled.", [
'backend' => $backendName
Expand Down Expand Up @@ -272,6 +279,7 @@ protected function process(iInput $input, iOutput $output): int
$this->logger->info("SYSTEM: Getting users from '{backend}'.", [
'backend' => $client->getContext()->backendName
]);

try {
foreach ($client->getUsersList(['tokens' => true]) as $user) {
$info = $backend;
Expand Down Expand Up @@ -325,27 +333,54 @@ protected function process(iInput $input, iOutput $output): int
'results' => arrayToString($this->usersList($users)),
]);

foreach (array_reverse($users) as $user) {
foreach (($input->getOption('test') ? array_reverse($users) : $users) as $user) {
$this->queue->reset();

$userName = ag($user, 'name', 'Unknown');
$perUserCache = perUserCacheAdapter($userName);
$this->logger->info("SYSTEM: Loading user mapper data.");
$perUserMapper = perUserMapper($this->mapper, $userName)
->withCache($perUserCache)
->withLogger($this->logger)->loadData();
$this->logger->info("SYSTEM: Load user mapper data complete.");

$this->queue->reset();

$list = [];
$displayName = null;

$configFile = ConfigFile::open(r(fixPath(Config::get('path') . '/users/{user}/servers.yaml'), [
'user' => $userName
]), 'yaml', autoSave: true, autoCreate: true);
$configFile->setLogger($this->logger);

foreach (ag($user, 'backends', []) as $backend) {
$name = ag($backend, 'client_data.backendName');
$clientData = ag($backend, 'client_data');
$clientData['name'] = $name;

if (false === $configFile->has($name)) {
$data = $clientData;
$data = ag_set($data, 'import.lastSync', null);
$data = ag_set($data, 'export.lastSync', null);
$data = ag_delete($data, ['webhook', 'name', 'backendName', 'displayName']);
$configFile->set($name, $data);
} else {
$clientData = ag_delete($clientData, 'import.lastSync');
$clientData = ag_delete($clientData, 'export.lastSync');
$clientData = array_replace_recursive($configFile->get($name), $clientData);
}

$clientData['class'] = makeBackend($clientData, $name, [
BackendCache::class => Container::get(BackendCache::class)->with(adapter: $perUserCache)
])->setLogger($this->logger);

$list[$name] = $clientData;
$displayName = ag($backend, 'client_data.displayName', '??');

if (false === $input->getOption('dry-run')) {
$configFile->set("{$name}.import.lastSync", time());
$configFile->set("{$name}.export.lastSync", time());
}
}

$start = makeDate();
Expand All @@ -356,7 +391,7 @@ protected function process(iInput $input, iOutput $output): int
]);

assert($perUserMapper instanceof iEImport);
$this->handleImport($perUserMapper, $displayName, $list);
$this->handleImport($perUserMapper, $displayName, $list, $input->getOption('force-full'), $configFile);

assert($perUserMapper instanceof MemoryMapper);
/** @var MemoryMapper $changes */
Expand Down Expand Up @@ -401,21 +436,37 @@ protected function process(iInput $input, iOutput $output): int
'peak' => getPeakMemoryUsage(),
],
]);
exit(1);


if ($input->getOption('test')) {
break;
}
}

return self::SUCCESS;
}

protected function handleImport(iEImport $mapper, string $name, array $backends): void
{
protected function handleImport(
iEImport $mapper,
string $name,
array $backends,
bool $isFull,
ConfigFile $config
): void {
/** @var array<array-key,ResponseInterface> $queue */
$queue = [];

foreach ($backends as $backend) {
/** @var iClient $client */
$client = ag($backend, 'class');
array_push($queue, ...$client->pull($mapper));
$context = $client->getContext();
$after = ag($context->options, Options::FORCE_FULL) || $isFull ? null : $config->get(
$context->backendName . '.import.lastSync'
);
if (null !== $after) {
$after = makeDate($after);
}
array_push($queue, ...$client->pull(mapper: $mapper, after: $after));
}

$start = makeDate();
Expand Down Expand Up @@ -580,7 +631,7 @@ private function generate_users_list(array $users, array $map = []): array
* 'backends' => [
* 'backend1' => userObj,
* 'backend2' => userObj,
* ...
* ...,
* ]
* ]
* </code>
Expand Down
11 changes: 9 additions & 2 deletions src/Libs/helpers.php
Original file line number Diff line number Diff line change
Expand Up @@ -254,13 +254,20 @@ function ag_exists(array $array, string|int $path, string $separator = '.'): boo
* Delete given key path.
*
* @param array $array The array to search in.
* @param int|string $path The key path to delete.
* @param int|string|array $path The key path to delete.
* @param string $separator The separator used in the key path (default is '.').
*
* @return array The modified array.
*/
function ag_delete(array $array, string|int $path, string $separator = '.'): array
function ag_delete(array $array, string|int|array $path, string $separator = '.'): array
{
if (is_array($path)) {
foreach ($path as $key) {
$array = ag_delete($array, $key, $separator);
}
return $array;
}

if (array_key_exists($path, $array)) {
unset($array[$path]);

Expand Down

0 comments on commit 4144c65

Please sign in to comment.