drum 0.2.1 → 0.2.3
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/Gemfile.lock +1 -1
- data/README.md +11 -4
- data/lib/drum/service/spotify.rb +53 -20
- data/lib/drum/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e1cf895018608f7c8ecbf68a5f243228d1569af86b9015c0f178b13f6614cd7c
|
|
4
|
+
data.tar.gz: f52ba7d7d00e81cd8f3f3a1793d637def247beb9c88a58d167d64e9c890ab841
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5c24724da7a46dc623202cef18dc779f9c5fa98d0f34491da5a4445927ee47cf7b0dda2f0372c9ed0d26a6a3a4ec13cfb9f515227009ffb0239d6bb751908038
|
|
7
|
+
data.tar.gz: 806e30e6353f897cd3f163f663769913ccb33f9f5df7b1f629cf97b5258cf3f682b9bbc185906785b570d8f97e9930b74fa837d5fd1a5cc019336e42d5708528
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -29,7 +29,8 @@ The basic usage pattern is always `drum cp [source] [destination]` where `source
|
|
|
29
29
|
* `@stdout`
|
|
30
30
|
* A dash `-`, synonymous with `@stdin` and `@stdout`, depending on usage
|
|
31
31
|
|
|
32
|
-
>
|
|
32
|
+
> [!NOTE]
|
|
33
|
+
> If the source is folder-like, i.e. includes multiple playlists, the destination has to be folder-like too. (The reverse is not true though.)
|
|
33
34
|
|
|
34
35
|
### Examples
|
|
35
36
|
|
|
@@ -59,7 +60,8 @@ Currently, the following music services are supported:
|
|
|
59
60
|
* Apple Music
|
|
60
61
|
* Local, YAML-based playlists (via stdio or files)
|
|
61
62
|
|
|
62
|
-
>
|
|
63
|
+
> [!NOTE]
|
|
64
|
+
> The tool only processes metadata, not the actual audio files.
|
|
63
65
|
|
|
64
66
|
## Development
|
|
65
67
|
|
|
@@ -67,11 +69,13 @@ After checking out the repo, run `bin/setup` (or `bundle install`) to install de
|
|
|
67
69
|
|
|
68
70
|
To run the application, run `bundle exec bin/drum`. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
|
69
71
|
|
|
70
|
-
>
|
|
72
|
+
> [!IMPORTANT]
|
|
73
|
+
> You may need to run `bundle exec ruby bin/drum` on Windows
|
|
71
74
|
|
|
72
75
|
To package the application into a gem, run `bundle exec rake build`. The built gem should then be located in `pkg`.
|
|
73
76
|
|
|
74
|
-
>
|
|
77
|
+
> [!IMPORTANT]
|
|
78
|
+
> 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
79
|
|
|
76
80
|
To install the gem, run `bundle exec rake install`.
|
|
77
81
|
|
|
@@ -79,6 +83,9 @@ To generate the documentation, run `bundle exec rake yard`.
|
|
|
79
83
|
|
|
80
84
|
To run tests, run `bundle exec rake spec`.
|
|
81
85
|
|
|
86
|
+
> [!TIP]
|
|
87
|
+
> If you wish to use a language server such as Solargraph and code completion isn't working for required gems, you may have to run `yard gems`: https://solargraph.org/guides/troubleshooting
|
|
88
|
+
|
|
82
89
|
### Spotify
|
|
83
90
|
|
|
84
91
|
To use the service integration with Spotify, set the following environment variables:
|
data/lib/drum/service/spotify.rb
CHANGED
|
@@ -31,6 +31,8 @@ module Drum
|
|
|
31
31
|
TO_SPOTIFY_TRACKS_CHUNK_SIZE = 50
|
|
32
32
|
UPLOAD_PLAYLIST_TRACKS_CHUNK_SIZE = 100
|
|
33
33
|
|
|
34
|
+
MAX_PLAYLIST_TRACKS = 10_000
|
|
35
|
+
|
|
34
36
|
CLIENT_ID_VAR = 'SPOTIFY_CLIENT_ID'
|
|
35
37
|
CLIENT_SECRET_VAR = 'SPOTIFY_CLIENT_SECRET'
|
|
36
38
|
|
|
@@ -241,30 +243,37 @@ module Drum
|
|
|
241
243
|
# Download helpers
|
|
242
244
|
|
|
243
245
|
def all_sp_library_playlists(offset: 0)
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
[]
|
|
246
|
+
all_sp_playlists = []
|
|
247
|
+
while !(sp_playlists = @me.playlists(limit: PLAYLISTS_CHUNK_SIZE, offset: offset)).empty?
|
|
248
|
+
offset += PLAYLISTS_CHUNK_SIZE
|
|
249
|
+
all_sp_playlists += sp_playlists
|
|
249
250
|
end
|
|
251
|
+
all_sp_playlists
|
|
250
252
|
end
|
|
251
253
|
|
|
252
254
|
def all_sp_playlist_tracks(sp_playlist, offset: 0)
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
255
|
+
all_sp_tracks = []
|
|
256
|
+
while !(sp_tracks = sp_playlist.tracks(limit: TRACKS_CHUNK_SIZE, offset: offset)).empty?
|
|
257
|
+
offset += TRACKS_CHUNK_SIZE
|
|
258
|
+
all_sp_tracks += sp_tracks
|
|
259
|
+
if offset > sp_playlist.total + TRACKS_CHUNK_SIZE
|
|
260
|
+
log.warn "Truncating playlist '#{sp_playlist.name}' at #{offset}, which strangely seems to yield more tracks than its length of #{sp_playlist.total} would suggest."
|
|
261
|
+
break
|
|
262
|
+
elsif offset > MAX_PLAYLIST_TRACKS
|
|
263
|
+
log.warn "Truncating playlist '#{sp_playlist.name}' at #{offset}, since it exceeds the maximum of #{MAX_PLAYLIST_TRACKS} tracks."
|
|
264
|
+
break
|
|
265
|
+
end
|
|
258
266
|
end
|
|
267
|
+
all_sp_tracks
|
|
259
268
|
end
|
|
260
269
|
|
|
261
270
|
def all_sp_library_tracks(offset: 0)
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
[]
|
|
271
|
+
all_sp_tracks = []
|
|
272
|
+
while !(sp_tracks = @me.saved_tracks(limit: SAVED_TRACKS_CHUNKS_SIZE, offset: offset)).empty?
|
|
273
|
+
offset += SAVED_TRACKS_CHUNKS_SIZE
|
|
274
|
+
all_sp_tracks += sp_tracks
|
|
267
275
|
end
|
|
276
|
+
all_sp_tracks
|
|
268
277
|
end
|
|
269
278
|
|
|
270
279
|
def extract_sp_features(sp_track)
|
|
@@ -555,11 +564,35 @@ module Drum
|
|
|
555
564
|
log.info 'Fetching playlists...'
|
|
556
565
|
Enumerator.new(sp_playlists.length) do |enum|
|
|
557
566
|
sp_playlists.each do |sp_playlist|
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
log.info "
|
|
567
|
+
# These playlists seem to cause trouble for some reason, by either
|
|
568
|
+
# 404ing or by returning seemingly endless amounts of tracks, so
|
|
569
|
+
# we'll ignore them for now...
|
|
570
|
+
if sp_playlist.name.start_with?('Your Top Songs')
|
|
571
|
+
log.info "Skipping '#{sp_playlist.name}'"
|
|
572
|
+
next
|
|
573
|
+
end
|
|
574
|
+
|
|
575
|
+
3.times do |attempt|
|
|
576
|
+
begin
|
|
577
|
+
if attempt > 0
|
|
578
|
+
log.info "Attempt \##{attempt + 1} to download '#{sp_playlist.name}'..."
|
|
579
|
+
end
|
|
580
|
+
new_playlist = self.from_sp_playlist(sp_playlist)
|
|
581
|
+
enum.yield new_playlist
|
|
582
|
+
break
|
|
583
|
+
rescue RestClient::TooManyRequests => e
|
|
584
|
+
seconds = e.response.headers[:retry_after]&.to_f || 0.5
|
|
585
|
+
if seconds <= 300
|
|
586
|
+
log.warn "Got 429 Too Many Requests while downloading '#{sp_playlist.name}', retrying in #{seconds} seconds..."
|
|
587
|
+
sleep seconds
|
|
588
|
+
else
|
|
589
|
+
log.error "Got 429 Too Many Requests while downloading '#{sp_playlist.name}' with a too large retry time of #{seconds} seconds"
|
|
590
|
+
raise
|
|
591
|
+
end
|
|
592
|
+
rescue StandardError => e
|
|
593
|
+
log.warn "Could not download playlist '#{sp_playlist.name}': #{e}"
|
|
594
|
+
break
|
|
595
|
+
end
|
|
563
596
|
end
|
|
564
597
|
end
|
|
565
598
|
end
|
data/lib/drum/version.rb
CHANGED
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.2.
|
|
4
|
+
version: 0.2.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- fwcd
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2024-
|
|
11
|
+
date: 2024-02-26 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: thor
|