├── .gitignore ├── LICENSE.txt ├── README.md ├── Timer.alfredworkflow ├── Timer ├── LICENSE.txt ├── alarm.m4a ├── icon.png ├── info.plist ├── kudos.plist └── timer.py └── screenshot.png /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cod] 2 | 3 | # C extensions 4 | *.so 5 | 6 | # Packages 7 | *.egg 8 | *.egg-info 9 | dist 10 | build 11 | eggs 12 | parts 13 | bin 14 | var 15 | sdist 16 | develop-eggs 17 | .installed.cfg 18 | lib 19 | lib64 20 | 21 | # Installer logs 22 | pip-log.txt 23 | 24 | # Unit test / coverage reports 25 | .coverage 26 | .tox 27 | nosetests.xml 28 | 29 | # Translations 30 | *.mo 31 | 32 | # Mr Developer 33 | .mr.developer.cfg 34 | .project 35 | .pydevproject 36 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Daniel Bader 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [A countdown timer extension for Alfred.app](http://dbader.org/blog/alfred-timer-extension) 2 | A simple countdown timer command for [Alfred.app](http://www.alfredapp.com/) that uses Mountain Lion User Notifications. 3 | 4 | ![Demo screenshot](https://raw.github.com/dbader/alfred-countdown-timer/master/screenshot.png) 5 | 6 | The extension is described in closer detail on my [blog](http://dbader.org/blog/alfred-timer-extension). 7 | 8 | ## Benefits 9 | - Helps you make great tea. 10 | - Solves your [Pomodoro](http://en.wikipedia.org/wiki/Pomodoro_Technique) needs. 11 | - Uses Mountain Lion's User Notifications to tell you when time's up. 12 | - Plays a non-intrusive alarm sound. 13 | - Allows you to run multiple timers at the same time. 14 | - Allows you to add an optional label to the timer, e.g. "Laundry is done!". Thanks to [Alexander Lehmann](http://rudairandamacha.blogspot.de) for the suggestion. 15 | - Shows you how to write Alfred extensions in Python. 16 | 17 | ## Installation 18 | - Download [Timer.alfredworkflow](https://github.com/dbader/alfred-countdown-timer/blob/master/Timer.alfredworkflow?raw=true) 19 | - Double-click `Timer.alfredworkflow` to install the extension. 20 | 21 | To use this extension you need [Alfred.app](http://www.alfredapp.com/) for macOS and the [Alfred PowerPack](http://www.alfredapp.com/powerpack/). 22 | 23 | ## Usage 24 | - The general syntax is `timer [minutes] [optional:title]` 25 | - `timer 5` sets a countdown timer that goes off after 5 minutes. 26 | - `timer 0:30` or `timer 0.5` sets a timer that goes off after 30 seconds. 27 | - `timer 40 Laundry is done!` adds an optional title to the timer. 28 | - `timer` displays usage information. 29 | 30 | ## Meta 31 | 32 | Daniel Bader – [@dbader_org](https://twitter.com/dbader_org) – mail@dbader.org 33 | 34 | Distributed under the MIT license. See ``LICENSE.txt`` for more information. 35 | 36 | https://github.com/dbader/alfred-countdown-timer 37 | -------------------------------------------------------------------------------- /Timer.alfredworkflow: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbader/alfred-countdown-timer/3f08bab53c5cbbb99dc7a707eefbdf23bd733db7/Timer.alfredworkflow -------------------------------------------------------------------------------- /Timer/LICENSE.txt: -------------------------------------------------------------------------------- 1 | The icon is from ~MazeNL77's "nx10" icon set. 2 | 3 | The sound is "Ice" from Nitram+Nunca's awesome "Minutes" dashboard widget. 4 | Sadly, the company seems to have vanished. I love this sound and use 5 | it on all my devices as an alarm sound. So Nitram+Nunca, I hope it is okay 6 | for you that I include your sound file. If not please contact me and I will 7 | take it offline. 8 | 9 | The rest of the project is released under the MIT license. 10 | 11 | 12 | Copyright (c) 2013 Daniel Bader (http://dbader.org) 13 | 14 | Permission is hereby granted, free of charge, to any person obtaining a copy 15 | of this software and associated documentation files (the "Software"), to deal 16 | in the Software without restriction, including without limitation the rights 17 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 18 | copies of the Software, and to permit persons to whom the Software is 19 | furnished to do so, subject to the following conditions: 20 | 21 | The above copyright notice and this permission notice shall be included in 22 | all copies or substantial portions of the Software. 23 | 24 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 25 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 26 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 27 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 28 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 29 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 30 | THE SOFTWARE. 31 | -------------------------------------------------------------------------------- /Timer/alarm.m4a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbader/alfred-countdown-timer/3f08bab53c5cbbb99dc7a707eefbdf23bd733db7/Timer/alarm.m4a -------------------------------------------------------------------------------- /Timer/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbader/alfred-countdown-timer/3f08bab53c5cbbb99dc7a707eefbdf23bd733db7/Timer/icon.png -------------------------------------------------------------------------------- /Timer/info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | action 6 | 7 | category 8 | SCRIPTS 9 | command 10 | python timer.py {query} 11 | disabled 12 | 13 | escapedollar 14 | 15 | escapequery 16 | 17 | escapequerybackquotes 18 | 19 | escapequerybrackets 20 | 21 | escapequeryquotes 22 | 23 | escapequerysemicolons 24 | 25 | growloutput 26 | 27 | growloutputsticky 28 | 29 | keyword 30 | timer 31 | logging 32 | 33 | multifileargs 34 | 35 | parameter 36 | 0 37 | silent 38 | 39 | subtitle 40 | Example: timer 5:30 41 | title 42 | Start a countdown timer 43 | 44 | 45 | -------------------------------------------------------------------------------- /Timer/kudos.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | creator 6 | Daniel Bader 7 | website 8 | http://dbader.org/blog/alfred-timer-extension 9 | 10 | 11 | -------------------------------------------------------------------------------- /Timer/timer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """ 4 | A simple countdown timer command for Alfred.app that 5 | uses Mountain Lion User Notifications. 6 | 7 | Copyright (c) 2013 Daniel Bader (http://dbader.org) 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy 10 | of this software and associated documentation files (the "Software"), to deal 11 | in the Software without restriction, including without limitation the rights 12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | copies of the Software, and to permit persons to whom the Software is 14 | furnished to do so, subject to the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included in 17 | all copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | THE SOFTWARE. 26 | """ 27 | 28 | import json 29 | import os 30 | import subprocess 31 | import sys 32 | import time 33 | 34 | 35 | def main(argv): 36 | interval = parse_time(argv) 37 | minutes = interval / 60 38 | seconds = interval % 60 39 | 40 | label = ' '.join(argv[1:]) 41 | title = 'Timer started' + (': %s' % label.capitalize() if label else '.') 42 | 43 | if minutes and seconds: 44 | notify(title, "I'll notify you in %i:%.2i." % (minutes, seconds)) 45 | passed_time = '%i:%.2i have passed.' % (minutes, seconds) 46 | elif minutes: 47 | notify(title, "I'll notify you in %i %s." % (minutes, 48 | 'minute' if minutes == 1 else 'minutes')) 49 | passed_time = '%i %s passed.' % (minutes, 50 | 'minute has' if minutes == 1 else 'minutes have') 51 | else: 52 | notify(title, "I'll notify you in %i seconds." % seconds) 53 | passed_time = '%i seconds have passed.' % seconds 54 | 55 | time.sleep(interval) 56 | notify("Time's up" + (': %s' % label.capitalize() if label else '.'), 57 | passed_time) 58 | play_sound('alarm.m4a') 59 | 60 | 61 | def parse_time(argv): 62 | """Parse and return the desired countdown duration in seconds from 63 | the commandline. 64 | """ 65 | try: 66 | duration = argv[0] 67 | if ':' in duration: 68 | # Minutes and seconds, e.g. "5:30" 69 | minutes, seconds = duration.split(':') 70 | return int(minutes) * 60 + int(seconds) 71 | else: 72 | # Just minutes, e.g. "1.5" 73 | return int(float(duration) * 60) 74 | except: 75 | show_usage() 76 | sys.exit(1) 77 | 78 | 79 | def show_usage(): 80 | notify('Timer usage', 'timer [minutes] [optional: title]') 81 | 82 | 83 | def notify(title, text=None): 84 | subprocess.Popen([ 85 | 'osascript', 86 | '-e', 87 | f'''tell application id "com.runningwithcrayons.Alfred" to run trigger "notification" in workflow "org.dbader.alfred.timer" with argument "{title}|||{text}"''' 88 | ]) 89 | 90 | 91 | def play_sound(filename): 92 | """Play the given sound file using the `afplay` command line utility.""" 93 | subprocess.Popen(['afplay', filename]) 94 | 95 | 96 | if __name__ == '__main__': 97 | if len(sys.argv) > 1: 98 | argv = sys.argv[1].split() 99 | else: 100 | argv = [] 101 | main(argv) 102 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbader/alfred-countdown-timer/3f08bab53c5cbbb99dc7a707eefbdf23bd733db7/screenshot.png --------------------------------------------------------------------------------