Files
plugin-record/restful.go
eanfs df6486a022 Eanfs v4 (#41)
* [feature] 支持录制完成后上传到Minio

* change module id

* Update mod name

* reset go.mod

* Update for minio uploading

* Update for log

* [feature] support all Recorder

* Update

* Merge branch 'v4' into githubv4

* v4:
  git commit for minio

* fix error

* Update

* Update

* Update for support max Duration

* Update v4.6.5

* Update for chang Config name

* [refactor] update for recording duration

* Update for remove orgion file

* Update mod

* Update

* fix: close mp4 record error

* Update readme

* Fix file not upload Successfully

* feat(recording): 支持录制检查回调

* feat:增加数据库录制检查

* Update 录制文件没有写入结束标志

* 更新依赖包

* fix(record): 自动删除的录像文件。

* Update for sqllite to db error
2025-06-20 16:33:44 +08:00

320 lines
8.4 KiB
Go

package record
import (
"encoding/json"
"net/http"
"os"
"path/filepath"
"strconv"
"strings"
"time"
"go.uber.org/zap"
. "m7s.live/engine/v4"
"m7s.live/engine/v4/util"
)
func (conf *RecordConfig) API_list(w http.ResponseWriter, r *http.Request) {
query := r.URL.Query()
t := query.Get("type")
var files []*VideoFileInfo
var err error
recorder := conf.getRecorderConfigByType(t)
if recorder == nil {
for _, t = range []string{"flv", "mp4", "fmp4", "hls", "raw", "raw_audio"} {
recorder = conf.getRecorderConfigByType(t)
var fs []*VideoFileInfo
if fs, err = recorder.Tree(recorder.Path, 0); err == nil {
files = append(files, fs...)
}
}
} else {
files, err = recorder.Tree(recorder.Path, 0)
}
if err == nil {
var bytes []byte
if bytes, err = json.Marshal(files); err == nil {
w.Write(bytes)
}
}
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
func (conf *RecordConfig) API_start(w http.ResponseWriter, r *http.Request) {
query := r.URL.Query()
streamPath := query.Get("streamPath")
fileName := query.Get("fileName")
fragment := query.Get("fragment")
if streamPath == "" {
http.Error(w, "no streamPath", http.StatusBadRequest)
return
}
t := query.Get("type")
duration := query.Get("duration")
var id string
var err error
var irecorder IRecorder
switch t {
case "":
t = "flv"
fallthrough
case "flv":
irecorder = NewFLVRecorder(OrdinaryMode)
case "mp4":
irecorder = NewMP4Recorder()
case "fmp4":
irecorder = NewFMP4Recorder()
case "hls":
irecorder = NewHLSRecorder()
case "raw":
irecorder = NewRawRecorder()
case "raw_audio":
irecorder = NewRawAudioRecorder()
default:
http.Error(w, "type not supported", http.StatusBadRequest)
return
}
recorder := irecorder.GetRecorder()
if fragment != "" {
if f, err := time.ParseDuration(fragment); err == nil {
recorder.Fragment = f
}
}
recorder.FileName = fileName
recorder.append = query.Get("append") != ""
if fileName != "" {
err = irecorder.StartWithFileName(streamPath, fileName)
} else {
err = irecorder.Start(streamPath)
}
id = recorder.ID
if err != nil {
util.ReturnError(util.APIErrorInternal, err.Error(), w, r)
return
}
// 设置录制时长限制
if duration != "" {
if d, err := time.ParseDuration(duration); err == nil {
recorder.Duration = d
}
}
util.ReturnError(util.APIErrorNone, id, w, r)
}
func (conf *RecordConfig) API_list_recording(w http.ResponseWriter, r *http.Request) {
util.ReturnFetchValue(func() (recordings []any) {
conf.recordings.Range(func(key, value any) bool {
recordings = append(recordings, value)
return true
})
return
}, w, r)
}
func (conf *RecordConfig) API_stop(w http.ResponseWriter, r *http.Request) {
id := r.URL.Query().Get("id")
if recorder, ok := conf.recordings.Load(id); ok {
recorder.(ISubscriber).Stop(zap.String("reason", "api"))
util.ReturnOK(w, r)
return
}
util.ReturnError(util.APIErrorNotFound, "no such recorder", w, r)
}
func (conf *RecordConfig) API_recordfile_delete(w http.ResponseWriter, r *http.Request) {
query := r.URL.Query()
path := query.Get("path")
err := os.Remove(path)
if err != nil {
plugin.Error("修改文件时出错", zap.Error(err))
util.ReturnError(1, "删除文件时出错", w, r)
return
}
util.ReturnOK(w, r)
}
func (conf *RecordConfig) API_recordfile_modify(w http.ResponseWriter, r *http.Request) {
query := r.URL.Query()
path := query.Get("path")
newName := query.Get("newName")
dirPath := filepath.Dir(path)
err := os.Rename(path, dirPath+"/"+newName)
if err != nil {
plugin.Error("修改文件时出错", zap.Error(err))
util.ReturnError(1, "修改文件时出错", w, r)
return
}
util.ReturnOK(w, r)
}
func (conf *RecordConfig) API_list_page(w http.ResponseWriter, r *http.Request) {
query := r.URL.Query()
t := query.Get("type")
pageSize := query.Get("pageSize")
pageNum := query.Get("pageNum")
streamPath := query.Get("streamPath") //搜索条件
var files []*VideoFileInfo
var outFiles []*VideoFileInfo
var err error
var totalPageCount int = 1
recorder := conf.getRecorderConfigByType(t)
if recorder == nil {
for _, t = range []string{"flv", "mp4", "fmp4", "hls", "raw", "raw_audio"} {
recorder = conf.getRecorderConfigByType(t)
var fs []*VideoFileInfo
if fs, err = recorder.Tree(recorder.Path, 0); err == nil {
files = append(files, fs...)
}
}
} else {
files, err = recorder.Tree(recorder.Path, 0)
}
if streamPath != "" {
for _, file := range files {
if strings.Contains(file.Path, streamPath) {
outFiles = append(outFiles, file)
}
}
} else {
outFiles = files
}
totalCount := len(outFiles) //总条数
if pageSize != "" && pageNum != "" {
pageSizeInt, err := strconv.Atoi(pageSize)
if err != nil {
http.Error(w, "pageSize parameter error", http.StatusBadRequest)
return
}
pageNumInt, err := strconv.Atoi(pageNum)
if err != nil {
http.Error(w, "pageNum parameter error", http.StatusBadRequest)
return
}
if pageSizeInt > 0 {
if pageNumInt > 0 {
totalPageCount = (totalCount / pageSizeInt) + 1 //总页数
remainCount := totalCount % pageSizeInt //分页后剩余条数
if remainCount == 0 && totalPageCount != 1 {
totalPageCount = totalCount / pageSizeInt
}
if pageNumInt > totalPageCount {
http.Error(w, "pageSize parameter error", http.StatusBadRequest)
return
}
startIndex := (pageNumInt - 1) * pageSizeInt //开始索引
endIndex := startIndex + pageSizeInt
if endIndex > totalCount {
endIndex = totalCount
}
outFiles = outFiles[startIndex:endIndex]
} else {
http.Error(w, "pageNum parameter error", http.StatusBadRequest)
return
}
}
}
if err == nil {
//var bytes []byte
//if bytes, err = json.Marshal(&struct {
// Files []*VideoFileInfo
// TotalCount int
// TotalPageCount int
//}{
// Files: outFiles,
// TotalCount: totalCount,
// TotalPageCount: totalPageCount,
//}); err == nil {
// w.Write(bytes)
//}
util.ReturnValue(&struct {
Files []*VideoFileInfo `json:"files"`
TotalCount int `json:"totalCount"`
TotalPageCount int `json:"totalPageCount"`
}{
Files: outFiles,
TotalCount: totalCount,
TotalPageCount: totalPageCount,
}, w, r)
}
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
func (conf *RecordConfig) API_list_recording_page(w http.ResponseWriter, r *http.Request) {
util.ReturnFetchValue(func() (outdata any) {
var recordings []any
conf.recordings.Range(func(key, value any) bool {
recordings = append(recordings, value)
return true
})
query := r.URL.Query()
pageSize := query.Get("pageSize")
pageNum := query.Get("pageNum")
RecId := query.Get("id") //搜索条件
var outRecordings []any
var totalPageCount int = 1
if RecId != "" {
for _, record := range recordings {
if record.(IRecorder).GetRecorder().ID == RecId {
outRecordings = append(outRecordings, record)
}
}
} else {
outRecordings = recordings
}
totalCount := len(outRecordings) //总条数
if pageSize != "" && pageNum != "" {
pageSizeInt, err := strconv.Atoi(pageSize)
if err != nil {
http.Error(w, "pageSize parameter error", http.StatusBadRequest)
return
}
pageNumInt, err := strconv.Atoi(pageNum)
if err != nil {
http.Error(w, "pageNum parameter error", http.StatusBadRequest)
return
}
if pageSizeInt > 0 {
if pageNumInt > 0 {
totalPageCount = (totalCount / pageSizeInt) + 1 //总页数
remainCount := totalCount % pageSizeInt //分页后剩余条数
if remainCount == 0 && totalPageCount != 1 {
totalPageCount = totalCount / pageSizeInt
}
if pageNumInt > totalPageCount {
http.Error(w, "pageSize parameter error", http.StatusBadRequest)
return
}
startIndex := (pageNumInt - 1) * pageSizeInt //开始索引
endIndex := startIndex + pageSizeInt
if endIndex > totalCount {
endIndex = totalCount
}
outRecordings = outRecordings[startIndex:endIndex]
} else {
http.Error(w, "pageNum parameter error", http.StatusBadRequest)
return
}
}
}
outdata = &struct {
Files []any `json:"files"`
TotalCount int `json:"totalCount"`
TotalPageCount int `json:"totalPageCount"`
}{
Files: outRecordings,
TotalCount: totalCount,
TotalPageCount: totalPageCount,
}
return
}, w, r)
}