{"action":"created","comment":{"url":"https://api.github.com/repos/albertlauncher/external/pulls/comments/139254286","pull_request_review_id":63166936,"id":139254286,"diff_hunk":"@@ -0,0 +1,232 @@\n+#!/usr/bin/env python\n+\n+from __future__ import print_function\n+import os\n+import re\n+import json\n+from subprocess import Popen, PIPE\n+\n+\n+ZIM_ICON = \"zim\"\n+MATCH_THRESHOLD = 60\n+MATCH_LIMIT = 3\n+USING_FUZZY = True\n+\n+try:\n+    import fuzzywuzzy.process\n+except ImportError:\n+    import difflib\n+    USING_FUZZY = False\n+\n+\n+def best_matches(term, options, cutoff=MATCH_THRESHOLD):\n+    if USING_FUZZY:\n+        matches = fuzzywuzzy.process.extractBests(term, options, limit=MATCH_LIMIT)\n+        good_matches = []\n+        for name, score in matches:\n+            if score > MATCH_THRESHOLD:\n+                good_matches += [name]\n+        return good_matches\n+    else:\n+        return difflib.get_close_matches(term, options, cutoff=MATCH_THRESHOLD / 100.0, n=MATCH_LIMIT)\n+\n+\n+class Notebook():\n+    def __init__(self, path):\n+        self.path = path\n+        self.__set_name()\n+\n+    def __set_name(self):\n+        self.name = None\n+        nbfile = os.path.join(self.path, \"notebook.zim\")\n+        if os.path.exists(nbfile):\n+            r = re.search(r'name=(.*)', open(nbfile, \"r\").read())\n+            if r:\n+                gs = r.groups()\n+                if gs:\n+                    self.name = gs[0]\n+\n+\n+class Page():\n+    def __init__(self, path, name, directory=None):\n+        self.path = path\n+        self.name = name\n+        self.dir = directory\n+\n+\n+def get_zim_notebooks():\n+    nbroot = os.path.join(os.path.expanduser(\"~\"), \"Notebooks\")\n+    nbdirs = os.listdir(nbroot)\n+    notebooks = []\n+    for d in nbdirs:\n+        nb = Notebook(os.path.join(nbroot, d))\n+        if nb.name:  # This should always be the case because every notebook should have a name\n+            notebooks += [nb]\n+    return notebooks\n+\n+\n+def get_zim_pages_for_notebook(nb):\n+    pages = []\n+    to_search = []\n+    sub = filter(lambda x: x[0] != \".\" and x.endswith(\".txt\"), os.listdir(nb.path))\n+    sub_paths = map(lambda x: os.path.join(nb.path, x), sub)\n+    for page_path in filter(lambda x: os.path.isfile(x), sub_paths):\n+        page_dir = page_path[:page_path.rindex(\".\")]\n+        if os.path.exists(page_dir) and os.path.isdir(page_dir):\n+            page = Page(page_path, os.path.basename(page_dir), page_dir)\n+            to_search += [page]\n+        else:\n+            page = Page(page_path, os.path.basename(page_dir))\n+        pages += [page]\n+\n+    while to_search:\n+        cur = to_search.pop()\n+        sub = filter(lambda x: x[0] != \".\" and x.endswith(\".txt\"), os.listdir(cur.dir))\n+        sub_paths = map(lambda x: os.path.join(cur.dir, x), sub)\n+        for page_path in filter(lambda x: os.path.isfile(x), sub_paths):\n+            page_dir = page_path[:page_path.rindex(\".\")]\n+            if os.path.exists(page_dir) and os.path.isdir(page_dir):\n+                page = Page(page_path, cur.name + \":\" + os.path.basename(page_dir), page_dir)\n+                to_search += [page]\n+            else:\n+                page = Page(page_path, cur.name + \":\" + os.path.basename(page_dir))\n+            pages += [page]\n+\n+    return pages\n+\n+\n+def metadata():\n+    return {\"iid\": \"org.albert.extension.external/v2.0\",\n+            \"version\": \"0.0.1\",\n+            \"name\": \"Zim Plugin\",\n+            \"trigger\": \"z\",\n+            \"author\": \"Jonathan Beaulieu <123.jonathan@gmail.com>\",\n+            \"dependencies\": []}\n+\n+\n+def _init():\n+    return\n+\n+\n+def _del():\n+    return\n+\n+\n+def begin():\n+    return\n+\n+\n+def end():\n+    return\n+\n+\n+def make_action(name=\"Open\", command=\"zim\", args=[]):\n+    return {\"name\": name, \"command\": command, \"arguments\": args}\n+\n+\n+def make_item(_id, name, descr, actions, icon=ZIM_ICON):\n+    return {\"id\": _id, \"name\": name, \"description\": descr, \"icon\": icon,\n+            \"actions\": actions}\n+\n+\n+def query(s):\n+    # TODO(derpferd): Maybe this can be done less than on every query\n+    notebooks = get_zim_notebooks()\n+    notebooks_by_name = dict(map(lambda x: (x.name, x), notebooks))\n+\n+    # remove the trigger\n+    if s[:3] == \"zim\":\n+        s = s[3:]\n+    elif s[:1] == \"z\":\n+        s = s[1:]\n+    s = s.strip()\n+\n+    items = []\n+    variables = {}\n+\n+    # TODO(derpferd): Add good support for multi-word notebook names\n+    # Options\n+    # - z/zim o/open\n+    # - z/zim NotebookName\n+    # - z/zim NotebookName Page\n+    # - z/zim NotebookName Query\n+\n+    if len(s.split()):\n+        first_word = s.split()[0]\n+        query = \" \".join(s.split()[1:])\n+    else:\n+        first_word = \"\"\n+        query = \"\"\n+\n+    # Zim Open\n+    if not first_word or first_word in \"open\":\n+        action = make_action()\n+        items += [make_item(\"open.zim\", \"Open Zim\", \"Open Zim\", [action])]\n+\n+    # Zim Notebook by name\n+    matches = best_matches(first_word, notebooks_by_name.keys())\n+    for name in matches:\n+        action = make_action(args=[name])\n+        items += [make_item(\"zim.\" + name, name, \"Open \" + name, [action])]\n+\n+    # Pick the best match as the notebook to search\n+    notebook = None\n+    pages = None\n+    pages_by_name = None\n+    if len(matches) > 0:\n+        notebook = notebooks_by_name[matches[0]]\n+        pages = get_zim_pages_for_notebook(notebook)\n+        pages_by_name = dict(map(lambda x: (x.name, x), pages))\n+\n+    # Zim Page by name\n+    if notebook:\n+        matches = best_matches(query, pages_by_name.keys())\n+        for name in matches:\n+            action = make_action(args=[notebook.name, name])\n+            items += [make_item(\"zim.\" + notebook.name + \".\" + name, \"Open \" + name,\n+                                \"Open zim to \" + name + \" in \" + notebook.name,\n+                                [action])]\n+\n+    # Notebook search\n+    if notebook:\n+        # Call zim --search NOTEBOOK QUERY\n+        p = Popen([\"zim\", \"--search\", notebook.name, query], stdin=PIPE,\n+                  stdout=PIPE, stderr=PIPE)\n+        output, err = p.communicate()\n+        for line in output.split(b'\\n'):\n+            if line not in pages_by_name:\n+                continue\n+            _id = \"zim.\" + notebook.name + \".\" + line\n+            if _id in map(lambda x: x[\"id\"], items):\n+                continue\n+            action = make_action(args=[notebook.name, line])\n+            items += [{\"id\": _id,\n+                       \"name\": \"Open \" + line,\n+                       \"description\": \"Open zim to \" + line + \" in \" + notebook.name,\n+                       \"icon\": ZIM_ICON,\n+                       \"actions\": [action]}]\n+\n+    return {\"items\": items, \"variables\": variables}\n+\n+\n+def main():\n+    op = os.environ[\"ALBERT_OP\"]\n+    res = {}\n+    if op == \"METADATA\":\n+        res = metadata()\n+    elif op == \"INITIALIZE\":\n+        res = _init()\n+    elif op == \"FINALIZE\":\n+        res = _del()\n+    elif op == \"SETUPSESSION\":","path":"org.albert.extension.external.zim.py","position":221,"original_position":221,"commit_id":"085b5685492cb2b2bfc3193f015a142b2480817f","original_commit_id":"085b5685492cb2b2bfc3193f015a142b2480817f","user":{"login":"ManuelSchneid3r","id":3252315,"avatar_url":"https://avatars1.githubusercontent.com/u/3252315?v=4","gravatar_id":"","url":"https://api.github.com/users/ManuelSchneid3r","html_url":"https://github.com/ManuelSchneid3r","followers_url":"https://api.github.com/users/ManuelSchneid3r/followers","following_url":"https://api.github.com/users/ManuelSchneid3r/following{/other_user}","gists_url":"https://api.github.com/users/ManuelSchneid3r/gists{/gist_id}","starred_url":"https://api.github.com/users/ManuelSchneid3r/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ManuelSchneid3r/subscriptions","organizations_url":"https://api.github.com/users/ManuelSchneid3r/orgs","repos_url":"https://api.github.com/users/ManuelSchneid3r/repos","events_url":"https://api.github.com/users/ManuelSchneid3r/events{/privacy}","received_events_url":"https://api.github.com/users/ManuelSchneid3r/received_events","type":"User","site_admin":false},"body":"Remove setup and teardown they will be dropped in the protocol v3.","created_at":"2017-09-15T21:30:25Z","updated_at":"2017-09-15T21:30:40Z","html_url":"https://github.com/albertlauncher/external/pull/4#discussion_r139254286","pull_request_url":"https://api.github.com/repos/albertlauncher/external/pulls/4","author_association":"OWNER","_links":{"self":{"href":"https://api.github.com/repos/albertlauncher/external/pulls/comments/139254286"},"html":{"href":"https://github.com/albertlauncher/external/pull/4#discussion_r139254286"},"pull_request":{"href":"https://api.github.com/repos/albertlauncher/external/pulls/4"}}},"pull_request":{"url":"https://api.github.com/repos/albertlauncher/external/pulls/4","id":110318635,"html_url":"https://github.com/albertlauncher/external/pull/4","diff_url":"https://github.com/albertlauncher/external/pull/4.diff","patch_url":"https://github.com/albertlauncher/external/pull/4.patch","issue_url":"https://api.github.com/repos/albertlauncher/external/issues/4","number":4,"state":"open","locked":false,"title":"Added Zim Search","user":{"login":"DerPferd","id":1833709,"avatar_url":"https://avatars2.githubusercontent.com/u/1833709?v=4","gravatar_id":"","url":"https://api.github.com/users/DerPferd","html_url":"https://github.com/DerPferd","followers_url":"https://api.github.com/users/DerPferd/followers","following_url":"https://api.github.com/users/DerPferd/following{/other_user}","gists_url":"https://api.github.com/users/DerPferd/gists{/gist_id}","starred_url":"https://api.github.com/users/DerPferd/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/DerPferd/subscriptions","organizations_url":"https://api.github.com/users/DerPferd/orgs","repos_url":"https://api.github.com/users/DerPferd/repos","events_url":"https://api.github.com/users/DerPferd/events{/privacy}","received_events_url":"https://api.github.com/users/DerPferd/received_events","type":"User","site_admin":false},"body":"Requires fuzzywuzzy to be installed. I use it to handle the fuzzy searching.\r\n\r\nTo install run: pip install fuzzywuzzy\r\n","created_at":"2017-03-12T22:26:41Z","updated_at":"2017-09-15T21:30:40Z","closed_at":null,"merged_at":null,"merge_commit_sha":"2c76391cda2ca54830c37c57a00d49149e57ede3","assignee":null,"assignees":[],"requested_reviewers":[],"milestone":null,"commits_url":"https://api.github.com/repos/albertlauncher/external/pulls/4/commits","review_comments_url":"https://api.github.com/repos/albertlauncher/external/pulls/4/comments","review_comment_url":"https://api.github.com/repos/albertlauncher/external/pulls/comments{/number}","comments_url":"https://api.github.com/repos/albertlauncher/external/issues/4/comments","statuses_url":"https://api.github.com/repos/albertlauncher/external/statuses/085b5685492cb2b2bfc3193f015a142b2480817f","head":{"label":"DerPferd:master","ref":"master","sha":"085b5685492cb2b2bfc3193f015a142b2480817f","user":{"login":"DerPferd","id":1833709,"avatar_url":"https://avatars2.githubusercontent.com/u/1833709?v=4","gravatar_id":"","url":"https://api.github.com/users/DerPferd","html_url":"https://github.com/DerPferd","followers_url":"https://api.github.com/users/DerPferd/followers","following_url":"https://api.github.com/users/DerPferd/following{/other_user}","gists_url":"https://api.github.com/users/DerPferd/gists{/gist_id}","starred_url":"https://api.github.com/users/DerPferd/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/DerPferd/subscriptions","organizations_url":"https://api.github.com/users/DerPferd/orgs","repos_url":"https://api.github.com/users/DerPferd/repos","events_url":"https://api.github.com/users/DerPferd/events{/privacy}","received_events_url":"https://api.github.com/users/DerPferd/received_events","type":"User","site_admin":false},"repo":{"id":84761065,"name":"external","full_name":"DerPferd/external","owner":{"login":"DerPferd","id":1833709,"avatar_url":"https://avatars2.githubusercontent.com/u/1833709?v=4","gravatar_id":"","url":"https://api.github.com/users/DerPferd","html_url":"https://github.com/DerPferd","followers_url":"https://api.github.com/users/DerPferd/followers","following_url":"https://api.github.com/users/DerPferd/following{/other_user}","gists_url":"https://api.github.com/users/DerPferd/gists{/gist_id}","starred_url":"https://api.github.com/users/DerPferd/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/DerPferd/subscriptions","organizations_url":"https://api.github.com/users/DerPferd/orgs","repos_url":"https://api.github.com/users/DerPferd/repos","events_url":"https://api.github.com/users/DerPferd/events{/privacy}","received_events_url":"https://api.github.com/users/DerPferd/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/DerPferd/external","description":"A repository for external plugins","fork":true,"url":"https://api.github.com/repos/DerPferd/external","forks_url":"https://api.github.com/repos/DerPferd/external/forks","keys_url":"https://api.github.com/repos/DerPferd/external/keys{/key_id}","collaborators_url":"https://api.github.com/repos/DerPferd/external/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/DerPferd/external/teams","hooks_url":"https://api.github.com/repos/DerPferd/external/hooks","issue_events_url":"https://api.github.com/repos/DerPferd/external/issues/events{/number}","events_url":"https://api.github.com/repos/DerPferd/external/events","assignees_url":"https://api.github.com/repos/DerPferd/external/assignees{/user}","branches_url":"https://api.github.com/repos/DerPferd/external/branches{/branch}","tags_url":"https://api.github.com/repos/DerPferd/external/tags","blobs_url":"https://api.github.com/repos/DerPferd/external/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/DerPferd/external/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/DerPferd/external/git/refs{/sha}","trees_url":"https://api.github.com/repos/DerPferd/external/git/trees{/sha}","statuses_url":"https://api.github.com/repos/DerPferd/external/statuses/{sha}","languages_url":"https://api.github.com/repos/DerPferd/external/languages","stargazers_url":"https://api.github.com/repos/DerPferd/external/stargazers","contributors_url":"https://api.github.com/repos/DerPferd/external/contributors","subscribers_url":"https://api.github.com/repos/DerPferd/external/subscribers","subscription_url":"https://api.github.com/repos/DerPferd/external/subscription","commits_url":"https://api.github.com/repos/DerPferd/external/commits{/sha}","git_commits_url":"https://api.github.com/repos/DerPferd/external/git/commits{/sha}","comments_url":"https://api.github.com/repos/DerPferd/external/comments{/number}","issue_comment_url":"https://api.github.com/repos/DerPferd/external/issues/comments{/number}","contents_url":"https://api.github.com/repos/DerPferd/external/contents/{+path}","compare_url":"https://api.github.com/repos/DerPferd/external/compare/{base}...{head}","merges_url":"https://api.github.com/repos/DerPferd/external/merges","archive_url":"https://api.github.com/repos/DerPferd/external/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/DerPferd/external/downloads","issues_url":"https://api.github.com/repos/DerPferd/external/issues{/number}","pulls_url":"https://api.github.com/repos/DerPferd/external/pulls{/number}","milestones_url":"https://api.github.com/repos/DerPferd/external/milestones{/number}","notifications_url":"https://api.github.com/repos/DerPferd/external/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/DerPferd/external/labels{/name}","releases_url":"https://api.github.com/repos/DerPferd/external/releases{/id}","deployments_url":"https://api.github.com/repos/DerPferd/external/deployments","created_at":"2017-03-12T22:09:25Z","updated_at":"2017-03-12T22:23:59Z","pushed_at":"2017-03-16T15:30:41Z","git_url":"git://github.com/DerPferd/external.git","ssh_url":"git@github.com:DerPferd/external.git","clone_url":"https://github.com/DerPferd/external.git","svn_url":"https://github.com/DerPferd/external","homepage":"","size":10,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"albertlauncher:master","ref":"master","sha":"f0551350b51a5f727ef59b3439008651369299a0","user":{"login":"albertlauncher","id":18707603,"avatar_url":"https://avatars0.githubusercontent.com/u/18707603?v=4","gravatar_id":"","url":"https://api.github.com/users/albertlauncher","html_url":"https://github.com/albertlauncher","followers_url":"https://api.github.com/users/albertlauncher/followers","following_url":"https://api.github.com/users/albertlauncher/following{/other_user}","gists_url":"https://api.github.com/users/albertlauncher/gists{/gist_id}","starred_url":"https://api.github.com/users/albertlauncher/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/albertlauncher/subscriptions","organizations_url":"https://api.github.com/users/albertlauncher/orgs","repos_url":"https://api.github.com/users/albertlauncher/repos","events_url":"https://api.github.com/users/albertlauncher/events{/privacy}","received_events_url":"https://api.github.com/users/albertlauncher/received_events","type":"Organization","site_admin":false},"repo":{"id":82161694,"name":"external","full_name":"albertlauncher/external","owner":{"login":"albertlauncher","id":18707603,"avatar_url":"https://avatars0.githubusercontent.com/u/18707603?v=4","gravatar_id":"","url":"https://api.github.com/users/albertlauncher","html_url":"https://github.com/albertlauncher","followers_url":"https://api.github.com/users/albertlauncher/followers","following_url":"https://api.github.com/users/albertlauncher/following{/other_user}","gists_url":"https://api.github.com/users/albertlauncher/gists{/gist_id}","starred_url":"https://api.github.com/users/albertlauncher/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/albertlauncher/subscriptions","organizations_url":"https://api.github.com/users/albertlauncher/orgs","repos_url":"https://api.github.com/users/albertlauncher/repos","events_url":"https://api.github.com/users/albertlauncher/events{/privacy}","received_events_url":"https://api.github.com/users/albertlauncher/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/albertlauncher/external","description":"A repository for external plugins","fork":false,"url":"https://api.github.com/repos/albertlauncher/external","forks_url":"https://api.github.com/repos/albertlauncher/external/forks","keys_url":"https://api.github.com/repos/albertlauncher/external/keys{/key_id}","collaborators_url":"https://api.github.com/repos/albertlauncher/external/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/albertlauncher/external/teams","hooks_url":"https://api.github.com/repos/albertlauncher/external/hooks","issue_events_url":"https://api.github.com/repos/albertlauncher/external/issues/events{/number}","events_url":"https://api.github.com/repos/albertlauncher/external/events","assignees_url":"https://api.github.com/repos/albertlauncher/external/assignees{/user}","branches_url":"https://api.github.com/repos/albertlauncher/external/branches{/branch}","tags_url":"https://api.github.com/repos/albertlauncher/external/tags","blobs_url":"https://api.github.com/repos/albertlauncher/external/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/albertlauncher/external/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/albertlauncher/external/git/refs{/sha}","trees_url":"https://api.github.com/repos/albertlauncher/external/git/trees{/sha}","statuses_url":"https://api.github.com/repos/albertlauncher/external/statuses/{sha}","languages_url":"https://api.github.com/repos/albertlauncher/external/languages","stargazers_url":"https://api.github.com/repos/albertlauncher/external/stargazers","contributors_url":"https://api.github.com/repos/albertlauncher/external/contributors","subscribers_url":"https://api.github.com/repos/albertlauncher/external/subscribers","subscription_url":"https://api.github.com/repos/albertlauncher/external/subscription","commits_url":"https://api.github.com/repos/albertlauncher/external/commits{/sha}","git_commits_url":"https://api.github.com/repos/albertlauncher/external/git/commits{/sha}","comments_url":"https://api.github.com/repos/albertlauncher/external/comments{/number}","issue_comment_url":"https://api.github.com/repos/albertlauncher/external/issues/comments{/number}","contents_url":"https://api.github.com/repos/albertlauncher/external/contents/{+path}","compare_url":"https://api.github.com/repos/albertlauncher/external/compare/{base}...{head}","merges_url":"https://api.github.com/repos/albertlauncher/external/merges","archive_url":"https://api.github.com/repos/albertlauncher/external/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/albertlauncher/external/downloads","issues_url":"https://api.github.com/repos/albertlauncher/external/issues{/number}","pulls_url":"https://api.github.com/repos/albertlauncher/external/pulls{/number}","milestones_url":"https://api.github.com/repos/albertlauncher/external/milestones{/number}","notifications_url":"https://api.github.com/repos/albertlauncher/external/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/albertlauncher/external/labels{/name}","releases_url":"https://api.github.com/repos/albertlauncher/external/releases{/id}","deployments_url":"https://api.github.com/repos/albertlauncher/external/deployments","created_at":"2017-02-16T09:12:19Z","updated_at":"2017-09-03T12:28:43Z","pushed_at":"2017-09-13T13:17:05Z","git_url":"git://github.com/albertlauncher/external.git","ssh_url":"git@github.com:albertlauncher/external.git","clone_url":"https://github.com/albertlauncher/external.git","svn_url":"https://github.com/albertlauncher/external","homepage":"","size":11,"stargazers_count":18,"watchers_count":18,"language":"Python","has_issues":false,"has_projects":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":26,"mirror_url":null,"open_issues_count":10,"forks":26,"open_issues":10,"watchers":18,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/albertlauncher/external/pulls/4"},"html":{"href":"https://github.com/albertlauncher/external/pull/4"},"issue":{"href":"https://api.github.com/repos/albertlauncher/external/issues/4"},"comments":{"href":"https://api.github.com/repos/albertlauncher/external/issues/4/comments"},"review_comments":{"href":"https://api.github.com/repos/albertlauncher/external/pulls/4/comments"},"review_comment":{"href":"https://api.github.com/repos/albertlauncher/external/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/albertlauncher/external/pulls/4/commits"},"statuses":{"href":"https://api.github.com/repos/albertlauncher/external/statuses/085b5685492cb2b2bfc3193f015a142b2480817f"}},"author_association":"NONE"}}
{"actor":{"display_login":"ManuelSchneid3r"}}