listlace 0.0.1 → 0.0.2
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.
- 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
|