airplay 1.0.0.beta1 → 1.0.0.beta2
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 +1 -0
- data/.travis.yml +9 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +3 -7
- data/README.md +2 -1
- data/Rakefile +74 -0
- data/airplay-cli.gemspec +19 -0
- data/airplay.gemspec +5 -8
- data/examples/demo.rb +5 -8
- data/lib/airplay.rb +20 -2
- data/lib/airplay/cli/version.rb +5 -0
- data/lib/airplay/configuration.rb +8 -3
- data/lib/airplay/connection.rb +0 -7
- data/lib/airplay/devices.rb +4 -1
- data/lib/airplay/group.rb +33 -0
- data/lib/airplay/group/players.rb +31 -0
- data/lib/airplay/playable.rb +7 -3
- data/lib/airplay/{protocol/player.rb → player.rb} +37 -17
- data/lib/airplay/player/media.rb +22 -0
- data/lib/airplay/player/playback_info.rb +51 -0
- data/lib/airplay/player/playlist.rb +41 -0
- data/lib/airplay/player/timers.rb +27 -0
- data/lib/airplay/server.rb +56 -0
- data/lib/airplay/server/app.rb +17 -0
- data/lib/airplay/version.rb +3 -0
- data/lib/airplay/viewable.rb +2 -2
- data/lib/airplay/{protocol/viewer.rb → viewer.rb} +2 -2
- metadata +22 -73
- data/lib/airplay/protocol.rb +0 -12
- data/lib/airplay/protocol/app.rb +0 -52
- data/lib/airplay/protocol/message.rb +0 -8
- data/lib/airplay/protocol/playback_info.rb +0 -49
- data/lib/airplay/protocol/reverse.rb +0 -69
- data/lib/airplay/protocol/slideshow.rb +0 -66
- data/lib/airplay/protocol/timers.rb +0 -25
- data/test/fixtures/cassettes/airplay/listing_slideshow_features.yml +0 -201
- data/test/fixtures/cassettes/airplay/play_an_entire_video.yml +0 -100
- data/test/fixtures/cassettes/airplay/sending_a_video.yml +0 -71
- data/test/fixtures/cassettes/airplay/sending_an_image.yml +0 -26439
- data/test/fixtures/cassettes/airplay/stop_any_transmission.yml +0 -8851
- data/test/integration/discovery_test.rb +0 -13
- data/test/integration/features_test.rb +0 -14
- data/test/integration/send_media_test.rb +0 -37
- data/test/integration/slideshow_test.rb +0 -26
- data/test/test_helper.rb +0 -42
- data/test/unit/node_test.rb +0 -17
- data/test/unit/protocol_test.rb +0 -44
data/.gitignore
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
pkg
|
data/.travis.yml
ADDED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
airplay (1.0.0.
|
|
4
|
+
airplay (1.0.0.beta2)
|
|
5
5
|
CFPropertyList (~> 2.2.0)
|
|
6
6
|
celluloid (~> 0.15.0)
|
|
7
|
-
clap (~> 1.0.0)
|
|
8
7
|
cuba (~> 3.1.0)
|
|
9
8
|
dnssd (~> 2.0)
|
|
10
9
|
log4r (~> 1.1.10)
|
|
11
10
|
micromachine (~> 1.0.4)
|
|
12
11
|
net-http-digest_auth (~> 1.2.1)
|
|
13
|
-
net-ptth (
|
|
14
|
-
ruby-progressbar (~> 1.2.0)
|
|
12
|
+
net-ptth (= 0.0.12)
|
|
15
13
|
uuid (~> 2.3.6)
|
|
16
14
|
|
|
17
15
|
GEM
|
|
@@ -23,7 +21,6 @@ GEM
|
|
|
23
21
|
celluloid-io (0.15.0)
|
|
24
22
|
celluloid (>= 0.15.0)
|
|
25
23
|
nio4r (>= 0.5.0)
|
|
26
|
-
clap (1.0.0)
|
|
27
24
|
columnize (0.3.6)
|
|
28
25
|
cuba (3.1.0)
|
|
29
26
|
rack
|
|
@@ -42,14 +39,13 @@ GEM
|
|
|
42
39
|
micromachine (1.0.4)
|
|
43
40
|
minitest (4.4.0)
|
|
44
41
|
net-http-digest_auth (1.2.1)
|
|
45
|
-
net-ptth (0.0.
|
|
42
|
+
net-ptth (0.0.12)
|
|
46
43
|
celluloid-io (~> 0.15.0)
|
|
47
44
|
http_parser.rb (~> 0.5.3)
|
|
48
45
|
rack (~> 1.4.5)
|
|
49
46
|
nio4r (0.5.0)
|
|
50
47
|
rack (1.4.5)
|
|
51
48
|
rake (10.1.0)
|
|
52
|
-
ruby-progressbar (1.2.0)
|
|
53
49
|
systemu (2.5.2)
|
|
54
50
|
timers (1.1.0)
|
|
55
51
|
uuid (2.3.7)
|
data/README.md
CHANGED
data/Rakefile
CHANGED
|
@@ -1,9 +1,83 @@
|
|
|
1
|
+
$: << File.expand_path("../lib", __FILE__)
|
|
2
|
+
|
|
1
3
|
require "rake/testtask"
|
|
4
|
+
require "fileutils"
|
|
5
|
+
require "airplay/version"
|
|
6
|
+
require "airplay/cli/version"
|
|
2
7
|
|
|
3
8
|
Rake::TestTask.new("spec") do |t|
|
|
4
9
|
t.libs << "test"
|
|
5
10
|
t.pattern = "test/**/*_test.rb"
|
|
6
11
|
end
|
|
7
12
|
|
|
13
|
+
class RuleBuilder
|
|
14
|
+
attr_reader :task, :info
|
|
15
|
+
|
|
16
|
+
TASKS = [:lib, :cli]
|
|
17
|
+
|
|
18
|
+
def initialize(options = {})
|
|
19
|
+
@task = options[:task]
|
|
20
|
+
|
|
21
|
+
@info = {
|
|
22
|
+
lib: { name: "airplay", version: Airplay::VERSION },
|
|
23
|
+
cli: { name: "airplay-cli", version: Airplay::CLI::VERSION }
|
|
24
|
+
}
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def construct(action)
|
|
28
|
+
-> n {
|
|
29
|
+
task.call(:all) do
|
|
30
|
+
TASKS.each { |task| Rake::Task["#{action}:#{task}"].invoke }
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
TASKS.each do |task_name|
|
|
34
|
+
task.call(task_name) { action_method(action, task_name) }
|
|
35
|
+
end
|
|
36
|
+
}
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
def action_method(action, task_name)
|
|
42
|
+
method("#{action}_gem".to_sym).call(task_name)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def build_gem(type)
|
|
46
|
+
name = info[type][:name]
|
|
47
|
+
version = info[type][:version]
|
|
48
|
+
|
|
49
|
+
gem_name = "#{name}-#{version}.gem"
|
|
50
|
+
|
|
51
|
+
FileUtils.mkdir_p("pkg")
|
|
52
|
+
`gem build #{name}.gemspec`
|
|
53
|
+
FileUtils.mv(gem_name, "pkg")
|
|
54
|
+
|
|
55
|
+
puts "#{name} (v#{version}) builded!"
|
|
56
|
+
|
|
57
|
+
"./pkg/#{gem_name}"
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def install_gem(type)
|
|
61
|
+
name = info[type][:name]
|
|
62
|
+
gem_path = build_gem(type)
|
|
63
|
+
`gem install --local #{gem_path}`
|
|
64
|
+
|
|
65
|
+
puts "#{gem_path} installed!"
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def release_gem(type)
|
|
69
|
+
name = info[type][:name]
|
|
70
|
+
gem_path = build_gem(type)
|
|
71
|
+
`gem push #{gem_path}`
|
|
72
|
+
|
|
73
|
+
puts "#{gem_path} released!"
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
builder = RuleBuilder.new(task: method(:task))
|
|
78
|
+
namespace :build, &builder.construct(:build)
|
|
79
|
+
namespace :install, &builder.construct(:install)
|
|
80
|
+
namespace :release, &builder.construct(:release)
|
|
81
|
+
|
|
8
82
|
task :default => [:test]
|
|
9
83
|
task :test => [:spec]
|
data/airplay-cli.gemspec
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
$: << File.expand_path("../lib", __FILE__)
|
|
2
|
+
require "airplay/cli/version"
|
|
3
|
+
|
|
4
|
+
Gem::Specification.new do |s|
|
|
5
|
+
s.name = "airplay-cli"
|
|
6
|
+
s.version = Airplay::CLI::VERSION
|
|
7
|
+
s.summary = "Airplay client CLI"
|
|
8
|
+
s.description = "Send pics and videos using the terminal"
|
|
9
|
+
s.executables = "air"
|
|
10
|
+
s.licenses = ["MIT", "HUGWARE"]
|
|
11
|
+
s.authors = ["elcuervo"]
|
|
12
|
+
s.email = ["yo@brunoaguirre.com"]
|
|
13
|
+
s.homepage = "http://github.com/elcuervo/airplay"
|
|
14
|
+
s.files = %w(bin/air lib/airplay/cli.rb)
|
|
15
|
+
|
|
16
|
+
s.add_dependency("airplay", "~> 1.0.0.beta2")
|
|
17
|
+
s.add_dependency("clap", "~> 1.0.0")
|
|
18
|
+
s.add_dependency("ruby-progressbar", "~> 1.2.0")
|
|
19
|
+
end
|
data/airplay.gemspec
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
$: << File.expand_path("../lib", __FILE__)
|
|
2
|
+
require "airplay/version"
|
|
3
|
+
|
|
1
4
|
Gem::Specification.new do |s|
|
|
2
5
|
s.name = "airplay"
|
|
3
|
-
s.version =
|
|
6
|
+
s.version = Airplay::VERSION
|
|
4
7
|
s.summary = "Airplay client"
|
|
5
8
|
s.description = "Send image/video to an airplay enabled device"
|
|
6
|
-
s.executables = "air"
|
|
7
9
|
s.licenses = ["MIT", "HUGWARE"]
|
|
8
10
|
s.authors = ["elcuervo"]
|
|
9
11
|
s.email = ["yo@brunoaguirre.com"]
|
|
@@ -11,7 +13,6 @@ Gem::Specification.new do |s|
|
|
|
11
13
|
s.files = `git ls-files`.split("\n")
|
|
12
14
|
s.test_files = `git ls-files test`.split("\n")
|
|
13
15
|
|
|
14
|
-
# Lib
|
|
15
16
|
s.add_dependency("dnssd", "~> 2.0")
|
|
16
17
|
s.add_dependency("uuid", "~> 2.3.6")
|
|
17
18
|
s.add_dependency("CFPropertyList", "~> 2.2.0")
|
|
@@ -19,13 +20,9 @@ Gem::Specification.new do |s|
|
|
|
19
20
|
s.add_dependency("cuba", "~> 3.1.0")
|
|
20
21
|
s.add_dependency("micromachine", "~> 1.0.4")
|
|
21
22
|
s.add_dependency("celluloid", "~> 0.15.0")
|
|
22
|
-
s.add_dependency("net-ptth", "
|
|
23
|
+
s.add_dependency("net-ptth", "= 0.0.12")
|
|
23
24
|
s.add_dependency("net-http-digest_auth", "~> 1.2.1")
|
|
24
25
|
|
|
25
|
-
# CLI
|
|
26
|
-
s.add_dependency("clap", "~> 1.0.0")
|
|
27
|
-
s.add_dependency("ruby-progressbar", "~> 1.2.0")
|
|
28
|
-
|
|
29
26
|
s.add_development_dependency("minitest", "~> 4.4.0")
|
|
30
27
|
s.add_development_dependency("fakeweb", "~> 1.3.0")
|
|
31
28
|
s.add_development_dependency("vcr", "~> 2.4.0")
|
data/examples/demo.rb
CHANGED
|
@@ -11,21 +11,18 @@ videos = [
|
|
|
11
11
|
]
|
|
12
12
|
|
|
13
13
|
apple_tv = Airplay["Apple TV"]
|
|
14
|
-
player = apple_tv.play(videos.last)
|
|
15
|
-
sleep 4
|
|
16
|
-
player.stop
|
|
17
|
-
sleep 5
|
|
18
|
-
|
|
19
|
-
|
|
20
14
|
|
|
15
|
+
apple_tv.view("./test/fixtures/files/logo.png", transition: "SlideLeft")
|
|
16
|
+
sleep 2
|
|
17
|
+
puts apple_tv.view("./test/fixtures/files/a.png", transition: "SlideLeft")
|
|
18
|
+
sleep 20
|
|
21
19
|
exit
|
|
22
20
|
|
|
23
21
|
videos.each do |video|
|
|
24
22
|
player = apple_tv.play(video)
|
|
23
|
+
sleep 10
|
|
25
24
|
end
|
|
26
25
|
|
|
27
|
-
apple_tv.stop
|
|
28
|
-
|
|
29
26
|
Airplay.group["Backyard"] << Airplay["Pool TV"]
|
|
30
27
|
Airplay.group["Backyard"] << Airplay.devices.add("BBQTV", "192.168.1.12")
|
|
31
28
|
|
data/lib/airplay.rb
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
require "airplay/configuration"
|
|
2
2
|
require "airplay/browser"
|
|
3
|
+
require "airplay/group"
|
|
4
|
+
require "airplay/server"
|
|
5
|
+
require "airplay/version"
|
|
3
6
|
|
|
4
7
|
# Public: Airplay core module
|
|
5
8
|
#
|
|
@@ -9,14 +12,30 @@ module Airplay
|
|
|
9
12
|
yield(configuration) if block
|
|
10
13
|
end
|
|
11
14
|
|
|
15
|
+
def server
|
|
16
|
+
@_server ||= Server.new
|
|
17
|
+
end
|
|
18
|
+
|
|
12
19
|
def browse
|
|
13
20
|
browser.browse
|
|
14
21
|
end
|
|
15
22
|
|
|
23
|
+
def group
|
|
24
|
+
@_group ||= Hash.new { |h, k| h[k] = Group.new(k) }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def all
|
|
28
|
+
@_all ||= begin
|
|
29
|
+
group = Group.new(:all)
|
|
30
|
+
devices.each { |device| group << device }
|
|
31
|
+
group
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
16
35
|
# Public: Lists found devices
|
|
17
36
|
#
|
|
18
37
|
def devices
|
|
19
|
-
browse if browser.devices.empty?
|
|
38
|
+
browse if browser.devices.empty? && configuration.autodiscover
|
|
20
39
|
browser.devices
|
|
21
40
|
end
|
|
22
41
|
|
|
@@ -35,4 +54,3 @@ module Airplay
|
|
|
35
54
|
end
|
|
36
55
|
end
|
|
37
56
|
end
|
|
38
|
-
|
|
@@ -1,15 +1,19 @@
|
|
|
1
|
-
require
|
|
1
|
+
require "log4r/config"
|
|
2
|
+
require "airplay/logger"
|
|
2
3
|
|
|
3
4
|
module Airplay
|
|
4
5
|
# Public: Handles the Airplay configuration
|
|
5
6
|
#
|
|
6
7
|
class Configuration
|
|
7
|
-
attr_accessor :log_level, :output
|
|
8
|
+
attr_accessor :log_level, :output, :autodiscover, :host, :port
|
|
8
9
|
|
|
9
10
|
def initialize
|
|
10
11
|
Log4r.define_levels(*Log4r::Log4rConfig::LogLevels)
|
|
11
12
|
|
|
12
|
-
@log_level = Log4r::
|
|
13
|
+
@log_level = Log4r::ERROR
|
|
14
|
+
@autodiscover = true
|
|
15
|
+
@host = "0.0.0.0"
|
|
16
|
+
@port = "1337"
|
|
13
17
|
@output = Log4r::Outputter.stdout
|
|
14
18
|
end
|
|
15
19
|
|
|
@@ -24,6 +28,7 @@ module Airplay
|
|
|
24
28
|
|
|
25
29
|
Log4r::Logger.root.add @output
|
|
26
30
|
Log4r::Logger.root.level = level
|
|
31
|
+
Celluloid.logger = Airplay::Logger.new("airplay::celluloid")
|
|
27
32
|
end
|
|
28
33
|
end
|
|
29
34
|
end
|
data/lib/airplay/connection.rb
CHANGED
|
@@ -8,8 +8,6 @@ module Airplay
|
|
|
8
8
|
class Connection
|
|
9
9
|
Response = Struct.new(:connection, :response)
|
|
10
10
|
|
|
11
|
-
attr_accessor :reverse, :events, :persistent
|
|
12
|
-
|
|
13
11
|
include Celluloid
|
|
14
12
|
|
|
15
13
|
def initialize(device, options = {})
|
|
@@ -23,11 +21,6 @@ module Airplay
|
|
|
23
21
|
@_persistent ||= Airplay::Connection::Persistent.new(address, @options)
|
|
24
22
|
end
|
|
25
23
|
|
|
26
|
-
def start_reverse_connection
|
|
27
|
-
@reverse = Airplay::Protocol::Reverse.new(Airplay.active)
|
|
28
|
-
@reverse.async.connect
|
|
29
|
-
end
|
|
30
|
-
|
|
31
24
|
def close
|
|
32
25
|
persistent.close
|
|
33
26
|
@_persistent = nil
|
data/lib/airplay/devices.rb
CHANGED
|
@@ -28,6 +28,10 @@ module Airplay
|
|
|
28
28
|
find_by_block { |device| device if device.ip == ip }
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
+
def add(name, address)
|
|
32
|
+
self << Device.new(name: name, address: address)
|
|
33
|
+
end
|
|
34
|
+
|
|
31
35
|
# Public: Adds a device to the list
|
|
32
36
|
#
|
|
33
37
|
# value - The Node
|
|
@@ -41,6 +45,5 @@ module Airplay
|
|
|
41
45
|
def find_by_block(&block)
|
|
42
46
|
@items.find(&block)
|
|
43
47
|
end
|
|
44
|
-
|
|
45
48
|
end
|
|
46
49
|
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
require "forwardable"
|
|
2
|
+
require "airplay/group/players"
|
|
3
|
+
|
|
4
|
+
module Airplay
|
|
5
|
+
class Group
|
|
6
|
+
include Enumerable
|
|
7
|
+
extend Forwardable
|
|
8
|
+
|
|
9
|
+
def_delegators :@devices, :each, :size, :empty?
|
|
10
|
+
|
|
11
|
+
def initialize(name)
|
|
12
|
+
@devices = []
|
|
13
|
+
@players = []
|
|
14
|
+
@name = name
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def <<(device)
|
|
18
|
+
@devices << device
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def play(file_or_url, options = {})
|
|
22
|
+
@players = @devices.map { |device| device.play(file_or_url, options) }
|
|
23
|
+
Players.new(@players)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def view(media_or_io, options = {})
|
|
27
|
+
@devices.map do |device|
|
|
28
|
+
ok = device.view(media_or_io, options)
|
|
29
|
+
[device, ok]
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module Airplay
|
|
2
|
+
class Group
|
|
3
|
+
class Players
|
|
4
|
+
attr_reader :players
|
|
5
|
+
|
|
6
|
+
def initialize(players)
|
|
7
|
+
@players = players
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def progress(callback)
|
|
11
|
+
players.each do |player|
|
|
12
|
+
player.progress -> info {
|
|
13
|
+
callback.call(player.device, info) if player.playing?
|
|
14
|
+
}
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def wait
|
|
19
|
+
sleep 0.1 while still_playing?
|
|
20
|
+
players.map(&:cleanup)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def still_playing?
|
|
26
|
+
states = players.map { |player| !player.played? || player.stopped? }
|
|
27
|
+
states.uniq == [true]
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
data/lib/airplay/playable.rb
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
require "airplay/
|
|
1
|
+
require "airplay/player"
|
|
2
2
|
|
|
3
3
|
module Airplay
|
|
4
4
|
module Playable
|
|
@@ -10,15 +10,19 @@ module Airplay
|
|
|
10
10
|
#
|
|
11
11
|
# Returns a Player object to control the playback
|
|
12
12
|
#
|
|
13
|
-
def play(file_or_url, options = {})
|
|
13
|
+
def play(file_or_url = "playlist", options = {})
|
|
14
14
|
player.async.play(file_or_url, options)
|
|
15
15
|
player
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
+
def playlist
|
|
19
|
+
player.playlist
|
|
20
|
+
end
|
|
21
|
+
|
|
18
22
|
private
|
|
19
23
|
|
|
20
24
|
def player
|
|
21
|
-
@_player ||= Airplay::
|
|
25
|
+
@_player ||= Airplay::Player.new(self)
|
|
22
26
|
end
|
|
23
27
|
end
|
|
24
28
|
end
|