2014-10-30 02:28:23 +01:00
|
|
|
<?php
|
|
|
|
|
2016-08-19 03:02:49 +02:00
|
|
|
require __DIR__.'/../app/common.php';
|
2014-10-30 02:28:23 +01:00
|
|
|
|
2016-08-25 03:25:24 +02:00
|
|
|
use Miniflux\Handler;
|
|
|
|
use Miniflux\Model;
|
|
|
|
use Miniflux\Model\Feed;
|
|
|
|
use Miniflux\Model\Group;
|
2014-10-30 02:28:23 +01:00
|
|
|
use PicoDb\Database;
|
|
|
|
|
|
|
|
// Route handler
|
|
|
|
function route($name, Closure $callback = null)
|
|
|
|
{
|
|
|
|
static $routes = array();
|
|
|
|
|
|
|
|
if ($callback !== null) {
|
|
|
|
$routes[$name] = $callback;
|
2016-04-18 01:44:45 +02:00
|
|
|
} elseif (isset($routes[$name])) {
|
2014-10-30 02:28:23 +01:00
|
|
|
$routes[$name]();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Serialize the payload in Json (XML is not supported)
|
|
|
|
function response(array $response)
|
|
|
|
{
|
|
|
|
header('Content-Type: application/json');
|
|
|
|
echo json_encode($response);
|
|
|
|
exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fever authentication
|
|
|
|
function auth()
|
|
|
|
{
|
2014-12-29 22:52:36 +01:00
|
|
|
if (! empty($_GET['database'])) {
|
2015-01-18 00:53:40 +01:00
|
|
|
// Return unauthorized if the requested database could not be found
|
2015-01-17 19:35:59 +01:00
|
|
|
if (! Model\Database\select($_GET['database'])) {
|
|
|
|
return array(
|
|
|
|
'api_version' => 3,
|
|
|
|
'auth' => 0,
|
|
|
|
);
|
|
|
|
}
|
2014-11-11 17:01:24 +01:00
|
|
|
}
|
2014-12-29 22:52:36 +01:00
|
|
|
|
2015-08-15 03:33:39 +02:00
|
|
|
$credentials = Database::getInstance('db')->hashtable('settings')->get('username', 'fever_token');
|
2014-10-30 02:28:23 +01:00
|
|
|
$api_key = md5($credentials['username'].':'.$credentials['fever_token']);
|
|
|
|
|
|
|
|
$response = array(
|
|
|
|
'api_version' => 3,
|
2016-04-18 01:44:45 +02:00
|
|
|
'auth' => (int) (isset($_POST['api_key']) && (strcasecmp($_POST['api_key'], $api_key) === 0)),
|
2014-10-30 02:28:23 +01:00
|
|
|
'last_refreshed_on_time' => time(),
|
|
|
|
);
|
|
|
|
|
|
|
|
return $response;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Call: ?api&groups
|
2016-04-18 01:44:45 +02:00
|
|
|
route('groups', function () {
|
2014-10-30 02:28:23 +01:00
|
|
|
|
|
|
|
$response = auth();
|
|
|
|
|
|
|
|
if ($response['auth']) {
|
2015-08-05 01:01:21 +02:00
|
|
|
$response['groups'] = Group\get_all();
|
2015-08-05 01:01:21 +02:00
|
|
|
$response['feeds_groups'] = array();
|
2015-08-05 01:01:21 +02:00
|
|
|
$group_map = Group\get_map();
|
|
|
|
|
|
|
|
foreach ($group_map as $group_id => $feed_ids) {
|
|
|
|
$response['feeds_groups'][] = array(
|
|
|
|
'group_id' => $group_id,
|
|
|
|
'feed_ids' => implode(',', $feed_ids)
|
|
|
|
);
|
|
|
|
}
|
2014-10-30 02:28:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
response($response);
|
|
|
|
});
|
|
|
|
|
|
|
|
// Call: ?api&feeds
|
2016-04-18 01:44:45 +02:00
|
|
|
route('feeds', function () {
|
2014-10-30 02:28:23 +01:00
|
|
|
|
|
|
|
$response = auth();
|
|
|
|
|
|
|
|
if ($response['auth']) {
|
|
|
|
$response['feeds'] = array();
|
2015-08-05 01:01:21 +02:00
|
|
|
$response['feeds_groups'] = array();
|
|
|
|
|
2014-10-30 02:28:23 +01:00
|
|
|
$feeds = Feed\get_all();
|
|
|
|
|
|
|
|
foreach ($feeds as $feed) {
|
|
|
|
$response['feeds'][] = array(
|
|
|
|
'id' => (int) $feed['id'],
|
2015-03-23 09:01:54 +01:00
|
|
|
'favicon_id' => (int) $feed['id'],
|
2014-10-30 02:28:23 +01:00
|
|
|
'title' => $feed['title'],
|
|
|
|
'url' => $feed['feed_url'],
|
|
|
|
'site_url' => $feed['site_url'],
|
|
|
|
'is_spark' => 0,
|
|
|
|
'last_updated_on_time' => $feed['last_checked'] ?: time(),
|
|
|
|
);
|
|
|
|
}
|
2015-08-05 01:01:21 +02:00
|
|
|
|
|
|
|
$group_map = Group\get_map();
|
|
|
|
foreach ($group_map as $group_id => $feed_ids) {
|
|
|
|
$response['feeds_groups'][] = array(
|
|
|
|
'group_id' => $group_id,
|
|
|
|
'feed_ids' => implode(',', $feed_ids)
|
|
|
|
);
|
|
|
|
}
|
2014-10-30 02:28:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
response($response);
|
|
|
|
});
|
|
|
|
|
|
|
|
// Call: ?api&favicons
|
2016-04-18 01:44:45 +02:00
|
|
|
route('favicons', function () {
|
2014-10-30 02:28:23 +01:00
|
|
|
|
|
|
|
$response = auth();
|
|
|
|
|
|
|
|
if ($response['auth']) {
|
2015-08-15 03:33:39 +02:00
|
|
|
$favicons = Database::getInstance('db')
|
2015-03-23 09:01:54 +01:00
|
|
|
->table('favicons')
|
|
|
|
->columns(
|
|
|
|
'feed_id',
|
2015-12-07 14:18:27 +01:00
|
|
|
'file',
|
|
|
|
'type'
|
2015-03-23 09:01:54 +01:00
|
|
|
)
|
|
|
|
->findAll();
|
|
|
|
|
2014-10-30 02:28:23 +01:00
|
|
|
$response['favicons'] = array();
|
2015-03-23 09:01:54 +01:00
|
|
|
foreach ($favicons as $favicon) {
|
|
|
|
$response['favicons'][] = array(
|
|
|
|
'id' => (int) $favicon['feed_id'],
|
2015-12-07 14:18:27 +01:00
|
|
|
'data' => 'data:'.$favicon['type'].';base64,'.base64_encode(file_get_contents(FAVICON_DIRECTORY.DIRECTORY_SEPARATOR.$favicon['file']))
|
2015-03-23 09:01:54 +01:00
|
|
|
);
|
|
|
|
}
|
2014-10-30 02:28:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
response($response);
|
|
|
|
});
|
|
|
|
|
|
|
|
// Call: ?api&items
|
2016-04-18 01:44:45 +02:00
|
|
|
route('items', function () {
|
2014-10-30 02:28:23 +01:00
|
|
|
|
|
|
|
$response = auth();
|
|
|
|
|
|
|
|
if ($response['auth']) {
|
2015-08-15 03:33:39 +02:00
|
|
|
$query = Database::getInstance('db')
|
2014-11-09 04:33:50 +01:00
|
|
|
->table('items')
|
|
|
|
->columns(
|
|
|
|
'rowid',
|
|
|
|
'feed_id',
|
|
|
|
'title',
|
|
|
|
'author',
|
|
|
|
'content',
|
|
|
|
'url',
|
|
|
|
'updated',
|
|
|
|
'status',
|
|
|
|
'bookmark'
|
2015-03-23 08:33:32 +01:00
|
|
|
)
|
|
|
|
->limit(50)
|
|
|
|
->neq('status', 'removed');
|
2014-10-30 02:28:23 +01:00
|
|
|
|
|
|
|
if (isset($_GET['since_id']) && is_numeric($_GET['since_id'])) {
|
2014-11-09 04:33:50 +01:00
|
|
|
$items = $query->gt('rowid', $_GET['since_id'])
|
|
|
|
->asc('rowid');
|
2016-04-18 01:44:45 +02:00
|
|
|
} elseif (! empty($_GET['with_ids'])) {
|
2014-10-30 02:28:23 +01:00
|
|
|
$query->in('rowid', explode(',', $_GET['with_ids']));
|
|
|
|
}
|
|
|
|
|
|
|
|
$items = $query->findAll();
|
|
|
|
$response['items'] = array();
|
|
|
|
|
|
|
|
foreach ($items as $item) {
|
|
|
|
$response['items'][] = array(
|
|
|
|
'id' => (int) $item['rowid'],
|
|
|
|
'feed_id' => (int) $item['feed_id'],
|
|
|
|
'title' => $item['title'],
|
|
|
|
'author' => $item['author'],
|
|
|
|
'html' => $item['content'],
|
|
|
|
'url' => $item['url'],
|
|
|
|
'is_saved' => (int) $item['bookmark'],
|
|
|
|
'is_read' => $item['status'] == 'read' ? 1 : 0,
|
|
|
|
'created_on_time' => $item['updated'],
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2015-08-15 03:33:39 +02:00
|
|
|
$response['total_items'] = Database::getInstance('db')
|
2014-10-30 02:28:23 +01:00
|
|
|
->table('items')
|
|
|
|
->neq('status', 'removed')
|
|
|
|
->count();
|
|
|
|
}
|
|
|
|
|
|
|
|
response($response);
|
|
|
|
});
|
|
|
|
|
|
|
|
// Call: ?api&links
|
2016-04-18 01:44:45 +02:00
|
|
|
route('links', function () {
|
2014-10-30 02:28:23 +01:00
|
|
|
|
|
|
|
$response = auth();
|
|
|
|
|
|
|
|
if ($response['auth']) {
|
|
|
|
$response['links'] = array();
|
|
|
|
}
|
|
|
|
|
|
|
|
response($response);
|
|
|
|
});
|
|
|
|
|
|
|
|
// Call: ?api&unread_item_ids
|
2016-04-18 01:44:45 +02:00
|
|
|
route('unread_item_ids', function () {
|
2014-10-30 02:28:23 +01:00
|
|
|
|
|
|
|
$response = auth();
|
|
|
|
|
|
|
|
if ($response['auth']) {
|
2015-08-15 03:33:39 +02:00
|
|
|
$item_ids = Database::getInstance('db')
|
2014-10-30 02:28:23 +01:00
|
|
|
->table('items')
|
|
|
|
->eq('status', 'unread')
|
|
|
|
->findAllByColumn('rowid');
|
|
|
|
|
|
|
|
$response['unread_item_ids'] = implode(',', $item_ids);
|
|
|
|
}
|
|
|
|
|
|
|
|
response($response);
|
|
|
|
});
|
|
|
|
|
|
|
|
// Call: ?api&saved_item_ids
|
2016-04-18 01:44:45 +02:00
|
|
|
route('saved_item_ids', function () {
|
2014-10-30 02:28:23 +01:00
|
|
|
|
|
|
|
$response = auth();
|
|
|
|
|
|
|
|
if ($response['auth']) {
|
2015-08-15 03:33:39 +02:00
|
|
|
$item_ids = Database::getInstance('db')
|
2014-10-30 02:28:23 +01:00
|
|
|
->table('items')
|
|
|
|
->eq('bookmark', 1)
|
|
|
|
->findAllByColumn('rowid');
|
|
|
|
|
|
|
|
$response['saved_item_ids'] = implode(',', $item_ids);
|
|
|
|
}
|
|
|
|
|
|
|
|
response($response);
|
|
|
|
});
|
|
|
|
|
|
|
|
// handle write items
|
2016-04-18 01:44:45 +02:00
|
|
|
route('write_items', function () {
|
2014-10-30 02:28:23 +01:00
|
|
|
|
|
|
|
$response = auth();
|
|
|
|
|
|
|
|
if ($response['auth']) {
|
2015-08-15 03:33:39 +02:00
|
|
|
$query = Database::getInstance('db')
|
2014-10-30 02:28:23 +01:00
|
|
|
->table('items')
|
|
|
|
->eq('rowid', $_POST['id']);
|
|
|
|
|
|
|
|
if ($_POST['as'] === 'saved') {
|
|
|
|
$query->update(array('bookmark' => 1));
|
2015-05-03 14:56:41 +02:00
|
|
|
|
|
|
|
// Send bookmark to third-party services if enabled
|
2015-08-15 03:33:39 +02:00
|
|
|
$item_id = Database::getInstance('db')
|
2015-05-03 14:56:41 +02:00
|
|
|
->table('items')
|
|
|
|
->eq('rowid', $_POST['id'])
|
|
|
|
->findOneColumn('id');
|
|
|
|
|
2016-08-19 04:53:52 +02:00
|
|
|
Handler\Service\sync($item_id);
|
2016-04-18 01:44:45 +02:00
|
|
|
} elseif ($_POST['as'] === 'unsaved') {
|
2014-10-30 02:28:23 +01:00
|
|
|
$query->update(array('bookmark' => 0));
|
2016-04-18 01:44:45 +02:00
|
|
|
} elseif ($_POST['as'] === 'read') {
|
2014-10-30 02:28:23 +01:00
|
|
|
$query->update(array('status' => 'read'));
|
2016-04-18 01:44:45 +02:00
|
|
|
} elseif ($_POST['as'] === 'unread') {
|
2014-10-30 02:28:23 +01:00
|
|
|
$query->update(array('status' => 'unread'));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
response($response);
|
|
|
|
});
|
|
|
|
|
|
|
|
// handle write feeds
|
2016-04-18 01:44:45 +02:00
|
|
|
route('write_feeds', function () {
|
2014-10-30 02:28:23 +01:00
|
|
|
|
|
|
|
$response = auth();
|
|
|
|
|
|
|
|
if ($response['auth']) {
|
2015-08-15 03:33:39 +02:00
|
|
|
Database::getInstance('db')
|
2014-10-30 02:28:23 +01:00
|
|
|
->table('items')
|
|
|
|
->eq('feed_id', $_POST['id'])
|
|
|
|
->lte('updated', $_POST['before'])
|
2015-08-05 01:01:21 +02:00
|
|
|
->update(array('status' => 'read'));
|
2014-10-30 02:28:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
response($response);
|
|
|
|
});
|
|
|
|
|
|
|
|
// handle write groups
|
2016-04-18 01:44:45 +02:00
|
|
|
route('write_groups', function () {
|
2014-10-30 02:28:23 +01:00
|
|
|
|
|
|
|
$response = auth();
|
|
|
|
|
|
|
|
if ($response['auth']) {
|
2015-08-15 03:33:39 +02:00
|
|
|
$db = Database::getInstance('db')
|
2015-08-05 01:01:21 +02:00
|
|
|
->table('items')
|
|
|
|
->lte('updated', $_POST['before']);
|
2014-10-30 02:28:23 +01:00
|
|
|
|
2015-08-05 01:01:21 +02:00
|
|
|
if ($_POST['id'] > 0) {
|
|
|
|
$db->in('feed_id', Model\Group\get_feeds_by_group($_POST['id']));
|
|
|
|
}
|
|
|
|
|
|
|
|
$db->update(array('status' => 'read'));
|
2014-10-30 02:28:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
response($response);
|
|
|
|
});
|
|
|
|
|
|
|
|
foreach (array_keys($_GET) as $action) {
|
|
|
|
route($action);
|
|
|
|
}
|
|
|
|
|
2014-11-06 19:54:12 +01:00
|
|
|
if (! empty($_POST['mark']) && ! empty($_POST['as'])
|
2016-05-03 10:45:07 +02:00
|
|
|
&& filter_input(INPUT_POST, 'id', FILTER_VALIDATE_INT, array('options' => array('default' => null, 'min_range' => -1))) !== null) {
|
2014-10-30 02:28:23 +01:00
|
|
|
if ($_POST['mark'] === 'item') {
|
|
|
|
route('write_items');
|
2016-04-18 01:44:45 +02:00
|
|
|
} elseif ($_POST['mark'] === 'feed' && ! empty($_POST['before'])) {
|
2014-10-30 02:28:23 +01:00
|
|
|
route('write_feeds');
|
2016-04-18 01:44:45 +02:00
|
|
|
} elseif ($_POST['mark'] === 'group' && ! empty($_POST['before'])) {
|
2014-10-30 02:28:23 +01:00
|
|
|
route('write_groups');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
response(auth());
|