Playback tracking fix 3

Fix for Series Tracking where different episode where tracking under the same episode for that show
This commit is contained in:
Thegan Govender
2024-01-11 10:57:03 +02:00
parent 6176ea21fa
commit 1c77dfb2dd
3 changed files with 165 additions and 6 deletions

View File

@@ -0,0 +1,159 @@
exports.up = async function(knex) {
try
{
await knex.schema.raw(`
CREATE OR REPLACE FUNCTION jf_recent_playback_activity(hour_offset INT)
RETURNS TABLE (
"RunTimeTicks" BIGINT,
"Progress" NUMERIC,
"Id" TEXT,
"IsPaused" BOOLEAN,
"UserId" TEXT,
"UserName" TEXT,
"Client" TEXT,
"DeviceName" TEXT,
"DeviceId" TEXT,
"ApplicationVersion" TEXT,
"NowPlayingItemId" TEXT,
"NowPlayingItemName" TEXT,
"SeasonId" TEXT,
"SeriesName" TEXT,
"EpisodeId" TEXT,
"PlaybackDuration" BIGINT,
"ActivityDateInserted" timestamptz,
"PlayMethod" TEXT,
"MediaStreams" JSON,
"TranscodingInfo" JSON,
"PlayState" JSON,
"OriginalContainer" TEXT,
"RemoteEndPoint" TEXT,
"ServerId" TEXT,
"Imported" BOOLEAN,
"RowNum" BIGINT
)
AS $$
BEGIN
RETURN QUERY
WITH rankedactivities AS (
SELECT COALESCE(i."RunTimeTicks", e."RunTimeTicks") AS "RunTimeTicks",
((a."PlaybackDuration" * 10000000)::numeric(100,0) / COALESCE(i."RunTimeTicks"::numeric(100,0), e."RunTimeTicks"::numeric(100,0), 1.0) * 100::numeric)::numeric(10,2) AS "Progress",
a."Id",
a."IsPaused",
a."UserId",
a."UserName",
a."Client",
a."DeviceName",
a."DeviceId",
a."ApplicationVersion",
a."NowPlayingItemId",
a."NowPlayingItemName",
a."SeasonId",
a."SeriesName",
a."EpisodeId",
a."PlaybackDuration",
a."ActivityDateInserted",
a."PlayMethod",
a."MediaStreams",
a."TranscodingInfo",
a."PlayState",
a."OriginalContainer",
a."RemoteEndPoint",
a."ServerId",
a.imported,
row_number() OVER (PARTITION BY a."NowPlayingItemId",a."EpisodeId",a."UserId" ORDER BY a."ActivityDateInserted" DESC) AS rownum
FROM jf_playback_activity a
LEFT JOIN jf_library_items i ON a."NowPlayingItemId" = i."Id"
LEFT JOIN jf_library_episodes e ON a."EpisodeId" = e."EpisodeId"
WHERE a."ActivityDateInserted" > (CURRENT_TIMESTAMP - (hour_offset || ' hours')::interval)
ORDER BY a."ActivityDateInserted" DESC
)
SELECT * FROM rankedactivities WHERE rankedactivities.rownum = 1;
END;
$$ LANGUAGE plpgsql;
`
);
}catch (error) {
console.error(error);
}
};
exports.down = async function(knex) {
try {
await knex.raw(`
CREATE OR REPLACE FUNCTION jf_recent_playback_activity(hour_offset INT)
RETURNS TABLE (
"RunTimeTicks" BIGINT,
"Progress" NUMERIC,
"Id" TEXT,
"IsPaused" BOOLEAN,
"UserId" TEXT,
"UserName" TEXT,
"Client" TEXT,
"DeviceName" TEXT,
"DeviceId" TEXT,
"ApplicationVersion" TEXT,
"NowPlayingItemId" TEXT,
"NowPlayingItemName" TEXT,
"SeasonId" TEXT,
"SeriesName" TEXT,
"EpisodeId" TEXT,
"PlaybackDuration" BIGINT,
"ActivityDateInserted" timestamptz,
"PlayMethod" TEXT,
"MediaStreams" JSON,
"TranscodingInfo" JSON,
"PlayState" JSON,
"OriginalContainer" TEXT,
"RemoteEndPoint" TEXT,
"ServerId" TEXT,
"Imported" BOOLEAN,
"RowNum" BIGINT
)
AS $$
BEGIN
RETURN QUERY
WITH rankedactivities AS (
SELECT COALESCE(i."RunTimeTicks", e."RunTimeTicks") AS "RunTimeTicks",
((a."PlaybackDuration" * 10000000)::numeric(100,0) / COALESCE(i."RunTimeTicks"::numeric(100,0), e."RunTimeTicks"::numeric(100,0), 1.0) * 100::numeric)::numeric(10,2) AS "Progress",
a."Id",
a."IsPaused",
a."UserId",
a."UserName",
a."Client",
a."DeviceName",
a."DeviceId",
a."ApplicationVersion",
a."NowPlayingItemId",
a."NowPlayingItemName",
a."SeasonId",
a."SeriesName",
a."EpisodeId",
a."PlaybackDuration",
a."ActivityDateInserted",
a."PlayMethod",
a."MediaStreams",
a."TranscodingInfo",
a."PlayState",
a."OriginalContainer",
a."RemoteEndPoint",
a."ServerId",
a.imported,
row_number() OVER (PARTITION BY a."NowPlayingItemId",a."UserId" ORDER BY a."ActivityDateInserted" DESC) AS rownum
FROM jf_playback_activity a
LEFT JOIN jf_library_items i ON a."NowPlayingItemId" = i."Id"
LEFT JOIN jf_library_episodes e ON a."EpisodeId" = e."EpisodeId"
WHERE a."ActivityDateInserted" > (CURRENT_TIMESTAMP - (hour_offset || ' hours')::interval)
ORDER BY a."ActivityDateInserted" DESC
)
SELECT * FROM rankedactivities WHERE rankedactivities.rownum = 1;
END;
$$ LANGUAGE plpgsql;
`);
} catch (error) {
console.error(error);
}
};

View File

@@ -160,10 +160,10 @@ async function ActivityMonitor(interval) {
});
const playbackToInsertIds=playbackToInsert.map((row) => row.NowPlayingItemId);
/////get data from jf_playback_activity within the last hour with progress of <=80% for current items in session
const ExistingRecords=await db.query(`SELECT * FROM jf_recent_playback_activity(1)`).then((res) => res.rows.filter((row) => playbackToInsertIds.includes(row.NowPlayingItemId) && row.Progress<=80.0));
const ExistingRecords=await db.query(`SELECT * FROM jf_recent_playback_activity(1)`).then((res) => res.rows.filter((row) => playbackToInsert.some((pbi) => pbi.NowPlayingItemId===row.NowPlayingItemId && pbi.EpisodeId===row.EpisodeId) && row.Progress<=80.0));
let ExistingDataToUpdate = [];
//for each item in playbackToInsert, check if it exists in the recent playback activity and update accordingly
@@ -171,7 +171,7 @@ async function ActivityMonitor(interval) {
{
ExistingDataToUpdate=playbackToInsert.filter((playbackData) => {
const existingrow=ExistingRecords.find((existing) => existing.NowPlayingItemId === playbackData.NowPlayingItemId && existing.UserId === playbackData.UserId);
const existingrow=ExistingRecords.find((existing) => existing.NowPlayingItemId === playbackData.NowPlayingItemId && existing.EpisodeId===playbackData.EpisodeId && existing.UserId === playbackData.UserId);
if(existingrow)
{
@@ -185,8 +185,8 @@ async function ActivityMonitor(interval) {
}
//remove items from playbackToInsert that already exists in the recent playback activity so it doesnt duplicate or where PlaybackDuration===0
playbackToInsert = playbackToInsert.filter((pb) => pb.PlaybackDuration>0 && !ExistingRecords.some(er => er.NowPlayingItemId === pb.NowPlayingItemId && er.UserId === pb.UserId));
playbackToInsert = playbackToInsert.filter((pb) => pb.PlaybackDuration>0 && !ExistingRecords.some(er => er.NowPlayingItemId === pb.NowPlayingItemId && er.EpisodeId===pb.EpisodeId && er.UserId === pb.UserId));
//remove items where PlaybackDuration===0
ExistingDataToUpdate = ExistingDataToUpdate.filter((pb) => pb.PlaybackDuration>0);

View File

@@ -1,6 +1,6 @@
{
"name": "jfstat",
"version": "1.0.9",
"version": "1.1.0",
"private": true,
"main": "src/index.jsx",
"scripts": {