plex-ruby 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## 0.0.1.alpha
2
+
3
+ * Initial Release
4
+ * Browsing a library works
5
+ * Sending commands to a clients works intermittently, needs lots of work
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in plex-ruby.gemspec
4
+ gemspec
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
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
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,3 @@
1
+ module Plex
2
+ VERSION = "0.1.0"
3
+ 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
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