Source code for papercast_zotero.zotero_subscriber

from websockets.client import connect
from typing import AsyncIterable, List, Dict, Any
import json
from papercast.base import BaseSubscriber
from papercast.production import Production
from papercast_zotero.zotero_types import ZoteroOutput

from pyzotero import zotero


[docs]class ZoteroSubscriber(BaseSubscriber): output_types = {"zotero_output": ZoteroOutput} def __init__(self, api_key: str, library_id: str, library_type: str) -> None: super().__init__() self.url = "wss://stream.zotero.org" self.api_key = api_key self.user_id = library_id self.library_type = library_type self.zot = zotero.Zotero(library_id, library_type, api_key) if self.library_type == "group": topic = f"/groups/{library_id}" elif self.library_type == "user": topic = f"/users/{library_id}" else: raise ValueError("library_type must be 'group' or 'user'") self.subscription_message = { "action": "createSubscriptions", "subscriptions": [ { "apiKey": api_key, "topics": [topic], }, ], } async def _subscribe_topic(self, socket): await socket.send(json.dumps(self.subscription_message)) response = await socket.recv() response_data = json.loads(response) if response_data["event"] == "subscriptionsCreated": errors = response_data.get("errors", []) if len(errors) > 0: raise ValueError(f"Error(s) creating subscriptions: {errors}") else: raise ValueError(f"Unexpected response: {response_data}") def _process_message(self, message) -> Production: message = json.loads(message) if message["event"] == "topicUpdated": print("Received Zotero update.") items = self.zot.top(limit=1) if not len(items) == 1: raise ValueError("Expected one item.") item = items[0] zotero_output = ZoteroOutput(**item) # type: ignore production = Production(zotero_output=zotero_output) return production else: raise ValueError(f"Unexpected message: {message}")
[docs] async def subscribe(self) -> AsyncIterable[Production]: print("Connecting to Zotero websocket...") socket = await connect(self.url) _ = await socket.recv() print("Connected to Zotero websocket.") await self._subscribe_topic(socket) print("Subscribed to Zotero websocket.") async for message in socket: yield self._process_message(message)
if __name__ == "__main__": async def print_output(subscriber): async for production in subscriber.subscribe(): print(production) from dotenv import load_dotenv import os load_dotenv() api_key = os.getenv("PAPERCAST_ZOTERO_API_KEY", None) user_id = os.getenv("PAPERCAST_ZOTERO_USER_ID", None) subscriber = ZoteroSubscriber(api_key, user_id, "user") # type: ignore import asyncio asyncio.run(print_output(subscriber))