airplay 0.2.0 → 0.2.1

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 CHANGED
@@ -1 +1,2 @@
1
1
  /pkg
2
+ Gemfile.lock
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
data/README.md CHANGED
@@ -29,6 +29,16 @@ airplay.password "password"
29
29
  airplay.send_image("lolcatz.jpg")
30
30
  ```
31
31
 
32
+ ## Player
33
+
34
+ ```ruby
35
+ require 'airplay'
36
+
37
+ airplay = Airplay::Client.new
38
+ player = airplay.send_video("http://www.yo-yo.org/mp4/yu2.mp4")
39
+ player.stop
40
+ ```
41
+
32
42
  ## Useful methods
33
43
 
34
44
  ```ruby
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "airplay"
3
- s.version = "0.2.0"
3
+ s.version = "0.2.1"
4
4
  s.summary = "Airplay client"
5
5
  s.description = "Send image/video to an airplay enabled device"
6
6
  s.authors = ["elcuervo"]
@@ -13,7 +13,6 @@ Gem::Specification.new do |s|
13
13
  s.add_dependency("net-http-digest_auth")
14
14
 
15
15
  s.add_development_dependency("cutest")
16
- s.add_development_dependency("mocha")
17
16
  s.add_development_dependency("capybara")
18
17
  s.add_development_dependency("fakeweb")
19
18
  s.add_development_dependency("vcr")
@@ -4,9 +4,13 @@ require 'net/http/digest_auth'
4
4
  require 'uri'
5
5
 
6
6
  module Airplay; end;
7
+ require 'airplay/server'
8
+ require 'airplay/server/browser'
9
+ require 'airplay/server/node'
10
+
7
11
  require 'airplay/protocol'
8
12
  require 'airplay/protocol/image'
9
- require 'airplay/protocol/video'
13
+ require 'airplay/protocol/media'
10
14
  require 'airplay/protocol/scrub'
11
- require 'airplay/node'
15
+
12
16
  require 'airplay/client'
@@ -1,13 +1,14 @@
1
1
  class Airplay::Client
2
2
  attr_reader :servers, :active_server, :password
3
3
 
4
- def initialize(server = false)
4
+ def initialize(server = false, server_browser = Airplay::Server::Browser)
5
+ @server_browser = server_browser
5
6
  browse unless server
6
- use servers.first if servers.any?
7
+ use servers.first if !@servers.nil?
7
8
  end
8
9
 
9
10
  def use(server)
10
- @active_server = server.is_a?(Airplay::Node) ? server : find_by_name(server)
11
+ @active_server = server.is_a?(Airplay::Server::Node) ? server : @server_browser.find_by_name(server)
11
12
  end
12
13
 
13
14
  def password(password)
@@ -15,29 +16,11 @@ class Airplay::Client
15
16
  end
16
17
 
17
18
  def find_by_name(name)
18
- found_server = @servers.detect do |server|
19
- server if server.name == name
20
- end
21
- raise Airplay::Client::ServerNotFoundError unless found_server
22
- found_server
19
+ @server_browser.find_by_name(name)
23
20
  end
24
21
 
25
22
  def browse
26
- @servers = []
27
- DNSSD.browse!(Airplay::Protocol::SEARCH) do |reply|
28
- resolver = DNSSD::Service.new
29
- target, port = nil
30
- resolver.resolve(reply) do |resolved|
31
- port = resolved.port
32
- target = resolved.target
33
- break unless resolved.flags.more_coming?
34
- end
35
- info = Socket.getaddrinfo(target, nil, Socket::AF_INET)
36
- ip_address = info[0][2]
37
- @servers << Airplay::Node.new(reply.name, reply.domain, ip_address, port)
38
- break unless reply.flags.more_coming?
39
- end
40
- @servers
23
+ @servers = @server_browser.browse
41
24
  end
42
25
 
43
26
  def handler
@@ -49,7 +32,11 @@ class Airplay::Client
49
32
  end
50
33
 
51
34
  def send_video(video, position = 0)
52
- Airplay::Protocol::Video.new(handler).send(video, position)
35
+ Airplay::Protocol::Media.new(handler).send(video, position)
36
+ end
37
+
38
+ def send_audio(audio, position = 0)
39
+ Airplay::Protocol::Media.new(handler).send(audio, position)
53
40
  end
54
41
 
55
42
  def scrub
@@ -1,4 +1,4 @@
1
- class Airplay::Protocol::Video
1
+ class Airplay::Protocol::Media
2
2
 
3
3
  def initialize(protocol_handler)
4
4
  @http = protocol_handler
@@ -8,28 +8,31 @@ class Airplay::Protocol::Video
8
8
  "/play"
9
9
  end
10
10
 
11
- def position_body(position = 0)
12
- "Start-Position: #{position}\n"
11
+ def stop_resource
12
+ "/stop"
13
13
  end
14
14
 
15
- def location_body(video)
16
- "Content-Location: #{video}\n"
15
+ def position_body(position = 0)
16
+ "Start-Position: #{position}\n"
17
17
  end
18
18
 
19
- def send(video, position = 0)
20
- body = location_body(video)
21
- body += position_body(position.to_s)
22
- @http.post(resource, body)
19
+ def location_body(media)
20
+ "Content-Location: #{media}\n"
23
21
  end
24
22
 
25
- def play
23
+ def send(media, position = 0)
24
+ play(media, position)
25
+ self
26
26
  end
27
27
 
28
- def pause
29
- # TODO: know how to pause video
28
+ def play(media, position = 0)
29
+ body = location_body(media)
30
+ body += position_body(position.to_s)
31
+ @http.post(resource, body)
30
32
  end
31
33
 
32
34
  def stop
35
+ @http.post(stop_resource)
33
36
  end
34
37
 
35
38
  end
@@ -0,0 +1,2 @@
1
+ class Airplay::Server
2
+ end
@@ -0,0 +1,30 @@
1
+ module Airplay::Server::Browser
2
+ attr_reader :servers
3
+
4
+ def self.find_by_name(name)
5
+ found_server = @servers.detect do |server|
6
+ server if server.name == name
7
+ end
8
+ raise Airplay::Client::ServerNotFoundError unless found_server
9
+ found_server
10
+ end
11
+
12
+ def self.browse
13
+ @servers = []
14
+ DNSSD.browse!(Airplay::Protocol::SEARCH) do |reply|
15
+ resolver = DNSSD::Service.new
16
+ target, port = nil
17
+ resolver.resolve(reply) do |resolved|
18
+ port = resolved.port
19
+ target = resolved.target
20
+ break unless resolved.flags.more_coming?
21
+ end
22
+ info = Socket.getaddrinfo(target, nil, Socket::AF_INET)
23
+ ip_address = info[0][2]
24
+ @servers << Airplay::Server::Node.new(reply.name, reply.domain, ip_address, port)
25
+ break unless reply.flags.more_coming?
26
+ end
27
+ @servers
28
+ end
29
+
30
+ end
@@ -1,4 +1,4 @@
1
- class Airplay::Node
1
+ class Airplay::Server::Node
2
2
  attr_reader :name, :domain, :ip, :port
3
3
 
4
4
  def initialize(name, domain, ip, port)
@@ -1,17 +1,13 @@
1
1
  require File.expand_path("helper", File.dirname(__FILE__))
2
2
 
3
3
  scope do
4
- setup do
5
- @airplay = Airplay::Client.new
6
- end
7
-
8
4
  test "connect to an authenticated source" do
9
5
  VCR.use_cassette("authenticate all the things!") do
10
- @airplay.use("Apple TV")
11
- @airplay.password("password")
6
+ airplay = Airplay::Client.new(false, MockedBrowser)
7
+ airplay.password("password")
12
8
 
13
- assert @airplay.scrub.has_key?("duration")
14
- assert @airplay.scrub.has_key?("position")
9
+ assert airplay.scrub.has_key?("duration")
10
+ assert airplay.scrub.has_key?("position")
15
11
  end
16
12
  end
17
13
  end
@@ -3,7 +3,7 @@ require File.expand_path("helper", File.dirname(__FILE__))
3
3
  scope do
4
4
 
5
5
  setup do
6
- @airplay = Airplay::Client.new
6
+ @airplay = Airplay::Client.new(false, MockedBrowser)
7
7
  end
8
8
 
9
9
  test "browse for available airplay servers" do
@@ -11,8 +11,7 @@ scope do
11
11
  end
12
12
 
13
13
  test "find servers by name" do
14
- airplay = Airplay::Client.new
15
- assert @airplay.find_by_name("Apple TV").is_a?(Airplay::Node)
14
+ assert @airplay.find_by_name("Mock TV").is_a?(Airplay::Server::Node)
16
15
  end
17
16
 
18
17
  test "raise on not found" do
@@ -22,7 +21,7 @@ scope do
22
21
  end
23
22
 
24
23
  test "autoselect if only one server available" do
25
- assert_equal "Apple TV", @airplay.active_server.name
24
+ assert_equal "Mock TV", @airplay.active_server.name
26
25
  end
27
26
 
28
27
  end
@@ -0,0 +1,25 @@
1
+ ---
2
+ - !ruby/struct:VCR::HTTPInteraction
3
+ request: !ruby/struct:VCR::Request
4
+ method: :post
5
+ uri: http://10.1.0.220:7000/play
6
+ body: ! 'Content-Location: http://www.robtowns.com/music/blind_willie.mp3
7
+
8
+ Start-Position: 0
9
+
10
+ '
11
+ headers:
12
+ user-agent:
13
+ - MediaControl/1.0
14
+ response: !ruby/struct:VCR::Response
15
+ status: !ruby/struct:VCR::ResponseStatus
16
+ code: 200
17
+ message: OK
18
+ headers:
19
+ date:
20
+ - Wed, 14 Sep 2011 13:12:35 GMT
21
+ content-length:
22
+ - '0'
23
+ body: !!null
24
+ http_version: '1.1'
25
+ ignored: false
@@ -17,7 +17,27 @@
17
17
  message: OK
18
18
  headers:
19
19
  date:
20
- - Wed, 31 Aug 2011 14:36:39 GMT
20
+ - Thu, 15 Sep 2011 14:55:22 GMT
21
+ content-length:
22
+ - '0'
23
+ body: !!null
24
+ http_version: '1.1'
25
+ ignored: false
26
+ - !ruby/struct:VCR::HTTPInteraction
27
+ request: !ruby/struct:VCR::Request
28
+ method: :post
29
+ uri: http://10.1.0.220:7000/stop
30
+ body: !!null
31
+ headers:
32
+ user-agent:
33
+ - MediaControl/1.0
34
+ response: !ruby/struct:VCR::Response
35
+ status: !ruby/struct:VCR::ResponseStatus
36
+ code: 200
37
+ message: OK
38
+ headers:
39
+ date:
40
+ - Thu, 15 Sep 2011 14:55:22 GMT
21
41
  content-length:
22
42
  - '0'
23
43
  body: !!null
@@ -2,9 +2,25 @@ $:.unshift(File.expand_path("../lib", File.dirname(__FILE__)))
2
2
 
3
3
  require "airplay"
4
4
  require 'vcr'
5
- require 'mocha'
6
5
  require "cutest"
7
6
 
7
+ module MockedBrowser
8
+ attr_reader :servers
9
+
10
+ def self.browse
11
+ @servers = [Airplay::Server::Node.new("Mock TV", ".local", "10.1.0.220", 7000)]
12
+ end
13
+
14
+ def self.find_by_name(name)
15
+ if name == "Mock TV"
16
+ @servers.first
17
+ else
18
+ raise Airplay::Client::ServerNotFoundError
19
+ end
20
+ end
21
+
22
+ end
23
+
8
24
  VCR.config do |c|
9
25
  c.cassette_library_dir = 'test/fixtures/cassettes/airplay'
10
26
  c.default_cassette_options = { :record => :once }
@@ -9,12 +9,11 @@ end
9
9
 
10
10
  scope do
11
11
  setup do
12
- @airplay = Airplay::Client.new
12
+ @airplay = Airplay::Client.new(false, MockedBrowser)
13
13
  end
14
14
 
15
15
  test "send an image to the server" do
16
16
  VCR.use_cassette("send image to apple tv") do
17
- @airplay.use("Apple TV")
18
17
  file_path = "./test/fixtures/image2.gif"
19
18
  assert @airplay.send_image(file_path).kind_of?(String)
20
19
  assert @airplay.send_image(File.open(file_path)).kind_of?(String)
@@ -23,7 +22,6 @@ scope do
23
22
 
24
23
  test "send an image to the server doing a dissolve" do
25
24
  VCR.use_cassette("send image to apple tv") do
26
- @airplay.use("Apple TV")
27
25
  assert @airplay.send_image("./test/fixtures/image.gif", :dissolve).kind_of?(String)
28
26
  end
29
27
  end
@@ -0,0 +1,28 @@
1
+ require File.expand_path("helper", File.dirname(__FILE__))
2
+
3
+ scope do
4
+ test "check media protocol class" do
5
+ image_protocol = Airplay::Protocol::Media.new("127.0.0.1")
6
+ assert_equal "/play", image_protocol.resource
7
+ end
8
+ end
9
+
10
+ scope do
11
+ setup do
12
+ @airplay = Airplay::Client.new(false, MockedBrowser)
13
+ end
14
+
15
+ test "send a video to the server" do
16
+ VCR.use_cassette("send video to apple tv") do
17
+ player = @airplay.send_video("http://www.yo-yo.org/mp4/yu.mp4")
18
+ assert player
19
+ assert player.stop.kind_of?(String)
20
+ end
21
+ end
22
+
23
+ test "send audio to the server" do
24
+ VCR.use_cassette("send audio to apple tv") do
25
+ assert @airplay.send_audio("http://www.robtowns.com/music/blind_willie.mp3")
26
+ end
27
+ end
28
+ end
@@ -9,12 +9,11 @@ end
9
9
 
10
10
  scope do
11
11
  setup do
12
- @airplay = Airplay::Client.new
12
+ @airplay = Airplay::Client.new(false, MockedBrowser)
13
13
  end
14
14
 
15
15
  test "check scrub status" do
16
16
  VCR.use_cassette("get current scrub from apple tv") do
17
- @airplay.use("Apple TV")
18
17
  assert @airplay.scrub.has_key?("duration")
19
18
  assert @airplay.scrub.has_key?("position")
20
19
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: airplay
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,12 +9,12 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-09-13 00:00:00.000000000 -03:00
12
+ date: 2011-09-15 00:00:00.000000000 -03:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: dnssd
17
- requirement: &70245624906500 !ruby/object:Gem::Requirement
17
+ requirement: &70210208536140 !ruby/object:Gem::Requirement
18
18
  none: false
19
19
  requirements:
20
20
  - - ! '>='
@@ -22,10 +22,10 @@ dependencies:
22
22
  version: '0'
23
23
  type: :runtime
24
24
  prerelease: false
25
- version_requirements: *70245624906500
25
+ version_requirements: *70210208536140
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: net-http-digest_auth
28
- requirement: &70245624906060 !ruby/object:Gem::Requirement
28
+ requirement: &70210208535700 !ruby/object:Gem::Requirement
29
29
  none: false
30
30
  requirements:
31
31
  - - ! '>='
@@ -33,10 +33,10 @@ dependencies:
33
33
  version: '0'
34
34
  type: :runtime
35
35
  prerelease: false
36
- version_requirements: *70245624906060
36
+ version_requirements: *70210208535700
37
37
  - !ruby/object:Gem::Dependency
38
38
  name: cutest
39
- requirement: &70245624905640 !ruby/object:Gem::Requirement
39
+ requirement: &70210208535280 !ruby/object:Gem::Requirement
40
40
  none: false
41
41
  requirements:
42
42
  - - ! '>='
@@ -44,21 +44,10 @@ dependencies:
44
44
  version: '0'
45
45
  type: :development
46
46
  prerelease: false
47
- version_requirements: *70245624905640
48
- - !ruby/object:Gem::Dependency
49
- name: mocha
50
- requirement: &70245624905220 !ruby/object:Gem::Requirement
51
- none: false
52
- requirements:
53
- - - ! '>='
54
- - !ruby/object:Gem::Version
55
- version: '0'
56
- type: :development
57
- prerelease: false
58
- version_requirements: *70245624905220
47
+ version_requirements: *70210208535280
59
48
  - !ruby/object:Gem::Dependency
60
49
  name: capybara
61
- requirement: &70245624904800 !ruby/object:Gem::Requirement
50
+ requirement: &70210208534860 !ruby/object:Gem::Requirement
62
51
  none: false
63
52
  requirements:
64
53
  - - ! '>='
@@ -66,10 +55,10 @@ dependencies:
66
55
  version: '0'
67
56
  type: :development
68
57
  prerelease: false
69
- version_requirements: *70245624904800
58
+ version_requirements: *70210208534860
70
59
  - !ruby/object:Gem::Dependency
71
60
  name: fakeweb
72
- requirement: &70245624904380 !ruby/object:Gem::Requirement
61
+ requirement: &70210208534440 !ruby/object:Gem::Requirement
73
62
  none: false
74
63
  requirements:
75
64
  - - ! '>='
@@ -77,10 +66,10 @@ dependencies:
77
66
  version: '0'
78
67
  type: :development
79
68
  prerelease: false
80
- version_requirements: *70245624904380
69
+ version_requirements: *70210208534440
81
70
  - !ruby/object:Gem::Dependency
82
71
  name: vcr
83
- requirement: &70245624903960 !ruby/object:Gem::Requirement
72
+ requirement: &70210208534020 !ruby/object:Gem::Requirement
84
73
  none: false
85
74
  requirements:
86
75
  - - ! '>='
@@ -88,7 +77,7 @@ dependencies:
88
77
  version: '0'
89
78
  type: :development
90
79
  prerelease: false
91
- version_requirements: *70245624903960
80
+ version_requirements: *70210208534020
92
81
  description: Send image/video to an airplay enabled device
93
82
  email:
94
83
  - yo@brunoaguirre.com
@@ -97,28 +86,32 @@ extensions: []
97
86
  extra_rdoc_files: []
98
87
  files:
99
88
  - .gitignore
89
+ - Gemfile
100
90
  - README.md
101
91
  - Rakefile
102
92
  - airplay.gemspec
103
93
  - lib/airplay.rb
104
94
  - lib/airplay/client.rb
105
- - lib/airplay/node.rb
106
95
  - lib/airplay/protocol.rb
107
96
  - lib/airplay/protocol/image.rb
97
+ - lib/airplay/protocol/media.rb
108
98
  - lib/airplay/protocol/scrub.rb
109
- - lib/airplay/protocol/video.rb
99
+ - lib/airplay/server.rb
100
+ - lib/airplay/server/browser.rb
101
+ - lib/airplay/server/node.rb
110
102
  - test/authentication.rb
111
103
  - test/discovery.rb
112
104
  - test/fixtures/cassettes/airplay/authenticate_all_the_things_.yml
113
105
  - test/fixtures/cassettes/airplay/get_current_scrub_from_apple_tv.yml
106
+ - test/fixtures/cassettes/airplay/send_audio_to_apple_tv.yml
114
107
  - test/fixtures/cassettes/airplay/send_image_to_apple_tv.yml
115
108
  - test/fixtures/cassettes/airplay/send_video_to_apple_tv.yml
116
109
  - test/fixtures/image.gif
117
110
  - test/fixtures/image2.gif
118
111
  - test/helper.rb
119
112
  - test/images.rb
113
+ - test/media.rb
120
114
  - test/scrub.rb
121
- - test/video.rb
122
115
  has_rdoc: true
123
116
  homepage: http://github.com/elcuervo/airplay
124
117
  licenses: []
@@ -1,21 +0,0 @@
1
- require File.expand_path("helper", File.dirname(__FILE__))
2
-
3
- scope do
4
- test "check video protocol class" do
5
- image_protocol = Airplay::Protocol::Video.new("127.0.0.1")
6
- assert_equal "/play", image_protocol.resource
7
- end
8
- end
9
-
10
- scope do
11
- setup do
12
- @airplay = Airplay::Client.new
13
- end
14
-
15
- test "send a video to the server" do
16
- VCR.use_cassette("send video to apple tv") do
17
- @airplay.use("Apple TV")
18
- assert @airplay.send_video("http://www.yo-yo.org/mp4/yu.mp4").kind_of?(String)
19
- end
20
- end
21
- end