spotify_cli 0.1.1 → 0.1.2
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/lib/spotify_cli/api.rb +59 -60
- data/lib/spotify_cli/app.rb +117 -83
- data/lib/spotify_cli/version.rb +1 -1
- data/lib/spotify_cli.rb +5 -0
- data/spotify_cli.gemspec +1 -0
- metadata +16 -3
- data/lib/helpers/doc.rb +0 -62
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0471a10bcc93c07d50e44f8d8cf461d6c608d269
|
4
|
+
data.tar.gz: 4d9001552b8b6eddb50c72929a20f990ecebdba6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d02251db2948e80df216d0423e1e3d75301167b6291123579814910e3710f06dac38848304269bb89a213eecdcc09bc5fc39cdb9459c5ac03259e7e6fd035e5a
|
7
|
+
data.tar.gz: 558017104ac1d61029fc01df0b904a9a680028be37176d99f04272203c7b44cd4c59242fe26c9457d9afc8702880d6adacb90f68a8d56594e39791da91274e28
|
data/lib/spotify_cli/api.rb
CHANGED
@@ -1,68 +1,56 @@
|
|
1
1
|
require 'spotify_cli/app'
|
2
|
-
require 'helpers/doc'
|
3
2
|
|
4
3
|
module SpotifyCli
|
5
4
|
class Api
|
6
5
|
PLAY = "▶"
|
7
6
|
STOP = "◼"
|
8
|
-
|
9
7
|
SPOTIFY_SEARCH_API = "https://api.spotify.com/v1/search"
|
10
8
|
|
11
9
|
class << self
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
{{command:spotify next}}
|
17
|
-
EOF
|
10
|
+
# Changes to the next song
|
11
|
+
#
|
12
|
+
# Usage:
|
13
|
+
# - spotify next
|
18
14
|
def next
|
19
15
|
puts "Playing next song"
|
20
16
|
SpotifyCli::App.next!
|
21
17
|
end
|
22
18
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
{{command:spotify previous}}
|
28
|
-
EOF
|
19
|
+
# Changes to the previous song
|
20
|
+
#
|
21
|
+
# Usage:
|
22
|
+
# - spotify previous
|
29
23
|
def previous
|
30
24
|
puts "Playing previous song"
|
31
25
|
SpotifyCli::App.prev!
|
32
26
|
end
|
33
27
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
{{command:spotify set_pos 60}}
|
39
|
-
EOF
|
28
|
+
# Sets the position in the song
|
29
|
+
#
|
30
|
+
# Usage:
|
31
|
+
# - spotify set_pos 60
|
40
32
|
def set_pos
|
41
33
|
puts "Setting position to #{ARGV[1]}"
|
42
34
|
SpotifyCli::App.set_pos!(ARGV[1])
|
43
35
|
end
|
44
36
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
{{command:spotify replay}}
|
50
|
-
EOF
|
37
|
+
# Replays the current song
|
38
|
+
#
|
39
|
+
# Usage:
|
40
|
+
# - spotify replay
|
51
41
|
def replay
|
52
42
|
puts "Restarting song"
|
53
43
|
SpotifyCli::App.replay!
|
54
44
|
end
|
55
45
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
{{command:spotify play uri [spotify uri]}}
|
65
|
-
EOF
|
46
|
+
# Play/Pause the current song, or play a specified artist,
|
47
|
+
# track, album, or uri
|
48
|
+
#
|
49
|
+
# Usage:
|
50
|
+
# - spotify play artist [name]
|
51
|
+
# - spotify play track [name]
|
52
|
+
# - spotify play album [name]
|
53
|
+
# - spotify play uri [spotify uri]
|
66
54
|
def play_pause
|
67
55
|
args = ARGV[1..-1]
|
68
56
|
|
@@ -92,25 +80,21 @@ module SpotifyCli
|
|
92
80
|
status
|
93
81
|
end
|
94
82
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
{{command:spotify stop}}
|
101
|
-
EOF
|
83
|
+
# Pause/stop the current song
|
84
|
+
#
|
85
|
+
# Usage:
|
86
|
+
# - spotify pause
|
87
|
+
# - spotify stop
|
102
88
|
def pause
|
103
89
|
SpotifyCli::App.pause!
|
104
90
|
status
|
105
91
|
end
|
106
92
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
{{command:spotify status}}
|
113
|
-
EOF
|
93
|
+
# Show the current song
|
94
|
+
#
|
95
|
+
# Usage:
|
96
|
+
# - spotify
|
97
|
+
# - spotify status
|
114
98
|
def status
|
115
99
|
stat = SpotifyCli::App.status
|
116
100
|
|
@@ -137,26 +121,27 @@ module SpotifyCli
|
|
137
121
|
end
|
138
122
|
end
|
139
123
|
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
{{command:spotify help}}
|
145
|
-
EOF
|
124
|
+
# Display Help
|
125
|
+
#
|
126
|
+
# Usage:
|
127
|
+
# - spotify help
|
146
128
|
def help(mappings)
|
129
|
+
require 'method_source'
|
130
|
+
|
147
131
|
Dex::UI.frame('Spotify CLI', timing: false) do
|
148
132
|
puts "CLI interface for Spotify"
|
149
133
|
end
|
150
134
|
|
151
135
|
mappings.group_by { |_,v| v }.each do |k, v|
|
152
136
|
v.reject! { |mapping| mapping.first == k.to_s }
|
153
|
-
doc =
|
137
|
+
doc = self.method(k).comment.gsub(/^#\s*/, '')
|
138
|
+
doc = strip_heredoc(doc)
|
154
139
|
|
155
140
|
Dex::UI.frame(k, timing: false) do
|
156
|
-
puts
|
141
|
+
puts strip_heredoc(doc)
|
157
142
|
next if v.empty?
|
158
|
-
puts
|
159
|
-
v.each { |mapping| puts
|
143
|
+
puts "\nAliases:"
|
144
|
+
v.each { |mapping| puts " - #{mapping.first}" }
|
160
145
|
end
|
161
146
|
end
|
162
147
|
end
|
@@ -177,6 +162,20 @@ module SpotifyCli
|
|
177
162
|
|
178
163
|
`#{curl_cmd}`.strip.split("\n")
|
179
164
|
end
|
165
|
+
|
166
|
+
# The following methods is taken from activesupport
|
167
|
+
#
|
168
|
+
# https://github.com/rails/rails/blob/d66e7835bea9505f7003e5038aa19b6ea95ceea1/activesupport/lib/active_support/core_ext/string/strip.rb
|
169
|
+
#
|
170
|
+
# All credit for this method goes to the original authors.
|
171
|
+
# The code is used under the MIT license.
|
172
|
+
#
|
173
|
+
# Strips indentation by removing the amount of leading whitespace in the least indented
|
174
|
+
# non-empty line in the whole string
|
175
|
+
#
|
176
|
+
def strip_heredoc(str)
|
177
|
+
str.gsub(/^#{str.scan(/^[ \t]*(?=\S)/).min}/, "".freeze)
|
178
|
+
end
|
180
179
|
end
|
181
180
|
end
|
182
181
|
end
|
data/lib/spotify_cli/app.rb
CHANGED
@@ -1,101 +1,135 @@
|
|
1
1
|
module SpotifyCli
|
2
2
|
class App
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
class << self
|
4
|
+
# Return the state Spotify is in.
|
5
|
+
# Either "playing" or "paused"
|
6
|
+
#
|
7
|
+
# @return state [String]
|
8
|
+
#
|
9
|
+
def state
|
10
|
+
oascript('tell application "Spotify" to player state as string')
|
11
|
+
end
|
6
12
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
13
|
+
# Return a hash representing the current status of Spotify
|
14
|
+
# Contains state, current artist, current album, current track,
|
15
|
+
# duration of the current track, position in the current track,
|
16
|
+
# percent of the track complete
|
17
|
+
#
|
18
|
+
# @return status [Hash]
|
19
|
+
#
|
20
|
+
def status
|
21
|
+
artist = oascript('tell application "Spotify" to artist of current track as string')
|
22
|
+
album = oascript('tell application "Spotify" to album of current track as string')
|
23
|
+
track = oascript('tell application "Spotify" to name of current track as string')
|
24
|
+
duration = oascript(<<-EOF)
|
25
|
+
tell application "Spotify"
|
26
|
+
set durSec to (duration of current track / 1000) as text
|
27
|
+
set tM to (round (durSec / 60) rounding down) as text
|
28
|
+
if length of ((durSec mod 60 div 1) as text) is greater than 1 then
|
29
|
+
set tS to (durSec mod 60 div 1) as text
|
30
|
+
else
|
31
|
+
set tS to ("0" & (durSec mod 60 div 1)) as text
|
32
|
+
end if
|
33
|
+
set myTime to tM as text & ":" & tS as text
|
34
|
+
end tell
|
35
|
+
return myTime
|
36
|
+
EOF
|
37
|
+
position = oascript(<<-EOF)
|
38
|
+
tell application "Spotify"
|
39
|
+
set pos to player position
|
40
|
+
set nM to (round (pos / 60) rounding down) as text
|
41
|
+
if length of ((round (pos mod 60) rounding down) as text) is greater than 1 then
|
42
|
+
set nS to (round (pos mod 60) rounding down) as text
|
43
|
+
else
|
44
|
+
set nS to ("0" & (round (pos mod 60) rounding down)) as text
|
45
|
+
end if
|
46
|
+
set nowAt to nM as text & ":" & nS as text
|
47
|
+
end tell
|
48
|
+
return nowAt
|
49
|
+
EOF
|
37
50
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
51
|
+
{
|
52
|
+
state: state,
|
53
|
+
artist: artist,
|
54
|
+
album: album,
|
55
|
+
track: track,
|
56
|
+
duration: duration,
|
57
|
+
position: position,
|
58
|
+
percent_done: percent_done(position, duration)
|
59
|
+
}
|
60
|
+
end
|
48
61
|
|
49
|
-
|
50
|
-
|
51
|
-
|
62
|
+
# Play or Pause Spotify
|
63
|
+
#
|
64
|
+
def play_pause!
|
65
|
+
oascript('tell application "Spotify" to playpause')
|
66
|
+
end
|
52
67
|
|
53
|
-
|
54
|
-
|
55
|
-
|
68
|
+
# Pause Spotify
|
69
|
+
#
|
70
|
+
def pause!
|
71
|
+
oascript('tell application "Spotify" to pause')
|
72
|
+
end
|
56
73
|
|
57
|
-
|
58
|
-
|
59
|
-
|
74
|
+
# Pause a given URI
|
75
|
+
#
|
76
|
+
# @param uri [String] Spotify URI returned from the API
|
77
|
+
#
|
78
|
+
def play_uri!(uri)
|
79
|
+
oascript("tell application \"Spotify\" to play track \"#{uri}\"")
|
80
|
+
end
|
60
81
|
|
61
|
-
|
62
|
-
|
63
|
-
|
82
|
+
# Change to the next song
|
83
|
+
#
|
84
|
+
def next!
|
85
|
+
oascript('tell application "Spotify" to next track')
|
86
|
+
end
|
64
87
|
|
65
|
-
|
66
|
-
|
67
|
-
|
88
|
+
# Change to the previous song
|
89
|
+
#
|
90
|
+
def previous!
|
91
|
+
oascript(<<-EOF)
|
92
|
+
tell application "Spotify"
|
93
|
+
set player position to 0
|
94
|
+
previous track
|
95
|
+
end tell
|
96
|
+
EOF
|
97
|
+
end
|
68
98
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
end
|
99
|
+
# Set position in song to the given point
|
100
|
+
#
|
101
|
+
# @param pos [Int] Position in seconds
|
102
|
+
#
|
103
|
+
def set_pos!(pos)
|
104
|
+
oascript("tell application \"Spotify\" to set player position to #{pos}")
|
105
|
+
end
|
77
106
|
|
78
|
-
|
79
|
-
|
80
|
-
|
107
|
+
# Replay the current song from the beginning
|
108
|
+
#
|
109
|
+
def replay!
|
110
|
+
oascript('tell application "Spotify" to set player position to 0')
|
111
|
+
end
|
81
112
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
113
|
+
private
|
114
|
+
|
115
|
+
def percent_done(position, duration)
|
116
|
+
seconds = ->(parts) do
|
117
|
+
acc = 0
|
118
|
+
multiplier = 1
|
119
|
+
while part = parts.shift
|
120
|
+
acc += part.to_f * multiplier
|
121
|
+
multiplier *= 60
|
122
|
+
end
|
123
|
+
acc
|
89
124
|
end
|
90
|
-
|
125
|
+
pos_parts = position.split(':').reverse
|
126
|
+
dur_parts = duration.split(':').reverse
|
127
|
+
seconds.call(pos_parts) / seconds.call(dur_parts)
|
91
128
|
end
|
92
|
-
pos_parts = position.split(':').reverse
|
93
|
-
dur_parts = duration.split(':').reverse
|
94
|
-
seconds.call(pos_parts) / seconds.call(dur_parts)
|
95
|
-
end
|
96
129
|
|
97
|
-
|
98
|
-
|
130
|
+
def oascript(command)
|
131
|
+
`osascript -e '#{command}'`.strip
|
132
|
+
end
|
99
133
|
end
|
100
134
|
end
|
101
135
|
end
|
data/lib/spotify_cli/version.rb
CHANGED
data/lib/spotify_cli.rb
CHANGED
@@ -3,6 +3,11 @@ require 'dex/ui'
|
|
3
3
|
require 'spotify_cli/api'
|
4
4
|
|
5
5
|
module SpotifyCli
|
6
|
+
# CLI interface for the application
|
7
|
+
# Converts arguments to a mapped command and executes the command
|
8
|
+
#
|
9
|
+
# @param args [Array] CLI arugments
|
10
|
+
#
|
6
11
|
def self.call(args)
|
7
12
|
mappings = {
|
8
13
|
'next' => :next,
|
data/spotify_cli.gemspec
CHANGED
@@ -30,6 +30,7 @@ Gem::Specification.new do |spec|
|
|
30
30
|
spec.executables = ['spotify']
|
31
31
|
spec.require_paths = ["lib"]
|
32
32
|
|
33
|
+
spec.add_dependency 'method_source', '~> 0'
|
33
34
|
spec.add_development_dependency "bundler", "~> 1.14"
|
34
35
|
spec.add_development_dependency "rake", "~> 10.0"
|
35
36
|
spec.add_development_dependency "minitest", "~> 5.0"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spotify_cli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Julian Nadeau
|
@@ -10,6 +10,20 @@ bindir: bin
|
|
10
10
|
cert_chain: []
|
11
11
|
date: 2017-05-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: method_source
|
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'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: bundler
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -82,7 +96,6 @@ files:
|
|
82
96
|
- lib/dex/ui/spinner.rb
|
83
97
|
- lib/dex/ui/stdout_router.rb
|
84
98
|
- lib/dex/ui/terminal.rb
|
85
|
-
- lib/helpers/doc.rb
|
86
99
|
- lib/spotify_cli.rb
|
87
100
|
- lib/spotify_cli/.DS_Store
|
88
101
|
- lib/spotify_cli/api.rb
|
@@ -110,7 +123,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
110
123
|
version: '0'
|
111
124
|
requirements: []
|
112
125
|
rubyforge_project:
|
113
|
-
rubygems_version: 2.
|
126
|
+
rubygems_version: 2.6.12
|
114
127
|
signing_key:
|
115
128
|
specification_version: 4
|
116
129
|
summary: Spotify Application wrapper for control via command line
|
data/lib/helpers/doc.rb
DELETED
@@ -1,62 +0,0 @@
|
|
1
|
-
module MethodAddedHook
|
2
|
-
private
|
3
|
-
|
4
|
-
def method_added(meth)
|
5
|
-
method_added_hook(meth)
|
6
|
-
super
|
7
|
-
end
|
8
|
-
|
9
|
-
def singleton_method_added(meth)
|
10
|
-
method_added_hook(meth)
|
11
|
-
super
|
12
|
-
end
|
13
|
-
|
14
|
-
def method_added_hook(meth)
|
15
|
-
@@__last_defined_doc__ ||= nil
|
16
|
-
return if !defined?(@@__last_defined_doc__) || @@__last_defined_doc__.nil?
|
17
|
-
@@__class_docs__ ||= {}
|
18
|
-
@@__class_docs__[self.to_s] ||= {}
|
19
|
-
|
20
|
-
@@__class_docs__[self.to_s][meth] = @@__last_defined_doc__
|
21
|
-
@@__last_defined_doc__ = nil
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
class Module
|
26
|
-
private
|
27
|
-
prepend MethodAddedHook
|
28
|
-
|
29
|
-
def doc(str, meth = nil)
|
30
|
-
return @@__class_docs__[self.to_s][meth] = str if meth
|
31
|
-
@@__last_defined_doc__ = str
|
32
|
-
end
|
33
|
-
|
34
|
-
def defdoc(str, meth, &block)
|
35
|
-
@@__class_docs__[self.to_s][meth] = str
|
36
|
-
define_method(meth, &block)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
module Kernel
|
41
|
-
def get_doc(klass, meth)
|
42
|
-
docs = klass.class_variable_get(:@@__class_docs__)
|
43
|
-
docs[self.to_s][meth.to_sym] if docs && docs[self.to_s]
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
|
48
|
-
class String
|
49
|
-
# The following methods is taken from activesupport
|
50
|
-
#
|
51
|
-
# https://github.com/rails/rails/blob/d66e7835bea9505f7003e5038aa19b6ea95ceea1/activesupport/lib/active_support/core_ext/string/strip.rb
|
52
|
-
#
|
53
|
-
# All credit for this method goes to the original authors.
|
54
|
-
# The code is used under the MIT license.
|
55
|
-
#
|
56
|
-
# Strips indentation by removing the amount of leading whitespace in the least indented
|
57
|
-
# non-empty line in the whole string
|
58
|
-
#
|
59
|
-
def strip_heredoc
|
60
|
-
self.gsub(/^#{self.scan(/^[ \t]*(?=\S)/).min}/, "".freeze)
|
61
|
-
end
|
62
|
-
end
|