From cb66c93354eebec113cf236979fd948c32527c6b Mon Sep 17 00:00:00 2001 From: Hellowlol Date: Mon, 27 Feb 2017 13:23:35 +0100 Subject: [PATCH 1/9] inital lib --- plexapi/library.py | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/plexapi/library.py b/plexapi/library.py index b132f457..80e1765c 100644 --- a/plexapi/library.py +++ b/plexapi/library.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- from plexapi import X_PLEX_CONTAINER_SIZE, log, utils from plexapi.base import PlexObject -from plexapi.compat import unquote +from plexapi.compat import unquote, urlencode, quote_plus from plexapi.media import MediaTag from plexapi.exceptions import BadRequest, NotFound @@ -144,6 +144,34 @@ class Library(PlexObject): for section in self.sections(): section.deleteMediaPreviews() + def addLibrary(self, name='', media_type='', location='', *args, **kwargs): + """ Simplified add for the most common options. + + name (str): Name of the library + media_type (str): movie, show, # check me + location (str): + + """ + from plexpai.compat import quote_plus, urlencode + + # agents + # https://10-0-0-97.b0b2cd13b5684d54bc9f439d7a9df61e.plex.direct:32400/system/agents?mediaType=2&X-Plex-Product=Plex%20Web&X-Plex-Version=2.13.0&X-Plex-Client-Identifier=9l332forz5fdpldi&X-Plex-Platform=Chrome&X-Plex-Platform-Version=56.0&X-Plex-Device=Windows&X-Plex-Device-Name=Plex%20Web%20%28Chrome%29&X-Plex-Device-Screen-Resolution=1366x662%2C1366x768&X-Plex-Token= + + # Scanner + # https://10-0-0-97.b0b2cd13b5684d54bc9f439d7a9df61e.plex.direct:32400/system/scanners/2?X-Plex-Product=Plex%20Web&X-Plex-Version=2.13.0&X-Plex-Client-Identifier=9l332forz5fdpldi&X-Plex-Platform=Chrome&X-Plex-Platform-Version=56.0&X-Plex-Device=Windows&X-Plex-Device-Name=Plex%20Web%20%28Chrome%29&X-Plex-Device-Screen-Resolution=1366x662%2C1366x768&X-Plex-Token= + + # advance gets the info from. + # https://10-0-0-97.b0b2cd13b5684d54bc9f439d7a9df61e.plex.direct:32400/library/sections/prefs?type=2&agent=com.plexapp.agents.thetvdb&X-Plex-Product=Plex%20Web&X-Plex-Version=2.13.0&X-Plex-Client-Identifier=9l332forz5fdpldi&X-Plex-Platform=Chrome&X-Plex-Platform-Version=56.0&X-Plex-Device=Windows&X-Plex-Device-Name=Plex%20Web%20%28Chrome%29&X-Plex-Device-Screen-Resolution=864x662%2C1366x768&X-Plex-Token= + + # Add lib. + part = '/library/sections?name=%s&type=%s&agent=%s&scanner=%s&language=en&importFromiTunes=&enableAutoPhotoTags=&location=%s' % (quote_plus(name), mtype, agent, scanner, quote_plus(location)) + if kwargs: # for advanced settings etc. + part += urlencode(kwargs) + + # https://10-0-0-97.b0b2cd13b5684d54bc9f439d7a9df61e.plex.direct:32400/library/sections?name=Movies&type=movie&agent=com.plexapp.agents.imdb&scanner=Plex%20Movie%20Scanner&language=en&importFromiTunes=&enableAutoPhotoTags=&location=D%3A%5Ccpmovies&X-Plex-Product=Plex%20Web&X-Plex-Version=2.13.0&X-Plex-Client-Identifier=9l332forz5fdpldi&X-Plex-Platform=Chrome&X-Plex-Platform-Version=56.0&X-Plex-Device=Windows&X-Plex-Device-Name=Plex%20Web%20%28Chrome%29&X-Plex-Device-Screen-Resolution=1366x662%2C1366x768&X-Plex-Token=utrPyACsqh26yCLR7gWo + self._server._session.query(url) + + class LibrarySection(PlexObject): """ Base class for a single library section. @@ -204,6 +232,11 @@ class LibrarySection(PlexObject): log.error(msg) raise + def editLibrary(self, **kwargs): + part = '/library/sections/%s?%s' % (self.key, urlencode(kwargs)) + print(part) + return self._server._query(part, method=self._server._session.put) + def get(self, title): """ Returns the media item with the specified title. From ff4b1010a99e38918bd7398d83d5492b4a630c2c Mon Sep 17 00:00:00 2001 From: Hellowlol Date: Mon, 27 Feb 2017 22:04:37 +0100 Subject: [PATCH 2/9] Add edit/add library. --- plexapi/library.py | 50 +++++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/plexapi/library.py b/plexapi/library.py index 80e1765c..862b363f 100644 --- a/plexapi/library.py +++ b/plexapi/library.py @@ -144,32 +144,24 @@ class Library(PlexObject): for section in self.sections(): section.deleteMediaPreviews() - def addLibrary(self, name='', media_type='', location='', *args, **kwargs): + def add(self, name='', media_type='', agent='', scanner='', location='', language='en', *args, **kwargs): """ Simplified add for the most common options. name (str): Name of the library - media_type (str): movie, show, # check me - location (str): + agent (str): Example com.plexapp.agents.imdb + type (str): movie, show, # check me + location (str): /path/to/files + language (str): Two letter language fx en + kwargs (dict): Advanced options should be passed as a dict. where the id is the key. """ - from plexpai.compat import quote_plus, urlencode + # Should this function be here or in server?? + part = '/library/sections?name=%s&type=%s&agent=%s&scanner=%s&language=%s&location=%s' % ( + quote_plus(name), type, agent, quote_plus(scanner), language, quote_plus(location)) - # agents - # https://10-0-0-97.b0b2cd13b5684d54bc9f439d7a9df61e.plex.direct:32400/system/agents?mediaType=2&X-Plex-Product=Plex%20Web&X-Plex-Version=2.13.0&X-Plex-Client-Identifier=9l332forz5fdpldi&X-Plex-Platform=Chrome&X-Plex-Platform-Version=56.0&X-Plex-Device=Windows&X-Plex-Device-Name=Plex%20Web%20%28Chrome%29&X-Plex-Device-Screen-Resolution=1366x662%2C1366x768&X-Plex-Token= - - # Scanner - # https://10-0-0-97.b0b2cd13b5684d54bc9f439d7a9df61e.plex.direct:32400/system/scanners/2?X-Plex-Product=Plex%20Web&X-Plex-Version=2.13.0&X-Plex-Client-Identifier=9l332forz5fdpldi&X-Plex-Platform=Chrome&X-Plex-Platform-Version=56.0&X-Plex-Device=Windows&X-Plex-Device-Name=Plex%20Web%20%28Chrome%29&X-Plex-Device-Screen-Resolution=1366x662%2C1366x768&X-Plex-Token= - - # advance gets the info from. - # https://10-0-0-97.b0b2cd13b5684d54bc9f439d7a9df61e.plex.direct:32400/library/sections/prefs?type=2&agent=com.plexapp.agents.thetvdb&X-Plex-Product=Plex%20Web&X-Plex-Version=2.13.0&X-Plex-Client-Identifier=9l332forz5fdpldi&X-Plex-Platform=Chrome&X-Plex-Platform-Version=56.0&X-Plex-Device=Windows&X-Plex-Device-Name=Plex%20Web%20%28Chrome%29&X-Plex-Device-Screen-Resolution=864x662%2C1366x768&X-Plex-Token= - - # Add lib. - part = '/library/sections?name=%s&type=%s&agent=%s&scanner=%s&language=en&importFromiTunes=&enableAutoPhotoTags=&location=%s' % (quote_plus(name), mtype, agent, scanner, quote_plus(location)) - if kwargs: # for advanced settings etc. + if kwargs: part += urlencode(kwargs) - - # https://10-0-0-97.b0b2cd13b5684d54bc9f439d7a9df61e.plex.direct:32400/library/sections?name=Movies&type=movie&agent=com.plexapp.agents.imdb&scanner=Plex%20Movie%20Scanner&language=en&importFromiTunes=&enableAutoPhotoTags=&location=D%3A%5Ccpmovies&X-Plex-Product=Plex%20Web&X-Plex-Version=2.13.0&X-Plex-Client-Identifier=9l332forz5fdpldi&X-Plex-Platform=Chrome&X-Plex-Platform-Version=56.0&X-Plex-Device=Windows&X-Plex-Device-Name=Plex%20Web%20%28Chrome%29&X-Plex-Device-Screen-Resolution=1366x662%2C1366x768&X-Plex-Token=utrPyACsqh26yCLR7gWo - self._server._session.query(url) + return self._server.query(part, method=self._server._session.post) @@ -232,10 +224,22 @@ class LibrarySection(PlexObject): log.error(msg) raise - def editLibrary(self, **kwargs): - part = '/library/sections/%s?%s' % (self.key, urlencode(kwargs)) - print(part) - return self._server._query(part, method=self._server._session.put) + def edit(self, **kwargs): + """Edit a library + + See addLibrary for example usage. + Note: agent is required. + + """ + # We might need to quote more, but lets start with what we know. + kw = {} + for k, v in kwargs.items(): + if k in ('scanner', 'name', 'location'): + v = quote_plus(v) + kw[k] = v + + part = '/library/sections/%s?%s' % (self.key, urlencode(kw)) + return self._server.query(part, method=self._server._session.put) def get(self, title): """ Returns the media item with the specified title. From db3b729360cfa0cae98af0fe447c411ddd90f7bd Mon Sep 17 00:00:00 2001 From: Hellowlol Date: Mon, 27 Feb 2017 23:16:02 +0100 Subject: [PATCH 3/9] one step closer with the test. --- plexapi/base.py | 9 +++++---- plexapi/library.py | 15 ++++++++++++--- tests/test_library.py | 16 ++++++++++++++++ 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/plexapi/base.py b/plexapi/base.py index 23df80bf..8fd2c452 100644 --- a/plexapi/base.py +++ b/plexapi/base.py @@ -177,12 +177,13 @@ class PlexObject(object): results.append(elem.attrib.get(attr)) return results - def reload(self): + def reload(self, key=None): """ Reload the data for this object from self.key. """ - if not self.key: + key = key or self.key + if not key: raise Unsupported('Cannot reload an object not built from a URL.') - self._initpath = self.key - data = self._server.query(self.key) + self._initpath = key + data = self._server.query(key) self._loadData(data[0]) return self diff --git a/plexapi/library.py b/plexapi/library.py index 862b363f..9e7bc5fc 100644 --- a/plexapi/library.py +++ b/plexapi/library.py @@ -144,7 +144,7 @@ class Library(PlexObject): for section in self.sections(): section.deleteMediaPreviews() - def add(self, name='', media_type='', agent='', scanner='', location='', language='en', *args, **kwargs): + def add(self, name='', type='', agent='', scanner='', location='', language='en', *args, **kwargs): """ Simplified add for the most common options. name (str): Name of the library @@ -227,9 +227,13 @@ class LibrarySection(PlexObject): def edit(self, **kwargs): """Edit a library - See addLibrary for example usage. + See :class:`~plexapi.library.Library for example usage. + Note: agent is required. + kwargs (dict): Dict of settings to edit. Some values might need to be quoted. + Value of scanner, name and location is quoted automatically. + """ # We might need to quote more, but lets start with what we know. kw = {} @@ -239,7 +243,12 @@ class LibrarySection(PlexObject): kw[k] = v part = '/library/sections/%s?%s' % (self.key, urlencode(kw)) - return self._server.query(part, method=self._server._session.put) + self._server.query(part, method=self._server._session.put) + # Reload this way since the self.key dont have a full path, but is simply a id. + for s in self._server.library.sections(): + if s.key == self.key: + return s + def get(self, title): """ Returns the media item with the specified title. diff --git a/tests/test_library.py b/tests/test_library.py index 99f2bdfa..9e7efbcf 100644 --- a/tests/test_library.py +++ b/tests/test_library.py @@ -76,6 +76,22 @@ def test_library_search(pms): m = pms.library.search('16 blocks')[0] assert m.title == '16 Blocks' +def test_library_add_edit_delete(pms): + d = dict(name='zomg strange11', type='movie', agent='com.plexapp.agents.imdb', + scanner='Plex Movie Scanner', language='en') + + rn = dict(name='a renamed lib', type='movie', agent='com.plexapp.agents.imdb') + + # We dont want to add a location because we dont want to start scanning. + pms.library.add(**d) + + assert pms.library.section('zomg strange11') + + edited_library = pms.library.section('zomg strange11').edit(**rn) + assert edited_library.title == 'a renamed lib' + + pms.library.section('a renamed lib').delete() + def test_library_Library_cleanBundle(pms): pms.library.cleanBundles() From cfae507471551aa0eff9229677cc40bd56814ab4 Mon Sep 17 00:00:00 2001 From: Hellowlol Date: Mon, 27 Feb 2017 23:20:10 +0100 Subject: [PATCH 4/9] Fix test. --- plexapi/library.py | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/plexapi/library.py b/plexapi/library.py index 9e7bc5fc..c1bbe60e 100644 --- a/plexapi/library.py +++ b/plexapi/library.py @@ -231,19 +231,12 @@ class LibrarySection(PlexObject): Note: agent is required. - kwargs (dict): Dict of settings to edit. Some values might need to be quoted. - Value of scanner, name and location is quoted automatically. + kwargs (dict): Dict of settings to edit. """ - # We might need to quote more, but lets start with what we know. - kw = {} - for k, v in kwargs.items(): - if k in ('scanner', 'name', 'location'): - v = quote_plus(v) - kw[k] = v - - part = '/library/sections/%s?%s' % (self.key, urlencode(kw)) + part = '/library/sections/%s?%s' % (self.key, urlencode(kwargs)) self._server.query(part, method=self._server._session.put) + # Reload this way since the self.key dont have a full path, but is simply a id. for s in self._server.library.sections(): if s.key == self.key: From 167939173f690701913da3b8a32d687e6bd2392e Mon Sep 17 00:00:00 2001 From: Hellowlol Date: Tue, 28 Feb 2017 22:30:34 +0100 Subject: [PATCH 5/9] flake fixes --- plexapi/library.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/plexapi/library.py b/plexapi/library.py index c1bbe60e..4de605a1 100644 --- a/plexapi/library.py +++ b/plexapi/library.py @@ -157,14 +157,13 @@ class Library(PlexObject): """ # Should this function be here or in server?? part = '/library/sections?name=%s&type=%s&agent=%s&scanner=%s&language=%s&location=%s' % ( - quote_plus(name), type, agent, quote_plus(scanner), language, quote_plus(location)) + quote_plus(name), type, agent, quote_plus(scanner), language, quote_plus(location)) # noqa E126 if kwargs: part += urlencode(kwargs) return self._server.query(part, method=self._server._session.post) - class LibrarySection(PlexObject): """ Base class for a single library section. @@ -242,7 +241,6 @@ class LibrarySection(PlexObject): if s.key == self.key: return s - def get(self, title): """ Returns the media item with the specified title. From 93a9ea348830a04f3d0b2ef7846b9d1ce95f4b3e Mon Sep 17 00:00:00 2001 From: Hellowlol Date: Tue, 28 Feb 2017 22:49:49 +0100 Subject: [PATCH 6/9] addtourl helper. --- plexapi/settings.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/plexapi/settings.py b/plexapi/settings.py index 3a7bb1a2..9f85ebdc 100644 --- a/plexapi/settings.py +++ b/plexapi/settings.py @@ -1,8 +1,9 @@ # -*- coding: utf-8 -*- from collections import defaultdict + from plexapi import log, utils from plexapi.base import PlexObject -from plexapi.compat import string_type, quote +from plexapi.compat import quote, string_type from plexapi.exceptions import BadRequest, NotFound @@ -149,3 +150,7 @@ class Setting(PlexObject): # store value off to the side until we call settings.save() tostr = self.TYPES[self.type]['tostr'] self._setValue = tostr(value) + + def toUrl(self): + """Helper for urls""" + return '%s=%s' % (self.id, self._value or self.value) From 70fce72f44211b8791744403b89556aad129d4dd Mon Sep 17 00:00:00 2001 From: Hellowlol Date: Fri, 3 Mar 2017 23:32:16 +0100 Subject: [PATCH 7/9] more dosc. --- plexapi/library.py | 37 +++++++++++++++++++++++++++ tools/atter_doc_string.py | 53 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 tools/atter_doc_string.py diff --git a/plexapi/library.py b/plexapi/library.py index 4de605a1..042d8976 100644 --- a/plexapi/library.py +++ b/plexapi/library.py @@ -153,6 +153,39 @@ class Library(PlexObject): location (str): /path/to/files language (str): Two letter language fx en kwargs (dict): Advanced options should be passed as a dict. where the id is the key. + # Sooo this was a major fucking pain.. + + # Prefs for album + includeInGlobal (bool): Default value true + + # Prefs for episode + includeInGlobal (bool): Default value true + + # Prefs for artist + includeInGlobal (bool): Default value true + respectTags (bool): Default value false + albumSort (int): Default value -1 Possible option: 0:Newest first,1:Oldest first,2:By name + enableTrackOffsets (bool): Default value false + scanner (str): Plex Music Scanner, Plex Premium Music Scanner + + # Prefs for track + includeInGlobal (bool): Default value true + + # Prefs for movie + includeInGlobal (bool): Default value true + enableCinemaTrailers (bool): Default value true + enableBIFGeneration (bool): Default value true + scanner (str): Options: Plex Movie Scanner, Plex Video Files Scanner + + # Prefs for show + includeInGlobal (bool): Default value true + enableBIFGeneration (bool): Default value true + flattenSeasons (int): Default value 0 Possible option: 0:Show,1:Hide + episodeSort (int): Default value -1 Possible option: 0:Oldest first,1:Newest first + + # Prefs for season + includeInGlobal (bool): Default value true + """ # Should this function be here or in server?? @@ -163,6 +196,10 @@ class Library(PlexObject): part += urlencode(kwargs) return self._server.query(part, method=self._server._session.post) + def share(self, user, *args, **kwargs): + """Share this library with the user.""" + pass + class LibrarySection(PlexObject): """ Base class for a single library section. diff --git a/tools/atter_doc_string.py b/tools/atter_doc_string.py new file mode 100644 index 00000000..63aef699 --- /dev/null +++ b/tools/atter_doc_string.py @@ -0,0 +1,53 @@ +from collections import OrderedDict +import re + +def type_finder(s): + type_string = str(type(s)) + x = re.search("'(.+)'", type_string) + if x: + return x.group(1) + + return '' + + +class AttDS(object): + """Helper that prints docstring attrs""" + + def __init__(self, o, keys=None, style='google'): + self.__o = o + + if not isinstance(o, dict): + self.o = o.__dict__.items() + self._as_dict = o.__dict__ + else: + self.o = o.items() + self._as_dict = o + + if keys is None: + self.keys = self._as_dict.keys() + else: + self.keys = keys + + if style == 'google': + self.template = '%s (%s): %s' + + self.res_dict = OrderedDict() + self.parse() + + def parse(self): + for k, v in sorted(self.o, key=lambda k: k[0]): + if self.keys: + ds = '' + for key in self.keys: + ds += '%s=%s ' % (key, self._as_dict.get(key, '')) + else: + ds = '' + + self.res_dict[k] = self.template % (k, type_finder(v), ds) + + def write(self): + for k, v in self.res_dict.items(): + print v + + +#x = AttDS(dict or object).write() From 9d0126f8084cdced85755d0042d2a767a95eccc9 Mon Sep 17 00:00:00 2001 From: Hellowlol Date: Sun, 5 Mar 2017 23:16:06 +0100 Subject: [PATCH 8/9] add docs --- plexapi/library.py | 97 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 73 insertions(+), 24 deletions(-) diff --git a/plexapi/library.py b/plexapi/library.py index 042d8976..cbeaae75 100644 --- a/plexapi/library.py +++ b/plexapi/library.py @@ -153,42 +153,91 @@ class Library(PlexObject): location (str): /path/to/files language (str): Two letter language fx en kwargs (dict): Advanced options should be passed as a dict. where the id is the key. - # Sooo this was a major fucking pain.. - # Prefs for album - includeInGlobal (bool): Default value true + # Prefs for photo + agent (str): com.plexapp.agents.none + enableAutoPhotoTags (bool): Tag photos. Default value false . + enableBIFGeneration (bool): Enable video preview thumbnails. Default value true . + includeInGlobal (bool): Include in dashboard. Default value true . + scanner (str): Plex Photo Scanner - # Prefs for episode - includeInGlobal (bool): Default value true + # Prefs for other movies + agent (str): com.plexapp.agents.none, com.plexapp.agents.imdb, com.plexapp.agents.themoviedb + enableBIFGeneration (bool): Enable video preview thumbnails. Default value true . + enableCinemaTrailers (bool): Enable Cinema Trailers. Default value true . + includeInGlobal (bool): Include in dashboard. Default value true . + scanner (str): Plex Movie Scanner, Plex Video Files Scanner - # Prefs for artist - includeInGlobal (bool): Default value true - respectTags (bool): Default value false - albumSort (int): Default value -1 Possible option: 0:Newest first,1:Oldest first,2:By name - enableTrackOffsets (bool): Default value false - scanner (str): Plex Music Scanner, Plex Premium Music Scanner + # other movies com.plexapp.agents.imdb settings options + title (bool): Localized titles. Default value false . + extras (bool): Find trailers and extras automatically (Plex Pass required). Default value true . + only_trailers (bool): Skip extras which aren't trailers. Default value false . + redband (bool): Use red band (restricted audiences) trailers when available. Default value false . + native_subs (bool): Include extras with subtitles in Library language. Default value false . + cast_list (int): Cast List Source: . Default value 1 Possible options: 0:IMDb,1:The Movie Database. + ratings (int): Ratings Source: . Default value 0 Possible options: 0:Rotten Tomatoes,1:IMDb,2:The Movie Database. + summary (int): Plot Summary Source: . Default value 1 Possible options: 0:IMDb,1:The Movie Database. + country (int): Country: . Default value 46 Possible options: 0:Argentina,1:Australia,2:Austria,3:Belgium,4:Belize,5:Bolivia,6:Brazil,7:Canada,8:Chile,9:Colombia,10:Costa Rica,11:Czech Republic,12:Denmark,13:Dominican Republic,14:Ecuador,15:El Salvador,16:France,17:Germany,18:Guatemala,19:Honduras,20:Hong Kong SAR,21:Ireland,22:Italy,23:Jamaica,24:Korea,25:Liechtenstein,26:Luxembourg,27:Mexico,28:Netherlands,29:New Zealand,30:Nicaragua,31:Panama,32:Paraguay,33:Peru,34:Portugal,35:Peoples Republic of China,36:Puerto Rico,37:Russia,38:Singapore,39:South Africa,40:Spain,41:Sweden,42:Switzerland,43:Taiwan,44:Trinidad,45:United Kingdom,46:United States,47:Uruguay,48:Venezuela. + collections (bool): Use collection info from The Movie Database. Default value false . + localart (bool): Prefer artwork based on library language. Default value true . + adult (bool): Include adult content. Default value false . + usage (bool): Send anonymous usage data to Plex. Default value true . - # Prefs for track - includeInGlobal (bool): Default value true + # other movies com.plexapp.agents.themoviedb settings options + collections (bool): Use collection info from The Movie Database. Default value false . + localart (bool): Prefer artwork based on library language. Default value true . + adult (bool): Include adult content. Default value false . + country (int): Country (used for release date and content rating). Default value 47 Possible options: 0:,1:Argentina,2:Australia,3:Austria,4:Belgium,5:Belize,6:Bolivia,7:Brazil,8:Canada,9:Chile,10:Colombia,11:Costa Rica,12:Czech Republic,13:Denmark,14:Dominican Republic,15:Ecuador,16:El Salvador,17:France,18:Germany,19:Guatemala,20:Honduras,21:Hong Kong SAR,22:Ireland,23:Italy,24:Jamaica,25:Korea,26:Liechtenstein,27:Luxembourg,28:Mexico,29:Netherlands,30:New Zealand,31:Nicaragua,32:Panama,33:Paraguay,34:Peru,35:Portugal,36:Peoples Republic of China,37:Puerto Rico,38:Russia,39:Singapore,40:South Africa,41:Spain,42:Sweden,43:Switzerland,44:Taiwan,45:Trinidad,46:United Kingdom,47:United States,48:Uruguay,49:Venezuela. # Prefs for movie - includeInGlobal (bool): Default value true - enableCinemaTrailers (bool): Default value true - enableBIFGeneration (bool): Default value true - scanner (str): Options: Plex Movie Scanner, Plex Video Files Scanner + agent (str): com.plexapp.agents.none, com.plexapp.agents.imdb, com.plexapp.agents.themoviedb + enableBIFGeneration (bool): Enable video preview thumbnails. Default value true . + enableCinemaTrailers (bool): Enable Cinema Trailers. Default value true . + includeInGlobal (bool): Include in dashboard. Default value true . + scanner (str): Plex Movie Scanner, Plex Video Files Scanner + + # movie com.plexapp.agents.imdb settings options + title (bool): Localized titles. Default value false . + extras (bool): Find trailers and extras automatically (Plex Pass required). Default value true . + only_trailers (bool): Skip extras which aren't trailers. Default value false . + redband (bool): Use red band (restricted audiences) trailers when available. Default value false . + native_subs (bool): Include extras with subtitles in Library language. Default value false . + cast_list (int): Cast List Source: . Default value 1 Possible options: 0:IMDb,1:The Movie Database. + ratings (int): Ratings Source: . Default value 0 Possible options: 0:Rotten Tomatoes,1:IMDb,2:The Movie Database. + summary (int): Plot Summary Source: . Default value 1 Possible options: 0:IMDb,1:The Movie Database. + country (int): Country: . Default value 46 Possible options: 0:Argentina,1:Australia,2:Austria,3:Belgium,4:Belize,5:Bolivia,6:Brazil,7:Canada,8:Chile,9:Colombia,10:Costa Rica,11:Czech Republic,12:Denmark,13:Dominican Republic,14:Ecuador,15:El Salvador,16:France,17:Germany,18:Guatemala,19:Honduras,20:Hong Kong SAR,21:Ireland,22:Italy,23:Jamaica,24:Korea,25:Liechtenstein,26:Luxembourg,27:Mexico,28:Netherlands,29:New Zealand,30:Nicaragua,31:Panama,32:Paraguay,33:Peru,34:Portugal,35:Peoples Republic of China,36:Puerto Rico,37:Russia,38:Singapore,39:South Africa,40:Spain,41:Sweden,42:Switzerland,43:Taiwan,44:Trinidad,45:United Kingdom,46:United States,47:Uruguay,48:Venezuela. + collections (bool): Use collection info from The Movie Database. Default value false . + localart (bool): Prefer artwork based on library language. Default value true . + adult (bool): Include adult content. Default value false . + usage (bool): Send anonymous usage data to Plex. Default value true . + + # movie com.plexapp.agents.themoviedb settings options + collections (bool): Use collection info from The Movie Database. Default value false . + localart (bool): Prefer artwork based on library language. Default value true . + adult (bool): Include adult content. Default value false . + country (int): Country (used for release date and content rating). Default value 47 Possible options: 0:,1:Argentina,2:Australia,3:Austria,4:Belgium,5:Belize,6:Bolivia,7:Brazil,8:Canada,9:Chile,10:Colombia,11:Costa Rica,12:Czech Republic,13:Denmark,14:Dominican Republic,15:Ecuador,16:El Salvador,17:France,18:Germany,19:Guatemala,20:Honduras,21:Hong Kong SAR,22:Ireland,23:Italy,24:Jamaica,25:Korea,26:Liechtenstein,27:Luxembourg,28:Mexico,29:Netherlands,30:New Zealand,31:Nicaragua,32:Panama,33:Paraguay,34:Peru,35:Portugal,36:Peoples Republic of China,37:Puerto Rico,38:Russia,39:Singapore,40:South Africa,41:Spain,42:Sweden,43:Switzerland,44:Taiwan,45:Trinidad,46:United Kingdom,47:United States,48:Uruguay,49:Venezuela. # Prefs for show - includeInGlobal (bool): Default value true - enableBIFGeneration (bool): Default value true - flattenSeasons (int): Default value 0 Possible option: 0:Show,1:Hide - episodeSort (int): Default value -1 Possible option: 0:Oldest first,1:Newest first + agent (str): com.plexapp.agents.none, com.plexapp.agents.thetvdb, com.plexapp.agents.themoviedb + enableBIFGeneration (bool): Enable video preview thumbnails. Default value true . + episodeSort (int): Episode order. Default value -1 Possible options: 0:Oldest first,1:Newest first. + flattenSeasons (int): Seasons. Default value 0 Possible options: 0:Show,1:Hide. + includeInGlobal (bool): Include in dashboard. Default value true . + scanner (str): Plex Series Scanner + + # show com.plexapp.agents.thetvdb settings options + extras (bool): Find trailers and extras automatically (Plex Pass required). Default value true . + native_subs (bool): Include extras with subtitles in Library language. Default value false . + + # show com.plexapp.agents.themoviedb settings + collections (bool): Use collection info from The Movie Database. Default value false . + localart (bool): Prefer artwork based on library language. Default value true . + adult (bool): Include adult content. Default value false . + country (int): Country (used for release date and content rating). Default value 47 Possible options: 0:,1:Argentina,2:Australia,3:Austria,4:Belgium,5:Belize,6:Bolivia,7:Brazil,8:Canada,9:Chile,10:Colombia,11:Costa Rica,12:Czech Republic,13:Denmark,14:Dominican Republic,15:Ecuador,16:El Salvador,17:France,18:Germany,19:Guatemala,20:Honduras,21:Hong Kong SAR,22:Ireland,23:Italy,24:Jamaica,25:Korea,26:Liechtenstein,27:Luxembourg,28:Mexico,29:Netherlands,30:New Zealand,31:Nicaragua,32:Panama,33:Paraguay,34:Peru,35:Portugal,36:Peoples Republic of China,37:Puerto Rico,38:Russia,39:Singapore,40:South Africa,41:Spain,42:Sweden,43:Switzerland,44:Taiwan,45:Trinidad,46:United Kingdom,47:United States,48:Uruguay,49:Venezuela. - # Prefs for season - includeInGlobal (bool): Default value true """ - # Should this function be here or in server?? part = '/library/sections?name=%s&type=%s&agent=%s&scanner=%s&language=%s&location=%s' % ( quote_plus(name), type, agent, quote_plus(scanner), language, quote_plus(location)) # noqa E126 From 421dcd7bcf831cf9e62c5904fd32174f504ff9af Mon Sep 17 00:00:00 2001 From: Hellowlol Date: Mon, 6 Mar 2017 23:18:10 +0100 Subject: [PATCH 9/9] Add share. works missing docs --- plexapi/library.py | 42 +++++++++++++++++++++++++++++++++++------- plexapi/server.py | 8 ++++++-- 2 files changed, 41 insertions(+), 9 deletions(-) diff --git a/plexapi/library.py b/plexapi/library.py index cbeaae75..aef3fec3 100644 --- a/plexapi/library.py +++ b/plexapi/library.py @@ -245,10 +245,6 @@ class Library(PlexObject): part += urlencode(kwargs) return self._server.query(part, method=self._server._session.post) - def share(self, user, *args, **kwargs): - """Share this library with the user.""" - pass - class LibrarySection(PlexObject): """ Base class for a single library section. @@ -415,6 +411,38 @@ class LibrarySection(PlexObject): key = '/library/sections/%s/%s%s' % (self.key, category, utils.joinArgs(args)) return self.fetchItems(key, cls=FilterChoice) + def share(self, user, **kwargs): + """Share this library with the user. + + user (str): username as a string or :class:`~plexapi.myplex.MyPlexUser` + kwargs (dict): Shared settings should be passed as kwargs. + """ + # So im not really sure where is belongs but it works. still need docs for kwargs. + + # Allow passing a User + if isinstance(user, type): + user = user.username + + # Grab the section ids, note this is NOT the same as the regular that the library has. + uri = 'https://plex.tv/api/servers/%s?X-Plex-Token=%s' % (self._server.machineIdentifier, self._server._token) + server = self._server.query(uri) + library_section_ids = [section.attrib.get('id') for section in server + if section.attrib.get('title') == self.title] + + cmd = {'shared_id': self._server.machineIdentifier, + 'shared_server': {'library_section_ids': library_section_ids, + 'invited_email': user}, + 'sharing_settings': kwargs # empty means none + + } + + # Json content type seems to be req. + h = {"Content-Type": "application/json"} + + share_uri = 'https://plex.tv/api/servers/%s/shared_servers?X-Plex-Token=%s' % ( + self._server.machineIdentifier, self._server._token) + r = self._server._session.post(share_uri, json=cmd, headers=h) + def search(self, title=None, sort=None, maxresults=999999, libtype=None, **kwargs): """ Search the library. If there are many results, they will be fetched from the server in batches of X_PLEX_CONTAINER_SIZE amounts. If you're only looking for the first @@ -518,9 +546,9 @@ class MovieSection(LibrarySection): TYPE (str): 'movie' """ ALLOWED_FILTERS = ('unwatched', 'duplicate', 'year', 'decade', 'genre', 'contentRating', - 'collection', 'director', 'actor', 'country', 'studio', 'resolution') + 'collection', 'director', 'actor', 'country', 'studio', 'resolution') ALLOWED_SORT = ('addedAt', 'originallyAvailableAt', 'lastViewedAt', 'titleSort', 'rating', - 'mediaHeight', 'duration') + 'mediaHeight', 'duration') TAG = 'Directory' TYPE = 'movie' @@ -538,7 +566,7 @@ class ShowSection(LibrarySection): """ ALLOWED_FILTERS = ('unwatched', 'year', 'genre', 'contentRating', 'network', 'collection') ALLOWED_SORT = ('addedAt', 'lastViewedAt', 'originallyAvailableAt', 'titleSort', - 'rating', 'unwatched') + 'rating', 'unwatched') TAG = 'Directory' TYPE = 'show' diff --git a/plexapi/server.py b/plexapi/server.py index 2f94cb31..ab13bcc8 100644 --- a/plexapi/server.py +++ b/plexapi/server.py @@ -265,7 +265,11 @@ class PlexServer(PlexObject): by encoding the response to utf-8 and parsing the returned XML into and ElementTree object. Returns None if no data exists in the response. """ - url = self.url(key) + if not key.startswith('http'): + url = self.url(key) + else: + url = key + method = method or self._session.get log.debug('%s %s', method.__name__.upper(), url) headers = self._headers(**headers or {}) @@ -349,7 +353,7 @@ class PlexServer(PlexObject): delim = '&' if '?' in key else '?' return '%s%s%sX-Plex-Token=%s' % (self._baseurl, key, delim, self._token) return '%s%s' % (self._baseurl, key) - + class Account(PlexObject): """ Contains the locally cached MyPlex account information. The properties provided don't