walkman 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.travis.yml +7 -0
- data/Gemfile +10 -0
- data/LICENSE.txt +22 -0
- data/README.md +52 -0
- data/Rakefile +6 -0
- data/lib/walkman.rb +57 -0
- data/lib/walkman/cli.rb +128 -0
- data/lib/walkman/commands/controls.rb +33 -0
- data/lib/walkman/commands/information.rb +26 -0
- data/lib/walkman/commands/player.rb +15 -0
- data/lib/walkman/commands/playlist.rb +17 -0
- data/lib/walkman/commands/queueing.rb +31 -0
- data/lib/walkman/config.rb +94 -0
- data/lib/walkman/player.rb +105 -0
- data/lib/walkman/playlist.rb +139 -0
- data/lib/walkman/services/base.rb +25 -0
- data/lib/walkman/services/rdio.rb +64 -0
- data/lib/walkman/services/rdio/rdio_player.rb +85 -0
- data/lib/walkman/song.rb +11 -0
- data/spec/factories/echowrap.rb +79 -0
- data/spec/factories/playlist.rb +32 -0
- data/spec/factories/song.rb +13 -0
- data/spec/sinatra_helper.rb +12 -0
- data/spec/spec_helper.rb +10 -0
- data/spec/support/factory_girl.rb +7 -0
- data/spec/walkman/commands/controls_spec.rb +26 -0
- data/spec/walkman/commands/information_spec.rb +45 -0
- data/spec/walkman/commands/player_spec.rb +19 -0
- data/spec/walkman/commands/queueing_spec.rb +62 -0
- data/spec/walkman/player_spec.rb +102 -0
- data/spec/walkman/playlist_spec.rb +150 -0
- data/spec/walkman/services/base_spec.rb +13 -0
- data/spec/walkman/services/rdio/rdio_player_spec.rb +24 -0
- data/spec/walkman/services/rdio_spec.rb +70 -0
- data/spec/walkman/song_spec.rb +33 -0
- data/walkman.gemspec +29 -0
- metadata +222 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 8e3d7ee1e1eeb85342fc9df700432e1a1879cf58
|
4
|
+
data.tar.gz: 7538521e2f9691d497aa9f780279fe6034d995d0
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: fb245267ddb8f2c75c0cf3711ee9d4006df6c2deefed5985cabb458d0b0bd38a48d6cce3c04fdca97ab3fa0fa397838cc2d9c14f6c2af7571a3bb657471cb20f
|
7
|
+
data.tar.gz: 549890eeb0a29f384329909e17d59d71ac0b69060489aad7d19f55a97a0adb0461e74d0b16f8f67a21cf2c7945e3b5e039ee25e2012314d33ad689182b4f7ef9
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Tres Trantham
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# Walkman
|
2
|
+
|
3
|
+
[![Build Status](https://travis-ci.org/trestrantham/walkman.png?branch=master)](https://travis-ci.org/trestrantham/walkman)
|
4
|
+
[![Code Climate](https://codeclimate.com/github/trestrantham/walkman.png)](https://codeclimate.com/github/trestrantham/walkman)
|
5
|
+
[![Coverage Status](https://coveralls.io/repos/trestrantham/walkman/badge.png)](https://coveralls.io/r/trestrantham/walkman)
|
6
|
+
[![Dependency Status](https://gemnasium.com/trestrantham/walkman.png)](https://gemnasium.com/trestrantham/walkman)
|
7
|
+
|
8
|
+
Walkman puts you in control if your music.
|
9
|
+
|
10
|
+
## Install
|
11
|
+
|
12
|
+
```
|
13
|
+
gem install walkman
|
14
|
+
```
|
15
|
+
|
16
|
+
## Dependencies
|
17
|
+
|
18
|
+
Walkman relies on a few external services to do its magic. Currently, the
|
19
|
+
canonical source for music data comes from [Echo Nest](http://echonest.com) who
|
20
|
+
provides artist/album/song information as well as playlist generation and
|
21
|
+
seeding. Actual music streams are currently provided via [Rdio](http://rdio.com)
|
22
|
+
with support for [Spotify](http://spotify.com) and local file playback via
|
23
|
+
[MPD](http://musicpd.org) in the works.
|
24
|
+
|
25
|
+
### Echo Nest
|
26
|
+
|
27
|
+
1. [Sign up](https://developer.echonest.com/account/register) for an Echo Nest developer account
|
28
|
+
2. Grab the `api_key`, `consumer_key`, and `shared_secret`
|
29
|
+
3. Create a catalog (taste profile) to use as your base library and grab its `id` to use as `catalog_id`:
|
30
|
+
|
31
|
+
```
|
32
|
+
curl -F "api_key=<api_key>" -F "format=json" -F "type=general" -F "name=base_profile"
|
33
|
+
```
|
34
|
+
|
35
|
+
### Rdio
|
36
|
+
|
37
|
+
1. [Sign up](http://developer.rdio.com/member/register) for a Rdio developer account
|
38
|
+
2. [Generate](http://rdioconsole.appspot.com/#method=getPlaybackToken) a `playback_token` after logging in at [rdio.com](http://rdio.com).
|
39
|
+
|
40
|
+
### Config
|
41
|
+
|
42
|
+
Create a Walkman config file at `~/.walkman`:
|
43
|
+
|
44
|
+
```
|
45
|
+
echonest:
|
46
|
+
api_key: ABCDEFGHIJKLMNOP
|
47
|
+
consumer_key: abc123efg456hij789klm098nop765qr
|
48
|
+
shared_secret: 4jh&kjhfg.@3kjfl987FJ3
|
49
|
+
catalog_id: CACABCD1234567890Z
|
50
|
+
rdio:
|
51
|
+
playback_token: GAlNi78J_____zlyYWs5ZG02N2pkaHlhcWsyOWJtYjkyN2xvY2FsaG9zdEbwl7EHvbylWSWFWYMZwfc=
|
52
|
+
```
|
data/Rakefile
ADDED
data/lib/walkman.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
require "echowrap"
|
2
|
+
|
3
|
+
require "walkman/config"
|
4
|
+
|
5
|
+
require "walkman/services/base"
|
6
|
+
require "walkman/services/rdio"
|
7
|
+
require "walkman/services/rdio/rdio_player"
|
8
|
+
|
9
|
+
require "walkman/player"
|
10
|
+
require "walkman/playlist"
|
11
|
+
require "walkman/song"
|
12
|
+
|
13
|
+
require "walkman/commands/controls"
|
14
|
+
require "walkman/commands/information"
|
15
|
+
require "walkman/commands/player"
|
16
|
+
require "walkman/commands/playlist"
|
17
|
+
require "walkman/commands/queueing"
|
18
|
+
|
19
|
+
require "walkman/cli"
|
20
|
+
|
21
|
+
module Walkman
|
22
|
+
def self.logger
|
23
|
+
@@logger ||= ::Logger.new(STDOUT).tap do |l|
|
24
|
+
l.level = log_level(Walkman.config.log_level)
|
25
|
+
l.formatter = proc do |severity, _, _, message|
|
26
|
+
"[walkman](#{severity.downcase}): #{message}\n"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.log_level(log_level_string)
|
32
|
+
case log_level_string.to_s
|
33
|
+
when "unknown"
|
34
|
+
::Logger::UNKNOWN
|
35
|
+
when "fatal"
|
36
|
+
::Logger::FATAL
|
37
|
+
when "error"
|
38
|
+
::Logger::ERROR
|
39
|
+
when "warn"
|
40
|
+
::Logger::WARN
|
41
|
+
when "info"
|
42
|
+
::Logger::INFO
|
43
|
+
when "debug"
|
44
|
+
::Logger::DEBUG
|
45
|
+
else
|
46
|
+
raise "Unknown log level given #{log_level_string}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.echowrap
|
51
|
+
@echowrap ||= Echowrap.configure do |config|
|
52
|
+
config.api_key = Walkman.config.echonest_api_key
|
53
|
+
config.consumer_key = Walkman.config.echonest_consumer_key
|
54
|
+
config.shared_secret = Walkman.config.echonest_shared_secret
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
data/lib/walkman/cli.rb
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
require "thor"
|
2
|
+
require "drb"
|
3
|
+
require "colorize"
|
4
|
+
|
5
|
+
module Walkman
|
6
|
+
class CLI < Thor
|
7
|
+
|
8
|
+
# server tasks
|
9
|
+
|
10
|
+
desc "start", "starts the walkman server"
|
11
|
+
option :daemon, type: :boolean, aliases: "-d"
|
12
|
+
def start
|
13
|
+
if options[:daemon]
|
14
|
+
Process.daemon
|
15
|
+
else
|
16
|
+
puts "Starting walkman server"
|
17
|
+
puts "Run `walkman start -d` for daemon"
|
18
|
+
puts "Ctrl-C to shutdown"
|
19
|
+
|
20
|
+
trap("INT") do
|
21
|
+
# calling this in a thread to get proper logging
|
22
|
+
thread = Thread.new do
|
23
|
+
shutdown
|
24
|
+
end
|
25
|
+
|
26
|
+
thread.join
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
Walkman.logger.info("starting server")
|
31
|
+
Walkman::Commands::Player.start
|
32
|
+
|
33
|
+
DRb.start_service(Walkman.config.drb_uri, self)
|
34
|
+
DRb.thread.join
|
35
|
+
end
|
36
|
+
|
37
|
+
desc "shutdown", "stops the walkman server"
|
38
|
+
def shutdown
|
39
|
+
response = server.run_command(:player_stop)
|
40
|
+
puts response unless response.empty?
|
41
|
+
|
42
|
+
server.stop_server
|
43
|
+
end
|
44
|
+
|
45
|
+
# controls tasks
|
46
|
+
|
47
|
+
desc "play", "plays the current playlist"
|
48
|
+
def play
|
49
|
+
response = server.run_command(:play)
|
50
|
+
puts response unless response.empty?
|
51
|
+
end
|
52
|
+
|
53
|
+
desc "stop", "stops playing music"
|
54
|
+
def stop
|
55
|
+
response = server.run_command(:stop)
|
56
|
+
puts response unless response.empty?
|
57
|
+
end
|
58
|
+
|
59
|
+
desc "next", "plays the next song in the current playlist"
|
60
|
+
def next(count = 1)
|
61
|
+
response = server.run_command(:next, { count: count.to_i })
|
62
|
+
puts response unless response.empty?
|
63
|
+
end
|
64
|
+
|
65
|
+
desc "skip COUNT", "skips the given amount of songs"
|
66
|
+
def skip(count = 1)
|
67
|
+
response = server.run_command(:skip, { count: count.to_i })
|
68
|
+
puts response unless response.empty?
|
69
|
+
end
|
70
|
+
|
71
|
+
desc "now_playing", "shows the song that's currently playing"
|
72
|
+
def now_playing
|
73
|
+
response = server.run_command(:now_playing)
|
74
|
+
puts response unless response.empty?
|
75
|
+
end
|
76
|
+
|
77
|
+
desc "up_next", "shows the next songs on the current playlist"
|
78
|
+
def up_next
|
79
|
+
response = server.run_command(:up_next)
|
80
|
+
puts response unless response.empty?
|
81
|
+
end
|
82
|
+
|
83
|
+
desc "play_artist ARTIST", "plays songs from the given artist"
|
84
|
+
def play_artist(*artist)
|
85
|
+
artist = artist.join(" ")
|
86
|
+
response = server.run_command(:artist, { artist: artist })
|
87
|
+
puts response unless response.empty?
|
88
|
+
end
|
89
|
+
|
90
|
+
desc "play_artist_radio ARTIST", "plays music like the given artist"
|
91
|
+
def play_artist_radio(*artist)
|
92
|
+
artist = artist.join(" ")
|
93
|
+
response = server.run_command(:artist_radio, { artist: artist })
|
94
|
+
puts response unless response.empty?
|
95
|
+
end
|
96
|
+
|
97
|
+
desc "like", "plays more music like the current song"
|
98
|
+
def like
|
99
|
+
response = server.run_command(:like)
|
100
|
+
puts response unless response.empty?
|
101
|
+
end
|
102
|
+
|
103
|
+
no_tasks do
|
104
|
+
def stop_server
|
105
|
+
DRb.stop_service
|
106
|
+
end
|
107
|
+
|
108
|
+
def server
|
109
|
+
@server ||= DRbObject.new_with_uri(Walkman.config.drb_uri)
|
110
|
+
end
|
111
|
+
|
112
|
+
def run_command(command, options = {})
|
113
|
+
case command
|
114
|
+
when :player_stop then Walkman::Commands::Player.stop
|
115
|
+
when :play then Walkman::Commands::Controls.play
|
116
|
+
when :stop then Walkman::Commands::Controls.stop
|
117
|
+
when :next then Walkman::Commands::Controls.next(options[:count])
|
118
|
+
when :skip then Walkman::Commands::Controls.skip(options[:count])
|
119
|
+
when :up_next then Walkman::Commands::Information.up_next
|
120
|
+
when :now_playing then Walkman::Commands::Information.now_playing
|
121
|
+
when :artist then Walkman::Commands::Queueing.artist(options[:artist])
|
122
|
+
when :artist_radio then Walkman::Commands::Queueing.artist_radio(options[:artist])
|
123
|
+
when :like then Walkman::Commands::Playlist.like
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Walkman
|
2
|
+
module Commands
|
3
|
+
module Controls
|
4
|
+
def self.play
|
5
|
+
Walkman.player.play
|
6
|
+
song = Walkman.player.current_song
|
7
|
+
|
8
|
+
output = ["♫".blue, "Playing"]
|
9
|
+
output << [song.title.bold, "by", song.artist.bold] if song
|
10
|
+
output.flatten.join(" ")
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.stop
|
14
|
+
Walkman.player.stop
|
15
|
+
""
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.next(count = 1)
|
19
|
+
if current_song = Walkman.player.current_song
|
20
|
+
Walkman.player.playlist.skip(current_song)
|
21
|
+
end
|
22
|
+
|
23
|
+
Walkman.player.next(count)
|
24
|
+
song = Walkman.player.current_song
|
25
|
+
|
26
|
+
output = ["♫".blue, "Skipping"]
|
27
|
+
output << ["to", song.title.bold, "by", song.artist.bold] if song
|
28
|
+
output.flatten.join(" ")
|
29
|
+
end
|
30
|
+
define_singleton_method(:skip) { |count| self.next(count) }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Walkman
|
2
|
+
module Commands
|
3
|
+
module Information
|
4
|
+
def self.now_playing
|
5
|
+
if song = Walkman.player.current_song
|
6
|
+
output = ["♫".blue, "Now playing"]
|
7
|
+
output << [song.title.bold, "by", song.artist.bold]
|
8
|
+
output.flatten.join(" ")
|
9
|
+
else
|
10
|
+
"No music is playing"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.up_next(count = 5)
|
15
|
+
songs = Walkman.player.playlist.queue.take(count)
|
16
|
+
songs_string = ""
|
17
|
+
|
18
|
+
songs.each do |song|
|
19
|
+
songs_string += "#{song.artist} - #{song.title}\n"
|
20
|
+
end
|
21
|
+
|
22
|
+
songs_string
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Walkman
|
2
|
+
module Commands
|
3
|
+
module Playlist
|
4
|
+
def self.like
|
5
|
+
current_song = Walkman.player.current_song
|
6
|
+
playlist = Walkman.player.playlist
|
7
|
+
|
8
|
+
if current_song && playlist
|
9
|
+
playlist.favorite(current_song)
|
10
|
+
"Awesome! I'll play more songs like this."
|
11
|
+
else
|
12
|
+
"No music is playing. Are you hearing things?"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Walkman
|
2
|
+
module Commands
|
3
|
+
module Queueing
|
4
|
+
def self.artist(artist)
|
5
|
+
playlist = Walkman::Playlist.new(type: "artist", artist: artist, auto_queue: true)
|
6
|
+
Walkman.player.playlist = playlist
|
7
|
+
|
8
|
+
if playlist.size > 0
|
9
|
+
Walkman.player.next
|
10
|
+
output = ["♫".blue, "Playing songs by", artist.titleize.bold]
|
11
|
+
output.flatten.join(" ")
|
12
|
+
else
|
13
|
+
"That artist couldn't be queued"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.artist_radio(artist)
|
18
|
+
playlist = Walkman::Playlist.new(type: "artist-radio", artist: artist, auto_queue: true)
|
19
|
+
Walkman.player.playlist = playlist
|
20
|
+
|
21
|
+
if playlist.size > 0
|
22
|
+
Walkman.player.next
|
23
|
+
output = ["♫".blue, "Playing music like", artist.titleize.bold]
|
24
|
+
output.flatten.join(" ")
|
25
|
+
else
|
26
|
+
"Music like that artist couldn't be queued"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|