duo_splitter 0.1.0 → 0.2.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 +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
|