Skip to content

Commit bc986e4

Browse files
committed
Enhance filter functionality across activity components
- Moved Library Id and Stream Type filtering to be handled server side
1 parent 313edf2 commit bc986e4

5 files changed

Lines changed: 207 additions & 89 deletions

File tree

backend/routes/api.js

Lines changed: 43 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ const filterFields = [
6161
{ field: "PlaybackDuration", column: `a.PlaybackDuration`, isColumn: true, applyToCTE: true },
6262
{ field: "TotalPlays", column: `COALESCE("TotalPlays",1)` },
6363
{ field: "PlayMethod", column: `LOWER(a."PlayMethod")` },
64+
{ field: "ParentId", column: "a.ParentId", isColumn: true },
6465
];
6566

6667
//Functions
@@ -178,6 +179,34 @@ function buildFilterList(query, filtersArray) {
178179
}
179180
}
180181

182+
if (filter.in) {
183+
const values = filter.in.split(",");
184+
const valuesPlaceholders = values.map((_, i) => `$${query.values.length + i + 1}`).join(", ");
185+
query.where.push({
186+
column: column,
187+
operator: "in",
188+
value: `(${valuesPlaceholders})`,
189+
});
190+
191+
if (applyToCTE) {
192+
if (query.cte) {
193+
if (!query.cte.where) {
194+
query.cte.where = [];
195+
}
196+
const valuesPlaceholdersCTE = values.map((_, i) => `$${query.values.length + values.length + i + 1}`).join(", ");
197+
query.cte.where.push({
198+
column: column,
199+
operator: "in",
200+
value: `(${valuesPlaceholdersCTE})`,
201+
});
202+
}
203+
}
204+
query.values.push(...values);
205+
if (applyToCTE && query.cte) {
206+
query.values.push(...values);
207+
}
208+
}
209+
181210
if (filter.max) {
182211
query.where.push({
183212
column: column,
@@ -914,13 +943,13 @@ router.post("/setTaskSettings", async (req, res) => {
914943
router.get("/getActivityMonitorSettings", async (req, res) => {
915944
try {
916945
const settingsjson = await db.query('SELECT settings FROM app_config where "ID"=1').then((res) => res.rows);
917-
946+
918947
if (settingsjson.length > 0) {
919948
const settings = settingsjson[0].settings || {};
920949
console.log(settings);
921950
const pollingSettings = settings.ActivityMonitorPolling || {
922951
activeSessionsInterval: 1000,
923-
idleInterval: 5000
952+
idleInterval: 5000,
924953
};
925954
res.send(pollingSettings);
926955
} else {
@@ -933,52 +962,52 @@ router.get("/getActivityMonitorSettings", async (req, res) => {
933962
}
934963
});
935964

936-
// Set Activity Monitor Polling Settings
965+
// Set Activity Monitor Polling Settings
937966
router.post("/setActivityMonitorSettings", async (req, res) => {
938967
const { activeSessionsInterval, idleInterval } = req.body;
939-
968+
940969
if (activeSessionsInterval === undefined || idleInterval === undefined) {
941970
res.status(400);
942971
res.send("activeSessionsInterval and idleInterval are required");
943972
return;
944973
}
945-
974+
946975
if (!Number.isInteger(activeSessionsInterval) || activeSessionsInterval <= 0) {
947976
res.status(400);
948977
res.send("A valid activeSessionsInterval(int) which is > 0 milliseconds is required");
949978
return;
950979
}
951-
980+
952981
if (!Number.isInteger(idleInterval) || idleInterval <= 0) {
953982
res.status(400);
954983
res.send("A valid idleInterval(int) which is > 0 milliseconds is required");
955984
return;
956985
}
957-
986+
958987
if (activeSessionsInterval > idleInterval) {
959988
res.status(400);
960989
res.send("activeSessionsInterval should be <= idleInterval for optimal performance");
961990
return;
962991
}
963-
992+
964993
try {
965994
const settingsjson = await db.query('SELECT settings FROM app_config where "ID"=1').then((res) => res.rows);
966-
995+
967996
if (settingsjson.length > 0) {
968997
const settings = settingsjson[0].settings || {};
969-
998+
970999
settings.ActivityMonitorPolling = {
9711000
activeSessionsInterval: activeSessionsInterval,
972-
idleInterval: idleInterval
1001+
idleInterval: idleInterval,
9731002
};
974-
1003+
9751004
let query = 'UPDATE app_config SET settings=$1 where "ID"=1';
9761005
await db.query(query, [settings]);
977-
1006+
9781007
res.status(200);
9791008
res.send(settings.ActivityMonitorPolling);
9801009
} else {
981-
res.status(404);
1010+
res.status(404);
9821011
res.send({ error: "Settings Not Found" });
9831012
}
9841013
} catch (error) {

src/pages/activity.jsx

Lines changed: 66 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -48,23 +48,65 @@ function Activity() {
4848
localStorage.setItem("PREF_ACTIVITY_ItemCount", limit);
4949
}
5050

51+
function setTypeFilterParam(filter) {
52+
const type = config?.IS_JELLYFIN ? filter : filter.replace("Play", "Stream");
53+
const params = [...filterParams];
54+
const playMethodFilterIndex = params.findIndex((filter) => filter.field === "PlayMethod");
55+
if (playMethodFilterIndex !== -1) {
56+
params[playMethodFilterIndex].value = type;
57+
} else {
58+
params.push({ field: "PlayMethod", value: type });
59+
}
60+
if (filter == "All") {
61+
const playMethodFilterIndex = params.findIndex((filter) => filter.field === "PlayMethod");
62+
if (playMethodFilterIndex !== -1) {
63+
params.splice(playMethodFilterIndex, 1);
64+
}
65+
}
66+
setFilterParams(params);
67+
}
68+
5169
function setTypeFilter(filter) {
5270
setStreamTypeFilter(filter);
5371
localStorage.setItem("PREF_ACTIVITY_StreamTypeFilter", filter);
72+
setTypeFilterParam(filter);
5473
}
5574

75+
const updateLibraryFilterParams = (libraries) => {
76+
const params = [...filterParams];
77+
if (libraries.length != 0) {
78+
const libraryFilterIndex = params.findIndex((filter) => filter.field === "ParentId");
79+
if (libraryFilterIndex !== -1) {
80+
params[libraryFilterIndex].in = libraries.join(",");
81+
} else {
82+
params.push({ field: "ParentId", in: libraries.join(",") });
83+
}
84+
} else {
85+
const libraryFilterIndex = params.findIndex((filter) => filter.field === "ParentId");
86+
if (libraryFilterIndex !== -1) {
87+
params[libraryFilterIndex].in = "no_libraries";
88+
} else {
89+
params.push({ field: "ParentId", in: "no_libraries" });
90+
}
91+
}
92+
setFilterParams(params);
93+
};
94+
5695
const handleLibraryFilter = (selectedOptions) => {
5796
setLibraryFilters(selectedOptions);
5897
localStorage.setItem("PREF_ACTIVITY_libraryFilters", JSON.stringify(selectedOptions));
98+
updateLibraryFilterParams(selectedOptions);
5999
};
60100

61101
const toggleSelectAll = () => {
62102
if (libraryFilters.length > 0) {
63103
setLibraryFilters([]);
64104
localStorage.setItem("PREF_ACTIVITY_libraryFilters", JSON.stringify([]));
105+
updateLibraryFilterParams([]);
65106
} else {
66107
setLibraryFilters(libraries.map((library) => library.Id));
67108
localStorage.setItem("PREF_ACTIVITY_libraryFilters", JSON.stringify(libraries.map((library) => library.Id)));
109+
updateLibraryFilterParams(libraries.map((library) => library.Id));
68110
}
69111
};
70112

@@ -96,6 +138,23 @@ function Activity() {
96138
if (filterParams) {
97139
console.log(JSON.stringify(filterParams));
98140
}
141+
if (libraryFilters.length != 0) {
142+
const libraryFilterIndex = filterParams.findIndex((filter) => filter.field === "ParentId");
143+
if (libraryFilterIndex !== -1) {
144+
filterParams[libraryFilterIndex].in = libraryFilters.join(",");
145+
} else {
146+
filterParams.push({ field: "ParentId", in: libraryFilters.join(",") });
147+
}
148+
}
149+
150+
if (streamTypeFilter != "All") {
151+
const streamTypeFilterIndex = filterParams.findIndex((filter) => filter.field === "PlayMethod");
152+
if (streamTypeFilterIndex !== -1) {
153+
filterParams[streamTypeFilterIndex].value = streamTypeFilter;
154+
} else {
155+
filterParams.push({ field: "PlayMethod", value: streamTypeFilter });
156+
}
157+
}
99158

100159
axios
101160
.get(url, {
@@ -164,7 +223,9 @@ function Activity() {
164223
JSON.stringify(data?.filters ?? []) !== JSON.stringify(filterParams ?? [])
165224
) {
166225
fetchHistory();
167-
fetchLibraries();
226+
if (libraries && libraries.length == 0) {
227+
fetchLibraries();
228+
}
168229
}
169230
}
170231

@@ -197,23 +258,6 @@ function Activity() {
197258
);
198259
}
199260

200-
let filteredData = data.results;
201-
202-
// if (searchQuery) {
203-
// filteredData = data.results.filter((item) =>
204-
// (!item.SeriesName ? item.NowPlayingItemName : item.SeriesName + " - " + item.NowPlayingItemName)
205-
// .toLowerCase()
206-
// .includes(searchQuery.toLowerCase())
207-
// );
208-
// }
209-
filteredData = filteredData.filter(
210-
(item) =>
211-
(libraryFilters.includes(item.ParentId) || item.ParentId == null) &&
212-
(streamTypeFilter == "All"
213-
? true
214-
: item.PlayMethod === (config?.IS_JELLYFIN ? streamTypeFilter : streamTypeFilter.replace("Play", "Stream")))
215-
);
216-
217261
return (
218262
<div className="Activity">
219263
<Modal show={showLibraryFilters} onHide={() => setShowLibraryFilters(false)}>
@@ -262,6 +306,9 @@ function Activity() {
262306
<option value="DirectPlay">
263307
<Trans i18nKey="DIRECT" />
264308
</option>
309+
<option value="DirectStream">
310+
<Trans i18nKey="DIRECT_STREAM" />
311+
</option>
265312
</FormSelect>
266313
</div>
267314

@@ -293,7 +340,7 @@ function Activity() {
293340
</div>
294341
<div className="Activity">
295342
<ActivityTable
296-
data={filteredData}
343+
data={data.results}
297344
itemCount={itemCount}
298345
onPageChange={handlePageChange}
299346
onSortChange={onSortChange}

src/pages/components/item-info/item-activity.jsx

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,24 @@ function ItemActivity(props) {
3636
localStorage.setItem("PREF_ACTIVITY_ItemCount", limit);
3737
}
3838

39+
function setTypeFilterParam(filter) {
40+
const type = config?.IS_JELLYFIN ? filter : filter.replace("Play", "Stream");
41+
const params = [...filterParams];
42+
const playMethodFilterIndex = params.findIndex((filter) => filter.field === "PlayMethod");
43+
if (playMethodFilterIndex !== -1) {
44+
params[playMethodFilterIndex].value = type;
45+
} else {
46+
params.push({ field: "PlayMethod", value: type });
47+
}
48+
if (filter == "All") {
49+
const playMethodFilterIndex = params.findIndex((filter) => filter.field === "PlayMethod");
50+
if (playMethodFilterIndex !== -1) {
51+
params.splice(playMethodFilterIndex, 1);
52+
}
53+
}
54+
setFilterParams(params);
55+
}
56+
3957
useEffect(() => {
4058
const handler = setTimeout(() => {
4159
setDebouncedSearchQuery(searchQuery);
@@ -110,23 +128,6 @@ function ItemActivity(props) {
110128
return <></>;
111129
}
112130

113-
let filteredData = data.results;
114-
115-
// if (searchQuery) {
116-
// filteredData = data.results.filter(
117-
// (item) =>
118-
// (!item.SeriesName ? item.NowPlayingItemName : item.SeriesName + " - " + item.NowPlayingItemName)
119-
// .toLowerCase()
120-
// .includes(searchQuery.toLowerCase()) || item.UserName.toLowerCase().includes(searchQuery.toLowerCase())
121-
// );
122-
// }
123-
124-
filteredData = filteredData.filter((item) =>
125-
streamTypeFilter === "All"
126-
? true
127-
: item.PlayMethod === (config?.IS_JELLYFIN ? streamTypeFilter : streamTypeFilter.replace("Play", "Stream"))
128-
);
129-
130131
return (
131132
<div className="Activity">
132133
<div className="d-md-flex justify-content-between">
@@ -142,6 +143,7 @@ function ItemActivity(props) {
142143
<FormSelect
143144
onChange={(event) => {
144145
setStreamTypeFilter(event.target.value);
146+
setTypeFilterParam(event.target.value);
145147
}}
146148
value={streamTypeFilter}
147149
className="w-md-75 rounded-0 rounded-end"
@@ -156,7 +158,7 @@ function ItemActivity(props) {
156158
<Trans i18nKey="DIRECT" />
157159
</option>
158160
<option value="DirectStream">
159-
<Trans i18nKey="DirectStream" /> (<Trans i18nKey="DirectStream" />)
161+
<Trans i18nKey="DIRECT_STREAM" />
160162
</option>
161163
</FormSelect>
162164
</div>
@@ -190,7 +192,7 @@ function ItemActivity(props) {
190192

191193
<div className="Activity">
192194
<ActivityTable
193-
data={filteredData}
195+
data={data.results}
194196
itemCount={itemCount}
195197
onPageChange={handlePageChange}
196198
onSortChange={onSortChange}

0 commit comments

Comments
 (0)