muzak 0.0.11 → 0.0.12
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.yardopts +1 -0
- data/lib/muzak/album.rb +11 -4
- data/lib/muzak/cmd.rb +1 -0
- data/lib/muzak/cmd/config.rb +3 -0
- data/lib/muzak/cmd/index.rb +15 -0
- data/lib/muzak/cmd/meta.rb +11 -0
- data/lib/muzak/cmd/player.rb +45 -0
- data/lib/muzak/cmd/playlist.rb +29 -13
- data/lib/muzak/config.rb +11 -1
- data/lib/muzak/const.rb +16 -1
- data/lib/muzak/index.rb +37 -1
- data/lib/muzak/instance.rb +23 -2
- data/lib/muzak/player.rb +9 -1
- data/lib/muzak/player/mpv.rb +42 -0
- data/lib/muzak/player/stub_player.rb +51 -0
- data/lib/muzak/playlist.rb +34 -1
- data/lib/muzak/plugin.rb +8 -1
- data/lib/muzak/plugin/stub_plugin.rb +4 -4
- data/lib/muzak/song.rb +36 -1
- data/lib/muzak/utils.rb +52 -0
- metadata +4 -6
- data/lib/muzak/plugin/cava.rb +0 -44
- data/lib/muzak/plugin/notify.rb +0 -16
- data/lib/muzak/plugin/scrobble.rb +0 -81
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cdbf4e0b472fdf7499bbd25915c178c00ea427f2
|
4
|
+
data.tar.gz: e0b39265673163d195dde538960beb7819e2ebbe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 18ae7d00640668f375390afc84d2ec0aec1fde26970d9e1636c943a7a29415267b97cf5c433efc2967ad630726525f617493a77e30cc2072646af95406078de1
|
7
|
+
data.tar.gz: 51f3a12b1e2018fb52c118cbd79afdc47a22a9a0a7feaf724960baffc9604b77042aafd60d3b0e7117e8b37bd9c12475c0653ffc71befc722c43c3289229b5f6
|
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--tag command:"muzak command" --tag cmdexample:"example invocation" --no-private --markup-provider=redcarpet --markup=markdown - README.md LICENSE
|
data/lib/muzak/album.rb
CHANGED
@@ -1,10 +1,17 @@
|
|
1
1
|
module Muzak
|
2
|
+
# Represents a collection of songs for muzak.
|
2
3
|
class Album
|
3
|
-
|
4
|
+
# @return [String] the album's title
|
5
|
+
attr_reader :title
|
4
6
|
|
5
|
-
#
|
6
|
-
|
7
|
-
|
7
|
+
# @return [Array<Muzak::Song>] the album's songs
|
8
|
+
attr_reader :songs
|
9
|
+
|
10
|
+
# @return [String] the path to the album's cover art
|
11
|
+
attr_reader :cover_art
|
12
|
+
|
13
|
+
# @note instead of passing an album hash directly from the index, this
|
14
|
+
# should really just take a title and an array of Song objects.
|
8
15
|
def initialize(title, album_hash)
|
9
16
|
@title = title
|
10
17
|
@cover_art = album_hash["cover"]
|
data/lib/muzak/cmd.rb
CHANGED
@@ -5,6 +5,7 @@ module Muzak
|
|
5
5
|
# load commands included by the user
|
6
6
|
Dir.glob(File.join(USER_COMMAND_DIR, "*")) { |file| require file }
|
7
7
|
|
8
|
+
# @return [Array<String>] all valid muzak commands
|
8
9
|
def self.commands
|
9
10
|
commands = instance_methods.map(&:to_s).reject { |m| m.start_with?("_") }
|
10
11
|
commands.map { |c| Utils.resolve_method c }
|
data/lib/muzak/cmd/config.rb
CHANGED
data/lib/muzak/cmd/index.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
module Muzak
|
2
2
|
module Cmd
|
3
|
+
# Rebuild the current instance's index.
|
4
|
+
# @command `index-build`
|
5
|
+
# @cmdexample `muzak> index-build`
|
3
6
|
def index_build(*args)
|
4
7
|
warn_arity(args, 0)
|
5
8
|
|
@@ -8,18 +11,27 @@ module Muzak
|
|
8
11
|
index.build!
|
9
12
|
end
|
10
13
|
|
14
|
+
# List all artists in the index.
|
15
|
+
# @command `list-artists`
|
16
|
+
# @cmdexample `muzak> list-artists`
|
11
17
|
def list_artists(*args)
|
12
18
|
warn_arity(args, 0)
|
13
19
|
|
14
20
|
puts index.artists.join("\n")
|
15
21
|
end
|
16
22
|
|
23
|
+
# List all albums in the index.
|
24
|
+
# @command `list-albums`
|
25
|
+
# @cmdexample `muzak> list-albums`
|
17
26
|
def list_albums(*args)
|
18
27
|
warn_arity(args, 0)
|
19
28
|
|
20
29
|
puts index.album_names.join("\n")
|
21
30
|
end
|
22
31
|
|
32
|
+
# List all albums by the given artist in the index.
|
33
|
+
# @command `albums-by-artist <artist name>`
|
34
|
+
# @cmdexample `muzak> albums-by-artist Your Favorite Artist`
|
23
35
|
def albums_by_artist(*args)
|
24
36
|
artist = args.join(" ")
|
25
37
|
return if artist.nil?
|
@@ -27,6 +39,9 @@ module Muzak
|
|
27
39
|
puts index.albums_by(artist).map(&:title)
|
28
40
|
end
|
29
41
|
|
42
|
+
# List all songs by the given artist in the index.
|
43
|
+
# @command `songs-by-artist <artist name>`
|
44
|
+
# @cmdexample `muzak> songs-by-artist Your Next Favorite Artist`
|
30
45
|
def songs_by_artist(*args)
|
31
46
|
artist = args.join(" ")
|
32
47
|
return if artist.nil?
|
data/lib/muzak/cmd/meta.rb
CHANGED
@@ -1,15 +1,26 @@
|
|
1
1
|
module Muzak
|
2
2
|
module Cmd
|
3
|
+
# Print a "helpful" listing of commands.
|
4
|
+
# @command `help`
|
5
|
+
# @cmdexample `muzak> help`
|
3
6
|
def help(*args)
|
4
7
|
commands = Muzak::Cmd.commands.join(", ")
|
5
8
|
info "available commands: #{commands}"
|
6
9
|
end
|
7
10
|
|
11
|
+
# List all available plugins.
|
12
|
+
# @command `list-plugins`
|
13
|
+
# @cmdexample `muzak> list-plugins`
|
14
|
+
# @note This list will differ from loaded plugins, if not all available
|
15
|
+
# plugins are configured.
|
8
16
|
def list_plugins
|
9
17
|
plugins = Plugin.plugin_names.join(", ")
|
10
18
|
puts "available plugins: #{plugins}"
|
11
19
|
end
|
12
20
|
|
21
|
+
# Terminates the muzak instance (**not** just the client).
|
22
|
+
# @command `quit`
|
23
|
+
# @cmdexample `muzak> quit`
|
13
24
|
def quit
|
14
25
|
verbose "muzak is quitting..."
|
15
26
|
player.deactivate!
|
data/lib/muzak/cmd/player.rb
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
module Muzak
|
2
2
|
module Cmd
|
3
|
+
# Activate the configured player.
|
4
|
+
# @command `player-activate`
|
5
|
+
# @cmdexample `muzak> player-activate`
|
6
|
+
# @note Many playback commands will automatically activate the player.
|
3
7
|
def player_activate
|
4
8
|
if player.running?
|
5
9
|
warn "player is already running"
|
@@ -9,6 +13,10 @@ module Muzak
|
|
9
13
|
player.activate!
|
10
14
|
end
|
11
15
|
|
16
|
+
# Deactivate the configured player.
|
17
|
+
# @command `player-deactivate`
|
18
|
+
# @cmdexample `muzak> player-deactivate`
|
19
|
+
# @note Deactivating the player (usually) ends playback immediately.
|
12
20
|
def player_deactivate
|
13
21
|
warn "player is not running" unless player.running?
|
14
22
|
|
@@ -16,14 +24,23 @@ module Muzak
|
|
16
24
|
player.deactivate!
|
17
25
|
end
|
18
26
|
|
27
|
+
# Tell the player to begin playback.
|
28
|
+
# @command `play`
|
29
|
+
# @cmdexample `muzak> play`
|
19
30
|
def play
|
20
31
|
player.play
|
21
32
|
end
|
22
33
|
|
34
|
+
# Tell the player to pause.
|
35
|
+
# @command `pause`
|
36
|
+
# @cmdexample `muzak> pause`
|
23
37
|
def pause
|
24
38
|
player.pause
|
25
39
|
end
|
26
40
|
|
41
|
+
# Tell the player to toggle its playback state.
|
42
|
+
# @command `toggle`
|
43
|
+
# @cmdexample `muzak> toggle`
|
27
44
|
def toggle
|
28
45
|
if player.playing?
|
29
46
|
player.pause
|
@@ -32,14 +49,23 @@ module Muzak
|
|
32
49
|
end
|
33
50
|
end
|
34
51
|
|
52
|
+
# Tell the player to load the next song.
|
53
|
+
# @command `next`
|
54
|
+
# @cmdexample `muzak> next`
|
35
55
|
def next
|
36
56
|
player.next_song
|
37
57
|
end
|
38
58
|
|
59
|
+
# Tell the player to load the previous song.
|
60
|
+
# @command `previous`
|
61
|
+
# @cmdexample `muzak> previous`
|
39
62
|
def previous
|
40
63
|
player.previous_song
|
41
64
|
end
|
42
65
|
|
66
|
+
# Tell the player to enqueue all songs by the given artist.
|
67
|
+
# @command `enqueue-artist <artist name>`
|
68
|
+
# @cmdexample `muzak> enqueue-artist Your Favorite Artist`
|
43
69
|
def enqueue_artist(*args)
|
44
70
|
artist = args.join(" ")
|
45
71
|
return if artist.nil?
|
@@ -52,6 +78,9 @@ module Muzak
|
|
52
78
|
end
|
53
79
|
end
|
54
80
|
|
81
|
+
# Tell the player to enqueue the given album.
|
82
|
+
# @command `enqueue-album <album name>`
|
83
|
+
# @cmdexample `muzak> enqueue-album Your Favorite Album`
|
55
84
|
def enqueue_album(*args)
|
56
85
|
album_name = args.join(" ")
|
57
86
|
return if album_name.nil?
|
@@ -64,6 +93,9 @@ module Muzak
|
|
64
93
|
player.enqueue_album album
|
65
94
|
end
|
66
95
|
|
96
|
+
# Tell the player to load the given number of random songs.
|
97
|
+
# @command `jukebox [count]`
|
98
|
+
# @cmdexample `muzak> jukebox 150`
|
67
99
|
def jukebox(*args)
|
68
100
|
count = args.shift || Config.jukebox_size
|
69
101
|
|
@@ -72,18 +104,31 @@ module Muzak
|
|
72
104
|
songs.each { |s| player.enqueue_song s }
|
73
105
|
end
|
74
106
|
|
107
|
+
# Tell the player to list its internal queue.
|
108
|
+
# @command `list-queue`
|
109
|
+
# @cmdexample `muzak> list-queue`
|
75
110
|
def list_queue
|
76
111
|
puts player.list_queue.map(&:title)
|
77
112
|
end
|
78
113
|
|
114
|
+
# Tell the player to shuffle its internal queue.
|
115
|
+
# @command `shuffle-queue`
|
116
|
+
# @cmdexample `muzak> shuffle-queue`
|
79
117
|
def shuffle_queue
|
80
118
|
player.shuffle_queue
|
81
119
|
end
|
82
120
|
|
121
|
+
# Tell the player to clear its internal queue.
|
122
|
+
# @command `clear-queue`
|
123
|
+
# @cmdexample `muzak> clear-queue`
|
124
|
+
# @note This does not (usually) stop the current song.
|
83
125
|
def clear_queue
|
84
126
|
player.clear_queue
|
85
127
|
end
|
86
128
|
|
129
|
+
# Retrieve the currently playing song from the player and print it.
|
130
|
+
# @command `now-playing`
|
131
|
+
# @cmdexample `muzak> now-playing`
|
87
132
|
def now_playing
|
88
133
|
return unless player.playing?
|
89
134
|
|
data/lib/muzak/cmd/playlist.rb
CHANGED
@@ -1,15 +1,17 @@
|
|
1
1
|
module Muzak
|
2
2
|
module Cmd
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
# List all currently available playlists.
|
4
|
+
# @command `list-playlists`
|
5
|
+
# @cmdexample `muzak> list-playlists`
|
7
6
|
def list_playlists(*args)
|
8
7
|
Playlist.playlist_names.each do |playlist|
|
9
8
|
info playlist
|
10
9
|
end
|
11
10
|
end
|
12
11
|
|
12
|
+
# Delete the given playlist.
|
13
|
+
# @command `playlist-delete <playlist>`
|
14
|
+
# @cmdexample `muzak> playlist-delete favorites`
|
13
15
|
def playlist_delete(*args)
|
14
16
|
fail_arity(args, 1)
|
15
17
|
pname = args.shift
|
@@ -20,8 +22,10 @@ module Muzak
|
|
20
22
|
playlists[pname] = nil
|
21
23
|
end
|
22
24
|
|
25
|
+
# Add the given playlist to the player's queue.
|
26
|
+
# @command `enqueue-playlist <playlist>`
|
27
|
+
# @cmdexample `muzak> enqueue-playlist favorites`
|
23
28
|
def enqueue_playlist(*args)
|
24
|
-
return unless _playlists_loaded?
|
25
29
|
fail_arity(args, 1)
|
26
30
|
pname = args.shift
|
27
31
|
|
@@ -29,9 +33,10 @@ module Muzak
|
|
29
33
|
event :playlist_enqueued, playlists[pname]
|
30
34
|
end
|
31
35
|
|
36
|
+
# Add the given album to the given playlist.
|
37
|
+
# @command `playlist-add-album <playlist> <album name>`
|
38
|
+
# @cmdexample `muzak> playlist-add-album favorites Your Favorite Album`
|
32
39
|
def playlist_add_album(*args)
|
33
|
-
return unless _playlists_loaded?
|
34
|
-
|
35
40
|
pname = args.shift
|
36
41
|
return if pname.nil?
|
37
42
|
|
@@ -44,9 +49,10 @@ module Muzak
|
|
44
49
|
playlists[pname].add(album.songs)
|
45
50
|
end
|
46
51
|
|
52
|
+
# Add the given artist to the given playlist.
|
53
|
+
# @command `playlist-add-artist <playlist> <artist name>`
|
54
|
+
# @cmdexample `muzak> playlist-add-artist dad-rock The Rolling Stones`
|
47
55
|
def playlist_add_artist(*args)
|
48
|
-
return unless _playlists_loaded?
|
49
|
-
|
50
56
|
pname = args.shift
|
51
57
|
return if pname.nil?
|
52
58
|
|
@@ -56,8 +62,12 @@ module Muzak
|
|
56
62
|
playlists[pname].add(index.songs_by(artist))
|
57
63
|
end
|
58
64
|
|
65
|
+
# Add the currently playing song to the given playlist.
|
66
|
+
# @see Muzak::Player::StubPlayer#now_playing
|
67
|
+
# @command `playlist-add-current <playlist>`
|
68
|
+
# @cmdexample `muzak> playlist-add-current favorites`
|
59
69
|
def playlist_add_current(*args)
|
60
|
-
return unless player.running?
|
70
|
+
return unless player.running?
|
61
71
|
|
62
72
|
pname = args.shift
|
63
73
|
return if pname.nil?
|
@@ -65,8 +75,12 @@ module Muzak
|
|
65
75
|
playlists[pname].add player.now_playing
|
66
76
|
end
|
67
77
|
|
78
|
+
# Deletes the currently playing song from the given playlist.
|
79
|
+
# @see Muzak::Player::StubPlayer#now_playing
|
80
|
+
# @command `playlist-del-current <playlist>`
|
81
|
+
# @cmdexample `muzak> playlist-del-current favorites`
|
68
82
|
def playlist_del_current(*args)
|
69
|
-
return unless player.running?
|
83
|
+
return unless player.running?
|
70
84
|
|
71
85
|
pname = args.shift
|
72
86
|
return if pname.nil?
|
@@ -74,9 +88,11 @@ module Muzak
|
|
74
88
|
playlists[pname].delete player.now_playing
|
75
89
|
end
|
76
90
|
|
91
|
+
# Shuffle the given playlist.
|
92
|
+
# @see Muzak::Playlist#shuffle!
|
93
|
+
# @command `playlist-shuffle <playlist>`
|
94
|
+
# @cmdexample `muzak> playlist-shuffle dad-rock`
|
77
95
|
def playlist_shuffle(*args)
|
78
|
-
return unless _playlists_loaded?
|
79
|
-
|
80
96
|
pname = args.shift
|
81
97
|
return if pname.nil?
|
82
98
|
|
data/lib/muzak/config.rb
CHANGED
@@ -1,6 +1,12 @@
|
|
1
1
|
require "yaml"
|
2
2
|
|
3
3
|
module Muzak
|
4
|
+
# Muzak's static configuration dumping ground.
|
5
|
+
# Key-value pairs are loaded from {CONFIG_FILE} and translated from
|
6
|
+
# kebab-case to snake_case methods.
|
7
|
+
# @example
|
8
|
+
# # corresponds to `art-geometry: 300x300` in configuration
|
9
|
+
# Config.art_geometry # => "300x300"
|
4
10
|
class Config
|
5
11
|
if File.exist?(CONFIG_FILE)
|
6
12
|
@config = YAML::load_file(CONFIG_FILE)
|
@@ -24,11 +30,15 @@ module Muzak
|
|
24
30
|
end
|
25
31
|
end
|
26
32
|
|
27
|
-
#
|
33
|
+
# Catches all undefined configuration keys and defaults them to false.
|
34
|
+
# @return [false]
|
28
35
|
def self.method_missing(method, *args)
|
29
36
|
false
|
30
37
|
end
|
31
38
|
|
39
|
+
# @return [Boolean] whether or not the given plugin is configured
|
40
|
+
# @note the truth-value of this method is used to determine which
|
41
|
+
# plugins should be loaded.
|
32
42
|
def self.plugin?(pname)
|
33
43
|
respond_to? "plugin_#{pname}"
|
34
44
|
end
|
data/lib/muzak/const.rb
CHANGED
@@ -1,17 +1,32 @@
|
|
1
1
|
module Muzak
|
2
|
-
|
2
|
+
# Muzak's current version
|
3
|
+
VERSION = "0.0.12".freeze
|
3
4
|
|
5
|
+
# The root directory for all user configuration, data, etc
|
4
6
|
CONFIG_DIR = File.expand_path("~/.config/muzak").freeze
|
7
|
+
|
8
|
+
# Muzak's primary configuration file
|
9
|
+
# @see Muzak::Config
|
5
10
|
CONFIG_FILE = File.join(CONFIG_DIR, "muzak.yml").freeze
|
11
|
+
|
12
|
+
# Muzak's music index
|
6
13
|
INDEX_FILE = File.join(CONFIG_DIR, "index.dat").freeze
|
14
|
+
|
15
|
+
# The directory for all user playlists
|
7
16
|
PLAYLIST_DIR = File.join(CONFIG_DIR, "playlists").freeze
|
17
|
+
|
18
|
+
# The directory for all user plugins
|
8
19
|
USER_PLUGIN_DIR = File.join(CONFIG_DIR, "plugins").freeze
|
20
|
+
|
21
|
+
# The directory for all user commands
|
9
22
|
USER_COMMAND_DIR = File.join(CONFIG_DIR, "commands").freeze
|
10
23
|
|
24
|
+
# All events currently propagated by {Muzak::Instance#event}
|
11
25
|
PLUGIN_EVENTS = [
|
12
26
|
:player_activated,
|
13
27
|
:player_deactivated,
|
14
28
|
:song_loaded,
|
29
|
+
:song_unloaded,
|
15
30
|
:playlist_enqueued
|
16
31
|
]
|
17
32
|
end
|
data/lib/muzak/index.rb
CHANGED
@@ -1,8 +1,22 @@
|
|
1
1
|
module Muzak
|
2
|
+
# Represents muzak's music index.
|
2
3
|
class Index
|
3
4
|
include Utils
|
4
|
-
attr_accessor :tree, :deep, :hash
|
5
5
|
|
6
|
+
# @return [String] the path of the root of the music tree
|
7
|
+
attr_accessor :tree
|
8
|
+
|
9
|
+
# @return [Boolean] whether the index is "deep" (includes metadata) or not
|
10
|
+
attr_accessor :deep
|
11
|
+
|
12
|
+
# @return [Hash] the index hash
|
13
|
+
attr_accessor :hash
|
14
|
+
|
15
|
+
# @param tree [String] the root to begin indexing from
|
16
|
+
# @param deep [Boolean] whether to build a "deep" index
|
17
|
+
# @note if the index ({Muzak::INDEX_FILE}) already exists and is not
|
18
|
+
# outdated, no building is performed.
|
19
|
+
# @see #build!
|
6
20
|
def initialize(tree, deep: false)
|
7
21
|
@tree = tree
|
8
22
|
@deep = deep
|
@@ -16,6 +30,8 @@ module Muzak
|
|
16
30
|
build!
|
17
31
|
end
|
18
32
|
|
33
|
+
# (Re)builds and saves the index ({Muzak::INDEX_FILE}) to disk.
|
34
|
+
# @note This method can be expensive.
|
19
35
|
def build!
|
20
36
|
@hash = build_index_hash!
|
21
37
|
|
@@ -24,22 +40,30 @@ module Muzak
|
|
24
40
|
File.open(INDEX_FILE, "w") { |io| io.write Marshal::dump @hash }
|
25
41
|
end
|
26
42
|
|
43
|
+
# @return [Boolean] whether or not the current index is deep
|
27
44
|
def deep?
|
28
45
|
deep
|
29
46
|
end
|
30
47
|
|
48
|
+
# @return [Integer] the UNIX timestamp from when the index was built
|
31
49
|
def timestamp
|
32
50
|
@hash["timestamp"]
|
33
51
|
end
|
34
52
|
|
53
|
+
# @return [Boolean] whether or not the index is currently out of date
|
54
|
+
# @note The behavior of this method is affected by the value of
|
55
|
+
# {Muzak::Config.index_autobuild}.
|
35
56
|
def outdated?
|
36
57
|
Time.now.to_i - timestamp >= Config.index_autobuild
|
37
58
|
end
|
38
59
|
|
60
|
+
# @return [Array<String>] a list of all artists in the index
|
39
61
|
def artists
|
40
62
|
@artists ||= @hash["artists"].keys
|
41
63
|
end
|
42
64
|
|
65
|
+
# @return [Hash{String => Album}] a hash of all album names with their
|
66
|
+
# {Album} objects
|
43
67
|
def albums
|
44
68
|
@albums_hash ||= begin
|
45
69
|
albums_hash = {}
|
@@ -54,10 +78,15 @@ module Muzak
|
|
54
78
|
end
|
55
79
|
end
|
56
80
|
|
81
|
+
# @return [Array<String>] a list of all albums in the index
|
82
|
+
# @note albums with the same name will appear, but can't be disambiguated
|
83
|
+
# from here
|
57
84
|
def album_names
|
58
85
|
artists.map { |a| @hash["artists"][a]["albums"].keys }.flatten
|
59
86
|
end
|
60
87
|
|
88
|
+
# @param artist [String] the artist's name
|
89
|
+
# @return [Array<Album>] all albums by the given artist
|
61
90
|
def albums_by(artist)
|
62
91
|
if artists.include?(artist)
|
63
92
|
@hash["artists"][artist]["albums"].map { |title, album| Album.new(title, album) }
|
@@ -67,6 +96,9 @@ module Muzak
|
|
67
96
|
end
|
68
97
|
end
|
69
98
|
|
99
|
+
# Produces a 'jukebox' of random songs.
|
100
|
+
# @param count [Integer] the number of random songs to return
|
101
|
+
# @return [Array<Song>] an array of randomly chosen songs
|
70
102
|
def jukebox(count = 50)
|
71
103
|
@all_albums ||= @hash["artists"].map { |_, a| a["albums"] }.flatten
|
72
104
|
|
@@ -79,6 +111,10 @@ module Muzak
|
|
79
111
|
end
|
80
112
|
end
|
81
113
|
|
114
|
+
# @param artist [String] the artist's name
|
115
|
+
# @return [Array<Song>] an array of all the artist's songs
|
116
|
+
# @note no inter-album order is guaranteed. songs within an album are
|
117
|
+
# generally sorted by track number.
|
82
118
|
def songs_by(artist)
|
83
119
|
error "no such artist: '#{artist}'" unless @hash["artists"].key?(artist)
|
84
120
|
|