From 6712dbb70966a922afb5ffeff2e9898476f58292 Mon Sep 17 00:00:00 2001 From: epriestley Date: Fri, 9 Mar 2012 12:40:03 -0800 Subject: [PATCH] Bring macros to IRC Summary: Adds a macro handler that spams your channel with macros. Config is: - macro.size: scale macros to this size before rasterizing - macro.sleep: sleep this many seconds between lines (evade flood protection) Test Plan: derpderp Reviewers: kdeggelman, btrahan Reviewed By: btrahan CC: aran, epriestley Differential Revision: https://secure.phabricator.com/D1838 --- resources/ircbot/example_config.json | 7 +- src/__phutil_library_map__.php | 6 + .../macro/base/ConduitAPI_macro_Method.php | 25 +++ .../conduit/method/macro/base/__init__.php | 12 ++ .../query/ConduitAPI_macro_query_Method.php | 67 ++++++ .../conduit/method/macro/query/__init__.php | 16 ++ .../macro/PhabricatorIRCMacroHandler.php | 200 ++++++++++++++++++ .../daemon/irc/handler/macro/__init__.php | 14 ++ 8 files changed, 346 insertions(+), 1 deletion(-) create mode 100644 src/applications/conduit/method/macro/base/ConduitAPI_macro_Method.php create mode 100644 src/applications/conduit/method/macro/base/__init__.php create mode 100644 src/applications/conduit/method/macro/query/ConduitAPI_macro_query_Method.php create mode 100644 src/applications/conduit/method/macro/query/__init__.php create mode 100644 src/infrastructure/daemon/irc/handler/macro/PhabricatorIRCMacroHandler.php create mode 100644 src/infrastructure/daemon/irc/handler/macro/__init__.php diff --git a/resources/ircbot/example_config.json b/resources/ircbot/example_config.json index 476d81d643..b2bbf5210d 100644 --- a/resources/ircbot/example_config.json +++ b/resources/ircbot/example_config.json @@ -10,12 +10,17 @@ "PhabricatorIRCObjectNameHandler", "PhabricatorIRCLogHandler", "PhabricatorIRCWhatsNewHandler", - "PhabricatorIRCDifferentialNotificationHandler" + "PhabricatorIRCDifferentialNotificationHandler", + "PhabricatorIRCMacroHandler" ], "conduit.uri" : null, "conduit.user" : null, "conduit.cert" : null, + "macro.size" : 48, + "macro.sleep" : 0.25, + "macro.aspect" : 0.66, + "notification.channels" : ["#phabot-test"] } diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index e48c3fdb27..6fd8ff642a 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -140,6 +140,8 @@ phutil_register_library_map(array( 'ConduitAPI_file_download_Method' => 'applications/conduit/method/file/download', 'ConduitAPI_file_info_Method' => 'applications/conduit/method/file/info', 'ConduitAPI_file_upload_Method' => 'applications/conduit/method/file/upload', + 'ConduitAPI_macro_Method' => 'applications/conduit/method/macro/base', + 'ConduitAPI_macro_query_Method' => 'applications/conduit/method/macro/query', 'ConduitAPI_maniphest_Method' => 'applications/conduit/method/maniphest/base', 'ConduitAPI_maniphest_createtask_Method' => 'applications/conduit/method/maniphest/createtask', 'ConduitAPI_maniphest_find_Method' => 'applications/conduit/method/maniphest/find', @@ -581,6 +583,7 @@ phutil_register_library_map(array( 'PhabricatorIRCDifferentialNotificationHandler' => 'infrastructure/daemon/irc/handler/differentialnotification', 'PhabricatorIRCHandler' => 'infrastructure/daemon/irc/handler/base', 'PhabricatorIRCLogHandler' => 'infrastructure/daemon/irc/handler/log', + 'PhabricatorIRCMacroHandler' => 'infrastructure/daemon/irc/handler/macro', 'PhabricatorIRCMessage' => 'infrastructure/daemon/irc/message', 'PhabricatorIRCObjectNameHandler' => 'infrastructure/daemon/irc/handler/objectname', 'PhabricatorIRCProtocolHandler' => 'infrastructure/daemon/irc/handler/protocol', @@ -1018,6 +1021,8 @@ phutil_register_library_map(array( 'ConduitAPI_file_download_Method' => 'ConduitAPIMethod', 'ConduitAPI_file_info_Method' => 'ConduitAPIMethod', 'ConduitAPI_file_upload_Method' => 'ConduitAPIMethod', + 'ConduitAPI_macro_Method' => 'ConduitAPIMethod', + 'ConduitAPI_macro_query_Method' => 'ConduitAPI_macro_Method', 'ConduitAPI_maniphest_Method' => 'ConduitAPIMethod', 'ConduitAPI_maniphest_createtask_Method' => 'ConduitAPI_maniphest_Method', 'ConduitAPI_maniphest_find_Method' => 'ConduitAPI_maniphest_Method', @@ -1359,6 +1364,7 @@ phutil_register_library_map(array( 'PhabricatorIRCBot' => 'PhabricatorDaemon', 'PhabricatorIRCDifferentialNotificationHandler' => 'PhabricatorIRCHandler', 'PhabricatorIRCLogHandler' => 'PhabricatorIRCHandler', + 'PhabricatorIRCMacroHandler' => 'PhabricatorIRCHandler', 'PhabricatorIRCObjectNameHandler' => 'PhabricatorIRCHandler', 'PhabricatorIRCProtocolHandler' => 'PhabricatorIRCHandler', 'PhabricatorIRCWhatsNewHandler' => 'PhabricatorIRCHandler', diff --git a/src/applications/conduit/method/macro/base/ConduitAPI_macro_Method.php b/src/applications/conduit/method/macro/base/ConduitAPI_macro_Method.php new file mode 100644 index 0000000000..0c98cbf6f7 --- /dev/null +++ b/src/applications/conduit/method/macro/base/ConduitAPI_macro_Method.php @@ -0,0 +1,25 @@ +'; + } + + public function defineErrorTypes() { + return array( + ); + } + + protected function execute(ConduitAPIRequest $request) { + + $macros = id(new PhabricatorFileImageMacro())->loadAll(); + + $files = array(); + if ($macros) { + $files = id(new PhabricatorFile())->loadAllWhere( + 'phid IN (%Ls)', + mpull($macros, 'getFilePHID')); + $files = mpull($files, null, 'getPHID'); + } + + $results = array(); + foreach ($macros as $macro) { + if (empty($files[$macro->getFilePHID()])) { + continue; + } + $results[$macro->getName()] = array( + 'uri' => $files[$macro->getFilePHID()]->getBestURI(), + ); + } + + return $results; + } + +} diff --git a/src/applications/conduit/method/macro/query/__init__.php b/src/applications/conduit/method/macro/query/__init__.php new file mode 100644 index 0000000000..f546de4731 --- /dev/null +++ b/src/applications/conduit/method/macro/query/__init__.php @@ -0,0 +1,16 @@ +macros === false) { + return false; + } + + if ($this->macros !== null) { + return true; + } + + $macros = $this->getConduit()->callMethodSynchronous( + 'macro.query', + array()); + + $this->macros = $macros; + + $regexp = array(); + foreach ($this->macros as $macro_name => $macro) { + $regexp[] = preg_quote($macro_name, '/'); + } + $regexp = '/('.implode('|', $regexp).')/'; + + $this->regexp = $regexp; + + return true; + } + + public function receiveMessage(PhabricatorIRCMessage $message) { + if (!$this->init()) { + return; + } + + switch ($message->getCommand()) { + case 'PRIVMSG': + $reply_to = $message->getReplyTo(); + if (!$reply_to) { + break; + } + + $message = $message->getMessageText(); + + $matches = null; + if (!preg_match($this->regexp, $message, $matches)) { + return; + } + + $macro = $matches[1]; + + $ascii = idx($this->macros[$macro], 'ascii'); + if ($ascii === false) { + return; + } + + if (!$ascii) { + $this->macros[$macro]['ascii'] = $this->rasterize( + $this->macros[$macro], + $this->getConfig('macro.size', 48), + $this->getConfig('macro.aspect', 0.66)); + $ascii = $this->macros[$macro]['ascii']; + } + + foreach ($ascii as $line) { + $this->buffer[$reply_to][] = $line; + } + break; + } + } + + public function runBackgroundTasks() { + if (microtime(true) < $this->next) { + return; + } + + foreach ($this->buffer as $channel => $lines) { + if (empty($lines)) { + unset($this->buffer[$channel]); + continue; + } + foreach ($lines as $key => $line) { + $this->write('PRIVMSG', "{$channel} :{$line}"); + unset($this->buffer[$channel][$key]); + break 2; + } + } + + $sleep = $this->getConfig('macro.sleep', 0.25); + $this->next = microtime(true) + ((mt_rand(75, 150) / 100) * $sleep); + } + + public function rasterize($macro, $size, $aspect) { + $image = @file_get_contents($macro['uri']); + if (!$image) { + return false; + } + + $img = @imagecreatefromstring($image); + if (!$img) { + return false; + } + + $sx = imagesx($img); + $sy = imagesy($img); + + if ($sx > $size || $sy > $size) { + $scale = max($sx, $sy) / $size; + $dx = floor($sx / $scale); + $dy = floor($sy / $scale); + } else { + $dx = $sx; + $dy = $sy; + } + + $dy = floor($dy * $aspect); + + $dst = imagecreatetruecolor($dx, $dy); + if (!$dst) { + return false; + } + imagealphablending($dst, false); + + $ok = imagecopyresampled( + $dst, $img, + 0, 0, + 0, 0, + $dx, $dy, + $sx, $sy); + + if (!$ok) { + return false; + } + + $map = array( + ' ', + '.', + ',', + ':', + ';', + '!', + '|', + '*', + '=', + '@', + '$', + '#', + ); + + $lines = array(); + + for ($ii = 0; $ii < $dy; $ii++) { + $buf = ''; + for ($jj = 0; $jj < $dx; $jj++) { + $c = imagecolorat($dst, $jj, $ii); + + $a = ($c >> 24) & 0xFF; + $r = ($c >> 16) & 0xFF; + $g = ($c >> 8) & 0xFF; + $b = ($c) & 0xFF; + + $luma = (255 - ((0.30 * $r) + (0.59 * $g) + (0.11 * $b))) / 256; + $luma *= ((127 - $a) / 127); + + $char = $map[max(0, floor($luma * count($map)))]; + $buf .= $char; + } + + $lines[] = $buf; + } + + return $lines; + } + +} diff --git a/src/infrastructure/daemon/irc/handler/macro/__init__.php b/src/infrastructure/daemon/irc/handler/macro/__init__.php new file mode 100644 index 0000000000..1233ce5415 --- /dev/null +++ b/src/infrastructure/daemon/irc/handler/macro/__init__.php @@ -0,0 +1,14 @@ +