cultome_player 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +1 -0
  3. data/.gitignore +24 -0
  4. data/.rspec +2 -0
  5. data/.travis.yml +7 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +325 -0
  9. data/Rakefile +8 -0
  10. data/bin/cultome_player +39 -0
  11. data/config/environment.yml +28 -0
  12. data/cultome_player.gemspec +35 -0
  13. data/db/001_create_schema.rb +58 -0
  14. data/lib/cultome_player.rb +107 -0
  15. data/lib/cultome_player/command.rb +11 -0
  16. data/lib/cultome_player/command/language.rb +61 -0
  17. data/lib/cultome_player/command/processor.rb +165 -0
  18. data/lib/cultome_player/command/reader.rb +86 -0
  19. data/lib/cultome_player/environment.rb +130 -0
  20. data/lib/cultome_player/events.rb +29 -0
  21. data/lib/cultome_player/media.rb +47 -0
  22. data/lib/cultome_player/objects.rb +15 -0
  23. data/lib/cultome_player/objects/album.rb +21 -0
  24. data/lib/cultome_player/objects/artist.rb +18 -0
  25. data/lib/cultome_player/objects/command.rb +37 -0
  26. data/lib/cultome_player/objects/drive.rb +26 -0
  27. data/lib/cultome_player/objects/genre.rb +16 -0
  28. data/lib/cultome_player/objects/parameter.rb +37 -0
  29. data/lib/cultome_player/objects/response.rb +42 -0
  30. data/lib/cultome_player/objects/song.rb +38 -0
  31. data/lib/cultome_player/player.rb +13 -0
  32. data/lib/cultome_player/player/adapter.rb +14 -0
  33. data/lib/cultome_player/player/adapter/mpg123.rb +143 -0
  34. data/lib/cultome_player/player/interactive.rb +56 -0
  35. data/lib/cultome_player/player/interface.rb +13 -0
  36. data/lib/cultome_player/player/interface/basic.rb +96 -0
  37. data/lib/cultome_player/player/interface/builtin_help.rb +368 -0
  38. data/lib/cultome_player/player/interface/extended.rb +199 -0
  39. data/lib/cultome_player/player/interface/helper.rb +300 -0
  40. data/lib/cultome_player/player/playlist.rb +280 -0
  41. data/lib/cultome_player/plugins.rb +23 -0
  42. data/lib/cultome_player/plugins/help.rb +58 -0
  43. data/lib/cultome_player/state_checker.rb +74 -0
  44. data/lib/cultome_player/utils.rb +95 -0
  45. data/lib/cultome_player/version.rb +3 -0
  46. data/spec/config.yml +0 -0
  47. data/spec/cultome_player/command/processor_spec.rb +168 -0
  48. data/spec/cultome_player/command/reader_spec.rb +45 -0
  49. data/spec/cultome_player/cultome_player_spec.rb +17 -0
  50. data/spec/cultome_player/environment_spec.rb +65 -0
  51. data/spec/cultome_player/events_spec.rb +22 -0
  52. data/spec/cultome_player/media_spec.rb +41 -0
  53. data/spec/cultome_player/player/adapter/mpg123_spec.rb +82 -0
  54. data/spec/cultome_player/player/interface/basic_spec.rb +168 -0
  55. data/spec/cultome_player/player/interface/extended/connect_spec.rb +117 -0
  56. data/spec/cultome_player/player/interface/extended/search_spec.rb +90 -0
  57. data/spec/cultome_player/player/interface/extended/show_spec.rb +36 -0
  58. data/spec/cultome_player/player/interface/extended/shuffle_spec.rb +26 -0
  59. data/spec/cultome_player/player/interface/extended_spec.rb +136 -0
  60. data/spec/cultome_player/player/interface/helper_spec.rb +63 -0
  61. data/spec/cultome_player/player/interface_spec.rb +17 -0
  62. data/spec/cultome_player/player/playlist_spec.rb +301 -0
  63. data/spec/cultome_player/plugins/help_spec.rb +21 -0
  64. data/spec/cultome_player/plugins_spec.rb +19 -0
  65. data/spec/cultome_player/utils_spec.rb +15 -0
  66. data/spec/spec_helper.rb +108 -0
  67. data/spec/test/uno/dos/dos.mp3 +0 -0
  68. data/spec/test/uno/dos/tres/tres.mp3 +0 -0
  69. data/spec/test/uno/uno.mp3 +0 -0
  70. data/tasks/console.rake +19 -0
  71. data/tasks/db.rake +19 -0
  72. data/tasks/run.rake +7 -0
  73. metadata +322 -0
@@ -0,0 +1,42 @@
1
+ module CultomePlayer
2
+ module Objects
3
+ class Response
4
+ attr_reader :data
5
+
6
+ def initialize(type, data)
7
+ @success = type == :success
8
+ @data = data
9
+
10
+ @data.each do |k,v|
11
+ self.class.send(:define_method, k) do
12
+ v
13
+ end
14
+ end
15
+ end
16
+
17
+ # Check if the success data associated to the response is false.
18
+ #
19
+ # @return [Boolean] True if success data is false, False otherwise.
20
+ def failure?
21
+ !@success
22
+ end
23
+
24
+ # Check if the success data associated to the response is true.
25
+ #
26
+ # @return [Boolean] True if success data is true, False otherwise.
27
+ def success?
28
+ @success
29
+ end
30
+
31
+ # Join two response together. The response type makes an OR and parameter response's data is merged into.
32
+ #
33
+ # @param response [Response] The response to join.
34
+ # @return [Response] The calculated new response.
35
+ def +(response)
36
+ type = success? && response.success? ? :success : :failure
37
+ data = @data.merge response.data
38
+ return Response.new(type, data)
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,38 @@
1
+ require 'active_record'
2
+
3
+ module CultomePlayer
4
+ module Objects
5
+ # The ActiveRecord model for Song objects.
6
+ class Song < ActiveRecord::Base
7
+ belongs_to :artist
8
+ belongs_to :album
9
+ has_and_belongs_to_many :genres
10
+ belongs_to :drive
11
+ has_many :similars, as: :similar
12
+
13
+ scope :connected, -> {joins(:drive).where('drives.connected' => true)}
14
+ # Get the full path to the song file.
15
+ #
16
+ # @return [String] The full path to the song file.
17
+ def path
18
+ File.join(self.drive.path, self.relative_path)
19
+ end
20
+
21
+ def to_s
22
+ str = c4(":::: Song: ")
23
+ str += c10(self.name)
24
+
25
+ unless self.artist.nil?
26
+ str += c4(" \\ Artist: ")
27
+ str += c11(self.artist.name)
28
+ end
29
+
30
+ unless self.album.nil?
31
+ str += c4(" \\ Album: ")
32
+ str += c13(self.album.name)
33
+ end
34
+ str += c4(" ::::")
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,13 @@
1
+ require 'cultome_player/player/interface'
2
+ require 'cultome_player/player/interactive'
3
+ require 'cultome_player/player/playlist'
4
+ require 'cultome_player/player/adapter'
5
+
6
+ module CultomePlayer
7
+ module Player
8
+ include Interface
9
+ include Interactive
10
+ include Playlist
11
+ include Adapter
12
+ end
13
+ end
@@ -0,0 +1,14 @@
1
+ require 'cultome_player/player/adapter/mpg123'
2
+
3
+ module CultomePlayer::Player::Adapter
4
+ include Mpg123
5
+
6
+ # Check if media player is running.
7
+ #
8
+ # @return [Boolean] True is player is running. False otherwise.
9
+ def player_running?
10
+ @is_player_running
11
+ end
12
+
13
+ end
14
+
@@ -0,0 +1,143 @@
1
+ module CultomePlayer::Player::Adapter
2
+ module Mpg123
3
+
4
+ # Start a playback in the media player.
5
+ #
6
+ # @contract Adapter
7
+ # @param song [Song] The song to be played.
8
+ def play_in_player(song)
9
+ @current_song = song
10
+ unless player_running?
11
+ start_player
12
+ end
13
+
14
+ loadfile(song)
15
+ end
16
+
17
+ # Activate the pause in media player.
18
+ #
19
+ # @contract Adapter
20
+ def pause_in_player
21
+ toggle_pause
22
+ end
23
+
24
+ # Resume playback in media player. If is paused or stopped.
25
+ #
26
+ # @contract Adapter
27
+ def resume_in_player
28
+ if paused?
29
+ toggle_pause
30
+ else
31
+ play_in_player current_song
32
+ end
33
+ end
34
+
35
+ # Stop playback in media player.
36
+ #
37
+ # @contract Adapter
38
+ def stop_in_player
39
+ @user_stopped = true
40
+ send_to_player "stop"
41
+ end
42
+
43
+ # Fast forward the playback
44
+ #
45
+ # @contract Adapter
46
+ # @param secs [Integer] Number of seconds to fast forward.
47
+ def ff_in_player(secs)
48
+ send_to_player "jump +#{secs}s"
49
+ end
50
+
51
+ # Fast backward the playback
52
+ #
53
+ # @contract Adapter
54
+ # @param secs [Integer] Number of seconds to fast backward.
55
+ def fb_in_player(secs)
56
+ send_to_player "jump -#{secs}s"
57
+ end
58
+
59
+ # Turn off the media player
60
+ def quit_in_player
61
+ begin
62
+ send_to_player "quit"
63
+ rescue Exception => e
64
+ end
65
+ end
66
+
67
+ # Play from the begining the current playback.
68
+ def repeat_in_player
69
+ send_to_player "jump 0"
70
+ end
71
+
72
+ private
73
+
74
+ def toggle_pause
75
+ send_to_player "pause"
76
+ end
77
+
78
+ def loadfile(song)
79
+ send_to_player "load #{song.path}"
80
+ end
81
+
82
+ def send_to_player(cmd)
83
+ raise 'invalid state:player is not running' unless player_running?
84
+ control_pipe.puts cmd
85
+ control_pipe.flush
86
+ end
87
+
88
+ def control_pipe
89
+ unless pipe_alive?
90
+ @pipe = File.open(mplayer_pipe, 'a+')
91
+ end
92
+ @pipe
93
+ end
94
+
95
+ def pipe_alive?
96
+ return !(@pipe.nil? || @pipe.closed?)
97
+ end
98
+
99
+ def start_player
100
+ # creamos el thread que lea la salida del mpg123
101
+ Thread.new do
102
+ start_cmd = "mpg123 --fifo #{mplayer_pipe} -R"
103
+ IO.popen(start_cmd).each do |line|
104
+ case line
105
+ when /^@R MPG123/
106
+ @is_player_running = true
107
+ when /^@P ([\d])$/
108
+ case $1.to_i
109
+ when 0 # stopped
110
+ @playing = @paused = false
111
+ @stopped = true
112
+ emit_event(:playback_finish) unless @user_stopped
113
+ @user_stopped = false
114
+ when 1 # paused
115
+ @stopped = @playing = false
116
+ @paused = true
117
+ emit_event(:playback_paused)
118
+ when 2 # unpaused
119
+ @playing = true
120
+ @paused = @stopped = false
121
+ emit_event(:playback_resumed)
122
+ end
123
+ when /^@F ([\d]+) ([\d]+) ([\d.]+) ([\d.]+)$/
124
+ @playback_time_position = $3.to_f
125
+ @playback_time_length = @playback_time_position + $4.to_f
126
+ end # case line
127
+ end # IO
128
+ end # Thread
129
+
130
+ wait_player
131
+ end
132
+
133
+ def wait_player
134
+ count = 0
135
+ while !player_running?
136
+ sleep(0.1)
137
+ count += 1
138
+ return if count > 50 # 5 seg
139
+ end
140
+ end
141
+
142
+ end
143
+ end
@@ -0,0 +1,56 @@
1
+ module CultomePlayer::Player
2
+ module Interactive
3
+
4
+ PROMPT = "cultome> "
5
+
6
+ # Begin a REP loop inside player.
7
+ def begin_session
8
+ @in_session = true
9
+ display "Cultome Player v#{CultomePlayer::VERSION}"
10
+
11
+ while in_session?
12
+ begin
13
+ r = execute read_command(PROMPT)
14
+ show_response(r)
15
+ rescue Exception => e
16
+ display e.message
17
+ end
18
+ end
19
+ end
20
+
21
+ # Check if there is an interactive session in progress.
22
+ #
23
+ # @return [Boolean] True if session in progress. False otherwise.
24
+ def in_session?
25
+ @in_session ||= false
26
+ end
27
+
28
+ # Terminates a interactive session.
29
+ def terminate_session
30
+ @in_session = false
31
+ end
32
+
33
+ private
34
+
35
+ def show_response(r)
36
+ if r.respond_to?(:response_type)
37
+ res_obj = r.send(r.response_type)
38
+ if res_obj.respond_to?(:each)
39
+ res_obj.each.with_index do |elem, idx|
40
+ display "#{(idx + 1).to_s.ljust(3)} | #{elem.to_s}"
41
+ end
42
+ elsif res_obj.class == String
43
+ display res_obj.to_s
44
+ else
45
+ display "(((#{res_obj.to_s})))"
46
+ end
47
+
48
+ elsif r.respond_to?(:message)
49
+ display r.message
50
+ else
51
+ display "!!!#{r}!!!"
52
+ end
53
+ end
54
+
55
+ end
56
+ end
@@ -0,0 +1,13 @@
1
+ require 'cultome_player/player/interface/basic'
2
+ require 'cultome_player/player/interface/extended'
3
+ require 'cultome_player/player/interface/helper'
4
+ require 'cultome_player/player/interface/builtin_help'
5
+
6
+ module CultomePlayer::Player
7
+ module Interface
8
+ include Basic
9
+ include Extended
10
+ include Helper
11
+ include BuiltinHelp
12
+ end
13
+ end
@@ -0,0 +1,96 @@
1
+ module CultomePlayer
2
+ module Player
3
+ module Interface
4
+ module Basic
5
+
6
+ # For more information on this command refer to user manual or inline help in interactive mode.
7
+ def play(cmd)
8
+ if cmd.params.empty?
9
+ # Estos los consideramos comportamientos inteligentes
10
+ # porque checan el contexto y toman una descision,
11
+ # por lo tanto la logica no aplica a el comando play normal
12
+
13
+ # tocar mientras ya estamos tocando algo??
14
+ return failure("What you mean? Im already playing!") if playing?
15
+ # quitamos la pausa
16
+ return execute "pause off" if paused?
17
+ # iniciamos ultima la reproduccion desde el principio
18
+ if stopped? && current_song
19
+ curr_song = player_object :song
20
+ return execute "play @song"
21
+ end
22
+ # tocamos toda la libreria
23
+ songs = whole_library
24
+ return failure("No music connected! You should try 'connect /home/yoo/music => main' first") if songs.empty?
25
+ playlists[:current, :focus] <= songs
26
+
27
+ else
28
+ songs = select_songs_with cmd
29
+ # checamos si el tipo de comando es para programar una
30
+ # nueva playlist o solo para tocar una cancion
31
+ if play_inline?(cmd)
32
+ playlists[:queue] << songs
33
+ else
34
+ playlists[:current] <= songs
35
+ end
36
+ end
37
+
38
+ return success(playlist: songs) + execute("next no_history")
39
+ end
40
+
41
+ # For more information on this command refer to user manual or inline help in interactive mode.
42
+ def pause(cmd)
43
+ if cmd.params.empty?
44
+ is_pause = !paused?
45
+ else
46
+ is_pause = cmd.params(:boolean).first.value
47
+ end
48
+
49
+ if is_pause
50
+ pause_in_player
51
+ else
52
+ resume_in_player
53
+ end
54
+
55
+ success(message: is_pause ? "Holding your horses" : "Letting it flow", paused: paused?, stopped: stopped?, playing: playing?)
56
+ end
57
+
58
+ # For more information on this command refer to user manual or inline help in interactive mode.
59
+ def stop(cmd)
60
+ stop_in_player
61
+ success(message: "Stoped it!", paused: paused?, stopped: stopped?, playing: playing?)
62
+ end
63
+
64
+ # For more information on this command refer to user manual or inline help in interactive mode.
65
+ def next(cmd)
66
+ if playlists[:queue].empty?
67
+ unless cmd.params(:literal).any?{|p| p.value == 'no_history'}
68
+ playlists[:history] << current_song
69
+ end
70
+ playlists[:queue] << playlists[:current].next
71
+ end
72
+
73
+ # aqui enviamos al reproductor externo a tocar
74
+ play_queue
75
+
76
+ return success(message: "Now playing #{current_song}", now_playing: current_song)
77
+ end
78
+
79
+ # For more information on this command refer to user manual or inline help in interactive mode.
80
+ def prev(cmd)
81
+ playlists[:queue] << playlists[:history].pop
82
+ playlists[:current].rewind_by 1
83
+ execute("next no_history")
84
+ end
85
+
86
+ # For more information on this command refer to user manual or inline help in interactive mode.
87
+ def quit(cmd)
88
+ quit_in_player
89
+ terminate_session
90
+ return success("See you next time!") unless in_session?
91
+ return failure("Oops! You should use Ctr-c or throw water to the CPU NOW!!!!")
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,368 @@
1
+ module CultomePlayer
2
+ module Player
3
+ module BuiltinHelp
4
+ def description_play
5
+ "Creates a playlist and start playing. Resumes playback."
6
+ end
7
+
8
+ def description_pause
9
+ "Toggle pause."
10
+ end
11
+
12
+ def description_stop
13
+ "Stops current playback."
14
+ end
15
+
16
+ def description_next
17
+ "Play the next song in current playlist."
18
+ end
19
+
20
+ def description_prev
21
+ "Play the last song in history playlist."
22
+ end
23
+
24
+ def description_quit
25
+ "Quits the playback and exit the player."
26
+ end
27
+
28
+ def description_search
29
+ "Search into the connected music drives."
30
+ end
31
+
32
+ def description_show
33
+ "Shows representations of diverse objects in the player."
34
+ end
35
+
36
+ def description_enqueue
37
+ "Append a playlist to the queue playlist."
38
+ end
39
+
40
+ def description_shuffle
41
+ "Check the state of shuffle. Can turn it on and off."
42
+ end
43
+
44
+ def description_connect
45
+ "Add or reconnect a drive to the music library."
46
+ end
47
+
48
+ def description_disconnect
49
+ "Disconnect a drive from the music library."
50
+ end
51
+
52
+ def description_ff
53
+ "Fast forward 10 seconds the current playback."
54
+ end
55
+
56
+ def description_fb
57
+ "Fast backward 10 seconds the current playback."
58
+ end
59
+
60
+ def description_repeat
61
+ "Repeat the current playback from the begining."
62
+ end
63
+
64
+ def usage_cultome_player
65
+ cmds_availables = methods.grep(/^description_/).collect do |method_name|
66
+ [method_name.to_s.gsub("description_", ""), send(method_name)]
67
+ end
68
+
69
+ border_width = 5
70
+ cmd_column_width = cmds_availables.reduce(0){|sum, arr| sum > arr[0].length ? sum : arr[0].length}
71
+ desc_column_width = 90 - border_width - cmd_column_width
72
+
73
+ cmds_availables_formatted = cmds_availables.collect do |arr|
74
+ " " + arrange_in_columns(arr, [cmd_column_width, desc_column_width], border_width)
75
+ end
76
+
77
+ return <<-HELP
78
+ usage: <command> [param param ...]
79
+
80
+ The following commands are availables:
81
+ #{cmds_availables_formatted.join("\n")}
82
+
83
+ The params can be of any of these types:
84
+ criterio A key:value pair. Only a,b,t are recognized.
85
+ literal Any valid string. If contains spaces quotes or double quotes are required.
86
+ object Identifiers preceded with an @.
87
+ number An integer number.
88
+ path A string representing a path in filesystem.
89
+ boolean Can be true, false. Accept some others.
90
+ ip An IP4 address.
91
+
92
+ See 'help <command>' for more information on a especific command.
93
+
94
+ Refer to the README file for a complete user guide.
95
+ HELP
96
+ end
97
+
98
+ def usage_play
99
+ return <<-USAGE
100
+ usage: play [literal|number|criteria|object]
101
+
102
+ This command is intelligent, so it reacts depending on its context.
103
+ Without parameters, if the current playlist is empty, play without parameters crate a playlist with all the music in your library and start playing, also if you stop or pause the player, this command resumes the playback where you left it.
104
+ With parameters works as if you make a search and then create a playlist from the results.
105
+ If you select songs from the *focus* playlist, this command dont replace the *current* playlist, just append the song to the *queue* playlist.
106
+
107
+ Examples:
108
+
109
+ Create a playlist with songs that contains "super" in its title, artist name o album name:
110
+ play super
111
+
112
+ Create a playlist with all the songs in the current album:
113
+ play @album
114
+
115
+ Create a playlist with songs whose artists contains the string "llica" or "gori":
116
+ play a:llica a:gori
117
+
118
+ If you use a command that modifies the *focus* playlist, you can play songs associated with their index in the list:
119
+ play 1 5 9
120
+
121
+ USAGE
122
+ end
123
+
124
+ def usage_pause
125
+ return <<-USAGE
126
+ usage: pause [boolean]
127
+
128
+ Without parameters, toggle pause. Whit a boolean parameter... well, just you what is been told.
129
+
130
+ Examples:
131
+
132
+ If there is an active playback, pause it:
133
+ pause
134
+
135
+ If is paused, resume:
136
+ pause
137
+
138
+ If you wanna make sure is paused:
139
+ pause on
140
+
141
+ USAGE
142
+ end
143
+
144
+ def usage_stop
145
+ return <<-USAGE
146
+ usage: stop
147
+
148
+ Stop the current playback. If *play* is called after *stop*, the playback will begin again.
149
+
150
+ Examples:
151
+
152
+ Stop current playback:
153
+ stop
154
+
155
+ USAGE
156
+ end
157
+
158
+ def usage_next
159
+ return <<-USAGE
160
+ usage: next
161
+
162
+ Select the next song in the *current* playlist and play it, if there is any or if *repeat* is on.
163
+
164
+ Examples:
165
+
166
+ You dont like the music and wanna try lunk with the next:
167
+ next
168
+
169
+ USAGE
170
+ end
171
+
172
+ def usage_prev
173
+ return <<-USAGE
174
+ usage: prev
175
+
176
+ Select the last song in the *history* playlist and plays it again.
177
+
178
+ Examples:
179
+
180
+ "OMG! I love that song, lets hear it again":
181
+ prev
182
+
183
+ USAGE
184
+ end
185
+
186
+ def usage_quit
187
+ return <<-USAGE
188
+ usage: quit
189
+
190
+ Stop playback and exit player.
191
+
192
+ Examples:
193
+
194
+ You wanna quit the player:
195
+ quit
196
+
197
+ USAGE
198
+ end
199
+
200
+ def usage_search
201
+ return <<-USAGE
202
+ usage: search (literal|criteria)
203
+
204
+ Search in the connected drives for song that fullfil the parameters criteria.
205
+ When a search is made, the results go to the *search* and *focus* playlist. From there, they can be manipulated.
206
+ To understand the results, I will explain the rules the search algorith uses:
207
+ 1. Similar criteria creates an OR filter and differents create AND filter.
208
+ Example:
209
+
210
+ search t:tres a:uno a:dos
211
+
212
+ This extract songs whose title contains "tres" and whose artist contains "uno" OR "dos" in their names
213
+
214
+ 2. Literal words form and OR
215
+
216
+ search uno dos tres
217
+
218
+ This extract songs whose title, artist name or album name contains "uno" OR "dos" OR "tres".
219
+
220
+ Examples:
221
+
222
+ Get all my Gorillaz's songs
223
+ search a:gorillaz
224
+
225
+ Im in love and I wanna hear love-related songs:
226
+ search love
227
+
228
+ USAGE
229
+ end
230
+
231
+ def usage_show
232
+ return <<-USAGE
233
+ usage: show [number|object]
234
+
235
+ Display a representation of player's objects.
236
+ Without parameters show the status of the current playback, if any.
237
+
238
+ Examples:
239
+
240
+ See how much time left of this song:
241
+ show
242
+
243
+ See what songs are in the *focus* playlist:
244
+ show @focus
245
+
246
+ USAGE
247
+ end
248
+
249
+ def usage_enqueue
250
+ return <<-USAGE
251
+ usage: enqueue [literal|number|criteria|object]
252
+
253
+ Search, pick and extract the song defined in the parameters and creates a playlist that is appended to the *queue* playlist.
254
+ Similar to a search with the literal and criteria parameters, but with number takes songs from the *focus* playlist, and with object extract the songs from the respective object.
255
+
256
+ Examples:
257
+
258
+ After the current song I want to play all Jugulator album:
259
+ enqueue b:Jugulator
260
+
261
+ Play te third song in the list after this:
262
+ enqueue 3
263
+
264
+ USAGE
265
+ end
266
+
267
+ def usage_shuffle
268
+ return <<-USAGE
269
+ usage: shuffle [boolean]
270
+
271
+ Without parameters, check the shuffle state. When parameters are provided, you can turn it on and off.
272
+
273
+ Examples:
274
+
275
+ Is shuffling?:
276
+ shuffle
277
+
278
+ Turn shuffle off:
279
+ shuffle off
280
+
281
+ USAGE
282
+ end
283
+
284
+ def usage_connect
285
+ return <<-USAGE
286
+ usage: connect (literal | path => literal)
287
+
288
+ This command allows you to create a new drive or reconnect an existing one.
289
+ A drive is a logical folder or container that groups songs by path. This player uses this concept to organize your music directories.
290
+ You can disconnect it to avoid the music search look in there.
291
+
292
+ Examples:
293
+
294
+ To connect a drive you use the following form:
295
+ connect path/to/my/music => my_library
296
+
297
+ To reconnect the same drive in the future (if you disconnect it for some reason):
298
+ connect my_library
299
+
300
+ USAGE
301
+ end
302
+
303
+ def usage_disconnect
304
+ return <<-USAGE
305
+ usage: disconnect literal
306
+
307
+ Disconnect a previously connected drive. With the drive disconnected the searches are not made in this drives.
308
+
309
+ Examples:
310
+
311
+ Disconnect a temporal download music drive:
312
+ disconnect my_downloads
313
+
314
+ USAGE
315
+ end
316
+
317
+ def usage_ff
318
+ return <<-USAGE
319
+ usage: ff [number]
320
+
321
+ Fast forward the current playback 10 seconds by default. This time can be customized passing a parameter with the seconds to fast forward.
322
+
323
+ Examples:
324
+
325
+ Fas forward 10 seconds:
326
+ ff
327
+
328
+ Fas forward 35 seconds:
329
+ ff 35
330
+
331
+ USAGE
332
+ end
333
+
334
+ def usage_fb
335
+ return <<-USAGE
336
+ usage: fb [number]
337
+
338
+ Fast backward the current playback 10 seconds by default. This time can be customized passing a parameter with the seconds to fast backward.
339
+
340
+ Examples:
341
+
342
+ Fas backward 10 seconds:
343
+ fb
344
+
345
+ Fas backward 5 seconds:
346
+ fb 5
347
+
348
+ USAGE
349
+ end
350
+
351
+ def usage_repeat
352
+ return <<-USAGE
353
+ usage: stop
354
+
355
+ Stop current playback.
356
+
357
+ Examples
358
+
359
+ Stop current playback:
360
+ stop
361
+
362
+ USAGE
363
+ end
364
+
365
+
366
+ end
367
+ end
368
+ end