audio_to_youtube 1.0.0 → 1.0.1

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.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/README.rdoc +30 -0
  3. metadata +3 -2
  4. data/lib/audio_to_youtube.rb +0 -326
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 222b2488455a1f11c03853d3772db05f473aab73
4
- data.tar.gz: 3d62868b920f7e694913b8cec93eff7b6e8a9b83
3
+ metadata.gz: c0e35ed366d88adb022bc5936ad38c8815b46d71
4
+ data.tar.gz: c81453f21b04751372ffbbd3b79be4527e3cc3ea
5
5
  SHA512:
6
- metadata.gz: 80e4dad589ee2596966310100151262afbe3f486c767159581ebbbcb1032b76ad803851c27ecbab33f8ad7718ba6955c16ff65b602722eb2a273d2a694d3ecc0
7
- data.tar.gz: 96eac8616a78146fb75764e391fb6e8f5045a14d07ca8d156cf16c2d64d37ac07e04e03ac3269f529c41f7b0622cc1d5e2c738e64b23d5fff65ebde65be8db9b
6
+ metadata.gz: 354cdcedabc8cc38e4168c2117cc96b37a438e13b8f2172fcbbb1049cf49018fa5746a30d386d743392a95e75f8c128007fff1bae933171fce17b78ec0cf7500
7
+ data.tar.gz: efde833ca0241f0b6a11415d7e5e3f1313746c608be69b62ac8335823130262c48febe40ea8862cc048c1a8a5fbf9f95ab7092881017dd2cbedd2670c43d36a6
@@ -0,0 +1,30 @@
1
+ = Audio to youtube
2
+ Convert audio with background image to mp4 for uploading to youtube using ffmpeg.
3
+
4
+ Based on a python script: https://github.com/ianharmon/mp3-to-youtube
5
+
6
+ == Install
7
+
8
+ gem install audio_to_youtube
9
+
10
+ == Usage
11
+
12
+ require 'audio_to_youtube'
13
+ AudioToYoutube.generate audio, background, out
14
+
15
+
16
+ == Description
17
+ * *audio*: audio file name with path
18
+
19
+ * *background*: static background for the output video (will use *bg.jpg* if not specified)
20
+
21
+ * *out*: output filename (will use *out.mp4* as default)
22
+
23
+ == License
24
+ Copyright (C) 2015 *Brian Doan*
25
+
26
+ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
27
+
28
+ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
29
+
30
+ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: audio_to_youtube
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Doan
@@ -16,7 +16,7 @@ executables: []
16
16
  extensions: []
17
17
  extra_rdoc_files: []
18
18
  files:
19
- - lib/audio_to_youtube.rb
19
+ - README.rdoc
20
20
  homepage: http://rubygems.org/gems/audio_to_youtube
21
21
  licenses:
22
22
  - MIT
@@ -42,3 +42,4 @@ signing_key:
42
42
  specification_version: 4
43
43
  summary: Convert audio with background image to mp4 for uploading to youtube
44
44
  test_files: []
45
+ has_rdoc:
@@ -1,326 +0,0 @@
1
- class AudioToYoutube
2
- @outputFile = 'out.mp4'
3
- @tempFolder = 'temp'
4
- @tempBg = 'bg.jpg'
5
- @backgroundBase = 'media/bg-720.png'
6
- @ffmpegDir = 'setme'
7
- @imagemagickDir = 'setme'
8
- private
9
- def self.exitWithError(message)
10
- puts ('\nError: ' + message)
11
- end
12
-
13
- ################################################################################
14
- # Generates the background art for the video
15
- def self.generateBackground(audio, backgroundBase, output, blur, text)
16
-
17
- blur ||= false
18
- text ||= ""
19
-
20
- # extract the album art
21
- tempArt = "#{Dir.pwd}/art.png"
22
- cmd = ["ffmpeg"]
23
- cmd += ['-y']
24
- cmd += ["-i #{audio}"]
25
- cmd += ['-acodec none']
26
- cmd += [tempArt]
27
- puts 'Extracting album art...'
28
- begin
29
- unless Dir.exist?(@tempFolder) ||
30
- Dir.mkdir(@tempFolder)
31
- puts p cmd.join(' ')
32
- end
33
- rescue
34
- exitWithError('Couldn\'t find album art in the audio file. ' +
35
- 'Use the -background option to select an image file.')
36
- end
37
-
38
- # now, build the background image
39
- cmd = ["imagick"]
40
- cmd += [backgroundBase]
41
-
42
- # draw the blurred album art background
43
- if blur
44
- cmd += ['-gravity', 'center']
45
- cmd += ['(']
46
- cmd += [tempArt]
47
- cmd += ['-resize', '1500x']
48
- cmd += ['-modulate', '90']
49
- cmd += ['-blur', '0x20']
50
- cmd += [')']
51
- cmd += ['-composite']
52
- end
53
-
54
- # set offsets depending on whether text is drawn
55
- gravity = 'center'
56
- offset = []
57
- shadowOffset = []
58
- unless text.empty?
59
- gravity = 'west'
60
- offset = ['-geometry', '+60+0']
61
- shadowOffset = ['-geometry', '+30+0']
62
- end
63
-
64
- # set some settings used twice
65
- mainArtFront = ['(']
66
- mainArtFront += [tempArt]
67
- mainArtFront += ['-resize', 'x720']
68
-
69
- mainArtBack = [')']
70
- mainArtBack += ['-gravity', gravity]
71
- mainArtBack += ['-composite']
72
-
73
- # draw shadow of the main album art
74
- cmd += mainArtFront
75
- cmd += ['-background', 'black']
76
- cmd += ['-shadow', '50x15+0+0']
77
- cmd += shadowOffset
78
- cmd += mainArtBack
79
-
80
- # draw the main album art
81
- cmd += mainArtFront
82
- cmd += offset
83
- cmd += mainArtBack
84
-
85
- # add in the track metadata text
86
- unless text.empty?
87
- labelText = text[0]
88
- for i in 1..text.length
89
- labelText += '\\n\\n' + text[i]
90
- end
91
-
92
- # set some settings used twice
93
- labelFront = ['(']
94
- labelFront += ['-size', '440x400']
95
- labelFront += ['-background', 'none']
96
- labelFront += ['-gravity', 'center']
97
- labelFront += ['-font', 'Segoe-UI-Semibold']
98
-
99
- labelMid = ['caption:' + labelText]
100
-
101
- labelBack = ['-geometry', '+25+0']
102
- labelBack += [')']
103
- labelBack += ['-gravity', 'east']
104
- labelBack += ['-composite']
105
-
106
- # draw text shadow
107
- cmd += labelFront.join(' ')
108
- cmd += ['-fill', '#00000090']
109
- cmd += labelMid.join(' ')
110
- cmd += ['-blur', '0x6']
111
- cmd += labelBack.join(' ')
112
-
113
- # draw text itself
114
- cmd += labelFront.join(' ')
115
- cmd += ['-fill', 'white']
116
- cmd += labelMid.join(' ')
117
- cmd += labelBack.join(' ')
118
-
119
- end
120
-
121
- # put it all together
122
- cmd += [output]
123
- puts 'Generating video background...'
124
- begin
125
- puts Open3.capture3(cmd.join(' '))
126
- rescue
127
- exitWithError('Something went wrong when generating the background.')
128
- end
129
- end
130
-
131
- ################################################################################
132
- # Splits text over multiple lines
133
- def self.splitText(text, maximumLength)
134
-
135
- maximumLength ||= 20
136
- words = text.split(' ')
137
- output = ''
138
- currentLine = ''
139
- words.each do |word|
140
- if currentLine == ''
141
- currentLine = word
142
- else
143
- temp = currentLine + ' ' + word
144
- # with next word, still under maximum length - add normally
145
- if len(temp) < maximumLength
146
- currentLine = temp
147
- # next word is longer than the maximum length - it gets its own line
148
- elsif len(word) > maximumLength
149
- if output != ''
150
- output += r'\n'
151
- end
152
- output += currentLine
153
- currentLine = ''
154
- if output != ''
155
- output += r'\n'
156
- end
157
- output += word
158
- # we've overrun the maximum length - start a new line with the word
159
- else
160
- if output != ''
161
- output += 'r\n'
162
- end
163
- output += currentLine
164
- currentLine = word
165
- end
166
- end
167
- end
168
- if output != ''
169
- output += r'\n'
170
- end
171
- output += currentLine
172
- #print(output)
173
- return output
174
- end
175
-
176
- ################################################################################
177
- # Retrieves the title and artist from the file
178
- def self.getMetadata(file)
179
- cmd = ["ffprobe"]
180
- cmd += ['-i', file]
181
- print('Extracting metadata...')
182
- lines = ""
183
- begin
184
- output = p cmd.join(' ')
185
- lines = output.split('\n')
186
- rescue
187
- exitWithError('Couldn\'t extract metadata from the file.')
188
- end
189
-
190
- title = ""
191
- artist = ""
192
-
193
- lines.each do |line|
194
- match = line.scan(/^\s*(.*?)\s*: (.*?)\s*@/)
195
- if match.length > 0
196
- pair = match[0]
197
-
198
- if len(pair) == 2
199
- if pair[0] == 'title' and pair[1].length > 0
200
- if title == "" # or len(title) < len(pair[1]):
201
- title = pair[1]
202
- print("Found title: " + title)
203
- end
204
- elsif pair[0] == 'artist' and pair[1].length > 0
205
- if artist == "" # or len(artist) < len(pair[1]):
206
- artist = pair[1]
207
- print("Found artist: " + artist)
208
- end
209
- end
210
- end
211
- end
212
- end
213
- return artist, title
214
- end
215
- ################################################################################
216
- # Creates the final video suitable for uploading
217
- def self.encode(audio, background, output)
218
- cmd = ["ffmpeg"]
219
- cmd += ['-y']
220
- cmd += ['-loop', '1']
221
- cmd += ['-r', '1']
222
- cmd += ['-i', background]
223
- cmd += ['-i', audio]
224
- cmd += ['-c:v', 'libx264']
225
- cmd += ['-preset', 'veryfast']
226
- cmd += ['-tune', 'stillimage']
227
- cmd += ['-crf', '15']
228
- cmd += ['-pix_fmt', 'yuv420p']
229
- cmd += ['-strict', 'experimental']
230
- cmd += ['-c:a', 'aac']
231
- cmd += ['-b:a', '256k']
232
- cmd += ['-shortest']
233
- cmd += ['-threads', '0']
234
- cmd += [output]
235
- print('Encoding video...')
236
- begin
237
- system(cmd.join(' '))
238
- rescue
239
- exitWithError('Something went wrong when encoding the video.')
240
- end
241
- print('\nDone. Saved output as "%s".' % @outputFile)
242
- end
243
-
244
- ################################################################################
245
- # Set library locations
246
- def self.setLibraryLocations()
247
-
248
- # set FFmpeg location
249
- if @ffmpegDir == 'setme' or @ffmpegDir == ''
250
- @ffmpegDir = '/usr/local/bin'
251
- end
252
-
253
- # set ImageMagick location
254
- if @imagemagickDir == 'setme' or @imagemagickDir == ''
255
- @imagemagickDir = '/usr/local/bin'
256
- end
257
-
258
- # set full paths
259
- ffprobe = Dir.pwd + " " + @ffmpegDir + ' ffprobe'
260
- ffmpeg = Dir.pwd + " " + @ffmpegDir + ' ffmpeg'
261
- imagick = Dir.pwd + " " + @imagemagickDir + ' convert'
262
-
263
- # ensure libraries are actually installed
264
- unless (os.path.exists(ffprobe) and os.path.exists(ffmpeg))
265
- exitWithError("FFmpeg couldn\'t be found at \"#{@ffmpegDir}\". " +
266
- 'Please check your configuration.')
267
- end
268
- unless os.path.exists(imagick)
269
- exitWithError("ImageMagick couldn\'t be found at \"#{@imagemagickDir}\". " +
270
- 'Please check your configuration.')
271
- end
272
- end
273
- public
274
- ################################################################################
275
- # Program entrypoint.
276
- def self.generate *args
277
- audio = nil
278
- bg = nil
279
- out = nil
280
- if args.size < 1 || args.size > 3
281
- puts 'This method takes either 1 to 3 arguments'
282
- else
283
- audio = args[0]
284
- if args.size == 2
285
- bg = args[1]
286
- elsif args.size == 3
287
- bg = args[1]
288
- out = args[2]
289
- end
290
- end
291
-
292
- bg ||= @tempBg
293
- out ||= @outputFile
294
- unless File.exist?(audio)
295
- exitWithError("Input file \"#{audio}\" doesn\'t exist or can\'t be read.")
296
- end
297
-
298
- # determine arguments
299
- custom = bg
300
- doBlur = true
301
- doText = false
302
-
303
- background = Dir.pwd + " " + @tempFolder + " " + bg
304
-
305
- # grab metadata if necessary
306
- text = ""
307
- if doText and custom == ""
308
- metadata = getMetadata(audio)
309
- metadata.each do |item|
310
- if item != ""
311
- #split = splitText(item)
312
- text.append(item)
313
- end
314
- end
315
- end
316
-
317
- # generate the background unless a premade one is specified
318
- if custom == ""
319
- generateBackground(audio, backgroundBase, background, blur=doBlur, text=text)
320
- else
321
- background = custom
322
- end
323
- encode(audio, background, out)
324
- end
325
-
326
- end