fix: support videos

Signed-off-by: Varun Raj <mailme@varunraj.in>
This commit is contained in:
Varun Raj
2024-08-28 08:30:19 +05:30
parent 9d259b554a
commit 58f6435689
6 changed files with 96 additions and 31 deletions
@@ -4,12 +4,13 @@ import { listPotentialAlbumsAssets } from "@/handlers/api/album.handler";
import { IAsset } from "@/types/asset";
import React, { useEffect, useMemo, useState } from "react";
import { Gallery } from "react-grid-gallery";
import Lightbox from "yet-another-react-lightbox";
import Lightbox, { SlideImage, SlideTypes } from "yet-another-react-lightbox";
import Captions from "yet-another-react-lightbox/plugins/captions";
import { CalendarArrowDown, CalendarArrowUp, Hourglass } from "lucide-react";
import Video from "yet-another-react-lightbox/plugins/video";
export default function PotentialAlbumsAssets() {
const { startDate, selectedIds, assets, updateContext } = usePotentialAlbumContext();
const { startDate, selectedIds, assets, updateContext } =
usePotentialAlbumContext();
const [loading, setLoading] = useState(false);
const [errorMessage, setErrorMessage] = useState<string | null>(null);
@@ -20,7 +21,7 @@ export default function PotentialAlbumsAssets() {
setLoading(true);
updateContext({
assets: [],
})
});
return listPotentialAlbumsAssets({ startDate })
.then((assets) => updateContext({ assets }))
.catch(setErrorMessage)
@@ -40,10 +41,20 @@ export default function PotentialAlbumsAssets() {
const slides = useMemo(
() =>
images.map(({ original, width, height }) => ({
images.map(({ original, width, height, type, videoURL }) => ({
src: original,
width,
height,
type: (type === "VIDEO" ? "video" : "image") as any,
sources:
type === "VIDEO"
? [
{
src: videoURL,
type: "video/mp4",
},
]
: [],
})),
[images]
);
@@ -51,41 +62,44 @@ export default function PotentialAlbumsAssets() {
const handleClick = (idx: number) => setIndex(idx);
const handleSelect = (_idx: number, asset: IAsset) => {
const isPresent =selectedIds.includes(asset.id)
if(isPresent){
updateContext({selectedIds:selectedIds.filter((id)=>id!==asset.id)})
const isPresent = selectedIds.includes(asset.id);
if (isPresent) {
updateContext({
selectedIds: selectedIds.filter((id) => id !== asset.id),
});
} else {
updateContext({ selectedIds: [...selectedIds, asset.id] });
}
else{
updateContext({selectedIds:[...selectedIds,asset.id]})
}
};
useEffect(() => {
if (startDate) fetchAssets();
}, [startDate]);
if (loading) return (
<div className="flex flex-col gap-2 h-full justify-center items-center w-full">
<Hourglass />
<p className="text-lg">Loading...</p>
</div>
)
if (loading)
return (
<div className="flex flex-col gap-2 min-h-full justify-center items-center w-full">
<Hourglass />
<p className="text-lg">Loading...</p>
</div>
);
if (!startDate) return (
<div className="flex flex-col gap-2 h-full justify-center items-center w-full">
<CalendarArrowUp />
<p className="text-lg">Please select a date</p>
<p className="text-sm">
When you select a date from the left, you will see all the orphan assets captured on that date
</p>
</div>
)
if (!startDate)
return (
<div className="flex flex-col gap-2 min-h-full justify-center items-center w-full">
<CalendarArrowUp />
<p className="text-lg">Please select a date</p>
<p className="text-sm text-zinc-700">
When you select a date from the left, you will see all the orphan
assets captured on that date
</p>
</div>
);
return (
<>
<Lightbox
slides={slides}
plugins={[Captions]}
plugins={[Captions, Video]}
open={index >= 0}
index={index}
close={() => setIndex(-1)}
@@ -96,7 +110,6 @@ export default function PotentialAlbumsAssets() {
onClick={handleClick}
enableImageSelection={true}
onSelect={handleSelect}
/>
</div>
</>
+2 -1
View File
@@ -25,4 +25,5 @@ export const LIST_MISSING_LOCATION_DATES_PATH = BASE_API_ENDPOINT + "/assets/mis
export const LIST_MISSING_LOCATION_ASSETS_PATH = BASE_API_ENDPOINT + "/assets/missing-location-assets";
export const ASSET_THUMBNAIL_PATH = (id: string) => BASE_PROXY_ENDPOINT + "/asset/thumbnail/" + id;
export const ASSET_PREVIEW_PATH = (id: string) => BASE_PROXY_ENDPOINT + "/asset/thumbnail/" + id + "?size=preview";
export const ASSET_PREVIEW_PATH = (id: string) => BASE_PROXY_ENDPOINT + "/asset/thumbnail/" + id + "?size=preview";
export const ASSET_VIDEO_PATH = (id: string) => BASE_PROXY_ENDPOINT + "/asset/video/" + id;
+2 -1
View File
@@ -1,4 +1,4 @@
import { ASSET_PREVIEW_PATH, ASSET_THUMBNAIL_PATH, PERSON_THUBNAIL_PATH } from "@/config/routes"
import { ASSET_PREVIEW_PATH, ASSET_THUMBNAIL_PATH, ASSET_VIDEO_PATH, PERSON_THUBNAIL_PATH } from "@/config/routes"
import { IPerson } from "@/types/person"
import { parseDate } from "./date.helper"
import { IAsset } from "@/types/asset"
@@ -9,5 +9,6 @@ export const cleanUpAsset = (asset: IAsset): IAsset => {
...asset,
url: ASSET_THUMBNAIL_PATH(asset.id),
previewUrl: ASSET_PREVIEW_PATH(asset.id),
videoURL: ASSET_VIDEO_PATH(asset.id),
}
}
@@ -38,6 +38,7 @@ const SELECT_ORPHAN_PHOTOS = (date: string, ownerId: string) =>
aaa."albumsId" IS NULL
AND a."ownerId" = '${ownerId}'
AND a."localDateTime"::date = '${date}'
AND a."type" = 'VIDEO'
`);
export default async function handler(
@@ -0,0 +1,48 @@
// pages/api/proxy.js
import { ENV } from '@/config/environment';
import { NextApiRequest, NextApiResponse } from 'next'
export const config = {
api: {
bodyParser: false,
},
}
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method !== 'GET') {
return res.status(405).json({ message: 'Method Not Allowed' })
}
const { id } = req.query;
const targetUrl = `${ENV.IMMICH_URL}/api/assets/${id}/original`;
try {
// Forward the request to the target API
const response = await fetch(targetUrl, {
method: 'GET',
headers: {
'Content-Type': 'application/octet-stream',
'x-api-key': ENV.IMMICH_API_KEY,
},
})
if (!response.ok) {
console.error('HTTP error:', response)
throw new Error(`HTTP error! status: ${response.status}`)
}
// Get the image data from the response
const imageBuffer = await response.arrayBuffer()
// Set the appropriate headers for the image response
res.setHeader('Content-Type', response.headers.get('Content-Type') || 'image/png')
res.setHeader('Content-Length', imageBuffer.byteLength)
// Send the image data
res.send(Buffer.from(imageBuffer))
} catch (error) {
console.error('Error:', error)
res.status(500).json({ message: 'Internal Server Error' })
}
}
+1
View File
@@ -18,6 +18,7 @@ export interface IAsset {
exifImageHeight: number;
url: string;
previewUrl: string;
videoURL?: string;
}
export interface IAssetThumbhash {