From d5e9541010f806f1cf55fc4cccca8687d7e0adf5 Mon Sep 17 00:00:00 2001 From: Merlin Danner Date: Thu, 9 Feb 2023 03:14:48 +0100 Subject: [PATCH 01/18] Fix too long URLs on getItems with many ids --- CONTRIBUTORS.md | 1 + src/components/notifications/notifications.js | 5 +- src/components/playback/playbackmanager.js | 5 +- src/plugins/chromecastPlayer/plugin.js | 5 +- src/plugins/syncPlay/core/Helper.js | 5 +- .../jellyfin-apiclient/getItemsHelper.ts | 63 +++++++++++++++++++ 6 files changed, 80 insertions(+), 4 deletions(-) create mode 100644 src/utils/jellyfin-apiclient/getItemsHelper.ts diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index c867d81580..2e7aac76de 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -59,6 +59,7 @@ - [Vankerkom](https://github.com/vankerkom) - [edvwib](https://github.com/edvwib) - [Rob Farraher](https://github.com/farraherbg) + - [Merlin Sievers](https://github.com/dann-merlin) # Emby Contributors diff --git a/src/components/notifications/notifications.js b/src/components/notifications/notifications.js index 16c8312867..59fb12dc28 100644 --- a/src/components/notifications/notifications.js +++ b/src/components/notifications/notifications.js @@ -2,6 +2,7 @@ import serverNotifications from '../../scripts/serverNotifications'; import { playbackManager } from '../playback/playbackmanager'; import Events from '../../utils/events.ts'; import globalize from '../../scripts/globalize'; +import { getItems } from '../../utils/jellyfin-apiclient/getItemsHelper.ts'; import NotificationIcon from './notificationicon.png'; @@ -130,7 +131,9 @@ function onLibraryChanged(data, apiClient) { newItems.length = 12; } - apiClient.getItems(apiClient.getCurrentUserId(), { + // call getItems from getItemsHelper instead of apiClient.getItems() + // to split up into multiple requests if necessary (URL might get too long) + getItems(apiClient, apiClient.getCurrentUserId(), { Recursive: true, Limit: 3, diff --git a/src/components/playback/playbackmanager.js b/src/components/playback/playbackmanager.js index ffcd0e4d91..4894f4dbd3 100644 --- a/src/components/playback/playbackmanager.js +++ b/src/components/playback/playbackmanager.js @@ -12,6 +12,7 @@ import Screenfull from 'screenfull'; import ServerConnections from '../ServerConnections'; import alert from '../alert'; import { includesAny } from '../../utils/container.ts'; +import { getItems } from '../../utils/jellyfin-apiclient/getItemsHelper.ts'; const UNLIMITED_ITEMS = -1; @@ -126,7 +127,9 @@ function getItemsForPlayback(serverId, query) { query.EnableTotalRecordCount = false; query.CollapseBoxSetItems = false; - return apiClient.getItems(apiClient.getCurrentUserId(), query); + // call getItems from getItemsHelper instead of apiClient.getItems() + // to split up into multiple requests if necessary (URL might get too long) + return getItems(apiClient, apiClient.getCurrentUserId(), query); } } diff --git a/src/plugins/chromecastPlayer/plugin.js b/src/plugins/chromecastPlayer/plugin.js index 9044cd3e30..121add1339 100644 --- a/src/plugins/chromecastPlayer/plugin.js +++ b/src/plugins/chromecastPlayer/plugin.js @@ -6,6 +6,7 @@ import castSenderApiLoader from './castSenderApi'; import ServerConnections from '../../components/ServerConnections'; import alert from '../../components/alert'; import Events from '../../utils/events.ts'; +import { getItems } from '../../utils/jellyfin-apiclient/getItemsHelper.ts'; // Based on https://github.com/googlecast/CastVideos-chrome/blob/master/CastVideos.js @@ -481,7 +482,9 @@ function getItemsForPlayback(apiClient, query) { query.ExcludeLocationTypes = 'Virtual'; query.EnableTotalRecordCount = false; - return apiClient.getItems(userId, query); + // call getItems from getItemsHelper instead of apiClient.getItems() + // to split up into multiple requests if necessary (URL might get too long) + return getItems(apiClient, userId, query); } } diff --git a/src/plugins/syncPlay/core/Helper.js b/src/plugins/syncPlay/core/Helper.js index 38cdf179e8..701af96c7e 100644 --- a/src/plugins/syncPlay/core/Helper.js +++ b/src/plugins/syncPlay/core/Helper.js @@ -4,6 +4,7 @@ */ import Events from '../../../utils/events.ts'; +import { getItems } from '../../../utils/jellyfin-apiclient/getItemsHelper.ts'; /** * Constants @@ -88,7 +89,9 @@ export function getItemsForPlayback(apiClient, query) { query.EnableTotalRecordCount = false; query.CollapseBoxSetItems = false; - return apiClient.getItems(apiClient.getCurrentUserId(), query); + // call getItems from getItemsHelper instead of apiClient.getItems() + // to split up into multiple requests if necessary (URL might get too long) + return getItems(apiClient, apiClient.getCurrentUserId(), query); } } diff --git a/src/utils/jellyfin-apiclient/getItemsHelper.ts b/src/utils/jellyfin-apiclient/getItemsHelper.ts new file mode 100644 index 0000000000..3eee2ff36f --- /dev/null +++ b/src/utils/jellyfin-apiclient/getItemsHelper.ts @@ -0,0 +1,63 @@ +import type {BaseItemDtoQueryResult} from '@jellyfin/sdk/lib/generated-client'; +import {ApiClient} from 'jellyfin-apiclient'; + +const idsPerItemRequestLimit = 25; + +function getItemsSplit(apiClient: ApiClient, userId: string, options: any) { + const optionsTemplate = {...options}; + const ids = options.Ids.split(','); + const results = []; + + let nextI; + for (let i = 0; i < ids.length && i < options.Limit; i = nextI) { + nextI = i + idsPerItemRequestLimit; + if (nextI > options.Limit) { + nextI = options.Limit; + } + const idsSlice = ids.slice(i, nextI); + console.log(idsSlice); + optionsTemplate.Ids = idsSlice.join(','); + results.push(apiClient.getItems(userId, optionsTemplate)); + } + + return results; +} + +function mergeResults(results: BaseItemDtoQueryResult[]) { + const merged: BaseItemDtoQueryResult = {}; + merged.Items = []; + merged.TotalRecordCount = 0; + merged.StartIndex = 0; + + for (const result of results) { + if (result.Items == null) { + console.log(`Retrieved Items array is invalid: ${result.Items}`); + continue; + } + if (result.TotalRecordCount == null) { + console.log(`Retrieved TotalRecordCount is invalid: ${ + result.TotalRecordCount}`); + continue; + } + if (result.StartIndex == null) { + console.log( + `Retrieved StartIndex is invalid: ${result.StartIndex}`); + continue; + } + merged.Items = merged.Items.concat(result.Items); + merged.TotalRecordCount += result.TotalRecordCount; + merged.StartIndex = Math.min(merged.StartIndex, result.StartIndex); + } + return merged; +} + +export function getItems(apiClient: ApiClient, userId: string, options?: any): + Promise { + if (options.Ids === undefined || + options.Ids.split(',').ength <= idsPerItemRequestLimit) { + return apiClient.getItems(apiClient.getCurrentUserId(), options); + } + const results = getItemsSplit(apiClient, userId, options); + + return Promise.all(results).then(mergeResults); +} From aede0fa8caaeece2d44272e299ada75b1415a9c8 Mon Sep 17 00:00:00 2001 From: dann-merlin <55287004+dann-merlin@users.noreply.github.com> Date: Tue, 7 Mar 2023 23:49:40 +0000 Subject: [PATCH 02/18] Fixing type in getItems.ts Co-authored-by: Bill Thornton --- src/utils/jellyfin-apiclient/getItemsHelper.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/jellyfin-apiclient/getItemsHelper.ts b/src/utils/jellyfin-apiclient/getItemsHelper.ts index 3eee2ff36f..bef989d349 100644 --- a/src/utils/jellyfin-apiclient/getItemsHelper.ts +++ b/src/utils/jellyfin-apiclient/getItemsHelper.ts @@ -54,7 +54,7 @@ function mergeResults(results: BaseItemDtoQueryResult[]) { export function getItems(apiClient: ApiClient, userId: string, options?: any): Promise { if (options.Ids === undefined || - options.Ids.split(',').ength <= idsPerItemRequestLimit) { + options.Ids.split(',').length <= idsPerItemRequestLimit) { return apiClient.getItems(apiClient.getCurrentUserId(), options); } const results = getItemsSplit(apiClient, userId, options); From baa4f0a29d01bd2dcc706f6f43a830d6d029f26f Mon Sep 17 00:00:00 2001 From: dann-merlin <55287004+dann-merlin@users.noreply.github.com> Date: Tue, 7 Mar 2023 23:52:34 +0000 Subject: [PATCH 03/18] Improve log message for invalid TotalRecordCount in getItems Co-authored-by: Bill Thornton --- src/utils/jellyfin-apiclient/getItemsHelper.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/utils/jellyfin-apiclient/getItemsHelper.ts b/src/utils/jellyfin-apiclient/getItemsHelper.ts index bef989d349..b783abb5a6 100644 --- a/src/utils/jellyfin-apiclient/getItemsHelper.ts +++ b/src/utils/jellyfin-apiclient/getItemsHelper.ts @@ -35,8 +35,7 @@ function mergeResults(results: BaseItemDtoQueryResult[]) { continue; } if (result.TotalRecordCount == null) { - console.log(`Retrieved TotalRecordCount is invalid: ${ - result.TotalRecordCount}`); + console.log('[getItems] Retrieved TotalRecordCount is invalid', result.TotalRecordCount); continue; } if (result.StartIndex == null) { From e6937240553c07405078acda30b09d6f2bc503ae Mon Sep 17 00:00:00 2001 From: Merlin Danner Date: Wed, 8 Mar 2023 00:53:26 +0100 Subject: [PATCH 04/18] Remove leftover debugging log in getItems --- src/utils/jellyfin-apiclient/getItemsHelper.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/utils/jellyfin-apiclient/getItemsHelper.ts b/src/utils/jellyfin-apiclient/getItemsHelper.ts index b783abb5a6..0f19ac8ae0 100644 --- a/src/utils/jellyfin-apiclient/getItemsHelper.ts +++ b/src/utils/jellyfin-apiclient/getItemsHelper.ts @@ -15,7 +15,6 @@ function getItemsSplit(apiClient: ApiClient, userId: string, options: any) { nextI = options.Limit; } const idsSlice = ids.slice(i, nextI); - console.log(idsSlice); optionsTemplate.Ids = idsSlice.join(','); results.push(apiClient.getItems(userId, optionsTemplate)); } From 1a069b49bebc6e0e10d3c0cb144a2230155d235b Mon Sep 17 00:00:00 2001 From: Merlin Danner Date: Wed, 8 Mar 2023 01:29:14 +0100 Subject: [PATCH 05/18] Rename getItemsHelper.ts to getItems.ts --- src/components/notifications/notifications.js | 4 ++-- src/components/playback/playbackmanager.js | 4 ++-- src/plugins/chromecastPlayer/plugin.js | 4 ++-- src/plugins/syncPlay/core/Helper.js | 4 ++-- .../jellyfin-apiclient/{getItemsHelper.ts => getItems.ts} | 0 5 files changed, 8 insertions(+), 8 deletions(-) rename src/utils/jellyfin-apiclient/{getItemsHelper.ts => getItems.ts} (100%) diff --git a/src/components/notifications/notifications.js b/src/components/notifications/notifications.js index 59fb12dc28..13c4ffd8da 100644 --- a/src/components/notifications/notifications.js +++ b/src/components/notifications/notifications.js @@ -2,7 +2,7 @@ import serverNotifications from '../../scripts/serverNotifications'; import { playbackManager } from '../playback/playbackmanager'; import Events from '../../utils/events.ts'; import globalize from '../../scripts/globalize'; -import { getItems } from '../../utils/jellyfin-apiclient/getItemsHelper.ts'; +import { getItems } from '../../utils/jellyfin-apiclient/getItems.ts'; import NotificationIcon from './notificationicon.png'; @@ -131,7 +131,7 @@ function onLibraryChanged(data, apiClient) { newItems.length = 12; } - // call getItems from getItemsHelper instead of apiClient.getItems() + // call getItems from jellyfin-apiclient/getItems.ts instead of apiClient.getItems() // to split up into multiple requests if necessary (URL might get too long) getItems(apiClient, apiClient.getCurrentUserId(), { diff --git a/src/components/playback/playbackmanager.js b/src/components/playback/playbackmanager.js index 4894f4dbd3..6088ad821d 100644 --- a/src/components/playback/playbackmanager.js +++ b/src/components/playback/playbackmanager.js @@ -12,7 +12,7 @@ import Screenfull from 'screenfull'; import ServerConnections from '../ServerConnections'; import alert from '../alert'; import { includesAny } from '../../utils/container.ts'; -import { getItems } from '../../utils/jellyfin-apiclient/getItemsHelper.ts'; +import { getItems } from '../../utils/jellyfin-apiclient/getItems.ts'; const UNLIMITED_ITEMS = -1; @@ -127,7 +127,7 @@ function getItemsForPlayback(serverId, query) { query.EnableTotalRecordCount = false; query.CollapseBoxSetItems = false; - // call getItems from getItemsHelper instead of apiClient.getItems() + // call getItems from jellyfin-apiclient/getItems.ts instead of apiClient.getItems() // to split up into multiple requests if necessary (URL might get too long) return getItems(apiClient, apiClient.getCurrentUserId(), query); } diff --git a/src/plugins/chromecastPlayer/plugin.js b/src/plugins/chromecastPlayer/plugin.js index 121add1339..ebc682cbb1 100644 --- a/src/plugins/chromecastPlayer/plugin.js +++ b/src/plugins/chromecastPlayer/plugin.js @@ -6,7 +6,7 @@ import castSenderApiLoader from './castSenderApi'; import ServerConnections from '../../components/ServerConnections'; import alert from '../../components/alert'; import Events from '../../utils/events.ts'; -import { getItems } from '../../utils/jellyfin-apiclient/getItemsHelper.ts'; +import { getItems } from '../../utils/jellyfin-apiclient/getItems.ts'; // Based on https://github.com/googlecast/CastVideos-chrome/blob/master/CastVideos.js @@ -482,7 +482,7 @@ function getItemsForPlayback(apiClient, query) { query.ExcludeLocationTypes = 'Virtual'; query.EnableTotalRecordCount = false; - // call getItems from getItemsHelper instead of apiClient.getItems() + // call getItems from jellyfin-apiclient/getItems.ts instead of apiClient.getItems() // to split up into multiple requests if necessary (URL might get too long) return getItems(apiClient, userId, query); } diff --git a/src/plugins/syncPlay/core/Helper.js b/src/plugins/syncPlay/core/Helper.js index 701af96c7e..364217e980 100644 --- a/src/plugins/syncPlay/core/Helper.js +++ b/src/plugins/syncPlay/core/Helper.js @@ -4,7 +4,7 @@ */ import Events from '../../../utils/events.ts'; -import { getItems } from '../../../utils/jellyfin-apiclient/getItemsHelper.ts'; +import { getItems } from '../../../utils/jellyfin-apiclient/getItems.ts'; /** * Constants @@ -89,7 +89,7 @@ export function getItemsForPlayback(apiClient, query) { query.EnableTotalRecordCount = false; query.CollapseBoxSetItems = false; - // call getItems from getItemsHelper instead of apiClient.getItems() + // call getItems from jellyfin-apiclient/getItems.ts instead of apiClient.getItems() // to split up into multiple requests if necessary (URL might get too long) return getItems(apiClient, apiClient.getCurrentUserId(), query); } diff --git a/src/utils/jellyfin-apiclient/getItemsHelper.ts b/src/utils/jellyfin-apiclient/getItems.ts similarity index 100% rename from src/utils/jellyfin-apiclient/getItemsHelper.ts rename to src/utils/jellyfin-apiclient/getItems.ts From 96febf9f254aad9571600d61498638a39202262c Mon Sep 17 00:00:00 2001 From: Merlin Danner Date: Wed, 29 Mar 2023 06:29:37 +0200 Subject: [PATCH 06/18] Rename file level constant to conform naming conv. Renames idsPerItemRequestLimit to ITEMS_PER_REQUEST_LIMIT as it as a file level constant. --- src/utils/jellyfin-apiclient/getItems.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/utils/jellyfin-apiclient/getItems.ts b/src/utils/jellyfin-apiclient/getItems.ts index 0f19ac8ae0..c17d9a50c1 100644 --- a/src/utils/jellyfin-apiclient/getItems.ts +++ b/src/utils/jellyfin-apiclient/getItems.ts @@ -1,7 +1,7 @@ import type {BaseItemDtoQueryResult} from '@jellyfin/sdk/lib/generated-client'; import {ApiClient} from 'jellyfin-apiclient'; -const idsPerItemRequestLimit = 25; +const ITEMS_PER_REQUEST_LIMIT = 25; function getItemsSplit(apiClient: ApiClient, userId: string, options: any) { const optionsTemplate = {...options}; @@ -10,7 +10,7 @@ function getItemsSplit(apiClient: ApiClient, userId: string, options: any) { let nextI; for (let i = 0; i < ids.length && i < options.Limit; i = nextI) { - nextI = i + idsPerItemRequestLimit; + nextI = i + ITEMS_PER_REQUEST_LIMIT; if (nextI > options.Limit) { nextI = options.Limit; } @@ -52,7 +52,7 @@ function mergeResults(results: BaseItemDtoQueryResult[]) { export function getItems(apiClient: ApiClient, userId: string, options?: any): Promise { if (options.Ids === undefined || - options.Ids.split(',').length <= idsPerItemRequestLimit) { + options.Ids.split(',').length <= ITEMS_PER_REQUEST_LIMIT) { return apiClient.getItems(apiClient.getCurrentUserId(), options); } const results = getItemsSplit(apiClient, userId, options); From 117dd153945c76ed3ebb9c249d698b76da6bffb2 Mon Sep 17 00:00:00 2001 From: Merlin Danner Date: Wed, 29 Mar 2023 06:50:15 +0200 Subject: [PATCH 07/18] Rename variable in getItemsSplit loop --- src/utils/jellyfin-apiclient/getItems.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/utils/jellyfin-apiclient/getItems.ts b/src/utils/jellyfin-apiclient/getItems.ts index c17d9a50c1..3b394fbbd7 100644 --- a/src/utils/jellyfin-apiclient/getItems.ts +++ b/src/utils/jellyfin-apiclient/getItems.ts @@ -8,13 +8,13 @@ function getItemsSplit(apiClient: ApiClient, userId: string, options: any) { const ids = options.Ids.split(','); const results = []; - let nextI; - for (let i = 0; i < ids.length && i < options.Limit; i = nextI) { - nextI = i + ITEMS_PER_REQUEST_LIMIT; - if (nextI > options.Limit) { - nextI = options.Limit; + let end; + for (let start = 0; start < ids.length && start < options.Limit; start = end) { + end = start + ITEMS_PER_REQUEST_LIMIT; + if (end > options.Limit) { + end = options.Limit; } - const idsSlice = ids.slice(i, nextI); + const idsSlice = ids.slice(start, end); optionsTemplate.Ids = idsSlice.join(','); results.push(apiClient.getItems(userId, optionsTemplate)); } From eca7cc7cedb2e3e5bac2b7361b1759dd8425d1ad Mon Sep 17 00:00:00 2001 From: dann-merlin <55287004+dann-merlin@users.noreply.github.com> Date: Wed, 29 Mar 2023 04:59:20 +0000 Subject: [PATCH 08/18] Update src/utils/jellyfin-apiclient/getItems.ts Co-authored-by: Bill Thornton --- src/utils/jellyfin-apiclient/getItems.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/utils/jellyfin-apiclient/getItems.ts b/src/utils/jellyfin-apiclient/getItems.ts index 3b394fbbd7..00c8290b22 100644 --- a/src/utils/jellyfin-apiclient/getItems.ts +++ b/src/utils/jellyfin-apiclient/getItems.ts @@ -23,10 +23,11 @@ function getItemsSplit(apiClient: ApiClient, userId: string, options: any) { } function mergeResults(results: BaseItemDtoQueryResult[]) { - const merged: BaseItemDtoQueryResult = {}; - merged.Items = []; - merged.TotalRecordCount = 0; - merged.StartIndex = 0; + const merged: BaseItemDtoQueryResult = { + Items: [], + TotalRecordCount: 0, + StartIndex: 0 + }; for (const result of results) { if (result.Items == null) { From da4f890adfdb2338b78ed4856fb3703c9ff2514d Mon Sep 17 00:00:00 2001 From: dann-merlin <55287004+dann-merlin@users.noreply.github.com> Date: Wed, 29 Mar 2023 05:00:04 +0000 Subject: [PATCH 09/18] Update src/utils/jellyfin-apiclient/getItems.ts Co-authored-by: Bill Thornton --- src/utils/jellyfin-apiclient/getItems.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/jellyfin-apiclient/getItems.ts b/src/utils/jellyfin-apiclient/getItems.ts index 00c8290b22..4323f64eef 100644 --- a/src/utils/jellyfin-apiclient/getItems.ts +++ b/src/utils/jellyfin-apiclient/getItems.ts @@ -31,7 +31,7 @@ function mergeResults(results: BaseItemDtoQueryResult[]) { for (const result of results) { if (result.Items == null) { - console.log(`Retrieved Items array is invalid: ${result.Items}`); + console.log('[getItems] Retrieved Items array is invalid', result.Items); continue; } if (result.TotalRecordCount == null) { From 5932decce5d8b9fcd1ba0897d1df3ee737322f06 Mon Sep 17 00:00:00 2001 From: dann-merlin <55287004+dann-merlin@users.noreply.github.com> Date: Wed, 29 Mar 2023 05:00:40 +0000 Subject: [PATCH 10/18] Update src/utils/jellyfin-apiclient/getItems.ts Co-authored-by: Bill Thornton --- src/utils/jellyfin-apiclient/getItems.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/utils/jellyfin-apiclient/getItems.ts b/src/utils/jellyfin-apiclient/getItems.ts index 4323f64eef..ddbebb5b73 100644 --- a/src/utils/jellyfin-apiclient/getItems.ts +++ b/src/utils/jellyfin-apiclient/getItems.ts @@ -39,8 +39,7 @@ function mergeResults(results: BaseItemDtoQueryResult[]) { continue; } if (result.StartIndex == null) { - console.log( - `Retrieved StartIndex is invalid: ${result.StartIndex}`); + console.log('[getItems] Retrieved StartIndex is invalid', result.StartIndex); continue; } merged.Items = merged.Items.concat(result.Items); From 2154ea64adb5535933929632d2527daa5c0dd368 Mon Sep 17 00:00:00 2001 From: dann-merlin <55287004+dann-merlin@users.noreply.github.com> Date: Wed, 29 Mar 2023 05:02:23 +0000 Subject: [PATCH 11/18] Update src/utils/jellyfin-apiclient/getItems.ts Co-authored-by: Bill Thornton --- src/utils/jellyfin-apiclient/getItems.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/utils/jellyfin-apiclient/getItems.ts b/src/utils/jellyfin-apiclient/getItems.ts index ddbebb5b73..ebdeeca8d8 100644 --- a/src/utils/jellyfin-apiclient/getItems.ts +++ b/src/utils/jellyfin-apiclient/getItems.ts @@ -49,8 +49,7 @@ function mergeResults(results: BaseItemDtoQueryResult[]) { return merged; } -export function getItems(apiClient: ApiClient, userId: string, options?: any): - Promise { +export function getItems(apiClient: ApiClient, userId: string, options?: any) { if (options.Ids === undefined || options.Ids.split(',').length <= ITEMS_PER_REQUEST_LIMIT) { return apiClient.getItems(apiClient.getCurrentUserId(), options); From 762feba94c696665f84910b96ceaf0f396dc53ea Mon Sep 17 00:00:00 2001 From: Merlin Danner Date: Wed, 29 Mar 2023 07:06:29 +0200 Subject: [PATCH 12/18] Use syntactic sugar to check if Ids is undefined --- src/utils/jellyfin-apiclient/getItems.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/utils/jellyfin-apiclient/getItems.ts b/src/utils/jellyfin-apiclient/getItems.ts index ebdeeca8d8..b08fefe8d4 100644 --- a/src/utils/jellyfin-apiclient/getItems.ts +++ b/src/utils/jellyfin-apiclient/getItems.ts @@ -50,8 +50,7 @@ function mergeResults(results: BaseItemDtoQueryResult[]) { } export function getItems(apiClient: ApiClient, userId: string, options?: any) { - if (options.Ids === undefined || - options.Ids.split(',').length <= ITEMS_PER_REQUEST_LIMIT) { + if (options.Ids?.split(',').length <= ITEMS_PER_REQUEST_LIMIT) { return apiClient.getItems(apiClient.getCurrentUserId(), options); } const results = getItemsSplit(apiClient, userId, options); From d8bbba2dc9be586813a414eb11fb3b2fd9946d3f Mon Sep 17 00:00:00 2001 From: Merlin Danner Date: Wed, 29 Mar 2023 07:26:22 +0200 Subject: [PATCH 13/18] Add handling of undefined cases for tsc The handled cases are never going to actually be undefined, as the affected variables are defined before. tsc however was not satisfied so these changed had to be made. --- src/utils/jellyfin-apiclient/getItems.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/utils/jellyfin-apiclient/getItems.ts b/src/utils/jellyfin-apiclient/getItems.ts index b08fefe8d4..c47e707cca 100644 --- a/src/utils/jellyfin-apiclient/getItems.ts +++ b/src/utils/jellyfin-apiclient/getItems.ts @@ -42,9 +42,9 @@ function mergeResults(results: BaseItemDtoQueryResult[]) { console.log('[getItems] Retrieved StartIndex is invalid', result.StartIndex); continue; } - merged.Items = merged.Items.concat(result.Items); - merged.TotalRecordCount += result.TotalRecordCount; - merged.StartIndex = Math.min(merged.StartIndex, result.StartIndex); + merged.Items = merged.Items?.concat(result.Items); + merged.TotalRecordCount! += result.TotalRecordCount; + merged.StartIndex = Math.min(merged.StartIndex || 0, result.StartIndex); } return merged; } From 06c4f0f258cfb444775442cea69f6c9de63649c0 Mon Sep 17 00:00:00 2001 From: Merlin Danner Date: Wed, 29 Mar 2023 07:44:21 +0200 Subject: [PATCH 14/18] Add JSDoc comment to getItems helper In return the comments at each usage are removed. --- src/components/notifications/notifications.js | 2 -- src/components/playback/playbackmanager.js | 2 -- src/plugins/chromecastPlayer/plugin.js | 2 -- src/plugins/syncPlay/core/Helper.js | 2 -- src/utils/jellyfin-apiclient/getItems.ts | 8 ++++++++ 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/components/notifications/notifications.js b/src/components/notifications/notifications.js index 13c4ffd8da..2d11691e95 100644 --- a/src/components/notifications/notifications.js +++ b/src/components/notifications/notifications.js @@ -131,8 +131,6 @@ function onLibraryChanged(data, apiClient) { newItems.length = 12; } - // call getItems from jellyfin-apiclient/getItems.ts instead of apiClient.getItems() - // to split up into multiple requests if necessary (URL might get too long) getItems(apiClient, apiClient.getCurrentUserId(), { Recursive: true, diff --git a/src/components/playback/playbackmanager.js b/src/components/playback/playbackmanager.js index 0d0434c972..14c841bea5 100644 --- a/src/components/playback/playbackmanager.js +++ b/src/components/playback/playbackmanager.js @@ -128,8 +128,6 @@ function getItemsForPlayback(serverId, query) { query.EnableTotalRecordCount = false; query.CollapseBoxSetItems = false; - // call getItems from jellyfin-apiclient/getItems.ts instead of apiClient.getItems() - // to split up into multiple requests if necessary (URL might get too long) return getItems(apiClient, apiClient.getCurrentUserId(), query); } } diff --git a/src/plugins/chromecastPlayer/plugin.js b/src/plugins/chromecastPlayer/plugin.js index d4aca76a3d..a656337d63 100644 --- a/src/plugins/chromecastPlayer/plugin.js +++ b/src/plugins/chromecastPlayer/plugin.js @@ -483,8 +483,6 @@ function getItemsForPlayback(apiClient, query) { query.ExcludeLocationTypes = 'Virtual'; query.EnableTotalRecordCount = false; - // call getItems from jellyfin-apiclient/getItems.ts instead of apiClient.getItems() - // to split up into multiple requests if necessary (URL might get too long) return getItems(apiClient, userId, query); } } diff --git a/src/plugins/syncPlay/core/Helper.js b/src/plugins/syncPlay/core/Helper.js index 364217e980..47f25578a3 100644 --- a/src/plugins/syncPlay/core/Helper.js +++ b/src/plugins/syncPlay/core/Helper.js @@ -89,8 +89,6 @@ export function getItemsForPlayback(apiClient, query) { query.EnableTotalRecordCount = false; query.CollapseBoxSetItems = false; - // call getItems from jellyfin-apiclient/getItems.ts instead of apiClient.getItems() - // to split up into multiple requests if necessary (URL might get too long) return getItems(apiClient, apiClient.getCurrentUserId(), query); } } diff --git a/src/utils/jellyfin-apiclient/getItems.ts b/src/utils/jellyfin-apiclient/getItems.ts index c47e707cca..03f242ac0d 100644 --- a/src/utils/jellyfin-apiclient/getItems.ts +++ b/src/utils/jellyfin-apiclient/getItems.ts @@ -49,6 +49,14 @@ function mergeResults(results: BaseItemDtoQueryResult[]) { return merged; } +/** + * Transparently handles the call to apiClient.getItems splitting the + * call into multiple ones if the URL might get too long. + * @param apiClient The ApiClient to use + * @param userId User id to pass to actual getItems call + * @param options Options object to specify getItems option. This includes a possibly long Items list that will be split up. + * @returns A promise that resolves to the merged result of all getItems calls + */ export function getItems(apiClient: ApiClient, userId: string, options?: any) { if (options.Ids?.split(',').length <= ITEMS_PER_REQUEST_LIMIT) { return apiClient.getItems(apiClient.getCurrentUserId(), options); From 4fe4ed2b0a245cb1a58c8d0a243f3762cae81537 Mon Sep 17 00:00:00 2001 From: Merlin Danner Date: Mon, 3 Apr 2023 14:34:57 +0200 Subject: [PATCH 15/18] Define interface for getItems options --- src/utils/jellyfin-apiclient/getItems.ts | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/utils/jellyfin-apiclient/getItems.ts b/src/utils/jellyfin-apiclient/getItems.ts index 03f242ac0d..1d0562f2c0 100644 --- a/src/utils/jellyfin-apiclient/getItems.ts +++ b/src/utils/jellyfin-apiclient/getItems.ts @@ -1,18 +1,24 @@ import type {BaseItemDtoQueryResult} from '@jellyfin/sdk/lib/generated-client'; import {ApiClient} from 'jellyfin-apiclient'; +interface GetItemsRequest { + Ids?: string; + Limit?: number; +} + const ITEMS_PER_REQUEST_LIMIT = 25; -function getItemsSplit(apiClient: ApiClient, userId: string, options: any) { +function getItemsSplit(apiClient: ApiClient, userId: string, options: GetItemsRequest) { const optionsTemplate = {...options}; - const ids = options.Ids.split(','); + const ids = options.Ids!.split(','); const results = []; + const limit = options.Limit ?? Infinity; let end; - for (let start = 0; start < ids.length && start < options.Limit; start = end) { + for (let start: number = 0; start < ids.length && start < limit; start = end) { end = start + ITEMS_PER_REQUEST_LIMIT; - if (end > options.Limit) { - end = options.Limit; + if (end > limit) { + end = limit; } const idsSlice = ids.slice(start, end); optionsTemplate.Ids = idsSlice.join(','); @@ -57,8 +63,9 @@ function mergeResults(results: BaseItemDtoQueryResult[]) { * @param options Options object to specify getItems option. This includes a possibly long Items list that will be split up. * @returns A promise that resolves to the merged result of all getItems calls */ -export function getItems(apiClient: ApiClient, userId: string, options?: any) { - if (options.Ids?.split(',').length <= ITEMS_PER_REQUEST_LIMIT) { +export function getItems(apiClient: ApiClient, userId: string, options?: GetItemsRequest) { + const ids = options?.Ids?.split(','); + if (!options || !ids || ids.length <= ITEMS_PER_REQUEST_LIMIT) { return apiClient.getItems(apiClient.getCurrentUserId(), options); } const results = getItemsSplit(apiClient, userId, options); From 840fbed68a96d23a3b97fc2a5e3de3fb5f9dba12 Mon Sep 17 00:00:00 2001 From: Merlin Danner Date: Thu, 13 Apr 2023 13:15:53 +0200 Subject: [PATCH 16/18] Fix eslint errors (syntax) --- src/utils/jellyfin-apiclient/getItems.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/utils/jellyfin-apiclient/getItems.ts b/src/utils/jellyfin-apiclient/getItems.ts index 1d0562f2c0..550d005254 100644 --- a/src/utils/jellyfin-apiclient/getItems.ts +++ b/src/utils/jellyfin-apiclient/getItems.ts @@ -1,5 +1,5 @@ -import type {BaseItemDtoQueryResult} from '@jellyfin/sdk/lib/generated-client'; -import {ApiClient} from 'jellyfin-apiclient'; +import type { BaseItemDtoQueryResult } from '@jellyfin/sdk/lib/generated-client'; +import { ApiClient } from 'jellyfin-apiclient'; interface GetItemsRequest { Ids?: string; @@ -9,13 +9,13 @@ interface GetItemsRequest { const ITEMS_PER_REQUEST_LIMIT = 25; function getItemsSplit(apiClient: ApiClient, userId: string, options: GetItemsRequest) { - const optionsTemplate = {...options}; + const optionsTemplate = { ...options }; const ids = options.Ids!.split(','); const results = []; const limit = options.Limit ?? Infinity; let end; - for (let start: number = 0; start < ids.length && start < limit; start = end) { + for (let start = 0; start < ids.length && start < limit; start = end) { end = start + ITEMS_PER_REQUEST_LIMIT; if (end > limit) { end = limit; From 3629e826dff36c316a3ada759d78bd7e922ddc60 Mon Sep 17 00:00:00 2001 From: dann-merlin <55287004+dann-merlin@users.noreply.github.com> Date: Wed, 19 Apr 2023 00:43:21 +0000 Subject: [PATCH 17/18] Update src/utils/jellyfin-apiclient/getItems.ts Co-authored-by: Bill Thornton --- src/utils/jellyfin-apiclient/getItems.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/jellyfin-apiclient/getItems.ts b/src/utils/jellyfin-apiclient/getItems.ts index 550d005254..79bdcbbca2 100644 --- a/src/utils/jellyfin-apiclient/getItems.ts +++ b/src/utils/jellyfin-apiclient/getItems.ts @@ -10,7 +10,7 @@ const ITEMS_PER_REQUEST_LIMIT = 25; function getItemsSplit(apiClient: ApiClient, userId: string, options: GetItemsRequest) { const optionsTemplate = { ...options }; - const ids = options.Ids!.split(','); + const ids = options.Ids?.split(',') || []; const results = []; const limit = options.Limit ?? Infinity; From 012c28161546b36037c319fd001649f1afe41bf1 Mon Sep 17 00:00:00 2001 From: Merlin Danner Date: Wed, 19 Apr 2023 02:43:47 +0200 Subject: [PATCH 18/18] Bump ITEMS_PER_REQUEST_LIMIT to 40 (getItems call) --- src/utils/jellyfin-apiclient/getItems.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/jellyfin-apiclient/getItems.ts b/src/utils/jellyfin-apiclient/getItems.ts index 79bdcbbca2..dee681a5d5 100644 --- a/src/utils/jellyfin-apiclient/getItems.ts +++ b/src/utils/jellyfin-apiclient/getItems.ts @@ -6,7 +6,7 @@ interface GetItemsRequest { Limit?: number; } -const ITEMS_PER_REQUEST_LIMIT = 25; +const ITEMS_PER_REQUEST_LIMIT = 40; function getItemsSplit(apiClient: ApiClient, userId: string, options: GetItemsRequest) { const optionsTemplate = { ...options };