drum 0.1.14 → 0.2.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: da330d9d023cd2cab59a1e210a1363fa00569fed1c5edcf382424112ba2e5bc3
4
- data.tar.gz: 7d339df36d5438a64ef33887ccfe084a350d8737cf0444fbe95adb901e1f6bd3
3
+ metadata.gz: 0515ca290089497d8667ed64575eb60dc604ba793812b77437ced8d27f70e6bb
4
+ data.tar.gz: 1da960b8dc5e79ce85328e918c43d214898824e51d544b613b58ede726666f97
5
5
  SHA512:
6
- metadata.gz: f023760cc5107baf38d87c60cba3d404732d14552c50a904358abd8153d28861386e53f359f4ba3735e7e66b6566dac529706ed29b15853a18c7c3c10ba53302
7
- data.tar.gz: fdd9371a7f21d5a879444f4d2c39552e5b15af27459c0126264171633a86b4c7f5c460405a9af63b3758aa130cf9cea919e9878c77b6b2d8726eccd2f3c1a439
6
+ metadata.gz: db118818875e8c9d0d5281697e033bcaeebb3bc204355e41ab4436ed2da1738297c703ed8aa813f32456f968851729794f3e209c0510ca1ddbf218b93af75ab0
7
+ data.tar.gz: 24ce2b4be59b259617cc50ba66fc35c48aeeeb89faa716a5ad457a959364ccb39cb37b7fa86c4e4f4da6593b7c753bc9eebcde02226d24a6a65402f5d2e7eca8
@@ -4,13 +4,18 @@ on: [push]
4
4
 
5
5
  jobs:
6
6
  test:
7
- runs-on: ubuntu-latest
7
+ strategy:
8
+ matrix:
9
+ os: ['ubuntu-latest', 'macos-latest']
10
+ ruby: ['2.7.0', '3.2.0']
11
+
12
+ runs-on: '${{ matrix.os }}'
8
13
  steps:
9
14
  - uses: actions/checkout@v2
10
15
  - name: Set up Ruby
11
16
  uses: ruby/setup-ruby@v1
12
17
  with:
13
- ruby-version: 2.7.0
18
+ ruby-version: '${{ matrix.ruby }}'
14
19
  - name: Install dependencies
15
20
  run: |
16
21
  gem install bundler -v 2.2.0
data/Gemfile CHANGED
@@ -3,6 +3,19 @@ source 'https://rubygems.org'
3
3
  # Specify your gem's dependencies in drum.gemspec
4
4
  gemspec
5
5
 
6
+ # Install AppleScript bridge on macOS
7
+ #
8
+ # Note: End-users installing drum via 'gem install'
9
+ # will need to install rb-scpt manually to use the integration.
10
+ #
11
+ # TODO: Investigate whether this could be done automatically
12
+ # See https://stackoverflow.com/a/10249133 for more info.
13
+ # Unfortunately checking the OS in the gemspec is insufficient,
14
+ # since the file is evaluated at packaging time.
15
+ if RUBY_PLATFORM =~ /\bdarwin/
16
+ gem 'rb-scpt', '~> 1.0'
17
+ end
18
+
6
19
  group :development, :test do
7
20
  gem 'rake', '~> 13.0'
8
21
  gem 'yard', '~> 0.9'
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- drum (0.1.14)
4
+ drum (0.2.1)
5
5
  highline (~> 2.0)
6
6
  jwt (~> 2.2)
7
7
  launchy (~> 2.4)
@@ -9,55 +9,55 @@ PATH
9
9
  rest-client (~> 2.0)
10
10
  rspotify (~> 2.10)
11
11
  ruby-limiter (~> 2.1)
12
- thor (~> 0.20)
12
+ thor (~> 1.2)
13
13
  webrick (~> 1.7)
14
14
 
15
15
  GEM
16
16
  remote: https://rubygems.org/
17
17
  specs:
18
- addressable (2.8.0)
19
- public_suffix (>= 2.0.2, < 5.0)
20
- diff-lcs (1.4.4)
18
+ addressable (2.8.4)
19
+ public_suffix (>= 2.0.2, < 6.0)
20
+ diff-lcs (1.5.0)
21
21
  domain_name (0.5.20190701)
22
22
  unf (>= 0.0.5, < 1.0.0)
23
- faraday (2.3.0)
24
- faraday-net_http (~> 2.0)
23
+ faraday (2.7.4)
24
+ faraday-net_http (>= 2.0, < 3.1)
25
25
  ruby2_keywords (>= 0.0.4)
26
- faraday-net_http (2.0.2)
27
- ffi (1.15.5-x64-mingw32)
26
+ faraday-net_http (3.0.2)
27
+ ffi (1.15.5)
28
28
  hashie (5.0.0)
29
- highline (2.0.3)
30
- http-cookie (1.0.4)
29
+ highline (2.1.0)
30
+ http-cookie (1.0.5)
31
31
  domain_name (~> 0.5)
32
- jwt (2.3.0)
33
- launchy (2.5.0)
34
- addressable (~> 2.7)
32
+ jwt (2.7.0)
33
+ launchy (2.5.2)
34
+ addressable (~> 2.8)
35
35
  mime-types (3.4.1)
36
36
  mime-types-data (~> 3.2015)
37
- mime-types-data (3.2022.0105)
38
- multi_json (1.15.0)
37
+ mime-types-data (3.2023.0218.1)
39
38
  multi_xml (0.6.0)
40
39
  netrc (0.11.0)
41
- oauth2 (1.4.9)
40
+ oauth2 (2.0.9)
42
41
  faraday (>= 0.17.3, < 3.0)
43
42
  jwt (>= 1.0, < 3.0)
44
- multi_json (~> 1.3)
45
43
  multi_xml (~> 0.5)
46
- rack (>= 1.2, < 3)
47
- omniauth (2.1.0)
44
+ rack (>= 1.2, < 4)
45
+ snaky_hash (~> 2.0)
46
+ version_gem (~> 1.1)
47
+ omniauth (2.1.1)
48
48
  hashie (>= 3.4.6)
49
49
  rack (>= 2.2.3)
50
50
  rack-protection
51
- omniauth-oauth2 (1.7.2)
52
- oauth2 (~> 1.4)
53
- omniauth (>= 1.9, < 3)
51
+ omniauth-oauth2 (1.8.0)
52
+ oauth2 (>= 1.4, < 3)
53
+ omniauth (~> 2.0)
54
54
  options (2.3.2)
55
55
  progress_bar (1.3.3)
56
56
  highline (>= 1.6, < 3)
57
57
  options (~> 2.3.0)
58
- public_suffix (4.0.7)
59
- rack (2.2.3)
60
- rack-protection (2.2.0)
58
+ public_suffix (5.0.1)
59
+ rack (3.0.7)
60
+ rack-protection (3.0.6)
61
61
  rack
62
62
  rake (13.0.6)
63
63
  rest-client (2.0.2)
@@ -69,31 +69,35 @@ GEM
69
69
  http-cookie (>= 1.0.2, < 2.0)
70
70
  mime-types (>= 1.16, < 4.0)
71
71
  netrc (~> 0.8)
72
- rspec (3.10.0)
73
- rspec-core (~> 3.10.0)
74
- rspec-expectations (~> 3.10.0)
75
- rspec-mocks (~> 3.10.0)
76
- rspec-core (3.10.1)
77
- rspec-support (~> 3.10.0)
78
- rspec-expectations (3.10.1)
72
+ rspec (3.12.0)
73
+ rspec-core (~> 3.12.0)
74
+ rspec-expectations (~> 3.12.0)
75
+ rspec-mocks (~> 3.12.0)
76
+ rspec-core (3.12.2)
77
+ rspec-support (~> 3.12.0)
78
+ rspec-expectations (3.12.3)
79
79
  diff-lcs (>= 1.2.0, < 2.0)
80
- rspec-support (~> 3.10.0)
81
- rspec-mocks (3.10.2)
80
+ rspec-support (~> 3.12.0)
81
+ rspec-mocks (3.12.5)
82
82
  diff-lcs (>= 1.2.0, < 2.0)
83
- rspec-support (~> 3.10.0)
84
- rspec-support (3.10.2)
83
+ rspec-support (~> 3.12.0)
84
+ rspec-support (3.12.0)
85
85
  rspotify (2.11.1)
86
86
  addressable (~> 2.8.0)
87
87
  omniauth-oauth2 (>= 1.6)
88
88
  rest-client (~> 2.0.2)
89
89
  ruby-limiter (2.2.2)
90
90
  ruby2_keywords (0.0.5)
91
- thor (0.20.3)
91
+ snaky_hash (2.0.1)
92
+ hashie
93
+ version_gem (~> 1.1, >= 1.1.1)
94
+ thor (1.2.1)
92
95
  unf (0.1.4)
93
96
  unf_ext
94
- unf_ext (0.0.8.1)
95
- webrick (1.7.0)
96
- yard (0.9.26)
97
+ unf_ext (0.0.8.2)
98
+ version_gem (1.1.2)
99
+ webrick (1.8.1)
100
+ yard (0.9.34)
97
101
 
98
102
  PLATFORMS
99
103
  ruby
@@ -107,4 +111,4 @@ DEPENDENCIES
107
111
  yard (~> 0.9)
108
112
 
109
113
  BUNDLED WITH
110
- 2.2.29
114
+ 2.4.12
data/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # Drum
2
2
 
3
+ [![Test](https://github.com/fwcd/drum/actions/workflows/test.yml/badge.svg)](https://github.com/fwcd/drum/actions/workflows/test.yml)
4
+ [![Documentation](https://github.com/fwcd/drum/actions/workflows/documentation.yml/badge.svg)](https://fwcd.github.io/drum)
5
+
3
6
  A small tool for copying your playlists across music streaming services. Think `rsync`, but for playlists.
4
7
 
5
8
  ![Icon](artwork/icon128.png)
@@ -21,6 +24,7 @@ The basic usage pattern is always `drum cp [source] [destination]` where `source
21
24
  * `@spotify/playlists`
22
25
  * `@spotify/tracks`
23
26
  * `@applemusic/playlists`
27
+ * `@music/playlists` (referring to the local Apple Music (`Music.app`) library on macOS)
24
28
  * `@stdin`
25
29
  * `@stdout`
26
30
  * A dash `-`, synonymous with `@stdin` and `@stdout`, depending on usage
@@ -67,6 +71,8 @@ To run the application, run `bundle exec bin/drum`. You can also run `bin/consol
67
71
 
68
72
  To package the application into a gem, run `bundle exec rake build`. The built gem should then be located in `pkg`.
69
73
 
74
+ > Note: If you wish to install `drum` using `gem install`, you may need to install additional gems such as `rb-scpt` on macOS to use platform-specific integrations. See [the `Gemfile`](Gemfile) for more information.
75
+
70
76
  To install the gem, run `bundle exec rake install`.
71
77
 
72
78
  To generate the documentation, run `bundle exec rake yard`.
data/drum.gemspec CHANGED
@@ -23,8 +23,8 @@ Gem::Specification.new do |spec|
23
23
  spec.bindir = 'bin'
24
24
  spec.executables = ['drum']
25
25
  spec.require_paths = ['lib']
26
-
27
- spec.add_dependency 'thor', '~> 0.20'
26
+
27
+ spec.add_dependency 'thor', '~> 1.2'
28
28
  spec.add_dependency 'rspotify', '~> 2.10'
29
29
  spec.add_dependency 'launchy', '~> 2.4'
30
30
  spec.add_dependency 'ruby-limiter', '~> 2.1'
@@ -167,8 +167,6 @@ module Drum
167
167
  server.shutdown
168
168
  end
169
169
 
170
- trap 'INT' do server.shutdown end
171
-
172
170
  log.info "Launching callback HTTP server on port #{port}, waiting for auth code..."
173
171
  server.start
174
172
 
@@ -186,6 +184,8 @@ module Drum
186
184
  }
187
185
 
188
186
  user_token
187
+ ensure
188
+ server&.shutdown
189
189
  end
190
190
 
191
191
  def authenticate
@@ -2,6 +2,7 @@ require 'drum/model/playlist'
2
2
  require 'drum/model/ref'
3
3
  require 'drum/service/service'
4
4
  require 'drum/utils/log'
5
+ require 'drum/utils/yaml'
5
6
  require 'pathname'
6
7
  require 'uri'
7
8
  require 'yaml'
@@ -9,7 +10,7 @@ require 'yaml'
9
10
  module Drum
10
11
  # A service that reads/writes playlists to/from YAML files.
11
12
  class FileService < Service
12
- include Log
13
+ include Log, YAMLUtils
13
14
 
14
15
  def name
15
16
  'file'
@@ -45,12 +46,12 @@ module Drum
45
46
  if base_path.directory?
46
47
  Dir.glob("#{base_path}/**/*.{yaml,yml}").map do |p|
47
48
  path = Pathname.new(p)
48
- playlist = Playlist.deserialize(YAML.load(path.read))
49
+ playlist = Playlist.deserialize(from_yaml(path.read))
49
50
  playlist.path = path.relative_path_from(base_path).parent.each_filename.to_a
50
51
  playlist
51
52
  end
52
53
  else
53
- [Playlist.deserialize(YAML.load(base_path.read))]
54
+ [Playlist.deserialize(from_yaml(base_path.read))]
54
55
  end
55
56
  end
56
57
 
@@ -74,7 +75,7 @@ module Drum
74
75
  end
75
76
 
76
77
  length = 6
77
- while playlist_path[length].exist? && Playlist.deserialize(YAML.load(playlist_path[length].read)).id != playlist.id
78
+ while playlist_path[length].exist? && Playlist.deserialize(from_yaml(playlist_path[length].read)).id != playlist.id
78
79
  length += 1
79
80
  end
80
81
 
@@ -0,0 +1,117 @@
1
+ require 'drum/model/album'
2
+ require 'drum/model/artist'
3
+ require 'drum/model/ref'
4
+ require 'drum/model/playlist'
5
+ require 'drum/model/track'
6
+ require 'drum/service/service'
7
+ require 'drum/utils/log'
8
+
9
+ module Drum
10
+ # A service that uses AppleScript to interact with the local Apple Music (Music.app) library.
11
+ #
12
+ # Useful resources:
13
+ # - https://github.com/BrendanThompson/rb-scpt/tree/develop/sample
14
+ # - https://stackoverflow.com/questions/12964766/create-playlist-in-itunes-with-python-and-scripting-bridge
15
+ # - https://dougscripts.com/itunes/itinfo/info01.php
16
+ # - https://dougscripts.com/itunes/itinfo/info02.php
17
+ # - https://dougscripts.com/itunes/itinfo/info03.php
18
+ # - https://github.com/sorah/jockey/blob/master/add.rb
19
+ class MusicService < Service
20
+ include Log
21
+
22
+ def name
23
+ 'music'
24
+ end
25
+
26
+ def require_rb_scpt
27
+ begin
28
+ require 'rb-scpt'
29
+ rescue LoadError
30
+ raise "Using the local Apple Music importer requires the 'rb-scpt' gem (which requires macOS)"
31
+ end
32
+ end
33
+
34
+ def get_library_proxy
35
+ self.require_rb_scpt
36
+ music = Appscript.app('Music')
37
+ source = music.sources[1]
38
+ unless source.kind.get == :library
39
+ raise 'Could not get music library source'
40
+ end
41
+ return source
42
+ end
43
+
44
+ # Ref parsing
45
+
46
+ def parse_ref(raw_ref)
47
+ if raw_ref.is_token
48
+ location = case raw_ref.text
49
+ when "#{self.name}/playlists" then :playlists
50
+ else return nil
51
+ end
52
+ Ref.new(self.name, :special, location)
53
+ else
54
+ nil
55
+ end
56
+ end
57
+
58
+ # Upload helpers
59
+
60
+ def to_track_proxy(library_proxy, playlist, track)
61
+ # Get track metadata
62
+ name = track.name
63
+ artists = track.artist_ids.map { |id| playlist.artists[id].name }
64
+
65
+ # Match the track with a track in the local library
66
+ # TODO: Don't require exact 100% matches
67
+ name_query = Appscript.its.name.eq(name)
68
+ artists_query = artists
69
+ .map { |a| Appscript.its.artist.contains(a) }
70
+ .reduce { |q1, q2| q1.or(q2) }
71
+ query = name_query.and(artists_query)
72
+
73
+ # Find a matching track in the track
74
+ # TODO: Instead of choosing the first, prefer iTunes-matched/higher bitrate ones etc.
75
+ track_proxy = library_proxy.tracks[query].get.first
76
+
77
+ if track_proxy.nil?
78
+ log.warn "No match found for '#{track.name}' by '#{artists.first}'"
79
+ else
80
+ log.info "Matched '#{track.name}' with '#{track_proxy.name.get}' by '#{track_proxy.artist.get}'"
81
+ end
82
+ track_proxy
83
+ end
84
+
85
+ def upload_playlist(library_proxy, playlist)
86
+ playlist_proxy = library_proxy.make(new: :playlist, with_properties: {
87
+ name: playlist.name,
88
+ description: playlist.description,
89
+ }.compact)
90
+
91
+ playlist.tracks.each do |track|
92
+ track_proxy = self.to_track_proxy(library_proxy, playlist, track)
93
+ unless track_proxy.nil?
94
+ track_proxy.duplicate(to: playlist_proxy)
95
+ end
96
+ end
97
+ end
98
+
99
+ # Service
100
+
101
+ def download(ref)
102
+ raise 'Downloading is not implemented yet'
103
+ end
104
+
105
+ def upload(ref, playlists)
106
+ library_proxy = self.get_library_proxy
107
+
108
+ unless ref.resource_type == :special && ref.resource_location == :playlists
109
+ raise "Cannot upload to anything other than @#{self.name}/playlists yet!"
110
+ end
111
+
112
+ playlists.each do |playlist|
113
+ self.upload_playlist(library_proxy, playlist)
114
+ end
115
+ end
116
+ end
117
+ end
@@ -137,8 +137,6 @@ module Drum
137
137
  authorize_url = "https://accounts.spotify.com/authorize?client_id=#{client_id}&response_type=code&redirect_uri=http%3A%2F%2Flocalhost:#{port}%2Fcallback&scope=#{scopes.join('%20')}&state=#{csrf_state}"
138
138
  Launchy.open(authorize_url)
139
139
 
140
- trap 'INT' do server.shutdown end
141
-
142
140
  log.info "Launching callback HTTP server on port #{port}, waiting for auth code..."
143
141
  server.start
144
142
 
@@ -155,6 +153,8 @@ module Drum
155
153
  })
156
154
 
157
155
  self.consume_authentication_response(auth_response)
156
+ ensure
157
+ server&.shutdown
158
158
  end
159
159
 
160
160
  def authenticate_user_via_refresh(client_id, client_secret, refresh_token)
@@ -2,12 +2,13 @@ require 'drum/model/playlist'
2
2
  require 'drum/model/ref'
3
3
  require 'drum/service/service'
4
4
  require 'drum/utils/log'
5
+ require 'drum/utils/yaml'
5
6
  require 'yaml'
6
7
 
7
8
  module Drum
8
9
  # A service that reads from stdin and writes to stdout.
9
10
  class StdioService < Service
10
- include Log
11
+ include Log, YAMLUtils
11
12
 
12
13
  def name
13
14
  'stdio'
@@ -31,7 +32,7 @@ module Drum
31
32
  def download(playlist_ref)
32
33
  if playlist_ref.resource_location.include?(:stdin)
33
34
  # TODO: Support multiple, --- delimited playlists?
34
- [Playlist.deserialize(YAML.load(STDIN.read))]
35
+ [Playlist.deserialize(from_yaml(STDIN.read))]
35
36
  else
36
37
  []
37
38
  end
@@ -1,50 +1,58 @@
1
+ require 'drum/utils/log'
2
+ require 'drum/utils/yaml'
1
3
  require 'yaml'
2
4
 
3
- # A wrapper around a hash that stores values persistently in a YAML.
4
- #
5
- # @!attribute value
6
- # @return [Hash] The wrapped hash
7
- class Drum::PersistentHash
8
- attr_reader :value
9
-
10
- # Creates a new persistent hash.
5
+ module Drum
6
+ # A wrapper around a hash that stores values persistently in a YAML.
11
7
  #
12
- # @param [String] file_path The path to the stored YAML file (may be non-existent).
13
- # @param [Hash] value The initial default value, if the file doesn't exist yet or is malformed
14
- def initialize(file_path, value={})
15
- @file_path = file_path
16
- begin
17
- self.load
18
- rescue StandardError => e
19
- @value = value
20
- self.store
8
+ # @!attribute value
9
+ # @return [Hash] The wrapped hash
10
+ class PersistentHash
11
+ include Log, YAMLUtils
12
+ attr_reader :value
13
+
14
+ # Creates a new persistent hash.
15
+ #
16
+ # @param [String] file_path The path to the stored YAML file (may be non-existent).
17
+ # @param [Hash] value The initial default value, if the file doesn't exist yet or is malformed
18
+ def initialize(file_path, value={})
19
+ @file_path = file_path
20
+ begin
21
+ self.load
22
+ rescue StandardError => e
23
+ unless e.is_a?(Errno::ENOENT)
24
+ log.warn "Could not load #{file_path}: #{e.inspect}... creating from scratch"
25
+ end
26
+ @value = value
27
+ self.store
28
+ end
21
29
  end
22
- end
23
30
 
24
- # Loads the hash from the file.
25
- def load
26
- @value = YAML.load(File.read(@file_path))
27
- end
31
+ # Loads the hash from the file.
32
+ def load
33
+ @value = from_yaml(File.read(@file_path))
34
+ end
28
35
 
29
- # Saves the hash to the file.
30
- def store
31
- File.write(@file_path, @value.to_yaml)
32
- end
36
+ # Saves the hash to the file.
37
+ def store
38
+ File.write(@file_path, @value.to_yaml)
39
+ end
33
40
 
34
- # Writes a mapping to the hash and stores it on disk.
35
- #
36
- # @param [Object] key The key to use.
37
- # @param [Object] value The value to map the key to.
38
- def []=(key, value)
39
- @value[key] = value
40
- store
41
- end
41
+ # Writes a mapping to the hash and stores it on disk.
42
+ #
43
+ # @param [Object] key The key to use.
44
+ # @param [Object] value The value to map the key to.
45
+ def []=(key, value)
46
+ @value[key] = value
47
+ store
48
+ end
42
49
 
43
- # Reads a mapping from the hash.
44
- #
45
- # @param [Object] key The key to use.
46
- # @return [Object] The value the key is mapped to.
47
- def [](key)
48
- @value[key]
50
+ # Reads a mapping from the hash.
51
+ #
52
+ # @param [Object] key The key to use.
53
+ # @return [Object] The value the key is mapped to.
54
+ def [](key)
55
+ @value[key]
56
+ end
49
57
  end
50
58
  end
@@ -0,0 +1,11 @@
1
+ require 'date'
2
+ require 'yaml'
3
+
4
+ module Drum
5
+ module YAMLUtils
6
+ # Deserializes YAML with a number of standard permitted classes.
7
+ def from_yaml(yaml)
8
+ YAML.load(yaml, permitted_classes: [Date, DateTime, Symbol, Time])
9
+ end
10
+ end
11
+ end
data/lib/drum/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Drum
2
- VERSION = '0.1.14'
2
+ VERSION = '0.2.1'
3
3
  end
data/lib/drum.rb CHANGED
@@ -2,6 +2,7 @@ require 'drum/model/raw_ref'
2
2
  require 'drum/service/applemusic'
3
3
  require 'drum/service/file'
4
4
  require 'drum/service/mock'
5
+ require 'drum/service/music'
5
6
  require 'drum/service/service'
6
7
  require 'drum/service/spotify'
7
8
  require 'drum/service/stdio'
@@ -25,8 +26,8 @@ module Drum
25
26
 
26
27
  @hl = HighLine.new
27
28
 
28
- # Set up .drum directory
29
- @dot_dir = Pathname.new(Dir.home) / '.drum'
29
+ # Set up directory for persisted state
30
+ @dot_dir = Pathname.new(Dir.home) / '.local' / 'state' / 'drum'
30
31
  @dot_dir.mkdir unless @dot_dir.directory?
31
32
 
32
33
  @cache_dir = @dot_dir / 'cache'
@@ -35,6 +36,7 @@ module Drum
35
36
  # Declare services in descending order of parse priority
36
37
  @services = [
37
38
  MockService.new,
39
+ MusicService.new,
38
40
  StdioService.new,
39
41
  AppleMusicService.new(@cache_dir),
40
42
  SpotifyService.new(@cache_dir),
@@ -130,7 +132,6 @@ module Drum
130
132
  method_option :recase_paths,
131
133
  type: :string,
132
134
  enum: ['kebabcase', 'startcase', 'camelcase', 'pascalcase'],
133
- default: false,
134
135
  desc: "Convert each playlist's path segments to a specific case."
135
136
 
136
137
  method_option :flatten,
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: drum
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.14
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - fwcd
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-05-08 00:00:00.000000000 Z
11
+ date: 2024-01-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0.20'
19
+ version: '1.2'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '0.20'
26
+ version: '1.2'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rspotify
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -171,12 +171,14 @@ files:
171
171
  - lib/drum/service/applemusic.rb
172
172
  - lib/drum/service/file.rb
173
173
  - lib/drum/service/mock.rb
174
+ - lib/drum/service/music.rb
174
175
  - lib/drum/service/service.rb
175
176
  - lib/drum/service/spotify.rb
176
177
  - lib/drum/service/stdio.rb
177
178
  - lib/drum/utils/ext.rb
178
179
  - lib/drum/utils/log.rb
179
180
  - lib/drum/utils/persist.rb
181
+ - lib/drum/utils/yaml.rb
180
182
  - lib/drum/version.rb
181
183
  - userdoc/playlist-format.md
182
184
  homepage: https://github.com/fwcd/drum.git