Add voice activity analysis (#1466)

* Add hasVoiceActivity attribute to Media

* Update tests for voice activity analysis

* Fix movie year test

* Add canAutoSync attribute to SubtitleStream
This commit is contained in:
JonnyWong16 2024-09-22 11:51:57 -07:00 committed by GitHub
parent 23ffc01756
commit 19582eb649
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 20 additions and 1 deletions

View file

@ -26,6 +26,7 @@ class Media(PlexObject):
height (int): The height of the media in pixels (ex: 256).
id (int): The unique ID for this media on the server.
has64bitOffsets (bool): True if video has 64 bit offsets.
hasVoiceActivity (bool): True if video has voice activity analyzed.
optimizedForStreaming (bool): True if video is optimized for streaming.
parts (List<:class:`~plexapi.media.MediaPart`>): List of media part objects.
proxyType (int): Equals 42 for optimized versions.
@ -61,6 +62,7 @@ class Media(PlexObject):
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.hasVoiceActivity = utils.cast(bool, data.attrib.get('hasVoiceActivity', '0'))
self.optimizedForStreaming = utils.cast(bool, data.attrib.get('optimizedForStreaming'))
self.parts = self.findItems(data, MediaPart)
self.proxyType = utils.cast(int, data.attrib.get('proxyType'))
@ -441,6 +443,7 @@ class SubtitleStream(MediaPartStream):
Attributes:
TAG (str): 'Stream'
STREAMTYPE (int): 3
canAutoSync (bool): True if the subtitle stream can be auto synced.
container (str): The container of the subtitle stream.
forced (bool): True if this is a forced subtitle.
format (str): The format of the subtitle stream (ex: srt).
@ -459,6 +462,7 @@ class SubtitleStream(MediaPartStream):
def _loadData(self, data):
""" Load attribute values from Plex XML response. """
super(SubtitleStream, self)._loadData(data)
self.canAutoSync = utils.cast(bool, data.attrib.get('canAutoSync'))
self.container = data.attrib.get('container')
self.forced = utils.cast(bool, data.attrib.get('forced', '0'))
self.format = data.attrib.get('format')

View file

@ -447,6 +447,11 @@ class Movie(
""" Returns True if the movie has a credits marker. """
return any(marker.type == 'credits' for marker in self.markers)
@property
def hasVoiceActivity(self):
""" Returns True if any of the media has voice activity analyzed. """
return any(media.hasVoiceActivity for media in self.media)
@property
def hasPreviewThumbnails(self):
""" Returns True if any of the media parts has generated preview (BIF) thumbnails. """
@ -1077,6 +1082,11 @@ class Episode(
""" Returns True if the episode has a credits marker. """
return any(marker.type == 'credits' for marker in self.markers)
@property
def hasVoiceActivity(self):
""" Returns True if any of the media has voice activity analyzed. """
return any(media.hasVoiceActivity for media in self.media)
@property
def hasPreviewThumbnails(self):
""" Returns True if any of the media parts has generated preview (BIF) thumbnails. """

View file

@ -77,6 +77,7 @@ def test_video_Movie_attrs(movies):
assert "Animation" in [i.tag for i in movie.genres]
assert "imdb://tt1172203" in [i.id for i in movie.guids]
assert movie.guid == "plex://movie/5d776846880197001ec967c6"
assert movie.hasVoiceActivity is False
assert movie.hasPreviewThumbnails is False
assert utils.is_metadata(movie._initpath)
assert utils.is_metadata(movie.key)
@ -108,7 +109,7 @@ def test_video_Movie_attrs(movies):
assert movie.userRating is None
assert movie.viewCount == 0
assert utils.is_int(movie.viewOffset, gte=0)
assert movie.year == 2009
assert movie.year >= 2008
# Audio
audio = movie.media[0].parts[0].audioStreams()[0]
if audio.audioChannelLayout:
@ -150,6 +151,7 @@ def test_video_Movie_attrs(movies):
assert utils.is_int(media.id)
assert utils.is_metadata(media._initpath)
assert media.has64bitOffsets is False
assert media.hasVoiceActivity is False
assert media.optimizedForStreaming in [None, False, True]
assert media.proxyType is None
assert media._server._baseurl == utils.SERVER_BASEURL
@ -1223,6 +1225,7 @@ def test_video_Episode_attrs(episode):
assert episode.grandparentTitle == "Game of Thrones"
assert episode.guid == "plex://episode/5d9c1275e98e47001eb84029"
assert "tvdb://3254641" in [i.id for i in episode.guids]
assert episode.hasVoiceActivity is False
assert episode.hasPreviewThumbnails is False
assert episode.index == 1
assert episode.episodeNumber == episode.index
@ -1279,6 +1282,7 @@ def test_video_Episode_attrs(episode):
assert media.container in utils.CONTAINERS
assert utils.is_int(media.duration, gte=150000)
assert utils.is_int(media.height, gte=200)
assert media.hasVoiceActivity is False
assert utils.is_int(media.id)
assert utils.is_metadata(media._initpath)
if media.optimizedForStreaming:

View file

@ -504,6 +504,7 @@ if __name__ == "__main__": # noqa: C901
if not opts.unclaimed and account and account.subscriptionActive:
server.settings.get("GenerateIntroMarkerBehavior").set("never")
server.settings.get("GenerateCreditsMarkerBehavior").set("never")
server.settings.get("GenerateVADBehavior").set("never")
server.settings.get("MusicAnalysisBehavior").set("never")
server.settings.get("GenerateBIFBehavior").set("never")
server.settings.get("GenerateChapterThumbBehavior").set("never")