diff --git a/src/Commands/Database/ListCommand.php b/src/Commands/Database/ListCommand.php index c5099814..1dc134e4 100644 --- a/src/Commands/Database/ListCommand.php +++ b/src/Commands/Database/ListCommand.php @@ -316,7 +316,7 @@ final class ListCommand extends Command $rows = null; - (new Table($output))->setHeaders(['Id', 'Type', 'Title', 'Via (Last)', 'Date', 'Played', 'Webhook Event']) + (new Table($output))->setHeaders(['Id', 'Type', 'Title', 'Via (Last)', 'Date', 'Played', 'Via Event']) ->setStyle('box')->setRows($list)->render(); } diff --git a/src/Libs/Entity/StateInterface.php b/src/Libs/Entity/StateInterface.php index 93dbd54a..7b2377e8 100644 --- a/src/Libs/Entity/StateInterface.php +++ b/src/Libs/Entity/StateInterface.php @@ -27,6 +27,7 @@ interface StateInterface 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_EXTRA = 'extra'; diff --git a/src/Libs/Initializer.php b/src/Libs/Initializer.php index c6c7e25b..8748d9dd 100644 --- a/src/Libs/Initializer.php +++ b/src/Libs/Initializer.php @@ -359,7 +359,13 @@ final class Initializer $keys = array_merge($keys, [iFace::COLUMN_GUIDS, iFace::COLUMN_EXTRA]); } - $local = $storage->update($local->apply(entity: $entity, fields: $keys)); + $local = $storage->update( + $local->apply( + entity: $entity, + fields: array_merge($keys, [iFace::COLUMN_EXTRA]) + ) + ); + return jsonResponse( status: 200, body: $local->getAll(), @@ -394,7 +400,12 @@ final class Initializer } if ((clone $cloned)->apply(entity: $entity, fields: $keys)->isChanged(fields: $keys)) { - $local = $storage->update($local->apply(entity: $entity, fields: $keys)); + $local = $storage->update( + $local->apply( + entity: $entity, + fields: array_merge($keys, [iFace::COLUMN_EXTRA]) + ) + ); return jsonResponse( status: 200, body: $local->getAll(), @@ -414,7 +425,7 @@ final class Initializer $message = '%1$s Updated.'; if ($cloned->isWatched() !== $local->isWatched()) { - $message = '%1$s Marked as [%2$s]'; + $message = '%1$s marked as [%2$s]'; queuePush($local); } diff --git a/src/Libs/Mappers/Import/DirectMapper.php b/src/Libs/Mappers/Import/DirectMapper.php index 98979f5b..374039f9 100644 --- a/src/Libs/Mappers/Import/DirectMapper.php +++ b/src/Libs/Mappers/Import/DirectMapper.php @@ -194,7 +194,7 @@ final class DirectMapper implements ImportInterface ag($entity->getMetadata($entity->via), iFace::COLUMN_ID) ); - $local = $local->apply(entity: $entity, fields: $localFields); + $local = $local->apply(entity: $entity, fields: array_merge($localFields, [iFace::COLUMN_EXTRA])); $this->removePointers($cloned)->addPointers($local, $local->id); $this->logger->notice('MAPPER: [%(backend)] updated [%(title)] metadata.', [ @@ -248,7 +248,10 @@ final class DirectMapper implements ImportInterface // -- Handle mark as unplayed logic. if (false === $entity->isWatched() && true === $cloned->shouldMarkAsUnplayed(backend: $entity)) { try { - $local = $local->apply(entity: $entity, fields: $keys)->markAsUnplayed($entity); + $local = $local->apply( + entity: $entity, + fields: array_merge($keys, [iFace::COLUMN_EXTRA]) + )->markAsUnplayed($entity); if (false === $inDryRunMode) { $this->storage->update($local); @@ -298,7 +301,10 @@ final class DirectMapper implements ImportInterface ag($entity->getMetadata($entity->via), 'id') ); - $local = $local->apply(entity: $entity, fields: $localFields); + $local = $local->apply( + entity: $entity, + fields: array_merge($localFields, [iFace::COLUMN_EXTRA]) + ); $this->logger->notice('MAPPER: [%(backend)] updated [%(title)] metadata.', [ 'id' => $cloned->id, @@ -349,7 +355,7 @@ final class DirectMapper implements ImportInterface if (true === (clone $cloned)->apply(entity: $entity, fields: $keys)->isChanged(fields: $keys)) { try { - $local = $local->apply(entity: $entity, fields: $keys); + $local = $local->apply(entity: $entity, fields: array_merge($keys, [iFace::COLUMN_EXTRA])); $this->logger->notice('MAPPER: [%(backend)] Updated [%(title)].', [ 'id' => $cloned->id, diff --git a/src/Libs/Mappers/Import/MemoryMapper.php b/src/Libs/Mappers/Import/MemoryMapper.php index fe77b9e9..9d32d206 100644 --- a/src/Libs/Mappers/Import/MemoryMapper.php +++ b/src/Libs/Mappers/Import/MemoryMapper.php @@ -163,7 +163,7 @@ final class MemoryMapper implements ImportInterface ag($entity->getMetadata($entity->via), iFace::COLUMN_ID) ); - $local = $local->apply(entity: $entity, fields: $localFields); + $local = $local->apply(entity: $entity, fields: array_merge($localFields, [iFace::COLUMN_EXTRA])); $this->removePointers($cloned)->addPointers($local, $pointer); @@ -196,7 +196,10 @@ final class MemoryMapper implements ImportInterface $this->changed[$pointer] = $pointer; Data::increment($entity->via, $entity->type . '_updated'); - $local = $local->apply(entity: $entity, fields: $keys)->markAsUnplayed(backend: $entity); + $local = $local->apply( + entity: $entity, + fields: array_merge($keys, [iFace::COLUMN_EXTRA]) + )->markAsUnplayed(backend: $entity); $this->logger->notice('MAPPER: [%(backend)] marked [%(title)] as unplayed.', [ 'id' => $cloned->id, @@ -223,7 +226,10 @@ final class MemoryMapper implements ImportInterface ag($entity->getMetadata($entity->via), iFace::COLUMN_ID) ); - $local = $local->apply(entity: $entity, fields: $localFields); + $local = $local->apply( + entity: $entity, + fields: array_merge($localFields, [iFace::COLUMN_EXTRA]) + ); $this->logger->notice('MAPPER: [%(backend)] updated [%(title)] metadata.', [ 'id' => $cloned->id, @@ -257,7 +263,7 @@ final class MemoryMapper implements ImportInterface $this->changed[$pointer] = $pointer; Data::increment($entity->via, $entity->type . '_updated'); - $local = $local->apply(entity: $entity, fields: $keys); + $local = $local->apply(entity: $entity, fields: array_merge($keys, [iFace::COLUMN_EXTRA])); $this->removePointers($cloned)->addPointers($local, $pointer); $this->logger->notice('MAPPER: [%(backend)] Updated [%(title)].', [ diff --git a/src/Libs/Servers/JellyfinServer.php b/src/Libs/Servers/JellyfinServer.php index 34e2b42f..acb20d56 100644 --- a/src/Libs/Servers/JellyfinServer.php +++ b/src/Libs/Servers/JellyfinServer.php @@ -78,6 +78,17 @@ class JellyfinServer implements ServerInterface 'PlaybackStop', ]; + protected const FIELDS = [ + 'ProviderIds', + 'DateCreated', + 'OriginalTitle', + 'SeasonUserData', + 'DateLastSaved', + 'PremiereDate', + 'ProductionYear', + 'Path', + ]; + protected UriInterface|null $url = null; protected string|null $token = null; protected string|null $user = null; @@ -436,12 +447,12 @@ class JellyfinServer implements ServerInterface array_replace_recursive( [ 'searchTerm' => $query, - 'Limit' => $limit, - 'Recursive' => 'true', - 'Fields' => 'ProviderIds,DateCreated,OriginalTitle,SeasonUserData,DateLastSaved', + 'limit' => $limit, + 'recursive' => 'true', + 'fields' => implode(',', self::FIELDS), 'enableUserData' => 'true', 'enableImages' => 'false', - 'IncludeItemTypes' => 'Episode,Movie,Series', + 'includeItemTypes' => 'Episode,Movie,Series', ], $opts['query'] ?? [] ) @@ -595,11 +606,11 @@ class JellyfinServer implements ServerInterface http_build_query( array_merge_recursive( [ - 'Recursive' => 'false', - 'Fields' => 'ProviderIds', + 'recursive' => 'false', + 'fields' => implode(',', self::FIELDS), 'enableUserData' => 'true', 'enableImages' => 'false', - 'IncludeItemTypes' => 'Episode,Movie,Series', + 'includeItemTypes' => 'Episode,Movie,Series', ], $opts['query'] ?? [] ), @@ -729,7 +740,7 @@ class JellyfinServer implements ServerInterface 'parentId' => $id, 'enableUserData' => 'false', 'enableImages' => 'false', - 'ExcludeLocationTypes' => 'Virtual', + 'excludeLocationTypes' => 'Virtual', 'include' => 'Series,Movie', ] ) @@ -930,8 +941,8 @@ class JellyfinServer implements ServerInterface $url = $this->url->withPath(sprintf('/Users/%s/items/', $this->user))->withQuery( http_build_query( [ - 'Recursive' => 'false', - 'Fields' => 'ProviderIds', + 'recursive' => 'false', + 'fields' => implode(',', self::FIELDS), 'enableUserData' => 'true', 'enableImages' => 'false', ] @@ -1068,7 +1079,7 @@ class JellyfinServer implements ServerInterface http_build_query( [ 'ids' => ag($metadata, iFace::COLUMN_ID), - 'Fields' => 'ProviderIds,DateCreated,OriginalTitle,SeasonUserData,DateLastSaved', + 'fields' => implode(',', self::FIELDS), 'enableUserData' => 'true', 'enableImages' => 'false', ] @@ -1663,8 +1674,8 @@ class JellyfinServer implements ServerInterface 'recursive' => 'false', 'enableUserData' => 'false', 'enableImages' => 'false', - 'Fields' => 'ProviderIds,DateCreated,OriginalTitle', - 'ExcludeLocationTypes' => 'Virtual', + 'fields' => implode(',', self::FIELDS), + 'excludeLocationTypes' => 'Virtual', ] ) ); @@ -1744,8 +1755,8 @@ class JellyfinServer implements ServerInterface 'enableUserData' => 'true', 'enableImages' => 'false', 'includeItemTypes' => 'Movie,Episode', - 'Fields' => 'ProviderIds,DateCreated,OriginalTitle,SeasonUserData,DateLastSaved,PremiereDate,ProductionYear', - 'ExcludeLocationTypes' => 'Virtual', + 'fields' => implode(',', self::FIELDS), + 'excludeLocationTypes' => 'Virtual', ] ) ); @@ -1861,7 +1872,17 @@ class JellyfinServer implements ServerInterface $entity = $this->createEntity( item: $item, type: $type, - opts: array_replace_recursive($opts, ['library' => ag($context, 'library.id')]) + opts: $opts + [ + 'library' => ag($context, 'library.id'), + 'override' => [ + iFace::COLUMN_EXTRA => [ + $this->getName() => [ + iFace::COLUMN_EXTRA_EVENT => 'task.import', + iFace::COLUMN_EXTRA_DATE => makeDate('now'), + ], + ], + ] + ], ); if (false === $entity->hasGuids() && false === $entity->hasRelativeGuid()) { @@ -2286,6 +2307,10 @@ class JellyfinServer implements ServerInterface $metadata[iFace::COLUMN_YEAR] = (string)$mediaYear; } + if (null !== ($mediaPath = ag($item, 'Path')) && !empty($mediaPath)) { + $metadata[iFace::COLUMN_META_PATH] = (string)$mediaPath; + } + if (null !== ($PremieredAt = ag($item, 'PremiereDate'))) { $metadataExtra[iFace::COLUMN_META_DATA_EXTRA_DATE] = makeDate($PremieredAt)->format('Y-m-d'); } @@ -2313,7 +2338,7 @@ class JellyfinServer implements ServerInterface $url = (string)$this->url->withPath(sprintf('/Users/%s/items/' . $id, $this->user))->withQuery( http_build_query( [ - 'Fields' => 'ProviderIds' + 'fields' => implode(',', self::FIELDS), ] ) ); diff --git a/src/Libs/Servers/PlexServer.php b/src/Libs/Servers/PlexServer.php index 3439d6e4..22d05a88 100644 --- a/src/Libs/Servers/PlexServer.php +++ b/src/Libs/Servers/PlexServer.php @@ -1858,7 +1858,20 @@ class PlexServer implements ServerInterface return; } - $entity = $this->createEntity(item: $item, type: $type, opts: $opts); + $entity = $this->createEntity( + item: $item, + type: $type, + opts: $opts + [ + 'override' => [ + iFace::COLUMN_EXTRA => [ + $this->getName() => [ + iFace::COLUMN_EXTRA_EVENT => 'task.import', + iFace::COLUMN_EXTRA_DATE => makeDate('now'), + ], + ], + ], + ] + ); if (!$entity->hasGuids() && !$entity->hasRelativeGuid()) { if (true === (bool)Config::get('debug.import')) { @@ -2435,8 +2448,12 @@ class PlexServer implements ServerInterface } if (null !== ($mediaYear = ag($item, ['grandParentYear', 'parentYear', 'year'])) && !empty($mediaYear)) { - $builder[iFace::COLUMN_YEAR] = $mediaYear; - $metadata[iFace::COLUMN_YEAR] = $mediaYear; + $builder[iFace::COLUMN_YEAR] = (int)$mediaYear; + $metadata[iFace::COLUMN_YEAR] = (string)$mediaYear; + } + + if (null !== ($mediaPath = ag($item, 'Media.0.Part.0.file')) && !empty($mediaPath)) { + $metadata[iFace::COLUMN_META_PATH] = (string)$mediaPath; } if (null !== ($PremieredAt = ag($item, 'originallyAvailableAt'))) {