领客空间 - Lincrow - 专注于分享SEO网络营销、建站技术的自媒体博客 - 代码片段
今天，使用centos9+宝塔搭建服务器，遇到了一个很有趣的问题：服务器是两张网卡，两个不同的网段，并且都接入了公网。A网段IP需要映射外网。B网端只需要内网访问即可。但实际情况却是：A网段和B网段内网访问都正常。但是A网段在公网访问服务器却不能访问。检测端口，80、443等端口都是关闭的。 经过多次排查，都找不到具体根结。后来突然想到，是不是和网关有关系。查看默认网关，发现系统默认B网关为默认。改A为默认网关即可。 在Linux中，当你为多张网卡配置了不同的网关时，系统默认只会选择一个作为默认网关。而不是每张网卡都会使用它自己的网关。所以，在这样的配置下，通常有一个主要的考虑因素决定哪一个网关被选择为默认网关，那就是网卡或路由的度量（metric）值。 在nmcli和其他网络配置工具中，度量值通常用来决定路由的优先级。具有最低度量值的路由将被选为默认路由。如果两张网卡的度量值相同，那么其它因素，如接口的激活顺序，可能会起作用。 我们如果想查看当前的路由设置和默认网关，可以使用命令： ip route show 如果是安装了NetworkManager route -n 然后，使用route命令来进行设置： route add default gw 192.168.1.1 如果要使用IP-Route2工具，那么请先安装iproute2工具： dnf install iproute2 接着，为网络接口设置IPv4地址： ip addr add 192.168.1.x dev eth0
宝塔面板邮局 Postfix的Sqlite包异常，修复不了问题解决
宝塔邮局出问题，提示，Postfix的Sqlite包异常，请检查。 重新安装之后、修复也不行，后来子网上找到一个重新下载postfix3-sqlite的方法，标记下。 1、首先在https://rhel.pkgs.org/7/ghettoforge-plus-x86_64/ 网站找到最新postfix3-sqlit版本地址。 例如：postfix3-sqlite-3.8.4-1.gf.el7.x86_64.rpm 在Download下找到下载地址： 运行命令： wget http://mirror.ghettoforge.org/distributions/gf/el/7/plus/x86_64/postfix3-sqlite-3.8.4-1.gf.el7.x86_64.rpm yum install postfix3-sqlite-3.8.4-1.gf.el7.x86_64.rpm -y 完成！！
支持 切换 Live2D 模型了（暂时只有 Pio 和 Tia 酱 支持 随机换装 和 顺序换装（收集了截至目前的 Pio、Tia 全套服装 *需要根据 自身情况 进行定制，不能直接套用（其他资源文件见 打包下载 ** waifu-tips.js 的详细设置说明，和 waifu-tips.json 节点说明，见 Live2D 看板娘小样 ReadMe waifu.css .waifu { position: fixed; bottom: 0; z-index: 1; font-size: 0; -webkit-transform: translateY(3px); transform: translateY(3px); } .waifu:hover { -webkit-transform: translateY(0); transform: translateY(0); } .waifu-tips { opacity: 0; margin: -20px 20px; padding: 5px 10px; border: 1px solid rgba(224, 186, 140, 0.62); border-radius: 12px; background-color: rgba(236, 217, 188, 0.5); box-shadow: 0 3px 15px 2px rgba(191, 158, 118, 0.2); text-overflow: ellipsis; overflow: hidden; position: absolute; animation-delay: 5s; animation-duration: 50s; animation-iteration-count: infinite; animation-name: shake; animation-timing-function: ease-in-out; } .waifu-tool { display: none; color: #aaa; top: 50px; right: 10px; position: absolute; } .waifu:hover .waifu-tool { display: block; } .waifu-tool span { display: block; cursor: pointer; color: #5b6c7d; transition: 0.2s; } .waifu-tool span:hover { color: #34495e; } .waifu #live2d{ position: relative; } @keyframes shake { 2% { transform: translate(0.5px, -1.5px) rotate(-0.5deg); } 4% { transform: translate(0.5px, 1.5px) rotate(1.5deg); } 6% { transform: translate(1.5px, 1.5px) rotate(1.5deg); } 8% { transform: translate(2.5px, 1.5px) rotate(0.5deg); } 10% { transform: translate(0.5px, 2.5px) rotate(0.5deg); } 12% { transform: translate(1.5px, 1.5px) rotate(0.5deg); } 14% { transform: translate(0.5px, 0.5px) rotate(0.5deg); } 16% { transform: translate(-1.5px, -0.5px) rotate(1.5deg); } 18% { transform: translate(0.5px, 0.5px) rotate(1.5deg); } 20% { transform: translate(2.5px, 2.5px) rotate(1.5deg); } 22% { transform: translate(0.5px, -1.5px) rotate(1.5deg); } 24% { transform: translate(-1.5px, 1.5px) rotate(-0.5deg); } 26% { transform: translate(1.5px, 0.5px) rotate(1.5deg); } 28% { transform: translate(-0.5px, -0.5px) rotate(-0.5deg); } 30% { transform: translate(1.5px, -0.5px) rotate(-0.5deg); } 32% { transform: translate(2.5px, -1.5px) rotate(1.5deg); } 34% { transform: translate(2.5px, 2.5px) rotate(-0.5deg); } 36% { transform: translate(0.5px, -1.5px) rotate(0.5deg); } 38% { transform: translate(2.5px, -0.5px) rotate(-0.5deg); } 40% { transform: translate(-0.5px, 2.5px) rotate(0.5deg); } 42% { transform: translate(-1.5px, 2.5px) rotate(0.5deg); } 44% { transform: translate(-1.5px, 1.5px) rotate(0.5deg); } 46% { transform: translate(1.5px, -0.5px) rotate(-0.5deg); } 48% { transform: translate(2.5px, -0.5px) rotate(0.5deg); } 50% { transform: translate(-1.5px, 1.5px) rotate(0.5deg); } 52% { transform: translate(-0.5px, 1.5px) rotate(0.5deg); } 54% { transform: translate(-1.5px, 1.5px) rotate(0.5deg); } 56% { transform: translate(0.5px, 2.5px) rotate(1.5deg); } 58% { transform: translate(2.5px, 2.5px) rotate(0.5deg); } 60% { transform: translate(2.5px, -1.5px) rotate(1.5deg); } 62% { transform: translate(-1.5px, 0.5px) rotate(1.5deg); } 64% { transform: translate(-1.5px, 1.5px) rotate(1.5deg); } 66% { transform: translate(0.5px, 2.5px) rotate(1.5deg); } 68% { transform: translate(2.5px, -1.5px) rotate(1.5deg); } 70% { transform: translate(2.5px, 2.5px) rotate(0.5deg); } 72% { transform: translate(-0.5px, -1.5px) rotate(1.5deg); } 74% { transform: translate(-1.5px, 2.5px) rotate(1.5deg); } 76% { transform: translate(-1.5px, 2.5px) rotate(1.5deg); } 78% { transform: translate(-1.5px, 2.5px) rotate(0.5deg); } 80% { transform: translate(-1.5px, 0.5px) rotate(-0.5deg); } 82% { transform: translate(-1.5px, 0.5px) rotate(-0.5deg); } 84% { transform: translate(-0.5px, 0.5px) rotate(1.5deg); } 86% { transform: translate(2.5px, 1.5px) rotate(0.5deg); } 88% { transform: translate(-1.5px, 0.5px) rotate(1.5deg); } 90% { transform: translate(-1.5px, -0.5px) rotate(-0.5deg); } 92% { transform: translate(-1.5px, -1.5px) rotate(1.5deg); } 94% { transform: translate(0.5px, 0.5px) rotate(-0.5deg); } 96% { transform: translate(2.5px, -0.5px) rotate(-0.5deg); } 98% { transform: translate(-1.5px, -1.5px) rotate(-0.5deg); } 0%, 100% { transform: translate(0, 0) rotate(0); } } @font-face { font-family: 'Flat-UI-Icons'; src: url('flat-ui-icons-regular.eot'); src: url('flat-ui-icons-regular.eot?#iefix') format('embedded-opentype'), url('flat-ui-icons-regular.woff') format('woff'), url('flat-ui-icons-regular.ttf') format('truetype'), url('flat-ui-icons-regular.svg#flat-ui-icons-regular') format('svg'); } [class^="fui-"], [class*="fui-"] { font-family: 'Flat-UI-Icons'; speak: none; font-style: normal; font-weight: normal; font-variant: normal; text-transform: none; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } .fui-cross:before { content: "\e609"; } .fui-info-circle:before { content: "\e60f"; } .fui-photo:before { content: "\e62a"; } .fui-eye:before { content: "\e62c"; } .fui-chat:before { content: "\e62d"; } .fui-home:before { content: "\e62e"; } .fui-user:before { content: "\e631"; } waifu-tips.js window.live2d_settings = Array(); /* く__,.ヘヽ. / ,ー､ 〉 ＼ ', !-─‐-i / /´ ／｀ｰ' L/／｀ヽ､ Live2D 看板娘 参数设置 / ／, /| , , ', Version 1.4.2 ｲ / /-‐/ ｉ L_ ﾊ ヽ! i Update 2018.11.12 ﾚ ﾍ 7ｲ｀ﾄ ﾚ'ｧ-ﾄ､!ハ| | !,/7 '0' ´0iソ| | |.从" _ ,,,, / |./ | 网页添加 Live2D 看板娘 ﾚ'| i＞.､,,__ _,.イ / .i | https://www.lincrow.com/archives/322/ ﾚ'| | / k_７_/ﾚ'ヽ, ﾊ. | | |/i 〈|/ i ,.ﾍ | i | .|/ / ｉ： ﾍ! ＼ | kヽ>､ﾊ _,.ﾍ､ /､! !'〈//｀Ｔ´', ＼ ｀'7'ｰr' ﾚ'ヽL__|___i,___,ンﾚ|ノ ﾄ-,/ |___./ 'ｰ' !_,.:*********************************************************************************/ // 后端接口 live2d_settings['modelAPI'] = '//live2d.gyhd.cc/api/'; // 自建 API 修改这里 live2d_settings['tipsMessage'] = 'waifu-tips.json'; // 同目录下可省略路径 live2d_settings['hitokotoAPI'] = 'lincrow'; // 一言 API，可选'hitokoto.cn', 'jinrishici.com'(古诗词) // 默认模型 live2d_settings['modelId'] = 1; // 默认模型 ID，可在 F12 控制台找到 live2d_settings['modelTexturesId'] = 53; // 默认材质 ID，可在 F12 控制台找到 // 工具栏设置 live2d_settings['showToolMenu'] = true; // 显示 工具栏 ，可选 true(真), false(假) live2d_settings['canCloseLive2d'] = true; // 显示 关闭看板娘 按钮，可选 true(真), false(假) live2d_settings['canSwitchModel'] = true; // 显示 模型切换 按钮，可选 true(真), false(假) live2d_settings['canSwitchTextures'] = true; // 显示 材质切换 按钮，可选 true(真), false(假) live2d_settings['canSwitchHitokoto'] = true; // 显示 一言切换 按钮，可选 true(真), false(假) live2d_settings['canTakeScreenshot'] = true; // 显示 看板娘截图 按钮，可选 true(真), false(假) live2d_settings['canTurnToHomePage'] = true; // 显示 返回首页 按钮，可选 true(真), false(假) live2d_settings['canTurnToAboutPage'] = true; // 显示 跳转关于页 按钮，可选 true(真), false(假) // 模型切换模式 live2d_settings['modelStorage'] = true; // 记录 ID (刷新后恢复)，可选 true(真), false(假) live2d_settings['modelRandMode'] = 'switch'; // 模型切换，可选 'rand'(随机), 'switch'(顺序) live2d_settings['modelTexturesRandMode']= 'rand'; // 材质切换，可选 'rand'(随机), 'switch'(顺序) // 提示消息选项 live2d_settings['showHitokoto'] = true; // 显示一言 live2d_settings['showF12Status'] = true; // 显示加载状态 live2d_settings['showF12Message'] = false; // 显示看板娘消息 live2d_settings['showF12OpenMsg'] = true; // 显示控制台打开提示 live2d_settings['showCopyMessage'] = true; // 显示 复制内容 提示 live2d_settings['showWelcomeMessage'] = true; // 显示进入面页欢迎词 //看板娘样式设置 live2d_settings['waifuSize'] = '280x250'; // 看板娘大小，例如 '280x250', '600x535' live2d_settings['waifuTipsSize'] = '250x70'; // 提示框大小，例如 '250x70', '570x150' live2d_settings['waifuFontSize'] = '12px'; // 提示框字体，例如 '12px', '30px' live2d_settings['waifuToolFont'] = '14px'; // 工具栏字体，例如 '14px', '36px' live2d_settings['waifuToolLine'] = '20px'; // 工具栏行高，例如 '20px', '36px' live2d_settings['waifuToolTop'] = '0px' // 工具栏顶部边距，例如 '0px', '-60px' live2d_settings['waifuMinWidth'] = '768px'; // 面页小于 指定宽度 隐藏看板娘，例如 'disable'(禁用), '768px' live2d_settings['waifuEdgeSide'] = 'left:0'; // 看板娘贴边方向，例如 'left:0'(靠左 0px), 'right:30'(靠右 30px) live2d_settings['waifuDraggable'] = 'disable'; // 拖拽样式，例如 'disable'(禁用), 'axis-x'(只能水平拖拽), 'unlimited'(自由拖拽) live2d_settings['waifuDraggableRevert'] = true; // 松开鼠标还原拖拽位置，可选 true(真), false(假) // 其他杂项设置 live2d_settings['l2dVersion'] = '1.4.2'; // 当前版本 live2d_settings['l2dVerDate'] = '2018.11.12'; // 版本更新日期 live2d_settings['homePageUrl'] = 'auto'; // 主页地址，可选 'auto'(自动), '{URL 网址}' live2d_settings['aboutPageUrl'] = 'https://www.lincrow.com/archives/322/'; // 关于页地址, '{URL 网址}' live2d_settings['screenshotCaptureName']= 'live2d.png'; // 看板娘截图文件名，例如 'live2d.png' /****************************************************************************************************/ String.prototype.render = function(context) { var tokenReg = /(\\)?\{([^\{\}\\]+)(\\)?\}/g; return this.replace(tokenReg, function (word, slash1, token, slash2) { if (slash1 || slash2) { return word.replace('\\', ''); } var variables = token.replace(/\s/g, '').split('.'); var currentObject = context; var i, length, variable; for (i = 0, length = variables.length; i < length; ++i) { variable = variables[i]; currentObject = currentObject[variable]; if (currentObject === undefined || currentObject === null) return ''; } return currentObject; }); }; var re = /x/; function empty(obj) {return typeof obj=="undefined"||obj==null||obj==""?true:false} function getRandText(text) {return Array.isArray(text) ? text[Math.floor(Math.random() * text.length + 1)-1] : text} function showMessage(text, timeout, flag) { if(flag || sessionStorage.getItem('waifu-text') === '' || sessionStorage.getItem('waifu-text') === null){ if(Array.isArray(text)) text = text[Math.floor(Math.random() * text.length + 1)-1]; if (live2d_settings.showF12Message) console.log('[Message]', text.replace(/<[^<>]+>/g,'')); if(flag) sessionStorage.setItem('waifu-text', text); $('.waifu-tips').stop(); $('.waifu-tips').html(text).fadeTo(200, 1); if (timeout === undefined) timeout = 5000; hideMessage(timeout); } } function hideMessage(timeout) { $('.waifu-tips').stop().css('opacity',1); if (timeout === undefined) timeout = 5000; window.setTimeout(function() {sessionStorage.removeItem('waifu-text')}, timeout); $('.waifu-tips').delay(timeout).fadeTo(200, 0); } function initModel(waifuPath, type) { /* console welcome message */ eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('8.d(" ");8.d("\\U,.\\y\\5.\\1\\1\\1\\1/\\1,\\u\\2 \\H\\n\\1\\1\\1\\1\\1\\b \', !-\\r\\j-i\\1/\\1/\\g\\n\\1\\1\\1 \\1 \\a\\4\\f\'\\1\\1\\1 L/\\a\\4\\5\\2\\n\\1\\1 \\1 /\\1 \\a,\\1 /|\\1 ,\\1 ,\\1\\1\\1 \',\\n\\1\\1\\1\\q \\1/ /-\\j/\\1\\h\\E \\9 \\5!\\1 i\\n\\1\\1\\1 \\3 \\6 7\\q\\4\\c\\1 \\3\'\\s-\\c\\2!\\t|\\1 |\\n\\1\\1\\1\\1 !,/7 \'0\'\\1\\1 \\X\\w| \\1 |\\1\\1\\1\\n\\1\\1\\1\\1 |.\\x\\"\\1\\l\\1\\1 ,,,, / |./ \\1 |\\n\\1\\1\\1\\1 \\3\'| i\\z.\\2,,A\\l,.\\B / \\1.i \\1|\\n\\1\\1\\1\\1\\1 \\3\'| | / C\\D/\\3\'\\5,\\1\\9.\\1|\\n\\1\\1\\1\\1\\1\\1 | |/i \\m|/\\1 i\\1,.\\6 |\\F\\1|\\n\\1\\1\\1\\1\\1\\1.|/ /\\1\\h\\G \\1 \\6!\\1\\1\\b\\1|\\n\\1\\1\\1 \\1 \\1 k\\5>\\2\\9 \\1 o,.\\6\\2 \\1 /\\2!\\n\\1\\1\\1\\1\\1\\1 !\'\\m//\\4\\I\\g\', \\b \\4\'7\'\\J\'\\n\\1\\1\\1\\1\\1\\1 \\3\'\\K|M,p,\\O\\3|\\P\\n\\1\\1\\1\\1\\1 \\1\\1\\1\\c-,/\\1|p./\\n\\1\\1\\1\\1\\1 \\1\\1\\1\'\\f\'\\1\\1!o,.:\\Q \\R\\S\\T v"+e.V+" / W "+e.N);8.d(" ");',60,60,'|u3000|uff64|uff9a|uff40|u30fd|uff8d||console|uff8a|uff0f|uff3c|uff84|log|live2d_settings|uff70|u00b4|uff49||u2010||u3000_|u3008||_|___|uff72|u2500|uff67|u30cf|u30fc||u30bd|u4ece|u30d8|uff1e|__|u30a4|k_|uff17_|u3000L_|u3000i|uff1a|u3009|uff34|uff70r|u30fdL__||___i|l2dVerDate|u30f3|u30ce|nLive2D|u770b|u677f|u5a18|u304f__|l2dVersion|LINCROW|u00b40i'.split('|'),0,{})); /* 判断 JQuery */ if (typeof($.ajax) != 'function') typeof(jQuery.ajax) == 'function' ? window.$ = jQuery : console.log('[Error] JQuery is not defined.'); /* 加载看板娘样式 */ live2d_settings.waifuSize = live2d_settings.waifuSize.split('x'); live2d_settings.waifuTipsSize = live2d_settings.waifuTipsSize.split('x'); live2d_settings.waifuEdgeSide = live2d_settings.waifuEdgeSide.split(':'); $("#live2d").attr("width",live2d_settings.waifuSize[0]); $("#live2d").attr("height",live2d_settings.waifuSize[1]); $(".waifu-tips").width(live2d_settings.waifuTipsSize[0]); $(".waifu-tips").height(live2d_settings.waifuTipsSize[1]); $(".waifu-tips").css("top",live2d_settings.waifuToolTop); $(".waifu-tips").css("font-size",live2d_settings.waifuFontSize); $(".waifu-tool").css("font-size",live2d_settings.waifuToolFont); $(".waifu-tool span").css("line-height",live2d_settings.waifuToolLine); if (live2d_settings.waifuEdgeSide[0] == 'left') $(".waifu").css("left",live2d_settings.waifuEdgeSide[1]+'px'); else if (live2d_settings.waifuEdgeSide[0] == 'right') $(".waifu").css("right",live2d_settings.waifuEdgeSide[1]+'px'); window.waifuResize = function() { $(window).width() <= Number(live2d_settings.waifuMinWidth.replace('px','')) ? $(".waifu").hide() : $(".waifu").show(); }; if (live2d_settings.waifuMinWidth != 'disable') { waifuResize(); $(window).resize(function() {waifuResize()}); } try { if (live2d_settings.waifuDraggable == 'axis-x') $(".waifu").draggable({ axis: "x", revert: live2d_settings.waifuDraggableRevert }); else if (live2d_settings.waifuDraggable == 'unlimited') $(".waifu").draggable({ revert: live2d_settings.waifuDraggableRevert }); else $(".waifu").css("transition", 'all .3s ease-in-out'); } catch(err) { console.log('[Error] JQuery UI is not defined.') } live2d_settings.homePageUrl == 'auto' ? window.location.protocol+'//'+window.location.hostname+'/' : live2d_settings.homePageUrl; if (window.location.protocol == 'file:' && live2d_settings.modelAPI.substr(0,2) == '//') live2d_settings.modelAPI = 'http:'+live2d_settings.modelAPI; $('.waifu-tool .fui-home').click(function (){ window.location = live2d_settings.homePageUrl; }); $('.waifu-tool .fui-info-circle').click(function (){ window.open(live2d_settings.aboutPageUrl); }); if (typeof(waifuPath) == "object") loadTipsMessage(waifuPath); else { $.ajax({ cache: true, url: waifuPath == '' ? live2d_settings.tipsMessage : (waifuPath.substr(waifuPath.length-15)=='waifu-tips.json'?waifuPath:waifuPath+'waifu-tips.json'), dataType: "json", success: function (result){ loadTipsMessage(result); } }); } if (!live2d_settings.showToolMenu) $('.waifu-tool').hide(); if (!live2d_settings.canCloseLive2d) $('.waifu-tool .fui-cross').hide(); if (!live2d_settings.canSwitchModel) $('.waifu-tool .fui-eye').hide(); if (!live2d_settings.canSwitchTextures) $('.waifu-tool .fui-user').hide(); if (!live2d_settings.canSwitchHitokoto) $('.waifu-tool .fui-chat').hide(); if (!live2d_settings.canTakeScreenshot) $('.waifu-tool .fui-photo').hide(); if (!live2d_settings.canTurnToHomePage) $('.waifu-tool .fui-home').hide(); if (!live2d_settings.canTurnToAboutPage) $('.waifu-tool .fui-info-circle').hide(); if (waifuPath === undefined) waifuPath = ''; var modelId = localStorage.getItem('modelId'); var modelTexturesId = localStorage.getItem('modelTexturesId'); if (!live2d_settings.modelStorage || modelId == null) { var modelId = live2d_settings.modelId; var modelTexturesId = live2d_settings.modelTexturesId; } loadModel(modelId, modelTexturesId); } function loadModel(modelId, modelTexturesId=0) { if (live2d_settings.modelStorage) { localStorage.setItem('modelId', modelId); localStorage.setItem('modelTexturesId', modelTexturesId); } else { sessionStorage.setItem('modelId', modelId); sessionStorage.setItem('modelTexturesId', modelTexturesId); } loadlive2d('live2d', live2d_settings.modelAPI+'get/?id='+modelId+'-'+modelTexturesId, (live2d_settings.showF12Status ? console.log('[Status]','live2d','模型',modelId+'-'+modelTexturesId,'加载完成'):null)); } function loadTipsMessage(result) { window.waifu_tips = result; $.each(result.mouseover, function (index, tips){ $(document).on("mouseover", tips.selector, function (){ var text = getRandText(tips.text); text = text.render({text: $(this).text()}); showMessage(text, 3000); }); }); $.each(result.click, function (index, tips){ $(document).on("click", tips.selector, function (){ var text = getRandText(tips.text); text = text.render({text: $(this).text()}); showMessage(text, 3000, true); }); }); $.each(result.seasons, function (index, tips){ var now = new Date(); var after = tips.date.split('-')[0]; var before = tips.date.split('-')[1] || after; if((after.split('/')[0] <= now.getMonth()+1 && now.getMonth()+1 <= before.split('/')[0]) && (after.split('/')[1] <= now.getDate() && now.getDate() <= before.split('/')[1])){ var text = getRandText(tips.text); text = text.render({year: now.getFullYear()}); showMessage(text, 6000, true); } }); if (live2d_settings.showF12OpenMsg) { re.toString = function() { showMessage(getRandText(result.waifu.console_open_msg), 5000, true); return ''; }; } if (live2d_settings.showCopyMessage) { $(document).on('copy', function() { showMessage(getRandText(result.waifu.copy_message), 5000, true); }); } $('.waifu-tool .fui-photo').click(function(){ showMessage(getRandText(result.waifu.screenshot_message), 5000, true); window.Live2D.captureName = live2d_settings.screenshotCaptureName; window.Live2D.captureFrame = true; }); $('.waifu-tool .fui-cross').click(function(){ sessionStorage.setItem('waifu-dsiplay', 'none'); showMessage(getRandText(result.waifu.hidden_message), 1300, true); window.setTimeout(function() {$('.waifu').hide();}, 1300); }); window.showWelcomeMessage = function(result) { var text; if (window.location.href == live2d_settings.homePageUrl) { var now = (new Date()).getHours(); if (now > 23 || now <= 5) text = getRandText(result.waifu.hour_tips.t23-5); else if (now > 5 && now <= 7) text = getRandText(result.waifu.hour_tips.t5-7); else if (now > 7 && now <= 11) text = getRandText(result.waifu.hour_tips.t7-11); else if (now > 11 && now <= 14) text = getRandText(result.waifu.hour_tips.t11-14); else if (now > 14 && now <= 17) text = getRandText(result.waifu.hour_tips.t14-17); else if (now > 17 && now <= 19) text = getRandText(result.waifu.hour_tips.t17-19); else if (now > 19 && now <= 21) text = getRandText(result.waifu.hour_tips.t19-21); else if (now > 21 && now <= 23) text = getRandText(result.waifu.hour_tips.t21-23); else text = getRandText(result.waifu.hour_tips.default); } else { var referrer_message = result.waifu.referrer_message; if (document.referrer !== '') { var referrer = document.createElement('a'); referrer.href = document.referrer; var domain = referrer.hostname.split('.')[1]; if (window.location.hostname == referrer.hostname) text = referrer_message.localhost[0] + document.title.split(referrer_message.localhost[2])[0] + referrer_message.localhost[1]; else if (domain == 'baidu') text = referrer_message.baidu[0] + referrer.search.split('&wd=')[1].split('&')[0] + referrer_message.baidu[1]; else if (domain == 'so') text = referrer_message.so[0] + referrer.search.split('&q=')[1].split('&')[0] + referrer_message.so[1]; else if (domain == 'google') text = referrer_message.google[0] + document.title.split(referrer_message.google[2])[0] + referrer_message.google[1]; else { $.each(result.waifu.referrer_hostname, function(i,val) {if (i==referrer.hostname) referrer.hostname = getRandText(val)}); text = referrer_message.default[0] + referrer.hostname + referrer_message.default[1]; } } else text = referrer_message.none[0] + document.title.split(referrer_message.none[2])[0] + referrer_message.none[1]; } showMessage(text, 6000); }; if (live2d_settings.showWelcomeMessage) showWelcomeMessage(result); var waifu_tips = result.waifu; function loadOtherModel() { var modelId = modelStorageGetItem('modelId'); var modelRandMode = live2d_settings.modelRandMode; $.ajax({ cache: modelRandMode == 'switch' ? true : false, url: live2d_settings.modelAPI+modelRandMode+'/?id='+modelId, dataType: "json", success: function(result) { loadModel(result.model['id']); var message = result.model['message']; $.each(waifu_tips.model_message, function(i,val) {if (i==result.model['id']) message = getRandText(val)}); showMessage(message, 3000, true); } }); } function loadRandTextures() { var modelId = modelStorageGetItem('modelId'); var modelTexturesId = modelStorageGetItem('modelTexturesId'); var modelTexturesRandMode = live2d_settings.modelTexturesRandMode; $.ajax({ cache: modelTexturesRandMode == 'switch' ? true : false, url: live2d_settings.modelAPI+modelTexturesRandMode+'_textures/?id='+modelId+'-'+modelTexturesId, dataType: "json", success: function(result) { if (result.textures['id'] == 1 && (modelTexturesId == 1 || modelTexturesId == 0)) showMessage(waifu_tips.load_rand_textures[0], 3000, true); else showMessage(waifu_tips.load_rand_textures[1], 3000, true); loadModel(modelId, result.textures['id']); } }); } function modelStorageGetItem(key) { return live2d_settings.modelStorage ? localStorage.getItem(key) : sessionStorage.getItem(key); } /* 检测用户活动状态，并在空闲时显示一言 */ if (live2d_settings.showHitokoto) { window.getActed = false; window.hitokotoTimer = 0; window.hitokotoInterval = false; $(document).mousemove(function(e){getActed = true;}).keydown(function(){getActed = true;}); setInterval(function(){ if (!getActed) ifActed(); else elseActed(); }, 1000); } function ifActed() { if (!hitokotoInterval) { hitokotoInterval = true; hitokotoTimer = window.setInterval(showHitokotoActed, 30000); } } function elseActed() { getActed = hitokotoInterval = false; window.clearInterval(hitokotoTimer); } function showHitokotoActed() { if ($(document)[0].visibilityState == 'visible') showHitokoto(); } function showHitokoto() { switch(live2d_settings.hitokotoAPI) { case 'hitokoto.cn': $.getJSON('https://v1.hitokoto.cn',function(result){ if (!empty(result.from)) { var text = waifu_tips.hitokoto_api_message['hitokoto.cn'][0]; text = text.render({source: result.from, creator: result.creator}); window.setTimeout(function() {showMessage(text, 3000, true);}, 5000); } showMessage(result.hitokoto, 5000, true); });break; case 'jinrishici.com': $.ajax({ url: 'https://v2.jinrishici.com/one.json', xhrFields: {withCredentials: true}, success: function (result, status) { if (!empty(result.data.origin.title)) { var text = waifu_tips.hitokoto_api_message['jinrishici.com'][0]; text = text.render({title: result.data.origin.title, dynasty: result.data.origin.dynasty, author:result.data.origin.author}); window.setTimeout(function() {showMessage(text, 3000, true);}, 5000); } showMessage(result.data.content, 5000, true); } });break; default: $.getJSON('https://api.gyhd.cc/get/onesay?tp=arr',function(result){ if (!empty(result.onesay)) { var text = waifu_tips.hitokoto_api_message['lincrow'][0]; text = text.render({from: result.from}); window.setTimeout(function() {showMessage(text, 3000, true);}, 5000); showMessage(result.onesay, 5000, true); } }); } } $('.waifu-tool .fui-eye').click(function (){loadOtherModel()}); $('.waifu-tool .fui-user').click(function (){loadRandTextures()}); $('.waifu-tool .fui-chat').click(function (){showHitokoto()}); } waifu-tips.json { "waifu": { "console_open_msg": ["哈哈，你打开了控制台，是想要看看我的秘密吗？"], "copy_message": ["你都复制了些什么呀，转载要记得加上出处哦"], "screenshot_message": ["照好了嘛，是不是很可爱呢？"], "hidden_message": ["我们还能再见面的吧…"], "load_rand_textures": ["我还没有其他衣服呢", "我的新衣服好看嘛"], "hour_tips": { "t5-7": ["早上好！一日之计在于晨，美好的一天就要开始了"], "t7-11": ["上午好！工作顺利嘛，不要久坐，多起来走动走动哦！"], "t11-14": ["中午了，工作了一个上午，现在是午餐时间！"], "t14-17": ["午后很容易犯困呢，今天的运动目标完成了吗？"], "t17-19": ["傍晚了！窗外夕阳的景色很美丽呢，最美不过夕阳红~"], "t19-21": ["晚上好，今天过得怎么样？"], "t21-23": ["已经这么晚了呀，早点休息吧，晚安~"], "t23-5": ["你是夜猫子呀？这么晚还不睡觉，明天起的来嘛"], "default": ["嗨~ 快来逗我玩吧！"] }, "referrer_message": { "localhost": ["欢迎阅读『", "』", " - "], "baidu": ["Hello! 来自 百度搜索 的朋友 你是搜索 ", " 找到的我吗？"], "so": ["Hello! 来自 360搜索 的朋友 你是搜索 ", " 找到的我吗？"], "google": ["Hello! 来自 谷歌搜索 的朋友 欢迎阅读『", "』", " - "], "default": ["Hello! 来自 ", " 的朋友"], "none": ["欢迎阅读『", "』", " - "] }, "referrer_hostname": { "example.com": ["示例网站"], "www.lincrow.com": ["LINCROW 的博客"] }, "model_message": { "1": ["来自 Potion Maker 的 Pio 酱 ~"], "2": ["来自 Potion Maker 的 Tia 酱 ~"] }, "hitokoto_api_message": { "lincrow": ["这句一言出自 『{from}』，收藏在 LINCROW 博客的经典语句中！"], "jinrishici.com": ["这句诗词出自 《{title}》，是 {dynasty}诗人 {author} 创作的！"], "hitokoto.cn": ["这句一言来自 『{source}』，是 {creator} 在 hitokoto.cn 投稿的。"] } }, "mouseover": [ { "selector": ".container a[href^='http']", "text": ["要看看 {text} 么？"] }, { "selector": ".fui-home", "text": ["点击前往首页，想回到上一页可以使用浏览器的后退功能哦"] }, { "selector": ".fui-chat", "text": ["一言一语，一颦一笑。一字一句，一颗赛艇。"] }, { "selector": ".fui-eye", "text": ["嗯··· 要切换 看板娘 吗？"] }, { "selector": ".fui-user", "text": ["喜欢换装 Play 吗？"] }, { "selector": ".fui-photo", "text": ["要拍张纪念照片吗？"] }, { "selector": ".fui-info-circle", "text": ["这里有关于我的信息呢"] }, { "selector": ".fui-cross", "text": ["你不喜欢我了吗..."] }, { "selector": "#tor_show", "text": ["翻页比较麻烦吗，点击可以显示这篇文章的目录呢"] }, { "selector": "#comment_go", "text": ["想要去评论些什么吗？"] }, { "selector": "#night_mode", "text": ["深夜时要爱护眼睛呀"] }, { "selector": "#qrcode", "text": ["手机扫一下就能继续看，很方便呢"] }, { "selector": ".comment_reply", "text": ["要吐槽些什么呢"] }, { "selector": "#back-to-top", "text": ["回到开始的地方吧"] }, { "selector": "#author", "text": ["该怎么称呼你呢"] }, { "selector": "#mail", "text": ["留下你的邮箱，不然就是无头像人士了"] }, { "selector": "#url", "text": ["你的家在哪里呢，好让我去参观参观"] }, { "selector": "#textarea", "text": ["认真填写哦，垃圾评论是禁止事项"] }, { "selector": ".OwO-logo", "text": ["要插入一个表情吗"] }, { "selector": "#csubmit", "text": ["要[提交]^(Commit)了吗，首次评论需要审核，请耐心等待~"] }, { "selector": ".ImageBox", "text": ["点击图片可以放大呢"] }, { "selector": "input[name=s]", "text": ["找不到想看的内容？搜索看看吧"] }, { "selector": ".previous", "text": ["去上一页看看吧"] }, { "selector": ".next", "text": ["去下一页看看吧"] }, { "selector": ".dropdown-toggle", "text": ["这里是菜单"] }, { "selector": "c-player a.play-icon", "text": ["想要听点音乐吗"] }, { "selector": "c-player div.time", "text": ["在这里可以调整播放进度呢"] }, { "selector": "c-player div.volume", "text": ["在这里可以调整音量呢"] }, { "selector": "c-player div.list-button", "text": ["播放列表里都有什么呢"] }, { "selector": "c-player div.lyric-button", "text": ["有歌词的话就能跟着一起唱呢"] }, { "selector": ".waifu #live2d", "text": ["干嘛呢你，快把手拿开", "鼠…鼠标放错地方了！"] } ], "click": [ { "selector": ".waifu #live2d", "text": [ "是…是不小心碰到了吧", "萝莉控是什么呀", "你看到我的小熊了吗", "再摸的话我可要报警了！⌇●﹏●⌇", "110吗，这里有个变态一直在摸我(ó﹏ò｡)" ] } ], "seasons": [ { "date": "01/01", "text": ["元旦了呢，新的一年又开始了，今年是{year}年~"] }, { "date": "02/14", "text": ["又是一年情人节，{year}年找到对象了嘛~"] }, { "date": "03/08", "text": ["今天是妇女节！"] }, { "date": "03/12", "text": ["今天是植树节，要保护环境呀"] }, { "date": "04/01", "text": ["悄悄告诉你一个秘密~今天是愚人节，不要被骗了哦~"] }, { "date": "05/01", "text": ["今天是五一劳动节，计划好假期去哪里了吗~"] }, { "date": "06/01", "text": ["儿童节了呢，快活的时光总是短暂，要是永远长不大该多好啊…"] }, { "date": "09/03", "text": ["中国人民抗日战争胜利纪念日，铭记历史、缅怀先烈、珍爱和平、开创未来。"] }, { "date": "09/10", "text": ["教师节，在学校要给老师问声好呀~"] }, { "date": "10/01", "text": ["国庆节，新中国已经成立69年了呢"] }, { "date": "11/05-11/12", "text": ["今年的双十一是和谁一起过的呢~"] }, { "date": "12/20-12/31", "text": ["这几天是圣诞节，主人肯定又去剁手买买买了~"] } ] } 加进 header.php 加进 footer.php（须 jQuery 支持） 或 实现自动加载，在 footer.php 的最后加上 autoload.js // 加载 CSS $(" ").attr({href: "https://www.example.com/path/waifu.css", rel: "stylesheet", type: "text/css"}).appendTo('head'); // 插入 DIV $('body').append(' '); // 加载 JS $.ajax({ url: 'https://www.example.com/path/waifu-tips.js', dataType:"script", cache: true, async: false }); $.ajax({ url: 'https://www.example.com/path/live2d.js', dataType:"script", cache: true, async: false }); // 初始化看板娘，加载 waifu-tips.json /* 可直接修改部分参数 */ live2d_settings['modelId'] = 5; // 默认模型 ID live2d_settings['modelTexturesId'] = 1; // 默认材质 ID /* 在 initModel 前添加 */ initModel('https://www.example.com/path/waifu-tips.json'); Demo https://www.lincrow.com/ (本站) https://live2d.gyhd.cc/demo/ 打包下载 看板娘 前端 源码 : Live2D 看板娘小样 模型切换 API 源码 : Live2D 看板娘插件API
（1）gitLab版本升级，是先小版本升级到最高版本，在升级到下一个大版本，进行依次升级 （2）比如：16.4.0->16.4.1->16.4.2->16.4.0 小版本升级到最高级，在向下一个版本升级 （3）升级前需要备份，或者做镜像、快照等操作 （4）升级完成后，重启服务，查看响应版本号是否正确 一、升级前备份 1、手动备份 gitlab-rake gitlab:backup:create 注意：gitlab升级的时候，会自动备份 2、配置文件备份 配置文件须备份 /etc/gitlab/gitlab.rb 二、检测最新版本 检测最新版本，若相邻版本可直接升级。 yum install gitlab-ce 三、开始升级 查看现版本：GitLab -> 帮助 查看官方版本： 查看 官方源：查看 清华源：查看 四、跨版本升级 逐步小版本升级 1.下载安装包 wget https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el7/gitlab-ce-15.2.4-ce.0.el7.x86_64.rpm gitlab-ce-15.2.4-ce.0.el7.x86_64.rpm 为需要下载升级的版本 2.关闭部分gitlab服务（不要全关，因为升级中可能需要部分服务） gitlab-ctl stop unicorn gitlab-ctl stop sidekiq gitlab-ctl stop nginx 3.安装新版本 rpm -Uvh gitlab-ce-15.2.4-ce.0.el7.x86_64.rpm gitlab-ce-15.2.4-ce.0.el7.x86_64.rpm 为需要下载升级的版本 4.刷新配置 gitlab-ctl reconfigure 五、其他命令 1、停止所有服务 gitlab-ctl stop 2、GitLab停止某服务 gitlab-ctl stop 服务名 3、GitLab打开服务 gitlab-ctl start 4、GitLab停止某服务 gitlab-ctl start 服务名 5、查看Gitlab状态 gitlab-ctl status 6、恢复备份 gitlab-rake gitlab:backup:restore BACKUP=/var/opt/gitlab/backups/1665366086_2022_10_10_15.4.0_gitlab_backup.tar /var/opt/gitlab/backups/1665366086_2022_10_10_15.4.0_gitlab_backup.tar 为备份文件
[scode type="share"]Alist V3是一个支持多种存储，支持网页浏览和 WebDAV 的文件列表程序，由 gin 和 Solidjs 驱动。 Alist的官方文档提供了V2版本的API说明，但对于最新的V3版本并没有，这里个人整理了一些V3版本的常用API和参数设置，返回示例供有需要的朋友参考。[/scode] token获取 [scode type="blue"]POST /api/auth/login[/scode] 请求参数 名称 位置 类型 必选 说明 Password query string 是 密码 Username query string 是 用户名 返回数据结构 状态码 200 名称 类型 必选 约束 中文名 说明 code integer true none 状态码 message string true none 信息 data object true none data token string true none token 返回示例 { "code": 200, "message": "success", "data": { "token": "abcd" } } 获取文件列表 [scode type="blue"]POST /api/fs/list[/scode] 请求参数 名称 位置 类型 必选 说明 Authorization header string 是 用户token Content-Type header string 否 none body body object 否 none page body integer 否 当前页数 password body string 否 密码 path body string 否 路径 per_page body integer 否 每页文件数 refresh body boolean 否 强制刷新 返回数据结构 名称 类型 必选 约束 中文名 说明 » code integer true none 状态码 » message string true none 信息 » data object true none none »» content [object] true none none »»» name string true none 文件名 »»» size integer true none 文件大小 »»» is_dir boolean true none 是否为目录 »»» modified string true none 修改时间 »»» sign string true none 访问密钥 »»» thumb string true none 缩略图地址 »»» type integer true none none »» total integer true none 总文件数 »» readme string true none none »» write boolean true none 写入权限 »» provider string true none 存储类型 返回示例 { "code": 200, "message": "success", "data": { "content": [ { "name": "201311", "size": 0, "is_dir": true, "modified": "2021-11-30T15:41:43.004Z", "sign": "", "thumb": "", "type": 1 }, { "name": "201312", "size": 0, "is_dir": true, "modified": "2021-11-30T15:42:26.839Z", "sign": "", "thumb": "", "type": 1 }, { "name": "201401", "size": 0, "is_dir": true, "modified": "2021-11-30T15:42:37.344Z", "sign": "", "thumb": "", "type": 1 }, { "name": "201402", "size": 0, "is_dir": true, "modified": "2021-11-30T15:41:35.053Z", "sign": "", "thumb": "", "type": 1 }, { "name": "201403", "size": 0, "is_dir": true, "modified": "2021-11-30T15:41:51.271Z", "sign": "", "thumb": "", "type": 1 } ], "total": 77, "readme": "", "write": true, "provider": "Aliyundrive" } } 新建文件夹 [scode type="blue"]POST /api/fs/mkdir[/scode] 请求参数 名称 位置 类型 必选 说明 Authorization header string 是 token Content-Type header string 否 none body body object 否 none path body string 是 新目录路径 返回数据结构 |名称|类型|必选|约束|中文名|说明| | :---: | :---: | :---: | :---: | :---: | |code|integer|true|none||状态码| |message|string|true|none||信息| |data|null|true|none||data| 返回示例 { "code": 200, "message": "success", "data": null } 重命名文件夹 [scode type="blue"]POST /api/fs/rename[/scode] 请求参数 名称 位置 类型 必选 说明 Authorization header string 是 token Content-Type header string 否 none body body object 否 none name body string 是 目标目录名，不支持’/’ path body string 是 源目录名 返回数据结构 名称 类型 必选 约束 中文名 说明 code integer true none 状态码 message string true none 信息 data null true none none 返回示例 { "code": 200, "message": "success", "data": null } 删除文件夹 [scode type="blue"]POST /api/fs/remove[/scode] 请求参数 名称 位置 类型 必选 说明 Authorization header string 是 token Content-Type header string 是 none body body object 否 none dir body string 是 文件所在目录 names body [string] 是 文件名列表 返回数据结构 名称 类型 必选 约束 中文名 说明 code integer true none 状态码 message string true none 信息 data null true none none 返回示例 { "code": 200, "message": "success", "data": null } PUT 表单上传文件 [scode type="blue"]PUT /api/fs/form[/scode] 请求参数 名称 位置 类型 必选 说明 Authorization header string 是 token Content-Type header string 是 需要是multipart/form-data; Content-Length header string 是 文件大小 file-path header string 是 经过URL编码的完整文件路径 body body object 否 none file body string(binary) 是 文件 返回数据结构 名称 类型 必选 约束 中文名 说明 code integer true none 状态码 message string true none 信息 data null true none none 返回示例 { "code": 200, "message": "success", "data": null } 获取下载信息 [scode type="blue"]POST /api/fs/get[/scode] 请求参数 名称 位置 类型 必选 说明 Authorization header string 是 token Content-Type header string 否 none body body object 否 none password body string 否 密码 path body string 是 文件路径 返回数据结构 名称 类型 必选 约束 中文名 说明 code integer true none 状态码 message string true none 信息 data object true none data name string true none 文件名 size integer true none 文件大小 is_dir boolean true none 是否是目录 modified string true none 修改时间 sign string true none 文件密钥 thumb string true none 缩略图地址 type integer true none 类型 raw_url string true none 源文件下载地址 readme string true none none provider string true none 驱动类型 related null true none none 返回示例 { "code": 200, "message": "success", "data": { "name": "sw.jpg", "size": 169918, "is_dir": false, "modified": "2022-11-26T12:54:54.534Z", "sign": "xxxx", "thumb": "", "type": 5, "raw_url": "https://cn-beijing-data.aliyundrive.net/xxxx", "readme": "", "provider": "Aliyundrive", "related": null } } 系统设置 [scode type="blue"]GET /api/admin/setting/list[/scode] 请求参数 名称 位置 类型 必选 说明 group query integer 是 0-站点；1-样式；2-预览；3-全局；4-令牌；5-aria2 Authorization header string 是 token Content-Type header string 是 none 返回数据结构 名称 类型 必选 约束 中文名 说明 code integer true none 状态码 message string true none 信息 data [object] true none none key string true none 键 value string true none 值 help string true none none type string true none 类型 options string true none none group integer true none none flag integer true none none 返回示例 { "code": 200, "message": "success", "data": [ { "key": "version", "value": "v3.5.1", "help": "", "type": "string", "options": "", "group": 0, "flag": 2 }, { "key": "site_title", "value": "", "help": "", "type": "string", "options": "", "group": 0, "flag": 0 }, { "key": "announcement", "value": "", "help": "", "type": "text", "options": "", "group": 0, "flag": 0 }, { "key": "pagination_type", "value": "pagination", "help": "", "type": "select", "options": "all,pagination,load_more,auto_load_more", "group": 0, "flag": 0 }, { "key": "default_page_size", "value": "30", "help": "", "type": "number", "options": "", "group": 0, "flag": 0 } ] } 账户列表 [scode type="blue"]GET /api/admin/user/list[/scode] 请求参数 名称 位置 类型 必选 说明 Authorization header string 是 token 返回数据结构 名称 类型 必选 约束 中文名 说明 code integer true none 状态码 message string true none 信息 data null true none none content [object] true none none id integer true none id username string true none 用户名 password string true none 密码 base_path string true none 目录 role integer true none none permission integer true none 权限 total integer true none none 返回示例 { "code": 200, "message": "success", "data": { "content": [ { "id": 1, "username": "admin", "password": "", "base_path": "/", "role": 2, "permission": 0 }, { "id": 2, "username": "guest", "password": "", "base_path": "/", "role": 1, "permission": 0 } ], "total": 2 } } 存储列表 [scode type="blue"]GET /api/admin/storage/list[/scode] 请求参数 名称 位置 类型 必选 说明 Authorization header string 是 token 返回数据结构 名称 类型 必选 约束 中文名 说明 code integer true none 状态码 message string true none 信息 data null true none none content [object] true none none id integer false none id mount_path string false none 挂载路径 order integer false none 顺序 driver string false none 驱动类型 cache_expiration integer false none 缓存时间 status string false none 状态 addition string false none 额外信息 remark string false none 备注名 modified string false none 修改时间 disabled boolean false none 是否被禁用 order_by string false none 排序方式 order_direction string false none 排序方向 extract_folder string false none 提取目录顺序 web_proxy boolean false none http代理 webdav_policy string false none webdav策略 down_proxy_url string false none 下载代理url total integer true none none 返回示例 { "code": 200, "message": "success", "data": { "content": [ { "id": 1, "mount_path": "/阿里云盘", "order": 0, "driver": "Aliyundrive", "cache_expiration": 30, "status": "work", "addition": "{\"root_folder_id\":\"xxx\",\"refresh_token\":\"xxx\",\"order_by\":\"name\",\"order_direction\":\"ASC\",\"rapid_upload\":false}", "remark": "", "modified": "2022-11-26T18:55:55.261579727+08:00", "disabled": false, "order_by": "", "order_direction": "", "extract_folder": "", "web_proxy": false, "webdav_policy": "302_redirect", "down_proxy_url": "" } ], "total": 1 } } 启用存储 [scode type="blue"]POST /api/admin/storage/enable[/scode] 请求参数 名称 位置 类型 必选 说明 id query integer 是 存储id Authorization header string 是 token 返回数据结构 名称 类型 必选 约束 中文名 说明 code integer true none 状态码 message string true none 信息 data null true none none 返回示例 { "code": 200, "message": "success", "data": null } 禁用存储 [scode type="blue"]POST /api/admin/storage/disable[/scode] 请求参数 名称 位置 类型 必选 说明 id query string 是 存储id Authorization header string 是 token 返回数据结构 名称 类型 必选 约束 中文名 说明 code integer true none 状态码 message string true none 信息 data null true none none 返回示例 { "code": 200, "message": "success", "data": null } 新建存储 [scode type="blue"]POST /api/admin/storage/create[/scode] 请求参数 名称 位置 类型 必选 说明 Authorization header string 是 token body body object 否 none mount_path body string 是 挂载路径 order body integer 是 排序 remark body string 是 备注名 cache_expiration body integer 是 缓存过期时间 web_proxy body boolean 是 web代理 webdav_policy body string 是 webdav策略 down_proxy_url body string 是 下载代理 extract_folder body string 是 提取目录 driver body string 是 驱动 addition body string 是 额外信息 返回数据结构 名称 类型 必选 约束 中文名 说明 code integer true none 状态码 message string true none 信息 data null true none none id integer true none none 返回示例 { "code": 200, "message": "success", "data": { "id": 2 } } 查询指定存储信息 [scode type="blue"]GET /api/admin/storage/get[/scode] 请求参数 名称 位置 类型 必选 说明 id query string 是 存储id Authorization header string 是 token 返回数据结构 名称 类型 必选 约束 中文名 说明 code integer true none 状态码 message string true none 信息 data null true none none id integer true none id mount_path string true none 挂载路径 order integer true none 排序 driver string true none 驱动 cache_expiration integer true none 缓存过期时间 status string true none 状态 addition string true none 额外信息 remark string true none 备注 modified string true none 修改时间 disabled boolean true none 是否被禁用 order_by string true none 排序方式 order_direction string true none 排序方向 extract_folder string true none 提取目录 web_proxy boolean true none web代理 webdav_policy string true none webdav策略 down_proxy_url string true none 下载代理 返回示例 { "code": 200, "message": "success", "data": { "id": 2, "mount_path": "/阿里云盘2", "order": 1, "driver": "Aliyundrive", "cache_expiration": 30, "status": "work", "addition": "{\"root_folder_id\":\"\",\"refresh_token\":\"\",\"order_by\":\"size\",\"order_direction\":\"ASC\",\"rapid_upload\":false}", "remark": "", "modified": "2022-11-26T21:50:44.142348853+08:00", "disabled": false, "order_by": "", "order_direction": "", "extract_folder": "front", "web_proxy": false, "webdav_policy": "302_redirect", "down_proxy_url": "" } } 查询所有驱动配置模板列表 [scode type="blue"]GET /api/admin/driver/list[/scode] 请求参数 名称 位置 类型 必选 说明 Authorization header string 是 token 返回数据结构 名称 类型 必选 约束 中文名 说明 code integer true none 状态码 message string true none 信息 data null true none none common [object] true none none name string true none none type string true none none default string true none none options string true none none required boolean true none none help string true none none additional [object] true none none name string true none none type string true none none default string true none none options string true none none required boolean true none none help string true none none config object true none none name string true none none local_sort boolean true none none only_local boolean true none none only_proxy boolean true none none no_cache boolean true none none no_upload boolean true none none need_ms boolean true none none default_root string true none none CheckStatus boolean true none none 返回示例 { "code": 200, "message": "success", "data": { "115 Cloud": { "common": [ { "name": "mount_path", "type": "string", "default": "", "options": "", "required": true, "help": "" }, { "name": "order", "type": "number", "default": "", "options": "", "required": false, "help": "use to sort" }, { "name": "remark", "type": "text", "default": "", "options": "", "required": false, "help": "" }, { "name": "cache_expiration", "type": "number", "default": "30", "options": "", "required": true, "help": "The cache expiration time for this storage" }, { "name": "webdav_policy", "type": "select", "default": "native_proxy", "options": "use_proxy_url,native_proxy", "required": true, "help": "" }, { "name": "down_proxy_url", "type": "text", "default": "", "options": "", "required": false, "help": "" }, { "name": "extract_folder", "type": "select", "default": "", "options": "front,back", "required": false, "help": "" } ], "additional": [ { "name": "cookie", "type": "string", "default": "", "options": "", "required": false, "help": "" }, { "name": "qrcode_token", "type": "string", "default": "", "options": "", "required": false, "help": "" }, { "name": "root_folder_id", "type": "string", "default": "0", "options": "", "required": true, "help": "" } ], "config": { "name": "115 Cloud", "local_sort": false, "only_local": true, "only_proxy": true, "no_cache": false, "no_upload": false, "need_ms": false, "default_root": "0", "CheckStatus": false } } } } 删除指定存储 [scode type="blue"]POST /api/admin/storage/delete[/scode] 请求参数 名称 位置 类型 必选 说明 id query string 否 存储id Authorization header string 是 token 返回数据结构 名称 类型 必选 约束 中文名 说明 code integer true none 状态码 message string true none 信息 data null true none none 返回示例 { "code": 200, "message": "success", "data": null }
自定义头部代码 自定义内容代码 <meting-js fixed="true" autoplay="false" theme="#409EFF" list-folded="true" auto="QQ音乐或者网易云的链接"></meting-js> " "人生最大的遗憾,就是在最无能为力的时候遇到一个想要保护一生的人." " —— Anwen's Cloud QQ | 邮箱 | 博客 | 留言 | 云盘 | 管理 | Alist 其他代码： 黑猫： 白猫： 鼠标点击出随机颜色的爱心: Document 隐藏右上角复制直链、下载切换布局等: 全白无框： 备案信息： 2023 LINCROW.COM | 鄂ICP备xxxxxx号-x | 由Alist驱动 底部网站运行时间： 载入天数...载入时分秒... 自定义背景：替换url即可: 去掉底部的管理文字： 去掉底部的 Powered by Alist： 去掉底部Powered by Alist和管理文字： 其他总结： 其他背景混合渐变色彩 /* 背景混合色彩1 / .chakra-ui-light{ background-image: linear-gradient( 102.7deg,#fddaff 8.2%,#dfadfc 19.6%,#adcdfc 36.8%,#adfcf4 73.2%,#caf8d0 90.9%); background-attachment: fixed; } /* 背景混合色彩2 */ .chakra-ui-light{ background-image: linear-gradient(310deg, #7ec4e9 10%, #fff, #eee); background-attachment: fixed; }
[scode type="blue"]Windows server系列系统是支持多用户同时连接远程桌面独立使用互不影响的，但是常规版本并未直接支持。如果您使用Windows Vista、Windows 7/8/8.1/10的配置参考：https://github.com/stascorp/rdpwrap。`win11中无需安装此软件`。[/scode] 在Win11中配置多用户同时登陆远程桌面（并发远程桌面RDP）之前，请先确保已开启远程桌面并单用户访问运行正常。 配置远程桌面服务 打开编辑组策略应用，进入本地计算机策略-计算机配置-管理模板-Windows组件-远程桌面服务-远程桌面会话主机-连接。 启用允许用户通过使用远程桌面服务进行远程连接，启用限制连接的数量并按自己需求修改数量，启用将远程桌面服务用户限制到单独的远程桌面服务会话，这样设置的目的是使得多用户链接的时候重新链接能恢复之前的工作而不是新开启一个会话（丢失桌面）。另外，推荐客户端为MacOS的用户启用选择 RDP 传输协议并选择同时使用UDP和TCP，同时使用Microsoft Remote Desktop Beta优化使用体验。 复制系统文件 多用户同时使用远程桌面，会提示必须下线对端用户，为了实现多用户同时使用且互不干扰，需要修改win11操作系统的C:\Windows\System32\termsrv.dll文件。 先将该文件复制出来，此DLL文件可以使用任何HEX编辑器（例如 Tiny Hexer ）进行修改。 为方便大家使用，工具已打包提供下载：修改及使用.zip 解压并进入文件夹内，右击并以管理员权限运行。 运行完毕后，文件夹内会将C:\Windows\System32\termsrv.dll进来，并已更改可编辑权限。 手工修改方法 HEX编辑器查找（注意，查找的最后四组XX可以是任何数字）： 39 81 3C 06 00 00 0F 84 XX XX XX XX 替换为： B8 00 01 00 00 89 81 38 06 00 00 90 替换系统文件 以管理员权限运行运行附件文件夹里面的2_替换.bat文件，即可（运行文件会重启，请注意保存文件）。
Windows子系统（WSL）通过桥接网络实现被外部局域网主机直接访问
实现方法 思路就是将wsl2自建的虚拟NAT网络桥接到windows主机网卡上，主要参考这篇文章 1、开启hyper-v 桥接功能需要windows的hyper-v组件支持，但是win10/11家庭版是不包含hyper-v的，专业版才包含。网上也有文章提到家庭版安装hyper-v的方法，但是我没有测试，以下内容都是在win11专业版上进行的测试，win10专业版应该也是一样的。 首先，进入控制面板—程序—启用或关闭windows功能，勾选hyper-v，确认后重启电脑。 2、桥接网络 WSL2 默认采用了一个 NAT 网络，这对于大多数情况而言都是没有问题的，但是如果想要把 WSL 中的服务直接暴露出来，就不得不考虑做端口转发等问题。以及如果要使用 IPv6，自带的 NAT 方案也不能满足。 因此，这种时候如果能让 WSL2 使用直接接在 NIC 上自然是最好的，可惜 Windows 中没有直接提供这样的配置选项，如果在 Hyper-V 管理器中配置 WSL 网卡为外部网络则会直接报错。 万幸的是，可以使用 PowerShell 直接进行配置，本文则记录使用 PowerShell 让 WSL2 用上桥接网络的方法。 以下内容需要以管理员身份在PowerShell内执行。 一切开始之前首先需要启动 WSL，直接运行 wsl 即可，这样 WSL 的网卡才会被自动创建出来。 重启后首先运行wsl2（这样才能出现WSL的虚拟网卡），以管理员方式打开powershell，执行Get-NetAdapter，可以列出系统所有的网卡，记住想要桥接的网卡名称，比如我想桥接到有线网络其名称为“以太网”。 桥接网卡输入以下代码： Set-VMSwitch WSL -NetAdapterName 以太网 将wsl虚拟网络和主机有线网络桥接起来。 3、手动修改WSL网络 接下来进入 WSL 配置 IP 地址和网关，假设WSL的有线网络为eth0，网关为 192.168.1.1，IP 设置为 192.168.1.150/24： ip addr del $(ip addr show eth0 | grep 'inet\b' | awk '{print $2}' | head -n 1) dev eth0 ip addr add 192.168.148.64/24 broadcast 192.168.148.255 dev eth0 ip route add 0.0.0.0/0 via 192.168.148.1 dev eth0 接下来更新名称解析服务器地址，执行 nano /etc/resolv.conf，修改其中内容为 nameserver 192.168.1.1，然后按 Ctrl+X保存退出即可。 4、取消桥接 在windows中管理员方式打开powershell，执行以下指令： Set-VMSwitch WSL -SwitchType Internal 然后执行 wsl --shutdown 重启wsl，即可恢复原有的虚拟内部网络。 一键脚本 上述步骤太繁琐，为了简单操作，我编写了两个powershell脚本，可以一键执行网络桥接和取消网络桥接 1、wsl linux配置网络脚本 进入wsl，在wsl的home目录下新建一个脚本文件，例如set_eth0.sh，其内容如下： #!/bin/bash new_ip=192.168.148.64 brd=192.168.148.255 gateway=192.168.148.1 nameserver=192.168.148.1 net_dev=eth0 echo "password" | sudo -S ip addr del $(ip addr show $net_dev | grep 'inet\b' | awk '{print $2}' | head -n 1) dev $net_dev sudo ip addr add $new_ip/24 broadcast $brd dev $net_dev sudo ip route add 0.0.0.0/0 via $gateway dev $net_dev sudo sed -i "\$c nameserver $nameserver" /etc/resolv.conf 注意将new_ip、brd、nameserver、gateway、net_dev分别修改为实际想要设定的值，另外将echo "password" | 中的password替换为wsl的用户密码。 2、powershell桥接网络脚本 在windows中新建一个ps1文件，例如wsl-bridge-on.ps1（ps1是powershell的脚本，其脚本语言和以前的bat是不一样的） 内容如下： # 检查并以管理员身份运行PS并带上参数 $currentWi = [Security.Principal.WindowsIdentity]::GetCurrent() $currentWp = [Security.Principal.WindowsPrincipal]$currentWi if( -not $currentWp.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { $boundPara = ($MyInvocation.BoundParameters.Keys | foreach{'-{0} {1}' -f $_ ,$MyInvocation.BoundParameters[$_]} ) -join ' ' $currentFile = $MyInvocation.MyCommand.Definition $fullPara = $boundPara + ' ' + $args -join ' ' Start-Process "$psHome\pwsh.exe" -ArgumentList "$currentFile $fullPara" -verb runas return } #首先随意执行一条wsl指令，确保wsl启动，这样后续步骤才会出现WSL网络 echo "正在检测wsl运行状态..." wsl --cd ~ -e ls echo "正在获取网卡信息..." Get-NetAdapter echo "`n正在将WSL网络桥接到以太网..." Set-VMSwitch WSL -NetAdapterName 以太网 echo "`n正在修改WSL网络配置..." wsl --cd ~ -e sh -c ./set_eth0.sh echo "`ndone" pause 最前面那一段是用来检查运行脚本的powershell有没有管理员权限，如果没有，则重新打开一个需要申请管理员权限的powershell； 然后随意执行一条wsl指令，这样如果wsl在后台未启动的情况下会自动启动，确保出现WSL的虚拟网卡；接下来就是网络桥接指令，注意把Set-VMSwitch WSL -NetAdapterName 以太网中的“以太网”改为你自己机器的网卡名称。最后是用到了windows和wsl混合命令，直接调用wsl执行linux脚本修改linux的网络配置。这里linux脚本就是步骤1中新建的set_eth0.sh，保存在home路径下。 3、powershell取消桥接脚本 在windows中新建一个ps1文件，例如wsl-bridge-off.ps1 # 检查并以管理员身份运行PS并带上参数 $currentWi = [Security.Principal.WindowsIdentity]::GetCurrent() $currentWp = [Security.Principal.WindowsPrincipal]$currentWi if( -not $currentWp.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { $boundPara = ($MyInvocation.BoundParameters.Keys | foreach{'-{0} {1}' -f $_ ,$MyInvocation.BoundParameters[$_]} ) -join ' ' $currentFile = $MyInvocation.MyCommand.Definition $fullPara = $boundPara + ' ' + $args -join ' ' Start-Process "$psHome\pwsh.exe" -ArgumentList "$currentFile $fullPara" -verb runas return } echo "正在解除wsl桥接..." Set-VMSwitch WSL -SwitchType Internal echo "正在重启wsl" wsl --shutdown wsl --cd ~ -e ls echo "`ndone" pause 最前面一段同样是检查管理员权限，然后执行解除桥接指令，最后重启wsl，就完成了 4、配置脚本属性 分别右键wsl-bridge-on.ps1和wsl-bridge-off.ps1这两个脚本，在打开方式中选择其它应用，找到powershell安装路径下的可执行文件pwsh.exe，勾选始终使用此应用打开.ps1文件，这样就可以直接双击运行了。不过，默认情况下windows powershell不允许执行自定义脚本，所以需要修改设置打开执行权限。管理员方式打开powershell，执行Set-ExecutionPolicy Unrestricted 或 Set-ExecutionPolicy RemoteSigned ，按y确认即可 5、使用方法 需要桥接wsl网络的时候直接双击运行wsl-bridge-on.ps1，出现申请管理员权限的时候按是确认，然后等待脚本执行完毕即可。取消桥接则运行wsl-bridge-off.ps1，也是同样的流程。
开篇 我们都知道，wsl安装完成后，通过命令行输入wsl即可进入系统，但是Windows cmd窗口真的不太友好，那么，我们有没有办法通过xshell等sshclient工具来进行连接进行操作呢？那么，本篇我们一起来学习一下吧。 那么，这里我们一般有2种方式来建立ssh连接。 ssh client连接 （一）生成密匙 这里需要注意的是，如果wsl不存在ssh服务，则直接跳到第二种方式进行操作，如果存在，建议先执行该种方式进行体验，若不成功，则再跳到第二种方式将会更明白个中道理。 一般wsl自带ssh服务，首先我们启动服务 service ssh restart 此时可能报错 sshd: no hostkeys available -- exiting. 这里可能有2种原因，一是当前用户非root用户，此时切换到root用户执行即可，二是可能缺少密匙文件，可进入/etc/ssh查看是否存在下图中2个文件，若不存在，执行以下命令生成即可。 $ sudo ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key $ sudo ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key 服务启动成功后，通过命令行以下方式进行连接 ssh jack@localhost The authenticity of host 'localhost (127.0.0.1)' can't be established. RSA 即可登录，但这里是使用密匙登录，要想通过账号密码登录，则需要修改配置文件。 修改完配置文件后，通过 输入密码即可登录。 这里需要注意的是，这里既可以通过local host也可以通过ip来进行访问，并不像其他教程里所说的一样需要进行端口转发，端口转发并不是用在这种情况下的，后面会讲解。 （二）删除并重新安装sshopen-server 这种方法网上随处可见，为了全面，我这里也记录一下，基本上分为以下几步。 1.卸载openssh-server apt remove openssh-server 2.安装openssh-server apt install openssh-server 3.修改配置文件 # 编辑/etc/ssh/sshd_config文件。 vi /etc/ssh/sshd_config 修改ip和port 修改允许root访问 修改允许用户名密码登录 4.重启 sudo service ssh restart 此时即可通过ssh进行连接或通过xshell等工具进行连接 （三）完成以上连接后，是否可以通过其他电脑来访问wsl? 毫无疑问是可以的！！!那么这步我们就需要配置防火墙出入站规则以及端口转发规则了 如果防火墙开启，那我们需要配置防火墙规则同时需要配置端口转发规则 1.配置端口转发规则 意思就是，访问到物理机的22端口的请求，转发到wsl的22端口，[IP]为wsl的ip [PORT]为wsl的端口 netsh interface portproxy add v4tov4 listenaddress=0.0.0.0 listenport=22 connectaddress=[IP] connectport=[PORT] 2.配置防火墙出入站规则 这是安全规则，如果防火墙关闭的话则不用配置， netsh advfirewall firewall add rule name=WSL2 dir=in action=allow protocol=TCP localport=22 配置完以上两步后，我们则可以通过外网来访问我们的wsl （例如，本机ip是1.2.3.4，wsl地址是172.16.12.1） 那么，远程访问时，通过 ssh root@1.2.3.4 -p 22 即可连接到wsl。 网上说，要连接到wsl时，wsl必须保持打开状态，也就是命令行窗口不能关闭，其实这是一个误区！！！ 经过验证，即使所有的命令行都关闭，只要wsl不是shutdown状态，ssh服务正常开启，那么就可以通过ssh进行连接！！！ 其实，通过这一步可以自由的配置本地端口与wsl端口的映射，也就是可以通过物理机来进行网站或应用程序的访问，比如，我们再wsl部署一个网站，我们可以直接将该网站的端口xxxx映射到物理机的8080（举例），那么我们通过本机ip:8080即可访问该网站，大大提高我们的易操作性。 但是不是到这里就万事大吉了呢？并不是，因为wsl每次重启，ip地址都会变化，也就是说通过以上步骤添加的映射规则再wsl重启后就失效了！【刚开始不知道，第一次配置好wsl后，第二天来开机就懵逼了，一通瞎操作才整明白】，所以，我们还的想办法来固定wsl的ip地址，以保证规则永久有效。 1.首先，下载wsl2host.exe wsl2host.exe 下载 2.管理员运行cmd，然后切换到wsl2host.exe目录下，执行 wsl2host.exe install Windows Username: xxx Windows Password:xxx 若不报错，则证明安装成功，打开服务，查找wsl2host查看状态，若为停止，手动启动 若启动失败，则打开本地组策略，进行如下设置 此时即可启动服务成功，打开C:\Windows\System32\drivers\etc\hosts，可以查看到 证明添加成功，之后，我们就再也不用担心wsl重启导致的IP变动问题了。 如果是家庭版win10，那么可以 @echo off pushd "%~dp0" dir /b C:\Windows\servicing\Packages\Microsoft-Windows-GroupPolicy-ClientExtensions-Package~3*.mum >List.txt dir /b C:\Windows\servicing\Packages\Microsoft-Windows-GroupPolicy-ClientTools-Package~3*.mum >>List.txt for /f %%i in ('findstr /i . List.txt 2^>nul') do dism /online /norestart /add-package:"C:\Windows\servicing\Packages\%%i" pause 复制以上内容到一个文本***.bat中，使用管理员运行即可。 经测试，当wsl --shutdown时，hosts文件中wsl域名行会消失，当wsl启动时，会自动添加。 附：常用命令 //端口转发 netsh interface portproxy add v4tov4 listenport=80 listenaddress=0.0.0.0 connectport=80 connectaddress=172.27.156.29 //转发80端口 netsh interface portproxy add v4tov4 listenport=443 listenaddress=0.0.0.0 connectport=443 connectaddress=172.27.156.29 //转发443端口 //查看转发 netsh interface portproxy show v4tov4 netsh interface portproxy show all //删除所有转发 netsh interface portproxy reset //配置防火墙 netsh advfirewall firewall add rule name=WSL2 dir=in action=allow protocol=TCP localport=[端口] //查看防火墙 netsh advfirewall firewall show rule name=WSL2 //删除防火墙 netsh advfirewall firewall delete rule name=WSL2 dir=in
调用 $webhook = '机器人地址'; //推送地址 $webhookdata = array( 'msgtype' => 'text', //文本类型 'content' => '测试消息', // 文本内容 'mentioned_list' => '', //@某个人 "@all"为全员 'mentioned_mobile_list' => '' //@手机号 "@all"为全员 ); $this->WorkRoboot($webhook,$webhookdata); 推送 public function WorkRoboot($webhook,$webhookdata){ $postdata['msgtype'] = $webhookdata['msgtype']; //接收类型 $postdata[$postdata['msgtype']]['content'] = $webhookdata['content']; //接收内容 if (!empty($webhookdata['mentioned_list'])) { $postdata[$postdata['msgtype']]['mentioned_list'] = $webhookdata['mentioned_list']; } if (!empty($webhookdata['mentioned_mobile_list'])) { $postdata[$postdata['msgtype']]['mentioned_mobile_list'] = $webhookdata['mentioned_mobile_list']; } // 初始化 $curl = curl_init(); // 设置url curl_setopt($curl, CURLOPT_URL, $webhook); // 设置头文件的信息作为数据流输出 curl_setopt($curl, CURLOPT_HEADER, true); // 设置获取的信息以文件流的形式返回，而不是直接输出。 curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); // 设置提交方式是utf8编码 curl_setopt($curl, CURLOPT_HTTPHEADER,array('Content-Type: application/json;charset=utf-8')); // 设置post方式提交 curl_setopt($curl, CURLOPT_POST, true); // 设置允许 cURL 函数执行的最长秒数 curl_setopt($curl, CURLOPT_TIMEOUT, 500); // 设置post数据 curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($postdata)); // 关闭就行 curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false); // 执行命令 $data = curl_exec($curl); // 关闭URL请求 curl_close($curl); }