cue_breaker 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: bd9d8859514a4edf0131c5f6e9c01939df0ee6cfe0389ff909e77c7a3e0828a6
4
+ data.tar.gz: 18c39dd44c5e26ced3b3a232ed521a499453a4ded92d1fb92cdd6b6d303d2875
5
+ SHA512:
6
+ metadata.gz: b7e39bcf1aa41da85fb871a4e4f9975a9bdc9fd45f68c4fc0b5ea221b1fcc7211befb2be4bfcac66ef997c1123e0052bbe9a3f726a557b1708d69c81d1dfa2cf
7
+ data.tar.gz: ba7b880ae0588c66c32f445c82959e0b07741f22f300150f77e262f1495d56c050cf6872909a1d40a9043481c48d30a1474f0361afc4f8bda71bb71ac128846d
data/README.md ADDED
@@ -0,0 +1,43 @@
1
+ # CueBreaker
2
+
3
+ CueBreaker is a Ruby script that parses CUE files and converts
4
+ associated WAV files into respective MP3 track files. It uses the
5
+ `rubycue` gem for parsing and FFmpeg for audio conversion and
6
+ metadata handling.
7
+
8
+ ## Features
9
+
10
+ - Parses CUE files to extract track information.
11
+ - Converts WAV segments to MP3 files.
12
+ - Adds metadata to the MP3 files (e.g. title, artist).
13
+
14
+ ## Requirements
15
+
16
+ - Ruby
17
+ - FFmpeg
18
+
19
+ ## Installation
20
+
21
+ 1. **Install Ruby:** Download and install Ruby from [ruby-lang.org](https://www.ruby-lang.org/).
22
+ 2. **Install FFmpeg:** Download and install FFmpeg from [ffmpeg.org](https://ffmpeg.org/download.html) and ensure it is added to your system's PATH.
23
+
24
+ ```sh
25
+ $ gem install cue_breaker
26
+ ```
27
+
28
+ ## Usage
29
+
30
+ Here's an example of how to use CueBreaker:
31
+
32
+ ```sh
33
+ $ cue_break --cue rockband.cue --wav rockband.wav --output $HOME/music/rockband
34
+ ```
35
+
36
+ ## License
37
+
38
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
39
+
40
+ ## Acknowledgments
41
+
42
+ - [rubycue](https://github.com/blakesmith/rubycue) for CUE file parsing.
43
+ - [FFmpeg](https://ffmpeg.org/) for audio processing.
data/bin/cue_break ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/local/bin/ruby
2
+
3
+ require 'bundler/setup'
4
+
5
+ require 'cue_breaker'
6
+
7
+ CueBreaker::CLI.start
@@ -0,0 +1,25 @@
1
+ require 'delegate'
2
+
3
+ module CueBreaker
4
+ class Album
5
+ attr_reader :title, :performer, :genre, :total_tracks, :date
6
+
7
+ def initialize(title:, performer:, genre:, total_tracks:, date:)
8
+ @title, @performer, @genre, @total_tracks, @date = title, performer, genre, total_tracks, date
9
+ end
10
+
11
+ def present
12
+ @_present ||= Presenter.new(self)
13
+ end
14
+
15
+ class Presenter < SimpleDelegator
16
+ def track_number(track)
17
+ "#{track.number}/#{total_tracks}"
18
+ end
19
+
20
+ def genre
21
+ super&.gsub(/[<>:"\/\\|?*]/, '').to_s
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,47 @@
1
+ require 'optparse'
2
+ require 'delegate'
3
+
4
+ require 'cue_breaker/version'
5
+ require 'cue_breaker/core'
6
+ require 'cue_breaker/dependencies'
7
+
8
+ module CueBreaker
9
+ module CLI
10
+ extend self
11
+
12
+ def start
13
+ Dependencies.check!
14
+
15
+ duration = Core.get_audio_duration(options.wav)
16
+
17
+ Core.parse_cue(options.cue, duration: duration) do |album, song|
18
+ Core.convert_to_mp3(options.wav, album.present, song.present, options.output)
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def options
25
+ @_options ||= Options.new
26
+ end
27
+
28
+ class Options < SimpleDelegator
29
+ def initialize
30
+ options = {}
31
+
32
+ OptionParser.new do |parser|
33
+ parser.banner = <<~BANNER
34
+ cue_break version #{VERSION}
35
+ Usage: cue_break [options]
36
+ BANNER
37
+
38
+ parser.on('-c', '--cue CUEFILE') { |o| options[:cue] = o }
39
+ parser.on('-w', '--wav WAVFILE') { |o| options[:wav] = o }
40
+ parser.on('-o', '--output OUTPUT') { |o| options[:output] = o }
41
+ end.parse!
42
+
43
+ super Struct.new(*options.keys).new(*options.values)
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,68 @@
1
+ require 'rubycue'
2
+ require 'fileutils'
3
+ require 'open3'
4
+
5
+ require 'cue_breaker/album'
6
+ require 'cue_breaker/track'
7
+ require 'cue_breaker/ffmpeg_args'
8
+
9
+ module CueBreaker
10
+ module Core
11
+ extend self
12
+
13
+ def parse_cue(cue_file, duration:, &block)
14
+ cue_sheet = RubyCue::Cuesheet.new(File.read(cue_file), duration.to_i)
15
+ cue_sheet.parse!
16
+
17
+ album = as_album(cue_sheet)
18
+
19
+ cue_sheet.songs.each do |song|
20
+ block.call(album, as_track(song))
21
+ end
22
+ end
23
+
24
+ def convert_to_mp3(wav_file, album, track, output_dir)
25
+ output_path = File.join(output_dir, sanitize_file_name(album.title))
26
+ FileUtils.mkdir_p(output_path) unless Dir.exist?(output_path)
27
+
28
+ ffmpeger = FFmpegArgs.new(wav_file, album, track)
29
+ system('ffmpeg', *ffmpeger.options(output_path))
30
+ puts "Exported: #{ffmpeger.output_file_path(output_path)}"
31
+ end
32
+
33
+ def get_audio_duration(file_path)
34
+ stdout, stderr, status = Open3.capture3(<<~CMD)
35
+ ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 \"#{file_path}\"
36
+ CMD
37
+
38
+ raise "Error getting duration: #{stderr}" unless status.success?
39
+
40
+ stdout.strip.to_f
41
+ end
42
+
43
+ private
44
+
45
+ def as_album(cue_sheet)
46
+ Album.new(
47
+ title: cue_sheet.title,
48
+ performer: cue_sheet.songs.first.fetch(:performer),
49
+ genre: cue_sheet.genre,
50
+ total_tracks: cue_sheet.songs.count,
51
+ date: cue_sheet.date
52
+ )
53
+ end
54
+
55
+ def as_track(song)
56
+ Track.new(
57
+ title: song.fetch(:title),
58
+ number: song.fetch(:track),
59
+ start: song.fetch(:index).to_s,
60
+ finish: (song.fetch(:index) + song.fetch(:duration)).to_s
61
+ )
62
+ end
63
+
64
+ def sanitize_file_name(name)
65
+ name.gsub(%r{[<>:"/\\|?*]}, '')
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,17 @@
1
+ module CueBreaker
2
+ module Dependencies
3
+ extend self
4
+
5
+ def check!
6
+ check_ffmpeg_installed!
7
+ end
8
+
9
+ private
10
+
11
+ def check_ffmpeg_installed!
12
+ unless system('which ffmpeg > /dev/null 2>&1')
13
+ raise 'ffmpeg is not installed. Please install it to use this gem.'
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,50 @@
1
+ module CueBreaker
2
+ class FFmpegArgs
3
+ def initialize(file, album, track)
4
+ @file, @album, @track = file, album, track
5
+ end
6
+
7
+ def options(output_path)
8
+ [
9
+ file,
10
+ start,
11
+ finish,
12
+ metadata,
13
+ ["-q:a", "0"],
14
+ output_file_path(output_path)
15
+ ].reject(&:empty?).flatten
16
+ end
17
+
18
+ def file
19
+ ["-i", @file]
20
+ end
21
+
22
+ def start
23
+ ["-ss", @track.start.to_s]
24
+ end
25
+
26
+ def finish
27
+ return [] unless @track.finish
28
+
29
+ ["-to", @track.finish.to_s]
30
+ end
31
+
32
+ def metadata
33
+ [
34
+ "-metadata", "title=#{@track.title}",
35
+ "-metadata", "artist=#{@album.performer}",
36
+ "-metadata", "genre=#{@album.genre}",
37
+ "-metadata", "album=#{@album.title}",
38
+ "-metadata", "date=#{@album.date}",
39
+ "-metadata", "track=#{@album.track_number(@track)}",
40
+ ]
41
+ end
42
+
43
+ def output_file_path(output_path)
44
+ File.join(
45
+ output_path,
46
+ "#{format('%02d', @track.number)} - #{@track.title}.mp3"
47
+ )
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,32 @@
1
+ require 'delegate'
2
+
3
+ module CueBreaker
4
+ class Track
5
+ attr_reader :title, :number, :start, :finish
6
+
7
+ def initialize(title:, number:, start:, finish:)
8
+ @title, @number, @start, @finish = title, number, start, finish
9
+ end
10
+
11
+ def present
12
+ @_present ||= Presenter.new(self)
13
+ end
14
+
15
+ class Presenter < SimpleDelegator
16
+ def start
17
+ parse_time(super)
18
+ end
19
+
20
+ def finish
21
+ super ? parse_time(super) : nil
22
+ end
23
+
24
+ private
25
+
26
+ def parse_time(time_str)
27
+ parts = time_str.split(':').map(&:to_f)
28
+ (parts[0] * 60) + parts[1] + (parts[2] / 75.0)
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,3 @@
1
+ module CueBreaker
2
+ VERSION = '0.1.0'
3
+ end
@@ -0,0 +1,6 @@
1
+ require 'rubycue'
2
+ require 'fileutils'
3
+ require 'open3'
4
+
5
+ require 'cue_breaker/cli'
6
+ require 'cue_breaker/core'
metadata ADDED
@@ -0,0 +1,81 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cue_breaker
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Lukas Alexander
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-05-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: pry-nav
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: A simple hello world gem
42
+ email: the.lukelex@gmail.com
43
+ executables:
44
+ - cue_break
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - README.md
49
+ - bin/cue_break
50
+ - lib/cue_breaker.rb
51
+ - lib/cue_breaker/album.rb
52
+ - lib/cue_breaker/cli.rb
53
+ - lib/cue_breaker/core.rb
54
+ - lib/cue_breaker/dependencies.rb
55
+ - lib/cue_breaker/ffmpeg_args.rb
56
+ - lib/cue_breaker/track.rb
57
+ - lib/cue_breaker/version.rb
58
+ homepage: https://rubygems.org/gems/cue_breaker
59
+ licenses:
60
+ - MIT
61
+ metadata: {}
62
+ post_install_message:
63
+ rdoc_options: []
64
+ require_paths:
65
+ - lib
66
+ required_ruby_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ required_rubygems_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ requirements: []
77
+ rubygems_version: 3.5.9
78
+ signing_key:
79
+ specification_version: 4
80
+ summary: Breaks CUE files into mp3s
81
+ test_files: []