Skip to content
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
14 changes: 8 additions & 6 deletions plexapi/audio.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from plexapi.base import Playable, PlexPartialObject
from plexapi.exceptions import BadRequest
from plexapi.mixins import AdvancedSettingsMixin, ArtUrlMixin, ArtMixin, PosterUrlMixin, PosterMixin
from plexapi.mixins import SplitMergeMixin, UnmatchMatchMixin
from plexapi.mixins import RatingMixin, SplitMergeMixin, UnmatchMatchMixin
from plexapi.mixins import CollectionMixin, CountryMixin, GenreMixin, LabelMixin, MoodMixin, SimilarArtistMixin, StyleMixin


Expand All @@ -21,6 +21,7 @@ class Audio(PlexPartialObject):
guid (str): Plex GUID for the artist, album, or track (plex://artist/5d07bcb0403c64029053ac4c).
index (int): Plex index number (often the track number).
key (str): API URL (/library/metadata/<ratingkey>).
lastRatedAt (datetime): Datetime the item was last rated.
lastViewedAt (datetime): Datetime the item was last played.
librarySectionID (int): :class:`~plexapi.library.LibrarySection` ID.
librarySectionKey (str): :class:`~plexapi.library.LibrarySection` key.
Expand All @@ -35,7 +36,7 @@ class Audio(PlexPartialObject):
titleSort (str): Title to use when sorting (defaults to title).
type (str): 'artist', 'album', or 'track'.
updatedAt (datatime): Datetime the item was updated.
userRating (float): Rating of the track (0.0 - 10.0) equaling (0 stars - 5 stars).
userRating (float): Rating of the item (0.0 - 10.0) equaling (0 stars - 5 stars).
viewCount (int): Count of times the item was played.
"""

Expand Down Expand Up @@ -66,7 +67,7 @@ def _loadData(self, data):
self.titleSort = data.attrib.get('titleSort', self.title)
self.type = data.attrib.get('type')
self.updatedAt = utils.toDatetime(data.attrib.get('updatedAt'))
self.userRating = utils.cast(float, data.attrib.get('userRating', 0))
self.userRating = utils.cast(float, data.attrib.get('userRating'))
self.viewCount = utils.cast(int, data.attrib.get('viewCount', 0))

def url(self, part):
Expand Down Expand Up @@ -115,7 +116,7 @@ def sync(self, bitrate, client=None, clientId=None, limit=None, title=None):


@utils.registerPlexObject
class Artist(Audio, AdvancedSettingsMixin, ArtMixin, PosterMixin, SplitMergeMixin, UnmatchMatchMixin,
class Artist(Audio, AdvancedSettingsMixin, ArtMixin, PosterMixin, RatingMixin, SplitMergeMixin, UnmatchMatchMixin,
CollectionMixin, CountryMixin, GenreMixin, MoodMixin, SimilarArtistMixin, StyleMixin):
""" Represents a single Artist.

Expand Down Expand Up @@ -222,7 +223,7 @@ def download(self, savepath=None, keep_original_name=False, **kwargs):


@utils.registerPlexObject
class Album(Audio, ArtMixin, PosterMixin, UnmatchMatchMixin,
class Album(Audio, ArtMixin, PosterMixin, RatingMixin, UnmatchMatchMixin,
CollectionMixin, GenreMixin, LabelMixin, MoodMixin, StyleMixin):
""" Represents a single Album.

Expand Down Expand Up @@ -329,7 +330,8 @@ def _defaultSyncTitle(self):


@utils.registerPlexObject
class Track(Audio, Playable, ArtUrlMixin, PosterUrlMixin, CollectionMixin, MoodMixin):
class Track(Audio, Playable, ArtUrlMixin, PosterUrlMixin, RatingMixin,
CollectionMixin, MoodMixin):
""" Represents a single Track.

Attributes:
Expand Down
2 changes: 1 addition & 1 deletion plexapi/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def __init__(self, server, data, initpath=None, parent=None):
self._server = server
self._data = data
self._initpath = initpath or self.key
self._parent = weakref.ref(parent) if parent else None
self._parent = weakref.ref(parent) if parent is not None else None
self._details_key = None
if data is not None:
self._loadData(data)
Expand Down
8 changes: 6 additions & 2 deletions plexapi/collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@
from plexapi.base import PlexPartialObject
from plexapi.exceptions import BadRequest, NotFound, Unsupported
from plexapi.library import LibrarySection
from plexapi.mixins import AdvancedSettingsMixin, ArtMixin, PosterMixin
from plexapi.mixins import AdvancedSettingsMixin, ArtMixin, PosterMixin, RatingMixin
from plexapi.mixins import LabelMixin
from plexapi.playqueue import PlayQueue
from plexapi.utils import deprecated


@utils.registerPlexObject
class Collection(PlexPartialObject, AdvancedSettingsMixin, ArtMixin, PosterMixin, LabelMixin):
class Collection(PlexPartialObject, AdvancedSettingsMixin, ArtMixin, PosterMixin, RatingMixin, LabelMixin):
""" Represents a single Collection.

Attributes:
Expand All @@ -32,6 +32,7 @@ class Collection(PlexPartialObject, AdvancedSettingsMixin, ArtMixin, PosterMixin
index (int): Plex index number for the collection.
key (str): API URL (/library/metadata/<ratingkey>).
labels (List<:class:`~plexapi.media.Label`>): List of label objects.
lastRatedAt (datetime): Datetime the collection was last rated.
librarySectionID (int): :class:`~plexapi.library.LibrarySection` ID.
librarySectionKey (str): :class:`~plexapi.library.LibrarySection` key.
librarySectionTitle (str): :class:`~plexapi.library.LibrarySection` title.
Expand All @@ -48,6 +49,7 @@ class Collection(PlexPartialObject, AdvancedSettingsMixin, ArtMixin, PosterMixin
titleSort (str): Title to use when sorting (defaults to title).
type (str): 'collection'
updatedAt (datatime): Datetime the collection was updated.
userRating (float): Rating of the collection (0.0 - 10.0) equaling (0 stars - 5 stars).
"""

TAG = 'Directory'
Expand All @@ -69,6 +71,7 @@ def _loadData(self, data):
self.index = utils.cast(int, data.attrib.get('index'))
self.key = data.attrib.get('key', '').replace('/children', '') # FIX_BUG_50
self.labels = self.findItems(data, media.Label)
self.lastRatedAt = utils.toDatetime(data.attrib.get('lastRatedAt'))
self.librarySectionID = utils.cast(int, data.attrib.get('librarySectionID'))
self.librarySectionKey = data.attrib.get('librarySectionKey')
self.librarySectionTitle = data.attrib.get('librarySectionTitle')
Expand All @@ -85,6 +88,7 @@ def _loadData(self, data):
self.titleSort = data.attrib.get('titleSort', self.title)
self.type = data.attrib.get('type')
self.updatedAt = utils.toDatetime(data.attrib.get('updatedAt'))
self.userRating = utils.cast(float, data.attrib.get('userRating'))
self._items = None # cache for self.items
self._section = None # cache for self.section

Expand Down
22 changes: 21 additions & 1 deletion plexapi/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from urllib.parse import quote_plus, urlencode

from plexapi import media, settings, utils
from plexapi.exceptions import NotFound
from plexapi.exceptions import BadRequest, NotFound


class AdvancedSettingsMixin(object):
Expand Down Expand Up @@ -192,6 +192,26 @@ def setPoster(self, poster):
poster.select()


class RatingMixin(object):
""" Mixin for Plex objects that can have user star ratings. """

def rate(self, rating=None):
""" Rate the Plex object. Note: Plex ratings are displayed out of 5 stars (e.g. rating 7.0 = 3.5 stars).

Parameters:
rating (float, optional): Rating from 0 to 10. Exclude to reset the rating.

Raises:
:exc:`~plexapi.exceptions.BadRequest`: If the rating is invalid.
"""
if rating is None:
rating = -1
elif not isinstance(rating, (int, float)) or rating < 0 or rating > 10:
raise BadRequest('Rating must be between 0 to 10.')
key = '/:/rate?key=%s&identifier=com.plexapp.plugins.library&rating=%s' % (self.ratingKey, rating)
self._server.query(key, method=self._server._session.put)


class SplitMergeMixin(object):
""" Mixin for Plex objects that can be split and merged. """

Expand Down
16 changes: 11 additions & 5 deletions plexapi/photo.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
from plexapi import media, utils, video
from plexapi.base import Playable, PlexPartialObject
from plexapi.exceptions import BadRequest
from plexapi.mixins import ArtUrlMixin, ArtMixin, PosterUrlMixin, PosterMixin, TagMixin
from plexapi.mixins import ArtUrlMixin, ArtMixin, PosterUrlMixin, PosterMixin, RatingMixin, TagMixin


@utils.registerPlexObject
class Photoalbum(PlexPartialObject, ArtMixin, PosterMixin):
class Photoalbum(PlexPartialObject, ArtMixin, PosterMixin, RatingMixin):
""" Represents a single Photoalbum (collection of photos).

Attributes:
Expand All @@ -21,6 +21,7 @@ class Photoalbum(PlexPartialObject, ArtMixin, PosterMixin):
guid (str): Plex GUID for the photo album (local://229674).
index (sting): Plex index number for the photo album.
key (str): API URL (/library/metadata/<ratingkey>).
lastRatedAt (datetime): Datetime the photo album was last rated.
librarySectionID (int): :class:`~plexapi.library.LibrarySection` ID.
librarySectionKey (str): :class:`~plexapi.library.LibrarySection` key.
librarySectionTitle (str): :class:`~plexapi.library.LibrarySection` title.
Expand All @@ -32,7 +33,7 @@ class Photoalbum(PlexPartialObject, ArtMixin, PosterMixin):
titleSort (str): Title to use when sorting (defaults to title).
type (str): 'photo'
updatedAt (datatime): Datetime the photo album was updated.
userRating (float): Rating of the photoalbum (0.0 - 10.0) equaling (0 stars - 5 stars).
userRating (float): Rating of the photo album (0.0 - 10.0) equaling (0 stars - 5 stars).
"""
TAG = 'Directory'
TYPE = 'photo'
Expand All @@ -46,6 +47,7 @@ def _loadData(self, data):
self.guid = data.attrib.get('guid')
self.index = utils.cast(int, data.attrib.get('index'))
self.key = data.attrib.get('key', '').replace('/children', '') # FIX_BUG_50
self.lastRatedAt = utils.toDatetime(data.attrib.get('lastRatedAt'))
self.librarySectionID = utils.cast(int, data.attrib.get('librarySectionID'))
self.librarySectionKey = data.attrib.get('librarySectionKey')
self.librarySectionTitle = data.attrib.get('librarySectionTitle')
Expand All @@ -57,7 +59,7 @@ def _loadData(self, data):
self.titleSort = data.attrib.get('titleSort', self.title)
self.type = data.attrib.get('type')
self.updatedAt = utils.toDatetime(data.attrib.get('updatedAt'))
self.userRating = utils.cast(float, data.attrib.get('userRating', 0))
self.userRating = utils.cast(float, data.attrib.get('userRating'))

def album(self, title):
""" Returns the :class:`~plexapi.photo.Photoalbum` that matches the specified title.
Expand Down Expand Up @@ -137,7 +139,7 @@ def download(self, savepath=None, keep_original_name=False, showstatus=False):


@utils.registerPlexObject
class Photo(PlexPartialObject, Playable, ArtUrlMixin, PosterUrlMixin, TagMixin):
class Photo(PlexPartialObject, Playable, ArtUrlMixin, PosterUrlMixin, RatingMixin, TagMixin):
""" Represents a single Photo.

Attributes:
Expand All @@ -150,6 +152,7 @@ class Photo(PlexPartialObject, Playable, ArtUrlMixin, PosterUrlMixin, TagMixin):
guid (str): Plex GUID for the photo (com.plexapp.agents.none://231714?lang=xn).
index (sting): Plex index number for the photo.
key (str): API URL (/library/metadata/<ratingkey>).
lastRatedAt (datetime): Datetime the photo was last rated.
librarySectionID (int): :class:`~plexapi.library.LibrarySection` ID.
librarySectionKey (str): :class:`~plexapi.library.LibrarySection` key.
librarySectionTitle (str): :class:`~plexapi.library.LibrarySection` title.
Expand All @@ -170,6 +173,7 @@ class Photo(PlexPartialObject, Playable, ArtUrlMixin, PosterUrlMixin, TagMixin):
titleSort (str): Title to use when sorting (defaults to title).
type (str): 'photo'
updatedAt (datatime): Datetime the photo was updated.
userRating (float): Rating of the photo (0.0 - 10.0) equaling (0 stars - 5 stars).
year (int): Year the photo was taken.
"""
TAG = 'Photo'
Expand All @@ -186,6 +190,7 @@ def _loadData(self, data):
self.guid = data.attrib.get('guid')
self.index = utils.cast(int, data.attrib.get('index'))
self.key = data.attrib.get('key', '')
self.lastRatedAt = utils.toDatetime(data.attrib.get('lastRatedAt'))
self.librarySectionID = utils.cast(int, data.attrib.get('librarySectionID'))
self.librarySectionKey = data.attrib.get('librarySectionKey')
self.librarySectionTitle = data.attrib.get('librarySectionTitle')
Expand All @@ -206,6 +211,7 @@ def _loadData(self, data):
self.titleSort = data.attrib.get('titleSort', self.title)
self.type = data.attrib.get('type')
self.updatedAt = utils.toDatetime(data.attrib.get('updatedAt'))
self.userRating = utils.cast(float, data.attrib.get('userRating'))
self.year = utils.cast(int, data.attrib.get('year'))

def photoalbum(self):
Expand Down
Loading