Fix for sync issues

Change to Included mixed libraries broke sync as Jellyfin does not populate a CollectionType for this library type breaking the no-null constraint. A default value of 'mixed' will be passed instead of a null.

Modified js_library_stats_overview to account for empty libraries

Modified Libraries view to cater for the above changes + added error boundaries
This commit is contained in:
Thegan Govender
2023-06-03 01:40:29 +02:00
parent 1d4f08ecf6
commit 37bbfef0ba
5 changed files with 131 additions and 8 deletions

View File

@@ -0,0 +1,123 @@
exports.up = function(knex) {
const query = `
CREATE OR REPLACE VIEW public.js_library_stats_overview
AS
SELECT DISTINCT ON (l."Id") l."Id",
l."Name",
l."ServerId",
l."IsFolder",
l."Type",
l."CollectionType",
l."ImageTagsPrimary",
i."Id" AS "ItemId",
i."Name" AS "ItemName",
i."Type" AS "ItemType",
i."PrimaryImageHash",
s."IndexNumber" AS "SeasonNumber",
e."IndexNumber" AS "EpisodeNumber",
e."Name" AS "EpisodeName",
( SELECT count(*) AS count
FROM jf_playback_activity a
JOIN jf_library_items i_1 ON a."NowPlayingItemId" = i_1."Id"
WHERE i_1."ParentId" = l."Id") AS "Plays",
( SELECT sum(a."PlaybackDuration") AS sum
FROM jf_playback_activity a
JOIN jf_library_items i_1 ON a."NowPlayingItemId" = i_1."Id"
WHERE i_1."ParentId" = l."Id") AS total_playback_duration,
COALESCE(cv."Library_Count",0)"Library_Count",
COALESCE(cv."Season_Count",0)"Season_Count",
COALESCE(cv."Episode_Count",0)"Episode_Count",
now() - latest_activity."ActivityDateInserted" AS "LastActivity"
FROM jf_libraries l
left JOIN jf_library_count_view cv ON cv."Id" = l."Id"
LEFT JOIN ( SELECT jf_playback_activity."Id",
jf_playback_activity."IsPaused",
jf_playback_activity."UserId",
jf_playback_activity."UserName",
jf_playback_activity."Client",
jf_playback_activity."DeviceName",
jf_playback_activity."DeviceId",
jf_playback_activity."ApplicationVersion",
jf_playback_activity."NowPlayingItemId",
jf_playback_activity."NowPlayingItemName",
jf_playback_activity."SeasonId",
jf_playback_activity."SeriesName",
jf_playback_activity."EpisodeId",
jf_playback_activity."PlaybackDuration",
jf_playback_activity."ActivityDateInserted",
jf_playback_activity."PlayMethod",
i_1."ParentId"
FROM jf_playback_activity
JOIN jf_library_items i_1 ON i_1."Id" = jf_playback_activity."NowPlayingItemId"
ORDER BY jf_playback_activity."ActivityDateInserted" DESC) latest_activity ON l."Id" = latest_activity."ParentId"
LEFT JOIN jf_library_items i ON i."Id" = latest_activity."NowPlayingItemId"
LEFT JOIN jf_library_seasons s ON s."Id" = latest_activity."SeasonId"
LEFT JOIN jf_library_episodes e ON e."EpisodeId" = latest_activity."EpisodeId"
ORDER BY l."Id", latest_activity."ActivityDateInserted" DESC;
`;
return knex.schema.raw(query).catch(function(error) {
console.error(error);
});
};
exports.down = function(knex) {
return knex.schema.raw(`
CREATE VIEW js_library_stats_overview AS
SELECT DISTINCT ON (l."Id") l."Id",
l."Name",
l."ServerId",
l."IsFolder",
l."Type",
l."CollectionType",
l."ImageTagsPrimary",
i."Id" AS "ItemId",
i."Name" AS "ItemName",
i."Type" AS "ItemType",
i."PrimaryImageHash",
s."IndexNumber" AS "SeasonNumber",
e."IndexNumber" AS "EpisodeNumber",
e."Name" AS "EpisodeName",
( SELECT count(*) AS count
FROM jf_playback_activity a
JOIN jf_library_items i_1 ON a."NowPlayingItemId" = i_1."Id"
WHERE i_1."ParentId" = l."Id") AS "Plays",
( SELECT sum(a."PlaybackDuration") AS sum
FROM jf_playback_activity a
JOIN jf_library_items i_1 ON a."NowPlayingItemId" = i_1."Id"
WHERE i_1."ParentId" = l."Id") AS total_playback_duration,
cv."Library_Count",
cv."Season_Count",
cv."Episode_Count",
now() - latest_activity."ActivityDateInserted" AS "LastActivity"
FROM jf_libraries l
JOIN jf_library_count_view cv ON cv."Id" = l."Id"
LEFT JOIN ( SELECT jf_playback_activity."Id",
jf_playback_activity."IsPaused",
jf_playback_activity."UserId",
jf_playback_activity."UserName",
jf_playback_activity."Client",
jf_playback_activity."DeviceName",
jf_playback_activity."DeviceId",
jf_playback_activity."ApplicationVersion",
jf_playback_activity."NowPlayingItemId",
jf_playback_activity."NowPlayingItemName",
jf_playback_activity."SeasonId",
jf_playback_activity."SeriesName",
jf_playback_activity."EpisodeId",
jf_playback_activity."PlaybackDuration",
jf_playback_activity."ActivityDateInserted",
jf_playback_activity."PlayMethod",
i_1."ParentId"
FROM jf_playback_activity
JOIN jf_library_items i_1 ON i_1."Id" = jf_playback_activity."NowPlayingItemId"
ORDER BY jf_playback_activity."ActivityDateInserted" DESC) latest_activity ON l."Id" = latest_activity."ParentId"
LEFT JOIN jf_library_items i ON i."Id" = latest_activity."NowPlayingItemId"
LEFT JOIN jf_library_seasons s ON s."Id" = latest_activity."SeasonId"
LEFT JOIN jf_library_episodes e ON e."EpisodeId" = latest_activity."EpisodeId"
ORDER BY l."Id", latest_activity."ActivityDateInserted" DESC;
`);
};

View File

@@ -15,7 +15,7 @@
ServerId: item.ServerId,
IsFolder: item.IsFolder,
Type: item.Type,
CollectionType: item.CollectionType,
CollectionType: item.CollectionType? item.CollectionType : 'mixed',
ImageTagsPrimary:
item.ImageTags && item.ImageTags.Primary ? item.ImageTags.Primary : null,
});

View File

@@ -1,6 +1,6 @@
{
"name": "jfstat",
"version": "1.0.4.5",
"version": "1.0.4.6",
"private": true,
"dependencies": {
"@emotion/react": "^11.10.6",

View File

@@ -105,12 +105,12 @@ function LibraryCard(props) {
<Row className="space-between-end card-row">
<Col className="card-label">Total Files</Col>
<Col className="text-end">{props.metadata.files}</Col>
<Col className="text-end">{props.metadata && props.metadata.files ? props.metadata.files :0}</Col>
</Row>
<Row className="space-between-end card-row">
<Col className="card-label">Library Size</Col>
<Col className="text-end">{formatFileSize(props.metadata.Size)}</Col>
<Col className="text-end">{formatFileSize(props.metadata && props.metadata.Size ? props.metadata.Size:0)}</Col>
</Row>
<Row className="space-between-end card-row">

View File

@@ -5,7 +5,7 @@ import Config from "../lib/config";
import "./css/library/libraries.css";
import Loading from "./components/general/loading";
import LibraryCard from "./components/library/library-card";
import ErrorBoundary from "./components/general/ErrorBoundary";
function Libraries() {
@@ -82,9 +82,9 @@ function Libraries() {
<div xs={1} md={2} lg={4} className="g-0 libraries-container">
{data &&
data.map((item) => (
<LibraryCard key={item.Id} data={item} metadata={metadata.find(data => data.Id === item.Id)} base_url={config.hostUrl}/>
<ErrorBoundary key={item.Id} >
<LibraryCard data={item} metadata={metadata.find(data => data.Id === item.Id)} base_url={config.hostUrl}/>
</ErrorBoundary>
))}
</div>