Infinite scrolling works

Maybe using Howler for audio?
This commit is contained in:
Luke Hagar
2022-07-31 22:24:55 -05:00
parent 5345624594
commit 01c993e12a
4 changed files with 138 additions and 52 deletions

23
package-lock.json generated
View File

@@ -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",

View File

@@ -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",

View File

@@ -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,7 +483,49 @@ 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) => {
if (libraryItems?.length === index + 10) {
return (
<Grid item xs={3} key={Obj.guid + index}>
<Card ref={lastLibraryItem}>
<CardActionArea
onClick={() => {
setActivePage(4);
}}
>
<CardMedia
loading="lazy"
component="img"
height="240"
image={
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>
);
}
return (
<Grid item xs={3} key={Obj.guid + index}> <Grid item xs={3} key={Obj.guid + index}>
<Card> <Card>
<CardActionArea <CardActionArea
@@ -495,7 +563,8 @@ function App() {
</CardActionArea> </CardActionArea>
</Card> </Card>
</Grid> </Grid>
))} );
})}
</Grid> </Grid>
</Box> </Box>
</Box> </Box>

View File

@@ -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"