init.php 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. <?php
  2. class Af_Readability extends Plugin {
  3. private $host;
  4. function about() {
  5. return array(1.0,
  6. "Try to inline article content using Readability",
  7. "fox");
  8. }
  9. function flags() {
  10. return array("needs_curl" => true);
  11. }
  12. function save() {
  13. $enable_share_anything = checkbox_to_sql_bool($_POST["enable_share_anything"]) == "true";
  14. $this->host->set($this, "enable_share_anything", $enable_share_anything);
  15. echo __("Data saved.");
  16. }
  17. function init($host)
  18. {
  19. $this->host = $host;
  20. $host->add_hook($host::HOOK_ARTICLE_FILTER, $this);
  21. $host->add_hook($host::HOOK_PREFS_TAB, $this);
  22. $host->add_hook($host::HOOK_PREFS_EDIT_FEED, $this);
  23. $host->add_hook($host::HOOK_PREFS_SAVE_FEED, $this);
  24. $host->add_filter_action($this, "action_inline", __("Inline content"));
  25. }
  26. function hook_prefs_tab($args) {
  27. if ($args != "prefFeeds") return;
  28. print "<div dojoType=\"dijit.layout.AccordionPane\" title=\"".__('af_readability settings')."\">";
  29. print_notice("Enable the plugin for specific feeds in the feed editor.");
  30. print "<form dojoType=\"dijit.form.Form\">";
  31. print "<script type=\"dojo/method\" event=\"onSubmit\" args=\"evt\">
  32. evt.preventDefault();
  33. if (this.validate()) {
  34. console.log(dojo.objectToQuery(this.getValues()));
  35. new Ajax.Request('backend.php', {
  36. parameters: dojo.objectToQuery(this.getValues()),
  37. onComplete: function(transport) {
  38. notify_info(transport.responseText);
  39. }
  40. });
  41. //this.reset();
  42. }
  43. </script>";
  44. print "<input dojoType=\"dijit.form.TextBox\" style=\"display : none\" name=\"op\" value=\"pluginhandler\">";
  45. print "<input dojoType=\"dijit.form.TextBox\" style=\"display : none\" name=\"method\" value=\"save\">";
  46. print "<input dojoType=\"dijit.form.TextBox\" style=\"display : none\" name=\"plugin\" value=\"af_readability\">";
  47. $enable_share_anything = $this->host->get($this, "enable_share_anything");
  48. $enable_share_anything_checked = $enable_share_anything ? "checked" : "";
  49. print "<input dojoType=\"dijit.form.CheckBox\"
  50. $enable_share_anything_checked name=\"enable_share_anything\" id=\"enable_share_anything\">
  51. <label for=\"enable_share_anything\">" . __("Use Readability for pages shared via bookmarklet.") . "</label>";
  52. print "<p><button dojoType=\"dijit.form.Button\" type=\"submit\">".
  53. __("Save")."</button>";
  54. print "</form>";
  55. $enabled_feeds = $this->host->get($this, "enabled_feeds");
  56. if (!is_array($enabled_feeds)) $enabled_feeds = array();
  57. $enabled_feeds = $this->filter_unknown_feeds($enabled_feeds);
  58. $this->host->set($this, "enabled_feeds", $enabled_feeds);
  59. if (count($enabled_feeds) > 0) {
  60. print "<h3>" . __("Currently enabled for (click to edit):") . "</h3>";
  61. print "<ul class=\"browseFeedList\" style=\"border-width : 1px\">";
  62. foreach ($enabled_feeds as $f) {
  63. print "<li>" .
  64. "<img src='images/pub_set.png'
  65. style='vertical-align : middle'> <a href='#'
  66. onclick='editFeed($f)'>".
  67. getFeedTitle($f) . "</a></li>";
  68. }
  69. print "</ul>";
  70. }
  71. print "</div>";
  72. }
  73. function hook_prefs_edit_feed($feed_id) {
  74. print "<div class=\"dlgSec\">".__("Readability")."</div>";
  75. print "<div class=\"dlgSecCont\">";
  76. $enabled_feeds = $this->host->get($this, "enabled_feeds");
  77. if (!is_array($enabled_feeds)) $enabled_feeds = array();
  78. $key = array_search($feed_id, $enabled_feeds);
  79. $checked = $key !== FALSE ? "checked" : "";
  80. print "<hr/><input dojoType=\"dijit.form.CheckBox\" type=\"checkbox\" id=\"af_readability_enabled\"
  81. name=\"af_readability_enabled\"
  82. $checked>&nbsp;<label for=\"af_readability_enabled\">".__('Inline article content')."</label>";
  83. print "</div>";
  84. }
  85. function hook_prefs_save_feed($feed_id) {
  86. $enabled_feeds = $this->host->get($this, "enabled_feeds");
  87. if (!is_array($enabled_feeds)) $enabled_feeds = array();
  88. $enable = checkbox_to_sql_bool($_POST["af_readability_enabled"]) == 'true';
  89. $key = array_search($feed_id, $enabled_feeds);
  90. if ($enable) {
  91. if ($key === FALSE) {
  92. array_push($enabled_feeds, $feed_id);
  93. }
  94. } else {
  95. if ($key !== FALSE) {
  96. unset($enabled_feeds[$key]);
  97. }
  98. }
  99. $this->host->set($this, "enabled_feeds", $enabled_feeds);
  100. }
  101. function hook_article_filter_action($article, $action) {
  102. return $this->process_article($article);
  103. }
  104. public function extract_content($url) {
  105. if (!class_exists("Readability")) require_once(dirname(dirname(__DIR__)). "/lib/readability/Readability.php");
  106. if (!defined('NO_CURL') && function_exists('curl_init') && !ini_get("open_basedir")) {
  107. $ch = curl_init($url);
  108. curl_setopt($ch, CURLOPT_TIMEOUT, 5);
  109. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  110. curl_setopt($ch, CURLOPT_HEADER, true);
  111. curl_setopt($ch, CURLOPT_NOBODY, true);
  112. curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
  113. curl_setopt($ch, CURLOPT_USERAGENT, SELF_USER_AGENT);
  114. @$result = curl_exec($ch);
  115. $content_type = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
  116. if (strpos($content_type, "text/html") === FALSE)
  117. return false;
  118. }
  119. $tmp = fetch_file_contents($url);
  120. if ($tmp && mb_strlen($tmp) < 65535 * 4) {
  121. $tmpdoc = new DOMDocument("1.0", "UTF-8");
  122. if (!$tmpdoc->loadHTML($tmp))
  123. return false;
  124. if (strtolower($tmpdoc->encoding) != 'utf-8') {
  125. $tmpxpath = new DOMXPath($tmpdoc);
  126. foreach ($tmpxpath->query("//meta") as $elem) {
  127. $elem->parentNode->removeChild($elem);
  128. }
  129. $tmp = $tmpdoc->saveHTML();
  130. }
  131. $r = new Readability($tmp, $url);
  132. if ($r->init()) {
  133. $tmpxpath = new DOMXPath($r->dom);
  134. $entries = $tmpxpath->query('(//a[@href]|//img[@src])');
  135. foreach ($entries as $entry) {
  136. if ($entry->hasAttribute("href")) {
  137. $entry->setAttribute("href",
  138. rewrite_relative_url($url, $entry->getAttribute("href")));
  139. }
  140. if ($entry->hasAttribute("src")) {
  141. $entry->setAttribute("src",
  142. rewrite_relative_url($url, $entry->getAttribute("src")));
  143. }
  144. }
  145. return $r->articleContent->innerHTML;
  146. }
  147. }
  148. return false;
  149. }
  150. function process_article($article) {
  151. $extracted_content = $this->extract_content($article["link"]);
  152. if ($extracted_content) {
  153. $article["content"] = $extracted_content;
  154. }
  155. return $article;
  156. }
  157. function hook_article_filter($article) {
  158. $enabled_feeds = $this->host->get($this, "enabled_feeds");
  159. if (!is_array($enabled_feeds)) return $article;
  160. $key = array_search($article["feed"]["id"], $enabled_feeds);
  161. if ($key === FALSE) return $article;
  162. return $this->process_article($article);
  163. }
  164. function api_version() {
  165. return 2;
  166. }
  167. private function filter_unknown_feeds($enabled_feeds) {
  168. $tmp = array();
  169. foreach ($enabled_feeds as $feed) {
  170. $result = db_query("SELECT id FROM ttrss_feeds WHERE id = '$feed' AND owner_uid = " . $_SESSION["uid"]);
  171. if (db_num_rows($result) != 0) {
  172. array_push($tmp, $feed);
  173. }
  174. }
  175. return $tmp;
  176. }
  177. }
  178. ?>