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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bfec18a0835cc1c148e9bf4c1ee3c9770143ba46
4
- data.tar.gz: 44f5b96244563e8161d6c9950079551b4554d80a
3
+ metadata.gz: cdbf4e0b472fdf7499bbd25915c178c00ea427f2
4
+ data.tar.gz: e0b39265673163d195dde538960beb7819e2ebbe
5
5
  SHA512:
6
- metadata.gz: 4c8c79d444285e835e753fe1582147a30de11bf96a9d3d18f2af54b116ff315937000a88ab1a2a8b1c89de767ac0692d95125bbbc01557cd42ed808c96173d68
7
- data.tar.gz: bbe8db2c4bdbe6f0df3eea079de83795ef4638437268ef779d5231ea8c3afde337e437335ff30a6899ab92d1defb8760f384f02b72c59524b842beefcd67b151
6
+ metadata.gz: 18ae7d00640668f375390afc84d2ec0aec1fde26970d9e1636c943a7a29415267b97cf5c433efc2967ad630726525f617493a77e30cc2072646af95406078de1
7
+ data.tar.gz: 51f3a12b1e2018fb52c118cbd79afdc47a22a9a0a7feaf724960baffc9604b77042aafd60d3b0e7117e8b37bd9c12475c0653ffc71befc722c43c3289229b5f6
@@ -0,0 +1 @@
1
+ --tag command:"muzak command" --tag cmdexample:"example invocation" --no-private --markup-provider=redcarpet --markup=markdown - README.md LICENSE
@@ -1,10 +1,17 @@
1
1
  module Muzak
2
+ # Represents a collection of songs for muzak.
2
3
  class Album
3
- attr_reader :title, :songs, :cover_art
4
+ # @return [String] the album's title
5
+ attr_reader :title
4
6
 
5
- # instead of passing an album hash directly from the index,
6
- # this should really just take a title and an array of Song
7
- # objects.
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"]
@@ -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 }
@@ -2,6 +2,9 @@ require "yaml"
2
2
 
3
3
  module Muzak
4
4
  module Cmd
5
+ # Query the {Muzak::Config} for a given key.
6
+ # @command `config-get <key>`
7
+ # @cmdexample `muzak> config-get player`
5
8
  def config_get(*args)
6
9
  fail_arity(args, 1)
7
10
  key = args.shift
@@ -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?
@@ -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!
@@ -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
 
@@ -1,15 +1,17 @@
1
1
  module Muzak
2
2
  module Cmd
3
- def _playlists_loaded?
4
- !!playlists
5
- end
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? && _playlists_loaded?
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? && _playlists_loaded?
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
 
@@ -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
- # if a key doesn't exist, assume it's false
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
@@ -1,17 +1,32 @@
1
1
  module Muzak
2
- VERSION = "0.0.11".freeze
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
@@ -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