wgif 0.0.1.pre

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 29562cbe754b572ffd1fc5e20a397b96405a703b
4
+ data.tar.gz: 3c7307a0a239c7867d2d6a205c14153e8b7c44f3
5
+ SHA512:
6
+ metadata.gz: 5953cef31a710c37e9d99e229673005c4737f20952150b398a678088b45ee67b61835d5311a1271a0aaae454b9299de2e3c1253efd135bdcc3b9ed65c22024b1
7
+ data.tar.gz: bfb4c0a042e3baefaca3f35621787041e0870f4c98a2cfba4cac5cb4e4cb0ec939a6b8ee941d1752588268cc3b748a8ac8fb38ea4b9c110363179e72e50f2ee5
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.0.0-p247
data/.travis.yml ADDED
@@ -0,0 +1,11 @@
1
+ language: ruby
2
+ install:
3
+ - sudo apt-get update
4
+ - sudo apt-get install ffmpeg
5
+ - sudo apt-get install imagemagick
6
+ - bundle install
7
+ command: bundle exec rake
8
+ rvm:
9
+ - 2.1.0
10
+ - 2.0.0
11
+ - 1.9.3
data/Brewfile ADDED
@@ -0,0 +1,2 @@
1
+ install ffmpeg
2
+ install imagemagick
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in wgif.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Connor Mendenhall
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,90 @@
1
+ # WGif
2
+ ![Travis Build](https://travis-ci.org/ecmendenhall/wgif.png?branch=master)
3
+
4
+ WGif is a command line tool for creating animated GIFs from YouTube videos.
5
+
6
+ ##TL;DR
7
+ ```
8
+ Usage: wgif [YouTube URL] [output file] [options]
9
+
10
+ -f, --frames N Number of frames in the final gif. (Default 20)
11
+ -s, --start HH:MM:SS Start creating gif from input video at this timestamp. (Default 00:00:00)
12
+ -d, --duration seconds Number of seconds of input video to capture. (Default 1)
13
+ -w, --width pixels Width of the gif in pixels. (Default 480px)
14
+
15
+ Example:
16
+
17
+ $ wgif https://www.youtube.com/watch?v=1A78yTvIY1k bjork.gif -s 00:03:30 -d 2 -w 400
18
+ ```
19
+
20
+ ## Installation (Mac OS X)
21
+ To install from Rubygems:
22
+
23
+ ```sh
24
+ $ gem install wgif
25
+ ```
26
+
27
+ To install from source, run
28
+
29
+ ```sh
30
+ $ gem build wgif.gemspec
31
+ ```
32
+
33
+ and
34
+
35
+ ```sh
36
+ $ gem install wgif-0.0.1.pre.gem
37
+ ```
38
+
39
+ to install the executable.
40
+
41
+ WGif uses FFmpeg for video transcoding and ImageMagick to optimize GIFs.
42
+ To install dependencies with [Homebrew](http://brew.sh/), just run
43
+
44
+ ```sh
45
+ $ wgif install
46
+ ```
47
+
48
+ ## Making a GIF
49
+ WGif expects two arguments: a YouTube video URL and a name for the GIF it creates. So,
50
+
51
+ ```sh
52
+ $ wgif https://www.youtube.com/watch?v=1A78yTvIY1k bjork.gif
53
+ ```
54
+
55
+ Is enough to create a GIF of [Bjork explaining her television](https://www.youtube.com/watch?v=1A78yTvIY1k). Without any extra parameters, WGif starts at
56
+ the beginning of the video, and creates a 20-frame, 480px GIF of the first second. Since GIFs are more
57
+ art than science, you'll probably want to tweak the size, duration, and number of frames.
58
+
59
+ Start by isolating the section of the video you'd like to GIF. Bjork starts her advice about dishonest
60
+ Icelandic poets around 3 minutes 30 seconds, and it lasts about two seconds. Pass the start timestamp with
61
+ `-s` or `--start` and the duration with `-d` or `--duration`:
62
+
63
+ ```sh
64
+ $ wgif https://www.youtube.com/watch?v=1A78yTvIY1k bjork.gif --start 00:03:30 -d 2
65
+ ```
66
+
67
+ A good start, but the GIF is way too big: around 5.6 megabytes. We can pass `-f` or `--frames` to specify the
68
+ total number of frames in the finished GIF. This defaults to 20, so let's drop a few to reduce the file size:
69
+
70
+ ```sh
71
+ $ wgif https://www.youtube.com/watch?v=1A78yTvIY1k bjork.gif --start 00:03:30 -d 2 -f 18
72
+ ```
73
+
74
+ Down to 2.2 megabytes, but still not small enough to post on my Sugarcubes fan-Tumblr. Let's scale it down a little
75
+ with the `-w` or `--width` flag:
76
+
77
+ ```sh
78
+ $ wgif https://www.youtube.com/watch?v=1A78yTvIY1k bjork.gif --start 00:03:30 -d 2 -f 18 --width 350
79
+ ```
80
+
81
+ And here it is:
82
+
83
+ ![Bjork](http://i.imgur.com/NZXWwey.gif)
84
+ ### "You shouldn't let poets lie to you."
85
+
86
+ ## Contributions
87
+ Are welcome via pull request.
88
+
89
+ ## License
90
+ This project is MIT licensed. See [LICENSE.txt](https://github.com/ecmendenhall/wgif/blob/master/LICENSE.txt) for details.
data/Rakefile ADDED
@@ -0,0 +1,5 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+ task :default => :spec
data/bin/wgif ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env/ruby
2
+
3
+ require 'wgif/cli'
4
+ WGif::CLI.new.make_gif ARGV
data/lib/wgif.rb ADDED
@@ -0,0 +1,9 @@
1
+ require "wgif/cli"
2
+ require "wgif/download_bar"
3
+ require "wgif/downloader"
4
+ require "wgif/exceptions"
5
+ require "wgif/gif_maker"
6
+ require "wgif/installer"
7
+ require "wgif/version"
8
+ require "wgif/video"
9
+ require "wgif/video_cache"
data/lib/wgif/cli.rb ADDED
@@ -0,0 +1,125 @@
1
+ require 'optparse'
2
+ require 'wgif/exceptions'
3
+ require 'wgif/downloader'
4
+ require 'wgif/gif_maker'
5
+ require 'wgif/installer'
6
+
7
+ module WGif
8
+ class CLI
9
+
10
+ attr_accessor :parser
11
+
12
+ def initialize
13
+ @options = {}
14
+ @defaults = {
15
+ trim_from: '00:00:00',
16
+ duration: 1.0,
17
+ dimensions: '480'
18
+ }
19
+ @parser = OptionParser.new do |opts|
20
+ opts.on('-f N',
21
+ '--frames N',
22
+ 'Number of frames in the final gif. (Default 20)') {
23
+ |n| @options[:frames] = n.to_i
24
+ }
25
+ opts.on('-s HH:MM:SS',
26
+ '--start HH:MM:SS',
27
+ 'Start creating gif from input video at this timestamp. (Default 00:00:00)') {
28
+ |ts| @options[:trim_from] = ts
29
+ }
30
+ opts.on('-d seconds',
31
+ '--duration seconds',
32
+ 'Number of seconds of input video to capture. (Default 5)') {
33
+ |d| @options[:duration] = d.to_f
34
+ }
35
+ opts.on('-w pixels',
36
+ '--width pixels',
37
+ 'Width of the gif in pixels. (Default 500px)') {
38
+ |gs| @options[:dimensions] = gs
39
+ }
40
+
41
+ opts.on_tail('-h',
42
+ '--help',
43
+ 'Print help information.') {
44
+ print_help
45
+ exit
46
+ }
47
+ end
48
+ end
49
+
50
+ def parse_args(args)
51
+ options = @defaults.merge(parse_options args)
52
+ options.merge(url: args[0], output: args[1])
53
+ end
54
+
55
+ def parse_options(args)
56
+ @parser.parse! args
57
+ @options
58
+ end
59
+
60
+ def validate_args(parsed_args)
61
+ raise WGif::InvalidUrlException unless parsed_args[:url] =~ /\Ahttps?\:\/\/.*\z/
62
+ raise WGif::InvalidTimestampException unless parsed_args[:trim_from] =~ /\A\d{1,2}(?::\d{2})+(?:\.\d*)?\z/
63
+ raise WGif::MissingOutputFileException unless parsed_args[:output]
64
+ end
65
+
66
+ def make_gif(cli_args)
67
+ WGif::Installer.new.run if cli_args[0] == 'install'
68
+ rescue_errors do
69
+ args = parse_args cli_args
70
+ validate_args(args)
71
+ video = Downloader.new.get_video(args[:url])
72
+ clip = video.trim(args[:trim_from], args[:duration])
73
+ frames = clip.to_frames(frames: args[:frames])
74
+ GifMaker.new.make_gif(frames, args[:output], args[:dimensions])
75
+ end
76
+ end
77
+
78
+ private
79
+
80
+ def rescue_errors
81
+ begin
82
+ yield
83
+ rescue WGif::InvalidUrlException
84
+ print_error "That looks like an invalid URL. Check the syntax."
85
+ rescue WGif::InvalidTimestampException
86
+ print_error "That looks like an invalid timestamp. Check the syntax."
87
+ rescue WGif::MissingOutputFileException
88
+ print_error 'Please specify an output file.'
89
+ rescue WGif::VideoNotFoundException
90
+ print_error "WGif can't find a valid YouTube video at that URL."
91
+ rescue WGif::ClipEncodingException
92
+ print_error "WGif encountered an error transcoding the video."
93
+ rescue SystemExit => e
94
+ raise e
95
+ rescue Exception => e
96
+ print_error <<-error
97
+ Something went wrong creating your GIF. The details:
98
+
99
+ #{e}
100
+ #{e.backtrace.join("\n")}
101
+
102
+ Please open an issue at: https://github.com/ecmendenhall/wgif/issues/new
103
+ error
104
+ end
105
+ end
106
+
107
+ def print_error(message)
108
+ puts message, "\n"
109
+ print_help
110
+ exit 1
111
+ end
112
+
113
+ def print_help
114
+ puts "Usage: wgif [YouTube URL] [output file] [options]", "\n"
115
+ puts @parser.summarize, "\n"
116
+ puts <<-example
117
+ Example:
118
+
119
+ $ wgif https://www.youtube.com/watch?v=1A78yTvIY1k bjork.gif -s 00:03:30 -d 2 -w 400
120
+
121
+ example
122
+ end
123
+
124
+ end
125
+ end
@@ -0,0 +1,28 @@
1
+ require 'ruby-progressbar'
2
+
3
+ module WGif
4
+ class DownloadBar
5
+
6
+ FORMAT = '==> %p%% |%B|'
7
+ SMOOTHING = 0.8
8
+
9
+ attr_reader :progress_bar
10
+
11
+ def initialize
12
+ @progress_bar = ProgressBar.create(
13
+ format: FORMAT,
14
+ smoothing: SMOOTHING,
15
+ total: @size
16
+ )
17
+ end
18
+
19
+ def update_total(size)
20
+ @progress_bar.total = size
21
+ end
22
+
23
+ def increment_progress(size)
24
+ @progress_bar.progress += size
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,84 @@
1
+ require 'viddl-rb'
2
+ require 'typhoeus'
3
+ require 'wgif/download_bar'
4
+ require 'wgif/exceptions'
5
+ require 'wgif/video'
6
+ require 'wgif/video_cache'
7
+ require 'uri'
8
+ require 'cgi'
9
+
10
+ module WGif
11
+ class Downloader
12
+
13
+ def initialize
14
+ @cache = WGif::VideoCache.new
15
+ end
16
+
17
+ def video_url youtube_url
18
+ begin
19
+ urls = ViddlRb.get_urls(youtube_url)
20
+ urls.first
21
+ rescue
22
+ raise WGif::VideoNotFoundException
23
+ end
24
+ end
25
+
26
+ def video_id youtube_url
27
+ begin
28
+ uri = URI(youtube_url)
29
+ params = CGI.parse(uri.query)
30
+ params['v'].first
31
+ rescue
32
+ raise WGif::InvalidUrlException
33
+ end
34
+ end
35
+
36
+ def get_video youtube_url
37
+ id = video_id youtube_url
38
+ if cached_clip = @cache.get(id)
39
+ return cached_clip
40
+ else
41
+ temp = load_clip(id, youtube_url)
42
+ video = WGif::Video.new(id, temp.path)
43
+ video
44
+ end
45
+ end
46
+
47
+ private
48
+
49
+ def create_progress_bar request, output_file
50
+ size = nil
51
+ download_bar = WGif::DownloadBar.new
52
+
53
+ request.on_headers do |response|
54
+ size = response.headers['Content-Length'].to_i
55
+ download_bar.update_total(size)
56
+ end
57
+
58
+ request.on_body do |chunk|
59
+ output_file.write(chunk)
60
+ download_bar.increment_progress(chunk.size)
61
+ end
62
+ end
63
+
64
+ def request_clip youtube_url, output_file
65
+ clip_url = self.video_url youtube_url
66
+ request = Typhoeus::Request.new clip_url
67
+ create_progress_bar(request, output_file)
68
+ request.run
69
+ end
70
+
71
+ def load_clip id, youtube_url
72
+ FileUtils.mkdir_p "/tmp/wgif"
73
+ temp = File.open("/tmp/wgif/#{id}", 'wb')
74
+ begin
75
+ clip = request_clip(youtube_url, temp)
76
+ raise WGif::VideoNotFoundException unless clip.response_code == 200
77
+ ensure
78
+ temp.close
79
+ end
80
+ temp
81
+ end
82
+
83
+ end
84
+ end
@@ -0,0 +1,24 @@
1
+ module WGif
2
+
3
+ class InvalidUrlException < Exception
4
+ end
5
+
6
+ class InvalidTimestampException < Exception
7
+ end
8
+
9
+ class InvalidDurationException < Exception
10
+ end
11
+
12
+ class InvalidFramesException < Exception
13
+ end
14
+
15
+ class MissingOutputFileException < Exception
16
+ end
17
+
18
+ class VideoNotFoundException < Exception
19
+ end
20
+
21
+ class ClipEncodingException < Exception
22
+ end
23
+
24
+ end