Skip to content

Commit

Permalink
#2 Added command random for lgtm.in fetching
Browse files Browse the repository at this point in the history
  • Loading branch information
phradion committed May 27, 2017
1 parent 5fe6dfe commit 32b1b7a
Show file tree
Hide file tree
Showing 8 changed files with 162 additions and 57 deletions.
6 changes: 4 additions & 2 deletions lgtm_hd.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ Gem::Specification.new do |spec|
spec.authors = ["Huy Dinh"]
spec.email = ["[email protected]"]

spec.summary = %q{Generating LGTM image to clipboard.}
spec.description = %q{Generating images from user input with LGTM text on it, or fetching images from LGTM.in based on user's query. Finally put the image to clipboard.}
spec.summary = %q{Generate LGTM image from a source image and copy to clipboard.}
spec.description = %q{Generate LGTM image from URL or file with smart text colors and positions. Support direct clipboard paste to github's comment box or Slack on MacOSX.}
spec.homepage = "http://github.com/phradion/lgtm_hd"
spec.license = "MIT"

Expand All @@ -34,7 +34,9 @@ Gem::Specification.new do |spec|
spec.add_development_dependency "rake", "~> 10.0"
spec.add_development_dependency "rspec", "3.6.0"
spec.add_development_dependency "simplecov"
spec.add_development_dependency "pry"
spec.add_development_dependency "codeclimate-test-reporter", "~> 1.0.0"
spec.add_runtime_dependency "open_uri_redirections"
spec.add_runtime_dependency "commander", "4.4.3"
spec.add_runtime_dependency "clipboard", "1.1.1"
spec.add_runtime_dependency "os", "1.0.0"
Expand Down
1 change: 1 addition & 0 deletions lib/lgtm_hd.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require "lgtm_hd/version"
require "lgtm_hd/configuration"
require "lgtm_hd/utilities"
require "lgtm_hd/lgtmdotin"
require "lgtm_hd/meme_generator"
require "lgtm_hd/cli"
135 changes: 87 additions & 48 deletions lib/lgtm_hd/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
require 'commander'
require 'os'
require 'clipboard'
require 'net/http'
require 'open-uri'
require 'uri'
require 'pry'

module LgtmHD
class CLI
Expand All @@ -12,80 +15,116 @@ def run
program :name, LgtmHD::Configuration::PROGRAM_NAME
program :version, LgtmHD::VERSION
program :description, LgtmHD::Configuration::DESCRIPTION

default_command :transform

command :transform do |c|
c.syntax = 'lgtm_hd <source_uri> <output_path> [--clipboard] [--interactive]'
c.summary = 'Generate a LGTM image from source_uri (local path or URL) into output folder'
global_option '-c', '--clipboard', 'Copy the end result (LGTM image) to OS\'s clipboard for direct pasting to other programs'
global_option '-i', '--interactive', 'Turn on interactive Mode. In case you forgot all these super complexive args and options' do say "-- LGTM HD Interactive Mode --" end

command :random do |c|
c.syntax = 'lgtm_hd random [--clipboard -c] [--interactive -i]'.freeze
c.summary = 'Fetch random images from LGTM.in and put into destination directory'.freeze
c.description = ''
c.example '', 'lgtm_hd export http://domain.com/image.png /path/to/lgtm.png'
c.option '--clipboard', 'Copy the end result (LGTM image) to OS\'s clipboard'
c.option '--interactive', 'In case you forgot all these super complexive args and options'
c.example 'Example', 'lgtm_hd random -c'

c.action do |args, options|
to_clipboard = options.clipboard
if options.interactive # Interactive mode!
input_dir = ask('[?] Destination Directory: ')
options.clipboard ||= agree("[?] Copy LGTM image to clipboard afterward? [Y/N]")
end
dest_dir = CLI.format_destination_dir(input_dir)
dest_file_prefix = CLI.format_destination_file_prefix
say "\\ Fetching random image from lgtm.in"
dest_uri,image_markdown = LgtmDotIn.fetch_random_image(dest_dir,dest_file_prefix) do |url, markdown|
say "\\ Loading image at #{url}"
end

say "\\ Exported image to #{dest_uri}"
if options.clipboard
copy_file_to_clipboard(dest_uri)
say "\\ Or you can copy the markdown format by lgtm.in directly below\n\n#{image_markdown}"
end
end
end

command :transform do |c|
c.syntax = 'lgtm_hd <image_URI> <dest_DIR> [--clipboard|-c] [--interactive|-i]'.freeze
c.summary = 'Generate a LGTM image from source_uri (local path or URL) into output folder'.freeze
c.description = ''
c.example 'Example', 'lgtm_hd transform http://domain.com/image.png /Users/lgtm/'

c.action do |args, options|
# ARGS validation!
if args.length == 2
if args.length >= 2
source_uri = args[0]
output_uri = args[1]
dest_dir = args[1]
elsif options.interactive # Interactive mode!
say "-- LGTM Interactive mode --"
source_uri = ask('Source (URL or Path/to/file): ')
output_uri = ask('Output Folder: ')
to_clipboard = agree("Copy to clipboard afterward? [Y/N]")
source_uri = ask('Source Image (URL or Path/to/file): ')
dest_dir = ask('Destination Directory: ')
options.clipboard ||= agree("Copy exported image to clipboard afterward? [Y/N]")
else
say "usage: lgtm_hd <source_uri> <output_path> [--clipboard] [--interactive]"
raise ArgumentError, "Too few or too many arguments provided, need 2: source and output URIs"
say "usage: lgtm_hd <source_img_URI> <dest_DIR> [--clipboard] [--interactive]"
raise ArgumentError, "Too few arguments provided. Need to provide <source_image_uri> and <destination_dir>"
end


# Validate the inputs
output_folder = File.expand_path(output_uri)
output_file = File.join(output_folder,
LgtmHD::Configuration::OUTPUT_PREFIX +
Time.now.strftime('%Y-%m-%d_%H-%M-%S') +
File.extname(source_uri))
raise "Source is not proper URIs (URL or Path/to/file)" unless source_uri =~ URI::regexp || File.exist?(source_uri)
raise "Output is invalid path or directory" unless File.exist?(output_folder) && File.directory?(output_folder)


dest_file = CLI.format_destination_uri(source_uri, dest_uri)
CLI.check_uris(dest_dir, source_uri)

# Do stuff with our LGTM meme
say "- Reading and inspecting source"
meme_generator = MemeGenerator.new(input_image_uri:source_uri, output_image_uri:output_file)
meme_generator = MemeGenerator.new(input_image_uri:source_uri, output_image_uri:dest_file)
say "- Rendering output"
meme_generator.draw

# Export and play around with the clipboard
say "- exporting to file"
meme_generator.export do |output|
say "LGTM image has been generated at #{output}."
if to_clipboard then
if OS.mac? then
applescript "set the clipboard to (read (POSIX file \"#{output}\") as GIF picture)"
say "I see you are using MacOSX. Content of the file has been copied to your clipboard."

# Apple Script Command reference
# Sample: `osascript -e 'set the clipboard to (read (POSIX file "#{output}") as JPEG picture)'`
#
# Currently Github allow pasting image directly to comment box.
# However it does not support pure text content produced by pbcopy so we have to use direct Applescript
# No Universal solution as for now.
#
# Apple Script reference: http://www.macosxautomation.com/applescript/imageevents/08.html
else
Clipboard.copy(output)
say "Path to LGTM file has been copied to your clipboard."
end
say "- Exported LGTM image to #{output}."
if options.clipboard then
CLI.copy_file_to_clipboard(output_file)
end # end of if to_clipboard
end # end of meme_generator.export block
end # end of action
end # end of command transform

end
run!
end # end run def

private

def copy_file_to_clipboard(output_file)
if OS.mac? then
applescript "set the clipboard to (read (POSIX file \"#{output_file}\") as GIF picture)"
say "\\ Copied file to OS's clipboard for direct pasting to Github comments or Slack"

# Apple Script Command reference
# Sample: `osascript -e 'set the clipboard to (read (POSIX file "#{output}") as JPEG picture)'`
#
# Currently Github allow pasting image directly to comment box.
# However it does not support pure text content produced by pbcopy so we have to use direct Applescript
# No Universal solution as for now.
#
# Apple Script reference: http://www.macosxautomation.com/applescript/imageevents/08.html
else
Clipboard.copy(output_file)
say "\\ Copied file's path to OS's clipboard"
end
end

run!
def self.check_uris(dest_dir, source_uri = nil)
raise "Source is not proper URIs (URL or Path/to/file)" unless source_uri =~ URI::regexp || File.exist?(source_uri)
if source_uri then return end
raise "Output is invalid path or directory" unless File.exist?(dest_dir) && File.directory?(dest_dir)
end

def self.format_destination_dir(dest_dir)
dest_dir ||= LgtmHD::Configuration::OUTPUT_PATH_DEFAULT
File.expand_path(dest_dir)
end
def self.format_destination_file_prefix
LgtmHD::Configuration::OUTPUT_PREFIX + Time.now.strftime('%Y%m%d%H%M%S')
end
end
end

end # end of Class
end # end of Module
5 changes: 5 additions & 0 deletions lib/lgtm_hd/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@ module LgtmHD
module Configuration
# Program configurations
PROGRAM_NAME = "lgtm_hd".freeze
AUTHOR = "Huy Dinh <[email protected]>".freeze
DESCRIPTION = "Generating images from user input with LGTM text on it, or fetching images from LGTM.in based on user's query. Finally put the image to clipboard.".freeze

# Output Image configurations
OUTPUT_PATH_DEFAULT = "/tmp".freeze
if (File.exist?("~/Desktop"))
OUTPUT_PATH_DEFAULT = File.expand("~/Desktop").freeze
end
OUTPUT_PREFIX = "lgtm_hd_".freeze
OUTPUT_MAX_WIDTH = 500.freeze
OUTPUT_MAX_HEIGHT = 500.freeze
Expand Down
57 changes: 57 additions & 0 deletions lib/lgtm_hd/lgtmdotin.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
require 'resolv-replace'
require 'open-uri'

module LgtmHD
class LgtmDotIn
API_STARTING_ENDPOINT = "http://www.lgtm.in/g".freeze
ACTUAL_IMAGE_URL_USE_SSL = false
TRY_FETCHING_IMAGE_LIMIT = 3
TRY_FETCHING_META_LIMIT = 3

def self.fetch_random_image(dest_path = nil, file_prefix = nil)
# LGTM.in has so many broken images
# So we loop until a good image is found
limit = TRY_FETCHING_IMAGE_LIMIT
begin
json_data = fetch_meta_data
image_url = json_data["actualImageUrl"]
image_markdown = json_data["markdown"]
yield image_url, image_markdown

# fetching image data
dest_file = File.join(dest_path ||= '/tmp', (file_prefix ||= 'lgtmdotin_') + File.extname(image_url))
uri = URI.parse(image_url)

uri.open(redirect: false, ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE) do |input_stream|
File.open(dest_file, 'wb') do |output_stream|
IO.copy_stream(input_stream, output_stream)
end
end
[dest_file, image_markdown]
rescue OpenURI::HTTPError, SocketError, Net::ReadTimeout => error
retry if (limit -= 1) > 0
raise error, "We have tried 3 times but all images are broken. Either LGTM.in is trash or you are super unlucky"
end
end


private
def self.fetch_meta_data(uri = API_STARTING_ENDPOINT, limit = TRY_FETCHING_META_LIMIT)
uri = URI.parse(API_STARTING_ENDPOINT)
##
# LGTM.in has a JSON endpoint that
# .forwards to an SSL HTTP address that
# .has no valid SSL certificate
# Hence the loop
#
begin
data = uri.open('Accept' => 'application/json', redirect: false, ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE)
json = JSON.parse data.readlines.join("")
rescue OpenURI::HTTPRedirect => redirect
uri = redirect.uri # assigned from the "Location" response header
retry if (limit -= 1) > 0
raise IOError, "There maybe a network issue. The program failed to contact LGTM.in JSON API"
end
end
end
end
10 changes: 4 additions & 6 deletions lib/lgtm_hd/meme_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

module LgtmHD
class MemeGenerator

@@caption_positions = {caption_position_top: "north center", caption_position_bottom: "south center"}

# TODO make options list for this class
# TODO pass BLOB data into this class instead of paths
def initialize(input_image_uri:, output_image_uri:)
Expand Down Expand Up @@ -54,11 +55,8 @@ def image_max_size
# Default value is top
#
def caption_position
if not [:caption_position_top, :caption_position_bottom].include? (@caption_position)
@caption_position = :caption_position_bottom
end
return {:caption_position_top => "north center",
:caption_position_bottom => "south center"}[@caption_position]
@caption_position = :caption_position_bottom unless [:caption_position_top, :caption_position_bottom].include? @caption_position
@@caption_positions[@caption_position]
end

def caption_font
Expand Down
3 changes: 3 additions & 0 deletions lib/lgtm_hd/utilities.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
require 'open-uri'
require 'net/http'

module LgtmHD
def self.gem_root
File.expand_path '../../..', __FILE__
Expand Down
2 changes: 1 addition & 1 deletion lib/lgtm_hd/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module LgtmHD
VERSION = "0.1.4".freeze
VERSION = "0.1.5".freeze
end

0 comments on commit 32b1b7a

Please sign in to comment.