Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Tautulli integration #1280

Merged
merged 1 commit into from
Sep 26, 2024
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
58 changes: 37 additions & 21 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,23 +1,39 @@
{
"eslint.enable": true,
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact"
],
"typescript.tsdk": "node_modules/typescript/lib",
"sqltools.connections": [
{
"previewLimit": 50,
"driver": "SQLite",
"name": "Local SQLite",
"database": "./data/maintainerr.sqlite"
}
],
"editor.formatOnSave": true,
"typescript.preferences.importModuleSpecifier": "non-relative",
"files.associations": {
"globals.css": "tailwindcss"
"eslint.enable": true,
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact"
],
"typescript.tsdk": "node_modules/typescript/lib",
"typescript.enablePromptUseWorkspaceTsdk": true,
"sqltools.connections": [
{
"previewLimit": 50,
"driver": "SQLite",
"name": "Local SQLite",
"database": "./data/maintainerr.sqlite"
}
}
],
"editor.formatOnSave": true,
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[css]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"typescript.preferences.importModuleSpecifier": "relative",
"files.associations": {
"globals.css": "tailwindcss"
},
}
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,12 @@ It's a one-stop-shop for handling those outlying shows and movies that take up p

# Features

- Configure rules specific to your needs, based off of several available options from Plex, Overseerr, Radarr, and Sonarr.
- Configure rules specific to your needs, based off of several available options from Plex, Overseerr, Radarr, Sonarr and Tautulli.
- Manually add media to a collection, in case it's not included after rule execution. (one-off items that don't match a rule set)
- Selectively exclude media from being added to a collection, even if it matches a rule.
- Show a collection, containing rule matched media, on the Plex home screen for a specific duration before deletion. Think "Leaving soon".
- Optionally, use a manual Plex collection, in case you don't want <b>Maintainerr</b> to add & remove Plex collections at will.
- Manage media straight from the collection within Plex. <b>Maintainerr</b> will sync and add or exclude media to/from the internal collection.

- Remove or unmonitor media from \*arr
- Clear requests from Overseerr
- Delete files from disk
Expand All @@ -47,6 +46,7 @@ Currently, <b>Maintainerr</b> supports rule parameters from these apps :
- Overseerr
- Radarr
- Sonarr
- Tautulli

# Preview

Expand Down
5 changes: 5 additions & 0 deletions server/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import { PlexApiService } from '../modules/api/plex-api/plex-api.service';
import { OverseerrApiService } from '../modules/api/overseerr-api/overseerr-api.service';
import { ServarrService } from '../modules/api/servarr-api/servarr.service';
import ormConfig from './config/typeOrmConfig';
import { TautulliApiModule } from '../modules/api/tautulli-api/tautulli-api.module';
import { TautulliApiService } from '../modules/api/tautulli-api/tautulli-api.service';

@Module({
imports: [
Expand All @@ -25,6 +27,7 @@ import ormConfig from './config/typeOrmConfig';
TmdbApiModule,
ServarrApiModule,
OverseerrApiModule,
TautulliApiModule,
RulesModule,
CollectionsModule,
],
Expand All @@ -37,12 +40,14 @@ export class AppModule implements OnModuleInit {
private readonly plexApi: PlexApiService,
private readonly overseerApi: OverseerrApiService,
private readonly servarr: ServarrService,
private readonly tautulliApi: TautulliApiService,
) {}
async onModuleInit() {
// Initialize stuff needing settings here.. Otherwise problems
await this.settings.init();
await this.plexApi.initialize({});
await this.servarr.init();
await this.overseerApi.init();
await this.tautulliApi.init();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { MigrationInterface, QueryRunner } from 'typeorm';

export class AddTautulliSettings1727097172777 implements MigrationInterface {
name = 'AddTautulliSettings1727097172777';

public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
'ALTER TABLE settings ADD COLUMN "tautulli_url" varchar',
);
await queryRunner.query(
'ALTER TABLE settings ADD COLUMN "tautulli_api_key" varchar',
);
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE settings DROP "tautulli_url"`);
await queryRunner.query(`ALTER TABLE settings DROP "tautulli_api_key"`);
}
}
4 changes: 3 additions & 1 deletion server/src/modules/api/lib/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ export type AvailableCacheIds =
| 'plexguid'
| 'plextv'
| 'overseerr'
| 'plexcommunity';
| 'plexcommunity'
| 'tautulli';

const DEFAULT_TTL = 300; // 5 min
const DEFAULT_CHECK_PERIOD = 120; // 2 min
Expand Down Expand Up @@ -51,6 +52,7 @@ class CacheManager {
plextv: new Cache('plextv', 'Plex.tv'),
overseerr: new Cache('overseerr', 'Overseerr API'),
plexcommunity: new Cache('plexcommunity', 'community.Plex.tv'),
tautulli: new Cache('tautulli', 'Tautulli API'),
};

public getCache(id: AvailableCacheIds): Cache {
Expand Down
22 changes: 22 additions & 0 deletions server/src/modules/api/tautulli-api/helpers/tautulli-api.helper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { ExternalApiService } from '../../external-api/external-api.service';
import cacheManager from '../../lib/cache';

export class TautulliApi extends ExternalApiService {
constructor({
url,
apiKey,
}: {
url: string;
apiKey: string;
}) {
super(
url,
{
apikey: apiKey,
},
{
nodeCache: cacheManager.getCache('tautulli').data,
},
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Controller } from '@nestjs/common';
import { TautulliApiService } from './tautulli-api.service';

@Controller('api/tautulli')
export class TautulliApiController {
constructor(private readonly tautulliApiService: TautulliApiService) {}
}
12 changes: 12 additions & 0 deletions server/src/modules/api/tautulli-api/tautulli-api.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Module } from '@nestjs/common';
import { TautulliApiService } from './tautulli-api.service';
import { TautulliApiController } from './tautulli-api.controller';
import { ExternalApiModule } from '../external-api/external-api.module';

@Module({
imports: [ExternalApiModule],
controllers: [TautulliApiController],
providers: [TautulliApiService],
exports: [TautulliApiService],
})
export class TautulliApiModule {}
Loading
Loading