linkpi_firmware_history/rootfs/link/webflex/push.php

464 lines
26 KiB
PHP
Raw Normal View History

2024-02-15 22:07:50 +01:00
<?php include ("./link/session.php") ?>
<!doctype html>
<html lang="uft-8">
<head>
<?php include ("./public/head.inc") ?>
<link href="assets/plugins/timepicker/css/bootstrap-timepicker.min.css" rel="stylesheet">
</head>
<body>
<?php include ("./public/menu.inc") ?>
<div data-simplebar>
<main class="page-content push" id="app" v-cloak>
<div class="row">
<div class="col-lg-7 lp-equal-height-container">
<div class="card lp-equal-height-item">
<div class="card-header bg-transparent">
<div class="p-2 mb-0 d-flex align-items-end">
<cn>视频预览</cn>
<en>Preview</en>
<small>
<cn>推流后可见</cn>
<en>visible when pushing</en>
</small>
</div>
</div>
<div class="card-body d-flex">
<div class="row flex-grow-1 lp-align-center">
<div class="col-lg-12">
<h5-player :url="playUrl" :codec="playerCodec" :audio="true" :canplay="hadPlayed"></h5-player>
</div>
</div>
</div>
</div>
</div>
<div class="col-lg-5 lp-equal-height-container">
<div class="lp-equal-height-item d-flex flex-column">
<div class="row flex-grow-1 pb-2">
<div class="col-lg-12">
<div class="card h-100 d-flex flex-column">
<div class="card-header bg-transparent">
<div class="p-2 mb-0 d-flex align-items-end">
<cn>基本设置</cn>
<en>Basic config</en>
</div>
</div>
<div class="card-body">
<div class="d-flex flex-column justify-content-between h-100" v-if="Object.keys(pushConf).length > 0">
<div class="row">
<div class="col-lg-4 lp-align-right pe-4">
<label>
<cn>视频源</cn>
<en>Video source</en>
</label>
</div>
<div class="col-lg-6">
<select class="form-select" v-model="pushConf.srcV" @change="onChangeSrcV">
<option v-for="(item,index) in handleEnableConf" :value="item.id">{{item.name}}</option>
</select>
</div>
</div>
<div class="row">
<div class="col-lg-4 lp-align-right pe-4">
<label>
<cn>音频源</cn>
<en>Audio source</en>
</label>
</div>
<div class="col-lg-6">
<select class="form-select" v-model="pushConf.srcA">
<option value="-1" cn="" en="None" v-language-option></option>
<option v-for="(item,index) in handleEnableConf" :value="item.id">{{item.name}}</option>
</select>
</div>
</div>
<div class="row">
<div class="col-lg-4 lp-align-right pe-4">
<label>
<cn>码流</cn>
<en>Stream</en>
</label>
</div>
<div class="col-lg-6">
<select class="form-select" v-model="pushConf.srcV_chn">
<option value="main" cn="主码流" en="Main Stream" v-language-option></option>
<option v-if="defaultSubEnable" value="sub" cn="辅码流" en="Sub Stream" v-language-option></option>
<option v-else value="sub" cn="辅码流(未启用)" en="Sub Stream(not enable)" v-language-option></option>
</select>
</div>
</div>
<div class="row">
<div class="col-lg-4 lp-align-right pe-4">
<label>
<cn>定时开启</cn>
<en>start time</en>
</label>
</div>
<div class="col-lg-3">
<select class="form-select" v-model="pushCron.start.day">
<option cn="从不" en="never" value="x" v-language-option></option>
<option cn="每天" en="everyday" value="*" v-language-option></option>
<option cn="每周一" en="monday" value="1" v-language-option></option>
<option cn="每周二" en="tuesday" value="2" v-language-option></option>
<option cn="每周三" en="wednesday" value="3" v-language-option></option>
<option cn="每周四" en="thursday" value="4" v-language-option></option>
<option cn="每周五" en="friday" value="5" v-language-option></option>
<option cn="每周六" en="saturday" value="6" v-language-option></option>
<option cn="每周日" en="sunday" value="0" v-language-option></option>
</select>
</div>
<div class="col-lg-3">
<time-picker v-model="pushCron.start.time"></time-picker>
</div>
</div>
<div class="row">
<div class="col-lg-4 lp-align-right pe-4">
<label>
<cn>定时结束</cn>
<en>stop time</en>
</label>
</div>
<div class="col-lg-3">
<select class="form-select" v-model="pushCron.stop.day">
<option cn="从不" en="never" value="x" v-language-option></option>
<option cn="每天" en="everyday" value="*" v-language-option></option>
<option cn="每周一" en="monday" value="1" v-language-option></option>
<option cn="每周二" en="tuesday" value="2" v-language-option></option>
<option cn="每周三" en="wednesday" value="3" v-language-option></option>
<option cn="每周四" en="thursday" value="4" v-language-option></option>
<option cn="每周五" en="friday" value="5" v-language-option></option>
<option cn="每周六" en="saturday" value="6" v-language-option></option>
<option cn="每周日" en="sunday" value="0" v-language-option></option>
</select>
</div>
<div class="col-lg-3">
<time-picker v-model="pushCron.stop.time"></time-picker>
</div>
</div>
<!-- <div class="hr-container">-->
<!-- <hr>-->
<!-- <span class="hr-text">OR</span>-->
<!-- </div>-->
<div class="row">
<div class="col-lg-4 lp-align-right pe-4">
<label>
<cn>开机启动</cn>
<en>auto push</en>
</label>
</div>
<div class="col-lg-6">
<select class="form-select" v-model="pushConf.autorun">
<option cn="关闭" en="OFF" value="false" v-language-option></option>
<option cn="开启" en="ON" value="true" v-language-option></option>
</select>
</div>
</div>
<div class="row mt-2">
<div class="col-lg-12 text-center">
<button type="button" class="btn border-3 btn-primary px-5" @click="savePushConf">
<cn>保存</cn>
<en>Save</en>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row flex-grow-0">
<div class="col-lg-12">
<div class="card">
<div class="card-body">
<div class="push-bar">
<div class="row">
<div class="col-4 text-center" style="line-height: 34px;">
<strong>{{pushTimeCount}}</strong>
</div>
<div class="col-7 d-flex align-items-start">
<button type="button" :class="['btn border-3',{'btn-primary':!pushState.pushing},{'btn-default disabled':pushState.pushing}]" @click="onPushStart">
<i class="fa-solid fa-video me-1"></i>
<cn>推流</cn>
<en>Push</en>
</button>
<button type="button" :class="['btn border-3 ms-1',{'btn-primary':pushState.pushing},{'btn-default disabled':!pushState.pushing}]" @click="onPushStop">
<i class="fa-solid fa-stop me-1"></i>
<cn>停止</cn>
<en>Stop</en>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-12">
<div class="card">
<div class="card-header bg-transparent">
<div class="p-2 mb-0 d-flex align-items-end">
<cn>推流设置</cn>
<en>Push config</en>
</div>
</div>
<div class="card-body">
<div class="row">
<div class="col-lg-2 text-center">
<cn>描述</cn>
<en>Description</en>
</div>
<div class="col-lg-5 text-center">
<cn>推流地址</cn>
<en>Push Url</en>
</div>
<div class="col-lg-2 text-center">
<cn>兼容性</cn>
<en>Compatible</en>
</div>
<div class="col-lg-1 text-center">
<cn>启用</cn>
<en>Enable</en>
</div>
<div class="col-lg-1 text-center">
<cn>操作</cn>
<en>Option</en>
</div>
<div class="col-lg-1 text-center">
<cn>速度</cn>
<en>Speed</en>
</div>
</div>
<hr class="my-3">
<div class="row" v-if="Object.keys(pushConf).length > 0" v-for="(item,index) in pushConf.url">
<div class="co-lg-12">
<div class="row">
<div class="col-lg-2">
<input type="text" class="form-control" v-model.trim.lazy="item.des">
</div>
<div class="col-lg-5">
<input type="text" class="form-control" v-model.trim.lazy="item.path">
</div>
<div class="col-lg-2">
<select class="form-select" v-model="item.flvflags">
<option cn="标准" en="normal" value="" v-language-option></option>
<option value="ext_header">enhanced-rtmp</option>
</select>
</div>
<div class="col-lg-1 lp-align-center">
<bs-switch v-model="item.enable"></bs-switch>
</div>
<div class="col-lg-1 text-center">
<button type="button" class="btn border-3 btn-primary" @click="delPushUrl(index)">
<cn>移除</cn>
<en>delete</en>
</button>
</div>
<div class="col-lg-1 text-center">
{{getPushSpeed(index)}} kb/s
</div>
</div>
<hr class="my-3">
</div>
</div>
<div class="row">
<div class="col-lg-12 text-center">
<button type="button" class="btn border-3 btn-primary px-5" @click="addPushUrl">
<cn>添加</cn>
<en>Add</en>
</button>
<button type="button" class="btn border-3 btn-primary px-5 ms-2" @click="savePushConf">
<cn>保存</cn>
<en>Save</en>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</main>
</div>
<?php include ("./public/foot.inc") ?>
<script type="module">
import { rpc,func,alertMsg } from "./assets/js/lp.utils.js";
import { useDefaultConf,usePushConf } from "./assets/js/vue.hooks.js";
import { ignoreCustomElementPlugin,bootstrapSwitchComponent,h5PlayerComponent,timepickerComponent,languageOptionDirective } from "./assets/js/vue.helper.js"
import vue from "./assets/js/vue.build.js";
const {createApp,ref,reactive,watchEffect,computed,onMounted} = vue;
const app = createApp({
directives: {
"language-option": languageOptionDirective
},
components:{
"bs-switch" : bootstrapSwitchComponent,
"h5-player": h5PlayerComponent,
"time-picker": timepickerComponent
},
setup(props,context) {
const { defaultConf } = useDefaultConf();
const { pushConf,updatePushConf } = usePushConf();
const state = {
playerCodec:ref("h264"),
defaultSubEnable:ref(null),
hadPlayed:ref(false),
playUrl:ref('http://'+window.location.host+'/flv?app=live&stream=preview'),
pushTimeCount:ref("00:00:00"),
updateTime:0,
pushCron: reactive({
start:{
day:"x",
time:"00:00"
},
stop: {
day:"x",
time:"00:00"
}
}),
pushState:reactive({
duration:0,
pushing:false,
speed:[]
}),
}
const unwatch = watchEffect(()=>{
if(Object.keys(pushConf).length > 0) {
defaultConf.forEach(item => {
if(item.id === pushConf.srcV) {
if(pushConf.srcV_chn === "sub" && item.enable2)
state.playerCodec.value = item.encv2.codec;
else
state.playerCodec.value = item.encv.codec;
}
});
unwatch();
}
})
const handleEnableConf = computed(()=>{
return defaultConf.filter((item,index) => {
if(item.enable && state.defaultSubEnable.value === null)
state.defaultSubEnable.value = item.enable2;
return !!item.enable;
})
});
const handlePushCrontab = () => {
func("/system/getPushCrontab").then(result => {
const keys = Object.keys(result.data);
keys.forEach(key => {
const value = result.data[key];
if(value === null)
return;
let list = value.split(" ");
if(list.length === 8) {
state.pushCron[key].day = list[4];
state.pushCron[key].time = list[1]+":"+list[0];
}
});
})
}
const onChangeSrcV = () => {
defaultConf.forEach(item => {
if(item.id === pushConf.srcV)
state.defaultSubEnable.value = item.enable2;
return true;
})
}
const handlePushState = () => {
rpc("push.getState").then(data => {
Object.assign(state.pushState, data);
state.updateTime = new Date().getTime() / 1000;
state.hadPlayed.value = state.pushState.pushing;
});
setTimeout(handlePushState,2000);
}
const getPushSpeed = index => {
return state.pushState.speed[index];
}
const handlePushTimeCount = () => {
if (state.pushState.pushing) {
const fix = num => {
if ( num < 10 )
return '0' + num;
else
return num;
}
let now = new Date();
let diff = now.getTime() / 1000 - state.updateTime + state.pushState.duration/1000;
let h = Math.floor(diff / 3600);
let m = Math.floor( diff % 3600 / 60 );
let s = Math.floor( diff % 60 );
state.pushTimeCount.value = "[" + fix(h) + ":" + fix( m ) + ":" + fix( s ) + "]"
} else {
state.pushTimeCount.value = "[--:--:--]";
}
setTimeout(handlePushTimeCount,1000);
}
const onPushStart = () => {
rpc("push.start").then(()=>{
handlePushState();
});
}
const onPushStop = () => {
rpc("push.stop").then(()=>{
handlePushState();
});
}
const addPushUrl = () => {
pushConf.url.push({
"des": "platform "+ (pushConf.url.length+1),
"enable": false,
"path": ""
})
}
const delPushUrl = (index) => {
pushConf.url.splice(index,1);
}
const savePushConf = () => {
defaultConf.forEach(item => {
if(item.id === pushConf.srcV) {
if(pushConf.srcV_chn === "sub" && item.enable2)
state.playerCodec.value = item.encv2.codec;
else
state.playerCodec.value = item.encv.codec;
}
});
updatePushConf().then(()=>{
func("/system/setPushCrontab",state.pushCron).then(data => {
if(data.status === "success")
alertMsg('<cn>保存设置成功</cn><en>Save config success!</en>', 'success');
});
})
}
onMounted(() => {
handlePushCrontab();
handlePushState();
handlePushTimeCount();
})
return {...state,pushConf,onChangeSrcV,onPushStart,onPushStop,addPushUrl,delPushUrl,handleEnableConf,getPushSpeed,savePushConf}
}
});
app.use(ignoreCustomElementPlugin);
app.mount('#app');
</script>
</body>
</html>