Skip to content
Open
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
25 changes: 25 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: CI

on:
pull_request:
branches:
- main

jobs:
test:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Set up Node.js
uses: actions/setup-node@v2
with:
node-version: '14'

- name: Install dependencies
run: npm install

- name: Run tests
run: npm test
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"]
84 changes: 84 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,87 @@ This repository is intended for operating a home server off of a Raspberry Pi. I
## Multi-Device Usage

This repository is designed to be used across multiple devices, making it easier to migrate where and how the various services are hosted. The scripts and configurations are intended to be flexible and adaptable to different environments.

---

## 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.

### 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
JELLYSEERR_API_URL=your-jellyseerr-api-url
```

---

## 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}
- JELLYSEERR_API_URL=${JELLYSEERR_API_URL}
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.
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"
4 changes: 4 additions & 0 deletions 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
25 changes: 25 additions & 0 deletions jellyfin-slackbot/.github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: CI

on:
pull_request:
branches:
- main

jobs:
test:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Set up Node.js
uses: actions/setup-node@v2
with:
node-version: '14'

- name: Install dependencies
run: npm install

- name: Run tests
run: npm test
11 changes: 11 additions & 0 deletions 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"]
10 changes: 10 additions & 0 deletions jellyfin-slackbot/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"
23 changes: 23 additions & 0 deletions jellyfin-slackbot/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
const { App } = require('@slack/bolt');
const requestHandler = require('./requestHandler');

const app = new App({
token: process.env.SLACK_BOT_TOKEN,
signingSecret: process.env.SLACK_SIGNING_SECRET
});

app.message(async ({ message, say }) => {
if (message.text.includes('request video')) {
try {
const response = await requestHandler.handleRequest(message.text);
await say(`Request received: ${response}`);
} catch (error) {
await say(`Error: ${error.message}`);
}
}
});

(async () => {
await app.start(process.env.PORT || 3000);
console.log('⚡️ Slack bot is running!');
})();
28 changes: 28 additions & 0 deletions jellyfin-slackbot/src/requestHandler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
const axios = require('axios');

async function handleRequest(message) {
const videoRequest = parseMessage(message);
const response = await forwardToJellyseerr(videoRequest);
return response;
}

function parseMessage(message) {
// Extract video request details from the message
// This is a placeholder implementation, adjust as needed
return {
title: message.split('request video ')[1]
};
}

async function forwardToJellyseerr(videoRequest) {
try {
const response = await axios.post(process.env.JELLYSEERR_API_URL, videoRequest);
return response.data;
} catch (error) {
throw new Error('Failed to forward request to Jellyseerr');
}
}

module.exports = {
handleRequest
};
14 changes: 14 additions & 0 deletions jellyfin-slackbot/tests/requestHandler.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const requestHandler = require('../src/requestHandler');

describe('requestHandler', () => {
test('should handle successful video request', async () => {
const message = 'request video Test Video';
const response = await requestHandler.handleRequest(message);
expect(response).toEqual({ success: true, message: 'Request forwarded to Jellyseerr' });
});

test('should handle error in video request', async () => {
const message = 'request video Invalid Video';
await expect(requestHandler.handleRequest(message)).rejects.toThrow('Failed to forward request to Jellyseerr');
});
});
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
23 changes: 23 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
const { App } = require('@slack/bolt');
const requestHandler = require('./requestHandler');

const app = new App({
token: process.env.SLACK_BOT_TOKEN,
signingSecret: process.env.SLACK_SIGNING_SECRET
});

app.message(async ({ message, say }) => {
if (message.text.includes('request video')) {
try {
const response = await requestHandler.handleRequest(message.text);
await say(`Request received: ${response}`);
} catch (error) {
await say(`Error: ${error.message}`);
}
}
});

(async () => {
await app.start(process.env.PORT || 3000);
console.log('⚡️ Slack bot is running!');
})();
28 changes: 28 additions & 0 deletions src/requestHandler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
const axios = require('axios');

async function handleRequest(message) {
const videoRequest = parseMessage(message);
const response = await forwardToJellyseerr(videoRequest);
return response;
}

function parseMessage(message) {
// Extract video request details from the message
// This is a placeholder implementation, adjust as needed
return {
title: message.split('request video ')[1]
};
}

async function forwardToJellyseerr(videoRequest) {
try {
const response = await axios.post(process.env.JELLYSEERR_API_URL, videoRequest);
return response.data;
} catch (error) {
throw new Error('Failed to forward request to Jellyseerr');
}
}

module.exports = {
handleRequest
};
14 changes: 14 additions & 0 deletions tests/requestHandler.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const requestHandler = require('../src/requestHandler');

describe('requestHandler', () => {
test('should handle successful video request', async () => {
const message = 'request video Test Video';
const response = await requestHandler.handleRequest(message);
expect(response).toEqual({ success: true, message: 'Request forwarded to Jellyseerr' });
});

test('should handle error in video request', async () => {
const message = 'request video Invalid Video';
await expect(requestHandler.handleRequest(message)).rejects.toThrow('Failed to forward request to Jellyseerr');
});
});
Loading