testing zotero://select
I was looking through the code and found zotero://select which seemed useful, but I noticed that item id's were not consistent across sync'd machines. That is, zotero://select/9/400 brings up a different item on different machines, even though both are sync'd otherwise. What is the expected behavior? Would a reset fix this?
My thinking was that zotero://select would be a handy way to access items from emacs (or any other external application, as suggested in http://forums.zotero.org/discussion/1286/freemind/).
I don't know if it matters, but both machines are linux and firefox 3.5 and I'm using 2.0b6.5
My thinking was that zotero://select would be a handy way to access items from emacs (or any other external application, as suggested in http://forums.zotero.org/discussion/1286/freemind/).
I don't know if it matters, but both machines are linux and firefox 3.5 and I'm using 2.0b6.5
Is there any public timeline for 2.0 Final? I'm just wondering if it's worth investigating a workaround for myself using MozRepl.
For me, the problem is workflow and being able to quickly drag Zotero items into emacs, where I work in LaTeX or org-mode, and from emacs to open Zotero to get at my items. I don't want to worry about an intermediate step of exporting from Zotero to a BibTeX file, and lose the easy access to the snapshot, pdf, etc in Zotero.
So, I have two things: a translator for Zotero and a small elisp function (at the bottom of this post).
The code below can be copied into a file (ZotSelect.js) and put in the translators directory (on Mac: ~/Library/Application Support/Firefox/Profiles//zotero/translators on Linux: ~/.mozilla/firefox/profiles//zotero/translators)
Restart Firefox. Zotero should load the new translator; it should show up in the Export pane of the Preferences. Select ZotSelect as the default export.
Now, I can drag and drop (or use the Quick Copy keyboard shortcut) from Zotero to emacs. It creates one or more links that look like this:
zotero://select//0_ASDF1234/creator_title_year
The can be copied into the Firefox location bar and loaded, and Zotero pops up with the current item highlighted. The "creator_title_year" bit is created using the same code the BibTeX exporter uses to generate a citation key (I understand that it's possible for one translator to re-use code in another translator, but due to time constraints, I haven't bothered, and just copied the code.) The goal for me was something I can quickly search-and-replace when it's time to run BibTeX.
{
"translatorID":"a729a9e4-a469-4a12-bcbe-7902419846c5",
"translatorType":2,
"label":"ZotSelect",
"creator":"Scott Campbell",
"target":"html",
"minVersion":"1.0.0b4.r1",
"maxVersion":"",
"priority":200,
"inRepository":false,
"lastUpdated":"2010-03-12 10:51:00"
}
Zotero.configure("dataMode", "block");
Zotero.addOption("exportCharset", "UTF-8");
//%a = first author surname
//%y = year
//%t = first word of title
var citeKeyFormat = "%a_%t_%y";
var numberRe = /^[0-9]+/;
// this is a list of words that should not appear as part of the citation key
var citeKeyTitleBannedRe = /(\s+|\b)(a|an|from|does|how|it\'s|its|on|some|the|this|why)(\s+|\b)/g;
var citeKeyConversionsRe = /%([a-zA-Z])/;
var citeKeyCleanRe = /[^a-z0-9\!\$\&\*\+\-\.\/\:\;\<\>\?\[\]\^\_\`\|]+/g;
var citeKeyConversions = {
"a":function (flags, item) {
if(item.creators && item.creators[0] && item.creators[0].lastName) {
return item.creators[0].lastName.toLowerCase().replace(/ /g,"_").replace(/,/g,"");
}
return "";
},
"t":function (flags, item) {
if (item["title"]) {
return item["title"].toLowerCase().replace(citeKeyTitleBannedRe, "").split(" ")[0];
}
return "";
},
"y":function (flags, item) {
if(item.date) {
var date = Zotero.Utilities.strToDate(item.date);
if(date.year && numberRe.test(date.year)) {
return date.year;
}
}
return "????";
}
}
function buildCiteKey (item,citekeys) {
var basekey = "";
var counter = 0;
citeKeyFormatRemaining = citeKeyFormat;
while (citeKeyConversionsRe.test(citeKeyFormatRemaining)) {
if (counter > 100) {
Zotero.debug("Pathological BibTeX format: " + citeKeyFormat);
break;
}
var m = citeKeyFormatRemaining.match(citeKeyConversionsRe);
if (m.index > 0) {
//add data before the conversion match to basekey
basekey = basekey + citeKeyFormatRemaining.substr(0, m.index);
}
var flags = ""; // for now
var f = citeKeyConversions[m[1]];
if (typeof(f) == "function") {
var value = f(flags, item);
Zotero.debug("Got value " + value + " for %" + m[1]);
//add conversion to basekey
basekey = basekey + value;
}
citeKeyFormatRemaining = citeKeyFormatRemaining.substr(m.index + m.length);
counter++;
}
if (citeKeyFormatRemaining.length > 0) {
basekey = basekey + citeKeyFormatRemaining;
}
// for now, remove any characters not explicitly known to be allowed;
// we might want to allow UTF-8 citation keys in the future, depending
// on implementation support.
//
// no matter what, we want to make sure we exclude
// " # % ' ( ) , = { } ~ and backslash
basekey = basekey.replace(citeKeyCleanRe, "");
var citekey = basekey;
var i = 0;
while(citekeys[citekey]) {
i++;
citekey = basekey + "-" + i;
}
citekeys[citekey] = true;
return citekey;
}
function doExport() {
// Zotero.write("zotero://select//");
// Zotero.write("\n");
var citekeys = new Object();
var item;
while(item = Zotero.nextItem()) {
Zotero.write("zotero://select//");
var library_id = item.LibraryID ? item.LibraryID : 0;
Zotero.write(library_id+"_"+item.key);
// create a unique citation key
var citekey = buildCiteKey(item, citekeys);
// write citation key
Zotero.write("/"+citekey);
Zotero.write("\n");
}
}
I use the following elisp function when on the zotero://select// item in emacs:
(defun smc/zot-select ()
"select on current 'zotero://select//HASH' using fresno"
(interactive)
(save-excursion
(let (zot-select js l)
(re-search-backward " \\|^")
(if (re-search-forward "\\(zotero:\\/\\/select\\/\\/0_[[:alnum:]]\\{8\\}\\)" (line-end-position) t)
(progn
(setq zot-select (match-string-no-properties 1))
;; (message zot-select)
(shell-command (concat "fresno -p \"" zot-select "\"")))
(message "no match")))))
Fresno is a complement to MozRepl (http://simile.mit.edu/wiki/Fresno) I do this because Firefox on the mac is braindead. It can't open "zotero://select" urls without fresno, although it does on Linux. And this is simpler than going through MozRepl.
I don't know if this will help anyone else, and if there are bugs or anything I make no promises or guarantees, but I'll happily accept advice or corrections. For now, it works for me. It may not work with shared libraries, or anything other than my exact circumstances.
Certainly, it was an interesting challenge, and it makes Zotero that much more useful to me.
The code works; dragging-and-dropping will yield:
<a href='zotero://select//0_SBIKZJUN'>Keenan. Dec., 1967.
<i>Muscovy and Kazan: Some Introductory Remarks on the
Patterns of Steppe Diplomacy</i></a>
Problems remain, however.
First, Zotero doesn't let export translators send formatted text to the clipboard (the appropriate code for exporting via styles is at fileInterface.js:376). This means that I cannot simply drag a link into my word processor, or a Zotero note, since the HTML source will not be interpreted as HTML, but displayed as-is. I think that it would be sufficient to have translators and styles use the same
*ToClipboard
methods.Second, I can't use the
Zotero.Items.getLibraryKeyHash(item)
code Dan mentioned above, since it's not available to translators (it seems).Third, I would like to use an existing style, but just wrap its output in a link that points to the item in my library. Currently, translators don't have access to Zotero.Styles.
Fourth, and perhaps separately from the first three issues, TinyMCE won't let me click on links, so even if I can make links, I still won't be able to use them to make navigable connections between my notes and items.
This is an exciting development.
With respect to the second problem, I ran into the same issue with Zotero.Items.getLibraryKeyHash(item). That's why I copied the two lines out of chrome/content/zotero/xpcom/data/dataObjects.js. I know that's cheating but this was a quick and dirty job. The translator might break if you have shared or multiple libraries. I didn't test that.
What I didn't mention is that this translator works if you drag the note, the attachment, or the original item: the hash refers to the individual entity, not the original item (although the citation key currently generated for notes is meaningless).
I was surprised to read (and then test) your comment that links don't work in the notes in TinyMCE. Is this a known bug or a consequence of limiting TinyMCE for Zotero? I can see how having links in notes to other items would be very handy.
I've often thought that it would be incredibly useful to embed zotero://select (and zotero://attachment) links in the generated reports, even if it were problematic for anyone else who read the report.
If we can do this, then we'll be able to add working links between notes and items!
@scottcampbell: I get a hash starting with 0_ even for items in group libraries, so I think the workaround may not work for shared items. Local is a good start, but it'd be nice for translators to receive access to more Zotero functionality...
I've read the threads listed here and in https://forums.zotero.org/discussion/24241/ and in particular I've seen the applescript solution in https://forums.zotero.org/discussion/28386/zoteroselect-for-z-standalone-select-z-item-from-external-application/ But (appart from been green with envy:-) ) I have no idea how to get something like that to work in Linux and it seems (https://github.com/zotero/zotero/issues/498#issuecomment-52443382) the answer would be no. Is that the case?
see e.g. http://superuser.com/questions/162092/how-can-i-register-a-custom-protocol-with-xdg
[Desktop Entry]
Version=1.0
Name=Zotero
Name=Zotero Client
Exec=zotero
Icon=zotero-icon
Type=Application
Terminal=false
MimeType=x-scheme-handler/zotero-protocol;
I've used both
xdg-desktop-menu install --novendor zotero.desktop
and adding the entry in my .local/share/applications/mimeapps.list
but when I do something like
xdg-open zotero://select/items/0_82UIB2W6
or
xdg-open zotero://open-pdf/0_X64D5CU8/4
I get "gvfs-open: zotero://open-pdf/0_X64D5CU8/4: error opening location: The specified location is not supported"
(the entries are to an existing entry ---obtained using the second procedure explained in https://zoteromusings.wordpress.com/2013/04/23/zotero-item-uris-from-client/ --- and to an existing PDF, with a link freshly generated with zotfile).
But then, I think the problem is previous and reflects I am doing something very wrong, as both
xdg-mime query filetype zotero://select/items/0_82UIB2W6
and
xdg-mime query filetype 0_82UIB2W6
say "xdg-mime: file '0_82UIB2W6' does not exist"
But in fact, I do not see how this would work: when I've used xdg-open and friends in the past, I associated a file type with a desktop entry that passes the file to the program I want (e.g., that is how I open PDFs by default: they are opened with Emacs because I have an entry that calls emacsclient.desktop and have associated PDFs with emacsclient.desktop). But this is not exactly the same.
I guess I'll need to try and understand xdg better.
MimeType=x-scheme-handler/zotero;
(note that org-protocol was used to open org-protocol://)
xdg-open zotero://select/items/0_82UIB2W6
will not take me to the entry, for instance. I think the problem is that what I have done is just allow me to type
xdg-open zotero://something
so that it is equivalent to calling
zotero
but the arguments (e.g., things like //select/items/0_82UIB2W6 or //open-pdf/0_X64D5CU8/4) are not passed to Zotero standalone.
I enabled debugging: nothing is shown in the output. But then, it makes sense that nothing is shown: it seems to me that nothing is being passed on to Zotero standalone. In other words
xdg-open zotero://select/items/0_82UIB2W6
is the same as
xdg-open zotero
(so that even something silly as
xdg-open zotero:aeiou-some-silly-string
does nothing but change focus and specifically it does not trigger any output in the degug console).
I've google around, and I do not see how to pass arguments to Zotero standalone in Linux (though this is clearly possible in Macs, as per https://forums.zotero.org/discussion/28386/zoteroselect-for-z-standalone-select-z-item-from-external-application/)
zotero zotero://select/items/0_82UIB2W6
do nothing, except move focus to Zotero (or open it if not running). So, as I said, the problem seems to be that I do not know how to get the Zotero Standalone process, under Linux, to listen/accept arguments.
What I am missing is a way to do the equivalent of
tell app "Zotero" to open location "zotero://select/items/0_82UIB2W6
https://github.com/willsALMANJ/Zutilo/issues/47#issuecomment-165952292
First, note that you should not try to run "run-zotero.sh" or however the Mozilla script might be called in your system ---the script might be under "/usr/bin" and be called "zotero" (see https://github.com/zotero/zotero-standalone-build/issues/39). You should use the zotero binary. So locate where the actual zotero binary executable lives. For instance, if you download the Zotero-4.0.28_linux-x86_64.tar.bz2 from https://www.zotero.org/download/, when you tar -jxf the file, you will get a directory "Zotero_linux-x86_64" that contains a binary executable file called "zotero", as well as a "run-zotero.sh", and a bunch of other files; you want to call the "zotero" one directly, not the "run-zotero.sh" script. In some Linux distributions at least, that binary is under "/usr/lib/zotero".
Now, if you already have Zotero standalone running (won't work for now if Zotero is not running ---https://github.com/zotero/zotero-standalone-build/issues/40), you can just pass the URL as:
/somewhere/Zotero_linux-x86_64/zotero --url zotero://select/items/0_someID
Thus, the zotero.desktop file so that xdg-open works might be (modify the path to the zotero binary accordingly)
#######################
[Desktop Entry]
Version=1.0
Name=Zotero Client
Exec=/wherever/Zotero_linux-x86_64/zotero --url %u
Type=Application
Terminal=false
MimeType=x-scheme-handler/zotero;
###########
The above works with "zotero://select/items". It does not seem to work with "zotero://open-pdf", from Zotfile, but it is easy enough to write a script, called from zotero.desktop, that will call zotero when a "select/items" is passed, and will call your pdf viewer of choice for it to open the PDF at the correct page ---say, invoking Okular or Emacs. For instance, my zotero.desktop file is
#################
[Desktop Entry]
Version=1.0
Name=Zotero Client
Exec=/home/ramon/bin/zotero-protocol.sh %u
# Exec=/home/ramon/Sources/Zotero_linux-x86_64/zotero --url %u
Type=Application
Terminal=false
MimeType=x-scheme-handler/zotero;
#############
Where zotero-protocol.sh is (with proper indentation :-) )
###################
#!/bin/bash
shopt -s extglob ## Remember to set extended options
USE_EMACS=1 ## Open PDFs with Emacs (+ pdf-tools and org-pdfview)
EMACS_NAME="emacsclient -s gral -c"
OKULAR_NAME="/usr/bin/okular"
ROOT_PDF_DIR="/home/ramon/Zotero-storage"
ZOTERO_BINARY="/home/ramon/Sources/Zotero_linux-x86_64/zotero"
## For now, we only handle "zotero://open-pdf"
## and "zotero://select/items/some_dir".
OPEN_PDF_HANDLE="zotero://open-pdf/0_"
ZOTERO_SELECT_ITEMS="zotero://select/items"
if [[ $(echo "$1" | grep $OPEN_PDF_HANDLE -c) -eq 1 ]]; then
DIR=$(echo "$1" | sed 's/0_//' | cut -d / -f 4)
PAGE=$(echo "$1" | sed 's/0_//' | cut -d / -f 5)
## There should be a single PDF per directory. See
## https://www.zotero.org/support/attaching_files search for "each
## file has its own subdirectory"
FILENAME=($ROOT_PDF_DIR/$DIR/*.@(pdf|PDF))
if [[ USE_EMACS -eq 1 ]]; then
FILEANDPAGE=$FILENAME::$PAGE
$EMACS_NAME --eval "(progn (org-pdfview-open \"$FILEANDPAGE\") (delete-other-windows))" > /dev/null
else
$OKULAR_NAME $FILENAME -p $PAGE
fi
elif [[ $(echo "$1" | grep $ZOTERO_SELECT_ITEMS -c) -eq 1 ]]; then
$ZOTERO_BINARY --url $1
else
echo -e "For now, we only handle calls with $OPEN_PDF_HANDLE or $ZOTERO_SELECT_ITEMS \n"
exit 1
fi
#####################
And yes, pretty MyLibrary is always 0 for the purpose of select (see dstillman to that extent towards the top of this thread). FWIW, you can now also use zotero://select/library/items/NWGAIEWW to the same effect -- that maps more elegantly to the web URIs. For groups, thats
zotero://select/groups/487712/items/6KQ4G4P6
Where 487712 is the same library ID as used by the web API.
Regarding different identifiers of a reference among libraries, it seems interesting that DOIs could be a global identifier unifying references across libraries for citation relevant metadata -- attachments and user-generated content in the database could differ of course. I guess Zotero uses the DOI already for the identification of duplicates. Also, such a global identifier is limited to items that have a DOI. But, a DOI or a shortDOI is sufficient for doi.org to generate a properly formatted entry for a bibliography, e.g., `curl -LH "Accept: text/x-bibliography; style=apa" "https://doi.org/10.1056/nejmoa2028836"` and `curl -LH "Accept: text/x-bibliography; style=apa" "https://doi.org/ffjp"`. The style argument supports the styles of the large CSL library I looked up at the DOI Citation Formatter https://citation.crosscite.org/.
My primary interest in these concepts is for a note-taking or Zettelkasten system and communication with other scientists. For notes or communications independent of my Zotero library, a global identifier is helpful. Locally, I use a short Zotero handler for linking to database items `zot:<<itemID>>`, e.g., `zot:NWGAIEWW`. A very small script takes the itemID, adds it to the URL template, and sends it to Zotero.