15 Commits
v1.2 ... v1.4.3

Author SHA1 Message Date
Torsten Stelling
b124f64191 small updates 2013-06-28 19:31:33 +02:00
Torsten Stelling
fe6a81ef3a added DEBUG_FILE to debug configuration
changed authentication call from Mr.Reader so that the reply is also uppercase, since the API-KEY comes in uppercase from clients
fixed debug output while authentication in Mr.Reader with displaying the email adress
2013-06-28 19:26:11 +02:00
Torsten Stelling
42157352af added debug section 2013-06-28 16:40:54 +02:00
Torsten Stelling
5a272dcd20 fixed DEBUG_USER to 0 2013-06-28 16:24:06 +02:00
Torsten Stelling
e7d868fad5 changed DEBUG_USER for disabling authentication without DEBUG = true 2013-06-28 16:23:10 +02:00
Torsten Stelling
2532634ac9 added version in php file, which may come handy with bug finding 2013-06-28 14:29:39 +02:00
Torsten Stelling
2eefcd7677 removed password from debug log 2013-06-28 12:56:42 +02:00
Torsten Stelling
c68878c9ea fixed Mr.Reader support
fixed debugging options
2013-06-28 11:12:08 +02:00
Torsten Stelling
3edbe9db82 added more info for the current Mr.Reader state 2013-06-27 23:24:29 +02:00
Torsten Stelling
a96310a9c0 added link to FAQ from Mr.Reader 2013-06-27 23:10:54 +02:00
Torsten Stelling
f4d09169c0 removed copyright link 2013-06-27 22:52:59 +02:00
Torsten Stelling
cabb42f722 Fixes in documentation 2013-06-27 22:41:06 +02:00
Torsten Stelling
c11edb8149 added first version which works with Mr.Reader 2.0 2013-06-27 22:38:38 +02:00
Torsten Stelling
28ecc6ab70 added first readme file 2013-06-27 22:08:39 +02:00
Torsten Stelling
0b1bcf2e2e formatting changes 2013-06-27 22:04:49 +02:00
4 changed files with 274 additions and 140 deletions

86
README.md Normal file
View File

@@ -0,0 +1,86 @@
# TinyTinyRSS Fever API plugin
## Description
This plugin is an open source module for TinyTinyRSS which simulates the Fever API for reading the RSS Feeds with your Fever clients.
- - -
* <a href="#features">Features</a>
* <a href="#download">Downloads</a>
* <a href="#supported">Supported/Tested Clients</a>
* <a href="#installation">Installation</a>
* <a href="#debug">Debugging</a>
* <a href="#license">License</a>
* <a href="#changelog">Changelog</a>
## <a name="features">Features</a>
Following Features are implemented:
* getting new RSS items
* getting starred RSS items
* setting read marker for item(s)
* setting starred marker for item(s)
* hot is **not** supported
## <a name="downloads">Downloads</a>
Please click the ```ZIP``` Button to download current version. ;)
## <a name="supported">Supported/Tested Clients</a>
These clients should be working fine with this API emulation.
* Reeder - iPhone
* Mr.Reader - iPad
## <a name="installation">Installation</a>
Upload the ```fever``` folder in the ```plugins``` folder of your TinyTinyRSS installation. Enable the plugin in the preferences and set your password for the Fever API.
See [here](http://tt-rss.org/forum/viewtopic.php?f=22&t=1981) for more detailed informations.
## <a name="debug">Debugging</a>
In the file ```fever_api.php``` there are two flags for debugging at the beginning of the file.
* ```DEBUG``` - set this to true to get a fever_debug.txt file in your root folder of the Tiny Tiny RSS installation.
* ```DEBUG_USER``` - set this to the id (from ttrss_users) of your user you would like to always authenticate on your Tiny Tiny RSS installation. The authentication process is then skipped and the api gets always authentication.
* ```DEBUG_FILE``` - set this to a filename that suits you for debugging this plugin if you need to.
## <a name="license">License</a>
Licensed under GNU GPL version 2 (<- I think this is okay for this plugin…)
## <a name="changelog">Changelog</a>
v1.0-v1.2 - 2013/5/27 - DigitalDJ version
* see this [thread](http://tt-rss.org/forum/viewtopic.php?f=22&t=1981) in the TinyTinyRSS Forum
v1.3 - 2013/6/27
* fixed several bugs in json output from the plugin
* added a small fix for Mr.Reader 2.0 so it can complete loading of all items (see [FAQ](http://www.curioustimes.de/mrreader/faq/))
* added first Mr.Reader compatiblity without marking items read/starred
* changed the field ```date_entered``` to ```updated``` for better reading experience
v1.4 - 2013/6/28
* fixed authentication with Mr.Reader 2.0
* fixed debugging options
v1.4.1 - 2013/6/28
* removed password from debug log file
v1.4.2 - 2013/6/28
* changed the ```DEBUG_USER``` evaluation a little bit for disabling authentication without DEBUG = true
v1.4.3 - 2013/6/28
* added ```DEBUG_FILE``` to debug configuration
* changed authentication call from Mr.Reader so that the reply is also uppercase, since the API-KEY comes in uppercase from clients
* fixed debug output while authentication in Mr.Reader with displaying the email adress

View File

@@ -1,27 +1,35 @@
<?php
// v1.4.3
class FeverAPI extends Handler {
const API_LEVEL = 3;
const STATUS_OK = 1;
const STATUS_ERR = 0;
// debugging only functions with JSON
const DEBUG = false; // enable if you need some debug output in your tinytinyrss root
const DEBUG_USER = 0; // your user id you need to debug - look it up in your mysql database and set it to a value bigger than 0
const DEBUG_FILE = './debug_fever.txt'; // the file for debugging output
private $xml;
// always include api_version, status as 'auth'
// output json/xml
function wrap($status, $reply)
function wrap($status, $reply)
{
$arr = array("api_version" => self::API_LEVEL,
"auth" => $status);
if ($status == self::STATUS_OK)
{
$arr["last_refreshed_on_time"] = $this->lastRefreshedOnTime()."";
if (!empty($reply) && is_array($reply))
$arr = array_merge($arr, $reply);
$arr["last_refreshed_on_time"] = $this->lastRefreshedOnTime();
}
if ($this->xml)
{
print $this->array_to_xml($arr);
@@ -29,16 +37,20 @@ class FeverAPI extends Handler {
else
{
print json_encode($arr);
}
if (self::DEBUG) {
// debug output
file_put_contents(self::DEBUG_FILE,'answer : '.json_encode($arr)."\n",FILE_APPEND);
}
}
}
// fever supports xml wrapped in <response> tags
private function array_to_xml($array, $container = 'response', $is_root = true)
{
if (!is_array($array)) return array_to_xml(array($array));
$xml = '';
if ($is_root)
{
$xml .= '<?xml version="1.0" encoding="utf-8"?>';
@@ -49,14 +61,14 @@ class FeverAPI extends Handler {
{
// make sure key is a string
$elem = $key;
if (!is_string($key) && !empty($container))
{
$elem = $container;
}
$xml .= "<{$elem}>";
if (is_array($value))
{
if (array_keys($value) !== array_keys(array_keys($value)))
@@ -72,18 +84,18 @@ class FeverAPI extends Handler {
{
$xml .= (htmlspecialchars($value, ENT_COMPAT, 'ISO-8859-1') != $value) ? "<![CDATA[{$value}]]>" : $value;
}
$xml .= "</{$elem}>";
}
if ($is_root)
{
$xml .= "</{$container}>";
}
return preg_replace('/[\x00-\x1F\x7F]/', '', $xml);
}
// every authenticated method includes last_refreshed_on_time
private function lastRefreshedOnTime()
{
@@ -91,35 +103,61 @@ class FeverAPI extends Handler {
FROM ttrss_feeds
WHERE owner_uid = " . $_SESSION["uid"] . "
ORDER BY last_updated DESC");
if ($this->dbh->num_rows($result) > 0)
if ($this->dbh->num_rows($result) > 0)
{
$last_refreshed_on_time = strtotime($this->dbh->fetch_result($result, 0, "last_updated"));
}
else
}
else
{
$last_refreshed_on_time = 0;
}
return $last_refreshed_on_time;
}
// find the user in the db with a particular api key
private function setUser()
{
if (isset($_REQUEST["api_key"]))
$apikey = isset($_REQUEST["api_key"])?$_REQUEST["api_key"]:'';
// here comes Mr.Reader special API for logging in
if ((strlen($apikey)==0)&&
(isset($_REQUEST["action"]))&&
($_REQUEST["action"]=='login')&&
(isset($_REQUEST["email"]))&&
(isset($_REQUEST["password"]))) {
$email = $_REQUEST["email"];
$password = $_REQUEST["password"];
$apikey = strtoupper(md5($email.":".db_escape_string($password)));
setcookie('fever_auth',$apikey,time()+60*60*24*30);
if (self::DEBUG) {
// debug output
$output = array();
$output['email'] = $email;
$output['apikey'] = $apikey;
file_put_contents(self::DEBUG_FILE,'auth POST: '.json_encode($output)."\n",FILE_APPEND);
}
}
if ((strlen($apikey)==0)&&isset($_REQUEST['fever_auth'])) { // override for Mr.Reader when doing some stuff
$apikey = $_REQUEST['fever_auth'];
}
if (strlen($apikey)>0)
{
$result = $this->dbh->query("SELECT owner_uid
FROM ttrss_plugin_storage
WHERE content = '" . db_escape_string('a:1:{s:8:"password";s:32:"') . db_escape_string(strtolower($_REQUEST["api_key"])) . db_escape_string('";}') . "'");
if ($this->dbh->num_rows($result) > 0)
WHERE content = '" . db_escape_string('a:1:{s:8:"password";s:32:"') . db_escape_string(strtolower($apikey)) . db_escape_string('";}') . "'");
if ($this->dbh->num_rows($result) > 0)
{
$_SESSION["uid"] = $this->dbh->fetch_result($result, 0, "owner_uid");
}
}
if (self::DEBUG_USER>0) {
$_SESSION["uid"] = self::DEBUG_USER; // always authenticate and set debug user
}
}
}
// set whether xml or json
private function setXml()
{
@@ -130,31 +168,31 @@ class FeverAPI extends Handler {
$this->xml = true;
}
}
private function flattenGroups(&$groupsToGroups, &$groups, &$groupsToTitle, $index)
{
foreach ($groupsToGroups[$index] as $item)
{
$id = substr($item, strpos($item, "-") + 1);
array_push($groups, array("id" => $id, "title" => $groupsToTitle[$id]));
array_push($groups, array("id" => intval($id), "title" => $groupsToTitle[$id]));
if (isset($groupsToGroups[$id]))
$this->flattenGroups($groupsToGroups, $groups, $groupsToTitle, $id);
}
}
function getGroups()
{
// TODO: ordering of child categories etc
$groups = array();
$result = $this->dbh->query("SELECT id, title, parent_cat
FROM ttrss_feed_categories
WHERE owner_uid = '" . db_escape_string($_SESSION["uid"]) . "'
ORDER BY order_id ASC");
$groupsToGroups = array();
$groupsToTitle = array();
while ($line = $this->dbh->fetch_assoc($result))
{
if ($line["parent_cat"] === NULL)
@@ -163,7 +201,7 @@ class FeverAPI extends Handler {
{
$groupsToGroups[-1] = array();
}
array_push($groupsToGroups[-1], $line["order_id"] . "-" . $line["id"]);
}
else
@@ -172,84 +210,85 @@ class FeverAPI extends Handler {
{
$groupsToGroups[$line["parent_cat"]] = array();
}
array_push($groupsToGroups[$line["parent_cat"]], $line["order_id"] . "-" . $line["id"]);
}
$groupsToTitle[$line["id"]] = $line["title"];
}
foreach ($groupsToGroups as $key => $value)
{
sort($value);
}
if (isset($groupsToGroups[-1]))
$this->flattenGroups($groupsToGroups, $groups, $groupsToTitle, -1);
return $groups;
}
function getFeeds()
{
$feeds = array();
$result = $this->dbh->query("SELECT id, title, feed_url, site_url, last_updated
FROM ttrss_feeds
WHERE owner_uid = '" . db_escape_string($_SESSION["uid"]) . "'
ORDER BY order_id ASC");
while ($line = $this->dbh->fetch_assoc($result))
{
array_push($feeds, array("id" => $line["id"],
"favicon_id" => $line["id"],
array_push($feeds, array("id" => intval($line["id"]),
"favicon_id" => intval($line["id"]),
"title" => $line["title"],
"url" => $line["feed_url"],
"site_url" => $line["site_url"],
"is_spark" => 0, // unsported
"last_updated_on_time" => strtotime($line["last_updated"])
));
}
}
return $feeds;
}
function getFavicons()
{
$favicons = array();
$result = $this->dbh->query("SELECT id
FROM ttrss_feeds
WHERE owner_uid = '" . db_escape_string($_SESSION["uid"]) . "'
ORDER BY order_id ASC");
// data = "image/gif;base64,<base64 encoded image>
while ($line = $this->dbh->fetch_assoc($result))
{
$filename = "feed-icons/" . $line["id"] . ".ico";
if (file_exists($filename))
{
array_push($favicons, array("id" => $line["id"],
array_push($favicons, array("id" => intval($line["id"]),
"data" => image_type_to_mime_type(exif_imagetype($filename)) . ";base64," . base64_encode(file_get_contents($filename))
));
}
}
}
return $favicons;
}
function getLinks()
{
// TODO: is there a 'hot links' alternative in ttrss?
// use ttrss_user_entries / score>0
$links = array();
return $links;
}
function getItems()
{
{
// items from specific groups, feeds
$items = array();
$item_limit = 50;
$where = " owner_uid = '" . db_escape_string($_SESSION["uid"]) . "' AND ref_id = id ";
@@ -280,16 +319,16 @@ class FeverAPI extends Handler {
$feeds_in_group_result = $this->dbh->query("SELECT id
FROM ttrss_feeds
WHERE owner_uid = '" . db_escape_string($_SESSION["uid"]) . "' " . $groups_query);
$group_feed_ids = array();
while ($line = $this->dbh->fetch_assoc($feeds_in_group_result))
{
array_push($group_feed_ids, $line["id"]);
}
$feed_ids = array_unique(array_merge($feed_ids, $group_feed_ids));
}
$query = " feed_id IN (";
$num_feed_ids = sizeof($feed_ids);
foreach ($feed_ids as $feed_id)
@@ -299,16 +338,16 @@ class FeverAPI extends Handler {
else
$num_feed_ids--;
}
if ($num_feed_ids <= 0)
$query = " feed_id IN ('') ";
else
$query = trim($query, ",") . ")";
if (!empty($where)) $where .= " AND ";
$where .= $query;
}
if (isset($_REQUEST["max_id"])) // descending from most recently added
{
// use the max_id argument to request the previous $item_limit items
@@ -324,14 +363,14 @@ class FeverAPI extends Handler {
{
$where .= "1";
}
$where .= " ORDER BY id DESC";
}
}
else if (isset($_REQUEST["with_ids"])) // selective
{
if (!empty($where)) $where .= " AND "; // group_ids & feed_ids don't make sense with this query but just in case
$item_ids = explode(",", $_REQUEST["with_ids"]);
$query = "id IN (";
$num_ids = sizeof($item_ids);
@@ -342,12 +381,12 @@ class FeverAPI extends Handler {
else
$num_ids--;
}
if ($num_ids <= 0)
$query = "id IN ('') ";
else
$query = trim($query, ",") . ") ";
$where .= $query;
}
else // ascending from first added
@@ -360,7 +399,8 @@ class FeverAPI extends Handler {
if ($since_id)
{
if (!empty($where)) $where .= " AND ";
$where .= "id > " . db_escape_string($since_id) . " ";
//$where .= "id > " . db_escape_string($since_id) . " ";
$where .= "id > " . db_escape_string($since_id*1000) . " "; // NASTY hack for Mr. Reader 2.0 on iOS and TinyTiny RSS Fever
}
else if (empty($where))
{
@@ -370,116 +410,116 @@ class FeverAPI extends Handler {
$where .= " ORDER BY id ASC";
}
}
$where .= " LIMIT " . $item_limit;
// id, feed_id, title, author, html, url, is_saved, is_read, created_on_time
$result = $this->dbh->query("SELECT ref_id, feed_id, title, link, content, id, marked, unread, author, date_entered
// id, feed_id, title, author, html, url, is_saved, is_read, created_on_time
$result = $this->dbh->query("SELECT ref_id, feed_id, title, link, content, id, marked, unread, author, updated
FROM ttrss_entries, ttrss_user_entries
WHERE " . $where);
while ($line = $this->dbh->fetch_assoc($result))
{
array_push($items, array("id" => $line["id"],
"feed_id" => $line["feed_id"],
array_push($items, array("id" => intval($line["id"]),
"feed_id" => intval($line["feed_id"]),
"title" => $line["title"],
"author" => $line["author"],
"html" => $line["content"],
"url" => $line["link"],
"is_saved" => (sql_bool_to_bool($line["marked"]) ? 1 : 0),
"is_read" => ( (!sql_bool_to_bool($line["unread"])) ? 1 : 0),
"created_on_time" => strtotime($line["date_entered"])
"created_on_time" => strtotime($line["updated"])
));
}
return $items;
}
function getTotalItems()
{
{
// number of total items
$total_items = 0;
$where = " owner_uid = '" . db_escape_string($_SESSION["uid"]) . "'";
$result = $this->dbh->query("SELECT COUNT(ref_id) as total_items
FROM ttrss_user_entries
WHERE " . $where);
if ($this->dbh->num_rows($result) > 0)
if ($this->dbh->num_rows($result) > 0)
{
$total_items = $this->dbh->fetch_result($result, 0, "total_items");
}
}
return $total_items;
}
function getFeedsGroup()
{
$feeds_groups = array();
$result = $this->dbh->query("SELECT id, cat_id
FROM ttrss_feeds
WHERE owner_uid = '" . db_escape_string($_SESSION["uid"]) . "'
WHERE owner_uid = '" . db_escape_string($_SESSION["uid"]) . "'
AND cat_id IS NOT NULL
ORDER BY id ASC");
$groupsToFeeds = array();
while ($line = $this->dbh->fetch_assoc($result))
{
if (!array_key_exists($line["cat_id"], $groupsToFeeds))
$groupsToFeeds[$line["cat_id"]] = array();
array_push($groupsToFeeds[$line["cat_id"]], $line["id"]);
}
foreach ($groupsToFeeds as $group => $feeds)
{
$feedsStr = "";
foreach ($feeds as $feed)
$feedsStr .= $feed . ",";
$feedsStr = trim($feedsStr, ",");
array_push($feeds_groups, array("group_id" => $group,
"feed_ids" => $feedsStr));
}
return $feeds_groups;
}
function getUnreadItemIds()
{
$unreadItemIdsCSV = "";
$result = $this->dbh->query("SELECT ref_id, unread
FROM ttrss_user_entries
WHERE owner_uid = '" . db_escape_string($_SESSION["uid"]) . "'");
WHERE owner_uid = '" . db_escape_string($_SESSION["uid"]) . "'"); // ORDER BY red_id DESC
while ($line = $this->dbh->fetch_assoc($result))
{
if (sql_bool_to_bool($line["unread"]))
$unreadItemIdsCSV .= $line["ref_id"] . ",";
}
$unreadItemIdsCSV = trim($unreadItemIdsCSV, ",");
return $unreadItemIdsCSV;
}
function getSavedItemIds()
{
$savedItemIdsCSV = "";
$result = $this->dbh->query("SELECT ref_id, marked
FROM ttrss_user_entries
WHERE owner_uid = '" . db_escape_string($_SESSION["uid"]) . "'");
while ($line = $this->dbh->fetch_assoc($result))
{
if (sql_bool_to_bool($line["marked"]))
$savedItemIdsCSV .= $line["ref_id"] . ",";
}
$savedItemIdsCSV = trim($savedItemIdsCSV, ",");
return $savedItemIdsCSV;
}
function setItem($id, $field_raw, $mode, $before = 0)
{
$field = "";
@@ -505,7 +545,7 @@ class FeverAPI extends Handler {
break;
}
if ($field && $set_to)
if ($field && $set_to)
{
$article_ids = db_escape_string($id);
@@ -523,40 +563,40 @@ class FeverAPI extends Handler {
}
}
}
function setItemAsRead($id)
{
$this->setItem($id, 1, 0);
}
function setItemAsUnread($id)
{
$this->setItem($id, 1, 1);
}
function setItemAsSaved($id)
{
$this->setItem($id, 0, 1);
}
function setItemAsUnsaved($id)
{
$this->setItem($id, 0, 0);
}
function setFeed($id, $cat, $before=0)
{
// if before is zero, set it to now so feeds all items are read from before this point in time
if ($before == 0)
$before = time();
if (is_numeric($id))
if (is_numeric($id))
{
// this is a category
if ($cat)
if ($cat)
{
// if not special feed
if ($id > 0)
if ($id > 0)
{
db_query("UPDATE ttrss_user_entries
SET unread = false, last_read = NOW() WHERE ref_id IN
@@ -578,7 +618,7 @@ class FeverAPI extends Handler {
}
}
// not a category
else if ($id > 0)
else if ($id > 0)
{
db_query("UPDATE ttrss_user_entries
SET unread = false, last_read = NOW() WHERE ref_id IN
@@ -588,24 +628,24 @@ class FeverAPI extends Handler {
}
ccache_update($id,$_SESSION["uid"], $cat);
}
}
}
function setFeedAsRead($id, $before)
{
$this->setFeed($id, false, $before);
}
function setGroupAsRead($id, $before)
{
$this->setFeed($id, true, $before);
}
// this does all the processing, since the fever api does not have a specific variable that specifies the operation
function index()
function index()
{
$response_arr = array();
if (isset($_REQUEST["groups"]))
{
$response_arr["groups"] = $this->getGroups();
@@ -638,14 +678,14 @@ class FeverAPI extends Handler {
{
$response_arr["saved_item_ids"] = $this->getSavedItemIds();
}
if (isset($_REQUEST["mark"], $_REQUEST["as"], $_REQUEST["id"]))
{
if (is_numeric($_REQUEST["id"]))
{
$before = (isset($_REQUEST["before"])) ? $_REQUEST["before"] : null;
$method_name = "set" . ucfirst($_REQUEST["mark"]) . "As" . ucfirst($_REQUEST["as"]);
if (method_exists($this, $method_name))
{
$id = intval($_REQUEST["id"]);
@@ -665,25 +705,29 @@ class FeverAPI extends Handler {
}
}
}
if ($_SESSION["uid"])
$this->wrap(self::STATUS_OK, $response_arr);
else if (!$_SESSION["uid"])
$this->wrap(self::STATUS_ERR, NULL);
}
// validate the api_key, user preferences
function before($method) {
if (parent::before($method)) {
if (self::DEBUG) {
// add request to debug log
file_put_contents(self::DEBUG_FILE,'parameter: '.json_encode($_REQUEST)."\n",FILE_APPEND);
}
// set the user from the db
$this->setUser();
// are we xml or json?
$this->setXml();
if ($this->xml)
if ($this->xml)
header("Content-Type: text/xml");
else
header("Content-Type: text/json");

View File

@@ -1,10 +1,11 @@
<?php
// do not support refresh command, this could take ages.
if (isset($_REQUEST["refresh"]))
{
exit;
}
error_reporting(E_ERROR | E_PARSE);
@@ -16,7 +17,7 @@
get_include_path());
chdir("../..");
define('NO_SESSION_AUTOSTART', true);
require_once "autoload.php";
@@ -34,17 +35,18 @@
} else {
ob_start();
}
if (!init_plugins()) return;
$handler = new FeverAPI(Db::get(), $_REQUEST);
if ($handler->before($method)) {
if (method_exists($handler, 'index')) {
$handler->index($method);
}
$handler->after();
}
ob_end_flush();
?>
?>

View File

@@ -1,11 +1,12 @@
<?php
class Fever extends Plugin {
private $host;
function about() {
return array(1.2,
"Emulates the Fever API for Tiny Tiny RSS",
"digitaldj");
"digitaldj & murphy");
}
function init($host) {
@@ -16,7 +17,7 @@ class Fever extends Plugin {
function before($method) {
return true;
}
function csrf_ignore($method) {
return true;
}
@@ -29,7 +30,7 @@ class Fever extends Plugin {
print "<h3>" . __("Fever Emulation") . "</h3>";
print "<p>" . __("Since the Fever API uses a different authentication mechanism to Tiny Tiny RSS, you must set a separate password to login. This password may be the same as your Tiny Tiny RSS password.") . "</p>";
print "<p>" . __("Set a password to login with Fever:") . "</p>";
print "<form dojoType=\"dijit.form.Form\">";
@@ -52,27 +53,27 @@ class Fever extends Plugin {
print "<input dojoType=\"dijit.form.ValidationTextBox\" required=\"1\" type=\"password\" name=\"password\" />";
print "<button dojoType=\"dijit.form.Button\" type=\"submit\">" . __("Set Password") . "</button>";
print "</form>";
print "<p>" . __("To login with the Fever API, set your server details in your favourite RSS application to: ") . ($_SERVER["HTTPS"] == "on" ? "https://" : "http://") . dirname($_SERVER["SERVER_NAME"] . $_SERVER["REQUEST_URI"]) . "/plugins/fever/" . "</p>";
print "<p>" . __("Additional details can be found at ") . "<a href=\"http://www.feedafever.com/api\" target=\"_blank\">http://www.feedafever.com/api</a></p>";
print "<p>" . __("Note: Due to the limitations of the API and some RSS clients (for example, Reeder on iOS), some features are unavailable: \"Special\" Feeds (Published / Tags / Labels / Fresh / Recent), Nested Categories (hierarchy is flattened)") . "</p>";
print "</div>";
}
function save()
{
if (isset($_POST["password"]) && isset($_SESSION["uid"]))
{
$result = db_query("SELECT login FROM ttrss_users WHERE id = '" . db_escape_string($_SESSION["uid"]) . "'");
if ($line = db_fetch_assoc($result))
if ($line = db_fetch_assoc($result))
{
$password = md5($line["login"] . ":" . db_escape_string($_POST["password"]));
$this->host->set($this, "password", $password);
echo __("Password saved.");
}
}
}
}
function after() {
@@ -83,4 +84,5 @@ class Fever extends Plugin {
return 2;
}
}
?>