Refactor to use improved event listener
MODIFY
plex_trakt_sync/commands/watch.py
plex_trakt_sync/commands/watch.py
import click
+from plex_trakt_sync.events import PlaySessionStateNotification
from plex_trakt_sync.factory import factory
-from plex_trakt_sync.listener import PLAYING, WebSocketListener
+from plex_trakt_sync.listener import WebSocketListener
from plex_trakt_sync.plex_api import PlexApi
from plex_trakt_sync.trakt_api import TraktApi
@@ -22,16 +23,22 @@ def __init__(self, plex: PlexApi, trakt: TraktApi):
self.trakt = trakt
self.scrobblers = ScrobblerCollection(trakt)
- def __call__(self, message):
- for pm, tm, item in self.filter_media(message):
+ def on_play(self, event: PlaySessionStateNotification):
+ pm = self.plex.fetch_item(event.key)
+ print(f"Found {pm}")
+ if not pm:
+ return
+
+ tm = self.trakt.find_by_media(pm)
+ if not tm:
+ return
+
movie = pm.item
- percent = pm.watch_progress(item["viewOffset"])
+ percent = pm.watch_progress(event.view_offset)
- print("%r: %.6F%% Watched: %s, LastViewed: %s" % (
- movie, percent, movie.isWatched, movie.lastViewedAt
- ))
+ print(f"{movie}: {percent:.6F}% Watched: {movie.isWatched}, LastViewed: {movie.lastViewedAt}")
- self.scrobble(tm, percent, item["state"])
+ self.scrobble(tm, percent, event.state)
def scrobble(self, tm, percent, state):
if state == "playing":
@@ -44,40 +51,6 @@ def scrobble(self, tm, percent, state):
self.scrobblers[tm].stop()
del self.scrobblers[tm]
- def filter_media(self, message):
- for item in self.filter_playing(message):
- pm = self.plex.fetch_item(int(item["ratingKey"]))
- print(f"Found {pm}")
- if not pm:
- continue
-
- tm = self.trakt.find_by_media(pm)
- if not tm:
- continue
-
- yield pm, tm, item
-
- def filter_playing(self, message):
- """
- {'sessionKey': '23', 'guid': '', 'ratingKey': '9725', 'url': '', 'key': '/library/metadata/9725', 'viewOffset': 0, 'playQueueItemID': 17679, 'state': 'playing'}
- {'sessionKey': '23', 'guid': '', 'ratingKey': '9725', 'url': '', 'key': '/library/metadata/9725', 'viewOffset': 10000, 'playQueueItemID': 17679, 'state': 'playing', 'transcodeSession': '18nyclub53k1ey37jjbg8ok3'}
- {'sessionKey': '23', 'guid': '', 'ratingKey': '9725', 'url': '', 'key': '/library/metadata/9725', 'viewOffset': 20000, 'playQueueItemID': 17679, 'state': 'playing', 'transcodeSession': '18nyclub53k1ey37jjbg8ok3'}
- {'sessionKey': '23', 'guid': '', 'ratingKey': '9725', 'url': '', 'key': '/library/metadata/9725', 'viewOffset': 30000, 'playQueueItemID': 17679, 'state': 'playing', 'transcodeSession': '18nyclub53k1ey37jjbg8ok3'}
- {'sessionKey': '23', 'guid': '', 'ratingKey': '9725', 'url': '', 'key': '/library/metadata/9725', 'viewOffset': 30000, 'playQueueItemID': 17679, 'state': 'paused', 'transcodeSession': '18nyclub53k1ey37jjbg8ok3'}
- {'sessionKey': '23', 'guid': '', 'ratingKey': '9725', 'url': '', 'key': '/library/metadata/9725', 'viewOffset': 30000, 'playQueueItemID': 17679, 'state': 'paused', 'transcodeSession': '18nyclub53k1ey37jjbg8ok3'}
- """
-
- if message["size"] != 1:
- raise ValueError("Unexpected size: %r" % message)
-
- for item in message["PlaySessionStateNotification"]:
- state = item["state"]
- print(f"State: {state}")
- if state not in ["playing", "stopped", "paused"]:
- continue
-
- yield item
-
@click.command()
def watch():
@@ -90,6 +63,8 @@ def watch():
plex = factory.plex_api()
ws = WebSocketListener(server)
- ws.on(PLAYING, WatchStateUpdater(plex, trakt))
+ updater = WatchStateUpdater(plex, trakt)
+ ws.on(PlaySessionStateNotification, updater.on_play, state=["playing", "stopped", "paused"])
+
print("Listening for events!")
ws.listen()

MODIFY
plex_trakt_sync/listener.py
plex_trakt_sync/listener.py
from plexapi.server import PlexServer
+from plex_trakt_sync.events import EventFactory
from plex_trakt_sync.logging import logging
PLAYING = "playing"
@@ -11,24 +12,44 @@ class WebSocketListener:
def __init__(self, plex: PlexServer, interval=1):
self.plex = plex
self.interval = interval
- self.event_handlers = {}
+ self.event_listeners = list()
+ self.event_factory = EventFactory()
self.logger = logging.getLogger("PlexTraktSync.WebSocketListener")
- def on(self, event_name, handler):
- if event_name not in self.event_handlers:
- self.event_handlers[event_name] = []
+ def on(self, event_type, listener, **kwargs):
+ self.event_listeners.append({
+ "listener": listener,
+ "event_type": event_type,
+ "filters": kwargs,
+ })
- self.event_handlers[event_name].append(handler)
+ def dispatch(self, event):
+ for listener in self.event_listeners:
+ if not self.is_candidate(event, listener):
+ continue
+
+ listener["listener"](event)
+
+ @staticmethod
+ def is_candidate(event, listener):
+ if not isinstance(event, listener["event_type"]):
+ return False
+
+ if listener["filters"]:
+ for name, value in listener["filters"].items():
+ if name not in event:
+ return False
+ if event[name] not in value:
+ return False
+
+ return True
def listen(self):
def handler(data):
self.logger.debug(data)
- event_type = data['type']
- if event_type not in self.event_handlers:
- return
-
- for handler in self.event_handlers[event_type]:
- handler(data)
+ events = self.event_factory.get_events(data)
+ for event in events:
+ self.dispatch(event)
while True:
notifier = self.plex.startAlertListener(callback=handler)

Refactor to use improved event listener