Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save FeralFlora/78f494c1862ce4457cef28d9d9ba5a01 to your computer and use it in GitHub Desktop.
Save FeralFlora/78f494c1862ce4457cef28d9d9ba5a01 to your computer and use it in GitHub Desktop.
Zotero import template for the Zotero integration plugin for Obsidian. Screenshots and usage guide over in the Obsidian forum here: https://forum.obsidian.md/t/zotero-integration-import-templates/36310/105?u=feralflora
  • ZI-main.md
    • The main Zotero Integration template
  • runImport.md
    • Template that enables updating literature notes at the click of a button, and much more.
  • Meta bind button template
    • Template for in-note button that executes runImport.md

The Buttons plugin is likely to be deprecated, and the maintainer (@shabegom) is urging users to migrated to Meta Bind and it's implementation of buttons. See mProjectsCode/obsidian-meta-bind-plugin#199. Therefore, I've switched out the old "Buttons" button to a Meta bind button that does the same thing.

Here's how to make it functional:

If you had set up the old "Buttons" button, you can skip steps 2, 3 & 4.

  1. If you haven't, install Meta Bind and Templater.
  2. Make sure you have the "runImport" Templater template in your vault (also found under this gist).
  3. In the runImport.md template, replace 'IMPORT_NAME' with the name you've given the Import format you want Zotero Integration to run, when importing your literature notes.

Warning

You need the name of the Import Format in Zotero Integration's settings, NOT the file name of your literature note template. See the example below.

For example, below here, the import name is "APA Literature Note", and that's what you should use.

image

  1. Associate the runImport template with a hotkey / command in Templater's settings under "Template hotkeys".
  2. Copy everything inside the "button" code block below (without the code block itself).
  3. Paste the code into an editor, and replace the path on the last line with the path to runImport inside your vault.
  4. Copy your newly edited button template, with the path corrected.
  5. Open Meta bind's settings.
  6. Find "Button templates" and press "Edit templates".
  7. At the bottom of the popup, press the button that says "Add Template from Clipboard".
  8. Then, remember to press save before you exit the "Edit templates" menu.

Button template

label: Update literature note
hidden: false
tooltip: "This will fetch new annotations from Zotero"
id: update-litnote
style: primary
actions:
  - type: command
    command: templater-obsidian:07 - Bins/Templates/Zotero Integration/runImport.md

Remember to replace path in the last line. The path starts at "07".

<%* // Get citekey from 'citekey' property, or alias starting with '@' or file name const citekey = tp.frontmatter?.citekey || tp.frontmatter.aliases?.find(alias => alias.startsWith('@')) || tp.file.title; // Get the library ID from the properties. Fall back to "My Library" (1), if the library ID is not accessible const libraryID = tp.frontmatter.libraryID || 1; // Run the import app.plugins.getPlugin('obsidian-zotero-desktop-connector').runImport('IMPORT NAME', citekey, libraryID); ; %>

{# version: 3.6 -#}

citekey: {{citekey}} aliases:

  • "{%- if creators -%} {{creators[0].lastName or creators[0].name }} {%- if creators|length == 2 %} & {{creators[1].lastName or creators[1].name}}{% endif -%} {%- if creators|length > 2 %} et al.{% endif -%} {%- endif -%} {%- if date %} ({{date | format("YYYY")}}){% endif -%} {%- if shortTitle %} {{shortTitle | safe}} {%- else %} {{title | safe}} {%- endif -%}"{% if itemType == "bookSection" %} book-title: "{{bookTitle | replace('"',"'")}}"{% endif %} title: "{{title | replace('"',"'")}}" {%- set camelRegex = r/([a-z])([A-Z])/g %} {%- for type, creators in creators | groupby("creatorType") %} {% if creators.length > 1 %}{{type | replace(camelRegex, "$1 $2") | lower | trim}}s:{%- for creator in creators %}{% if creator.name %}
  • {{creator.name}}{% else%}
  • {{creator.firstName}} {{creator.lastName}} {% endif %}{%- endfor %} {% else -%} {{type | replace(camelRegex, "$1-$2") | lower | trim}}:{%- for creator in creators %}{% if creator.name %} "{{creator.name}}"{% else%} "{{creator.firstName}} {{creator.lastName}}"{% endif -%}{%- endfor -%}{% endif -%}{% endfor %} year: {% if date %}{{date | format("YYYY")}}{% endif %} item-type: {{itemType | replace(camelRegex, "$1 $2") | title | trim}} publisher: {% if publicationTitle %}"{{publicationTitle}}"{% else %}"{{publisher}}"{% endif %} {%- if notes.length > 0 -%} {%- set longShortCutoff = 20 -%} {%- set shortnotes = [] -%} {%- set longnotes = [] -%} {%- for note in notes -%} {%- if note.note | wordcount <= longShortCutoff -%} {%- set shortnotes = (shortnotes.push(note.note), shortnotes) -%} {%- else -%} {%- set longnotes = (longnotes.push(note), longnotes) -%} {%- endif -%}{%- endfor -%}{%- endif -%} {%- for comment in shortnotes %} {%- if comment and loop.first %} comments: {% endif -%}
  • "{{comment|replace('"',"'")| replace("\n"," ")}}"{% endfor %} tags:{% for t in tags %}
  • {{t.tag | replace(r/\s+/g, "-")}}{% endfor %}{% if DOI %} doi: https://doi.org/{{DOI}}{% endif %}{% if itemType == "book" %} ISBN: {{ISBN}}{% endif %} cssclasses:
  • literature-note{% if attachments.length > 0 %}{% for attachment in attachments %}{% if loop.first %} attachments:{% endif %}
  • {{attachment.path}}{% endfor %}{% endif %} libraryID: {{libraryID}}

BUTTON[update-litnote]

{% persist "notes" -%} {%- if isFirstImport %}

{# ==The following sections (Key takeaways and Processing) are not filled automatically. They are for for you to write into manually.== -#}

Key takeaways

{#- The following is a cursor placeholder for the Templater plugin. After importing the note, you can jump to each of these with an assigned hotkey like ctrl+J #}

  • <% tp.file.cursor(1) %>

Processing

  • Status:: new
  • Connections:: <% tp.file.cursor(4) %>
  • Projects::

{% endif %}{% endpersist %}

[!info]- Info 🔗 Zotero{% if DOI %} | DOI{% endif %}{% for attachment in attachments | filterby("path", "endswith", ".pdf") %} | [PDF-{{loop.index}}](file:///{{attachment.path | replace(" ", "%20")}}){%- endfor %}

{% if bibliography %}Bibliography: {{bibliography|replace("\n","" )}}{% endif %}

Authors:: {% for a in creators %} [[03 - Source notes/People/{{a.firstName}} {{a.lastName}}|{{a.firstName}} {{a.lastName}}]]{% if not loop.last %}, {% endif %}{% endfor %}

{% if tags %}Tags: {% for t in tags %}#{{t.tag | replace(r/\s+/g, "-")}}{% if not loop.last %}, {% endif %}{% endfor %}{% endif %}

Collections:: {% for collection in collections %}[[{{collection.name}}]]{% if not loop.last %}, {% endif %}{% endfor -%} {%- set readingSpeed = 220 %} {%- set wordsPerPage = 360 %} {%- if pages %} {%- set pageRegex = r/(\d+)-(\d+)/ %} {%- set splitPages = pageRegex.test(pages) %} {%- if splitPages %} {%- set pageMatch = pageRegex.exec(pages) %} {%- set firstPage = pageMatch[1] %} {%- set pageCount = pageMatch[2] - pageMatch[1] %} {%- else %} {%- set pageCount = pages %} {%- endif %} {%- elif numPages %} {%- set pageCount = numPages %} {%- else %} {%- set pageCount = 0 %} {% endif -%} {%- if firstPage %}

First-page:: {{firstPage}} {%- endif -%} {%- if pageCount > 0 -%} {%- set readingTime = ((pageCount* wordsPerPage)/readingSpeed)/60 %}

Page-count:: {{pageCount}}

Reading-time:: {% if readingTime < 1 %}{{(readingTime * 60) | round + " minutes"}}{% else %}{{readingTime | round(3) + " hours"}}{% endif %}{% endif %}

[!abstract]- {% if abstractNote %} {{abstractNote|replace("\n","\n>")|striptags(true)|replace("Objectives", "Objectives")|replace("Background", "Background")|replace("Methodology", "Methodology")|replace("Results","Results")|replace("Conclusion","Conclusion")}} {% endif %}

[!quote]- Citations

content: "@{{citekey}}" -file:@{{citekey}}

{%- set headingRegex = r/^#+/ -%} {%- set titleRegex = r/^#+./ -%} {%- set lineRegex = r/^.$/m %} {%- if longnotes.length > 0 -%} {%- for n in longnotes -%} {%- if n and loop.first %}

[!note]- Zotero notes ({{longnotes.length}})

Notes longer than {{longShortCutoff}} words. {%- endif %}

[!example]- Note {{loop.index}} |{%- if headingRegex.test(n.note) == true %}{{n.note | replace(n.note,titleRegex.exec(n.note))|replace(headingRegex,"")}}{% else %} {{lineRegex.exec(n.note | truncate(30))}} {% endif %} {{n.note | replace("\n", "\n>> ")| replace(titleRegex, "")}}{% if n.tags.length > 0 %}

Tags:{% for t in n.tags %} #{{t.tag}}{% if not loop.last %}, {% endif %}{% endfor %}{% endif -%}{%- if not loop.last %} {%- endif -%} {%- endfor -%}{%- endif %}


Reading notes

{% set colorValueMap = { "#2ea8e5": { "colorCategory": "Blue", "heading": "❓ Problem formulation", "symbol": "?" }, "#5fb236": { "colorCategory": "Green", "heading": "🎯 Key takeaways", "symbol": "$" }, "#ffd400": { "colorCategory": "Yellow", "heading": "💬 Evidence and arguments", "symbol": "&" }, "#f19837": { "colorCategory": "Orange", "heading": "✅ Actionable takeaways", "symbol": "!" }, "#a28ae5": { "colorCategory": "Purple", "heading": "🧩 Concepts and frameworks", "symbol": "~" }, "#e56eee": { "colorCategory": "Magenta", "heading": "🗺️ Context and connections", "symbol": "€" }, "#ff6666": { "colorCategory": "Red", "heading": "🚧 Digging and disclaimers", "symbol": "£" }, "#aaaaaa": { "colorCategory": "Gray", "heading": "📌 Statistics and info", "symbol": "%" } } -%}

{%- macro tagFormatter(annotation) -%} {% if annotation.tags -%} {%- for t in annotation.tags %} #{{ t.tag | replace(r/\s+/g, "-") }}{% if not loop.last %}, {% endif %}{%- endfor %} {%- endif %} {%- endmacro -%}

{% persist "annotations" %} {% set annotations = annotations | filterby("date", "dateafter", lastImportDate) -%} {% if annotations.length > 0 %} Imported on [[{{importDate | format("YYYY-MM-DD")}}]] at {{importDate | format("HH:mm")}}

{%- set grouped_annotations = annotations | groupby("color") -%} {%- for color, colorValue in colorValueMap -%} {%- if color in grouped_annotations -%} {%- set annotations = grouped_annotations[color] -%} {%- for annotation in annotations -%} {%- set citationLink = '[(p. ' ~ annotation.pageLabel ~ ')](' ~ annotation.desktopURI ~ ')' %} {%- set tagString = tagFormatter(annotation) %}

{%- if annotation and loop.first %}

{{colorValue.heading}} %% fold %%

{% endif -%}

{%- if annotation.imageRelativePath %}

[!cite]+ Image {{citationLink}} ![[{{annotation.imageRelativePath}}]]{% if annotation.tags %} {{tagString}}{% endif %}{%- if (annotation.comment or []).indexOf("todo ") !== -1 %}

  • {{annotation.comment | replace("todo ", "")}}{%- elif annotation.comment %} {{annotation.comment}}{%- endif %} {% elif (annotation.comment or []).indexOf("todo ") !== -1 %}
  • {{annotation.comment | replace("todo ", "")}}:{% if not annotation.annotatedText %} {{citationLink}}{% else %}
    • {{colorValue.symbol}} {{annotation.annotatedText | replace(r/\s+/g, " ")}} {{citationLink}}{{tagString}}{% endif -%} {% elif annotation.comment %}
  • {{annotation.comment}}:{% if not annotation.annotatedText %} {{citationLink}}{% else %}
    • {{colorValue.symbol}} {{annotation.annotatedText | replace(r/\s+/g, " ") }} {{citationLink}}{{tagString}}{% endif -%} {%- elif annotation.annotatedText %}
  • {{colorValue.symbol}} {{annotation.annotatedText | replace(r/\s+/g, " ") }} {{citationLink}}{{tagString}} {%- endif -%}{%- endfor %}{%- endif -%} {% endfor -%} {% endif %}

{% endpersist %}

@FeralFlora
Copy link
Author

Please note that the template version 3.3 had an issue where spaces were incorrectly replaced with dashes in the information callout, leading to malformed tags. This is fixed in version 3.4.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment