Skip to content

Add support for editing audience ratings and critic ratings #1417

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions plexapi/audio.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,13 +181,15 @@ 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.
guids (List<:class:`~plexapi.media.Guid`>): List of guid objects.
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>).
Expand All @@ -199,13 +201,15 @@ def _loadData(self, data):
""" 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)
self.guids = self.findItems(data, media.Guid)
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')
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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.
Expand All @@ -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)
Expand All @@ -465,6 +473,7 @@ def _loadData(self, data):
""" 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)
Expand All @@ -488,6 +497,7 @@ def _loadData(self, data):
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
Expand Down
4 changes: 4 additions & 0 deletions plexapi/collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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.
Expand All @@ -69,6 +71,7 @@ def _loadData(self, data):
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'))
Expand All @@ -87,6 +90,7 @@ def _loadData(self, data):
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'))
Expand Down
52 changes: 43 additions & 9 deletions plexapi/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,19 @@ def editAddedAt(self, addedAt, locked=True):
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. """

Expand All @@ -580,6 +593,19 @@ def editContentRating(self, contentRating, locked=True):
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. """

Expand Down Expand Up @@ -751,7 +777,7 @@ def editUserRating(self, userRating, locked=True):
""" 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)
Expand Down Expand Up @@ -1145,7 +1171,8 @@ def streamingServices(self, account=None):

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
):
Expand All @@ -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,
):
Expand All @@ -1163,39 +1191,44 @@ class ShowEditMixins(

class SeasonEditMixins(
ArtLockMixin, PosterLockMixin, ThemeLockMixin,
AddedAtMixin, SummaryMixin, TitleMixin, UserRatingMixin,
AddedAtMixin, AudienceRatingMixin, CriticRatingMixin,
SummaryMixin, TitleMixin, UserRatingMixin,
CollectionMixin, LabelMixin
):
pass


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


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


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


class TrackEditMixins(
ArtLockMixin, PosterLockMixin, ThemeLockMixin,
AddedAtMixin, TitleMixin, TrackArtistMixin, TrackNumberMixin, TrackDiscNumberMixin, UserRatingMixin,
AddedAtMixin, AudienceRatingMixin, CriticRatingMixin,
TitleMixin, TrackArtistMixin, TrackNumberMixin, TrackDiscNumberMixin, UserRatingMixin,
CollectionMixin, GenreMixin, LabelMixin, MoodMixin
):
pass
Expand All @@ -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
Expand Down
4 changes: 4 additions & 0 deletions plexapi/video.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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.
Expand All @@ -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)
Expand All @@ -759,6 +762,7 @@ def _loadData(self, data):
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'))
Expand Down
6 changes: 6 additions & 0 deletions tests/test_audio.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions tests/test_collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
10 changes: 9 additions & 1 deletion tests/test_mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")

Expand Down Expand Up @@ -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):
Expand Down
8 changes: 8 additions & 0 deletions tests/test_video.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down