Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Example environment variables for the Slack bot

SLACK_BOT_TOKEN=your-slack-bot-token
JELLYSEERR_API_URL=your-jellyseerr-api-url
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
.vscode/sftp.json
.vscode/sftp.json
.env
11 changes: 11 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
FROM node:14

WORKDIR /app

COPY package*.json ./

RUN npm install

COPY . .

CMD ["node", "src/index.js"]
10 changes: 10 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
version: '3'

services:
slack-bot:
build: .
environment:
- SLACK_BOT_TOKEN=${SLACK_BOT_TOKEN}
- JELLYSEERR_API_URL=${JELLYSEERR_API_URL}
ports:
- "3000:3000"
7 changes: 7 additions & 0 deletions machines/media/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
version: "3"

services:
jellyfin-slackbot:
extends:
file: ./services/jellyfin-slackbot.yml
service: slack-bot
15 changes: 0 additions & 15 deletions machines/media/services/jellyfin.yml

This file was deleted.

4 changes: 4 additions & 0 deletions machines/pi/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,7 @@ services:
extends:
file: ./services/homeassistant.yml
service: homeassistant
jellyfin-slackbot:
extends:
file: ./services/jellyfin-slackbot.yml
service: slack-bot
13 changes: 0 additions & 13 deletions machines/pi/services/homeassistant.yml

This file was deleted.

24 changes: 0 additions & 24 deletions machines/pi/services/pihole.yml

This file was deleted.

4 changes: 4 additions & 0 deletions services/jellyfin-slackbot/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Example environment variables for the Slack bot

SLACK_BOT_TOKEN=your-slack-bot-token
JELLYSEERR_API_URL=your-jellyseerr-api-url
11 changes: 11 additions & 0 deletions services/jellyfin-slackbot/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
FROM node:14

WORKDIR /app

COPY package*.json ./

RUN npm install

COPY . .

CMD ["node", "src/index.js"]
114 changes: 114 additions & 0 deletions services/jellyfin-slackbot/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
## Slack Bot Setup Instructions

### Slack Bot Creation

1. Go to the [Slack API](https://api.slack.com/apps) and create a new app.
2. Choose a name for your app and select the workspace where you want to install it.
3. Once the app is created, navigate to the "OAuth & Permissions" section.
4. Add the following bot token scopes:
- `channels:history`
- `channels:read`
- `chat:write`
- `groups:history`
- `groups:read`
- `im:history`
- `im:read`
- `mpim:history`
- `mpim:read`
5. Install the app to your workspace and copy the Bot User OAuth Token.
6. In the "Basic Information" section, locate the "Signing Secret" under "App Credentials".
Copy this value as you'll need it for the configuration.

### Required Permissions & OAuth Setup

1. In the "OAuth & Permissions" section, ensure that the required bot token scopes are added.
2. Copy the Bot User OAuth Token and add it to your `.env` file as `SLACK_BOT_TOKEN`.

### Configuration Using `.env` File

1. Create a `.env` file in the root directory of the project.
2. Add the following environment variables to the `.env` file:
```
SLACK_BOT_TOKEN=your-slack-bot-token
SLACK_SIGNING_SECRET=your-slack-signing-secret
JELLYSEERR_API_URL=your-jellyseerr-api-url
JELLYSEERR_API_KEY=your-jellyseerr-api-key
```

### Environment Variables

The following environment variables are required:

| Variable | Description |
|----------|-------------|
| SLACK_BOT_TOKEN | OAuth token starting with `xoxb-`. Found under "OAuth & Permissions" in your Slack app settings. Required for the bot to interact with Slack's APIs. |
| SLACK_SIGNING_SECRET | Used to verify requests are coming from Slack. Found under "Basic Information" in your Slack app settings. |
| JELLYSEERR_API_URL | Base URL for your Jellyseerr instance (e.g., `http://localhost:5055`). |
| JELLYSEERR_API_KEY | API key for Jellyseerr, generated in the Jellyseerr settings. |

Optional environment variables:

| Variable | Description |
|----------|-------------|
| SLACK_APP_TOKEN | Token starting with `xapp-`. **Only required if using Socket Mode**. Found under "Basic Information" in your Slack app settings. |
| PORT | Port for the HTTP server to listen on (default: 3000). Not needed if using Socket Mode. |

### Connection Modes

The bot supports two connection modes:

1. **HTTP Mode (default)** - Requires a public URL with proper request URLs configured in the Slack app settings
2. **Socket Mode** - No public URL required, but needs the additional SLACK_APP_TOKEN

To use Socket Mode, set `socketMode: true` in the App initialization and ensure you've set the SLACK_APP_TOKEN environment variable.

---

## Running the Slack Bot Using Docker and Docker Compose

### Docker Setup

1. Create a `Dockerfile` in the root directory of the project with the following content:
```
FROM node:14

WORKDIR /app

COPY package*.json ./

RUN npm install

COPY . .

CMD ["node", "src/index.js"]
```

2. Create a `docker-compose.yml` file in the root directory of the project with the following content:
```
version: '3'

services:
slack-bot:
build: .
environment:
- SLACK_BOT_TOKEN=${SLACK_BOT_TOKEN}
- SLACK_SIGNING_SECRET=${SLACK_SIGNING_SECRET}
- JELLYSEERR_API_URL=${JELLYSEERR_API_URL}
- JELLYSEERR_API_KEY=${JELLYSEERR_API_KEY}
ports:
- "3000:3000"
```

### Running the Slack Bot

1. Build the Docker image:
```
docker-compose build
```

2. Start the Slack bot:
```
docker-compose up
```

3. The Slack bot should now be running and listening for messages in the configured channel.
11 changes: 11 additions & 0 deletions services/jellyfin-slackbot/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
services:
slack-bot:
build: .
environment:
- SLACK_BOT_TOKEN=${SLACK_BOT_TOKEN}
- SLACK_SIGNING_SECRET=${SLACK_SIGNING_SECRET}
- SLACK_APP_TOKEN=${SLACK_APP_TOKEN}
- JELLYSEERR_API_URL=${JELLYSEERR_API_URL}
- JELLYSEERR_API_KEY=${JELLYSEERR_API_KEY}
ports:
- "3000:3000"
32 changes: 32 additions & 0 deletions services/jellyfin-slackbot/jellyseer-api-notes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Jellyseerr API Notes

## Authentication
- Requires API key in header: `X-Api-Key`
- API key generated in Jellyseerr settings / general

## Relevant Endpoints

### Search Media
- `GET /api/v1/search`
- Query params:
- `query` (string, required): Search term
- `page` (integer, optional): Page number
- `language` (string, optional): ISO 639-1 language code

### Request Media
- `POST /api/v1/request`
- Required body parameters:
- `mediaType`: "movie" or "tv"
- `mediaId`: TMDB ID of the media
- Optional parameters:
- `seasons`: Array of season numbers (for TV)
- `tvdbId`: TVDB ID (for TV shows)

## Example Flow
1. Search for media using title
2. Get TMDB ID from search results
3. Use TMDB ID to make request

## Required Environment Variables
- `JELLYSEERR_API_URL`: Base URL of Jellyseerr instance
- `JELLYSEERR_API_KEY`: API key from settings
17 changes: 17 additions & 0 deletions services/jellyfin-slackbot/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "jellyfin-slackbot",
"version": "1.0.0",
"description": "Slack bot for Jellyfin requests",
"main": "src/index.js",
"scripts": {
"start": "node src/index.js",
"test": "jest"
},
"dependencies": {
"@slack/bolt": "^3.0.0",
"axios": "^0.21.1"
},
"devDependencies": {
"jest": "^27.0.0"
}
}
5 changes: 5 additions & 0 deletions services/jellyfin-slackbot/references.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
https://api-docs.jellyseerr.com/

https://api-docs.jellyseerr.com/#request-media

https://api-docs.jellyseerr.com/#search
38 changes: 38 additions & 0 deletions services/jellyfin-slackbot/slack-app-manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"display_information": {
"name": "Jellyfin Request Bot",
"description": "A Slack bot for managing Jellyfin media requests",
"background_color": "#2c3e50"
},
"features": {
"bot_user": {
"display_name": "Jellyfin Bot",
"always_online": true
},
"app_home": {
"home_tab_enabled": true,
"messages_tab_enabled": true
}
},
"oauth_config": {
"scopes": {
"bot": [
"channels:history",
"channels:read",
"chat:write",
"groups:history",
"groups:read",
"im:history",
"im:read",
"mpim:history",
"mpim:read"
]
}
},
"settings": {
"socket_mode_enabled": true,
"interactivity": {
"is_enabled": true
}
}
}
45 changes: 45 additions & 0 deletions services/jellyfin-slackbot/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
const { createSlackApp, updateBotStatus } = require('./slackApp');
const { checkJellyseerrHealth } = require('./jellyseerClient');

const requiredEnvVars = [
'SLACK_BOT_TOKEN',
'SLACK_APP_TOKEN',
'SLACK_SIGNING_SECRET',
'JELLYSEERR_API_URL',
'JELLYSEERR_API_KEY'
];

// Add global unhandled promise rejection handler
process.on('unhandledRejection', (reason, promise) => {
console.error('🔴 Unhandled Promise Rejection:', reason);
// Optionally log the promise that caused the rejection
console.error('Promise:', promise);
});

function validateEnvironment() {
const missing = requiredEnvVars.filter(varName => !process.env[varName]?.length);
if (missing.length) {
throw new Error(`Missing environment variables: ${missing.join(', ')}`);
}
}

// Start the app
(async () => {
console.log('🚀 Starting server...');
try {
validateEnvironment();
await checkJellyseerrHealth();

const app = createSlackApp();

// Comment out the status update function call since it's causing errors
// await updateBotStatus(app, "Online", ":white_check_mark:");

console.log('🌐 Starting Slack app listener...');
await app.start(process.env.PORT || 3000);
console.log('✅ Bot is running!');
} catch (error) {
console.error('🔴 Failed to start app:', error);
process.exit(1);
}
})();
Loading
Loading