mirror of
				https://github.com/Monibuca/plugin-record.git
				synced 2025-10-31 03:46:21 +08:00 
			
		
		
		
	适配3.0
This commit is contained in:
		
							
								
								
									
										43
									
								
								flv.go
									
									
									
									
									
								
							
							
						
						
									
										43
									
								
								flv.go
									
									
									
									
									
								
							| @@ -6,19 +6,19 @@ import ( | ||||
| 	"path" | ||||
| 	"path/filepath" | ||||
|  | ||||
| 	. "github.com/Monibuca/engine/v2" | ||||
| 	"github.com/Monibuca/engine/v2/avformat" | ||||
| 	"github.com/Monibuca/engine/v2/util" | ||||
| 	. "github.com/Monibuca/engine/v3" | ||||
| 	. "github.com/Monibuca/utils/v3" | ||||
| 	"github.com/Monibuca/utils/v3/codec" | ||||
| ) | ||||
|  | ||||
| func getDuration(file *os.File) uint32 { | ||||
| 	_, err := file.Seek(-4, io.SeekEnd) | ||||
| 	if err == nil { | ||||
| 		var tagSize uint32 | ||||
| 		if tagSize, err = util.ReadByteToUint32(file, true); err == nil { | ||||
| 		if tagSize, err = ReadByteToUint32(file, true); err == nil { | ||||
| 			_, err = file.Seek(-int64(tagSize)-4, io.SeekEnd) | ||||
| 			if err == nil { | ||||
| 				_, timestamp, _, err := avformat.ReadFLVTag(file) | ||||
| 				_, timestamp, _, err := codec.ReadFLVTag(file) | ||||
| 				if err == nil { | ||||
| 					return timestamp | ||||
| 				} | ||||
| @@ -35,28 +35,43 @@ func SaveFlv(streamPath string, append bool) error { | ||||
| 		flag = flag | os.O_TRUNC | os.O_WRONLY | ||||
| 	} | ||||
| 	filePath := filepath.Join(config.Path, streamPath+".flv") | ||||
| 	os.MkdirAll(path.Dir(filePath), 0775) | ||||
| 	file, err := os.OpenFile(filePath, flag, 0775) | ||||
| 	os.MkdirAll(path.Dir(filePath), 0755) | ||||
| 	file, err := os.OpenFile(filePath, flag, 0755) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	p := Subscriber{OnData: func(packet *avformat.SendPacket) error { | ||||
| 		return avformat.WriteFLVTag(file, packet) | ||||
| 	}} | ||||
| 	p.ID = filePath | ||||
| 	p.Type = "FlvRecord" | ||||
| 	// return avformat.WriteFLVTag(file, packet) | ||||
| 	p := Subscriber{ | ||||
| 		ID:   filePath, | ||||
| 		Type: "FlvRecord", | ||||
| 	} | ||||
|  | ||||
| 	if append { | ||||
| 		p.OffsetTime = getDuration(file) | ||||
| 		file.Seek(0, io.SeekEnd) | ||||
| 	} else { | ||||
| 		_, err = file.Write(avformat.FLVHeader) | ||||
| 		_, err = file.Write(codec.FLVHeader) | ||||
| 	} | ||||
| 	if err == nil { | ||||
| 		recordings.Store(filePath, &p) | ||||
| 		if err := p.Subscribe(streamPath); err == nil { | ||||
| 			at, vt := p.OriginAudioTrack, p.OriginVideoTrack | ||||
| 			var aac byte | ||||
| 			if at.SoundFormat == 10 { | ||||
| 				aac = at.RtmpTag[0] | ||||
| 			} | ||||
| 			p.OnAudio = func(audio AudioPack) { | ||||
| 				codec.WriteFLVTag(file, codec.FLV_TAG_TYPE_AUDIO, audio.Timestamp, audio.ToRTMPTag(aac)) | ||||
| 			} | ||||
| 			p.OnVideo = func(video VideoPack) { | ||||
| 				codec.WriteFLVTag(file, codec.FLV_TAG_TYPE_VIDEO, video.Timestamp, video.ToRTMPTag()) | ||||
| 			} | ||||
| 			go func() { | ||||
| 			p.Subscribe(streamPath) | ||||
| 				p.Play(at, vt) | ||||
| 				file.Close() | ||||
| 			}() | ||||
| 		} | ||||
|  | ||||
| 	} else { | ||||
| 		file.Close() | ||||
| 	} | ||||
|   | ||||
							
								
								
									
										8
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								go.mod
									
									
									
									
									
								
							| @@ -1,5 +1,9 @@ | ||||
| module github.com/Monibuca/plugin-record | ||||
| module github.com/Monibuca/plugin-record/v3 | ||||
|  | ||||
| go 1.13 | ||||
|  | ||||
| require github.com/Monibuca/engine/v2 v2.0.0 | ||||
| require ( | ||||
| 	github.com/Monibuca/engine/v3 v3.0.0-alpha6 | ||||
| 	github.com/Monibuca/utils/v3 v3.0.0-alpha5 | ||||
| 	github.com/pion/rtp v1.6.2 // indirect | ||||
| ) | ||||
|   | ||||
							
								
								
									
										49
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										49
									
								
								go.sum
									
									
									
									
									
								
							| @@ -1,47 +1,28 @@ | ||||
| github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= | ||||
| github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= | ||||
| github.com/Monibuca/engine v1.0.3 h1:/xwiEpqgQDAzjDb6zAwqFSZP8y0MOOVXv5aUx1os5nM= | ||||
| github.com/Monibuca/engine v1.0.3/go.mod h1:NjqVgtXuRSOyk3+NWgCuDf2p7TsBisjYxoEwA9uCZ38= | ||||
| github.com/Monibuca/engine v1.1.1 h1:wk5qBJCssCOpeA7jyGU/oInVmFnfc9r+eT+sbjOIZfw= | ||||
| github.com/Monibuca/engine v1.1.1/go.mod h1:NjqVgtXuRSOyk3+NWgCuDf2p7TsBisjYxoEwA9uCZ38= | ||||
| github.com/Monibuca/engine v1.2.1 h1:TJmC6eZA1lR1MScWgempZLiEZD4T6aY/nn/rlQ9UdK8= | ||||
| github.com/Monibuca/engine v1.2.1/go.mod h1:WbDkXENLjcPjyjCR1Mix1GA+uAlwORkv/+8aMVrDX2g= | ||||
| github.com/Monibuca/engine v1.2.2 h1:hNjsrZpOmui8lYhgCJ5ltJU8g/k0Rrdysx2tHNGGnbI= | ||||
| github.com/Monibuca/engine/v2 v2.0.0-alpha2 h1:45yazqnnxEEcfHcOJGuIr1xtnBzQT6cPvhlymeZrDmA= | ||||
| github.com/Monibuca/engine/v2 v2.0.0-alpha2/go.mod h1:34EYjjV15G6myuHOKaJkO7y5tJ1Arq/NfC9Weacr2mc= | ||||
| github.com/Monibuca/engine/v2 v2.0.0-alpha3 h1:G1Mbq3Q0hbZuA0evrByf8qqRx/rk3lbvJa7Qp55tOsw= | ||||
| github.com/Monibuca/engine/v2 v2.0.0-alpha3/go.mod h1:34EYjjV15G6myuHOKaJkO7y5tJ1Arq/NfC9Weacr2mc= | ||||
| github.com/Monibuca/engine/v2 v2.0.0 h1:8FjaScrtN8QdbcxO9zZYABMC0Re3I1O1T4p94zAXYb0= | ||||
| github.com/Monibuca/engine/v2 v2.0.0/go.mod h1:34EYjjV15G6myuHOKaJkO7y5tJ1Arq/NfC9Weacr2mc= | ||||
| github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk= | ||||
| github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= | ||||
| github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= | ||||
| github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||||
| github.com/Monibuca/engine/v3 v3.0.0-alpha6 h1:USZa+JDVJd13rb9wmX06ZxjRCrqYTAPe5wVD+0IODEE= | ||||
| github.com/Monibuca/engine/v3 v3.0.0-alpha6/go.mod h1:V0/kfen6K5O/RLXHPsZj4DF/LboDZ0OqfeCfn35bWMo= | ||||
| github.com/Monibuca/utils/v3 v3.0.0-alpha4/go.mod h1:3xYmhQbgAZBHLyIMteUCd1va+1z/xnd72B585mCaT3c= | ||||
| github.com/Monibuca/utils/v3 v3.0.0-alpha5 h1:IOyW/KJSRdRg+TPcgwkHLBynqfNQOV6p3iP7LgXEMFc= | ||||
| github.com/Monibuca/utils/v3 v3.0.0-alpha5/go.mod h1:3xYmhQbgAZBHLyIMteUCd1va+1z/xnd72B585mCaT3c= | ||||
| github.com/funny/slab v0.0.0-20180511031532-b1fad5e5d478 h1:Db9StoJ6RZN3YttC0Pm0I4Y5izITRYch3RMbT59BYN0= | ||||
| github.com/funny/slab v0.0.0-20180511031532-b1fad5e5d478/go.mod h1:0j1+svBH8ABEIPdUP0AIg4qedsybnXGJBakCEw8cfoo= | ||||
| github.com/funny/utest v0.0.0-20161029064919-43870a374500 h1:Z0r1CZnoIWFB/Uiwh1BU5FYmuFe6L5NPi6XWQEmsTRg= | ||||
| github.com/funny/utest v0.0.0-20161029064919-43870a374500/go.mod h1:mUn39tBov9jKnTWV1RlOYoNzxdBFHiSzXWdY1FoNGGg= | ||||
| github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI= | ||||
| github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= | ||||
| github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381 h1:bqDmpDG49ZRnB5PcgP0RXtQvnMSgIF14M7CBd2shtXs= | ||||
| github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= | ||||
| github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE= | ||||
| github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= | ||||
| github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= | ||||
| github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= | ||||
| github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= | ||||
| github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= | ||||
| github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= | ||||
| github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= | ||||
| github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA= | ||||
| github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8= | ||||
| github.com/pion/rtp v1.6.2 h1:iGBerLX6JiDjB9NXuaPzHyxHFG9JsIEdgwTC0lp5n/U= | ||||
| github.com/pion/rtp v1.6.2/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko= | ||||
| github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= | ||||
| github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | ||||
| github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||||
| github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||||
| github.com/shirou/gopsutil v2.20.1+incompatible h1:oIq9Cq4i84Hk8uQAUOG3eNdI/29hBawGrD5YRl6JRDY= | ||||
| github.com/shirou/gopsutil v2.20.1+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= | ||||
| github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||||
| github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= | ||||
| github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= | ||||
| golang.org/x/sync v0.0.0-20201207232520-09787c993a3a h1:DcqTD9SDLc+1P/r1EmRBwnVsrOwW+kk2vWf9n+1sGhs= | ||||
| golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||
| golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8= | ||||
| golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= | ||||
| gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||||
| gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= | ||||
| gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | ||||
|   | ||||
							
								
								
									
										31
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								main.go
									
									
									
									
									
								
							| @@ -9,8 +9,8 @@ import ( | ||||
| 	"strings" | ||||
| 	"sync" | ||||
|  | ||||
| 	. "github.com/Monibuca/engine/v2" | ||||
| 	. "github.com/Monibuca/engine/v2/util" | ||||
| 	. "github.com/Monibuca/engine/v3" | ||||
| 	. "github.com/Monibuca/utils/v3" | ||||
| ) | ||||
|  | ||||
| var config struct { | ||||
| @@ -29,7 +29,6 @@ type FlvFileInfo struct { | ||||
| func init() { | ||||
| 	InstallPlugin(&PluginConfig{ | ||||
| 		Name:   "Record", | ||||
| 		Type:   PLUGIN_SUBSCRIBER, | ||||
| 		Config: &config, | ||||
| 		Run:    run, | ||||
| 		HotConfig: map[string]func(interface{}){ | ||||
| @@ -43,10 +42,10 @@ func init() { | ||||
| 	}) | ||||
| } | ||||
| func run() { | ||||
| 	OnSubscribeHooks.AddHook(onSubscribe) | ||||
| 	OnPublishHooks.AddHook(onPublish) | ||||
| 	go AddHook(HOOK_SUBSCRIBE, onSubscribe) | ||||
| 	go AddHook(HOOK_PUBLISH, onPublish) | ||||
| 	os.MkdirAll(config.Path, 0755) | ||||
| 	http.HandleFunc("/record/flv/list", func(writer http.ResponseWriter, r *http.Request) { | ||||
| 	http.HandleFunc("/api/record/flv/list", func(writer http.ResponseWriter, r *http.Request) { | ||||
| 		if files, err := tree(config.Path, 0); err == nil { | ||||
| 			var bytes []byte | ||||
| 			if bytes, err = json.Marshal(files); err == nil { | ||||
| @@ -58,7 +57,7 @@ func run() { | ||||
| 			writer.Write([]byte("{\"err\":\"" + err.Error() + "\"}")) | ||||
| 		} | ||||
| 	}) | ||||
| 	http.HandleFunc("/record/flv", func(writer http.ResponseWriter, r *http.Request) { | ||||
| 	http.HandleFunc("/api/record/flv", func(writer http.ResponseWriter, r *http.Request) { | ||||
| 		if streamPath := r.URL.Query().Get("streamPath"); streamPath != "" { | ||||
| 			if err := SaveFlv(streamPath, r.URL.Query().Get("append") == "true"); err != nil { | ||||
| 				writer.Write([]byte(err.Error())) | ||||
| @@ -70,8 +69,8 @@ func run() { | ||||
| 		} | ||||
| 	}) | ||||
|  | ||||
| 	http.HandleFunc("/record/flv/stop", func(w http.ResponseWriter, r *http.Request) { | ||||
| 		w.Header().Set("Access-Control-Allow-Origin", "*") | ||||
| 	http.HandleFunc("/api/record/flv/stop", func(w http.ResponseWriter, r *http.Request) { | ||||
| 		CORS(w, r) | ||||
| 		if streamPath := r.URL.Query().Get("streamPath"); streamPath != "" { | ||||
| 			filePath := filepath.Join(config.Path, streamPath+".flv") | ||||
| 			if stream, ok := recordings.Load(filePath); ok { | ||||
| @@ -85,7 +84,7 @@ func run() { | ||||
| 			w.Write([]byte("no such stream")) | ||||
| 		} | ||||
| 	}) | ||||
| 	http.HandleFunc("/record/flv/play", func(w http.ResponseWriter, r *http.Request) { | ||||
| 	http.HandleFunc("/api/record/flv/play", func(w http.ResponseWriter, r *http.Request) { | ||||
| 		if streamPath := r.URL.Query().Get("streamPath"); streamPath != "" { | ||||
| 			if err := PublishFlvFile(streamPath); err != nil { | ||||
| 				w.Write([]byte(err.Error())) | ||||
| @@ -96,7 +95,7 @@ func run() { | ||||
| 			w.Write([]byte("no streamPath")) | ||||
| 		} | ||||
| 	}) | ||||
| 	http.HandleFunc("/record/flv/delete", func(w http.ResponseWriter, r *http.Request) { | ||||
| 	http.HandleFunc("/api/record/flv/delete", func(w http.ResponseWriter, r *http.Request) { | ||||
| 		if streamPath := r.URL.Query().Get("streamPath"); streamPath != "" { | ||||
| 			filePath := filepath.Join(config.Path, streamPath+".flv") | ||||
| 			if Exist(filePath) { | ||||
| @@ -113,17 +112,19 @@ func run() { | ||||
| 		} | ||||
| 	}) | ||||
| } | ||||
| func onSubscribe(s *Subscriber) { | ||||
| func onSubscribe(v interface{}) { | ||||
| 	s:=v.(*Subscriber) | ||||
| 	if config.AutoPublish { | ||||
| 		filePath := filepath.Join(config.Path, s.StreamPath+".flv") | ||||
| 		if s.Publisher == nil && Exist(filePath) { | ||||
| 			go PublishFlvFile(s.StreamPath) | ||||
| 			PublishFlvFile(s.StreamPath) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| func onPublish(p *Stream) { | ||||
| func onPublish(v interface{}) { | ||||
| 	p := v.(*Stream) | ||||
| 	if config.AutoRecord { | ||||
| 		go SaveFlv(p.StreamPath, false) | ||||
| 		SaveFlv(p.StreamPath, false) | ||||
| 	} | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										23
									
								
								publisher.go
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								publisher.go
									
									
									
									
									
								
							| @@ -7,8 +7,9 @@ import ( | ||||
| 	"path/filepath" | ||||
| 	"time" | ||||
|  | ||||
| 	. "github.com/Monibuca/engine/v2" | ||||
| 	"github.com/Monibuca/engine/v2/avformat" | ||||
| 	. "github.com/Monibuca/engine/v3" | ||||
| 	. "github.com/Monibuca/utils/v3" | ||||
| 	"github.com/Monibuca/utils/v3/codec" | ||||
| ) | ||||
|  | ||||
| type FlvFile struct { | ||||
| @@ -19,25 +20,27 @@ func PublishFlvFile(streamPath string) error { | ||||
| 	flvPath := filepath.Join(config.Path, streamPath+".flv") | ||||
| 	os.MkdirAll(filepath.Dir(flvPath), 0755) | ||||
| 	if file, err := os.Open(flvPath); err == nil { | ||||
| 		stream := FlvFile{} | ||||
| 		var stream FlvFile | ||||
| 		if stream.Publish(streamPath) { | ||||
| 			stream.Type = "FlvFile" | ||||
| 			defer stream.Close() | ||||
| 			stream.UseTimestamp = true | ||||
| 			file.Seek(int64(len(avformat.FLVHeader)), io.SeekStart) | ||||
| 			file.Seek(int64(len(codec.FLVHeader)), io.SeekStart) | ||||
| 			var lastTime uint32 | ||||
| 			at := NewAudioTrack() | ||||
| 			vt := NewVideoTrack() | ||||
| 			stream.SetOriginAT(at) | ||||
| 			for { | ||||
| 				if t, timestamp, payload, err := avformat.ReadFLVTag(file); err == nil { | ||||
| 				if t, timestamp, payload, err := codec.ReadFLVTag(file); err == nil { | ||||
| 					switch t { | ||||
| 					case avformat.FLV_TAG_TYPE_AUDIO: | ||||
| 						stream.PushAudio(timestamp, payload) | ||||
| 					case avformat.FLV_TAG_TYPE_VIDEO: | ||||
| 					case codec.FLV_TAG_TYPE_AUDIO: | ||||
| 						at.Push(timestamp, payload) | ||||
| 					case codec.FLV_TAG_TYPE_VIDEO: | ||||
| 						if timestamp != 0 { | ||||
| 							if lastTime == 0 { | ||||
| 								lastTime = timestamp | ||||
| 							} | ||||
| 						} | ||||
| 						stream.PushVideo(timestamp, payload) | ||||
| 						vt.Push(VideoPack{Timestamp: timestamp, CompositionTime: BigEndian.Uint24(payload[2:5]), Payload: payload[5:]}) | ||||
| 						time.Sleep(time.Duration(timestamp-lastTime) * time.Millisecond) | ||||
| 						lastTime = timestamp | ||||
| 					} | ||||
|   | ||||
							
								
								
									
										19
									
								
								ui/dist/demo.html
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										19
									
								
								ui/dist/demo.html
									
									
									
									
										vendored
									
									
								
							| @@ -1,19 +0,0 @@ | ||||
| <meta charset="utf-8"> | ||||
| <title>plugin-record demo</title> | ||||
| <script src="https://unpkg.com/vue"></script> | ||||
| <script src="./plugin-record.umd.js"></script> | ||||
|  | ||||
| <link rel="stylesheet" href="./plugin-record.css"> | ||||
|  | ||||
|  | ||||
| <div id="app"> | ||||
|   <demo></demo> | ||||
| </div> | ||||
|  | ||||
| <script> | ||||
| new Vue({ | ||||
|   components: { | ||||
|     demo: plugin-record | ||||
|   } | ||||
| }).$mount('#app') | ||||
| </script> | ||||
							
								
								
									
										524
									
								
								ui/dist/plugin-record.common.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										524
									
								
								ui/dist/plugin-record.common.js
									
									
									
									
										vendored
									
									
								
							| @@ -1,524 +0,0 @@ | ||||
| module.exports = | ||||
| /******/ (function(modules) { // webpackBootstrap | ||||
| /******/ 	// The module cache | ||||
| /******/ 	var installedModules = {}; | ||||
| /******/ | ||||
| /******/ 	// The require function | ||||
| /******/ 	function __webpack_require__(moduleId) { | ||||
| /******/ | ||||
| /******/ 		// Check if module is in cache | ||||
| /******/ 		if(installedModules[moduleId]) { | ||||
| /******/ 			return installedModules[moduleId].exports; | ||||
| /******/ 		} | ||||
| /******/ 		// Create a new module (and put it into the cache) | ||||
| /******/ 		var module = installedModules[moduleId] = { | ||||
| /******/ 			i: moduleId, | ||||
| /******/ 			l: false, | ||||
| /******/ 			exports: {} | ||||
| /******/ 		}; | ||||
| /******/ | ||||
| /******/ 		// Execute the module function | ||||
| /******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); | ||||
| /******/ | ||||
| /******/ 		// Flag the module as loaded | ||||
| /******/ 		module.l = true; | ||||
| /******/ | ||||
| /******/ 		// Return the exports of the module | ||||
| /******/ 		return module.exports; | ||||
| /******/ 	} | ||||
| /******/ | ||||
| /******/ | ||||
| /******/ 	// expose the modules object (__webpack_modules__) | ||||
| /******/ 	__webpack_require__.m = modules; | ||||
| /******/ | ||||
| /******/ 	// expose the module cache | ||||
| /******/ 	__webpack_require__.c = installedModules; | ||||
| /******/ | ||||
| /******/ 	// define getter function for harmony exports | ||||
| /******/ 	__webpack_require__.d = function(exports, name, getter) { | ||||
| /******/ 		if(!__webpack_require__.o(exports, name)) { | ||||
| /******/ 			Object.defineProperty(exports, name, { enumerable: true, get: getter }); | ||||
| /******/ 		} | ||||
| /******/ 	}; | ||||
| /******/ | ||||
| /******/ 	// define __esModule on exports | ||||
| /******/ 	__webpack_require__.r = function(exports) { | ||||
| /******/ 		if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { | ||||
| /******/ 			Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||||
| /******/ 		} | ||||
| /******/ 		Object.defineProperty(exports, '__esModule', { value: true }); | ||||
| /******/ 	}; | ||||
| /******/ | ||||
| /******/ 	// create a fake namespace object | ||||
| /******/ 	// mode & 1: value is a module id, require it | ||||
| /******/ 	// mode & 2: merge all properties of value into the ns | ||||
| /******/ 	// mode & 4: return value when already ns object | ||||
| /******/ 	// mode & 8|1: behave like require | ||||
| /******/ 	__webpack_require__.t = function(value, mode) { | ||||
| /******/ 		if(mode & 1) value = __webpack_require__(value); | ||||
| /******/ 		if(mode & 8) return value; | ||||
| /******/ 		if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; | ||||
| /******/ 		var ns = Object.create(null); | ||||
| /******/ 		__webpack_require__.r(ns); | ||||
| /******/ 		Object.defineProperty(ns, 'default', { enumerable: true, value: value }); | ||||
| /******/ 		if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); | ||||
| /******/ 		return ns; | ||||
| /******/ 	}; | ||||
| /******/ | ||||
| /******/ 	// getDefaultExport function for compatibility with non-harmony modules | ||||
| /******/ 	__webpack_require__.n = function(module) { | ||||
| /******/ 		var getter = module && module.__esModule ? | ||||
| /******/ 			function getDefault() { return module['default']; } : | ||||
| /******/ 			function getModuleExports() { return module; }; | ||||
| /******/ 		__webpack_require__.d(getter, 'a', getter); | ||||
| /******/ 		return getter; | ||||
| /******/ 	}; | ||||
| /******/ | ||||
| /******/ 	// Object.prototype.hasOwnProperty.call | ||||
| /******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; | ||||
| /******/ | ||||
| /******/ 	// __webpack_public_path__ | ||||
| /******/ 	__webpack_require__.p = ""; | ||||
| /******/ | ||||
| /******/ | ||||
| /******/ 	// Load entry module and return exports | ||||
| /******/ 	return __webpack_require__(__webpack_require__.s = "fb15"); | ||||
| /******/ }) | ||||
| /************************************************************************/ | ||||
| /******/ ({ | ||||
|  | ||||
| /***/ "5941": | ||||
| /***/ (function(module, exports, __webpack_require__) { | ||||
|  | ||||
| // extracted by mini-css-extract-plugin | ||||
|  | ||||
| /***/ }), | ||||
|  | ||||
| /***/ "f6fd": | ||||
| /***/ (function(module, exports) { | ||||
|  | ||||
| // document.currentScript polyfill by Adam Miller | ||||
|  | ||||
| // MIT license | ||||
|  | ||||
| (function(document){ | ||||
|   var currentScript = "currentScript", | ||||
|       scripts = document.getElementsByTagName('script'); // Live NodeList collection | ||||
|  | ||||
|   // If browser needs currentScript polyfill, add get currentScript() to the document object | ||||
|   if (!(currentScript in document)) { | ||||
|     Object.defineProperty(document, currentScript, { | ||||
|       get: function(){ | ||||
|  | ||||
|         // IE 6-10 supports script readyState | ||||
|         // IE 10+ support stack trace | ||||
|         try { throw new Error(); } | ||||
|         catch (err) { | ||||
|  | ||||
|           // Find the second match for the "at" string to get file src url from stack. | ||||
|           // Specifically works with the format of stack traces in IE. | ||||
|           var i, res = ((/.*at [^\(]*\((.*):.+:.+\)$/ig).exec(err.stack) || [false])[1]; | ||||
|  | ||||
|           // For all scripts on the page, if src matches or if ready state is interactive, return the script tag | ||||
|           for(i in scripts){ | ||||
|             if(scripts[i].src == res || scripts[i].readyState == "interactive"){ | ||||
|               return scripts[i]; | ||||
|             } | ||||
|           } | ||||
|  | ||||
|           // If no match, return null | ||||
|           return null; | ||||
|         } | ||||
|       } | ||||
|     }); | ||||
|   } | ||||
| })(document); | ||||
|  | ||||
|  | ||||
| /***/ }), | ||||
|  | ||||
| /***/ "f87e": | ||||
| /***/ (function(module, __webpack_exports__, __webpack_require__) { | ||||
|  | ||||
| "use strict"; | ||||
| /* harmony import */ var _node_modules_mini_css_extract_plugin_dist_loader_js_ref_6_oneOf_1_0_node_modules_css_loader_dist_cjs_js_ref_6_oneOf_1_1_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_postcss_loader_src_index_js_ref_6_oneOf_1_2_node_modules_cache_loader_dist_cjs_js_ref_0_0_node_modules_vue_loader_lib_index_js_vue_loader_options_App_vue_vue_type_style_index_0_id_015b8bdf_scoped_true_lang_css___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("5941"); | ||||
| /* harmony import */ var _node_modules_mini_css_extract_plugin_dist_loader_js_ref_6_oneOf_1_0_node_modules_css_loader_dist_cjs_js_ref_6_oneOf_1_1_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_postcss_loader_src_index_js_ref_6_oneOf_1_2_node_modules_cache_loader_dist_cjs_js_ref_0_0_node_modules_vue_loader_lib_index_js_vue_loader_options_App_vue_vue_type_style_index_0_id_015b8bdf_scoped_true_lang_css___WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_mini_css_extract_plugin_dist_loader_js_ref_6_oneOf_1_0_node_modules_css_loader_dist_cjs_js_ref_6_oneOf_1_1_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_postcss_loader_src_index_js_ref_6_oneOf_1_2_node_modules_cache_loader_dist_cjs_js_ref_0_0_node_modules_vue_loader_lib_index_js_vue_loader_options_App_vue_vue_type_style_index_0_id_015b8bdf_scoped_true_lang_css___WEBPACK_IMPORTED_MODULE_0__); | ||||
| /* unused harmony reexport * */ | ||||
|  /* unused harmony default export */ var _unused_webpack_default_export = (_node_modules_mini_css_extract_plugin_dist_loader_js_ref_6_oneOf_1_0_node_modules_css_loader_dist_cjs_js_ref_6_oneOf_1_1_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_postcss_loader_src_index_js_ref_6_oneOf_1_2_node_modules_cache_loader_dist_cjs_js_ref_0_0_node_modules_vue_loader_lib_index_js_vue_loader_options_App_vue_vue_type_style_index_0_id_015b8bdf_scoped_true_lang_css___WEBPACK_IMPORTED_MODULE_0___default.a);  | ||||
|  | ||||
| /***/ }), | ||||
|  | ||||
| /***/ "fb15": | ||||
| /***/ (function(module, __webpack_exports__, __webpack_require__) { | ||||
|  | ||||
| "use strict"; | ||||
| // ESM COMPAT FLAG | ||||
| __webpack_require__.r(__webpack_exports__); | ||||
|  | ||||
| // CONCATENATED MODULE: ./node_modules/@vue/cli-service/lib/commands/build/setPublicPath.js | ||||
| // This file is imported into lib/wc client bundles. | ||||
|  | ||||
| if (typeof window !== 'undefined') { | ||||
|   if (true) { | ||||
|     __webpack_require__("f6fd") | ||||
|   } | ||||
|  | ||||
|   var i | ||||
|   if ((i = window.document.currentScript) && (i = i.src.match(/(.+\/)[^/]+\.js(\?.*)?$/))) { | ||||
|     __webpack_require__.p = i[1] // eslint-disable-line | ||||
|   } | ||||
| } | ||||
|  | ||||
| // Indicate to webpack that this file can be concatenated | ||||
| /* harmony default export */ var setPublicPath = (null); | ||||
|  | ||||
| // CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"5b04a8fd-vue-loader-template"}!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/App.vue?vue&type=template&id=015b8bdf&scoped=true& | ||||
| var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',[(_vm.$parent.titleTabActive==1)?_c('Records',{ref:"recordsPanel"}):_c('stream-table',{scopedSlots:_vm._u([{key:"default",fn:function(ref){ | ||||
| var stream = ref.row; | ||||
| return [(_vm.isRecording(stream))?_c('m-button',{attrs:{"blink":""},on:{"click":function($event){return _vm.stopRecord(stream)}}},[_vm._v("正在录制")]):_c('m-button',{on:{"click":function($event){return _vm.record(stream)}}},[_vm._v("录制")])]}}])})],1)} | ||||
| var staticRenderFns = [] | ||||
|  | ||||
|  | ||||
| // CONCATENATED MODULE: ./src/App.vue?vue&type=template&id=015b8bdf&scoped=true& | ||||
|  | ||||
| // CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"5b04a8fd-vue-loader-template"}!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/Records.vue?vue&type=template&id=675e088d& | ||||
| var Recordsvue_type_template_id_675e088d_render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('mu-data-table',{attrs:{"data":_vm.data,"columns":_vm.columns},scopedSlots:_vm._u([{key:"default",fn:function(ref){ | ||||
| var row = ref.row; | ||||
| return [_c('td',[_vm._v(_vm._s(row.Path))]),_c('td',[_vm._v(_vm._s(_vm.unitFormat(row.Size)))]),_c('td',[_vm._v(_vm._s(_vm.toDurationStr(row.Duration)))]),_c('td',[_c('mu-button',{attrs:{"icon":"","small":""},on:{"click":function($event){return _vm.play(row)}}},[_c('mu-icon',{attrs:{"value":"play_arrow"}})],1),_c('mu-button',{attrs:{"icon":"","small":""},on:{"click":function($event){return _vm.deleteFlv(row)}}},[_c('mu-icon',{attrs:{"value":"delete_forever"}})],1)],1)]}}])})} | ||||
| var Recordsvue_type_template_id_675e088d_staticRenderFns = [] | ||||
|  | ||||
|  | ||||
| // CONCATENATED MODULE: ./src/components/Records.vue?vue&type=template&id=675e088d& | ||||
|  | ||||
| // CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/Records.vue?vue&type=script&lang=js& | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
|  | ||||
| /* harmony default export */ var Recordsvue_type_script_lang_js_ = ({ | ||||
|     data() { | ||||
|         return { | ||||
|             data: [], | ||||
|             columns:[ | ||||
|                 { | ||||
|                     title:"文件路径" | ||||
|                 },{ | ||||
|                     title:"大小" | ||||
|                 },{ | ||||
|                     title:"时长" | ||||
|                 },{title:"操作"} | ||||
|             ] | ||||
|         }; | ||||
|     }, | ||||
|     methods: { | ||||
|         play(item) { | ||||
|             this.ajax.get( | ||||
|                 "/record/flv/play", | ||||
|                 { streamPath: item.Path.replace(".flv", "") }, | ||||
|                 x => { | ||||
|                     if (x == "success") { | ||||
|                         this.ajax.getJSON("/record/flv/list", x => this.data = x); | ||||
|                         this.$toast.success("开始发布"); | ||||
|                     } else { | ||||
|                         this.$toast.error(x); | ||||
|                     } | ||||
|                 } | ||||
|             ); | ||||
|         }, | ||||
|         deleteFlv(item) { | ||||
|             this.$confirm("是否删除Flv文件", "提示").then(result => { | ||||
|                 if (result) { | ||||
|                     return this.ajax.get( | ||||
|                         "/record/flv/delete", | ||||
|                         { streamPath: item.Path.replace(".flv", "") }, | ||||
|                         x => { | ||||
|                             if (x == "success") { | ||||
|                                 this.$toast.success("删除成功"); | ||||
|                             } else { | ||||
|                                 this.$toast.error(x); | ||||
|                             } | ||||
|                         } | ||||
|                     ); | ||||
|                 } | ||||
|             }); | ||||
|         }, | ||||
|         toDurationStr(value) { | ||||
|             if (value > 1000) { | ||||
|                 let s = value / 1000; | ||||
|                 if (s > 60) { | ||||
|                     s = s | 0; | ||||
|                     let min = (s / 60) >> 0; | ||||
|                     if (min > 60) { | ||||
|                         let hour = (min / 60) >> 0; | ||||
|                         return hour + "hour" + (min % 60) + "min"; | ||||
|                     } else { | ||||
|                         return min + "min" + (s % 60) + "s"; | ||||
|                     } | ||||
|                 } else { | ||||
|                     return s.toFixed(3) + "s"; | ||||
|                 } | ||||
|             } else { | ||||
|                 return value + "ms"; | ||||
|             } | ||||
|         } | ||||
|     }, | ||||
|     mounted() { | ||||
|         this.ajax.getJSON("/record/flv/list", x => this.data = x); | ||||
|     } | ||||
| }); | ||||
|  | ||||
| // CONCATENATED MODULE: ./src/components/Records.vue?vue&type=script&lang=js& | ||||
|  /* harmony default export */ var components_Recordsvue_type_script_lang_js_ = (Recordsvue_type_script_lang_js_);  | ||||
| // CONCATENATED MODULE: ./node_modules/vue-loader/lib/runtime/componentNormalizer.js | ||||
| /* globals __VUE_SSR_CONTEXT__ */ | ||||
|  | ||||
| // IMPORTANT: Do NOT use ES2015 features in this file (except for modules). | ||||
| // This module is a runtime utility for cleaner component module output and will | ||||
| // be included in the final webpack user bundle. | ||||
|  | ||||
| function normalizeComponent ( | ||||
|   scriptExports, | ||||
|   render, | ||||
|   staticRenderFns, | ||||
|   functionalTemplate, | ||||
|   injectStyles, | ||||
|   scopeId, | ||||
|   moduleIdentifier, /* server only */ | ||||
|   shadowMode /* vue-cli only */ | ||||
| ) { | ||||
|   // Vue.extend constructor export interop | ||||
|   var options = typeof scriptExports === 'function' | ||||
|     ? scriptExports.options | ||||
|     : scriptExports | ||||
|  | ||||
|   // render functions | ||||
|   if (render) { | ||||
|     options.render = render | ||||
|     options.staticRenderFns = staticRenderFns | ||||
|     options._compiled = true | ||||
|   } | ||||
|  | ||||
|   // functional template | ||||
|   if (functionalTemplate) { | ||||
|     options.functional = true | ||||
|   } | ||||
|  | ||||
|   // scopedId | ||||
|   if (scopeId) { | ||||
|     options._scopeId = 'data-v-' + scopeId | ||||
|   } | ||||
|  | ||||
|   var hook | ||||
|   if (moduleIdentifier) { // server build | ||||
|     hook = function (context) { | ||||
|       // 2.3 injection | ||||
|       context = | ||||
|         context || // cached call | ||||
|         (this.$vnode && this.$vnode.ssrContext) || // stateful | ||||
|         (this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext) // functional | ||||
|       // 2.2 with runInNewContext: true | ||||
|       if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') { | ||||
|         context = __VUE_SSR_CONTEXT__ | ||||
|       } | ||||
|       // inject component styles | ||||
|       if (injectStyles) { | ||||
|         injectStyles.call(this, context) | ||||
|       } | ||||
|       // register component module identifier for async chunk inferrence | ||||
|       if (context && context._registeredComponents) { | ||||
|         context._registeredComponents.add(moduleIdentifier) | ||||
|       } | ||||
|     } | ||||
|     // used by ssr in case component is cached and beforeCreate | ||||
|     // never gets called | ||||
|     options._ssrRegister = hook | ||||
|   } else if (injectStyles) { | ||||
|     hook = shadowMode | ||||
|       ? function () { injectStyles.call(this, this.$root.$options.shadowRoot) } | ||||
|       : injectStyles | ||||
|   } | ||||
|  | ||||
|   if (hook) { | ||||
|     if (options.functional) { | ||||
|       // for template-only hot-reload because in that case the render fn doesn't | ||||
|       // go through the normalizer | ||||
|       options._injectStyles = hook | ||||
|       // register for functional component in vue file | ||||
|       var originalRender = options.render | ||||
|       options.render = function renderWithStyleInjection (h, context) { | ||||
|         hook.call(context) | ||||
|         return originalRender(h, context) | ||||
|       } | ||||
|     } else { | ||||
|       // inject component registration as beforeCreate hook | ||||
|       var existing = options.beforeCreate | ||||
|       options.beforeCreate = existing | ||||
|         ? [].concat(existing, hook) | ||||
|         : [hook] | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   return { | ||||
|     exports: scriptExports, | ||||
|     options: options | ||||
|   } | ||||
| } | ||||
|  | ||||
| // CONCATENATED MODULE: ./src/components/Records.vue | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| /* normalize component */ | ||||
|  | ||||
| var component = normalizeComponent( | ||||
|   components_Recordsvue_type_script_lang_js_, | ||||
|   Recordsvue_type_template_id_675e088d_render, | ||||
|   Recordsvue_type_template_id_675e088d_staticRenderFns, | ||||
|   false, | ||||
|   null, | ||||
|   null, | ||||
|   null | ||||
|    | ||||
| ) | ||||
|  | ||||
| /* harmony default export */ var Records = (component.exports); | ||||
| // CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/App.vue?vue&type=script&lang=js& | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
|  | ||||
|  | ||||
| /* harmony default export */ var Appvue_type_script_lang_js_ = ({ | ||||
|     components: { | ||||
|         Records: Records | ||||
|     }, | ||||
|     data() { | ||||
|         return {}; | ||||
|     }, | ||||
|     methods: { | ||||
|         record(item) { | ||||
|             let append = false; | ||||
|             this.$confirm( | ||||
|                 h => | ||||
|                     h("mu-switch", { | ||||
|                         props: { | ||||
|                             label: "追加模式" | ||||
|                         }, | ||||
|                         on: { | ||||
|                             change(value) { | ||||
|                                 append = value; | ||||
|                             } | ||||
|                         } | ||||
|                     }), | ||||
|                 "是否开始录制" | ||||
|             ).then(result => { | ||||
|                 if (result) { | ||||
|                     this.ajax.get( | ||||
|                         "/record/flv?append=" + append, | ||||
|                         { streamPath: item.StreamPath }, | ||||
|                         x => { | ||||
|                             if (x == "success") { | ||||
|                                 this.$toast.success( | ||||
|                                     "开始录制" + (append ? "(追加模式)" : "") | ||||
|                                 ); | ||||
|                             } else { | ||||
|                                 this.$toast.error(x); | ||||
|                             } | ||||
|                         } | ||||
|                     ); | ||||
|                 } | ||||
|             }); | ||||
|         }, | ||||
|         stopRecord(item) { | ||||
|             this.$confirm("是否停止录制", "提示").then(result => { | ||||
|                 if(result) | ||||
|                 { | ||||
|                     this.ajax.get( | ||||
|                         "/record/flv/stop", | ||||
|                         { streamPath: item.StreamPath }, | ||||
|                         x => { | ||||
|                             if (x == "success") { | ||||
|                                 this.$toast.success("停止录制"); | ||||
|                             } else { | ||||
|                                 this.$toast.error(x); | ||||
|                             } | ||||
|                         } | ||||
|                     ); | ||||
|                 } | ||||
|             }); | ||||
|         }, | ||||
|         isRecording(item) { | ||||
|             return ( | ||||
|                 item.SubscriberInfo && | ||||
|                 item.SubscriberInfo.find(x => x.Type == "FlvRecord") | ||||
|             ); | ||||
|         } | ||||
|     }, | ||||
|     mounted() { | ||||
|         this.$parent.titleTabs = ["StreamList", "录制的视频"]; | ||||
|     } | ||||
| }); | ||||
|  | ||||
| // CONCATENATED MODULE: ./src/App.vue?vue&type=script&lang=js& | ||||
|  /* harmony default export */ var src_Appvue_type_script_lang_js_ = (Appvue_type_script_lang_js_);  | ||||
| // EXTERNAL MODULE: ./src/App.vue?vue&type=style&index=0&id=015b8bdf&scoped=true&lang=css& | ||||
| var Appvue_type_style_index_0_id_015b8bdf_scoped_true_lang_css_ = __webpack_require__("f87e"); | ||||
|  | ||||
| // CONCATENATED MODULE: ./src/App.vue | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| /* normalize component */ | ||||
|  | ||||
| var App_component = normalizeComponent( | ||||
|   src_Appvue_type_script_lang_js_, | ||||
|   render, | ||||
|   staticRenderFns, | ||||
|   false, | ||||
|   null, | ||||
|   "015b8bdf", | ||||
|   null | ||||
|    | ||||
| ) | ||||
|  | ||||
| /* harmony default export */ var App = (App_component.exports); | ||||
| // CONCATENATED MODULE: ./node_modules/@vue/cli-service/lib/commands/build/entry-lib.js | ||||
|  | ||||
|  | ||||
| /* harmony default export */ var entry_lib = __webpack_exports__["default"] = (App); | ||||
|  | ||||
|  | ||||
|  | ||||
| /***/ }) | ||||
|  | ||||
| /******/ })["default"]; | ||||
| //# sourceMappingURL=plugin-record.common.js.map | ||||
							
								
								
									
										1
									
								
								ui/dist/plugin-record.common.js.map
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								ui/dist/plugin-record.common.js.map
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										1
									
								
								ui/dist/plugin-record.css
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								ui/dist/plugin-record.css
									
									
									
									
										vendored
									
									
								
							| @@ -1 +0,0 @@ | ||||
| @-webkit-keyframes recording-data-v-015b8bdf{0%{opacity:.2}50%{opacity:1}to{opacity:.2}}@keyframes recording-data-v-015b8bdf{0%{opacity:.2}50%{opacity:1}to{opacity:.2}}.recording[data-v-015b8bdf]{-webkit-animation:recording-data-v-015b8bdf 1s infinite;animation:recording-data-v-015b8bdf 1s infinite}.layout[data-v-015b8bdf]{padding-bottom:30px;display:flex;flex-wrap:wrap}.room[data-v-015b8bdf]{width:250px;margin:10px;text-align:left}.empty[data-v-015b8bdf]{color:#ffc107;width:100%;min-height:500px;display:flex;justify-content:center;align-items:center}.status[data-v-015b8bdf]{position:fixed;display:flex;left:5px;bottom:10px}.status>div[data-v-015b8bdf]{margin:0 5px} | ||||
							
								
								
									
										534
									
								
								ui/dist/plugin-record.umd.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										534
									
								
								ui/dist/plugin-record.umd.js
									
									
									
									
										vendored
									
									
								
							| @@ -1,534 +0,0 @@ | ||||
| (function webpackUniversalModuleDefinition(root, factory) { | ||||
| 	if(typeof exports === 'object' && typeof module === 'object') | ||||
| 		module.exports = factory(); | ||||
| 	else if(typeof define === 'function' && define.amd) | ||||
| 		define([], factory); | ||||
| 	else if(typeof exports === 'object') | ||||
| 		exports["plugin-record"] = factory(); | ||||
| 	else | ||||
| 		root["plugin-record"] = factory(); | ||||
| })((typeof self !== 'undefined' ? self : this), function() { | ||||
| return /******/ (function(modules) { // webpackBootstrap | ||||
| /******/ 	// The module cache | ||||
| /******/ 	var installedModules = {}; | ||||
| /******/ | ||||
| /******/ 	// The require function | ||||
| /******/ 	function __webpack_require__(moduleId) { | ||||
| /******/ | ||||
| /******/ 		// Check if module is in cache | ||||
| /******/ 		if(installedModules[moduleId]) { | ||||
| /******/ 			return installedModules[moduleId].exports; | ||||
| /******/ 		} | ||||
| /******/ 		// Create a new module (and put it into the cache) | ||||
| /******/ 		var module = installedModules[moduleId] = { | ||||
| /******/ 			i: moduleId, | ||||
| /******/ 			l: false, | ||||
| /******/ 			exports: {} | ||||
| /******/ 		}; | ||||
| /******/ | ||||
| /******/ 		// Execute the module function | ||||
| /******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); | ||||
| /******/ | ||||
| /******/ 		// Flag the module as loaded | ||||
| /******/ 		module.l = true; | ||||
| /******/ | ||||
| /******/ 		// Return the exports of the module | ||||
| /******/ 		return module.exports; | ||||
| /******/ 	} | ||||
| /******/ | ||||
| /******/ | ||||
| /******/ 	// expose the modules object (__webpack_modules__) | ||||
| /******/ 	__webpack_require__.m = modules; | ||||
| /******/ | ||||
| /******/ 	// expose the module cache | ||||
| /******/ 	__webpack_require__.c = installedModules; | ||||
| /******/ | ||||
| /******/ 	// define getter function for harmony exports | ||||
| /******/ 	__webpack_require__.d = function(exports, name, getter) { | ||||
| /******/ 		if(!__webpack_require__.o(exports, name)) { | ||||
| /******/ 			Object.defineProperty(exports, name, { enumerable: true, get: getter }); | ||||
| /******/ 		} | ||||
| /******/ 	}; | ||||
| /******/ | ||||
| /******/ 	// define __esModule on exports | ||||
| /******/ 	__webpack_require__.r = function(exports) { | ||||
| /******/ 		if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { | ||||
| /******/ 			Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||||
| /******/ 		} | ||||
| /******/ 		Object.defineProperty(exports, '__esModule', { value: true }); | ||||
| /******/ 	}; | ||||
| /******/ | ||||
| /******/ 	// create a fake namespace object | ||||
| /******/ 	// mode & 1: value is a module id, require it | ||||
| /******/ 	// mode & 2: merge all properties of value into the ns | ||||
| /******/ 	// mode & 4: return value when already ns object | ||||
| /******/ 	// mode & 8|1: behave like require | ||||
| /******/ 	__webpack_require__.t = function(value, mode) { | ||||
| /******/ 		if(mode & 1) value = __webpack_require__(value); | ||||
| /******/ 		if(mode & 8) return value; | ||||
| /******/ 		if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; | ||||
| /******/ 		var ns = Object.create(null); | ||||
| /******/ 		__webpack_require__.r(ns); | ||||
| /******/ 		Object.defineProperty(ns, 'default', { enumerable: true, value: value }); | ||||
| /******/ 		if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); | ||||
| /******/ 		return ns; | ||||
| /******/ 	}; | ||||
| /******/ | ||||
| /******/ 	// getDefaultExport function for compatibility with non-harmony modules | ||||
| /******/ 	__webpack_require__.n = function(module) { | ||||
| /******/ 		var getter = module && module.__esModule ? | ||||
| /******/ 			function getDefault() { return module['default']; } : | ||||
| /******/ 			function getModuleExports() { return module; }; | ||||
| /******/ 		__webpack_require__.d(getter, 'a', getter); | ||||
| /******/ 		return getter; | ||||
| /******/ 	}; | ||||
| /******/ | ||||
| /******/ 	// Object.prototype.hasOwnProperty.call | ||||
| /******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; | ||||
| /******/ | ||||
| /******/ 	// __webpack_public_path__ | ||||
| /******/ 	__webpack_require__.p = ""; | ||||
| /******/ | ||||
| /******/ | ||||
| /******/ 	// Load entry module and return exports | ||||
| /******/ 	return __webpack_require__(__webpack_require__.s = "fb15"); | ||||
| /******/ }) | ||||
| /************************************************************************/ | ||||
| /******/ ({ | ||||
|  | ||||
| /***/ "5941": | ||||
| /***/ (function(module, exports, __webpack_require__) { | ||||
|  | ||||
| // extracted by mini-css-extract-plugin | ||||
|  | ||||
| /***/ }), | ||||
|  | ||||
| /***/ "f6fd": | ||||
| /***/ (function(module, exports) { | ||||
|  | ||||
| // document.currentScript polyfill by Adam Miller | ||||
|  | ||||
| // MIT license | ||||
|  | ||||
| (function(document){ | ||||
|   var currentScript = "currentScript", | ||||
|       scripts = document.getElementsByTagName('script'); // Live NodeList collection | ||||
|  | ||||
|   // If browser needs currentScript polyfill, add get currentScript() to the document object | ||||
|   if (!(currentScript in document)) { | ||||
|     Object.defineProperty(document, currentScript, { | ||||
|       get: function(){ | ||||
|  | ||||
|         // IE 6-10 supports script readyState | ||||
|         // IE 10+ support stack trace | ||||
|         try { throw new Error(); } | ||||
|         catch (err) { | ||||
|  | ||||
|           // Find the second match for the "at" string to get file src url from stack. | ||||
|           // Specifically works with the format of stack traces in IE. | ||||
|           var i, res = ((/.*at [^\(]*\((.*):.+:.+\)$/ig).exec(err.stack) || [false])[1]; | ||||
|  | ||||
|           // For all scripts on the page, if src matches or if ready state is interactive, return the script tag | ||||
|           for(i in scripts){ | ||||
|             if(scripts[i].src == res || scripts[i].readyState == "interactive"){ | ||||
|               return scripts[i]; | ||||
|             } | ||||
|           } | ||||
|  | ||||
|           // If no match, return null | ||||
|           return null; | ||||
|         } | ||||
|       } | ||||
|     }); | ||||
|   } | ||||
| })(document); | ||||
|  | ||||
|  | ||||
| /***/ }), | ||||
|  | ||||
| /***/ "f87e": | ||||
| /***/ (function(module, __webpack_exports__, __webpack_require__) { | ||||
|  | ||||
| "use strict"; | ||||
| /* harmony import */ var _node_modules_mini_css_extract_plugin_dist_loader_js_ref_6_oneOf_1_0_node_modules_css_loader_dist_cjs_js_ref_6_oneOf_1_1_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_postcss_loader_src_index_js_ref_6_oneOf_1_2_node_modules_cache_loader_dist_cjs_js_ref_0_0_node_modules_vue_loader_lib_index_js_vue_loader_options_App_vue_vue_type_style_index_0_id_015b8bdf_scoped_true_lang_css___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("5941"); | ||||
| /* harmony import */ var _node_modules_mini_css_extract_plugin_dist_loader_js_ref_6_oneOf_1_0_node_modules_css_loader_dist_cjs_js_ref_6_oneOf_1_1_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_postcss_loader_src_index_js_ref_6_oneOf_1_2_node_modules_cache_loader_dist_cjs_js_ref_0_0_node_modules_vue_loader_lib_index_js_vue_loader_options_App_vue_vue_type_style_index_0_id_015b8bdf_scoped_true_lang_css___WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_mini_css_extract_plugin_dist_loader_js_ref_6_oneOf_1_0_node_modules_css_loader_dist_cjs_js_ref_6_oneOf_1_1_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_postcss_loader_src_index_js_ref_6_oneOf_1_2_node_modules_cache_loader_dist_cjs_js_ref_0_0_node_modules_vue_loader_lib_index_js_vue_loader_options_App_vue_vue_type_style_index_0_id_015b8bdf_scoped_true_lang_css___WEBPACK_IMPORTED_MODULE_0__); | ||||
| /* unused harmony reexport * */ | ||||
|  /* unused harmony default export */ var _unused_webpack_default_export = (_node_modules_mini_css_extract_plugin_dist_loader_js_ref_6_oneOf_1_0_node_modules_css_loader_dist_cjs_js_ref_6_oneOf_1_1_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_postcss_loader_src_index_js_ref_6_oneOf_1_2_node_modules_cache_loader_dist_cjs_js_ref_0_0_node_modules_vue_loader_lib_index_js_vue_loader_options_App_vue_vue_type_style_index_0_id_015b8bdf_scoped_true_lang_css___WEBPACK_IMPORTED_MODULE_0___default.a);  | ||||
|  | ||||
| /***/ }), | ||||
|  | ||||
| /***/ "fb15": | ||||
| /***/ (function(module, __webpack_exports__, __webpack_require__) { | ||||
|  | ||||
| "use strict"; | ||||
| // ESM COMPAT FLAG | ||||
| __webpack_require__.r(__webpack_exports__); | ||||
|  | ||||
| // CONCATENATED MODULE: ./node_modules/@vue/cli-service/lib/commands/build/setPublicPath.js | ||||
| // This file is imported into lib/wc client bundles. | ||||
|  | ||||
| if (typeof window !== 'undefined') { | ||||
|   if (true) { | ||||
|     __webpack_require__("f6fd") | ||||
|   } | ||||
|  | ||||
|   var i | ||||
|   if ((i = window.document.currentScript) && (i = i.src.match(/(.+\/)[^/]+\.js(\?.*)?$/))) { | ||||
|     __webpack_require__.p = i[1] // eslint-disable-line | ||||
|   } | ||||
| } | ||||
|  | ||||
| // Indicate to webpack that this file can be concatenated | ||||
| /* harmony default export */ var setPublicPath = (null); | ||||
|  | ||||
| // CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"5b04a8fd-vue-loader-template"}!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/App.vue?vue&type=template&id=015b8bdf&scoped=true& | ||||
| var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',[(_vm.$parent.titleTabActive==1)?_c('Records',{ref:"recordsPanel"}):_c('stream-table',{scopedSlots:_vm._u([{key:"default",fn:function(ref){ | ||||
| var stream = ref.row; | ||||
| return [(_vm.isRecording(stream))?_c('m-button',{attrs:{"blink":""},on:{"click":function($event){return _vm.stopRecord(stream)}}},[_vm._v("正在录制")]):_c('m-button',{on:{"click":function($event){return _vm.record(stream)}}},[_vm._v("录制")])]}}])})],1)} | ||||
| var staticRenderFns = [] | ||||
|  | ||||
|  | ||||
| // CONCATENATED MODULE: ./src/App.vue?vue&type=template&id=015b8bdf&scoped=true& | ||||
|  | ||||
| // CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"5b04a8fd-vue-loader-template"}!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/Records.vue?vue&type=template&id=675e088d& | ||||
| var Recordsvue_type_template_id_675e088d_render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('mu-data-table',{attrs:{"data":_vm.data,"columns":_vm.columns},scopedSlots:_vm._u([{key:"default",fn:function(ref){ | ||||
| var row = ref.row; | ||||
| return [_c('td',[_vm._v(_vm._s(row.Path))]),_c('td',[_vm._v(_vm._s(_vm.unitFormat(row.Size)))]),_c('td',[_vm._v(_vm._s(_vm.toDurationStr(row.Duration)))]),_c('td',[_c('mu-button',{attrs:{"icon":"","small":""},on:{"click":function($event){return _vm.play(row)}}},[_c('mu-icon',{attrs:{"value":"play_arrow"}})],1),_c('mu-button',{attrs:{"icon":"","small":""},on:{"click":function($event){return _vm.deleteFlv(row)}}},[_c('mu-icon',{attrs:{"value":"delete_forever"}})],1)],1)]}}])})} | ||||
| var Recordsvue_type_template_id_675e088d_staticRenderFns = [] | ||||
|  | ||||
|  | ||||
| // CONCATENATED MODULE: ./src/components/Records.vue?vue&type=template&id=675e088d& | ||||
|  | ||||
| // CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/Records.vue?vue&type=script&lang=js& | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
|  | ||||
| /* harmony default export */ var Recordsvue_type_script_lang_js_ = ({ | ||||
|     data() { | ||||
|         return { | ||||
|             data: [], | ||||
|             columns:[ | ||||
|                 { | ||||
|                     title:"文件路径" | ||||
|                 },{ | ||||
|                     title:"大小" | ||||
|                 },{ | ||||
|                     title:"时长" | ||||
|                 },{title:"操作"} | ||||
|             ] | ||||
|         }; | ||||
|     }, | ||||
|     methods: { | ||||
|         play(item) { | ||||
|             this.ajax.get( | ||||
|                 "/record/flv/play", | ||||
|                 { streamPath: item.Path.replace(".flv", "") }, | ||||
|                 x => { | ||||
|                     if (x == "success") { | ||||
|                         this.ajax.getJSON("/record/flv/list", x => this.data = x); | ||||
|                         this.$toast.success("开始发布"); | ||||
|                     } else { | ||||
|                         this.$toast.error(x); | ||||
|                     } | ||||
|                 } | ||||
|             ); | ||||
|         }, | ||||
|         deleteFlv(item) { | ||||
|             this.$confirm("是否删除Flv文件", "提示").then(result => { | ||||
|                 if (result) { | ||||
|                     return this.ajax.get( | ||||
|                         "/record/flv/delete", | ||||
|                         { streamPath: item.Path.replace(".flv", "") }, | ||||
|                         x => { | ||||
|                             if (x == "success") { | ||||
|                                 this.$toast.success("删除成功"); | ||||
|                             } else { | ||||
|                                 this.$toast.error(x); | ||||
|                             } | ||||
|                         } | ||||
|                     ); | ||||
|                 } | ||||
|             }); | ||||
|         }, | ||||
|         toDurationStr(value) { | ||||
|             if (value > 1000) { | ||||
|                 let s = value / 1000; | ||||
|                 if (s > 60) { | ||||
|                     s = s | 0; | ||||
|                     let min = (s / 60) >> 0; | ||||
|                     if (min > 60) { | ||||
|                         let hour = (min / 60) >> 0; | ||||
|                         return hour + "hour" + (min % 60) + "min"; | ||||
|                     } else { | ||||
|                         return min + "min" + (s % 60) + "s"; | ||||
|                     } | ||||
|                 } else { | ||||
|                     return s.toFixed(3) + "s"; | ||||
|                 } | ||||
|             } else { | ||||
|                 return value + "ms"; | ||||
|             } | ||||
|         } | ||||
|     }, | ||||
|     mounted() { | ||||
|         this.ajax.getJSON("/record/flv/list", x => this.data = x); | ||||
|     } | ||||
| }); | ||||
|  | ||||
| // CONCATENATED MODULE: ./src/components/Records.vue?vue&type=script&lang=js& | ||||
|  /* harmony default export */ var components_Recordsvue_type_script_lang_js_ = (Recordsvue_type_script_lang_js_);  | ||||
| // CONCATENATED MODULE: ./node_modules/vue-loader/lib/runtime/componentNormalizer.js | ||||
| /* globals __VUE_SSR_CONTEXT__ */ | ||||
|  | ||||
| // IMPORTANT: Do NOT use ES2015 features in this file (except for modules). | ||||
| // This module is a runtime utility for cleaner component module output and will | ||||
| // be included in the final webpack user bundle. | ||||
|  | ||||
| function normalizeComponent ( | ||||
|   scriptExports, | ||||
|   render, | ||||
|   staticRenderFns, | ||||
|   functionalTemplate, | ||||
|   injectStyles, | ||||
|   scopeId, | ||||
|   moduleIdentifier, /* server only */ | ||||
|   shadowMode /* vue-cli only */ | ||||
| ) { | ||||
|   // Vue.extend constructor export interop | ||||
|   var options = typeof scriptExports === 'function' | ||||
|     ? scriptExports.options | ||||
|     : scriptExports | ||||
|  | ||||
|   // render functions | ||||
|   if (render) { | ||||
|     options.render = render | ||||
|     options.staticRenderFns = staticRenderFns | ||||
|     options._compiled = true | ||||
|   } | ||||
|  | ||||
|   // functional template | ||||
|   if (functionalTemplate) { | ||||
|     options.functional = true | ||||
|   } | ||||
|  | ||||
|   // scopedId | ||||
|   if (scopeId) { | ||||
|     options._scopeId = 'data-v-' + scopeId | ||||
|   } | ||||
|  | ||||
|   var hook | ||||
|   if (moduleIdentifier) { // server build | ||||
|     hook = function (context) { | ||||
|       // 2.3 injection | ||||
|       context = | ||||
|         context || // cached call | ||||
|         (this.$vnode && this.$vnode.ssrContext) || // stateful | ||||
|         (this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext) // functional | ||||
|       // 2.2 with runInNewContext: true | ||||
|       if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') { | ||||
|         context = __VUE_SSR_CONTEXT__ | ||||
|       } | ||||
|       // inject component styles | ||||
|       if (injectStyles) { | ||||
|         injectStyles.call(this, context) | ||||
|       } | ||||
|       // register component module identifier for async chunk inferrence | ||||
|       if (context && context._registeredComponents) { | ||||
|         context._registeredComponents.add(moduleIdentifier) | ||||
|       } | ||||
|     } | ||||
|     // used by ssr in case component is cached and beforeCreate | ||||
|     // never gets called | ||||
|     options._ssrRegister = hook | ||||
|   } else if (injectStyles) { | ||||
|     hook = shadowMode | ||||
|       ? function () { injectStyles.call(this, this.$root.$options.shadowRoot) } | ||||
|       : injectStyles | ||||
|   } | ||||
|  | ||||
|   if (hook) { | ||||
|     if (options.functional) { | ||||
|       // for template-only hot-reload because in that case the render fn doesn't | ||||
|       // go through the normalizer | ||||
|       options._injectStyles = hook | ||||
|       // register for functional component in vue file | ||||
|       var originalRender = options.render | ||||
|       options.render = function renderWithStyleInjection (h, context) { | ||||
|         hook.call(context) | ||||
|         return originalRender(h, context) | ||||
|       } | ||||
|     } else { | ||||
|       // inject component registration as beforeCreate hook | ||||
|       var existing = options.beforeCreate | ||||
|       options.beforeCreate = existing | ||||
|         ? [].concat(existing, hook) | ||||
|         : [hook] | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   return { | ||||
|     exports: scriptExports, | ||||
|     options: options | ||||
|   } | ||||
| } | ||||
|  | ||||
| // CONCATENATED MODULE: ./src/components/Records.vue | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| /* normalize component */ | ||||
|  | ||||
| var component = normalizeComponent( | ||||
|   components_Recordsvue_type_script_lang_js_, | ||||
|   Recordsvue_type_template_id_675e088d_render, | ||||
|   Recordsvue_type_template_id_675e088d_staticRenderFns, | ||||
|   false, | ||||
|   null, | ||||
|   null, | ||||
|   null | ||||
|    | ||||
| ) | ||||
|  | ||||
| /* harmony default export */ var Records = (component.exports); | ||||
| // CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/App.vue?vue&type=script&lang=js& | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
|  | ||||
|  | ||||
| /* harmony default export */ var Appvue_type_script_lang_js_ = ({ | ||||
|     components: { | ||||
|         Records: Records | ||||
|     }, | ||||
|     data() { | ||||
|         return {}; | ||||
|     }, | ||||
|     methods: { | ||||
|         record(item) { | ||||
|             let append = false; | ||||
|             this.$confirm( | ||||
|                 h => | ||||
|                     h("mu-switch", { | ||||
|                         props: { | ||||
|                             label: "追加模式" | ||||
|                         }, | ||||
|                         on: { | ||||
|                             change(value) { | ||||
|                                 append = value; | ||||
|                             } | ||||
|                         } | ||||
|                     }), | ||||
|                 "是否开始录制" | ||||
|             ).then(result => { | ||||
|                 if (result) { | ||||
|                     this.ajax.get( | ||||
|                         "/record/flv?append=" + append, | ||||
|                         { streamPath: item.StreamPath }, | ||||
|                         x => { | ||||
|                             if (x == "success") { | ||||
|                                 this.$toast.success( | ||||
|                                     "开始录制" + (append ? "(追加模式)" : "") | ||||
|                                 ); | ||||
|                             } else { | ||||
|                                 this.$toast.error(x); | ||||
|                             } | ||||
|                         } | ||||
|                     ); | ||||
|                 } | ||||
|             }); | ||||
|         }, | ||||
|         stopRecord(item) { | ||||
|             this.$confirm("是否停止录制", "提示").then(result => { | ||||
|                 if(result) | ||||
|                 { | ||||
|                     this.ajax.get( | ||||
|                         "/record/flv/stop", | ||||
|                         { streamPath: item.StreamPath }, | ||||
|                         x => { | ||||
|                             if (x == "success") { | ||||
|                                 this.$toast.success("停止录制"); | ||||
|                             } else { | ||||
|                                 this.$toast.error(x); | ||||
|                             } | ||||
|                         } | ||||
|                     ); | ||||
|                 } | ||||
|             }); | ||||
|         }, | ||||
|         isRecording(item) { | ||||
|             return ( | ||||
|                 item.SubscriberInfo && | ||||
|                 item.SubscriberInfo.find(x => x.Type == "FlvRecord") | ||||
|             ); | ||||
|         } | ||||
|     }, | ||||
|     mounted() { | ||||
|         this.$parent.titleTabs = ["StreamList", "录制的视频"]; | ||||
|     } | ||||
| }); | ||||
|  | ||||
| // CONCATENATED MODULE: ./src/App.vue?vue&type=script&lang=js& | ||||
|  /* harmony default export */ var src_Appvue_type_script_lang_js_ = (Appvue_type_script_lang_js_);  | ||||
| // EXTERNAL MODULE: ./src/App.vue?vue&type=style&index=0&id=015b8bdf&scoped=true&lang=css& | ||||
| var Appvue_type_style_index_0_id_015b8bdf_scoped_true_lang_css_ = __webpack_require__("f87e"); | ||||
|  | ||||
| // CONCATENATED MODULE: ./src/App.vue | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| /* normalize component */ | ||||
|  | ||||
| var App_component = normalizeComponent( | ||||
|   src_Appvue_type_script_lang_js_, | ||||
|   render, | ||||
|   staticRenderFns, | ||||
|   false, | ||||
|   null, | ||||
|   "015b8bdf", | ||||
|   null | ||||
|    | ||||
| ) | ||||
|  | ||||
| /* harmony default export */ var App = (App_component.exports); | ||||
| // CONCATENATED MODULE: ./node_modules/@vue/cli-service/lib/commands/build/entry-lib.js | ||||
|  | ||||
|  | ||||
| /* harmony default export */ var entry_lib = __webpack_exports__["default"] = (App); | ||||
|  | ||||
|  | ||||
|  | ||||
| /***/ }) | ||||
|  | ||||
| /******/ })["default"]; | ||||
| }); | ||||
| //# sourceMappingURL=plugin-record.umd.js.map | ||||
							
								
								
									
										1
									
								
								ui/dist/plugin-record.umd.js.map
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								ui/dist/plugin-record.umd.js.map
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								ui/dist/plugin-record.umd.min.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								ui/dist/plugin-record.umd.min.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										1
									
								
								ui/dist/plugin-record.umd.min.js.map
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								ui/dist/plugin-record.umd.min.js.map
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										9560
									
								
								ui/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										9560
									
								
								ui/package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,15 +0,0 @@ | ||||
| { | ||||
|     "name": "dashboard", | ||||
|     "version": "1.0.0", | ||||
|     "description": "dashboard of record plugin for monibuca", | ||||
|     "main": "index.js", | ||||
|     "scripts": { | ||||
|         "build": "vue-cli-service build --target lib --name plugin-record" | ||||
|     }, | ||||
|     "author": "dexter", | ||||
|     "license": "ISC", | ||||
|     "devDependencies": { | ||||
|         "@vue/cli-service": "^4.2.3", | ||||
|         "vue-template-compiler": "^2.6.11" | ||||
|     } | ||||
| } | ||||
							
								
								
									
										135
									
								
								ui/src/App.vue
									
									
									
									
									
								
							
							
						
						
									
										135
									
								
								ui/src/App.vue
									
									
									
									
									
								
							| @@ -1,135 +0,0 @@ | ||||
| <template> | ||||
|     <div> | ||||
|         <Records ref="recordsPanel" v-if="$parent.titleTabActive==1" /> | ||||
|         <stream-table v-else> | ||||
|             <template v-slot="{row:stream}"> | ||||
|                 <m-button v-if="isRecording(stream)" @click="stopRecord(stream)" blink>正在录制</m-button> | ||||
|                 <m-button v-else @click="record(stream)">录制</m-button> | ||||
|             </template> | ||||
|         </stream-table> | ||||
|     </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import Records from "./components/Records"; | ||||
| export default { | ||||
|     components: { | ||||
|         Records | ||||
|     }, | ||||
|     data() { | ||||
|         return {}; | ||||
|     }, | ||||
|     methods: { | ||||
|         record(item) { | ||||
|             let append = false; | ||||
|             this.$confirm( | ||||
|                 h => | ||||
|                     h("mu-switch", { | ||||
|                         props: { | ||||
|                             label: "追加模式" | ||||
|                         }, | ||||
|                         on: { | ||||
|                             change(value) { | ||||
|                                 append = value; | ||||
|                             } | ||||
|                         } | ||||
|                     }), | ||||
|                 "是否开始录制" | ||||
|             ).then(result => { | ||||
|                 if (result) { | ||||
|                     this.ajax.get( | ||||
|                         "/record/flv?append=" + append, | ||||
|                         { streamPath: item.StreamPath }, | ||||
|                         x => { | ||||
|                             if (x == "success") { | ||||
|                                 this.$toast.success( | ||||
|                                     "开始录制" + (append ? "(追加模式)" : "") | ||||
|                                 ); | ||||
|                             } else { | ||||
|                                 this.$toast.error(x); | ||||
|                             } | ||||
|                         } | ||||
|                     ); | ||||
|                 } | ||||
|             }); | ||||
|         }, | ||||
|         stopRecord(item) { | ||||
|             this.$confirm("是否停止录制", "提示").then(result => { | ||||
|                 if(result) | ||||
|                 { | ||||
|                     this.ajax.get( | ||||
|                         "/record/flv/stop", | ||||
|                         { streamPath: item.StreamPath }, | ||||
|                         x => { | ||||
|                             if (x == "success") { | ||||
|                                 this.$toast.success("停止录制"); | ||||
|                             } else { | ||||
|                                 this.$toast.error(x); | ||||
|                             } | ||||
|                         } | ||||
|                     ); | ||||
|                 } | ||||
|             }); | ||||
|         }, | ||||
|         isRecording(item) { | ||||
|             return ( | ||||
|                 item.SubscriberInfo && | ||||
|                 item.SubscriberInfo.find(x => x.Type == "FlvRecord") | ||||
|             ); | ||||
|         } | ||||
|     }, | ||||
|     mounted() { | ||||
|         this.$parent.titleTabs = ["StreamList", "录制的视频"]; | ||||
|     } | ||||
| }; | ||||
| </script> | ||||
|  | ||||
| <style scoped> | ||||
| @keyframes recording { | ||||
|     0% { | ||||
|         opacity: 0.2; | ||||
|     } | ||||
|     50% { | ||||
|         opacity: 1; | ||||
|     } | ||||
|     100% { | ||||
|         opacity: 0.2; | ||||
|     } | ||||
| } | ||||
|  | ||||
| .recording { | ||||
|     animation: recording 1s infinite; | ||||
| } | ||||
|  | ||||
| .layout { | ||||
|     padding-bottom: 30px; | ||||
|     display: flex; | ||||
|     flex-wrap: wrap; | ||||
| } | ||||
|  | ||||
| .room { | ||||
|     width: 250px; | ||||
|     margin: 10px; | ||||
|     text-align: left; | ||||
| } | ||||
|  | ||||
| .empty { | ||||
|     color: #ffc107; | ||||
|     width: 100%; | ||||
|     min-height: 500px; | ||||
|     display: flex; | ||||
|     justify-content: center; | ||||
|     align-items: center; | ||||
| } | ||||
|  | ||||
| .status { | ||||
|     position: fixed; | ||||
|     display: flex; | ||||
|     left: 5px; | ||||
|     bottom: 10px; | ||||
| } | ||||
|  | ||||
| .status > div { | ||||
|     margin: 0 5px; | ||||
| } | ||||
| </style> | ||||
| @@ -1,92 +0,0 @@ | ||||
| <template> | ||||
|     <mu-data-table :data="data" :columns="columns"> | ||||
|         <template #default="{row}"> | ||||
|             <td>{{row.Path}}</td> | ||||
|             <td>{{unitFormat(row.Size)}}</td> | ||||
|             <td>{{toDurationStr(row.Duration)}}</td> | ||||
|             <td> | ||||
|                 <mu-button @click="play(row)" icon small> | ||||
|                     <mu-icon value="play_arrow" /> | ||||
|                 </mu-button> | ||||
|                 <mu-button @click="deleteFlv(row)" icon small> | ||||
|                     <mu-icon value="delete_forever" /> | ||||
|                 </mu-button> | ||||
|             </td> | ||||
|         </template> | ||||
|     </mu-data-table> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| export default { | ||||
|     data() { | ||||
|         return { | ||||
|             data: [], | ||||
|             columns:[ | ||||
|                 { | ||||
|                     title:"文件路径" | ||||
|                 },{ | ||||
|                     title:"大小" | ||||
|                 },{ | ||||
|                     title:"时长" | ||||
|                 },{title:"操作"} | ||||
|             ] | ||||
|         }; | ||||
|     }, | ||||
|     methods: { | ||||
|         play(item) { | ||||
|             this.ajax.get( | ||||
|                 "/record/flv/play", | ||||
|                 { streamPath: item.Path.replace(".flv", "") }, | ||||
|                 x => { | ||||
|                     if (x == "success") { | ||||
|                         this.ajax.getJSON("/record/flv/list", x => this.data = x); | ||||
|                         this.$toast.success("开始发布"); | ||||
|                     } else { | ||||
|                         this.$toast.error(x); | ||||
|                     } | ||||
|                 } | ||||
|             ); | ||||
|         }, | ||||
|         deleteFlv(item) { | ||||
|             this.$confirm("是否删除Flv文件", "提示").then(result => { | ||||
|                 if (result) { | ||||
|                     return this.ajax.get( | ||||
|                         "/record/flv/delete", | ||||
|                         { streamPath: item.Path.replace(".flv", "") }, | ||||
|                         x => { | ||||
|                             if (x == "success") { | ||||
|                                 this.$toast.success("删除成功"); | ||||
|                             } else { | ||||
|                                 this.$toast.error(x); | ||||
|                             } | ||||
|                         } | ||||
|                     ); | ||||
|                 } | ||||
|             }); | ||||
|         }, | ||||
|         toDurationStr(value) { | ||||
|             if (value > 1000) { | ||||
|                 let s = value / 1000; | ||||
|                 if (s > 60) { | ||||
|                     s = s | 0; | ||||
|                     let min = (s / 60) >> 0; | ||||
|                     if (min > 60) { | ||||
|                         let hour = (min / 60) >> 0; | ||||
|                         return hour + "hour" + (min % 60) + "min"; | ||||
|                     } else { | ||||
|                         return min + "min" + (s % 60) + "s"; | ||||
|                     } | ||||
|                 } else { | ||||
|                     return s.toFixed(3) + "s"; | ||||
|                 } | ||||
|             } else { | ||||
|                 return value + "ms"; | ||||
|             } | ||||
|         } | ||||
|     }, | ||||
|     mounted() { | ||||
|         this.ajax.getJSON("/record/flv/list", x => this.data = x); | ||||
|     } | ||||
| }; | ||||
| </script> | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 langhuihui
					langhuihui