小帽子alfred是mac上最為傳奇的效率作品,, 今天,我們一起來探索alfred workflow 的世界吧!
1. alfred 簡(jiǎn)介
小帽子是 Mac 平臺(tái)上最為傳奇的效率作品,,譽(yù)為神兵利器毫不為過,。
由于中文網(wǎng)絡(luò)上尚無系統(tǒng)的alfred workflow 開發(fā)教程,便有了寫一個(gè)教程的心思,,以期拋磚引玉,,為alfred吸引更多的開發(fā)者加入。
2.alfred 插件開發(fā)
2.1 alfred 插件開發(fā)概述
Workflow 是alfred2.0推出的最激動(dòng)人心的特性,,通過與腳本語言的交互,,workflow可以支持任意操作,把您日常的重復(fù)性事務(wù)封裝在腳本中,,大大的提高工作效率,。
Workflow 支持php、bash,、perl,、ruby以及python作為腳本語言,并內(nèi)置腳本語言解釋器,,并通過stdio的形式在各個(gè)腳本模塊中傳遞參數(shù),。
在代碼中插入 {query}塊可以接收上一個(gè)腳本輸出的內(nèi)容。形成完整的控制鏈條,。 最后由alfred輸出至 Output 模塊,, 在Output模塊中, 我們可以啟動(dòng)瀏覽器,、將內(nèi)容復(fù)制到剪切板,、 啟動(dòng)通知中心、甚至執(zhí)行bash腳本,。
在日常的使用中,,我們通常通過關(guān)鍵字來調(diào)用某一模塊,例如“find xxx" 即是調(diào)用find內(nèi)建模塊 query內(nèi)容為xxx,。 在workflow的開發(fā)中,, 開發(fā)者可以自定義自己編寫模塊的關(guān)鍵字,,只要不與其他模塊沖突即可。
在workflow的結(jié)構(gòu)中,,數(shù)據(jù)流通過alfred的控制線進(jìn)行傳遞,,每一個(gè)腳本模塊的STDIO輸出會(huì)被alfred替換到 下一個(gè)腳本的{query}塊中。
如下圖所示:
其中,,我們使用『拖動(dòng)』的方式,,控制數(shù)據(jù)在workflow的流向:
以上的 有道翻譯workflow的數(shù)據(jù)流向是這樣的。
通過yd作為關(guān)鍵字啟動(dòng)workflow,, 如果直接回車,,使用OpenURL,啟動(dòng)youdao網(wǎng)站,。如果使用Cmd+回車的方式,,
則執(zhí)行Run Scirpt 并將其輸出到剪切板,并用Post Notification的方式,,在通知中心顯示,。
2.2 Alfred的XML格式概述
在Alfred腳本執(zhí)行的最后一部中, 所有數(shù)據(jù)要被封裝到XML格式中被alfred調(diào)用,,其格式為
<items>
<item autocomplete = "autocompletex" uid = "123321" arg = "argsx" >
<title >title</title>
<subtitle >subtitle</subtitle>
<icon >icon</icon>
</item>
</items>
運(yùn)行之后的效果是:
根節(jié)點(diǎn)為items 其中包括任意多個(gè)item節(jié)點(diǎn),,每一個(gè)item節(jié)點(diǎn)代表本次查詢結(jié)果的一行。
每一個(gè)item節(jié)點(diǎn)包括若干parameter與childnode,,其含義為:
uid: 每一個(gè)item要有一個(gè)獨(dú)立的uid,,不可重復(fù)
valid:值為yes 或者 no, 若為no,該行結(jié)果不可被選擇
autocomplete : 自動(dòng)補(bǔ)全的值,, 使用tab可以令alfred自動(dòng)補(bǔ)全為 autocompelete屬性的值.
arg:作為下一個(gè)模塊的參數(shù)傳遞
<title> 該行item的標(biāo)題,,也是主要顯示的位置。
<subtitle> 該行字標(biāo)題位置,,會(huì)被顯示為灰色小字
<icon> 該行圖標(biāo)的文件名,,其大小為64X64 pixels
2.3 {query} 與 stdio
alfred模塊間數(shù)據(jù)是如何傳遞的,曾經(jīng)困擾我很久,。
其數(shù)據(jù)流是這樣的,, 你在關(guān)鍵字之后的文字會(huì)作為第一個(gè)模塊的query, 由alfred替換代碼中{query}的位置, 該模塊print到stdio的數(shù)據(jù)會(huì)像第一個(gè)模塊一樣,,去替換第二個(gè)模塊的{query}位置,,直到最后生成XML文件, 只有最后一步是不一樣的,,也就是xml文件輸出之后, 用戶在不同的條目上按回車,, alfred將把該條目對(duì)應(yīng)的item的arg屬性的值傳遞給下一個(gè)模塊,。
2.4 python 開發(fā)示例
下面,,我將用開發(fā)一個(gè)百度詞典為例,詳細(xì)講解開發(fā)alred插件中的每一個(gè)步驟,。
2.4.1 Script Filter
Script Filter 的作用是提供一個(gè)Alfred workflow的起始點(diǎn),,可以通過點(diǎn)擊右上角的加號(hào),從Inputs中選擇,。
它的界面如下圖所示:
在上圖中可以看出, 輸入 “bdc hello” 之后,, alfred會(huì)啟動(dòng)一個(gè)python解釋器,,并運(yùn)行Scirpt欄中的代碼,。
Script中的{query}會(huì)被alfred自動(dòng)的取代為「hello」.
也就是,,此時(shí) 實(shí)際運(yùn)行的代碼是
import bddict
bddict.query('hello')
其中 , bddict.py 的代碼如下:
# -*- coding: utf_8 -*-
# author xiaogo
import sys
import hashlib
import time
import math
import base64
import urllib2
import urllib
import re
import json
import alfredxml
client_id = '1xML4eLvqG8runr4uHcDPU6f'
def is_cn_char(i):
return 0x4e00<=ord(i)<0x9fa6
def bdDict(From,To,Q):
resp = urllib2.urlopen("http://openapi.baidu.com/public/2.0/translate/dict/simple?client_id=%s&q=%s&from=%s&to=%s"%(client_id,Q,From,To)).read()
js = json.loads(resp,encoding = 'utf-8')
return js
# alfred 的入口函數(shù).
def query(query):
# 對(duì)query 作防御
if(len(query)==0):
rowList = [{'uid':'1',
'arg':'',
'autocomplete':'',
'icon':'icon.png',
'subtitle':'Please Input',
'title':'Please Input'}]
element = alfredxml.genAlfredXML(rowList)
print(element)
return
# 判斷是否為中文字符,若是 漢譯英 若否 英譯漢
if(is_cn_char(unicode(query,"utf-8")[0] )):
resp = bdDict("zh","en",query)
else:
resp = bdDict("en","zh",query)
if(resp[u'errno'] == 0): # 通過bdDict() 函數(shù) ,,調(diào)用百度詞典HTTP接口.
if(len(resp[u'data'])==0):
return
rowList = []
subtitle = ''
k = resp['data']['symbols'][0] # 解析JSON.
uid = 1
for i in k.keys():
if(i.startswith("ph_")):
subtitle +=i[3:]+'['+ resp['data']['symbols'][0][i] + ']'
# 解析JSON, 生成rowList
rowList.append({
'uid':uid,
'arg':query,
'autocomplete':query,
'icon':'icon.png',
'subtitle':subtitle.encode("utf-8"),
'title':'發(fā)音'})
uid +=1
for i in resp['data']['symbols'][0]['parts']:
if(len(i['part'])>0):
subtitle = reduce(lambda x,y:x+","+y, i['part'])
else:
subtitle = ''
title = reduce(lambda x,y:x+","+y, i['means'])
rowList.append({
'uid':uid,
'arg':query,
'autocomplete':query,
'icon':'icon.png',
'subtitle':subtitle.encode("utf-8"),
'title':title.encode("utf-8")})
uid +=1
else:
print("err")
pass
#print(rowList)
# 生成XML文件.
print(alfredxml.genAlfredXML(rowList))
其中, 生成XML的代碼如下 alfredxml.py :
# 生成XML文件
def genElement(lists):
assert(len(lists)%3==0)
name = lists[0] # 節(jié)點(diǎn)名
params = lists[1] # 節(jié)點(diǎn)屬性list
content = lists[2] # 節(jié)點(diǎn)內(nèi)容 , 可能是String 或者是包含其他Element.
string = ''
string +="<%s"%name + “ “ # 以下為解析XML List的過程
for k,v in params.items(): # 枚舉屬性
string+='%s = "%s" '%(k,v)
if(isinstance(content, str)): # 通過遞歸 解析子節(jié)點(diǎn)
text = content
else:
text = genElement(content)
string +=">" + text + "</%s>\n"%name
if(len(lists)<=3): # 通過遞歸, 解析同級(jí)節(jié)點(diǎn)
return string
else:
return string + genElement(lists[3:])
def genAlfredXML(rowList): # 生成alfred所需要的XML String.
item = []
for row in rowList:
tsi = ['title',{},row['title'],'subtitle',{},row['subtitle'],'icon',{},row['icon']]
item.extend(['item',{'uid':row['uid'],'arg':row['arg'],'autocomplete':row['autocomplete']},tsi])
items = ['items',{},item]
return genElement(items)
if __name__=='__main__':
rowList = [{'uid':'123321','arg':'argsx','autocomplete':'autocompletex','icon':'icon','subtitle':'subtitle','title':'title'}]
element = genAlfredXML(rowList)
print(element)
2.4.2 Output
output 是 alfred 中的『執(zhí)行器』。
通過Script Filter,, 我們已經(jīng)得到了一個(gè)alfred 的結(jié)果列表,, 通過點(diǎn)按回車鍵,,我們可以執(zhí)行相應(yīng)的命令,。
以百度詞典這個(gè)workflow為例,,我們打開了百度詞典的網(wǎng)站。
執(zhí)行的時(shí)候,,我們打開了http://dict.baidu.com/s?wd={query}
注意,,這里又出現(xiàn)了一個(gè){query}
這個(gè){query} 將承接 Scirpt Filter 中,,被點(diǎn)擊回車的那條XML 節(jié)點(diǎn)中的 arg參數(shù) ,。
實(shí)際上,我們不僅可以使用URL Open 作為 結(jié)果,,也可以使用Terminal Command 作為結(jié)果執(zhí)行。
使用Terminal ,,可以令你更加隨心所欲的控制你的MAC. 實(shí)現(xiàn)諸如Wifi切換、更改DNS服務(wù)器,、啟動(dòng)某個(gè)服務(wù)端、甚至可以控制你家的空調(diào)或者咖啡機(jī),, 這以前只有emacs才能做到 ;)
3.參考文獻(xiàn)
1.Alfred - workflow python dev lib
2.Tutorial on alfred workflow with python
|