diff --git a/rootfs/etc/udev/rules.d/11-usb-hotplug.rules b/rootfs/etc/udev/rules.d/11-usb-hotplug.rules index c597353..79ea19d 100644 --- a/rootfs/etc/udev/rules.d/11-usb-hotplug.rules +++ b/rootfs/etc/udev/rules.d/11-usb-hotplug.rules @@ -1,6 +1,7 @@ ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1f01", RUN+="/etc/udev/usb4g.sh" ATTRS{idVendor}=="0bda", ATTRS{idProduct}=="1a2b", RUN+="/etc/udev/usbWiFi.sh" SUBSYSTEM=="net", ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="14db", KERNEL=="eth*", RUN+="/etc/udev/usbUp.sh %k" +SUBSYSTEM=="net", KERNEL=="usb*", RUN+="/etc/udev/usbUp.sh %k" ACTION=="add", KERNEL=="sd*", SUBSYSTEM=="block", RUN+="/link/shell/mountUsb.sh" ACTION=="remove",KERNEL=="sd*", SUBSYSTEM=="block", RUN+="/etc/udev/autounmount.sh" diff --git a/rootfs/link/bin/Encoder b/rootfs/link/bin/Encoder index 4712b44..cde4911 100644 Binary files a/rootfs/link/bin/Encoder and b/rootfs/link/bin/Encoder differ diff --git a/rootfs/link/bin/Monitor b/rootfs/link/bin/Monitor new file mode 100644 index 0000000..492f616 Binary files /dev/null and b/rootfs/link/bin/Monitor differ diff --git a/rootfs/link/bin/PTZ b/rootfs/link/bin/PTZ index 5b2c423..621d75a 100644 Binary files a/rootfs/link/bin/PTZ and b/rootfs/link/bin/PTZ differ diff --git a/rootfs/link/bin/mqtt b/rootfs/link/bin/mqtt new file mode 100644 index 0000000..9496347 Binary files /dev/null and b/rootfs/link/bin/mqtt differ diff --git a/rootfs/link/config/misc/remote/remfea.json b/rootfs/link/config/misc/remote/remfea.json new file mode 100644 index 0000000..7b887e0 --- /dev/null +++ b/rootfs/link/config/misc/remote/remfea.json @@ -0,0 +1,314 @@ +[ + { + "id": 1, + "nameCH": "方案 1", + "nameEN": "project 1", + "used": true, + "btns": [ + { + "icon": "fa-power-off", + "code": 3944021760, + "tapCH": "关闭 Hdmi/Vga", + "tapEN": "Close Hdmi/Vga", + "pressCH": "开启 Hdmi/Vga", + "pressEN": "Open Hdmi/Vga" + }, + { + "icon": "fa-bars", + "code": 3960733440, + "tapCH": "开启 Hdmi/Vga", + "tapEN": "Open Hdmi/Vga", + "pressCH": "关闭 Hdmi/Vga", + "pressEN": "Close Hdmi/Vga" + }, + { + "icon": "fa-caret-up", + "code": 4228120320, + "tapCH": "开启全平台推流", + "tapEN": "Stop Platform Push", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-caret-down", + "code": 4244832000, + "tapCH": "关闭全平台推流", + "tapEN": "Stop Platform Push", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-caret-left", + "code": 4044291840, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-caret-right", + "code": 3843751680, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "my-ok", + "code": 4161273600, + "tapCH": "开启录制", + "tapEN": "Start Record", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-volume-down", + "code": 2807627520, + "tapCH": "开启 Dhcp", + "tapEN": "Open Dhcp", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-clone", + "code": 2740780800, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-volume-up", + "code": 4094426880, + "tapCH": "关闭 Dhcp", + "tapEN": "Close Dhcp", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-reply", + "code": 4261543680, + "tapCH": "关闭录制", + "tapEN": "Stop Record", + "pressCH": "重启机器", + "pressEN": "Restart" + }, + { + "icon": "fa-home", + "code": 3075014400, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "恢复出厂设置", + "pressEN": "Factory Data Reset" + } + ] + }, + { + "id": 2, + "nameCH": "方案 2", + "nameEN": "project 2", + "used": false, + "btns": [ + { + "icon": "fa-power-off", + "code": 3944021760, + "tapCH": "开启Mix直播", + "tapEN": "Start Mix Live", + "pressCH": "关闭Mix直播", + "pressEN": "Stop Mix Live" + }, + { + "icon": "fa-bars", + "code": 3960733440, + "tapCH": "关闭全平台推流", + "tapEN": "Stop Platform Push", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-caret-up", + "code": 4228120320, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-caret-down", + "code": 4244832000, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-caret-left", + "code": 4044291840, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-caret-right", + "code": 3843751680, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "my-ok", + "code": 4161273600, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-volume-down", + "code": 2807627520, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-clone", + "code": 2740780800, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-volume-up", + "code": 4094426880, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-reply", + "code": 4261543680, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-home", + "code": 3075014400, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "未启用", + "pressEN": "None" + } + ] + }, + { + "id": 3, + "nameCH": "方案 3", + "nameEN": "project 3", + "used": false, + "btns": [ + { + "icon": "fa-power-off", + "code": 3944021760, + "tapCH": "开启Mix直播", + "tapEN": "Start Mix Live", + "pressCH": "关闭Mix直播", + "pressEN": "Stop Mix Live" + }, + { + "icon": "fa-bars", + "code": 3960733440, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-caret-up", + "code": 4228120320, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-caret-down", + "code": 4244832000, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-caret-left", + "code": 4044291840, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-caret-right", + "code": 3843751680, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "my-ok", + "code": 4161273600, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-volume-down", + "code": 2807627520, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-clone", + "code": 2740780800, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-volume-up", + "code": 4094426880, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-reply", + "code": 4261543680, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-home", + "code": 3075014400, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "未启用", + "pressEN": "None" + } + ] + } +] \ No newline at end of file diff --git a/rootfs/link/config/misc/remote/remods.json b/rootfs/link/config/misc/remote/remods.json new file mode 100644 index 0000000..2284959 --- /dev/null +++ b/rootfs/link/config/misc/remote/remods.json @@ -0,0 +1,92 @@ +{ + "mods1":[ + { + "titleCH":"录播模块", + "titleEN":"Broadcast", + "func":[ + { + "ch":"开启Mix直播", + "en":"Start Mix Live" + }, + { + "ch":"关闭Mix直播", + "en":"Stop Mix Live" + }, + { + "ch":"开启Mix推流", + "en":"Start Mix Push" + }, + { + "ch":"关闭Mix推流", + "en":"Stop Mix Push" + }, + { + "ch":"开启录制", + "en":"Start Record" + }, + { + "ch":"关闭录制", + "en":"Stop Record" + }, + { + "ch":"开启全平台推流", + "en":"Stop Platform Push" + }, + { + "ch":"关闭全平台推流", + "en":"Stop Platform Push" + } + ] + } + ], + "mods2":[ + { + "titleCH":"系统模块", + "titleEN":"Network", + "func":[ + { + "ch":"开启 Dhcp", + "en":"Open Dhcp" + }, + { + "ch":"关闭 Dhcp", + "en":"Close Dhcp" + }, + { + "ch":"重启机器", + "en":"Restart" + }, + { + "ch":"恢复出厂设置", + "en":"Factory Data Reset" + } + + ] + }, + { + "titleCH":"输出模块", + "titleEN":"Output", + "func":[ + { + "ch":"开启 Hdmi/Vga", + "en":"Open Hdmi/Vga" + }, + { + "ch":"关闭 Hdmi/Vga", + "en":"Close Hdmi/Vga" + } + ] + }, + { + "titleCH":"", + "titleEN":"", + "func":[ + { + "ch":"未启用", + "en":"None" + } + ] + } + + ] +} \ No newline at end of file diff --git a/rootfs/link/config/misc/remote/remote.json b/rootfs/link/config/misc/remote/remote.json new file mode 100644 index 0000000..6e1bbac --- /dev/null +++ b/rootfs/link/config/misc/remote/remote.json @@ -0,0 +1,86 @@ +[ + { + "btnId": 1, + "remoteCode": 3944021760, + "btnNameCN": "按键1", + "btnNameEN": "Button1", + "icon": "fa-power-off" + }, + { + "btnId": 2, + "remoteCode": 3960733440, + "btnNameCN": "按键 2", + "btnNameEN": "Button 2", + "icon": "fa-bars" + }, + { + "btnId": 3, + "remoteCode": 4228120320, + "btnNameCN": "按键 3", + "btnNameEN": "Button 3", + "icon": "fa-caret-up" + }, + { + "btnId": 4, + "remoteCode": 4244832000, + "btnNameCN": "按键 4", + "btnNameEN": "Button 4", + "icon": "fa-caret-down" + }, + { + "btnId": 5, + "remoteCode": 4044291840, + "btnNameCN": "按键 5", + "btnNameEN": "Button 5", + "icon": "fa-caret-left" + }, + { + "btnId": 6, + "remoteCode": 3843751680, + "btnNameCN": "按键 6", + "btnNameEN": "Button 6", + "icon": "fa-caret-right" + }, + { + "btnId": 7, + "remoteCode": 4161273600, + "btnNameCN": "按键 7", + "btnNameEN": "Button 7", + "icon": "my-ok" + }, + { + "btnId": 8, + "remoteCode": 2807627520, + "btnNameCN": "按键 8", + "btnNameEN": "Button 8", + "icon": "fa-volume-down" + }, + { + "btnId": 9, + "remoteCode": 2740780800, + "btnNameCN": "按键 9", + "btnNameEN": "Button 9", + "icon": "fa-clone" + }, + { + "btnId": 10, + "remoteCode": 4094426880, + "btnNameCN": "按键 10", + "btnNameEN": "Button 10", + "icon": "fa-volume-up" + }, + { + "btnId": 11, + "remoteCode": 4261543680, + "btnNameCN": "按键 11", + "btnNameEN": "Button 11", + "icon": "fa-reply" + }, + { + "btnId": 12, + "remoteCode": 3075014400, + "btnNameCN": "按键 12", + "btnNameEN": "Button 12", + "icon": "fa-home" + } +] \ No newline at end of file diff --git a/rootfs/link/config/verLogs.json b/rootfs/link/config/verLogs.json index c5e215a..f9d614d 100644 --- a/rootfs/link/config/verLogs.json +++ b/rootfs/link/config/verLogs.json @@ -1,4 +1,18 @@ [ + { + "version": "2.2.0 build 20230531", + "logs": [ + "全平台直播新增定时开启/关闭推流功能", + "优化部分机型Onvif PTZ功能", + "优化集成通信功能", + "优化设备内存占用", + "调整首页端口状态显示逻辑", + "修正roi设置功能", + "修正开启推流后,更改系统时间导致的推流时长显示不准确的问题", + "修正ENC1机型按键小概率不触发问题", + "支持全新基于互联网的微信小程序,不在依赖局域网,真正做到的随时随地查看" + ] + }, { "version": "2.1.0 build 20230426", "logs": [ diff --git a/rootfs/link/config/version.json b/rootfs/link/config/version.json index 3241538..1baf278 100644 --- a/rootfs/link/config/version.json +++ b/rootfs/link/config/version.json @@ -1,5 +1,5 @@ { "app": "2.0.0 build 20220512_869", "sdk": "2.0.0 build 20220518_20716", - "sys": "2.1.0 build 20230426" + "sys": "2.2.0 build 20230531" } diff --git a/rootfs/link/fac/EX2/bin/Monitor b/rootfs/link/fac/EX2/bin/Monitor new file mode 100644 index 0000000..492f616 Binary files /dev/null and b/rootfs/link/fac/EX2/bin/Monitor differ diff --git a/rootfs/link/fac/EX2/config/.hardware.json.swo b/rootfs/link/fac/EX2/config/.hardware.json.swo new file mode 100644 index 0000000..c041816 Binary files /dev/null and b/rootfs/link/fac/EX2/config/.hardware.json.swo differ diff --git a/rootfs/link/fac/EX2/config/.hardware.json.swp b/rootfs/link/fac/EX2/config/.hardware.json.swp new file mode 100644 index 0000000..33eabdd Binary files /dev/null and b/rootfs/link/fac/EX2/config/.hardware.json.swp differ diff --git a/rootfs/link/fac/EX2/config/gpio.json b/rootfs/link/fac/EX2/config/gpio.json new file mode 100644 index 0000000..ce800d9 --- /dev/null +++ b/rootfs/link/fac/EX2/config/gpio.json @@ -0,0 +1,4 @@ +[ + {"name":"GPIO0_0","addr":"12150000","offset": 0,"irq":89}, + {"name":"GPIO0_1","addr":"12150000","offset": 1,"irq":89} +] diff --git a/rootfs/link/fac/EX2/gpio.sh b/rootfs/link/fac/EX2/gpio.sh new file mode 100644 index 0000000..b238c0a --- /dev/null +++ b/rootfs/link/fac/EX2/gpio.sh @@ -0,0 +1,63 @@ +. /link/shell/util/hardware.sh +count=0 +type=`jget gpio.type` +himmGPIO() +{ + gpioName=`jget gpio.name` + gpioAddr=`jget gpio.addr` + eval "`jget gpio.mux` > /dev/null" + eval "`jget gpio.dir` > /dev/null" + + echo "Init $gpioName($gpioAddr) done." + + while [ true ] + do + ret=`himd.l $gpioAddr 1 | awk 'NR==4{print $2}'` + if [ "$ret" == "00000000" ]; then + count=$(($count+1)) + echo "keyDown $count" + if [ "$count" == "5" ]; then + echo "reset default config" + /link/shell/reset.sh + fi + else + count=0 + fi + sleep 1 + done +} + +sysfsGPIO() +{ + gpioName=`jget gpio.name` + gpioIndex=`jget gpio.index` + eval "`jget gpio.mux` > /dev/null" + if [ ! -d "/sys/class/gpio/gpio$gpioIndex" ];then + echo $gpioIndex > /sys/class/gpio/export + fi + echo "in" > /sys/class/gpio/gpio$gpioIndex/direction + + echo "Init $gpioName($gpioIndex) done." + + while [ true ] + do + ret=`cat /sys/class/gpio/gpio$gpioIndex/value` + if [ "$ret" == "0" ]; then + count=$(($count+1)) + echo "keyDown $count" + if [ "$count" == "5" ]; then + echo "reset default config" + /link/shell/reset.sh + fi + else + count=0 + fi + sleep 1 + done +} + +if [ "$type" == "himm" ]; then + himmGPIO +elif [ "$type" == "sysfs" ]; then + sysfsGPIO +fi diff --git a/rootfs/link/fac/EX2/shell/monitor.sh b/rootfs/link/fac/EX2/shell/monitor.sh new file mode 100644 index 0000000..1d33a08 --- /dev/null +++ b/rootfs/link/fac/EX2/shell/monitor.sh @@ -0,0 +1,5 @@ +while [ true ] +do +/link/bin/Monitor +sleep 1 +done diff --git a/rootfs/link/fac/V2/bin/Monitor b/rootfs/link/fac/V2/bin/Monitor new file mode 100644 index 0000000..492f616 Binary files /dev/null and b/rootfs/link/fac/V2/bin/Monitor differ diff --git a/rootfs/link/fac/V2/config/misc/remote/remfea.json b/rootfs/link/fac/V2/config/misc/remote/remfea.json new file mode 100644 index 0000000..7b887e0 --- /dev/null +++ b/rootfs/link/fac/V2/config/misc/remote/remfea.json @@ -0,0 +1,314 @@ +[ + { + "id": 1, + "nameCH": "方案 1", + "nameEN": "project 1", + "used": true, + "btns": [ + { + "icon": "fa-power-off", + "code": 3944021760, + "tapCH": "关闭 Hdmi/Vga", + "tapEN": "Close Hdmi/Vga", + "pressCH": "开启 Hdmi/Vga", + "pressEN": "Open Hdmi/Vga" + }, + { + "icon": "fa-bars", + "code": 3960733440, + "tapCH": "开启 Hdmi/Vga", + "tapEN": "Open Hdmi/Vga", + "pressCH": "关闭 Hdmi/Vga", + "pressEN": "Close Hdmi/Vga" + }, + { + "icon": "fa-caret-up", + "code": 4228120320, + "tapCH": "开启全平台推流", + "tapEN": "Stop Platform Push", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-caret-down", + "code": 4244832000, + "tapCH": "关闭全平台推流", + "tapEN": "Stop Platform Push", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-caret-left", + "code": 4044291840, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-caret-right", + "code": 3843751680, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "my-ok", + "code": 4161273600, + "tapCH": "开启录制", + "tapEN": "Start Record", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-volume-down", + "code": 2807627520, + "tapCH": "开启 Dhcp", + "tapEN": "Open Dhcp", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-clone", + "code": 2740780800, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-volume-up", + "code": 4094426880, + "tapCH": "关闭 Dhcp", + "tapEN": "Close Dhcp", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-reply", + "code": 4261543680, + "tapCH": "关闭录制", + "tapEN": "Stop Record", + "pressCH": "重启机器", + "pressEN": "Restart" + }, + { + "icon": "fa-home", + "code": 3075014400, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "恢复出厂设置", + "pressEN": "Factory Data Reset" + } + ] + }, + { + "id": 2, + "nameCH": "方案 2", + "nameEN": "project 2", + "used": false, + "btns": [ + { + "icon": "fa-power-off", + "code": 3944021760, + "tapCH": "开启Mix直播", + "tapEN": "Start Mix Live", + "pressCH": "关闭Mix直播", + "pressEN": "Stop Mix Live" + }, + { + "icon": "fa-bars", + "code": 3960733440, + "tapCH": "关闭全平台推流", + "tapEN": "Stop Platform Push", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-caret-up", + "code": 4228120320, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-caret-down", + "code": 4244832000, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-caret-left", + "code": 4044291840, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-caret-right", + "code": 3843751680, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "my-ok", + "code": 4161273600, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-volume-down", + "code": 2807627520, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-clone", + "code": 2740780800, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-volume-up", + "code": 4094426880, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-reply", + "code": 4261543680, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-home", + "code": 3075014400, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "未启用", + "pressEN": "None" + } + ] + }, + { + "id": 3, + "nameCH": "方案 3", + "nameEN": "project 3", + "used": false, + "btns": [ + { + "icon": "fa-power-off", + "code": 3944021760, + "tapCH": "开启Mix直播", + "tapEN": "Start Mix Live", + "pressCH": "关闭Mix直播", + "pressEN": "Stop Mix Live" + }, + { + "icon": "fa-bars", + "code": 3960733440, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-caret-up", + "code": 4228120320, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-caret-down", + "code": 4244832000, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-caret-left", + "code": 4044291840, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-caret-right", + "code": 3843751680, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "my-ok", + "code": 4161273600, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-volume-down", + "code": 2807627520, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-clone", + "code": 2740780800, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-volume-up", + "code": 4094426880, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-reply", + "code": 4261543680, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "未启用", + "pressEN": "None" + }, + { + "icon": "fa-home", + "code": 3075014400, + "tapCH": "未启用", + "tapEN": "None", + "pressCH": "未启用", + "pressEN": "None" + } + ] + } +] \ No newline at end of file diff --git a/rootfs/link/fac/V2/config/misc/remote/remods.json b/rootfs/link/fac/V2/config/misc/remote/remods.json new file mode 100644 index 0000000..2284959 --- /dev/null +++ b/rootfs/link/fac/V2/config/misc/remote/remods.json @@ -0,0 +1,92 @@ +{ + "mods1":[ + { + "titleCH":"录播模块", + "titleEN":"Broadcast", + "func":[ + { + "ch":"开启Mix直播", + "en":"Start Mix Live" + }, + { + "ch":"关闭Mix直播", + "en":"Stop Mix Live" + }, + { + "ch":"开启Mix推流", + "en":"Start Mix Push" + }, + { + "ch":"关闭Mix推流", + "en":"Stop Mix Push" + }, + { + "ch":"开启录制", + "en":"Start Record" + }, + { + "ch":"关闭录制", + "en":"Stop Record" + }, + { + "ch":"开启全平台推流", + "en":"Stop Platform Push" + }, + { + "ch":"关闭全平台推流", + "en":"Stop Platform Push" + } + ] + } + ], + "mods2":[ + { + "titleCH":"系统模块", + "titleEN":"Network", + "func":[ + { + "ch":"开启 Dhcp", + "en":"Open Dhcp" + }, + { + "ch":"关闭 Dhcp", + "en":"Close Dhcp" + }, + { + "ch":"重启机器", + "en":"Restart" + }, + { + "ch":"恢复出厂设置", + "en":"Factory Data Reset" + } + + ] + }, + { + "titleCH":"输出模块", + "titleEN":"Output", + "func":[ + { + "ch":"开启 Hdmi/Vga", + "en":"Open Hdmi/Vga" + }, + { + "ch":"关闭 Hdmi/Vga", + "en":"Close Hdmi/Vga" + } + ] + }, + { + "titleCH":"", + "titleEN":"", + "func":[ + { + "ch":"未启用", + "en":"None" + } + ] + } + + ] +} \ No newline at end of file diff --git a/rootfs/link/fac/V2/config/misc/remote/remote.json b/rootfs/link/fac/V2/config/misc/remote/remote.json new file mode 100644 index 0000000..6e1bbac --- /dev/null +++ b/rootfs/link/fac/V2/config/misc/remote/remote.json @@ -0,0 +1,86 @@ +[ + { + "btnId": 1, + "remoteCode": 3944021760, + "btnNameCN": "按键1", + "btnNameEN": "Button1", + "icon": "fa-power-off" + }, + { + "btnId": 2, + "remoteCode": 3960733440, + "btnNameCN": "按键 2", + "btnNameEN": "Button 2", + "icon": "fa-bars" + }, + { + "btnId": 3, + "remoteCode": 4228120320, + "btnNameCN": "按键 3", + "btnNameEN": "Button 3", + "icon": "fa-caret-up" + }, + { + "btnId": 4, + "remoteCode": 4244832000, + "btnNameCN": "按键 4", + "btnNameEN": "Button 4", + "icon": "fa-caret-down" + }, + { + "btnId": 5, + "remoteCode": 4044291840, + "btnNameCN": "按键 5", + "btnNameEN": "Button 5", + "icon": "fa-caret-left" + }, + { + "btnId": 6, + "remoteCode": 3843751680, + "btnNameCN": "按键 6", + "btnNameEN": "Button 6", + "icon": "fa-caret-right" + }, + { + "btnId": 7, + "remoteCode": 4161273600, + "btnNameCN": "按键 7", + "btnNameEN": "Button 7", + "icon": "my-ok" + }, + { + "btnId": 8, + "remoteCode": 2807627520, + "btnNameCN": "按键 8", + "btnNameEN": "Button 8", + "icon": "fa-volume-down" + }, + { + "btnId": 9, + "remoteCode": 2740780800, + "btnNameCN": "按键 9", + "btnNameEN": "Button 9", + "icon": "fa-clone" + }, + { + "btnId": 10, + "remoteCode": 4094426880, + "btnNameCN": "按键 10", + "btnNameEN": "Button 10", + "icon": "fa-volume-up" + }, + { + "btnId": 11, + "remoteCode": 4261543680, + "btnNameCN": "按键 11", + "btnNameEN": "Button 11", + "icon": "fa-reply" + }, + { + "btnId": 12, + "remoteCode": 3075014400, + "btnNameCN": "按键 12", + "btnNameEN": "Button 12", + "icon": "fa-home" + } +] \ No newline at end of file diff --git a/rootfs/link/fac/V2/shell/monitor.sh b/rootfs/link/fac/V2/shell/monitor.sh new file mode 100644 index 0000000..1d33a08 --- /dev/null +++ b/rootfs/link/fac/V2/shell/monitor.sh @@ -0,0 +1,5 @@ +while [ true ] +do +/link/bin/Monitor +sleep 1 +done diff --git a/rootfs/link/shell/.fusb.sh.swp b/rootfs/link/shell/.fusb.sh.swp new file mode 100644 index 0000000..cbb5665 Binary files /dev/null and b/rootfs/link/shell/.fusb.sh.swp differ diff --git a/rootfs/link/shell/app.sh b/rootfs/link/shell/app.sh index 981d6bd..58ac629 100644 --- a/rootfs/link/shell/app.sh +++ b/rootfs/link/shell/app.sh @@ -9,3 +9,10 @@ if [ -f /link/shell/ptz.sh ] ;then /link/shell/ptz.sh & fi +if [ -f /link/bin/mqtt ] ;then +/link/bin/mqtt & +fi + +if [ -f /link/bin/Monitor ];then +/link/shell/monitor.sh & +fi diff --git a/rootfs/link/shell/enc.sh b/rootfs/link/shell/enc.sh index a2b0a85..af8e399 100644 --- a/rootfs/link/shell/enc.sh +++ b/rootfs/link/shell/enc.sh @@ -2,7 +2,7 @@ /link/shell/trans.sh & while [ true ] do -pkill OLED +pkill Monitor /link/bin/Encoder sleep 2 done diff --git a/rootfs/link/shell/fusb.sh b/rootfs/link/shell/fusb.sh index b8d7747..2d0deda 100644 --- a/rootfs/link/shell/fusb.sh +++ b/rootfs/link/shell/fusb.sh @@ -16,9 +16,15 @@ umount_usb(){ umount_usb if [ $1 == "ext4" ];then - echo -e "\ny" | mkfs.ext4 -T largefile /dev/sda1 - sleep 1 - mount -t ext4 /dev/sda1 /root/usb + if [ -b /dev/sda1 ];then + echo -e "\ny" | mkfs.ext4 -T largefile /dev/sda1 + sleep 1 + mount -t ext4 /dev/sda1 /root/usb + elif [ -b /dev/mmcblk0p6 ];then + echo -e "\ny" | mkfs.ext4 -T largefile /dev/mmcblk0p6 + sleep 1 + mount -o rw,sync,barrier=0 /dev/mmcblk0p6 /root/usb + fi else mkfs.vfat -F 32 /dev/sda1 sleep 1 diff --git a/rootfs/link/shell/init/filesystem.sh b/rootfs/link/shell/init/filesystem.sh index 2b0733a..9255c0c 100644 --- a/rootfs/link/shell/init/filesystem.sh +++ b/rootfs/link/shell/init/filesystem.sh @@ -11,6 +11,17 @@ if [ -b /dev/mmcblk0p5 ]; then fi if [ -b /dev/mmcblk0p6 ]; then -/bin/mount -o rw,sync,barrier=0 /dev/mmcblk0p6 /root/usb + /bin/mount -o rw,sync,barrier=0 /dev/mmcblk0p6 /root/usb + mnt=`df -h | grep /dev/mmcblk0p6 | wc -l` + if [ "$mnt" == "1" ] && [ ! -d /root/usb/lost+found ];then + umount -f /root/usb/ + mnt=`df -h | grep /dev/mmcblk0p6 | wc -l` + if [ "$mnt" == "0" ];then + echo -e "\ny" | mkfs.ext4 -T largefile /dev/mmcblk0p6 + if [ ! -b /dev/sda1 ];then + /bin/mount -o rw,sync,barrier=0 /dev/mmcblk0p6 /root/usb + fi + fi + fi fi diff --git a/rootfs/link/shell/init/service.sh b/rootfs/link/shell/init/service.sh index ffd8014..95f2cb0 100644 --- a/rootfs/link/shell/init/service.sh +++ b/rootfs/link/shell/init/service.sh @@ -22,6 +22,13 @@ if [ `jget nginx` == "true" ]; then fi if [ `jget crond` == "true" ]; then +if [ ! -f /var/spool/cron/crontabs/root ];then + touch /var/spool/cron/crontabs/root + echo "" >> /var/spool/cron/crontabs/root + echo "" >> /var/spool/cron/crontabs/root + echo "" >> /var/spool/cron/crontabs/root +fi +chown -R root:root /var/spool /usr/sbin/crond -d 8 fi diff --git a/rootfs/link/shell/monitor.sh b/rootfs/link/shell/monitor.sh new file mode 100644 index 0000000..1d33a08 --- /dev/null +++ b/rootfs/link/shell/monitor.sh @@ -0,0 +1,5 @@ +while [ true ] +do +/link/bin/Monitor +sleep 1 +done diff --git a/rootfs/link/shell/update.sh b/rootfs/link/shell/update.sh index 9f28ffa..cb65493 100644 --- a/rootfs/link/shell/update.sh +++ b/rootfs/link/shell/update.sh @@ -1,6 +1,6 @@ if [ ! -z "$(ls -A /link/update)" ]; then mv /link/update/* /link/update/update.tar - tar -xf /link/update/update.tar -C / + tar -xof /link/update/update.tar -C / sleep 1 if [ -c "/dev/mtd1" ]; then diff --git a/rootfs/link/web/dashboard.php b/rootfs/link/web/dashboard.php index 399429b..e9cc524 100644 --- a/rootfs/link/web/dashboard.php +++ b/rootfs/link/web/dashboard.php @@ -303,9 +303,6 @@ include("head.php"); } - - - function update() { rpc( "enc.getSysState", null, function ( data ) { try { @@ -356,10 +353,6 @@ include("head.php"); } - for( var i = hdmi.length; i < $( ".hdmi" ).length; i++ ){ - $( ".hdmi" ).eq( i ).hide(); - } - for ( var i = 0; i < sdi.length; i++ ) { if ( sdi[ i ].avalible ) { $( ".sdi" ).eq( i ).removeClass( "disable" ); @@ -371,11 +364,6 @@ include("head.php"); } } - - for( var i = sdi.length; i < $( ".sdi" ).length; i++ ){ - $( ".sdi" ).eq( i ).hide(); - } - } ); setTimeout( update, 3000 ); diff --git a/rootfs/link/web/func.php b/rootfs/link/web/func.php index 25553ff..e0985ce 100644 --- a/rootfs/link/web/func.php +++ b/rootfs/link/web/func.php @@ -116,19 +116,65 @@ function setCron() { if ( isset( $_POST[ 'day' ] ) && isset( $_POST[ 'time' ] ) ) { if ( $_POST[ 'day' ] == "x" ) { - exec( 'echo "" | crontab -u root -' ); + exec("sed -i '1s/.*/ /' /var/spool/cron/crontabs/root"); + exec("cp -a /var/spool/cron/crontabs/root /link/config/auto/root.cron"); } else { - exec( 'echo "0 ' . $_POST[ 'time' ] . ' * * ' . $_POST[ 'day' ] . ' /link/shell/reboot.sh" | crontab -u root -' ); + $cron = '0 ' . $_POST[ 'time' ] . ' * * ' . $_POST[ 'day' ]; + exec("sed -i '1s/.*/".$cron." \/link\/shell\/reboot.sh/' /var/spool/cron/crontabs/root"); exec("cp -a /var/spool/cron/crontabs/root /link/config/auto/root.cron"); } $result->result = "OK"; } else { - $result->result = shell_exec( 'crontab -u root -l' ); + $result->result = shell_exec( 'crontab -u root -l | grep /link/shell/reboot.sh' ); } } +function setPushCron() { + global $result; + $start = $_POST['start']; + if ( isset( $start[ 'day' ] ) && isset( $start[ 'time' ] ) ) { + if ( $start[ 'day' ] == "x" ) + { + exec("sed -i '2s/.*/ /' /var/spool/cron/crontabs/root"); + exec("cp -a /var/spool/cron/crontabs/root /link/config/auto/root.cron"); + } + else { + $tm = explode(":", $start[ 'time' ]); + $cron = intval($tm[1]).' ' . intval($tm[0]) . ' * * ' . $start[ 'day' ]; + exec("sed -i '2s/.*/".$cron." \/usr\/php\/bin\/php \/link\/web\/link\/timer\/autoPush.php start/' /var/spool/cron/crontabs/root"); + exec("cp -a /var/spool/cron/crontabs/root /link/config/auto/root.cron"); + } + } + + $stop = $_POST['stop']; + if ( isset( $stop[ 'day' ] ) && isset( $stop[ 'time' ] ) ) { + if ( $stop[ 'day' ] == "x" ) + { + exec("sed -i '3s/.*/ /' /var/spool/cron/crontabs/root"); + exec("cp -a /var/spool/cron/crontabs/root /link/config/auto/root.cron"); + } + else { + $tm = explode(":", $stop[ 'time' ]); + $cron = intval($tm[1]).' ' . intval($tm[0]) . ' * * ' . $stop[ 'day' ]; + exec("sed -i '3s/.*/".$cron." \/usr\/php\/bin\/php \/link\/web\/link\/timer\/autoPush.php stop/' /var/spool/cron/crontabs/root"); + exec("cp -a /var/spool/cron/crontabs/root /link/config/auto/root.cron"); + } + } + $result->result = "OK"; +} + +function getPushCron() { + global $result; + exec( "crontab -u root -l | grep '/link/web/link/timer/autoPush.php start'",$output1); + exec( "crontab -u root -l | grep '/link/web/link/timer/autoPush.php stop'",$output2); + $result->result = [ + 'start'=>$output1[0], + 'stop'=>$output2[0] + ]; +} + function startHelp() { global $result; global $hardware; diff --git a/rootfs/link/web/head.php b/rootfs/link/web/head.php index 6ea9315..5050545 100644 --- a/rootfs/link/web/head.php +++ b/rootfs/link/web/head.php @@ -84,14 +84,22 @@ include("headhead.php"); H5 播放器 H5 Player -
  • - 集成通信 - Intercom -
  • + + +
  • + 集成通信 + Intercom +
  • +
  • U盘助手 Usb Disk
  • + diff --git a/rootfs/link/web/intercom.php b/rootfs/link/web/intercom.php index ce913cc..c53bcdf 100644 --- a/rootfs/link/web/intercom.php +++ b/rootfs/link/web/intercom.php @@ -433,7 +433,7 @@ include( "head.php" ); var intercom=res.intercom; var tally=res.tally; var ids=[]; - ids.push(myid); + ids.push(Number(myid)); $("#did"+myid).addClass("alive"); $("#did"+myid).parent().parent().find("h3").text(myname); if(res.talking) @@ -444,7 +444,7 @@ include( "head.php" ); for(var i=0;ihttp://www.d-project.com/ + * @see http://jeromeetienne.github.com/jquery-qrcode/ + */ +var QRCode; + +(function () { + //--------------------------------------------------------------------- + // QRCode for JavaScript + // + // Copyright (c) 2009 Kazuhiko Arase + // + // URL: http://www.d-project.com/ + // + // Licensed under the MIT license: + // http://www.opensource.org/licenses/mit-license.php + // + // The word "QR Code" is registered trademark of + // DENSO WAVE INCORPORATED + // http://www.denso-wave.com/qrcode/faqpatent-e.html + // + //--------------------------------------------------------------------- + function QR8bitByte(data) { + this.mode = QRMode.MODE_8BIT_BYTE; + this.data = data; + this.parsedData = []; + + // Added to support UTF-8 Characters + for (var i = 0, l = this.data.length; i < l; i++) { + var byteArray = []; + var code = this.data.charCodeAt(i); + + if (code > 0x10000) { + byteArray[0] = 0xF0 | ((code & 0x1C0000) >>> 18); + byteArray[1] = 0x80 | ((code & 0x3F000) >>> 12); + byteArray[2] = 0x80 | ((code & 0xFC0) >>> 6); + byteArray[3] = 0x80 | (code & 0x3F); + } else if (code > 0x800) { + byteArray[0] = 0xE0 | ((code & 0xF000) >>> 12); + byteArray[1] = 0x80 | ((code & 0xFC0) >>> 6); + byteArray[2] = 0x80 | (code & 0x3F); + } else if (code > 0x80) { + byteArray[0] = 0xC0 | ((code & 0x7C0) >>> 6); + byteArray[1] = 0x80 | (code & 0x3F); + } else { + byteArray[0] = code; + } + + this.parsedData.push(byteArray); + } + + this.parsedData = Array.prototype.concat.apply([], this.parsedData); + + if (this.parsedData.length != this.data.length) { + this.parsedData.unshift(191); + this.parsedData.unshift(187); + this.parsedData.unshift(239); + } + } + + QR8bitByte.prototype = { + getLength: function (buffer) { + return this.parsedData.length; + }, + write: function (buffer) { + for (var i = 0, l = this.parsedData.length; i < l; i++) { + buffer.put(this.parsedData[i], 8); + } + } + }; + + function QRCodeModel(typeNumber, errorCorrectLevel) { + this.typeNumber = typeNumber; + this.errorCorrectLevel = errorCorrectLevel; + this.modules = null; + this.moduleCount = 0; + this.dataCache = null; + this.dataList = []; + } + + QRCodeModel.prototype={addData:function(data){var newData=new QR8bitByte(data);this.dataList.push(newData);this.dataCache=null;},isDark:function(row,col){if(row<0||this.moduleCount<=row||col<0||this.moduleCount<=col){throw new Error(row+","+col);} + return this.modules[row][col];},getModuleCount:function(){return this.moduleCount;},make:function(){this.makeImpl(false,this.getBestMaskPattern());},makeImpl:function(test,maskPattern){this.moduleCount=this.typeNumber*4+17;this.modules=new Array(this.moduleCount);for(var row=0;row=7){this.setupTypeNumber(test);} + if(this.dataCache==null){this.dataCache=QRCodeModel.createData(this.typeNumber,this.errorCorrectLevel,this.dataList);} + this.mapData(this.dataCache,maskPattern);},setupPositionProbePattern:function(row,col){for(var r=-1;r<=7;r++){if(row+r<=-1||this.moduleCount<=row+r)continue;for(var c=-1;c<=7;c++){if(col+c<=-1||this.moduleCount<=col+c)continue;if((0<=r&&r<=6&&(c==0||c==6))||(0<=c&&c<=6&&(r==0||r==6))||(2<=r&&r<=4&&2<=c&&c<=4)){this.modules[row+r][col+c]=true;}else{this.modules[row+r][col+c]=false;}}}},getBestMaskPattern:function(){var minLostPoint=0;var pattern=0;for(var i=0;i<8;i++){this.makeImpl(true,i);var lostPoint=QRUtil.getLostPoint(this);if(i==0||minLostPoint>lostPoint){minLostPoint=lostPoint;pattern=i;}} + return pattern;},createMovieClip:function(target_mc,instance_name,depth){var qr_mc=target_mc.createEmptyMovieClip(instance_name,depth);var cs=1;this.make();for(var row=0;row>i)&1)==1);this.modules[Math.floor(i/3)][i%3+this.moduleCount-8-3]=mod;} + for(var i=0;i<18;i++){var mod=(!test&&((bits>>i)&1)==1);this.modules[i%3+this.moduleCount-8-3][Math.floor(i/3)]=mod;}},setupTypeInfo:function(test,maskPattern){var data=(this.errorCorrectLevel<<3)|maskPattern;var bits=QRUtil.getBCHTypeInfo(data);for(var i=0;i<15;i++){var mod=(!test&&((bits>>i)&1)==1);if(i<6){this.modules[i][8]=mod;}else if(i<8){this.modules[i+1][8]=mod;}else{this.modules[this.moduleCount-15+i][8]=mod;}} + for(var i=0;i<15;i++){var mod=(!test&&((bits>>i)&1)==1);if(i<8){this.modules[8][this.moduleCount-i-1]=mod;}else if(i<9){this.modules[8][15-i-1+1]=mod;}else{this.modules[8][15-i-1]=mod;}} + this.modules[this.moduleCount-8][8]=(!test);},mapData:function(data,maskPattern){var inc=-1;var row=this.moduleCount-1;var bitIndex=7;var byteIndex=0;for(var col=this.moduleCount-1;col>0;col-=2){if(col==6)col--;while(true){for(var c=0;c<2;c++){if(this.modules[row][col-c]==null){var dark=false;if(byteIndex>>bitIndex)&1)==1);} + var mask=QRUtil.getMask(maskPattern,row,col-c);if(mask){dark=!dark;} + this.modules[row][col-c]=dark;bitIndex--;if(bitIndex==-1){byteIndex++;bitIndex=7;}}} + row+=inc;if(row<0||this.moduleCount<=row){row-=inc;inc=-inc;break;}}}}};QRCodeModel.PAD0=0xEC;QRCodeModel.PAD1=0x11;QRCodeModel.createData=function(typeNumber,errorCorrectLevel,dataList){var rsBlocks=QRRSBlock.getRSBlocks(typeNumber,errorCorrectLevel);var buffer=new QRBitBuffer();for(var i=0;itotalDataCount*8){throw new Error("code length overflow. (" + +buffer.getLengthInBits() + +">" + +totalDataCount*8 + +")");} + if(buffer.getLengthInBits()+4<=totalDataCount*8){buffer.put(0,4);} + while(buffer.getLengthInBits()%8!=0){buffer.putBit(false);} + while(true){if(buffer.getLengthInBits()>=totalDataCount*8){break;} + buffer.put(QRCodeModel.PAD0,8);if(buffer.getLengthInBits()>=totalDataCount*8){break;} + buffer.put(QRCodeModel.PAD1,8);} + return QRCodeModel.createBytes(buffer,rsBlocks);};QRCodeModel.createBytes=function(buffer,rsBlocks){var offset=0;var maxDcCount=0;var maxEcCount=0;var dcdata=new Array(rsBlocks.length);var ecdata=new Array(rsBlocks.length);for(var r=0;r=0)?modPoly.get(modIndex):0;}} + var totalCodeCount=0;for(var i=0;i=0){d^=(QRUtil.G15<<(QRUtil.getBCHDigit(d)-QRUtil.getBCHDigit(QRUtil.G15)));} + return((data<<10)|d)^QRUtil.G15_MASK;},getBCHTypeNumber:function(data){var d=data<<12;while(QRUtil.getBCHDigit(d)-QRUtil.getBCHDigit(QRUtil.G18)>=0){d^=(QRUtil.G18<<(QRUtil.getBCHDigit(d)-QRUtil.getBCHDigit(QRUtil.G18)));} + return(data<<12)|d;},getBCHDigit:function(data){var digit=0;while(data!=0){digit++;data>>>=1;} + return digit;},getPatternPosition:function(typeNumber){return QRUtil.PATTERN_POSITION_TABLE[typeNumber-1];},getMask:function(maskPattern,i,j){switch(maskPattern){case QRMaskPattern.PATTERN000:return(i+j)%2==0;case QRMaskPattern.PATTERN001:return i%2==0;case QRMaskPattern.PATTERN010:return j%3==0;case QRMaskPattern.PATTERN011:return(i+j)%3==0;case QRMaskPattern.PATTERN100:return(Math.floor(i/2)+Math.floor(j/3))%2==0;case QRMaskPattern.PATTERN101:return(i*j)%2+(i*j)%3==0;case QRMaskPattern.PATTERN110:return((i*j)%2+(i*j)%3)%2==0;case QRMaskPattern.PATTERN111:return((i*j)%3+(i+j)%2)%2==0;default:throw new Error("bad maskPattern:"+maskPattern);}},getErrorCorrectPolynomial:function(errorCorrectLength){var a=new QRPolynomial([1],0);for(var i=0;i5){lostPoint+=(3+sameCount-5);}}} + for(var row=0;row=256){n-=255;} + return QRMath.EXP_TABLE[n];},EXP_TABLE:new Array(256),LOG_TABLE:new Array(256)};for(var i=0;i<8;i++){QRMath.EXP_TABLE[i]=1<>>(7-index%8))&1)==1;},put:function(num,length){for(var i=0;i>>(length-i-1))&1)==1);}},getLengthInBits:function(){return this.length;},putBit:function(bit){var bufIndex=Math.floor(this.length/8);if(this.buffer.length<=bufIndex){this.buffer.push(0);} + if(bit){this.buffer[bufIndex]|=(0x80>>>(this.length%8));} + this.length++;}};var QRCodeLimitLength=[[17,14,11,7],[32,26,20,14],[53,42,32,24],[78,62,46,34],[106,84,60,44],[134,106,74,58],[154,122,86,64],[192,152,108,84],[230,180,130,98],[271,213,151,119],[321,251,177,137],[367,287,203,155],[425,331,241,177],[458,362,258,194],[520,412,292,220],[586,450,322,250],[644,504,364,280],[718,560,394,310],[792,624,442,338],[858,666,482,382],[929,711,509,403],[1003,779,565,439],[1091,857,611,461],[1171,911,661,511],[1273,997,715,535],[1367,1059,751,593],[1465,1125,805,625],[1528,1190,868,658],[1628,1264,908,698],[1732,1370,982,742],[1840,1452,1030,790],[1952,1538,1112,842],[2068,1628,1168,898],[2188,1722,1228,958],[2303,1809,1283,983],[2431,1911,1351,1051],[2563,1989,1423,1093],[2699,2099,1499,1139],[2809,2213,1579,1219],[2953,2331,1663,1273]]; + + function _isSupportCanvas() { + return typeof CanvasRenderingContext2D != "undefined"; + } + + // android 2.x doesn't support Data-URI spec + function _getAndroid() { + var android = false; + var sAgent = navigator.userAgent; + + if (/android/i.test(sAgent)) { // android + android = true; + var aMat = sAgent.toString().match(/android ([0-9]\.[0-9])/i); + + if (aMat && aMat[1]) { + android = parseFloat(aMat[1]); + } + } + + return android; + } + + var svgDrawer = (function() { + + var Drawing = function (el, htOption) { + this._el = el; + this._htOption = htOption; + }; + + Drawing.prototype.draw = function (oQRCode) { + var _htOption = this._htOption; + var _el = this._el; + var nCount = oQRCode.getModuleCount(); + var nWidth = Math.floor(_htOption.width / nCount); + var nHeight = Math.floor(_htOption.height / nCount); + + this.clear(); + + function makeSVG(tag, attrs) { + var el = document.createElementNS('http://www.w3.org/2000/svg', tag); + for (var k in attrs) + if (attrs.hasOwnProperty(k)) el.setAttribute(k, attrs[k]); + return el; + } + + var svg = makeSVG("svg" , {'viewBox': '0 0 ' + String(nCount) + " " + String(nCount), 'width': '100%', 'height': '100%', 'fill': _htOption.colorLight}); + svg.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:xlink", "http://www.w3.org/1999/xlink"); + _el.appendChild(svg); + + svg.appendChild(makeSVG("rect", {"fill": _htOption.colorLight, "width": "100%", "height": "100%"})); + svg.appendChild(makeSVG("rect", {"fill": _htOption.colorDark, "width": "1", "height": "1", "id": "template"})); + + for (var row = 0; row < nCount; row++) { + for (var col = 0; col < nCount; col++) { + if (oQRCode.isDark(row, col)) { + var child = makeSVG("use", {"x": String(col), "y": String(row)}); + child.setAttributeNS("http://www.w3.org/1999/xlink", "href", "#template") + svg.appendChild(child); + } + } + } + }; + Drawing.prototype.clear = function () { + while (this._el.hasChildNodes()) + this._el.removeChild(this._el.lastChild); + }; + return Drawing; + })(); + + var useSVG = document.documentElement.tagName.toLowerCase() === "svg"; + + // Drawing in DOM by using Table tag + var Drawing = useSVG ? svgDrawer : !_isSupportCanvas() ? (function () { + var Drawing = function (el, htOption) { + this._el = el; + this._htOption = htOption; + }; + + /** + * Draw the QRCode + * + * @param {QRCode} oQRCode + */ + Drawing.prototype.draw = function (oQRCode) { + var _htOption = this._htOption; + var _el = this._el; + var nCount = oQRCode.getModuleCount(); + var nWidth = Math.floor(_htOption.width / nCount); + var nHeight = Math.floor(_htOption.height / nCount); + var aHTML = ['']; + + for (var row = 0; row < nCount; row++) { + aHTML.push(''); + + for (var col = 0; col < nCount; col++) { + aHTML.push(''); + } + + aHTML.push(''); + } + + aHTML.push('
    '); + _el.innerHTML = aHTML.join(''); + + // Fix the margin values as real size. + var elTable = _el.childNodes[0]; + var nLeftMarginTable = (_htOption.width - elTable.offsetWidth) / 2; + var nTopMarginTable = (_htOption.height - elTable.offsetHeight) / 2; + + if (nLeftMarginTable > 0 && nTopMarginTable > 0) { + elTable.style.margin = nTopMarginTable + "px " + nLeftMarginTable + "px"; + } + }; + + /** + * Clear the QRCode + */ + Drawing.prototype.clear = function () { + this._el.innerHTML = ''; + }; + + return Drawing; + })() : (function () { // Drawing in Canvas + function _onMakeImage() { + this._elImage.src = this._elCanvas.toDataURL("image/png"); + this._elImage.style.display = "inline-block"; + this._elCanvas.style.display = "none"; + } + + // Android 2.1 bug workaround + // http://code.google.com/p/android/issues/detail?id=5141 + if (this._android && this._android <= 2.1) { + var factor = 1 / window.devicePixelRatio; + var drawImage = CanvasRenderingContext2D.prototype.drawImage; + CanvasRenderingContext2D.prototype.drawImage = function (image, sx, sy, sw, sh, dx, dy, dw, dh) { + if (("nodeName" in image) && /img/i.test(image.nodeName)) { + for (var i = arguments.length - 1; i >= 1; i--) { + arguments[i] = arguments[i] * factor; + } + } else if (typeof dw == "undefined") { + arguments[1] *= factor; + arguments[2] *= factor; + arguments[3] *= factor; + arguments[4] *= factor; + } + + drawImage.apply(this, arguments); + }; + } + + /** + * Check whether the user's browser supports Data URI or not + * + * @private + * @param {Function} fSuccess Occurs if it supports Data URI + * @param {Function} fFail Occurs if it doesn't support Data URI + */ + function _safeSetDataURI(fSuccess, fFail) { + var self = this; + self._fFail = fFail; + self._fSuccess = fSuccess; + + // Check it just once + if (self._bSupportDataURI === null) { + var el = document.createElement("img"); + var fOnError = function() { + self._bSupportDataURI = false; + + if (self._fFail) { + self._fFail.call(self); + } + }; + var fOnSuccess = function() { + self._bSupportDataURI = true; + + if (self._fSuccess) { + self._fSuccess.call(self); + } + }; + + el.onabort = fOnError; + el.onerror = fOnError; + el.onload = fOnSuccess; + el.src = "data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="; // the Image contains 1px data. + return; + } else if (self._bSupportDataURI === true && self._fSuccess) { + self._fSuccess.call(self); + } else if (self._bSupportDataURI === false && self._fFail) { + self._fFail.call(self); + } + }; + + /** + * Drawing QRCode by using canvas + * + * @constructor + * @param {HTMLElement} el + * @param {Object} htOption QRCode Options + */ + var Drawing = function (el, htOption) { + this._bIsPainted = false; + this._android = _getAndroid(); + + this._htOption = htOption; + this._elCanvas = document.createElement("canvas"); + this._elCanvas.width = htOption.width; + this._elCanvas.height = htOption.height; + el.appendChild(this._elCanvas); + this._el = el; + this._oContext = this._elCanvas.getContext("2d"); + this._bIsPainted = false; + this._elImage = document.createElement("img"); + this._elImage.alt = "Scan me!"; + this._elImage.style.display = "none"; + this._el.appendChild(this._elImage); + this._bSupportDataURI = null; + }; + + /** + * Draw the QRCode + * + * @param {QRCode} oQRCode + */ + Drawing.prototype.draw = function (oQRCode) { + var _elImage = this._elImage; + var _oContext = this._oContext; + var _htOption = this._htOption; + + var nCount = oQRCode.getModuleCount(); + var nWidth = _htOption.width / nCount; + var nHeight = _htOption.height / nCount; + var nRoundedWidth = Math.round(nWidth); + var nRoundedHeight = Math.round(nHeight); + + _elImage.style.display = "none"; + this.clear(); + + for (var row = 0; row < nCount; row++) { + for (var col = 0; col < nCount; col++) { + var bIsDark = oQRCode.isDark(row, col); + var nLeft = col * nWidth; + var nTop = row * nHeight; + _oContext.strokeStyle = bIsDark ? _htOption.colorDark : _htOption.colorLight; + _oContext.lineWidth = 1; + _oContext.fillStyle = bIsDark ? _htOption.colorDark : _htOption.colorLight; + _oContext.fillRect(nLeft, nTop, nWidth, nHeight); + + // 안티 앨리어싱 방지 처리 + _oContext.strokeRect( + Math.floor(nLeft) + 0.5, + Math.floor(nTop) + 0.5, + nRoundedWidth, + nRoundedHeight + ); + + _oContext.strokeRect( + Math.ceil(nLeft) - 0.5, + Math.ceil(nTop) - 0.5, + nRoundedWidth, + nRoundedHeight + ); + } + } + + this._bIsPainted = true; + }; + + /** + * Make the image from Canvas if the browser supports Data URI. + */ + Drawing.prototype.makeImage = function () { + if (this._bIsPainted) { + _safeSetDataURI.call(this, _onMakeImage); + } + }; + + /** + * Return whether the QRCode is painted or not + * + * @return {Boolean} + */ + Drawing.prototype.isPainted = function () { + return this._bIsPainted; + }; + + /** + * Clear the QRCode + */ + Drawing.prototype.clear = function () { + this._oContext.clearRect(0, 0, this._elCanvas.width, this._elCanvas.height); + this._bIsPainted = false; + }; + + /** + * @private + * @param {Number} nNumber + */ + Drawing.prototype.round = function (nNumber) { + if (!nNumber) { + return nNumber; + } + + return Math.floor(nNumber * 1000) / 1000; + }; + + return Drawing; + })(); + + /** + * Get the type by string length + * + * @private + * @param {String} sText + * @param {Number} nCorrectLevel + * @return {Number} type + */ + function _getTypeNumber(sText, nCorrectLevel) { + var nType = 1; + var length = _getUTF8Length(sText); + + for (var i = 0, len = QRCodeLimitLength.length; i <= len; i++) { + var nLimit = 0; + + switch (nCorrectLevel) { + case QRErrorCorrectLevel.L : + nLimit = QRCodeLimitLength[i][0]; + break; + case QRErrorCorrectLevel.M : + nLimit = QRCodeLimitLength[i][1]; + break; + case QRErrorCorrectLevel.Q : + nLimit = QRCodeLimitLength[i][2]; + break; + case QRErrorCorrectLevel.H : + nLimit = QRCodeLimitLength[i][3]; + break; + } + + if (length <= nLimit) { + break; + } else { + nType++; + } + } + + if (nType > QRCodeLimitLength.length) { + throw new Error("Too long data"); + } + + return nType; + } + + function _getUTF8Length(sText) { + var replacedText = encodeURI(sText).toString().replace(/\%[0-9a-fA-F]{2}/g, 'a'); + return replacedText.length + (replacedText.length != sText ? 3 : 0); + } + + /** + * @class QRCode + * @constructor + * @example + * new QRCode(document.getElementById("test"), "http://jindo.dev.naver.com/collie"); + * + * @example + * var oQRCode = new QRCode("test", { + * text : "http://naver.com", + * width : 128, + * height : 128 + * }); + * + * oQRCode.clear(); // Clear the QRCode. + * oQRCode.makeCode("http://map.naver.com"); // Re-create the QRCode. + * + * @param {HTMLElement|String} el target element or 'id' attribute of element. + * @param {Object|String} vOption + * @param {String} vOption.text QRCode link data + * @param {Number} [vOption.width=256] + * @param {Number} [vOption.height=256] + * @param {String} [vOption.colorDark="#000000"] + * @param {String} [vOption.colorLight="#ffffff"] + * @param {QRCode.CorrectLevel} [vOption.correctLevel=QRCode.CorrectLevel.H] [L|M|Q|H] + */ + QRCode = function (el, vOption) { + this._htOption = { + width : 256, + height : 256, + typeNumber : 4, + colorDark : "#000000", + colorLight : "#ffffff", + correctLevel : QRErrorCorrectLevel.H + }; + + if (typeof vOption === 'string') { + vOption = { + text : vOption + }; + } + + // Overwrites options + if (vOption) { + for (var i in vOption) { + this._htOption[i] = vOption[i]; + } + } + + if (typeof el == "string") { + el = document.getElementById(el); + } + + if (this._htOption.useSVG) { + Drawing = svgDrawer; + } + + this._android = _getAndroid(); + this._el = el; + this._oQRCode = null; + this._oDrawing = new Drawing(this._el, this._htOption); + + if (this._htOption.text) { + this.makeCode(this._htOption.text); + } + }; + + /** + * Make the QRCode + * + * @param {String} sText link data + */ + QRCode.prototype.makeCode = function (sText) { + this._oQRCode = new QRCodeModel(_getTypeNumber(sText, this._htOption.correctLevel), this._htOption.correctLevel); + this._oQRCode.addData(sText); + this._oQRCode.make(); + this._el.title = sText; + this._oDrawing.draw(this._oQRCode); + this.makeImage(); + }; + + /** + * Make the Image from Canvas element + * - It occurs automatically + * - Android below 3 doesn't support Data-URI spec. + * + * @private + */ + QRCode.prototype.makeImage = function () { + if (typeof this._oDrawing.makeImage == "function" && (!this._android || this._android >= 3)) { + this._oDrawing.makeImage(); + } + }; + + /** + * Clear the QRCode + */ + QRCode.prototype.clear = function () { + this._oDrawing.clear(); + }; + + /** + * @name QRCode.CorrectLevel + */ + QRCode.CorrectLevel = QRErrorCorrectLevel; +})(); diff --git a/rootfs/link/web/link/api/push.php b/rootfs/link/web/link/api/push.php new file mode 100644 index 0000000..0f9f358 --- /dev/null +++ b/rootfs/link/web/link/api/push.php @@ -0,0 +1,23 @@ +start_push(); + return $this->handleRet('','success','推流开启成功','start push successful'); + } + + + public function stop_push(): string + { + $client = new RpcClient(); + $client->stop_push(); + return $this->handleRet('','success','推流停止成功','stop push successful'); + } +} \ No newline at end of file diff --git a/rootfs/link/web/link/rpc/http/client.php b/rootfs/link/web/link/rpc/http/client.php index cea689d..8f3fdb4 100644 --- a/rootfs/link/web/link/rpc/http/client.php +++ b/rootfs/link/web/link/rpc/http/client.php @@ -165,7 +165,7 @@ class Client * Returns the object handle (so you can chain method calls if you're into * that kinky stuff) */ - public function query($method, $arguments, &$response) + public function query($method, $arguments, &$response = null) { $id = count($this->responses); $this->responses[$id] = &$response; diff --git a/rootfs/link/web/link/timer/autoPush.php b/rootfs/link/web/link/timer/autoPush.php new file mode 100644 index 0000000..f3e60b7 --- /dev/null +++ b/rootfs/link/web/link/timer/autoPush.php @@ -0,0 +1,19 @@ +[ + 'method'=>"POST" + ] +]; +$context = stream_context_create($opts); +$json = file_get_contents($url, false, $context); + diff --git a/rootfs/link/web/push.php b/rootfs/link/web/push.php index d1d9611..ac53317 100644 --- a/rootfs/link/web/push.php +++ b/rootfs/link/web/push.php @@ -1,10 +1,28 @@ + +
    -
    +

    视频预览 @@ -12,10 +30,30 @@ include( "head.php" ); 推流后可见visible when pushing

    -
    +
    +
    +
    +
    + [--:--] +
    +
    + + + +
    +
    +
    @@ -50,12 +88,81 @@ include( "head.php" );
    -
    - -
    - -
    -
    +
    +
    + +
    + +
    +
    +
    + + +
    +
    +
    +
    + +
    + +
    +
    +
    + + +
    +
    +
    +
    +
    + OR +
    +
    + +
    + +
    +
    + + + + + + + +
    @@ -68,26 +175,6 @@ include( "head.php" );
    -
    -
    -
    - [--:--] -
    -
    - - - -
    -
    -
    @@ -187,6 +274,7 @@ include( "head.php" ); + diff --git a/rootfs/link/web/rproxy.php b/rootfs/link/web/rproxy.php index 32a8f0c..3dd56a3 100644 --- a/rootfs/link/web/rproxy.php +++ b/rootfs/link/web/rproxy.php @@ -12,7 +12,7 @@ include( "head.php" );
    -
    +
    -
    - +
    - +

    -
    - +
    @@ -135,21 +137,51 @@ include( "head.php" );
    + + + @@ -136,7 +136,7 @@ switch ($page) { 保存设置失败Save config failed!", "", 2000 ); } else { diff --git a/rootfs/link/web/vendor/timepicker/css/bootstrap-timepicker.min.css b/rootfs/link/web/vendor/timepicker/css/bootstrap-timepicker.min.css new file mode 100644 index 0000000..2284c9c --- /dev/null +++ b/rootfs/link/web/vendor/timepicker/css/bootstrap-timepicker.min.css @@ -0,0 +1,146 @@ +/*! + * Timepicker Component for Twitter Bootstrap + * + * Copyright 2013 Joris de Wit + * + * Contributors https://github.com/jdewit/bootstrap-timepicker/graphs/contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +.bootstrap-timepicker { + position: relative; +} +.bootstrap-timepicker.pull-right .bootstrap-timepicker-widget.dropdown-menu { + left: auto; + right: 0; +} +.bootstrap-timepicker.pull-right .bootstrap-timepicker-widget.dropdown-menu:before { + left: auto; + right: 12px; +} +.bootstrap-timepicker.pull-right .bootstrap-timepicker-widget.dropdown-menu:after { + left: auto; + right: 13px; +} +.bootstrap-timepicker .input-group-addon { + cursor: pointer; +} +.bootstrap-timepicker .input-group-addon i { + display: inline-block; + width: 16px; + height: 16px; +} +.bootstrap-timepicker-widget.dropdown-menu { + padding: 4px; +} +.bootstrap-timepicker-widget.dropdown-menu.open { + display: inline-block; +} +.bootstrap-timepicker-widget.dropdown-menu:before { + border-bottom: 7px solid rgba(0, 0, 0, 0.2); + border-left: 7px solid transparent; + border-right: 7px solid transparent; + content: ""; + display: inline-block; + position: absolute; +} +.bootstrap-timepicker-widget.dropdown-menu:after { + border-bottom: 6px solid #FFFFFF; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + content: ""; + display: inline-block; + position: absolute; +} +.bootstrap-timepicker-widget.timepicker-orient-left:before { + left: 6px; +} +.bootstrap-timepicker-widget.timepicker-orient-left:after { + left: 7px; +} +.bootstrap-timepicker-widget.timepicker-orient-right:before { + right: 6px; +} +.bootstrap-timepicker-widget.timepicker-orient-right:after { + right: 7px; +} +.bootstrap-timepicker-widget.timepicker-orient-top:before { + top: -7px; +} +.bootstrap-timepicker-widget.timepicker-orient-top:after { + top: -6px; +} +.bootstrap-timepicker-widget.timepicker-orient-bottom:before { + bottom: -7px; + border-bottom: 0; + border-top: 7px solid #999; +} +.bootstrap-timepicker-widget.timepicker-orient-bottom:after { + bottom: -6px; + border-bottom: 0; + border-top: 6px solid #ffffff; +} +.bootstrap-timepicker-widget a.btn, +.bootstrap-timepicker-widget input { + border-radius: 4px; +} +.bootstrap-timepicker-widget table { + width: 100%; + margin: 0; +} +.bootstrap-timepicker-widget table td { + text-align: center; + height: 30px; + margin: 0; + padding: 2px; +} +.bootstrap-timepicker-widget table td:not(.separator) { + min-width: 30px; +} +.bootstrap-timepicker-widget table td span { + width: 100%; +} +.bootstrap-timepicker-widget table td a { + border: 1px transparent solid; + width: 100%; + display: inline-block; + margin: 0; + padding: 8px 0; + outline: 0; + color: #333; +} +.bootstrap-timepicker-widget table td a:hover { + text-decoration: none; + background-color: #eee; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + border-color: #ddd; +} +.bootstrap-timepicker-widget table td a i { + margin-top: 2px; + font-size: 18px; +} +.bootstrap-timepicker-widget table td input { + width: 25px; + margin: 0; + text-align: center; +} +.bootstrap-timepicker-widget .modal-content { + padding: 4px; +} +@media (min-width: 767px) { + .bootstrap-timepicker-widget.modal { + width: 200px; + margin-left: -100px; + } +} +@media (max-width: 767px) { + .bootstrap-timepicker { + width: 100%; + } + .bootstrap-timepicker .dropdown-menu { + width: 100%; + } +} \ No newline at end of file diff --git a/rootfs/link/web/vendor/timepicker/js/bootstrap-timepicker.min.js b/rootfs/link/web/vendor/timepicker/js/bootstrap-timepicker.min.js new file mode 100644 index 0000000..d7396f6 --- /dev/null +++ b/rootfs/link/web/vendor/timepicker/js/bootstrap-timepicker.min.js @@ -0,0 +1,1177 @@ +/*! + * Timepicker Component for Twitter Bootstrap + * + * Copyright 2013 Joris de Wit and bootstrap-timepicker contributors + * + * Contributors https://github.com/jdewit/bootstrap-timepicker/graphs/contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +(function($, window, document) { + 'use strict'; + + // TIMEPICKER PUBLIC CLASS DEFINITION + var Timepicker = function(element, options) { + this.widget = ''; + this.$element = $(element); + this.defaultTime = options.defaultTime; + this.disableFocus = options.disableFocus; + this.disableMousewheel = options.disableMousewheel; + this.isOpen = options.isOpen; + this.minuteStep = options.minuteStep; + this.modalBackdrop = options.modalBackdrop; + this.orientation = options.orientation; + this.secondStep = options.secondStep; + this.snapToStep = options.snapToStep; + this.showInputs = options.showInputs; + this.showMeridian = options.showMeridian; + this.showSeconds = options.showSeconds; + this.template = options.template; + this.appendWidgetTo = options.appendWidgetTo; + this.showWidgetOnAddonClick = options.showWidgetOnAddonClick; + this.icons = options.icons; + this.maxHours = options.maxHours; + this.explicitMode = options.explicitMode; // If true 123 = 1:23, 12345 = 1:23:45, else invalid. + + this.handleDocumentClick = function (e) { + var self = e.data.scope; + // This condition was inspired by bootstrap-datepicker. + // The element the timepicker is invoked on is the input but it has a sibling for addon/button. + if (!(self.$element.parent().find(e.target).length || + self.$widget.is(e.target) || + self.$widget.find(e.target).length)) { + self.hideWidget(); + } + }; + + this._init(); + }; + + Timepicker.prototype = { + + constructor: Timepicker, + _init: function() { + var self = this; + + if (this.showWidgetOnAddonClick && (this.$element.parent().hasClass('input-group') && this.$element.parent().hasClass('bootstrap-timepicker'))) { + this.$element.parent('.input-group.bootstrap-timepicker').find('.input-group-addon').on({ + 'click.timepicker': $.proxy(this.showWidget, this) + }); + this.$element.on({ + 'focus.timepicker': $.proxy(this.highlightUnit, this), + 'click.timepicker': $.proxy(this.highlightUnit, this), + 'keydown.timepicker': $.proxy(this.elementKeydown, this), + 'blur.timepicker': $.proxy(this.blurElement, this), + 'mousewheel.timepicker DOMMouseScroll.timepicker': $.proxy(this.mousewheel, this) + }); + } else { + if (this.template) { + this.$element.on({ + 'focus.timepicker': $.proxy(this.showWidget, this), + 'click.timepicker': $.proxy(this.showWidget, this), + 'blur.timepicker': $.proxy(this.blurElement, this), + 'mousewheel.timepicker DOMMouseScroll.timepicker': $.proxy(this.mousewheel, this) + }); + } else { + this.$element.on({ + 'focus.timepicker': $.proxy(this.highlightUnit, this), + 'click.timepicker': $.proxy(this.highlightUnit, this), + 'keydown.timepicker': $.proxy(this.elementKeydown, this), + 'blur.timepicker': $.proxy(this.blurElement, this), + 'mousewheel.timepicker DOMMouseScroll.timepicker': $.proxy(this.mousewheel, this) + }); + } + } + + if (this.template !== false) { + this.$widget = $(this.getTemplate()).on('click', $.proxy(this.widgetClick, this)); + } else { + this.$widget = false; + } + + if (this.showInputs && this.$widget !== false) { + this.$widget.find('input').each(function() { + $(this).on({ + 'click.timepicker': function() { $(this).select(); }, + 'keydown.timepicker': $.proxy(self.widgetKeydown, self), + 'keyup.timepicker': $.proxy(self.widgetKeyup, self) + }); + }); + } + + this.setDefaultTime(this.defaultTime); + }, + + blurElement: function() { + this.highlightedUnit = null; + this.updateFromElementVal(); + }, + + clear: function() { + this.hour = ''; + this.minute = ''; + this.second = ''; + this.meridian = ''; + + this.$element.val(''); + }, + + decrementHour: function() { + if (this.showMeridian) { + if (this.hour === 1) { + this.hour = 12; + } else if (this.hour === 12) { + this.hour--; + + return this.toggleMeridian(); + } else if (this.hour === 0) { + this.hour = 11; + + return this.toggleMeridian(); + } else { + this.hour--; + } + } else { + if (this.hour <= 0) { + this.hour = this.maxHours - 1; + } else { + this.hour--; + } + } + }, + + decrementMinute: function(step) { + var newVal; + + if (step) { + newVal = this.minute - step; + } else { + newVal = this.minute - this.minuteStep; + } + + if (newVal < 0) { + this.decrementHour(); + this.minute = newVal + 60; + } else { + this.minute = newVal; + } + }, + + decrementSecond: function() { + var newVal = this.second - this.secondStep; + + if (newVal < 0) { + this.decrementMinute(true); + this.second = newVal + 60; + } else { + this.second = newVal; + } + }, + + elementKeydown: function(e) { + switch (e.which) { + case 9: //tab + if (e.shiftKey) { + if (this.highlightedUnit === 'hour') { + this.hideWidget(); + break; + } + this.highlightPrevUnit(); + } else if ((this.showMeridian && this.highlightedUnit === 'meridian') || (this.showSeconds && this.highlightedUnit === 'second') || (!this.showMeridian && !this.showSeconds && this.highlightedUnit ==='minute')) { + this.hideWidget(); + break; + } else { + this.highlightNextUnit(); + } + e.preventDefault(); + this.updateFromElementVal(); + break; + case 27: // escape + this.updateFromElementVal(); + break; + case 37: // left arrow + e.preventDefault(); + this.highlightPrevUnit(); + this.updateFromElementVal(); + break; + case 38: // up arrow + e.preventDefault(); + switch (this.highlightedUnit) { + case 'hour': + this.incrementHour(); + this.highlightHour(); + break; + case 'minute': + this.incrementMinute(); + this.highlightMinute(); + break; + case 'second': + this.incrementSecond(); + this.highlightSecond(); + break; + case 'meridian': + this.toggleMeridian(); + this.highlightMeridian(); + break; + } + this.update(); + break; + case 39: // right arrow + e.preventDefault(); + this.highlightNextUnit(); + this.updateFromElementVal(); + break; + case 40: // down arrow + e.preventDefault(); + switch (this.highlightedUnit) { + case 'hour': + this.decrementHour(); + this.highlightHour(); + break; + case 'minute': + this.decrementMinute(); + this.highlightMinute(); + break; + case 'second': + this.decrementSecond(); + this.highlightSecond(); + break; + case 'meridian': + this.toggleMeridian(); + this.highlightMeridian(); + break; + } + + this.update(); + break; + } + }, + + getCursorPosition: function() { + var input = this.$element.get(0); + + if ('selectionStart' in input) {// Standard-compliant browsers + + return input.selectionStart; + } else if (document.selection) {// IE fix + input.focus(); + var sel = document.selection.createRange(), + selLen = document.selection.createRange().text.length; + + sel.moveStart('character', - input.value.length); + + return sel.text.length - selLen; + } + }, + + getTemplate: function() { + var template, + hourTemplate, + minuteTemplate, + secondTemplate, + meridianTemplate, + templateContent; + + if (this.showInputs) { + hourTemplate = ''; + minuteTemplate = ''; + secondTemplate = ''; + meridianTemplate = ''; + } else { + hourTemplate = ''; + minuteTemplate = ''; + secondTemplate = ''; + meridianTemplate = ''; + } + + templateContent = ''+ + ''+ + ''+ + ''+ + ''+ + (this.showSeconds ? + ''+ + '' + : '') + + (this.showMeridian ? + ''+ + '' + : '') + + ''+ + ''+ + ' '+ + ''+ + ' '+ + (this.showSeconds ? + ''+ + '' + : '') + + (this.showMeridian ? + ''+ + '' + : '') + + ''+ + ''+ + ''+ + ''+ + ''+ + (this.showSeconds ? + ''+ + '' + : '') + + (this.showMeridian ? + ''+ + '' + : '') + + ''+ + '
       
    '+ hourTemplate +':'+ minuteTemplate +':'+ secondTemplate +' '+ meridianTemplate +'
      
    '; + + switch(this.template) { + case 'modal': + template = ''; + break; + case 'dropdown': + template = ''; + break; + } + + return template; + }, + + getTime: function() { + if (this.hour === '') { + return ''; + } + + return this.hour + ':' + (this.minute.toString().length === 1 ? '0' + this.minute : this.minute) + (this.showSeconds ? ':' + (this.second.toString().length === 1 ? '0' + this.second : this.second) : '') + (this.showMeridian ? ' ' + this.meridian : ''); + }, + + hideWidget: function() { + if (this.isOpen === false) { + return; + } + + this.$element.trigger({ + 'type': 'hide.timepicker', + 'time': { + 'value': this.getTime(), + 'hours': this.hour, + 'minutes': this.minute, + 'seconds': this.second, + 'meridian': this.meridian + } + }); + + if (this.template === 'modal' && this.$widget.modal) { + this.$widget.modal('hide'); + } else { + this.$widget.removeClass('open'); + } + + $(document).off('mousedown.timepicker, touchend.timepicker', this.handleDocumentClick); + + this.isOpen = false; + // show/hide approach taken by datepicker + this.$widget.detach(); + }, + + highlightUnit: function() { + this.position = this.getCursorPosition(); + if (this.position >= 0 && this.position <= 2) { + this.highlightHour(); + } else if (this.position >= 3 && this.position <= 5) { + this.highlightMinute(); + } else if (this.position >= 6 && this.position <= 8) { + if (this.showSeconds) { + this.highlightSecond(); + } else { + this.highlightMeridian(); + } + } else if (this.position >= 9 && this.position <= 11) { + this.highlightMeridian(); + } + }, + + highlightNextUnit: function() { + switch (this.highlightedUnit) { + case 'hour': + this.highlightMinute(); + break; + case 'minute': + if (this.showSeconds) { + this.highlightSecond(); + } else if (this.showMeridian){ + this.highlightMeridian(); + } else { + this.highlightHour(); + } + break; + case 'second': + if (this.showMeridian) { + this.highlightMeridian(); + } else { + this.highlightHour(); + } + break; + case 'meridian': + this.highlightHour(); + break; + } + }, + + highlightPrevUnit: function() { + switch (this.highlightedUnit) { + case 'hour': + if(this.showMeridian){ + this.highlightMeridian(); + } else if (this.showSeconds) { + this.highlightSecond(); + } else { + this.highlightMinute(); + } + break; + case 'minute': + this.highlightHour(); + break; + case 'second': + this.highlightMinute(); + break; + case 'meridian': + if (this.showSeconds) { + this.highlightSecond(); + } else { + this.highlightMinute(); + } + break; + } + }, + + highlightHour: function() { + var $element = this.$element.get(0), + self = this; + + this.highlightedUnit = 'hour'; + + if ($element.setSelectionRange) { + setTimeout(function() { + if (self.hour < 10) { + $element.setSelectionRange(0,1); + } else { + $element.setSelectionRange(0,2); + } + }, 0); + } + }, + + highlightMinute: function() { + var $element = this.$element.get(0), + self = this; + + this.highlightedUnit = 'minute'; + + if ($element.setSelectionRange) { + setTimeout(function() { + if (self.hour < 10) { + $element.setSelectionRange(2,4); + } else { + $element.setSelectionRange(3,5); + } + }, 0); + } + }, + + highlightSecond: function() { + var $element = this.$element.get(0), + self = this; + + this.highlightedUnit = 'second'; + + if ($element.setSelectionRange) { + setTimeout(function() { + if (self.hour < 10) { + $element.setSelectionRange(5,7); + } else { + $element.setSelectionRange(6,8); + } + }, 0); + } + }, + + highlightMeridian: function() { + var $element = this.$element.get(0), + self = this; + + this.highlightedUnit = 'meridian'; + + if ($element.setSelectionRange) { + if (this.showSeconds) { + setTimeout(function() { + if (self.hour < 10) { + $element.setSelectionRange(8,10); + } else { + $element.setSelectionRange(9,11); + } + }, 0); + } else { + setTimeout(function() { + if (self.hour < 10) { + $element.setSelectionRange(5,7); + } else { + $element.setSelectionRange(6,8); + } + }, 0); + } + } + }, + + incrementHour: function() { + if (this.showMeridian) { + if (this.hour === 11) { + this.hour++; + return this.toggleMeridian(); + } else if (this.hour === 12) { + this.hour = 0; + } + } + if (this.hour === this.maxHours - 1) { + this.hour = 0; + + return; + } + this.hour++; + }, + + incrementMinute: function(step) { + var newVal; + + if (step) { + newVal = this.minute + step; + } else { + newVal = this.minute + this.minuteStep - (this.minute % this.minuteStep); + } + + if (newVal > 59) { + this.incrementHour(); + this.minute = newVal - 60; + } else { + this.minute = newVal; + } + }, + + incrementSecond: function() { + var newVal = this.second + this.secondStep - (this.second % this.secondStep); + + if (newVal > 59) { + this.incrementMinute(true); + this.second = newVal - 60; + } else { + this.second = newVal; + } + }, + + mousewheel: function(e) { + if (this.disableMousewheel) { + return; + } + + e.preventDefault(); + e.stopPropagation(); + + var delta = e.originalEvent.wheelDelta || -e.originalEvent.detail, + scrollTo = null; + + if (e.type === 'mousewheel') { + scrollTo = (e.originalEvent.wheelDelta * -1); + } + else if (e.type === 'DOMMouseScroll') { + scrollTo = 40 * e.originalEvent.detail; + } + + if (scrollTo) { + e.preventDefault(); + $(this).scrollTop(scrollTo + $(this).scrollTop()); + } + + switch (this.highlightedUnit) { + case 'minute': + if (delta > 0) { + this.incrementMinute(); + } else { + this.decrementMinute(); + } + this.highlightMinute(); + break; + case 'second': + if (delta > 0) { + this.incrementSecond(); + } else { + this.decrementSecond(); + } + this.highlightSecond(); + break; + case 'meridian': + this.toggleMeridian(); + this.highlightMeridian(); + break; + default: + if (delta > 0) { + this.incrementHour(); + } else { + this.decrementHour(); + } + this.highlightHour(); + break; + } + + return false; + }, + + /** + * Given a segment value like 43, will round and snap the segment + * to the nearest "step", like 45 if step is 15. Segment will + * "overflow" to 0 if it's larger than 59 or would otherwise + * round up to 60. + */ + changeToNearestStep: function (segment, step) { + if (segment % step === 0) { + return segment; + } + if (Math.round((segment % step) / step)) { + return (segment + (step - segment % step)) % 60; + } else { + return segment - segment % step; + } + }, + + // This method was adapted from bootstrap-datepicker. + place : function() { + if (this.isInline) { + return; + } + var widgetWidth = this.$widget.outerWidth(), widgetHeight = this.$widget.outerHeight(), visualPadding = 10, windowWidth = + $(window).width(), windowHeight = $(window).height(), scrollTop = $(window).scrollTop(); + + var zIndex = parseInt(this.$element.parents().filter(function() { return $(this).css('z-index') !== 'auto'; }).first().css('z-index'), 10) + 10; + var offset = this.component ? this.component.parent().offset() : this.$element.offset(); + var height = this.component ? this.component.outerHeight(true) : this.$element.outerHeight(false); + var width = this.component ? this.component.outerWidth(true) : this.$element.outerWidth(false); + var left = offset.left, top = offset.top; + + this.$widget.removeClass('timepicker-orient-top timepicker-orient-bottom timepicker-orient-right timepicker-orient-left'); + + if (this.orientation.x !== 'auto') { + this.$widget.addClass('timepicker-orient-' + this.orientation.x); + if (this.orientation.x === 'right') { + left -= widgetWidth - width; + } + } else{ + // auto x orientation is best-placement: if it crosses a window edge, fudge it sideways + // Default to left + this.$widget.addClass('timepicker-orient-left'); + if (offset.left < 0) { + left -= offset.left - visualPadding; + } else if (offset.left + widgetWidth > windowWidth) { + left = windowWidth - widgetWidth - visualPadding; + } + } + // auto y orientation is best-situation: top or bottom, no fudging, decision based on which shows more of the widget + var yorient = this.orientation.y, topOverflow, bottomOverflow; + if (yorient === 'auto') { + topOverflow = -scrollTop + offset.top - widgetHeight; + bottomOverflow = scrollTop + windowHeight - (offset.top + height + widgetHeight); + if (Math.max(topOverflow, bottomOverflow) === bottomOverflow) { + yorient = 'top'; + } else { + yorient = 'bottom'; + } + } + this.$widget.addClass('timepicker-orient-' + yorient); + if (yorient === 'top'){ + top += height; + } else{ + top -= widgetHeight + parseInt(this.$widget.css('padding-top'), 10); + } + + this.$widget.css({ + top : top, + left : left, + zIndex : zIndex + }); + }, + + remove: function() { + $('document').off('.timepicker'); + if (this.$widget) { + this.$widget.remove(); + } + delete this.$element.data().timepicker; + }, + + setDefaultTime: function(defaultTime) { + if (!this.$element.val()) { + if (defaultTime === 'current') { + var dTime = new Date(), + hours = dTime.getHours(), + minutes = dTime.getMinutes(), + seconds = dTime.getSeconds(), + meridian = 'AM'; + + if (seconds !== 0) { + seconds = Math.ceil(dTime.getSeconds() / this.secondStep) * this.secondStep; + if (seconds === 60) { + minutes += 1; + seconds = 0; + } + } + + if (minutes !== 0) { + minutes = Math.ceil(dTime.getMinutes() / this.minuteStep) * this.minuteStep; + if (minutes === 60) { + hours += 1; + minutes = 0; + } + } + + if (this.showMeridian) { + if (hours === 0) { + hours = 12; + } else if (hours >= 12) { + if (hours > 12) { + hours = hours - 12; + } + meridian = 'PM'; + } else { + meridian = 'AM'; + } + } + + this.hour = hours; + this.minute = minutes; + this.second = seconds; + this.meridian = meridian; + + this.update(); + + } else if (defaultTime === false) { + this.hour = 0; + this.minute = 0; + this.second = 0; + this.meridian = 'AM'; + } else { + this.setTime(defaultTime); + } + } else { + this.updateFromElementVal(); + } + }, + + setTime: function(time, ignoreWidget) { + if (!time) { + this.clear(); + return; + } + + var timeMode, + timeArray, + hour, + minute, + second, + meridian; + + if (typeof time === 'object' && time.getMonth){ + // this is a date object + hour = time.getHours(); + minute = time.getMinutes(); + second = time.getSeconds(); + + if (this.showMeridian){ + meridian = 'AM'; + if (hour > 12){ + meridian = 'PM'; + hour = hour % 12; + } + + if (hour === 12){ + meridian = 'PM'; + } + } + } else { + timeMode = ((/a/i).test(time) ? 1 : 0) + ((/p/i).test(time) ? 2 : 0); // 0 = none, 1 = AM, 2 = PM, 3 = BOTH. + if (timeMode > 2) { // If both are present, fail. + this.clear(); + return; + } + + timeArray = time.replace(/[^0-9\:]/g, '').split(':'); + + hour = timeArray[0] ? timeArray[0].toString() : timeArray.toString(); + + if(this.explicitMode && hour.length > 2 && (hour.length % 2) !== 0 ) { + this.clear(); + return; + } + + minute = timeArray[1] ? timeArray[1].toString() : ''; + second = timeArray[2] ? timeArray[2].toString() : ''; + + // adaptive time parsing + if (hour.length > 4) { + second = hour.slice(-2); + hour = hour.slice(0, -2); + } + + if (hour.length > 2) { + minute = hour.slice(-2); + hour = hour.slice(0, -2); + } + + if (minute.length > 2) { + second = minute.slice(-2); + minute = minute.slice(0, -2); + } + + hour = parseInt(hour, 10); + minute = parseInt(minute, 10); + second = parseInt(second, 10); + + if (isNaN(hour)) { + hour = 0; + } + if (isNaN(minute)) { + minute = 0; + } + if (isNaN(second)) { + second = 0; + } + + // Adjust the time based upon unit boundary. + // NOTE: Negatives will never occur due to time.replace() above. + if (second > 59) { + second = 59; + } + + if (minute > 59) { + minute = 59; + } + + if (hour >= this.maxHours) { + // No day/date handling. + hour = this.maxHours - 1; + } + + if (this.showMeridian) { + if (hour > 12) { + // Force PM. + timeMode = 2; + hour -= 12; + } + if (!timeMode) { + timeMode = 1; + } + if (hour === 0) { + hour = 12; // AM or PM, reset to 12. 0 AM = 12 AM. 0 PM = 12 PM, etc. + } + meridian = timeMode === 1 ? 'AM' : 'PM'; + } else if (hour < 12 && timeMode === 2) { + hour += 12; + } else { + if (hour >= this.maxHours) { + hour = this.maxHours - 1; + } else if ((hour < 0) || (hour === 12 && timeMode === 1)){ + hour = 0; + } + } + } + + this.hour = hour; + if (this.snapToStep) { + this.minute = this.changeToNearestStep(minute, this.minuteStep); + this.second = this.changeToNearestStep(second, this.secondStep); + } else { + this.minute = minute; + this.second = second; + } + this.meridian = meridian; + + this.update(ignoreWidget); + }, + + showWidget: function() { + if (this.isOpen) { + return; + } + + if (this.$element.is(':disabled')) { + return; + } + + // show/hide approach taken by datepicker + this.$widget.appendTo(this.appendWidgetTo); + $(document).on('mousedown.timepicker, touchend.timepicker', {scope: this}, this.handleDocumentClick); + + this.$element.trigger({ + 'type': 'show.timepicker', + 'time': { + 'value': this.getTime(), + 'hours': this.hour, + 'minutes': this.minute, + 'seconds': this.second, + 'meridian': this.meridian + } + }); + + this.place(); + if (this.disableFocus) { + this.$element.blur(); + } + + // widget shouldn't be empty on open + if (this.hour === '') { + if (this.defaultTime) { + this.setDefaultTime(this.defaultTime); + } else { + this.setTime('0:0:0'); + } + } + + if (this.template === 'modal' && this.$widget.modal) { + this.$widget.modal('show').on('hidden', $.proxy(this.hideWidget, this)); + } else { + if (this.isOpen === false) { + this.$widget.addClass('open'); + } + } + + this.isOpen = true; + }, + + toggleMeridian: function() { + this.meridian = this.meridian === 'AM' ? 'PM' : 'AM'; + }, + + update: function(ignoreWidget) { + this.updateElement(); + if (!ignoreWidget) { + this.updateWidget(); + } + + this.$element.trigger({ + 'type': 'changeTime.timepicker', + 'time': { + 'value': this.getTime(), + 'hours': this.hour, + 'minutes': this.minute, + 'seconds': this.second, + 'meridian': this.meridian + } + }); + }, + + updateElement: function() { + this.$element.val(this.getTime()).change(); + }, + + updateFromElementVal: function() { + this.setTime(this.$element.val()); + }, + + updateWidget: function() { + if (this.$widget === false) { + return; + } + + var hour = this.hour, + minute = this.minute.toString().length === 1 ? '0' + this.minute : this.minute, + second = this.second.toString().length === 1 ? '0' + this.second : this.second; + + if (this.showInputs) { + this.$widget.find('input.bootstrap-timepicker-hour').val(hour); + this.$widget.find('input.bootstrap-timepicker-minute').val(minute); + + if (this.showSeconds) { + this.$widget.find('input.bootstrap-timepicker-second').val(second); + } + if (this.showMeridian) { + this.$widget.find('input.bootstrap-timepicker-meridian').val(this.meridian); + } + } else { + this.$widget.find('span.bootstrap-timepicker-hour').text(hour); + this.$widget.find('span.bootstrap-timepicker-minute').text(minute); + + if (this.showSeconds) { + this.$widget.find('span.bootstrap-timepicker-second').text(second); + } + if (this.showMeridian) { + this.$widget.find('span.bootstrap-timepicker-meridian').text(this.meridian); + } + } + }, + + updateFromWidgetInputs: function() { + if (this.$widget === false) { + return; + } + + var t = this.$widget.find('input.bootstrap-timepicker-hour').val() + ':' + + this.$widget.find('input.bootstrap-timepicker-minute').val() + + (this.showSeconds ? ':' + this.$widget.find('input.bootstrap-timepicker-second').val() : '') + + (this.showMeridian ? this.$widget.find('input.bootstrap-timepicker-meridian').val() : '') + ; + + this.setTime(t, true); + }, + + widgetClick: function(e) { + e.stopPropagation(); + e.preventDefault(); + + var $input = $(e.target), + action = $input.closest('a').data('action'); + + if (action) { + this[action](); + } + this.update(); + + if ($input.is('input')) { + $input.get(0).setSelectionRange(0,2); + } + }, + + widgetKeydown: function(e) { + var $input = $(e.target), + name = $input.attr('class').replace('bootstrap-timepicker-', ''); + + switch (e.which) { + case 9: //tab + if (e.shiftKey) { + if (name === 'hour') { + return this.hideWidget(); + } + } else if ((this.showMeridian && name === 'meridian') || (this.showSeconds && name === 'second') || (!this.showMeridian && !this.showSeconds && name === 'minute')) { + return this.hideWidget(); + } + break; + case 27: // escape + this.hideWidget(); + break; + case 38: // up arrow + e.preventDefault(); + switch (name) { + case 'hour': + this.incrementHour(); + break; + case 'minute': + this.incrementMinute(); + break; + case 'second': + this.incrementSecond(); + break; + case 'meridian': + this.toggleMeridian(); + break; + } + this.setTime(this.getTime()); + $input.get(0).setSelectionRange(0,2); + break; + case 40: // down arrow + e.preventDefault(); + switch (name) { + case 'hour': + this.decrementHour(); + break; + case 'minute': + this.decrementMinute(); + break; + case 'second': + this.decrementSecond(); + break; + case 'meridian': + this.toggleMeridian(); + break; + } + this.setTime(this.getTime()); + $input.get(0).setSelectionRange(0,2); + break; + } + }, + + widgetKeyup: function(e) { + if ((e.which === 65) || (e.which === 77) || (e.which === 80) || (e.which === 46) || (e.which === 8) || (e.which >= 48 && e.which <= 57) || (e.which >= 96 && e.which <= 105)) { + this.updateFromWidgetInputs(); + } + } + }; + + //TIMEPICKER PLUGIN DEFINITION + $.fn.timepicker = function(option) { + var args = Array.apply(null, arguments); + args.shift(); + return this.each(function() { + var $this = $(this), + data = $this.data('timepicker'), + options = typeof option === 'object' && option; + + if (!data) { + $this.data('timepicker', (data = new Timepicker(this, $.extend({}, $.fn.timepicker.defaults, options, $(this).data())))); + } + + if (typeof option === 'string') { + data[option].apply(data, args); + } + }); + }; + + $.fn.timepicker.defaults = { + defaultTime: 'current', + disableFocus: false, + disableMousewheel: false, + isOpen: false, + minuteStep: 15, + modalBackdrop: false, + orientation: { x: 'auto', y: 'auto'}, + secondStep: 15, + snapToStep: false, + showSeconds: false, + showInputs: true, + showMeridian: true, + template: 'dropdown', + appendWidgetTo: 'body', + showWidgetOnAddonClick: true, + icons: { + up: 'glyphicon glyphicon-chevron-up', + down: 'glyphicon glyphicon-chevron-down' + }, + maxHours: 24, + explicitMode: false + }; + + $.fn.timepicker.Constructor = Timepicker; + + $(document).on( + 'focus.timepicker.data-api click.timepicker.data-api', + '[data-provide="timepicker"]', + function(e){ + var $this = $(this); + if ($this.data('timepicker')) { + return; + } + e.preventDefault(); + // component click requires us to explicitly show it + $this.timepicker(); + } + ); + +})(jQuery, window, document); \ No newline at end of file diff --git a/rootfs/usr/lib/libLinkBase.so.1.0.0 b/rootfs/usr/lib/libLinkBase.so.1.0.0 index 39275ca..7f80e98 100644 Binary files a/rootfs/usr/lib/libLinkBase.so.1.0.0 and b/rootfs/usr/lib/libLinkBase.so.1.0.0 differ diff --git a/rootfs/usr/lib/libLinkCodec.so.1.0.0 b/rootfs/usr/lib/libLinkCodec.so.1.0.0 index 2887186..4513f51 100644 Binary files a/rootfs/usr/lib/libLinkCodec.so.1.0.0 and b/rootfs/usr/lib/libLinkCodec.so.1.0.0 differ diff --git a/rootfs/usr/lib/libLinkGB28181.so.1.0.0 b/rootfs/usr/lib/libLinkGB28181.so.1.0.0 index 181216b..aeba344 100644 Binary files a/rootfs/usr/lib/libLinkGB28181.so.1.0.0 and b/rootfs/usr/lib/libLinkGB28181.so.1.0.0 differ diff --git a/rootfs/usr/lib/libLinkIO.so.1.0.0 b/rootfs/usr/lib/libLinkIO.so.1.0.0 index a14880b..b93f251 100644 Binary files a/rootfs/usr/lib/libLinkIO.so.1.0.0 and b/rootfs/usr/lib/libLinkIO.so.1.0.0 differ diff --git a/rootfs/usr/lib/libLinkNDI.so.1.0.0 b/rootfs/usr/lib/libLinkNDI.so.1.0.0 index cac89f2..df61450 100644 Binary files a/rootfs/usr/lib/libLinkNDI.so.1.0.0 and b/rootfs/usr/lib/libLinkNDI.so.1.0.0 differ diff --git a/rootfs/usr/lib/libLinkStream.so.1.0.0 b/rootfs/usr/lib/libLinkStream.so.1.0.0 index 4c0ca8c..a36f08a 100644 Binary files a/rootfs/usr/lib/libLinkStream.so.1.0.0 and b/rootfs/usr/lib/libLinkStream.so.1.0.0 differ diff --git a/rootfs/usr/nginx/conf/mime.types b/rootfs/usr/nginx/conf/mime.types index 89be9a4..ce1aec1 100644 --- a/rootfs/usr/nginx/conf/mime.types +++ b/rootfs/usr/nginx/conf/mime.types @@ -1,5 +1,6 @@ types { + text/inc inc; text/html html htm shtml; text/css css; text/xml xml; diff --git a/rootfs/usr/nginx/conf/nginx.conf b/rootfs/usr/nginx/conf/nginx.conf index cc0e9f9..47f06dc 100644 --- a/rootfs/usr/nginx/conf/nginx.conf +++ b/rootfs/usr/nginx/conf/nginx.conf @@ -111,6 +111,8 @@ http { location / { ssi on; + ssi_silent_errors on; + ssi_types text/inc; root /link/web; index dashboard.php; @@ -143,6 +145,11 @@ http { proxy_pass http://127.0.0.1:7010/RPC; proxy_max_temp_file_size 0m; } + + location /RPC6 { + proxy_pass http://127.0.0.1:7020/RPC; + proxy_max_temp_file_size 0m; + } location ~ /socket.io { proxy_pass http://127.0.0.1:7857; @@ -162,11 +169,15 @@ http { location /hls/ { alias /tmp/hls/; + add_header Cache-Control no-store; + add_header Access-Control-Allow-Origin *; + add_header Access-Control-Allow-Headers X-Requested-With,content-type; + add_header Access-Control-Allow-Methods GET,POST,OPTIONS; } location /config/ { alias /link/config/; - add_header Cache-Control no-store; + add_header Cache-Control no-store; add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Headers X-Requested-With,content-type; add_header Access-Control-Allow-Methods GET,POST,OPTIONS; diff --git a/rootfs/usr/nginx/sbin/nginx b/rootfs/usr/nginx/sbin/nginx index cdd23ae..1aa3fe4 100644 Binary files a/rootfs/usr/nginx/sbin/nginx and b/rootfs/usr/nginx/sbin/nginx differ diff --git a/rootfs/usr/qt/lib/libQt5Qmqtt.so b/rootfs/usr/qt/lib/libQt5Qmqtt.so new file mode 120000 index 0000000..3381c95 --- /dev/null +++ b/rootfs/usr/qt/lib/libQt5Qmqtt.so @@ -0,0 +1 @@ +libQt5Qmqtt.so.1.0.2 \ No newline at end of file diff --git a/rootfs/usr/qt/lib/libQt5Qmqtt.so.1 b/rootfs/usr/qt/lib/libQt5Qmqtt.so.1 new file mode 120000 index 0000000..3381c95 --- /dev/null +++ b/rootfs/usr/qt/lib/libQt5Qmqtt.so.1 @@ -0,0 +1 @@ +libQt5Qmqtt.so.1.0.2 \ No newline at end of file diff --git a/rootfs/usr/qt/lib/libQt5Qmqtt.so.1.0 b/rootfs/usr/qt/lib/libQt5Qmqtt.so.1.0 new file mode 120000 index 0000000..3381c95 --- /dev/null +++ b/rootfs/usr/qt/lib/libQt5Qmqtt.so.1.0 @@ -0,0 +1 @@ +libQt5Qmqtt.so.1.0.2 \ No newline at end of file diff --git a/rootfs/usr/qt/lib/libQt5Qmqtt.so.1.0.2 b/rootfs/usr/qt/lib/libQt5Qmqtt.so.1.0.2 new file mode 100644 index 0000000..68010bd Binary files /dev/null and b/rootfs/usr/qt/lib/libQt5Qmqtt.so.1.0.2 differ diff --git a/rootfs/var/spool/cron/crontabs/root b/rootfs/var/spool/cron/crontabs/root new file mode 100644 index 0000000..b7ec413 --- /dev/null +++ b/rootfs/var/spool/cron/crontabs/root @@ -0,0 +1,3 @@ + + +