mirror of
https://github.com/pkkid/python-plexapi
synced 2024-11-22 03:33:08 +00:00
Add support for editing audience ratings and critic ratings (#1417)
* Add support for editing audience ratings and critic ratings * Note: Not all types of ratings are supported/shown in the Plex UIs. However they can be edited/updated and stored in the Plex Media Server database. * Add tests for editing audience rating and critic rating
This commit is contained in:
parent
7b317ef822
commit
2142514955
8 changed files with 86 additions and 10 deletions
|
@ -181,6 +181,7 @@ class Artist(
|
|||
TYPE (str): 'artist'
|
||||
albumSort (int): Setting that indicates how albums are sorted for the artist
|
||||
(-1 = Library default, 0 = Newest first, 1 = Oldest first, 2 = By name).
|
||||
audienceRating (float): Audience rating.
|
||||
collections (List<:class:`~plexapi.media.Collection`>): List of collection objects.
|
||||
countries (List<:class:`~plexapi.media.Country`>): List country objects.
|
||||
genres (List<:class:`~plexapi.media.Genre`>): List of genre objects.
|
||||
|
@ -188,6 +189,7 @@ class Artist(
|
|||
key (str): API URL (/library/metadata/<ratingkey>).
|
||||
labels (List<:class:`~plexapi.media.Label`>): List of label objects.
|
||||
locations (List<str>): List of folder paths where the artist is found on disk.
|
||||
rating (float): Artist rating (7.9; 9.8; 8.1).
|
||||
similar (List<:class:`~plexapi.media.Similar`>): List of similar objects.
|
||||
styles (List<:class:`~plexapi.media.Style`>): List of style objects.
|
||||
theme (str): URL to theme resource (/library/metadata/<ratingkey>/theme/<themeid>).
|
||||
|
@ -199,6 +201,7 @@ class Artist(
|
|||
""" Load attribute values from Plex XML response. """
|
||||
Audio._loadData(self, data)
|
||||
self.albumSort = utils.cast(int, data.attrib.get('albumSort', '-1'))
|
||||
self.audienceRating = utils.cast(float, data.attrib.get('audienceRating'))
|
||||
self.collections = self.findItems(data, media.Collection)
|
||||
self.countries = self.findItems(data, media.Country)
|
||||
self.genres = self.findItems(data, media.Genre)
|
||||
|
@ -206,6 +209,7 @@ class Artist(
|
|||
self.key = self.key.replace('/children', '') # FIX_BUG_50
|
||||
self.labels = self.findItems(data, media.Label)
|
||||
self.locations = self.listAttrs(data, 'path', etag='Location')
|
||||
self.rating = utils.cast(float, data.attrib.get('rating'))
|
||||
self.similar = self.findItems(data, media.Similar)
|
||||
self.styles = self.findItems(data, media.Style)
|
||||
self.theme = data.attrib.get('theme')
|
||||
|
@ -301,6 +305,7 @@ class Album(
|
|||
Attributes:
|
||||
TAG (str): 'Directory'
|
||||
TYPE (str): 'album'
|
||||
audienceRating (float): Audience rating.
|
||||
collections (List<:class:`~plexapi.media.Collection`>): List of collection objects.
|
||||
formats (List<:class:`~plexapi.media.Format`>): List of format objects.
|
||||
genres (List<:class:`~plexapi.media.Genre`>): List of genre objects.
|
||||
|
@ -329,6 +334,7 @@ class Album(
|
|||
def _loadData(self, data):
|
||||
""" Load attribute values from Plex XML response. """
|
||||
Audio._loadData(self, data)
|
||||
self.audienceRating = utils.cast(float, data.attrib.get('audienceRating'))
|
||||
self.collections = self.findItems(data, media.Collection)
|
||||
self.formats = self.findItems(data, media.Format)
|
||||
self.genres = self.findItems(data, media.Genre)
|
||||
|
@ -426,6 +432,7 @@ class Track(
|
|||
Attributes:
|
||||
TAG (str): 'Directory'
|
||||
TYPE (str): 'track'
|
||||
audienceRating (float): Audience rating.
|
||||
chapters (List<:class:`~plexapi.media.Chapter`>): List of Chapter objects.
|
||||
chapterSource (str): Unknown
|
||||
collections (List<:class:`~plexapi.media.Collection`>): List of collection objects.
|
||||
|
@ -451,6 +458,7 @@ class Track(
|
|||
parentThumb (str): URL to album thumbnail image (/library/metadata/<parentRatingKey>/thumb/<thumbid>).
|
||||
parentTitle (str): Name of the album for the track.
|
||||
primaryExtraKey (str) API URL for the primary extra for the track.
|
||||
rating (float): Track rating (7.9; 9.8; 8.1).
|
||||
ratingCount (int): Number of listeners who have scrobbled this track, as reported by Last.fm.
|
||||
skipCount (int): Number of times the track has been skipped.
|
||||
sourceURI (str): Remote server URI (server://<machineIdentifier>/com.plexapp.plugins.library)
|
||||
|
@ -465,6 +473,7 @@ class Track(
|
|||
""" Load attribute values from Plex XML response. """
|
||||
Audio._loadData(self, data)
|
||||
Playable._loadData(self, data)
|
||||
self.audienceRating = utils.cast(float, data.attrib.get('audienceRating'))
|
||||
self.chapters = self.findItems(data, media.Chapter)
|
||||
self.chapterSource = data.attrib.get('chapterSource')
|
||||
self.collections = self.findItems(data, media.Collection)
|
||||
|
@ -488,6 +497,7 @@ class Track(
|
|||
self.parentThumb = data.attrib.get('parentThumb')
|
||||
self.parentTitle = data.attrib.get('parentTitle')
|
||||
self.primaryExtraKey = data.attrib.get('primaryExtraKey')
|
||||
self.rating = utils.cast(float, data.attrib.get('rating'))
|
||||
self.ratingCount = utils.cast(int, data.attrib.get('ratingCount'))
|
||||
self.skipCount = utils.cast(int, data.attrib.get('skipCount'))
|
||||
self.sourceURI = data.attrib.get('source') # remote playlist item
|
||||
|
|
|
@ -29,6 +29,7 @@ class Collection(
|
|||
addedAt (datetime): Datetime the collection was added to the library.
|
||||
art (str): URL to artwork image (/library/metadata/<ratingKey>/art/<artid>).
|
||||
artBlurHash (str): BlurHash string for artwork image.
|
||||
audienceRating (float): Audience rating.
|
||||
childCount (int): Number of items in the collection.
|
||||
collectionFilterBasedOnUser (int): Which user's activity is used for the collection filtering.
|
||||
collectionMode (int): How the items in the collection are displayed.
|
||||
|
@ -47,6 +48,7 @@ class Collection(
|
|||
librarySectionTitle (str): :class:`~plexapi.library.LibrarySection` title.
|
||||
maxYear (int): Maximum year for the items in the collection.
|
||||
minYear (int): Minimum year for the items in the collection.
|
||||
rating (float): Collection rating (7.9; 9.8; 8.1).
|
||||
ratingCount (int): The number of ratings.
|
||||
ratingKey (int): Unique key identifying the collection.
|
||||
smart (bool): True if the collection is a smart collection.
|
||||
|
@ -69,6 +71,7 @@ class Collection(
|
|||
self.addedAt = utils.toDatetime(data.attrib.get('addedAt'))
|
||||
self.art = data.attrib.get('art')
|
||||
self.artBlurHash = data.attrib.get('artBlurHash')
|
||||
self.audienceRating = utils.cast(float, data.attrib.get('audienceRating'))
|
||||
self.childCount = utils.cast(int, data.attrib.get('childCount'))
|
||||
self.collectionFilterBasedOnUser = utils.cast(int, data.attrib.get('collectionFilterBasedOnUser', '0'))
|
||||
self.collectionMode = utils.cast(int, data.attrib.get('collectionMode', '-1'))
|
||||
|
@ -87,6 +90,7 @@ class Collection(
|
|||
self.librarySectionTitle = data.attrib.get('librarySectionTitle')
|
||||
self.maxYear = utils.cast(int, data.attrib.get('maxYear'))
|
||||
self.minYear = utils.cast(int, data.attrib.get('minYear'))
|
||||
self.rating = utils.cast(float, data.attrib.get('rating'))
|
||||
self.ratingCount = utils.cast(int, data.attrib.get('ratingCount'))
|
||||
self.ratingKey = utils.cast(int, data.attrib.get('ratingKey'))
|
||||
self.smart = utils.cast(bool, data.attrib.get('smart', '0'))
|
||||
|
|
|
@ -567,6 +567,19 @@ class AddedAtMixin(EditFieldMixin):
|
|||
return self.editField('addedAt', addedAt, locked=locked)
|
||||
|
||||
|
||||
class AudienceRatingMixin(EditFieldMixin):
|
||||
""" Mixin for Plex objects that can have an audience rating. """
|
||||
|
||||
def editAudienceRating(self, audienceRating, locked=True):
|
||||
""" Edit the audience rating.
|
||||
|
||||
Parameters:
|
||||
audienceRating (float): The new value.
|
||||
locked (bool): True (default) to lock the field, False to unlock the field.
|
||||
"""
|
||||
return self.editField('audienceRating', audienceRating, locked=locked)
|
||||
|
||||
|
||||
class ContentRatingMixin(EditFieldMixin):
|
||||
""" Mixin for Plex objects that can have a content rating. """
|
||||
|
||||
|
@ -580,6 +593,19 @@ class ContentRatingMixin(EditFieldMixin):
|
|||
return self.editField('contentRating', contentRating, locked=locked)
|
||||
|
||||
|
||||
class CriticRatingMixin(EditFieldMixin):
|
||||
""" Mixin for Plex objects that can have a critic rating. """
|
||||
|
||||
def editCriticRating(self, criticRating, locked=True):
|
||||
""" Edit the critic rating.
|
||||
|
||||
Parameters:
|
||||
criticRating (float): The new value.
|
||||
locked (bool): True (default) to lock the field, False to unlock the field.
|
||||
"""
|
||||
return self.editField('rating', criticRating, locked=locked)
|
||||
|
||||
|
||||
class EditionTitleMixin(EditFieldMixin):
|
||||
""" Mixin for Plex objects that can have an edition title. """
|
||||
|
||||
|
@ -751,7 +777,7 @@ class UserRatingMixin(EditFieldMixin):
|
|||
""" Edit the user rating.
|
||||
|
||||
Parameters:
|
||||
userRating (int): The new value.
|
||||
userRating (float): The new value.
|
||||
locked (bool): True (default) to lock the field, False to unlock the field.
|
||||
"""
|
||||
return self.editField('userRating', userRating, locked=locked)
|
||||
|
@ -1145,7 +1171,8 @@ class WatchlistMixin:
|
|||
|
||||
class MovieEditMixins(
|
||||
ArtLockMixin, PosterLockMixin, ThemeLockMixin,
|
||||
AddedAtMixin, ContentRatingMixin, EditionTitleMixin, OriginallyAvailableMixin, OriginalTitleMixin, SortTitleMixin,
|
||||
AddedAtMixin, AudienceRatingMixin, ContentRatingMixin, CriticRatingMixin, EditionTitleMixin,
|
||||
OriginallyAvailableMixin, OriginalTitleMixin, SortTitleMixin,
|
||||
StudioMixin, SummaryMixin, TaglineMixin, TitleMixin, UserRatingMixin,
|
||||
CollectionMixin, CountryMixin, DirectorMixin, GenreMixin, LabelMixin, ProducerMixin, WriterMixin
|
||||
):
|
||||
|
@ -1154,7 +1181,8 @@ class MovieEditMixins(
|
|||
|
||||
class ShowEditMixins(
|
||||
ArtLockMixin, PosterLockMixin, ThemeLockMixin,
|
||||
AddedAtMixin, ContentRatingMixin, OriginallyAvailableMixin, OriginalTitleMixin, SortTitleMixin, StudioMixin,
|
||||
AddedAtMixin, AudienceRatingMixin, ContentRatingMixin, CriticRatingMixin,
|
||||
OriginallyAvailableMixin, OriginalTitleMixin, SortTitleMixin, StudioMixin,
|
||||
SummaryMixin, TaglineMixin, TitleMixin, UserRatingMixin,
|
||||
CollectionMixin, GenreMixin, LabelMixin,
|
||||
):
|
||||
|
@ -1163,7 +1191,8 @@ class ShowEditMixins(
|
|||
|
||||
class SeasonEditMixins(
|
||||
ArtLockMixin, PosterLockMixin, ThemeLockMixin,
|
||||
AddedAtMixin, SummaryMixin, TitleMixin, UserRatingMixin,
|
||||
AddedAtMixin, AudienceRatingMixin, CriticRatingMixin,
|
||||
SummaryMixin, TitleMixin, UserRatingMixin,
|
||||
CollectionMixin, LabelMixin
|
||||
):
|
||||
pass
|
||||
|
@ -1171,7 +1200,8 @@ class SeasonEditMixins(
|
|||
|
||||
class EpisodeEditMixins(
|
||||
ArtLockMixin, PosterLockMixin, ThemeLockMixin,
|
||||
AddedAtMixin, ContentRatingMixin, OriginallyAvailableMixin, SortTitleMixin, SummaryMixin, TitleMixin, UserRatingMixin,
|
||||
AddedAtMixin, AudienceRatingMixin, ContentRatingMixin, CriticRatingMixin,
|
||||
OriginallyAvailableMixin, SortTitleMixin, SummaryMixin, TitleMixin, UserRatingMixin,
|
||||
CollectionMixin, DirectorMixin, LabelMixin, WriterMixin
|
||||
):
|
||||
pass
|
||||
|
@ -1179,7 +1209,8 @@ class EpisodeEditMixins(
|
|||
|
||||
class ArtistEditMixins(
|
||||
ArtLockMixin, PosterLockMixin, ThemeLockMixin,
|
||||
AddedAtMixin, SortTitleMixin, SummaryMixin, TitleMixin, UserRatingMixin,
|
||||
AddedAtMixin, AudienceRatingMixin, CriticRatingMixin,
|
||||
SortTitleMixin, SummaryMixin, TitleMixin, UserRatingMixin,
|
||||
CollectionMixin, CountryMixin, GenreMixin, LabelMixin, MoodMixin, SimilarArtistMixin, StyleMixin
|
||||
):
|
||||
pass
|
||||
|
@ -1187,7 +1218,8 @@ class ArtistEditMixins(
|
|||
|
||||
class AlbumEditMixins(
|
||||
ArtLockMixin, PosterLockMixin, ThemeLockMixin,
|
||||
AddedAtMixin, OriginallyAvailableMixin, SortTitleMixin, StudioMixin, SummaryMixin, TitleMixin, UserRatingMixin,
|
||||
AddedAtMixin, AudienceRatingMixin, CriticRatingMixin,
|
||||
OriginallyAvailableMixin, SortTitleMixin, StudioMixin, SummaryMixin, TitleMixin, UserRatingMixin,
|
||||
CollectionMixin, GenreMixin, LabelMixin, MoodMixin, StyleMixin
|
||||
):
|
||||
pass
|
||||
|
@ -1195,7 +1227,8 @@ class AlbumEditMixins(
|
|||
|
||||
class TrackEditMixins(
|
||||
ArtLockMixin, PosterLockMixin, ThemeLockMixin,
|
||||
AddedAtMixin, TitleMixin, TrackArtistMixin, TrackNumberMixin, TrackDiscNumberMixin, UserRatingMixin,
|
||||
AddedAtMixin, AudienceRatingMixin, CriticRatingMixin,
|
||||
TitleMixin, TrackArtistMixin, TrackNumberMixin, TrackDiscNumberMixin, UserRatingMixin,
|
||||
CollectionMixin, GenreMixin, LabelMixin, MoodMixin
|
||||
):
|
||||
pass
|
||||
|
@ -1218,7 +1251,8 @@ class PhotoEditMixins(
|
|||
|
||||
class CollectionEditMixins(
|
||||
ArtLockMixin, PosterLockMixin, ThemeLockMixin,
|
||||
AddedAtMixin, ContentRatingMixin, SortTitleMixin, SummaryMixin, TitleMixin, UserRatingMixin,
|
||||
AddedAtMixin, AudienceRatingMixin, ContentRatingMixin, CriticRatingMixin,
|
||||
SortTitleMixin, SummaryMixin, TitleMixin, UserRatingMixin,
|
||||
LabelMixin
|
||||
):
|
||||
pass
|
||||
|
|
|
@ -713,6 +713,7 @@ class Season(
|
|||
Attributes:
|
||||
TAG (str): 'Directory'
|
||||
TYPE (str): 'season'
|
||||
audienceRating (float): Audience rating.
|
||||
audioLanguage (str): Setting that indicates the preferred audio language.
|
||||
collections (List<:class:`~plexapi.media.Collection`>): List of collection objects.
|
||||
guids (List<:class:`~plexapi.media.Guid`>): List of guid objects.
|
||||
|
@ -729,6 +730,7 @@ class Season(
|
|||
parentTheme (str): URL to show theme resource (/library/metadata/<parentRatingkey>/theme/<themeid>).
|
||||
parentThumb (str): URL to show thumbnail image (/library/metadata/<parentRatingKey>/thumb/<thumbid>).
|
||||
parentTitle (str): Name of the show for the season.
|
||||
rating (float): Season rating (7.9; 9.8; 8.1).
|
||||
ratings (List<:class:`~plexapi.media.Rating`>): List of rating objects.
|
||||
subtitleLanguage (str): Setting that indicates the preferred subtitle language.
|
||||
subtitleMode (int): Setting that indicates the auto-select subtitle mode.
|
||||
|
@ -743,6 +745,7 @@ class Season(
|
|||
def _loadData(self, data):
|
||||
""" Load attribute values from Plex XML response. """
|
||||
Video._loadData(self, data)
|
||||
self.audienceRating = utils.cast(float, data.attrib.get('audienceRating'))
|
||||
self.audioLanguage = data.attrib.get('audioLanguage', '')
|
||||
self.collections = self.findItems(data, media.Collection)
|
||||
self.guids = self.findItems(data, media.Guid)
|
||||
|
@ -759,6 +762,7 @@ class Season(
|
|||
self.parentTheme = data.attrib.get('parentTheme')
|
||||
self.parentThumb = data.attrib.get('parentThumb')
|
||||
self.parentTitle = data.attrib.get('parentTitle')
|
||||
self.rating = utils.cast(float, data.attrib.get('rating'))
|
||||
self.ratings = self.findItems(data, media.Rating)
|
||||
self.subtitleLanguage = data.attrib.get('subtitleLanguage', '')
|
||||
self.subtitleMode = utils.cast(int, data.attrib.get('subtitleMode', '-1'))
|
||||
|
|
|
@ -112,6 +112,8 @@ def test_audio_Artist_mixins_rating(artist):
|
|||
|
||||
def test_audio_Artist_mixins_fields(artist):
|
||||
test_mixins.edit_added_at(artist)
|
||||
test_mixins.edit_audience_rating(artist)
|
||||
test_mixins.edit_critic_rating(artist)
|
||||
test_mixins.edit_sort_title(artist)
|
||||
test_mixins.edit_summary(artist)
|
||||
test_mixins.edit_title(artist)
|
||||
|
@ -239,6 +241,8 @@ def test_audio_Album_mixins_rating(album):
|
|||
|
||||
def test_audio_Album_mixins_fields(album):
|
||||
test_mixins.edit_added_at(album)
|
||||
test_mixins.edit_audience_rating(album)
|
||||
test_mixins.edit_critic_rating(album)
|
||||
test_mixins.edit_originally_available(album)
|
||||
test_mixins.edit_sort_title(album)
|
||||
test_mixins.edit_studio(album)
|
||||
|
@ -422,6 +426,8 @@ def test_audio_Track_mixins_rating(track):
|
|||
|
||||
def test_audio_Track_mixins_fields(track):
|
||||
test_mixins.edit_added_at(track)
|
||||
test_mixins.edit_audience_rating(track)
|
||||
test_mixins.edit_critic_rating(track)
|
||||
test_mixins.edit_title(track)
|
||||
test_mixins.edit_track_artist(track)
|
||||
test_mixins.edit_track_number(track)
|
||||
|
|
|
@ -366,7 +366,9 @@ def test_Collection_mixins_rating(collection):
|
|||
|
||||
def test_Collection_mixins_fields(collection):
|
||||
test_mixins.edit_added_at(collection)
|
||||
test_mixins.edit_audience_rating(collection)
|
||||
test_mixins.edit_content_rating(collection)
|
||||
test_mixins.edit_critic_rating(collection)
|
||||
test_mixins.edit_sort_title(collection)
|
||||
test_mixins.edit_summary(collection)
|
||||
test_mixins.edit_title(collection)
|
||||
|
|
|
@ -51,10 +51,18 @@ def edit_added_at(obj):
|
|||
_test_mixins_field(obj, "addedAt", "AddedAt")
|
||||
|
||||
|
||||
def edit_audience_rating(obj):
|
||||
_test_mixins_field(obj, "audienceRating", "AudienceRating", default=None, value=7.7)
|
||||
|
||||
|
||||
def edit_content_rating(obj):
|
||||
_test_mixins_field(obj, "contentRating", "ContentRating")
|
||||
|
||||
|
||||
def edit_critic_rating(obj):
|
||||
_test_mixins_field(obj, "rating", "CriticRating", default=None, value=8.8)
|
||||
|
||||
|
||||
def edit_edition_title(obj):
|
||||
_test_mixins_field(obj, "editionTitle", "EditionTitle")
|
||||
|
||||
|
@ -104,7 +112,7 @@ def edit_photo_captured_time(obj):
|
|||
|
||||
|
||||
def edit_user_rating(obj):
|
||||
_test_mixins_field(obj, "userRating", "UserRating", default=None, value=10)
|
||||
_test_mixins_field(obj, "userRating", "UserRating", default=None, value=10.0)
|
||||
|
||||
|
||||
def _test_mixins_tag(obj, attr, tag_method):
|
||||
|
|
|
@ -689,7 +689,9 @@ def test_video_Movie_mixins_rating(movie):
|
|||
|
||||
def test_video_Movie_mixins_fields(movie):
|
||||
test_mixins.edit_added_at(movie)
|
||||
test_mixins.edit_audience_rating(movie)
|
||||
test_mixins.edit_content_rating(movie)
|
||||
test_mixins.edit_critic_rating(movie)
|
||||
test_mixins.edit_originally_available(movie)
|
||||
test_mixins.edit_original_title(movie)
|
||||
test_mixins.edit_sort_title(movie)
|
||||
|
@ -955,7 +957,9 @@ def test_video_Show_mixins_rating(show):
|
|||
|
||||
def test_video_Show_mixins_fields(show):
|
||||
test_mixins.edit_added_at(show)
|
||||
test_mixins.edit_audience_rating(show)
|
||||
test_mixins.edit_content_rating(show)
|
||||
test_mixins.edit_critic_rating(show)
|
||||
test_mixins.edit_originally_available(show)
|
||||
test_mixins.edit_original_title(show)
|
||||
test_mixins.edit_sort_title(show)
|
||||
|
@ -1112,6 +1116,8 @@ def test_video_Season_mixins_rating(show):
|
|||
def test_video_Season_mixins_fields(show):
|
||||
season = show.season(season=1)
|
||||
test_mixins.edit_added_at(season)
|
||||
test_mixins.edit_audience_rating(season)
|
||||
test_mixins.edit_critic_rating(season)
|
||||
test_mixins.edit_summary(season)
|
||||
test_mixins.edit_title(season)
|
||||
test_mixins.edit_user_rating(season)
|
||||
|
@ -1322,7 +1328,9 @@ def test_video_Episode_mixins_rating(episode):
|
|||
|
||||
def test_video_Episode_mixins_fields(episode):
|
||||
test_mixins.edit_added_at(episode)
|
||||
test_mixins.edit_audience_rating(episode)
|
||||
test_mixins.edit_content_rating(episode)
|
||||
test_mixins.edit_critic_rating(episode)
|
||||
test_mixins.edit_originally_available(episode)
|
||||
test_mixins.edit_sort_title(episode)
|
||||
test_mixins.edit_summary(episode)
|
||||
|
|
Loading…
Reference in a new issue