spotify-to-mp3 0.6.1 → 0.7.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 +7 -0
- data/Gemfile.lock +46 -8
- data/README.md +31 -2
- data/lib/spotify_to_mp3/app.rb +64 -21
- data/lib/spotify_to_mp3/app/download_progress_bar.rb +34 -0
- data/lib/spotify_to_mp3/app/{stream_track_ids.rb → stream_queries.rb} +5 -5
- data/lib/spotify_to_mp3/dependency_container.rb +10 -4
- data/lib/spotify_to_mp3/grooveshark.rb +18 -6
- data/lib/spotify_to_mp3/logger.rb +31 -0
- data/lib/spotify_to_mp3/query_resolver.rb +38 -0
- data/lib/spotify_to_mp3/spotify.rb +30 -6
- data/lib/spotify_to_mp3/spotify/album.rb +13 -0
- data/lib/spotify_to_mp3/spotify/track.rb +4 -4
- data/spec/app/{file_track_ids_spec.rb → stream_queries_spec.rb} +3 -3
- data/spec/logger_spec.rb +27 -0
- data/spec/query_resolver_spec.rb +41 -0
- data/spec/spotify_spec.rb +38 -4
- data/spotify-to-mp3.gemspec +4 -1
- metadata +68 -34
- data/lib/spotify_to_mp3/track_id_resolver.rb +0 -28
- data/spec/track_id_resolver_spec.rb +0 -24
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 3e09cd40e8d3fd9fa8a9005348f187a7f301f613
|
4
|
+
data.tar.gz: 48170d9318b1a5bdb7b76abeb449cf6d97a523a6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7c07693aa826b648138bfdd7a6e0e1702f5c57844e19435c70768278850b3cae235c9e8e707d8425aa312a367b0b462ec25bea1cdb95a1c9a36d2db605d37a1e
|
7
|
+
data.tar.gz: 237746ec5370e849a32020cb0a55135f02b51f9425b024c52311049c88ede37b7e8d9ae7c27364371aa6aa550bd9955d0fc0b40cddfd3f2f21a71e1c57c19973
|
data/Gemfile.lock
CHANGED
@@ -1,28 +1,60 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
spotify-to-mp3 (0.6.
|
4
|
+
spotify-to-mp3 (0.6.1)
|
5
5
|
colorize
|
6
6
|
grooveshark
|
7
7
|
json_pure
|
8
8
|
rest-client
|
9
|
+
rspotify
|
10
|
+
ruby-progressbar
|
9
11
|
|
10
12
|
GEM
|
11
13
|
remote: https://rubygems.org/
|
12
14
|
specs:
|
13
|
-
|
15
|
+
coderay (1.1.0)
|
16
|
+
colorize (0.7.5)
|
14
17
|
diff-lcs (1.2.5)
|
15
|
-
|
18
|
+
faraday (0.9.1)
|
19
|
+
multipart-post (>= 1.2, < 3)
|
20
|
+
grooveshark (0.2.12)
|
16
21
|
json (>= 1.4.6)
|
17
22
|
rest-client (>= 1.5.1)
|
18
23
|
uuid (~> 2.0)
|
19
|
-
|
20
|
-
|
24
|
+
hashie (3.3.2)
|
25
|
+
json (1.8.2)
|
26
|
+
json_pure (1.8.2)
|
27
|
+
jwt (1.2.0)
|
21
28
|
macaddr (1.7.1)
|
22
29
|
systemu (~> 2.6.2)
|
23
|
-
|
24
|
-
|
25
|
-
|
30
|
+
method_source (0.8.2)
|
31
|
+
mime-types (2.4.3)
|
32
|
+
multi_json (1.10.1)
|
33
|
+
multi_xml (0.5.5)
|
34
|
+
multipart-post (2.0.0)
|
35
|
+
netrc (0.10.2)
|
36
|
+
oauth2 (1.0.0)
|
37
|
+
faraday (>= 0.8, < 0.10)
|
38
|
+
jwt (~> 1.0)
|
39
|
+
multi_json (~> 1.3)
|
40
|
+
multi_xml (~> 0.5)
|
41
|
+
rack (~> 1.2)
|
42
|
+
omniauth (1.2.2)
|
43
|
+
hashie (>= 1.2, < 4)
|
44
|
+
rack (~> 1.0)
|
45
|
+
omniauth-oauth2 (1.2.0)
|
46
|
+
faraday (>= 0.8, < 0.10)
|
47
|
+
multi_json (~> 1.3)
|
48
|
+
oauth2 (~> 1.0)
|
49
|
+
omniauth (~> 1.2)
|
50
|
+
pry (0.10.1)
|
51
|
+
coderay (~> 1.1.0)
|
52
|
+
method_source (~> 0.8.1)
|
53
|
+
slop (~> 3.4)
|
54
|
+
rack (1.6.0)
|
55
|
+
rest-client (1.7.2)
|
56
|
+
mime-types (>= 1.16, < 3.0)
|
57
|
+
netrc (~> 0.7)
|
26
58
|
rspec (2.14.1)
|
27
59
|
rspec-core (~> 2.14.0)
|
28
60
|
rspec-expectations (~> 2.14.0)
|
@@ -31,6 +63,11 @@ GEM
|
|
31
63
|
rspec-expectations (2.14.5)
|
32
64
|
diff-lcs (>= 1.1.3, < 2.0)
|
33
65
|
rspec-mocks (2.14.6)
|
66
|
+
rspotify (1.11.0)
|
67
|
+
omniauth-oauth2 (~> 1.1)
|
68
|
+
rest-client (~> 1.7)
|
69
|
+
ruby-progressbar (1.7.1)
|
70
|
+
slop (3.6.0)
|
34
71
|
systemu (2.6.4)
|
35
72
|
uuid (2.3.7)
|
36
73
|
macaddr (~> 1.0)
|
@@ -39,5 +76,6 @@ PLATFORMS
|
|
39
76
|
ruby
|
40
77
|
|
41
78
|
DEPENDENCIES
|
79
|
+
pry
|
42
80
|
rspec
|
43
81
|
spotify-to-mp3!
|
data/README.md
CHANGED
@@ -1,6 +1,17 @@
|
|
1
1
|
# Spotify to MP3
|
2
2
|
|
3
|
-
A simple command line utility to download MP3 files of Spotify tracks
|
3
|
+
A simple command line utility to download MP3 files of Spotify tracks. *Note those files are downloaded from Grooveshark, not from Spotify itself.*
|
4
|
+
|
5
|
+
---
|
6
|
+
|
7
|
+
**THIS PROJECT IS IN MAINTENANCE MODE**
|
8
|
+
|
9
|
+
Time is finite and these days I'm focusing on other projects. Hope you understand.
|
10
|
+
|
11
|
+
- I'll keep working on the occasional bug fixing and making sure it still works on the supported platforms.
|
12
|
+
- Most probably I won't add any new feature. [Feature requests](https://github.com/frosas/spotify-to-mp3/labels/Feature) will be kept open in case somebody wants to contribute with a pull request.
|
13
|
+
|
14
|
+
---
|
4
15
|
|
5
16
|
## Installation
|
6
17
|
|
@@ -58,6 +69,13 @@ and drag the songs from the Spotify app to the terminal.
|
|
58
69
|
|
59
70
|
## Changelog
|
60
71
|
|
72
|
+
2015-01-25
|
73
|
+
|
74
|
+
- Accept album URI's
|
75
|
+
- Download progress bar
|
76
|
+
|
77
|
+
A big thanks to @dulakm for such great contributions!
|
78
|
+
|
61
79
|
2014-05-05
|
62
80
|
|
63
81
|
- Accept track IDs from stdin
|
@@ -78,7 +96,18 @@ and drag the songs from the Spotify app to the terminal.
|
|
78
96
|
|
79
97
|
- Both Spotify URLs and plain song names are accepted
|
80
98
|
|
81
|
-
##
|
99
|
+
## Development
|
100
|
+
|
101
|
+
Install Ruby.
|
102
|
+
|
103
|
+
```bash
|
104
|
+
$ gem install bundler
|
105
|
+
$ bundle install
|
106
|
+
```
|
107
|
+
|
108
|
+
Do some coding.
|
109
|
+
|
110
|
+
Run the tests:
|
82
111
|
|
83
112
|
```bash
|
84
113
|
$ rspec
|
data/lib/spotify_to_mp3/app.rb
CHANGED
@@ -1,39 +1,82 @@
|
|
1
|
-
require 'colorize'
|
2
1
|
require 'fileutils'
|
3
|
-
require 'spotify_to_mp3/app/
|
2
|
+
require 'spotify_to_mp3/app/stream_queries'
|
3
|
+
require 'spotify_to_mp3/app/download_progress_bar'
|
4
4
|
|
5
5
|
module SpotifyToMp3
|
6
6
|
class App
|
7
|
-
def initialize(
|
8
|
-
@
|
7
|
+
def initialize(query_resolver, grooveshark, logger)
|
8
|
+
@query_resolver = query_resolver
|
9
9
|
@grooveshark = grooveshark
|
10
|
+
@logger = logger
|
10
11
|
end
|
11
12
|
|
12
13
|
def run
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
14
|
+
tracks_to_download = []
|
15
|
+
|
16
|
+
StreamQueries.new(ARGF).each do |query|
|
17
|
+
@logger.info "Resolving \"#{query}\""
|
18
|
+
tracks = @query_resolver.resolve(query)
|
17
19
|
|
18
|
-
|
19
|
-
|
20
|
+
tracks.each do |track|
|
21
|
+
begin
|
22
|
+
@logger.info "Searching \"#{track}\" on Grooveshark"
|
23
|
+
grooveshark_track = @grooveshark.get_track(track.grooveshark_query)
|
20
24
|
|
21
|
-
|
22
|
-
|
23
|
-
|
25
|
+
if File.exists?(grooveshark_track.filename)
|
26
|
+
# To know about songs no longer in download list
|
27
|
+
FileUtils.touch grooveshark_track.filename
|
24
28
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
+
@logger.info "Skipping \"#{grooveshark_track}\", it already exists"
|
30
|
+
else
|
31
|
+
@logger.info "\"#{grooveshark_track}\" will be downloaded"
|
32
|
+
tracks_to_download << grooveshark_track
|
33
|
+
end
|
34
|
+
rescue Exception => exception # For some reason without the "Exception" it is ignored
|
35
|
+
@logger.error "\"#{track}\" won't be downloaded - #{exception.message}"
|
36
|
+
# Continue with the next track
|
29
37
|
end
|
30
|
-
rescue Exception => exception # For some reason without the "Exception" it is ignored
|
31
|
-
puts exception.message.red
|
32
|
-
# Continue with the next track
|
33
38
|
end
|
34
39
|
end
|
40
|
+
|
41
|
+
@logger.info("\n")
|
42
|
+
|
43
|
+
download tracks_to_download
|
35
44
|
rescue
|
36
|
-
|
45
|
+
@logger.error "#{$!}"
|
37
46
|
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def download(tracks)
|
51
|
+
if tracks.empty?
|
52
|
+
@logger.info "Nothing to download"
|
53
|
+
return
|
54
|
+
end
|
55
|
+
|
56
|
+
@logger.info "Downloading tracks..."
|
57
|
+
tracks.each_with_index do |track, i|
|
58
|
+
begin
|
59
|
+
progress_bar = nil
|
60
|
+
@grooveshark.download(
|
61
|
+
track: track,
|
62
|
+
on_response: Proc.new { |response|
|
63
|
+
progress_bar = DownloadProgressBar.new(
|
64
|
+
track: track,
|
65
|
+
track_number: i.next,
|
66
|
+
track_size: response['content-length'].to_i,
|
67
|
+
total_tracks: tracks.length
|
68
|
+
)
|
69
|
+
},
|
70
|
+
on_body_chunk: Proc.new { |chunk|
|
71
|
+
progress_bar.progress += chunk.length
|
72
|
+
}
|
73
|
+
)
|
74
|
+
progress_bar.finish
|
75
|
+
rescue Exception => exception
|
76
|
+
@logger.error exception.message
|
77
|
+
end
|
78
|
+
end
|
79
|
+
@logger.success "Download complete"
|
80
|
+
end
|
38
81
|
end
|
39
82
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'ruby-progressbar'
|
2
|
+
require 'forwardable'
|
3
|
+
|
4
|
+
module SpotifyToMp3
|
5
|
+
class App
|
6
|
+
class DownloadProgressBar
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
def_delegators :@progress_bar, :progress, :progress=, :finish
|
10
|
+
|
11
|
+
def initialize(options)
|
12
|
+
track = options.fetch(:track)
|
13
|
+
track_number = options.fetch(:track_number)
|
14
|
+
track_size = options.fetch(:track_size)
|
15
|
+
total_tracks = options.fetch(:total_tracks)
|
16
|
+
|
17
|
+
@progress_bar = ProgressBar.create(
|
18
|
+
title: cut_title("[#{track_number}/#{total_tracks}] #{track}"),
|
19
|
+
total: track_size,
|
20
|
+
format: "%t %p%% [%B] %E"
|
21
|
+
)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def cut_title(title)
|
27
|
+
win_half = $stdout.winsize[1] / 2
|
28
|
+
cut_title = title[0..win_half.pred].ljust win_half
|
29
|
+
cut_title.gsub(/.{3}$/, '...') if title.length > win_half
|
30
|
+
cut_title
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module SpotifyToMp3
|
2
2
|
class App
|
3
|
-
class
|
3
|
+
class StreamQueries
|
4
4
|
include Enumerable
|
5
5
|
|
6
6
|
def initialize(stream)
|
@@ -8,10 +8,10 @@ module SpotifyToMp3
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def each
|
11
|
-
@stream.each do |
|
12
|
-
|
13
|
-
next if
|
14
|
-
yield
|
11
|
+
@stream.each do |query|
|
12
|
+
query.strip!
|
13
|
+
next if query.empty?
|
14
|
+
yield query
|
15
15
|
end
|
16
16
|
end
|
17
17
|
end
|
@@ -2,20 +2,26 @@ require 'grooveshark'
|
|
2
2
|
require 'spotify_to_mp3/app'
|
3
3
|
require 'spotify_to_mp3/grooveshark'
|
4
4
|
require 'spotify_to_mp3/spotify'
|
5
|
-
require 'spotify_to_mp3/
|
5
|
+
require 'spotify_to_mp3/query_resolver'
|
6
|
+
require 'spotify_to_mp3/logger'
|
6
7
|
|
7
8
|
module SpotifyToMp3
|
8
9
|
class DependencyContainer
|
9
|
-
def
|
10
|
-
@
|
10
|
+
def query_resolver
|
11
|
+
@query_resolver ||= QueryResolver.new(Spotify.new)
|
11
12
|
end
|
12
13
|
|
13
14
|
def grooveshark
|
14
15
|
@grooveshark ||= Grooveshark.new(::Grooveshark::Client.new)
|
15
16
|
end
|
16
17
|
|
18
|
+
def logger
|
19
|
+
@logger ||= Logger.new($stdout)
|
20
|
+
end
|
21
|
+
|
17
22
|
def app
|
18
|
-
@app ||= App.new(
|
23
|
+
@app ||= App.new(query_resolver, grooveshark, logger)
|
19
24
|
end
|
25
|
+
|
20
26
|
end
|
21
27
|
end
|
@@ -1,5 +1,4 @@
|
|
1
|
-
require '
|
2
|
-
require 'rest-client'
|
1
|
+
require 'net/http'
|
3
2
|
require 'spotify_to_mp3/grooveshark/track'
|
4
3
|
|
5
4
|
module SpotifyToMp3
|
@@ -13,10 +12,23 @@ module SpotifyToMp3
|
|
13
12
|
Track.new(client_track)
|
14
13
|
end
|
15
14
|
|
16
|
-
def download(
|
17
|
-
|
18
|
-
|
19
|
-
|
15
|
+
def download(options)
|
16
|
+
track = options.fetch(:track)
|
17
|
+
on_response = options.fetch(:on_response)
|
18
|
+
on_body_chunk = options.fetch(:on_body_chunk)
|
19
|
+
|
20
|
+
url = URI(@client.get_song_url(track.client_track))
|
21
|
+
Net::HTTP.start(url.host) do |http|
|
22
|
+
http.request_post("#{url.path}?#{url.query}", "") do |response|
|
23
|
+
on_response.call(response)
|
24
|
+
File.open(track.filename, 'w') do |f|
|
25
|
+
response.read_body do |chunk|
|
26
|
+
on_body_chunk.call(chunk)
|
27
|
+
f.write(chunk)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
20
32
|
end
|
21
33
|
end
|
22
34
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'colorize'
|
2
|
+
|
3
|
+
module SpotifyToMp3
|
4
|
+
class Logger
|
5
|
+
def initialize(io_stream)
|
6
|
+
@io_stream = io_stream
|
7
|
+
end
|
8
|
+
|
9
|
+
def info(str)
|
10
|
+
@io_stream.puts str
|
11
|
+
end
|
12
|
+
|
13
|
+
def success(str)
|
14
|
+
@io_stream.puts colorize_success(str)
|
15
|
+
end
|
16
|
+
|
17
|
+
def error(str)
|
18
|
+
@io_stream.puts colorize_error(str)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def colorize_success(str)
|
24
|
+
str.green
|
25
|
+
end
|
26
|
+
|
27
|
+
def colorize_error(str)
|
28
|
+
str.red
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'spotify_to_mp3/track'
|
2
|
+
|
3
|
+
module SpotifyToMp3
|
4
|
+
class QueryResolver
|
5
|
+
def initialize(spotify)
|
6
|
+
@spotify = spotify
|
7
|
+
end
|
8
|
+
|
9
|
+
def resolve(query)
|
10
|
+
tracks = []
|
11
|
+
|
12
|
+
if @spotify.track_uri?(query)
|
13
|
+
spotify_track = @spotify.get_track(query)
|
14
|
+
tracks << convert_spotify_track(spotify_track)
|
15
|
+
elsif @spotify.album_uri?(query)
|
16
|
+
spotify_album = @spotify.get_album(query)
|
17
|
+
spotify_album.tracks.each { |track| tracks << convert_spotify_track(track) }
|
18
|
+
else
|
19
|
+
tracks << resolve_plain_track(query)
|
20
|
+
end
|
21
|
+
|
22
|
+
tracks
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def convert_spotify_track(track)
|
28
|
+
description = "#{track.artist} - #{track.name}"
|
29
|
+
grooveshark_query = "artist:\"#{track.artist}\" title:\"#{track.name}\""
|
30
|
+
|
31
|
+
Track.new(description, grooveshark_query)
|
32
|
+
end
|
33
|
+
|
34
|
+
def resolve_plain_track(description)
|
35
|
+
Track.new(description)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -1,17 +1,41 @@
|
|
1
|
-
require '
|
2
|
-
require 'open-uri'
|
1
|
+
require 'rspotify'
|
3
2
|
require 'spotify_to_mp3/spotify/track'
|
3
|
+
require 'spotify_to_mp3/spotify/album'
|
4
4
|
|
5
5
|
module SpotifyToMp3
|
6
6
|
class Spotify
|
7
7
|
def get_track(uri)
|
8
|
-
|
9
|
-
|
10
|
-
Track.new(
|
8
|
+
track_id = parse_id(uri)
|
9
|
+
track = RSpotify::Track.find(track_id)
|
10
|
+
Track.new(track.artists.first.name, track.name)
|
11
11
|
end
|
12
12
|
|
13
|
-
def
|
13
|
+
def get_album(uri)
|
14
|
+
album_id = parse_id(uri)
|
15
|
+
album = RSpotify::Album.find(album_id)
|
16
|
+
|
17
|
+
tracks = []
|
18
|
+
album.tracks.each do |track|
|
19
|
+
tracks << Track.new(album.artists.first.name, track.name)
|
20
|
+
end
|
21
|
+
|
22
|
+
Album.new(album.artists.first.name, album.name, tracks)
|
23
|
+
end
|
24
|
+
|
25
|
+
def track_uri?(uri)
|
14
26
|
uri.start_with?('http://open.spotify.com/track/', 'spotify:track:')
|
15
27
|
end
|
28
|
+
|
29
|
+
def album_uri?(uri)
|
30
|
+
uri.start_with?('http://open.spotify.com/album/', 'spotify:album:')
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def parse_id(uri)
|
36
|
+
id = uri.sub(/.*:/, '')
|
37
|
+
id = id.sub(/.*\//, '') if uri.start_with?('http')
|
38
|
+
id
|
39
|
+
end
|
16
40
|
end
|
17
41
|
end
|
@@ -1,11 +1,11 @@
|
|
1
1
|
module SpotifyToMp3
|
2
2
|
class Spotify
|
3
3
|
class Track
|
4
|
-
attr_reader :
|
4
|
+
attr_reader :artist, :name
|
5
5
|
|
6
|
-
def initialize(
|
7
|
-
@
|
8
|
-
@
|
6
|
+
def initialize(artist, name)
|
7
|
+
@artist = artist
|
8
|
+
@name = name
|
9
9
|
end
|
10
10
|
end
|
11
11
|
end
|
@@ -1,8 +1,8 @@
|
|
1
|
-
require 'spotify_to_mp3/app/
|
1
|
+
require 'spotify_to_mp3/app/stream_queries'
|
2
2
|
require 'tempfile'
|
3
3
|
|
4
4
|
module SpotifyToMp3
|
5
|
-
describe App::
|
5
|
+
describe App::StreamQueries do
|
6
6
|
it "reads lines" do
|
7
7
|
open_test_file("1\n2\n3") do |ids|
|
8
8
|
ids.count.should == 3
|
@@ -25,7 +25,7 @@ module SpotifyToMp3
|
|
25
25
|
Tempfile.open('tracks') do |file|
|
26
26
|
file.write(content)
|
27
27
|
file.rewind
|
28
|
-
yield App::
|
28
|
+
yield App::StreamQueries.new(file)
|
29
29
|
end
|
30
30
|
end
|
31
31
|
end
|
data/spec/logger_spec.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spotify_to_mp3/logger'
|
2
|
+
|
3
|
+
describe SpotifyToMp3::Logger do
|
4
|
+
let(:io_stream) { double }
|
5
|
+
let(:logger) { described_class.new(io_stream) }
|
6
|
+
|
7
|
+
describe '#info' do
|
8
|
+
it 'prints message to stream' do
|
9
|
+
message = 'Hello world'
|
10
|
+
|
11
|
+
expect(io_stream).to receive(:puts).with(message)
|
12
|
+
|
13
|
+
logger.info message
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '#error' do
|
18
|
+
it 'prints colorized message to stream' do
|
19
|
+
message = 'Hello world'
|
20
|
+
colorized_message = "\e[0;31;49m#{message}\e[0m" # red
|
21
|
+
|
22
|
+
expect(io_stream).to receive(:puts).with(colorized_message)
|
23
|
+
|
24
|
+
logger.error message
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spotify_to_mp3/dependency_container'
|
2
|
+
|
3
|
+
module SpotifyToMp3
|
4
|
+
describe QueryResolver do
|
5
|
+
before(:each) do
|
6
|
+
@resolver = DependencyContainer.new.query_resolver
|
7
|
+
end
|
8
|
+
|
9
|
+
it "resolves Spotify track HTTP URLs" do
|
10
|
+
tracks = @resolver.resolve('http://open.spotify.com/track/0qgiFuYhYuwtFXEwYakddE')
|
11
|
+
tracks.length.should == 1
|
12
|
+
tracks.first.to_s.should == "Cake - I Will Survive"
|
13
|
+
end
|
14
|
+
|
15
|
+
it "resolves Spotify track URIs" do
|
16
|
+
tracks = @resolver.resolve('spotify:track:0qgiFuYhYuwtFXEwYakddE')
|
17
|
+
tracks.length.should == 1
|
18
|
+
tracks.first.to_s.should == "Cake - I Will Survive"
|
19
|
+
end
|
20
|
+
|
21
|
+
it "resolves Spotify album HTTP URLs" do
|
22
|
+
tracks = @resolver.resolve('http://open.spotify.com/album/7wq5vhqramVPzjArlmr70k')
|
23
|
+
tracks.length.should == 2
|
24
|
+
tracks[0].to_s.should == "Arctic Monkeys - Suck It and See"
|
25
|
+
tracks[1].to_s.should == "Arctic Monkeys - Evil Twin"
|
26
|
+
end
|
27
|
+
|
28
|
+
it "resolves Spotify album URIs" do
|
29
|
+
tracks = @resolver.resolve('spotify:album:7wq5vhqramVPzjArlmr70k')
|
30
|
+
tracks.length.should == 2
|
31
|
+
tracks[0].to_s.should == "Arctic Monkeys - Suck It and See"
|
32
|
+
tracks[1].to_s.should == "Arctic Monkeys - Evil Twin"
|
33
|
+
end
|
34
|
+
|
35
|
+
it "resolves track titles" do
|
36
|
+
tracks = @resolver.resolve('Cake - I Will Survive')
|
37
|
+
tracks.length.should == 1
|
38
|
+
tracks.first.to_s.should == "Cake - I Will Survive"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/spec/spotify_spec.rb
CHANGED
@@ -24,17 +24,51 @@ module SpotifyToMp3
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
-
context
|
27
|
+
context '#get_album' do
|
28
|
+
it "resolves HTTP URLs" do
|
29
|
+
album = @spotify.get_album('http://open.spotify.com/album/7wq5vhqramVPzjArlmr70k')
|
30
|
+
album.tracks.length.should == 2
|
31
|
+
album.name.should == "Suck It and See"
|
32
|
+
album.artist.should == "Arctic Monkeys"
|
33
|
+
end
|
34
|
+
|
35
|
+
it "resolves Spotify URIs" do
|
36
|
+
album = @spotify.get_album('spotify:album:7wq5vhqramVPzjArlmr70k')
|
37
|
+
album.tracks.length.should == 2
|
38
|
+
album.name.should == "Suck It and See"
|
39
|
+
album.artist.should == "Arctic Monkeys"
|
40
|
+
end
|
41
|
+
|
42
|
+
it "fails on nonexistent URI" do
|
43
|
+
expect { @spotify.get_album('spotify:album:not-found') }.to raise_error
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context "#track_uri?" do
|
48
|
+
it "accepts HTTP URLs" do
|
49
|
+
@spotify.track_uri?('http://open.spotify.com/track/0qgiFuYhYuwtFXEwYakddE').should be_true
|
50
|
+
end
|
51
|
+
|
52
|
+
it "accepts Spotify URIs" do
|
53
|
+
@spotify.track_uri?('spotify:track:0qgiFuYhYuwtFXEwYakddE').should be_true
|
54
|
+
end
|
55
|
+
|
56
|
+
it "refuses other URIs" do
|
57
|
+
@spotify.track_uri?('123').should be_false
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context "#album_uri?" do
|
28
62
|
it "accepts HTTP URLs" do
|
29
|
-
@spotify.
|
63
|
+
@spotify.album_uri?('http://open.spotify.com/album/7wq5vhqramVPzjArlmr70k').should be_true
|
30
64
|
end
|
31
65
|
|
32
66
|
it "accepts Spotify URIs" do
|
33
|
-
@spotify.
|
67
|
+
@spotify.album_uri?('spotify:album:7wq5vhqramVPzjArlmr70k').should be_true
|
34
68
|
end
|
35
69
|
|
36
70
|
it "refuses other URIs" do
|
37
|
-
@spotify.
|
71
|
+
@spotify.album_uri?('123').should be_false
|
38
72
|
end
|
39
73
|
end
|
40
74
|
end
|
data/spotify-to-mp3.gemspec
CHANGED
@@ -2,17 +2,20 @@ Gem::Specification.new do |gem|
|
|
2
2
|
gem.name = 'spotify-to-mp3'
|
3
3
|
gem.summary = 'Spotify to MP3'
|
4
4
|
gem.description = 'Download MP3 files of your Spotify tracks from Grooveshark'
|
5
|
-
gem.version = '0.
|
5
|
+
gem.version = '0.7.0'
|
6
6
|
gem.author = 'Francesc Rosàs'
|
7
7
|
gem.email = 'francescrosasbosque@gmail.com'
|
8
8
|
gem.homepage = 'https://github.com/frosas/spotify-to-mp3'
|
9
9
|
|
10
|
+
gem.add_runtime_dependency 'rspotify'
|
10
11
|
gem.add_runtime_dependency 'grooveshark'
|
11
12
|
gem.add_runtime_dependency 'colorize'
|
12
13
|
gem.add_runtime_dependency 'rest-client'
|
13
14
|
gem.add_runtime_dependency 'json_pure'
|
15
|
+
gem.add_runtime_dependency 'ruby-progressbar'
|
14
16
|
|
15
17
|
gem.add_development_dependency 'rspec'
|
18
|
+
gem.add_development_dependency 'pry'
|
16
19
|
|
17
20
|
gem.files = `git ls-files`.split("\n")
|
18
21
|
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
metadata
CHANGED
@@ -1,94 +1,125 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spotify-to-mp3
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.7.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Francesc Rosàs
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2015-01-26 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspotify
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
14
27
|
- !ruby/object:Gem::Dependency
|
15
28
|
name: grooveshark
|
16
29
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
30
|
requirements:
|
19
|
-
- -
|
31
|
+
- - ">="
|
20
32
|
- !ruby/object:Gem::Version
|
21
33
|
version: '0'
|
22
34
|
type: :runtime
|
23
35
|
prerelease: false
|
24
36
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
37
|
requirements:
|
27
|
-
- -
|
38
|
+
- - ">="
|
28
39
|
- !ruby/object:Gem::Version
|
29
40
|
version: '0'
|
30
41
|
- !ruby/object:Gem::Dependency
|
31
42
|
name: colorize
|
32
43
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
44
|
requirements:
|
35
|
-
- -
|
45
|
+
- - ">="
|
36
46
|
- !ruby/object:Gem::Version
|
37
47
|
version: '0'
|
38
48
|
type: :runtime
|
39
49
|
prerelease: false
|
40
50
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
51
|
requirements:
|
43
|
-
- -
|
52
|
+
- - ">="
|
44
53
|
- !ruby/object:Gem::Version
|
45
54
|
version: '0'
|
46
55
|
- !ruby/object:Gem::Dependency
|
47
56
|
name: rest-client
|
48
57
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
58
|
requirements:
|
51
|
-
- -
|
59
|
+
- - ">="
|
52
60
|
- !ruby/object:Gem::Version
|
53
61
|
version: '0'
|
54
62
|
type: :runtime
|
55
63
|
prerelease: false
|
56
64
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
65
|
requirements:
|
59
|
-
- -
|
66
|
+
- - ">="
|
60
67
|
- !ruby/object:Gem::Version
|
61
68
|
version: '0'
|
62
69
|
- !ruby/object:Gem::Dependency
|
63
70
|
name: json_pure
|
64
71
|
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
72
|
requirements:
|
67
|
-
- -
|
73
|
+
- - ">="
|
68
74
|
- !ruby/object:Gem::Version
|
69
75
|
version: '0'
|
70
76
|
type: :runtime
|
71
77
|
prerelease: false
|
72
78
|
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
79
|
requirements:
|
75
|
-
- -
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: ruby-progressbar
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
76
95
|
- !ruby/object:Gem::Version
|
77
96
|
version: '0'
|
78
97
|
- !ruby/object:Gem::Dependency
|
79
98
|
name: rspec
|
80
99
|
requirement: !ruby/object:Gem::Requirement
|
81
|
-
none: false
|
82
100
|
requirements:
|
83
|
-
- -
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: pry
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
84
116
|
- !ruby/object:Gem::Version
|
85
117
|
version: '0'
|
86
118
|
type: :development
|
87
119
|
prerelease: false
|
88
120
|
version_requirements: !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
121
|
requirements:
|
91
|
-
- -
|
122
|
+
- - ">="
|
92
123
|
- !ruby/object:Gem::Version
|
93
124
|
version: '0'
|
94
125
|
description: Download MP3 files of your Spotify tracks from Grooveshark
|
@@ -98,48 +129,51 @@ executables:
|
|
98
129
|
extensions: []
|
99
130
|
extra_rdoc_files: []
|
100
131
|
files:
|
101
|
-
- .rspec
|
132
|
+
- ".rspec"
|
102
133
|
- Gemfile
|
103
134
|
- Gemfile.lock
|
104
135
|
- LICENSE
|
105
136
|
- README.md
|
106
137
|
- bin/spotify-to-mp3
|
107
138
|
- lib/spotify_to_mp3/app.rb
|
108
|
-
- lib/spotify_to_mp3/app/
|
139
|
+
- lib/spotify_to_mp3/app/download_progress_bar.rb
|
140
|
+
- lib/spotify_to_mp3/app/stream_queries.rb
|
109
141
|
- lib/spotify_to_mp3/dependency_container.rb
|
110
142
|
- lib/spotify_to_mp3/grooveshark.rb
|
111
143
|
- lib/spotify_to_mp3/grooveshark/track.rb
|
144
|
+
- lib/spotify_to_mp3/logger.rb
|
145
|
+
- lib/spotify_to_mp3/query_resolver.rb
|
112
146
|
- lib/spotify_to_mp3/spotify.rb
|
147
|
+
- lib/spotify_to_mp3/spotify/album.rb
|
113
148
|
- lib/spotify_to_mp3/spotify/track.rb
|
114
149
|
- lib/spotify_to_mp3/track.rb
|
115
|
-
-
|
116
|
-
- spec/app/file_track_ids_spec.rb
|
150
|
+
- spec/app/stream_queries_spec.rb
|
117
151
|
- spec/grooveshark_spec.rb
|
152
|
+
- spec/logger_spec.rb
|
153
|
+
- spec/query_resolver_spec.rb
|
118
154
|
- spec/spotify_spec.rb
|
119
|
-
- spec/track_id_resolver_spec.rb
|
120
155
|
- spotify-to-mp3.gemspec
|
121
156
|
homepage: https://github.com/frosas/spotify-to-mp3
|
122
157
|
licenses: []
|
158
|
+
metadata: {}
|
123
159
|
post_install_message:
|
124
160
|
rdoc_options: []
|
125
161
|
require_paths:
|
126
162
|
- lib
|
127
163
|
required_ruby_version: !ruby/object:Gem::Requirement
|
128
|
-
none: false
|
129
164
|
requirements:
|
130
|
-
- -
|
165
|
+
- - ">="
|
131
166
|
- !ruby/object:Gem::Version
|
132
167
|
version: '0'
|
133
168
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
134
|
-
none: false
|
135
169
|
requirements:
|
136
|
-
- -
|
170
|
+
- - ">="
|
137
171
|
- !ruby/object:Gem::Version
|
138
172
|
version: '0'
|
139
173
|
requirements: []
|
140
174
|
rubyforge_project:
|
141
|
-
rubygems_version:
|
175
|
+
rubygems_version: 2.4.5
|
142
176
|
signing_key:
|
143
|
-
specification_version:
|
177
|
+
specification_version: 4
|
144
178
|
summary: Spotify to MP3
|
145
179
|
test_files: []
|
@@ -1,28 +0,0 @@
|
|
1
|
-
require 'spotify_to_mp3/track'
|
2
|
-
|
3
|
-
module SpotifyToMp3
|
4
|
-
class TrackIdResolver
|
5
|
-
def initialize(spotify)
|
6
|
-
@spotify = spotify
|
7
|
-
end
|
8
|
-
|
9
|
-
def resolve(track_id)
|
10
|
-
resolve_spotify_track(track_id) || resolve_plain_track(track_id)
|
11
|
-
end
|
12
|
-
|
13
|
-
private
|
14
|
-
|
15
|
-
def resolve_spotify_track(id)
|
16
|
-
if @spotify.resolvable_uri?(id)
|
17
|
-
spotify_track = @spotify.get_track(id)
|
18
|
-
description = "#{spotify_track.artist} - #{spotify_track.name}"
|
19
|
-
grooveshark_query = "artist:\"#{spotify_track.artist}\" title:\"#{spotify_track.name}\""
|
20
|
-
Track.new(description, grooveshark_query)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def resolve_plain_track(id)
|
25
|
-
Track.new(id)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
@@ -1,24 +0,0 @@
|
|
1
|
-
require 'spotify_to_mp3/dependency_container'
|
2
|
-
|
3
|
-
module SpotifyToMp3
|
4
|
-
describe TrackIdResolver do
|
5
|
-
before(:each) do
|
6
|
-
@resolver = DependencyContainer.new.track_id_resolver
|
7
|
-
end
|
8
|
-
|
9
|
-
it "resolves Spotify HTTP URLs" do
|
10
|
-
track = @resolver.resolve('http://open.spotify.com/track/0qgiFuYhYuwtFXEwYakddE')
|
11
|
-
track.to_s.should == "Cake - I Will Survive"
|
12
|
-
end
|
13
|
-
|
14
|
-
it "resolves Spotify URIs" do
|
15
|
-
track = @resolver.resolve('spotify:track:0qgiFuYhYuwtFXEwYakddE')
|
16
|
-
track.to_s.should == "Cake - I Will Survive"
|
17
|
-
end
|
18
|
-
|
19
|
-
it "resolves track titles" do
|
20
|
-
track = @resolver.resolve('Cake - I Will Survive')
|
21
|
-
track.to_s.should == "Cake - I Will Survive"
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|