package api import ( "io" "os" "fmt" "strings" "net/http" "encoding/json" log "github.com/sirupsen/logrus" "github.com/dsoprea/go-exif/v3" "reichard.io/imagini/internal/models" ) func (api *API) mediaItemsHandler(w http.ResponseWriter, r *http.Request) { if r.Method == http.MethodPost { // CREATE api.createMediaItem(w, r) } else if r.Method == http.MethodPut { // UPDATE / REPLACE } else if r.Method == http.MethodPatch { // UPDATE / MODIFY } else if r.Method == http.MethodDelete { // DELETE } else if r.Method == http.MethodGet { // GET } else { errorJSON(w, "Method is not supported.", http.StatusMethodNotAllowed) return } } func (api *API) createMediaItem(w http.ResponseWriter, r *http.Request) { r.ParseMultipartForm(64 << 20) // Parse metadata metadata := r.FormValue("metadata") var mediaItem models.MediaItem err := json.Unmarshal([]byte(metadata), &mediaItem) if err != nil { log.Warn("[api] createMediaItem - Invalid metadata: ", err) errorJSON(w, "Metadata invalid.", http.StatusBadRequest) return } // TODO: Verify mediaItem contains appropriate values // fmt.Printf("Media Item: %+v\n", mediaItem) // Open form file formFile, multipartFileHeader, err := r.FormFile("file") if err != nil { errorJSON(w, "Upload failed.", http.StatusInternalServerError) return } defer formFile.Close() // File header placeholder fileHeader := make([]byte, 512) // Copy headers into the buffer if _, err := formFile.Read(fileHeader); err != nil { errorJSON(w, "Upload failed.", http.StatusInternalServerError) return } // Reset position if _, err := formFile.Seek(0, 0); err != nil { errorJSON(w, "Upload failed.", http.StatusInternalServerError) return } // Determine media type var mediaType string contentType := http.DetectContentType(fileHeader) if strings.HasPrefix(contentType, "image/") { mediaType = "Image" } else if strings.HasPrefix(contentType, "video/") { mediaType = "Video" } else { errorJSON(w, "Invalid filetype.", http.StatusUnsupportedMediaType) return } _ = mediaType _ = multipartFileHeader // Print details // Filename: multipartFileHeader.Filename // Size: multipartFileHeader.Size // ContentType: http.DetectContentType(fileHeader) // Open file to store filePath := "./test.png" // TODO: Change dynamic f, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE, 0600) if err != nil { log.Warn("[api] createMediaItem - Unable to open file: ", filePath) errorJSON(w, "Upload failed.", http.StatusInternalServerError) return } defer f.Close() // Copy data to file _, err = io.Copy(f, formFile) if err != nil { errorJSON(w, "Upload failed.", http.StatusInternalServerError) return } // Gather EXIF Data mediaItem = deriveEXIFData(filePath, mediaItem) // TODO: Add resource location in response successJSON(w, "Upload succeeded.", http.StatusCreated) } func deriveEXIFData(filePath string, mediaItem models.MediaItem) models.MediaItem { rawExif, err := exif.SearchFileAndExtractExif(filePath) entries, _, err := exif.GetFlatExifData(rawExif, nil) _ = err // parsedJSON, err := json.MarshalIndent(entries, "", " ") // fmt.Printf("EXIF String: %+v\n", string(parsedJSON)) for _, entry := range entries { fmt.Printf("IFD-PATH=[%s] ID=(0x%04x) NAME=[%s] COUNT=(%d) TYPE=[%s] VALUE=[%s]\n", entry.IfdPath, entry.TagId, entry.TagName, entry.UnitCount, entry.TagTypeName, entry.Formatted) } return mediaItem }