package main import ( "crypto/sha256" "encoding/base64" "image" "io/ioutil" "log" "net/http" "os" "path/filepath" "text/template" "time" "gocv.io/x/gocv" ) // StreamURL Unexported type StreamURL struct { URL string } // Stream Unexported type Stream struct { URL string base64 string streamDirPath string previousInstantPath string currentInstantPath string nextInstantPath string } // NewStream Unexported func NewStream(URL string) Stream { base64 := URLToBase64(URL) streamDirPath := filepath.Join(".", "streams", base64) return Stream{ URL: URL, base64: base64, streamDirPath: streamDirPath, // Maybe make these three functions ? previousInstantPath: filepath.Join(streamDirPath, "previous.jpg"), currentInstantPath: filepath.Join(streamDirPath, "current.jpg"), nextInstantPath: filepath.Join(streamDirPath, "next.jpg"), } } func index(w http.ResponseWriter, r *http.Request) { if r.FormValue("URL") == "" { indexTemplate, err := template.ParseFiles(filepath.Join("templates", "index.html")) if err != nil { log.Fatal(err) } indexTemplate.Execute(w, nil) return } streamURL := StreamURL{ URL: r.FormValue("URL"), } streamTemplate, err := template.ParseFiles(filepath.Join("templates", "stream.html")) if err != nil { log.Fatal(err) } streamTemplate.Execute(w, streamURL) } func stream(w http.ResponseWriter, r *http.Request) { if r.FormValue("URL") == "" { return } w.Header().Set("Content-Type", "image/jpeg") URL := r.FormValue("URL") img := getStreamInstant(URL) go saveStreamInstant(URL, img) streamDir := URLToBase64(URL) streamStoreDir := filepath.Join(".", "streams", string(streamDir)) previousStreamInstantPath := filepath.Join(streamStoreDir, "previous.jpg") if fileExists(previousStreamInstantPath) { newMat := gocv.NewMat() mat, err := gocv.IMDecode(img, gocv.IMReadColor) if err != nil { log.Fatal("Could not IMDecode img") } gocv.CvtColor(mat, &newMat, gocv.ColorBGRToGray) gocv.GaussianBlur(newMat, &newMat, image.Point{X: 21, Y: 21}, 0, 0, gocv.BorderReflect) previous := gocv.IMRead(previousStreamInstantPath, gocv.IMReadColor) gocv.CvtColor(previous, &previous, gocv.ColorBGRToGray) gocv.GaussianBlur(previous, &previous, image.Point{X: 21, Y: 21}, 0, 0, gocv.BorderReflect) gocv.AbsDiff(previous, newMat, &newMat) gocv.Threshold(newMat, &newMat, 25, 255, gocv.ThresholdBinary) img, err = gocv.IMEncode(".jpg", newMat) } w.Write(img) } func getStreamInstant(URL string) []byte { resp, err := http.Get(URL) if err != nil { log.Fatal(err) } img, err := ioutil.ReadAll(resp.Body) defer resp.Body.Close() return img } func saveStreamInstant(URL string, img []byte) { streamDir := URLToBase64(URL) streamStoreDir := filepath.Join(".", "streams", string(streamDir)) os.MkdirAll(streamStoreDir, os.ModePerm) currentStreamInstantPath := filepath.Join(streamStoreDir, "current.jpg") swap := fileExists(streamStoreDir) if swap { currentStreamInstantPath = filepath.Join(streamStoreDir, "next.jpg") } err := ioutil.WriteFile(currentStreamInstantPath, img, os.ModePerm) if err != nil { log.Fatal("Can't write latest stream instant.") } if swap { previousStreamInstantPath := filepath.Join(streamStoreDir, "previous.jpg") nextStreamInstantPath := currentStreamInstantPath currentStreamInstantPath = filepath.Join(streamStoreDir, "current.jpg") err = os.Rename(currentStreamInstantPath, previousStreamInstantPath) err = os.Rename(nextStreamInstantPath, currentStreamInstantPath) } } func listenAndServe() { staticFileServer := http.FileServer(http.Dir("./static")) http.Handle("/static/", http.StripPrefix("/static/", staticFileServer)) http.HandleFunc("/", index) http.HandleFunc("/stream", stream) log.Fatal(http.ListenAndServe(":8080", nil)) } func backend() { for { time.Sleep(time.Second) } } func main() { go listenAndServe() backend() } func fileExists(path string) bool { _, err := os.Stat(path) return !os.IsNotExist(err) } func URLToBase64(URL string) string { h := sha256.New() h.Write([]byte(URL)) return base64.URLEncoding.EncodeToString(h.Sum(nil)) }