diff --git a/src/Command.php b/src/Command.php index 4b044599..3a37931a 100644 --- a/src/Command.php +++ b/src/Command.php @@ -45,7 +45,7 @@ class Command extends BaseCommand $data['meta']['url'] = $data['meta']['simple_url'] = $url; $data['meta']['get'] = $data['meta']['env'] = []; $data['meta']['SERVER'] = array_replace_recursive($data['meta']['SERVER'], [ - 'APP_VERSION' => Config::get('version'), + 'APP_VERSION' => getAppVersion(), 'PHP_VERSION' => PHP_VERSION, 'PHP_VERSION_ID' => PHP_VERSION_ID, 'PHP_OS' => PHP_OS, diff --git a/src/Commands/State/ImportCommand.php b/src/Commands/State/ImportCommand.php index fc0c03bd..84f3d0d2 100644 --- a/src/Commands/State/ImportCommand.php +++ b/src/Commands/State/ImportCommand.php @@ -10,7 +10,6 @@ use App\Libs\Data; use App\Libs\Entity\StateInterface; use App\Libs\Mappers\ImportInterface; use App\Libs\Options; -use App\Libs\Storage\PDO\PDOAdapter; use App\Libs\Storage\StorageInterface; use Psr\Log\LoggerInterface; use RuntimeException; @@ -105,8 +104,6 @@ class ImportCommand extends Command $isCustom = !empty($serversFilter) && count($selected) >= 1; $supported = Config::get('supported', []); - $this->logger->info(sprintf('Running WatchState Version \'%s\'.', getAppVersion())); - $mapperOpts = []; if ($input->getOption('dry-run')) { @@ -171,15 +168,13 @@ class ImportCommand extends Command /** @var array $queue */ $queue = []; - if (count($list) >= 1) { - $this->logger->info('Preloading all mapper data.'); - $this->mapper->loadData(); - $this->logger->info('Finished preloading mapper data.'); - } + $this->logger->notice(sprintf('Running WatchState Version \'%s\'.', getAppVersion())); - if ($this->storage instanceof PDOAdapter) { - $this->storage->singleTransaction(); - } + $this->logger->notice('MAPPER: Preloading database into memory.'); + $this->mapper->loadData(); + $this->logger->notice('MAPPER: Finished Preloading database.'); + + $this->storage->singleTransaction(); foreach ($list as $name => &$server) { Data::addBucket($name); diff --git a/src/Libs/Mappers/Import/MemoryMapper.php b/src/Libs/Mappers/Import/MemoryMapper.php index 3ba753c6..ba5e8adb 100644 --- a/src/Libs/Mappers/Import/MemoryMapper.php +++ b/src/Libs/Mappers/Import/MemoryMapper.php @@ -184,7 +184,7 @@ final class MemoryMapper implements ImportInterface $count = count($this->changed); $this->logger->notice( - 0 === $count ? 'No changes detected.' : sprintf('Updating backend storage with \'%d\' changes.', $count) + 0 === $count ? 'MAPPER: No changes detected.' : sprintf('MAPPER: Updating \'%d\' db records.', $count) ); $inDryRunMode = $this->inDryRunMode(); diff --git a/src/Libs/Servers/EmbyServer.php b/src/Libs/Servers/EmbyServer.php index 8024278d..e4f96e3f 100644 --- a/src/Libs/Servers/EmbyServer.php +++ b/src/Libs/Servers/EmbyServer.php @@ -151,15 +151,6 @@ class EmbyServer extends JellyfinServer iFace::COLUMN_VIA => $this->name, iFace::COLUMN_TITLE => ag($json, ['Item.Name', 'Item.OriginalTitle'], '??'), iFace::COLUMN_YEAR => ag($json, 'Item.ProductionYear', 0000), - iFace::COLUMN_SEASON => null, - iFace::COLUMN_EPISODE => null, - iFace::COLUMN_META_DATA_EXTRA => [ - iFace::COLUMN_META_DATA_EXTRA_DATE => makeDate( - ag($json, ['Item.PremiereDate', 'Item.ProductionYear', 'Item.DateCreated'], 'now') - )->format('Y-m-d'), - iFace::COLUMN_META_DATA_EXTRA_EVENT => $event, - ], - iFace::COLUMN_META_DATA_PAYLOAD => $json, ], ], iFace::COLUMN_EXTRA => [], @@ -171,16 +162,22 @@ class EmbyServer extends JellyfinServer $row[iFace::COLUMN_EPISODE] = ag($json, 'Item.IndexNumber', 0); $row[iFace::COLUMN_META_DATA][$this->name][iFace::COLUMN_SEASON] = ag($json, 'Item.ParentIndexNumber', 0); $row[iFace::COLUMN_META_DATA][$this->name][iFace::COLUMN_EPISODE] = ag($json, 'Item.IndexNumber', 0); - - if (null !== ($epTitle = ag($json, ['Item.Name', 'Item.OriginalTitle'], null))) { - $row[iFace::COLUMN_META_DATA][$this->name][iFace::COLUMN_META_DATA_EXTRA][iFace::COLUMN_META_DATA_EXTRA_TITLE] = $epTitle; - } + $row[iFace::COLUMN_META_DATA][$this->name][iFace::COLUMN_META_DATA_EXTRA][iFace::COLUMN_META_DATA_EXTRA_TITLE] = ag( + $json, + ['Item.Name', 'Item.OriginalTitle'], + '??' + ); if (null !== ag($json, 'Item.SeriesId')) { $row[iFace::COLUMN_PARENT] = $this->getEpisodeParent(ag($json, 'Item.SeriesId'), ''); } } + $row[iFace::COLUMN_META_DATA][$this->name][iFace::COLUMN_META_DATA_EXTRA][iFace::COLUMN_META_DATA_EXTRA_DATE] = makeDate( + ag($json, ['Item.PremiereDate', 'Item.ProductionYear', 'Item.DateCreated'], 'now') + )->format('Y-m-d'); + $row[iFace::COLUMN_META_DATA][$this->name][iFace::COLUMN_META_DATA_EXTRA][iFace::COLUMN_META_DATA_EXTRA_EVENT] = $event; + $entity = Container::get(iFace::class)::fromArray($row)->setIsTainted($isTainted); if (!$entity->hasGuids() && !$entity->hasRelativeGuid()) { diff --git a/src/Libs/Servers/JellyfinServer.php b/src/Libs/Servers/JellyfinServer.php index 8cee1fc2..a968d431 100644 --- a/src/Libs/Servers/JellyfinServer.php +++ b/src/Libs/Servers/JellyfinServer.php @@ -338,15 +338,7 @@ class JellyfinServer implements ServerInterface iFace::COLUMN_VIA => $this->name, iFace::COLUMN_TITLE => ag($json, ['Name', 'OriginalTitle'], '??'), iFace::COLUMN_YEAR => (string)ag($json, 'Year', 0000), - iFace::COLUMN_SEASON => null, - iFace::COLUMN_EPISODE => null, - iFace::COLUMN_META_DATA_EXTRA => [ - iFace::COLUMN_META_DATA_EXTRA_DATE => makeDate( - ag($json, ['PremiereDate', 'ProductionYear', 'DateCreated'], 'now') - )->format('Y-m-d'), - iFace::COLUMN_META_DATA_EXTRA_EVENT => $event, - ], - iFace::COLUMN_META_DATA_PAYLOAD => $json, + iFace::COLUMN_GUIDS => array_change_key_case($providersId, CASE_LOWER) ] ], iFace::COLUMN_EXTRA => [], @@ -360,10 +352,11 @@ class JellyfinServer implements ServerInterface $row[iFace::COLUMN_EPISODE] = ag($json, 'EpisodeNumber', 0); $row[iFace::COLUMN_META_DATA][$this->name][iFace::COLUMN_SEASON] = ag($json, 'SeasonNumber', 0); $row[iFace::COLUMN_META_DATA][$this->name][iFace::COLUMN_EPISODE] = ag($json, 'EpisodeNumber', 0); - - if (null !== ($epTitle = ag($json, ['Name', 'OriginalTitle'], null))) { - $row[iFace::COLUMN_META_DATA][$this->name][iFace::COLUMN_META_DATA_EXTRA][iFace::COLUMN_META_DATA_EXTRA_TITLE] = $epTitle; - } + $row[iFace::COLUMN_META_DATA][$this->name][iFace::COLUMN_META_DATA_EXTRA][iFace::COLUMN_META_DATA_EXTRA_TITLE] = ag( + $json, + ['Name', 'OriginalTitle'], + '??' + ); if (null !== $seriesName) { $row[iFace::COLUMN_PARENT] = $this->getEpisodeParent( @@ -373,6 +366,11 @@ class JellyfinServer implements ServerInterface } } + $row[iFace::COLUMN_META_DATA][$this->name][iFace::COLUMN_META_DATA_EXTRA][iFace::COLUMN_META_DATA_EXTRA_DATE] = makeDate( + ag($json, ['PremiereDate', 'ProductionYear', 'DateCreated'], 'now') + )->format('Y-m-d'); + $row[iFace::COLUMN_META_DATA][$this->name][iFace::COLUMN_META_DATA_EXTRA][iFace::COLUMN_META_DATA_EXTRA_EVENT] = $event; + $entity = Container::get(iFace::class)::fromArray($row)->setIsTainted($isTainted); if (!$entity->hasGuids() && !$entity->hasRelativeGuid()) { @@ -1680,14 +1678,7 @@ class JellyfinServer implements ServerInterface iFace::COLUMN_VIA => $this->name, iFace::COLUMN_TITLE => $item->Name ?? $item->OriginalTitle ?? '??', iFace::COLUMN_YEAR => $item->ProductionYear ?? 0000, - iFace::COLUMN_SEASON => null, - iFace::COLUMN_EPISODE => null, - iFace::COLUMN_META_DATA_EXTRA => [ - iFace::COLUMN_META_DATA_EXTRA_DATE => makeDate( - $item->PremiereDate ?? $item->ProductionYear ?? 'now' - )->format('Y-m-d'), - ], - iFace::COLUMN_META_DATA_PAYLOAD => get_object_vars($item), + iFace::COLUMN_GUIDS => array_change_key_case((array)($item->ProviderIds ?? []), CASE_LOWER), ], ], iFace::COLUMN_EXTRA => [], @@ -1699,16 +1690,18 @@ class JellyfinServer implements ServerInterface $row[iFace::COLUMN_EPISODE] = $item->IndexNumber ?? 0; $row[iFace::COLUMN_META_DATA][$this->name][iFace::COLUMN_SEASON] = $item->ParentIndexNumber ?? 0; $row[iFace::COLUMN_META_DATA][$this->name][iFace::COLUMN_EPISODE] = $item->IndexNumber ?? 0; - - if (null !== ($item->Name ?? null)) { - $row[iFace::COLUMN_META_DATA][$this->name][iFace::COLUMN_META_DATA_EXTRA][iFace::COLUMN_META_DATA_EXTRA_TITLE] = $item->Name; - } + $row[iFace::COLUMN_META_DATA][$this->name][iFace::COLUMN_META_DATA_EXTRA][iFace::COLUMN_META_DATA_EXTRA_TITLE] = $item->Name ?? $item->OriginalTitle ?? '??'; if (null !== ($item->SeriesId ?? null)) { $row[iFace::COLUMN_PARENT] = $this->cacheShow[$item->SeriesId] ?? []; + $row[iFace::COLUMN_META_DATA][$this->name][iFace::COLUMN_PARENT] = $row[iFace::COLUMN_PARENT]; } } + $row[iFace::COLUMN_META_DATA][$this->name][iFace::COLUMN_META_DATA_EXTRA][iFace::COLUMN_META_DATA_EXTRA_DATE] = makeDate( + $item->PremiereDate ?? $item->ProductionYear ?? 'now' + )->format('Y-m-d'); + $entity = Container::get(iFace::class)::fromArray($row); foreach ([...$entity->getRelativePointers(), ...$entity->getPointers()] as $guid) { diff --git a/src/Libs/Servers/PlexServer.php b/src/Libs/Servers/PlexServer.php index 66468e21..e3e6b350 100644 --- a/src/Libs/Servers/PlexServer.php +++ b/src/Libs/Servers/PlexServer.php @@ -385,17 +385,7 @@ class PlexServer implements ServerInterface iFace::COLUMN_VIA => $this->name, iFace::COLUMN_TITLE => ag($item, ['title', 'originalTitle'], '??'), iFace::COLUMN_YEAR => (int)ag($item, ['grandParentYear', 'parentYear', 'year'], 0000), - iFace::COLUMN_SEASON => null, - iFace::COLUMN_EPISODE => null, - iFace::COLUMN_META_DATA_EXTRA => [ - iFace::COLUMN_META_DATA_EXTRA_DATE => makeDate( - ag($item, 'originallyAvailableAt', 'now') - )->format( - 'Y-m-d' - ), - iFace::COLUMN_META_DATA_EXTRA_EVENT => $event, - ], - iFace::COLUMN_META_DATA_PAYLOAD => $json, + iFace::COLUMN_GUIDS => ag($item, 'Guid', []), ], ], iFace::COLUMN_EXTRA => [], @@ -415,9 +405,17 @@ class PlexServer implements ServerInterface if (null !== ($parentId = ag($item, ['grandparentRatingKey', 'parentRatingKey'], null))) { $row[iFace::COLUMN_PARENT] = $this->getEpisodeParent($parentId); + $row[iFace::COLUMN_META_DATA][$this->name][iFace::COLUMN_PARENT] = $row[iFace::COLUMN_PARENT]; } } + $row[iFace::COLUMN_META_DATA][$this->name][iFace::COLUMN_META_DATA_EXTRA][iFace::COLUMN_META_DATA_EXTRA_DATE] = makeDate( + ag($item, 'originallyAvailableAt', 'now') + )->format( + 'Y-m-d' + ); + $row[iFace::COLUMN_META_DATA][$this->name][iFace::COLUMN_META_DATA_EXTRA][iFace::COLUMN_META_DATA_EXTRA_EVENT] = $event; + $entity = Container::get(iFace::class)::fromArray($row)->setIsTainted($isTainted); if (!$entity->hasGuids() && !$entity->hasRelativeGuid()) { @@ -1653,6 +1651,44 @@ class PlexServer implements ServerInterface $this->cacheShow[$item->ratingKey] = Guid::fromArray($this->getGuids($item->Guid))->getAll(); } + protected function parseGuids(array $guids): array + { + $guid = []; + + foreach ($guids as $_id) { + try { + $val = is_object($_id) ? $_id->id : $_id['id']; + + if (empty($val)) { + continue; + } + + if (true === str_starts_with($val, 'com.plexapp.agents.')) { + // -- DO NOT accept plex relative unique ids, we generate our own. + if (substr_count($val, '/') >= 3) { + continue; + } + $val = $this->parseLegacyAgent($val); + } + + if (false === str_contains($val, '://')) { + continue; + } + + [$key, $value] = explode('://', $val); + $key = strtolower($key); + + $guid[$key] = $value; + } catch (Throwable) { + continue; + } + } + + ksort($guid); + + return $guid; + } + protected function getGuids(array $guids): array { $guid = []; @@ -1826,14 +1862,7 @@ class PlexServer implements ServerInterface iFace::COLUMN_VIA => $this->name, iFace::COLUMN_TITLE => $item->title ?? $item->originalTitle ?? '??', iFace::COLUMN_YEAR => (int)($item->grandParentYear ?? $item->parentYear ?? $item->year ?? 0000), - iFace::COLUMN_SEASON => null, - iFace::COLUMN_EPISODE => null, - iFace::COLUMN_META_DATA_EXTRA => [ - iFace::COLUMN_META_DATA_EXTRA_DATE => makeDate($item->originallyAvailableAt ?? 'now')->format( - 'Y-m-d' - ), - ], - iFace::COLUMN_META_DATA_PAYLOAD => get_object_vars($item), + iFace::COLUMN_GUIDS => $this->parseGuids($item->Guid ?? []), ], ], iFace::COLUMN_EXTRA => [], @@ -1845,15 +1874,22 @@ class PlexServer implements ServerInterface $row[iFace::COLUMN_EPISODE] = $item->index ?? 0; $row[iFace::COLUMN_META_DATA][$this->name][iFace::COLUMN_SEASON] = $item->parentIndex ?? 0; $row[iFace::COLUMN_META_DATA][$this->name][iFace::COLUMN_EPISODE] = $item->index ?? 0; - $row[iFace::COLUMN_META_DATA][$this->name][iFace::COLUMN_META_DATA_EXTRA][iFace::COLUMN_META_DATA_EXTRA_TITLE] = $item->title ?? $item->originalTitle ?? '??'; + $parentId = $item->grandparentRatingKey ?? $item->parentRatingKey ?? null; if (null !== $parentId) { $row[iFace::COLUMN_PARENT] = $this->getEpisodeParent($parentId); + $row[iFace::COLUMN_META_DATA][$this->name][iFace::COLUMN_PARENT] = $row[iFace::COLUMN_PARENT]; } } + $row[iFace::COLUMN_META_DATA][$this->name][iFace::COLUMN_META_DATA_EXTRA][iFace::COLUMN_META_DATA_EXTRA_DATE] = makeDate( + $item->originallyAvailableAt ?? 'now' + )->format( + 'Y-m-d' + ); + $entity = Container::get(iFace::class)::fromArray($row); foreach ([...$entity->getRelativePointers(), ...$entity->getPointers()] as $guid) {