mirror of
https://github.com/sct/overseerr.git
synced 2025-09-17 17:24:35 +02:00
feat: Tautulli integration (#2230)
* feat: media/user watch history data via Tautulli * fix(frontend): only display slideover cog button if there is media to manage * fix(lang): tweak permission denied messages * refactor: reorder Media section in slideover * refactor: use new Tautulli stats API * fix(frontend): do not attempt to fetch data when user lacks req perms * fix: remove unneccessary get_user requests * feat(frontend): display user avatars * feat: add external URL setting * feat: add play counts for past week/month * fix(lang): tweak strings Co-authored-by: Ryan Cohen <ryan@sct.dev>
This commit is contained in:
@@ -1,8 +1,11 @@
|
||||
import { Router } from 'express';
|
||||
import gravatarUrl from 'gravatar-url';
|
||||
import { uniqWith } from 'lodash';
|
||||
import { getRepository, Not } from 'typeorm';
|
||||
import PlexTvAPI from '../../api/plextv';
|
||||
import TautulliAPI from '../../api/tautulli';
|
||||
import { UserType } from '../../constants/user';
|
||||
import Media from '../../entity/Media';
|
||||
import { MediaRequest } from '../../entity/MediaRequest';
|
||||
import { User } from '../../entity/User';
|
||||
import { UserPushSubscription } from '../../entity/UserPushSubscription';
|
||||
@@ -10,6 +13,7 @@ import {
|
||||
QuotaResponse,
|
||||
UserRequestsResponse,
|
||||
UserResultsResponse,
|
||||
UserWatchDataResponse,
|
||||
} from '../../interfaces/api/userInterfaces';
|
||||
import { hasPermission, Permission } from '../../lib/permissions';
|
||||
import { getSettings } from '../../lib/settings';
|
||||
@@ -475,7 +479,8 @@ router.get<{ id: string }, QuotaResponse>(
|
||||
) {
|
||||
return next({
|
||||
status: 403,
|
||||
message: 'You do not have permission to access this endpoint.',
|
||||
message:
|
||||
"You do not have permission to view this user's request limits.",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -492,4 +497,82 @@ router.get<{ id: string }, QuotaResponse>(
|
||||
}
|
||||
);
|
||||
|
||||
router.get<{ id: string }, UserWatchDataResponse>(
|
||||
'/:id/watch_data',
|
||||
async (req, res, next) => {
|
||||
if (
|
||||
Number(req.params.id) !== req.user?.id &&
|
||||
!req.user?.hasPermission(Permission.ADMIN)
|
||||
) {
|
||||
return next({
|
||||
status: 403,
|
||||
message:
|
||||
"You do not have permission to view this user's recently watched media.",
|
||||
});
|
||||
}
|
||||
|
||||
const settings = getSettings().tautulli;
|
||||
|
||||
if (!settings.hostname || !settings.port || !settings.apiKey) {
|
||||
return next({
|
||||
status: 404,
|
||||
message: 'Tautulli API not configured.',
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
const mediaRepository = getRepository(Media);
|
||||
const user = await getRepository(User).findOneOrFail({
|
||||
where: { id: Number(req.params.id) },
|
||||
select: ['id', 'plexId'],
|
||||
});
|
||||
|
||||
const tautulli = new TautulliAPI(settings);
|
||||
|
||||
const watchStats = await tautulli.getUserWatchStats(user);
|
||||
const watchHistory = await tautulli.getUserWatchHistory(user);
|
||||
|
||||
const media = (
|
||||
await Promise.all(
|
||||
uniqWith(watchHistory, (recordA, recordB) =>
|
||||
recordA.grandparent_rating_key && recordB.grandparent_rating_key
|
||||
? recordA.grandparent_rating_key ===
|
||||
recordB.grandparent_rating_key
|
||||
: recordA.parent_rating_key && recordB.parent_rating_key
|
||||
? recordA.parent_rating_key === recordB.parent_rating_key
|
||||
: recordA.rating_key === recordB.rating_key
|
||||
)
|
||||
.slice(0, 20)
|
||||
.map(
|
||||
async (record) =>
|
||||
await mediaRepository.findOne({
|
||||
where: {
|
||||
ratingKey:
|
||||
record.media_type === 'movie'
|
||||
? record.rating_key
|
||||
: record.grandparent_rating_key,
|
||||
},
|
||||
})
|
||||
)
|
||||
)
|
||||
).filter((media) => !!media) as Media[];
|
||||
|
||||
return res.status(200).json({
|
||||
recentlyWatched: media,
|
||||
playCount: watchStats.total_plays,
|
||||
});
|
||||
} catch (e) {
|
||||
logger.error('Something went wrong fetching user watch data', {
|
||||
label: 'API',
|
||||
errorMessage: e.message,
|
||||
userId: req.params.id,
|
||||
});
|
||||
next({
|
||||
status: 500,
|
||||
message: 'Failed to fetch user watch data.',
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export default router;
|
||||
|
Reference in New Issue
Block a user