listlace 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +0 -2
- data/Gemfile.lock +2 -10
- data/README +57 -27
- data/lib/listlace/commands/playback.rb +97 -6
- data/lib/listlace/mplayer.rb +32 -0
- data/lib/listlace/player.rb +88 -29
- data/lib/listlace.rb +3 -1
- data/listlace.gemspec +2 -2
- metadata +3 -2
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,17 +1,10 @@
|
|
1
|
-
GIT
|
2
|
-
remote: git://github.com/yjerem/mplayer-ruby.git
|
3
|
-
revision: ffa7213d1c0340fa79aa794929affba65d4cff28
|
4
|
-
specs:
|
5
|
-
mplayer-ruby (0.1.0)
|
6
|
-
open4 (>= 1.0.1)
|
7
|
-
|
8
1
|
PATH
|
9
2
|
remote: .
|
10
3
|
specs:
|
11
|
-
listlace (0.0.
|
4
|
+
listlace (0.0.2)
|
12
5
|
activerecord
|
13
6
|
activesupport
|
14
|
-
|
7
|
+
open4
|
15
8
|
plist
|
16
9
|
pry
|
17
10
|
sqlite3
|
@@ -52,5 +45,4 @@ PLATFORMS
|
|
52
45
|
|
53
46
|
DEPENDENCIES
|
54
47
|
listlace!
|
55
|
-
mplayer-ruby!
|
56
48
|
rake
|
data/README
CHANGED
@@ -13,31 +13,61 @@ double-click.
|
|
13
13
|
Conjuring audio with spells is much more
|
14
14
|
appropriate, don't you think?
|
15
15
|
|
16
|
-
|
17
|
-
like this. Observe:
|
18
|
-
|
19
|
-
$ listlace
|
20
|
-
Hello, you have 1466 songs.
|
21
|
-
ll> muse = album("Origin of Symmetry") + song("Blackout", artist: "Muse")
|
22
|
-
=> Playlist (12 songs)
|
23
|
-
ll> maps = album("Turning The Mind") - song("Die Happy, Die Smiling")
|
24
|
-
=> Playlist (11 songs)
|
25
|
-
ll> playlist = muse.shuffle + maps.shuffle
|
26
|
-
=> Playlist (23 songs)
|
27
|
-
ll> playlist.play
|
28
|
-
Now Playing: Blackout - Muse (0:00 / 4:22)
|
29
|
-
ll> p
|
30
|
-
Paused: Blackout - Muse (0:07 / 4:22)
|
31
|
-
ll> seek 3..10
|
32
|
-
Paused: Blackout - Muse (3:10 / 4:22)
|
33
|
-
ll> p
|
34
|
-
Now Playing: Blackout - Muse (3:10 / 4:22)
|
35
|
-
ll> playlist.save "Maps & Muse"
|
36
|
-
ll> status
|
37
|
-
Playing playlist "Maps & Muse" (1 / 23)
|
38
|
-
Now Playing: Blackout - Muse (4:04 / 4:22)
|
39
|
-
ll> next
|
40
|
-
Now Playing: Space Dementia - Muse (0:00 / 6:21)
|
41
|
-
|
42
|
-
And so on.
|
16
|
+
-- install
|
43
17
|
|
18
|
+
It's a gem. So do this:
|
19
|
+
|
20
|
+
gem install listlace
|
21
|
+
|
22
|
+
But you also need mplayer. It has to be
|
23
|
+
at /usr/bin/mplayer, for now.
|
24
|
+
|
25
|
+
-- usage
|
26
|
+
|
27
|
+
The gem gives you an executable called
|
28
|
+
'listlace'. So do this:
|
29
|
+
|
30
|
+
$ listlace
|
31
|
+
|
32
|
+
It will make a '.listlace' directory in
|
33
|
+
$HOME, where the database of tracks and
|
34
|
+
playlists is stored. Then it will give you
|
35
|
+
a prompt. Don't be alarmed, it speaks
|
36
|
+
Ruby.
|
37
|
+
|
38
|
+
The only way to populate the database right
|
39
|
+
now is to import your iTunes library.
|
40
|
+
That goes a little something like this:
|
41
|
+
|
42
|
+
>> import_from_itunes "/Users/jeremy/Music/iTunes/iTunes Music Library.xml"
|
43
|
+
|
44
|
+
Now you can play your music.
|
45
|
+
|
46
|
+
-- p's and q's
|
47
|
+
|
48
|
+
p is the most important command. It's the
|
49
|
+
play command. It's also the pause/resume
|
50
|
+
command. You can pass it some tracks or a
|
51
|
+
playlist, and it will queue up the music
|
52
|
+
and start playing it, sequentially. If you
|
53
|
+
don't pass it anything, that's when it acts
|
54
|
+
as a pause/resume button.
|
55
|
+
|
56
|
+
q is the queue command. You can pass it some
|
57
|
+
tracks or a playlist and it'll add them to the
|
58
|
+
queue. The queue is just an array of tracks
|
59
|
+
to be played in order. The p command by
|
60
|
+
itself will start playing the queue.
|
61
|
+
|
62
|
+
-- commands
|
63
|
+
|
64
|
+
* playback
|
65
|
+
- p: play/pause/resume
|
66
|
+
- stop: stop playback
|
67
|
+
- restart: seek back to the beginning of the current track
|
68
|
+
- back: go back a song
|
69
|
+
- skip: go to the next song
|
70
|
+
- status: show what's currently playing, as well as other information
|
71
|
+
* queueing
|
72
|
+
- q: append some tracks to the queue, or get the queue
|
73
|
+
- clear: clear the queue
|
@@ -1,15 +1,106 @@
|
|
1
1
|
module Listlace
|
2
|
-
|
3
|
-
|
4
|
-
|
2
|
+
# The play command. With no arguments, it either resumes playback or starts
|
3
|
+
# playing the queue. With arguments, it replaces the queue with the given
|
4
|
+
# tracks and starts playing.
|
5
|
+
def p(*tracks)
|
6
|
+
if tracks.empty?
|
7
|
+
if $player.paused?
|
8
|
+
$player.resume
|
9
|
+
status :playing
|
10
|
+
elsif $player.started?
|
11
|
+
$player.pause
|
12
|
+
status :playing
|
13
|
+
else
|
14
|
+
if $player.empty?
|
15
|
+
puts "Nothing to play."
|
16
|
+
else
|
17
|
+
$player.start
|
18
|
+
track = $player.current_track
|
19
|
+
status :playing
|
20
|
+
end
|
21
|
+
end
|
5
22
|
else
|
6
|
-
|
7
|
-
|
8
|
-
|
23
|
+
stop
|
24
|
+
clear
|
25
|
+
q *tracks
|
26
|
+
p
|
9
27
|
end
|
10
28
|
end
|
11
29
|
|
30
|
+
# Stops playback. The queue is still intact, but goes back to the beginning
|
31
|
+
# when playback is started again.
|
12
32
|
def stop
|
13
33
|
$player.stop
|
34
|
+
puts "Stopped."
|
35
|
+
end
|
36
|
+
|
37
|
+
# Start the current track from the beginning.
|
38
|
+
def restart
|
39
|
+
$player.restart
|
40
|
+
status :playing
|
41
|
+
end
|
42
|
+
|
43
|
+
# Go back one song in the queue.
|
44
|
+
def back
|
45
|
+
if $player.back
|
46
|
+
status :playing
|
47
|
+
else
|
48
|
+
puts "End of queue."
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Go directly to the next song in the queue.
|
53
|
+
def skip
|
54
|
+
if $player.skip
|
55
|
+
status :playing
|
56
|
+
else
|
57
|
+
puts "End of queue."
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# The queue command. Simply appends tracks to the queue. Tracks can be
|
62
|
+
# specified by a single Track, a Playlist, an ActiveRecord::Relation, or an
|
63
|
+
# Array containing any of the above. With or without arguments, it returns the
|
64
|
+
# queue as an Array of Tracks, so this can be used as an accessor method.
|
65
|
+
def q(*tracks)
|
66
|
+
tracks.each do |playlist_or_track|
|
67
|
+
case playlist_or_track
|
68
|
+
when Track
|
69
|
+
$player.queue playlist_or_track
|
70
|
+
when Playlist
|
71
|
+
q *playlist_or_track.tracks
|
72
|
+
when Array
|
73
|
+
q *playlist_or_track
|
74
|
+
when ActiveRecord::Relation
|
75
|
+
q *playlist_or_track.all
|
76
|
+
end
|
77
|
+
end
|
78
|
+
$player.queue
|
79
|
+
end
|
80
|
+
|
81
|
+
# Clears the queue.
|
82
|
+
def clear
|
83
|
+
$player.clear
|
84
|
+
puts "Queue cleared."
|
85
|
+
end
|
86
|
+
|
87
|
+
def status(type = [:playlist, :playing])
|
88
|
+
case type
|
89
|
+
when Array
|
90
|
+
type.each { |t| status t }
|
91
|
+
when :playlist
|
92
|
+
#nop
|
93
|
+
when :playing
|
94
|
+
if $player.started?
|
95
|
+
s = $player.paused? ? "Paused" : "Now Playing"
|
96
|
+
name = $player.current_track.name
|
97
|
+
artist = $player.current_track.artist
|
98
|
+
time = $player.formatted_current_time
|
99
|
+
total_time = $player.current_track.formatted_total_time
|
100
|
+
puts "%s: %s - %s (%s / %s)" % [s, name, artist, time, total_time]
|
101
|
+
else
|
102
|
+
puts "Stopped."
|
103
|
+
end
|
104
|
+
end
|
14
105
|
end
|
15
106
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Listlace
|
2
|
+
# This is a simple MPlayer wrapper, it just handles opening the MPlayer
|
3
|
+
# process, hooking into when mplayer exits (when the song is done), and
|
4
|
+
# issuing commands through the slave protocol.
|
5
|
+
class MPlayer
|
6
|
+
def initialize(track, &on_quit)
|
7
|
+
cmd = "/usr/bin/mplayer -slave -quiet #{Shellwords.shellescape(track.location)}"
|
8
|
+
@pid, @stdin, @stdout, @stderr = Open4.popen4(cmd)
|
9
|
+
|
10
|
+
@quit_hook = Thread.new do
|
11
|
+
Process.wait(@pid)
|
12
|
+
on_quit.call
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def command(cmd)
|
17
|
+
@stdin.puts cmd
|
18
|
+
end
|
19
|
+
|
20
|
+
def quit
|
21
|
+
@quit_hook.kill
|
22
|
+
command "quit" if alive?
|
23
|
+
end
|
24
|
+
|
25
|
+
def alive?
|
26
|
+
Process.getpgid(@pid)
|
27
|
+
true
|
28
|
+
rescue Errno::ESRCH
|
29
|
+
false
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/listlace/player.rb
CHANGED
@@ -1,60 +1,119 @@
|
|
1
1
|
module Listlace
|
2
|
+
# This is the music box. It contains a queue, which is an array of tracks. It
|
3
|
+
# then plays these tracks sequentially. The buttons for play, pause, next,
|
4
|
+
# previous, etc. are all located here.
|
2
5
|
class Player
|
3
|
-
attr_accessor :
|
6
|
+
attr_accessor :current_track
|
4
7
|
|
5
8
|
def initialize
|
6
9
|
@mplayer = nil
|
7
10
|
@queue = []
|
8
11
|
@current_track = nil
|
9
12
|
@current_track_index = nil
|
13
|
+
@paused = false
|
14
|
+
@started = false
|
15
|
+
end
|
16
|
+
|
17
|
+
def queue(track = nil)
|
18
|
+
@queue << track if track.is_a? Track
|
19
|
+
@queue.dup
|
20
|
+
end
|
21
|
+
|
22
|
+
def clear
|
23
|
+
stop
|
24
|
+
@queue = []
|
25
|
+
end
|
26
|
+
|
27
|
+
def empty?
|
28
|
+
@queue.empty?
|
29
|
+
end
|
30
|
+
|
31
|
+
def paused?
|
32
|
+
@paused
|
33
|
+
end
|
34
|
+
|
35
|
+
def started?
|
36
|
+
@started
|
10
37
|
end
|
11
38
|
|
12
39
|
def start
|
13
|
-
unless
|
40
|
+
unless empty?
|
41
|
+
@started = true
|
14
42
|
@current_track = @queue.first
|
15
43
|
@current_track_index = 0
|
16
|
-
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
def next
|
21
|
-
@current_track_index += 1
|
22
|
-
@current_track = @queue[@current_track_index]
|
23
|
-
if @current_track
|
24
|
-
_play @current_track
|
25
|
-
else
|
26
|
-
stop
|
44
|
+
load_track(@current_track)
|
27
45
|
end
|
28
46
|
end
|
29
47
|
|
30
48
|
def stop
|
31
|
-
@mplayer.quit if
|
49
|
+
@mplayer.quit if @mplayer
|
32
50
|
@mplayer = nil
|
33
51
|
@current_track = nil
|
34
52
|
@current_track_index = nil
|
53
|
+
@paused = false
|
54
|
+
@started = false
|
35
55
|
end
|
36
56
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
57
|
+
def pause
|
58
|
+
if not paused?
|
59
|
+
@paused = true
|
60
|
+
@mplayer.command "pause"
|
61
|
+
end
|
62
|
+
end
|
42
63
|
|
43
|
-
|
44
|
-
|
45
|
-
|
64
|
+
def resume
|
65
|
+
if paused?
|
66
|
+
@paused = false
|
67
|
+
if @mplayer && @mplayer.alive?
|
68
|
+
@mplayer.command "pause"
|
69
|
+
else
|
70
|
+
load_track @current_track
|
71
|
+
end
|
46
72
|
end
|
47
73
|
end
|
48
74
|
|
49
|
-
def
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
75
|
+
def restart
|
76
|
+
change_track(0)
|
77
|
+
end
|
78
|
+
|
79
|
+
def back
|
80
|
+
change_track(-1)
|
81
|
+
end
|
82
|
+
|
83
|
+
def skip
|
84
|
+
change_track(1)
|
85
|
+
end
|
86
|
+
|
87
|
+
def current_time
|
88
|
+
0
|
89
|
+
end
|
90
|
+
|
91
|
+
def formatted_current_time
|
92
|
+
"0:00"
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
def change_track(by = 1)
|
98
|
+
@current_track_index += by
|
99
|
+
@current_track = @queue[@current_track_index]
|
100
|
+
if @current_track && @current_track_index >= 0
|
101
|
+
if paused?
|
102
|
+
@mplayer.quit if @mplayer
|
103
|
+
else
|
104
|
+
load_track(@current_track)
|
56
105
|
end
|
106
|
+
true
|
107
|
+
else
|
108
|
+
stop
|
109
|
+
false
|
57
110
|
end
|
58
111
|
end
|
112
|
+
|
113
|
+
def load_track(track)
|
114
|
+
@mplayer.quit if @mplayer
|
115
|
+
@mplayer = MPlayer.new(track) { send :change_track }
|
116
|
+
@paused = false
|
117
|
+
end
|
59
118
|
end
|
60
119
|
end
|
data/lib/listlace.rb
CHANGED
@@ -5,11 +5,13 @@ module Listlace
|
|
5
5
|
PROMPT = [proc { ">> " }, proc { " | " }]
|
6
6
|
end
|
7
7
|
|
8
|
-
require "
|
8
|
+
require "open4"
|
9
|
+
require "shellwords"
|
9
10
|
require "active_record"
|
10
11
|
|
11
12
|
require "listlace/database"
|
12
13
|
require "listlace/player"
|
14
|
+
require "listlace/mplayer"
|
13
15
|
|
14
16
|
require "listlace/models/track"
|
15
17
|
require "listlace/models/playlist"
|
data/listlace.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "listlace"
|
3
|
-
s.version = "0.0.
|
3
|
+
s.version = "0.0.2"
|
4
4
|
s.date = "2012-08-22"
|
5
5
|
s.summary = "A music player in a REPL."
|
6
6
|
s.description = "Listlace is a music player which is interacted with through a Ruby REPL."
|
@@ -16,7 +16,7 @@ Gem::Specification.new do |s|
|
|
16
16
|
s.files += ["bin/listlace"]
|
17
17
|
s.files += Dir["lib/**/*.rb"]
|
18
18
|
|
19
|
-
%w(pry plist sqlite3 activerecord activesupport
|
19
|
+
%w(pry plist sqlite3 activerecord activesupport open4).each do |gem_name|
|
20
20
|
s.add_runtime_dependency gem_name
|
21
21
|
end
|
22
22
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: listlace
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -92,7 +92,7 @@ dependencies:
|
|
92
92
|
- !ruby/object:Gem::Version
|
93
93
|
version: '0'
|
94
94
|
- !ruby/object:Gem::Dependency
|
95
|
-
name:
|
95
|
+
name: open4
|
96
96
|
requirement: !ruby/object:Gem::Requirement
|
97
97
|
none: false
|
98
98
|
requirements:
|
@@ -144,6 +144,7 @@ files:
|
|
144
144
|
- lib/listlace/models/playlist.rb
|
145
145
|
- lib/listlace/models/playlist_item.rb
|
146
146
|
- lib/listlace/models/track.rb
|
147
|
+
- lib/listlace/mplayer.rb
|
147
148
|
- lib/listlace/player.rb
|
148
149
|
- lib/listlace.rb
|
149
150
|
homepage: http://github.com/yjerem/listlace
|