fix(tautulli): fetch additional user history as necessary to return 20 unique media (#2446)

* fix(tautulli): fetch additional user history as necessary to return 20 unique media

* refactor: rename var for clarity

* refactor: make single DB query for recently watched media

* fix: resolve query builder weirdness

* refactor: use find instead of qb

* refactor: minor refactor

* fix: also find 4K rating keys
pull/2611/head
TheCatLady 2 years ago committed by GitHub
parent 72c825d2a5
commit 7d19de6a4a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,4 +1,5 @@
import axios, { AxiosInstance } from 'axios';
import { uniqWith } from 'lodash';
import { User } from '../entity/User';
import { TautulliSettings } from '../lib/settings';
import logger from '../logger';
@ -231,23 +232,48 @@ class TautulliAPI {
public async getUserWatchHistory(
user: User
): Promise<TautulliHistoryRecord[]> {
let results: TautulliHistoryRecord[] = [];
try {
if (!user.plexId) {
throw new Error('User does not have an associated Plex ID');
}
return (
await this.axios.get<TautulliHistoryResponse>('/api/v2', {
params: {
cmd: 'get_history',
grouping: 1,
order_column: 'date',
order_dir: 'desc',
user_id: user.plexId,
length: 100,
},
})
).data.response.data.data;
const take = 100;
let start = 0;
while (results.length < 20) {
const tautulliData = (
await this.axios.get<TautulliHistoryResponse>('/api/v2', {
params: {
cmd: 'get_history',
grouping: 1,
order_column: 'date',
order_dir: 'desc',
user_id: user.plexId,
media_type: 'movie,episode',
length: take,
start,
},
})
).data.response.data.data;
if (!tautulliData.length) {
return results;
}
results = uniqWith(results.concat(tautulliData), (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
);
start += take;
}
return results.slice(0, 20);
} catch (e) {
logger.error(
'Something went wrong fetching user watch history from Tautulli',

@ -1,9 +1,10 @@
import { Router } from 'express';
import gravatarUrl from 'gravatar-url';
import { uniqWith } from 'lodash';
import { getRepository, Not } from 'typeorm';
import { findIndex, sortBy } from 'lodash';
import { getRepository, In, Not } from 'typeorm';
import PlexTvAPI from '../../api/plextv';
import TautulliAPI from '../../api/tautulli';
import { MediaType } from '../../constants/media';
import { UserType } from '../../constants/user';
import Media from '../../entity/Media';
import { MediaRequest } from '../../entity/MediaRequest';
@ -521,7 +522,6 @@ router.get<{ id: string }, UserWatchDataResponse>(
}
try {
const mediaRepository = getRepository(Media);
const user = await getRepository(User).findOneOrFail({
where: { id: Number(req.params.id) },
select: ['id', 'plexId'],
@ -532,33 +532,64 @@ router.get<{ id: string }, UserWatchDataResponse>(
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[];
const recentlyWatched = sortBy(
await getRepository(Media).find({
where: [
{
mediaType: MediaType.MOVIE,
ratingKey: In(
watchHistory
.filter((record) => record.media_type === 'movie')
.map((record) => record.rating_key)
),
},
{
mediaType: MediaType.MOVIE,
ratingKey4k: In(
watchHistory
.filter((record) => record.media_type === 'movie')
.map((record) => record.rating_key)
),
},
{
mediaType: MediaType.TV,
ratingKey: In(
watchHistory
.filter((record) => record.media_type === 'episode')
.map((record) => record.grandparent_rating_key)
),
},
{
mediaType: MediaType.TV,
ratingKey4k: In(
watchHistory
.filter((record) => record.media_type === 'episode')
.map((record) => record.grandparent_rating_key)
),
},
],
}),
[
(media) =>
findIndex(
watchHistory,
(record) =>
(!!media.ratingKey &&
parseInt(media.ratingKey) ===
(record.media_type === 'movie'
? record.rating_key
: record.grandparent_rating_key)) ||
(!!media.ratingKey4k &&
parseInt(media.ratingKey4k) ===
(record.media_type === 'movie'
? record.rating_key
: record.grandparent_rating_key))
),
]
);
return res.status(200).json({
recentlyWatched: media,
recentlyWatched,
playCount: watchStats.total_plays,
});
} catch (e) {

Loading…
Cancel
Save