Preparing parseWebhook to support relative GUIDs. related to #69

This commit is contained in:
Abdulmhsen B. A. A
2022-05-04 20:26:30 +03:00
parent 04c7c8c50d
commit 7e35eecfea
5 changed files with 109 additions and 69 deletions

View File

@@ -342,7 +342,11 @@ final class Initializer
]);
}
return new Response(status: 200, headers: ['X-Status' => 'Entity is unchanged.']);
return new Response(status: 200, headers: [
'X-Status' => 'Entity is unchanged.',
'X-WH-Type' => $request->getAttribute('WH_TYPE', 'not_set'),
'X-WH-Event' => $request->getAttribute('WH_EVENT', 'not_set'),
]);
} catch (HttpException $e) {
if (200 === $e->getCode()) {
return new Response(status: $e->getCode(), headers: [

View File

@@ -102,7 +102,7 @@ class EmbyServer extends JellyfinServer
throw new HttpException(sprintf('%s: Not allowed event [%s]', afterLast(__CLASS__, '\\'), $event), 200);
}
$date = time();
$isTainted = in_array($event, self::WEBHOOK_TAINTED_EVENTS);
$meta = match ($type) {
StateInterface::TYPE_MOVIE => [
@@ -145,16 +145,9 @@ class EmbyServer extends JellyfinServer
$isWatched = (int)(bool)ag($json, 'Item.Played', ag($json, 'Item.PlayedToCompletion', 0));
}
$guids = ag($json, 'Item.ProviderIds', []);
$providersId = ag($json, 'Item.ProviderIds', []);
if (!$this->hasSupportedIds($guids)) {
throw new HttpException(
sprintf('%s: No supported GUID was given. [%s]', afterLast(__CLASS__, '\\'), arrayToString($guids)),
400
);
}
$guids = $this->getGuids($type, $guids);
$guids = $this->getGuids($providersId, $type);
foreach (Guid::fromArray($guids)->getPointers() as $guid) {
$this->cacheData[$guid] = ag($json, 'Item.Id');
@@ -162,19 +155,40 @@ class EmbyServer extends JellyfinServer
$row = [
'type' => $type,
'updated' => $date,
'updated' => time(),
'watched' => $isWatched,
'meta' => $meta,
...$guids
];
if (true === Config::get('webhook.debug') || null !== ag($request->getQueryParams(), 'debug')) {
saveWebhookPayload($request, "{$this->name}.{$event}", $json + ['entity' => $row]);
$entity = Container::get(StateInterface::class)::fromArray($row)->setIsTainted($isTainted);
if (!$entity->hasGuids()) {
throw new HttpException(
sprintf(
'%s: No supported GUID was given. [%s]',
afterLast(__CLASS__, '\\'),
arrayToString(
[
'guids' => !empty($providersId) ? $providersId : 'None',
'rGuids' => $entity->hasRelativeGuids() ? $entity->getRelativeGuids() : 'None',
]
)
), 400
);
}
return Container::get(StateInterface::class)::fromArray($row)->setIsTainted(
in_array($event, self::WEBHOOK_TAINTED_EVENTS)
);
if (false === $isTainted && (true === Config::get('webhook.debug') || null !== ag(
$request->getQueryParams(),
'debug'
))) {
saveWebhookPayload($this->name . '.' . $event, $request, [
'entity' => $entity->getAll(),
'payload' => $json,
]);
}
return $entity;
}
public function push(array $entities, DateTimeInterface|null $after = null): array

View File

@@ -286,8 +286,6 @@ class JellyfinServer implements ServerInterface
$isTainted = in_array($event, self::WEBHOOK_TAINTED_EVENTS);
$date = time();
$meta = match ($type) {
StateInterface::TYPE_MOVIE => [
'via' => $this->name,
@@ -311,49 +309,65 @@ class JellyfinServer implements ServerInterface
default => throw new HttpException(sprintf('%s: Invalid content type.', afterLast(__CLASS__, '\\')), 400),
};
$guids = [];
$providersId = [];
foreach ($json as $key => $val) {
if (str_starts_with($key, 'Provider_')) {
$guids[self::afterString($key, 'Provider_')] = $val;
if (!str_starts_with($key, 'Provider_')) {
continue;
}
$providersId[self::afterString($key, 'Provider_')] = $val;
}
if (!$this->hasSupportedIds($guids)) {
throw new HttpException(
sprintf('%s: No supported GUID was given. [%s]', afterLast(__CLASS__, '\\'), arrayToString($guids)),
400
);
// We use SeriesName to overcome jellyfin webhook limitation, it does not send series id.
if (StateInterface::TYPE_EPISODE === $type && null !== ag($json, 'SeriesName')) {
$meta['parent'] = $this->getEpisodeParent(ag($json, 'ItemId'), ag($json, 'SeriesName'));
}
if (false === $isTainted && StateInterface::TYPE_EPISODE === $type) {
$meta['parent'] = $this->getParentGUIDs(ag($json, 'ItemId'), ag($json, 'SeriesName'));
}
$guids = $this->getGuids($guids, $type);
$guids = $this->getGuids($providersId, $type);
foreach (Guid::fromArray($guids)->getPointers() as $guid) {
$this->cacheData[$guid] = ag($json, 'Item.ItemId');
}
$isWatched = (int)(bool)ag($json, 'Played', ag($json, 'PlayedToCompletion', 0));
$row = [
'type' => $type,
'updated' => $date,
'watched' => $isWatched,
'updated' => time(),
'watched' => (int)(bool)ag($json, 'Played', ag($json, 'PlayedToCompletion', 0)),
'meta' => $meta,
...$guids
];
if (true === Config::get('webhook.debug') || null !== ag($request->getQueryParams(), 'debug')) {
saveWebhookPayload($request, "{$this->name}.{$event}", $json + ['entity' => $row]);
$entity = Container::get(StateInterface::class)::fromArray($row)->setIsTainted($isTainted);
if (!$entity->hasGuids()) {
throw new HttpException(
sprintf(
'%s: No supported GUID was given. [%s]',
afterLast(__CLASS__, '\\'),
arrayToString(
[
'guids' => !empty($providersId) ? $providersId : 'None',
'rGuids' => $entity->hasRelativeGuids() ? $entity->getRelativeGuids() : 'None',
]
)
), 400
);
}
return Container::get(StateInterface::class)::fromArray($row)->setIsTainted($isTainted);
if (false === $isTainted && (true === Config::get('webhook.debug') || null !== ag(
$request->getQueryParams(),
'debug'
))) {
saveWebhookPayload($this->name . '.' . $event, $request, [
'entity' => $entity->getAll(),
'payload' => $json,
]);
}
return $entity;
}
protected function getParentGUIDs(mixed $id, string|null $series): array
protected function getEpisodeParent(mixed $id, string|null $series): array
{
if (null !== $series && array_key_exists($series, $this->cacheShow)) {
return $this->cacheShow[$series];

View File

@@ -366,49 +366,56 @@ class PlexServer implements ServerInterface
];
}
$isWatched = (int)(bool)ag($json, 'Metadata.viewCount', 0);
$date = time();
if (!$this->hasSupportedIds($json['Metadata']['Guid'] ?? [])) {
throw new HttpException(
sprintf(
'%s: No supported GUID was given. [%s]',
afterLast(__CLASS__, '\\'),
arrayToString($json['Metadata']['Guid'] ?? [])
),
400
);
}
$guids = $this->getGuids($json['Metadata']['Guid'] ?? [], $type);
foreach (Guid::fromArray($guids)->getPointers() as $guid) {
$this->cacheData[$guid] = ag($json, 'Metadata.guid');
}
if (false === $isTainted && StateInterface::TYPE_EPISODE === $type) {
$meta['parent'] = $this->getParentGUIDs(
$json['Metadata']['grandparentRatingKey'] ?? $json['Metadata']['parentRatingKey']
);
if (StateInterface::TYPE_EPISODE === $type) {
$parentId = ag($json, 'Metadata.grandparentRatingKey', fn() => ag($json, 'Metadata.parentRatingKey'));
$meta['parent'] = null !== $parentId ? $this->getEpisodeParent($parentId) : [];
}
$row = [
'type' => $type,
'updated' => $date,
'watched' => $isWatched,
'updated' => time(),
'watched' => (int)(bool)ag($json, 'Metadata.viewCount', 0),
'meta' => $meta,
...$guids
];
if (true === Config::get('webhook.debug') || null !== ag($request->getQueryParams(), 'debug')) {
saveWebhookPayload($request, "{$this->name}.{$event}", $json + ['entity' => $row]);
$entity = Container::get(StateInterface::class)::fromArray($row)->setIsTainted($isTainted);
if (!$entity->hasGuids()) {
throw new HttpException(
sprintf(
'%s: No supported GUID was given. [%s]',
afterLast(__CLASS__, '\\'),
arrayToString(
[
'guids' => !empty($json['Metadata']['Guid']) ? $json['Metadata']['Guid'] : 'None',
'rGuids' => $entity->hasRelativeGuids() ? $entity->getRelativeGuids() : 'None',
]
)
), 400
);
}
return Container::get(StateInterface::class)::fromArray($row)->setIsTainted($isTainted);
if (false !== $isTainted && (true === Config::get('webhook.debug') || null !== ag(
$request->getQueryParams(),
'debug'
))) {
saveWebhookPayload($this->name . '.' . $event, $request, [
'entity' => $entity->getAll(),
'payload' => $json,
]);
}
return $entity;
}
protected function getParentGUIDs(mixed $id): array
protected function getEpisodeParent(int|string $id): array
{
if (array_key_exists($id, $this->cacheShow)) {
return $this->cacheShow[$id];
@@ -443,7 +450,6 @@ class PlexServer implements ServerInterface
$json['Guid'][] = ['id' => $json['guid']];
}
if (!$this->hasSupportedIds($json['Guid'])) {
$this->cacheShow[$id] = [];
return $this->cacheShow[$id];
@@ -1850,8 +1856,10 @@ class PlexServer implements ServerInterface
'date' => makeDate($item->originallyAvailableAt ?? 'now')->format('Y-m-d'),
];
if (null !== ($item->grandparentRatingKey ?? null)) {
$meta['parent'] = $this->showInfo[$item->grandparentRatingKey] ?? [];
$parentId = $item->grandparentRatingKey ?? $item->parentRatingKey ?? null;
if (null !== $parentId) {
$meta['parent'] = $this->showInfo[$parentId] ?? [];
}
}

View File

@@ -226,7 +226,7 @@ if (!function_exists('fsize')) {
}
if (!function_exists('saveWebhookPayload')) {
function saveWebhookPayload(ServerRequestInterface $request, string $name, array $parsed = []): void
function saveWebhookPayload(string $name, ServerRequestInterface $request, array $parsed = []): void
{
$content = [
'query' => $request->getQueryParams(),