|
|
@ -1,4 +1,5 @@
|
|
|
|
<?php /** @noinspection HtmlUnknownTarget */
|
|
|
|
<?php
|
|
|
|
|
|
|
|
/** @noinspection HtmlUnknownTarget */
|
|
|
|
|
|
|
|
|
|
|
|
namespace jrosset;
|
|
|
|
namespace jrosset;
|
|
|
|
|
|
|
|
|
|
|
@ -41,16 +42,16 @@ class Main {
|
|
|
|
self::TWIG_TEMPLATE_METADATA_DESCRIPTION => <<<'TWIG'
|
|
|
|
self::TWIG_TEMPLATE_METADATA_DESCRIPTION => <<<'TWIG'
|
|
|
|
<div>
|
|
|
|
<div>
|
|
|
|
<p>{{ description }}</p>
|
|
|
|
<p>{{ description }}</p>
|
|
|
|
<p><b>Chapters:</b> {{ chapters ?? 1 }}</p>
|
|
|
|
<p><strong>Chapters:</strong> {{ chapters ?? 1 }}</p>
|
|
|
|
<p><b>Word count:</b> {{ words }}</p>
|
|
|
|
<p><strong>Word count:</strong> {{ words }}</p>
|
|
|
|
<p><b>Published:</b> {{ publishDate }}</p>
|
|
|
|
<p><strong>Published:</strong> {{ publishDate }}</p>
|
|
|
|
<p><b>Last update:</b> {{ lastUpdateDate ?? publishDate }}</p>
|
|
|
|
<p><strong>Last update:</strong> {{ lastUpdateDate ?? publishDate }}</p>
|
|
|
|
<p><b>Status:</b> {{ status }}</p>
|
|
|
|
<p><strong>Status:</strong> {{ status }}</p>
|
|
|
|
<p><b>Rated:</b> {{ rated }}</p>
|
|
|
|
<p><strong>Rated:</strong> {{ rated }}</p>
|
|
|
|
<p><b>Genre:</b> {{ genre }}</p>
|
|
|
|
<p><strong>Genre:</strong> {{ genre }}</p>
|
|
|
|
<p><b>Pairings:</b> {{ characters }}</p>
|
|
|
|
<p><strong>Pairings:</strong> {{ characters }}</p>
|
|
|
|
<p><b>Source link:</b><a href="{{ url }}"><span style="color: #6cb4ee">{{ url }}</span></a></p>
|
|
|
|
<p><strong>Source link:</strong><a href="{{ url|default('#') }}"><span style="color: #6cb4ee">{{ url|default(' ') }}</span></a></p>
|
|
|
|
<p><b>Exported by:</b> {{ exportedBy }})</p>
|
|
|
|
<p><strong>Exported by:</strong> {{ exportedBy }}</p>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
TWIG
|
|
|
|
TWIG
|
|
|
|
,
|
|
|
|
,
|
|
|
@ -260,7 +261,7 @@ EOF
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Execute the command
|
|
|
|
* Execute the command
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @param InputInterface $input The command line input
|
|
|
|
* @param InputInterface $input The command line input
|
|
|
|
* @param OutputInterface $output The command line output
|
|
|
|
* @param OutputInterface $output The command line output
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @return int The command exit status code
|
|
|
|
* @return int The command exit status code
|
|
|
@ -318,7 +319,7 @@ EOF
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Process a file
|
|
|
|
* Process a file
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @param SplFileInfo $file The file
|
|
|
|
* @param SplFileInfo $file The file
|
|
|
|
* @param OutputInterface $output The command line output
|
|
|
|
* @param OutputInterface $output The command line output
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @return void
|
|
|
|
* @return void
|
|
|
@ -386,7 +387,7 @@ EOF
|
|
|
|
//endregion
|
|
|
|
//endregion
|
|
|
|
|
|
|
|
|
|
|
|
//region Meta "container" file: root file path
|
|
|
|
//region Meta "container" file: root file path
|
|
|
|
$metaContainerPath = 'META-INF' . DIRECTORY_SEPARATOR . 'container.xml';
|
|
|
|
$metaContainerPath = 'META-INF/container.xml';
|
|
|
|
$output->writeln('Processing meta "container": ' . $metaContainerPath, OutputInterface::VERBOSITY_VERBOSE);
|
|
|
|
$output->writeln('Processing meta "container": ' . $metaContainerPath, OutputInterface::VERBOSITY_VERBOSE);
|
|
|
|
|
|
|
|
|
|
|
|
//region Read and parse
|
|
|
|
//region Read and parse
|
|
|
@ -476,11 +477,72 @@ EOF
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//endregion
|
|
|
|
//endregion
|
|
|
|
|
|
|
|
//region Delete description if present
|
|
|
|
|
|
|
|
//region Deletion form DOM
|
|
|
|
|
|
|
|
$rootFileDirty = false;
|
|
|
|
|
|
|
|
/** @noinspection HttpUrlsUsage */
|
|
|
|
|
|
|
|
$rootFileXPath->registerNamespace('dc', 'http://purl.org/dc/elements/1.1/');
|
|
|
|
|
|
|
|
if (($descriptionNodeList = $rootFileXPath->query('/r:package/r:metadata/dc:description')) !== false && $descriptionNodeList->count() > 0) {
|
|
|
|
|
|
|
|
$output->writeln($descriptionNodeList->count() . ' descriptions found → removing', OutputInterface::VERBOSITY_VERBOSE);
|
|
|
|
|
|
|
|
/** @var DOMNode $descriptionNode */
|
|
|
|
|
|
|
|
foreach ($descriptionNodeList as $descriptionNode) {
|
|
|
|
|
|
|
|
$descriptionNode->parentNode->removeChild($descriptionNode);
|
|
|
|
|
|
|
|
$rootFileDirty = true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else {
|
|
|
|
|
|
|
|
$output->writeln('no descriptions found', OutputInterface::VERBOSITY_VERBOSE);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//endregion
|
|
|
|
|
|
|
|
//region Overwrite root file in ZIP
|
|
|
|
|
|
|
|
if ($rootFileDirty) {
|
|
|
|
|
|
|
|
//region Get temporary TOC file
|
|
|
|
|
|
|
|
$rootFilePathTemp = sys_get_temp_dir() . DIRECTORY_SEPARATOR . basename($rootFilePath);
|
|
|
|
|
|
|
|
$output->writeln('Temporary TOC file path: ' . $rootFilePathTemp, OutputInterface::VERBOSITY_VERBOSE);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (file_exists($rootFilePathTemp)) {
|
|
|
|
|
|
|
|
if (!unlink($rootFilePathTemp)) {
|
|
|
|
|
|
|
|
$output->writeln('<error>Unable to delete existing temporary TOC file (' . $rootFilePathTemp . '): ' . (new LastErrorException())->getMessage() . '</error>');
|
|
|
|
|
|
|
|
$fileArchive->close();
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//endregion
|
|
|
|
|
|
|
|
//region Write temporary TOC file
|
|
|
|
|
|
|
|
$rootFileDocument = $rootFileXPath->document;
|
|
|
|
|
|
|
|
$rootFileDocument->formatOutput = true;
|
|
|
|
|
|
|
|
if (file_put_contents($rootFilePathTemp, $rootFileDocument->saveXML()) === false) {
|
|
|
|
|
|
|
|
$output->writeln('<error>Failed to write temporary TOC file (' . $rootFilePathTemp . '): ' . (new LastErrorException())->getMessage() . '</error>');
|
|
|
|
|
|
|
|
$fileArchive->close();
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//endregion
|
|
|
|
|
|
|
|
//region Replace TOC file in ZIP
|
|
|
|
|
|
|
|
if (($rootFileIndex = $fileArchive->locateName($rootFilePath)) === false) {
|
|
|
|
|
|
|
|
$output->writeln('<error>Unable to locate TOC file index: ' . $rootFilePath . '</error>');
|
|
|
|
|
|
|
|
$fileArchive->close();
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** @noinspection PhpVoidFunctionResultUsedInspection */
|
|
|
|
|
|
|
|
if (!$fileArchive->replaceFile(
|
|
|
|
|
|
|
|
$rootFilePathTemp,
|
|
|
|
|
|
|
|
$rootFileIndex,
|
|
|
|
|
|
|
|
flags: ZipArchive::FL_ENC_UTF_8
|
|
|
|
|
|
|
|
)) {
|
|
|
|
|
|
|
|
$output->writeln('<error>Unable to replace TOC file: ' . $fileArchive->getStatusString() . '</error>');
|
|
|
|
|
|
|
|
$fileArchive->close();
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//endregion
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//endregion
|
|
|
|
|
|
|
|
//endregion
|
|
|
|
|
|
|
|
|
|
|
|
unset($rootFileXPath);
|
|
|
|
unset($rootFileXPath);
|
|
|
|
//endregion
|
|
|
|
//endregion
|
|
|
|
//region TOC file: first page content
|
|
|
|
//region TOC file: first page content
|
|
|
|
$tocFilePath = dirname($rootFilePath) . DIRECTORY_SEPARATOR . $tocFilePath;
|
|
|
|
$tocFilePath = dirname($rootFilePath) . '/' . $tocFilePath;
|
|
|
|
$output->writeln('Processing TOC file: ' . $tocFilePath, OutputInterface::VERBOSITY_VERBOSE);
|
|
|
|
$output->writeln('Processing TOC file: ' . $tocFilePath, OutputInterface::VERBOSITY_VERBOSE);
|
|
|
|
|
|
|
|
|
|
|
|
//region Read and parse
|
|
|
|
//region Read and parse
|
|
|
@ -554,10 +616,10 @@ EOF
|
|
|
|
unset($tocFileXPath);
|
|
|
|
unset($tocFileXPath);
|
|
|
|
//endregion
|
|
|
|
//endregion
|
|
|
|
//region Read the first page
|
|
|
|
//region Read the first page
|
|
|
|
$firstPagePath = dirname($tocFilePath) . DIRECTORY_SEPARATOR . $firstPagePath;
|
|
|
|
$firstPagePath = dirname($tocFilePath) . '/' . $firstPagePath;
|
|
|
|
$output->writeln('Read first page: ' . $firstPagePath, OutputInterface::VERBOSITY_VERBOSE);
|
|
|
|
$output->writeln('Read first page: ' . $firstPagePath, OutputInterface::VERBOSITY_VERBOSE);
|
|
|
|
if (($firstPageStream = $fileArchive->getStream($firstPagePath)) === false) {
|
|
|
|
if (($firstPageStream = $fileArchive->getStream($firstPagePath)) === false) {
|
|
|
|
$output->writeln('<error>Failed to open first page: ' . $fileArchive->getStatusString() . '</error>');
|
|
|
|
$output->writeln('<error>Failed to open first page (' . $firstPagePath . '): ' . $fileArchive->getStatusString() . '</error>');
|
|
|
|
$fileArchive->close();
|
|
|
|
$fileArchive->close();
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -688,7 +750,7 @@ EOF
|
|
|
|
case 'status':
|
|
|
|
case 'status':
|
|
|
|
$metadata->status = match (mb_strtolower($match['value'])) {
|
|
|
|
$metadata->status = match (mb_strtolower($match['value'])) {
|
|
|
|
'completed' => 'complete',
|
|
|
|
'completed' => 'complete',
|
|
|
|
default => $match['value'],
|
|
|
|
default => $match['value'],
|
|
|
|
};
|
|
|
|
};
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
@ -757,8 +819,8 @@ EOF
|
|
|
|
/** @noinspection HttpUrlsUsage */
|
|
|
|
/** @noinspection HttpUrlsUsage */
|
|
|
|
$opfMetadata->setAttributeNS(self::DOM_NAMESPACE_ATTRIBUTE, 'xmlns:opf', self::OPF_NAMESPACE_OPF);
|
|
|
|
$opfMetadata->setAttributeNS(self::DOM_NAMESPACE_ATTRIBUTE, 'xmlns:opf', self::OPF_NAMESPACE_OPF);
|
|
|
|
|
|
|
|
|
|
|
|
$title = $opf->createElementNS(self::OPF_NAMESPACE_DC, 'dc:publisher', $metadata->publisher);
|
|
|
|
$publisher = $opf->createElementNS(self::OPF_NAMESPACE_DC, 'dc:publisher', $metadata->publisher);
|
|
|
|
$opfMetadata->appendChild($title);
|
|
|
|
$opfMetadata->appendChild($publisher);
|
|
|
|
|
|
|
|
|
|
|
|
if (isset($metadata->title)) {
|
|
|
|
if (isset($metadata->title)) {
|
|
|
|
$title = $opf->createElementNS(self::OPF_NAMESPACE_DC, 'dc:title', $metadata->title);
|
|
|
|
$title = $opf->createElementNS(self::OPF_NAMESPACE_DC, 'dc:title', $metadata->title);
|
|
|
@ -836,10 +898,10 @@ EOF
|
|
|
|
foreach ($errors as $error) {
|
|
|
|
foreach ($errors as $error) {
|
|
|
|
$levelName = match ($error->level) {
|
|
|
|
$levelName = match ($error->level) {
|
|
|
|
LIBXML_ERR_WARNING => 'Warning',
|
|
|
|
LIBXML_ERR_WARNING => 'Warning',
|
|
|
|
LIBXML_ERR_ERROR => 'Error',
|
|
|
|
LIBXML_ERR_ERROR => 'Error',
|
|
|
|
LIBXML_ERR_FATAL => 'Fatal',
|
|
|
|
LIBXML_ERR_FATAL => 'Fatal',
|
|
|
|
LIBXML_ERR_NONE => 'None',
|
|
|
|
LIBXML_ERR_NONE => 'None',
|
|
|
|
default => 'Unknown (' . $error->level . ')'
|
|
|
|
default => 'Unknown (' . $error->level . ')'
|
|
|
|
};
|
|
|
|
};
|
|
|
|
$output->writeln(
|
|
|
|
$output->writeln(
|
|
|
|
'<error>' . $levelName . ' #' . $error->code . ': ' . $error->message . ' (line: ' . $error->line . ', column: ' . $error->column . ')</error>',
|
|
|
|
'<error>' . $levelName . ' #' . $error->code . ': ' . $error->message . ' (line: ' . $error->line . ', column: ' . $error->column . ')</error>',
|
|
|
|