├── api ├── public │ ├── m │ │ └── .gitignore │ └── img │ │ ├── fry.png │ │ ├── aliens.jpg │ │ ├── kenobi.gif │ │ ├── kenobi.jpg │ │ ├── mugatu.jpg │ │ ├── sparta.jpg │ │ ├── taken.jpg │ │ ├── walter.jpg │ │ ├── wonka.jpg │ │ ├── xzibit.jpg │ │ ├── y_u_no.jpg │ │ ├── boromir.jpg │ │ ├── emperor.jpg │ │ ├── ned_stark.jpg │ │ ├── over_9000.jpg │ │ ├── batman-slap.jpg │ │ ├── craig-happy.jpg │ │ ├── inquisition.jpg │ │ ├── all_the_things.jpg │ │ ├── goes_to_eleven.jpg │ │ ├── i_am_the_law.jpg │ │ ├── kermit-panic.gif │ │ ├── laughing-men.jpg │ │ ├── too_damn_high.jpg │ │ ├── conspiracy_keanu.jpg │ │ ├── fantastic-doctor.jpg │ │ ├── most_interesting.jpg │ │ ├── shampoo-is-better.jpg │ │ └── you_should_feel_bad.jpg ├── .gitignore ├── Impact.ttf ├── test │ ├── init.rb │ └── regex_spec.rb ├── config.template.yml ├── Rakefile ├── config.ru ├── Gemfile ├── schema.sql ├── README.md ├── Gemfile.lock ├── lib │ └── meme-match.rb ├── memes.json └── app.rb ├── .travis.yml └── README.md /api/public/m/.gitignore: -------------------------------------------------------------------------------- 1 | *.jpg 2 | *.gif 3 | -------------------------------------------------------------------------------- /api/.gitignore: -------------------------------------------------------------------------------- 1 | config.yml 2 | .DS_Store 3 | .bundle/ 4 | vendor/ -------------------------------------------------------------------------------- /api/Impact.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronpk/Meme-API/main/api/Impact.ttf -------------------------------------------------------------------------------- /api/public/img/fry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronpk/Meme-API/main/api/public/img/fry.png -------------------------------------------------------------------------------- /api/public/img/aliens.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronpk/Meme-API/main/api/public/img/aliens.jpg -------------------------------------------------------------------------------- /api/public/img/kenobi.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronpk/Meme-API/main/api/public/img/kenobi.gif -------------------------------------------------------------------------------- /api/public/img/kenobi.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronpk/Meme-API/main/api/public/img/kenobi.jpg -------------------------------------------------------------------------------- /api/public/img/mugatu.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronpk/Meme-API/main/api/public/img/mugatu.jpg -------------------------------------------------------------------------------- /api/public/img/sparta.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronpk/Meme-API/main/api/public/img/sparta.jpg -------------------------------------------------------------------------------- /api/public/img/taken.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronpk/Meme-API/main/api/public/img/taken.jpg -------------------------------------------------------------------------------- /api/public/img/walter.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronpk/Meme-API/main/api/public/img/walter.jpg -------------------------------------------------------------------------------- /api/public/img/wonka.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronpk/Meme-API/main/api/public/img/wonka.jpg -------------------------------------------------------------------------------- /api/public/img/xzibit.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronpk/Meme-API/main/api/public/img/xzibit.jpg -------------------------------------------------------------------------------- /api/public/img/y_u_no.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronpk/Meme-API/main/api/public/img/y_u_no.jpg -------------------------------------------------------------------------------- /api/test/init.rb: -------------------------------------------------------------------------------- 1 | require 'minitest/autorun' 2 | require 'json' 3 | require './lib/meme-match' 4 | 5 | -------------------------------------------------------------------------------- /api/public/img/boromir.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronpk/Meme-API/main/api/public/img/boromir.jpg -------------------------------------------------------------------------------- /api/public/img/emperor.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronpk/Meme-API/main/api/public/img/emperor.jpg -------------------------------------------------------------------------------- /api/public/img/ned_stark.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronpk/Meme-API/main/api/public/img/ned_stark.jpg -------------------------------------------------------------------------------- /api/public/img/over_9000.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronpk/Meme-API/main/api/public/img/over_9000.jpg -------------------------------------------------------------------------------- /api/public/img/batman-slap.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronpk/Meme-API/main/api/public/img/batman-slap.jpg -------------------------------------------------------------------------------- /api/public/img/craig-happy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronpk/Meme-API/main/api/public/img/craig-happy.jpg -------------------------------------------------------------------------------- /api/public/img/inquisition.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronpk/Meme-API/main/api/public/img/inquisition.jpg -------------------------------------------------------------------------------- /api/public/img/all_the_things.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronpk/Meme-API/main/api/public/img/all_the_things.jpg -------------------------------------------------------------------------------- /api/public/img/goes_to_eleven.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronpk/Meme-API/main/api/public/img/goes_to_eleven.jpg -------------------------------------------------------------------------------- /api/public/img/i_am_the_law.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronpk/Meme-API/main/api/public/img/i_am_the_law.jpg -------------------------------------------------------------------------------- /api/public/img/kermit-panic.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronpk/Meme-API/main/api/public/img/kermit-panic.gif -------------------------------------------------------------------------------- /api/public/img/laughing-men.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronpk/Meme-API/main/api/public/img/laughing-men.jpg -------------------------------------------------------------------------------- /api/public/img/too_damn_high.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronpk/Meme-API/main/api/public/img/too_damn_high.jpg -------------------------------------------------------------------------------- /api/public/img/conspiracy_keanu.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronpk/Meme-API/main/api/public/img/conspiracy_keanu.jpg -------------------------------------------------------------------------------- /api/public/img/fantastic-doctor.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronpk/Meme-API/main/api/public/img/fantastic-doctor.jpg -------------------------------------------------------------------------------- /api/public/img/most_interesting.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronpk/Meme-API/main/api/public/img/most_interesting.jpg -------------------------------------------------------------------------------- /api/public/img/shampoo-is-better.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronpk/Meme-API/main/api/public/img/shampoo-is-better.jpg -------------------------------------------------------------------------------- /api/public/img/you_should_feel_bad.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronpk/Meme-API/main/api/public/img/you_should_feel_bad.jpg -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | rvm: 3 | - 2.6.3 4 | root: false 5 | gemfile: api/Gemfile 6 | script: sh -c 'cd api && bundle exec rake' 7 | -------------------------------------------------------------------------------- /api/config.template.yml: -------------------------------------------------------------------------------- 1 | base_url: http://localhost:9393 2 | google_server_key: 3 | google_cx: 4 | database: "mysql2://root@127.0.0.1/memes" 5 | -------------------------------------------------------------------------------- /api/Rakefile: -------------------------------------------------------------------------------- 1 | Bundler.require 2 | require 'rake/testtask' 3 | 4 | Rake::TestTask.new do |t| 5 | t.pattern = ENV['TEST_PATTERN'] || "test/**/*_spec.rb" 6 | end 7 | 8 | task :default => :test 9 | 10 | -------------------------------------------------------------------------------- /api/config.ru: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'bundler/setup' 3 | require 'open-uri' 4 | 5 | Bundler.require 6 | 7 | set :public_folder, 'public' 8 | 9 | require './app.rb' 10 | 11 | run Sinatra::Application 12 | 13 | -------------------------------------------------------------------------------- /api/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'rake' 4 | 5 | gem 'thin' 6 | gem 'sinatra' 7 | gem 'httparty' 8 | gem 'meme_captain' 9 | gem 'new_base_60' 10 | 11 | gem 'mysql2' 12 | gem 'sequel' 13 | 14 | group :development do 15 | gem 'shotgun' 16 | end 17 | 18 | group :test do 19 | gem 'minitest' 20 | end 21 | -------------------------------------------------------------------------------- /api/schema.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `memes` ( 2 | `id` int(11) unsigned NOT NULL AUTO_INCREMENT, 3 | `date` datetime DEFAULT NULL, 4 | `tz` varchar(50) DEFAULT NULL, 5 | `nick` varchar(50) DEFAULT NULL, 6 | `channel` varchar(50) DEFAULT NULL, 7 | `server` varchar(50) DEFAULT NULL, 8 | `filename` varchar(50) DEFAULT NULL, 9 | `text` text, 10 | PRIMARY KEY (`id`) 11 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 12 | -------------------------------------------------------------------------------- /api/README.md: -------------------------------------------------------------------------------- 1 | MemeCaptain API 2 | =============== 3 | 4 | This is a simple Sinatra app that wraps the [meme_captain](https://github.com/mmb/meme_captain) gem. 5 | 6 | To run this using passenger, create an nginx config block like the following: 7 | 8 | --- 9 | server { 10 | listen 80; 11 | server_name meme.loqi.me; 12 | 13 | root /web/zenircbot-meme/api/public; 14 | passenger_enabled on; 15 | 16 | location / { 17 | rewrite ^/([0-9a-zA-Z_]+\.jpg)$ /m/$1 break; 18 | passenger_enabled on; 19 | } 20 | } 21 | --- 22 | 23 | -------------------------------------------------------------------------------- /api/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | daemons (1.3.1) 5 | eventmachine (1.2.7) 6 | httparty (0.16.2) 7 | multi_xml (>= 0.5.2) 8 | meme_captain (0.3.1) 9 | mime-types (~> 2.5) 10 | rmagick (~> 2.14.0) 11 | mime-types (2.99.3) 12 | minitest (5.11.3) 13 | multi_xml (0.6.0) 14 | mustermann (1.0.3) 15 | mysql2 (0.5.2) 16 | new_base_60 (1.1.2) 17 | rack (2.0.7) 18 | rack-protection (2.0.5) 19 | rack 20 | rake (12.3.3) 21 | rmagick (2.14.0) 22 | sequel (5.22.0) 23 | shotgun (0.9.2) 24 | rack (>= 1.0) 25 | sinatra (2.0.5) 26 | mustermann (~> 1.0) 27 | rack (~> 2.0) 28 | rack-protection (= 2.0.5) 29 | tilt (~> 2.0) 30 | thin (1.7.2) 31 | daemons (~> 1.0, >= 1.0.9) 32 | eventmachine (~> 1.0, >= 1.0.4) 33 | rack (>= 1, < 3) 34 | tilt (2.0.9) 35 | 36 | PLATFORMS 37 | ruby 38 | 39 | DEPENDENCIES 40 | httparty 41 | meme_captain 42 | minitest 43 | mysql2 44 | new_base_60 45 | rake 46 | sequel 47 | shotgun 48 | sinatra 49 | thin 50 | 51 | BUNDLED WITH 52 | 1.16.2 53 | -------------------------------------------------------------------------------- /api/lib/meme-match.rb: -------------------------------------------------------------------------------- 1 | class MemeMatch 2 | 3 | def self.split(input) 4 | top = nil 5 | bottom = nil 6 | 7 | split = input.split '|' 8 | 9 | if split.length == 1 10 | if input[-1] == "|" 11 | top = split[0] 12 | else 13 | bottom = split[0] 14 | end 15 | elsif split.length == 2 16 | top = split[0] 17 | bottom = split[1] 18 | end 19 | 20 | top = top.gsub(/[. \|]+$/,'') if top 21 | bottom = bottom.gsub(/[. \|]+$/,'').gsub(/^[| ]+/,'') if bottom 22 | 23 | top = nil if top == "" 24 | bottom = nil if bottom == "" 25 | 26 | { 27 | top: top, 28 | bottom: bottom 29 | } 30 | end 31 | 32 | @@memes = {} 33 | 34 | def self.load_memes 35 | @@memes = JSON.parse IO.read File.dirname(__FILE__) + '/../memes.json' 36 | end 37 | 38 | def self.memes 39 | @@memes['memes'] 40 | end 41 | 42 | def self.match_meme(input) 43 | self.memes.each do |meme| 44 | if match=Regexp.new(meme['regex'], true).match(input) 45 | return { 46 | top: match.captures[0], 47 | bottom: match.captures[1], 48 | img: meme['img'] 49 | } 50 | end 51 | end 52 | nil 53 | end 54 | 55 | end 56 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Meme API 2 | ======== 3 | An API and TikTokBot integration that implements a !meme command to generate a meme image 4 | 5 | Usage 6 | ===== 7 | 8 | You can explicitly invoke the meme generator from Slack or IRC by saying `!meme ...` 9 | 10 | The top text is the message before the first '.' is encountered. Unless there is no '.', then all of the text is put on the bottom of the image. You can also explicitly set the top and bottom text by separating with `|`. 11 | 12 | The default image is the Aliens guy if no image is specified: 13 | 14 | 15 | 16 | You can override the default image by putting an image url or search term after the message surrounded by []. 17 | 18 | Examples 19 | ======== 20 | !meme I don't always test my code. | But when I do, I do it in production [http://meme.loqi.me/img/most_interesting.jpg] 21 | 22 | 23 | 24 | !meme Top | Bottom [http://meme.loqi.me/img/most_interesting.jpg] 25 | 26 | !meme Top | Bottom [largest bunny] 27 | 28 | Auto-detecting memes 29 | ==================== 30 | 31 | Certain sentences will be auto-matched according to the regexes in [memes.json](api/memes.json), and memes will be created without explicitly using the !meme command. 32 | 33 | Feel free to add new meme templates to the config! 34 | 35 | -------------------------------------------------------------------------------- /api/test/regex_spec.rb: -------------------------------------------------------------------------------- 1 | require_relative './init' 2 | 3 | describe MemeMatch do 4 | 5 | def assert_top_and_bottom(match) 6 | match[:top].must_equal 'top' 7 | match[:bottom].must_equal 'bottom' 8 | end 9 | 10 | def assert_bottom_only(match) 11 | match[:top].must_equal nil 12 | match[:bottom].must_equal 'bottom' 13 | end 14 | 15 | def assert_top_only(match) 16 | match[:top].must_equal 'top' 17 | match[:bottom].must_equal nil 18 | end 19 | 20 | it 'matches top and bottom' do 21 | assert_top_and_bottom MemeMatch.split('top... | bottom.') 22 | assert_top_and_bottom MemeMatch.split('top... | bottom') 23 | assert_top_and_bottom MemeMatch.split('top. | bottom.') 24 | assert_top_and_bottom MemeMatch.split('top. | bottom') 25 | assert_top_and_bottom MemeMatch.split('top | bottom.') 26 | assert_top_and_bottom MemeMatch.split('top | bottom') 27 | end 28 | 29 | it 'matches bottom' do 30 | assert_bottom_only MemeMatch.split('bottom') 31 | assert_bottom_only MemeMatch.split('bottom.') 32 | assert_bottom_only MemeMatch.split('|bottom') 33 | assert_bottom_only MemeMatch.split('| bottom') 34 | end 35 | 36 | it 'matches top' do 37 | assert_top_only MemeMatch.split('top|') 38 | assert_top_only MemeMatch.split('top |') 39 | assert_top_only MemeMatch.split('top. |') 40 | end 41 | 42 | it 'matches full sentence' do 43 | match = MemeMatch.split('line one. with a period. | line two.') 44 | match[:top].must_equal 'line one. with a period' 45 | match[:bottom].must_equal 'line two' 46 | end 47 | 48 | MemeMatch.load_memes 49 | MemeMatch.memes.each do |meme| 50 | it "matches #{meme['img']}" do 51 | result = MemeMatch.match_meme meme['test'] 52 | result.wont_be_nil 53 | result[:img].must_equal meme['img'] 54 | end 55 | end 56 | 57 | end 58 | -------------------------------------------------------------------------------- /api/memes.json: -------------------------------------------------------------------------------- 1 | {"memes": [ 2 | { 3 | "regex": "(^I don't (?:always|normally|usually) .+) (but when I do,? .+$)", 4 | "img": "most_interesting.jpg", 5 | "test": "I don't always test my code, but when I do, I do it in production." 6 | }, 7 | { 8 | "regex": "^([\\w:]+(?: [\\w:]+)?) (all the [\\w:]+s)[!\\.]*$", 9 | "img": "all_the_things.jpg", 10 | "test": "Refactor all the things!" 11 | }, 12 | { 13 | "regex": "(^one does not simply) (.+$)", 14 | "img": "boromir.jpg", 15 | "test": "One does not simply meme in IRC." 16 | }, 17 | { 18 | "regex": "(^not sure if [^\\|]+)(?: \\|)? (or .+$)", 19 | "img": "fry.png", 20 | "test": "Not sure if this is working, or is awesome." 21 | }, 22 | { 23 | "regex": "(^yo,? (?:dawg|dog)[\\.,]* I hea?rd (?:you|u) like .+) (so (?:i|we) .+$)", 24 | "img": "xzibit.jpg", 25 | "test": "Yo dawg I herd you like regex. so we put a regex in yo regex so you can match while you match." 26 | }, 27 | { 28 | "regex": "(^.+) (is too damn .+[!\\.]?$)", 29 | "img": "too_damn_high.jpg", 30 | "test": "The amount of memes in this channel is too damn high!" 31 | }, 32 | { 33 | "regex": "^(brace yourselves)[, ]+(.+ (?:is|are) coming)[!\\.]?$", 34 | "img": "ned_stark.jpg", 35 | "test": "Brace yourselves the memes are coming." 36 | }, 37 | { 38 | "regex": "(^what if) (.+[\\?!]+$)", 39 | "img": "conspiracy_keanu.jpg", 40 | "test": "What if space nachos?!" 41 | }, 42 | { 43 | "regex": "(^.+) (and you should feel bad\\.?$)", 44 | "img": "you_should_feel_bad.jpg", 45 | "test": "This meme is bad; and you should feel bad." 46 | }, 47 | { 48 | "regex": "(^.+) (y u no .+$)", 49 | "img": "y_u_no.jpg", 50 | "test": "IRC y u no do memes yourself?" 51 | }, 52 | { 53 | "regex": "(^am i the only one around here) (.+$)", 54 | "img": "walter.jpg", 55 | "test": "Am I the only one around here who gives a shit about the rules?!" 56 | }, 57 | { 58 | "regex": "(^.+) (so hot right now[\\.!]*$)", 59 | "img": "mugatu.jpg", 60 | "test": "Memes, so hot right now." 61 | }, 62 | { 63 | "regex": "(^.+) (is strong with this one[!\\.]*$)", 64 | "img": "emperor.jpg", 65 | "test": "The force is strong with this one." 66 | }, 67 | { 68 | "regex": "(^this is) (.{1,50}!$)", 69 | "img": "sparta.jpg", 70 | "test": "This is IRC!" 71 | }, 72 | { 73 | "regex": "(.+) (\\w+ go(?:es)? to (?:eleven|11))!?$", 74 | "img": "goes_to_eleven.jpg", 75 | "test": "The memes, they go to eleven!" 76 | }, 77 | { 78 | "regex": "^()(fantastic)!*$", 79 | "img": "fantastic-doctor.jpg", 80 | "test": "fantastic!" 81 | }, 82 | { 83 | "regex": "(^enough with) (.+!$)", 84 | "img": "batman-slap.jpg", 85 | "test": "Enough with the memes!" 86 | }, 87 | { 88 | "regex": "(^nobody expects) (.+$)", 89 | "img": "inquisition.jpg", 90 | "test": "Nobody expects a pull request!" 91 | }, 92 | { 93 | "regex": "(^.+ (?:is|are) better), (no .+ (?:is|are) better[!\\.])", 94 | "img": "shampoo-is-better.jpg", 95 | "test": "Shampoo is better, no conditioner is better!" 96 | }, 97 | { 98 | "regex": "(^if .+) (I would be so happy[!\\.]?)$", 99 | "img": "craig-happy.jpg", 100 | "test": "If it was warmer, I would be so happy" 101 | }, 102 | { 103 | "regex": "(.+) (over [0-9]+[\\.!]*)$", 104 | "img": "over_9000.jpg", 105 | "test": "His karma, it's over 9000!" 106 | }, 107 | { 108 | "regex": "^(and then (?:we|I) told (?:him|her|them),?) (.+)$", 109 | "img": "laughing-men.jpg", 110 | "test": "And then we told him we had consensus!" 111 | }, 112 | { 113 | "regex": "^(.+ (?:is|are)(?: ?n['o]?t) the .+) (you'?re looking for)", 114 | "img": "kenobi.gif", 115 | "test": "These are not the droids you're looking for" 116 | }, 117 | { 118 | "regex": "^(.+) ([^ ]+ kermit panic\\?*)$", 119 | "img": "kermit-panic.gif", 120 | "test": "did you immediately kermit panic?" 121 | }, 122 | { 123 | "regex": "^([^,]+),? (panic!+?)$", 124 | "img": "kermit-panic.gif", 125 | "test": "ok, panic!!" 126 | }, 127 | { 128 | "regex": "([^\\|]+)(?: \\|)? (I will find .+$)", 129 | "img": "taken.jpg", 130 | "test": "I don't know who you are. I will find you and add you to my LinkedIn." 131 | }, 132 | { 133 | "regex": "^(i .+),? (i am the .+)$", 134 | "img": "i_am_the_law.jpg", 135 | "test": "I can't break the cloud, I am the cloud!" 136 | }, 137 | { 138 | "regex": "^(oh really.+[,\? ]+?)(tell me more.+)", 139 | "img": "wonka.jpg", 140 | "test": "oh really? tell me more..." 141 | } 142 | ]} 143 | -------------------------------------------------------------------------------- /api/app.rb: -------------------------------------------------------------------------------- 1 | require_relative './lib/meme-match' 2 | require 'json' 3 | 4 | MemeMatch.load_memes 5 | $config = YAML.load_file 'config.yml' 6 | 7 | DB = Sequel.connect $config['database'] 8 | 9 | get '/g' do 10 | 11 | if !params[:u].match(/^http:/) 12 | return "Invalid image url" 13 | end 14 | 15 | open(params[:u], 'rb') do |f| 16 | begin 17 | i = MemeCaptain.meme_top_bottom(f, params[:t1], params[:t2], :font => './Impact.ttf') 18 | if(params[:u].match(/\.gif$/)) 19 | ext = "gif" 20 | else 21 | ext = "jpg" 22 | end 23 | filename = "#{DateTime.now.to_sxg}#{SecureRandom.random_number(60**5).to_sxg}.#{ext}" 24 | i.write("./public/m/#{filename}") 25 | headers 'Content-type' => 'application/json' 26 | {imageUrl: "http://#{request.host}/#{filename}"}.to_json 27 | rescue => e 28 | {error: e.message} 29 | end 30 | end 31 | 32 | end 33 | 34 | post '/message' do 35 | 36 | # TikTokBot posts JSON 37 | request.body.rewind 38 | @params = JSON.parse request.body.read 39 | 40 | top = nil 41 | bottom = nil 42 | img = nil 43 | 44 | if match=/^!meme (.+)/.match(@params['content']) 45 | # user explicitly requested a meme 46 | text = match.captures[0] 47 | # check if they specified an image or image search 48 | if match=/(.+) \[(https?:\/\/[^\] ]+)\]$/.match(text) 49 | text = match.captures[0] 50 | img = match.captures[1] 51 | split = MemeMatch.split text 52 | top = split[:top] 53 | bottom = split[:bottom] 54 | elsif match=/(.+) \[([^\]]+)\]$/.match(text) 55 | text = match.captures[0] 56 | search = match.captures[1] 57 | split = MemeMatch.split text 58 | top = split[:top] 59 | bottom = split[:bottom] 60 | img = image_search search 61 | else 62 | # check if the meme matches a pattern 63 | if match=MemeMatch.match_meme(text) 64 | top = match[:top] 65 | bottom = match[:bottom] 66 | img = match[:img] 67 | else 68 | # If it doesn't, make a meme anyway because it was explicitly requested 69 | split = MemeMatch.split text 70 | top = split[:top] 71 | bottom = split[:bottom] 72 | img = "aliens.jpg" # default 73 | end 74 | end 75 | else 76 | # all other chat messages are sent here, check if the line matches a meme pattern 77 | if match=MemeMatch.match_meme(@params['content']) 78 | top = match[:top] 79 | bottom = match[:bottom] 80 | img = match[:img] 81 | end 82 | end 83 | 84 | if img && !img.match(/^https?:\/\//) 85 | img = "./public/img/#{img}" 86 | end 87 | 88 | headers 'Content-type' => 'application/json' 89 | if img 90 | # If the message is from Slack, send back a typing indicator 91 | if @params['network'] == 'slack' 92 | HTTParty.post @params['response_url'], { 93 | body: {action: 'typing'} 94 | } 95 | end 96 | 97 | meme = make_meme img, top, bottom 98 | 99 | DB[:memes] << { 100 | date: DateTime.now.strftime('%Y-%m-%d %H:%M:%S'), 101 | tz: @params['author']['tz'], 102 | nick: @params['author']['nickname'], 103 | channel: @params['channel']['name'], 104 | server: @params['server'], 105 | filename: meme[:filename], 106 | text: @params['content'] 107 | } 108 | 109 | # If the message is from Slack, respond with the image as an attachment 110 | if @params['network'] == 'slack' 111 | if !top.nil? && !bottom.nil? 112 | title = "#{top} #{bottom}" 113 | elsif !top.nil? 114 | title = top 115 | else 116 | title = bottom 117 | end 118 | 119 | # response = { 120 | # attachments: [ 121 | # { 122 | # "fallback": meme[:url], 123 | # "title": title, 124 | # "image_url": meme[:url] 125 | # } 126 | # ] 127 | # }.to_json 128 | response = { 129 | file: { 130 | "title": title, 131 | "filename": title, 132 | "url": meme[:url] 133 | } 134 | }.to_json 135 | puts response 136 | response 137 | else 138 | # otherwise respond with a link to the image 139 | {content: meme[:url]}.to_json 140 | end 141 | else 142 | {error: "no image"}.to_json 143 | end 144 | end 145 | 146 | def make_meme(img, top, bottom) 147 | open(img, 'rb') do |f| 148 | begin 149 | i = MemeCaptain.meme_top_bottom(f, top, bottom, :font => './Impact.ttf') 150 | if(img.match(/\.gif$/)) 151 | ext = "gif" 152 | else 153 | ext = "jpg" 154 | end 155 | filename = "#{DateTime.now.to_sxg}#{SecureRandom.random_number(60**5).to_sxg}.#{ext}" 156 | i.write("./public/m/#{filename}") 157 | {url: "#{$config['base_url']}/m/#{filename}", filename: filename} 158 | rescue => e 159 | {error: e.message} 160 | end 161 | end 162 | end 163 | 164 | 165 | def image_search(term) 166 | query = URI.encode_www_form({ 167 | q: term, 168 | fileType: 'jpg', 169 | imgColorType: 'color', 170 | imgSize: 'large', 171 | imgType: 'photo', 172 | num: '1', 173 | safe: 'medium', 174 | searchType: 'image', 175 | cx: $config['google_cx'], 176 | key: $config['google_server_key'] 177 | }) 178 | response = HTTParty.get "https://www.googleapis.com/customsearch/v1?#{query}" 179 | if response && response.parsed_response 180 | r = response.parsed_response 181 | if r['items'] && r['items'].length > 0 182 | return r['items'][0]['link'] 183 | end 184 | end 185 | nil 186 | end 187 | 188 | --------------------------------------------------------------------------------