diff --git a/cmd/info.go b/cmd/info.go new file mode 100644 index 0000000..b5512fe --- /dev/null +++ b/cmd/info.go @@ -0,0 +1,100 @@ +package cmd + +import ( + "fmt" + + "github.com/erdaltsksn/cui" + "github.com/konradit/mmt/pkg/gopro" + "github.com/konradit/mmt/pkg/utils" + "github.com/spf13/cobra" +) + +var infoCmd = &cobra.Command{ + Use: "info", + Run: func(cmd *cobra.Command, args []string) { + input := getFlagString(cmd, "input") + camera := getFlagString(cmd, "camera") + customCameraOpts := make(map[string]interface{}) + 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) + camera = "gopro" + } + if camera != "" && input != "" { + c, err := utils.CameraGet(camera) + if err != nil { + cui.Error("Something went wrong", err) + } + switch c { + case utils.GoPro: + if customCameraOpts["connection"] == "" { + connection := getFlagString(cmd, "connection") + if connection == "" { + connection = "sd_card" + } + customCameraOpts["connection"] = connection + } + switch customCameraOpts["connection"] { + case "connect": + printGpStatus(input) + default: + gopro.GetFileInfo(input) + } + } + } + }, +} + +func printGpStatus(input string) { + var gpStatus = gopro.CameraStatus{} + gpStatus, _ = gopro.GetInfo(input) + fmt.Printf("SSID : %s\n", gpStatus.Status.WiFiSSID) + currentMode := gpStatus.Status.CurrentMode + var modeName = "Video" + var whiteBal = gpStatus.Settings.Num11 + var isoMode = gpStatus.Settings.Num74 + var isoLimit = gpStatus.Settings.Num13 + var isoMin = 0 + var proTune = gpStatus.Settings.Num10 + switch currentMode { + case 1: + modeName = "Photo" + whiteBal = gpStatus.Settings.Num22 + isoMin = gpStatus.Settings.Num75 + isoLimit = gpStatus.Settings.Num24 + proTune = gpStatus.Settings.Num21 + case 2: + modeName = "MultiShot" + whiteBal = gpStatus.Settings.Num35 + isoMin = gpStatus.Settings.Num76 + isoLimit = gpStatus.Settings.Num37 + proTune = gpStatus.Settings.Num34 + } + fmt.Printf("Mode : %s\n", modeName) + fmt.Printf("White Balance : %s\n", gopro.GetWhiteBalance(whiteBal)) + if currentMode == 0 { + fmt.Printf("Resolution : %s\n", gopro.GetVidRes(gpStatus.Settings.VideoResolutions)) + var isoText = "" + if isoMode == 1 { + isoText = "Lock" + } else { + isoText = "Max" + } + fmt.Printf("ISO Mode : %s\n", isoText) + } else { + fmt.Printf("ISO Min : %d\n", gopro.GetISO(isoMin)) + } + fmt.Printf("ISO Limit : %d\n", gopro.GetISO(isoLimit)) + fmt.Printf("Protune : %t\n", proTune != 0) +} + +func init() { + rootCmd.AddCommand(infoCmd) + infoCmd.Flags().StringP("input", "i", "", "Input IP Address") + infoCmd.Flags().StringP("camera", "c", "", "Camera type") + infoCmd.Flags().StringP("connection", "x", "", "Connexion type: `sd_card`, `connect` (GoPro-specific)") +} diff --git a/pkg/gopro/info.go b/pkg/gopro/info.go new file mode 100644 index 0000000..4453614 --- /dev/null +++ b/pkg/gopro/info.go @@ -0,0 +1,96 @@ +package gopro + +/* GoPro Connect - API exposed over USB Ethernet */ + +import ( + "fmt" + + "github.com/konradit/mmt/pkg/utils" +) + +func GetInfo(in string) (CameraStatus, error) { + var gpStatus = &CameraStatus{} + err := caller(in, "gp/gpControl/status", gpStatus) + if err != nil { + return *gpStatus, err + } + return *gpStatus, nil +} + +func GetISO(in int) int { + switch in { + case 0: + return 800 + case 1: + return 400 + case 2: + return 200 + case 3: + return 100 + default: + return 0 + } +} + +func GetVidRes(in int) string { + switch in { + case 1: + return "4K" + case 2: + return "4K SuperView" + case 4: + return "2.7K" + case 5: + return "2.7K SuperView" + case 6: + return "2.7K 4:3" + case 7: + return "1440" + case 8: + return "1080 SuperView" + case 9: + return "1080" + case 10: + return "960" + case 11: + return "720 SuperView" + case 12: + return "720" + case 13: + return "WVGA" + default: + return "" + } +} + +func GetWhiteBalance(in int) string { + switch in { + case 0: + return "Auto" + case 1: + return "3000K" + case 5: + return "4000K" + case 6: + return "4800K" + case 2: + return "5500K" + case 7: + return "6000K" + case 3: + return "6500K" + case 4: + return "Native" + default: + return "" + } +} + +func GetFileInfo(in string) (*utils.Result, error) { + var result utils.Result + returned, err := fromMP4(in) + if returned != nil { + fmt.Printf("\n\treturned: %f %f\n", returned.Latitude, returned.Longitude) + } + return &result, err +} diff --git a/pkg/gopro/structs.go b/pkg/gopro/structs.go index d762520..fa6d413 100644 --- a/pkg/gopro/structs.go +++ b/pkg/gopro/structs.go @@ -143,3 +143,314 @@ type goProMediaMetadata struct { Prog string `json:"prog"` Subsample string `json:"subsample"` } +//CameraStatus current status and settings of the camera +type CameraStatus struct { + Status CurrentStatus `json:"status"` + Settings CurrentSettings `json:"settings"` +} + +// CurrentStatus ... +type CurrentStatus struct { + // 1 - Internal Battery is available: + // 0 = No Battery + // 1 = Battery is available + InternalBattery int `json:"1"` + + // 2 - Internal Battery Level: + // 4 = Charging + // 3 = Full + // 2 = Halfway + // 1 = Low + // 0 = Empty + InternalBatteryLevel int `json:"2"` + + Num3 int `json:"3"` + Num4 int `json:"4"` + Num6 int `json:"6"` + Num8 int `json:"8"` + Num9 int `json:"9"` + Num10 int `json:"10"` + Num11 int `json:"11"` + + // 13 - Current Recording Video Duration + CurrentRecordingVideoDuration int `json:"13"` + + Num14 int `json:"14"` + Num15 int `json:"15"` + Num16 int `json:"16"` + Num17 int `json:"17"` + Num19 int `json:"19"` + Num20 int `json:"20"` + Num21 int `json:"21"` + Num22 int `json:"22"` + Num23 int `json:"23"` + Num24 int `json:"24"` + Num26 int `json:"26"` + Num27 int `json:"27"` + Num28 int `json:"28"` + Num29 string `json:"29"` + + // 30 - WiFi SSID + WiFiSSID string `json:"30"` + + // 31 - Number of clients connected to the camera + NumberOfClients int `json:"31"` + + // 32 - Streaming feed status: + // 0 = Not Streaming + // 1 = Streaming + StreamingFeed int `json:"32"` + + // 33 - SD card inserted: + // 0 = SD card inserted + // 2 = No SD Card present + SDcardInserted int `json:"33"` + + // 34 - Remaining Photos + RemainingPhotos int `json:"34"` + + // 35 - Remaining Video Time + RemainingVideoTime int `json:"35"` + + // 36 - Number of Batch Photos taken (Example: TimeLapse batches, burst batches, continouous photo batches...) + NumberOfBatchPhotos int `json:"36"` + + // 37 - Number of videos shot + NumberOfVideos int `json:"37"` + + // 38 - Number of ALL photos taken + Num38 int `json:"38"` + + // 39 - Number of MultiShot pictures taken + // 39 - Number of ALL videos taken + // 8 = Recording/Processing status: + // 0 = Not recording/Processing + // 1 = Recording/processing + Num39 int `json:"39"` + Num40 string `json:"40"` + Num41 int `json:"41"` + Num42 int `json:"42"` + + // 43 - Current Mode: + // Video - 0 + // Photo - 1 + // MultiShot - 2 + CurrentMode int `json:"43"` + + // 44 - Current SubMode + // 0 = Video/Single Pic/Burst + // 1 = TL Video/Continuous/TimeLapse + // 2 = Video+Photo/NightPhoto/NightLapse + CurrentSubMode int `json:"44"` + + Num45 int `json:"45"` + Num46 int `json:"46"` + Num47 int `json:"47"` + Num48 int `json:"48"` + Num49 int `json:"49"` + + // 54 - Remaning free space on memorycard in bytes + RemaningFreeSpace int `json:"54"` + + Num55 int `json:"55"` + Num56 int `json:"56"` + Num57 int `json:"57"` + Num58 int `json:"58"` + Num59 int `json:"59"` + Num60 int `json:"60"` + Num61 int `json:"61"` + Num62 int `json:"62"` + Num63 int `json:"63"` + Num64 int `json:"64"` + Num65 int `json:"65"` + Num66 int `json:"66"` + Num67 int `json:"67"` + Num68 int `json:"68"` + Num69 int `json:"69"` + + // 70 - Battery Percentage + BatteryPercentage int `json:"70"` + + Num71 int `json:"71"` + Num72 int `json:"72"` + Num73 int `json:"73"` + Num74 int `json:"74"` +} + +// CurrentSettings ... +type CurrentSettings struct { + Num1 int `json:"1"` + + // 2 - Video Resolutions + // 1 = 4K + // 4 = 2.7K: http://10.5.5.9/gp/gpControl/setting/2/4 + // 6 = 2.7K 4:3: http://10.5.5.9/gp/gpControl/setting/2/6 + // 7 = 1440p: http://10.5.5.9/gp/gpControl/setting/2/7 + // 9 = 1080p: http://10.5.5.9/gp/gpControl/setting/2/9 + // 10 = 960p: http://10.5.5.9/gp/gpControl/setting/2/10 + // 12 = 720p: http://10.5.5.9/gp/gpControl/setting/2/12 + // 17 = WVGA: http://10.5.5.9/gp/gpControl/setting/2/17 + VideoResolutions int `json:"2"` + + // 3 - Frame Rate + // 0 = 240fps: http://10.5.5.9/gp/gpControl/setting/3/0 + // 1 = 120fps: http://10.5.5.9/gp/gpControl/setting/3/1 + // 2 = 100fps: http://10.5.5.9/gp/gpControl/setting/3/2 + // 3 = 90fps: http://10.5.5.9/gp/gpControl/setting/3/3 + // 4 = 80fps: http://10.5.5.9/gp/gpControl/setting/3/4 + // 5 = 60fps: http://10.5.5.9/gp/gpControl/setting/3/5 + // 6 = 50fps: http://10.5.5.9/gp/gpControl/setting/3/6 + // 7 = 48fps: http://10.5.5.9/gp/gpControl/setting/3/7 + // 8 = 30fps: http://10.5.5.9/gp/gpControl/setting/3/8 + // 9 = 25fps: http://10.5.5.9/gp/gpControl/setting/3/9 + FrameRate int `json:"3"` + + // 4 - Field of View + // 0 = Wide: http://10.5.5.9/gp/gpControl/setting/4/0 + // 1 = Medium: http://10.5.5.9/gp/gpControl/setting/4/1 + // 2 = Narrow: http://10.5.5.9/gp/gpControl/setting/4/2 + // 3 = SuperView: http://10.5.5.9/gp/gpControl/4/3 + // 4 = Linear: http://10.5.5.9/gp/gpControl/setting/4/4 + FOV int `json:"4"` + + // 5 - Video Timelapse Interval: + // 0 = 0.5: http://10.5.5.9/gp/gpControl/setting/5/0 + // 1 = 1: http://10.5.5.9/gp/gpControl/setting/5/1 + // 2 = 2: http://10.5.5.9/gp/gpControl/setting/5/2 + // 3 = 5: http://10.5.5.9/gp/gpControl/setting/5/3 + // 4 = 10: http://10.5.5.9/gp/gpControl/setting/5/4 + // 5 = 30: http://10.5.5.9/gp/gpControl/setting/5/5 + // 6 = 60: http://10.5.5.9/gp/gpControl/setting/5/6 + VideoTimelapseInterval int `json:"5"` + + // 6 - Video Looping Duration: + // 0 = Max: http://10.5.5.9/gp/gpControl/setting/6/0 + // 1 = 5Min: http://10.5.5.9/gp/gpControl/setting/6/1 + // 2 = 20Min: http://10.5.5.9/gp/gpControl/setting/6/2 + // 3 = 60Min: http://10.5.5.9/gp/gpControl/setting/6/3 + // 4 = 120Min: http://10.5.5.9/gp/gpControl/setting/6/4 + VideoLoopingDuration int `json:"6"` + + // 7 - Video+Photo Interval: + // 1 = 5: http://10.5.5.9/gp/gpControl/setting/7/1 + // 2 = 10: http://10.5.5.9/gp/gpControl/setting/7/2 + // 3 = 30: http://10.5.5.9/gp/gpControl/setting/7/3 + // 4 = 60Min: http://10.5.5.9/gp/gpControl/setting/7/4 + VideoPhotoInterval int `json:"7"` + + // 8 - Low Light + // 0 = OFF: http://10.5.5.9/gp/gpControl/setting/8/0 + // 1 = ON: http://10.5.5.9/gp/gpControl/setting/8/1 + LowLight int `json:"8"` + + // 9 - Spot Meter: + // 0 = off: http://10.5.5.9/gp/gpControl/setting/9/0 + // 1 = on: http://10.5.5.9/gp/gpControl/setting/9/1 + SpotMeter int `json:"9"` + + // https://github.com/KonradIT/goprowifihack/blob/master/HERO5/HERO5-Commands.md + Num10 int `json:"10"` + Num11 int `json:"11"` + Num12 int `json:"12"` + Num13 int `json:"13"` + Num14 int `json:"14"` + Num15 int `json:"15"` + Num16 int `json:"16"` + Num17 int `json:"17"` + Num18 int `json:"18"` + Num19 int `json:"19"` + Num20 int `json:"20"` + Num21 int `json:"21"` + Num22 int `json:"22"` + Num23 int `json:"23"` + Num24 int `json:"24"` + Num25 int `json:"25"` + Num26 int `json:"26"` + Num27 int `json:"27"` + Num28 int `json:"28"` + Num29 int `json:"29"` + Num30 int `json:"30"` + Num31 int `json:"31"` + Num32 int `json:"32"` + Num33 int `json:"33"` + Num34 int `json:"34"` + Num35 int `json:"35"` + Num36 int `json:"36"` + Num37 int `json:"37"` + Num38 int `json:"38"` + Num39 int `json:"39"` + Num40 int `json:"40"` + Num41 int `json:"41"` + Num42 int `json:"42"` + + // 43 - Primary modes + // 0 = Video: http://10.5.5.9/gp/gpControl/command/mode?p=0 + // 1 = Photo: http://10.5.5.9/gp/gpControl/command/mode?p=1 + // 2 = MultiShot: http://10.5.5.9/gp/gpControl/command/mode?p=2 + PrimaryMode int `json:"43"` + + // 44 - Secondary modes + // 0 = Video (VIDEO): http://10.5.5.9/gp/gpControl/command/sub_mode?mode=0&sub_mode=0 + // 1 = TimeLapse Video (VIDEO): http://10.5.5.9/gp/gpControl/command/sub_mode?mode=0&sub_mode=1 + // 2 = Video + Photo (VIDEO): http://10.5.5.9/gp/gpControl/command/sub_mode?mode=0&sub_mode=2 + // 3 = Looping (VIDEO): http://10.5.5.9/gp/gpControl/command/sub_mode?mode=0&sub_mode=3 + + // 1 = Single (PHOTO): http://10.5.5.9/gp/gpControl/command/sub_mode?mode=1&sub_mode=1 + // 2 = Night (PHOTO): http://10.5.5.9/gp/gpControl/command/sub_mode?mode=1&sub_mode=2 + + // 0 = Burst (MultiShot): http://10.5.5.9/gp/gpControl/command/sub_mode?mode=2&sub_mode=0 + // 1 = Timelapse (MultiShot): http://10.5.5.9/gp/gpControl/command/sub_mode?mode=2&sub_mode=1 + // 2 = NightLapse (MultiShot): http://10.5.5.9/gp/gpControl/command/sub_mode?mode=2&sub_mode=2 + SecondaryModes int `json:"44"` + + Num45 int `json:"45"` + Num46 int `json:"46"` + Num47 int `json:"47"` + Num48 int `json:"48"` + Num50 int `json:"50"` + Num51 int `json:"51"` + Num52 int `json:"52"` + Num54 int `json:"54"` + Num57 int `json:"57"` + Num58 int `json:"58"` + Num59 int `json:"59"` + Num60 int `json:"60"` + Num61 int `json:"61"` + Num62 int `json:"62"` + Num63 int `json:"63"` + Num64 int `json:"64"` + Num65 int `json:"65"` + Num66 int `json:"66"` + Num67 int `json:"67"` + Num68 int `json:"68"` + Num69 int `json:"69"` + Num70 int `json:"70"` + Num71 int `json:"71"` + Num72 int `json:"72"` + Num73 int `json:"73"` + Num74 int `json:"74"` + Num75 int `json:"75"` + Num76 int `json:"76"` + Num77 int `json:"77"` + Num78 int `json:"78"` + Num79 int `json:"79"` + Num80 int `json:"80"` + Num81 int `json:"81"` + Num82 int `json:"82"` + Num83 int `json:"83"` + Num84 int `json:"84"` + Num85 int `json:"85"` + Num86 int `json:"86"` + Num87 int `json:"87"` + Num88 int `json:"88"` + Num89 int `json:"89"` + Num91 int `json:"91"` + Num92 int `json:"92"` + Num93 int `json:"93"` + Num94 int `json:"94"` + Num95 int `json:"95"` + Num96 int `json:"96"` + Num97 int `json:"97"` + Num98 int `json:"98"` + Num99 int `json:"99"` +}