测试版本库,随便折腾。
陈炜
2022-09-13 7cddd83d6de8a30cc0dd759a077db79d5d09d7fd
合并提交
已添加24个文件
4779 ■■■■■ 文件已修改
0.default.conf 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
49c6b2e842c45bff058c346866e55f799e6b3d53d116898c3386f87d2623d9da/49c6b2e842c45bff058c346866e55f799e6b3d53d116898c3386f87d2623d9da-json.log 251 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
49c6b2e842c45bff058c346866e55f799e6b3d53d116898c3386f87d2623d9da/config.v2.json 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
49c6b2e842c45bff058c346866e55f799e6b3d53d116898c3386f87d2623d9da/hostconfig.json 100 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
49c6b2e842c45bff058c346866e55f799e6b3d53d116898c3386f87d2623d9da/hostname 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
49c6b2e842c45bff058c346866e55f799e6b3d53d116898c3386f87d2623d9da/hosts 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
49c6b2e842c45bff058c346866e55f799e6b3d53d116898c3386f87d2623d9da/resolv.conf 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
49c6b2e842c45bff058c346866e55f799e6b3d53d116898c3386f87d2623d9da/resolv.conf.hash 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Android FUStaKit Java API 参考文档.md 867 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Android FUStaKit 集成文档.md 1205 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
STA更新日志.md 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
duan.md 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
haha.sh 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
install.sh 738 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
java_gaga.com.conf 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
java_wa.cn.conf 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
manager.xml 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
nginx.conf 164 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
nn.cn.conf 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
phpfpm_status.conf 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server.xml 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web.xml 161 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
开关机盒子测试报告.md 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
黑宝塔install_6.0.sh 738 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
0.default.conf
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,7 @@
server
{
    listen 80;
    server_name _;
    index index.html;
    root /www/server/nginx/html;
}
49c6b2e842c45bff058c346866e55f799e6b3d53d116898c3386f87d2623d9da/49c6b2e842c45bff058c346866e55f799e6b3d53d116898c3386f87d2623d9da-json.log
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,251 @@
{"log":"/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration\n","stream":"stdout","time":"2022-07-05T17:11:43.023884377Z"}
{"log":"/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/\n","stream":"stdout","time":"2022-07-05T17:11:43.023953693Z"}
{"log":"/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh\n","stream":"stdout","time":"2022-07-05T17:11:43.027132386Z"}
{"log":"10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf\n","stream":"stdout","time":"2022-07-05T17:11:43.053161519Z"}
{"log":"10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf\n","stream":"stdout","time":"2022-07-05T17:11:43.065952329Z"}
{"log":"/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh\n","stream":"stdout","time":"2022-07-05T17:11:43.066287049Z"}
{"log":"/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh\n","stream":"stdout","time":"2022-07-05T17:11:43.0714795Z"}
{"log":"/docker-entrypoint.sh: Configuration complete; ready for start up\n","stream":"stdout","time":"2022-07-05T17:11:43.074755632Z"}
{"log":"2022/07/05 17:11:43 [notice] 1#1: using the \"epoll\" event method\n","stream":"stderr","time":"2022-07-05T17:11:43.085978711Z"}
{"log":"2022/07/05 17:11:43 [notice] 1#1: nginx/1.23.0\n","stream":"stderr","time":"2022-07-05T17:11:43.086008851Z"}
{"log":"2022/07/05 17:11:43 [notice] 1#1: built by gcc 10.2.1 20210110 (Debian 10.2.1-6) \n","stream":"stderr","time":"2022-07-05T17:11:43.086016264Z"}
{"log":"2022/07/05 17:11:43 [notice] 1#1: OS: Linux 3.10.0-1160.el7.x86_64\n","stream":"stderr","time":"2022-07-05T17:11:43.086022197Z"}
{"log":"2022/07/05 17:11:43 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576\n","stream":"stderr","time":"2022-07-05T17:11:43.086027701Z"}
{"log":"2022/07/05 17:11:43 [notice] 1#1: start worker processes\n","stream":"stderr","time":"2022-07-05T17:11:43.086033201Z"}
{"log":"2022/07/05 17:11:43 [notice] 1#1: start worker process 31\n","stream":"stderr","time":"2022-07-05T17:11:43.086185158Z"}
{"log":"2022/07/05 17:11:43 [notice] 1#1: start worker process 32\n","stream":"stderr","time":"2022-07-05T17:11:43.086298454Z"}
{"log":"2022/07/05 17:11:43 [notice] 1#1: start worker process 33\n","stream":"stderr","time":"2022-07-05T17:11:43.086508701Z"}
{"log":"2022/07/05 17:11:43 [notice] 1#1: start worker process 34\n","stream":"stderr","time":"2022-07-05T17:11:43.086645748Z"}
{"log":"2022/07/05 17:11:43 [notice] 1#1: start worker process 35\n","stream":"stderr","time":"2022-07-05T17:11:43.086846015Z"}
{"log":"2022/07/05 17:11:43 [notice] 1#1: start worker process 36\n","stream":"stderr","time":"2022-07-05T17:11:43.087038398Z"}
{"log":"2022/07/05 17:11:43 [notice] 1#1: start worker process 37\n","stream":"stderr","time":"2022-07-05T17:11:43.087223435Z"}
{"log":"2022/07/05 17:11:43 [notice] 1#1: start worker process 38\n","stream":"stderr","time":"2022-07-05T17:11:43.088882515Z"}
{"log":"2022/07/05 17:11:43 [notice] 1#1: start worker process 39\n","stream":"stderr","time":"2022-07-05T17:11:43.088898883Z"}
{"log":"2022/07/05 17:11:43 [notice] 1#1: start worker process 40\n","stream":"stderr","time":"2022-07-05T17:11:43.088901981Z"}
{"log":"2022/07/05 17:11:43 [notice] 1#1: start worker process 41\n","stream":"stderr","time":"2022-07-05T17:11:43.088904384Z"}
{"log":"2022/07/05 17:11:43 [notice] 1#1: start worker process 42\n","stream":"stderr","time":"2022-07-05T17:11:43.088906786Z"}
{"log":"2022/07/05 17:11:43 [notice] 1#1: start worker process 43\n","stream":"stderr","time":"2022-07-05T17:11:43.088909311Z"}
{"log":"2022/07/05 17:11:43 [notice] 1#1: start worker process 44\n","stream":"stderr","time":"2022-07-05T17:11:43.088911564Z"}
{"log":"2022/07/05 17:11:43 [notice] 1#1: start worker process 45\n","stream":"stderr","time":"2022-07-05T17:11:43.088969256Z"}
{"log":"2022/07/05 17:11:43 [notice] 1#1: start worker process 46\n","stream":"stderr","time":"2022-07-05T17:11:43.089228027Z"}
{"log":"192.168.1.21 - - [05/Jul/2022:17:11:56 +0000] \"GET / HTTP/1.1\" 200 615 \"-\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36\" \"-\"\n","stream":"stdout","time":"2022-07-05T17:11:56.614265095Z"}
{"log":"192.168.1.21 - - [05/Jul/2022:17:11:56 +0000] \"GET /favicon.ico HTTP/1.1\" 404 555 \"http://192.168.1.233:8080/\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36\" \"-\"\n","stream":"stdout","time":"2022-07-05T17:11:56.698158889Z"}
{"log":"2022/07/05 17:11:56 [error] 32#32: *2 open() \"/usr/share/nginx/html/favicon.ico\" failed (2: No such file or directory), client: 192.168.1.21, server: localhost, request: \"GET /favicon.ico HTTP/1.1\", host: \"192.168.1.233:8080\", referrer: \"http://192.168.1.233:8080/\"\n","stream":"stderr","time":"2022-07-05T17:11:56.698244049Z"}
{"log":"2022/07/05 17:27:31 [notice] 1#1: signal 3 (SIGQUIT) received, shutting down\n","stream":"stderr","time":"2022-07-05T17:27:31.784883933Z"}
{"log":"2022/07/05 17:27:31 [notice] 32#32: gracefully shutting down\n","stream":"stderr","time":"2022-07-05T17:27:31.785033304Z"}
{"log":"2022/07/05 17:27:31 [notice] 32#32: exiting\n","stream":"stderr","time":"2022-07-05T17:27:31.785043587Z"}
{"log":"2022/07/05 17:27:31 [notice] 37#37: gracefully shutting down\n","stream":"stderr","time":"2022-07-05T17:27:31.7850468Z"}
{"log":"2022/07/05 17:27:31 [notice] 33#33: gracefully shutting down\n","stream":"stderr","time":"2022-07-05T17:27:31.785050024Z"}
{"log":"2022/07/05 17:27:31 [notice] 33#33: exiting\n","stream":"stderr","time":"2022-07-05T17:27:31.78505328Z"}
{"log":"2022/07/05 17:27:31 [notice] 37#37: exiting\n","stream":"stderr","time":"2022-07-05T17:27:31.78505666Z"}
{"log":"2022/07/05 17:27:31 [notice] 33#33: exit\n","stream":"stderr","time":"2022-07-05T17:27:31.785059675Z"}
{"log":"2022/07/05 17:27:31 [notice] 32#32: exit\n","stream":"stderr","time":"2022-07-05T17:27:31.785062615Z"}
{"log":"2022/07/05 17:27:31 [notice] 37#37: exit\n","stream":"stderr","time":"2022-07-05T17:27:31.785065819Z"}
{"log":"2022/07/05 17:27:31 [notice] 44#44: gracefully shutting down\n","stream":"stderr","time":"2022-07-05T17:27:31.785118012Z"}
{"log":"2022/07/05 17:27:31 [notice] 42#42: gracefully shutting down\n","stream":"stderr","time":"2022-07-05T17:27:31.785124897Z"}
{"log":"2022/07/05 17:27:31 [notice] 38#38: gracefully shutting down\n","stream":"stderr","time":"2022-07-05T17:27:31.785128102Z"}
{"log":"2022/07/05 17:27:31 [notice] 35#35: gracefully shutting down\n","stream":"stderr","time":"2022-07-05T17:27:31.785281534Z"}
{"log":"2022/07/05 17:27:31 [notice] 39#39: gracefully shutting down\n","stream":"stderr","time":"2022-07-05T17:27:31.785310007Z"}
{"log":"2022/07/05 17:27:31 [notice] 44#44: exiting\n","stream":"stderr","time":"2022-07-05T17:27:31.785316867Z"}
{"log":"2022/07/05 17:27:31 [notice] 42#42: exiting\n","stream":"stderr","time":"2022-07-05T17:27:31.78532278Z"}
{"log":"2022/07/05 17:27:31 [notice] 38#38: exiting\n","stream":"stderr","time":"2022-07-05T17:27:31.785328734Z"}
{"log":"2022/07/05 17:27:31 [notice] 40#40: gracefully shutting down\n","stream":"stderr","time":"2022-07-05T17:27:31.78533466Z"}
{"log":"2022/07/05 17:27:31 [notice] 35#35: exiting\n","stream":"stderr","time":"2022-07-05T17:27:31.785340464Z"}
{"log":"2022/07/05 17:27:31 [notice] 36#36: gracefully shutting down\n","stream":"stderr","time":"2022-07-05T17:27:31.785346727Z"}
{"log":"2022/07/05 17:27:31 [notice] 39#39: exiting\n","stream":"stderr","time":"2022-07-05T17:27:31.785352504Z"}
{"log":"2022/07/05 17:27:31 [notice] 40#40: exiting\n","stream":"stderr","time":"2022-07-05T17:27:31.785486697Z"}
{"log":"2022/07/05 17:27:31 [notice] 31#31: gracefully shutting down\n","stream":"stderr","time":"2022-07-05T17:27:31.785497671Z"}
{"log":"2022/07/05 17:27:31 [notice] 36#36: exiting\n","stream":"stderr","time":"2022-07-05T17:27:31.785503664Z"}
{"log":"2022/07/05 17:27:31 [notice] 35#35: exit\n","stream":"stderr","time":"2022-07-05T17:27:31.785509191Z"}
{"log":"2022/07/05 17:27:31 [notice] 44#44: exit\n","stream":"stderr","time":"2022-07-05T17:27:31.785529984Z"}
{"log":"2022/07/05 17:27:31 [notice] 42#42: exit\n","stream":"stderr","time":"2022-07-05T17:27:31.785536784Z"}
{"log":"2022/07/05 17:27:31 [notice] 38#38: exit\n","stream":"stderr","time":"2022-07-05T17:27:31.785542237Z"}
{"log":"2022/07/05 17:27:31 [notice] 31#31: exiting\n","stream":"stderr","time":"2022-07-05T17:27:31.785547857Z"}
{"log":"2022/07/05 17:27:31 [notice] 36#36: exit\n","stream":"stderr","time":"2022-07-05T17:27:31.785553251Z"}
{"log":"2022/07/05 17:27:31 [notice] 39#39: exit\n","stream":"stderr","time":"2022-07-05T17:27:31.785558431Z"}
{"log":"2022/07/05 17:27:31 [notice] 40#40: exit\n","stream":"stderr","time":"2022-07-05T17:27:31.785563757Z"}
{"log":"2022/07/05 17:27:31 [notice] 31#31: exit\n","stream":"stderr","time":"2022-07-05T17:27:31.785569204Z"}
{"log":"2022/07/05 17:27:31 [notice] 45#45: gracefully shutting down\n","stream":"stderr","time":"2022-07-05T17:27:31.785660804Z"}
{"log":"2022/07/05 17:27:31 [notice] 45#45: exiting\n","stream":"stderr","time":"2022-07-05T17:27:31.785670791Z"}
{"log":"2022/07/05 17:27:31 [notice] 45#45: exit\n","stream":"stderr","time":"2022-07-05T17:27:31.785758197Z"}
{"log":"2022/07/05 17:27:31 [notice] 34#34: gracefully shutting down\n","stream":"stderr","time":"2022-07-05T17:27:31.785874241Z"}
{"log":"2022/07/05 17:27:31 [notice] 34#34: exiting\n","stream":"stderr","time":"2022-07-05T17:27:31.785885124Z"}
{"log":"2022/07/05 17:27:31 [notice] 43#43: gracefully shutting down\n","stream":"stderr","time":"2022-07-05T17:27:31.785976184Z"}
{"log":"2022/07/05 17:27:31 [notice] 34#34: exit\n","stream":"stderr","time":"2022-07-05T17:27:31.785985534Z"}
{"log":"2022/07/05 17:27:31 [notice] 43#43: exiting\n","stream":"stderr","time":"2022-07-05T17:27:31.785991021Z"}
{"log":"2022/07/05 17:27:31 [notice] 43#43: exit\n","stream":"stderr","time":"2022-07-05T17:27:31.786072678Z"}
{"log":"2022/07/05 17:27:31 [notice] 41#41: gracefully shutting down\n","stream":"stderr","time":"2022-07-05T17:27:31.786081931Z"}
{"log":"2022/07/05 17:27:31 [notice] 41#41: exiting\n","stream":"stderr","time":"2022-07-05T17:27:31.786171004Z"}
{"log":"2022/07/05 17:27:31 [notice] 41#41: exit\n","stream":"stderr","time":"2022-07-05T17:27:31.786180041Z"}
{"log":"2022/07/05 17:27:31 [notice] 46#46: gracefully shutting down\n","stream":"stderr","time":"2022-07-05T17:27:31.786849618Z"}
{"log":"2022/07/05 17:27:31 [notice] 46#46: exiting\n","stream":"stderr","time":"2022-07-05T17:27:31.78699349Z"}
{"log":"2022/07/05 17:27:31 [notice] 46#46: exit\n","stream":"stderr","time":"2022-07-05T17:27:31.787007725Z"}
{"log":"2022/07/05 17:27:31 [notice] 1#1: signal 17 (SIGCHLD) received from 40\n","stream":"stderr","time":"2022-07-05T17:27:31.792423349Z"}
{"log":"2022/07/05 17:27:31 [notice] 1#1: worker process 40 exited with code 0\n","stream":"stderr","time":"2022-07-05T17:27:31.792444142Z"}
{"log":"2022/07/05 17:27:31 [notice] 1#1: worker process 39 exited with code 0\n","stream":"stderr","time":"2022-07-05T17:27:31.792448464Z"}
{"log":"2022/07/05 17:27:31 [notice] 1#1: signal 29 (SIGIO) received\n","stream":"stderr","time":"2022-07-05T17:27:31.792853331Z"}
{"log":"2022/07/05 17:27:31 [notice] 1#1: signal 17 (SIGCHLD) received from 39\n","stream":"stderr","time":"2022-07-05T17:27:31.792868194Z"}
{"log":"2022/07/05 17:27:31 [notice] 1#1: worker process 33 exited with code 0\n","stream":"stderr","time":"2022-07-05T17:27:31.792901385Z"}
{"log":"2022/07/05 17:27:31 [notice] 1#1: worker process 36 exited with code 0\n","stream":"stderr","time":"2022-07-05T17:27:31.792906033Z"}
{"log":"2022/07/05 17:27:31 [notice] 1#1: worker process 37 exited with code 0\n","stream":"stderr","time":"2022-07-05T17:27:31.792952488Z"}
{"log":"2022/07/05 17:27:31 [notice] 1#1: worker process 38 exited with code 0\n","stream":"stderr","time":"2022-07-05T17:27:31.792959076Z"}
{"log":"2022/07/05 17:27:31 [notice] 1#1: signal 17 (SIGCHLD) received from 44\n","stream":"stderr","time":"2022-07-05T17:27:31.793303196Z"}
{"log":"2022/07/05 17:27:31 [notice] 1#1: worker process 44 exited with code 0\n","stream":"stderr","time":"2022-07-05T17:27:31.79331285Z"}
{"log":"2022/07/05 17:27:31 [notice] 1#1: signal 29 (SIGIO) received\n","stream":"stderr","time":"2022-07-05T17:27:31.793352688Z"}
{"log":"2022/07/05 17:27:31 [notice] 1#1: signal 29 (SIGIO) received\n","stream":"stderr","time":"2022-07-05T17:27:31.793446618Z"}
{"log":"2022/07/05 17:27:31 [notice] 1#1: signal 17 (SIGCHLD) received from 42\n","stream":"stderr","time":"2022-07-05T17:27:31.79345632Z"}
{"log":"2022/07/05 17:27:31 [notice] 1#1: worker process 32 exited with code 0\n","stream":"stderr","time":"2022-07-05T17:27:31.793525097Z"}
{"log":"2022/07/05 17:27:31 [notice] 1#1: worker process 42 exited with code 0\n","stream":"stderr","time":"2022-07-05T17:27:31.79354997Z"}
{"log":"2022/07/05 17:27:31 [notice] 1#1: signal 29 (SIGIO) received\n","stream":"stderr","time":"2022-07-05T17:27:31.793665833Z"}
{"log":"2022/07/05 17:27:31 [notice] 1#1: signal 17 (SIGCHLD) received from 35\n","stream":"stderr","time":"2022-07-05T17:27:31.794379787Z"}
{"log":"2022/07/05 17:27:31 [notice] 1#1: worker process 35 exited with code 0\n","stream":"stderr","time":"2022-07-05T17:27:31.794404941Z"}
{"log":"2022/07/05 17:27:31 [notice] 1#1: worker process 34 exited with code 0\n","stream":"stderr","time":"2022-07-05T17:27:31.794411194Z"}
{"log":"2022/07/05 17:27:31 [notice] 1#1: signal 29 (SIGIO) received\n","stream":"stderr","time":"2022-07-05T17:27:31.794543027Z"}
{"log":"2022/07/05 17:27:31 [notice] 1#1: signal 17 (SIGCHLD) received from 34\n","stream":"stderr","time":"2022-07-05T17:27:31.794555131Z"}
{"log":"2022/07/05 17:27:31 [notice] 1#1: signal 17 (SIGCHLD) received from 31\n","stream":"stderr","time":"2022-07-05T17:27:31.796654336Z"}
{"log":"2022/07/05 17:27:31 [notice] 1#1: worker process 31 exited with code 0\n","stream":"stderr","time":"2022-07-05T17:27:31.796685429Z"}
{"log":"2022/07/05 17:27:31 [notice] 1#1: worker process 43 exited with code 0\n","stream":"stderr","time":"2022-07-05T17:27:31.796692869Z"}
{"log":"2022/07/05 17:27:31 [notice] 1#1: signal 29 (SIGIO) received\n","stream":"stderr","time":"2022-07-05T17:27:31.796698899Z"}
{"log":"2022/07/05 17:27:31 [notice] 1#1: signal 17 (SIGCHLD) received from 43\n","stream":"stderr","time":"2022-07-05T17:27:31.796704589Z"}
{"log":"2022/07/05 17:27:31 [notice] 1#1: worker process 45 exited with code 0\n","stream":"stderr","time":"2022-07-05T17:27:31.796710306Z"}
{"log":"2022/07/05 17:27:31 [notice] 1#1: worker process 41 exited with code 0\n","stream":"stderr","time":"2022-07-05T17:27:31.796724102Z"}
{"log":"2022/07/05 17:27:31 [notice] 1#1: signal 29 (SIGIO) received\n","stream":"stderr","time":"2022-07-05T17:27:31.796729789Z"}
{"log":"2022/07/05 17:27:31 [notice] 1#1: signal 17 (SIGCHLD) received from 41\n","stream":"stderr","time":"2022-07-05T17:27:31.796736776Z"}
{"log":"2022/07/05 17:27:31 [notice] 1#1: signal 17 (SIGCHLD) received from 46\n","stream":"stderr","time":"2022-07-05T17:27:31.796897943Z"}
{"log":"2022/07/05 17:27:31 [notice] 1#1: worker process 46 exited with code 0\n","stream":"stderr","time":"2022-07-05T17:27:31.796924143Z"}
{"log":"2022/07/05 17:27:31 [notice] 1#1: exit\n","stream":"stderr","time":"2022-07-05T17:27:31.797136969Z"}
{"log":"/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration\n","stream":"stdout","time":"2022-07-05T17:29:27.356495697Z"}
{"log":"/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/\n","stream":"stdout","time":"2022-07-05T17:29:27.356539534Z"}
{"log":"/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh\n","stream":"stdout","time":"2022-07-05T17:29:27.359725623Z"}
{"log":"10-listen-on-ipv6-by-default.sh: info: IPv6 listen already enabled\n","stream":"stdout","time":"2022-07-05T17:29:27.366524468Z"}
{"log":"/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh\n","stream":"stdout","time":"2022-07-05T17:29:27.366913132Z"}
{"log":"/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh\n","stream":"stdout","time":"2022-07-05T17:29:27.37328057Z"}
{"log":"/docker-entrypoint.sh: Configuration complete; ready for start up\n","stream":"stdout","time":"2022-07-05T17:29:27.376860026Z"}
{"log":"2022/07/05 17:29:27 [notice] 1#1: using the \"epoll\" event method\n","stream":"stderr","time":"2022-07-05T17:29:27.387190285Z"}
{"log":"2022/07/05 17:29:27 [notice] 1#1: nginx/1.23.0\n","stream":"stderr","time":"2022-07-05T17:29:27.387208187Z"}
{"log":"2022/07/05 17:29:27 [notice] 1#1: built by gcc 10.2.1 20210110 (Debian 10.2.1-6) \n","stream":"stderr","time":"2022-07-05T17:29:27.387212772Z"}
{"log":"2022/07/05 17:29:27 [notice] 1#1: OS: Linux 3.10.0-1160.el7.x86_64\n","stream":"stderr","time":"2022-07-05T17:29:27.387215297Z"}
{"log":"2022/07/05 17:29:27 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576\n","stream":"stderr","time":"2022-07-05T17:29:27.387217901Z"}
{"log":"2022/07/05 17:29:27 [notice] 1#1: start worker processes\n","stream":"stderr","time":"2022-07-05T17:29:27.387220406Z"}
{"log":"2022/07/05 17:29:27 [notice] 1#1: start worker process 24\n","stream":"stderr","time":"2022-07-05T17:29:27.387385128Z"}
{"log":"2022/07/05 17:29:27 [notice] 1#1: start worker process 25\n","stream":"stderr","time":"2022-07-05T17:29:27.387507241Z"}
{"log":"2022/07/05 17:29:27 [notice] 1#1: start worker process 26\n","stream":"stderr","time":"2022-07-05T17:29:27.38766927Z"}
{"log":"2022/07/05 17:29:27 [notice] 1#1: start worker process 27\n","stream":"stderr","time":"2022-07-05T17:29:27.387852483Z"}
{"log":"2022/07/05 17:29:27 [notice] 1#1: start worker process 28\n","stream":"stderr","time":"2022-07-05T17:29:27.388800028Z"}
{"log":"2022/07/05 17:29:27 [notice] 1#1: start worker process 29\n","stream":"stderr","time":"2022-07-05T17:29:27.388815818Z"}
{"log":"2022/07/05 17:29:27 [notice] 1#1: start worker process 30\n","stream":"stderr","time":"2022-07-05T17:29:27.388819192Z"}
{"log":"2022/07/05 17:29:27 [notice] 1#1: start worker process 31\n","stream":"stderr","time":"2022-07-05T17:29:27.388821416Z"}
{"log":"2022/07/05 17:29:27 [notice] 1#1: start worker process 32\n","stream":"stderr","time":"2022-07-05T17:29:27.388823911Z"}
{"log":"2022/07/05 17:29:27 [notice] 1#1: start worker process 33\n","stream":"stderr","time":"2022-07-05T17:29:27.38905136Z"}
{"log":"2022/07/05 17:29:27 [notice] 1#1: start worker process 34\n","stream":"stderr","time":"2022-07-05T17:29:27.389254357Z"}
{"log":"2022/07/05 17:29:27 [notice] 1#1: start worker process 35\n","stream":"stderr","time":"2022-07-05T17:29:27.389529243Z"}
{"log":"2022/07/05 17:29:27 [notice] 1#1: start worker process 36\n","stream":"stderr","time":"2022-07-05T17:29:27.390566303Z"}
{"log":"2022/07/05 17:29:27 [notice] 1#1: start worker process 37\n","stream":"stderr","time":"2022-07-05T17:29:27.390579337Z"}
{"log":"2022/07/05 17:29:27 [notice] 1#1: start worker process 38\n","stream":"stderr","time":"2022-07-05T17:29:27.390582228Z"}
{"log":"2022/07/05 17:29:27 [notice] 1#1: start worker process 39\n","stream":"stderr","time":"2022-07-05T17:29:27.390584482Z"}
{"log":"/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration\n","stream":"stdout","time":"2022-07-06T09:20:42.621797321Z"}
{"log":"/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/\n","stream":"stdout","time":"2022-07-06T09:20:42.630989561Z"}
{"log":"/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh\n","stream":"stdout","time":"2022-07-06T09:20:42.671377719Z"}
{"log":"10-listen-on-ipv6-by-default.sh: info: IPv6 listen already enabled\n","stream":"stdout","time":"2022-07-06T09:20:42.743092643Z"}
{"log":"/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh\n","stream":"stdout","time":"2022-07-06T09:20:42.743456494Z"}
{"log":"/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh\n","stream":"stdout","time":"2022-07-06T09:20:42.760016Z"}
{"log":"/docker-entrypoint.sh: Configuration complete; ready for start up\n","stream":"stdout","time":"2022-07-06T09:20:42.763675892Z"}
{"log":"2022/07/06 09:20:42 [notice] 1#1: using the \"epoll\" event method\n","stream":"stderr","time":"2022-07-06T09:20:42.942126479Z"}
{"log":"2022/07/06 09:20:42 [notice] 1#1: nginx/1.23.0\n","stream":"stderr","time":"2022-07-06T09:20:42.942157735Z"}
{"log":"2022/07/06 09:20:42 [notice] 1#1: built by gcc 10.2.1 20210110 (Debian 10.2.1-6) \n","stream":"stderr","time":"2022-07-06T09:20:42.942165355Z"}
{"log":"2022/07/06 09:20:42 [notice] 1#1: OS: Linux 3.10.0-1160.el7.x86_64\n","stream":"stderr","time":"2022-07-06T09:20:42.942171169Z"}
{"log":"2022/07/06 09:20:42 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576\n","stream":"stderr","time":"2022-07-06T09:20:42.942177075Z"}
{"log":"2022/07/06 09:20:42 [notice] 1#1: start worker processes\n","stream":"stderr","time":"2022-07-06T09:20:42.942376859Z"}
{"log":"2022/07/06 09:20:42 [notice] 1#1: start worker process 24\n","stream":"stderr","time":"2022-07-06T09:20:42.942603109Z"}
{"log":"2022/07/06 09:20:42 [notice] 1#1: start worker process 25\n","stream":"stderr","time":"2022-07-06T09:20:42.942880286Z"}
{"log":"2022/07/06 09:20:42 [notice] 1#1: start worker process 26\n","stream":"stderr","time":"2022-07-06T09:20:42.943177023Z"}
{"log":"2022/07/06 09:20:42 [notice] 1#1: start worker process 27\n","stream":"stderr","time":"2022-07-06T09:20:42.943465683Z"}
{"log":"2022/07/06 09:20:42 [notice] 1#1: start worker process 28\n","stream":"stderr","time":"2022-07-06T09:20:42.943775436Z"}
{"log":"2022/07/06 09:20:42 [notice] 1#1: start worker process 29\n","stream":"stderr","time":"2022-07-06T09:20:42.944104823Z"}
{"log":"2022/07/06 09:20:42 [notice] 1#1: start worker process 30\n","stream":"stderr","time":"2022-07-06T09:20:42.94444174Z"}
{"log":"2022/07/06 09:20:42 [notice] 1#1: start worker process 31\n","stream":"stderr","time":"2022-07-06T09:20:42.944786871Z"}
{"log":"2022/07/06 09:20:42 [notice] 1#1: start worker process 32\n","stream":"stderr","time":"2022-07-06T09:20:42.945142594Z"}
{"log":"2022/07/06 09:20:42 [notice] 1#1: start worker process 33\n","stream":"stderr","time":"2022-07-06T09:20:42.945523908Z"}
{"log":"2022/07/06 09:20:42 [notice] 1#1: start worker process 34\n","stream":"stderr","time":"2022-07-06T09:20:42.945921218Z"}
{"log":"2022/07/06 09:20:42 [notice] 1#1: start worker process 35\n","stream":"stderr","time":"2022-07-06T09:20:42.946303805Z"}
{"log":"2022/07/06 09:20:42 [notice] 1#1: start worker process 36\n","stream":"stderr","time":"2022-07-06T09:20:42.946722425Z"}
{"log":"2022/07/06 09:20:42 [notice] 1#1: start worker process 37\n","stream":"stderr","time":"2022-07-06T09:20:42.947126812Z"}
{"log":"2022/07/06 09:20:42 [notice] 1#1: start worker process 38\n","stream":"stderr","time":"2022-07-06T09:20:42.947589949Z"}
{"log":"2022/07/06 09:20:42 [notice] 1#1: start worker process 39\n","stream":"stderr","time":"2022-07-06T09:20:42.94806926Z"}
{"log":"192.168.1.21 - - [06/Jul/2022:09:20:54 +0000] \"GET / HTTP/1.1\" 200 615 \"-\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36\" \"-\"\n","stream":"stdout","time":"2022-07-06T09:20:54.337362109Z"}
{"log":"192.168.1.21 - - [06/Jul/2022:09:20:54 +0000] \"GET /favicon.ico HTTP/1.1\" 404 555 \"http://192.168.1.233:8080/\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36\" \"-\"\n","stream":"stdout","time":"2022-07-06T09:20:54.414529771Z"}
{"log":"2022/07/06 09:20:54 [error] 25#25: *1 open() \"/usr/share/nginx/html/favicon.ico\" failed (2: No such file or directory), client: 192.168.1.21, server: localhost, request: \"GET /favicon.ico HTTP/1.1\", host: \"192.168.1.233:8080\", referrer: \"http://192.168.1.233:8080/\"\n","stream":"stderr","time":"2022-07-06T09:20:54.414547748Z"}
{"log":"2022/07/06 09:21:17 [notice] 1#1: signal 3 (SIGQUIT) received, shutting down\n","stream":"stderr","time":"2022-07-06T09:21:17.354390973Z"}
{"log":"2022/07/06 09:21:17 [notice] 25#25: gracefully shutting down\n","stream":"stderr","time":"2022-07-06T09:21:17.355691939Z"}
{"log":"2022/07/06 09:21:17 [notice] 28#28: gracefully shutting down\n","stream":"stderr","time":"2022-07-06T09:21:17.355729569Z"}
{"log":"2022/07/06 09:21:17 [notice] 30#30: gracefully shutting down\n","stream":"stderr","time":"2022-07-06T09:21:17.355749506Z"}
{"log":"2022/07/06 09:21:17 [notice] 24#24: gracefully shutting down\n","stream":"stderr","time":"2022-07-06T09:21:17.355753507Z"}
{"log":"2022/07/06 09:21:17 [notice] 26#26: gracefully shutting down\n","stream":"stderr","time":"2022-07-06T09:21:17.355756232Z"}
{"log":"2022/07/06 09:21:17 [notice] 28#28: exiting\n","stream":"stderr","time":"2022-07-06T09:21:17.355759072Z"}
{"log":"2022/07/06 09:21:17 [notice] 30#30: exiting\n","stream":"stderr","time":"2022-07-06T09:21:17.355761634Z"}
{"log":"2022/07/06 09:21:17 [notice] 26#26: exiting\n","stream":"stderr","time":"2022-07-06T09:21:17.355764229Z"}
{"log":"2022/07/06 09:21:17 [notice] 24#24: exiting\n","stream":"stderr","time":"2022-07-06T09:21:17.355767152Z"}
{"log":"2022/07/06 09:21:17 [notice] 39#39: gracefully shutting down\n","stream":"stderr","time":"2022-07-06T09:21:17.355769914Z"}
{"log":"2022/07/06 09:21:17 [notice] 27#27: gracefully shutting down\n","stream":"stderr","time":"2022-07-06T09:21:17.355772554Z"}
{"log":"2022/07/06 09:21:17 [notice] 28#28: exit\n","stream":"stderr","time":"2022-07-06T09:21:17.355775181Z"}
{"log":"2022/07/06 09:21:17 [notice] 30#30: exit\n","stream":"stderr","time":"2022-07-06T09:21:17.355777776Z"}
{"log":"2022/07/06 09:21:17 [notice] 26#26: exit\n","stream":"stderr","time":"2022-07-06T09:21:17.355780457Z"}
{"log":"2022/07/06 09:21:17 [notice] 39#39: exiting\n","stream":"stderr","time":"2022-07-06T09:21:17.355783031Z"}
{"log":"2022/07/06 09:21:17 [notice] 27#27: exiting\n","stream":"stderr","time":"2022-07-06T09:21:17.355785594Z"}
{"log":"2022/07/06 09:21:17 [notice] 24#24: exit\n","stream":"stderr","time":"2022-07-06T09:21:17.355788269Z"}
{"log":"2022/07/06 09:21:17 [notice] 33#33: gracefully shutting down\n","stream":"stderr","time":"2022-07-06T09:21:17.355790997Z"}
{"log":"2022/07/06 09:21:17 [notice] 34#34: gracefully shutting down\n","stream":"stderr","time":"2022-07-06T09:21:17.355793597Z"}
{"log":"2022/07/06 09:21:17 [notice] 39#39: exit\n","stream":"stderr","time":"2022-07-06T09:21:17.355796192Z"}
{"log":"2022/07/06 09:21:17 [notice] 33#33: exiting\n","stream":"stderr","time":"2022-07-06T09:21:17.355798749Z"}
{"log":"2022/07/06 09:21:17 [notice] 27#27: exit\n","stream":"stderr","time":"2022-07-06T09:21:17.355801406Z"}
{"log":"2022/07/06 09:21:17 [notice] 32#32: gracefully shutting down\n","stream":"stderr","time":"2022-07-06T09:21:17.355803911Z"}
{"log":"2022/07/06 09:21:17 [notice] 29#29: gracefully shutting down\n","stream":"stderr","time":"2022-07-06T09:21:17.355806502Z"}
{"log":"2022/07/06 09:21:17 [notice] 33#33: exit\n","stream":"stderr","time":"2022-07-06T09:21:17.355809192Z"}
{"log":"2022/07/06 09:21:17 [notice] 36#36: gracefully shutting down\n","stream":"stderr","time":"2022-07-06T09:21:17.355811891Z"}
{"log":"2022/07/06 09:21:17 [notice] 32#32: exiting\n","stream":"stderr","time":"2022-07-06T09:21:17.355814477Z"}
{"log":"2022/07/06 09:21:17 [notice] 29#29: exiting\n","stream":"stderr","time":"2022-07-06T09:21:17.355817047Z"}
{"log":"2022/07/06 09:21:17 [notice] 34#34: exiting\n","stream":"stderr","time":"2022-07-06T09:21:17.355819574Z"}
{"log":"2022/07/06 09:21:17 [notice] 36#36: exiting\n","stream":"stderr","time":"2022-07-06T09:21:17.355822201Z"}
{"log":"2022/07/06 09:21:17 [notice] 32#32: exit\n","stream":"stderr","time":"2022-07-06T09:21:17.355824736Z"}
{"log":"2022/07/06 09:21:17 [notice] 34#34: exit\n","stream":"stderr","time":"2022-07-06T09:21:17.355827277Z"}
{"log":"2022/07/06 09:21:17 [notice] 29#29: exit\n","stream":"stderr","time":"2022-07-06T09:21:17.355829912Z"}
{"log":"2022/07/06 09:21:17 [notice] 36#36: exit\n","stream":"stderr","time":"2022-07-06T09:21:17.355832454Z"}
{"log":"2022/07/06 09:21:17 [notice] 35#35: gracefully shutting down\n","stream":"stderr","time":"2022-07-06T09:21:17.355835554Z"}
{"log":"2022/07/06 09:21:17 [notice] 35#35: exiting\n","stream":"stderr","time":"2022-07-06T09:21:17.355838291Z"}
{"log":"2022/07/06 09:21:17 [notice] 35#35: exit\n","stream":"stderr","time":"2022-07-06T09:21:17.355843702Z"}
{"log":"2022/07/06 09:21:17 [notice] 37#37: gracefully shutting down\n","stream":"stderr","time":"2022-07-06T09:21:17.355956091Z"}
{"log":"2022/07/06 09:21:17 [notice] 31#31: gracefully shutting down\n","stream":"stderr","time":"2022-07-06T09:21:17.355978114Z"}
{"log":"2022/07/06 09:21:17 [notice] 37#37: exiting\n","stream":"stderr","time":"2022-07-06T09:21:17.355985071Z"}
{"log":"2022/07/06 09:21:17 [notice] 31#31: exiting\n","stream":"stderr","time":"2022-07-06T09:21:17.355990341Z"}
{"log":"2022/07/06 09:21:17 [notice] 37#37: exit\n","stream":"stderr","time":"2022-07-06T09:21:17.355995661Z"}
{"log":"2022/07/06 09:21:17 [notice] 31#31: exit\n","stream":"stderr","time":"2022-07-06T09:21:17.356001041Z"}
{"log":"2022/07/06 09:21:17 [notice] 38#38: gracefully shutting down\n","stream":"stderr","time":"2022-07-06T09:21:17.356326528Z"}
{"log":"2022/07/06 09:21:17 [notice] 38#38: exiting\n","stream":"stderr","time":"2022-07-06T09:21:17.356412983Z"}
{"log":"2022/07/06 09:21:17 [notice] 38#38: exit\n","stream":"stderr","time":"2022-07-06T09:21:17.356521935Z"}
{"log":"2022/07/06 09:21:17 [notice] 1#1: signal 17 (SIGCHLD) received from 34\n","stream":"stderr","time":"2022-07-06T09:21:17.362293119Z"}
{"log":"2022/07/06 09:21:17 [notice] 1#1: worker process 34 exited with code 0\n","stream":"stderr","time":"2022-07-06T09:21:17.362310967Z"}
{"log":"2022/07/06 09:21:17 [notice] 1#1: worker process 26 exited with code 0\n","stream":"stderr","time":"2022-07-06T09:21:17.362314188Z"}
{"log":"2022/07/06 09:21:17 [notice] 1#1: signal 29 (SIGIO) received\n","stream":"stderr","time":"2022-07-06T09:21:17.362422059Z"}
{"log":"2022/07/06 09:21:17 [notice] 1#1: signal 17 (SIGCHLD) received from 26\n","stream":"stderr","time":"2022-07-06T09:21:17.36243076Z"}
{"log":"2022/07/06 09:21:17 [notice] 1#1: worker process 28 exited with code 0\n","stream":"stderr","time":"2022-07-06T09:21:17.362433169Z"}
{"log":"2022/07/06 09:21:17 [notice] 1#1: worker process 24 exited with code 0\n","stream":"stderr","time":"2022-07-06T09:21:17.362534199Z"}
{"log":"2022/07/06 09:21:17 [notice] 1#1: worker process 29 exited with code 0\n","stream":"stderr","time":"2022-07-06T09:21:17.362557946Z"}
{"log":"2022/07/06 09:21:17 [notice] 1#1: worker process 30 exited with code 0\n","stream":"stderr","time":"2022-07-06T09:21:17.362564769Z"}
{"log":"2022/07/06 09:21:17 [notice] 1#1: worker process 27 exited with code 0\n","stream":"stderr","time":"2022-07-06T09:21:17.362570333Z"}
{"log":"2022/07/06 09:21:17 [notice] 1#1: worker process 33 exited with code 0\n","stream":"stderr","time":"2022-07-06T09:21:17.362575993Z"}
{"log":"2022/07/06 09:21:17 [notice] 1#1: worker process 36 exited with code 0\n","stream":"stderr","time":"2022-07-06T09:21:17.362581683Z"}
{"log":"2022/07/06 09:21:17 [notice] 1#1: worker process 39 exited with code 0\n","stream":"stderr","time":"2022-07-06T09:21:17.362587236Z"}
{"log":"2022/07/06 09:21:17 [notice] 1#1: signal 29 (SIGIO) received\n","stream":"stderr","time":"2022-07-06T09:21:17.362965863Z"}
{"log":"2022/07/06 09:21:17 [notice] 1#1: signal 17 (SIGCHLD) received from 39\n","stream":"stderr","time":"2022-07-06T09:21:17.36299692Z"}
{"log":"2022/07/06 09:21:17 [notice] 1#1: signal 17 (SIGCHLD) received from 32\n","stream":"stderr","time":"2022-07-06T09:21:17.363087306Z"}
{"log":"2022/07/06 09:21:17 [notice] 1#1: worker process 32 exited with code 0\n","stream":"stderr","time":"2022-07-06T09:21:17.363104773Z"}
{"log":"2022/07/06 09:21:17 [notice] 1#1: signal 29 (SIGIO) received\n","stream":"stderr","time":"2022-07-06T09:21:17.36313471Z"}
{"log":"2022/07/06 09:21:17 [notice] 1#1: signal 17 (SIGCHLD) received from 37\n","stream":"stderr","time":"2022-07-06T09:21:17.365167351Z"}
{"log":"2022/07/06 09:21:17 [notice] 1#1: worker process 31 exited with code 0\n","stream":"stderr","time":"2022-07-06T09:21:17.365185651Z"}
{"log":"2022/07/06 09:21:17 [notice] 1#1: worker process 35 exited with code 0\n","stream":"stderr","time":"2022-07-06T09:21:17.365191591Z"}
{"log":"2022/07/06 09:21:17 [notice] 1#1: worker process 37 exited with code 0\n","stream":"stderr","time":"2022-07-06T09:21:17.365211448Z"}
{"log":"2022/07/06 09:21:17 [notice] 1#1: signal 29 (SIGIO) received\n","stream":"stderr","time":"2022-07-06T09:21:17.365322291Z"}
{"log":"2022/07/06 09:21:17 [notice] 1#1: signal 17 (SIGCHLD) received from 31\n","stream":"stderr","time":"2022-07-06T09:21:17.365340408Z"}
{"log":"2022/07/06 09:21:17 [notice] 1#1: signal 17 (SIGCHLD) received from 38\n","stream":"stderr","time":"2022-07-06T09:21:17.366217352Z"}
{"log":"2022/07/06 09:21:17 [notice] 1#1: worker process 38 exited with code 0\n","stream":"stderr","time":"2022-07-06T09:21:17.366235909Z"}
{"log":"2022/07/06 09:21:17 [notice] 1#1: signal 29 (SIGIO) received\n","stream":"stderr","time":"2022-07-06T09:21:17.366306542Z"}
49c6b2e842c45bff058c346866e55f799e6b3d53d116898c3386f87d2623d9da/config.v2.json
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1 @@
{"StreamConfig":{},"State":{"Running":false,"Paused":false,"Restarting":false,"OOMKilled":false,"RemovalInProgress":false,"Dead":false,"Pid":0,"ExitCode":137,"Error":"","StartedAt":"2022-07-06T09:20:42.477658398Z","FinishedAt":"2022-07-06T09:21:27.449539552Z","Health":null},"ID":"49c6b2e842c45bff058c346866e55f799e6b3d53d116898c3386f87d2623d9da","Created":"2022-07-05T17:08:58.650960754Z","Managed":false,"Path":"/docker-entrypoint.sh","Args":["nginx","-g","daemon off;"],"Config":{"Hostname":"49c6b2e842c4","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"ExposedPorts":{"80/tcp":{}},"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin","NGINX_VERSION=1.23.0","NJS_VERSION=0.7.5","PKG_RELEASE=1~bullseye"],"Cmd":["nginx","-g","daemon off;"],"Image":"nginx","Volumes":null,"WorkingDir":"","Entrypoint":["/docker-entrypoint.sh"],"OnBuild":null,"Labels":{"maintainer":"NGINX Docker Maintainers \u003cdocker-maint@nginx.com\u003e"},"StopSignal":"SIGQUIT"},"Image":"sha256:55f4b40fe486a5b734b46bb7bf28f52fa31426bf23be068c8e7b19e58d9b8deb","NetworkSettings":{"Bridge":"","SandboxID":"b946b0337d5c27a04f486818f98ef5a23c7e198776c380a261e50cdfc50b1af3","HairpinMode":false,"LinkLocalIPv6Address":"","LinkLocalIPv6PrefixLen":0,"Networks":{"bridge":{"IPAMConfig":null,"Links":null,"Aliases":null,"NetworkID":"d8847f36e01af680c74244f0b44c635f80f7dbd6ec7a6f03ee499cb73d0360ed","EndpointID":"","Gateway":"","IPAddress":"","IPPrefixLen":0,"IPv6Gateway":"","GlobalIPv6Address":"","GlobalIPv6PrefixLen":0,"MacAddress":"","DriverOpts":null,"IPAMOperational":false}},"Service":null,"Ports":null,"SandboxKey":"/var/run/docker/netns/b946b0337d5c","SecondaryIPAddresses":null,"SecondaryIPv6Addresses":null,"IsAnonymousEndpoint":false,"HasSwarmEndpoint":false},"LogPath":"/var/lib/docker/containers/49c6b2e842c45bff058c346866e55f799e6b3d53d116898c3386f87d2623d9da/49c6b2e842c45bff058c346866e55f799e6b3d53d116898c3386f87d2623d9da-json.log","Name":"/hahan","Driver":"overlay2","OS":"linux","MountLabel":"","ProcessLabel":"","RestartCount":0,"HasBeenStartedBefore":true,"HasBeenManuallyStopped":true,"MountPoints":{},"SecretReferences":null,"ConfigReferences":null,"AppArmorProfile":"","HostnamePath":"/var/lib/docker/containers/49c6b2e842c45bff058c346866e55f799e6b3d53d116898c3386f87d2623d9da/hostname","HostsPath":"/var/lib/docker/containers/49c6b2e842c45bff058c346866e55f799e6b3d53d116898c3386f87d2623d9da/hosts","ShmPath":"","ResolvConfPath":"/var/lib/docker/containers/49c6b2e842c45bff058c346866e55f799e6b3d53d116898c3386f87d2623d9da/resolv.conf","SeccompProfile":"","NoNewPrivileges":false,"LocalLogCacheMeta":{"HaveNotifyEnabled":false}}
49c6b2e842c45bff058c346866e55f799e6b3d53d116898c3386f87d2623d9da/hostconfig.json
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,100 @@
{
    "Binds": null,
    "ContainerIDFile": "",
    "LogConfig": {
        "Type": "json-file",
        "Config": {}
    },
    "NetworkMode": "default",
    "PortBindings": {
        "80/tcp": [
            {
                "HostIp": "",
                "HostPort": "8080"
            }
        ]
    },
    "RestartPolicy": {
        "Name": "no",
        "MaximumRetryCount": 0
    },
    "AutoRemove": false,
    "VolumeDriver": "",
    "VolumesFrom": null,
    "CapAdd": null,
    "CapDrop": null,
    "CgroupnsMode": "host",
    "Dns": [],
    "DnsOptions": [],
    "DnsSearch": [],
    "ExtraHosts": null,
    "GroupAdd": null,
    "IpcMode": "private",
    "Cgroup": "",
    "Links": null,
    "OomScoreAdj": 0,
    "PidMode": "",
    "Privileged": false,
    "PublishAllPorts": false,
    "ReadonlyRootfs": false,
    "SecurityOpt": null,
    "UTSMode": "",
    "UsernsMode": "",
    "ShmSize": 67108864,
    "Runtime": "runc",
    "ConsoleSize": [
        0,
        0
    ],
    "Isolation": "",
    "CpuShares": 0,
    "Memory": 0,
    "NanoCpus": 0,
    "CgroupParent": "",
    "BlkioWeight": 0,
    "BlkioWeightDevice": [],
    "BlkioDeviceReadBps": null,
    "BlkioDeviceWriteBps": null,
    "BlkioDeviceReadIOps": null,
    "BlkioDeviceWriteIOps": null,
    "CpuPeriod": 0,
    "CpuQuota": 0,
    "CpuRealtimePeriod": 0,
    "CpuRealtimeRuntime": 0,
    "CpusetCpus": "",
    "CpusetMems": "",
    "Devices": [],
    "DeviceCgroupRules": null,
    "DeviceRequests": null,
    "KernelMemory": 0,
    "KernelMemoryTCP": 0,
    "MemoryReservation": 0,
    "MemorySwap": 0,
    "MemorySwappiness": null,
    "OomKillDisable": false,
    "PidsLimit": null,
    "Ulimits": null,
    "CpuCount": 0,
    "CpuPercent": 0,
    "IOMaximumIOps": 0,
    "IOMaximumBandwidth": 0,
    "MaskedPaths": [
        "/proc/asound",
        "/proc/acpi",
        "/proc/kcore",
        "/proc/keys",
        "/proc/latency_stats",
        "/proc/timer_list",
        "/proc/timer_stats",
        "/proc/sched_debug",
        "/proc/scsi",
        "/sys/firmware"
    ],
    "ReadonlyPaths": [
        "/proc/bus",
        "/proc/fs",
        "/proc/irq",
        "/proc/sys",
        "/proc/sysrq-trigger"
    ]
}
49c6b2e842c45bff058c346866e55f799e6b3d53d116898c3386f87d2623d9da/hostname
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1 @@
49c6b2e842c4
49c6b2e842c45bff058c346866e55f799e6b3d53d116898c3386f87d2623d9da/hosts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,7 @@
127.0.0.1   localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.2  49c6b2e842c4
49c6b2e842c45bff058c346866e55f799e6b3d53d116898c3386f87d2623d9da/resolv.conf
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,3 @@
# Generated by NetworkManager
nameserver 202.96.209.133
nameserver 114.114.114.114
49c6b2e842c45bff058c346866e55f799e6b3d53d116898c3386f87d2623d9da/resolv.conf.hash
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1 @@
sha256:a5f0b8686d307e34722405f285ba7230bf9c08653699822f0dd54a95d379d5ed
Android FUStaKit Java API ²Î¿¼Îĵµ.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,867 @@
# FUStaSDK接口文档
本 SDK é›†æˆäº† FaceUnity çš„语音驱动形象引擎(Speeach to Animation) ï¼Œèƒ½å¤Ÿå¿«é€Ÿæž„建并驱动虚拟形象说话,营造更加真实自然的人机交互场景。
## ç‰ˆæœ¬ä¿¡æ¯
版本号:2.1
更新日期:2022-01-21
更新内容:
- ä¼˜åŒ–CPU性能以及查询效率
- æ–°å¢žåŠ¨ç”»æ’­æ”¾é€Ÿåº¦æŽ§åˆ¶æŽ¥å£
- æ›´æ–°BS系数57-47
- ä¿®å¤é™éŸ³å¸§é—®é¢˜
- â½€æ–°å¢žè®¾ç½®æ—‹è½¬è§’度
- ä¼˜åŒ–阴影锯齿算法
- å¢žåŠ è¯¦ç»†æ—¥å¿—æŽ¥å£
## APIs
SDK接口根据作用逻辑归为五类
- <a href="#1">配置初始化数据</a>
- <a href="#2">初始化</a>
- <a href="#3">Avatar切换</a>
- <a href="#4">渲染控制</a>
- <a href="#5">口型查询和驱动</a>
- <a href="#6">Avatar动画和表情切换</a>
- <a href="#7">销毁</a>
- <a href="#8">其他</a>
------
> ### <a name="1">配置初始化数据</a>
###### FUSta SDK配置初始化数据(在线鉴权数据)
    FUStaKit.Builder builder = new FUStaKit
                    .Builder(mContext)
                    .setAuth(authpack.A())
                    .setAlignData(bytesAlign)
                     //.setAsrData(bytesAsr)
                    .setFUTtsType(FUTtsType.ALIGNMENT)
                    .setCharacterDecoder(bytesDecoder);
     mFUStaKit = builder.build();
###### æŽ¥å£è¯´æ˜Ž
初始化FUSta,传入上下文(必要),
加载网络鉴权数据(必要),
设置语音自动校准工具包(Align模式需要设置),
设置语音识别工具包(ASR方式需要设置,此处是Align模式故注释该方法),
设置tts查询方式,必要(ASR方式需要设置:FUTtsType.ASR;Align方式需要设置:FUTtsType.ALIGNMENT,此处是Align模式故设置为FUTtsType.ALIGNMENT)
设置文字编码功能数据文件(ALIGN方式和文本时间戳需要设置)。
###### å‚数说明
``` context ```:上下文
``` setAuth(byte[]) ```:网络鉴权数据
``` setAlignData(byte[]) ```:语音自动校准工具包数据
``` setAsrData(byte[]) ```:语音识别工具包数据
``` setFUTtsType(TtsTypeEnum type) ```:tts查询方式
``` setCharacterDecoder(byte[]) ```:文字编码功能数据
###### å¤‡æ³¨ï¼š
App å¯åŠ¨åŽåªéœ€è¦ SDK配置初始化数据 ä¸€æ¬¡å³å¯ï¼Œå…¶ä¸­ authpack.A() é‰´æƒæ•°æ®å£°æ˜Žåœ¨ authpack.java ä¸­ã€‚必须配置好有效的证书,SDK æ‰èƒ½æ­£å¸¸å·¥ä½œã€‚
在线鉴权只需要设置authpack.A() é‰´æƒæ•°æ®å³å¯ã€‚FUSta SDK é…ç½®åˆå§‹åŒ–数据详见"Android FUStaKit é›†æˆæ–‡æ¡£"。
###### FUSta SDK配置初始化数据(离线鉴权数据)
     FUStaKit.Builder builder = new FUStaKit
                    .Builder(mContext)
                    .setAuth(authpack.A())
                    .setAlignData(bytesAlign)
                     //.setAsrData(bytesAsr)
                    .setFUTtsType(FUTtsType.ALIGNMENT)
                    .setCharacterDecoder(bytesDecoder);
                    .setOffLineData(offLineAuth);
     mFUStaKit = builder.build();
###### æŽ¥å£è¯´æ˜Ž
初始化FUSta,传入上下文(必要),
加载网络鉴权数据(必要),
设置语音自动校准工具包(Align模式需要设置),
设置语音识别工具包(ASR方式需要设置,此处是Align模式故注释该方法),
设置tts查询方式,必要(ASR方式需要设置:FUTtsType.ASR;Align方式需要设置:FUTtsType.ALIGNMENT,此处是Align模式故设置为FUTtsType.ALIGNMENT)
设置文字编码功能数据文件(ALIGN方式和文本时间戳需要设置)。
###### å‚数说明
``` context ```:上下文
``` setAuth(byte[]) ```:网络鉴权数据
``` setAlignData(byte[]) ```:语音自动校准工具包数据
``` setAsrData(byte[]) ```:语音识别工具包数据
``` setFUTtsType(TtsTypeEnum type) ```:tts查询方式
``` setCharacterDecoder(byte[]) ```:文字编码功能数据
``` setOffLineData(byte[]) ```:离线鉴权数据
###### å¤‡æ³¨ï¼š
App å¯åŠ¨åŽåªéœ€è¦ SDK配置初始化数据 ä¸€æ¬¡å³å¯ï¼Œå…¶ä¸­ authpack.A() é‰´æƒæ•°æ®å£°æ˜Žåœ¨ authpack.java ä¸­ã€‚必须配置好有效的证书,SDK æ‰èƒ½æ­£å¸¸å·¥ä½œã€‚
离线鉴权除了设置authpack.A() é‰´æƒæ•°æ®ï¼Œè¿˜éœ€è¦è®¾ç½®ç¦»çº¿é‰´æƒæ•°æ®åŒ…路径:setOffLineAuth(byte[])。
注意,有key.bundle就使用key.bundle,这样会走离线;使用未鉴权的bundle,会联网鉴权。
根据应用需求,鉴权数据也可以运行时提供(如网络下载),不过要注意证书泄露风险,防止证书被滥用。FUSta SDK é…ç½®åˆå§‹åŒ–数据详见"Android FUStaKit é›†æˆæ–‡æ¡£"。
---
> ### <a name="2">初始化</a>
###### FUSta SDK初始化(在线鉴权)
```
void init(FUAuthType.ONLINE, StaKitInitCallback listener);
```
###### æŽ¥å£è¯´æ˜Ž
调用FUSta SDK初始化方法,必须放在 FUStaKit SDK配置初始化数据之后
###### å‚数说明
``` FUAuthType.ONLINE ```:在线鉴权
``` FUStaKit.StaKitInitCallback ```:SDK初始化状态的回调,参数位空即没有初始化完成回调的方式,如果调用该方法之后紧接着调用口型驱动方法,口型驱动任务会等待初始化任务完成才开始。开发者可根据初始化回调进行相关逻辑处理。
###### å¤‡æ³¨ï¼š
init åˆå§‹åŒ–方法,务必在后续操作前调用,否则无法驱动口型。
FUSta SDK åˆå§‹åŒ–详见"Android FUStaKit é›†æˆæ–‡æ¡£â€œã€‚
###### FUSta SDK初始化(离线鉴权)
```
void init(FUAuthType.OFFLINE_BUNDLE, StaKitInitCallback listener);
```
###### æŽ¥å£è¯´æ˜Ž
调用FUSta SDK初始化方法,必须放在 FUStaKit SDK配置初始化数据之后
###### å‚数说明
``` FUAuthType.OFFLINE_BUNDLE ```:离线鉴权
``` FUStaKit.StaKitInitCallback ```:SDK初始化状态的回调,参数位空即没有初始化完成回调的方式,如果调用该方法之后紧接着调用口型驱动方法,口型驱动任务会等待初始化任务完成才开始。开发者可根据初始化回调进行相关逻辑处理。
###### å¤‡æ³¨ï¼š
init åˆå§‹åŒ–方法,务必在后续操作前调用,否则无法驱动口型。
FUSta SDK åˆå§‹åŒ–详见"Android FUStaKit é›†æˆæ–‡æ¡£â€œã€‚
---
> ### <a name="3">Avatar切换</a>
###### FUSta SDK设置Avatar
```
void setAvatar(FUAvatar avatar, FUAvatarType avatarType);
或
void setAvatar(FUAvatar avatar, FUAvatarType avatarType, OnAvatarStateListener listener);
```
###### æŽ¥å£è¯´æ˜Ž
切换Avatar方法,设置后在渲染时会切换对应Avatar。
###### å‚数说明
``` avatar ```:FUAvatar实例
``` avatarType ```:Avatar类型的枚举,用来表示Avatar类型,用来区别内置表情数据源,默认:`FUAvatarType.CARTOON`
``` listener ```:Avatar执行状态接口,实现接口,Avatar加载完成回调onAvatarComplete()
###### å¤‡æ³¨ï¼š
###### FUSta SDK设置Avatar位置
```
void setPosition(double positionX, double positionY, double positionZ);
```
###### æŽ¥å£è¯´æ˜Ž
设置Avatar在坐标系的位置。
###### å‚数说明
``` positionX ```:X轴坐标 èŒƒå›´`-200, 200`
``` positionY ```:Y轴坐标 èŒƒå›´`-600, 800`
``` positionZ ```:Z轴坐标 èŒƒå›´`-3000, 600`
###### å¤‡æ³¨ï¼š
###### FUSta SDK设置Avatar背景
```
void setBackground(String background);
```
###### æŽ¥å£è¯´æ˜Ž
设置Avatar背景。
###### å‚数说明
``` background ```:背景道具路径,background为空则背景透明
###### å¤‡æ³¨ï¼š
###### FUSta SDK设置Avatar光照
```
void setLight(String light);
```
###### æŽ¥å£è¯´æ˜Ž
设置Avatar光照。
###### å‚数说明
``` light ```:灯光道具路径
###### å¤‡æ³¨ï¼š
###### FUSta SDK设置Avatar相机位
```
void setCamera(String camera);
```
###### æŽ¥å£è¯´æ˜Ž
设置Avatar相机位。
###### å‚数说明
``` camera ```:相机道具路径
###### å¤‡æ³¨ï¼š
###### FUSta SDK开启阴影
```
void enableShadow(Boolean enableShadow);
```
###### æŽ¥å£è¯´æ˜Ž
设置是否开启阴影。
###### å‚数说明
``` enableShadow ```:是否开启阴影
###### å¤‡æ³¨ï¼š
---
> ### <a name="4">渲染控制</a>
###### FUSta SDK开始渲染
```
void requestRender(GLTextureView glTextureView);
```
###### æŽ¥å£è¯´æ˜Ž
开始渲染。
###### å‚数说明
``` glTextureView ```:GLTextureView,SDK提供的渲染View
###### å¤‡æ³¨ï¼š
###### FUSta SDK渲染状态同步
```
void onResume();
void onPause();
void onDestroy();
```
###### æŽ¥å£è¯´æ˜Ž
onResume() å¯¹åº”Activity onResume(),
onPause() å¯¹åº”Activity onPause(),
onDestroy() å¯¹åº”Activity onDestroy()。
###### å‚数说明
###### å¤‡æ³¨ï¼š
onResume()与onPause()成对出现,在Activity的onPause()调用时停止后台渲染减少消耗,并且在Activity的onResume()调用时重新加载。
onResume()与onPause()可不用调用,在Activity的onPause()调用时后台会继续渲染;
onDestroy()必须调用。
###### FUSta SDK设置渲染分辨率
```
void setCustomRenderResolution(int renderWidth, int renderHeight);
```
###### æŽ¥å£è¯´æ˜Ž
设置渲染分辨率尺寸。
###### å‚数说明
``` renderWidth ```:纹理宽度
``` renderHeight ```:纹理宽度
###### å¤‡æ³¨ï¼š
###### FUSta SDK设置渲染帧率
```
void setRenderFPS(int renderFPS);
```
###### æŽ¥å£è¯´æ˜Ž
设置渲染帧率,默认30帧/s。
###### å‚数说明
``` renderFPS ```:渲染帧率
###### å¤‡æ³¨ï¼š
如果低端设备最大帧率小于设置的帧率,实际帧率为该设备的最大帧率。
###### FUSta SDK设置抗锯齿
```
void setMultiSamples(int samples);
```
###### æŽ¥å£è¯´æ˜Ž
3D抗锯齿配置
###### å‚数说明
``` samples ```:抗锯齿级别,默认4。
###### å¤‡æ³¨ï¼š
###### FUSta SDK设置阴影抗锯齿
```
void setShadowPCFLevel(int level);
```
###### æŽ¥å£è¯´æ˜Ž
设置阴影抗锯齿级别
###### å‚数说明
``` level ```:抗锯齿级别,默认2。
###### å¤‡æ³¨ï¼š
###### FUSta SDK设置渲染信息回调接口
```
void setEnableDebug(boolean enableDebug)
void setStaRenderDebugListener(OnRenderDebugListener renderDebugListener);
```
###### æŽ¥å£è¯´æ˜Ž
设置渲染debug数据的回调
###### å‚数说明
``` enableDebug ```:调试开关为true,相关debug数据才会进行统计。
``` renderDebugListener ```:渲染debug数据接口,onBenchmarkFPSChanged(int width, int height, double fps, double renderTime)。
###### å¤‡æ³¨ï¼š
###### FUSta SDK日志保存到本地
```
void setLogOutputDir(String dir);
void enableLogOutput(boolean enableDebug)
```
###### æŽ¥å£è¯´æ˜Ž
SDK日志保存到本地
###### å‚数说明
``` dir ```:设置保存到本地的指定目录。
``` enableDebug ```:是否保存日志信息到指定的目录。
###### å¤‡æ³¨ï¼š
---
> ### <a name="5">口型查询和驱动</a>
###### FUSta SDK初始化播放器
```
void initStaPlayer(FUPlayerConfig playerConfig);
```
###### æŽ¥å£è¯´æ˜Ž
初始化播放器
###### å‚数说明
``` playerConfig ```:播放器相关配置,主要是采样率、声道和位深,SDK根据播放器的配置内部会初始化对应播放器。
###### å¤‡æ³¨ï¼š
该播放器用于内部播放,如采用外部播放器播放可不设置。
###### FUSta SDK口型驱动并且播放音频
```
void staProcess(FUStaParams staParams);
```
###### æŽ¥å£è¯´æ˜Ž
FUSta SDK查询口型系数,播放音频并驱动对应口型。
使用场景:
         1、流式音频,有时间戳,只支持pcm
         2、流式音频,无时间戳,只支持pcm
         3、流式音频,无时间戳,有Align文本,只支持pcm
         4、非流式音频,有时间戳,支持pcm与wav
         5、非流式音频,无时间戳,支持pcm与wav
         6、非流式音频,无时间戳,有Align文本,支持pcm与wav
###### å‚数说明
``` params ```:FUStaParams为配置类,参数基本设置: è®¾ç½®STA操作为非流式、设置音频数据、设置音频数据类型、设置音频数据对应时间戳等,目前支持 pcm ä¸Ž wav
###### å¤‡æ³¨ï¼š
有时间戳,查询口型系数根据时间戳查询,速度会更快。
无时间戳,查询口型系数根据音频数据查询,根据机型配置不同耗时也有差别,查询速度稍耗时。一般无时间戳查询口型系数方式有ASR方式和ALIGN方式,ALIGN方式较快,ASR方式较慢。
FUStaParams参数详情与该口型驱动模式调用见```Android FUStaKit é›†æˆæ–‡æ¡£```
###### FUSta SDK流式查询状态同步
```
void notifyStaProcessStart();
void notifyStaProcessFinish();
```
###### æŽ¥å£è¯´æ˜Ž
流式口型驱动模式下,需要给SDK同步查询状态。
notifyStaProcessStart()对应于流式查询开始调用;notifyStaProcessFinish()对应于流式查询结束调用。
###### å‚数说明
###### å¤‡æ³¨ï¼š
流式查询必须要给SDK设置同步状态。详情见```Android FUStaKit é›†æˆæ–‡æ¡£```
###### FUSta SDK设置内部播放器状态接口
```
void setStaPlayerListener(OnStaPlayerListener staPlayerListener);
```
###### æŽ¥å£è¯´æ˜Ž
SDK采用内部播放器播放,播放器状态接口。
###### å‚数说明
```OnStaPlayerListener```:实现该接口,相关方法定义:
```onPrepared()```:播放开始
```onCompleted()```:播放结束
```onCancel()```:播放取消
```onError(String message)```:播放出错
###### å¤‡æ³¨ï¼š
###### FUSta SDK口型驱动(外部播放场景)
```
void staProcessNoPlayer(FUStaParams staParams);
```
###### æŽ¥å£è¯´æ˜Ž
FUSta SDK查询口型系数,外部播放器播放音频,需要两者配合驱动对应口型。
使用场景:
         1、流式音频,有时间戳,只支持pcm
         2、流式音频,无时间戳,只支持pcm
         3、流式音频,无时间戳,有Align文本,只支持pcm
         4、非流式音频,有时间戳,支持pcm与wav
         5、非流式音频,无时间戳,支持pcm与wav
         6、非流式音频,无时间戳,有Align文本,支持pcm与wav
###### å‚数说明
``` params ```:FUStaParams为配置类,参数基本设置: è®¾ç½®STA操作为非流式、设置音频数据、设置音频数据类型、设置音频数据对应时间戳等,目前支持 pcm ä¸Ž wav
###### å¤‡æ³¨ï¼š
有时间戳,查询口型系数根据时间戳查询,速度会更快。
无时间戳,查询口型系数根据音频数据查询,根据机型配置不同耗时也有差别,查询速度稍耗时。一般无时间戳查询口型系数方式有ASR方式和ALIGN方式,ALIGN方式较快,ASR方式较慢。
FUStaParams参数详情与该口型驱动模式调用见```Android FUStaKit é›†æˆæ–‡æ¡£```
###### FUSta SDK外部播放场景状态同步
```
void onExternalPlayerStart();
void onExternalPlayerStop();
```
###### æŽ¥å£è¯´æ˜Ž
SDK内部口型系数查询,外部播放器播放,两者配合驱动口型,需要给SDK同步播放器状态,设置口型驱动的开关。
onExternalPlayerStart()对应于外部播放器播放开始;onExternalPlayerStop()对应于外部播放器播放暂停或结束。
###### å‚数说明
###### å¤‡æ³¨ï¼š
外部播放场景必须要给SDK设置同步状态。详情见```Android FUStaKit é›†æˆæ–‡æ¡£```
###### FUSta SDK设置外部播放器接口
```
void setExternalPlayerListener(OnExternalPlayerListener externalPlayerListener);
```
###### æŽ¥å£è¯´æ˜Ž
SDK内部口型系数查询,外部播放器播放,两者配合驱动口型,需要给SDK同步播放器进度,sdk拿到播放进度驱动对应的口型。
###### å‚数说明
```OnExternalPlayerListener```:实现该接口,相关方法定义:
```updateCurrentPosition()```:获取外部播放器音频播放进度
###### å¤‡æ³¨ï¼š
###### FUSta SDK设置音频数据查询状态的接口
```
void setStaProcessListener(OnStaProcessListener onStaProcessListener);
```
###### æŽ¥å£è¯´æ˜Ž
SDK内部口型系数查询,该接口会回调每一段查询音频数据的数据:`FUAudioProgressType`和内部处理过后的音频,该状态接口主要用于外部播放器场景下,为了规避口型系数查询耗时的影响,通知开发者SDK已经有口型查询完成,可以执行外部播放器播放逻辑。
###### å‚数说明
```OnStaProcessListener```:实现该接口,相关方法定义:
```onStaProcess(FUAudioProgressType audioProgressType, byte[] data)```:回调每一段查询音频数据的数据
###### å¤‡æ³¨ï¼š
```FUAudioProgressType```是`开始`、`中间`、`结束`、`整段`的枚举。`date`是每一段的音频,注意该音频不一定等于用户传入的音频格式和大小。
###### FUSta SDK停止口型查询和驱动
```
void stopStaProcess();
```
###### æŽ¥å£è¯´æ˜Ž
打断SDK内部口型系数查询任务,该接口会清掉已经查询的口型数据的缓存,停止内部播放器的播放。
###### å‚数说明
###### å¤‡æ³¨ï¼š
外部播放场景需要配合外部播放器停止方法和调用SDK外部播放器播放暂停或结束通知方法:`onExternalPlayerStop()`。
###### FUSta SDK设置英语口型张开幅度
```
void setENIntensity(float intensity);
```
###### æŽ¥å£è¯´æ˜Ž
设置英语口型张开幅度。
###### å‚数说明
```intensity```:英语口型张开幅度,取值范围`1.0, 1.5`:
###### å¤‡æ³¨ï¼š
---
> ### <a name="6">Avatar动画和表情切换</a>
###### åŠ¨ç”»å¾ªçŽ¯æ’­æ”¾
```
void playAnimation(String anim);
或
void playAnimation(String anim, String[] prop, String[] propAnimation);
```
###### æŽ¥å£è¯´æ˜Ž
循环播放Avatar动画。
###### å‚数说明
```anim```:String,Avatar动画道具路径
```prop```:String[], é“具路径数组
```propAnimation```:String[], é“具动画路径数组
###### å¤‡æ³¨ï¼š
###### åŠ¨ç”»å•æ¬¡æ’­æ”¾
```
void playAnimationOnce(String anim);
或
void playAnimationOnce(String anim, String[] prop, String[] propAnimation);
```
###### æŽ¥å£è¯´æ˜Ž
单次播放Avatar动画。
###### å‚数说明
```anim```:String,Avatar动画道具路径
```prop```:String[], é“具路径数组
```propAnimation```:String[], é“具动画路径数组
###### å¤‡æ³¨ï¼š
###### ç»§ç»­æ’­æ”¾å½“前动画
```
void startCurrentAnimation();
```
###### æŽ¥å£è¯´æ˜Ž
继续播放当前动画。
###### å‚数说明
###### å¤‡æ³¨ï¼š
###### æš‚停播放当前动画
```
void pauseCurrentAnimation();
```
###### æŽ¥å£è¯´æ˜Ž
继续播放当前动画。
###### å‚数说明
###### å¤‡æ³¨ï¼š
###### ç§»é™¤åŠ¨ç”»
```
void removeAnimation(String anim);
```
###### æŽ¥å£è¯´æ˜Ž
移除动画。
###### å‚数说明
```anim```:String,要移除的Avatar动画道具路径
###### å¤‡æ³¨ï¼š
###### è®¾ç½®åŠ¨ç”»çš„è¿‡æ¸¡æ—¶é—´
```
void setAnimationTransitionTime(float time);
```
###### æŽ¥å£è¯´æ˜Ž
设置动画的过渡时间,单位为秒,默认0.5秒。
###### å‚数说明
```time```:float,动画的过渡时间
###### å¤‡æ³¨ï¼š
###### è®¾ç½®åŠ¨ç”»çš„æ’­æ”¾é€Ÿåº¦
```
void setAnimationSpeed(float speed);
```
###### æŽ¥å£è¯´æ˜Ž
设置动画的播放速度系数,默认为1,范围`0.2, 5.2`。
###### å‚数说明
```speed```:float,播放速度系数
###### å¤‡æ³¨ï¼š
###### å†…置表情切换
```
void updateEmotion(FUEmotionType emotionType);
或
void updateEmotion(FUEmotionType emotionType, int fpsNum);
```
###### æŽ¥å£è¯´æ˜Ž
SDK内置表情切换,在`fpsNum`帧内过渡到目标表情。
###### å‚数说明
```emotionType```:FUEmotionType,内置表情的枚举,目前只支持特定的Avatar类型(`FUAvatarType.CARTOON`和`FUAvatarType.REAL`)。
```fpsNum```:int,在`fpsNum`帧内过渡到目标表情,默认为0。
###### å¤‡æ³¨ï¼š
###### è‡ªå®šä¹‰è¡¨æƒ…切换
```
void updateCustomEmotion(String path);
或
void updateCustomEmotion(String path, int fpsNum);
```
###### æŽ¥å£è¯´æ˜Ž
自定义表情切换,通过传入自定义bs文件,内部解析并且驱动表情,在`fpsNum`帧内过渡到目标表情。
###### å‚数说明
```path```:String,自定义表情的文件。
```fpsNum```:int,在`fpsNum`帧内过渡到目标表情,默认为0。
###### å¤‡æ³¨ï¼š
###### è®¾ç½®æ ‡ç­¾é…ç½®è¡¨
```
void setAlignTagConfig(String tagConfig, String defaultAnimation);
```
###### æŽ¥å£è¯´æ˜Ž
设置标签配置表,配合Align模式使用可定制动作表情切换的实际。
###### å‚数说明
```tagConfig```:String,标签配置表
```defaultAnimation```:String,标签配置表动作执行完成后执行的默认动作道具路径
###### å¤‡æ³¨ï¼š
标签配置表调用见```Android FUStaKit é›†æˆæ–‡æ¡£```
---
> ### <a name="7">销毁</a>
###### é”€æ¯ FUSta SDK
```
void release();
```
###### æŽ¥å£è¯´æ˜Ž
销毁SDK,释放内存资源。
###### å‚数说明
###### å¤‡æ³¨ï¼š
---
> ### <a name="8">其他</a>
###### æ—‹è½¬Avatar
```
setRotDelta(float delta)
```
###### æŽ¥å£è¯´æ˜Ž
旋转角色。
###### å‚数说明
```delta```:表示旋转增量,取值范围`-1.0, 1.0`
###### å¤‡æ³¨ï¼š
###### ç¼©æ”¾Avatar
```
setScaleDelta(float delta)
```
###### æŽ¥å£è¯´æ˜Ž
缩放角色。
###### å‚数说明
```delta```:表示缩放增量,取值范围`-1.0, 1.0`
###### å¤‡æ³¨ï¼š
###### ä¸Šä¸‹ç§»åЍAvatar
```
setTranslateDelta(float delta)
```
###### æŽ¥å£è¯´æ˜Ž
上下移动角色。
###### å‚数说明
```delta```:表示上下增量,取值范围`-1.0, 1.0`
###### å¤‡æ³¨ï¼š
###### è®¾ç½®Avatar旋转角度
```
setRotate(float rotate)
```
###### æŽ¥å£è¯´æ˜Ž
设置Avatar旋转角度。
###### å‚数说明
```rotate```:表示旋转角度
###### å¤‡æ³¨ï¼š
###### è®¾ç½®bs表情系数数据
```
setBSConfigData(String configPath)
```
###### æŽ¥å£è¯´æ˜Ž
设置当前Avatarbs表情系数数据包路径,可不设置,不设置则使用默认数据包
###### å‚数说明
```configPath```:String,bs表情系数数据包路径
###### å¤‡æ³¨ï¼š
---
Android FUStaKit ¼¯³ÉÎĵµ.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,1205 @@
### FUStaSDK集成文档
本 SDK é›†æˆäº† FaceUnity çš„语音驱动形象引擎(Speeach to Animation) ï¼Œèƒ½å¤Ÿå¿«é€Ÿæž„建并驱动虚拟形象说话,营造更加真实自然的人机交互场景。
## ç‰ˆæœ¬ä¿¡æ¯
* **版本号**:2.1
* **更新日期**:2022-01-21
* **更新内容**:
  1. ä¼˜åŒ–CPU性能以及查询效率
  2. æ–°å¢žåŠ¨ç”»æ’­æ”¾é€Ÿåº¦æŽ§åˆ¶æŽ¥å£
  3. æ›´æ–°BS系数57-47
  4. ä¿®å¤é™éŸ³å¸§é—®é¢˜
  5. æ–°å¢žè®¾ç½®æ—‹è½¬è§’度
  6. ä¼˜åŒ–阴影锯齿算法
  7. å¢žåŠ è¯¦ç»†æ—¥å¿—æŽ¥å£
* **增量大小**:
    SDK ä½“积以及apk增量数据(单位:M):
    * v7a + v8a 22.8M   app å¢žé‡ï¼š32.6M
    SDK å†…部内置资源共计6.57M,其中包含:
  1. `controller_cpp.bundle`  å…±1.46M,graphics相关。
  2. `new_BSConfig` å…±4.11M,bs表情系数数据包。
  3. å…¶ä»–资源  çº¦1M
备注:
  ç›®å‰SDK只支持当前两个架构,如有特殊需求可打包对应架构的SDK。
## é…ç½®è¦æ±‚
* **SDK支持安卓版本:`API 21` åŠä»¥ä¸Šï¼Œå¿…须在硬件加速的窗口中使用**
## å¿«é€Ÿé›†æˆ
1. é¦–先要获取证书 `authpack.java`,放到 `faceunity` æ¨¡å— `com.faceunity.fustademo` åŒ…下;语音校准工具包`data_ali.bin`放到`assets`目录下(ALIGN方式查询口型,可不设置),语音识别工具包`data_asr.bin`放到`assets`目录下(ASR方式查询口型,可不设置),以上工具包都不设置默认只支持音频时间戳查询口型系数。
2. æž„建工程,运行到手机上,即可体验 demo åŠŸèƒ½ã€‚
3. æƒ³è¦ä½“验`流式音频播报`功能,可申请`标贝`TTS的`client_id`和`client_secret`或者对接其他三方的TTS服务。
## ä½¿ç”¨è¯´æ˜Ž
* **FU语音助手**
    **功能模块**:
    1. éžæµå¼éŸ³é¢‘播报
        æ’­æŠ¥ä¸€æ•´æ®µéŸ³é¢‘文件,查询音频对应的口型系数,并播放音频。
    2. æµå¼éŸ³é¢‘播报
        æ–‡æœ¬è¾“入通过语音合成(TTS)(由第三方服务商实现)生成音频传入SDK,查询音频对应的口型系数,并播放音频。
    3. æ­Œæ›²æ¼”å”±
        æ’­æ”¾æ­Œæ›²é©±åŠ¨å½¢è±¡ï¼Œæ­Œè¯æ˜¯å¸¦æœ‰éŸ³ç´ çš„æ–‡æœ¬ï¼ŒæŸ¥è¯¢éŸ³é¢‘å¯¹åº”çš„å£åž‹ç³»æ•°ï¼Œå¹¶æ’­æ”¾éŸ³é¢‘ã€‚
    **Demo资源集成**:
    ä»¥ä¸‹æ˜¯å½“前Demo的Avatar资源相关和STA相关数据包的集成的解析,便于开发者理解Demo和SDK调用。但不仅仅限于当前集成方式,开发者可根据项目需求自行定义集成方式。
    1. assets ç›®å½•
       è¯¥ç›®å½•存放所有的形象资源以及STA相关数据包资源,不同资源都存放在对应的子文件夹中。
      - fusta_demo/src/main/assets/sta:该目录为所有Avatar资源的存放目录
      - fusta_demo/src/main/assets/sta/animation:该目录为所有Avatar的动画资源的存放目录
      - fusta_demo/src/main/assets/sta/body:该目录为所有Avatar的body资源的存放目录
      - fusta_demo/src/main/assets/sta/builtin:该目录结构下有一个 avatar_list.json æ–‡ä»¶ï¼Œä¸»è¦ç”¨æ¥é…ç½® avatar åˆ—表,其格式如下:
          ```
          [
            {
                "name": "3D·卡通女",// avatar åç§°ï¼Œå¯ä»¥ä¸é…ç½®ã€‚
                "dirName": "cartoon_female_moren"// avatar æ–‡ä»¶å¤¹åç§°ï¼Œè¯¥æ–‡ä»¶å¤¹ä½äºŽ avatar ç›®å½•的根目录。
            },
            {
                "name": "3D·卡通男",
                "dirName": "cartoon_male_moren"
            }
          ]
          ```
        å¦‚ avatar_list.json é…ç½®ï¼Œæ¯ä¸ªå…ƒç´ å¯¹åº”一个avatar文件夹,在文件夹中保存着形象的 avatar.json é…ç½®æ–‡ä»¶ã€ç´ ææ–‡ä»¶ä»¥åŠå›¾æ ‡ç­‰ç›¸å…³æ–‡ä»¶ï¼Œavatar.json çš„æ ¼å¼å¦‚下:
          ```
          {
          "gender": 0,// æ€§åˆ«ï¼Œ0男、1女、2通用,必须配置
          "components": [// èº«ä½“各个部件,需要配置部件名称加路径
            {
              "name": "body",
              "path": "@assets/body/STA_avatar_kt_def_female_moren.bundle"
            }
          ],
          "animations": [// å½¢è±¡åŠ¨ç”»ï¼Œéœ€è¦é…ç½®åŠ¨ç”»åç§°åŠ è·¯å¾„
            {
              "name": "默认呼吸",
              "path": "@assets/animation/STA_anim_kt_def_female_weixiao.bundle"
            }
          ],
          "position": {// å½¢è±¡é»˜è®¤çš„坐标
            "x": 10.0,
            "y": 50.0,
            "z": -600.0
          },
          "scene": {// åœºæ™¯é…ç½®ï¼ŒåŒ…括背景(background)、相机(camera)、灯光(light),需要配置名称加路径
            "background": {
              "name": "background",
              "path": "@assets/STA_default_bg.bundle"
            },
            "light": {
              "name": "light",
              "path": "@assets/STA_default_light.bundle"
            }
          },
          "custom": ""//Demo业务逻辑相关的配置,主要是Avatar名称、动作列表和标签列表的定义
        }
        ```
        å¤‡æ³¨ï¼šè·¯å¾„指定的前缀@assets表示资源存在的assets下。
      - fusta_demo/src/main/assets/sta_kit:该目录存放所有STA相关数据包资源,该文件的STA相关资源包数据:
        `data_ali.bin`语音自动校准工具包(Align模式需要设置)
        `data_asr.bin`设置文字编码功能数据文件(Align模式和文本时间戳需要设置)
        `data_decoder.bin`设置语音识别工具包(ASR方式需要设置)
        åœ¨`fusta_demo/src/main/java/com/faceunity/fustademo/util/StaKitUtils.java`的`init`方法中按需加载。
      - fusta_demo/src/main/assets/sta_kit/emotion:该目录存放自定义表情bs文件。
      - fusta_demo/src/main/assets/sta_kit/song:该目录存放歌曲相关文件,用于歌曲播放能力展示。
  2. å½¢è±¡å±•示
     `com.faceunity.fu_data.data.FUDataCenter`会根据配置的 avatar ç›®å½•路径,读取 avatar_list.json ä»¥éåŽ†æ‰€æœ‰å½¢è±¡æ–‡ä»¶å¤¹ä¸­çš„ avatar.json ï¼Œç”Ÿæˆ avatar æ¨¡åž‹åˆ—表,上层业务调用者只需要传入下标便可轻松选择要展示的形象。具体调用示例如下:
     ```
     FUDataCenter fuDataCenter = new FUDataCenter(mContext);
     fuDataCenter.initWithAvatarDirAndAssetsPath(null, FUConstant.STA_ASSENTS_PATH);
     ArrayList<FUAvatarModel> avatarModels = fuDataCenter.loadAvatarLists();
     ```
     `com.faceunity.fustademo.data.AvatarDataFactory`持有`avatarModels`列表数据,调用`setAvatar(int index)`拿到对应的`FUAvatarModel`进而实现Avatar加载或切换。
* **证书**
    demo中的`authpack.java`是我司发布的SDK证书,FUStaSDK需要通过`authpack`鉴权并初始化。无法独立于证书运行,因此需要将`authpack.java`替换到你的工程中。
* **未鉴权的bundle**
    ï¼ˆç¦»çº¿é‰´æƒå†…容,在线鉴权模式请忽略)assets目录下的`fustaengine\offline\***.bundle`数据是未鉴权的bundle数据,离线鉴权过程首先需要使用未鉴权的bundle数据联网进行一次在线鉴权,鉴权成功后生成`key.bundle`,
* **key.bundle**
    ï¼ˆç¦»çº¿é‰´æƒå†…容,在线鉴权模式请忽略)`key.bundle`是SDK内部自动生成的bundle,有了该bundle后续开发者可使用该文件进行离线权限,不再需要联网操作。`key.bundle`是第一次联网鉴权成功后生成的,保存在SD卡目录下的\FaceUnity\FUStaKit\key.bundle
* **FUStaKit**
    `FUStaKit`是SDK对外的门面类。通过`FUStaKit`对象调用SDK相关功能。
* **道具资源**
    é™¤äº†SDK和证书,我们还需要道具资源供SDK加载,Demo中的`assets`文件夹包含了一些预置的资源文件(背景、形象、动作、扩展功能数据包等)。由于部分道具资源文件较大,实际开发过程中可以选择通过网络下载的方式集成到你的项目中。你可以暂先将Demo中的`assets`文件夹拖入到你的工程中使用免费道具
## é›†æˆ SDK
### 1. æ·»åŠ ä¾èµ–
在工程目录下`build.gradle`->`repositories`下添加` maven { url 'http://maven.faceunity.com/repository/maven-public/' }`。
在项目目录下的`build.gradle`下添加依赖库`api 'com.faceunity:sta-full-featured:2.1.0-RELEASES'`
### 2. FUStaKit SDK é…ç½®åˆå§‹åŒ–数据
在FUStaKit SDK初始化之前,一般放在`Application`中配置。鉴权方式分为在线鉴权和离线鉴权,可根据业务需求自行选择:
#### é…ç½®åœ¨çº¿é‰´æƒåˆå§‹åŒ–数据
**示例代码:**
```
public void initOnline(@NonNull Context context) {
     mContext = context.getApplicationContext();
     FUStaKit.Builder builder = new FUStaKit
                   //传入上下文,必要
                   .Builder(mContext)
                   //验证证书,必要
                   .setAuth(authpack.A())
                   //设置tts查询方式,必要(ASR方式需要设置:FUTtsType.ASR;Align方式需要设置:FUTtsType.ALIGNMENT)
                   .setFUTtsType(FUTtsType.ALIGNMENT)
                   //设置语音识别工具包(ASR方式需要设置)
                   // .setAsrData(bytesAsr)
                   //设置语音自动校准工具包(Align模式需要设置)
                   .setAlignData(bytesAlign)
                   //设置文字编码功能数据文件(Align模式和文本时间戳需要设置)
                   .setCharacterDecoder(bytesDecoder);
     mFUStaKit = builder.build();
}
```
备注:
#### é…ç½®ç¦»çº¿é‰´æƒåˆå§‹åŒ–数据
**示例代码:**
```
public void initOffline(@NonNull Context context) {
     mContext = context.getApplicationContext();
     FUStaKit.Builder builder = new FUStaKit
                    //传入上下文,必要
                    .Builder(mContext)
                    //验证证书,必要
                    .setAuth(authpack.A())
                    //设置tts查询方式,必要(ASR方式需要设置:FUTtsType.ASR;Align方式需要设置:FUTtsType.ALIGNMENT)
                    .setFUTtsType(FUTtsType.ALIGNMENT)
                    //设置语音识别工具包(ASR方式需要设置)
                    // .setAsrData(bytesAsr)
                    //设置语音自动校准工具包(Align模式需要设置)
                    .setAlignData(bytesAlign)
                    //设置文字编码功能数据文件(Align模式和文本时间戳需要设置)
                    .setCharacterDecoder(bytesDecoder)
                    //设置离线鉴权数据
                    .setOffLineData(offLineAuth);
     mFUStaKit = builder.build();
}
```
备注:
离线鉴权除了设置`authpack.A()` é‰´æƒæ•°æ®ï¼Œè¿˜éœ€è¦è®¾ç½®ç¦»çº¿é‰´æƒæ•°æ®åŒ…数据:`setOffLineAuth(offLineAuth)`,该逻辑可参考集成Demo中的示例代码:[StaKitUtils.java: Lines 82-150](../app/src/main/java/com/faceunity/fustademo/util/StaKitUtils.java#L82-L150)。
注意离线鉴权还需要有WRITE_EXTERNAL_STORAGE权限。
### 3. FUStaKit SDK é‰´æƒ
FUStaKit SDK初始化,必须放在 FUStaKit SDK配置初始化数据之后,鉴权方式分为在线鉴权和离线鉴权,可根据业务需求自行选择:
#### é…ç½®åœ¨çº¿é‰´æƒåˆå§‹åŒ–数据
方法:`init(FUAuthType.ONLINE, StaKitInitCallback listener)`
     `init(FUAuthType.ONLINE, null)`
参数:`FUAuthType.ONLINE`:在线鉴权;
     `FUStaKit.StaKitInitCallback`,SDK初始化状态的回调。参数可为空。
**示例代码:**
    1.有初始化完成回调的方式,SDK初始化完成的回调,进入功能页面
    // åˆå§‹çŠ¶æ€ç›‘å¬å™¨ï¼Œç›‘å¬init是否成功,回调在非UI线程
    private FUStaKit.StaKitInitCallback mInitListener = new FUStaKit.StaKitInitCallback() {
        @Override
        public void onInitComplete(int code, @NotNull String msg) {
        }
        @Override
        public void onError(int errCode, @Nullable String errMsg) {
        }
    };
    // SDK åˆå§‹åŒ–
    mFUStaKit.init(FUAuthType.ONLINE, mInitListener);
    2.没有初始化完成回调的方式,如果调用该方法之后紧接着调用口型驱动方法,口型驱动任务会等待初始化任务完成才开始
    // SDK åˆå§‹åŒ–
    mFUStaKit.init(null);
备注:
init åˆå§‹åŒ–方法,务必在后续操作前调用,否则无法驱动口型。
SDK初始化方法是耗时的,SDK内部已将任务添加到异步线程处理。如果SDK初始化任务尚未处理完毕,后续口型驱动任务回调加到任务队列等待该方法处理完毕再按照顺序操作,用户端表现为第一次口型驱动耗时时间长。
该步骤可参考集成Demo中的示例代码:[SplashActivity.java: Lines 72-117](../app/src/main/java/com/faceunity/fustademo/ui/SplashActivity.java#L72-L117)
#### é…ç½®ç¦»çº¿é‰´æƒåˆå§‹åŒ–数据
方法:`init(FUAuthType.OFFLINE_BUNDLE, StaKitInitCallback listener)`
     `init(FUAuthType.OFFLINE_BUNDLE, null)`
参数:`FUAuthType.OFFLINE_BUNDLE`:离线鉴权;
     `FUStaKit.StaKitInitCallback`:SDK初始化状态的回调。参数可为空。
**示例代码:**
    1.有初始化完成回调的方式,SDK初始化完成的回调,进入功能页面
    // SDK åˆå§‹åŒ–
    mFUStaKit.init(FUAuthType.OFFLINE_BUNDLE, mInitListener);
    2.没有初始化完成回调的方式,如果调用该方法之后紧接着调用口型驱动方法,口型驱动任务会等待初始化任务完成才开始
    // SDK åˆå§‹åŒ–
    mFUStaKit.init(null);
备注:
### 4. FUStaKit SDK è®¾ç½®é»˜è®¤FUAvatar
设置默认的FUAvatar,推荐在开始渲染前设置默认FUAvatar。
方法:`setAvatar(FUAvatar avatar, FUAvatarType avatarType, OnAvatarStateListener listener)`
方法传入参数主要是:
`FUAvatar`:FUStaKit SDK Avatar人物数据模型;
`FUAvatarType`:Avatar类型的枚举:`FUAvatarType.CARTOON`、`FUAvatarType.REAL`,默认是`FUAvatarType.CARTOON`,该参数主要用来区别SDK内置表情。缺省参数。
`OnAvatarStateListener`:Avatar执行状态接口,方法`onAvatarComplete()`表示Avatar加载完成。缺省参数。
**示例代码:**
```
 FUAvatar fuAvatar = new FUAvatar.Builder()
                    .setAvatar(avatar)// åˆ‡æ¢å½¢è±¡
                    .setCoordinate(x, y, z)// è®¾ç½®å½¢è±¡ä½ç½®
                    .setBackground(backGround)// è®¾ç½®èƒŒæ™¯
                    .setCamera(camera)// è®¾ç½®ç›¸æœºä½
                    .setLight(light)// è®¾ç½®å…‰ç…§
                    .enableShadow(enable)// è®¾ç½®é˜´å½±
                    .build();
// åˆ‡æ¢Avatar
mFUStaKit.setAvatar(fuAvatar);
或
mFUStaKit.setAvatar(fuAvatar, FUAvatarType.CARTOON);
或
mFUStaKit.setAvatar(fuAvatar, FUAvatarType.CARTOON, onAvatarStateListener);
```
备注:
设置默认的Avatar和Avatar切换调用方式一致,调用时机可以在开始渲染前设置也可以在渲染后设置,Avatar切换其对应的特征也会有变化,例如切换Avatar也会切换对应的背景、光照、位置等等。
该步骤可参考集成Demo中的示例代码:[AvatarDataFactory.java: Lines 250-278](../app/src/main/java/com/faceunity/fustademo/data/AvatarDataFactory.java#L250-L278)
### 5. FUStaKit SDK å¼€å§‹æ¸²æŸ“
SDK配置渲染相关参数并开始渲染。
方法:`requestRender(GLTextureView glTextureView)`
参数: `GLTextureView` SDK提供的渲染的组件
**示例代码:**
    mFUStaKit.requestRender(glTextureView);// è¯·æ±‚渲染
    mFUStaKit.setCustomRenderResolution(renderWidth, renderHeight);// è®¾ç½®æ¸²æŸ“分辨率,renderWidth:宽度,默认1280;renderHeight:高度,默认720
    // Activity onDestroy è°ƒç”¨
    Activity.onDestroy() {
        super.onDestroy();
        mFUStaKit.onDestroy();
    }
备注:
该步骤可参考集成Demo中的示例代码:[AvatarDataFactory.java: Lines 149-155](../app/src/main/java/com/faceunity/fustademo/data/AvatarDataFactory.java#L149-L155)
### 6. å½¢è±¡å£åž‹æŸ¥è¯¢å’Œé©±åЍ
根据传入的音频数据或者是时间戳数据查询口型并驱动口型,开发者可根据业务场景和需求选择合适的驱动方式:
根据音频数据或者时间戳数据的返回方式可分为`流式音频驱动`和`非流式音频驱动`;
根据能够提供的数据资源可分为`时间戳驱动`、`Align驱动`、`ASR驱动`;
根据是否由SDK播放器播报音频可分为`SDK内置播放器播报`、`自定义播放器播报`。
文档以`SDK内置播放器播报`、`自定义播放器播报`两种模式分类讲解。
#### SDK å†…置播放器播报
内置播放器播报,需要在口型查询之前初始化内部播放器。
方法:`initStaPlayer(new FUPlayerConfig.Builder().setAudioSampleRate(sampleRate).build())`
参数: `FUPlayerConfig`:内部播放器的参数配置类,主要配置采样率、声道数和位深。
**示例代码:**
    mFUStaKit.initStaPlayer(new FUPlayerConfig.Builder().setAudioSampleRate(16000).build());// è®¾ç½®é‡‡æ ·çŽ‡ä¸º16k
备注:
内置播放器播报,必须要先初始化播放器,接下来才能开始口型的查询和驱动。
* **流式音频,无时间戳**
    é’ˆå¯¹æµå¼è¿”回的音频数据且无时间戳的场景`(有时间戳肯定要采用时间戳方式,因为时间戳查询效率高,口型更精准)`,支持音频类型:`pcm`,根据音频数据信息查询口型系数,播放音频并驱动对应的口型。
    æ ¹æ®èƒ½ä¸èƒ½æä¾›éŸ³é¢‘数据对应的文本`(后文统一称之为AlignText)`分为:`Align`方式 ä¸Ž `ASR` æ–¹å¼ã€‚
    1、`ALIGN` æ–¹å¼
     `Align`方式查询口型系数是靠音频数据和与之对应的AlignText,在流式的查询中,音频数据是一段段返回,但是AlignText是完整的一段文本,`Align`方式查询速度较`ASR`方式更快,也可以支持高级的动作表情的定制化,但是也有限制,例如AlignText不支持繁体中文。
    **示例代码:**
      // æµå¼å¤„理开始
      mFUStaKit.notifyStaProcessStart(); 1、`ALIGN` æ–¹å¼
     `Align`方式查询口型系数是靠音频数据和与之对应的AlignText,在流式的查询中,音频数据是一段段返回,但是AlignText是完整的一段文本,`Align`方式查询速度较`ASR`方式更快,也可以支持高级的动作表情的定制化,但是也有限制,例如AlignText不支持繁体中文。
    **示例代码:**
      // æµå¼å¤„理开始
      mFUStaKit.notifyStaProcessStart();
      ...
      // å£åž‹æŸ¥è¯¢ã€éŸ³é¢‘播放并驱动对应口型,这段是多次调用的,即每次有流式音频返回都会重新设置`FUStaParams`并调用`staProcess(params)`
      FUStaParams params = new FUStaParams.Builder()
                .setStreamMode(1)// 1 æµå¼æ¨¡å¼ï¼Œ 0 éžæµå¼æ¨¡å¼   é»˜è®¤éžæµå¼
                .setAudioData(data)// éŸ³é¢‘数据,流式查询要求只能是PCM
                .setAudioType(FUAudioType.PCM)// éŸ³é¢‘类型 æµå¼æŸ¥è¯¢åªæ”¯æŒpcm  é»˜è®¤pcm
                .setAlignText(align)// AlignText æ³¨æ„æ­¤å¤„设置的是整段的文本而不是与该段音频对应的文本
                .setTimestampType(FUTimestampType.PHONE)// æ—¶é—´æˆ³ç±»åž‹ï¼Œ`ALIGN` æ–¹å¼è®¾ç½®ä¸º`FUTimestampType.PHONE`
                .build();
      mFUStaKit.staProcess(params);
      ...
      // æµå¼å¤„理结束
      mFUStaKit.notifyStaProcessFinish();
    å¤‡æ³¨ï¼š
      éŸ³é¢‘时间戳有两种类型:音素时间戳和文字时间戳,分别对应 `FUTimestampType.PHONE` å’Œ `FUTimestampType.CHARACTER`,有关音素时间戳和文本时间戳的区别可参考`12. FUStaParams å‚数配置类`里面对时间戳的示例。
      æµå¼æ— æ—¶é—´æˆ³é‡‡ç”¨`ALIGN`方式查询口型系数,sdk内部会根据音频数据和生成整段音频的文本计算出音素时间戳,故`setTimestampType(FUTimestampType.PHONE)`必须设置。
      å…³äºŽæµå¼`ALIGN`方式,比流式`ASR`方式需要多设置生成音频数据的文本,注意此处设置的是整段的文本而不是与该段音频对应的文本。
      è¯¥æ­¥éª¤å¯å‚考集成Demo中的示例代码com.faceunity.fustademo.ui.TtsActivity.DataBakerTtsCallback。
    2、`ASR`方式
    `ASR`方式查询口型系数是靠音频数据,`ASR`方式查询速度较慢,单位音频处理速度稍耗时,但流式查询场景下,SDK底层库查询处理n秒的音频速度远远大于n秒音频播放时长,因此可忽略性能差异。
     **示例代码:**
      // æµå¼å¤„理开始
      mFUStaKit.notifyStaProcessStart();
      ...
      // å£åž‹æŸ¥è¯¢ã€éŸ³é¢‘播放并驱动对应口型,这段是多次调用的,即每次有流式音频返回都会重新设置`FUStaParams`并调用`staProcess(params)`
      FUStaParams params = new FUStaParams.Builder()
                .setStreamMode(1)// 1 æµå¼æ¨¡å¼ï¼Œ 0 éžæµå¼æ¨¡å¼   é»˜è®¤éžæµå¼
                .setAudioData(data)// éŸ³é¢‘数据,流式查询要求只能是PCM
                .setAudioType(FUAudioType.PCM)// éŸ³é¢‘类型 æµå¼æŸ¥è¯¢åªæ”¯æŒpcm  é»˜è®¤pcm
                .setTimestampType(FUTimestampType.PHONE)// æ—¶é—´æˆ³ç±»åž‹ï¼Œ`ASR` æ–¹å¼è®¾ç½®ä¸º`FUTimestampType.PHONE`
                .build();
      mFUStaKit.staProcess(params);
      ...
      // æµå¼å¤„理结束
      mFUStaKit.notifyStaProcessFinish();
    å¤‡æ³¨ï¼š
    éŸ³é¢‘时间戳有两种类型:音素时间戳和文字时间戳,分别对应 `FUTimestampType.PHONE` å’Œ `FUTimestampType.CHARACTER`,有关音素时间戳和文本时间戳的区别可参考`12. FUStaParams å‚数配置类`里面对时间戳的示例。
    æµå¼æ— æ—¶é—´æˆ³é‡‡ç”¨`ASR`方式查询口型系数,sdk内部会根据音频数据计算出音素时间戳,故`setTimestampType(FUTimestampType.PHONE)`必须设置。
    è¯¥æ­¥éª¤å¯å‚考集成Demo中的示例代码com.faceunity.fustademo.ui.TtsActivity.DataBakerTtsCallback。
* **流式音频,有时间戳**
     é’ˆå¯¹æµå¼è¿”回的音频数据且有时间戳的场景,查询耗时最少,有时间戳数据优先采用时间戳方式。支持音频类型:`pcm`,根据音频数据信息查询口型系数,播放音频并驱动对应的口型。
    **示例代码:**
      // æµå¼å¤„理开始
      mFUStaKit.notifyStaProcessStart();
      ...
      // å£åž‹æŸ¥è¯¢ã€éŸ³é¢‘播放并驱动对应口型,这段是多次调用的,即每次有流式音频返回都会重新设置`FUStaParams`并调用`staProcess(params)`
      FUStaParams params = new FUStaParams.Builder()
                .setStreamMode(1)// 1 æµå¼æ¨¡å¼ï¼Œ 0 éžæµå¼æ¨¡å¼   é»˜è®¤éžæµå¼
                .setAudioData(data)// éŸ³é¢‘数据,流式查询要求只能是PCM
                .setAudioType(FUAudioType.PCM)// éŸ³é¢‘类型 æµå¼æŸ¥è¯¢åªæ”¯æŒpcm  é»˜è®¤pcm
                .setTimestamp(timestamp)// æ—¶é—´æˆ³æ•°æ®
                .setTimestampType(FUTimestampType.PHONE)// æ—¶é—´æˆ³ç±»åž‹ï¼Œå…·ä½“类型要根据时间戳的类型来定
                .build();
      mFUStaKit.staProcess(params);
      ...
      // æµå¼å¤„理结束
      mFUStaKit.notifyStaProcessFinish();
    å¤‡æ³¨ï¼š
    éŸ³é¢‘时间戳有两种类型:音素时间戳和文字时间戳,分别对应 `FUTimestampType.PHONE` å’Œ `FUTimestampType.CHARACTER`,有关音素时间戳和文本时间戳的区别可参考`12. FUStaParams å‚数配置类`里面对时间戳的示例。
    è¯¥æ­¥éª¤å¯å‚考集成Demo中的示例代码com.faceunity.fustademo.ui.TtsActivity.DataBakerTtsCallback。
* **非流式音频,无时间戳**
    é’ˆå¯¹éžæµå¼è¿”回的音频数据且无时间戳的场景`(有时间戳肯定要采用时间戳方式,因为时间戳查询效率高,口型更精准)`,支持音频类型:`pcm\wav`,根据音频数据信息查询口型系数,播放音频并驱动对应的口型。
    æ ¹æ®èƒ½ä¸èƒ½æä¾›éŸ³é¢‘数据对应的文本`(后文统一称之为AlignText)`分为:`Align`方式 ä¸Ž `ASR` æ–¹å¼ã€‚
    1、`ALIGN` æ–¹å¼
     `Align`方式查询口型系数是靠音频数据和与之对应的AlignText,在非流式的查询中,音频数据是一整段返回,AlignText是音频对应的文本,`Align`方式查询速度较`ASR`方式更快,也可以支持高级的动作表情的定制化,但是也有限制,例如AlignText不支持繁体中文。
    **示例代码:**
      // å£åž‹æŸ¥è¯¢ã€éŸ³é¢‘播放并驱动对应口型,这段是单次调用的
      FUStaParams params = new FUStaParams.Builder()
                .setAudioData(data)// éŸ³é¢‘数据,非流式查询支持PCM和WAV
                .setAudioType(FUAudioType.PCM)// éŸ³é¢‘类型 éžæµå¼æŸ¥è¯¢æ”¯æŒpcm、wav  é»˜è®¤pcm
                .setAlignText(align)// AlignText æ³¨æ„æ­¤å¤„设置的是整段的文本而不是与该段音频对应的文本
                .setTimestampType(FUTimestampType.PHONE)// æ—¶é—´æˆ³ç±»åž‹ï¼Œ`ALIGN` æ–¹å¼è®¾ç½®ä¸º`FUTimestampType.PHONE`
                .build();
      mFUStaKit.staProcess(params);
     å¤‡æ³¨ï¼š
     éŸ³é¢‘时间戳有两种类型:音素时间戳和文字时间戳,分别对应 `FUTimestampType.PHONE` å’Œ `FUTimestampType.CHARACTER`,有关音素时间戳和文本时间戳的区别可参考`12. FUStaParams å‚数配置类`里面对时间戳的示例。
     `setTimestampType(FUTimestampType.PHONE)`,非流式无时间戳采用`ALIGN`方式查询口型系数,sdk内部会根据音频数据和生成整段音频的文本计算出音素时间戳,故`setTimestampType(FUTimestampType.PHONE)`必须设置。
     è¯¥æ­¥éª¤å¯å‚考集成Demo中的示例代码com.faceunity.fustademo.ui.SimpleActivity#sendText。
    2、`ASR` æ–¹å¼
      `ASR`方式查询口型系数是靠音频数据,`ASR`方式查询速度较慢,单位音频处理速度稍耗时, å•位音频处理速度不如`ALIGN`方式,但内部实现了音频分割提高效率。
     **示例代码:**
      // å£åž‹æŸ¥è¯¢ã€éŸ³é¢‘播放并驱动对应口型,这段是单次调用的
      FUStaParams params = new FUStaParams.Builder()
                .setAudioData(data)// éŸ³é¢‘数据,非流式查询支持PCM和WAV
                .setAudioType(FUAudioType.PCM)// éŸ³é¢‘类型 éžæµå¼æŸ¥è¯¢æ”¯æŒpcm、wav  é»˜è®¤pcm
                .setTimestampType(FUTimestampType.PHONE)// æ—¶é—´æˆ³ç±»åž‹ï¼Œ`ASR` æ–¹å¼è®¾ç½®ä¸º`FUTimestampType.PHONE`
                .build();
      mFUStaKit.staProcess(params);
    å¤‡æ³¨ï¼š
    éŸ³é¢‘时间戳有两种类型:音素时间戳和文字时间戳,分别对应 `FUTimestampType.PHONE` å’Œ `FUTimestampType.CHARACTER`,有关音素时间戳和文本时间戳的区别可参考`12. FUStaParams å‚数配置类`里面对时间戳的示例。
    éžæµå¼æ— æ—¶é—´æˆ³é‡‡ç”¨`ASR`方式查询口型系数,sdk内部会根据音频数据计算出音素时间戳,故`setTimestampType(FUTimestampType.PHONE)`必须设置。
    è¯¥æ­¥éª¤å¯å‚考集成Demo中的示例代码com.faceunity.fustademo.ui.SimpleActivity#sendText。
* **非流式音频,有时间戳**
    é’ˆå¯¹éžæµå¼è¿”回的音频数据且有时间戳的场景,查询耗时最少,有时间戳数据优先采用时间戳方式。支持音频类型:`pcm\wav`,根据音频数据信息查询口型系数,播放音频并驱动对应的口型。
    **示例代码:**
    // å£åž‹æŸ¥è¯¢ã€éŸ³é¢‘播放并驱动对应口型
    FUStaParams params = new FUStaParams.Builder()
              .setAudioData(data)// éŸ³é¢‘数据,非流式查询支持PCM和WAV
              .setAudioType(FUAudioType.PCM)// éŸ³é¢‘类型 éžæµå¼æŸ¥è¯¢æ”¯æŒpcm、wav  é»˜è®¤pcm
              .setTimestamp(timestamp)// æ—¶é—´æˆ³æ•°æ®
              .setTimestampType(FUTimestampType.PHONE)// æ—¶é—´æˆ³ç±»åž‹ï¼Œ`ASR` æ–¹å¼è®¾ç½®ä¸º`FUTimestampType.PHONE`
              .build();
    mFUStaKit.staProcess(params);
    å¤‡æ³¨ï¼š
      éŸ³é¢‘时间戳有两种类型:音素时间戳和文字时间戳,分别对应 `FUTimestampType.PHONE` å’Œ `FUTimestampType.CHARACTER`,有关音素时间戳和文本时间戳的区别可参考`12. FUStaParams å‚数配置类`里面对时间戳的示例。
      è¯¥æ­¥éª¤å¯å‚考集成Demo中的示例代码com.faceunity.fustademo.ui.SimpleActivity#sendText。
* **设置内部播放器播放状态接口**
     ä»¥ä¸Šæ–¹å¼å‡é‡‡ç”¨å†…部播放器播放音频,SDK内部播放状态的接口为`OnStaPlayerListener`;
     æ–¹æ³•:`setStaPlayerListener(OnStaPlayerListener listener)`,方法传入参数主要是`OnStaPlayerListener`。
     **示例代码:**
      mFUStaKit.setStaPlayerListener(new OnStaPlayerListener() {
            @Override
            public void onPrepared() {
                // æ’­æ”¾å¼€å§‹
            }
            @Override
            public void onCompleted() {
                // æ’­æ”¾ç»“束
            }
            @Override
            public void onCancel() {
                // æ’­æ”¾å–消
            }
            @Override
            public void onError(@Nullable String message) {
                // æ’­æ”¾å‡ºé”™
            }
        });
  å¤‡æ³¨ï¼š
  è¯¥æ­¥éª¤å¯å‚考集成Demo中的示例代码[AvatarDataFactory.java: Lines 98-105](../app/src/main/java/com/faceunity/fustademo/data/AvatarDataFactory.java#L98-L105)
#### è‡ªå®šä¹‰æ’­æ”¾å™¨æ’­æŠ¥
    ç”¨æˆ·è‡ªå®šä¹‰æ’­æ”¾å™¨æ’­æŠ¥ï¼Œå…ˆæŸ¥è¯¢å£åž‹ç³»æ•°ï¼ŒæŸ¥è¯¢å®Œæˆæˆ–者首段查询完成即可以开始自定义的播放器播放,然后通过`OnExternalPlayerListener`接口的`updateCurrentPosition()`返回播放进度给SDK,
    SDK拿到播放进度驱动对应的口型,具体步骤为:
#### 1、自定义播放器查询
   `自定义播放器播报`查询方法与`内置播放器播报`不同,不过`FUStaParams`参数设置方式都一致。这里简单列举`流式时间戳查询`和`非流式时间戳查询`两种方式。
###### æµå¼æ—¶é—´æˆ³æŸ¥è¯¢
   é’ˆå¯¹æµå¼è¿”回的音频数据且有时间戳的场景,查询耗时最少,有时间戳数据优先采用时间戳方式。支持音频类型:`pcm`,根据音频数据信息查询口型系数,播放音频并驱动对应的口型。
   **示例代码:**
    // æµå¼å¤„理开始
    mFUStaKit.notifyStaProcessStart();
    ...
    // å£åž‹æŸ¥è¯¢ã€éŸ³é¢‘播放并驱动对应口型,这段是多次调用的,即每次有流式音频返回都会重新设置`FUStaParams`并调用`staProcess(params)`
    FUStaParams params = new FUStaParams.Builder()
              .setStreamMode(1)// 1 æµå¼æ¨¡å¼ï¼Œ 0 éžæµå¼æ¨¡å¼   é»˜è®¤éžæµå¼
              .setAudioType(FUAudioType.PCM)// éŸ³é¢‘类型 æµå¼æŸ¥è¯¢åªæ”¯æŒpcm  é»˜è®¤pcm
              .setTimestamp(timestamp)// æ—¶é—´æˆ³æ•°æ®
              .setTimestampType(FUTimestampType.PHONE)// æ—¶é—´æˆ³ç±»åž‹ï¼Œå…·ä½“类型要根据时间戳的类型来定
              .build();
    mFUStaKit.staProcessNoPlayer(params);
    ...
    // æµå¼å¤„理结束
    mFUStaKit.notifyStaProcessFinish();
   å¤‡æ³¨ï¼š
   éŸ³é¢‘时间戳有两种类型:音素时间戳和文字时间戳,分别对应 `FUTimestampType.PHONE` å’Œ `FUTimestampType.CHARACTER`,有关音素时间戳和文本时间戳的区别可参考`12. FUStaParams å‚数配置类`里面对时间戳的示例。
###### éžæµå¼æ—¶é—´æˆ³æŸ¥è¯¢
   é’ˆå¯¹éžæµå¼è¿”回的音频数据且有时间戳的场景,查询耗时最少,有时间戳数据优先采用时间戳方式。支持音频类型:`pcm\wav`,根据音频数据信息查询口型系数,播放音频并驱动对应的口型。
   **示例代码:**
    // å£åž‹æŸ¥è¯¢ã€éŸ³é¢‘播放并驱动对应口型,这段是多次调用的,即每次有流式音频返回都会重新设置`FUStaParams`并调用`staProcess(params)`
    FUStaParams params = new FUStaParams.Builder()
              .setAudioType(FUAudioType.PCM)// éŸ³é¢‘类型 æµå¼æŸ¥è¯¢åªæ”¯æŒpcm  é»˜è®¤pcm
              .setTimestamp(timestamp)// æ—¶é—´æˆ³æ•°æ®
              .setTimestampType(FUTimestampType.PHONE)// æ—¶é—´æˆ³ç±»åž‹ï¼Œå…·ä½“类型要根据时间戳的类型来定
              .build();
    mFUStaKit.staProcessNoPlayer(params);
   å¤‡æ³¨ï¼š
   éŸ³é¢‘时间戳有两种类型:音素时间戳和文字时间戳,分别对应 `FUTimestampType.PHONE` å’Œ `FUTimestampType.CHARACTER`,有关音素时间戳和文本时间戳的区别可参考`12. FUStaParams å‚数配置类`里面对时间戳的示例。
   è¯¥æ­¥éª¤å¯å‚考集成Demo中的示例代码:com.faceunity.fustademo.ui.SongActivity.SongSelectedListener#play。
#### 2、设置SDK口型查询状态接口
   åœ¨`1、自定义播放器查询`中查询口型系数数据,无论流式查询还是非流式查询,我们都能够通过`OnStaProcessListener`接口获得查询一次口型系数数据的回调,
   æœ‰ä¸ªè¿™ä¸ªå›žè°ƒï¼Œæˆ‘们可以认为现在SDK内部已经有口型系数的缓存了,这时候就可以开始自定义播放器的播放。
   **示例代码:**
    mFUStaKit.setStaProcessListener(new OnStaProcessListener() {
        @Override
        public void onStaProcess(FUAudioProgressType audioProgressType, byte[] date) {
              // ä¼ªä»£ç 
              CustomPlayer.startPlay();
        }
    });
   å¤‡æ³¨ï¼š
   å¯¹äºŽæµå¼æŸ¥è¯¢ï¼Œæˆ‘们可以在该次查询首次`onStaProcess()`方法回调时调用外部播放器的播放方法;对于非流式查询,我们可以在`onStaProcess()`方法回调时调用外部播放器的播放方法。
   `onStaProcess()`方法回调在非UI线程。
#### 3、外部播放器播放状态同步
   åœ¨`2、设置SDK口型查询状态接口`我们通过`OnStaProcessListener`接口知道了自定义播放器的播放时机,接下来进行外部播放器和SDK的状态同步才能驱动口型。
* **自定义播放器播报状态同步**
   å¤–部播放器播放的状态`is playing`需要向SDK同步,SDK只有接收到`playing`信号才认为外部播放器开始播放,进而根据播放进度驱动口型。
      CustomPlayer.startPlay() // å¤–部播放器播放(伪代码)
      mFUStaKit.onExternalPlayerStart(); // æ’­æ”¾å™¨æ’­æ”¾ï¼Œé€šçŸ¥SDK播放器状态:playing
      CustomPlayer.pause(); // å¤–部播放器暂停(伪代码)
      mFUStaKit.onExternalPlayerStop();  // æ’­æ”¾å™¨æš‚停,通知SDK播放器状态:no playing
      CustomPlayer.resume(); // å¤–部播放器恢复播放(伪代码)
      mFUStaKit.onExternalPlayerStart(); // æ’­æ”¾å™¨å¤æ’­æ”¾ï¼Œé€šçŸ¥SDK播放器状态:playing
      CustomPlayer.stop(); // å¤–部播放器停止播放(伪代码)
      mFUStaKit.onExternalPlayerStop(); // æ’­æ”¾å™¨åœæ­¢æ’­æ”¾ï¼Œé€šçŸ¥SDK播放器状态:no playing
   å¤‡æ³¨ï¼š
* **自定义播放器播报进度同步**
   å¤–部播放器播放的进度通过`OnExternalPlayerListener`的`updateCurrentPosition()`同步播放进度给SDK,SDK接收到`playing`信号根据播放进度驱动口型。
     **示例代码:**
      mFUStaKit.setExternalPlayerListener(new OnExternalPlayerListener() {
          @Override
          public long updateCurrentPosition() {
            return position;
          }
      });
   å¤‡æ³¨ï¼šè¯¥æ­¥éª¤å¯å‚考集成Demo中的示例代码:[AvatarDataFactory.java: Lines 195-202](../app/src/main/java/com/faceunity/fustademo/data/AvatarDataFactory.java#L195-L202)。
### 7. Align方式TAG标签功能
   é«˜çº§ç”¨æ³•,通过配置`标签映射表`和在AlignText中设置固定标记位,播放过程中用来精确控制形象动作行为的能力,支持流式和非流式。
   ä¸»è¦æ­¥éª¤å¦‚下:
#### 1、配置标签映射表
   `标签映射表`,以JSON表示,JSON中字段不可随意更改
   æ–¹æ³•:`setAlignTagConfig(String tagConfig, String defaultAnimation)`,
   æ–¹æ³•传入参数主要是`tagConfig`:标签映射表;`defaultAnimation`:标签动作播放完毕会切换到的动作路径。
   **示例代码:**
    JSON:
    {
      "tag": "#%欢迎#%",// å¯¹åº”标签,对应值为固定格式的字段,我们规定的标签格式:`#%字符#%`;
      "emotion": "welcome emotion path",// å¯¹åº”表情bs路径,动态切换表情
      "animation": "sta/animation/STA_anim_real_def_chuchu_v3_huanying.bundle"// å¯¹åº”动作路径,对应值为动作的绝对路径。
    },
    {
      "tag": "#%单手强调#%",
      "animation": "sta/animation/STA_anim_real_def_chuchu_v3_danshouqiangdiao.bundle"
    },
    {
      "tag": "#%指引走#%",
      "animation": "sta/animation/STA_anim_real_def_chuchu_v3_zhiyinzou.bundle"
    },
    {
      "tag": "#%比心#%",
      "emotion": "default emotion path",
      "animation": "sta/animation/STA_anim_real_def_chuchu_v3_bixin.bundle"
    }
    // æ›´æ–°æ ‡ç­¾é…ç½®è¡¨
    mFUStaKit.setAlignTagConfig(JSON, defaultAnimation);
   å¤‡æ³¨ï¼š
   `setAlignTagConfig`必须要传入`defaultAnimation`默认动画,执行完标签动作后会循环执行`defaultAnimation`动画。
#### 2、设置AlignText
   é€šè¿‡è¯¥æ–‡æœ¬æ’å…¥`标签映射表`中配置的标签,后续音频驱动时音频播放到插入标签关键字时就会切换该标签匹配的动作和表情。
   **示例代码:**
    éŸ³é¢‘播放内容:"大家好~我是小玉。下面由我来介绍一下公司:我们专注于智能图形的创新与应用,为移动互联网提供3D内容生成与互动的行业解决方案。致力于将好莱坞电影级的特效技术在消费级应用中的普及。";
    AlignText:"大家好~我是小玉。下面由我来#%欢迎#%介绍一下公司:#%单手强调#%我们专注于智能图形的创新与应用,#%指引走#%为移动互联网提供3D内容生成与互动的行业解决方案。#%比心#%致力于将好莱坞电影级的特效技术在消费级应用中的普及。";
    FUStaParams params = new FUStaParams.Builder()
                .setStreamMode(1)// 1 æµå¼æ¨¡å¼ï¼Œ 0 éžæµå¼æ¨¡å¼   é»˜è®¤éžæµå¼
                .setAudioData(data)// éŸ³é¢‘数据,流式查询要求只能是PCM
                .setAudioType(FUAudioType.PCM)// éŸ³é¢‘类型 æµå¼æŸ¥è¯¢åªæ”¯æŒpcm  é»˜è®¤pcm
                .setAlignText(align)// AlignText æ³¨æ„æ­¤å¤„设置的是整段的文本而不是与该段音频对应的文本
                .setTimestampType(FUTimestampType.PHONE)// æ—¶é—´æˆ³ç±»åž‹ï¼Œ`ALIGN` æ–¹å¼è®¾ç½®ä¸º`FUTimestampType.PHONE`
                .build();
    mFUStaKit.staProcess(params);
  å¤‡æ³¨ï¼š
  ä¸Šè¿°ç¤ºä¾‹ä¸­ï¼Œæ’­æ”¾å†…容时,会在“来”关键字切换#%欢迎#%对应的“STA_anim_real_def_chuchu_v3_huanying.bundle”动作和对应表情。
  â€œç›¸â€å…³é”®å­—切换#%单手强调#%对应的“STA_anim_real_def_chuchu_v3_danshouqiangdiao.bundle”动作和对应表情。后续现象均为读到所插入标签关键字时切换对应动作和对应表情。
  æœ€åŽæ’­æ”¾â€œè‡´åŠ›äºŽâ€å…³é”®å­—ä¹‹å‰åˆ‡æ¢#%比心#%对应的动作和表情,此时音频播放完成动作还没播放完成的话也会继续播放动作,等动作播放完毕会切换到默认动作。
### 8. Avatar动画切换功能
   Avatar切换并播放其支持的动画,支持单次播放和循环播放,支持多道具和多道具动作和Avatar动画同时执行。
* **循环播放动画**
   æ–¹æ³•:`playAnimation(String path, String[] prop, String[] propAnimation)`
   æ–¹æ³•传入参数:
   `path`:Avatar要切换的目标动画的路径。
   `prop`:Avatar要加载的道具的路径数组,缺省参数。
   `propAnimation`:Avatar要加载的道具动作的路径数组,缺省参数,缺省参数。
   **示例代码:**
      // åˆ‡æ¢åŠ¨ä½œ
      mFUStaKit.playAnimation(animPath, prop, propAnimation);
      æˆ–
      mFUStaKit.playAnimation(animPath);
   å¤‡æ³¨ï¼š
   è¯¥æ­¥éª¤å¯å‚考集成Demo中的示例代码:[AvatarDataFactory.java: Lines 290-305](../app/src/main/java/com/faceunity/fustademo/data/AvatarDataFactory.java#L290-L305)。
* **播放单次动画**
   æ–¹æ³•:`playAnimationOnce(String path, String[] prop, String[] propAnimation)`
   æ–¹æ³•传入参数:
   `path`:Avatar要切换的目标动画的路径。
   `prop`:Avatar要加载的道具的路径数组,缺省参数。
   `propAnimation`:Avatar要加载的道具动作的路径数组,缺省参数,缺省参数。
   **示例代码:**
      // åˆ‡æ¢åŠ¨ä½œ
      mFUStaKit.playAnimationOnce(animPath, prop, propAnimation);
      æˆ–
      mFUStaKit.playAnimationOnce(animPath);
   å¤‡æ³¨ï¼š
   è¯¥æ­¥éª¤å¯å‚考集成Demo中的示例代码:[AvatarDataFactory.java: Lines 290-305](../app/src/main/java/com/faceunity/fustademo/data/AvatarDataFactory.java#L290-L305)。
### 9. Avatar表情切换功能
   Avatar切换表情,支持SDK内置表情和自定义表情。
* **切换SDK内置表情**
   æ–¹æ³•:`updateEmotion(FUEmotionType emotionType, int fpsNum)`
   æ–¹æ³•传入参数:
   `FUEmotionType`:SDK支持的内置表情的枚举。
   `fpsNum`:过渡帧,当前表情切换到目标表情的帧数,默认为0,缺省参数。
   **示例代码:**
      // åˆ‡æ¢åŠ¨ä½œ
      mFUStaKit.updateEmotion(emotionType, 5);
      æˆ–
      mFUStaKit.updateEmotion(emotionType);
   å¤‡æ³¨ï¼š
   `FUEmotionType`详细介绍请参考`13. FUEmotionType SDK支持的内置表情的枚举`。
   è¯¥æ­¥éª¤å¯å‚考集成Demo中的示例代码:[AvatarDataFactory.java: Lines 392-400](../app/src/main/java/com/faceunity/fustademo/data/AvatarDataFactory.java#L392-L400)。
* **切换SDK自定义表情**
   æ–¹æ³•:`updateCustomEmotion(String path, int fpsNum)`
   æ–¹æ³•传入参数:
   `path`:自定义表情bs文件路径。
   `fpsNum`:过渡帧,当前表情切换到目标表情的帧数,默认为0,缺省参数。
   **示例代码:**
      // åˆ‡æ¢åŠ¨ä½œ
      mFUStaKit.updateCustomEmotion(animPath, 5);
      æˆ–
      mFUStaKit.updateCustomEmotion(animPath);
   å¤‡æ³¨ï¼š
   è¯¥æ­¥éª¤å¯å‚考集成Demo中的示例代码:[AvatarDataFactory.java: Lines 392-400](../app/src/main/java/com/faceunity/fustademo/data/AvatarDataFactory.java#L392-L400)。
### 10. å¸¸ç”¨æ–¹æ³•
* **设置3D抗锯齿配置**
    è®¾ç½®æŠ—锯齿,减少渲染的锯齿感。
    **示例代码:**
      mFUStaKit.setMultiSamples(int samples);// samples默认为4
* **设置渲染帧率**
    è®¾ç½®æ¸²æŸ“帧率。
    **示例代码:**
      mFUStaKit.setRenderFPS(int renderFPS);// renderFPS默认30
* **SDK onResume()**
    ä¸Žsdk onPause()成对出现,对应Activity onResume()减少不必要的渲染从而提高性能;非必需调用,可不设置该方法。
    **示例代码:**
      mFUStaKit.onResume();
* **SDK onPause()**
    ä¸Žsdk onResume()成对出现,对应Activity onPause()减少不必要的渲染从而提高性能;非必需调用,可不设置该方法。
    **示例代码:**
      mFUStaKit.onPause();
* **SDK onDestroy()**
    Activity onDestroy()调用。
    **示例代码:**
      mFUStaKit.onDestroy();
* **Avatar更新背景**
    æ”¯æŒèƒŒæ™¯é“具更新。参数: èƒŒæ™¯é“具的绝对路径。
    **示例代码:**
      mFUStaKit.setBackground(String background);// èƒŒæ™¯åˆ‡æ¢ï¼Œå‚数为背景道具路径
* **Avatar光照更新**
    æ”¯æŒå…‰ç…§é“具更新。参数: ç¯å…‰é“具的绝对路径。
    **示例代码:**
      mFUStaKit.setLight(String light);// æ›´æ–°å…‰ç…§ï¼Œå‚数为灯光道具路径
* **Avatar相机位更新**
    æ”¯æŒç›¸æœºä½é“具更新。参数: ç›¸æœºä½é“具的绝对路径。
    **示例代码:**
      mFUStaKit.setCamera(String camera);// æ›´æ–°ç›¸æœºä½ï¼Œå‚数为相机道具路径
* **Avatar开启阴影**
    æ”¯æŒå¼€å¯é˜´å½±ã€‚
    **示例代码:**
      mFUStaKit.enableShadow(String enableShadow);// æ˜¯å¦å¼€å¯é˜´å½±
* **Avatar开启阴影抗锯齿**
    å¼€å¯é˜´å½±æŠ—锯齿。
    **示例代码:**
      mFUStaKit.setShadowPCFLevel(int level);// é˜´å½±é”¯é½¿ç®—法级别
* **设置Avatar位置**
    è®¾ç½®è§’色在三维空间的位置,参数:
    x:double X轴坐标 ä¸€èˆ¬è°ƒæ•´èŒƒå›´ -200.0~200.0
    y:double Y轴坐标 ä¸€èˆ¬è°ƒæ•´èŒƒå›´ -600.0~800.0
    z:double Z轴坐标 ä¸€èˆ¬è°ƒæ•´èŒƒå›´ -3000.0~600.0
    **示例代码:**
      mFUStaKit.setPosition(x,y, z);
* **旋转形象**
    æ—‹è½¬è§’色,参数:double è¡¨ç¤ºæ—‹è½¬å¢žé‡ï¼Œä¸€èˆ¬è°ƒæ•´èŒƒå›´ -1.0~1.0,效果为旋转
    **示例代码:**
      mFUStaKit.setRotDelta(val)  // æ—‹è½¬è§’色
* **缩放形象**
    ç¼©æ”¾è§’色,参数:double è¡¨ç¤ºç¼©æ”¾å¢žé‡ï¼Œä¸€èˆ¬è°ƒæ•´èŒƒå›´ -1.0~1.0,效果为缩放
    **示例代码:**
      mFUStaKit.setScaleDelta(val)  // ç¼©æ”¾è§’色
* **上下移动形象**
    ä¸Šä¸‹ç§»åŠ¨è§’è‰²ï¼Œå‚æ•°:double è¡¨ç¤ºä¸Šä¸‹å¢žé‡ï¼Œä¸€èˆ¬è°ƒæ•´èŒƒå›´ -1.0~1.0,效果为上下移动
    **示例代码:**
      mFUStaKit.setTranslateDelta(val)  // ä¸Šä¸‹ç§»åŠ¨è§’è‰²
* **设置旋转角度**
    è®¾ç½®æ—‹è½¬è§’度,参数:float è¡¨ç¤ºæ—‹è½¬è§’度,效果为旋转
    **示例代码:**
      mFUStaKit.setRotate(val)  // è®¾ç½®æ—‹è½¬è§’度
* **Avatar动画恢复播放**
    æ¢å¤æ’­æ”¾å½“前动画
    **示例代码:**
      // ç»§ç»­æ’­æ”¾å½“前动画
      mFUStaKit.startCurrentAnimation();
* **Avatar动画暂停播放**
    æš‚停播放当前动画
    **示例代码:**
      // æš‚停播放当前动画
      mFUStaKit.pauseCurrentAnimation();
* **设置Avatar动画的过渡时间**
    åŠ¨ç”»åˆ‡æ¢æœ‰ä¸€ä¸ªè¿‡æ¸¡ï¼Œæ­¤æ–¹æ³•è®¾ç½®åŠ¨ä½œåˆ‡æ¢æ—¶ï¼ŒåŽŸåŠ¨ä½œå’Œåˆ‡æ¢åŠ¨ä½œçš„è¿‡æ¸¡æ—¶é—´ã€‚
    å‚数:过渡时间,单位为秒,默认为0.5
    **示例代码:**
      // è®¾ç½®åŠ¨ä½œçš„è¿‡æ¸¡æ—¶é—´
      mFUStaKit.setAnimationTransitionTime(time);
* **设置Avatar动画的播放速度**
    åŠ¨ç”»åˆ‡æ¢æœ‰ä¸€ä¸ªè¿‡æ¸¡ï¼Œæ­¤æ–¹æ³•è®¾ç½®åŠ¨ä½œæ’­æ”¾çš„é€Ÿåº¦ã€‚
    å‚数:播放速度挡位,范围0.2-5.0,默认为1.0
    **示例代码:**
      // è®¾ç½®åŠ¨ä½œçš„æ’­æ”¾é€Ÿåº¦
      mFUStaKit.setAnimationSpeed(speed);
 * **设置日志是否输出到文件**
    è®¾ç½®SDK输出到指定本地目录。
    **示例代码:**
      // è®¾ç½®æ—¥å¿—输出的目录路径
      mFUStaKit.setLogOutputDir(logcatDir)
      // è®¾ç½®æ—¥å¿—是否输出到文件
      mFUStaKit.enableLogOutput(enable);
### 11. é”€æ¯ FUStaKit å®žä¾‹
在需要销毁FUStaKit时,销毁SDK,释放内存资源。
**示例代码:**
```
mFUStaKit().release();
```
### 12. FUStaParams å‚数配置类
`streamMode` : 1 æµå¼æ¨¡å¼ï¼Œ 0 éžæµå¼æ¨¡å¼  é»˜è®¤ï¼š0
`splitSegmentSeconds` : æµå¼åˆ†å‰²æ¯æ®µé—´éš”,单位秒  é»˜è®¤ï¼š2
`audioData` : éŸ³é¢‘数据 ç±»åž‹ï¼šå­—节数组
`audioType` : éŸ³é¢‘类型 `FUAudioType.WAV`,`FUAudioType.PCM`,默认:`FUAudioType.PCM`
`audioSampleRate` : é‡‡æ ·çއ é»˜è®¤ï¼š16K,必须与内部播放器设置的采样率一致
`audioEncoding` : é‡‡æ ·ç²¾åº¦  é»˜è®¤ï¼š16
`audioChannel` : å£°é“æ•°  é»˜è®¤ï¼š 1
`alignText` : éŸ³é¢‘对应的文本
`timestamp` : æ—¶é—´æˆ³  ç±»åž‹ï¼šString  ç”¨äºŽå­˜åœ¨æ—¶é—´æˆ³çš„æƒ…况
```
时间戳格式示例:
0.000000 0.070000 sil
0.070000 0.105000 n
0.105000 0.165000 i
0.165000 0.275000 h
0.275000 0.452000 ao
0.452000 0.802000 sil
```
每个音素以换行符\n分行,每行内容分别为:开始时间,结束时间,音素
`timestampType` ï¼š æ—¶é—´æˆ³ç±»åž‹  éŸ³é¢‘数据类型对应着音节时间戳,有两种类型:音素、文字时间戳格式,分别对应 `FUTimestampType.PHONE` ã€ `FUTimestampType.CHARACTER`  é»˜è®¤ï¼šFUTimestampType.CHARACTER
```
音素类型,比如:
0.0 0.075 SIL
0.075 0.185 c
0.185 0.315 ong
0.315 0.41 m
0.41 0.509 ing
0.509 0.594 t
0.594 0.779 ian
0.779 0.98399997 q
0.98399997 1.189 i
1.189 1.511 SIL
文本类型,比如:
0.000000 1.871000 SIL
1.872000 2.056000 æˆ‘
2.057000 2.248000 çš„
2.249000 2.444000 çœ¼
2.445000 2.993000 ç›
2.994000 3.313000 æœ›
3.314000 3.680000 å‘
3.681000 4.130000 çª—
4.131000 4.767000 å¤–
4.767000 4.967000 SIL
```
### 13. FUEmotionType SDK支持的内置表情的枚举
```
NONE : æ— è¡¨æƒ…,眨眼,表情跟随动画表情
DYNAMIC_NORMAL : æ­£å¸¸è¡¨æƒ…
DYNAMIC_JOY : åŠ¨æ€å¼€å¿ƒ
DYNAMIC_ANGER : åŠ¨æ€ç”Ÿæ°”
DYNAMIC_DISGUST : åŠ¨æ€åŽŒæ¶
DYNAMIC_SURPRISE : åŠ¨æ€æƒŠè®¶
DYNAMIC_FEAR : åŠ¨æ€ææƒ§
DYNAMIC_TRUST : åŠ¨æ€ä¿¡ä»»
DYNAMIC_SADNESS : åŠ¨æ€æ‚²ä¼¤
DYNAMIC_DOUBT : åŠ¨æ€ç–‘é—®
```
### 14. å¸¸è§é—®é¢˜
* **如何让获取日志**
    è§£ç­”:
    1. åœ¨åˆå§‹åŒ–前设置`FUStaKit.setStaKitDebug(FUStaLogger.LogLevel.TRACE)`。
    2. å£åž‹é—®é¢˜å¯ä»¥ç”¨`FUSTA_LOG`过滤,渲染问题可以用`KIT_SDKController`过滤。
* **形象加载失败\加载不出来**
    è§£ç­”:
    1. æ£€æŸ¥è¯ä¹¦æ˜¯å¦è¿‡æœŸã€‚
    2. æ£€æŸ¥èµ„源文件(bundle)路径(绝对路径)是否设置正确。
    3. æ£€æŸ¥å¹¶è°ƒæ•´å½¢è±¡ä½ç½®å¤§å°ã€‚
    4. æ£€æŸ¥FUStaSDK版本与要加载的资源文件版本是否对应。
* **形象无法驱动口型**
    è§£ç­”:
    1. æ£€æŸ¥è¯ä¹¦æ˜¯å¦è¿‡æœŸã€‚
    2. æ£€æŸ¥SDK初始化设置。
    3. æ£€æŸ¥å½¢è±¡é©±åŠ¨å£åž‹æ–¹æ³•å‚æ•°é…ç½®ã€‚
    4. å¤–部播放器是否设置了开始播放方法或者有没有设置播放进度。
    5. å¦‚果使用了asr或者align方式,检查是否加载了扩展数据包。
    6. æ£€æŸ¥ç›®æ ‡æž¶æž„å’ŒSDK所支持架构是否一致。
    7. æ£€æŸ¥æ˜¯å¦æœ‰ç¬¬ä¸‰æ–¹åº“与SDK冲突且开发做了以下操作:打包时移除项目中的库文件或设置匹配到第一个库文件。
* **口型不准确**
    è§£ç­”:
    1. æ£€æŸ¥å½¢è±¡é©±åŠ¨å£åž‹æ–¹æ³•å‚æ•°é…ç½®ã€‚
    2. å¤–部播放器同步到SDK的播放进度不准确。
* **背景透明**
    æœ‰äº›éœ€æ±‚场景希望可以实现背景透明的需求,可参考以下方式。
    è§£ç­”:
  1. GLTextureView.setOpaque(false);
  2. mFUStaKit.setBackground(null);
* **横竖屏切换**
    è§£ç­”:
  1. åœ¨AndroidManifest.xml中配置Activity android:configChanges="orientation|screenSize"。
STA¸üÐÂÈÕÖ¾.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,120 @@
#### 2019.11.08
**1.1.1**
- æ·»åŠ é‰´æƒæ–¹å¼ï¼Œç›®å‰æ”¯æŒåœ¨çº¿é‰´æƒã€type1、离线鉴权type2
- ä¼˜åŒ–sdk初始化数据包方法
- æé«˜åº•层查询速度,适配多设备形象展示
- æ›´æ–°å½¢è±¡åŠ¨ä½œèµ„æº
#### 2019.11.26
**2.1.1**
- æ›´æ–°æ·»åŠ å½¢è±¡åŠ¨ä½œèµ„æº
- åˆ é™¤æ—§Align底层库
- æ·»åŠ å½¢è±¡æ”¯æŒç‰¹å®šå…‰ç…§bundle、bsconfigdata(bs系数)
- æ›´æ–°sta、sta_lite底层库,最低支持安卓4.2版本
#### 2019.12.25
**1.0**
- åŸºäºŽ2.1.1更新的稳定版本
- ä¿®å¤æµå¼æ’­æ”¾å™¨bug
- æ›´æ¢controller、nama、默认光照,升级动画系统,controller可复用,支持资源数组和独立avatar资源加载
- æ›´æ–°bs系数,添加bs融合
- æ”¯æŒèµ„源路径加载方式:assets\sdcard
#### 2020.01.15
**1.1**
- ä¿®å¤æ’­æ”¾å™¨bug
- æ›´æ–°åº•层库,sta库支持流式查询,Align方式支持流式查询
- æ›¿æ¢äº†æµå¼æ—¶é—´æˆ³å’Œæµå¼éŸ³é¢‘驱动口型算法
- æ”¯æŒé•¿éŸ³é¢‘按照静音帧分割
- ä¼˜åŒ–驱动逻辑
#### 2020.04.1
**1.2**
- å¢žåŠ sdk初始化回调
- æ›´æ”¹GLSurfaceView为GLTextureView,完全支持背景透明方案
- æ›´æ–°nama和controller,支持物理动效
- æ›´æ–°sta口型库和相关配置文件
- æ’­æ”¾å™¨æ–°å¢žcancle()回调
- æ–°å¢žåŠ¨ç”»æš‚åœã€æ¢å¤æ’­æ”¾æ–¹æ³•
#### 2020.06.9
**1.2.1**
- å†…部逻辑优化
- æ”¯æŒåŠ¨æ€åˆ‡æ¢èƒŒæ™¯bundle和自定义背景
#### 2020.07.6
**1.3**
- æ”¯æŒäº†Align模式的标签功能
- æ”¯æŒç»„合道具切换
- æ”¯æŒåŠ¨æ€é˜´å½±é“å…·
- æ”¯æŒè®¾ç½®åŠ¨ç”»è¿‡æ¸¡æ—¶é—´
#### 2020.01.20
**1.4**
- æ›´æ–°sta口型库,优化口型
- æ›´æ–°CNama库,修复渲染相关bug
- æ–°å¢žåŠ¨æ€é˜´å½±å¼€å…³
- æ–°å¢žæ¨¡åž‹æ—‹è½¬ã€ç¼©æ”¾ã€ä¸Šä¸‹ç§»åŠ¨çš„æ–¹æ³•
- æ–°å¢žè¡¨æƒ…过渡开关,更新表情bs文件
- ä¼˜åŒ–日志分级打印功能
- ä¼˜åŒ–背景透明和背景切换效果
- ä¼˜åŒ–代码逻辑
#### 2021.02.24
**1.4.1**
- ä¼˜åŒ–表情切换和表情过渡功能
- ä¼˜åŒ–口型播报效果
- ä¿®å¤å…¶ä»–已知问题
#### 2021.04.23
**1.5**
- â½€æŒâ¾ƒå®šä¹‰å¸§çއ
- â½€æŒâ¾ƒå®šä¹‰åˆ†è¾¨çއ
- â½€æŒè¿â¾æ—¶ä¿®æ”¹æ ‡ç­¾é…ç½®è¡¨
- â½€æŒè¾“出RGBABuffer数据
- ä¼˜åŒ–透明背景抗锯⻮效果
- ä¼˜åŒ–多道具组合接⼝
- ä¿®å¤â¾ƒå®šä¹‰èƒŒæ™¯å¤±æ•ˆçš„问题
#### 2021.09.30
**2.0**
- æ›´æ–°sta口型库
- åŸºäºŽRender-Kit组件渲染
- æ›´æ–°éƒ¨åˆ†æ–¹æ³•定义
- â½€æŒåŠ¨æ€æ›´æ–°æœºä½
- â½€æŒåŠ¨æ€æ›´æ–°å…‰ç…§
#### 2022.01.21
**2.1**
- ä¼˜åŒ–CPU性能以及查询效率
- æ–°å¢žåŠ¨ç”»æ’­æ”¾é€Ÿåº¦æŽ§åˆ¶æŽ¥å£
- æ›´æ–°BS系数57-47
- ä¿®å¤é™éŸ³å¸§é—®é¢˜
- â½€æ–°å¢žè®¾ç½®æ—‹è½¬è§’度
- ä¼˜åŒ–阴影锯齿算法
- å¢žåŠ è¯¦ç»†æ—¥å¿—æŽ¥å£
duan.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,54 @@
                å¼€å…³æœºç›’子测试报告
测试素材:
无
测试目的:
确认18个开关机盒子是否正常开关机
测试时间:
第三批:开始时间2021-12-24
                  ç»“束时间2021-12-30
终端MAC地址:
01:0025E1033D53
02:0025E1033CF6
03:0025E1033D00
04:0025E1033D02
05:0025E1033CF3
06:0025E1033D72
07:0025E1033D66
08:0025E1033A8B
09:0025E1033CF2
10:0025E1033D5B
11:0025E1033D6F
12:0025E1033A61
13:0025E1033D4A
14:0025E1033D68
15:0025E1033D67
16:0025E1033CE4
17:0025E1033D47
18:0025E1033DA1
测试过程:
1、 å°†18台开关机盒子时间设置统一,统一勾选关机时段内上电保持开机
周一至周五:08:15 â€“ 09:00
                                    09:10 â€“ 10:00
                             10:10 â€“ 12:00
                         12:10 â€“ 13:00
                         13:10 â€“ 18:00
            å‘¨å…­å…¨å¤©å¼€
            å‘¨æ—¥å…¨å¤©å…³
结果:18台开关机盒子在规定的时间正常开关机
总结
Mac地址为0025E1033CF2 çº¿æŽ¥é”™äº†ï¼Œä»¥ä¸‹æ˜¯å›¾ç‰‡ï¼š
haha.sh
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,28 @@
#!/bin/bash
#检查是否为root账号
if [ $(whoami) != "root" ];then
    echo "请使用root权限执行"
    exit 1;
fi
#检查是否为64位系统
is64bit=$(getconf LONG_BIT)
if [ "${is64bit}" != '64' ];then
    Red_Error "请使用64位系统";
fi
#设定软件安装目录为/server
cd /
mkdir server
install_path="/server"
#安装JDK并设置环境变量
mkdir $install_path/JDK
rm -rf $install_path/JDK/jdk-18.0.2.1/
tar -xvf /Tools/jdk-18_linux-x64_bin.tar.gz -C $install_path/JDK
JAVA_HOME=$install_path/JDK/jdk-18.0.2.1
echo export JAVA_HOME=$install_path/JDK/jdk-18.0.2.1 >> /etc/profile
echo export PATH=$JAVA_HOME/bin:$PATH >> /etc/profile
echo export CLASSPATH=$JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib/dt.jar >> /etc/profile
source /etc/profile
install.sh
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,738 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
LANG=en_US.UTF-8
if [ $(whoami) != "root" ];then
    echo "请使用root权限执行宝塔安装命令!"
    exit 1;
fi
is64bit=$(getconf LONG_BIT)
if [ "${is64bit}" != '64' ];then
    Red_Error "抱歉, å½“前面板版本不支持32位系统, è¯·ä½¿ç”¨64位系统或安装宝塔5.9!";
fi
cd ~
setup_path="/www"
python_bin=$setup_path/server/panel/pyenv/bin/python
cpu_cpunt=$(cat /proc/cpuinfo|grep processor|wc -l)
if [ "$1" ];then
    IDC_CODE=$1
fi
GetSysInfo(){
    if [ -s "/etc/redhat-release" ];then
        SYS_VERSION=$(cat /etc/redhat-release)
    elif [ -s "/etc/issue" ]; then
        SYS_VERSION=$(cat /etc/issue)
    fi
    SYS_INFO=$(uname -a)
    SYS_BIT=$(getconf LONG_BIT)
    MEM_TOTAL=$(free -m|grep Mem|awk '{print $2}')
    CPU_INFO=$(getconf _NPROCESSORS_ONLN)
    echo -e ${SYS_VERSION}
    echo -e Bit:${SYS_BIT} Mem:${MEM_TOTAL}M Core:${CPU_INFO}
    echo -e ${SYS_INFO}
    echo -e "请截图以上报错信息发帖至论坛v7.hostcli.com/bbs求助"
}
Red_Error(){
    echo '=================================================';
    printf '\033[1;31;40m%b\033[0m\n' "$1";
    GetSysInfo
    exit 1;
}
Lock_Clear(){
    if [ -f "/etc/bt_crack.pl" ];then
        chattr -R -ia /www
        chattr -ia /etc/init.d/bt
        \cp -rpa /www/backup/panel/vhost/* /www/server/panel/vhost/
        mv /www/server/panel/BTPanel/__init__.bak /www/server/panel/BTPanel/__init__.py
        rm -f /etc/bt_crack.pl
    fi
}
Install_Check(){
    if [ "${INSTALL_FORCE}" ];then
        return
    fi
    echo -e "----------------------------------------------------"
    echo -e "检查已有其他Web/mysql环境,安装宝塔可能影响现有站点及数据"
    echo -e "Web/mysql service is alreday installed,Can't install panel"
    echo -e "----------------------------------------------------"
    echo -e "已知风险/Enter yes to force installation"
    read -p "输入yes强制安装: " yes;
    if [ "$yes" != "yes" ];then
        echo -e "------------"
        echo "取消安装"
        exit;
    fi
    INSTALL_FORCE="true"
}
System_Check(){
    MYSQLD_CHECK=$(ps -ef |grep mysqld|grep -v grep|grep -v /www/server/mysql)
    PHP_CHECK=$(ps -ef|grep php-fpm|grep master|grep -v /www/server/php)
    NGINX_CHECK=$(ps -ef|grep nginx|grep master|grep -v /www/server/nginx)
    HTTPD_CHECK=$(ps -ef |grep -E 'httpd|apache'|grep -v /www/server/apache|grep -v grep)
    if [ "${PHP_CHECK}" ] || [ "${MYSQLD_CHECK}" ] || [ "${NGINX_CHECK}" ] || [ "${HTTPD_CHECK}" ];then
        Install_Check
    fi
}
Get_Pack_Manager(){
    if [ -f "/usr/bin/yum" ] && [ -d "/etc/yum.repos.d" ]; then
        PM="yum"
    elif [ -f "/usr/bin/apt-get" ] && [ -f "/usr/bin/dpkg" ]; then
        PM="apt-get"
    fi
}
Auto_Swap()
{
    swap=$(free |grep Swap|awk '{print $2}')
    if [ "${swap}" -gt 1 ];then
        echo "Swap total sizse: $swap";
        return;
    fi
    if [ ! -d /www ];then
        mkdir /www
    fi
    swapFile="/www/swap"
    dd if=/dev/zero of=$swapFile bs=1M count=1025
    mkswap -f $swapFile
    swapon $swapFile
    echo "$swapFile    swap    swap    defaults    0 0" >> /etc/fstab
    swap=`free |grep Swap|awk '{print $2}'`
    if [ $swap -gt 1 ];then
        echo "Swap total sizse: $swap";
        return;
    fi
    sed -i "/\/www\/swap/d" /etc/fstab
    rm -f $swapFile
}
Service_Add(){
    if [ "${PM}" == "yum" ] || [ "${PM}" == "dnf" ]; then
        chkconfig --add bt
        chkconfig --level 2345 bt on
    elif [ "${PM}" == "apt-get" ]; then
        update-rc.d bt defaults
    fi
}
get_node_url(){
    if [ ! -f /bin/curl ];then
        if [ "${PM}" = "yum" ]; then
            yum install curl -y
        elif [ "${PM}" = "apt-get" ]; then
            apt-get install curl -y
        fi
    fi
    echo '---------------------------------------------';
    echo "Selected download node...";
    download_Url='http://v7.hostcli.com';
    echo "Download node: $download_Url";
    echo '---------------------------------------------';
}
Remove_Package(){
    local PackageNmae=$1
    if [ "${PM}" == "yum" ];then
        isPackage=$(rpm -q ${PackageNmae}|grep "not installed")
        if [ -z "${isPackage}" ];then
            yum remove ${PackageNmae} -y
        fi
    elif [ "${PM}" == "apt-get" ];then
        isPackage=$(dpkg -l|grep ${PackageNmae})
        if [ "${PackageNmae}" ];then
            apt-get remove ${PackageNmae} -y
        fi
    fi
}
Install_RPM_Pack(){
    yumPath=/etc/yum.conf
    Centos8Check=$(cat /etc/redhat-release | grep ' 8.' | grep -iE 'centos|Red Hat')
    isExc=$(cat $yumPath|grep httpd)
    if [ "$isExc" = "" ];then
        echo "exclude=httpd nginx php mysql mairadb python-psutil python2-psutil" >> $yumPath
    fi
    #yumBaseUrl=$(cat /etc/yum.repos.d/CentOS-Base.repo|grep baseurl=http|cut -d '=' -f 2|cut -d '$' -f 1|head -n 1)
    #[ "${yumBaseUrl}" ] && checkYumRepo=$(curl --connect-timeout 5 --head -s -o /dev/null -w %{http_code} ${yumBaseUrl})
    #if [ "${checkYumRepo}" != "200" ];then
    #   curl -Ss --connect-timeout 3 -m 60 http://download.bt.cn/install/yumRepo_select.sh|bash
    #fi
    #尝试同步时间(从bt.cn)
    echo 'Synchronizing system time...'
    getBtTime=$(curl -sS --connect-timeout 3 -m 60 http://v7.hostcli.com/api/index/get_time)
    if [ "${getBtTime}" ];then
        date -s "$(date -d @$getBtTime +"%Y-%m-%d %H:%M:%S")"
    fi
    if [ -z "${Centos8Check}" ]; then
        yum install ntp -y
        rm -rf /etc/localtime
        ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
        #尝试同步国际时间(从ntp服务器)
        ntpdate 0.asia.pool.ntp.org
        setenforce 0
    fi
    startTime=`date +%s`
    sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config
    #yum remove -y python-requests python3-requests python-greenlet python3-greenlet
    yumPacks="libcurl-devel wget tar gcc make zip unzip openssl openssl-devel gcc libxml2 libxml2-devel libxslt* zlib zlib-devel libjpeg-devel libpng-devel libwebp libwebp-devel freetype freetype-devel lsof pcre pcre-devel vixie-cron crontabs icu libicu-devel c-ares libffi-devel bzip2-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel"
    yum install -y ${yumPacks}
    for yumPack in ${yumPacks}
    do
        rpmPack=$(rpm -q ${yumPack})
        packCheck=$(echo ${rpmPack}|grep not)
        if [ "${packCheck}" ]; then
            yum install ${yumPack} -y
        fi
    done
    if [ -f "/usr/bin/dnf" ]; then
        dnf install -y redhat-rpm-config
    fi
    ALI_OS=$(cat /etc/redhat-release |grep "Alibaba Cloud Linux release 3")
    if [ -z "${ALI_OS}" ];then
        yum install epel-release -y
    fi
}
Install_Deb_Pack(){
    ln -sf bash /bin/sh
    apt-get update -y
    apt-get install ruby -y
    apt-get install lsb-release -y
    #apt-get install ntp ntpdate -y
    #/etc/init.d/ntp stop
    #update-rc.d ntp remove
    #cat >>~/.profile<<EOF
    #TZ='Asia/Shanghai'; export TZ
    #EOF
    #rm -rf /etc/localtime
    #cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
    #echo 'Synchronizing system time...'
    #ntpdate 0.asia.pool.ntp.org
    #apt-get upgrade -y
    debPacks="wget curl libcurl4-openssl-dev gcc make zip unzip tar openssl libssl-dev gcc libxml2 libxml2-dev zlib1g zlib1g-dev libjpeg-dev libpng-dev lsof libpcre3 libpcre3-dev cron net-tools swig build-essential libffi-dev libbz2-dev libncurses-dev libsqlite3-dev libreadline-dev tk-dev libgdbm-dev libdb-dev libdb++-dev libpcap-dev xz-utils git";
    apt-get install -y $debPacks --force-yes
    for debPack in ${debPacks}
    do
        packCheck=$(dpkg -l ${debPack})
        if [ "$?" -ne "0" ] ;then
            apt-get install -y debPack
        fi
    done
    if [ ! -d '/etc/letsencrypt' ];then
        mkdir -p /etc/letsencryp
        mkdir -p /var/spool/cron
        if [ ! -f '/var/spool/cron/crontabs/root' ];then
            echo '' > /var/spool/cron/crontabs/root
            chmod 600 /var/spool/cron/crontabs/root
        fi
    fi
}
Install_Bt(){
    panelPort="8888"
    if [ -f ${setup_path}/server/panel/data/port.pl ];then
        panelPort=$(cat ${setup_path}/server/panel/data/port.pl)
    fi
    mkdir -p ${setup_path}/server/panel/logs
    mkdir -p ${setup_path}/server/panel/vhost/apache
    mkdir -p ${setup_path}/server/panel/vhost/nginx
    mkdir -p ${setup_path}/server/panel/vhost/rewrite
    mkdir -p ${setup_path}/server/panel/install
    mkdir -p /www/server
    mkdir -p /www/wwwroot
    mkdir -p /www/wwwlogs
    mkdir -p /www/backup/database
    mkdir -p /www/backup/site
    if [ ! -f "/usr/bin/unzip" ]; then
        if [ "${PM}" = "yum" ]; then
            yum install unzip -y
        elif [ "${PM}" = "apt-get" ]; then
            apt-get install unzip -y
        fi
    fi
    if [ -f "/etc/init.d/bt" ]; then
        /etc/init.d/bt stop
        sleep 1
    fi
    wget -O panel.zip ${download_Url}/install/src/panel_new.zip -T 10
    wget -O /etc/init.d/bt ${download_Url}/install/src/bt6.init -T 10
    wget -O /www/server/panel/install/public.sh ${download_Url}/install/public.sh -T 10
    if [ -f "${setup_path}/server/panel/data/default.db" ];then
        if [ -d "/${setup_path}/server/panel/old_data" ];then
            rm -rf ${setup_path}/server/panel/old_data
        fi
        mkdir -p ${setup_path}/server/panel/old_data
        d_format=$(date +"%Y%m%d_%H%M%S")
        \cp -arf ${setup_path}/server/panel/data/default.db ${setup_path}/server/panel/data/default_backup_${d_format}.db
        mv -f ${setup_path}/server/panel/data/default.db ${setup_path}/server/panel/old_data/default.db
        mv -f ${setup_path}/server/panel/data/system.db ${setup_path}/server/panel/old_data/system.db
        mv -f ${setup_path}/server/panel/data/port.pl ${setup_path}/server/panel/old_data/port.pl
        mv -f ${setup_path}/server/panel/data/admin_path.pl ${setup_path}/server/panel/old_data/admin_path.pl
    fi
    unzip -o panel.zip -d ${setup_path}/server/ > /dev/null
    if [ -d "${setup_path}/server/panel/old_data" ];then
        mv -f ${setup_path}/server/panel/old_data/default.db ${setup_path}/server/panel/data/default.db
        mv -f ${setup_path}/server/panel/old_data/system.db ${setup_path}/server/panel/data/system.db
        mv -f ${setup_path}/server/panel/old_data/port.pl ${setup_path}/server/panel/data/port.pl
        mv -f ${setup_path}/server/panel/old_data/admin_path.pl ${setup_path}/server/panel/data/admin_path.pl
        if [ -d "/${setup_path}/server/panel/old_data" ];then
            rm -rf ${setup_path}/server/panel/old_data
        fi
    fi
    rm -f panel.zip
    if [ ! -f ${setup_path}/server/panel/tools.py ];then
        Red_Error "ERROR: Failed to download, please try install again!"
    fi
    rm -f ${setup_path}/server/panel/class/*.pyc
    rm -f ${setup_path}/server/panel/*.pyc
    chmod +x /etc/init.d/bt
    chmod -R 600 ${setup_path}/server/panel
    chmod -R +x ${setup_path}/server/panel/script
    ln -sf /etc/init.d/bt /usr/bin/bt
    echo "${panelPort}" > ${setup_path}/server/panel/data/port.pl
    wget -O /etc/init.d/bt ${download_Url}/install/src/bt7.init -T 10
    wget -O /www/server/panel/init.sh ${download_Url}/install/src/bt7.init -T 10
}
Install_Python_Lib(){
    curl -Ss --connect-timeout 3 -m 60 $download_Url/install/pip_select.sh|bash
    pyenv_path="/www/server/panel"
    if [ -f $pyenv_path/pyenv/bin/python ];then
        is_err=$($pyenv_path/pyenv/bin/python3.7 -V 2>&1|grep 'Could not find platform')
        if [ "$is_err" = "" ];then
            chmod -R 700 $pyenv_path/pyenv/bin
            is_package=$($python_bin -m psutil 2>&1|grep package)
            if [ "$is_package" = "" ];then
                wget -O $pyenv_path/pyenv/pip.txt $download_Url/install/pyenv/pip.txt -T 5
                $pyenv_path/pyenv/bin/pip install -U pip
                $pyenv_path/pyenv/bin/pip install -U setuptools
                $pyenv_path/pyenv/bin/pip install -r $pyenv_path/pyenv/pip.txt
            fi
            source $pyenv_path/pyenv/bin/activate
            return
        else
            rm -rf $pyenv_path/pyenv
        fi
    fi
    py_version="3.7.8"
    mkdir -p $pyenv_path
    os_type='el'
    os_version='7'
    is_export_openssl=0
    Get_Versions
    Centos6_Openssl
    Other_Openssl
    echo "OS: $os_type - $os_version"
    is_aarch64=$(uname -a|grep aarch64)
    if [ "$is_aarch64" != "" ];then
        os_version="aarch64"
    fi
    if [ -f "/www/server/panel/pymake.pl" ];then
        os_version=""
        rm -f /www/server/panel/pymake.pl
    fi
    if [ "${os_version}" != "" ];then
        pyenv_file="/www/pyenv.tar.gz"
        wget -O $pyenv_file $download_Url/install/pyenv/pyenv-${os_type}${os_version}-x${is64bit}.tar.gz -T 10
        tmp_size=$(du -b $pyenv_file|awk '{print $1}')
        if [ $tmp_size -lt 703460 ];then
            rm -f $pyenv_file
            echo "ERROR: Download python env fielded."
        else
            echo "Install python env..."
            tar zxvf $pyenv_file -C $pyenv_path/ > /dev/null
            chmod -R 700 $pyenv_path/pyenv/bin
            if [ ! -f $pyenv_path/pyenv/bin/python ];then
                rm -f $pyenv_file
                Red_Error "ERROR: Install python env fielded."
            fi
            is_err=$($pyenv_path/pyenv/bin/python3.7 -V 2>&1|grep 'Could not find platform')
            if [ "$is_err" = "" ];then
                rm -f $pyenv_file
                ln -sf $pyenv_path/pyenv/bin/pip3.7 /usr/bin/btpip
                ln -sf $pyenv_path/pyenv/bin/python3.7 /usr/bin/btpython
                source $pyenv_path/pyenv/bin/activate
                return
            else
                rm -f $pyenv_file
                rm -rf $pyenv_path/pyenv
            fi
        fi
    fi
    if [ -f /usr/local/openssl/lib/libssl.so ];then
        export LDFLAGS="-L/usr/local/openssl/lib"
        export CPPFLAGS="-I/usr/local/openssl/include"
        export PKG_CONFIG_PATH="/usr/local/openssl/lib/pkgconfig"
        echo "export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/openssl/lib" >> /etc/profile
        source /etc/profile
    fi
    cd /www
    python_src='/www/python_src.tar.xz'
    python_src_path="/www/Python-${py_version}"
    wget -O $python_src $download_Url/src/Python-${py_version}.tar.xz -T 5
    tmp_size=$(du -b $python_src|awk '{print $1}')
    if [ $tmp_size -lt 10703460 ];then
        rm -f $python_src
        Red_Error "ERROR: Download python source code fielded."
    fi
    tar xvf $python_src
    rm -f $python_src
    cd $python_src_path
    ./configure --prefix=$pyenv_path/pyenv
    make -j$cpu_cpunt
    make install
    if [ ! -f $pyenv_path/pyenv/bin/python3.7 ];then
        rm -rf $python_src_path
        Red_Error "ERROR: Make python env fielded."
    fi
    cd ~
    rm -rf $python_src_path
    wget -O $pyenv_path/pyenv/bin/activate $download_Url/install/pyenv/activate.panel -T 5
    wget -O $pyenv_path/pyenv/pip.txt $download_Url/install/pyenv/pip-3.7.8.txt -T 5
    ln -sf $pyenv_path/pyenv/bin/pip3.7 $pyenv_path/pyenv/bin/pip
    ln -sf $pyenv_path/pyenv/bin/python3.7 $pyenv_path/pyenv/bin/python
    ln -sf $pyenv_path/pyenv/bin/pip3.7 /usr/bin/btpip
    ln -sf $pyenv_path/pyenv/bin/python3.7 /usr/bin/btpython
    chmod -R 700 $pyenv_path/pyenv/bin
    $pyenv_path/pyenv/bin/pip install -U pip
    $pyenv_path/pyenv/bin/pip install -U setuptools
    $pyenv_path/pyenv/bin/pip install -U wheel==0.34.2
    $pyenv_path/pyenv/bin/pip install -r $pyenv_path/pyenv/pip.txt
    source $pyenv_path/pyenv/bin/activate
}
Other_Openssl(){
    openssl_version=$(openssl version|grep -Eo '[0-9]\.[0-9]\.[0-9]')
    if [ "$openssl_version" = '1.0.1' ] || [ "$openssl_version" = '1.0.0' ];then
        opensslVersion="1.0.2r"
        if [ ! -f "/usr/local/openssl/lib/libssl.so" ];then
            cd /www
            openssl_src_file=/www/openssl.tar.gz
            wget -O $openssl_src_file ${download_Url}/src/openssl-${opensslVersion}.tar.gz
            tmp_size=$(du -b $openssl_src_file|awk '{print $1}')
            if [ $tmp_size -lt 703460 ];then
                rm -f $openssl_src_file
                Red_Error "ERROR: Download openssl-1.0.2 source code fielded."
            fi
            tar -zxf $openssl_src_file
            rm -f $openssl_src_file
            cd openssl-${opensslVersion}
            #zlib-dynamic shared
            ./config --openssldir=/usr/local/openssl zlib-dynamic shared
            make -j${cpuCore}
            make install
            echo  "/usr/local/openssl/lib" > /etc/ld.so.conf.d/zopenssl.conf
            ldconfig
            cd ..
            rm -rf openssl-${opensslVersion}
            is_export_openssl=1
            cd ~
        fi
    fi
}
Insatll_Libressl(){
    openssl_version=$(openssl version|grep -Eo '[0-9]\.[0-9]\.[0-9]')
    if [ "$openssl_version" = '1.0.1' ] || [ "$openssl_version" = '1.0.0' ];then
        opensslVersion="3.0.2"
        cd /www
        openssl_src_file=/www/openssl.tar.gz
        wget -O $openssl_src_file ${download_Url}/install/pyenv/libressl-${opensslVersion}.tar.gz
        tmp_size=$(du -b $openssl_src_file|awk '{print $1}')
        if [ $tmp_size -lt 703460 ];then
            rm -f $openssl_src_file
            Red_Error "ERROR: Download libressl-$opensslVersion source code fielded."
        fi
        tar -zxf $openssl_src_file
        rm -f $openssl_src_file
        cd libressl-${opensslVersion}
        ./config â€“prefix=/usr/local/lib
        make -j${cpuCore}
        make install
        ldconfig
        ldconfig -v
        cd ..
        rm -rf libressl-${opensslVersion}
        is_export_openssl=1
        cd ~
    fi
}
Centos6_Openssl(){
    if [ "$os_type" != 'el' ];then
        return
    fi
    if [ "$os_version" != '6' ];then
        return
    fi
    echo 'Centos6 install openssl-1.0.2...'
    openssl_rpm_file="/www/openssl.rpm"
    wget -O $openssl_rpm_file $download_Url/rpm/centos6/${is64bit}/bt-openssl102.rpm -T 10
    tmp_size=$(du -b $openssl_rpm_file|awk '{print $1}')
    if [ $tmp_size -lt 102400 ];then
        rm -f $openssl_rpm_file
        Red_Error "ERROR: Download python env fielded."
    fi
    rpm -ivh $openssl_rpm_file
    rm -f $openssl_rpm_file
    is_export_openssl=1
}
Get_Versions(){
    redhat_version_file="/etc/redhat-release"
    deb_version_file="/etc/issue"
    if [ -f $redhat_version_file ];then
        os_type='el'
        is_aliyunos=$(cat $redhat_version_file|grep Aliyun)
        if [ "$is_aliyunos" != "" ];then
            return
        fi
        os_version=$(cat $redhat_version_file|grep CentOS|grep -Eo '([0-9]+\.)+[0-9]+'|grep -Eo '^[0-9]')
        if [ "${os_version}" = "5" ];then
            os_version=""
        fi
    else
        os_type='ubuntu'
        os_version=$(cat $deb_version_file|grep Ubuntu|grep -Eo '([0-9]+\.)+[0-9]+'|grep -Eo '^[0-9]+')
        if [ "${os_version}" = "" ];then
            os_type='debian'
            os_version=$(cat $deb_version_file|grep Debian|grep -Eo '([0-9]+\.)+[0-9]+'|grep -Eo '[0-9]+')
            if [ "${os_version}" = "" ];then
                os_version=$(cat $deb_version_file|grep Debian|grep -Eo '[0-9]+')
            fi
            if [ "${os_version}" = "8" ];then
                os_version=""
            fi
            if [ "${is64bit}" = '32' ];then
                os_version=""
            fi
        else
            if [ "$os_version" = "14" ];then
                os_version=""
            fi
            if [ "$os_version" = "12" ];then
                os_version=""
            fi
            if [ "$os_version" = "19" ];then
                os_version=""
            fi
        fi
    fi
}
Set_Bt_Panel(){
    password=$(cat /dev/urandom | head -n 16 | md5sum | head -c 8)
    sleep 1
    admin_auth="/www/server/panel/data/admin_path.pl"
    if [ ! -f ${admin_auth} ];then
        auth_path=$(cat /dev/urandom | head -n 16 | md5sum | head -c 8)
        echo "/${auth_path}" > ${admin_auth}
    fi
    auth_path=$(cat ${admin_auth})
    cd ${setup_path}/server/panel/
    /etc/init.d/bt start
    $python_bin -m py_compile tools.py
    $python_bin tools.py username
    username=$($python_bin tools.py panel ${password})
    cd ~
    echo "${password}" > ${setup_path}/server/panel/default.pl
    chmod 600 ${setup_path}/server/panel/default.pl
    sleep 3
    /etc/init.d/bt restart
    sleep 3
    isStart=$(ps aux |grep 'BT-Panel'|grep -v grep|awk '{print $2}')
    LOCAL_CURL=$(curl 127.0.0.1:8888/login 2>&1 |grep -i html)
    if [ -z "${isStart}" ] && [ -z "${LOCAL_CURL}" ];then
        /etc/init.d/bt 22
        cd /www/server/panel/pyenv/bin
        touch t.pl
        ls -al python3.7 python
        lsattr python3.7 python
        Red_Error "ERROR: The BT-Panel service startup failed."
    fi
}
Set_Firewall(){
    sshPort=$(cat /etc/ssh/sshd_config | grep 'Port '|awk '{print $2}')
    if [ "${PM}" = "apt-get" ]; then
        apt-get install -y ufw
        if [ -f "/usr/sbin/ufw" ];then
            ufw allow 20/tcp
            ufw allow 21/tcp
            ufw allow 22/tcp
            ufw allow 80/tcp
            ufw allow 888/tcp
            ufw allow ${panelPort}/tcp
            ufw allow ${sshPort}/tcp
            ufw allow 39000:40000/tcp
            ufw_status=`ufw status`
            echo y|ufw enable
            ufw default deny
            ufw reload
        fi
    else
        if [ -f "/etc/init.d/iptables" ];then
            iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 20 -j ACCEPT
            iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 21 -j ACCEPT
            iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
            iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT
            iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport ${panelPort} -j ACCEPT
            iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport ${sshPort} -j ACCEPT
            iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 39000:40000 -j ACCEPT
            #iptables -I INPUT -p tcp -m state --state NEW -m udp --dport 39000:40000 -j ACCEPT
            iptables -A INPUT -p icmp --icmp-type any -j ACCEPT
            iptables -A INPUT -s localhost -d localhost -j ACCEPT
            iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
            iptables -P INPUT DROP
            service iptables save
            sed -i "s#IPTABLES_MODULES=\"\"#IPTABLES_MODULES=\"ip_conntrack_netbios_ns ip_conntrack_ftp ip_nat_ftp\"#" /etc/sysconfig/iptables-config
            iptables_status=$(service iptables status | grep 'not running')
            if [ "${iptables_status}" == '' ];then
                service iptables restart
            fi
        else
            AliyunCheck=$(cat /etc/redhat-release|grep "Aliyun Linux")
            [ "${AliyunCheck}" ] && return
            yum install firewalld -y
            [ "${Centos8Check}" ] && yum reinstall python3-six -y
            systemctl enable firewalld
            systemctl start firewalld
            firewall-cmd --set-default-zone=public > /dev/null 2>&1
            firewall-cmd --permanent --zone=public --add-port=20/tcp > /dev/null 2>&1
            firewall-cmd --permanent --zone=public --add-port=21/tcp > /dev/null 2>&1
            firewall-cmd --permanent --zone=public --add-port=22/tcp > /dev/null 2>&1
            firewall-cmd --permanent --zone=public --add-port=80/tcp > /dev/null 2>&1
            firewall-cmd --permanent --zone=public --add-port=${panelPort}/tcp > /dev/null 2>&1
            firewall-cmd --permanent --zone=public --add-port=${sshPort}/tcp > /dev/null 2>&1
            firewall-cmd --permanent --zone=public --add-port=39000-40000/tcp > /dev/null 2>&1
            #firewall-cmd --permanent --zone=public --add-port=39000-40000/udp > /dev/null 2>&1
            firewall-cmd --reload
        fi
    fi
}
Get_Ip_Address(){
    getIpAddress=""
    getIpAddress=$(curl -sS --connect-timeout 10 -m 60 https://v7.hostcli.com/Api/getIpAddress)
    if [ -z "${getIpAddress}" ] || [ "${getIpAddress}" = "0.0.0.0" ]; then
        isHosts=$(cat /etc/hosts|grep 'v7.hostcli.com')
        if [ -z "${isHosts}" ];then
            #echo "" >> /etc/hosts
            #echo "103.224.251.67 v7.hostcli.com" >> /etc/hosts
            getIpAddress=$(curl -sS --connect-timeout 10 -m 60 https://v7.hostcli.com/Api/getIpAddress)
            if [ -z "${getIpAddress}" ];then
                sed -i "/v7.hostcli.com/d" /etc/hosts
            fi
        fi
    fi
    ipv4Check=$($python_bin -c "import re; print(re.match('^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$','${getIpAddress}'))")
    if [ "${ipv4Check}" == "None" ];then
        ipv6Address=$(echo ${getIpAddress}|tr -d "[]")
        ipv6Check=$($python_bin -c "import re; print(re.match('^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}$','${ipv6Address}'))")
        if [ "${ipv6Check}" == "None" ]; then
            getIpAddress="SERVER_IP"
        else
            echo "True" > ${setup_path}/server/panel/data/ipv6.pl
            sleep 1
            /etc/init.d/bt restart
        fi
    fi
    if [ "${getIpAddress}" != "SERVER_IP" ];then
        echo "${getIpAddress}" > ${setup_path}/server/panel/data/iplist.txt
    fi
    LOCAL_IP=$(ip addr | grep -E -o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | grep -E -v "^127\.|^255\.|^0\." | head -n 1)
}
Setup_Count(){
    curl -sS --connect-timeout 10 -m 60 https://v7.hostcli.com/Api/SetupCount?type=Linux\&o=$1 > /dev/null 2>&1
    if [ "$1" != "" ];then
        echo $1 > /www/server/panel/data/o.pl
        cd /www/server/panel
        $python_bin tools.py o
    fi
    echo /www > /var/bt_setupPath.conf
}
Install_Main(){
    startTime=`date +%s`
    Lock_Clear
    System_Check
    Get_Pack_Manager
    get_node_url
    MEM_TOTAL=$(free -g|grep Mem|awk '{print $2}')
    if [ "${MEM_TOTAL}" -le "1" ];then
        Auto_Swap
    fi
    if [ "${PM}" = "yum" ]; then
        Install_RPM_Pack
    elif [ "${PM}" = "apt-get" ]; then
        Install_Deb_Pack
    fi
    Install_Python_Lib
    Install_Bt
    Set_Bt_Panel
    Service_Add
    Set_Firewall
    Get_Ip_Address
    Setup_Count ${IDC_CODE}
}
echo "
+----------------------------------------------------------------------
| hostcli.com FOR CentOS/Ubuntu/Debian
+----------------------------------------------------------------------
| Copyright Â© 2015-2099 HostCli(http://v7.hostcli.com) All rights reserved.
+----------------------------------------------------------------------
| The WebPanel URL will be http://SERVER_IP:8888 when installed.
+----------------------------------------------------------------------
"
while [ "$go" != 'y' ] && [ "$go" != 'n' ]
do
    read -p "Do you want to install Bt-Panel to the $setup_path directory now?(y/n): " go;
done
if [ "$go" == 'n' ];then
    exit;
fi
Install_Main
echo > /www/server/panel/data/bind.pl
echo -e "=================================================================="
echo -e "\033[32mCongratulations! Installed successfully!\033[0m"
echo -e "=================================================================="
echo  "外网面板地址: http://${getIpAddress}:${panelPort}${auth_path}"
echo  "内网面板地址: http://${LOCAL_IP}:${panelPort}${auth_path}"
echo -e "username: $username"
echo -e "password: $password"
echo -e "\033[33mIf you cannot access the panel,\033[0m"
echo -e "\033[33mrelease the following panel port [${panelPort}] in the security group\033[0m"
echo -e "\033[33m若无法访问面板,请检查防火墙/安全组是否有放行面板[${panelPort}]端口\033[0m"
echo -e "=================================================================="
endTime=`date +%s`
((outTime=($endTime-$startTime)/60))
echo -e "Time consumed:\033[32m $outTime \033[0mMinute!"
java_gaga.com.conf
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,57 @@
server
{
    listen 80;
    server_name gaga.com aa.com bb.com;
    index index.html index.htm default.htm default.html;
    root /www/wwwroot/gaga.com;
    #SSL-START SSL相关配置
    #error_page 404/404.html;
    #SSL-END
    #ERROR-PAGE-START  é”™è¯¯é¡µç›¸å…³é…ç½®
    #error_page 404 /404.html;
    #error_page 502 /502.html;
    #ERROR-PAGE-END
    #REWRITE-START ä¼ªé™æ€ç›¸å…³é…ç½®
    include /www/server/panel/vhost/rewrite/java_gaga.com.conf;
    #REWRITE-END
    #禁止访问的文件或目录
    location ~ ^/(\.user.ini|\.htaccess|\.git|\.svn|\.project|LICENSE|README.md|package.json|package-lock.json|\.env|node_modules) {
        return 404;
    }
    #一键申请SSL证书验证目录相关设置
    location /.well-known/ {
        root /www/wwwroot/java_node_ssl;
    }
    # HTTP反向代理相关配置开始 >>>
    location ~ /purge(/.*) {
        proxy_cache_purge cache_one gaga.com$request_uri$is_args$args;
    }
    location / {
        proxy_pass http://127.0.0.1:8231;
        proxy_set_header Host gaga.com:$server_port;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header REMOTE-HOST $remote_addr;
        add_header X-Cache $upstream_cache_status;
        proxy_connect_timeout 30s;
        proxy_read_timeout 86400s;
        proxy_send_timeout 30s;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
    # HTTP反向代理相关配置结束 <<<
    access_log  /www/wwwlogs/gaga.com.log;
    error_log  /www/wwwlogs/gaga.com.error.log;
}
java_wa.cn.conf
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,57 @@
server
{
    listen 80;
    server_name wa.cn;
    index index.html index.htm default.htm default.html;
    root /www/wwwroot/wa.cn;
    #SSL-START SSL相关配置
    #error_page 404/404.html;
    #SSL-END
    #ERROR-PAGE-START  é”™è¯¯é¡µç›¸å…³é…ç½®
    #error_page 404 /404.html;
    #error_page 502 /502.html;
    #ERROR-PAGE-END
    #REWRITE-START ä¼ªé™æ€ç›¸å…³é…ç½®
    include /www/server/panel/vhost/rewrite/java_wa.cn.conf;
    #REWRITE-END
    #禁止访问的文件或目录
    location ~ ^/(\.user.ini|\.htaccess|\.git|\.svn|\.project|LICENSE|README.md|package.json|package-lock.json|\.env|node_modules) {
        return 404;
    }
    #一键申请SSL证书验证目录相关设置
    location /.well-known/ {
        root /www/wwwroot/java_node_ssl;
    }
    # HTTP反向代理相关配置开始 >>>
    location ~ /purge(/.*) {
        proxy_cache_purge cache_one wa.cn$request_uri$is_args$args;
    }
    location / {
        proxy_pass http://127.0.0.1:99;
        proxy_set_header Host wa.cn:$server_port;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header REMOTE-HOST $remote_addr;
        add_header X-Cache $upstream_cache_status;
        proxy_connect_timeout 30s;
        proxy_read_timeout 86400s;
        proxy_send_timeout 30s;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
    # HTTP反向代理相关配置结束 <<<
    access_log  /www/wwwlogs/wa.cn.log;
    error_log  /www/wwwlogs/wa.cn.error.log;
}
manager.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
  Licensed to the Apache Software Foundation (ASF) under one or more
  contributor license agreements.  See the NOTICE file distributed with
  this work for additional information regarding copyright ownership.
  The ASF licenses this file to You under the Apache License, Version 2.0
  (the "License"); you may not use this file except in compliance with
  the License.  You may obtain a copy of the License at
      http://www.apache.org/licenses/LICENSE-2.0
  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
-->
<!--
    Context configuration file for the Tomcat Manager Web App
-->
<Context docBase="${catalina.home}/webapps/manager"
         privileged="true" antiResourceLocking="false" antiJARLocking="false">
  <Valve className="org.apache.catalina.valves.RemoteAddrValve"
         allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" />
  <Manager sessionAttributeValueClassNameFilter="java\.lang\.(?:Boolean|Integer|Long|Number|String)|org\.apache\.catalina\.filters\.CsrfPreventionFilter\$LruCache(?:\$1)?|java\.util\.(?:Linked)?HashMap"/>
</Context>
nginx.conf
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,164 @@
#user  nobody;
worker_processes  1;
#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;
#pid        logs/nginx.pid;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    server_tokens        off;
    sendfile        on;
    #tcp_nopush     on;
    client_max_body_size 5m;
    #keepalive_timeout  0;
    keepalive_timeout  65;
    #gzip  on;
server {
        listen 80 default_server;
        listen 8888 default_server;
        server_name  _;
        return 444;
    }
    server {
        listen       8888;
        server_name  oa.shiyi.tv oa.brawin.cn;
        #强制转HTTPS
        #rewrite ^(.*)$  https://$host$1 permanent;
        #强制域名访问
#   if ($host != oa.shiyi.tv) {
#            return 403;
#           }
        #charset koi8-r;
        #access_log  logs/host.access.log  main;
        #禁止Scrapy等爬虫工具的抓取,如果用到百度收录,这里就要注释掉
        if ($http_user_agent ~* "Scrapy|Sogou web spider|Baiduspider") {
            return 403;
            }
        #禁止指定UA及UA为空的访问
        if ($http_user_agent ~ "FeedDemon|JikeSpider|Indy Library|Alexa Toolbar|AskTbFXTV|AhrefsBot|CrawlDaddy|CoolpadWebkit|Java|Feedly|UniversalFeedParser|ApacheBench|Microsoft URL Control|Swiftbot|ZmEu|oBot|jaunty|Python-urllib|lightDeckReports Bot|YYSpider|DigExt|YisouSpider|HttpClient|MJ12bot|heritrix|EasouSpider|LinkpadBot|Ezooms|^$"){
            return 403;
            }
        #禁止非GET|HEAD|POST方式的抓取,此处可能会导致网页打不开
        #if ($request_method !~ A(GET|HEAD|POST)$) {
        #    return 403;
        #   }
        #针对特殊的user_agent的访问
        if ($http_user_agent ~ "Mozilla/4.0\ \(compatible;\ MSIE\ 6.;\ Windows\ NT\ 5.1;\ SV1;\ .NET\ CLR\ 1.1.4322;\ .NET\ CLR\ 2.0.50727\)") {
            return 404;
        }
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        #proxy_set_header Host $host;
        proxy_set_header Upgrade-Insecure-Requests 1;
        proxy_set_header X-Forwarded-Proto https;
        proxy_read_timeout 300;
        location / {
            root   html;
            index  index.html index.htm;
        proxy_pass http://192.168.1.91:80;
            proxy_redirect off;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
        server {
        listen       80;
        server_name  oa.shiyi.tv oa.brawin.cn;
        #强制转HTTPS
        #rewrite ^(.*)$  https://$host$1 permanent;
        #强制域名访问
#   if ($host != oa.shiyi.tv) {
#            return 403;
#           }
        #charset koi8-r;
        #access_log  logs/host.access.log  main;
        #禁止Scrapy等爬虫工具的抓取,如果用到百度收录,这里就要注释掉
        if ($http_user_agent ~* "Scrapy|Sogou web spider|Baiduspider") {
            return 403;
            }
        #禁止指定UA及UA为空的访问
        if ($http_user_agent ~ "FeedDemon|JikeSpider|Indy Library|Alexa Toolbar|AskTbFXTV|AhrefsBot|CrawlDaddy|CoolpadWebkit|Java|Feedly|UniversalFeedParser|ApacheBench|Microsoft URL Control|Swiftbot|ZmEu|oBot|jaunty|Python-urllib|lightDeckReports Bot|YYSpider|DigExt|YisouSpider|HttpClient|MJ12bot|heritrix|EasouSpider|LinkpadBot|Ezooms|^$"){
            return 403;
            }
        #禁止非GET|HEAD|POST方式的抓取,此处可能会导致网页打不开
        #if ($request_method !~ A(GET|HEAD|POST)$) {
        #    return 403;
        #   }
        #针对特殊的user_agent的访问
        if ($http_user_agent ~ "Mozilla/4.0\ \(compatible;\ MSIE\ 6.;\ Windows\ NT\ 5.1;\ SV1;\ .NET\ CLR\ 1.1.4322;\ .NET\ CLR\ 2.0.50727\)") {
            return 404;
        }
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        #proxy_set_header Host $host;
        proxy_set_header Upgrade-Insecure-Requests 1;
        proxy_set_header X-Forwarded-Proto https;
        proxy_read_timeout 300;
        location / {
            root   html;
            index  index.html index.htm;
            proxy_pass http://192.168.1.91:80;
            proxy_redirect off;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
}
nn.cn.conf
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,51 @@
server
{
    listen 80;
    server_name nn.cn 192.168.1.233;
    index index.php index.html index.htm default.php default.htm default.html;
    root /www/wwwroot/nn.cn;
    #SSL-START SSL相关配置,请勿删除或修改下一行带注释的404规则
    #error_page 404/404.html;
    #SSL-END
    #ERROR-PAGE-START  é”™è¯¯é¡µé…ç½®ï¼Œå¯ä»¥æ³¨é‡Šã€åˆ é™¤æˆ–修改
    #error_page 404 /404.html;
    #error_page 502 /502.html;
    #ERROR-PAGE-END
    #PHP-INFO-START  PHP引用配置,可以注释或修改
    include enable-php-00.conf;
    #PHP-INFO-END
    #REWRITE-START URL重写规则引用,修改后将导致面板设置的伪静态规则失效
    include /www/server/panel/vhost/rewrite/nn.cn.conf;
    #REWRITE-END
    #禁止访问的文件或目录
    location ~ ^/(\.user.ini|\.htaccess|\.git|\.svn|\.project|LICENSE|README.md)
    {
        return 404;
    }
    #一键申请SSL证书验证目录相关设置
    location ~ \.well-known{
        allow all;
    }
    location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
    {
        expires      30d;
        error_log /dev/null;
        access_log /dev/null;
    }
    location ~ .*\.(js|css)?$
    {
        expires      12h;
        error_log /dev/null;
        access_log /dev/null;
    }
    access_log  /www/wwwlogs/nn.cn.log;
    error_log  /www/wwwlogs/nn.cn.error.log;
}
phpfpm_status.conf
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,69 @@
server {
    listen 80;
    server_name 127.0.0.1;
    allow 127.0.0.1;
    location /nginx_status {
        stub_status on;
        access_log off;
    }
    location /phpfpm_52_status {
        fastcgi_pass unix:/tmp/php-cgi-52.sock;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $fastcgi_script_name;
    }
    location /phpfpm_53_status {
        fastcgi_pass unix:/tmp/php-cgi-53.sock;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $fastcgi_script_name;
    }
    location /phpfpm_54_status {
        fastcgi_pass unix:/tmp/php-cgi-54.sock;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $fastcgi_script_name;
    }
    location /phpfpm_55_status {
        fastcgi_pass unix:/tmp/php-cgi-55.sock;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $fastcgi_script_name;
    }
    location /phpfpm_56_status {
        fastcgi_pass unix:/tmp/php-cgi-56.sock;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $fastcgi_script_name;
    }
    location /phpfpm_70_status {
        fastcgi_pass unix:/tmp/php-cgi-70.sock;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $fastcgi_script_name;
    }
    location /phpfpm_71_status {
        fastcgi_pass unix:/tmp/php-cgi-71.sock;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $fastcgi_script_name;
    }
    location /phpfpm_72_status {
        fastcgi_pass unix:/tmp/php-cgi-72.sock;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $fastcgi_script_name;
    }
    location /phpfpm_73_status {
        fastcgi_pass unix:/tmp/php-cgi-73.sock;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $fastcgi_script_name;
    }
    location /phpfpm_74_status {
        fastcgi_pass unix:/tmp/php-cgi-74.sock;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $fastcgi_script_name;
    }
    location /phpfpm_80_status {
        fastcgi_pass unix:/tmp/php-cgi-80.sock;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $fastcgi_script_name;
    }
    location /phpfpm_81_status {
        fastcgi_pass unix:/tmp/php-cgi-81.sock;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $fastcgi_script_name;
    }
}
server.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,24 @@
<Server port="5712" shutdown="SHUTDOWN">
  <Listener className="org.apache.catalina.startup.VersionLoggerListener" />
<Listener SSLEngine="on" className="org.apache.catalina.core.AprLifecycleListener" />
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
<GlobalNamingResources>
    <Resource auth="Container" description="User database that can be updated and saved" factory="org.apache.catalina.users.MemoryUserDatabaseFactory" name="UserDatabase" pathname="conf/tomcat-users.xml" type="org.apache.catalina.UserDatabase" />
  </GlobalNamingResources>
<Service name="Catalina">
    <Connector connectionTimeout="20000" port="99" protocol="HTTP/1.1" redirectPort="8490" />
  <Engine defaultHost="localhost" name="Catalina">
      <Realm className="org.apache.catalina.realm.LockOutRealm">
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase" />
      </Realm>
    <Host appBase="webapps" autoDeploy="true" name="localhost" unpackWARs="true">
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" pattern="%h %l %u %t &quot;%r&quot; %s %b" prefix="localhost_access_log" suffix=".txt" />
      </Host>
    <Host autoDeploy="true" name="wa.cn" unpackWARs="true" xmlNamespaceAware="false" xmlValidation="false">
        <Context crossContext="true" docBase="/www/wwwroot/wa.cn" path="" reloadable="true" />
      </Host>
    </Engine>
  </Service>
</Server>
web.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,161 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!--
  Licensed to the Apache Software Foundation (ASF) under one or more
  contributor license agreements.  See the NOTICE file distributed with
  this work for additional information regarding copyright ownership.
  The ASF licenses this file to You under the Apache License, Version 2.0
  (the "License"); you may not use this file except in compliance with
  the License.  You may obtain a copy of the License at
      http://www.apache.org/licenses/LICENSE-2.0
  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
-->
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                      http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
  version="3.0"
  metadata-complete="true">
  <display-name>Tomcat Host Manager Application</display-name>
  <description>
    A scriptable host management web application for the Tomcat Web Server;
    Manager lets you view, create and remove virtual hosts.
  </description>
  <servlet>
    <servlet-name>HostManager</servlet-name>
    <servlet-class>org.apache.catalina.manager.host.HostManagerServlet</servlet-class>
    <init-param>
      <param-name>debug</param-name>
      <param-value>2</param-value>
    </init-param>
  </servlet>
  <servlet>
    <servlet-name>HTMLHostManager</servlet-name>
    <servlet-class>org.apache.catalina.manager.host.HTMLHostManagerServlet</servlet-class>
    <init-param>
      <param-name>debug</param-name>
      <param-value>2</param-value>
    </init-param>
  </servlet>
  <filter>
    <filter-name>SetCharacterEncoding</filter-name>
    <filter-class>org.apache.catalina.filters.SetCharacterEncodingFilter</filter-class>
    <init-param>
      <param-name>encoding</param-name>
      <param-value>UTF-8</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>SetCharacterEncoding</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  <filter>
    <filter-name>CSRF</filter-name>
    <filter-class>org.apache.catalina.filters.CsrfPreventionFilter</filter-class>
    <init-param>
      <param-name>entryPoints</param-name>
      <param-value>/html,/html/,/html/list,/index.jsp</param-value>
    </init-param>
  </filter>
  <!-- Configured to set X-FRAME-OPTIONS. Disable HSTS in case it interferes -->
  <!-- with an existing setting. Keep X-Content-Type-Options and             -->
  <!-- X-XSS-Protection as they are page specific.                           -->
  <filter>
    <filter-name>HTTP header security filter</filter-name>
    <filter-class>org.apache.catalina.filters.HttpHeaderSecurityFilter</filter-class>
    <init-param>
      <param-name>hstsEnabled</param-name>
      <param-value>false</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>CSRF</filter-name>
    <servlet-name>HTMLHostManager</servlet-name>
  </filter-mapping>
  <filter-mapping>
    <filter-name>HTTP header security filter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  <!-- Define the Manager Servlet Mapping -->
  <servlet-mapping>
    <servlet-name>HostManager</servlet-name>
    <url-pattern>/text/*</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>HTMLHostManager</servlet-name>
    <url-pattern>/html/*</url-pattern>
  </servlet-mapping>
  <!-- Define a Security Constraint on this Application -->
  <security-constraint>
    <web-resource-collection>
      <web-resource-name>HostManager commands</web-resource-name>
      <url-pattern>/text/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
       <!-- NOTE:  This role is not present in the default users file -->
       <role-name>admin-script</role-name>
    </auth-constraint>
  </security-constraint>
  <security-constraint>
    <web-resource-collection>
      <web-resource-name>HTMLHostManager commands</web-resource-name>
      <url-pattern>/html/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
       <!-- NOTE:  This role is not present in the default users file -->
       <role-name>admin-gui</role-name>
    </auth-constraint>
  </security-constraint>
  <!-- Define the Login Configuration for this Application -->
  <login-config>
    <auth-method>BASIC</auth-method>
    <realm-name>Tomcat Host Manager Application</realm-name>
  </login-config>
  <!-- Security roles referenced by this web application -->
  <security-role>
    <description>
      The role that is required to log in to the Host Manager Application HTML
      interface
    </description>
    <role-name>admin-gui</role-name>
  </security-role>
  <security-role>
    <description>
      The role that is required to log in to the Host Manager Application text
      interface
    </description>
    <role-name>admin-script</role-name>
  </security-role>
  <error-page>
    <error-code>401</error-code>
    <location>/WEB-INF/jsp/401.jsp</location>
  </error-page>
  <error-page>
    <error-code>403</error-code>
    <location>/WEB-INF/jsp/403.jsp</location>
  </error-page>
  <error-page>
    <error-code>404</error-code>
    <location>/WEB-INF/jsp/404.jsp</location>
  </error-page>
</web-app>
¿ª¹Ø»úºÐ×Ó²âÊÔ±¨¸æ.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,47 @@
# å¼€å…³æœºç›’子测试报告
## æµ‹è¯•素材
无
## æµ‹è¯•目的
确认18个开关机盒子是否正常开关机
## æµ‹è¯•æ—¶é—´
第三批:2021.12.24 - 2021.12.30
## ç»ˆç«¯MAC地址
01:0025E1033D53
02:0025E1033CF6
03:0025E1033D00
04:0025E1033D02
05:0025E1033CF3
06:0025E1033D72
07:0025E1033D66
08:0025E1033A8B
09:0025E1033CF2
10:0025E1033D5B
11:0025E1033D6F
12:0025E1033A61
13:0025E1033D4A
14:0025E1033D68
15:0025E1033D67
16:0025E1033CE4
17:0025E1033D47
18:0025E1033DA1
## æµ‹è¯•例
将18台开关机盒子时间设置统一,统一勾选关机时段内上电保持开机
周一至周五:
08:15 â€“ 09:00
09:10 â€“ 10:00
10:10 â€“ 12:00
12:10 â€“ 13:00
13:10 â€“ 18:00
周六:全天开
周日:全天关
## æµ‹è¯•结果
17台开关机盒子在规定的时间正常开关机
1台不良
## ä¸è‰¯åŽŸå› åˆ†æž
Mac地址为0025E1033CF2 çº¿æŽ¥é”™äº†ï¼Œä»¥ä¸‹æ˜¯å›¾ç‰‡ï¼š
ºÚ±¦Ëþinstall_6.0.sh
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,738 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
LANG=en_US.UTF-8
if [ $(whoami) != "root" ];then
    echo "请使用root权限执行宝塔安装命令!"
    exit 1;
fi
is64bit=$(getconf LONG_BIT)
if [ "${is64bit}" != '64' ];then
    Red_Error "抱歉, å½“前面板版本不支持32位系统, è¯·ä½¿ç”¨64位系统或安装宝塔5.9!";
fi
cd ~
setup_path="/www"
python_bin=$setup_path/server/panel/pyenv/bin/python
cpu_cpunt=$(cat /proc/cpuinfo|grep processor|wc -l)
if [ "$1" ];then
    IDC_CODE=$1
fi
GetSysInfo(){
    if [ -s "/etc/redhat-release" ];then
        SYS_VERSION=$(cat /etc/redhat-release)
    elif [ -s "/etc/issue" ]; then
        SYS_VERSION=$(cat /etc/issue)
    fi
    SYS_INFO=$(uname -a)
    SYS_BIT=$(getconf LONG_BIT)
    MEM_TOTAL=$(free -m|grep Mem|awk '{print $2}')
    CPU_INFO=$(getconf _NPROCESSORS_ONLN)
    echo -e ${SYS_VERSION}
    echo -e Bit:${SYS_BIT} Mem:${MEM_TOTAL}M Core:${CPU_INFO}
    echo -e ${SYS_INFO}
    echo -e "请截图以上报错信息发帖至论坛v7.hostcli.com/bbs求助"
}
Red_Error(){
    echo '=================================================';
    printf '\033[1;31;40m%b\033[0m\n' "$1";
    GetSysInfo
    exit 1;
}
Lock_Clear(){
    if [ -f "/etc/bt_crack.pl" ];then
        chattr -R -ia /www
        chattr -ia /etc/init.d/bt
        \cp -rpa /www/backup/panel/vhost/* /www/server/panel/vhost/
        mv /www/server/panel/BTPanel/__init__.bak /www/server/panel/BTPanel/__init__.py
        rm -f /etc/bt_crack.pl
    fi
}
Install_Check(){
    if [ "${INSTALL_FORCE}" ];then
        return
    fi
    echo -e "----------------------------------------------------"
    echo -e "检查已有其他Web/mysql环境,安装宝塔可能影响现有站点及数据"
    echo -e "Web/mysql service is alreday installed,Can't install panel"
    echo -e "----------------------------------------------------"
    echo -e "已知风险/Enter yes to force installation"
    read -p "输入yes强制安装: " yes;
    if [ "$yes" != "yes" ];then
        echo -e "------------"
        echo "取消安装"
        exit;
    fi
    INSTALL_FORCE="true"
}
System_Check(){
    MYSQLD_CHECK=$(ps -ef |grep mysqld|grep -v grep|grep -v /www/server/mysql)
    PHP_CHECK=$(ps -ef|grep php-fpm|grep master|grep -v /www/server/php)
    NGINX_CHECK=$(ps -ef|grep nginx|grep master|grep -v /www/server/nginx)
    HTTPD_CHECK=$(ps -ef |grep -E 'httpd|apache'|grep -v /www/server/apache|grep -v grep)
    if [ "${PHP_CHECK}" ] || [ "${MYSQLD_CHECK}" ] || [ "${NGINX_CHECK}" ] || [ "${HTTPD_CHECK}" ];then
        Install_Check
    fi
}
Get_Pack_Manager(){
    if [ -f "/usr/bin/yum" ] && [ -d "/etc/yum.repos.d" ]; then
        PM="yum"
    elif [ -f "/usr/bin/apt-get" ] && [ -f "/usr/bin/dpkg" ]; then
        PM="apt-get"
    fi
}
Auto_Swap()
{
    swap=$(free |grep Swap|awk '{print $2}')
    if [ "${swap}" -gt 1 ];then
        echo "Swap total sizse: $swap";
        return;
    fi
    if [ ! -d /www ];then
        mkdir /www
    fi
    swapFile="/www/swap"
    dd if=/dev/zero of=$swapFile bs=1M count=1025
    mkswap -f $swapFile
    swapon $swapFile
    echo "$swapFile    swap    swap    defaults    0 0" >> /etc/fstab
    swap=`free |grep Swap|awk '{print $2}'`
    if [ $swap -gt 1 ];then
        echo "Swap total sizse: $swap";
        return;
    fi
    sed -i "/\/www\/swap/d" /etc/fstab
    rm -f $swapFile
}
Service_Add(){
    if [ "${PM}" == "yum" ] || [ "${PM}" == "dnf" ]; then
        chkconfig --add bt
        chkconfig --level 2345 bt on
    elif [ "${PM}" == "apt-get" ]; then
        update-rc.d bt defaults
    fi
}
get_node_url(){
    if [ ! -f /bin/curl ];then
        if [ "${PM}" = "yum" ]; then
            yum install curl -y
        elif [ "${PM}" = "apt-get" ]; then
            apt-get install curl -y
        fi
    fi
    echo '---------------------------------------------';
    echo "Selected download node...";
    download_Url='http://v7.hostcli.com';
    echo "Download node: $download_Url";
    echo '---------------------------------------------';
}
Remove_Package(){
    local PackageNmae=$1
    if [ "${PM}" == "yum" ];then
        isPackage=$(rpm -q ${PackageNmae}|grep "not installed")
        if [ -z "${isPackage}" ];then
            yum remove ${PackageNmae} -y
        fi
    elif [ "${PM}" == "apt-get" ];then
        isPackage=$(dpkg -l|grep ${PackageNmae})
        if [ "${PackageNmae}" ];then
            apt-get remove ${PackageNmae} -y
        fi
    fi
}
Install_RPM_Pack(){
    yumPath=/etc/yum.conf
    Centos8Check=$(cat /etc/redhat-release | grep ' 8.' | grep -iE 'centos|Red Hat')
    isExc=$(cat $yumPath|grep httpd)
    if [ "$isExc" = "" ];then
        echo "exclude=httpd nginx php mysql mairadb python-psutil python2-psutil" >> $yumPath
    fi
    #yumBaseUrl=$(cat /etc/yum.repos.d/CentOS-Base.repo|grep baseurl=http|cut -d '=' -f 2|cut -d '$' -f 1|head -n 1)
    #[ "${yumBaseUrl}" ] && checkYumRepo=$(curl --connect-timeout 5 --head -s -o /dev/null -w %{http_code} ${yumBaseUrl})
    #if [ "${checkYumRepo}" != "200" ];then
    #   curl -Ss --connect-timeout 3 -m 60 http://download.bt.cn/install/yumRepo_select.sh|bash
    #fi
    #尝试同步时间(从bt.cn)
    echo 'Synchronizing system time...'
    getBtTime=$(curl -sS --connect-timeout 3 -m 60 http://v7.hostcli.com/api/index/get_time)
    if [ "${getBtTime}" ];then
        date -s "$(date -d @$getBtTime +"%Y-%m-%d %H:%M:%S")"
    fi
    if [ -z "${Centos8Check}" ]; then
        yum install ntp -y
        rm -rf /etc/localtime
        ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
        #尝试同步国际时间(从ntp服务器)
        ntpdate 0.asia.pool.ntp.org
        setenforce 0
    fi
    startTime=`date +%s`
    sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config
    #yum remove -y python-requests python3-requests python-greenlet python3-greenlet
    yumPacks="libcurl-devel wget tar gcc make zip unzip openssl openssl-devel gcc libxml2 libxml2-devel libxslt* zlib zlib-devel libjpeg-devel libpng-devel libwebp libwebp-devel freetype freetype-devel lsof pcre pcre-devel vixie-cron crontabs icu libicu-devel c-ares libffi-devel bzip2-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel"
    yum install -y ${yumPacks}
    for yumPack in ${yumPacks}
    do
        rpmPack=$(rpm -q ${yumPack})
        packCheck=$(echo ${rpmPack}|grep not)
        if [ "${packCheck}" ]; then
            yum install ${yumPack} -y
        fi
    done
    if [ -f "/usr/bin/dnf" ]; then
        dnf install -y redhat-rpm-config
    fi
    ALI_OS=$(cat /etc/redhat-release |grep "Alibaba Cloud Linux release 3")
    if [ -z "${ALI_OS}" ];then
        yum install epel-release -y
    fi
}
Install_Deb_Pack(){
    ln -sf bash /bin/sh
    apt-get update -y
    apt-get install ruby -y
    apt-get install lsb-release -y
    #apt-get install ntp ntpdate -y
    #/etc/init.d/ntp stop
    #update-rc.d ntp remove
    #cat >>~/.profile<<EOF
    #TZ='Asia/Shanghai'; export TZ
    #EOF
    #rm -rf /etc/localtime
    #cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
    #echo 'Synchronizing system time...'
    #ntpdate 0.asia.pool.ntp.org
    #apt-get upgrade -y
    debPacks="wget curl libcurl4-openssl-dev gcc make zip unzip tar openssl libssl-dev gcc libxml2 libxml2-dev zlib1g zlib1g-dev libjpeg-dev libpng-dev lsof libpcre3 libpcre3-dev cron net-tools swig build-essential libffi-dev libbz2-dev libncurses-dev libsqlite3-dev libreadline-dev tk-dev libgdbm-dev libdb-dev libdb++-dev libpcap-dev xz-utils git";
    apt-get install -y $debPacks --force-yes
    for debPack in ${debPacks}
    do
        packCheck=$(dpkg -l ${debPack})
        if [ "$?" -ne "0" ] ;then
            apt-get install -y debPack
        fi
    done
    if [ ! -d '/etc/letsencrypt' ];then
        mkdir -p /etc/letsencryp
        mkdir -p /var/spool/cron
        if [ ! -f '/var/spool/cron/crontabs/root' ];then
            echo '' > /var/spool/cron/crontabs/root
            chmod 600 /var/spool/cron/crontabs/root
        fi
    fi
}
Install_Bt(){
    panelPort="8888"
    if [ -f ${setup_path}/server/panel/data/port.pl ];then
        panelPort=$(cat ${setup_path}/server/panel/data/port.pl)
    fi
    mkdir -p ${setup_path}/server/panel/logs
    mkdir -p ${setup_path}/server/panel/vhost/apache
    mkdir -p ${setup_path}/server/panel/vhost/nginx
    mkdir -p ${setup_path}/server/panel/vhost/rewrite
    mkdir -p ${setup_path}/server/panel/install
    mkdir -p /www/server
    mkdir -p /www/wwwroot
    mkdir -p /www/wwwlogs
    mkdir -p /www/backup/database
    mkdir -p /www/backup/site
    if [ ! -f "/usr/bin/unzip" ]; then
        if [ "${PM}" = "yum" ]; then
            yum install unzip -y
        elif [ "${PM}" = "apt-get" ]; then
            apt-get install unzip -y
        fi
    fi
    if [ -f "/etc/init.d/bt" ]; then
        /etc/init.d/bt stop
        sleep 1
    fi
    wget -O panel.zip ${download_Url}/install/src/panel_new.zip -T 10
    wget -O /etc/init.d/bt ${download_Url}/install/src/bt6.init -T 10
    wget -O /www/server/panel/install/public.sh ${download_Url}/install/public.sh -T 10
    if [ -f "${setup_path}/server/panel/data/default.db" ];then
        if [ -d "/${setup_path}/server/panel/old_data" ];then
            rm -rf ${setup_path}/server/panel/old_data
        fi
        mkdir -p ${setup_path}/server/panel/old_data
        d_format=$(date +"%Y%m%d_%H%M%S")
        \cp -arf ${setup_path}/server/panel/data/default.db ${setup_path}/server/panel/data/default_backup_${d_format}.db
        mv -f ${setup_path}/server/panel/data/default.db ${setup_path}/server/panel/old_data/default.db
        mv -f ${setup_path}/server/panel/data/system.db ${setup_path}/server/panel/old_data/system.db
        mv -f ${setup_path}/server/panel/data/port.pl ${setup_path}/server/panel/old_data/port.pl
        mv -f ${setup_path}/server/panel/data/admin_path.pl ${setup_path}/server/panel/old_data/admin_path.pl
    fi
    unzip -o panel.zip -d ${setup_path}/server/ > /dev/null
    if [ -d "${setup_path}/server/panel/old_data" ];then
        mv -f ${setup_path}/server/panel/old_data/default.db ${setup_path}/server/panel/data/default.db
        mv -f ${setup_path}/server/panel/old_data/system.db ${setup_path}/server/panel/data/system.db
        mv -f ${setup_path}/server/panel/old_data/port.pl ${setup_path}/server/panel/data/port.pl
        mv -f ${setup_path}/server/panel/old_data/admin_path.pl ${setup_path}/server/panel/data/admin_path.pl
        if [ -d "/${setup_path}/server/panel/old_data" ];then
            rm -rf ${setup_path}/server/panel/old_data
        fi
    fi
    rm -f panel.zip
    if [ ! -f ${setup_path}/server/panel/tools.py ];then
        Red_Error "ERROR: Failed to download, please try install again!"
    fi
    rm -f ${setup_path}/server/panel/class/*.pyc
    rm -f ${setup_path}/server/panel/*.pyc
    chmod +x /etc/init.d/bt
    chmod -R 600 ${setup_path}/server/panel
    chmod -R +x ${setup_path}/server/panel/script
    ln -sf /etc/init.d/bt /usr/bin/bt
    echo "${panelPort}" > ${setup_path}/server/panel/data/port.pl
    wget -O /etc/init.d/bt ${download_Url}/install/src/bt7.init -T 10
    wget -O /www/server/panel/init.sh ${download_Url}/install/src/bt7.init -T 10
}
Install_Python_Lib(){
    curl -Ss --connect-timeout 3 -m 60 $download_Url/install/pip_select.sh|bash
    pyenv_path="/www/server/panel"
    if [ -f $pyenv_path/pyenv/bin/python ];then
        is_err=$($pyenv_path/pyenv/bin/python3.7 -V 2>&1|grep 'Could not find platform')
        if [ "$is_err" = "" ];then
            chmod -R 700 $pyenv_path/pyenv/bin
            is_package=$($python_bin -m psutil 2>&1|grep package)
            if [ "$is_package" = "" ];then
                wget -O $pyenv_path/pyenv/pip.txt $download_Url/install/pyenv/pip.txt -T 5
                $pyenv_path/pyenv/bin/pip install -U pip
                $pyenv_path/pyenv/bin/pip install -U setuptools
                $pyenv_path/pyenv/bin/pip install -r $pyenv_path/pyenv/pip.txt
            fi
            source $pyenv_path/pyenv/bin/activate
            return
        else
            rm -rf $pyenv_path/pyenv
        fi
    fi
    py_version="3.7.8"
    mkdir -p $pyenv_path
    os_type='el'
    os_version='7'
    is_export_openssl=0
    Get_Versions
    Centos6_Openssl
    Other_Openssl
    echo "OS: $os_type - $os_version"
    is_aarch64=$(uname -a|grep aarch64)
    if [ "$is_aarch64" != "" ];then
        os_version="aarch64"
    fi
    if [ -f "/www/server/panel/pymake.pl" ];then
        os_version=""
        rm -f /www/server/panel/pymake.pl
    fi
    if [ "${os_version}" != "" ];then
        pyenv_file="/www/pyenv.tar.gz"
        wget -O $pyenv_file $download_Url/install/pyenv/pyenv-${os_type}${os_version}-x${is64bit}.tar.gz -T 10
        tmp_size=$(du -b $pyenv_file|awk '{print $1}')
        if [ $tmp_size -lt 703460 ];then
            rm -f $pyenv_file
            echo "ERROR: Download python env fielded."
        else
            echo "Install python env..."
            tar zxvf $pyenv_file -C $pyenv_path/ > /dev/null
            chmod -R 700 $pyenv_path/pyenv/bin
            if [ ! -f $pyenv_path/pyenv/bin/python ];then
                rm -f $pyenv_file
                Red_Error "ERROR: Install python env fielded."
            fi
            is_err=$($pyenv_path/pyenv/bin/python3.7 -V 2>&1|grep 'Could not find platform')
            if [ "$is_err" = "" ];then
                rm -f $pyenv_file
                ln -sf $pyenv_path/pyenv/bin/pip3.7 /usr/bin/btpip
                ln -sf $pyenv_path/pyenv/bin/python3.7 /usr/bin/btpython
                source $pyenv_path/pyenv/bin/activate
                return
            else
                rm -f $pyenv_file
                rm -rf $pyenv_path/pyenv
            fi
        fi
    fi
    if [ -f /usr/local/openssl/lib/libssl.so ];then
        export LDFLAGS="-L/usr/local/openssl/lib"
        export CPPFLAGS="-I/usr/local/openssl/include"
        export PKG_CONFIG_PATH="/usr/local/openssl/lib/pkgconfig"
        echo "export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/openssl/lib" >> /etc/profile
        source /etc/profile
    fi
    cd /www
    python_src='/www/python_src.tar.xz'
    python_src_path="/www/Python-${py_version}"
    wget -O $python_src $download_Url/src/Python-${py_version}.tar.xz -T 5
    tmp_size=$(du -b $python_src|awk '{print $1}')
    if [ $tmp_size -lt 10703460 ];then
        rm -f $python_src
        Red_Error "ERROR: Download python source code fielded."
    fi
    tar xvf $python_src
    rm -f $python_src
    cd $python_src_path
    ./configure --prefix=$pyenv_path/pyenv
    make -j$cpu_cpunt
    make install
    if [ ! -f $pyenv_path/pyenv/bin/python3.7 ];then
        rm -rf $python_src_path
        Red_Error "ERROR: Make python env fielded."
    fi
    cd ~
    rm -rf $python_src_path
    wget -O $pyenv_path/pyenv/bin/activate $download_Url/install/pyenv/activate.panel -T 5
    wget -O $pyenv_path/pyenv/pip.txt $download_Url/install/pyenv/pip-3.7.8.txt -T 5
    ln -sf $pyenv_path/pyenv/bin/pip3.7 $pyenv_path/pyenv/bin/pip
    ln -sf $pyenv_path/pyenv/bin/python3.7 $pyenv_path/pyenv/bin/python
    ln -sf $pyenv_path/pyenv/bin/pip3.7 /usr/bin/btpip
    ln -sf $pyenv_path/pyenv/bin/python3.7 /usr/bin/btpython
    chmod -R 700 $pyenv_path/pyenv/bin
    $pyenv_path/pyenv/bin/pip install -U pip
    $pyenv_path/pyenv/bin/pip install -U setuptools
    $pyenv_path/pyenv/bin/pip install -U wheel==0.34.2
    $pyenv_path/pyenv/bin/pip install -r $pyenv_path/pyenv/pip.txt
    source $pyenv_path/pyenv/bin/activate
}
Other_Openssl(){
    openssl_version=$(openssl version|grep -Eo '[0-9]\.[0-9]\.[0-9]')
    if [ "$openssl_version" = '1.0.1' ] || [ "$openssl_version" = '1.0.0' ];then
        opensslVersion="1.0.2r"
        if [ ! -f "/usr/local/openssl/lib/libssl.so" ];then
            cd /www
            openssl_src_file=/www/openssl.tar.gz
            wget -O $openssl_src_file ${download_Url}/src/openssl-${opensslVersion}.tar.gz
            tmp_size=$(du -b $openssl_src_file|awk '{print $1}')
            if [ $tmp_size -lt 703460 ];then
                rm -f $openssl_src_file
                Red_Error "ERROR: Download openssl-1.0.2 source code fielded."
            fi
            tar -zxf $openssl_src_file
            rm -f $openssl_src_file
            cd openssl-${opensslVersion}
            #zlib-dynamic shared
            ./config --openssldir=/usr/local/openssl zlib-dynamic shared
            make -j${cpuCore}
            make install
            echo  "/usr/local/openssl/lib" > /etc/ld.so.conf.d/zopenssl.conf
            ldconfig
            cd ..
            rm -rf openssl-${opensslVersion}
            is_export_openssl=1
            cd ~
        fi
    fi
}
Insatll_Libressl(){
    openssl_version=$(openssl version|grep -Eo '[0-9]\.[0-9]\.[0-9]')
    if [ "$openssl_version" = '1.0.1' ] || [ "$openssl_version" = '1.0.0' ];then
        opensslVersion="3.0.2"
        cd /www
        openssl_src_file=/www/openssl.tar.gz
        wget -O $openssl_src_file ${download_Url}/install/pyenv/libressl-${opensslVersion}.tar.gz
        tmp_size=$(du -b $openssl_src_file|awk '{print $1}')
        if [ $tmp_size -lt 703460 ];then
            rm -f $openssl_src_file
            Red_Error "ERROR: Download libressl-$opensslVersion source code fielded."
        fi
        tar -zxf $openssl_src_file
        rm -f $openssl_src_file
        cd libressl-${opensslVersion}
        ./config â€“prefix=/usr/local/lib
        make -j${cpuCore}
        make install
        ldconfig
        ldconfig -v
        cd ..
        rm -rf libressl-${opensslVersion}
        is_export_openssl=1
        cd ~
    fi
}
Centos6_Openssl(){
    if [ "$os_type" != 'el' ];then
        return
    fi
    if [ "$os_version" != '6' ];then
        return
    fi
    echo 'Centos6 install openssl-1.0.2...'
    openssl_rpm_file="/www/openssl.rpm"
    wget -O $openssl_rpm_file $download_Url/rpm/centos6/${is64bit}/bt-openssl102.rpm -T 10
    tmp_size=$(du -b $openssl_rpm_file|awk '{print $1}')
    if [ $tmp_size -lt 102400 ];then
        rm -f $openssl_rpm_file
        Red_Error "ERROR: Download python env fielded."
    fi
    rpm -ivh $openssl_rpm_file
    rm -f $openssl_rpm_file
    is_export_openssl=1
}
Get_Versions(){
    redhat_version_file="/etc/redhat-release"
    deb_version_file="/etc/issue"
    if [ -f $redhat_version_file ];then
        os_type='el'
        is_aliyunos=$(cat $redhat_version_file|grep Aliyun)
        if [ "$is_aliyunos" != "" ];then
            return
        fi
        os_version=$(cat $redhat_version_file|grep CentOS|grep -Eo '([0-9]+\.)+[0-9]+'|grep -Eo '^[0-9]')
        if [ "${os_version}" = "5" ];then
            os_version=""
        fi
    else
        os_type='ubuntu'
        os_version=$(cat $deb_version_file|grep Ubuntu|grep -Eo '([0-9]+\.)+[0-9]+'|grep -Eo '^[0-9]+')
        if [ "${os_version}" = "" ];then
            os_type='debian'
            os_version=$(cat $deb_version_file|grep Debian|grep -Eo '([0-9]+\.)+[0-9]+'|grep -Eo '[0-9]+')
            if [ "${os_version}" = "" ];then
                os_version=$(cat $deb_version_file|grep Debian|grep -Eo '[0-9]+')
            fi
            if [ "${os_version}" = "8" ];then
                os_version=""
            fi
            if [ "${is64bit}" = '32' ];then
                os_version=""
            fi
        else
            if [ "$os_version" = "14" ];then
                os_version=""
            fi
            if [ "$os_version" = "12" ];then
                os_version=""
            fi
            if [ "$os_version" = "19" ];then
                os_version=""
            fi
        fi
    fi
}
Set_Bt_Panel(){
    password=$(cat /dev/urandom | head -n 16 | md5sum | head -c 8)
    sleep 1
    admin_auth="/www/server/panel/data/admin_path.pl"
    if [ ! -f ${admin_auth} ];then
        auth_path=$(cat /dev/urandom | head -n 16 | md5sum | head -c 8)
        echo "/${auth_path}" > ${admin_auth}
    fi
    auth_path=$(cat ${admin_auth})
    cd ${setup_path}/server/panel/
    /etc/init.d/bt start
    $python_bin -m py_compile tools.py
    $python_bin tools.py username
    username=$($python_bin tools.py panel ${password})
    cd ~
    echo "${password}" > ${setup_path}/server/panel/default.pl
    chmod 600 ${setup_path}/server/panel/default.pl
    sleep 3
    /etc/init.d/bt restart
    sleep 3
    isStart=$(ps aux |grep 'BT-Panel'|grep -v grep|awk '{print $2}')
    LOCAL_CURL=$(curl 127.0.0.1:8888/login 2>&1 |grep -i html)
    if [ -z "${isStart}" ] && [ -z "${LOCAL_CURL}" ];then
        /etc/init.d/bt 22
        cd /www/server/panel/pyenv/bin
        touch t.pl
        ls -al python3.7 python
        lsattr python3.7 python
        Red_Error "ERROR: The BT-Panel service startup failed."
    fi
}
Set_Firewall(){
    sshPort=$(cat /etc/ssh/sshd_config | grep 'Port '|awk '{print $2}')
    if [ "${PM}" = "apt-get" ]; then
        apt-get install -y ufw
        if [ -f "/usr/sbin/ufw" ];then
            ufw allow 20/tcp
            ufw allow 21/tcp
            ufw allow 22/tcp
            ufw allow 80/tcp
            ufw allow 888/tcp
            ufw allow ${panelPort}/tcp
            ufw allow ${sshPort}/tcp
            ufw allow 39000:40000/tcp
            ufw_status=`ufw status`
            echo y|ufw enable
            ufw default deny
            ufw reload
        fi
    else
        if [ -f "/etc/init.d/iptables" ];then
            iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 20 -j ACCEPT
            iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 21 -j ACCEPT
            iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
            iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT
            iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport ${panelPort} -j ACCEPT
            iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport ${sshPort} -j ACCEPT
            iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 39000:40000 -j ACCEPT
            #iptables -I INPUT -p tcp -m state --state NEW -m udp --dport 39000:40000 -j ACCEPT
            iptables -A INPUT -p icmp --icmp-type any -j ACCEPT
            iptables -A INPUT -s localhost -d localhost -j ACCEPT
            iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
            iptables -P INPUT DROP
            service iptables save
            sed -i "s#IPTABLES_MODULES=\"\"#IPTABLES_MODULES=\"ip_conntrack_netbios_ns ip_conntrack_ftp ip_nat_ftp\"#" /etc/sysconfig/iptables-config
            iptables_status=$(service iptables status | grep 'not running')
            if [ "${iptables_status}" == '' ];then
                service iptables restart
            fi
        else
            AliyunCheck=$(cat /etc/redhat-release|grep "Aliyun Linux")
            [ "${AliyunCheck}" ] && return
            yum install firewalld -y
            [ "${Centos8Check}" ] && yum reinstall python3-six -y
            systemctl enable firewalld
            systemctl start firewalld
            firewall-cmd --set-default-zone=public > /dev/null 2>&1
            firewall-cmd --permanent --zone=public --add-port=20/tcp > /dev/null 2>&1
            firewall-cmd --permanent --zone=public --add-port=21/tcp > /dev/null 2>&1
            firewall-cmd --permanent --zone=public --add-port=22/tcp > /dev/null 2>&1
            firewall-cmd --permanent --zone=public --add-port=80/tcp > /dev/null 2>&1
            firewall-cmd --permanent --zone=public --add-port=${panelPort}/tcp > /dev/null 2>&1
            firewall-cmd --permanent --zone=public --add-port=${sshPort}/tcp > /dev/null 2>&1
            firewall-cmd --permanent --zone=public --add-port=39000-40000/tcp > /dev/null 2>&1
            #firewall-cmd --permanent --zone=public --add-port=39000-40000/udp > /dev/null 2>&1
            firewall-cmd --reload
        fi
    fi
}
Get_Ip_Address(){
    getIpAddress=""
    getIpAddress=$(curl -sS --connect-timeout 10 -m 60 https://v7.hostcli.com/Api/getIpAddress)
    if [ -z "${getIpAddress}" ] || [ "${getIpAddress}" = "0.0.0.0" ]; then
        isHosts=$(cat /etc/hosts|grep 'v7.hostcli.com')
        if [ -z "${isHosts}" ];then
            #echo "" >> /etc/hosts
            #echo "103.224.251.67 v7.hostcli.com" >> /etc/hosts
            getIpAddress=$(curl -sS --connect-timeout 10 -m 60 https://v7.hostcli.com/Api/getIpAddress)
            if [ -z "${getIpAddress}" ];then
                sed -i "/v7.hostcli.com/d" /etc/hosts
            fi
        fi
    fi
    ipv4Check=$($python_bin -c "import re; print(re.match('^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$','${getIpAddress}'))")
    if [ "${ipv4Check}" == "None" ];then
        ipv6Address=$(echo ${getIpAddress}|tr -d "[]")
        ipv6Check=$($python_bin -c "import re; print(re.match('^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}$','${ipv6Address}'))")
        if [ "${ipv6Check}" == "None" ]; then
            getIpAddress="SERVER_IP"
        else
            echo "True" > ${setup_path}/server/panel/data/ipv6.pl
            sleep 1
            /etc/init.d/bt restart
        fi
    fi
    if [ "${getIpAddress}" != "SERVER_IP" ];then
        echo "${getIpAddress}" > ${setup_path}/server/panel/data/iplist.txt
    fi
    LOCAL_IP=$(ip addr | grep -E -o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | grep -E -v "^127\.|^255\.|^0\." | head -n 1)
}
Setup_Count(){
    curl -sS --connect-timeout 10 -m 60 https://v7.hostcli.com/Api/SetupCount?type=Linux\&o=$1 > /dev/null 2>&1
    if [ "$1" != "" ];then
        echo $1 > /www/server/panel/data/o.pl
        cd /www/server/panel
        $python_bin tools.py o
    fi
    echo /www > /var/bt_setupPath.conf
}
Install_Main(){
    startTime=`date +%s`
    Lock_Clear
    System_Check
    Get_Pack_Manager
    get_node_url
    MEM_TOTAL=$(free -g|grep Mem|awk '{print $2}')
    if [ "${MEM_TOTAL}" -le "1" ];then
        Auto_Swap
    fi
    if [ "${PM}" = "yum" ]; then
        Install_RPM_Pack
    elif [ "${PM}" = "apt-get" ]; then
        Install_Deb_Pack
    fi
    Install_Python_Lib
    Install_Bt
    Set_Bt_Panel
    Service_Add
    Set_Firewall
    Get_Ip_Address
    Setup_Count ${IDC_CODE}
}
echo "
+----------------------------------------------------------------------
| hostcli.com FOR CentOS/Ubuntu/Debian
+----------------------------------------------------------------------
| Copyright Â© 2015-2099 HostCli(http://v7.hostcli.com) All rights reserved.
+----------------------------------------------------------------------
| The WebPanel URL will be http://SERVER_IP:8888 when installed.
+----------------------------------------------------------------------
"
while [ "$go" != 'y' ] && [ "$go" != 'n' ]
do
    read -p "Do you want to install Bt-Panel to the $setup_path directory now?(y/n): " go;
done
if [ "$go" == 'n' ];then
    exit;
fi
Install_Main
echo > /www/server/panel/data/bind.pl
echo -e "=================================================================="
echo -e "\033[32mCongratulations! Installed successfully!\033[0m"
echo -e "=================================================================="
echo  "外网面板地址: http://${getIpAddress}:${panelPort}${auth_path}"
echo  "内网面板地址: http://${LOCAL_IP}:${panelPort}${auth_path}"
echo -e "username: $username"
echo -e "password: $password"
echo -e "\033[33mIf you cannot access the panel,\033[0m"
echo -e "\033[33mrelease the following panel port [${panelPort}] in the security group\033[0m"
echo -e "\033[33m若无法访问面板,请检查防火墙/安全组是否有放行面板[${panelPort}]端口\033[0m"
echo -e "=================================================================="
endTime=`date +%s`
((outTime=($endTime-$startTime)/60))
echo -e "Time consumed:\033[32m $outTime \033[0mMinute!"