Skip to content

Commit

Permalink
[feat] Add API + webhook ingestion (#236)
Browse files Browse the repository at this point in the history
- Add Flask server with health and ping endpoints
- Add `webhook/tautulli/recently_added` endpoint for ingestion Recently Added webhooks from Tautulli
- Add webhook parsing logic
- Add internal SQLite database
  - Store webhook + recently added media records
- Add "Recently Added" per-library statistic, using database records to count recently-added items
- Update config YAML schema, Docker files, documentation accordingly
  • Loading branch information
nwithan8 authored Dec 2, 2024
1 parent 1ca775e commit db87a9e
Show file tree
Hide file tree
Showing 40 changed files with 1,319 additions and 32 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -145,3 +145,4 @@ tauticord.yaml
/on_host/
00*.yaml
.migration_*
/reference/
63 changes: 61 additions & 2 deletions .schema/config_v2.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -129,11 +129,60 @@
}
},
"required": [
"CustomName",
"CustomEmoji",
"Enable",
"VoiceChannelID"
]
},
"recentlyAddedVoiceChannel": {
"id": "#/definitions/voiceChannel",
"type": "object",
"properties": {
"CustomName": {
"description": "The custom name to use for the voice channel (overrides the default name)",
"oneOf": [
{
"$ref": "#/definitions/discordVoiceChannelName"
},
{
"$ref": "#/definitions/emptyString"
}
]
},
"CustomEmoji": {
"description": "The custom emoji to use for the voice channel (overrides the default emoji)",
"type": "string"
},
"Enable": {
"description": "Whether to enable the voice channel",
"type": "boolean"
},
"VoiceChannelID": {
"description": "The ID of the voice channel",
"oneOf": [
{
"$ref": "#/definitions/discordChannelId"
},
{
"$ref": "#/definitions/numberZero"
}
]
},
"Hours": {
"description": "The number of hours to look back for recently added items",
"type": "integer",
"minimum": 1
}
},
"required": [
"CustomName",
"CustomEmoji",
"Enable",
"VoiceChannelID",
"Hours"
]
},
"library": {
"id": "#/definitions/library",
"type": "object",
Expand Down Expand Up @@ -187,6 +236,10 @@
"Tracks": {
"description": "Settings for the voice channel about track information (used if the library is a music library)",
"$ref": "#/definitions/voiceChannel"
},
"RecentlyAdded": {
"description": "Settings for the voice channel about recently added items",
"$ref": "#/definitions/recentlyAddedVoiceChannel"
}
},
"required": [
Expand All @@ -197,7 +250,8 @@
"Episodes",
"Movies",
"Series",
"Tracks"
"Tracks",
"RecentlyAdded"
]
},
"combinedLibrarySubLibrary": {
Expand Down Expand Up @@ -269,6 +323,10 @@
"Tracks": {
"description": "Settings for the voice channel about track information (used if the library is a music library)",
"$ref": "#/definitions/voiceChannel"
},
"RecentlyAdded": {
"description": "Settings for the voice channel about recently added items",
"$ref": "#/definitions/recentlyAddedVoiceChannel"
}
},
"required": [
Expand All @@ -279,7 +337,8 @@
"Episodes",
"Movies",
"Series",
"Tracks"
"Tracks",
"RecentlyAdded"
]
}
},
Expand Down
3 changes: 3 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ VOLUME /logs
# Copy source code from build machine to WORKDIR (/app) folder
COPY . .

# Expose port 8283 for API
EXPOSE 8283

# Delete unnecessary files in WORKDIR (/app) folder (not caught by .dockerignore)
RUN echo "**** removing unneeded files ****"

Expand Down
3 changes: 3 additions & 0 deletions consts.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@
GOOGLE_ANALYTICS_ID = 'UA-174268200-2'
DEFAULT_CONFIG_PATH = "/config/tauticord.yaml"
DEFAULT_LOG_DIR = "/logs/"
DEFAULT_DATABASE_PATH = "/config/tauticord.db"
CONSOLE_LOG_LEVEL = "INFO"
FILE_LOG_LEVEL = "DEBUG"
GITHUB_REPO = "nwithan8/tauticord"
GITHUB_REPO_FULL_LINK = f"https://github.com/{GITHUB_REPO}"
GITHUB_REPO_MASTER_BRANCH = "master"
FLASK_ADDRESS = "0.0.0.0"
FLASK_PORT = 8283
2 changes: 2 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ version: "3.9"
services:
tauticord:
image: nwithan8/tauticord:latest
ports:
- "8283:8283"
volumes:
- /path/to/config:/config
- /path/to/logs:/logs
Expand Down
74 changes: 74 additions & 0 deletions documentation/DOCUMENTATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@ All statistic voice channels have the following customization options:
- Custom emoji (overrides the default emoji for the statistic)
- Voice channel ID specification (rather than letting Tauticord auto-generate the channel)

"Recently added" statistic voice channels also have the following additional customization options:

- Custom time frame (how many hours to consider something "recently added")

## Activity Statistics

Activity statistics are about live activity taking place on the Plex server. This includes:
Expand All @@ -140,6 +144,7 @@ Library statistics are about the media stored on the Plex server. This includes
- Total music artist count
- Total album count
- Total song/track count
- Recently added media (movie, episode, or track) count

Only metrics relevant to the library type will be displayed. For example, a music library will not display a movie
count, and a movie library will not display an album count.
Expand Down Expand Up @@ -171,6 +176,9 @@ Libraries:
...
Tracks: # Settings for the "Tracks" statistic
...
RecentlyAdded: # Settings for the "Recently Added" statistic
Hours: 24 # How many hours to consider something "recently added"
...
- Name: Movies
AlternateName: My Movies
Albums:
Expand All @@ -185,6 +193,8 @@ Libraries:
...
Tracks:
...
RecentlyAdded:
...
```
Library data updates at a configurable interval (with a minimum of 5 minutes between updates).
Expand Down Expand Up @@ -218,6 +228,9 @@ CombinedLibraries:
...
Tracks:
...
RecentlyAdded:
Hours: 24 # How many hours to consider something "recently added"
...
```

Combined library data updates at the same interval as regular library data (with a minimum of 5 minutes between
Expand Down Expand Up @@ -273,6 +286,67 @@ path mounted to `/monitor` inside the Docker container). This feature can be use
space of your Plex library, as long as the path to the library is mounted to `/monitor`. This will not work if Tauticord
is running on a separate system from the Plex library.

# Webhooks

Tauticord can ingest webhooks from Tautulli, acting upon them in various ways.

Currently, Tauticord can do the following:

- Ingest "Recently Added" webhooks. These webhooks and details about the associated recently-added media are stored in Tauticord's database. This data is used for the "Recently Added" [Library Statistics](#library-statistics).
- Ingest playback state change-related webhooks (e.g. "Playback Start", "Playback Stop", etc.). These webhooks are stored in Tauticord's database, but not currently used for anything.

## Setup

Tauticord expects to receive webhooks from Tautulli as at its `/webhooks/tautulli/recently_added` webhook endpoint, available at POST `http://<TAUTICORD_IP_ADDRESS>:8283/webhooks/tautulli/recently_added`.

To set up Tautulli to send webhooks to Tauticord, follow these steps:
1. Expose port 8283 from Tauticord to the network so Tautulli can reach it.
1. To do this in Docker, add `-p 8283:8283` to the `docker run` command.
1. If you are using Docker Compose, add the following to your `docker-compose.yml` file:
```yaml
ports:
- 8283:8283
```
1. If you are using the Unraid Docker template, a "Port" field is available in the template settings, preset to map port 8283 externally to 8283 internally.
1. In Tautulli, navigate to `Settings -> Notification Agents`. Click the `Add a new notification agent` button and select "Webhook".
1. On the "Configuration" tab, fill in the following fields:
- **Webhook URL**: `http://<TAUTICORD_IP_ADDRESS>:8283/webhooks/tautulli/recently_added`
- **Webhook Method**: `POST`
- **Description**: A description of the webhook (e.g. "Tauticord - Recently Added")

<img src="https://raw.githubusercontent.com/nwithan8/tauticord/master/documentation/images/tauticord_webhook_config_1.png">

1. On the "Triggers" tab, check the box next to "Recently Added". Do not check any other boxes.

<img src="https://raw.githubusercontent.com/nwithan8/tauticord/master/documentation/images/tauticord_webhook_config_2.png">

1. Do not make any changes on the "Conditions" tab.
1. On the "Data" tab, add the following to "JSON Data" under "Recently Added":
```json
{
"media_type": "{{media_type}}",
"library_name": "{{library_name}}",
"title": "{{title}}",
"year": "{{year}}",
"duration": "{{duration}}",
"tagline": "{{tagline}}",
"summary": "{{summary}}",
"studio": "{{studio}}",
"directors": "{{directors}}",
"actors": "{{actors}}",
"genres": "{{genres}}",
"plex_id": "{{plex_id}}",
"critic_rating": "{{critic_rating}}",
"audience_rating": "{{audience_rating}}",
"poster_url": "{{poster_url}}"
}
```
1. Leave "JSON Headers" blank.

<img src="https://raw.githubusercontent.com/nwithan8/tauticord/master/documentation/images/tauticord_webhook_config_3.png">

1. Click the "Save" button to save the webhook.

# Commands

Out of the box, Tauticord does mostly passive, non-interactive things (posting messages, updating voice channels, etc.).
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file added modules/database/__init__.py
Empty file.
Empty file.
Loading

0 comments on commit db87a9e

Please sign in to comment.