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