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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/README.ja.md +128 -0
  3. data/README.md +13 -11
  4. data/exe/duo_splitter +9 -3
  5. data/lib/duo_splitter.rb +39 -10
  6. data/lib/duo_splitter/batch_processor.rb +36 -0
  7. data/lib/duo_splitter/commands/base_command.rb +121 -0
  8. data/lib/duo_splitter/commands/overlapping_command.rb +37 -0
  9. data/lib/duo_splitter/commands/repeating_command.rb +38 -0
  10. data/lib/duo_splitter/commands/split_command.rb +31 -0
  11. data/lib/duo_splitter/context.rb +34 -0
  12. data/lib/duo_splitter/encoders/aac_encoder.rb +17 -0
  13. data/lib/duo_splitter/encoders/base_encoder.rb +57 -0
  14. data/lib/duo_splitter/encoders/mp3_encoder.rb +17 -0
  15. data/lib/duo_splitter/encoders/wav_encoder.rb +17 -0
  16. data/lib/duo_splitter/models/album.rb +23 -0
  17. data/lib/duo_splitter/models/section.rb +38 -0
  18. data/lib/duo_splitter/models/sentence.rb +35 -0
  19. data/lib/duo_splitter/runner.rb +43 -64
  20. data/lib/duo_splitter/services/create_overlapping_sentences.rb +19 -0
  21. data/lib/duo_splitter/services/create_repeating_sentences.rb +20 -0
  22. data/lib/duo_splitter/services/create_sentences.rb +18 -0
  23. data/lib/duo_splitter/services/support/base_concatenate.rb +46 -0
  24. data/lib/duo_splitter/services/support/create_blank_sentences.rb +40 -0
  25. data/lib/duo_splitter/services/support/encode.rb +23 -0
  26. data/lib/duo_splitter/services/support/overlapping_concatenate.rb +19 -0
  27. data/lib/duo_splitter/services/support/repeating_concatenate.rb +22 -0
  28. data/lib/duo_splitter/services/support/split_tracks.rb +42 -0
  29. data/lib/duo_splitter/temp_dir_wrapper.rb +20 -0
  30. data/lib/duo_splitter/version.rb +3 -1
  31. metadata +34 -15
  32. data/lib/duo_splitter/aac_encoder.rb +0 -13
  33. data/lib/duo_splitter/album.rb +0 -21
  34. data/lib/duo_splitter/encoder.rb +0 -71
  35. data/lib/duo_splitter/mp3_encoder.rb +0 -13
  36. data/lib/duo_splitter/section.rb +0 -30
  37. data/lib/duo_splitter/sentence.rb +0 -22
  38. 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
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DuoSplitter
2
- VERSION = "0.1.0"
4
+ VERSION = '0.2.0'
3
5
  end
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.1.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: 2019-02-15 00:00:00.000000000 Z
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: '10.0'
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: '10.0'
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/aac_encoder.rb
112
- - lib/duo_splitter/album.rb
113
- - lib/duo_splitter/encoder.rb
114
- - lib/duo_splitter/mp3_encoder.rb
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/section.rb
117
- - lib/duo_splitter/sentence.rb
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: '0'
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
- rubygems_version: 3.0.1
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 tracks
161
+ summary: Split "DUO 3.0 CD" tracks into separate sentences
143
162
  test_files: []
@@ -1,13 +0,0 @@
1
- module DuoSplitter
2
- class AACEncoder < Encoder
3
- attr_reader :ext, :encoding_options
4
-
5
- def initialize(**)
6
- super
7
- @ext = 'm4a'
8
- @encoding_options = ['-codec:a', 'aac', '-b:a', '256k']
9
- end
10
- end
11
-
12
- Encoder.register(:aac, AACEncoder)
13
- end
@@ -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
@@ -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