Skip to content

Commit

Permalink
Merge pull request #1279 from glensc/cache-patterns-for-plex
Browse files Browse the repository at this point in the history
  • Loading branch information
glensc authored Dec 22, 2022
2 parents 0313cbc + 6ebd0b7 commit 71a1e3a
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 32 deletions.
51 changes: 51 additions & 0 deletions plextraktsync/config/HttpCacheConfig.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
from __future__ import annotations

from dataclasses import dataclass
from datetime import timedelta
from typing import TYPE_CHECKING

from requests_cache import DO_NOT_CACHE

if TYPE_CHECKING:
from requests_cache import ExpirationPatterns

# 3 Months
LONG_EXPIRY = timedelta(weeks=4 * 3)


@dataclass(frozen=True)
class HttpCacheConfig:
Expand All @@ -30,6 +34,53 @@ class HttpCacheConfig:
"*.trakt.tv/users/*/watchlist/shows": DO_NOT_CACHE,
"*.trakt.tv/users/likes/lists": DO_NOT_CACHE,
"*.trakt.tv/users/me": DO_NOT_CACHE,

# Online Plex patterns
"metadata.provider.plex.tv/library/metadata/*/userState": DO_NOT_CACHE,
"metadata.provider.plex.tv/library/metadata/*?*includeUserState=1": DO_NOT_CACHE,
"metadata.provider.plex.tv/library/metadata/*": LONG_EXPIRY,
"metadata.provider.plex.tv/library/sections/watchlist/all": DO_NOT_CACHE,
# plex account
"plex.tv/users/account": DO_NOT_CACHE,

# Plex patterns
# Ratings search
"*/library/sections/*/all?*userRating%3E%3E=-1*": DO_NOT_CACHE,
# len(PlexLibrarySection)
"*/library/sections/*/all?includeCollections=0&X-Plex-Container-Size=0&X-Plex-Container-Start=0": DO_NOT_CACHE,
# __iter__(PlexLibrarySection)
"*/library/sections/*/all?includeGuids=1": DO_NOT_CACHE,
# find_by_title
"*/library/sections/*/all?includeGuids=1&title=*": DO_NOT_CACHE,
# fetch_item, fetch_items
"*/library/sections/*/all?*": DO_NOT_CACHE,
"*/library/sections/*/collections": DO_NOT_CACHE,
# library_sections
"*/library/sections": DO_NOT_CACHE,

# reloads
"*/library/metadata/*?*include*": DO_NOT_CACHE,
# episodes
"*/library/metadata/*/allLeaves": DO_NOT_CACHE,
# find_by_id
"*/library/metadata/*": DO_NOT_CACHE,
# mark played, mark unplayed
"*/:/scrobble?key=*&identifier=com.plexapp.plugins.library": DO_NOT_CACHE,
"*/:/unscrobble?key=&&identifier=com.plexapp.plugins.library": DO_NOT_CACHE,
# playlists
"*/playlists?title=": DO_NOT_CACHE,
"*/playlists/*/items": DO_NOT_CACHE,
"*/library": DO_NOT_CACHE,
# history
"*/status/sessions/history/all": DO_NOT_CACHE,
# has_sessions
"*/status/sessions": DO_NOT_CACHE,
# system_device
"*/devices": DO_NOT_CACHE,
# system_account
"*/accounts": DO_NOT_CACHE,
# version, updated_at
# "*/": DO_NOT_CACHE,
}

@property
Expand Down
23 changes: 2 additions & 21 deletions plextraktsync/plex/PlexApi.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
from plextraktsync.decorators.cached_property import cached_property
from plextraktsync.decorators.flatten import flatten_dict, flatten_list
from plextraktsync.decorators.memoize import memoize
from plextraktsync.decorators.nocache import nocache
from plextraktsync.decorators.retry import retry
from plextraktsync.factory import factory, logger
from plextraktsync.plex.PlexLibraryItem import PlexLibraryItem
Expand Down Expand Up @@ -62,7 +61,6 @@ def show_sections(self, library=None) -> List[PlexLibrarySection]:
yield section

@memoize
@nocache
@retry()
def fetch_item(self, key: Union[int, str]) -> Optional[PlexLibraryItem]:
try:
Expand Down Expand Up @@ -98,17 +96,14 @@ def search(self, title: str, **kwargs):
yield PlexLibraryItem(media, plex=self)

@cached_property
@nocache
def version(self):
return self.plex.version

@cached_property
@nocache
def updated_at(self):
return self.plex.updatedAt

@cached_property
@nocache
@flatten_dict
def library_sections(self) -> Dict[int, PlexLibrarySection]:
excluded_libraries = factory.config["excluded-libraries"]
Expand All @@ -122,12 +117,10 @@ def library_section_names(self):
return [s.title for s in self.library_sections.values()]

@memoize
@nocache
def system_device(self, device_id: int) -> SystemDevice:
return self.plex.systemDevice(device_id)

@memoize
@nocache
def system_account(self, account_id: int) -> SystemAccount:
return self.plex.systemAccount(account_id)

Expand All @@ -137,7 +130,6 @@ def ratings(self):

return PlexRatings(self)

@nocache
@retry()
def rate(self, m, rating):
m.rate(rating)
Expand All @@ -159,7 +151,6 @@ def same_list(list_a: List[PlexMedia], list_b: List[PlexMedia]) -> bool:

return a == b

@nocache
def update_playlist(self, name: str, items: List[PlexMedia], description=None) -> bool:
"""
Updates playlist (creates if name missing) replacing contents with items[]
Expand Down Expand Up @@ -188,7 +179,6 @@ def update_playlist(self, name: str, items: List[PlexMedia], description=None) -
playlist.addItems(items)
return True

@nocache
@flatten_list
def history(self, m, device=False, account=False):
try:
Expand All @@ -204,43 +194,38 @@ def history(self, m, device=False, account=False):
h.account = self.system_account(h.accountID)
yield h

@nocache
@retry()
def mark_watched(self, m):
m.markPlayed()

@nocache
@retry()
def mark_unwatched(self, m):
m.markUnplayed()

@nocache
def has_sessions(self):
try:
self.plex.sessions()
return True
except Unauthorized:
return False

@nocache
def get_sessions(self):
return self.plex.sessions()

@nocache
def _plex_account(self):
CONFIG = factory.config
plex_owner_token = CONFIG.get("PLEX_OWNER_TOKEN")
plex_account_token = CONFIG.get("PLEX_ACCOUNT_TOKEN")
plex_username = CONFIG.get("PLEX_USERNAME")
if plex_owner_token:
try:
plex_owner_account = MyPlexAccount(token=plex_owner_token)
plex_owner_account = MyPlexAccount(token=plex_owner_token, session=factory.session)
return plex_owner_account.switchHomeUser(plex_username)
except BadRequest as e:
logger.error(f"Error during {plex_username} account access: {e}")
elif plex_account_token:
try:
return MyPlexAccount(token=plex_account_token)
return MyPlexAccount(token=plex_account_token, session=factory.session)
except BadRequest as e:
logger.error(f"Error during {plex_username} account access: {e}")
else:
Expand All @@ -250,7 +235,6 @@ def _plex_account(self):
logger.error(f"Error during {plex_username} account access: {e}")
return None

@nocache
def watchlist(self) -> Optional[List[Union[Movie, Show]]]:
if self.account:
try:
Expand All @@ -259,14 +243,12 @@ def watchlist(self) -> Optional[List[Union[Movie, Show]]]:
logger.error(f"Error during {self.account.username} watchlist access: {e}")
return None

@nocache
def add_to_watchlist(self, item):
try:
self.account.addToWatchlist(item)
except BadRequest as e:
logger.error(f"Error when adding {item.title} to Plex watchlist: {e}")

@nocache
def remove_from_watchlist(self, item):
try:
self.account.removeFromWatchlist(item)
Expand All @@ -286,7 +268,6 @@ def search_online(self, title: str, media_type: str):
return None
return map(PlexLibraryItem, result)

@nocache
def reset_show(self, show: Show, reset_date: datetime):
reset_count = 0
for ep in show.watched():
Expand Down
5 changes: 0 additions & 5 deletions plextraktsync/plex/PlexLibraryItem.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

from plextraktsync.decorators.cached_property import cached_property
from plextraktsync.decorators.flatten import flatten_list
from plextraktsync.decorators.nocache import nocache
from plextraktsync.decorators.retry import retry
from plextraktsync.factory import factory
from plextraktsync.plex.PlexGuid import PlexGuid
Expand All @@ -31,7 +30,6 @@ def __init__(self, item: PlexMedia, plex: PlexApi = None):
def is_legacy_agent(self):
return not self.item.guid.startswith("plex://")

@nocache
@retry()
def get_guids(self):
return self.item.guids
Expand Down Expand Up @@ -101,7 +99,6 @@ def title(self):

return value

@nocache
@retry(retries=1)
def rating(self, show_id: int = None):
if self.plex is not None:
Expand All @@ -119,7 +116,6 @@ def seen_date(self):
return self.date_value(self.item.lastViewedAt)

@property
@nocache
def is_watched(self):
return self.item.isPlayed

Expand Down Expand Up @@ -259,7 +255,6 @@ def episodes(self):
for ep in self._get_episodes():
yield PlexLibraryItem(ep, plex=self.plex)

@nocache
@retry()
def _get_episodes(self):
return self.item.episodes()
Expand Down
9 changes: 3 additions & 6 deletions plextraktsync/plex/PlexLibrarySection.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
from plexapi import X_PLEX_CONTAINER_SIZE
from plexapi.exceptions import NotFound

from plextraktsync.decorators.nocache import nocache
from plextraktsync.decorators.retry import retry
from plextraktsync.plex.PlexLibraryItem import PlexLibraryItem

Expand All @@ -23,10 +22,12 @@ def __init__(self, section: LibrarySection, plex: PlexApi = None):
self.section = section
self.plex = plex

@nocache
def __len__(self):
return self.section.totalSize

def __iter__(self):
return self.items(len(self))

@property
def type(self):
return self.section.type
Expand All @@ -35,18 +36,15 @@ def type(self):
def title(self):
return self.section.title

@nocache
def find_by_title(self, name: str):
try:
return self.section.get(name)
except NotFound:
return None

@nocache
def search(self, **kwargs):
return self.section.search(**kwargs)

@nocache
def find_by_id(self, id: Union[str, int]) -> Optional[PlexMedia]:
try:
return self.section.fetchItem(int(id))
Expand All @@ -70,7 +68,6 @@ def all(self, max_items: int):
if start > max_items:
break

@nocache
@retry()
def fetch_items(self, key: str, size: int, start: int):
return self.section.fetchItems(key, container_start=start, container_size=size)
Expand Down

0 comments on commit 71a1e3a

Please sign in to comment.