Skip to content

Commit 97c13e5

Browse files
authored
Add support for Square Art (#1557)
* Add support for Square Art * Add tests for square art * Add square art to artist/album/track, collection, photoalbum/photo, playlist * Add square art tests * Add sqaureArt property * Fix docstring typos
1 parent c4ea6e7 commit 97c13e5

File tree

14 files changed

+136
-20
lines changed

14 files changed

+136
-20
lines changed

plexapi/audio.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from plexapi.exceptions import BadRequest
1313
from plexapi.mixins import (
1414
AdvancedSettingsMixin, SplitMergeMixin, UnmatchMatchMixin, ExtrasMixin, HubsMixin, PlayedUnplayedMixin, RatingMixin,
15-
ArtUrlMixin, ArtMixin, PosterUrlMixin, PosterMixin, ThemeMixin, ThemeUrlMixin,
15+
ArtUrlMixin, ArtMixin, PosterUrlMixin, PosterMixin, SquareArtMixin, SquareArtUrlMixin, ThemeMixin, ThemeUrlMixin,
1616
ArtistEditMixins, AlbumEditMixins, TrackEditMixins
1717
)
1818
from plexapi.playlist import Playlist
@@ -181,7 +181,7 @@ def sonicallySimilar(
181181
class Artist(
182182
Audio,
183183
AdvancedSettingsMixin, SplitMergeMixin, UnmatchMatchMixin, ExtrasMixin, HubsMixin, RatingMixin,
184-
ArtMixin, PosterMixin, ThemeMixin,
184+
ArtMixin, PosterMixin, SquareArtMixin, ThemeMixin,
185185
ArtistEditMixins
186186
):
187187
""" Represents a single Artist.
@@ -351,7 +351,7 @@ def metadataDirectory(self):
351351
class Album(
352352
Audio,
353353
SplitMergeMixin, UnmatchMatchMixin, RatingMixin,
354-
ArtMixin, PosterMixin, ThemeUrlMixin,
354+
ArtMixin, PosterMixin, SquareArtMixin, ThemeUrlMixin,
355355
AlbumEditMixins
356356
):
357357
""" Represents a single Album.
@@ -504,7 +504,7 @@ def metadataDirectory(self):
504504
class Track(
505505
Audio, Playable,
506506
ExtrasMixin, RatingMixin,
507-
ArtUrlMixin, PosterUrlMixin, ThemeUrlMixin,
507+
ArtUrlMixin, PosterUrlMixin, SquareArtUrlMixin, ThemeUrlMixin,
508508
TrackEditMixins
509509
):
510510
""" Represents a single Track.

plexapi/collection.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from plexapi.library import LibrarySection, ManagedHub
99
from plexapi.mixins import (
1010
AdvancedSettingsMixin, SmartFilterMixin, HubsMixin, RatingMixin,
11-
ArtMixin, PosterMixin, ThemeMixin,
11+
ArtMixin, PosterMixin, SquareArtMixin, ThemeMixin,
1212
CollectionEditMixins
1313
)
1414
from plexapi.utils import deprecated
@@ -18,7 +18,7 @@
1818
class Collection(
1919
PlexPartialObject,
2020
AdvancedSettingsMixin, SmartFilterMixin, HubsMixin, RatingMixin,
21-
ArtMixin, PosterMixin, ThemeMixin,
21+
ArtMixin, PosterMixin, SquareArtMixin, ThemeMixin,
2222
CollectionEditMixins
2323
):
2424
""" Represents a single Collection.

plexapi/media.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1116,6 +1116,11 @@ class Poster(BaseResource):
11161116
TAG = 'Photo'
11171117

11181118

1119+
class SquareArt(BaseResource):
1120+
""" Represents a single Square Art object. """
1121+
TAG = 'Photo'
1122+
1123+
11191124
class Theme(BaseResource):
11201125
""" Represents a single Theme object. """
11211126
TAG = 'Track'

plexapi/mixins.py

Lines changed: 68 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,7 @@ def uploadArt(self, url=None, filepath=None):
382382
383383
Parameters:
384384
url (str): The full URL to the image to upload.
385-
filepath (str): The full file path the the image to upload or file-like object.
385+
filepath (str): The full file path to the image to upload or file-like object.
386386
"""
387387
if url:
388388
key = f'/library/metadata/{self.ratingKey}/arts?url={quote_plus(url)}'
@@ -437,7 +437,7 @@ def uploadLogo(self, url=None, filepath=None):
437437
438438
Parameters:
439439
url (str): The full URL to the image to upload.
440-
filepath (str): The full file path the the image to upload or file-like object.
440+
filepath (str): The full file path to the image to upload or file-like object.
441441
"""
442442
if url:
443443
key = f'/library/metadata/{self.ratingKey}/clearLogos?url={quote_plus(url)}'
@@ -499,7 +499,7 @@ def uploadPoster(self, url=None, filepath=None):
499499
500500
Parameters:
501501
url (str): The full URL to the image to upload.
502-
filepath (str): The full file path the the image to upload or file-like object.
502+
filepath (str): The full file path to the image to upload or file-like object.
503503
"""
504504
if url:
505505
key = f'/library/metadata/{self.ratingKey}/posters?url={quote_plus(url)}'
@@ -520,6 +520,71 @@ def setPoster(self, poster):
520520
return self
521521

522522

523+
class SquareArtUrlMixin:
524+
""" Mixin for Plex objects that can have a square art url. """
525+
526+
@property
527+
def squareArt(self):
528+
""" Return the API path to the square art image. """
529+
return next((i.url for i in self.images if i.type == 'backgroundSquare'), None)
530+
531+
@property
532+
def squareArtUrl(self):
533+
""" Return the square art url for the Plex object. """
534+
return self._server.url(self.squareArt, includeToken=True) if self.squareArt else None
535+
536+
537+
class SquareArtLockMixin:
538+
""" Mixin for Plex objects that can have a locked square art. """
539+
540+
def lockSquareArt(self):
541+
""" Lock the square art for a Plex object. """
542+
return self._edit(**{'squareArt.locked': 1})
543+
544+
def unlockSquareArt(self):
545+
""" Unlock the square art for a Plex object. """
546+
return self._edit(**{'squareArt.locked': 0})
547+
548+
549+
class SquareArtMixin(SquareArtUrlMixin, SquareArtLockMixin):
550+
""" Mixin for Plex objects that can have square art. """
551+
552+
def squareArts(self):
553+
""" Returns list of available :class:`~plexapi.media.SquareArt` objects. """
554+
return self.fetchItems(f'/library/metadata/{self.ratingKey}/squareArts', cls=media.SquareArt)
555+
556+
def uploadSquareArt(self, url=None, filepath=None):
557+
""" Upload a square art from a url or filepath.
558+
559+
Parameters:
560+
url (str): The full URL to the image to upload.
561+
filepath (str): The full file path to the image to upload or file-like object.
562+
"""
563+
if url:
564+
key = f'/library/metadata/{self.ratingKey}/squareArts?url={quote_plus(url)}'
565+
self._server.query(key, method=self._server._session.post)
566+
elif filepath:
567+
key = f'/library/metadata/{self.ratingKey}/squareArts'
568+
data = openOrRead(filepath)
569+
self._server.query(key, method=self._server._session.post, data=data)
570+
return self
571+
572+
def setSquareArt(self, squareArt):
573+
""" Set the square art for a Plex object.
574+
575+
Parameters:
576+
squareArt (:class:`~plexapi.media.SquareArt`): The square art object to select.
577+
"""
578+
squareArt.select()
579+
return self
580+
581+
def deleteSquareArt(self):
582+
""" Delete the square art from a Plex object. """
583+
key = f'/library/metadata/{self.ratingKey}/squareArt'
584+
self._server.query(key, method=self._server._session.delete)
585+
return self
586+
587+
523588
class ThemeUrlMixin:
524589
""" Mixin for Plex objects that can have a theme url. """
525590

plexapi/photo.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from plexapi.exceptions import BadRequest
99
from plexapi.mixins import (
1010
RatingMixin,
11-
ArtUrlMixin, ArtMixin, PosterUrlMixin, PosterMixin,
11+
ArtUrlMixin, ArtMixin, PosterUrlMixin, PosterMixin, SquareArtMixin, SquareArtUrlMixin,
1212
PhotoalbumEditMixins, PhotoEditMixins
1313
)
1414

@@ -17,7 +17,7 @@
1717
class Photoalbum(
1818
PlexPartialObject,
1919
RatingMixin,
20-
ArtMixin, PosterMixin,
20+
ArtMixin, PosterMixin, SquareArtMixin,
2121
PhotoalbumEditMixins
2222
):
2323
""" Represents a single Photoalbum (collection of photos).
@@ -159,7 +159,7 @@ def metadataDirectory(self):
159159
class Photo(
160160
PlexPartialObject, Playable,
161161
RatingMixin,
162-
ArtUrlMixin, PosterUrlMixin,
162+
ArtUrlMixin, PosterUrlMixin, SquareArtUrlMixin,
163163
PhotoEditMixins
164164
):
165165
""" Represents a single Photo.

plexapi/playlist.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,15 @@
88
from plexapi.base import Playable, PlexPartialObject, cached_data_property
99
from plexapi.exceptions import BadRequest, NotFound, Unsupported
1010
from plexapi.library import LibrarySection, MusicSection
11-
from plexapi.mixins import SmartFilterMixin, ArtMixin, PosterMixin, PlaylistEditMixins
11+
from plexapi.mixins import SmartFilterMixin, ArtMixin, PosterMixin, SquareArtMixin, PlaylistEditMixins
1212
from plexapi.utils import deprecated
1313

1414

1515
@utils.registerPlexObject
1616
class Playlist(
1717
PlexPartialObject, Playable,
1818
SmartFilterMixin,
19-
ArtMixin, PosterMixin,
19+
ArtMixin, PosterMixin, SquareArtMixin,
2020
PlaylistEditMixins
2121
):
2222
""" Represents a single Playlist.

plexapi/utils.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@
9595
'showOrdering': 322,
9696
'clearLogo': 323,
9797
'commonSenseMedia': 324,
98+
'squareArt': 325,
9899
'place': 400,
99100
'sharedWidth': 500,
100101
}

plexapi/video.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
from plexapi.exceptions import BadRequest
99
from plexapi.mixins import (
1010
AdvancedSettingsMixin, SplitMergeMixin, UnmatchMatchMixin, ExtrasMixin, HubsMixin, PlayedUnplayedMixin, RatingMixin,
11-
ArtUrlMixin, ArtMixin, LogoMixin, PosterUrlMixin, PosterMixin, ThemeUrlMixin, ThemeMixin,
11+
ArtUrlMixin, ArtMixin, LogoMixin, LogoUrlMixin, PosterUrlMixin, PosterMixin, SquareArtMixin, SquareArtUrlMixin,
12+
ThemeUrlMixin, ThemeMixin,
1213
MovieEditMixins, ShowEditMixins, SeasonEditMixins, EpisodeEditMixins,
1314
WatchlistMixin
1415
)
@@ -338,7 +339,7 @@ def sync(self, videoQuality, client=None, clientId=None, limit=None, unwatched=F
338339
class Movie(
339340
Video, Playable,
340341
AdvancedSettingsMixin, SplitMergeMixin, UnmatchMatchMixin, ExtrasMixin, HubsMixin, RatingMixin,
341-
ArtMixin, LogoMixin, PosterMixin, ThemeMixin,
342+
ArtMixin, LogoMixin, PosterMixin, SquareArtMixin, ThemeMixin,
342343
MovieEditMixins,
343344
WatchlistMixin
344345
):
@@ -550,7 +551,7 @@ def metadataDirectory(self):
550551
class Show(
551552
Video,
552553
AdvancedSettingsMixin, SplitMergeMixin, UnmatchMatchMixin, ExtrasMixin, HubsMixin, RatingMixin,
553-
ArtMixin, LogoMixin, PosterMixin, ThemeMixin,
554+
ArtMixin, LogoMixin, PosterMixin, SquareArtMixin, ThemeMixin,
554555
ShowEditMixins,
555556
WatchlistMixin
556557
):
@@ -802,7 +803,7 @@ def metadataDirectory(self):
802803
class Season(
803804
Video,
804805
AdvancedSettingsMixin, ExtrasMixin, RatingMixin,
805-
ArtMixin, LogoMixin, PosterMixin, ThemeUrlMixin,
806+
ArtMixin, LogoMixin, PosterMixin, SquareArtMixin, ThemeUrlMixin,
806807
SeasonEditMixins
807808
):
808809
""" Represents a single Season.
@@ -984,7 +985,7 @@ def metadataDirectory(self):
984985
class Episode(
985986
Video, Playable,
986987
ExtrasMixin, RatingMixin,
987-
ArtMixin, LogoMixin, PosterMixin, ThemeUrlMixin,
988+
ArtMixin, LogoMixin, PosterMixin, SquareArtMixin, ThemeUrlMixin,
988989
EpisodeEditMixins
989990
):
990991
""" Represents a single Episode.
@@ -1260,7 +1261,7 @@ def metadataDirectory(self):
12601261
@utils.registerPlexObject
12611262
class Clip(
12621263
Video, Playable,
1263-
ArtUrlMixin, PosterUrlMixin
1264+
ArtUrlMixin, LogoUrlMixin, PosterUrlMixin, SquareArtUrlMixin
12641265
):
12651266
""" Represents a single Clip.
12661267

tests/test_audio.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,10 +104,13 @@ def test_audio_Artist_mixins_edit_advanced_settings(artist):
104104
def test_audio_Artist_mixins_images(artist):
105105
test_mixins.lock_art(artist)
106106
test_mixins.lock_poster(artist)
107+
test_mixins.lock_square_art(artist)
107108
test_mixins.edit_art(artist)
108109
test_mixins.edit_poster(artist)
110+
test_mixins.edit_square_art(artist)
109111
test_mixins.attr_artUrl(artist)
110112
test_mixins.attr_posterUrl(artist)
113+
test_mixins.attr_squareArtUrl(artist)
111114

112115

113116
def test_audio_Artist_mixins_themes(artist):
@@ -234,10 +237,13 @@ def test_audio_Album_artist(album):
234237
def test_audio_Album_mixins_images(album):
235238
test_mixins.lock_art(album)
236239
test_mixins.lock_poster(album)
240+
test_mixins.lock_square_art(album)
237241
test_mixins.edit_art(album)
238242
test_mixins.edit_poster(album)
243+
test_mixins.edit_square_art(album)
239244
test_mixins.attr_artUrl(album)
240245
test_mixins.attr_posterUrl(album)
246+
test_mixins.attr_squareArtUrl(album)
241247

242248

243249
def test_audio_Album_mixins_themes(album):
@@ -425,6 +431,7 @@ def test_audio_Track_sonicAdventure(account_plexpass, music):
425431
def test_audio_Track_mixins_images(track):
426432
test_mixins.attr_artUrl(track)
427433
test_mixins.attr_posterUrl(track)
434+
test_mixins.attr_squareArtUrl(track)
428435

429436

430437
def test_audio_Track_mixins_themes(track):

tests/test_collection.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,10 +353,13 @@ def test_Collection_art(collection):
353353
def test_Collection_mixins_images(collection):
354354
test_mixins.lock_art(collection)
355355
test_mixins.lock_poster(collection)
356+
test_mixins.lock_square_art(collection)
356357
test_mixins.edit_art(collection)
357358
test_mixins.edit_poster(collection)
359+
test_mixins.edit_square_art(collection)
358360
test_mixins.attr_artUrl(collection)
359361
test_mixins.attr_posterUrl(collection)
362+
test_mixins.attr_squareArtUrl(collection)
360363

361364

362365
def test_Collection_mixins_themes(collection):

0 commit comments

Comments
 (0)