muvy 0.1.0
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 +7 -0
- data/.gitignore +54 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/Gemfile +5 -0
- data/LICENSE +21 -0
- data/README.md +172 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/exe/muvy +5 -0
- data/lib/muvy.rb +5 -0
- data/lib/muvy/cli.rb +119 -0
- data/lib/muvy/download.rb +64 -0
- data/lib/muvy/errors.rb +9 -0
- data/lib/muvy/image.rb +125 -0
- data/lib/muvy/imagefolder.rb +56 -0
- data/lib/muvy/media.rb +62 -0
- data/lib/muvy/version.rb +3 -0
- data/lib/muvy/video.rb +60 -0
- data/muvy.gemspec +31 -0
- metadata +163 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 86d7b6a8c11d0ce8195f6d35bf9400028771c85a
|
|
4
|
+
data.tar.gz: a8c38340f7e011b1821f89f0e6ce7f040382dfd9
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 209b168a3b90bd569a48504295a4a745adbaf4e08c46d742d73b9027d12624fa6327dc9369fe738fbaf8a65f27f4d8668b048279eefb7723c4bd930397677122
|
|
7
|
+
data.tar.gz: 9bbcaa4a1ff2a929d2d1983d493e387b3f9124c104a9e74e6c9b5b84c6670e6266eed611b69fad1097873c4d009b473a1c99214df8cdae231f8a11f6d62859d4
|
data/.gitignore
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
*.gem
|
|
2
|
+
*.rbc
|
|
3
|
+
/.config
|
|
4
|
+
/coverage/
|
|
5
|
+
/InstalledFiles
|
|
6
|
+
/pkg/
|
|
7
|
+
/spec/reports/
|
|
8
|
+
/spec/examples.txt
|
|
9
|
+
/test/
|
|
10
|
+
/test/tmp/
|
|
11
|
+
/test/version_tmp/
|
|
12
|
+
/tmp/
|
|
13
|
+
|
|
14
|
+
# Used by dotenv library to load environment variables.
|
|
15
|
+
# .env
|
|
16
|
+
|
|
17
|
+
## Specific to RubyMotion:
|
|
18
|
+
.dat*
|
|
19
|
+
.repl_history
|
|
20
|
+
build/
|
|
21
|
+
*.bridgesupport
|
|
22
|
+
build-iPhoneOS/
|
|
23
|
+
build-iPhoneSimulator/
|
|
24
|
+
|
|
25
|
+
## Specific to RubyMotion (use of CocoaPods):
|
|
26
|
+
#
|
|
27
|
+
# We recommend against adding the Pods directory to your .gitignore. However
|
|
28
|
+
# you should judge for yourself, the pros and cons are mentioned at:
|
|
29
|
+
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
|
|
30
|
+
#
|
|
31
|
+
# vendor/Pods/
|
|
32
|
+
|
|
33
|
+
## Documentation cache and generated files:
|
|
34
|
+
/.yardoc/
|
|
35
|
+
/_yardoc/
|
|
36
|
+
/doc/
|
|
37
|
+
/rdoc/
|
|
38
|
+
|
|
39
|
+
## Environment normalization:
|
|
40
|
+
/.bundle/
|
|
41
|
+
/vendor/bundle
|
|
42
|
+
/lib/bundler/man/
|
|
43
|
+
|
|
44
|
+
# for a library or gem, you might want to ignore these files since the code is
|
|
45
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
46
|
+
Gemfile.lock
|
|
47
|
+
# .ruby-version
|
|
48
|
+
# .ruby-gemset
|
|
49
|
+
|
|
50
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
|
51
|
+
.rvmrc
|
|
52
|
+
|
|
53
|
+
# rspec failure tracking
|
|
54
|
+
.rspec_status
|
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2017 Aaron Agarunov
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+

|
|
2
|
+
|
|
3
|
+
**muvy** is a simple Ruby movie barcode generator.
|
|
4
|
+
You can feed it a youtube video, phone gallery, or any locally stored video files. It pulls most of the frames out, moves around the colors, and throws them back together in a neat montage.
|
|
5
|
+
|
|
6
|
+
------
|
|
7
|
+
* [Install](#install)
|
|
8
|
+
* [Notes](#notes)
|
|
9
|
+
* [Getting Started](#getting-started)
|
|
10
|
+
* [Usage](#usage)
|
|
11
|
+
* [Basics](#basics)
|
|
12
|
+
* [Options](#options)
|
|
13
|
+
* [Features](#features)
|
|
14
|
+
* [Examples](#examples)
|
|
15
|
+
* [Links](#links)
|
|
16
|
+
------
|
|
17
|
+
|
|
18
|
+
## Install
|
|
19
|
+
|
|
20
|
+
### Notes
|
|
21
|
+
|
|
22
|
+
* Currently version 0.2.0, with many [features still planned](#features).
|
|
23
|
+
|
|
24
|
+
### Getting Started
|
|
25
|
+
|
|
26
|
+
#### macOS
|
|
27
|
+
If you don't already have FFmpeg, ImageMagick, or youtube-dl installed, you can download all of them with [Homebrew](https://brew.sh/). You can use `ffmpeg -v`, `convert -v`, or `youtube-dl --version` at the terminal to check if you've already got them.
|
|
28
|
+
|
|
29
|
+
With Homewbrew, just bring up a terminal session and type:
|
|
30
|
+
```sh
|
|
31
|
+
$ brew install ffmpeg
|
|
32
|
+
$ brew install imagemagick
|
|
33
|
+
$ brew install youtube-dl
|
|
34
|
+
$ gem install muvy
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
#### Windows
|
|
38
|
+
1. You can [download Ruby here](https://rubyinstaller.org/).
|
|
39
|
+
2. Then you can grab [FFmpeg here](http://ffmpeg.zeranoe.com/builds/).
|
|
40
|
+
3. ..and then download [ImageMagick here](https://www.imagemagick.org/script/download.php#windows), **noting**:
|
|
41
|
+
* On the nth installation window, you need to check 2 boxes:
|
|
42
|
+
* [x] Add folder to your path variable
|
|
43
|
+
* [x] Download legacy binaries
|
|
44
|
+
4. And finally get [youtube-dl here](https://rg3.github.io/youtube-dl/download.html).
|
|
45
|
+
5. Then, you can install any gem like so:
|
|
46
|
+
```sh
|
|
47
|
+
$ gem install muvy
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
## Usage
|
|
52
|
+
|
|
53
|
+
### Basics
|
|
54
|
+
|
|
55
|
+
| Type | Command: `muvy [Type] [Options]` | Support |
|
|
56
|
+
|--------|--------------------------------------------|-----------------------------------------------------------------------------------------------|
|
|
57
|
+
| URL | `muvy https://someVideoSite.com/someVidID` | [youtube-dl supported sites](https://rg3.github.io/youtube-dl/supportedsites.html) |
|
|
58
|
+
| Local | `muvy /Documents/Fave-Films/movie.mp4` | [FFmpeg supported formats](https://www.ffmpeg.org/general.html#File-Formats) |
|
|
59
|
+
| Folder | `muvy /Downloads/Phone-Backup-1/Photos` | [ImageMagick supported formats](https://www.imagemagick.org/script/formats.php) |
|
|
60
|
+
|
|
61
|
+
### Options
|
|
62
|
+
|
|
63
|
+
#### `-p, --path`
|
|
64
|
+
|
|
65
|
+
Optionally specify the path where your final image will be saved.
|
|
66
|
+
**Default**: your present working directory
|
|
67
|
+
|
|
68
|
+
#### `-s, --style`
|
|
69
|
+
Optionally specify currently supported styles: [solid](link) or [stretch](link).
|
|
70
|
+
**Default**: solid
|
|
71
|
+
|
|
72
|
+
#### `-g, --gradient`
|
|
73
|
+
Optionally add a gradient on top of the final image.
|
|
74
|
+
|
|
75
|
+
Choose one:
|
|
76
|
+
```
|
|
77
|
+
black:heavy black:medium black:light
|
|
78
|
+
white:heavy white:medium white:light
|
|
79
|
+
```
|
|
80
|
+
**Default**: none
|
|
81
|
+
|
|
82
|
+
[See examples](link)
|
|
83
|
+
|
|
84
|
+
#### `--arc`
|
|
85
|
+
Pass `--arc` to wrap all of the lines around a center point.
|
|
86
|
+
|
|
87
|
+
[See examples](link)
|
|
88
|
+
|
|
89
|
+
#### `--rotate`
|
|
90
|
+
Pass `--rotate` to rotate the final image 90 degrees, i.e. to draw horizontal lines,
|
|
91
|
+
where the top is the 'start' of your media file.
|
|
92
|
+
TODO - check if the last sentence is true
|
|
93
|
+
|
|
94
|
+
#### `-h, --height`
|
|
95
|
+
Optionally specify a custom height for the output image.
|
|
96
|
+
|
|
97
|
+
#### `--format`
|
|
98
|
+
Optionally force the download quality for `youtube-dl`.
|
|
99
|
+
This determines the height of your image when using `-s stretch` only if you didn't specify --height.
|
|
100
|
+
**Default**: 135 *(854x480 DASH at 24fps)*
|
|
101
|
+
|
|
102
|
+
See [youtube-dl docs on format selection](https://github.com/rg3/youtube-dl/blob/master/README.md#format-selection).
|
|
103
|
+
|
|
104
|
+
#### `--frame_rate`
|
|
105
|
+
Optionally specify the amount of frames to extract per second from the media.
|
|
106
|
+
This determines the width of the image.
|
|
107
|
+
|
|
108
|
+
You should run `muvy [..]` without this option once and check the stats printout
|
|
109
|
+
to get an idea of a better number.
|
|
110
|
+
For example, if the stats printout used "1.6 fps," passing `--frame_rate 3.2`
|
|
111
|
+
would double the amount of frames, lines, and subsequently the width.
|
|
112
|
+
|
|
113
|
+
> Setting this to an unreasonable number might cause hundreds of thousands
|
|
114
|
+
of files to be temporarily created in your system's temp files.
|
|
115
|
+
|
|
116
|
+
#### `--start` and `--end`
|
|
117
|
+
Optionally specify starting and ending times for processing videos.
|
|
118
|
+
If you only specify one of them, the other will default to the start/end.
|
|
119
|
+
|
|
120
|
+
[Examples](link)
|
|
121
|
+
|
|
122
|
+
### Features
|
|
123
|
+
- [x] Accepting image galleries, local videos, and online videos
|
|
124
|
+
- [x] Specifying start & end times for frame extraction
|
|
125
|
+
- [x] Vertical lines
|
|
126
|
+
- [x] Horizontal lines
|
|
127
|
+
- [x] Stretched output (average of each line of pixels)
|
|
128
|
+
- [x] Arc distortion
|
|
129
|
+
- [ ] Spotmap output ('QR' code)
|
|
130
|
+
- [ ] Slit scan output
|
|
131
|
+
- [ ] 'Bedforms' output
|
|
132
|
+
- [ ] Dominant color algorithms
|
|
133
|
+
- [ ] via ImageMagick histograms
|
|
134
|
+
- [ ] via k-means clustering
|
|
135
|
+
- [ ] Fade to black or white on edges
|
|
136
|
+
- [ ] Pixel thickness control
|
|
137
|
+
- [ ] Colorspace adjustments
|
|
138
|
+
- [ ] Accept music files
|
|
139
|
+
- [ ] Generate audio waveforms
|
|
140
|
+
- [ ] Randomize waveform colors
|
|
141
|
+
- [ ] Presets
|
|
142
|
+
|
|
143
|
+
## Examples
|
|
144
|
+
|
|
145
|
+
## Troubleshooting
|
|
146
|
+
|
|
147
|
+
Make sure you can access `ffmpeg -v`, `magick -v`, and `youtube-dl --version` on the command line. If you can't, you likely have to update your existing PATH environment variable [like this](https://video.stackexchange.com/questions/20495/how-do-i-set-up-and-use-ffmpeg-in-windows).
|
|
148
|
+
|
|
149
|
+
You might also want to update all three binaries.
|
|
150
|
+
|
|
151
|
+
If it's not working out, [I've linked more generators](#links) and methods that you can try out, most of them depending on some combination of `ffmpeg` and `ImageMagick`.
|
|
152
|
+
|
|
153
|
+
## Links
|
|
154
|
+
* Binaries · Gems
|
|
155
|
+
* [FFmpeg](https://www.ffmpeg.org/documentation.html) · [Streamio FFmpeg](https://github.com/streamio/streamio-ffmpeg)
|
|
156
|
+
* [ImageMagick](https://www.imagemagick.org/script/command-line-options.php) · [MiniMagick](https://github.com/minimagick/minimagick)
|
|
157
|
+
* [youtube-dl](https://github.com/rg3/youtube-dl) · [youtube-dl.rb](https://github.com/layer8x/youtube-dl.rb)
|
|
158
|
+
* Other Works & Inspirations
|
|
159
|
+
* [Zach Whalen's Barcoder](http://zachwhalen.net/pg/barcoder/)
|
|
160
|
+
* [arcanesanctum generator](http://arcanesanctum.net/movie-barcode-generator/)
|
|
161
|
+
* [moviebarcode on tumblr](http://moviebarcode.tumblr.com/)
|
|
162
|
+
* [/u/etherealpenguin on reddit](https://www.reddit.com/r/dataisbeautiful/comments/3rb8zi/the_average_color_of_every_frame_of_a_given_movie/)
|
|
163
|
+
* [Colors of Motion](http://thecolorsofmotion.com/films)
|
|
164
|
+
* Slit scanning
|
|
165
|
+
* [informal catalogue of research on this topic by Levin](http://www.flong.com/texts/lists/slit_scan/)
|
|
166
|
+
* K-means clustering as dominant color algorithms
|
|
167
|
+
* [k-means clustering on wikipedia](link)
|
|
168
|
+
* ImageMagick Histograms
|
|
169
|
+
* [Sparse color docs](http://www.imagemagick.org/Usage/canvas/#sparse-color)
|
|
170
|
+
* [Stackoverflow discussion (1)](https://stackoverflow.com/questions/40381273/apply-gradient-mask-on-image-that-already-has-transparency-with-imagemagick)
|
|
171
|
+
* ImageMagick support
|
|
172
|
+
* tremendous thank you to [fmw](http://www.fmwconcepts.com/imagemagick/index.php) & [snibgo](http://im.snibgo.com/index.htm)
|
data/Rakefile
ADDED
data/bin/console
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require "bundler/setup"
|
|
4
|
+
require "muvy"
|
|
5
|
+
|
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
|
8
|
+
|
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
|
10
|
+
# require "pry"
|
|
11
|
+
# Pry.start
|
|
12
|
+
|
|
13
|
+
require "irb"
|
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/exe/muvy
ADDED
data/lib/muvy.rb
ADDED
data/lib/muvy/cli.rb
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
require 'muvy/media'
|
|
2
|
+
require 'muvy/errors'
|
|
3
|
+
require 'slop'
|
|
4
|
+
|
|
5
|
+
module Muvy
|
|
6
|
+
class CLI
|
|
7
|
+
attr_reader :media, :options
|
|
8
|
+
|
|
9
|
+
def start
|
|
10
|
+
parse
|
|
11
|
+
handle_media
|
|
12
|
+
handle_path
|
|
13
|
+
convert_options
|
|
14
|
+
read_media
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def parse
|
|
18
|
+
@options = Slop.parse do |o|
|
|
19
|
+
o.banner = "Usage: muvy [media link, file, or file path] [options]"
|
|
20
|
+
|
|
21
|
+
o.separator ""
|
|
22
|
+
o.separator "Optional adjustments:"
|
|
23
|
+
o.string "-p", "--path", "Directory to save final images, " +
|
|
24
|
+
"\n\t\t\s\s\s\sDefault: your pwd → #{Dir.pwd}",
|
|
25
|
+
default: Dir.pwd
|
|
26
|
+
o.string "-s", "--style", "Choose image style: solid, stretch " +
|
|
27
|
+
"\n\t\t\s\s\s\sDefault: solid",
|
|
28
|
+
default: "solid"
|
|
29
|
+
o.string "-g", "--gradient", "Add a gradient over the final image" +
|
|
30
|
+
"\n\t\t\s\s\s\sChoose one from: black:heavy black:medium black:light" +
|
|
31
|
+
"\n\t\t\s\s\s\s\t\t\s\s\s\s\swhite:heavy white:medium white:light" +
|
|
32
|
+
"\n\t\t\s\s\s\sDefault: none"
|
|
33
|
+
o.boolean "--arc", "Wrap all of the lines around a center point"
|
|
34
|
+
o.boolean "-r", "--rotate", "Image will have horizontal lines"
|
|
35
|
+
o.integer "-h", "--height", "Custom height of the final image"
|
|
36
|
+
o.string "--start", "Custom video start time"
|
|
37
|
+
o.string "--end", "Custom video end time"
|
|
38
|
+
o.string "--format", "Force youtube-dl to use a specific video quality"
|
|
39
|
+
o.string "--frame_rate", <<~FPS
|
|
40
|
+
Set a custom frame rate. Be careful!
|
|
41
|
+
\t\t\s\s\s\sSetting this to a high number might cause hundreds of
|
|
42
|
+
\t\t\s\s\s\sthousands of images to be generated in your sytem's temp dir.
|
|
43
|
+
\t\t\s\s\s\sThe specific frame_rate used by default for your file is printed
|
|
44
|
+
\t\t\s\s\s\safter generation. You can use that number to make a reasonable change.
|
|
45
|
+
FPS
|
|
46
|
+
|
|
47
|
+
o.separator "More:"
|
|
48
|
+
o.on "--help", "Shows this usage page" do
|
|
49
|
+
abort o.to_s
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
o.on "-v", "--version", "Displays the version" do
|
|
53
|
+
abort "muvy version #{VERSION}"
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
rescue Slop::Error => e
|
|
57
|
+
abort <<~ERROR
|
|
58
|
+
#{e}.
|
|
59
|
+
Type `muvy --help` to see options, or visit the
|
|
60
|
+
github repo for extensive usage examples.
|
|
61
|
+
ERROR
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
private
|
|
65
|
+
|
|
66
|
+
def handle_media
|
|
67
|
+
@media = options.arguments.shift
|
|
68
|
+
raise Muvy::Errors::NoMediaInput if media.nil?
|
|
69
|
+
rescue => e
|
|
70
|
+
abort input_error(e)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# if -path was specified but is invalid, raise an error
|
|
74
|
+
# if -path was not specified, it was set to the pwd by Slop defaults
|
|
75
|
+
def handle_path
|
|
76
|
+
raise Muvy::Errors::InvalidPathOption unless File.directory?(options[:path])
|
|
77
|
+
rescue => e
|
|
78
|
+
abort "#{e}: You specified a non-existent path '#{options[:path]}'"
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# FileUtils.remove_entry_secure is called before ::mktmpdir returns
|
|
82
|
+
def read_media
|
|
83
|
+
Dir.mktmpdir do |tmp_dir|
|
|
84
|
+
options[:tmp_dir] = tmp_dir
|
|
85
|
+
puts "Using #{tmp_dir} to store jobs locally..."
|
|
86
|
+
|
|
87
|
+
Media.new(media, options).run
|
|
88
|
+
end
|
|
89
|
+
rescue => e
|
|
90
|
+
abort media_error(e)
|
|
91
|
+
ensure
|
|
92
|
+
puts "#{options[:tmp_dir]} was erased." if options[:tmp_dir]
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def convert_options
|
|
96
|
+
@options = options.to_hash # finalize
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def input_error(e)
|
|
100
|
+
<<~INPUT_ERROR
|
|
101
|
+
#{e}
|
|
102
|
+
You forgot to enter a URL, file, or folder with images.
|
|
103
|
+
|
|
104
|
+
#{options}
|
|
105
|
+
INPUT_ERROR
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def media_error(e)
|
|
109
|
+
<<~MEDIA_ERROR
|
|
110
|
+
#{e}
|
|
111
|
+
Media is unrecognized.
|
|
112
|
+
The input was not a valid URL, file, or folder with images.
|
|
113
|
+
|
|
114
|
+
#{options}
|
|
115
|
+
MEDIA_ERROR
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
end
|
|
119
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'youtube-dl.rb'
|
|
4
|
+
|
|
5
|
+
module Muvy
|
|
6
|
+
class Download
|
|
7
|
+
attr_reader :media, :options, :settings
|
|
8
|
+
|
|
9
|
+
def initialize(media, options = {})
|
|
10
|
+
@media = media
|
|
11
|
+
@options = options
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def run
|
|
15
|
+
@settings = merge_settings
|
|
16
|
+
|
|
17
|
+
download_video
|
|
18
|
+
send_video
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def download_video
|
|
24
|
+
vid = YoutubeDL.download(media, settings)
|
|
25
|
+
add_options(vid)
|
|
26
|
+
|
|
27
|
+
puts <<~DOWNLOADED
|
|
28
|
+
Download complete.
|
|
29
|
+
Video title: #{vid.information[:title]}
|
|
30
|
+
Video URL: #{vid.information[:webpage_url]}
|
|
31
|
+
Video format: #{vid.information[:format]} saved as #{vid.information[:ext]}
|
|
32
|
+
as #{vid.information[:_filename]}
|
|
33
|
+
File size: #{(vid.information[:filesize] / 1.024e6).round(2)} MB.
|
|
34
|
+
DOWNLOADED
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Add important settings to @options hash for use by FFmpeg
|
|
38
|
+
def add_options(vid)
|
|
39
|
+
options[:fps] = vid.information[:fps]
|
|
40
|
+
options[:media_length] = vid.information[:duration]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def send_video
|
|
44
|
+
Video.new(settings[:output], options).run if File.exists?(settings[:output])
|
|
45
|
+
rescue => e
|
|
46
|
+
puts e
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# defaults holds default values
|
|
50
|
+
# options holds command-line arguments
|
|
51
|
+
# settings merges defaults with options where appropriate
|
|
52
|
+
def merge_settings
|
|
53
|
+
defaults = {
|
|
54
|
+
continue: false,
|
|
55
|
+
format: 135,
|
|
56
|
+
output: "#{options[:tmp_dir]}/" +
|
|
57
|
+
Time.now.strftime("%d-%m-%Y-%H%M%S") +
|
|
58
|
+
".mp4"
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
@settings = defaults.merge!(options.select { |k, v| defaults.key?(k) && v })
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
data/lib/muvy/errors.rb
ADDED
data/lib/muvy/image.rb
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
require "mini_magick"
|
|
2
|
+
|
|
3
|
+
module Muvy
|
|
4
|
+
class Image
|
|
5
|
+
attr_reader :media, :options
|
|
6
|
+
|
|
7
|
+
def initialize(media, options)
|
|
8
|
+
@media = media
|
|
9
|
+
@options = options
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def run
|
|
13
|
+
montage
|
|
14
|
+
modification
|
|
15
|
+
printout
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def montage
|
|
21
|
+
MiniMagick::Tool::Montage.new do |montage|
|
|
22
|
+
montage << "#{media}/thumb*.png"
|
|
23
|
+
montage.mode("Concatenate")
|
|
24
|
+
montage.tile("x1")
|
|
25
|
+
options[:img] =
|
|
26
|
+
File.absolute_path(options[:path]) +
|
|
27
|
+
"/muvy-" +
|
|
28
|
+
Time.now.strftime('%d-%m-%H%M%S') +
|
|
29
|
+
".png"
|
|
30
|
+
montage << options[:img]
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def modification
|
|
35
|
+
image = MiniMagick::Image.new(options[:img])
|
|
36
|
+
|
|
37
|
+
# TODO: Programatically trigger the methods based on options `nil` status
|
|
38
|
+
resize(image)
|
|
39
|
+
gradient(image)
|
|
40
|
+
rotate(image)
|
|
41
|
+
arc
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Arbitrary default height 720
|
|
45
|
+
def resize(image)
|
|
46
|
+
if options[:style] != "stretch"
|
|
47
|
+
image.resize "#{image.width}x#{options[:height] ||= 720}!"
|
|
48
|
+
elsif options[:height] # and style is stretch
|
|
49
|
+
image.resize "#{image.width}x#{options[:height]}!"
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def gradient(image)
|
|
54
|
+
if options[:gradient]
|
|
55
|
+
choice = options[:gradient].split(":")
|
|
56
|
+
choice_path = "#{options[:tmp_dir]}/muvy-gradient.png"
|
|
57
|
+
|
|
58
|
+
weights = {
|
|
59
|
+
"heavy" => 1.6,
|
|
60
|
+
"medium" => 0.9,
|
|
61
|
+
"light" => 0.5
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
MiniMagick::Tool::Convert.new do |cmd|
|
|
65
|
+
cmd.size("#{image.width}x#{image.height}")
|
|
66
|
+
cmd << "gradient:"
|
|
67
|
+
cmd << "-function" << "Polynomial" << "-4,4,.1"
|
|
68
|
+
cmd << "-evaluate" << "Pow" << weights[choice[1]]
|
|
69
|
+
cmd.negate unless choice[0] == "white"
|
|
70
|
+
cmd.stack do |stack|
|
|
71
|
+
stack.merge! ["+clone", "-fill", "Black", "-colorize", "100"]
|
|
72
|
+
end
|
|
73
|
+
cmd << "+swap"
|
|
74
|
+
cmd << "-alpha" << "Off"
|
|
75
|
+
cmd.compose("CopyOpacity")
|
|
76
|
+
cmd << "-composite"
|
|
77
|
+
cmd.negate unless choice[0] == "black"
|
|
78
|
+
cmd << choice_path
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
gradient_image = MiniMagick::Image.new(choice_path)
|
|
82
|
+
apply_gradient = image.composite(gradient_image) do |composite|
|
|
83
|
+
composite.compose "Over"
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
apply_gradient.write(options[:img])
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def rotate(image)
|
|
91
|
+
image.rotate(90) if options[:rotate]
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def arc
|
|
95
|
+
if options[:arc]
|
|
96
|
+
MiniMagick::Tool::Convert.new do |cmd|
|
|
97
|
+
cmd << options[:img]
|
|
98
|
+
cmd << "-gravity" << "center"
|
|
99
|
+
cmd << "+repage"
|
|
100
|
+
cmd << "-virtual-pixel" << "Transparent"
|
|
101
|
+
cmd << "-distort" << "Arc" << "366"
|
|
102
|
+
cmd << options[:img]
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def printout
|
|
108
|
+
image = MiniMagick::Image.open(options[:img])
|
|
109
|
+
puts <<~PRINTOUT_IMG
|
|
110
|
+
Saved to #{options[:img]}.
|
|
111
|
+
Width: #{image.dimensions[0]}, Height: #{image.dimensions[1]}
|
|
112
|
+
Type: #{image.type}
|
|
113
|
+
Colorspace: #{image.colorspace}
|
|
114
|
+
PRINTOUT_IMG
|
|
115
|
+
|
|
116
|
+
puts <<~PRINTOUT_VIDEO if options[:fps]
|
|
117
|
+
|
|
118
|
+
Thumbnails made at #{options[:frame_rate] ? options[:frame_rate] : (options[:fps] / (options[:media_length]**(1 / 1.99))).round(4) } frames per second.
|
|
119
|
+
Original video duration was #{options[:media_length]}.
|
|
120
|
+
#{'Start time: ' + options[:start].to_s if options[:start]}
|
|
121
|
+
#{'End time: ' + options[:end].to_s if options[:end]}
|
|
122
|
+
PRINTOUT_VIDEO
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
require "mini_magick"
|
|
2
|
+
|
|
3
|
+
module Muvy
|
|
4
|
+
class ImageFolder
|
|
5
|
+
attr_reader :media, :options, :photos
|
|
6
|
+
|
|
7
|
+
def initialize(media, options)
|
|
8
|
+
@media = media
|
|
9
|
+
@options = options
|
|
10
|
+
@photos = add_photos
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def run
|
|
14
|
+
average
|
|
15
|
+
send_thumbs
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def add_photos
|
|
21
|
+
Dir.glob("#{media}/*")
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def average
|
|
25
|
+
# Store the average photos here
|
|
26
|
+
Dir.mkdir("#{options[:tmp_dir]}/muvy-img-folder/")
|
|
27
|
+
|
|
28
|
+
photos.each_with_index do |photo, i|
|
|
29
|
+
MiniMagick::Tool::Convert.new do |convert|
|
|
30
|
+
convert << photo
|
|
31
|
+
convert.resize("1x#{height}!")
|
|
32
|
+
convert << "#{options[:tmp_dir]}/muvy-img-folder/thumb#{i.to_s.rjust(6, '0')}.png"
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def height
|
|
38
|
+
if options[:style] == "stretch"
|
|
39
|
+
options[:height] ? options[:height] : (abort <<~NO_HEIGHT)
|
|
40
|
+
You specified an image folder and 'stretch' with the --style flag.
|
|
41
|
+
You should also specify a uniform height with the --height option.
|
|
42
|
+
NO_HEIGHT
|
|
43
|
+
else
|
|
44
|
+
# Arbitrary default height 720
|
|
45
|
+
options[:height] ||= 720
|
|
46
|
+
|
|
47
|
+
# 1x1 to get average colors ('solid' style)
|
|
48
|
+
1
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def send_thumbs
|
|
53
|
+
Image.new("#{options[:tmp_dir]}/muvy-img-folder", options).run
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
data/lib/muvy/media.rb
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
require 'muvy/download'
|
|
2
|
+
require 'muvy/video'
|
|
3
|
+
require 'muvy/imagefolder'
|
|
4
|
+
require 'muvy/errors'
|
|
5
|
+
require 'uri'
|
|
6
|
+
|
|
7
|
+
module Muvy
|
|
8
|
+
class Media
|
|
9
|
+
attr_reader :media, :options, :type
|
|
10
|
+
|
|
11
|
+
def initialize(media, options)
|
|
12
|
+
@media = media
|
|
13
|
+
@options = options
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def run
|
|
17
|
+
get_type
|
|
18
|
+
send_type
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def send_type
|
|
24
|
+
Muvy.const_get(type.to_s).new(media, options).run
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Checks the first argument (store in :media, access via getter).
|
|
28
|
+
# Determines if it should be read by Download (type - online URL),
|
|
29
|
+
# by Video (type - local media), or by Image (type - local image files).
|
|
30
|
+
# Unrecognized inputs invoke the usage heredocs and banners at `CLI`
|
|
31
|
+
def get_type
|
|
32
|
+
if valid_url?(media)
|
|
33
|
+
@type = :Download
|
|
34
|
+
elsif file_exists?(media)
|
|
35
|
+
@type = :Video
|
|
36
|
+
elsif path_exists?(media)
|
|
37
|
+
@type = :ImageFolder
|
|
38
|
+
else
|
|
39
|
+
raise Muvy::Errors::InvalidMediaInput
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Accepts a string that behaves like a URL.
|
|
44
|
+
# The URL must have a valid URI scheme (e.g. http) to differentiate
|
|
45
|
+
# it from file paths. URI module doesn't recognize #host without it.
|
|
46
|
+
def valid_url?(url)
|
|
47
|
+
encoded_url = URI.escape(url)
|
|
48
|
+
parsed_url = URI.parse(encoded_url)
|
|
49
|
+
!parsed_url.host.nil?
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def file_exists?(file)
|
|
53
|
+
file_path = File.absolute_path(file)
|
|
54
|
+
File.file?(file_path)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def path_exists?(path)
|
|
58
|
+
full_path = File.absolute_path(path)
|
|
59
|
+
File.directory?(full_path)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
data/lib/muvy/version.rb
ADDED
data/lib/muvy/video.rb
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
require 'streamio-ffmpeg'
|
|
2
|
+
require 'muvy/image'
|
|
3
|
+
|
|
4
|
+
module Muvy
|
|
5
|
+
class Video
|
|
6
|
+
attr_reader :media, :options, :settings, :vid
|
|
7
|
+
|
|
8
|
+
def initialize(media, options = {})
|
|
9
|
+
@media = media
|
|
10
|
+
@options = options
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def run
|
|
14
|
+
@vid = FFMPEG::Movie.new(media)
|
|
15
|
+
@settings = merge_settings
|
|
16
|
+
|
|
17
|
+
thumbs
|
|
18
|
+
send_thumbs
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
# Add important settings to @options hash for use by FFmpeg
|
|
24
|
+
def add_options
|
|
25
|
+
options[:fps] = vid.frame_rate
|
|
26
|
+
options[:media_length] = vid.duration
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# defaults holds default values
|
|
30
|
+
# options holds command-line arguments
|
|
31
|
+
# settings merges defaults with options where appropriate
|
|
32
|
+
def merge_settings
|
|
33
|
+
add_options
|
|
34
|
+
|
|
35
|
+
defaults = {
|
|
36
|
+
vframes: (options[:fps] * options[:media_length]).floor,
|
|
37
|
+
frame_rate: options[:fps] / (options[:media_length]**(1 / 1.99)),
|
|
38
|
+
custom: %W{
|
|
39
|
+
-vf scale=1:#{options[:style] == 'stretch' ? vid.height : 1}
|
|
40
|
+
-ss #{options[:start] ? options[:start] : 0}
|
|
41
|
+
-to #{options[:end] ? options[:end] : options[:media_length]}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
@settings = defaults.merge!(options.select { |k, v| defaults.key?(k) && v })
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def thumbs
|
|
49
|
+
vid.screenshot(
|
|
50
|
+
"#{options[:tmp_dir]}/thumb%06d.png",
|
|
51
|
+
settings,
|
|
52
|
+
validate: false
|
|
53
|
+
)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def send_thumbs
|
|
57
|
+
Image.new(options[:tmp_dir], options).run
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
data/muvy.gemspec
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
require "muvy/version"
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |spec|
|
|
7
|
+
spec.name = "muvy"
|
|
8
|
+
spec.version = Muvy::VERSION
|
|
9
|
+
spec.authors = ["agarun"]
|
|
10
|
+
spec.email = ["19801205+agarun@users.noreply.github.com"]
|
|
11
|
+
|
|
12
|
+
spec.summary = "Ruby movie barcode generator."
|
|
13
|
+
spec.homepage = "https://github.com/agarun/ruby-muvy"
|
|
14
|
+
spec.license = "MIT"
|
|
15
|
+
|
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
|
17
|
+
f.match(%r{^(test|spec|features)/})
|
|
18
|
+
end
|
|
19
|
+
spec.bindir = "exe"
|
|
20
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
21
|
+
spec.require_paths = ["lib"]
|
|
22
|
+
|
|
23
|
+
spec.add_runtime_dependency "youtube-dl.rb", "~> 0"
|
|
24
|
+
spec.add_runtime_dependency "streamio-ffmpeg", "~> 3.0"
|
|
25
|
+
spec.add_runtime_dependency "mini_magick", "~> 4.8"
|
|
26
|
+
spec.add_runtime_dependency "slop", "~> 4.6"
|
|
27
|
+
|
|
28
|
+
spec.add_development_dependency "bundler", "~> 1.15"
|
|
29
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
|
30
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
|
31
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: muvy
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- agarun
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: exe
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2017-10-11 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: youtube-dl.rb
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '0'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '0'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: streamio-ffmpeg
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '3.0'
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '3.0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: mini_magick
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '4.8'
|
|
48
|
+
type: :runtime
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '4.8'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: slop
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - "~>"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '4.6'
|
|
62
|
+
type: :runtime
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - "~>"
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '4.6'
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: bundler
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - "~>"
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '1.15'
|
|
76
|
+
type: :development
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - "~>"
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '1.15'
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: rake
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - "~>"
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '10.0'
|
|
90
|
+
type: :development
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - "~>"
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: '10.0'
|
|
97
|
+
- !ruby/object:Gem::Dependency
|
|
98
|
+
name: rspec
|
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
|
100
|
+
requirements:
|
|
101
|
+
- - "~>"
|
|
102
|
+
- !ruby/object:Gem::Version
|
|
103
|
+
version: '3.0'
|
|
104
|
+
type: :development
|
|
105
|
+
prerelease: false
|
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
107
|
+
requirements:
|
|
108
|
+
- - "~>"
|
|
109
|
+
- !ruby/object:Gem::Version
|
|
110
|
+
version: '3.0'
|
|
111
|
+
description:
|
|
112
|
+
email:
|
|
113
|
+
- 19801205+agarun@users.noreply.github.com
|
|
114
|
+
executables:
|
|
115
|
+
- muvy
|
|
116
|
+
extensions: []
|
|
117
|
+
extra_rdoc_files: []
|
|
118
|
+
files:
|
|
119
|
+
- ".gitignore"
|
|
120
|
+
- ".rspec"
|
|
121
|
+
- ".travis.yml"
|
|
122
|
+
- Gemfile
|
|
123
|
+
- LICENSE
|
|
124
|
+
- README.md
|
|
125
|
+
- Rakefile
|
|
126
|
+
- bin/console
|
|
127
|
+
- bin/setup
|
|
128
|
+
- exe/muvy
|
|
129
|
+
- lib/muvy.rb
|
|
130
|
+
- lib/muvy/cli.rb
|
|
131
|
+
- lib/muvy/download.rb
|
|
132
|
+
- lib/muvy/errors.rb
|
|
133
|
+
- lib/muvy/image.rb
|
|
134
|
+
- lib/muvy/imagefolder.rb
|
|
135
|
+
- lib/muvy/media.rb
|
|
136
|
+
- lib/muvy/version.rb
|
|
137
|
+
- lib/muvy/video.rb
|
|
138
|
+
- muvy.gemspec
|
|
139
|
+
homepage: https://github.com/agarun/ruby-muvy
|
|
140
|
+
licenses:
|
|
141
|
+
- MIT
|
|
142
|
+
metadata: {}
|
|
143
|
+
post_install_message:
|
|
144
|
+
rdoc_options: []
|
|
145
|
+
require_paths:
|
|
146
|
+
- lib
|
|
147
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
148
|
+
requirements:
|
|
149
|
+
- - ">="
|
|
150
|
+
- !ruby/object:Gem::Version
|
|
151
|
+
version: '0'
|
|
152
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
153
|
+
requirements:
|
|
154
|
+
- - ">="
|
|
155
|
+
- !ruby/object:Gem::Version
|
|
156
|
+
version: '0'
|
|
157
|
+
requirements: []
|
|
158
|
+
rubyforge_project:
|
|
159
|
+
rubygems_version: 2.5.1
|
|
160
|
+
signing_key:
|
|
161
|
+
specification_version: 4
|
|
162
|
+
summary: Ruby movie barcode generator.
|
|
163
|
+
test_files: []
|