diff --git a/plexapi/media.py b/plexapi/media.py index c1530959..718b5b7c 100644 --- a/plexapi/media.py +++ b/plexapi/media.py @@ -433,6 +433,17 @@ def setSelected(self): """ return self._parent().setSelectedAudioStream(self) + def levels(self, subSample=128): + """ Returns a list of :class:`~plexapi.media.Level` objects for this AudioStream. + Only available for Tracks which have been analyzed for loudness. + + Attributes: + subSample (int): The number of loudness samples to return. Default 128. + """ + key = f'/library/streams/{self.id}/levels' + params = {'subsample': subSample} + return self.fetchItems(key, params=params) + @deprecated('Use "setSelected" instead.') def setDefault(self): return self.setSelected() @@ -1343,3 +1354,15 @@ def _loadData(self, data): self.quality = data.attrib.get('quality') self.title = data.attrib.get('title') self.url = data.attrib.get('url') + + +@utils.registerPlexObject +class Level(PlexObject): + """ Represents a single loudness Level sample for an AudioStream. + + Attributes: + loudness (float): Loudness level value + """ + def _loadData(self, data): + """ Load attribute values from Plex XML response. """ + self.loudness = utils.cast(float, data.attrib.get('v')) diff --git a/tests/test_audio.py b/tests/test_audio.py index b73f2ba1..43f941d3 100644 --- a/tests/test_audio.py +++ b/tests/test_audio.py @@ -397,6 +397,8 @@ def test_audio_Track_attrs(album): assert stream.lra is None assert stream.peak is None assert stream.startRamp is None + if stream.loudness is not None: + assert len(stream.levels(subSample=32)) == 32 def test_audio_Track_album(album):