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 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