diff options
author | ArthurHoaro <arthur@hoa.ro> | 2019-06-08 13:59:19 +0200 |
---|---|---|
committer | ArthurHoaro <arthur@hoa.ro> | 2019-07-06 12:21:52 +0200 |
commit | 6a4872520cbbc012b5a8358cd50c78844afe8d07 (patch) | |
tree | bf7ce75b0c93a95d8e7a805b1ebfbe8d90a9565a | |
parent | 5d8a958d5d139337546bb3f4091a6ef7592ea752 (diff) | |
download | Shaarli-6a4872520cbbc012b5a8358cd50c78844afe8d07.tar.gz Shaarli-6a4872520cbbc012b5a8358cd50c78844afe8d07.tar.zst Shaarli-6a4872520cbbc012b5a8358cd50c78844afe8d07.zip |
Automatically retrieve description for new bookmarks
If the option is enabled, it will try to find a meta tag containing
the page description and keywords, just like we do for the page title.
It will either look for regular meta tag or OpenGraph ones.
The option is disabled by default.
Note that keywords meta tags is mostly not used.
In `configure` template, the variable associated with this setting
is `$retrieve_description`.
Fixes #1302
-rw-r--r-- | application/bookmark/LinkUtils.php | 85 | ||||
-rw-r--r-- | application/config/ConfigManager.php | 1 | ||||
-rw-r--r-- | doc/md/Shaarli-configuration.md | 2 | ||||
-rw-r--r-- | inc/languages/fr/LC_MESSAGES/shaarli.po | 128 | ||||
-rw-r--r-- | index.php | 5 | ||||
-rw-r--r-- | tests/bookmark/LinkUtilsTest.php | 204 | ||||
-rw-r--r-- | tpl/default/configure.html | 16 | ||||
-rw-r--r-- | tpl/vintage/configure.html | 8 |
8 files changed, 374 insertions, 75 deletions
diff --git a/application/bookmark/LinkUtils.php b/application/bookmark/LinkUtils.php index 35a5b290..77eb2d95 100644 --- a/application/bookmark/LinkUtils.php +++ b/application/bookmark/LinkUtils.php | |||
@@ -7,13 +7,25 @@ use Shaarli\Bookmark\LinkDB; | |||
7 | * | 7 | * |
8 | * @param string $charset to extract from the downloaded page (reference) | 8 | * @param string $charset to extract from the downloaded page (reference) |
9 | * @param string $title to extract from the downloaded page (reference) | 9 | * @param string $title to extract from the downloaded page (reference) |
10 | * @param string $description to extract from the downloaded page (reference) | ||
11 | * @param string $keywords to extract from the downloaded page (reference) | ||
12 | * @param bool $retrieveDescription Automatically tries to retrieve description and keywords from HTML content | ||
10 | * @param string $curlGetInfo Optionally overrides curl_getinfo function | 13 | * @param string $curlGetInfo Optionally overrides curl_getinfo function |
11 | * | 14 | * |
12 | * @return Closure | 15 | * @return Closure |
13 | */ | 16 | */ |
14 | function get_curl_download_callback(&$charset, &$title, $curlGetInfo = 'curl_getinfo') | 17 | function get_curl_download_callback( |
15 | { | 18 | &$charset, |
19 | &$title, | ||
20 | &$description, | ||
21 | &$keywords, | ||
22 | $retrieveDescription, | ||
23 | $curlGetInfo = 'curl_getinfo' | ||
24 | ) { | ||
16 | $isRedirected = false; | 25 | $isRedirected = false; |
26 | $currentChunk = 0; | ||
27 | $foundChunk = null; | ||
28 | |||
17 | /** | 29 | /** |
18 | * cURL callback function for CURLOPT_WRITEFUNCTION (called during the download). | 30 | * cURL callback function for CURLOPT_WRITEFUNCTION (called during the download). |
19 | * | 31 | * |
@@ -25,7 +37,18 @@ function get_curl_download_callback(&$charset, &$title, $curlGetInfo = 'curl_get | |||
25 | * | 37 | * |
26 | * @return int|bool length of $data or false if we need to stop the download | 38 | * @return int|bool length of $data or false if we need to stop the download |
27 | */ | 39 | */ |
28 | return function (&$ch, $data) use ($curlGetInfo, &$charset, &$title, &$isRedirected) { | 40 | return function (&$ch, $data) use ( |
41 | $retrieveDescription, | ||
42 | $curlGetInfo, | ||
43 | &$charset, | ||
44 | &$title, | ||
45 | &$description, | ||
46 | &$keywords, | ||
47 | &$isRedirected, | ||
48 | &$currentChunk, | ||
49 | &$foundChunk | ||
50 | ) { | ||
51 | $currentChunk++; | ||
29 | $responseCode = $curlGetInfo($ch, CURLINFO_RESPONSE_CODE); | 52 | $responseCode = $curlGetInfo($ch, CURLINFO_RESPONSE_CODE); |
30 | if (!empty($responseCode) && in_array($responseCode, [301, 302])) { | 53 | if (!empty($responseCode) && in_array($responseCode, [301, 302])) { |
31 | $isRedirected = true; | 54 | $isRedirected = true; |
@@ -50,9 +73,34 @@ function get_curl_download_callback(&$charset, &$title, $curlGetInfo = 'curl_get | |||
50 | } | 73 | } |
51 | if (empty($title)) { | 74 | if (empty($title)) { |
52 | $title = html_extract_title($data); | 75 | $title = html_extract_title($data); |
76 | $foundChunk = ! empty($title) ? $currentChunk : $foundChunk; | ||
77 | } | ||
78 | if ($retrieveDescription && empty($description)) { | ||
79 | $description = html_extract_tag('description', $data); | ||
80 | $foundChunk = ! empty($description) ? $currentChunk : $foundChunk; | ||
53 | } | 81 | } |
82 | if ($retrieveDescription && empty($keywords)) { | ||
83 | $keywords = html_extract_tag('keywords', $data); | ||
84 | if (! empty($keywords)) { | ||
85 | $foundChunk = $currentChunk; | ||
86 | // Keywords use the format tag1, tag2 multiple words, tag | ||
87 | // So we format them to match Shaarli's separator and glue multiple words with '-' | ||
88 | $keywords = implode(' ', array_map(function($keyword) { | ||
89 | return implode('-', preg_split('/\s+/', trim($keyword))); | ||
90 | }, explode(',', $keywords))); | ||
91 | } | ||
92 | } | ||
93 | |||
54 | // We got everything we want, stop the download. | 94 | // We got everything we want, stop the download. |
55 | if (!empty($responseCode) && !empty($contentType) && !empty($charset) && !empty($title)) { | 95 | // If we already found either the title, description or keywords, |
96 | // it's highly unlikely that we'll found the other metas further than | ||
97 | // in the same chunk of data or the next one. So we also stop the download after that. | ||
98 | if ((!empty($responseCode) && !empty($contentType) && !empty($charset)) && $foundChunk !== null | ||
99 | && (! $retrieveDescription | ||
100 | || $foundChunk < $currentChunk | ||
101 | || (!empty($title) && !empty($description) && !empty($keywords)) | ||
102 | ) | ||
103 | ) { | ||
56 | return false; | 104 | return false; |
57 | } | 105 | } |
58 | 106 | ||
@@ -111,6 +159,35 @@ function html_extract_charset($html) | |||
111 | } | 159 | } |
112 | 160 | ||
113 | /** | 161 | /** |
162 | * Extract meta tag from HTML content in either: | ||
163 | * - OpenGraph: <meta property="og:[tag]" ...> | ||
164 | * - Meta tag: <meta name="[tag]" ...> | ||
165 | * | ||
166 | * @param string $tag Name of the tag to retrieve. | ||
167 | * @param string $html HTML content where to look for charset. | ||
168 | * | ||
169 | * @return bool|string Charset string if found, false otherwise. | ||
170 | */ | ||
171 | function html_extract_tag($tag, $html) | ||
172 | { | ||
173 | $propertiesKey = ['property', 'name', 'itemprop']; | ||
174 | $properties = implode('|', $propertiesKey); | ||
175 | // Try to retrieve OpenGraph image. | ||
176 | $ogRegex = '#<meta[^>]+(?:'. $properties .')=["\']?(?:og:)?'. $tag .'["\'\s][^>]*content=["\']?(.*?)["\'/>]#'; | ||
177 | // If the attributes are not in the order property => content (e.g. Github) | ||
178 | // New regex to keep this readable... more or less. | ||
179 | $ogRegexReverse = '#<meta[^>]+content=["\']([^"\']+)[^>]+(?:'. $properties .')=["\']?(?:og)?:'. $tag .'["\'\s/>]#'; | ||
180 | |||
181 | if (preg_match($ogRegex, $html, $matches) > 0 | ||
182 | || preg_match($ogRegexReverse, $html, $matches) > 0 | ||
183 | ) { | ||
184 | return $matches[1]; | ||
185 | } | ||
186 | |||
187 | return false; | ||
188 | } | ||
189 | |||
190 | /** | ||
114 | * Count private links in given linklist. | 191 | * Count private links in given linklist. |
115 | * | 192 | * |
116 | * @param array|Countable $links Linklist. | 193 | * @param array|Countable $links Linklist. |
diff --git a/application/config/ConfigManager.php b/application/config/ConfigManager.php index 30993928..c95e6800 100644 --- a/application/config/ConfigManager.php +++ b/application/config/ConfigManager.php | |||
@@ -365,6 +365,7 @@ class ConfigManager | |||
365 | $this->setEmpty('general.links_per_page', 20); | 365 | $this->setEmpty('general.links_per_page', 20); |
366 | $this->setEmpty('general.enabled_plugins', self::$DEFAULT_PLUGINS); | 366 | $this->setEmpty('general.enabled_plugins', self::$DEFAULT_PLUGINS); |
367 | $this->setEmpty('general.default_note_title', 'Note: '); | 367 | $this->setEmpty('general.default_note_title', 'Note: '); |
368 | $this->setEmpty('general.retrieve_description', false); | ||
368 | 369 | ||
369 | $this->setEmpty('updates.check_updates', false); | 370 | $this->setEmpty('updates.check_updates', false); |
370 | $this->setEmpty('updates.check_updates_branch', 'stable'); | 371 | $this->setEmpty('updates.check_updates_branch', 'stable'); |
diff --git a/doc/md/Shaarli-configuration.md b/doc/md/Shaarli-configuration.md index a931ab1e..664e36dd 100644 --- a/doc/md/Shaarli-configuration.md +++ b/doc/md/Shaarli-configuration.md | |||
@@ -56,6 +56,8 @@ _These settings should not be edited_ | |||
56 | - **timezone**: See [the list of supported timezones](http://php.net/manual/en/timezones.php). | 56 | - **timezone**: See [the list of supported timezones](http://php.net/manual/en/timezones.php). |
57 | - **enabled_plugins**: List of enabled plugins. | 57 | - **enabled_plugins**: List of enabled plugins. |
58 | - **default_note_title**: Default title of a new note. | 58 | - **default_note_title**: Default title of a new note. |
59 | - **retrieve_description** (boolean): If set to true, for every new links Shaarli will try | ||
60 | to retrieve the description and keywords from the HTML meta tags. | ||
59 | 61 | ||
60 | ### Security | 62 | ### Security |
61 | 63 | ||
diff --git a/inc/languages/fr/LC_MESSAGES/shaarli.po b/inc/languages/fr/LC_MESSAGES/shaarli.po index c2c73b29..611296f1 100644 --- a/inc/languages/fr/LC_MESSAGES/shaarli.po +++ b/inc/languages/fr/LC_MESSAGES/shaarli.po | |||
@@ -1,8 +1,8 @@ | |||
1 | msgid "" | 1 | msgid "" |
2 | msgstr "" | 2 | msgstr "" |
3 | "Project-Id-Version: Shaarli\n" | 3 | "Project-Id-Version: Shaarli\n" |
4 | "POT-Creation-Date: 2019-05-25 16:37+0200\n" | 4 | "POT-Creation-Date: 2019-07-06 12:14+0200\n" |
5 | "PO-Revision-Date: 2019-05-25 16:37+0200\n" | 5 | "PO-Revision-Date: 2019-07-06 12:17+0200\n" |
6 | "Last-Translator: \n" | 6 | "Last-Translator: \n" |
7 | "Language-Team: Shaarli\n" | 7 | "Language-Team: Shaarli\n" |
8 | "Language: fr_FR\n" | 8 | "Language: fr_FR\n" |
@@ -252,7 +252,7 @@ msgstr "404 Introuvable" | |||
252 | msgid "Couldn't retrieve updater class methods." | 252 | msgid "Couldn't retrieve updater class methods." |
253 | msgstr "Impossible de récupérer les méthodes de la classe Updater." | 253 | msgstr "Impossible de récupérer les méthodes de la classe Updater." |
254 | 254 | ||
255 | #: application/updater/Updater.php:526 index.php:1033 | 255 | #: application/updater/Updater.php:526 index.php:1034 |
256 | msgid "" | 256 | msgid "" |
257 | "You have enabled or changed thumbnails mode. <a href=\"?do=thumbs_update" | 257 | "You have enabled or changed thumbnails mode. <a href=\"?do=thumbs_update" |
258 | "\">Please synchronize them</a>." | 258 | "\">Please synchronize them</a>." |
@@ -337,8 +337,8 @@ msgid "You are not supposed to change a password on an Open Shaarli." | |||
337 | msgstr "" | 337 | msgstr "" |
338 | "Vous n'êtes pas censé modifier le mot de passe d'un Shaarli en mode ouvert." | 338 | "Vous n'êtes pas censé modifier le mot de passe d'un Shaarli en mode ouvert." |
339 | 339 | ||
340 | #: index.php:957 index.php:1007 index.php:1092 index.php:1122 index.php:1232 | 340 | #: index.php:957 index.php:1007 index.php:1094 index.php:1124 index.php:1234 |
341 | #: index.php:1279 | 341 | #: index.php:1281 |
342 | msgid "Wrong token." | 342 | msgid "Wrong token." |
343 | msgstr "Jeton invalide." | 343 | msgstr "Jeton invalide." |
344 | 344 | ||
@@ -356,64 +356,64 @@ msgstr "Votre mot de passe a été modifié" | |||
356 | msgid "Change password" | 356 | msgid "Change password" |
357 | msgstr "Modifier le mot de passe" | 357 | msgstr "Modifier le mot de passe" |
358 | 358 | ||
359 | #: index.php:1053 | 359 | #: index.php:1054 |
360 | msgid "Configuration was saved." | 360 | msgid "Configuration was saved." |
361 | msgstr "La configuration a été sauvegardée." | 361 | msgstr "La configuration a été sauvegardée." |
362 | 362 | ||
363 | #: index.php:1076 tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:24 | 363 | #: index.php:1078 tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:24 |
364 | msgid "Configure" | 364 | msgid "Configure" |
365 | msgstr "Configurer" | 365 | msgstr "Configurer" |
366 | 366 | ||
367 | #: index.php:1086 tmp/changetag.b91ef64efc3688266305ea9b42e5017e.rtpl.php:13 | 367 | #: index.php:1088 tmp/changetag.b91ef64efc3688266305ea9b42e5017e.rtpl.php:13 |
368 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:36 | 368 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:36 |
369 | msgid "Manage tags" | 369 | msgid "Manage tags" |
370 | msgstr "Gérer les tags" | 370 | msgstr "Gérer les tags" |
371 | 371 | ||
372 | #: index.php:1105 | 372 | #: index.php:1107 |
373 | #, php-format | 373 | #, php-format |
374 | msgid "The tag was removed from %d link." | 374 | msgid "The tag was removed from %d link." |
375 | msgid_plural "The tag was removed from %d links." | 375 | msgid_plural "The tag was removed from %d links." |
376 | msgstr[0] "Le tag a été supprimé de %d lien." | 376 | msgstr[0] "Le tag a été supprimé de %d lien." |
377 | msgstr[1] "Le tag a été supprimé de %d liens." | 377 | msgstr[1] "Le tag a été supprimé de %d liens." |
378 | 378 | ||
379 | #: index.php:1106 | 379 | #: index.php:1108 |
380 | #, php-format | 380 | #, php-format |
381 | msgid "The tag was renamed in %d link." | 381 | msgid "The tag was renamed in %d link." |
382 | msgid_plural "The tag was renamed in %d links." | 382 | msgid_plural "The tag was renamed in %d links." |
383 | msgstr[0] "Le tag a été renommé dans %d lien." | 383 | msgstr[0] "Le tag a été renommé dans %d lien." |
384 | msgstr[1] "Le tag a été renommé dans %d liens." | 384 | msgstr[1] "Le tag a été renommé dans %d liens." |
385 | 385 | ||
386 | #: index.php:1113 tmp/addlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:13 | 386 | #: index.php:1115 tmp/addlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:13 |
387 | msgid "Shaare a new link" | 387 | msgid "Shaare a new link" |
388 | msgstr "Partager un nouveau lien" | 388 | msgstr "Partager un nouveau lien" |
389 | 389 | ||
390 | #: index.php:1342 tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:169 | 390 | #: index.php:1344 tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:169 |
391 | msgid "Edit" | 391 | msgid "Edit" |
392 | msgstr "Modifier" | 392 | msgstr "Modifier" |
393 | 393 | ||
394 | #: index.php:1342 index.php:1413 | 394 | #: index.php:1344 index.php:1416 |
395 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:26 | 395 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:26 |
396 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:26 | 396 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:26 |
397 | msgid "Shaare" | 397 | msgid "Shaare" |
398 | msgstr "Shaare" | 398 | msgstr "Shaare" |
399 | 399 | ||
400 | #: index.php:1382 | 400 | #: index.php:1385 |
401 | msgid "Note: " | 401 | msgid "Note: " |
402 | msgstr "Note : " | 402 | msgstr "Note : " |
403 | 403 | ||
404 | #: index.php:1421 | 404 | #: index.php:1424 |
405 | msgid "Invalid link ID provided" | 405 | msgid "Invalid link ID provided" |
406 | msgstr "" | 406 | msgstr "" |
407 | 407 | ||
408 | #: index.php:1441 tmp/export.b91ef64efc3688266305ea9b42e5017e.rtpl.php:65 | 408 | #: index.php:1444 tmp/export.b91ef64efc3688266305ea9b42e5017e.rtpl.php:65 |
409 | msgid "Export" | 409 | msgid "Export" |
410 | msgstr "Exporter" | 410 | msgstr "Exporter" |
411 | 411 | ||
412 | #: index.php:1503 tmp/import.b91ef64efc3688266305ea9b42e5017e.rtpl.php:83 | 412 | #: index.php:1506 tmp/import.b91ef64efc3688266305ea9b42e5017e.rtpl.php:83 |
413 | msgid "Import" | 413 | msgid "Import" |
414 | msgstr "Importer" | 414 | msgstr "Importer" |
415 | 415 | ||
416 | #: index.php:1513 | 416 | #: index.php:1516 |
417 | #, php-format | 417 | #, php-format |
418 | msgid "" | 418 | msgid "" |
419 | "The file you are trying to upload is probably bigger than what this " | 419 | "The file you are trying to upload is probably bigger than what this " |
@@ -423,20 +423,20 @@ msgstr "" | |||
423 | "le serveur web peut accepter (%s). Merci de l'envoyer en parties plus " | 423 | "le serveur web peut accepter (%s). Merci de l'envoyer en parties plus " |
424 | "légères." | 424 | "légères." |
425 | 425 | ||
426 | #: index.php:1558 tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:26 | 426 | #: index.php:1561 tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:26 |
427 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:22 | 427 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:22 |
428 | msgid "Plugin administration" | 428 | msgid "Plugin administration" |
429 | msgstr "Administration des plugins" | 429 | msgstr "Administration des plugins" |
430 | 430 | ||
431 | #: index.php:1612 tmp/thumbnails.b91ef64efc3688266305ea9b42e5017e.rtpl.php:14 | 431 | #: index.php:1615 tmp/thumbnails.b91ef64efc3688266305ea9b42e5017e.rtpl.php:14 |
432 | msgid "Thumbnails update" | 432 | msgid "Thumbnails update" |
433 | msgstr "Mise à jour des miniatures" | 433 | msgstr "Mise à jour des miniatures" |
434 | 434 | ||
435 | #: index.php:1778 | 435 | #: index.php:1781 |
436 | msgid "Search: " | 436 | msgid "Search: " |
437 | msgstr "Recherche : " | 437 | msgstr "Recherche : " |
438 | 438 | ||
439 | #: index.php:1821 | 439 | #: index.php:1824 |
440 | #, php-format | 440 | #, php-format |
441 | msgid "" | 441 | msgid "" |
442 | "<pre>Sessions do not seem to work correctly on your server.<br>Make sure the " | 442 | "<pre>Sessions do not seem to work correctly on your server.<br>Make sure the " |
@@ -455,7 +455,7 @@ msgstr "" | |||
455 | "des cookies. Nous vous recommandons d'accéder à votre serveur depuis son " | 455 | "des cookies. Nous vous recommandons d'accéder à votre serveur depuis son " |
456 | "adresse IP ou un <em>Fully Qualified Domain Name</em>.<br>" | 456 | "adresse IP ou un <em>Fully Qualified Domain Name</em>.<br>" |
457 | 457 | ||
458 | #: index.php:1831 | 458 | #: index.php:1834 |
459 | msgid "Click to try again." | 459 | msgid "Click to try again." |
460 | msgstr "Cliquer ici pour réessayer." | 460 | msgstr "Cliquer ici pour réessayer." |
461 | 461 | ||
@@ -592,7 +592,7 @@ msgstr "Mauvaise réponse du hub %s" | |||
592 | msgid "Enable PubSubHubbub feed publishing." | 592 | msgid "Enable PubSubHubbub feed publishing." |
593 | msgstr "Active la publication de flux vers PubSubHubbub." | 593 | msgstr "Active la publication de flux vers PubSubHubbub." |
594 | 594 | ||
595 | #: plugins/qrcode/qrcode.php:73 plugins/wallabag/wallabag.php:68 | 595 | #: plugins/qrcode/qrcode.php:72 plugins/wallabag/wallabag.php:68 |
596 | msgid "For each link, add a QRCode icon." | 596 | msgid "For each link, add a QRCode icon." |
597 | msgstr "Pour chaque lien, ajouter une icône de QRCode." | 597 | msgstr "Pour chaque lien, ajouter une icône de QRCode." |
598 | 598 | ||
@@ -679,6 +679,34 @@ msgstr "Vous pouvez aussi modifier les tags dans la" | |||
679 | msgid "tag list" | 679 | msgid "tag list" |
680 | msgstr "liste des tags" | 680 | msgstr "liste des tags" |
681 | 681 | ||
682 | #: tmp/configure.90100d2eaf5d3705e14b9b4f78ecddc9.rtpl.php:143 | ||
683 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:312 | ||
684 | #: tmp/export.b91ef64efc3688266305ea9b42e5017e.rtpl.php:31 | ||
685 | msgid "All" | ||
686 | msgstr "Tous" | ||
687 | |||
688 | #: tmp/configure.90100d2eaf5d3705e14b9b4f78ecddc9.rtpl.php:147 | ||
689 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:316 | ||
690 | msgid "Only common media hosts" | ||
691 | msgstr "Seulement les hébergeurs de média connus" | ||
692 | |||
693 | #: tmp/configure.90100d2eaf5d3705e14b9b4f78ecddc9.rtpl.php:151 | ||
694 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:320 | ||
695 | msgid "None" | ||
696 | msgstr "Aucune" | ||
697 | |||
698 | #: tmp/configure.90100d2eaf5d3705e14b9b4f78ecddc9.rtpl.php:158 | ||
699 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:297 | ||
700 | msgid "You need to enable the extension <code>php-gd</code> to use thumbnails." | ||
701 | msgstr "" | ||
702 | "Vous devez activer l'extension <code>php-gd</code> pour utiliser les " | ||
703 | "miniatures." | ||
704 | |||
705 | #: tmp/configure.90100d2eaf5d3705e14b9b4f78ecddc9.rtpl.php:162 | ||
706 | #| msgid "Enable thumbnails" | ||
707 | msgid "Synchonize thumbnails" | ||
708 | msgstr "" | ||
709 | |||
682 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:29 | 710 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:29 |
683 | msgid "title" | 711 | msgid "title" |
684 | msgstr "titre" | 712 | msgstr "titre" |
@@ -762,50 +790,41 @@ msgid "Notify me when a new release is ready" | |||
762 | msgstr "Me notifier lorsqu'une nouvelle version est disponible" | 790 | msgstr "Me notifier lorsqu'une nouvelle version est disponible" |
763 | 791 | ||
764 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:247 | 792 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:247 |
793 | msgid "Automatically retrieve description for new bookmarks" | ||
794 | msgstr "Récupérer automatiquement la description" | ||
795 | |||
796 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:248 | ||
797 | msgid "Shaarli will try to retrieve the description from meta HTML headers" | ||
798 | msgstr "" | ||
799 | "Shaarli essaiera de récupérer la description depuis les balises HTML meta " | ||
800 | "dans les entêtes" | ||
801 | |||
802 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:263 | ||
765 | #: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:169 | 803 | #: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:169 |
766 | msgid "Enable REST API" | 804 | msgid "Enable REST API" |
767 | msgstr "Activer l'API REST" | 805 | msgstr "Activer l'API REST" |
768 | 806 | ||
769 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:248 | 807 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:264 |
770 | #: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:170 | 808 | #: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:170 |
771 | msgid "Allow third party software to use Shaarli such as mobile application" | 809 | msgid "Allow third party software to use Shaarli such as mobile application" |
772 | msgstr "" | 810 | msgstr "" |
773 | "Permet aux applications tierces d'utiliser Shaarli, par exemple les " | 811 | "Permet aux applications tierces d'utiliser Shaarli, par exemple les " |
774 | "applications mobiles" | 812 | "applications mobiles" |
775 | 813 | ||
776 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:263 | 814 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:279 |
777 | msgid "API secret" | 815 | msgid "API secret" |
778 | msgstr "Clé d'API secrète" | 816 | msgstr "Clé d'API secrète" |
779 | 817 | ||
780 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:277 | 818 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:293 |
781 | msgid "Enable thumbnails" | 819 | msgid "Enable thumbnails" |
782 | msgstr "Activer les miniatures" | 820 | msgstr "Activer les miniatures" |
783 | 821 | ||
784 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:281 | 822 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:301 |
785 | msgid "You need to enable the extension <code>php-gd</code> to use thumbnails." | ||
786 | msgstr "" | ||
787 | "Vous devez activer l'extension <code>php-gd</code> pour utiliser les " | ||
788 | "miniatures." | ||
789 | |||
790 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:285 | ||
791 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:56 | 823 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:56 |
792 | msgid "Synchronize thumbnails" | 824 | msgid "Synchronize thumbnails" |
793 | msgstr "Synchroniser les miniatures" | 825 | msgstr "Synchroniser les miniatures" |
794 | 826 | ||
795 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:296 | 827 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:328 |
796 | #: tmp/export.b91ef64efc3688266305ea9b42e5017e.rtpl.php:31 | ||
797 | msgid "All" | ||
798 | msgstr "Tous" | ||
799 | |||
800 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:300 | ||
801 | msgid "Only common media hosts" | ||
802 | msgstr "Seulement les hébergeurs de média connus" | ||
803 | |||
804 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:304 | ||
805 | msgid "None" | ||
806 | msgstr "Aucune" | ||
807 | |||
808 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:312 | ||
809 | #: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:72 | 828 | #: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:72 |
810 | #: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:139 | 829 | #: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:139 |
811 | #: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:199 | 830 | #: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:199 |
@@ -1149,17 +1168,13 @@ msgstr "Déconnexion" | |||
1149 | 1168 | ||
1150 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:150 | 1169 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:150 |
1151 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:150 | 1170 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:150 |
1152 | #, fuzzy | ||
1153 | #| msgid "Public" | ||
1154 | msgid "Set public" | 1171 | msgid "Set public" |
1155 | msgstr "Publics" | 1172 | msgstr "Rendre public" |
1156 | 1173 | ||
1157 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:155 | 1174 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:155 |
1158 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:155 | 1175 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:155 |
1159 | #, fuzzy | ||
1160 | #| msgid "Private" | ||
1161 | msgid "Set private" | 1176 | msgid "Set private" |
1162 | msgstr "Privé" | 1177 | msgstr "Rendre privé" |
1163 | 1178 | ||
1164 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:187 | 1179 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:187 |
1165 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:187 | 1180 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:187 |
@@ -1409,11 +1424,6 @@ msgstr "" | |||
1409 | "Glisser ce lien dans votre barre de favoris ou cliquer droit dessus et « " | 1424 | "Glisser ce lien dans votre barre de favoris ou cliquer droit dessus et « " |
1410 | "Ajouter aux favoris »" | 1425 | "Ajouter aux favoris »" |
1411 | 1426 | ||
1412 | #, fuzzy | ||
1413 | #~| msgid "Enable thumbnails" | ||
1414 | #~ msgid "Synchonize thumbnails" | ||
1415 | #~ msgstr "Activer les miniatures" | ||
1416 | |||
1417 | #~ msgid "" | 1427 | #~ msgid "" |
1418 | #~ "You need to browse your Shaarli over <strong>HTTPS</strong> to use this " | 1428 | #~ "You need to browse your Shaarli over <strong>HTTPS</strong> to use this " |
1419 | #~ "functionality." | 1429 | #~ "functionality." |
@@ -1015,6 +1015,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager, | |||
1015 | $conf->set('general.timezone', $tz); | 1015 | $conf->set('general.timezone', $tz); |
1016 | $conf->set('general.title', escape($_POST['title'])); | 1016 | $conf->set('general.title', escape($_POST['title'])); |
1017 | $conf->set('general.header_link', escape($_POST['titleLink'])); | 1017 | $conf->set('general.header_link', escape($_POST['titleLink'])); |
1018 | $conf->set('general.retrieve_description', !empty($_POST['retrieveDescription'])); | ||
1018 | $conf->set('resource.theme', escape($_POST['theme'])); | 1019 | $conf->set('resource.theme', escape($_POST['theme'])); |
1019 | $conf->set('security.session_protection_disabled', !empty($_POST['disablesessionprotection'])); | 1020 | $conf->set('security.session_protection_disabled', !empty($_POST['disablesessionprotection'])); |
1020 | $conf->set('privacy.default_private_links', !empty($_POST['privateLinkByDefault'])); | 1021 | $conf->set('privacy.default_private_links', !empty($_POST['privateLinkByDefault'])); |
@@ -1063,6 +1064,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager, | |||
1063 | ); | 1064 | ); |
1064 | $PAGE->assign('continents', $continents); | 1065 | $PAGE->assign('continents', $continents); |
1065 | $PAGE->assign('cities', $cities); | 1066 | $PAGE->assign('cities', $cities); |
1067 | $PAGE->assign('retrieve_description', $conf->get('general.retrieve_description')); | ||
1066 | $PAGE->assign('private_links_default', $conf->get('privacy.default_private_links', false)); | 1068 | $PAGE->assign('private_links_default', $conf->get('privacy.default_private_links', false)); |
1067 | $PAGE->assign('session_protection_disabled', $conf->get('security.session_protection_disabled', false)); | 1069 | $PAGE->assign('session_protection_disabled', $conf->get('security.session_protection_disabled', false)); |
1068 | $PAGE->assign('enable_rss_permalinks', $conf->get('feed.rss_permalinks', false)); | 1070 | $PAGE->assign('enable_rss_permalinks', $conf->get('feed.rss_permalinks', false)); |
@@ -1364,13 +1366,14 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager, | |||
1364 | // If this is an HTTP(S) link, we try go get the page to extract | 1366 | // If this is an HTTP(S) link, we try go get the page to extract |
1365 | // the title (otherwise we will to straight to the edit form.) | 1367 | // the title (otherwise we will to straight to the edit form.) |
1366 | if (empty($title) && strpos(get_url_scheme($url), 'http') !== false) { | 1368 | if (empty($title) && strpos(get_url_scheme($url), 'http') !== false) { |
1369 | $retrieveDescription = $conf->get('general.retrieve_description'); | ||
1367 | // Short timeout to keep the application responsive | 1370 | // Short timeout to keep the application responsive |
1368 | // The callback will fill $charset and $title with data from the downloaded page. | 1371 | // The callback will fill $charset and $title with data from the downloaded page. |
1369 | get_http_response( | 1372 | get_http_response( |
1370 | $url, | 1373 | $url, |
1371 | $conf->get('general.download_timeout', 30), | 1374 | $conf->get('general.download_timeout', 30), |
1372 | $conf->get('general.download_max_size', 4194304), | 1375 | $conf->get('general.download_max_size', 4194304), |
1373 | get_curl_download_callback($charset, $title) | 1376 | get_curl_download_callback($charset, $title, $description, $tags, $retrieveDescription) |
1374 | ); | 1377 | ); |
1375 | if (! empty($title) && strtolower($charset) != 'utf-8') { | 1378 | if (! empty($title) && strtolower($charset) != 'utf-8') { |
1376 | $title = mb_convert_encoding($title, 'utf-8', $charset); | 1379 | $title = mb_convert_encoding($title, 'utf-8', $charset); |
diff --git a/tests/bookmark/LinkUtilsTest.php b/tests/bookmark/LinkUtilsTest.php index 25fb3043..78cb8f2a 100644 --- a/tests/bookmark/LinkUtilsTest.php +++ b/tests/bookmark/LinkUtilsTest.php | |||
@@ -2,14 +2,16 @@ | |||
2 | 2 | ||
3 | namespace Shaarli\Bookmark; | 3 | namespace Shaarli\Bookmark; |
4 | 4 | ||
5 | use PHPUnit\Framework\TestCase; | ||
5 | use ReferenceLinkDB; | 6 | use ReferenceLinkDB; |
7 | use Shaarli\Config\ConfigManager; | ||
6 | 8 | ||
7 | require_once 'tests/utils/CurlUtils.php'; | 9 | require_once 'tests/utils/CurlUtils.php'; |
8 | 10 | ||
9 | /** | 11 | /** |
10 | * Class LinkUtilsTest. | 12 | * Class LinkUtilsTest. |
11 | */ | 13 | */ |
12 | class LinkUtilsTest extends \PHPUnit\Framework\TestCase | 14 | class LinkUtilsTest extends TestCase |
13 | { | 15 | { |
14 | /** | 16 | /** |
15 | * Test html_extract_title() when the title is found. | 17 | * Test html_extract_title() when the title is found. |
@@ -76,11 +78,56 @@ class LinkUtilsTest extends \PHPUnit\Framework\TestCase | |||
76 | } | 78 | } |
77 | 79 | ||
78 | /** | 80 | /** |
81 | * Test html_extract_tag() when the tag <meta name= is found. | ||
82 | */ | ||
83 | public function testHtmlExtractExistentNameTag() | ||
84 | { | ||
85 | $description = 'Bob and Alice share cookies.'; | ||
86 | $html = '<html><meta>stuff2</meta><meta name="description" content="' . $description . '"/></html>'; | ||
87 | $this->assertEquals($description, html_extract_tag('description', $html)); | ||
88 | } | ||
89 | |||
90 | /** | ||
91 | * Test html_extract_tag() when the tag <meta name= is not found. | ||
92 | */ | ||
93 | public function testHtmlExtractNonExistentNameTag() | ||
94 | { | ||
95 | $html = '<html><meta>stuff2</meta><meta name="image" content="img"/></html>'; | ||
96 | $this->assertFalse(html_extract_tag('description', $html)); | ||
97 | } | ||
98 | |||
99 | /** | ||
100 | * Test html_extract_tag() when the tag <meta property="og: is found. | ||
101 | */ | ||
102 | public function testHtmlExtractExistentOgTag() | ||
103 | { | ||
104 | $description = 'Bob and Alice share cookies.'; | ||
105 | $html = '<html><meta>stuff2</meta><meta property="og:description" content="' . $description . '"/></html>'; | ||
106 | $this->assertEquals($description, html_extract_tag('description', $html)); | ||
107 | } | ||
108 | |||
109 | /** | ||
110 | * Test html_extract_tag() when the tag <meta property="og: is not found. | ||
111 | */ | ||
112 | public function testHtmlExtractNonExistentOgTag() | ||
113 | { | ||
114 | $html = '<html><meta>stuff2</meta><meta name="image" content="img"/></html>'; | ||
115 | $this->assertFalse(html_extract_tag('description', $html)); | ||
116 | } | ||
117 | |||
118 | /** | ||
79 | * Test the download callback with valid value | 119 | * Test the download callback with valid value |
80 | */ | 120 | */ |
81 | public function testCurlDownloadCallbackOk() | 121 | public function testCurlDownloadCallbackOk() |
82 | { | 122 | { |
83 | $callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_ok'); | 123 | $callback = get_curl_download_callback( |
124 | $charset, | ||
125 | $title, | ||
126 | $desc, | ||
127 | $keywords, | ||
128 | false, | ||
129 | 'ut_curl_getinfo_ok' | ||
130 | ); | ||
84 | $data = [ | 131 | $data = [ |
85 | 'HTTP/1.1 200 OK', | 132 | 'HTTP/1.1 200 OK', |
86 | 'Server: GitHub.com', | 133 | 'Server: GitHub.com', |
@@ -90,7 +137,9 @@ class LinkUtilsTest extends \PHPUnit\Framework\TestCase | |||
90 | 'end' => 'th=device-width">' | 137 | 'end' => 'th=device-width">' |
91 | . '<title>Refactoring · GitHub</title>' | 138 | . '<title>Refactoring · GitHub</title>' |
92 | . '<link rel="search" type="application/opensea', | 139 | . '<link rel="search" type="application/opensea', |
93 | '<title>ignored</title>', | 140 | '<title>ignored</title>' |
141 | . '<meta name="description" content="desc" />' | ||
142 | . '<meta name="keywords" content="key1,key2" />', | ||
94 | ]; | 143 | ]; |
95 | foreach ($data as $key => $line) { | 144 | foreach ($data as $key => $line) { |
96 | $ignore = null; | 145 | $ignore = null; |
@@ -102,6 +151,8 @@ class LinkUtilsTest extends \PHPUnit\Framework\TestCase | |||
102 | } | 151 | } |
103 | $this->assertEquals('utf-8', $charset); | 152 | $this->assertEquals('utf-8', $charset); |
104 | $this->assertEquals('Refactoring · GitHub', $title); | 153 | $this->assertEquals('Refactoring · GitHub', $title); |
154 | $this->assertEmpty($desc); | ||
155 | $this->assertEmpty($keywords); | ||
105 | } | 156 | } |
106 | 157 | ||
107 | /** | 158 | /** |
@@ -109,13 +160,22 @@ class LinkUtilsTest extends \PHPUnit\Framework\TestCase | |||
109 | */ | 160 | */ |
110 | public function testCurlDownloadCallbackOkNoCharset() | 161 | public function testCurlDownloadCallbackOkNoCharset() |
111 | { | 162 | { |
112 | $callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_no_charset'); | 163 | $callback = get_curl_download_callback( |
164 | $charset, | ||
165 | $title, | ||
166 | $desc, | ||
167 | $keywords, | ||
168 | false, | ||
169 | 'ut_curl_getinfo_no_charset' | ||
170 | ); | ||
113 | $data = [ | 171 | $data = [ |
114 | 'HTTP/1.1 200 OK', | 172 | 'HTTP/1.1 200 OK', |
115 | 'end' => 'th=device-width">' | 173 | 'end' => 'th=device-width">' |
116 | . '<title>Refactoring · GitHub</title>' | 174 | . '<title>Refactoring · GitHub</title>' |
117 | . '<link rel="search" type="application/opensea', | 175 | . '<link rel="search" type="application/opensea', |
118 | '<title>ignored</title>', | 176 | '<title>ignored</title>' |
177 | . '<meta name="description" content="desc" />' | ||
178 | . '<meta name="keywords" content="key1,key2" />', | ||
119 | ]; | 179 | ]; |
120 | foreach ($data as $key => $line) { | 180 | foreach ($data as $key => $line) { |
121 | $ignore = null; | 181 | $ignore = null; |
@@ -123,6 +183,8 @@ class LinkUtilsTest extends \PHPUnit\Framework\TestCase | |||
123 | } | 183 | } |
124 | $this->assertEmpty($charset); | 184 | $this->assertEmpty($charset); |
125 | $this->assertEquals('Refactoring · GitHub', $title); | 185 | $this->assertEquals('Refactoring · GitHub', $title); |
186 | $this->assertEmpty($desc); | ||
187 | $this->assertEmpty($keywords); | ||
126 | } | 188 | } |
127 | 189 | ||
128 | /** | 190 | /** |
@@ -130,14 +192,23 @@ class LinkUtilsTest extends \PHPUnit\Framework\TestCase | |||
130 | */ | 192 | */ |
131 | public function testCurlDownloadCallbackOkHtmlCharset() | 193 | public function testCurlDownloadCallbackOkHtmlCharset() |
132 | { | 194 | { |
133 | $callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_no_charset'); | 195 | $callback = get_curl_download_callback( |
196 | $charset, | ||
197 | $title, | ||
198 | $desc, | ||
199 | $keywords, | ||
200 | false, | ||
201 | 'ut_curl_getinfo_no_charset' | ||
202 | ); | ||
134 | $data = [ | 203 | $data = [ |
135 | 'HTTP/1.1 200 OK', | 204 | 'HTTP/1.1 200 OK', |
136 | '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />', | 205 | '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />', |
137 | 'end' => 'th=device-width">' | 206 | 'end' => 'th=device-width">' |
138 | . '<title>Refactoring · GitHub</title>' | 207 | . '<title>Refactoring · GitHub</title>' |
139 | . '<link rel="search" type="application/opensea', | 208 | . '<link rel="search" type="application/opensea', |
140 | '<title>ignored</title>', | 209 | '<title>ignored</title>' |
210 | . '<meta name="description" content="desc" />' | ||
211 | . '<meta name="keywords" content="key1,key2" />', | ||
141 | ]; | 212 | ]; |
142 | foreach ($data as $key => $line) { | 213 | foreach ($data as $key => $line) { |
143 | $ignore = null; | 214 | $ignore = null; |
@@ -149,6 +220,8 @@ class LinkUtilsTest extends \PHPUnit\Framework\TestCase | |||
149 | } | 220 | } |
150 | $this->assertEquals('utf-8', $charset); | 221 | $this->assertEquals('utf-8', $charset); |
151 | $this->assertEquals('Refactoring · GitHub', $title); | 222 | $this->assertEquals('Refactoring · GitHub', $title); |
223 | $this->assertEmpty($desc); | ||
224 | $this->assertEmpty($keywords); | ||
152 | } | 225 | } |
153 | 226 | ||
154 | /** | 227 | /** |
@@ -156,7 +229,14 @@ class LinkUtilsTest extends \PHPUnit\Framework\TestCase | |||
156 | */ | 229 | */ |
157 | public function testCurlDownloadCallbackOkNoTitle() | 230 | public function testCurlDownloadCallbackOkNoTitle() |
158 | { | 231 | { |
159 | $callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_ok'); | 232 | $callback = get_curl_download_callback( |
233 | $charset, | ||
234 | $title, | ||
235 | $desc, | ||
236 | $keywords, | ||
237 | false, | ||
238 | 'ut_curl_getinfo_ok' | ||
239 | ); | ||
160 | $data = [ | 240 | $data = [ |
161 | 'HTTP/1.1 200 OK', | 241 | 'HTTP/1.1 200 OK', |
162 | 'end' => 'th=device-width">Refactoring · GitHub<link rel="search" type="application/opensea', | 242 | 'end' => 'th=device-width">Refactoring · GitHub<link rel="search" type="application/opensea', |
@@ -168,6 +248,8 @@ class LinkUtilsTest extends \PHPUnit\Framework\TestCase | |||
168 | } | 248 | } |
169 | $this->assertEquals('utf-8', $charset); | 249 | $this->assertEquals('utf-8', $charset); |
170 | $this->assertEmpty($title); | 250 | $this->assertEmpty($title); |
251 | $this->assertEmpty($desc); | ||
252 | $this->assertEmpty($keywords); | ||
171 | } | 253 | } |
172 | 254 | ||
173 | /** | 255 | /** |
@@ -175,7 +257,14 @@ class LinkUtilsTest extends \PHPUnit\Framework\TestCase | |||
175 | */ | 257 | */ |
176 | public function testCurlDownloadCallbackInvalidContentType() | 258 | public function testCurlDownloadCallbackInvalidContentType() |
177 | { | 259 | { |
178 | $callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_ct_ko'); | 260 | $callback = get_curl_download_callback( |
261 | $charset, | ||
262 | $title, | ||
263 | $desc, | ||
264 | $keywords, | ||
265 | false, | ||
266 | 'ut_curl_getinfo_ct_ko' | ||
267 | ); | ||
179 | $ignore = null; | 268 | $ignore = null; |
180 | $this->assertFalse($callback($ignore, '')); | 269 | $this->assertFalse($callback($ignore, '')); |
181 | $this->assertEmpty($charset); | 270 | $this->assertEmpty($charset); |
@@ -187,7 +276,14 @@ class LinkUtilsTest extends \PHPUnit\Framework\TestCase | |||
187 | */ | 276 | */ |
188 | public function testCurlDownloadCallbackInvalidResponseCode() | 277 | public function testCurlDownloadCallbackInvalidResponseCode() |
189 | { | 278 | { |
190 | $callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_rc_ko'); | 279 | $callback = $callback = get_curl_download_callback( |
280 | $charset, | ||
281 | $title, | ||
282 | $desc, | ||
283 | $keywords, | ||
284 | false, | ||
285 | 'ut_curl_getinfo_rc_ko' | ||
286 | ); | ||
191 | $ignore = null; | 287 | $ignore = null; |
192 | $this->assertFalse($callback($ignore, '')); | 288 | $this->assertFalse($callback($ignore, '')); |
193 | $this->assertEmpty($charset); | 289 | $this->assertEmpty($charset); |
@@ -199,7 +295,14 @@ class LinkUtilsTest extends \PHPUnit\Framework\TestCase | |||
199 | */ | 295 | */ |
200 | public function testCurlDownloadCallbackInvalidContentTypeAndResponseCode() | 296 | public function testCurlDownloadCallbackInvalidContentTypeAndResponseCode() |
201 | { | 297 | { |
202 | $callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_rs_ct_ko'); | 298 | $callback = $callback = get_curl_download_callback( |
299 | $charset, | ||
300 | $title, | ||
301 | $desc, | ||
302 | $keywords, | ||
303 | false, | ||
304 | 'ut_curl_getinfo_rs_ct_ko' | ||
305 | ); | ||
203 | $ignore = null; | 306 | $ignore = null; |
204 | $this->assertFalse($callback($ignore, '')); | 307 | $this->assertFalse($callback($ignore, '')); |
205 | $this->assertEmpty($charset); | 308 | $this->assertEmpty($charset); |
@@ -207,6 +310,85 @@ class LinkUtilsTest extends \PHPUnit\Framework\TestCase | |||
207 | } | 310 | } |
208 | 311 | ||
209 | /** | 312 | /** |
313 | * Test the download callback with valid value, and retrieve_description option enabled. | ||
314 | */ | ||
315 | public function testCurlDownloadCallbackOkWithDesc() | ||
316 | { | ||
317 | $callback = get_curl_download_callback( | ||
318 | $charset, | ||
319 | $title, | ||
320 | $desc, | ||
321 | $keywords, | ||
322 | true, | ||
323 | 'ut_curl_getinfo_ok' | ||
324 | ); | ||
325 | $data = [ | ||
326 | 'HTTP/1.1 200 OK', | ||
327 | 'Server: GitHub.com', | ||
328 | 'Date: Sat, 28 Oct 2017 12:01:33 GMT', | ||
329 | 'Content-Type: text/html; charset=utf-8', | ||
330 | 'Status: 200 OK', | ||
331 | 'th=device-width">' | ||
332 | . '<title>Refactoring · GitHub</title>' | ||
333 | . '<link rel="search" type="application/opensea', | ||
334 | 'end' => '<title>ignored</title>' | ||
335 | . '<meta name="description" content="link desc" />' | ||
336 | . '<meta name="keywords" content="key1,key2" />', | ||
337 | ]; | ||
338 | foreach ($data as $key => $line) { | ||
339 | $ignore = null; | ||
340 | $expected = $key !== 'end' ? strlen($line) : false; | ||
341 | $this->assertEquals($expected, $callback($ignore, $line)); | ||
342 | if ($expected === false) { | ||
343 | break; | ||
344 | } | ||
345 | } | ||
346 | $this->assertEquals('utf-8', $charset); | ||
347 | $this->assertEquals('Refactoring · GitHub', $title); | ||
348 | $this->assertEquals('link desc', $desc); | ||
349 | $this->assertEquals('key1 key2', $keywords); | ||
350 | } | ||
351 | |||
352 | /** | ||
353 | * Test the download callback with valid value, and retrieve_description option enabled, | ||
354 | * but no desc or keyword defined in the page. | ||
355 | */ | ||
356 | public function testCurlDownloadCallbackOkWithDescNotFound() | ||
357 | { | ||
358 | $callback = get_curl_download_callback( | ||
359 | $charset, | ||
360 | $title, | ||
361 | $desc, | ||
362 | $keywords, | ||
363 | true, | ||
364 | 'ut_curl_getinfo_ok' | ||
365 | ); | ||
366 | $data = [ | ||
367 | 'HTTP/1.1 200 OK', | ||
368 | 'Server: GitHub.com', | ||
369 | 'Date: Sat, 28 Oct 2017 12:01:33 GMT', | ||
370 | 'Content-Type: text/html; charset=utf-8', | ||
371 | 'Status: 200 OK', | ||
372 | 'th=device-width">' | ||
373 | . '<title>Refactoring · GitHub</title>' | ||
374 | . '<link rel="search" type="application/opensea', | ||
375 | 'end' => '<title>ignored</title>', | ||
376 | ]; | ||
377 | foreach ($data as $key => $line) { | ||
378 | $ignore = null; | ||
379 | $expected = $key !== 'end' ? strlen($line) : false; | ||
380 | $this->assertEquals($expected, $callback($ignore, $line)); | ||
381 | if ($expected === false) { | ||
382 | break; | ||
383 | } | ||
384 | } | ||
385 | $this->assertEquals('utf-8', $charset); | ||
386 | $this->assertEquals('Refactoring · GitHub', $title); | ||
387 | $this->assertEmpty($desc); | ||
388 | $this->assertEmpty($keywords); | ||
389 | } | ||
390 | |||
391 | /** | ||
210 | * Test count_private. | 392 | * Test count_private. |
211 | */ | 393 | */ |
212 | public function testCountPrivateLinks() | 394 | public function testCountPrivateLinks() |
diff --git a/tpl/default/configure.html b/tpl/default/configure.html index 7a87c05d..83033624 100644 --- a/tpl/default/configure.html +++ b/tpl/default/configure.html | |||
@@ -215,6 +215,22 @@ | |||
215 | <div class="pure-g"> | 215 | <div class="pure-g"> |
216 | <div class="pure-u-lg-{$ratioLabel} pure-u-{$ratioLabelMobile}"> | 216 | <div class="pure-u-lg-{$ratioLabel} pure-u-{$ratioLabelMobile}"> |
217 | <div class="form-label"> | 217 | <div class="form-label"> |
218 | <label for="retrieveDescription"> | ||
219 | <span class="label-name">{'Automatically retrieve description for new bookmarks'|t}</span><br> | ||
220 | <span class="label-desc">{'Shaarli will try to retrieve the description from meta HTML headers'|t}</span> | ||
221 | </label> | ||
222 | </div> | ||
223 | </div> | ||
224 | <div class="pure-u-lg-{$ratioInput} pure-u-{$ratioInputMobile}"> | ||
225 | <div class="form-input"> | ||
226 | <input type="checkbox" name="retrieveDescription" id="retrieveDescription" | ||
227 | {if="$retrieve_description"}checked{/if}/> | ||
228 | </div> | ||
229 | </div> | ||
230 | </div> | ||
231 | <div class="pure-g"> | ||
232 | <div class="pure-u-lg-{$ratioLabel} pure-u-{$ratioLabelMobile}"> | ||
233 | <div class="form-label"> | ||
218 | <label for="enableApi"> | 234 | <label for="enableApi"> |
219 | <span class="label-name">{'Enable REST API'|t}</span><br> | 235 | <span class="label-name">{'Enable REST API'|t}</span><br> |
220 | <span class="label-desc">{'Allow third party software to use Shaarli such as mobile application'|t}</span> | 236 | <span class="label-desc">{'Allow third party software to use Shaarli such as mobile application'|t}</span> |
diff --git a/tpl/vintage/configure.html b/tpl/vintage/configure.html index f1892fa1..160286a5 100644 --- a/tpl/vintage/configure.html +++ b/tpl/vintage/configure.html | |||
@@ -107,6 +107,14 @@ | |||
107 | </td> | 107 | </td> |
108 | </tr> | 108 | </tr> |
109 | <tr> | 109 | <tr> |
110 | <td valign="top"><b>Automatically retrieve description for new bookmarks:</b></td> | ||
111 | <td> | ||
112 | <input type="checkbox" name="retrieveDescription" id="retrieveDescription" | ||
113 | {if="$retrieve_description"}checked{/if}/> | ||
114 | <label for="retrieveDescription"> Shaarli will try to retrieve the description from meta HTML headers</label> | ||
115 | </td> | ||
116 | </tr> | ||
117 | <tr> | ||
110 | <td valign="top"><b>Enable REST API</b></td> | 118 | <td valign="top"><b>Enable REST API</b></td> |
111 | <td> | 119 | <td> |
112 | <input type="checkbox" name="enableApi" id="enableApi" | 120 | <input type="checkbox" name="enableApi" id="enableApi" |