Bump plexapi from 4.15.4 to 4.15.10 (#2251)

* Bump plexapi from 4.15.4 to 4.15.10

Bumps [plexapi](https://github.com/pkkid/python-plexapi) from 4.15.4 to 4.15.10.
- [Release notes](https://github.com/pkkid/python-plexapi/releases)
- [Commits](https://github.com/pkkid/python-plexapi/compare/4.15.4...4.15.10)

---
updated-dependencies:
- dependency-name: plexapi
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* Update plexapi==4.15.10

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com>

[skip ci]
This commit is contained in:
dependabot[bot] 2024-03-02 13:52:45 -08:00 committed by GitHub
parent 040972bcba
commit b1c0972077
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 413 additions and 189 deletions

View file

@ -1,5 +1,7 @@
# -*- coding: utf-8 -*-
from collections import deque
from datetime import datetime
from typing import Deque, Set, Tuple, Union
from urllib.parse import parse_qsl, quote, quote_plus, unquote, urlencode, urlsplit
from plexapi import media, settings, utils
@ -61,63 +63,96 @@ class AdvancedSettingsMixin:
class SmartFilterMixin:
""" Mixing for Plex objects that can have smart filters. """
""" Mixin for Plex objects that can have smart filters. """
def _parseFilterGroups(self, feed: Deque[Tuple[str, str]], returnOn: Union[Set[str], None] = None) -> dict:
""" Parse filter groups from input lines between push and pop. """
currentFiltersStack: list[dict] = []
operatorForStack = None
if returnOn is None:
returnOn = set("pop")
else:
returnOn.add("pop")
allowedLogicalOperators = ["and", "or"] # first is the default
while feed:
key, value = feed.popleft() # consume the first item
if key == "push":
# recurse and add the result to the current stack
currentFiltersStack.append(
self._parseFilterGroups(feed, returnOn)
)
elif key in returnOn:
# stop iterating and return the current stack
if not key == "pop":
feed.appendleft((key, value)) # put the item back
break
elif key in allowedLogicalOperators:
# set the operator
if operatorForStack and not operatorForStack == key:
raise ValueError(
"cannot have different logical operators for the same"
" filter group"
)
operatorForStack = key
else:
# add the key value pair to the current filter
currentFiltersStack.append({key: value})
if not operatorForStack and len(currentFiltersStack) > 1:
# consider 'and' as the default operator
operatorForStack = allowedLogicalOperators[0]
if operatorForStack:
return {operatorForStack: currentFiltersStack}
return currentFiltersStack.pop()
def _parseQueryFeed(self, feed: "deque[Tuple[str, str]]") -> dict:
""" Parse the query string into a dict. """
filtersDict = {}
special_keys = {"type", "sort"}
integer_keys = {"includeGuids", "limit"}
as_is_keys = {"group", "having"}
reserved_keys = special_keys | integer_keys | as_is_keys
while feed:
key, value = feed.popleft()
if key in integer_keys:
filtersDict[key] = int(value)
elif key in as_is_keys:
filtersDict[key] = value
elif key == "type":
filtersDict["libtype"] = utils.reverseSearchType(value)
elif key == "sort":
filtersDict["sort"] = value.split(",")
else:
feed.appendleft((key, value)) # put the item back
filter_group = self._parseFilterGroups(
feed, returnOn=reserved_keys
)
if "filters" in filtersDict:
filtersDict["filters"] = {
"and": [filtersDict["filters"], filter_group]
}
else:
filtersDict["filters"] = filter_group
return filtersDict
def _parseFilters(self, content):
""" Parse the content string and returns the filter dict. """
content = urlsplit(unquote(content))
filters = {}
filterOp = 'and'
filterGroups = [[]]
feed = deque()
for key, value in parse_qsl(content.query):
# Move = sign to key when operator is ==
if value.startswith('='):
key += '='
value = value[1:]
if value.startswith("="):
key, value = f"{key}=", value[1:]
if key == 'includeGuids':
filters['includeGuids'] = int(value)
elif key == 'type':
filters['libtype'] = utils.reverseSearchType(value)
elif key == 'sort':
filters['sort'] = value.split(',')
elif key == 'limit':
filters['limit'] = int(value)
elif key == 'push':
filterGroups[-1].append([])
filterGroups.append(filterGroups[-1][-1])
elif key == 'and':
filterOp = 'and'
elif key == 'or':
filterOp = 'or'
elif key == 'pop':
filterGroups[-1].insert(0, filterOp)
filterGroups.pop()
else:
filterGroups[-1].append({key: value})
feed.append((key, value))
if filterGroups:
filters['filters'] = self._formatFilterGroups(filterGroups.pop())
return filters
def _formatFilterGroups(self, groups):
""" Formats the filter groups into the advanced search rules. """
if len(groups) == 1 and isinstance(groups[0], list):
groups = groups.pop()
filterOp = 'and'
rules = []
for g in groups:
if isinstance(g, list):
rules.append(self._formatFilterGroups(g))
elif isinstance(g, dict):
rules.append(g)
elif g in {'and', 'or'}:
filterOp = g
return {filterOp: rules}
return self._parseQueryFeed(feed)
class SplitMergeMixin:
@ -281,19 +316,16 @@ class PlayedUnplayedMixin:
return self
@property
@deprecated('use "isPlayed" instead', stacklevel=3)
def isWatched(self):
""" Returns True if the show is watched. """
""" Alias to self.isPlayed. """
return self.isPlayed
@deprecated('use "markPlayed" instead')
def markWatched(self):
""" Mark the video as played. """
""" Alias to :func:`~plexapi.mixins.PlayedUnplayedMixin.markPlayed`. """
self.markPlayed()
@deprecated('use "markUnplayed" instead')
def markUnwatched(self):
""" Mark the video as unplayed. """
""" Alias to :func:`~plexapi.mixins.PlayedUnplayedMixin.markUnplayed`. """
self.markUnplayed()
@ -755,7 +787,8 @@ class EditTagsMixin:
if not remove:
tags = getattr(self, self._tagPlural(tag), [])
items = tags + items
if isinstance(tags, list):
items = tags + items
edits = self._tagHelper(self._tagSingular(tag), items, locked, remove)
edits.update(kwargs)
@ -1163,7 +1196,7 @@ class AlbumEditMixins(
class TrackEditMixins(
ArtLockMixin, PosterLockMixin, ThemeLockMixin,
AddedAtMixin, TitleMixin, TrackArtistMixin, TrackNumberMixin, TrackDiscNumberMixin, UserRatingMixin,
CollectionMixin, LabelMixin, MoodMixin
CollectionMixin, GenreMixin, LabelMixin, MoodMixin
):
pass
@ -1189,3 +1222,10 @@ class CollectionEditMixins(
LabelMixin
):
pass
class PlaylistEditMixins(
ArtLockMixin, PosterLockMixin,
SortTitleMixin, SummaryMixin, TitleMixin
):
pass