diff --git a/backend/migrations/061_jf_recent_playback_activity_function_fix_3.js b/backend/migrations/061_jf_recent_playback_activity_function_fix_3.js new file mode 100644 index 0000000..ccc4129 --- /dev/null +++ b/backend/migrations/061_jf_recent_playback_activity_function_fix_3.js @@ -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); + } +}; diff --git a/backend/tasks/ActivityMonitor.js b/backend/tasks/ActivityMonitor.js index 0ecb724..63a7414 100644 --- a/backend/tasks/ActivityMonitor.js +++ b/backend/tasks/ActivityMonitor.js @@ -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); diff --git a/package.json b/package.json index 7d4d9dd..5b89010 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "jfstat", - "version": "1.0.9", + "version": "1.1.0", "private": true, "main": "src/index.jsx", "scripts": {