-
Notifications
You must be signed in to change notification settings - Fork 0
/
extract_audio.sf
111 lines (82 loc) · 2.42 KB
/
extract_audio.sf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#!/usr/bin/ruby
# Daniel "Trizen" Șuteu
# Date: 21 March 2020
# Edit: 24 October 2023
# https://github.com/trizen
# Extract audio from video files with ffmpeg, using `n` parallel processes.
func ffmpeg_convert(input, output) {
Sys.run("ffmpeg", "-loglevel", "warning", "-i", input, "-vn", "-sn", "-dn", "-c:a", "copy", output)
}
func prepare_file(file, outdir, ext) {
var out = ""
if (file =~ /^(.*)\.\w+\z/s) {|m|
out = (m[0] + "." + ext)
}
else {
out = (file + "." + ext)
}
out = File(outdir, File(out).basename)
if (File(out).rel2abs == File(file).rel2abs) {
return nil
}
return out
}
var threads = 2
var format = 'opus'
var outdir = Dir.cwd
var delete_original = false
func print_help(exit_code=0) {
var name = File(__FILE__).basename
print <<"EOT"
usage: #{name} [options] [files]
options:
-f --format=s : output format (default: #{format})
-d --delete! : delete the original files (default: #{delete_original})
-o --outdir=s : output directory (default: .)
-t --threads=i : number of threads to use (default: #{threads})
example:
#{name} -f opus -t 4 *.webm # extract OPUS audio from WEBM videos
EOT
Sys.exit(exit_code)
}
ARGV.getopt!(
'f|format=s' => \format,
't|threads=i' => \threads,
'o|outdir=s' => \outdir,
'd|delete!' => \delete_original,
'h|help' => print_help,
)
outdir.exists || outdir.make_path || die "Can't create directory <<#{outdir}>>: #{$!}"
ARGV || print_help(1)
ARGV.each_slice(threads, {|*slice|
var files = slice.grep { File(_).exists }
var conversions = files.map {|file|
[File(file), prepare_file(file, outdir, format)]
}.grep {
defined(.tail)
}.grep {
!.tail.exists
}
conversions || next
conversions.each_2d {|from,to|
say ":: Converting: '#{from}' -> '#{to}'"
}
var forks = conversions.map_2d {|input, output|
ffmpeg_convert.fork(input, output)
}
forks.each {|t|
say ":: Waiting..."
t.wait
}
conversions.each_2d {|input, output|
output.is_file || next
var output_size = output.size
if (delete_original && (output_size > 0)) {
say "Removing: #{input}"
input.delete || warn "failed to remove: #{$!}"
}
elsif (output_size == 0) { # ffmpeg failed
output.delete # remove empty file
}
}
})