airplayer 0.0.8 → 0.0.9
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.
- checksums.yaml +4 -4
- data/Gemfile.lock +74 -37
- data/airplayer.gemspec +2 -1
- data/lib/airplayer.rb +1 -3
- data/lib/airplayer/app.rb +6 -3
- data/lib/airplayer/controller.rb +23 -85
- data/lib/airplayer/device.rb +19 -18
- data/lib/airplayer/media.rb +1 -11
- data/lib/airplayer/version.rb +1 -1
- data/spec/airplayer/app_spec.rb +25 -3
- data/spec/airplayer/controller_spec.rb +35 -0
- data/spec/airplayer/device_spec.rb +56 -0
- data/spec/airplayer/media_spec.rb +31 -35
- data/spec/airplayer/playlist_spec.rb +36 -19
- data/spec/spec_helper.rb +37 -2
- metadata +24 -11
- data/lib/airplayer/logger.rb +0 -18
- data/lib/airplayer/progress_bar/base.rb +0 -9
- data/lib/airplayer/server.rb +0 -41
- data/spec/airplayer/logger_spec.rb +0 -15
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8498cbf608d7722d098753117793a825b4f65e04
|
|
4
|
+
data.tar.gz: 67b89490ab729572c54f0d3d259b86d0a62183b5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 95a6c703fd68fe8975ae9bf567956a13f333dec5cef75cb79e59b5e066a15b812fb5396a934cdb339af5e423e355a62c94db091f736b101cb8f82653b6cd6365
|
|
7
|
+
data.tar.gz: dfe225b835b481d59d6df7dd5416e1b710f58221d42f9ac29b34213d59a7014b88619f0be2c5fd9809c42101637ed82decbab4ccfa757f033912031fa465c377
|
data/Gemfile.lock
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
airplayer (0.0.
|
|
5
|
-
airplay (
|
|
4
|
+
airplayer (0.0.9)
|
|
5
|
+
airplay (= 1.0.2)
|
|
6
6
|
mime-types
|
|
7
7
|
nokogiri
|
|
8
8
|
rack
|
|
@@ -12,75 +12,111 @@ PATH
|
|
|
12
12
|
GEM
|
|
13
13
|
remote: https://rubygems.org/
|
|
14
14
|
specs:
|
|
15
|
-
|
|
15
|
+
CFPropertyList (2.2.6)
|
|
16
|
+
airplay (1.0.2)
|
|
17
|
+
CFPropertyList (~> 2.2.0)
|
|
18
|
+
celluloid (>= 0.15.0)
|
|
19
|
+
cuba (~> 3.1.0)
|
|
16
20
|
dnssd (~> 2.0)
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
21
|
+
log4r (~> 1.1.10)
|
|
22
|
+
micromachine (~> 1.0.4)
|
|
23
|
+
mime-types (>= 1.16)
|
|
24
|
+
net-http-digest_auth (~> 1.2.1)
|
|
25
|
+
net-ptth (= 0.0.17)
|
|
26
|
+
reel-rack (~> 0.1.0)
|
|
27
|
+
celluloid (0.15.2)
|
|
20
28
|
timers (~> 1.1.0)
|
|
21
|
-
|
|
29
|
+
celluloid-io (0.15.0)
|
|
30
|
+
celluloid (>= 0.15.0)
|
|
31
|
+
nio4r (>= 0.5.0)
|
|
32
|
+
coderay (1.1.0)
|
|
22
33
|
coveralls (0.7.0)
|
|
23
34
|
multi_json (~> 1.3)
|
|
24
35
|
rest-client
|
|
25
36
|
simplecov (>= 0.7)
|
|
26
37
|
term-ansicolor
|
|
27
38
|
thor
|
|
28
|
-
|
|
39
|
+
cuba (3.1.0)
|
|
40
|
+
rack
|
|
41
|
+
diff-lcs (1.2.5)
|
|
29
42
|
dnssd (2.0)
|
|
30
|
-
|
|
43
|
+
docile (1.1.2)
|
|
44
|
+
fakefs (0.5.0)
|
|
45
|
+
ffi (1.9.3)
|
|
31
46
|
formatador (0.2.4)
|
|
32
|
-
guard (2.0
|
|
47
|
+
guard (2.3.0)
|
|
33
48
|
formatador (>= 0.2.4)
|
|
34
|
-
listen (~> 2.
|
|
49
|
+
listen (~> 2.1)
|
|
35
50
|
lumberjack (~> 1.0)
|
|
36
51
|
pry (>= 0.9.12)
|
|
37
52
|
thor (>= 0.18.1)
|
|
38
|
-
guard-rspec (
|
|
39
|
-
guard (
|
|
40
|
-
rspec (
|
|
41
|
-
|
|
42
|
-
|
|
53
|
+
guard-rspec (4.2.4)
|
|
54
|
+
guard (~> 2.1)
|
|
55
|
+
rspec (>= 2.14, < 4.0)
|
|
56
|
+
http (0.5.0)
|
|
57
|
+
http_parser.rb
|
|
58
|
+
http_parser.rb (0.6.0)
|
|
59
|
+
listen (2.4.0)
|
|
60
|
+
celluloid (>= 0.15.2)
|
|
43
61
|
rb-fsevent (>= 0.9.3)
|
|
44
62
|
rb-inotify (>= 0.9)
|
|
63
|
+
log4r (1.1.10)
|
|
45
64
|
lumberjack (1.0.4)
|
|
46
65
|
method_source (0.8.2)
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
net-http-
|
|
52
|
-
|
|
66
|
+
micromachine (1.0.4)
|
|
67
|
+
mime-types (2.0)
|
|
68
|
+
mini_portile (0.5.2)
|
|
69
|
+
multi_json (1.8.4)
|
|
70
|
+
net-http-digest_auth (1.2.1)
|
|
71
|
+
net-ptth (0.0.17)
|
|
72
|
+
celluloid-io (>= 0.15.0)
|
|
73
|
+
http_parser.rb (>= 0.6.0.beta.2)
|
|
74
|
+
rack (>= 1.4.5)
|
|
75
|
+
nio4r (1.0.0)
|
|
76
|
+
nokogiri (1.6.1)
|
|
53
77
|
mini_portile (~> 0.5.0)
|
|
54
|
-
pry (0.9.12.
|
|
55
|
-
coderay (~> 1.0
|
|
78
|
+
pry (0.9.12.4)
|
|
79
|
+
coderay (~> 1.0)
|
|
56
80
|
method_source (~> 0.8)
|
|
57
81
|
slop (~> 3.4)
|
|
58
82
|
rack (1.5.2)
|
|
59
|
-
rake (10.1.
|
|
60
|
-
rb-fsevent (0.9.
|
|
61
|
-
rb-inotify (0.9.
|
|
83
|
+
rake (10.1.1)
|
|
84
|
+
rb-fsevent (0.9.4)
|
|
85
|
+
rb-inotify (0.9.3)
|
|
62
86
|
ffi (>= 0.5.0)
|
|
87
|
+
reel (0.4.0)
|
|
88
|
+
celluloid (>= 0.15.1)
|
|
89
|
+
celluloid-io (>= 0.15.0)
|
|
90
|
+
http (>= 0.5.0)
|
|
91
|
+
http_parser.rb (>= 0.6.0.beta.2)
|
|
92
|
+
websocket_parser (>= 0.1.4)
|
|
93
|
+
reel-rack (0.1.0)
|
|
94
|
+
rack (>= 1.4.0)
|
|
95
|
+
reel (>= 0.4.0)
|
|
63
96
|
rest-client (1.6.7)
|
|
64
97
|
mime-types (>= 1.16)
|
|
65
98
|
rspec (2.14.1)
|
|
66
99
|
rspec-core (~> 2.14.0)
|
|
67
100
|
rspec-expectations (~> 2.14.0)
|
|
68
101
|
rspec-mocks (~> 2.14.0)
|
|
69
|
-
rspec-core (2.14.
|
|
70
|
-
rspec-expectations (2.14.
|
|
102
|
+
rspec-core (2.14.7)
|
|
103
|
+
rspec-expectations (2.14.4)
|
|
71
104
|
diff-lcs (>= 1.1.3, < 2.0)
|
|
72
|
-
rspec-mocks (2.14.
|
|
73
|
-
ruby-progressbar (1.
|
|
74
|
-
simplecov (0.
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
105
|
+
rspec-mocks (2.14.4)
|
|
106
|
+
ruby-progressbar (1.4.0)
|
|
107
|
+
simplecov (0.8.2)
|
|
108
|
+
docile (~> 1.1.0)
|
|
109
|
+
multi_json
|
|
110
|
+
simplecov-html (~> 0.8.0)
|
|
111
|
+
simplecov-html (0.8.0)
|
|
112
|
+
slop (3.4.7)
|
|
79
113
|
term-ansicolor (1.2.2)
|
|
80
114
|
tins (~> 0.8)
|
|
81
115
|
thor (0.18.1)
|
|
82
116
|
timers (1.1.0)
|
|
83
|
-
tins (0.
|
|
117
|
+
tins (0.13.1)
|
|
118
|
+
websocket_parser (0.1.5)
|
|
119
|
+
http
|
|
84
120
|
|
|
85
121
|
PLATFORMS
|
|
86
122
|
ruby
|
|
@@ -89,6 +125,7 @@ DEPENDENCIES
|
|
|
89
125
|
airplayer!
|
|
90
126
|
bundler
|
|
91
127
|
coveralls
|
|
128
|
+
fakefs
|
|
92
129
|
guard-rspec
|
|
93
130
|
rake
|
|
94
131
|
rspec
|
data/airplayer.gemspec
CHANGED
|
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
|
|
|
19
19
|
|
|
20
20
|
spec.add_runtime_dependency 'thor'
|
|
21
21
|
spec.add_runtime_dependency 'ruby-progressbar'
|
|
22
|
-
spec.add_runtime_dependency 'airplay', '
|
|
22
|
+
spec.add_runtime_dependency 'airplay', '= 1.0.2'
|
|
23
23
|
spec.add_runtime_dependency 'rack'
|
|
24
24
|
spec.add_runtime_dependency 'mime-types'
|
|
25
25
|
spec.add_runtime_dependency 'nokogiri'
|
|
@@ -28,5 +28,6 @@ Gem::Specification.new do |spec|
|
|
|
28
28
|
spec.add_development_dependency 'rake'
|
|
29
29
|
spec.add_development_dependency 'rspec'
|
|
30
30
|
spec.add_development_dependency 'guard-rspec'
|
|
31
|
+
spec.add_development_dependency 'fakefs'
|
|
31
32
|
spec.add_development_dependency 'coveralls'
|
|
32
33
|
end
|
data/lib/airplayer.rb
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
require 'rubygems'
|
|
2
1
|
require 'airplay'
|
|
2
|
+
Airplay.configuration.load
|
|
3
3
|
|
|
4
4
|
module AirPlayer
|
|
5
5
|
require 'airplayer/version'
|
|
6
|
-
require 'airplayer/logger'
|
|
7
6
|
require 'airplayer/app'
|
|
8
7
|
require 'airplayer/controller'
|
|
9
8
|
require 'airplayer/device'
|
|
10
|
-
require 'airplayer/server'
|
|
11
9
|
require 'airplayer/playlist'
|
|
12
10
|
require 'airplayer/media'
|
|
13
11
|
end
|
data/lib/airplayer/app.rb
CHANGED
|
@@ -7,15 +7,18 @@ module AirPlayer
|
|
|
7
7
|
method_option :shuffle, aliases: '-s', desc: 'Shuffle play', type: :boolean
|
|
8
8
|
method_option :device, aliases: '-d', desc: 'Device number', type: :numeric
|
|
9
9
|
def play(target)
|
|
10
|
-
controller = Controller.new
|
|
10
|
+
controller = Controller.new(device: options.fetch('device', 0))
|
|
11
11
|
Playlist.new(options).add(target).entries do |media|
|
|
12
|
-
controller.play(media
|
|
12
|
+
controller.play(media)
|
|
13
|
+
controller.pause
|
|
13
14
|
end
|
|
14
15
|
end
|
|
15
16
|
|
|
16
17
|
desc 'devices', 'Show AirPlay devices'
|
|
17
18
|
def devices
|
|
18
|
-
Device.
|
|
19
|
+
Device.devices.each_with_index do |device, number|
|
|
20
|
+
puts "#{number}: #{device.name} (Resolution: #{device.info.resolution}, Version: #{device.info.os_version}, IP: #{device.address})"
|
|
21
|
+
end
|
|
19
22
|
end
|
|
20
23
|
|
|
21
24
|
map '--version' => :version
|
data/lib/airplayer/controller.rb
CHANGED
|
@@ -1,98 +1,36 @@
|
|
|
1
|
-
require '
|
|
2
|
-
require 'airplayer/progress_bar/base'
|
|
1
|
+
require 'ruby-progressbar'
|
|
3
2
|
|
|
4
3
|
module AirPlayer
|
|
5
4
|
class Controller
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
@
|
|
10
|
-
@player = nil
|
|
11
|
-
@progressbar = nil
|
|
12
|
-
@timeout = 30
|
|
13
|
-
@interval = 1
|
|
14
|
-
@total_sec = 0
|
|
15
|
-
@current_sec = 0
|
|
16
|
-
rescue Airplay::Client::ServerNotFoundError
|
|
17
|
-
abort '[ERROR] AirPlay device is not found'
|
|
5
|
+
def initialize(options = { device: nil })
|
|
6
|
+
@device = Device.get(options[:device])
|
|
7
|
+
@player = nil
|
|
8
|
+
@progressbar = nil
|
|
18
9
|
end
|
|
19
10
|
|
|
20
|
-
def play(media
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
@player
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
@progressbar.title = :Complete
|
|
33
|
-
pause
|
|
34
|
-
media.close
|
|
35
|
-
rescue BufferingTimeoutError
|
|
36
|
-
abort '[ERROR] Buffering timeout'
|
|
37
|
-
rescue TypeError
|
|
38
|
-
abort '[ERROR] Not media class'
|
|
39
|
-
rescue
|
|
40
|
-
abort 'Play stopped'
|
|
11
|
+
def play(media)
|
|
12
|
+
puts " Source: #{media.path}"
|
|
13
|
+
puts " Title: #{media.title}"
|
|
14
|
+
puts " Device: #{@device.name} (Resolution: #{@device.info.resolution})"
|
|
15
|
+
|
|
16
|
+
@progressbar = ProgressBar.create(format: ' %a |%b%i| %p%% %t')
|
|
17
|
+
@player = @device.play(media.path)
|
|
18
|
+
@player.progress -> playback {
|
|
19
|
+
@progressbar.title = 'Streaming'
|
|
20
|
+
@progressbar.progress = playback.percent if playback.percent
|
|
21
|
+
}
|
|
22
|
+
@player.wait
|
|
41
23
|
end
|
|
42
24
|
|
|
43
25
|
def pause
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
def replay
|
|
49
|
-
@player.scrub(0)
|
|
50
|
-
@player.resume
|
|
51
|
-
|
|
52
|
-
@progressbar.reset
|
|
53
|
-
@progressbar.resume
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
private
|
|
57
|
-
def display_information(device, media)
|
|
58
|
-
puts
|
|
59
|
-
puts " Source: #{media.path}"
|
|
60
|
-
puts " Title: #{media.title}"
|
|
61
|
-
puts " Device: #{device.name} (#{device.ip})"
|
|
62
|
-
|
|
63
|
-
@progressbar = ProgressBar.create(format: ' %a |%b%i| %p%% %t')
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
def buffering
|
|
67
|
-
timeout @timeout, BufferingTimeoutError do
|
|
68
|
-
@progressbar.title = :Buffering until playing
|
|
69
|
-
@progressbar.title = :Streaming
|
|
70
|
-
@progressbar.total = @total_sec
|
|
71
|
-
end
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
def playing
|
|
75
|
-
scrub = @player.scrub
|
|
76
|
-
@total_sec = scrub['duration']
|
|
77
|
-
@current_sec = scrub['position']
|
|
78
|
-
sleep @interval
|
|
79
|
-
progress?
|
|
26
|
+
if @player
|
|
27
|
+
@player.stop
|
|
80
28
|
end
|
|
81
29
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
def select_device(device_number = nil)
|
|
87
|
-
device_number ||= 0
|
|
88
|
-
device = Device.new
|
|
89
|
-
|
|
90
|
-
if device.exist?(device_number)
|
|
91
|
-
device.get(device_number)
|
|
92
|
-
else
|
|
93
|
-
puts "Device number #{device_number} is not found. Use default device"
|
|
94
|
-
device.default
|
|
95
|
-
end
|
|
30
|
+
if @progressbar
|
|
31
|
+
@progressbar.title = 'Complete'
|
|
32
|
+
@progressbar.finish
|
|
96
33
|
end
|
|
34
|
+
end
|
|
97
35
|
end
|
|
98
36
|
end
|
data/lib/airplayer/device.rb
CHANGED
|
@@ -1,26 +1,27 @@
|
|
|
1
1
|
module AirPlayer
|
|
2
2
|
class Device
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
def default
|
|
10
|
-
@airplay.browse.first
|
|
11
|
-
end
|
|
3
|
+
class << self
|
|
4
|
+
def devices
|
|
5
|
+
Airplay.devices.to_a
|
|
6
|
+
rescue Airplay::Browser::NoDevicesFound
|
|
7
|
+
abort 'AirPlay devices not found.'
|
|
8
|
+
end
|
|
12
9
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
def get(device_number = 0)
|
|
11
|
+
if exist?(device_number)
|
|
12
|
+
Airplay[devices.at(device_number).name]
|
|
13
|
+
else
|
|
14
|
+
puts "Device number #{device_number} is not found. So choose #{default.name}."
|
|
15
|
+
default
|
|
16
|
+
end
|
|
17
|
+
end
|
|
16
18
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
def exist?(device_number)
|
|
20
|
+
!!devices.at(device_number)
|
|
21
|
+
end
|
|
20
22
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
puts "#{number}: #{device.name} (#{device.ip}:#{device.port})"
|
|
23
|
+
def default
|
|
24
|
+
devices.first
|
|
24
25
|
end
|
|
25
26
|
end
|
|
26
27
|
end
|
data/lib/airplayer/media.rb
CHANGED
|
@@ -31,8 +31,7 @@ module AirPlayer
|
|
|
31
31
|
path = File.expand_path(target)
|
|
32
32
|
|
|
33
33
|
if File.exist? path
|
|
34
|
-
@
|
|
35
|
-
@path = @video_server.uri
|
|
34
|
+
@path = path
|
|
36
35
|
@title = File.basename(path)
|
|
37
36
|
@type = :file
|
|
38
37
|
else
|
|
@@ -56,15 +55,6 @@ module AirPlayer
|
|
|
56
55
|
false
|
|
57
56
|
end
|
|
58
57
|
|
|
59
|
-
def open
|
|
60
|
-
@video_server.start if file?
|
|
61
|
-
@path
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
def close
|
|
65
|
-
@video_server.stop if file?
|
|
66
|
-
end
|
|
67
|
-
|
|
68
58
|
def file?
|
|
69
59
|
@type == :file
|
|
70
60
|
end
|
data/lib/airplayer/version.rb
CHANGED
data/spec/airplayer/app_spec.rb
CHANGED
|
@@ -2,9 +2,31 @@ require 'spec_helper'
|
|
|
2
2
|
|
|
3
3
|
module AirPlayer
|
|
4
4
|
describe App do
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
let (:airplayer) do
|
|
6
|
+
AirPlayer::App.new
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
describe '.new' do
|
|
10
|
+
it 'returns instance of Thor' do
|
|
11
|
+
expect(airplayer).to be_kind_of Thor
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
describe '.devices' do
|
|
16
|
+
before do
|
|
17
|
+
Airplay.devices << double_device
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it 'display devices' do
|
|
21
|
+
devices = capture(:stdout) { airplayer.devices }
|
|
22
|
+
expect(devices).to match double_device.name
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
describe '.version' do
|
|
27
|
+
it 'display version' do
|
|
28
|
+
version = capture(:stdout) { airplayer.version }
|
|
29
|
+
expect(version.chomp).to eq AirPlayer::VERSION
|
|
8
30
|
end
|
|
9
31
|
end
|
|
10
32
|
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module AirPlayer
|
|
4
|
+
describe Controller do
|
|
5
|
+
let (:controller) do
|
|
6
|
+
AirPlayer::Controller
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
before do
|
|
10
|
+
Airplay.devices << double_device
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
describe '.new' do
|
|
14
|
+
context 'with args' do
|
|
15
|
+
it 'returns instance of Controller' do
|
|
16
|
+
expect(controller.new(device: 0)).to be_kind_of Controller
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
context 'without args' do
|
|
21
|
+
it 'raise TypeError' do
|
|
22
|
+
expect{ controller.new }.to raise_error(TypeError)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
describe '.pause' do
|
|
28
|
+
context 'with not playing media' do
|
|
29
|
+
it 'do nothing' do
|
|
30
|
+
expect(controller.new(device: 0).pause).to be nil
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module AirPlayer
|
|
4
|
+
describe Device do
|
|
5
|
+
let (:device) do
|
|
6
|
+
AirPlayer::Device
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
before do
|
|
10
|
+
Airplay.devices << double_device
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
describe '#devices' do
|
|
14
|
+
it 'returns array' do
|
|
15
|
+
expect(device.devices).to be_kind_of Array
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
describe '#get' do
|
|
20
|
+
context 'with exist device number' do
|
|
21
|
+
it 'returns instance of device' do
|
|
22
|
+
expect(device.get(0)).to be_kind_of Airplay::Device
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
context 'with not exist device number' do
|
|
27
|
+
it 'returns default device and display message' do
|
|
28
|
+
default_device = nil
|
|
29
|
+
message = capture(:stdout) { default_device = device.get(99) }
|
|
30
|
+
expect(default_device).to eq device.default
|
|
31
|
+
expect(message).to match('Device number 99 is not found')
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
describe '#exist?' do
|
|
37
|
+
context 'with exist device number' do
|
|
38
|
+
it 'returns true' do
|
|
39
|
+
expect(device.exist?(0)).to be true
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
context 'with not exist device number' do
|
|
44
|
+
it 'returns false' do
|
|
45
|
+
expect(device.exist?(99)).to be false
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
describe '#default' do
|
|
51
|
+
it 'returns first airplay device' do
|
|
52
|
+
expect(device.default).to eq Airplay.devices.first
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -1,54 +1,50 @@
|
|
|
1
1
|
# encoding: UTF-8
|
|
2
|
+
require 'fakefs/spec_helpers'
|
|
2
3
|
require 'spec_helper'
|
|
3
4
|
|
|
4
5
|
module AirPlayer
|
|
5
6
|
describe Media do
|
|
6
|
-
|
|
7
|
+
include FakeFS::SpecHelpers
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
expect(subject.playable?('007 SKYFALL.mp4')).to be_true
|
|
11
|
-
expect(subject.playable?('007 SKYFALL.ts')).to be_true
|
|
12
|
-
expect(subject.playable?('007 SKYFALL.m4v')).to be_true
|
|
13
|
-
expect(subject.playable?('007 SKYFALL.mov')).to be_true
|
|
14
|
-
expect(subject.playable?('007 SKYFALL.ts')).to be_true
|
|
15
|
-
end
|
|
9
|
+
let (:media) do
|
|
10
|
+
AirPlayer::Media
|
|
16
11
|
end
|
|
17
12
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
13
|
+
describe '#playable?' do
|
|
14
|
+
context 'with supported mime types' do
|
|
15
|
+
it 'returns true' do
|
|
16
|
+
expect(media.playable?('007 SKYFALL.mp4')).to be true
|
|
17
|
+
expect(media.playable?('007 SKYFALL.ts')).to be true
|
|
18
|
+
expect(media.playable?('007 SKYFALL.m4v')).to be true
|
|
19
|
+
expect(media.playable?('007 SKYFALL.mov')).to be true
|
|
20
|
+
expect(media.playable?('007 SKYFALL.ts')).to be true
|
|
21
|
+
expect(media.playable?('マルチ☆バイト.mp4')).to be true
|
|
22
|
+
end
|
|
24
23
|
end
|
|
25
|
-
end
|
|
26
24
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
25
|
+
context 'with unsupported mime types' do
|
|
26
|
+
it 'returns false' do
|
|
27
|
+
expect(media.playable?('007 SKYFALL.flv')).to be false
|
|
28
|
+
expect(media.playable?('007 SKYFALL.wmv')).to be false
|
|
29
|
+
expect(media.playable?('NOT_PLAYABLE_FILE')).to be false
|
|
30
|
+
end
|
|
31
31
|
end
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
describe '.file?' do
|
|
35
|
+
context 'with given local file' do
|
|
36
|
+
it 'returns true' do
|
|
37
|
+
FileUtils.touch('fake_movie.m4v')
|
|
38
|
+
expect(media.new('fake_movie.m4v').file?).to be true
|
|
39
|
+
end
|
|
38
40
|
end
|
|
39
41
|
end
|
|
40
42
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
it 'has title and short url' do
|
|
49
|
-
#media = subject.new('http://youtu.be/gVNYm9Qncyc')
|
|
50
|
-
#expect(media.url?).to be_true
|
|
51
|
-
#expect(media.title).to match(/Mogwai/)
|
|
43
|
+
describe '.url?' do
|
|
44
|
+
context 'with given URL' do
|
|
45
|
+
it 'returns true' do
|
|
46
|
+
expect(media.new('http://example.com/video.mp4').url?).to be true
|
|
47
|
+
end
|
|
52
48
|
end
|
|
53
49
|
end
|
|
54
50
|
end
|
|
@@ -1,37 +1,54 @@
|
|
|
1
|
+
require 'fakefs/spec_helpers'
|
|
1
2
|
require 'spec_helper'
|
|
2
3
|
|
|
3
4
|
module AirPlayer
|
|
4
5
|
describe Playlist do
|
|
5
|
-
|
|
6
|
+
let (:playlist) do
|
|
7
|
+
AirPlayer::Playlist.new
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
describe '.add' do
|
|
11
|
+
context 'with local directory' do
|
|
12
|
+
it 'returns media type is local file' do
|
|
13
|
+
FakeFS do
|
|
14
|
+
FileUtils.touch('01.m4v')
|
|
15
|
+
FileUtils.touch('02.m4v')
|
|
16
|
+
end
|
|
6
17
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
expect(subject.first.path).to match 'http'
|
|
18
|
+
playlist.add('.')
|
|
19
|
+
playlist.entries do |media|
|
|
20
|
+
expect(media.file?).to be true
|
|
21
|
+
end
|
|
12
22
|
end
|
|
13
23
|
end
|
|
14
24
|
|
|
15
|
-
context '
|
|
16
|
-
it do
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
expect(media).to be_kind_of AirPlayer::Media
|
|
20
|
-
end
|
|
25
|
+
context 'with URL' do
|
|
26
|
+
it 'returns media type is url' do
|
|
27
|
+
playlist.add('http://example.com/video.mp4')
|
|
28
|
+
expect(playlist.first.path).to match 'http'
|
|
21
29
|
end
|
|
22
30
|
end
|
|
23
31
|
|
|
24
|
-
context 'multiple files' do
|
|
32
|
+
context 'with multiple files' do
|
|
25
33
|
it 'have multiple files' do
|
|
26
|
-
expect(
|
|
27
|
-
expect(
|
|
34
|
+
expect(playlist.add('video.mp4').size).to eq 1
|
|
35
|
+
expect(playlist.add('video.m4v').size).to eq 2
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
context 'with podcast RSS' do
|
|
40
|
+
it 'returns media instances' do
|
|
41
|
+
playlist.add('http://rss.cnn.com/services/podcasting/cnnnewsroom/rss.xml')
|
|
42
|
+
playlist.entries do |media|
|
|
43
|
+
expect(media).to be_kind_of AirPlayer::Media
|
|
44
|
+
end
|
|
28
45
|
end
|
|
29
46
|
end
|
|
30
47
|
|
|
31
|
-
context 'local file' do
|
|
32
|
-
it '
|
|
33
|
-
|
|
34
|
-
|
|
48
|
+
context 'with local file' do
|
|
49
|
+
it 'returns media instances' do
|
|
50
|
+
playlist.add('video.mp4')
|
|
51
|
+
playlist.entries do |media|
|
|
35
52
|
expect(media).to be_kind_of AirPlayer::Media
|
|
36
53
|
end
|
|
37
54
|
end
|
data/spec/spec_helper.rb
CHANGED
|
@@ -1,4 +1,39 @@
|
|
|
1
|
-
require 'airplayer'
|
|
2
|
-
|
|
3
1
|
require 'coveralls'
|
|
4
2
|
Coveralls.wear!
|
|
3
|
+
|
|
4
|
+
require 'stringio'
|
|
5
|
+
RSpec.configure do |c|
|
|
6
|
+
def capture(stream)
|
|
7
|
+
begin
|
|
8
|
+
stream = stream.to_s
|
|
9
|
+
eval "$#{stream} = StringIO.new"
|
|
10
|
+
yield
|
|
11
|
+
result = eval("$#{stream}").string
|
|
12
|
+
ensure
|
|
13
|
+
eval "$#{stream} = #{stream.upcase}"
|
|
14
|
+
end
|
|
15
|
+
result
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
require 'airplay'
|
|
21
|
+
Airplay.configure do |c|
|
|
22
|
+
c.autodiscover = false
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# https://github.com/elcuervo/airplay/blob/master/lib/airplay/device.rb
|
|
26
|
+
# https://github.com/elcuervo/airplay/blob/master/lib/airplay/device/info.rb
|
|
27
|
+
def double_device
|
|
28
|
+
device = Airplay::Device.new(name: 'Double Device', address: 'double.appletv.local:7000')
|
|
29
|
+
allow(device).to receive('ip').and_return('127.0.0.1')
|
|
30
|
+
allow(device).to receive('server_info').and_return({
|
|
31
|
+
'model' => 'AppleTV2,1',
|
|
32
|
+
'os_version' => '11B554a',
|
|
33
|
+
'width' => '1280',
|
|
34
|
+
'height' => '720'
|
|
35
|
+
})
|
|
36
|
+
device
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
require 'airplayer'
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: airplayer
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.9
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tomohiro TAIRA
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2014-01-19 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: thor
|
|
@@ -42,16 +42,16 @@ dependencies:
|
|
|
42
42
|
name: airplay
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
44
44
|
requirements:
|
|
45
|
-
- -
|
|
45
|
+
- - '='
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
|
-
version: 0.2
|
|
47
|
+
version: 1.0.2
|
|
48
48
|
type: :runtime
|
|
49
49
|
prerelease: false
|
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
51
|
requirements:
|
|
52
|
-
- -
|
|
52
|
+
- - '='
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
|
-
version: 0.2
|
|
54
|
+
version: 1.0.2
|
|
55
55
|
- !ruby/object:Gem::Dependency
|
|
56
56
|
name: rack
|
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -150,6 +150,20 @@ dependencies:
|
|
|
150
150
|
- - '>='
|
|
151
151
|
- !ruby/object:Gem::Version
|
|
152
152
|
version: '0'
|
|
153
|
+
- !ruby/object:Gem::Dependency
|
|
154
|
+
name: fakefs
|
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
|
156
|
+
requirements:
|
|
157
|
+
- - '>='
|
|
158
|
+
- !ruby/object:Gem::Version
|
|
159
|
+
version: '0'
|
|
160
|
+
type: :development
|
|
161
|
+
prerelease: false
|
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
163
|
+
requirements:
|
|
164
|
+
- - '>='
|
|
165
|
+
- !ruby/object:Gem::Version
|
|
166
|
+
version: '0'
|
|
153
167
|
- !ruby/object:Gem::Dependency
|
|
154
168
|
name: coveralls
|
|
155
169
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -187,14 +201,12 @@ files:
|
|
|
187
201
|
- lib/airplayer/app.rb
|
|
188
202
|
- lib/airplayer/controller.rb
|
|
189
203
|
- lib/airplayer/device.rb
|
|
190
|
-
- lib/airplayer/logger.rb
|
|
191
204
|
- lib/airplayer/media.rb
|
|
192
205
|
- lib/airplayer/playlist.rb
|
|
193
|
-
- lib/airplayer/progress_bar/base.rb
|
|
194
|
-
- lib/airplayer/server.rb
|
|
195
206
|
- lib/airplayer/version.rb
|
|
196
207
|
- spec/airplayer/app_spec.rb
|
|
197
|
-
- spec/airplayer/
|
|
208
|
+
- spec/airplayer/controller_spec.rb
|
|
209
|
+
- spec/airplayer/device_spec.rb
|
|
198
210
|
- spec/airplayer/media_spec.rb
|
|
199
211
|
- spec/airplayer/playlist_spec.rb
|
|
200
212
|
- spec/spec_helper.rb
|
|
@@ -223,7 +235,8 @@ specification_version: 4
|
|
|
223
235
|
summary: Command-line AirPlay video client for Apple TV
|
|
224
236
|
test_files:
|
|
225
237
|
- spec/airplayer/app_spec.rb
|
|
226
|
-
- spec/airplayer/
|
|
238
|
+
- spec/airplayer/controller_spec.rb
|
|
239
|
+
- spec/airplayer/device_spec.rb
|
|
227
240
|
- spec/airplayer/media_spec.rb
|
|
228
241
|
- spec/airplayer/playlist_spec.rb
|
|
229
242
|
- spec/spec_helper.rb
|
data/lib/airplayer/logger.rb
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
require 'rbconfig'
|
|
2
|
-
|
|
3
|
-
module AirPlayer
|
|
4
|
-
class Logger
|
|
5
|
-
def self.path
|
|
6
|
-
case RbConfig::CONFIG['target_os']
|
|
7
|
-
when /darwin|osx/i
|
|
8
|
-
File.expand_path('~/Library/Logs/airplayer-access.log')
|
|
9
|
-
when /linux|unix/i
|
|
10
|
-
'/tmp/airplayer-access.log'
|
|
11
|
-
when /mswin|windows|cygwin/i
|
|
12
|
-
'NUL'
|
|
13
|
-
else
|
|
14
|
-
STDOUT
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end
|
data/lib/airplayer/server.rb
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
require 'rack'
|
|
2
|
-
require 'socket'
|
|
3
|
-
|
|
4
|
-
module AirPlayer
|
|
5
|
-
class Server
|
|
6
|
-
attr_reader :uri
|
|
7
|
-
|
|
8
|
-
def initialize(video_path)
|
|
9
|
-
@server = Rack::Server.new(server: :webrick, Host: local_ip, Port: 7070, app: Rack::File.new(video_path))
|
|
10
|
-
@uri = "http://#{@server.options[:Host]}:#{@server.options[:Port]}"
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def start
|
|
14
|
-
Thread.start do
|
|
15
|
-
# Output WEBrick access log to file
|
|
16
|
-
$stderr = File.open(Logger.path, File::WRONLY | File::APPEND | File::CREAT)
|
|
17
|
-
@server.start
|
|
18
|
-
$stderr = STDERR
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
def stop
|
|
23
|
-
@server.server.shutdown
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
private
|
|
27
|
-
# networking - Getting the Hostname or IP in Ruby on Rails - Stack Overflow
|
|
28
|
-
# http://stackoverflow.com/questions/42566/getting-the-hostname-or-ip-in-ruby-on-rails
|
|
29
|
-
def local_ip
|
|
30
|
-
# turn off reverse DNS resolution temporarily
|
|
31
|
-
orig, Socket.do_not_reverse_lookup = Socket.do_not_reverse_lookup, true
|
|
32
|
-
|
|
33
|
-
UDPSocket.open do |s|
|
|
34
|
-
s.connect('8.8.8.8', 1)
|
|
35
|
-
s.addr.last
|
|
36
|
-
end
|
|
37
|
-
ensure
|
|
38
|
-
Socket.do_not_reverse_lookup = orig
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
end
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
|
|
3
|
-
module AirPlayer
|
|
4
|
-
describe Logger do
|
|
5
|
-
subject { AirPlayer::Logger }
|
|
6
|
-
|
|
7
|
-
context 'file path' do
|
|
8
|
-
it '/tmp/airplayer-access.log on Linux' do
|
|
9
|
-
if RbConfig::CONFIG['target_os'] =~ /linux|unix/
|
|
10
|
-
expect(subject.path).to eq '/tmp/airplayer-access.log'
|
|
11
|
-
end
|
|
12
|
-
end
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
end
|