Added more complex setup of logging
[pyTivo.git] / config.py
blobc5af5cc34de1163f2c1b28f649c8388906346464
1 import ConfigParser, os
2 import re
3 import random
4 import string
5 from ConfigParser import NoOptionError
7 BLACKLIST_169 = ('540', '649')
8 guid = ''.join([random.choice(string.letters) for i in range(10)])
10 config = ConfigParser.ConfigParser()
11 p = os.path.dirname(__file__)
12 config_files = [
13 '/etc/pyTivo.conf',
14 os.path.join(p, 'pyTivo.conf'),
16 config.read(config_files)
18 def reset():
19 global config
20 del config
21 config = ConfigParser.ConfigParser()
22 config.read(config_file)
24 def getGUID():
25 if config.has_option('Server', 'GUID'):
26 return config.get('Server', 'GUID')
27 else:
28 return guid
30 def getTivoUsername():
31 return config.get('Server', 'tivo_username')
33 def getTivoPassword():
34 return config.get('Server', 'tivo_password')
36 def getBeaconAddresses():
37 if config.has_option('Server', 'beacon'):
38 beacon_ips = config.get('Server', 'beacon')
39 else:
40 beacon_ips = '255.255.255.255'
41 return beacon_ips
43 def getPort():
44 return config.get('Server', 'Port')
46 def get169Setting(tsn):
47 if not tsn:
48 return True
50 if config.has_section('_tivo_' + tsn):
51 if config.has_option('_tivo_' + tsn, 'aspect169'):
52 try:
53 return config.getboolean('_tivo_' + tsn, 'aspect169')
54 except ValueError:
55 pass
57 if tsn[:3] in BLACKLIST_169:
58 return False
60 return True
62 def getShares(tsn=''):
63 shares = [(section, dict(config.items(section)))
64 for section in config.sections()
65 if not (
66 section.startswith('_tivo_')
67 or section in ('Server', 'loggers', 'handlers', 'formatters')
68 or section.startswith('logger_')
69 or section.startswith('handler_')
70 or section.startswith('formatter_')
74 if config.has_section('_tivo_' + tsn):
75 if config.has_option('_tivo_' + tsn, 'shares'):
76 # clean up leading and trailing spaces & make sure ref is valid
77 tsnshares = []
78 for x in config.get('_tivo_' + tsn, 'shares').split(','):
79 y = x.lstrip().rstrip()
80 if config.has_section(y):
81 tsnshares += [(y, dict(config.items(y)))]
82 if tsnshares:
83 shares = tsnshares
85 for name, data in shares:
86 if not data.get('auto_subshares', 'False').lower() == 'true':
87 continue
89 base_path = data['path']
90 try:
91 for item in os.listdir(base_path):
92 item_path = os.path.join(base_path, item)
93 if not os.path.isdir(item_path):
94 continue
96 new_name = name + '/' + item
97 new_data = dict(data)
98 new_data['path'] = item_path
100 shares.append((new_name, new_data))
101 except:
102 pass
104 return shares
106 def getDebug(ref):
107 if config.has_option('Server', 'debug'):
108 try:
109 return str2tuple(config.get('Server', 'debug')+',,')[ref]
110 except NoOptionError:
111 pass
112 return str2tuple('False,,')[ref]
114 def getHack83():
115 try:
116 debug = config.get('Server', 'hack83')
117 if debug.lower() == 'true':
118 return True
119 else:
120 return False
121 except NoOptionError:
122 return False
124 def getOptres(tsn = None):
125 if tsn and config.has_section('_tivo_' + tsn):
126 try:
127 return config.getboolean('_tivo_' + tsn, 'optres')
128 except NoOptionError, ValueError:
129 pass
130 try:
131 return config.getboolean('Server', 'optres')
132 except NoOptionError, ValueError:
133 return False
135 def getPixelAR(ref):
136 if config.has_option('Server', 'par'):
137 try:
138 return (True, config.getfloat('Server', 'par'))[ref]
139 except NoOptionError, ValueError:
140 pass
141 return (False, 1.0)[ref]
143 def get(section, key):
144 return config.get(section, key)
146 def getFFmpegTemplate(tsn):
147 if tsn and config.has_section('_tivo_' + tsn):
148 try:
149 return config.get('_tivo_' + tsn, 'ffmpeg_tmpl', raw=True)
150 except NoOptionError:
151 pass
152 try:
153 return config.get('Server', 'ffmpeg_tmpl', raw=True)
154 except NoOptionError: #default
155 return '%(video_codec)s %(video_fps)s %(video_br)s %(max_video_br)s \
156 %(buff_size)s %(aspect_ratio)s -comment pyTivo.py %(audio_br)s \
157 %(audio_fr)s %(audio_ch)s %(audio_codec)s %(ffmpeg_pram)s %(format)s'
159 def getFFmpegPrams(tsn):
160 if tsn and config.has_section('_tivo_' + tsn):
161 try:
162 return config.get('_tivo_' + tsn, 'ffmpeg_pram', raw=True)
163 except NoOptionError:
164 pass
165 try:
166 return config.get('Server', 'ffmpeg_pram', raw=True)
167 except NoOptionError:
168 return None
170 def isHDtivo(tsn): # tsn's of High Definition Tivo's
171 return tsn != '' and tsn[:3] in ['648', '652']
173 def getValidWidths():
174 return [1920, 1440, 1280, 720, 704, 544, 480, 352]
176 def getValidHeights():
177 return [1080, 720, 480] # Technically 240 is also supported
179 # Return the number in list that is nearest to x
180 # if two values are equidistant, return the larger
181 def nearest(x, list):
182 return reduce(lambda a, b: closest(x, a, b), list)
184 def closest(x, a, b):
185 if abs(x - a) < abs(x - b) or (abs(x - a) == abs(x - b) and a > b):
186 return a
187 else:
188 return b
190 def nearestTivoHeight(height):
191 return nearest(height, getValidHeights())
193 def nearestTivoWidth(width):
194 return nearest(width, getValidWidths())
196 def getTivoHeight(tsn):
197 if tsn and config.has_section('_tivo_' + tsn):
198 try:
199 height = config.getint('_tivo_' + tsn, 'height')
200 return nearestTivoHeight(height)
201 except NoOptionError:
202 pass
203 try:
204 height = config.getint('Server', 'height')
205 return nearestTivoHeight(height)
206 except NoOptionError: #defaults for S3/S2 TiVo
207 if isHDtivo(tsn):
208 return 720
209 else:
210 return 480
212 def getTivoWidth(tsn):
213 if tsn and config.has_section('_tivo_' + tsn):
214 try:
215 width = config.getint('_tivo_' + tsn, 'width')
216 return nearestTivoWidth(width)
217 except NoOptionError:
218 pass
219 try:
220 width = config.getint('Server', 'width')
221 return nearestTivoWidth(width)
222 except NoOptionError: #defaults for S3/S2 TiVo
223 if isHDtivo(tsn):
224 return 1280
225 else:
226 return 544
228 def getAudioBR(tsn = None):
229 #convert to non-zero multiple of 64 to ensure ffmpeg compatibility
230 #compare audio_br to max_audio_br and return lowest
231 if tsn and config.has_section('_tivo_' + tsn):
232 try:
233 audiobr = int(max(int(strtod(config.get('_tivo_' + tsn, 'audio_br'))/1000), 64)/64)*64
234 return str(min(audiobr, getMaxAudioBR(tsn))) + 'k'
235 except NoOptionError:
236 pass
237 try:
238 audiobr = int(max(int(strtod(config.get('Server', 'audio_br'))/1000), 64)/64)*64
239 return str(min(audiobr, getMaxAudioBR(tsn))) + 'k'
240 except NoOptionError:
241 return str(min(384, getMaxAudioBR(tsn))) + 'k'
243 def getVideoBR(tsn = None):
244 if tsn and config.has_section('_tivo_' + tsn):
245 try:
246 return config.get('_tivo_' + tsn, 'video_br')
247 except NoOptionError:
248 pass
249 try:
250 return config.get('Server', 'video_br')
251 except NoOptionError: #defaults for S3/S2 TiVo
252 if isHDtivo(tsn):
253 return '8192k'
254 else:
255 return '4096K'
257 def getMaxVideoBR():
258 try:
259 return str(int(strtod(config.get('Server', 'max_video_br'))/1000)) + 'k'
260 except NoOptionError: #default to 17Mi
261 return '17408k'
263 def getBuffSize():
264 try:
265 return str(int(strtod(config.get('Server', 'bufsize'))))
266 except NoOptionError: #default 1024k
267 return '1024k'
269 def getMaxAudioBR(tsn = None):
270 #convert to non-zero multiple of 64 for ffmpeg compatibility
271 if tsn and config.has_section('_tivo_' + tsn):
272 try:
273 return int(int(strtod(config.get('_tivo_' + tsn, 'max_audio_br'))/1000)/64)*64
274 except NoOptionError:
275 pass
276 try:
277 return int(int(strtod(config.get('Server', 'max_audio_br'))/1000)/64)*64
278 except NoOptionError:
279 return int(448) #default to 448
281 def getAudioCodec(tsn = None):
282 if tsn and config.has_section('_tivo_' + tsn):
283 try:
284 return config.get('_tivo_' + tsn, 'audio_codec')
285 except NoOptionError:
286 pass
287 try:
288 return config.get('Server', 'audio_codec')
289 except NoOptionError:
290 return None
292 def getAudioCH(tsn = None):
293 if tsn and config.has_section('_tivo_' + tsn):
294 try:
295 return config.get('_tivo_' + tsn, 'audio_ch')
296 except NoOptionError:
297 pass
298 try:
299 return config.get('Server', 'audio_ch')
300 except NoOptionError:
301 return None
303 def getAudioFR(tsn = None):
304 if tsn and config.has_section('_tivo_' + tsn):
305 try:
306 return config.get('_tivo_' + tsn, 'audio_fr')
307 except NoOptionError:
308 pass
309 try:
310 return config.get('Server', 'audio_fr')
311 except NoOptionError:
312 return None
314 def getVideoFPS(tsn = None):
315 if tsn and config.has_section('_tivo_' + tsn):
316 try:
317 return config.get('_tivo_' + tsn, 'video_fps')
318 except NoOptionError:
319 pass
320 try:
321 return config.get('Server', 'video_fps')
322 except NoOptionError:
323 return None
325 def getVideoCodec(tsn = None):
326 if tsn and config.has_section('_tivo_' + tsn):
327 try:
328 return config.get('_tivo_' + tsn, 'video_codec')
329 except NoOptionError:
330 pass
331 try:
332 return config.get('Server', 'video_codec')
333 except NoOptionError:
334 return None
336 def getFormat(tsn = None):
337 if tsn and config.has_section('_tivo_' + tsn):
338 try:
339 return config.get('_tivo_' + tsn, 'force_format')
340 except NoOptionError:
341 pass
342 try:
343 return config.get('Server', 'force_format')
344 except NoOptionError:
345 return None
347 def str2tuple(s):
348 items = s.split(',')
349 L = [x.strip() for x in items]
350 return tuple(L)
352 # Parse a bitrate using the SI/IEEE suffix values as if by ffmpeg
353 # For example, 2K==2000, 2Ki==2048, 2MB==16000000, 2MiB==16777216
354 # Algorithm: http://svn.mplayerhq.hu/ffmpeg/trunk/libavcodec/eval.c
355 def strtod(value):
356 prefixes = {'y': -24, 'z': -21, 'a': -18, 'f': -15, 'p': -12,
357 'n': -9, 'u': -6, 'm': -3, 'c': -2, 'd': -1,
358 'h': 2, 'k': 3, 'K': 3, 'M': 6, 'G': 9,
359 'T': 12, 'P': 15, 'E': 18, 'Z': 21, 'Y': 24}
360 p = re.compile(r'^(\d+)(?:([yzafpnumcdhkKMGTPEZY])(i)?)?([Bb])?$')
361 m = p.match(value)
362 if m is None:
363 raise SyntaxError('Invalid bit value syntax')
364 (coef, prefix, power, byte) = m.groups()
365 if prefix is None:
366 value = float(coef)
367 else:
368 exponent = float(prefixes[prefix])
369 if power == 'i':
370 # Use powers of 2
371 value = float(coef) * pow(2.0, exponent / 0.3)
372 else:
373 # Use powers of 10
374 value = float(coef) * pow(10.0, exponent)
375 if byte == 'B': # B == Byte, b == bit
376 value *= 8;
377 return value