├── .gitignore ├── LICENSE ├── MANIFEST.in ├── README.rst ├── conf └── example-conf ├── requirements.txt ├── setup.py └── vol ├── __init__.py └── main.py /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.pyc 3 | *.egg* 4 | dist/* 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any person obtaining a 2 | copy of this software and associated documentation files (the 3 | "Software"), to deal in the Software without restriction, including 4 | without limitation the rights to use, copy, modify, merge, publish, dis- 5 | tribute, sublicense, and/or sell copies of the Software, and to permit 6 | persons to whom the Software is furnished to do so, subject to the fol- 7 | lowing conditions: 8 | 9 | The above copyright notice and this permission notice shall be included 10 | in all copies or substantial portions of the Software. 11 | 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 13 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- 14 | ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 15 | SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 16 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 18 | IN THE SOFTWARE. -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.rst LICENSE 2 | recursive-include conf * -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | =============== 2 | vol 3 | =============== 4 | 5 | ************ 6 | Installation 7 | ************ 8 | 9 | with pip as easy as: :: 10 | 11 | $ pip install vol 12 | 13 | or checkout the latest version from github: :: 14 | 15 | $ git clone https://github.com/bmaeser/vol.git 16 | $ cd vol 17 | $ python setup.py install 18 | 19 | ***** 20 | What? 21 | ***** 22 | 23 | vol lets you control your mac's audio volume from the commandline. It also has support for profiles. 24 | 25 | **** 26 | Why? 27 | **** 28 | 29 | Because i want to have profiles, and want to change my audio-volume via commandline. 30 | So i can ssh into the box in my livingroom and change the volume while sitting on the couch. 31 | 32 | **** 33 | How? 34 | **** 35 | 36 | :: 37 | 38 | vol (in|out|alert) 39 | vol mute 40 | vol unmute 41 | vol load 42 | vol info 43 | 44 | vol (-h | --help) 45 | vol --version 46 | 47 | Options: 48 | -h --help Show this screen. 49 | --version Show version. 50 | 51 | ********* 52 | Examples 53 | ********* 54 | 55 | set output volume to 50 (of 100 max): :: 56 | 57 | vol out 50 58 | 59 | set input (mic) volume to 10: :: 60 | 61 | vol in 10 62 | 63 | mute and unmute: :: 64 | 65 | vol mute 66 | vol unmute 67 | 68 | load a profile from ``$HOME/.vol`` - file: :: 69 | 70 | vol load party 71 | 72 | ******** 73 | Profiles 74 | ******** 75 | 76 | vol looks for profiles in ``.vol`` in your home. 77 | 78 | If your username is 'bob' vol will parse ``/Users/bob/.vol`` 79 | 80 | a short example for ``.vol``: :: 81 | 82 | [party] 83 | in= 0 84 | alert= 0 85 | out= 100 86 | 87 | [silence] 88 | out = 0 89 | in = 0 90 | alert = 0 91 | mute=True 92 | 93 | ``.vol`` uses ini-style syntax. Please see the full example configfile in ./conf/ 94 | 95 | 96 | 97 | .. image:: https://d2weczhvl823v0.cloudfront.net/bmaeser/vol/trend.png 98 | :alt: Bitdeli badge 99 | :target: https://bitdeli.com/free 100 | 101 | -------------------------------------------------------------------------------- /conf/example-conf: -------------------------------------------------------------------------------- 1 | # save me at $HOME/.vol 2 | 3 | # i am a comment 4 | ; so am i 5 | 6 | # key-values are ini-style 7 | 8 | # all the same and valid: 9 | 10 | 11 | ; out = 20 12 | ; out=20 13 | ; out:20 14 | ; out: 20 15 | 16 | # allowed settings for mute: 17 | 18 | # true: 19 | ; mute=true 20 | ; mute=1 21 | ; mute=on 22 | ; mute=yes 23 | 24 | # false: 25 | ; mute=false 26 | ; mute=0 27 | ; mute=off 28 | ; mute=no 29 | 30 | 31 | 32 | [work] 33 | out:20 34 | alert:30 35 | 36 | [headphones] 37 | out:12 38 | alert:10 39 | 40 | [skype] 41 | in = 25 42 | out = 20 43 | alert = 10 44 | 45 | [party] 46 | in= 0 47 | alert= 0 48 | out= 100 49 | 50 | [silence] 51 | out = 0 52 | in = 0 53 | alert = 0 54 | mute=True 55 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | docopt==0.6.1 2 | wsgiref==0.1.2 3 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import vol 5 | from setuptools import setup, find_packages 6 | 7 | install_requires = [ 8 | 'docopt', 9 | ] 10 | 11 | entry_points = { 12 | 'console_scripts': [ 13 | 'vol = vol.main:main', 14 | ] 15 | } 16 | 17 | packages = find_packages() 18 | 19 | setup( 20 | name='vol', 21 | version=vol.__version__, 22 | author='Bernhard Maeser', 23 | author_email='bernhard.maeser@gmail.com', 24 | url='https://github.com/bmaeser/vol', 25 | license="MIT", 26 | description="volume control in the shell for your mac", 27 | long_description=open('README.rst').read(), 28 | packages = packages, 29 | include_package_data=True, 30 | install_requires = install_requires, 31 | zip_safe=False, 32 | entry_points=entry_points, 33 | classifiers=( 34 | 'Development Status :: 4 - Beta', 35 | 'Operating System :: MacOS :: MacOS X', 36 | 'Intended Audience :: End Users/Desktop', 37 | 'License :: OSI Approved :: MIT License', 38 | 'Programming Language :: Python', 39 | 'Programming Language :: Python :: 2.7', 40 | 'Topic :: Multimedia :: Sound/Audio', 41 | 'Topic :: Utilities', 42 | ), 43 | ) -------------------------------------------------------------------------------- /vol/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | __version__ = '0.1.1' -------------------------------------------------------------------------------- /vol/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """vol 5 | 6 | volume control in the shell for your mac 7 | 8 | Usage: 9 | vol (in|out|alert) 10 | vol mute 11 | vol unmute 12 | vol load 13 | vol info 14 | 15 | vol (-h | --help) 16 | vol --version 17 | 18 | Options: 19 | -h --help Show this screen. 20 | --version Show version. 21 | 22 | """ 23 | 24 | import ConfigParser 25 | import os 26 | import subprocess 27 | import sys 28 | 29 | from docopt import docopt 30 | 31 | from . import __version__ as version 32 | 33 | 34 | def asrun(ascript): 35 | "Run the given AppleScript and return the standard output and error." 36 | 37 | ## shamelessly stolen from 38 | ## http://www.leancrew.com/all-this/2013/03/combining-python-and-applescript/ 39 | 40 | osa = subprocess.Popen(['osascript', '-'], 41 | stdin=subprocess.PIPE, 42 | stdout=subprocess.PIPE) 43 | 44 | return osa.communicate(ascript)[0] 45 | 46 | def setvolume(device, amount): 47 | "Set the volume to 'amount' on 'device' " 48 | 49 | if device == 'out': 50 | device = 'output' 51 | if device == 'in': 52 | device = 'input' 53 | 54 | cmd = 'set volume {0} volume {1}'.format(device, amount) 55 | return asrun(cmd) 56 | 57 | def main(): 58 | "Run the main programm." 59 | args = docopt(__doc__, version='vol version '+ version) 60 | 61 | 62 | if args['load'] and args['']: 63 | 64 | home = os.path.expanduser("~") 65 | cfile = os.path.join(home, '.vol') 66 | 67 | try: 68 | cfg = ConfigParser.RawConfigParser() 69 | cfg.read(cfile) 70 | 71 | profile = args[''] 72 | 73 | if cfg.has_section(profile): 74 | for o in cfg.options(profile): 75 | if o == 'out' or o == 'in' or o == 'alert': 76 | setvolume(o, cfg.get(profile, o)) 77 | elif o == 'mute': 78 | if cfg.getboolean(profile, o): 79 | asrun('set volume output muted true') 80 | else: 81 | asrun('set volume output muted false') 82 | else: 83 | raise Error 84 | 85 | except Exception, e: 86 | print "Error: {0} in {1} does not exist or is malformed".format(args[''], cfile) 87 | 88 | 89 | elif args['info']: 90 | print asrun('get volume settings') 91 | 92 | elif args['mute']: 93 | asrun('set volume output muted true') 94 | 95 | elif args['unmute']: 96 | asrun('set volume output muted false') 97 | 98 | elif args['out']: 99 | setvolume('out', args['']) 100 | 101 | elif args['in']: 102 | setvolume('in', args['']) 103 | 104 | elif args['alert']: 105 | setvolume('alert', args['']) 106 | 107 | 108 | sys.exit(0) 109 | --------------------------------------------------------------------------------