引言

首先给出仓库地址

在使用了一段时间的 MacOS Spotlight 搜索过后被其丝滑的体验俘获,并且作为一个多年的群晖 Synology NAS 用户,其内置的 Universal Search 功能更是及其强大,这个功能使用 ElasticSearch 提供搜索服务,使用 Apache Tika 进行数据提取,可以对 NAS 中的所有文件内容注意是内容进行检索,功能是非常的强大。

所以我萌生了将 Universal Search 搬到电脑上的想法,经过调研发现非常的困难其实是我太菜,将这么重型的服务运行在笔记本电脑上常驻是不现实的,经过一番查找发现了很多资料,最后决定使用 Alfred 与 NAS 进行交互从而快速检索文件。

主要流程

由于以前没有接触过 Workflow 开发,所以这次是跟着官方的 Example 走了一遍,结果发现官方的 workflow-python 竟然不支持 Python3(官方文档说马上就要开发新版本 Workflow),并且我找到的 Synology API 只支持 Python3 ,看起来是我和 Python 五行不合 😇😇😇

在一番谷歌后找到了第三方开发者维护的支持 Python3 的版本,成功的跑起来了~~

全局搜索API

找到的 API 中并没有实现全局搜索的 API,开始以为是 FileStation 中的搜索🔍,尝试了一番发现没有作用😃。

作为一个开源的共产主义者,在原始仓库中实现了认证流程,那我们直接糊一个就行,首先我们进行一个包的抓,看看搜索时调用的到底是哪个API

发现 API 名称是 SYNO.Finder.FileIndexing.Search然后抄一个登陆流程

1
2
3
4
5
6
7
8
9
10
def __init__(self, ip_address, port, username, password, secure=False, cert_verify=False, dsm_version=7, debug=True, otp_code=None):
self.session = auth.Authentication(ip_address, port, username, password, secure, cert_verify, dsm_version, debug, otp_code)
self.session.login('Finder')
self.session.get_api_list('Finder')
self.request_data = self.session.request_data
self.finder_list = self.session.app_api_list
self._sid = self.session.sid
self.base_url = self.session.base_url
if debug is True:
print('You are now logged in!')

可以在 finder_list 中看到所有的 API,可以发现对我们有用的就一个 SYNO.Finder.FileIndexing.Search ,然后把前面抓到的包进行一个抄

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
def search(self, keyword):
api_name = 'SYNO.Finder.FileIndexing.Search'
info=self.finder_list[api_name]
api_path = info['path']

req_param={
"query_serial":1,
"indice":'[]',
"keyword":keyword,
"orig_keyword":keyword,
"criteria_list":'[]',
"from":0,
"size":10,
"fields":'["SYNOMDAcquisitionMake","SYNOMDAcquisitionModel","SYNOMDAlbum","SYNOMDAperture","SYNOMDAudioBitRate","SYNOMDAudioTrackNumber","SYNOMDAuthors","SYNOMDCodecs","SYNOMDContentCreationDate","SYNOMDContentModificationDate","SYNOMDCreator","SYNOMDDurationSecond","SYNOMDExposureTimeString","SYNOMDExtension","SYNOMDFSCreationDate","SYNOMDFSName","SYNOMDFSSize","SYNOMDISOSpeed","SYNOMDLastUsedDate","SYNOMDMediaTypes","SYNOMDMusicalGenre","SYNOMDOwnerUserID","SYNOMDOwnerUserName","SYNOMDRecordingYear","SYNOMDResolutionHeightDPI","SYNOMDResolutionWidthDPI","SYNOMDTitle","SYNOMDVideoBitRate","SYNOMDIsEncrypted"]',
"file_type":"",
"search_weight_list":'[{"field":"SYNOMDWildcard","weight":1},{"field":"SYNOMDTextContent","weight":1},{"field":"SYNOMDSearchFileName","weight":8.5,"trailing_wildcard":"true"}]',
"sorter_field":"relevance",
"sorter_direction":"asc",
"sorter_use_nature_sort":"false",
"sorter_show_directory_first":"true",
"api":"SYNO.Finder.FileIndexing.Search",
"method":"search",
"version":1
}

return self.request_data(api_name, api_path, req_param)

这样我们的搜索功能就是完成了,接下来就是把输出丢到 Alfred 中。

Workflow下拉菜单

但似乎这位开发者维护的包 workflow.add_item 不起作用?那就换个方法,虽然在 add 后并没有出现新的内容,但 Alfred 会接受符合规范的 xml 或 json 格式的输出作为下拉菜单的选项。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
for item in res:
t=""
if item['SYNOMDIsDir'] != 'y':
t="/"+item["SYNOMDFSName"]
result = {
"title": item["SYNOMDFSName"],
"subtitle": item["SYNOMDSharePath"],
"arg": item["SYNOMDSharePath"].replace(t,""),
"autocomplete": "",
"icon": {
"path": "./icon.png"
}
}
dat.append(result)
response = json.dumps({
"items": dat
})
sys.stdout.write(response)

这样就可以将标准输出作为下拉菜单了,最后看看效果

可以看到3,4,5文件名并没有出现信息论,但已经匹配到文件内容了,然后最终想实现的效果是按下回车打开对应文件,不过这里不太清楚该使用 webAPI 下载文件实现还是直接在挂载到本地的网络磁盘中打开,就暂时使用回车复制 NAS 中的文件路径,顺便打开 FileStation,直接粘贴路径就能访问到文件了,为了防止误下载,如果搜索到的路径是一个文件的话,还要删除掉最后的文件名,以免 FileStation 访问出错

参考