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.
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