duo_splitter 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.ja.md +128 -0
- data/README.md +13 -11
- data/exe/duo_splitter +9 -3
- data/lib/duo_splitter.rb +39 -10
- data/lib/duo_splitter/batch_processor.rb +36 -0
- data/lib/duo_splitter/commands/base_command.rb +121 -0
- data/lib/duo_splitter/commands/overlapping_command.rb +37 -0
- data/lib/duo_splitter/commands/repeating_command.rb +38 -0
- data/lib/duo_splitter/commands/split_command.rb +31 -0
- data/lib/duo_splitter/context.rb +34 -0
- data/lib/duo_splitter/encoders/aac_encoder.rb +17 -0
- data/lib/duo_splitter/encoders/base_encoder.rb +57 -0
- data/lib/duo_splitter/encoders/mp3_encoder.rb +17 -0
- data/lib/duo_splitter/encoders/wav_encoder.rb +17 -0
- data/lib/duo_splitter/models/album.rb +23 -0
- data/lib/duo_splitter/models/section.rb +38 -0
- data/lib/duo_splitter/models/sentence.rb +35 -0
- data/lib/duo_splitter/runner.rb +43 -64
- data/lib/duo_splitter/services/create_overlapping_sentences.rb +19 -0
- data/lib/duo_splitter/services/create_repeating_sentences.rb +20 -0
- data/lib/duo_splitter/services/create_sentences.rb +18 -0
- data/lib/duo_splitter/services/support/base_concatenate.rb +46 -0
- data/lib/duo_splitter/services/support/create_blank_sentences.rb +40 -0
- data/lib/duo_splitter/services/support/encode.rb +23 -0
- data/lib/duo_splitter/services/support/overlapping_concatenate.rb +19 -0
- data/lib/duo_splitter/services/support/repeating_concatenate.rb +22 -0
- data/lib/duo_splitter/services/support/split_tracks.rb +42 -0
- data/lib/duo_splitter/temp_dir_wrapper.rb +20 -0
- data/lib/duo_splitter/version.rb +3 -1
- metadata +34 -15
- data/lib/duo_splitter/aac_encoder.rb +0 -13
- data/lib/duo_splitter/album.rb +0 -21
- data/lib/duo_splitter/encoder.rb +0 -71
- data/lib/duo_splitter/mp3_encoder.rb +0 -13
- data/lib/duo_splitter/section.rb +0 -30
- data/lib/duo_splitter/sentence.rb +0 -22
- data/lib/duo_splitter/wav_encoder.rb +0 -13
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DuoSplitter
|
4
|
+
module Services
|
5
|
+
class CreateOverlappingSentences
|
6
|
+
def initialize(context:)
|
7
|
+
@context = context
|
8
|
+
end
|
9
|
+
|
10
|
+
def run
|
11
|
+
TempDirWrapper.new(context: @context).run do
|
12
|
+
Support::SplitTracks.new(context: @context).run
|
13
|
+
Support::OverlappingConcatenate.new(context: @context).run
|
14
|
+
Support::Encode.new(context: @context).run
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DuoSplitter
|
4
|
+
module Services
|
5
|
+
class CreateRepeatingSentences
|
6
|
+
def initialize(context:)
|
7
|
+
@context = context
|
8
|
+
end
|
9
|
+
|
10
|
+
def run
|
11
|
+
TempDirWrapper.new(context: @context).run do
|
12
|
+
Support::SplitTracks.new(context: @context).run
|
13
|
+
Support::CreateBlankSentences.new(context: @context).run
|
14
|
+
Support::RepeatingConcatenate.new(context: @context).run
|
15
|
+
Support::Encode.new(context: @context).run
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DuoSplitter
|
4
|
+
module Services
|
5
|
+
class CreateSentences
|
6
|
+
def initialize(context:)
|
7
|
+
@context = context
|
8
|
+
end
|
9
|
+
|
10
|
+
def run
|
11
|
+
TempDirWrapper.new(context: @context).run do
|
12
|
+
Support::SplitTracks.new(context: @context).run
|
13
|
+
Support::Encode.new(context: @context).run
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DuoSplitter
|
4
|
+
module Services
|
5
|
+
module Support
|
6
|
+
class BaseConcatenate
|
7
|
+
attr_reader :context, :commands
|
8
|
+
|
9
|
+
def initialize(context:)
|
10
|
+
@context = context
|
11
|
+
@commands = build_commands
|
12
|
+
end
|
13
|
+
|
14
|
+
def run
|
15
|
+
return if @commands.empty?
|
16
|
+
|
17
|
+
BatchProcessor.new(message: 'concatenating...', show_progress: @context.show_progress).run(@commands)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def build_commands
|
23
|
+
sentences.map do |sentence|
|
24
|
+
output_path = @context.temp_dir.join(sentence.output_basename(prefix_section_number: @context.prefix_section_number, concatenated: true, ext: 'wav'))
|
25
|
+
|
26
|
+
sentence.source_audio_path = output_path
|
27
|
+
|
28
|
+
command = [@context.sox_path]
|
29
|
+
command += source_paths(sentence)
|
30
|
+
command += [output_path.to_s]
|
31
|
+
|
32
|
+
command
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def sentences
|
37
|
+
raise Error, '#sentences must be defined in sub classes'
|
38
|
+
end
|
39
|
+
|
40
|
+
def source_paths(_sentence)
|
41
|
+
raise Error, '#source_paths must be defined in sub classes'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DuoSplitter
|
4
|
+
module Services
|
5
|
+
module Support
|
6
|
+
class CreateBlankSentences
|
7
|
+
attr_reader :commands
|
8
|
+
|
9
|
+
def initialize(context:)
|
10
|
+
@context = context
|
11
|
+
@commands = build_commands
|
12
|
+
end
|
13
|
+
|
14
|
+
def run
|
15
|
+
return if @commands.empty?
|
16
|
+
|
17
|
+
BatchProcessor.new(message: 'creating blank sentences...', show_progress: @context.show_progress).run(@commands)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def build_commands
|
23
|
+
sentences = @context.album.sentences(intro: @context.output_intro).select(&:audio_path)
|
24
|
+
|
25
|
+
sentences.map do |sentence|
|
26
|
+
output_path = @context.temp_dir.join(sentence.output_basename(prefix_section_number: @context.prefix_section_number, blank: true, ext: 'wav'))
|
27
|
+
|
28
|
+
sentence.blank_audio_path = output_path
|
29
|
+
|
30
|
+
command = [@context.sox_path]
|
31
|
+
command += %w[-n -c 2 -e signed-integer -r 44100 -b 16]
|
32
|
+
command += [output_path.to_s, 'trim', '0.0', sentence.duration.to_s]
|
33
|
+
|
34
|
+
command
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DuoSplitter
|
4
|
+
module Services
|
5
|
+
module Support
|
6
|
+
class Encode
|
7
|
+
def initialize(context:)
|
8
|
+
@context = context
|
9
|
+
end
|
10
|
+
|
11
|
+
def run
|
12
|
+
output_format = @context.output_format.to_sym
|
13
|
+
|
14
|
+
encoder_class = Encoders::BaseEncoder.known_encoders[output_format]
|
15
|
+
|
16
|
+
raise Error, "unknown output format: #{output_format}" unless encoder_class
|
17
|
+
|
18
|
+
encoder_class.new(context: @context).run
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DuoSplitter
|
4
|
+
module Services
|
5
|
+
module Support
|
6
|
+
class OverlappingConcatenate < BaseConcatenate
|
7
|
+
private
|
8
|
+
|
9
|
+
def sentences
|
10
|
+
context.album.sentences(intro: context.output_intro).select(&:audio_path)
|
11
|
+
end
|
12
|
+
|
13
|
+
def source_paths(sentence)
|
14
|
+
[context.notification_sound_path.to_s, sentence.audio_path.to_s]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DuoSplitter
|
4
|
+
module Services
|
5
|
+
module Support
|
6
|
+
class RepeatingConcatenate < BaseConcatenate
|
7
|
+
private
|
8
|
+
|
9
|
+
def sentences
|
10
|
+
context.album.sentences(intro: context.output_intro).select {|sentence| sentence.audio_path && sentence.blank_audio_path }
|
11
|
+
end
|
12
|
+
|
13
|
+
def source_paths(sentence)
|
14
|
+
paths = [sentence.audio_path.to_s]
|
15
|
+
paths += [context.notification_sound_path.to_s] if context.use_notification_sound
|
16
|
+
paths += [sentence.blank_audio_path.to_s]
|
17
|
+
paths
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DuoSplitter
|
4
|
+
module Services
|
5
|
+
module Support
|
6
|
+
class SplitTracks
|
7
|
+
attr_reader :commands
|
8
|
+
|
9
|
+
def initialize(context:)
|
10
|
+
@context = context
|
11
|
+
@commands = build_commands
|
12
|
+
end
|
13
|
+
|
14
|
+
def run
|
15
|
+
return if @commands.empty?
|
16
|
+
|
17
|
+
BatchProcessor.new(message: 'splitting...', show_progress: @context.show_progress).run(@commands)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def build_commands
|
23
|
+
sentences = @context.album.sentences(intro: @context.output_intro).select {|sentence| sentence.section.audio_path }
|
24
|
+
|
25
|
+
sentences.map do |sentence|
|
26
|
+
output_path = @context.temp_dir.join(sentence.output_basename(prefix_section_number: @context.prefix_section_number, ext: 'wav'))
|
27
|
+
|
28
|
+
sentence.source_audio_path = sentence.audio_path = output_path
|
29
|
+
|
30
|
+
command = [@context.ffmpeg_path, '-y']
|
31
|
+
command += ['-i', sentence.section.audio_path.to_s]
|
32
|
+
command += ['-ss', sentence.start_pos, '-to', sentence.end_pos]
|
33
|
+
command += %w[-codec:a pcm_s16le -ar 44100 -ac 2]
|
34
|
+
command += [output_path.to_s]
|
35
|
+
|
36
|
+
command
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'pathname'
|
4
|
+
require 'tmpdir'
|
5
|
+
|
6
|
+
module DuoSplitter
|
7
|
+
class TempDirWrapper
|
8
|
+
def initialize(context:)
|
9
|
+
@context = context
|
10
|
+
end
|
11
|
+
|
12
|
+
def run
|
13
|
+
Dir.mktmpdir do |dirname|
|
14
|
+
@context.temp_dir = Pathname.new(dirname)
|
15
|
+
|
16
|
+
yield
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/duo_splitter/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: duo_splitter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- healthypackrat
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-04-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '13.0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '13.0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rspec
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -60,6 +60,7 @@ executables:
|
|
60
60
|
extensions: []
|
61
61
|
extra_rdoc_files: []
|
62
62
|
files:
|
63
|
+
- README.ja.md
|
63
64
|
- README.md
|
64
65
|
- data/labels/01.txt
|
65
66
|
- data/labels/02.txt
|
@@ -108,15 +109,31 @@ files:
|
|
108
109
|
- data/labels/45.txt
|
109
110
|
- exe/duo_splitter
|
110
111
|
- lib/duo_splitter.rb
|
111
|
-
- lib/duo_splitter/
|
112
|
-
- lib/duo_splitter/
|
113
|
-
- lib/duo_splitter/
|
114
|
-
- lib/duo_splitter/
|
112
|
+
- lib/duo_splitter/batch_processor.rb
|
113
|
+
- lib/duo_splitter/commands/base_command.rb
|
114
|
+
- lib/duo_splitter/commands/overlapping_command.rb
|
115
|
+
- lib/duo_splitter/commands/repeating_command.rb
|
116
|
+
- lib/duo_splitter/commands/split_command.rb
|
117
|
+
- lib/duo_splitter/context.rb
|
118
|
+
- lib/duo_splitter/encoders/aac_encoder.rb
|
119
|
+
- lib/duo_splitter/encoders/base_encoder.rb
|
120
|
+
- lib/duo_splitter/encoders/mp3_encoder.rb
|
121
|
+
- lib/duo_splitter/encoders/wav_encoder.rb
|
122
|
+
- lib/duo_splitter/models/album.rb
|
123
|
+
- lib/duo_splitter/models/section.rb
|
124
|
+
- lib/duo_splitter/models/sentence.rb
|
115
125
|
- lib/duo_splitter/runner.rb
|
116
|
-
- lib/duo_splitter/
|
117
|
-
- lib/duo_splitter/
|
126
|
+
- lib/duo_splitter/services/create_overlapping_sentences.rb
|
127
|
+
- lib/duo_splitter/services/create_repeating_sentences.rb
|
128
|
+
- lib/duo_splitter/services/create_sentences.rb
|
129
|
+
- lib/duo_splitter/services/support/base_concatenate.rb
|
130
|
+
- lib/duo_splitter/services/support/create_blank_sentences.rb
|
131
|
+
- lib/duo_splitter/services/support/encode.rb
|
132
|
+
- lib/duo_splitter/services/support/overlapping_concatenate.rb
|
133
|
+
- lib/duo_splitter/services/support/repeating_concatenate.rb
|
134
|
+
- lib/duo_splitter/services/support/split_tracks.rb
|
135
|
+
- lib/duo_splitter/temp_dir_wrapper.rb
|
118
136
|
- lib/duo_splitter/version.rb
|
119
|
-
- lib/duo_splitter/wav_encoder.rb
|
120
137
|
homepage: https://github.com/healthypackrat/duo_splitter
|
121
138
|
licenses:
|
122
139
|
- MIT
|
@@ -129,15 +146,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
129
146
|
requirements:
|
130
147
|
- - ">="
|
131
148
|
- !ruby/object:Gem::Version
|
132
|
-
version:
|
149
|
+
version: 2.5.0
|
133
150
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
134
151
|
requirements:
|
135
152
|
- - ">="
|
136
153
|
- !ruby/object:Gem::Version
|
137
154
|
version: '0'
|
138
|
-
requirements:
|
139
|
-
|
155
|
+
requirements:
|
156
|
+
- ffmpeg
|
157
|
+
- sox
|
158
|
+
rubygems_version: 3.1.2
|
140
159
|
signing_key:
|
141
160
|
specification_version: 4
|
142
|
-
summary: Split "DUO 3.0 CD" into separate
|
161
|
+
summary: Split "DUO 3.0 CD" tracks into separate sentences
|
143
162
|
test_files: []
|
data/lib/duo_splitter/album.rb
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
module DuoSplitter
|
2
|
-
class Album
|
3
|
-
attr_reader :sections
|
4
|
-
|
5
|
-
def initialize
|
6
|
-
@sections = load_sections
|
7
|
-
end
|
8
|
-
|
9
|
-
def sentences(intro: true)
|
10
|
-
sections.map(&:sentences).flatten.reject do |sentence|
|
11
|
-
!intro && sentence.intro?
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
private
|
16
|
-
|
17
|
-
def load_sections
|
18
|
-
1.upto(NUMBER_OF_SECTIONS).map {|n| Section.new(number: n) }
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
data/lib/duo_splitter/encoder.rb
DELETED
@@ -1,71 +0,0 @@
|
|
1
|
-
require 'pathname'
|
2
|
-
|
3
|
-
module DuoSplitter
|
4
|
-
class Encoder
|
5
|
-
class << self
|
6
|
-
def known_encoders
|
7
|
-
@known_encoders ||= {}
|
8
|
-
end
|
9
|
-
|
10
|
-
def register(key, encoder)
|
11
|
-
known_encoders[key] = encoder
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
def initialize(album:, output_dir:, output_intro:, add_section_prefix:, ffmpeg_path:)
|
16
|
-
@album = album
|
17
|
-
@output_dir = Pathname.new(output_dir)
|
18
|
-
@output_intro = output_intro
|
19
|
-
@add_section_prefix = add_section_prefix
|
20
|
-
@ffmpeg_path = ffmpeg_path
|
21
|
-
end
|
22
|
-
|
23
|
-
def run
|
24
|
-
commands = to_commands
|
25
|
-
|
26
|
-
return if commands.empty?
|
27
|
-
|
28
|
-
@output_dir.mkpath
|
29
|
-
|
30
|
-
commands.each.with_index(1) do |command, index|
|
31
|
-
$stderr.print "proccessing #{index}/#{commands.size}\r"
|
32
|
-
|
33
|
-
shell_output = IO.popen(command, err: [:child, :out]) {|io| io.read }
|
34
|
-
|
35
|
-
status = $?.exitstatus
|
36
|
-
|
37
|
-
unless status.zero?
|
38
|
-
$stderr.print "\n"
|
39
|
-
$stderr.print "#{shell_output}\n"
|
40
|
-
raise Error, "process exit with #{status}"
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
$stderr.print "\n"
|
45
|
-
$stderr.print "\u{1F37A} done.\n"
|
46
|
-
end
|
47
|
-
|
48
|
-
def to_commands
|
49
|
-
sentences = @album.sentences(intro: @output_intro).select {|sentence| sentence.section.source_path }
|
50
|
-
|
51
|
-
sentences.map do |sentence|
|
52
|
-
output_name = sentence.output_name(add_section_prefix: @add_section_prefix, ext: ext)
|
53
|
-
|
54
|
-
command = [@ffmpeg_path, '-y']
|
55
|
-
command += ['-i', sentence.section.source_path.to_s]
|
56
|
-
command += ['-ss', sentence.start_pos, '-to', sentence.end_pos]
|
57
|
-
command += encoding_options
|
58
|
-
command += [@output_dir.join(output_name).to_s]
|
59
|
-
command
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
def ext
|
64
|
-
raise NotImplementedError, '#ext must be defined in a sub class'
|
65
|
-
end
|
66
|
-
|
67
|
-
def encoding_options
|
68
|
-
raise NotImplementedError, '#encoding_options must be defined in a sub class'
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|