viddl 0.0.2

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: 754721cccbe03abc4baaaeeb3cc7b4a466ff792b
4
+ data.tar.gz: 4aaddeaa7ff0dcd5bdedd75e81168671a640e528
5
+ SHA512:
6
+ metadata.gz: d0ac5e272ff2b62a0db0e2de646c85450ad802a1b9248216966f1421a3fdcaa555ca4938c867629bc09756945915f787e59976195147852941bc0823cc1ac5c8
7
+ data.tar.gz: 81f1c6314ab103b92c6bead41880835dc5eb4afebe9362d09f6881d35cc9fb4122b8b82604745b426364dfe7ec8d410ce14fa1f725d965e696451fa4d143fd8f
data/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright 2017 Ari Russo
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,100 @@
1
+ # Viddl
2
+
3
+ ![Viddl](http://i.imgur.com/OuHviqv.png "Viddl")
4
+
5
+ Use Viddl to quickly download, cut, crop and resize videos
6
+
7
+ Viddl can be used at the [command line](#command-line) or in [Ruby](#ruby)
8
+
9
+ It requires that both [youtube-dl](https://github.com/rg3/youtube-dl) and [ffmpeg](https://ffmpeg.org) are installed before using.
10
+
11
+ ## Usage
12
+
13
+ Running Viddl generates video clip files in the current directory
14
+
15
+ ### Command Line
16
+
17
+ The command line usage and options are as follows:
18
+
19
+ #### Download
20
+
21
+ With no options, Viddl will download the original video
22
+
23
+ ```sh
24
+ viddl https://www.youtube.com/watch?v=6g4dkBF5anU
25
+ ```
26
+
27
+ #### Cut
28
+
29
+ This will start the clip at 10 seconds into the original video and run for five seconds
30
+
31
+ ```sh
32
+ viddl https://www.youtube.com/watch?v=6g4dkBF5anU -s 10 -d 5
33
+ ```
34
+
35
+ Alternately, this will start the clip at 15 seconds in the original video and stop at 22 seconds
36
+
37
+ ```sh
38
+ viddl https://www.youtube.com/watch?v=6g4dkBF5anU -s 15 -e 22
39
+ ```
40
+
41
+ #### Resize
42
+
43
+ This will resize to 640 x 480:
44
+
45
+ ```sh
46
+ viddl https://www.youtube.com/watch?v=6g4dkBF5anU -w 640 -h 480
47
+ ```
48
+
49
+ #### Crop
50
+
51
+ This will crop a 40 x 40 pixel box at position 20 x 20:
52
+
53
+ ```sh
54
+ viddl https://www.youtube.com/watch?v=6g4dkBF5anU --cx 20 --cy 20 --cw 40 --ch 40
55
+ ```
56
+
57
+ #### Strip Audio
58
+
59
+ Audio can be left out of the clip:
60
+
61
+ ```sh
62
+ viddl https://www.youtube.com/watch?v=6g4dkBF5anU --no-audio
63
+ ```
64
+
65
+ #### Combine
66
+
67
+ Any or all of these options can be used together:
68
+
69
+ ```sh
70
+ viddl https://www.youtube.com/watch?v=6g4dkBF5anU -s 15 -e 22 --no-audio --cx 20 --cy 20 --cw 40 --ch 40 -w 640 -h 480
71
+ ```
72
+
73
+ ### Ruby
74
+
75
+ Similar to the command line, Ruby usage and options are as follows:
76
+
77
+ ```ruby
78
+ options = {
79
+ start: 15,
80
+ end: 22,
81
+ audio: false,
82
+ crop: {
83
+ x: 20,
84
+ y: 20,
85
+ width: 40,
86
+ height: 40
87
+ },
88
+ width: 640,
89
+ height: 480
90
+ }
91
+
92
+ video = Viddl::Video.download("https://www.youtube.com/watch?v=6g4dkBF5anU")
93
+ video.create_clip(options)
94
+ ```
95
+
96
+ ## License
97
+
98
+ Licensed under Apache 2.0, See the file LICENSE
99
+
100
+ Copyright (c) 2017 [Ari Russo](http://arirusso.com)
data/bin/viddl ADDED
@@ -0,0 +1,80 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
3
+
4
+ require "optparse"
5
+ require "viddl"
6
+
7
+ def help(opts)
8
+ puts(opts)
9
+ exit
10
+ end
11
+
12
+ options = {}
13
+ opts = OptionParser.new do |opts|
14
+ opts.banner = "Usage: viddl [url] [options]"
15
+
16
+ ## cut
17
+
18
+ opts.on("-dDURATION", "--duration=DURATION", "Duration") do |duration|
19
+ options[:duration] = duration.to_f
20
+ end
21
+
22
+ opts.on("-eEND", "--end=END", "End time") do |en|
23
+ options[:end] = en.to_f
24
+ end
25
+
26
+ opts.on("-sSTART", "--start=START", "Start time") do |start|
27
+ options[:start] = start.to_f
28
+ end
29
+
30
+ # resize
31
+
32
+ opts.on("-wWIDTH", "--width=WIDTH", "Width") do |width|
33
+ options[:width] = width.to_i
34
+ end
35
+
36
+ opts.on("-hHEIGHT", "--height=HEIGHT", "Height") do |height|
37
+ options[:height] = height.to_i
38
+ end
39
+
40
+ # crop
41
+
42
+ opts.on("--cx=CX", "Crop X") do |cx|
43
+ options[:crop] ||= {}
44
+ options[:crop][:x] = cx.to_i
45
+ end
46
+
47
+ opts.on("--cy=CY", "Crop Y") do |cy|
48
+ options[:crop] ||= {}
49
+ options[:crop][:y] = cy.to_i
50
+ end
51
+
52
+ opts.on("--cw=CWIDTH", "Crop Width") do |cwidth|
53
+ options[:crop] ||= {}
54
+ options[:crop][:width] = cwidth.to_i
55
+ end
56
+
57
+ opts.on("--ch=CHEIGHT", "Crop Height") do |cheight|
58
+ options[:crop] ||= {}
59
+ options[:crop][:height] = cheight.to_i
60
+ end
61
+
62
+ # audio
63
+
64
+ opts.on("--no-audio", "No audio") do
65
+ options[:audio] = false
66
+ end
67
+
68
+ opts.on_tail("--help", "Show this message") { help(opts) }
69
+
70
+ end
71
+ opts.parse!
72
+
73
+ url = ARGV[0]
74
+
75
+ if url.nil?
76
+ help(opts) and exit
77
+ end
78
+
79
+ video = Viddl::Video.download(url)
80
+ video.create_clip(options)
data/lib/viddl.rb ADDED
@@ -0,0 +1,19 @@
1
+ #
2
+ # viddl
3
+ #
4
+ # (c)2017 Ari Russo
5
+ # Apache 2.0 License
6
+ # https://github.com/arirusso/viddl
7
+ #
8
+
9
+ # modules
10
+ require "viddl/system"
11
+ require "viddl/video"
12
+
13
+ module Viddl
14
+
15
+ extend self
16
+
17
+ VERSION = "0.0.2"
18
+
19
+ end
@@ -0,0 +1,38 @@
1
+ module Viddl
2
+
3
+ module System
4
+
5
+ extend self
6
+
7
+ # Validate that the system has all of its dependencies
8
+ # @return [Boolean]
9
+ def validate
10
+ validate_ffmpeg
11
+ validate_youtube_dl
12
+ true
13
+ end
14
+
15
+ private
16
+
17
+ # Validate that ffmpeg is installed
18
+ # @return [Boolean]
19
+ def validate_ffmpeg
20
+ result = Kernel.system("ffmpeg")
21
+ if result.nil?
22
+ raise("Viddl requires that ffmpeg be installed")
23
+ end
24
+ true
25
+ end
26
+
27
+ # Validate that youtube-dl is installed
28
+ # @return [Boolean]
29
+ def validate_youtube_dl
30
+ result = Kernel.system("youtube-dl")
31
+ if result.nil?
32
+ raise("Viddl requires that youtube-dl be installed https://github.com/rg3/youtube-dl")
33
+ end
34
+ end
35
+
36
+ end
37
+
38
+ end
@@ -0,0 +1,23 @@
1
+ require "viddl/video/clip"
2
+ require "viddl/video/download"
3
+ require "viddl/video/instance"
4
+
5
+ module Viddl
6
+
7
+ module Video
8
+
9
+ extend self
10
+
11
+ # Download a video using the given url
12
+ # @param [String] url
13
+ # @param [Hash] options
14
+ # @return [Video::Instance]
15
+ def download(url, options = {})
16
+ video = Instance.new(url)
17
+ video.process_download(options)
18
+ video
19
+ end
20
+
21
+ end
22
+
23
+ end
@@ -0,0 +1,129 @@
1
+ require "viddl/video/clip/audio"
2
+ require "viddl/video/clip/crop"
3
+ require "viddl/video/clip/cut"
4
+ require "viddl/video/clip/resize"
5
+
6
+ module Viddl
7
+
8
+ module Video
9
+
10
+ class Clip
11
+
12
+ MODULES = [Audio, Crop, Cut, Resize]
13
+
14
+ # Create a clip using the given video source file path and options
15
+ # @param [String] source_path Path to video file to create clip from
16
+ # @param [Hash] options
17
+ # @option options [Boolean] :audio Whether to include audio
18
+ # @option options [Numeric] :start Time in the source file where the clip starts
19
+ # @option options [Numeric] :duration Duration of the clip
20
+ # @option options [Numeric] :end Time in the source file where the clip ends
21
+ # @option options [Integer, String] :width The desired width to resize to
22
+ # @option options [Integer, String] :height The desired height to resize to
23
+ # @option options [Hash] :crop The desired crop parameters (:x, :y, :width, :height)
24
+ # @return [Clip]
25
+ def self.process(path, options = {})
26
+ clip = new(path)
27
+ clip.process(options)
28
+ clip
29
+ end
30
+
31
+ # @param [String] source_path Path to video file to create clip from
32
+ def initialize(source_path)
33
+ @source_path = source_path
34
+ end
35
+
36
+ # Create a clip using the given options
37
+ # @param [Hash] options
38
+ # @option options [Boolean] :audio Whether to include audio
39
+ # @option options [Numeric] :start Time in the source file where the clip starts
40
+ # @option options [Numeric] :duration Duration of the clip
41
+ # @option options [Numeric] :end Time in the source file where the clip ends
42
+ # @option options [Integer, String] :width The desired width to resize to
43
+ # @option options [Integer, String] :height The desired height to resize to
44
+ # @option options [Hash] :crop The desired crop parameters (:x, :y, :width, :height)
45
+ # @return [Boolean]
46
+ def process(options = {})
47
+ command = command_line(options)
48
+ Kernel.system(command)
49
+ end
50
+
51
+ private
52
+
53
+ # Command line to create a clip from the source file and given options
54
+ # @param [Hash] options
55
+ # @option options [Boolean] :audio Whether to include audio
56
+ # @option options [Numeric] :start Time in the source file where the clip starts
57
+ # @option options [Numeric] :duration Duration of the clip
58
+ # @option options [Numeric] :end Time in the source file where the clip ends
59
+ # @option options [Integer, String] :width The desired width to resize to
60
+ # @option options [Integer, String] :height The desired height to resize to
61
+ # @option options [Hash] :crop The desired crop parameters (:x, :y, :width, :height)
62
+ # @return [String]
63
+ def command_line(options = {})
64
+ if options.values.compact.empty?
65
+ # when there are no clip options, the source file can just be copied
66
+ # over to the output file location without using ffmpeg
67
+ "cp #{@source_path} #{output_path}"
68
+ else
69
+ formatted_opts = options_formatted(options)
70
+
71
+ modules_with_args = MODULES.select { |mod| mod.respond_to?(:args) }
72
+ modules_with_filters = MODULES.select { |mod| mod.respond_to?(:filter_args) }
73
+
74
+ module_args = modules_with_args.map { |mod| mod.args(formatted_opts) }.compact
75
+ module_filters = modules_with_filters.map { |mod| mod.filter_args(formatted_opts) }.compact
76
+
77
+ module_arg_string = module_args.join(" ")
78
+ unless module_filters.empty?
79
+ module_arg_string += " -vf '#{module_filters.join(",")}'"
80
+ end
81
+
82
+ "ffmpeg -i #{@source_path} #{module_arg_string} #{output_path(formatted_opts)}"
83
+ end
84
+ end
85
+
86
+ # Options formatted for ffmpeg
87
+ # @param [Hash] options
88
+ # @option options [Boolean] :audio Whether to include audio (default: true)
89
+ # @option options [Numeric] :start Time in the source file where the clip starts
90
+ # @option options [Numeric] :duration Duration of the clip
91
+ # @option options [Numeric] :end Time in the source file where the clip ends
92
+ # @option options [Integer, String] :width The desired width to resize to
93
+ # @option options [Integer, String] :height The desired height to resize to
94
+ # @option options [Hash] :crop The desired crop parameters (:x, :y, :width, :height)
95
+ # @return [Hash]
96
+ def options_formatted(options = {})
97
+ mod_options = MODULES.map { |mod| mod.options_formatted(options) }
98
+ mod_options.inject(:merge)
99
+ end
100
+
101
+ # Path of the created clip
102
+ # @param [Hash] options
103
+ # @option options [Boolean] :audio Whether to include audio
104
+ # @option options [Numeric] :start Time in the source file where the clip starts
105
+ # @option options [Numeric] :duration Duration of the clip
106
+ # @option options [Integer, String] :width The desired width to resize to
107
+ # @option options [Integer, String] :height The desired height to resize to
108
+ # @option options [Hash] :crop The desired crop parameters (:x, :y, :width, :height)
109
+ # @return [String]
110
+ def output_path(options = {})
111
+ base = @source_path.scan(/#{Download::TEMPDIR}\/(.*)/).flatten.first
112
+ result = base
113
+ if !options.values.flatten.compact.empty?
114
+ name, ext = *base.split(".")
115
+ tokens = ""
116
+ MODULES.each do |mod|
117
+ token = mod.filename_token(options)
118
+ tokens += "-#{token}" unless token.nil?
119
+ end
120
+ result = "#{name}#{tokens}.#{ext}"
121
+ end
122
+ result
123
+ end
124
+
125
+ end
126
+
127
+ end
128
+
129
+ end
@@ -0,0 +1,43 @@
1
+ module Viddl
2
+
3
+ module Video
4
+
5
+ class Clip
6
+
7
+ module Audio
8
+
9
+ extend self
10
+
11
+ # Audio options formatted for ffmpeg
12
+ # @param [Hash] options
13
+ # @option options [Boolean] :audio Whether to include audio (default: true)
14
+ # @return [Hash]
15
+ def options_formatted(options = {})
16
+ result = {}
17
+ result[:audio] = !options[:audio].eql?(false)
18
+ result
19
+ end
20
+
21
+ # Command line options for audio
22
+ # @param [Hash] options
23
+ # @option options [Boolean] :audio Whether to include audio (default: false)
24
+ # @return [String, nil]
25
+ def args(options = {})
26
+ "-an" if options[:audio].eql?(false)
27
+ end
28
+
29
+ # Token added to clip filename for audio args
30
+ # @param [Hash] options
31
+ # @option options [Boolean] :audio Whether to include audio in the clip (default: false)
32
+ # @return [String, nil]
33
+ def filename_token(options = {})
34
+ "noaudio" if options[:audio].eql?(false)
35
+ end
36
+
37
+ end
38
+
39
+ end
40
+
41
+ end
42
+
43
+ end