diff --git a/.travis.yml b/.travis.yml
index dc2e8c8..cec036a 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,3 +1,4 @@
rvm:
- - 1.9.2
- 1.9.3
+ - 2.0.0
+ - 2.1.1
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 42db3f5..1e477e6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,9 @@
+## 1.5.3
+* The player name is now escaped correctly in the URI (@jodyalbritton)
+
+## 1.5.2
+* Added support for authentication token via `Plex.configure`
+
## 1.5.1
* `Plex::Video` now supports multiple media entries (`@media` renamed to `@medias`)
diff --git a/lib/plex-ruby.rb b/lib/plex-ruby.rb
index 793cb20..aea65f1 100644
--- a/lib/plex-ruby.rb
+++ b/lib/plex-ruby.rb
@@ -22,10 +22,10 @@ def self.configure
# Custom open func which adds the required headers configured by
# Plex.configure
def self.open(url)
- headers = {}
+ headers = {:ssl_verify_mode => 0}
headers["X-Plex-Token"] = config.auth_token if config.auth_token
- super(url, headers)
+ URI.open(url, headers)
end
# Converts camel case names that are commonly found in the Plex APIs into
@@ -62,10 +62,15 @@ def self.camelize(string, first_letter_uppercase = false)
require 'plex-ruby/video'
require 'plex-ruby/media'
require 'plex-ruby/part'
+require 'plex-ruby/player'
require 'plex-ruby/stream'
+require 'plex-ruby/status'
require 'plex-ruby/tags'
require 'plex-ruby/show'
require 'plex-ruby/season'
require 'plex-ruby/episode'
require 'plex-ruby/movie'
+require 'plex-ruby/artist'
+require 'plex-ruby/album'
+require 'plex-ruby/track'
diff --git a/lib/plex-ruby/album.rb b/lib/plex-ruby/album.rb
new file mode 100644
index 0000000..3d25e9c
--- /dev/null
+++ b/lib/plex-ruby/album.rb
@@ -0,0 +1,85 @@
+module Plex
+ class Album
+
+ ATTRIBUTES = %w(ratingKey guid title summary index thumb year addedAt updatedAt)
+
+ attr_reader :section, :key, :attribute_hash
+
+ # @param [Artist] Artist this album belongs to
+ # @param [String] key to use to later grab this Album
+ def initialize(section, key)
+ @section = section
+ @key = key
+ @attribute_hash = {}
+
+ directory.attributes.each do |method, val|
+ @attribute_hash[Plex.underscore(method)] = val.value
+ define_singleton_method(Plex.underscore(method).to_sym) do
+ val.value
+ end
+ end
+
+ @attribute_hash.merge({'key' => @key})
+ end
+
+ # The list of Tracks in the library that belong to this Album
+ #
+ # @return [Array] list of Tracks that appear on this Album
+ def tracks
+ search_children children
+ end
+
+ # @private
+ def url #:nodoc:
+ section.url
+ end
+
+ # @private
+ def ==(other) #:nodoc:
+ if other.is_a? Plex::Album
+ key == other.key
+ else
+ super
+ end
+ end
+
+ # @private
+ def inspect #:nodoc:
+ "#"
+ end
+
+ private
+
+ def base_doc
+ Nokogiri::XML( open(url+key) )
+ end
+
+ def children_base
+ Nokogiri::XML( open(url+key+'/children') )
+ end
+
+ def xml_doc
+ @xml_doc ||= base_doc
+ end
+
+ def children
+ @children ||= children_base
+ end
+
+ def directory
+ @directory ||= xml_doc.search('Directory').first
+ end
+
+ def search_children(node)
+ node.search('Track').map do |track|
+ plex_track.new(self, track.attr('key'), track.search('Media'))
+ end
+ end
+
+ def plex_track
+ @plex_track ||= Plex::Track
+ end
+
+ end
+
+end
diff --git a/lib/plex-ruby/artist.rb b/lib/plex-ruby/artist.rb
new file mode 100644
index 0000000..a635ab9
--- /dev/null
+++ b/lib/plex-ruby/artist.rb
@@ -0,0 +1,85 @@
+module Plex
+ class Artist
+
+ ATTRIBUTES = %w(ratingKey guid title summary index thumb addedAt updatedAt)
+
+ attr_reader :section, :key, :attribute_hash
+
+ # @param [Section] section this artist belongs to
+ # @param [String] key to use to later grab this Artist
+ def initialize(section, key)
+ @section = section
+ @key = key
+ @attribute_hash = {}
+
+ directory.attributes.each do |method, val|
+ @attribute_hash[Plex.underscore(method)] = val.value
+ define_singleton_method(Plex.underscore(method).to_sym) do
+ val.value
+ end
+ end
+
+ @attribute_hash.merge({'key' => @key})
+ end
+
+ # The list of Albums in the library that belong to this Artist
+ #
+ # @return [Array] list of Albums that are credited to this Artist
+ def albums
+ @albums ||= search_children children
+ end
+
+ # @private
+ def url #:nodoc:
+ section.url
+ end
+
+ # @private
+ def ==(other) #:nodoc:
+ if other.is_a? Plex::Artist
+ key == other.key
+ else
+ super
+ end
+ end
+
+ # @private
+ def inspect #:nodoc:
+ "#"
+ end
+
+ private
+
+ def base_doc
+ Nokogiri::XML( open(url+key) )
+ end
+
+ def children_base
+ Nokogiri::XML( open(url+key+'/children') )
+ end
+
+ def xml_doc
+ @xml_doc ||= base_doc
+ end
+
+ def children
+ @children ||= children_base
+ end
+
+ def directory
+ @directory ||= xml_doc.search('Directory').first
+ end
+
+ def search_children(node)
+ node.search('Directory[type="album"]').map do |album|
+ plex_album.new(self, album.attr('key')[0..-10]) # Remove /children
+ end
+ end
+
+ def plex_album
+ @plex_album ||= Plex::Album
+ end
+
+ end
+
+end
diff --git a/lib/plex-ruby/client.rb b/lib/plex-ruby/client.rb
index 023c443..e8e19e2 100644
--- a/lib/plex-ruby/client.rb
+++ b/lib/plex-ruby/client.rb
@@ -133,7 +133,7 @@ def inspect #:nodoc:
private
def player_url
- url+"/system/players/#{name}"
+ URI.escape(url+"/system/players/#{name}")
end
def ping(url)
diff --git a/lib/plex-ruby/library.rb b/lib/plex-ruby/library.rb
index e21d33c..e6a52c5 100644
--- a/lib/plex-ruby/library.rb
+++ b/lib/plex-ruby/library.rb
@@ -3,6 +3,9 @@ class Library
attr_reader :server
+ WATCHED_LINK = "/:/scrobble?identifier=com.plexapp.plugins.library&key="
+ UNWATCHED_LINK = "/:/unscrobble?identifier=com.plexapp.plugins.library&key="
+
# @param [Server] server this libary belongs to
def initialize(server)
@server = server
@@ -33,6 +36,20 @@ def sections!
@sections = search_sections(xml_doc!)
end
+ # Set the video as watched
+ #
+ # @param [Video] video to be set as watched
+ def watched(video)
+ open(url+WATCHED_LINK+video.rating_key)
+ end
+
+ # Set the video as unwatched
+ #
+ # @param [Video] video to be set as unwatched
+ def unwatched(video)
+ open(url+UNWATCHED_LINK+video.rating_key)
+ end
+
# @private
def key #:nodoc:
"/library/sections"
diff --git a/lib/plex-ruby/parser.rb b/lib/plex-ruby/parser.rb
index 21dd61d..eea0244 100644
--- a/lib/plex-ruby/parser.rb
+++ b/lib/plex-ruby/parser.rb
@@ -63,6 +63,10 @@ def parse_directory
case node.attr('type')
when 'show'
Plex::Show.new( parent, node.attr('key')[0..-10] ) # Remove /children
+ when 'artist'
+ Plex::Artist.new( parent, node.attr('key')[0..-10] )
+ when 'album'
+ Plex::Album.new( parent, node.attr('key')[0..-10] )
else
raise "Unsupported Directory type #{node.attr('type')}"
end
diff --git a/lib/plex-ruby/player.rb b/lib/plex-ruby/player.rb
new file mode 100644
index 0000000..aa68f1a
--- /dev/null
+++ b/lib/plex-ruby/player.rb
@@ -0,0 +1,27 @@
+module Plex
+ class Player
+
+ ATTRIBUTES = %w(machineIdentifier platform product state title)
+
+ attr_reader :parts
+
+ # @param [Nokogiri::XML::Element] nokogiri element that represents this
+ # Media
+ def initialize(node)
+ node.attributes.each do |method, val|
+ define_singleton_method(Plex.underscore(method).to_sym) do
+ val.value
+ end
+ end
+ end
+
+ def ==(other)
+ if other.is_a? Media
+ id == other.id
+ else
+ super
+ end
+ end
+
+ end
+end
diff --git a/lib/plex-ruby/section.rb b/lib/plex-ruby/section.rb
index 772d1eb..b97bf17 100644
--- a/lib/plex-ruby/section.rb
+++ b/lib/plex-ruby/section.rb
@@ -20,8 +20,8 @@ def initialize(library, node)
}
end
- # NOT IMPLEMENTED
- def refresh(deep = false, force = false)
+ def refresh
+ Plex.open(url + key + '/refresh')
end
@@ -35,13 +35,14 @@ def refresh(deep = false, force = false)
# on_deck - videos that are "on deck" in this Section
#
# @return [Array] list of Shows or Movies in that group
- GROUPS.each { |method|
- class_eval %(
- def #{Plex.underscore(method)}
- Plex::Parser.new( self, Nokogiri::XML(Plex.open(url+key+'/#{method}')) ).parse
- end
- )
- }
+ GROUPS.each do |method|
+ define_method(Plex.underscore(method).to_sym) do |options = {}|
+ path = '/' + method + '?'
+ path += "title=#{CGI::escape(options[:title])}" if options[:title]
+ path += "type=4" if options[:episodes]
+ Plex::Parser.new( self, Nokogiri::XML(Plex.open(url+key+path )) ).parse
+ end
+ end
# Find TV Shows / Episodes by categories
#
diff --git a/lib/plex-ruby/server.rb b/lib/plex-ruby/server.rb
index 29c2243..cea0b90 100644
--- a/lib/plex-ruby/server.rb
+++ b/lib/plex-ruby/server.rb
@@ -14,6 +14,13 @@ def initialize(host, port)
def library
@library ||= Plex::Library.new(self)
end
+
+ # The current status of this server
+ #
+ # @return [Status] this Servers status
+ def status
+ @status ||= Plex::Status.new(self)
+ end
# The Plex clients that are connected to this Server
#
@@ -29,7 +36,7 @@ def clients!
# @private
def url #:nodoc:
- "http://#{host}:#{port}"
+ "https://#{host}:#{port}"
end
# @private
diff --git a/lib/plex-ruby/status.rb b/lib/plex-ruby/status.rb
new file mode 100644
index 0000000..7f7a408
--- /dev/null
+++ b/lib/plex-ruby/status.rb
@@ -0,0 +1,81 @@
+module Plex
+ class Status
+
+ attr_reader :server
+
+ # @param [Server] server this libary belongs to
+ def initialize(server)
+ @server = server
+ end
+
+ # Grab a specific session
+ #
+ # @param [String, Fixnum] key of the session we want
+ # @return [Video] session with that key
+ def session(id)
+ search_sessions(xml_doc, id).first
+ end
+
+ # Cache busting version of #session
+ def session!(id)
+ search_sessions(xml_doc!, id).first
+ end
+
+ # A list of sessions that are located in this library
+ #
+ # @return [Array] list of videos
+ def sessions
+ @sessions ||= search_sessions(xml_doc)
+ end
+
+ # Cache busting version of #sessions
+ def sessions!
+ @sessions = search_sessions(xml_doc!)
+ end
+
+ # @private
+ def key #:nodoc:
+ "/status/sessions"
+ end
+
+ # @private
+ def url #:nodoc:
+ server.url
+ end
+
+ # @private
+ def ==(other) #:nodoc:
+ if other.is_a? Library
+ server == other.server
+ else
+ super
+ end
+ end
+
+ # @private
+ def inspect #:nodoc:
+ "#"
+ end
+
+ private
+
+ def search_sessions(doc, key = nil)
+ term = key ? "Video[@sessionKey='#{key}']" : 'Video'
+ doc.search(term).map { |m| Plex::Video.new(m) }
+ end
+
+ def xml_doc
+ @xml_doc ||= base_doc
+ end
+
+ def xml_doc!
+ @xml_doc = base_doc
+ end
+
+ def base_doc
+ Nokogiri::XML( Plex.open(url+key) )
+ end
+
+
+ end
+end
diff --git a/lib/plex-ruby/track.rb b/lib/plex-ruby/track.rb
new file mode 100644
index 0000000..b03263b
--- /dev/null
+++ b/lib/plex-ruby/track.rb
@@ -0,0 +1,72 @@
+module Plex
+ class Track
+
+ ATTRIBUTES = %w(ratingKey title originalTitle summary index duration thumb year addedAt updatedAt)
+
+ attr_reader :section, :key, :attribute_hash
+ attr_reader :medias
+
+ # @param [Album] Album this Track belongs to
+ # @param [String] key to use to later grab this Track
+ # @param [Nokogiri::XML::Element] Media node(s)
+ def initialize(section, key, medias = nil)
+ @section = section
+ @key = key
+ @attribute_hash = {}
+
+ track.attributes.each do |method, val|
+ @attribute_hash[Plex.underscore(method)] = val.value
+ define_singleton_method(Plex.underscore(method).to_sym) do
+ val.value
+ end
+ end
+
+ @attribute_hash.merge({'key' => @key})
+
+ @medias = medias.map { |m| Plex::Media.new(m) }
+ end
+
+ # @private
+ def url #:nodoc:
+ section.url
+ end
+
+ # @private
+ def ==(other) #:nodoc:
+ if other.is_a? Plex::Track
+ key == other.key
+ else
+ super
+ end
+ end
+
+ # @private
+ def inspect #:nodoc:
+ "#"
+ end
+
+ private
+
+ def base_doc
+ Nokogiri::XML( open(url+key) )
+ end
+
+ def children_base
+ Nokogiri::XML( open(url+key+'/children') )
+ end
+
+ def xml_doc
+ @xml_doc ||= base_doc
+ end
+
+ def children
+ @children ||= children_base
+ end
+
+ def track
+ @track ||= xml_doc.search('Track').first
+ end
+
+ end
+
+end
diff --git a/lib/plex-ruby/version.rb b/lib/plex-ruby/version.rb
index a95ac9e..9d95496 100644
--- a/lib/plex-ruby/version.rb
+++ b/lib/plex-ruby/version.rb
@@ -1,3 +1,3 @@
module Plex
- VERSION = "1.5.1"
+ VERSION = "1.5.3"
end
diff --git a/lib/plex-ruby/video.rb b/lib/plex-ruby/video.rb
index 79d896e..528a1e2 100644
--- a/lib/plex-ruby/video.rb
+++ b/lib/plex-ruby/video.rb
@@ -5,7 +5,7 @@ class Video
rating viewCount year tagline thumb art duration
originallyAvailableAt updatedAt)
- attr_reader :medias, :genres, :writers, :directors, :roles, :attribute_hash
+ attr_reader :medias, :genres, :writers, :directors, :roles, :players, :attribute_hash
# @param [Nokogiri::XML::Element] nokogiri element that represents this
# Video
@@ -23,6 +23,7 @@ def initialize(node)
@writers = node.search('Writer').map { |m| Plex::Writer.new(m) }
@directors = node.search('Director').map { |m| Plex::Director.new(m) }
@roles = node.search('Role').map { |m| Plex::Role.new(m) }
+ @players = node.search('Player').map { |m| Plex::Player.new(m) }
end
diff --git a/test/test_client.rb b/test/test_client.rb
index 41ccf95..659d3be 100644
--- a/test/test_client.rb
+++ b/test/test_client.rb
@@ -5,7 +5,7 @@
before do
@server = FakeParent.new
@client = Plex::Client.new(@server, FakeNode.new(FAKE_CLIENT_NODE_HASH))
- FakeWeb.register_uri(:get, %r|http://localhost:32400|, :body => "")
+ FakeWeb.register_uri(:get, %r|https://localhost:32400|, :body => "")
end
after do
diff --git a/test/test_helper.rb b/test/test_helper.rb
index dcb7a62..bca534f 100644
--- a/test/test_helper.rb
+++ b/test/test_helper.rb
@@ -39,7 +39,7 @@ def search(value)
class FakeParent
def url
- 'http://localhost:32400'
+ 'https://localhost:32400'
end
end
diff --git a/test/test_plex.rb b/test/test_plex.rb
index 9c8a38f..fac008e 100644
--- a/test/test_plex.rb
+++ b/test/test_plex.rb
@@ -9,7 +9,7 @@
end
before do
- FakeWeb.register_uri(:get, "http://localhost:32400", :body => "")
+ FakeWeb.register_uri(:get, "https://localhost:32400", :body => "")
end
after do
@@ -20,7 +20,7 @@
it "has an open function which respects the configuration" do
Plex.configure {|config| config.auth_token = "ABCD" }
- Plex.open("http://localhost:32400").read
+ Plex.open("https://localhost:32400").read
FakeWeb.last_request["X-Plex-Token"].must_equal "ABCD"
end
end
diff --git a/test/test_server.rb b/test/test_server.rb
index 4a643ae..3ce3994 100644
--- a/test/test_server.rb
+++ b/test/test_server.rb
@@ -14,7 +14,7 @@
end
it "properly formats its url" do
- @server.url.must_equal "http://localhost:3000"
+ @server.url.must_equal "https://localhost:3000"
end
it "has a libary" do