Jump to content

deanishe

Member
  • Posts

    8,759
  • Joined

  • Last visited

  • Days Won

    522

Everything posted by deanishe

  1. I've been tinkering with and running the script for a week or two now, and it's working very well.
  2. BTW, if you haven't done so already, you should probably post this in the Share Your Workflows forum. And perhaps on Packal, too.
  3. You can just hit ⌘+C. When you're looking at Alfred's fallback searches, using ⌘+C will copy the query to the clipboard.
  4. Hmm. The workflow appears to choke on non-ASCII queries, which is kind of a big thing when it's designed to accept German words… If I enter a query that contains an umlaut, the workflow sends XML to Alfred, but all the values are empty. Here's the result of entering the query "über": <?xml version="1.0" encoding="UTF-8"?> <items><item valid="true" arg="" uid=""><title></title><subtitle></subtitle><icon></icon></item><item valid="true" arg="" uid=""><title></title><subtitle></subtitle><icon></icon></item><item valid="true" arg="" uid=""><title></title><subtitle></subtitle><icon></icon></item><item valid="true" arg="" uid=""><title></title><subtitle></subtitle><icon></icon></item><item valid="true" arg="" uid=""><title></title><subtitle></subtitle><icon></icon></item><item valid="true" arg="" uid=""><title></title><subtitle></subtitle><icon></icon></item><item valid="true" arg="" uid=""><title></title><subtitle></subtitle><icon></icon></item><item valid="true" arg="" uid=""><title></title><subtitle></subtitle><icon></icon></item><item valid="true" arg="" uid=""><title></title><subtitle></subtitle><icon></icon></item><item valid="true" arg="" uid=""><title></title><subtitle></subtitle><icon></icon></item></items> Also, the escaping options for the Script Filter are wrong. If you use bash as the language you need to enclose {query} in double quotes ("{query}") and select the Backquotes, Double Quotes, Dollars and Backslashes escaping options. Escaping shouldn't be a problem with this workflow (I don't think verbformen.de has any multi-word entries), but "can't go wrong" > "should work". The GitHub repo isn't particularly fork-friendly. Most of the files required to build a working workflow (info.plist, icon.png) are only included in the .alfredworkflow file. Might I suggest you put all of the files required to build the workflow in the repo itself and the compiled .alfredworkflow file in a GitHub release? Or put the source files in a subdirectory if you want to keep the .alfredworkflow file in the repo. I'd advise against that, though, as GitHub won't let you put .alfredworkflow files >10MB in a repo (they have to go in releases). Finally, there's a workflows.php file in the workflow. Is this file actually required?
  5. I really like the idea of toggling Alfred's theme, so I've written a Python script that will change your theme to/from dark at sunset/sunrise. It isn't possible to hook into f.lux directly (or OS X's dark mode), but I think this is a reasonable solution. It creates a Launch Agent that will call the script at sunrise and sunset every day to change the theme to/from dark/light. I'm looking into turning it into a workflow, but that will probably depend on being able to find an API that will let me look up latitude, longitude, elevation and timezone for a given location. Note: Seeing as I just wrote the script, it obviously hasn't been tested across several sunrise/sunset cycles. It also requires the astral and pytz libraries. Get the script here.
  6. This AppleScript will change Alfred's theme based on whether dark mode is on or off, but I haven't figured out a way to trigger it automatically when dark mode is toggled. You might have to use a Launch Agent to run it every 5 minutes or so (or grab a list of sunset times for your location from somewhere). tell application "System Events" tell appearance preferences to set dark mode to false if (dark mode of appearance preferences) then tell application "Alfred 2" to set theme "Dark" else tell application "Alfred 2" to set theme "Light" end if end tell
  7. Apple has fairly gutted the Spaces functionality in recent version of OS X. I don't think it's natively possible to programatically move windows from Space to Space. What you can do is install something like BetterTouchTool (which is totally awesome). You can use that to assign keyboard shortcuts (or trackpad gestures) to Move To Next/Previous Space actions.
  8. To see what type an object has, do print(repr(obj)) or log.debug(repr(obj)). Unicode strings will look like u'blah' and bytestrings will look like 'blah'. u'' doesn't convert anything: it's just a way of specifying in your source code that the string is a Unicode string. In my script, I imported unicode_literals, which switches the behaviour, so that 'blah' is a Unicode string and b'blah' is a bytestring. 'blah'.decode('utf-8') and unicode('blah', 'utf-8') are equivalent. Workflow.decode('blah') is a better bet in workflows, though, as you can also call it on Unicode strings without an error and it also normalises Unicode. With web.py, you can either pass a URL already containing a query string (?a=b&c=d) or params, which web.py will turn into a query string (so {'key': API_KEY} becomes ?key=API_KEY). Unfortunately, it's not smart enough to handle both. {'key': API_KEY} and dict(key=API_KEY) are functionally equivalent. They each have their advantages, but I tend to use the former as, all other things being equal, it runs faster. Yeah. I think ElementTree's parsing behaviour is better in this regard. No problem.
  9. This should do the trick: # encoding: utf-8 from __future__ import print_function, unicode_literals from HTMLParser import HTMLParser from urllib import quote import sys import hashlib from xml.etree.cElementTree import fromstring as make_etree from workflow import Workflow, ICON_WEB, web API_KEY = 'API KEY' # These don't really need to be bytes, but it's more correct, as # we're going to replace {query} and {title} with bytestrings API_URL = b'http://www.dictionaryapi.com/api/v1/references/medical/xml/{query}' WEB_URL = b'http://www.merriam-webster.com/medical/{title}' log = None def dict_search(query): """Return XML from API""" url = API_URL.format(query=quote(query.encode('utf-8'))) params = {'key': API_KEY} r = web.get(url, params) r.raise_for_status() # Return `r.text`, not `r.content` because # we want Unicode, not bytes. In this case, returning `r.content` # should work just as well, but `web.py` has additional encoding # information from the HTTP headers, so it's usually a good idea # to let it do any decoding return r.text def sanitise_output(text, simplify=False): """Decode HTML entities. Also remove/replace some non-ASCII characters if `simplify` is True""" # HTML entities -> text h = HTMLParser() text = h.unescape(text) if simplify: # Remove · text = text.replace('\xb7', '') # Replace en-dashes with hyphens text = text.replace('\u2013', '-') return text def parse_response(xmlstr): """Parse XML response to list of dicts""" results = [] root = make_etree(xmlstr) entries = root.findall('entry') log.debug('{} entries'.format(len(entries))) for entry in entries: # Default values data = {'title': None, 'url': None, 'definition': None} # Title hw = entry.find('hw') if hw is not None and hw.text is not None: title = sanitise_output(wf.decode(hw.text), True) data['title'] = title data['url'] = WEB_URL.format(title=quote(title.encode('utf-8'))) # Definition definition = entry.find('def/sensb/sens/dt') if definition is not None and definition.text is not None: data['definition'] = sanitise_output(wf.decode(definition.text)) log.debug(data) if data['title'] is None: # Ignore results w/o title continue results.append(data) return results def make_cache_key(query): """Return cache key for `query`""" m = hashlib.md5(query) return m.hexdigest() def main(wf): query = wf.args[0] def wrapper(): return dict_search(query) # We want to keep a separate cache for each query, so we generate # a cache key based on `query`. We use an MD5 hash of `query` because # query might contain characters that are not allowed in filenames key = 'search-{}'.format(make_cache_key(query)) # During development, cache the XML rather than the parsed results. # This way, we can change the parsing code and get different results # in Alfred without hitting the API all the time xmlstr = wf.cached_data(key, wrapper, max_age=600) results = parse_response(xmlstr) # Compile results for Alfred for result in results: wf.add_item( title=result['title'], subtitle=result['definition'], arg=result['url'], valid=True, icon=ICON_WEB) wf.send_feedback() if __name__ == '__main__': wf = Workflow() log = wf.logger sys.exit(wf.run(main)) I'm not sure exactly where your code is going wrong (I don't have BeautifulSoup installed), but there are a few issues with it. Firstly, you have the URL wrong. API_KEY needs to go in param key, not auth_token, and ?key= wants removing from the URL. When you add strings to a URL, you also need to %-escape them (urllib.quote) to ensure the URL is valid. This function requires a bytestring, however, which is why I do quote(title.encode('utf-8')) instead of just quote(title). The latter would explode if given non-ASCII. Secondly, there's no real need to use BeautifulSoup to parse XML. At least not something this simple. The built-in library is more than up to the job. There's no need to use things like str.replace with this XML. The XML library will parse and return the text as you want it. Thirdly, when you cache results, use a cache key based on query. If you just use results, all your result sets will use the same cache file, regardless of the query, so you'll always see the results from the first query that got cached until the cache expires instead of the results for the current query. I've added a bit of tidying up code in sanitise_output(). It turns HTML entities like & etc. back into proper text, which is important, but also removes/replaces a couple of characters I noticed popping up in result titles that mean the web URL will lead to no results. That code will probably need refining over time as you find other characters that break the web URL. If you have any questions, ask away.
  10. You might want to add a more useful description of your issue before doing that waiting thing.
  11. You need to update to the v2 beta. That runs just dandy on Yosemite and supports LDAP and CalDAV contact accounts, too.
  12. I have renamed it Alfred Sidekick in my mind. It all makes a lot more sense that way. It's much more powerful (and makes more sense) as a "magic keypad" to put next to your keyboard rather than something to control your computer from across the room. It can still do the latter to a certain extent, but I think you'll find it much more useful for the former application, at least in the general case.
  13. By all means, you can bide your time till one of Vero or Andrew (who already have their hands full with requests after the double release of Alfred 2.6 and Alfred Remote) finds the time to help you, or you can wind in the attitude and get some assistance from one of the knowledgeable and helpful forum members who owe you absolutely nothing, but will still donate their free time to helping you out of the sheer goodness of their hearts as long as you're not a nob about it. And as Shawn says, apart from the attitude, you're not really making it particularly easy to help you. I'm sure what you're trying to do is perfectly clear in your mind, but it isn't very clear in your posts.
  14. Exactly. autocomplete is what Alfred will show as the query if a user hits TAB on a result item (or ENTER, too, if the item is not valid). arg is the value of the item that Alfred will pass to any subsequent actions. I suspect your mental model of how workflows work might be a bit wrong. You filter the results before generating the XML. It might be worthwhile to read a tutorial or two or take apart some simple workflows. Here's a tutorial I wrote. It's tied closely to the workflow library it belongs to, and uses Python no AppleScript, but I think it should be understandable enough for you to get an idea of how Script Filters work. Alfred isn't designed to be used by other apps, it's designed to use other apps. You'll find workflows a lot simpler to build if you use Alfred to control X instead of X to control Alfred.
  15. This is definitely something that needs addressing. The workflow editor very quickly becomes annoying to use as the number of items in the workflow increases. Reorganising a large workflow is a nightmare. Even if other elements moved out of the way when you drop another element above/below them, that would be a big improvement.
  16. Your escaping options are wrong. Set Escaping to "Double Quotes" and "Backslashes" only and try that.
  17. You can just pass q to keystroke to "type" it into the app: keystroke q
  18. You're not providing very much information. What does Alfred's debugger say? Can you post a screenshot of the Script Filter configuration?
  19. Use the AppleScript tell application "VLC" to step forward to skip forwards and tell application "VLC" to step backward to skip back. You can connect them to your hotkeys using your preferred method (FastScripts, Keyboard Maestro, Alfred etc.) In Alfred, use Run Script Actions with Language set to /usr/bin/osascript.
  20. If you only search a relatively small number of folders and filetypes, you can set up Saved Searches for folder/filetype and use this workflow. Or you could use a workflow File Action to get a folder, then pass that and your query to mdfind in a Script Filter. No offense, but you said straight off that you don't know anything about writing workflows. What you're asking isn't complex in a shell. It isn't anywhere near as straightforward to implement as a workflow.
  21. If you can watch your videos in VLC instead, you could make that work, as it can be controlled via AppleScript.
  22. I had a look at the API and libraries. There's an official Python library, so it'd be easy enough to write a workflow with that and this. I don't know exactly what you want to workflow to do, but the main issue that I see is that the API doesn't provide a way to easily get a list of all your stuff. There's a recent items method, but to get a list of all your items, you may need to make a lot of API calls, which would be slow.
  23. Yeah, that's what Alfred Remote most put me in mind of. It's not easy, it's tedious, like you say.
×
×
  • Create New...