Add support for credit markers (#1094)

* Add credit markers

* Disable credit detection in bootstrap test server

* Add `first` property for credits markers

* Add credits detection setting attribute

* Update tests for credits detection setting
This commit is contained in:
JonnyWong16 2023-03-09 13:32:17 -08:00 committed by GitHub
parent 6350e85ff9
commit 1e220eb311
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 36 additions and 2 deletions

View file

@ -1037,9 +1037,11 @@ class Marker(PlexObject):
Attributes:
TAG (str): 'Marker'
end (int): The end time of the marker in milliseconds.
final (bool): True if the marker is the final credits marker.
id (int): The ID of the marker.
type (str): The type of marker.
start (int): The start time of the marker in milliseconds.
version (int): The Plex marker version.
"""
TAG = 'Marker'
@ -1053,10 +1055,25 @@ class Marker(PlexObject):
def _loadData(self, data):
self._data = data
self.end = utils.cast(int, data.attrib.get('endTimeOffset'))
self.final = utils.cast(bool, data.attrib.get('final'))
self.id = utils.cast(int, data.attrib.get('id'))
self.type = data.attrib.get('type')
self.start = utils.cast(int, data.attrib.get('startTimeOffset'))
attributes = data.find('Attributes')
self.version = attributes.attrib.get('version')
@property
def first(self):
""" Returns True if the marker in the first credits marker. """
if self.type != 'credits':
return None
first = min(
(marker for marker in self._parent().markers if marker.type == 'credits'),
key=lambda m: m.start
)
return first == self
@utils.registerPlexObject
class Field(PlexObject):

View file

@ -311,6 +311,7 @@ class Movie(
directors (List<:class:`~plexapi.media.Director`>): List of director objects.
duration (int): Duration of the movie in milliseconds.
editionTitle (str): The edition title of the movie (e.g. Director's Cut, Extended Edition, etc.).
enableCreditsMarkerGeneration (int): Setting that indicates if credits markers detection is enabled.
genres (List<:class:`~plexapi.media.Genre`>): List of genre objects.
guids (List<:class:`~plexapi.media.Guid`>): List of guid objects.
labels (List<:class:`~plexapi.media.Label`>): List of label objects.
@ -353,6 +354,7 @@ class Movie(
self.directors = self.findItems(data, media.Director)
self.duration = utils.cast(int, data.attrib.get('duration'))
self.editionTitle = data.attrib.get('editionTitle')
self.enableCreditsMarkerGeneration = utils.cast(int, data.attrib.get('enableCreditsMarkerGeneration', '-1'))
self.genres = self.findItems(data, media.Genre)
self.guids = self.findItems(data, media.Guid)
self.labels = self.findItems(data, media.Label)
@ -390,6 +392,11 @@ class Movie(
"""
return [part.file for part in self.iterParts() if part]
@property
def hasCreditsMarker(self):
""" Returns True if the movie has a credits marker. """
return any(marker.type == 'credits' for marker in self.markers)
@property
def hasPreviewThumbnails(self):
""" Returns True if any of the media parts has generated preview (BIF) thumbnails. """
@ -444,6 +451,7 @@ class Show(
collections (List<:class:`~plexapi.media.Collection`>): List of collection objects.
contentRating (str) Content rating (PG-13; NR; TV-G).
duration (int): Typical duration of the show episodes in milliseconds.
enableCreditsMarkerGeneration (int): Setting that indicates if credits markers detection is enabled.
episodeSort (int): Setting that indicates how episodes are sorted for the show
(-1 = Library default, 0 = Oldest first, 1 = Newest first).
flattenSeasons (int): Setting that indicates if seasons are set to hidden for the show
@ -493,6 +501,7 @@ class Show(
self.collections = self.findItems(data, media.Collection)
self.contentRating = data.attrib.get('contentRating')
self.duration = utils.cast(int, data.attrib.get('duration'))
self.enableCreditsMarkerGeneration = utils.cast(int, data.attrib.get('enableCreditsMarkerGeneration', '-1'))
self.episodeSort = utils.cast(int, data.attrib.get('episodeSort', '-1'))
self.flattenSeasons = utils.cast(int, data.attrib.get('flattenSeasons', '-1'))
self.genres = self.findItems(data, media.Genre)
@ -920,14 +929,19 @@ class Episode(
@property
def hasCommercialMarker(self):
""" Returns True if the episode has a commercial marker in the xml. """
""" Returns True if the episode has a commercial marker. """
return any(marker.type == 'commercial' for marker in self.markers)
@property
def hasIntroMarker(self):
""" Returns True if the episode has an intro marker in the xml. """
""" Returns True if the episode has an intro marker. """
return any(marker.type == 'intro' for marker in self.markers)
@property
def hasCreditsMarker(self):
""" Returns True if the episode has a credits marker. """
return any(marker.type == 'credits' for marker in self.markers)
@property
def hasPreviewThumbnails(self):
""" Returns True if any of the media parts has generated preview (BIF) thumbnails. """

View file

@ -59,6 +59,7 @@ def test_video_Movie_attrs(movies):
assert not movie.collections
assert movie.contentRating in utils.CONTENTRATINGS
assert movie.editionTitle is None
assert movie.enableCreditsMarkerGeneration == -1
if movie.countries:
assert "United States of America" in [i.tag for i in movie.countries]
if movie.producers:
@ -724,6 +725,7 @@ def test_video_Show_attrs(show):
assert show.audienceRatingImage == "themoviedb://image.rating"
assert show.autoDeletionItemPolicyUnwatchedLibrary == 0
assert show.autoDeletionItemPolicyWatchedLibrary == 0
assert show.enableCreditsMarkerGeneration == -1
assert show.episodeSort == -1
assert show.flattenSeasons == -1
assert "Drama" in [i.tag for i in show.genres]

View file

@ -502,6 +502,7 @@ if __name__ == "__main__":
# These tasks won't work on the test server since we are using fake media files
if not opts.unclaimed and account and account.subscriptionActive:
server.settings.get("GenerateIntroMarkerBehavior").set("never")
server.settings.get("GenerateCreditsMarkerBehavior").set("never")
server.settings.get("GenerateBIFBehavior").set("never")
server.settings.get("GenerateChapterThumbBehavior").set("never")
server.settings.get("LoudnessAnalysisBehavior").set("never")