From a87dd2c0d56d74c9c8d5feebc0cad227552d3379 Mon Sep 17 00:00:00 2001 From: Thegan Govender Date: Sun, 16 Apr 2023 20:55:05 +0200 Subject: [PATCH] fixed migration sequence Had duplicate migration sequences Minor css changes and link rewrites to take you the specific item in the library overview for last watched items --- .../025_fs_last_library_activity_function.js | 87 +++++++++++++++++ .../026_fs_last_user_activity_function.js | 96 +++++++++++++++++++ ...iew.js => 027_js_library_metadata_view.js} | 0 .../components/general/last-watched-card.js | 2 +- src/pages/components/item-info.js | 3 +- .../components/item-info/item-details.js | 1 - .../libraryStatCard/library-stat-component.js | 2 +- src/pages/components/sessions/session-card.js | 2 +- .../components/statCards/ItemStatComponent.js | 4 +- src/pages/css/globalstats.css | 2 +- src/pages/css/items/item-details.css | 4 +- src/pages/css/lastplayed.css | 6 +- src/pages/css/libraryOverview.css | 4 +- src/pages/css/loading.css | 7 ++ src/pages/css/recent.css | 8 +- src/pages/css/sessions.css | 10 +- src/pages/css/statCard.css | 6 +- src/pages/css/stats.css | 2 +- src/pages/css/users/user-details.css | 2 +- src/pages/css/users/users.css | 4 +- src/pages/css/websocket/websocket.css | 2 +- 21 files changed, 221 insertions(+), 33 deletions(-) create mode 100644 backend/migrations/025_fs_last_library_activity_function.js create mode 100644 backend/migrations/026_fs_last_user_activity_function.js rename backend/migrations/{024_js_library_metadata_view.js => 027_js_library_metadata_view.js} (100%) diff --git a/backend/migrations/025_fs_last_library_activity_function.js b/backend/migrations/025_fs_last_library_activity_function.js new file mode 100644 index 0000000..7b1a52c --- /dev/null +++ b/backend/migrations/025_fs_last_library_activity_function.js @@ -0,0 +1,87 @@ +exports.up = function(knex) { + return knex.schema.raw(` + DROP FUNCTION IF EXISTS fs_last_library_activity(text); + CREATE OR REPLACE FUNCTION public.fs_last_library_activity( + libraryid text) + RETURNS TABLE("Id" text,"EpisodeId" text, "Name" text, "EpisodeName" text, "SeasonNumber" integer, "EpisodeNumber" integer, "PrimaryImageHash" text, "UserId" text, "UserName" text, "LastPlayed" interval) + LANGUAGE 'plpgsql' + COST 100 + VOLATILE PARALLEL UNSAFE + ROWS 1000 + + AS $BODY$ + BEGIN + RETURN QUERY + SELECT * + FROM ( + SELECT DISTINCT ON (i."Name", e."Name") + i."Id", + a."EpisodeId", + i."Name", + e."Name" AS "EpisodeName", + CASE WHEN a."SeasonId" IS NOT NULL THEN s."IndexNumber" ELSE NULL END AS "SeasonNumber", + CASE WHEN a."SeasonId" IS NOT NULL THEN e."IndexNumber" ELSE NULL END AS "EpisodeNumber", + i."PrimaryImageHash", + a."UserId", + a."UserName", + (NOW() - a."ActivityDateInserted") as "LastPlayed" + FROM jf_playback_activity a + JOIN jf_library_items i ON i."Id" = a."NowPlayingItemId" + JOIN jf_libraries l ON i."ParentId" = l."Id" + LEFT JOIN jf_library_seasons s ON s."Id" = a."SeasonId" + LEFT JOIN jf_library_episodes e ON e."EpisodeId" = a."EpisodeId" + WHERE l."Id" = libraryid + ORDER BY i."Name", e."Name", a."ActivityDateInserted" DESC + ) AS latest_distinct_rows + ORDER BY "LastPlayed" + LIMIT 15; + END; + + $BODY$; + + `).catch(function(error) { + console.error(error); + }); + }; + + exports.down = function(knex) { + return knex.schema.raw(` + DROP FUNCTION IF EXISTS fs_last_library_activity(text); + CREATE OR REPLACE FUNCTION fs_last_library_activity( + libraryid text) + RETURNS TABLE("Id" text, "Name" text, "EpisodeName" text, "SeasonNumber" integer, "EpisodeNumber" integer, "PrimaryImageHash" text, "UserId" text, "UserName" text, "LastPlayed" interval) + LANGUAGE 'plpgsql' + COST 100 + VOLATILE PARALLEL UNSAFE + ROWS 1000 + + AS $BODY$ + BEGIN + RETURN QUERY + SELECT * + FROM ( + SELECT DISTINCT ON (i."Name", e."Name") + i."Id", + i."Name", + e."Name" AS "EpisodeName", + CASE WHEN a."SeasonId" IS NOT NULL THEN s."IndexNumber" ELSE NULL END AS "SeasonNumber", + CASE WHEN a."SeasonId" IS NOT NULL THEN e."IndexNumber" ELSE NULL END AS "EpisodeNumber", + i."PrimaryImageHash", + a."UserId", + a."UserName", + (NOW() - a."ActivityDateInserted") as "LastPlayed" + FROM jf_playback_activity a + JOIN jf_library_items i ON i."Id" = a."NowPlayingItemId" + JOIN jf_libraries l ON i."ParentId" = l."Id" + LEFT JOIN jf_library_seasons s ON s."Id" = a."SeasonId" + LEFT JOIN jf_library_episodes e ON e."EpisodeId" = a."EpisodeId" + WHERE l."Id" = libraryid + ORDER BY i."Name", e."Name", a."ActivityDateInserted" DESC + ) AS latest_distinct_rows + ORDER BY "LastPlayed" + LIMIT 15; + END; + $BODY$; + `); + }; + \ No newline at end of file diff --git a/backend/migrations/026_fs_last_user_activity_function.js b/backend/migrations/026_fs_last_user_activity_function.js new file mode 100644 index 0000000..2ce4bba --- /dev/null +++ b/backend/migrations/026_fs_last_user_activity_function.js @@ -0,0 +1,96 @@ +exports.up = function(knex) { + return knex.raw(` + DROP FUNCTION IF EXISTS fs_last_user_activity(text); + CREATE OR REPLACE FUNCTION public.fs_last_user_activity( + userid text) + RETURNS TABLE("Id" text,"EpisodeId" text, "Name" text, "EpisodeName" text, "SeasonNumber" integer, "EpisodeNumber" integer, "PrimaryImageHash" text, "UserId" text, "UserName" text, "LastPlayed" interval) + LANGUAGE 'plpgsql' + COST 100 + VOLATILE PARALLEL UNSAFE + ROWS 1000 + + AS $BODY$ + BEGIN + RETURN QUERY + SELECT * + FROM ( + SELECT DISTINCT ON (i."Name", e."Name") + i."Id", + a."EpisodeId", + i."Name", + e."Name" AS "EpisodeName", + CASE WHEN a."SeasonId" IS NOT NULL THEN s."IndexNumber" ELSE NULL END AS "SeasonNumber", + CASE WHEN a."SeasonId" IS NOT NULL THEN e."IndexNumber" ELSE NULL END AS "EpisodeNumber", + i."PrimaryImageHash", + a."UserId", + a."UserName", + (NOW() - a."ActivityDateInserted") as "LastPlayed" + FROM jf_playback_activity a + JOIN jf_library_items i ON i."Id" = a."NowPlayingItemId" + LEFT JOIN jf_library_seasons s ON s."Id" = a."SeasonId" + LEFT JOIN jf_library_episodes e ON e."EpisodeId" = a."EpisodeId" + WHERE a."UserId" = userid + ) AS latest_distinct_rows + ORDER BY "LastPlayed"; + END; + + $BODY$; + + ALTER FUNCTION fs_last_user_activity(text) + OWNER TO ${process.env.POSTGRES_USER}; + `).catch(function(error) { + console.error(error); + }); + }; + + exports.down = function(knex) { + return knex.raw(` + DROP FUNCTION IF EXISTS fs_last_user_activity(text); + CREATE OR REPLACE FUNCTION fs_last_user_activity( + userid text + ) + RETURNS TABLE( + "Id" text, + "Name" text, + "EpisodeName" text, + "SeasonNumber" integer, + "EpisodeNumber" integer, + "PrimaryImageHash" text, + "UserId" text, + "UserName" text, + "LastPlayed" interval + ) + LANGUAGE 'plpgsql' + COST 100 + VOLATILE PARALLEL UNSAFE + ROWS 1000 + AS $BODY$ + BEGIN + RETURN QUERY + SELECT * + FROM ( + SELECT DISTINCT ON (i."Name", e."Name") + i."Id", + i."Name", + e."Name" AS "EpisodeName", + CASE WHEN a."SeasonId" IS NOT NULL THEN s."IndexNumber" ELSE NULL END AS "SeasonNumber", + CASE WHEN a."SeasonId" IS NOT NULL THEN e."IndexNumber" ELSE NULL END AS "EpisodeNumber", + i."PrimaryImageHash", + a."UserId", + a."UserName", + (NOW() - a."ActivityDateInserted") as "LastPlayed" + FROM jf_playback_activity a + JOIN jf_library_items i ON i."Id" = a."NowPlayingItemId" + LEFT JOIN jf_library_seasons s ON s."Id" = a."SeasonId" + LEFT JOIN jf_library_episodes e ON e."EpisodeId" = a."EpisodeId" + WHERE a."UserId" = userid + ) AS latest_distinct_rows + ORDER BY "LastPlayed"; + END; + $BODY$; + + ALTER FUNCTION fs_last_user_activity(text) + OWNER TO ${process.env.POSTGRES_USER}; + `); + }; + \ No newline at end of file diff --git a/backend/migrations/024_js_library_metadata_view.js b/backend/migrations/027_js_library_metadata_view.js similarity index 100% rename from backend/migrations/024_js_library_metadata_view.js rename to backend/migrations/027_js_library_metadata_view.js diff --git a/src/pages/components/general/last-watched-card.js b/src/pages/components/general/last-watched-card.js index 3f20a65..5fcb292 100644 --- a/src/pages/components/general/last-watched-card.js +++ b/src/pages/components/general/last-watched-card.js @@ -33,7 +33,7 @@ function LastWatchedCard(props) { const [loaded, setLoaded] = useState(false); return (
- +
{loaded ? null : } { if(config){ setRefresh(true); try { - console.log(Id); const itemData = await axios.post(`/api/getItemDetails`, { Id: Id }, { @@ -64,7 +63,7 @@ useEffect(() => { return () => clearInterval(intervalId); }, [config, Id]); -console.log(data); + if(!data) diff --git a/src/pages/components/item-info/item-details.js b/src/pages/components/item-info/item-details.js index 3d9860b..057e338 100644 --- a/src/pages/components/item-info/item-details.js +++ b/src/pages/components/item-info/item-details.js @@ -75,7 +75,6 @@ function ItemDetails(props) {
- {props.data.CommunityRating ?

Community Rating: {props.data.CommunityRating}

:<>} {props.data.Type==="Episode"?

{props.data.SeasonName} Episode {props.data.IndexNumber} - {props.data.Name}

: <> } {props.data.Type==="Season"?

{props.data.Name}

: <> } {props.data.FileName ?

File Name: {props.data.FileName}

:<>} diff --git a/src/pages/components/libraryStatCard/library-stat-component.js b/src/pages/components/libraryStatCard/library-stat-component.js index 51c193c..2717899 100644 --- a/src/pages/components/libraryStatCard/library-stat-component.js +++ b/src/pages/components/libraryStatCard/library-stat-component.js @@ -14,7 +14,7 @@ function LibraryStatComponent(props) { }; const cardBgStyle = { - backdropFilter: 'blur(10px)', + backdropFilter: 'blur(5px)', backgroundColor: 'rgb(0, 0, 0, 0.6)', height:'100%', }; diff --git a/src/pages/components/sessions/session-card.js b/src/pages/components/sessions/session-card.js index 1122fe8..cf391f4 100644 --- a/src/pages/components/sessions/session-card.js +++ b/src/pages/components/sessions/session-card.js @@ -39,7 +39,7 @@ function sessionCard(props) { }; const cardBgStyle = { - backdropFilter: 'blur(10px)', + backdropFilter: 'blur(5px)', backgroundColor: 'rgb(0, 0, 0, 0.6)', height:'100%', }; diff --git a/src/pages/components/statCards/ItemStatComponent.js b/src/pages/components/statCards/ItemStatComponent.js index e1218f7..f9e8a77 100644 --- a/src/pages/components/statCards/ItemStatComponent.js +++ b/src/pages/components/statCards/ItemStatComponent.js @@ -17,11 +17,11 @@ function ItemStatComponent(props) { const cardStyle = { backgroundImage: `url(${props.base_url}/Items/${props.data[0].Id}/Images/Backdrop/?fillWidth=300&quality=10), linear-gradient(to right, #00A4DC, #AA5CC3)`, height:'100%', - backgroundSize: 'contain', + backgroundSize: 'cover', }; const cardBgStyle = { - backdropFilter: 'blur(10px)', + backdropFilter: 'blur(5px)', backgroundColor: 'rgb(0, 0, 0, 0.6)', height:'100%', }; diff --git a/src/pages/css/globalstats.css b/src/pages/css/globalstats.css index 394aa67..fe25a32 100644 --- a/src/pages/css/globalstats.css +++ b/src/pages/css/globalstats.css @@ -5,7 +5,7 @@ grid-auto-rows: 120px; background-color: rgb(100, 100, 100,0.2); padding: 20px; - border-radius: 4px; + border-radius: 8px; font-size: 1.3em; } diff --git a/src/pages/css/items/item-details.css b/src/pages/css/items/item-details.css index db49c8f..3f82f30 100644 --- a/src/pages/css/items/item-details.css +++ b/src/pages/css/items/item-details.css @@ -4,7 +4,7 @@ background-color: rgb(100, 100, 100,0.2); padding: 20px; margin: 20px 0; - border-radius: 4px; + border-radius: 8px; } .item-name @@ -16,7 +16,7 @@ .item-image { max-width: 200px; - border-radius: 4px; + border-radius: 8px; object-fit: cover; } diff --git a/src/pages/css/lastplayed.css b/src/pages/css/lastplayed.css index 974e21b..d1d67eb 100644 --- a/src/pages/css/lastplayed.css +++ b/src/pages/css/lastplayed.css @@ -4,7 +4,7 @@ overflow-x: auto; background-color: rgb(100, 100, 100,0.2); padding: 20px; - border-radius: 4px; + border-radius: 8px; color: white; margin-bottom: 20px; min-height: 300px; @@ -41,7 +41,7 @@ margin-right: 20px; width: 150px; - border-radius: 4px; + border-radius: 8px; } @@ -70,7 +70,7 @@ width: 100%; height: 100%; - border-radius: 4px 4px 0px 0px; + border-radius: 8px 8px 0px 0px; } diff --git a/src/pages/css/libraryOverview.css b/src/pages/css/libraryOverview.css index 78e7dcc..484a420 100644 --- a/src/pages/css/libraryOverview.css +++ b/src/pages/css/libraryOverview.css @@ -4,7 +4,7 @@ grid-template-columns: repeat(auto-fit, minmax(320px, 520px)); grid-auto-rows: 200px;/* max-width+offset so 215 + 20*/ - border-radius: 4px; + border-radius: 8px; /* margin-right: 20px; */ } @@ -106,7 +106,7 @@ .library{ width: 100%; padding: 5px 20px; - backdrop-filter: blur(4px); + backdrop-filter: blur(8px); background-color: rgb(0, 0, 0, 0.6); } diff --git a/src/pages/css/loading.css b/src/pages/css/loading.css index 575b140..550b120 100644 --- a/src/pages/css/loading.css +++ b/src/pages/css/loading.css @@ -9,7 +9,14 @@ align-items: center; z-index: 9999; background-color: #1e1c22; + transition: opacity 800ms ease-in; + opacity: 1; } +.loading::before +{ + opacity: 0; +} + .component-loading { height: inherit; diff --git a/src/pages/css/recent.css b/src/pages/css/recent.css index 1c7b443..1bcd718 100644 --- a/src/pages/css/recent.css +++ b/src/pages/css/recent.css @@ -4,7 +4,7 @@ grid-auto-rows: 340px;/* max-width+offset so 215 + 20*/ background-color: rgba(0,0,0,0.5); padding: 20px; - border-radius: 4px; + border-radius: 8px; margin-right: 20px; color: white; @@ -23,7 +23,7 @@ height: 320px; width: 185px; - border-radius: 4px; + border-radius: 8px; /* Add a third row that takes up remaining space */ @@ -36,7 +36,7 @@ background-size: cover; background-repeat: no-repeat; background-position: center top; - border-radius: 4px 4px 0px 0px; + border-radius: 8px 8px 0px 0px; } @@ -46,7 +46,7 @@ width: 100%; height: 30%; position: relative; - /* margin: 4px; */ + /* margin: 8px; */ /* background-color: #f71b1b; */ } diff --git a/src/pages/css/sessions.css b/src/pages/css/sessions.css index 2173ce1..57e24df 100644 --- a/src/pages/css/sessions.css +++ b/src/pages/css/sessions.css @@ -22,7 +22,7 @@ /* margin-bottom: 10px; */ background-size: cover; - border-radius: 4px 4px 0px 4px; + border-radius: 8px 8px 0px 8px; display: grid; grid-template-columns: auto 1fr; @@ -36,7 +36,7 @@ grid-column: 1/3; */ height: 5px; background-color: #101010 !important; - border-radius: 0px 0px 4px 4px; + border-radius: 0px 0px 8px 8px; } @@ -45,7 +45,7 @@ height: 100%; background-color: #00A4DC; transition: width 0.2s ease-in-out; - border-radius: 0px 0px 0px 4px; + border-radius: 0px 0px 0px 8px; } .card-banner { @@ -66,12 +66,12 @@ grid-column: 2 / 3; backdrop-filter: blur(1px); background-color: rgb(0, 0, 0, 0.6); - border-radius: 0px 4px 0px 0px; + border-radius: 0px 8px 0px 0px; } .card-banner-image { - border-radius: 4px 0px 0px 0px; + border-radius: 8px 0px 0px 0px; max-height: inherit; /* box-shadow: 0 0 20px 5px rgba(0, 0, 0, 0.8); */ } diff --git a/src/pages/css/statCard.css b/src/pages/css/statCard.css index a651b73..355bc7c 100644 --- a/src/pages/css/statCard.css +++ b/src/pages/css/statCard.css @@ -4,7 +4,7 @@ grid-template-columns: repeat(auto-fit, minmax(320px, 520px)); grid-auto-rows: 200px;/* max-width+offset so 215 + 20*/ /* margin-right: 20px; */ - margin-top: 4px; + margin-top: 8px; } .stat-card{ border: 0 !important; @@ -12,7 +12,7 @@ color: white; max-width: 500px; max-height: 180px; - border-radius: 4px !important; + border-radius: 8px !important; } .stat-card-banner @@ -71,7 +71,7 @@ color: white; display: flex; background-color: rgb(100, 100, 100,0.3); - border-radius: 4px; + border-radius: 8px; font-size: 1.2em; align-self: flex-end; justify-content: space-evenly; diff --git a/src/pages/css/stats.css b/src/pages/css/stats.css index fff8326..3940fa4 100644 --- a/src/pages/css/stats.css +++ b/src/pages/css/stats.css @@ -11,7 +11,7 @@ background-color:rgba(100,100,100,0.2); padding:10px; - border-radius:4px; + border-radius:8px; /* text-align: center; */ } diff --git a/src/pages/css/users/user-details.css b/src/pages/css/users/user-details.css index 9ff2d18..77a1846 100644 --- a/src/pages/css/users/user-details.css +++ b/src/pages/css/users/user-details.css @@ -4,7 +4,7 @@ background-color: rgb(100, 100, 100,0.2); padding: 20px; margin: 20px 0; - border-radius: 4px; + border-radius: 8px; display: flex; align-items: center; diff --git a/src/pages/css/users/users.css b/src/pages/css/users/users.css index cbe41c5..e2c2a90 100644 --- a/src/pages/css/users/users.css +++ b/src/pages/css/users/users.css @@ -124,7 +124,7 @@ td:first-child { color: white; display: flex; background-color: rgb(100, 100, 100,0.3); - border-radius: 4px; + border-radius: 8px; font-size: 1.2em; align-self: flex-end; justify-content: space-between; @@ -136,7 +136,7 @@ td:first-child { height: 35px; outline: none; border: none; - border-radius: 4px; + border-radius: 8px; background-color: rgb(255, 255, 255, 0.1); color:white; font-size: 1em; diff --git a/src/pages/css/websocket/websocket.css b/src/pages/css/websocket/websocket.css index 148ebc9..778bb62 100644 --- a/src/pages/css/websocket/websocket.css +++ b/src/pages/css/websocket/websocket.css @@ -6,7 +6,7 @@ margin-top: 20px; padding: 10px; margin-right: 10px; - border-radius: 4px; + border-radius: 8px; } .console-message {