<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Kaihao&#39;s Blog</title>
  
  
  <link href="/atom.xml" rel="self"/>
  
  <link href="https://kaihao.io/"/>
  <updated>2019-10-16T09:10:34.043Z</updated>
  <id>https://kaihao.io/</id>
  
  <author>
    <name>Kaihao</name>
    
  </author>
  
  <generator uri="http://hexo.io/">Hexo</generator>
  
  <entry>
    <title>OmniFocus中根据艾宾浩斯遗忘曲线快捷添加复习任务</title>
    <link href="https://kaihao.io/2018/omnifocus-review-with-ebbinghaus/"/>
    <id>https://kaihao.io/2018/omnifocus-review-with-ebbinghaus/</id>
    <published>2018-08-06T07:58:06.042Z</published>
    <updated>2019-10-16T09:10:34.043Z</updated>
    
    <content type="html"><![CDATA[<p>OmniFocus中需要根据艾宾浩斯遗忘曲线来添加多个任务。找了下网上的AppleScript，基本上因为版本太老不能正常使用，于是自己简单写了一下。</p><p>使用方法：选中一个或多个任务后，运行程序可生成若干个同样名称的复习任务。复习任务的“推迟至”时间按照艾宾浩斯的记忆曲线来设定，可以自行在AppleScript中修改。</p><p>另外也可以设置“截止时间”，即“推迟至”时间后的若干天。若该天数设置为负，则代表不设置截至时间。</p><p><a href="https://kaihao.io/downloads/ebbinghaus.zip" class="btn">程序下载地址</a></p><p>安装方法是在macOS中打开OmniFocus，选择菜单栏中的“帮助”→“打开Scripts文件夹”。将下载后的文件解压，得到的scpt文件复制到该文件夹中。之后右键OmniFocus工具栏，将“Ebbinghaus” Script拖进工具栏。之后点击“Ebbinghaus”即可运行AppleScript。</p><p>当然，也可以采用Alfred、Keyboard Maestro等工具运行AppleScript。</p><p>下面是AppleScript具体内容。</p><a id="more"></a><figure class="highlight applescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">(* </span></span><br><span class="line"><span class="comment">Schedule tasks for reviewing material in spirit of Ebbinghaus forgetting curves</span></span><br><span class="line"><span class="comment">by Kaihao, August 2018</span></span><br><span class="line"><span class="comment">https://kaihao.io/2018/omnifocus-review-with-ebbinghaus/</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">Revised from Curt Clifton's "Complete and Await Reply" script(http://curtclifton.net/complete)</span></span><br><span class="line"><span class="comment">*)</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Number of defer days</span></span><br><span class="line"><span class="keyword">property</span> deferIntervals : &#123;<span class="number">1</span>, <span class="number">2</span>, <span class="number">4</span>, <span class="number">8</span>, <span class="number">16</span>, <span class="number">32</span>&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment"># Number of days from defer date that the newly created "review" action will be due. Set to a negative number to put no due date on the new action.</span></span><br><span class="line"><span class="keyword">property</span> daysUntilDue : <span class="number">-1</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">set</span> itemTitle <span class="keyword">to</span> <span class="literal">missing value</span></span><br><span class="line"><span class="keyword">tell</span> <span class="built_in">application</span> <span class="string">"OmniFocus"</span></span><br><span class="line"><span class="keyword">tell</span> <span class="keyword">front</span> document</span><br><span class="line"><span class="keyword">tell</span> content <span class="keyword">of</span> document window <span class="number">1</span> <span class="comment">-- (first document window whose index is 1)</span></span><br><span class="line"><span class="keyword">set</span> theSelectedItems <span class="keyword">to</span> value <span class="keyword">of</span> <span class="keyword">every</span> selected tree</span><br><span class="line"><span class="keyword">if</span> ((<span class="built_in">count</span> <span class="keyword">of</span> theSelectedItems) &lt; <span class="number">1</span>) <span class="keyword">then</span></span><br><span class="line"><span class="built_in">display alert</span> <span class="string">"You must first select an item to complete."</span> <span class="keyword">as</span> warning</span><br><span class="line"><span class="built_in">return</span></span><br><span class="line"><span class="keyword">end</span> <span class="keyword">if</span></span><br><span class="line"><span class="keyword">set</span> reversedDeferIntervals <span class="keyword">to</span> <span class="built_in">reverse</span> <span class="keyword">of</span> deferIntervals</span><br><span class="line"><span class="keyword">repeat</span> <span class="keyword">with</span> anItem <span class="keyword">in</span> theSelectedItems</span><br><span class="line"><span class="keyword">set</span> itemTitle <span class="keyword">to</span> <span class="built_in">name</span> <span class="keyword">of</span> anItem</span><br><span class="line"><span class="keyword">repeat</span> <span class="keyword">with</span> i <span class="keyword">from</span> <span class="number">1</span> <span class="keyword">to</span> (<span class="built_in">length</span> <span class="keyword">of</span> deferIntervals)</span><br><span class="line"><span class="keyword">set</span> theDupe <span class="keyword">to</span> duplicate anItem <span class="keyword">to</span> <span class="keyword">after</span> anItem</span><br><span class="line"></span><br><span class="line"><span class="comment">-- Set defer date</span></span><br><span class="line"><span class="keyword">set</span> deferForDays <span class="keyword">to</span> <span class="built_in">item</span> i <span class="keyword">of</span> reversedDeferIntervals</span><br><span class="line"><span class="keyword">set</span> deferUntilDate <span class="keyword">to</span> <span class="built_in">current date</span></span><br><span class="line"><span class="keyword">set</span> <span class="built_in">time</span> <span class="keyword">of</span> deferUntilDate <span class="keyword">to</span> <span class="number">0</span></span><br><span class="line"><span class="keyword">set</span> deferUntilDate <span class="keyword">to</span> (deferUntilDate) + deferForDays * days</span><br><span class="line"><span class="keyword">set</span> defer <span class="built_in">date</span> <span class="keyword">of</span> theDupe <span class="keyword">to</span> deferUntilDate</span><br><span class="line"></span><br><span class="line"><span class="comment">-- Set due date</span></span><br><span class="line"><span class="keyword">if</span> (daysUntilDue &lt; <span class="number">0</span>) <span class="keyword">then</span></span><br><span class="line"><span class="keyword">set</span> due <span class="built_in">date</span> <span class="keyword">of</span> theDupe <span class="keyword">to</span> <span class="literal">missing value</span></span><br><span class="line"><span class="keyword">else</span></span><br><span class="line"><span class="keyword">set</span> due <span class="built_in">date</span> <span class="keyword">of</span> theDupe <span class="keyword">to</span> (defer <span class="built_in">date</span> <span class="keyword">of</span> theDupe) + daysUntilDue * days</span><br><span class="line"><span class="keyword">end</span> <span class="keyword">if</span></span><br><span class="line"><span class="keyword">end</span> <span class="keyword">repeat</span></span><br><span class="line"><span class="keyword">end</span> <span class="keyword">repeat</span></span><br><span class="line"><span class="keyword">end</span> <span class="keyword">tell</span></span><br><span class="line"><span class="keyword">end</span> <span class="keyword">tell</span></span><br><span class="line"><span class="keyword">end</span> <span class="keyword">tell</span></span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;OmniFocus中需要根据艾宾浩斯遗忘曲线来添加多个任务。找了下网上的AppleScript，基本上因为版本太老不能正常使用，于是自己简单写了一下。&lt;/p&gt;
&lt;p&gt;使用方法：选中一个或多个任务后，运行程序可生成若干个同样名称的复习任务。复习任务的“推迟至”时间按照艾宾浩斯的记忆曲线来设定，可以自行在AppleScript中修改。&lt;/p&gt;
&lt;p&gt;另外也可以设置“截止时间”，即“推迟至”时间后的若干天。若该天数设置为负，则代表不设置截至时间。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://kaihao.io/downloads/ebbinghaus.zip&quot; class=&quot;btn&quot;&gt;程序下载地址&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;安装方法是在macOS中打开OmniFocus，选择菜单栏中的“帮助”→“打开Scripts文件夹”。将下载后的文件解压，得到的scpt文件复制到该文件夹中。之后右键OmniFocus工具栏，将“Ebbinghaus” Script拖进工具栏。之后点击“Ebbinghaus”即可运行AppleScript。&lt;/p&gt;
&lt;p&gt;当然，也可以采用Alfred、Keyboard Maestro等工具运行AppleScript。&lt;/p&gt;
&lt;p&gt;下面是AppleScript具体内容。&lt;/p&gt;
    
    </summary>
    
      <category term="Software" scheme="https://kaihao.io/categories/Software/"/>
    
      <category term="AppleScript" scheme="https://kaihao.io/categories/Software/AppleScript/"/>
    
    
      <category term="macOS" scheme="https://kaihao.io/tags/macOS/"/>
    
      <category term="OmniFocus" scheme="https://kaihao.io/tags/OmniFocus/"/>
    
      <category term="AppleScript" scheme="https://kaihao.io/tags/AppleScript/"/>
    
      <category term="Forgetting Curve" scheme="https://kaihao.io/tags/Forgetting-Curve/"/>
    
  </entry>
  
  <entry>
    <title>OmniOutliner和OmniFocus快捷键添加超链接</title>
    <link href="https://kaihao.io/2018/add-link-in-omnioutliner-and-omnifocus/"/>
    <id>https://kaihao.io/2018/add-link-in-omnioutliner-and-omnifocus/</id>
    <published>2018-05-19T13:57:03.000Z</published>
    <updated>2019-11-09T03:21:27.548Z</updated>
    
    <content type="html"><![CDATA[<p>Omni Group旗下的OmniOutliner和OmniFocus目前用得挺顺手，但是有一点不爽的是没法选中文字添加超链接<del>（OmniFocus的菜单栏中有这个选项，但实际上没有效果）</del>。以往添加超链接是复制URL到app中，然后右键URL选择编辑。<del>但是OmniFocus的Note里编辑超链接又有奇怪的Bug，改动后有时又会恢复原样。</del></p><p>更新：OmniFocus for Mac 3.0.1中添加超链接的功能已经能够正常使用。<br>再次更新：OmniOutliner for Mac 5.5中添加超链接的功能已经能够正常使用。</p><p>折腾后解决了这个问题，实现在OmniOutliner和OmniFocus中按⌘+K弹出对话框，在对话框中输入URL后添加超链接的功能。</p><a id="more"></a><p>主要参考Keyboard Maestro论坛里的<a href="https://forum.keyboardmaestro.com/t/attaching-a-url-to-selected-text-in-omnioutliner/3661" target="_blank" rel="external nofollow noopener noreferrer">这个脚本</a>。不过该脚本遇到中文内容会乱码，于是替换了其中的AppleScript内容。</p><p>其实在原先脚本的HTML<code>&lt;meta&gt;</code>标签中注明<code>UTF-8</code>编码就能解决乱码问题。不过等发现是这个问题时已经重写了AppleScript，还是把AppleScript放上来吧。</p><p>在执行该AppleScript之前，Keyboard Maestro中已经将选中的文本存入变量<code>title</code>里，将URL链接存入变量<code>url</code>里。</p><figure class="highlight applescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">tell</span> <span class="built_in">application</span> <span class="string">"Keyboard Maestro Engine"</span></span><br><span class="line"><span class="keyword">set</span> strURL <span class="keyword">to</span> value <span class="keyword">of</span> variable <span class="string">"url"</span></span><br><span class="line"><span class="keyword">set</span> strTitle <span class="keyword">to</span> value <span class="keyword">of</span> variable <span class="string">"title"</span></span><br><span class="line"><span class="keyword">end</span> <span class="keyword">tell</span></span><br><span class="line"><span class="keyword">set</span> <span class="built_in">the clipboard</span> <span class="keyword">to</span> <span class="string">"&lt;meta charset=\"utf-8\"&gt;&lt;a href=\""</span> &amp; strURL &amp; <span class="string">"\"&gt;"</span> &amp; strTitle &amp; <span class="string">"&lt;/a&gt;"</span></span><br><span class="line"><span class="keyword">set</span> theHEX <span class="keyword">to</span> <span class="built_in">do shell script</span> <span class="string">"LC_ALL=en_US.UTF-8 pbpaste | hexdump -ve '1/1 \"%.2x\"'"</span></span><br><span class="line"><span class="built_in">run script</span> <span class="string">"set the clipboard to «data HTML"</span> &amp; theHEX &amp; <span class="string">"»"</span></span><br></pre></td></tr></table></figure><p>修改ApplesSript后Keyboard Maestro脚本在OmniOutliner中运行正常，不过OmniFocus中默认会对生成的内容采用Songti SC字体，有点看不习惯。所以AppleScript中加入字体信息。</p><figure class="highlight applescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">tell</span> <span class="built_in">application</span> <span class="string">"Keyboard Maestro Engine"</span></span><br><span class="line"><span class="keyword">set</span> strURL <span class="keyword">to</span> value <span class="keyword">of</span> variable <span class="string">"url"</span></span><br><span class="line"><span class="keyword">set</span> strTitle <span class="keyword">to</span> value <span class="keyword">of</span> variable <span class="string">"title"</span></span><br><span class="line"><span class="keyword">end</span> <span class="keyword">tell</span></span><br><span class="line"><span class="keyword">set</span> <span class="built_in">the clipboard</span> <span class="keyword">to</span> <span class="string">"&lt;meta charset=\"utf-8\"&gt;&lt;font face=\"Open Sans\"&gt;&lt;a href=\""</span> &amp; strURL &amp; <span class="string">"\"&gt;"</span> &amp; strTitle &amp; <span class="string">"&lt;/a&gt;&lt;/font&gt;"</span></span><br><span class="line"><span class="keyword">set</span> theHEX <span class="keyword">to</span> <span class="built_in">do shell script</span> <span class="string">"LC_ALL=en_US.UTF-8 pbpaste | hexdump -ve '1/1 \"%.2x\"'"</span></span><br><span class="line"><span class="built_in">run script</span> <span class="string">"set the clipboard to «data HTML"</span> &amp; theHEX &amp; <span class="string">"»"</span></span><br></pre></td></tr></table></figure><p>我这边是使用了Open Sans字体，macOS中没有自带，将其换成想要的字体就好。</p><p>另外提一下，OmniFous的Note的超链接配合<a href="http://jesse.hollington.ca/2016/05/getting-focused-with-omnifocus.html#scripting-better-flow" target="_blank" rel="external nofollow noopener noreferrer">这个AppleScript</a>可以实现快捷键跳转，结合URL schemes可以跳转到特定app的特定页面，比如OmniFous的Project、Context、Task以及Evernote的笔记页面等。</p><p>附上Keyboard Maestro的Macro<strong>下载地址</strong>：<a href="https://kaihao.io/downloads/Attach-URL-to-text-selected-in-OmniOutliner.kmmacros" class="btn">OmniOutliner</a><a href="https://kaihao.io/downloads/Attach-URL-to-text-selected-in-OmniFocus.kmmacros" class="btn">OmniFocus</a></p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;Omni Group旗下的OmniOutliner和OmniFocus目前用得挺顺手，但是有一点不爽的是没法选中文字添加超链接&lt;del&gt;（OmniFocus的菜单栏中有这个选项，但实际上没有效果）&lt;/del&gt;。以往添加超链接是复制URL到app中，然后右键URL选择编辑。&lt;del&gt;但是OmniFocus的Note里编辑超链接又有奇怪的Bug，改动后有时又会恢复原样。&lt;/del&gt;&lt;/p&gt;
&lt;p&gt;更新：OmniFocus for Mac 3.0.1中添加超链接的功能已经能够正常使用。&lt;br&gt;再次更新：OmniOutliner for Mac 5.5中添加超链接的功能已经能够正常使用。&lt;/p&gt;
&lt;p&gt;折腾后解决了这个问题，实现在OmniOutliner和OmniFocus中按⌘+K弹出对话框，在对话框中输入URL后添加超链接的功能。&lt;/p&gt;
    
    </summary>
    
      <category term="Software" scheme="https://kaihao.io/categories/Software/"/>
    
      <category term="AppleScript" scheme="https://kaihao.io/categories/Software/AppleScript/"/>
    
    
      <category term="macOS" scheme="https://kaihao.io/tags/macOS/"/>
    
      <category term="OmniFocus" scheme="https://kaihao.io/tags/OmniFocus/"/>
    
      <category term="AppleScript" scheme="https://kaihao.io/tags/AppleScript/"/>
    
      <category term="OmniOutliner" scheme="https://kaihao.io/tags/OmniOutliner/"/>
    
      <category term="Keyboard Maestro" scheme="https://kaihao.io/tags/Keyboard-Maestro/"/>
    
  </entry>
  
  <entry>
    <title>在互联网上如何保护自己的隐私与安全？</title>
    <link href="https://kaihao.io/2018/protect-your-privacy-online/"/>
    <id>https://kaihao.io/2018/protect-your-privacy-online/</id>
    <published>2018-04-03T06:19:36.000Z</published>
    <updated>2020-11-02T13:34:55.190Z</updated>
    
    <content type="html"><![CDATA[<p>最近隐私问题屡屡成为热点，整理了下保护隐私和安全的一些措施。</p><h3 id="一、账号体系"><a href="#一、账号体系" class="headerlink" title="一、账号体系"></a>一、账号体系</h3><ol><li>区分不同重要性的账号。尽量使用邮箱注册或者使用Google Voice等服务，对于大陆手机号码的话可以使用阿里小号、移动和多号等服务。</li><li>重要账号开启两步验证，特别重要的账号可以用物理密钥。</li><li>对于能够联系到你真人的（如各种IM、社交App）账号与个人私密账号区分开。</li><li>临时性账号使用一次性邮箱。</li><li>为防止撞库，不同网站的密码不一样，更安全的是每个网站生成随机密码。为防止人肉，不同网站用户名/昵称不一样。为了方便管理可以iCloud Keychain或Chrome密码管理。当然更推荐使用1Password、LastPass、KeePass等密码管理软件。</li></ol><a id="more"></a><h3 id="二、其它措施"><a href="#二、其它措施" class="headerlink" title="二、其它措施"></a>二、其它措施</h3><ol><li>线上线下没必要的不要填真实信息，如快递姓名可以用某先生/小姐、张三等，网上身份信息可用<a href="https://www.fakenamegenerator.com/" target="_blank" rel="external nofollow noopener noreferrer">fakenamegenerator</a>等网站生成。</li><li>离开电脑锁屏，电脑借给别人用时新开一个非管理员账户。</li><li>电脑、手机开启加密防止丢失时别人取出硬盘读取里面信息，Windows自带BitLocker，macOS自带FileVault。</li><li>软件更新至最新版本，开启自动更新。</li><li>不在USB接口插入陌生的设备。不用陌生的充电器和充电线充电，具体可参考<a href="https://mg.lol/blog/" target="_blank" rel="external nofollow noopener noreferrer">链接</a>。实在要用的话使用“USB data blocker”。</li><li>手机App关闭不必要的权限，电脑软件也一样。App、软件、系统里都把信息收集、体验改进计划关掉。不使用破解软件（当然仅仅输一个序列号还是安全的）。</li><li>不使用搜狗等联网输入法，使用系统自带输入法或者不上传数据的其它输入法，禁止联网权限。</li><li>不可信文件在虚拟机中打开，不可信链接在隐身模式下打开。</li><li>离开熟悉环境关闭手机WiFi，防止自动连上不安全WiFi。不得不用陌生WiFi时使用靠谱的VPN，或者浏览器隐身模式下不登陆账户仅仅浏览，或者只使用全程HTTPS加密的服务。</li><li>开启SIM卡PIN码，防止手机丢失时别人利用手机验证码进入我们的账户。</li><li>上传照片时注意是否已消除GPS、拍摄时间等EXIF信息。</li><li>关键文件不要用迅雷下载，从原始地址下载，并且对比Hash值。</li><li>用公用电脑或者别人电脑上网时，如果登陆账户，不保存密码，用完后退出账户，删除历史、cookies等，或者直接用隐身模式。</li><li>笔记本电脑的摄像头用胶布粘住。</li><li>浏览器开启DNT（Do Not Track），禁止第三方Cookies。使用uBlock Origin、HTTPS Everywhere等拓展，另外可使用NoScript（Firefox）、uMatrix（Chrome）选择性启动插件和脚本。</li><li>不要随意添加没有开源的浏览器插件。安装插件时检查权限。</li><li>网上绑定信用卡时用虚拟信用卡。信用卡不用时可以在手机银行中锁卡。</li><li>去不知名的酒店入住时注意是否有摄像头偷拍，摄像头偷拍，具体检查方法可参考<a href="https://www.zhihu.com/question/19670034" target="_blank" rel="external nofollow noopener noreferrer">知乎链接</a>。</li><li>将网上发布过的个人信息删除，如果不能删除的联系网站管理员删除。</li></ol><h3 id="防什么"><a href="#防什么" class="headerlink" title="防什么"></a>防什么</h3><p>密码泄漏、脱库从而导致其他账户被攻破、利用网络上的公开信息人肉、个人数据被买卖用来推销、广告等。<br>不涉及隐匿性保护（严格的匿名性，针对危险性的、违法的网络行为）</p><h3 id="总结一下"><a href="#总结一下" class="headerlink" title="总结一下"></a>总结一下</h3><p>隐私保护和方便是矛盾的，但是可以牺牲一部分方便换取足够好的隐私保护。<br>保密不上网，上网不保密。</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;最近隐私问题屡屡成为热点，整理了下保护隐私和安全的一些措施。&lt;/p&gt;
&lt;h3 id=&quot;一、账号体系&quot;&gt;&lt;a href=&quot;#一、账号体系&quot; class=&quot;headerlink&quot; title=&quot;一、账号体系&quot;&gt;&lt;/a&gt;一、账号体系&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;区分不同重要性的账号。尽量使用邮箱注册或者使用Google Voice等服务，对于大陆手机号码的话可以使用阿里小号、移动和多号等服务。&lt;/li&gt;
&lt;li&gt;重要账号开启两步验证，特别重要的账号可以用物理密钥。&lt;/li&gt;
&lt;li&gt;对于能够联系到你真人的（如各种IM、社交App）账号与个人私密账号区分开。&lt;/li&gt;
&lt;li&gt;临时性账号使用一次性邮箱。&lt;/li&gt;
&lt;li&gt;为防止撞库，不同网站的密码不一样，更安全的是每个网站生成随机密码。为防止人肉，不同网站用户名/昵称不一样。为了方便管理可以iCloud Keychain或Chrome密码管理。当然更推荐使用1Password、LastPass、KeePass等密码管理软件。&lt;/li&gt;
&lt;/ol&gt;
    
    </summary>
    
      <category term="Notes" scheme="https://kaihao.io/categories/Notes/"/>
    
    
      <category term="privacy" scheme="https://kaihao.io/tags/privacy/"/>
    
      <category term="computer security" scheme="https://kaihao.io/tags/computer-security/"/>
    
      <category term="internet" scheme="https://kaihao.io/tags/internet/"/>
    
  </entry>
  
  <entry>
    <title>跑步，从一双好鞋开始</title>
    <link href="https://kaihao.io/2018/running-shoes/"/>
    <id>https://kaihao.io/2018/running-shoes/</id>
    <published>2018-01-19T11:44:19.541Z</published>
    <updated>2019-10-16T09:10:23.709Z</updated>
    
    <content type="html"><![CDATA[<p>自己有规模地开始跑步也已经有三年了。三年来虽然跑步一直断断续续，跑步装备倒是买了不少。关于跑步的书籍以及各种装备的评测也看了不少。感觉跑步相关的东西可以稍微分享一下。</p><p>下面主要讲讲跑鞋的选购。本文将分为三个部分，第一部分讲跑鞋存在的意义，第二部分介绍跑鞋的分类、第三部分讲怎样快速找到适合自己的跑鞋。</p><a id="more"></a><h3 id="为什么需要一双跑鞋"><a href="#为什么需要一双跑鞋" class="headerlink" title="为什么需要一双跑鞋"></a><strong>为什么需要一双跑鞋</strong></h3><h4 id="跑步时的落地方式"><a href="#跑步时的落地方式" class="headerlink" title="跑步时的落地方式"></a><strong>跑步时的落地方式</strong></h4><p>跑步时脚的<strong>落地方式</strong>一般有三种：后脚跟着地、足弓处着地、前脚掌着地(如下图所示)。</p><p><img src="/images/1801-running-shoes-01.png" alt="1801-running-shoes-01"></p><p>运动力学领域的学术杂志《Gait &amp; Posture》上的一篇研究文章指出，在一项对900名初级跑者进行的研究中,<strong>绝大多数人在跑步时后脚跟首先落地</strong>。研究者发现,在456名男性研究对象中,96.9%为脚后跟先落地。在447名女性研究对象中,99.3%为脚后跟先落地。因此，下面主要针对后脚跟着地方式进行介绍。</p><h4 id="跑步时膝关节为什么会受到损伤"><a href="#跑步时膝关节为什么会受到损伤" class="headerlink" title="跑步时膝关节为什么会受到损伤"></a><strong>跑步时膝关节为什么会受到损伤</strong></h4><p><img src="/images/1801-running-shoes-02.jpg" alt="1801-running-shoes-02"></p><p>上图的曲线描绘出了从后脚跟着地至脚掌离开面过程中地面反作用力的变化，很明显看到有两个峰值。第一个峰值是脚后跟接触地面的瞬间，地面给脚和小腿的反作用力，冲击力峰值基本上反映出了此时地面对脚和小腿冲击力的大小，也是造成损伤的主要原因。</p><p>当我们后脚跟着地时，在很短的时间内（小于0.05秒），几倍于体重的地面反作用力施加在脚跟和脚踝上，尤其是不恰当的跑步姿势使得着地时膝关节伸直，<strong>其附近肌肉难以参与缓冲，只能靠软组织（脂肪垫、关节软骨、半月板）来应对冲击。</strong></p><p>这仅仅是一次着地带来的效应，跑步时成千上万次的冲击不断累积，势必使得膝关节承受很大压力，这是为什么膝伤成为大众跑者头号伤痛的重要诱因之一。很多保护不周的跑步爱好者下半生都承受着巨大的膝盖伤痛折磨，甚至连走路都需要扶着东西才能动。</p><h4 id="跑鞋的作用"><a href="#跑鞋的作用" class="headerlink" title="跑鞋的作用"></a><strong>跑鞋的作用</strong></h4><p>因此，以前没有经过专业训练的，现在跑量比较大的人，需要跑鞋来进行缓冲。就像杯子直接落在地上很容易摔碎，而包上一层海绵后，缓冲时间变长，就不容易摔碎。慢跑鞋就是类似的原理。慢跑鞋往往有一个比较厚的鞋底，同时采用特殊的鞋底材料与结构来帮助我们进行缓冲。比如Asics的Gel缓震胶、New Balance的Abzorb泡沫聚酯、Mizuno的Wave波浪板缓震片，都能减少跑步时对膝关节的冲击。因此，跑鞋不是为了让你跑得更快，而是为了让你跑步的时候不受伤。这就是跑鞋存在的意义。 </p><h4 id="前脚掌着地的跑步姿势"><a href="#前脚掌着地的跑步姿势" class="headerlink" title="前脚掌着地的跑步姿势"></a><strong>前脚掌着地的跑步姿势</strong></h4><p>也许你会问，前脚掌着地的跑步方式是不是对膝关节损伤小一点。的确，前脚掌着地时地面的反作用力增加比较缓慢，对膝关节的冲击相对较小。此时适宜穿的鞋也不是后脚跟比较高的慢跑鞋。但是前脚掌着地的跑步方式对腿部肌肉的要求比较高，而且当配速比较慢时反而比较费力。因此，对于经验不是很丰富的跑者，如果你不是对跑步速度较高的要求的话，还是后脚跟着地比较好。</p><p>注：对于水平相对较高的跑者（例如男子10km在40分钟以内），不需要鞋子具有太多保护性，可以参考<a href="https://mp.weixin.qq.com/s/BV3xq8gAHjjis4kjurZDZw" target="_blank" rel="external nofollow noopener noreferrer">这篇文章</a>选择跑鞋。</p><h3 id="跑鞋有哪些种类"><a href="#跑鞋有哪些种类" class="headerlink" title="跑鞋有哪些种类"></a><strong>跑鞋有哪些种类</strong></h3><h4 id="简介"><a href="#简介" class="headerlink" title="简介"></a><strong>简介</strong></h4><p>跑鞋简单归纳一下常见的分类有<strong>慢跑鞋</strong>、<strong>越野鞋</strong>、<strong>马拉松鞋 </strong>、<strong>赤足鞋</strong>等等。</p><p>(1)<strong>慢跑鞋</strong>适合日常平路跑步，鞋底一般较厚，提供比较好的保护性。</p><p><img src="/images/1801-running-shoes-03.jpg" alt="1801-running-shoes-03"></p><p>(2) <strong>越野型</strong>的跑鞋由于其针对性，鞋底构造与传统跑鞋不同，作为日常公路跑步或者比赛用鞋并不适合。</p><p><img src="/images/1801-running-shoes-04.jpg" alt="1801-running-shoes-04"></p><p>(3)<strong>马拉松鞋</strong>和<strong>赤足型跑鞋</strong>在设计上为了追求速度强调轻量化，而保护性方面就薄弱些，需要有强壮的腿部和足部力量才能驾驭，比较适用于之前提到的前脚掌着地的跑法，适用于有训练基础的跑者，而且使用寿命相对较短。<br><img src="/images/1801-running-shoes-05.jpg" alt="1801-running-shoes-05"><br><img src="/images/1801-running-shoes-06.jpg" alt="1801-running-shoes-06"></p><h4 id="慢跑鞋的分类"><a href="#慢跑鞋的分类" class="headerlink" title="慢跑鞋的分类"></a><strong>慢跑鞋的分类</strong></h4><p>慢跑鞋可分为缓冲/减震、支撑/稳定型、控制型三种。对应的跑步姿势分别为足内翻，足外翻，严重内翻（一般对应于高足弓、低足弓、扁平足）。<br>足内翻、足外翻、正常三种跑步姿态可以参考下面三张图。（如果你觉得这部分比较抽象的直接跳过就好，并不影响你选鞋哈。） </p><p>(1)足内翻=脚背向外翻=脚心向内翻=缓冲/减震系跑鞋=underpronation=supination</p><p><img src="/images/1801-running-shoes-07.jpg" alt="1801-running-shoes-07"></p><p>(2) 足外翻=脚背向内翻=脚心向外翻=支撑/稳定系跑鞋=overpronation</p><p><img src="/images/1801-running-shoes-08.jpg" alt="1801-running-shoes-08"></p><p>(3) 正常=随意=neutral pronation</p><p><img src="/images/1801-running-shoes-09.jpg" alt="1801-running-shoes-09"></p><p>一般来说可以用高低足弓来判断选哪种跑鞋，见下图。</p><p><img src="/images/1801-running-shoes-10.jpg" alt="1801-running-shoes-10"></p><p><img src="/images/1801-running-shoes-11.png" alt="1801-running-shoes-11"></p><h4 id="跑鞋的量级"><a href="#跑鞋的量级" class="headerlink" title="跑鞋的量级"></a><strong>跑鞋的量级</strong></h4><p>一般体重越重，跑道缓冲性越差，所需的跑鞋缓冲能力越强，跑鞋量级就越高，跑鞋价格也越贵。但是这不意味着量级高的跑鞋就高级。高量级的跑鞋是为大体重的人设计的，其用于吸收较大冲击力的缓冲材料对于体重轻的人来说往往显得太硬了。这点对于采用机械减震技术的Mizuno跑鞋尤其明显，体重轻的的人穿高量级的鞋简直是受罪。<br><img src="/images/1801-running-shoes-12.png" alt="1801-running-shoes-12"></p><p><img src="/images/1801-run&gt; ning-shoes-13.png" alt="1801-running-shoes-13"></p><h3 id="快速选择适合的跑鞋"><a href="#快速选择适合的跑鞋" class="headerlink" title="快速选择适合的跑鞋"></a><strong>快速选择适合的跑鞋</strong></h3><p>哈哈，前面介绍了那么多，你是否已经看晕了呢？<br>没关系，抛开前面那些烦人的内翻外翻之类的概念吧。采用下面方法很快可以很快确定适合的跑鞋。 </p><p>在<a href="http://www.myprecisionfit.com/" target="_blank" rel="external nofollow noopener noreferrer"><strong>Mizuno官方测试分析</strong></a>这个网站上，有详细的<strong>在线测试</strong>，测试完之后会向你推荐适合你的Mizuno跑鞋。</p><p>如果你对在线评测不放心的话还可以去<strong>实体店检测脚型</strong>，比如<a href="http://www.dianping.com/shop/17682965" target="_blank" rel="external nofollow noopener noreferrer">Asics北京世界城店</a>与<a href="http://www.dianping.com/shop/15099064/" target="_blank" rel="external nofollow noopener noreferrer">Asics上海黄金城道店</a>就能提供详细的脚型测试报告，并能推荐适合你的Asics跑鞋。</p><p>但这并不意味着要买Mizuno或者Asics的跑鞋，借助<strong><a href="http://bbs.runbible.cn/thread-120804-1-1.html" target="_blank" rel="external nofollow noopener noreferrer">跑鞋矩阵</a></strong>可以找到各个品牌适合你的鞋。跑鞋矩阵Excel文件里有详细的各个品牌各个型号的跑鞋的类别、量级及其对应关系。根据上一步得到的Mizuno或者Asics的鞋的型号去矩阵中找到是它属于什么类型（即表格第一列缓冲/减震、支撑/稳定型、控制型等）与量级（即表格第二列入门级、实用级、次顶级等），然后就可以依据类型和量级找到各个品牌适合你的鞋的型号啦。</p><p>当然Mizuno和Asics这两个品牌在跑鞋领域都十分专业，还是很推荐的。</p><p>上面的跑鞋矩阵Excel文件可能需要登录论坛才能下载，这里提供<strong><a href="https://pan.baidu.com/s/1Cxht19v1KnOiPrVRDMfZww" target="_blank" rel="external nofollow noopener noreferrer">百度云链接</a></strong> （密码: hkhs）。</p><p>上述Mizuno在线测试网站部分评测结果加载不出来，这时可以用<strong><a href="http://www.runnersworld.com/shoefinder" target="_blank" rel="external nofollow noopener noreferrer">Shoe Finder | Runner’s World</a></strong> （英文版）或 <strong><a href="http://shoeadvisor.newbalance.com.cn/" target="_blank" rel="external nofollow noopener noreferrer">New Balance跑鞋顾问</a></strong>（中文版） 这两个网站替代。</p><p><strong>结语</strong>：选好跑鞋后就是去买啦。实体店可能会有些溢价，有条件的推荐海淘。电商网站有优惠时也可以赶紧剁手。 当然，拿到新鞋后就要多出去跑跑跑啊~ </p><p><img src="/images/1801-running-shoes-14.jpg" alt="1801-running-shoes-14"></p><p>本文首先于2016年发布于<a href="https://www.zhihu.com/question/19937281/answer/145980716" target="_blank" rel="external nofollow noopener noreferrer">知乎</a>，略有删改。</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;自己有规模地开始跑步也已经有三年了。三年来虽然跑步一直断断续续，跑步装备倒是买了不少。关于跑步的书籍以及各种装备的评测也看了不少。感觉跑步相关的东西可以稍微分享一下。&lt;/p&gt;
&lt;p&gt;下面主要讲讲跑鞋的选购。本文将分为三个部分，第一部分讲跑鞋存在的意义，第二部分介绍跑鞋的分类、第三部分讲怎样快速找到适合自己的跑鞋。&lt;/p&gt;
    
    </summary>
    
      <category term="Running" scheme="https://kaihao.io/categories/Running/"/>
    
    
      <category term="running" scheme="https://kaihao.io/tags/running/"/>
    
      <category term="shopping" scheme="https://kaihao.io/tags/shopping/"/>
    
  </entry>
  
  <entry>
    <title>爱剪辑加字幕之经验及Python程序批量加字幕</title>
    <link href="https://kaihao.io/2018/subtitles-with-aijianji-and-python/"/>
    <id>https://kaihao.io/2018/subtitles-with-aijianji-and-python/</id>
    <published>2018-01-19T08:32:56.578Z</published>
    <updated>2019-10-16T09:10:20.692Z</updated>
    
    <content type="html"><![CDATA[<p>最近学校社团做了个视频，以前都用Premiere加字幕比较麻烦，听说爱剪辑比较傻瓜，试了下的确比较方便，还可以用程序实现（半）自动化加字幕，就在这里记录下经验吧。</p><p>视频主要是用After Effect套上一些照片的模板，再做几个如片头片尾的特效，之后用Premiere剪辑采访的视频素材和其他照片素材、特效素材，最终用爱剪辑加上字幕。整体视频后期大概用了是三人×一个礼拜的课余时间。</p><a id="more"></a><p>视频里用到的字幕主要有两种格式，第一种是全屏打字效果，第二种是普通的对话字幕及人物附注，见下面两张图。</p><p><img src="/images/1801-subtitles-with-aijianji-and-python-01.png" alt="全屏打字效果"></p><p><img src="/images/1801-subtitles-with-aijianji-and-python-02.png" alt="对话字幕及人物附注"></p><h3 id="具体步骤"><a href="#具体步骤" class="headerlink" title="具体步骤"></a>具体步骤</h3><p>首先根据音频整理成文字稿，建议软件识别后人工修正，软件识别方法见<a href="https://www.zhihu.com/question/20124290/answer/152611666" target="_blank" rel="external nofollow noopener noreferrer">我的知乎回答</a>。</p><h4 id="经过试验后字幕格式"><a href="#经过试验后字幕格式" class="headerlink" title="经过试验后字幕格式"></a>经过试验后字幕格式</h4><ul><li>中文字体用冬青黑传统中文W3</li><li>字体为白色，阴影为4，阴影颜色为rgb(63,63,63)，无描边</li></ul><h4 id="使用爱剪辑加字幕的经验"><a href="#使用爱剪辑加字幕的经验" class="headerlink" title="使用爱剪辑加字幕的经验"></a>使用爱剪辑加字幕的经验</h4><ul><li><p>因为每次爱剪辑新增字幕后格式都要重新调，所以不妨复制已经调整好格式的字幕然后调整时间轴到所需加字幕处粘贴即可。</p></li><li><p>每次加字幕时均会在视频前加上一个片头，并吃掉一部分结尾，所以在爱剪辑结尾加上一分钟左右的黑屏，最后再用Premiere减掉即可。</p></li><li><p>人物对话字幕因为出现特效时间长、消失特效时间长不能为零，均设为0.01秒</p></li></ul><h4 id="确定字幕时间"><a href="#确定字幕时间" class="headerlink" title="确定字幕时间"></a>确定字幕时间</h4><ul><li><p>用Adobe Edition依照波形来精确确定时间精确到0.01秒</p></li><li><p>如果说话之间没有明显停顿，只要确定两句话之间的一个时间点作为这句话的结束和下句话的开始即可</p></li></ul><h4 id="打字效果字幕"><a href="#打字效果字幕" class="headerlink" title="打字效果字幕"></a>打字效果字幕</h4><ul><li><p>确定在时间轴上每句话的开始、结束时间，依次确定字幕逐字出现的特效时长（后者减前者）</p></li><li><p>确定所有字幕淡出的时间轴时间，并参照时间轴上每句话的结束时间确定字幕停留的特效时间长(前者减后者)</p></li><li><p>所有字幕的消失特效时间长均相同，1s以下即可</p></li><li><p>一句话中即使视频里面为一行如果有明显停顿的仍拆分为两个字幕</p></li></ul><h3 id="使用程序批量加字幕"><a href="#使用程序批量加字幕" class="headerlink" title="使用程序批量加字幕"></a>使用程序批量加字幕</h3><h4 id="确定工程文件中的字幕格式"><a href="#确定工程文件中的字幕格式" class="headerlink" title="确定工程文件中的字幕格式"></a>确定工程文件中的字幕格式</h4><p>对于人物说话的字幕，由于格式比较固定（字体格式均相同、位置均处于屏幕下方），又发现爱剪辑的工程文件为文本文件，里面的字幕参数直接可以修改，工程文件中字幕为<code>&quot;TextList&quot;:[{字幕1},{字幕2}]</code>，且每个字幕中只有<code>BeginTime</code>、<code>EndTime</code>、<code>StayEffTimeLen</code>、<code>Transform</code>、<code>ZOrder</code>这些参数要修改：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">BeginTime&#x3D;时间轴上开始秒数*10000000</span><br><span class="line">EndTime&#x3D;时间轴上结束秒数*10000000</span><br><span class="line">StayEffTimeLen&#x3D;EndTime-BeginTime-0.02*10000000(0.02秒为出现特效时间长加上消失特效时间长)</span><br><span class="line">Transform确定字幕的位置和其它一些信息，我暂时没看到什么规律</span><br><span class="line">ZOrder为字幕的序号，第一个为-1073741824，之后每个依次加1</span><br></pre></td></tr></table></figure></p><h4 id="将字幕信息存为文本文件"><a href="#将字幕信息存为文本文件" class="headerlink" title="将字幕信息存为文本文件"></a>将字幕信息存为文本文件</h4><p>将字幕的信息输入excel后得到如下图<br><img src="/images/1801-subtitles-with-aijianji-and-python-03.jpg" alt="字幕Excel.JPG"><br>然后存为csv文件如下<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">BeginTime,EndTime,StayEffTimeLen,字幕</span><br><span class="line">431600000,444000000,12200000,他留校之后</span><br><span class="line">444000000,473300000,29100000,就向教育基金会的老师提出了一个想法</span><br><span class="line">476700000,505000000,28100000,能不能把明德奖学金的获得者组织起来</span><br><span class="line">505000000,524400000,19200000,变成一个社团</span><br><span class="line">528000000,538000000,9800000,当时很神奇啊</span><br><span class="line">......</span><br></pre></td></tr></table></figure></p><h4 id="用Python批量生成所有字幕"><a href="#用Python批量生成所有字幕" class="headerlink" title="用Python批量生成所有字幕"></a>用Python批量生成所有字幕</h4><p>先在爱剪辑中调整好一句字幕的格式，然后保存成工程文件后从中提取字幕的代码，并依次用Python生成所有字幕的代码<br>Python程序的作用是依照调整好的字幕格式，根据excel中其他字幕的开始时间、结束时间和字幕本文来生成所有字幕的代码，由于我在Transform参数中没看到什么规律，所有字幕的transform参数均设置相同，所以最终还要调整下字幕的位置<br>Python代码示例如下（倒数第四行依据工程文件中的字幕代码调整即可,一般来说先设置好一句字幕的格式，然后只需修改下面代码中第四行中”FontSize”和”Transform”的内容）</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!user/bin/env python3</span></span><br><span class="line"><span class="comment"># -*- coding: gbk -*-</span></span><br><span class="line">BeginTime,EndTime,StayEffTimeLen,Text=[],[],[],[]</span><br><span class="line">outcome=<span class="string">""</span></span><br><span class="line">lines = open(<span class="string">'001.csv'</span>)</span><br><span class="line">num=<span class="number">-1073741825</span></span><br><span class="line"><span class="keyword">for</span> line <span class="keyword">in</span> lines:</span><br><span class="line">    BeginTime.append( line.split(<span class="string">','</span>)[<span class="number">0</span>])</span><br><span class="line">    EndTime.append( line.split(<span class="string">','</span>)[<span class="number">1</span>])</span><br><span class="line">    StayEffTimeLen.append( line.split(<span class="string">','</span>)[<span class="number">2</span>])</span><br><span class="line">    Text.append( line.split(<span class="string">','</span>)[<span class="number">3</span>].rstrip())</span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> range(<span class="number">1</span>,len(BeginTime)):</span><br><span class="line">    num+=<span class="number">1</span></span><br><span class="line">    outcome+=<span class="string">'&#123;"Alignment":1,"BeginTime":'</span>+str(BeginTime[i])+<span class="string">',"CharSpacing":1,"Effect":&#123;"InEffRowSpaceTime":0,"InEffTimeLen":100000,"InEffWordSpaceTime":0,"InEffectName":"FadeText","Name":"TextCombination","OutEffRowSpaceTime":0,"OutEffTimeLen":100000,"OutEffWordSpaceTime":0,"OutEffectName":"FadeText","StayEffRowSpaceTime":0,"StayEffTimeLen":'</span>+str(StayEffTimeLen[i])+<span class="string">',"StayEffWordSpaceTime":0,"StayEffectName":"ImageStaticLinear"&#125;,"EndTime":'</span>+str(EndTime[i])+<span class="string">',"IsCreateBorderTexture":false,"IsCreateShadowTexture":false,"IsRightToLeft":false,"IsVertical":false,"LayoutType":1,"RowSpacing":0,"SplitType":4,"Style":[&#123;"Alpha":255,"BorderColor":[255,0,0,0],"BorderSize":0,"FontName":"H-冬青黑体传统中文-W3","FontSize":70,"IsBold":false,"IsItalic":false,"IsLucencyText":false,"IsShadowSuccessive":false,"IsStrikeout":false,"IsUnderline":false,"IsVertical":false,"ShadowColor":[255,63,63,63],"ShadowOffsetX":4,"ShadowOffsetY":4,"TextBGImagePath":"","TextColor":[255,255,255,255],"TextColorMode":0,"TextGradientBeginColor":[255,63,63,63],"TextGradientColorAngle":90,"TextGradientEndColor":[255,0,0,0]&#125;],"Text":"'</span>+Text[i]+<span class="string">'","TextureUnitSpacing":1,"Transform":[1,0,0,0,0.99999994039535522,0,693.99993896484375,951.99993896484375,1],"WordSpacing":1,"ZOrder":'</span>+str(num)+<span class="string">'&#125;,'</span></span><br><span class="line">outcome=outcome[<span class="number">0</span>:len(outcome)<span class="number">-1</span>]</span><br><span class="line">f=open(<span class="string">'file'</span>,<span class="string">'w'</span>)</span><br><span class="line">f.write(outcome)</span><br></pre></td></tr></table></figure><h4 id="将用生成的代码替换工程文件中的字幕代码"><a href="#将用生成的代码替换工程文件中的字幕代码" class="headerlink" title="将用生成的代码替换工程文件中的字幕代码"></a>将用生成的代码替换工程文件中的字幕代码</h4><p>用python生成的file文件中的内容替换原始工程文件中”TextList”这个list里面的内容，保存工程文件，然后所有字幕就批量生成了，最后只需要调整字幕位置即可（在爱剪辑中点击字幕中字体设置中的位置，选“中下”位置即可）</p><p>​    </p><p>本文首先于2016年4月发布于<a href="https://www.jianshu.com/p/64fa0abd11af" target="_blank" rel="external nofollow noopener noreferrer">简书</a>，略有删改。</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;最近学校社团做了个视频，以前都用Premiere加字幕比较麻烦，听说爱剪辑比较傻瓜，试了下的确比较方便，还可以用程序实现（半）自动化加字幕，就在这里记录下经验吧。&lt;/p&gt;
&lt;p&gt;视频主要是用After Effect套上一些照片的模板，再做几个如片头片尾的特效，之后用Premiere剪辑采访的视频素材和其他照片素材、特效素材，最终用爱剪辑加上字幕。整体视频后期大概用了是三人×一个礼拜的课余时间。&lt;/p&gt;
    
    </summary>
    
      <category term="Software" scheme="https://kaihao.io/categories/Software/"/>
    
      <category term="Video Editing" scheme="https://kaihao.io/categories/Software/Video-Editing/"/>
    
    
      <category term="video editing" scheme="https://kaihao.io/tags/video-editing/"/>
    
      <category term="subtitles" scheme="https://kaihao.io/tags/subtitles/"/>
    
      <category term="python" scheme="https://kaihao.io/tags/python/"/>
    
  </entry>
  
  <entry>
    <title>Mdict to macOS Dictionary转换笔记</title>
    <link href="https://kaihao.io/2018/mdict-to-macos-dictionary/"/>
    <id>https://kaihao.io/2018/mdict-to-macos-dictionary/</id>
    <published>2018-01-19T04:11:33.965Z</published>
    <updated>2020-11-21T09:06:40.710Z</updated>
    
    <content type="html"><![CDATA[<p>首先介绍一下词典软件。</p><p>目前最流行的还是有道词典、金山词霸等app。但是这些app在专业性和权威性上又有所不足。而Mdcit系列词典可以添加各种自定义词库，而且很多网友已经制作好了很多权威词典对应的Mdict词库（见<a href="https://www.pdawiki.com/forum/forum-4-1.html" target="_blank" rel="external nofollow noopener noreferrer">Pdawiki</a>与<a href="https://freemdict.com/" target="_blank" rel="external nofollow noopener noreferrer">FreeMdict</a>）。</p><p>而对于自己最常使用的macOS，支持Mdict词库的GoldenDict开发进度缓慢，界面不太好看，有时会遇到Bug。而另一款欧路词典需要收费才能添加自定义词库，而且界面、操作也不令人满意。</p><p>更新：欧路词典用户体验还可以。目前是常用的词典转换成macOS Dictionary格式使用，其它词典在欧路词典使用。毕竟每本词典都转换的话太费时间了。</p><p>相反，macOS系统原生的Dictionary有着良好的操作体验，支持三指取词，阅读体验也很棒，却没有那么多自定义词库可以添加。</p><p>于是，就想着把两者的优点结合起来，将丰富的Mdict词库转换成macOS Dictionary支持的格式，而且支持图片显示、发音等等功能。</p><p>下面简要简要记录由Mdict词库文件转换成完美macOS Dictionary词库文件的过程。</p><a id="more"></a><h3 id="所需环境"><a href="#所需环境" class="headerlink" title="所需环境"></a>所需环境</h3><ul><li>开源项目</li></ul><p><a href="https://github.com/ilius/pyglossary" target="_blank" rel="external nofollow noopener noreferrer">PYGLOSSARY</a>：最新Releases见<a href="https://github.com/ilius/pyglossary/releases" target="_blank" rel="external nofollow noopener noreferrer">ilius/pyglossary/releases</a></p><p><a href="https://github.com/jd-boyd/python-lzo" target="_blank" rel="external nofollow noopener noreferrer">python-lzo</a>：<code>sudo pip3 install python-lzo</code></p><ul><li>Writing to AppleDict: <code>sudo pip3 install lxml beautifulsoup4 html5lib</code></li></ul><ul><li>GNU make as part of <a href="http://developer.apple.com/downloads" target="_blank" rel="external nofollow noopener noreferrer">Command Line Tools for Xcode</a></li><li>Dictionary Development Kit as part of <a href="http://developer.apple.com/downloads" target="_blank" rel="external nofollow noopener noreferrer">Auxillary Tools for Xcode</a>. Extract to/Developer/Extras/Dictionary Development Kit</li></ul><h3 id="转换过程"><a href="#转换过程" class="headerlink" title="转换过程"></a>转换过程</h3><ul><li><strong>用PYGLOSSARY进行转换</strong></li></ul><p>假设词典文件为~/Downloads/oald8/oald8.mdx, 图片、语音文件oald8.mdd也在同一文件夹下。</p><p>先将词典文件转换成xml文件，并将其他图片、音频等文件提取出来放在OtherResources文件夹下。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> ~/Downloads/oald8/</span><br><span class="line">python3 ~/Software/pyglossary/pyglossary.pyw --<span class="built_in">read</span>-options=resPath=OtherResources --write-format=AppleDict oald8.mdx oald8-apple</span><br><span class="line"><span class="built_in">cd</span> oald8-apple</span><br></pre></td></tr></table></figure><p>在<a href="https://github.com/ilius/pyglossary" target="_blank" rel="external nofollow noopener noreferrer">PYGLOSSARY</a>的说明中接下来是将xml文件中的相对链接中的”/“去掉以及替换spx为wav。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">sed -i <span class="string">""</span> <span class="string">'s:src="/:src=":g'</span> oald8.xml</span><br><span class="line">sed -i <span class="string">""</span> <span class="string">'s|sound://\([/_a-zA-Z0-9]*\).spx|\1.wav|g'</span> oald8.xml</span><br></pre></td></tr></table></figure><p>其实这两步可以在之后用正则统一替换。</p><ul><li><strong>转换语音文件</strong></li></ul><p>如果是spx文件，先转换成wav（需安装speex）。若是wav文件则可跳过这一步。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">find OtherResources -name <span class="string">"*.spx"</span> -execdir sh -c <span class="string">'spx=&#123;&#125;;speexdec $spx  $&#123;spx%.*&#125;.wav'</span> \;</span><br></pre></td></tr></table></figure><p>然后用FFmpeg把wav文件转换成mp3文件（macOS中默认的iTunes与QuickTime均不支持wav格式）。</p><p>在当前目录新建Sounds文件夹，并新建sh脚本convert.sh文件如下。</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span> x <span class="keyword">in</span> ./OtherResources/*.wav; <span class="keyword">do</span> ffmpeg -i <span class="string">"<span class="variable">$x</span>"</span> <span class="string">"Sounds/`basename "</span><span class="variable">$x</span><span class="string">" .wav`.mp3"</span>; <span class="keyword">done</span></span><br></pre></td></tr></table></figure><p>然后执行sh脚本。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sh ./convert.sh</span><br></pre></td></tr></table></figure><p>如果语音文件较多的话需等待较长时间。</p><ul><li><strong>编译</strong></li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">make</span><br></pre></td></tr></table></figure><p>有时生成的词典包文件中并没有图片、音频文件。这时将OtherResources文件夹中除音频外的其他文件以及放置mp3文件的Sounds文件夹复制到xxx.dictionary/Contents目录下（右键dictionary文件，选择Show Package Contents）。</p><ul><li><strong>安装</strong></li></ul><p>将生成的dictionary文件复制到当前用户文件夹下的/Library/Dictionaries中（或者打开Dictionary App，选择菜单栏中的文件-&gt;打开词典文件夹，即可进入该文件夹），之后在Dictionary App的菜单栏中词典-&gt;偏好设置中启用一下就行。</p><h3 id="修正词典文件的各种问题"><a href="#修正词典文件的各种问题" class="headerlink" title="修正词典文件的各种问题"></a>修正词典文件的各种问题</h3><p>以上方法生成的词典会有开头说到的词典内链接跳转不正常，不能发音、图片不能显示等种种小问题。下面修复这些问题。</p><ul><li><strong>Dictionary的URI Scheme介绍</strong></li></ul><p>以下引自<a href="https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/DictionaryServicesProgGuide/schema/schema.html" target="_blank" rel="external nofollow noopener noreferrer">Dictionary Services Programming Guide</a>。</p><p>x-dictionary: is an URI scheme that describes cross references between entries in dictionaries.  It is used in tag such as <code>&lt;a href=&quot;x-dictionary:r:another_id&quot;&gt;</code>.</p><p>The x-dictionary:URI contains three elements separated by colons as the general form—target selector, target text, and dictionary bundle ID.  The target selector must be either d (for definition) or r (for reference). Use d if you want to search definitions of the following key text. Use r if you want to refer to the entry specified by the reference ID which must be unique to each dictionary.</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">x-dictionary:d:key_text:dict_bundle_id</span><br><span class="line">x-dictionary:r:reference_id:dict_bundle_id</span><br></pre></td></tr></table></figure><p>The dictionary bundle ID can be omitted in both forms, as shown in the following lines.  If it is omitted, Dictionary Services searches the target text in all active dictionaries.</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">x-dictionary:d:key_text</span><br><span class="line">x-dictionary:r:reference_id</span><br></pre></td></tr></table></figure><ul><li><strong>修复词典中的链接跳转问题。</strong></li></ul><p>举例来说，假设dict_bundle_id为Longman5。（dict_bundle_id可在生成的词典文件中的Info.plist中修改。）</p><p>假设xml文件中为：</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">a</span> <span class="attr">href</span>=<span class="string">"x-dictionary:d:entry://hour"</span>&gt;</span>hour<span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br></pre></td></tr></table></figure><p>可替换为：</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">a</span> <span class="attr">href</span>=<span class="string">"x-dictionary:d:hour:Longman5"</span>&gt;</span>hour<span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br></pre></td></tr></table></figure><p>可用正则表达式匹配然后处理。</p><ul><li><strong>修正词典中页面内的定位问题</strong></li></ul><p>例如点击apple1会跳转到同一个页面中的apple2处。</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">a</span> <span class="attr">href</span>=<span class="string">"x-dictionary:d:entry://#_hke1"</span>&gt;</span>apple1<span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">a</span> <span class="attr">name</span>=<span class="string">"_hke1"</span>&gt;</span>apple2<span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br></pre></td></tr></table></figure><p>将其替换为</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">a</span> <span class="attr">href</span>=<span class="string">"#_hke1"</span>&gt;</span>apple1<span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">a</span> <span class="attr">name</span>=<span class="string">"_hke1"</span>&gt;</span>apple2<span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br></pre></td></tr></table></figure><ul><li><strong>修复词典的发音问题</strong></li></ul><p>假设xml文件中为：</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">a</span> <span class="attr">href</span>=<span class="string">"x-dictionary:d:sound://1.spx"</span>&gt;</span><span class="tag">&lt;<span class="name">img</span> <span class="attr">border</span>=<span class="string">"0"</span> <span class="attr">src</span>=<span class="string">"Br.gif"</span>/&gt;</span><span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br></pre></td></tr></table></figure><p>可替换为</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">audio</span> <span class="attr">id</span>=<span class="string">"1"</span> <span class="attr">src</span>=<span class="string">"Sounds/1.mp3"</span>/&gt;</span><span class="tag">&lt;<span class="name">img</span> <span class="attr">border</span>=<span class="string">"0"</span> <span class="attr">src</span>=<span class="string">"Br.gif"</span> <span class="attr">onmousedown</span>=<span class="string">"document.getElementById('1').play(); return false;"</span>/&gt;</span></span><br></pre></td></tr></table></figure><p><code>onmousedown</code>可替换成<code>onmouseover</code>，这样鼠标悬浮上发音图标就开始发音，而不用单击。</p><p>可用正则表达式匹配然后处理。</p><ul><li><strong>Java正则替换代码示例</strong></li></ul><p>以Longman5_Activator为示例，假设只需要修复链接跳转问题和页面内的定位问题。写得比较随便，随意看一下就好。</p><p>当然挺多编辑器（比如Sublime Text、Visual Studio Code）直接支持正则表达式查找和替换，这样就不用写程序了。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> java.io.*;</span><br><span class="line"><span class="keyword">import</span> java.util.regex.Matcher;</span><br><span class="line"><span class="keyword">import</span> java.util.regex.Pattern;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Replace</span> </span>&#123;</span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">final</span> String REGEX_1 = <span class="string">"x-dictionary:d:entry:\\/\\/#"</span>;</span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">final</span> String REGEX_2 = <span class="string">"entry:\\/\\/([^#\"][^\"]*)\""</span>;</span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">final</span> String Bundle_Id = <span class="string">"Longman5_Activator"</span>;</span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">final</span> String inputName = <span class="string">"Longman5_Activator.xml"</span>;</span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">final</span> String outputName = <span class="string">"Longman5_Activator_Output.xml"</span>;</span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">final</span> String ENCODE = <span class="string">"UTF-8"</span>;</span><br><span class="line">    BufferedReader br = <span class="keyword">null</span>;</span><br><span class="line">    BufferedWriter bw = <span class="keyword">null</span>;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line">        <span class="keyword">new</span> Replace().replaceFile();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">replacefun1</span><span class="params">(String line)</span> </span>&#123;</span><br><span class="line">        Pattern pattern = Pattern.compile(REGEX_1);</span><br><span class="line">        StringBuffer sbr = <span class="keyword">new</span> StringBuffer();</span><br><span class="line">        Matcher matcher = pattern.matcher(line);</span><br><span class="line">        <span class="keyword">while</span> (matcher.find()) &#123;</span><br><span class="line">            matcher.appendReplacement(sbr, <span class="string">"#"</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        matcher.appendTail(sbr);</span><br><span class="line">        <span class="keyword">return</span> sbr.toString();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">replacefun2</span><span class="params">(String line)</span> </span>&#123;</span><br><span class="line">        Pattern pattern = Pattern.compile(REGEX_2);</span><br><span class="line">        StringBuffer sbr = <span class="keyword">new</span> StringBuffer();</span><br><span class="line">        Matcher matcher = pattern.matcher(line);</span><br><span class="line">        <span class="keyword">while</span> (matcher.find()) &#123;</span><br><span class="line">            matcher.appendReplacement(sbr, matcher.group(<span class="number">1</span>) + <span class="string">":"</span> + Bundle_Id + <span class="string">"\""</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        matcher.appendTail(sbr);</span><br><span class="line">        <span class="keyword">return</span> sbr.toString();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">replaceFile</span><span class="params">()</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            br = <span class="keyword">new</span> BufferedReader(<span class="keyword">new</span> InputStreamReader(<span class="keyword">new</span> FileInputStream(</span><br><span class="line">                    inputName), ENCODE));</span><br><span class="line">            bw = <span class="keyword">new</span> BufferedWriter(<span class="keyword">new</span> OutputStreamWriter(</span><br><span class="line">                    <span class="keyword">new</span> FileOutputStream(outputName)));</span><br><span class="line">            String line = <span class="keyword">null</span>;</span><br><span class="line">            <span class="keyword">while</span> ((line = br.readLine()) != <span class="keyword">null</span>) &#123;</span><br><span class="line">                bw.write(replacefun2(replacefun1(line)));</span><br><span class="line">                bw.newLine();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            bw.close();</span><br><span class="line">            br.close();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="其他注意事项"><a href="#其他注意事项" class="headerlink" title="其他注意事项"></a>其他注意事项</h3><ul><li><strong>文本匹配的正则表达式需一一调试</strong></li></ul><p>以上每个词典文件中的具体模式均不太一样，而且有时会有与一般模式不同的个例（如多加了几个空格、标签间加了个<code>&lt;br/&gt;</code>、中间换了一行、图片大多是png个别是gif等等），需要一一调试。推荐调试网站<a href="http://regexr.com/" target="_blank" rel="external nofollow noopener noreferrer">Regexr</a>。</p><ul><li><strong>空格相关问题</strong></li></ul><p>连续两个粗体单词之间的空格会不显示。例如</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">b</span>&gt;</span>apple<span class="tag">&lt;/<span class="name">b</span>&gt;</span> <span class="tag">&lt;<span class="name">b</span>&gt;</span>pie<span class="tag">&lt;/<span class="name">b</span>&gt;</span></span><br></pre></td></tr></table></figure><p>会显示为applepie。此时将其替换为</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">b</span>&gt;</span>apple<span class="tag">&lt;/<span class="name">b</span>&gt;</span><span class="symbol">&amp;#160;</span><span class="tag">&lt;<span class="name">b</span>&gt;</span>pie<span class="tag">&lt;/<span class="name">b</span>&gt;</span></span><br></pre></td></tr></table></figure><p>注意xml中不能用<code>&amp;nbsp;</code>。</p><p>另外有时xml中会有<code>&amp;amp;nbsp;</code>，原意应显示为空格，却显示为<code>&amp;nbsp;</code>。此时将其替换为<code>&amp;#160;</code>就好。</p><ul><li><strong>取词小窗口修改大小</strong></li></ul><p>若取词小窗口中字体太小，可在词典包内容中的DefaultStyle.css文件中加上以下内容：</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">.apple_client-panel body&#123;margin: 0 0 15px;font-size: 16px;&#125;</span><br></pre></td></tr></table></figure><ul><li><strong>CSS样式文件</strong></li></ul><p>若OtherResources文件夹中有其它CSS文件，或者原来CSS文件就独立于MDict文件之外，将其内容复制到词典文件包中的DefaultStyle.css文件中。</p><ul><li><strong>深色模式</strong></li></ul><p>在深色模式中，转换的词典背景颜色依旧是白色，这可以通过修改词典包内容中的DefaultStyle.css文件解决。具体参考<a href="https://eclecticlight.co/2018/10/04/make-mojave-custom-dictionaries-work-better/" target="_blank" rel="external nofollow noopener noreferrer">Make Mojave custom dictionaries work better</a>。</p><ul><li><strong>其它问题</strong></li></ul><p>将<code>@@@LINK=abc</code>替换成<code>&lt;a href=&quot;x-dictionary:d:abc:dict_bundle_id&quot;&gt;abc&lt;/a&gt;</code>。不过这样处理后显示的是指向另一个词条的链接，不是直接显示另一个词条。解决办法是扫描整个XML文件，将@@@LINK引用移动到正确的词条下。具体可以参考下述Python代码（引用自该<a href="https://www.pdawiki.com/forum/thread-30203-1-1.html" target="_blank" rel="external nofollow noopener noreferrer">链接</a>）。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python3</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> xml.etree.ElementTree <span class="keyword">as</span> ET</span><br><span class="line"></span><br><span class="line"><span class="string">'''</span></span><br><span class="line"><span class="string">1. find the d:entry node which descendant contains the keyword "@@@LINK=" in text</span></span><br><span class="line"><span class="string">2. parse the value behind "@@@LINK=" keyword and save it to variable title</span></span><br><span class="line"><span class="string">3. save the index node belongs to the d:entry to variable index</span></span><br><span class="line"><span class="string">4. find the d:entry node which title property exactly matches title</span></span><br><span class="line"><span class="string">5. append index to the current d:entry node as child</span></span><br><span class="line"><span class="string">6. remove the d:entry which descendant contains the keyword "@@@LINK="</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">NOTE: please remove the default namespace from oald8.xml file manually before the script running and add it back when script done.</span></span><br><span class="line"><span class="string">'''</span></span><br><span class="line"></span><br><span class="line">tree = ET.parse(<span class="string">'./oald8.xml'</span>)</span><br><span class="line">root = tree.getroot()</span><br><span class="line"></span><br><span class="line">ns = &#123;<span class="string">'d'</span>: <span class="string">'http://www.apple.com/DTDs/DictionaryService-1.0.rng'</span>&#125;</span><br><span class="line">ET.register_namespace(<span class="string">'d'</span>, <span class="string">'http://www.apple.com/DTDs/DictionaryService-1.0.rng'</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># find all d:entry nodes which contains the keyword "@@@LINK=" in text</span></span><br><span class="line">link_entries = root.findall(<span class="string">'.//p/..'</span>, ns)</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> l_entry <span class="keyword">in</span> link_entries:</span><br><span class="line">    index = l_entry.find(<span class="string">'./d:index'</span>, ns)</span><br><span class="line">    title = l_entry.find(<span class="string">'./p'</span>, ns).text.replace(<span class="string">'@@@LINK='</span>, <span class="string">''</span>)</span><br><span class="line">    entry = root.find(<span class="string">'./d:entry[@d:title="'</span> + title + <span class="string">'"]'</span>, ns)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># remove l_entry directly if title cannot be found in entries</span></span><br><span class="line">    <span class="keyword">if</span> entry <span class="keyword">is</span> <span class="literal">None</span>:</span><br><span class="line">        print(title)</span><br><span class="line">        root.remove(l_entry)</span><br><span class="line">        <span class="keyword">continue</span></span><br><span class="line"></span><br><span class="line">    <span class="comment"># append the index element to right entry</span></span><br><span class="line">    entry.insert(<span class="number">0</span>, index)</span><br><span class="line">root.remove(l_entry)tree.write(<span class="string">'oald8f.xml'</span>, <span class="string">'UTF-8'</span>)</span><br></pre></td></tr></table></figure><p>如果图片无法正常显示，将相对路径名最前面的/去掉，例如将<code>&lt;img src=&quot;/dir/abc.png&quot;/&gt;</code>替换成<code>&lt;img src=&quot;dir/abc.png&quot;/&gt;</code>.</p><p>由于macOS的Dictionary中鼠标悬浮于某一内容之上时会将其视作一个span，如果CSS中原本就有应用于所有span的样式，会把该样式应用于鼠标经过的区域。这样鼠标经过的区域会有很奇怪的样式。解决办法是在原有span中加一个class，并把原来span的样式归到新建的class中。</p><p>等等。</p><ul><li><strong>其他功能</strong></li></ul><p>Dictinary还支持高亮搜索关键词、家长控制功能等等，参考之前提到过的<a href="https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/DictionaryServicesProgGuide/schema/schema.html" target="_blank" rel="external nofollow noopener noreferrer">Dictionary Services Programming Guide</a>。</p><h3 id="与Alfred结合的一些功能"><a href="#与Alfred结合的一些功能" class="headerlink" title="与Alfred结合的一些功能"></a>与Alfred结合的一些功能</h3><ul><li><strong>快捷键取词</strong></li></ul><p>虽然三指轻点取词很方便，但是有些软件并不支持三指取词。结合Alfed Workflow即可实现选中待查内容后快捷键取词。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">query&#x3D;&quot;&#123;query&#125;&quot;</span><br><span class="line">word1&#x3D;&quot;$&#123;query&#x2F;&#x2F;\&#39;&#x2F;%27&#125;&quot;</span><br><span class="line">word2&#x3D;&quot;$&#123;word1&#x2F;&#x2F; &#x2F;%20&#125;&quot;</span><br><span class="line">open dict:&#x2F;&#x2F;&quot;$word2&quot;</span><br></pre></td></tr></table></figure><ul><li><strong>快捷键发音</strong></li></ul><p>下载<a href="https://pan.baidu.com/s/14NNOeOrc_U1R5EQWLNvfpw" target="_blank" rel="external nofollow noopener noreferrer">韦氏142000单词发音库</a>(密码:w4mw)后，假设解压至~/Voice文件夹下。同理即可实现选中待查内容后快捷键发音。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">query=<span class="string">"&#123;query&#125;"</span></span><br><span class="line">char=<span class="string">"<span class="variable">$&#123;query::1&#125;</span>"</span></span><br><span class="line">afplay ~/Voice/<span class="string">"<span class="variable">$char</span>"</span>/<span class="string">"<span class="variable">$query</span>"</span>.wav</span><br></pre></td></tr></table></figure><p>当然系统中开启Speech功能，结合快捷键也能实现类似功能。缺点是这是合成的发音而非真人发音，优点是单词变形乃至句子段落都能发音。</p><p>这里附上快捷键取词和快捷键发音的Alfred Workflow<a href="https://kaihao.io/downloads/Dictionary.alfredworkflow">下载地址</a>。​<br>更新：在单词中有空格或单引号时，原workflow失效。现在已修正。</p><p>Reference:</p><ol><li><a href="https://www.pdawiki.com/forum/thread-13014-1-1.html" target="_blank" rel="external nofollow noopener noreferrer">MAC OSX词典转换笔记</a></li><li><a href="http://qunwang6.github.io/blog/OSXDictionary/" target="_blank" rel="external nofollow noopener noreferrer">\BGL\DSL\MDX\CD\ ===&gt; OS X dictionary</a>  </li></ol>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;首先介绍一下词典软件。&lt;/p&gt;
&lt;p&gt;目前最流行的还是有道词典、金山词霸等app。但是这些app在专业性和权威性上又有所不足。而Mdcit系列词典可以添加各种自定义词库，而且很多网友已经制作好了很多权威词典对应的Mdict词库（见&lt;a href=&quot;https://www.pdawiki.com/forum/forum-4-1.html&quot; target=&quot;_blank&quot; rel=&quot;external nofollow noopener noreferrer&quot;&gt;Pdawiki&lt;/a&gt;与&lt;a href=&quot;https://freemdict.com/&quot; target=&quot;_blank&quot; rel=&quot;external nofollow noopener noreferrer&quot;&gt;FreeMdict&lt;/a&gt;）。&lt;/p&gt;
&lt;p&gt;而对于自己最常使用的macOS，支持Mdict词库的GoldenDict开发进度缓慢，界面不太好看，有时会遇到Bug。而另一款欧路词典需要收费才能添加自定义词库，而且界面、操作也不令人满意。&lt;/p&gt;
&lt;p&gt;更新：欧路词典用户体验还可以。目前是常用的词典转换成macOS Dictionary格式使用，其它词典在欧路词典使用。毕竟每本词典都转换的话太费时间了。&lt;/p&gt;
&lt;p&gt;相反，macOS系统原生的Dictionary有着良好的操作体验，支持三指取词，阅读体验也很棒，却没有那么多自定义词库可以添加。&lt;/p&gt;
&lt;p&gt;于是，就想着把两者的优点结合起来，将丰富的Mdict词库转换成macOS Dictionary支持的格式，而且支持图片显示、发音等等功能。&lt;/p&gt;
&lt;p&gt;下面简要简要记录由Mdict词库文件转换成完美macOS Dictionary词库文件的过程。&lt;/p&gt;
    
    </summary>
    
      <category term="Software" scheme="https://kaihao.io/categories/Software/"/>
    
      <category term="Dictionary" scheme="https://kaihao.io/categories/Software/Dictionary/"/>
    
    
      <category term="macOS" scheme="https://kaihao.io/tags/macOS/"/>
    
      <category term="dictionary" scheme="https://kaihao.io/tags/dictionary/"/>
    
      <category term="Mdict" scheme="https://kaihao.io/tags/Mdict/"/>
    
      <category term="Alfred" scheme="https://kaihao.io/tags/Alfred/"/>
    
  </entry>
  
  <entry>
    <title>用Hexo搭建博客记录</title>
    <link href="https://kaihao.io/2018/hexo-blog/"/>
    <id>https://kaihao.io/2018/hexo-blog/</id>
    <published>2018-01-02T07:39:39.833Z</published>
    <updated>2019-10-16T09:08:36.848Z</updated>
    
    <content type="html"><![CDATA[<p>以前总没有一个合适的平台发点自己随便写的东西（其实是自己太懒没怎么写），这几天终于把博客搭起来了。建这个博客也是督促自己多多动笔。许多东西不写下来也就慢慢消逝了。当然如果有其他人愿意看，甚至能对他们有所帮助，那就更好了。</p><p>下面把博客搭建的过程简要记录一下。</p><a id="more"></a><h3 id="博客搭建过程"><a href="#博客搭建过程" class="headerlink" title="博客搭建过程"></a>博客搭建过程</h3><p>博客采用Hexo框架与NexT主题<del>，托管在GitHub Pages上</del>。</p><p>Hexo安装和使用见<a href="https://hexo.io/docs/index.html" target="_blank" rel="external nofollow noopener noreferrer">Hexo.io</a></p><p>NexT主题见<a href="https://github.com/iissnan/hexo-theme-next" target="_blank" rel="external nofollow noopener noreferrer">iissnan/hexo-theme-next</a>，不过现在<a href="https://github.com/iissnan" target="_blank" rel="external nofollow noopener noreferrer">iissnan</a>已经把维护主要交给<a href="https://github.com/ivan-nginx" target="_blank" rel="external nofollow noopener noreferrer">ivan-nginx</a>了，从6.0.0版本开始该主题转移至<a href="https://github.com/theme-next/hexo-theme-next" target="_blank" rel="external nofollow noopener noreferrer">hexo-theme-next</a>。</p><p>目前NexT具体配置说明见<a href="http://theme-next.iissnan.com" target="_blank" rel="external nofollow noopener noreferrer">http://theme-next.iissnan.com</a>，以后也许会搬到<a href="https://theme-next.org" target="_blank" rel="external nofollow noopener noreferrer">https://theme-next.org</a>。</p><p>域名是在Namecheap上注册的，DNS解析服务用<del>DNSPod</del>已改为Namecheap自带的BasicDNS（因为最近DNSPod解析服务在大陆以外不太正常，导致网站不能访问，而Namecheap BasicDNS在各地均正常。另外吐槽下DNSPod UI太老土，好久没改了，还有是有严重Bug，不能删除已添加的域名）。</p><p><del>GitHub Pages设置见官网说明即可。如果是独立域名的话CNAME和DNS解析要配置一下。</del></p><p>目前已由GitHub Pages迁移到Netlify，因为GitHub屏蔽了百度的爬虫，百度无法收录。一种解决方法是同时托管在Coding Pages上。但是Coding Pages上不付费就要加上Hosted by Coding Pages的标志。而且经过<a href="https://www.17ce.com/" target="_blank" rel="external nofollow noopener noreferrer">17ce</a>测试三者中还是Netlify平均访问速度最快，还免费提供HTTPS支持。Netlify设置可参考<a href="https://jaeger.itscoder.com/web/2017/08/30/github-page-https" target="_blank" rel="external nofollow noopener noreferrer">GitHub Page 博客自定义域名添加 HTTPS 支持</a>。</p><p>更新：GitHub Pages现在也提供自定义域名的HTTPS支持了，见<a href="https://blog.github.com/2018-05-01-github-pages-custom-domains-https/" target="_blank" rel="external nofollow noopener noreferrer">Custom domains on GitHub Pages gain support for HTTPS</a>。</p><p>​        </p><p>下面是一些记录，方便以后用到时参考。</p><h3 id="Hexo配置"><a href="#Hexo配置" class="headerlink" title="Hexo配置"></a>Hexo配置</h3><ul><li>插入Twitter、iframe、Vimeo、YouTube、HTML与JavaScript见<a href="https://hexo.io/docs/tag-plugins.html" target="_blank" rel="external nofollow noopener noreferrer">Tag Plugins</a>。</li><li>要使每片post有独立的资源文件夹，见<a href="https://hexo.io/docs/asset-folders.html" target="_blank" rel="external nofollow noopener noreferrer">Asset Folders</a>。</li><li>部署到不同平台，见<a href="https://hexo.io/docs/deployment.html" target="_blank" rel="external nofollow noopener noreferrer">Deploy</a>。</li></ul><h3 id="主题配置"><a href="#主题配置" class="headerlink" title="主题配置"></a>主题配置</h3><ul><li>菜单设置、头像设置见<a href="http://theme-next.iissnan.com/getting-started.html" target="_blank" rel="external nofollow noopener noreferrer">http://theme-next.iissnan.com/getting-started.html</a></li><li>设置字体库、修改侧边栏社交链接、开启打赏功能、设置友情链接、添加微信公众号见<a href="http://theme-next.iissnan.com/theme-settings.html" target="_blank" rel="external nofollow noopener noreferrer">http://theme-next.iissnan.com/theme-settings.html</a></li><li>评论系统、分享系统、统计与分析系统、搜索服务、MathJax服务见<a href="http://theme-next.iissnan.com/third-party-services.html" target="_blank" rel="external nofollow noopener noreferrer">http://theme-next.iissnan.com/third-party-services.html</a></li><li>评论系统目前采用的是Disqus，缺点是会被墙。这可以通过自建代理解决。各个评论系统介绍可见<a href="https://blog.shuiba.co/comment-systems-recommendation" target="_blank" rel="external nofollow noopener noreferrer">第三方评论系统推荐</a></li><li>目前添加的第三方服务还有Google Analytics、不蒜子UV&amp;PV统计、LeanCloud阅读次数统计、Local Search、Widget Pack评分等</li><li>设置阅读全文、关闭页面的评论功能见<a href="http://theme-next.iissnan.com/faqs.html" target="_blank" rel="external nofollow noopener noreferrer">http://theme-next.iissnan.com/faqs.html</a></li></ul><h3 id="其它"><a href="#其它" class="headerlink" title="其它"></a>其它</h3><ul><li><a href="http://www.itvincent.info/2017/02/06/hexo-blog-baidu-google-seo/" target="_blank" rel="external nofollow noopener noreferrer">提交百度和Google收录</a></li><li><a href="https://www.zhihu.com/question/39130089" target="_blank" rel="external nofollow noopener noreferrer">hexo博文分类数和标签数显示不正确怎么办？</a></li><li><a href="http://www.arao.me/2015/hexo-next-theme-optimize-seo/" target="_blank" rel="external nofollow noopener noreferrer">SEO优化</a></li><li>几个常见的问题，比如<code>hexo g</code>与<code>hexo s</code>命令执行失败、无法通过浏览器访问本地网页等，见<a href="http://www.yellowmax2001.com/2017/08/08/hexo%E6%B7%B1%E5%BA%A6%E4%BD%BF%E7%94%A8/" target="_blank" rel="external nofollow noopener noreferrer">hexo博客深度使用</a></li></ul><p>下面是几个详细的Hexo&amp;NexT Theme配置教程，太细碎了其实很多其实内容不会用到。</p><ul><li><a href="http://yangbingdong.com/2017/build-blog-hexo-base/" target="_blank" rel="external nofollow noopener noreferrer">基于Hexo+github+coding搭建个人博客——基础篇(从菜鸟到放弃)</a></li><li><a href="http://yangbingdong.com/2017/build-blog-hexo-advanced/" target="_blank" rel="external nofollow noopener noreferrer">基于Hexo搭建个人博客——进阶篇(从入门到入土)</a></li><li><a href="https://reuixiy.github.io/technology/computer/computer-aided-art/2017/06/09/hexo-next-optimization.html" target="_blank" rel="external nofollow noopener noreferrer">打造个性超赞博客Hexo+NexT+GithubPages的超深度优化</a></li></ul>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;以前总没有一个合适的平台发点自己随便写的东西（其实是自己太懒没怎么写），这几天终于把博客搭起来了。建这个博客也是督促自己多多动笔。许多东西不写下来也就慢慢消逝了。当然如果有其他人愿意看，甚至能对他们有所帮助，那就更好了。&lt;/p&gt;
&lt;p&gt;下面把博客搭建的过程简要记录一下。&lt;/p&gt;
    
    </summary>
    
      <category term="Software" scheme="https://kaihao.io/categories/Software/"/>
    
      <category term="Hexo" scheme="https://kaihao.io/categories/Software/Hexo/"/>
    
    
      <category term="blog" scheme="https://kaihao.io/tags/blog/"/>
    
      <category term="Hexo" scheme="https://kaihao.io/tags/Hexo/"/>
    
      <category term="GitHub" scheme="https://kaihao.io/tags/GitHub/"/>
    
      <category term="Netlify" scheme="https://kaihao.io/tags/Netlify/"/>
    
  </entry>
  
</feed>
