import axios, { AxiosInstance } from 'axios'; import { User } from '../entity/User'; import { TautulliSettings } from '../lib/settings'; import logger from '../logger'; export interface TautulliHistoryRecord { date: number; duration: number; friendly_name: string; full_title: string; grandparent_rating_key: number; grandparent_title: string; original_title: string; group_count: number; group_ids?: string; guid: string; ip_address: string; live: number; machine_id: string; media_index: number; media_type: string; originally_available_at: string; parent_media_index: number; parent_rating_key: number; parent_title: string; paused_counter: number; percent_complete: number; platform: string; product: string; player: string; rating_key: number; reference_id?: number; row_id?: number; session_key?: string; started: number; state?: string; stopped: number; thumb: string; title: string; transcode_decision: string; user: string; user_id: number; watched_status: number; year: number; } interface TautulliHistoryResponse { response: { result: string; message?: string; data: { draw: number; recordsTotal: number; recordsFiltered: number; total_duration: string; filter_duration: string; data: TautulliHistoryRecord[]; }; }; } interface TautulliWatchStats { query_days: number; total_time: number; total_plays: number; } interface TautulliWatchStatsResponse { response: { result: string; message?: string; data: TautulliWatchStats[]; }; } interface TautulliWatchUser { friendly_name: string; user_id: number; user_thumb: string; username: string; total_plays: number; total_time: number; } interface TautulliWatchUsersResponse { response: { result: string; message?: string; data: TautulliWatchUser[]; }; } class TautulliAPI { private axios: AxiosInstance; constructor(settings: TautulliSettings) { this.axios = axios.create({ baseURL: `${settings.useSsl ? 'https' : 'http'}://${settings.hostname}:${ settings.port }${settings.urlBase ?? ''}`, params: { apikey: settings.apiKey }, }); } public async getMediaWatchStats( ratingKey: string ): Promise { try { return ( await this.axios.get('/api/v2', { params: { cmd: 'get_item_watch_time_stats', rating_key: ratingKey, grouping: 1, }, }) ).data.response.data; } catch (e) { logger.error( 'Something went wrong fetching media watch stats from Tautulli', { label: 'Tautulli API', errorMessage: e.message, ratingKey, } ); throw new Error( `[Tautulli] Failed to fetch media watch stats: ${e.message}` ); } } public async getMediaWatchUsers( ratingKey: string ): Promise { try { return ( await this.axios.get('/api/v2', { params: { cmd: 'get_item_user_stats', rating_key: ratingKey, grouping: 1, }, }) ).data.response.data; } catch (e) { logger.error( 'Something went wrong fetching media watch users from Tautulli', { label: 'Tautulli API', errorMessage: e.message, ratingKey, } ); throw new Error( `[Tautulli] Failed to fetch media watch users: ${e.message}` ); } } public async getUserWatchStats(user: User): Promise { try { if (!user.plexId) { throw new Error('User does not have an associated Plex ID'); } return ( await this.axios.get('/api/v2', { params: { cmd: 'get_user_watch_time_stats', user_id: user.plexId, query_days: 0, grouping: 1, }, }) ).data.response.data[0]; } catch (e) { logger.error( 'Something went wrong fetching user watch stats from Tautulli', { label: 'Tautulli API', errorMessage: e.message, user: user.displayName, } ); throw new Error( `[Tautulli] Failed to fetch user watch stats: ${e.message}` ); } } public async getUserWatchHistory( user: User ): Promise { try { if (!user.plexId) { throw new Error('User does not have an associated Plex ID'); } return ( await this.axios.get('/api/v2', { params: { cmd: 'get_history', grouping: 1, order_column: 'date', order_dir: 'desc', user_id: user.plexId, length: 100, }, }) ).data.response.data.data; } catch (e) { logger.error( 'Something went wrong fetching user watch history from Tautulli', { label: 'Tautulli API', errorMessage: e.message, user: user.displayName, } ); throw new Error( `[Tautulli] Failed to fetch user watch history: ${e.message}` ); } } } export default TautulliAPI;