JIGZEG.INFO
类目(7)
    标签(13)

      给博客加入游戏控制器操作功能

      发布


      大概在3年前得到了人生中第一个Xbox游戏手柄,随后它就一路陪伴了自己多年来的游戏时光。最近,自己花了几天时间研究了浏览器W3C关于 Gamepad (游戏控制器)的API规范文档,希望博客能够实现像游戏一样支持手柄操作,达到手柄基本替代键盘鼠标操作来浏览页面的效果。目前为止,已经对手头设备上安装的浏览器博客页面的手柄操作的兼容情况做了测试,暂时没发现什么问题。

      如果想要测试你的浏览器是否支持Gamepad的API,可以到博客“关于”页面,在页面底部点击“此客户端”选项查看。

      如果点击没有反应、或者没有显示 控制器:支持 等字样的话,说明你所使用的浏览器已经太过时,是时候该升级WebView内核或者更新你的浏览器了!(远在十多年前——2012年Gamepad API在Chrome21被支持 [1])。

      热键设计

      # 操作 控制器热键
      1 上滑 左摇杆向上翘起
      2 下滑 左摇杆向下翘起
      3 模拟按下Tab键 十字键右/左按下
      4 模拟点击目前聚焦的元素 右扳机键按下
      5 打开导航 右肩键按下
      6 回到页面顶部 左肩键+十字键左按下
      7 滑到页面底部 左肩键+十字键右按下
      8 上滑一页 十字键上按下
      9 下滑一页 十字键下按下
      10 打开控制器测试工具窗口 右菜单按钮按下
      11 收起热键提示 左菜单按钮按下

      这些按键组合在所有页面基本都适用,部分页面和功能弹窗的热键布局可能会有差异,目前的热键布局未来可能有所调整。当前场景热键提示可以通过按下左菜单键查看。

      控制器测试

      设备在连接手柄后,打开博客的任意界面,按下右菜单键,即可打开控制器测试弹窗,测试控制器的按钮:

      鼠标滚动切换手柄,在Chrome上navigator.getGamepads()会返回一个长度为4的数组,故最多支持4个控制器的连接和测试。测试窗口下,支持测试手柄的震动功能(扳机震动/手柄震动),如果手柄带有振动模块,但是点击“测试震动”无反应,很有可能是浏览器不支持,升级浏览器到最新版本即可。

      功能设计

      博客适配手柄操作是以替代键盘功能键方向去设计的:

      • 例如在浏览界面时可以将十字键的右方向键当作键盘的“Tab键”来使用,切换聚焦的元素,然后按下右扳机键相当于键盘按下“回车”或者“空格”触发元素的点击事件;
      • 左摇杆上下抬起,相当于按下键盘的上下方向键,滚动页面,根据摇杆翘起程度,分级加速滚动;
      • 十字键上下方向键,相当于键盘的PageUp/PageDown按钮,上滑/下滑一页;
      • 左扳机键+十字键左右方向键,相当于按下Home/End键,回到当前页面顶部/底部;
      • 按下右肩键可以快捷呼出菜单,选择切换跳转博客板块子页

      目前还不能在文本框键入文字,未来将考虑加入虚拟键盘输入文字功能。

      继续阅读…


      此文被收纳在#星碎札#类目下,被贴上了#Gamepad##博客#标签

      网络设备间带宽测试

      发布


      如果想要测试网络带宽性能,可以使用iperf这个工具。Iperf在使用时,分为服务端和客户端两部分,通过运行iperf命令,可以得到两个终端设备之间的网络带宽性能数据 [1]

      安装和使用

      Iperf3 是从头重写的 iperf,目的是创建一个更小、更简洁的代码库 [2],不同操作系统下都可以比较方便安装它:

      • Termux: pkg install iperf3
      • Ubuntu: apt install iperf3
      • MacOS: brew install iperf3
      • Windows: 在 https://files.budman.pw/ 下载解压iperf3二进制可执行文件

      完整的官网使用说明文档见此:https://iperf.fr/iperf-doc.php

      启动服务端

      iperf3 -s

      将会启动iperf3服务,默认监听端口5201

      开始测试

      iperf3 -c < 服务端IP地址 > -t 30

      在客户端运行上面的命令,终端命令行将显示从客户端到服务器的网络带宽,包括吞吐量、丢包等信息,测试时间30s。服务端的终端也会同时相应输出测试数据。

      如果想要将带宽速率单位展示为 MB/s 可以加上参数 -f M,例如:

      iperf3 -c 10.7.0.1 -t 30 -f M

      结果解读

      🟢 服务端 iperf3 -s -f M 输出:

      -----------------------------------------------------------
      Server listening on 5201 (test #1)
      -----------------------------------------------------------
      Accepted connection from 192.168.128.3, port 58816
      [  5] local 192.168.128.1 port 5201 connected to 192.168.128.3 port 58828
      [ ID] Interval           Transfer     Bitrate
      [  5]   0.00-1.00   sec   643 MBytes   641 MBytes/sec                  
      [  5]   1.00-2.00   sec   676 MBytes   677 MBytes/sec                  
      [  5]   2.00-3.00   sec   682 MBytes   682 MBytes/sec                  
      [  5]   3.00-4.00   sec   682 MBytes   683 MBytes/sec                  
      [  5]   4.00-5.00   sec   688 MBytes   686 MBytes/sec                  
      [  5]   5.00-6.00   sec   684 MBytes   684 MBytes/sec                  
      [  5]   6.00-7.00   sec   678 MBytes   679 MBytes/sec                  
      [  5]   7.00-8.00   sec   682 MBytes   682 MBytes/sec                  
      [  5]   8.00-9.00   sec   681 MBytes   681 MBytes/sec                  
      [  5]   9.00-10.00  sec   680 MBytes   681 MBytes/sec                  
      [  5]  10.00-11.00  sec   683 MBytes   683 MBytes/sec                  
      [  5]  11.00-12.00  sec   688 MBytes   687 MBytes/sec                  
      [  5]  12.00-13.00  sec   685 MBytes   686 MBytes/sec                  
      [  5]  13.00-14.00  sec   687 MBytes   684 MBytes/sec                  
      [  5]  14.00-15.00  sec   682 MBytes   684 MBytes/sec                  
      [  5]  15.00-16.00  sec   684 MBytes   683 MBytes/sec                  
      [  5]  16.00-17.00  sec   682 MBytes   682 MBytes/sec                  
      [  5]  17.00-18.00  sec   672 MBytes   671 MBytes/sec                  
      [  5]  18.00-19.00  sec   683 MBytes   682 MBytes/sec                  
      [  5]  19.00-20.00  sec   627 MBytes   629 MBytes/sec                  
      [  5]  20.00-21.00  sec   583 MBytes   581 MBytes/sec                  
      [  5]  21.00-22.00  sec   679 MBytes   679 MBytes/sec                  
      [  5]  22.00-23.00  sec   683 MBytes   684 MBytes/sec                  
      [  5]  23.00-24.00  sec   680 MBytes   682 MBytes/sec                  
      [  5]  24.00-25.00  sec   679 MBytes   679 MBytes/sec                  
      [  5]  25.00-26.00  sec   660 MBytes   661 MBytes/sec                  
      [  5]  26.00-27.00  sec   682 MBytes   680 MBytes/sec                  
      [  5]  27.00-28.00  sec   679 MBytes   680 MBytes/sec                  
      [  5]  28.00-29.00  sec   682 MBytes   681 MBytes/sec                  
      [  5]  29.00-30.00  sec   672 MBytes   671 MBytes/sec                  
      - - - - - - - - - - - - - - - - - - - - - - - - -
      [ ID] Interval           Transfer     Bitrate
      [  5]   0.00-30.00  sec  19.8 GBytes   674 MBytes/sec                  receiver
      -----------------------------------------------------------
      Server listening on 5201 (test #2)
      -----------------------------------------------------------

      可以看到服务端收到了IP地址为 192.168.128.3 设备的连接请求,往下就是测试的结果数据:第一列 [ID] 表示连接的流ID,第二列 Interval 表示测试时间间隔,第三列 Transfer 表示该时间段(1s)内传输的数据量(单位MB),第四列 Bitrate 表示此时间段的传输速率。再往下,就是在以上整个测试期间内的总体性能。

      🔴 客户端 运行命令 iperf3 -c 192.168.128.1 -t 30 -f M 输出:

      Connecting to host 192.168.128.1, port 5201
      [  5] local 192.168.128.3 port 58828 connected to 192.168.128.1 port 5201
      [ ID] Interval           Transfer     Bitrate         Retr  Cwnd
      [  5]   0.00-1.00   sec   653 MBytes   652 MBytes/sec  179   1.44 MBytes       
      [  5]   1.00-2.00   sec   674 MBytes   674 MBytes/sec    0   1.41 MBytes       
      [  5]   2.00-3.00   sec   682 MBytes   682 MBytes/sec    0   1.72 MBytes       
      [  5]   3.00-4.00   sec   676 MBytes   675 MBytes/sec   40   2.12 MBytes       
      [  5]   4.00-5.00   sec   690 MBytes   690 MBytes/sec  212   2.31 MBytes       
      [  5]   5.00-6.00   sec   681 MBytes   681 MBytes/sec    0   1.43 MBytes       
      [  5]   6.00-7.00   sec   677 MBytes   678 MBytes/sec   81   1.72 MBytes       
      [  5]   7.00-8.00   sec   681 MBytes   681 MBytes/sec   44   2.05 MBytes       
      [  5]   8.00-9.00   sec   674 MBytes   674 MBytes/sec    0   1.84 MBytes       
      [  5]   9.00-10.00  sec   678 MBytes   677 MBytes/sec    0   1.44 MBytes       
      [  5]  10.00-11.00  sec   687 MBytes   688 MBytes/sec    0   1.33 MBytes       
      [  5]  11.00-12.00  sec   680 MBytes   681 MBytes/sec    0   1.28 MBytes       
      [  5]  12.00-13.00  sec   686 MBytes   686 MBytes/sec    0   1.98 MBytes       
      [  5]  13.00-14.01  sec   679 MBytes   676 MBytes/sec    0   1.75 MBytes       
      [  5]  14.01-15.00  sec   679 MBytes   681 MBytes/sec   32   1.43 MBytes       
      [  5]  15.00-16.00  sec   684 MBytes   685 MBytes/sec    0   1.73 MBytes       
      [  5]  16.00-17.00  sec   684 MBytes   682 MBytes/sec   23   1.82 MBytes       
      [  5]  17.00-18.00  sec   672 MBytes   672 MBytes/sec    0   2.02 MBytes       
      [  5]  18.00-19.00  sec   679 MBytes   680 MBytes/sec    0   1.77 MBytes       
      [  5]  19.00-20.01  sec   629 MBytes   628 MBytes/sec    0   5.66 KBytes       
      [  5]  20.01-21.00  sec   578 MBytes   580 MBytes/sec   89   1.72 MBytes       
      [  5]  21.00-22.01  sec   681 MBytes   678 MBytes/sec    0   1.62 MBytes       
      [  5]  22.01-23.00  sec   675 MBytes   678 MBytes/sec    0   1.65 MBytes       
      [  5]  23.00-24.00  sec   681 MBytes   680 MBytes/sec    0   1.33 MBytes       
      [  5]  24.00-25.00  sec   672 MBytes   672 MBytes/sec    0   1.22 MBytes       
      [  5]  25.00-26.00  sec   646 MBytes   645 MBytes/sec    0   1.87 MBytes       
      [  5]  26.00-27.00  sec   689 MBytes   691 MBytes/sec   66   1.41 MBytes       
      [  5]  27.00-28.00  sec   681 MBytes   681 MBytes/sec   85   1.83 MBytes       
      [  5]  28.00-29.00  sec   681 MBytes   681 MBytes/sec    0   1.44 MBytes       
      [  5]  29.00-30.00  sec   672 MBytes   671 MBytes/sec   43   1.19 MBytes       
      - - - - - - - - - - - - - - - - - - - - - - - - -
      [ ID] Interval           Transfer     Bitrate         Retr
      [  5]   0.00-30.00  sec  19.8 GBytes   675 MBytes/sec  894             sender
      [  5]   0.00-30.00  sec  19.8 GBytes   674 MBytes/sec                  receiver
      
      iperf Done.

      上方客户端输出的数据,前4列代表的意义和服务端的一致,只不过客户端这边是作为数据发送的角色;后面的 Retr 一列表示在此时间间隔内的TCP重传次数(或者出错次数);之后的 Cwnd(Congestion Window,拥塞窗口),表示当前的TCP拥塞窗口大小。


      1. Iperf - Wikipedia ↩︎

      2. Iperf: iperf3 - Wikipedia ↩︎


      此文被收纳在#操作系统#类目下,被贴上了#运维#标签

      MarkdownIt Emoji插件语法参考

      发布


      参考:Supported emoticons - Emoticon@GitHub

      # Emoji Name Emoticons
      1 😠 angry >:(; >:[; >:-(; >:-[; >=(; >=[; >=-(; >=-[
      2 😊 blush :"); :"]; :"D; :-"); :-"]; :-"D; ="); ="]; ="D; =-"); =-"]; =-"D
      3 💔 broken_heart </3
      4 😕 confused :/; :-/; =/; =-/
      5 😢 cry :,(; :,[; :,\|; :,-(; :,-[; :,-\|; :'(; :'[; :'\|; :'-(; :'-[; :'-\|; =,(; =,[; =,\|; =,-(; =,-[; =,-\|; ='(; ='[; ='\|; ='-(; ='-[; ='-\|; T-T
      6 😦 frowning :(; :[; :-(; :-[; =(; =[; =-(; =-[
      7 ❤️ heart <3
      8 👿 imp ]:(; ]:[; ]:-(; ]:-[; ]=(; ]=[; ]=-(; ]=-[
      9 😇 innocent o:); o:]; o:D; o:-); o:-]; o:-D; o=); o=]; o=D; o=-); o=-]; o=-D; O:); O:]; O:D; O:-); O:-]; O:-D; O=); O=]; O=D; O=-); O=-]; O=-D; 0:); 0:]; 0:D; 0:-); 0:-]; 0:-D; 0=); 0=]; 0=D; 0=-); 0=-]; 0=-D
      10 😂 joy :,); :,]; :,D; :,-); :,-]; :,-D; :'); :']; :'D; :'-); :'-]; :'-D; =,); =,]; =,D; =,-); =,-]; =,-D; ='); =']; ='D; ='-); ='-]; ='-D
      11 😗 kissing :*
      12 😆 laughing x); x]; xD; x-); x-]; x-D; X); X]; X-); X-]; X-D
      13 👨 man :3; :-3; =3; =-3; ;3; ;-3; x3; x-3; X3; X-3
      14 😐 neutral_face :\|; :-\|; =\|; =-\|
      15 😶 no_mouth :-
      16 😮 open_mouth :o; :O; :0; :-o; :-O; :-0; =o; =O; =0; =-o; =-O; =-0
      17 😡 rage :@; :-@; =@; =-@
      18 😄 smile :D; :-D; =D; =-D
      19 😃 smiley :); :]; :-); :-]; =); =]; =-); =-]
      20 😈 smiling_imp ]:); ]:]; ]:D; ]:-); ]:-]; ]:-D; ]=); ]=]; ]=D; ]=-); ]=-]; ]=-D
      21 😭 sob :,'(; :,'[; :,'-(; :,'-[; :',(; :',[; :',-(; :',-[; =,'(; =,'[; =,'-(; =,'-[; =',(; =',[; =',-(; =',-[
      22 😛 stuck_out_tongue :p; :P; :d; :-p; :-P; :-d; =p; =P; =d; =-p; =-P; =-d
      23 😝 stuck_out_tongue_closed_eyes xP; x-p; x-P; x-d; Xp; Xd; X-p; X-P; X-d
      24 😜 stuck_out_tongue_winking_eye ;p; ;P; ;d; ;-p; ;-P; ;-d
      25 😎 sunglasses 8); 8]; 8D; 8-); 8-]; 8-D; B); B]; B-); B-]; B-D
      26 😓 sweat ,:(; ,:[; ,:-(; ,:-[; ,=(; ,=[; ,=-(; ,=-[; ':(; ':[; ':-(; ':-[; '=(; '=[; '=-(; '=-[
      27 😅 sweat_smile ,:); ,:]; ,:D; ,:-); ,:-]; ,:-D; ,=); ,=]; ,=D; ,=-); ,=-]; ,=-D; ':); ':]; ':D; ':-); ':-]; ':-D; '=); '=]; '=D; '=-); '=-]; '=-D
      28 😒 unamused :s; :z; :S; :Z; :-s; :-z; :-S; :-Z; =s; =z; =S; =Z; =-s; =-z; =-S; =-Z
      29 😉 wink ;); ;]; ;D; ;-); ;-]; ;-D


      Emoji语法测试区

      继续阅读…


      此文被收纳在#参考表#类目下,被贴上了#Markdown#标签

      VLC播放器的圣诞彩蛋

      发布


      很久没用过VLC Player了,今天偶然打开一个midi文件时,发现VLC的“雪糕帽”图标变得有一点点不一样,很有趣,遂记录一下。

      “关于软件”里展示的应用图标也发生变化,戴上了一顶圣诞帽 😃:

      于是乎在网上查了一下,不出所料就是开发者留下的彩蛋:VLC在圣诞节的前后各一周(12月18日至翌年1月1日)会自动把软件图标设置为一个戴圣诞帽的交通锥 [1]

      如果想要关闭这个特性,可以在播放器的偏好设置中取消勾选“允许自动更改图标”,然后关闭窗口重启软件即可,配置项的大概位置在 “界面 - 主界面” 里。不同系统或者不同软件版本,可能会不一样。


      1. VLC多媒体播放器 彩蛋 - Wikipedia ↩︎


      此文被收纳在#星碎札#类目下,被贴上了#播放器#标签

      使用Python批量读取/修改ogg音频元数据

      发布


      第一次碰到Ogg文件是在安卓系统的/system/media/audio/目录下的一些文件夹(alarms/notifications/ringtones/ui等文件夹)里,尽管后缀名非常奇怪,但这种格式的文件已经被广泛传播和使用了。使用十六进制文件查看器任意打开一个OGG文件,可以看到它的文件头的Magic Number为:0x4F676753,转换为文本就是OggS,即这种文件的后缀名的全称:OggSquish [1]

      这种文件格式的优势在于开源,支持多种编码类型,且压缩率高。

      我们可以使用Python的一个库 mutagen,简单修改包括Ogg这种文件格式在内的音频文件的元数据(如,标题、作者等……)。

      安装mutagen

      python -m pip install mutagen

      安装mutagen之后,即可借助这个库简单查看OGG文件的一些基础数据:

      import mutagen
      
      audio = mutagen.File('ping.ogg')
      
      print(audio.pprint())
      """输出:
      Ogg Vorbis, 0.27 seconds, 120000 bps (audio/vorbis)
      ANDROID_LOOP=false
      TITLE=android.resource://com.google.android.soundpicker/string/ping
      """

      以及,修改文件的数据:

      import mutagen
      
      audio = mutagen.File('ping.ogg')
      
      print(audio.pprint())
      
      audio['TITLE'] = "Ping" # 修改标题
      audio['ARTIST'] = "Google Pixel" # 修改作者
      
      audio.save() # 保存修改
      
      print()
      print("""--- AFTER MODIFIED ---""")
      print()
      
      modified = mutagen.File('ping.ogg')
      
      print(modified.pprint())
      
      
      """输出:
      Ogg Vorbis, 0.27 seconds, 120000 bps (audio/vorbis)
      ANDROID_LOOP=false
      TITLE=android.resource://com.google.android.soundpicker/string/ping
      
      --- AFTER MODIFIED ---
      
      Ogg Vorbis, 0.27 seconds, 120000 bps (audio/vorbis)
      ANDROID_LOOP=false
      TITLE=Ping
      ARTIST=Google Pixel
      """

      假设目录都是后缀为ogg的文件,文件命名格式都是xxx_yyy.ogg之类,目标是修改其元数据信息的标题TITLEXxx Yyy,可以写出一个批量修改OGG文件标题和作者等元数据的脚本:

      import os
      import re
      import sys
      import time
      import mutagen
      
      try:
      
          _path = input('Please input ogg files folder path: ')
      
          _path = _path.strip('\' ')
      
      except KeyboardInterrupt as e:
          print()
          print('Good bye.')
          sys.exit(0)
      
      if len(_path) <= 0:
          print('Param error.')
          sys.exit(1)
      
      print('Ogg files folder path is: [%s]' % (_path, ))
      
      print()
      print('---')
      print()
      
      t0 = time.time()
      
      def format_name_str(s: str):
          parts = s.split('_')
          capitalized_parts = [part.capitalize() for part in parts]
          return ' '.join(capitalized_parts)
      
      tasks = []
      successed_tasks = []
      
      def modify_metadata(file_path: str, title: str, artist: str):
          try:
              audio = mutagen.File(file_path)
              
              audio['TITLE'] = title
              audio['ARTIST'] = artist
              
              audio.save()
              print(f'Metadata updated for {file_path}')
              successed_tasks.append(file_path)
          except Exception as e:
              print(f'Error processing {file_path}: {e}')
      
      for root, _, files in os.walk(_path):
          for file in files:
              if file.lower().endswith('.ogg'):
                  file_path = os.path.join(root, file)
                  tasks.append(file_path)
                  modify_metadata(file_path, format_name_str(re.sub(r'\.ogg$', '', file)), 'Google Pixel')
      
      print()
      print('---')
      print()
      
      print('Processed %d /%d file(s).' % (len(successed_tasks), len(tasks)))
      
      print('Cost: %.4f s.' % (time.time()-t0, ))

      脚本将会递归遍历指定文件夹下的所有OGG文件,并根据文件名称相应修改文件元数据的标题、修改作者为Google Pixel

      运行结果如下:

      Please input ogg files folder path: '/Users/azhza/Downloads/Ringtones'
      Ogg files folder path is: [/Users/azhza/Downloads/Ringtones]
      
      ---
      
      Metadata updated for /Users/azhza/Downloads/Ringtones/eureka.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/flick.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/scamper.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/party_favor.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/pipes.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/sleigh_bells.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/champagne_pop.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/moondrop.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/be_mine.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/twang.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/sweetheart.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/swoosh.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/tune_up.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/orbiter.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/coconuts.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/rainstick.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/flutter.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/glimpse.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/droplet.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/plonk.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/epiphany.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/popcorn.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/begining.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/sunflower.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/gradient.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/snowflake.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/chitter.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/winter_wind.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/twinkle.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/sticks_and_stones.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/bumble.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/mallet.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/shopkeeper.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/thumb.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/everblue.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/chime.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/teapot.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/gentle_gong.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/iota.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/ping.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/chord.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/holiday_magic.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/carbonate.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/mystique.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/cheers.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/knock.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/orders_up.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/tweeter.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/watery.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/discovery.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/shuffle.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/duet.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Material Adventures/approach.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Material Adventures/shimmering.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Material Adventures/tinsel.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Material Adventures/dish_hop.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Material Adventures/dragon_dreams.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Material Adventures/flitter.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Material Adventures/pivot.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Material Adventures/go_off_king.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Material Adventures/star_jump.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Material Adventures/snap_technique.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Material Adventures/departure.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Material Adventures/blue_harp.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Material Adventures/beats_and_bops.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Material Adventures/aqueous.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Play It Loud/construction_zone.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Play It Loud/dots.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Play It Loud/heaviest_metal.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Play It Loud/pots_and_pans.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Play It Loud/high_flying.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Play It Loud/glassy_ring.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Play It Loud/dubstep_drops.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Play It Loud/sharp_ring.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Play It Loud/beach_jam.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Play It Loud/radient_chimes.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Play It Loud/mystical_chimes.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Play It Loud/glass_bubbles.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Seasonal Celebrations/jingle_bells.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Seasonal Celebrations/lion_dance.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Seasonal Celebrations/cupids_arrow.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Seasonal Celebrations/holiday_bells.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Seasonal Celebrations/deck_the_halls.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Seasonal Celebrations/flower_waltz.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Seasonal Celebrations/spring_mist.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Seasonal Celebrations/spooky_organ.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Seasonal Celebrations/auld_lang_syne.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Seasonal Celebrations/dreidel_dreidel.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Seasonal Celebrations/autumn_rainstorm.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Seasonal Celebrations/hello_spring.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Seasonal Celebrations/haunted_house.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/MinimalMelodies/milky_way.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/MinimalMelodies/galaxy.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/MinimalMelodies/falling_star.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/MinimalMelodies/big_dipper.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/MinimalMelodies/satellite.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/MinimalMelodies/constellation.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/MinimalMelodies/cosmic_dust.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/MinimalMelodies/north_star.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/MinimalMelodies/asteroid.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/MinimalMelodies/comet.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Classical Harmonies/the_hunt.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Classical Harmonies/presto.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Classical Harmonies/air.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Classical Harmonies/hungarian_dance.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Classical Harmonies/blue_lily.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Classical Harmonies/nutcracker.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Classical Harmonies/moonlight.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Classical Harmonies/minuet.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Classical Harmonies/butterflys_wings.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Classical Harmonies/mephistos_dance.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Classical Harmonies/nocturne.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Classical Harmonies/breeze.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Retro Riffs/finish_line.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Retro Riffs/flip_phone.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Retro Riffs/back_in_time.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Retro Riffs/game_on.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Retro Riffs/glow_stick.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Retro Riffs/high_score.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Retro Riffs/gateway.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Retro Riffs/power_up.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Retro Riffs/bonus_points.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Retro Riffs/light_crackle.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Retro Riffs/tropical_beats.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Retro Riffs/the_small_adventure.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Pixel Sounds/shooting_star.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Pixel Sounds/copycat.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Pixel Sounds/your_new_adventure.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Pixel Sounds/monkey_around.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Pixel Sounds/lost_and_found.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Pixel Sounds/spaceship.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Pixel Sounds/hotline.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Pixel Sounds/futterby.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Pixel Sounds/early_bird.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Pixel Sounds/rrring.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Pixel Sounds/zen.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Pixel Sounds/crackle.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Pixel Sounds/summer_night.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Pixel Sounds/leaps_and_bounds.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Pixel Sounds/hey_hey.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Pixel Sounds/dance_party.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Pixel Sounds/beats.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Pixel Sounds/schools_out.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Pixel Sounds/romance.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Pixel Sounds/lolipop.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Pixel Sounds/zen_too.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Pixel Sounds/mash_up.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Pixel Sounds/the_big_adventure.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Natural Elements/dewdrop.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Natural Elements/log_drum.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Natural Elements/cloud_drift.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Natural Elements/busy_bee.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Natural Elements/woodpecker.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Natural Elements/garden_breeze.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Natural Elements/mingle.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Natural Elements/voyages.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Natural Elements/dusty_plain.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Natural Elements/songbird.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Natural Elements/awakening.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Natural Elements/night_song.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Reality Bytes/little_red_trolley.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Reality Bytes/band_practice.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Reality Bytes/merry_go_round.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Reality Bytes/hen_house.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Reality Bytes/the_cats_meow.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Reality Bytes/sealed_with_a_kiss.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Reality Bytes/pinwheel.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Reality Bytes/old_timey_phone.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Reality Bytes/didgeridoo.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Reality Bytes/fair_tale.ogg
      Metadata updated for /Users/azhza/Downloads/Ringtones/Reality Bytes/sweet_dreams.ogg
      
      ---
      
      Processed 171 /171 file(s).
      Cost: 0.4646 s.

      1. Ogg - Wikipedia ↩︎


      此文被收纳在#写写代码#类目下,被贴上了#Python##OGG音频#标签

      给老笔记本再次更新黑苹果

      发布最后更新于


      EFI下载地址见此:ASUS-Zenbook-U4100U-OpenCore-EFI/releases


      2024-12-05更新:修复了Wi-Fi和蓝牙驱动问题,目前来看大部分硬件都驱动上了,算是比较完美的黑苹果。

      手柄尝试连接多次,貌似连不上,不知道什么原因,只能通过USB连接和识别 😦


      2024-12-06更新:



      将多年前的老笔记本的黑苹果系统macOS版本从12的Monterey升级到了15的Sequoia,使用OpenCore引导,目前系统的主要硬件驱动情况:

      • 电源/休眠
      • 键盘/键盘背灯
      • USB端口映射
      • 音频/耳机口/麦克风
      • 摄像头
      • 触摸板
      • Wi-Fi
      • 蓝牙
      • 多系统切换

      老设备再次焕发新生机~目前双系统支持切换Windows11:


      此文被收纳在#操作系统#类目下,被贴上了#Hackintosh#标签

      使用Webpack内联CSS JS

      发布


      有些场景下,希望能将引用的CSS文件内联至style标签中,将JS文件内联至script标签中,这样就可以减少网络请求数量,提升页面加载速度。尤其是在页面引用到了众多小型的资源文件时,嵌入到一个html文件中,页面首次加载速度会有明显提高。

      我们可以配置Webpack,借助插件:html-bundler-webpack-plugin,将这些小型文件都内联化,配置打包到一个html文件中就可以了。下面是一个简单用例:

      假如项目目录如下:

      .
      ├── package.json
      └── src
          ├── a.html
          ├── b.html
          ├── scripts
          │   ├── a1.js
          │   └── a2.js
          └── styles
              ├── a1.css
              └── a2.css
      

      其中,a.html引用了a1.jsa1.css

      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
          <title>Page a</title>
          <link rel="stylesheet" href="styles/a1.css">
      </head>
      <body>
          <script src="scripts/a1.js"></script>
      </body>
      </html>

      b.html引用了a2.jsa2.css

      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
          <title>Page a</title>
          <link rel="stylesheet" href="styles/a2.css">
      </head>
      <body>
          <script src="scripts/a2.js"></script>
      </body>
      </html>

      我们希望将两个html文件各自所引用到的文件,分别打包到各自所在的html文件中,最终得到dist/a.htmldist/b.html两个文件,那么,可以按如下步骤来进行配置操作:

      首先安装Webpack、html-bundler-webpack-plugin以及css-loader等依赖:

      npm install html-bundler-webpack-plugin css-minimizer-webpack-plugin css-loader webpack webpack-cli -D

      然后创建webpack.config.js配置文件:

      // webpack.config.js
      import path from 'path';
      import HtmlBundlerPlugin from 'html-bundler-webpack-plugin';
      import CssMinimizerPlugin from 'css-minimizer-webpack-plugin';
      import { fileURLToPath } from 'url';
      
      const __filename = fileURLToPath(import.meta.url); // 获取当前文件路径
      const __dirname = path.dirname(__filename);
      
      export default {
        mode: 'production',
      
        output: {
          path: path.join(__dirname, 'dist/'),
        },
      
        plugins: [
          new HtmlBundlerPlugin({
            entry: {
              'a': './src/a.html',
              'b': './src/b.html',
            },
            css: {
              inline: true,
            },
            js: {
              inline: true,
            },
            minify: true,
          }),
          new CssMinimizerPlugin(), // 压缩CSS
        ],
      
        module: {
          rules: [
            {
              test: /\.css$/,
              use: ['css-loader'],
            },
          ],
        },
      
        performance: false,
      };

      然后编辑package.json,加入一个打包指令:

      {
        "name": "_proj",
        "version": "1.0.0",
        "main": "index.js",
        "scripts": {
          "build": "webpack build --mode=production"
        },
        "keywords": [],
        "author": "",
        "license": "ISC",
        "description": "",
        "devDependencies": {
          "css-loader": "^7.1.2",
          "css-minimizer-webpack-plugin": "^7.0.0",
          "html-bundler-webpack-plugin": "^4.4.1",
          "webpack": "^5.96.1",
          "webpack-cli": "^5.1.4"
        },
        "type": "module"
      }

      终端运行:

      npm run build

      会在dist目录下生成两个内嵌了所引用的CSS/JS文件内容的HTML文件。


      此文被收纳在#Webpack#类目下,被贴上了#Webpack#标签

      有趣的“码神挑战”

      发布最后更新于


      昨天在B站刷到一位叫“鱼皮”的Up的视频,内容是介绍面向广大程序员发起的“码神挑战”答题活动。想要证明自己的“编程实力”的同学可以去看看,答题的同时巩固一下自己的编程知识,同时收获一份快乐~ 😆

      点击此处开始挑战。

      P.S.

      已通关,学无止境!(全程开发者控制台工具没关过~有几关没解出来,切到移动端视图跳过去的)


      此文被收纳在#写写代码#类目下,被贴上了#1024程序员节#标签

      在Termux中安装Deno

      发布


      Termux 是一款运行在安卓设备平台上的终端命令行模拟器,无需Root权限就能直接安装和运行Linux环境下的一些程序 [1]

      我们可以给家里旧安卓手机安装上Termux,再通过Termux的终端命令行工具装上openssl等工具就可以拥有一台小型的本地远程Linux终端了(当然,如安卓设备未获取Root权限,某些操作也会受限)。使用Termux,可以在安卓机上跑一些小型服务,让吃灰的旧手机也能发光发热。下面介绍在Termux终端命令行下安装Deno的几种方式。

      方式一:使用proot-distro

      proot-distro 是Termux下的各种Linux发行版的安装和管理工具,有了它就可以在不需要root权限的情况下运行诸如Ubuntu、Debian、Fedora等Linux发行版了,下面以安装Ubuntu为例进行介绍。

      安装proot-distro

      # 安装proot-distro
      pkg install proot-distro
      # 查看可用的Linux发行版
      proot-distro list
      # 安装Ubuntu(这里会从github下载一些资源,如下载缓慢建议开启代理)
      proot-distro i ubuntu
      # 等待下载完毕,启动Ubuntu
      proot-distro login ubuntu

      进入Ubuntu的Shell环境,之后,就可以像在普通Linux环境下安装Deno了。

      安装Deno

      安装解压缩工具:

      apt update
      # 安装zip和unzip
      apt install unzip zip

      可以选择安装Deno的最新版本:

      # opt1. 安装Deno的最新版本
      curl -fsSL https://deno.land/install.sh | sh

      或者指定版本安装:

      # opt2. 指定安装版本,例如:v1.45.2
      curl -fsSL https://deno.land/x/install/install.sh | sh -s v1.45.2

      在出现对话语句:Edit shell configs to add deno to the PATH? (Y/n) 时输入Y回车,设置PATH环境变量。

      在出现对话语句:Set up completions? 时,可以直接按下回车。

      之后终端运行:

      # 刷新环境变量
      source ~/.bashrc
      # 查看Deno安装状态
      deno --version

      方式二:直接下载termux-deno二进制可执行文件

      相关说明见此仓库:https://github.com/cions/termux-deno 的 README.md。

      • 在Termux终端环境下,安装Deno的最新版本:
      # opt1. 下载安装Termux-Deno的二进制可执行文件
      curl -fsSL -o ~/.deno/bin/deno https://api.cirrus-ci.com/v1/artifact/github/cions/termux-deno/deno/deno-aarch64-android/deno && chmod +x ~/.deno/bin/deno

      然后在右侧编译任务列表中点击选择某个Deno的编译版本;

      之后,在任务列表下,点击选择 Build Deno

      在之后的跳转页面,在 Artifacts 一栏、打开 deno-aarch64-android 文件夹,下载此版本的Termux-Deno二进制编译文件:

      将下载的文件复制到 ~/.deno/bin/ 目录下,为其添加可执行权限,再将 ~/.deno/bin 追加到PATH环境变量,即可。

      如上的操作,可以简化为一行命令:

      # opt2. 安装指定版本的Termux-Deno,例如:v1.46.2
      ## v1.46.2
      curl -fsSL -o ~/.deno/bin/deno https://api.cirrus-ci.com/v1/artifact/task/6156973433946112/deno-aarch64-android/deno && chmod +x ~/.deno/bin/deno

      最后

      # 卸载Deno
      rm -rf ~/.deno

      1. The Termux Wiki: Introduction ↩︎


      此文被收纳在#Deno#类目下,被贴上了#Termux#标签

      简单使用deno实现反向地理编码

      发布


      反向地理编码(Reverse Geocoding)是将经纬度等坐标信息转换为人类可读的地址(如城市名、街道名等)的过程。实现反向地理编码有多种办法,可以调用百度、高德、谷歌等服务商提供的第三方API,也可自行去解析地图离线数据实现。如果需求不是要得到精确地址(例如只要得到省、市名),那么采用后者无疑是最优的。

      下载省、市边界数据

      点击打开:https://datav.aliyun.com/portal/school/atlas/area_selector,在页面右侧,就可以下载省或市的边界数据了:

      或者终端里边运行:

      # 市级粒度数据
      wget -O china_full_city.geo.json https://geo.datav.aliyun.com/areas_v3/bound/100000_full_city.json

      最后下载来的 china_full_city.geo.json 数据结构大概长这样:

      interface FeatureCollection {
          features: {
              // 各个市级行政区域的轮廓数据
              geometry: {
                  coordinates: [float, float][][];
                  type: 'MultiPolygon';
              };
              properties: {
                  name: string;
                  parent: {
                      areacode: int;
                  };
                  // …此处省略其他的一些属性
              };
              type: 'Feature';
          }[];
          type: 'FeatureCollection';
      }

      它是遵循 GeoJSON 的。所谓“GeoJSON”,就是一种用于编码地理数据的开源格式,专门用于描述几何对象(点、线、多边形等)这类数据的一种格式规范,被广泛应用于地理信息系统(GIS)、地图服务和Web应用。

      有了全国所有市的轮廓数据,我们就知道全国每个市在地图上的板块范围。这样,通过遍历每个市的多边形区域,使用turf.js中几何的算法,判断待查询的GPS坐标是否在多边形的范围内,即可得出所在城市。

      使用 Turf.js 来检索GeoJSON文件

      china_full_city.geo.json 同级目录下新建 getCityName.ts 文件,编写TypeScript代码:

      import { FeatureCollection, Feature, MultiPolygon } from 'https://esm.sh/v135/@types/geojson@7946.0.14/index.d.ts';
      
      // # 首先是根据这个json文件的结构,可以写出它的类型`XFeatureCollection`:
      
      // properties的属性
      type XGeoJsonProperties = {
          acroutes: number[],
          adcode: number,
          center: number[],
          centroid: number[],
          childrenNum: 0,
          level: string,
          name: string, // 市级行政区名称
          parent: {adcode: number}, // 市级行政区所在的省级行政区编码
          subFeatureIndex: number,
      }
      
      type XFeatureCollection = FeatureCollection<MultiPolygon, XGeoJsonProperties>;
      
      // # 然后遍历features列表的各个城市,使用turf.js封装的`booleanPointInPolygon`方法,
      //   判断待查询经纬度的点是不是在市级行政区图块多边形之中,是:则表示坐标在该市范围之内
      
      import chinaProvincesGeoJSON from "./china_full_city.geo.json" with {type: 'json'};
      import { booleanPointInPolygon } from "https://esm.sh/@turf/boolean-point-in-polygon@7.1.0";
      import * as turf from "https://esm.sh/@turf/turf@7.1.0";
      
      // 定义一个待查询的国内经纬度坐标,形式是“度分秒”
      const [[d0, m0, s0], [d1, m1, s1]] = [[112, 34, 56], [34, 56, 12]];
      // 转化为“度”的坐标形式
      const [lng, lat] = [d0+m0/60+s0/3600, d1+m1/60+s1/3600];
      // 定义为Point坐标类型
      const pt = turf.point([lng, lat]);
      
      // 定义类型
      const collections = chinaProvincesGeoJSON as XFeatureCollection;
      
      let targetFeature!: Feature<MultiPolygon, XGeoJsonProperties>;
      
      for (const f of collections.features) {
          // 使用turf的这个函数判断这个点是不是在(市级行政区)多边形区域内
          const ret = booleanPointInPolygon(pt, turf.multiPolygon(f.geometry.coordinates));
          if (ret) {
              targetFeature = f;
              break;
          }
      }
      
      console.log(targetFeature ? targetFeature.properties.name : '(超出查询范围)');

      然后终端运行:

      # 返回:焦作市
      deno run -A getCityName.ts

      如果想要知道城市所在的省级行政区名,可以通过查询父级行政区域码 targetFeature.properties.parent.adcode 得知:

      const provinceAdcodeNameMapping: {[k: number|string]: string} = {
          "110000":"北京市","120000":"天津市","130000":"河北省","140000":"山西省","150000":"内蒙古自治区",
          "210000":"辽宁省","220000":"吉林省","230000":"黑龙江省",
          "310000":"上海市","320000":"江苏省","330000":"浙江省","340000":"安徽省","350000":"福建省","360000":"江西省","370000":"山东省",
          "410000":"河南省","420000":"湖北省","430000":"湖南省","440000":"广东省","450000":"广西壮族自治区","460000":"海南省",
          "500000":"重庆市","510000":"四川省","520000":"贵州省","530000":"云南省","540000":"西藏自治区",
          "610000":"陕西省","620000":"甘肃省","630000":"青海省","640000":"宁夏回族自治区","650000":"新疆维吾尔自治区",
          "710000":"台湾省",
          "810000":"香港特别行政区","820000":"澳门特别行政区",
          "100000_JD":""
      };
      
      // 返回:河南省
      console.log(targetFeature ? provinceAdcodeNameMapping[targetFeature.properties.parent.adcode] : '');

      最后

      这种办法适合对解析精度要求不太高的场景,如果想要解析到区和街道或者更高级别,考虑到未来数据更新和维护的复杂度,建议还是使用各大第三方平台的API比较好。


      此文被收纳在#Deno#类目下,被贴上了#反向地理编码#标签
      ← 早期文第 1 页 / 共 2 页近期文 →