Added Media Listing to libraries

Added Media Listing to libraries
Minor css changes to item cards and image constraints
Minor css changes to stat cards
Added api endpoint to show all items per library
This commit is contained in:
Thegan Govender
2023-04-28 01:36:15 +02:00
parent 6f7f5c069f
commit 894cf1bcc9
11 changed files with 131 additions and 24 deletions

View File

@@ -69,12 +69,11 @@ router.get("/getLibraries", async (req, res) => {
router.post("/getLibraryItems", async (req, res) => {
try{
const Id = req.headers['id'];
const {libraryid} = req.body;
console.log(`ENDPOINT CALLED: /getLibraryItems: `+libraryid);
const { rows } = await db.query(
`SELECT * FROM jf_library_items where "ParentId"='${Id}'`
`SELECT * FROM jf_library_items where "ParentId"='${libraryid}'`
);
console.log({ Id: Id });
res.send(rows);
@@ -83,7 +82,7 @@ router.post("/getLibraryItems", async (req, res) => {
console.log(error);
}
console.log(`ENDPOINT CALLED: /getLibraryItems: `);
});
router.post("/getSeasons", async (req, res) => {

View File

@@ -61,7 +61,7 @@ function Row(data) {
size="small"
onClick={() => {if(row.results.length>1){setOpen(!open);}}}
>
{!open ? <AddCircleFillIcon /> : <IndeterminateCircleFillIcon />}
{!open ? <AddCircleFillIcon opacity={row.results.length>1 ?1 : 0} cursor={row.results.length>1 ? "pointer":"default"}/> : <IndeterminateCircleFillIcon />}
</IconButton>
</TableCell>
<TableCell><Link to={`/users/${row.UserId}`} className='text-decoration-none'>{row.UserName}</Link></TableCell>

View File

@@ -12,13 +12,14 @@ function MoreItemCards(props) {
const [loaded, setLoaded] = useState(false);
const [fallback, setFallback] = useState(false);
return (
<div className={props.data.Type==="Episode" ? "last-card episode" : "last-card"}>
<div className={props.data.Type==="Episode" ? "last-card episode-card" : "last-card"}>
<Link to={`/libraries/item/${ (props.data.Type==="Episode" ? props.data.EpisodeId : props.data.Id) }`}>
<div className={props.data.Type==="Episode" ? "last-card-banner episode" : "last-card-banner"}>
{props.data.ImageBlurHashes && !loaded ? <Blurhash hash={props.data.ImageBlurHashes.Primary[props.data.ImageTags.Primary]} width={'100%'} height={'100%'}/> : null}
{fallback ?
<img
className="episode"
src={
`${
props.base_url +

View File

@@ -11,6 +11,7 @@ import LibraryGlobalStats from './library/library-stats';
import LibraryLastWatched from './library/last-watched';
import RecentlyPlayed from './library/recently-added';
import LibraryActivity from './library/library-activity';
import LibraryItems from './library/library-items';
import { Tabs, Tab, Button, ButtonGroup } from 'react-bootstrap';
@@ -90,7 +91,7 @@ function LibraryInfo() {
<LibraryActivity LibraryId={LibraryId}/>
</Tab>
<Tab eventKey="tabItems" className='bg-transparent'>
<LibraryActivity LibraryId={LibraryId}/>
<LibraryItems LibraryId={LibraryId}/>
</Tab>
</Tabs>
</div>

View File

@@ -0,0 +1,75 @@
import React, { useState, useEffect } from "react";
import axios from "axios";
import MoreItemCards from "../item-info/more-items/more-items-card";
import Config from "../../../lib/config";
import "../../css/library/media-items.css";
function LibraryItems(props) {
const [data, setData] = useState();
const [config, setConfig] = useState();
useEffect(() => {
const fetchConfig = async () => {
try {
const newConfig = await Config();
setConfig(newConfig);
} catch (error) {
console.log(error);
}
};
const fetchData = async () => {
try {
const itemData = await axios.post(`/api/getLibraryItems`, {
libraryid: props.LibraryId,
}, {
headers: {
Authorization: `Bearer ${config.token}`,
"Content-Type": "application/json",
},
});
setData(itemData.data);
console.log(itemData.data);
} catch (error) {
console.log(error);
}
};
if (!config) {
fetchConfig();
}else{
fetchData();
}
const intervalId = setInterval(fetchData, 60000 * 5);
return () => clearInterval(intervalId);
}, [config, props.LibraryId]);
if (!data || !config) {
return <></>;
}
return (
<div className="last-played">
<h1 className="my-3">Media</h1>
<div className="media-items-container">
{data.map((item) => (
<MoreItemCards data={item} base_url={config.hostUrl} key={item.Id+item.SeasonNumber+item.EpisodeNumber}/>
))}
</div>
</div>
);
}
export default LibraryItems;

View File

@@ -14,15 +14,15 @@ function LibraryStatComponent(props) {
};
const cardBgStyle = {
backdropFilter: 'blur(5px)',
// backdropFilter: 'blur(5px)',
backgroundColor: 'rgb(0, 0, 0, 0.6)',
height:'100%',
};
return (
<Card className="stat-card" style={cardStyle}>
<div style={cardBgStyle}>
<Card className="stat-card rounded-3" style={cardStyle}>
<div style={cardBgStyle} className="rounded-3">
<Row className="h-100">
<Col className="d-none d-lg-block stat-card-banner">

View File

@@ -21,7 +21,7 @@ function ItemStatComponent(props) {
};
const cardBgStyle = {
backdropFilter: 'blur(5px)',
backdropFilter: props.base_url ? 'blur(5px)' : 'blur(0px)',
backgroundColor: 'rgb(0, 0, 0, 0.6)',
height:'100%',
};

View File

@@ -64,19 +64,13 @@ function MostActiveUsers(props) {
}, [data, config, days,props.days]);
// const handleImageError = () => {
// setImgError(true);
// };
if (!data || data.length === 0) {
return <></>;
}
return (
<ItemStatComponent base_url={config.hostUrl} icon={<AccountCircleFillIcon color="white" size={"100%"}/>} data={data} heading={"MOST ACTIVE USERS"} units={"Plays"}/>
<ItemStatComponent icon={<AccountCircleFillIcon color="white" size={"100%"}/>} data={data} heading={"MOST ACTIVE USERS"} units={"Plays"}/>
);
}

View File

@@ -8,10 +8,8 @@
color: white;
margin-bottom: 20px;
min-height: 300px;
}
.last-played-container::-webkit-scrollbar {
width: 5px; /* set scrollbar width */
}
@@ -42,6 +40,7 @@
width: 150px;
border-radius: 8px;
background-color: #1e1c22;
}
@@ -49,13 +48,19 @@
.episode{
width: 220px !important;
height: 128px !important;
}
.episode-card{
width: 220px !important;
}
.last-card-banner {
width: 150px;
height: 224px;
height: 220px;
transition: opacity 0.2s ease-in-out;
}

View File

@@ -0,0 +1,33 @@
.media-items-container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 150px));
grid-gap: 20px;
background-color: rgb(100, 100, 100,0.2);
padding: 20px;
border-radius: 8px;
color: white;
margin-bottom: 20px;
min-height: 300px;
}
.media-items-container::-webkit-scrollbar {
width: 5px; /* set scrollbar width */
}
.media-items-container::-webkit-scrollbar-track {
background-color: transparent; /* set track color */
}
.media-items-container::-webkit-scrollbar-thumb {
background-color: #8888884d; /* set thumb color */
border-radius: 5px; /* round corners */
width: 5px;
}
.media-items-container::-webkit-scrollbar-thumb:hover {
background-color: #88888883; /* set thumb color */
}

View File

@@ -12,7 +12,6 @@
color: white;
max-width: 500px;
max-height: 180px;
border-radius: 8px !important;
}
.stat-card-banner