Skip to content

Commit

Permalink
Merge pull request #6 from johnpc/hide-movies-shows
Browse files Browse the repository at this point in the history
add ability to hide movies/shows
  • Loading branch information
johnpc authored Jan 2, 2025
2 parents 3700854 + 5190695 commit 8066212
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 37 deletions.
16 changes: 13 additions & 3 deletions src/components/pages/MoviesReviewPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,29 @@ import { itemVariants, Title } from "../ui/styled";
import { useNavigate } from "react-router-dom";
import { generateGuid } from "@/lib/utils";
import { useErrorBoundary } from "react-error-boundary";
import { getCachedHiddenIds, setCachedHiddenId } from "@/lib/cache";

export default function MoviesReviewPage() {
const { showBoundary } = useErrorBoundary();
const navigate = useNavigate();
const [isLoading, setIsLoading] = useState(true);
const [movies, setMovies] = useState<SimpleItemDto[]>([]);
const [hiddenIds, setHiddenIds] = useState<string[]>(getCachedHiddenIds());

useEffect(() => {
const setup = async () => {
setIsLoading(true);
try {
setMovies(await listMovies());
const movies = await listMovies();
setMovies(movies.filter((movie) => !hiddenIds.includes(movie.id!)));
} catch (error) {
showBoundary(error);
} finally {
setIsLoading(false);
}
};
setup();
}, []);
}, [hiddenIds]);

if (isLoading) {
return (
Expand Down Expand Up @@ -58,7 +61,14 @@ export default function MoviesReviewPage() {

<Grid columns={{ initial: "2", sm: "3", md: "4", lg: "5" }} gap="4">
{movies.map((movie) => (
<MovieCard key={generateGuid()} item={movie} />
<MovieCard
key={generateGuid()}
item={movie}
onHide={() => {
setCachedHiddenId(movie.id!);
setHiddenIds([...hiddenIds, movie.id!]);
}}
/>
))}
</Grid>
</Grid>
Expand Down
17 changes: 16 additions & 1 deletion src/components/pages/MoviesReviewPage/MovieCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,20 @@ import {
getImageUrlById,
SimpleItemDto,
} from "@/lib/playback-reporting-queries";
import { Trash2 } from "lucide-react";

interface MovieCardProps {
item: SimpleItemDto;
playbackTime?: number;
episodeCount?: number;
onHide?: () => void;
}

export function MovieCard({
item,
playbackTime,
episodeCount,
onHide,
}: MovieCardProps) {
const [imageUrl, setImageUrl] = useState<string>();
useEffect(() => {
Expand Down Expand Up @@ -48,7 +51,19 @@ export function MovieCard({
/>
</div>
<div className="p-4">
<h3 className="font-semibold text-lg">{item.name}</h3>
<h3 className="font-semibold text-lg">
{item.name}{" "}
{onHide && (
<Trash2
size={16}
onClick={(e) => {
e.stopPropagation();
onHide();
}}
className="w-5 h-5 text-white"
/>
)}
</h3>
<p className="text-sm text-muted-foreground">
{item.productionYear && `Released: ${item.productionYear}`}
</p>
Expand Down
14 changes: 12 additions & 2 deletions src/components/pages/ShowReviewPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ import { motion } from "framer-motion";
import { styled } from "@stitches/react";
import { useNavigate } from "react-router-dom";
import { useErrorBoundary } from "react-error-boundary";
import { getCachedHiddenIds, setCachedHiddenId } from "@/lib/cache";

export default function ShowReviewPage() {
const { showBoundary } = useErrorBoundary();
const navigate = useNavigate();
const [isLoading, setIsLoading] = useState(true);
const [hiddenIds, setHiddenIds] = useState<string[]>(getCachedHiddenIds());
const [shows, setShows] = useState<
{
showName: string;
Expand All @@ -24,15 +26,19 @@ export default function ShowReviewPage() {
const setup = async () => {
setIsLoading(true);
try {
setShows(await listShows());
const shows = await listShows();
const filteredShows = shows.filter(
(show) => !hiddenIds.includes(show.item.id!),
);
setShows(filteredShows);
} catch (e) {
showBoundary(e);
} finally {
setIsLoading(false);
}
};
setup();
}, []);
}, [hiddenIds]);

if (isLoading) {
return (
Expand Down Expand Up @@ -90,6 +96,10 @@ export default function ShowReviewPage() {
item={show.item}
episodeCount={show.episodeCount}
playbackTime={show.playbackTime}
onHide={() => {
setCachedHiddenId(show.item.id!);
setHiddenIds([...hiddenIds, show.item.id!]);
}}
/>
</>
))}
Expand Down
11 changes: 11 additions & 0 deletions src/lib/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export const JELLYFIN_AUTH_TOKEN_CACHE_KEY = "jellyfinAuthToken";
export const JELLYFIN_USERNAME_CACHE_KEY = "jellyfinUsername";
export const JELLYFIN_PASSWORD_CACHE_KEY = "jellyfinPassword";
export const JELLYFIN_CURRENT_USER_CACHE_KEY = "jellyfinwrapped_current_user";
export const JELLYFIN_HIDDEN_ITEMS = "jellyfinwrapped_hidden_items";
const localCache: Record<string, string> = {};
export const setCacheValue = (key: string, value: string) => {
try {
Expand Down Expand Up @@ -39,3 +40,13 @@ export const getCacheValue = (key: string): string | null => {
// If the value is not in localStorage, return null
return null;
};

export const getCachedHiddenIds = (): string[] => {
return getCacheValue(JELLYFIN_HIDDEN_ITEMS)?.split(",") ?? [];
};

export const setCachedHiddenId = (id: string) => {
const hiddenIds = getCachedHiddenIds();
hiddenIds.push(id);
setCacheValue(JELLYFIN_HIDDEN_ITEMS, hiddenIds.join(","));
};
66 changes: 35 additions & 31 deletions src/lib/playback-reporting-queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
PluginStatus,
} from "@jellyfin/sdk/lib/generated-client";
import {
getCachedHiddenIds,
getCacheValue,
JELLYFIN_CURRENT_USER_CACHE_KEY,
setCacheValue,
Expand Down Expand Up @@ -90,42 +91,45 @@ export const getImageUrlById = async (id: string) => {
};

const getItemDtosByIds = async (ids: string[]): Promise<SimpleItemDto[]> => {
const hiddenIds = getCachedHiddenIds();
const authenticatedApi = await getAuthenticatedJellyfinApi();
const userId = await getCurrentUserId();
const itemsApi = getUserLibraryApi(authenticatedApi);

const itemPromises = ids.map(async (itemId: string) => {
try {
const cachedItem = getCacheValue(`item_${itemId}`);

if (cachedItem) {
// If item exists in cache, parse and use it
return JSON.parse(cachedItem);
} else {
// If not in cache, fetch from API
const item = await itemsApi.getItem({
itemId,
userId,
});

const simpleItem: SimpleItemDto = {
id: item.data.Id,
parentId: item.data.ParentId,
name: item.data.Name,
productionYear: item.data.ProductionYear,
communityRating: item.data.CommunityRating,
people: item.data.People,
date: item.data.PremiereDate,
};
setCacheValue(`item_${itemId}`, JSON.stringify(simpleItem));

return simpleItem;
const itemPromises = ids
.filter((id) => !hiddenIds.includes(id))
.map(async (itemId: string) => {
try {
const cachedItem = getCacheValue(`item_${itemId}`);

if (cachedItem) {
// If item exists in cache, parse and use it
return JSON.parse(cachedItem);
} else {
// If not in cache, fetch from API
const item = await itemsApi.getItem({
itemId,
userId,
});

const simpleItem: SimpleItemDto = {
id: item.data.Id,
parentId: item.data.ParentId,
name: item.data.Name,
productionYear: item.data.ProductionYear,
communityRating: item.data.CommunityRating,
people: item.data.People,
date: item.data.PremiereDate,
};
setCacheValue(`item_${itemId}`, JSON.stringify(simpleItem));

return simpleItem;
}
} catch (e) {
console.error(e);
return null;
}
} catch (e) {
console.error(e);
return null;
}
});
});
const movieItems = await Promise.all(itemPromises);
return movieItems.filter((item) => item !== null) as SimpleItemDto[];
};
Expand Down

0 comments on commit 8066212

Please sign in to comment.