Enable episodes GUID parsing by default, and remove option to disable it.

This commit is contained in:
arabcoders
2025-05-10 16:36:04 +03:00
parent b47194bad4
commit a342c85816
13 changed files with 49 additions and 136 deletions

View File

@@ -67,11 +67,6 @@ return (function () {
// -- Extra margin for marking item not found for backend in export mode. Default 3 days.
'not_found' => (int)env('WS_EXPORT_NOT_FOUND', 259_200),
],
'episodes' => [
'enable' => [
'guid' => (bool)env('WS_EPISODES_ENABLE_GUID', false),
],
],
'ignore' => [],
'trust' => [
'proxy' => (bool)env('WS_TRUST_PROXY', false),

View File

@@ -94,11 +94,6 @@ return (function () {
'description' => 'Trigger full export mode if changes exceed this number.',
'type' => 'int',
],
[
'key' => 'WS_EPISODES_ENABLE_GUID',
'description' => 'Enable Episodes GUID parsing.',
'type' => 'bool',
],
[
'key' => 'WS_BACKENDS_FILE',
'description' => 'The full path to the backends file.',

View File

@@ -88,7 +88,7 @@ final class ParseWebhook
{
return $this->tryResponse(
context: $context,
fn: fn () => $this->parse($context, $guid, $request),
fn: fn() => $this->parse($context, $guid, $request),
action: $this->action,
);
}
@@ -153,7 +153,7 @@ final class ParseWebhook
}
try {
$resp = Container::get(GetMetaData::class)(context: $context, id: $id, opts:[
$resp = Container::get(GetMetaData::class)(context: $context, id: $id, opts: [
Options::LOG_CONTEXT => ['request' => $json],
]);
if (!$resp->isSuccessful()) {
@@ -207,16 +207,8 @@ final class ParseWebhook
],
];
$enableGUID = (bool)Config::get('episodes.enable.guid');
if (EmbyClient::TYPE_EPISODE === $type && false === $enableGUID) {
$guids = [];
} else {
$guids = $guid->get(guids: ag($json, 'Item.ProviderIds', []), context: $logContext);
}
$fields = [
iState::COLUMN_GUIDS => $guids,
iState::COLUMN_GUIDS => $guid->get(guids: ag($json, 'Item.ProviderIds', []), context: $logContext),
iState::COLUMN_META_DATA => [
$context->backendName => [
iState::COLUMN_GUIDS => $guid->parse(
@@ -263,7 +255,7 @@ final class ParseWebhook
context: $context,
guid: $guid,
item: $obj,
opts: ['override' => $fields, Options::ENABLE_EPISODE_GUID => $enableGUID],
opts: ['override' => $fields],
)->setIsTainted(isTainted: true === in_array($event, self::WEBHOOK_TAINTED_EVENTS));
if (false === $entity->hasGuids() && false === $entity->hasRelativeGuid()) {

View File

@@ -238,7 +238,6 @@ class EmbyClient implements iClient
guid: $this->guid,
mapper: $mapper,
after: $after,
opts: [Options::ENABLE_EPISODE_GUID => (bool)Config::get('episodes.enable.guid')]
);
if ($response->hasError()) {
@@ -261,10 +260,7 @@ class EmbyClient implements iClient
context: $this->context,
guid: $this->guid,
mapper: $mapper,
opts: ag_sets($opts, [
'writer' => $writer,
Options::ENABLE_EPISODE_GUID => (bool)Config::get('episodes.enable.guid'),
])
opts: ag_sets($opts, ['writer' => $writer])
);
if ($response->hasError()) {
@@ -288,10 +284,7 @@ class EmbyClient implements iClient
guid: $this->guid,
mapper: $mapper,
after: $after,
opts: [
'queue' => $queue,
Options::ENABLE_EPISODE_GUID => (bool)Config::get('episodes.enable.guid'),
],
opts: ['queue' => $queue],
);
if ($response->hasError()) {
@@ -447,10 +440,7 @@ class EmbyClient implements iClient
guid: $this->guid,
mapper: $mapper,
after: null,
opts: ag_sets($opts, [
Options::ENABLE_EPISODE_GUID => (bool)Config::get('episodes.enable.guid'),
Options::ONLY_LIBRARY_ID => $libraryId,
])
opts: ag_sets($opts, [Options::ONLY_LIBRARY_ID => $libraryId])
);
if ($response->hasError()) {

View File

@@ -73,7 +73,7 @@ final class ParseWebhook
*/
public function __invoke(Context $context, iGuid $guid, iRequest $request): Response
{
return $this->tryResponse(context: $context, fn: fn () => $this->parse($context, $guid, $request));
return $this->tryResponse(context: $context, fn: fn() => $this->parse($context, $guid, $request));
}
/**
@@ -166,8 +166,6 @@ final class ParseWebhook
],
];
$enableGUID = (bool)Config::get('episodes.enable.guid');
$providersId = [];
foreach (array_change_key_case($json, CASE_LOWER) as $key => $val) {
@@ -177,15 +175,9 @@ final class ParseWebhook
$providersId[after($key, 'provider_')] = $val;
}
if (JFC::TYPE_EPISODE === $type && false === $enableGUID) {
$guids = [];
} else {
$guids = $guid->get(guids: $providersId, context: $logContext);
}
$fields = [
iState::COLUMN_WATCHED => (int)$isPlayed,
iState::COLUMN_GUIDS => $guids,
iState::COLUMN_GUIDS => $guid->get(guids: $providersId, context: $logContext),
iState::COLUMN_META_DATA => [
$context->backendName => [
iState::COLUMN_WATCHED => true === $isPlayed ? '1' : '0',
@@ -227,7 +219,7 @@ final class ParseWebhook
context: $context,
guid: $guid,
item: $obj,
opts: ['override' => $fields, Options::ENABLE_EPISODE_GUID => $enableGUID],
opts: ['override' => $fields],
)->setIsTainted(isTainted: true === in_array($event, self::WEBHOOK_TAINTED_EVENTS));
if (false === $entity->hasGuids() && false === $entity->hasRelativeGuid()) {

View File

@@ -93,19 +93,13 @@ trait JellyfinActionTrait
],
];
if (iState::TYPE_EPISODE === $type && false === (bool)ag($opts, Options::ENABLE_EPISODE_GUID, false)) {
$guids = [];
} else {
$guids = $guid->get(guids: ag($item, 'ProviderIds', []), context: $logContext);
}
$builder = [
iState::COLUMN_TYPE => $type,
iState::COLUMN_UPDATED => makeDate($date)->getTimestamp(),
iState::COLUMN_WATCHED => (int)$isPlayed,
iState::COLUMN_VIA => $context->backendName,
iState::COLUMN_TITLE => ag($item, ['Name', 'OriginalTitle'], '??'),
iState::COLUMN_GUIDS => $guids,
iState::COLUMN_GUIDS => $guid->get(guids: ag($item, 'ProviderIds', []), context: $logContext),
iState::COLUMN_META_DATA => [
$context->backendName => [
iState::COLUMN_ID => (string)ag($item, 'Id'),
@@ -126,7 +120,8 @@ trait JellyfinActionTrait
$metadata = &$builder[iState::COLUMN_META_DATA][$context->backendName];
$metadataExtra = &$metadata[iState::COLUMN_META_DATA_EXTRA];
$metadataExtra[iState::COLUMN_META_DATA_EXTRA_GENRES] = array_map(fn ($v) => strtolower($v), ag($item, 'Genres', []));
$metadataExtra[iState::COLUMN_META_DATA_EXTRA_GENRES] = array_map(fn($v) => strtolower($v),
ag($item, 'Genres', []));
// -- jellyfin/emby API does not provide library ID.
if (null !== ($library = $opts[iState::COLUMN_META_LIBRARY] ?? null)) {
@@ -159,7 +154,7 @@ trait JellyfinActionTrait
if (count($metadataExtra[iState::COLUMN_META_DATA_EXTRA_GENRES]) < 1) {
$metadataExtra[iState::COLUMN_META_DATA_EXTRA_GENRES] = array_map(
fn ($v) => strtolower($v),
fn($v) => strtolower($v),
ag($this->getItemDetails(context: $context, id: $parentId), 'Genres', [])
);
}

View File

@@ -247,7 +247,7 @@ class JellyfinClient implements iClient
if (false === $response->isSuccessful()) {
throw new HttpException(
ag($response->extra, 'message', fn () => $response->error->format()),
ag($response->extra, 'message', fn() => $response->error->format()),
ag($response->extra, 'http_code', 400),
);
}
@@ -265,7 +265,6 @@ class JellyfinClient implements iClient
guid: $this->guid,
mapper: $mapper,
after: $after,
opts: [Options::ENABLE_EPISODE_GUID => (bool)Config::get('episodes.enable.guid')]
);
if ($response->hasError()) {
@@ -288,10 +287,7 @@ class JellyfinClient implements iClient
context: $this->context,
guid: $this->guid,
mapper: $mapper,
opts: ag_sets($opts, [
'writer' => $writer,
Options::ENABLE_EPISODE_GUID => (bool)Config::get('episodes.enable.guid')
])
opts: ag_sets($opts, ['writer' => $writer])
);
if ($response->hasError()) {
@@ -315,10 +311,7 @@ class JellyfinClient implements iClient
guid: $this->guid,
mapper: $mapper,
after: $after,
opts: [
'queue' => $queue,
Options::ENABLE_EPISODE_GUID => (bool)Config::get('episodes.enable.guid'),
],
opts: ['queue' => $queue],
);
if ($response->hasError()) {
@@ -498,10 +491,7 @@ class JellyfinClient implements iClient
guid: $this->guid,
mapper: $mapper,
after: null,
opts: ag_sets($opts, [
Options::ONLY_LIBRARY_ID => $libraryId,
Options::ENABLE_EPISODE_GUID => (bool)Config::get('episodes.enable.guid'),
])
opts: ag_sets($opts, [Options::ONLY_LIBRARY_ID => $libraryId])
);
if ($response->hasError()) {
@@ -788,7 +778,7 @@ class JellyfinClient implements iClient
private function throwError(Response $response, string $className = RuntimeException::class, int $code = 0): void
{
throw new $className(
message: ag($response->extra, 'message', fn () => $response->error->format()),
message: ag($response->extra, 'message', fn() => $response->error->format()),
code: $code,
previous: $response->error->previous
);

View File

@@ -268,27 +268,19 @@ class JellyfinGuid implements iGuid
} catch (Throwable $e) {
if (true === $log) {
$this->logger->error(
message: "{class}: Exception '{error.kind}' was thrown unhandled during '{client}: {user}@{backend}' parsing '{agent}' identifier. Error '{error.message}' at '{error.file}:{error.line}'.",
message: "{class}: Unhandled exception was thrown during '{client}: {user}@{backend}' {title}parsing '{agent}' identifier. '{error.message}' at '{error.file}:{error.line}'.",
context: [
'class' => afterLast(static::class, '\\'),
'backend' => $this->context->backendName,
'client' => $this->context->clientName,
'user' => $this->context->userContext->name,
'error' => [
'kind' => $e::class,
'line' => $e->getLine(),
'message' => $e->getMessage(),
'file' => after($e->getFile(), ROOT_PATH),
],
'agent' => $value,
'exception' => [
'file' => $e->getFile(),
'line' => $e->getLine(),
'kind' => get_class($e),
'message' => $e->getMessage(),
'trace' => $e->getTrace(),
],
'title' => ag_exists($context, 'item.title') ? r(
"'{item.id}: {item.title}'",
$context
) . ' ' : '',
...$context,
...exception_log($e),
]
);
}

View File

@@ -182,17 +182,9 @@ final class ParseWebhook
],
];
$enableGUID = (bool)Config::get('episodes.enable.guid');
if (PlexClient::TYPE_EPISODE === $type && false === $enableGUID) {
$guids = [];
} else {
$guids = $guid->get(guids: ag($item, 'Guid', []), context: $logContext);
}
$fields = [
iState::COLUMN_WATCHED => (int)$isPlayed,
iState::COLUMN_GUIDS => $guids,
iState::COLUMN_GUIDS => $guid->get(guids: ag($item, 'Guid', []), context: $logContext),
iState::COLUMN_META_DATA => [
$context->backendName => [
iState::COLUMN_WATCHED => true === $isPlayed ? '1' : '0',
@@ -234,7 +226,7 @@ final class ParseWebhook
context: $context,
guid: $guid,
item: $obj,
opts: ['override' => $fields, Options::ENABLE_EPISODE_GUID => $enableGUID],
opts: ['override' => $fields],
)->setIsTainted(isTainted: true === in_array($event, self::WEBHOOK_TAINTED_EVENTS));
if (false === $entity->hasGuids() && false === $entity->hasRelativeGuid()) {

View File

@@ -104,19 +104,13 @@ trait PlexActionTrait
],
];
if (iState::TYPE_EPISODE === $type && false === (bool)ag($opts, Options::ENABLE_EPISODE_GUID, false)) {
$guids = [];
} else {
$guids = $guid->get(guids: ag($item, 'Guid', []), context: $logContext);
}
$builder = [
iState::COLUMN_TYPE => $type,
iState::COLUMN_UPDATED => (int)$date,
iState::COLUMN_WATCHED => (int)$isPlayed,
iState::COLUMN_VIA => $context->backendName,
iState::COLUMN_TITLE => ag($item, ['title', 'originalTitle'], '??'),
iState::COLUMN_GUIDS => $guids,
iState::COLUMN_GUIDS => $guid->get(guids: ag($item, 'Guid', []), context: $logContext),
iState::COLUMN_META_DATA => [
$context->backendName => [
iState::COLUMN_ID => (string)ag($item, 'ratingKey'),
@@ -139,7 +133,7 @@ trait PlexActionTrait
if (count(ag($item, 'Genre', [])) > 0) {
$metadataExtra[iState::COLUMN_META_DATA_EXTRA_GENRES] = array_map(
fn ($item) => strtolower((string)ag($item, 'tag', '??')),
fn($item) => strtolower((string)ag($item, 'tag', '??')),
ag($item, 'Genre', [])
);
}
@@ -172,8 +166,12 @@ trait PlexActionTrait
if (count($metadataExtra[iState::COLUMN_META_DATA_EXTRA_GENRES]) < 1) {
$metadataExtra[iState::COLUMN_META_DATA_EXTRA_GENRES] = array_map(
fn ($i) => strtolower((string)ag($i, 'tag', '??')),
ag($this->getItemDetails(context: $context, id: $parentId), 'MediaContainer.Metadata.0.Genre', [])
fn($i) => strtolower((string)ag($i, 'tag', '??')),
ag(
$this->getItemDetails(context: $context, id: $parentId),
'MediaContainer.Metadata.0.Genre',
[]
)
);
}
}
@@ -383,9 +381,9 @@ trait PlexActionTrait
protected function isSupportedType(string $type): bool
{
return true === in_array(
PlexClient::TYPE_MAPPER[$type] ?? PlexClient::TYPE_MAPPER[strtolower($type)] ?? $type,
iState::TYPES_LIST,
true
);
PlexClient::TYPE_MAPPER[$type] ?? PlexClient::TYPE_MAPPER[strtolower($type)] ?? $type,
iState::TYPES_LIST,
true
);
}
}

View File

@@ -257,9 +257,6 @@ class PlexClient implements iClient
guid: $this->guid,
mapper: $mapper,
after: $after,
opts: [
Options::ENABLE_EPISODE_GUID => (bool)Config::get('episodes.enable.guid'),
]
);
if ($response->hasError()) {
@@ -282,10 +279,7 @@ class PlexClient implements iClient
context: $this->context,
guid: $this->guid,
mapper: $mapper,
opts: ag_sets($opts, [
'writer' => $writer,
Options::ENABLE_EPISODE_GUID => (bool)Config::get('episodes.enable.guid')
])
opts: ag_sets($opts, ['writer' => $writer])
);
if ($response->hasError()) {
@@ -309,7 +303,7 @@ class PlexClient implements iClient
guid: $this->guid,
mapper: $mapper,
after: $after,
opts: ['queue' => $queue, Options::ENABLE_EPISODE_GUID => (bool)Config::get('episodes.enable.guid')],
opts: ['queue' => $queue],
);
if ($response->hasError()) {
@@ -467,10 +461,7 @@ class PlexClient implements iClient
guid: $this->guid,
mapper: $mapper,
after: null,
opts: ag_sets($opts, [
Options::ONLY_LIBRARY_ID => $libraryId,
Options::ENABLE_EPISODE_GUID => (bool)Config::get('episodes.enable.guid'),
]),
opts: ag_sets($opts, [Options::ONLY_LIBRARY_ID => $libraryId]),
);
if ($response->hasError()) {
@@ -964,7 +955,7 @@ class PlexClient implements iClient
private function throwError(Response $response, string $className = RuntimeException::class, int $code = 0): void
{
throw new $className(
message: ag($response->extra, 'message', fn () => $response->error->format()),
message: ag($response->extra, 'message', fn() => $response->error->format()),
code: $code,
previous: $response->error->previous
);

View File

@@ -419,25 +419,17 @@ final class PlexGuid implements iGuid
} catch (Throwable $e) {
if (true === $log) {
$this->logger->error(
message: "PlexGuid: Exception '{error.kind}' was thrown unhandled during '{client}: {backend}' parsing '{agent}' identifier. Error '{error.message}' at '{error.file}:{error.line}'.",
message: "PlexGuid: Unhandled exception was thrown during '{client}: {backend}' {title}parsing '{agent}' identifier. '{error.message}' at '{error.file}:{error.line}'.",
context: [
'backend' => $this->context->backendName,
'client' => $this->context->clientName,
'error' => [
'kind' => $e::class,
'line' => $e->getLine(),
'message' => $e->getMessage(),
'file' => after($e->getFile(), ROOT_PATH),
],
'agent' => $val,
'exception' => [
'file' => $e->getFile(),
'line' => $e->getLine(),
'kind' => get_class($e),
'message' => $e->getMessage(),
'trace' => $e->getTrace(),
],
'title' => ag_exists($context, 'item.title') ? r(
"'{item.id}: {item.title}'",
$context
) . ' ' : '',
...$context,
...exception_log($e),
]
);
}

View File

@@ -50,7 +50,6 @@ final class Options
public const string DELAY_BY = 'DELAY_BY';
public const string RAW_RESPONSE_CALLBACK = 'RAW_RESPONSE_CALLBACK';
public const string INTERNAL_REQUEST = 'INTERNAL_REQUEST';
public const string ENABLE_EPISODE_GUID = 'ENABLE_EPISODE_GUID';
private function __construct()
{