Skip to content

Commit

Permalink
Read directories from Zotero config files. Closes #21
Browse files Browse the repository at this point in the history
  • Loading branch information
deanishe committed Jan 6, 2019
1 parent d246c39 commit aa37479
Show file tree
Hide file tree
Showing 8 changed files with 170 additions and 69 deletions.
22 changes: 11 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,17 +82,17 @@ When you copy a citation, ZotHero puts both HTML and rich text (RTF) representat
Configuration
-------------

The workflow partly manages its own configuration with the keyword `zotconf`, but you may need to use the [workflow configuration sheet][conf-sheet] if you don't use Zotero 5's default data directory.
The workflow reads Zotero's own config files and partly manages its own configuration with the keyword `zotconf`, but you may need to use the [workflow configuration sheet][conf-sheet] if the workflow can't read Zotero's config files.


<a name="zotero-data"></a>
### Zotero data ###

The workflow uses your Zotero database and styles, therefore it needs to know where to find them. By default, the workflow looks in `~/Zotero` (the default location for Zotero 5).
The workflow uses your Zotero database and styles, therefore it needs to know where to find them. The workflow tries to read Zotero's own configuration files, and falls back to `~/Zotero` (the default location for Zotero 5).

If you data are stored somewhere else, you need to set `ZOTERO_DIR` in the [workflow configuration sheet][conf-sheet].
If the workflow can't find your data, you need to set `ZOTERO_DIR` in the [workflow configuration sheet][conf-sheet].

If you have set a "Linked Attachment Base Directory" in Zotero, enter its path for `ATTACHMENTS_DIR` in the [configuration sheet][conf-sheet].
Similarly, if you have set a "Linked Attachment Base Directory" in Zotero, but the workflow can't find the directory, enter its path for `ATTACHMENTS_DIR` in the [configuration sheet][conf-sheet].

**Note**: You can use the UNIX shortcut `~` to represent your home directory, e.g. `~/Zotero` for Zotero 5's default directory.

Expand Down Expand Up @@ -178,13 +178,13 @@ Theses are all settings available in the [workflow configuration sheet][conf-she
You probably shouldn't edit the `CITE_STYLE` or `LOCALE` variables yourself, as there's no guarantee the value you set is actually available. Adjust them using the `zotconf` keyword.


| Variable | Meaning |
|-------------------|------------------------------------------------------|
| `ATTACHMENTS_DIR` | Path to your Zotero attachments. |
| `CITE_STYLE` | Citation style copied by `⌘↩` and `⌥↩` |
| `LOCALE` | Locale for citations. Default: `en-US` (US English). |
| `ZOTERO_DIR` | Path to your Zotero data. |
| | |
| Variable | Meaning |
|-------------------|------------------------------------------------------------------------|
| `ATTACHMENTS_DIR` | Path to your Zotero attachments. Read from Zotero's config by default. |
| `CITE_STYLE` | Citation style copied by `⌘↩` and `⌥↩` |
| `LOCALE` | Locale for citations. Default: `en-US` (US English). |
| `ZOTERO_DIR` | Path to your Zotero data. Read from Zotero's config by default. |


<a name="licence--thanks"></a>
Licence & thanks
Expand Down
Binary file not shown.
88 changes: 44 additions & 44 deletions src/info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -1000,48 +1000,15 @@ EOS</string>
<dict>
<key>config</key>
<dict>
<key>alfredfiltersresults</key>
<false/>
<key>alfredfiltersresultsmatchmode</key>
<integer>0</integer>
<key>argumenttrimmode</key>
<integer>0</integer>
<key>argumenttype</key>
<integer>1</integer>
<key>escaping</key>
<integer>102</integer>
<key>queuedelaycustom</key>
<integer>3</integer>
<key>queuedelayimmediatelyinitially</key>
<true/>
<key>queuedelaymode</key>
<integer>0</integer>
<key>queuemode</key>
<integer>1</integer>
<key>runningsubtext</key>
<string></string>
<key>script</key>
<string>./zh citations "$id" "$1"
</string>
<key>scriptargtype</key>
<integer>1</integer>
<key>scriptfile</key>
<string></string>
<key>subtext</key>
<string></string>
<key>title</key>
<string></string>
<key>type</key>
<integer>5</integer>
<key>withspace</key>
<false/>
<key>triggerid</key>
<string>copy-citation</string>
</dict>
<key>type</key>
<string>alfred.workflow.input.scriptfilter</string>
<string>alfred.workflow.trigger.external</string>
<key>uid</key>
<string>8956B5DB-42F0-4570-9265-ECD302239D56</string>
<string>AEE6452E-9186-4609-8AD4-D74F469F1A79</string>
<key>version</key>
<integer>2</integer>
<integer>1</integer>
</dict>
<dict>
<key>config</key>
Expand Down Expand Up @@ -1106,15 +1073,48 @@ test -n "$autopaste" &amp;&amp; flags+=(--paste)
<dict>
<key>config</key>
<dict>
<key>triggerid</key>
<string>copy-citation</string>
<key>alfredfiltersresults</key>
<false/>
<key>alfredfiltersresultsmatchmode</key>
<integer>0</integer>
<key>argumenttrimmode</key>
<integer>0</integer>
<key>argumenttype</key>
<integer>1</integer>
<key>escaping</key>
<integer>102</integer>
<key>queuedelaycustom</key>
<integer>3</integer>
<key>queuedelayimmediatelyinitially</key>
<true/>
<key>queuedelaymode</key>
<integer>0</integer>
<key>queuemode</key>
<integer>1</integer>
<key>runningsubtext</key>
<string></string>
<key>script</key>
<string>./zh citations "$id" "$1"
</string>
<key>scriptargtype</key>
<integer>1</integer>
<key>scriptfile</key>
<string></string>
<key>subtext</key>
<string></string>
<key>title</key>
<string></string>
<key>type</key>
<integer>5</integer>
<key>withspace</key>
<false/>
</dict>
<key>type</key>
<string>alfred.workflow.trigger.external</string>
<string>alfred.workflow.input.scriptfilter</string>
<key>uid</key>
<string>AEE6452E-9186-4609-8AD4-D74F469F1A79</string>
<string>8956B5DB-42F0-4570-9265-ECD302239D56</string>
<key>version</key>
<integer>1</integer>
<integer>2</integer>
</dict>
<dict>
<key>config</key>
Expand Down Expand Up @@ -2224,7 +2224,7 @@ Edit the `ZOTERO_DIR` variable to point to Zotero 5's data directory if you aren
<string></string>
</dict>
<key>version</key>
<string>1.1</string>
<string>1.2</string>
<key>webaddress</key>
<string>https://github.com/deanishe/zothero</string>
</dict>
Expand Down
90 changes: 90 additions & 0 deletions src/lib/zothero/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# encoding: utf-8
#
# Copyright (c) 2019 Dean Jackson <[email protected]>
#
# MIT Licence. See http://opensource.org/licenses/MIT
#
# Created on 2019-01-06
#

"""Read Zotero configuration files."""

from ConfigParser import SafeConfigParser
import logging
import os
import re

from .util import unicodify

CONFDIR = os.path.expanduser(u'~/Library/Application Support/Zotero')
PROFILES = os.path.join(CONFDIR, u'profiles.ini')
DATADIR_KEY = 'extensions.zotero.dataDir'
ATTACH_KEY = 'extensions.zotero.baseAttachmentPath'
# Start of preference lines
PREFIX = 'user_pref("'

log = logging.getLogger(__name__)
log.addHandler(logging.NullHandler())


def read():
"""Load data and attachments directories from Zotero prefs."""
p = find_prefs()
if p:
return parse_prefs(p)

return None, None


def find_prefs():
"""Find prefs.js by parsing profiles.ini."""
conf = SafeConfigParser()
try:
conf.read(PROFILES)
except Exception as err:
log.error('reading profiles.ini: %s', err)
return None

for section in conf.sections():
if conf.has_option(section, 'Name') and \
conf.get(section, 'Name') == 'default':
path = conf.get(section, 'Path')
if conf.getboolean(section, 'IsRelative'):
path = os.path.join(CONFDIR, path)

return unicodify(os.path.join(path, 'prefs.js'))

return None


def parse_prefs(path):
"""Extract relevant preferences from prefs.js."""
datadir = attachdir = None

def extract_value(s):
m = re.search(r'"(.+)"', s)
if not m:
return None

return unicodify(m.group(1))

with open(path) as fp:
for line in fp:
line = line.strip()
if not line.startswith(PREFIX):
continue

line = line[len(PREFIX):]
i = line.find('",')
if i < 0:
continue

key = line[:i]
if key == DATADIR_KEY:
datadir = extract_value(line[i + 2:])
log.debug('[config] datadir=%r', datadir)
elif key == ATTACH_KEY:
attachdir = extract_value(line[i + 2:])
log.debug('[config] attachdir=%r', attachdir)

return datadir, attachdir
21 changes: 8 additions & 13 deletions src/lib/zothero/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import logging
import os

from .config import read as read_config
from .util import copyifnewer, unicodify, shortpath

# Default location of Zotero's data in version 5
Expand Down Expand Up @@ -57,11 +58,14 @@ def __init__(self, cachedir, zot_data_dir=None, zot_attachments_dir=None):
# it's necessary to make a copy.
self._copy_path = os.path.join(cachedir, 'zotero.sqlite')

# Attributes to back lazy-loading properties
self._zotero_dir = zot_data_dir # Zotero's data directory
self._attachments_dir = zot_attachments_dir # Zotero's attachment base
# Read Zotero config files
datadir, attachdir = read_config()

# Zotero's data directory
self._zotero_dir = zot_data_dir or datadir
# Zotero's attachment base
self._attachments_dir = zot_attachments_dir or attachdir
self._zot = None # Zotero object
# self._cache = None # Cache object
self._index = None # Index object
self._styles = None # Styles object

Expand Down Expand Up @@ -161,15 +165,6 @@ def update_index(self, force=False):
"""Update the search index."""
self.index.update(self.zotero, force)

# @property
# def cache(self):
# """Top-level cache."""
# if not self._cache:
# from .cache import Cache
# self._cache = Cache(os.path.join(self.cachedir, 'cache.sqlite'))

# return self._cache

@property
def styles(self):
"""CSL Styles loader.
Expand Down
5 changes: 5 additions & 0 deletions src/lib/zothero/csl.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ def get_field(zfield, ztype):
Returns:
unicode: CSL field name or ``None``.
"""
# Get "canonical" Zotero field name
zfield = REMAP.get(zfield, zfield)
Expand All @@ -56,6 +57,7 @@ def get_creator(ztype):
Returns:
unicode: CSL creator type or ``None``.
"""
# Get "canonical" Zotero type
ztype = REMAP.get(ztype, ztype)
Expand All @@ -73,6 +75,7 @@ def get_type(ztype):
Returns:
unicode: CSL type or ``None``.
"""
# Get "canonical" Zotero type
ztype = REMAP.get(ztype, ztype)
Expand Down Expand Up @@ -106,6 +109,7 @@ def entry_data(e):
Returns:
dict: CSL data.
"""
data = {'id': e.key}
ctype = get_type(e.type)
Expand Down Expand Up @@ -144,6 +148,7 @@ def parse_date(datestr):
Returns:
dict: ``date-parts`` dict for CSL JSON.
"""
parsed = util.parse_date(datestr)
if parsed:
Expand Down
3 changes: 3 additions & 0 deletions src/lib/zothero/formatting.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ def title(self):
Returns:
unicode: Formatted title.
"""
title = self.e.title

Expand All @@ -53,6 +54,7 @@ def creators(self):
Returns:
unicode: Formatted list of creators.
"""
n = len(self.e.creators)
if n == 0:
Expand Down Expand Up @@ -96,6 +98,7 @@ def year(self):
Returns:
unicode: Formatted year.
"""
if not self.e.year:
return 'xxx.'
Expand Down
Loading

0 comments on commit aa37479

Please sign in to comment.