Skip to content

Commit

Permalink
Use Alfred 3.2's re-run feature to update results live after refresh
Browse files Browse the repository at this point in the history
  • Loading branch information
deanishe committed Nov 10, 2016
1 parent 6b20bf9 commit 2478697
Show file tree
Hide file tree
Showing 14 changed files with 950 additions and 538 deletions.
Binary file not shown.
38 changes: 23 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,27 @@ Default Folder X for Alfred
===========================


Show and search Default Folder X favourites and recent items in [Alfred 2 & 3][alfredapp].
Show and search Default Folder X favourites and recent items in [Alfred][alfredapp].

**Note:** v0.3 and above are not compatible with Alfred 2!

## Usage ##

- `dfx` — Show/search all DFX favourite/recent items.
- `` or `⌘+<NUM>` — Open in Finder/default application.
Usage
-----

- `dfx [<query>]` — Show/search all DFX favourite/recent items.
- `` or `⌘+<NUM>` — Open in default application.
- `⌘+C` — Copy path to clipboard.
- `⌘+L` — Show path in Alfred's Large Text window.
- `dfxf` — Show/search only DFX favourite folders.
- `` or `⌘+<NUM>` — Open in Finder/default application.
- `dfxf [<query>]` — Show/search only DFX favourite folders.
- `` or `⌘+<NUM>` — Open in default application.
- `⌘+C` — Copy path to clipboard.
- `⌘+L` — Show path in Alfred's Large Text window.
- `dfxr` — Show/search only DFX recent files/folders.
- `` or `⌘+<NUM>` — Open in Finder/default application.
- `dfxr [<query>]` — Show/search only DFX recent files/folders.
- `` or `⌘+<NUM>` — Open in default application.
- `⌘+C` — Copy path to clipboard.
- `⌘+L` — Show path in Alfred's Large Text window.


## Licencing, thanks ##
Licencing, thanks
-----------------

This workflow is released under the [MIT licence][mit].

Expand All @@ -33,17 +34,24 @@ It is based on the [Alfred-Workflow][aw] library, which is also released under t
This bloody useful workflow would not exist but for [nickwild][nickwild].


## Changelog ##
Changelog
---------

### 0.1.0 ###
### 0.3.0 ###

- First release
- Remove update notification
- Use Alfred 3.2's re-run feature to update results when cached data are updated

### 0.2.0 ###

- Update folders in background
- Add auto-update info

### 0.1.0 ###

- First release


[mit]: ./src/LICENCE.txt
[aw]: http://www.deanishe.net/alfred-workflow/
[alfredapp]: https://www.alfredapp.com/
Expand Down
Binary file added src/DFX Files.scpt
Binary file not shown.
91 changes: 69 additions & 22 deletions src/dfx.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@
Usage:
dfx.py [-t <type>...] [<query>]
dfx.py -u
dfx.py -h | --help
dfx.py --version
Options:
-t <TYPE>, --type=<TYPE> Show only items of type. May be "fav", "rfile",
"rfolder" or "all" [default: all].
-u, --update Update cached data.
-h, --help Show this message and exit.
--version Show version number and exit.
Expand All @@ -26,10 +28,13 @@
from __future__ import print_function, unicode_literals, absolute_import

from collections import namedtuple
import os
from subprocess import check_output
import sys
from time import time

import docopt
from workflow import Workflow, ICON_WARNING
from workflow import Workflow3, ICON_WARNING
from workflow.background import is_running, run_in_background

log = None
Expand All @@ -55,14 +60,46 @@
DfxEntry = namedtuple('DfxEntry', ['type', 'path', 'name', 'pretty_path'])


# oo dP
# 88
# .d8888b. .d8888b. 88d888b. dP 88d888b. d8888P
# Y8ooooo. 88' `"" 88' `88 88 88' `88 88
# 88 88. ... 88 88 88. .88 88
# `88888P' `88888P' dP dP 88Y888P' dP
# 88
# dP
def get_dfx_data():
"""Return DFX favourites and recent items.
Returns:
list: Sequence of `DfxEntry` objects.
"""
st = time()
script = wf.workflowfile('DFX Files.scpt')
output = wf.decode(check_output(['/usr/bin/osascript', script]))
log.debug('DFX files updated in %0.3fs', time() - st)

entries = []

home = os.getenv('HOME')
for line in [s.strip() for s in output.split('\n') if s.strip()]:
row = line.split('\t')
if len(row) != 2:
log.warning('Invalid output from DFX : %r', line)
continue
typ, path = row
# Remove trailing slash from path or things go wrong...
path = path.rstrip('/')
e = DfxEntry(
typ,
path,
os.path.basename(path),
path.replace(home, '~'),
)
log.debug('entry=%r', e)
entries.append(e)

return entries


def do_update():
"""Update cached DFX files and folders."""
log.info('Updating DFX data...')
data = get_dfx_data()
wf.cache_data(DFX_CACHE_KEY, data)


def prefix_name(entry):
"""Prepend a Unicode icon to `entry.name` based on `entry.type`.
Expand All @@ -84,26 +121,37 @@ def prefix_name(entry):

def main(wf):
"""Run workflow script."""
# Parse input ------------------------------------------------------
# Call this to ensure magic arguments are parsed
# Parse input
wf.args
args = docopt.docopt(__doc__, version=wf.version)
query = args.get('<query>') or b''
query = wf.decode(query).strip()
types = args.get('--type')
log.debug('args=%r', args)

# Load data --------------------------------------------------------
# -----------------------------------------------------------------
# Update cached DFX data

if args.get('--update'):
return do_update()

# -----------------------------------------------------------------
# Script Filter

# Load cached entries first and start update if they've
# expired (or don't exist)
entries = wf.cached_data(DFX_CACHE_KEY, max_age=0)
if not entries or not wf.cached_data_fresh(DFX_CACHE_KEY, MAX_CACHE_AGE):
if not is_running('update'):
run_in_background(
'update',
['/usr/bin/python', wf.workflowfile('update.py')]
['/usr/bin/python', wf.workflowfile('dfx.py'), '--update']
)

# Tell Alfred to re-run the Script Filter if cache is being updated
if is_running('update'):
wf.rerun = 1

# No data in cache yet. Show warning and exit.
if entries is None:
wf.add_item('Waiting for Default Folder X data…',
Expand All @@ -112,27 +160,28 @@ def main(wf):
wf.send_feedback()
return

# Filter entries ---------------------------------------------------
# Filter entries
if types != ['all']:
log.debug('Filtering for types : %r', types)
entries = [e for e in entries if e.type in types]

# Remove duplicates and non-existent files
entries = [e for e in set(entries) if os.path.exists(e.path)]

# Filter data against query if there is one
if query:
total = len(entries)
entries = wf.filter(query, entries, lambda e: e.name, min_score=30)
log.info('%d/%d entries match `%s`', len(entries), total, query)

# Display results --------------------------------------------------
# Prepare Alfred results
if not entries:
wf.add_item(
'Nothing found',
'Try a different query?',
icon=ICON_WARNING)

# Don't add duplicate entries for paths in both favourites and recent
seen = set()
for e in entries:
if e.path in seen:
continue

if types == ['all']:
title = prefix_name(e)
Expand All @@ -151,15 +200,13 @@ def main(wf):
icon=e.path,
icontype='fileicon')

seen.add(e.path)

wf.send_feedback()

return 0


if __name__ == '__main__':
wf = Workflow(
wf = Workflow3(
default_settings=DEFAULT_SETTINGS,
update_settings=UPDATE_SETTINGS,
help_url=HELP_URL,
Expand Down
Loading

0 comments on commit 2478697

Please sign in to comment.