cue_breaker 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/bin/cue_break +3 -2
- data/lib/cue_breaker/album.rb +9 -3
- data/lib/cue_breaker/cli.rb +18 -14
- data/lib/cue_breaker/core.rb +13 -11
- data/lib/cue_breaker/cue/index.rb +125 -0
- data/lib/cue_breaker/cue/sheet.rb +134 -0
- data/lib/cue_breaker/dependencies.rb +5 -3
- data/lib/cue_breaker/ffmpeg_args.rb +6 -2
- data/lib/cue_breaker/track.rb +8 -3
- data/lib/cue_breaker/version.rb +3 -1
- data/lib/cue_breaker.rb +3 -5
- metadata +11 -36
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0f81daf932fcd49508c2ebd0e7959cba52eae031b6ad2414d62b1665784256c8
|
|
4
|
+
data.tar.gz: eceb7224f2c5cfaa88c1f36b3952c294c4235b51663dad387cd8e8d7f03e32c2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: feaa1224b9f477473f8eb2a5ff6d42ff2af6e3b0b1b95072388342e229fe5faa655a8bfaef60be8add7f2d79892c02c6901dc95fbe36ebff943a7d32a932edbf
|
|
7
|
+
data.tar.gz: 808f0efc30ea766782ea4b8fbe1d506c8f83d202b0eac336a76d309b094b74a77f05ae6bb998a4807e20216de3605f29bd2cfe3c9563247b4d988dd063250e00
|
data/bin/cue_break
CHANGED
data/lib/cue_breaker/album.rb
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "delegate"
|
|
2
4
|
|
|
3
5
|
module CueBreaker
|
|
4
6
|
class Album
|
|
5
7
|
attr_reader :title, :performer, :genre, :total_tracks, :date
|
|
6
8
|
|
|
7
9
|
def initialize(title:, performer:, genre:, total_tracks:, date:)
|
|
8
|
-
@title
|
|
10
|
+
@title = title
|
|
11
|
+
@performer = performer
|
|
12
|
+
@genre = genre
|
|
13
|
+
@total_tracks = total_tracks
|
|
14
|
+
@date = date
|
|
9
15
|
end
|
|
10
16
|
|
|
11
17
|
def present
|
|
@@ -18,7 +24,7 @@ module CueBreaker
|
|
|
18
24
|
end
|
|
19
25
|
|
|
20
26
|
def genre
|
|
21
|
-
super&.gsub(
|
|
27
|
+
super&.gsub(%r{[<>:"/\\|?*]}, "").to_s
|
|
22
28
|
end
|
|
23
29
|
end
|
|
24
30
|
end
|
data/lib/cue_breaker/cli.rb
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
require 'delegate'
|
|
1
|
+
# frozen_string_literal: true
|
|
3
2
|
|
|
4
|
-
require
|
|
5
|
-
require
|
|
6
|
-
|
|
3
|
+
require "optparse"
|
|
4
|
+
require "delegate"
|
|
5
|
+
|
|
6
|
+
require "cue_breaker/version"
|
|
7
|
+
require "cue_breaker/core"
|
|
8
|
+
require "cue_breaker/dependencies"
|
|
7
9
|
|
|
8
10
|
module CueBreaker
|
|
9
11
|
module CLI
|
|
@@ -30,18 +32,20 @@ module CueBreaker
|
|
|
30
32
|
options = {}
|
|
31
33
|
|
|
32
34
|
OptionParser.new do |parser|
|
|
33
|
-
parser.banner =
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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 }
|
|
35
|
+
parser.banner = BANNER
|
|
36
|
+
|
|
37
|
+
parser.on("-c", "--cue CUEFILE") { |o| options[:cue] = o }
|
|
38
|
+
parser.on("-w", "--wav WAVFILE") { |o| options[:wav] = o }
|
|
39
|
+
parser.on("-o", "--output OUTPUT") { |o| options[:output] = o }
|
|
41
40
|
end.parse!
|
|
42
41
|
|
|
43
|
-
super
|
|
42
|
+
super(Struct.new(*options.keys).new(*options.values))
|
|
44
43
|
end
|
|
44
|
+
|
|
45
|
+
BANNER = <<~BANNER.freeze
|
|
46
|
+
cue_break version #{VERSION}
|
|
47
|
+
Usage: cue_break [options]
|
|
48
|
+
BANNER
|
|
45
49
|
end
|
|
46
50
|
end
|
|
47
51
|
end
|
data/lib/cue_breaker/core.rb
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
require 'fileutils'
|
|
3
|
-
require 'open3'
|
|
1
|
+
# frozen_string_literal: true
|
|
4
2
|
|
|
5
|
-
require
|
|
6
|
-
require
|
|
7
|
-
|
|
3
|
+
require "fileutils"
|
|
4
|
+
require "open3"
|
|
5
|
+
|
|
6
|
+
require "cue_breaker/album"
|
|
7
|
+
require "cue_breaker/track"
|
|
8
|
+
require "cue_breaker/ffmpeg_args"
|
|
9
|
+
require "cue_breaker/cue/sheet"
|
|
8
10
|
|
|
9
11
|
module CueBreaker
|
|
10
12
|
module Core
|
|
11
13
|
extend self
|
|
12
14
|
|
|
13
15
|
def parse_cue(cue_file, duration:, &block)
|
|
14
|
-
cue_sheet =
|
|
16
|
+
cue_sheet = Cue::Sheet.new(File.read(cue_file), duration.to_i)
|
|
15
17
|
cue_sheet.parse!
|
|
16
18
|
|
|
17
19
|
album = as_album(cue_sheet)
|
|
@@ -23,16 +25,16 @@ module CueBreaker
|
|
|
23
25
|
|
|
24
26
|
def convert_to_mp3(wav_file, album, track, output_dir)
|
|
25
27
|
output_path = File.join(output_dir, sanitize_file_name(album.title))
|
|
26
|
-
FileUtils.mkdir_p(output_path)
|
|
28
|
+
FileUtils.mkdir_p(output_path)
|
|
27
29
|
|
|
28
30
|
ffmpeger = FFmpegArgs.new(wav_file, album, track)
|
|
29
|
-
system(
|
|
31
|
+
system("ffmpeg", *ffmpeger.options(output_path))
|
|
30
32
|
puts "Exported: #{ffmpeger.output_file_path(output_path)}"
|
|
31
33
|
end
|
|
32
34
|
|
|
33
35
|
def get_audio_duration(file_path)
|
|
34
36
|
stdout, stderr, status = Open3.capture3(<<~CMD)
|
|
35
|
-
ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1
|
|
37
|
+
ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "#{file_path}"
|
|
36
38
|
CMD
|
|
37
39
|
|
|
38
40
|
raise "Error getting duration: #{stderr}" unless status.success?
|
|
@@ -62,7 +64,7 @@ module CueBreaker
|
|
|
62
64
|
end
|
|
63
65
|
|
|
64
66
|
def sanitize_file_name(name)
|
|
65
|
-
name.gsub(%r{[<>:"/\\|?*]},
|
|
67
|
+
name.gsub(%r{[<>:"/\\|?*]}, "")
|
|
66
68
|
end
|
|
67
69
|
end
|
|
68
70
|
end
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module CueBreaker
|
|
4
|
+
module Cue
|
|
5
|
+
class Index
|
|
6
|
+
include Enumerable
|
|
7
|
+
|
|
8
|
+
SECONDS_PER_MINUTE = 60
|
|
9
|
+
FRAMES_PER_SECOND = 75
|
|
10
|
+
FRAMES_PER_MINUTE = FRAMES_PER_SECOND * 60
|
|
11
|
+
|
|
12
|
+
attr_reader :minutes, :seconds, :frames
|
|
13
|
+
|
|
14
|
+
class << self
|
|
15
|
+
def parse_from(value)
|
|
16
|
+
case value
|
|
17
|
+
when Array
|
|
18
|
+
from_list(value)
|
|
19
|
+
when Integer
|
|
20
|
+
from_integer(value)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def from_list(array)
|
|
27
|
+
if array.size != 3 || array.any? { |element| !element.is_a?(Integer) }
|
|
28
|
+
raise ArgumentError,
|
|
29
|
+
"Must be initialized with an array in the format of [minutes, seconds,frames], all integers"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
array
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def from_integer(seconds)
|
|
36
|
+
minutes = 0
|
|
37
|
+
frames = 0
|
|
38
|
+
|
|
39
|
+
while seconds >= SECONDS_PER_MINUTE
|
|
40
|
+
minutes += 1
|
|
41
|
+
seconds -= SECONDS_PER_MINUTE
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
[minutes, seconds, frames]
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def initialize(value = nil)
|
|
49
|
+
@minutes, @seconds, @frames = *self.class.parse_from(value)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def to_f
|
|
53
|
+
((@minutes * SECONDS_PER_MINUTE) + @seconds + (@frames.to_f / FRAMES_PER_SECOND)).to_f
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def to_i
|
|
57
|
+
to_f.floor
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def to_a
|
|
61
|
+
[@minutes, @seconds, @frames]
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def to_s
|
|
65
|
+
"#{format('%02d', @minutes)}:#{format('%02d', @seconds)}:#{format('%02d', @frames)}"
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def +(other)
|
|
69
|
+
self.class.new(carrying_addition(other))
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def -(other)
|
|
73
|
+
self.class.new(carrying_subtraction(other))
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def >(other)
|
|
77
|
+
to_f > other.to_f
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def <(other)
|
|
81
|
+
to_f < other.to_f
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def ==(other)
|
|
85
|
+
to_a == other.to_a
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def each(&block)
|
|
89
|
+
to_a.each(&block)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
private
|
|
93
|
+
|
|
94
|
+
def carrying_addition(other)
|
|
95
|
+
minutes = @minutes + other.minutes
|
|
96
|
+
seconds = @seconds + other.seconds
|
|
97
|
+
frames = @frames + other.frames
|
|
98
|
+
|
|
99
|
+
seconds, frames = *convert_with_rate(frames, seconds, FRAMES_PER_SECOND)
|
|
100
|
+
minutes, seconds = *convert_with_rate(seconds, minutes, SECONDS_PER_MINUTE)
|
|
101
|
+
[minutes, seconds, frames]
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def carrying_subtraction(other)
|
|
105
|
+
seconds = minutes = 0
|
|
106
|
+
|
|
107
|
+
my_frames = @frames + (@seconds * FRAMES_PER_SECOND) + (@minutes * FRAMES_PER_MINUTE)
|
|
108
|
+
other_frames = other.frames + (other.seconds * FRAMES_PER_SECOND) + (other.minutes * FRAMES_PER_MINUTE)
|
|
109
|
+
frames = my_frames - other_frames
|
|
110
|
+
|
|
111
|
+
seconds, frames = *convert_with_rate(frames, seconds, FRAMES_PER_SECOND)
|
|
112
|
+
minutes, seconds = *convert_with_rate(seconds, minutes, SECONDS_PER_MINUTE)
|
|
113
|
+
[minutes, seconds, frames]
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def convert_with_rate(from, to, rate, step = 1)
|
|
117
|
+
while from >= rate
|
|
118
|
+
to += step
|
|
119
|
+
from -= rate
|
|
120
|
+
end
|
|
121
|
+
[to, from]
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "cue_breaker/cue/index"
|
|
4
|
+
|
|
5
|
+
module CueBreaker
|
|
6
|
+
module Cue
|
|
7
|
+
class Sheet
|
|
8
|
+
attr_reader :cuesheet, :songs, :track_duration, :performer, :title, :file, :genre, :date
|
|
9
|
+
|
|
10
|
+
class MalformedError < ::RuntimeError; end
|
|
11
|
+
|
|
12
|
+
PATTERNS = {
|
|
13
|
+
track: /TRACK (\d{1,3}) AUDIO/,
|
|
14
|
+
performer: /PERFORMER "(.*)"/,
|
|
15
|
+
title: /TITLE "(.*)"/,
|
|
16
|
+
index: /INDEX \d{1,3} (\d{1,3}):(\d{1,2}):(\d{1,2})/,
|
|
17
|
+
file: /FILE "(.*)"/,
|
|
18
|
+
genre: /REM GENRE (.*)\b/,
|
|
19
|
+
date: /REM DATE (\d*)/
|
|
20
|
+
}.freeze
|
|
21
|
+
|
|
22
|
+
def initialize(cuesheet, track_duration = nil)
|
|
23
|
+
@cuesheet = cuesheet
|
|
24
|
+
@track_duration = Index.new(track_duration) if track_duration
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def parse!
|
|
28
|
+
@songs = parse_titles.map { |title| { title: title } }
|
|
29
|
+
@songs.each_with_index do |song, i|
|
|
30
|
+
song[:performer] = parse_performers[i] || @performer
|
|
31
|
+
song[:track] = parse_tracks[i]
|
|
32
|
+
song[:index] = parse_indices[i]
|
|
33
|
+
song[:file] = parse_files[i]
|
|
34
|
+
end
|
|
35
|
+
parse_genre
|
|
36
|
+
parse_date
|
|
37
|
+
raise MalformedError, "Field amounts are not all present. Cuesheet is malformed!" unless valid?
|
|
38
|
+
|
|
39
|
+
calculate_song_durations!
|
|
40
|
+
true
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def position(value)
|
|
44
|
+
index = Index.new(value)
|
|
45
|
+
|
|
46
|
+
return @songs.first if index < @songs.first[:index]
|
|
47
|
+
|
|
48
|
+
@songs.each_with_index do |song, i|
|
|
49
|
+
return song if song == @songs.last
|
|
50
|
+
return song if between(song[:index], @songs[i + 1][:index], index)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def valid?
|
|
55
|
+
@songs.all? do |song|
|
|
56
|
+
%i[performer track index title].all? do |key|
|
|
57
|
+
!song[key].nil?
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
private
|
|
63
|
+
|
|
64
|
+
def calculate_song_durations!
|
|
65
|
+
@songs.each_with_index do |song, i|
|
|
66
|
+
if song == @songs.last
|
|
67
|
+
song[:duration] = (@track_duration - song[:index]) if @track_duration
|
|
68
|
+
return nil
|
|
69
|
+
end
|
|
70
|
+
song[:duration] = @songs[i + 1][:index] - song[:index]
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def between(a, b, position_index)
|
|
75
|
+
(position_index > a) && (position_index < b)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def parse_titles
|
|
79
|
+
unless @titles
|
|
80
|
+
@titles = cuesheet_scan(:title).map(&:first)
|
|
81
|
+
@title = @titles.delete_at(0)
|
|
82
|
+
end
|
|
83
|
+
@titles
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def parse_performers
|
|
87
|
+
unless @performers
|
|
88
|
+
@performers = cuesheet_scan(:performer).map(&:first)
|
|
89
|
+
@performer = @performers.delete_at(0)
|
|
90
|
+
end
|
|
91
|
+
@performers
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def parse_tracks
|
|
95
|
+
@_parse_tracks ||= cuesheet_scan(:track).map { |track| track.first.to_i }
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def parse_indices
|
|
99
|
+
@_parse_indices ||= cuesheet_scan(:index).map do |index|
|
|
100
|
+
Index.new([index[0].to_i, index[1].to_i, index[2].to_i])
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def parse_files
|
|
105
|
+
unless @files
|
|
106
|
+
@files = cuesheet_scan(:file).map(&:first)
|
|
107
|
+
@file = @files.delete_at(0) if @files.size == 1
|
|
108
|
+
end
|
|
109
|
+
@files
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def parse_genre
|
|
113
|
+
@cuesheet.scan(PATTERNS[:genre]) do |genre|
|
|
114
|
+
@genre = genre.first
|
|
115
|
+
break
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def parse_date
|
|
120
|
+
@cuesheet.scan(PATTERNS[:date]) do |date|
|
|
121
|
+
@date = date.first.to_i
|
|
122
|
+
break
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def cuesheet_scan(field)
|
|
127
|
+
scan = @cuesheet.scan(PATTERNS[field])
|
|
128
|
+
raise MalformedError, "No fields were found for #{field}" if scan.empty?
|
|
129
|
+
|
|
130
|
+
scan
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module CueBreaker
|
|
2
4
|
module Dependencies
|
|
3
5
|
extend self
|
|
@@ -9,9 +11,9 @@ module CueBreaker
|
|
|
9
11
|
private
|
|
10
12
|
|
|
11
13
|
def check_ffmpeg_installed!
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
return if system("which ffmpeg > /dev/null 2>&1")
|
|
15
|
+
|
|
16
|
+
raise "ffmpeg is not installed. Please install it to use this gem."
|
|
15
17
|
end
|
|
16
18
|
end
|
|
17
19
|
end
|
|
@@ -1,7 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module CueBreaker
|
|
2
4
|
class FFmpegArgs
|
|
3
5
|
def initialize(file, album, track)
|
|
4
|
-
@file
|
|
6
|
+
@file = file
|
|
7
|
+
@album = album
|
|
8
|
+
@track = track
|
|
5
9
|
end
|
|
6
10
|
|
|
7
11
|
def options(output_path)
|
|
@@ -36,7 +40,7 @@ module CueBreaker
|
|
|
36
40
|
"-metadata", "genre=#{@album.genre}",
|
|
37
41
|
"-metadata", "album=#{@album.title}",
|
|
38
42
|
"-metadata", "date=#{@album.date}",
|
|
39
|
-
"-metadata", "track=#{@album.track_number(@track)}"
|
|
43
|
+
"-metadata", "track=#{@album.track_number(@track)}"
|
|
40
44
|
]
|
|
41
45
|
end
|
|
42
46
|
|
data/lib/cue_breaker/track.rb
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "delegate"
|
|
2
4
|
|
|
3
5
|
module CueBreaker
|
|
4
6
|
class Track
|
|
5
7
|
attr_reader :title, :number, :start, :finish
|
|
6
8
|
|
|
7
9
|
def initialize(title:, number:, start:, finish:)
|
|
8
|
-
@title
|
|
10
|
+
@title = title
|
|
11
|
+
@number = number
|
|
12
|
+
@start = start
|
|
13
|
+
@finish = finish
|
|
9
14
|
end
|
|
10
15
|
|
|
11
16
|
def present
|
|
@@ -24,7 +29,7 @@ module CueBreaker
|
|
|
24
29
|
private
|
|
25
30
|
|
|
26
31
|
def parse_time(time_str)
|
|
27
|
-
parts = time_str.split(
|
|
32
|
+
parts = time_str.split(":").map(&:to_f)
|
|
28
33
|
(parts[0] * 60) + parts[1] + (parts[2] / 75.0)
|
|
29
34
|
end
|
|
30
35
|
end
|
data/lib/cue_breaker/version.rb
CHANGED
data/lib/cue_breaker.rb
CHANGED
metadata
CHANGED
|
@@ -1,44 +1,16 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: cue_breaker
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Lukas Alexander
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2024-05-
|
|
12
|
-
dependencies:
|
|
13
|
-
|
|
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
|
|
11
|
+
date: 2024-05-24 00:00:00.000000000 Z
|
|
12
|
+
dependencies: []
|
|
13
|
+
description: Breaks down large CUE/WAV files into mp3 chunks
|
|
42
14
|
email: the.lukelex@gmail.com
|
|
43
15
|
executables:
|
|
44
16
|
- cue_break
|
|
@@ -51,23 +23,26 @@ files:
|
|
|
51
23
|
- lib/cue_breaker/album.rb
|
|
52
24
|
- lib/cue_breaker/cli.rb
|
|
53
25
|
- lib/cue_breaker/core.rb
|
|
26
|
+
- lib/cue_breaker/cue/index.rb
|
|
27
|
+
- lib/cue_breaker/cue/sheet.rb
|
|
54
28
|
- lib/cue_breaker/dependencies.rb
|
|
55
29
|
- lib/cue_breaker/ffmpeg_args.rb
|
|
56
30
|
- lib/cue_breaker/track.rb
|
|
57
31
|
- lib/cue_breaker/version.rb
|
|
58
|
-
homepage: https://
|
|
32
|
+
homepage: https://github.com/lukelex/cue_breaker
|
|
59
33
|
licenses:
|
|
60
34
|
- MIT
|
|
61
|
-
metadata:
|
|
35
|
+
metadata:
|
|
36
|
+
rubygems_mfa_required: 'true'
|
|
62
37
|
post_install_message:
|
|
63
38
|
rdoc_options: []
|
|
64
39
|
require_paths:
|
|
65
40
|
- lib
|
|
66
41
|
required_ruby_version: !ruby/object:Gem::Requirement
|
|
67
42
|
requirements:
|
|
68
|
-
- - "
|
|
43
|
+
- - "~>"
|
|
69
44
|
- !ruby/object:Gem::Version
|
|
70
|
-
version: '0'
|
|
45
|
+
version: '3.0'
|
|
71
46
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
72
47
|
requirements:
|
|
73
48
|
- - ">="
|