Skip to content

Commit

Permalink
refactor FetchHandler to support kepubify - see #77
Browse files Browse the repository at this point in the history
  • Loading branch information
mikespub committed Sep 1, 2024
1 parent 63801c5 commit 8647d12
Show file tree
Hide file tree
Showing 12 changed files with 137 additions and 100 deletions.
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,15 @@ x.x.x - TODO
1.5.x - 2024xxxx Maintenance release for 1.x (PHP >= 7.4)
* ...

2.7.x - 2024xxxx
2.8.x - 2024xxxx
* ...

2.8.0 - 20240901 Support 'kepubify' tool for Kobo
* Add FileRenderer class to send files + use sendHeaders
* Fix Zipper to allow unicode chars in file names
* Refactor FetchHandler and getUpdatedEpub to support kepubify
* Use optional kepubify tool to convert EPUB files for Kobo - see #77 by @SenorSmartyPants

2.7.5 - 20240831 Show extra data files in book detail + start GraphQL
* Changes in config_default.php file:
- new $config['cops_kepubify_path']
Expand Down
26 changes: 14 additions & 12 deletions lib/Calibre/Book.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use SebLucas\Cops\Model\EntryBook;
use SebLucas\Cops\Model\LinkEntry;
use SebLucas\Cops\Model\LinkFeed;
use SebLucas\Cops\Output\FileRenderer;
use SebLucas\Cops\Output\Format;
use SebLucas\Cops\Pages\PageId;
use SebLucas\EPubMeta\EPub;
Expand Down Expand Up @@ -567,18 +568,16 @@ public function getCoverFilePath($extension)
/**
* Summary of getUpdatedEpub
* @param int $idData
* @param bool $sendHeaders
* @return void
*/
public function getUpdatedEpub($idData, $sendHeaders = true)
public function getUpdatedEpub($idData)
{
$data = $this->getDataById($idData);

// if we want to update metadata and then use kepubify, we need to save the updated Epub first
if ($this->updateForKepub && !empty(Config::get('kepubify_path'))) {
// make a temp copy for the updated Epub file
$tmpdir = sys_get_temp_dir();
$tmpfile = tempnam($tmpdir, 'COPS') . '.epub';
$tmpfile = FileRenderer::getTempFile('epub');
if (!copy($data->getLocalPath(), $tmpfile)) {
echo 'Error: unable to copy epub file';
return;
Expand Down Expand Up @@ -626,6 +625,7 @@ public function getUpdatedEpub($idData, $sendHeaders = true)
}
$epub->updateForKepub();
}
$sendHeaders = headers_sent() ? false : true;
$epub->download($filename, $sendHeaders);
} catch (Exception $e) {
echo 'Exception : ' . $e->getMessage();
Expand All @@ -635,26 +635,28 @@ public function getUpdatedEpub($idData, $sendHeaders = true)
/**
* Summary of runKepubify
* @param string $filepath
* @param ?string $sendfile
* @param ?string $sendFile
* @return string|null
*/
public function runKepubify($filepath, $sendfile = null)
public function runKepubify($filepath, $sendFile = null)
{
if (empty(Config::get('kepubify_path'))) {
return null;
}
$tmpdir = sys_get_temp_dir();
$tmpfile = tempnam($tmpdir, 'COPS') . '.kepub.epub';
$tmpfile = FileRenderer::getTempFile('kepub.epub');
$cmd = escapeshellarg(Config::get('kepubify_path'));
$cmd .= ' -o ' . escapeshellarg($tmpfile);
$cmd .= ' ' . escapeshellarg($filepath);
exec($cmd, $output, $return);
if ($return == 0 && file_exists($tmpfile)) {
if (!empty($sendfile)) {
header('Content-Type: ' . EPub::MIME_TYPE);
header('Content-Disposition: attachment; filename="' . basename($sendfile) . '"');
if (!empty($sendFile)) {
// don't use x_accel_redirect since we deal with a tmpfile here
header('Content-Length: ' . filesize($tmpfile));
$sendHeaders = headers_sent() ? false : true;
if ($sendHeaders) {
header('Content-Type: ' . EPub::MIME_TYPE);
header('Content-Disposition: attachment; filename="' . basename($sendFile) . '"');
header('Content-Length: ' . filesize($tmpfile));
}
readfile($tmpfile);
}
return $tmpfile;
Expand Down
4 changes: 2 additions & 2 deletions lib/Calibre/Cover.php
Original file line number Diff line number Diff line change
Expand Up @@ -207,10 +207,9 @@ public function getThumbnail($width, $height, $outputfile = null, $inType = 'jpg
/**
* Summary of sendThumbnail
* @param Request $request
* @param bool $sendHeaders
* @return void
*/
public function sendThumbnail($request, $sendHeaders = true)
public function sendThumbnail($request)
{
$type = $request->get('type', 'jpg');
$width = $request->get('width');
Expand Down Expand Up @@ -239,6 +238,7 @@ public function sendThumbnail($request, $sendHeaders = true)
$mime = ($type == 'jpg') ? 'image/jpeg' : 'image/png';
$file = $this->coverFileName;

$sendHeaders = headers_sent() ? false : true;
if ($sendHeaders) {
$expires = 60 * 60 * 24 * 14;
header('Pragma: public');
Expand Down
11 changes: 7 additions & 4 deletions lib/Handlers/EpubFsHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,13 @@ public function handle($request)
try {
$data = EPubReader::getContent($idData, $component, $request);

$expires = 60 * 60 * 24 * 14;
header('Pragma: public');
header('Cache-Control: maxage=' . $expires);
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $expires) . ' GMT');
$sendHeaders = headers_sent() ? false : true;
if ($sendHeaders) {
$expires = 60 * 60 * 24 * 14;
header('Pragma: public');
header('Cache-Control: maxage=' . $expires);
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $expires) . ' GMT');
}

echo $data;
} catch (Exception $e) {
Expand Down
84 changes: 50 additions & 34 deletions lib/Handlers/FetchHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,6 @@ public function handle($request)
}

if (!empty($file)) {
if ($file == 'zipped') {
// zip all extra files and send back
$this->zipExtraFiles($request, $book);
return;
}
$this->sendExtraFile($request, $book, $file);
return;
}
Expand All @@ -113,40 +108,13 @@ public function handle($request)
}

if ($type == 'epub' && Config::get('provide_kepub') == '1' && preg_match('/Kobo/', $request->agent())) {
// run kepubify on original Epub file and send converted tmpfile
if (!empty(Config::get('kepubify_path'))) {
$kepubFile = $book->runKepubify($file, $data->getUpdatedFilenameKepub());
if (empty($kepubFile)) {
echo 'Error: failed to convert epub file';
}
return;
}
// provide kepub in name only (without update of opf properties for cover-image in Epub)
FileRenderer::sendFile($file, basename($data->getUpdatedFilenameKepub()), $data->getMimeType());
$this->sendConvertedKepub($book, $file, $data);
return;
}

FileRenderer::sendFile($file, basename($file), $data->getMimeType());
}

/**
* Summary of zipExtraFiles
* @param Request $request
* @param Book $book
* @return void
*/
public function zipExtraFiles($request, $book)
{
$zipper = new Zipper($request);

if ($zipper->isValidForExtraFiles($book)) {
// disable nginx buffering by default
header('X-Accel-Buffering: no');
$zipper->download();
} else {
echo "Invalid zipped: " . $zipper->getMessage();
}
}

/**
* Summary of sendExtraFile
* @param Request $request
Expand All @@ -156,6 +124,11 @@ public function zipExtraFiles($request, $book)
*/
public function sendExtraFile($request, $book, $file)
{
if ($file == 'zipped') {
// zip all extra files and send back
$this->zipExtraFiles($request, $book);
return;
}
$extraFiles = $book->getExtraFiles();
if (!in_array($file, $extraFiles)) {
// this will call exit()
Expand All @@ -170,6 +143,28 @@ public function sendExtraFile($request, $book, $file)
FileRenderer::sendFile($filepath, basename($filepath));
}

/**
* Summary of zipExtraFiles
* @param Request $request
* @param Book $book
* @return void
*/
public function zipExtraFiles($request, $book)
{
$zipper = new Zipper($request);

if ($zipper->isValidForExtraFiles($book)) {
$sendHeaders = headers_sent() ? false : true;
// disable nginx buffering by default
if ($sendHeaders) {
header('X-Accel-Buffering: no');
}
$zipper->download(null, $sendHeaders);
} else {
echo "Invalid zipped: " . $zipper->getMessage();
}
}

/**
* Summary of sendThumbnail
* @param Request $request
Expand Down Expand Up @@ -204,4 +199,25 @@ public function sendUpdatedEpub($request, $book, $idData)
// this will also use kepubify_path internally if defined
$book->getUpdatedEpub($idData);
}

/**
* Summary of sendConvertedKepub
* @param Book $book
* @param string $file
* @param Data $data
* @return void
*/
public function sendConvertedKepub($book, $file, $data)
{
// run kepubify on original Epub file and send converted tmpfile
if (!empty(Config::get('kepubify_path'))) {
$kepubFile = $book->runKepubify($file, $data->getUpdatedFilenameKepub());
if (empty($kepubFile)) {
echo 'Error: failed to convert epub file';
}
return;
}
// provide kepub in name only (without update of opf properties for cover-image in Epub)
FileRenderer::sendFile($file, basename($data->getUpdatedFilenameKepub()), $data->getMimeType());
}
}
12 changes: 8 additions & 4 deletions lib/Handlers/ZipFsHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,14 @@ public function handle($request)
if ($res === false) {
throw new Exception('Unknown component ' . $component);
}
$expires = 60 * 60 * 24 * 14;
header('Pragma: public');
header('Cache-Control: maxage=' . $expires);
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $expires) . ' GMT');

$sendHeaders = headers_sent() ? false : true;
if ($sendHeaders) {
$expires = 60 * 60 * 24 * 14;
header('Pragma: public');
header('Cache-Control: maxage=' . $expires);
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $expires) . ' GMT');
}

echo $zip->getFromName($component);
$zip->close();
Expand Down
7 changes: 5 additions & 2 deletions lib/Handlers/ZipperHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,12 @@ public function handle($request)
$zipper = new Zipper($request);

if ($zipper->isValidForDownload()) {
$sendHeaders = headers_sent() ? false : true;
// disable nginx buffering by default
header('X-Accel-Buffering: no');
$zipper->download();
if ($sendHeaders) {
header('X-Accel-Buffering: no');
}
$zipper->download(null, $sendHeaders);
} else {
echo "Invalid download: " . $zipper->getMessage();
}
Expand Down
2 changes: 1 addition & 1 deletion lib/Input/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
*/
class Config
{
public const VERSION = '2.7.5';
public const VERSION = '2.8.0';
public const ENDPOINT = [
"index" => "index.php",
"feed" => "feed.php",
Expand Down
16 changes: 16 additions & 0 deletions lib/Output/FileRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,22 @@ public static function getMimeType($filepath)
return $mimetype;
}

/**
* Summary of getTempFile
* @param string $extension
* @return string
*/
public static function getTempFile($extension = '')
{
$tmpdir = sys_get_temp_dir();
$tmpfile = tempnam($tmpdir, 'COPS');
if (empty($extension)) {
return $tmpfile;
}
rename($tmpfile, $tmpfile . '.' . $extension);
return $tmpfile . '.' . $extension;
}

/**
* Summary of sendFile
* @param string $filepath actual filepath
Expand Down
10 changes: 5 additions & 5 deletions test/BookTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ public function testSendThumbnailOriginal(): void

// no thumbnail resizing
ob_start();
$cover->sendThumbnail($request, false);
$cover->sendThumbnail($request);
$headers = headers_list();
$output = ob_get_clean();

Expand All @@ -392,7 +392,7 @@ public function testSendThumbnailResize(): void

// no thumbnail cache
ob_start();
$cover->sendThumbnail($request, false);
$cover->sendThumbnail($request);
$headers = headers_list();
$output = ob_get_clean();

Expand Down Expand Up @@ -422,7 +422,7 @@ public function testSendThumbnailCacheMiss(): void

// 1. cache miss
ob_start();
$cover->sendThumbnail($request, false);
$cover->sendThumbnail($request);
$headers = headers_list();
$output = ob_get_clean();

Expand All @@ -448,7 +448,7 @@ public function testSendThumbnailCacheHit(): void

// 2. cache hit
ob_start();
$cover->sendThumbnail($request, false);
$cover->sendThumbnail($request);
$headers = headers_list();
$output = ob_get_clean();

Expand Down Expand Up @@ -576,7 +576,7 @@ public function testGetUpdatedEpub(): void
$book = Book::getBookById(17);

ob_start();
$book->getUpdatedEpub(20, false);
$book->getUpdatedEpub(20);
$headers = headers_list();
$output = ob_get_clean();

Expand Down
10 changes: 0 additions & 10 deletions test/EpubFsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -132,11 +132,6 @@ public function testEncodeDecode(): void
$this->assertEquals($decoded, EPubReader::decode($encoded));
}

/**
* Summary of testEpubFsHandler
* @runInSeparateProcess
* @return void
*/
public function testEpubFsHandler(): void
{
// set request handler to 'phpunit' to override cli check in handler
Expand All @@ -152,11 +147,6 @@ public function testEpubFsHandler(): void
$this->assertStringContainsString($expected, $output);
}

/**
* Summary of testZipFsHandler
* @runInSeparateProcess
* @return void
*/
public function testZipFsHandler(): void
{
// set request handler to 'phpunit' to override cli check in handler
Expand Down
Loading

0 comments on commit 8647d12

Please sign in to comment.