diff --git a/internal/piwigo/files.go b/internal/piwigo/files.go new file mode 100644 index 0000000..80ec9ae --- /dev/null +++ b/internal/piwigo/files.go @@ -0,0 +1,64 @@ +package piwigo + +import ( + "errors" + "fmt" + "net/url" + "os" +) + +func (p *Piwigo) FileExists(md5 string) bool { + var resp map[string]*string + + if err := p.Post("pwg.images.exist", &url.Values{ + "md5sum_list": []string{md5}, + }, &resp); err != nil { + return false + } + + return resp[md5] != nil +} + +func (p *Piwigo) UploadChunks(filename string) error { + md5, err := Md5File(filename) + if err != nil { + return err + } + + if p.FileExists(md5) { + return errors.New("file already exists") + } + + f, err := os.Open(filename) + if err != nil { + return err + } + defer f.Close() + + st, err := f.Stat() + if err != nil { + return err + } + + nbChunks := st.Size()/CHUNK_SIZE + 1 + for position := int64(0); position < nbChunks; position++ { + b64, err := Base64Chunk(f, int64(position)) + if err != nil { + return err + } + + err = p.Post("pwg.images.addChunk", &url.Values{ + "original_sum": []string{md5}, + "position": []string{fmt.Sprint(position)}, + "type": []string{"file"}, + "data": []string{b64}, + }, nil) + if err != nil { + return err + } + fmt.Printf("Upload %d/%d ok\n", position+1, nbChunks) + } + fmt.Println(md5) + + return nil +} diff --git a/internal/piwigo/helper.go b/internal/piwigo/helper.go index 94dda4d..94eaf69 100644 --- a/internal/piwigo/helper.go +++ b/internal/piwigo/helper.go @@ -1,13 +1,20 @@ package piwigo import ( + "crypto/md5" + "encoding/base64" "encoding/json" "errors" "fmt" + "io" + "math" "net/url" + "os" "strings" ) +var CHUNK_SIZE int64 = int64(math.Pow(1024, 2)) + func DumpResponse(v interface{}) (err error) { b, err := json.MarshalIndent(v, "", " ") if err == nil { @@ -27,3 +34,28 @@ func ArgsToForm(args []string) (*url.Values, error) { } return params, nil } + +func Md5File(filename string) (string, error) { + file, err := os.Open(filename) + if err != nil { + return "", err + } + hash := md5.New() + _, err = io.Copy(hash, file) + if err != nil { + return "", err + } + return fmt.Sprintf("%x", hash.Sum(nil)), nil +} + +func Base64Chunk(file *os.File, position int64) (string, error) { + b := make([]byte, CHUNK_SIZE) + n, err := file.ReadAt(b, position*CHUNK_SIZE) + if err != nil && err != io.EOF { + return "", err + } + if n == 0 { + return "", errors.New("position out of bound") + } + return base64.StdEncoding.EncodeToString(b[:n]), nil +} diff --git a/internal/piwigocli/images.go b/internal/piwigocli/images.go index 5d07762..3b51009 100644 --- a/internal/piwigocli/images.go +++ b/internal/piwigocli/images.go @@ -2,6 +2,7 @@ package piwigocli type ImagesGroup struct { Details ImagesDetailsCommand `command:"details" description:"Details of the images"` + Upload ImagesUploadCommand `command:"upload" description:"Upload of an images"` } var imagesGroup ImagesGroup diff --git a/internal/piwigocli/images_upload.go b/internal/piwigocli/images_upload.go new file mode 100644 index 0000000..c5df3ac --- /dev/null +++ b/internal/piwigocli/images_upload.go @@ -0,0 +1,28 @@ +package piwigocli + +import ( + "github.com/celogeek/piwigo-cli/internal/piwigo" +) + +type ImagesUploadCommand struct { + Filename string `short:"f" long:"filename" description:"File to upload"` +} + +func (c *ImagesUploadCommand) Execute(args []string) error { + p := piwigo.Piwigo{} + if err := p.LoadConfig(); err != nil { + return err + } + + _, err := p.Login() + if err != nil { + return err + } + + err = p.UploadChunks(c.Filename) + if err != nil { + return err + } + + return nil +}