mirror of
https://github.com/Mabbs/mabbs.github.io
synced 2025-09-29 01:05:41 +08:00
Compare commits
35 Commits
AR-Backup-
...
AR-Backup-
Author | SHA1 | Date | |
---|---|---|---|
2fd191d418 | |||
99ec7de3cd | |||
cd294479e0 | |||
b7ab4e6356 | |||
934c04aea7 | |||
5c7773fb59 | |||
41ce7aabb0 | |||
cbe4db5992 | |||
04e63388b6 | |||
106aa95def | |||
f1e7070380 | |||
10a3521795 | |||
881ed13576 | |||
982a87e0bf | |||
5097364988 | |||
c437b255f1 | |||
efaaa32674 | |||
8a51f7a942 | |||
afe8b95115 | |||
2aad4be863 | |||
74cb7d028c | |||
d74fe7b4b8 | |||
8f7d02697d | |||
4afea923c5 | |||
e6281bfa5f | |||
a4e9d17cf1 | |||
975fcf9d8e | |||
1734d36dd5 | |||
eefdb73475 | |||
c622346eaa | |||
7609bb0b8f | |||
2298c9b271 | |||
f9abd1e5d7 | |||
62ea62e8e8 | |||
3dc82a814a |
@ -6,14 +6,14 @@
|
|||||||
|
|
||||||
# Template project: https://gitlab.com/pages/jekyll
|
# Template project: https://gitlab.com/pages/jekyll
|
||||||
# Docs: https://docs.gitlab.com/ee/pages/
|
# Docs: https://docs.gitlab.com/ee/pages/
|
||||||
image: ruby:2.6
|
image: ruby:2.7
|
||||||
|
|
||||||
variables:
|
variables:
|
||||||
JEKYLL_ENV: production
|
JEKYLL_ENV: production
|
||||||
LC_ALL: C.UTF-8
|
LC_ALL: C.UTF-8
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- gem install bundler
|
- gem install bundler -v 2.4.22
|
||||||
- bundle install
|
- bundle install
|
||||||
|
|
||||||
pages:
|
pages:
|
||||||
|
16
Gemfile
16
Gemfile
@ -1,11 +1,13 @@
|
|||||||
source "https://rubygems.org"
|
source "https://rubygems.org"
|
||||||
gem "jekyll", "~> 4.1.0"
|
gem "jekyll", "~> 3.9.3"
|
||||||
group :jekyll_plugins do
|
group :jekyll_plugins do
|
||||||
gem "jekyll-gist"
|
gem "jekyll-gist", "~> 1.5.0"
|
||||||
gem "jekyll-coffeescript"
|
gem "jekyll-coffeescript", "~> 1.1.1"
|
||||||
gem "jekyll-assets"
|
gem "jekyll-assets", "~> 1.0.0"
|
||||||
gem "jekyll-sitemap"
|
gem "jekyll-sitemap", "~> 1.4.0"
|
||||||
gem "jekyll-feed"
|
gem "jekyll-feed", "~> 0.15.1"
|
||||||
gem "jekyll-theme-minimal"
|
gem "jekyll-theme-minimal"
|
||||||
gem "jekyll-paginate"
|
gem "jekyll-paginate", "~> 1.1.0"
|
||||||
|
gem "kramdown-parser-gfm", "~> 1.1.0"
|
||||||
|
gem "kramdown", "~> 2.3.2"
|
||||||
end
|
end
|
||||||
|
@ -290,15 +290,15 @@ if(!norunFlag){
|
|||||||
url: talkAPI,
|
url: talkAPI,
|
||||||
data: {
|
data: {
|
||||||
"info": info_,
|
"info": info_,
|
||||||
"userid":userid_
|
"userId": userid_
|
||||||
},
|
},
|
||||||
success: function(res) {
|
success: function(res) {
|
||||||
if(res.code !== 100000){
|
if(res.intent.code !== 0){
|
||||||
talkValTimer();
|
talkValTimer();
|
||||||
showMessage('似乎有什么错误,请和站长联系!',0);
|
showMessage('似乎有什么错误,请和站长联系!',0);
|
||||||
}else{
|
}else{
|
||||||
talkValTimer();
|
talkValTimer();
|
||||||
showMessage(res.text,0);
|
showMessage(res.results[0].values.text,0);
|
||||||
}
|
}
|
||||||
console.log(res);
|
console.log(res);
|
||||||
$('#AIuserText').val("");
|
$('#AIuserText').val("");
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
@ -26,26 +27,6 @@
|
|||||||
|
|
||||||
gtag('config', '{{ site.google_analytics }}');
|
gtag('config', '{{ site.google_analytics }}');
|
||||||
var lastUpdated = new Date("{{ site.time | date: "%FT%T%z" }}");
|
var lastUpdated = new Date("{{ site.time | date: "%FT%T%z" }}");
|
||||||
Date.prototype.format = function(fmt) {
|
|
||||||
var o = {
|
|
||||||
"M+" : this.getMonth()+1, //月份
|
|
||||||
"d+" : this.getDate(), //日
|
|
||||||
"h+" : this.getHours(), //小时
|
|
||||||
"m+" : this.getMinutes(), //分
|
|
||||||
"s+" : this.getSeconds(), //秒
|
|
||||||
"q+" : Math.floor((this.getMonth()+3)/3), //季度
|
|
||||||
"S" : this.getMilliseconds() //毫秒
|
|
||||||
};
|
|
||||||
if(/(y+)/.test(fmt)) {
|
|
||||||
fmt=fmt.replace(RegExp.$1, (this.getFullYear()+"").substr(4 - RegExp.$1.length));
|
|
||||||
}
|
|
||||||
for(var k in o) {
|
|
||||||
if(new RegExp("("+ k +")").test(fmt)){
|
|
||||||
fmt = fmt.replace(RegExp.$1, (RegExp.$1.length==1) ? (o[k]) : (("00"+ o[k]).substr((""+ o[k]).length)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return fmt;
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<style>
|
<style>
|
||||||
@ -69,28 +50,34 @@
|
|||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<header>
|
<header>
|
||||||
<h1><a href="{{ "/" | relative_url }}">{{ site.title | default: site.github.repository_name }}</a></h1>
|
<h1><a href="{{ "/" | relative_url }}">{{ site.title | default: site.github.repository_name }}</a></h1>
|
||||||
|
|
||||||
{% if site.logo %}
|
{% if site.logo %}
|
||||||
<img src="{{ site.logo | relative_url}}" alt="Logo" />
|
<img src="{{ site.logo }}" alt="Logo" />
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<p>{{ site.description | default: site.github.project_tagline }}</p>
|
<p>{{ site.description | default: site.github.project_tagline }}</p>
|
||||||
|
|
||||||
<p><form action="/search.html"><input type="text" name="keyword" id="search-input-all" placeholder="Search blog posts.."> <input type="submit"></form></p>
|
<p>
|
||||||
|
<form action="/search.html"><input type="text" name="keyword" id="search-input-all" placeholder="Search blog posts..">
|
||||||
|
<input type="submit">
|
||||||
|
</form>
|
||||||
|
</p>
|
||||||
|
|
||||||
{% if site.github.is_project_page %}
|
{% if site.github.is_project_page %}
|
||||||
<p class="view"><a href="{{ site.github.repository_url }}">View the Project on GitHub <small>{{ site.github.repository_nwo }}</small></a></p>
|
<p class="view"><a href="{{ site.github.repository_url }}">View the Project on GitHub
|
||||||
|
<small>{{ site.github.repository_nwo }}</small></a></p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if site.github.is_user_page %}
|
{% if site.github.is_user_page %}
|
||||||
<p class="view"><a href="{{ site.github.owner_url }}">View My GitHub Profile</a></p>
|
<p class="view"><a href="{{ site.github.owner_url }}">View My GitHub Profile</a></p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<p class="view"><a href="{{ "/Mabbs/" | relative_url }}">About Me</a></p>
|
<p class="view"><a href="/Mabbs/">About Me</a></p>
|
||||||
|
|
||||||
<ul class="downloads">
|
<ul class="downloads">
|
||||||
{% if site.github %}
|
{% if site.github %}
|
||||||
@ -135,10 +122,9 @@
|
|||||||
<div id="open_live2d">召唤伊斯特瓦尔</div>
|
<div id="open_live2d">召唤伊斯特瓦尔</div>
|
||||||
<!-- <![endif]-->
|
<!-- <![endif]-->
|
||||||
<footer>
|
<footer>
|
||||||
<p><small>Made with ❤ by Mayx<br />Last updated at <script>document.write(lastUpdated.format("yyyy-MM-dd hh:mm:ss"));</script><br /> 总字数:
|
<p>
|
||||||
{% assign count = 0 %}{% for post in site.posts %}{% assign single_count = post.content | strip_html | strip_newlines | remove: " " | size %}
|
<small>Made with ❤ by Mayx<br />Last updated at <script>document.write(lastUpdated.toLocaleString());</script><br /> 总字数:{% assign count = 0 %}{% for post in site.posts %}{% assign single_count = post.content | strip_html | strip_newlines | remove: " " | size %}{% assign count = count | plus: single_count %}{% endfor %}{% if count > 10000 %}{{ count | divided_by: 10000 }} 万 {{ count | modulo: 10000 }}{% else %}{{ count }}{% endif %} - 文章数:{% for post in site.posts %}{% assign co = co | plus: 1 %}{% endfor %}{{ co }} - <a href="{{ "/atom.xml" | relative_url }}" >Atom</a> - <a href="{{ "/README.html" | relative_url }}" >About</a></small>
|
||||||
{% assign count = count | plus: single_count %}{% endfor %}{% if count > 10000 %}{{ count | divided_by: 10000 }} 万 {{ count | modulo: 10000 }}
|
</p>
|
||||||
{% else %}{{ count }}{% endif %} - 文章数:{% for post in site.posts %}{% assign co = co | plus: 1 %}{% endfor %}{{ co }} - <a href="{{ "/atom.xml" | relative_url }}" >Atom</a> - <a href="{{ "/README.html" | relative_url }}" >About</a></small></p>
|
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
<script src="{{ "/assets/js/scale.fix.js" | relative_url }}"></script>
|
<script src="{{ "/assets/js/scale.fix.js" | relative_url }}"></script>
|
||||||
@ -150,4 +136,5 @@
|
|||||||
|
|
||||||
<!-- <![endif]-->
|
<!-- <![endif]-->
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
@ -2,8 +2,7 @@
|
|||||||
layout: default
|
layout: default
|
||||||
---
|
---
|
||||||
|
|
||||||
<small>{{ page.date | date: "%-d %B %Y" }} - 字数统计:{% if page.layout == "encrypt" %}God Knows {% else %}{{ page.content | strip_html | strip_newlines | remove: " " | size }} - 阅读大约需要{{ page.content | strip_html | strip_newlines | remove: " " | size | divided_by: 350 | plus: 1 }}分钟{% endif %} - Hits: <span id="{{ page.url }}" class="visitors" >Loading...</span>
|
<small>{{ page.date | date: "%-d %B %Y" }} - 字数统计:{% if page.layout == "encrypt" %}God Knows {% else %}{{ page.content | strip_html | strip_newlines | remove: " " | size }} - 阅读大约需要{{ page.content | strip_html | strip_newlines | remove: "" | size | divided_by: 350 | plus: 1 }}分钟{% endif %} - Hits: <span id="{{ page.url }}" class="visitors">Loading...</span></small>
|
||||||
</small>
|
|
||||||
<h1>{{ page.title }}</h1>
|
<h1>{{ page.title }}</h1>
|
||||||
|
|
||||||
<p class="view">by <a href="//github.com/{{ page.author | default: "Mabbs" }}">{{ page.author | default: site.author }}</a></p>
|
<p class="view">by <a href="//github.com/{{ page.author | default: "Mabbs" }}">{{ page.author | default: site.author }}</a></p>
|
||||||
@ -26,6 +25,53 @@ if (daysold > 90) {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<hr />
|
<hr />
|
||||||
|
{% if page.layout != "encrypt" %}
|
||||||
|
<!--[if !IE]> -->
|
||||||
|
<b>AI摘要</b>
|
||||||
|
<p id="ai-output">正在生成中……</p>
|
||||||
|
<script>
|
||||||
|
async function sha(str) {
|
||||||
|
const encoder = new TextEncoder();
|
||||||
|
const data = encoder.encode(str);
|
||||||
|
const hashBuffer = await crypto.subtle.digest("SHA-256", data);
|
||||||
|
const hashArray = Array.from(new Uint8Array(hashBuffer)); // convert buffer to byte array
|
||||||
|
const hashHex = hashArray
|
||||||
|
.map((b) => b.toString(16).padStart(2, "0"))
|
||||||
|
.join(""); // convert bytes to hex string
|
||||||
|
return hashHex;
|
||||||
|
}
|
||||||
|
async function ai_gen(){
|
||||||
|
var postContent = "文章标题:" + {{ page.title | jsonify }} + ";文章内容:" + {{ page.content | strip_html | strip_newlines | jsonify }};
|
||||||
|
var postContentSign = await sha(postContent);
|
||||||
|
var outputContainer = document.getElementById("ai-output");
|
||||||
|
$.get("https://summary.mayx.eu.org/is_uploaded?id={{ page.url }}&sign=" + postContentSign, function (data) {
|
||||||
|
if (data == "yes") {
|
||||||
|
$.get("https://summary.mayx.eu.org/get_summary?id={{ page.url }}&sign=" + postContentSign, function (data2) {
|
||||||
|
outputContainer.textContent = data2;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
$.post("https://summary.mayx.eu.org/upload_blog?id={{ page.url }}", postContent, function (data) {
|
||||||
|
$.get("https://summary.mayx.eu.org/get_summary?id={{ page.url }}&sign=" + postContentSign);
|
||||||
|
const evSource = new EventSource("https://summary.mayx.eu.org/summary?id={{ page.url }}");
|
||||||
|
outputContainer.textContent = "";
|
||||||
|
evSource.onmessage = (event) => {
|
||||||
|
if (event.data == "[DONE]") {
|
||||||
|
evSource.close();
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
const data = JSON.parse(event.data);
|
||||||
|
outputContainer.textContent += data.response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
ai_gen();
|
||||||
|
</script>
|
||||||
|
<hr />
|
||||||
|
<!-- <![endif]-->
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% include toc.html html=content sanitize=true h_max=3 %}
|
{% include toc.html html=content sanitize=true h_max=3 %}
|
||||||
|
|
||||||
@ -60,8 +106,7 @@ if (daysold > 90) {
|
|||||||
<div id="gitalk-container"></div>
|
<div id="gitalk-container"></div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
if (window.location.host != "mabbs.github.io")
|
if (window.location.host != "mabbs.github.io") {
|
||||||
{
|
|
||||||
var gitalk = new Gitalk({
|
var gitalk = new Gitalk({
|
||||||
clientID: '098934a2556425f19d6e',
|
clientID: '098934a2556425f19d6e',
|
||||||
clientSecret: '0bd44eed8425e5437ce43c4ba9b2791fbc04581d',
|
clientSecret: '0bd44eed8425e5437ce43c4ba9b2791fbc04581d',
|
||||||
@ -72,8 +117,7 @@ var gitalk = new Gitalk({
|
|||||||
distractionFreeMode: false // Facebook-like distraction free mode
|
distractionFreeMode: false // Facebook-like distraction free mode
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
var gitalk = new Gitalk({
|
var gitalk = new Gitalk({
|
||||||
clientID: '36557aec4c3cb04f7ac6',
|
clientID: '36557aec4c3cb04f7ac6',
|
||||||
clientSecret: 'ac32993299751cb5a9ba81cf2b171cca65879cdb',
|
clientSecret: 'ac32993299751cb5a9ba81cf2b171cca65879cdb',
|
||||||
|
@ -28,7 +28,7 @@ tags: [Apple, MacBook, 体验]
|
|||||||
## 游戏体验
|
## 游戏体验
|
||||||
众所周知,MacBook很不适合用来打游戏,因为大多数游戏都是在Windows上编写的。不过我已经安装了Windows11ARM的虚拟机,如果用来跑游戏效果会怎么样呢?我从我原来用的电脑上传了一个Galgame过来,打开试了一下,卡的不得了,不知道是因为没法调用显卡还是怎么回事,感觉帧率就10fps的样子,我在我原来的电脑上运行了一下试了试,运行非常流畅。连运行Galgame都这么垃圾,其他游戏估计更不用说了。不过这估计也是因为是虚拟机的缘故,所以我想找找MacOS支持的游戏。去Apple Store下载游戏……都要花钱,不过我看到我的MacBook作为Pro,有个Touch Bar,所以想整个Touch Bar的游戏,正好看到了个打砖块,试了试效果还不错。
|
众所周知,MacBook很不适合用来打游戏,因为大多数游戏都是在Windows上编写的。不过我已经安装了Windows11ARM的虚拟机,如果用来跑游戏效果会怎么样呢?我从我原来用的电脑上传了一个Galgame过来,打开试了一下,卡的不得了,不知道是因为没法调用显卡还是怎么回事,感觉帧率就10fps的样子,我在我原来的电脑上运行了一下试了试,运行非常流畅。连运行Galgame都这么垃圾,其他游戏估计更不用说了。不过这估计也是因为是虚拟机的缘故,所以我想找找MacOS支持的游戏。去Apple Store下载游戏……都要花钱,不过我看到我的MacBook作为Pro,有个Touch Bar,所以想整个Touch Bar的游戏,正好看到了个打砖块,试了试效果还不错。
|
||||||
当然用MacBook光看打砖块流畅那就没啥意义了,所以再升点级,试试三维弹球吧😝,之前我在网上看到一个开源版本的三维弹球,叫做[SpaceCadetPinball](https://github.com/k4zmu2a/SpaceCadetPinball),是用Windows XP自带的那个版本逆向出来的,我看了一眼是支持在MacOS上运行的,于是就下载下来编译了一下,效果确实不错,不过我又试了一下在Windows原生的版本,一样很流畅啊😂,而且不知道为什么感觉开源的这个版本缓冲器不太对劲,弹的没原生的舒服……这试游戏没必要针对弹球游戏吧😂。
|
当然用MacBook光看打砖块流畅那就没啥意义了,所以再升点级,试试三维弹球吧😝,之前我在网上看到一个开源版本的三维弹球,叫做[SpaceCadetPinball](https://github.com/k4zmu2a/SpaceCadetPinball),是用Windows XP自带的那个版本逆向出来的,我看了一眼是支持在MacOS上运行的,于是就下载下来编译了一下,效果确实不错,不过我又试了一下在Windows原生的版本,一样很流畅啊😂,而且不知道为什么感觉开源的这个版本缓冲器不太对劲,弹的没原生的舒服……这试游戏没必要针对弹球游戏吧😂。
|
||||||
不过我也不知道MacOS支持什么游戏,想了想我在Epicgames上白嫖了不少游戏,干脆下载下来看看都有啥支持吧。看了一圈while True:learn()居然支持,然后就下载下来试了一下,不过这个基本上也没啥特效啥的,就是那种逻辑推理游戏,也展现不出什么,不过我原来的电脑运行这个游戏的时候风扇就开始高速转起来了,MacBook能完全没声音应该还是证明有点东西的。
|
不过我也不知道MacOS支持什么游戏,想了想我在Epic Games上白嫖了不少游戏,干脆下载下来看看都有啥支持吧。看了一圈while True:learn()居然支持,然后就下载下来试了一下,不过这个基本上也没啥特效啥的,就是那种逻辑推理游戏,也展现不出什么,不过我原来的电脑运行这个游戏的时候风扇就开始高速转起来了,MacBook能完全没声音应该还是证明有点东西的。
|
||||||
不过我也不一定非要考虑电脑游戏,我也可以考虑一下手机游戏,毕竟MacOS在M系列芯片上是可以运行iOS软件的,不过系统做了一些限制,不是所有都支持,所以我就下了一个[PlayCover](https://github.com/PlayCover/PlayCover),在上面安装了公主连结 Re:Dive。效果还挺不错的,完全不卡,不过运行的时候可以明显感觉有点开始发热了,我浏览网页看视频的时候完全不发热,看来这个游戏还是挺费资源的。
|
不过我也不一定非要考虑电脑游戏,我也可以考虑一下手机游戏,毕竟MacOS在M系列芯片上是可以运行iOS软件的,不过系统做了一些限制,不是所有都支持,所以我就下了一个[PlayCover](https://github.com/PlayCover/PlayCover),在上面安装了公主连结 Re:Dive。效果还挺不错的,完全不卡,不过运行的时候可以明显感觉有点开始发热了,我浏览网页看视频的时候完全不发热,看来这个游戏还是挺费资源的。
|
||||||
## 综合体验
|
## 综合体验
|
||||||
经过这些天的使用,我感触最深的就是这台电脑的续航了,别说一天不充电,感觉两三天不充电都没问题,毕竟标称续航是20小时,可以算是续航最强的笔记本电脑了。不过这样的话感觉就更像是大号手机/平板那样了,用的时候不充电,24小时不用关机,感觉和手机差不多,相比平板功能还是更多,要是说用iPad那个东西可没有终端,越狱也还是比不了MacOS。而相比Android平板,我之前还在上面[试过Termux](/2022/02/15/termux.html),不过问题和越狱差不多,支持的东西还是不如MacOS,虽然MacOS也不是开源的,但是对我来说我感觉那个终端就像Linux那个终端差不多,加上HomeBrew效果还是挺不错的,另外MacBook比平板的续航更长,就是重量也更重了。
|
经过这些天的使用,我感触最深的就是这台电脑的续航了,别说一天不充电,感觉两三天不充电都没问题,毕竟标称续航是20小时,可以算是续航最强的笔记本电脑了。不过这样的话感觉就更像是大号手机/平板那样了,用的时候不充电,24小时不用关机,感觉和手机差不多,相比平板功能还是更多,要是说用iPad那个东西可没有终端,越狱也还是比不了MacOS。而相比Android平板,我之前还在上面[试过Termux](/2022/02/15/termux.html),不过问题和越狱差不多,支持的东西还是不如MacOS,虽然MacOS也不是开源的,但是对我来说我感觉那个终端就像Linux那个终端差不多,加上HomeBrew效果还是挺不错的,另外MacBook比平板的续航更长,就是重量也更重了。
|
||||||
|
@ -7,7 +7,7 @@ tags: [AI, LLM, 人工智能]
|
|||||||
最近人工智能发展的还真是不错啊……<!--more-->
|
最近人工智能发展的还真是不错啊……<!--more-->
|
||||||
|
|
||||||
# 起因
|
# 起因
|
||||||
最近ChatGPT为代表的人工智能发展的越来越好了,而且因为它对生产力的提升使得了解AI的人也越来越多了。虽然我也不算是对AI很感兴趣,但是我在Github Copilot刚出的时候就已经用上了,到现在一直在用(不过毕业了以后估计就用不了了吧😂)。不过那时候Copilot毕竟专业性比较高,知道的人也比较少,不像现在ChatGPT能在各行各业使用,甚至还有基于类似模型的Vtuber,比如[Neuro-sama](https://www.twitch.tv/vedel987),所以即使是普通人使用它,都能够减轻自己的工作压力,所以现在的人们都在讨论它。
|
最近ChatGPT为代表的人工智能发展的越来越好了,而且因为它对生产力的提升使得了解AI的人也越来越多了。虽然我也不算是对AI很感兴趣,但是我在Github Copilot刚出的时候就已经用上了,到现在一直在用(不过毕业了以后估计就用不了了吧😂)。不过那时候Copilot毕竟专业性比较高,知道的人也比较少,不像现在ChatGPT能在各行各业使用,甚至还有基于类似模型的Vtuber,比如[Neuro-sama](https://www.twitch.tv/vedal987),所以即使是普通人使用它,都能够减轻自己的工作压力,所以现在的人们都在讨论它。
|
||||||
当然在这之前,还有一些很厉害的画图AI,比如使用了Stable Difusion的NovalAI,以及Midjourney啥的,不过因为我对画图并不感兴趣,所以它发展的有多好也基本上和我没有关系。其实除了这些能够AIGC的模型之外,在那之前还有下围棋的AlphaGO啥的,那个我就更不感兴趣了,相信大多数人也不感兴趣,所以总的来看也就只有现在才能证明AI发展到了能够让大家觉得能干涉到更多人的地步吧。
|
当然在这之前,还有一些很厉害的画图AI,比如使用了Stable Difusion的NovalAI,以及Midjourney啥的,不过因为我对画图并不感兴趣,所以它发展的有多好也基本上和我没有关系。其实除了这些能够AIGC的模型之外,在那之前还有下围棋的AlphaGO啥的,那个我就更不感兴趣了,相信大多数人也不感兴趣,所以总的来看也就只有现在才能证明AI发展到了能够让大家觉得能干涉到更多人的地步吧。
|
||||||
也正因为现在以ChatGPT为代表的LLM的发展,开源社区也开始搞起来一些有意思的东西。不过LLM的训练成本比较高,所以现在开源社区在这一块的发展也许得感谢比如Facebook的[LLaMA](https://github.com/facebookresearch/llama)之类基础的模型,才能让大家能用较低的成本去训练属于自己的AI吧。
|
也正因为现在以ChatGPT为代表的LLM的发展,开源社区也开始搞起来一些有意思的东西。不过LLM的训练成本比较高,所以现在开源社区在这一块的发展也许得感谢比如Facebook的[LLaMA](https://github.com/facebookresearch/llama)之类基础的模型,才能让大家能用较低的成本去训练属于自己的AI吧。
|
||||||
|
|
||||||
|
33
_posts/2023-10-21-game.md
Normal file
33
_posts/2023-10-21-game.md
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
---
|
||||||
|
layout: post
|
||||||
|
title: 在MacBook玩游戏的各种方法
|
||||||
|
tags: [Apple, MacBook, 游戏]
|
||||||
|
---
|
||||||
|
|
||||||
|
我倒要看看是谁在说Mac打游戏是疯子😡<!--more-->
|
||||||
|
|
||||||
|
# 起因
|
||||||
|
自从[用了MacBook Pro](/2023/02/03/mbp.html)以后,我用我以前Windows笔记本的次数越来越少了。虽然性能可能比不上,但是安静和超长续航的体验还是相当不错的。但是我也不是完全不玩游戏的人,有时候闲了也有打游戏的需求,那我如何在不使用Windows系统的情况下打游戏呢?
|
||||||
|
|
||||||
|
# 在MacBook玩游戏的方法
|
||||||
|
## 原生游戏
|
||||||
|
一般来说如果想发挥MacBook的全部能力,那自然是完完全全为Mac设计,不需要任何转换等方法的游戏最好了,这类游戏一般在Mac App Store就能找到和下载,只是绝大多数都不是免费的,我也就下过一款[TouchBrickOut](https://apps.apple.com/us/app/ibreakout/id1582094533)的打砖块游戏,这是真真正正为Mac设计的,不仅原生还要Touch Bar。当然对于大多数游戏来说不会为Mac专门设计,毕竟Mac的游戏玩家比较少。但是能在Mac上原生运行的游戏除了为Mac设计以外,就是开源游戏了。毕竟源代码都有了,想在哪里编译都可以。对于我玩的游戏来说,有几款正好符合这一点,比如[osu!lazer](https://github.com/ppy/osu),还有之前玩过的[三维弹球](https://github.com/k4zmu2a/SpaceCadetPinball)。
|
||||||
|
## iOS游戏
|
||||||
|
因为M系列芯片基于ARM架构,所以我的MacBook也可以玩iOS的游戏。这类游戏一般也能直接在Mac App Store上下载到,比如我玩过的[药水制作师](https://apps.apple.com/us/app/%E8%8D%AF%E6%B0%B4%E5%88%B6%E4%BD%9C%E5%B8%88/id950654598)。但其实有很多iOS游戏在Mac App Store上都搜索不到,应该是开发者设置了规则不允许在Mac上使用。对于这类游戏可以在[Decrypt IPA Store](https://decrypt.day/)上下载,并且使用[PlayCover](https://github.com/PlayCover/PlayCover)安装。对我来说,我一般玩[公主连结Re:Dive](https://decrypt.day/app/id1423525213),以及一些模拟器,比如[XP3Player](https://apps.apple.com/us/app/xp3player/id1064060287)和[ONSPlayer](https://apps.apple.com/us/app/onsplayer/id1388250129)(其实这两款软件可以在Mac App Store上下载,但是都要花钱……所以我就去网上找的ipa文件然后在PlayCover上安装了)
|
||||||
|
## 使用Rosetta 2的x86游戏
|
||||||
|
在M系列芯片出来以前,其实也有不少Mac上的游戏,但是这类游戏可能在M芯片的Mac出来之前就已经开发好了,想让开发者为M芯片做适配显然不大可能。不过macOS有Rosetta 2可以让开发者不需要任何改动的情况下就让游戏在M系列芯片Mac上运行。这类游戏非常多,基本上在Steam和Epic Games上下载的游戏都是x86的,像我用的Epic Games Launcher以及在上面下载的游戏[while True:learn()](https://launcher.store.epicgames.com/zh-CN/p/while-true-learn)都是这样的,不过我玩的这些对性能要求都非常低,所以即使用了转译,但是玩起来并不会卡。
|
||||||
|
## 基于脚本的Galgame游戏
|
||||||
|
很多Galgame都是用一些专用的脚本引擎工具写出来的,例如T Visual Presenter、NScripter还有Ren'Py等等,因为是脚本,所以通常来说很容易跨平台,毕竟它们没有太多依赖系统本身的东西,只要能写出对应平台的解析器,脚本都能运行。像上述提到的XP3Player、ONSPlayer还有[RenPyViewer](https://apps.apple.com/us/app/renpyviewer/id1547796767)就可以运行很多基于脚本的游戏。不过很多Ren'Py游戏都有发行macOS版本,所以一般不需要安装RenPyViewer。只是有可能它们都是基于x86开发的,可能需要用Rosetta 2转译……
|
||||||
|
## 在网页上运行的游戏
|
||||||
|
浏览器作为跨平台最强的解决方法,自然游戏也不例外,能在网页上运行的游戏也很多,像RPG Maker MV制作的游戏基本上都可以在浏览器上运行。我看到有一个[网站](https://amemei-lists.top/posts/49e03169/)就收集了很多这种游戏,他们之前还把游戏放在了GitHub上。不过Github对[Sexually Obscene Content](https://docs.github.com/zh/site-policy/acceptable-use-policies/github-sexually-obscene-content)内容是不容忍的,所以他们在GitHub上的东西就消失了……不过我搜了一下还有一些漏网之鱼,[这个账号](https://github.com/jjbR18)还有这样的游戏可以玩🤣(有效性只限我写文章之前的时间,说不定哪天被GitHub发现就没了)。其实对于这种网页上可以运行的游戏来说,最好下载下来,虽然RPG Maker MV的游戏可以在线玩,但是加载那么多资源,尤其这些文件还是在境外,对国内玩家非常的不友好😆,所以如果想在Mac上玩,可以下载下来,然后在终端那个目录下执行`python3 -m http.server`,就可以打开 <http://127.0.0.1:8000> 下开始游戏了。不过Safari的效果不太行,很多游戏连声音都没有,想玩还是下载Chrome之类的浏览器比较好。
|
||||||
|
## 使用Wine🍷游玩Windows游戏
|
||||||
|
除了相对比较原生的办法,不太优雅的办法就是用基于Wine的各种东西了。其实我之前不太想在MacBook上使用Wine的,因为一般如果是Linux系统在ARM芯片上运行的话需要用QEMU User模式模拟x86,然后再运行Wine,效率极其低下,还不如用虚拟机呢(虽然听过Crossover,不过我当时以为它是按这种方式的,而且还要收费😂)。不过macOS不太一样,它有Rosetta 2加持,效率比QEMU User模式高太多了,虽然是两次翻译但是毕竟有黑科技还算是能玩。尤其是前段时间出的Game Porting Toolkit,据说很厉害,所以前几天我根据[这个教程](https://www.applegamingwiki.com/wiki/Game_Porting_Toolkit)安装了一个,编译的时候第一次听到我的MacBook风扇转😂。试了试效果确实不错,找了个Unity3D的游戏可以满帧率运行。虽然很不错,不过我又去网上搜了搜,发现我是**,有个开源的软件[Whisky](https://github.com/Whisky-App/Whisky)不需要编译任何东西,就可以使用Wine和GPTk,而且配置也很简单,还能使用DXVK,而且因为是已经编译好的,不需要安装依赖,也不需要源码之类的东西,我通过上面教程安装的大小要4个多GiB,但是这个就只要1个多GiB,还不需要考虑乱七八糟的东西。
|
||||||
|
经过我的实测,GPTk(其实就是D3DMetal)兼容性更好一些,效率也更高,但是占内存很大,DXVK似乎效率低一些,但是占内存比较小,因为我的MacBook只有8GiB内存,而且我玩的游戏在哪个上面都能跑满帧率 ~~(反正3A大作我也不可能在MacBook上玩,估计M2的水平也玩不了……不如说我基本上不玩3A大作🤣)~~ ,所以我在玩游戏一般还是会用DXVK多一些,除非打不开才会用D3DMetal。
|
||||||
|
## 使用虚拟机游玩Windows游戏
|
||||||
|
因为我的MacBook只有8GiB内存,而且硬盘也只有256GiB,跑虚拟机压力实在是太大了,我以前试过[UTM](https://github.com/utmapp/UTM),但是玩不了游戏,随便什么游戏都会卡的动不了,当然也可能是UTM的显卡驱动不太行,不过现在的话我也不想尝试其他虚拟机了,所以我只能说强烈不推荐使用虚拟机玩游戏。
|
||||||
|
## 云游戏方案
|
||||||
|
这种方案直接就不在本机运行了,流畅程度全看网络和连接的主机性能。我以前也写过一篇[关于云游戏的体验](/2021/09/28/cloudgame.html),在这里就不多赘述了。
|
||||||
|
|
||||||
|
# 感想
|
||||||
|
这么看来MacBook玩游戏的方法挺多的嘛,谁说一定要Windows才能打游戏呢?我觉得说在macOS上打游戏的人是精神病的人自己才是精神病吧,谁也没有说买MacBook就是专门拿来打游戏的,那些人就是觉得买Mac亏,估计还很穷吧🤣。
|
||||||
|
顺便一说,有个叫[AppleGamingWiki](https://www.applegamingwiki.com/wiki/Home)的网站上记录了一些比较大的游戏在M系列芯片上的兼容性,如果真的有想在Mac上打游戏的想法,也可以去这个Wiki上参考一下。
|
24
_posts/2023-12-10-openfyde.md
Normal file
24
_posts/2023-12-10-openfyde.md
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
---
|
||||||
|
layout: post
|
||||||
|
title: rpi4-openfyde的使用体验
|
||||||
|
tags: [树莓派, openfyde]
|
||||||
|
---
|
||||||
|
|
||||||
|
什么样的系统用户体验更好呢?<!--more-->
|
||||||
|
|
||||||
|
# 起因
|
||||||
|
最近玩树莓派感觉有点玩腻了,毕竟我不是搞硬件的人,树莓派的GPIO接口对我来说毫无意义,当作PC或者服务器的话性能又太差了,兼容性也不太行(这么看来新出的树莓派5一样对我来说毫无意义,和4B一样都是垃圾)。但是毕竟那个东西也挺贵的,闲置也不太好,因此我想在上面装上适合普通人使用的系统,然后送给家里的人使用。
|
||||||
|
|
||||||
|
# 系统的选择
|
||||||
|
首先服务器版的系统肯定不需要考虑了,谁会用一个满是命令行的系统啊,在我看来普通人使用的系统只能在Windows, MacOS, Android, ChromeOS里面选了,任何GNU/Linux发行版的桌面版在我看来都不太适合普通人使用,[Windows之前已经试过了](/2023/05/22/rpi-win.html),可以说基本上没法用,就是纯粹的垃圾。MacOS显然还没有什么方案可以安装(至于仿MacOS的TwisterOS对于普通人来说使用难度也很大,安装软件都是难事),Android虽然也不是不能用但是作为桌面端系统效果还是不太行,所以我觉得可能也就只有ChromeOS可以考虑一用了。
|
||||||
|
不过官方的ChromeOS要支持的设备才能刷,树莓派显然不在其中,要么就刷ChromiumOS,但是那个要登谷歌账号,在国内使用也不太好。幸好国内有一家对ChromeOS做了本地化的公司,开发了FydeOS,我看了一下如果想在树莓派上安装,就只能安装FydeOS for You,但那个是收费的,每年要120CNY,太贵了,我肯定是不会考虑的。还好,还有一个替代品,那就是openFyde,两个系统我也不太清楚有什么区别,可能是云服务有所不同吧?对于树莓派来说,安装[rpi4-openfyde](https://github.com/openFyde/overlay-rpi4-openfyde)就可以了,另外想要安装的话最好选文件名中包含“archero”的那个,才能使用Android子系统。
|
||||||
|
|
||||||
|
# 安装与使用体验
|
||||||
|
第一次安装的时候我是直接把镜像用Raspberry Pi Imager刷进去的,我以为它和其他的树莓派系统一样刷进去之后再配置其他东西,结果并不是,那个镜像是个安装包,想要用的话需要先格式化TF卡,然后找一个U盘把系统刷进去,然后把U盘和TF卡都插入树莓派才能安装,就和安装ESXi一样。
|
||||||
|
安装之后拔掉U盘重启就可以创建用户使用了,首先作为浏览器为基础的系统,我平时用浏览器可能也就是看看Bilibili吧,之前我使用树莓派官方系统的浏览器看Bilibili效果非常差,看看装了openFyde的效果怎么样?结果令人失望,效果还是一样的差,主要应该还是没有硬件解码的问题吧……树莓派4B的GPU好像只支持硬件解码H264,而树莓派5更是卧龙凤雏,只支持H265,真是有够逆天。这么说来FydeOS for You可是要每年120CNY呢,这个水平的性能他们有自己测过吗?就这样也能收费吗?至于其他不涉及视频的网页倒是还算流畅,不过毕竟GPU很垃圾,有一些特殊情况还是会卡。
|
||||||
|
除了浏览器之外,可能用的比较多的就是Android子系统了吧,要是想轻度办公的话应该需要一个Office,用浏览器的Office也不太好,所以先安装个WPS Office试试看,这个从Fyde的应用商店里就能直接安装,还挺方便的。不过安装好之后效果感觉不太行,首先这个Android子系统居然不支持滚轮,复制粘贴都要像手机那样长按,而且很多时候比如新建文档,它会开两个窗口,原来新建文档的窗口不会关掉……这可不像是能让人用的样子啊……而且整体使用也比浏览器卡,使用起来并不顺畅。另外输入法也不是默认开启的,要在设置里设置,体验也不太行。
|
||||||
|
我试了一下那个应用商店,上面的应用要么就是网页链接,要么就是Android程序,要么就是浏览器插件,Android程序从我用了WPS Office来看不怎么抱有希望了,放网页链接的我感觉有点无语😓,其他系统的浏览器都能把网页当作应用,这个系统反倒是直接当超链接跳过去了……至于浏览器插件,那个只要是能安装浏览器就都能用吧,没啥特别的。
|
||||||
|
虽然普通人可能用不上,这个系统还有一个Linux子系统,具体是什么Linux我没细看,不过好像是使用容器启动的。我试了一下效果还行,只是不知道为什么不能使用全部内存,我使用的是8GiB的树莓派,但是分配给Linux的只有6GiB,存储也是分配的,默认10GiB。明明都是Linux系统为什么ChromeOS要限制子系统的资源呢?
|
||||||
|
# 总结
|
||||||
|
总的用下来,树莓派4B的性能可能真的就只能看看网页了,连视频都不能流畅播放,安装Android应用效果也很差,不过有时候限制多并不是一件坏事,毕竟对普通人来说如果这个性能让人不要抱有更多的希望,反倒是提高了用户体验呢。虽然如果是用比如Ubuntu之类的系统能做的事情应该更多,但很多情况不是普通人应该关心的事情,尤其这个芯片还是ARM指令集的,即使某些应用提供了Linux版也不一定能在树莓派上安装,尤其这个安装很多时候也不是双击就能搞定的,openFyde至少能做到真想安装Android应用的时候双击还是能安装的,卡虽卡了点,但是一般情况不会出现让普通人看了会看不懂的情况,已经算很不错了。
|
||||||
|
因此,我觉得如果让普通人使用树莓派,安装openFyde是最好的选择了。
|
24
_posts/2023-12-24-android.md
Normal file
24
_posts/2023-12-24-android.md
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
---
|
||||||
|
layout: post
|
||||||
|
title: 如何在Linux容器内运行Android?
|
||||||
|
tags: [Linux, Android]
|
||||||
|
---
|
||||||
|
|
||||||
|
原生运行Android肯定比虚拟机好!<!--more-->
|
||||||
|
|
||||||
|
# 起因
|
||||||
|
前段时间我在树莓派上安装了[openFyde](/2023/12/10/openfyde.html),后来发现原来它的ArcHero安卓子系统是基于anbox开发的,和ChromeOS的安卓子系统有一些区别,至于区别在哪我也不是特别清楚。不过既然它的安卓子系统和Linux直接安装的没啥区别,那不如我试试看在普通的Linux上安装容器化的安卓系统效果怎么样?
|
||||||
|
|
||||||
|
# 试用Waydroid
|
||||||
|
最开始我测试的是[Waydroid](https://github.com/waydroid/waydroid),因为听说anbox的升级版就是Waydroid,据说性能比anbox强,所以想试试看,安装挺简单的,执行个脚本之后用apt就能安装。不过我的测试平台是Ubuntu Server 20.04LTS,Waydroid之所以叫这个名字是因为它要基于Wayland显示服务器运行,可我是无界面的系统要怎么用它啊?Waydroid好像没有无头模式这种东西,不过我搜了一下weston实现了Wayland协议而且支持无头模式,用法也很简单,安装好weston之后执行`weston --backend=headless-backend.so`就可以了。
|
||||||
|
不过默认安装好的Waydroid不能运行ARM架构的程序,似乎是因为libhoudini之类的库是有版权的,所以不能直接集成,不过还好有人开发了一个[工具包](https://github.com/casualsnek/waydroid_script),可以给Waydroid安装包括libhoudini在内的多个因为版权等原因不能直接在项目里使用的程序,而且操作起来也很简单,体验还不错。
|
||||||
|
至于怎么查看界面,因为是无头模式启动的所以没有界面,只能通过adb查看,不过我试了一下scrcpy不知道为什么不能用,但是用Airtest就能看到界面,就挺奇怪的……还有就是分辨率很低,不过这个应该改weston的启动参数就可以改分辨率了吧,但因为后来发现Waydroid不能开多个实例感觉有点废物就没有在继续研究了。
|
||||||
|
不过总的来看,如果是在桌面版的Linux上,而且界面是使用Wayland协议的效果应该会比较好,好像Ubuntu22.04以上的系统默认会使用Wayland,在这个系统上面使用Waydroid效果应该比在Windows上使用WSA的效果还要好。毕竟这可不是虚拟机运行,而是使用容器技术原生运行的,如果有机会的话还是值得一用的。
|
||||||
|
|
||||||
|
# 试用redroid
|
||||||
|
因为Waydroid不能开多个实例,所以我搜了一下有没有类似技术而且能开多个实例的,结果就找到了[redroid](https://github.com/remote-android)。安装也很简单,执行几个命令修改下内核模块然后直接用docker pull个镜像就可以用,而且这个切换版本比Waydroid简单,Waydroid想换别的安卓版本要自己整镜像,不然就只能用基于Android 11的LineageOS,redroid可以按镜像的版本号选择希望使用的安卓版本,而且我测试了一下,redroid是可以使用scrcpy连接的,看起来效果还不错。
|
||||||
|
但是我试了一下运行一些ARM的安卓程序会出现闪退的情况,我以为是因为没有ARM兼容库的问题,但是文档上写的镜像里面已经自带了libndk……这么看来可能是因为libndk的兼容性不太行啊,另外libndk好像是给AMD的CPU使用的,我用的CPU是Intel的,Intel应该用libhoudini才对,然而我找了半天也没有找到怎么让redroid使用libhoudini……真是令人失望啊。
|
||||||
|
|
||||||
|
# 总结
|
||||||
|
看来在容器内运行Android系统的需求还是太少了,很多问题都没人解决……不过想想也是,那些搞云手机的大多直接拿真机运行Android,用兼容层的性能损耗也很大,而服务器级别的ARM芯片也不便宜……
|
||||||
|
另外就是使用Linux的人也很少,而且像那些在Windows上玩安卓游戏的人都是用的虚拟机,性能也都够用了,毕竟那么高功率的桌面端CPU怎么样都比超低功率的手机CPU强啊,所以容器内运行Android的需求比较少可能也很正常吧……
|
21
_posts/2024-01-01-summary.md
Normal file
21
_posts/2024-01-01-summary.md
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
---
|
||||||
|
layout: post
|
||||||
|
title: 年终总结
|
||||||
|
tags: [总结]
|
||||||
|
---
|
||||||
|
|
||||||
|
接下来,就是长跑的时间了……<!--more-->
|
||||||
|
|
||||||
|
# 2023年过的怎么样?
|
||||||
|
至少今年我顺利毕业了,而且也有一份还可以的工作能让我赚点钱,比年初的预期已经好了很多,从总体上来看还算不错吧,另外还有一个很重要的原因就是我早晨抽卡抽到UP角色了😂,所以状态还可以。
|
||||||
|
不过从我写博客的次数可以看出来,今年我探索新事物的动力也不怎么高了,其实吧我的工作也不怎么忙,算是965的程度,平时也没什么加班之类的,但我每次回到住所之后就只会躺在床上看看视频和打游戏(视觉小说)而已,而且经常就玩到很晚,导致我晚上睡觉的时间还很短,可能也就6个小时多。也就是说我平时我晚上玩的时间可能就要7个小时多了。另外这对我的影响还是挺大的,最近我在玩osu!mania,前段时间我打的水平应该算越来越好吧,但是最近脑子不太好使了,打的效果越来越差了,还有最近幻视(看错字)的情况比之前发生的概率高了不少,还挺令我头疼的……
|
||||||
|
不过这可能和我未来的打算差不多,我本来就想在赚够我一个人一辈子花的钱之后就不再继续工作了,不过要是到那个时候我还是像现在这样黑白颠倒,不能好好吃饭的话可能一辈子也花不完我赚的那些钱🤣。
|
||||||
|
不过总的来说可能就是因为我没啥照顾自己的能力吧,所以说明明是挺不错的环境但是过的就像那些997的人一样🥲……像这种问题还是应该考虑解决一下才行。
|
||||||
|
至于在2023年发生的事情倒是还挺多的,令人印象最深刻的大概就是AI了吧,自从ChatGPT出了之后各行各业都开始搞LLM了,而且正是因为LLaMA这种东西的出现,国内的AI才会五花八门吧,只是LLM对我的影响可能还是不太大,后来发现大多数问题我自己就能解决,我解决不了的问题问它也没法解决,而且需要我写文案的时候很少,大多数情况并不需要生成一堆废话。
|
||||||
|
|
||||||
|
# 未来的打算
|
||||||
|
就和上面提的一样,我的目标就是赚够我一个人一辈子花的钱,所以接下来的日子很可能会是一成不变的,工作日上班,下班了玩电脑,休息日睡觉,节假日回家了🤣,而且未来的10年里很可能都是这样,没有更多的计划了。
|
||||||
|
但是看环境我猜应该会比往常有更多不可预料的情况吧,最近在这个世界上各种各样的事情越来越多了,我想接下来的一年里可能会有更多情况发生,说不定就是世界末日呢😆,至于会不会影响到我可能也只能到时候才知道了吧,不过对我来说最好还是别发生对普通人影响特别大的事情,比如手头的钱全变成废纸啥的,如果真出现那种情况,最好能提前发现然后全部转成黄金或者USDT之类的最好吧,如果没有这样做的话……反正大家的起点可能就差不多了吧,不知道到时候会发生什么样的事情。
|
||||||
|
|
||||||
|
# 总结
|
||||||
|
总的来说,过去一年里倒是没那么差,至于未来会更差还是更好也很难说,至于过去的一年里到底发生了什么我也记不太清了,现在的我只能说一些没什么营养的废话填充这篇文章了🤣。
|
25
_posts/2024-01-20-renpy.md
Normal file
25
_posts/2024-01-20-renpy.md
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
---
|
||||||
|
layout: post
|
||||||
|
title: 如何在macOS上玩基于Ren'Py的视觉小说
|
||||||
|
tags: [Apple, macOS, 视觉小说]
|
||||||
|
---
|
||||||
|
|
||||||
|
跨平台的游戏移植起来就是简单啊<!--more-->
|
||||||
|
|
||||||
|
# 起因
|
||||||
|
最近我在玩[Winged Cloud](https://store.steampowered.com/developer/WingedCloud/)出的视觉小说,他们家出的视觉小说画风都很不错,比很多其他同行画的好看,另外长度一般都很短,大概1-2个小时就能看完,很适合下班之后闲了看一部,不过我现在已经换了MacBook,要怎么玩呢?他们家的视觉小说基本上都是用的Ren'Py引擎开发的。Ren'Py引擎的游戏本身其实原生就是跨平台的,但是也许是因为我是直接从互联网上下载的,macOS会有些验证之类的?直接运行.app结尾的文件是没办法打开游戏的,双击会显示应用程序无法打开……那该怎么运行呢?
|
||||||
|
|
||||||
|
# 玩法研究
|
||||||
|
## 使用iOS版的RenPyViewer
|
||||||
|
不过看看之前[我在MacOS上玩游戏的经验](/2023/10/21/game.html),对于Apple芯片的Mac来说,可以下载[RenPyViewer](https://apps.apple.com/us/app/renpyviewer/id1547796767)来玩。只是经过我的测试发现,RenPyViewer能玩的游戏很有限,因为它内置的Ren'Py引擎版本是7.5.3的,如果游戏用的Ren'Py引擎和这个版本相差不大,或者没有用到新版的特性之类的倒是能正常运行,我试了一下Sakura MMO系列、Sakura Gamer系列等都能正常运行,但只要运行游戏Ren'Py的版本过高或者过低的游戏都会报错,尤其像新出的基本上都是8.0以上的版本了,Python的版本也从2换成3了,显然用RenPyViewer肯定是没法运行的。
|
||||||
|
## 使用Intel macOS版的RenPyViewer
|
||||||
|
其实在我发现iOS版的RenpyViewer不能运行一部分Ren'Py游戏之后,我又去搜了一下,在知乎上找到了iOS版的RenPyViewer作者发的文章,介绍了[macOS如何游玩Ren'Py引擎游戏](https://zhuanlan.zhihu.com/p/477696534),其中包含了他为macOS做的RenPyViewer,不过我下载看了一下是Intel版的……不过也许这个里面用的引擎更新一点,一部分iOS版不能玩的这个版本就可以玩。
|
||||||
|
## 使用终端运行
|
||||||
|
但毕竟前面两个方法内置的引擎版本是固定的,能玩的游戏也很少,看来得想个通用的办法,毕竟Ren'Py游戏在发行的时候是支持macOS的啊。所以我又看了看,Ren'Py开发的游戏发行之后一般在游戏文件夹里有一个.sh的文件,看起来应该是给Linux系统运行使用的,但是macOS也可以运行.sh的文件啊,所以我就直接在终端运行了它,结果macOS和Linux不一样的地方是所有从网上下载的可执行文件都必须签名,不然就会报移到废纸篓之类的错,关于这个问题,我看网上说的好像是执行`xattr -r -d com.apple.quarantine <path>`就可以,不过后来我也忘了是出什么问题,最后是手动一个一个给每个可执行文件加的权限,最终倒是也运行起来了。
|
||||||
|
## 手动修改.app文件
|
||||||
|
不过每次运行要是用终端那不是很麻烦嘛,另外既然游戏里面明明有.app的文件,为什么会运行不了呢?后来我看了看,发现Contents/MacOS文件夹下的文件并没有可执行权限,我猜可能是和这个有关系?加了可执行权限之后倒是没有报应用程序无法打开的错了,但是还是不能运行,点开之后在Dock栏跳了几下就消失了……然后我就去看了下那个可执行文件,发现就是一个Shell脚本(后面的版本换成可执行文件了)里面定义了几个ROOT变量,一个是和脚本同级的目录,一个是和.app同级的目录,还有一个是Contents/Resources/autorun目录,这么看来正常情况下因为游戏是跨平台的,游戏肯定不会在.app里面,在外面的话……看现在macOS权限管的这么严格,让它读取.app外面的文件估计不太行,肯定只能读取.app里面的文件,至于Intel macOS版的RenPyViewer我看了一下好像原理差不多,是把游戏目录用软链接映射过去的,所以才能在不直接获取.app外面的文件下运行。之后我又参考了一下其他直接在macOS发行的Ren'Py游戏,感觉也差不多。所以解决方法也很简单,要么把游戏文件放到Contents/Resources/autorun目录下,要么做个软链接放过去,我觉得单个.app管理起来会方便一些,所以就直接把游戏文件全部移动进去了。试了一下,总算可以正常运行了。而且多试了几个,基本上都没有问题。
|
||||||
|
但有些Ren'Py游戏连.app都没提供,我不知道SDK默认生成分发版的时候会不会包含macOS上用的.app文件,不过也有可能是发行的时候只针对Windows所以删掉了,对于一些非官方汉化版很有可能是汉化的人给删掉了。对于这种情况,可以先搞清楚这个游戏使用的Ren'Py版本,然后去Ren'Py官网下载对应版本的SDK,把SDK中的renpy.app复制出来,然后按照上面的方法把游戏拷进去就可以正常运行了。
|
||||||
|
另外macOS上还有一些坑,比如说Windows的文件名是不区分大小写的,但是macOS是区分的,有时候他们写脚本的时候文件名和程序里可能有些比如CG之类的大小写不一致,结果图片不能正常加载,这种情况就只能用unrpa解包然后把对应的图片名改成正确的才能运行了,当然Ren'Py提供了忽略错误的功能,但是不知道为什么只有英文模式下有,中文下就没有……这种情况还得先切换到英文才行。
|
||||||
|
|
||||||
|
# 总结
|
||||||
|
总的来看,以后如果想在macOS上玩Ren'Py游戏,优先应该用游戏自带的.app最好,把Contents/MacOS下的文件添加可执行权限,然后把文件全部移动到Contents/Resources/autorun下。不过旧版的Ren'Py基本上都是只有x86_64的可执行文件,新的才有两种都支持的,如果是用的Apple芯片的Mac,最好先看看可执行文件是不是通用的,如果不是优先应该先试试iOS版的RenPyViewer,毕竟原生运行肯定要更省电一些,如果不能运行再用上面的办法。
|
23
_posts/2024-02-03-1panel.md
Normal file
23
_posts/2024-02-03-1panel.md
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
---
|
||||||
|
layout: post
|
||||||
|
title: 如何离线安装1Panel
|
||||||
|
tags: [离线, 1Panel]
|
||||||
|
---
|
||||||
|
|
||||||
|
Go写的程序感觉离线使用还挺方便的<!--more-->
|
||||||
|
|
||||||
|
# 起因
|
||||||
|
为了更好的管理服务器,我之前用过几种面板,比如宝塔,小皮,appnode还有[1Panel](https://github.com/1Panel-dev/1Panel)之类的,之所以用面板主要还是觉得这种用起来方便一些。有些脑子不合适的人看不起使用面板的人,他们可能用了比如软件包安装,或者源码编译、容器等等,结果一顿操作猛如虎,结果配置还是安装默认的,连调优都没做🤣。
|
||||||
|
总之最近正好需要在不能连接互联网的地方安装LEMP的环境,虽然现在的面板很多,但是似乎很少有面板支持离线安装。宝塔好像有付费的离线安装服务,但是我首先不信任宝塔,另外怎么可能给他们付钱呢😆?1Panel虽然官方不支持离线安装,但是社区中有离线安装的方法,不过好像不能使用网站管理的功能……当然经过我的测试,其实是有办法可以使用网站管理的功能,所以分享一下方法。
|
||||||
|
|
||||||
|
# 离线安装1Panel的方法
|
||||||
|
一般想离线安装的话搜到的文章应该就是[这篇文章](https://bbs.fit2cloud.com/t/topic/386)了吧,看起来操作有一点点复杂,不过评论里有个人整了个可以离线安装的[项目](https://github.com/wojiushixiaobai/1Panel-installer),使用起来非常简单,连docker也一起安装了。只是使用的时候稍微有一点点坑,就是它的“--install-dir”参数默认是“/opt/1panel”,但是安装的时候会在这个目录里再建一个1panel文件夹,所以在使用的时候最好手动把参数设置为“--install-dir /opt”。
|
||||||
|
安装没什么问题,不过应用商店是空的,什么软件都安装不了,我在社区论坛里找了一下,好像可以把在互联网端1Panel实例中“/opt/1panel/resource/apps/remote”中的文件拷到离线设备中的“/opt/1panel/resource/apps/local”下,然后点更新就可以了,我试了一下确实可以,把镜像导出来再导入到离线设备,直接安装可能会报错,但是重建一下容器就能正常启动了。虽然容器是启动了,但是面板好像没识别到,还是不能管理,而且应用的文件被放在了“/opt/1panel/apps/local”目录下,就算能识别到,文件路径也是错的。看来得让面板认为导入的程序不是本地安装的,而是在线安装的。
|
||||||
|
|
||||||
|
# 离线安装1Panel中应用的方法
|
||||||
|
我在网上怎么搜,都没有找到现成的解决方法,看来只能我自己研究了😂。我找了一下,面板安装目录下有一个“/opt/1panel/db/1Panel.db”文件,应该是面板的数据库,我用sqlite3客户端打开看了一下,里面的apps表中可以看到应用被导入了,但是key在前面都被加了local,比如openresty变成了localopenresty,我对比了一下互联网端的数据库,除了这一处外,还有resource字段的内容也从remote变成了local。既然是这里有不一样的地方那就把它改成一样的呗,另外这里的字段名既然叫resource,那么肯定和那个目录也有关系,所以就得把“/opt/1panel/resource/apps/local”文件夹下的内容再全部移动到“/opt/1panel/resource/apps/remote”中,把数据库上传然后重启,离线环境中的1Panel也能正常识别了,而且安装后网站标签页也能正常创建网站之类的操作了。
|
||||||
|
Nginx(openresty)和MySQL这样安装都没啥问题,但是PHP出现了点问题,因为1Panel的PHP会在线下载扩展来构建镜像的,不是直接使用镜像创建的容器,所以安装会报错。不过既然能看到数据库,我发现有个runtimes表记录了PHP的状态,那么我把状态改成normal就可以了吧,试了一下还真行,改完上传然后重新导入容器,PHP也正常了。另外需要注意的是从互联网端导出的镜像名字和版本必须和离线端一样,不然可能识别不到,至于扩展啥的在互联网端选择好就可以了,离线端不需要修改。
|
||||||
|
所有操作完成之后试了试创建网站以及和PHP的连接之类的都可以正常使用了,就可以在内网环境下完全发挥1Panel的能力了。
|
||||||
|
|
||||||
|
# 感想
|
||||||
|
无论是Docker还是1Panel,能这么简单的在离线环境下安装我想可能是因为它是Go写的程序吧,能无依赖,静态编译的程序在没网的情况下还是方便啊……另外就是Docker果然也是离线使用的利器,想安什么在互联网准备好直接拿到离线端就能用,真是方便啊。
|
24
_posts/2024-02-24-luckfox.md
Normal file
24
_posts/2024-02-24-luckfox.md
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
---
|
||||||
|
layout: post
|
||||||
|
title: Luckfox Pico Plus使用体验
|
||||||
|
tags: [开发板, 树莓派]
|
||||||
|
---
|
||||||
|
|
||||||
|
开发板还是越小越好啊<!--more-->
|
||||||
|
|
||||||
|
# 起因
|
||||||
|
前段时间,银行送了我一张满50减50的淘宝不限品类优惠券,但是我一时半会没想好买什么。不知道怎么的就想起在Bilibili上看到的微型开发板Luckfox Pico系列,当时看了视频觉得挺有意思的,这次既然有机会了就可以买一个了吧……不过有这钱去买箱牛奶不好吗🤣。
|
||||||
|
最终买的Luckfox Pico Plus开发板,当时的价格是52CNY,加了8CNY的运费,然后用券抵完就是10CNY了。价格看上去挺不错的,不过相比之下还是不如随身WiFi便宜,那个正常买好像也才10CNY,而且整体性能也要比这个好很多,还能用WiFi联网……不过既然买了就玩玩呗,看起来也挺有意思的。
|
||||||
|
|
||||||
|
# 使用体验
|
||||||
|
从外观来看,整体大小只有一根食指大,因为选了带RJ45接口的板子所以其实不算特别小,而且背面甚至没有焊元件,其实它的SOC RV1103只有不到小拇指指甲盖的大小,很难不相信它其实还能做的更小。
|
||||||
|
## 安装系统
|
||||||
|
刚买来的时候里面有预装的测试系统,不过测试系统几乎把里面的空间都占满了,肯定是不能用的,我去看了看[官方的Wiki](https://wiki.luckfox.com/zh/Luckfox-Pico/Luckfox-Pico-quick-start),官方有提供编译好的BusyBOX、Ubuntu、buildroot以及Alpine Linux,也有可以自己编译的SDK。对我来说我也不愿意整麻烦的事情,所以肯定会选编译好的,至于系统也肯定要有软件包管理器的,另外因为这个开发板只有64MiB的内存和128MiB的存储(虽然可以插TF卡,但是内存还是没法加),系统也不能太大,所以就只有Alpine Linux可以选了。我之前[在虚拟机里测试过Alpine Linux](/2022/03/12/alpine.html),体验还是挺不错的。
|
||||||
|
安装方法也很简单,[官网的Wiki](https://wiki.luckfox.com/zh/Luckfox-Pico/Luckfox-Pico-Alpine-Linux-1)有详细的说明。不过有一些不太一样的地方,我没有USB转UART串口模块,我有的只是树莓派。所以烧录完系统之后的改密码以及配置网络的过程就得用树莓派来做了,其实这体现了一下树莓派的作用,至少那堆GPIO接口不是当摆设的🤣。用法的话就是首先刷一个树莓派的官方系统到树莓派上,然后在配置里打开UART并关掉树莓派的串口登录,按官网的图接三根线,只要是导线就行,对树莓派来说应该是第8和第10脚分别是RX和TX,第6脚有一个地线,依次接到开发板上,在终端里安装screen,使用`screen /dev/serial0 115200`,就可以登录开发板的终端了,如果连接有问题可能是RX和TX接反了,反过来重新插一下就行。之后改密码以及配置网络就很简单,配置好之后连上网线就可以正常使用了。
|
||||||
|
不过这个系统有个缺陷,没有配置TF卡,这还是挺重要的,回头有时间可能还是得编译个能使用TF卡的Alpine Linux,或者看看官方愿不愿意编译一个?
|
||||||
|
## 使用软件
|
||||||
|
安装好系统之后就可以用SSH连接了。首先试了一下安装软件,Alpine Linux的软件包管理器apk用法和apt的用法差不多,而且源里的软件也非常多,安装了个Python3试了一下,没有任何问题,安装好pip之后安装python包也没有问题,这样就可以运行我用python写的一些定时任务了。另外我又下了一个[go-cqhttp](https://github.com/Mrs4s/go-cqhttp)搭了个机器人试了一下,居然也能正常运行,看来64MiB的内存还可以啊,跑些软件还是绰绰有余的,这么看来的话就可以替代掉我的树莓派了,反正我的树莓派平时除了网口其他的口都没用,运行些定时任务或者QQ机器人又觉得利用的性能太少了,而且很明显的是这个东西显然比树莓派的能耗要小的多,挂在家里挺合适的,不过缺陷可能就是如果哪天我想整个[电台](/2022/03/27/radio.html),树莓派的GPIO接口还能派上用场,这个Luckfox Pico Plus的GPIO可能除了最开始装系统的时候用了一下,之后就再没有用了。
|
||||||
|
另外作为在家里装的开发板,内网穿透也是需要的,但是装了个go-cqhttp之后内存就剩下30MiB了,还要考虑定时任务运行时也要用掉一些内存,用frp肯定不太合适,但是用ssh的话又容易断,我想了一下干脆折中一下用autossh吧,如果断了也能自动重连。
|
||||||
|
|
||||||
|
# 感想
|
||||||
|
感觉作为开发板,Luckfox Pico Plus相比树莓派来说用途差不多,而树莓派的定位却不太准确,又想当开发板,又想当普通PC,结果作为开发板价格有点贵,尺寸有点大,功耗也有点高;作为PC性能过差,啥也干不了;作为NAS接硬盘也接不了几块,才两个USB3.0口,还要另外接供电,属实是比上不足,比下有余。这款产品我倒是觉得挺不错的,主要是颜值比较吸引我😆,其实还有和这个一样芯片的另外一个开发板,更便宜还带WiFi模块,但是相比之下还是这个好看,所以如果想整开发板我觉得Luckfox Pico Plus比树莓派更合适。
|
41
_posts/2024-03-16-ssl-pinning.md
Normal file
41
_posts/2024-03-16-ssl-pinning.md
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
---
|
||||||
|
layout: post
|
||||||
|
title: 如何用requests库验证证书
|
||||||
|
tags: [Python, requests, ssl]
|
||||||
|
---
|
||||||
|
|
||||||
|
用Python制作的程序怎么样?<!--more-->
|
||||||
|
|
||||||
|
# 起因
|
||||||
|
之前在抓包某些APP的时候,可能会遇到即使信任了抓包软件的CA根证书也无法抓包的情况,听说之所以遇到这种情况是因为那些APP使用了“SSL Pinning”的技术,可以只信任代码中认为可以信任的证书。不过对于逆向之类的事情我并不擅长,这种问题我也不太会解决。但是不能解决问题我可以创造问题啊,Java的APP我不会写,但是我会用Python写,所以今天来看看怎么样用Python实现类似“SSL Pinning”的技术。
|
||||||
|
|
||||||
|
# 实现方案
|
||||||
|
真正的SSL Pinning似乎是通过预置网站所使用的根证书或者中间证书来实现的,这样的好处是即使证书到期换了证书也能继续验证。不过我觉得其实没必要这么麻烦,一般Python程序要连接的后端也没必要在浏览器中调用,大不了就自签一个证书,然后自己验证证书就好了,反正中间人攻击重新签的公钥证书的指纹肯定和原来网站公钥证书的指纹不一样,用这一点就可以判断有没有被抓包。
|
||||||
|
不过我搜了一下,如果想实现这个功能,首先请求的时候就要获得网站的证书,很多资料都是直接用socket和ssl这两个包实现的,但是在python上请求一般都是用requests,用socket操作有点太麻烦了吧,再问问AI呢?AI给出的回复是:`response.raw.connection.getpeercert()`,结果执行了根本没有这个方法,不愧是只会东拼西凑,这应该是ssl库的函数吧……要么可以用`urllib3.contrib.pyopenssl.ssl.get_server_certificate()`这个方法获取,但是这个方法不是在发起请求的时候获取的证书,而是直接先访问了一下服务器然后直接获取的证书,这样每次调用接口的时候可能就要请求两次服务器了,感觉不怎么好……后来去Stack Overflow上搜了一下,还真有关于类似这个问题的[讨论](https://stackoverflow.com/questions/16903528/how-to-get-response-ssl-certificate-from-requests-in-python),于是我简单改编了一下,最终效果如下:
|
||||||
|
```python
|
||||||
|
import requests
|
||||||
|
import hashlib
|
||||||
|
|
||||||
|
HTTPSConnection = requests.packages.urllib3.connection.HTTPSConnection
|
||||||
|
orig_HTTPSConnection_connect = HTTPSConnection.connect
|
||||||
|
def new_HTTPSConnection_connect(self):
|
||||||
|
orig_HTTPSConnection_connect(self)
|
||||||
|
try:
|
||||||
|
self.peer_certificate = self.sock.getpeercert(binary_form=True)
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
HTTPSConnection.connect = new_HTTPSConnection_connect
|
||||||
|
|
||||||
|
def verify_cert_request(url):
|
||||||
|
with requests.get(url, stream=True, verify=False) as r:
|
||||||
|
result = [ hashlib.sha256(r.raw.connection.sock.getpeercert(binary_form=True)).hexdigest(), r.text ]
|
||||||
|
return result
|
||||||
|
|
||||||
|
result = verify_cert_request('https://www.baidu.com')
|
||||||
|
print(result[0])
|
||||||
|
print(result[1][:10])
|
||||||
|
```
|
||||||
|
用这个代码就能获取到请求的网站中证书的指纹了,如果不希望其他人抓包,先自己计算一下自己证书的hash指纹,然后在代码中执行逻辑的时候先判断一下请求网站的指纹是不是自己网站的指纹,如果不是还可以考虑一下反制措施?这样就能实现证书的验证了。
|
||||||
|
|
||||||
|
# 后记
|
||||||
|
不过Python作为解释型语言,代码不是随便看😂?就算用Cython然后加壳啥的调用的库依然不是加密的,大不了修改依赖的库然后让它返回的结果向正确的凑可能也行?不过这样至少能防止绝大多数抓包的人了。
|
213
_posts/2024-04-06-old-pc.md
Normal file
213
_posts/2024-04-06-old-pc.md
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
---
|
||||||
|
layout: post
|
||||||
|
title: 关于旧电脑的使用探索
|
||||||
|
tags: [旧电脑, Darling, whisper, Anbox]
|
||||||
|
---
|
||||||
|
|
||||||
|
性能差也不一定要淘汰!<!--more-->
|
||||||
|
|
||||||
|
# 起因
|
||||||
|
最近我偶然得到了几台淘汰的废旧电脑,试着重新拼装了一下,发现还有4台电脑还能开机,所以我想试试看这些旧电脑除了性能以外有什么该被淘汰的地方。
|
||||||
|
|
||||||
|
# 测试平台介绍
|
||||||
|
本次测试的4台电脑为了方便操作,我都装了Linux发行版,Windows的话想要登录还要远程桌面太麻烦了,以下是这些电脑的配置:
|
||||||
|
一、装有 [Intel® Pentium® E5300](https://www.intel.cn/content/www/cn/zh/products/sku/35300/intel-pentium-processor-e5300-2m-cache-2-60-ghz-800-mhz-fsb/specifications.html) CPU的电脑
|
||||||
|
|
||||||
|
```
|
||||||
|
.. root@localhost.localdomain
|
||||||
|
.PLTJ. --------------------------
|
||||||
|
<><><><> OS: CentOS Stream 8 x86_64
|
||||||
|
KKSSV' 4KKK LJ KKKL.'VSSKK Host: G31M-ES2C
|
||||||
|
KKV' 4KKKKK LJ KKKKAL 'VKK Kernel: 6.8.1-1.el8.elrepo.x86_64
|
||||||
|
V' ' 'VKKKK LJ KKKKV' ' 'V Uptime: 2 days, 19 hours, 11 mins
|
||||||
|
.4MA.' 'VKK LJ KKV' '.4Mb. Packages: 953 (rpm)
|
||||||
|
. KKKKKA.' 'V LJ V' '.4KKKKK . Shell: bash 4.4.20
|
||||||
|
.4D KKKKKKKA.'' LJ ''.4KKKKKKK FA. Terminal: /dev/pts/2
|
||||||
|
<QDD ++++++++++++ ++++++++++++ GFD> CPU: Pentium E5300 (2) @ 2.600GHz
|
||||||
|
'VD KKKKKKKK'.. LJ ..'KKKKKKKK FV GPU: Intel 82G33/G31 Express
|
||||||
|
' VKKKKK'. .4 LJ K. .'KKKKKV ' Memory: 597MiB / 2969MiB
|
||||||
|
'VK'. .4KK LJ KKA. .'KV'
|
||||||
|
A. . .4KKKK LJ KKKKA. . .4
|
||||||
|
KKA. 'KKKKK LJ KKKKK' .4KK
|
||||||
|
KKSSA. VKKK LJ KKKV .4SSKK
|
||||||
|
<><><><>
|
||||||
|
'MKKM'
|
||||||
|
''
|
||||||
|
```
|
||||||
|
二、装有 [AMD Athlon™ II X4 641](https://www.amd.com/zh-hans/product/1326) CPU 和 NVIDIA GeForce GT 440 的电脑
|
||||||
|
|
||||||
|
```
|
||||||
|
.-/+oossssoo+/-. mayx@mayx-server
|
||||||
|
`:+ssssssssssssssssss+:` ----------------
|
||||||
|
-+ssssssssssssssssssyyssss+- OS: Ubuntu 20.04.6 LTS x86_64
|
||||||
|
.ossssssssssssssssssdMMMNysssso. Kernel: 5.4.0-174-generic
|
||||||
|
/ssssssssssshdmmNNmmyNMMMMhssssss/ Uptime: 1 day, 23 hours, 13 mins
|
||||||
|
+ssssssssshmydMMMMMMMNddddyssssssss+ Packages: 1276 (dpkg), 4 (snap)
|
||||||
|
/sssssssshNMMMyhhyyyyhmNMMMNhssssssss/ Shell: bash 5.0.17
|
||||||
|
.ssssssssdMMMNhsssssssssshNMMMdssssssss. Terminal: /dev/pts/0
|
||||||
|
+sssshhhyNMMNyssssssssssssyNMMMysssssss+ CPU: AMD Athlon II X4 641 (4) @ 2.800GHz
|
||||||
|
ossyNMMMNyMMhsssssssssssssshmmmhssssssso GPU: NVIDIA GeForce GT 440
|
||||||
|
ossyNMMMNyMMhsssssssssssssshmmmhssssssso Memory: 242MiB / 7925MiB
|
||||||
|
+sssshhhyNMMNyssssssssssssyNMMMysssssss+
|
||||||
|
.ssssssssdMMMNhsssssssssshNMMMdssssssss.
|
||||||
|
/sssssssshNMMMyhhyyyyhdNMMMNhssssssss/
|
||||||
|
+sssssssssdmydMMMMMMMMddddyssssssss+
|
||||||
|
/ssssssssssshdmNNNNmyNMMMMhssssss/
|
||||||
|
.ossssssssssssssssssdMMMNysssso.
|
||||||
|
-+sssssssssssssssssyyyssss+-
|
||||||
|
`:+ssssssssssssssssss+:`
|
||||||
|
.-/+oossssoo+/-.
|
||||||
|
```
|
||||||
|
三、装有 [Intel® Pentium® G3240](https://www.intel.cn/content/www/cn/zh/products/sku/80796/intel-pentium-processor-g3240-3m-cache-3-10-ghz/specifications.html) CPU的电脑
|
||||||
|
|
||||||
|
```
|
||||||
|
.-/+oossssoo+/-. mayx@mayx-server
|
||||||
|
`:+ssssssssssssssssss+:` ----------------
|
||||||
|
-+ssssssssssssssssssyyssss+- OS: Ubuntu 22.04.4 LTS x86_64
|
||||||
|
.ossssssssssssssssssdMMMNysssso. Host: H81M-S1
|
||||||
|
/ssssssssssshdmmNNmmyNMMMMhssssss/ Kernel: 5.15.0-101-generic
|
||||||
|
+ssssssssshmydMMMMMMMNddddyssssssss+ Uptime: 2 days, 19 hours, 58 mins
|
||||||
|
/sssssssshNMMMyhhyyyyhmNMMMNhssssssss/ Packages: 984 (dpkg), 6 (snap)
|
||||||
|
.ssssssssdMMMNhsssssssssshNMMMdssssssss. Shell: bash 5.1.16
|
||||||
|
+sssshhhyNMMNyssssssssssssyNMMMysssssss+ Terminal: /dev/pts/3
|
||||||
|
ossyNMMMNyMMhsssssssssssssshmmmhssssssso CPU: Intel Pentium G3240 (2) @ 3.100GHz
|
||||||
|
ossyNMMMNyMMhsssssssssssssshmmmhssssssso GPU: Intel HD Graphics
|
||||||
|
+sssshhhyNMMNyssssssssssssyNMMMysssssss+ Memory: 371MiB / 3800MiB
|
||||||
|
.ssssssssdMMMNhsssssssssshNMMMdssssssss.
|
||||||
|
/sssssssshNMMMyhhyyyyhdNMMMNhssssssss/
|
||||||
|
+sssssssssdmydMMMMMMMMddddyssssssss+
|
||||||
|
/ssssssssssshdmNNNNmyNMMMMhssssss/
|
||||||
|
.ossssssssssssssssssdMMMNysssso.
|
||||||
|
-+sssssssssssssssssyyyssss+-
|
||||||
|
`:+ssssssssssssssssss+:`
|
||||||
|
.-/+oossssoo+/-.
|
||||||
|
```
|
||||||
|
四、装有 [Intel® Xeon® E5-2620](https://www.intel.cn/content/www/cn/zh/products/sku/64594/intel-xeon-processor-e52620-15m-cache-2-00-ghz-7-20-gts-intel-qpi/specifications.html) CPU的电脑
|
||||||
|
|
||||||
|
```
|
||||||
|
.-/+oossssoo+/-. mayx@mayxserver
|
||||||
|
`:+ssssssssssssssssss+:` ---------------
|
||||||
|
-+ssssssssssssssssssyyssss+- OS: Ubuntu 22.04.4 LTS x86_64
|
||||||
|
.ossssssssssssssssssdMMMNysssso. Host: X79 0.9
|
||||||
|
/ssssssssssshdmmNNmmyNMMMMhssssss/ Kernel: 5.15.0-101-generic
|
||||||
|
+ssssssssshmydMMMMMMMNddddyssssssss+ Uptime: 18 hours, 41 mins
|
||||||
|
/sssssssshNMMMyhhyyyyhmNMMMNhssssssss/ Packages: 773 (dpkg), 9 (snap)
|
||||||
|
.ssssssssdMMMNhsssssssssshNMMMdssssssss. Shell: bash 5.1.16
|
||||||
|
+sssshhhyNMMNyssssssssssssyNMMMysssssss+ Terminal: /dev/pts/0
|
||||||
|
ossyNMMMNyMMhsssssssssssssshmmmhssssssso CPU: Intel Xeon E5-2620 0 (12) @ 2.500GHz
|
||||||
|
ossyNMMMNyMMhsssssssssssssshmmmhssssssso Memory: 8773MiB / 11928MiB
|
||||||
|
+sssshhhyNMMNyssssssssssssyNMMMysssssss+
|
||||||
|
.ssssssssdMMMNhsssssssssshNMMMdssssssss.
|
||||||
|
/sssssssshNMMMyhhyyyyhdNMMMNhssssssss/
|
||||||
|
+sssssssssdmydMMMMMMMMddddyssssssss+
|
||||||
|
/ssssssssssshdmNNNNmyNMMMMhssssss/
|
||||||
|
.ossssssssssssssssssdMMMNysssso.
|
||||||
|
-+sssssssssssssssssyyyssss+-
|
||||||
|
`:+ssssssssssssssssss+:`
|
||||||
|
.-/+oossssoo+/-.
|
||||||
|
```
|
||||||
|
|
||||||
|
# 使用探索
|
||||||
|
其实对我来说,性能根本不是什么问题,毕竟想想即使是这些淘汰的电脑,性能也比树莓派强的多,包括对比上次买的[Luckfox Pico Plus](/2024/02/24/luckfox.html)来说就强的更多了,所以即使性能比较差的电脑也不是不能用。
|
||||||
|
不过这些老机器还是有一些坑的,像第一台奔腾E5300的电脑,我试了一下Ubuntu就装不上,安装程序都打不开,可能还是有一些有差别的地方,所以安装了CentOS Stream 8。不过还好这些机器都是64位的CPU,如果是32位的就更麻烦了,可能很多包都没地方下载。
|
||||||
|
## 关于Darling的探索
|
||||||
|
那么对于这些机器来说干点什么好呢?当然除了GPIO之类的,树莓派能干的他们也能干,所以要干就干一些特别的东西。我想了一下,我平时用的电脑是macOS系统,虽然给那些旧电脑装黑苹果可能不太现实,但是我之前发现了一个叫[Darling](https://github.com/darlinghq/darling)的项目,类似Wine那样在Linux上运行Windows程序,这个项目可以在Linux上运行macOS的程序。看起来挺有意思的,所以我打算在第一台机器上试着安装一下。
|
||||||
|
不过我按照官方文档上安装,对于CentOS Stream 8来说有好多包不知道为什么似乎都没有,比如libavformat-free-devel之类的,我只好从网上找其他RedHat系列类似的包,或者找替代品FFmpeg,另外Darling需要Linux 5.0或者更高的内核,CentOS的内核版本太低了,所以我升到了主线版本的Linux,也就是6.8的版本……最终花了一天的时间终于编译好了,然而悲剧的是运行的时候报了非法指令“Illegal instruction (core dumped)”的错误。一般来说这个错误是新机器上编译的程序在旧机器运行才会报的错,可我是在同一台机器上编译的为什么会报这种错误呢?可能是因为代码里包含汇编语言的代码吧。我发了个[Issue](https://github.com/darlinghq/darling/issues/1497)问了一下作者,不过看起来他也不知道是什么问题……
|
||||||
|
对于这种问题我感觉也没什么好办法……可能这台机器真的就没办法了?在第二台速龙641的电脑上试了一下也不行……不过后来我在第三台装有奔腾G3240的电脑上试着编译安装了一下,结果可以运行。看来确实是奔腾E5300的问题。不过它俩到底差在哪里呢?看介绍会发现奔腾G3240里包含了Intel® SSE4.1和Intel® SSE4.2的指令集扩展。那么对于没有这个指令集扩展的CPU就没办法了吗?Intel官方给了一个解决方法是[Intel® SDE](https://www.intel.com/content/www/us/en/developer/articles/tool/software-development-emulator.html),可以在旧机器上模拟运行使用了最新指令集的程序,甚至包括AVX512都可以模拟的出来,但是我用这个东西运行Darling的时候还是报错了,可能Darling需要用到内核的一些特性,但是SDE不能模拟……这都没办法是不是就彻底没办法了呢?
|
||||||
|
在偶然的一次浏览中,我发现了一个神奇的东西,内核扩展[OPEMU](https://github.com/mirh/opemu-linux),它可以让不支持一些指令集扩展的CPU通过模拟的方式支持,其实功能和SDE很像,只是它是在内核中运行的,我试着在第一台机器上编译安装了一下(顺便一说,如果是旧的5.x或者更早的Linux可以直接用这个仓库,而更新的Linux比如6.x的需要用[PR](https://github.com/Spacefish/opemu-linux)中的这个仓库),结果Darling真的可以运行了!真是令人难以置信。
|
||||||
|
安装成功之后我在网上找了个C语言的程序:[endoh1](http://www.ioccc.org/2012/endoh1/hint.html),这个程序可以用文本模拟流体。我在我的MacBook上编译了试了一下,运行没有问题,当然直接编译的程序是ARM64的程序,肯定不能在Darling里面运行,于是我切换到x86_64模式下又编译了一次,并且用`lipo`命令把两个程序合并到了一起,然后把程序上传到第一台机器中使用Darling运行,竟然可以正常运行,看来那个内核扩展还不错啊,Darling居然没有出问题。
|
||||||
|
不过测试了一下,可能还是有些地方有BUG,比如用Git的时候会报错,可能是和README中所说的CRC32表现有问题吧,不过Darling好像可以直接运行Linux中的命令,那我在用Git的时候调用Linux下的Git是不是也可以呢?试了一下不太行,因为执行Linux程序的时候不能用Darling中的目录结构,不过我想装omz只需要/Users目录就够了,我直接创建一个软链接把Darling的/Users目录映射到Linux的根目录就可以了吧,试了一下还行,可以正常运行,虽然Homebrew不能安装有点可惜……不过Neofetch可以安装😆,效果如下:
|
||||||
|
```
|
||||||
|
'c. root@localhost.localdomain
|
||||||
|
,xNMM. --------------------------
|
||||||
|
.OMMMMo OS: macOS 11.7.4 Darling x86_64
|
||||||
|
OMMM0, Kernel: 20.6.0
|
||||||
|
.;loddo:' loolloddol;. Uptime: 2 days, 21 hours, 11 mins
|
||||||
|
cKMMMMMMMMMMNWMMMMMMMMMM0: Shell: bash 3.2.57
|
||||||
|
.KMMMMMMMMMMMMMMMMMMMMMMMWd. DE: Aqua
|
||||||
|
XMMMMMMMMMMMMMMMMMMMMMMMX. WM: Quartz Compositor
|
||||||
|
;MMMMMMMMMMMMMMMMMMMMMMMM: WM Theme: Blue (Print: Entry, AppleInterfaceStyle, Does Not Exist)
|
||||||
|
:MMMMMMMMMMMMMMMMMMMMMMMM: Terminal: /dev/pts/2
|
||||||
|
.MMMMMMMMMMMMMMMMMMMMMMMMX. Memory: 0MiB / 2969MiB
|
||||||
|
kMMMMMMMMMMMMMMMMMMMMMMMMWd.
|
||||||
|
.XMMMMMMMMMMMMMMMMMMMMMMMMMMk
|
||||||
|
.XMMMMMMMMMMMMMMMMMMMMMMMMK.
|
||||||
|
kMMMMMMMMMMMMMMMMMMMMMMd
|
||||||
|
;KMMMMMMMWXXWMMMMMMMk.
|
||||||
|
.cooc,. .,coo:.
|
||||||
|
```
|
||||||
|
既然第一台电脑装了内核扩展还是有BUG,那么对于第三台电脑来说总该没问题了吧,试了一下Git可以正常运行,安装Homebrew也没问题,但是用brew安装软件的时候会报错,似乎是因为Darling安装的Command Line Tools for Xcode太旧了,有些命令没有所以不能正常安装,不过Neofetch又不需要编译,试着安装了一下没问题,但是运行的时候会报Segmentation fault: 11 (core dumped)的错误……不知道是什么问题。
|
||||||
|
## 关于旧显卡利用的探索
|
||||||
|
对于第二台电脑,可以看出来它有一张上古的独显NVIDIA GeForce GT 440,我装好驱动之后运行nvidia-smi可以看到:
|
||||||
|
```
|
||||||
|
Sat Apr 6 08:26:45 2024
|
||||||
|
+------------------------------------------------------+
|
||||||
|
| NVIDIA-SMI 340.108 Driver Version: 340.108 |
|
||||||
|
|-------------------------------+----------------------+----------------------+
|
||||||
|
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
|
||||||
|
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
|
||||||
|
|===============================+======================+======================|
|
||||||
|
| 0 GeForce GT 440 Off | 0000:01:00.0 N/A | N/A |
|
||||||
|
| 40% 49C P0 N/A / N/A | 3MiB / 1023MiB | N/A Default |
|
||||||
|
+-------------------------------+----------------------+----------------------+
|
||||||
|
|
||||||
|
+-----------------------------------------------------------------------------+
|
||||||
|
| Compute processes: GPU Memory |
|
||||||
|
| GPU PID Process name Usage |
|
||||||
|
|=============================================================================|
|
||||||
|
| 0 Not Supported |
|
||||||
|
+-----------------------------------------------------------------------------+
|
||||||
|
```
|
||||||
|
既然是独显,那么果然还是想试试看能不能跑机器学习的算法呢。可是一般来说执行上面的命令可以看到显卡支持的CUDA版本,这个执行完并没有显示啊……那我要怎么用?首先我想试试装个PaddleOCR试试看,但就是因为不知道这个显卡到底能用哪个版本的CUDA,也不知道安装哪个版本的PaddlePaddle框架,更何况之前的机器学习算法对环境要求特别严格,甚至系统新了都没法用,于是在各种报错下我败下阵来,放弃使用CUDA来用这张显卡😭……
|
||||||
|
但并不代表机器学习必须使用CUDA,OpenCL也是可以的啊,正好我之前在测试OpenAI的ASR模型Whisper,有人开发的一个C++使用这个模型的软件[whisper.cpp](https://github.com/ggerganov/whisper.cpp)是支持通过CLBlast使用OpenCL。于是我就先编译安装了CLBlast,然后用对应的参数编译了whisper.cpp,总算是能跑起来了,后来看了一眼clinfo,原来这张显卡才支持CUDA 6.5啊,这能运行啥啊……最后试了一下效果也挺令人失望的,就测试的那个音频用了大概33秒左右才转录完成,果然旧显卡就是纯粹的垃圾啊。
|
||||||
|
## 关于Anbox Cloud的探索
|
||||||
|
现在轮到第四台至强E5-2620的电脑了呢,这台电脑可不一般,用的是服务器上用的CPU,一看就是被奸商坑了,买了个i9级处理器,殊不知是淘汰的洋垃圾🤣。不过我手头用的服务器其实也没多好,一台是[至强E5-2620v2](https://www.intel.cn/content/www/cn/zh/products/sku/75789/intel-xeon-processor-e52620-v2-15m-cache-2-10-ghz/specifications.html)(双路),另一台是[至强E5-2620v3](https://www.intel.cn/content/www/cn/zh/products/sku/83352/intel-xeon-processor-e52620-v3-15m-cache-2-40-ghz/specifications.html)(也是双路)(一二三代都有了🤣):
|
||||||
|
```
|
||||||
|
.-/+oossssoo+/-. mayx@mayx-server
|
||||||
|
`:+ssssssssssssssssss+:` ----------------------
|
||||||
|
-+ssssssssssssssssssyyssss+- OS: Ubuntu 22.04.3 LTS x86_64
|
||||||
|
.ossssssssssssssssssdMMMNysssso. Host: NF5270M3 00001
|
||||||
|
/ssssssssssshdmmNNmmyNMMMMhssssss/ Kernel: 5.15.0-78-generic
|
||||||
|
+ssssssssshmydMMMMMMMNddddyssssssss+ Uptime: 84 days, 22 hours, 20 mins
|
||||||
|
/sssssssshNMMMyhhyyyyhmNMMMNhssssssss/ Packages: 954 (dpkg), 4 (snap)
|
||||||
|
.ssssssssdMMMNhsssssssssshNMMMdssssssss. Shell: bash 5.1.16
|
||||||
|
+sssshhhyNMMNyssssssssssssyNMMMysssssss+ Resolution: 1440x900
|
||||||
|
ossyNMMMNyMMhsssssssssssssshmmmhssssssso Terminal: /dev/pts/1
|
||||||
|
ossyNMMMNyMMhsssssssssssssshmmmhssssssso CPU: Intel Xeon E5-2620 v2 (24) @ 2.600GHz
|
||||||
|
+sssshhhyNMMNyssssssssssssyNMMMysssssss+ GPU: 0b:00.0 ASPEED Technology, Inc. ASPEED Graphics Family
|
||||||
|
.ssssssssdMMMNhsssssssssshNMMMdssssssss. Memory: 68987MiB / 128875MiB
|
||||||
|
/sssssssshNMMMyhhyyyyhdNMMMNhssssssss/
|
||||||
|
+sssssssssdmydMMMMMMMMddddyssssssss+
|
||||||
|
/ssssssssssshdmNNNNmyNMMMMhssssss/
|
||||||
|
.ossssssssssssssssssdMMMNysssso.
|
||||||
|
-+sssssssssssssssssyyyssss+-
|
||||||
|
`:+ssssssssssssssssss+:`
|
||||||
|
.-/+oossssoo+/-.
|
||||||
|
|
||||||
|
.-/+oossssoo+/-. mayx@mayx-algo-server
|
||||||
|
`:+ssssssssssssssssss+:` ---------------------
|
||||||
|
-+ssssssssssssssssssyyssss+- OS: Ubuntu 22.04.3 LTS x86_64
|
||||||
|
.ossssssssssssssssssdMMMNysssso. Host: PowerEdge R730
|
||||||
|
/ssssssssssshdmmNNmmyNMMMMhssssss/ Kernel: 5.15.0-91-generic
|
||||||
|
+ssssssssshmydMMMMMMMNddddyssssssss+ Uptime: 84 days, 20 hours, 16 mins
|
||||||
|
/sssssssshNMMMyhhyyyyhmNMMMNhssssssss/ Packages: 1047 (dpkg), 4 (snap)
|
||||||
|
.ssssssssdMMMNhsssssssssshNMMMdssssssss. Shell: bash 5.1.16
|
||||||
|
+sssshhhyNMMNyssssssssssssyNMMMysssssss+ Resolution: 1024x768
|
||||||
|
ossyNMMMNyMMhsssssssssssssshmmmhssssssso Terminal: /dev/pts/1
|
||||||
|
ossyNMMMNyMMhsssssssssssssshmmmhssssssso CPU: Intel Xeon E5-2620 v3 (24) @ 3.200GHz
|
||||||
|
+sssshhhyNMMNyssssssssssssyNMMMysssssss+ GPU: NVIDIA Tesla T4
|
||||||
|
.ssssssssdMMMNhsssssssssshNMMMdssssssss. GPU: NVIDIA Tesla T4
|
||||||
|
/sssssssshNMMMyhhyyyyhdNMMMNhssssssss/ Memory: 66345MiB / 128808MiB
|
||||||
|
+sssssssssdmydMMMMMMMMddddyssssssss+
|
||||||
|
/ssssssssssshdmNNNNmyNMMMMhssssss/
|
||||||
|
.ossssssssssssssssssdMMMNysssso.
|
||||||
|
-+sssssssssssssssssyyyssss+-
|
||||||
|
`:+ssssssssssssssssss+:`
|
||||||
|
.-/+oossssoo+/-.
|
||||||
|
```
|
||||||
|
都是正儿八经的洋垃圾,不过对于服务器嘛,垃圾一点也没什么,又不是不能用,至少比租的云服务器好吧。
|
||||||
|
不过既然是服务器级的CPU,自然实验也得要符合服务器级(这个级别的处理器就不用担心什么指令集缺失之类的问题了),正好最近注册了个Ubuntu Pro,里面有个Anbox Cloud,可以拿来试试看。
|
||||||
|
关于Anbox,我之前[试过Waydroid和redroid](/2023/12/24/android.html),不过Anbox Cloud不太一样,这个有点像OpenStack那样,是云手机的管理和实现平台,Anbox对它来说就像QEMU对OpenStack,是创建实例的工具。安装还挺简单的,启用Ubuntu Pro之后再执行`sudo pro enable anbox-cloud`,剩下的跟着提示走就行了,不过因为我的硬盘有点问题,有一半的区域有坏块,虽然屏蔽掉了但还是有些问题,第一次安装失败了,第二次才成功。不过应该说不愧是云平台吗,用起来和我当年学OpenStack在虚拟机里安装一样卡,而且啥也没干先占掉8GiB内存,尤其是对这个又老,内存也小的垃圾旧机器来说果然还是有点勉强啊,更何况硬盘还是坏的🤣。安装好之后用浏览器直接输入IP就能登录平台了,第一次使用要绑定Ubuntu One账号,感觉有点不开放啊……登录之后可以上传应用作为模板,类似镜像那样,可以在创建会话的时候使用相同的镜像,然后每个会话之间是隔离的。不过有个问题是这个东西居然没有ARM兼容层,上传不兼容x86_64的软件会不允许创建应用😅,这有点废物啊,难不成想用这个东西搭个云手机厂商还要买一堆ARM的服务器?之后我找了半天发现Via浏览器可以兼容所有架构的处理器,上传上去之后又报错一次😅,重新再上传才算正常运行起来了。
|
||||||
|
|
||||||
|
# 感想
|
||||||
|
经过这次的测试,可以看出来这些旧电脑其实安装了Linux发行版之后除了会遇到一堆莫名其妙的问题之外,并不是不能用,顶多是卡了一些,或者要花点精力解决罢了。其实这么看来,除了人工智能方面的发展确实受到了硬件方面的制约,其他的程序其实都无所谓呢?即使是现在的软件放到以前的电脑上也能运行,不知道是软件发展的太慢,还是兼容性做的太好了呢?
|
30
_posts/2024-05-19-bt-ops.md
Normal file
30
_posts/2024-05-19-bt-ops.md
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
---
|
||||||
|
layout: post
|
||||||
|
title: 从宝塔面板中学习运维知识
|
||||||
|
tags: [宝塔, 运维]
|
||||||
|
---
|
||||||
|
|
||||||
|
用Python代码的程序就等着被抄吧!<!--more-->
|
||||||
|
|
||||||
|
# 起因
|
||||||
|
之前我[用旧电脑拼了一堆服务器](/2024/04/06/old-pc.html),但是上面装的东西其实试完之后就没什么兴趣了,主要是它们实际上没有解决什么问题。后来我觉得还是更应该向更有意义的地方靠,于是我就在每个机器上安装了不同的运维面板,打算分别测试一下效果。
|
||||||
|
我安装的面板有[1Panel](https://github.com/1Panel-dev/1Panel),[小皮面板公测版](https://beta.xp.cn/),[宝塔面板破解版](https://baota.sbs/)。1Panel很不错,但是除了网站管理之外功能全是Docker带来的,另外代码是Go写的我现在还看不懂。小皮面板重构之后很令我失望,功能比旧版小皮面板还少,安装的时候居然还会收集服务器信息并上传?运行环境版本少,PHP连扩展安装的功能都没有,而且现在直接摆烂全放的是配置文件,要是都自己改配置文件了还要面板干啥?另外重构之后也变成Go写的了,就这样拿什么和别的面板打?
|
||||||
|
宝塔面板破解版之前我在[测试Koyeb](/2022/11/29/free-server.html)的时候试过一个,不过后来看到了一个新的,主要是之前那个界面上改的全是的广告,新找的这个破解版不仅界面没有做什么修改,而且[后端开源](https://github.com/flucont/btcloud),也不用担心有什么后门。
|
||||||
|
虽然我不信任宝塔面板,毕竟漏洞出的多,各种收费项目,还各种收集用户信息,强制登录啥的,但是有一个好处就是它是Python写的,而且大多数代码并没有混淆(代码倒是[开源](https://github.com/aaPanel)了,就是没更新)。作为一款算是比较成熟的面板,有些功能还是比较有意思的,而且我也能看懂Python代码,所以有些有意思的功能就可以看看它的代码是如何实现的。
|
||||||
|
|
||||||
|
# 功能探索与解析
|
||||||
|
对于免费版有的功能,其实我不太关心,一是那些大多数并不复杂,自己装也没什么难度,二是大多功能其实我并不感兴趣🤣。对于付费功能不得不说有的还挺离谱的,有些非常简单的功能价格居然很贵,比如服务器网络加速BBR,这个功能是内核提供的,自己一个命令就能打开,和宝塔半毛钱关系都没有,价格居然是4.93元/天?不过我没用过官网下的宝塔,不知道是破解版乱标还是真是这个价格。
|
||||||
|
另外还有一些是纯粹解析类的也没什么意思,比如网站监控报表还有WAF啥的,那些没什么技巧,就只是只要肯写这个功能就会有的东西。我的话更关心一些看起来实现还算难,值得收钱,但是实现其实很简单的东西😁。
|
||||||
|
## 宝塔防入侵
|
||||||
|
其实对于这个功能,我觉得实现应该不复杂,用SELinux或者AppArmor然后进行合理的配置应该就可以了,但是离谱的是开了这个功能我安装Redis等软件的时候各种报错,用宝塔安装Redis是通过编译安装的,正常来说不应该报错才对的啊,而且就算用了SELinux或者AppArmor也不应该有问题,另外它的报错是Segmentation fault,什么情况编译会报这种错误啊……所以我看了看它的代码,原来他们的实现根本没有用SELinux或者AppArmor,可能一是配置复杂,他们的程序员驾驭不了,二是Ubuntu和红帽系不一定都有安SELinux或者AppArmor,适配起来比较麻烦。他们用的居然是一个不知名的开源软件:[Snoopy](https://github.com/a2o/snoopy),原理也很简单,就是在环境变量里配置在运行任意软件的时候把Snoopy先加载进去,然后它就能记录程序运行时的行为了,但显然这个程序并不怎么成熟,运行某些软件的时候居然会报Segmentation fault的错误,这样的东西也好意思收钱?
|
||||||
|
## 宝塔系统加固
|
||||||
|
其实这个功能没啥特别的,但是我看它有好多关于等保的功能,因为我维护的服务器中也有需要符合等保要求的,所以这个功能对我来说还挺有用,至少可以做个参考。不过里面有些比如对文件或者文件夹的保护这个实现我还挺感兴趣的,正常来说就算拿权限限制也限制不了root,可是这个功能打开之后居然连root都没有权限操作,还是挺神奇的,之后我看了一下代码,原来有一个叫做chattr的东西,用这个可以加扩展权限,比如`chattr +i <file>`就可以让任何人都没有权限操作这个文件,想要操作的话必须执行`chattr -i <file>`解除才行。因为一般都是拿普通权限限制的,从来没考虑过扩展权限,这下学到新知识了😆。
|
||||||
|
## 文件监控
|
||||||
|
这个功能其实也不复杂,之前我写过一个[定时调度器](/2022/09/21/cron.html),其中的热载功能用的是watchdog,而wathcdog在Linux下其实用的就是inotify特性,宝塔在实现这个东西的时候用的是pyinotify库,其实它俩倒是没什么特别大的区别,只是watchdog能跨平台而已,虽然宝塔面板也有Windows版,不过估计应该是没有这个插件吧。
|
||||||
|
## 堡塔企业级防篡改
|
||||||
|
这个和刚才那个用chattr的从功能上来看倒是挺像的,不过这个写的是内核级,看了一下确实有个内核模块,叫做tempercore,虽然编译是在本地进行的但是代码加了密,编译还得用它文件夹里一个叫jm的程序进行编译😅,我猜它的实现应该是在内核里hook了操作文件的API,操作完之后会进行记录,不过试了一下根本没有起效果😅,不知道是我破解版的问题还是不支持Ubuntu……
|
||||||
|
## 堡塔运维平台
|
||||||
|
从功能上来看挺像Ansible的,看了一下代码是用paramiko直接在远程服务器上执行命令的。不过Ansible也是Python写的,倒是没差。功能有点太简单了,自己用脚本也能实现,不过提供了个面板可能相对适合小白吧,就是这个价格恐怕只有脑子进水的人才会买了。
|
||||||
|
|
||||||
|
# 总结
|
||||||
|
总的看来宝塔确实有些有意思的功能,实现有些挺有意思的,看了他们的代码之后感觉也能学到点东西,也许以后有机会可以用得上。但是完全不值那个价,这点东西也敢卖钱也真是挺厉害的,不过可能对于政府项目来说这些安全功能还是挺有意义的,毕竟没什么运维会去当公务员,而且企业版的价格对他们来说都已经算相当便宜了🤣。
|
27
_posts/2024-06-16-hackintosh.md
Normal file
27
_posts/2024-06-16-hackintosh.md
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
---
|
||||||
|
layout: post
|
||||||
|
title: Hackintosh使用体验
|
||||||
|
tags: [Apple, Hackintosh, macOS, 黑苹果]
|
||||||
|
---
|
||||||
|
|
||||||
|
使用Mac到底有些什么优势呢?<!--more-->
|
||||||
|
|
||||||
|
# 起因
|
||||||
|
我曾经装过很多系统,Windows、FreeBSD、Linux发行版什么的都试过,但是直到我[拥有MacBook](/2023/02/03/mbp.html)我也没有试过安装黑苹果。主要是在ARM芯片的Mac出现之前,我一直看不起Mac,因为没有差异化,明明和其他电脑用的是同样的东西,一样的CPU、一样的显卡、一样的内存以及硬盘,凭什么比其他电脑贵那么多,也因此CPU能效不行,续航也不行,而且质量也不行,据说在使用蝴蝶键盘那段时间,键盘的损坏率极高,而且散热很差,经常出现CPU空焊的问题,还因此有了“梦幻单热管”的名号。
|
||||||
|
当然也是因为垃圾的硬件,与其配套的软件macOS也并没有什么优势,我也没什么兴趣去装黑苹果,对我来说我觉得x86时代的macOS更像是一种Linux发行版。
|
||||||
|
但直到ARM芯片的Mac出来之后,一切才不一样起来,差异化是一方面,在这个芯片的加持下的macOS也出现了很多的黑科技……当然这都不是重点,重点是最近正好需要一台Mac,我又不想用我自己的MacBook,所以随便找了台电脑装了个黑苹果试试效果。
|
||||||
|
|
||||||
|
# 安装体验
|
||||||
|
据说安装黑苹果很麻烦,不过具体麻烦在哪我也不太清楚。看了一下教程是要根据自己的电脑硬件情况自定义一个EFI文件夹用来引导,应该就是用这个方式模拟Mac的引导环境。至于怎么搞这个EFI文件夹我搜了一下,有一个叫做[RapidEFI-Tool](https://github.com/JeoJay127/RapidEFI-Tool)的软件可以填入自己电脑的硬件信息然后一键生成EFI。生成完成之后把要装macOS的硬盘的分区全部删除,然后新建ESP分区,把EFI文件放进去就行了,然后剩余的空间再创建一个分区,把苹果官方的系统镜像用[balenaEtcher](https://etcher.balena.io/)烧录到U盘里,剩下的就和正常安装系统的步骤一样了,遵循向导的提示进行就行了。
|
||||||
|
这么来看好像也没有很复杂,也可能是因为我用的是台式机,不用考虑无线网络之类的问题吧(当然隔空投送之类的东西就用不了了),我看其他大多数人遇到的问题好像都出在无线网络上,而且我的CPU比较老,是i5-7500,在适合装黑苹果的范围内,所以没有出现奇怪的问题,安装完成之后硬盘、显卡、内存都正确识别了,打开浏览器也能正常上网,看来是成功了。
|
||||||
|
|
||||||
|
# 使用体验
|
||||||
|
我装的系统和我的MacBook一样,都是macOS Sonoma 14.5,所以整体体验都是一样的,而且黑苹果的内存还更大,是16GiB的,这也能让我安心的尝试虚拟机了,不像我的笔记本才8GiB连虚拟机都不敢安。
|
||||||
|
绝大多数软件安装都没有问题,使用也和笔记本一样,不过如果完全一样不就体现不出我笔记本的优势了嘛🤣,我还试了试别的软件,比如针对Apple芯片优化的[llama.cpp](https://github.com/ggerganov/llama.cpp),试了一下可以运行,但是结果全是乱码。应该是llama.cpp可以调Metal的API使用核显进行加速,但是核显好像最多只能分配2GiB的显存,而且和Apple芯片不一样的是它好像并不是可以随意分配内存给显卡的,分配给显卡的部分CPU就不能用了,而Apple芯片是两边都可以用,也正是如此,假设核显的内存够用,模型也要占两份内存,而Apple芯片的只需要占一份内存(我猜的😝)。
|
||||||
|
另外使用了Apple芯片的NPU的软件[Mochi Diffusion](https://github.com/MochiDiffusion/MochiDiffusion)也是不能运行的,因为根本没有做x86版本的🤣,不过用brew安装居然可以安,但是打不开🤣,所以提了个[pr](https://github.com/Homebrew/homebrew-cask/pull/176891)。不过就算做了拿Intel那个核显跑估计会卡死。
|
||||||
|
另外还有[PlayCover](https://github.com/PlayCover/PlayCover)也装不了,这个也算是Apple芯片的特色了,毕竟苹果不可能做ARM转x86的Rosetta,iOS的软件只可能是ARM架构的,Intel的Mac当然执行不了了。
|
||||||
|
还有为GPTk设计的软件[Whisky](https://github.com/Whisky-App/Whisky)也不能用,不过这个无所谓,毕竟黑苹果想切回Windows再简单不过了,根本没有安装这种软件的必要,当然如果说类似的,Crossover应该可以用,不过那个不是免费的,所以我不会去尝试它。
|
||||||
|
虚拟机的话我先试了一下VMware Fusion,安装是正常的,但是打不开,BIOS的虚拟化也开了,VT-d好像黑苹果不能开但应该不影响运行虚拟机。之后又试了一下UTM,我本来以为UTM是专门给Apple芯片使用的,结果居然能安装上,而且Intel版也有苹果官方的虚拟化框架,所以原生运行x86版的Ubuntu没有问题,而且系统信息显示的是Apple Virtualization Generic Platform,看来虚拟化的功能都是正常的,黑苹果效果还不错。
|
||||||
|
|
||||||
|
# 感想
|
||||||
|
虽然总的来看黑苹果算是不错,但是在我看来也顶多省了个Mac Mini而已,当然Mac Pro应该也能拿黑苹果代替,iMac毕竟有个质量还不错的屏幕,不能完全代替。毕竟从功能来说,我觉得macOS和Linux差不多,尤其现在Linux的软件越来越多,现在连微信都有Linux原生版了,而且还有Intel Mac没有的移动端软件(Linux可以[用容器运行Android](/2023/12/24/android.html))。不过对于笔记本来说,续航是最大的优势,Apple芯片+macOS带来的笔记本体验才是最好的,其他Mac Mini啥的根本没有体现出Apple芯片的优势,毕竟要说性能的话同价格Mac是没有优势的,唯有续航是没有其他笔记本产品能打的(带充电宝没用,充电宝能续几个航啊)。
|
294
_posts/2024-07-03-ai-summary.md
Normal file
294
_posts/2024-07-03-ai-summary.md
Normal file
@ -0,0 +1,294 @@
|
|||||||
|
---
|
||||||
|
layout: post
|
||||||
|
title: 使用Cloudflare Workers制作博客AI摘要
|
||||||
|
tags: [Cloudflare, Workers, AI, 博客]
|
||||||
|
---
|
||||||
|
|
||||||
|
Cloudflare实在是太强了,以至于全都依赖它了😂<!--more-->
|
||||||
|
|
||||||
|
# 起因
|
||||||
|
虽然很早就在[关注AI](/2023/04/05/ai.html)了,而且也看到有些博客早已用上了AI摘要(比如xLog下的),但是一般都要后端提前生成好,另外那时候还没有那么多免费好用的接口可以用,像OpenAI到现在还没有GPT免费的API😂,至于花钱就更是想都别想,互联网的东西我是不会花钱的,就因为这样我一直都没有考虑过给我的博客加AI摘要的功能。
|
||||||
|
直到前两天看到一个Hexo的博客有一个AI摘要的功能,如果是有后端的博客我可能还没什么兴趣,但是既然是纯前端的就引发了我的兴趣,我大概看了一下,用的是一个叫[Post-Abstract-AI](https://github.com/zhheo/Post-Abstract-AI)的项目,定睛一看,居然还是收费的,而且API Key还是直接明文放代码里的,给我看笑了。如果我拿着这个Key去不停刷使用量不一会就把它刷完了?不过这时候我想起来赛博活佛Cloudflare之前也出了AI功能,还是免费的,我何不用Workers写一个好好打脸一下这个收费的项目?就像我对[Server酱](/2021/02/02/serverchan.html)做的事情一样。
|
||||||
|
|
||||||
|
# 开始制作
|
||||||
|
首先先不考虑重复造轮子,去Github上看看有没有现成的,毕竟Cloudflare的这个AI功能也出了不少时间了,搜了一下还真有,叫[Qwen-Post-Summary](https://github.com/FloatSheep/Qwen-Post-Summary),用的居然还是阿里的通义千问模型,这倒是不错,毕竟如果用Llama3的话说不定给我生成出来全是英文了,国产的模型至少都是对中文优化过的。
|
||||||
|
我仔细看了看,发现它怎么是把文章放GET请求里的,要知道浏览器是不会允许超过4KiB的请求头的,看了一下代码还截取成前1800字了,感觉有点不爽,不过我搜了一下,为了能简单的做到流式效果,用的EventSource功能根本不支持POST请求……看来这个代码不能直接拿来用了,另外我也不希望每次打开文章都重新生成摘要,那样不仅浪费计算资源,而且毫无意义,毕竟文章又不会变。所以我首先考虑怎么样存AI生成的结果呢?另外为了能通过POST把文章喂给AI我也得考虑存文章。最开始我想着用Workers的KV数据库,因为那是最早出的,虽然限制很多但当时没得选。但这次点开发现居然有个D1数据库,容量更大,[延迟更低](https://github.com/bruceharrison1984/kv-d1-benchmark),操作次数更多而且还支持SQL语法,这不比那个KV数据库好太多了,这下都不知道这个KV数据库留着还有啥意义了,可能就单纯是为了兼容以前的应用不得不留着了吧。
|
||||||
|
不过既然会存储内容,还得考虑一点就是万一有人偷偷拿我的接口把我的文章内容换了,让AI生成了糟糕的内容,显示在我的文章里多不合适啊,所以为了避免这种问题,我每次会对比文章的数字摘要,免得有人把我数据库里的文章篡改了🤣。
|
||||||
|
最终基于上面的代码边查文档边改把代码写出来了,顺便把我之前写的[博客计数器](/2019/06/22/counter.html)也一起替换掉了,做到真正的Serverless:
|
||||||
|
```javascript
|
||||||
|
async function sha(str) {
|
||||||
|
const encoder = new TextEncoder();
|
||||||
|
const data = encoder.encode(str);
|
||||||
|
const hashBuffer = await crypto.subtle.digest("SHA-256", data);
|
||||||
|
const hashArray = Array.from(new Uint8Array(hashBuffer)); // convert buffer to byte array
|
||||||
|
const hashHex = hashArray
|
||||||
|
.map((b) => b.toString(16).padStart(2, "0"))
|
||||||
|
.join(""); // convert bytes to hex string
|
||||||
|
return hashHex;
|
||||||
|
}
|
||||||
|
async function md5(str) {
|
||||||
|
const encoder = new TextEncoder();
|
||||||
|
const data = encoder.encode(str);
|
||||||
|
const hashBuffer = await crypto.subtle.digest("MD5", data);
|
||||||
|
const hashArray = Array.from(new Uint8Array(hashBuffer)); // convert buffer to byte array
|
||||||
|
const hashHex = hashArray
|
||||||
|
.map((b) => b.toString(16).padStart(2, "0"))
|
||||||
|
.join(""); // convert bytes to hex string
|
||||||
|
return hashHex;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
async fetch(request, env, ctx) {
|
||||||
|
const db = env.blog_summary;
|
||||||
|
const url = new URL(request.url);
|
||||||
|
const query = decodeURIComponent(url.searchParams.get('id'));
|
||||||
|
const commonHeader = {
|
||||||
|
'Access-Control-Allow-Origin': '*',
|
||||||
|
'Access-Control-Allow-Methods': "*",
|
||||||
|
'Access-Control-Allow-Headers': "*",
|
||||||
|
'Access-Control-Max-Age': '86400',
|
||||||
|
}
|
||||||
|
if (query == "null") {
|
||||||
|
return new Response("id cannot be none", {
|
||||||
|
headers: {
|
||||||
|
'Access-Control-Allow-Origin': '*',
|
||||||
|
'Access-Control-Allow-Methods': "*",
|
||||||
|
'Access-Control-Allow-Headers': "*",
|
||||||
|
'Access-Control-Max-Age': '86400',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (url.pathname.startsWith("/summary")) {
|
||||||
|
let result = await db.prepare(
|
||||||
|
"SELECT content FROM blog_summary WHERE id = ?1"
|
||||||
|
).bind(query).first("content");
|
||||||
|
if (!result) {
|
||||||
|
return new Response("No Record", {
|
||||||
|
headers: commonHeader
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const messages = [
|
||||||
|
{
|
||||||
|
role: "system", content: `
|
||||||
|
你是一个专业的文章摘要助手。你的主要任务是对各种文章进行精炼和摘要,帮助用户快速了解文章的核心内容。你读完整篇文章后,能够提炼出文章的关键信息,以及作者的主要观点和结论。
|
||||||
|
技能
|
||||||
|
精炼摘要:能够快速阅读并理解文章内容,提取出文章的主要关键点,用简洁明了的中文进行阐述。
|
||||||
|
关键信息提取:识别文章中的重要信息,如主要观点、数据支持、结论等,并有效地进行总结。
|
||||||
|
客观中立:在摘要过程中保持客观中立的态度,避免引入个人偏见。
|
||||||
|
约束
|
||||||
|
输出内容必须以中文进行。
|
||||||
|
必须确保摘要内容准确反映原文章的主旨和重点。
|
||||||
|
尊重原文的观点,不能进行歪曲或误导。
|
||||||
|
在摘要中明确区分事实与作者的意见或分析。
|
||||||
|
提示
|
||||||
|
不需要在回答中注明摘要(不需要使用冒号),只需要输出内容。
|
||||||
|
格式
|
||||||
|
你的回答格式应该如下:
|
||||||
|
这篇文章介绍了<这里是内容>
|
||||||
|
` },
|
||||||
|
{ role: "user", content: result.substring(0, 5000) }
|
||||||
|
]
|
||||||
|
|
||||||
|
const stream = await env.AI.run('@cf/qwen/qwen1.5-14b-chat-awq', {
|
||||||
|
messages,
|
||||||
|
stream: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
return new Response(stream, {
|
||||||
|
headers: {
|
||||||
|
"content-type": "text/event-stream; charset=utf-8",
|
||||||
|
'Access-Control-Allow-Origin': '*',
|
||||||
|
'Access-Control-Allow-Methods': "*",
|
||||||
|
'Access-Control-Allow-Headers': "*",
|
||||||
|
'Access-Control-Max-Age': '86400',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (url.pathname.startsWith("/get_summary")) {
|
||||||
|
const orig_sha = decodeURIComponent(url.searchParams.get('sign'));
|
||||||
|
let result = await db.prepare(
|
||||||
|
"SELECT content FROM blog_summary WHERE id = ?1"
|
||||||
|
).bind(query).first("content");
|
||||||
|
if (!result) {
|
||||||
|
return new Response("no", {
|
||||||
|
headers: commonHeader
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let result_sha = await sha(result);
|
||||||
|
if (result_sha != orig_sha) {
|
||||||
|
return new Response("no", {
|
||||||
|
headers: commonHeader
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
let resp = await db.prepare(
|
||||||
|
"SELECT summary FROM blog_summary WHERE id = ?1"
|
||||||
|
).bind(query).first("summary");
|
||||||
|
if (resp) {
|
||||||
|
return new Response(resp, {
|
||||||
|
headers: commonHeader
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const messages = [
|
||||||
|
{
|
||||||
|
role: "system", content: `
|
||||||
|
你是一个专业的文章摘要助手。你的主要任务是对各种文章进行精炼和摘要,帮助用户快速了解文章的核心内容。你读完整篇文章后,能够提炼出文章的关键信息,以及作者的主要观点和结论。
|
||||||
|
技能
|
||||||
|
精炼摘要:能够快速阅读并理解文章内容,提取出文章的主要关键点,用简洁明了的中文进行阐述。
|
||||||
|
关键信息提取:识别文章中的重要信息,如主要观点、数据支持、结论等,并有效地进行总结。
|
||||||
|
客观中立:在摘要过程中保持客观中立的态度,避免引入个人偏见。
|
||||||
|
约束
|
||||||
|
输出内容必须以中文进行。
|
||||||
|
必须确保摘要内容准确反映原文章的主旨和重点。
|
||||||
|
尊重原文的观点,不能进行歪曲或误导。
|
||||||
|
在摘要中明确区分事实与作者的意见或分析。
|
||||||
|
提示
|
||||||
|
不需要在回答中注明摘要(不需要使用冒号),只需要输出内容。
|
||||||
|
格式
|
||||||
|
你的回答格式应该如下:
|
||||||
|
这篇文章介绍了<这里是内容>
|
||||||
|
` },
|
||||||
|
{ role: "user", content: result.substring(0, 5000) }
|
||||||
|
]
|
||||||
|
|
||||||
|
const answer = await env.AI.run('@cf/qwen/qwen1.5-14b-chat-awq', {
|
||||||
|
messages,
|
||||||
|
stream: false,
|
||||||
|
});
|
||||||
|
resp = answer.response
|
||||||
|
await db.prepare("UPDATE blog_summary SET summary = ?1 WHERE id = ?2")
|
||||||
|
.bind(resp, query).run();
|
||||||
|
return new Response(resp, {
|
||||||
|
headers: commonHeader
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (url.pathname.startsWith("/is_uploaded")) {
|
||||||
|
const orig_sha = decodeURIComponent(url.searchParams.get('sign'));
|
||||||
|
let result = await db.prepare(
|
||||||
|
"SELECT content FROM blog_summary WHERE id = ?1"
|
||||||
|
).bind(query).first("content");
|
||||||
|
if (!result) {
|
||||||
|
return new Response("no", {
|
||||||
|
headers: commonHeader
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let result_sha = await sha(result);
|
||||||
|
if (result_sha != orig_sha) {
|
||||||
|
return new Response("no", {
|
||||||
|
headers: commonHeader
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return new Response("yes", {
|
||||||
|
headers: commonHeader
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (url.pathname.startsWith("/upload_blog")) {
|
||||||
|
if (request.method == "POST") {
|
||||||
|
const data = await request.text();
|
||||||
|
let result = await db.prepare(
|
||||||
|
"SELECT content FROM blog_summary WHERE id = ?1"
|
||||||
|
).bind(query).first("content");
|
||||||
|
if (!result) {
|
||||||
|
await db.prepare("INSERT INTO blog_summary(id, content) VALUES (?1, ?2)")
|
||||||
|
.bind(query, data).run();
|
||||||
|
result = await db.prepare(
|
||||||
|
"SELECT content FROM blog_summary WHERE id = ?1"
|
||||||
|
).bind(query).first("content");
|
||||||
|
}
|
||||||
|
if (result != data) {
|
||||||
|
await db.prepare("UPDATE blog_summary SET content = ?1, summary = NULL WHERE id = ?2")
|
||||||
|
.bind(data, query).run();
|
||||||
|
}
|
||||||
|
return new Response("OK", {
|
||||||
|
headers: commonHeader
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return new Response("need post", {
|
||||||
|
headers: commonHeader
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (url.pathname.startsWith("/count_click")) {
|
||||||
|
let id_md5 = await md5(query);
|
||||||
|
let count = await db.prepare("SELECT `counter` FROM `counter` WHERE `url` = ?1")
|
||||||
|
.bind(id_md5).first("counter");
|
||||||
|
if (url.pathname.startsWith("/count_click_add")) {
|
||||||
|
if (!count) {
|
||||||
|
await db.prepare("INSERT INTO `counter` (`url`, `counter`) VALUES (?1, 1)")
|
||||||
|
.bind(id_md5).run();
|
||||||
|
count = 1;
|
||||||
|
} else {
|
||||||
|
count += 1;
|
||||||
|
await db.prepare("UPDATE `counter` SET `counter` = ?1 WHERE `url` = ?2")
|
||||||
|
.bind(count, id_md5).run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!count) {
|
||||||
|
count = 0;
|
||||||
|
}
|
||||||
|
return new Response(count, {
|
||||||
|
headers: commonHeader
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return Response.redirect("https://mabbs.github.io", 302)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
另外也写了配套的前端代码(用的jQuery,其实应该用Fetch的😂):
|
||||||
|
```html
|
||||||
|
{% raw %}
|
||||||
|
<b>AI摘要</b>
|
||||||
|
<p id="ai-output">正在生成中……</p>
|
||||||
|
<script>
|
||||||
|
async function sha(str) {
|
||||||
|
const encoder = new TextEncoder();
|
||||||
|
const data = encoder.encode(str);
|
||||||
|
const hashBuffer = await crypto.subtle.digest("SHA-256", data);
|
||||||
|
const hashArray = Array.from(new Uint8Array(hashBuffer)); // convert buffer to byte array
|
||||||
|
const hashHex = hashArray
|
||||||
|
.map((b) => b.toString(16).padStart(2, "0"))
|
||||||
|
.join(""); // convert bytes to hex string
|
||||||
|
return hashHex;
|
||||||
|
}
|
||||||
|
async function ai_gen(){
|
||||||
|
var postContent = "文章标题:" + {{ page.title | jsonify }} + ";文章内容:" + {{ page.content | strip_html | strip_newlines | jsonify }};
|
||||||
|
var postContentSign = await sha(postContent);
|
||||||
|
var outputContainer = document.getElementById("ai-output");
|
||||||
|
$.get("https://summary.mayx.eu.org/is_uploaded?id={{ page.url }}&sign=" + postContentSign, function (data) {
|
||||||
|
if (data == "yes") {
|
||||||
|
$.get("https://summary.mayx.eu.org/get_summary?id={{ page.url }}&sign=" + postContentSign, function (data2) {
|
||||||
|
outputContainer.textContent = data2;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
$.post("https://summary.mayx.eu.org/upload_blog?id={{ page.url }}", postContent, function (data) {
|
||||||
|
$.get("https://summary.mayx.eu.org/get_summary?id={{ page.url }}&sign=" + postContentSign);
|
||||||
|
const evSource = new EventSource("https://summary.mayx.eu.org/summary?id={{ page.url }}");
|
||||||
|
outputContainer.textContent = "";
|
||||||
|
evSource.onmessage = (event) => {
|
||||||
|
if (event.data == "[DONE]") {
|
||||||
|
evSource.close();
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
const data = JSON.parse(event.data);
|
||||||
|
outputContainer.textContent += data.response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
ai_gen();
|
||||||
|
</script>
|
||||||
|
{% endraw %}
|
||||||
|
```
|
||||||
|
本来文章内容应该从html里读更好一些,但是标签啥的还得用正则去掉,感觉不如Liquid方便😂。另外博客计数器不应该用MD5的,但懒得改之前的数据了,还好Cloudflare Workers为了兼容是支持MD5的,免得我还得想办法改数据库里的数据。
|
||||||
|
|
||||||
|
# 使用方法
|
||||||
|
如果想给自己的静态博客加AI摘要功能的话也可以用我的接口,把前端代码粘到模板里就行,反正是用的Cloudflare的资源,而且现在通义千问的模型还是Beta版调用没有次数限制,就算之后变正式版,也能每天免费用1w个神经元,好像可以进行1k次左右的生成,完全够用了,只要别和我文章url重了就行。
|
||||||
|
不过毕竟Workers本身是有每日调用次数限制的,自己部署当然更好。方法也很简单,首先在D1里创建一个数据库,然后创建一个Workers,在变量里绑定AI和新建的D1数据库,名字要起成blog_summary,如果想换名字就要改代码,里面建一张叫做blog_summary的表,需要有3个字段,分别是id、content、summary,都是text类型,如果想用博客计数器功能就再加一张counter表,一个是url,text类型,另一个是counter,int类型。本来博客计数器接口名字也打算用counter的,结果不知道AdBlock有什么大病,居然会屏蔽“counter?id=”这样的请求😆,害的我只能改成count_click这样的名字了。
|
||||||
|
|
||||||
|
# 其他想法
|
||||||
|
加了这个功能之后感觉效果还挺不错的,这下就有点想加点别的功能了,比如文章推荐和知识库问答啥的,不过这个似乎需要什么向量数据库,而且数据需要进行“嵌入”处理,这用现有的东西感觉难度实在是太高了所以就算了……另外还想用文生图模型给我的文章加个头图,不过我天天写的都是些技术文章,没啥图可加吧🤣。其他的之后再看看有什么有意思的功能再加吧。
|
||||||
|
|
||||||
|
# 感想
|
||||||
|
Cloudflare真不愧是赛博活佛,这波操作下来不就省下了那笔生成费用?啥都是免费的,不过问题就是Cloudflare在这方面几乎是垄断地位,虽然国际大厂倒是不担心倒闭,不过万一挂了想再找个这样厉害的平台可就没了😆。
|
18
card.html
18
card.html
@ -1,18 +0,0 @@
|
|||||||
<!DOCTYPE html><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><meta charset="utf-8"><title>抽卡</title>
|
|
||||||
<script type="text/javascript">
|
|
||||||
window.onload=function (){
|
|
||||||
o.imgRandom();
|
|
||||||
}
|
|
||||||
var o={
|
|
||||||
aImg:['1001', '1002', '1003', '1004', '1005', '1006', '1007', '1008', '1009', '1010', '1011', '1012', '1013', '1014', '1015', '1016', '1017', '1018', '1019', '1020', '1021', '1022', '1023', '1024', '1025', '1026', '1027', '1028', '1029', '1030', '1031', '1032', '1033', '1034', '1035', '1036', '1037', '1038', '1039', '1040', '1041', '1042', '1043', '1044', '1045', '1046', '1047', '1048', '1049', '1050', '1051', '1052', '1053', '1054', '1055', '1056', '1057', '1058', '1059', '1060', '1061', '1062', '1063', '1064', '1065', '1066', '1067', '1068', '1069', '1070', '1071', '1072', '1073', '1074', '1075', '1076', '1077', '1078', '1079', '1080', '1081', '1082', '1083', '1084', '1085', '1086', '1087', '1088', '1089', '1090', '1091', '1092', '1093', '1094', '1095', '1096', '1097', '1098', '1099', '1100', '1101', '1102', '1103', '2001', '2002', '2003', '2004', '2005', '2006', '2007', '2008', '2009', '2010', '2011', '2012', '2013', '2014', '2015', '2016', '2017', '2018', '2019', '2020', '2021', '2022', '2023', '2024', '2025', '2026', '2027', '2028', '2029', '2030', '2031', '2032', '2033', '2034', '2035', '2036', '2037', '2038', '2039', '2040', '2041', '2042', '2043', '2044', '2045', '2046', '2047', '2048', '2049', '2050', '2051', '2052', '2053', '2054', '2055', '2056', '2057', '2058', '2059', '2060', '2061', '2062', '2063', '2064', '2065', '2066', '2067', '2068', '2069', '2070', '2071', '2072', '2073', '2074', '2075', '2076', '2077', '2078', '2079', '2080', '2081', '2082', '2083', '2084', '2085', '2086', '2087', '2088', '2089', '2090', '2091', '2092', '2093', '2094', '2095', '2096', '3001', '3002', '3003', '3004', '3005', '3006', '3007', '3008', '3009', '3010', '3011', '3012', '3013', '3014', '3015', '3016', '3017', '3018', '3019', '3020', '3021', '3022', '3023', '3024', '3025', '3026', '3027', '3028', '3029', '3030', '3031', '3032', '3033', '3034', '3035', '3036', '3037', '3038', '3039', '3040', '3041', '3042', '3043', '3044', '3045', '3046', '3047', '3048', '3049', '3050', '3051', '3052', '3053', '3054', '3055', '3056', '3057', '3058', '3059', '3060', '3061', '3062', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '30', '31', '32', '33', '34', '35', '36', '37', '38', '39', '40', '41', '42', '43', '44', '45', '46', '47', '48', '49', '50', '51', '52', '53', '54', '55', '56', '57', '58', '59', '60', '61', '62', '63', '64', '65', '66', '67', '68', '69', '70', '71', '72', '73', '74', '75', '76', '77', '78', '79', '80', '81', '82', '83', '84', '85', '86', '87', '88', '89', '90', '91', '92', '93', '94', '95', '96', '97', '98', '99', '100', '101', '102', '103', '104', '105', '106', '107', '108', '109', '110', '111', '112', '113', '114', '115', '116', '117', '118', '119', '120', '121', '122', '5410', '5491', '5510', '5511', '5512', '5543', '5546', '5547', '5548', '5549', '5550', '5551', '5552', '5656', '5685', '5798', '6406', '6525', '7728812653'],
|
|
||||||
imgRandom:function (){
|
|
||||||
var img=document.getElementsByTagName("img")[0];
|
|
||||||
var b=Math.random()*10000;
|
|
||||||
b=Math.floor(b)%(this.aImg.length);
|
|
||||||
img.src="https://nodejs.wikimoe.com:667/card/0/"+this.aImg[b]+".jpg";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script> <body>
|
|
||||||
<h1>您抽到了:</h1><hr>
|
|
||||||
<img src="" onerror="o.imgRandom();">
|
|
||||||
</body></html>
|
|
1
images/offline.svg
Normal file
1
images/offline.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg class="icon" width="200px" height="200.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M512 64.49899 512 64.49899c-247.148913 0-447.50101 200.353121-447.50101 447.50101l0 0.001023c0 247.14789 200.353121 447.50101 447.50101 447.50101l0.001023 0c247.14789 0 447.50101-200.353121 447.50101-447.50101l0-0.001023C959.50101 264.85211 759.14789 64.49899 512 64.49899zM668.789952 627.865891c15.07637 15.07637 18.176988 36.554544 6.904247 47.827285-11.272741 11.272741-32.751938 8.172123-47.827285-6.904247L512 552.923038 396.133086 668.789952c-15.07637 15.07637-36.554544 18.176988-47.827285 6.904247-11.272741-11.272741-8.172123-32.751938 6.904247-47.827285l115.865891-115.865891L355.210048 396.133086c-15.07637-15.07637-18.176988-36.554544-6.904247-47.827285 11.272741-11.272741 32.751938-8.172123 47.827285 6.904247l115.865891 115.865891 115.865891-115.865891c15.07637-15.07637 36.554544-18.176988 47.827285-6.904247 11.272741 11.272741 8.172123 32.751938-6.904247 47.827285L552.923038 512 668.789952 627.865891z" fill="#858585" /></svg>
|
After Width: | Height: | Size: 1.2 KiB |
1
images/online.svg
Normal file
1
images/online.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg class="icon" width="200px" height="200.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M512 64.49899 512 64.49899c-247.148913 0-447.50101 200.353121-447.50101 447.50101l0 0.001023c0 247.14789 200.353121 447.50101 447.50101 447.50101l0.001023 0c247.14789 0 447.50101-200.353121 447.50101-447.50101l0-0.001023C959.50101 264.85211 759.14789 64.49899 512 64.49899zM710.214411 408.40969 496.774227 621.849874c0 0-0.001023 0.001023-0.001023 0.001023-0.001023 0.001023-0.001023 0.001023-0.002047 0.002047l-1.070378 1.070378c-5.852288 5.852288-13.643742 8.694009-21.530362 8.581446-7.886621 0.112564-15.677051-2.729158-21.530362-8.581446L334.48605 504.767272c-11.861142-11.861142-11.380188-31.680537 1.072425-44.132126s32.270984-12.933567 44.132126-1.072425l94.480838 94.480838L665.010883 363.205139c11.861142-11.861142 31.680537-11.380188 44.132126 1.072425C721.594599 376.729154 722.075553 396.548548 710.214411 408.40969z" fill="#71DF2F" /></svg>
|
After Width: | Height: | Size: 1.1 KiB |
@ -58,7 +58,7 @@ title: 首页 - 我的文章
|
|||||||
|
|
||||||
<a href="{% unless site.github %}https://mabbs.github.io{% endunless %}/pixiv-index/">Pixiv图片索引API</a><br>
|
<a href="{% unless site.github %}https://mabbs.github.io{% endunless %}/pixiv-index/">Pixiv图片索引API</a><br>
|
||||||
|
|
||||||
<a href="/card.html">抽卡</a> - 由<a href="https://github.com/eeg1412/">广树</a>大佬提供卡牌<br>
|
<a href="{% unless site.github %}https://mabbs.github.io{% endunless %}/karyl-yabaival/">拯救凯露</a><br>
|
||||||
|
|
||||||
<a href="/message.html">留言板</a><br>
|
<a href="/message.html">留言板</a><br>
|
||||||
|
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
$(window).bind("scroll", $backToTopFun);
|
$(window).bind("scroll", $backToTopFun);
|
||||||
$(function() { $backToTopFun(); });
|
$(function() { $backToTopFun(); });
|
||||||
})();
|
})();
|
||||||
var auxiliaryHost = "https://counter.mayx.eu.org";
|
|
||||||
$(function(){
|
$(function(){
|
||||||
$("div#landlord").mouseenter(function(){
|
$("div#landlord").mouseenter(function(){
|
||||||
$("div.live_ico_box").fadeIn();
|
$("div.live_ico_box").fadeIn();
|
||||||
@ -18,7 +17,7 @@ $(function(){
|
|||||||
$("div.live_ico_box").fadeOut();
|
$("div.live_ico_box").fadeOut();
|
||||||
});
|
});
|
||||||
function showHitS(hits){
|
function showHitS(hits){
|
||||||
$.get(auxiliaryHost+"/counter.php?action=show&id="+hits.id,function(data){
|
$.get("https://summary.mayx.eu.org/count_click?id="+hits.id,function(data){
|
||||||
hits.innerHTML=Number(data);
|
hits.innerHTML=Number(data);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -31,7 +30,7 @@ function showHitCount() {
|
|||||||
}
|
}
|
||||||
function addCount() {
|
function addCount() {
|
||||||
var visitors=$(".visitors");
|
var visitors=$(".visitors");
|
||||||
$.get(auxiliaryHost+"/counter.php?action=add&id="+visitors[0].id,function(data){
|
$.get("https://summary.mayx.eu.org/count_click_add?id="+visitors[0].id,function(data){
|
||||||
visitors[0].innerHTML=Number(data);
|
visitors[0].innerHTML=Number(data);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -54,4 +53,4 @@ if (daysold > 90) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var message_Path = '/Live2dHistoire/live2d/';
|
var message_Path = '/Live2dHistoire/live2d/';
|
||||||
var talkAPI = auxiliaryHost+"/talk.php";
|
var talkAPI = "https://turing-api.mayx.eu.org/";
|
||||||
|
7
package.json
Normal file
7
package.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"name": "mayx-blog",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"scripts": {
|
||||||
|
"build": "bash deploy.sh"
|
||||||
|
}
|
||||||
|
}
|
33
proxylist.md
33
proxylist.md
@ -3,28 +3,29 @@ layout: default
|
|||||||
title: 代理列表
|
title: 代理列表
|
||||||
---
|
---
|
||||||
|
|
||||||
源站:<https://mabbs.github.io>
|
源站:<https://mabbs.github.io> <img src="https://mabbs.github.io/images/online.svg" style="width:22px;vertical-align: bottom" onerror="this.src = '/images/offline.svg'"/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# 代理列表
|
# 代理列表
|
||||||
考虑到中国对于Github Pages在很多地区都有一定程度的解析异常,所以我为我的博客做了很多反向代理。以下代理站均为官方授权:
|
考虑到中国对于Github Pages在很多地区都有一定程度的解析异常,所以我为我的博客做了很多反向代理。以下代理站均为官方授权:
|
||||||
(根据可能的可用性排序)
|
(根据可能的可用性排序)
|
||||||
- <https://blog.mayx.workers.dev/>
|
- <https://blog.mayx.workers.dev/> <img src="https://blog.mayx.workers.dev/images/online.svg" style="width:22px;vertical-align: bottom" onerror="this.src = '/images/offline.svg'"/>
|
||||||
- <https://mayx.deno.dev/>
|
- <https://mayx.deno.dev/> <img src="https://mayx.deno.dev/images/online.svg" style="width:22px;vertical-align: bottom" onerror="this.src = '/images/offline.svg'"/>
|
||||||
- <https://mayx.cyclic.app/>
|
- <https://mayx.serv00.net/> <img src="https://mayx.serv00.net/images/online.svg" style="width:22px;vertical-align: bottom" onerror="this.src = '/images/offline.svg'"/>
|
||||||
- <https://mayx.glitch.me/>
|
- <https://mayx.glitch.me/> <img src="https://mayx.glitch.me/images/online.svg" style="width:22px;vertical-align: bottom" onerror="this.src = '/images/offline.svg'"/>
|
||||||
- <https://blog.mayx.cf/>
|
- <https://yuki.gear.host/> <img src="https://yuki.gear.host/images/online.svg" style="width:22px;vertical-align: bottom" onerror="this.src = '/images/offline.svg'"/>
|
||||||
- <https://blog.mayx.tk/>
|
|
||||||
- <https://yuki.gear.host/>
|
|
||||||
|
|
||||||
# 镜像列表
|
# 镜像列表
|
||||||
由于[Github已经不再可信](/2022/01/04/banned.html),所以现在提供以下镜像站:
|
由于[Github已经不再可信](/2022/01/04/banned.html),所以现在提供以下镜像站:
|
||||||
- <https://mayx.gitlab.io/>
|
- <https://mayx.gitlab.io/> <img src="https://mayx.gitlab.io/images/online.svg" style="width:22px;vertical-align: bottom" onerror="this.src = '/images/offline.svg'"/>
|
||||||
- <https://mayx.pages.dev/>
|
- <https://mayx.pages.dev/> <img src="https://mayx.pages.dev/images/online.svg" style="width:22px;vertical-align: bottom" onerror="this.src = '/images/offline.svg'"/>
|
||||||
- <https://mayx.eu.org/>
|
- <https://mayx.eu.org/> <img src="https://mayx.eu.org/images/online.svg" style="width:22px;vertical-align: bottom" onerror="this.src = '/images/offline.svg'"/>
|
||||||
- <https://mayx.vercel.app/>
|
- <https://mayx.vercel.app/> <img src="https://mayx.vercel.app/images/online.svg" style="width:22px;vertical-align: bottom" onerror="this.src = '/images/offline.svg'"/>
|
||||||
- <https://mayx.netlify.app/>
|
- <https://mayx.netlify.app/> <img src="https://mayx.netlify.app/images/online.svg" style="width:22px;vertical-align: bottom" onerror="this.src = '/images/offline.svg'"/>
|
||||||
- <https://mayx.4everland.app/>
|
- <https://mayx.4everland.app/> <img src="https://mayx.4everland.app/images/online.svg" style="width:22px;vertical-align: bottom" onerror="this.src = '/images/offline.svg'"/>
|
||||||
- <https://xu4qy-yiaaa-aaaag-aa2iq-cai.raw.ic0.app/>
|
- <https://mayx.dappling.network/> <img src="https://mayx.dappling.network/images/online.svg" style="width:22px;vertical-align: bottom" onerror="this.src = '/images/offline.svg'"/>
|
||||||
|
- <https://xu4qy-yiaaa-aaaag-aa2iq-cai.raw.ic0.app/> <img src="https://xu4qy-yiaaa-aaaag-aa2iq-cai.raw.ic0.app/images/online.svg" style="width:22px;vertical-align: bottom" onerror="this.src = '/images/offline.svg'"/>
|
||||||
|
|
||||||
# 其他平台博客(备用)
|
# 其他平台博客(备用)
|
||||||
- <https://unmayx.blogspot.com/>
|
- <https://unmayx.blogspot.com/>
|
||||||
@ -35,5 +36,3 @@ title: 代理列表
|
|||||||
- <https://unmayx.medium.com/>
|
- <https://unmayx.medium.com/>
|
||||||
- <https://mayx.cnblogs.com/>
|
- <https://mayx.cnblogs.com/>
|
||||||
- <https://mayx.xlog.app/>
|
- <https://mayx.xlog.app/>
|
||||||
- <https://mayx.proselog.com/>
|
|
||||||
- <https://mayx.substack.com/>
|
|
||||||
|
Reference in New Issue
Block a user