Merge pull request #687 from ArthurHoaro/web-thumb
Use web-thumbnailer to retrieve thumbnails
This commit is contained in:
commit
ad5f47adba
34 changed files with 1495 additions and 769 deletions
|
@ -1,6 +1,7 @@
|
|||
<?php
|
||||
|
||||
use Shaarli\Config\ConfigManager;
|
||||
use Shaarli\Thumbnailer;
|
||||
|
||||
/**
|
||||
* This class is in charge of building the final page.
|
||||
|
@ -21,11 +22,21 @@ class PageBuilder
|
|||
*/
|
||||
protected $conf;
|
||||
|
||||
/**
|
||||
* @var array $_SESSION
|
||||
*/
|
||||
protected $session;
|
||||
|
||||
/**
|
||||
* @var LinkDB $linkDB instance.
|
||||
*/
|
||||
protected $linkDB;
|
||||
|
||||
/**
|
||||
* @var null|string XSRF token
|
||||
*/
|
||||
protected $token;
|
||||
|
||||
/** @var bool $isLoggedIn Whether the user is logged in **/
|
||||
protected $isLoggedIn = false;
|
||||
|
||||
|
@ -34,13 +45,16 @@ class PageBuilder
|
|||
* $tpl is initialized at false for lazy loading.
|
||||
*
|
||||
* @param ConfigManager $conf Configuration Manager instance (reference).
|
||||
* @param array $session $_SESSION array
|
||||
* @param LinkDB $linkDB instance.
|
||||
* @param string $token Session token
|
||||
* @param bool $isLoggedIn
|
||||
*/
|
||||
public function __construct(&$conf, $linkDB = null, $token = null, $isLoggedIn = false)
|
||||
public function __construct(&$conf, $session, $linkDB = null, $token = null, $isLoggedIn = false)
|
||||
{
|
||||
$this->tpl = false;
|
||||
$this->conf = $conf;
|
||||
$this->session = $session;
|
||||
$this->linkDB = $linkDB;
|
||||
$this->token = $token;
|
||||
$this->isLoggedIn = $isLoggedIn;
|
||||
|
@ -105,6 +119,19 @@ private function initialize()
|
|||
if ($this->linkDB !== null) {
|
||||
$this->tpl->assign('tags', $this->linkDB->linksCountPerTag());
|
||||
}
|
||||
|
||||
$this->tpl->assign(
|
||||
'thumbnails_enabled',
|
||||
$this->conf->get('thumbnails.mode', Thumbnailer::MODE_NONE) !== Thumbnailer::MODE_NONE
|
||||
);
|
||||
$this->tpl->assign('thumbnails_width', $this->conf->get('thumbnails.width'));
|
||||
$this->tpl->assign('thumbnails_height', $this->conf->get('thumbnails.height'));
|
||||
|
||||
if (! empty($_SESSION['warnings'])) {
|
||||
$this->tpl->assign('global_warnings', $_SESSION['warnings']);
|
||||
unset($_SESSION['warnings']);
|
||||
}
|
||||
|
||||
// To be removed with a proper theme configuration.
|
||||
$this->tpl->assign('conf', $this->conf);
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
*/
|
||||
class Router
|
||||
{
|
||||
public static $AJAX_THUMB_UPDATE = 'ajax_thumb_update';
|
||||
|
||||
public static $PAGE_LOGIN = 'login';
|
||||
|
||||
public static $PAGE_PICWALL = 'picwall';
|
||||
|
@ -47,6 +49,8 @@ class Router
|
|||
|
||||
public static $PAGE_SAVE_PLUGINSADMIN = 'save_pluginadmin';
|
||||
|
||||
public static $PAGE_THUMBS_UPDATE = 'thumbs_update';
|
||||
|
||||
public static $GET_TOKEN = 'token';
|
||||
|
||||
/**
|
||||
|
@ -101,6 +105,14 @@ public static function findPage($query, $get, $loggedIn)
|
|||
return self::$PAGE_FEED_RSS;
|
||||
}
|
||||
|
||||
if (startsWith($query, 'do='. self::$PAGE_THUMBS_UPDATE)) {
|
||||
return self::$PAGE_THUMBS_UPDATE;
|
||||
}
|
||||
|
||||
if (startsWith($query, 'do='. self::$AJAX_THUMB_UPDATE)) {
|
||||
return self::$AJAX_THUMB_UPDATE;
|
||||
}
|
||||
|
||||
// At this point, only loggedin pages.
|
||||
if (!$loggedIn) {
|
||||
return self::$PAGE_LINKLIST;
|
||||
|
|
127
application/Thumbnailer.php
Normal file
127
application/Thumbnailer.php
Normal file
|
@ -0,0 +1,127 @@
|
|||
<?php
|
||||
|
||||
namespace Shaarli;
|
||||
|
||||
use Shaarli\Config\ConfigManager;
|
||||
use WebThumbnailer\Exception\WebThumbnailerException;
|
||||
use WebThumbnailer\WebThumbnailer;
|
||||
use WebThumbnailer\Application\ConfigManager as WTConfigManager;
|
||||
|
||||
/**
|
||||
* Class Thumbnailer
|
||||
*
|
||||
* Utility class used to retrieve thumbnails using web-thumbnailer dependency.
|
||||
*/
|
||||
class Thumbnailer
|
||||
{
|
||||
const COMMON_MEDIA_DOMAINS = [
|
||||
'imgur.com',
|
||||
'flickr.com',
|
||||
'youtube.com',
|
||||
'wikimedia.org',
|
||||
'redd.it',
|
||||
'gfycat.com',
|
||||
'media.giphy.com',
|
||||
'twitter.com',
|
||||
'twimg.com',
|
||||
'instagram.com',
|
||||
'pinterest.com',
|
||||
'pinterest.fr',
|
||||
'tumblr.com',
|
||||
'deviantart.com',
|
||||
];
|
||||
|
||||
const MODE_ALL = 'all';
|
||||
const MODE_COMMON = 'common';
|
||||
const MODE_NONE = 'none';
|
||||
|
||||
/**
|
||||
* @var WebThumbnailer instance.
|
||||
*/
|
||||
protected $wt;
|
||||
|
||||
/**
|
||||
* @var ConfigManager instance.
|
||||
*/
|
||||
protected $conf;
|
||||
|
||||
/**
|
||||
* Thumbnailer constructor.
|
||||
*
|
||||
* @param ConfigManager $conf instance.
|
||||
*/
|
||||
public function __construct($conf)
|
||||
{
|
||||
$this->conf = $conf;
|
||||
|
||||
if (! $this->checkRequirements()) {
|
||||
$this->conf->set('thumbnails.enabled', false);
|
||||
$this->conf->write(true);
|
||||
// TODO: create a proper error handling system able to catch exceptions...
|
||||
die(t('php-gd extension must be loaded to use thumbnails. Thumbnails are now disabled. Please reload the page.'));
|
||||
}
|
||||
|
||||
$this->wt = new WebThumbnailer();
|
||||
WTConfigManager::addFile('inc/web-thumbnailer.json');
|
||||
$this->wt->maxWidth($this->conf->get('thumbnails.width'))
|
||||
->maxHeight($this->conf->get('thumbnails.height'))
|
||||
->crop(true)
|
||||
->debug($this->conf->get('dev.debug', false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a thumbnail for given URL
|
||||
*
|
||||
* @param string $url where to look for a thumbnail.
|
||||
*
|
||||
* @return bool|string The thumbnail relative cache file path, or false if none has been found.
|
||||
*/
|
||||
public function get($url)
|
||||
{
|
||||
if ($this->conf->get('thumbnails.mode') === self::MODE_COMMON
|
||||
&& ! $this->isCommonMediaOrImage($url)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
return $this->wt->thumbnail($url);
|
||||
} catch (WebThumbnailerException $e) {
|
||||
// Exceptions are only thrown in debug mode.
|
||||
error_log(get_class($e) . ': ' . $e->getMessage());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* We check weather the given URL is from a common media domain,
|
||||
* or if the file extension is an image.
|
||||
*
|
||||
* @param string $url to check
|
||||
*
|
||||
* @return bool true if it's an image or from a common media domain, false otherwise.
|
||||
*/
|
||||
public function isCommonMediaOrImage($url)
|
||||
{
|
||||
foreach (self::COMMON_MEDIA_DOMAINS as $domain) {
|
||||
if (strpos($url, $domain) !== false) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (endsWith($url, '.jpg') || endsWith($url, '.png') || endsWith($url, '.jpeg')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure that requirements are match to use thumbnails:
|
||||
* - php-gd is loaded
|
||||
*/
|
||||
protected function checkRequirements()
|
||||
{
|
||||
return extension_loaded('gd');
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
use Shaarli\Config\ConfigJson;
|
||||
use Shaarli\Config\ConfigPhp;
|
||||
use Shaarli\Config\ConfigManager;
|
||||
use Shaarli\Thumbnailer;
|
||||
|
||||
/**
|
||||
* Class Updater.
|
||||
|
@ -30,6 +31,11 @@ class Updater
|
|||
*/
|
||||
protected $isLoggedIn;
|
||||
|
||||
/**
|
||||
* @var array $_SESSION
|
||||
*/
|
||||
protected $session;
|
||||
|
||||
/**
|
||||
* @var ReflectionMethod[] List of current class methods.
|
||||
*/
|
||||
|
@ -42,13 +48,17 @@ class Updater
|
|||
* @param LinkDB $linkDB LinkDB instance.
|
||||
* @param ConfigManager $conf Configuration Manager instance.
|
||||
* @param boolean $isLoggedIn True if the user is logged in.
|
||||
* @param array $session $_SESSION (by reference)
|
||||
*
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
public function __construct($doneUpdates, $linkDB, $conf, $isLoggedIn)
|
||||
public function __construct($doneUpdates, $linkDB, $conf, $isLoggedIn, &$session = [])
|
||||
{
|
||||
$this->doneUpdates = $doneUpdates;
|
||||
$this->linkDB = $linkDB;
|
||||
$this->conf = $conf;
|
||||
$this->isLoggedIn = $isLoggedIn;
|
||||
$this->session = &$session;
|
||||
|
||||
// Retrieve all update methods.
|
||||
$class = new ReflectionClass($this);
|
||||
|
@ -480,6 +490,30 @@ public function updateMethodDownloadSizeAndTimeoutConf()
|
|||
}
|
||||
|
||||
$this->conf->write($this->isLoggedIn);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* * Move thumbnails management to WebThumbnailer, coming with new settings.
|
||||
*/
|
||||
public function updateMethodWebThumbnailer()
|
||||
{
|
||||
if ($this->conf->exists('thumbnails.mode')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$thumbnailsEnabled = $this->conf->get('thumbnail.enable_thumbnails', true);
|
||||
$this->conf->set('thumbnails.mode', $thumbnailsEnabled ? Thumbnailer::MODE_ALL : Thumbnailer::MODE_NONE);
|
||||
$this->conf->set('thumbnails.width', 125);
|
||||
$this->conf->set('thumbnails.height', 90);
|
||||
$this->conf->remove('thumbnail');
|
||||
$this->conf->write(true);
|
||||
|
||||
if ($thumbnailsEnabled) {
|
||||
$this->session['warnings'][] = t(
|
||||
'You have enabled or changed thumbnails mode. <a href="?do=thumbs_update">Please synchronize them</a>.'
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -147,6 +147,33 @@ public function set($setting, $value, $write = false, $isLoggedIn = false)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a config element from the config file.
|
||||
*
|
||||
* @param string $setting Asked setting, keys separated with dots.
|
||||
* @param bool $write Write the new setting in the config file, default false.
|
||||
* @param bool $isLoggedIn User login state, default false.
|
||||
*
|
||||
* @throws \Exception Invalid
|
||||
*/
|
||||
public function remove($setting, $write = false, $isLoggedIn = false)
|
||||
{
|
||||
if (empty($setting) || ! is_string($setting)) {
|
||||
throw new \Exception(t('Invalid setting key parameter. String expected, got: '). gettype($setting));
|
||||
}
|
||||
|
||||
// During the ConfigIO transition, map legacy settings to the new ones.
|
||||
if ($this->configIO instanceof ConfigPhp && isset(ConfigPhp::$LEGACY_KEYS_MAPPING[$setting])) {
|
||||
$setting = ConfigPhp::$LEGACY_KEYS_MAPPING[$setting];
|
||||
}
|
||||
|
||||
$settings = explode('.', $setting);
|
||||
self::removeConfig($settings, $this->loadedConfig);
|
||||
if ($write) {
|
||||
$this->write($isLoggedIn);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a settings exists.
|
||||
*
|
||||
|
@ -289,6 +316,27 @@ protected static function setConfig($settings, $value, &$conf)
|
|||
$conf[$setting] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursive function which find asked setting in the loaded config and deletes it.
|
||||
*
|
||||
* @param array $settings Ordered array which contains keys to find.
|
||||
* @param array $conf Loaded settings, then sub-array.
|
||||
*
|
||||
* @return mixed Found setting or NOT_FOUND flag.
|
||||
*/
|
||||
protected static function removeConfig($settings, &$conf)
|
||||
{
|
||||
if (!is_array($settings) || count($settings) == 0) {
|
||||
return self::$NOT_FOUND;
|
||||
}
|
||||
|
||||
$setting = array_shift($settings);
|
||||
if (count($settings) > 0) {
|
||||
return self::removeConfig($settings, $conf[$setting]);
|
||||
}
|
||||
unset($conf[$setting]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a bunch of default values allowing Shaarli to start without a config file.
|
||||
*/
|
||||
|
@ -333,12 +381,12 @@ protected function setDefaultValues()
|
|||
// default state of the 'remember me' checkbox of the login form
|
||||
$this->setEmpty('privacy.remember_user_default', true);
|
||||
|
||||
$this->setEmpty('thumbnail.enable_thumbnails', true);
|
||||
$this->setEmpty('thumbnail.enable_localcache', true);
|
||||
|
||||
$this->setEmpty('redirector.url', '');
|
||||
$this->setEmpty('redirector.encode_url', true);
|
||||
|
||||
$this->setEmpty('thumbnails.width', '125');
|
||||
$this->setEmpty('thumbnails.height', '90');
|
||||
|
||||
$this->setEmpty('translation.language', 'auto');
|
||||
$this->setEmpty('translation.mode', 'php');
|
||||
$this->setEmpty('translation.extensions', []);
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
import Blazy from 'blazy';
|
||||
|
||||
(() => {
|
||||
const picwall = document.getElementById('picwall_container');
|
||||
if (picwall != null) {
|
||||
// Suppress ESLint error because that's how bLazy works
|
||||
/* eslint-disable no-new */
|
||||
new Blazy();
|
||||
}
|
||||
})();
|
51
assets/common/js/thumbnails-update.js
Normal file
51
assets/common/js/thumbnails-update.js
Normal file
|
@ -0,0 +1,51 @@
|
|||
/**
|
||||
* Script used in the thumbnails update page.
|
||||
*
|
||||
* It retrieves the list of link IDs to update, and execute AJAX requests
|
||||
* to update their thumbnails, while updating the progress bar.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Update the thumbnail of the link with the current i index in ids.
|
||||
* It contains a recursive call to retrieve the thumb of the next link when it succeed.
|
||||
* It also update the progress bar and other visual feedback elements.
|
||||
*
|
||||
* @param {array} ids List of LinkID to update
|
||||
* @param {int} i Current index in ids
|
||||
* @param {object} elements List of DOM element to avoid retrieving them at each iteration
|
||||
*/
|
||||
function updateThumb(ids, i, elements) {
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open('POST', '?do=ajax_thumb_update');
|
||||
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
|
||||
xhr.responseType = 'json';
|
||||
xhr.onload = () => {
|
||||
if (xhr.status !== 200) {
|
||||
alert(`An error occurred. Return code: ${xhr.status}`);
|
||||
} else {
|
||||
const { response } = xhr;
|
||||
i += 1;
|
||||
elements.progressBar.style.width = `${(i * 100) / ids.length}%`;
|
||||
elements.current.innerHTML = i;
|
||||
elements.title.innerHTML = response.title;
|
||||
if (response.thumbnail !== false) {
|
||||
elements.thumbnail.innerHTML = `<img src="${response.thumbnail}">`;
|
||||
}
|
||||
if (i < ids.length) {
|
||||
updateThumb(ids, i, elements);
|
||||
}
|
||||
}
|
||||
};
|
||||
xhr.send(`id=${ids[i]}`);
|
||||
}
|
||||
|
||||
(() => {
|
||||
const ids = document.getElementsByName('ids')[0].value.split(',');
|
||||
const elements = {
|
||||
progressBar: document.querySelector('.progressbar > div'),
|
||||
current: document.querySelector('.progress-current'),
|
||||
thumbnail: document.querySelector('.thumbnail-placeholder'),
|
||||
title: document.querySelector('.thumbnail-link-title'),
|
||||
};
|
||||
updateThumb(ids, 0, elements);
|
||||
})();
|
7
assets/common/js/thumbnails.js
Normal file
7
assets/common/js/thumbnails.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
import Blazy from 'blazy';
|
||||
|
||||
(() => {
|
||||
// Suppress ESLint error because that's how bLazy works
|
||||
/* eslint-disable no-new */
|
||||
new Blazy();
|
||||
})();
|
|
@ -146,6 +146,17 @@ body,
|
|||
background-color: $main-green;
|
||||
}
|
||||
|
||||
.pure-alert-warning {
|
||||
a {
|
||||
color: $warning-text;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.page-single-alert {
|
||||
margin-top: 100px;
|
||||
}
|
||||
|
||||
.anchor {
|
||||
&:target {
|
||||
padding-top: 40px;
|
||||
|
@ -625,23 +636,22 @@ body,
|
|||
}
|
||||
|
||||
.linklist-item {
|
||||
position: relative;
|
||||
margin: 0 0 10px;
|
||||
box-shadow: 1px 1px 3px $light-grey;
|
||||
background: $almost-white;
|
||||
|
||||
&.private {
|
||||
.linklist-item-title {
|
||||
&::before {
|
||||
@extend %private-border;
|
||||
margin-top: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
.linklist-item-description {
|
||||
&::before {
|
||||
@extend %private-border;
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
background: $orange;
|
||||
width: 2px;
|
||||
height: 100%;
|
||||
}
|
||||
content: '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1543,3 +1553,40 @@ form {
|
|||
.pure-button-shaarli {
|
||||
background-color: $main-green;
|
||||
}
|
||||
|
||||
.progressbar {
|
||||
border-radius: 6px;
|
||||
background-color: $main-green;
|
||||
padding: 1px;
|
||||
|
||||
> div {
|
||||
border-radius: 10px;
|
||||
background: repeating-linear-gradient(
|
||||
-45deg,
|
||||
$almost-white,
|
||||
$almost-white 6px,
|
||||
$background-color 6px,
|
||||
$background-color 12px
|
||||
);
|
||||
width: 0%;
|
||||
height: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.thumbnails-page-container {
|
||||
.progress-counter {
|
||||
padding: 10px 0 20px;
|
||||
}
|
||||
|
||||
.thumbnail-placeholder {
|
||||
margin: 10px auto;
|
||||
background-color: $light-grey;
|
||||
}
|
||||
|
||||
.thumbnail-link-title {
|
||||
padding-bottom: 20px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -701,8 +701,8 @@ a.bigbutton, #pageheader a.bigbutton {
|
|||
position: relative;
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
float: left;
|
||||
|
@ -739,9 +739,9 @@ a.bigbutton, #pageheader a.bigbutton {
|
|||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 90px;
|
||||
width: 120px;
|
||||
font-weight: bold;
|
||||
font-size: 8pt;
|
||||
font-size: 9pt;
|
||||
color: #fff;
|
||||
text-align: left;
|
||||
background-color: transparent;
|
||||
|
@ -1210,3 +1210,43 @@ ul.errors {
|
|||
width: 13px;
|
||||
height: 13px;
|
||||
}
|
||||
|
||||
.thumbnails-update-container {
|
||||
padding: 20px 0;
|
||||
width: 50%;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.thumbnails-update-container .thumbnail-placeholder {
|
||||
background: grey;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.thumbnails-update-container .thumbnail-link-title {
|
||||
width: 75%;
|
||||
margin: auto;
|
||||
|
||||
padding-bottom: 20px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.progressbar {
|
||||
border-radius: 6px;
|
||||
background-color: #111;
|
||||
padding: 1px;
|
||||
}
|
||||
|
||||
.progressbar > div {
|
||||
border-radius: 10px;
|
||||
background: repeating-linear-gradient(
|
||||
-45deg,
|
||||
#f5f5f5,
|
||||
#f5f5f5 6px,
|
||||
#d0d0d0 6px,
|
||||
#d0d0d0 12px
|
||||
);
|
||||
width: 0%;
|
||||
height: 10px;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
"shaarli/netscape-bookmark-parser": "^2.0",
|
||||
"erusev/parsedown": "^1.6",
|
||||
"slim/slim": "^3.0",
|
||||
"arthurhoaro/web-thumbnailer": "^1.1",
|
||||
"pubsubhubbub/publisher": "dev-master",
|
||||
"gettext/gettext": "^4.4"
|
||||
},
|
||||
|
|
338
composer.lock
generated
338
composer.lock
generated
|
@ -1,11 +1,59 @@
|
|||
{
|
||||
"_readme": [
|
||||
"This file locks the dependencies of your project to a known state",
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "308a35eab91602fbb449f2c669c445ed",
|
||||
"content-hash": "da7a0c081b61d949154c5d2e5370cbab",
|
||||
"packages": [
|
||||
{
|
||||
"name": "arthurhoaro/web-thumbnailer",
|
||||
"version": "v1.2.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ArthurHoaro/web-thumbnailer.git",
|
||||
"reference": "a5a52f69e8e8f3c71fab9649e2a927e2d3f418f1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/ArthurHoaro/web-thumbnailer/zipball/a5a52f69e8e8f3c71fab9649e2a927e2d3f418f1",
|
||||
"reference": "a5a52f69e8e8f3c71fab9649e2a927e2d3f418f1",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.6",
|
||||
"phpunit/php-text-template": "^1.2"
|
||||
},
|
||||
"conflict": {
|
||||
"phpunit/php-timer": ">=2"
|
||||
},
|
||||
"require-dev": {
|
||||
"php-coveralls/php-coveralls": "^2.0",
|
||||
"phpunit/phpunit": "5.2.*",
|
||||
"squizlabs/php_codesniffer": "^3.2"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"WebThumbnailer\\": [
|
||||
"src/",
|
||||
"tests/"
|
||||
]
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Arthur Hoaro",
|
||||
"homepage": "http://hoa.ro"
|
||||
}
|
||||
],
|
||||
"description": "PHP library which will retrieve a thumbnail for any given URL",
|
||||
"time": "2018-07-17T10:21:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "container-interop/container-interop",
|
||||
"version": "1.2.0",
|
||||
|
@ -85,16 +133,16 @@
|
|||
},
|
||||
{
|
||||
"name": "gettext/gettext",
|
||||
"version": "v4.4.4",
|
||||
"version": "v4.6.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/oscarotero/Gettext.git",
|
||||
"reference": "ab5e863de2f60806d02e6e6081e21efd45249168"
|
||||
"reference": "cae84aff39a87e07bd6e5cddb5adb720a0ffa357"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/oscarotero/Gettext/zipball/ab5e863de2f60806d02e6e6081e21efd45249168",
|
||||
"reference": "ab5e863de2f60806d02e6e6081e21efd45249168",
|
||||
"url": "https://api.github.com/repos/oscarotero/Gettext/zipball/cae84aff39a87e07bd6e5cddb5adb720a0ffa357",
|
||||
"reference": "cae84aff39a87e07bd6e5cddb5adb720a0ffa357",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -103,7 +151,7 @@
|
|||
},
|
||||
"require-dev": {
|
||||
"illuminate/view": "*",
|
||||
"phpunit/phpunit": "^4.8|^5.7",
|
||||
"phpunit/phpunit": "^4.8|^5.7|^6.5",
|
||||
"squizlabs/php_codesniffer": "^3.0",
|
||||
"symfony/yaml": "~2",
|
||||
"twig/extensions": "*",
|
||||
|
@ -143,20 +191,20 @@
|
|||
"po",
|
||||
"translation"
|
||||
],
|
||||
"time": "2018-02-21T18:49:59+00:00"
|
||||
"time": "2018-06-26T16:51:09+00:00"
|
||||
},
|
||||
{
|
||||
"name": "gettext/languages",
|
||||
"version": "2.3.0",
|
||||
"version": "2.4.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mlocati/cldr-to-gettext-plural-rules.git",
|
||||
"reference": "49c39e51569963cc917a924b489e7025bfb9d8c7"
|
||||
"reference": "1b74377bd0c4cd87e8d72b948f5d8867e23505a5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/mlocati/cldr-to-gettext-plural-rules/zipball/49c39e51569963cc917a924b489e7025bfb9d8c7",
|
||||
"reference": "49c39e51569963cc917a924b489e7025bfb9d8c7",
|
||||
"url": "https://api.github.com/repos/mlocati/cldr-to-gettext-plural-rules/zipball/1b74377bd0c4cd87e8d72b948f5d8867e23505a5",
|
||||
"reference": "1b74377bd0c4cd87e8d72b948f5d8867e23505a5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -204,7 +252,7 @@
|
|||
"translations",
|
||||
"unicode"
|
||||
],
|
||||
"time": "2017-03-23T17:02:28+00:00"
|
||||
"time": "2018-06-21T15:58:36+00:00"
|
||||
},
|
||||
{
|
||||
"name": "katzgrau/klogger",
|
||||
|
@ -302,6 +350,47 @@
|
|||
],
|
||||
"time": "2018-02-13T20:26:39+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-text-template",
|
||||
"version": "1.2.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-text-template.git",
|
||||
"reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
|
||||
"reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"src/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Sebastian Bergmann",
|
||||
"email": "sebastian@phpunit.de",
|
||||
"role": "lead"
|
||||
}
|
||||
],
|
||||
"description": "Simple template engine.",
|
||||
"homepage": "https://github.com/sebastianbergmann/php-text-template/",
|
||||
"keywords": [
|
||||
"template"
|
||||
],
|
||||
"time": "2015-06-21T13:50:34+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pimple/pimple",
|
||||
"version": "v3.2.3",
|
||||
|
@ -504,12 +593,12 @@
|
|||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pubsubhubbub/php-publisher.git",
|
||||
"reference": "0d224daebd504ab61c22fee4db58f8d1fc18945f"
|
||||
"reference": "5008fc529b057251b48f4d17a10fdb20047ea8f5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pubsubhubbub/php-publisher/zipball/0d224daebd504ab61c22fee4db58f8d1fc18945f",
|
||||
"reference": "0d224daebd504ab61c22fee4db58f8d1fc18945f",
|
||||
"url": "https://api.github.com/repos/pubsubhubbub/php-publisher/zipball/5008fc529b057251b48f4d17a10fdb20047ea8f5",
|
||||
"reference": "5008fc529b057251b48f4d17a10fdb20047ea8f5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -539,7 +628,7 @@
|
|||
"publishers",
|
||||
"pubsubhubbub"
|
||||
],
|
||||
"time": "2017-10-08T10:59:41+00:00"
|
||||
"time": "2018-05-22T11:56:26+00:00"
|
||||
},
|
||||
{
|
||||
"name": "shaarli/netscape-bookmark-parser",
|
||||
|
@ -598,16 +687,16 @@
|
|||
},
|
||||
{
|
||||
"name": "slim/slim",
|
||||
"version": "3.9.2",
|
||||
"version": "3.10.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/slimphp/Slim.git",
|
||||
"reference": "4086d0106cf5a7135c69fce4161fe355a8feb118"
|
||||
"reference": "d8aabeacc3688b25e2f2dd2db91df91ec6fdd748"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/slimphp/Slim/zipball/4086d0106cf5a7135c69fce4161fe355a8feb118",
|
||||
"reference": "4086d0106cf5a7135c69fce4161fe355a8feb118",
|
||||
"url": "https://api.github.com/repos/slimphp/Slim/zipball/d8aabeacc3688b25e2f2dd2db91df91ec6fdd748",
|
||||
"reference": "d8aabeacc3688b25e2f2dd2db91df91ec6fdd748",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -665,7 +754,7 @@
|
|||
"micro",
|
||||
"router"
|
||||
],
|
||||
"time": "2017-11-26T19:13:09+00:00"
|
||||
"time": "2018-04-19T19:29:08+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [
|
||||
|
@ -1022,23 +1111,23 @@
|
|||
},
|
||||
{
|
||||
"name": "phpspec/prophecy",
|
||||
"version": "1.7.5",
|
||||
"version": "1.7.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpspec/prophecy.git",
|
||||
"reference": "dfd6be44111a7c41c2e884a336cc4f461b3b2401"
|
||||
"reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/dfd6be44111a7c41c2e884a336cc4f461b3b2401",
|
||||
"reference": "dfd6be44111a7c41c2e884a336cc4f461b3b2401",
|
||||
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/33a7e3c4fda54e912ff6338c48823bd5c0f0b712",
|
||||
"reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/instantiator": "^1.0.2",
|
||||
"php": "^5.3|^7.0",
|
||||
"phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0",
|
||||
"sebastian/comparator": "^1.1|^2.0",
|
||||
"sebastian/comparator": "^1.1|^2.0|^3.0",
|
||||
"sebastian/recursion-context": "^1.0|^2.0|^3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
|
@ -1081,7 +1170,7 @@
|
|||
"spy",
|
||||
"stub"
|
||||
],
|
||||
"time": "2018-02-19T10:16:54+00:00"
|
||||
"time": "2018-04-18T13:57:24+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
|
@ -1193,47 +1282,6 @@
|
|||
],
|
||||
"time": "2017-11-27T13:52:08+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-text-template",
|
||||
"version": "1.2.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-text-template.git",
|
||||
"reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
|
||||
"reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"src/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Sebastian Bergmann",
|
||||
"email": "sebastian@phpunit.de",
|
||||
"role": "lead"
|
||||
}
|
||||
],
|
||||
"description": "Simple template engine.",
|
||||
"homepage": "https://github.com/sebastianbergmann/php-text-template/",
|
||||
"keywords": [
|
||||
"template"
|
||||
],
|
||||
"time": "2015-06-21T13:50:34+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-timer",
|
||||
"version": "1.0.9",
|
||||
|
@ -2207,21 +2255,22 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/config",
|
||||
"version": "v3.4.6",
|
||||
"version": "v3.4.12",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/config.git",
|
||||
"reference": "05e10567b529476a006b00746c5f538f1636810e"
|
||||
"reference": "1fffdeb349ff36a25184e5564c25289b1dbfc402"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/config/zipball/05e10567b529476a006b00746c5f538f1636810e",
|
||||
"reference": "05e10567b529476a006b00746c5f538f1636810e",
|
||||
"url": "https://api.github.com/repos/symfony/config/zipball/1fffdeb349ff36a25184e5564c25289b1dbfc402",
|
||||
"reference": "1fffdeb349ff36a25184e5564c25289b1dbfc402",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^5.5.9|>=7.0.8",
|
||||
"symfony/filesystem": "~2.8|~3.0|~4.0"
|
||||
"symfony/filesystem": "~2.8|~3.0|~4.0",
|
||||
"symfony/polyfill-ctype": "~1.8"
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/dependency-injection": "<3.3",
|
||||
|
@ -2266,20 +2315,20 @@
|
|||
],
|
||||
"description": "Symfony Config Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2018-02-14T10:03:57+00:00"
|
||||
"time": "2018-06-19T14:02:58+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v3.4.6",
|
||||
"version": "v3.4.12",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/console.git",
|
||||
"reference": "067339e9b8ec30d5f19f5950208893ff026b94f7"
|
||||
"reference": "1b97071a26d028c9bd4588264e101e14f6e7cd00"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/067339e9b8ec30d5f19f5950208893ff026b94f7",
|
||||
"reference": "067339e9b8ec30d5f19f5950208893ff026b94f7",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/1b97071a26d028c9bd4588264e101e14f6e7cd00",
|
||||
"reference": "1b97071a26d028c9bd4588264e101e14f6e7cd00",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2300,7 +2349,7 @@
|
|||
"symfony/process": "~3.3|~4.0"
|
||||
},
|
||||
"suggest": {
|
||||
"psr/log": "For using the console logger",
|
||||
"psr/log-implementation": "For using the console logger",
|
||||
"symfony/event-dispatcher": "",
|
||||
"symfony/lock": "",
|
||||
"symfony/process": ""
|
||||
|
@ -2335,20 +2384,20 @@
|
|||
],
|
||||
"description": "Symfony Console Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2018-02-26T15:46:28+00:00"
|
||||
"time": "2018-05-23T05:02:55+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/debug",
|
||||
"version": "v3.4.6",
|
||||
"version": "v3.4.12",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/debug.git",
|
||||
"reference": "9b1071f86e79e1999b3d3675d2e0e7684268b9bc"
|
||||
"reference": "47e6788c5b151cf0cfdf3329116bf33800632d75"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/debug/zipball/9b1071f86e79e1999b3d3675d2e0e7684268b9bc",
|
||||
"reference": "9b1071f86e79e1999b3d3675d2e0e7684268b9bc",
|
||||
"url": "https://api.github.com/repos/symfony/debug/zipball/47e6788c5b151cf0cfdf3329116bf33800632d75",
|
||||
"reference": "47e6788c5b151cf0cfdf3329116bf33800632d75",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2391,20 +2440,20 @@
|
|||
],
|
||||
"description": "Symfony Debug Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2018-02-28T21:49:22+00:00"
|
||||
"time": "2018-06-25T11:10:40+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/dependency-injection",
|
||||
"version": "v3.4.6",
|
||||
"version": "v3.4.12",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/dependency-injection.git",
|
||||
"reference": "12e901abc1cb0d637a0e5abe9923471361d96b07"
|
||||
"reference": "a0be80e3f8c11aca506e250c00bb100c04c35d10"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/dependency-injection/zipball/12e901abc1cb0d637a0e5abe9923471361d96b07",
|
||||
"reference": "12e901abc1cb0d637a0e5abe9923471361d96b07",
|
||||
"url": "https://api.github.com/repos/symfony/dependency-injection/zipball/a0be80e3f8c11aca506e250c00bb100c04c35d10",
|
||||
"reference": "a0be80e3f8c11aca506e250c00bb100c04c35d10",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2462,24 +2511,25 @@
|
|||
],
|
||||
"description": "Symfony DependencyInjection Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2018-03-04T03:54:53+00:00"
|
||||
"time": "2018-06-25T08:36:56+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/filesystem",
|
||||
"version": "v3.4.6",
|
||||
"version": "v3.4.12",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/filesystem.git",
|
||||
"reference": "253a4490b528597aa14d2bf5aeded6f5e5e4a541"
|
||||
"reference": "8a721a5f2553c6c3482b1c5b22ed60fe94dd63ed"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/filesystem/zipball/253a4490b528597aa14d2bf5aeded6f5e5e4a541",
|
||||
"reference": "253a4490b528597aa14d2bf5aeded6f5e5e4a541",
|
||||
"url": "https://api.github.com/repos/symfony/filesystem/zipball/8a721a5f2553c6c3482b1c5b22ed60fe94dd63ed",
|
||||
"reference": "8a721a5f2553c6c3482b1c5b22ed60fe94dd63ed",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^5.5.9|>=7.0.8"
|
||||
"php": "^5.5.9|>=7.0.8",
|
||||
"symfony/polyfill-ctype": "~1.8"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
|
@ -2511,20 +2561,20 @@
|
|||
],
|
||||
"description": "Symfony Filesystem Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2018-02-22T10:48:49+00:00"
|
||||
"time": "2018-06-21T11:10:19+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/finder",
|
||||
"version": "v3.4.6",
|
||||
"version": "v3.4.12",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/finder.git",
|
||||
"reference": "a479817ce0a9e4adfd7d39c6407c95d97c254625"
|
||||
"reference": "3a8c3de91d2b2c68cd2d665cf9d00f7ef9eaa394"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/a479817ce0a9e4adfd7d39c6407c95d97c254625",
|
||||
"reference": "a479817ce0a9e4adfd7d39c6407c95d97c254625",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/3a8c3de91d2b2c68cd2d665cf9d00f7ef9eaa394",
|
||||
"reference": "3a8c3de91d2b2c68cd2d665cf9d00f7ef9eaa394",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2560,20 +2610,75 @@
|
|||
],
|
||||
"description": "Symfony Finder Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2018-03-05T18:28:11+00:00"
|
||||
"time": "2018-06-19T20:52:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
"version": "v1.7.0",
|
||||
"name": "symfony/polyfill-ctype",
|
||||
"version": "v1.8.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||
"reference": "78be803ce01e55d3491c1397cf1c64beb9c1b63b"
|
||||
"url": "https://github.com/symfony/polyfill-ctype.git",
|
||||
"reference": "7cc359f1b7b80fc25ed7796be7d96adc9b354bae"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/78be803ce01e55d3491c1397cf1c64beb9c1b63b",
|
||||
"reference": "78be803ce01e55d3491c1397cf1c64beb9c1b63b",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/7cc359f1b7b80fc25ed7796be7d96adc9b354bae",
|
||||
"reference": "7cc359f1b7b80fc25ed7796be7d96adc9b354bae",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.8-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Ctype\\": ""
|
||||
},
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
},
|
||||
{
|
||||
"name": "Gert de Pagter",
|
||||
"email": "BackEndTea@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Symfony polyfill for ctype functions",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"compatibility",
|
||||
"ctype",
|
||||
"polyfill",
|
||||
"portable"
|
||||
],
|
||||
"time": "2018-04-30T19:57:29+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
"version": "v1.8.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||
"reference": "3296adf6a6454a050679cde90f95350ad604b171"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/3296adf6a6454a050679cde90f95350ad604b171",
|
||||
"reference": "3296adf6a6454a050679cde90f95350ad604b171",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2585,7 +2690,7 @@
|
|||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.7-dev"
|
||||
"dev-master": "1.8-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
|
@ -2619,24 +2724,25 @@
|
|||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"time": "2018-01-30T19:27:44+00:00"
|
||||
"time": "2018-04-26T10:06:28+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/yaml",
|
||||
"version": "v3.4.6",
|
||||
"version": "v3.4.12",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/yaml.git",
|
||||
"reference": "6af42631dcf89e9c616242c900d6c52bd53bd1bb"
|
||||
"reference": "c5010cc1692ce1fa328b1fb666961eb3d4a85bb0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/yaml/zipball/6af42631dcf89e9c616242c900d6c52bd53bd1bb",
|
||||
"reference": "6af42631dcf89e9c616242c900d6c52bd53bd1bb",
|
||||
"url": "https://api.github.com/repos/symfony/yaml/zipball/c5010cc1692ce1fa328b1fb666961eb3d4a85bb0",
|
||||
"reference": "c5010cc1692ce1fa328b1fb666961eb3d4a85bb0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^5.5.9|>=7.0.8"
|
||||
"php": "^5.5.9|>=7.0.8",
|
||||
"symfony/polyfill-ctype": "~1.8"
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/console": "<3.4"
|
||||
|
@ -2677,7 +2783,7 @@
|
|||
],
|
||||
"description": "Symfony Yaml Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2018-02-16T09:50:28+00:00"
|
||||
"time": "2018-05-03T23:18:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "theseer/fdomdocument",
|
||||
|
|
18
doc/md/Link-structure.md
Normal file
18
doc/md/Link-structure.md
Normal file
|
@ -0,0 +1,18 @@
|
|||
## Link structure
|
||||
|
||||
Every link available through the `LinkDB` object is represented as an array
|
||||
containing the following fields:
|
||||
|
||||
* `id` (integer): Unique identifier.
|
||||
* `title` (string): Title of the link.
|
||||
* `url` (string): URL of the link. Used for displayable links (without redirector, url encoding, etc.).
|
||||
Can be absolute or relative for Notes.
|
||||
* `real_url` (string): Real destination URL, can be redirected, encoded, etc.
|
||||
* `shorturl` (string): Permalink small hash.
|
||||
* `description` (string): Link text description.
|
||||
* `private` (boolean): whether the link is private or not.
|
||||
* `tags` (string): all link tags separated by a single space
|
||||
* `thumbnail` (string|boolean): relative path of the thumbnail cache file, or false if there isn't any.
|
||||
* `created` (DateTime): link creation date time.
|
||||
* `updated` (DateTime): last modification date time.
|
||||
|
|
@ -29,7 +29,7 @@ Extension | Required? | Usage
|
|||
---|:---:|---
|
||||
[`openssl`](http://php.net/manual/en/book.openssl.php) | All | OpenSSL, HTTPS
|
||||
[`php-mbstring`](http://php.net/manual/en/book.mbstring.php) | CentOS, Fedora, RHEL, Windows, some hosting providers | multibyte (Unicode) string support
|
||||
[`php-gd`](http://php.net/manual/en/book.image.php) | optional | thumbnail resizing
|
||||
[`php-gd`](http://php.net/manual/en/book.image.php) | optional | required to use thumbnails
|
||||
[`php-intl`](http://php.net/manual/en/book.intl.php) | optional | localized text sorting (e.g. `e->è->f`)
|
||||
[`php-curl`](http://php.net/manual/en/book.curl.php) | optional | using cURL for fetching webpages and thumbnails in a more robust way
|
||||
[`php-gettext`](http://php.net/manual/en/book.gettext.php) | optional | Use the translation system in gettext mode (faster)
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Shaarli\n"
|
||||
"POT-Creation-Date: 2018-01-24 18:43+0100\n"
|
||||
"PO-Revision-Date: 2018-03-06 18:44+0100\n"
|
||||
"POT-Creation-Date: 2018-07-17 13:04+0200\n"
|
||||
"PO-Revision-Date: 2018-07-17 13:07+0200\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Shaarli\n"
|
||||
"Language: fr_FR\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: Poedit 2.0.6\n"
|
||||
"X-Generator: Poedit 2.0.9\n"
|
||||
"X-Poedit-Basepath: ../../../..\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
"X-Poedit-SourceCharset: UTF-8\n"
|
||||
|
@ -56,7 +56,7 @@ msgstr "Liens directs"
|
|||
|
||||
#: application/FeedBuilder.php:153
|
||||
#: tmp/daily.b91ef64efc3688266305ea9b42e5017e.rtpl.php:88
|
||||
#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:178
|
||||
#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:177
|
||||
msgid "Permalink"
|
||||
msgstr "Permalien"
|
||||
|
||||
|
@ -68,18 +68,22 @@ msgstr "Le fichier d'historique n'est pas accessible en lecture ou en écriture"
|
|||
msgid "Could not parse history file"
|
||||
msgstr "Format incorrect pour le fichier d'historique"
|
||||
|
||||
#: application/Languages.php:161
|
||||
#: application/Languages.php:177
|
||||
msgid "Automatic"
|
||||
msgstr "Automatique"
|
||||
|
||||
#: application/Languages.php:162
|
||||
#: application/Languages.php:178
|
||||
msgid "English"
|
||||
msgstr "Anglais"
|
||||
|
||||
#: application/Languages.php:163
|
||||
#: application/Languages.php:179
|
||||
msgid "French"
|
||||
msgstr "Français"
|
||||
|
||||
#: application/Languages.php:180
|
||||
msgid "German"
|
||||
msgstr "Allemand"
|
||||
|
||||
#: application/LinkDB.php:136
|
||||
msgid "You are not authorized to add a link."
|
||||
msgstr "Vous n'êtes pas autorisé à ajouter un lien."
|
||||
|
@ -163,11 +167,11 @@ msgstr ""
|
|||
"a été importé avec succès en %d secondes : %d liens importés, %d liens "
|
||||
"écrasés, %d liens ignorés."
|
||||
|
||||
#: application/PageBuilder.php:168
|
||||
#: application/PageBuilder.php:200
|
||||
msgid "The page you are trying to reach does not exist or has been deleted."
|
||||
msgstr "La page que vous essayez de consulter n'existe pas ou a été supprimée."
|
||||
|
||||
#: application/PageBuilder.php:170
|
||||
#: application/PageBuilder.php:202
|
||||
msgid "404 Not Found"
|
||||
msgstr "404 Introuvable"
|
||||
|
||||
|
@ -176,21 +180,37 @@ msgstr "404 Introuvable"
|
|||
msgid "Plugin \"%s\" files not found."
|
||||
msgstr "Les fichiers de l'extension \"%s\" sont introuvables."
|
||||
|
||||
#: application/Updater.php:76
|
||||
#: application/Thumbnailer.php:61
|
||||
msgid ""
|
||||
"php-gd extension must be loaded to use thumbnails. Thumbnails are now "
|
||||
"disabled. Please reload the page."
|
||||
msgstr ""
|
||||
"php-gd extension must be loaded to use thumbnails. Thumbnails are now "
|
||||
"disabled. Please reload the page."
|
||||
|
||||
#: application/Updater.php:86
|
||||
msgid "Couldn't retrieve Updater class methods."
|
||||
msgstr "Impossible de récupérer les méthodes de la classe Updater."
|
||||
|
||||
#: application/Updater.php:506
|
||||
#: application/Updater.php:514 index.php:1023
|
||||
msgid ""
|
||||
"You have enabled or changed thumbnails mode. <a href=\"?do=thumbs_update"
|
||||
"\">Please synchronize them</a>."
|
||||
msgstr ""
|
||||
"Vous avez activé ou changé le mode de miniatures. <a href=\"?do=thumbs_update"
|
||||
"\">Merci de les synchroniser</a>."
|
||||
|
||||
#: application/Updater.php:566
|
||||
msgid "An error occurred while running the update "
|
||||
msgstr "Une erreur s'est produite lors de l'exécution de la mise à jour "
|
||||
|
||||
#: application/Updater.php:546
|
||||
#: application/Updater.php:606
|
||||
msgid "Updates file path is not set, can't write updates."
|
||||
msgstr ""
|
||||
"Le chemin vers le fichier de mise à jour n'est pas défini, impossible "
|
||||
"d'écrire les mises à jour."
|
||||
|
||||
#: application/Updater.php:551
|
||||
#: application/Updater.php:611
|
||||
msgid "Unable to write updates in "
|
||||
msgstr "Impossible d'écrire les mises à jour dans "
|
||||
|
||||
|
@ -230,6 +250,7 @@ msgstr ""
|
|||
"Shaarli a les droits d'écriture dans le dossier dans lequel il est installé."
|
||||
|
||||
#: application/config/ConfigManager.php:135
|
||||
#: application/config/ConfigManager.php:162
|
||||
msgid "Invalid setting key parameter. String expected, got: "
|
||||
msgstr "Clé de paramétrage invalide. Chaîne de caractères obtenue, attendu : "
|
||||
|
||||
|
@ -251,135 +272,133 @@ msgstr "Vous n'êtes pas autorisé à modifier la configuration."
|
|||
msgid "Error accessing"
|
||||
msgstr "Une erreur s'est produite en accédant à"
|
||||
|
||||
#: index.php:142
|
||||
#: index.php:143
|
||||
msgid "Shared links on "
|
||||
msgstr "Liens partagés sur "
|
||||
|
||||
#: index.php:164
|
||||
#: index.php:165
|
||||
msgid "Insufficient permissions:"
|
||||
msgstr "Permissions insuffisantes :"
|
||||
|
||||
#: index.php:303
|
||||
#: index.php:201
|
||||
msgid "I said: NO. You are banned for the moment. Go away."
|
||||
msgstr "NON. Vous êtes banni pour le moment. Revenez plus tard."
|
||||
|
||||
#: index.php:368
|
||||
#: index.php:273
|
||||
msgid "Wrong login/password."
|
||||
msgstr "Nom d'utilisateur ou mot de passe incorrects."
|
||||
|
||||
#: index.php:576 tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:42
|
||||
#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:42
|
||||
#: index.php:483 tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:46
|
||||
#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:46
|
||||
msgid "Daily"
|
||||
msgstr "Quotidien"
|
||||
|
||||
#: index.php:681 tmp/loginform.b91ef64efc3688266305ea9b42e5017e.rtpl.php:28
|
||||
#: index.php:589 tmp/loginform.b91ef64efc3688266305ea9b42e5017e.rtpl.php:28
|
||||
#: tmp/loginform.b91ef64efc3688266305ea9b42e5017e.rtpl.php:44
|
||||
#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:71
|
||||
#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:95
|
||||
#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:71
|
||||
#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:95
|
||||
#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:75
|
||||
#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:99
|
||||
#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:75
|
||||
#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:99
|
||||
msgid "Login"
|
||||
msgstr "Connexion"
|
||||
|
||||
#: index.php:722 tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:39
|
||||
#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:39
|
||||
#: index.php:606 tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:41
|
||||
#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:41
|
||||
msgid "Picture wall"
|
||||
msgstr "Mur d'images"
|
||||
|
||||
#: index.php:770 tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:36
|
||||
#: index.php:683 tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:36
|
||||
#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:36
|
||||
#: tmp/tag.cloud.b91ef64efc3688266305ea9b42e5017e.rtpl.php:19
|
||||
msgid "Tag cloud"
|
||||
msgstr "Nuage de tags"
|
||||
|
||||
#: index.php:803 tmp/tag.list.b91ef64efc3688266305ea9b42e5017e.rtpl.php:19
|
||||
#: index.php:716 tmp/tag.list.b91ef64efc3688266305ea9b42e5017e.rtpl.php:19
|
||||
msgid "Tag list"
|
||||
msgstr "Liste des tags"
|
||||
|
||||
#: index.php:1028 tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:31
|
||||
#: index.php:941 tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:31
|
||||
#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:31
|
||||
msgid "Tools"
|
||||
msgstr "Outils"
|
||||
|
||||
#: index.php:1037
|
||||
#: index.php:950
|
||||
msgid "You are not supposed to change a password on an Open Shaarli."
|
||||
msgstr ""
|
||||
"Vous n'êtes pas censé modifier le mot de passe d'un Shaarli en mode ouvert."
|
||||
|
||||
#: index.php:1042 index.php:1084 index.php:1162 index.php:1193 index.php:1293
|
||||
#: index.php:955 index.php:997 index.php:1085 index.php:1116 index.php:1221
|
||||
msgid "Wrong token."
|
||||
msgstr "Jeton invalide."
|
||||
|
||||
#: index.php:1047
|
||||
#: index.php:960
|
||||
msgid "The old password is not correct."
|
||||
msgstr "L'ancien mot de passe est incorrect."
|
||||
|
||||
#: index.php:1067
|
||||
#: index.php:980
|
||||
msgid "Your password has been changed"
|
||||
msgstr "Votre mot de passe a été modifié"
|
||||
|
||||
#: index.php:1072
|
||||
#: index.php:985
|
||||
#: tmp/changepassword.b91ef64efc3688266305ea9b42e5017e.rtpl.php:13
|
||||
#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:29
|
||||
msgid "Change password"
|
||||
msgstr "Modification du mot de passe"
|
||||
|
||||
#: index.php:1121
|
||||
#: index.php:1043
|
||||
msgid "Configuration was saved."
|
||||
msgstr "La configuration a été sauvegardé."
|
||||
|
||||
#: index.php:1145 tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:24
|
||||
#: index.php:1068 tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:24
|
||||
msgid "Configure"
|
||||
msgstr "Configurer"
|
||||
|
||||
#: index.php:1156 tmp/changetag.b91ef64efc3688266305ea9b42e5017e.rtpl.php:13
|
||||
#: index.php:1079 tmp/changetag.b91ef64efc3688266305ea9b42e5017e.rtpl.php:13
|
||||
#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:36
|
||||
msgid "Manage tags"
|
||||
msgstr "Gérer les tags"
|
||||
|
||||
#: index.php:1174
|
||||
#: index.php:1097
|
||||
#, php-format
|
||||
msgid "The tag was removed from %d link."
|
||||
msgid_plural "The tag was removed from %d links."
|
||||
msgstr[0] "Le tag a été supprimé de %d lien."
|
||||
msgstr[1] "Le tag a été supprimé de %d liens."
|
||||
|
||||
#: index.php:1175
|
||||
#: index.php:1098
|
||||
#, php-format
|
||||
msgid "The tag was renamed in %d link."
|
||||
msgid_plural "The tag was renamed in %d links."
|
||||
msgstr[0] "Le tag a été renommé dans %d lien."
|
||||
msgstr[1] "Le tag a été renommé dans %d liens."
|
||||
|
||||
#: index.php:1183 tmp/addlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:13
|
||||
#: index.php:1106 tmp/addlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:13
|
||||
msgid "Shaare a new link"
|
||||
msgstr "Partager un nouveau lien"
|
||||
|
||||
#: index.php:1353 tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:14
|
||||
#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:170
|
||||
#: index.php:1281 tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:169
|
||||
msgid "Edit"
|
||||
msgstr "Modifier"
|
||||
|
||||
#: index.php:1353 index.php:1418
|
||||
#: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:16
|
||||
#: index.php:1281 index.php:1351
|
||||
#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:26
|
||||
#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:26
|
||||
msgid "Shaare"
|
||||
msgstr "Shaare"
|
||||
|
||||
#: index.php:1387
|
||||
#: index.php:1320
|
||||
msgid "Note: "
|
||||
msgstr "Note : "
|
||||
|
||||
#: index.php:1427 tmp/export.b91ef64efc3688266305ea9b42e5017e.rtpl.php:65
|
||||
#: index.php:1360 tmp/export.b91ef64efc3688266305ea9b42e5017e.rtpl.php:65
|
||||
msgid "Export"
|
||||
msgstr "Exporter"
|
||||
|
||||
#: index.php:1489 tmp/import.b91ef64efc3688266305ea9b42e5017e.rtpl.php:83
|
||||
#: index.php:1422 tmp/import.b91ef64efc3688266305ea9b42e5017e.rtpl.php:83
|
||||
msgid "Import"
|
||||
msgstr "Importer"
|
||||
|
||||
#: index.php:1499
|
||||
#: index.php:1432
|
||||
#, php-format
|
||||
msgid ""
|
||||
"The file you are trying to upload is probably bigger than what this "
|
||||
|
@ -389,16 +408,20 @@ msgstr ""
|
|||
"le serveur web peut accepter (%s). Merci de l'envoyer en parties plus "
|
||||
"légères."
|
||||
|
||||
#: index.php:1538 tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:26
|
||||
#: index.php:1471 tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:26
|
||||
#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:22
|
||||
msgid "Plugin administration"
|
||||
msgstr "Administration des extensions"
|
||||
|
||||
#: index.php:1703
|
||||
#: index.php:1523 tmp/thumbnails.b91ef64efc3688266305ea9b42e5017e.rtpl.php:14
|
||||
msgid "Thumbnails update"
|
||||
msgstr "Mise à jour des miniatures"
|
||||
|
||||
#: index.php:1695
|
||||
msgid "Search: "
|
||||
msgstr "Recherche : "
|
||||
|
||||
#: index.php:1930
|
||||
#: index.php:1735
|
||||
#, php-format
|
||||
msgid ""
|
||||
"<pre>Sessions do not seem to work correctly on your server.<br>Make sure the "
|
||||
|
@ -417,7 +440,7 @@ msgstr ""
|
|||
"cookies. Nous vous recommandons d'accéder à votre serveur depuis son adresse "
|
||||
"IP ou un <em>Fully Qualified Domain Name</em>.<br>"
|
||||
|
||||
#: index.php:1940
|
||||
#: index.php:1745
|
||||
msgid "Click to try again."
|
||||
msgstr "Cliquer ici pour réessayer."
|
||||
|
||||
|
@ -467,19 +490,19 @@ msgstr ""
|
|||
msgid "Isso server URL (without 'http://')"
|
||||
msgstr "URL du serveur Isso (sans 'http://')"
|
||||
|
||||
#: plugins/markdown/markdown.php:158
|
||||
#: plugins/markdown/markdown.php:161
|
||||
msgid "Description will be rendered with"
|
||||
msgstr "La description sera générée avec"
|
||||
|
||||
#: plugins/markdown/markdown.php:159
|
||||
#: plugins/markdown/markdown.php:162
|
||||
msgid "Markdown syntax documentation"
|
||||
msgstr "Documentation sur la syntaxe Markdown"
|
||||
|
||||
#: plugins/markdown/markdown.php:160
|
||||
#: plugins/markdown/markdown.php:163
|
||||
msgid "Markdown syntax"
|
||||
msgstr "la syntaxe Markdown"
|
||||
|
||||
#: plugins/markdown/markdown.php:339
|
||||
#: plugins/markdown/markdown.php:347
|
||||
msgid ""
|
||||
"Render shaare description with Markdown syntax.<br><strong>Warning</"
|
||||
"strong>:\n"
|
||||
|
@ -577,11 +600,11 @@ msgstr "URL de l'API Wallabag"
|
|||
msgid "Wallabag API version (1 or 2)"
|
||||
msgstr "Version de l'API Wallabag (1 ou 2)"
|
||||
|
||||
#: tests/LanguagesTest.php:188 tests/LanguagesTest.php:201
|
||||
#: tests/LanguagesTest.php:214 tests/LanguagesTest.php:227
|
||||
#: tests/languages/fr/LanguagesFrTest.php:160
|
||||
#: tests/languages/fr/LanguagesFrTest.php:173
|
||||
#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:81
|
||||
#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:81
|
||||
#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:85
|
||||
#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:85
|
||||
msgid "Search"
|
||||
msgid_plural "Search"
|
||||
msgstr[0] "Rechercher"
|
||||
|
@ -625,8 +648,8 @@ msgid "Rename"
|
|||
msgstr "Renommer"
|
||||
|
||||
#: tmp/changetag.b91ef64efc3688266305ea9b42e5017e.rtpl.php:35
|
||||
#: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:79
|
||||
#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:172
|
||||
#: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:77
|
||||
#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:171
|
||||
msgid "Delete"
|
||||
msgstr "Supprimer"
|
||||
|
||||
|
@ -736,8 +759,36 @@ msgstr ""
|
|||
msgid "API secret"
|
||||
msgstr "Clé d'API secrète"
|
||||
|
||||
#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:274
|
||||
#: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:74
|
||||
#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:277
|
||||
msgid "Enable thumbnails"
|
||||
msgstr "Activer les miniatures"
|
||||
|
||||
#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:281
|
||||
msgid "You need to enable the extension <code>php-gd</code> to use thumbnails."
|
||||
msgstr ""
|
||||
"Vous devez activer l'extension <code>php-gd</code> pour utiliser les "
|
||||
"miniatures."
|
||||
|
||||
#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:285
|
||||
#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:56
|
||||
msgid "Synchronize thumbnails"
|
||||
msgstr "Synchroniser les miniatures"
|
||||
|
||||
#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:296
|
||||
#: tmp/export.b91ef64efc3688266305ea9b42e5017e.rtpl.php:31
|
||||
msgid "All"
|
||||
msgstr "Tous"
|
||||
|
||||
#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:300
|
||||
msgid "Only common media hosts"
|
||||
msgstr "Seulement les hébergeurs de média connus"
|
||||
|
||||
#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:304
|
||||
msgid "None"
|
||||
msgstr "Aucune"
|
||||
|
||||
#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:312
|
||||
#: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:72
|
||||
#: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:139
|
||||
#: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:199
|
||||
msgid "Save"
|
||||
|
@ -763,25 +814,27 @@ msgstr "Tous les liens d'un jour sur une page."
|
|||
msgid "Next day"
|
||||
msgstr "Jour suivant"
|
||||
|
||||
#: tpl/editlink.html
|
||||
#: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:14
|
||||
msgid "Edit Shaare"
|
||||
msgstr "Modifier le Shaare"
|
||||
|
||||
#: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:14
|
||||
msgid "New Shaare"
|
||||
msgstr "Nouveau Shaare"
|
||||
|
||||
#: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:25
|
||||
#: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:23
|
||||
msgid "Created:"
|
||||
msgstr "Création :"
|
||||
|
||||
#: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:28
|
||||
#: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:26
|
||||
msgid "URL"
|
||||
msgstr "URL"
|
||||
|
||||
#: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:34
|
||||
#: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:32
|
||||
msgid "Title"
|
||||
msgstr "Titre"
|
||||
|
||||
#: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:40
|
||||
#: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:38
|
||||
#: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:42
|
||||
#: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:75
|
||||
#: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:99
|
||||
|
@ -789,17 +842,17 @@ msgstr "Titre"
|
|||
msgid "Description"
|
||||
msgstr "Description"
|
||||
|
||||
#: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:46
|
||||
#: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:44
|
||||
msgid "Tags"
|
||||
msgstr "Tags"
|
||||
|
||||
#: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:59
|
||||
#: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:57
|
||||
#: tmp/export.b91ef64efc3688266305ea9b42e5017e.rtpl.php:36
|
||||
#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:168
|
||||
#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:167
|
||||
msgid "Private"
|
||||
msgstr "Privé"
|
||||
|
||||
#: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:74
|
||||
#: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:72
|
||||
msgid "Apply Changes"
|
||||
msgstr "Appliquer"
|
||||
|
||||
|
@ -811,10 +864,6 @@ msgstr "Exporter les données"
|
|||
msgid "Selection"
|
||||
msgstr "Choisir"
|
||||
|
||||
#: tmp/export.b91ef64efc3688266305ea9b42e5017e.rtpl.php:31
|
||||
msgid "All"
|
||||
msgstr "Tous"
|
||||
|
||||
#: tmp/export.b91ef64efc3688266305ea9b42e5017e.rtpl.php:41
|
||||
msgid "Public"
|
||||
msgstr "Publics"
|
||||
|
@ -876,15 +925,15 @@ msgstr ""
|
|||
|
||||
#: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:33
|
||||
#: tmp/loginform.b91ef64efc3688266305ea9b42e5017e.rtpl.php:30
|
||||
#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:147
|
||||
#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:147
|
||||
#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:151
|
||||
#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:151
|
||||
msgid "Username"
|
||||
msgstr "Nom d'utilisateur"
|
||||
|
||||
#: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:48
|
||||
#: tmp/loginform.b91ef64efc3688266305ea9b42e5017e.rtpl.php:34
|
||||
#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:148
|
||||
#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:148
|
||||
#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:152
|
||||
#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:152
|
||||
msgid "Password"
|
||||
msgstr "Mot de passe"
|
||||
|
||||
|
@ -901,28 +950,28 @@ msgid "Install"
|
|||
msgstr "Installer"
|
||||
|
||||
#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:14
|
||||
#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:80
|
||||
#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:79
|
||||
msgid "shaare"
|
||||
msgid_plural "shaares"
|
||||
msgstr[0] "shaare"
|
||||
msgstr[1] "shaares"
|
||||
|
||||
#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:18
|
||||
#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:84
|
||||
#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:83
|
||||
msgid "private link"
|
||||
msgid_plural "private links"
|
||||
msgstr[0] "lien privé"
|
||||
msgstr[1] "liens privés"
|
||||
|
||||
#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:31
|
||||
#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:117
|
||||
#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:117
|
||||
#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:30
|
||||
#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:121
|
||||
#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:121
|
||||
msgid "Search text"
|
||||
msgstr "Recherche texte"
|
||||
|
||||
#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:38
|
||||
#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:124
|
||||
#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:124
|
||||
#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:37
|
||||
#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:128
|
||||
#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:128
|
||||
#: tmp/tag.cloud.b91ef64efc3688266305ea9b42e5017e.rtpl.php:36
|
||||
#: tmp/tag.cloud.b91ef64efc3688266305ea9b42e5017e.rtpl.php:64
|
||||
#: tmp/tag.list.b91ef64efc3688266305ea9b42e5017e.rtpl.php:36
|
||||
|
@ -930,52 +979,52 @@ msgstr "Recherche texte"
|
|||
msgid "Filter by tag"
|
||||
msgstr "Filtrer par tag"
|
||||
|
||||
#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:111
|
||||
#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:110
|
||||
msgid "Nothing found."
|
||||
msgstr "Aucun résultat."
|
||||
|
||||
#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:119
|
||||
#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:118
|
||||
#, php-format
|
||||
msgid "%s result"
|
||||
msgid_plural "%s results"
|
||||
msgstr[0] "%s résultat"
|
||||
msgstr[1] "%s résultats"
|
||||
|
||||
#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:123
|
||||
#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:122
|
||||
msgid "for"
|
||||
msgstr "pour"
|
||||
|
||||
#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:130
|
||||
#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:129
|
||||
msgid "tagged"
|
||||
msgstr "taggé"
|
||||
|
||||
#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:134
|
||||
#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:133
|
||||
msgid "Remove tag"
|
||||
msgstr "Retirer le tag"
|
||||
|
||||
#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:143
|
||||
#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:142
|
||||
msgid "with status"
|
||||
msgstr "avec le statut"
|
||||
|
||||
#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:154
|
||||
#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:153
|
||||
msgid "without any tag"
|
||||
msgstr "sans tag"
|
||||
|
||||
#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:174
|
||||
#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:173
|
||||
#: tmp/page.footer.b91ef64efc3688266305ea9b42e5017e.rtpl.php:42
|
||||
#: tmp/page.footer.cedf684561d925457130839629000a81.rtpl.php:42
|
||||
msgid "Fold"
|
||||
msgstr "Replier"
|
||||
|
||||
#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:176
|
||||
#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:175
|
||||
msgid "Edited: "
|
||||
msgstr "Modifié : "
|
||||
|
||||
#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:180
|
||||
#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:179
|
||||
msgid "permalink"
|
||||
msgstr "permalien"
|
||||
|
||||
#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:182
|
||||
#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:181
|
||||
msgid "Add tag"
|
||||
msgstr "Ajouter un tag"
|
||||
|
||||
|
@ -1021,8 +1070,8 @@ msgstr ""
|
|||
"réessayer plus tard."
|
||||
|
||||
#: tmp/loginform.b91ef64efc3688266305ea9b42e5017e.rtpl.php:41
|
||||
#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:151
|
||||
#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:151
|
||||
#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:155
|
||||
#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:155
|
||||
msgid "Remember me"
|
||||
msgstr "Rester connecté"
|
||||
|
||||
|
@ -1053,35 +1102,52 @@ msgstr "Déplier tout"
|
|||
msgid "Are you sure you want to delete this link?"
|
||||
msgstr "Êtes-vous sûr de vouloir supprimer ce lien ?"
|
||||
|
||||
#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:61
|
||||
#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:86
|
||||
#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:61
|
||||
#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:86
|
||||
#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:65
|
||||
#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:90
|
||||
#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:65
|
||||
#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:90
|
||||
msgid "RSS Feed"
|
||||
msgstr "Flux RSS"
|
||||
|
||||
#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:66
|
||||
#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:102
|
||||
#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:66
|
||||
#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:102
|
||||
#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:70
|
||||
#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:106
|
||||
#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:70
|
||||
#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:106
|
||||
msgid "Logout"
|
||||
msgstr "Déconnexion"
|
||||
|
||||
#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:169
|
||||
#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:169
|
||||
#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:173
|
||||
#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:173
|
||||
msgid "is available"
|
||||
msgstr "est disponible"
|
||||
|
||||
#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:176
|
||||
#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:176
|
||||
#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:180
|
||||
#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:180
|
||||
msgid "Error"
|
||||
msgstr "Erreur"
|
||||
|
||||
#: tmp/picwall.b91ef64efc3688266305ea9b42e5017e.rtpl.php:16
|
||||
#: tmp/picwall.b91ef64efc3688266305ea9b42e5017e.rtpl.php:14
|
||||
msgid "Picture wall unavailable (thumbnails are disabled)."
|
||||
msgstr ""
|
||||
"Le mur d'images n'est pas disponible (les miniatures sont désactivées)."
|
||||
|
||||
#: tmp/picwall.b91ef64efc3688266305ea9b42e5017e.rtpl.php:24
|
||||
#, fuzzy
|
||||
#| msgid ""
|
||||
#| "You don't have any cached thumbnail. Try to <a href=\"?do=thumbs_update"
|
||||
#| "\">synchronize them</a>."
|
||||
msgid ""
|
||||
"There is no cached thumbnail. Try to <a href=\"?do=thumbs_update"
|
||||
"\">synchronize them</a>."
|
||||
msgstr ""
|
||||
"Il n'y a aucune miniature en cache. Essayer de <a href=\"?do=thumbs_update"
|
||||
"\">les synchroniser</a>."
|
||||
|
||||
#: tmp/picwall.b91ef64efc3688266305ea9b42e5017e.rtpl.php:36
|
||||
msgid "Picture Wall"
|
||||
msgstr "Mur d'images"
|
||||
|
||||
#: tmp/picwall.b91ef64efc3688266305ea9b42e5017e.rtpl.php:16
|
||||
#: tmp/picwall.b91ef64efc3688266305ea9b42e5017e.rtpl.php:36
|
||||
msgid "pics"
|
||||
msgstr "images"
|
||||
|
||||
|
@ -1223,7 +1289,11 @@ msgstr ""
|
|||
msgid "Export database"
|
||||
msgstr "Exporter les données"
|
||||
|
||||
#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:71
|
||||
#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:55
|
||||
msgid "Synchronize all link thumbnails"
|
||||
msgstr "Synchroniser toutes les miniatures"
|
||||
|
||||
#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:81
|
||||
msgid ""
|
||||
"Drag one of these button to your bookmarks toolbar or right-click it and "
|
||||
"\"Bookmark This Link\""
|
||||
|
@ -1231,13 +1301,13 @@ msgstr ""
|
|||
"Glisser un de ces bouttons dans votre barre de favoris ou cliquer droit "
|
||||
"dessus et « Ajouter aux favoris »"
|
||||
|
||||
#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:72
|
||||
#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:82
|
||||
msgid "then click on the bookmarklet in any page you want to share."
|
||||
msgstr ""
|
||||
"puis cliquer sur le marque page depuis un site que vous souhaitez partager."
|
||||
|
||||
#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:76
|
||||
#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:100
|
||||
#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:86
|
||||
#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:110
|
||||
msgid ""
|
||||
"Drag this link to your bookmarks toolbar or right-click it and Bookmark This "
|
||||
"Link"
|
||||
|
@ -1245,31 +1315,31 @@ msgstr ""
|
|||
"Glisser ce lien dans votre barre de favoris ou cliquer droit dessus et « "
|
||||
"Ajouter aux favoris »"
|
||||
|
||||
#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:77
|
||||
#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:87
|
||||
msgid "then click ✚Shaare link button in any page you want to share"
|
||||
msgstr "puis cliquer sur ✚Shaare depuis un site que vous souhaitez partager"
|
||||
|
||||
#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:86
|
||||
#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:108
|
||||
#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:96
|
||||
#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:118
|
||||
msgid "The selected text is too long, it will be truncated."
|
||||
msgstr "Le texte sélectionné est trop long, il sera tronqué."
|
||||
|
||||
#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:96
|
||||
#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:106
|
||||
msgid "Shaare link"
|
||||
msgstr "Shaare"
|
||||
|
||||
#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:101
|
||||
#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:111
|
||||
msgid ""
|
||||
"Then click ✚Add Note button anytime to start composing a private Note (text "
|
||||
"post) to your Shaarli"
|
||||
msgstr ""
|
||||
"Puis cliquer sur ✚Add Note pour commencer à rédiger une Note sur Shaarli"
|
||||
|
||||
#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:117
|
||||
#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:127
|
||||
msgid "Add Note"
|
||||
msgstr "Ajouter une Note"
|
||||
|
||||
#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:129
|
||||
#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:139
|
||||
msgid ""
|
||||
"You need to browse your Shaarli over <strong>HTTPS</strong> to use this "
|
||||
"functionality."
|
||||
|
@ -1277,25 +1347,25 @@ msgstr ""
|
|||
"Vous devez utiliser Shaarli en <strong>HTTPS</strong> pour utiliser cette "
|
||||
"fonctionalité."
|
||||
|
||||
#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:134
|
||||
#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:144
|
||||
msgid "Add to"
|
||||
msgstr "Ajouter à"
|
||||
|
||||
#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:145
|
||||
#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:155
|
||||
msgid "3rd party"
|
||||
msgstr "Applications tierces"
|
||||
|
||||
#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:147
|
||||
#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:153
|
||||
#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:157
|
||||
#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:163
|
||||
msgid "Plugin"
|
||||
msgstr "Extension"
|
||||
|
||||
#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:148
|
||||
#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:154
|
||||
#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:158
|
||||
#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:164
|
||||
msgid "plugin"
|
||||
msgstr "extension"
|
||||
|
||||
#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:175
|
||||
#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:191
|
||||
msgid ""
|
||||
"Drag this link to your bookmarks toolbar, or right-click it and choose "
|
||||
"Bookmark This Link"
|
||||
|
@ -1303,6 +1373,26 @@ msgstr ""
|
|||
"Glisser ce lien dans votre barre de favoris ou cliquer droit dessus et « "
|
||||
"Ajouter aux favoris »"
|
||||
|
||||
#, fuzzy
|
||||
#~| msgid "Enable thumbnails"
|
||||
#~ msgid "Synchonize thumbnails"
|
||||
#~ msgstr "Activer les miniatures"
|
||||
|
||||
#~ msgid "Warning: "
|
||||
#~ msgstr "Attention : "
|
||||
|
||||
#~ msgid ""
|
||||
#~ "It's recommended to visit the picture wall after enabling this feature."
|
||||
#~ msgstr ""
|
||||
#~ "Il est recommandé de visiter le Mur d'images après avoir activé cette "
|
||||
#~ "fonctionnalité."
|
||||
|
||||
#~ msgid ""
|
||||
#~ "If you have a large database, the first retrieval may take a few minutes."
|
||||
#~ msgstr ""
|
||||
#~ "Si vous avez beaucoup de liens, la première récupération peut prendre "
|
||||
#~ "plusieurs minutes."
|
||||
|
||||
#, fuzzy
|
||||
#~| msgid "Change"
|
||||
#~ msgid "range"
|
||||
|
|
13
inc/web-thumbnailer.json
Normal file
13
inc/web-thumbnailer.json
Normal file
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"settings": {
|
||||
"default": {
|
||||
"download_mode": "DOWNLOAD",
|
||||
"_comment": "infinite cache",
|
||||
"cache_duration": -1,
|
||||
"timeout": 10
|
||||
},
|
||||
"path": {
|
||||
"cache": "cache/"
|
||||
}
|
||||
}
|
||||
}
|
527
index.php
527
index.php
|
@ -75,11 +75,12 @@
|
|||
require_once 'application/PluginManager.php';
|
||||
require_once 'application/Router.php';
|
||||
require_once 'application/Updater.php';
|
||||
use \Shaarli\Languages;
|
||||
use \Shaarli\ThemeUtils;
|
||||
use \Shaarli\Config\ConfigManager;
|
||||
use \Shaarli\Languages;
|
||||
use \Shaarli\Security\LoginManager;
|
||||
use \Shaarli\Security\SessionManager;
|
||||
use \Shaarli\ThemeUtils;
|
||||
use \Shaarli\Thumbnailer;
|
||||
|
||||
// Ensure the PHP version is supported
|
||||
try {
|
||||
|
@ -513,7 +514,8 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
|
|||
read_updates_file($conf->get('resource.updates')),
|
||||
$LINKSDB,
|
||||
$conf,
|
||||
$loginManager->isLoggedIn()
|
||||
$loginManager->isLoggedIn(),
|
||||
$_SESSION
|
||||
);
|
||||
try {
|
||||
$newUpdates = $updater->update();
|
||||
|
@ -528,7 +530,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
|
|||
die($e->getMessage());
|
||||
}
|
||||
|
||||
$PAGE = new PageBuilder($conf, $LINKSDB, $sessionManager->generateToken(), $loginManager->isLoggedIn());
|
||||
$PAGE = new PageBuilder($conf, $_SESSION, $LINKSDB, $sessionManager->generateToken(), $loginManager->isLoggedIn());
|
||||
$PAGE->assign('linkcount', count($LINKSDB));
|
||||
$PAGE->assign('privateLinkcount', count_private($LINKSDB));
|
||||
$PAGE->assign('plugin_errors', $pluginManager->getErrors());
|
||||
|
@ -601,19 +603,23 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
|
|||
// -------- Picture wall
|
||||
if ($targetPage == Router::$PAGE_PICWALL)
|
||||
{
|
||||
$PAGE->assign('pagetitle', t('Picture wall') .' - '. $conf->get('general.title', 'Shaarli'));
|
||||
if (! $conf->get('thumbnails.mode', Thumbnailer::MODE_NONE) === Thumbnailer::MODE_NONE) {
|
||||
$PAGE->assign('linksToDisplay', []);
|
||||
$PAGE->renderPage('picwall');
|
||||
exit;
|
||||
}
|
||||
|
||||
// Optionally filter the results:
|
||||
$links = $LINKSDB->filterSearch($_GET);
|
||||
$linksToDisplay = array();
|
||||
|
||||
// Get only links which have a thumbnail.
|
||||
foreach($links as $link)
|
||||
// Note: we do not retrieve thumbnails here, the request is too heavy.
|
||||
foreach($links as $key => $link)
|
||||
{
|
||||
$permalink='?'.$link['shorturl'];
|
||||
$thumb=lazyThumbnail($conf, $link['url'],$permalink);
|
||||
if ($thumb!='') // Only output links which have a thumbnail.
|
||||
{
|
||||
$link['thumbnail']=$thumb; // Thumbnail HTML code.
|
||||
$linksToDisplay[]=$link; // Add to array.
|
||||
if (isset($link['thumbnail']) && $link['thumbnail'] !== false) {
|
||||
$linksToDisplay[] = $link; // Add to array.
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -626,7 +632,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
|
|||
$PAGE->assign($key, $value);
|
||||
}
|
||||
|
||||
$PAGE->assign('pagetitle', t('Picture wall') .' - '. $conf->get('general.title', 'Shaarli'));
|
||||
|
||||
$PAGE->renderPage('picwall');
|
||||
exit;
|
||||
}
|
||||
|
@ -1009,6 +1015,16 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
|
|||
$conf->set('api.secret', escape($_POST['apiSecret']));
|
||||
$conf->set('translation.language', escape($_POST['language']));
|
||||
|
||||
$thumbnailsMode = extension_loaded('gd') ? $_POST['enableThumbnails'] : Thumbnailer::MODE_NONE;
|
||||
if ($thumbnailsMode !== Thumbnailer::MODE_NONE
|
||||
&& $thumbnailsMode !== $conf->get('thumbnails.mode', Thumbnailer::MODE_NONE)
|
||||
) {
|
||||
$_SESSION['warnings'][] = t(
|
||||
'You have enabled or changed thumbnails mode. <a href="?do=thumbs_update">Please synchronize them</a>.'
|
||||
);
|
||||
}
|
||||
$conf->set('thumbnails.mode', $thumbnailsMode);
|
||||
|
||||
try {
|
||||
$conf->write($loginManager->isLoggedIn());
|
||||
$history->updateSettings();
|
||||
|
@ -1047,6 +1063,8 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
|
|||
$PAGE->assign('api_secret', $conf->get('api.secret'));
|
||||
$PAGE->assign('languages', Languages::getAvailableLanguages());
|
||||
$PAGE->assign('language', $conf->get('translation.language'));
|
||||
$PAGE->assign('gd_enabled', extension_loaded('gd'));
|
||||
$PAGE->assign('thumbnails_mode', $conf->get('thumbnails.mode', Thumbnailer::MODE_NONE));
|
||||
$PAGE->assign('pagetitle', t('Configure') .' - '. $conf->get('general.title', 'Shaarli'));
|
||||
$PAGE->renderPage('configure');
|
||||
exit;
|
||||
|
@ -1148,6 +1166,11 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
|
|||
$link['title'] = $link['url'];
|
||||
}
|
||||
|
||||
if ($conf->get('thumbnails.mode', Thumbnailer::MODE_NONE) !== Thumbnailer::MODE_NONE) {
|
||||
$thumbnailer = new Thumbnailer($conf);
|
||||
$link['thumbnail'] = $thumbnailer->get($url);
|
||||
}
|
||||
|
||||
$pluginManager->executeHooks('save_link', $link);
|
||||
|
||||
$LINKSDB[$id] = $link;
|
||||
|
@ -1486,6 +1509,43 @@ function($a, $b) { return $a['order'] - $b['order']; }
|
|||
exit;
|
||||
}
|
||||
|
||||
// -------- Thumbnails Update
|
||||
if ($targetPage == Router::$PAGE_THUMBS_UPDATE) {
|
||||
$ids = [];
|
||||
foreach ($LINKSDB as $link) {
|
||||
// A note or not HTTP(S)
|
||||
if ($link['url'][0] === '?' || ! startsWith(strtolower($link['url']), 'http')) {
|
||||
continue;
|
||||
}
|
||||
$ids[] = $link['id'];
|
||||
}
|
||||
$PAGE->assign('ids', $ids);
|
||||
$PAGE->assign('pagetitle', t('Thumbnails update') .' - '. $conf->get('general.title', 'Shaarli'));
|
||||
$PAGE->renderPage('thumbnails');
|
||||
exit;
|
||||
}
|
||||
|
||||
// -------- Single Thumbnail Update
|
||||
if ($targetPage == Router::$AJAX_THUMB_UPDATE) {
|
||||
if (! isset($_POST['id']) || ! ctype_digit($_POST['id'])) {
|
||||
http_response_code(400);
|
||||
exit;
|
||||
}
|
||||
$id = (int) $_POST['id'];
|
||||
if (empty($LINKSDB[$id])) {
|
||||
http_response_code(404);
|
||||
exit;
|
||||
}
|
||||
$thumbnailer = new Thumbnailer($conf);
|
||||
$link = $LINKSDB[$id];
|
||||
$link['thumbnail'] = $thumbnailer->get($link['url']);
|
||||
$LINKSDB[$id] = $link;
|
||||
$LINKSDB->save($conf->get('resource.page_cache'));
|
||||
|
||||
echo json_encode($link);
|
||||
exit;
|
||||
}
|
||||
|
||||
// -------- Otherwise, simply display search form and links:
|
||||
showLinkList($PAGE, $LINKSDB, $conf, $pluginManager, $loginManager);
|
||||
exit;
|
||||
|
@ -1549,6 +1609,12 @@ function buildLinkList($PAGE, $LINKSDB, $conf, $pluginManager, $loginManager)
|
|||
// Start index.
|
||||
$i = ($page-1) * $_SESSION['LINKS_PER_PAGE'];
|
||||
$end = $i + $_SESSION['LINKS_PER_PAGE'];
|
||||
|
||||
$thumbnailsEnabled = $conf->get('thumbnails.mode', Thumbnailer::MODE_NONE) !== Thumbnailer::MODE_NONE;
|
||||
if ($thumbnailsEnabled) {
|
||||
$thumbnailer = new Thumbnailer($conf);
|
||||
}
|
||||
|
||||
$linkDisp = array();
|
||||
while ($i<$end && $i<count($keys))
|
||||
{
|
||||
|
@ -1569,9 +1635,21 @@ function buildLinkList($PAGE, $LINKSDB, $conf, $pluginManager, $loginManager)
|
|||
$taglist = preg_split('/\s+/', $link['tags'], -1, PREG_SPLIT_NO_EMPTY);
|
||||
uasort($taglist, 'strcasecmp');
|
||||
$link['taglist'] = $taglist;
|
||||
|
||||
// Thumbnails enabled, not a note,
|
||||
// and (never retrieved yet or no valid cache file)
|
||||
if ($thumbnailsEnabled && $link['url'][0] != '?'
|
||||
&& (! isset($link['thumbnail']) || ($link['thumbnail'] !== false && ! is_file($link['thumbnail'])))
|
||||
) {
|
||||
$elem = $LINKSDB[$keys[$i]];
|
||||
$elem['thumbnail'] = $thumbnailer->get($link['url']);
|
||||
$LINKSDB[$keys[$i]] = $elem;
|
||||
$updateDB = true;
|
||||
$link['thumbnail'] = $elem['thumbnail'];
|
||||
}
|
||||
|
||||
// Check for both signs of a note: starting with ? and 7 chars long.
|
||||
if ($link['url'][0] === '?' &&
|
||||
strlen($link['url']) === 7) {
|
||||
if ($link['url'][0] === '?' && strlen($link['url']) === 7) {
|
||||
$link['url'] = index_url($_SERVER) . $link['url'];
|
||||
}
|
||||
|
||||
|
@ -1579,6 +1657,11 @@ function buildLinkList($PAGE, $LINKSDB, $conf, $pluginManager, $loginManager)
|
|||
$i++;
|
||||
}
|
||||
|
||||
// If we retrieved new thumbnails, we update the database.
|
||||
if (!empty($updateDB)) {
|
||||
$LINKSDB->save($conf->get('resource.page_cache'));
|
||||
}
|
||||
|
||||
// Compute paging navigation
|
||||
$searchtagsUrl = $searchtags === '' ? '' : '&searchtags=' . urlencode($searchtags);
|
||||
$searchtermUrl = empty($searchterm) ? '' : '&searchterm=' . urlencode($searchterm);
|
||||
|
@ -1629,194 +1712,6 @@ function buildLinkList($PAGE, $LINKSDB, $conf, $pluginManager, $loginManager)
|
|||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the thumbnail for a link.
|
||||
*
|
||||
* With a link to the original URL.
|
||||
* Understands various services (youtube.com...)
|
||||
* Input: $url = URL for which the thumbnail must be found.
|
||||
* $href = if provided, this URL will be followed instead of $url
|
||||
* Returns an associative array with thumbnail attributes (src,href,width,height,style,alt)
|
||||
* Some of them may be missing.
|
||||
* Return an empty array if no thumbnail available.
|
||||
*
|
||||
* @param ConfigManager $conf Configuration Manager instance.
|
||||
* @param string $url
|
||||
* @param string|bool $href
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function computeThumbnail($conf, $url, $href = false)
|
||||
{
|
||||
if (!$conf->get('thumbnail.enable_thumbnails')) return array();
|
||||
if ($href==false) $href=$url;
|
||||
|
||||
// For most hosts, the URL of the thumbnail can be easily deduced from the URL of the link.
|
||||
// (e.g. http://www.youtube.com/watch?v=spVypYk4kto ---> http://img.youtube.com/vi/spVypYk4kto/default.jpg )
|
||||
// ^^^^^^^^^^^ ^^^^^^^^^^^
|
||||
$domain = parse_url($url,PHP_URL_HOST);
|
||||
if ($domain=='youtube.com' || $domain=='www.youtube.com')
|
||||
{
|
||||
parse_str(parse_url($url,PHP_URL_QUERY), $params); // Extract video ID and get thumbnail
|
||||
if (!empty($params['v'])) return array('src'=>'https://img.youtube.com/vi/'.$params['v'].'/default.jpg',
|
||||
'href'=>$href,'width'=>'120','height'=>'90','alt'=>'YouTube thumbnail');
|
||||
}
|
||||
if ($domain=='youtu.be') // Youtube short links
|
||||
{
|
||||
$path = parse_url($url,PHP_URL_PATH);
|
||||
return array('src'=>'https://img.youtube.com/vi'.$path.'/default.jpg',
|
||||
'href'=>$href,'width'=>'120','height'=>'90','alt'=>'YouTube thumbnail');
|
||||
}
|
||||
if ($domain=='pix.toile-libre.org') // pix.toile-libre.org image hosting
|
||||
{
|
||||
parse_str(parse_url($url,PHP_URL_QUERY), $params); // Extract image filename.
|
||||
if (!empty($params) && !empty($params['img'])) return array('src'=>'http://pix.toile-libre.org/upload/thumb/'.urlencode($params['img']),
|
||||
'href'=>$href,'style'=>'max-width:120px; max-height:150px','alt'=>'pix.toile-libre.org thumbnail');
|
||||
}
|
||||
|
||||
if ($domain=='imgur.com')
|
||||
{
|
||||
$path = parse_url($url,PHP_URL_PATH);
|
||||
if (startsWith($path,'/a/')) return array(); // Thumbnails for albums are not available.
|
||||
if (startsWith($path,'/r/')) return array('src'=>'https://i.imgur.com/'.basename($path).'s.jpg',
|
||||
'href'=>$href,'width'=>'90','height'=>'90','alt'=>'imgur.com thumbnail');
|
||||
if (startsWith($path,'/gallery/')) return array('src'=>'https://i.imgur.com'.substr($path,8).'s.jpg',
|
||||
'href'=>$href,'width'=>'90','height'=>'90','alt'=>'imgur.com thumbnail');
|
||||
|
||||
if (substr_count($path,'/')==1) return array('src'=>'https://i.imgur.com/'.substr($path,1).'s.jpg',
|
||||
'href'=>$href,'width'=>'90','height'=>'90','alt'=>'imgur.com thumbnail');
|
||||
}
|
||||
if ($domain=='i.imgur.com')
|
||||
{
|
||||
$pi = pathinfo(parse_url($url,PHP_URL_PATH));
|
||||
if (!empty($pi['filename'])) return array('src'=>'https://i.imgur.com/'.$pi['filename'].'s.jpg',
|
||||
'href'=>$href,'width'=>'90','height'=>'90','alt'=>'imgur.com thumbnail');
|
||||
}
|
||||
if ($domain=='dailymotion.com' || $domain=='www.dailymotion.com')
|
||||
{
|
||||
if (strpos($url,'dailymotion.com/video/')!==false)
|
||||
{
|
||||
$thumburl=str_replace('dailymotion.com/video/','dailymotion.com/thumbnail/video/',$url);
|
||||
return array('src'=>$thumburl,
|
||||
'href'=>$href,'width'=>'120','style'=>'height:auto;','alt'=>'DailyMotion thumbnail');
|
||||
}
|
||||
}
|
||||
if (endsWith($domain,'.imageshack.us'))
|
||||
{
|
||||
$ext=strtolower(pathinfo($url,PATHINFO_EXTENSION));
|
||||
if ($ext=='jpg' || $ext=='jpeg' || $ext=='png' || $ext=='gif')
|
||||
{
|
||||
$thumburl = substr($url,0,strlen($url)-strlen($ext)).'th.'.$ext;
|
||||
return array('src'=>$thumburl,
|
||||
'href'=>$href,'width'=>'120','style'=>'height:auto;','alt'=>'imageshack.us thumbnail');
|
||||
}
|
||||
}
|
||||
|
||||
// Some other hosts are SLOW AS HELL and usually require an extra HTTP request to get the thumbnail URL.
|
||||
// So we deport the thumbnail generation in order not to slow down page generation
|
||||
// (and we also cache the thumbnail)
|
||||
|
||||
if (! $conf->get('thumbnail.enable_localcache')) return array(); // If local cache is disabled, no thumbnails for services which require the use a local cache.
|
||||
|
||||
if ($domain=='flickr.com' || endsWith($domain,'.flickr.com')
|
||||
|| $domain=='vimeo.com'
|
||||
|| $domain=='ted.com' || endsWith($domain,'.ted.com')
|
||||
|| $domain=='xkcd.com' || endsWith($domain,'.xkcd.com')
|
||||
)
|
||||
{
|
||||
if ($domain=='vimeo.com')
|
||||
{ // Make sure this vimeo URL points to a video (/xxx... where xxx is numeric)
|
||||
$path = parse_url($url,PHP_URL_PATH);
|
||||
if (!preg_match('!/\d+.+?!',$path)) return array(); // This is not a single video URL.
|
||||
}
|
||||
if ($domain=='xkcd.com' || endsWith($domain,'.xkcd.com'))
|
||||
{ // Make sure this URL points to a single comic (/xxx... where xxx is numeric)
|
||||
$path = parse_url($url,PHP_URL_PATH);
|
||||
if (!preg_match('!/\d+.+?!',$path)) return array();
|
||||
}
|
||||
if ($domain=='ted.com' || endsWith($domain,'.ted.com'))
|
||||
{ // Make sure this TED URL points to a video (/talks/...)
|
||||
$path = parse_url($url,PHP_URL_PATH);
|
||||
if ("/talks/" !== substr($path,0,7)) return array(); // This is not a single video URL.
|
||||
}
|
||||
$sign = hash_hmac('sha256', $url, $conf->get('credentials.salt')); // We use the salt to sign data (it's random, secret, and specific to each installation)
|
||||
return array('src'=>index_url($_SERVER).'?do=genthumbnail&hmac='.$sign.'&url='.urlencode($url),
|
||||
'href'=>$href,'width'=>'120','style'=>'height:auto;','alt'=>'thumbnail');
|
||||
}
|
||||
|
||||
// For all other, we try to make a thumbnail of links ending with .jpg/jpeg/png/gif
|
||||
// Technically speaking, we should download ALL links and check their Content-Type to see if they are images.
|
||||
// But using the extension will do.
|
||||
$ext=strtolower(pathinfo($url,PATHINFO_EXTENSION));
|
||||
if ($ext=='jpg' || $ext=='jpeg' || $ext=='png' || $ext=='gif')
|
||||
{
|
||||
$sign = hash_hmac('sha256', $url, $conf->get('credentials.salt')); // We use the salt to sign data (it's random, secret, and specific to each installation)
|
||||
return array('src'=>index_url($_SERVER).'?do=genthumbnail&hmac='.$sign.'&url='.urlencode($url),
|
||||
'href'=>$href,'width'=>'120','style'=>'height:auto;','alt'=>'thumbnail');
|
||||
}
|
||||
return array(); // No thumbnail.
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Returns the HTML code to display a thumbnail for a link
|
||||
// with a link to the original URL.
|
||||
// Understands various services (youtube.com...)
|
||||
// Input: $url = URL for which the thumbnail must be found.
|
||||
// $href = if provided, this URL will be followed instead of $url
|
||||
// Returns '' if no thumbnail available.
|
||||
function thumbnail($url,$href=false)
|
||||
{
|
||||
// FIXME!
|
||||
global $conf;
|
||||
$t = computeThumbnail($conf, $url,$href);
|
||||
if (count($t)==0) return ''; // Empty array = no thumbnail for this URL.
|
||||
|
||||
$html='<a href="'.escape($t['href']).'"><img src="'.escape($t['src']).'"';
|
||||
if (!empty($t['width'])) $html.=' width="'.escape($t['width']).'"';
|
||||
if (!empty($t['height'])) $html.=' height="'.escape($t['height']).'"';
|
||||
if (!empty($t['style'])) $html.=' style="'.escape($t['style']).'"';
|
||||
if (!empty($t['alt'])) $html.=' alt="'.escape($t['alt']).'"';
|
||||
$html.='></a>';
|
||||
return $html;
|
||||
}
|
||||
|
||||
// Returns the HTML code to display a thumbnail for a link
|
||||
// for the picture wall (using lazy image loading)
|
||||
// Understands various services (youtube.com...)
|
||||
// Input: $url = URL for which the thumbnail must be found.
|
||||
// $href = if provided, this URL will be followed instead of $url
|
||||
// Returns '' if no thumbnail available.
|
||||
function lazyThumbnail($conf, $url,$href=false)
|
||||
{
|
||||
// FIXME!
|
||||
global $conf;
|
||||
$t = computeThumbnail($conf, $url,$href);
|
||||
if (count($t)==0) return ''; // Empty array = no thumbnail for this URL.
|
||||
|
||||
$html='<a href="'.escape($t['href']).'">';
|
||||
|
||||
// Lazy image
|
||||
$html.='<img class="b-lazy" src="#" data-src="'.escape($t['src']).'"';
|
||||
|
||||
if (!empty($t['width'])) $html.=' width="'.escape($t['width']).'"';
|
||||
if (!empty($t['height'])) $html.=' height="'.escape($t['height']).'"';
|
||||
if (!empty($t['style'])) $html.=' style="'.escape($t['style']).'"';
|
||||
if (!empty($t['alt'])) $html.=' alt="'.escape($t['alt']).'"';
|
||||
$html.='>';
|
||||
|
||||
// No-JavaScript fallback.
|
||||
$html.='<noscript><img src="'.escape($t['src']).'"';
|
||||
if (!empty($t['width'])) $html.=' width="'.escape($t['width']).'"';
|
||||
if (!empty($t['height'])) $html.=' height="'.escape($t['height']).'"';
|
||||
if (!empty($t['style'])) $html.=' style="'.escape($t['style']).'"';
|
||||
if (!empty($t['alt'])) $html.=' alt="'.escape($t['alt']).'"';
|
||||
$html.='></noscript></a>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Installation
|
||||
* This function should NEVER be called if the file data/config.php exists.
|
||||
|
@ -1908,7 +1803,7 @@ function install($conf, $sessionManager, $loginManager) {
|
|||
exit;
|
||||
}
|
||||
|
||||
$PAGE = new PageBuilder($conf, null, $sessionManager->generateToken());
|
||||
$PAGE = new PageBuilder($conf, $_SESSION, null, $sessionManager->generateToken());
|
||||
list($continents, $cities) = generateTimeZoneData(timezone_identifiers_list(), date_default_timezone_get());
|
||||
$PAGE->assign('continents', $continents);
|
||||
$PAGE->assign('cities', $cities);
|
||||
|
@ -1917,232 +1812,6 @@ function install($conf, $sessionManager, $loginManager) {
|
|||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Because some f*cking services like flickr require an extra HTTP request to get the thumbnail URL,
|
||||
* I have deported the thumbnail URL code generation here, otherwise this would slow down page generation.
|
||||
* The following function takes the URL a link (e.g. a flickr page) and return the proper thumbnail.
|
||||
* This function is called by passing the URL:
|
||||
* http://mywebsite.com/shaarli/?do=genthumbnail&hmac=[HMAC]&url=[URL]
|
||||
* [URL] is the URL of the link (e.g. a flickr page)
|
||||
* [HMAC] is the signature for the [URL] (so that these URL cannot be forged).
|
||||
* The function below will fetch the image from the webservice and store it in the cache.
|
||||
*
|
||||
* @param ConfigManager $conf Configuration Manager instance,
|
||||
*/
|
||||
function genThumbnail($conf)
|
||||
{
|
||||
// Make sure the parameters in the URL were generated by us.
|
||||
$sign = hash_hmac('sha256', $_GET['url'], $conf->get('credentials.salt'));
|
||||
if ($sign!=$_GET['hmac']) die('Naughty boy!');
|
||||
|
||||
$cacheDir = $conf->get('resource.thumbnails_cache', 'cache');
|
||||
// Let's see if we don't already have the image for this URL in the cache.
|
||||
$thumbname=hash('sha1',$_GET['url']).'.jpg';
|
||||
if (is_file($cacheDir .'/'. $thumbname))
|
||||
{ // We have the thumbnail, just serve it:
|
||||
header('Content-Type: image/jpeg');
|
||||
echo file_get_contents($cacheDir .'/'. $thumbname);
|
||||
return;
|
||||
}
|
||||
// We may also serve a blank image (if service did not respond)
|
||||
$blankname=hash('sha1',$_GET['url']).'.gif';
|
||||
if (is_file($cacheDir .'/'. $blankname))
|
||||
{
|
||||
header('Content-Type: image/gif');
|
||||
echo file_get_contents($cacheDir .'/'. $blankname);
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, generate the thumbnail.
|
||||
$url = $_GET['url'];
|
||||
$domain = parse_url($url,PHP_URL_HOST);
|
||||
|
||||
if ($domain=='flickr.com' || endsWith($domain,'.flickr.com'))
|
||||
{
|
||||
// Crude replacement to handle new flickr domain policy (They prefer www. now)
|
||||
$url = str_replace('http://flickr.com/','http://www.flickr.com/',$url);
|
||||
|
||||
// Is this a link to an image, or to a flickr page ?
|
||||
$imageurl='';
|
||||
if (endsWith(parse_url($url, PHP_URL_PATH), '.jpg'))
|
||||
{ // This is a direct link to an image. e.g. http://farm1.staticflickr.com/5/5921913_ac83ed27bd_o.jpg
|
||||
preg_match('!(http://farm\d+\.staticflickr\.com/\d+/\d+_\w+_)\w.jpg!',$url,$matches);
|
||||
if (!empty($matches[1])) $imageurl=$matches[1].'m.jpg';
|
||||
}
|
||||
else // This is a flickr page (html)
|
||||
{
|
||||
// Get the flickr html page.
|
||||
list($headers, $content) = get_http_response($url, 20);
|
||||
if (strpos($headers[0], '200 OK') !== false)
|
||||
{
|
||||
// flickr now nicely provides the URL of the thumbnail in each flickr page.
|
||||
preg_match('!<link rel=\"image_src\" href=\"(.+?)\"!', $content, $matches);
|
||||
if (!empty($matches[1])) $imageurl=$matches[1];
|
||||
|
||||
// In albums (and some other pages), the link rel="image_src" is not provided,
|
||||
// but flickr provides:
|
||||
// <meta property="og:image" content="http://farm4.staticflickr.com/3398/3239339068_25d13535ff_z.jpg" />
|
||||
if ($imageurl=='')
|
||||
{
|
||||
preg_match('!<meta property=\"og:image\" content=\"(.+?)\"!', $content, $matches);
|
||||
if (!empty($matches[1])) $imageurl=$matches[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($imageurl!='')
|
||||
{ // Let's download the image.
|
||||
// Image is 240x120, so 10 seconds to download should be enough.
|
||||
list($headers, $content) = get_http_response($imageurl, 10);
|
||||
if (strpos($headers[0], '200 OK') !== false) {
|
||||
// Save image to cache.
|
||||
file_put_contents($cacheDir .'/'. $thumbname, $content);
|
||||
header('Content-Type: image/jpeg');
|
||||
echo $content;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
elseif ($domain=='vimeo.com' )
|
||||
{
|
||||
// This is more complex: we have to perform a HTTP request, then parse the result.
|
||||
// Maybe we should deport this to JavaScript ? Example: http://stackoverflow.com/questions/1361149/get-img-thumbnails-from-vimeo/4285098#4285098
|
||||
$vid = substr(parse_url($url,PHP_URL_PATH),1);
|
||||
list($headers, $content) = get_http_response('https://vimeo.com/api/v2/video/'.escape($vid).'.php', 5);
|
||||
if (strpos($headers[0], '200 OK') !== false) {
|
||||
$t = unserialize($content);
|
||||
$imageurl = $t[0]['thumbnail_medium'];
|
||||
// Then we download the image and serve it to our client.
|
||||
list($headers, $content) = get_http_response($imageurl, 10);
|
||||
if (strpos($headers[0], '200 OK') !== false) {
|
||||
// Save image to cache.
|
||||
file_put_contents($cacheDir .'/'. $thumbname, $content);
|
||||
header('Content-Type: image/jpeg');
|
||||
echo $content;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
elseif ($domain=='ted.com' || endsWith($domain,'.ted.com'))
|
||||
{
|
||||
// The thumbnail for TED talks is located in the <link rel="image_src" [...]> tag on that page
|
||||
// http://www.ted.com/talks/mikko_hypponen_fighting_viruses_defending_the_net.html
|
||||
// <link rel="image_src" href="http://images.ted.com/images/ted/28bced335898ba54d4441809c5b1112ffaf36781_389x292.jpg" />
|
||||
list($headers, $content) = get_http_response($url, 5);
|
||||
if (strpos($headers[0], '200 OK') !== false) {
|
||||
// Extract the link to the thumbnail
|
||||
preg_match('!link rel="image_src" href="(http://images.ted.com/images/ted/.+_\d+x\d+\.jpg)"!', $content, $matches);
|
||||
if (!empty($matches[1]))
|
||||
{ // Let's download the image.
|
||||
$imageurl=$matches[1];
|
||||
// No control on image size, so wait long enough
|
||||
list($headers, $content) = get_http_response($imageurl, 20);
|
||||
if (strpos($headers[0], '200 OK') !== false) {
|
||||
$filepath = $cacheDir .'/'. $thumbname;
|
||||
file_put_contents($filepath, $content); // Save image to cache.
|
||||
if (resizeImage($filepath))
|
||||
{
|
||||
header('Content-Type: image/jpeg');
|
||||
echo file_get_contents($filepath);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
elseif ($domain=='xkcd.com' || endsWith($domain,'.xkcd.com'))
|
||||
{
|
||||
// There is no thumbnail available for xkcd comics, so download the whole image and resize it.
|
||||
// http://xkcd.com/327/
|
||||
// <img src="http://imgs.xkcd.com/comics/exploits_of_a_mom.png" title="<BLABLA>" alt="<BLABLA>" />
|
||||
list($headers, $content) = get_http_response($url, 5);
|
||||
if (strpos($headers[0], '200 OK') !== false) {
|
||||
// Extract the link to the thumbnail
|
||||
preg_match('!<img src="(http://imgs.xkcd.com/comics/.*)" title="[^s]!', $content, $matches);
|
||||
if (!empty($matches[1]))
|
||||
{ // Let's download the image.
|
||||
$imageurl=$matches[1];
|
||||
// No control on image size, so wait long enough
|
||||
list($headers, $content) = get_http_response($imageurl, 20);
|
||||
if (strpos($headers[0], '200 OK') !== false) {
|
||||
$filepath = $cacheDir.'/'.$thumbname;
|
||||
// Save image to cache.
|
||||
file_put_contents($filepath, $content);
|
||||
if (resizeImage($filepath))
|
||||
{
|
||||
header('Content-Type: image/jpeg');
|
||||
echo file_get_contents($filepath);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
// For all other domains, we try to download the image and make a thumbnail.
|
||||
// We allow 30 seconds max to download (and downloads are limited to 4 Mb)
|
||||
list($headers, $content) = get_http_response($url, 30);
|
||||
if (strpos($headers[0], '200 OK') !== false) {
|
||||
$filepath = $cacheDir .'/'.$thumbname;
|
||||
// Save image to cache.
|
||||
file_put_contents($filepath, $content);
|
||||
if (resizeImage($filepath))
|
||||
{
|
||||
header('Content-Type: image/jpeg');
|
||||
echo file_get_contents($filepath);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Otherwise, return an empty image (8x8 transparent gif)
|
||||
$blankgif = base64_decode('R0lGODlhCAAIAIAAAP///////yH5BAEKAAEALAAAAAAIAAgAAAIHjI+py+1dAAA7');
|
||||
// Also put something in cache so that this URL is not requested twice.
|
||||
file_put_contents($cacheDir .'/'. $blankname, $blankgif);
|
||||
header('Content-Type: image/gif');
|
||||
echo $blankgif;
|
||||
}
|
||||
|
||||
// Make a thumbnail of the image (to width: 120 pixels)
|
||||
// Returns true if success, false otherwise.
|
||||
function resizeImage($filepath)
|
||||
{
|
||||
if (!function_exists('imagecreatefromjpeg')) return false; // GD not present: no thumbnail possible.
|
||||
|
||||
// Trick: some stupid people rename GIF as JPEG... or else.
|
||||
// So we really try to open each image type whatever the extension is.
|
||||
$header=file_get_contents($filepath,false,NULL,0,256); // Read first 256 bytes and try to sniff file type.
|
||||
$im=false;
|
||||
$i=strpos($header,'GIF8'); if (($i!==false) && ($i==0)) $im = imagecreatefromgif($filepath); // Well this is crude, but it should be enough.
|
||||
$i=strpos($header,'PNG'); if (($i!==false) && ($i==1)) $im = imagecreatefrompng($filepath);
|
||||
$i=strpos($header,'JFIF'); if ($i!==false) $im = imagecreatefromjpeg($filepath);
|
||||
if (!$im) return false; // Unable to open image (corrupted or not an image)
|
||||
$w = imagesx($im);
|
||||
$h = imagesy($im);
|
||||
$ystart = 0; $yheight=$h;
|
||||
if ($h>$w) { $ystart= ($h/2)-($w/2); $yheight=$w/2; }
|
||||
$nw = 120; // Desired width
|
||||
$nh = min(floor(($h*$nw)/$w),120); // Compute new width/height, but maximum 120 pixels height.
|
||||
// Resize image:
|
||||
$im2 = imagecreatetruecolor($nw,$nh);
|
||||
imagecopyresampled($im2, $im, 0, 0, 0, $ystart, $nw, $nh, $w, $yheight);
|
||||
imageinterlace($im2,true); // For progressive JPEG.
|
||||
$tempname=$filepath.'_TEMP.jpg';
|
||||
imagejpeg($im2, $tempname, 90);
|
||||
imagedestroy($im);
|
||||
imagedestroy($im2);
|
||||
unlink($filepath);
|
||||
rename($tempname,$filepath); // Overwrite original picture with thumbnail.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isset($_SERVER['QUERY_STRING']) && startsWith($_SERVER['QUERY_STRING'], 'do=genthumbnail')) { genThumbnail($conf); exit; } // Thumbnail generation/cache does not need the link database.
|
||||
if (isset($_SERVER['QUERY_STRING']) && startsWith($_SERVER['QUERY_STRING'], 'do=dailyrss')) { showDailyRSS($conf); exit; }
|
||||
if (!isset($_SESSION['LINKS_PER_PAGE'])) {
|
||||
$_SESSION['LINKS_PER_PAGE'] = $conf->get('general.links_per_page', 20);
|
||||
|
|
|
@ -39,6 +39,7 @@ pages:
|
|||
- Continuous integration tools: Continuous-integration-tools.md
|
||||
- GnuPG signature: GnuPG-signature.md
|
||||
- Directory structure: Directory-structure.md
|
||||
- Link Structure: Link-structure.md
|
||||
- 3rd party libraries: 3rd-party-libraries.md
|
||||
- Plugin System: Plugin-System.md
|
||||
- Release Shaarli: Release-Shaarli.md
|
||||
|
|
114
tests/ThumbnailerTest.php
Normal file
114
tests/ThumbnailerTest.php
Normal file
|
@ -0,0 +1,114 @@
|
|||
<?php
|
||||
|
||||
namespace Shaarli;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Shaarli\Config\ConfigManager;
|
||||
use WebThumbnailer\Application\ConfigManager as WTConfigManager;
|
||||
|
||||
/**
|
||||
* Class ThumbnailerTest
|
||||
*
|
||||
* We only make 1 thumb test because:
|
||||
*
|
||||
* 1. the thumbnailer library is itself tested
|
||||
* 2. we don't want to make too many external requests during the tests
|
||||
*/
|
||||
class ThumbnailerTest extends TestCase
|
||||
{
|
||||
const WIDTH = 190;
|
||||
|
||||
const HEIGHT = 210;
|
||||
|
||||
/**
|
||||
* @var Thumbnailer;
|
||||
*/
|
||||
protected $thumbnailer;
|
||||
|
||||
/**
|
||||
* @var ConfigManager
|
||||
*/
|
||||
protected $conf;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->conf = new ConfigManager('tests/utils/config/configJson');
|
||||
$this->conf->set('thumbnails.mode', Thumbnailer::MODE_ALL);
|
||||
$this->conf->set('thumbnails.width', self::WIDTH);
|
||||
$this->conf->set('thumbnails.height', self::HEIGHT);
|
||||
$this->conf->set('dev.debug', true);
|
||||
|
||||
$this->thumbnailer = new Thumbnailer($this->conf);
|
||||
// cache files in the sandbox
|
||||
WTConfigManager::addFile('tests/utils/config/wt.json');
|
||||
}
|
||||
|
||||
public function tearDown()
|
||||
{
|
||||
$this->rrmdirContent('sandbox/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a thumbnail with a custom size in 'all' mode.
|
||||
*/
|
||||
public function testThumbnailAllValid()
|
||||
{
|
||||
$thumb = $this->thumbnailer->get('https://github.com/shaarli/Shaarli/');
|
||||
$this->assertNotFalse($thumb);
|
||||
$image = imagecreatefromstring(file_get_contents($thumb));
|
||||
$this->assertEquals(self::WIDTH, imagesx($image));
|
||||
$this->assertEquals(self::HEIGHT, imagesy($image));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a thumbnail with a custom size in 'common' mode.
|
||||
*/
|
||||
public function testThumbnailCommonValid()
|
||||
{
|
||||
$this->conf->set('thumbnails.mode', Thumbnailer::MODE_COMMON);
|
||||
$thumb = $this->thumbnailer->get('https://imgur.com/jlFgGpe');
|
||||
$this->assertNotFalse($thumb);
|
||||
$image = imagecreatefromstring(file_get_contents($thumb));
|
||||
$this->assertEquals(self::WIDTH, imagesx($image));
|
||||
$this->assertEquals(self::HEIGHT, imagesy($image));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a thumbnail in 'common' mode which isn't include in common websites.
|
||||
*/
|
||||
public function testThumbnailCommonInvalid()
|
||||
{
|
||||
$this->conf->set('thumbnails.mode', Thumbnailer::MODE_COMMON);
|
||||
$thumb = $this->thumbnailer->get('https://github.com/shaarli/Shaarli/');
|
||||
$this->assertFalse($thumb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a thumbnail that can't be retrieved.
|
||||
*/
|
||||
public function testThumbnailNotValid()
|
||||
{
|
||||
$oldlog = ini_get('error_log');
|
||||
ini_set('error_log', '/dev/null');
|
||||
|
||||
$thumbnailer = new Thumbnailer(new ConfigManager());
|
||||
$thumb = $thumbnailer->get('nope');
|
||||
$this->assertFalse($thumb);
|
||||
|
||||
ini_set('error_log', $oldlog);
|
||||
}
|
||||
|
||||
protected function rrmdirContent($dir) {
|
||||
if (is_dir($dir)) {
|
||||
$objects = scandir($dir);
|
||||
foreach ($objects as $object) {
|
||||
if ($object != "." && $object != "..") {
|
||||
if (is_dir($dir."/".$object))
|
||||
$this->rrmdirContent($dir."/".$object);
|
||||
else
|
||||
unlink($dir."/".$object);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
use Shaarli\Config\ConfigJson;
|
||||
use Shaarli\Config\ConfigManager;
|
||||
use Shaarli\Config\ConfigPhp;
|
||||
use Shaarli\Thumbnailer;
|
||||
|
||||
require_once 'tests/Updater/DummyUpdater.php';
|
||||
require_once 'inc/rain.tpl.class.php';
|
||||
|
@ -20,7 +21,7 @@ class UpdaterTest extends PHPUnit_Framework_TestCase
|
|||
/**
|
||||
* @var string Config file path (without extension).
|
||||
*/
|
||||
protected static $configFile = 'tests/utils/config/configJson';
|
||||
protected static $configFile = 'sandbox/config';
|
||||
|
||||
/**
|
||||
* @var ConfigManager
|
||||
|
@ -32,6 +33,7 @@ class UpdaterTest extends PHPUnit_Framework_TestCase
|
|||
*/
|
||||
public function setUp()
|
||||
{
|
||||
copy('tests/utils/config/configJson.json.php', self::$configFile .'.json.php');
|
||||
$this->conf = new ConfigManager(self::$configFile);
|
||||
}
|
||||
|
||||
|
@ -684,4 +686,50 @@ public function testUpdateMethodDownloadSizeAndTimeoutConfOnlyTimeout()
|
|||
$this->assertEquals(4194304, $this->conf->get('general.download_max_size'));
|
||||
$this->assertEquals(3, $this->conf->get('general.download_timeout'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test updateMethodWebThumbnailer with thumbnails enabled.
|
||||
*/
|
||||
public function testUpdateMethodWebThumbnailerEnabled()
|
||||
{
|
||||
$this->conf->remove('thumbnails');
|
||||
$this->conf->set('thumbnail.enable_thumbnails', true);
|
||||
$updater = new Updater([], [], $this->conf, true, $_SESSION);
|
||||
$this->assertTrue($updater->updateMethodWebThumbnailer());
|
||||
$this->assertFalse($this->conf->exists('thumbnail'));
|
||||
$this->assertEquals(\Shaarli\Thumbnailer::MODE_ALL, $this->conf->get('thumbnails.mode'));
|
||||
$this->assertEquals(125, $this->conf->get('thumbnails.width'));
|
||||
$this->assertEquals(90, $this->conf->get('thumbnails.height'));
|
||||
$this->assertContains('You have enabled or changed thumbnails', $_SESSION['warnings'][0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test updateMethodWebThumbnailer with thumbnails disabled.
|
||||
*/
|
||||
public function testUpdateMethodWebThumbnailerDisabled()
|
||||
{
|
||||
$this->conf->remove('thumbnails');
|
||||
$this->conf->set('thumbnail.enable_thumbnails', false);
|
||||
$updater = new Updater([], [], $this->conf, true, $_SESSION);
|
||||
$this->assertTrue($updater->updateMethodWebThumbnailer());
|
||||
$this->assertFalse($this->conf->exists('thumbnail'));
|
||||
$this->assertEquals(Thumbnailer::MODE_NONE, $this->conf->get('thumbnails.mode'));
|
||||
$this->assertEquals(125, $this->conf->get('thumbnails.width'));
|
||||
$this->assertEquals(90, $this->conf->get('thumbnails.height'));
|
||||
$this->assertTrue(empty($_SESSION['warnings']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test updateMethodWebThumbnailer with thumbnails disabled.
|
||||
*/
|
||||
public function testUpdateMethodWebThumbnailerNothingToDo()
|
||||
{
|
||||
$updater = new Updater([], [], $this->conf, true, $_SESSION);
|
||||
$this->assertTrue($updater->updateMethodWebThumbnailer());
|
||||
$this->assertFalse($this->conf->exists('thumbnail'));
|
||||
$this->assertEquals(Thumbnailer::MODE_COMMON, $this->conf->get('thumbnails.mode'));
|
||||
$this->assertEquals(90, $this->conf->get('thumbnails.width'));
|
||||
$this->assertEquals(53, $this->conf->get('thumbnails.height'));
|
||||
$this->assertTrue(empty($_SESSION['warnings']));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,6 +81,18 @@ public function testSetWriteGetNested()
|
|||
$this->assertEquals('testSetWriteGetNested', $this->conf->get('foo.bar.key.stuff'));
|
||||
}
|
||||
|
||||
public function testSetDeleteNested()
|
||||
{
|
||||
$this->conf->set('foo.bar.key.stuff', 'testSetDeleteNested');
|
||||
$this->assertTrue($this->conf->exists('foo.bar'));
|
||||
$this->assertTrue($this->conf->exists('foo.bar.key.stuff'));
|
||||
$this->assertEquals('testSetDeleteNested', $this->conf->get('foo.bar.key.stuff'));
|
||||
|
||||
$this->conf->remove('foo.bar');
|
||||
$this->assertFalse($this->conf->exists('foo.bar.key.stuff'));
|
||||
$this->assertFalse($this->conf->exists('foo.bar'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set with an empty key.
|
||||
*
|
||||
|
@ -103,6 +115,17 @@ public function testSetArrayKey()
|
|||
$this->conf->set(array('foo' => 'bar'), 'stuff');
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove with an empty key.
|
||||
*
|
||||
* @expectedException \Exception
|
||||
* @expectedExceptionMessageRegExp #^Invalid setting key parameter. String expected, got.*#
|
||||
*/
|
||||
public function testRmoveEmptyKey()
|
||||
{
|
||||
$this->conf->remove('');
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to write the config without mandatory parameter (e.g. 'login').
|
||||
*
|
||||
|
|
|
@ -1,35 +1,84 @@
|
|||
<?php /*
|
||||
{
|
||||
"credentials": {
|
||||
"login":"root",
|
||||
"hash":"hash",
|
||||
"salt":"salt"
|
||||
"login": "root",
|
||||
"hash": "hash",
|
||||
"salt": "salt"
|
||||
},
|
||||
"security": {
|
||||
"session_protection_disabled":false
|
||||
"session_protection_disabled": false,
|
||||
"ban_after": 4,
|
||||
"ban_duration": 1800,
|
||||
"open_shaarli": false,
|
||||
"allowed_protocols": [
|
||||
"ftp",
|
||||
"ftps",
|
||||
"magnet"
|
||||
]
|
||||
},
|
||||
"general": {
|
||||
"timezone":"Europe\/Paris",
|
||||
"timezone": "Europe\/Paris",
|
||||
"title": "Shaarli",
|
||||
"header_link": "?"
|
||||
"header_link": "?",
|
||||
"links_per_page": 20,
|
||||
"enabled_plugins": [
|
||||
"qrcode"
|
||||
],
|
||||
"default_note_title": "Note: "
|
||||
},
|
||||
"privacy": {
|
||||
"default_private_links":true
|
||||
"default_private_links": true,
|
||||
"hide_public_links": false,
|
||||
"force_login": false,
|
||||
"hide_timestamps": false,
|
||||
"remember_user_default": true
|
||||
},
|
||||
"redirector": {
|
||||
"url":"lala"
|
||||
"url": "lala",
|
||||
"encode_url": true
|
||||
},
|
||||
"config": {
|
||||
"foo": "bar"
|
||||
},
|
||||
"resource": {
|
||||
"datastore": "tests\/utils\/config\/datastore.php",
|
||||
"data_dir": "sandbox/",
|
||||
"raintpl_tpl": "tpl/"
|
||||
"data_dir": "sandbox\/",
|
||||
"raintpl_tpl": "tpl\/",
|
||||
"config": "data\/config.php",
|
||||
"ban_file": "data\/ipbans.php",
|
||||
"updates": "data\/updates.txt",
|
||||
"log": "data\/log.txt",
|
||||
"update_check": "data\/lastupdatecheck.txt",
|
||||
"history": "data\/history.php",
|
||||
"theme": "default",
|
||||
"raintpl_tmp": "tmp\/",
|
||||
"thumbnails_cache": "cache",
|
||||
"page_cache": "pagecache"
|
||||
},
|
||||
"plugins": {
|
||||
"WALLABAG_VERSION": 1
|
||||
},
|
||||
"dev": {
|
||||
"debug": true
|
||||
},
|
||||
"updates": {
|
||||
"check_updates": false,
|
||||
"check_updates_branch": "stable",
|
||||
"check_updates_interval": 86400
|
||||
},
|
||||
"feed": {
|
||||
"rss_permalinks": true,
|
||||
"show_atom": true
|
||||
},
|
||||
"translation": {
|
||||
"language": "auto",
|
||||
"mode": "php",
|
||||
"extensions": []
|
||||
},
|
||||
"thumbnails": {
|
||||
"mode": "common",
|
||||
"width": 90,
|
||||
"height": 53
|
||||
}
|
||||
}
|
||||
*/ ?>
|
||||
|
||||
|
|
12
tests/utils/config/wt.json
Normal file
12
tests/utils/config/wt.json
Normal file
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"settings": {
|
||||
"default": {
|
||||
"_comment": "infinite cache",
|
||||
"cache_duration": -1,
|
||||
"timeout": 10
|
||||
},
|
||||
"path": {
|
||||
"cache": "sandbox/"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -242,6 +242,37 @@ <h2 class="window-title">{'Configure'|t}</h2>
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pure-g">
|
||||
<div class="pure-u-lg-{$ratioLabel} pure-u-{$ratioLabelMobile}">
|
||||
<div class="form-label">
|
||||
<label for="enableThumbnails">
|
||||
<span class="label-name">{'Enable thumbnails'|t}</span><br>
|
||||
<span class="label-desc">
|
||||
{if="! $gd_enabled"}
|
||||
{'You need to enable the extension <code>php-gd</code> to use thumbnails.'|t}
|
||||
{elseif="$thumbnails_enabled"}
|
||||
<a href="?do=thumbs_update">{'Synchronize thumbnails'|t}</a>
|
||||
{/if}
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pure-u-lg-{$ratioInput} pure-u-{$ratioInputMobile}">
|
||||
<div class="form-input">
|
||||
<select name="enableThumbnails" id="enableThumbnails" class="align">
|
||||
<option value="all" {if="$thumbnails_mode=='all'"}selected{/if}>
|
||||
{'All'|t}
|
||||
</option>
|
||||
<option value="common" {if="$thumbnails_mode=='common'"}selected{/if}>
|
||||
{'Only common media hosts'|t}
|
||||
</option>
|
||||
<option value="none" {if="$thumbnails_mode=='none'"}selected{/if}>
|
||||
{'None'|t}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="center">
|
||||
<input type="submit" value="{'Save'|t}" name="save">
|
||||
</div>
|
||||
|
|
|
@ -131,9 +131,17 @@
|
|||
|
||||
<div class="linklist-item linklist-item{if="$value.class"} {$value.class}{/if}" data-id="{$value.id}">
|
||||
<div class="linklist-item-title">
|
||||
{$thumb=thumbnail($value.url)}
|
||||
{if="$thumb!=false"}
|
||||
<div class="linklist-item-thumbnail">{$thumb}</div>
|
||||
{if="$thumbnails_enabled && !empty($value.thumbnail)"}
|
||||
<div class="linklist-item-thumbnail" style="width:{$thumbnails_width}px;height:{$thumbnails_height}px;">
|
||||
<div class="thumbnail">
|
||||
<a href="{$value.real_url}">
|
||||
{ignore}RainTPL hack: put the 2 src on two different line to avoid path replace bug{/ignore}
|
||||
<img data-src="{$value.thumbnail}#" class="b-lazy"
|
||||
src="#"
|
||||
alt="thumbnail" width="{$thumbnails_width}" height="{$thumbnails_height}" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{if="$is_logged_in"}
|
||||
|
@ -268,5 +276,6 @@ <h2>
|
|||
</div>
|
||||
|
||||
{include="page.footer"}
|
||||
<script src="js/thumbnails.min.js?v={$version_hash}"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -30,9 +30,11 @@
|
|||
<li class="pure-menu-item" id="shaarli-menu-tags">
|
||||
<a href="?do=tagcloud" class="pure-menu-link">{'Tag cloud'|t}</a>
|
||||
</li>
|
||||
{if="$thumbnails_enabled"}
|
||||
<li class="pure-menu-item" id="shaarli-menu-picwall">
|
||||
<a href="?do=picwall{$searchcrits}" class="pure-menu-link">{'Picture wall'|t}</a>
|
||||
</li>
|
||||
{/if}
|
||||
<li class="pure-menu-item" id="shaarli-menu-daily">
|
||||
<a href="?do=daily" class="pure-menu-link">{'Daily'|t}</a>
|
||||
</li>
|
||||
|
@ -169,4 +171,18 @@
|
|||
</div>
|
||||
{/if}
|
||||
|
||||
{if="!empty($global_warnings) && $is_logged_in"}
|
||||
<div class="pure-g pure-alert pure-alert-warning pure-alert-closable" id="shaarli-warnings-alert">
|
||||
<div class="pure-u-2-24"></div>
|
||||
<div class="pure-u-20-24">
|
||||
{loop="global_warnings"}
|
||||
<p>{$value}</p>
|
||||
{/loop}
|
||||
</div>
|
||||
<div class="pure-u-2-24">
|
||||
<i class="fa fa-times pure-alert-close"></i>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="clear"></div>
|
||||
|
|
|
@ -5,8 +5,22 @@
|
|||
</head>
|
||||
<body>
|
||||
{include="page.header"}
|
||||
{if="!$thumbnails_enabled"}
|
||||
<div class="pure-g pure-alert pure-alert-warning page-single-alert">
|
||||
<div class="pure-u-1 center">
|
||||
{'Picture wall unavailable (thumbnails are disabled).'|t}
|
||||
</div>
|
||||
</div>
|
||||
{else}
|
||||
{if="count($linksToDisplay)===0 && $is_logged_in"}
|
||||
<div class="pure-g pure-alert pure-alert-warning page-single-alert">
|
||||
<div class="pure-u-1 center">
|
||||
{'There is no cached thumbnail. Try to <a href="?do=thumbs_update">synchronize them</a>.'|t}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="pure-g">
|
||||
<div class="pure-g">
|
||||
<div class="pure-u-lg-1-6 pure-u-1-24"></div>
|
||||
<div class="pure-u-lg-2-3 pure-u-22-24 page-form page-visitor">
|
||||
{$countPics=count($linksToDisplay)}
|
||||
|
@ -18,10 +32,14 @@ <h2 class="window-title">{'Picture Wall'|t} - {$countPics} {'pics'|t}</h2>
|
|||
{/loop}
|
||||
</div>
|
||||
|
||||
<div id="picwall_container" class="picwall-container">
|
||||
<div id="picwall-container" class="picwall-container">
|
||||
{loop="$linksToDisplay"}
|
||||
<div class="picwall-pictureframe">
|
||||
{$value.thumbnail}<a href="{$value.real_url}"><span class="info">{$value.title}</span></a>
|
||||
{ignore}RainTPL hack: put the 2 src on two different line to avoid path replace bug{/ignore}
|
||||
<img data-src="{$value.thumbnail}#" class="b-lazy"
|
||||
src="#"
|
||||
alt="thumbnail" width="{$thumbnails_width}" height="{$thumbnails_height}" />
|
||||
<a href="{$value.real_url}"><span class="info">{$value.title}</span></a>
|
||||
{loop="$value.picwall_plugin"}
|
||||
{$value}
|
||||
{/loop}
|
||||
|
@ -36,10 +54,12 @@ <h2 class="window-title">{'Picture Wall'|t} - {$countPics} {'pics'|t}</h2>
|
|||
{/loop}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pure-u-lg-1-6 pure-u-1-24"></div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{include="page.footer"}
|
||||
<script src="js/picwall.min.js?v={$version_hash}"></script>
|
||||
<script src="js/thumbnails.min.js?v={$version_hash}"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
|
48
tpl/default/thumbnails.html
Normal file
48
tpl/default/thumbnails.html
Normal file
|
@ -0,0 +1,48 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
{include="includes"}
|
||||
</head>
|
||||
<body>
|
||||
{include="page.header"}
|
||||
|
||||
<div class="pure-g thumbnails-page-container">
|
||||
<div class="pure-u-lg-1-3 pure-u-1-24"></div>
|
||||
<div class="pure-u-lg-1-3 pure-u-22-24 page-form page-form-light">
|
||||
<h2 class="window-title">{'Thumbnails update'|t}</h2>
|
||||
|
||||
<div class="pure-g">
|
||||
<div class="pure-u-lg-1-3 pure-u-1-24"></div>
|
||||
<div class="pure-u-lg-1-3 pure-u-22-24">
|
||||
<div class="thumbnail-placeholder" style="width: {$thumbnails_width}px; height: {$thumbnails_height}px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pure-g">
|
||||
<div class="pure-u-1-12"></div>
|
||||
<div class="pure-u-5-6">
|
||||
<div class="thumbnail-link-title"></div>
|
||||
|
||||
<div class="progressbar">
|
||||
<div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pure-g">
|
||||
<div class="pure-u-lg-1-3 pure-u-1-24"></div>
|
||||
<div class="pure-u-lg-1-3 pure-u-22-24">
|
||||
<div class="progress-counter">
|
||||
<span class="progress-current">0</span> / <span class="progress-total">{$ids|count}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<input type="hidden" name="ids" value="{function="implode($ids, ',')"}" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{include="page.footer"}
|
||||
<script src="js/thumbnails_update.min.js?v={$version_hash}"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -45,6 +45,14 @@ <h2 class="window-title">{'Settings'|t}</h2>
|
|||
</a>
|
||||
</div>
|
||||
|
||||
{if="$thumbnails_enabled"}
|
||||
<div class="tools-item">
|
||||
<a href="?do=thumbs_update" title="{'Synchronize all link thumbnails'|t}">
|
||||
<span class="pure-button pure-u-lg-2-3 pure-u-3-4">{'Synchronize thumbnails'|t}</span>
|
||||
</a>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{loop="$tools_plugin"}
|
||||
<div class="tools-item">
|
||||
{$value}
|
||||
|
|
|
@ -128,6 +128,29 @@
|
|||
<input type="text" name="apiSecret" id="apiSecret" size="50" value="{$api_secret}" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><b>Enable thumbnails</b></td>
|
||||
<td>
|
||||
<select name="enableThumbnails" id="enableThumbnails" class="align">
|
||||
<option value="all" {if="$thumbnails_mode=='all'"}selected{/if}>
|
||||
{'All'|t}
|
||||
</option>
|
||||
<option value="common" {if="$thumbnails_mode=='common'"}selected{/if}>
|
||||
{'Only common media hosts'|t}
|
||||
</option>
|
||||
<option value="none" {if="$thumbnails_mode=='none'"}selected{/if}>
|
||||
{'None'|t}
|
||||
</option>
|
||||
</select>
|
||||
<label for="enableThumbnails">
|
||||
{if="! $gd_enabled"}
|
||||
{'You need to enable the extension <code>php-gd</code> to use thumbnails.'|t}
|
||||
{elseif="$thumbnails_enabled"}
|
||||
<a href="?do=thumbs_update">{'Synchonize thumbnails'|t}</a>
|
||||
{/if}
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td></td>
|
||||
|
|
|
@ -80,7 +80,16 @@
|
|||
{loop="$links"}
|
||||
<li{if="$value.class"} class="{$value.class}"{/if}>
|
||||
<a id="{$value.shorturl}"></a>
|
||||
<div class="thumbnail">{$value.url|thumbnail}</div>
|
||||
{if="$thumbnails_enabled && !empty($value.thumbnail)"}
|
||||
<div class="thumbnail">
|
||||
<a href="{$value.real_url}">
|
||||
{ignore}RainTPL hack: put the 2 src on two different line to avoid path replace bug{/ignore}
|
||||
<img data-src="{$value.thumbnail}#" class="b-lazy"
|
||||
src="#"
|
||||
alt="thumbnail" width="{$thumbnails_width}" height="{$thumbnails_height}" />
|
||||
</a>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="linkcontainer">
|
||||
{if="$is_logged_in"}
|
||||
<div class="linkeditbuttons">
|
||||
|
@ -145,6 +154,7 @@
|
|||
</div>
|
||||
|
||||
{include="page.footer"}
|
||||
<script src="js/thumbnails.min.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -15,7 +15,11 @@
|
|||
<div id="picwall_container">
|
||||
{loop="$linksToDisplay"}
|
||||
<div class="picwall_pictureframe">
|
||||
{$value.thumbnail}<a href="{$value.real_url}"><span class="info">{$value.title}</span></a>
|
||||
{ignore}RainTPL hack: put the 2 src on two different line to avoid path replace bug{/ignore}
|
||||
<img data-src="{$value.thumbnail}#" class="b-lazy"
|
||||
src="#"
|
||||
alt="thumbnail" width="{$thumbnails_width}" height="{$thumbnails_height}" />
|
||||
<a href="{$value.real_url}"><span class="info">{$value.title}</span></a>
|
||||
{loop="$value.picwall_plugin"}
|
||||
{$value}
|
||||
{/loop}
|
||||
|
@ -34,6 +38,6 @@
|
|||
|
||||
{include="page.footer"}
|
||||
|
||||
<script src="js/picwall.min.js"></script>
|
||||
<script src="js/thumbnails.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
28
tpl/vintage/thumbnails.html
Normal file
28
tpl/vintage/thumbnails.html
Normal file
|
@ -0,0 +1,28 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>{include="includes"}</head>
|
||||
<body>
|
||||
<div id="pageheader">
|
||||
{include="page.header"}
|
||||
</div>
|
||||
|
||||
<div class="center thumbnails-update-container">
|
||||
<div class="thumbnail-placeholder" style="width: {$thumbnails_width}px; height: {$thumbnails_height}px;"></div>
|
||||
|
||||
<div class="thumbnail-link-title"></div>
|
||||
|
||||
<div class="progressbar">
|
||||
<div></div>
|
||||
</div>
|
||||
|
||||
<div class="progress-counter">
|
||||
<span class="progress-current">0</span> / <span class="progress-total">{$ids|count}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<input type="hidden" name="ids" value="{function="implode($ids, ',')"}" />
|
||||
|
||||
{include="page.footer"}
|
||||
<script src="js/thumbnails_update.min.js?v={$version_hash}"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -23,7 +23,8 @@ const extractCssVintage = new ExtractTextPlugin({
|
|||
module.exports = [
|
||||
{
|
||||
entry: {
|
||||
picwall: './assets/common/js/picwall.js',
|
||||
thumbnails: './assets/common/js/thumbnails.js',
|
||||
thumbnails_update: './assets/common/js/thumbnails-update.js',
|
||||
pluginsadmin: './assets/default/js/plugins-admin.js',
|
||||
shaarli: [
|
||||
'./assets/default/js/base.js',
|
||||
|
@ -96,7 +97,8 @@ module.exports = [
|
|||
'./assets/vintage/css/reset.css',
|
||||
'./assets/vintage/css/shaarli.css',
|
||||
].concat(glob.sync('./assets/vintage/img/*')),
|
||||
picwall: './assets/common/js/picwall.js',
|
||||
thumbnails: './assets/common/js/thumbnails.js',
|
||||
thumbnails_update: './assets/common/js/thumbnails-update.js',
|
||||
},
|
||||
output: {
|
||||
filename: '[name].min.js',
|
||||
|
|
Loading…
Reference in a new issue