From 6f8a7ec14c6dacdfd8d651edf98f432d07a7fe9e Mon Sep 17 00:00:00 2001 From: abdulmohsen Date: Sun, 9 Jun 2024 15:17:19 +0300 Subject: [PATCH] Made possible to deserialize show into a StateEntity object. --- src/Backends/Jellyfin/Action/ToEntity.php | 4 +- src/Backends/Jellyfin/JellyfinActionTrait.php | 26 ++++--- src/Backends/Plex/PlexActionTrait.php | 11 ++- src/Libs/Database/DatabaseInterface.php | 4 +- src/Libs/Entity/StateEntity.php | 17 ++++- src/Libs/Entity/StateInterface.php | 73 ++++++++++--------- src/Libs/Options.php | 1 + 7 files changed, 82 insertions(+), 54 deletions(-) diff --git a/src/Backends/Jellyfin/Action/ToEntity.php b/src/Backends/Jellyfin/Action/ToEntity.php index 384d195c..f1325238 100644 --- a/src/Backends/Jellyfin/Action/ToEntity.php +++ b/src/Backends/Jellyfin/Action/ToEntity.php @@ -7,14 +7,14 @@ namespace App\Backends\Jellyfin\Action; use App\Backends\Common\CommonTrait; use App\Backends\Common\Context; use App\Backends\Common\Response; +use App\Backends\Jellyfin\JellyfinActionTrait; use App\Backends\Jellyfin\JellyfinGuid; -use App\Backends\Plex\PlexActionTrait; use App\Libs\Entity\StateInterface; class ToEntity { use CommonTrait; - use PlexActionTrait; + use JellyfinActionTrait; private string $action = 'jellyfin.toEntity'; diff --git a/src/Backends/Jellyfin/JellyfinActionTrait.php b/src/Backends/Jellyfin/JellyfinActionTrait.php index f6c8e46a..b410e8df 100644 --- a/src/Backends/Jellyfin/JellyfinActionTrait.php +++ b/src/Backends/Jellyfin/JellyfinActionTrait.php @@ -54,32 +54,36 @@ trait JellyfinActionTrait } } - if (null === $date) { - throw new InvalidArgumentException('No date was set on object.'); - } - $type = JellyfinClient::TYPE_MAPPER[ag($item, 'Type')] ?? ag($item, 'Type'); + if (null === $date) { + if (iState::TYPE_SHOW !== $type) { + throw new InvalidArgumentException(r("'{type}' No date was set on object.", ['type' => $type])); + } + $date = 0; + } + $logContext = [ 'backend' => $context->backendName, 'item' => [ 'id' => (string)ag($item, 'Id'), - 'type' => ag($item, 'Type'), - 'title' => match (ag($item, 'Type')) { - JellyfinClient::TYPE_MOVIE => sprintf( + 'type' => $type, + 'title' => match ($type) { + iState::TYPE_MOVIE, iState::TYPE_SHOW => sprintf( '%s (%s)', ag($item, ['Name', 'OriginalTitle'], '??'), ag($item, 'ProductionYear', '0000') ), - JellyfinClient::TYPE_EPISODE => sprintf( + iState::TYPE_EPISODE => sprintf( '%s - (%sx%s)', ag($item, ['Name', 'OriginalTitle'], '??'), str_pad((string)ag($item, 'ParentIndexNumber', 0), 2, '0', STR_PAD_LEFT), str_pad((string)ag($item, 'IndexNumber', 0), 3, '0', STR_PAD_LEFT), ), default => throw new InvalidArgumentException( - r('Unexpected Content type [{type}] was received.', [ - 'type' => $type + r("Unexpected Content type '{type}' was received. '{content}'.", [ + 'type' => $type, + 'content' => arrayToString($item), ]) ), }, @@ -94,7 +98,7 @@ trait JellyfinActionTrait } $builder = [ - iState::COLUMN_TYPE => strtolower(ag($item, 'Type')), + iState::COLUMN_TYPE => $type, iState::COLUMN_UPDATED => makeDate($date)->getTimestamp(), iState::COLUMN_WATCHED => (int)$isPlayed, iState::COLUMN_VIA => $context->backendName, diff --git a/src/Backends/Plex/PlexActionTrait.php b/src/Backends/Plex/PlexActionTrait.php index 5758dfa9..e62f97ef 100644 --- a/src/Backends/Plex/PlexActionTrait.php +++ b/src/Backends/Plex/PlexActionTrait.php @@ -56,7 +56,10 @@ trait PlexActionTrait } if (null === $date) { - throw new InvalidArgumentException('No date was set on object.'); + if (PlexClient::TYPE_SHOW !== ag($item, 'type', '')) { + throw new InvalidArgumentException('No date was set on object.'); + } + $date = 0; } $year = (int)ag($item, ['grandParentYear', 'parentYear', 'year'], 0); @@ -78,7 +81,7 @@ trait PlexActionTrait 'id' => ag($item, 'ratingKey'), 'type' => ag($item, 'type'), 'title' => match (ag($item, 'type')) { - PlexClient::TYPE_MOVIE => sprintf( + PlexClient::TYPE_MOVIE, PlexClient::TYPE_SHOW => sprintf( '%s (%s)', ag($item, ['title', 'originalTitle'], '??'), 0 === $year ? '0000' : $year, @@ -167,6 +170,10 @@ trait PlexActionTrait $metadata[iState::COLUMN_META_PATH] = (string)$mediaPath; } + if (null === $mediaPath && null !== ($showPath = ag($item, 'Location.0.path')) && !empty($showPath)) { + $metadata[iState::COLUMN_META_PATH] = (string)$showPath; + } + if (null !== ($PremieredAt = ag($item, 'originallyAvailableAt'))) { $metadataExtra[iState::COLUMN_META_DATA_EXTRA_DATE] = makeDate($PremieredAt)->format('Y-m-d'); } diff --git a/src/Libs/Database/DatabaseInterface.php b/src/Libs/Database/DatabaseInterface.php index 3a331f05..9b289b06 100644 --- a/src/Libs/Database/DatabaseInterface.php +++ b/src/Libs/Database/DatabaseInterface.php @@ -14,9 +14,9 @@ use RuntimeException; interface DatabaseInterface { - public const MIGRATE_UP = 'up'; + public const string MIGRATE_UP = 'up'; - public const MIGRATE_DOWN = 'down'; + public const string MIGRATE_DOWN = 'down'; /** * Set options diff --git a/src/Libs/Entity/StateEntity.php b/src/Libs/Entity/StateEntity.php index d9542046..0409bf47 100644 --- a/src/Libs/Entity/StateEntity.php +++ b/src/Libs/Entity/StateEntity.php @@ -39,6 +39,7 @@ final class StateEntity implements iState * @var string $type What type of data this entity holds. */ public string $type = ''; + /** * @var int $updated When was the entity last updated. */ @@ -106,11 +107,11 @@ final class StateEntity implements iState continue; } - if (iState::COLUMN_TYPE === $key && self::TYPE_MOVIE !== $val && self::TYPE_EPISODE !== $val) { + if (iState::COLUMN_TYPE === $key && false === in_array($val, self::TYPES_LIST)) { throw new RuntimeException( - r('StateEntity: Unexpected [{value}] type was given. Expecting [{types_list}].', context: [ + r("StateEntity: Unexpected '{value}' type was given. Expecting '{types_list}'.", context: [ 'value' => $val, - 'types_list' => implode(', ', [iState::TYPE_MOVIE, iState::TYPE_EPISODE]), + 'types_list' => implode(', ', self::TYPES_LIST), ]) ); } @@ -181,7 +182,7 @@ final class StateEntity implements iState $year = ag($this->data, iState::COLUMN_YEAR, $this->year); $title = ag($this->data, iState::COLUMN_TITLE, $this->title); - if ($this->isMovie() || true === $asMovie) { + if ($this->isMovie() || $this->isShow() || true === $asMovie) { return r('{title} ({year})', [ 'title' => !empty($title) ? $title : '??', 'year' => $year ?? '0000' @@ -290,6 +291,14 @@ final class StateEntity implements iState return iState::TYPE_MOVIE === $this->type; } + /** + * @inheritdoc + */ + public function isShow(): bool + { + return iState::TYPE_SHOW === $this->type; + } + /** * @inheritdoc */ diff --git a/src/Libs/Entity/StateInterface.php b/src/Libs/Entity/StateInterface.php index ead71473..bdd16aac 100644 --- a/src/Libs/Entity/StateInterface.php +++ b/src/Libs/Entity/StateInterface.php @@ -8,14 +8,14 @@ use Psr\Log\LoggerAwareInterface; interface StateInterface extends LoggerAwareInterface { - public const TYPE_MOVIE = 'movie'; - public const TYPE_EPISODE = 'episode'; - public const TYPE_SHOW = 'show'; + public const string TYPE_MOVIE = 'movie'; + public const string TYPE_EPISODE = 'episode'; + public const string TYPE_SHOW = 'show'; /** * @var array list of supported types. */ - public const TYPES_LIST = [ + public const array TYPES_LIST = [ self::TYPE_MOVIE, self::TYPE_SHOW, self::TYPE_EPISODE, @@ -24,36 +24,36 @@ interface StateInterface extends LoggerAwareInterface /** * If you must reference field directly, use those constants. */ - public const COLUMN_ID = 'id'; - public const COLUMN_TYPE = 'type'; - public const COLUMN_UPDATED = 'updated'; - public const COLUMN_WATCHED = 'watched'; - public const COLUMN_VIA = 'via'; - public const COLUMN_TITLE = 'title'; - public const COLUMN_YEAR = 'year'; - public const COLUMN_SEASON = 'season'; - public const COLUMN_EPISODE = 'episode'; - public const COLUMN_PARENT = 'parent'; - public const COLUMN_GUIDS = 'guids'; - public const COLUMN_META_DATA = 'metadata'; - public const COLUMN_META_SHOW = 'show'; - public const COLUMN_META_LIBRARY = 'library'; - public const COLUMN_META_PATH = 'path'; - public const COLUMN_META_DATA_ADDED_AT = 'added_at'; - public const COLUMN_META_DATA_PLAYED_AT = 'played_at'; - public const COLUMN_META_DATA_PROGRESS = 'progress'; - public const COLUMN_META_DATA_RATING = 'rating'; - public const COLUMN_META_DATA_EXTRA = 'extra'; - public const COLUMN_META_DATA_EXTRA_TITLE = 'title'; - public const COLUMN_META_DATA_EXTRA_DATE = 'date'; - public const COLUMN_EXTRA = 'extra'; - public const COLUMN_EXTRA_EVENT = 'event'; - public const COLUMN_EXTRA_DATE = 'received_at'; + public const string COLUMN_ID = 'id'; + public const string COLUMN_TYPE = 'type'; + public const string COLUMN_UPDATED = 'updated'; + public const string COLUMN_WATCHED = 'watched'; + public const string COLUMN_VIA = 'via'; + public const string COLUMN_TITLE = 'title'; + public const string COLUMN_YEAR = 'year'; + public const string COLUMN_SEASON = 'season'; + public const string COLUMN_EPISODE = 'episode'; + public const string COLUMN_PARENT = 'parent'; + public const string COLUMN_GUIDS = 'guids'; + public const string COLUMN_META_DATA = 'metadata'; + public const string COLUMN_META_SHOW = 'show'; + public const string COLUMN_META_LIBRARY = 'library'; + public const string COLUMN_META_PATH = 'path'; + public const string COLUMN_META_DATA_ADDED_AT = 'added_at'; + public const string COLUMN_META_DATA_PLAYED_AT = 'played_at'; + public const string COLUMN_META_DATA_PROGRESS = 'progress'; + public const string COLUMN_META_DATA_RATING = 'rating'; + public const string COLUMN_META_DATA_EXTRA = 'extra'; + public const string COLUMN_META_DATA_EXTRA_TITLE = 'title'; + public const string COLUMN_META_DATA_EXTRA_DATE = 'date'; + public const string COLUMN_EXTRA = 'extra'; + public const string COLUMN_EXTRA_EVENT = 'event'; + public const string COLUMN_EXTRA_DATE = 'received_at'; /** * List of table keys. */ - public const ENTITY_KEYS = [ + public const array ENTITY_KEYS = [ self::COLUMN_ID, self::COLUMN_TYPE, self::COLUMN_UPDATED, @@ -72,7 +72,7 @@ interface StateInterface extends LoggerAwareInterface /** * Ignore listed fields if the played status did not change. */ - public const ENTITY_IGNORE_DIFF_CHANGES = [ + public const array ENTITY_IGNORE_DIFF_CHANGES = [ self::COLUMN_VIA, self::COLUMN_TITLE, self::COLUMN_YEAR, @@ -84,7 +84,7 @@ interface StateInterface extends LoggerAwareInterface /** * Fields that if changed will trigger an update regardless of the watch state or event. */ - public const ENTITY_FORCE_UPDATE_FIELDS = [ + public const array ENTITY_FORCE_UPDATE_FIELDS = [ self::COLUMN_PARENT, self::COLUMN_GUIDS, self::COLUMN_META_DATA, @@ -93,7 +93,7 @@ interface StateInterface extends LoggerAwareInterface /** * List of JSON/array fields. */ - public const ENTITY_ARRAY_KEYS = [ + public const array ENTITY_ARRAY_KEYS = [ self::COLUMN_PARENT, self::COLUMN_GUIDS, self::COLUMN_META_DATA, @@ -190,6 +190,13 @@ interface StateInterface extends LoggerAwareInterface */ public function isMovie(): bool; + /** + * Is the entity of show type? + * + * @return bool Return true if the entity is of show type. + */ + public function isShow(): bool; + /** * Is the entity of episode type? * diff --git a/src/Libs/Options.php b/src/Libs/Options.php index e28d967b..0d4f80ad 100644 --- a/src/Libs/Options.php +++ b/src/Libs/Options.php @@ -32,6 +32,7 @@ final class Options public const string MAX_EPISODE_RANGE = 'MAX_EPISODE_RANGE'; public const string IGNORE = 'ignore'; public const string PLEX_USE_OLD_PROGRESS_ENDPOINT = 'use_old_progress_endpoint'; + public const string TO_ENTITY = 'to_entity'; private function __construct() {