muzak 0.0.11 → 0.0.12

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 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