airplayer 1.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e9c44f9475e943b7eaccfc3332b176f125dc2c76
4
- data.tar.gz: 5b48cb351a45ed3e439deeb5e57197533dbd03de
3
+ metadata.gz: c2b6af16b4d901fa48c2d07c409c89507be2c652
4
+ data.tar.gz: 37da9c298b6d1142b95353bb06d3cb42c3249f6f
5
5
  SHA512:
6
- metadata.gz: 6c0665b7d5e1a597180d57af7f3824f4995929725e6cf7a1890f3f9576ba286020887e3a5ee0448aa64f33385910b74c924ee78ece10a4a3e354f9f7a518e4c7
7
- data.tar.gz: ba606717a2d040ddd95324fe09c6c4f955defdd04f9274e7d42bffaf89c642604637f550cfce9fad1a441c6b4085dd4cc36e45f0c5f9845296eb80a52a6f5f60
6
+ metadata.gz: 042c297753ce32f4e4231f02c629f67aa33d5c6e579d4d487456f85c8b7bd856802e3eb238a440d1f039468bdddc6d88f6e009560eb437b4ab0a59a7b8bbeb22
7
+ data.tar.gz: 55308fd2bed65b39f41d969745c7470fad3b5eba8d4aee490c84994c21b5ddcd71d668561f30685bc3b0b09d71084d42aabead41c4c555512308e161a357754d
@@ -1,8 +1,18 @@
1
- language: ruby
1
+ sudo: false
2
+ language: objective-c
2
3
  rvm:
3
- - 1.9.3
4
- - 2.1.3
4
+ - 2.2.3
5
+
6
+ cache: bundler
7
+
8
+ os:
9
+ - osx
10
+
5
11
  before_install:
6
- - 'sudo apt-get -qq update'
7
- - 'sudo apt-get -qq install youtube-dl rdnssd libavahi-compat-libdnssd-dev'
12
+ - brew install youtube-dl
13
+
14
+ before_script:
15
+ - which youtube-dl
16
+ - youtube-dl --version
17
+
8
18
  script: bundle exec rake spec
@@ -1,13 +1,14 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- airplayer (1.0.1)
4
+ airplayer (1.1.0)
5
5
  airplay (~> 1.0.2)
6
6
  celluloid (= 0.15.2)
7
7
  celluloid-io (= 0.15.0)
8
8
  cuba (= 3.1.1)
9
9
  http (= 0.5.0)
10
10
  mime-types (~> 2.4.0)
11
+ nio4r (~> 1.1.0)
11
12
  rack (~> 1.5.0)
12
13
  reel (= 0.4.0)
13
14
  reel-rack (= 0.1.0)
@@ -35,34 +36,43 @@ GEM
35
36
  celluloid (>= 0.15.0)
36
37
  nio4r (>= 0.5.0)
37
38
  coderay (1.1.0)
38
- coveralls (0.7.1)
39
- multi_json (~> 1.3)
40
- rest-client
41
- simplecov (>= 0.7)
42
- term-ansicolor
43
- thor
39
+ coveralls (0.8.2)
40
+ json (~> 1.8)
41
+ rest-client (>= 1.6.8, < 2)
42
+ simplecov (~> 0.10.0)
43
+ term-ansicolor (~> 1.3)
44
+ thor (~> 0.19.1)
44
45
  cuba (3.1.1)
45
46
  rack
46
47
  diff-lcs (1.2.5)
47
- dnssd (2.0)
48
+ dnssd (2.0.1)
48
49
  docile (1.1.5)
49
- fakefs (0.6.0)
50
- ffi (1.9.6)
50
+ domain_name (0.5.24)
51
+ unf (>= 0.0.5, < 1.0.0)
52
+ fakefs (0.6.7)
53
+ ffi (1.9.10)
51
54
  formatador (0.2.5)
52
- guard (2.6.1)
55
+ guard (2.12.8)
53
56
  formatador (>= 0.2.4)
54
- listen (~> 2.7)
57
+ listen (>= 2.7, <= 4.0)
55
58
  lumberjack (~> 1.0)
59
+ nenv (~> 0.1)
60
+ notiffany (~> 0.0)
56
61
  pry (>= 0.9.12)
62
+ shellany (~> 0.0)
57
63
  thor (>= 0.18.1)
58
- guard-rspec (4.3.1)
64
+ guard-compat (1.2.1)
65
+ guard-rspec (4.6.0)
59
66
  guard (~> 2.1)
60
- rspec (>= 2.14, < 4.0)
67
+ guard-compat (~> 1.1)
68
+ rspec (>= 2.99.0, < 4.0)
61
69
  http (0.5.0)
62
70
  http_parser.rb
71
+ http-cookie (1.0.2)
72
+ domain_name (~> 0.5)
63
73
  http_parser.rb (0.6.0)
64
- listen (2.7.11)
65
- celluloid (>= 0.15.2)
74
+ json (1.8.3)
75
+ listen (3.0.1)
66
76
  rb-fsevent (>= 0.9.3)
67
77
  rb-inotify (>= 0.9)
68
78
  log4r (1.1.10)
@@ -70,21 +80,24 @@ GEM
70
80
  method_source (0.8.2)
71
81
  micromachine (1.0.4)
72
82
  mime-types (2.4.3)
73
- multi_json (1.10.1)
83
+ nenv (0.2.0)
74
84
  net-http-digest_auth (1.2.1)
75
85
  net-ptth (0.0.17)
76
86
  celluloid-io (>= 0.15.0)
77
87
  http_parser.rb (>= 0.6.0.beta.2)
78
88
  rack (>= 1.4.5)
79
- netrc (0.8.0)
80
- nio4r (1.0.1)
89
+ netrc (0.10.3)
90
+ nio4r (1.1.1)
91
+ notiffany (0.0.6)
92
+ nenv (~> 0.1)
93
+ shellany (~> 0.0)
81
94
  pry (0.10.1)
82
95
  coderay (~> 1.1.0)
83
96
  method_source (~> 0.8.1)
84
97
  slop (~> 3.4)
85
- rack (1.5.2)
86
- rake (10.3.2)
87
- rb-fsevent (0.9.4)
98
+ rack (1.5.5)
99
+ rake (10.4.2)
100
+ rb-fsevent (0.9.5)
88
101
  rb-inotify (0.9.5)
89
102
  ffi (>= 0.5.0)
90
103
  reel (0.4.0)
@@ -96,34 +109,40 @@ GEM
96
109
  reel-rack (0.1.0)
97
110
  rack (>= 1.4.0)
98
111
  reel (>= 0.4.0)
99
- rest-client (1.7.2)
112
+ rest-client (1.8.0)
113
+ http-cookie (>= 1.0.2, < 2.0)
100
114
  mime-types (>= 1.16, < 3.0)
101
115
  netrc (~> 0.7)
102
- rspec (3.1.0)
103
- rspec-core (~> 3.1.0)
104
- rspec-expectations (~> 3.1.0)
105
- rspec-mocks (~> 3.1.0)
106
- rspec-core (3.1.7)
107
- rspec-support (~> 3.1.0)
108
- rspec-expectations (3.1.2)
116
+ rspec (3.3.0)
117
+ rspec-core (~> 3.3.0)
118
+ rspec-expectations (~> 3.3.0)
119
+ rspec-mocks (~> 3.3.0)
120
+ rspec-core (3.3.1)
121
+ rspec-support (~> 3.3.0)
122
+ rspec-expectations (3.3.0)
123
+ diff-lcs (>= 1.2.0, < 2.0)
124
+ rspec-support (~> 3.3.0)
125
+ rspec-mocks (3.3.1)
109
126
  diff-lcs (>= 1.2.0, < 2.0)
110
- rspec-support (~> 3.1.0)
111
- rspec-mocks (3.1.3)
112
- rspec-support (~> 3.1.0)
113
- rspec-support (3.1.2)
114
- ruby-progressbar (1.6.0)
115
- simplecov (0.9.1)
127
+ rspec-support (~> 3.3.0)
128
+ rspec-support (3.3.0)
129
+ ruby-progressbar (1.7.5)
130
+ shellany (0.0.1)
131
+ simplecov (0.10.0)
116
132
  docile (~> 1.1.0)
117
- multi_json (~> 1.0)
118
- simplecov-html (~> 0.8.0)
119
- simplecov-html (0.8.0)
133
+ json (~> 1.8)
134
+ simplecov-html (~> 0.10.0)
135
+ simplecov-html (0.10.0)
120
136
  slop (3.6.0)
121
- term-ansicolor (1.3.0)
137
+ term-ansicolor (1.3.2)
122
138
  tins (~> 1.0)
123
139
  thor (0.19.1)
124
140
  timers (1.1.0)
125
- tins (1.3.3)
126
- websocket_parser (0.1.6)
141
+ tins (1.5.4)
142
+ unf (0.1.4)
143
+ unf_ext
144
+ unf_ext (0.0.7.1)
145
+ websocket_parser (1.0.0)
127
146
 
128
147
  PLATFORMS
129
148
  ruby
@@ -134,5 +153,9 @@ DEPENDENCIES
134
153
  coveralls
135
154
  fakefs
136
155
  guard-rspec
156
+ pry
137
157
  rake
138
158
  rspec
159
+
160
+ BUNDLED WITH
161
+ 1.11.2
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2012 - 2014 Tomohiro TAIRA
1
+ Copyright (c) 2012 - 2016 Tomohiro TAIRA
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -3,27 +3,37 @@ AirPlayer
3
3
 
4
4
  Command-line AirPlay video client for Apple TV
5
5
 
6
- [![Stillmaintained](http://stillmaintained.com/Tomohiro/airplayer.png)](http://stillmaintained.com/Tomohiro/airplayer)
7
- [![Gem Version](https://badge.fury.io/rb/airplayer.png)](http://badge.fury.io/rb/airplayer)
8
- [![Dependency Status](https://gemnasium.com/Tomohiro/airplayer.png)](https://gemnasium.com/Tomohiro/airplayer)
9
- [![Build Status](https://travis-ci.org/Tomohiro/airplayer.png?branch=master)](https://travis-ci.org/Tomohiro/airplayer)
10
- [![Coverage Status](https://coveralls.io/repos/Tomohiro/airplayer/badge.png?branch=master)](https://coveralls.io/r/Tomohiro/airplayer)
11
- [![Code Climate](https://codeclimate.com/github/Tomohiro/airplayer.png)](https://codeclimate.com/github/Tomohiro/airplayer)
12
-
13
-
14
- ---
6
+ [![Gem Version](https://img.shields.io/gem/v/airplayer.svg?style=flat-square)](http://badge.fury.io/rb/airplayer)
7
+ [![Dependency Status](https://img.shields.io/gemnasium/Tomohiro/airplayer.svg?style=flat-square)](https://gemnasium.com/Tomohiro/airplayer)
8
+ [![Build Status](https://img.shields.io/travis/Tomohiro/airplayer.svg?style=flat-square)](https://travis-ci.org/Tomohiro/airplayer)
9
+ [![Coverage Status](https://img.shields.io/coveralls/Tomohiro/airplayer.svg?style=flat-square)](https://coveralls.io/r/Tomohiro/airplayer)
10
+ [![Code Climate](https://img.shields.io/codeclimate/github/Tomohiro/airplayer.svg?style=flat-square)](https://codeclimate.com/github/Tomohiro/airplayer)
15
11
 
16
12
 
17
13
  Requirements
18
14
  -------------------------------------------------------------------------------
19
15
 
20
- - OS X or Ubuntu
21
- - Ruby 1.9.3, 2.1.3 or later
16
+ - OS X, Ubuntu, Arch Linux
17
+ - Ruby 2.2 or later
18
+ - Bundler 1.10.0 or later
22
19
  - AppleTV 2G or later
23
20
  - [youtube-dl](http://rg3.github.com/youtube-dl/) (If you want to watch YouTube)
24
21
 
25
22
 
26
- ### Ubuntu
23
+ ### For Arch Linux
24
+
25
+ [nss-mdns](https://www.archlinux.org/packages/extra/x86_64/nss-mdns/) package is required.
26
+
27
+ ```sh
28
+ $ sudo pacman -S nss-mdns
29
+ ```
30
+ or
31
+
32
+ ```sh
33
+ $ yaourt -S nss-mdns
34
+ ```
35
+
36
+ ### For Ubuntu
27
37
 
28
38
  ```sh
29
39
  $ sudo apt-get install rdnssd libavahi-compat-libdnssd-dev
@@ -156,6 +166,16 @@ $ airplayer play --device 1 '~/Movies/GHOST IN THE SHELL.mp4'
156
166
  ```
157
167
 
158
168
 
169
+ Advanced Usage
170
+ --------------------------------------------------------------------------------
171
+
172
+ ### Register to OS X Service
173
+
174
+ You can create Automator Service, that opens URL from your browser in airplayer.
175
+
176
+ ![automator service](https://cloud.githubusercontent.com/assets/154571/6997755/aa2599e8-dbc8-11e4-8cc4-9671d9cd8ad7.png)
177
+
178
+
159
179
  Supported MIME types
160
180
  --------------------------------------------------------------------------------
161
181
 
@@ -172,6 +192,6 @@ File extension | MIME type | Ruby `mime-types`
172
192
  LICENSE
173
193
  --------------------------------------------------------------------------------
174
194
 
175
- &copy; 2012 - 2014 Tomohiro TAIRA.
176
- This project is licensed under the MIT license.
177
- See LICENSE for details.
195
+ &copy; 2012 - 2016 Tomohiro TAIRA.
196
+
197
+ This project is licensed under the MIT license. See [LICENSE](LICENSE) for details.
@@ -8,15 +8,20 @@ Gem::Specification.new do |spec|
8
8
  spec.version = AirPlayer::VERSION
9
9
  spec.authors = ['Tomohiro TAIRA']
10
10
  spec.email = ['tomohiro.t@gmail.com']
11
- spec.description = 'Command-line AirPlay video client for Apple TV'
11
+
12
12
  spec.summary = 'Command-line AirPlay video client for Apple TV'
13
+ spec.description = 'Command-line AirPlay video client for Apple TV'
13
14
  spec.homepage = 'https://github.com/Tomohiro/airplayer'
15
+ spec.license = 'MIT'
14
16
 
15
- spec.files = `git ls-files`.split($/)
16
- spec.executables = spec.files.grep(%r{^bin/}).map { |f| File.basename(f) }
17
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^spec/}) }
18
+ spec.bindir = 'exe'
19
+ spec.executables = spec.files.grep(%r{^exe/}).map { |f| File.basename(f) }
18
20
  spec.require_paths = ['lib']
19
21
 
22
+ # This gem will work with 2.2.0 or greater...
23
+ spec.required_ruby_version = '>= 2.2.0'
24
+
20
25
  spec.add_runtime_dependency 'thor'
21
26
  spec.add_runtime_dependency 'ruby-progressbar'
22
27
  spec.add_runtime_dependency 'mime-types', '~> 2.4.0'
@@ -24,6 +29,7 @@ Gem::Specification.new do |spec|
24
29
  spec.add_runtime_dependency 'airplay', '~> 1.0.2'
25
30
  spec.add_runtime_dependency 'rack', '~> 1.5.0'
26
31
  spec.add_runtime_dependency 'http', '= 0.5.0'
32
+ spec.add_runtime_dependency 'nio4r', '~> 1.1.0'
27
33
  spec.add_runtime_dependency 'reel', '= 0.4.0'
28
34
  spec.add_runtime_dependency 'reel-rack', '= 0.1.0'
29
35
  spec.add_runtime_dependency 'celluloid', '= 0.15.2'
@@ -36,4 +42,5 @@ Gem::Specification.new do |spec|
36
42
  spec.add_development_dependency 'guard-rspec'
37
43
  spec.add_development_dependency 'fakefs'
38
44
  spec.add_development_dependency 'coveralls'
45
+ spec.add_development_dependency 'pry'
39
46
  end
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'airplayer'
5
+
6
+ require 'pry'
7
+ Pry.start
@@ -0,0 +1,5 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
File without changes
@@ -3,9 +3,11 @@ Airplay.configuration.load
3
3
 
4
4
  module AirPlayer
5
5
  require 'airplayer/version'
6
- require 'airplayer/app'
7
6
  require 'airplayer/controller'
8
7
  require 'airplayer/device'
9
8
  require 'airplayer/playlist'
10
9
  require 'airplayer/media'
10
+ require 'airplayer/youtube_dl'
11
+
12
+ require 'airplayer/app'
11
13
  end
@@ -2,16 +2,21 @@ require 'thor'
2
2
 
3
3
  module AirPlayer
4
4
  class App < Thor
5
+ class_option :youtube_dl, desc: 'path to youtube-dl', default: YoutubeDl.default_path
6
+
5
7
  desc 'play <URI|PATH> [-r|--repeat] [-s|--shuffle] [-d=|--device=]', 'Play video(URI[Podcast URI, YouTube] or Path[local video file, directory])'
6
8
  method_option :repeat, aliases: '-r', desc: 'Repeat play', type: :boolean
7
9
  method_option :shuffle, aliases: '-s', desc: 'Shuffle play', type: :boolean
8
10
  method_option :device, aliases: '-d', desc: 'Device number', type: :numeric
9
11
  def play(target)
12
+ YoutubeDl.path = options[:youtube_dl]
10
13
  controller = Controller.new(device: options.fetch('device', 0))
14
+
11
15
  Playlist.new(options).add(target).entries do |media|
12
16
  controller.play(media)
13
17
  controller.pause
14
18
  end
19
+ rescue Interrupt # capture Ctrl-C
15
20
  end
16
21
 
17
22
  desc 'devices', 'Show AirPlay devices'
@@ -19,11 +19,6 @@ module AirPlayer
19
19
  video/mpeg4
20
20
  )
21
21
 
22
- SUPPORTED_DOMAINS = %w(
23
- youtube
24
- youtu.be
25
- )
26
-
27
22
  class Media
28
23
  attr_reader :title, :path, :type
29
24
 
@@ -35,26 +30,38 @@ module AirPlayer
35
30
  @title = File.basename(path)
36
31
  @type = :file
37
32
  else
38
- uri = URI.encode(target)
39
- @path = online_media_path(uri)
40
- @title = online_media_title(uri)
33
+ @path = YoutubeDl.get_url(target)
34
+ @title = YoutubeDl.get_title(target)
41
35
  @type = :url
42
36
  end
43
37
  end
44
38
 
45
- def self.playable?(path)
46
- MIME::Types.of(path).map(&:simplified).each do |mimetype|
47
- return SUPPORTED_MIME_TYPES.include?(mimetype)
39
+ class << self
40
+ def playable?(path)
41
+ if is_url?(path)
42
+ YoutubeDl.supports?(path) || supported_mime_type?(YoutubeDl.filename(path))
43
+ else
44
+ supported_mime_type?(path)
45
+ end
48
46
  end
49
47
 
50
- host = URI.parse(URI.escape(path)).host
51
- SUPPORTED_DOMAINS.each do |domain|
52
- return true if host =~ /#{domain}/
48
+ def is_url?(path)
49
+ uri = URI(path)
50
+ uri.scheme && uri.absolute?
51
+ rescue URI::InvalidURIError
52
+ false
53
53
  end
54
54
 
55
- false
55
+ def supported_mime_type?(path)
56
+ MIME::Types.of(path).map(&:simplified).each do |mimetype|
57
+ return SUPPORTED_MIME_TYPES.include?(mimetype)
58
+ end
59
+
60
+ false
61
+ end
56
62
  end
57
63
 
64
+
58
65
  def file?
59
66
  @type == :file
60
67
  end
@@ -62,24 +69,5 @@ module AirPlayer
62
69
  def url?
63
70
  @type == :url
64
71
  end
65
-
66
- private
67
- def online_media_path(uri)
68
- case URI.parse(uri).host
69
- when /youtube|youtu\.be/
70
- uri = `youtube-dl -g #{uri}`
71
- else
72
- uri
73
- end
74
- end
75
-
76
- def online_media_title(uri)
77
- case URI.parse(uri).host
78
- when /youtube|youtu\.be/
79
- title = `youtube-dl -e #{uri}`
80
- else
81
- title = File.basename(uri)
82
- end
83
- end
84
72
  end
85
73
  end
@@ -6,7 +6,7 @@ module AirPlayer
6
6
  class Playlist < Array
7
7
  def initialize(options = {})
8
8
  @shuffle = options['shuffle'] || false
9
- @repeat = options['repeat'] || false
9
+ @repeat = options['repeat'] || false
10
10
  end
11
11
 
12
12
  def add(item)
@@ -18,6 +18,7 @@ module AirPlayer
18
18
  when :url
19
19
  push(Media.new(item))
20
20
  end
21
+
21
22
  self
22
23
  end
23
24
 
@@ -30,26 +31,28 @@ module AirPlayer
30
31
  end
31
32
 
32
33
  private
33
- def type(item)
34
- if Dir.exists?(File.expand_path(item))
35
- :local_dir
36
- elsif Media.playable? item
37
- :url
38
- elsif item.match(/.+(xml|rss)$/)
39
- :podcast
40
- end
41
- end
42
34
 
43
- def media_in_local(path)
44
- Dir.entries(File.expand_path(path)).sort.map do |node|
45
- Media.new(File.expand_path(node, path)) if Media.playable? node
46
- end.compact
35
+ def type(item)
36
+ if Dir.exist?(File.expand_path(item))
37
+ :local_dir
38
+ elsif Media.playable?(item)
39
+ :url
40
+ elsif item.match(/.+(xml|rss)$/)
41
+ :podcast
47
42
  end
43
+ end
48
44
 
49
- def media_in_podcast(path)
50
- RSS::Parser.parse(path).items.map do |node|
51
- Media.new(node.link)
52
- end
45
+ def media_in_local(path)
46
+ Dir.entries(File.expand_path(path)).sort.map do |node|
47
+ Media.new(File.expand_path(node, path)) if Media.playable? node
48
+ end.compact
49
+ end
50
+
51
+ def media_in_podcast(path)
52
+ strict_parse = false
53
+ RSS::Parser.parse(path, strict_parse).items.map do |node|
54
+ Media.new(node.link)
53
55
  end
56
+ end
54
57
  end
55
58
  end
@@ -1,3 +1,3 @@
1
1
  module AirPlayer
2
- VERSION = '1.0.1'
2
+ VERSION = '1.1.0'
3
3
  end
@@ -0,0 +1,100 @@
1
+ require 'shellwords'
2
+
3
+ module AirPlayer
4
+ class YoutubeDl
5
+
6
+ attr_reader :path
7
+
8
+ def initialize(path = self.class.path || self.class.default_path)
9
+ @path = path
10
+
11
+ if @path
12
+ File.exist?(@path) or raise "youtube-dl could not be found at #{@path}"
13
+ end
14
+
15
+ @output = '2> /dev/null'.freeze
16
+ end
17
+
18
+ def enabled?
19
+ @path && ! @path.empty?
20
+ end
21
+
22
+ EXTRACT_EXTRACTOR_AND_URL = %r{
23
+ (?<extractor>.+)\n # extractor name and new line
24
+ \s+(:?.+) # the url if the extractor supports it
25
+ }x
26
+
27
+ GENERIC_EXTRACTOR = 'generic'.freeze
28
+
29
+ def supports?(url)
30
+ extractors = list_extractors(url).scan(EXTRACT_EXTRACTOR_AND_URL).flatten
31
+ extractors.delete(GENERIC_EXTRACTOR)
32
+ ! extractors.empty?
33
+ end
34
+
35
+ def list_extractors(*urls)
36
+ execute('--list-extractors', *urls)
37
+ end
38
+
39
+ def get_url(url)
40
+ execute('--get-url', url)
41
+ end
42
+
43
+ def get_filename(url)
44
+ execute('--get-filename', url)
45
+ end
46
+
47
+ def get_title(url)
48
+ execute('--get-title', url)
49
+ end
50
+
51
+ def execute(*args)
52
+ return '' unless enabled?
53
+ escape = Shellwords.method(:escape)
54
+ parts = [ path, args.flat_map(&escape), @output ]
55
+ %x`#{parts.flatten.join(' ')}`.strip
56
+ end
57
+
58
+ class << self
59
+ attr_accessor :path
60
+
61
+ def enabled?
62
+ path && ! path.empty?
63
+ end
64
+
65
+ def default_path
66
+ @default_path ||= `which youtube-dl 2> /dev/null`.strip
67
+ end
68
+
69
+ def get_url(uri)
70
+ if enabled?
71
+ new.get_url(uri)
72
+ else
73
+ uri
74
+ end
75
+ end
76
+
77
+ def supports?(path)
78
+ if enabled?
79
+ new.supports?(path)
80
+ end
81
+ end
82
+
83
+ def filename(url)
84
+ if enabled?
85
+ new.get_filename(url)
86
+ else
87
+ File.basename(url)
88
+ end
89
+ end
90
+
91
+ def get_title(uri)
92
+ if enabled?
93
+ new.get_title(uri)
94
+ else
95
+ File.basename(uri)
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
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: 1.0.1
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tomohiro TAIRA
8
8
  autorequire:
9
- bindir: bin
9
+ bindir: exe
10
10
  cert_chain: []
11
- date: 2014-10-27 00:00:00.000000000 Z
11
+ date: 2016-01-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -94,6 +94,20 @@ dependencies:
94
94
  - - '='
95
95
  - !ruby/object:Gem::Version
96
96
  version: 0.5.0
97
+ - !ruby/object:Gem::Dependency
98
+ name: nio4r
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 1.1.0
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 1.1.0
97
111
  - !ruby/object:Gem::Dependency
98
112
  name: reel
99
113
  requirement: !ruby/object:Gem::Requirement
@@ -248,6 +262,20 @@ dependencies:
248
262
  - - ">="
249
263
  - !ruby/object:Gem::Version
250
264
  version: '0'
265
+ - !ruby/object:Gem::Dependency
266
+ name: pry
267
+ requirement: !ruby/object:Gem::Requirement
268
+ requirements:
269
+ - - ">="
270
+ - !ruby/object:Gem::Version
271
+ version: '0'
272
+ type: :development
273
+ prerelease: false
274
+ version_requirements: !ruby/object:Gem::Requirement
275
+ requirements:
276
+ - - ">="
277
+ - !ruby/object:Gem::Version
278
+ version: '0'
251
279
  description: Command-line AirPlay video client for Apple TV
252
280
  email:
253
281
  - tomohiro.t@gmail.com
@@ -267,7 +295,9 @@ files:
267
295
  - README.md
268
296
  - Rakefile
269
297
  - airplayer.gemspec
270
- - bin/airplayer
298
+ - bin/console
299
+ - bin/setup
300
+ - exe/airplayer
271
301
  - lib/airplayer.rb
272
302
  - lib/airplayer/app.rb
273
303
  - lib/airplayer/controller.rb
@@ -275,14 +305,10 @@ files:
275
305
  - lib/airplayer/media.rb
276
306
  - lib/airplayer/playlist.rb
277
307
  - lib/airplayer/version.rb
278
- - spec/airplayer/app_spec.rb
279
- - spec/airplayer/controller_spec.rb
280
- - spec/airplayer/device_spec.rb
281
- - spec/airplayer/media_spec.rb
282
- - spec/airplayer/playlist_spec.rb
283
- - spec/spec_helper.rb
308
+ - lib/airplayer/youtube_dl.rb
284
309
  homepage: https://github.com/Tomohiro/airplayer
285
- licenses: []
310
+ licenses:
311
+ - MIT
286
312
  metadata: {}
287
313
  post_install_message:
288
314
  rdoc_options: []
@@ -292,7 +318,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
292
318
  requirements:
293
319
  - - ">="
294
320
  - !ruby/object:Gem::Version
295
- version: '0'
321
+ version: 2.2.0
296
322
  required_rubygems_version: !ruby/object:Gem::Requirement
297
323
  requirements:
298
324
  - - ">="
@@ -300,14 +326,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
300
326
  version: '0'
301
327
  requirements: []
302
328
  rubyforge_project:
303
- rubygems_version: 2.2.2
329
+ rubygems_version: 2.5.1
304
330
  signing_key:
305
331
  specification_version: 4
306
332
  summary: Command-line AirPlay video client for Apple TV
307
- test_files:
308
- - spec/airplayer/app_spec.rb
309
- - spec/airplayer/controller_spec.rb
310
- - spec/airplayer/device_spec.rb
311
- - spec/airplayer/media_spec.rb
312
- - spec/airplayer/playlist_spec.rb
313
- - spec/spec_helper.rb
333
+ test_files: []
@@ -1,33 +0,0 @@
1
- require 'spec_helper'
2
-
3
- module AirPlayer
4
- describe App do
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
30
- end
31
- end
32
- end
33
- end
@@ -1,35 +0,0 @@
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
@@ -1,56 +0,0 @@
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,51 +0,0 @@
1
- # encoding: UTF-8
2
- require 'fakefs/spec_helpers'
3
- require 'spec_helper'
4
-
5
- module AirPlayer
6
- describe Media do
7
- include FakeFS::SpecHelpers
8
-
9
- let (:media) do
10
- AirPlayer::Media
11
- end
12
-
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
23
- end
24
-
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
- end
32
- end
33
-
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
40
- end
41
- end
42
-
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
48
- end
49
- end
50
- end
51
- end
@@ -1,58 +0,0 @@
1
- require 'fakefs/spec_helpers'
2
- require 'spec_helper'
3
-
4
- module AirPlayer
5
- describe Playlist do
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
17
-
18
- playlist.add('.')
19
- playlist.entries do |media|
20
- expect(media.file?).to be true
21
- end
22
- end
23
- end
24
-
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'
29
- end
30
- end
31
-
32
- context 'with multiple files' do
33
- it 'have multiple files' do
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
45
- end
46
- end
47
-
48
- context 'with local file' do
49
- it 'returns media instances' do
50
- playlist.add('video.mp4')
51
- playlist.entries do |media|
52
- expect(media).to be_kind_of AirPlayer::Media
53
- end
54
- end
55
- end
56
- end
57
- end
58
- end
@@ -1,39 +0,0 @@
1
- require 'coveralls'
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'