mirror of
https://github.com/LukeHagar/Warden.git
synced 2025-12-06 04:22:06 +00:00
Infinite scrolling works
Maybe using Howler for audio?
This commit is contained in:
23
package-lock.json
generated
23
package-lock.json
generated
@@ -23,6 +23,7 @@
|
|||||||
"electron-util": "^0.17.2",
|
"electron-util": "^0.17.2",
|
||||||
"fs": "^0.0.1-security",
|
"fs": "^0.0.1-security",
|
||||||
"gh-pages": "^4.0.0",
|
"gh-pages": "^4.0.0",
|
||||||
|
"howler": "^2.2.3",
|
||||||
"http-browserify": "^1.7.0",
|
"http-browserify": "^1.7.0",
|
||||||
"https-browserify": "^1.0.0",
|
"https-browserify": "^1.0.0",
|
||||||
"ipaddr.js": "^2.0.1",
|
"ipaddr.js": "^2.0.1",
|
||||||
@@ -9984,6 +9985,11 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/howler": {
|
||||||
|
"version": "2.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/howler/-/howler-2.2.3.tgz",
|
||||||
|
"integrity": "sha512-QM0FFkw0LRX1PR8pNzJVAY25JhIWvbKMBFM4gqk+QdV+kPXOhleWGCB6AiAF/goGjIHK2e/nIElplvjQwhr0jg=="
|
||||||
|
},
|
||||||
"node_modules/hpack.js": {
|
"node_modules/hpack.js": {
|
||||||
"version": "2.1.6",
|
"version": "2.1.6",
|
||||||
"resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz",
|
||||||
@@ -14261,9 +14267,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/plex-api-oauth": {
|
"node_modules/plex-api-oauth": {
|
||||||
"version": "1.1.98",
|
"version": "1.1.103",
|
||||||
"resolved": "https://registry.npmjs.org/plex-api-oauth/-/plex-api-oauth-1.1.98.tgz",
|
"resolved": "https://registry.npmjs.org/plex-api-oauth/-/plex-api-oauth-1.1.103.tgz",
|
||||||
"integrity": "sha512-nuH3BJBN/UXGRNp6n2lts/Zw1gpbrXFqLaHS+16UToqjM0v4kk/bjP+nV2LXmAAM+a9uamNLI94oTwZT5tTByg==",
|
"integrity": "sha512-PgUJ62StsmEkzEjWRBXRwRgDe5XUmPB5AxMfBXsrqibduv0upnj3pUvtLWqsPJj3l3+FcTLDw+0Yy2ozvjOWKA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^0.27.2",
|
"axios": "^0.27.2",
|
||||||
"plex-oauth": "^2.0.2",
|
"plex-oauth": "^2.0.2",
|
||||||
@@ -26383,6 +26389,11 @@
|
|||||||
"lru-cache": "^6.0.0"
|
"lru-cache": "^6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"howler": {
|
||||||
|
"version": "2.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/howler/-/howler-2.2.3.tgz",
|
||||||
|
"integrity": "sha512-QM0FFkw0LRX1PR8pNzJVAY25JhIWvbKMBFM4gqk+QdV+kPXOhleWGCB6AiAF/goGjIHK2e/nIElplvjQwhr0jg=="
|
||||||
|
},
|
||||||
"hpack.js": {
|
"hpack.js": {
|
||||||
"version": "2.1.6",
|
"version": "2.1.6",
|
||||||
"resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz",
|
||||||
@@ -29568,9 +29579,9 @@
|
|||||||
"integrity": "sha512-Igl37++MSa+4H8LNP3Ene9GU0e1YypmXvFVNvVUwoAx44e74jbUlJXy4Q5rLSBisn0O2lBKdE6VkFIwrDl+UnQ=="
|
"integrity": "sha512-Igl37++MSa+4H8LNP3Ene9GU0e1YypmXvFVNvVUwoAx44e74jbUlJXy4Q5rLSBisn0O2lBKdE6VkFIwrDl+UnQ=="
|
||||||
},
|
},
|
||||||
"plex-api-oauth": {
|
"plex-api-oauth": {
|
||||||
"version": "1.1.98",
|
"version": "1.1.103",
|
||||||
"resolved": "https://registry.npmjs.org/plex-api-oauth/-/plex-api-oauth-1.1.98.tgz",
|
"resolved": "https://registry.npmjs.org/plex-api-oauth/-/plex-api-oauth-1.1.103.tgz",
|
||||||
"integrity": "sha512-nuH3BJBN/UXGRNp6n2lts/Zw1gpbrXFqLaHS+16UToqjM0v4kk/bjP+nV2LXmAAM+a9uamNLI94oTwZT5tTByg==",
|
"integrity": "sha512-PgUJ62StsmEkzEjWRBXRwRgDe5XUmPB5AxMfBXsrqibduv0upnj3pUvtLWqsPJj3l3+FcTLDw+0Yy2ozvjOWKA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"axios": "^0.27.2",
|
"axios": "^0.27.2",
|
||||||
"plex-oauth": "^2.0.2",
|
"plex-oauth": "^2.0.2",
|
||||||
|
|||||||
@@ -125,6 +125,7 @@
|
|||||||
"electron-util": "^0.17.2",
|
"electron-util": "^0.17.2",
|
||||||
"fs": "^0.0.1-security",
|
"fs": "^0.0.1-security",
|
||||||
"gh-pages": "^4.0.0",
|
"gh-pages": "^4.0.0",
|
||||||
|
"howler": "^2.2.3",
|
||||||
"http-browserify": "^1.7.0",
|
"http-browserify": "^1.7.0",
|
||||||
"https-browserify": "^1.0.0",
|
"https-browserify": "^1.0.0",
|
||||||
"ipaddr.js": "^2.0.1",
|
"ipaddr.js": "^2.0.1",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
/* eslint-disable react/no-array-index-key */
|
/* eslint-disable react/no-array-index-key */
|
||||||
/* eslint-disable prefer-template */
|
/* eslint-disable prefer-template */
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { useState, useEffect } from 'react';
|
import { useState, useEffect, useRef, useCallback } from 'react';
|
||||||
import { createTheme, ThemeProvider } from '@mui/material/styles';
|
import { createTheme, ThemeProvider } from '@mui/material/styles';
|
||||||
|
|
||||||
import Box from '@mui/material/Box';
|
import Box from '@mui/material/Box';
|
||||||
@@ -44,6 +44,7 @@ import {
|
|||||||
Grid,
|
Grid,
|
||||||
Icon,
|
Icon,
|
||||||
IconButton,
|
IconButton,
|
||||||
|
StepButton,
|
||||||
TextareaAutosize,
|
TextareaAutosize,
|
||||||
TextField,
|
TextField,
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
@@ -55,7 +56,7 @@ import TableHead from '@mui/material/TableHead';
|
|||||||
import TableRow from '@mui/material/TableRow';
|
import TableRow from '@mui/material/TableRow';
|
||||||
import Paper from '@mui/material/Paper';
|
import Paper from '@mui/material/Paper';
|
||||||
|
|
||||||
import ReactJkMusicPlayer from 'react-jinke-music-player';
|
import { Howl, Howler } from 'howler';
|
||||||
import XMLParser from 'react-xml-parser';
|
import XMLParser from 'react-xml-parser';
|
||||||
import {
|
import {
|
||||||
CreatePlexClientInformation,
|
CreatePlexClientInformation,
|
||||||
@@ -111,6 +112,7 @@ function App() {
|
|||||||
|
|
||||||
const [query, setQuery] = useState('');
|
const [query, setQuery] = useState('');
|
||||||
const [pageNumber, setPageNumber] = useState(0);
|
const [pageNumber, setPageNumber] = useState(0);
|
||||||
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [topic, setTopic] = useState();
|
const [topic, setTopic] = useState();
|
||||||
|
|
||||||
function handleSearch(event) {
|
function handleSearch(event) {
|
||||||
@@ -195,6 +197,7 @@ function App() {
|
|||||||
// }, [pageNumber, topic, query, plexSessionData]);
|
// }, [pageNumber, topic, query, plexSessionData]);
|
||||||
|
|
||||||
async function UpdateLibrary() {
|
async function UpdateLibrary() {
|
||||||
|
setIsLoading(true);
|
||||||
console.log("I'M HERE");
|
console.log("I'M HERE");
|
||||||
let returnObject = await GetLibraryPages(
|
let returnObject = await GetLibraryPages(
|
||||||
plexServers,
|
plexServers,
|
||||||
@@ -204,14 +207,29 @@ function App() {
|
|||||||
50
|
50
|
||||||
);
|
);
|
||||||
console.log(returnObject);
|
console.log(returnObject);
|
||||||
if (libraryItems.length > 0) {
|
returnObject.items = [...new Set([...libraryItems, ...returnObject.items])];
|
||||||
returnObject.items = [...returnObject.items, ...libraryItems];
|
|
||||||
}
|
|
||||||
|
|
||||||
setLibraryItems(returnObject.items);
|
setLibraryItems(returnObject.items);
|
||||||
setLibraryHasMore(returnObject.hasMore);
|
setLibraryHasMore(returnObject.hasMore);
|
||||||
|
setIsLoading(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const observer = useRef();
|
||||||
|
const lastLibraryItem = useCallback(
|
||||||
|
(node) => {
|
||||||
|
if (isLoading) return;
|
||||||
|
if (observer.current) observer.current.disconnect();
|
||||||
|
observer.current = new IntersectionObserver((entries) => {
|
||||||
|
if (entries[0].isIntersecting && libraryHasMore) {
|
||||||
|
setPageNumber(pageNumber + 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (node) observer.current.observe(node);
|
||||||
|
console.log(node);
|
||||||
|
},
|
||||||
|
[isLoading, libraryHasMore]
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setLibraryItems([]);
|
setLibraryItems([]);
|
||||||
setLibraryHasMore(false);
|
setLibraryHasMore(false);
|
||||||
@@ -299,6 +317,7 @@ function App() {
|
|||||||
<ListItemButton
|
<ListItemButton
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setActivePage(0);
|
setActivePage(0);
|
||||||
|
setPageNumber(0);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ListItemIcon>{iconindex.Home}</ListItemIcon>
|
<ListItemIcon>{iconindex.Home}</ListItemIcon>
|
||||||
@@ -310,6 +329,7 @@ function App() {
|
|||||||
<ListItemButton
|
<ListItemButton
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setActivePage(1);
|
setActivePage(1);
|
||||||
|
setPageNumber(0);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ListItemIcon>{iconindex.Library}</ListItemIcon>
|
<ListItemIcon>{iconindex.Library}</ListItemIcon>
|
||||||
@@ -322,6 +342,7 @@ function App() {
|
|||||||
onClick={() => {
|
onClick={() => {
|
||||||
setActivePage(2);
|
setActivePage(2);
|
||||||
topic !== 'artists' && setLibraryItems([]);
|
topic !== 'artists' && setLibraryItems([]);
|
||||||
|
setPageNumber(0);
|
||||||
setTopic('artists');
|
setTopic('artists');
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -335,6 +356,7 @@ function App() {
|
|||||||
onClick={() => {
|
onClick={() => {
|
||||||
setActivePage(2);
|
setActivePage(2);
|
||||||
topic !== 'albums' && setLibraryItems([]);
|
topic !== 'albums' && setLibraryItems([]);
|
||||||
|
setPageNumber(0);
|
||||||
setTopic('albums');
|
setTopic('albums');
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -348,6 +370,7 @@ function App() {
|
|||||||
onClick={() => {
|
onClick={() => {
|
||||||
setActivePage(2);
|
setActivePage(2);
|
||||||
topic !== 'songs' && setLibraryItems([]);
|
topic !== 'songs' && setLibraryItems([]);
|
||||||
|
setPageNumber(0);
|
||||||
setTopic('songs');
|
setTopic('songs');
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -360,6 +383,7 @@ function App() {
|
|||||||
<ListItemButton
|
<ListItemButton
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setActivePage(5);
|
setActivePage(5);
|
||||||
|
setPageNumber(0);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ListItemIcon>{iconindex.Playlists}</ListItemIcon>
|
<ListItemIcon>{iconindex.Playlists}</ListItemIcon>
|
||||||
@@ -371,6 +395,7 @@ function App() {
|
|||||||
<ListItemButton
|
<ListItemButton
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setActivePage(6);
|
setActivePage(6);
|
||||||
|
setPageNumber(0);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ListItemIcon>{iconindex.Settings}</ListItemIcon>
|
<ListItemIcon>{iconindex.Settings}</ListItemIcon>
|
||||||
@@ -409,6 +434,7 @@ function App() {
|
|||||||
<CardActionArea
|
<CardActionArea
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setActivePage(4);
|
setActivePage(4);
|
||||||
|
setPageNumber(0);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CardMedia
|
<CardMedia
|
||||||
@@ -457,45 +483,88 @@ function App() {
|
|||||||
<Toolbar />
|
<Toolbar />
|
||||||
<Box sx={{}} loading="lazy">
|
<Box sx={{}} loading="lazy">
|
||||||
<Grid container spacing={2}>
|
<Grid container spacing={2}>
|
||||||
{libraryItems?.map((Obj, index) => (
|
{libraryItems?.sort()?.map((Obj, index) => {
|
||||||
<Grid item xs={3} key={Obj.guid + index}>
|
if (libraryItems?.length === index + 10) {
|
||||||
<Card>
|
return (
|
||||||
<CardActionArea
|
<Grid item xs={3} key={Obj.guid + index}>
|
||||||
onClick={() => {
|
<Card ref={lastLibraryItem}>
|
||||||
setActivePage(4);
|
<CardActionArea
|
||||||
}}
|
onClick={() => {
|
||||||
>
|
setActivePage(4);
|
||||||
<CardMedia
|
}}
|
||||||
loading="lazy"
|
>
|
||||||
component="img"
|
<CardMedia
|
||||||
height="240"
|
loading="lazy"
|
||||||
image={
|
component="img"
|
||||||
Obj.server.preferredConnection.uri +
|
height="240"
|
||||||
'/photo/:/transcode?' +
|
image={
|
||||||
qs.stringify({
|
Obj.server.preferredConnection.uri +
|
||||||
width: 240,
|
'/photo/:/transcode?' +
|
||||||
height: 240,
|
qs.stringify({
|
||||||
minSize: 1,
|
width: 240,
|
||||||
upscale: 1,
|
height: 240,
|
||||||
url:
|
minSize: 1,
|
||||||
Obj.thumb +
|
upscale: 1,
|
||||||
'?X-Plex-Token=' +
|
url:
|
||||||
Obj.server.accessToken,
|
Obj.thumb +
|
||||||
'X-Plex-Token': Obj.server.accessToken,
|
'?X-Plex-Token=' +
|
||||||
}) || NoArt
|
Obj.server.accessToken,
|
||||||
}
|
'X-Plex-Token': Obj.server.accessToken,
|
||||||
onError={({ currentTarget }) => {
|
}) || NoArt
|
||||||
currentTarget.onerror = null; // prevents looping
|
}
|
||||||
currentTarget.src = NoArt;
|
onError={({ currentTarget }) => {
|
||||||
|
currentTarget.onerror = null; // prevents looping
|
||||||
|
currentTarget.src = NoArt;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<CardContent>
|
||||||
|
<Typography noWrap>{Obj.title}</Typography>
|
||||||
|
</CardContent>
|
||||||
|
</CardActionArea>
|
||||||
|
</Card>
|
||||||
|
</Grid>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Grid item xs={3} key={Obj.guid + index}>
|
||||||
|
<Card>
|
||||||
|
<CardActionArea
|
||||||
|
onClick={() => {
|
||||||
|
setActivePage(4);
|
||||||
}}
|
}}
|
||||||
/>
|
>
|
||||||
<CardContent>
|
<CardMedia
|
||||||
<Typography noWrap>{Obj.title}</Typography>
|
loading="lazy"
|
||||||
</CardContent>
|
component="img"
|
||||||
</CardActionArea>
|
height="240"
|
||||||
</Card>
|
image={
|
||||||
</Grid>
|
Obj.server.preferredConnection.uri +
|
||||||
))}
|
'/photo/:/transcode?' +
|
||||||
|
qs.stringify({
|
||||||
|
width: 240,
|
||||||
|
height: 240,
|
||||||
|
minSize: 1,
|
||||||
|
upscale: 1,
|
||||||
|
url:
|
||||||
|
Obj.thumb +
|
||||||
|
'?X-Plex-Token=' +
|
||||||
|
Obj.server.accessToken,
|
||||||
|
'X-Plex-Token': Obj.server.accessToken,
|
||||||
|
}) || NoArt
|
||||||
|
}
|
||||||
|
onError={({ currentTarget }) => {
|
||||||
|
currentTarget.onerror = null; // prevents looping
|
||||||
|
currentTarget.src = NoArt;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<CardContent>
|
||||||
|
<Typography noWrap>{Obj.title}</Typography>
|
||||||
|
</CardContent>
|
||||||
|
</CardActionArea>
|
||||||
|
</Card>
|
||||||
|
</Grid>
|
||||||
|
);
|
||||||
|
})}
|
||||||
</Grid>
|
</Grid>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
11
yarn.lock
11
yarn.lock
@@ -5418,6 +5418,11 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"lru-cache" "^6.0.0"
|
"lru-cache" "^6.0.0"
|
||||||
|
|
||||||
|
"howler@^2.2.3":
|
||||||
|
"integrity" "sha512-QM0FFkw0LRX1PR8pNzJVAY25JhIWvbKMBFM4gqk+QdV+kPXOhleWGCB6AiAF/goGjIHK2e/nIElplvjQwhr0jg=="
|
||||||
|
"resolved" "https://registry.npmjs.org/howler/-/howler-2.2.3.tgz"
|
||||||
|
"version" "2.2.3"
|
||||||
|
|
||||||
"hpack.js@^2.1.6":
|
"hpack.js@^2.1.6":
|
||||||
"integrity" "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ=="
|
"integrity" "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ=="
|
||||||
"resolved" "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz"
|
"resolved" "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz"
|
||||||
@@ -7870,9 +7875,9 @@
|
|||||||
"version" "1.1.0"
|
"version" "1.1.0"
|
||||||
|
|
||||||
"plex-api-oauth@^1.0.4":
|
"plex-api-oauth@^1.0.4":
|
||||||
"integrity" "sha512-nuH3BJBN/UXGRNp6n2lts/Zw1gpbrXFqLaHS+16UToqjM0v4kk/bjP+nV2LXmAAM+a9uamNLI94oTwZT5tTByg=="
|
"integrity" "sha512-PgUJ62StsmEkzEjWRBXRwRgDe5XUmPB5AxMfBXsrqibduv0upnj3pUvtLWqsPJj3l3+FcTLDw+0Yy2ozvjOWKA=="
|
||||||
"resolved" "https://registry.npmjs.org/plex-api-oauth/-/plex-api-oauth-1.1.98.tgz"
|
"resolved" "https://registry.npmjs.org/plex-api-oauth/-/plex-api-oauth-1.1.103.tgz"
|
||||||
"version" "1.1.98"
|
"version" "1.1.103"
|
||||||
dependencies:
|
dependencies:
|
||||||
"axios" "^0.27.2"
|
"axios" "^0.27.2"
|
||||||
"plex-oauth" "^2.0.2"
|
"plex-oauth" "^2.0.2"
|
||||||
|
|||||||
Reference in New Issue
Block a user