From 3fc69a370960ddee2e6e5e550bee4fd6b07b9e49 Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Mon, 24 May 2021 17:28:11 -0700 Subject: [PATCH 1/5] Refactor usage of findItems --- plexapi/audio.py | 6 +----- plexapi/base.py | 5 ++++- plexapi/collection.py | 6 +----- plexapi/library.py | 10 +++------- plexapi/mixins.py | 9 +-------- plexapi/myplex.py | 8 +------- plexapi/settings.py | 2 +- plexapi/video.py | 22 ++++------------------ 8 files changed, 16 insertions(+), 52 deletions(-) diff --git a/plexapi/audio.py b/plexapi/audio.py index 25ac659b1..0013e632a 100644 --- a/plexapi/audio.py +++ b/plexapi/audio.py @@ -154,11 +154,7 @@ def __iter__(self): def hubs(self): """ Returns a list of :class:`~plexapi.library.Hub` objects. """ data = self._server.query(self._details_key) - directory = data.find('Directory') - if directory: - related = directory.find('Related') - if related: - return self.findItems(related, library.Hub) + return self.findItems(data, library.Hub, rtag='Related') def album(self, title): """ Returns the :class:`~plexapi.audio.Album` that matches the specified title. diff --git a/plexapi/base.py b/plexapi/base.py index 060c7d906..990226acc 100644 --- a/plexapi/base.py +++ b/plexapi/base.py @@ -263,7 +263,7 @@ def fetchItems(self, ekey, cls=None, container_start=None, container_size=None, item.librarySectionID = librarySectionID return items - def findItems(self, data, cls=None, initpath=None, **kwargs): + def findItems(self, data, cls=None, initpath=None, rtag=None, **kwargs): """ Load the specified data to find and build all items with the specified tag and attrs. See :func:`~plexapi.base.PlexObject.fetchItem` for more details on how this is used. @@ -273,6 +273,9 @@ def findItems(self, data, cls=None, initpath=None, **kwargs): kwargs['etag'] = cls.TAG if cls and cls.TYPE and 'type' not in kwargs: kwargs['type'] = cls.TYPE + # rtag to iter on a specific root tag + if rtag: + data = next(data.iter(rtag), []) # loop through all data elements to find matches items = [] for elem in data: diff --git a/plexapi/collection.py b/plexapi/collection.py index de4c165df..470cd6241 100644 --- a/plexapi/collection.py +++ b/plexapi/collection.py @@ -110,12 +110,8 @@ def __len__(self): def _preferences(self): """ Returns a list of :class:`~plexapi.settings.Preferences` objects. """ - items = [] data = self._server.query(self._details_key) - for item in data.iter('Setting'): - items.append(Setting(data=item, server=self._server)) - - return items + return self.findItems(data, Setting, rtag='Preferences') def modeUpdate(self, mode=None): """ Update Collection Mode diff --git a/plexapi/library.py b/plexapi/library.py index b262c2856..bc99a9db2 100644 --- a/plexapi/library.py +++ b/plexapi/library.py @@ -603,17 +603,13 @@ def _loadFilters(self): key = _key % (self.key, 'all') data = self._server.query(key) - meta = data.find('Meta') - if meta: - self._filterTypes = self.findItems(meta, FilteringType) - self._fieldTypes = self.findItems(meta, FilteringFieldType) + self._filterTypes = self.findItems(data, FilteringType, rtag='Meta') + self._fieldTypes = self.findItems(data, FilteringFieldType, rtag='Meta') if self.TYPE != 'photo': # No collections for photo library key = _key % (self.key, 'collections') data = self._server.query(key) - meta = data.find('Meta') - if meta: - self._filterTypes.extend(self.findItems(meta, FilteringType)) + self._filterTypes.extend(self.findItems(data, FilteringType, rtag='Meta')) def filterTypes(self): """ Returns a list of available :class:`~plexapi.library.FilteringType` for this library section. """ diff --git a/plexapi/mixins.py b/plexapi/mixins.py index 05d1f40fa..9ca01cf63 100644 --- a/plexapi/mixins.py +++ b/plexapi/mixins.py @@ -10,15 +10,8 @@ class AdvancedSettingsMixin(object): def preferences(self): """ Returns a list of :class:`~plexapi.settings.Preferences` objects. """ - items = [] data = self._server.query(self._details_key) - for item in data.iter('Preferences'): - for elem in item: - setting = settings.Preferences(data=elem, server=self._server) - setting._initpath = self.key - items.append(setting) - - return items + return self.findItems(data, settings.Preferences, rtag='Preferences') def preference(self, pref): """ Returns a :class:`~plexapi.settings.Preferences` object for the specified pref. diff --git a/plexapi/myplex.py b/plexapi/myplex.py index ffce9a1fb..42f597791 100644 --- a/plexapi/myplex.py +++ b/plexapi/myplex.py @@ -885,13 +885,7 @@ def sections(self): """ url = MyPlexAccount.FRIENDSERVERS.format(machineId=self.machineIdentifier, serverId=self.id) data = self._server.query(url) - sections = [] - - for section in data.iter('Section'): - if ElementTree.iselement(section): - sections.append(Section(self, section, url)) - - return sections + return self.findItems(data, Section, rtag='SharedServer') def history(self, maxresults=9999999, mindate=None): """ Get all Play History for a user in this shared server. diff --git a/plexapi/settings.py b/plexapi/settings.py index 734cc1198..0b14d2074 100644 --- a/plexapi/settings.py +++ b/plexapi/settings.py @@ -167,7 +167,7 @@ class Preferences(Setting): TAG (str): 'Preferences' FILTER (str): 'preferences' """ - TAG = 'Preferences' + TAG = 'Setting' FILTER = 'preferences' def _default(self): diff --git a/plexapi/video.py b/plexapi/video.py index 141e29150..51ac94fa3 100644 --- a/plexapi/video.py +++ b/plexapi/video.py @@ -353,11 +353,7 @@ def _prettyfilename(self): def hubs(self): """ Returns a list of :class:`~plexapi.library.Hub` objects. """ data = self._server.query(self._details_key) - video = data.find('Video') - if video: - related = video.find('Related') - if related: - return self.findItems(related, library.Hub) + return self.findItems(data, library.Hub, rtag='Related') def download(self, savepath=None, keep_original_name=False, **kwargs): """ Download video files to specified directory. @@ -498,21 +494,14 @@ def isWatched(self): def hubs(self): """ Returns a list of :class:`~plexapi.library.Hub` objects. """ data = self._server.query(self._details_key) - directory = data.find('Directory') - if directory: - related = directory.find('Related') - if related: - return self.findItems(related, library.Hub) + return self.findItems(data, library.Hub, rtag='Related') def onDeck(self): """ Returns show's On Deck :class:`~plexapi.video.Video` object or `None`. If show is unwatched, return will likely be the first episode. """ data = self._server.query(self._details_key) - episode = next(data.iter('OnDeck'), None) - if episode: - return self.findItems(episode)[0] - return None + return next(iter(self.findItems(data, rtag='OnDeck')), None) def season(self, title=None, season=None): """ Returns the season with the specified title or number. @@ -692,10 +681,7 @@ def onDeck(self): Will only return a match if the show's On Deck episode is in this season. """ data = self._server.query(self._details_key) - episode = next(data.iter('OnDeck'), None) - if episode: - return self.findItems(episode)[0] - return None + return next(iter(self.findItems(data, rtag='OnDeck')), None) def show(self): """ Return the season's :class:`~plexapi.video.Show`. """ From f81456d3b638d60f1f58bc3168fcfa63f1190e54 Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Mon, 24 May 2021 17:37:37 -0700 Subject: [PATCH 2/5] Refactor usage of listAttrs --- plexapi/myplex.py | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/plexapi/myplex.py b/plexapi/myplex.py index 42f597791..d1944b513 100644 --- a/plexapi/myplex.py +++ b/plexapi/myplex.py @@ -128,26 +128,18 @@ def _loadData(self, data): self.title = data.attrib.get('title') self.username = data.attrib.get('username') self.uuid = data.attrib.get('uuid') - subscription = data.find('subscription') + subscription = data.find('subscription') self.subscriptionActive = utils.cast(bool, subscription.attrib.get('active')) self.subscriptionStatus = subscription.attrib.get('status') self.subscriptionPlan = subscription.attrib.get('plan') - - self.subscriptionFeatures = [] - for feature in subscription.iter('feature'): - self.subscriptionFeatures.append(feature.attrib.get('id')) + self.subscriptionFeatures = self.listAttrs(subscription, 'id', etag='feature') roles = data.find('roles') - self.roles = [] - if roles is not None: - for role in roles.iter('role'): - self.roles.append(role.attrib.get('id')) + self.roles = self.listAttrs(roles, 'id', etag='role') entitlements = data.find('entitlements') - self.entitlements = [] - for entitlement in entitlements.iter('entitlement'): - self.entitlements.append(entitlement.attrib.get('id')) + self.entitlements = self.listAttrs(entitlements, 'id', etag='entitlement') # TODO: Fetch missing MyPlexAccount attributes self.profile_settings = None @@ -1070,7 +1062,7 @@ def _loadData(self, data): self.screenDensity = data.attrib.get('screenDensity') self.createdAt = utils.toDatetime(data.attrib.get('createdAt')) self.lastSeenAt = utils.toDatetime(data.attrib.get('lastSeenAt')) - self.connections = [connection.attrib.get('uri') for connection in data.iter('Connection')] + self.connections = self.listAttrs(data, 'uri', etag='Connection') def connect(self, timeout=None): """ Returns a new :class:`~plexapi.client.PlexClient` or :class:`~plexapi.server.PlexServer` From 6726a64e6406439a71755075c6654494a18c143b Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Mon, 24 May 2021 19:36:26 -0700 Subject: [PATCH 3/5] Fix settings.Preferences doc string TAG --- plexapi/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plexapi/settings.py b/plexapi/settings.py index 0b14d2074..30c1c583c 100644 --- a/plexapi/settings.py +++ b/plexapi/settings.py @@ -164,7 +164,7 @@ class Preferences(Setting): """ Represents a single Preferences. Attributes: - TAG (str): 'Preferences' + TAG (str): 'Setting' FILTER (str): 'preferences' """ TAG = 'Setting' From 0095e83f75659ff3fba6326bbba9f2dbd08e3440 Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Wed, 26 May 2021 19:45:12 -0700 Subject: [PATCH 4/5] Cleanup utils imports --- plexapi/base.py | 5 +- plexapi/media.py | 181 ++++++++++++++++++++++---------------------- plexapi/myplex.py | 3 +- plexapi/playlist.py | 17 ++--- plexapi/server.py | 90 +++++++++++----------- 5 files changed, 146 insertions(+), 150 deletions(-) diff --git a/plexapi/base.py b/plexapi/base.py index 990226acc..7cb5acbf3 100644 --- a/plexapi/base.py +++ b/plexapi/base.py @@ -6,7 +6,6 @@ from plexapi import log, utils from plexapi.exceptions import BadRequest, NotFound, UnknownType, Unsupported -from plexapi.utils import tag_plural, tag_helper DONT_RELOAD_FOR_KEYS = {'key', 'session'} DONT_OVERWRITE_SESSION_KEYS = {'usernames', 'players', 'transcodeSessions', 'session'} @@ -524,9 +523,9 @@ def _edit_tags(self, tag, items, locked=True, remove=False): """ if not isinstance(items, list): items = [items] - value = getattr(self, tag_plural(tag)) + value = getattr(self, utils.tag_plural(tag)) existing_tags = [t.tag for t in value if t and remove is False] - tag_edits = tag_helper(tag, existing_tags + items, locked, remove) + tag_edits = utils.tag_helper(tag, existing_tags + items, locked, remove) self.edit(**tag_edits) def refresh(self): diff --git a/plexapi/media.py b/plexapi/media.py index 88313e47a..37c1cb7a3 100644 --- a/plexapi/media.py +++ b/plexapi/media.py @@ -6,7 +6,6 @@ from plexapi import log, settings, utils from plexapi.base import PlexObject from plexapi.exceptions import BadRequest -from plexapi.utils import cast @utils.registerPlexObject @@ -51,31 +50,31 @@ class Media(PlexObject): def _loadData(self, data): """ Load attribute values from Plex XML response. """ self._data = data - self.aspectRatio = cast(float, data.attrib.get('aspectRatio')) - self.audioChannels = cast(int, data.attrib.get('audioChannels')) + self.aspectRatio = utils.cast(float, data.attrib.get('aspectRatio')) + self.audioChannels = utils.cast(int, data.attrib.get('audioChannels')) self.audioCodec = data.attrib.get('audioCodec') self.audioProfile = data.attrib.get('audioProfile') - self.bitrate = cast(int, data.attrib.get('bitrate')) + self.bitrate = utils.cast(int, data.attrib.get('bitrate')) self.container = data.attrib.get('container') - self.duration = cast(int, data.attrib.get('duration')) - self.height = cast(int, data.attrib.get('height')) - self.id = cast(int, data.attrib.get('id')) - self.has64bitOffsets = cast(bool, data.attrib.get('has64bitOffsets')) - self.optimizedForStreaming = cast(bool, data.attrib.get('optimizedForStreaming')) + self.duration = utils.cast(int, data.attrib.get('duration')) + self.height = utils.cast(int, data.attrib.get('height')) + self.id = utils.cast(int, data.attrib.get('id')) + self.has64bitOffsets = utils.cast(bool, data.attrib.get('has64bitOffsets')) + self.optimizedForStreaming = utils.cast(bool, data.attrib.get('optimizedForStreaming')) self.parts = self.findItems(data, MediaPart) - self.proxyType = cast(int, data.attrib.get('proxyType')) + self.proxyType = utils.cast(int, data.attrib.get('proxyType')) self.target = data.attrib.get('target') self.title = data.attrib.get('title') self.videoCodec = data.attrib.get('videoCodec') self.videoFrameRate = data.attrib.get('videoFrameRate') self.videoProfile = data.attrib.get('videoProfile') self.videoResolution = data.attrib.get('videoResolution') - self.width = cast(int, data.attrib.get('width')) + self.width = utils.cast(int, data.attrib.get('width')) if self._isChildOf(etag='Photo'): self.aperture = data.attrib.get('aperture') self.exposure = data.attrib.get('exposure') - self.iso = cast(int, data.attrib.get('iso')) + self.iso = utils.cast(int, data.attrib.get('iso')) self.lens = data.attrib.get('lens') self.make = data.attrib.get('make') self.model = data.attrib.get('model') @@ -128,25 +127,25 @@ class MediaPart(PlexObject): def _loadData(self, data): """ Load attribute values from Plex XML response. """ self._data = data - self.accessible = cast(bool, data.attrib.get('accessible')) + self.accessible = utils.cast(bool, data.attrib.get('accessible')) self.audioProfile = data.attrib.get('audioProfile') self.container = data.attrib.get('container') self.decision = data.attrib.get('decision') - self.deepAnalysisVersion = cast(int, data.attrib.get('deepAnalysisVersion')) - self.duration = cast(int, data.attrib.get('duration')) - self.exists = cast(bool, data.attrib.get('exists')) + self.deepAnalysisVersion = utils.cast(int, data.attrib.get('deepAnalysisVersion')) + self.duration = utils.cast(int, data.attrib.get('duration')) + self.exists = utils.cast(bool, data.attrib.get('exists')) self.file = data.attrib.get('file') - self.has64bitOffsets = cast(bool, data.attrib.get('has64bitOffsets')) - self.hasThumbnail = cast(bool, data.attrib.get('hasThumbnail')) - self.id = cast(int, data.attrib.get('id')) + self.has64bitOffsets = utils.cast(bool, data.attrib.get('has64bitOffsets')) + self.hasThumbnail = utils.cast(bool, data.attrib.get('hasThumbnail')) + self.id = utils.cast(int, data.attrib.get('id')) self.indexes = data.attrib.get('indexes') self.key = data.attrib.get('key') - self.optimizedForStreaming = cast(bool, data.attrib.get('optimizedForStreaming')) - self.packetLength = cast(int, data.attrib.get('packetLength')) + self.optimizedForStreaming = utils.cast(bool, data.attrib.get('optimizedForStreaming')) + self.packetLength = utils.cast(int, data.attrib.get('packetLength')) self.requiredBandwidths = data.attrib.get('requiredBandwidths') - self.size = cast(int, data.attrib.get('size')) + self.size = utils.cast(int, data.attrib.get('size')) self.streams = self._buildStreams(data) - self.syncItemId = cast(int, data.attrib.get('syncItemId')) + self.syncItemId = utils.cast(int, data.attrib.get('syncItemId')) self.syncState = data.attrib.get('syncState') self.videoProfile = data.attrib.get('videoProfile') @@ -233,21 +232,21 @@ class MediaPartStream(PlexObject): def _loadData(self, data): """ Load attribute values from Plex XML response. """ self._data = data - self.bitrate = cast(int, data.attrib.get('bitrate')) + self.bitrate = utils.cast(int, data.attrib.get('bitrate')) self.codec = data.attrib.get('codec') - self.default = cast(bool, data.attrib.get('default')) + self.default = utils.cast(bool, data.attrib.get('default')) self.displayTitle = data.attrib.get('displayTitle') self.extendedDisplayTitle = data.attrib.get('extendedDisplayTitle') self.key = data.attrib.get('key') - self.id = cast(int, data.attrib.get('id')) - self.index = cast(int, data.attrib.get('index', '-1')) + self.id = utils.cast(int, data.attrib.get('id')) + self.index = utils.cast(int, data.attrib.get('index', '-1')) self.language = data.attrib.get('language') self.languageCode = data.attrib.get('languageCode') self.requiredBandwidths = data.attrib.get('requiredBandwidths') - self.selected = cast(bool, data.attrib.get('selected', '0')) - self.streamType = cast(int, data.attrib.get('streamType')) + self.selected = utils.cast(bool, data.attrib.get('selected', '0')) + self.streamType = utils.cast(int, data.attrib.get('streamType')) self.title = data.attrib.get('title') - self.type = cast(int, data.attrib.get('streamType')) + self.type = utils.cast(int, data.attrib.get('streamType')) @utils.registerPlexObject @@ -298,38 +297,38 @@ def _loadData(self, data): """ Load attribute values from Plex XML response. """ super(VideoStream, self)._loadData(data) self.anamorphic = data.attrib.get('anamorphic') - self.bitDepth = cast(int, data.attrib.get('bitDepth')) - self.cabac = cast(int, data.attrib.get('cabac')) + self.bitDepth = utils.cast(int, data.attrib.get('bitDepth')) + self.cabac = utils.cast(int, data.attrib.get('cabac')) self.chromaLocation = data.attrib.get('chromaLocation') self.chromaSubsampling = data.attrib.get('chromaSubsampling') self.codecID = data.attrib.get('codecID') - self.codedHeight = cast(int, data.attrib.get('codedHeight')) - self.codedWidth = cast(int, data.attrib.get('codedWidth')) + self.codedHeight = utils.cast(int, data.attrib.get('codedHeight')) + self.codedWidth = utils.cast(int, data.attrib.get('codedWidth')) self.colorPrimaries = data.attrib.get('colorPrimaries') self.colorRange = data.attrib.get('colorRange') self.colorSpace = data.attrib.get('colorSpace') self.colorTrc = data.attrib.get('colorTrc') - self.DOVIBLCompatID = cast(int, data.attrib.get('DOVIBLCompatID')) - self.DOVIBLPresent = cast(bool, data.attrib.get('DOVIBLPresent')) - self.DOVIELPresent = cast(bool, data.attrib.get('DOVIELPresent')) - self.DOVILevel = cast(int, data.attrib.get('DOVILevel')) - self.DOVIPresent = cast(bool, data.attrib.get('DOVIPresent')) - self.DOVIProfile = cast(int, data.attrib.get('DOVIProfile')) - self.DOVIRPUPresent = cast(bool, data.attrib.get('DOVIRPUPresent')) - self.DOVIVersion = cast(float, data.attrib.get('DOVIVersion')) - self.duration = cast(int, data.attrib.get('duration')) - self.frameRate = cast(float, data.attrib.get('frameRate')) + self.DOVIBLCompatID = utils.cast(int, data.attrib.get('DOVIBLCompatID')) + self.DOVIBLPresent = utils.cast(bool, data.attrib.get('DOVIBLPresent')) + self.DOVIELPresent = utils.cast(bool, data.attrib.get('DOVIELPresent')) + self.DOVILevel = utils.cast(int, data.attrib.get('DOVILevel')) + self.DOVIPresent = utils.cast(bool, data.attrib.get('DOVIPresent')) + self.DOVIProfile = utils.cast(int, data.attrib.get('DOVIProfile')) + self.DOVIRPUPresent = utils.cast(bool, data.attrib.get('DOVIRPUPresent')) + self.DOVIVersion = utils.cast(float, data.attrib.get('DOVIVersion')) + self.duration = utils.cast(int, data.attrib.get('duration')) + self.frameRate = utils.cast(float, data.attrib.get('frameRate')) self.frameRateMode = data.attrib.get('frameRateMode') - self.hasScallingMatrix = cast(bool, data.attrib.get('hasScallingMatrix')) - self.height = cast(int, data.attrib.get('height')) - self.level = cast(int, data.attrib.get('level')) + self.hasScallingMatrix = utils.cast(bool, data.attrib.get('hasScallingMatrix')) + self.height = utils.cast(int, data.attrib.get('height')) + self.level = utils.cast(int, data.attrib.get('level')) self.profile = data.attrib.get('profile') self.pixelAspectRatio = data.attrib.get('pixelAspectRatio') self.pixelFormat = data.attrib.get('pixelFormat') - self.refFrames = cast(int, data.attrib.get('refFrames')) + self.refFrames = utils.cast(int, data.attrib.get('refFrames')) self.scanType = data.attrib.get('scanType') - self.streamIdentifier = cast(int, data.attrib.get('streamIdentifier')) - self.width = cast(int, data.attrib.get('width')) + self.streamIdentifier = utils.cast(int, data.attrib.get('streamIdentifier')) + self.width = utils.cast(int, data.attrib.get('width')) @utils.registerPlexObject @@ -367,23 +366,23 @@ def _loadData(self, data): """ Load attribute values from Plex XML response. """ super(AudioStream, self)._loadData(data) self.audioChannelLayout = data.attrib.get('audioChannelLayout') - self.bitDepth = cast(int, data.attrib.get('bitDepth')) + self.bitDepth = utils.cast(int, data.attrib.get('bitDepth')) self.bitrateMode = data.attrib.get('bitrateMode') - self.channels = cast(int, data.attrib.get('channels')) - self.duration = cast(int, data.attrib.get('duration')) + self.channels = utils.cast(int, data.attrib.get('channels')) + self.duration = utils.cast(int, data.attrib.get('duration')) self.profile = data.attrib.get('profile') - self.samplingRate = cast(int, data.attrib.get('samplingRate')) - self.streamIdentifier = cast(int, data.attrib.get('streamIdentifier')) + self.samplingRate = utils.cast(int, data.attrib.get('samplingRate')) + self.streamIdentifier = utils.cast(int, data.attrib.get('streamIdentifier')) if self._isChildOf(etag='Track'): - self.albumGain = cast(float, data.attrib.get('albumGain')) - self.albumPeak = cast(float, data.attrib.get('albumPeak')) - self.albumRange = cast(float, data.attrib.get('albumRange')) + self.albumGain = utils.cast(float, data.attrib.get('albumGain')) + self.albumPeak = utils.cast(float, data.attrib.get('albumPeak')) + self.albumRange = utils.cast(float, data.attrib.get('albumRange')) self.endRamp = data.attrib.get('endRamp') - self.gain = cast(float, data.attrib.get('gain')) - self.loudness = cast(float, data.attrib.get('loudness')) - self.lra = cast(float, data.attrib.get('lra')) - self.peak = cast(float, data.attrib.get('peak')) + self.gain = utils.cast(float, data.attrib.get('gain')) + self.loudness = utils.cast(float, data.attrib.get('loudness')) + self.lra = utils.cast(float, data.attrib.get('lra')) + self.peak = utils.cast(float, data.attrib.get('peak')) self.startRamp = data.attrib.get('startRamp') @@ -407,7 +406,7 @@ def _loadData(self, data): """ Load attribute values from Plex XML response. """ super(SubtitleStream, self)._loadData(data) self.container = data.attrib.get('container') - self.forced = cast(bool, data.attrib.get('forced', '0')) + self.forced = utils.cast(bool, data.attrib.get('forced', '0')) self.format = data.attrib.get('format') self.headerCompression = data.attrib.get('headerCompression') self.transient = data.attrib.get('transient') @@ -431,9 +430,9 @@ def _loadData(self, data): """ Load attribute values from Plex XML response. """ super(LyricStream, self)._loadData(data) self.format = data.attrib.get('format') - self.minLines = cast(int, data.attrib.get('minLines')) + self.minLines = utils.cast(int, data.attrib.get('minLines')) self.provider = data.attrib.get('provider') - self.timed = cast(bool, data.attrib.get('timed', '0')) + self.timed = utils.cast(bool, data.attrib.get('timed', '0')) @utils.registerPlexObject @@ -496,36 +495,36 @@ class TranscodeSession(PlexObject): def _loadData(self, data): """ Load attribute values from Plex XML response. """ self._data = data - self.audioChannels = cast(int, data.attrib.get('audioChannels')) + self.audioChannels = utils.cast(int, data.attrib.get('audioChannels')) self.audioCodec = data.attrib.get('audioCodec') self.audioDecision = data.attrib.get('audioDecision') - self.complete = cast(bool, data.attrib.get('complete', '0')) + self.complete = utils.cast(bool, data.attrib.get('complete', '0')) self.container = data.attrib.get('container') self.context = data.attrib.get('context') - self.duration = cast(int, data.attrib.get('duration')) - self.height = cast(int, data.attrib.get('height')) + self.duration = utils.cast(int, data.attrib.get('duration')) + self.height = utils.cast(int, data.attrib.get('height')) self.key = data.attrib.get('key') - self.maxOffsetAvailable = cast(float, data.attrib.get('maxOffsetAvailable')) - self.minOffsetAvailable = cast(float, data.attrib.get('minOffsetAvailable')) - self.progress = cast(float, data.attrib.get('progress')) + self.maxOffsetAvailable = utils.cast(float, data.attrib.get('maxOffsetAvailable')) + self.minOffsetAvailable = utils.cast(float, data.attrib.get('minOffsetAvailable')) + self.progress = utils.cast(float, data.attrib.get('progress')) self.protocol = data.attrib.get('protocol') - self.remaining = cast(int, data.attrib.get('remaining')) - self.size = cast(int, data.attrib.get('size')) + self.remaining = utils.cast(int, data.attrib.get('remaining')) + self.size = utils.cast(int, data.attrib.get('size')) self.sourceAudioCodec = data.attrib.get('sourceAudioCodec') self.sourceVideoCodec = data.attrib.get('sourceVideoCodec') - self.speed = cast(float, data.attrib.get('speed')) + self.speed = utils.cast(float, data.attrib.get('speed')) self.subtitleDecision = data.attrib.get('subtitleDecision') - self.throttled = cast(bool, data.attrib.get('throttled', '0')) - self.timestamp = cast(float, data.attrib.get('timeStamp')) + self.throttled = utils.cast(bool, data.attrib.get('throttled', '0')) + self.timestamp = utils.cast(float, data.attrib.get('timeStamp')) self.transcodeHwDecoding = data.attrib.get('transcodeHwDecoding') self.transcodeHwDecodingTitle = data.attrib.get('transcodeHwDecodingTitle') self.transcodeHwEncoding = data.attrib.get('transcodeHwEncoding') self.transcodeHwEncodingTitle = data.attrib.get('transcodeHwEncodingTitle') - self.transcodeHwFullPipeline = cast(bool, data.attrib.get('transcodeHwFullPipeline', '0')) - self.transcodeHwRequested = cast(bool, data.attrib.get('transcodeHwRequested', '0')) + self.transcodeHwFullPipeline = utils.cast(bool, data.attrib.get('transcodeHwFullPipeline', '0')) + self.transcodeHwRequested = utils.cast(bool, data.attrib.get('transcodeHwRequested', '0')) self.videoCodec = data.attrib.get('videoCodec') self.videoDecision = data.attrib.get('videoDecision') - self.width = cast(int, data.attrib.get('width')) + self.width = utils.cast(int, data.attrib.get('width')) @utils.registerPlexObject @@ -666,7 +665,7 @@ def _loadData(self, data): """ Load attribute values from Plex XML response. """ self._data = data self.filter = data.attrib.get('filter') - self.id = cast(int, data.attrib.get('id')) + self.id = utils.cast(int, data.attrib.get('id')) self.key = data.attrib.get('key') self.role = data.attrib.get('role') self.tag = data.attrib.get('tag') @@ -881,7 +880,7 @@ def _loadData(self, data): self.key = data.attrib.get('key') self.provider = data.attrib.get('provider') self.ratingKey = data.attrib.get('ratingKey') - self.selected = cast(bool, data.attrib.get('selected')) + self.selected = utils.cast(bool, data.attrib.get('selected')) self.thumb = data.attrib.get('thumb') def select(self): @@ -916,13 +915,13 @@ class Chapter(PlexObject): def _loadData(self, data): self._data = data - self.id = cast(int, data.attrib.get('id', 0)) + self.id = utils.cast(int, data.attrib.get('id', 0)) self.filter = data.attrib.get('filter') # I couldn't filter on it anyways self.tag = data.attrib.get('tag') self.title = self.tag - self.index = cast(int, data.attrib.get('index')) - self.start = cast(int, data.attrib.get('startTimeOffset')) - self.end = cast(int, data.attrib.get('endTimeOffset')) + self.index = utils.cast(int, data.attrib.get('index')) + self.start = utils.cast(int, data.attrib.get('startTimeOffset')) + self.end = utils.cast(int, data.attrib.get('endTimeOffset')) @utils.registerPlexObject @@ -943,8 +942,8 @@ def __repr__(self): def _loadData(self, data): self._data = data self.type = data.attrib.get('type') - self.start = cast(int, data.attrib.get('startTimeOffset')) - self.end = cast(int, data.attrib.get('endTimeOffset')) + self.start = utils.cast(int, data.attrib.get('startTimeOffset')) + self.end = utils.cast(int, data.attrib.get('endTimeOffset')) @utils.registerPlexObject @@ -959,7 +958,7 @@ class Field(PlexObject): def _loadData(self, data): self._data = data self.name = data.attrib.get('name') - self.locked = cast(bool, data.attrib.get('locked')) + self.locked = utils.cast(bool, data.attrib.get('locked')) @utils.registerPlexObject @@ -981,7 +980,7 @@ def _loadData(self, data): self.guid = data.attrib.get('guid') self.lifespanEnded = data.attrib.get('lifespanEnded') self.name = data.attrib.get('name') - self.score = cast(int, data.attrib.get('score')) + self.score = utils.cast(int, data.attrib.get('score')) self.year = data.attrib.get('year') @@ -1026,7 +1025,7 @@ def __repr__(self): return '<%s>' % ':'.join([p for p in [self.__class__.__name__, uid] if p]) def _loadData(self, data): - self.mediaType = cast(int, data.attrib.get('mediaType')) + self.mediaType = utils.cast(int, data.attrib.get('mediaType')) self.name = data.attrib.get('name') self.languageCode = [] for code in data: diff --git a/plexapi/myplex.py b/plexapi/myplex.py index d1944b513..d2d4ec37d 100644 --- a/plexapi/myplex.py +++ b/plexapi/myplex.py @@ -14,7 +14,6 @@ from plexapi.server import PlexServer from plexapi.sonos import PlexSonosClient from plexapi.sync import SyncItem, SyncList -from plexapi.utils import joinArgs from requests.status_codes import _codes as codes @@ -452,7 +451,7 @@ def updateFriend(self, user, server, sections=None, removeSections=False, allowS if isinstance(allowChannels, dict): params['filterMusic'] = self._filterDictToStr(filterMusic or {}) if params: - url += joinArgs(params) + url += utils.joinArgs(params) response_filters = self.query(url, self._session.put) return response_servers, response_filters diff --git a/plexapi/playlist.py b/plexapi/playlist.py index 7e6f10b1f..16bec0b18 100644 --- a/plexapi/playlist.py +++ b/plexapi/playlist.py @@ -7,7 +7,6 @@ from plexapi.library import LibrarySection from plexapi.mixins import ArtMixin, PosterMixin from plexapi.playqueue import PlayQueue -from plexapi.utils import cast, toDatetime @utils.registerPlexObject @@ -39,21 +38,21 @@ class Playlist(PlexPartialObject, Playable, ArtMixin, PosterMixin): def _loadData(self, data): """ Load attribute values from Plex XML response. """ Playable._loadData(self, data) - self.addedAt = toDatetime(data.attrib.get('addedAt')) - self.allowSync = cast(bool, data.attrib.get('allowSync')) + self.addedAt = utils.toDatetime(data.attrib.get('addedAt')) + self.allowSync = utils.cast(bool, data.attrib.get('allowSync')) self.composite = data.attrib.get('composite') # url to thumbnail - self.duration = cast(int, data.attrib.get('duration')) - self.durationInSeconds = cast(int, data.attrib.get('durationInSeconds')) + self.duration = utils.cast(int, data.attrib.get('duration')) + self.durationInSeconds = utils.cast(int, data.attrib.get('durationInSeconds')) self.guid = data.attrib.get('guid') self.key = data.attrib.get('key', '').replace('/items', '') # FIX_BUG_50 - self.leafCount = cast(int, data.attrib.get('leafCount')) + self.leafCount = utils.cast(int, data.attrib.get('leafCount')) self.playlistType = data.attrib.get('playlistType') - self.ratingKey = cast(int, data.attrib.get('ratingKey')) - self.smart = cast(bool, data.attrib.get('smart')) + self.ratingKey = utils.cast(int, data.attrib.get('ratingKey')) + self.smart = utils.cast(bool, data.attrib.get('smart')) self.summary = data.attrib.get('summary') self.title = data.attrib.get('title') self.type = data.attrib.get('type') - self.updatedAt = toDatetime(data.attrib.get('updatedAt')) + self.updatedAt = utils.toDatetime(data.attrib.get('updatedAt')) self._items = None # cache for self.items def __len__(self): # pragma: no cover diff --git a/plexapi/server.py b/plexapi/server.py index 3c6d63f5a..4923a52d7 100644 --- a/plexapi/server.py +++ b/plexapi/server.py @@ -15,7 +15,7 @@ from plexapi.playlist import Playlist from plexapi.playqueue import PlayQueue from plexapi.settings import Settings -from plexapi.utils import cast, deprecated +from plexapi.utils import deprecated from requests.status_codes import _codes as codes # Need these imports to populate utils.PLEXOBJECTS @@ -118,47 +118,47 @@ def __init__(self, baseurl=None, token=None, session=None, timeout=None): def _loadData(self, data): """ Load attribute values from Plex XML response. """ self._data = data - self.allowCameraUpload = cast(bool, data.attrib.get('allowCameraUpload')) - self.allowChannelAccess = cast(bool, data.attrib.get('allowChannelAccess')) - self.allowMediaDeletion = cast(bool, data.attrib.get('allowMediaDeletion')) - self.allowSharing = cast(bool, data.attrib.get('allowSharing')) - self.allowSync = cast(bool, data.attrib.get('allowSync')) - self.backgroundProcessing = cast(bool, data.attrib.get('backgroundProcessing')) - self.certificate = cast(bool, data.attrib.get('certificate')) - self.companionProxy = cast(bool, data.attrib.get('companionProxy')) + self.allowCameraUpload = utils.cast(bool, data.attrib.get('allowCameraUpload')) + self.allowChannelAccess = utils.cast(bool, data.attrib.get('allowChannelAccess')) + self.allowMediaDeletion = utils.cast(bool, data.attrib.get('allowMediaDeletion')) + self.allowSharing = utils.cast(bool, data.attrib.get('allowSharing')) + self.allowSync = utils.cast(bool, data.attrib.get('allowSync')) + self.backgroundProcessing = utils.cast(bool, data.attrib.get('backgroundProcessing')) + self.certificate = utils.cast(bool, data.attrib.get('certificate')) + self.companionProxy = utils.cast(bool, data.attrib.get('companionProxy')) self.diagnostics = utils.toList(data.attrib.get('diagnostics')) - self.eventStream = cast(bool, data.attrib.get('eventStream')) + self.eventStream = utils.cast(bool, data.attrib.get('eventStream')) self.friendlyName = data.attrib.get('friendlyName') - self.hubSearch = cast(bool, data.attrib.get('hubSearch')) + self.hubSearch = utils.cast(bool, data.attrib.get('hubSearch')) self.machineIdentifier = data.attrib.get('machineIdentifier') - self.multiuser = cast(bool, data.attrib.get('multiuser')) - self.myPlex = cast(bool, data.attrib.get('myPlex')) + self.multiuser = utils.cast(bool, data.attrib.get('multiuser')) + self.myPlex = utils.cast(bool, data.attrib.get('myPlex')) self.myPlexMappingState = data.attrib.get('myPlexMappingState') self.myPlexSigninState = data.attrib.get('myPlexSigninState') - self.myPlexSubscription = cast(bool, data.attrib.get('myPlexSubscription')) + self.myPlexSubscription = utils.cast(bool, data.attrib.get('myPlexSubscription')) self.myPlexUsername = data.attrib.get('myPlexUsername') self.ownerFeatures = utils.toList(data.attrib.get('ownerFeatures')) - self.photoAutoTag = cast(bool, data.attrib.get('photoAutoTag')) + self.photoAutoTag = utils.cast(bool, data.attrib.get('photoAutoTag')) self.platform = data.attrib.get('platform') self.platformVersion = data.attrib.get('platformVersion') - self.pluginHost = cast(bool, data.attrib.get('pluginHost')) - self.readOnlyLibraries = cast(int, data.attrib.get('readOnlyLibraries')) - self.requestParametersInCookie = cast(bool, data.attrib.get('requestParametersInCookie')) + self.pluginHost = utils.cast(bool, data.attrib.get('pluginHost')) + self.readOnlyLibraries = utils.cast(int, data.attrib.get('readOnlyLibraries')) + self.requestParametersInCookie = utils.cast(bool, data.attrib.get('requestParametersInCookie')) self.streamingBrainVersion = data.attrib.get('streamingBrainVersion') - self.sync = cast(bool, data.attrib.get('sync')) + self.sync = utils.cast(bool, data.attrib.get('sync')) self.transcoderActiveVideoSessions = int(data.attrib.get('transcoderActiveVideoSessions', 0)) - self.transcoderAudio = cast(bool, data.attrib.get('transcoderAudio')) - self.transcoderLyrics = cast(bool, data.attrib.get('transcoderLyrics')) - self.transcoderPhoto = cast(bool, data.attrib.get('transcoderPhoto')) - self.transcoderSubtitles = cast(bool, data.attrib.get('transcoderSubtitles')) - self.transcoderVideo = cast(bool, data.attrib.get('transcoderVideo')) + self.transcoderAudio = utils.cast(bool, data.attrib.get('transcoderAudio')) + self.transcoderLyrics = utils.cast(bool, data.attrib.get('transcoderLyrics')) + self.transcoderPhoto = utils.cast(bool, data.attrib.get('transcoderPhoto')) + self.transcoderSubtitles = utils.cast(bool, data.attrib.get('transcoderSubtitles')) + self.transcoderVideo = utils.cast(bool, data.attrib.get('transcoderVideo')) self.transcoderVideoBitrates = utils.toList(data.attrib.get('transcoderVideoBitrates')) self.transcoderVideoQualities = utils.toList(data.attrib.get('transcoderVideoQualities')) self.transcoderVideoResolutions = utils.toList(data.attrib.get('transcoderVideoResolutions')) self.updatedAt = utils.toDatetime(data.attrib.get('updatedAt')) - self.updater = cast(bool, data.attrib.get('updater')) + self.updater = utils.cast(bool, data.attrib.get('updater')) self.version = data.attrib.get('version') - self.voiceSearch = cast(bool, data.attrib.get('voiceSearch')) + self.voiceSearch = utils.cast(bool, data.attrib.get('voiceSearch')) def _headers(self, **kwargs): """ Returns dict containing base headers for all requests to the server. """ @@ -770,11 +770,11 @@ def bandwidth(self, timespan=None, **kwargs): raise BadRequest('Unknown filter: %s=%s' % (key, value)) if key.startswith('at'): try: - value = cast(int, value.timestamp()) + value = utils.cast(int, value.timestamp()) except AttributeError: raise BadRequest('Time frame filter must be a datetime object: %s=%s' % (key, value)) elif key.startswith('bytes') or key == 'lan': - value = cast(int, value) + value = utils.cast(int, value) elif key == 'accountID': if value == self.myPlexAccount().id: value = 1 # The admin account is accountID=1 @@ -834,7 +834,7 @@ def _loadData(self, data): self.privateAddress = data.attrib.get('privateAddress') self.privatePort = data.attrib.get('privatePort') self.subscriptionFeatures = utils.toList(data.attrib.get('subscriptionFeatures')) - self.subscriptionActive = cast(bool, data.attrib.get('subscriptionActive')) + self.subscriptionActive = utils.cast(bool, data.attrib.get('subscriptionActive')) self.subscriptionState = data.attrib.get('subscriptionState') @@ -844,8 +844,8 @@ class Activity(PlexObject): def _loadData(self, data): self._data = data - self.cancellable = cast(bool, data.attrib.get('cancellable')) - self.progress = cast(int, data.attrib.get('progress')) + self.cancellable = utils.cast(bool, data.attrib.get('cancellable')) + self.progress = utils.cast(int, data.attrib.get('progress')) self.title = data.attrib.get('title') self.subtitle = data.attrib.get('subtitle') self.type = data.attrib.get('type') @@ -884,13 +884,13 @@ class SystemAccount(PlexObject): def _loadData(self, data): self._data = data - self.autoSelectAudio = cast(bool, data.attrib.get('autoSelectAudio')) + self.autoSelectAudio = utils.cast(bool, data.attrib.get('autoSelectAudio')) self.defaultAudioLanguage = data.attrib.get('defaultAudioLanguage') self.defaultSubtitleLanguage = data.attrib.get('defaultSubtitleLanguage') - self.id = cast(int, data.attrib.get('id')) + self.id = utils.cast(int, data.attrib.get('id')) self.key = data.attrib.get('key') self.name = data.attrib.get('name') - self.subtitleMode = cast(int, data.attrib.get('subtitleMode')) + self.subtitleMode = utils.cast(int, data.attrib.get('subtitleMode')) self.thumb = data.attrib.get('thumb') # For backwards compatibility self.accountID = self.id @@ -915,7 +915,7 @@ def _loadData(self, data): self._data = data self.clientIdentifier = data.attrib.get('clientIdentifier') self.createdAt = utils.toDatetime(data.attrib.get('createdAt')) - self.id = cast(int, data.attrib.get('id')) + self.id = utils.cast(int, data.attrib.get('id')) self.key = '/devices/%s' % self.id self.name = data.attrib.get('name') self.platform = data.attrib.get('platform') @@ -939,12 +939,12 @@ class StatisticsBandwidth(PlexObject): def _loadData(self, data): self._data = data - self.accountID = cast(int, data.attrib.get('accountID')) + self.accountID = utils.cast(int, data.attrib.get('accountID')) self.at = utils.toDatetime(data.attrib.get('at')) - self.bytes = cast(int, data.attrib.get('bytes')) - self.deviceID = cast(int, data.attrib.get('deviceID')) - self.lan = cast(bool, data.attrib.get('lan')) - self.timespan = cast(int, data.attrib.get('timespan')) + self.bytes = utils.cast(int, data.attrib.get('bytes')) + self.deviceID = utils.cast(int, data.attrib.get('deviceID')) + self.lan = utils.cast(bool, data.attrib.get('lan')) + self.timespan = utils.cast(int, data.attrib.get('timespan')) def __repr__(self): return '<%s>' % ':'.join([p for p in [ @@ -980,11 +980,11 @@ class StatisticsResources(PlexObject): def _loadData(self, data): self._data = data self.at = utils.toDatetime(data.attrib.get('at')) - self.hostCpuUtilization = cast(float, data.attrib.get('hostCpuUtilization')) - self.hostMemoryUtilization = cast(float, data.attrib.get('hostMemoryUtilization')) - self.processCpuUtilization = cast(float, data.attrib.get('processCpuUtilization')) - self.processMemoryUtilization = cast(float, data.attrib.get('processMemoryUtilization')) - self.timespan = cast(int, data.attrib.get('timespan')) + self.hostCpuUtilization = utils.cast(float, data.attrib.get('hostCpuUtilization')) + self.hostMemoryUtilization = utils.cast(float, data.attrib.get('hostMemoryUtilization')) + self.processCpuUtilization = utils.cast(float, data.attrib.get('processCpuUtilization')) + self.processMemoryUtilization = utils.cast(float, data.attrib.get('processMemoryUtilization')) + self.timespan = utils.cast(int, data.attrib.get('timespan')) def __repr__(self): return '<%s>' % ':'.join([p for p in [ From 64488371129a32efd9fe55434dc4a7818ebbebc4 Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Sun, 6 Jun 2021 14:54:15 -0700 Subject: [PATCH 5/5] Fix return typo in doc strings --- plexapi/audio.py | 2 +- plexapi/base.py | 2 +- plexapi/photo.py | 2 +- plexapi/video.py | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/plexapi/audio.py b/plexapi/audio.py index a92b85596..bb1dee225 100644 --- a/plexapi/audio.py +++ b/plexapi/audio.py @@ -402,7 +402,7 @@ def locations(self): """ This does not exist in plex xml response but is added to have a common interface to get the locations of the track. - Retruns: + Returns: List of file paths where the track is found on disk. """ return [part.file for part in self.iterParts() if part] diff --git a/plexapi/base.py b/plexapi/base.py index d3e8b515a..fa823fa7b 100644 --- a/plexapi/base.py +++ b/plexapi/base.py @@ -480,7 +480,7 @@ def analyze(self): self._server.query(key, method=self._server._session.put) def isFullObject(self): - """ Retruns True if this is already a full object. A full object means all attributes + """ Returns True if this is already a full object. A full object means all attributes were populated from the api path representing only this item. For example, the search result for a movie often only contain a portion of the attributes a full object (main url) for that movie would contain. diff --git a/plexapi/photo.py b/plexapi/photo.py index ad8e0706b..f3196663b 100644 --- a/plexapi/photo.py +++ b/plexapi/photo.py @@ -232,7 +232,7 @@ def locations(self): """ This does not exist in plex xml response but is added to have a common interface to get the locations of the photo. - Retruns: + Returns: List of file paths where the photo is found on disk. """ return [part.file for item in self.media for part in item.parts if part] diff --git a/plexapi/video.py b/plexapi/video.py index 0955b4749..8c2ee8eb4 100644 --- a/plexapi/video.py +++ b/plexapi/video.py @@ -328,7 +328,7 @@ def locations(self): """ This does not exist in plex xml response but is added to have a common interface to get the locations of the movie. - Retruns: + Returns: List of file paths where the movie is found on disk. """ return [part.file for part in self.iterParts() if part] @@ -815,7 +815,7 @@ def locations(self): """ This does not exist in plex xml response but is added to have a common interface to get the locations of the episode. - Retruns: + Returns: List of file paths where the episode is found on disk. """ return [part.file for part in self.iterParts() if part] @@ -904,7 +904,7 @@ def locations(self): """ This does not exist in plex xml response but is added to have a common interface to get the locations of the clip. - Retruns: + Returns: List of file paths where the clip is found on disk. """ return [part.file for part in self.iterParts() if part]