Rich Presence changes in accordance with Discord updates

This commit is contained in:
Phin 2024-08-31 00:17:55 +05:30
parent 51e54394cf
commit 4d4c312ee1
2 changed files with 43 additions and 20 deletions

View file

@ -33,7 +33,13 @@ def getAuthToken(id: str, code: str) -> Optional[str]:
}).json() }).json()
return response["authToken"] return response["authToken"]
validMediaTypes = ["movie", "episode", "live_episode", "track", "clip"] mediaTypeActivityTypeMap = {
"movie": models.discord.ActivityType.WATCHING,
"episode": models.discord.ActivityType.WATCHING,
"live_episode": models.discord.ActivityType.WATCHING,
"track": models.discord.ActivityType.LISTENING,
"clip": models.discord.ActivityType.WATCHING,
}
buttonTypeGuidTypeMap = { buttonTypeGuidTypeMap = {
"imdb": "imdb", "imdb": "imdb",
"tmdb": "tmdb", "tmdb": "tmdb",
@ -131,7 +137,6 @@ class PlexAlertListener(threading.Thread):
def connectionCheck(self) -> None: def connectionCheck(self) -> None:
try: try:
self.logger.debug("Running periodic connection check") self.logger.debug("Running periodic connection check")
assert self.server
self.server.clients() self.server.clients()
except Exception as e: except Exception as e:
self.reconnect(e) self.reconnect(e)
@ -146,19 +151,26 @@ class PlexAlertListener(threading.Thread):
self.logger.exception("An unexpected error occured in the Plex alert handler") self.logger.exception("An unexpected error occured in the Plex alert handler")
self.disconnectRpc() self.disconnectRpc()
def uploadToImgur(self, thumb: str) -> Optional[str]:
thumbUrl = getCacheKey(thumb)
if not thumbUrl or not isinstance(thumbUrl, str):
self.logger.debug("Uploading image to Imgur")
thumbUrl = uploadToImgur(self.server.url(thumb, True))
setCacheKey(thumb, thumbUrl)
return thumbUrl
def handleAlert(self, alert: models.plex.Alert) -> None: def handleAlert(self, alert: models.plex.Alert) -> None:
if alert["type"] != "playing" or "PlaySessionStateNotification" not in alert: if alert["type"] != "playing" or "PlaySessionStateNotification" not in alert:
return return
stateNotification = alert["PlaySessionStateNotification"][0] stateNotification = alert["PlaySessionStateNotification"][0]
self.logger.debug("Received alert: %s", stateNotification) self.logger.debug("Received alert: %s", stateNotification)
ratingKey = int(stateNotification["ratingKey"]) ratingKey = int(stateNotification["ratingKey"])
assert self.server
item = self.server.fetchItem(ratingKey) item = self.server.fetchItem(ratingKey)
if item.key and item.key.startswith("/livetv"): if item.key and item.key.startswith("/livetv"):
mediaType = "live_episode" mediaType = "live_episode"
else: else:
mediaType = item.type mediaType = item.type
if mediaType not in validMediaTypes: if mediaType not in mediaTypeActivityTypeMap:
self.logger.debug("Unsupported media type '%s', ignoring", mediaType) self.logger.debug("Unsupported media type '%s', ignoring", mediaType)
return return
state = stateNotification["state"] state = stateNotification["state"]
@ -228,6 +240,8 @@ class PlexAlertListener(threading.Thread):
stateStrings.append(f"{', '.join(genre.tag for genre in genres)}") stateStrings.append(f"{', '.join(genre.tag for genre in genres)}")
largeText = "Watching a movie" largeText = "Watching a movie"
thumb = item.thumb thumb = item.thumb
smallText = ""
smallThumb = ""
elif mediaType == "episode": elif mediaType == "episode":
title = shortTitle = item.grandparentTitle title = shortTitle = item.grandparentTitle
grandparent = self.server.fetchItem(item.grandparentRatingKey) grandparent = self.server.fetchItem(item.grandparentRatingKey)
@ -237,45 +251,48 @@ class PlexAlertListener(threading.Thread):
stateStrings.append(item.title) stateStrings.append(item.title)
largeText = "Watching a TV show" largeText = "Watching a TV show"
thumb = item.grandparentThumb thumb = item.grandparentThumb
smallText = ""
smallThumb = ""
elif mediaType == "live_episode": elif mediaType == "live_episode":
title = shortTitle = item.grandparentTitle title = shortTitle = item.grandparentTitle
if item.title != item.grandparentTitle: if item.title != item.grandparentTitle:
stateStrings.append(item.title) stateStrings.append(item.title)
largeText = "Watching live TV" largeText = "Watching live TV"
thumb = item.grandparentThumb thumb = item.grandparentThumb
smallText = ""
smallThumb = ""
elif mediaType == "track": elif mediaType == "track":
title = shortTitle = item.title title = shortTitle = item.title
artistAlbum = f"{item.originalTitle or item.grandparentTitle} - {item.parentTitle}" largeText = item.parentTitle
parent = self.server.fetchItem(item.parentRatingKey) parent = self.server.fetchItem(item.parentRatingKey)
if parent.year: if parent.year:
artistAlbum += f" ({parent.year})" largeText += f" ({parent.year})"
stateStrings.append(artistAlbum)
largeText = "Listening to music"
thumb = item.thumb thumb = item.thumb
smallText = item.originalTitle or item.grandparentTitle
stateStrings.append(smallText)
smallThumb = item.grandparentThumb
else: else:
title = shortTitle = item.title title = shortTitle = item.title
largeText = "Watching a video" largeText = "Watching a video"
thumb = item.thumb thumb = item.thumb
smallText = ""
smallThumb = ""
if state != "playing" and mediaType != "track": if state != "playing" and mediaType != "track":
if config["display"]["useRemainingTime"]: if config["display"]["useRemainingTime"]:
stateStrings.append(f"{formatSeconds((item.duration - viewOffset) / 1000, ':')} left") stateStrings.append(f"{formatSeconds((item.duration - viewOffset) / 1000, ':')} left")
else: else:
stateStrings.append(f"{formatSeconds(viewOffset / 1000, ':')} elapsed") stateStrings.append(f"{formatSeconds(viewOffset / 1000, ':')} elapsed")
stateText = " · ".join(stateString for stateString in stateStrings if stateString) stateText = " · ".join(stateString for stateString in stateStrings if stateString)
thumbUrl = "" thumbUrl = self.uploadToImgur(thumb) if thumb and config["display"]["posters"]["enabled"] else ""
if thumb and config["display"]["posters"]["enabled"]: smallThumbUrl = self.uploadToImgur(smallThumb) if smallThumb and config["display"]["posters"]["enabled"] else ""
thumbUrl = getCacheKey(thumb)
if not thumbUrl or not isinstance(thumbUrl, str):
self.logger.debug("Uploading poster to Imgur")
thumbUrl = uploadToImgur(self.server.url(thumb, True))
setCacheKey(thumb, thumbUrl)
activity: models.discord.Activity = { activity: models.discord.Activity = {
"type": mediaTypeActivityTypeMap[mediaType],
"details": truncate(title, 128), "details": truncate(title, 128),
"assets": { "assets": {
"large_text": largeText, "large_text": largeText,
"large_image": thumbUrl or "logo", "large_image": thumbUrl or "logo",
"small_text": state.capitalize(), "small_text": smallText or state.capitalize(),
"small_image": state, "small_image": smallThumbUrl or state,
}, },
} }
if stateText: if stateText:
@ -323,11 +340,11 @@ class PlexAlertListener(threading.Thread):
if buttons: if buttons:
activity["buttons"] = buttons[:2] activity["buttons"] = buttons[:2]
if state == "playing": if state == "playing":
currentTimestamp = int(time.time()) currentTimestamp = int(time.time() * 1000)
if config["display"]["useRemainingTime"]: if config["display"]["useRemainingTime"]:
activity["timestamps"] = { "end": round(currentTimestamp + ((item.duration - viewOffset) / 1000)) } activity["timestamps"] = { "end": round(currentTimestamp + (item.duration - viewOffset)) }
else: else:
activity["timestamps"] = { "start": round(currentTimestamp - (viewOffset / 1000)) } activity["timestamps"] = { "start": round(currentTimestamp - viewOffset) }
if not self.discordIpcService.connected: if not self.discordIpcService.connected:
self.discordIpcService.connect() self.discordIpcService.connect()
if self.discordIpcService.connected: if self.discordIpcService.connected:

View file

@ -1,5 +1,10 @@
from enum import IntEnum
from typing import TypedDict from typing import TypedDict
class ActivityType(IntEnum):
LISTENING = 2
WATCHING = 3
class ActivityAssets(TypedDict): class ActivityAssets(TypedDict):
large_text: str large_text: str
large_image: str large_image: str
@ -15,6 +20,7 @@ class ActivityButton(TypedDict):
url: str url: str
class Activity(TypedDict, total = False): class Activity(TypedDict, total = False):
type: ActivityType
details: str details: str
state: str state: str
assets: ActivityAssets assets: ActivityAssets