]> kaliko git repositories - mpd-goodies.git/blob - bin/mfade
61a68f305d166944c8cb6e3ece4a1b361db23cb2
[mpd-goodies.git] / bin / mfade
1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*-
3
4 # Copyright (c) 2009,2010,2012,2019 kaliko <kaliko@azylum.org>
5 #
6 #   This program is free software: you can redistribute it and/or modify
7 #   it under the terms of the GNU General Public License as published by
8 #   the Free Software Foundation, either version 3 of the License, or
9 #   (at your option) any later version.
10 #
11 #   This program is distributed in the hope that it will be useful,
12 #   but WITHOUT ANY WARRANTY; without even the implied warranty of
13 #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 #   GNU General Public License for more details.
15 #
16 #   You should have received a copy of the GNU General Public License
17 #   along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 #
19
20 """
21 DOC:
22     heavily borrowed from perl script mpdtoys and converted to python.
23     mpdtoys © 2007 Joey Hess <joey@kitenet.net>
24     http://kitenet.net/~joey/code/mpdtoys
25 """
26
27 import argparse
28 import sys
29
30 from time import sleep
31 from os.path import basename
32
33 import musicpd
34
35
36 VERSION = '0.2'
37 DESC = """Fade in/out to <final volume level> over <time>.
38 Defaults are from 0% to 50% when paused or stopped 
39 and from current volume to 10th of it if playing,
40 both over 10 minutes."""
41 DESC = """Fade in/out to <final volume level> over <time>.
42 Defaults are from 0% to 50% when paused or stopped and from current volume to 10th of it if playing, both over 10 minutes."""
43 EPILOG = """You might need to set your audio_output with "always_on yes" for
44 this command to work properly.
45
46 Set MPD host/port in env. var"""
47
48 class Sleep(musicpd.MPDClient):
49     """"""
50     script_info = dict({
51         'prog': basename(__file__),
52         'description': DESC,
53         'epilog': EPILOG,
54         'formatter_class': argparse.RawDescriptionHelpFormatter,
55     })
56
57     def __init__(self):
58         """"""
59         musicpd.MPDClient.__init__(self)
60         self.tempo = 600
61         self.volum = None
62         self._get_args()
63         self._run()
64
65     def _test_volume_access(self):
66         status = self.status()
67         if 'volume' not in status:
68             print('Mixer not available!')
69             print('Try to set the always_on audio_output option on.')
70             sys.exit(1)
71
72     def _get_args(self):
73         """"""
74         parser = argparse.ArgumentParser(**self.__class__.script_info)
75         parser.add_argument('--version', action='version',
76                             version='v%s' % VERSION)
77         group = parser.add_mutually_exclusive_group()
78         group.add_argument('-m', '--minutes', type=int,
79                            help='duration to fade in/out over')
80         group.add_argument('-s', '--seconds', type=int,
81                            help='duration to fade in/out over')
82         parser.add_argument('volume', type=int, nargs='?',
83                             help='final volume level')
84         args = parser.parse_args()
85         if args.minutes:
86             self.tempo = args.minutes*60
87         if args.seconds:
88             self.tempo = args.seconds
89         if args.volume:
90             self.volum = args.volume
91
92     def _run(self):
93         """"""
94         self.connect()
95         self.mpd_state = str(self.status().get('state'))
96         if self.mpd_state == 'play':
97             self.mpd_vol = int(self.status().get('volume'))
98             if not self.volum:
99                 self.volum = self.mpd_vol // 10
100             if self.volum > self.mpd_vol:
101                 print('Error: specified min volume (%d%%) > to current volume (%d%%)' % (
102                     self.volum, self.mpd_vol))
103                 sys.exit(1)
104             print('fading down from %d%% to %d%% over %ss' % (self.mpd_vol, self.volum, self.tempo), file=sys.stdout)
105             if self.fade(self.mpd_vol, self.volum):
106                 self.stop()
107         elif self.mpd_state in ['stop', 'pause']:
108             self._test_volume_access()
109             if not self.volum:
110                 self.volum = int(50)
111             print('fading up from 0%% to %d%% over %ss' % (self.volum, self.tempo), file=sys.stdout)
112             self.mpd_vol = 0
113             self.setvol(0)
114             self.play()
115             self.fade(self.mpd_vol, self.volum)
116
117     def fade(self, mpd_vol, target):
118         """"""
119         # TODO: handle possible lost connections
120         span = target - mpd_vol
121         step = span / (10*self.tempo)
122         vol = mpd_vol
123         if step == 0:
124             return True
125         while True:
126             if int(vol) != int(self.status().get('volume')):
127                 sys.stderr.write(
128                     'Warning: external volume change, aborting!\n')
129                 return False
130             vol += step
131             self.setvol(int(vol))
132             if abs(vol - target) < 1.1*abs(step):
133                 self.setvol(target)
134                 return True
135             sleep(.1)
136
137
138 # Script starts here
139 if __name__ == '__main__':
140     try:
141         Sleep()
142     except KeyboardInterrupt:
143         sys.stdout.write('exit')
144
145 # VIM MODLINE
146 # vim: ai ts=4 sw=4 sts=4 expandtab