Browse Source

working screen capture in /remote.html

main
Martin Dørum 10 months ago
parent
commit
0051b63a33
6 changed files with 162 additions and 3 deletions
  1. 1
    0
      go.mod
  2. 6
    0
      go.sum
  3. 43
    2
      main.go
  4. 88
    0
      screencap/screencap.go
  5. 1
    1
      web/files.html
  6. 23
    0
      web/remote.html

+ 1
- 0
go.mod View File

@@ -5,4 +5,5 @@ go 1.16
require (
github.com/BurntSushi/toml v0.4.1
github.com/go-vgo/robotgo v0.99.0
github.com/kbinani/screenshot v0.0.0-20210720154843-7d3a670d8329
)

+ 6
- 0
go.sum View File

@@ -7,10 +7,16 @@ github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46/go.mod h1:3eOhrU
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gen2brain/shm v0.0.0-20200228170931-49f9650110c5 h1:Y5Q2mEwfzjMt5+3u70Gtw93ZOu2UuPeeeTBDntF7FoY=
github.com/gen2brain/shm v0.0.0-20200228170931-49f9650110c5/go.mod h1:uF6rMu/1nvu+5DpiRLwusA6xB8zlkNoGzKn8lmYONUo=
github.com/go-ole/go-ole v1.2.5 h1:t4MGB5xEDZvXI+0rMjjsfBsD7yAgp/s9ZDkL1JndXwY=
github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-vgo/robotgo v0.99.0 h1:Lp6kvic1/LxkSShf6KNjcrcE21FCFlonrCguQN96Ay4=
github.com/go-vgo/robotgo v0.99.0/go.mod h1:0+i2QWRmZtbIF02RwmiGfFj33Judprukd8ls5J6Eajg=
github.com/jezek/xgb v0.0.0-20210312150743-0e0f116e1240 h1:dy+DS31tGEGCsZzB45HmJJNHjur8GDgtRNX9U7HnSX4=
github.com/jezek/xgb v0.0.0-20210312150743-0e0f116e1240/go.mod h1:3P4UH/k22rXyHIJD2w4h2XMqPX4Of/eySEZq9L6wqc4=
github.com/kbinani/screenshot v0.0.0-20210720154843-7d3a670d8329 h1:qq2nCpSrXrmvDGRxW0ruW9BVEV1CN2a9YDOExdt+U0o=
github.com/kbinani/screenshot v0.0.0-20210720154843-7d3a670d8329/go.mod h1:2VPVQDR4wO7KXHwP+DAypEy67rXf+okUx2zjgpCxZw4=
github.com/lxn/win v0.0.0-20210218163916-a377121e959e h1:H+t6A/QJMbhCSEH5rAuRxh+CtW96g0Or0Fxa9IKr4uc=
github.com/lxn/win v0.0.0-20210218163916-a377121e959e/go.mod h1:KxxjdtRkfNoYDCUP5ryK7XJJNTnpC8atvtmTheChOtk=
github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=

+ 43
- 2
main.go View File

@@ -3,12 +3,14 @@ package main
import "errors"
import "log"
import "os"
import "fmt"
import "path"
import "net/http"
import "io/ioutil"
import "encoding/json"
import "github.com/go-vgo/robotgo"
import "github.com/BurntSushi/toml"
import "coffee.mort.mediator/screencap"

type Config struct {
BasePath string `toml:"base_path"`
@@ -81,7 +83,7 @@ func main() {
fs := http.FileServer(http.Dir("./web"))
http.Handle("/", fs)

http.HandleFunc("/api/screen-size", handler(func(w RW, req *Req) error {
http.HandleFunc("/api/remote/screen-size", handler(func(w RW, req *Req) error {
if req.Method == "GET" {
var size ScreenSizeData
size.Width, size.Height = robotgo.GetScreenSize()
@@ -91,7 +93,7 @@ func main() {
}
}))

http.HandleFunc("/api/mouse-pos", handler(func(w RW, req *Req) error {
http.HandleFunc("/api/remote/mouse-pos", handler(func(w RW, req *Req) error {
if req.Method == "GET" {
var pos MousePosData
pos.X, pos.Y = robotgo.GetMousePos()
@@ -110,6 +112,43 @@ func main() {
}
}))

http.HandleFunc("/api/remote/screencast", handler(func(w RW, req *Req) error {
if req.Method == "GET" {
w.Header().Add("Content-Type", "multipart/x-mixed-replace;boundary=MEDIATOR_FRAME_BOUNDARY")
w.WriteHeader(200)

for {
img := <-screencap.Capture()
log.Printf("Got image, %v bytes", img.Length)

var err error
_, err = w.Write([]byte(fmt.Sprintf(
"--MEDIATOR_FRAME_BOUNDARY\r\n" +
"Content-Type: image/jpeg\r\n" +
"Content-Length: %d\r\n" +
"\r\n", img.Length)))
if err != nil {
log.Printf("Write error: %v", err)
return nil
}

_, err = w.Write(img.Data[0:img.Length])
if err != nil {
log.Printf("Write error: %v", err)
return nil
}

_, err = w.Write([]byte("\r\n"))
if err != nil {
log.Printf("Write error: %v", err)
return nil
}
}
} else {
return errors.New("Invalid method: " + req.Method)
}
}));

http.HandleFunc("/api/dir/", handler(func(w RW, req *Req) error {
if req.Method == "GET" {
subPath := req.URL.Path[len("/api/dir/"):]
@@ -140,6 +179,8 @@ func main() {
}
}))

go screencap.Run()

log.Println("Listening on :3000...")
err = http.ListenAndServe("localhost:3000", nil)
if err != nil {

+ 88
- 0
screencap/screencap.go View File

@@ -0,0 +1,88 @@
package screencap

import "github.com/kbinani/screenshot"
import "image/jpeg"
import "sync"
import "time"
import "log"

type Buffer struct {
Data []byte
Length int
}

func (buf *Buffer) Write(data []byte) (int, error) {
if len(buf.Data) == 0 {
l := len(data)
if l < 1024 {
l = 2024
}
buf.Data = make([]byte, l)
} else if buf.Length + len(data) > len(buf.Data) {
newSize := len(buf.Data) * 2
for buf.Length + len(data) > newSize {
newSize *= 2
}

newBuf := make([]byte, newSize)
copy(newBuf, buf.Data[0:buf.Length])
buf.Data = newBuf
}

copy(buf.Data[buf.Length:], data)
buf.Length += len(data)
return len(data), nil
}

var (
mut = sync.Mutex{}
chans = make([]chan *Buffer, 0)
startChan = make(chan struct{}, 1)

buffers = make([]Buffer, 4)
currentBuffer = 0
)

func Capture() chan *Buffer {
ch := make(chan *Buffer)
mut.Lock()
chans = append(chans, ch)
mut.Unlock()

select {
case startChan <- struct{}{}:
default:
}

return ch
}

func Run() {
for {
<-startChan

img, err := screenshot.CaptureDisplay(0)
if err != nil {
log.Printf("Failed to capture screenshot: %v", err)
time.Sleep(2 * time.Second)
continue
}

buf := &buffers[currentBuffer]
currentBuffer = (currentBuffer + 1) % len(buffers)
buf.Length = 0
err = jpeg.Encode(buf, img, &jpeg.Options{Quality: 80})
if err != nil {
log.Printf("Failed to encode jpeg: %v", err)
time.Sleep(2 * time.Second)
continue
}

mut.Lock()
for _, ch := range chans {
ch <- buf
}
chans = make([]chan *Buffer, 0)
mut.Unlock()
}
}

+ 1
- 1
web/files.html View File

@@ -2,7 +2,7 @@
<html>
<head>
<meta charset="utf-8">
<title>Mediator</title>
<title>Mediator - Files</title>
<link rel="stylesheet" href="style.css">
<link rel="icon" type="image/png" href="favicon.png">


+ 23
- 0
web/remote.html View File

@@ -0,0 +1,23 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Mediator - Remote</title>
<link rel="stylesheet" href="style.css">
<link rel="icon" type="image/png" href="favicon.png">
</head>

<body>
<img src="/api/remote/screencast">

<script src="util.js"></script>
<script>
async function main() {
let screenSize = api("GET", "remote/screen-size");
let mousePos = api("GET", "remote/mouse-pos");
}

main();
</script>
</body>
</html>

Loading…
Cancel
Save