年度归档:2022年

吐槽设备管理和多电脑管理:无线总是比有线方便吗?

作为一个前信息类学科学生和现 IT 行业从业者,电脑一直是我生活中不可分割的一部分。同时如何方便的打理好我的电脑和其周边设备一直是个不断更新的问题。

为什么这个问题会不断更新呢?

环境决定需求

在学校的时候,我能够掌控地仅仅在宿舍里面的一个小桌子。所以那个时候,我所追求的方便就是周边外设要尽量轻薄和无线。这样子可以方便地把鼠标和键盘都塞到抽屉里面,同时不需要重新插拔线。当然不得不承认,如果忘了关了鼠标和键盘的开关,红外接收器真的很废电池 😂。那个时候还没有蓝牙,以及后面出现的早期版本蓝牙还不适用于支撑鼠标键盘的信息传输。

无线鼠标和信号接收器
无线鼠标和信号接收器

那个时候,看着我宿舍桌上那笨重的主机和荧光屏显示器,拥有一台笔记本电脑也当是一直我梦想的事情。这样子我就可以随身带着我的电脑;一旦放寒暑假,我可以方便地把它带回家 🤭。

荧光屏显示器和主机箱
荧光屏显示器和主机箱

工作之后,所使用的电脑设备已经几乎都是笔记本电脑了,而且随着苹果掀起的笔记本轻薄化风潮所造成的接口精简化,我不得不将随身携带的外设都换成了支持蓝牙的,要不然接口完全不够用。然后由于工作内容的保密性,需要工作电脑和生活电脑分离,我又不得不尽量使用支持多设备记忆的蓝牙设备,以保证我的一套外设可以在多个电脑之间方便切换。

无线一定比有线方便吗?

然而,因为目前公司的工作需要以及我的个人需要,最近我的设备管理变得前所未有的麻烦 🤦。我需要让一套外设(键盘、鼠标、摄像头、显示器)可以方便地在四台笔记本和一台主机箱之间切换,显然蓝牙已经不可能做到了。

顺便提一句,不要对五台电脑觉得奇怪,我在前前公司做涉及到移动端项目的时候,我有十几台手机、几台平板电脑和四台电脑,当然他们几乎都不属于我个人,是属于公司的。那个时候还没有云测试平台,所有兼容性测试都只能在本地设备上完成。

言归正传,好在我的大多数外设都是有线无线双模的,所以我想了折中方案。我把一套鼠标、键盘和显示器都接在一个多接口转换器上,当我需要用哪台电脑时,我就把转换器接到哪个电脑上。由于 COVID 的影响已经很小,所以我们偶尔也需要去办公楼一下。所以当我需要去公司的时候,我只需要将显示器线拔掉,连着扩展器和键鼠一起塞到背包里。搞定!

前几天,我突发奇想,既然有 HDMI 切换器这种东西来实现显示器信号源的自由切换,难道就没有一个硬件可以实现所有外设的切换吗?于是,我真的发现了 KVM 切换器,又叫多电脑切换器。这个 KVM 不是基于内核的虚拟机,它代表了 Keyboard、Video 和 Mouse。

KVM切換器(英語:KVM switch),一般簡稱KVM,又名多電腦切換器,是一種计算机硬件設備,可以使用户透過一組鍵盤螢幕滑鼠控制多台電腦。KVM,即键盘、显示器、鼠标的英文首字母缩写(Keyboard、Video、Mouse)。

摘自 维基百科
KVM 切换器 图纸
KVM 切换器 图纸

这个切换器真是拯救了我。我不需要准备多套外设来覆盖我所有的电脑,也不需要反复插拔接线来保证我的所有电脑都能被操作。我的桌面也变得更有条理了一些,虽然还是很乱。

选择合适的 KVM 切换器

KVM 切换器的种类很多,坑也很多。选购的时候,要关注技术参数,尤其是 HDMI 部分,参数不同差异很大。

  1. 首先要确定电脑数量,即,你需要将这套外设共享给几台电脑。
  2. USB 的参数。因为 USB 1 和 USB 2 的传输速率相差很大,主要看你的需求,是否有很多外置存储设备等等。
  3. HDMI 的规格。如果你使用 Apple TV 等支持 HDR 和杜比视界的设备,需要查看提供的 HDMI 是否支持 HDR 和杜比视界的传递。HDR 有很多种,例如 HDR、HDR 10、HDR 10+ 等等。同样,也要关注是否支持音频传递,以及支持的音频编码。
  4. 对于视频和游戏爱好者,支持的最高刷新率和分辨率尤为重要。需要关注一下。
  5. 是否支持热切换。直接影响切换效率和用户体验。

希望这篇吐槽能帮到一些同样苦于多设备管理的朋友。

我初期用于提升英语的方法

到新加坡一年多了,一直工作在一个几乎没人说汉语的公司。当同事通过闲聊发现我之前没有留学过也没有在任何英语环境下工作过,大多数都表示很诧异。也说明了另外一个事实:中国人哑巴英语的情况非常严重,严重到不少老外们都发现了。最近也有很多国内朋友问我怎么提升英语,虽然我的英语还是很糟糕,没留学和海外工作经验且英语比我好的人真的是太多了,而且我也不敢妄称我有能力去教别人,但是我还是决定分享一下我初期用于提升英语的方法,希望能够帮助一些想要做出一些改变的朋友入门初级英语练习 😄。

张开嘴

最初,练习英语完全是出于偶然。当时我刚刚从北京搬到杭州,在杭州我几乎没有朋友。于是我希望能够在工作伙伴外也能交到一些朋友,就决定参加英语角试试看。

我很幸运地发现了一个叫 Have Fun English Club 的英语角,结识了一些有意思的朋友。在这我衷心感谢这几位朋友,是他们给了我很多动力,帮助我熬过了人生中极其灰暗的一段日子。刚开始的时候,我是典型的轻度哑巴英语。平时说中文的时候,不带打嗝的,一切到英语就立马变得小声,而且磕磕巴巴的。不过好在我这个人脸皮够厚,很快就和大家打成一片,当时我给自己的要求是可以错,但是不能怂。🤣 为了能够更多地结交朋友,我申请成为了 HFEC 的志愿者,去担任他们活动的 Group Leader,帮助他们一起起草 Topic。久而久之,我便喜欢上了练习英语(改天我会再写一篇日志,介绍一下我们英语角的活动模式。这个模式比较独特在当地英语角圈还是挺受欢迎的)

没多久,HFEC 因为一些内部原因解散了。突然之间没有英语角可以唠嗑了,大家觉得很无聊。为了能够继续磨练自己的口语和结交更多的朋友,我们几个在 HFEC 认识的老朋友就创立了 Whatever English Club,模式更多的是借鉴 HFEC 的模式,但增加了更多游戏元素,整体效果非常棒,在当地也小有名气了。

练习口语,尤其是初期,不能太在乎面子。比如说,不要太在乎发音。如果有机会和老外交流,就会发现这个世界上千奇百怪的口音多了去了,但这些口音并不会掩盖他们优秀的英语水平。也不要太在乎说错,我们即便说中文都会有嘴瓢的时候,为什么还在乎说外语出个错呢?出错了,才有机会纠错,才有机会不断进步。

把自己当小学生

很多朋友说英语的时候总是会磕吧,原因是嘴跟不上脑子。但是为什么嘴会跟不上脑子了,要把这个问题说明白并不容易。

我曾经听到过这么一个说法:“中国人口语差,很大程度上是因为他们的中文太好了。”

我感觉特别有道理,让我分享下我的理解。很多朋友初期说英语的时候,会先在脑子里面想好怎么用汉语回答,然后再翻译成英语,最后说出来。但是汉语是我们的母语,而且汉语和英语又归属于差别很大的两大语系。所以当我们在脑子里面试图把想好的华丽文字翻译成英语的时候,瞬间就卡壳了,然后就“呃呃呃……”

所以我的方法是,强迫自己成为小学生。每次要需要用英语表达的时候,都用最简单的主谓宾句式来构思,什么成语、谚语、歇后语,全部都不要。这样子在转换成英语说出来的时候就会容易得多,不至于会卡壳。随着用英语交流的来来回回变得顺畅后,你的自信心也会得到很大的提升,会给自己更多的动力继续坚持下去。

把自己当外国人

在和英语非母语的朋友用英语交流的时候,比方说两个中国人在英语角说英语,或者最近我和波兰同事开会,都可能遇到一种情况。就是你说了一个单词或者一个词组,对方听不懂。如果没有足够的练习,接下来一定就是一阵尴尬的沉默 😄。

所以,当我成为了小学生之后,我就开始尝试让自己成为一个外国小学生。我开始慢慢拒绝所有英汉词典,改用英英词典。这样子久而久之,当别人听不懂我的英语表达时,我可以用英语用另外一种方式解释给他听。我个人感觉,这是个非常有用的英语沟通技能。另外,我也很久没有对着单词表背过单词了,我觉得翻英英词典而接触到的新单词非常容易被记住。以此同时,Lexico 也成为了我最爱访问的站点之一。

假装自己身处外语环境

经常听到一些人想当然的说:学英语就是要有英语环境,如果能在国外住上几个星期英语绝对能突飞猛进。这话对也不对,学英语的确需要英语环境。但并不是呆在国外就能行。呆在国外英语也没啥进步的人,我身边见得多了。在都是华人的团队里面,上班说汉语,下班和家人也是说汉语。也就出门购物和吃饭,会偶尔说上几句英语。即便几年过去了,英语水平几乎没啥明显进步。

我个人先从看剧只开英文字幕开始,即便初期很多都听不懂,但是英文字幕也能提升阅读速度。我虽然也很喜欢看电影,但是我看的电视剧远多于电影,因为电视剧的对白更贴近日常,更能让我自己沉浸的更真实。如果因为字幕难度太高,依然跟不上的话,可以从英文动画片开始。因为大多数的英文动画片,语速比较慢,而且相对用词比较简单。为什么我用的是大多数,因为有例外,比方说 Rick and Morty,那语速和词汇量简直是噩梦。很长一段时间之后,在看片的时候,我会刷手机。如果发现自己跟不上了,就倒回去看。我承认这样子看片很费时间,但是这样子才能慢慢让自己听英语可以和听汉语一样。比方说,我现在就在边写日志边看少年谢尔顿。因为我们在听别人用汉语唠嗑的时候,并不需要多集中精神。多亏了这个练习,我现在可以在午饭点边吃盒饭边和其他时区的同事开会了。除此之外,我在做其他一些不需要集中精神的事情,例如:通勤、做饭、刷网页等等,也会听英语播客、新闻、电视剧对白等等。顺便吐槽一下,我一直觉得听新闻非常难。因为新闻很短,而且大多数情况下上一条和下一条完全没有上下文关系。

说说我对听力变化和对英语敏感度的几个转折点:

  • 某一天,突然发现自己看片的时候,不会下意识的一直盯着下排字幕了。
  • 某一天,突然发现自己即便偶尔刷下手机也能够跟上电视剧的剧情了。
  • 某一天,突然发现自己可以捕捉到字幕里面的错误了。
  • 某一天,突然发现自己不配字幕也能大致明白剧情了。
  • 某一天,有个人突然和我说句英语,我也能 get 到他在说什么了。
  • 某一天,突然发现自己不配字幕完全不影响观影一些简单内容了。

以上的变化,是通过长期练习从量变到质变的过程。总而言之,需要有足够的耐性去练习。

当然不得不承认,身在一个真实的英语环境,如果能善用这个环境的话,你的英语提升将会变得非常快。至少,我在这一年多英语的提升速度远胜于之前,当然这也要感谢之前自己不懈练习打下的基础。

效果验证

在杭州工作的还是很愉快的,但是职业生涯永远都不可能尽善尽美的,所以我刚喜欢上练习英语后,我也尝试面试过几家海外公司,每次都意料之中的以沟通存在障碍而告终。直到多年后,随着我孩子的降生,我也希望真正让生活来点改变。我面试了四个公司,经历过印度人、爱尔兰人、美国人、意大利人、日本人、新加坡人、中国人的多轮英语面试,最终都拿到了 Offer。这个结果,给我自己坚持练习英语打了一剂强心针。

当然,要让自己的英语练习有成效,前提是,切忌自欺欺人。不要把学习英语作为你沉迷于刷剧、刷电影和刷动画片的借口。真正把他们用在英语学习上才是关键。

抓住一切练习英语的机会

进入现在的公司之后,我越发发现更多自己在英语上的短板,譬如说:英语写作。由于无法忍受自己写的稀烂的英语邮件,Grammarly 也成为了我最爱访问的站点之一。我重开博客一部分原因也是因为这个,还将其设置为了双语博客。不知道大家有没有发现,我的每篇文章都是有中英两个版本的,可以通过菜单和侧边栏选择自己想看的语言版本。我希望通过书写日志能进一步练习自己的英语写作。即便这篇日志,其实并不适合给英语母语者看,旨在不浪费任何一个练习的机会,我还是写了这篇日志的英文版 🤣。

就先分享到这吧。在这希望大家能够坚持下去。学习英语,练习是不可避免的。而且练习本来就不是一个轻松的过程,不要指望一蹴而就。动不动就放弃的,其实还是一开始就没整明白。如果此文能让任何一个人有一点点收获,我也就满足了。如果此文能帮助任何一个人入门英语练习,我就高兴坏了。

Hammerspoon : macOS 界的瑞士军刀

相信很多朋友在自己的电脑里面都有特殊化定制。这可能也是为什么很多人都非常不喜欢配置新电脑或者重装系统。

譬如我自己,有一波应用用来提升我的电脑使用体验,如下是不完全统计:

应用用途
SizeUp可以通过快捷键将窗口吸附在屏幕的上下左右以及死角。对于大屏幕非常有用,左侧文档,右侧代码
Pap.er可以自动定时将美丽的风景画设置成我的壁纸
Stretchly定时遮挡屏幕以强制休息
Lexico.com牛津英英词典官方网站
Cheatsheet用来查看当前应用的所有快捷键
New Terminal Here在当前目录打开终端
我的常用工具列表

这些工具在提升我的用机舒适度的同时,也在我造成了一些困扰,尤其重装系统和换电脑的时候。有时候是因为软件开始收费了,我需要寻找一个免费的替代品;有时候是因为停止维护很久不再支持最新系统了,我需要寻找一个新的替代品。直到有段时间,Mac 似乎都和我有仇一般,半年更换了三台电脑。忍无可忍之下,我开始寻找一个能够替代这些小工具的方法,终于被我找到了一个 MacOS 上的瑞士军刀: Hammerspoon

类似的工具其实也不少,但是 Hammerspoon 在定制化能力和易用性上找到了一个平衡点。用户只需要稍微了解一下 Lua 基础就能很快上手利用 Hammerspoon 通俗易懂的 API 和完整的 Spoon 库实现一些定制化功能。我在毫无 Lua 基础的情况下,很快通过阅读文档完成了几个功能的定制。

我们可以用官方提供的 Spoon 来定制,以窗口控制为例

-- 我们可以通过引入 WinWin 这个 Spoon 来轻松实现
hs.loadSpoon("WinWin")

-- 判断 WinWin 是否正常载入,并根据窗口控制效果配置热键
if spoon.WinWin then
  -- 文本提示能完美支持符号字符,这对后面设置热键列表非常有用,后面会说
  -- Side
  hs.hotkey.bind({"cmd", "alt", "ctrl"}, "left", "Window ⬅", function() spoon.WinWin:moveAndResize("halfleft") end) 
  hs.hotkey.bind({"cmd", "alt", "ctrl"}, "right", "Window ➡", function() spoon.WinWin:moveAndResize("halfright") end) 
  hs.hotkey.bind({"cmd", "alt", "ctrl"}, "up", "Window ⬆", function() spoon.WinWin:moveAndResize("halfup") end) 
  hs.hotkey.bind({"cmd", "alt", "ctrl"}, "down", "Window ⬇", function() spoon.WinWin:moveAndResize("halfdown") end) 
  -- Corner
  hs.hotkey.bind({"shift", "alt", "ctrl"}, "left", "Window ↖", function() spoon.WinWin:moveAndResize("cornerNW") end) 
  hs.hotkey.bind({"shift", "alt", "ctrl"}, "right", "Window ↘", function() spoon.WinWin:moveAndResize("cornerSE") end) 
  hs.hotkey.bind({"shift", "alt", "ctrl"}, "up", "Window ↗", function() spoon.WinWin:moveAndResize("cornerNE") end) 
  hs.hotkey.bind({"shift", "alt", "ctrl"}, "down", "Window ↙", function() spoon.WinWin:moveAndResize("cornerSW") end) 
  -- Stretch
  hs.hotkey.bind({"cmd", "alt", "ctrl"}, "C", "Window Center", function() spoon.WinWin:moveAndResize("center") end) 
  hs.hotkey.bind({"cmd", "alt", "ctrl"}, "M", "Window ↕↔", function() spoon.WinWin:moveAndResize("maximize") end) 
  -- Screen
  hs.hotkey.bind({"alt", "ctrl"}, "right", "Window ➡ 🖥", function() spoon.WinWin:moveToScreen("next") end) 
  -- Other
  hs.hotkey.bind({"cmd", "alt", "ctrl"}, "/", "Window Undo", function() spoon.WinWin:undo() end) 
end
Code language: Lua (lua)

是不是很简单?只需要定义几个热键,选择一下需要的控制效果就 OK 了。

我们也可以利用 Hammerspoon 的 API 自定义 Spoon ,以 BreakTime 为例

为了实现这个,我们需要定时使用一个页面或者图片遮挡整个屏幕以提示电脑前的家伙应该短暂休息一下了。

首先,我们可以轻松通过 hs.timer 开启一个定时器:

obj.Timer = hs.timer.new(60, refresh)
obj.Timer:start()
Code language: Lua (lua)

然后,我们可以通过 hs.webview 创建一个遮挡这个屏幕的网页,页面中展示一个半透明的图片以达到透明效果

function makeBrowserOfBreakTime ()
  local screen = require"hs.screen"
  local webview = require"hs.webview"

  local mainScreenFrame = screen:primaryScreen():frame()
  browserFrame = {
     x = mainScreenFrame.x,
     y = mainScreenFrame.y,
     h = mainScreenFrame.h,
     w = mainScreenFrame.w
  }

  local options = {
      developerExtrasEnabled = true,
  }

  -- local browser = webview.new(browserFrame, options):windowStyle(1+2+4+8)
  local browser = webview.new(browserFrame, options):windowStyle(1+2+128)
    :closeOnEscape(true)
    :deleteOnClose(true)
    :bringToFront(true)
    :allowTextEntry(true)
    :transparent(true)

  return browser
end
Code language: Lua (lua)

接下来,我们就可以通过定时器来创建 browser:show() 和销毁 browser:delete() 页面来实现遮挡效果。

function refresh()

  obj.curTime = obj.curTime + 1
  if obj.curTime > obj.microbreakInterval then
  
    obj.curMicrobreakCount = obj.curMicrobreakCount + 1
    if obj.curMicrobreakCount > obj.microbreakCount then
      hs.alert.show(obj.breakTime .. " minute break starts")

      local browser = makeBrowserOfBreakTime();
      browser:url("file://" .. hs.spoons.scriptPath() .. "BreakTime.html?time=" .. (obj.breakTime * 60 - 1)):show()
      hs.timer.doAfter(obj.breakTime * 60, function()
        if browser ~= nil then 
          browser:delete(); 
        end 
      end)

      obj.curMicrobreakCount = 0
    else
      hs.alert.show(obj.microbreakTime .. " second microbreak starts")

      local browser = makeBrowserOfBreakTime();
      browser:url("file://" .. hs.spoons.scriptPath() .. "BreakTime.html?time=" .. (obj.microbreakTime - 1)):show()
      hs.timer.doAfter(obj.microbreakTime, function() 
        if browser ~= nil then 
          browser:delete(); 
        end 
      end)
    end

    obj.curTime = obj.curTime - obj.microbreakInterval

  end
end
Code language: Lua (lua)

最后,我们就可以像前面调用 WinWin 一样载入 BreakTime 这个自定义 spoon 并启动就可以了。

我们还可以定义任务栏菜单和提升一下用户体验

以 BreakTime 为例,我们可以将下一个休息时间显示出来

BreakTime 菜单提示
BreakTime 菜单提示

不光如此,我们还可以把所有在 Hammerspoon 定义的热键都展示出来。

所有热键的菜单提示
所有热键的菜单提示

由于他对符号字符支持的很完美,所以你在菜单里面可以设置很多有意思的提示,是不是很赞?😄

obj.menubar:setTitle("⌨️")
obj.menubar:setTooltip("Hot Key Info")

local hotkeys = hs.hotkey.getHotkeys()
local menuItem = {}
  
for key, value in pairs(hotkeys) do  
  local item = { title = value["msg"] }
  table.insert(menuItem, item)
end 

obj.menubar:setMenu(menuItem)Code language: Lua (lua)

除以上这些,Hammerspoon 还有很多东西值得探索。各位如果有兴趣的话,可以用我的定制随便试试。我也在不断摸索完善我自己的定制。

其实不光这些小工具,每次重新安装我的常用 App,例如 VS Code、Plex、Sublime Text、VIM 等等,也是个很痛苦的事情。我现在通过维护一套 homebrew 列表来快速完成大多数的 App 安装。😂

ImgCache 0.2.1 发布

我终于给 ImgCache 进行了一次版本更新。当时我承诺会在下一个版本完成对 HTTPS 图片链接的支持,没想到一晃就是十二年。我还在开博日志中吐槽了一下自己。现在我终于信守承诺,在新版本中搞定了 😂。Better late than never!

时隔 12 年发布 ImgCache 0.2.1
时隔 12 年发布 ImgCache 0.2.1

当然除了支持了 HTTPS 图片链接的缓存,也升级了 Snoopy 类,更新了代码格式使得更符合代码规范和 README,还修复了两个有意思的小 bug。

第一个 bug 是对 SVG 图片后缀名的错误提取。这几天在开发 HTTPS 支持功能的时候,我用 PNG 测试,功能完全正常。但是我偶然使用了一个 SVG 图片链接来作为测试,发现缓存的图片无法在前端展示,看了下源代码缓存的图片文件后缀名不是 .svg 而是 .svg+xml 。

坦白说,我已经完全想不起来,在这套十二年代的远古代码里面我是通过什么方式来确定缓存图片文件后缀名的。简单翻了下代码,原来是用图片链接请求 HTTP 头字段中的 Content-Type 去判断。通常图片链接的 HTTP 头字段中都包含类似于 Content-Type: image/png 的信息来定义 MIME 类型,我们只要通过 / 前部分来判断是否是图片,后半部分来判断图片类型直接得到后缀名就可以了。本来插件也基本上就是自用,所以当时估计就随便测试了常用格式,发现一切 OK,就发布版本了。

但是很奇怪的是,SVG 的 Content-Type 并不是 image/svg 而是 image/svg+xml,所以当我把提取出 svg+xml 作为后缀名的时候,前端展示就出现了问题。

根据 Wikipedia 中,SVG 中的矢量图信息是以 XML 格式保存的,所以本质上 SVG 是一个 XML 文件。这样子一切就说得通了。

Scalable Vector Graphics (SVG) is an XML-based vector image format for two-dimensional graphics with support for interactivity and animation. The SVG specification is an open standard developed by the World Wide Web Consortium (W3C) since 1999.

SVG images are defined in a vector graphics format and stored in XML text files. SVG images can thus be scaled in size without loss of quality, and SVG files can be searched, indexed, scripted, and compressed. The XML text files can be created and edited with text editors or vector graphics editors, and are rendered by the most-used web browsers.

https://en.wikipedia.org/wiki/Scalable_Vector_Graphics

于是我不得不对 SVG 的 Content-Type 做一个预处理后再作为后缀名来使用。其实存在这个问题的还不止 SVG,打算在后续版本中处理掉。

第二个 bug 是因为 WordPress 编辑器生成的 IMG 标签是不关闭的,且最后的属性和标签末尾之间缺少空格,如下:

<meta http-equiv="content-type" content="text/html; charset=utf-8"><img src="http://nginx.org/nginx.png">
Code language: HTML, XML (xml)

而当时的我,认为所有的 HTML 标签都应该是关闭了,且最后的属性和标签结束应该是存在空格的,如下:

<meta http-equiv="content-type" content="text/html; charset=utf-8"><img src="http://nginx.org/nginx.png" />
<img src="http://nginx.org/nginx.png" ></img>
Code language: HTML, XML (xml)

基于这个认知,之前版本中提取图片 URL 的正则鲁棒性不够,所以无法成功从这个 WordPress 生成的 IMG 标签中提取出正确的图片 URL,使得插件认为图片链接都是无效的,就停止了缓存。😅

关于这个版本的故事就先扯的这里。至于下个版本,我可能会加上对缓存图片过期时间的自定义能力。由于这个插件当时主要是为了用来缓存 Feedburner 订阅数之类的图片,更新频率比较高,所以我把过期时间固定在了 1 小时,即 3600 秒。现在想想,过期时间能自定义肯定是更合理一点。

好了,下个版本见吧。

风云再起

风云阁重新上线啦!

其实这不是我第一次写博客了,从标题里面就能看到一些端倪。作为开博第一篇,正好扯扯我的博客历史。由于太久远了,时间上可能和实际情况有点点出入。我的博客走向大致如下:

新浪博客 –> Live Space –> WordPress
托管 托管 自建

大二的时候,博客在国内刚刚兴起,几个有名的门户都开启了博客板块。我就凑热闹申请了一个托管在新浪博客上面。因为个人很喜欢风云漫画,所以起名为风云阁。那个时候并没有很好的经营,纯当一个记录有意思文章的地方。

没过多久,发现新浪博客限制实在太多了。作为一个计科专业学生完全忍不了。刚好赶上微软的 Live Space 发布,就直接搬迁过去了。当时博文也不多,所以纯人肉迁移完成。博客也慢慢从记录文章的地方,变成了一个记录我心情的地方。我开始在里面写一些自己的东西。

然后时间快进到了研二,自建博客慢慢流行起来。在同班同学 Solrex 的建议下,我申请了个域名,并开始着手将我的博客迁移到朋友顾俊Hostmonster 的 VPC 上面,CMS 打算用 WordPress。当时的域名是 iron-feet.cn,后来事实证明用 CN 域名就是个深坑,后面会简单说下。

当时 Live Space 上面已经积累了很多日志了,对于我这个懒人来说,手动一篇一篇迁移简直是不可能完成的任务,更别提还要原样保留各种 tag、日志发布时间等信息。所以为了快速完成迁移,我还用 C# 写了一个 GUI 的从 Live Space 到 WordPress 的迁移工具。那个时候,自身也没有什么开源思维,并没有把这个工具开源出来。后来某个更换电脑,代码都找不到了。想想当时如果开源出来,说不定在微软下线 Live Space 的时候能够帮助到很多朋友。有点遗憾。

自从把博客从托管改为自建之后,整个心态上面都有了很大的变化。我开始花费很多时间来经营这个博客,保证每周能发表一篇,尽量以技术日志为主。不再转载别人的文章,顶多在自己的文章里面注明出处的引用别人的优秀内容。同时也在 WordPress 上面也花了很多功夫。WordPress 虽然很赞,但只是想对比其他一些 CMS 而言,当时的老版本也并没有非常好用。莫名其妙的编码问题、升版本卡死后引起数据库脏数据、一些插件升级后拖慢整个后台、各种升级后二次修改内容被覆盖,若细细道来够好几篇日志了。

那个时候订阅博客很流行用 RSS,所以很多博主都喜欢用 RSS 订阅量在跟踪自己的博客质量和访问情况,我也是其中之一。由于 WordPress 自己的统计功能接近于不可用,所以大家很流行用 Feedburner 去烧制一个 Feed。除此之外,Feedburner 强大的纠错能力还能够帮助博主修复一些 RSS 里面的 XML 错误。

当时鉴于 Feedburner 的流行和业界认可度,博主们还会把 Feedburner 的订阅数量放在页面上,以显示自己博客的质量,如下图:

Feedburner 订阅数在博客上的样例
Feedburner 订阅数

想使用这个不错的功能,对于我这种订阅用户主要在墙内的博主成了难题,因为 Feedburner 订阅数量图是在谷歌域名下的,所以在墙内展示不了。

当时不得不手撸了一个叫 ImgCache 的插件来解决这个问题。激活了这个插件之后,只要你在 <img> 标签里面加上 ref=imgcache4wordpress ,插件就会自动把图片缓存在站点本地,把图片链接替换为本地路径。这样子墙网友也能看到这张图片了。当时站内的 Feedburner、Twitter 等等的图片都是用这个方式来展示的。

ImgCache 也算是遗留插件之一了,最近一次更新是十二年前……请无视我的塑料英语和当时稀烂的代码水平。插件页面里面,还写着将在新版本中解决已知问题。果然只要不更新版本,问题永远可以不解决,😅。看来是时候修复一个新版本出来了。

除此之外,我还手撸了另外一个插件叫 Custom URL Shorter 。我知道应该叫 shortener ,请无视 🤦‍♂️。当时不允许修改插件名,不知道现在行不行。一失足成千古恨!(现在允许修改了,我也已经把名字改成了 Custom URL Shortener)

接下来时间一下子跳跃到了研究生毕业后第三年,我心痛地关闭了风云阁。个中原因,让我内心五味杂陈:

  1. GFW 简单粗暴的封 IP 方式。一旦该 IP 下有任何一个站点存在敏感内容,整个 IP 就会被封禁。于是乎,我经常需要和 VPS 供应商沟通更换 IP,而且沟通频率越来越高。
    不知道是不是受 GFW 影响,站点打开也经常时好时不好。找墙外朋友测试就完全没问题
  2. 莫名其妙的备案机制。这个备案机制老变,经常会通知补交材料,或者是更新信息,或者是又有新的规定要在页面里面添加什么信息。
    每次就发一个邮件告知,宽限期还贼短。一个不小心站点页面就变成工信部未备案网站告示了
  3. 无聊的黑客:进入互联网公司之后,瞬间变得很忙,就没有时间及时升级 WordPress。博客被攻击过几次,虽然有备份,但是恢复还是很花时间的

天天工作上卷,下班后还要应付 GFW、备案这些和技术完全没关系的破事。最终我认怂,很无奈的选择了关停……这事情一直是我的心头梗,难以抹去。

其实刚到新加坡的时候,我就打算重开博客了。只是因为入职一家新公司,还是纯英语沟通,就耽误了一下。然后老婆孩子来了,两个人自己带娃真的是超乎我想象的难,又继续耽误了。终于现在下定决心重开了。由于我好久没自建站点了,对现在的供应商也不了解了。感谢赖信涛推荐给我 DigitalOcean