airplayer 1.0.1 → 1.1.0

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 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'