mirror of
https://github.com/wisplite/raster.git
synced 2026-05-01 06:32:44 -05:00
Add first metadata values and vastly improve gallery tiling
This commit is contained in:
@@ -1,11 +1,17 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"image"
|
||||
_ "image/jpeg"
|
||||
_ "image/png"
|
||||
"mime/multipart"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/wisplite/raster/internal/db"
|
||||
"github.com/wisplite/raster/internal/models"
|
||||
"mime/multipart"
|
||||
"gorm.io/datatypes"
|
||||
)
|
||||
|
||||
func UploadMedia(file *multipart.FileHeader, albumID string, accessToken string) (models.Media, error) {
|
||||
@@ -24,6 +30,23 @@ func UploadMedia(file *multipart.FileHeader, albumID string, accessToken string)
|
||||
if albumID == "" {
|
||||
albumPath = "root"
|
||||
}
|
||||
|
||||
// Extract metadata (dimensions)
|
||||
var meta datatypes.JSON
|
||||
src, err := file.Open()
|
||||
if err == nil {
|
||||
defer src.Close()
|
||||
cfg, _, err := image.DecodeConfig(src)
|
||||
if err == nil {
|
||||
m := map[string]int{
|
||||
"width": cfg.Width,
|
||||
"height": cfg.Height,
|
||||
}
|
||||
b, _ := json.Marshal(m)
|
||||
meta = datatypes.JSON(b)
|
||||
}
|
||||
}
|
||||
|
||||
mediaID := uuid.New().String()
|
||||
mediaPath := fmt.Sprintf("media/%s/%s.%s", albumPath, mediaID, file.Filename)
|
||||
media := models.Media{
|
||||
@@ -31,6 +54,7 @@ func UploadMedia(file *multipart.FileHeader, albumID string, accessToken string)
|
||||
AlbumID: albumID,
|
||||
Path: mediaPath,
|
||||
Type: file.Header.Get("Content-Type"),
|
||||
Metadata: meta,
|
||||
}
|
||||
result := db.GetDB().Create(&media)
|
||||
if result.Error != nil {
|
||||
|
||||
@@ -10,13 +10,12 @@ export default function MediaList({ albumId, albumName }) {
|
||||
const { getAccessToken } = useAccount()
|
||||
const [open, setOpen] = useState(false)
|
||||
const [media, setMedia] = useState([])
|
||||
const [aspectRatios, setAspectRatios] = useState({})
|
||||
const { showError } = useNotifier()
|
||||
|
||||
useEffect(() => {
|
||||
let ignore = false;
|
||||
const getMedia = async () => {
|
||||
// TODO: Implement media fetching from API
|
||||
// const response = await fetch(...)
|
||||
const response = await fetch(`${getServerUrl()}/api/media/getAllMediaInAlbum?albumId=${albumId}`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
@@ -28,7 +27,6 @@ export default function MediaList({ albumId, albumName }) {
|
||||
if (data.error) {
|
||||
showError(data.error)
|
||||
} else {
|
||||
console.log("data.media", data.media)
|
||||
setMedia(data.media)
|
||||
}
|
||||
}
|
||||
@@ -36,6 +34,16 @@ export default function MediaList({ albumId, albumName }) {
|
||||
return () => { ignore = true; }
|
||||
}, [albumId])
|
||||
|
||||
const handleImageLoad = (id, event) => {
|
||||
const { naturalWidth, naturalHeight } = event.target
|
||||
if (naturalWidth && naturalHeight) {
|
||||
setAspectRatios(prev => ({
|
||||
...prev,
|
||||
[id]: naturalWidth / naturalHeight
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-start w-full bg-[#141414]">
|
||||
<div className="flex flex-row items-center justify-between gap-2 w-full px-6 py-4">
|
||||
@@ -44,20 +52,41 @@ export default function MediaList({ albumId, albumName }) {
|
||||
</div>
|
||||
|
||||
{/* Media Grid */}
|
||||
<div className="flex flex-row items-center justify-start gap-2 w-full px-6 flex-wrap">
|
||||
<div className="flex flex-wrap justify-start gap-2 w-full px-6">
|
||||
{media.length === 0 && (
|
||||
<p className="text-gray-500 red-hat-text">No media in this album</p>
|
||||
)}
|
||||
{media.map((media) => (
|
||||
<div key={media.id} className="flex flex-col items-center justify-center w-24 h-24 bg-[#1A1A1A] rounded-md border border-[#2B2B2B]">
|
||||
{media.map((item) => {
|
||||
let ar = 1;
|
||||
// Try to get aspect ratio from metadata (new uploads) or fallback to loaded state (old uploads)
|
||||
if (item.Metadata && item.Metadata.width && item.Metadata.height) {
|
||||
ar = item.Metadata.width / item.Metadata.height;
|
||||
} else if (aspectRatios[item.ID]) {
|
||||
ar = aspectRatios[item.ID];
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
key={item.ID}
|
||||
style={{
|
||||
height: '220px',
|
||||
flexGrow: ar,
|
||||
flexBasis: `${220 * ar}px`,
|
||||
}}
|
||||
className="relative bg-[#1A1A1A] rounded-md overflow-hidden border border-[#2B2B2B] min-w-[100px]"
|
||||
>
|
||||
<AuthImage
|
||||
src={`${getServerUrl()}/api/media/${albumId ? albumId : 'root'}/${media.ID}`}
|
||||
src={`${getServerUrl()}/api/media/${albumId ? albumId : 'root'}/${item.ID}`}
|
||||
token={getAccessToken()}
|
||||
alt={media.Title}
|
||||
alt={item.Title}
|
||||
className="w-full h-full object-cover"
|
||||
onLoad={(e) => handleImageLoad(item.ID, e)}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
)
|
||||
})}
|
||||
{/* Spacer to prevent the last row from expanding to fill width if it has few items */}
|
||||
<div style={{ flexGrow: 9999, flexBasis: '50%' }}></div>
|
||||
</div>
|
||||
|
||||
<MediaUploadModal
|
||||
|
||||
Reference in New Issue
Block a user