mirror of
https://github.com/Mabbs/mabbs.github.io
synced 2025-09-28 19:15:42 +08:00
Compare commits
53 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 | |||
09c88ebf18 | |||
2aed9e9d90 | |||
bfe05eef58 | |||
5713b1b477 | |||
52eb8cd0a7 | |||
c17b6f0971 | |||
e7ad732f8d | |||
8b6738dcef | |||
c52e7ded82 | |||
2df79d6a44 | |||
59688d1e1f | |||
86edb37efb | |||
d06229e705 | |||
385b842c80 | |||
1cd08a24bd | |||
c664d9e93a | |||
8dcfcaeb7b | |||
57f8e30bf4 |
@ -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:
|
||||||
|
10
BlogCard.svg
10
BlogCard.svg
@ -105,31 +105,31 @@
|
|||||||
<g class="stagger" style="animation-delay: 450ms" transform="translate(25, 0)">
|
<g class="stagger" style="animation-delay: 450ms" transform="translate(25, 0)">
|
||||||
<line x1="12" y1="6.25" x2="19" y2="6.25"
|
<line x1="12" y1="6.25" x2="19" y2="6.25"
|
||||||
style="stroke:rgb(255,255,255);stroke-width:2"/>
|
style="stroke:rgb(255,255,255);stroke-width:2"/>
|
||||||
<text class="stat bold" x="25" y="12.5">{{ site.posts[0].title }}</text>
|
<text class="stat bold" x="25" y="12.5">{{ site.posts[0].title | truncate: 18 }}</text>
|
||||||
</g>
|
</g>
|
||||||
</g><g transform="translate(0, 25)">
|
</g><g transform="translate(0, 25)">
|
||||||
<g class="stagger" style="animation-delay: 600ms" transform="translate(25, 0)">
|
<g class="stagger" style="animation-delay: 600ms" transform="translate(25, 0)">
|
||||||
<line x1="12" y1="6.25" x2="19" y2="6.25"
|
<line x1="12" y1="6.25" x2="19" y2="6.25"
|
||||||
style="stroke:rgb(255,255,255);stroke-width:2"/>
|
style="stroke:rgb(255,255,255);stroke-width:2"/>
|
||||||
<text class="stat bold" x="25" y="12.5">{{ site.posts[1].title }}</text>
|
<text class="stat bold" x="25" y="12.5">{{ site.posts[1].title | truncate: 18 }}</text>
|
||||||
</g>
|
</g>
|
||||||
</g><g transform="translate(0, 50)">
|
</g><g transform="translate(0, 50)">
|
||||||
<g class="stagger" style="animation-delay: 750ms" transform="translate(25, 0)">
|
<g class="stagger" style="animation-delay: 750ms" transform="translate(25, 0)">
|
||||||
<line x1="12" y1="6.25" x2="19" y2="6.25"
|
<line x1="12" y1="6.25" x2="19" y2="6.25"
|
||||||
style="stroke:rgb(255,255,255);stroke-width:2"/>
|
style="stroke:rgb(255,255,255);stroke-width:2"/>
|
||||||
<text class="stat bold" x="25" y="12.5">{{ site.posts[2].title }}</text>
|
<text class="stat bold" x="25" y="12.5">{{ site.posts[2].title | truncate: 18 }}</text>
|
||||||
</g>
|
</g>
|
||||||
</g><g transform="translate(0, 75)">
|
</g><g transform="translate(0, 75)">
|
||||||
<g class="stagger" style="animation-delay: 900ms" transform="translate(25, 0)">
|
<g class="stagger" style="animation-delay: 900ms" transform="translate(25, 0)">
|
||||||
<line x1="12" y1="6.25" x2="19" y2="6.25"
|
<line x1="12" y1="6.25" x2="19" y2="6.25"
|
||||||
style="stroke:rgb(255,255,255);stroke-width:2"/>
|
style="stroke:rgb(255,255,255);stroke-width:2"/>
|
||||||
<text class="stat bold" x="25" y="12.5">{{ site.posts[3].title }}</text>
|
<text class="stat bold" x="25" y="12.5">{{ site.posts[3].title | truncate: 18 }}</text>
|
||||||
</g>
|
</g>
|
||||||
</g><g transform="translate(0, 100)">
|
</g><g transform="translate(0, 100)">
|
||||||
<g class="stagger" style="animation-delay: 1050ms" transform="translate(25, 0)">
|
<g class="stagger" style="animation-delay: 1050ms" transform="translate(25, 0)">
|
||||||
<line x1="12" y1="6.25" x2="19" y2="6.25"
|
<line x1="12" y1="6.25" x2="19" y2="6.25"
|
||||||
style="stroke:rgb(255,255,255);stroke-width:2"/>
|
style="stroke:rgb(255,255,255);stroke-width:2"/>
|
||||||
<text class="stat bold" x="25" y="12.5">{{ site.posts[4].title }}</text>
|
<text class="stat bold" x="25" y="12.5">{{ site.posts[4].title | truncate: 18 }}</text>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
|
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
|
||||||
|
@ -289,16 +289,16 @@ if(!norunFlag){
|
|||||||
type: 'POST',
|
type: 'POST',
|
||||||
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,153 +1,140 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
|
|
||||||
{% seo %}
|
<head>
|
||||||
{% feed_meta %}
|
<meta charset="UTF-8">
|
||||||
<link rel="stylesheet" href="{{ "/assets/css/style.css?v=" | append: site.github.build_revision | relative_url }}">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<!--[if !IE]> -->
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="stylesheet" href="/Live2dHistoire/live2d/css/live2d.css" />
|
|
||||||
<script src="/js/jquery.min.js"></script>
|
{% seo %}
|
||||||
<!-- <![endif]-->
|
{% feed_meta %}
|
||||||
<!--[if lt IE 9]>
|
<link rel="stylesheet" href="{{ "/assets/css/style.css?v=" | append: site.github.build_revision | relative_url }}">
|
||||||
|
<!--[if !IE]> -->
|
||||||
|
<link rel="stylesheet" href="/Live2dHistoire/live2d/css/live2d.css" />
|
||||||
|
<script src="/js/jquery.min.js"></script>
|
||||||
|
<!-- <![endif]-->
|
||||||
|
<!--[if lt IE 9]>
|
||||||
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.min.js"></script>
|
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.min.js"></script>
|
||||||
<![endif]-->
|
<![endif]-->
|
||||||
|
|
||||||
{% if site.google_analytics %}
|
{% if site.google_analytics %}
|
||||||
<!-- Global site tag (gtag.js) - Google Analytics -->
|
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||||||
<script async src="https://www.googletagmanager.com/gtag/js?id={{ site.google_analytics }}"></script>
|
<script async src="https://www.googletagmanager.com/gtag/js?id={{ site.google_analytics }}"></script>
|
||||||
<script>
|
<script>
|
||||||
window.dataLayer = window.dataLayer || [];
|
window.dataLayer = window.dataLayer || [];
|
||||||
function gtag(){dataLayer.push(arguments);}
|
function gtag(){dataLayer.push(arguments);}
|
||||||
gtag('js', new Date());
|
gtag('js', new Date());
|
||||||
|
|
||||||
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) {
|
</script>
|
||||||
var o = {
|
{% endif %}
|
||||||
"M+" : this.getMonth()+1, //月份
|
<style>
|
||||||
"d+" : this.getDate(), //日
|
.backToTop {
|
||||||
"h+" : this.getHours(), //小时
|
display: none;
|
||||||
"m+" : this.getMinutes(), //分
|
width: 18px;
|
||||||
"s+" : this.getSeconds(), //秒
|
line-height: 1.2;
|
||||||
"q+" : Math.floor((this.getMonth()+3)/3), //季度
|
padding: 5px 0;
|
||||||
"S" : this.getMilliseconds() //毫秒
|
background-color: #000;
|
||||||
};
|
color: #fff;
|
||||||
if(/(y+)/.test(fmt)) {
|
font-size: 12px;
|
||||||
fmt=fmt.replace(RegExp.$1, (this.getFullYear()+"").substr(4 - RegExp.$1.length));
|
text-align: center;
|
||||||
|
position: fixed;
|
||||||
|
_position: absolute;
|
||||||
|
right: 10px;
|
||||||
|
bottom: 100px;
|
||||||
|
_bottom: "auto";
|
||||||
|
cursor: pointer;
|
||||||
|
opacity: .6;
|
||||||
|
filter: Alpha(opacity=60);
|
||||||
}
|
}
|
||||||
for(var k in o) {
|
</style>
|
||||||
if(new RegExp("("+ k +")").test(fmt)){
|
</head>
|
||||||
fmt = fmt.replace(RegExp.$1, (RegExp.$1.length==1) ? (o[k]) : (("00"+ o[k]).substr((""+ o[k]).length)));
|
|
||||||
}
|
<body>
|
||||||
}
|
<div class="wrapper">
|
||||||
return fmt;
|
<header>
|
||||||
}
|
<h1><a href="{{ "/" | relative_url }}">{{ site.title | default: site.github.repository_name }}</a></h1>
|
||||||
</script>
|
|
||||||
{% endif %}
|
{% if site.logo %}
|
||||||
<style>
|
<img src="{{ site.logo }}" alt="Logo" />
|
||||||
.backToTop {
|
|
||||||
display: none;
|
|
||||||
width: 18px;
|
|
||||||
line-height: 1.2;
|
|
||||||
padding: 5px 0;
|
|
||||||
background-color: #000;
|
|
||||||
color: #fff;
|
|
||||||
font-size: 12px;
|
|
||||||
text-align: center;
|
|
||||||
position: fixed;
|
|
||||||
_position: absolute;
|
|
||||||
right: 10px;
|
|
||||||
bottom: 100px;
|
|
||||||
_bottom: "auto";
|
|
||||||
cursor: pointer;
|
|
||||||
opacity: .6;
|
|
||||||
filter: Alpha(opacity=60);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="wrapper">
|
|
||||||
<header>
|
|
||||||
<h1><a href="{{ "/" | relative_url }}">{{ site.title | default: site.github.repository_name }}</a></h1>
|
|
||||||
|
|
||||||
{% if site.logo %}
|
|
||||||
<img src="{{ site.logo | relative_url}}" 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>
|
|
||||||
|
|
||||||
{% if site.github.is_project_page %}
|
<p>
|
||||||
<p class="view"><a href="{{ site.github.repository_url }}">View the Project on GitHub <small>{{ site.github.repository_nwo }}</small></a></p>
|
<form action="/search.html"><input type="text" name="keyword" id="search-input-all" placeholder="Search blog posts..">
|
||||||
{% endif %}
|
<input type="submit">
|
||||||
|
</form>
|
||||||
|
</p>
|
||||||
|
|
||||||
{% if site.github.is_user_page %}
|
{% if site.github.is_project_page %}
|
||||||
<p class="view"><a href="{{ site.github.owner_url }}">View My GitHub Profile</a></p>
|
<p class="view"><a href="{{ site.github.repository_url }}">View the Project on GitHub
|
||||||
{% endif %}
|
<small>{{ site.github.repository_nwo }}</small></a></p>
|
||||||
|
{% endif %}
|
||||||
<p class="view"><a href="{{ "/Mabbs/" | relative_url }}">About Me</a></p>
|
|
||||||
|
|
||||||
<ul class="downloads">
|
{% if site.github.is_user_page %}
|
||||||
|
<p class="view"><a href="{{ site.github.owner_url }}">View My GitHub Profile</a></p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<p class="view"><a href="/Mabbs/">About Me</a></p>
|
||||||
|
|
||||||
|
<ul class="downloads">
|
||||||
{% if site.github %}
|
{% if site.github %}
|
||||||
<li><a href="{{ site.github.zip_url }}">Download <strong>ZIP File</strong></a></li>
|
<li><a href="{{ site.github.zip_url }}">Download <strong>ZIP File</strong></a></li>
|
||||||
<li><a href="{{ site.github.tar_url }}">Download <strong>TAR Ball</strong></a></li>
|
<li><a href="{{ site.github.tar_url }}">Download <strong>TAR Ball</strong></a></li>
|
||||||
<li><a href="{{ site.github.repository_url }}">View On <strong>GitHub</strong></a></li>
|
<li><a href="{{ site.github.repository_url }}">View On <strong>GitHub</strong></a></li>
|
||||||
{% else %}
|
{% else %}
|
||||||
<li style="width: 270px;border-right:0px;"><a href="/MayxBlog.tgz">Download <strong>TGZ File</strong></a></li>
|
<li style="width: 270px;border-right:0px;"><a href="/MayxBlog.tgz">Download <strong>TGZ File</strong></a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
</header>
|
</header>
|
||||||
<section>
|
<section>
|
||||||
|
|
||||||
{{ content }}
|
{{ content }}
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
<!--[if !IE]> -->
|
<!--[if !IE]> -->
|
||||||
<div id="landlord" style="left:5px;bottom:0px;">
|
<div id="landlord" style="left:5px;bottom:0px;">
|
||||||
<div class="message" style="opacity:0"></div>
|
<div class="message" style="opacity:0"></div>
|
||||||
<canvas id="live2d" width="500" height="560" class="live2d"></canvas>
|
<canvas id="live2d" width="500" height="560" class="live2d"></canvas>
|
||||||
<div class="live_talk_input_body">
|
<div class="live_talk_input_body">
|
||||||
<div class="live_talk_input_name_body" style="display:none;">
|
<div class="live_talk_input_name_body" style="display:none;">
|
||||||
<input name="name" type="hidden" class="live_talk_name white_input" id="AIuserName" value="Mayx_Blog_Talk" />
|
<input name="name" type="hidden" class="live_talk_name white_input" id="AIuserName" value="Mayx_Blog_Talk" />
|
||||||
</div>
|
</div>
|
||||||
<div class="live_talk_input_text_body">
|
<div class="live_talk_input_text_body">
|
||||||
<input name="talk" type="text" class="live_talk_talk white_input" id="AIuserText" autocomplete="off" placeholder="要和我聊什么呀?"/>
|
<input name="talk" type="text" class="live_talk_talk white_input" id="AIuserText" autocomplete="off" placeholder="要和我聊什么呀?"/>
|
||||||
<button type="button" class="live_talk_send_btn" id="talk_send">发送</button>
|
<button type="button" class="live_talk_send_btn" id="talk_send">发送</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<input name="live_talk" id="live_talk" value="1" type="hidden" />
|
<input name="live_talk" id="live_talk" value="1" type="hidden" />
|
||||||
<div class="live_ico_box" style="display:none;">
|
<div class="live_ico_box" style="display:none;">
|
||||||
<div class="live_ico_item type_info" id="showInfoBtn"></div>
|
<div class="live_ico_item type_info" id="showInfoBtn"></div>
|
||||||
<div class="live_ico_item type_talk" id="showTalkBtn"></div>
|
<div class="live_ico_item type_talk" id="showTalkBtn"></div>
|
||||||
<div class="live_ico_item type_music" id="musicButton"></div>
|
<div class="live_ico_item type_music" id="musicButton"></div>
|
||||||
<div class="live_ico_item type_youdu" id="youduButton"></div>
|
<div class="live_ico_item type_youdu" id="youduButton"></div>
|
||||||
<div class="live_ico_item type_quit" id="hideButton"></div>
|
<div class="live_ico_item type_quit" id="hideButton"></div>
|
||||||
<input name="live_statu_val" id="live_statu_val" value="0" type="hidden" />
|
<input name="live_statu_val" id="live_statu_val" value="0" type="hidden" />
|
||||||
<audio src="" style="display:none;" id="live2d_bgm" data-bgm="0" preload="none"></audio>
|
<audio src="" style="display:none;" id="live2d_bgm" data-bgm="0" preload="none"></audio>
|
||||||
<input id="duType" value="douqilai" type="hidden">
|
<input id="duType" value="douqilai" type="hidden">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<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>
|
|
||||||
|
|
||||||
<script src="/js/main.js"></script>
|
<script src="/js/main.js"></script>
|
||||||
<!--[if !IE]> -->
|
<!--[if !IE]> -->
|
||||||
<script src="/Live2dHistoire/live2d/js/live2d.js"></script>
|
<script src="/Live2dHistoire/live2d/js/live2d.js"></script>
|
||||||
<script src="/Live2dHistoire/live2d/js/message.js"></script>
|
<script src="/Live2dHistoire/live2d/js/message.js"></script>
|
||||||
|
|
||||||
<!-- <![endif]-->
|
<!-- <![endif]-->
|
||||||
</body>
|
</body>
|
||||||
</html>
|
|
||||||
|
</html>
|
@ -2,89 +2,133 @@
|
|||||||
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>
|
||||||
<div id="outdate" style="display:none;">
|
<div id="outdate" style="display:none;">
|
||||||
<hr />
|
<hr />
|
||||||
这是一篇创建于 <span id="outime"></span> 天前的文章,其中的信息可能已经有所发展或是发生改变。
|
这是一篇创建于 <span id="outime"></span> 天前的文章,其中的信息可能已经有所发展或是发生改变。
|
||||||
<br /><br />
|
<br /><br />
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
BirthDay = new Date("{{ page.date | date: "%m/%d/%Y" }} 00:00:00");
|
BirthDay = new Date("{{ page.date | date: "%m/%d/%Y" }} 00:00:00");
|
||||||
today = new Date();
|
today = new Date();
|
||||||
timeold = (today.getTime() - BirthDay.getTime());
|
timeold = (today.getTime() - BirthDay.getTime());
|
||||||
secondsold = Math.floor(timeold / 1000);
|
secondsold = Math.floor(timeold / 1000);
|
||||||
e_daysold = timeold / (24 * 60 * 60 * 1000);
|
e_daysold = timeold / (24 * 60 * 60 * 1000);
|
||||||
daysold = Math.floor(e_daysold);
|
daysold = Math.floor(e_daysold);
|
||||||
if (daysold > 90) {
|
if (daysold > 90) {
|
||||||
document.getElementById("outdate").style.display = "block";
|
document.getElementById("outdate").style.display = "block";
|
||||||
document.getElementById("outime").innerHTML = daysold;
|
document.getElementById("outime").innerHTML = daysold;
|
||||||
}
|
}
|
||||||
</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 %}
|
{% include toc.html html=content sanitize=true h_max=3 %}
|
||||||
|
|
||||||
{{content}}
|
{{content}}
|
||||||
|
|
||||||
{% if page.tags %}
|
{% if page.tags %}
|
||||||
<small>tags: <em>{{ page.tags | join: "</em> - <em>" }}</em></small>
|
<small>tags: <em>{{ page.tags | join: "</em> - <em>" }}</em></small>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<div class="pagination">
|
<div class="pagination">
|
||||||
{% if page.previous.url %}
|
{% if page.previous.url %}
|
||||||
<span class="prev" >
|
<span class="prev">
|
||||||
<a href="{{ site.baseurl }}{{ page.previous.url }}">
|
<a href="{{ site.baseurl }}{{ page.previous.url }}">
|
||||||
上一篇:{{ page.previous.title }}
|
上一篇:{{ page.previous.title }}
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<br />
|
<br />
|
||||||
{% if page.next.url %}
|
{% if page.next.url %}
|
||||||
<span class="next" >
|
<span class="next">
|
||||||
<a href="{{ site.baseurl }}{{ page.next.url }}">
|
<a href="{{ site.baseurl }}{{ page.next.url }}">
|
||||||
下一篇:{{ page.next.title }}
|
下一篇:{{ page.next.title }}
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!--[if !IE]> -->
|
<!--[if !IE]> -->
|
||||||
<link rel="stylesheet" href="/css/gitalk.css">
|
<link rel="stylesheet" href="/css/gitalk.css">
|
||||||
<script src="/js/gitalk.min.js"></script>
|
<script src="/js/gitalk.min.js"></script>
|
||||||
|
|
||||||
<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',
|
repo: 'mabbs.github.io',
|
||||||
repo: 'mabbs.github.io',
|
owner: 'Mabbs',
|
||||||
owner: 'Mabbs',
|
admin: ['Mabbs'],
|
||||||
admin: ['Mabbs'],
|
id: '{{ page.id }}', // Ensure uniqueness and length less than 50
|
||||||
id: '{{ page.id }}', // Ensure uniqueness and length less than 50
|
distractionFreeMode: false // Facebook-like distraction free mode
|
||||||
distractionFreeMode: false // Facebook-like distraction free mode
|
})
|
||||||
})
|
}
|
||||||
}
|
else {
|
||||||
else
|
var gitalk = new Gitalk({
|
||||||
{
|
clientID: '36557aec4c3cb04f7ac6',
|
||||||
var gitalk = new Gitalk({
|
clientSecret: 'ac32993299751cb5a9ba81cf2b171cca65879cdb',
|
||||||
clientID: '36557aec4c3cb04f7ac6',
|
repo: 'mabbs.github.io',
|
||||||
clientSecret: 'ac32993299751cb5a9ba81cf2b171cca65879cdb',
|
owner: 'Mabbs',
|
||||||
repo: 'mabbs.github.io',
|
admin: ['Mabbs'],
|
||||||
owner: 'Mabbs',
|
id: '{{ page.id }}', // Ensure uniqueness and length less than 50
|
||||||
admin: ['Mabbs'],
|
distractionFreeMode: false // Facebook-like distraction free mode
|
||||||
id: '{{ page.id }}', // Ensure uniqueness and length less than 50
|
})
|
||||||
distractionFreeMode: false // Facebook-like distraction free mode
|
}
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
gitalk.render('gitalk-container')
|
gitalk.render('gitalk-container')
|
||||||
</script>
|
</script>
|
||||||
<!-- <![endif]-->
|
<!-- <![endif]-->
|
@ -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吧。
|
||||||
|
|
||||||
|
23
_posts/2023-05-22-rpi-win.md
Normal file
23
_posts/2023-05-22-rpi-win.md
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
---
|
||||||
|
layout: post
|
||||||
|
title: 使用树莓派安装Windows的尝试
|
||||||
|
tags: [树莓派, Windows]
|
||||||
|
---
|
||||||
|
|
||||||
|
树莓派能不能作为迷你主机使用呢?<!--more-->
|
||||||
|
|
||||||
|
# 起因
|
||||||
|
前段时间,家里人送给了我一个树莓派4B-8GiB内存版,因为手头用着MacBook Pro,看到这个比我之前用的树莓派3B好了不少的东西,就开始想它能不能和用着一样是ARM架构的Mac Mini M2那样使用,当然想给树莓派安装黑苹果那就是天方夜谭了,毕竟macOS里用到的很多东西也不完全只是ARM,想想也知道既然是苹果自己研发的芯片,里面肯定是有一些比如专有的指令集什么的,树莓派应该算是公版的ARM吧?肯定有些指令是没有的……不过我还是愿意仿个macOS试试看,我在网上看好像[TwisterOS](https://twisteros.com)仿macOS的效果最好,而且它是基于树莓派官方系统开发的,所以应该也没啥兼容性的问题,另外它其他的主题比如仿Windows的做的也不错,但仿Windows还不如给它装一个真正的Windows,毕竟网上是有能够给树莓派安装Windows ARM版的办法的。
|
||||||
|
|
||||||
|
# 给树莓派安装Windows
|
||||||
|
最开始我想给树莓派安装Windows的时候手头没有Windows的电脑,但是给树莓派安装Windows所用的软件[Windows on R](https://worproject.com)貌似用到了Windows上的一些东西。不过他们提供了一种可以先给卡里安装WinPE然后再安装系统的办法,最开始我是先尝试的那种方案,我可以先用一张安装了树莓派官方系统启动树莓派,然后用[WoR-flasher](https://github.com/Botspot/wor-flasher)给另外一张卡安装WinPE以及系统镜像。操作很简单,照着README做就行了,不过不知道是为什么,尝试了好几次,每次安装到一半就卡住然后报错安装失败,然后连WinPE都进不去了……
|
||||||
|
我怀疑是通过这种方式安装可能有什么问题,而且当时安装到时候卡是32GiB大小的,虽然官网上说32GiB是足够的,不过也许还是有什么问题?所以后来我重新买了一张64GiB的卡片,并且用Windows去运行Windows on Raspberry imager给卡里安装了Windows 11,不过很奇怪的是还是运行不了……换了好几个系统镜像都不行,后来才发现原来是我自作多情每次启动的时候都把频率调成2.2GHz所以不能启动,默认的1.5GHz或者调高到2.0GHz都没有问题😥,因为这个问题尝试了好多次……
|
||||||
|
|
||||||
|
# 在树莓派上的Windows体验
|
||||||
|
安装好之后就可以尝试验证树莓派的生产力了,不过结果让我很失望……首先是我用的TF卡是UHS-1,写速度貌似是10MiB/s?读速度商家宣传是130MiB/s不过实际上我也不太清楚,随机读写估计就更慢了……这样的速度加载东西实在是有够慢……另外目前[在树莓派上使用的Windows驱动](https://github.com/worproject/RPi-Windows-Drivers)里并没有无线网卡和核显的驱动,所以体验也很差,移动窗口之类的操作CPU都占用了不少,我本来还想着考虑能不能比Macbook开虚拟机效果好一些,不过目前来看这个结果应该是只差不好吧……虽然价格上树莓派和Mac Mini M2差了4倍,不过体验这么差的话估计当生产力是没机会了。
|
||||||
|
|
||||||
|
# Linux的生产力对比
|
||||||
|
相比之下用树莓派官方的系统感觉要流畅不少,毕竟官方系统的所有驱动都是正常工作的,应该也能使用硬件解码,只是有些桌面版的程序没有,比如MS Office,还有像7-Zip、WinSCP、XShell之类的软件 ~~(其实macOS也不行🤣)~~ ……用Wine怎么样呢?其实我觉得应该好不到哪里,毕竟大多数Windows的程序都是x86_64指令集,Wine想要运行这些软件照样得靠QEMU翻译,只不过可能调用的一些Windows的API可以原生执行而已,除了这些之外,我还试了试用Chromium播放Bilibili的视频,结果也令人大失所望,360p的视频都不能流畅播放,更别说1080p了(当然也不排除是因为Bilibili的视频用了硬件解码器不能解码的编码方式),虽然相比树莓派3B来说确实至少可以流畅浏览网页了,但是连视频都不能流畅播放那看来想当生产力还很远呢。
|
||||||
|
|
||||||
|
# 感想
|
||||||
|
果然树莓派还是没有办法当作普通的电脑来用啊,更不用说生产力了,同样的价格至少还能组个能打游戏的电脑。尽管性能比树莓派3B好不少,但毕竟用的还是很低级的芯片,也许它就应该当作物联网的开发板来使用吧,但很奇怪的是如果是这样,树莓派3B就足够了吧,何必开发树莓派4B以及带键盘的树莓派400呢?还有就是树莓派CM4,他们不会真以为自己的芯片速度很快吧🤣?
|
301
_posts/2023-06-30-nucleic-acid.md
Normal file
301
_posts/2023-06-30-nucleic-acid.md
Normal file
@ -0,0 +1,301 @@
|
|||||||
|
---
|
||||||
|
layout: post
|
||||||
|
title: 基于ThinkPHP5.1核酸检测登记系统的设计与开发
|
||||||
|
tags: [核酸检测, 后端, 系统设计, 论文]
|
||||||
|
---
|
||||||
|
|
||||||
|
论如何水一篇论文🤣<!--more-->
|
||||||
|
|
||||||
|
# 前言
|
||||||
|
最近终于顺利毕业了……既然说到毕业,那毕业论文肯定是最重要的。既然已经毕业了,那就顺便把毕业论文发出来吧,反正也算是我写的东西 ~~(可以拿来水一水博客😝)~~ 。另外还有配套的[项目源代码](https://github.com/Mabbs/nucleic-acid-management)也一起发出来吧。
|
||||||
|
另外这个毕业论文经过了ChatGPT润色,包括项目代码也使用Github Copilot,现在的AI真的是相当方便啊,自己写的不通顺的地方,它可以帮你改的更流畅,算是理科生的福音了😝,而且内容是完全原创的,查重也只有个位数,大大降低我在写这个没用的东西上浪费的时间😁,而且写的也相当不错,可以说确实是能大幅提高生产力了,至少在AI兴起的这段时间里,不仅仅是[玩AI](/2023/04/05/ai.html),也得拿AI解决点自己的问题才算跟得上时代吧。
|
||||||
|
另外原文的所有图片为了节省空间,还有一些比较复杂的表格因为用Markdown写太麻烦所以都去除掉了,那么从接下来开始就是论文的正文部分了:
|
||||||
|
|
||||||
|
# 摘要
|
||||||
|
本文介绍了基于ThinkPHP框架开发的核酸检测登记系统的设计和开发过程,包括需求分析、数据库设计、功能实现和系统测试等方面。该系统旨在方便用户在线登记核酸检测信息,提高检测效率、减少人员接触,专为新冠疫情防控而设计。在需求分析阶段,规划了系统的功能和性能需求;在数据库设计方面,采用了关系型数据库MySQL;在功能实现方面,使用了前后端分离架构,其中后台前端采用Vue框架,用户前端使用jQuery库,后端采用ThinkPHP框架;在系统测试方面,介绍了系统测试结果及问题解决方案。通过本文的介绍,读者可以了解项目开发的各个方面,对具体的项目开发有更深入的认识。
|
||||||
|
|
||||||
|
**关键词:** 核酸检测,后端,系统设计
|
||||||
|
|
||||||
|
# ABSTRACT
|
||||||
|
This article describes the design and development process of a nucleic acid testing registration system based on the ThinkPHP framework, including requirements analysis, database design, feature implementation, and system testing. The system aims to facilitate users in registering nucleic acid testing information online, improve testing efficiency, reduce personnel contact, and is specifically designed for COVID-19 pandemic prevention and control. In the requirements analysis phase, the system's functional and performance requirements were planned. For database design, a relational database MySQL was adopted. In feature implementation, a front-end and back-end separation architecture was used, with the back-end front-end using the Vue framework, user front-end using the jQuery library, and the back-end using the ThinkPHP framework. System testing results and problem-solving solutions are also presented. Through this article, readers can gain a comprehensive understanding of the various aspects of project development and have a deeper understanding of specific project development.
|
||||||
|
**Key Words:** nucleic acid testing, back-end, system design
|
||||||
|
|
||||||
|
# 第1章 绪论
|
||||||
|
## 1.1 选题背景
|
||||||
|
核酸检测是一种用于检测病原体(例如病毒、细菌等)的常见检测方法之一,也被广泛用于新型冠状病毒(COVID-19)的检测中。在COVID-19大流行期间,核酸检测已成为公共卫生应对策略的重要组成部分。核酸检测主要是通过提取样本中的核酸(例如RNA或DNA),然后使用特定的技术(例如聚合酶链式反应PCR)扩增特定的基因序列来检测是否存在目标病原体。这些检测技术可以用于检测病原体的存在,也可以用于确定感染者的数量和病毒载量等信息文章内容<sup id="al1">[[1]](#ref1)</sup>。对于COVID-19,核酸检测被广泛用于诊断和监测感染者,以及筛查病毒感染的人群。许多国家和地区都采取了强制性的核酸检测措施来控制疫情,例如旅行前的检测和隔离措施。为了有效地管理核酸检测和监测COVID-19疫情,许多地区建立了核酸检测登记系统。这些系统通常由卫生部门或其他相关机构负责,旨在收集和管理核酸检测的数据,以便有效地跟踪和监测疫情的发展趋势,并及时采取必要的应对措施。本文以ThinkPHP开发框架为基础,微信平台作为承载,研究了基于ThinkPHP5.1的核酸检测登记系统的设计与实现,包括系统需求分析、系统功能设计、公众号设计、接口设计以及数据库设计。重点阐述了普通用户与管理用户的用户模块、核酸试剂模块、公告模块的设计<sup id="al2">[[2]](#ref2)</sup>。
|
||||||
|
## 1.2 研究目标和意义
|
||||||
|
该研究的主要目标是设计和实现一个基于ThinkPHP5.1的核酸检测登记系统,该系统可以通过微信平台进行访问和使用。该系统将具有以下功能:
|
||||||
|
用户模块:该系统将支持普通用户和管理用户两种不同类型的用户。普通用户可以在系统中注册并填写个人信息,以便卫生部门进行核酸检测和疫情监测。管理用户可以对系统中的数据进行管理和维护,包括审核用户信息、发布公告、查询数据等。
|
||||||
|
核酸试剂模块:该系统将支持管理用户管理核酸试剂信息,包括试剂的识别码、生产商、库存等信息。同时,系统将支持管理用户对试剂进行状态编辑、入库、销毁等操作,以便跟踪试剂的使用情况和库存情况。
|
||||||
|
公告模块:该系统将支持管理用户发布公告,包括疫情通报、政策通知、操作指南等信息。同时,系统将支持普通用户查看最新公告,并及时掌握疫情信息和政策变化。
|
||||||
|
该系统的意义在于:1.提高疫情监测和管理的效率:该系统可以有效地收集和管理核酸检测数据和试剂信息,为卫生部门和政府提供准确的疫情数据和管理信息,有助于及时发现和控制疫情的蔓延。2.提高用户体验和服务质量:该系统通过微信平台进行访问和使用,方便用户随时随地进行核酸检测登记和信息查询,提高用户的使用体验和服务质量。3.促进信息共享和协同合作:该系统可以实现数据共享和信息协同,协助各个部门和机构之间的合作,提高疫情防控的效率和质量。
|
||||||
|
该研究的创新点在于:将核酸检测结果通过微信公众号进行推送,从而方便用户快速查看检测结果,避免用户不必要的出行和接触风险。此外,通过将核酸检测与微信公众号相结合,可以实现对用户健康状态的实时监测和管理,进而提高社区健康防控水平。这一创新方法不仅提高了检测结果的传递效率,还为健康管理和疾病预防提供了新的思路。值得一提的是,该方法不仅适用于核酸检测,在其他领域的应用也具有潜力,可以为现代社会的公共卫生事业做出更大的贡献。
|
||||||
|
## 1.3 国内外现状
|
||||||
|
为确保核酸检测结果的真实性和可靠性,全球各国和地区都采用信息化技术建立了核酸检测登记系统,该系统将检测结果与检测者身份信息进行绑定。在疫情防控中,该系统有助于追踪和管理疫情。在设计相关产品之前,需要了解国内外核酸检测登记系统的现状,以更好地进行系统设计和开发。
|
||||||
|
### 1.3.1 国内现状
|
||||||
|
在中国,核酸检测登记系统已成为疫情防控的重要组成部分,并且已得到广泛应用。从2020年开始,核酸检测登记系统已成为中国疫情防控的重要组成部分,并且已得到广泛应用。这个系统的实施为疫情防控提供了极大的便利和帮助,既可以确保每个接受核酸检测的人的检测结果真实可靠,也可以实现有效的疫情追踪和管理。
|
||||||
|
在这个系统中,每个接受核酸检测的人都需要提供身份证件信息和手机号码,并将检测结果与个人信息进行绑定。这样一来,每个人的检测结果都可以被准确地记录和管理。此外,中国各个城市和机场也建立了相应的核酸检测登记系统,以确保疫情防控的有效性。这些系统通过高效的信息技术手段,实现了对接受检测的人员的信息管理和追踪,使疫情防控工作更加有力和高效。
|
||||||
|
除了国家级的核酸检测登记系统外,很多省市也建立了自己的系统,通过手机应用程序实现了个人核酸检测结果、健康状态和行程轨迹的信息管理。每个人的健康码都是动态的,根据个人的核酸检测结果、行程轨迹和接触史等信息进行自动更新,方便了疫情追踪和管理。这些系统的建立和应用为疫情防控提供了重要的技术支持和保障,同时也为其他公共卫生事件的应对提供了宝贵的经验和借鉴。
|
||||||
|
### 1.3.2 国外现状
|
||||||
|
随着新冠疫情在全球蔓延,越来越多的国家开始采取措施建立自己的核酸检测登记系统。除了美国CDC建立的COVID-19报告门户网站之外,其他国家也纷纷建立类似的在线平台,以便实验室和医疗机构可以直接向相关部门报告病例和检测结果。这些国家包括但不限于英国、德国、法国、澳大利亚等。
|
||||||
|
在欧洲,除了欧盟数字COVID证书系统外,一些国家也开始建立自己的核酸检测登记系统。例如,英国建立了国家医疗服务体系(NHS)测试和跟踪系统,该系统允许英国居民在线预约COVID-19测试,同时可以跟踪他们的检测结果<sup id="al3">[[3]](#ref3)</sup>。在德国,类似的系统名为Corona-Warn-App,通过手机应用程序追踪人们的接触历史和检测结果<sup id="al4">[[4]](#ref4)</sup>。
|
||||||
|
随着全球疫情形势的不断发展,建立核酸检测登记系统已成为越来越多国家的必然选择。这些系统可以更好地追踪和管理疫情,为政府和公众提供及时、准确的疫情信息,从而更好地应对疫情挑战。此外,这些系统还可以为旅行者提供方便,使他们能够更加安全地穿越不同国家和地区的边境,保护自己和他人的健康安全。
|
||||||
|
## 1.4 论文结构
|
||||||
|
本论文根据软件开发过程,详细阐述了系统实现整体流程,分为七章内容,具体结构如下:
|
||||||
|
第一章是本文的引言部分,主要介绍了核酸检测的背景、研究目的与意义、国内外研究现状以及研究内容与方法。通过对核酸检测的背景和相关问题的深入认识和分析,可以更好地理解本文的研究背景和动机。
|
||||||
|
第二章将对与本研究相关的技术进行概述,本章旨在为后续的研究内容提供技术支持和基础知识,帮助读者更好地理解本研究的实现和应用。
|
||||||
|
第三章主要对系统进行了需求分析及设计。具体而言,本章包括了系统的设计目标、功能和角色的关系和流程等方面的详细介绍。
|
||||||
|
第四章通过详细介绍每个模块的接口设计,展示了系统各个模块之间的联系和交互方式,以及模块之间的数据传输方式和数据格式。此外,我们还介绍了数据库的结构设计,包括表的设计、数据类型的选择、索引的使用等等。通过这些介绍,读者可以更好地了解系统的整体架构和实现细节。
|
||||||
|
第五章详细描述了系统的部分模块的具体实现过程,其中包括系统设计、系统功能的实际实现以及部分实现后的系统运行界面展示等。这一章节的目的是满足系统设计需求,并确保系统的各项功能能够得到有效的实现。
|
||||||
|
第六章我们会对一些接口进行软件测试。这包括设计测试用例、配置测试环境以及记录相应的测试结果。通过这些测试,我们不断改进系统,提高其性能。
|
||||||
|
第七章对主要是对本论文内容的总述以及展望。
|
||||||
|
|
||||||
|
# 第2章 相关技术概述
|
||||||
|
## 2.1 PHP语言
|
||||||
|
PHP(全称:Hypertext Preprocessor,中文名“超文本预处理器”)是一种广泛使用的开源服务器端脚本语言,它主要用于Web应用程序的开发。PHP可以嵌入到HTML中,也可以独立运行在服务器端,通过处理数据、生成动态内容和与数据库交互等方式来构建Web应用程序<sup id="al5">[[5]](#ref5)</sup>。
|
||||||
|
PHP最初是由Rasmus Lerdorf在1994年开发的,后来由开源社区不断发展和完善。PHP具有易学易用、高效快速、跨平台等特点,可以与各种Web服务器和数据库配合使用。目前,PHP已经成为最受欢迎的Web开发语言之一,许多知名的网站和应用程序都采用了PHP开发<sup id="al6">[[6]](#ref6)</sup>。
|
||||||
|
## 2.2 ThinkPHP框架
|
||||||
|
ThinkPHP是一个免费开源的,快速、简单的面向对象的轻量级PHP开发框架,是为了敏捷WEB应用开发和简化企业应用开发而诞生的。此框架提供了一系列丰富的功能和组件,包括路由、模板引擎、数据库操作、缓存、表单验证、文件上传等,支持多语言、多模块、多应用等功能,能够满足不同规模和需求的项目开发。另外该框架具有良好的扩展性和可定制性,可以根据实际需求选择和配置不同的组件和插件<sup id="al7">[[7]](#ref7)</sup>。同时,ThinkPHP框架也拥有一个活跃的开源社区,提供了丰富的文档和教程,方便开发者快速学习和上手。
|
||||||
|
## 2.3 MySQL数据库
|
||||||
|
MySQL是一款开源的关系型数据库管理系统,是目前最受欢迎的数据库之一。MySQL使用标准的SQL语言进行操作,支持多种操作系统,包括Windows、Linux、UNIX等,以及多种编程语言,如PHP、Java、Python等。
|
||||||
|
MySQL提供了高性能、高可靠性、高可扩展性和丰富的功能,支持事务处理、存储过程、触发器、视图、索引等,具有较好的安全性和稳定性。同时,MySQL也有很好的社区支持和文档资料,开发者可以方便地获取相关帮助和资源<sup id="al8">[[8]](#ref8)</sup>。
|
||||||
|
MySQL被广泛应用于Web应用程序、电子商务、社交网络、金融、游戏等领域,是许多知名网站和企业的首选数据库。
|
||||||
|
## 2.4 API技术
|
||||||
|
API(Application Programming Interface,应用程序编程接口)是一组定义了软件应用程序之间如何互相通信的规则和接口。API提供了一个标准的方式,使得应用程序之间可以相互调用,获取所需的数据和功能。它可以用于不同平台和编程语言之间的通信,如Web应用程序、移动应用程序、桌面应用程序等。API定义了一些公共的接口和参数,使得应用程序之间可以相互交换数据和信息,完成各种任务和功能。API可以分为不同的类型,如Web API、操作系统API、库API等。其中,Web API是最为常见和广泛应用的类型,它通过HTTP协议传输数据,通常采用RESTful架构风格或者SOAP协议<sup id="al9">[[9]](#ref9)</sup>。使用API可以极大地提高应用程序的开发效率和可重用性,促进应用程序之间的协作和集成。
|
||||||
|
# 2.5 本章小结
|
||||||
|
在本章中,我们对本论文开发过程中使用的开发语言、工具和数据库软件进行了介绍。此外,本章还介绍了系统开发项目在实现过程中使用到的主要开发技术。我们详细介绍了这些技术的原理和应用,以帮助读者更好地理解本项目的开发过程。
|
||||||
|
|
||||||
|
# 第3章 需求分析及设计
|
||||||
|
## 3.1 软件需求分析
|
||||||
|
基于ThinkPHP5.1的核酸检测登记系统是一个高负荷的系统,为了保障核酸检测登记系统的高可用和长期稳定使用,并满足业务流转的需求,我们将采用基于ThinkPHP5.1框架的PHP语言进行开发。同时,我们将通过前后端分离的方式<sup id="al10">[[10]](#ref10)</sup>,使用Vue框架编写后台前端,微信公众号作为面向普通用户的前端,并将数据存储在MySQL数据库中,以建立一套稳定高效的系统。
|
||||||
|
## 3.2 功能需求分析
|
||||||
|
核酸检测登记系统的设计与开发需要考虑到各方面的因素,包括系统的可用性、可扩展性、可维护性等。在设计之初,我们通过对以往核酸检测的经验和实际需求的分析,确定了该系统的主要功能和模块,以及各个模块之间的交互和流程。
|
||||||
|
为了实现高效的信息收集和处理,系统采用了基于微信端和后台管理系统的分层设计,将不同的功能模块划分到不同的层级中。微信端提供给用户和检测者使用的功能主要包括绑定、二维码展示、检测结果查询、扫码登记和公告查看等,这些功能通过微信公众号平台实现,可以方便地让用户和检测者进行操作,同时也保障了系统的安全性。后台管理系统则负责管理整个系统的数据和逻辑流程,包括公告管理、用户管理和管码管理等,这些功能可以通过Web界面进行操作,使得系统管理员可以方便地对整个系统进行管理和监控。
|
||||||
|
在核酸检测登记系统的实现过程中,也需要注重用户体验的设计。系统采用了人性化的交互方式和UI设计,以简洁、明了的方式呈现信息和功能,从而提高了用户的使用体验和操作效率。
|
||||||
|
## 3.3 非功能需求分析
|
||||||
|
非功能性需求分析包括易用性和可靠性等方面的分析。对于面向大众的系统来说,易用性要求系统容易被理解,使用学习成本低,操作简洁明了;而对于用户量庞大的系统,可靠性更加重要,需要保证系统在高负载下也不会出现严重问题,并且在出现问题后能够及时恢复。
|
||||||
|
除此之外,在非功能性需求分析中还需要考虑性能和安全性等方面的分析。性能分析需要考虑系统的响应速度、吞吐量等指标,以确保系统能够在合理时间内完成任务。安全性分析需要考虑系统的数据保密性、完整性和可用性,以避免系统受到恶意攻击或数据泄露等安全问题的影响。
|
||||||
|
同时,在非功能性需求分析中也需要考虑可维护性和可扩展性等方面。可维护性要求系统易于维护和修改,以保证系统的稳定性和可靠性。可扩展性要求系统能够根据需求增加新的功能或扩展规模,以适应未来的业务需求和用户数量增长<sup id="al11">[[11]](#ref11)</sup>。
|
||||||
|
## 3.4 功能设计
|
||||||
|
### 3.4.1 角色关系设计
|
||||||
|
核酸检测系统涉及到管理员、核酸检测机构、登记人员和市民四个至关重要的角色,各自担负着不同的职责和任务。下面将详细描述这四个角色在核酸检测系统中所需使用的功能和任务。
|
||||||
|
管理员是核酸检测系统中的管理者和决策者,拥有对系统的管理和监控职责。管理员需要使用该系统来收集和管理所有与核酸检测相关的信息,例如检测机构、登记人员和检测核酸的市民的基本信息、检测结果、样本的处理情况等等。他们需要定期更新系统中的信息,以确保信息准确完整。此外,管理员还需确保核酸检测系统的安全性,防止信息泄露等安全问题的发生。管理员需要监控整个核酸检测系统的运行,确保系统工作高效运作,以便政府决策人员及时掌握最新的疫情情况。
|
||||||
|
核酸检测机构在核酸检测系统中扮演着产出核酸检测结果的关键角色。他们需要使用该系统记录和管理所有检测样本相关的信息,例如每个样本的采集时间、状态、结果等等。同时,核酸检测机构需及时更新系统中的信息,以确保管理人员和市民能够及时获取最新的检测结果。在核酸检测工作中,核酸检测机构需要严格遵守操作规程,并保证检测结果的准确性。只有准确的检测结果才能帮助政府制定有效的疫情防控策略。
|
||||||
|
登记人员在核酸检测系统中扮演着关键执行者的角色。他们需要使用该系统进行前台扫码登记,提交并关联用户信息到系统中,方便用户和管理人员及时得到核酸检测结果通知。登记人员需要确保每个参与核酸检测的市民都完成了前台扫码登记,以便核酸检测机构可以顺利地获取相关的样本的关联信息。
|
||||||
|
市民是核酸检测系统中的使用者,需要通过该系统记录个人信息,并在核酸检测时通过展示二维码的方式绑定核酸关联关系。市民可通过该系统查询自己的核酸检测情况,并了解相关政策和指导意见。在使用核酸检测系统前,市民需要提供必要的身份验证信息,以确保信息安全和准确性。市民有义务按照规定参加核酸检测,并及时核实检测结果。
|
||||||
|
## 3.4.2 流程设计
|
||||||
|
根据上述设计,核酸检测系统将会按以下步骤执行:
|
||||||
|
试管登记:厂家需要对试管进行登记,包括试管编号等信息,以确保试管的准确性和追踪性。
|
||||||
|
用户注册和身份验证:用户需要在系统中进行注册并提供身份信息,以便核实身份。扫码人员会根据标准操作采集相应部位的样本,并将样品与试管编码和用户进行绑定,以避免混淆和错误。
|
||||||
|
样品运输:采样的样品会被运输到核酸检测机构,以进行后续检测步骤。
|
||||||
|
核酸检测过程:在检测机构内,样品经过复杂的生化反应和PCR扩增等过程,来检测是否存在新冠病毒。
|
||||||
|
结果上传和记录:检测结果信息会被上传至相关系统中,并记录下核酸检测时间、地点等信息,以便后续跟踪和分析。
|
||||||
|
结果查看和处理:用户和管理员可以通过系统查看结果信息。如果结果为阳性,则用户需要立即进行隔离治疗,并配合当地防控部门的要求进行后续措施。
|
||||||
|
整个核酸检测流程需要各方密切配合和精准管理,从而最大程度地提高检测的准确性和效率,进一步强化疫情防控的力量。
|
||||||
|
## 3.5 本章小结
|
||||||
|
本章主要针对核酸检测登记系统进行了详细的需求分析。首先明确了系统的总体目标和需求分析的前提条件,为后续的功能分析和需求分析奠定了基础。接着对系统进行了功能分析,明确了各个模块之间的业务逻辑关系,确保系统的各项功能能够相互协调和配合。针对系统的核心功能,进行了具体的需求分析,明确每个功能的详细需求,以确保系统的各项功能能够准确地满足用户的需求。
|
||||||
|
此外,本章还对系统进行了非功能性需求分析,主要考虑系统的易用性、可靠性、性能和安全性等方面,以确保系统不仅具有高效的功能,而且还具有良好的用户体验和安全保障。最后,本章还对系统中各个角色之间的关系和流程进行了详细的设计。
|
||||||
|
|
||||||
|
# 第4章 详细设计
|
||||||
|
作为系统的后端API,需要负责处理各种请求并返回相应的数据。为此,必须仔细设计数据库结构,以确保数据的高效存储和检索。此外,还需要定义各种接口,以便客户端应用程序可以方便地与后端API进行交互。因此,下面提供了关于该系统的详细设计,包括数据库结构、接口定义等方面的内容。
|
||||||
|
## 4.1 接口设计
|
||||||
|
该系统旨在为微信用户端和后台管理端提供服务,因此需要设计两个独立的模块以支持这两部分服务。这两个模块将包含不同的功能和接口定义,以满足微信用户和后台管理员的需求。因此,在整个系统的设计中,需要考虑这两个模块的交互和协同工作,以确保系统的可靠性和稳定性。
|
||||||
|
### 4.1.1 后台接口
|
||||||
|
作为后台管理,管理用户是必不可少的任务之一。因此,需要设计一套完整的用户管理接口,以便管理员可以方便地进行用户管理。这些接口将包括用户信息的创建、修改和删除等操作,同时还需要提供查询用户信息的接口,以便管理员能够快速查找和浏览用户信息。
|
||||||
|
作为核酸检测系统,管理核酸试剂是必不可少的任务之一。因此,需要设计一套完整的核酸试剂管理接口,以便管理员可以方便地进行试剂管理。这些接口将包括试剂的添加,删除、查询和更新等操作。
|
||||||
|
对于一个管理系统,公告也是必须的信息之一。管理员需要及时发布各种公告,以便向用户传达重要信息或者通知用户系统的更新和维护等情况。因此,需要设计一套完整的公告管理接口,以便管理员可以方便地发布、查询、修改和删除各种公告。这些接口应该具有良好的可扩展性和可维护性,以便随时满足不同的公告需求。
|
||||||
|
对于一个管理系统,了解系统运行的状态是必不可少的。管理员需要随时监控系统的各种指标,以便发现并解决可能出现的问题。因此,需要设计一套完整的系统状态查看接口,以便管理员可以方便地查看系统的注册量、试剂量等信息。这些接口应该具有良好的可扩展性和可定制性,以便满足不同的监控需求。此外,还需要考虑系统状态信息的安全性和保密性,以确保管理员的身份和权限得到充分验证和保护。
|
||||||
|
### 4.1.2 前台接口
|
||||||
|
在用户端,验证用户身份和获取用户信息是非常关键的操作。系统需要验证用户的身份,以确保用户的合法性和权限。因此,需要设计一套完整的用户验证和信息获取接口,以便用户可以方便地进行身份验证和信息查询。
|
||||||
|
在核酸检测的用户端,用户需要能够方便地查询自己的检测信息和相关结果,同时扫码人员也需要能够方便地进行核酸检测操作。因此,需要设计一套完整的核酸检测接口,以便用户和扫码人员可以方便地进行核酸检测相关操作。
|
||||||
|
由于微信的各种限制,例如在微信上调用扫码等操作,需要进行验证。为此,需要后端对微信端的页面进行验证。
|
||||||
|
为了确保用户端能够获取到管理员发布的与核酸检测相关的信息,需要提供公告的接口。这样,用户端就可以及时了解最新的政策和指南,并采取相应的措施。
|
||||||
|
## 4.2 数据库设计
|
||||||
|
在核酸检测登记系统中,准确地记录并存储每个人的检测数据至关重要。为了实现这一目标,必须精心设计数据库结构,并确保其可靠性和完整性。设计数据库的关键在于确定各种实体之间的关系以及它们之间的属性,以便能够准确地存储和检索数据。因此,为了满足这些要求,需要采用实体关系图(E-R图)来建立该系统的数据库结构。E-R图能够清晰地展示实体之间的关系,包括实体之间的联系和依赖关系,以及它们之间的属性<sup id="al12">[[12]](#ref12)</sup>。
|
||||||
|
此外,为了进一步确保核酸检测登记系统数据库的可靠性和完整性,我们还对其进行了详细设计。详细设计涵盖了数据库的各个方面,包括数据类型、数据表结构、索引等等。通过仔细考虑每一个细节,我们能够确保该数据库能够准确地存储、管理和检索所有的检测数据,并能够满足各种数据操作的要求。因此,在进行详细设计时,我们不仅仅关注数据库的功能和性能,还需要考虑到系统的可维护性和扩展性,以便在未来的运营过程中能够方便地进行系统的更新和维护。以下内容是该数据库的详细设计。
|
||||||
|
在进行核酸检测时,通常需要对试管的状态进行检测,因为试管的状态与被检测者的状态是对应的。因此,在设计检测流程时,我将重点记录试管的状态信息。在下表中,我们可以看到有关试管状态的信息,这些信息将有助于我们进行准确的核酸检测。
|
||||||
|
#### 表 核酸检测管信息表结构
|
||||||
|
|
||||||
|
| 字段名 | 类型 | 长度 | 索引及关系 | 注释 |
|
||||||
|
| - | - | - | - | - |
|
||||||
|
| id | int | 11 | 主键 | 主键ID |
|
||||||
|
| serial | varchar | 11 | 唯一键 | 管码 |
|
||||||
|
| fuid | int | 10 | 关联user表id | 所属用户ID |
|
||||||
|
| status | enum | 0,1 | | 状态(0=未检,1=阴性,2=阳性) |
|
||||||
|
| is_del | enum | 0,1 | | 软删除 |
|
||||||
|
| create_time | datetime | | | 添加时间 |
|
||||||
|
| update_time | datetime | | | 更新时间 |
|
||||||
|
|
||||||
|
在存储公告信息的过程中,为了方便管理和使用,我设计了一个包含标题、内容和图片信息的数据表。标题信息是公告的主题,通过标题可以快速地了解公告的内容和主要信息。内容信息则是公告的详细描述,可以包括公告的发布时间、地点、目的、重要性等内容。在某些情况下,公告可能需要配有图片信息,以便更直观地展示公告的内容和意义。因此,我在设计表格时特别留出了图片信息的存储空间。通过这些信息的存储和管理,我们可以更加高效地发布和管理公告,同时也可以使公告信息更加全面和直观。这样有助于提高公告的传播效果和实际效果,确保公告信息得到更好地传递和利用,具体表结构见下表。
|
||||||
|
#### 表 公告数据表结构
|
||||||
|
|
||||||
|
| 字段名 | 类型 | 长度 | 索引及关系 | 注释 |
|
||||||
|
| - | - | - | - | - |
|
||||||
|
| id | int | 11 | 主键 | 主键ID |
|
||||||
|
| title | varchar | 255 | | 标题 |
|
||||||
|
| content | text | | | 内容 |
|
||||||
|
| media_url | varchar | 255 | | 媒体URL |
|
||||||
|
| uid | int | 10 | 关联user表id | 添加者(仅超管) |
|
||||||
|
| is_del | enum | 0,1 | | 软删除 |
|
||||||
|
| create_time | datetime | | | 添加时间 |
|
||||||
|
| update_time | datetime | | | 更新时间 |
|
||||||
|
|
||||||
|
为了使后台管理人员和微信用户都能够方便地使用系统,我在设计用户信息表时特别考虑了用户权限的管理和用户身份的识别。为此,我同时设计了密码和微信OpenID字段。密码字段可以使后台管理人员设置用户密码,以便管理人员能够轻松地通过用户名和密码登录系统进行管理操作。微信OpenID字段则是为了便于微信用户在登录系统时进行身份识别和权限验证,从而能够更加便捷地使用系统的各种功能。通过这样的设计,系统不仅可以实现后台管理和微信用户端的统一管理,而且也使得系统更加简洁和易用,具体表结构见下表。
|
||||||
|
#### 表 用户信息表结构
|
||||||
|
|
||||||
|
| 字段名 | 类型 | 长度 | 索引及关系 | 注释 |
|
||||||
|
| - | - | - | - | - |
|
||||||
|
| id | int | 11 | 主键 | 主键ID |
|
||||||
|
| name | varchar | 11 | | 用户名 |
|
||||||
|
| password | char | 32 | | 密码(md5) |
|
||||||
|
| uniqid | char | 18 | 唯一键 | 身份证号码或员工号码(登录用) |
|
||||||
|
| gid | enum | 1,2,3,4 | | 组ID(1=普通用户,2=扫码员,3=检测员,4=超管) |
|
||||||
|
| wechat_openid | char | 29 | 唯一键 | 微信OpenID |
|
||||||
|
| is_del | enum | 0,1 | | 软删除 |
|
||||||
|
| create_time | datetime | | | 添加时间 |
|
||||||
|
| update_time | datetime | | | 更新时间 |
|
||||||
|
|
||||||
|
由于核酸检测中往往会存在混检的情况,即多个人的检测样本可能会被混在一起进行处理,因此在设计数据库表格时需要特别注意用户和检测管之间的关系。为了更好地处理这种情况,我将用户与检测管的关系设计为多对多的关系,即一个用户可能对应多个检测管,一个检测管也可能对应多个用户。这样,当出现混检情况时,我们可以通过用户与检测管之间的关联表来准确地确定每个检测管中所包含的样本属于哪些用户,从而可以快速地解决混检问题。下表是用户与检测管的关联表的表结构,包括用户ID、检测管ID等字段,这些字段将为用户和检测管之间的关系提供关键信息。
|
||||||
|
#### 表 用户-检测管关联表结构
|
||||||
|
|
||||||
|
| 字段名 | 类型 | 长度 | 索引及关系 | 注释 |
|
||||||
|
| - | - | - | - | - |
|
||||||
|
| id | int | 11 | 主键 | 主键ID |
|
||||||
|
| kid | int | 11 | 关联kit表id | 检测管ID |
|
||||||
|
| uid | int | 11 | 关联user表id | 用户ID |
|
||||||
|
| add_time | datetime | | | 添加时间 |
|
||||||
|
|
||||||
|
## 4.3 本章小结
|
||||||
|
本章详细介绍了核酸检测登记系统的系统设计。明确了系统设计的目标和预期的成果,为项目的顺利实施奠定了基础。设计实现了数据库的搭建,确保系统的数据存储和管理能够高效、稳定地运行。详细描述了系统的接口,以确保系统的各个模块之间能够良好地交互和通信。通过对系统接口的设计描述,为最后的相关系统的实现打下了坚实的基础。
|
||||||
|
|
||||||
|
# 第5章 系统实现
|
||||||
|
在本系统中,由于大多数接口都是常规的接口,所以我们在本章中主要着重介绍其中核心的功能以及技术。这些核心功能和技术对于系统的整体性能和可用性起着至关重要的作用。我们将详细介绍这些核心功能和技术的实现原理,包括其设计思路和代码实现等方面,以便读者可以更加深入地理解系统的工作原理和实现细节。
|
||||||
|
## 5.1 权限系统的实现
|
||||||
|
在一个系统中,确保每个用户只能访问其被授权的资源是至关重要的。为了实现这一目标,开发者需要采取措施来明确用户之间的权限区分。在我开发的系统中,我使用了ThinkPHP框架提供的Controller的$beforeActionList属性,这个属性可以在每个控制器方法执行之前调用指定的方法,从而使得系统可以对用户的权限进行预处理。通过在$beforeActionList中设置适当的权限验证方法,可以确保只有具备相应权限的用户才能够执行对应的操作。这种做法不仅可以提高系统的安全性,还可以保护系统中的敏感信息不受未授权用户的访问。
|
||||||
|
所以我在我的大多数接口前都写了一个auth()函数,内容如下:
|
||||||
|
```php
|
||||||
|
protected $beforeActionList = [
|
||||||
|
'auth'
|
||||||
|
];
|
||||||
|
protected function auth(){
|
||||||
|
if (!session('user')) {
|
||||||
|
die(json_encode(['code'=>400,'msg'=>'请先登录']));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
因为系统在登录时使用了Session存储用户信息,所以通过这种方式就可以判断用户是否登录,未登录用户将没有权限执行接下来的语句。
|
||||||
|
不过对于登录注册等功能不适用此方法,这时候将`$beforeActionList`中所调用的函数后面加一个值,例如:
|
||||||
|
```php
|
||||||
|
protected $beforeActionList = [
|
||||||
|
'auth' => ['except'=>'login,register']
|
||||||
|
];
|
||||||
|
```
|
||||||
|
就可以让这两个方法不调用`auth()`函数。
|
||||||
|
在此系统中,为了确保不同用户能够获得其对应的权限,我采用了gid进行区分。gid是指用户所属的组别,在我的设计中,不同的gid代表不同的权限级别。为了使系统更加安全,我设置了一个权限门槛,只有具备特定gid的用户才能够访问系统中的特定资源。例如以下代码:
|
||||||
|
```php
|
||||||
|
if (session('user')['gid'] < 3) {
|
||||||
|
die(json_encode(['code'=>400,'msg'=>'权限不足']));
|
||||||
|
}
|
||||||
|
```
|
||||||
|
如果用户的gid值小于3,即比检测员的权限小,则表示其权限不足,无法执行相应的操作,我会通过在程序中判断用户的gid值,如果用户权限不足,则会返回一个错误提示,并终止程序的执行。这种做法可以保护系统中的敏感资源不被未授权用户访问,同时还可以防止潜在的恶意行为对系统造成损害。此外,我还允许高权限的用户执行低权限用户的所有接口,从而能够更加灵活地控制系统中的访问权限。这种做法可以为系统的使用者提供更加便利的操作体验,同时还能够保护系统的安全性和稳定性。
|
||||||
|
## 5.2 数据增删改查的实现
|
||||||
|
在ThinkPHP5.1框架中,我们可以使用think\Db类来访问数据库。考虑到系统需要具备高性能的特点,我在使用数据库时,使用了Db::execute和Db::query方法,而不是使用构造器或者模型来实现数据操作。这是因为使用构造器或者模型会增加系统的复杂度和开销,而Db::execute和Db::query方法能够更加高效地实现数据操作,从而提升系统的性能。同时,为了保证系统的安全性,我在使用Db::execute和Db::query方法时,采用了参数化的方式来进行数据查询和更新操作,避免了SQL注入等安全问题。参数化查询能够通过将参数传递到查询语句中,从而防止恶意用户通过在查询参数中插入恶意代码,对系统造成安全威胁。
|
||||||
|
在设计查询接口时,我为了进一步提高系统的运行效率,使用了SQL_CALC_FOUND_ROWS关键字来统计查询结果的总条数。相比于使用COUNT()函数,使用SQL_CALC_FOUND_ROWS可以减少不必要的查询次数,从而更加高效地实现数据的查询和处理<sup id="al13">[[13]](#ref13)</sup>。这是因为在使用COUNT()函数时,需要进行两次查询:第一次查询结果记录数,第二次查询结果数据,而使用SQL_CALC_FOUND_ROWS则只需要进行一次查询,同时还能够获得查询结果的总条数,这种做法能够节省系统的运行时间和资源开销,从而提升系统的性能和用户体验。例如获取公告列表方法:
|
||||||
|
```php
|
||||||
|
public function read($offset = 0, $limit = 10){
|
||||||
|
return json(['code'=>200,'msg'=>'获取成功','data'=>Db::query("select SQL_CALC_FOUND_ROWS id, title, content, media_url, create_time, update_time from notice where is_del='0' limit ?,?",[$offset,$limit]),'count'=>Db::query("select FOUND_ROWS() as count")[0]['count']]);
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
## 5.3 核酸检测的实现
|
||||||
|
在微信网页开发中,为了保证安全性,微信官方要求从后端调用微信公众号接口获取凭据<sup id="al14">[[14]](#ref14)</sup>,然后在前端注入后才可以使用诸如扫码等功能。在使用扫码功能时,对于管码只处理条形码,添加用户时只处理二维码。
|
||||||
|
另外,用户的二维码除了用户本身的信息以外,还有红黄绿三种颜色。这三种颜色是根据最近的核酸结果得出,如果七天未检查为黄色,七天内最后一次检查为阴性为绿色,阳性为红色。
|
||||||
|
在实现扫码功能时,为了保证系统的高效性,我们会将需要提交至后端的数据在一个变量中进行处理,最终收集齐所有信息再一次性提交。这种做法能够降低整个服务器的压力,提高系统的性能表现。
|
||||||
|
在此之后,检测员将会使用后台界面去修改核酸状态。修改后,用户就能及时收到检测结果。并显示在用户检测的历史记录中。
|
||||||
|
## 5.4 微信公众号异步发送通知的实现
|
||||||
|
在本系统中,用户需要通过微信公众号接收核酸检测的结果。当检测员得出结论并修改核酸结果后,用户就能收到核酸检测的结果。
|
||||||
|
收到通知后可以在近7次核酸检测中看到结果,这个结果是使用一条联表查询得出:
|
||||||
|
```php
|
||||||
|
Db::query("SELECT user.`name`, kit.`status`, user_kit.add_time FROM user_kit INNER JOIN kit ON user_kit.kid = kit.id INNER JOIN `user` ON kit.fuid = user.id WHERE user_kit.uid = ? ORDER BY user_kit.add_time DESC LIMIT 7", [session('user')['id']])
|
||||||
|
```
|
||||||
|
然而,调用微信公众号接口通知用户的速度较慢,可能会导致用户体验不佳。为了避免这种情况的发生,我使用了php-fpm专有的函数fastcgi_finish_request()来实现此功能。
|
||||||
|
fastcgi_finish_request()函数可以将响应发送到客户端,然后继续处理其他任务,从而提高系统的响应速度和性能。在我的设计中,当检测员修改核酸检测结果后,我在调用微信公众号接口通知用户之前,先使用fastcgi_finish_request()函数将响应发送给客户端。这样一来,系统就可以在发送响应的同时,继续执行其他任务,从而避免了用户等待时间过长的问题,提高了系统的响应速度和用户体验。
|
||||||
|
## 5.5 公众号界面的菜单实现
|
||||||
|
为了更方便地设计菜单,我选择使用回复信息来承载菜单。具体实现方法如下:首先,在定义微信内置的菜单时,我设定了一个带有click事件的按钮。然后,在我的回调地址中监听这个事件,一旦收到了点击事件,就会触发回复菜单的操作。这样,就可以很轻松地获取用户信息,并根据用户的权限来判断可以使用哪些选项,从而实现更加个性化的菜单设计。
|
||||||
|
为了保证系统的高效运行,我在这里的实现中使用了cache去缓存用户信息。这种做法的好处在于,它可以避免因为数据库过慢而导致的性能问题,同时还可以让菜单更快速地返回。具体来说,当用户进行菜单操作时,系统会首先检查cache中是否存在该用户的信息。如果存在,则可以直接从cache中获取用户信息,而无需再次访问数据库,从而大大提高了系统的响应速度。而如果cache中不存在该用户的信息,则会去数据库中获取,并将获取到的信息缓存到cache中,以供下一次使用。
|
||||||
|
## 5.6 本章小结
|
||||||
|
在前几章的内容基础上,本章详细阐述了系统的具体实现过程。考虑到篇幅限制,我们选择了一些关键技术作为示范进行说明。包括了系统的一些重要功能和实现。
|
||||||
|
|
||||||
|
# 第6章 系统测试
|
||||||
|
## 6.1 测试概述
|
||||||
|
核酸检测登记系统是一种用于信息收集的软件,其研发和使用对于疫情的防控具有十分重要的意义。本章旨在对核酸检测系统进行测试,并对测试过程和结果进行概述。
|
||||||
|
测试的目的是为了验证核酸检测系统在生产环境下的性能、可靠性、安全性以及交互性等方面是否符合需求和用户期望,同时确保系统的完整性和稳定性。测试的对象包括系统的功能、性能、接口、兼容性、安全等各个方面。在测试过程中,我们还将发现问题和瑕疵,并提出改进建议,以确保系统能够更好地满足用户需求。
|
||||||
|
在功能性测试阶段,我们将测试每个功能的正确性、完整性和易用性,以确保系统能够按照用户需求稳定运行,并关注客户需求,提高用户满意度。在兼容性测试中,我们将测试核酸检测系统的兼容性。在性能测试中,我们将测试系统的响应时间、资源使用率和负载能力等,以确保系统具备高效、快速和高性能的特点。
|
||||||
|
此外,测试活动还关注了其他方面的问题,如数据安全、网络安全和用户体验等。我们测试了数据的保密性和完整性,网络通信的防伪保密等方面,并检查软件是否易于使用,是否具有直观性、一致性和可信度等特点。
|
||||||
|
## 6.2 关键环境测试
|
||||||
|
在开发过程中,环境测试的重要性不言而喻。在测试过程中,尽可能多地考虑不同软硬件条件下的情况可以最大化地发现问题。因此,建议在不同的操作系统环境和不同的计算机硬件环境下进行测试<sup id="al15">[[15]](#ref15)</sup>。
|
||||||
|
对于关键测试的软件环境,我们的程序主要是在微信客户端上运行,因此测试主要针对微信上的运行环境进行。其次,我们也在Android系统、iOS系统以及Android模拟器上进行了测试,除此之外,还有后端API接口是在服务器上运行,也会对其进行测试,具体测试内容如下表所示:
|
||||||
|
#### 表 关键环境测试列表
|
||||||
|
|
||||||
|
| 软件环境 | 硬件环境 | 软件 | 测评对象 | 能否使用 |
|
||||||
|
| - | - | - | - | - |
|
||||||
|
| Android 12 | Redmi K20 Pro | 微信 | 公众号页面 | 能 |
|
||||||
|
| iOS 13 | iPhone 12 | 微信 | 公众号页面 | 能 |
|
||||||
|
| Android 12 | Xiaomi 12 | 微信 | 公众号页面 | 能 |
|
||||||
|
| Android 13 | WSA模拟器 | 微信 | 公众号页面 | 能 |
|
||||||
|
| MacOS 13 | Macbook Pro | PHP | 后端API | 能 |
|
||||||
|
| Ubuntu 22 | 阿里云服务器 | PHP | 后端API | 能 |
|
||||||
|
| Windows Server 2022 | 阿里云服务器 | PHP | 后端API | 能 |
|
||||||
|
|
||||||
|
## 6.3 软件性能测试
|
||||||
|
性能测试是一种测试方法,用于测量软件系统在不同的工作负载下的性能、稳定性和可靠性,以确定系统性能瓶颈和性能瓶颈的原因。在设计性能测试时,需要考虑系统的关键性能指标,并设计测试用例以验证这些指标。对于本系统来说,响应时间和并发数是比较重要的性能指标,因此,在设计性能测试时主要针对这两点进行测试<sup id="al16">[[16]](#ref16)</sup>。
|
||||||
|
为了测试系统的性能,我们以后台登录为示例,设计了一个性能测试用例表,结果如下表所示。
|
||||||
|
#### 表 性能测试用例表
|
||||||
|
|
||||||
|
| 用例名称 | 描述 | 预期结果 |
|
||||||
|
| - | - | - |
|
||||||
|
| 正常登录测试 | 输入正确的用户名和密码,登录系统 | 登录响应时间在3秒以内,用户能够成功登录系统 |
|
||||||
|
| 错误用户名测试 | 输入错误的用户名和正确的密码,尝试登录系统 | 登录响应时间在3秒以内,系统提示用户名或密码错误 |
|
||||||
|
| 错误密码测试 | 输入正确的用户名和错误的密码,尝试登录系统 | 登录响应时间在3秒以内,系统提示用户名或密码错误 |
|
||||||
|
| 多用户并发测试 | 多个用户同时登录系统 | 系统能够处理多个用户的请求,并保持响应时间在3秒以内 |
|
||||||
|
| 长时间登录测试 | 单个用户长时间登录系统 | 系统能够保持响应时间稳定,并不会出现登录超时或登录失败的情况 |
|
||||||
|
|
||||||
|
## 6.4 测试功能及测试用例设计
|
||||||
|
设计测试用例是为了检查程序路径是否满足某些特定要求,测试用例包含实际测试输入、执行条件和预期结果。整个测试任务的核心工作在于测试用例的设计,因为好的测试用例可以直接揭示系统中的潜在问题。通过解决这些潜在问题,可以大幅提升系统的性能和用户体验。在功能测试过程中,测试用例的设计一般包括四个部分:主题、前提条件、执行步骤和期望输出结果。以下以进行核酸检测接口为例设计测试用例,并总结测试结果<sup id="al17">[[17]](#ref17)</sup>。
|
||||||
|
针对核酸检测接口进行测试后,对测试结果进行了分析:所有测试结果都与预期输出结果一致,表明该用例的功能测试已经完成。测试表明,本系统能够达到与测试性能相应的要求,并且成功地完成了相应的功能。
|
||||||
|
## 6.5 本章小结
|
||||||
|
在本章中,首先简要介绍了软件测试的必要性和常见的测试方法。接着,我们详细讲解了如何进行软件环境和软件性能测试,包括性能测试中的负载测试、压力测试等。最后,我们以核酸检测功能为例,设计了测试用例并进行了用例测试,得到了丰富的测试结果和数据,帮助我们评估软件的稳定性和可靠性,以及发现和修复潜在的问题和漏洞。
|
||||||
|
|
||||||
|
# 第7章 结论
|
||||||
|
## 7.1 总结
|
||||||
|
在这次的软件设计过程中,我采用了系统化的方法来确保最终的系统能够满足用户的需求和期望。首先,我进行了详细的需求分析,明确了系统的核心功能和特点。在这个过程中,我深入研究了中外核酸管理系统,学习借鉴了其中的经验和教训,从而能够更好地理解核酸数据的隐私和安全问题。因此,在系统设计中,我注重了权限验证和安全措施,以确保用户的数据不会被恶意使用或泄露。同时,我也考虑到用户的使用体验,优化了交互方式,让系统更加易于使用和友好。
|
||||||
|
在流程梳理过程中,我将整个系统的业务流程进行了详细的拆分和设计,通过建立流程图来清晰地表达系统的运作方式。我采用了敏捷开发的方法,将整个开发过程划分为多个迭代,每个迭代都可以快速交付可用的功能模块,以确保系统可以逐步完善。在这个过程中,我进行了前后端的沟通和协作,以及技术的不断学习和探索,以便更好地解决遇到的挑战和问题。
|
||||||
|
在开发过程中,我遵循了代码规范和工程管理标准,采用了Git等工具进行版本控制和团队协作。我使用了ThinkPHP框架和MySQL数据库进行开发,并对系统进行性能和安全方面的优化,以确保系统的可靠性和稳定性。我深入研究了框架和数据库的细节,并对它们进行了合理的调优,从而提高了系统的运行效率和安全性。
|
||||||
|
同时,我们还进行了系统的测试和优化。在测试过程中,我们对系统进行了功能测试、性能测试、安全测试等多个方面的测试,以确保系统的功能符合要求、性能稳定高效、安全性强。在测试中发现的问题,我们及时进行了优化和修复,确保了系统的稳定性和可靠性。
|
||||||
|
在整个开发过程中,我们遇到了很多挑战和问题。例如,开发周期紧张、需求变化频繁、技术不熟悉等。但是,通过加强前后端的沟通和协作,以及技术团队的不断学习和探索,我们逐步解决了这些问题,并最终实现了一个高效、稳定、安全的系统。
|
||||||
|
综上所述,基于ThinkPHP的核酸检测登记系统的设计与开发是一项非常具有挑战性的工作。通过对需求分析、流程梳理、开发过程等的认真规划和实践,最终,我们成功地实现了一个高效、稳定、安全的系统,能够为疫情防控工作做出贡献。
|
||||||
|
## 7.2 展望
|
||||||
|
虽然疫情已经结束,但是可以将登记系统进一步完善,以适应未来的发展需求。以下是三个可以实施的改进方案:
|
||||||
|
首先,可以增强数据分析功能。通过积累更多用户数据,我们可以进行更全面的数据分析和处理,从而提供更准确、有用的信息和分析结果。例如,我们可以分析疫情传播趋势、用户行为模式等,为政府和医疗机构提供更有效的决策支持。
|
||||||
|
其次,可以增加预约功能。现有系统只能登记用户信息和检测结果,但未来我们可以考虑增加预约功能,让用户能够在线上进行检测预约。这样用户就可以更方便地安排行程,同时也可以减少排队等待时间。
|
||||||
|
第三,可以引入自动化处理技术,如人脸识别技术等,以实现自动识别用户信息和检测结果。这样就可以减少人工处理的时间和工作量,提高工作效率。
|
||||||
|
未来,如果有机会,我们可以让这个系统发挥更多的作用,比如在未来的其他疫情中起到重要的作用。我们可以引入更多的功能和技术,以满足未来需求的变化,从而更好地保障公共卫生和社会安全。
|
||||||
|
|
||||||
|
# 参考文献
|
||||||
|
1. <span id="ref1"><a href="#al1">^</a></span> 靳英辉,蔡林,程真顺,等. 新型冠状病毒(2019-nCoV)感染的肺炎诊疗快速建议指南(标准版)[J]. 解放军医学杂志,2020,45(01):1-20.
|
||||||
|
2. <span id="ref2"><a href="#al2">^</a></span> 宗晓祥,胡云,马利亚.核酸检测云平台的设计与实现[J].集成电路应用, 2022, 39(10): 47-49.
|
||||||
|
3. <span id="ref3"><a href="#al3">^</a></span> Shaun Griffin. Covid-19: NHS England should manage test and trace system, says Independent SAGE[N]. BMJ,2020,371:m4330
|
||||||
|
4. <span id="ref4"><a href="#al4">^</a></span> Simon Judith,Rieder Gernot. Trusting the Corona-Warn-App? Contemplations on trust and trustworthiness at the intersection of technology, politics and public debate[J]. European Journal of Communication,2021,36(4).
|
||||||
|
5. <span id="ref5"><a href="#al5">^</a></span> 喻健,鲍琪. 基于ThinkPHP的人口信息系统设计[J]. 信息技术与信息化,2022,(02):9-12.
|
||||||
|
6. <span id="ref6"><a href="#al6">^</a></span> 蒋先梅. 基于PHP的学生信息管理系统的设计与实现[J]. 无线互联科技,2023,20(01):45-47.
|
||||||
|
7. <span id="ref7"><a href="#al7">^</a></span> 谷恪忱. 基于ThinkPHP框架的工控品采购平台设计与实现[J]. 软件工程,2020,23(03):53-59.
|
||||||
|
8. <span id="ref8"><a href="#al8">^</a></span> 赵莹,胡畅达,王国宇. 三种关系型空间数据库比较[J]. 科技创新与应用,2021,11(19):62-64.
|
||||||
|
9. <span id="ref9"><a href="#al9">^</a></span> 李琦,姚龙. 基于REST架构的湖泊环境监测物联网平台[J]. 计算机工程,2016,42(11):27-31+37.
|
||||||
|
10. <span id="ref10"><a href="#al10">^</a></span> 卢彦晓. 浅谈前后端分离技术在权限管理系统中的应用[J]. 电脑知识与技术,2021,17(34):68-69.
|
||||||
|
11. <span id="ref11"><a href="#al11">^</a></span> 张然,孙浩,张鑫. 基于JavaWeb的阿尔茨海默症早期康复系统设计[J]. 电子技术与软件工程,2022,(23):259-262.
|
||||||
|
12. <span id="ref12"><a href="#al12">^</a></span> 杨中书,刘臣宇. 基于E-R模型的关系数据库设计方法[J]. 价值工程,2014,33(30):242-243.
|
||||||
|
13. <span id="ref13"><a href="#al13">^</a></span> 黄金春,杜娟娇. 编写web服务器远程查看mysql数据[J]. 信息系统工程,2009,(07):26-29.
|
||||||
|
14. <span id="ref14"><a href="#al14">^</a></span> 陶亮亮. 基于微信公众号的掌上医院的设计与实现[J]. 电脑知识与技术,2022,18(09):46-48.
|
||||||
|
15. <span id="ref15"><a href="#al15">^</a></span> 陈莎莎. 基于JSP网页技术的高校PU系统功能可视化界面设计[J]. 自动化与仪器仪表,2023,(02):146-151.
|
||||||
|
16. <span id="ref16"><a href="#al16">^</a></span> 纪芩. 基于云平台的软件性能测试技术分析[J]. 电子技术与软件工程,2022,(23):74-77.
|
||||||
|
17. <span id="ref17"><a href="#al17">^</a></span> 刘肖. 基于JSP+MySQL的供电管理系统的设计与实现[D].电子科技大学,2021.
|
33
_posts/2023-07-09-bitmo.md
Normal file
33
_posts/2023-07-09-bitmo.md
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
---
|
||||||
|
layout: post
|
||||||
|
title: 分享一种无人值守的新型诈骗手段
|
||||||
|
tags: [骗子, 诈骗]
|
||||||
|
---
|
||||||
|
|
||||||
|
差点就被骗子骗了🤣,还是主动上钩的……<!--more-->
|
||||||
|
|
||||||
|
# 起因
|
||||||
|
今天因为某些原因从网上随便搜了一个公共的接码平台用,接完自己要用的短信之后突然瞥到这么一条信息:
|
||||||
|
|
||||||
|
> NEW BlTMØ L0GlN \|\| www.Bitmo.vip \|\| Username:Huzhou Pa**word:4894688 BaIance:65.77BTC.........
|
||||||
|
|
||||||
|
我没怎么注意这条信息的意思,但是既然有网站名,用户名和密码,自然会不由自主的想去登录一下啦,然后就会看到账户里有巨额的财产。我登录的时候账户里面还有67BTC,换算下来大概有**1400wCNY**的样子。
|
||||||
|
|
||||||
|
# 落入圈套
|
||||||
|
刚开始我打开这个网站的时候还没意识到这是个诈骗网站,还以为是哪个交易所,不过既然登录上来了自然想看看登录账号后的网站都有些啥功能,首先看到的就是些充值、提现、转账和开票之类的功能,看上去好像还挺像回事的,不过试了几下除了转账之外的其他功能其实是没法用的,充值和开票需要用到安全密钥,而提现除了需要用到安全密钥外,系统说账户因为1年没提现了,所以提现功能被禁用了,但是仍然可以转账:
|
||||||
|
|
||||||
|
> Withdrawal to your registered ฿itcoin wallet address has been disabled because you haven't withdrawn for more than 365 days. To reactivate withdrawal you need to contact customer care and provide your secure key you created during account registration.
|
||||||
|
> You will still be able to carry out transfers and transactions from your account balance to other BITMO VIP members without your secure key for the next 6 months.
|
||||||
|
|
||||||
|
于是我想都没想就注册了一个账户,想着既然有这个功能就给自己转点钱呗。注册好账户以后发现我是免费账户,除了开通VIP外什么功能都用不了,而开通VIP至少要充0.004BTC进去,大约相当于800多CNY。当然VIP我是不可能开的,我打算先试试转钱到我的账户中。
|
||||||
|
在转账的过程中,一次最多只能转出0.2BTC,而且同一个IP似乎只能转一次。我试着转了0.2BTC到我的账户中,想不到还成功了😨,毕竟0.2BTC也相当于4w多CNY呢,于是我换了一个IP又转了一次,也成功了,不过第三次会失败,貌似免费账户最多只能接受0.4BTC。随后我登录到我的账户上看了一眼,我以为转完之后我会直升VIP6,结果系统显示免费账户不能接受转账,必须开通VIP才可以:
|
||||||
|
|
||||||
|
> Hello MAYX, the user HUZHOU has recently tried to transfer 0.40000 ฿TC ($ 12088.33) to your account. Our system witheld the transfer because free-trial accounts cannot send or receive Bitcoin through our service. Once you make an investment in any of our VIP plans, our system will automatically add the 0.40000 ฿TC ($ 12088.33) to your VIP account balance.
|
||||||
|
|
||||||
|
# 产生怀疑
|
||||||
|
这时候我开始怀疑这个网站的身份了,我看了一眼帮助,显示这个平台是一个2014年创立的平台,可是我搜了一下域名的WHOIS发现它是2023-05-28创建的……也就不可能存在有大佬在一年或者更早存这么多钱进去了。Google搜索了一下这个平台也没有相关的结果,看来是诈骗网站没错了。毕竟就算是最低的VIP也要不少钱,充进去能把那0.4BTC拿到的概率只能说是0%……可惜错失了一次发财的机会啊🤣。
|
||||||
|
之后看了看它的源代码,里面怎么还有中文🤣,原来是国人开发的诈骗网站。仔细看了看结果发现其他功能的报错都是硬编码的,根本就没有请求服务器😅。
|
||||||
|
|
||||||
|
# 感想
|
||||||
|
前两次收到的诈骗邮件[富婆找对象](/2019/06/10/cheat.html)和[被拍糟糕视频](/2021/11/28/spam.html)两个可以说是真的傻子才会相信,因为内容太离谱了,能上当的人太少了,而且我发完邮件他们还得回复,效率也很低下。这次遇到的这个诈骗就好多了,让被骗的人很有参与感,而且建好网站之后什么都不用做,只要等着有人打钱就好,效率非常高,而且做的还挺像回事,估计被骗的人不会少。
|
||||||
|
不过之后想想也是,这种短信大概率就是那种群发的垃圾短信,实际上主动登录的人应该也不多吧😂。
|
129
_posts/2023-08-01-auth.md
Normal file
129
_posts/2023-08-01-auth.md
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
---
|
||||||
|
layout: post
|
||||||
|
title: 如何让Python脚本接收OAuth2.0的Code?
|
||||||
|
tags: [Python, 服务器, OAuth]
|
||||||
|
---
|
||||||
|
|
||||||
|
越简单,就越复杂。<!--more-->
|
||||||
|
|
||||||
|
# 起因
|
||||||
|
最近我在写一个在Windows上运行的Python脚本,需要做一个类似于第三方登录的功能。一般来说像这种东西都是使用的OAuth2.0来做认证,我接入的平台没有悬念的也是使用的这个东西,其中的重点就是获取到第三方网站的授权码Code,然后用它换取用户信息。于是我就在想怎么做比较好呢?
|
||||||
|
|
||||||
|
# 解决方法
|
||||||
|
## 1. 使用URI Scheme
|
||||||
|
我看VSCode在实现类似功能的时候似乎用到了URI Scheme,就是在系统中注册一个伪协议,然后通过这个伪协议来调用程序实现获取Code,方法很简单,首先先在注册表里导入:
|
||||||
|
```ini
|
||||||
|
Windows Registry Editor Version 5.00
|
||||||
|
|
||||||
|
[HKEY_CLASSES_ROOT\mayx]
|
||||||
|
"URL Protocol"="D:\\mayx.exe"
|
||||||
|
@="MayxProtocol"
|
||||||
|
|
||||||
|
[HKEY_CLASSES_ROOT\mayx\DefaultIcon]
|
||||||
|
@="D:\\mayx.exe,1"
|
||||||
|
|
||||||
|
[HKEY_CLASSES_ROOT\mayx\shell]
|
||||||
|
|
||||||
|
[HKEY_CLASSES_ROOT\mayx\shell\open]
|
||||||
|
|
||||||
|
[HKEY_CLASSES_ROOT\mayx\shell\open\command]
|
||||||
|
@="\"D:\\mayx.exe\" \"%1\""
|
||||||
|
```
|
||||||
|
然后编写一个Python脚本并用Pyinstaller打包:
|
||||||
|
```python
|
||||||
|
import sys
|
||||||
|
print(sys.argv[1])
|
||||||
|
```
|
||||||
|
最后将回调地址填为“mayx://get”,这样认证完成之后就会像这样调用程序:“D:\mayx.exe mayx://get?code=something”,再用urllib简单做个解析就完成了。
|
||||||
|
这样看起来是不是非常的简单?看起来确实是挺简单的,可惜坑比较大,第一个是像上述这样的注册表有些杀毒软件会拒绝导入,因为像“shell\open\command”这种东西被病毒啥的滥用的地方太多了,除非软件通过了数字签名或者某些认证,否则正常情况下根本没法导入。二是不是所有的第三方平台都支持伪协议的方式调用,不过我试了一下我用的那个平台倒是支持😂,除了杀毒软件比较讨厌之外其他的倒还好。
|
||||||
|
## 2. 使用http服务监听
|
||||||
|
很多跨平台的程序,像有些主要在Linux上运行的某些程序就喜欢在获取Code的时候启动一个简单的web服务。其实用这个方法的话可能还更方便一点,不容易出问题。
|
||||||
|
### 使用Flask实现
|
||||||
|
最开始,我想着要不然就用Flask来实现这个功能吧,实现起来也简单,写起来就几行:
|
||||||
|
```python
|
||||||
|
from flask import Flask, request
|
||||||
|
code = ""
|
||||||
|
app = Flask(__name__)
|
||||||
|
@app.route('/getcode')
|
||||||
|
def get():
|
||||||
|
global code
|
||||||
|
code = request.args.get("code")
|
||||||
|
shutdown = request.environ["werkzeug.server.shutdown"]
|
||||||
|
shutdown()
|
||||||
|
return "OK"
|
||||||
|
|
||||||
|
app.run(host="127.0.0.1",port=8000)
|
||||||
|
print(code)
|
||||||
|
```
|
||||||
|
看起来也确实很简单,功能实现的也很完美,但是有个问题是总感觉用Flask做这么简单的事情实在是大材小用,打包成程序也要占不少空间,另外就是这个方法已经被弃用了,感觉就是很不爽。那要说不爽的话怎么才爽呢?
|
||||||
|
### 使用socket实现
|
||||||
|
我想起来之前期末时写的期末作业[socket-bbs](https://github.com/Mabbs/socket-bbs),这就是用socket实现的一个简单的论坛,那我这么简单的功能想来用socket实现不是很好吗?于是就写了一个:(这段代码没有测试,因为这个方法不能用所以把代码删了,这是重新做的)
|
||||||
|
```python
|
||||||
|
import socket
|
||||||
|
import urllib.parse
|
||||||
|
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #打开一个网络连接
|
||||||
|
server.bind(('127.0.0.1',8000)) #绑定要监听的端口
|
||||||
|
server.listen(5) # 设置最大的连接数量为5
|
||||||
|
code = ""
|
||||||
|
while True:
|
||||||
|
sock, addr = server.accept() # 建立客户端连接
|
||||||
|
data = sock.recv(8192).decode('utf-8').split('\r\n')#接收TCP数据,数据以字符串的形式返还
|
||||||
|
if not data[0]:
|
||||||
|
sock.close() # 关闭连接
|
||||||
|
continue
|
||||||
|
url = urllib.parse.urlparse(data[0].split()[1])
|
||||||
|
if url.path == '/getcode':
|
||||||
|
query = urllib.parse.parse_qs(self.data)
|
||||||
|
code = query["code"][0]
|
||||||
|
sock.send(("HTTP/1.0 200 OK" + '\r\n').encode('utf-8'))
|
||||||
|
sock.send(("Content-Type: text/html; charset=utf-8" + '\r\n').encode('utf-8'))
|
||||||
|
sock.send('\r\n'.encode('utf-8'))
|
||||||
|
sock.send("OK".encode('utf-8')) #发送TCP数据
|
||||||
|
sock.close() # 关闭连接
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
sock.send(("HTTP/1.0 404 Not Found" + '\r\n').encode('utf-8'))
|
||||||
|
sock.send(("Content-Type: text/html; charset=utf-8" + '\r\n').encode('utf-8'))
|
||||||
|
sock.send('\r\n'.encode('utf-8'))
|
||||||
|
sock.send("Not Found".encode('utf-8')) #发送TCP数据
|
||||||
|
sock.close() # 关闭连接
|
||||||
|
print(code)
|
||||||
|
```
|
||||||
|
看起来是不是复杂多了?其实大多数时候工作的好像挺正常的,但是不知道为什么莫名其妙第一次访问的时候会卡住,改了半天头都大了,于是就只好放弃这种方法了……
|
||||||
|
### 使用http.server实现
|
||||||
|
这时候我突然想到我平时用来传文件用的python自带的模块http.server,既然这个模块是自带的,大小应该大不到哪去吧?随后我就写了一个:
|
||||||
|
```python
|
||||||
|
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
||||||
|
import urllib.parse
|
||||||
|
code = ""
|
||||||
|
class Resquest(BaseHTTPRequestHandler):
|
||||||
|
timeout = 5
|
||||||
|
def do_GET(self):
|
||||||
|
url = urllib.parse.urlparse(self.path)
|
||||||
|
if url.path == "/getuser":
|
||||||
|
self.send_response(200)
|
||||||
|
self.send_header("Content-type", "text/html") # 设置服务器响应头
|
||||||
|
code = urllib.parse.parse_qs(url.query)["code"][0]
|
||||||
|
buf = '''OK'''
|
||||||
|
self.wfile.write(buf.encode())
|
||||||
|
self.server.shutdown()
|
||||||
|
else:
|
||||||
|
self.send_response(404)
|
||||||
|
self.send_header("Content-type", "text/html") # 设置服务器响应头
|
||||||
|
self.end_headers()
|
||||||
|
buf = '''Not Found'''
|
||||||
|
self.wfile.write(buf.encode())
|
||||||
|
host = ("127.0.0.1", 8000)
|
||||||
|
server = ThreadingHTTPServer(host, Resquest)
|
||||||
|
print("Starting server, listen at: %s:%s" % host)
|
||||||
|
server.serve_forever()
|
||||||
|
server.socket.close()
|
||||||
|
print(code)
|
||||||
|
```
|
||||||
|
最后打包试了一下,功能正常,虽然还是大了点,不过比Flask小😁。其实我在写这个代码的时候,最开始不知道要在最后加上`server.socket.close()`,一开始写的时候总是遇到程序执行完之前端口必定不会释放,令人很烦,直接搜也没什么好的结果,不过问了下ChatGPT立马就解决了🤣,它说:
|
||||||
|
> 当你调用`server.shutdown()`来停止服务器时,它会停止接收新的连接,并关闭已有的连接。但是,由于Python的socket库的设计,socket对象并不会立即释放端口。相反,它会在一段时间内处于TIME_WAIT状态,以确保在网络中所有挂起的数据都被正确传递或丢弃。这是一种网络协议的要求,称为"TCP TIME_WAIT"状态。
|
||||||
|
|
||||||
|
AI还真是方便啊……
|
||||||
|
|
||||||
|
# 感想
|
||||||
|
解决这么一个小问题却一时半会拿不下最合适的方案,这难道就是了解太多的副作用吗😝,不过最终来看还是AI厉害,一下子就解决了我的问题。
|
27
_posts/2023-09-06-satellite.md
Normal file
27
_posts/2023-09-06-satellite.md
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
---
|
||||||
|
layout: post
|
||||||
|
title: 关于卫星通信的一些看法
|
||||||
|
tags: [卫星, 通信]
|
||||||
|
---
|
||||||
|
|
||||||
|
卫星通信也许并不困难😁<!--more-->
|
||||||
|
|
||||||
|
# 起因
|
||||||
|
前段时间,华为出了一款可以打卫星电话的手机——Mate 60 Pro。我虽然对华为不怎么感兴趣,对于它能把3年前的芯片卖到7K+CNY的营销水平也不感兴趣,但是对于卫星通信我还是挺感兴趣的,所以今天我就想说说我了解到的一些关于卫星通信的东西。
|
||||||
|
|
||||||
|
# 关于卫星通信
|
||||||
|
其实卫星通信在我们身边非常的常见,最常见的应该就是GNSS了,现在不仅手机可以通过卫星来导航,连各种各样的物联网设备也可以做到。不过这和卫星电话还是有点区别,因为卫星电话是双向通信,但是导航卫星是单向通信,手机通过卫星广播的位置信息以及一些信号差分等方式来计算出当前的坐标,所以连接导航卫星并不需要很长的天线,因为它不需要发射信号。
|
||||||
|
和这个类似的还有卫星电视,虽然卫星电视也不需要双向通信,但是可能因为它带宽比较大,然后稳定性要求比较高?所以大多需要一个接收锅来接收卫星信号。不过也许我说的是错的,以前在智能手机不太流行的时候有一种能在小型设备上观看的卫星电视,叫做CMMB,那个就是在手机上拉出一条天线就可以看电视了,不过我不太确定这个是通过卫星还是通过地面中继的方式工作的,也许两个都有?我记得这个似乎在房间里面也能收到信号,不太确定这小小的天线是不是真的能连接到卫星。
|
||||||
|
除了这些之外,还有一些搞业余无线电之类的人可以从国际空间站上通过SSTV之类的方式发送比如在太空中拍的图片啥的,不过我不太了解这些😂,就不多说了。
|
||||||
|
至于双向通信可能日常遇见的比较少,可能比较常见的就是有些电视台会使用卫星来转发信号之类的,还有就是打国际长途的时候似乎也是通过卫星来转发的。当然做这些操作的设备一般天线都非常大。
|
||||||
|
小的倒也不是没有,有些比较高级的车上面会搭载车载卫星电话,在紧急救援的时候就可以使用,当然普通的卫星电话也不大,只不过一般都会带折叠天线,价格倒是也还好,便宜的也有2K多。除了卫星电话之外可能最知名的就是星链了,那个也是使用的是卫星锅来上网,不过因为是近地卫星,而且数量众多,所以速度要比通讯卫星的速度快得多。
|
||||||
|
除此之外我之前还看过一位大佬[用卫星和世界各地的人通信](https://blog.aoaoao.me/p/amateur-satellite/),不过那个天线比较大,还要手动操作😂。
|
||||||
|
|
||||||
|
# 关于华为卫星电话的看法
|
||||||
|
综上所述,华为新出的卫星电话能不使用外置天线就能使用卫星电话似乎确实挺厉害的?不过因为我没用过普通的卫星电话所以不太清楚,如果普通的卫星电话不需要转手机来寻星,那华为的卫星电话可能算不了什么,毕竟那么大个直板机,把自己当天线也不是什么难事。不过如果普通的卫星电话也需要瞄准卫星才能通信,那华为应该还是有点水平的。
|
||||||
|
我看过几个这个手机拆解视频,不过到处都没有看到明显的天线痕迹,卫星电话应该需要一个比较大的天线吧……那它能把天线藏到哪里呢?我想那个巨大的均热板会不会是天线呢?本来就是铜的,当个天线可能也是正常的吧,不过我毕竟在云,也不能完全确定😂。
|
||||||
|
至于在智能手机上增加卫星电话的功能……其实我觉得这是个莫名其妙的行为,可能主要还是为了营销,从价格上来说,3K买个卫星电话+3K买个SOC是骁龙8gen2的手机(例如红米K60 Pro)也比华为Mate 60 Pro便宜,而且灵活性和手机性能都更好,我不知道增加了这个卫星电话功能对手机成本的增加到底有多少,如果很多的话我想除了脑子有病的厂商才会去干这件事,毕竟绝大多数的情况都用不到卫星电话,很多时候没有移动信号的时候同样也接收不到卫星信号,比如埋在废墟中或者在电梯中等,除此之外还只能使用中国电信的SIM卡才能使用,还要开通套餐,还只能使用天通卫星,去远一点的海上旅个游是不是又得买别的卫星电话😅。当然如果成本很低,比如确实就是均热板另外加个芯片就能用那我觉得还行,就是销售价格太贵,不过是公司想多赚点嘛,这能理解😆。
|
||||||
|
至于有些人说的布局6G那就更扯了,如果真的6G是卫星网络,那不可能不加天线,我相信没人会想瞄着卫星上网吧,而且卫星网络无论如何都没办法做的比地面基站更快,总不至于6G比5G还慢吧🤣。
|
||||||
|
|
||||||
|
# 感想
|
||||||
|
卫星通信看似高级,不过本质其实就只是和飞的比较快(同步卫星可能不需要考虑这个吧……),离得比较远 ~~(几万公里其实还挺远的🤣)~~ 的无线电台通信罢了,再简单点,拿个激光笔都能和几公里外的人通信,所以这真不是啥难事,想想人类都能和飞了不知多远的旅行者1号通信,是不是觉得其实还好呢?
|
65
_posts/2023-09-24-rpi-ubuntu.md
Normal file
65
_posts/2023-09-24-rpi-ubuntu.md
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
---
|
||||||
|
layout: post
|
||||||
|
title: 在树莓派4B上安装Ubuntu以及各种操作
|
||||||
|
tags: [树莓派, Ubuntu]
|
||||||
|
---
|
||||||
|
|
||||||
|
明明在普通的电脑上也能完成这些操作……😥<!--more-->
|
||||||
|
|
||||||
|
# 起因
|
||||||
|
自从上次我给我的树莓派4B-8GiB内存版[安装了Windows11](/2023/05/22/rpi-win.html)以后,我感觉这个东西上是真的鸡肋,速度慢而且兼容性还差,指令集有缺失连很多需要用到加密库的软件都不能正常运行……后来我就重装了一个ESXi-Arm Fling,但是装这个也有个问题,就是它不能使用TF卡存储东西,我还特地为了Windows买了个64GiB的TF卡,结果装虚拟机还用不了😂,U盘我也只有一个32GiB的,ESXi-Arm Fling如果想要正常的存储配置信息就至少需要占用掉3*4GiB的空间,这样虚拟机就只能使用20GiB的空间……真的全都是垃圾,20GiB能开几个虚拟机啊,开了也没啥能用的。所以这个树莓派就一直在吃灰。
|
||||||
|
后来我又想整点活,想着干脆安装个Ubuntu好了,反正放着也是吃灰,也错过了最佳卖树莓派的机会,就用起来吧,安装Ubuntu的时候居然也是各种碰壁😓,一开始我用树莓派镜像烧录器,闭着眼睛直接选了Ubuntu Server系统,我还以为它可以像安装树莓派系统那样第一次启动的时候让我设置密码,结果烧录完之后引导就直接让登录了,我连密码都不知道要怎么登录啊😥,网上搜了一下有默认密码,输进去之后显示需要让我更改密码,结果这个需要更改的密码怎么设置都不能生效😰,后来去Ubuntu官网看了一眼才知道原来需要在烧录中选择高级设置,手动设置密码才行……网上这些教程都是垃圾,这个软件也一样🤬,啥提示都没有,不看文档就只能靠猜了😢。
|
||||||
|
最后终于把Ubuntu安装好了,可以开始整活了😁。
|
||||||
|
|
||||||
|
# 用树莓派整点什么
|
||||||
|
## 整点FM电台
|
||||||
|
安装好Ubuntu后我最先想干的事情还是整[FM电台](/2022/03/27/radio.html),毕竟这真的就是树莓派唯一和其他设备不一样的地方了啊,于是我就编译了一下[PiFmAdv](https://github.com/miegl/PiFmAdv)并运行,结果不知道为什么一运行树莓派就直接死机……于是我退而求其次,选择了[fm_transmitter](https://github.com/markondej/fm_transmitter),这个倒是能运行,不过操作和树莓派3B区别相当大,首先编译得要用`make GPIO21=1`,然后杜邦线也要插到第40个接口,具体如下图打x的位置:
|
||||||
|
```
|
||||||
|
,--------------------------------.
|
||||||
|
| ooooooooooooooooooox J8 +======
|
||||||
|
| 1ooooooooooooooooooo PoE | Net
|
||||||
|
| Wi 1o +======
|
||||||
|
| Fi Pi Model 4B V1.4 oo |
|
||||||
|
| ,----. +---+ +====
|
||||||
|
| |D| |SoC | |RAM| |USB3
|
||||||
|
| |S| | | | | +====
|
||||||
|
| |I| `----' +---+ |
|
||||||
|
| |C| +====
|
||||||
|
| |S| |USB2
|
||||||
|
| pwr |hd| |hd| |I||A| +====
|
||||||
|
`-| |---|m0|---|m1|----|V|-------'
|
||||||
|
```
|
||||||
|
CPU和GPU也全部需要定频运行,另外设置频率不能超过93 MHz……我调了半天才能正常运行……还有就是不像之前PiFmAdv那个项目可以使用立体声,感觉树莓派4B还不如3B……
|
||||||
|
不过我写着写着感觉好像不太对劲,看了一眼我上次写电台的那篇文章的时间比PiFmAdv最后一次更新还要早,看了一眼提交发现人家已经把问题解决了,难怪我运行不起来,原来是代码没用最新的🤣,刚刚更新了一下代码之后再运行已经没有任何问题了,立体声啥的都能正常使用了。不过Makefile还是没改……aarch64的系统运行依然会出问题😥……其实改起来也很简单,把Makefile里面的两个参数换成:
|
||||||
|
```Makefile
|
||||||
|
CFLAGS = $(STD_CFLAGS) -march=armv8-a -ffast-math -DRASPI=4
|
||||||
|
TARGET = pi4
|
||||||
|
```
|
||||||
|
就可以正常编译了。
|
||||||
|
## 整点大语言模型LLaMA
|
||||||
|
因为我的树莓派有8GiB内存,之前我在我的8GiB内存的[MacBook Pro上跑LLaMA](/2023/04/05/ai.html)都没问题,那在树莓派上跑个LLaMA应该也没问题,所以就想试试看。跑起来非常简单,把[llama.cpp](https://github.com/ggerganov/llama.cpp)拉下来,然后直接编译就行了,但是实际跑起来速度非常慢,大概1token要1-2秒……根本用不成,不过现在的llama.cpp已经非常完善了,支持各种各样的硬件加速,无论是在我的MacBook上,还是用N卡、A卡,甚至手机使用OpenCL似乎都可以进行硬件加速。这些都能得到很不错的速度,那树莓派呢?树莓派用的好像是博通的叫什么VideoCore的显卡,我搜了一下,貌似没有办法使用OpenCL……不过搜的过程中发现似乎可以[装Vulkan](https://qengineering.eu/install-vulkan-on-raspberry-pi.html),虽然llama.cpp不能使用Vulkan,不过ncnn框架似乎可以使用Vulkan,跑个waifu2x也算不浪费这个树莓派的GPU啊,只是安了半天发现不连接屏幕貌似安了也识别不了……所以还是算了吧……
|
||||||
|
## 整点QEMU-KVM Windows虚拟机
|
||||||
|
当时我在树莓派上安装Windows11的时候听说在虚拟机上运行的效果要比裸机安装效果更好,我听到之后认为这是胡说八道,哪有虚拟机比裸机运行效果好的啊,不过树莓派嘛……说不定会有因为驱动不完整之类的情况,毕竟如果是在虚拟机里安装系统外面的Linux系统可以使用无线网卡,而直接安装Windows是不能使用无线网卡的,所以这次我也打算试试看,反正树莓派上使用虚拟机是可以使用KVM加速的,所以试试也没关系。
|
||||||
|
安装QEMU也很简单,直接执行:
|
||||||
|
```bash
|
||||||
|
sudo apt install qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils virtinst virt-manager qemu-system-arm qemu-efi-aarch64 seabios vgabios
|
||||||
|
```
|
||||||
|
就可以了,安装系统的话也很简单,首先去下载Windows所需要的驱动[virtio-win](https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/latest-virtio/),然后下载Windows ARM版的安装光盘,这个去MSDN I tell you下载就行了,之后下载一个VNC客户端用来连接虚拟机的屏幕,然后创建硬盘:
|
||||||
|
```bash
|
||||||
|
qemu-img create -f vhdx -o subformat=fixed system.vhdx 30G
|
||||||
|
```
|
||||||
|
准备好这些以后就可以启动虚拟机了,启动的命令如下:
|
||||||
|
```bash
|
||||||
|
sudo qemu-system-aarch64 -M virt-2.12 -smp 4 -m 4G -cpu host -enable-kvm -bios /usr/share/qemu-efi-aarch64/QEMU_EFI.fd -device ramfb -device qemu-xhci,id=xhci -usb -device usb-kbd -device usb-mouse -device usb-tablet -k en-us -device virtio-balloon -device virtio-rng -device virtio-blk,drive=system -drive if=none,id=system,format=raw,media=disk,file=system.vhdx -device usb-storage,drive=install -drive if=none,id=install,format=raw,media=cdrom,file=win10.iso -device usb-storage,drive=drivers -drive if=none,id=drivers,media=cdrom,file=virtio-win.iso -device virtio-net,disable-legacy=on,netdev=net0 -netdev user,id=net0,hostfwd=tcp::3389-:3389 -vnc :1
|
||||||
|
```
|
||||||
|
然后就能像正常安装Windows系统那样安装了,其中需要注意的一点是安装的时候会读不到硬盘,需要加载光盘中的驱动,其他缺失的驱动光盘里基本上都有,直接安装就行。另外第一次重启前最好把`-device usb-storage,drive=install -drive if=none,id=install,format=raw,media=cdrom,file=win10.iso`删掉,安装好之后可以打开远程桌面,就可以直接使用树莓派的IP去连接Windows系统,还能有完整的分辨率和音频支持。
|
||||||
|
既然装好了虚拟机,那么我就应该验证一下虚拟机是不是真的比物理机安装效果更好了。具体怎么验证呢?我又找了一个树莓派4B-4GiB内存版,在上面安装直接安装同版本的Windows ARM版,然后把两个树莓派的频率都调为1.8GHz,在两个Windows系统上下载了7-Zip ARM版,跑一遍基准测试,结果裸机安装的总体评分为6.1GIPS左右,虚拟机是5.1GIPS左右,这很明显裸机还是更强嘛,虚拟机唯一的优势就是可以用无线网络罢了,说到网络我也测了一下这个速度,在同样使用有线网络的情况下,虚拟机因为用的是user模式效果很差,连50Mbps都跑不到,而裸机可以超过100Mbps。至于qemu怎么使用其他网络模式我也不太会,整起来好像还挺麻烦的。总的来看树莓派安装QEMU-KVM运行Windows实在是不怎么样……一样是个垃圾。
|
||||||
|
## 让树莓派运行x86程序
|
||||||
|
既然安装了QEMU,那就该玩玩跨指令集的东西了,当然跨指令集是没办法使用KVM了,而且树莓派不像MacBook的Rosetta 2那样有硬件加速,效果肯定会非常差,不过我已经做好了觉悟,还是想整个玩玩。怎么整呢?非常简单,只要运行
|
||||||
|
```bash
|
||||||
|
sudo apt install qemu-user-binfmt
|
||||||
|
```
|
||||||
|
就好了,那到底是什么软件让我想大费周章的让树莓派运行x86程序呢?其实是一个叫做[postjson](http://cdn.ouapi.com/postjson_linux.zip)的接口测试工具,似乎是拿Go写的,但是没有开源,也没有ARM64的二进制文件,所以就只好用QEMU啦,试了一下还真能运行,而且就像Rosetta 2那样直接当作原生的程序运行就可以,效果挺不错,不过CPU占用非常高,一运行一个CPU核心就占满了😂,也就是勉强能用的水平吧。
|
||||||
|
|
||||||
|
# 感想
|
||||||
|
搞了这么多东西之后发现树莓派除了那个FM电台不能在普通电脑上操作其他不是和普通的电脑一样吗🤣?那买树莓派还有什么意义,不如买个二手手机,不过有了树莓派就感觉越垃圾越想挖掘它的作用,这可能就是它存在的意义吧🤣。
|
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:['0001','0002','0003','0004','0005','0006','0007','0008','0009','0010','0011','0012','0013','0014','0015','0016','0017','0018','0019','0020','0021','0022','0023','0024','0025','0026','0027','0028','0029','0030','0031','0032','0033','0034','0035','0036','0037','0038','0039','0040','0041','0042','0043','0044','0045','0046','0047','0048','0049','0050','0051','0052','0053','0054','0055','0056','0057','0058','0059','0060','0061','0062','0063','0064','0065','0066','0067','0068','0069','0070','0071','0072','0073','0074','0075','0076','0077','0078','0079','0080','0081','0082','0083','0084','0085','0086','0087','0088','0089','0090','0091','0092','0093','0094','0095','0096','0097','0098','0099','0100','0101','0102','0103','0104','0105','0106','0107','0108','0109','0110','0111','0112','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','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','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'],
|
|
||||||
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="">
|
|
||||||
</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,9 +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="/iwara.html">Iwara Download</a><br>
|
<a href="{% unless site.github %}https://mabbs.github.io{% endunless %}/karyl-yabaival/">拯救凯露</a><br>
|
||||||
|
|
||||||
<a href="/card.html">抽卡</a> - 由<a href="https://github.com/eeg1412/">广树</a>大佬提供卡牌<br>
|
|
||||||
|
|
||||||
<a href="/message.html">留言板</a><br>
|
<a href="/message.html">留言板</a><br>
|
||||||
|
|
||||||
|
35
iwara.html
35
iwara.html
@ -1,35 +0,0 @@
|
|||||||
<title>Iwara Downloader</title>
|
|
||||||
<h1>Iwara Downloader</h1>
|
|
||||||
URL: <input type="text" id="url" /> <button onclick="resolve()">Resolve</button>
|
|
||||||
<table id="result-table" border="1" style="display:none">
|
|
||||||
<tr><th>Resolution</th><th>URI</th><th>IP</th><th>Host</th></tr>
|
|
||||||
<tbody id="result"></tbody>
|
|
||||||
</table>
|
|
||||||
<script src="/js/jquery.min.js"></script>
|
|
||||||
<script>
|
|
||||||
function resolve(){
|
|
||||||
$("#result-table").css('display', "none");
|
|
||||||
$("#result").empty();
|
|
||||||
$.get("https://iwara.mayx.eu.org/api/video/" + $("#url")[0].value.split("/").pop(), function(data){
|
|
||||||
if(!data.length){
|
|
||||||
alert("Resolve Failed");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$("#result-table").css('display', "table");
|
|
||||||
var hosts = new Set();
|
|
||||||
console.log(data);
|
|
||||||
data.forEach(function(downuri){
|
|
||||||
var host = downuri["uri"].split("/")[2];
|
|
||||||
hosts.add(host);
|
|
||||||
$("#result").append("<tr><td>" + downuri["resolution"] + '</td><td><a href="' + downuri["uri"] + '">Download</a></td><td class="' + host.split(".")[0] + '">Loading...</td><td>' + host + '</td></tr>');
|
|
||||||
});
|
|
||||||
hosts.forEach(function(host){
|
|
||||||
$.get("https://dns.mayx.eu.org/resolve?type=A&name=" + host, function(result){
|
|
||||||
$("." + host.split(".")[0]).each(function(i, element){
|
|
||||||
element.innerHTML = result["Answer"][0]["data"];
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
|
@ -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/";
|
||||||
|
6
links.md
6
links.md
@ -8,14 +8,16 @@ tags: [links]
|
|||||||
|
|
||||||
| Links | Introduce |
|
| Links | Introduce |
|
||||||
| - | - |
|
| - | - |
|
||||||
| [花火学园](https://www.sayhuahuo.com/) | 和谐融洽的ACG交流以及资源聚集地 |
|
| [花火学园](https://www.sayhuahuo.shop/) | 和谐融洽的ACG交流以及资源聚集地 |
|
||||||
| [资源统筹局](https://gkdworld.xyz/) | 统筹保管用户分享的资源 |
|
| [资源统筹局](https://gkdworld.com/) | 统筹保管用户分享的资源 |
|
||||||
| [贫困的蚊子](https://mozz.ie/) | *No description* |
|
| [贫困的蚊子](https://mozz.ie/) | *No description* |
|
||||||
| [极客兔兔](https://geektutu.com/) | 致力于分享有趣的技术实践 |
|
| [极客兔兔](https://geektutu.com/) | 致力于分享有趣的技术实践 |
|
||||||
| [维基萌](https://www.wikimoe.com/) | 萌即是正义!一名热爱acg的前端设计师的小站! |
|
| [维基萌](https://www.wikimoe.com/) | 萌即是正义!一名热爱acg的前端设计师的小站! |
|
||||||
| [7gugu's blog](https://www.7gugu.com/) | 一个用来存放我爱好的地方,编程,摄影之类的空间 |
|
| [7gugu's blog](https://www.7gugu.com/) | 一个用来存放我爱好的地方,编程,摄影之类的空间 |
|
||||||
| [云游君](https://www.yunyoujun.cn/) | 希望能成为一个有趣的人。 |
|
| [云游君](https://www.yunyoujun.cn/) | 希望能成为一个有趣的人。 |
|
||||||
| [Kingfish404](https://blog.kingfish404.cn/) | Stay curious,stay naive. WUT. Jin Yu's Blog |
|
| [Kingfish404](https://blog.kingfish404.cn/) | Stay curious,stay naive. WUT. Jin Yu's Blog |
|
||||||
|
| [FKUN](https://blog.fkun.tech/) | *No description* |
|
||||||
|
| [Sinofine](https://sinofine.me/) | *No description* |
|
||||||
|
|
||||||
|
|
||||||
## Links申请
|
## Links申请
|
||||||
|
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"
|
||||||
|
}
|
||||||
|
}
|
35
proxylist.md
35
proxylist.md
@ -3,30 +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://mayx.mabbs.repl.co/>
|
- <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.cf/>
|
|
||||||
- <https://blog.mayx.tk/>
|
|
||||||
- <https://yuki.gear.host/>
|
|
||||||
- <https://mayx.tech/>
|
|
||||||
|
|
||||||
# 镜像列表
|
# 镜像列表
|
||||||
由于[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/>
|
||||||
@ -37,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