ituner 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/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in ituner.gemspec
4
+ gemspec
5
+
6
+ gem "rake"
7
+ gem "rspec"
8
+ gem "rr"
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require "rspec/core/rake_task"
5
+
6
+ task "default" => "spec"
7
+
8
+ RSpec::Core::RakeTask.new do |t|
9
+ t.pattern = 'spec/**/*_spec.rb'
10
+ t.rspec_opts = ["--colour", "--format", "nested"]
11
+ end
data/ituner.gemspec ADDED
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "ituner/version"
4
+
5
+ Gem::Specification.new do |gem|
6
+
7
+ gem.name = "ituner"
8
+ gem.summary = "control iTunes using Ruby"
9
+ gem.homepage = "http://github.com/mdub/ituner"
10
+
11
+ gem.version = ITuner::VERSION
12
+ gem.platform = Gem::Platform::RUBY
13
+
14
+ gem.authors = ["Mike Williams"]
15
+ gem.email = ["mdub@dogbiscuit.org"]
16
+
17
+ gem.files = `git ls-files`.split("\n")
18
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ gem.require_paths = ["lib"]
20
+
21
+ gem.add_runtime_dependency "rb-appscript"
22
+
23
+ end
data/lib/ituner.rb ADDED
@@ -0,0 +1 @@
1
+ require 'ituner/itunes'
@@ -0,0 +1,84 @@
1
+ module ITuner
2
+
3
+ class Collection
4
+
5
+ def initialize(app_collection, item_type, item_class, &block)
6
+ @app_collection = app_collection
7
+ @item_type = item_type
8
+ @item_class = item_class
9
+ if block
10
+ self.extend(Module.new(&block))
11
+ end
12
+ end
13
+
14
+ attr_reader :app_collection
15
+ attr_reader :item_class
16
+ attr_reader :item_type
17
+
18
+ def get(index)
19
+ app_reference = app_collection[translate_index(index)]
20
+ wrap_item(resolve_reference(app_reference))
21
+ end
22
+
23
+ alias :[] :get
24
+
25
+ def translate_index(index)
26
+ case index
27
+ when Integer
28
+ index + 1
29
+ else
30
+ index
31
+ end
32
+ end
33
+
34
+ def size
35
+ app_collection.get.size
36
+ end
37
+
38
+ def empty?
39
+ size == 0
40
+ end
41
+
42
+ def each
43
+ app_collection.get.each do |item|
44
+ yield wrap_item(item)
45
+ end
46
+ end
47
+
48
+ include Enumerable
49
+
50
+ def first
51
+ wrap_item(app_collection.first.get)
52
+ end
53
+
54
+ def last
55
+ wrap_item(app_collection.last.get)
56
+ end
57
+
58
+ def create(properties = {})
59
+ wrap_item(ITuner.itunes_app.make(:new => item_type, :with_properties => properties))
60
+ end
61
+
62
+ def inspect
63
+ s = take(10).inspect
64
+ if size > 10
65
+ s[-1,1] = ", (and #{size - 10} more)]"
66
+ end
67
+ s
68
+ end
69
+
70
+ private
71
+
72
+ def resolve_reference(ref)
73
+ ref.get
74
+ rescue Appscript::CommandError
75
+ return nil
76
+ end
77
+
78
+ def wrap_item(item)
79
+ item_class.new(item) if item
80
+ end
81
+
82
+ end
83
+
84
+ end
@@ -0,0 +1,68 @@
1
+ require 'appscript'
2
+ require 'ituner/collection'
3
+ require 'ituner/source'
4
+ require 'ituner/playlist'
5
+ require 'ituner/track'
6
+
7
+ module ITuner
8
+
9
+ class << self
10
+
11
+ def itunes_app
12
+ @itunes_app ||= Appscript.app("iTunes")
13
+ end
14
+
15
+ def itunes
16
+ itunes_app.launch
17
+ ITunes.new(itunes_app)
18
+ end
19
+
20
+ end
21
+
22
+ class ITunes < Model
23
+
24
+ def running?
25
+ app.is_running?
26
+ end
27
+
28
+ action :play
29
+ action :pause
30
+ action :stop
31
+
32
+ def state
33
+ app.player_state.get
34
+ end
35
+
36
+ def playing?; state == :playing; end
37
+ def paused?; state == :paused; end
38
+ def stopped?; state == :stopped; end
39
+
40
+ def current_track
41
+ Track.new(app.current_track.get)
42
+ rescue Appscript::CommandError
43
+ nil
44
+ end
45
+
46
+ collection :sources
47
+
48
+ def library
49
+ sources["Library"]
50
+ end
51
+
52
+ def playlists
53
+ library.playlists
54
+ end
55
+
56
+ def music
57
+ playlists["Music"]
58
+ end
59
+
60
+ private
61
+
62
+ def app
63
+ app_object
64
+ end
65
+
66
+ end
67
+
68
+ end
@@ -0,0 +1,54 @@
1
+ module ITuner
2
+
3
+ class Model
4
+
5
+ def initialize(app_object)
6
+ @app_object = app_object
7
+ end
8
+
9
+ attr_accessor :app_object
10
+
11
+ def ==(other)
12
+ other && (app_object == other.app_object)
13
+ end
14
+
15
+ def inspect
16
+ s = "{" + self.class.name
17
+ if respond_to?(:name)
18
+ s += " #{name.inspect}"
19
+ end
20
+ s += "}"
21
+ s
22
+ end
23
+
24
+ class << self
25
+
26
+ def property(name, app_name = name)
27
+ define_method(name) do
28
+ app_object.send(app_name).get
29
+ end
30
+ end
31
+
32
+ def collection(name, app_name = name, &block)
33
+ item_type = name.to_s.sub(/s$/,'').to_sym
34
+ item_class = ITuner.const_get(item_type.to_s.capitalize)
35
+ define_method(name) do
36
+ Collection.new(app_object.send(app_name), item_type, item_class, &block)
37
+ end
38
+ end
39
+
40
+ def action(name, app_name = name)
41
+ define_method(name) do |*args|
42
+ app_object.send(app_name, *args)
43
+ end
44
+ end
45
+
46
+ end
47
+
48
+ action :delete
49
+
50
+ property :kind
51
+
52
+ end
53
+
54
+ end
@@ -0,0 +1,38 @@
1
+ require 'ituner/model'
2
+ require 'ituner/track'
3
+
4
+ module ITuner
5
+
6
+ class Playlist < Model
7
+
8
+ property :name
9
+
10
+ collection :tracks do
11
+
12
+ def clear
13
+ app_collection.delete
14
+ end
15
+
16
+ end
17
+
18
+ def clear
19
+ tracks.clear
20
+ end
21
+
22
+ def search(name, only = :all)
23
+ ITuner.itunes_app.search(app_object, :for => name, :only => only).map do |app_track|
24
+ Track.new(app_track)
25
+ end
26
+ end
27
+
28
+ def add(track)
29
+ ITuner.itunes_app.duplicate(track.app_object, :to => app_object)
30
+ end
31
+
32
+ def play
33
+ app_object.play(:once => true)
34
+ end
35
+
36
+ end
37
+
38
+ end
@@ -0,0 +1,26 @@
1
+ require 'ituner/model'
2
+ require 'ituner/playlist'
3
+
4
+ module ITuner
5
+
6
+ class Source < Model
7
+
8
+ property :name
9
+
10
+ collection :playlists do
11
+
12
+ def find_or_create(name)
13
+ get(name) || create(:name => name)
14
+ end
15
+
16
+ end
17
+
18
+ collection :tracks
19
+
20
+ def music
21
+ playlists["Music"]
22
+ end
23
+
24
+ end
25
+
26
+ end
@@ -0,0 +1,32 @@
1
+ require 'ituner/model'
2
+
3
+ module ITuner
4
+
5
+ class Track < Model
6
+
7
+ property :name
8
+ property :artist
9
+ property :album
10
+
11
+ property :uid, :database_ID
12
+
13
+ def play
14
+ app_object.play(:once => true)
15
+ end
16
+
17
+ class << self
18
+
19
+ include Appscript
20
+
21
+ def find_by_uid(uid)
22
+ app_track = ITuner.itunes_app.tracks[its.database_ID.eq(uid)].first.get
23
+ Track.new(app_track)
24
+ rescue CommandError
25
+ nil
26
+ end
27
+
28
+ end
29
+
30
+ end
31
+
32
+ end
@@ -0,0 +1,3 @@
1
+ module ITuner
2
+ VERSION = "0.0.2"
3
+ end
@@ -0,0 +1,110 @@
1
+ require 'spec_helper'
2
+
3
+ describe ITuner::Collection do
4
+
5
+ before do
6
+ @collection = ITuner.itunes.playlists
7
+ end
8
+
9
+ describe "#size" do
10
+ it "returns the number of items" do
11
+ size = @collection.size
12
+ size.should be_kind_of(Integer)
13
+ size.should be > 5
14
+ end
15
+ end
16
+
17
+ describe "#get" do
18
+
19
+ describe "with a string" do
20
+
21
+ it "returns the entry with matching name" do
22
+ @collection["Library"].should be_kind_of(ITuner::Playlist)
23
+ @collection["Library"].name.should == "Library"
24
+ end
25
+
26
+ end
27
+
28
+ describe "with a number" do
29
+
30
+ it "returns the entry in the referenced position" do
31
+ @collection[0].name.should == "Library"
32
+ end
33
+
34
+ end
35
+
36
+ describe "with a bogus name" do
37
+
38
+ it "returns nil" do
39
+ @collection["bogus"].should be_nil
40
+ end
41
+
42
+ end
43
+
44
+ describe "with an out-of-bounds number" do
45
+
46
+ it "returns nil" do
47
+ @collection[666].should be_nil
48
+ end
49
+
50
+ end
51
+
52
+ end
53
+
54
+ it "can be enumerated" do
55
+ @collection.should respond_to(:each)
56
+
57
+ @count = 0
58
+ @collection.each do |item|
59
+ @count += 1
60
+ end
61
+ @count.should == @collection.size
62
+ end
63
+
64
+ it "is Enumerable" do
65
+ @collection.should be_kind_of(Enumerable)
66
+ end
67
+
68
+ describe "#create" do
69
+
70
+ before do
71
+ @collection["XYZ"].delete rescue nil
72
+ end
73
+
74
+ it "creates a new item" do
75
+ xyz = @collection.create(:name => "XYZ")
76
+ xyz.should be_kind_of(ITuner::Playlist)
77
+ xyz.name.should == "XYZ"
78
+ end
79
+
80
+ after do
81
+ @collection["XYZ"].delete rescue nil
82
+ end
83
+
84
+ end
85
+
86
+ describe "#inspect" do
87
+
88
+ it "makes the collection looks like an array" do
89
+ @collection.inspect.should =~ /^\[.*\]$/
90
+ end
91
+
92
+ it "invokes #inspect on each element" do
93
+ stub(@collection).each { |block| [1,2,3].each(&block) }
94
+ stub(@collection).size { 3 }
95
+ @collection.inspect.should == "[1, 2, 3]"
96
+ end
97
+
98
+ context "when the collection contains more than 10 elements" do
99
+
100
+ it "invokes #inspect on each element" do
101
+ stub(@collection).each { |block| (1..20).each(&block) }
102
+ stub(@collection).size { 20 }
103
+ @collection.inspect.should == "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, (and 10 more)]"
104
+ end
105
+
106
+ end
107
+
108
+ end
109
+
110
+ end
@@ -0,0 +1,60 @@
1
+ require 'spec_helper'
2
+
3
+ describe ITuner, "controls" do
4
+
5
+ before do
6
+ @itunes = ITuner.itunes
7
+ end
8
+
9
+ it "is running" do
10
+ @itunes.should be_running
11
+ end
12
+
13
+ it "can play" do
14
+ @itunes.play
15
+ @itunes.should be_playing
16
+ end
17
+
18
+ it "can pause" do
19
+ @itunes.play
20
+ @itunes.pause
21
+ @itunes.should_not be_playing
22
+ end
23
+
24
+ describe "#current_track" do
25
+
26
+ it "returns the current Track" do
27
+ @itunes.play
28
+ @itunes.current_track.should be_kind_of(ITuner::Track)
29
+ end
30
+
31
+ after do
32
+ @itunes.stop
33
+ end
34
+
35
+ end
36
+
37
+ describe "#sources" do
38
+
39
+ it "returns the media sources" do
40
+ @sources = @itunes.sources
41
+ @sources.each do |source|
42
+ source.should be_kind_of(ITuner::Source)
43
+ end
44
+ @sources[0].name.should == "Library"
45
+ @sources[1].name.should == "Radio"
46
+ end
47
+
48
+ end
49
+
50
+ describe "#library" do
51
+
52
+ it "returns the Library source" do
53
+ @library = @itunes.library
54
+ @library.should be_kind_of(ITuner::Source)
55
+ @library.name.should == "Library"
56
+ end
57
+
58
+ end
59
+
60
+ end
@@ -0,0 +1,70 @@
1
+ require 'spec_helper'
2
+
3
+ describe ITuner::Playlist do
4
+
5
+ before do
6
+ @playlist = ITuner.itunes.playlists["Library"]
7
+ end
8
+
9
+ it "has a name" do
10
+ @playlist.name.should == "Library"
11
+ end
12
+
13
+ it "has tracks" do
14
+ @playlist.tracks.should be_kind_of(ITuner::Collection)
15
+ end
16
+
17
+ describe "#search" do
18
+
19
+ it "returns matching tracks" do
20
+ @playlist.search("FreeLoader").map(&:name).should include("Freddie Freeloader")
21
+ @playlist.search("Nirvana").map(&:name).should include("Smells Like Teen Spirit")
22
+ end
23
+
24
+ it "can be restricted" do
25
+ @playlist.search("Nirvana", :artists).map(&:name).should include("Smells Like Teen Spirit")
26
+ @playlist.search("Nirvana", :songs).map(&:name).should_not include("Smells Like Teen Spirit")
27
+ end
28
+
29
+ end
30
+
31
+ describe "#add" do
32
+
33
+ before do
34
+ @playlist = ITuner.itunes.playlists.create(:name => "Test")
35
+ @track = ITuner.itunes.music.tracks.first
36
+ end
37
+
38
+ after do
39
+ @playlist.delete
40
+ end
41
+
42
+ it "add a track to the playlist" do
43
+ @playlist.add(@track)
44
+ @playlist.tracks.size.should == 1
45
+ end
46
+
47
+ end
48
+
49
+ describe "#clear" do
50
+
51
+ before do
52
+ @playlist = ITuner.itunes.playlists.create(:name => "Test")
53
+ end
54
+
55
+ after do
56
+ @playlist.delete
57
+ end
58
+
59
+ it "removes all tracks" do
60
+ ITuner.itunes.music.tracks.take(3).each do |track|
61
+ @playlist.add(track)
62
+ end
63
+ @playlist.tracks.size.should == 3
64
+ @playlist.clear
65
+ @playlist.tracks.size.should == 0
66
+ end
67
+
68
+ end
69
+
70
+ end
@@ -0,0 +1,48 @@
1
+ require 'spec_helper'
2
+
3
+ describe ITuner::Source do
4
+
5
+ before do
6
+ @source = ITuner.itunes.sources["Library"]
7
+ end
8
+
9
+ it "has a name" do
10
+ @source.name.should == "Library"
11
+ end
12
+
13
+ describe "#playlists" do
14
+
15
+ it "returns playlists" do
16
+ @playlists = @source.playlists
17
+ @playlists.should_not be_empty
18
+ @playlists.each do |playlist|
19
+ playlist.should be_kind_of(ITuner::Playlist)
20
+ end
21
+ end
22
+
23
+ describe ".find_or_create" do
24
+
25
+ context "with the name of an existing playlist" do
26
+ it "finds the existing one" do
27
+ music = @source.music
28
+ @source.playlists.find_or_create("Music").should == music
29
+ end
30
+ end
31
+
32
+ context "with the name of a non-existant playlist" do
33
+
34
+ it "creates a new one" do
35
+ old_xxx = @source.playlists["XXX"]
36
+ old_xxx.delete unless old_xxx.nil?
37
+ new_xxx = @source.playlists.find_or_create("XXX")
38
+ new_xxx.should be_kind_of(ITuner::Playlist)
39
+ new_xxx.name.should == "XXX"
40
+ end
41
+
42
+ end
43
+
44
+ end
45
+
46
+ end
47
+
48
+ end
@@ -0,0 +1,67 @@
1
+ require 'spec_helper'
2
+
3
+ describe ITuner::Track do
4
+
5
+ before do
6
+ @itunes = ITuner.itunes
7
+ @track = @itunes.library.tracks["Freddie Freeloader"]
8
+ end
9
+
10
+ it "has a name" do
11
+ @track.name.should == "Freddie Freeloader"
12
+ end
13
+
14
+ it "has an artist" do
15
+ @track.artist.should == "Miles Davis"
16
+ end
17
+
18
+ it "has an album" do
19
+ @track.album.should == "Kind Of Blue"
20
+ end
21
+
22
+ it "has a uid" do
23
+ @track.uid.should be_kind_of(Fixnum)
24
+ end
25
+
26
+ it "can be played" do
27
+ @track.play
28
+ end
29
+
30
+ describe "#play" do
31
+
32
+ before do
33
+ @itunes.stop
34
+ end
35
+
36
+ it "plays the song (and then stops)" do
37
+ stub.proxy(@track.app_object).play
38
+ @track.play
39
+ @itunes.should be_playing
40
+ @track.app_object.should have_received.play(:once => true)
41
+ end
42
+
43
+ end
44
+
45
+ describe ".find_by_uid" do
46
+
47
+ context "with the uid of an existing track" do
48
+ it "returns the track" do
49
+ @reloaded_track = ITuner::Track.find_by_uid(@track.uid)
50
+ @reloaded_track.name.should == @track.name
51
+ @reloaded_track.uid.should == @track.uid
52
+ end
53
+ end
54
+
55
+ context "with a bogus uid" do
56
+ it "returns nil" do
57
+ ITuner::Track.find_by_uid(99999999999).should == nil
58
+ end
59
+ end
60
+
61
+ end
62
+
63
+ after do
64
+ @itunes.stop
65
+ end
66
+
67
+ end
@@ -0,0 +1,24 @@
1
+ require 'rspec'
2
+ require 'ituner'
3
+ require 'rr'
4
+ require 'rr/adapters/rspec'
5
+
6
+ module HaveReceivedSupport
7
+
8
+ def have_received(method = nil)
9
+ RR::Adapters::Rspec::InvocationMatcher.new(method)
10
+ end
11
+
12
+ end
13
+
14
+ RSpec.configure do |config|
15
+
16
+ config.mock_with :rr
17
+ config.include HaveReceivedSupport
18
+
19
+ config.after do
20
+ ITuner.itunes.stop
21
+ end
22
+
23
+ end
24
+
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ituner
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.2
6
+ platform: ruby
7
+ authors:
8
+ - Mike Williams
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-03-21 00:00:00 +11:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: rb-appscript
18
+ prerelease: false
19
+ requirement: &id001 !ruby/object:Gem::Requirement
20
+ none: false
21
+ requirements:
22
+ - - ">="
23
+ - !ruby/object:Gem::Version
24
+ version: "0"
25
+ type: :runtime
26
+ version_requirements: *id001
27
+ description:
28
+ email:
29
+ - mdub@dogbiscuit.org
30
+ executables: []
31
+
32
+ extensions: []
33
+
34
+ extra_rdoc_files: []
35
+
36
+ files:
37
+ - .gitignore
38
+ - Gemfile
39
+ - Rakefile
40
+ - ituner.gemspec
41
+ - lib/ituner.rb
42
+ - lib/ituner/collection.rb
43
+ - lib/ituner/itunes.rb
44
+ - lib/ituner/model.rb
45
+ - lib/ituner/playlist.rb
46
+ - lib/ituner/source.rb
47
+ - lib/ituner/track.rb
48
+ - lib/ituner/version.rb
49
+ - spec/ituner/collection_spec.rb
50
+ - spec/ituner/itunes_spec.rb
51
+ - spec/ituner/playlist_spec.rb
52
+ - spec/ituner/source_spec.rb
53
+ - spec/ituner/track_spec.rb
54
+ - spec/spec_helper.rb
55
+ has_rdoc: true
56
+ homepage: http://github.com/mdub/ituner
57
+ licenses: []
58
+
59
+ post_install_message:
60
+ rdoc_options: []
61
+
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: "0"
70
+ required_rubygems_version: !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: "0"
76
+ requirements: []
77
+
78
+ rubyforge_project:
79
+ rubygems_version: 1.6.2
80
+ signing_key:
81
+ specification_version: 3
82
+ summary: control iTunes using Ruby
83
+ test_files:
84
+ - spec/ituner/collection_spec.rb
85
+ - spec/ituner/itunes_spec.rb
86
+ - spec/ituner/playlist_spec.rb
87
+ - spec/ituner/source_spec.rb
88
+ - spec/ituner/track_spec.rb
89
+ - spec/spec_helper.rb