mirror of
https://github.com/celogeek/piwigo-cli.git
synced 2025-05-25 18:22:37 +02:00
merge file info
This commit is contained in:
parent
28e99a59d2
commit
cabd7084fc
@ -1,55 +0,0 @@
|
|||||||
package base64
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
b64 "encoding/base64"
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
var CHUNK_SIZE int64 = 1 * 1024 * 1024
|
|
||||||
var CHUNK_BUFF_SIZE int64 = 32 * 1024
|
|
||||||
var CHUNK_BUFF_COUNT = CHUNK_SIZE / CHUNK_BUFF_SIZE
|
|
||||||
|
|
||||||
type Chunk struct {
|
|
||||||
Position int64
|
|
||||||
Size int64
|
|
||||||
Buffer bytes.Buffer
|
|
||||||
}
|
|
||||||
|
|
||||||
func Chunker(filename string) (chan *Chunk, error) {
|
|
||||||
f, err := os.Open(filename)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
out := make(chan *Chunk, 8)
|
|
||||||
chunker := func() {
|
|
||||||
b := make([]byte, CHUNK_BUFF_SIZE)
|
|
||||||
defer f.Close()
|
|
||||||
defer close(out)
|
|
||||||
ok := false
|
|
||||||
for position := int64(0); !ok; position += 1 {
|
|
||||||
bf := &Chunk{
|
|
||||||
Position: position,
|
|
||||||
}
|
|
||||||
b64 := b64.NewEncoder(b64.StdEncoding, &bf.Buffer)
|
|
||||||
for i := int64(0); i < CHUNK_BUFF_COUNT; i++ {
|
|
||||||
n, _ := f.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
|
|
||||||
}
|
|
@ -1,56 +0,0 @@
|
|||||||
package exif
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/barasher/go-exiftool"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Info struct {
|
|
||||||
CreatedAt *time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
CreateDateFormat = "2006:01:02 15:04:05-07:00"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Extract(filename string) (*Info, error) {
|
|
||||||
et, err := exiftool.NewExiftool()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer et.Close()
|
|
||||||
|
|
||||||
var resp *Info = &Info{}
|
|
||||||
fileInfos := et.ExtractMetadata(filename)
|
|
||||||
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 resp.CreatedAt == nil || resp.CreatedAt.After(t) {
|
|
||||||
resp.CreatedAt = &t
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
package md5
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/md5"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
func File(filename string) (string, error) {
|
|
||||||
file, err := os.Open(filename)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
hash := md5.New()
|
|
||||||
if _, err = io.Copy(hash, file); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("%x", hash.Sum(nil)), nil
|
|
||||||
}
|
|
@ -8,8 +8,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/celogeek/piwigo-cli/internal/base64"
|
|
||||||
"github.com/celogeek/piwigo-cli/internal/exif"
|
|
||||||
"github.com/celogeek/piwigo-cli/internal/piwigo/piwigotools"
|
"github.com/celogeek/piwigo-cli/internal/piwigo/piwigotools"
|
||||||
"golang.org/x/text/unicode/norm"
|
"golang.org/x/text/unicode/norm"
|
||||||
)
|
)
|
||||||
@ -59,7 +57,7 @@ func (p *Piwigo) Upload(file *piwigotools.FileToUpload, stat *piwigotools.FileTo
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
wg := &sync.WaitGroup{}
|
wg := &sync.WaitGroup{}
|
||||||
chunks, err := base64.Chunker(file.FullPath())
|
chunks, err := file.Base64Chunker()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
stat.Error("Base64Chunker", file.FullPath(), err)
|
stat.Error("Base64Chunker", file.FullPath(), err)
|
||||||
return
|
return
|
||||||
@ -82,10 +80,9 @@ func (p *Piwigo) Upload(file *piwigotools.FileToUpload, stat *piwigotools.FileTo
|
|||||||
data.Set("original_sum", file.MD5())
|
data.Set("original_sum", file.MD5())
|
||||||
data.Set("original_filename", file.Name)
|
data.Set("original_filename", file.Name)
|
||||||
data.Set("check_uniqueness", "true")
|
data.Set("check_uniqueness", "true")
|
||||||
|
if file.CreatedAt() != nil {
|
||||||
info, _ := exif.Extract(file.FullPath())
|
fmt.Println(file.CreatedAt())
|
||||||
if info != nil && info.CreatedAt != nil {
|
data.Set("date_creation", file.CreatedAt().String())
|
||||||
data.Set("date_creation", piwigotools.TimeResult(*info.CreatedAt).String())
|
|
||||||
}
|
}
|
||||||
if file.CategoryId > 0 {
|
if file.CategoryId > 0 {
|
||||||
data.Set("categories", fmt.Sprint(file.CategoryId))
|
data.Set("categories", fmt.Sprint(file.CategoryId))
|
||||||
@ -117,7 +114,7 @@ func (p *Piwigo) Upload(file *piwigotools.FileToUpload, stat *piwigotools.FileTo
|
|||||||
stat.Done()
|
stat.Done()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Piwigo) UploadChunk(file *piwigotools.FileToUpload, chunks chan *base64.Chunk, wg *sync.WaitGroup, stat *piwigotools.FileToUploadStat, ok *bool) {
|
func (p *Piwigo) UploadChunk(file *piwigotools.FileToUpload, chunks chan *piwigotools.FileToUploadChunk, wg *sync.WaitGroup, stat *piwigotools.FileToUploadStat, ok *bool) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
for chunk := range chunks {
|
for chunk := range chunks {
|
||||||
var err error
|
var err error
|
||||||
|
@ -1,58 +1,196 @@
|
|||||||
package piwigotools
|
package piwigotools
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/md5"
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/celogeek/piwigo-cli/internal/md5"
|
"github.com/barasher/go-exiftool"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type FileInfo struct {
|
||||||
|
md5 string
|
||||||
|
size int64
|
||||||
|
ext string
|
||||||
|
createdAt *TimeResult
|
||||||
|
}
|
||||||
|
|
||||||
type FileToUpload struct {
|
type FileToUpload struct {
|
||||||
Dir string
|
Dir string
|
||||||
Name string
|
Name string
|
||||||
CategoryId int
|
CategoryId int
|
||||||
|
|
||||||
md5 *string
|
info *FileInfo
|
||||||
size *int64
|
|
||||||
ext *string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FileToUpload) FullPath() string {
|
func (f *FileToUpload) FullPath() string {
|
||||||
return filepath.Join(f.Dir, f.Name)
|
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 {
|
func (f *FileToUpload) Checked() bool {
|
||||||
return f.md5 != nil
|
return f.info != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FileToUpload) MD5() string {
|
func (f *FileToUpload) MD5() string {
|
||||||
if f.md5 == nil {
|
if info := f.Info(); info != nil {
|
||||||
md5, err := md5.File(f.FullPath())
|
return info.md5
|
||||||
if err != nil {
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
f.md5 = &md5
|
|
||||||
}
|
|
||||||
return *f.md5
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FileToUpload) Size() int64 {
|
func (f *FileToUpload) Size() int64 {
|
||||||
if f.size == nil {
|
if info := f.Info(); info != nil {
|
||||||
st, err := os.Stat(f.FullPath())
|
return info.size
|
||||||
if err != nil {
|
}
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
size := st.Size()
|
|
||||||
f.size = &size
|
|
||||||
}
|
|
||||||
return *f.size
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FileToUpload) Ext() string {
|
func (f *FileToUpload) Ext() string {
|
||||||
if f.ext == nil {
|
if info := f.Info(); info != nil {
|
||||||
ext := strings.ToLower(filepath.Ext(f.Name)[1:])
|
return info.ext
|
||||||
f.ext = &ext
|
|
||||||
}
|
}
|
||||||
return *f.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
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user