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 CHANGED
@@ -1,4 +1,2 @@
1
1
  source :rubygems
2
2
  gemspec
3
-
4
- gem "mplayer-ruby", git: "git://github.com/yjerem/mplayer-ruby.git"
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.1)
4
+ listlace (0.0.2)
12
5
  activerecord
13
6
  activesupport
14
- mplayer-ruby
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
- I'm thinking it'll go a little something
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
- def play
3
- if $player.queue.empty?
4
- puts "Nothing to play."
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
- $player.start
7
- track = $player.current_track
8
- puts "Now Playing: #{track.artist} - #{track.name} (0:00 / #{track.formatted_total_time})"
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
@@ -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 :mplayer, :queue, :current_track
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 @queue.empty?
40
+ unless empty?
41
+ @started = true
14
42
  @current_track = @queue.first
15
43
  @current_track_index = 0
16
- _play @current_track
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 _mplayer_alive?
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
- private
38
-
39
- def _play(track)
40
- @mplayer.quit if _mplayer_alive?
41
- @mplayer = MPlayer::Slave.new track.location
57
+ def pause
58
+ if not paused?
59
+ @paused = true
60
+ @mplayer.command "pause"
61
+ end
62
+ end
42
63
 
43
- Thread.new do
44
- Process.wait(@mplayer.pid)
45
- $player.next
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 _mplayer_alive?
50
- if @mplayer
51
- begin
52
- Process.getpgid(@mplayer.pid)
53
- true
54
- rescue Errno::ESRCH
55
- false
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 "mplayer-ruby"
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.1"
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 mplayer-ruby).each do |gem_name|
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.1
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: mplayer-ruby
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