京me快速发起联系人聊天插件

1,027 阅读6分钟

写在前面

插件实现 Cr. to zxu Jiang。

为什么做这件事?作为大厂搬砖人,每天在各种代码中周转之余,还要处理诸多消息。京me作为京东内部的通讯工具,确实有很多内在提高沟通效率的功能,但你或许还是有这样的体会:每天仍然重复大量的 “1.鼠标点击打开京me - 2.focus在搜索栏 - 3.键盘搜索好友 - 4.选择并发起聊天”。

因此在浅浅调研了下Alfred之后,考虑是否可以自定义开发一个插件,提高京me搜索聊天的效率。最终实现效果可大致理解为Mac的Spotlight Search,省去了很多鼠标操作。键盘键入后可以直接定位某一特定erp的联系人或者群聊并发起聊天,无论你身处哪个页面,都可以一键操作。

注意: 本插件实现及使用目前仅支持MacOs京东内部员工,但开发思路不受限制。

me_search_demo (1).gif

简介

Alfred介绍

Alfred 是一个用键盘通过热键、关键字、自定义插件来加快操作效率的工具,它不但是搜索工具,还是快速启动工具,甚至能够操作许多系统功能,扩充性极强。简单点说就是使用了 Alfred 后你就可以丢掉鼠标了!

Workflow 是Alfred2.0推出的最激动人心的特性,通过与脚本语言的交互,workflow可以支持任意操作,把日常的重复性事务封装在脚本中,大大的提高工作效率。

Workflow 支持phpbashperlruby以及python(本次所用脚本)作为脚本语言,并内置脚本语言解释器,并通过Stdio的形式在各个脚本模块中传递参数。

在代码中插入{query}块可以接收上一个脚本输出的内容。形成完整的控制链条。 最后由 Alfred 输出至 Output 模块, 在Output模块中, 我们可以启动浏览器、将内容复制到剪切板、 启动通知中心、甚至执行bash脚本。

在日常的使用中,我们通常通过关键字来调用某一模块,例如“find xxx” 即是调用find内建模块,query内容为xxx。 在workflow的开发中, 开发者可以自定义自己编写模块的关键字,只要不与其他模块冲突即可。

在workflow的结构中,数据流通过Alfred的控制线进行传递,每一个脚本模块的Stdio输出会被Alfred替换到下一个脚本的{query}块中。

原理概括

  1. 第一步通过joyspace的搜索API搜索京me联系人或者群;
url = "https://apijoyspace.jd.com/v1/search" # api来自joyspace search接口
  1. 构建alfred要求的返回结果(www.alfredapp.com/help/workfl…);
{"items": [
    {
        "uid": "desktop",
        "type": "file",
        "title": "Desktop",
        "subtitle": "~/Desktop",
        "arg": "~/Desktop",
        "autocomplete": "Desktop",
        "icon": {
            "type": "fileicon",
            "path": "~/Desktop"
        }
    }
]}
  1. 将对应的员工erp或者群ID带过来,通过京me私有协议将对应的员工聊天框唤起。由于京me是基于electron开发,electron框架支持唤起应用的私有协议。京me的研发人员开发了唤起员工聊天框和群聊天框的协议,通过私有协议可以直接唤起京me联系人或者群聊天框;
# 唤起协议
员工: timline://chat/?topin={query}          # query是员工erp
群聊: timline://chat/?topin={query}&type=2   # query是群聊Id
  1. 结束

实现思路

1.如何唤起京me并跳转至对应聊天页

最开始注意到这个问题是在京东内部域名下搜索员工erp时,会看到浏览器询问是否允许打开京me,允许后京me将被跳转打开,并直接切换到对应搜索结果的联系人|群聊页面,也是在这里想到用京me的搜索api作为关键去获取构建{query}的参数来实现唤起应用的操作。

mac系统在application中选中京me并点开详情,可以看到它的框架是electron

image.png

因此一通查,知道是electron应用在开发时允许调用私有协议唤起应用,就好比日常中苹果手机用户用Safari浏览器打开某一App是一个道理(一篇比较不错的文章贴在最后参考中)。

通过浏览器抓包可知,唤起应用时需要传入指定参数,也就是上面提到的员工erp群聊Id,因此,先去构建指定格式的唤起链接:

员工: timline://chat/?topin={query}          # query是员工erp
群聊: timline://chat/?topin={query}&type=2   # query是群聊Id

2.使用 Alfred

思路: 利用 Alfred 把流程化的固定步骤使用脚本自动化,在Alfred中搜索出京me好友或群聊并直接发起会话。

这里不再截图展示,可以自行探索Alfred的workflow使用方法,可大致概括为:

  • Alfred中新建新的workflow,根据要实现的功能选择合适的特性,填写相关信息,写入脚本即可。

Alfred提供了已经封装好的workflow util,可以大大提高写脚本效率。

下方参考链接中贴了一份一位其他大佬利用workflow实现插件的过程。

脚本实现:

# python脚本文件

# encoding: utf-8
import json
import sys

import browser_cookie3
import requests as requests

from workflow import Workflow, ICON_USER, ICON_GROUP

API_KEY = 'your-pinboard-api-key'


class user():
    def __int__(self, id, user_id, username, name, avatar_url, org_name, position_name):
        self.id = id
        self.user_id = user_id
        self.username = username
        self.name = name
        self.avatar_url = avatar_url
        self.org_name = org_name
        self.position_name = position_name


def user(cls):
    return {
        'id': cls.id,
        'user_id': cls.user_id,
        'username': cls.username,
        'name': cls.name,
        'avatar_url': cls.avatar_url,
        'org_name': cls.org_name,
        'position_name': cls.position_name
    }


class group():
    def __int__(self, gid, name, avatar, owner, ownername):
        self.gid = gid
        self.name = name
        self.avatar = avatar
        self.owner = owner
        self.ownername = ownername


def group(cls):
    return {
        'gid': cls.gid,
        'name': cls.name,
        'avatar': cls.avatar,
        'owner': cls.owner,
        'ownername': cls.ownername
    }


class Search_request():
    def __init__(self, search, page_id, mode, scene, folder_id):
        self.search = search
        self.page_id = page_id
        self.mode = mode
        self.scene = scene
        self.folder_id = folder_id


def search_to_direct(cls):
    return {
        'search': cls.search,
        'page_id': cls.page_id,
        'mode': cls.mode,
        'scene': cls.scene,
        'folder_id': cls.folder_id
    }


class Search_response():
    def __init__(self, result):
        self.__dict__ = result


''':parameter query'''


def search(query):
    # 设置连接活跃状态为false,及时释放资源
    session = requests.session()
    session.keep_alive = False
    # 构建请求行 请求头 请求体,api来自joyspace search接口
    url = "https://apijoyspace.jd.com/v1/search"
    temp_request = Search_request(query, 'cgHL83y1H66MU9Frjlh2', 15, 'share', '')
    request_dic = search_to_direct(temp_request)
    request = json.dumps(request_dic)
    # cookie动态获取
    cookie = browser_cookie3.chrome(domain_name='.jd.com')
    headers = {
        'Content-Type': 'application/json'
    }
    response = requests.post(url, data=request, cookies=cookie, headers=headers)
    # 对结果进行反序列化,并构建支持alfred展示的json格式
    result = json.loads(response.text, object_hook=Search_response)
    users = result.data.users
    groups = result.data.groups
    # 对员工和群结果进行筛选,考虑体验问题只取前5个
    u_length = len(users)
    if len(users) > 5:
        u_length = 5
    g_length = len(groups)
    if len(groups) > 5:
        g_length = 5
    # 构建支持alfred展示的json,包括员工和群信息
    for i in range(u_length):
        # users[i].avatar_url
        wf.add_item(arg=users[i].username, type="user", title="姓名: " + users[i].name,
                    subtitle="erp: " + users[i].username, valid=True, icon=ICON_USER)
    for j in range(g_length):
        # group[j].avatar
        wf.add_item(arg=groups[j].gid, type="group", title="群名称: " + groups[j].name,
                    subtitle="owner: " + groups[j].ownername, valid=True, icon=ICON_GROUP)
    wf.send_feedback()


if __name__ == "__main__":
    wf = Workflow()
    query = sys.argv[1] # eg: query = 'jiangzixu'
    search(query)

如何使用本插件

插件特性

  1. 支持搜索京me联系人
  2. 支持搜索京me群
  3. 支持模糊搜索并快速打开对应聊天框

使用说明

  1. 下载安装Alfred,需要支持powerpack,建议购买正版。
  2. 将远程代码clone到本地(CF搜)
  3. 将 『me_search.alfredworkflow』拖拽至workflow
  4. 修改python脚本本地路径
  5. 开始使用

参考文档

  1. Alfred 官网: www.alfredforum.com/
  2. electron官网: www.electronjs.org/
  3. 一位大佬写的electron私有协议实现相关: juejin.cn/post/688304…
  4. 一位大佬写的workflow实现相关: juejin.cn/post/684490…