diff options
Diffstat (limited to 'src/Wallabag/CoreBundle/Helper/EntriesExport.php')
-rw-r--r-- | src/Wallabag/CoreBundle/Helper/EntriesExport.php | 114 |
1 files changed, 80 insertions, 34 deletions
diff --git a/src/Wallabag/CoreBundle/Helper/EntriesExport.php b/src/Wallabag/CoreBundle/Helper/EntriesExport.php index cbf1037b..f981ee50 100644 --- a/src/Wallabag/CoreBundle/Helper/EntriesExport.php +++ b/src/Wallabag/CoreBundle/Helper/EntriesExport.php | |||
@@ -85,7 +85,7 @@ class EntriesExport | |||
85 | public function updateAuthor($method) | 85 | public function updateAuthor($method) |
86 | { | 86 | { |
87 | if ('entry' !== $method) { | 87 | if ('entry' !== $method) { |
88 | $this->author = $method . ' authors'; | 88 | $this->author = 'Various authors'; |
89 | 89 | ||
90 | return $this; | 90 | return $this; |
91 | } | 91 | } |
@@ -150,8 +150,6 @@ class EntriesExport | |||
150 | */ | 150 | */ |
151 | 151 | ||
152 | $book->setTitle($this->title); | 152 | $book->setTitle($this->title); |
153 | // Could also be the ISBN number, prefered for published books, or a UUID. | ||
154 | $book->setIdentifier($this->title, EPub::IDENTIFIER_URI); | ||
155 | // Not needed, but included for the example, Language is mandatory, but EPub defaults to "en". Use RFC3066 Language codes, such as "en", "da", "fr" etc. | 153 | // Not needed, but included for the example, Language is mandatory, but EPub defaults to "en". Use RFC3066 Language codes, such as "en", "da", "fr" etc. |
156 | $book->setLanguage($this->language); | 154 | $book->setLanguage($this->language); |
157 | $book->setDescription('Some articles saved on my wallabag'); | 155 | $book->setDescription('Some articles saved on my wallabag'); |
@@ -167,12 +165,9 @@ class EntriesExport | |||
167 | $book->addDublinCoreMetadata(DublinCore::CONTRIBUTOR, 'PHP'); | 165 | $book->addDublinCoreMetadata(DublinCore::CONTRIBUTOR, 'PHP'); |
168 | $book->addDublinCoreMetadata(DublinCore::CONTRIBUTOR, 'wallabag'); | 166 | $book->addDublinCoreMetadata(DublinCore::CONTRIBUTOR, 'wallabag'); |
169 | 167 | ||
170 | /* | 168 | $entryIds = []; |
171 | * Front page | 169 | $entryCount = \count($this->entries); |
172 | */ | 170 | $i = 0; |
173 | if (file_exists($this->logoPath)) { | ||
174 | $book->setCoverImage('Cover.png', file_get_contents($this->logoPath), 'image/png'); | ||
175 | } | ||
176 | 171 | ||
177 | /* | 172 | /* |
178 | * Adding actual entries | 173 | * Adding actual entries |
@@ -180,21 +175,48 @@ class EntriesExport | |||
180 | 175 | ||
181 | // set tags as subjects | 176 | // set tags as subjects |
182 | foreach ($this->entries as $entry) { | 177 | foreach ($this->entries as $entry) { |
178 | ++$i; | ||
179 | |||
180 | /* | ||
181 | * Front page | ||
182 | * Set if there's only one entry in the given set | ||
183 | */ | ||
184 | if (1 === $entryCount && null !== $entry->getPreviewPicture()) { | ||
185 | $book->setCoverImage($entry->getPreviewPicture()); | ||
186 | } | ||
187 | |||
183 | foreach ($entry->getTags() as $tag) { | 188 | foreach ($entry->getTags() as $tag) { |
184 | $book->setSubject($tag->getLabel()); | 189 | $book->setSubject($tag->getLabel()); |
185 | } | 190 | } |
191 | $filename = sha1(sprintf('%s:%s', $entry->getUrl(), $entry->getTitle())); | ||
186 | 192 | ||
187 | // the reader in Kobo Devices doesn't likes special caracters | 193 | $publishedBy = $entry->getPublishedBy(); |
188 | // in filenames, we limit to A-z/0-9 | 194 | $authors = $this->translator->trans('export.unknown'); |
189 | $filename = preg_replace('/[^A-Za-z0-9\-]/', '', $entry->getTitle()); | 195 | if (!empty($publishedBy)) { |
196 | $authors = implode(',', $publishedBy); | ||
197 | } | ||
190 | 198 | ||
191 | $titlepage = $content_start . '<h1>' . $entry->getTitle() . '</h1>' . $this->getExportInformation('PHPePub') . $bookEnd; | 199 | $titlepage = $content_start . |
192 | $book->addChapter('Title', 'Title.html', $titlepage, true, EPub::EXTERNAL_REF_ADD); | 200 | '<h1>' . $entry->getTitle() . '</h1>' . |
201 | '<dl>' . | ||
202 | '<dt>' . $this->translator->trans('entry.view.published_by') . '</dt><dd>' . $authors . '</dd>' . | ||
203 | '<dt>' . $this->translator->trans('entry.metadata.reading_time') . '</dt><dd>' . $this->translator->trans('entry.metadata.reading_time_minutes_short', ['%readingTime%' => $entry->getReadingTime()]) . '</dd>' . | ||
204 | '<dt>' . $this->translator->trans('entry.metadata.added_on') . '</dt><dd>' . $entry->getCreatedAt()->format('Y-m-d') . '</dd>' . | ||
205 | '<dt>' . $this->translator->trans('entry.metadata.address') . '</dt><dd><a href="' . $entry->getUrl() . '">' . $entry->getUrl() . '</a></dd>' . | ||
206 | '</dl>' . | ||
207 | $bookEnd; | ||
208 | $book->addChapter("Entry {$i} of {$entryCount}", "{$filename}_cover.html", $titlepage, true, EPub::EXTERNAL_REF_ADD); | ||
193 | $chapter = $content_start . $entry->getContent() . $bookEnd; | 209 | $chapter = $content_start . $entry->getContent() . $bookEnd; |
194 | $book->addChapter($entry->getTitle(), htmlspecialchars($filename) . '.html', $chapter, true, EPub::EXTERNAL_REF_ADD); | 210 | |
211 | $entryIds[] = $entry->getId(); | ||
212 | $book->addChapter($entry->getTitle(), "{$filename}.html", $chapter, true, EPub::EXTERNAL_REF_ADD); | ||
195 | } | 213 | } |
196 | 214 | ||
197 | $book->buildTOC(); | 215 | $book->addChapter('Notices', 'Cover2.html', $content_start . $this->getExportInformation('PHPePub') . $bookEnd); |
216 | |||
217 | // Could also be the ISBN number, prefered for published books, or a UUID. | ||
218 | $hash = sha1(sprintf('%s:%s', $this->wallabagUrl, implode(',', $entryIds))); | ||
219 | $book->setIdentifier(sprintf('urn:wallabag:%s', $hash), EPub::IDENTIFIER_URI); | ||
198 | 220 | ||
199 | return Response::create( | 221 | return Response::create( |
200 | $book->getBook(), | 222 | $book->getBook(), |
@@ -202,7 +224,7 @@ class EntriesExport | |||
202 | [ | 224 | [ |
203 | 'Content-Description' => 'File Transfer', | 225 | 'Content-Description' => 'File Transfer', |
204 | 'Content-type' => 'application/epub+zip', | 226 | 'Content-type' => 'application/epub+zip', |
205 | 'Content-Disposition' => 'attachment; filename="' . $this->title . '.epub"', | 227 | 'Content-Disposition' => 'attachment; filename="' . $this->getSanitizedFilename() . '.epub"', |
206 | 'Content-Transfer-Encoding' => 'binary', | 228 | 'Content-Transfer-Encoding' => 'binary', |
207 | ] | 229 | ] |
208 | ); | 230 | ); |
@@ -244,9 +266,6 @@ class EntriesExport | |||
244 | } | 266 | } |
245 | $mobi->setContentProvider($content); | 267 | $mobi->setContentProvider($content); |
246 | 268 | ||
247 | // the browser inside Kindle Devices doesn't likes special caracters either, we limit to A-z/0-9 | ||
248 | $this->title = preg_replace('/[^A-Za-z0-9\-]/', '', $this->title); | ||
249 | |||
250 | return Response::create( | 269 | return Response::create( |
251 | $mobi->toString(), | 270 | $mobi->toString(), |
252 | 200, | 271 | 200, |
@@ -254,7 +273,7 @@ class EntriesExport | |||
254 | 'Accept-Ranges' => 'bytes', | 273 | 'Accept-Ranges' => 'bytes', |
255 | 'Content-Description' => 'File Transfer', | 274 | 'Content-Description' => 'File Transfer', |
256 | 'Content-type' => 'application/x-mobipocket-ebook', | 275 | 'Content-type' => 'application/x-mobipocket-ebook', |
257 | 'Content-Disposition' => 'attachment; filename="' . $this->title . '.mobi"', | 276 | 'Content-Disposition' => 'attachment; filename="' . $this->getSanitizedFilename() . '.mobi"', |
258 | 'Content-Transfer-Encoding' => 'binary', | 277 | 'Content-Transfer-Encoding' => 'binary', |
259 | ] | 278 | ] |
260 | ); | 279 | ); |
@@ -279,14 +298,6 @@ class EntriesExport | |||
279 | $pdf->SetKeywords('wallabag'); | 298 | $pdf->SetKeywords('wallabag'); |
280 | 299 | ||
281 | /* | 300 | /* |
282 | * Front page | ||
283 | */ | ||
284 | $pdf->AddPage(); | ||
285 | $intro = '<h1>' . $this->title . '</h1>' . $this->getExportInformation('tcpdf'); | ||
286 | |||
287 | $pdf->writeHTMLCell(0, 0, '', '', $intro, 0, 1, 0, true, '', true); | ||
288 | |||
289 | /* | ||
290 | * Adding actual entries | 301 | * Adding actual entries |
291 | */ | 302 | */ |
292 | foreach ($this->entries as $entry) { | 303 | foreach ($this->entries as $entry) { |
@@ -294,6 +305,22 @@ class EntriesExport | |||
294 | $pdf->SetKeywords($tag->getLabel()); | 305 | $pdf->SetKeywords($tag->getLabel()); |
295 | } | 306 | } |
296 | 307 | ||
308 | $publishedBy = $entry->getPublishedBy(); | ||
309 | $authors = $this->translator->trans('export.unknown'); | ||
310 | if (!empty($publishedBy)) { | ||
311 | $authors = implode(',', $publishedBy); | ||
312 | } | ||
313 | |||
314 | $pdf->addPage(); | ||
315 | $html = '<h1>' . $entry->getTitle() . '</h1>' . | ||
316 | '<dl>' . | ||
317 | '<dt>' . $this->translator->trans('entry.view.published_by') . '</dt><dd>' . $authors . '</dd>' . | ||
318 | '<dt>' . $this->translator->trans('entry.metadata.reading_time') . '</dt><dd>' . $this->translator->trans('entry.metadata.reading_time_minutes_short', ['%readingTime%' => $entry->getReadingTime()]) . '</dd>' . | ||
319 | '<dt>' . $this->translator->trans('entry.metadata.added_on') . '</dt><dd>' . $entry->getCreatedAt()->format('Y-m-d') . '</dd>' . | ||
320 | '<dt>' . $this->translator->trans('entry.metadata.address') . '</dt><dd><a href="' . $entry->getUrl() . '">' . $entry->getUrl() . '</a></dd>' . | ||
321 | '</dl>'; | ||
322 | $pdf->writeHTMLCell(0, 0, '', '', $html, 0, 1, 0, true, '', true); | ||
323 | |||
297 | $pdf->AddPage(); | 324 | $pdf->AddPage(); |
298 | $html = '<h1>' . $entry->getTitle() . '</h1>'; | 325 | $html = '<h1>' . $entry->getTitle() . '</h1>'; |
299 | $html .= $entry->getContent(); | 326 | $html .= $entry->getContent(); |
@@ -301,6 +328,14 @@ class EntriesExport | |||
301 | $pdf->writeHTMLCell(0, 0, '', '', $html, 0, 1, 0, true, '', true); | 328 | $pdf->writeHTMLCell(0, 0, '', '', $html, 0, 1, 0, true, '', true); |
302 | } | 329 | } |
303 | 330 | ||
331 | /* | ||
332 | * Last page | ||
333 | */ | ||
334 | $pdf->AddPage(); | ||
335 | $html = $this->getExportInformation('tcpdf'); | ||
336 | |||
337 | $pdf->writeHTMLCell(0, 0, '', '', $html, 0, 1, 0, true, '', true); | ||
338 | |||
304 | // set image scale factor | 339 | // set image scale factor |
305 | $pdf->setImageScale(PDF_IMAGE_SCALE_RATIO); | 340 | $pdf->setImageScale(PDF_IMAGE_SCALE_RATIO); |
306 | 341 | ||
@@ -310,7 +345,7 @@ class EntriesExport | |||
310 | [ | 345 | [ |
311 | 'Content-Description' => 'File Transfer', | 346 | 'Content-Description' => 'File Transfer', |
312 | 'Content-type' => 'application/pdf', | 347 | 'Content-type' => 'application/pdf', |
313 | 'Content-Disposition' => 'attachment; filename="' . $this->title . '.pdf"', | 348 | 'Content-Disposition' => 'attachment; filename="' . $this->getSanitizedFilename() . '.pdf"', |
314 | 'Content-Transfer-Encoding' => 'binary', | 349 | 'Content-Transfer-Encoding' => 'binary', |
315 | ] | 350 | ] |
316 | ); | 351 | ); |
@@ -356,7 +391,7 @@ class EntriesExport | |||
356 | 200, | 391 | 200, |
357 | [ | 392 | [ |
358 | 'Content-type' => 'application/csv', | 393 | 'Content-type' => 'application/csv', |
359 | 'Content-Disposition' => 'attachment; filename="' . $this->title . '.csv"', | 394 | 'Content-Disposition' => 'attachment; filename="' . $this->getSanitizedFilename() . '.csv"', |
360 | 'Content-Transfer-Encoding' => 'UTF-8', | 395 | 'Content-Transfer-Encoding' => 'UTF-8', |
361 | ] | 396 | ] |
362 | ); | 397 | ); |
@@ -374,7 +409,7 @@ class EntriesExport | |||
374 | 200, | 409 | 200, |
375 | [ | 410 | [ |
376 | 'Content-type' => 'application/json', | 411 | 'Content-type' => 'application/json', |
377 | 'Content-Disposition' => 'attachment; filename="' . $this->title . '.json"', | 412 | 'Content-Disposition' => 'attachment; filename="' . $this->getSanitizedFilename() . '.json"', |
378 | 'Content-Transfer-Encoding' => 'UTF-8', | 413 | 'Content-Transfer-Encoding' => 'UTF-8', |
379 | ] | 414 | ] |
380 | ); | 415 | ); |
@@ -392,7 +427,7 @@ class EntriesExport | |||
392 | 200, | 427 | 200, |
393 | [ | 428 | [ |
394 | 'Content-type' => 'application/xml', | 429 | 'Content-type' => 'application/xml', |
395 | 'Content-Disposition' => 'attachment; filename="' . $this->title . '.xml"', | 430 | 'Content-Disposition' => 'attachment; filename="' . $this->getSanitizedFilename() . '.xml"', |
396 | 'Content-Transfer-Encoding' => 'UTF-8', | 431 | 'Content-Transfer-Encoding' => 'UTF-8', |
397 | ] | 432 | ] |
398 | ); | 433 | ); |
@@ -418,7 +453,7 @@ class EntriesExport | |||
418 | 200, | 453 | 200, |
419 | [ | 454 | [ |
420 | 'Content-type' => 'text/plain', | 455 | 'Content-type' => 'text/plain', |
421 | 'Content-Disposition' => 'attachment; filename="' . $this->title . '.txt"', | 456 | 'Content-Disposition' => 'attachment; filename="' . $this->getSanitizedFilename() . '.txt"', |
422 | 'Content-Transfer-Encoding' => 'UTF-8', | 457 | 'Content-Transfer-Encoding' => 'UTF-8', |
423 | ] | 458 | ] |
424 | ); | 459 | ); |
@@ -461,4 +496,15 @@ class EntriesExport | |||
461 | 496 | ||
462 | return str_replace('%IMAGE%', '', $info); | 497 | return str_replace('%IMAGE%', '', $info); |
463 | } | 498 | } |
499 | |||
500 | /** | ||
501 | * Return a sanitized version of the title by applying translit iconv | ||
502 | * and removing non alphanumeric characters, - and space. | ||
503 | * | ||
504 | * @return string Sanitized filename | ||
505 | */ | ||
506 | private function getSanitizedFilename() | ||
507 | { | ||
508 | return preg_replace('/[^A-Za-z0-9\- \']/', '', iconv('utf-8', 'us-ascii//TRANSLIT', $this->title)); | ||
509 | } | ||
464 | } | 510 | } |