wavesync 1.0.0.alpha1 → 1.0.0.alpha2
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.md +22 -1
- data/lib/wavesync/analyzer.rb +4 -0
- data/lib/wavesync/cli.rb +7 -146
- data/lib/wavesync/commands/analyze.rb +23 -0
- data/lib/wavesync/commands/command.rb +29 -0
- data/lib/wavesync/commands/help.rb +81 -0
- data/lib/wavesync/commands/set.rb +63 -0
- data/lib/wavesync/commands/sync.rb +53 -0
- data/lib/wavesync/commands.rb +30 -0
- data/lib/wavesync/ui.rb +12 -0
- data/lib/wavesync/version.rb +1 -1
- data/lib/wavesync.rb +1 -0
- metadata +11 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 166c4643be69e020ac6ac73611146502faa4891ad35f60bd30f3143702113c14
|
|
4
|
+
data.tar.gz: f41b3be18c7f4014f892a19e27612a363502d1f70effe098e74d239b19d9d873
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d1df257786183fa8253036ca6e59b7b559bab4d82fba2da101aa86c58e91f56af272215fd406785e05c8eec6cb473c22ea8d90ff9fd4367f6894ae9916aef54a
|
|
7
|
+
data.tar.gz: b29f51c0a796aedddee42d219e042e02b150b89ec23775b40ca7c8d7e93b2b7c1dae438a240aa3e549e2e3f53318f3960d6305965d29a6199b29f62d99c1fa10
|
data/README.md
CHANGED
|
@@ -63,10 +63,17 @@ devices:
|
|
|
63
63
|
|
|
64
64
|
Wavesync will exit with an error if a device model in the config is not supported.
|
|
65
65
|
|
|
66
|
+
## Help
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
wavesync help
|
|
70
|
+
```
|
|
71
|
+
|
|
66
72
|
## Usage
|
|
67
73
|
|
|
68
74
|
```bash
|
|
69
|
-
# Sync library
|
|
75
|
+
# Sync library (uses default config at ~/wavesync.yml)
|
|
76
|
+
# If multiple devices are configured, you will be prompted to select one
|
|
70
77
|
wavesync sync
|
|
71
78
|
|
|
72
79
|
# Use a config at a specific path
|
|
@@ -133,3 +140,17 @@ Example: If a 96kHz file is synced to an Octatrack (which only supports 44.1kHz)
|
|
|
133
140
|
```bash
|
|
134
141
|
rake test
|
|
135
142
|
```
|
|
143
|
+
|
|
144
|
+
### Running RuboCop
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
bundle exec rubocop
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Releasing
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
rake release:publish
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
This tags the current version, pushes the tag to origin, builds the gem, and publishes it to RubyGems.
|
data/lib/wavesync/analyzer.rb
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
module Wavesync
|
|
4
4
|
class Analyzer
|
|
5
|
+
CONFIRM_MESSAGE = 'wavesync analyze will add bpm meta data to files in library. Continue? [y/N] '
|
|
6
|
+
|
|
5
7
|
def initialize(library_path)
|
|
6
8
|
@library_path = File.expand_path(library_path)
|
|
7
9
|
@audio_files = find_audio_files
|
|
@@ -14,6 +16,8 @@ module Wavesync
|
|
|
14
16
|
exit 1
|
|
15
17
|
end
|
|
16
18
|
|
|
19
|
+
return unless @ui.confirm(CONFIRM_MESSAGE)
|
|
20
|
+
|
|
17
21
|
@audio_files.each_with_index do |file, index|
|
|
18
22
|
audio = Audio.new(file)
|
|
19
23
|
|
data/lib/wavesync/cli.rb
CHANGED
|
@@ -1,159 +1,20 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
require_relative 'commands'
|
|
4
4
|
|
|
5
5
|
module Wavesync
|
|
6
6
|
class CLI
|
|
7
7
|
def self.start
|
|
8
|
-
|
|
8
|
+
command_name = ARGV.first && !ARGV.first.start_with?('-') ? ARGV.shift : 'sync'
|
|
9
|
+
command_class = Commands::ALL.find { |cmd| command_name == cmd.name }
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
start_sync
|
|
13
|
-
when 'analyze'
|
|
14
|
-
start_analyze
|
|
15
|
-
when 'set'
|
|
16
|
-
start_set
|
|
11
|
+
if command_class
|
|
12
|
+
command_class.new.run
|
|
17
13
|
else
|
|
18
|
-
puts "Unknown command: #{
|
|
19
|
-
puts
|
|
14
|
+
puts "Unknown command: #{command_name}"
|
|
15
|
+
puts "Available commands: #{Commands::ALL.map(&:name).join(', ')}"
|
|
20
16
|
exit 1
|
|
21
17
|
end
|
|
22
18
|
end
|
|
23
|
-
|
|
24
|
-
def self.start_sync
|
|
25
|
-
options = {}
|
|
26
|
-
parser = OptionParser.new do |opts|
|
|
27
|
-
opts.banner = 'Usage: wavesync sync [options]'
|
|
28
|
-
|
|
29
|
-
opts.on('-d', '--device NAME', 'Name of device to sync (as defined in config)') do |value|
|
|
30
|
-
options[:device] = value
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
opts.on('-c', '--config PATH', 'Path to wavesync config YAML file') do |value|
|
|
34
|
-
options[:config] = value
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
opts.on('-p', '--pad', 'Pad tracks with silence so total length is a multiple of 64 bars (Octatrack only)') do
|
|
38
|
-
options[:pad] = true
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
parser.parse!
|
|
43
|
-
|
|
44
|
-
config_path = options[:config] || Wavesync::Config::DEFAULT_PATH
|
|
45
|
-
config = load_config(config_path)
|
|
46
|
-
|
|
47
|
-
device_configs = config.device_configs
|
|
48
|
-
if options[:device]
|
|
49
|
-
device_configs = device_configs.select { |device_config| device_config[:name] == options[:device] }
|
|
50
|
-
if device_configs.empty?
|
|
51
|
-
known = config.device_configs.map { |device_config| device_config[:name] }.join(', ')
|
|
52
|
-
puts "Unknown device \"#{options[:device]}\". Devices in config: #{known}"
|
|
53
|
-
exit 1
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
device_configs.each do |device_config|
|
|
58
|
-
next if Wavesync::Device.find_by(name: device_config[:model])
|
|
59
|
-
|
|
60
|
-
supported = Wavesync::Device.all.map(&:name).join(', ')
|
|
61
|
-
puts "Unknown device model \"#{device_config[:model]}\" in config. Supported models: #{supported}"
|
|
62
|
-
exit 1
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
scanner = Wavesync::Scanner.new(config.library)
|
|
66
|
-
|
|
67
|
-
device_configs.each do |device_config|
|
|
68
|
-
scanner.sync(device_config[:path], Wavesync::Device.find_by(name: device_config[:model]),
|
|
69
|
-
pad: options[:pad] || false)
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
def self.start_set
|
|
74
|
-
subcommand = ARGV.shift
|
|
75
|
-
|
|
76
|
-
options = {}
|
|
77
|
-
parser = OptionParser.new do |opts|
|
|
78
|
-
opts.banner = 'Usage: wavesync set <subcommand> [options]'
|
|
79
|
-
|
|
80
|
-
opts.on('-c', '--config PATH', 'Path to wavesync config YAML file') do |value|
|
|
81
|
-
options[:config] = value
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
parser.parse!
|
|
86
|
-
|
|
87
|
-
config_path = options[:config] || Wavesync::Config::DEFAULT_PATH
|
|
88
|
-
config = load_config(config_path)
|
|
89
|
-
|
|
90
|
-
case subcommand
|
|
91
|
-
when 'create'
|
|
92
|
-
name = require_set_name('create')
|
|
93
|
-
if Wavesync::Set.exists?(config.library, name)
|
|
94
|
-
puts "Set '#{name}' already exists. Use 'wavesync set edit #{name}' to edit it."
|
|
95
|
-
exit 1
|
|
96
|
-
end
|
|
97
|
-
set = Wavesync::Set.new(config.library, name)
|
|
98
|
-
Wavesync::SetEditor.new(set, config.library).run
|
|
99
|
-
when 'edit'
|
|
100
|
-
name = require_set_name('edit')
|
|
101
|
-
unless Wavesync::Set.exists?(config.library, name)
|
|
102
|
-
puts "Set '#{name}' not found. Use 'wavesync set create #{name}' to create it."
|
|
103
|
-
exit 1
|
|
104
|
-
end
|
|
105
|
-
set = Wavesync::Set.load(config.library, name)
|
|
106
|
-
Wavesync::SetEditor.new(set, config.library).run
|
|
107
|
-
when 'list'
|
|
108
|
-
sets = Wavesync::Set.all(config.library)
|
|
109
|
-
if sets.empty?
|
|
110
|
-
puts 'No sets found.'
|
|
111
|
-
else
|
|
112
|
-
sets.each { |s| puts "#{s.name} (#{s.tracks.size} tracks)" }
|
|
113
|
-
end
|
|
114
|
-
else
|
|
115
|
-
puts "Unknown subcommand: #{subcommand || '(none)'}"
|
|
116
|
-
puts 'Available subcommands: create, edit, list'
|
|
117
|
-
exit 1
|
|
118
|
-
end
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
def self.load_config(path)
|
|
122
|
-
Wavesync::Config.load(path)
|
|
123
|
-
rescue Wavesync::ConfigError => e
|
|
124
|
-
puts "Configuration error: #{e.message}"
|
|
125
|
-
exit 1
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
def self.require_set_name(subcommand)
|
|
129
|
-
name = ARGV.shift
|
|
130
|
-
unless name
|
|
131
|
-
puts "Usage: wavesync set #{subcommand} <name>"
|
|
132
|
-
exit 1
|
|
133
|
-
end
|
|
134
|
-
name
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
def self.start_analyze
|
|
138
|
-
options = {}
|
|
139
|
-
parser = OptionParser.new do |opts|
|
|
140
|
-
opts.banner = 'Usage: wavesync analyze [options]'
|
|
141
|
-
|
|
142
|
-
opts.on('-c', '--config PATH', 'Path to wavesync config YAML file') do |value|
|
|
143
|
-
options[:config] = value
|
|
144
|
-
end
|
|
145
|
-
|
|
146
|
-
opts.on('-f', '--force', 'Overwrite existing BPM values') do
|
|
147
|
-
options[:overwrite] = true
|
|
148
|
-
end
|
|
149
|
-
end
|
|
150
|
-
|
|
151
|
-
parser.parse!
|
|
152
|
-
|
|
153
|
-
config_path = options[:config] || Wavesync::Config::DEFAULT_PATH
|
|
154
|
-
config = load_config(config_path)
|
|
155
|
-
|
|
156
|
-
Wavesync::Analyzer.new(config.library).analyze(overwrite: options[:overwrite] || false)
|
|
157
|
-
end
|
|
158
19
|
end
|
|
159
20
|
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'optparse'
|
|
4
|
+
|
|
5
|
+
module Wavesync
|
|
6
|
+
module Commands
|
|
7
|
+
class Analyze < Command
|
|
8
|
+
FORCE_OPTION = Option.new(short: '-f', long: '--force', description: 'Overwrite existing BPM values')
|
|
9
|
+
|
|
10
|
+
self.name = 'analyze'
|
|
11
|
+
self.description = 'Detect and write BPM metadata to library tracks'
|
|
12
|
+
self.options = [FORCE_OPTION].freeze
|
|
13
|
+
|
|
14
|
+
def run
|
|
15
|
+
options, config = parse_options(banner: 'Usage: wavesync analyze [options]') do |opts, opts_hash|
|
|
16
|
+
opts.on(*FORCE_OPTION.to_a) { opts_hash[:overwrite] = true }
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
Wavesync::Analyzer.new(config.library).analyze(overwrite: options[:overwrite] || false)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'optparse'
|
|
4
|
+
|
|
5
|
+
module Wavesync
|
|
6
|
+
module Commands
|
|
7
|
+
class Command
|
|
8
|
+
class << self
|
|
9
|
+
attr_accessor :name, :description
|
|
10
|
+
attr_writer :options, :subcommands
|
|
11
|
+
|
|
12
|
+
def options = @options || []
|
|
13
|
+
def subcommands = @subcommands || []
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def parse_options(banner:)
|
|
17
|
+
options = {}
|
|
18
|
+
OptionParser.new do |opts|
|
|
19
|
+
opts.banner = banner
|
|
20
|
+
opts.on(*CONFIG_OPTION.to_a) { |value| options[:config] = value }
|
|
21
|
+
yield opts, options if block_given?
|
|
22
|
+
end.parse!
|
|
23
|
+
config_path = options[:config] || Wavesync::Config::DEFAULT_PATH
|
|
24
|
+
config = Commands.load_config(config_path)
|
|
25
|
+
[options, config]
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'optparse'
|
|
4
|
+
require 'rainbow'
|
|
5
|
+
|
|
6
|
+
module Wavesync
|
|
7
|
+
module Commands
|
|
8
|
+
class Help < Command
|
|
9
|
+
self.name = 'help'
|
|
10
|
+
self.description = 'Show this help message'
|
|
11
|
+
|
|
12
|
+
DESCRIPTION_COLUMN = 23
|
|
13
|
+
|
|
14
|
+
def run
|
|
15
|
+
subcommand_name = ARGV.shift
|
|
16
|
+
|
|
17
|
+
if subcommand_name
|
|
18
|
+
command = ALL.find { |cmd| subcommand_name == cmd.name }
|
|
19
|
+
if command
|
|
20
|
+
show_command_help(command)
|
|
21
|
+
else
|
|
22
|
+
puts "Unknown command: #{subcommand_name}"
|
|
23
|
+
puts "Available commands: #{ALL.map(&:name).reject { |cmd_name| cmd_name == self.class.name }.join(', ')}"
|
|
24
|
+
exit 1
|
|
25
|
+
end
|
|
26
|
+
else
|
|
27
|
+
show_general_help
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def show_general_help
|
|
34
|
+
puts 'Usage: wavesync [command] [options]'
|
|
35
|
+
puts ''
|
|
36
|
+
puts 'Commands:'
|
|
37
|
+
ALL.each do |command|
|
|
38
|
+
if command.subcommands.any?
|
|
39
|
+
command.subcommands.each { |subcommand| puts format_command_line(subcommand.usage, subcommand.description) }
|
|
40
|
+
else
|
|
41
|
+
puts format_command_line(command.name, command.description)
|
|
42
|
+
command.options.each { |option| puts format_option_line(option, indent: 4) }
|
|
43
|
+
end
|
|
44
|
+
puts ''
|
|
45
|
+
end
|
|
46
|
+
puts 'Options:'
|
|
47
|
+
GLOBAL_OPTIONS.each { |option| puts format_option_line(option, indent: 2) }
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def show_command_help(command)
|
|
51
|
+
if command.subcommands.any?
|
|
52
|
+
puts "Usage: wavesync #{command.name} <subcommand> [options]"
|
|
53
|
+
puts ''
|
|
54
|
+
puts 'Subcommands:'
|
|
55
|
+
command.subcommands.each do |subcommand|
|
|
56
|
+
subcommand_key = subcommand.usage.delete_prefix("#{command.name} ")
|
|
57
|
+
puts " #{subcommand_key.ljust(DESCRIPTION_COLUMN - 2)}#{subcommand.description}"
|
|
58
|
+
end
|
|
59
|
+
puts ''
|
|
60
|
+
puts 'Options:'
|
|
61
|
+
GLOBAL_OPTIONS.each { |option| puts " #{option.short}, #{option.long} #{option.description}" }
|
|
62
|
+
else
|
|
63
|
+
OptionParser.new do |opts|
|
|
64
|
+
opts.banner = "Usage: wavesync #{command.name} [options]"
|
|
65
|
+
(command.options + GLOBAL_OPTIONS).each { |option| opts.on(*option.to_a) }
|
|
66
|
+
puts opts
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def format_command_line(name, description)
|
|
72
|
+
" #{name.ljust(DESCRIPTION_COLUMN - 2)}#{description}"
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def format_option_line(option, indent:)
|
|
76
|
+
key = "#{option.short}, #{option.long}"
|
|
77
|
+
Rainbow("#{' ' * indent}#{key.ljust(DESCRIPTION_COLUMN - indent)}#{option.description}").darkgray
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'optparse'
|
|
4
|
+
|
|
5
|
+
module Wavesync
|
|
6
|
+
module Commands
|
|
7
|
+
class Set < Command
|
|
8
|
+
self.name = 'set'
|
|
9
|
+
self.subcommands = [
|
|
10
|
+
Subcommand.new(usage: 'set create NAME', description: 'Create a new track set'),
|
|
11
|
+
Subcommand.new(usage: 'set edit NAME', description: 'Edit an existing track set'),
|
|
12
|
+
Subcommand.new(usage: 'set list', description: 'List all track sets')
|
|
13
|
+
].freeze
|
|
14
|
+
|
|
15
|
+
def run
|
|
16
|
+
subcommand = ARGV.shift
|
|
17
|
+
|
|
18
|
+
_options, config = parse_options(banner: 'Usage: wavesync set <subcommand> [options]')
|
|
19
|
+
|
|
20
|
+
case subcommand
|
|
21
|
+
when 'create'
|
|
22
|
+
name = require_name('create')
|
|
23
|
+
if Wavesync::Set.exists?(config.library, name)
|
|
24
|
+
puts "Set '#{name}' already exists. Use 'wavesync set edit #{name}' to edit it."
|
|
25
|
+
exit 1
|
|
26
|
+
end
|
|
27
|
+
set = Wavesync::Set.new(config.library, name)
|
|
28
|
+
Wavesync::SetEditor.new(set, config.library).run
|
|
29
|
+
when 'edit'
|
|
30
|
+
name = require_name('edit')
|
|
31
|
+
unless Wavesync::Set.exists?(config.library, name)
|
|
32
|
+
puts "Set '#{name}' not found. Use 'wavesync set create #{name}' to create it."
|
|
33
|
+
exit 1
|
|
34
|
+
end
|
|
35
|
+
set = Wavesync::Set.load(config.library, name)
|
|
36
|
+
Wavesync::SetEditor.new(set, config.library).run
|
|
37
|
+
when 'list'
|
|
38
|
+
sets = Wavesync::Set.all(config.library)
|
|
39
|
+
if sets.empty?
|
|
40
|
+
puts 'No sets found.'
|
|
41
|
+
else
|
|
42
|
+
sets.each { |set| puts "#{set.name} (#{set.tracks.size} tracks)" }
|
|
43
|
+
end
|
|
44
|
+
else
|
|
45
|
+
puts "Unknown subcommand: #{subcommand || '(none)'}"
|
|
46
|
+
puts 'Available subcommands: create, edit, list'
|
|
47
|
+
exit 1
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
def require_name(subcommand)
|
|
54
|
+
name = ARGV.shift
|
|
55
|
+
unless name
|
|
56
|
+
puts "Usage: wavesync set #{subcommand} <name>"
|
|
57
|
+
exit 1
|
|
58
|
+
end
|
|
59
|
+
name
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'optparse'
|
|
4
|
+
|
|
5
|
+
module Wavesync
|
|
6
|
+
module Commands
|
|
7
|
+
class Sync < Command
|
|
8
|
+
DEVICE_OPTION = Option.new(short: '-d', long: '--device NAME', description: 'Name of device to sync (as defined in config)')
|
|
9
|
+
PAD_OPTION = Option.new(short: '-p', long: '--pad', description: 'Pad tracks with silence so total length is a multiple of 64 bars (Octatrack only)')
|
|
10
|
+
|
|
11
|
+
self.name = 'sync'
|
|
12
|
+
self.description = 'Sync music library to a device'
|
|
13
|
+
self.options = [DEVICE_OPTION, PAD_OPTION].freeze
|
|
14
|
+
|
|
15
|
+
def run
|
|
16
|
+
options, config = parse_options(banner: 'Usage: wavesync sync [options]') do |opts, opts_hash|
|
|
17
|
+
opts.on(*DEVICE_OPTION.to_a) { |value| opts_hash[:device] = value }
|
|
18
|
+
opts.on(*PAD_OPTION.to_a) { opts_hash[:pad] = true }
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
device_configs = config.device_configs
|
|
22
|
+
if options[:device]
|
|
23
|
+
device_configs = device_configs.select { |device_config| device_config[:name] == options[:device] }
|
|
24
|
+
if device_configs.empty?
|
|
25
|
+
known = config.device_configs.map { |device_config| device_config[:name] }.join(', ')
|
|
26
|
+
puts "Unknown device \"#{options[:device]}\". Devices in config: #{known}"
|
|
27
|
+
exit 1
|
|
28
|
+
end
|
|
29
|
+
elsif device_configs.size > 1
|
|
30
|
+
device_names = device_configs.map { |device_config| device_config[:name] }
|
|
31
|
+
selected_name = Wavesync::UI.new.select('Select device', device_names)
|
|
32
|
+
device_configs = device_configs.select { |device_config| device_config[:name] == selected_name }
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
device_pairs = device_configs.map do |device_config|
|
|
36
|
+
device = Wavesync::Device.find_by(name: device_config[:model])
|
|
37
|
+
unless device
|
|
38
|
+
supported = Wavesync::Device.all.map(&:name).join(', ')
|
|
39
|
+
puts "Unknown device model \"#{device_config[:model]}\" in config. Supported models: #{supported}"
|
|
40
|
+
exit 1
|
|
41
|
+
end
|
|
42
|
+
[device_config, device]
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
scanner = Wavesync::Scanner.new(config.library)
|
|
46
|
+
|
|
47
|
+
device_pairs.each do |device_config, device|
|
|
48
|
+
scanner.sync(device_config[:path], device, pad: options[:pad] || false)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wavesync
|
|
4
|
+
module Commands
|
|
5
|
+
Option = Struct.new(:short, :long, :description, keyword_init: true)
|
|
6
|
+
Subcommand = Struct.new(:usage, :description, keyword_init: true)
|
|
7
|
+
|
|
8
|
+
CONFIG_OPTION = Option.new(short: '-c', long: '--config PATH', description: 'Path to wavesync config YAML file')
|
|
9
|
+
GLOBAL_OPTIONS = [CONFIG_OPTION].freeze
|
|
10
|
+
|
|
11
|
+
def self.load_config(path)
|
|
12
|
+
Wavesync::Config.load(path)
|
|
13
|
+
rescue Wavesync::ConfigError => e
|
|
14
|
+
puts "Configuration error: #{e.message}"
|
|
15
|
+
exit 1
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
require_relative 'commands/command'
|
|
21
|
+
require_relative 'commands/sync'
|
|
22
|
+
require_relative 'commands/analyze'
|
|
23
|
+
require_relative 'commands/set'
|
|
24
|
+
require_relative 'commands/help'
|
|
25
|
+
|
|
26
|
+
module Wavesync
|
|
27
|
+
module Commands
|
|
28
|
+
ALL = [Sync, Analyze, Set, Help].freeze
|
|
29
|
+
end
|
|
30
|
+
end
|
data/lib/wavesync/ui.rb
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'tty-cursor'
|
|
4
|
+
require 'tty-prompt'
|
|
4
5
|
require 'rainbow'
|
|
5
6
|
|
|
6
7
|
module Wavesync
|
|
@@ -17,6 +18,7 @@ module Wavesync
|
|
|
17
18
|
def initialize
|
|
18
19
|
@cursor = TTY::Cursor
|
|
19
20
|
@sticky_lines = []
|
|
21
|
+
@prompt = TTY::Prompt.new(interrupt: :exit, active_color: :red)
|
|
20
22
|
end
|
|
21
23
|
|
|
22
24
|
def file_progress(filename)
|
|
@@ -86,6 +88,16 @@ module Wavesync
|
|
|
86
88
|
set_analyze_file_stickies(file, label)
|
|
87
89
|
end
|
|
88
90
|
|
|
91
|
+
def confirm(message)
|
|
92
|
+
print in_color(message, :secondary)
|
|
93
|
+
response = $stdin.gets.to_s.strip.downcase
|
|
94
|
+
response == 'y'
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def select(label, options)
|
|
98
|
+
@prompt.select(label, options, cycle: true)
|
|
99
|
+
end
|
|
100
|
+
|
|
89
101
|
def color(text, key)
|
|
90
102
|
in_color(text, key)
|
|
91
103
|
end
|
data/lib/wavesync/version.rb
CHANGED
data/lib/wavesync.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: wavesync
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.0.
|
|
4
|
+
version: 1.0.0.alpha2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andreas Zecher
|
|
@@ -109,6 +109,12 @@ files:
|
|
|
109
109
|
- lib/wavesync/audio_format.rb
|
|
110
110
|
- lib/wavesync/bpm_detector.rb
|
|
111
111
|
- lib/wavesync/cli.rb
|
|
112
|
+
- lib/wavesync/commands.rb
|
|
113
|
+
- lib/wavesync/commands/analyze.rb
|
|
114
|
+
- lib/wavesync/commands/command.rb
|
|
115
|
+
- lib/wavesync/commands/help.rb
|
|
116
|
+
- lib/wavesync/commands/set.rb
|
|
117
|
+
- lib/wavesync/commands/sync.rb
|
|
112
118
|
- lib/wavesync/config.rb
|
|
113
119
|
- lib/wavesync/device.rb
|
|
114
120
|
- lib/wavesync/file_converter.rb
|
|
@@ -122,7 +128,9 @@ files:
|
|
|
122
128
|
homepage: https://github.com/pixelate/wavesync
|
|
123
129
|
licenses:
|
|
124
130
|
- MIT
|
|
125
|
-
metadata:
|
|
131
|
+
metadata:
|
|
132
|
+
documentation_uri: https://github.com/pixelate/wavesync?tab=readme-ov-file#wavesync
|
|
133
|
+
rubygems_mfa_required: 'true'
|
|
126
134
|
rdoc_options: []
|
|
127
135
|
require_paths:
|
|
128
136
|
- lib
|
|
@@ -130,7 +138,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
130
138
|
requirements:
|
|
131
139
|
- - ">="
|
|
132
140
|
- !ruby/object:Gem::Version
|
|
133
|
-
version: '3.
|
|
141
|
+
version: '3.3'
|
|
134
142
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
135
143
|
requirements:
|
|
136
144
|
- - ">="
|