Add favicon support

This commit is contained in:
Frédéric Guillot 2014-12-24 17:54:27 -05:00
parent 7d4d4e0193
commit c1d74b8332
28 changed files with 176 additions and 61 deletions

View File

@ -662,6 +662,10 @@ a.icon:hover {
padding-bottom: 10px; padding-bottom: 10px;
} }
.items article .favicon {
height: 16px;
}
/* other pages */ /* other pages */
section li { section li {
margin-left: 15px; margin-left: 15px;

View File

@ -42,12 +42,14 @@ Router\get_action('bookmarks', function() {
$offset = Request\int_param('offset', 0); $offset = Request\int_param('offset', 0);
$nb_items = Model\Item\count_bookmarks(); $nb_items = Model\Item\count_bookmarks();
$items = Model\Item\get_bookmarks($offset, Model\Config\get('items_per_page'));
Response\html(Template\layout('bookmarks', array( Response\html(Template\layout('bookmarks', array(
'favicons' => Model\Feed\get_item_favicons($items),
'order' => '', 'order' => '',
'direction' => '', 'direction' => '',
'display_mode' => Model\Config\get('items_display_mode'), 'display_mode' => Model\Config\get('items_display_mode'),
'items' => Model\Item\get_bookmarks($offset, Model\Config\get('items_per_page')), 'items' => $items,
'nb_items' => $nb_items, 'nb_items' => $nb_items,
'offset' => $offset, 'offset' => $offset,
'items_per_page' => Model\Config\get('items_per_page'), 'items_per_page' => Model\Config\get('items_per_page'),

View File

@ -134,7 +134,7 @@ Router\get_action('config', function() {
// Update preferences // Update preferences
Router\post_action('config', function() { Router\post_action('config', function() {
$values = Request\values() + array('nocontent' => 0, 'image_proxy' => 0); $values = Request\values() + array('nocontent' => 0, 'image_proxy' => 0, 'favicons' => 0);
Model\Config\check_csrf_values($values); Model\Config\check_csrf_values($values);
list($valid, $errors) = Model\Config\validate_modification($values); list($valid, $errors) = Model\Config\validate_modification($values);

View File

@ -11,15 +11,17 @@ Router\get_action('history', function() {
$offset = Request\int_param('offset', 0); $offset = Request\int_param('offset', 0);
$nb_items = Model\Item\count_by_status('read'); $nb_items = Model\Item\count_by_status('read');
$items = Model\Item\get_all(
Response\html(Template\layout('history', array(
'items' => Model\Item\get_all(
'read', 'read',
$offset, $offset,
Model\Config\get('items_per_page'), Model\Config\get('items_per_page'),
'updated', 'updated',
Model\Config\get('items_sorting_direction') Model\Config\get('items_sorting_direction')
), );
Response\html(Template\layout('history', array(
'favicons' => Model\Feed\get_item_favicons($items),
'items' => $items,
'order' => '', 'order' => '',
'direction' => '', 'direction' => '',
'display_mode' => Model\Config\get('items_display_mode'), 'display_mode' => Model\Config\get('items_display_mode'),

View File

@ -25,6 +25,7 @@ Router\get_action('unread', function() {
} }
Response\html(Template\layout('unread_items', array( Response\html(Template\layout('unread_items', array(
'favicons' => Model\Feed\get_item_favicons($items),
'order' => $order, 'order' => $order,
'direction' => $direction, 'direction' => $direction,
'display_mode' => Model\Config\get('items_display_mode'), 'display_mode' => Model\Config\get('items_display_mode'),
@ -88,6 +89,7 @@ Router\get_action('feed-items', function() {
$items = Model\Item\get_all_by_feed($feed_id, $offset, Model\Config\get('items_per_page'), $order, $direction); $items = Model\Item\get_all_by_feed($feed_id, $offset, Model\Config\get('items_per_page'), $order, $direction);
Response\html(Template\layout('feed_items', array( Response\html(Template\layout('feed_items', array(
'favicons' => Model\Feed\get_favicons(array($feed['id'])),
'order' => $order, 'order' => $order,
'direction' => $direction, 'direction' => $direction,
'display_mode' => Model\Config\get('items_display_mode'), 'display_mode' => Model\Config\get('items_display_mode'),

View File

@ -2,6 +2,15 @@
namespace Helper; namespace Helper;
function favicon(array $favicons, $feed_id)
{
if (isset($favicons[$feed_id])) {
return '<img src="'.$favicons[$feed_id].'" class="favicon"/>';
}
return '';
}
function isRTL(array $item) function isRTL(array $item)
{ {
return ! empty($item['rtl']) || \PicoFeed\Parser\Parser::isLanguageRTL($item['language']); return ! empty($item['rtl']) || \PicoFeed\Parser\Parser::isLanguageRTL($item['language']);

View File

@ -232,4 +232,5 @@ return array(
// 'Application' => '', // 'Application' => '',
// 'Enable image proxy' => '', // 'Enable image proxy' => '',
// 'Avoid mixed content warnings with HTTPS' => '', // 'Avoid mixed content warnings with HTTPS' => '',
// 'Download favicons' => '',
); );

View File

@ -232,4 +232,5 @@ return array(
// 'Application' => '', // 'Application' => '',
// 'Enable image proxy' => '', // 'Enable image proxy' => '',
// 'Avoid mixed content warnings with HTTPS' => '', // 'Avoid mixed content warnings with HTTPS' => '',
// 'Download favicons' => '',
); );

View File

@ -232,4 +232,5 @@ return array(
// 'Application' => '', // 'Application' => '',
// 'Enable image proxy' => '', // 'Enable image proxy' => '',
// 'Avoid mixed content warnings with HTTPS' => '', // 'Avoid mixed content warnings with HTTPS' => '',
// 'Download favicons' => '',
); );

View File

@ -232,4 +232,5 @@ return array(
'Application' => 'Application', 'Application' => 'Application',
'Enable image proxy' => 'Activer le proxy pour les images', 'Enable image proxy' => 'Activer le proxy pour les images',
'Avoid mixed content warnings with HTTPS' => 'Évite les alertes du navigateur web en HTTPS', 'Avoid mixed content warnings with HTTPS' => 'Évite les alertes du navigateur web en HTTPS',
'Download favicons' => 'Télécharger les icônes des sites web',
); );

View File

@ -232,4 +232,5 @@ return array(
// 'Application' => '', // 'Application' => '',
// 'Enable image proxy' => '', // 'Enable image proxy' => '',
// 'Avoid mixed content warnings with HTTPS' => '', // 'Avoid mixed content warnings with HTTPS' => '',
// 'Download favicons' => '',
); );

View File

@ -232,4 +232,5 @@ return array(
// 'Application' => '', // 'Application' => '',
// 'Enable image proxy' => '', // 'Enable image proxy' => '',
// 'Avoid mixed content warnings with HTTPS' => '', // 'Avoid mixed content warnings with HTTPS' => '',
// 'Download favicons' => '',
); );

View File

@ -232,4 +232,5 @@ return array(
// 'Application' => '', // 'Application' => '',
// 'Enable image proxy' => '', // 'Enable image proxy' => '',
// 'Avoid mixed content warnings with HTTPS' => '', // 'Avoid mixed content warnings with HTTPS' => '',
// 'Download favicons' => '',
); );

View File

@ -285,34 +285,13 @@ function get($name)
// Get all config parameters // Get all config parameters
function get_all() function get_all()
{ {
return Database::get('db') $config = Database::get('db')
->table('config') ->table('config')
->columns(
'username',
'language',
'timezone',
'autoflush',
'autoflush_unread',
'nocontent',
'items_per_page',
'theme',
'api_token',
'feed_token',
'fever_token',
'bookmarklet_token',
'items_sorting_direction',
'items_display_mode',
'redirect_nothing_to_read',
'auto_update_url',
'pinboard_enabled',
'pinboard_token',
'pinboard_tags',
'instapaper_enabled',
'instapaper_username',
'instapaper_password',
'image_proxy'
)
->findOne(); ->findOne();
unset($config['password']);
return $config;
} }
// Validation for edit action // Validation for edit action

View File

@ -2,18 +2,72 @@
namespace Model\Feed; namespace Model\Feed;
use Model\Config;
use Model\Item;
use SimpleValidator\Validator; use SimpleValidator\Validator;
use SimpleValidator\Validators; use SimpleValidator\Validators;
use PicoDb\Database; use PicoDb\Database;
use Model\Config;
use Model\Item;
use PicoFeed\Serialization\Export; use PicoFeed\Serialization\Export;
use PicoFeed\Serialization\Import; use PicoFeed\Serialization\Import;
use PicoFeed\Reader\Reader; use PicoFeed\Reader\Reader;
use PicoFeed\Reader\Favicon;
use PicoFeed\PicoFeedException; use PicoFeed\PicoFeedException;
const LIMIT_ALL = -1; const LIMIT_ALL = -1;
// Download and store the favicon
function fetch_favicon($feed_id, $site_url)
{
$favicon = new Favicon;
return Database::get('db')
->table('favicons')
->save(array(
'feed_id' => $feed_id,
'link' => $favicon->find($site_url),
'icon' => $favicon->getDataUri(),
));
}
// Refresh favicon
function refresh_favicon($feed_id, $site_url)
{
if (Config\get('favicons') == 1 && ! has_favicon($feed_id)) {
fetch_favicon($feed_id, $site_url);
}
}
// Return true if the feed have a favicon
function has_favicon($feed_id)
{
return Database::get('db')->table('favicons')->eq('feed_id', $feed_id)->count() === 1;
}
// Get favicons for those feeds
function get_favicons(array $feed_ids)
{
if (Config\get('favicons') == 0) {
return array();
}
return Database::get('db')
->table('favicons')
->in('feed_id', $feed_ids)
->listing('feed_id', 'icon');
}
// Get all favicons for a list of items
function get_item_favicons(array $items)
{
$feed_ids = array();
foreach ($items as $item) {
$feeds_ids[] = $item['feed_id'];
}
return get_favicons($feed_ids);
}
// Update feed information // Update feed information
function update(array $values) function update(array $values)
{ {
@ -117,6 +171,8 @@ function create($url, $enable_grabber = false, $force_rtl = false)
$feed_id = $db->getConnection()->getLastId(); $feed_id = $db->getConnection()->getLastId();
Item\update_all($feed_id, $feed->getItems()); Item\update_all($feed_id, $feed->getItems());
refresh_favicon($feed_id, $feed->getSiteUrl());
Config\write_debug(); Config\write_debug();
return (int) $feed_id; return (int) $feed_id;
@ -187,6 +243,7 @@ function refresh($feed_id)
update_cache($feed_id, $resource->getLastModified(), $resource->getEtag()); update_cache($feed_id, $resource->getLastModified(), $resource->getEtag());
Item\update_all($feed_id, $feed->getItems()); Item\update_all($feed_id, $feed->getItems());
refresh_favicon($feed_id, $feed->getSiteUrl());
} }
update_parsing_error($feed_id, 0); update_parsing_error($feed_id, 0);

View File

@ -5,7 +5,21 @@ namespace Schema;
use PDO; use PDO;
use Model\Config; use Model\Config;
const VERSION = 33; const VERSION = 34;
function version_34($pdo)
{
$pdo->exec('ALTER TABLE config ADD COLUMN favicons INTEGER DEFAULT 0');
$pdo->exec(
'CREATE TABLE favicons (
feed_id INTEGER UNIQUE,
link TEXT,
icon TEXT,
FOREIGN KEY(feed_id) REFERENCES feeds(id) ON DELETE CASCADE
)'
);
}
function version_33($pdo) function version_33($pdo)
{ {

View File

@ -12,7 +12,14 @@
<section class="items" id="listing"> <section class="items" id="listing">
<?php foreach ($items as $item): ?> <?php foreach ($items as $item): ?>
<?= \PicoFarad\Template\load('item', array('item' => $item, 'menu' => $menu, 'offset' => $offset, 'hide' => false, 'display_mode' => $display_mode)) ?> <?= \PicoFarad\Template\load('item', array(
'item' => $item,
'menu' => $menu,
'offset' => $offset,
'hide' => false,
'display_mode' => $display_mode,
'favicons' => $favicons,
)) ?>
<?php endforeach ?> <?php endforeach ?>
<?= \PicoFarad\Template\load('paging', array('menu' => $menu, 'nb_items' => $nb_items, 'items_per_page' => $items_per_page, 'offset' => $offset, 'order' => $order, 'direction' => $direction)) ?> <?= \PicoFarad\Template\load('paging', array('menu' => $menu, 'nb_items' => $nb_items, 'items_per_page' => $items_per_page, 'offset' => $offset, 'order' => $order, 'direction' => $direction)) ?>

View File

@ -12,7 +12,6 @@
<form method="post" action="?action=config" autocomplete="off"> <form method="post" action="?action=config" autocomplete="off">
<h3><?= t('Authentication') ?></h3> <h3><?= t('Authentication') ?></h3>
<?= Helper\form_hidden('csrf', $values) ?> <?= Helper\form_hidden('csrf', $values) ?>
<?= Helper\form_label(t('Username'), 'username') ?> <?= Helper\form_label(t('Username'), 'username') ?>
<?= Helper\form_text('username', $values, $errors, array('required')) ?><br/> <?= Helper\form_text('username', $values, $errors, array('required')) ?><br/>
@ -62,6 +61,8 @@
<?= Helper\form_checkbox('nocontent', t('Do not fetch the content of articles'), 1, isset($values['nocontent']) && $values['nocontent'] == 1) ?><br /> <?= Helper\form_checkbox('nocontent', t('Do not fetch the content of articles'), 1, isset($values['nocontent']) && $values['nocontent'] == 1) ?><br />
<?= Helper\form_checkbox('favicons', t('Download favicons'), 1, isset($values['favicons']) && $values['favicons'] == 1) ?><br />
<div class="form-actions"> <div class="form-actions">
<input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/> <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/>
</div> </div>

View File

@ -28,6 +28,7 @@
'offset' => $offset, 'offset' => $offset,
'hide' => false, 'hide' => false,
'display_mode' => $display_mode, 'display_mode' => $display_mode,
'favicons' => $favicons,
)) ?> )) ?>
<?php endforeach ?> <?php endforeach ?>

View File

@ -15,7 +15,14 @@
<section class="items" id="listing"> <section class="items" id="listing">
<?php foreach ($items as $item): ?> <?php foreach ($items as $item): ?>
<?= \PicoFarad\Template\load('item', array('item' => $item, 'menu' => $menu, 'offset' => $offset, 'hide' => true, 'display_mode' => $display_mode)) ?> <?= \PicoFarad\Template\load('item', array(
'item' => $item,
'menu' => $menu,
'offset' => $offset,
'hide' => true,
'display_mode' => $display_mode,
'favicons' => $favicons,
)) ?>
<?php endforeach ?> <?php endforeach ?>
<?= \PicoFarad\Template\load('paging', array('menu' => $menu, 'nb_items' => $nb_items, 'items_per_page' => $items_per_page, 'offset' => $offset, 'order' => $order, 'direction' => $direction)) ?> <?= \PicoFarad\Template\load('paging', array('menu' => $menu, 'nb_items' => $nb_items, 'items_per_page' => $items_per_page, 'offset' => $offset, 'order' => $order, 'direction' => $direction)) ?>

View File

@ -10,6 +10,7 @@
<h2 <?= Helper\isRTL($item) ? 'dir="rtl"' : '' ?>> <h2 <?= Helper\isRTL($item) ? 'dir="rtl"' : '' ?>>
<span class="bookmark-icon"></span> <span class="bookmark-icon"></span>
<span class="read-icon"></span> <span class="read-icon"></span>
<?= Helper\favicon($favicons, $item['feed_id']) ?>
<a <a
href="?action=show&amp;menu=<?= $menu ?>&amp;id=<?= $item['id'] ?>" href="?action=show&amp;menu=<?= $menu ?>&amp;id=<?= $item['id'] ?>"
class="show" class="show"

View File

@ -44,13 +44,6 @@
data-action="bookmark" data-action="bookmark"
></a> ></a>
</li> </li>
<li>
<a
href="?action=mark-item-unread&amp;id=<?= $item['id'] ?>&amp;redirect=<?= $menu ?>&amp;feed_id=<?= $item['feed_id'] ?>"
title="<?= t('mark as unread') ?>"
class="read-icon icon"
></a>
</li>
<li> <li>
<a href="?action=feed-items&amp;feed_id=<?= $feed['id'] ?>"><?= Helper\escape($feed['title']) ?></a> <a href="?action=feed-items&amp;feed_id=<?= $feed['id'] ?>"><?= Helper\escape($feed['title']) ?></a>
</li> </li>

View File

@ -22,6 +22,7 @@
'offset' => $offset, 'offset' => $offset,
'hide' => true, 'hide' => true,
'display_mode' => $display_mode, 'display_mode' => $display_mode,
'favicons' => $favicons,
)) ?> )) ?>
<?php endforeach ?> <?php endforeach ?>

2
vendor/autoload.php vendored
View File

@ -4,4 +4,4 @@
require_once __DIR__ . '/composer' . '/autoload_real.php'; require_once __DIR__ . '/composer' . '/autoload_real.php';
return ComposerAutoloaderInit2e47cecea56754de3b457018a8eee985::getLoader(); return ComposerAutoloaderInita5bf9ee28a13532106d0068a171b06ab::getLoader();

View File

@ -2,7 +2,7 @@
// autoload_real.php @generated by Composer // autoload_real.php @generated by Composer
class ComposerAutoloaderInit2e47cecea56754de3b457018a8eee985 class ComposerAutoloaderInita5bf9ee28a13532106d0068a171b06ab
{ {
private static $loader; private static $loader;
@ -19,9 +19,9 @@ class ComposerAutoloaderInit2e47cecea56754de3b457018a8eee985
return self::$loader; return self::$loader;
} }
spl_autoload_register(array('ComposerAutoloaderInit2e47cecea56754de3b457018a8eee985', 'loadClassLoader'), true, true); spl_autoload_register(array('ComposerAutoloaderInita5bf9ee28a13532106d0068a171b06ab', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(); self::$loader = $loader = new \Composer\Autoload\ClassLoader();
spl_autoload_unregister(array('ComposerAutoloaderInit2e47cecea56754de3b457018a8eee985', 'loadClassLoader')); spl_autoload_unregister(array('ComposerAutoloaderInita5bf9ee28a13532106d0068a171b06ab', 'loadClassLoader'));
$map = require __DIR__ . '/autoload_namespaces.php'; $map = require __DIR__ . '/autoload_namespaces.php';
foreach ($map as $namespace => $path) { foreach ($map as $namespace => $path) {
@ -42,14 +42,14 @@ class ComposerAutoloaderInit2e47cecea56754de3b457018a8eee985
$includeFiles = require __DIR__ . '/autoload_files.php'; $includeFiles = require __DIR__ . '/autoload_files.php';
foreach ($includeFiles as $file) { foreach ($includeFiles as $file) {
composerRequire2e47cecea56754de3b457018a8eee985($file); composerRequirea5bf9ee28a13532106d0068a171b06ab($file);
} }
return $loader; return $loader;
} }
} }
function composerRequire2e47cecea56754de3b457018a8eee985($file) function composerRequirea5bf9ee28a13532106d0068a171b06ab($file)
{ {
require $file; require $file;
} }

View File

@ -162,18 +162,18 @@
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/fguillot/picoFeed.git", "url": "https://github.com/fguillot/picoFeed.git",
"reference": "b3f2202845be5895ce818f1393cdd28b0aa1b8cb" "reference": "e785e62ee79a02478e9691cc0cc50e689f2bf4a4"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/fguillot/picoFeed/zipball/b3f2202845be5895ce818f1393cdd28b0aa1b8cb", "url": "https://api.github.com/repos/fguillot/picoFeed/zipball/e785e62ee79a02478e9691cc0cc50e689f2bf4a4",
"reference": "b3f2202845be5895ce818f1393cdd28b0aa1b8cb", "reference": "e785e62ee79a02478e9691cc0cc50e689f2bf4a4",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=5.3.0" "php": ">=5.3.0"
}, },
"time": "2014-12-24 20:46:58", "time": "2014-12-24 22:35:22",
"type": "library", "type": "library",
"installation-source": "dist", "installation-source": "dist",
"autoload": { "autoload": {

View File

@ -20,6 +20,20 @@ use PicoFeed\Parser\XmlParser;
*/ */
class Favicon class Favicon
{ {
/**
* Valid types for favicon (supported by browsers)
*
* @access private
* @var array
*/
private $types = array(
'image/png',
'image/gif',
'image/x-icon',
'image/jpeg',
'image/jpg',
);
/** /**
* Config class instance * Config class instance
* *
@ -74,7 +88,13 @@ class Favicon
*/ */
public function getType() public function getType()
{ {
return $this->content_type; foreach ($this->types as $type) {
if (strpos($this->content_type, $type) === 0) {
return $type;
}
}
return 'image/x-icon';
} }
/** /**
@ -87,7 +107,7 @@ class Favicon
{ {
return sprintf( return sprintf(
'data:%s;base64,%s', 'data:%s;base64,%s',
$this->content_type, $this->getType(),
base64_encode($this->content) base64_encode($this->content)
); );
} }

View File

@ -155,4 +155,12 @@ class FaviconTest extends PHPUnit_Framework_TestCase
$this->assertEquals($expected, $favicon->getDataUri()); $this->assertEquals($expected, $favicon->getDataUri());
} }
public function testDataUriWithBadContentType()
{
$favicon = new Favicon;
$this->assertNotEmpty($favicon->find('http://www.lemonde.fr/'));
$expected = 'data:image/x-icon;base64,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';
$this->assertEquals($expected, $favicon->getDataUri());
}
} }