package piwigotools import ( "bytes" "crypto/md5" "encoding/base64" "fmt" "io" "os" "path/filepath" "strings" "time" "github.com/barasher/go-exiftool" ) type FileInfo struct { md5 string size int64 ext string createdAt *TimeResult } type FileToUpload struct { Dir string Name string CategoryId int info *FileInfo } func (f *FileToUpload) FullPath() string { return filepath.Join(f.Dir, f.Name) } func (f *FileToUpload) Info() *FileInfo { if f.info != nil { return f.info } file, err := os.Open(f.FullPath()) if err != nil { return nil } defer file.Close() st, err := file.Stat() if err != nil { return nil } hash := md5.New() if _, err = io.Copy(hash, file); err != nil { return nil } checksum := fmt.Sprintf("%x", hash.Sum(nil)) info := FileInfo{ size: st.Size(), ext: strings.ToLower(filepath.Ext(f.Name)[1:]), md5: checksum, createdAt: f.exifCreatedAt(), } f.info = &info return f.info } func (f *FileToUpload) Checked() bool { return f.info != nil } func (f *FileToUpload) MD5() string { if info := f.Info(); info != nil { return info.md5 } return "" } func (f *FileToUpload) Size() int64 { if info := f.Info(); info != nil { return info.size } return -1 } func (f *FileToUpload) Ext() string { if info := f.Info(); info != nil { return info.ext } return "" } func (f *FileToUpload) CreatedAt() *TimeResult { if info := f.Info(); info != nil { return info.createdAt } return nil } var ( CHUNK_SIZE int64 = 1 * 1024 * 1024 CHUNK_BUFF_SIZE int64 = 32 * 1024 CHUNK_BUFF_COUNT = CHUNK_SIZE / CHUNK_BUFF_SIZE ) type FileToUploadChunk struct { Position int64 Size int64 Buffer bytes.Buffer } func (f *FileToUpload) Base64Chunker() (chan *FileToUploadChunk, error) { fh, err := os.Open(f.FullPath()) if err != nil { return nil, err } out := make(chan *FileToUploadChunk, 8) chunker := func() { b := make([]byte, CHUNK_BUFF_SIZE) defer fh.Close() defer close(out) ok := false for position := int64(0); !ok; position += 1 { bf := &FileToUploadChunk{ Position: position, } b64 := base64.NewEncoder(base64.StdEncoding, &bf.Buffer) for i := int64(0); i < CHUNK_BUFF_COUNT; i++ { n, _ := fh.Read(b) if n == 0 { ok = true break } bf.Size += int64(n) b64.Write(b[:n]) } b64.Close() if bf.Size > 0 { out <- bf } } } go chunker() return out, nil } func (f *FileToUpload) exifCreatedAt() *TimeResult { et, err := exiftool.NewExiftool() if err != nil { return nil } defer et.Close() var createdAt *time.Time var CreateDateFormat = "2006:01:02 15:04:05-07:00" fileInfos := et.ExtractMetadata(f.FullPath()) for _, fileInfo := range fileInfos { if fileInfo.Err != nil { continue } var t time.Time for k, v := range fileInfo.Fields { switch k { case "CreateDate": offset, ok := fileInfo.Fields["OffsetTime"] if !ok { offset = "+00:00" } v := fmt.Sprintf("%s%s", v, offset) t, err = time.Parse(CreateDateFormat, v) case "CreationDate": t, err = time.Parse(CreateDateFormat, fmt.Sprint(v)) default: continue } if err != nil { continue } if createdAt == nil || createdAt.After(t) { createdAt = &t } } } if createdAt != nil { result := TimeResult(*createdAt) return &result } return nil }