anyplayer 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.
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
data/Gemfile CHANGED
@@ -1,5 +1,7 @@
1
1
  source "http://rubygems.org"
2
2
 
3
+ gem "rake"
4
+
3
5
  # Gem dependencies in anyplayer.gemspec
4
6
  gemspec
5
7
 
@@ -0,0 +1,18 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ anyplayer (0.0.2)
5
+
6
+ GEM
7
+ remote: http://rubygems.org/
8
+ specs:
9
+ minitest (4.1.0)
10
+ rake (0.9.2.2)
11
+
12
+ PLATFORMS
13
+ ruby
14
+
15
+ DEPENDENCIES
16
+ anyplayer!
17
+ minitest
18
+ rake
data/Rakefile CHANGED
@@ -1,2 +1,11 @@
1
1
  require 'bundler'
2
+ require 'rake/testtask'
3
+
2
4
  Bundler::GemHelper.install_tasks
5
+
6
+ task :default => :test
7
+
8
+ Rake::TestTask.new do |t|
9
+ t.pattern = "test/*_test.rb"
10
+ t.verbose = true
11
+ end
@@ -1,12 +1,71 @@
1
1
  Anyplayer
2
2
  =========
3
3
 
4
- Ruby library to interact with the running music player (iTunes, Rythmbox, MPD, XMMS).
4
+ Interacts with the currently running music player. Supports iTunes OS X, iTunes Windows,
5
+ Rythmbox, MPD & XMMS2.
5
6
 
6
- require 'anyplayer'
7
- player = Anyplayer::launched
8
- player.name # => Rythmbox
9
- player.track # => "Frontier Psychiatrist"
10
- player.next
11
- player.track # => "Ready For The Floor"
7
+ Install
8
+ -------
12
9
 
10
+ ```sh
11
+ $ gem install anyplayer
12
+ ```
13
+
14
+ Use it in your terminal
15
+ -----------------------
16
+
17
+ ```sh
18
+ $ anyplayer artist # artist of the current track
19
+ New Order
20
+ $ anyplayer track # name of the current track
21
+ Blue Monday
22
+ $ anyplayer album
23
+ Power, Corruption & Lies
24
+ $ anyplayer next # changes track forward
25
+ $ anyplayer prev # backward
26
+ $ anyplayer playpause # pauses if it is playing, plays if it's paused
27
+ $ anyplayer play
28
+ $ anyplayer pause
29
+ $ anyplayer voldown # put the volume somewhat up
30
+ $ anyplayer volup # down
31
+ $ anyplayer volume # prints the volume percentage
32
+ 100
33
+ $ anyplayer vote # votes to go to next song (default number of votes is 5)
34
+ $ anyplayer name
35
+ iTunes
36
+ $ anyplayer launched && echo "a player is running" || echo "nothing running"
37
+ a player is running
38
+ ```
39
+
40
+ Or in Ruby
41
+ ----------
42
+
43
+ ```ruby
44
+ require 'anyplayer'
45
+ player = Anyplayer::launched
46
+
47
+ player.launched? # => true
48
+ player.name # => Rythmbox
49
+ player.artist # => "The Avalanches"
50
+ player.track # => "Frontier Psychiatrist"
51
+ # …
52
+ ```
53
+
54
+ Or in a browser
55
+ ----------------
56
+
57
+ With the [So Nice](https://github.com/sunny/so-nice/) Web interface:
58
+
59
+ ![So Nice Screenshot](https://github.com/sunny/so-nice/raw/gh-pages/screenshot.png)
60
+
61
+ Development
62
+ -----------
63
+
64
+ Launch from source:
65
+
66
+ ruby -Ilib bin/anyplayer
67
+
68
+ Install from source:
69
+
70
+ gem build anyplayer.gemspec
71
+ gem install anyplayer-*.gem
@@ -6,8 +6,8 @@ Gem::Specification.new do |s|
6
6
  s.name = "anyplayer"
7
7
  s.version = Anyplayer::VERSION
8
8
  s.platform = Gem::Platform::RUBY
9
- s.authors = ["Sunny Ripert"]
10
- s.email = ["sunny@sunfox.org"]
9
+ s.authors = ["Sunny Ripert", "Gordon Diggs"]
10
+ s.email = ["sunny@sunfox.org", "gordon@gordondiggs.com"]
11
11
  s.homepage = "http://github.com/sunny/anyplayer"
12
12
  s.summary = %q{Interact with the running music player}
13
13
  s.description = %q{Play/pause/skip songs in iTunes, Rythmbox, MPD, XMMS}
@@ -16,4 +16,6 @@ Gem::Specification.new do |s|
16
16
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
17
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
18
  s.require_paths = ["lib"]
19
+
20
+ s.add_development_dependency 'minitest'
19
21
  end
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- encoding: utf-8 -*-
3
+ require 'anyplayer'
4
+
5
+ player = Anyplayer::launched
6
+
7
+ if !player
8
+ puts "Error: no player connected."
9
+ exit 1
10
+ end
11
+
12
+ case ARGV.first
13
+ when "playpause" then player.playpause
14
+ when "play" then player.play
15
+ when "pause" then palyer.pause
16
+ when "next" then player.next
17
+ when "prev" then player.next
18
+ when "voldown" then player.voldown
19
+ when "volup" then player.volup
20
+ when "volume" then puts player.volume
21
+ when "track" then puts player.track
22
+ when "artist" then puts player.artist
23
+ when "album" then puts player.album
24
+ when "vote" then player.vote
25
+ when "name" then puts player.name
26
+ when "launched" then exit(player.launched? ? 0 : 1)
27
+ when "playing" then exit(player.playing? ? 0 : 1)
28
+ when "paused" then exit(player.playing? ? 0 : 1)
29
+ else
30
+ puts <<USAGE
31
+ Usage: #{$0} [command]
32
+
33
+ Where command is one of: playpause, play, pause, next, prev, voldown, volup,
34
+ volume, track, artist, album, vote, name, launched.
35
+
36
+ Player connected: #{player.name}.
37
+ USAGE
38
+ exit(1)
39
+ end
@@ -2,7 +2,7 @@ require "timeout"
2
2
  require "anyplayer/player"
3
3
 
4
4
  module Anyplayer
5
- PLAYERS = :itunes, :rhythmbox, :ituneswindows, :mpd, :xmms2, :amarok
5
+ PLAYERS = [:itunes, :rhythmbox, :ituneswindows, :mpd, :xmms2, :amarok]
6
6
  for player in PLAYERS
7
7
  require "anyplayer/players/#{player}"
8
8
  end
@@ -1,22 +1,68 @@
1
+ # Default Player class that is inherrited by all players.
2
+ #
3
+ # All players should override these methods:
4
+ # launched? (return bool)
5
+ # next
6
+ # prev
7
+ # play
8
+ # pause
9
+ # playpause
10
+ # track (return string)
11
+ # artist (return string)
12
+ # album (return string)
13
+ # voldown
14
+ # volup
15
+ # volume (return int)
16
+ # playing? (return bool)
17
+ # paused? (return bool)
1
18
  module Anyplayer
2
19
  class Player
20
+ DEFAULT_VOTES_TO_SKIP = 5
3
21
 
4
- # Guess the player name
22
+ def initialize
23
+ @votes = 0
24
+ end
25
+
26
+ def launched?
27
+ false
28
+ end
29
+
30
+ # Player name is the classe's, feel free to override it
5
31
  def name
6
32
  self.class.to_s.gsub(/^.*::/, '')
7
33
  end
8
34
 
9
- # Methods to override
10
- def launched?; false; end
11
- def playpause; end
12
- def next; end
13
- def prev; end
14
- def voldown; end
15
- def volup; end
16
- def volume; end
17
- def track; end
18
- def artist; end
19
- def album; end
35
+ def playpause
36
+ paused? ? play : pause
37
+ end
38
+
39
+ # Vote to skip song
40
+ def vote(votes_to_skip = DEFAULT_VOTES_TO_SKIP)
41
+ @votes += 1
42
+ if @votes >= votes_to_skip
43
+ self.next
44
+ reset_votes
45
+ end
46
+ end
47
+
48
+ def votes
49
+ @votes
50
+ end
51
+
52
+ # Root next and prev reset the votes, so be sure to call super
53
+ # in children
54
+ def next
55
+ reset_votes
56
+ end
57
+
58
+ def prev
59
+ reset_votes
60
+ end
61
+
62
+ private
63
+ def reset_votes
64
+ @votes = 0
65
+ end
20
66
 
21
67
  end
22
68
  end
@@ -4,12 +4,22 @@ module Anyplayer
4
4
  tell_to 'PlayPause'
5
5
  end
6
6
 
7
+ def play
8
+ tell_to 'Play'
9
+ end
10
+
11
+ def pause
12
+ tell_to 'Pause'
13
+ end
14
+
7
15
  def prev
8
16
  tell_to 'Prev'
17
+ super
9
18
  end
10
19
 
11
20
  def next
12
21
  tell_to 'Next'
22
+ super
13
23
  end
14
24
 
15
25
  def voldown
@@ -27,17 +37,17 @@ module Anyplayer
27
37
  def track
28
38
  get_metadata('title')
29
39
  end
30
-
40
+
31
41
  def artist
32
42
  get_metadata('artist')
33
43
  end
34
-
44
+
35
45
  def album
36
46
  get_metadata('album')
37
47
  end
38
48
 
39
49
  def launched?
40
- not %x(qdbus org.kde.amarok 2>&1).match(/does not exist/)
50
+ not %x(qdbus org.kde.amarok 2>&1).match(/does not exist|command not found/)
41
51
  end
42
52
 
43
53
  private
@@ -1,55 +1,66 @@
1
+ if RUBY_PLATFORM =~ /darwin/
2
+ require 'appscript'
3
+ include Appscript
4
+ end
5
+
1
6
  module Anyplayer
2
7
  class Itunes < Player
3
8
  def playpause
4
- tell_to 'playpause'
9
+ @app.playpause
10
+ end
11
+
12
+ def play
13
+ @app.play
14
+ end
15
+
16
+ def pause
17
+ @app.pause
5
18
  end
6
19
 
7
20
  def prev
8
- tell_to 'previous track'
21
+ @app.previous_track
22
+ super
9
23
  end
10
24
 
11
25
  def next
12
- tell_to 'next track'
26
+ @app.next_track
27
+ super
13
28
  end
14
29
 
15
30
  def voldown
16
- tell_to 'set sound volume to sound volume - 10'
31
+ @app.sound_volume.set(volume + 10)
17
32
  end
18
33
 
19
34
  def volup
20
- tell_to 'set sound volume to sound volume + 10'
35
+ @app.sound_volume.set(volume + 10)
21
36
  end
22
37
 
23
38
  def volume
24
- tell_to 'return sound volume'
39
+ @app.sound_volume.get
25
40
  end
26
41
 
27
42
  def track
28
- tell_to 'return name of current track'
43
+ @app.current_track.name.get
29
44
  end
30
45
 
31
46
  def artist
32
- tell_to 'return artist of current track'
47
+ @app.current_track.artist.get
33
48
  end
34
49
 
35
50
  def album
36
- tell_to 'return album of current track'
51
+ @app.current_track.album.get
37
52
  end
38
53
 
39
54
  def launched?
40
- return false if RUBY_PLATFORM !~ /darwin/
41
- nb = %x(osascript -e 'tell app "System Events" to count (every process whose name is "iTunes")' 2>/dev/null).rstrip
42
- nb.match(/^\d+/) and nb.to_i > 0 ? true : false
55
+ return false unless RUBY_PLATFORM =~ /darwin/
56
+ return false unless app('System Events').processes.name.get.include? "iTunes"
57
+ @app = app('iTunes')
58
+ true
43
59
  end
44
60
 
45
61
  def name
46
62
  "iTunes"
47
63
  end
48
-
49
- private
50
- def tell_to(command)
51
- %x(osascript -e 'tell app "iTunes" to #{command}').rstrip
52
- end
53
64
  end
54
65
  end
55
66
 
@@ -4,12 +4,22 @@ module Anyplayer
4
4
  @itunes.PlayPause()
5
5
  end
6
6
 
7
+ def play
8
+ @itunes.Play()
9
+ end
10
+
11
+ def pause
12
+ @itunes.Pause()
13
+ end
14
+
7
15
  def prev
8
16
  @itunes.PreviousTrack()
17
+ super
9
18
  end
10
19
 
11
20
  def next
12
21
  @itunes.NextTrack()
22
+ super
13
23
  end
14
24
 
15
25
  def voldown
@@ -4,12 +4,22 @@ module Anyplayer
4
4
  mpc 'toggle'
5
5
  end
6
6
 
7
+ def play
8
+ mpc 'play'
9
+ end
10
+
11
+ def pause
12
+ mpc 'pause'
13
+ end
14
+
7
15
  def prev
8
16
  mpc 'prev'
17
+ super
9
18
  end
10
19
 
11
20
  def next
12
21
  mpc 'next'
22
+ super
13
23
  end
14
24
 
15
25
  def voldown
@@ -4,12 +4,22 @@ module Anyplayer
4
4
  tell_to 'play-pause'
5
5
  end
6
6
 
7
+ def play
8
+ tell_to 'play'
9
+ end
10
+
11
+ def pause
12
+ tell_to 'pause'
13
+ end
14
+
7
15
  def prev
8
16
  tell_to 'previous'
17
+ super
9
18
  end
10
19
 
11
20
  def next
12
21
  tell_to 'next'
22
+ super
13
23
  end
14
24
 
15
25
  def voldown
@@ -31,7 +41,7 @@ module Anyplayer
31
41
  def artist
32
42
  tell_to 'print-playing-format=%ta'
33
43
  end
34
-
44
+
35
45
  def album
36
46
  tell_to 'print-playing-format=%at'
37
47
  end
@@ -4,12 +4,22 @@ module Anyplayer
4
4
  xmms2 'toggle'
5
5
  end
6
6
 
7
+ def play
8
+ xmms2 'play'
9
+ end
10
+
11
+ def pause
12
+ xmms2 'pause'
13
+ end
14
+
7
15
  def prev
8
16
  xmms2 'prev'
17
+ super
9
18
  end
10
19
 
11
20
  def next
12
21
  xmms2 'next'
22
+ super
13
23
  end
14
24
 
15
25
  def voldown
@@ -25,8 +35,8 @@ module Anyplayer
25
35
  end
26
36
 
27
37
  def volume
28
- #currently just the first (left?) channel
29
- xmms2('server volume').split("\n").first.sub /([^0-9]*)/, ''
38
+ # currently just the first (left?) channel
39
+ xmms2('server volume').split("\n").first.sub(/([^0-9]*)/, '')
30
40
  $1
31
41
  end
32
42
 
@@ -42,6 +52,14 @@ module Anyplayer
42
52
  xmms2 "status -f '${album}'"
43
53
  end
44
54
 
55
+ def playing?
56
+ xmms2("status -f '${playback_status}'") == "Playing"
57
+ end
58
+
59
+ def paused?
60
+ xmms2("status -f '${playback_status}'") == "Paused"
61
+ end
62
+
45
63
  def launched?
46
64
  # xmms2 autolaunches the daemon, so this should always be true
47
65
  %x(xmms2 status 2> /dev/null)
@@ -54,8 +72,8 @@ module Anyplayer
54
72
 
55
73
  private
56
74
  def xmms2(command)
57
- %x(xmms2 #{command}).split("\n").first
75
+ %x(xmms2 #{command}).split("\n").first.strip
58
76
  end
59
77
  end
60
78
 
61
- end
79
+ end
@@ -1,3 +1,3 @@
1
1
  module Anyplayer
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -1,13 +1,75 @@
1
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
- $LOAD_PATH.unshift(File.dirname(__FILE__))
1
+ require "minitest/unit"
2
+ require "minitest/autorun"
3
+ require "anyplayer"
3
4
 
4
- require 'test/unit'
5
- require 'anyplayer'
5
+ class AnyplayerTest < MiniTest::Unit::TestCase
6
+ def setup
7
+ @player = Anyplayer::launched
8
+ refute_nil @player, "Make sure you have launched a player for tests to run"
9
+ end
6
10
 
7
- class AnyplayerTest < Test::Unit::TestCase
8
11
  def test_music_player_running
9
- player = Anyplayer::launched
10
- assert_not_nil player
11
- assert player.is_a?(Anyplayer::Player)
12
+ assert_kind_of Anyplayer::Player, @player
13
+ end
14
+
15
+
16
+ def test_voting
17
+ assert_equal @player.votes, 0
18
+
19
+ first_track = @player.track
20
+
21
+ Anyplayer::Player::DEFAULT_VOTES_TO_SKIP.times do |i|
22
+ @player.vote
23
+
24
+ # votes should be 0 if we've voted enough times
25
+ if i == Anyplayer::Player::DEFAULT_VOTES_TO_SKIP-1
26
+ assert_equal @player.votes, 0
27
+ else
28
+ assert_equal @player.votes, i+1
29
+ end
30
+ end
31
+
32
+ # make sure we actually changed tracks
33
+ refute_equal @player.track, first_track
34
+
35
+ # rewind test
36
+ @player.prev
37
+ @player.play
38
+ end
39
+
40
+ def test_vote_resets
41
+ assert_equal @player.votes, 0
42
+
43
+ @player.next
44
+ assert_equal @player.votes, 0
45
+
46
+ @player.prev
47
+ assert_equal @player.votes, 0
48
+ end
49
+
50
+ def test_custom_voting_quota
51
+ assert_equal @player.votes, 0
52
+
53
+ num_votes = 10
54
+
55
+ first_track = @player.track
56
+
57
+ num_votes.times do |i|
58
+ @player.vote(num_votes)
59
+
60
+ # votes should be 0 if we've voted enough times
61
+ if i == num_votes-1
62
+ assert_equal @player.votes, 0
63
+ else
64
+ assert_equal @player.votes, i+1
65
+ end
66
+ end
67
+
68
+ # make sure we actually changed tracks
69
+ refute_equal @player.track, first_track
70
+
71
+ # rewind test
72
+ @player.prev
73
+ @player.play
12
74
  end
13
75
  end
metadata CHANGED
@@ -1,39 +1,50 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: anyplayer
3
- version: !ruby/object:Gem::Version
4
- hash: 29
5
- prerelease: false
6
- segments:
7
- - 0
8
- - 0
9
- - 1
10
- version: 0.0.1
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ prerelease:
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - Sunny Ripert
9
+ - Gordon Diggs
14
10
  autorequire:
15
11
  bindir: bin
16
12
  cert_chain: []
17
-
18
- date: 2011-01-18 00:00:00 +01:00
19
- default_executable:
20
- dependencies: []
21
-
13
+ date: 2013-01-22 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: minitest
17
+ requirement: !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
23
+ type: :development
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ! '>='
29
+ - !ruby/object:Gem::Version
30
+ version: '0'
22
31
  description: Play/pause/skip songs in iTunes, Rythmbox, MPD, XMMS
23
- email:
32
+ email:
24
33
  - sunny@sunfox.org
25
- executables: []
26
-
34
+ - gordon@gordondiggs.com
35
+ executables:
36
+ - anyplayer
27
37
  extensions: []
28
-
29
38
  extra_rdoc_files: []
30
-
31
- files:
39
+ files:
32
40
  - .gitignore
41
+ - .travis.yml
33
42
  - Gemfile
43
+ - Gemfile.lock
34
44
  - Rakefile
35
45
  - Readme.markdown
36
46
  - anyplayer.gemspec
47
+ - bin/anyplayer
37
48
  - lib/anyplayer.rb
38
49
  - lib/anyplayer/player.rb
39
50
  - lib/anyplayer/players/amarok.rb
@@ -44,39 +55,29 @@ files:
44
55
  - lib/anyplayer/players/xmms2.rb
45
56
  - lib/anyplayer/version.rb
46
57
  - test/anyplayer_test.rb
47
- has_rdoc: true
48
58
  homepage: http://github.com/sunny/anyplayer
49
59
  licenses: []
50
-
51
60
  post_install_message:
52
61
  rdoc_options: []
53
-
54
- require_paths:
62
+ require_paths:
55
63
  - lib
56
- required_ruby_version: !ruby/object:Gem::Requirement
64
+ required_ruby_version: !ruby/object:Gem::Requirement
57
65
  none: false
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- hash: 3
62
- segments:
63
- - 0
64
- version: "0"
65
- required_rubygems_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ required_rubygems_version: !ruby/object:Gem::Requirement
66
71
  none: false
67
- requirements:
68
- - - ">="
69
- - !ruby/object:Gem::Version
70
- hash: 3
71
- segments:
72
- - 0
73
- version: "0"
72
+ requirements:
73
+ - - ! '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
74
76
  requirements: []
75
-
76
77
  rubyforge_project:
77
- rubygems_version: 1.3.7
78
+ rubygems_version: 1.8.23
78
79
  signing_key:
79
80
  specification_version: 3
80
81
  summary: Interact with the running music player
81
- test_files: []
82
-
82
+ test_files:
83
+ - test/anyplayer_test.rb