前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Alfred 4: MacOS效率提升大杀器(下篇)

Alfred 4: MacOS效率提升大杀器(下篇)

作者头像
Y1ng
发布2022-10-31 11:25:24
8790
发布2022-10-31 11:25:24
举报
文章被收录于专栏:颖奇L'Amore

Author: 颖奇L’Amore

Blog: www.gem-love.com


MacOS高效使用文章合集:here

前言

前篇中我们介绍了Alfred的内置feature,这篇文章介绍Alfred的终极技能:Workflow

注意,未激活的Alfred不支持workflow功能,所以你需要先购买powerpack激活码

初识workflow

workflow是由用户开发的工作流程,只要你懂得任何一门编程语言基本上都可以来编写自己的workflow,可以通过以下几个渠道获取别人分享的workflow:

  1. https://www.alfredapp.com/workflows/
  2. http://www.packal.org/workflow-list
  3. https://github.com/zenorocha/alfred-workflows
  4. https://github.com/alfred-workflows/awesome-alfred-workflows
  5. https://github.com/ctwise/alfred-workflows
  6. https://pacmax.org/
  7. https://github.com/vitorgalvao/alfred-workflows/
  8. https://www.alfredforum.com/forum/3-share-your-workflows/

其中8是论坛,大家可以自由分享自己写的workflow;其他是精选workflow合集,上面第3个里有相应的效果图,可以先去点进去看一下workflow的使用效果,然后下载自己需要的workflow

Debug

有时候我们发现导入了别人的workflow,然后自己用不了,这时候就需要调试了 这里我以我自己的环境为例,实际操作一下debug and fix的流程

举例1:encode / decode

下载:https://github.com/willfarrell/alfred-encode-decode-workflow 这是它的使用效果:

但是我却用不了:

此时我们进入该workflow,点击右上角的🕷打开debug页面,可以发现错误原因是/bin/bash: php: command not found

那么我们双击encode和decode的script filter打开,发现它的代码实际上是直接用bash去执行了php

这可能是PATH中找不到php的路径,所以我们直接将其改为自己的php的绝对路径

改完之后就能用了:

举例2:DevDocs

下载:https://github.com/yannickglt/alfred-devdocs 这是它的使用效果:

同样我本地用不了:

报错显示找不到所使用的的编程语言,进入workflow双击打开,可以发现它使用的是/usr/bin/php而我们的php不在这个目录

首先考虑用软链接把php链接过来,但奈何/usr/bin目录在当前macos版本已经不可写了

这时候只能用bash去调用php了

首先我们先看一个run script,是不用传参的

使用的语言改成/bin/bash,同时代码改成:

代码语言:javascript
复制
/Applications/MxSrvs/bin/php/bin/php -r <span class="hljs-string">'$query = "nuke";require_once("scripts/conf.php");'</span>

然后我们看node这个script filter,原本使用的/usr/bin/php时的代码如下:

代码语言:javascript
复制
$query = "{query}";
$documentation = 'node';
require_once("scripts/devdocs.php");

这个是要接收参数的,有点麻烦,我们先右键open in finder进入该workflow的目录

新建一个node.php,代码写成:

代码语言:javascript
复制
<span class="hljs-meta">&lt;?php</span>
<span class="hljs-variable">$query</span> = <span class="hljs-variable">$argv</span>[<span class="hljs-number">1</span>];
<span class="hljs-variable">$documentation</span> = <span class="hljs-string">'node'</span>;
<span class="hljs-keyword">require_once</span>(<span class="hljs-string">"scripts/devdocs.php"</span>);

然后使用的语言改成/bin/bash,同时代码改成:

代码语言:javascript
复制
query=<span class="hljs-string">"{query}"</span>
/Applications/MxSrvs/bin/php/bin/php node.php <span class="hljs-variable">$query</span>

此时就解决了/usr/bin/php未安装的问题,尽管此时还不能用,debug显示报错为网页访问不了(但这不是我们workflow的问题了,是对方的文档请求不了了,node命令是直接去这个远程文档去搜索的):

代码语言:javascript
复制
Warning: file_get_contents(http://maxcdn-docs.devdocs.io/node/index.json): failed to open stream: php_network_getaddresses: getaddrinfo failed: nodename nor servname provided, or not known in /Users/amortang/Library/Application Support/Alfred/Alfred.alfredpreferences/workflows/user.workflow.9CE45714-7860-4A74-B002-78AA58F3BC8E/scripts/devdocs.php on line 73

同样的方法把其他的script filter给处理了,依然不能用,看debug的php报错信息:

代码语言:javascript
复制
Deprecated: Array and string offset access syntax with curly braces is deprecated in /Users/amortang/Library/Application Support/Alfred/Alfred.alfredpreferences/workflows/user.workflow.9CE45714-7860-4A74-B002-78AA58F3BC8E/scripts/vendor/rodneyrehm/plist/classes/CFPropertyList/CFBinaryPropertyList.php on line 787

Call Stack:
    0.0002     395432   1. {main}() /Users/amortang/Library/Application Support/Alfred/Alfred.alfredpreferences/workflows/user.workflow.9CE45714-7860-4A74-B002-78AA58F3BC8E/cdocadd.php:0
    0.0008     443448   2. require_once('/Users/amortang/Library/Application Support/Alfred/Alfred.alfredpreferences/workflows/user.workflow.9CE45714-7860-4A74-B002-78AA58F3BC8E/scripts/conf.php') /Users/amortang/Library/Application Support/Alfred/Alfred.alfredpreferences/workflows/user.workflow.9CE45714-7860-4A74-B002-78AA58F3BC8E/cdocadd.php:4
    0.0017     549832   3. CFPropertyList\DevDocsConf-&gt;__construct() /Users/amortang/Library/Application Support/Alfred/Alfred.alfredpreferences/workflows/user.workflow.9CE45714-7860-4A74-B002-78AA58F3BC8E/scripts/conf.php:253
    0.1059     550896   4. CFPropertyList\DevDocsConf-&gt;openPlist() /Users/amortang/Library/Application Support/Alfred/Alfred.alfredpreferences/workflows/user.workflow.9CE45714-7860-4A74-B002-78AA58F3BC8E/scripts/conf.php:40
    0.1059     550896   5. spl_autoload_call() /Users/amortang/Library/Application Support/Alfred/Alfred.alfredpreferences/workflows/user.workflow.9CE45714-7860-4A74-B002-78AA58F3BC8E/scripts/conf.php:51
    0.1059     550952   6. Composer\Autoload\ClassLoader-&gt;loadClass() /Users/amortang/Library/Application Support/Alfred/Alfred.alfredpreferences/workflows/user.workflow.9CE45714-7860-4A74-B002-78AA58F3BC8E/scripts/conf.php:51
    0.1059     551208   7. Composer\Autoload\includeFile() /Users/amortang/Library/Application Support/Alfred/Alfred.alfredpreferences/workflows/user.workflow.9CE45714-7860-4A74-B002-78AA58F3BC8E/scripts/vendor/composer/ClassLoader.php:274
    0.1063     625656   8. include('/Users/amortang/Library/Application Support/Alfred/Alfred.alfredpreferences/workflows/user.workflow.9CE45714-7860-4A74-B002-78AA58F3BC8E/scripts/vendor/rodneyrehm/plist/classes/CFPropertyList/CFPropertyList.php') /Users/amortang/Library/Application Support/Alfred/Alfred.alfredpreferences/workflows/user.workflow.9CE45714-7860-4A74-B002-78AA58F3BC8E/scripts/vendor/composer/ClassLoader.php:382


Deprecated: Array and string offset access syntax with curly braces is deprecated in /Users/amortang/Library/Application Support/Alfred/Alfred.alfredpreferences/workflows/user.workflow.9CE45714-7860-4A74-B002-78AA58F3BC8E/scripts/vendor/rodneyrehm/plist/classes/CFPropertyList/CFBinaryPropertyList.php on line 810

Call Stack:
    0.0002     395432   1. {main}() /Users/amortang/Library/Application Support/Alfred/Alfred.alfredpreferences/workflows/user.workflow.9CE45714-7860-4A74-B002-78AA58F3BC8E/cdocadd.php:0
    0.0008     443448   2. require_once('/Users/amortang/Library/Application Support/Alfred/Alfred.alfredpreferences/workflows/user.workflow.9CE45714-7860-4A74-B002-78AA58F3BC8E/scripts/conf.php') /Users/amortang/Library/Application Support/Alfred/Alfred.alfredpreferences/workflows/user.workflow.9CE45714-7860-4A74-B002-78AA58F3BC8E/cdocadd.php:4
    0.0017     549832   3. CFPropertyList\DevDocsConf-&gt;__construct() /Users/amortang/Library/Application Support/Alfred/Alfred.alfredpreferences/workflows/user.workflow.9CE45714-7860-4A74-B002-78AA58F3BC8E/scripts/conf.php:253
    0.1059     550896   4. CFPropertyList\DevDocsConf-&gt;openPlist() /Users/amortang/Library/Application Support/Alfred/Alfred.alfredpreferences/workflows/user.workflow.9CE45714-7860-4A74-B002-78AA58F3BC8E/scripts/conf.php:40
    0.1059     550896   5. spl_autoload_call() /Users/amortang/Library/Application Support/Alfred/Alfred.alfredpreferences/workflows/user.workflow.9CE45714-7860-4A74-B002-78AA58F3BC8E/scripts/conf.php:51
    0.1059     550952   6. Composer\Autoload\ClassLoader-&gt;loadClass() /Users/amortang/Library/Application Support/Alfred/Alfred.alfredpreferences/workflows/user.workflow.9CE45714-7860-4A74-B002-78AA58F3BC8E/scripts/conf.php:51
    0.1059     551208   7. Composer\Autoload\includeFile() /Users/amortang/Library/Application Support/Alfred/Alfred.alfredpreferences/workflows/user.workflow.9CE45714-7860-4A74-B002-78AA58F3BC8E/scripts/vendor/composer/ClassLoader.php:274
    0.1063     625656   8. include('/Users/amortang/Library/Application Support/Alfred/Alfred.alfredpreferences/workflows/user.workflow.9CE45714-7860-4A74-B002-78AA58F3BC8E/scripts/vendor/rodneyrehm/plist/classes/CFPropertyList/CFPropertyList.php') /Users/amortang/Library/Application Support/Alfred/Alfred.alfredpreferences/workflows/user.workflow.9CE45714-7860-4A74-B002-78AA58F3BC8E/scripts/vendor/composer/ClassLoader.php:382


Warning: Invalid argument supplied for foreach() in /Users/amortang/Library/Application Support/Alfred/Alfred.alfredpreferences/workflows/user.workflow.9CE45714-7860-4A74-B002-78AA58F3BC8E/scripts/conf.php on line 107

Call Stack:
    0.0002     395432   1. {main}() /Users/amortang/Library/Application Support/Alfred/Alfred.alfredpreferences/workflows/user.workflow.9CE45714-7860-4A74-B002-78AA58F3BC8E/cdocadd.php:0
    0.0008     443448   2. require_once('/Users/amortang/Library/Application Support/Alfred/Alfred.alfredpreferences/workflows/user.workflow.9CE45714-7860-4A74-B002-78AA58F3BC8E/scripts/conf.php') /Users/amortang/Library/Application Support/Alfred/Alfred.alfredpreferences/workflows/user.workflow.9CE45714-7860-4A74-B002-78AA58F3BC8E/cdocadd.php:4
    0.0017     549832   3. CFPropertyList\DevDocsConf-&gt;__construct() /Users/amortang/Library/Application Support/Alfred/Alfred.alfredpreferences/workflows/user.workflow.9CE45714-7860-4A74-B002-78AA58F3BC8E/scripts/conf.php:253
    0.1118     916104   4. CFPropertyList\DevDocsConf-&gt;setDocumentations() /Users/amortang/Library/Application Support/Alfred/Alfred.alfredpreferences/workflows/user.workflow.9CE45714-7860-4A74-B002-78AA58F3BC8E/scripts/conf.php:41

这是因为7.4的php的数组不支持用大括号寻址了

根据php的报错修改一下源码的对应源码,可以用了:

编写workflow

类型

我们右键可以发现,Alfred支持的东西太多了,比如打开文件、弹个通知、打开浏览器等等

这里面有一些东西是用来控制执行流程之类的东西的,但是最核心的东西其实还是运行脚本,脚本里写的才是我们最核心的操作,你会发现有两种脚本运行:Run Script和Script Filter

简单来讲,想让一个脚本后台自己的去跑一个脚本,没有反馈,这种用run script,例如:

如果想通过一个脚本进行相应操作,不用回车,直接得到单个或多个结果,则需要Script Filter,例如:

写一个Run Script

我这个电脑的AntSword有个bug,没法退出,每次都得kill进程才能退出,所以我们就以这个为需求来写一个kill蚁剑进程的东西 新建workflow选空白即可,他也给我们提供了一些流程模板

对workflow写一些基本信息

添加一个keywords,用klat来触发,并选择不需要参数:

后面跟上一个Run Script,不用输入信息,执行固定的语句,语言选择/bin/bash

代码语言:javascript
复制
ps -ef | grep AntSword | grep -v grep | awk '{print $2}' | xargs kill -9

效果如下(蚁剑被kill掉退出了):

当然这个workflow就比较简单(但是也达到了提升工作效率的目的,这就是Alfred的初衷),其他复杂的功能大家自行探索吧,方法就是这样的。

写一个Script Filter

这里我们就来简单写一个货币转换的workflow吧,可以在我的github下载这个workflow

使用方法可以看github的说明,转100美元到欧元效果如下:

整个项目就一个script filter,将用户输入传给了run.py这个python文件:

在看具体文件代码之前,我们需要先来看Alfred的官方文档

这个文档告诉我们,想要使用script filter让结果显示出来,脚本的输出是有固定的json格式的,例如:

代码语言:javascript
复制
{<span class="hljs-attr">"items"</span>: [
    {
        <span class="hljs-attr">"uid"</span>: <span class="hljs-string">"desktop"</span>,
        <span class="hljs-attr">"type"</span>: <span class="hljs-string">"file"</span>,
        <span class="hljs-attr">"title"</span>: <span class="hljs-string">"Desktop"</span>,
        <span class="hljs-attr">"subtitle"</span>: <span class="hljs-string">"~/Desktop"</span>,
        <span class="hljs-attr">"arg"</span>: <span class="hljs-string">"~/Desktop"</span>,
        <span class="hljs-attr">"autocomplete"</span>: <span class="hljs-string">"Desktop"</span>,
        <span class="hljs-attr">"icon"</span>: {
            <span class="hljs-attr">"type"</span>: <span class="hljs-string">"fileicon"</span>,
            <span class="hljs-attr">"path"</span>: <span class="hljs-string">"~/Desktop"</span>
        }
    }
]}

items是一个数组,里面的每一个元素是一个对象,一个对象就是一个输出结果,具体的参数的意思大家把上面文档读一读就明白了。

接着我们就来写转换货币的具体代码,主要的思路就是获取用户的输入,然后判断是否合法,如果符合要求,就去https://api.getgeoapi.com/v2/currency/convert这个货币兑换的api进行货币转换。最后的输出一定是要符合它要求的json格式,所以使用了json.dumps

代码语言:javascript
复制
<span class="hljs-keyword">import</span> requests
<span class="hljs-keyword">import</span> re
<span class="hljs-keyword">import</span> os 
<span class="hljs-keyword">import</span> sys 
<span class="hljs-keyword">import</span> warnings
<span class="hljs-keyword">import</span> json


warnings.filterwarnings(<span class="hljs-string">'ignore'</span>)

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">mysplit</span>(<span class="hljs-params">s</span>):</span>
	<span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> re.match(<span class="hljs-string">r"^[\d.]+[a-zA-Z]+$"</span>, s):
		sys.exit(<span class="hljs-number">0</span>)
	cnt = <span class="hljs-number">0</span>
	<span class="hljs-keyword">while</span> cnt &lt; <span class="hljs-built_in">len</span>(s):
		<span class="hljs-keyword">if</span> s[cnt].isalpha():
			<span class="hljs-keyword">break</span>
		cnt += <span class="hljs-number">1</span>
	<span class="hljs-keyword">return</span> [s[:cnt], s[cnt:]]


<span class="hljs-keyword">if</span> <span class="hljs-built_in">len</span>(sys.argv) &lt; <span class="hljs-number">2</span> <span class="hljs-keyword">or</span> <span class="hljs-keyword">not</span> re.match(<span class="hljs-string">r"^[\d.]+[a-zA-Z]+\ [a-zA-Z]+$"</span>, sys.argv[<span class="hljs-number">1</span>]):
	sys.exit(<span class="hljs-number">0</span>)

api = os.getenv(<span class="hljs-string">'api'</span>)
amonut_from = sys.argv[<span class="hljs-number">1</span>].split(<span class="hljs-string">' '</span>)[<span class="hljs-number">0</span>]
to = sys.argv[<span class="hljs-number">1</span>].split(<span class="hljs-string">' '</span>)[<span class="hljs-number">1</span>]
amonut_from_split = mysplit(amonut_from)

baseurl = <span class="hljs-string">"https://api.getgeoapi.com/v2/currency/convert"</span> 
url = <span class="hljs-string">"%s?api_key=%s&amp;from=%s&amp;to=%s&amp;amount=%s&amp;format=json"</span> % (baseurl, api, amonut_from_split[<span class="hljs-number">1</span>], to, amonut_from_split[<span class="hljs-number">0</span>])
r = requests.get(url)
res = r.json()
<span class="hljs-keyword">if</span> res[<span class="hljs-string">'status'</span>] != <span class="hljs-string">'success'</span> :
	<span class="hljs-built_in">print</span>(json.dumps({<span class="hljs-string">"items"</span>:[{<span class="hljs-string">"title"</span>: <span class="hljs-string">"Error"</span>, <span class="hljs-string">"subtitle"</span> : <span class="hljs-string">"something wrong"</span>, <span class="hljs-string">"arg"</span> : <span class="hljs-string">"please check your input"</span>}]})) 
	sys.exit(<span class="hljs-number">0</span>)

result = {}
<span class="hljs-keyword">try</span>:
	result = res[<span class="hljs-string">'rates'</span>][<span class="hljs-built_in">list</span>(res[<span class="hljs-string">'rates'</span>].keys())[<span class="hljs-number">0</span>]]
<span class="hljs-keyword">except</span>:
	<span class="hljs-built_in">print</span>(json.dumps({<span class="hljs-string">"items"</span>:[{<span class="hljs-string">"title"</span>: <span class="hljs-string">"Error"</span>, <span class="hljs-string">"subtitle"</span> : <span class="hljs-string">"something wrong"</span>, <span class="hljs-string">"arg"</span> : <span class="hljs-string">"please check your input"</span>}]})) 
	sys.exit(<span class="hljs-number">0</span>)


items = {<span class="hljs-string">"items"</span>: [
 		{
			<span class="hljs-string">"subtitle"</span>: <span class="hljs-string">"currency name"</span>,
			<span class="hljs-string">"title"</span>: result[<span class="hljs-string">'currency_name'</span>],
			<span class="hljs-string">"arg"</span>: result[<span class="hljs-string">'currency_name'</span>]
		},
		{
			<span class="hljs-string">"subtitle"</span>: <span class="hljs-string">"rate"</span>,
			<span class="hljs-string">"title"</span>: result[<span class="hljs-string">'rate'</span>],
			<span class="hljs-string">"arg"</span>: result[<span class="hljs-string">'rate'</span>]
		},
		{
			<span class="hljs-string">"subtitle"</span>: <span class="hljs-string">"Total value of currency after conversion"</span>,
			<span class="hljs-string">"title"</span>: result[<span class="hljs-string">'rate_for_amount'</span>],
			<span class="hljs-string">"arg"</span>: result[<span class="hljs-string">'rate_for_amount'</span>]
		}]
	}
<span class="hljs-built_in">print</span>(json.dumps(items))

但是这里面我们使用了一个api接口,这个api接口需要有API Key才可以,我们不能把这个API Key写死在代码里,因为我们希望能让用户自己去注册去申请它自己的API Key,而又不用编写源代码文件就可以把API Key导入进去,这时我们可以设置Alfred当前workflow的环境变量。点击这个[x]

左边是项目的描述,右边就是环境变量的键和值,勾上Do not export的话导出时就不会把值给导出了

这样在代码里就可以通过获取环境变量的方法os.getenv('api')来取到了。 在share中可以导出workflow,相当于生成release版本,这里可以对项目信息进行一些配置之类的,然后就可以分享给你的小伙伴了,或者分享到Alfred论坛

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-04-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言▸
  • 初识workflow▸
  • Debug▸
    • 举例1:encode / decode▸
      • 举例2:DevDocs▸
      • 编写workflow▸
        • 类型▸
          • 写一个Run Script▸
            • 写一个Script Filter▸
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档