Skip to content

Commit

Permalink
mobi cover
Browse files Browse the repository at this point in the history
  • Loading branch information
ewilan-riviere committed Sep 19, 2023
1 parent d8cfda8 commit 86b8cad
Show file tree
Hide file tree
Showing 10 changed files with 304 additions and 143 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@ psalm.xml
vendor
.php-cs-fixer.cache
.DS_Store
CHANGELOG-draft.md
node_modules
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ There is a lot of different formats for eBooks and comics, if you want to know m
| iBook (Apple) | `.ibooks` || _proprietary_ |
| DjVu | `.djvu`, `.djv` || |
| Rich Text Format | `.rtf` || |
| FictionBook | `.fb2` | | |
| FictionBook | `.fb2` | | |
| Broadband eBooks | `.lrf`, `.lrx` || |
| Palm Media | `.pdb` || |
| CBA | `.cbz`, `.cbr`, `.cb7`, `.cbt` || |
Expand Down
43 changes: 25 additions & 18 deletions src/Formats/Mobi/MobiModule.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Kiwilan\Ebook\EbookCover;
use Kiwilan\Ebook\Formats\EbookModule;
use Kiwilan\Ebook\Formats\Mobi\Parser\MobiParser;
use Kiwilan\Ebook\Formats\Mobi\Parser\MobiReader;
use Kiwilan\Ebook\Tools\BookAuthor;
use Kiwilan\Ebook\Tools\BookIdentifier;

Expand All @@ -18,8 +19,6 @@ class MobiModule extends EbookModule
{
protected ?MobiParser $parser = null;

protected ?string $cover = null;

public static function make(Ebook $ebook): EbookModule
{
$self = new self($ebook);
Expand All @@ -30,44 +29,42 @@ public static function make(Ebook $ebook): EbookModule

public function toEbook(): Ebook
{
if (! $this->parser->getReader() || empty($this->parser->getReader()->getRecords())) {
if (! $this->parser->isValid()) {
return $this->ebook;
}

$reader = $this->parser->getReader();

foreach ($reader->get(100, true) as $author) {
foreach ($this->parser->get(MobiReader::AUTHOR, true) as $author) {
$this->ebook->setAuthor(new BookAuthor($author));
}

foreach ($reader->get(104, true) as $isbn) {
foreach ($this->parser->get(MobiReader::ISBN, true) as $isbn) {
$this->ebook->setIdentifier(new BookIdentifier($isbn));
}

$this->ebook->setIdentifier(new BookIdentifier($reader->get(113), '113'));
$this->ebook->setIdentifier(new BookIdentifier($reader->get(112), '112'));
$this->ebook->setIdentifier(new BookIdentifier($this->parser->get(MobiReader::SOURCE), 'source'));
$this->ebook->setIdentifier(new BookIdentifier($this->parser->get(MobiReader::ASIN), 'asin'));

$publishingDate = $reader->get(106);
$publishingDate = $this->parser->get(MobiReader::PUBLISHINGDATE);
if ($publishingDate) {
$publishingDate = new DateTime($publishingDate);
}

$this->ebook->setPublisher($reader->get(101));
$this->ebook->setPublisher($this->parser->get(MobiReader::PUBLISHER));

$description = $reader->get(103);
$description = $this->parser->get(MobiReader::DESCRIPTION);
$this->ebook->setDescription($this->descriptionToString($description));
$this->ebook->setDescriptionHtml($this->descriptionToHtml($description));

foreach ($reader->get(105, true) as $value) {
foreach ($this->parser->get(MobiReader::SUBJECT, true) as $value) {
$this->ebook->setTag($value);
}

$this->ebook->setPublishDate($publishingDate);
$this->ebook->setTitle($reader->get(503));
$this->ebook->setLanguage($reader->get(524));
$this->ebook->setCopyright($reader->get(108));
$this->ebook->setTitle($this->parser->get(MobiReader::UPDATEDTITLE));
$this->ebook->setLanguage($this->parser->get(MobiReader::LANGUAGE));
$this->ebook->setCopyright($this->parser->get(MobiReader::CONTRIBUTOR));

foreach ($reader->getRecords() as $value) {
foreach ($this->parser->getExthRecords() as $value) {
$this->ebook->setExtra($value->data);
}

Expand All @@ -76,7 +73,12 @@ public function toEbook(): Ebook

public function toCover(): ?EbookCover
{
return EbookCover::make(content: $this->cover);
$items = $this->parser->getImages()->getItems();
if (count($items) === 0) {
return null;
}

return EbookCover::make(content: end($items));
}

public function toCounts(): Ebook
Expand All @@ -88,4 +90,9 @@ public function toArray(): array
{
return [];
}

public function getParser(): ?MobiParser
{
return $this->parser;
}
}
48 changes: 48 additions & 0 deletions src/Formats/Mobi/Parser/MobiImages.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

namespace Kiwilan\Ebook\Formats\Mobi\Parser;

use Kiwilan\Ebook\Utils\Stream;

class MobiImages
{
protected function __construct(
protected Stream $stream,
protected array $items = [],
) {
}

public static function make(string $path): ?self
{
$self = new self(Stream::make($path));

$fileContent = $self->stream->read($self->stream->filesize());
$self->stream->close();

$regexJpg = '/\xff\xd8\xff.*?\xff\xd9/s';
if (preg_match_all($regexJpg, $fileContent, $matches)) {
foreach ($matches[0] as $index => $imageData) {
$self->items[] = base64_encode($imageData);
}
}

return $self;
}

/**
* @return string[]
*/
public function getItems(bool $base64Decode = true): array
{
if (! $base64Decode) {
return $this->items;
}

$data = [];
foreach ($this->items as $item) {
$data[] = base64_decode($item);
}

return $data;
}
}
70 changes: 51 additions & 19 deletions src/Formats/Mobi/Parser/MobiParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,38 +10,44 @@
class MobiParser
{
/**
* @param PalmRecord[] $records
* @param PalmRecord[] $palmRecords
* @param ExthRecord[] $exthRecords
*/
protected function __construct(
protected Stream $stream,
protected ?string $error = null,
protected array $records = [],
protected array $palmRecords = [],
protected array $exthRecords = [],
protected ?PalmDOCHeader $palmDOCHeader = null,
protected ?MobiHeader $mobiHeader = null,
protected ?ExthHeader $exthHeader = null,
protected ?MobiReader $reader = null,
protected ?MobiImages $images = null,
protected bool $isValid = false,
) {
}

public static function make(string $path): ?self
{
$self = new self(
stream: Stream::make($path),
);
$self = new self(Stream::make($path));
$self->parse();
$self->reader = MobiReader::make($self);
$self->images = MobiImages::make($path);

return $self;
}

public function getReader(): ?MobiReader
public function get(int $record, bool $asArray = false): array|string|null
{
return $this->reader;
}
$data = $this->getRecordData($record);

public function getError(): ?string
{
return $this->error;
if ($asArray) {
return $data;
}

if (count($data) === 1) {
return $data[0];
}

return implode(', ', $data);
}

private function parse(): self
Expand Down Expand Up @@ -71,11 +77,11 @@ private function parse(): self
id: $this->stream->binaryToDecimal($this->stream->read(3)),
);

$this->records[] = $record;
$this->palmRecords[] = $record;
}

$this->palmDOCHeader = new PalmDOCHeader();
$this->stream->seek($this->records[0]->offset);
$this->stream->seek($this->palmRecords[0]->offset);
$this->palmDOCHeader->compression = $this->stream->binaryToDecimal($this->stream->read(2));
$this->stream->read(2);
$this->palmDOCHeader->textLength = $this->stream->binaryToDecimal($this->stream->read(4));
Expand Down Expand Up @@ -122,6 +128,9 @@ private function parse(): self
$this->exthHeader->records[] = $record;
}

$this->exthRecords = $this->exthHeader->records;
$this->isValid = true;

$this->stream->close();

return $this;
Expand Down Expand Up @@ -150,15 +159,38 @@ public function getExthHeader(): ?ExthHeader
/**
* @return PalmRecord[]
*/
public function getRecords(): array
public function getPalmRecords(): array
{
return $this->palmRecords;
}

/**
* @return ExthRecord[]
*/
public function getExthRecords(): array
{
return $this->exthRecords;
}

public function getError(): ?string
{
return $this->error;
}

public function getImages(): ?MobiImages
{
return $this->images;
}

public function isValid(): bool
{
return $this->records;
return $this->isValid;
}

/**
* @return ExthRecord[]|null
*/
protected function getRecord(int $type): ?array
private function getRecord(int $type): ?array
{
if (! $this->exthHeader?->records) {
return null;
Expand All @@ -181,7 +213,7 @@ protected function getRecord(int $type): ?array
/**
* @return string[]|null
*/
public function getRecordData(int $type): ?array
private function getRecordData(int $type): ?array
{
$records = $this->getRecord($type);
$data = [];
Expand Down
Loading

0 comments on commit 86b8cad

Please sign in to comment.