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

View file

@ -447,6 +447,11 @@ class Movie(
""" Returns True if the movie has a credits marker. """ """ Returns True if the movie has a credits marker. """
return any(marker.type == 'credits' for marker in self.markers) 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 @property
def hasPreviewThumbnails(self): def hasPreviewThumbnails(self):
""" Returns True if any of the media parts has generated preview (BIF) thumbnails. """ """ 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. """ """ Returns True if the episode has a credits marker. """
return any(marker.type == 'credits' for marker in self.markers) 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 @property
def hasPreviewThumbnails(self): def hasPreviewThumbnails(self):
""" Returns True if any of the media parts has generated preview (BIF) thumbnails. """ """ 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 "Animation" in [i.tag for i in movie.genres]
assert "imdb://tt1172203" in [i.id for i in movie.guids] assert "imdb://tt1172203" in [i.id for i in movie.guids]
assert movie.guid == "plex://movie/5d776846880197001ec967c6" assert movie.guid == "plex://movie/5d776846880197001ec967c6"
assert movie.hasVoiceActivity is False
assert movie.hasPreviewThumbnails is False assert movie.hasPreviewThumbnails is False
assert utils.is_metadata(movie._initpath) assert utils.is_metadata(movie._initpath)
assert utils.is_metadata(movie.key) assert utils.is_metadata(movie.key)
@ -108,7 +109,7 @@ def test_video_Movie_attrs(movies):
assert movie.userRating is None assert movie.userRating is None
assert movie.viewCount == 0 assert movie.viewCount == 0
assert utils.is_int(movie.viewOffset, gte=0) assert utils.is_int(movie.viewOffset, gte=0)
assert movie.year == 2009 assert movie.year >= 2008
# Audio # Audio
audio = movie.media[0].parts[0].audioStreams()[0] audio = movie.media[0].parts[0].audioStreams()[0]
if audio.audioChannelLayout: if audio.audioChannelLayout:
@ -150,6 +151,7 @@ def test_video_Movie_attrs(movies):
assert utils.is_int(media.id) assert utils.is_int(media.id)
assert utils.is_metadata(media._initpath) assert utils.is_metadata(media._initpath)
assert media.has64bitOffsets is False assert media.has64bitOffsets is False
assert media.hasVoiceActivity is False
assert media.optimizedForStreaming in [None, False, True] assert media.optimizedForStreaming in [None, False, True]
assert media.proxyType is None assert media.proxyType is None
assert media._server._baseurl == utils.SERVER_BASEURL 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.grandparentTitle == "Game of Thrones"
assert episode.guid == "plex://episode/5d9c1275e98e47001eb84029" assert episode.guid == "plex://episode/5d9c1275e98e47001eb84029"
assert "tvdb://3254641" in [i.id for i in episode.guids] assert "tvdb://3254641" in [i.id for i in episode.guids]
assert episode.hasVoiceActivity is False
assert episode.hasPreviewThumbnails is False assert episode.hasPreviewThumbnails is False
assert episode.index == 1 assert episode.index == 1
assert episode.episodeNumber == episode.index assert episode.episodeNumber == episode.index
@ -1279,6 +1282,7 @@ def test_video_Episode_attrs(episode):
assert media.container in utils.CONTAINERS assert media.container in utils.CONTAINERS
assert utils.is_int(media.duration, gte=150000) assert utils.is_int(media.duration, gte=150000)
assert utils.is_int(media.height, gte=200) assert utils.is_int(media.height, gte=200)
assert media.hasVoiceActivity is False
assert utils.is_int(media.id) assert utils.is_int(media.id)
assert utils.is_metadata(media._initpath) assert utils.is_metadata(media._initpath)
if media.optimizedForStreaming: if media.optimizedForStreaming:

View file

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