cultome_player 2.0.0
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 +7 -0
- data/.coveralls.yml +1 -0
- data/.gitignore +24 -0
- data/.rspec +2 -0
- data/.travis.yml +7 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +325 -0
- data/Rakefile +8 -0
- data/bin/cultome_player +39 -0
- data/config/environment.yml +28 -0
- data/cultome_player.gemspec +35 -0
- data/db/001_create_schema.rb +58 -0
- data/lib/cultome_player.rb +107 -0
- data/lib/cultome_player/command.rb +11 -0
- data/lib/cultome_player/command/language.rb +61 -0
- data/lib/cultome_player/command/processor.rb +165 -0
- data/lib/cultome_player/command/reader.rb +86 -0
- data/lib/cultome_player/environment.rb +130 -0
- data/lib/cultome_player/events.rb +29 -0
- data/lib/cultome_player/media.rb +47 -0
- data/lib/cultome_player/objects.rb +15 -0
- data/lib/cultome_player/objects/album.rb +21 -0
- data/lib/cultome_player/objects/artist.rb +18 -0
- data/lib/cultome_player/objects/command.rb +37 -0
- data/lib/cultome_player/objects/drive.rb +26 -0
- data/lib/cultome_player/objects/genre.rb +16 -0
- data/lib/cultome_player/objects/parameter.rb +37 -0
- data/lib/cultome_player/objects/response.rb +42 -0
- data/lib/cultome_player/objects/song.rb +38 -0
- data/lib/cultome_player/player.rb +13 -0
- data/lib/cultome_player/player/adapter.rb +14 -0
- data/lib/cultome_player/player/adapter/mpg123.rb +143 -0
- data/lib/cultome_player/player/interactive.rb +56 -0
- data/lib/cultome_player/player/interface.rb +13 -0
- data/lib/cultome_player/player/interface/basic.rb +96 -0
- data/lib/cultome_player/player/interface/builtin_help.rb +368 -0
- data/lib/cultome_player/player/interface/extended.rb +199 -0
- data/lib/cultome_player/player/interface/helper.rb +300 -0
- data/lib/cultome_player/player/playlist.rb +280 -0
- data/lib/cultome_player/plugins.rb +23 -0
- data/lib/cultome_player/plugins/help.rb +58 -0
- data/lib/cultome_player/state_checker.rb +74 -0
- data/lib/cultome_player/utils.rb +95 -0
- data/lib/cultome_player/version.rb +3 -0
- data/spec/config.yml +0 -0
- data/spec/cultome_player/command/processor_spec.rb +168 -0
- data/spec/cultome_player/command/reader_spec.rb +45 -0
- data/spec/cultome_player/cultome_player_spec.rb +17 -0
- data/spec/cultome_player/environment_spec.rb +65 -0
- data/spec/cultome_player/events_spec.rb +22 -0
- data/spec/cultome_player/media_spec.rb +41 -0
- data/spec/cultome_player/player/adapter/mpg123_spec.rb +82 -0
- data/spec/cultome_player/player/interface/basic_spec.rb +168 -0
- data/spec/cultome_player/player/interface/extended/connect_spec.rb +117 -0
- data/spec/cultome_player/player/interface/extended/search_spec.rb +90 -0
- data/spec/cultome_player/player/interface/extended/show_spec.rb +36 -0
- data/spec/cultome_player/player/interface/extended/shuffle_spec.rb +26 -0
- data/spec/cultome_player/player/interface/extended_spec.rb +136 -0
- data/spec/cultome_player/player/interface/helper_spec.rb +63 -0
- data/spec/cultome_player/player/interface_spec.rb +17 -0
- data/spec/cultome_player/player/playlist_spec.rb +301 -0
- data/spec/cultome_player/plugins/help_spec.rb +21 -0
- data/spec/cultome_player/plugins_spec.rb +19 -0
- data/spec/cultome_player/utils_spec.rb +15 -0
- data/spec/spec_helper.rb +108 -0
- data/spec/test/uno/dos/dos.mp3 +0 -0
- data/spec/test/uno/dos/tres/tres.mp3 +0 -0
- data/spec/test/uno/uno.mp3 +0 -0
- data/tasks/console.rake +19 -0
- data/tasks/db.rake +19 -0
- data/tasks/run.rake +7 -0
- 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
|