Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions FAQ.md
Original file line number Diff line number Diff line change
Expand Up @@ -615,3 +615,11 @@ creation failing to load. To fix the issue it's recommended to change the backen
* For Plex: `Library/Application Support/Plex Media Server/Preferences.xml` key: `ProcessedMachineIdentifier`.

Those values need to be unique per instance.

---

# Some Plex users are not showing up in the user list?

Sometimes, the plex user list may not fully load all users, Please <!--i:fa-cogs--> **Env** page and add the following environment variable:
`WS_CLIENTS_PLEX_DISABLE_DEDUP` and turn it on. This will disable the deduplication logic for plex users. Once you enable this option please restart watchstate
and try again. If the user still doesn't show up, please open a bug report with the relevant logs and we will investigate the issue.
4 changes: 3 additions & 1 deletion config/config.php
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,9 @@
];

$config['clients'] = [
strtolower(PlexClient::CLIENT_NAME) => [],
strtolower(PlexClient::CLIENT_NAME) => [
'disable_dedup' => (bool) env('WS_CLIENTS_PLEX_DISABLE_DEDUP', false),
],
strtolower(EmbyClient::CLIENT_NAME) => [],
strtolower(JellyfinClient::CLIENT_NAME) => [
'fix_played' => (bool) env('WS_CLIENTS_JELLYFIN_FIX_PLAYED', false),
Expand Down
33 changes: 20 additions & 13 deletions config/env.spec.php
Original file line number Diff line number Diff line change
Expand Up @@ -260,13 +260,13 @@
throw new ValidationException('Invalid progress threshold. Must be a number.');
}

$cmp = (int)$value;
$cmp = (int) $value;

if (0 !== $cmp && $cmp < 180) {
throw new ValidationException('Invalid progress threshold. Must be at least 180 seconds.');
}

return (string)$value;
return (string) $value;
},
],
[
Expand Down Expand Up @@ -294,7 +294,7 @@
if (false === is_valid_url($value)) {
throw new ValidationException('Invalid remote logger URL. Must be a valid URL.');
}
return (string)$value;
return (string) $value;
},
'mask' => true,
],
Expand All @@ -316,10 +316,10 @@

if (false === is_valid_name($value)) {
throw new ValidationException(
'Invalid username. Username can only contains [lower case a-z, 0-9 and _].'
'Invalid username. Username can only contains [lower case a-z, 0-9 and _].',
);
}
return (string)$value;
return (string) $value;
},
'mask' => true,
'protected' => true,
Expand All @@ -337,15 +337,16 @@
$prefix = Config::get('password.prefix', 'ws_hash@:');

if (true === str_starts_with($value, $prefix)) {
return (string)$value;
return (string) $value;
}

try {
return $prefix . password_hash(
$value,
Config::get('password.algo'),
Config::get('password.options', [])
);
return $prefix
. password_hash(
$value,
Config::get('password.algo'),
Config::get('password.options', []),
);
} catch (ValueError $e) {
throw new ValidationException('Invalid password. Password hashing failed.', $e->getCode(), $e);
}
Expand Down Expand Up @@ -396,13 +397,13 @@
throw new ValidationException('Invalid minimum progress. Must be a number.');
}

$cmp = (int)$value;
$cmp = (int) $value;

if ($cmp < 60) {
throw new ValidationException('Invalid minimum progress. Must be at least 60 seconds.');
}

return (string)$value;
return (string) $value;
},
],
[
Expand All @@ -411,6 +412,12 @@
'description' => 'Enable partial fix for Jellyfin marking items as played.',
'type' => 'bool',
],
[
'key' => 'WS_CLIENTS_PLEX_DISABLE_DEDUP',
'config' => 'clients.plex.disable_dedup',
'description' => 'Disable de-duplication of plex users.',
'type' => 'bool',
],
];

$validateCronExpression = function (string $value, array $spec = []): string {
Expand Down
1 change: 0 additions & 1 deletion frontend/app/pages/tools/sub_users.vue
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,6 @@ import { computed, nextTick, onMounted, ref, toRaw } from 'vue';
import { useStorage } from '@vueuse/core';
import { navigateTo, useRoute } from '#app';
import moment from 'moment';
import draggable from 'vuedraggable';
import { makeConsoleCommand, notification, parse_api_response, request } from '~/utils';
import Message from '~/components/Message.vue';
import { useDialog } from '~/composables/useDialog';
Expand Down
6 changes: 3 additions & 3 deletions frontend/bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
"vue": "^3.5.28",
"vue-router": "^5.0.2",
"vue-toastification": "^2.0.0-rc.5",
"vuedraggable": "^2.24.3",
"vuedraggable": "^4.1.0",
"@nuxt/eslint": "^1.15.1",
"@nuxt/eslint-config": "^1.15.1"
},
Expand Down
51 changes: 27 additions & 24 deletions src/Backends/Plex/Action/GetUsersList.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use App\Backends\Common\Error;
use App\Backends\Common\Levels;
use App\Backends\Common\Response;
use App\Libs\Config;
use App\Libs\Container;
use App\Libs\Enums\Http\Status;
use App\Libs\Exceptions\Backends\InvalidArgumentException;
Expand Down Expand Up @@ -233,7 +234,7 @@ private function processHomeUsers(
'id' => ag($data, 'id'),
'type' => 'H',
'uuid' => ag($data, 'uuid'),
'name' => ag($data, ['friendlyName', 'username', 'title', 'email', 'id'], '??'),
'name' => normalize_name(ag($data, ['friendlyName', 'username', 'title', 'email', 'id'], '??')),
'admin' => (bool) ag($data, 'admin'),
'guest' => (bool) ag($data, 'guest'),
'restricted' => (bool) ag($data, 'restricted'),
Expand Down Expand Up @@ -270,31 +271,33 @@ private function processHomeUsers(
'count' => count($list),
]));

if (true === (bool) Config::get('clients.plex.disable_dedup', false)) {
array_push($list, ...$external);
return new Response(status: true, response: $list);
}

/**
* @TODO: Disabled the de-duplication for now.
* De-duplicate users.
* Plex in their infinite wisdom sometimes return home users as external users.
* Plex in their infinite wisdom sometimes return home users as external users and vice versa.
*/
// foreach ($external as $user) {
// if (
// null !== ($homeUser = array_find(
// $list,
// static fn($u) => (int) $u['id'] === (int) $user['id'] && $u['name'] === $user['name'],
// ))
// ) {
// $opts[Options::LOG_TO_WRITER](r("Skipping external user '{name}' with id '{id}' because match a home user with id '{userId}' and name '{userName}'.", [
// 'id' => ag($user, 'id'),
// 'name' => ag($user, 'name'),
// 'userId' => ag($homeUser, 'id'),
// 'userName' => ag($homeUser, 'name'),
// ]));
// continue;
// }

// $list[] = $user;
// }

array_push($list, ...$external);
foreach ($external as $user) {
if (
null !== ($homeUser = array_find(
$list,
static fn($u) => (int) $u['id'] === (int) $user['id'] && $u['name'] === $user['name'],
))
) {
$opts[Options::LOG_TO_WRITER](r("Skipping external user '{name}' with id '{id}' because match a home user with id '{userId}' and name '{userName}'.", [
'id' => ag($user, 'id'),
'name' => ag($user, 'name'),
'userId' => ag($homeUser, 'id'),
'userName' => ag($homeUser, 'name'),
]));
continue;
}

$list[] = $user;
}

return new Response(status: true, response: $list);
}
Expand Down Expand Up @@ -440,7 +443,7 @@ private function processExternalUsers(iResponse $response, Context $context, iUr
'id' => (int) ag($user, 'id'),
'type' => 'E',
'uuid' => 1 === $uuidStatus ? ag($matches, 'uuid') : ag($user, 'invited_user'),
'name' => ag($user, ['username', 'title', 'email', 'id'], '??'),
'name' => normalize_name(ag($user, ['username', 'title', 'email', 'id'], '??')),
'admin' => false,
'guest' => 1 !== (int) ag($user, 'home'),
'restricted' => 1 === (int) ag($user, 'restricted'),
Expand Down
2 changes: 1 addition & 1 deletion tests/Backends/Plex/GetUsersListTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public function test_get_users_list_home_users(): void
$result = $action($context);

$this->assertTrue($result->isSuccessful());
$this->assertSame('Test User', $result->response[0]['name']);
$this->assertSame('test_user', $result->response[0]['name'], 'Name normalization failed');
$this->assertTrue($result->response[0]['admin']);
}

Expand Down