BibQuery(ZotQuery) for Bookends

A place for users to ask each other questions, make suggestions, and discuss Bookends.
Post Reply
Dellu
Posts: 271
Joined: Sun Mar 27, 2016 5:30 am

BibQuery(ZotQuery) for Bookends

Post by Dellu »

The community in Alfred developed two great reference citation add-ons for BibDesk and Zotero.

Look at these tool here:
http://www.alfredforum.com/topic/4346-b ... om-alfred/
http://www.alfredforum.com/topic/3708-z ... or-zotero/

They really great tools which made citation everywhere possible. If you want to cite in Word document, your note writing app, Tinderbox, Simplenote, or what you have it...everywhere, you can just search your whole BibDesk library from Alfred and drop it. Extremely efficient system.

Since I am now migrating to Bookends, I was hoping that some experienced programmers could implement the system to Bookends.

Won't it be great to search the Bookends library from everywhere and insert the citation in every application?

Can anybody help please?
Jon
Site Admin
Posts: 10292
Joined: Tue Jul 13, 2004 6:27 pm
Location: Bethesda, MD
Contact:

Re: BibQuery(ZotQuery) for Bookends

Post by Jon »

Did landol post something similar to this in the AppleScript forum recently?

viewtopic.php?f=6&t=3995

Jon
Sonny Software

P.S. You can change your linked "word processor" (which can be any app) at any time with File -> Link To. Bookends will default to the setting in preferences when you relaunch.
Dellu
Posts: 271
Joined: Sun Mar 27, 2016 5:30 am

Re: BibQuery(ZotQuery) for Bookends

Post by Dellu »

Yah, I have seen that one before. I don't get much of use of it.
But,
Do you think that script can be used in Alfred?
Can it insert the citation in an editor, any editor?
Jon
Site Admin
Posts: 10292
Joined: Tue Jul 13, 2004 6:27 pm
Location: Bethesda, MD
Contact:

Re: BibQuery(ZotQuery) for Bookends

Post by Jon »

landol can possibly comment on this. I don't use Alfred, personally, it should work with any AppleScript, right? This is from landol's post

"As they are plain Applescripts they normally live in ~/Library/Scripts, but to quickly access them you need some way to trigger them. I use Quicksilver, which automatically indexes ~/Library/Scripts, so you can easily trigger these scripts wherever you are. Alfred/Launchbar/Keyboard maestro and others also allow you to quickly trigger Applescripts, though each may do so in a slightly different way. OS X also has a built-in scripts menu you can display (Script Editor > Preferences > General to enable it); you then run them from the menu bar."

As for inserting the citation into any editor, you'll have to test and see. But since it's using GUI scripting, I think it would work with any app that obeys the OS X interface guidelines.

Jon
Sonny Software
Dellu
Posts: 271
Joined: Sun Mar 27, 2016 5:30 am

Re: BibQuery(ZotQuery) for Bookends

Post by Dellu »

I now tried landol's script. What is does is:
It copies a selected text
activates Bookends
pastes into the search field
searches it

This, I have been doing in Keyboard Maestro. The process is simple. The good part in landol's script is it also cleans up the messy text. I like that part of the script.
But, what the BibQueries I mentioned above do a different job; don't really call for Bookends per se. The BibQuery, for example, works even when BibDesk is not running. It uses Alfred's searching capabilities, so far as I can understand, rather than calling for the bibliography manager. The script is built on the Catch data, I think.
Dellu
Posts: 271
Joined: Sun Mar 27, 2016 5:30 am

Re: BibQuery(ZotQuery) for Bookends

Post by Dellu »

here is the python & and applescript doing all the task: for the BibQuery script:

Code: Select all

#!/usr/bin/python
# encoding: utf-8
from __future__ import unicode_literals

import sys
import urllib
import os.path
import subprocess

import workflow
import ccl_bplist

HOME = os.path.expanduser("~")
BIB_DIR = HOME + "/Library/Caches/Metadata/edu.ucsd.cs.mmccrack.bibdesk/"

################################################
# AppleScript Functions
################################################

def _applescriptify_str(text):
    """Replace double quotes in text for Applescript string"""
    text = text.replace('"', '" & quote & "')
    text = text.replace('\\', '\\\\')
    return text

def _applescriptify_list(_list):
    """Convert Python list to Applescript list"""
    quoted_list = []
    for item in _list:
        if type(item) is unicode:   # unicode string to AS string
            _new = '"' + item + '"'
            quoted_list.append(_new)    
        elif type(item) is str:     # string to AS string
            _new = '"' + item + '"'
            quoted_list.append(_new)    
        elif type(item) is int:     # int to AS number
            _new = str(item)
            quoted_list.append(_new)
        elif type(item) is bool:    # bool to AS Boolean
            _new = str(item).lower()
            quoted_list.append(_new)
    quoted_str = ', '.join(quoted_list)
    return '{' + quoted_str + '}'

def as_run(ascript):
    """Run the given AppleScript and return the standard output and error."""
    osa = subprocess.Popen(['osascript', '-'],
                            stdin=subprocess.PIPE,
                            stdout=subprocess.PIPE)
    return osa.communicate(ascript)[0].strip()

def set_clipboard(data):
    """Set clipboard to ``data``""" 
    scpt = """
        set the clipboard to "{0}"
    """.format(_applescriptify_str(data))
    subprocess.call(['osascript', '-e', scpt])

################################################
# Helper Function
################################################

def read_cachedir():
    """Read BibDesk cache dir into Python array"""
    _data = []
    for bib in os.listdir(BIB_DIR):
        bib_path = os.path.join(BIB_DIR, bib)
        with open(bib_path, 'rb') as _file:
            bib_data = ccl_bplist.load(_file)
            _file.close()
        _data.append(bib_data)
    return _data

################################################
# Actions
################################################   

def export_cite_command(cite_key):
    """Return LaTeX cite command"""
    cmd = "\\cite{{{0}}}".format(cite_key)
    set_clipboard(cmd)
    return "Cite Command"

def open_attachment(cite_key):
    """Open PDF attachment in default app"""
    data = read_cachedir()
    sources = [x['kMDItemWhereFroms']
                for x in data
                if x['net_sourceforge_bibdesk_citekey'] == cite_key]
    for _val in sources:
        if _val != []:
            for source in _val:
                if 'pdf' in source:
                    if not 'http' in source:
                        clean_file = urllib.unquote(source)
                        _file = clean_file.replace('file://localhost', '')
                        if os.path.isfile(_file):
                            subprocess.Popen(
                                ['open', _file], 
                                shell=False, 
                                stdout=subprocess.PIPE)

def open_item(cite_key):
    """Open item in BibDesk"""
    scpt = """
        if application id "edu.ucsd.cs.mmccrack.bibdesk" is not running then
            tell application id "edu.ucsd.cs.mmccrack.bibdesk"
                launch
                delay 0.3
                activate
                delay 0.3
                open location "x-bdsk://" & "{0}"
            end tell
        else
            tell application id "edu.ucsd.cs.mmccrack.bibdesk"
                activate
                delay 0.3
                open location "x-bdsk://" & "{0}"
            end tell
        end if
    """.format(cite_key)
    as_run(scpt)

def save_group(group, wf):
    """Save Group name to tmp file"""
    with open(wf.cachefile("group_result.txt"), 'w') as _file:
        _file.write(group.encode('utf-8'))
        _file.close()

def save_keyword(keyword, wf):
    """Save Keyword name to tmp file"""
    with open(wf.cachefile("keyword_result.txt"), 'w') as _file:
        _file.write(keyword.encode('utf-8'))
        _file.close()

def act(cite_key, action, wf):
    """Main API method"""
    if action == 'open':
        open_item(cite_key)
    elif action == 'cite':
        return export_cite_command(cite_key)
    elif action == 'att':
        open_attachment(cite_key)
    elif action == 'save_group':
        save_group(cite_key, wf)
    elif action == 'save_keyword':
        save_keyword(cite_key, wf)
    
    #elif action == 'ref':
    #    return export_ref()
    #elif action == 'cite_group':
    #    return export_group()
    #elif action == 'append':
    #    return append_to_bib()
    #elif action == 'bib':
    #    return read_save_bib()

################################################
# Main Function
################################################

def main(wf):
    #cite_key = "Allen_1938a_On-the-Friendship-of-Lucretius-with"
    #action = "cite"
    cite_key = wf.args[0]
    action = wf.args[1]

    print act(cite_key, action, wf)


if __name__ == '__main__':
    wf = workflow.Workflow()
    sys.exit(wf.run(main))  
Jon
Site Admin
Posts: 10292
Joined: Tue Jul 13, 2004 6:27 pm
Location: Bethesda, MD
Contact:

Re: BibQuery(ZotQuery) for Bookends

Post by Jon »

It works when BibDesk isn't running? I see this in the script

if application id "edu.ucsd.cs.mmccrack.bibdesk" is not running then
tell application id "edu.ucsd.cs.mmccrack.bibdesk"
launch

In any case, to search a Bookends database and have Bookends insert citations it would definitely have to be running (or launched by the script if it wasn't running when the script was invoked).

Jon
Sonny Software
Dellu
Posts: 271
Joined: Sun Mar 27, 2016 5:30 am

Re: BibQuery(ZotQuery) for Bookends

Post by Dellu »

oh, sorry, I copied the wrong part of the script. The whole script has a number of branches from these, some of them open the recording in BibDesk; others simply copy the bib key in latex citation format: like \cite{John2013}. I copied the part that opens the references. i actually want to get just the citation key that would look like {John, 2010, #3970} in Bookends.

If it is not possible with the Bookends, I will use the BibDesk by exporting.
Dellu
Posts: 271
Joined: Sun Mar 27, 2016 5:30 am

Re: BibQuery(ZotQuery) for Bookends

Post by Dellu »

I think this is the right script to copy the citation without launching BibDesk:

Code: Select all

#!/usr/bin/python
# encoding: utf-8
from __future__ import unicode_literals

import sys
import urllib
import os.path
import subprocess

import workflow
import ccl_bplist

HOME = os.path.expanduser("~")
BIB_DIR = HOME + "/Library/Caches/Metadata/edu.ucsd.cs.mmccrack.bibdesk/"

################################################
# AppleScript Functions
################################################

def _applescriptify_str(text):
    """Replace double quotes in text for Applescript string"""
    text = text.replace('"', '" & quote & "')
    text = text.replace('\\', '\\\\')
    return text

def _applescriptify_list(_list):
    """Convert Python list to Applescript list"""
    quoted_list = []
    for item in _list:
        if type(item) is unicode:   # unicode string to AS string
            _new = '"' + item + '"'
            quoted_list.append(_new)    
        elif type(item) is str:     # string to AS string
            _new = '"' + item + '"'
            quoted_list.append(_new)    
        elif type(item) is int:     # int to AS number
            _new = str(item)
            quoted_list.append(_new)
        elif type(item) is bool:    # bool to AS Boolean
            _new = str(item).lower()
            quoted_list.append(_new)
    quoted_str = ', '.join(quoted_list)
    return '{' + quoted_str + '}'

def as_run(ascript):
    """Run the given AppleScript and return the standard output and error."""
    osa = subprocess.Popen(['osascript', '-'],
                            stdin=subprocess.PIPE,
                            stdout=subprocess.PIPE)
    return osa.communicate(ascript)[0].strip()

def set_clipboard(data):
    """Set clipboard to ``data``""" 
    scpt = """
        set the clipboard to "{0}"
    """.format(_applescriptify_str(data))
    subprocess.call(['osascript', '-e', scpt])

################################################
# Helper Function
################################################

def read_cachedir():
    """Read BibDesk cache dir into Python array"""
    _data = []
    for bib in os.listdir(BIB_DIR):
        bib_path = os.path.join(BIB_DIR, bib)
        with open(bib_path, 'rb') as _file:
            bib_data = ccl_bplist.load(_file)
            _file.close()
        _data.append(bib_data)
    return _data

################################################
# Actions
################################################   

def export_cite_command(cite_key):
    """Return LaTeX cite command"""
    cmd = "\\cite{{{0}}}".format(cite_key)
    set_clipboard(cmd)
    return "Cite Command"

def open_attachment(cite_key):
    """Open PDF attachment in default app"""
    data = read_cachedir()
    sources = [x['kMDItemWhereFroms']
                for x in data
                if x['net_sourceforge_bibdesk_citekey'] == cite_key]
    for _val in sources:
        if _val != []:
            for source in _val:
                if 'pdf' in source:
                    if not 'http' in source:
                        clean_file = urllib.unquote(source)
                        _file = clean_file.replace('file://localhost', '')
                        if os.path.isfile(_file):
                            subprocess.Popen(
                                ['open', _file], 
                                shell=False, 
                                stdout=subprocess.PIPE)

def open_item(cite_key):
    """Open item in BibDesk"""
    scpt = """
        if application id "edu.ucsd.cs.mmccrack.bibdesk" is not running then
            tell application id "edu.ucsd.cs.mmccrack.bibdesk"
                launch
                delay 0.3
                activate
                delay 0.3
                open location "x-bdsk://" & "{0}"
            end tell
        else
            tell application id "edu.ucsd.cs.mmccrack.bibdesk"
                activate
                delay 0.3
                open location "x-bdsk://" & "{0}"
            end tell
        end if
    """.format(cite_key)
    as_run(scpt)

def save_group(group, wf):
    """Save Group name to tmp file"""
    with open(wf.cachefile("group_result.txt"), 'w') as _file:
        _file.write(group.encode('utf-8'))
        _file.close()

def save_keyword(keyword, wf):
    """Save Keyword name to tmp file"""
    with open(wf.cachefile("keyword_result.txt"), 'w') as _file:
        _file.write(keyword.encode('utf-8'))
        _file.close()

def act(cite_key, action, wf):
    """Main API method"""
    if action == 'open':
        open_item(cite_key)
    elif action == 'cite':
        return export_cite_command(cite_key)
    elif action == 'att':
        open_attachment(cite_key)
    elif action == 'save_group':
        save_group(cite_key, wf)
    elif action == 'save_keyword':
        save_keyword(cite_key, wf)
    
    #elif action == 'ref':
    #    return export_ref()
    #elif action == 'cite_group':
    #    return export_group()
    #elif action == 'append':
    #    return append_to_bib()
    #elif action == 'bib':
    #    return read_save_bib()

################################################
# Main Function
################################################

def main(wf):
    #cite_key = "Allen_1938a_On-the-Friendship-of-Lucretius-with"
    #action = "cite"
    cite_key = wf.args[0]
    action = wf.args[1]

    print act(cite_key, action, wf)


if __name__ == '__main__':
    wf = workflow.Workflow()
    sys.exit(wf.run(main))  
Jon
Site Admin
Posts: 10292
Joined: Tue Jul 13, 2004 6:27 pm
Location: Bethesda, MD
Contact:

Re: BibQuery(ZotQuery) for Bookends

Post by Jon »

Without a great understanding of python, it looks like BibDesk is storing ref metadata in a cache that can searched by Spotlight, and that's what this script is accessing. Bookends uses an entirely different method and the metadata are accessible the the SQL database that Bookends creates. So Bookends has to be running to access and format the temp citation.

Jon
Sonny Software
Dellu
Posts: 271
Joined: Sun Mar 27, 2016 5:30 am

Re: BibQuery(ZotQuery) for Bookends

Post by Dellu »

I find a way around this problem based on a post:http://www.rousette.org.uk/blog/archive ... nd-pandoc/. I can explain in depth if anybody is interested.
iandol
Posts: 481
Joined: Fri Jan 25, 2008 2:31 pm

Re: BibQuery(ZotQuery) for Bookends

Post by iandol »

Thanks for posting this update Dellu! I'm also probably going to switch from using Bookend bibliography formatting to using pandoc-citeproc, though I think BE's Format manager is still nicer and more flexible than hacking CSL.

BUT I don't think your new workflow exactly fulfills your original query right? Having a floating search interface (in your OP it was Alfred+spotlight, but papers has a nice floating search window) would still be a nice workflow improvement...
Dellu
Posts: 271
Joined: Sun Mar 27, 2016 5:30 am

Re: BibQuery(ZotQuery) for Bookends

Post by Dellu »

Yes, it solves my problem. But, I need to export my References in BibTex format. I open them in BibDesk; and, then use the BibQuery for BibDesk. I am able to insert my references, on every of my favorite softwares: Mou, MultimMarkdown Composer, Sublime, Tinderbox, nvALT. The freedom to use my reference on any application, to cite everywhere, is what pushed me to this direction. Now, I don't have to open BE, nor BibDesk; I don't have worry about restrictions of Application X is supported or not (that, you also have to face in Papers Magic Manuscript---doesn't support many of the apps I use; such as Tinderbox & nvALT). I just cite everywhere. Pandoc is a Freedom. If you don't mind to export your references, it works great.

Later, when I am composing, unless I have some other reasons, I don't even have to convert them from Markdown to Latex: I simply find and replace:

Code: Select all

[@] by \cite{} 
using Regex in my editor (Texstudio).


I do this by modifying the BibQuery to cite in Pandoc format, by the way. I think ZotQuery can also be modified to the same effect even if the latter requires exporting to Zotero. I never tried that one.
kseggleton
Posts: 43
Joined: Fri Jan 01, 2016 6:47 am

Re: BibQuery(ZotQuery) for Bookends

Post by kseggleton »

I have created an Alfred workflow that does what the OP wanted. It does not rely on BibTex, although exporting a BibTex file would be required if using Pandoc. The workflow will search the Bookends library for an author name (1st or subsequent authors) and then paste either a Bookends citation, a Multimarkdown citation or a Pandoc citation into the text editor that you are in. I have been using it for about 9 months and it has really sped up my writing. The Alfred workflow is here http://www.alfredforum.com/topic/8817-b ... citations/ an additional script that automates the export of BibTex files is here viewtopic.php?f=6&t=4044. I have created a separate discussion on the workflow here viewtopic.php?f=2&t=4046. One down side to the workflow is that it requires Bookends to be open, unlike the ZotQuery Alfred workflow. The ZotQuery workflow may be slightly faster as it is using Python and my workflow is using Applescript (so far I have not experienced significant delays on a small library - unsure of how it would cope with a really large library). The advantage of my workflow is that enables you to use Bookends citations, i.e. doesn't limit you to BibTex citations and it enables you to paste BibTex citations even if you haven't exported a BibTex file. The export of the BibTex file can occur at the end of the writing process.
Dellu
Posts: 271
Joined: Sun Mar 27, 2016 5:30 am

Re: BibQuery(ZotQuery) for Bookends

Post by Dellu »

it enables you to paste BibTex citations even if you haven't exported a BibTex file.
very good. I am downloading it
Post Reply