Files
channels-seerr/server/api/channelsdvr.ts
Synapse c2fe0fdc95
Some checks failed
Seerr CI / i18n Check (push) Has been cancelled
Seerr CI / Lint & Test Build (push) Has been cancelled
Seerr CI / Build (per-arch, native runners) (amd64, linux/amd64, ubuntu-24.04) (push) Has been cancelled
Seerr CI / Build (per-arch, native runners) (arm64, linux/arm64, ubuntu-24.04-arm) (push) Has been cancelled
Seerr CI / Publish multi-arch image (push) Has been cancelled
Seerr CI / Send Discord Notification (push) Has been cancelled
CodeQL / Analyze (actions) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Merge Conflict Labeler / Labeling (push) Has been cancelled
feat: Add Channels DVR as 4th media server backend
- Add CHANNELS_DVR to MediaServerType enum
- Create channelsdvr.ts API client with full REST support
- Implement library scanner with TMDb lookup
- Add settings interface and configuration
- Document implementation in CHANNELS_DVR_INTEGRATION.md

Phase 1 (Core Integration) complete. Ready for testing.
2026-02-20 03:05:20 +00:00

221 lines
5.1 KiB
TypeScript

/* eslint-disable @typescript-eslint/no-explicit-any */
import ExternalAPI from '@server/api/externalapi';
import { getAppVersion } from '@server/utils/appVersion';
import logger from '@server/logger';
export interface ChannelsDVRShow {
id: string;
name: string;
summary: string;
image_url: string;
release_year: number;
release_date: string;
genres: string[];
categories: string[];
labels: string[];
cast: string[];
episode_count: number;
number_unwatched: number;
favorited: boolean;
last_watched_at?: number;
last_recorded_at?: number;
created_at: number;
updated_at: number;
}
export interface ChannelsDVRMovie {
id: string;
program_id: string;
path: string;
channel: string;
title: string;
summary: string;
full_summary: string;
content_rating: string;
image_url: string;
thumbnail_url: string;
duration: number;
playback_time: number;
release_year: number;
release_date: string;
genres: string[];
tags: string[];
labels: string[];
categories: string[];
cast: string[];
directors: string[];
watched: boolean;
favorited: boolean;
delayed: boolean;
cancelled: boolean;
corrupted: boolean;
completed: boolean;
processed: boolean;
verified: boolean;
last_watched_at?: number;
created_at: number;
updated_at: number;
}
export interface ChannelsDVREpisode {
id: string;
show_id: string;
program_id: string;
path: string;
channel: string;
season_number: number;
episode_number: number;
title: string;
episode_title: string;
summary: string;
full_summary: string;
content_rating: string;
image_url: string;
thumbnail_url: string;
duration: number;
playback_time: number;
original_air_date: string;
genres: string[];
tags: string[];
categories: string[];
cast: string[];
commercials: number[];
watched: boolean;
favorited: boolean;
delayed: boolean;
cancelled: boolean;
corrupted: boolean;
completed: boolean;
processed: boolean;
locked: boolean;
verified: boolean;
created_at: number;
updated_at: number;
}
class ChannelsDVRAPI extends ExternalAPI {
constructor(baseUrl: string) {
super(
baseUrl,
{},
{
headers: {
'User-Agent': `Seerr/${getAppVersion()}`,
},
}
);
}
/**
* Get all TV shows from Channels DVR library
*/
public async getShows(): Promise<ChannelsDVRShow[]> {
try {
const data = await this.get<ChannelsDVRShow[]>('/api/v1/shows');
return data;
} catch (e) {
logger.error('Failed to fetch shows from Channels DVR', {
label: 'Channels DVR API',
errorMessage: e.message,
});
throw new Error('Failed to fetch shows from Channels DVR');
}
}
/**
* Get a specific show by ID
*/
public async getShow(showId: string): Promise<ChannelsDVRShow> {
try {
const data = await this.get<ChannelsDVRShow>(`/api/v1/shows/${showId}`);
return data;
} catch (e) {
logger.error(
`Failed to fetch show ${showId} from Channels DVR`,
{
label: 'Channels DVR API',
errorMessage: e.message,
}
);
throw new Error(`Failed to fetch show ${showId} from Channels DVR`);
}
}
/**
* Get all episodes for a specific show
*/
public async getShowEpisodes(showId: string): Promise<ChannelsDVREpisode[]> {
try {
const data = await this.get<ChannelsDVREpisode[]>(
`/api/v1/shows/${showId}/episodes`
);
return data;
} catch (e) {
logger.error(
`Failed to fetch episodes for show ${showId} from Channels DVR`,
{
label: 'Channels DVR API',
errorMessage: e.message,
}
);
throw new Error(
`Failed to fetch episodes for show ${showId} from Channels DVR`
);
}
}
/**
* Get all movies from Channels DVR library
*/
public async getMovies(): Promise<ChannelsDVRMovie[]> {
try {
const data = await this.get<ChannelsDVRMovie[]>('/api/v1/movies');
return data;
} catch (e) {
logger.error('Failed to fetch movies from Channels DVR', {
label: 'Channels DVR API',
errorMessage: e.message,
});
throw new Error('Failed to fetch movies from Channels DVR');
}
}
/**
* Get a specific movie by ID
*/
public async getMovie(movieId: string): Promise<ChannelsDVRMovie> {
try {
const data = await this.get<ChannelsDVRMovie>(`/api/v1/movies/${movieId}`);
return data;
} catch (e) {
logger.error(
`Failed to fetch movie ${movieId} from Channels DVR`,
{
label: 'Channels DVR API',
errorMessage: e.message,
}
);
throw new Error(`Failed to fetch movie ${movieId} from Channels DVR`);
}
}
/**
* Test connectivity to Channels DVR server
*/
public async testConnection(): Promise<boolean> {
try {
// Try to fetch shows list as a connectivity test
await this.getShows();
return true;
} catch (e) {
logger.error('Channels DVR connection test failed', {
label: 'Channels DVR API',
errorMessage: e.message,
});
return false;
}
}
}
export default ChannelsDVRAPI;