plex-ruby 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +4 -0
- data/LICENSE +7 -0
- data/README.md +59 -0
- data/Rakefile +2 -0
- data/lib/plex-ruby.rb +39 -0
- data/lib/plex-ruby/client.rb +79 -0
- data/lib/plex-ruby/episode.rb +29 -0
- data/lib/plex-ruby/libary.rb +25 -0
- data/lib/plex-ruby/media.rb +23 -0
- data/lib/plex-ruby/movie.rb +29 -0
- data/lib/plex-ruby/null.rb +13 -0
- data/lib/plex-ruby/parser.rb +62 -0
- data/lib/plex-ruby/part.rb +17 -0
- data/lib/plex-ruby/season.rb +38 -0
- data/lib/plex-ruby/section.rb +36 -0
- data/lib/plex-ruby/server.rb +30 -0
- data/lib/plex-ruby/show.rb +42 -0
- data/lib/plex-ruby/stream.rb +16 -0
- data/lib/plex-ruby/tags.rb +30 -0
- data/lib/plex-ruby/version.rb +3 -0
- data/lib/plex-ruby/video.rb +36 -0
- data/plex-ruby.gemspec +25 -0
- data/test/test_helper.rb +0 -0
- metadata +113 -0
data/.gitignore
ADDED
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
Copyright (c) 2011 Eric Koslow
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
4
|
+
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
6
|
+
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
# Plex-Ruby
|
2
|
+
|
3
|
+
A handy gem for working with Plex within Ruby. Tries to emulate and document
|
4
|
+
all of the Plex APIs using simple ruby code. I will try and keep it as
|
5
|
+
up-to-date as possible, but pull requests are always welcomed.
|
6
|
+
|
7
|
+
|
8
|
+
## Installation
|
9
|
+
|
10
|
+
Add to your `Gemfile` and run the `bundle` command
|
11
|
+
|
12
|
+
```ruby
|
13
|
+
gem 'plex-ruby'
|
14
|
+
```
|
15
|
+
|
16
|
+
I developed this using Ruby 1.9.2 so no guaranties that it will work with
|
17
|
+
lesser versions of Ruby.
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
Everything Stems from the Plex MediaServer. Create a server with the host and
|
22
|
+
port number.
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
server = Plex::Server.new(CONFIG[:host], CONFIG[:port])
|
26
|
+
```
|
27
|
+
|
28
|
+
From here we can start doing cool things. Lets pause whats currently playing.
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
clients = server.clients
|
32
|
+
client = # pick the media player you want
|
33
|
+
client.pause # That was easy
|
34
|
+
````
|
35
|
+
|
36
|
+
Lets search the libary.
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
sections = server.library.sections
|
40
|
+
section = # Pick the section you want I.E. TV, Movies, Home Videos
|
41
|
+
shows = section.all # Returns a list of shows/movies
|
42
|
+
bsg = shows.select { |s| s.title =~ /Battlestar/ }.first # Pick a great show
|
43
|
+
bsg.seasons # array of its seasons
|
44
|
+
episodes = bsg.seasons.last.episodes # Array the last seasons episodes
|
45
|
+
puts "#{episodes.first.title} - #{episodes.first.summary}" # Looks good
|
46
|
+
client.play_media(episodes.first.key) # Play it!
|
47
|
+
```
|
48
|
+
|
49
|
+
For a full list of commands check out the documentation.
|
50
|
+
|
51
|
+
## Development
|
52
|
+
|
53
|
+
All development of this gem takes place on its GitHub page. There you can
|
54
|
+
create issues or submit pull requests.
|
55
|
+
|
56
|
+
When submiting a pull request please write tests for your changes as well as
|
57
|
+
use feature branches. Thank you!
|
58
|
+
|
59
|
+
This gem was created by Eric Koslow and is under the MIT Licence.
|
data/Rakefile
ADDED
data/lib/plex-ruby.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
require 'open-uri'
|
3
|
+
require 'cgi'
|
4
|
+
|
5
|
+
module Plex
|
6
|
+
|
7
|
+
def self.snake_case(string)
|
8
|
+
string.gsub(/::/, '/').
|
9
|
+
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
10
|
+
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
11
|
+
tr("-", "_").
|
12
|
+
downcase
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.url
|
16
|
+
@@base_url
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.url=(val)
|
20
|
+
@@base_url = val
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
require 'plex-ruby/parser'
|
26
|
+
require 'plex-ruby/server'
|
27
|
+
require 'plex-ruby/client'
|
28
|
+
require 'plex-ruby/libary'
|
29
|
+
require 'plex-ruby/section'
|
30
|
+
require 'plex-ruby/video'
|
31
|
+
require 'plex-ruby/media'
|
32
|
+
require 'plex-ruby/part'
|
33
|
+
require 'plex-ruby/stream'
|
34
|
+
require 'plex-ruby/tags'
|
35
|
+
require 'plex-ruby/show'
|
36
|
+
require 'plex-ruby/season'
|
37
|
+
require 'plex-ruby/episode'
|
38
|
+
require 'plex-ruby/movie'
|
39
|
+
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module Plex
|
2
|
+
class Client
|
3
|
+
|
4
|
+
attr_reader :name, :host, :address, :port, :machine_identifier, :version
|
5
|
+
|
6
|
+
def initialize(node)
|
7
|
+
@name = node.attr('name')
|
8
|
+
@host = node.attr('host')
|
9
|
+
@address = node.attr('address')
|
10
|
+
@port = node.attr('port')
|
11
|
+
@machine_identifier = node.attr('machineIdentifier')
|
12
|
+
@version = node.attr('version')
|
13
|
+
end
|
14
|
+
|
15
|
+
%w(moveUp moveDown moveLeft moveRight pageUp pageDown nextLetter previousLetter
|
16
|
+
select back contextMenu toggleOSD).each { |nav|
|
17
|
+
class_eval %(
|
18
|
+
def #{Plex.snake_case(nav)}
|
19
|
+
ping player_url+'/navigation/#{nav}'
|
20
|
+
end
|
21
|
+
)
|
22
|
+
}
|
23
|
+
|
24
|
+
%w(play pause stop rewind fastForward stepForward bigStepForward stepBack
|
25
|
+
bigStepBack skipNext skipPrevious).each { |playback|
|
26
|
+
class_eval %(
|
27
|
+
def #{Plex.snake_case(playback)}
|
28
|
+
ping player_url+'/playback/#{playback}'
|
29
|
+
end
|
30
|
+
)
|
31
|
+
}
|
32
|
+
|
33
|
+
def play_file
|
34
|
+
ping player_url+"/application/playFile"
|
35
|
+
end
|
36
|
+
|
37
|
+
def play_media(key, user_agent = nil, http_cookies = nil, view_offset = nil)
|
38
|
+
url = player_url+'/application/playMedia?'
|
39
|
+
url += "path=#{CGI::escape(Plex.url+key)}"
|
40
|
+
url += "&key=#{CGI::escape(key)}"
|
41
|
+
url += "&userAgent=#{user_agent}" if user_agent
|
42
|
+
url += "&httpCookies=#{http_cookies}" if http_cookies
|
43
|
+
url += "&viewOffset=#{view_offset}" if view_offset
|
44
|
+
|
45
|
+
ping url
|
46
|
+
end
|
47
|
+
|
48
|
+
def screenshot(width, height, quality)
|
49
|
+
url = player_url+'/application/screenshot?'
|
50
|
+
url += "width=#{width}"
|
51
|
+
url += "&height=#{height}"
|
52
|
+
end
|
53
|
+
|
54
|
+
def send_string(text)
|
55
|
+
ping player_url+"/application/sendString?text=#{CGI::escape(text)}"
|
56
|
+
end
|
57
|
+
|
58
|
+
def send_key(code)
|
59
|
+
ping player_url+"/application/sendKey?code=#{CGI::escape(code)}"
|
60
|
+
end
|
61
|
+
|
62
|
+
def send_virtual_key(code)
|
63
|
+
ping player_url+"/application/sendVirtualKey?code=#{CGI::escape(code)}"
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def player_url
|
69
|
+
Plex.url+"/system/players/#{name}"
|
70
|
+
end
|
71
|
+
|
72
|
+
def ping(url)
|
73
|
+
!!open(url).read
|
74
|
+
rescue => e
|
75
|
+
puts "Error trying to ping #{url} - #{e.message}"
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Plex
|
2
|
+
class Episode
|
3
|
+
|
4
|
+
attr_reader :key
|
5
|
+
|
6
|
+
def initialize(key)
|
7
|
+
@key = key
|
8
|
+
end
|
9
|
+
|
10
|
+
def method_missing(method, *args, &block)
|
11
|
+
if video.respond_to? method
|
12
|
+
video.send(method, *args, &block)
|
13
|
+
else
|
14
|
+
super
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def xml_doc
|
21
|
+
@xml_doc ||= Nokogiri::XML( open(Plex.url+key) )
|
22
|
+
end
|
23
|
+
|
24
|
+
def video
|
25
|
+
@video ||= Plex::Video.new(xml_doc.search('Video').first)
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Plex
|
2
|
+
class Libary
|
3
|
+
|
4
|
+
def section(id)
|
5
|
+
xml_doc.search("Directory[@key='#{id}']").map do |m|
|
6
|
+
Plex::Section.new(m.attributes)
|
7
|
+
end.first
|
8
|
+
end
|
9
|
+
|
10
|
+
def sections
|
11
|
+
xml_doc.search('Directory').map { |m| Plex::Section.new(m.attributes) }
|
12
|
+
end
|
13
|
+
|
14
|
+
def key
|
15
|
+
"/library/sections"
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def xml_doc
|
21
|
+
@xml_doc ||= Nokogiri::XML( open(Plex.url+key) )
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Plex
|
2
|
+
class Media
|
3
|
+
attr_reader :id, :durration, :bitrate, :aspect_ratio, :audio_channels,
|
4
|
+
:audio_codec, :video_codec, :video_resolution, :container, :video_frame_rate,
|
5
|
+
:parts
|
6
|
+
|
7
|
+
def initialize(node)
|
8
|
+
@id = node.attr('id')
|
9
|
+
@durration = node.attr('durration')
|
10
|
+
@bitrate = node.attr('bitrate')
|
11
|
+
@aspect_ratio = node.attr('aspectRatio')
|
12
|
+
@audio_channels = node.attr('audioChannels')
|
13
|
+
@audio_codec = node.attr('audioCodec')
|
14
|
+
@video_codec = node.attr('videoCodec')
|
15
|
+
@video_resolution = node.attr('videoResolution')
|
16
|
+
@container = node.attr('container')
|
17
|
+
@video_frame_rate = node.attr('videoFrameRate')
|
18
|
+
|
19
|
+
@parts = node.search("Part").map { |m| Plex::Part.new(m) }
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Plex
|
2
|
+
class Movie
|
3
|
+
|
4
|
+
attr_reader :key
|
5
|
+
|
6
|
+
def initialize(key)
|
7
|
+
@key = key
|
8
|
+
end
|
9
|
+
|
10
|
+
def method_missing(method, *args, &block)
|
11
|
+
if video.respond_to? method
|
12
|
+
video.send(method, *args, &block)
|
13
|
+
else
|
14
|
+
super
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def xml_doc
|
21
|
+
@xml_doc ||= Nokogiri::XML( open(Plex.url+key) )
|
22
|
+
end
|
23
|
+
|
24
|
+
def video
|
25
|
+
@video ||= Plex::Video.new(xml_doc.search('Video').first)
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class Null
|
2
|
+
|
3
|
+
def self.to_s; "" end
|
4
|
+
def self.to_i; 0 end
|
5
|
+
def self.to_a; [] end
|
6
|
+
def self.to_f; 0.0 end
|
7
|
+
def self.!@; true end
|
8
|
+
def self.nil?; true end
|
9
|
+
def self.present?; false end
|
10
|
+
def self.blank?; true end
|
11
|
+
def self.empty?; true end
|
12
|
+
|
13
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Plex
|
2
|
+
class Parser
|
3
|
+
|
4
|
+
attr_reader :node
|
5
|
+
|
6
|
+
def initialize(node)
|
7
|
+
@node = node
|
8
|
+
end
|
9
|
+
|
10
|
+
def parse
|
11
|
+
case node.name
|
12
|
+
when 'document'
|
13
|
+
Plex::Parser.new(node.root).parse
|
14
|
+
when 'MediaContainer'
|
15
|
+
parse_media_container
|
16
|
+
when 'Video'
|
17
|
+
parse_video
|
18
|
+
when 'Directory'
|
19
|
+
parse_directory
|
20
|
+
when 'text'
|
21
|
+
nil
|
22
|
+
else
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def parse_media_container
|
29
|
+
return nil if node.attr('size').to_i == 0
|
30
|
+
node.children.map {|m| Plex::Parser.new(m).parse }.compact
|
31
|
+
end
|
32
|
+
|
33
|
+
def parse_video
|
34
|
+
case node.attr('type')
|
35
|
+
when 'movie'
|
36
|
+
parse_movie
|
37
|
+
when 'episode'
|
38
|
+
parse_episode
|
39
|
+
else
|
40
|
+
raise 'Unsupported Video Type!'
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def parse_movie
|
45
|
+
Plex::Movie.new( node.attr('key') )
|
46
|
+
end
|
47
|
+
|
48
|
+
def parse_episode
|
49
|
+
Plex::Episode.new( node.attr('key') )
|
50
|
+
end
|
51
|
+
|
52
|
+
def parse_directory
|
53
|
+
case node.attr('type')
|
54
|
+
when 'show'
|
55
|
+
Plex::Show.new( node.attr('key')[0..-10] ) # Remove /children
|
56
|
+
else
|
57
|
+
raise "Unsupported Directory type #{node.attr('type')}"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Plex
|
2
|
+
class Part
|
3
|
+
|
4
|
+
attr_reader :id, :key, :duration, :file, :size, :streams
|
5
|
+
|
6
|
+
def initialize(node)
|
7
|
+
@id = node.attr('id')
|
8
|
+
@key = node.attr('key')
|
9
|
+
@duration = node.attr('duration')
|
10
|
+
@file = node.attr('file')
|
11
|
+
@size = node.attr('size')
|
12
|
+
|
13
|
+
@streams = node.search('Stream').map { |m| Stream.new(m) }
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Plex
|
2
|
+
# Found at /libary/metadata/:key
|
3
|
+
class Season
|
4
|
+
|
5
|
+
attr_reader :key
|
6
|
+
|
7
|
+
def initialize(key)
|
8
|
+
@key = key
|
9
|
+
end
|
10
|
+
|
11
|
+
%w(ratingKey guid type title summary index thumb leafCount viewedLeafCount
|
12
|
+
addedAt updatedAt).each { |method|
|
13
|
+
class_eval %(
|
14
|
+
def #{Plex.snake_case(method)}; directory.attr('#{method}') end
|
15
|
+
)
|
16
|
+
}
|
17
|
+
|
18
|
+
def episodes
|
19
|
+
@episodes ||=
|
20
|
+
children.search("Video").map { |m| Plex::Episode.new(m.attr('key')) }
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def xml_doc
|
26
|
+
@xml_doc ||= Nokogiri::XML( open(Plex.url+key) )
|
27
|
+
end
|
28
|
+
|
29
|
+
def children
|
30
|
+
@children ||= Nokogiri::XML( open(Plex.url+key+'/children') )
|
31
|
+
end
|
32
|
+
|
33
|
+
def directory
|
34
|
+
@directory ||= xml_doc.search("Directory").first
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Plex
|
2
|
+
class Section
|
3
|
+
|
4
|
+
attr_reader :refreshing, :type, :title, :art, :agent, :scanner, :language,
|
5
|
+
:updated_at
|
6
|
+
|
7
|
+
def initialize(options)
|
8
|
+
@refreshing = options['refreshing'].value
|
9
|
+
@key = options['key'].value
|
10
|
+
@type = options['type'].value
|
11
|
+
@title = options['title'].value
|
12
|
+
@art = options['art'].value
|
13
|
+
@agent = options['agent'].value
|
14
|
+
@scanner = options['scanner'].value
|
15
|
+
@language = options['language'].value
|
16
|
+
@updated_at = options['updatedAt'].value
|
17
|
+
end
|
18
|
+
|
19
|
+
def refresh(deep = false, force = false)
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
%w(all unwatched newest recentlyAdded recentlyViewed onDeck).each { |method|
|
24
|
+
class_eval %(
|
25
|
+
def #{Plex.snake_case(method)}
|
26
|
+
Plex::Parser.new( Nokogiri::XML(open(Plex.url+key+'/#{method}')) ).parse
|
27
|
+
end
|
28
|
+
)
|
29
|
+
}
|
30
|
+
|
31
|
+
def key
|
32
|
+
"/library/sections/#{@key}"
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Plex
|
2
|
+
class Server
|
3
|
+
|
4
|
+
attr_reader :host, :port
|
5
|
+
|
6
|
+
def initialize(host, port)
|
7
|
+
@host = host
|
8
|
+
@port = port
|
9
|
+
Plex.url = "http://#{host}:#{port}"
|
10
|
+
end
|
11
|
+
|
12
|
+
def system
|
13
|
+
end
|
14
|
+
|
15
|
+
def libary
|
16
|
+
@libary ||= Plex::Libary.new
|
17
|
+
end
|
18
|
+
|
19
|
+
def clients
|
20
|
+
@clients ||= clients_doc.search('Server').map { |m| Plex::Client.new(m) }
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def clients_doc
|
26
|
+
@clients_doc ||= Nokogiri::XML( open(Plex.url+'/clients') )
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Plex
|
2
|
+
# Found at /libary/metadata/:key
|
3
|
+
class Show
|
4
|
+
|
5
|
+
attr_reader :key
|
6
|
+
|
7
|
+
def initialize(key)
|
8
|
+
@key = key
|
9
|
+
end
|
10
|
+
|
11
|
+
%w(guid studio title contentRating summary index rating year thumb art banner
|
12
|
+
theme duration originallyAvailableAt leafCount viewedLeafCount addedAt
|
13
|
+
updatedAt).each { |method|
|
14
|
+
class_eval %(
|
15
|
+
def #{Plex.snake_case(method)}; @#{method} ||= directory.attr('#{method}') end
|
16
|
+
)
|
17
|
+
}
|
18
|
+
|
19
|
+
def seasons
|
20
|
+
@seasons ||=
|
21
|
+
children.search('Directory').map do |season|
|
22
|
+
Plex::Season.new(season.attr('key')[0..-10]) # Remove /children
|
23
|
+
end.compact
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def children
|
29
|
+
@children ||= Nokogiri::XML( open(Plex.url+key+'/children') )
|
30
|
+
end
|
31
|
+
|
32
|
+
def directory
|
33
|
+
@directory ||= xml_doc.search('Directory').first
|
34
|
+
end
|
35
|
+
|
36
|
+
def xml_doc
|
37
|
+
@xml_doc ||= Nokogiri::XML( open(Plex.url+key) )
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Plex
|
2
|
+
class Stream
|
3
|
+
|
4
|
+
attr_reader :id, :stream_type, :codec, :index, :language, :language_code
|
5
|
+
|
6
|
+
def initialize(node)
|
7
|
+
@id = node.attr('id')
|
8
|
+
@stream_type = node.attr('stream_type')
|
9
|
+
@codec = node.attr('codec')
|
10
|
+
@index = node.attr('index')
|
11
|
+
@language = node.attr('language')
|
12
|
+
@language_code = node.attr('language_code')
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
%w(Genre Writer Director Country).each { |type|
|
2
|
+
eval <<-CLASS
|
3
|
+
module Plex
|
4
|
+
class #{type}
|
5
|
+
|
6
|
+
attr_reader :id, :tag
|
7
|
+
|
8
|
+
def initialize(node)
|
9
|
+
@id = node.attr('id')
|
10
|
+
@tag = node.attr('tag')
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
15
|
+
CLASS
|
16
|
+
}
|
17
|
+
|
18
|
+
module Plex
|
19
|
+
class Role
|
20
|
+
|
21
|
+
attr_reader :id, :tag, :role
|
22
|
+
|
23
|
+
def initialize(node)
|
24
|
+
@id = node.attr('id')
|
25
|
+
@tag = node.attr('tag')
|
26
|
+
@role = node.attr('role')
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Plex
|
2
|
+
class Video
|
3
|
+
|
4
|
+
attr_reader :rating_key, :key, :studio, :type, :title, :title_sort,
|
5
|
+
:content_rating, :summary, :rating, :view_count, :year, :tagline, :thumb, :art,
|
6
|
+
:duration, :originally_available_at, :updated_at, :media, :genres, :writers,
|
7
|
+
:directors, :roles
|
8
|
+
|
9
|
+
def initialize(node)
|
10
|
+
@rating_key = node.attr('ratingKey')
|
11
|
+
@key = node.attr('key')
|
12
|
+
@studio = node.attr('studio')
|
13
|
+
@type = node.attr('type')
|
14
|
+
@title = node.attr('title')
|
15
|
+
@title_sort = node.attr('titleSort')
|
16
|
+
@content_rating = node.attr('contentRating')
|
17
|
+
@summary = node.attr('summary')
|
18
|
+
@rating = node.attr('rating')
|
19
|
+
@viewCount = node.attr('viewCount')
|
20
|
+
@year = node.attr('year')
|
21
|
+
@tagline = node.attr('tagline')
|
22
|
+
@thumb = node.attr('thumb')
|
23
|
+
@art = node.attr('art')
|
24
|
+
@duration = node.attr('duration')
|
25
|
+
@originally_available_at = node.attr('originallyAvailableAt')
|
26
|
+
@updatedAt = node.attr('updatedAt')
|
27
|
+
|
28
|
+
@media = Plex::Media.new(node.search('Media').first)
|
29
|
+
@genres = node.search('Genre').map { |m| Plex::Genre.new(m) }
|
30
|
+
@writers = node.search('Writer').map { |m| Plex::Writer.new(m) }
|
31
|
+
@directors = node.search('Director').map { |m| Plex::Director.new(m) }
|
32
|
+
@roles = node.search('Role').map { |m| Plex::Role.new(m) }
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
data/plex-ruby.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "plex-ruby/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "plex-ruby"
|
7
|
+
s.version = Plex::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Eric Koslow"]
|
10
|
+
s.email = ["ekoslow@gmail.com"]
|
11
|
+
s.homepage = ""
|
12
|
+
s.summary = %q{Plex APIs in easy ruby code}
|
13
|
+
s.description = %q{Extracts the Plex API into easy to write ruby code}
|
14
|
+
|
15
|
+
s.rubyforge_project = "plex-ruby"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
s.add_development_dependency 'minitest'
|
23
|
+
s.add_runtime_dependency 'nokogiri'
|
24
|
+
s.add_runtime_dependency 'open-uri'
|
25
|
+
end
|
data/test/test_helper.rb
ADDED
File without changes
|
metadata
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: plex-ruby
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.1.0
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Eric Koslow
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-12-08 00:00:00 -05:00
|
14
|
+
default_executable:
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: minitest
|
18
|
+
prerelease: false
|
19
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
20
|
+
none: false
|
21
|
+
requirements:
|
22
|
+
- - ">="
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: "0"
|
25
|
+
type: :development
|
26
|
+
version_requirements: *id001
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: nokogiri
|
29
|
+
prerelease: false
|
30
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
31
|
+
none: false
|
32
|
+
requirements:
|
33
|
+
- - ">="
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: "0"
|
36
|
+
type: :runtime
|
37
|
+
version_requirements: *id002
|
38
|
+
- !ruby/object:Gem::Dependency
|
39
|
+
name: open-uri
|
40
|
+
prerelease: false
|
41
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: "0"
|
47
|
+
type: :runtime
|
48
|
+
version_requirements: *id003
|
49
|
+
description: Extracts the Plex API into easy to write ruby code
|
50
|
+
email:
|
51
|
+
- ekoslow@gmail.com
|
52
|
+
executables: []
|
53
|
+
|
54
|
+
extensions: []
|
55
|
+
|
56
|
+
extra_rdoc_files: []
|
57
|
+
|
58
|
+
files:
|
59
|
+
- .gitignore
|
60
|
+
- CHANGELOG.md
|
61
|
+
- Gemfile
|
62
|
+
- LICENSE
|
63
|
+
- README.md
|
64
|
+
- Rakefile
|
65
|
+
- lib/plex-ruby.rb
|
66
|
+
- lib/plex-ruby/client.rb
|
67
|
+
- lib/plex-ruby/episode.rb
|
68
|
+
- lib/plex-ruby/libary.rb
|
69
|
+
- lib/plex-ruby/media.rb
|
70
|
+
- lib/plex-ruby/movie.rb
|
71
|
+
- lib/plex-ruby/null.rb
|
72
|
+
- lib/plex-ruby/parser.rb
|
73
|
+
- lib/plex-ruby/part.rb
|
74
|
+
- lib/plex-ruby/season.rb
|
75
|
+
- lib/plex-ruby/section.rb
|
76
|
+
- lib/plex-ruby/server.rb
|
77
|
+
- lib/plex-ruby/show.rb
|
78
|
+
- lib/plex-ruby/stream.rb
|
79
|
+
- lib/plex-ruby/tags.rb
|
80
|
+
- lib/plex-ruby/version.rb
|
81
|
+
- lib/plex-ruby/video.rb
|
82
|
+
- plex-ruby.gemspec
|
83
|
+
- test/test_helper.rb
|
84
|
+
has_rdoc: true
|
85
|
+
homepage: ""
|
86
|
+
licenses: []
|
87
|
+
|
88
|
+
post_install_message:
|
89
|
+
rdoc_options: []
|
90
|
+
|
91
|
+
require_paths:
|
92
|
+
- lib
|
93
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
94
|
+
none: false
|
95
|
+
requirements:
|
96
|
+
- - ">="
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: "0"
|
99
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
100
|
+
none: false
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: "0"
|
105
|
+
requirements: []
|
106
|
+
|
107
|
+
rubyforge_project: plex-ruby
|
108
|
+
rubygems_version: 1.6.2
|
109
|
+
signing_key:
|
110
|
+
specification_version: 3
|
111
|
+
summary: Plex APIs in easy ruby code
|
112
|
+
test_files:
|
113
|
+
- test/test_helper.rb
|