Added an option to disable external id parsing for episodes and rely on relative ids.

This commit is contained in:
Abdulmhsen B. A. A
2022-06-25 21:20:56 +03:00
parent dbcb348841
commit ce0d8bf0d4
15 changed files with 282 additions and 178 deletions

39
FAQ.md
View File

@@ -308,25 +308,26 @@ it's slower than `MemoryMapper`.
### Q: What environment variables supported?
| Key | Type | Description | Default |
|-----------------------|--------|---------------------------------------------------------------------------------|-------------------------------|
| WS_DATA_PATH | string | Where to store main data. (config, db). | `${BASE_PATH}/var` |
| WS_TMP_DIR | string | Where to store temp data. (logs, cache) | `${WS_DATA_PATH}` |
| WS_TZ | string | Set timezone. | `UTC` |
| WS_CRON_IMPORT | bool | Enable import scheduled task. Value casted to bool. | `false` |
| WS_CRON_IMPORT_AT | string | When to run import scheduled task. Valid Cron Expression Expected. | `0 */1 * * *` (Every 1h) |
| WS_CRON_IMPORT_ARGS | string | Flags to pass to the import command. | `-v` |
| WS_CRON_EXPORT | bool | Enable export scheduled task. Value casted to bool. | `false` |
| WS_CRON_EXPORT_AT | string | When to run export scheduled task. Valid Cron Expression Expected. | `30 */1 * * *` (Every 1h 30m) |
| WS_CRON_EXPORT_ARGS | string | Flags to pass to the export command. | `-v` |
| WS_CRON_PUSH | bool | Enable push scheduled task. Value casted to bool. | `false` |
| WS_CRON_PUSH_AT | string | When to run push scheduled task. Valid Cron Expression Expected. | `*/10 * * * *` (Every 10m) |
| WS_CRON_PUSH_ARGS | string | Flags to pass to the push command. | `-v` |
| WS_LOGS_PRUNE_AFTER | string | Delete logs older than specified time. Set to `disable` to disable the pruning. | `-3 DAYS` |
| WS_LOGS_CONTEXT | bool | Add context to console output messages. | `false` |
| WS_LOGGER_FILE_ENABLE | bool | Save logs to file. | `true` |
| WS_LOGGER_FILE_LEVEL | string | File Logger Level. | `ERROR` |
| WS_WEBHOOK_DEBUG | bool | If enabled, allow dumping request/webhook using `rdump` & `wdump` parameters. | `false` |
| Key | Type | Description | Default |
|--------------------------|--------|---------------------------------------------------------------------------------|-------------------------------|
| WS_DATA_PATH | string | Where to store main data. (config, db). | `${BASE_PATH}/var` |
| WS_TMP_DIR | string | Where to store temp data. (logs, cache) | `${WS_DATA_PATH}` |
| WS_TZ | string | Set timezone. | `UTC` |
| WS_CRON_IMPORT | bool | Enable import scheduled task. Value casted to bool. | `false` |
| WS_CRON_IMPORT_AT | string | When to run import scheduled task. Valid Cron Expression Expected. | `0 */1 * * *` (Every 1h) |
| WS_CRON_IMPORT_ARGS | string | Flags to pass to the import command. | `-v` |
| WS_CRON_EXPORT | bool | Enable export scheduled task. Value casted to bool. | `false` |
| WS_CRON_EXPORT_AT | string | When to run export scheduled task. Valid Cron Expression Expected. | `30 */1 * * *` (Every 1h 30m) |
| WS_CRON_EXPORT_ARGS | string | Flags to pass to the export command. | `-v` |
| WS_CRON_PUSH | bool | Enable push scheduled task. Value casted to bool. | `false` |
| WS_CRON_PUSH_AT | string | When to run push scheduled task. Valid Cron Expression Expected. | `*/10 * * * *` (Every 10m) |
| WS_CRON_PUSH_ARGS | string | Flags to pass to the push command. | `-v` |
| WS_LOGS_PRUNE_AFTER | string | Delete logs older than specified time. Set to `disable` to disable the pruning. | `-3 DAYS` |
| WS_LOGS_CONTEXT | bool | Add context to console output messages. | `false` |
| WS_LOGGER_FILE_ENABLE | bool | Save logs to file. | `true` |
| WS_LOGGER_FILE_LEVEL | string | File Logger Level. | `ERROR` |
| WS_WEBHOOK_DEBUG | bool | If enabled, allow dumping request/webhook using `rdump` & `wdump` parameters. | `false` |
| WS_EPISODES_DISABLE_GUID | bool | Disable external id parsing for episodes and rely on relative ids. | `false` |
#### Container specific environment variables.

View File

@@ -32,6 +32,11 @@ return (function () {
// -- Trigger full export mode if changes exceed X number.
'threshold' => env('WS_EXPORT_THRESHOLD', 1000),
],
'episodes' => [
'disable' => [
'guid' => (bool)env('WS_EPISODES_DISABLE_GUID', false),
]
],
'ignore' => [],
];

View File

@@ -13,8 +13,10 @@ use App\Backends\Common\Response;
use App\Backends\Emby\EmbyActionTrait;
use App\Backends\Emby\EmbyClient;
use App\Backends\Jellyfin\JellyfinActionTrait;
use App\Libs\Entity\StateInterface as iFace;
use App\Libs\Config;
use App\Libs\Entity\StateInterface as iState;
use App\Libs\Guid;
use App\Libs\Options;
use Psr\Http\Message\ServerRequestInterface as iRequest;
use Throwable;
@@ -92,6 +94,8 @@ final class ParseWebhook
}
try {
$obj = $this->getItemDetails(context: $context, id: $id);
if ('item.markplayed' === $event || 'playback.scrobble' === $event) {
$isPlayed = 1;
$lastPlayedAt = time();
@@ -112,31 +116,7 @@ final class ParseWebhook
$lastPlayedAt = (0 === $isPlayed) ? makeDate(ag($json, 'Item.DateCreated'))->getTimestamp() : time();
}
$fields = [
iFace::COLUMN_EXTRA => [
$context->backendName => [
iFace::COLUMN_EXTRA_EVENT => $event,
iFace::COLUMN_EXTRA_DATE => makeDate('now'),
],
],
];
if (false === in_array($event, self::WEBHOOK_TAINTED_EVENTS)) {
$fields += [
iFace::COLUMN_WATCHED => $isPlayed,
iFace::COLUMN_UPDATED => $lastPlayedAt,
iFace::COLUMN_META_DATA => [
$context->backendName => [
iFace::COLUMN_WATCHED => (string)$isPlayed,
iFace::COLUMN_META_DATA_PLAYED_AT => (string)$lastPlayedAt,
]
],
];
}
$obj = $this->getItemDetails(context: $context, id: $id);
$guids = $guid->get(guids: ag($json, 'Item.ProviderIds', []), context: [
$logContext = [
'item' => [
'id' => ag($obj, 'Id'),
'type' => ag($obj, 'Type'),
@@ -157,19 +137,54 @@ final class ParseWebhook
},
'year' => ag($obj, 'ProductionYear'),
],
]);
];
if (count($guids) >= 1) {
$guids += Guid::makeVirtualGuid($context->backendName, (string)$id);
$fields[iFace::COLUMN_GUIDS] = $guids;
$fields[iFace::COLUMN_META_DATA][$context->backendName][iFace::COLUMN_GUIDS] = $fields[iFace::COLUMN_GUIDS];
$disableGuid = (bool)Config::get('episodes.disable.guid');
if (EmbyClient::TYPE_EPISODE === $type && true === $disableGuid) {
$guids = [];
} else {
$guids = $guid->get(guids: ag($json, 'Item.ProviderIds', []), context: $logContext);
}
$guids += Guid::makeVirtualGuid($context->backendName, (string)$id);
$fields = [
iState::COLUMN_GUIDS => $guids,
iState::COLUMN_META_DATA => [
$context->backendName => [
iState::COLUMN_GUIDS => $guid->parse(
guids: ag($json, 'Item.ProviderIds', []),
context: $logContext
),
]
],
iState::COLUMN_EXTRA => [
$context->backendName => [
iState::COLUMN_EXTRA_EVENT => $event,
iState::COLUMN_EXTRA_DATE => makeDate('now'),
],
],
];
if (false === in_array($event, self::WEBHOOK_TAINTED_EVENTS)) {
$fields = array_replace_recursive($fields, [
iState::COLUMN_WATCHED => $isPlayed,
iState::COLUMN_UPDATED => $lastPlayedAt,
iState::COLUMN_META_DATA => [
$context->backendName => [
iState::COLUMN_WATCHED => (string)$isPlayed,
iState::COLUMN_META_DATA_PLAYED_AT => (string)$lastPlayedAt,
]
],
]);
}
$entity = $this->createEntity(
context: $context,
guid: $guid,
item: $obj,
opts: ['override' => $fields],
opts: ['override' => $fields, Options::DISABLE_GUID => $disableGuid],
)->setIsTainted(isTainted: true === in_array($event, self::WEBHOOK_TAINTED_EVENTS));
if (false === $entity->hasGuids() && false === $entity->hasRelativeGuid()) {

View File

@@ -193,7 +193,7 @@ class Export extends Import
if (true === (bool)ag($context->options, Options::DRY_RUN, false)) {
return;
}
$queue->add(
$this->http->request(
$entity->isWatched() ? 'POST' : 'DELETE',

View File

@@ -11,9 +11,11 @@ use App\Backends\Common\GuidInterface as iGuid;
use App\Backends\Common\Levels;
use App\Backends\Common\Response;
use App\Backends\Jellyfin\JellyfinActionTrait;
use App\Backends\Jellyfin\JellyfinClient;
use App\Libs\Entity\StateInterface as iFace;
use App\Backends\Jellyfin\JellyfinClient as JFC;
use App\Libs\Config;
use App\Libs\Entity\StateInterface as iState;
use App\Libs\Guid;
use App\Libs\Options;
use Psr\Http\Message\ServerRequestInterface as iRequest;
use Throwable;
@@ -22,8 +24,8 @@ final class ParseWebhook
use CommonTrait, JellyfinActionTrait;
protected const WEBHOOK_ALLOWED_TYPES = [
JellyfinClient::TYPE_MOVIE,
JellyfinClient::TYPE_EPISODE,
JFC::TYPE_MOVIE,
JFC::TYPE_EPISODE,
];
protected const WEBHOOK_ALLOWED_EVENTS = [
@@ -87,58 +89,22 @@ final class ParseWebhook
}
try {
$obj = $this->getItemDetails(context: $context, id: $id);
$isPlayed = (bool)ag($json, 'Played');
$lastPlayedAt = true === $isPlayed ? ag($json, 'LastPlayedDate') : null;
$fields = [
iFace::COLUMN_WATCHED => (int)$isPlayed,
iFace::COLUMN_META_DATA => [
$context->backendName => [
iFace::COLUMN_WATCHED => true === $isPlayed ? '1' : '0',
]
],
iFace::COLUMN_EXTRA => [
$context->backendName => [
iFace::COLUMN_EXTRA_EVENT => $event,
iFace::COLUMN_EXTRA_DATE => makeDate('now'),
],
],
];
if (true === $isPlayed && null !== $lastPlayedAt) {
$lastPlayedAt = makeDate($lastPlayedAt)->getTimestamp();
$fields = array_replace_recursive($fields, [
iFace::COLUMN_UPDATED => $lastPlayedAt,
iFace::COLUMN_META_DATA => [
$context->backendName => [
iFace::COLUMN_META_DATA_PLAYED_AT => (string)$lastPlayedAt,
]
],
]);
}
$obj = $this->getItemDetails(context: $context, id: $id);
$providersId = [];
foreach (array_change_key_case($json, CASE_LOWER) as $key => $val) {
if (false === str_starts_with($key, 'provider_')) {
continue;
}
$providersId[after($key, 'provider_')] = $val;
}
$guids = $guid->get(guids: $providersId, context: [
$logContext = [
'item' => [
'id' => ag($obj, 'Id'),
'type' => ag($obj, 'Type'),
'title' => match (ag($obj, 'Type')) {
JellyfinClient::TYPE_MOVIE => sprintf(
JFC::TYPE_MOVIE => sprintf(
'%s (%s)',
ag($obj, ['Name', 'OriginalTitle'], '??'),
ag($obj, 'ProductionYear', '0000')
),
JellyfinClient::TYPE_EPISODE => trim(
JFC::TYPE_EPISODE => trim(
sprintf(
'%s - (%sx%s)',
ag($obj, 'SeriesName', '??'),
@@ -149,19 +115,64 @@ final class ParseWebhook
},
'year' => ag($obj, 'ProductionYear'),
],
]);
];
if (count($guids) >= 1) {
$guids += Guid::makeVirtualGuid($context->backendName, (string)$id);
$fields[iFace::COLUMN_GUIDS] = $guids;
$fields[iFace::COLUMN_META_DATA][$context->backendName][iFace::COLUMN_GUIDS] = $fields[iFace::COLUMN_GUIDS];
$disableGuid = (bool)Config::get('episodes.disable.guid');
$providersId = [];
foreach (array_change_key_case($json, CASE_LOWER) as $key => $val) {
if (false === str_starts_with($key, 'provider_')) {
continue;
}
$providersId[after($key, 'provider_')] = $val;
}
if (JFC::TYPE_EPISODE === $type && true === $disableGuid) {
$guids = [];
} else {
$guids = $guid->get(guids: $providersId, context: $logContext);
}
$guids += Guid::makeVirtualGuid($context->backendName, (string)$id);
$fields = [
iState::COLUMN_WATCHED => (int)$isPlayed,
iState::COLUMN_GUIDS => $guids,
iState::COLUMN_META_DATA => [
$context->backendName => [
iState::COLUMN_WATCHED => true === $isPlayed ? '1' : '0',
iState::COLUMN_GUIDS => $guid->parse(
guids: $providersId,
context: $logContext
),
]
],
iState::COLUMN_EXTRA => [
$context->backendName => [
iState::COLUMN_EXTRA_EVENT => $event,
iState::COLUMN_EXTRA_DATE => makeDate('now'),
],
],
];
if (true === $isPlayed && null !== $lastPlayedAt) {
$lastPlayedAt = makeDate($lastPlayedAt)->getTimestamp();
$fields = array_replace_recursive($fields, [
iState::COLUMN_UPDATED => $lastPlayedAt,
iState::COLUMN_META_DATA => [
$context->backendName => [
iState::COLUMN_META_DATA_PLAYED_AT => (string)$lastPlayedAt,
]
],
]);
}
$entity = $this->createEntity(
context: $context,
guid: $guid,
item: $obj,
opts: ['override' => $fields],
opts: ['override' => $fields, Options::DISABLE_GUID => $disableGuid],
)->setIsTainted(isTainted: true === in_array($event, self::WEBHOOK_TAINTED_EVENTS));
if (false === $entity->hasGuids() && false === $entity->hasRelativeGuid()) {

View File

@@ -44,6 +44,7 @@ trait JellyfinActionTrait
$type = JellyfinClient::TYPE_MAPPER[ag($item, 'Type')] ?? ag($item, 'Type');
$logContext = [
'backend' => $context->backendName,
'item' => [
'id' => (string)ag($item, 'Id'),
'type' => ag($item, 'Type'),
@@ -64,7 +65,12 @@ trait JellyfinActionTrait
],
];
$guids = $guid->get(guids: ag($item, 'ProviderIds', []), context: $logContext);
if (iState::TYPE_EPISODE === $type && true === (bool)ag($opts, Options::DISABLE_GUID, false)) {
$guids = [];
} else {
$guids = $guid->get(guids: ag($item, 'ProviderIds', []), context: $logContext);
}
$guids += Guid::makeVirtualGuid($context->backendName, (string)ag($item, 'Id'));
$builder = [
@@ -147,6 +153,13 @@ trait JellyfinActionTrait
$builder = array_replace_recursive($builder, $opts['override'] ?? []);
}
if (true === is_array($builder[iState::COLUMN_GUIDS] ?? false)) {
$builder[iState::COLUMN_GUIDS] = Guid::fromArray(
payload: $builder[iState::COLUMN_GUIDS],
context: $logContext,
)->getAll();
}
return Container::get(iState::class)::fromArray($builder);
}

View File

@@ -124,21 +124,23 @@ class JellyfinGuid implements iGuid
$guid[self::GUID_MAPPER[$key]] = $value;
} catch (Throwable $e) {
$this->logger->error(
'Unhandled exception was thrown in parsing of [%(backend)] [%(agent)] identifier.',
[
'backend' => $this->context->backendName,
'agent' => $value,
'exception' => [
'file' => $e->getFile(),
'line' => $e->getLine(),
'kind' => get_class($e),
'message' => $e->getMessage(),
],
'trace' => $this->context->trace ? $e->getTrace() : [],
...$context,
]
);
if (true === $log) {
$this->logger->error(
'Unhandled exception was thrown in parsing of [%(backend)] [%(agent)] identifier.',
[
'backend' => $this->context->backendName,
'agent' => $value,
'exception' => [
'file' => $e->getFile(),
'line' => $e->getLine(),
'kind' => get_class($e),
'message' => $e->getMessage(),
],
'trace' => $this->context->trace ? $e->getTrace() : [],
...$context,
]
);
}
continue;
}
}

View File

@@ -12,8 +12,10 @@ use App\Backends\Common\Levels;
use App\Backends\Common\Response;
use App\Backends\Plex\PlexActionTrait;
use App\Backends\Plex\PlexClient;
use App\Libs\Entity\StateInterface as iFace;
use App\Libs\Config;
use App\Libs\Entity\StateInterface as iState;
use App\Libs\Guid;
use App\Libs\Options;
use Psr\Http\Message\ServerRequestInterface as iRequest;
use Throwable;
@@ -104,53 +106,27 @@ final class ParseWebhook
}
try {
$obj = ag($this->getItemDetails(context: $context, id: $id), 'MediaContainer.Metadata.0', []);
$isPlayed = (bool)ag($item, 'viewCount', false);
$lastPlayedAt = true === $isPlayed ? ag($item, 'lastViewedAt') : null;
$fields = [
iFace::COLUMN_WATCHED => (int)$isPlayed,
iFace::COLUMN_META_DATA => [
$context->backendName => [
iFace::COLUMN_WATCHED => true === $isPlayed ? '1' : '0',
]
],
iFace::COLUMN_EXTRA => [
$context->backendName => [
iFace::COLUMN_EXTRA_EVENT => $event,
iFace::COLUMN_EXTRA_DATE => makeDate('now'),
],
],
];
if (true === $isPlayed && null !== $lastPlayedAt) {
$fields = array_replace_recursive($fields, [
iFace::COLUMN_UPDATED => (int)$lastPlayedAt,
iFace::COLUMN_META_DATA => [
$context->backendName => [
iFace::COLUMN_META_DATA_PLAYED_AT => (string)$lastPlayedAt,
]
],
]);
}
$obj = ag($this->getItemDetails(context: $context, id: $id), 'MediaContainer.Metadata.0', []);
$year = (int)ag($obj, ['grandParentYear', 'parentYear', 'year'], 0);
if (0 === $year && null !== ($airDate = ag($obj, 'originallyAvailableAt'))) {
$year = (int)makeDate($airDate)->format('Y');
}
$guids = $guid->get(guids: ag($item, 'Guid', []), context: [
$logContext = [
'item' => [
'id' => ag($item, 'ratingKey'),
'type' => ag($item, 'type'),
'title' => match ($type) {
iFace::TYPE_MOVIE => sprintf(
iState::TYPE_MOVIE => sprintf(
'%s (%s)',
ag($item, ['title', 'originalTitle'], '??'),
0 === $year ? '0000' : $year,
),
iFace::TYPE_EPISODE => sprintf(
iState::TYPE_EPISODE => sprintf(
'%s - (%sx%s)',
ag($item, ['grandparentTitle', 'originalTitle', 'title'], '??'),
str_pad((string)ag($item, 'parentIndex', 0), 2, '0', STR_PAD_LEFT),
@@ -160,19 +136,54 @@ final class ParseWebhook
'year' => 0 === $year ? '0000' : $year,
'plex_id' => str_starts_with(ag($item, 'guid', ''), 'plex://') ? ag($item, 'guid') : 'none',
],
]);
];
if (count($guids) >= 1) {
$guids += Guid::makeVirtualGuid($context->backendName, (string)$id);
$fields[iFace::COLUMN_GUIDS] = $guids;
$fields[iFace::COLUMN_META_DATA][$context->backendName][iFace::COLUMN_GUIDS] = $fields[iFace::COLUMN_GUIDS];
$disableGuid = (bool)Config::get('episodes.disable.guid');
if (PlexClient::TYPE_EPISODE === $type && true === $disableGuid) {
$guids = [];
} else {
$guids = $guid->get(guids: ag($item, 'Guid', []), context: $logContext);
}
$guids += Guid::makeVirtualGuid($context->backendName, (string)$id);
$fields = [
iState::COLUMN_WATCHED => (int)$isPlayed,
iState::COLUMN_GUIDS => $guids,
iState::COLUMN_META_DATA => [
$context->backendName => [
iState::COLUMN_WATCHED => true === $isPlayed ? '1' : '0',
iState::COLUMN_GUIDS => $guid->parse(
guids: ag($item, 'Guid', []),
context: $logContext
),
]
],
iState::COLUMN_EXTRA => [
$context->backendName => [
iState::COLUMN_EXTRA_EVENT => $event,
iState::COLUMN_EXTRA_DATE => makeDate('now'),
],
],
];
if (true === $isPlayed && null !== $lastPlayedAt) {
$fields = array_replace_recursive($fields, [
iState::COLUMN_UPDATED => (int)$lastPlayedAt,
iState::COLUMN_META_DATA => [
$context->backendName => [
iState::COLUMN_META_DATA_PLAYED_AT => (string)$lastPlayedAt,
]
],
]);
}
$entity = $this->createEntity(
context: $context,
guid: $guid,
item: $obj,
opts: ['override' => $fields],
opts: ['override' => $fields, Options::DISABLE_GUID => $disableGuid],
)->setIsTainted(isTainted: true === in_array($event, self::WEBHOOK_TAINTED_EVENTS));
if (false === $entity->hasGuids() && false === $entity->hasRelativeGuid()) {

View File

@@ -62,6 +62,7 @@ trait PlexActionTrait
$type = $this->typeMapper[ag($item, 'type')] ?? ag($item, 'type');
$logContext = [
'backend' => $context->backendName,
'item' => [
'id' => ag($item, 'ratingKey'),
'type' => ag($item, 'type'),
@@ -83,7 +84,12 @@ trait PlexActionTrait
],
];
$guids = $guid->get(guids: ag($item, 'Guid', []), context: $logContext);
if (iState::TYPE_EPISODE === $type && true === (bool)ag($opts, Options::DISABLE_GUID, false)) {
$guids = [];
} else {
$guids = $guid->get(guids: ag($item, 'Guid', []), context: $logContext);
}
$guids += Guid::makeVirtualGuid($context->backendName, (string)ag($item, 'ratingKey'));
$builder = [
@@ -163,6 +169,13 @@ trait PlexActionTrait
$builder = array_replace_recursive($builder, $opts['override'] ?? []);
}
if (true === is_array($builder[iState::COLUMN_GUIDS] ?? false)) {
$builder[iState::COLUMN_GUIDS] = Guid::fromArray(
payload: $builder[iState::COLUMN_GUIDS],
context: $logContext,
)->getAll();
}
return Container::get(iState::class)::fromArray($builder);
}

View File

@@ -186,21 +186,23 @@ final class PlexGuid implements GuidInterface
$guid[self::GUID_MAPPER[$key]] = $value;
} catch (Throwable $e) {
$this->logger->error(
'Unhandled exception was thrown in parsing of [%(backend)] [%(agent)] identifier.',
[
'backend' => $this->context->backendName,
'agent' => $val ?? null,
'exception' => [
'file' => $e->getFile(),
'line' => $e->getLine(),
'kind' => get_class($e),
'message' => $e->getMessage(),
],
'trace' => $this->context->trace ? $e->getTrace() : [],
...$context,
]
);
if (true === $log) {
$this->logger->error(
'Unhandled exception was thrown in parsing of [%(backend)] [%(agent)] identifier.',
[
'backend' => $this->context->backendName,
'agent' => $val ?? null,
'exception' => [
'file' => $e->getFile(),
'line' => $e->getLine(),
'kind' => get_class($e),
'message' => $e->getMessage(),
],
'trace' => $this->context->trace ? $e->getTrace() : [],
...$context,
]
);
}
continue;
}
}

View File

@@ -150,6 +150,10 @@ class ExportCommand extends Command
$opts[Options::IGNORE_DATE] = true;
}
if ($input->getOption('trace')) {
$opts[Options::DEBUG_TRACE] = true;
}
if ($input->getOption('dry-run')) {
$opts[Options::DRY_RUN] = true;
}

View File

@@ -5,10 +5,12 @@ declare(strict_types=1);
namespace App\Libs;
use InvalidArgumentException;
use JsonSerializable;
use Psr\Log\LoggerInterface;
use RuntimeException;
use Stringable;
final class Guid
final class Guid implements JsonSerializable, Stringable
{
public const GUID_IMDB = 'guid_imdb';
public const GUID_TVDB = 'guid_tvdb';
@@ -268,4 +270,14 @@ final class Guid
return self::$logger;
}
public function jsonSerialize(): mixed
{
return $this->getAll();
}
public function __toString(): string
{
return json_encode($this->getAll());
}
}

View File

@@ -18,6 +18,7 @@ final class Options
public const MAPPER_DISABLE_AUTOCOMMIT = 'DISABLE_AUTOCOMMIT';
public const IMPORT_METADATA_ONLY = 'IMPORT_METADATA_ONLY';
public const MISMATCH_DEEP_SCAN = 'MISMATCH_DEEP_SCAN';
public const DISABLE_GUID = 'DISABLE_GUID';
private function __construct()
{

View File

@@ -19,6 +19,7 @@ use App\Backends\Jellyfin\Action\SearchId;
use App\Backends\Jellyfin\Action\SearchQuery;
use App\Backends\Jellyfin\JellyfinActionTrait;
use App\Backends\Jellyfin\JellyfinGuid;
use App\Libs\Config;
use App\Libs\Container;
use App\Libs\Entity\StateInterface as iFace;
use App\Libs\HttpException;
@@ -260,7 +261,10 @@ class JellyfinServer implements ServerInterface
context: $this->context,
guid: $this->guid,
mapper: $mapper,
after: $after
after: $after,
opts: [
Options::DISABLE_GUID => (bool)Config::get('episodes.disable.guid'),
]
);
if ($response->hasError()) {
@@ -281,7 +285,10 @@ class JellyfinServer implements ServerInterface
guid: $this->guid,
mapper: $mapper,
after: $after,
opts: ['queue' => $queue]
opts: [
'queue' => $queue,
Options::DISABLE_GUID => (bool)Config::get('episodes.disable.guid'),
]
);
if ($response->hasError()) {

View File

@@ -19,6 +19,7 @@ use App\Backends\Plex\Action\SearchId;
use App\Backends\Plex\Action\SearchQuery;
use App\Backends\Plex\PlexActionTrait;
use App\Backends\Plex\PlexGuid;
use App\Libs\Config;
use App\Libs\Container;
use App\Libs\Entity\StateInterface as iFace;
use App\Libs\HttpException;
@@ -252,7 +253,10 @@ class PlexServer implements ServerInterface
context: $this->context,
guid: $this->guid,
mapper: $mapper,
after: $after
after: $after,
opts: [
Options::DISABLE_GUID => (bool)Config::get('episodes.disable.guid'),
]
);
if ($response->hasError()) {
@@ -273,7 +277,10 @@ class PlexServer implements ServerInterface
guid: $this->guid,
mapper: $mapper,
after: $after,
opts: ['queue' => $queue],
opts: [
'queue' => $queue,
Options::DISABLE_GUID => (bool)Config::get('episodes.disable.guid'),
],
);
if ($response->hasError()) {