Add Instapaper support

This commit is contained in:
Frédéric Guillot 2014-12-24 13:50:20 -05:00
parent 635e3bb813
commit b2e3116350
19 changed files with 207 additions and 26 deletions

View File

@ -145,6 +145,14 @@ form {
border-left: 2px dotted #ddd; border-left: 2px dotted #ddd;
} }
form h3 {
font-weight: bold;
}
form h3:first-child {
margin-top: 0;
}
label { label {
cursor: pointer; cursor: pointer;
display: block; display: block;

View File

@ -224,7 +224,7 @@ Router\get_action('services', function() {
// Update bookmark services // Update bookmark services
Router\post_action('services', function() { Router\post_action('services', function() {
$values = Request\values() + array('pinboard_enabled' => 0); $values = Request\values() + array('pinboard_enabled' => 0, 'instapaper_enabled' => 0);
Model\Config\check_csrf_values($values); Model\Config\check_csrf_values($values);
if (Model\Config\save($values)) { if (Model\Config\save($values)) {

View File

@ -222,4 +222,9 @@ return array(
// 'Send bookmarks to Pinboard' => '', // 'Send bookmarks to Pinboard' => '',
// 'Pinboard API token' => '', // 'Pinboard API token' => '',
// 'Pinboard tags' => '', // 'Pinboard tags' => '',
// 'Instapaper username' => '',
// 'Instapaper password' => '',
// 'Instapaper' => '',
// 'Pinboard' => '',
// 'Send bookmarks to Instapaper' => '',
); );

View File

@ -222,4 +222,9 @@ return array(
// 'Send bookmarks to Pinboard' => '', // 'Send bookmarks to Pinboard' => '',
// 'Pinboard API token' => '', // 'Pinboard API token' => '',
// 'Pinboard tags' => '', // 'Pinboard tags' => '',
// 'Instapaper username' => '',
// 'Instapaper password' => '',
// 'Instapaper' => '',
// 'Pinboard' => '',
// 'Send bookmarks to Instapaper' => '',
); );

View File

@ -222,4 +222,9 @@ return array(
// 'Send bookmarks to Pinboard' => '', // 'Send bookmarks to Pinboard' => '',
// 'Pinboard API token' => '', // 'Pinboard API token' => '',
// 'Pinboard tags' => '', // 'Pinboard tags' => '',
// 'Instapaper username' => '',
// 'Instapaper password' => '',
// 'Instapaper' => '',
// 'Pinboard' => '',
// 'Send bookmarks to Instapaper' => '',
); );

View File

@ -222,4 +222,9 @@ return array(
'Send bookmarks to Pinboard' => 'Envoyer les favoris vers Pinboard', 'Send bookmarks to Pinboard' => 'Envoyer les favoris vers Pinboard',
'Pinboard API token' => 'Jeton d\'accès à l\'API de Pinboard', 'Pinboard API token' => 'Jeton d\'accès à l\'API de Pinboard',
'Pinboard tags' => 'Tags Pinboard', 'Pinboard tags' => 'Tags Pinboard',
'Instapaper username' => 'Utilisateur Instapaper',
'Instapaper password' => 'Mot de passe Instapaper',
'Instapaper' => 'Instapaper',
'Pinboard' => 'Pinboard',
'Send bookmarks to Instapaper' => 'Envoyer les favoris vers Instapaper',
); );

View File

@ -222,4 +222,9 @@ return array(
// 'Send bookmarks to Pinboard' => '', // 'Send bookmarks to Pinboard' => '',
// 'Pinboard API token' => '', // 'Pinboard API token' => '',
// 'Pinboard tags' => '', // 'Pinboard tags' => '',
// 'Instapaper username' => '',
// 'Instapaper password' => '',
// 'Instapaper' => '',
// 'Pinboard' => '',
// 'Send bookmarks to Instapaper' => '',
); );

View File

@ -222,4 +222,9 @@ return array(
// 'Send bookmarks to Pinboard' => '', // 'Send bookmarks to Pinboard' => '',
// 'Pinboard API token' => '', // 'Pinboard API token' => '',
// 'Pinboard tags' => '', // 'Pinboard tags' => '',
// 'Instapaper username' => '',
// 'Instapaper password' => '',
// 'Instapaper' => '',
// 'Pinboard' => '',
// 'Send bookmarks to Instapaper' => '',
); );

View File

@ -222,4 +222,9 @@ return array(
// 'Send bookmarks to Pinboard' => '', // 'Send bookmarks to Pinboard' => '',
// 'Pinboard API token' => '', // 'Pinboard API token' => '',
// 'Pinboard tags' => '', // 'Pinboard tags' => '',
// 'Instapaper username' => '',
// 'Instapaper password' => '',
// 'Instapaper' => '',
// 'Pinboard' => '',
// 'Send bookmarks to Instapaper' => '',
); );

View File

@ -9,7 +9,7 @@ use PicoDb\Database;
use PicoFeed\Config\Config as ReaderConfig; use PicoFeed\Config\Config as ReaderConfig;
use PicoFeed\Logging\Logger; use PicoFeed\Logging\Logger;
const DB_VERSION = 31; const DB_VERSION = 32;
const HTTP_USER_AGENT = 'Miniflux (http://miniflux.net)'; const HTTP_USER_AGENT = 'Miniflux (http://miniflux.net)';
// Get PicoFeed config // Get PicoFeed config
@ -303,7 +303,10 @@ function get_all()
'auto_update_url', 'auto_update_url',
'pinboard_enabled', 'pinboard_enabled',
'pinboard_token', 'pinboard_token',
'pinboard_tags' 'pinboard_tags',
'instapaper_enabled',
'instapaper_username',
'instapaper_password'
) )
->findOne(); ->findOne();
} }

View File

@ -5,6 +5,13 @@ namespace Schema;
use PDO; use PDO;
use Model\Config; use Model\Config;
function version_32($pdo)
{
$pdo->exec('ALTER TABLE config ADD COLUMN instapaper_enabled INTEGER DEFAULT 0');
$pdo->exec('ALTER TABLE config ADD COLUMN instapaper_username TEXT');
$pdo->exec('ALTER TABLE config ADD COLUMN instapaper_password TEXT');
}
function version_31($pdo) function version_31($pdo)
{ {
$pdo->exec('ALTER TABLE config ADD COLUMN pinboard_enabled INTEGER DEFAULT 0'); $pdo->exec('ALTER TABLE config ADD COLUMN pinboard_enabled INTEGER DEFAULT 0');

View File

@ -10,35 +10,69 @@ use PicoFeed\Client\ClientException;
// Sync the item to an external service // Sync the item to an external service
function push($item_id) function push($item_id)
{ {
$item = Item\get($item_id);
if ((bool) Config\get('pinboard_enabled')) { if ((bool) Config\get('pinboard_enabled')) {
pinboard_add(Item\get($item_id)); pinboard_add($item);
} }
if ((bool) Config\get('instapaper_enabled')) {
instapaper_add($item);
}
}
// Send item to Instapaper
function instapaper_add(array $item)
{
$params = array(
'username' => Config\get('instapaper_username'),
'password' => Config\get('instapaper_password'),
'url' => $item['url'],
'title' => $item['title'],
);
$url = 'https://www.instapaper.com/api/add?'.http_build_query($params);
$client = api_call($url);
if ($client !== false) {
return $client->getStatusCode() === 201;
}
return false;
} }
// Add a Pinboard bookmark // Add a Pinboard bookmark
function pinboard_add(array $item) function pinboard_add(array $item)
{ {
return pinboard_api('/posts/add', array( $params = array(
'auth_token' => Config\get('pinboard_token'),
'format' => 'json',
'url' => $item['url'], 'url' => $item['url'],
'description' => $item['title'], 'description' => $item['title'],
'tags' => Config\get('pinboard_tags'), 'tags' => Config\get('pinboard_tags'),
)); );
$url = 'https://api.pinboard.in/v1/posts/add?'.http_build_query($params);
$client = api_call($url);
if ($client !== false) {
$response = json_decode($client->getContent(), true);
return is_array($response) && $response['result_code'] === 'done';
} }
// Pinboard API client return false;
function pinboard_api($method, array $params) }
// HTTP client
function api_call($url)
{ {
try { try {
$params += array('auth_token' => Config\get('pinboard_token'), 'format' => 'json');
$url = 'https://api.pinboard.in/v1'.$method.'?'.http_build_query($params);
$client = Client::getInstance(); $client = Client::getInstance();
$client->setUserAgent(Config\HTTP_USER_AGENT); $client->setUserAgent(Config\HTTP_USER_AGENT);
$client->execute($url); $client->execute($url);
return $client;
$response = json_decode($client->getContent(), true);
return is_array($response) && $response['result_code'] === 'done';
} }
catch (ClientException $e) { catch (ClientException $e) {
return false; return false;

View File

@ -9,8 +9,10 @@
</ul> </ul>
</div> </div>
<section> <section>
<form method="post" action="?action=services" autocomplete="off"> <form method="post" action="?action=services" autocomplete="off">
<h3><?= t('Pinboard') ?></h3>
<?= Helper\form_hidden('csrf', $values) ?> <?= Helper\form_hidden('csrf', $values) ?>
<?= Helper\form_checkbox('pinboard_enabled', t('Send bookmarks to Pinboard'), 1, isset($values['pinboard_enabled']) && $values['pinboard_enabled'] == 1) ?><br /> <?= Helper\form_checkbox('pinboard_enabled', t('Send bookmarks to Pinboard'), 1, isset($values['pinboard_enabled']) && $values['pinboard_enabled'] == 1) ?><br />
@ -19,7 +21,17 @@
<?= Helper\form_text('pinboard_token', $values, $errors) ?><br/> <?= Helper\form_text('pinboard_token', $values, $errors) ?><br/>
<?= Helper\form_label(t('Pinboard tags'), 'pinboard_tags') ?> <?= Helper\form_label(t('Pinboard tags'), 'pinboard_tags') ?>
<?= Helper\form_text('pinboard_tags', $values, $errors) ?><br/> <?= Helper\form_text('pinboard_tags', $values, $errors) ?>
<h3><?= t('Instapaper') ?></h3>
<?= Helper\form_checkbox('instapaper_enabled', t('Send bookmarks to Instapaper'), 1, isset($values['instapaper_enabled']) && $values['instapaper_enabled'] == 1) ?><br />
<?= Helper\form_label(t('Instapaper username'), 'instapaper_username') ?>
<?= Helper\form_text('instapaper_username', $values, $errors) ?><br/>
<?= Helper\form_label(t('Instapaper password'), 'instapaper_password') ?>
<?= Helper\form_password('instapaper_password', $values, $errors) ?><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"/>

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 ComposerAutoloaderInit75276362b3cf9253f7e5cb38a60a4693::getLoader(); return ComposerAutoloaderInite2d22b082480fbe8c7c1ceae6d7cbe85::getLoader();

View File

@ -2,7 +2,7 @@
// autoload_real.php @generated by Composer // autoload_real.php @generated by Composer
class ComposerAutoloaderInit75276362b3cf9253f7e5cb38a60a4693 class ComposerAutoloaderInite2d22b082480fbe8c7c1ceae6d7cbe85
{ {
private static $loader; private static $loader;
@ -19,9 +19,9 @@ class ComposerAutoloaderInit75276362b3cf9253f7e5cb38a60a4693
return self::$loader; return self::$loader;
} }
spl_autoload_register(array('ComposerAutoloaderInit75276362b3cf9253f7e5cb38a60a4693', 'loadClassLoader'), true, true); spl_autoload_register(array('ComposerAutoloaderInite2d22b082480fbe8c7c1ceae6d7cbe85', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(); self::$loader = $loader = new \Composer\Autoload\ClassLoader();
spl_autoload_unregister(array('ComposerAutoloaderInit75276362b3cf9253f7e5cb38a60a4693', 'loadClassLoader')); spl_autoload_unregister(array('ComposerAutoloaderInite2d22b082480fbe8c7c1ceae6d7cbe85', '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 ComposerAutoloaderInit75276362b3cf9253f7e5cb38a60a4693
$includeFiles = require __DIR__ . '/autoload_files.php'; $includeFiles = require __DIR__ . '/autoload_files.php';
foreach ($includeFiles as $file) { foreach ($includeFiles as $file) {
composerRequire75276362b3cf9253f7e5cb38a60a4693($file); composerRequiree2d22b082480fbe8c7c1ceae6d7cbe85($file);
} }
return $loader; return $loader;
} }
} }
function composerRequire75276362b3cf9253f7e5cb38a60a4693($file) function composerRequiree2d22b082480fbe8c7c1ceae6d7cbe85($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": "2d538a140020794fad248ccc0f88bb29263a61d6" "reference": "eefd3f78268627e07ccf31c71cadd4c5ec0955bd"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/fguillot/picoFeed/zipball/2d538a140020794fad248ccc0f88bb29263a61d6", "url": "https://api.github.com/repos/fguillot/picoFeed/zipball/eefd3f78268627e07ccf31c71cadd4c5ec0955bd",
"reference": "2d538a140020794fad248ccc0f88bb29263a61d6", "reference": "eefd3f78268627e07ccf31c71cadd4c5ec0955bd",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=5.3.0" "php": ">=5.3.0"
}, },
"time": "2014-12-24 02:16:53", "time": "2014-12-24 18:41:58",
"type": "library", "type": "library",
"installation-source": "dist", "installation-source": "dist",
"autoload": { "autoload": {

View File

@ -85,6 +85,22 @@ abstract class Client
*/ */
protected $proxy_password = ''; protected $proxy_password = '';
/**
* Basic auth username
*
* @access protected
* @var string
*/
protected $username = '';
/**
* Basic auth password
*
* @access protected
* @var string
*/
protected $password = '';
/** /**
* Client connection timeout * Client connection timeout
* *
@ -133,6 +149,14 @@ abstract class Client
*/ */
protected $max_body_size = 2097152; // 2MB protected $max_body_size = 2097152; // 2MB
/**
* HTTP response status code
*
* @access protected
* @var integer
*/
protected $status_code = 0;
/** /**
* Do the HTTP request * Do the HTTP request
* *
@ -180,6 +204,7 @@ abstract class Client
$response = $this->doRequest(); $response = $this->doRequest();
$this->status_code = $response['status'];
$this->handleNotModifiedResponse($response); $this->handleNotModifiedResponse($response);
$this->handleNotFoundResponse($response); $this->handleNotFoundResponse($response);
$this->handleNormalResponse($response); $this->handleNormalResponse($response);
@ -415,6 +440,17 @@ abstract class Client
return $this; return $this;
} }
/**
* Get the HTTP response status code
*
* @access public
* @return integer
*/
public function getStatusCode()
{
return $this->status_code;
}
/** /**
* Get the body of the HTTP response * Get the body of the HTTP response
* *
@ -563,6 +599,32 @@ abstract class Client
return $this; return $this;
} }
/**
* Set the username
*
* @access public
* @param string $username Basic Auth username
* @return \PicoFeed\Client\Client
*/
public function setUsername($username)
{
$this->username = $username ?: $this->username;
return $this;
}
/**
* Set the password
*
* @access public
* @param string $password Basic Auth Password
* @return \PicoFeed\Client\Client
*/
public function setPassword($password)
{
$this->password = $password ?: $this->password;
return $this;
}
/** /**
* Set config object * Set config object
* *

View File

@ -147,6 +147,21 @@ class Curl extends Client
return $ch; return $ch;
} }
/**
* Prepare curl auth context
*
* @access private
* @return resource $ch
*/
private function prepareAuthContext($ch)
{
if ($this->username && $this->password) {
curl_setopt($ch, CURLOPT_USERPWD, $this->username.':'.$this->password);
}
return $ch;
}
/** /**
* Prepare curl context * Prepare curl context
* *
@ -170,6 +185,7 @@ class Curl extends Client
curl_setopt($ch, CURLOPT_COOKIEFILE, 'php://memory'); curl_setopt($ch, CURLOPT_COOKIEFILE, 'php://memory');
$ch = $this->prepareProxyContext($ch); $ch = $this->prepareProxyContext($ch);
$ch = $this->prepareAuthContext($ch);
return $ch; return $ch;
} }

View File

@ -41,6 +41,10 @@ class Stream extends Client
$headers[] = 'Proxy-Authorization: Basic '.base64_encode($this->proxy_username.':'.$this->proxy_password); $headers[] = 'Proxy-Authorization: Basic '.base64_encode($this->proxy_username.':'.$this->proxy_password);
} }
if ($this->username && $this->password) {
$headers[] = 'Authorization: Basic '.base64_encode($this->username.':'.$this->password);
}
return $headers; return $headers;
} }