From 72912a4a1a3926a652f6aa7968410b66fea48cac Mon Sep 17 00:00:00 2001 From: Konrad Iturbe Date: Tue, 14 Feb 2023 16:47:30 +0100 Subject: [PATCH] Code quality refactor (#101) --- .golangci.yaml | 10 ++ cmd/apply_lut.go | 1 - cmd/calendar.go | 8 +- cmd/export_tags.go | 14 +- cmd/import.go | 126 +++++++++++++----- cmd/update.go | 1 - pkg/android/android.go | 99 +++++--------- pkg/dji/dji.go | 104 +++++---------- pkg/dji/filetypes.go | 4 - pkg/dji/location.go | 1 + pkg/dji/structs.go | 1 - pkg/errors/errors.go | 1 + pkg/gopro/connect.go | 101 +++++++------- pkg/gopro/gopro.go | 250 ++++++++++++----------------------- pkg/gopro/hilight_tags.go | 2 +- pkg/gopro/location.go | 1 + pkg/gopro/mp4parse.go | 3 +- pkg/gopro/update.go | 5 +- pkg/insta360/insta360.go | 75 +++-------- pkg/insta360/update.go | 6 +- pkg/utils/cameras.go | 38 +----- pkg/utils/client.go | 18 +++ pkg/utils/import.go | 19 +++ pkg/utils/ordering.go | 16 +-- pkg/utils/reversegeo.go | 6 + pkg/utils/reversegeo_test.go | 7 +- 26 files changed, 411 insertions(+), 506 deletions(-) create mode 100644 pkg/utils/client.go create mode 100644 pkg/utils/import.go diff --git a/.golangci.yaml b/.golangci.yaml index 45dda3f..c01eb27 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -11,6 +11,16 @@ linters: - nestif - goconst - asasalint + - bodyclose + - dupl + - durationcheck + - errname + - goconst + - godox + - gofumpt + - importas + - unconvert + - unparam linter-settings: nestif: min-complexity: 20 diff --git a/cmd/apply_lut.go b/cmd/apply_lut.go index dbf60a9..f59517e 100644 --- a/cmd/apply_lut.go +++ b/cmd/apply_lut.go @@ -131,7 +131,6 @@ var applyLutCmd = &cobra.Command{ } color.Green(">> Successfully applied LUT to: %s", input) } - }, } diff --git a/cmd/calendar.go b/cmd/calendar.go index 61cd631..b2a4bfa 100644 --- a/cmd/calendar.go +++ b/cmd/calendar.go @@ -27,7 +27,7 @@ func pad(d time.Weekday) int { return int(d) } -func SplitSliceInChunks(a []string, chuckSize int) [][]string { +func splitSliceInChunks(a []string, chuckSize int) [][]string { chunks := [][]string{} for chuckSize < len(a) { a, chunks = a[chuckSize:], append(chunks, a[0:chuckSize:chuckSize]) @@ -37,7 +37,7 @@ func SplitSliceInChunks(a []string, chuckSize int) [][]string { } func getModDates(input string) ([]time.Time, error) { - var modificationDates = []time.Time{} + modificationDates := []time.Time{} items, err := ioutil.ReadDir(input) if err != nil { return nil, err @@ -69,7 +69,7 @@ var calendarView = &cobra.Command{ cui.Error(err.Error()) } - var modificationDates = []time.Time{} + modificationDates := []time.Time{} switch connectionType { case utils.Connect: @@ -127,7 +127,7 @@ var calendarView = &cobra.Command{ data = append(data, color.YellowString(strconv.Itoa(i))) } } - prepared := SplitSliceInChunks(data, 7) + prepared := splitSliceInChunks(data, 7) for _, v := range prepared { table.Append(v) } diff --git a/cmd/export_tags.go b/cmd/export_tags.go index 68d32e0..88ffe41 100644 --- a/cmd/export_tags.go +++ b/cmd/export_tags.go @@ -24,7 +24,7 @@ func tagAsDuration(tag int, increase bool) string { return fmt.Sprintf("01:00:%d:%03d", seconds, 0) } -func exportCSV(name string, tags gopro.HiLights, output string) error { +func exportCSV(tags gopro.HiLights, output string) error { csvFile, err := os.Create(output) if err != nil { return err @@ -43,12 +43,12 @@ func exportCSV(name string, tags gopro.HiLights, output string) error { return writer.Error() } -func exportJSON(name string, tags gopro.HiLights, output string) error { +func exportJSON(tags gopro.HiLights, output string) error { b, err := json.MarshalIndent(tags, "", "\t") if err != nil { return err } - return os.WriteFile(output, b, 0600) + return os.WriteFile(output, b, 0o600) } func exportEDL(name string, tags gopro.HiLights, output string) error { @@ -58,7 +58,7 @@ FCM: NON-DROP FRAME for index, tag := range tags.Timestamps { content = fmt.Sprintf("%s\n%03d AX V C %s %s %s %s\n* FROM CLIP NAME: %s\n", content, index, "00:00:00:00", "00:00:00:01", tagAsDuration(tag, false), tagAsDuration(tag, true), name) } - return os.WriteFile(output, []byte(content), 0600) + return os.WriteFile(output, []byte(content), 0o600) } func extractIndividual(input, output, format string) (int, error) { @@ -72,12 +72,12 @@ func extractIndividual(input, output, format string) (int, error) { if output == "" { output = strings.Replace(input, filepath.Ext(input), ".csv", -1) } - err = exportCSV(filepath.Base(input), *hilights, output) + err = exportCSV(*hilights, output) case "json": if output == "" { output = strings.Replace(input, filepath.Ext(input), ".json", -1) } - err = exportJSON(filepath.Base(input), *hilights, output) + err = exportJSON(*hilights, output) case "edl": if output == "" { output = strings.Replace(input, filepath.Ext(input), ".edl", -1) @@ -88,7 +88,7 @@ func extractIndividual(input, output, format string) (int, error) { } var exportTags = &cobra.Command{ - Use: "export_tags", + Use: "export-tags", Short: "Export HiLight/other tags in video", Run: func(cmd *cobra.Command, args []string) { input := getFlagString(cmd, "input") diff --git a/cmd/import.go b/cmd/import.go index c86af86..a7114fa 100644 --- a/cmd/import.go +++ b/cmd/import.go @@ -2,9 +2,11 @@ package cmd import ( "fmt" + "log" "os" "path/filepath" "strconv" + "time" "github.com/erdaltsksn/cui" "github.com/fatih/color" @@ -16,6 +18,7 @@ import ( "github.com/konradit/mmt/pkg/utils" "github.com/olekukonko/tablewriter" "github.com/spf13/cobra" + "golang.org/x/exp/slices" ) var importCmd = &cobra.Command{ @@ -30,7 +33,7 @@ var importCmd = &cobra.Command{ if projectName != "" { _, err := os.Stat(filepath.Join(output, projectName)) if os.IsNotExist(err) { - err := os.Mkdir(filepath.Join(output, projectName), 0755) + err := os.Mkdir(filepath.Join(output, projectName), 0o755) if err != nil { cui.Error("Something went wrong creating project dir", err) } @@ -41,25 +44,34 @@ var importCmd = &cobra.Command{ bufferSize := getFlagInt(cmd, "buffer", "1000") prefix := getFlagString(cmd, "prefix") dateRange := getFlagSlice(cmd, "range") - cameraName := getFlagString(cmd, "camera_name") - - customCameraOpts := make(map[string]interface{}) + cameraName := getFlagString(cmd, "camera-name") + connection := utils.ConnectionType(getFlagString(cmd, "connection")) + skipAuxFiles := getFlagBool(cmd, "skip-aux", "true") + sortBy := getFlagSlice(cmd, "sort-by") + if len(sortBy) == 0 { + sortBy = []string{"camera", "location"} + } + sortOptions := utils.SortOptions{ + ByLocation: slices.Contains(sortBy, "location"), + ByCamera: slices.Contains(sortBy, "camera"), + } + tagNames := getFlagSlice(cmd, "tag-names") - if useGoPro, err := cmd.Flags().GetBool("use_gopro"); err == nil && useGoPro { + if useGoPro, err := cmd.Flags().GetBool("use-gopro"); err == nil && useGoPro { detectedGoPro, connectionType, err := gopro.Detect() if err != nil { cui.Error(err.Error()) } input = detectedGoPro - customCameraOpts["connection"] = string(connectionType) + connection = connectionType camera = "gopro" - } else if useInsta360, err := cmd.Flags().GetBool("use_insta360"); err == nil && useInsta360 { + } else if useInsta360, err := cmd.Flags().GetBool("use-insta360"); err == nil && useInsta360 { detectedInsta360, connectionType, err := insta360.Detect() if err != nil { cui.Error(err.Error()) } input = detectedInsta360 - customCameraOpts["connection"] = string(connectionType) + connection = connectionType camera = "insta360" } @@ -69,29 +81,31 @@ var importCmd = &cobra.Command{ cui.Error("Something went wrong", err) } - skipAuxFiles := getFlagBool(cmd, "skip_aux", "true") - customCameraOpts["skip_aux"] = skipAuxFiles - sortBy := getFlagSlice(cmd, "sort_by") - if len(sortBy) == 0 { - customCameraOpts["sort_by"] = []string{"camera", "location"} - } else { - customCameraOpts["sort_by"] = sortBy - } switch c { case utils.GoPro: - if customCameraOpts["connection"] == "" { - connection := getFlagString(cmd, "connection") - if connection == "" { - connection = "sd_card" - } - customCameraOpts["connection"] = connection + if connection == "" { + connection = utils.SDCard } - customCameraOpts["tag_names"] = getFlagSlice(cmd, "tag_names") } - r, err := importFromCamera(c, input, filepath.Join(output, projectName), dateFormat, bufferSize, prefix, dateRange, cameraName, customCameraOpts) + + params := utils.ImportParams{ + Input: input, + Output: output, + CameraName: cameraName, + SkipAuxiliaryFiles: skipAuxFiles, + DateFormat: dateFormat, + BufferSize: bufferSize, + Prefix: prefix, + DateRange: parseDateRange(dateRange, dateFormat), + TagNames: tagNames, + Connection: connection, + Sort: sortOptions, + } + r, err := importFromCamera(c, params) if err != nil { cui.Error("Something went wrong", err) } + data := [][]string{ {strconv.Itoa(r.FilesImported), strconv.Itoa(len(r.FilesNotImported)), strconv.Itoa(len(r.Errors))}, } @@ -128,26 +142,68 @@ func init() { importCmd.Flags().StringP("prefix", "p", "", "Prefix for each file, pass `cameraname` to prepend the camera name (eg: Hero9 Black)") importCmd.Flags().StringSlice("range", []string{}, "A date range, eg: 01-05-2020,05-05-2020 -- also accepted: `today`, `yesterday`, `week`") importCmd.Flags().StringP("connection", "x", "", "Connexion type: `sd_card`, `connect` (GoPro-specific)") - importCmd.Flags().StringSlice("sort_by", []string{}, "Sort files by: `camera`, `location`") - importCmd.Flags().StringSlice("tag_names", []string{}, "Tag names for number of HiLight tags in last 10s of video, each position being the amount, eg: 'marked 1,good stuff,important' => num of tags: 1,2,3") - importCmd.Flags().StringP("skip_aux", "s", "true", "Skip auxiliary files (GoPro: THM, LRV. DJI: SRT)") - importCmd.Flags().String("camera_name", "", "Override camera name detection with specified string") + importCmd.Flags().StringSlice("sort-by", []string{}, "Sort files by: `camera`, `location`") + importCmd.Flags().StringSlice("tag-names", []string{}, "Tag names for number of HiLight tags in last 10s of video, each position being the amount, eg: 'marked 1,good stuff,important' => num of tags: 1,2,3") + importCmd.Flags().StringP("skip-aux", "s", "true", "Skip auxiliary files (GoPro: THM, LRV. DJI: SRT)") + importCmd.Flags().String("camera-name", "", "Override camera name detection with specified string") // Camera helpers - importCmd.Flags().Bool("use_gopro", false, "Detect GoPro camera attached") - importCmd.Flags().Bool("use_insta360", false, "Detect Insta360 camera attached") + importCmd.Flags().Bool("use-gopro", false, "Detect GoPro camera attached") + importCmd.Flags().Bool("use-insta360", false, "Detect Insta360 camera attached") +} + +func parseDateRange(dateRange []string, dateFormat string) []time.Time { + dateStart := time.Date(0o000, time.Month(1), 1, 0, 0, 0, 0, time.UTC) + dateEnd := time.Now() + + if len(dateRange) == 1 { + today := time.Date(dateEnd.Year(), dateEnd.Month(), dateEnd.Day(), 0, 0, 0, 0, dateEnd.Location()) + switch dateRange[0] { + case "today": + dateStart = today + case "yesterday": + dateStart = today.Add(-24 * time.Hour) + case "week": + dateStart = today.Add(-24 * time.Duration((int(dateEnd.Weekday()) - 1)) * time.Hour) + case "week-back": + dateStart = today.Add((-24 * 7) * time.Hour) + } + } + + if len(dateRange) == 2 { + start, err := time.Parse(utils.DateFormatReplacer.Replace(dateFormat), dateRange[0]) + if err != nil { + log.Fatal(err.Error()) + } + if err == nil { + dateStart = time.Date(start.Year(), start.Month(), start.Day(), 0, 0, 0, 0, start.Location()) + } + end, err := time.Parse(utils.DateFormatReplacer.Replace(dateFormat), dateRange[1]) + if err != nil { + log.Fatal(err.Error()) + } + if err == nil { + dateEnd = time.Date(end.Year(), end.Month(), end.Day(), 0, 0, 0, 0, end.Location()) + } + } + + return []time.Time{dateStart, dateEnd} +} + +func callImport(cameraIf utils.Import, params utils.ImportParams) (*utils.Result, error) { + return cameraIf.Import(params) } -func importFromCamera(c utils.Camera, input string, output string, dateFormat string, bufferSize int, prefix string, dateRange []string, cameraName string, camOpts map[string]interface{}) (*utils.Result, error) { +func importFromCamera(c utils.Camera, params utils.ImportParams) (*utils.Result, error) { switch c { case utils.GoPro: - return gopro.Import(input, output, dateFormat, bufferSize, prefix, dateRange, cameraName, camOpts) + return callImport(gopro.Entrypoint{}, params) case utils.DJI: - return dji.Import(input, output, dateFormat, bufferSize, prefix, dateRange, cameraName, camOpts) + return callImport(dji.Entrypoint{}, params) case utils.Insta360: - return insta360.Import(input, output, dateFormat, bufferSize, prefix, dateRange, cameraName, camOpts) + return callImport(insta360.Entrypoint{}, params) case utils.Android: - return android.Import(input, output, dateFormat, bufferSize, prefix, dateRange, cameraName, camOpts) + return callImport(android.Entrypoint{}, params) } return nil, mErrors.ErrUnsupportedCamera("") } diff --git a/cmd/update.go b/cmd/update.go index e45e981..7f5e7dd 100644 --- a/cmd/update.go +++ b/cmd/update.go @@ -31,7 +31,6 @@ var updateCmd = &cobra.Command{ cui.Error("Something went wrong", err) } } - }, } diff --git a/pkg/android/android.go b/pkg/android/android.go index 91b2d9b..eed5049 100644 --- a/pkg/android/android.go +++ b/pkg/android/android.go @@ -3,7 +3,6 @@ package android import ( "io" "io/ioutil" - "log" "os" "path/filepath" "strings" @@ -26,8 +25,10 @@ func pixelNameSort(filename string) (string, string) { return filename, "" } -var locationService = LocationService{} -var replacer = strings.NewReplacer("dd", "02", "mm", "01", "yyyy", "2006") +var ( + locationService = LocationService{} + replacer = strings.NewReplacer("dd", "02", "mm", "01", "yyyy", "2006") +) func prepare(out string, deviceFileName string, deviceModel string, mediaDate string, sortOptions utils.SortOptions, deviceFileReader io.ReadCloser, progressBar *mpb.Progress) (*mpb.Bar, string, error) { localFile, err := ioutil.TempFile(out, deviceFileName) @@ -59,10 +60,11 @@ func prepare(out string, deviceFileName string, deviceModel string, mediaDate st } return bar, dayFolder, nil } -func Import(in, out, dateFormat string, bufferSize int, prefix string, dateRange []string, cameraName string, cameraOptions map[string]interface{}) (*utils.Result, error) { - var result utils.Result - sortOptions := utils.ParseCliOptions(cameraOptions) +type Entrypoint struct{} + +func (Entrypoint) Import(params utils.ImportParams) (*utils.Result, error) { + var result utils.Result client, err := adb.NewWithConfig(adb.ServerConfig{ Port: 5037, @@ -76,8 +78,8 @@ func Import(in, out, dateFormat string, bufferSize int, prefix string, dateRange } deviceDescriptor := adb.AnyUsbDevice() - if in != "any" { - deviceDescriptor = adb.DeviceWithSerial(in) + if params.Input != "any" { + deviceDescriptor = adb.DeviceWithSerial(params.Input) } device := client.Device(deviceDescriptor) @@ -103,45 +105,13 @@ func Import(in, out, dateFormat string, bufferSize int, prefix string, dateRange for entries.Next() { mediaDate := entries.Entry().ModifiedAt.Format("02-01-2006") - if strings.Contains(dateFormat, "yyyy") && strings.Contains(dateFormat, "mm") && strings.Contains(dateFormat, "dd") { - mediaDate = entries.Entry().ModifiedAt.Format(replacer.Replace(dateFormat)) + if strings.Contains(params.DateFormat, "yyyy") && strings.Contains(params.DateFormat, "mm") && strings.Contains(params.DateFormat, "dd") { + mediaDate = entries.Entry().ModifiedAt.Format(replacer.Replace(params.DateFormat)) } // check if is in date range - dateStart := time.Date(0000, time.Month(1), 1, 0, 0, 0, 0, time.UTC) - - dateEnd := time.Now() - - if len(dateRange) == 1 { - switch dateRange[0] { - case "today": - dateStart = time.Date(dateEnd.Year(), dateEnd.Month(), dateEnd.Day(), 0, 0, 0, 0, dateEnd.Location()) - case "yesterday": - dateStart = time.Date(dateEnd.Year(), dateEnd.Month(), dateEnd.Day(), 0, 0, 0, 0, dateEnd.Location()).Add(-24 * time.Hour) - case "week": - dateStart = time.Date(dateEnd.Year(), dateEnd.Month(), dateEnd.Day(), 0, 0, 0, 0, dateEnd.Location()).Add(-24 * time.Duration((int(dateEnd.Weekday()) - 1)) * time.Hour) - } - if entries.Entry().ModifiedAt.Before(dateStart) { - continue - } - if entries.Entry().ModifiedAt.After(dateEnd) { - continue - } - } - - if len(dateRange) == 2 { //nolint - layout := replacer.Replace(dateFormat) - - start, err1 := time.Parse(layout, dateRange[0]) - end, err2 := time.Parse(layout, dateRange[1]) - if err1 == nil && err2 == nil { - if entries.Entry().ModifiedAt.Before(start) { - continue - } - if entries.Entry().ModifiedAt.After(end) { - continue - } - } + if entries.Entry().ModifiedAt.Before(params.DateRange[0]) || entries.Entry().ModifiedAt.After(params.DateRange[0]) { + continue } // Read Original file from device @@ -154,15 +124,14 @@ func Import(in, out, dateFormat string, bufferSize int, prefix string, dateRange } bar, dayFolder, err := prepare( - out, + params.Output, entries.Entry().Name, deviceInfo.Product, mediaDate, - sortOptions, + params.Sort, readfile, progressBar, ) - if err != nil { result.Errors = append(result.Errors, err) result.FilesNotImported = append(result.FilesNotImported, entries.Entry().Name) @@ -177,15 +146,19 @@ func Import(in, out, dateFormat string, bufferSize int, prefix string, dateRange } if _, err := os.Stat(filepath.Join(dayFolder, "videos")); os.IsNotExist(err) { - err = os.MkdirAll(filepath.Join(dayFolder, "videos"), 0755) - if err != nil { - log.Fatal(err.Error()) + mkdirerr := os.MkdirAll(filepath.Join(dayFolder, "videos"), 0o755) + if mkdirerr != nil { + result.Errors = append(result.Errors, mkdirerr) + result.FilesNotImported = append(result.FilesNotImported, entries.Entry().Name) + return &result, nil //nolint } } if _, err := os.Stat(filepath.Join(dayFolder, "photos")); os.IsNotExist(err) { - err = os.MkdirAll(filepath.Join(dayFolder, "photos"), 0755) - if err != nil { - log.Fatal(err.Error()) + mkdirerr := os.MkdirAll(filepath.Join(dayFolder, "photos"), 0o755) + if mkdirerr != nil { + result.Errors = append(result.Errors, mkdirerr) + result.FilesNotImported = append(result.FilesNotImported, entries.Entry().Name) + return &result, nil //nolint } } @@ -195,18 +168,18 @@ func Import(in, out, dateFormat string, bufferSize int, prefix string, dateRange } filename, folder := pixelNameSort(entries.Entry().Name) - if strings.HasSuffix(strings.ToLower(entries.Entry().Name), ".jpg") { //nolint:nestif - if folder != "" { - if _, err := os.Stat(filepath.Join(dayFolder, "photos", folder)); os.IsNotExist(err) { - err = os.MkdirAll(filepath.Join(dayFolder, "photos", folder), 0755) - if err != nil { - log.Fatal(err.Error()) - } + if folder != "" { + if _, err := os.Stat(filepath.Join(dayFolder, "photos", folder)); os.IsNotExist(err) { + mkdirerr := os.MkdirAll(filepath.Join(dayFolder, "photos", folder), 0o755) + if mkdirerr != nil { + result.Errors = append(result.Errors, mkdirerr) + result.FilesNotImported = append(result.FilesNotImported, entries.Entry().Name) + return &result, nil //nolint } - - localPath = filepath.Join(dayFolder, "photos", folder, filename) } - } else { + + localPath = filepath.Join(dayFolder, "photos", folder, filename) + } else if strings.HasSuffix(strings.ToLower(entries.Entry().Name), ".jpg") { localPath = filepath.Join(dayFolder, "photos", entries.Entry().Name) } diff --git a/pkg/dji/dji.go b/pkg/dji/dji.go index 6168007..fad991b 100644 --- a/pkg/dji/dji.go +++ b/pkg/dji/dji.go @@ -44,14 +44,15 @@ func getDeviceNameFromPhoto(path string) (string, error) { //nolint:unused var locationService = LocationService{} -func Import(in, out, dateFormat string, bufferSize int, prefix string, dateRange []string, cameraName string, cameraOptions map[string]interface{}) (*utils.Result, error) { +type Entrypoint struct{} + +func (Entrypoint) Import(params utils.ImportParams) (*utils.Result, error) { // Tested on Mavic Air 2. Osmo Pocket v1 and Spark specific changes to follow. - sortOptions := utils.ParseCliOptions(cameraOptions) - if cameraName == "" { - cameraName = "DJI Device" + if params.CameraName == "" { + params.CameraName = "DJI Device" } - di, err := disk.GetInfo(in) + di, err := disk.GetInfo(params.Input) if err != nil { return nil, err } @@ -65,7 +66,7 @@ func Import(in, out, dateFormat string, bufferSize int, prefix string, dateRange mediaFolderRegex := regexp.MustCompile(`\d+MEDIA`) - root := filepath.Join(in, "DCIM") + root := filepath.Join(params.Input, "DCIM") var result utils.Result folders, err := ioutil.ReadDir(root) @@ -101,47 +102,16 @@ func Import(in, out, dateFormat string, bufferSize int, prefix string, dateRange return godirwalk.SkipThis } d := t.ModTime() - replacer := strings.NewReplacer("dd", "02", "mm", "01", "yyyy", "2006") mediaDate := d.Format("02-01-2006") - if strings.Contains(dateFormat, "yyyy") && strings.Contains(dateFormat, "mm") && strings.Contains(dateFormat, "dd") { - mediaDate = d.Format(replacer.Replace(dateFormat)) + if strings.Contains(params.DateFormat, "yyyy") && strings.Contains(params.DateFormat, "mm") && strings.Contains(params.DateFormat, "dd") { + mediaDate = d.Format(utils.DateFormatReplacer.Replace(params.DateFormat)) } // check if is in date range - if len(dateRange) == 1 { - dateStart := time.Date(0000, time.Month(1), 1, 0, 0, 0, 0, time.UTC) - dateEnd := time.Now() - switch dateRange[0] { - case "today": - dateStart = time.Date(dateEnd.Year(), dateEnd.Month(), dateEnd.Day(), 0, 0, 0, 0, dateEnd.Location()) - case "yesterday": - dateStart = time.Date(dateEnd.Year(), dateEnd.Month(), dateEnd.Day(), 0, 0, 0, 0, dateEnd.Location()).Add(-24 * time.Hour) - case "week": - dateStart = time.Date(dateEnd.Year(), dateEnd.Month(), dateEnd.Day(), 0, 0, 0, 0, dateEnd.Location()).Add(-24 * time.Duration((int(dateEnd.Weekday()) - 1)) * time.Hour) - } - if d.Before(dateStart) { - return godirwalk.SkipThis - } - if d.After(dateEnd) { - return godirwalk.SkipThis - } - } - - if len(dateRange) == 2 { //nolint:nestif - layout := replacer.Replace(dateFormat) - - start, err1 := time.Parse(layout, dateRange[0]) - end, err2 := time.Parse(layout, dateRange[1]) - if err1 == nil && err2 == nil { - if d.Before(start) { - return godirwalk.SkipThis - } - if d.After(end) { - return godirwalk.SkipThis - } - } + if d.Before(params.DateRange[0]) || d.After(params.DateRange[1]) { + return godirwalk.SkipThis } info, err := os.Stat(osPathname) @@ -152,19 +122,19 @@ func Import(in, out, dateFormat string, bufferSize int, prefix string, dateRange wg.Add(1) bar := utils.GetNewBar(progressBar, info.Size(), de.Name(), utils.IoTX) - dayFolder := utils.GetOrder(sortOptions, locationService, osPathname, out, mediaDate, cameraName) + dayFolder := utils.GetOrder(params.Sort, locationService, osPathname, params.Output, mediaDate, params.CameraName) switch ftype.Type { case Photo: if _, err := os.Stat(filepath.Join(dayFolder, "photos")); os.IsNotExist(err) { - err = os.MkdirAll(filepath.Join(dayFolder, "photos"), 0755) - if err != nil { + mkdirerr := os.MkdirAll(filepath.Join(dayFolder, "photos"), 0o755) + if mkdirerr != nil { return godirwalk.SkipThis } } - go func(folder, filename, osPathname string, bar *mpb.Bar) { + go func(filename, osPathname string, bar *mpb.Bar) { defer wg.Done() - err = utils.CopyFile(osPathname, filepath.Join(dayFolder, "photos", filename), bufferSize, bar) + err = utils.CopyFile(osPathname, filepath.Join(dayFolder, "photos", filename), params.BufferSize, bar) if err != nil { bar.EwmaSetCurrent(info.Size(), 1*time.Millisecond) bar.EwmaIncrInt64(info.Size(), 1*time.Millisecond) @@ -172,19 +142,19 @@ func Import(in, out, dateFormat string, bufferSize int, prefix string, dateRange } else { inlineCounter.SetSuccess() } - }(f.Name(), de.Name(), osPathname, bar) + }(de.Name(), osPathname, bar) case Video: if _, err := os.Stat(filepath.Join(dayFolder, "videos")); os.IsNotExist(err) { - err = os.MkdirAll(filepath.Join(dayFolder, "videos"), 0755) - if err != nil { - log.Fatal(err.Error()) + mkdirerr := os.MkdirAll(filepath.Join(dayFolder, "videos"), 0o755) + if mkdirerr != nil { + log.Fatal(mkdirerr.Error()) } } - go func(folder, filename, osPathname string, bar *mpb.Bar) { + go func(filename, osPathname string, bar *mpb.Bar) { defer wg.Done() - err = utils.CopyFile(osPathname, filepath.Join(dayFolder, "videos", filename), bufferSize, bar) + err = utils.CopyFile(osPathname, filepath.Join(dayFolder, "videos", filename), params.BufferSize, bar) if err != nil { bar.EwmaSetCurrent(info.Size(), 1*time.Millisecond) bar.EwmaIncrInt64(info.Size(), 1*time.Millisecond) @@ -192,25 +162,25 @@ func Import(in, out, dateFormat string, bufferSize int, prefix string, dateRange } else { inlineCounter.SetSuccess() } - }(f.Name(), de.Name(), osPathname, bar) + }(de.Name(), osPathname, bar) case Subtitle: extraPath := srtFolderFromConfig() - if sortOptions.SkipAuxiliaryFiles { + if params.SkipAuxiliaryFiles { wg.Done() bar.Abort(true) break } if _, err := os.Stat(filepath.Join(dayFolder, "videos", extraPath)); os.IsNotExist(err) { - err = os.MkdirAll(filepath.Join(dayFolder, "videos", extraPath), 0755) - if err != nil { - log.Fatal(err.Error()) + mkdirerr := os.MkdirAll(filepath.Join(dayFolder, "videos", extraPath), 0o755) + if mkdirerr != nil { + log.Fatal(mkdirerr.Error()) } } - go func(folder, filename, osPathname string, bar *mpb.Bar) { + go func(filename, osPathname string, bar *mpb.Bar) { defer wg.Done() - err = utils.CopyFile(osPathname, filepath.Join(dayFolder, "videos", extraPath, filename), bufferSize, bar) + err = utils.CopyFile(osPathname, filepath.Join(dayFolder, "videos", extraPath, filename), params.BufferSize, bar) if err != nil { bar.EwmaSetCurrent(info.Size(), 1*time.Millisecond) bar.EwmaIncrInt64(info.Size(), 1*time.Millisecond) @@ -218,18 +188,18 @@ func Import(in, out, dateFormat string, bufferSize int, prefix string, dateRange } else { inlineCounter.SetSuccess() } - }(f.Name(), de.Name(), osPathname, bar) + }(de.Name(), osPathname, bar) case RawPhoto: if _, err := os.Stat(filepath.Join(dayFolder, "photos/raw")); os.IsNotExist(err) { - err = os.MkdirAll(filepath.Join(dayFolder, "photos/raw"), 0755) - if err != nil { - log.Fatal(err.Error()) + mkdirerr := os.MkdirAll(filepath.Join(dayFolder, "photos/raw"), 0o755) + if mkdirerr != nil { + log.Fatal(mkdirerr.Error()) } } - go func(folder, filename, osPathname string, bar *mpb.Bar) { + go func(filename, osPathname string, bar *mpb.Bar) { defer wg.Done() - err = utils.CopyFile(osPathname, filepath.Join(dayFolder, "photos/raw", filename), bufferSize, bar) + err = utils.CopyFile(osPathname, filepath.Join(dayFolder, "photos/raw", filename), params.BufferSize, bar) if err != nil { bar.EwmaSetCurrent(info.Size(), 1*time.Millisecond) bar.EwmaIncrInt64(info.Size(), 1*time.Millisecond) @@ -237,10 +207,8 @@ func Import(in, out, dateFormat string, bufferSize int, prefix string, dateRange } else { inlineCounter.SetSuccess() } - }(f.Name(), de.Name(), osPathname, bar) + }(de.Name(), osPathname, bar) case PanoramaIndex: - case Audio: - // TODO get audio files } } diff --git a/pkg/dji/filetypes.go b/pkg/dji/filetypes.go index fccd09f..ea2b9a7 100644 --- a/pkg/dji/filetypes.go +++ b/pkg/dji/filetypes.go @@ -23,8 +23,4 @@ var fileTypes = []FileTypeMatch{ Regex: regexp.MustCompile(`.html`), Type: PanoramaIndex, }, - { - Regex: regexp.MustCompile(`.AAC`), - Type: Audio, - }, } diff --git a/pkg/dji/location.go b/pkg/dji/location.go index 8bb6281..426932d 100644 --- a/pkg/dji/location.go +++ b/pkg/dji/location.go @@ -39,6 +39,7 @@ func (LocationService) GetLocation(path string) (*utils.Location, error) { return nil, mErrors.ErrInvalidFile } } + func fromSRT(srtPath string) (*utils.Location, error) { content, err := ioutil.ReadFile(strings.Replace(srtPath, ".MP4", ".SRT", -1)) if err != nil { diff --git a/pkg/dji/structs.go b/pkg/dji/structs.go index 9fe0c61..97b0dd5 100644 --- a/pkg/dji/structs.go +++ b/pkg/dji/structs.go @@ -10,7 +10,6 @@ const ( Subtitle FileType = "srt" RawPhoto FileType = "dng" PanoramaIndex FileType = "panoramaindex" - Audio FileType = "audio" ) type FileTypeMatch struct { diff --git a/pkg/errors/errors.go b/pkg/errors/errors.go index e1f818d..6c71c9b 100644 --- a/pkg/errors/errors.go +++ b/pkg/errors/errors.go @@ -14,6 +14,7 @@ var ( ErrGeneric = errors.New("Generic error") ErrNoGPS = errors.New("No GPS data found") ErrInvalidCoordinatesFormat = errors.New("Invalid coordinates format") + ErrInvalidSuppliedData = func(data interface{}) error { return fmt.Errorf("Invalid data: %s", data) } ErrUnsupportedCamera = func(camera string) error { return fmt.Errorf("camera %s is not supported", camera) } ErrNotFound = func(item string) error { return fmt.Errorf("Unable to find %s", item) } ) diff --git a/pkg/gopro/connect.go b/pkg/gopro/connect.go index f4e7bc9..bb4a34d 100644 --- a/pkg/gopro/connect.go +++ b/pkg/gopro/connect.go @@ -24,12 +24,14 @@ import ( "github.com/vbauerster/mpb/v8" ) -var ipAddress = "" -var gpTurbo = true +var ( + ipAddress = "" + gpTurbo = true +) func handleKill() { - c := make(chan os.Signal) - signal.Notify(c, os.Interrupt, syscall.SIGTERM) //nolint + c := make(chan os.Signal, 2) + signal.Notify(c, os.Interrupt, syscall.SIGTERM) go func() { <-c color.Red("\nKilling program, exiting Turbo mode.") @@ -41,15 +43,13 @@ func handleKill() { os.Exit(0) }() } + func caller(ip, path string, object interface{}) error { - client := &http.Client{ - Timeout: 10 * time.Second, - } req, err := http.NewRequest("GET", fmt.Sprintf("http://%s/%s", ip, path), nil) if err != nil { return err } - resp, err := client.Do(req) + resp, err := utils.Client.Do(req) if err != nil { return err } @@ -64,15 +64,16 @@ func caller(ip, path string, object interface{}) error { } func head(path string) (int, error) { - client := &http.Client{} req, err := http.NewRequest("HEAD", path, nil) if err != nil { return 0, err } - resp, err := client.Do(req) + resp, err := utils.Client.Do(req) if err != nil { return 0, err } + defer resp.Body.Close() + length, err := strconv.Atoi(resp.Header.Get("Content-Length")) if err != nil { return 0, err @@ -96,7 +97,7 @@ func GetGoProNetworkAddresses() ([]ConnectDevice, error) { ipv4Addr := a.(*net.IPNet).IP.To4() if r.MatchString(ipv4Addr.String()) { correctIP := ipv4Addr.String()[:len(ipv4Addr.String())-1] + "1" - var gpInfo = &cameraInfo{} + gpInfo := &cameraInfo{} err := caller(correctIP, "gp/gpControl/info", gpInfo) if err != nil { continue @@ -112,34 +113,43 @@ func GetGoProNetworkAddresses() ([]ConnectDevice, error) { } func GetMediaList(in string) (*MediaList, error) { - var gpMediaList = &MediaList{} + gpMediaList := &MediaList{} err := caller(in, "gp/gpMediaList", gpMediaList) if err != nil { return nil, err } return gpMediaList, nil } + func forceGetFolder(path string) { if _, err := os.Stat(path); os.IsNotExist(err) { - err = os.MkdirAll(path, 0755) - if err != nil { - log.Fatal(err.Error()) + mkdirerr := os.MkdirAll(path, 0o755) + if mkdirerr != nil { + log.Fatal(mkdirerr.Error()) } } } -func ImportConnect(in, out string, sortOptions utils.SortOptions) (*utils.Result, error) { +func validateIP() bool { + valid := regexp.MustCompile(`^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}$`) + return valid.MatchString(ipAddress) +} + +func ImportConnect(params utils.ImportParams) (*utils.Result, error) { var verType Type var result utils.Result - ipAddress = in + ipAddress = params.Input // handle ctrl-c handleKill() - var gpInfo = &cameraInfo{} - err := caller(in, "gp/gpControl/info", gpInfo) + if !validateIP() { + return nil, mErrors.ErrInvalidSuppliedData(ipAddress) + } + gpInfo := &cameraInfo{} + err := caller(params.Input, "gp/gpControl/info", gpInfo) if err != nil { - return nil, err + return nil, mErrors.ErrNotFound("Connect camera: " + params.Input) } cameraName := gpInfo.Info.ModelName @@ -159,13 +169,13 @@ func ImportConnect(in, out string, sortOptions utils.SortOptions) (*utils.Result // activate turbo if gpTurbo { - err = caller(in, "gp/gpTurbo?p=1", nil) + err = caller(params.Input, "gp/gpTurbo?p=1", nil) if err != nil { color.Red("Error activating Turbo! Download speeds will be much slower") } } - gpMediaList, err := GetMediaList(in) + gpMediaList, err := GetMediaList(params.Input) if err != nil { return nil, err } @@ -177,9 +187,9 @@ func ImportConnect(in, out string, sortOptions utils.SortOptions) (*utils.Result inlineCounter := utils.ResultCounter{} - unsorted := filepath.Join(out, "unsorted") + unsorted := filepath.Join(params.Output, "unsorted") if _, err := os.Stat(unsorted); os.IsNotExist(err) { - _ = os.Mkdir(unsorted, 0755) + _ = os.Mkdir(unsorted, 0o755) } chaptered := regexp.MustCompile(`GP\d+.MP4`) @@ -195,15 +205,15 @@ func ImportConnect(in, out string, sortOptions utils.SortOptions) (*utils.Result continue } tm := time.Unix(i, 0).UTC() - start := sortOptions.DateRange[0] - end := sortOptions.DateRange[1] + start := params.DateRange[0] + end := params.DateRange[1] zoneName, _ := end.Zone() newTime := strings.Replace(tm.Format(time.UnixDate), "UTC", zoneName, -1) tm, _ = time.Parse(time.UnixDate, newTime) mediaDate := tm.Format("02-01-2006") - if strings.Contains(sortOptions.DateFormat, "yyyy") && strings.Contains(sortOptions.DateFormat, "mm") && strings.Contains(sortOptions.DateFormat, "dd") { - mediaDate = tm.Format(replacer.Replace(sortOptions.DateFormat)) + if strings.Contains(params.DateFormat, "yyyy") && strings.Contains(params.DateFormat, "mm") && strings.Contains(params.DateFormat, "dd") { + mediaDate = tm.Format(utils.DateFormatReplacer.Replace(params.DateFormat)) } if tm.Before(start) || tm.After(end) { @@ -216,7 +226,7 @@ func ImportConnect(in, out string, sortOptions utils.SortOptions) (*utils.Result switch fileTypeMatch.Type { case Video, ChapteredVideo: - go func(in, folder, origFilename, unsorted string, origSize int64, lrvSize int, bar *mpb.Bar, result utils.Result) { + go func(in, folder, origFilename, unsorted string, origSize int64, lrvSize int, bar *mpb.Bar) { defer wg.Done() x := origFilename filename := origFilename @@ -243,15 +253,15 @@ func ImportConnect(in, out string, sortOptions utils.SortOptions) (*utils.Result // Move to actual folder - finalPath := utils.GetOrder(sortOptions, locationService, filepath.Join(unsorted, origFilename), out, mediaDate, cameraName) - var gpFileInfo = &goProMediaMetadata{} + finalPath := utils.GetOrder(params.Sort, locationService, filepath.Join(unsorted, origFilename), params.Output, mediaDate, cameraName) + gpFileInfo := &goProMediaMetadata{} err = caller(in, fmt.Sprintf("gp/gpMediaMetadata?p=%s/%s&t=v4info", folder, origFilename), gpFileInfo) if err != nil { inlineCounter.SetFailure(err, origFilename) return } - importanceName := getImportanceName(gpFileInfo.Hi, gpFileInfo.Dur, sortOptions.TagNames) + importanceName := getImportanceName(gpFileInfo.Hi, gpFileInfo.Dur, params.TagNames) denom := gpFileInfo.FpsDenom if denom == 0 { @@ -276,7 +286,7 @@ func ImportConnect(in, out string, sortOptions utils.SortOptions) (*utils.Result } // download proxy - if lrvSize > 0 && !sortOptions.SkipAuxiliaryFiles { + if lrvSize > 0 && !params.SkipAuxiliaryFiles { proxyVideoName := "GL" + strings.Replace(origFilename[2:], ".MP4", ".LRV", -1) if verType == V1 { proxyVideoName = strings.Replace(origFilename, ".MP4", ".LRV", -1) @@ -305,7 +315,7 @@ func ImportConnect(in, out string, sortOptions utils.SortOptions) (*utils.Result } inlineCounter.SetSuccess() } - }(in, folder.D, goprofile.N, unsorted, goprofile.S, goprofile.Glrv, bar, result) + }(params.Input, folder.D, goprofile.N, unsorted, goprofile.S, goprofile.Glrv, bar) case Photo: type photo struct { @@ -320,7 +330,8 @@ func ImportConnect(in, out string, sortOptions utils.SortOptions) (*utils.Result Folder: folder.D, Name: goprofile.N, IsRaw: false, - Bar: bar}, + Bar: bar, + }, } hasRawPhoto := goprofile.Raw == "1" @@ -328,7 +339,7 @@ func ImportConnect(in, out string, sortOptions utils.SortOptions) (*utils.Result wg.Add(1) rawPhotoName := strings.Replace(goprofile.N, ".JPG", ".GPR", -1) - rawPhotoTotal, err := head(fmt.Sprintf("http://%s:8080/videos/DCIM/%s/%s", in, folder.D, rawPhotoName)) + rawPhotoTotal, err := head(fmt.Sprintf("http://%s:8080/videos/DCIM/%s/%s", params.Input, folder.D, rawPhotoName)) if err != nil { continue } @@ -344,7 +355,7 @@ func ImportConnect(in, out string, sortOptions utils.SortOptions) (*utils.Result } for _, item := range totalPhotos { - go func(in string, nowPhoto photo, unsorted string, result utils.Result) { + go func(in string, nowPhoto photo, unsorted string) { defer wg.Done() err := utils.DownloadFile( @@ -360,7 +371,7 @@ func ImportConnect(in, out string, sortOptions utils.SortOptions) (*utils.Result inlineCounter.SetSuccess() // Move to actual folder - finalPath := utils.GetOrder(sortOptions, locationService, filepath.Join(unsorted, nowPhoto.Name), out, mediaDate, cameraName) + finalPath := utils.GetOrder(params.Sort, locationService, filepath.Join(unsorted, nowPhoto.Name), params.Output, mediaDate, cameraName) photoPath := filepath.Join(finalPath, "photos") if nowPhoto.IsRaw { @@ -377,7 +388,7 @@ func ImportConnect(in, out string, sortOptions utils.SortOptions) (*utils.Result return } } - }(in, item, unsorted, result) + }(params.Input, item, unsorted) } case Multishot: @@ -389,14 +400,14 @@ func ImportConnect(in, out string, sortOptions utils.SortOptions) (*utils.Result } filename := fmt.Sprintf("%s%04d.JPG", filebaseroot, i) - var gpFileInfo = &goProMediaMetadata{} - err = caller(in, fmt.Sprintf("gp/gpMediaMetadata?p=%s/%s&t=v4info", folder.D, filename), gpFileInfo) + gpFileInfo := &goProMediaMetadata{} + err = caller(params.Input, fmt.Sprintf("gp/gpMediaMetadata?p=%s/%s&t=v4info", folder.D, filename), gpFileInfo) if err != nil { log.Fatal(err.Error()) } multiShotBar := utils.GetNewBar(progressBar, gpFileInfo.S, filename, utils.IoTX) - go func(in, folder, origFilename, unsorted string, origSize int64, result utils.Result) { + go func(in, folder, origFilename, unsorted string, origSize int64) { defer wg.Done() err := utils.DownloadFile( @@ -411,7 +422,7 @@ func ImportConnect(in, out string, sortOptions utils.SortOptions) (*utils.Result } else { inlineCounter.SetSuccess() // Move to actual folder - finalPath := utils.GetOrder(sortOptions, locationService, filepath.Join(unsorted, origFilename), out, mediaDate, cameraName) + finalPath := utils.GetOrder(params.Sort, locationService, filepath.Join(unsorted, origFilename), params.Output, mediaDate, cameraName) forceGetFolder(filepath.Join(finalPath, "multishot", filebaseroot)) err := os.Rename( @@ -423,7 +434,7 @@ func ImportConnect(in, out string, sortOptions utils.SortOptions) (*utils.Result return } } - }(in, folder.D, filename, unsorted, gpFileInfo.S, result) + }(params.Input, folder.D, filename, unsorted, gpFileInfo.S) } default: @@ -438,7 +449,7 @@ func ImportConnect(in, out string, sortOptions utils.SortOptions) (*utils.Result wg.Wait() progressBar.Shutdown() if gpTurbo { - if err := caller(in, "gp/gpTurbo?p=0", nil); err != nil { + if err := caller(params.Input, "gp/gpTurbo?p=0", nil); err != nil { color.Red("Could not exit turbo mode") } } diff --git a/pkg/gopro/gopro.go b/pkg/gopro/gopro.go index fc47ec2..adfe54e 100644 --- a/pkg/gopro/gopro.go +++ b/pkg/gopro/gopro.go @@ -30,8 +30,6 @@ Uses data from: https://community.gopro.com/t5/en/GoPro-Camera-File-Naming-Convention/ta-p/390220# */ -var replacer = strings.NewReplacer("dd", "02", "mm", "01", "yyyy", "2006") - var MediaFolderRegex = regexp.MustCompile(`\d\d\dGOPRO`) var ffprobe = utils.NewFFprobe(nil) @@ -54,90 +52,31 @@ func getRfpsFolder(pathName string) (string, error) { fpsAsFloat := strconv.Itoa(framerate.(int)) return fmt.Sprintf("%dx%d %s", s.Streams[0].Width, s.Streams[0].Height, fpsAsFloat), nil } -func Import(in, out, dateFormat string, bufferSize int, prefix string, dateRange []string, cameraName string, cameraOptions map[string]interface{}) (*utils.Result, error) { - /* Import method using SD card bay or SD card reader */ - dateStart := time.Date(0000, time.Month(1), 1, 0, 0, 0, 0, time.UTC) - dateEnd := time.Now() - - byCamera := false - byLocation := false - - sortByOptions, found := cameraOptions["sort_by"] - if found { - for _, sortop := range sortByOptions.([]string) { - if sortop == "camera" { - byCamera = true - } - if sortop == "location" { - byLocation = true - } - - if sortop != "camera" && sortop != "days" && sortop != "location" { - return nil, fmt.Errorf("Unrecognized option for sort_by: %s", sortop) - } - } - } - if len(dateRange) == 1 { - today := time.Date(dateEnd.Year(), dateEnd.Month(), dateEnd.Day(), 0, 0, 0, 0, dateEnd.Location()) - switch dateRange[0] { - case "today": - dateStart = today - case "yesterday": - dateStart = today.Add(-24 * time.Hour) - case "week": - dateStart = today.Add(-24 * time.Duration((int(dateEnd.Weekday()) - 1)) * time.Hour) - case "week-back": - dateStart = today.Add((-24 * 7) * time.Hour) - } - } +type Entrypoint struct{} - if len(dateRange) == 2 { - start, err := time.Parse(replacer.Replace(dateFormat), dateRange[0]) - if err != nil { - log.Fatal(err.Error()) - } - if err == nil { - dateStart = time.Date(start.Year(), start.Month(), start.Day(), 0, 0, 0, 0, start.Location()) - } - end, err := time.Parse(replacer.Replace(dateFormat), dateRange[1]) - if err != nil { - log.Fatal(err.Error()) - } - if err == nil { - dateEnd = time.Date(end.Year(), end.Month(), end.Day(), 0, 0, 0, 0, end.Location()) - } - } +func (Entrypoint) Import(params utils.ImportParams) (*utils.Result, error) { + /* Import method using SD card bay or SD card reader */ - skipAux := false - skipAuxOption, found := cameraOptions["skip_aux"] - if found { - skipAux = skipAuxOption.(bool) - } - sortOptions := utils.SortOptions{ - SkipAuxiliaryFiles: skipAux, - ByCamera: byCamera, - ByLocation: byLocation, - DateFormat: dateFormat, - BufferSize: bufferSize, - Prefix: prefix, - DateRange: []time.Time{dateStart, dateEnd}, - TagNames: cameraOptions["tag_names"].([]string), + switch params.Connection { + case utils.Connect: + return ImportConnect(params) + case utils.SDCard: + break + default: + return nil, mErrors.ErrUnsupportedConnection } - connectionType, found := cameraOptions["connection"] - if found { - switch connectionType.(string) { - case string(utils.Connect): - return ImportConnect(in, out, sortOptions) - case string(utils.SDCard): - break - default: - return nil, mErrors.ErrUnsupportedConnection + versionFile := filepath.Join(params.Input, "MISC", fmt.Sprint(Version)) + + _, err := os.Stat(versionFile) + if err != nil { + if os.IsNotExist(err) { + return nil, mErrors.ErrNoCameraDetected } + return nil, mErrors.ErrNotFound(versionFile) } - - versionContent, err := os.ReadFile(filepath.Join(in, "MISC", fmt.Sprint(Version))) + versionContent, err := os.ReadFile(versionFile) if err != nil { return nil, err } @@ -147,7 +86,7 @@ func Import(in, out, dateFormat string, bufferSize int, prefix string, dateRange return nil, err } - di, err := disk.GetInfo(in) + di, err := disk.GetInfo(params.Input) if err != nil { return nil, err } @@ -166,26 +105,31 @@ func Import(in, out, dateFormat string, bufferSize int, prefix string, dateRange root := strings.Split(gpVersion.FirmwareVersion, ".")[0] - if cameraName == "" { - cameraName = gpVersion.CameraType + if params.CameraName == "" { + params.CameraName = gpVersion.CameraType } + if params.Prefix != "" { + params.CameraName = fmt.Sprintf("%s %s", params.Prefix, params.CameraName) + } + params.Input = filepath.Join(params.Input, fmt.Sprint(DCIM)) + switch root { case "HD6", "HD7", "HD8", "H19", "HD9", "H21", "H22": - result := importFromGoProV2(filepath.Join(in, fmt.Sprint(DCIM)), out, sortOptions, cameraName) + result := importFromGoProV2(params) return &result, nil case "HD2", "HD3", "HD4", "HX", "HD5": - result := importFromGoProV1(filepath.Join(in, fmt.Sprint(DCIM)), out, sortOptions, cameraName) + result := importFromGoProV1(params) return &result, nil default: return nil, mErrors.ErrUnsupportedCamera(gpVersion.CameraType) } } -func importFromGoProV2(root string, output string, sortoptions utils.SortOptions, cameraName string) utils.Result { +func importFromGoProV2(params utils.ImportParams) utils.Result { fileTypes := FileTypeMatches[V2] var result utils.Result - folders, err := ioutil.ReadDir(root) + folders, err := ioutil.ReadDir(params.Input) if err != nil { result.Errors = append(result.Errors, err) return result @@ -198,34 +142,28 @@ func importFromGoProV2(root string, output string, sortoptions utils.SortOptions inlineCounter := utils.ResultCounter{} +folderLoop: for _, f := range folders { r := MediaFolderRegex.MatchString(f.Name()) if !r { - continue + continue folderLoop } color.Green("Looking at %s", f.Name()) - err = godirwalk.Walk(filepath.Join(root, f.Name()), &godirwalk.Options{ + err = godirwalk.Walk(filepath.Join(params.Input, f.Name()), &godirwalk.Options{ Callback: func(osPathname string, de *godirwalk.Dirent) error { + fileTypeLoop: for _, ftype := range fileTypes { if !ftype.Regex.MatchString(de.Name()) { - continue + continue fileTypeLoop } - d := getFileTime(osPathname, false) - - mediaDate := getMediaDate(d, sortoptions) + d := getFileTime(osPathname, true) + mediaDate := getMediaDate(getFileTime(osPathname, true), params.DateFormat) - if len(sortoptions.DateRange) == 2 { - start := sortoptions.DateRange[0] - end := sortoptions.DateRange[1] - if d.Before(start) { - return godirwalk.SkipThis - } - if d.After(end) { - return godirwalk.SkipThis - } + if d.Before(params.DateRange[0]) || d.After(params.DateRange[1]) { + return godirwalk.SkipThis } info, err := os.Stat(osPathname) @@ -233,7 +171,7 @@ func importFromGoProV2(root string, output string, sortoptions utils.SortOptions return godirwalk.SkipThis } - dayFolder := utils.GetOrder(sortoptions, locationService, osPathname, output, mediaDate, cameraName) + dayFolder := utils.GetOrder(params.Sort, locationService, osPathname, params.Output, mediaDate, params.CameraName) wg.Add(1) bar := utils.GetNewBar(progressBar, info.Size(), de.Name(), utils.IoTX) @@ -253,16 +191,14 @@ func importFromGoProV2(root string, output string, sortoptions utils.SortOptions if hilights, err := GetHiLights(osPathname); err == nil { if durationResp, err := ffprobe.Duration(osPathname); err == nil { - additionalDir = filepath.Join(additionalDir, getImportanceName(hilights.Timestamps, int(durationResp.Streams[0].Duration), sortoptions.TagNames)) + additionalDir = filepath.Join(additionalDir, getImportanceName(hilights.Timestamps, int(durationResp.Streams[0].Duration), params.TagNames)) } } folder := filepath.Join(dayFolder, "videos", additionalDir, rfpsFolder) go func(folder, filename, osPathname string, bar *mpb.Bar) { defer wg.Done() - err := parse(folder, filename, osPathname, sortoptions, result, bar) + err := parse(folder, filename, osPathname, params.BufferSize, bar) if err != nil { - bar.EwmaSetCurrent(info.Size(), 1*time.Millisecond) - bar.EwmaIncrInt64(info.Size(), 1*time.Millisecond) inlineCounter.SetFailure(err, filename) } else { inlineCounter.SetSuccess() @@ -270,7 +206,7 @@ func importFromGoProV2(root string, output string, sortoptions utils.SortOptions }(folder, filename, osPathname, bar) // Get LRV - if sortoptions.SkipAuxiliaryFiles { + if params.SkipAuxiliaryFiles { return godirwalk.SkipThis } @@ -286,7 +222,7 @@ func importFromGoProV2(root string, output string, sortoptions utils.SortOptions go func(folder, filename, osPathname string, bar *mpb.Bar) { defer wg.Done() - _ = parse(folder, filename, osPathname, sortoptions, result, bar) + _ = parse(folder, filename, osPathname, params.BufferSize, bar) }(folder, filename, lrvFullpath, proxyVideoBar) case Photo: additionalDir := "" @@ -296,10 +232,8 @@ func importFromGoProV2(root string, output string, sortoptions utils.SortOptions folder := filepath.Join(dayFolder, "photos", additionalDir) go func(folder, filename, osPathname string, bar *mpb.Bar) { defer wg.Done() - err := parse(folder, filename, osPathname, sortoptions, result, bar) + err := parse(folder, filename, osPathname, params.BufferSize, bar) if err != nil { - bar.EwmaSetCurrent(info.Size(), 1*time.Millisecond) - bar.EwmaIncrInt64(info.Size(), 1*time.Millisecond) inlineCounter.SetFailure(err, filename) } else { inlineCounter.SetSuccess() @@ -314,10 +248,8 @@ func importFromGoProV2(root string, output string, sortoptions utils.SortOptions folder := filepath.Join(dayFolder, "multishot", additionalDir, de.Name()[:4]) go func(folder, filename, osPathname string, bar *mpb.Bar) { defer wg.Done() - err := parse(folder, filename, osPathname, sortoptions, result, bar) + err := parse(folder, filename, osPathname, params.BufferSize, bar) if err != nil { - bar.EwmaSetCurrent(info.Size(), 1*time.Millisecond) - bar.EwmaIncrInt64(info.Size(), 1*time.Millisecond) inlineCounter.SetFailure(err, filename) } else { inlineCounter.SetSuccess() @@ -328,10 +260,8 @@ func importFromGoProV2(root string, output string, sortoptions utils.SortOptions folder := filepath.Join(dayFolder, "photos/raw") go func(folder, filename, osPathname string, bar *mpb.Bar) { defer wg.Done() - err := parse(folder, filename, osPathname, sortoptions, result, bar) + err := parse(folder, filename, osPathname, params.BufferSize, bar) if err != nil { - bar.EwmaSetCurrent(info.Size(), 1*time.Millisecond) - bar.EwmaIncrInt64(info.Size(), 1*time.Millisecond) inlineCounter.SetFailure(err, filename) } else { inlineCounter.SetSuccess() @@ -362,11 +292,11 @@ func importFromGoProV2(root string, output string, sortoptions utils.SortOptions return result } -func importFromGoProV1(root string, output string, sortoptions utils.SortOptions, cameraName string) utils.Result { +func importFromGoProV1(params utils.ImportParams) utils.Result { fileTypes := FileTypeMatches[V1] var result utils.Result - folders, err := ioutil.ReadDir(root) + folders, err := ioutil.ReadDir(params.Input) if err != nil { result.Errors = append(result.Errors, err) return result @@ -387,7 +317,7 @@ func importFromGoProV1(root string, output string, sortoptions utils.SortOptions } color.Green("Looking at %s", f.Name()) - err = godirwalk.Walk(filepath.Join(root, f.Name()), &godirwalk.Options{ + err = godirwalk.Walk(filepath.Join(params.Input, f.Name()), &godirwalk.Options{ Callback: func(osPathname string, de *godirwalk.Dirent) error { for _, ftype := range fileTypes { if !ftype.Regex.MatchString(de.Name()) { @@ -395,18 +325,10 @@ func importFromGoProV1(root string, output string, sortoptions utils.SortOptions } d := getFileTime(osPathname, true) + mediaDate := getMediaDate(d, params.DateFormat) - mediaDate := getMediaDate(d, sortoptions) - - if len(sortoptions.DateRange) == 2 { - start := sortoptions.DateRange[0] - end := sortoptions.DateRange[1] - if d.Before(start) { - return godirwalk.SkipThis - } - if d.After(end) { - return godirwalk.SkipThis - } + if d.Before(params.DateRange[0]) || d.After(params.DateRange[1]) { + return godirwalk.SkipThis } info, err := os.Stat(osPathname) @@ -417,7 +339,7 @@ func importFromGoProV1(root string, output string, sortoptions utils.SortOptions wg.Add(1) bar := utils.GetNewBar(progressBar, info.Size(), de.Name(), utils.IoTX) - dayFolder := utils.GetOrder(sortoptions, locationService, osPathname, output, mediaDate, cameraName) + dayFolder := utils.GetOrder(params.Sort, locationService, osPathname, params.Output, mediaDate, params.CameraName) switch ftype.Type { case Video: @@ -438,24 +360,22 @@ func importFromGoProV1(root string, output string, sortoptions utils.SortOptions additionalDir := "" if hilights, err := GetHiLights(osPathname); err == nil { if durationResp, err := ffprobe.Duration(osPathname); err == nil { - additionalDir = filepath.Join(additionalDir, getImportanceName(hilights.Timestamps, int(durationResp.Streams[0].Duration), sortoptions.TagNames)) + additionalDir = filepath.Join(additionalDir, getImportanceName(hilights.Timestamps, int(durationResp.Streams[0].Duration), params.TagNames)) } } folder := filepath.Join(dayFolder, "videos", additionalDir, rfpsFolder) go func(folder, filename, osPathname string, bar *mpb.Bar) { defer wg.Done() - err := parse(folder, filename, osPathname, sortoptions, result, bar) + err := parse(folder, filename, osPathname, params.BufferSize, bar) if err != nil { - bar.EwmaSetCurrent(info.Size(), 1*time.Millisecond) - bar.EwmaIncrInt64(info.Size(), 1*time.Millisecond) inlineCounter.SetFailure(err, filename) } else { inlineCounter.SetSuccess() } }(folder, x, osPathname, bar) - if sortoptions.SkipAuxiliaryFiles { + if params.SkipAuxiliaryFiles { return godirwalk.SkipThis } @@ -470,7 +390,7 @@ func importFromGoProV1(root string, output string, sortoptions utils.SortOptions go func(folder, filename, osPathname string, bar *mpb.Bar) { defer wg.Done() - _ = parse(folder, filename, osPathname, sortoptions, result, bar) + _ = parse(folder, filename, osPathname, params.BufferSize, bar) }(folder, x, lrvFullpath, proxyVideoBar) case ChapteredVideo: @@ -487,24 +407,22 @@ func importFromGoProV1(root string, output string, sortoptions utils.SortOptions additionalDir := "" if hilights, err := GetHiLights(osPathname); err == nil { if durationResp, err := ffprobe.Duration(osPathname); err == nil { - additionalDir = filepath.Join(additionalDir, getImportanceName(hilights.Timestamps, int(durationResp.Streams[0].Duration), sortoptions.TagNames)) + additionalDir = filepath.Join(additionalDir, getImportanceName(hilights.Timestamps, int(durationResp.Streams[0].Duration), params.TagNames)) } } folder := filepath.Join(dayFolder, "videos", additionalDir, rfpsFolder) go func(folder, filename, osPathname string, bar *mpb.Bar) { defer wg.Done() - err := parse(folder, filename, osPathname, sortoptions, result, bar) + err := parse(folder, filename, osPathname, params.BufferSize, bar) if err != nil { - bar.EwmaSetCurrent(info.Size(), 1*time.Millisecond) - bar.EwmaIncrInt64(info.Size(), 1*time.Millisecond) inlineCounter.SetFailure(err, filename) } else { inlineCounter.SetSuccess() } }(folder, name, osPathname, bar) - if sortoptions.SkipAuxiliaryFiles { + if params.SkipAuxiliaryFiles { return godirwalk.SkipThis } @@ -519,16 +437,14 @@ func importFromGoProV1(root string, output string, sortoptions utils.SortOptions go func(folder, filename, osPathname string, bar *mpb.Bar) { defer wg.Done() - _ = parse(folder, filename, osPathname, sortoptions, result, bar) + _ = parse(folder, filename, osPathname, params.BufferSize, bar) }(folder, x, lrvFullpath, proxyVideoBar) case Photo: folder := filepath.Join(dayFolder, "photos") go func(folder, filename, osPathname string, bar *mpb.Bar) { defer wg.Done() - err := parse(folder, filename, osPathname, sortoptions, result, bar) + err := parse(folder, filename, osPathname, params.BufferSize, bar) if err != nil { - bar.EwmaSetCurrent(info.Size(), 1*time.Millisecond) - bar.EwmaIncrInt64(info.Size(), 1*time.Millisecond) inlineCounter.SetFailure(err, filename) } else { inlineCounter.SetSuccess() @@ -536,16 +452,14 @@ func importFromGoProV1(root string, output string, sortoptions utils.SortOptions }(folder, de.Name(), osPathname, bar) case LowResolutionVideo: - if sortoptions.SkipAuxiliaryFiles { + if params.SkipAuxiliaryFiles { return godirwalk.SkipThis } folder := filepath.Join(dayFolder, "videos/proxy") go func(folder, filename, osPathname string, bar *mpb.Bar) { defer wg.Done() - err := parse(folder, filename, osPathname, sortoptions, result, bar) + err := parse(folder, filename, osPathname, params.BufferSize, bar) if err != nil { - bar.EwmaSetCurrent(info.Size(), 1*time.Millisecond) - bar.EwmaIncrInt64(info.Size(), 1*time.Millisecond) inlineCounter.SetFailure(err, filename) } else { inlineCounter.SetSuccess() @@ -556,10 +470,8 @@ func importFromGoProV1(root string, output string, sortoptions utils.SortOptions folder := filepath.Join(dayFolder, "multishot", de.Name()[:4]) go func(folder, filename, osPathname string, bar *mpb.Bar) { defer wg.Done() - err := parse(folder, filename, osPathname, sortoptions, result, bar) + err := parse(folder, filename, osPathname, params.BufferSize, bar) if err != nil { - bar.EwmaSetCurrent(info.Size(), 1*time.Millisecond) - bar.EwmaIncrInt64(info.Size(), 1*time.Millisecond) inlineCounter.SetFailure(err, filename) } else { inlineCounter.SetSuccess() @@ -570,10 +482,8 @@ func importFromGoProV1(root string, output string, sortoptions utils.SortOptions folder := filepath.Join(dayFolder, "photos/raw") go func(folder, filename, osPathname string, bar *mpb.Bar) { defer wg.Done() - err := parse(folder, filename, osPathname, sortoptions, result, bar) + err := parse(folder, filename, osPathname, params.BufferSize, bar) if err != nil { - bar.EwmaSetCurrent(info.Size(), 1*time.Millisecond) - bar.EwmaIncrInt64(info.Size(), 1*time.Millisecond) inlineCounter.SetFailure(err, filename) } else { inlineCounter.SetSuccess() @@ -643,21 +553,31 @@ func getFileTime(osPathname string, utcFix bool) time.Time { return d } -func getMediaDate(d time.Time, sortoptions utils.SortOptions) string { +func getMediaDate(d time.Time, dateFormat string) string { mediaDate := d.Format("02-01-2006") - if strings.Contains(sortoptions.DateFormat, "yyyy") && strings.Contains(sortoptions.DateFormat, "mm") && strings.Contains(sortoptions.DateFormat, "dd") { - mediaDate = d.Format(replacer.Replace(sortoptions.DateFormat)) + if strings.Contains(dateFormat, "yyyy") && strings.Contains(dateFormat, "mm") && strings.Contains(dateFormat, "dd") { + mediaDate = d.Format(utils.DateFormatReplacer.Replace(dateFormat)) } return mediaDate } -func parse(folder string, name string, osPathname string, sortoptions utils.SortOptions, result utils.Result, bar *mpb.Bar) error { +func parse(folder string, name string, osPathname string, bufferSize int, bar *mpb.Bar) error { if _, err := os.Stat(folder); os.IsNotExist(err) { - err = os.MkdirAll(folder, 0755) - if err != nil { - log.Fatal(err.Error()) + mkdirerr := os.MkdirAll(folder, 0o755) + if mkdirerr != nil { + return mkdirerr } } + sourceFileStat, err := os.Stat(osPathname) + if err != nil { + return err + } - return utils.CopyFile(osPathname, filepath.Join(folder, name), sortoptions.BufferSize, bar) + err = utils.CopyFile(osPathname, filepath.Join(folder, name), bufferSize, bar) + if err != nil { + bar.EwmaSetCurrent(sourceFileStat.Size(), 1*time.Millisecond) + bar.EwmaIncrInt64(sourceFileStat.Size(), 1*time.Millisecond) + return err + } + return nil } diff --git a/pkg/gopro/hilight_tags.go b/pkg/gopro/hilight_tags.go index cdeb7d2..26532ac 100644 --- a/pkg/gopro/hilight_tags.go +++ b/pkg/gopro/hilight_tags.go @@ -6,7 +6,7 @@ func getImportanceName(tags []int, videoDuration int, names []string) string { if videoDuration < 20 || len(names) < 3 { return "" } - var lastSeconds = 10 // Last 10 seconds + lastSeconds := 10 // Last 10 seconds rangeToFind := (videoDuration * int(time.Microsecond)) - lastSeconds*int(time.Microsecond) howMany := 0 diff --git a/pkg/gopro/location.go b/pkg/gopro/location.go index c11abae..f3dafec 100644 --- a/pkg/gopro/location.go +++ b/pkg/gopro/location.go @@ -24,6 +24,7 @@ func (LocationService) GetLocation(path string) (*utils.Location, error) { return nil, mErrors.ErrInvalidFile } } + func fromMP4(videoPath string) (*utils.Location, error) { vman := videomanipulation.New() data, err := vman.ExtractGPMF(videoPath) diff --git a/pkg/gopro/mp4parse.go b/pkg/gopro/mp4parse.go index b0bf8bc..050c51f 100644 --- a/pkg/gopro/mp4parse.go +++ b/pkg/gopro/mp4parse.go @@ -55,7 +55,8 @@ func GetHiLights(path string) (*HiLights, error) { if hmmtData != nil { return &HiLights{ hmmtData.Count, - hmmtData.Entries}, nil + hmmtData.Entries, + }, nil } return nil, errors.New("No data found") } diff --git a/pkg/gopro/update.go b/pkg/gopro/update.go index 408d9e1..28b17f6 100644 --- a/pkg/gopro/update.go +++ b/pkg/gopro/update.go @@ -17,17 +17,16 @@ import ( var FirmwareCatalogRemoteURL = "https://firmware-api.gopro.com/v2/firmware/catalog" func UpdateCamera(sdcard string) error { - client := &http.Client{} req, err := http.NewRequest("GET", FirmwareCatalogRemoteURL, nil) if err != nil { return err } - resp, err := client.Do(req) + resp, err := utils.Client.Do(req) if err != nil { return err } defer resp.Body.Close() - var response = &FirmwareCatalog{} + response := &FirmwareCatalog{} err = json.NewDecoder(resp.Body).Decode(response) if err != nil { return err diff --git a/pkg/insta360/insta360.go b/pkg/insta360/insta360.go index ecc4f97..ea54061 100644 --- a/pkg/insta360/insta360.go +++ b/pkg/insta360/insta360.go @@ -40,13 +40,14 @@ func getDeviceName(manifest string) string { } return fmt.Sprintf("Insta360%s", modelName[0]) } -func Import(in, out, dateFormat string, bufferSize int, prefix string, dateRange []string, cameraName string, cameraOptions map[string]interface{}) (*utils.Result, error) { - sortOptions := utils.ParseCliOptions(cameraOptions) - if cameraName == "" { - cameraName = getDeviceName(filepath.Join(in, "DCIM", "fileinfo_list.list")) +type Entrypoint struct{} + +func (Entrypoint) Import(params utils.ImportParams) (*utils.Result, error) { + if params.CameraName == "" { + params.CameraName = getDeviceName(filepath.Join(params.Input, "DCIM", "fileinfo_list.list")) } - di, err := disk.GetInfo(in) + di, err := disk.GetInfo(params.Input) if err != nil { return nil, err } @@ -61,7 +62,7 @@ func Import(in, out, dateFormat string, bufferSize int, prefix string, dateRange mediaFolder := `Camera\d+` mediaFolderRegex := regexp.MustCompile(mediaFolder) - root := filepath.Join(in, "DCIM") + root := filepath.Join(params.Input, "DCIM") var result utils.Result folders, err := ioutil.ReadDir(root) @@ -96,50 +97,16 @@ func Import(in, out, dateFormat string, bufferSize int, prefix string, dateRange } d := t.ModTime() - replacer := strings.NewReplacer("dd", "02", "mm", "01", "yyyy", "2006") mediaDate := d.Format("02-01-2006") - if strings.Contains(dateFormat, "yyyy") && strings.Contains(dateFormat, "mm") && strings.Contains(dateFormat, "dd") { - mediaDate = d.Format(replacer.Replace(dateFormat)) + if strings.Contains(params.DateFormat, "yyyy") && strings.Contains(params.DateFormat, "mm") && strings.Contains(params.DateFormat, "dd") { + mediaDate = d.Format(utils.DateFormatReplacer.Replace(params.DateFormat)) } // check if is in date range - if len(dateRange) == 2 { //nolint:nestif - layout := replacer.Replace(dateFormat) - - start, err1 := time.Parse(layout, dateRange[0]) - end, err2 := time.Parse(layout, dateRange[1]) - if err1 == nil && err2 == nil { - if d.Before(start) { - return godirwalk.SkipThis - } - if d.After(end) { - return godirwalk.SkipThis - } - } - } - - if len(dateRange) == 1 { //nolint:nestif - dateEnd := time.Now() - dateStart := dateEnd - switch dateRange[0] { - case "today": - dateStart = time.Date(dateEnd.Year(), dateEnd.Month(), dateEnd.Day(), 0, 0, 0, 0, dateEnd.Location()) - case "yesterday": - dateStart = time.Date(dateEnd.Year(), dateEnd.Month(), dateEnd.Day(), 0, 0, 0, 0, dateEnd.Location()).Add(-24 * time.Hour) - case "week": - dateStart = time.Date(dateEnd.Year(), dateEnd.Month(), dateEnd.Day(), 0, 0, 0, 0, dateEnd.Location()).Add(-24 * time.Duration((int(dateEnd.Weekday()) - 1)) * time.Hour) - } - - if dateStart != dateEnd { - if d.Before(dateStart) { - return godirwalk.SkipThis - } - if d.After(dateEnd) { - return godirwalk.SkipThis - } - } + if d.Before(params.DateRange[0]) || d.After(params.DateRange[1]) { + return godirwalk.SkipThis } info, err := os.Stat(osPathname) @@ -149,7 +116,7 @@ func Import(in, out, dateFormat string, bufferSize int, prefix string, dateRange wg.Add(1) bar := utils.GetNewBar(progressBar, info.Size(), de.Name(), utils.IoTX) - dayFolder := utils.GetOrder(sortOptions, nil, osPathname, out, mediaDate, cameraName) + dayFolder := utils.GetOrder(params.Sort, nil, osPathname, params.Output, mediaDate, params.CameraName) x := de.Name() @@ -157,16 +124,16 @@ func Import(in, out, dateFormat string, bufferSize int, prefix string, dateRange case Photo, RawPhoto: id := x[3+8+2 : 3+8+6+2] if _, err := os.Stat(filepath.Join(dayFolder, "photos", id)); os.IsNotExist(err) { - err = os.MkdirAll(filepath.Join(dayFolder, "photos", id), 0755) - if err != nil { - log.Fatal(err.Error()) + mkdirerr := os.MkdirAll(filepath.Join(dayFolder, "photos", id), 0o755) + if mkdirerr != nil { + log.Fatal(mkdirerr.Error()) } } go func(id, filename, osPathname string, bar *mpb.Bar) { defer wg.Done() - err = utils.CopyFile(osPathname, filepath.Join(dayFolder, "photos", id, x), bufferSize, bar) + err = utils.CopyFile(osPathname, filepath.Join(dayFolder, "photos", id, x), params.BufferSize, bar) if err != nil { bar.EwmaSetCurrent(info.Size(), 1*time.Millisecond) bar.EwmaIncrInt64(info.Size(), 1*time.Millisecond) @@ -176,7 +143,7 @@ func Import(in, out, dateFormat string, bufferSize int, prefix string, dateRange } }(id, x, osPathname, bar) case Video, LowResolutionVideo: - if sortOptions.SkipAuxiliaryFiles && ftype.Type == LowResolutionVideo { + if params.SkipAuxiliaryFiles && ftype.Type == LowResolutionVideo { wg.Done() bar.Abort(true) break @@ -195,16 +162,16 @@ func Import(in, out, dateFormat string, bufferSize int, prefix string, dateRange id = x[3+3+8+2+1 : 3+3+8+6+2+1] } if _, err := os.Stat(filepath.Join(dayFolder, slug, id)); os.IsNotExist(err) { - err = os.MkdirAll(filepath.Join(dayFolder, slug, id), 0755) - if err != nil { - log.Fatal(err.Error()) + mkdirerr := os.MkdirAll(filepath.Join(dayFolder, slug, id), 0o755) + if mkdirerr != nil { + log.Fatal(mkdirerr.Error()) } } go func(id, filename, osPathname string, bar *mpb.Bar) { defer wg.Done() - err = utils.CopyFile(osPathname, filepath.Join(dayFolder, slug, id, x), bufferSize, bar) + err = utils.CopyFile(osPathname, filepath.Join(dayFolder, slug, id, x), params.BufferSize, bar) if err != nil { bar.EwmaSetCurrent(info.Size(), 1*time.Millisecond) bar.EwmaIncrInt64(info.Size(), 1*time.Millisecond) diff --git a/pkg/insta360/update.go b/pkg/insta360/update.go index 373249b..b090975 100644 --- a/pkg/insta360/update.go +++ b/pkg/insta360/update.go @@ -15,8 +15,6 @@ import ( var FirmwareCatalogRemoteURL = "https://openapi.insta360.com/website/appDownload/getGroupApp?group=%s&X-Language=en-us" func UpdateCamera(sdcard string, model string) error { - client := &http.Client{} - camera, err := CameraGet("insta360-" + model) if err != nil { return err @@ -25,12 +23,12 @@ func UpdateCamera(sdcard string, model string) error { if err != nil { return err } - resp, err := client.Do(req) + resp, err := utils.Client.Do(req) if err != nil { return err } defer resp.Body.Close() - var response = &FirmwareDownloadList{} + response := &FirmwareDownloadList{} err = json.NewDecoder(resp.Body).Decode(response) if err != nil { return err diff --git a/pkg/utils/cameras.go b/pkg/utils/cameras.go index 9e47e9a..83c69ba 100644 --- a/pkg/utils/cameras.go +++ b/pkg/utils/cameras.go @@ -79,11 +79,6 @@ func CopyFile(src string, dst string, buffersize int, progressbar *mpb.Bar) erro if err != nil { return err } - - if !sourceFileStat.Mode().IsRegular() { - return fmt.Errorf("%s is not a regular file", src) - } - source, err := os.Open(src) if err != nil { return err @@ -226,14 +221,14 @@ func Unzip(src string, dest string) error { if f.FileInfo().IsDir() { // Make Folder - if err = os.MkdirAll(fpath, os.ModePerm); err != nil { + if err := os.MkdirAll(fpath, os.ModePerm); err != nil { return err } continue } // Make File - if err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm); err != nil { + if err := os.MkdirAll(filepath.Dir(fpath), os.ModePerm); err != nil { return err } @@ -267,33 +262,6 @@ func Unzip(src string, dest string) error { return nil } -func ParseCliOptions(cameraOptions map[string]interface{}) SortOptions { - byCamera := false - byLocation := false - skipAux := false - skipAuxOption, found := cameraOptions["skip_aux"] - if found { - skipAux = skipAuxOption.(bool) - } - sortByOptions, found := cameraOptions["sort_by"] - if found { - for _, sortop := range sortByOptions.([]string) { - if sortop == "camera" { - byCamera = true - } - if sortop == "location" { - byLocation = true - } - } - } - - return SortOptions{ - ByCamera: byCamera, - ByLocation: byLocation, - SkipAuxiliaryFiles: skipAux, - } -} - func FindFolderInPath(entirePath, directory string) (string, error) { modified := filepath.Dir(entirePath) if filepath.Base(modified) == directory { @@ -362,3 +330,5 @@ func GetNewBar(progressBar *mpb.Progress, total int64, filename string, barType ), ) } + +var DateFormatReplacer = strings.NewReplacer("dd", "02", "mm", "01", "yyyy", "2006") diff --git a/pkg/utils/client.go b/pkg/utils/client.go new file mode 100644 index 0000000..cc8f92b --- /dev/null +++ b/pkg/utils/client.go @@ -0,0 +1,18 @@ +package utils + +import ( + "net/http" + "time" + + "github.com/spf13/viper" +) + +func timeoutFromConfig() int { + key := "network_timeout" + viper.SetDefault(key, 10) + return viper.GetInt(key) +} + +var Client = &http.Client{ + Timeout: time.Duration(timeoutFromConfig()) * time.Second, +} diff --git a/pkg/utils/import.go b/pkg/utils/import.go new file mode 100644 index 0000000..dad1c0e --- /dev/null +++ b/pkg/utils/import.go @@ -0,0 +1,19 @@ +package utils + +import "time" + +type ImportParams struct { + Input, Output, CameraName string + SkipAuxiliaryFiles bool + DateFormat string + BufferSize int + Prefix string + DateRange []time.Time + TagNames []string + Connection ConnectionType + Sort SortOptions +} + +type Import interface { + Import(params ImportParams) (*Result, error) +} diff --git a/pkg/utils/ordering.go b/pkg/utils/ordering.go index bba1948..9865c58 100644 --- a/pkg/utils/ordering.go +++ b/pkg/utils/ordering.go @@ -3,7 +3,6 @@ package utils import ( "os" "path/filepath" - "time" ) type locationUtil interface { @@ -11,14 +10,8 @@ type locationUtil interface { } type SortOptions struct { - ByLocation bool - SkipAuxiliaryFiles bool - ByCamera bool - DateFormat string - BufferSize int - Prefix string - DateRange []time.Time - TagNames []string + ByLocation bool + ByCamera bool } func GetOrder(sortoptions SortOptions, GetLocation locationUtil, osPathname, out, mediaDate, deviceName string) string { @@ -31,9 +24,6 @@ func GetOrder(sortoptions SortOptions, GetLocation locationUtil, osPathname, out dayFolder = filepath.Join(dayFolder, mediaDate) case "camera": if sortoptions.ByCamera { - if sortoptions.Prefix != "" { - deviceName = sortoptions.Prefix + " " + deviceName - } dayFolder = filepath.Join(dayFolder, deviceName) } case "location": @@ -59,7 +49,7 @@ func GetOrder(sortoptions SortOptions, GetLocation locationUtil, osPathname, out } } if _, err := os.Stat(dayFolder); os.IsNotExist(err) { - _ = os.MkdirAll(dayFolder, 0755) + _ = os.MkdirAll(dayFolder, 0o755) } return dayFolder } diff --git a/pkg/utils/reversegeo.go b/pkg/utils/reversegeo.go index aa72787..12baff4 100644 --- a/pkg/utils/reversegeo.go +++ b/pkg/utils/reversegeo.go @@ -56,6 +56,12 @@ func (format2) format(address *geo.Address) string { return address.Country } +type format3 struct{} + +func (format3) format(address *geo.Address) string { + return address.FormattedAddress +} + func getPrettyAddress(format locationFormat, address *geo.Address) string { return cleanup(format.format(address)) } diff --git a/pkg/utils/reversegeo_test.go b/pkg/utils/reversegeo_test.go index 97e2225..94984a1 100644 --- a/pkg/utils/reversegeo_test.go +++ b/pkg/utils/reversegeo_test.go @@ -20,14 +20,14 @@ func TestPrettyAddress(t *testing.T) { Latitude: -39.6375091, Longitude: 175.2222849, }, - Result: []string{"Manawatū-Whanganui New Zealand _ Aotearoa", "New Zealand _ Aotearoa"}, + Result: []string{"Manawatū-Whanganui New Zealand_Aotearoa", "New Zealand_Aotearoa", "Whanganui District, Manawatū-Whanganui, New Zealand_Aotearoa"}, }, { Address: Location{ Latitude: 52.547567, Longitude: 13.385176, }, - Result: []string{"Berlin Deutschland", "Deutschland"}, + Result: []string{"Berlin Deutschland", "Deutschland", "Flakturm Humboldthain, Humboldtsteg, Gesundbrunnen, Mitte, Berlin, 13357, Deutschland"}, }, } @@ -42,6 +42,9 @@ func TestPrettyAddress(t *testing.T) { resp = getPrettyAddress(format2{}, address) require.Equal(t, value.Result[1], resp) + + resp = getPrettyAddress(format3{}, address) + require.Equal(t, value.Result[2], resp) }) } }