From ff493de09848ce6463cc30b3ecc60897e8042dfe Mon Sep 17 00:00:00 2001 From: sandreas <2050604+sandreas@users.noreply.github.com> Date: Tue, 14 Jan 2025 00:12:12 +0100 Subject: [PATCH] fix #268 - metadata.json file from audiobookshelf produces error --- src/library/Audio/Tag/AbstractTagImprover.php | 30 ++++++++++++++ src/library/Audio/Tag/ContentMetadataJson.php | 39 +++++-------------- src/library/Audio/Tag/MetadataJson.php | 18 ++++++++- 3 files changed, 56 insertions(+), 31 deletions(-) diff --git a/src/library/Audio/Tag/AbstractTagImprover.php b/src/library/Audio/Tag/AbstractTagImprover.php index 1fcdd49..1afe02d 100644 --- a/src/library/Audio/Tag/AbstractTagImprover.php +++ b/src/library/Audio/Tag/AbstractTagImprover.php @@ -4,10 +4,12 @@ namespace M4bTool\Audio\Tag; +use M4bTool\Audio\Chapter; use M4bTool\Audio\Tag; use M4bTool\Audio\Traits\LogTrait; use M4bTool\Common\Flags; use M4bTool\Tags\StringBuffer; +use Sandreas\Time\TimeUnit; use SplFileInfo; abstract class AbstractTagImprover implements TagImproverInterface @@ -117,4 +119,32 @@ public static function fromFile(SplFileInfo $reference, string $fileName = null, return $fileToLoad ? new static(file_get_contents($fileToLoad)) : new static(); } + /** + * @param Chapter[] $refChapters + * @param int $refChapterIndex + * @param array $jsonChapters + * @param int $level + */ + protected function jsonArrayToChapters(array &$refChapters, int &$refChapterIndex, array $jsonChapters, int $level = 0): void + { + foreach ($jsonChapters as $decodedChapter) { + if(isset($decodedChapter["length_ms"])) { + $lengthMs = (int)$decodedChapter["length_ms"]; + } else if(isset($decodedChapter["start"], $decodedChapter["end"])) { + $lengthMs = (float)$decodedChapter["end"] - (float)$decodedChapter["start"]; + } else { + $lengthMs = 0; + } + $title = trim($decodedChapter["title"]) ?? $refChapterIndex++; + $lastKey = count($refChapters) - 1; + $lastChapterEnd = isset($refChapters[$lastKey]) ? new TimeUnit($refChapters[$lastKey]->getEnd()->milliseconds()) : new TimeUnit(); + $refChapters[] = new Chapter($lastChapterEnd, new TimeUnit($lengthMs), $title); + + // handle subchapters + if (isset($decodedChapter["chapters"]) && is_array($decodedChapter["chapters"])) { + $this->jsonArrayToChapters($refChapters, $refChapterIndex,$decodedChapter["chapters"], $level + 1); + } + } + } + } diff --git a/src/library/Audio/Tag/ContentMetadataJson.php b/src/library/Audio/Tag/ContentMetadataJson.php index 22e46ba..5c4dba9 100644 --- a/src/library/Audio/Tag/ContentMetadataJson.php +++ b/src/library/Audio/Tag/ContentMetadataJson.php @@ -13,13 +13,11 @@ class ContentMetadataJson extends AbstractTagImprover { - public $overloadChapters = []; + public array $overloadChapters = []; - protected $chaptersContent; - /** @var Flags */ - protected $flags; - /** @var int */ - protected $chapterIndex; + protected string $chaptersContent; + protected Flags $flags; + protected int $chapterIndex; public function __construct($fileContents = "", Flags $flags = null) { @@ -31,17 +29,17 @@ public function __construct($fileContents = "", Flags $flags = null) /** * Cover constructor. * @param SplFileInfo $reference - * @param null $fileName + * @param string|null $fileName * @param Flags|null $flags * @return ContentMetadataJson */ - public static function fromFile(SplFileInfo $reference, string $fileName = null, Flags $flags = null): static + public static function fromFile(SplFileInfo $reference, ?string $fileName = null, Flags $flags = null): static { $fileContents = static::loadFileContents($reference, $fileName); return new static($fileContents, $flags); } - protected static function loadFileContents(SplFileInfo $reference, $fileName = null) + protected static function loadFileContents(SplFileInfo $reference, $fileName = null): string { $path = $reference->isDir() ? $reference : new SplFileInfo($reference->getPath()); $fileName = $fileName ?: "content_metadata_*.json"; @@ -81,7 +79,7 @@ public function improve(Tag $tag): Tag if (isset($decoded["content_metadata"]["chapter_info"]["brandIntroDurationMs"])) { $chapters[] = new Chapter(new TimeUnit(0), new TimeUnit($decoded["content_metadata"]["chapter_info"]["brandIntroDurationMs"]), Chapter::DEFAULT_INTRO_NAME); } - $this->createChapters($chapters, $decodedChapters); + $this->jsonArrayToChapters($chapters, $this->chapterIndex, $decodedChapters); $lastChapter = end($chapters); @@ -102,24 +100,5 @@ public function improve(Tag $tag): Tag } - /** - * @param Chapter[] $chapters - * @param $decodedChapters - * @param int $level - */ - private function createChapters(&$chapters, $decodedChapters, $level = 0) - { - foreach ($decodedChapters as $decodedChapter) { - $lengthMs = $decodedChapter["length_ms"] ?? 0; - $title = trim($decodedChapter["title"]) ?? $this->chapterIndex++; - $lastKey = count($chapters) - 1; - $lastChapterEnd = isset($chapters[$lastKey]) ? new TimeUnit($chapters[$lastKey]->getEnd()->milliseconds()) : new TimeUnit(); - $chapters[] = new Chapter($lastChapterEnd, new TimeUnit($lengthMs), $title); - - // handle sub chapters - if (isset($decodedChapter["chapters"]) && is_array($decodedChapter["chapters"])) { - $this->createChapters($chapters, $decodedChapter["chapters"], $level + 1); - } - } - } + } diff --git a/src/library/Audio/Tag/MetadataJson.php b/src/library/Audio/Tag/MetadataJson.php index 51325de..3aa1987 100644 --- a/src/library/Audio/Tag/MetadataJson.php +++ b/src/library/Audio/Tag/MetadataJson.php @@ -28,7 +28,7 @@ public function improve(Tag $tag): Tag $this->notice(sprintf("%s loaded for tagging", self::$defaultFileName)); foreach ($decoded as $propertyName => $propertyValue) { - if (!property_exists($tag, $propertyName)) { + if (!property_exists($tag, $propertyName) || $tag->isTransientProperty($propertyName)) { continue; } if ($propertyName === "year") { @@ -43,6 +43,22 @@ public function improve(Tag $tag): Tag $tag->$propertyName = $propertyValue; } + if(isset($decoded["series"])) { + $tag->series = is_scalar($decoded["series"]) ? $decoded["series"] : implode(", ", $decoded["series"]); + } + if(isset($decoded["seriesPart"])) { + $tag->seriesPart = is_scalar($decoded["seriesPart"]) ? $decoded["seriesPart"] : implode(", ", $decoded["seriesPart"]); + } + + if(isset($decoded["chapters"]) && is_array($decoded["chapters"])) { + if(count($tag->chapters) < count($decoded["chapters"])) { + $tag->chapters = []; + } + $chapterIndex = 1; + $this->jsonArrayToChapters($tag->chapters, $chapterIndex, $decoded["chapters"]); + } + + return $tag; }