init.php 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. <?php
  2. class Af_RedditImgur extends Plugin {
  3. private $host;
  4. function about() {
  5. return array(1.0,
  6. "Inline images (and other content) in Reddit RSS feeds",
  7. "fox");
  8. }
  9. function init($host) {
  10. $this->host = $host;
  11. $host->add_hook($host::HOOK_ARTICLE_FILTER, $this);
  12. $host->add_hook($host::HOOK_PREFS_TAB, $this);
  13. }
  14. function hook_prefs_tab($args) {
  15. if ($args != "prefFeeds") return;
  16. print "<div id=\"af_redditimgur_prefs\" dojoType=\"dijit.layout.AccordionPane\" title=\"".__('af_redditimgur settings')."\">";
  17. $enable_readability = $this->host->get($this, "enable_readability");
  18. $enable_readability_checked = $enable_readability ? "checked" : "";
  19. print "<form dojoType=\"dijit.form.Form\">";
  20. print "<script type=\"dojo/method\" event=\"onSubmit\" args=\"evt\">
  21. evt.preventDefault();
  22. if (this.validate()) {
  23. console.log(dojo.objectToQuery(this.getValues()));
  24. new Ajax.Request('backend.php', {
  25. parameters: dojo.objectToQuery(this.getValues()),
  26. onComplete: function(transport) {
  27. notify_info(transport.responseText);
  28. }
  29. });
  30. //this.reset();
  31. }
  32. </script>";
  33. print "<input dojoType=\"dijit.form.TextBox\" style=\"display : none\" name=\"op\" value=\"pluginhandler\">";
  34. print "<input dojoType=\"dijit.form.TextBox\" style=\"display : none\" name=\"method\" value=\"save\">";
  35. print "<input dojoType=\"dijit.form.TextBox\" style=\"display : none\" name=\"plugin\" value=\"af_redditimgur\">";
  36. print "<h3>" . __("Global settings") . "</h3>";
  37. print_notice("Uses Readability (full-text-rss) implementation by <a target='_blank' href='https://bitbucket.org/fivefilters/'>FiveFilters.org</a>");
  38. print "<p/>";
  39. print "<input dojoType=\"dijit.form.CheckBox\" id=\"enable_readability\"
  40. $enable_readability_checked name=\"enable_readability\">&nbsp;";
  41. print "<label for=\"enable_readability\">" . __("Extract missing content using Readability") . "</label>";
  42. print "<p><button dojoType=\"dijit.form.Button\" type=\"submit\">".
  43. __("Save")."</button>";
  44. print "</form>";
  45. print "</div>";
  46. }
  47. function save() {
  48. $enable_readability = checkbox_to_sql_bool($_POST["enable_readability"]) == "true";
  49. $this->host->set($this, "enable_readability", $enable_readability);
  50. echo __("Configuration saved");
  51. }
  52. private function inline_stuff($article, &$doc, $xpath) {
  53. $entries = $xpath->query('(//a[@href]|//img[@src])');
  54. $found = false;
  55. foreach ($entries as $entry) {
  56. if ($entry->hasAttribute("href")) {
  57. $matches = array();
  58. if (preg_match("/https?:\/\/gfycat.com\/([a-z]+)$/i", $entry->getAttribute("href"), $matches)) {
  59. $tmp = fetch_file_contents($entry->getAttribute("href"));
  60. if ($tmp) {
  61. $tmpdoc = new DOMDocument();
  62. @$tmpdoc->loadHTML($tmp);
  63. if ($tmpdoc) {
  64. $tmpxpath = new DOMXPath($tmpdoc);
  65. $source_meta = $tmpxpath->query("//meta[@property='og:video']")->item(0);
  66. if ($source_meta) {
  67. $source_stream = $source_meta->getAttribute("content");
  68. if ($source_stream) {
  69. $this->handle_as_video($doc, $entry, $source_stream);
  70. $found = 1;
  71. }
  72. }
  73. }
  74. }
  75. }
  76. if (preg_match("/\.(gifv)$/i", $entry->getAttribute("href"))) {
  77. $source_stream = str_replace(".gifv", ".mp4", $entry->getAttribute("href"));
  78. $this->handle_as_video($doc, $entry, $source_stream);
  79. $found = true;
  80. }
  81. $matches = array();
  82. if (preg_match("/\.youtube\.com\/v\/([\w-]+)/", $entry->getAttribute("href"), $matches) ||
  83. preg_match("/\.youtube\.com\/watch\?v=([\w-]+)/", $entry->getAttribute("href"), $matches) ||
  84. preg_match("/\/\/youtu.be\/([\w-]+)/", $entry->getAttribute("href"), $matches)) {
  85. $vid_id = $matches[1];
  86. $iframe = $doc->createElement("iframe");
  87. $iframe->setAttribute("class", "youtube-player");
  88. $iframe->setAttribute("type", "text/html");
  89. $iframe->setAttribute("width", "640");
  90. $iframe->setAttribute("height", "385");
  91. $iframe->setAttribute("src", "https://www.youtube.com/embed/$vid_id");
  92. $iframe->setAttribute("allowfullscreen", "1");
  93. $iframe->setAttribute("frameborder", "0");
  94. $br = $doc->createElement('br');
  95. $entry->parentNode->insertBefore($iframe, $entry);
  96. $entry->parentNode->insertBefore($br, $entry);
  97. $found = true;
  98. }
  99. if (preg_match("/\.(jpg|jpeg|gif|png)(\?[0-9][0-9]*)?$/i", $entry->getAttribute("href"))) {
  100. $img = $doc->createElement('img');
  101. $img->setAttribute("src", $entry->getAttribute("href"));
  102. $br = $doc->createElement('br');
  103. $entry->parentNode->insertBefore($img, $entry);
  104. $entry->parentNode->insertBefore($br, $entry);
  105. $found = true;
  106. }
  107. // links to imgur pages
  108. $matches = array();
  109. if (preg_match("/^https?:\/\/(m\.)?imgur.com\/([^\.\/]+$)/", $entry->getAttribute("href"), $matches)) {
  110. $token = $matches[2];
  111. $album_content = fetch_file_contents($entry->getAttribute("href"),
  112. false, false, false, false, 10);
  113. if ($album_content && $token) {
  114. $adoc = new DOMDocument();
  115. @$adoc->loadHTML($album_content);
  116. if ($adoc) {
  117. $axpath = new DOMXPath($adoc);
  118. $aentries = $axpath->query('(//img[@src])');
  119. foreach ($aentries as $aentry) {
  120. if (preg_match("/\/\/i.imgur.com\/$token\./", $aentry->getAttribute("src"))) {
  121. $img = $doc->createElement('img');
  122. $img->setAttribute("src", $aentry->getAttribute("src"));
  123. $br = $doc->createElement('br');
  124. $entry->parentNode->insertBefore($img, $entry);
  125. $entry->parentNode->insertBefore($br, $entry);
  126. $found = true;
  127. break;
  128. }
  129. }
  130. }
  131. }
  132. }
  133. // linked albums, ffs
  134. if (preg_match("/^https?:\/\/imgur.com\/(a|album|gallery)\/[^\.]+$/", $entry->getAttribute("href"), $matches)) {
  135. $album_content = fetch_file_contents($entry->getAttribute("href"),
  136. false, false, false, false, 10);
  137. if ($album_content) {
  138. $adoc = new DOMDocument();
  139. @$adoc->loadHTML($album_content);
  140. if ($adoc) {
  141. $axpath = new DOMXPath($adoc);
  142. $aentries = $axpath->query("//meta[@property='og:image']");
  143. $urls = array();
  144. foreach ($aentries as $aentry) {
  145. if (!in_array($aentry->getAttribute("content"), $urls)) {
  146. $img = $doc->createElement('img');
  147. $img->setAttribute("src", $aentry->getAttribute("content"));
  148. $entry->parentNode->insertBefore($doc->createElement('br'), $entry);
  149. $br = $doc->createElement('br');
  150. $entry->parentNode->insertBefore($img, $entry);
  151. $entry->parentNode->insertBefore($br, $entry);
  152. array_push($urls, $aentry->getAttribute("content"));
  153. $found = true;
  154. }
  155. }
  156. }
  157. }
  158. }
  159. }
  160. // remove tiny thumbnails
  161. if ($entry->hasAttribute("src")) {
  162. if ($entry->parentNode && $entry->parentNode->parentNode) {
  163. $entry->parentNode->parentNode->removeChild($entry->parentNode);
  164. }
  165. }
  166. }
  167. return $found;
  168. }
  169. function hook_article_filter($article) {
  170. if (strpos($article["link"], "reddit.com/r/") !== FALSE) {
  171. $doc = new DOMDocument();
  172. @$doc->loadHTML($article["content"]);
  173. $xpath = new DOMXPath($doc);
  174. $found = $this->inline_stuff($article, $doc, $xpath);
  175. if (!$found && $this->host->get($this, "enable_readability") && mb_strlen(strip_tags($article["content"])) <= 150) {
  176. if (!class_exists("Readability")) require_once(__DIR__ . "/classes/Readability.php");
  177. $content_link = $xpath->query("(//a[contains(., '[link]')])")->item(0);
  178. if ($content_link && strpos($content_link->getAttribute("href"), "reddit.com") === FALSE) {
  179. $tmp = fetch_file_contents($content_link->getAttribute("href"));
  180. if ($tmp) {
  181. $r = new Readability($tmp, $content_link->getAttribute("href"));
  182. if ($r->init()) {
  183. //$article["content"] = $r->articleContent->innerHTML . "<hr/>" . $article["content"];
  184. $tmpxpath = new DOMXPath($r->dom);
  185. $entries = $tmpxpath->query('(//a[@href]|//img[@src])');
  186. foreach ($entries as $entry) {
  187. if ($entry->hasAttribute("href")) {
  188. $entry->setAttribute("href",
  189. rewrite_relative_url($content_link->getAttribute("href"), $entry->getAttribute("href")));
  190. }
  191. if ($entry->hasAttribute("src")) {
  192. $entry->setAttribute("src",
  193. rewrite_relative_url($content_link->getAttribute("href"), $entry->getAttribute("src")));
  194. }
  195. }
  196. $article["content"] = $r->articleContent->innerHTML . "<hr/>" . $article["content"];
  197. $doc = new DOMDocument();
  198. @$doc->loadHTML($article["content"]);
  199. $xpath = new DOMXPath($doc);
  200. $found = $this->inline_stuff($article, $doc, $xpath);
  201. }
  202. }
  203. }
  204. }
  205. $node = $doc->getElementsByTagName('body')->item(0);
  206. if ($node && $found) {
  207. $article["content"] = $doc->saveXML($node);
  208. }
  209. }
  210. return $article;
  211. }
  212. function api_version() {
  213. return 2;
  214. }
  215. private function handle_as_video($doc, $entry, $source_stream) {
  216. $video = $doc->createElement('video');
  217. $video->setAttribute("autoplay", "1");
  218. $video->setAttribute("controls", "1");
  219. $video->setAttribute("loop", "1");
  220. $source = $doc->createElement('source');
  221. $source->setAttribute("src", $source_stream);
  222. $source->setAttribute("type", "video/mp4");
  223. $video->appendChild($source);
  224. $br = $doc->createElement('br');
  225. $entry->parentNode->insertBefore($video, $entry);
  226. $entry->parentNode->insertBefore($br, $entry);
  227. $img = $doc->createElement('img');
  228. $img->setAttribute("src",
  229. "data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs%3D");
  230. $entry->parentNode->insertBefore($img, $entry);
  231. }
  232. }
  233. ?>