7 Commits

Author SHA1 Message Date
mayx
71d493c2a8 Update 4 files
- /_data/other_repo_list.csv
- /_posts/2026-06-01-dedupe.md
- /assets/js/pjax.js
- /index.html
2026-05-31 16:00:35 +00:00
mayx
156f964333 Update 3 files
- /_data/other_repo_list.csv
- /assets/js/main_new.js
- /assets/js/pjax.js
2026-05-27 02:37:23 +00:00
mayx
481df19596 Update 5 files
- /_layouts/default.html
- /_data/proxylist.yml
- /assets/js/main.js
- /assets/js/pjax.js
- /assets/js/main_new.js
2026-05-23 10:06:55 +00:00
mayx
1a529143a8 Update 6 files
- /assets/js/pjax.js
- /assets/js/gitalk.min.js
- /assets/js/jquery.min.js
- /assets/css/gitalk.css
- /_data/proxylist.yml
- /_tools/stormkit-env_install
2026-05-22 16:07:03 +00:00
mayx
b25a864ee3 Update 3 files
- /_layouts/default.html
- /assets/js/pjax.js
- /assets/css/style.scss
2026-05-22 12:52:39 +00:00
mayx
c5ad917d9e Update 6 files
- /_layouts/post.html
- /_layouts/default.html
- /assets/js/main.js
- /assets/js/pjax.js
- /_data/other_repo_list.csv
- /Live2dHistoire/live2d/js/message.js
2026-05-22 12:00:45 +00:00
mayx
d6274791a8 Update 2 files
- /assets/js/pjax.js
- /index.html
2026-05-21 10:11:01 +00:00
15 changed files with 366 additions and 338 deletions

View File

@@ -129,35 +129,8 @@ if (!norunFlag) {
} else {
text = '嗨!来自 <span style="color:#0099cc;">' + referrer.hostname + '</span> 的朋友!';
}
} else if (typeof window._pjaxGetWelcomeText === 'function') {
// 复用 pjax.js 中的欢迎语生成函数,避免重复逻辑
text = window._pjaxGetWelcomeText();
} else {
// pjax.js 尚未加载时的兜底(首次访问且 pjax.js 在 message.js 之后加载)
if (window.location.pathname == "/") {
var now = (new Date()).getHours();
if (now > 23 || now <= 5) {
text = '你是夜猫子呀?这么晚还不睡觉,明天起的来嘛?';
} else if (now > 5 && now <= 7) {
text = '早上好!一日之计在于晨,美好的一天就要开始了!';
} else if (now > 7 && now <= 11) {
text = '上午好!工作顺利嘛,不要久坐,多起来走动走动哦!';
} else if (now > 11 && now <= 14) {
text = '中午了,工作了一个上午,现在是午餐时间!';
} else if (now > 14 && now <= 17) {
text = '午后很容易犯困呢,今天的运动目标完成了吗?';
} else if (now > 17 && now <= 19) {
text = '傍晚了!窗外夕阳的景色很美丽呢,最美不过夕阳红~~';
} else if (now > 19 && now <= 21) {
text = '晚上好,今天过得怎么样?';
} else if (now > 21 && now <= 23) {
text = '已经这么晚了呀,早点休息吧,晚安~~';
} else {
text = '嗨~ 快来逗我玩吧!';
}
} else {
text = '欢迎阅读<span style="color:#0099cc;">「 ' + document.title.split(' | ')[0] + ' 」</span>';
}
text = getWelcomeText();
}
showMessage(text, 12000);
})();

View File

@@ -18,7 +18,6 @@ https://repo2.serv00.com/git/pub/Mayx/mayx/
https://git.pixie.town/mayx/mayx
https://codefloe.com/mayx/blog
https://git.minetest.land/Mayx/blog
http://47.120.60.153:10880/mayx/blog
http://1.6.141.109:3000/mayx/blog
http://52.28.156.42/mayx/blog
https://code.dsconce.space/mayx/blog
@@ -46,20 +45,14 @@ http://47.107.88.161:3000/mayx/blog
http://142.171.47.170:3000/mayx/blog
http://111.231.146.230:8418/mayx/blog
https://git.pwaapp.cc/mayx/blog
https://git.sleepingforest.co.uk/mayx/blog
https://an360.top/mayx/blog
http://106.15.78.64:3000/mayx/blog
https://git.wisder.net/mayx/blog
http://111.119.244.185:3000/mayx/blog
http://110.41.179.36:13000/mayx/blog
https://git.influxfin.com/mayx/blog
http://219.157.255.213:25311/mayx/blog
https://git.vekus.ru/mayx/blog
http://116.204.75.78:6180/mayx/blog
http://109.228.48.121:8000/mayx/blog
https://git.hubhoo.com/mayx/blog
http://27.124.12.222:3000/mayx/blog
https://git.sayndone.ru/mayx/blog
https://gitea.hintsight.com/mayx/blog
http://blackobelisk.xyz:3000/mayx/blog
https://git.the-kn.com/mayx/blog
@@ -134,8 +127,6 @@ http://101.201.34.43:3000/mayx/blog
https://git.gloje-rinchen-dorjee-rinpoche-buddhist-monastery.org/mayx/blog
http://101.35.227.2:3000/mayx/blog
http://175.126.123.163:3000/mayx/blog
http://git.uhfdemo.com/mayx/blog
https://git.jakubzabski.pl/mayx/blog
http://209.141.47.52:3000/mayx/blog
http://60.204.158.188:3000/mayx/blog
http://60.204.156.211:3000/mayx/blog
@@ -168,7 +159,6 @@ http://210.245.20.73:3333/mayx/blog
http://43.248.97.109:3000/mayx/blog
http://113.207.86.104:3080/mayx/blog
http://39.96.195.72:10082/mayx/blog
http://8.148.24.160:3000/mayx/blog
https://221.219.181.35:30000/mayx/blog
http://172.172.102.93:3000/mayx/blog
http://115.120.245.164:3000/mayx/blog
@@ -204,7 +194,6 @@ http://docker.clhero.fun:3000/mayx/blog
https://bdgit.educoder.net/mayx/blog
http://e19510c831.iok.la/mayx/blog
http://119.45.49.212:3000/mayx/blog
https://gitea.kdlsvps.top/mayx/blog
https://code.antopie.org/mayx/blog
https://git.serenetia.com/mayx/blog
https://vcs.cozydsp.space/mayx/blog
@@ -270,12 +259,10 @@ https://git.cenoq.com/mayx/blog
http://8.152.205.35:3000/mayx/blog
http://120.210.80.160:3000/mayx/blog
http://1.95.192.200:59300/mayx/blog
https://git.medis.com.vn/mayx/blog
http://194.5.152.156:3000/mayx/blog
http://8.155.172.147:3001/mayx/blog
https://git.erfmann.dev/mayx/blog
https://git.weavefun.com:5443/mayx/blog
https://git.vajdak.cz/mayx/blog
http://58.65.162.118:3000/mayx/blog
https://git.arkon.solutions/mayx/blog
http://8.131.93.145:54082/mayx/blog
@@ -283,9 +270,7 @@ http://111.9.31.174:10007/mayx/blog
https://forgejo.bridgetownrb.com/mayx/blog
http://54.199.96.217:3000/mayx/blog
http://20.219.0.85:3000/mayx/blog
https://dev01.open-alt.com/mayx/blog
https://gitea.doinlab.com/mayx/blog
https://gitea.creative-tg1.ru/mayx/blog
https://git.7af.ru/mayx/blog
https://gitea.yimoyuyan.cn/mayx/blog
https://git.apextoaster.com/mayx/blog
@@ -297,14 +282,12 @@ https://dev.kiramtech.com/mayx/blog
https://git.ihatemen.uk/mayx/blog
https://git.123doit.com/mayx/blog
http://62.43.207.91:8889/mayx/blog
https://rsas.de/mayx/blog
https://git.johntsai.online/mayx/blog
https://gitea.css-sistemas.com.br/mayx/blog
https://git.f4e.lol/mayx/blog
http://47.113.145.232:3000/mayx/blog
http://47.115.212.237:3000/mayx/blog
http://72.61.229.93:4000/mayx/blog
https://git.yinbonet.cn/mayx/blog
https://lishan148.synology.me:3014/mayx/blog_cn
http://1.95.221.174:3000/mayx/blog
https://git.huwhy.cn/mayx/blog_cn
@@ -344,7 +327,6 @@ http://xujiesoft.vicp.net:3000/mayx/blog_cn
http://113.44.36.103:23000/mayx/blog_cn
https://git.mingliqiye.com/mayx/blog_cn
http://119.29.194.155:8894/mayx/blog_cn
http://43.138.249.161:3000/mayx/blog_cn
http://58.213.60.6:19000/mayx/blog_cn
http://36.153.162.171:3000/mayx/blog_cn
http://47.92.113.131:3000/mayx/blog
@@ -354,9 +336,6 @@ https://git.gnyra.com/mayx/blog
https://git.graveyard.sh/mayx/blog
https://git.nathanspackman.com/mayx/blog
https://git.rmarl.in/mayx/blog
https://git.alderautomation.ca/mayx/blog
http://git.qniao.cn/mayx/blog
https://git.fast-blast.uk/mayx/blog
http://git.mynas71.myds.me/mayx/blog
https://git.4lsa.com/mayx/blog
https://rlgit.pro/mayx/blog
@@ -364,24 +343,19 @@ https://git.veraskolivna.net/mayx/blog
https://git.lifetop.net/mayx/blog
https://gitea.jnyuxia.com/mayx/blog
http://git.liuhung.com/mayx/blog
https://git.secretserver.club/mayx/blog
https://gitea.adber.tech/mayx/blog
https://gitea.hello.faith/mayx/blog
https://tea.neuron.my/mayx/blog
https://git.violka-it.net/mayx/blog
https://git.adityagupta.dev/mayx/blog
https://code.ownwire.net/mayx/blog
https://git.danpeak.co.uk/mayx/blog
https://gitea.mynas-lechner.de/mayx/blog
https://git.automathon.org/mayx/blog
https://aeterna.cim.mcgill.ca/mayx/blog
https://git.esen.gay/mayx/blog
https://git.webtims.ru/mayx/blog
https://gitea.personalsoftware.space/mayx/blog
http://gitea.yiban.com.tw:3030/mayx/blog
https://gitlab.iplusus.com/mayx/blog
https://git.cyberuk.me/mayx/blog
https://git.privezishop.ru/mayx/blog
https://gitea.zachl.tech/mayx/blog
https://git.miasma-os.com/mayx/blog
https://gitea.nacsity.cn/mayx/blog
@@ -397,13 +371,10 @@ http://47.105.124.101:3000/mayx/blog_cn
http://49.232.183.190:3000/mayx/blog_cn
http://git.zxkedu.com:33769/mayx/blog_cn
https://code.wemediacn.com/mayx/blog_cn
https://gitea.shizuka.icu/mayx/blog_cn
http://43.139.2.237:3000/mayx/blog_cn
http://51.159.198.233:3000/mayx/blog
https://gitea.adriangonzalezbarbosa.eu/mayx/blog
https://git.legatus.ru/mayx/blog
https://git.kayashov.keenetic.pro/mayx/blog
http://43.138.83.20:3000/mayx/blog_cn
http://47.104.241.192:19999/mayx/blog_cn
http://47.98.148.146:1026/mayx/blog_cn
http://119.96.62.56:3000/mayx/blog_cn
@@ -445,7 +416,6 @@ http://47.117.245.9:17701/mayx/blog_cn
https://git.sunlix.one/mayx/blog_cn
http://47.106.222.181:20511/mayx/blog_cn
http://101.43.95.130:3001/mayx/blog_cn
http://39.101.170.62:9080/mayx/blog_cn
https://gitea.myat4.com/mayx/blog_cn
http://118.24.161.24:3000/mayx/blog_cn
http://githanea.s.odn.cc/mayx/blog_cn
@@ -454,7 +424,6 @@ http://35.175.189.8/mayx/blog
http://meowug.com:8418/mayx/blog_cn
http://36.138.125.206:3000/mayx/blog_cn
https://git.4lcap.com/mayx/blog_cn
https://gitea.visoftware.com.co/mayx/blog_cn
http://101.43.238.71:3000/mayx/blog_cn
http://59.110.175.62:4322/mayx/blog_cn
https://www.luluvip.cn:8419/mayx/blog_cn
@@ -464,7 +433,6 @@ https://silica.codes/mayx/blog
https://git.crystalyx.net/mayx/blog
https://gittea.dev/mayx/blog
https://git.newnaturalphilosophy.org/mayx/blog
http://mrjinit.com:3000/mayx/blog
https://code.infininov.com/mayx/blog
https://git.apt142.ru/mayx/blog
http://gitea.mcelwain.net/mayx/blog
@@ -488,17 +456,13 @@ https://papi.tkpups.com/mayx/blog
https://git.beyond-a-i.org/mayx/blog
http://huanghomenas2.myqnapcloud.com:4000/mayx/blog_cn
http://43.142.166.108:10082/mayx/blog_cn
https://git.ueda.sk/mayx/blog_cn
https://tm-jikayo.com/mayx/blog_cn
http://zzdgitea.stnav.com/mayx/blog_cn
http://1.117.66.197:3000/mayx/blog_cn
http://git.zhmight.com/mayx/blog_cn
https://intl-dev.gaia888.com/mayx/blog_cn
https://gitea.xinyuxi.com/mayx/blog_cn
http://gitea.snailtrack.cn/mayx/blog_cn
https://git.powerdata.dk/mayx/blog
http://ydds.cloud:3000/mayx/blog_cn
https://git.keruixinda.com/mayx/blog_cn
http://120.24.50.145:3000/mayx/blog_cn
https://code.draussenfunker.de/mayx/blog_cn
https://git.dinsor.co.th/mayx/blog
@@ -508,8 +472,6 @@ http://www.arkproject.top/mayx/blog
http://www.bkandssp.cn:30/mayx/blog
https://gitea.spitaki.cloud/mayx/blog
https://git.codle.ru/mayx/blog
http://139.224.24.61:3000/mayx/blog
https://git.sao.ru/mayx/blog
https://codeop.ru/mayx/blog
https://git.mirocom.org/mayx/blog
http://gitea.ydxtool.com/mayx/blog
@@ -523,12 +485,10 @@ https://git.kraevsky.ru/mayx/blog
https://ruyiscx.cloud:3000/mayx/blog
https://git.0xee.eu/mayx/blog
https://gitea.deitglobal.com/mayx/blog
https://www.mygitea.ru/mayx/blog
https://git.crwlr.ir/mayx/blog
https://git.nozora.top/mayx/blog
https://git.sortug.com/mayx/blog
https://aivyx-gitea.cloud/mayx/blog
https://git.akarmain.ru/mayx/blog
https://git.edenit.co.kr/mayx/blog
https://git.catgirlsneed.homes/mayx/blog
https://git.eldev.netcraze.pro/mayx/blog
@@ -538,7 +498,6 @@ https://gitea.molietech.com/mayx/blog_cn
http://58.87.88.234:3000/mayx/blog_cn
http://210.75.240.13:3000/mayx/blog_cn
https://git.xz-i.com:30443/mayx/blog_cn
http://111.229.64.148:8080/mayx/blog_cn
https://git.fynn.vip/mayx/blog_cn
http://119.91.212.17:3000/mayx/blog_cn
http://git.hbg99.com:8080/mayx/blog_cn
@@ -548,4 +507,16 @@ http://namonba.asuscomm.com:3001/mayx/blog
http://109.199.98.226:3001/mayx/blog
https://git.extra.eiffel.com/mayx/blog
https://gitea.digitanie.org/mayx/blog
http://124.207.0.162:30000/mayx/blog
https://git.xleed.com/mayx/blog
https://qlcodegitserver.online/mayx/blog
https://gitea.vvzvlad.xyz/mayx/blog
https://git.supernets.org/mayx/blog
https://git.digitaltelepresence.com/mayx/blog
https://git.hrfee.pw/mayx/blog
https://git.libregaming.org/mayx/blog
https://git.kaki87.net/mayx/blog
https://forgejo.vanten-s.com/mayx/blog
https://git.heartnn.com/mayx/blog
https://git.joinplu.me/mayx/blog
https://git.research.dezeeuw.ca/mayx/blog
http://149.104.29.239:8081/mayx/blog
1 repo_url
18 https://git.pixie.town/mayx/mayx
19 https://codefloe.com/mayx/blog
20 https://git.minetest.land/Mayx/blog
http://47.120.60.153:10880/mayx/blog
21 http://1.6.141.109:3000/mayx/blog
22 http://52.28.156.42/mayx/blog
23 https://code.dsconce.space/mayx/blog
45 http://142.171.47.170:3000/mayx/blog
46 http://111.231.146.230:8418/mayx/blog
47 https://git.pwaapp.cc/mayx/blog
https://git.sleepingforest.co.uk/mayx/blog
48 https://an360.top/mayx/blog
http://106.15.78.64:3000/mayx/blog
https://git.wisder.net/mayx/blog
49 http://111.119.244.185:3000/mayx/blog
http://110.41.179.36:13000/mayx/blog
50 https://git.influxfin.com/mayx/blog
51 http://219.157.255.213:25311/mayx/blog
52 https://git.vekus.ru/mayx/blog
53 http://116.204.75.78:6180/mayx/blog
54 http://109.228.48.121:8000/mayx/blog
https://git.hubhoo.com/mayx/blog
55 http://27.124.12.222:3000/mayx/blog
https://git.sayndone.ru/mayx/blog
56 https://gitea.hintsight.com/mayx/blog
57 http://blackobelisk.xyz:3000/mayx/blog
58 https://git.the-kn.com/mayx/blog
127 https://git.gloje-rinchen-dorjee-rinpoche-buddhist-monastery.org/mayx/blog
128 http://101.35.227.2:3000/mayx/blog
129 http://175.126.123.163:3000/mayx/blog
http://git.uhfdemo.com/mayx/blog
https://git.jakubzabski.pl/mayx/blog
130 http://209.141.47.52:3000/mayx/blog
131 http://60.204.158.188:3000/mayx/blog
132 http://60.204.156.211:3000/mayx/blog
159 http://43.248.97.109:3000/mayx/blog
160 http://113.207.86.104:3080/mayx/blog
161 http://39.96.195.72:10082/mayx/blog
http://8.148.24.160:3000/mayx/blog
162 https://221.219.181.35:30000/mayx/blog
163 http://172.172.102.93:3000/mayx/blog
164 http://115.120.245.164:3000/mayx/blog
194 https://bdgit.educoder.net/mayx/blog
195 http://e19510c831.iok.la/mayx/blog
196 http://119.45.49.212:3000/mayx/blog
https://gitea.kdlsvps.top/mayx/blog
197 https://code.antopie.org/mayx/blog
198 https://git.serenetia.com/mayx/blog
199 https://vcs.cozydsp.space/mayx/blog
259 http://8.152.205.35:3000/mayx/blog
260 http://120.210.80.160:3000/mayx/blog
261 http://1.95.192.200:59300/mayx/blog
https://git.medis.com.vn/mayx/blog
262 http://194.5.152.156:3000/mayx/blog
263 http://8.155.172.147:3001/mayx/blog
264 https://git.erfmann.dev/mayx/blog
265 https://git.weavefun.com:5443/mayx/blog
https://git.vajdak.cz/mayx/blog
266 http://58.65.162.118:3000/mayx/blog
267 https://git.arkon.solutions/mayx/blog
268 http://8.131.93.145:54082/mayx/blog
270 https://forgejo.bridgetownrb.com/mayx/blog
271 http://54.199.96.217:3000/mayx/blog
272 http://20.219.0.85:3000/mayx/blog
https://dev01.open-alt.com/mayx/blog
273 https://gitea.doinlab.com/mayx/blog
https://gitea.creative-tg1.ru/mayx/blog
274 https://git.7af.ru/mayx/blog
275 https://gitea.yimoyuyan.cn/mayx/blog
276 https://git.apextoaster.com/mayx/blog
282 https://git.ihatemen.uk/mayx/blog
283 https://git.123doit.com/mayx/blog
284 http://62.43.207.91:8889/mayx/blog
https://rsas.de/mayx/blog
285 https://git.johntsai.online/mayx/blog
286 https://gitea.css-sistemas.com.br/mayx/blog
287 https://git.f4e.lol/mayx/blog
288 http://47.113.145.232:3000/mayx/blog
289 http://47.115.212.237:3000/mayx/blog
290 http://72.61.229.93:4000/mayx/blog
https://git.yinbonet.cn/mayx/blog
291 https://lishan148.synology.me:3014/mayx/blog_cn
292 http://1.95.221.174:3000/mayx/blog
293 https://git.huwhy.cn/mayx/blog_cn
327 http://113.44.36.103:23000/mayx/blog_cn
328 https://git.mingliqiye.com/mayx/blog_cn
329 http://119.29.194.155:8894/mayx/blog_cn
http://43.138.249.161:3000/mayx/blog_cn
330 http://58.213.60.6:19000/mayx/blog_cn
331 http://36.153.162.171:3000/mayx/blog_cn
332 http://47.92.113.131:3000/mayx/blog
336 https://git.graveyard.sh/mayx/blog
337 https://git.nathanspackman.com/mayx/blog
338 https://git.rmarl.in/mayx/blog
https://git.alderautomation.ca/mayx/blog
http://git.qniao.cn/mayx/blog
https://git.fast-blast.uk/mayx/blog
339 http://git.mynas71.myds.me/mayx/blog
340 https://git.4lsa.com/mayx/blog
341 https://rlgit.pro/mayx/blog
343 https://git.lifetop.net/mayx/blog
344 https://gitea.jnyuxia.com/mayx/blog
345 http://git.liuhung.com/mayx/blog
https://git.secretserver.club/mayx/blog
346 https://gitea.adber.tech/mayx/blog
347 https://gitea.hello.faith/mayx/blog
348 https://tea.neuron.my/mayx/blog
349 https://git.violka-it.net/mayx/blog
350 https://git.adityagupta.dev/mayx/blog
https://code.ownwire.net/mayx/blog
351 https://git.danpeak.co.uk/mayx/blog
352 https://gitea.mynas-lechner.de/mayx/blog
353 https://git.automathon.org/mayx/blog
https://aeterna.cim.mcgill.ca/mayx/blog
354 https://git.esen.gay/mayx/blog
355 https://git.webtims.ru/mayx/blog
356 https://gitea.personalsoftware.space/mayx/blog
357 http://gitea.yiban.com.tw:3030/mayx/blog
358 https://gitlab.iplusus.com/mayx/blog
https://git.cyberuk.me/mayx/blog
https://git.privezishop.ru/mayx/blog
359 https://gitea.zachl.tech/mayx/blog
360 https://git.miasma-os.com/mayx/blog
361 https://gitea.nacsity.cn/mayx/blog
371 http://49.232.183.190:3000/mayx/blog_cn
372 http://git.zxkedu.com:33769/mayx/blog_cn
373 https://code.wemediacn.com/mayx/blog_cn
https://gitea.shizuka.icu/mayx/blog_cn
http://43.139.2.237:3000/mayx/blog_cn
374 http://51.159.198.233:3000/mayx/blog
375 https://gitea.adriangonzalezbarbosa.eu/mayx/blog
376 https://git.legatus.ru/mayx/blog
377 https://git.kayashov.keenetic.pro/mayx/blog
http://43.138.83.20:3000/mayx/blog_cn
378 http://47.104.241.192:19999/mayx/blog_cn
379 http://47.98.148.146:1026/mayx/blog_cn
380 http://119.96.62.56:3000/mayx/blog_cn
416 https://git.sunlix.one/mayx/blog_cn
417 http://47.106.222.181:20511/mayx/blog_cn
418 http://101.43.95.130:3001/mayx/blog_cn
http://39.101.170.62:9080/mayx/blog_cn
419 https://gitea.myat4.com/mayx/blog_cn
420 http://118.24.161.24:3000/mayx/blog_cn
421 http://githanea.s.odn.cc/mayx/blog_cn
424 http://meowug.com:8418/mayx/blog_cn
425 http://36.138.125.206:3000/mayx/blog_cn
426 https://git.4lcap.com/mayx/blog_cn
https://gitea.visoftware.com.co/mayx/blog_cn
427 http://101.43.238.71:3000/mayx/blog_cn
428 http://59.110.175.62:4322/mayx/blog_cn
429 https://www.luluvip.cn:8419/mayx/blog_cn
433 https://git.crystalyx.net/mayx/blog
434 https://gittea.dev/mayx/blog
435 https://git.newnaturalphilosophy.org/mayx/blog
http://mrjinit.com:3000/mayx/blog
436 https://code.infininov.com/mayx/blog
437 https://git.apt142.ru/mayx/blog
438 http://gitea.mcelwain.net/mayx/blog
456 https://git.beyond-a-i.org/mayx/blog
457 http://huanghomenas2.myqnapcloud.com:4000/mayx/blog_cn
458 http://43.142.166.108:10082/mayx/blog_cn
https://git.ueda.sk/mayx/blog_cn
459 https://tm-jikayo.com/mayx/blog_cn
460 http://zzdgitea.stnav.com/mayx/blog_cn
461 http://1.117.66.197:3000/mayx/blog_cn
462 http://git.zhmight.com/mayx/blog_cn
463 https://intl-dev.gaia888.com/mayx/blog_cn
https://gitea.xinyuxi.com/mayx/blog_cn
464 http://gitea.snailtrack.cn/mayx/blog_cn
https://git.powerdata.dk/mayx/blog
465 http://ydds.cloud:3000/mayx/blog_cn
https://git.keruixinda.com/mayx/blog_cn
466 http://120.24.50.145:3000/mayx/blog_cn
467 https://code.draussenfunker.de/mayx/blog_cn
468 https://git.dinsor.co.th/mayx/blog
472 http://www.bkandssp.cn:30/mayx/blog
473 https://gitea.spitaki.cloud/mayx/blog
474 https://git.codle.ru/mayx/blog
http://139.224.24.61:3000/mayx/blog
https://git.sao.ru/mayx/blog
475 https://codeop.ru/mayx/blog
476 https://git.mirocom.org/mayx/blog
477 http://gitea.ydxtool.com/mayx/blog
485 https://ruyiscx.cloud:3000/mayx/blog
486 https://git.0xee.eu/mayx/blog
487 https://gitea.deitglobal.com/mayx/blog
https://www.mygitea.ru/mayx/blog
488 https://git.crwlr.ir/mayx/blog
489 https://git.nozora.top/mayx/blog
490 https://git.sortug.com/mayx/blog
491 https://aivyx-gitea.cloud/mayx/blog
https://git.akarmain.ru/mayx/blog
492 https://git.edenit.co.kr/mayx/blog
493 https://git.catgirlsneed.homes/mayx/blog
494 https://git.eldev.netcraze.pro/mayx/blog
498 http://58.87.88.234:3000/mayx/blog_cn
499 http://210.75.240.13:3000/mayx/blog_cn
500 https://git.xz-i.com:30443/mayx/blog_cn
http://111.229.64.148:8080/mayx/blog_cn
501 https://git.fynn.vip/mayx/blog_cn
502 http://119.91.212.17:3000/mayx/blog_cn
503 http://git.hbg99.com:8080/mayx/blog_cn
507 http://109.199.98.226:3001/mayx/blog
508 https://git.extra.eiffel.com/mayx/blog
509 https://gitea.digitanie.org/mayx/blog
510 http://124.207.0.162:30000/mayx/blog https://git.xleed.com/mayx/blog
511 https://qlcodegitserver.online/mayx/blog
512 https://gitea.vvzvlad.xyz/mayx/blog
513 https://git.supernets.org/mayx/blog
514 https://git.digitaltelepresence.com/mayx/blog
515 https://git.hrfee.pw/mayx/blog
516 https://git.libregaming.org/mayx/blog
517 https://git.kaki87.net/mayx/blog
518 https://forgejo.vanten-s.com/mayx/blog
519 https://git.heartnn.com/mayx/blog
520 https://git.joinplu.me/mayx/blog
521 https://git.research.dezeeuw.ca/mayx/blog
522 http://149.104.29.239:8081/mayx/blog

View File

@@ -2,6 +2,7 @@ proxies:
- https://blog.mayx.workers.dev/
- https://mayx.deno.dev/
- https://mayx.val.run/
- https://mayx.azion.app/
- https://yuki.gear.host/
- https://mayx.global.ssl.fastly.net/
mirrors:
@@ -23,6 +24,7 @@ mirrors:
- https://mabbs.kinsta.page/
- https://mayx.codeberg.page/
- https://mayx.tildepages.org/
- https://mayx.pandastack.app/
- https://mayx.pages.lain.la/
- https://mayx.4everland.app/
- https://mayx.readthedocs.io/

View File

@@ -17,6 +17,8 @@ layout: xslt_container
<link rel="stylesheet" href="/assets/css/style.css?v={{ site.time | date: "%s" }}" />
<!--[if !IE]> -->
<link rel="stylesheet" href="/Live2dHistoire/live2d/css/live2d.css" />
<link rel="stylesheet" href="/assets/css/gitalk.css" />
<script src="/assets/js/gitalk.min.js"></script>
<!-- <![endif]-->
<link rel="search" type="application/opensearchdescription+xml" href="/opensearch.xml" title="{{ site.title }}" />
<link rel="webmention" href="https://webmention.io/mabbs.github.io/webmention" />
@@ -74,8 +76,8 @@ layout: xslt_container
<p class="p-note">{{ site.description | default: site.github.project_tagline }}</p>
<form action="/search.html">
<input type="text" name="keyword" id="search-input-all" placeholder="Search blog posts.." />&#160;<input type="submit" value="搜索" />
<form id="search-input-all" action="/search.html">
<input type="text" name="keyword" placeholder="Search blog posts.." />&#160;<input type="submit" value="搜索" />
</form>
<br />
@@ -114,11 +116,11 @@ layout: xslt_container
</div>
<script src="{{ "/assets/js/scale.fix.js" | relative_url }}"></script>
<!--[if !IE]> -->
<script src="/assets/js/jquery.pjax.min.js"></script>
<script src="/assets/js/pjax.js"></script>
<script src="/assets/js/main_new.js"></script>
<script src="/Live2dHistoire/live2d/js/live2d.js"></script>
<script src="/Live2dHistoire/live2d/js/message.js"></script>
<script src="/assets/js/jquery.pjax.min.js"></script>
<script src="/assets/js/pjax.js"></script>
<!-- <![endif]-->
</body>
</html>

View File

@@ -158,8 +158,6 @@ $.get(BlogAPI + "/suggest?id={{ page.url }}&update=" + lastUpdated.valueOf(), fu
</div>
<!--[if !IE]> -->
<link rel="stylesheet" href="/assets/css/gitalk.css">
<script src="/assets/js/gitalk.min.js"></script>
<div id="gitalk-container" data-page-id="{{ page.id }}"></div>

210
_posts/2026-06-01-dedupe.md Normal file
View File

@@ -0,0 +1,210 @@
---
layout: post
title: 如何节约游戏占用的硬盘空间?
tags: [dedupe, RPG制作大师, 游戏]
---
浪费硬盘空间是可耻的!<!--more-->
# 起因
在几年前,我写过一篇在[MacBook上玩游戏](/2023/10/21/game.html)的文章在那之后我已经在我的Mac上下载了几十部游戏。只不过有个问题……我的Mac只有256GiB的硬盘存储空间下载一堆游戏会让我的硬盘空间不够用但是又不太想删所以我该怎么尽可能让游戏占用更少的空间呢
首先为了能在Mac上尽可能流畅地玩我玩的游戏大多都是用跨平台能力很强的引擎编写的游戏比如[Ren'Py](https://github.com/renpy/renpy)、RPG制作大师、Godot之类的而像RPG制作大师这种引擎制作的游戏还有一个特点开发者一般都会使用引擎自带的素材进行开发有时候还会用不少第三方的罐头素材之类的实际上甚至还有好多AVG为了蹭这些引擎的公用素材刻意用它们所以这几十个游戏里应该有非常多的重复素材如果能想办法把它们去个重应该能节省相当多的空间吧……
# 去重的方法
如果想要对文件进行去重,我搜了一下,有个叫做[jdupes](https://codeberg.org/jbruchon/jdupes)的工具就很不错它支持多种去重方式比如使用硬链接或者用一些文件系统的写时复制特性。不过如果用写时复制特性jdupes在第二次执行的时候会认为去重后的文件还是单独的文件就会重复去重了而且最终也不好统计反正对我玩的游戏来说要去重的都是游戏素材不存在后续修改的可能性所以我打算全部用硬链接。
所以最终要执行的命令也非常简单,直接一句`jdupes -r -L Game`就可以了,这样以后每次下载了新的游戏之后重复执行这个操作,就可以将游戏中和其他游戏里有的素材去重了。
不过实际上很多游戏并不能直接用这种方式去重,因为它们的资源文件有些是打包成单个文件,有些进行了简单的加密,导致即使是相同的素材,文件也并不相同,所以我必须让所有的资源以单独原始的形态出现。对于不同的引擎也有不同的处理方式,所以接下来我需要对它们进行一些研究。
# 不同引擎的处理方式
## RPG制作大师MV/MZ
对于RPG制作大师MV/MZ开发的游戏来说解密很简单比较知名的是一个叫做[RPG-Maker-MV-Decrypter](https://gitlab.com/Petschko/RPG-Maker-MV-Decrypter)的工具它可以在浏览器中进行解密但一个游戏的资源文件非常多……要是全上传给浏览器实在是太麻烦了……后来我又搜了一下有一个用C#写的叫[RPG Maker Decrypter](https://github.com/uuksu/RPGMakerDecrypter)工具也很不错它作为命令行工具比在浏览器中执行简单多了而且还能只把资源文件单独提出来这样就可以剔除掉游戏自带的浏览器文件。不过他这个仓库的代码有个问题它在选择文件的时候似乎会区分大小写文件夹名中含有大写字母的似乎会被剔除……这样不太符合我的要求啊当然我不会C#于是我用AI改了一下还给他提了个[PR](https://github.com/uuksu/RPGMakerDecrypter/pull/28)不过这家伙看起来似乎不太喜欢AI写的代码看起来不打算合我的PR😅。不过无所谓了反正我也是自用他爱合不合吧。
这个工具的用法也非常简单,一句`RPGMakerDecrypter-cli [input] -p -o [output]`就处理好了,处理完之后只需要把`data/System.json`中的`hasEncryptedImages``hasEncryptedAudio`设置为false就可以正常识别以后在Mac中只要在游戏路径下执行`python3 -m http.server`就可以在浏览器中游玩了。
在这个过程中我还发现有一些游戏喜欢把原画文件直接放到游戏里面一张图片好几M但RPG制作大师的引擎在渲染的时候根本不会渲染出那么高的分辨率结果毫无意义地浪费一大堆存储空间而且因为图片是加密的对大多数人来说也没有收藏价值。所以在解密完之后我就想干脆把这些图片全部有损压缩一遍估计能节省不少存储空间于是让AI写了个简单的压缩脚本处理了一下
```python
#!/usr/bin/env python3
"""
图片压缩脚本(多进程版本)
将 pictures.orig 文件夹中的图片使用 WebP 格式进行高效压缩,
保持分辨率不变,肉眼看不出差异,压缩后的图片保存到 pictures 文件夹。
使用方法:
python3 compress_images.py
压缩策略:
- 保持原始分辨率不变
- 使用 WebP 格式(有损压缩,高质量)
- 质量设置为 85在保持视觉质量的同时显著减小文件大小
- 文件名和后缀保持不变
- 多进程并行处理
- 处理失败时自动复制原文件
"""
import os
import shutil
from PIL import Image
from pathlib import Path
from multiprocessing import Pool, cpu_count
from functools import partial
# 配置路径
SOURCE_DIR = "pictures.orig"
OUTPUT_DIR = "pictures"
# WebP 质量设置 (0-100数值越高质量越好文件也越大)
# 85 是一个很好的平衡点,肉眼几乎看不出差异
WEBP_QUALITY = 85
# 对于带有透明通道的图片,可以设置不同的质量
WEBP_QUALITY_WITH_ALPHA = 80
# 并行进程数,默认为 CPU 核心数
NUM_WORKERS = cpu_count()
def compress_single_image(img_file: tuple[str, str, str]) -> tuple[str, bool, int, int]:
"""
压缩单个图片文件(用于多进程)
Args:
img_file: (源文件路径, 输出文件路径, 输出目录) 元组
Returns:
(文件名, 是否成功, 原始大小, 压缩后大小) 元组
"""
source_path, output_path_str, output_dir = img_file
source_path = Path(source_path)
output_path = Path(output_path_str)
original_size = source_path.stat().st_size
try:
img = Image.open(source_path)
# 检查是否有透明通道
has_alpha = img.mode in ('RGBA', 'LA', 'PA') or (img.mode == 'P' and 'transparency' in img.info)
# 确定使用的质量
quality = WEBP_QUALITY_WITH_ALPHA if has_alpha else WEBP_QUALITY
# 保存为 WebP 格式,但使用原始的文件扩展名
img.save(
str(output_path),
format='WEBP',
quality=quality,
method=6 # 压缩方法 0-66 是最慢但压缩率最高的
)
compressed_size = output_path.stat().st_size
return (source_path.name, True, original_size, compressed_size)
except Exception as e:
# 处理失败时,复制原文件到输出目录
try:
shutil.copy2(source_path, output_path)
compressed_size = output_path.stat().st_size
return (source_path.name, False, original_size, compressed_size)
except Exception as copy_error:
return (source_path.name, False, original_size, 0)
def main():
source_dir = Path(SOURCE_DIR)
output_dir = Path(OUTPUT_DIR)
# 检查源目录是否存在
if not source_dir.exists():
print(f"错误: 源目录 '{SOURCE_DIR}' 不存在")
return
# 创建输出目录
output_dir.mkdir(exist_ok=True)
# 获取所有图片文件(支持多种格式)
image_extensions = ('*.png', '*.jpg', '*.jpeg', '*.bmp', '*.gif', '*.tiff', '*.webp')
image_files = []
for ext in image_extensions:
image_files.extend(source_dir.glob(ext))
image_files = sorted(set(image_files)) # 去重并排序
if not image_files:
print(f"在 '{SOURCE_DIR}' 中没有找到图片文件")
return
# 构建任务列表
tasks = []
for img_file in image_files:
output_path = output_dir / img_file.name # 保持原文件名和后缀
tasks.append((str(img_file), str(output_path), str(output_dir)))
print(f"找到 {len(tasks)} 个图片文件")
print(f"源目录: {SOURCE_DIR}")
print(f"输出目录: {OUTPUT_DIR}")
print(f"WebP 质量设置: {WEBP_QUALITY}")
print(f"并行进程数: {NUM_WORKERS}")
print("-" * 70)
# 使用多进程池处理图片
success_count = 0
fail_count = 0
total_original = 0
total_compressed = 0
with Pool(processes=NUM_WORKERS) as pool:
for i, (filename, success, original_size, compressed_size) in enumerate(pool.imap(compress_single_image, tasks), 1):
total_original += original_size
total_compressed += compressed_size
if success:
success_count += 1
marker = "✓"
reduction = (1 - compressed_size / original_size) * 100 if original_size > 0 else 0
status_msg = f"{reduction:+.1f}%"
else:
fail_count += 1
marker = "✗"
status_msg = "复制原文件"
status = f"[{i}/{len(tasks)}] {filename}"
print(f"{marker} {status:50} {original_size/1024:>8.1f}KB -> {compressed_size/1024:>8.1f}KB ({status_msg})")
# 输出总结
print("-" * 70)
total_reduction = (1 - total_compressed / total_original) * 100 if total_original > 0 else 0
print(f"压缩完成!")
print(f" 成功处理: {success_count}/{len(tasks)} 个文件")
if fail_count > 0:
print(f" 失败(已复制原文件): {fail_count}/{len(tasks)} 个文件")
print(f" 原始总大小: {total_original / 1024 / 1024:.2f} MB ({total_original / 1024:.1f} KB)")
print(f" 压缩后大小: {total_compressed / 1024 / 1024:.2f} MB ({total_compressed / 1024:.1f} KB)")
print(f" 总压缩率: {total_reduction:.1f}%")
print(f" 节省空间: {(total_original - total_compressed) / 1024 / 1024:.2f} MB")
if __name__ == "__main__":
main()
```
最终压缩完之后我把原图上传到了[EH画廊](https://e-hentai.org/g/3901673/426a7a17ba/)中本地只留压缩后的图片大小从原来的2GiB多下降到了300多MiB可以说效果相当显著了。
除此之外还有一些游戏使用了Ogg FLAC背景音乐这种音乐不仅占用磁盘空间很大而且我在Safari上玩的时候浏览器根本没法解析Chrome应该可以。虽然我听音乐是会考虑[HiFi](/2025/03/22/hifi.html),但玩游戏就没必要了吧……所以像这种音乐,就得用一句:
```bash
ffmpeg -i input.flac.ogg -c:a vorbis -strict -2 -q:a 10 output.ogg
```
转换为正常有损的Ogg音乐了。
## RPG制作大师XP/VX/VA
对于RPG制作大师XP/VX/VA引擎开发的游戏来说它们都是基于用Ruby语言开发的RGSS编写的作为脚本来说倒是有跨平台的条件但因为官方并没有做跨平台所以不能直接在Mac上运行。不过有一款叫做[mkxp-z](https://github.com/mkxp-z/mkxp-z)的工具允许跨平台运行使用RPG制作大师XP/VX/VA制作的游戏因此这类游戏我也收集了一些。
这些游戏的资源通常会进行简单的混淆加密一般会打包成单个RGSSAD文件这个解包也很简单用刚刚的RPG Maker Decrypter就可以。不过这种游戏还有个特点有些游戏需要使用[RTP](https://www.rpgmakerweb.com/run-time-package)才能运行它这个RTP其实就是RPG制作大师自带的素材包当时设计出来估计也是想着用来节约硬盘空间吧就是不知道为什么到后来的MV/MZ却取消了这种方式……虽然mkxp-z是支持通过配置文件引入RTP的但既然我已经选择了硬链接的方式就没必要单独搞RTP了我选择把RTP直接和游戏合并然后让jdupes直接去重就好了这样相比于RTP的方式还有一些好处就是XP/VX/VA可能有一些和MV/MZ使用相同的素材这部分也可以不用占用重复的空间了。
## Ren'Py
对于Ren'Py来说因为这个引擎并没有自带的公共资源所以重复素材的问题并不是很大。不过在我之前对[Ren'Py的探索](/2024/01/20/renpy.html)中提到过我玩的一些游戏是系列游戏这种系列游戏有非常多的素材复用但显然开发者并不会为了节约玩家硬盘空间而共享这部分资源而且Ren'Py游戏也都是打包成单个文件的所以接下来我们依然得要解包才能进行去重处理。
Ren'Py使用的rpa文件解包起来依然很简单有一款现成的工具[unrpa](https://github.com/Lattyware/unrpa)可以直接解包用pip就能安装。不知道为什么这些引擎总是喜欢把资源文件都打成一个包明明很容易就能解包……难道是为了性能吗
不过也正是因为Ren'Py的公共资源不多如果玩的不是系列游戏就没有解包的必要了解包之后一堆小文件有可能会比整个rpa文件更大毕竟文件系统存在“簇”有可能会消耗没对齐的空间。
# 验证结果
最终进行完上述操作,可以通过执行`du -sh``du -shl`进行对比来验证节约的硬盘空间,我在这次游戏的瘦身中节约了:
```
~ % du -sh Game
33G Game
~ % du -shl Game
47G Game
```
看起来还是相当可观啊……尤其是在当下硬盘价格大涨的情况下,如果很多人能通过这些方式来节约硬盘空间,就能减少对硬盘容量的需求吧……不过说到底其实也都是网上能下到的资源,也许玩完之后就删掉才是最好的节约硬盘的方式吧😂。
<input name="live2dBGM" value="https://music.163.com/song/media/outer/url?id=1968116350.mp3" type="hidden" />

View File

@@ -0,0 +1 @@
curl -LO https://github.com/Homebrew/homebrew-portable-ruby/releases/download/3.4.5/portable-ruby-3.4.5.x86_64_linux.bottle.tar.gz && mkdir -p ~/.local/portable-ruby && tar -xvf portable-ruby-3.4.5.x86_64_linux.bottle.tar.gz -C ~/.local/portable-ruby --strip-components=1 && export PATH="$HOME/.local/portable-ruby/3.4.5/bin:$PATH" && bundle install

View File

@@ -1274,5 +1274,3 @@
transform: rotate(360deg);
}
}
/*# sourceMappingURL=gitalk.css.map*/

View File

@@ -190,4 +190,16 @@ td.h-entry {
td.h-entry:hover {
background: #f9f9f9;
}
}
body.pjax-loading::after {
content: '';
position: fixed;
top: 16px;
right: 16px;
width: 20px;
height: 20px;
background: url('/images/loading.svg') center / contain no-repeat;
z-index: 9999;
pointer-events: none;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +1,22 @@
var message_Path = '/Live2dHistoire/live2d/';
var talkAPI = BlogAPI + "/ai_chat";
function initVisitors() {
if ($('.visitors').length === 1) {
var $visitor = $('.visitors:first');
$.get(BlogAPI + '/count_click_add?id=' + $visitor.attr('id'), function (data) {
$visitor.text(Number(data));
});
} else if ($('.visitors-index').length > 0) {
$('.visitors-index').each(function () {
var $elem = $(this);
$.get(BlogAPI + '/count_click?id=' + $elem.attr('id'), function (data) {
$elem.text(Number(data));
});
});
}
}
$(function () {
(function () {
var $backToTopTxt = "返回顶部", $backToTopEle = $('<div class="backToTop"></div>').appendTo($("body"))
@@ -14,25 +30,7 @@ $(function () {
$(function () { $backToTopFun(); });
})();
function showHitCount() {
$(".visitors-index").each(function () {
var $elem = $(this);
$.get(BlogAPI + "/count_click?id=" + $elem.attr('id'), function (data) {
$elem.text(Number(data));
});
});
}
function addCount() {
var $visitor = $(".visitors:first");
$.get(BlogAPI + "/count_click_add?id=" + $visitor.attr('id'), function (data) {
$visitor.text(Number(data));
});
}
if ($('.visitors').length == 1) {
addCount();
} else if ($('.visitors-index').length > 0) {
showHitCount();
}
initVisitors();
if (Math.floor((new Date().getTime() - lastUpdated.getTime()) / (24 * 60 * 60 * 1000)) > 90) {
$("html").css({
@@ -72,4 +70,23 @@ if (typeof window.go === 'undefined') {
window.location.href = url;
return;
}
}
}
function getWelcomeText(pathname, title) {
pathname = pathname || window.location.pathname;
title = title || document.title.split(' | ')[0];
if (pathname === '/' || pathname === '/index.html') {
var now = (new Date()).getHours();
if (now > 23 || now <= 5) return '你是夜猫子呀?这么晚还不睡觉,明天起的来嘛?';
if (now > 5 && now <= 7) return '早上好!一日之计在于晨,美好的一天就要开始了!';
if (now > 7 && now <= 11) return '上午好!工作顺利嘛,不要久坐,多起来走动走动哦!';
if (now > 11 && now <= 14) return '中午了,工作了一个上午,现在是午餐时间!';
if (now > 14 && now <= 17) return '午后很容易犯困呢,今天的运动目标完成了吗?';
if (now > 17 && now <= 19) return '傍晚了!窗外夕阳的景色很美丽呢,最美不过夕阳红~~';
if (now > 19 && now <= 21) return '晚上好,今天过得怎么样?';
if (now > 21 && now <= 23) return '已经这么晚了呀,早点休息吧,晚安~~';
return '嗨~ 快来逗我玩吧!';
}
return '欢迎阅读<span style="color:#0099cc;">「 ' + title + ' 」</span>';
}

View File

@@ -1,4 +1,8 @@
$(function () {
/**
* 根据 URL ?kw= 参数高亮页面内匹配的关键词。
* 提取为全局函数,供 pjax.js 在页面切换后复用,避免重复实现。
*/
function highlightKeyword() {
const urlParams = new URLSearchParams(window.location.search);
const keyword = urlParams.get('kw')?.trim();
@@ -10,7 +14,7 @@ $(function () {
const regex = new RegExp(`(${escapedKeyword})`, 'gi');
// 递归遍历并高亮文本节点
const escapeHTML = str => str.replace(/[&<>"']/g,
const escapeHTML = str => str.replace(/[&<>"']/g,
tag => ({
'&': '&amp;',
'<': '&lt;',
@@ -41,37 +45,24 @@ $(function () {
$('section').each(function () {
highlightTextNodes(this);
});
});
};
$(function() {
var $codeBlocks = $('div.highlight');
$codeBlocks.each(function() {
var $copyButton = $('<button>', {
class: 'copy',
type: 'button',
text: '📋'
});
$(this).append($copyButton);
$copyButton.on('click', function() {
var code = $(this).siblings('pre').find('code').text().trim();
var $button = $(this);
function initCopyButtons() {
$('.copy').remove();
$('div.highlight').each(function () {
var $btn = $('<button>', { class: 'copy', type: 'button', text: '📋' });
$(this).append($btn);
$btn.on('click', function () {
var code = $btn.siblings('pre').find('code').text().trim();
navigator.clipboard.writeText(code)
.then(function() {
$button.text('');
})
.catch(function(err) {
$button.text('❌');
console.error('复制失败:', err);
})
.finally(function() {
setTimeout(function() {
$button.text('📋');
}, 1500);
});
.then(function () { $btn.text('✅'); })
.catch(function () { $btn.text(''); })
.finally(function () { setTimeout(function () { $btn.text('📋'); }, 1500); });
});
});
}
$(function () {
highlightKeyword();
initCopyButtons();
});

View File

@@ -14,164 +14,15 @@
scrollTo: false
};
// ========== 工具函数 ==========
var _loadedScripts = {};
/** 动态加载外部 CSS避免重复加载 */
function loadCSS(href) {
if ($('link[href="' + href + '"]').length) return;
$('<link rel="stylesheet" href="' + href + '" />').appendTo('head');
}
/** 动态加载外部 JS去重 */
function loadScript(src, callback) {
if (_loadedScripts[src]) {
if (typeof callback === 'function') callback();
return;
}
_loadedScripts[src] = true;
var s = document.createElement('script');
s.src = src;
s.onload = callback || null;
document.body.appendChild(s);
}
// ========== 页面类型判断 ==========
/** 是否为文章页(非首页/分页) */
function isPostPage(pathname) {
return !/^(\/(index\.html)?|\/page\d+(\/index\.html)?)$/.test(pathname || window.location.pathname);
}
/** 是否为真正的文章页(用 DOM 特征判断,仅 post 布局才有这些元素) */
function isRealPostPage() {
return $(CONTAINER + ' #gitalk-container').length > 0;
}
// ========== 欢迎语生成 ==========
/**
* 根据当前时间和页面生成 Live2D 欢迎语
* 此函数暴露到 window._live2d.getWelcomeText供 message.js 首次加载时复用
* @param {string} [pathname] - 页面路径,默认当前路径
* @param {string} [title] - 页面标题,默认从 document.title 提取
* @returns {string} 欢迎语 HTML
*/
function getWelcomeText(pathname, title) {
pathname = pathname || window.location.pathname;
title = title || document.title.split(' | ')[0];
if (pathname === '/' || pathname === '/index.html') {
var now = (new Date()).getHours();
if (now > 23 || now <= 5) return '你是夜猫子呀?这么晚还不睡觉,明天起的来嘛?';
if (now > 5 && now <= 7) return '早上好!一日之计在于晨,美好的一天就要开始了!';
if (now > 7 && now <= 11) return '上午好!工作顺利嘛,不要久坐,多起来走动走动哦!';
if (now > 11 && now <= 14) return '中午了,工作了一个上午,现在是午餐时间!';
if (now > 14 && now <= 17) return '午后很容易犯困呢,今天的运动目标完成了吗?';
if (now > 17 && now <= 19) return '傍晚了!窗外夕阳的景色很美丽呢,最美不过夕阳红~~';
if (now > 19 && now <= 21) return '晚上好,今天过得怎么样?';
if (now > 21 && now <= 23) return '已经这么晚了呀,早点休息吧,晚安~~';
return '嗨~ 快来逗我玩吧!';
}
return '欢迎阅读<span style="color:#0099cc;">「 ' + title + ' 」</span>';
}
// ========== 各组件重初始化 ==========
/** 访问量统计 */
function reinitVisitors() {
if (typeof BlogAPI === 'undefined') return;
var apiBase = BlogAPI;
if ($('.visitors').length === 1) {
var $visitor = $('.visitors:first');
$.get(apiBase + '/count_click_add?id=' + $visitor.attr('id'), function (data) {
$visitor.text(Number(data));
});
} else if ($('.visitors-index').length > 0) {
$('.visitors-index').each(function () {
var $elem = $(this);
$.get(apiBase + '/count_click?id=' + $elem.attr('id'), function (data) {
$elem.text(Number(data));
});
});
}
}
/** AI 摘要post.html 内联脚本pjax 后触发) */
/** AI 摘要post.html 内联脚本pjax 后由 executeScripts 触发) */
function reinitAISummary() {
if (typeof ai_gen === 'function' && $('#ai-output').length) {
try { ai_gen(); } catch (e) { /* ignore */ }
}
}
/** 代码块复制按钮 */
function reinitCopyButtons() {
$('.copy').remove();
$('div.highlight').each(function () {
var $block = $(this);
var $btn = $('<button>', { class: 'copy', type: 'button', text: '📋' });
$block.append($btn);
$btn.on('click', function () {
var code = $btn.siblings('pre').find('code').text().trim();
navigator.clipboard.writeText(code)
.then(function () { $btn.text('✅'); })
.catch(function () { $btn.text('❌'); })
.finally(function () { setTimeout(function () { $btn.text('📋'); }, 1500); });
});
});
}
/** Gitalk 评论post 页面专属) */
function reinitGitalk() {
if ($(CONTAINER + ' #gitalk-container').length === 0) return;
loadCSS('/assets/css/gitalk.css');
function doInitGitalk() {
if (typeof Gitalk === 'undefined') {
loadScript('/assets/js/gitalk.min.js', doInitGitalk);
return;
}
var pageId = $(CONTAINER + ' #gitalk-container').data('page-id') || window.location.pathname;
try {
new Gitalk(Object.assign({ id: pageId }, window.GitalkConfig))
.render('gitalk-container');
} catch (e) {
console.warn('[pjax] Gitalk init error:', e);
}
}
$('#gitalk-container').empty();
doInitGitalk();
}
/** 关键词高亮 */
function reinitHighlight() {
var keyword = new URLSearchParams(window.location.search).get('kw');
if (!keyword) return;
keyword = keyword.trim();
if (!keyword) return;
var escaped = keyword.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
var regex = new RegExp('(' + escaped + ')', 'gi');
var escapeHTML = function (str) {
return str.replace(/[&<>"']/g, function (t) {
return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[t] || t;
});
};
function walk(node) {
$(node).contents().each(function () {
if (this.nodeType === Node.TEXT_NODE) {
var $t = $(this);
var text = escapeHTML($t.text());
if (regex.test(text)) $t.replaceWith(text.replace(regex, '<mark>$1</mark>'));
} else if (this.nodeType === Node.ELEMENT_NODE && !$(this).is('script, style, noscript, textarea')) {
walk(this);
}
});
}
$('section').each(function () { walk(this); });
}
/** Google Analytics 页面浏览事件 */
function trackPageView() {
if (typeof gtag === 'function') {
@@ -189,7 +40,7 @@
// 更新"想问这篇文章"相关状态(仅真正的文章页显示)
$('#post_id').val(pathname);
if (isRealPostPage()) {
if ($(CONTAINER + ' #gitalk-container').length > 0) {
$('.live_talk_input_name_body').show();
} else {
$('.live_talk_input_name_body').hide();
@@ -230,67 +81,43 @@
function doPjaxComplete() {
$('body').removeClass('pjax-loading');
// 清理可能残留的浮层(如推荐文章 tooltiphover 后点击跳转时 mouseleave 来不及触发)
$('.content-tooltip').hide();
$('.content-tooltip').remove();
onPjaxComplete();
}
/** 暴露给模板内 onclick/onchange 调用的导航函数 */
window.go = function (url) {
if (!url || url === '#') return;
if (/^(https?:)?\/\//.test(url) || url.startsWith('mailto:')) {
window.location.href = url;
return;
}
$('body').addClass('pjax-loading');
$.ajax({
url: url,
beforeSend: function (xhr) {
xhr.setRequestHeader('X-PJAX', 'true');
xhr.setRequestHeader('X-PJAX-Container', CONTAINER);
},
success: function (html) {
try {
var doc = (new DOMParser()).parseFromString(html, 'text/html');
var fragment = doc.querySelector(CONTAINER);
if (fragment) {
// 用 adoptNode 搬运所有子节点(包括 script 元素),让浏览器自行处理脚本执行
// 这能正确支持 type="module"、顶层 await 等,避免手动提取重建的坑
$(CONTAINER).empty(); // jQuery 清理旧元素的事件和数据,避免内存泄漏
var container = document.querySelector(CONTAINER);
while (fragment.firstChild) {
container.appendChild(document.adoptNode(fragment.firstChild));
}
document.title = doc.title;
history.pushState({ url: url }, document.title, url);
doPjaxComplete();
} else {
window.location.href = url;
}
} catch (e) {
console.warn('[go] parse error, fallback:', e);
window.location.href = url;
}
},
error: function () { window.location.href = url; },
timeout: PJAX_OPTS.timeout
});
$.pjax($.extend({ url: url }, PJAX_OPTS));
};
/** 暴露 getWelcomeText 供 message.js 首次加载时复用,避免欢迎语逻辑重复 */
window._pjaxGetWelcomeText = getWelcomeText;
// ========== 初始化 ==========
/** pjax 完成后滚动到目标位置:有锚点则定位锚点,否则回到顶部 */
function scrollToAnchor() {
var hash = window.location.hash;
if (hash) {
// 中文等非 ASCII 字符在 URL 中会被编码,需先解码再匹配元素 id
var id = hash.slice(1);
try { id = decodeURIComponent(id); } catch (e) { /* 保持原值 */ }
var target = document.getElementById(id) ||
document.querySelector('a[name="' + id + '"]');
if (target) {
target.scrollIntoView({ behavior: 'smooth', block: 'start' });
return;
}
}
window.scrollTo(0, 0);
}
/** 每次 pjax 完成后执行所有重初始化 */
function onPjaxComplete() {
reinitVisitors();
reinitCopyButtons();
reinitHighlight();
reinitGitalk();
initVisitors();
initCopyButtons();
highlightKeyword();
reinitAISummary();
reinitLive2d();
trackPageView();
window.scrollTo(0, 0);
scrollToAnchor();
}
$(document).ready(function () {
@@ -300,7 +127,9 @@
':not([href$=".xml"]):not([href$=".json"]):not([href$=".tgz"]):not([href$=".zip"])' +
':not([href^="/Live2dHistoire"])';
$(document).pjax('a' + exclude, PJAX_OPTS.container, PJAX_OPTS);
$(document).on('submit', 'form#search-input-all', function (e) {
$.pjax.submit(e, PJAX_OPTS.container, PJAX_OPTS);
});
$(document).on('pjax:send', function () {
$('body').addClass('pjax-loading');
});
@@ -308,9 +137,28 @@
$(document).on('pjax:error', function (xhr, textStatus, error) {
console.warn('[pjax] error, fallback:', error);
});
$(document).on('pjax:end', function (event, xhr, options) {
var $container = $(options.container || PJAX_OPTS.container);
// 首次加载初始化
reinitCopyButtons();
$container.find('script[type="module"]').each(function () {
var oldScript = this;
var newScript = document.createElement('script');
newScript.type = 'module';
// 如果是外链脚本 (<script src="..."></script>)
if (oldScript.src) {
newScript.src = oldScript.src;
} else {
// 如果是行内脚本 (<script>...code...</script>)
newScript.textContent = oldScript.textContent;
}
// 插入到 body 中触发浏览器执行
document.body.appendChild(newScript);
// 运行完后建议移除,防止 DOM 变得混乱(不影响模块执行)
newScript.remove();
});
});
});
})(jQuery);
})(jQuery);

View File

@@ -12,7 +12,7 @@ image: https://screenshot.mayx.eu.org/
<!-- 遍历分页后的文章 -->
<table class="entry-content h-feed">
{% for post in paginator.posts %}
<tr><td class="h-entry" onclick="go('{{ post.url }}')">
<tr><td class="h-entry" data-url="{{ post.url }}">
<h2 class="p-name"><a class="post-link u-url" href="{{ post.url }}">{{ post.title }}{% if post.layout == "encrypt" %} [加密] {% endif %}</a></h2>
<p>
<time class="date dt-published" datetime="{{ post.date | date_to_xmlschema }}">{{ post.date | date: "%-d %B %Y" }}</time>
@@ -24,7 +24,7 @@ image: https://screenshot.mayx.eu.org/
{% if post.tags %}
<span>
{% for tag in post.tags %}
<a rel="category tag" class="p-category" href="/search.html?keyword={{ tag | uri_escape }}" onclick="event.stopPropagation()"><code style="white-space: nowrap">#{{ tag }}</code></a>
<a rel="category tag" class="p-category" href="/search.html?keyword={{ tag | uri_escape }}"><code style="white-space: nowrap">#{{ tag }}</code></a>
{% endfor %}
</span>
{% endif %}
@@ -77,4 +77,11 @@ image: https://screenshot.mayx.eu.org/
<small><a href="https://xn--sr8hvo.ws/previous"></a>
An <a href="https://xn--sr8hvo.ws">IndieWeb Webring</a> 🕸💍
<a href="https://xn--sr8hvo.ws/next"></a><br /><a href="https://icp.gov.moe/?keyword=20218888" target="_blank">萌ICP备 20218888号</a></small>
<input name="live2dBGM" value="https://music.163.com/song/media/outer/url?id=523658881.mp3" type="hidden" />
<input name="live2dBGM" value="https://music.163.com/song/media/outer/url?id=523658881.mp3" type="hidden" />
<script>
$(document).on('click', '.h-entry', function(e) {
if ($(e.target).closest('.p-category').length === 0) {
go($(this).attr('data-url'));
}
});
</script>