mirror of
https://github.com/Monibuca/plugin-rtsp.git
synced 2025-09-26 19:51:14 +08:00
更新UI
This commit is contained in:
83
client.go
83
client.go
@@ -375,7 +375,7 @@ func (this *RtspClient) AuthBasic(phase string, message string) bool {
|
||||
return false
|
||||
}
|
||||
if status, message := this.Read(); status && strings.Contains(message, "200") {
|
||||
this.track = ParseMedia(message)
|
||||
this.track = this.ParseMedia(message)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
@@ -391,7 +391,7 @@ func (this *RtspClient) AuthDigest(phase string, message string) bool {
|
||||
return false
|
||||
}
|
||||
if status, message := this.Read(); status && strings.Contains(message, "200") {
|
||||
this.track = ParseMedia(message)
|
||||
this.track = this.ParseMedia(message)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
@@ -455,48 +455,49 @@ func ParseSession(header string) string {
|
||||
}
|
||||
return ""
|
||||
}
|
||||
func ParseMedia(header string) []string {
|
||||
letters := []string{}
|
||||
mparsed := strings.Split(header, "\r\n")
|
||||
paste := ""
|
||||
|
||||
// if true {
|
||||
// log.Println("headers", header)
|
||||
// }
|
||||
// func ParseMedia(header string) []string {
|
||||
// letters := []string{}
|
||||
// mparsed := strings.Split(header, "\r\n")
|
||||
// paste := ""
|
||||
|
||||
for _, element := range mparsed {
|
||||
if strings.Contains(element, "a=control:") && !strings.Contains(element, "*") {
|
||||
paste = element[10:]
|
||||
if strings.Contains(element, "/") {
|
||||
striped := strings.Split(element, "/")
|
||||
paste = striped[len(striped)-1]
|
||||
}
|
||||
letters = append(letters, paste)
|
||||
}
|
||||
// // if true {
|
||||
// // log.Println("headers", header)
|
||||
// // }
|
||||
|
||||
dimensionsPrefix := "a=x-dimensions:"
|
||||
if strings.HasPrefix(element, dimensionsPrefix) {
|
||||
dims := []int{}
|
||||
for _, s := range strings.Split(element[len(dimensionsPrefix):], ",") {
|
||||
v := 0
|
||||
fmt.Sscanf(s, "%d", &v)
|
||||
if v <= 0 {
|
||||
break
|
||||
}
|
||||
dims = append(dims, v)
|
||||
}
|
||||
if len(dims) == 2 {
|
||||
VideoWidth = dims[0]
|
||||
VideoHeight = dims[1]
|
||||
}
|
||||
}
|
||||
if strings.Contains(element, "sprop-parameter-sets") {
|
||||
group := spropReg.FindAllStringSubmatch(element, -1)
|
||||
log.Println(group[1])
|
||||
}
|
||||
}
|
||||
return letters
|
||||
}
|
||||
// for _, element := range mparsed {
|
||||
// if strings.Contains(element, "a=control:") && !strings.Contains(element, "*") {
|
||||
// paste = element[10:]
|
||||
// if strings.Contains(element, "/") {
|
||||
// striped := strings.Split(element, "/")
|
||||
// paste = striped[len(striped)-1]
|
||||
// }
|
||||
// letters = append(letters, paste)
|
||||
// }
|
||||
|
||||
// dimensionsPrefix := "a=x-dimensions:"
|
||||
// if strings.HasPrefix(element, dimensionsPrefix) {
|
||||
// dims := []int{}
|
||||
// for _, s := range strings.Split(element[len(dimensionsPrefix):], ",") {
|
||||
// v := 0
|
||||
// fmt.Sscanf(s, "%d", &v)
|
||||
// if v <= 0 {
|
||||
// break
|
||||
// }
|
||||
// dims = append(dims, v)
|
||||
// }
|
||||
// if len(dims) == 2 {
|
||||
// VideoWidth = dims[0]
|
||||
// VideoHeight = dims[1]
|
||||
// }
|
||||
// }
|
||||
// if strings.Contains(element, "sprop-parameter-sets") {
|
||||
// group := spropReg.FindAllStringSubmatch(element, -1)
|
||||
// log.Println(group[1])
|
||||
// }
|
||||
// }
|
||||
// return letters
|
||||
// }
|
||||
func GetMD5Hash(text string) string {
|
||||
hash := md5.Sum([]byte(text))
|
||||
return hex.EncodeToString(hash[:])
|
||||
|
@@ -1,150 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<Button @click="addPull" type="success">拉流转发</Button>
|
||||
<Spin fix v-if="Rooms==null">
|
||||
<Icon type="ios-loading" size="18" class="demo-spin-icon-load"></Icon>
|
||||
<div>Loading</div>
|
||||
</Spin>
|
||||
<div v-else-if="Rooms.length==0" class="empty">
|
||||
<Icon type="md-wine" size="50" />没有任何房间
|
||||
</div>
|
||||
<div class="layout" v-else>
|
||||
<Card v-for="item in Rooms" :key="item.RoomInfo.StreamPath" class="room">
|
||||
<p slot="title">{{item.RoomInfo.StreamPath}}</p>
|
||||
<StartTime slot="extra" :value="item.RoomInfo.StartTime"></StartTime>
|
||||
<div class="hls-info">
|
||||
<Progress :stroke-width="20" :percent="Math.ceil(item.BufferRate)" text-inside />
|
||||
<div>📜{{item.SyncCount}}</div>
|
||||
</div>
|
||||
<Button @click="showHeader(item)">
|
||||
<Icon type="ios-code-working" />
|
||||
</Button>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
let listES = null;
|
||||
import StartTime from "./components/StartTime";
|
||||
export default {
|
||||
components: {
|
||||
StartTime
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
currentStream: null,
|
||||
Rooms: null,
|
||||
remoteAddr: "",
|
||||
streamPath: ""
|
||||
};
|
||||
},
|
||||
|
||||
methods: {
|
||||
fetchlist() {
|
||||
listES = new EventSource("/rtsp/list");
|
||||
listES.onmessage = evt => {
|
||||
if (!evt.data) return;
|
||||
this.Rooms = JSON.parse(evt.data) || [];
|
||||
this.Rooms.sort((a, b) =>
|
||||
a.RoomInfo.StreamPath > b.RoomInfo.StreamPath ? 1 : -1
|
||||
);
|
||||
};
|
||||
},
|
||||
showHeader(item) {
|
||||
this.$Modal.info({
|
||||
title: "RTSP Header",
|
||||
width: "1000px",
|
||||
scrollable: true,
|
||||
content: item.Header
|
||||
});
|
||||
},
|
||||
addPull() {
|
||||
this.$Modal.confirm({
|
||||
title: "拉流转发",
|
||||
onOk:()=> {
|
||||
window.ajax
|
||||
.getJSON("/rtsp/pull", {
|
||||
target: this.remoteAddr,
|
||||
streamPath: this.streamPath
|
||||
})
|
||||
.then(x => {
|
||||
if (x.code == 0) {
|
||||
this.$Message.success({
|
||||
title: "提示",
|
||||
content: "已启动拉流"
|
||||
});
|
||||
} else {
|
||||
this.$Message.error({
|
||||
title: "提示",
|
||||
content: x.msg
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
render: h => {
|
||||
return h("div", {}, [
|
||||
h("Input", {
|
||||
props: {
|
||||
value: this.remoteAddr,
|
||||
autofocus: true,
|
||||
placeholder: "Please enter URL of rtsp..."
|
||||
},
|
||||
on: {
|
||||
input: val => {
|
||||
this.remoteAddr = val;
|
||||
}
|
||||
}
|
||||
}),
|
||||
h("Input", {
|
||||
props: {
|
||||
value: this.streamPath,
|
||||
placeholder:
|
||||
"Please enter streamPath to publish."
|
||||
},
|
||||
on: {
|
||||
input: val => {
|
||||
this.streamPath = val;
|
||||
}
|
||||
}
|
||||
})
|
||||
]);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.fetchlist();
|
||||
},
|
||||
deactivated() {
|
||||
listES.close();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@import url("/iview.css");
|
||||
.empty {
|
||||
color: #eb5e46;
|
||||
width: 100%;
|
||||
min-height: 500px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.layout {
|
||||
padding-bottom: 30px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.ts-info {
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
.hls-info {
|
||||
width: 350px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
</style>
|
@@ -1,8 +0,0 @@
|
||||
<meta charset="utf-8">
|
||||
<title>plugin-rtsp demo</title>
|
||||
<script src="https://unpkg.com/vue"></script>
|
||||
<script src="./plugin-rtsp.js"></script>
|
||||
|
||||
|
||||
<plugin-rtsp></plugin-rtsp>
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
2
dashboard/ui/plugin-rtsp.min.js
vendored
2
dashboard/ui/plugin-rtsp.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
9
go.mod
9
go.mod
@@ -1,10 +1,5 @@
|
||||
module github.com/Monibuca/rtspplugin
|
||||
module github.com/Monibuca/plugin-rtsp
|
||||
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/Monibuca/engine v1.1.0
|
||||
github.com/falconray0704/gortmp v0.0.0-20170613085150-e3f9bb02c7c8
|
||||
github.com/zhangpeihao/goamf v0.0.0-20140409082417-3ff2c19514a8 // indirect
|
||||
github.com/zhangpeihao/log v0.0.0-20170117094621-62e921e41859
|
||||
)
|
||||
require github.com/Monibuca/engine v1.2.1
|
||||
|
22
go.sum
22
go.sum
@@ -1,30 +1,44 @@
|
||||
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.1.0 h1:X/dEUWpASCPESYx1cGXk5pp73Egiou5obGUEfrRZUdg=
|
||||
github.com/Monibuca/engine v1.1.0/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/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/falconray0704/gortmp v0.0.0-20170613085150-e3f9bb02c7c8 h1:Bkx+0neYCcHW7BUeVCbR2GOn47NesdImh8nHHOKccD4=
|
||||
github.com/falconray0704/gortmp v0.0.0-20170613085150-e3f9bb02c7c8/go.mod h1:/JBZajtCDe9Z4j84v5QWo4PLn1K6jcBHh6qXN/bm/vw=
|
||||
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/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/pixelbender/go-sdp v1.0.0 h1:hLP2ALBN4sLpgp2r3EDcFUSN3AyOkg1jonuWEJniotY=
|
||||
github.com/pixelbender/go-sdp v1.0.0/go.mod h1:6IBlz9+BrUHoFTea7gcp4S54khtOhjCW/nVDLhmZBAs=
|
||||
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=
|
||||
github.com/teris-io/shortid v0.0.0-20171029131806-771a37caa5cf h1:Z2X3Os7oRzpdJ75iPqWZc0HeJWFYNCvKsfpQwFpRNTA=
|
||||
github.com/teris-io/shortid v0.0.0-20171029131806-771a37caa5cf/go.mod h1:M8agBzgqHIhgj7wEn9/0hJUZcrvt9VY+Ln+S1I5Mha0=
|
||||
github.com/zhangpeihao/goamf v0.0.0-20140409082417-3ff2c19514a8 h1:r1JUI0wuHlgRb8jNd3zPBBkjUdrjpVKr8SdJWc8ntg8=
|
||||
github.com/zhangpeihao/goamf v0.0.0-20140409082417-3ff2c19514a8/go.mod h1:RZd/IqzNpFANwOB9rVmsnAYpo/6KesK4PqrN1a5cRgg=
|
||||
github.com/zhangpeihao/log v0.0.0-20170117094621-62e921e41859 h1:vrlOUrBlpVmIvWsd8FhUwXWzdYqYcgFzbf8j1qPkGM8=
|
||||
github.com/zhangpeihao/log v0.0.0-20170117094621-62e921e41859/go.mod h1:OAvmouyIV28taMw4SC4+hSnouObQqQkTQNOhU3Zowl0=
|
||||
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=
|
||||
|
10
main.go
10
main.go
@@ -23,12 +23,10 @@ var config = struct {
|
||||
|
||||
func init() {
|
||||
InstallPlugin(&PluginConfig{
|
||||
Name: "RTSP",
|
||||
Type: PLUGIN_PUBLISHER | PLUGIN_HOOK,
|
||||
Version: "1.0.0",
|
||||
Config: &config,
|
||||
UI: util.CurrentDir("dashboard", "ui", "plugin-rtsp.min.js"),
|
||||
Run: runPlugin,
|
||||
Name: "RTSP",
|
||||
Type: PLUGIN_PUBLISHER | PLUGIN_HOOK,
|
||||
Config: &config,
|
||||
Run: runPlugin,
|
||||
})
|
||||
}
|
||||
func runPlugin() {
|
||||
|
19
ui/dist/demo.html
vendored
Normal file
19
ui/dist/demo.html
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
<meta charset="utf-8">
|
||||
<title>plugin-rtsp demo</title>
|
||||
<script src="https://unpkg.com/vue"></script>
|
||||
<script src="./plugin-rtsp.umd.js"></script>
|
||||
|
||||
<link rel="stylesheet" href="./plugin-rtsp.css">
|
||||
|
||||
|
||||
<div id="app">
|
||||
<demo></demo>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
new Vue({
|
||||
components: {
|
||||
demo: plugin-rtsp
|
||||
}
|
||||
}).$mount('#app')
|
||||
</script>
|
456
ui/dist/plugin-rtsp.common.js
vendored
Normal file
456
ui/dist/plugin-rtsp.common.js
vendored
Normal file
@@ -0,0 +1,456 @@
|
||||
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");
|
||||
/******/ })
|
||||
/************************************************************************/
|
||||
/******/ ({
|
||||
|
||||
/***/ "034f":
|
||||
/***/ (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_lang_css___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("85ec");
|
||||
/* 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_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_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_lang_css___WEBPACK_IMPORTED_MODULE_0___default.a);
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ "85ec":
|
||||
/***/ (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);
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ "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":"29918b3a-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=6fc0793e&
|
||||
var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{directives:[{name:"loading",rawName:"v-loading",value:(_vm.Rooms==null),expression:"Rooms==null"}]},[(_vm.Rooms==null)?_c('div'):(_vm.Rooms.length==0)?_c('div',{staticClass:"empty"},[_c('Icon',{attrs:{"type":"md-wine","size":"50"}}),_vm._v("没有任何房间 ")],1):_c('div',{staticClass:"layout"},_vm._l((_vm.Rooms),function(item){return _c('Card',{key:item.RoomInfo.StreamPath,staticClass:"room"},[_c('p',{attrs:{"slot":"title"},slot:"title"},[_vm._v(_vm._s(item.RoomInfo.StreamPath))]),_c('StartTime',{attrs:{"slot":"extra","value":item.RoomInfo.StartTime},slot:"extra"}),_c('div',{staticClass:"hls-info"},[_c('Progress',{attrs:{"stroke-width":20,"percent":Math.ceil(item.BufferRate),"text-inside":""}}),_c('div',[_vm._v("📜"+_vm._s(item.SyncCount))])],1),_c('Button',{on:{"click":function($event){return _vm.showHeader(item)}}},[_c('Icon',{attrs:{"type":"ios-code-working"}})],1)],1)}),1),_c('mu-dialog',{attrs:{"title":"拉流转发","width":"360","open":_vm.openPull},on:{"update:open":function($event){_vm.openPull=$event}}},[_c('mu-text-field',{attrs:{"label":"rtsp url","label-float":"","help-text":"Please enter URL of rtsp..."},model:{value:(_vm.remoteAddr),callback:function ($$v) {_vm.remoteAddr=$$v},expression:"remoteAddr"}}),_c('mu-text-field',{attrs:{"label":"streamPath","label-float":"","help-text":"Please enter streamPath to publish."},model:{value:(_vm.streamPath),callback:function ($$v) {_vm.streamPath=$$v},expression:"streamPath"}}),_c('mu-button',{attrs:{"slot":"actions","flat":"","color":"primary"},on:{"click":_vm.addPull},slot:"actions"},[_vm._v("确定")])],1)],1)}
|
||||
var staticRenderFns = []
|
||||
|
||||
|
||||
// CONCATENATED MODULE: ./src/App.vue?vue&type=template&id=6fc0793e&
|
||||
|
||||
// CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"29918b3a-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/StartTime.vue?vue&type=template&id=2632acaa&scoped=true&
|
||||
var StartTimevue_type_template_id_2632acaa_scoped_true_render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('Poptip',{attrs:{"trigger":"hover","content":'⌚️'+ new Date(_vm.value).toLocaleString()}},[_c('Time',{attrs:{"time":new Date(_vm.value)}})],1)}
|
||||
var StartTimevue_type_template_id_2632acaa_scoped_true_staticRenderFns = []
|
||||
|
||||
|
||||
// CONCATENATED MODULE: ./src/components/StartTime.vue?vue&type=template&id=2632acaa&scoped=true&
|
||||
|
||||
// CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/StartTime.vue?vue&type=script&lang=js&
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
/* harmony default export */ var StartTimevue_type_script_lang_js_ = ({
|
||||
name: "StartTime",
|
||||
props: {
|
||||
value: String
|
||||
}
|
||||
});
|
||||
|
||||
// CONCATENATED MODULE: ./src/components/StartTime.vue?vue&type=script&lang=js&
|
||||
/* harmony default export */ var components_StartTimevue_type_script_lang_js_ = (StartTimevue_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/StartTime.vue
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* normalize component */
|
||||
|
||||
var component = normalizeComponent(
|
||||
components_StartTimevue_type_script_lang_js_,
|
||||
StartTimevue_type_template_id_2632acaa_scoped_true_render,
|
||||
StartTimevue_type_template_id_2632acaa_scoped_true_staticRenderFns,
|
||||
false,
|
||||
null,
|
||||
"2632acaa",
|
||||
null
|
||||
|
||||
)
|
||||
|
||||
/* harmony default export */ var StartTime = (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&
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
let listES = null;
|
||||
|
||||
/* harmony default export */ var Appvue_type_script_lang_js_ = ({
|
||||
components: {
|
||||
StartTime: StartTime
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
currentStream: null,
|
||||
Rooms: null,
|
||||
remoteAddr: "",
|
||||
streamPath: "",
|
||||
openPull: false
|
||||
};
|
||||
},
|
||||
|
||||
methods: {
|
||||
fetchlist() {
|
||||
listES = new EventSource(this.apiHost + "/rtsp/list");
|
||||
listES.onmessage = evt => {
|
||||
if (!evt.data) return;
|
||||
this.Rooms = JSON.parse(evt.data) || [];
|
||||
this.Rooms.sort((a, b) =>
|
||||
a.RoomInfo.StreamPath > b.RoomInfo.StreamPath ? 1 : -1
|
||||
);
|
||||
};
|
||||
},
|
||||
showHeader(item) {
|
||||
this.$Modal.info({
|
||||
title: "RTSP Header",
|
||||
width: "1000px",
|
||||
scrollable: true,
|
||||
content: item.Header
|
||||
});
|
||||
},
|
||||
addPull() {
|
||||
this.openPull = false;
|
||||
this.ajax
|
||||
.getJSON(this.apiHost + "/rtsp/pull", {
|
||||
target: this.remoteAddr,
|
||||
streamPath: this.streamPath
|
||||
})
|
||||
.then(x => {
|
||||
if (x.code == 0) {
|
||||
this.$toast.success("已启动拉流");
|
||||
} else {
|
||||
this.$toast.error(x.msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.fetchlist();
|
||||
this.$parent.menus = [
|
||||
{
|
||||
label: "拉流转发",
|
||||
action: () => {
|
||||
this.openPull = true;
|
||||
}
|
||||
}
|
||||
];
|
||||
},
|
||||
destroyed() {
|
||||
listES.close();
|
||||
this.$parent.menus = [];
|
||||
}
|
||||
});
|
||||
|
||||
// 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&lang=css&
|
||||
var Appvue_type_style_index_0_lang_css_ = __webpack_require__("034f");
|
||||
|
||||
// CONCATENATED MODULE: ./src/App.vue
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* normalize component */
|
||||
|
||||
var App_component = normalizeComponent(
|
||||
src_Appvue_type_script_lang_js_,
|
||||
render,
|
||||
staticRenderFns,
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
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-rtsp.common.js.map
|
1
ui/dist/plugin-rtsp.common.js.map
vendored
Normal file
1
ui/dist/plugin-rtsp.common.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
1
ui/dist/plugin-rtsp.css
vendored
Normal file
1
ui/dist/plugin-rtsp.css
vendored
Normal file
@@ -0,0 +1 @@
|
||||
@import url(/iview.css);.empty{color:#eb5e46;width:100%;min-height:500px;display:flex;justify-content:center;align-items:center}.layout{padding-bottom:30px;display:flex;flex-wrap:wrap}.ts-info{width:300px}.hls-info{width:350px;display:flex;flex-direction:column}
|
466
ui/dist/plugin-rtsp.umd.js
vendored
Normal file
466
ui/dist/plugin-rtsp.umd.js
vendored
Normal file
@@ -0,0 +1,466 @@
|
||||
(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-rtsp"] = factory();
|
||||
else
|
||||
root["plugin-rtsp"] = 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");
|
||||
/******/ })
|
||||
/************************************************************************/
|
||||
/******/ ({
|
||||
|
||||
/***/ "034f":
|
||||
/***/ (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_lang_css___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("85ec");
|
||||
/* 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_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_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_lang_css___WEBPACK_IMPORTED_MODULE_0___default.a);
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ "85ec":
|
||||
/***/ (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);
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ "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":"29918b3a-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=6fc0793e&
|
||||
var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{directives:[{name:"loading",rawName:"v-loading",value:(_vm.Rooms==null),expression:"Rooms==null"}]},[(_vm.Rooms==null)?_c('div'):(_vm.Rooms.length==0)?_c('div',{staticClass:"empty"},[_c('Icon',{attrs:{"type":"md-wine","size":"50"}}),_vm._v("没有任何房间 ")],1):_c('div',{staticClass:"layout"},_vm._l((_vm.Rooms),function(item){return _c('Card',{key:item.RoomInfo.StreamPath,staticClass:"room"},[_c('p',{attrs:{"slot":"title"},slot:"title"},[_vm._v(_vm._s(item.RoomInfo.StreamPath))]),_c('StartTime',{attrs:{"slot":"extra","value":item.RoomInfo.StartTime},slot:"extra"}),_c('div',{staticClass:"hls-info"},[_c('Progress',{attrs:{"stroke-width":20,"percent":Math.ceil(item.BufferRate),"text-inside":""}}),_c('div',[_vm._v("📜"+_vm._s(item.SyncCount))])],1),_c('Button',{on:{"click":function($event){return _vm.showHeader(item)}}},[_c('Icon',{attrs:{"type":"ios-code-working"}})],1)],1)}),1),_c('mu-dialog',{attrs:{"title":"拉流转发","width":"360","open":_vm.openPull},on:{"update:open":function($event){_vm.openPull=$event}}},[_c('mu-text-field',{attrs:{"label":"rtsp url","label-float":"","help-text":"Please enter URL of rtsp..."},model:{value:(_vm.remoteAddr),callback:function ($$v) {_vm.remoteAddr=$$v},expression:"remoteAddr"}}),_c('mu-text-field',{attrs:{"label":"streamPath","label-float":"","help-text":"Please enter streamPath to publish."},model:{value:(_vm.streamPath),callback:function ($$v) {_vm.streamPath=$$v},expression:"streamPath"}}),_c('mu-button',{attrs:{"slot":"actions","flat":"","color":"primary"},on:{"click":_vm.addPull},slot:"actions"},[_vm._v("确定")])],1)],1)}
|
||||
var staticRenderFns = []
|
||||
|
||||
|
||||
// CONCATENATED MODULE: ./src/App.vue?vue&type=template&id=6fc0793e&
|
||||
|
||||
// CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"29918b3a-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/StartTime.vue?vue&type=template&id=2632acaa&scoped=true&
|
||||
var StartTimevue_type_template_id_2632acaa_scoped_true_render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('Poptip',{attrs:{"trigger":"hover","content":'⌚️'+ new Date(_vm.value).toLocaleString()}},[_c('Time',{attrs:{"time":new Date(_vm.value)}})],1)}
|
||||
var StartTimevue_type_template_id_2632acaa_scoped_true_staticRenderFns = []
|
||||
|
||||
|
||||
// CONCATENATED MODULE: ./src/components/StartTime.vue?vue&type=template&id=2632acaa&scoped=true&
|
||||
|
||||
// CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/StartTime.vue?vue&type=script&lang=js&
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
/* harmony default export */ var StartTimevue_type_script_lang_js_ = ({
|
||||
name: "StartTime",
|
||||
props: {
|
||||
value: String
|
||||
}
|
||||
});
|
||||
|
||||
// CONCATENATED MODULE: ./src/components/StartTime.vue?vue&type=script&lang=js&
|
||||
/* harmony default export */ var components_StartTimevue_type_script_lang_js_ = (StartTimevue_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/StartTime.vue
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* normalize component */
|
||||
|
||||
var component = normalizeComponent(
|
||||
components_StartTimevue_type_script_lang_js_,
|
||||
StartTimevue_type_template_id_2632acaa_scoped_true_render,
|
||||
StartTimevue_type_template_id_2632acaa_scoped_true_staticRenderFns,
|
||||
false,
|
||||
null,
|
||||
"2632acaa",
|
||||
null
|
||||
|
||||
)
|
||||
|
||||
/* harmony default export */ var StartTime = (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&
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
let listES = null;
|
||||
|
||||
/* harmony default export */ var Appvue_type_script_lang_js_ = ({
|
||||
components: {
|
||||
StartTime: StartTime
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
currentStream: null,
|
||||
Rooms: null,
|
||||
remoteAddr: "",
|
||||
streamPath: "",
|
||||
openPull: false
|
||||
};
|
||||
},
|
||||
|
||||
methods: {
|
||||
fetchlist() {
|
||||
listES = new EventSource(this.apiHost + "/rtsp/list");
|
||||
listES.onmessage = evt => {
|
||||
if (!evt.data) return;
|
||||
this.Rooms = JSON.parse(evt.data) || [];
|
||||
this.Rooms.sort((a, b) =>
|
||||
a.RoomInfo.StreamPath > b.RoomInfo.StreamPath ? 1 : -1
|
||||
);
|
||||
};
|
||||
},
|
||||
showHeader(item) {
|
||||
this.$Modal.info({
|
||||
title: "RTSP Header",
|
||||
width: "1000px",
|
||||
scrollable: true,
|
||||
content: item.Header
|
||||
});
|
||||
},
|
||||
addPull() {
|
||||
this.openPull = false;
|
||||
this.ajax
|
||||
.getJSON(this.apiHost + "/rtsp/pull", {
|
||||
target: this.remoteAddr,
|
||||
streamPath: this.streamPath
|
||||
})
|
||||
.then(x => {
|
||||
if (x.code == 0) {
|
||||
this.$toast.success("已启动拉流");
|
||||
} else {
|
||||
this.$toast.error(x.msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.fetchlist();
|
||||
this.$parent.menus = [
|
||||
{
|
||||
label: "拉流转发",
|
||||
action: () => {
|
||||
this.openPull = true;
|
||||
}
|
||||
}
|
||||
];
|
||||
},
|
||||
destroyed() {
|
||||
listES.close();
|
||||
this.$parent.menus = [];
|
||||
}
|
||||
});
|
||||
|
||||
// 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&lang=css&
|
||||
var Appvue_type_style_index_0_lang_css_ = __webpack_require__("034f");
|
||||
|
||||
// CONCATENATED MODULE: ./src/App.vue
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* normalize component */
|
||||
|
||||
var App_component = normalizeComponent(
|
||||
src_Appvue_type_script_lang_js_,
|
||||
render,
|
||||
staticRenderFns,
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
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-rtsp.umd.js.map
|
1
ui/dist/plugin-rtsp.umd.js.map
vendored
Normal file
1
ui/dist/plugin-rtsp.umd.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
2
ui/dist/plugin-rtsp.umd.min.js
vendored
Normal file
2
ui/dist/plugin-rtsp.umd.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
ui/dist/plugin-rtsp.umd.min.js.map
vendored
Normal file
1
ui/dist/plugin-rtsp.umd.min.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -4,7 +4,7 @@
|
||||
"description": "dashboard of rtsp plugin for monibuca",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"build": "vue-cli-service build --dest ui --target wc --name plugin-rtsp index.vue"
|
||||
"build": "vue-cli-service build --target lib --name plugin-rtsp"
|
||||
},
|
||||
"author": "dexter",
|
||||
"license": "ISC",
|
||||
@@ -12,4 +12,4 @@
|
||||
"@vue/cli-service": "^4.2.3",
|
||||
"vue-template-compiler": "^2.6.11"
|
||||
}
|
||||
}
|
||||
}
|
125
ui/src/App.vue
Normal file
125
ui/src/App.vue
Normal file
@@ -0,0 +1,125 @@
|
||||
<template>
|
||||
<div v-loading="Rooms==null">
|
||||
<div v-if="Rooms==null"></div>
|
||||
<div v-else-if="Rooms.length==0" class="empty">
|
||||
<Icon type="md-wine" size="50" />没有任何房间
|
||||
</div>
|
||||
<div class="layout" v-else>
|
||||
<Card v-for="item in Rooms" :key="item.RoomInfo.StreamPath" class="room">
|
||||
<p slot="title">{{item.RoomInfo.StreamPath}}</p>
|
||||
<StartTime slot="extra" :value="item.RoomInfo.StartTime"></StartTime>
|
||||
<div class="hls-info">
|
||||
<Progress :stroke-width="20" :percent="Math.ceil(item.BufferRate)" text-inside />
|
||||
<div>📜{{item.SyncCount}}</div>
|
||||
</div>
|
||||
<Button @click="showHeader(item)">
|
||||
<Icon type="ios-code-working" />
|
||||
</Button>
|
||||
</Card>
|
||||
</div>
|
||||
<mu-dialog title="拉流转发" width="360" :open.sync="openPull">
|
||||
<mu-text-field v-model="remoteAddr" label="rtsp url" label-float help-text="Please enter URL of rtsp...">
|
||||
</mu-text-field>
|
||||
<mu-text-field v-model="streamPath" label="streamPath" label-float
|
||||
help-text="Please enter streamPath to publish."></mu-text-field>
|
||||
<mu-button slot="actions" flat color="primary" @click="addPull">确定</mu-button>
|
||||
</mu-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
let listES = null;
|
||||
import StartTime from "./components/StartTime";
|
||||
export default {
|
||||
components: {
|
||||
StartTime
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
currentStream: null,
|
||||
Rooms: null,
|
||||
remoteAddr: "",
|
||||
streamPath: "",
|
||||
openPull: false
|
||||
};
|
||||
},
|
||||
|
||||
methods: {
|
||||
fetchlist() {
|
||||
listES = new EventSource(this.apiHost + "/rtsp/list");
|
||||
listES.onmessage = evt => {
|
||||
if (!evt.data) return;
|
||||
this.Rooms = JSON.parse(evt.data) || [];
|
||||
this.Rooms.sort((a, b) =>
|
||||
a.RoomInfo.StreamPath > b.RoomInfo.StreamPath ? 1 : -1
|
||||
);
|
||||
};
|
||||
},
|
||||
showHeader(item) {
|
||||
this.$Modal.info({
|
||||
title: "RTSP Header",
|
||||
width: "1000px",
|
||||
scrollable: true,
|
||||
content: item.Header
|
||||
});
|
||||
},
|
||||
addPull() {
|
||||
this.openPull = false;
|
||||
this.ajax
|
||||
.getJSON(this.apiHost + "/rtsp/pull", {
|
||||
target: this.remoteAddr,
|
||||
streamPath: this.streamPath
|
||||
})
|
||||
.then(x => {
|
||||
if (x.code == 0) {
|
||||
this.$toast.success("已启动拉流");
|
||||
} else {
|
||||
this.$toast.error(x.msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.fetchlist();
|
||||
this.$parent.menus = [
|
||||
{
|
||||
label: "拉流转发",
|
||||
action: () => {
|
||||
this.openPull = true;
|
||||
}
|
||||
}
|
||||
];
|
||||
},
|
||||
destroyed() {
|
||||
listES.close();
|
||||
this.$parent.menus = [];
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@import url("/iview.css");
|
||||
.empty {
|
||||
color: #eb5e46;
|
||||
width: 100%;
|
||||
min-height: 500px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.layout {
|
||||
padding-bottom: 30px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.ts-info {
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
.hls-info {
|
||||
width: 350px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
</style>
|
Reference in New Issue
Block a user