wgif 0.0.1.pre

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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