mirror of
https://github.com/phin05/discord-rich-presence-plex
synced 2024-11-24 18:43:02 +00:00
Added additional display configuration fields
This commit is contained in:
parent
4d4c312ee1
commit
11efd871e0
5 changed files with 54 additions and 25 deletions
|
@ -13,8 +13,12 @@ config: models.config.Config = {
|
||||||
"writeToFile": False,
|
"writeToFile": False,
|
||||||
},
|
},
|
||||||
"display": {
|
"display": {
|
||||||
"hideTotalTime": False,
|
"duration": True,
|
||||||
"useRemainingTime": False,
|
"genres": True,
|
||||||
|
"album": True,
|
||||||
|
"year": True,
|
||||||
|
"remainingTime": False,
|
||||||
|
"paused": False,
|
||||||
"posters": {
|
"posters": {
|
||||||
"enabled": False,
|
"enabled": False,
|
||||||
"imgurClientID": "",
|
"imgurClientID": "",
|
||||||
|
@ -57,6 +61,12 @@ def loadConfig() -> None:
|
||||||
logger.exception("Failed to parse the config file. A new one will be created.")
|
logger.exception("Failed to parse the config file. A new one will be created.")
|
||||||
else:
|
else:
|
||||||
copyDict(loadedConfig, config)
|
copyDict(loadedConfig, config)
|
||||||
|
if "hideTotalTime" in config["display"]:
|
||||||
|
config["display"]["duration"] = not config["display"]["hideTotalTime"]
|
||||||
|
del config["display"]["hideTotalTime"]
|
||||||
|
if "useRemainingTime" in config["display"]:
|
||||||
|
config["display"]["remainingTime"] = config["display"]["useRemainingTime"]
|
||||||
|
del config["display"]["useRemainingTime"]
|
||||||
saveConfig()
|
saveConfig()
|
||||||
|
|
||||||
class YamlSafeDumper(yaml.SafeDumper):
|
class YamlSafeDumper(yaml.SafeDumper):
|
||||||
|
|
34
core/plex.py
34
core/plex.py
|
@ -10,7 +10,7 @@ from plexapi.myplex import MyPlexAccount, PlexServer
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from utils.cache import getCacheKey, setCacheKey
|
from utils.cache import getCacheKey, setCacheKey
|
||||||
from utils.logging import LoggerWithPrefix
|
from utils.logging import LoggerWithPrefix
|
||||||
from utils.text import formatSeconds, truncate
|
from utils.text import formatSeconds, truncate, stripNonAscii
|
||||||
import models.config
|
import models.config
|
||||||
import models.discord
|
import models.discord
|
||||||
import models.plex
|
import models.plex
|
||||||
|
@ -186,6 +186,7 @@ class PlexAlertListener(threading.Thread):
|
||||||
if "whitelistedLibraries" in self.serverConfig and libraryName not in self.serverConfig["whitelistedLibraries"]:
|
if "whitelistedLibraries" in self.serverConfig and libraryName not in self.serverConfig["whitelistedLibraries"]:
|
||||||
self.logger.debug("Library '%s' is not whitelisted, ignoring", libraryName)
|
self.logger.debug("Library '%s' is not whitelisted, ignoring", libraryName)
|
||||||
return
|
return
|
||||||
|
isIgnorableState = state == "stopped" or (state == "paused" and not config["display"]["paused"])
|
||||||
if self.lastSessionKey == sessionKey and self.lastRatingKey == ratingKey:
|
if self.lastSessionKey == sessionKey and self.lastRatingKey == ratingKey:
|
||||||
if self.updateTimeoutTimer:
|
if self.updateTimeoutTimer:
|
||||||
self.updateTimeoutTimer.cancel()
|
self.updateTimeoutTimer.cancel()
|
||||||
|
@ -198,11 +199,11 @@ class PlexAlertListener(threading.Thread):
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
self.ignoreCount = 0
|
self.ignoreCount = 0
|
||||||
if state == "stopped":
|
if isIgnorableState:
|
||||||
self.disconnectRpc()
|
self.disconnectRpc()
|
||||||
return
|
return
|
||||||
elif state == "stopped":
|
elif isIgnorableState:
|
||||||
self.logger.debug("Received 'stopped' state alert from unknown session, ignoring")
|
self.logger.debug("Received '%s' state alert from unknown session, ignoring", state)
|
||||||
return
|
return
|
||||||
if self.isServerOwner:
|
if self.isServerOwner:
|
||||||
self.logger.debug("Searching sessions for session key %s", sessionKey)
|
self.logger.debug("Searching sessions for session key %s", sessionKey)
|
||||||
|
@ -229,13 +230,13 @@ class PlexAlertListener(threading.Thread):
|
||||||
self.updateTimeoutTimer.start()
|
self.updateTimeoutTimer.start()
|
||||||
self.lastState, self.lastSessionKey, self.lastRatingKey = state, sessionKey, ratingKey
|
self.lastState, self.lastSessionKey, self.lastRatingKey = state, sessionKey, ratingKey
|
||||||
stateStrings: list[str] = []
|
stateStrings: list[str] = []
|
||||||
if not config["display"]["hideTotalTime"] and item.duration and mediaType != "track":
|
if config["display"]["duration"] and item.duration and mediaType != "track":
|
||||||
stateStrings.append(formatSeconds(item.duration / 1000))
|
stateStrings.append(formatSeconds(item.duration / 1000))
|
||||||
if mediaType == "movie":
|
if mediaType == "movie":
|
||||||
title = shortTitle = item.title
|
title = shortTitle = item.title
|
||||||
if item.year:
|
if config["display"]["year"] and item.year:
|
||||||
title += f" ({item.year})"
|
title += f" ({item.year})"
|
||||||
if item.genres:
|
if config["display"]["genres"] and item.genres:
|
||||||
genres: list[Genre] = item.genres[:3]
|
genres: list[Genre] = item.genres[:3]
|
||||||
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"
|
||||||
|
@ -244,6 +245,7 @@ class PlexAlertListener(threading.Thread):
|
||||||
smallThumb = ""
|
smallThumb = ""
|
||||||
elif mediaType == "episode":
|
elif mediaType == "episode":
|
||||||
title = shortTitle = item.grandparentTitle
|
title = shortTitle = item.grandparentTitle
|
||||||
|
if config["display"]["year"]:
|
||||||
grandparent = self.server.fetchItem(item.grandparentRatingKey)
|
grandparent = self.server.fetchItem(item.grandparentRatingKey)
|
||||||
if grandparent.year:
|
if grandparent.year:
|
||||||
title += f" ({grandparent.year})"
|
title += f" ({grandparent.year})"
|
||||||
|
@ -263,13 +265,17 @@ class PlexAlertListener(threading.Thread):
|
||||||
smallThumb = ""
|
smallThumb = ""
|
||||||
elif mediaType == "track":
|
elif mediaType == "track":
|
||||||
title = shortTitle = item.title
|
title = shortTitle = item.title
|
||||||
|
smallText = item.originalTitle or item.grandparentTitle
|
||||||
|
if config["display"]["album"]:
|
||||||
largeText = item.parentTitle
|
largeText = item.parentTitle
|
||||||
|
if config["display"]["year"]:
|
||||||
parent = self.server.fetchItem(item.parentRatingKey)
|
parent = self.server.fetchItem(item.parentRatingKey)
|
||||||
if parent.year:
|
if parent.year:
|
||||||
largeText += f" ({parent.year})"
|
largeText += f" ({parent.year})"
|
||||||
thumb = item.thumb
|
|
||||||
smallText = item.originalTitle or item.grandparentTitle
|
|
||||||
stateStrings.append(smallText)
|
stateStrings.append(smallText)
|
||||||
|
else:
|
||||||
|
largeText = smallText
|
||||||
|
thumb = item.thumb
|
||||||
smallThumb = item.grandparentThumb
|
smallThumb = item.grandparentThumb
|
||||||
else:
|
else:
|
||||||
title = shortTitle = item.title
|
title = shortTitle = item.title
|
||||||
|
@ -278,7 +284,7 @@ class PlexAlertListener(threading.Thread):
|
||||||
smallText = ""
|
smallText = ""
|
||||||
smallThumb = ""
|
smallThumb = ""
|
||||||
if state != "playing" and mediaType != "track":
|
if state != "playing" and mediaType != "track":
|
||||||
if config["display"]["useRemainingTime"]:
|
if config["display"]["remainingTime"]:
|
||||||
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")
|
||||||
|
@ -287,7 +293,7 @@ class PlexAlertListener(threading.Thread):
|
||||||
smallThumbUrl = self.uploadToImgur(smallThumb) if smallThumb and config["display"]["posters"]["enabled"] else ""
|
smallThumbUrl = self.uploadToImgur(smallThumb) if smallThumb and config["display"]["posters"]["enabled"] else ""
|
||||||
activity: models.discord.Activity = {
|
activity: models.discord.Activity = {
|
||||||
"type": mediaTypeActivityTypeMap[mediaType],
|
"type": mediaTypeActivityTypeMap[mediaType],
|
||||||
"details": truncate(title, 128),
|
"details": truncate(title, 120),
|
||||||
"assets": {
|
"assets": {
|
||||||
"large_text": largeText,
|
"large_text": largeText,
|
||||||
"large_image": thumbUrl or "logo",
|
"large_image": thumbUrl or "logo",
|
||||||
|
@ -296,7 +302,7 @@ class PlexAlertListener(threading.Thread):
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if stateText:
|
if stateText:
|
||||||
activity["state"] = truncate(stateText, 128)
|
activity["state"] = truncate(stateText, 120)
|
||||||
if config["display"]["buttons"]:
|
if config["display"]["buttons"]:
|
||||||
guidsRaw: list[Guid] = []
|
guidsRaw: list[Guid] = []
|
||||||
if mediaType in ["movie", "track"]:
|
if mediaType in ["movie", "track"]:
|
||||||
|
@ -308,7 +314,7 @@ class PlexAlertListener(threading.Thread):
|
||||||
for button in config["display"]["buttons"]:
|
for button in config["display"]["buttons"]:
|
||||||
if "mediaTypes" in button and mediaType not in button["mediaTypes"]:
|
if "mediaTypes" in button and mediaType not in button["mediaTypes"]:
|
||||||
continue
|
continue
|
||||||
label = truncate(button["label"].format(title = shortTitle), 32)
|
label = truncate(button["label"].format(title = stripNonAscii(shortTitle)), 30)
|
||||||
if not button["url"].startswith("dynamic:"):
|
if not button["url"].startswith("dynamic:"):
|
||||||
buttons.append({ "label": label, "url": button["url"] })
|
buttons.append({ "label": label, "url": button["url"] })
|
||||||
continue
|
continue
|
||||||
|
@ -341,7 +347,7 @@ class PlexAlertListener(threading.Thread):
|
||||||
activity["buttons"] = buttons[:2]
|
activity["buttons"] = buttons[:2]
|
||||||
if state == "playing":
|
if state == "playing":
|
||||||
currentTimestamp = int(time.time() * 1000)
|
currentTimestamp = int(time.time() * 1000)
|
||||||
if config["display"]["useRemainingTime"]:
|
if config["display"]["remainingTime"]:
|
||||||
activity["timestamps"] = { "end": round(currentTimestamp + (item.duration - viewOffset)) }
|
activity["timestamps"] = { "end": round(currentTimestamp + (item.duration - viewOffset)) }
|
||||||
else:
|
else:
|
||||||
activity["timestamps"] = { "start": round(currentTimestamp - viewOffset) }
|
activity["timestamps"] = { "start": round(currentTimestamp - viewOffset) }
|
||||||
|
|
5
main.py
5
main.py
|
@ -86,6 +86,11 @@ def main() -> None:
|
||||||
userInput = input()
|
userInput = input()
|
||||||
if userInput in ["exit", "quit"]:
|
if userInput in ["exit", "quit"]:
|
||||||
raise KeyboardInterrupt
|
raise KeyboardInterrupt
|
||||||
|
elif userInput == "reload-config":
|
||||||
|
loadConfig()
|
||||||
|
print("Config reloaded from file")
|
||||||
|
else:
|
||||||
|
print("Unrecognised command")
|
||||||
else:
|
else:
|
||||||
while True:
|
while True:
|
||||||
time.sleep(3600)
|
time.sleep(3600)
|
||||||
|
|
|
@ -15,8 +15,12 @@ class Button(TypedDict):
|
||||||
mediaTypes: list[str]
|
mediaTypes: list[str]
|
||||||
|
|
||||||
class Display(TypedDict):
|
class Display(TypedDict):
|
||||||
hideTotalTime: bool
|
duration: bool
|
||||||
useRemainingTime: bool
|
genres: bool
|
||||||
|
album: bool
|
||||||
|
year: bool
|
||||||
|
remainingTime: bool
|
||||||
|
paused: bool
|
||||||
posters: Posters
|
posters: Posters
|
||||||
buttons: list[Button]
|
buttons: list[Button]
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
import re
|
||||||
|
|
||||||
def formatSeconds(seconds: int | float, joiner: Optional[str] = None) -> str:
|
def formatSeconds(seconds: int | float, joiner: Optional[str] = None) -> str:
|
||||||
seconds = round(seconds)
|
seconds = round(seconds)
|
||||||
|
@ -13,3 +14,6 @@ def truncate(text: str, maxLength: int) -> str:
|
||||||
if len(text) > maxLength:
|
if len(text) > maxLength:
|
||||||
text = text[:maxLength-3] + "..."
|
text = text[:maxLength-3] + "..."
|
||||||
return text
|
return text
|
||||||
|
|
||||||
|
def stripNonAscii(text: str) -> str:
|
||||||
|
return re.sub(r"[^\x00-\x7f]", "", text)
|
||||||
|
|
Loading…
Reference in a new issue