From 7c12720f8e2e6e663b9d11f62c8414c8a822dd06 Mon Sep 17 00:00:00 2001 From: jonghyeons Date: Wed, 31 Aug 2022 17:02:52 +0900 Subject: [PATCH 1/3] =?UTF-8?q?feat:=202.0=20=EC=97=85=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + cmd/root.go | 20 ++++++++ cmd/run.go | 133 ++++++++++++++++++++++++++++++++++++++++++++++++ cmd/run_test.go | 70 +++++++++++++++++++++++++ go.mod | 7 ++- go.sum | 10 ++++ main.go | 117 +----------------------------------------- sample/.keep | 0 utils/utils.go | 42 +++++++++++++++ 9 files changed, 283 insertions(+), 117 deletions(-) create mode 100644 .gitignore create mode 100644 cmd/root.go create mode 100644 cmd/run.go create mode 100644 cmd/run_test.go create mode 100644 sample/.keep create mode 100644 utils/utils.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..723ef36 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.idea \ No newline at end of file diff --git a/cmd/root.go b/cmd/root.go new file mode 100644 index 0000000..5d61884 --- /dev/null +++ b/cmd/root.go @@ -0,0 +1,20 @@ +package cmd + +import ( + "os" + + "github.com/spf13/cobra" +) + +var rootCmd = &cobra.Command{ + Use: "photopic", + Short: "Photopic is JPG, RAW file sorting program in terminal", + Long: `Photopic is JPG, RAW file sorting program in terminal`, +} + +func Execute() { + err := rootCmd.Execute() + if err != nil { + os.Exit(1) + } +} diff --git a/cmd/run.go b/cmd/run.go new file mode 100644 index 0000000..0661f27 --- /dev/null +++ b/cmd/run.go @@ -0,0 +1,133 @@ +package cmd + +import ( + "fmt" + "github.com/jonghyeons/photopic/utils" + "github.com/rwcarlsen/goexif/exif" + "github.com/spf13/cobra" + "io/fs" + "io/ioutil" + "os" + "path/filepath" + "strings" +) + +var ( + wideAngleLensCnt = 0 + standardLensCnt = 0 + telephotoLensCnt = 0 + errCnt = 0 +) + +var runCmd = &cobra.Command{ + Use: "run", + Short: "Classify JPEG and RAW files.", + Long: `Classify JPEG and RAW files. +Usage: +photopic run [filepath]`, + Run: func(cmd *cobra.Command, args []string) { + dir := "" + if len(args) != 0 { + dir = args[0] + } else { + var err error + dir, err = os.Getwd() + if err != nil { + fmt.Println(err.Error()) + os.Exit(1) + } + } + + err := utils.MakeDir(dir) + if err != nil { + fmt.Println(err.Error()) + os.Exit(1) + } + + files, err := ioutil.ReadDir(dir) + if err != nil { + fmt.Println(err.Error()) + os.Exit(1) + } + if len(files) == 0 { + fmt.Println("empty directory") + os.Exit(1) + } + + AnalysisExifAndMoveFile(dir, files) + + fmt.Println("## It's done!") + fmt.Println("## Photopic Report") + fmt.Println("1. Lens Angle") + fmt.Println("# This data is analyzed only in the raw files.") + fmt.Println("wide-angle ", wideAngleLensCnt, "shot") + fmt.Println("standard ", standardLensCnt, "shot") + fmt.Println("telephoto ", telephotoLensCnt, "shot") + fmt.Println("analysis failure: ", errCnt) + }, +} + +func init() { + rootCmd.AddCommand(runCmd) + rootCmd.Flags().BoolP("directory", "d", false, "Specifies the directory. (default: current file path)") +} + +func AnalysisExifAndMoveFile(dir string, files []fs.FileInfo) { + rawTypes := []string{"RAF", "CRW", "CR2", "CR3", "NEF", "NRW", "PEF", "DNG", "SRW", "ORF", "SRF", "SR2", "ARW", "RW2", "3FR", "DCR", "KDC", "MRW", "RWL", "DNG", "MOS", "X3F", "GPR"} + + for _, file := range files { + fn := strings.Split(file.Name(), ".") + fileType := fn[len(fn)-1] + + if fileType == "JPG" { + err := os.Rename(filepath.Join(dir, "/", file.Name()), filepath.Join(dir, "/jpg/", file.Name())) + if err != nil { + fmt.Println(file.Name(), err.Error()) + } + } else if utils.Contains(rawTypes, fileType) { + err := SetLensAngleCnt(dir + "/" + file.Name()) + if err != nil { + fmt.Println(file.Name(), err.Error()) + } + err = os.Rename(filepath.Join(dir, "/", file.Name()), filepath.Join(dir, "/raw/", file.Name())) + if err != nil { + fmt.Println(file.Name(), err.Error()) + } + } + } +} + +func SetLensAngleCnt(fnameWithPath string) error { + f, err := os.Open(fnameWithPath) + if err != nil { + return err + } + + exif.RegisterParsers() + x, err := exif.Decode(f) + if err != nil { + return err + } + + focal, err := x.Get(exif.FocalLength) + if err != nil { + errCnt++ + return err + } + + numer, denom, err := focal.Rat2(0) + if err != nil { + errCnt++ + return err + } + + if numer/denom < 35 { + wideAngleLensCnt++ + } else if numer/denom >= 35 || numer/denom < 85 { + standardLensCnt++ + } else { + telephotoLensCnt++ + } + + return nil +} diff --git a/cmd/run_test.go b/cmd/run_test.go new file mode 100644 index 0000000..264c1ce --- /dev/null +++ b/cmd/run_test.go @@ -0,0 +1,70 @@ +package cmd + +import ( + "fmt" + "github.com/jonghyeons/photopic/utils" + "io/fs" + "io/ioutil" + "os" + "path/filepath" + "testing" +) + +// The image file must be located in the path(/sample). +func TestAnalysisExifAndMoveFile(t *testing.T) { + dir, err := os.Getwd() + if err != nil { + t.Errorf(err.Error()) + } + + dir = filepath.Join(dir, "/../sample") + err = utils.MakeDir(dir) + if err != nil { + t.Errorf(err.Error()) + } + + files, err := ioutil.ReadDir(dir) + if err != nil { + t.Errorf(err.Error()) + } + if len(files) == 0 { + fmt.Println("empty directory") + t.Error() + } + + type args struct { + dir string + files []fs.FileInfo + } + tests := []struct { + name string + args args + }{ + { + name: "exif analysis test", + args: args{ + dir: dir, + files: files, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + AnalysisExifAndMoveFile(tt.args.dir, tt.args.files) + }) + } + + if wideAngleLensCnt > 0 || standardLensCnt > 0 || telephotoLensCnt > 0 || errCnt > 0 { + fmt.Println("## It's done!") + fmt.Println("## Photopic Report") + fmt.Println("1. Lens Angle") + fmt.Println("# This data is analyzed only in the raw files.") + fmt.Println("wide-angle ", wideAngleLensCnt, "shot") + fmt.Println("standard ", standardLensCnt, "shot") + fmt.Println("telephoto ", telephotoLensCnt, "shot") + fmt.Println("analysis failure: ", errCnt) + } else { + t.Error() + } +} diff --git a/go.mod b/go.mod index daa727c..4c71eaa 100644 --- a/go.mod +++ b/go.mod @@ -1,5 +1,8 @@ module github.com/jonghyeons/photopic -go 1.12 +go 1.13 -require github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd +require ( + github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd + github.com/spf13/cobra v1.4.0 +) diff --git a/go.sum b/go.sum index 4f6df19..554f54d 100644 --- a/go.sum +++ b/go.sum @@ -1,2 +1,12 @@ +github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd h1:CmH9+J6ZSsIjUK3dcGsnCnO41eRBOnY12zwkn5qVwgc= github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk= +github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q= +github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= diff --git a/main.go b/main.go index 78dcb9a..d781db1 100644 --- a/main.go +++ b/main.go @@ -1,120 +1,7 @@ package main -import ( - "flag" - "fmt" - "github.com/rwcarlsen/goexif/exif" - "io/ioutil" - "os" - "path/filepath" - "strings" -) - -var ( - wideAngleLensCnt = 0 - standardLensCnt = 0 - telephotoLensCnt = 0 - errCnt = 0 -) +import "github.com/jonghyeons/photopic/cmd" func main() { - dir := "" - flag.Parse() - // fmt.Println("Your flags :: ", flag.Args()) - - if len(flag.Args()) != 0 { - dir = flag.Args()[0] - } else { - dir, _ = filepath.Abs(filepath.Dir(os.Args[0])) - } - - MakeDir(dir) - files, err := ioutil.ReadDir(dir) - - if len(files) == 0 || err != nil { - fmt.Println("ERROR") - fmt.Println(err.Error()) - return - } - - rawType := []string{"RAF", "CR2", "CR3", "ARW"} - - for _, file := range files { - fn := strings.Split(file.Name(), ".") - fileType := fn[len(fn)-1] - - if fileType == "JPG" { - os.Rename(dir+"/"+file.Name(), dir+"/jpg/"+file.Name()) - } else if Contains(rawType, fileType) { - done := SetLensAngleCnt(dir + "/" + file.Name()) - if !done { - errCnt++ - } - - os.Rename(dir+"/"+file.Name(), dir+"/raw/"+file.Name()) - } - } - - fmt.Println("## Photopic Report") - fmt.Println("1. Lens Angle") - fmt.Println("# This data is analyzed only in the raw files. ") - fmt.Println("wide-angle: ", wideAngleLensCnt, "shot") - fmt.Println("standard: ", standardLensCnt, "shot") - fmt.Println("telephoto: ", telephotoLensCnt, "shot") - fmt.Println("analysis failure: ", errCnt) - -} - -func MakeDir(path string) { - jpgDir, _ := Exists(path + "/jpg") - if !jpgDir { - os.MkdirAll(path+"/jpg", os.ModePerm) - } - rawDir, _ := Exists(path + "/raw") - if !rawDir { - os.MkdirAll(path+"/raw", os.ModePerm) - } -} - -func Exists(path string) (bool, error) { - _, err := os.Stat(path) - if err == nil { - return true, nil - } - if os.IsNotExist(err) { - return false, nil - } - return true, err -} - -func Contains(a []string, x string) bool { - for _, n := range a { - if x == n { - return true - } - } - return false -} - -func SetLensAngleCnt(fnameWithPath string) bool { - f, _ := os.Open(fnameWithPath) - - exif.RegisterParsers() - x, err := exif.Decode(f) - if err != nil { - return false - } - - focal, _ := x.Get(exif.FocalLength) - numer, denom, _ := focal.Rat2(0) - - if numer/denom < 35 { - wideAngleLensCnt++ - } else if numer/denom >= 35 || numer/denom < 85 { - standardLensCnt++ - } else { - telephotoLensCnt++ - } - - return true + cmd.Execute() } diff --git a/sample/.keep b/sample/.keep new file mode 100644 index 0000000..e69de29 diff --git a/utils/utils.go b/utils/utils.go new file mode 100644 index 0000000..1096487 --- /dev/null +++ b/utils/utils.go @@ -0,0 +1,42 @@ +package utils + +import ( + "os" + "path/filepath" +) + +func MakeDir(path string) error { + jpgPath := filepath.Join(path, "/jpg") + if !Exists(jpgPath) { + err := os.MkdirAll(jpgPath, os.ModePerm) + if err != nil { + return err + } + } + + rawPath := filepath.Join(path, "/raw") + if !Exists(rawPath) { + err := os.MkdirAll(rawPath, os.ModePerm) + if err != nil { + return err + } + } + return nil +} + +func Exists(path string) bool { + _, err := os.Stat(path) + if os.IsNotExist(err) { + return false + } + return true +} + +func Contains(a []string, x string) bool { + for _, n := range a { + if x == n { + return true + } + } + return false +} From ece783c1216903040c6773cd1787363d2e536008 Mon Sep 17 00:00:00 2001 From: jonghyeons Date: Wed, 31 Aug 2022 17:03:02 +0900 Subject: [PATCH 2/3] =?UTF-8?q?docs:=20README=20=EC=97=85=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c17f8b1..a516c2e 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,10 @@ JPG, RAW file sorter program in terminal written golang ### How to install - +```bash +go get github.com/jonghyeons/photopic +``` +OR ```bash $ git clone https://github.com/jonghyeons/photopic.git $ cd photopic @@ -17,11 +20,14 @@ $ go install ### Usage ```bash +# Show help +$ photopic help + # Run in current filepath -$ photopic +$ photopic run # Run another filepath -$ photopic YOURFILEPATH +$ photopic run YOUR_FILE_PATH ``` From 918a8dc49bcc51bd48bed74579dc7dd85db57cdc Mon Sep 17 00:00:00 2001 From: jonghyeons Date: Wed, 31 Aug 2022 17:03:25 +0900 Subject: [PATCH 3/3] =?UTF-8?q?docs:=20BSD=203=20=EB=9D=BC=EC=9D=B4?= =?UTF-8?q?=EC=84=BC=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- LICENSE | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..8bbff51 --- /dev/null +++ b/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2022, jonghyeons +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.