mirror of
https://github.com/phin05/discord-rich-presence-plex
synced 2024-11-24 02:23:03 +00:00
Added support for YAML config file
This commit is contained in:
parent
a6fdb596db
commit
5e4a56ada4
7 changed files with 128 additions and 21 deletions
26
NOTICE
26
NOTICE
|
@ -437,3 +437,29 @@ limitations under the License.
|
|||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
PyYAML
|
||||
https://github.com/yaml/pyyaml
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2017-2021 Ingy döt Net
|
||||
Copyright (c) 2006-2016 Kirill Simonov
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
|
72
README.md
72
README.md
|
@ -11,18 +11,26 @@ Discord Rich Presence for Plex is a Python script which displays your [Plex](htt
|
|||
|
||||
If you're using a Linux-based operating system, you can [run this script with Docker](#run-with-docker). Otherwise, follow these instructions:
|
||||
|
||||
1. Install [Python 3.10](https://www.python.org/downloads/) - Make sure to tick "Add Python 3.10 to PATH" during the installation.
|
||||
1. Install [Python](https://www.python.org/downloads/) (version 3.10 or newer) - Make sure to tick "Add Python to PATH" during the installation.
|
||||
2. Download the [latest release](https://github.com/phin05/discord-rich-presence-plex/releases/latest) of this script.
|
||||
3. Extract the directory contained in the above ZIP file.
|
||||
4. Navigate a command-line interface (cmd.exe, PowerShell, bash, etc.) into the above-extracted directory.
|
||||
5. Install the required Python modules by running `python -m pip install -U -r requirements.txt`.
|
||||
6. Start the script by running `python main.py`.
|
||||
4. Navigate a command-line interface (cmd, PowerShell, bash, etc.) into the above-extracted directory.
|
||||
5. Start the script by running `python main.py`.
|
||||
|
||||
When the script runs for the first time, a `data` directory will be created in the current working directory along with a `config.json` file inside of it. You will be prompted to complete the authentication flow to allow the script to retrieve an access token for your Plex account.
|
||||
When the script runs for the first time, a directory named `data` will be created in the current working directory along with a `config.yaml` file inside of it. You will be prompted to complete authentication to allow the script to retrieve an access token for your Plex account.
|
||||
|
||||
The script must be running on the same machine as your Discord client.
|
||||
|
||||
## Configuration - `config.json`
|
||||
## Configuration
|
||||
|
||||
A directory named `data` is used for storing the configuration file.
|
||||
|
||||
### Supported Formats
|
||||
|
||||
* YAML - `config.yaml` / `config.yml`
|
||||
* JSON - `config.json`
|
||||
|
||||
### Reference
|
||||
|
||||
* `logging`
|
||||
* `debug` (boolean, default: `true`) - Outputs additional debug-helpful information to the console if enabled.
|
||||
|
@ -64,6 +72,44 @@ During runtime, the following dynamic URL placeholders will get replaced with re
|
|||
|
||||
### Example
|
||||
|
||||
<details>
|
||||
|
||||
<summary>YAML</summary>
|
||||
|
||||
<br />
|
||||
|
||||
```yaml
|
||||
logging:
|
||||
debug: true
|
||||
writeToFile: false
|
||||
display:
|
||||
hideTotalTime: false
|
||||
useRemainingTime: false
|
||||
posters:
|
||||
enabled: true
|
||||
imgurClientID: 9e9sf637S8bRp4z
|
||||
buttons:
|
||||
- label: IMDb Link
|
||||
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>
|
||||
|
||||
<details>
|
||||
|
||||
<summary>JSON</summary>
|
||||
|
||||
<br />
|
||||
|
||||
```json
|
||||
{
|
||||
"logging": {
|
||||
|
@ -98,7 +144,9 @@ During runtime, the following dynamic URL placeholders will get replaced with re
|
|||
{
|
||||
"name": "A Friend's Server",
|
||||
"listenForUser": "xyz",
|
||||
"whitelistedLibraries": ["Movies"]
|
||||
"whitelistedLibraries": [
|
||||
"Movies"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -106,9 +154,7 @@ During runtime, the following dynamic URL placeholders will get replaced with re
|
|||
}
|
||||
```
|
||||
|
||||
## Configuration - Environment Variables
|
||||
|
||||
* `PLEX_SERVER_NAME` - Name of the Plex Media Server you wish to connect to. Used only during the initial setup (when there are no users in the config) for adding a server to the config after 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.
|
||||
</details>
|
||||
|
||||
## Configuration - Discord
|
||||
|
||||
|
@ -116,6 +162,10 @@ The "Display current activity as a status message" setting must be enabled in Di
|
|||
|
||||
![Discord Settings](https://user-images.githubusercontent.com/59180111/186830889-35af3895-ece0-4a7d-9efb-f68640116884.png)
|
||||
|
||||
## Configuration - Environment Variables
|
||||
|
||||
* `PLEX_SERVER_NAME` - Name of the Plex Media Server you wish to connect to. Used only during the initial setup (when there are no users in the config) for adding a server to the config after 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 configuration file and restarting the script.
|
||||
|
||||
## Run with Docker
|
||||
|
||||
### Image
|
||||
|
@ -124,7 +174,7 @@ The "Display current activity as a status message" setting must be enabled in Di
|
|||
|
||||
### Volumes
|
||||
|
||||
Mount a directory for persistent data (config file, cache file and log file) at `/app/data`.
|
||||
Mount a directory for persistent data (configuration file, cache file and log file) at `/app/data`.
|
||||
|
||||
The directory where Discord stores its inter-process communication Unix socket file needs to be mounted into the container at `/run/app`. The path for this would be the first non-null value from the values of the following environment variables: ([source](https://github.com/discord/discord-rpc/blob/963aa9f3e5ce81a4682c6ca3d136cddda614db33/src/connection_unix.cpp#L29C33-L29C33))
|
||||
|
||||
|
|
|
@ -2,13 +2,13 @@ import os
|
|||
import sys
|
||||
|
||||
name = "Discord Rich Presence for Plex"
|
||||
version = "2.3.5"
|
||||
version = "2.4.0"
|
||||
|
||||
plexClientID = "discord-rich-presence-plex"
|
||||
discordClientID = "413407336082833418"
|
||||
|
||||
dataDirectoryPath = "data"
|
||||
configFilePath = os.path.join(dataDirectoryPath, "config.json")
|
||||
configFilePathRoot = os.path.join(dataDirectoryPath, "config")
|
||||
cacheFilePath = os.path.join(dataDirectoryPath, "cache.json")
|
||||
logFilePath = os.path.join(dataDirectoryPath, "console.log")
|
||||
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
from config.constants import configFilePath
|
||||
from config.constants import configFilePathRoot
|
||||
from utils.dict import copyDict
|
||||
from utils.logging import logger
|
||||
import json
|
||||
import models.config
|
||||
import os
|
||||
import time
|
||||
import yaml
|
||||
|
||||
config: models.config.Config = {
|
||||
"logging": {
|
||||
|
@ -22,23 +23,52 @@ config: models.config.Config = {
|
|||
},
|
||||
"users": [],
|
||||
}
|
||||
supportedConfigFileExtensions = {
|
||||
"yaml": "yaml",
|
||||
"yml": "yaml",
|
||||
"json": "json",
|
||||
}
|
||||
configFileExtension = ""
|
||||
configFileType = ""
|
||||
configFilePath = ""
|
||||
|
||||
def loadConfig() -> None:
|
||||
global configFileType, configFileExtension, configFilePath
|
||||
for fileExtension, fileType in supportedConfigFileExtensions.items():
|
||||
filePath = f"{configFilePathRoot}.{fileExtension}"
|
||||
if os.path.isfile(filePath):
|
||||
configFileExtension = fileExtension
|
||||
configFileType = fileType
|
||||
break
|
||||
else:
|
||||
configFileExtension, configFileType = list(supportedConfigFileExtensions.items())[0]
|
||||
filePath = f"{configFilePathRoot}.{configFileExtension}"
|
||||
configFilePath = filePath
|
||||
if os.path.isfile(configFilePath):
|
||||
try:
|
||||
with open(configFilePath, "r", encoding = "UTF-8") as configFile:
|
||||
loadedConfig = json.load(configFile)
|
||||
if configFileType == "yaml":
|
||||
loadedConfig = yaml.safe_load(configFile) or {}
|
||||
else:
|
||||
loadedConfig = json.load(configFile) or {}
|
||||
except:
|
||||
os.rename(configFilePath, configFilePath.replace(".json", f"-{time.time():.0f}.json"))
|
||||
os.rename(configFilePath, f"{configFilePathRoot}-{time.time():.0f}.{configFileExtension}")
|
||||
logger.exception("Failed to parse the application's config file. A new one will be created.")
|
||||
else:
|
||||
copyDict(loadedConfig, config)
|
||||
saveConfig()
|
||||
|
||||
class YamlSafeDumper(yaml.SafeDumper):
|
||||
def increase_indent(self, flow: bool = False, indentless: bool = False) -> None:
|
||||
return super().increase_indent(flow, False)
|
||||
|
||||
def saveConfig() -> None:
|
||||
try:
|
||||
with open(configFilePath, "w", encoding = "UTF-8") as configFile:
|
||||
json.dump(config, configFile, indent = "\t")
|
||||
configFile.write("\n")
|
||||
if configFileType == "yaml":
|
||||
yaml.dump(config, configFile, sort_keys = False, Dumper = YamlSafeDumper, allow_unicode = True)
|
||||
else:
|
||||
json.dump(config, configFile, indent = "\t")
|
||||
configFile.write("\n")
|
||||
except:
|
||||
logger.exception("Failed to write to the application's config file.")
|
||||
|
|
|
@ -59,7 +59,7 @@ class PlexAlertListener(threading.Thread):
|
|||
except:
|
||||
pass
|
||||
self.logger.info("Connected to %s \"%s\"", self.productName, resource.name)
|
||||
self.alertListener = AlertListener(self.server, self.handlePlexAlert, self.reconnect)
|
||||
self.alertListener = AlertListener(self.server, self.handleAlert, self.reconnect)
|
||||
self.alertListener.start()
|
||||
self.logger.info("Listening for alerts from user \"%s\"", self.listenForUser)
|
||||
self.connectionTimeoutTimer = threading.Timer(self.connectionTimeoutTimerInterval, self.connectionTimeout)
|
||||
|
@ -116,7 +116,7 @@ class PlexAlertListener(threading.Thread):
|
|||
self.connectionTimeoutTimer = threading.Timer(self.connectionTimeoutTimerInterval, self.connectionTimeout)
|
||||
self.connectionTimeoutTimer.start()
|
||||
|
||||
def handlePlexAlert(self, alert: models.plex.Alert) -> None:
|
||||
def handleAlert(self, alert: models.plex.Alert) -> None:
|
||||
try:
|
||||
if alert["type"] == "playing" and "PlaySessionStateNotification" in alert:
|
||||
stateNotification = alert["PlaySessionStateNotification"][0]
|
||||
|
|
2
main.py
2
main.py
|
@ -49,7 +49,7 @@ def main() -> None:
|
|||
logger.info("%s - v%s", name, version)
|
||||
loadCache()
|
||||
if not config["users"]:
|
||||
logger.info("No users found in the config file. Initiating authentication flow.")
|
||||
logger.info("No users found in the config file")
|
||||
user = authUser()
|
||||
if not user:
|
||||
exit()
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
PlexAPI==4.10.1
|
||||
requests==2.26.0
|
||||
websocket-client==1.3.2
|
||||
PyYAML==6.0.1
|
||||
|
|
Loading…
Reference in a new issue