Skip to content
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

Add support for updated episodes #34

Merged
merged 2 commits into from
May 2, 2022
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
23 changes: 15 additions & 8 deletions plex_auto_languages/alerts/status.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,25 @@ def process(self, plex: PlexServer):
return
logger.info("[Status] Library scan complete")

# Get all recently added episodes
for section in plex.get_all_show_sections():
recent = section.searchEpisodes(filters={"addedAt>>": "5m"})
if len(recent) == 0:
continue
logger.debug(f"[Status] Found {len(recent)} newly added episode(s) in section {section}")
for item in recent:
added, updated = plex.cache.refresh_library_cache()

# Process recently added episodes
if len(added) > 0:
logger.debug(f"[Status] Found {len(added)} newly added episode(s)")
for item in added:
# Check if the item has already been processed
if item.key in plex.cache.newly_added and plex.cache.newly_added[item.key] == item.addedAt:
continue
plex.cache.newly_added[item.key] = item.addedAt

# Change tracks for all users
logger.info(f"[Status] Processing newly added episode {plex.get_episode_short_name(item)}")
plex.process_new_episode(item.key)
plex.process_new_or_updated_episode(item.key)

# Process updated episodes
if len(updated) > 0:
logger.debug(f"[Status] Found {len(updated)} updated episode(s)")
for item in updated:
# Change tracks for all users
logger.info(f"[Status] Processing updated episode {plex.get_episode_short_name(item)}")
plex.process_new_or_updated_episode(item.key, new=False)
2 changes: 1 addition & 1 deletion plex_auto_languages/alerts/timeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,4 @@ def process(self, plex: PlexServer):

# Change tracks for all users
logger.info(f"[Timeline] Processing newly added episode {plex.get_episode_short_name(item)}")
plex.process_new_episode(self.item_id)
plex.process_new_or_updated_episode(self.item_id)
41 changes: 23 additions & 18 deletions plex_auto_languages/plex_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from plex_auto_languages.plex_alert_handler import PlexAlertHandler
from plex_auto_languages.track_changes import TrackChanges
from plex_auto_languages.utils.notifier import Notifier
from plex_auto_languages.plex_server_cache import PlexServerCache


logger = get_logger()
Expand All @@ -24,12 +25,29 @@ def __init__(self, url: str, token: str):
self._plex_url = url
self._plex = BasePlexServer(url, token)

@property
def unique_id(self):
return self._plex.machineIdentifier

def fetch_item(self, item_id: Union[str, int]):
try:
return self._plex.fetchItem(item_id)
except NotFound:
return None

def episodes(self):
return self._plex.library.all(libtype="episode")

def get_recently_added_episodes(self, minutes: int):
episodes = []
for section in self.get_show_sections():
recent = section.searchEpisodes(filters={"addedAt>>": f"{minutes}m"})
episodes.extend(recent)
return episodes

def get_show_sections(self):
return [s for s in self._plex.library.sections() if isinstance(s, ShowSection)]

@staticmethod
def get_last_watched_or_first_episode(show: Show):
watched_episodes = show.watched()
Expand Down Expand Up @@ -67,7 +85,7 @@ def __init__(self, url: str, token: str, notifier: Notifier, config: Configurati
logger.info(f"Successfully connected as user '{self.username}' (id: {self.user_id})")
self._alert_handler = None
self._alert_listener = None
self.cache = PlexCache()
self.cache = PlexServerCache(self)

@property
def is_alive(self):
Expand Down Expand Up @@ -118,7 +136,7 @@ def get_user_by_id(self, user_id: Union[int, str]):
return None
return matching_users[0]

def process_new_episode(self, item_id: Union[int, str]):
def process_new_or_updated_episode(self, item_id: Union[int, str], new: bool = True):
for user_id in self.get_all_user_ids():
# Switch to the user's Plex instance
user_plex = self.get_plex_instance_of_user(user_id)
Expand All @@ -140,7 +158,7 @@ def process_new_episode(self, item_id: Union[int, str]):
if user is None:
return
self.change_default_tracks_if_needed(user.name, reference, episodes=[user_item], notify=False)
self.notify_new_episode(self.fetch_item(item_id))
self.notify_updated_or_new_episode(self.fetch_item(item_id), new)

def change_default_tracks_if_needed(self, username: str, episode: Episode, episodes: List[Episode] = None,
notify: bool = True):
Expand Down Expand Up @@ -173,8 +191,8 @@ def notify_changes(self, track_changes: TrackChanges):
title = f"PlexAutoLanguages - {track_changes.reference_name}"
self.notifier.notify_user(title, track_changes.description, track_changes.username)

def notify_new_episode(self, episode: Episode):
title = "PlexAutoLanguages - New episode"
def notify_updated_or_new_episode(self, episode: Episode, new: bool):
title = f"PlexAutoLanguages - {'New' if new else 'Updated'} episode"
message = (
f"Episode: {self.get_episode_short_name(episode)}\n"
f"Updated language for all users"
Expand All @@ -185,9 +203,6 @@ def notify_new_episode(self, episode: Episode):
return
self.notifier.notify(title, message)

def get_all_show_sections(self):
return [s for s in self._plex.library.sections() if isinstance(s, ShowSection)]

def start_deep_analysis(self):
min_date = datetime.now() - timedelta(days=1)
history = self._plex.history(mindate=min_date)
Expand All @@ -197,13 +212,3 @@ def start_deep_analysis(self):
continue
episode.reload()
self.change_default_tracks_if_needed(user.name, episode)


class PlexCache():

def __init__(self):
self.session_states = {} # session_key: session_state
self.default_streams = {} # item_key: (audio_stream_id, substitle_stream_id)
self.user_clients = {} # client_identifier: user_id
self.newly_added = {} # episode_id: added_at
self.recent_activities = {} # (user_id, item_id): timestamp
44 changes: 44 additions & 0 deletions plex_auto_languages/plex_server_cache.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
from __future__ import annotations
from typing import TYPE_CHECKING

from plex_auto_languages.utils.logger import get_logger

if TYPE_CHECKING:
from plex_auto_languages.plex_server import PlexServer


logger = get_logger()


class PlexServerCache():

def __init__(self, plex: PlexServer):
self._plex = plex
# Alerts cache
self.session_states = {} # session_key: session_state
self.default_streams = {} # item_key: (audio_stream_id, substitle_stream_id)
self.user_clients = {} # client_identifier: user_id
self.newly_added = {} # episode_id: added_at
self.recent_activities = {} # (user_id, item_id): timestamp
# Library cache
self.episode_parts = {}
# Initialization
logger.info("Scanning all episodes from the library, this action can take a few seconds")
self.refresh_library_cache()
logger.info(f"Scanned {len(self.episode_parts)} episodes from the library")

def refresh_library_cache(self):
logger.debug("[Cache] Refreshing library cache")
added = []
updated = []
new_episode_parts = {}
for episode in self._plex.episodes():
part_list = new_episode_parts.setdefault(episode.key, [])
for part in episode.iterParts():
part_list.append(part.key)
if episode.key in self.episode_parts and set(self.episode_parts[episode.key]) != set(part_list):
updated.append(episode)
elif episode.key not in self.episode_parts:
added.append(episode)
self.episode_parts = new_episode_parts
return added, updated