Added more dynamic button URL placeholders

This commit is contained in:
Phin 2024-02-11 01:50:56 +05:30
parent 31e9628f26
commit eeeb680877
3 changed files with 54 additions and 88 deletions

View file

@ -45,6 +45,7 @@ The config file is stored in a directory named `data`.
* `buttons` (list) - [Information](#buttons)
* `label` (string) - The label to be displayed on the button.
* `url` (string) - A web address or a [dynamic URL placeholder](#dynamic-button-urls).
* `mediaTypes` (list, optional) - If set, the button is displayed only for the specified media types. Valid media types are `movie`, `episode` and `track`.
* `users` (list)
* `token` (string) - An access token associated with your Plex account. ([X-Plex-Token](https://support.plex.tv/articles/204059436-finding-an-authentication-token-x-plex-token/), [Authenticating with Plex](https://forums.plex.tv/t/authenticating-with-plex/609370))
* `servers` (list)
@ -69,16 +70,15 @@ Due to a strange Discord bug, these buttons may be unresponsive or exhibit stran
#### Dynamic Button URLs
During runtime, the following dynamic URL placeholders will get replaced with real URLs based on the media being played:
* `dynamic:imdb`
* `dynamic:tmdb`
* `dynamic:thetvdb`
* `dynamic:trakt`
* `dynamic:letterboxd`
* `dynamic:musicbrainz`
### Example
<details>
<summary>YAML</summary>
<br />
### Example (YAML)
```yaml
logging:
@ -94,8 +94,10 @@ display:
buttons:
- label: IMDb
url: dynamic:imdb
- label: My YouTube Channel
url: https://www.youtube.com/channel/me
- label: Music Stats
url: https://github.com
mediaTypes:
- track
users:
- token: HPbrz2NhfLRjU888Rrdt
servers:
@ -105,60 +107,6 @@ users:
- Movies
```
</details>
<details>
<summary>JSON</summary>
<br />
```json
{
"logging": {
"debug": true,
"writeToFile": false
},
"display": {
"hideTotalTime": false,
"useRemainingTime": false,
"posters": {
"enabled": true,
"imgurClientID": "9e9sf637S8bRp4z",
"maxSize": 256
},
"buttons": [
{
"label": "IMDb",
"url": "dynamic:imdb"
},
{
"label": "My YouTube Channel",
"url": "https://www.youtube.com/channel/me"
}
]
},
"users": [
{
"token": "HPbrz2NhfLRjU888Rrdt",
"servers": [
{
"name": "Bob's Home Media Server"
},
{
"name": "A Friend's Server",
"whitelistedLibraries": [
"Movies"
]
}
]
}
]
}
```
</details>
## Configuration - Discord
The "Display current activity as a status message" setting must be enabled in Discord Settings → Activity Settings → Activity Privacy.
@ -168,7 +116,7 @@ The "Display current activity as a status message" setting must be enabled in Di
## Configuration - Environment Variables
* `DRPP_PLEX_SERVER_NAME_INPUT` - This is used only during the initial setup (when there are no users in the config) as the name of the Plex server to be added to the config file after user authentication. If this isn't set, in interactive environments, the user is prompted for an input, and in non-interactive environments, "ServerName" is used as a placeholder, which can later be changed by editing the config file and restarting the script.
* `DRPP_NO_PIP_INSTALL` - Automatic invocation of pip to install missing dependencies is skipped if this is set to `true`.
* `DRPP_NO_PIP_INSTALL` - Set this to `true` to skip automatic invocation of pip on script startup to install missing dependencies.
## Run with Docker

View file

@ -34,6 +34,15 @@ def getAuthToken(id: str, code: str) -> Optional[str]:
}).json()
return response["authToken"]
buttonTypeGuidTypeMap = {
"imdb": "imdb",
"tmdb": "tmdb",
"thetvdb": "tvdb",
"trakt": "tmdb",
"letterboxd": "tmdb",
"musicbrainz": "mbid",
}
class PlexAlertListener(threading.Thread):
productName = "Plex Media Server"
@ -242,32 +251,40 @@ class PlexAlertListener(threading.Thread):
},
}
if config["display"]["buttons"]:
guidTags: list[Guid] = []
if mediaType == "movie":
guidTags = item.guids
elif mediaType == "episode":
guidTags = self.server.fetchItem(item.grandparentRatingKey).guids
guids: list[str] = [guid.id for guid in guidTags]
guidsRaw: list[Guid] = item.guids if mediaType in ["movie", "track"] else self.server.fetchItem(item.grandparentRatingKey).guids
guids: dict[str, str] = { guidSplit[0]: guidSplit[1] for guidSplit in [guid.id.split("://") for guid in guidsRaw] if len(guidSplit) > 1 }
buttons: list[models.discord.ActivityButton] = []
for button in config["display"]["buttons"]:
if button["url"].startswith("dynamic:"):
if guids:
newUrl = button["url"]
if button["url"] == "dynamic:imdb":
for guid in guids:
if guid.startswith("imdb://"):
newUrl = guid.replace("imdb://", "https://www.imdb.com/title/")
break
elif button["url"] == "dynamic:tmdb":
for guid in guids:
if guid.startswith("tmdb://"):
if "mediaTypes" in button and mediaType not in button["mediaTypes"]:
continue
if not button["url"].startswith("dynamic:"):
buttons.append({ "label": button["label"], "url": button["url"] })
continue
buttonType = button["url"][8:]
guidType = buttonTypeGuidTypeMap.get(buttonType)
if not guidType:
continue
guid = guids.get(guidType)
if not guid:
continue
url = ""
if buttonType == "imdb":
url = f"https://www.imdb.com/title/{guid}"
elif buttonType == "tmdb":
tmdbPathSegment = "movie" if mediaType == "movie" else "tv"
newUrl = guid.replace("tmdb://", f"https://www.themoviedb.org/{tmdbPathSegment}/")
break
if newUrl:
buttons.append({ "label": button["label"], "url": newUrl })
else:
buttons.append(button)
url = f"https://www.themoviedb.org/{tmdbPathSegment}/{guid}"
elif buttonType == "thetvdb":
theTvdbPathSegment = "movie" if mediaType == "movie" else "series"
url = f"https://www.thetvdb.com/dereferrer/{theTvdbPathSegment}/{guid}"
elif buttonType == "trakt":
idType = "movie" if mediaType == "movie" else "show"
url = f"https://trakt.tv/search/tmdb/{guid}?id_type={idType}"
elif buttonType == "letterboxd" and mediaType == "movie":
url = f"https://letterboxd.com/tmdb/{guid}"
elif buttonType == "musicbrainz":
url = f"https://musicbrainz.org/track/{guid}"
if url:
buttons.append({ "label": button["label"], "url": url })
if buttons:
activity["buttons"] = buttons[:2]
if state == "playing":

View file

@ -12,6 +12,7 @@ class Posters(TypedDict):
class Button(TypedDict):
label: str
url: str
mediaTypes: list[str]
class Display(TypedDict):
hideTotalTime: bool