大凉山里的跑步

去盐源之前,我以为它不过是地图上一个普通的县城,一个点而已。抵达西昌,租了车,便开始了这段漫长的大凉山之旅。120公里的路程,导航显示需要三个多小时,我当时觉得这时间大概是给那些开慢车的司机准备的。直到车子真正钻进山里,我才意识到,这不仅仅是“进山”,而是进入另一个世界。盘山公路像一条条无止境的缎带,在山间缠绕,蜿蜒曲折。那些在别处被称作“十八弯”的弯道,在这里都成了不足为道的日常。车子一会儿被抛上山顶,一会儿又坠入谷底,像是在一场无休止的过山车游戏。 终于,在颠簸了三个多小时后,我们抵达了盐源县城。工作结束后,我竟开始期待第二天早上的跑步。清晨六点半醒来,天空灰蒙蒙的,气温凉爽,穿上加绒长袖和厚厚的压缩裤,感觉刚刚好。 简单活动一下手脚,便出发了。刚跑起来就觉得呼吸有些困难,刚出旅馆就是一个漫长的大上坡,足足有一点五公里,心率蹭蹭地往上蹿,几乎要突破170。 我开始调整呼吸,放慢脚步。好在上坡之后,迎来一段相对平缓的下坡路,坡度不那么陡峭,心率也慢慢降了下来。要不是接下来的这段下坡路,我可能在中途就想放弃,掉头回宾馆了。 清晨的县城,与喧嚣的夜晚截然不同,显得格外安静。没有烟火气十足的烧烤摊,只有停靠在路边的车辆,和偶尔匆匆走过的行人。偶尔会碰到清扫街道的工人,还有一些早起的人们。幸运的是,我还遇到了两位跑者。第一个跑者与我同路很短一段距离,想来他大概是跑完了,正要拐进一个小区的样子。第二个跑友,和我前后跑了一公里多,后来他便折返回去了。 我选择了一条绕县城一圈的路线,大概九公里左右。跑到关键的路口,还会停下来看看手机地图,确认路线是否正确。总的来说,这条路线还算不错,红绿灯不多,早上的车辆和行人也比较少。唯一美中不足的是,自行车道上偶尔会有停放的汽车和货车,把路堵得水泄不通。还有就是人行道与马路之间有很大的高度差,一不小心就容易崴脚。 跑步结束后,我查看了一下数据,才发现盐源县的海拔竟然有2500米,累积爬升将近100米。难怪心率飙升得那么厉害。我仔细研究了一遍数据,好像在试图从这些数字里找到一些跑得气喘吁吁的理由。 时间: 2024-12-11 06:50:04 距离: 9.32 km 时长: 59:07 配速: 6:20 / km 心率: 155 bpm 跑步之外,我对这座小县城的印象也逐渐清晰。街道还算干净,人们喜欢晒太阳,三三两两地聚在一起,仿佛时间在这里流动得格外缓慢。在西昌,我甚至看到有人直接躺在草地上晒太阳,那景象像极了一幅静谧的油画。 虽然都是山路,但道路状况还算不错,没有太多压线过弯的情况。在路上,我看到了不少散落在山间的房屋和村落,能感受到大山里的生活不易。这些分散的房屋,像一颗颗散落在绿色地毯上的棋子,诉说着一种与城市截然不同的生活方式。 跑步的时候,我常常思考这些无关紧要的事情。它们像影子一样,跟随在我跑步的脚步之后,在汗水和喘息之间,渐渐变得清晰起来。也许这就是跑步的意义之一吧,它不仅是身体的锻炼,也是一场与自己对话的旅程。

十二月 11, 2024 · 1 分钟 · 25 字 · Byter ·  跑步记事

2024-11 跑步日记

2024-11 运动次数: 9 运动距离: 102.76 km 运动时长: 10:15:11 平均距离: 11.42 km 平均心率: 147 bpm 平均配速: 5:59 / km 2024-11-01 时间: 2024-11-01 07:05:41 距离: 5.58 km 时长: 33:35 配速: 6:00 / km 心率: 138 bpm ...

十一月 30, 2024 · 1 分钟 · 162 字 · Jogger ·  跑步

Hugo个人博客搭建

Hugo 能做什么 通过 Hugo 你可以快速搭建你的静态网站,比如博客系统、文档介绍、公司主页、产品介绍等等。相对于其他静态网站生成器来说,Hugo 具备如下特点: 极快的页面编译生成速度。( ~1 ms 每页面) 完全跨平台支持,可以运行在 Mac OS X, Linux, Windows, 以及更多! 安装方便 Installation 本地调试 Usage 时通过 LiveReload 自动即时刷新页面。 完全的皮肤支持。 可以部署在任何的支持 HTTP 的服务器上。 安装部署简要说明: 操作系统是Ubuntu 22.04.4 LTS Hugo生成静态页面 Nginx发布服务 Go环境安装 前往go.dev下载最新的go程序 wget https://go.dev/dl/go1.22.1.linux-amd64.tar.gz 解压安装 sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.22.1.linux-amd64.tar.gz 加入环境变量 sudo vim /etc/profile 在文件最后增加 export PATH=$PATH:/usr/local/go/bin 退出登录或者source /etc/profile重新加载环境配置,检查go是否正常运行,能正常输出版本信息就正常 go version Hugo安装 由于Ubuntu源里的版本不是最新版,这里直接采用go的编译安装模式,在主目录下运行 go install github.com/gohugoio/hugo@latest 加入环境变量 vim ~/.bashrc 在文件最后增加 export PATH=$PATH:~/go/bin 退出登录或者source ~/.bashrc重新加载环境配置,检查hugo是否正常运行,能正常输出版本信息就正常 hugo version 现在使用的hugo版本信息 ...

十一月 19, 2024 · 4 分钟 · 814 字 · Byter ·  Hugo ·  Blog ·  Ubuntu

为Hugo搭建的博客添加友情链接

为了和LINUX DO交换友情链接,研究了一下怎么给Hugo添加这个功能。 搜索找到kkkgo的hugo-friendlinks,按照说明配置好之后,确实可以展示了,但是有两个问题:一是没有和博客的页面融合,显示的是单独的链接页面;二是,友情链接的博客描述是乱码,可能是我配置的问题。 于是又找到鐵手的 Hugo 白话文 | 添加友情链接,看完之后觉得配置的过程有点复杂。 于是想着其实友情链接也是一篇文章,把kkkgo和鐵手融合一下,借鉴kkkgo的关于友情链接的shortcodes内容,样式部分从kkkgo的links.html找到对应内容,试了一下,果然成功,效果还可以。进入我的 友链 看看效果。 增加友链菜单 需要修改Hugo的配置文件hugo.yaml,修改的内容如下: languages: zh: languageName: "中文" weight: 1 menu: main: - name: 标签 url: tags/ weight: 1 - name: 存档 url: archives weight: 2 - name: 搜索 url: search/ weight: 3 - name: 关于/联系 url: about/ weight: 5 - name: 友链 url: links/ weight: 4 最下面的三行是添加友链的菜单内容,参数说明: ...

十一月 19, 2024 · 2 分钟 · 263 字 · Byter ·  友情链接

西宁冬日跑步

清晨的西宁,被一层薄薄的寒意笼罩着。湟水河畔是我最爱的跑步之地,尤其是在这样一个零下三度的冬日早晨。尽管心中有些犹豫,面对寒冷,我还是穿上长袖运动衫,套上那件夏天的防晒服,出发了。 小跑到湟水河湿地,开始感受到身体逐渐进入状态。耳机里传来音乐的节拍,我的双脚在节奏中轻快地踏在地面上。然而,后面一直传来轻微的脚步声,尽管戴着耳机,我仍能感受到那种若即若离的跟随。 我不喜欢被人跟着,这总是打乱我的节奏。于是,我加快了步伐,以每公里5分30秒的速度奔跑,希望能摆脱那份无形的压力。然而,心率也随之飙升,我知道这样的配速无法持续太久。于是,我放慢了脚步,调整到每公里6分钟的节奏。 跑了大约6公里,前方有环卫工人在清扫落叶,我停了下来。就在这时,那位女跑友超过了我。她的呼吸声在我身边渐渐远去。我重新起跑,追上她,打了个招呼。原来,她也在寻找一条适合的跑步路线,看到我便临时决定跟随。 我们并排跑着,交流着。她告诉我,她的配速通常在每公里6分30秒到7分钟之间,今天因为跟着我,才跑得更快。西宁的跑步者不多,跑团也在慢慢兴起。我们聊起各自的跑步经历,她有腰伤,所以不敢跑太长的距离,通常只跑10公里。 跑到火车站,她的终点到了。她说今天跟着我跑,几乎要创下个人最好成绩。我们互相道别后,我折返回程,穿越湟水河,来到河对岸。 河对岸的路况不如想象中好,方板石的人行道让跑步变得有些挑战。沿着湟水河中间的小道奔跑,左边是清澈的河水,右边却是浑浊的流淌。在这条小道上,我突然遇到了断头路,只得返回几百米,找到一座小铁桥继续前行。 最终,我回到了起点,完成了23.70公里的跑步。查看数据,每5公里的平均时间约为30分钟,最终配速6分钟整,心率平均157。在西宁的高海拔下,这样的心率显得有些高。下次再来,我需要带上腰带,备上水和能量胶,可以在西宁进行一次30公里以上的长距离拉练。 冬日的西宁,寒冷而宁静,湟水河畔的跑步,像是一场与自己内心的对话。每一次呼吸,每一次脚步,都是对身体和心灵的洗礼。

十一月 17, 2024 · 1 分钟 · 9 字 · Jogger ·  跑步记事

Hugo集成大善人Cloudflare+D1网页访客统计服务

本文主要是采用开源项目analytics_with_cloudflare 。 analytics_with_cloudflare服务部署 下载项目文件 git clone https://github.com/yestool/analytics_with_cloudflare 安装依赖 cd analytics_with_cloudflare npm install -g wrangler npm install hono 登录 跳转cloudflare网页授权 npx wrangler login 创建D1数据库:[web_analytics] 数据库名称为web_analytics,与package.json内保持一致 npx wrangler d1 create web_analytics 成功后显示: ✅ Successfully created DB web_analytics [[d1_databases]] binding = "DB" # available in your Worker on env.DB database_name = "web_analytics" database_id = "<unique-ID-for-your-database>" 配置worker和D1数据库绑定 将上个步骤返回的unique-ID-for-your-database写进wrangler.toml中 name = "analytics_with_cloudflare" main = "src/index.ts" compatibility_date = "2024-06-14" [[d1_databases]] binding = "DB" # available in your Worker on env.DB database_name = "web_analytics" database_id = "<unique-ID-for-your-database>" 初始化D1数据库的表结构 npm run initSql 修改src/index.ts 内容 const body = await c.req.json() const hostname = body.hostname const url_path = body.url const referrer = body.referrer const pv = body.pv const uv = body.uv // 添加以下两行 const spv = body.spv const suv = body.suv // 中间代码忽略 // 修改下面代码内容 const resData:{pv?: number, uv?: number, spv?: number, suv?: number} = {} // 中间代码忽略 if (uv){ const total = await c.env.DB.prepare('SELECT COUNT(*) AS total from (select DISTINCT visitor_ip from t_web_visitor where website_id = ? and url_path = ?) t').bind(websiteId, url_path).first('total'); resData['uv'] = Number(total) } // 添加以下两段代码 if (spv){ const total = await c.env.DB.prepare('SELECT COUNT(*) AS total from t_web_visitor where website_id = ?').bind(websiteId).first('total'); resData['spv'] = Number(total) } if (suv){ const total = await c.env.DB.prepare('SELECT COUNT(*) AS total from (select DISTINCT visitor_ip from t_web_visitor where website_id = ?) t').bind(websiteId).first('total'); resData['suv'] = Number(total) } // 修改完成 完整代码内容,可以下载index.ts 原来的代码只支撑返回单个页面的访问数据,不支持返回整个网站的访问数据,增加spv和suv两个返回值,分别是全站访问人次和全站访问人数。 ...

2024-10 跑步日记

2024-10 运动次数: 12 运动距离: 139.29 km 运动时长: 13:18:51 平均距离: 11.61 km 平均心率: 148 bpm 平均配速: 5:44 / km 2024-10-01 时间: 2024-10-01 06:55:32 距离: 11.30 km 时长: 56:31 配速: 4:59 / km 心率: 131 bpm ...

十月 30, 2024 · 1 分钟 · 210 字 · Jogger ·  跑步

顺利完成人生首次马拉松比赛

一直认为,跑步是一种孤独的修行。即便是在熙熙攘攘的马拉松赛道上,心灵深处的那份孤独感依旧如影随形。9月的某个下午,朋友给我转了一个廊坊市“通北”协同马拉松的报名链接。想着时间尚早,赛期在10月底,我不敢贸然报名全马,选择了半马作为挑战。 10月中旬,收到中签短信时,我告诉了朋友,结果他却说自己没报名,嫌路程太远。我这才意识到,自己还没弄清比赛的具体地点。打开手机一查,发现开车全程不堵车也要一个半小时。心里不禁有些打鼓,想着比赛当天得起个大早。 10月26日,我匆匆从外地赶回,前往廊坊香河领取参赛物品。第一次参赛,缺乏经验,也没有朋友相伴,只能反复阅读组委会发来的参赛手册。一路忐忑地来到目的地,看到许多跑友背着参赛包走过,心中稍安。跟随他们的脚步,我很快找到了物品领取处。整个过程其实简单:打印小票、领取号码布和手环、领取参赛服和参赛包、手环监测,结束。 回到家,我按照要求提前佩戴好号码布,准备好裤子、鞋子,还模仿着那些跑步大神拍了一张定装照。设好闹钟,第二天5点半起床,简单吃了几口面包和一大杯水。 早晨的路上,车速很快,一个小时左右就快到了。快到7点时,交警开始封路,心中不免担忧。幸运的是,顺利到达前一天踩点的地方。到了那里,背上参赛包直奔存包处。 由于喝了太多水,我急需排空。找到一个临时卫生间,只有四个位置,每个门口都排着长队。离发枪只有半个小时,后面还有人不断加入队伍。有人抱怨,有人着急,也有小孩直接在旁边稍微遮挡的地方解决。 好在有惊无险,上完厕所,还有15分钟。迅速跑到存包处,脱掉外套,感觉有些冷,存包倒是顺利。顺着人流来到半马集结区,比赛的气氛与自己一个人跑步截然不同。 稍微往里面走了走,发现旁边的人大多与熟人聊着,心中不免有些孤独。我们半马区在后面,听不到主持人的声音,只能等待8点的枪声。 枪声响起,人群开始移动,几分钟后才到达计时点,正式开跑。起初的兴奋让我心率飙升到160,于是放慢了配速,心率逐渐恢复。两侧的观众不断为我们加油,动力十足。 我的目标是200分钟内完赛。途中与一位戴帽子的跑友默契地跑了近5公里,后来因为我进水站,他渐渐跑远。跑到15公里左右,疲惫感袭来,可能是出差途中没休息好,体能储备不足。 虽然速度没掉,但心率升到170多,距离终点还有2公里时,已飙至180。赛后查看记录,最高达到190,现在想想有些后怕。以后比赛要更加注意,安全完赛最重要。 最终以01:55:24到达终点,比之前PB快了1分钟。赛后提供的保温毯和姜糖水让人倍感温馨,稍作休息,顺着人流领取比赛奖牌和完赛包。 总体来说,这次半马体验顺利,让我熟悉了马拉松比赛的安排,也体验了与个人跑步截然不同的感受。即便在喧嚣的赛道上,孤独依然是跑者心中最真实的伙伴。

音乐文件下载和元数据刮削思路

前言 个人音乐服务Navidrome搭建之后,必然会碰到高质量的音乐文件来源和歌曲元数据的问题,这里说一下个人解决办法。我是以腾讯音乐为基础,从腾讯下载mp3音乐文件,然后将腾讯音乐的元数据写入到mp3里,偶尔碰到在腾讯里没有版权的音乐,会在网易音乐里搜索有没有,使用网易音乐的音乐元数据,实在没有就没有办法了。 过程中会使用的一些开源服务,两个已经都不更新,一直用得挺好就没有找其他替代了。 QQMusicApi: 腾讯音乐API服务,需要部署在自有的服务器或者本机都可以,需要的时候启动,使用之前需要设置账号信息和更新登陆的Cookie。 需要会员,不提供无会员下载320的音乐 NeteaseCloudMusicApi: 网易音乐API服务,可以实现在Vercel部署使用。 请支持正版音乐!!!有需要更新音乐的时候,会购买一个的腾讯音乐会员,登陆后提取Cookie发送到QQMusicApi服务,后面使用到QQMusicApi的服务都是在登陆之后的操作。网易音乐我只是使用元数据,暂时没有购买过会员。 腾讯音乐会员可以官方购买,或者某些APP里兑换会员服务,或者是闲鱼、淘宝都可以的,哪个便宜搞哪个 整体使用Python代码实现的下面过程,因为不具备通用性,这里只说一下怎么使用的思路。 音乐来源 专辑: 如你在腾讯音乐找到周杰伦的《J III MP3 Player》,看到浏览器的URL:https://y.qq.com/n/ryqq/albumDetail/002MAeob3zLXwZ,最后的002MAeob3zLXwZ就是专辑的albummid,接下来调用QQMusicApi的获取专辑内的歌曲接口,可以获取到专辑歌曲清单的json数据。 歌单: 腾讯音乐提供了榜单和歌单,都可以QQMusicApi的获取榜单详情和获取歌单详情,根据个人喜好可以找对应的日常更新。 网易音乐也有提供排行榜和歌单,可以调用NeteaseCloudMusicApi的获取歌单所有歌曲。 Apple Music有每周热门100首和城市排行榜的歌单,找到对应歌单返回歌曲链接,分析请求参数和header信息,后续需要更新音乐的时候,重新访问地址获取Cookie里的authorization,更新到请求代码,处理返回的json数据就可以获取歌单信息了。 Spotify榜单,找自己想更新的对应榜单,同样也是看返回歌曲的链接,分析请求参数和header信息,处理返回的json数据就可以获取歌单信息,当然每次更新歌曲时候也需要更新authorization参数。 歌手: 在腾讯音乐里找歌手的singermid,调用QQMusicApi的 获取热门歌曲,修改参数page能够获取歌手的歌曲清单。 单曲: 在腾讯音乐找对应单曲的songmid,调用QQMusicApi的 单个获取,可以获取包含了很多的歌曲信息,包括歌手、专辑、语种、曲风等,但是不包含歌词。 匹配歌曲 腾讯音乐直接有对应的songmid字段,可以跳过这个步骤。 对于网易、Apple Music、Spotify里获取歌曲清单,基本都会包含歌曲id(songmid)、歌名(songname)、歌手信息等,然后遍历歌单数据拼接查询关键词:歌手名称 - 歌名,如周杰伦 - 晴天,然后调用QQMusicApi的 搜索接口获取返回搜索的数据,具体接口参数详细见链接。对返回的结果第一条数据进行,看歌名和歌手名称是否一致,如果一致就搜索成功,然后找到返回结果的mid就是腾讯音乐的songmid,基本上成功率能达到90%以上,如果没有找到需要手动在浏览器里调用接口自己找一下返回的数据看看(推荐使用firefox,查看json数据方便)。 举例: 网易音乐: 周杰伦 - 晴天,songmid=186016 腾讯音乐:周杰伦 - 晴天,songmid=0039MnYb0qxYhV 根据找到的ID,可以放到一个ID对照文件里,每次搜索之前加载对应的对照表,先通过ID查找一下,是否存在,如果不存在则调用QQMusicApi的 搜索接口,找到了对应的腾讯音乐的songmid,再把ID对应关系写会对照文件,可以加快歌单的更新速度,因为大量是已经下载好的歌曲。 对照表文件示意: 186016 0039MnYb0qxYhV 2133271060 2133271060 nt 对照的文件,我做一个特殊处理,如果在腾讯音乐没有找到的音乐,可以在网易音乐里搜索,采用网易音乐的元数据文件。 如果确实没有找到元数据,我可能就不会放到Navidrome里了。 歌曲信息 腾讯音乐的歌曲信息调用QQMusicApi的 单个获取 网易音乐的歌曲信息调用NeteaseCloudMusicApi的获取歌曲详情 同样这里把获取到的歌曲详情json文件保存到文件系统,按照一定的目录结构组织起来,加快歌曲信息获取速度,先找缓存,再调用接口。 下载歌曲 只试过腾讯会员的下载音乐,网易音乐需要大家尝试。 下载之前,检查本地是否已经下载好了音乐文件,存在就可以跳过。 调用调用QQMusicApi的 下载链接接口获取音乐文件地址,可以传入音质的参数,获取不同音质的音乐文件。 请求音乐文件地址,保存到本地。由于有时会出错,可以在代码里加入重试下载的次数。 歌曲专辑 如果需要更新音乐文件元数据,一般包括:歌曲信息、专辑信息、封面、歌词。 腾讯音乐的歌曲专辑调用QQMusicApi的 获取专辑信息 网易音乐的歌曲专辑调用NeteaseCloudMusicApi的获取专辑内容 同样这里把获取到的歌曲专辑json文件保存到文件系统,按照一定的目录结构组织起来,加快歌曲专辑获取速度,先找缓存,再调用接口。 歌曲封面 歌曲的封面,如果属于专辑的歌曲,获取专辑的封面,如果属于单曲,获取歌手的封面。 腾讯音乐:https://y.gtimg.cn/music/photo_new/T002R300x300M000${mid}.jpg?max_age=2592000 mid参数替换为专辑的id或者歌手的id 网易音乐,如果歌曲信息里al.picUrl存在,直接使用里面的封面地址,否则需要调用NeteaseCloudMusicApi的获取歌手详情,使用data.artist.cover里的歌手封面地址。 下载的封面 对于获取的封面建议也做缓存,以专辑ID、歌手ID为文件名,按照一定的目录结构组织起来,加快歌曲封面获取速度,先找缓存,再调用接口。 ...

十月 27, 2024 · 1 分钟 · 91 字 · Byter ·  Music ·  Metadata

Matplotlib绘图中文乱码解决方法

使用python的matplotlib的库生成图片时,中文字体可能会现实乱码(方块),因为matplotlib默认的字体不支持显示中文。 检查Matplotlib环境 查看matplotlib字体配置文件路径 import matplotlib print(matplotlib.matplotlib_fname()) 返回matplotlibrc 文件路径,如: /usr/local/lib/python3.9/site-packages/matplotlib/mpl-data/matplotlibrc 可以得到 ttf 字体文件的路径: /usr/local/lib/python3.9/site-packages/matplotlib/mpl-data/fonts/ttf 查看matplotlib缓存目录 import matplotlib print(matplotlib.get_cachedir()) 返回的缓存路径,如: /home/xxx/.cache/matplotlib TTF字体文件获取 从Windows系统获取字体 # 如微软雅黑 c:\windows\fonts\msyh.ttc 网络搜索TTF中文字体 配置Matplotlib使用中文字体 方法1: 使用font_manager模块加载字体使用 from matplotlib.font_manager import FontProperties import matplotlib.pyplot as plt font = FontProperties(fname='下载的ttf文件路径', size=12) plt.plot([1, 2, 3], [4, 5, 6]) plt.title('中文标题', fontproperties=font) plt.show() 适合于简单的使用plt场景 方法2: 设置matplotlib字体参数 拷贝字体文件到matplotlib的 ttf 字体文件的路径下 删除matplotlib缓存目录下的json文件 查看字体的Family Name from matplotlib import font_manager for font in font_manager.fontManager.ttflist: print(font.fname,font.name) 输出如下数据: /usr/local/lib/python3.9/site-packages/matplotlib/mpl-data/fonts/ttf/msyh.ttc Microsoft YaHei Family Name 为Microsoft YaHei。 注意,没有输出新加入的字体,需要删除缓存目录下的json文件。 4. 使用示例 import matplotlib.pyplot as plt import matplotlib # 指定默认字体 plt.rcParams['font.family'] = 'Microsoft YaHei' # 或其他支持中文的字体 plt.rcParams['axes.unicode_minus'] = False # 解决负号'-'显示为方块的问题 plt.plot([1, 2, 3], [4, 5, 6]) plt.title('中文标题') plt.show()