This file is indexed.

/usr/share/oidua/oidua.py is in oidua 0.16.1-9.

This file is owned by root:root, with mode 0o755.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
#! /usr/bin/python
# -*- coding: iso-8859-1 -*-
#
# Script gathering information about directory trees of audio files
#
# This program is under GPL license. See COPYING file for details.
#
# Copyright 2003  Sylvester Johansson  (sylvestor@telia.com)
#                 Mattias Päivärinta   (mpa99001@student.mdh.se)


# TODO: Use list comprehension instead of bulky map and filter calls (later)
# TODO: Make specification for smoke tests (later)
# TODO: Actually create smoke tests (later)
# TODO: Consider custom character escaping (later)
# TODO: Installation guides? (later)
# TODO: [s,5] looks bad mixing 98.2 and 100M for instance (later)
# TODO: Customize metadata output? (later)
# TODO: to_human is duplicated in audiodir.py (later)


r"""Usage:  oidua.py [options] <basedir> ...

Options:
  -B, --bg COLOR	Set HTML background color
  -D, --date		Display datestamp header
      --debug		Output debug trace to stderr
  -e, --exclude DIR	Exclude dir from search
  -f, --file FILE	Write output to FILE
  -h, --help		Display this message
  -H, --html		HTML output
      --ignore-bad	Don't list files that cause Audiotype failure
  -i, --ignore-case	Case-insensitive directory sorting
  -I, --indent N	Set indent to N

  -m, --merge		Merge identical directories

			Basedirs with identical names are merged. This Means
			that all their subdirs are considered being subdirs of
			a single directory, and therefore sorted and displayed
			together. If there are duplicate names among the
			subdirs then those are also merged.

  -o, --output STRING	Set output format to STRING

			Anything enclosed by brackets is considered a field. A
			field must have the following syntax:
			  [TAG]
			  [TAG,WIDTH]
			  [TAG,WIDTH,SUFFIX]
			  [TAG,,SUFFIX]

			TAG is any of the following characters:
			  a	list of bitrates in Audiolist compatible format
			  b	bitrate with suffix (i.e. 192k)
			  B	bitrate in bps
			  d	depth; distance from respective basedir
			  f	number of audio files (including spacers)
			  l	length in minutes and seconds
			  L	length in seconds
			  m	time of last change
			  M	time of last change in seconds since the epoch
			  n	directory name (indented)
			  N	directory name
			  p	profile
			  P	full path
			  q	quality
			  s	size with suffix (i.e. 65.4M)
			  S	size in bytes
			  t	file type
			  T	bitrate type:
				  ~	mixed files
				  C	constant bitrate
				  L	lossless compression
				  V	variable bitrate

			WIDTH defines the exact width of the field. The output
			is cropped to this width if needed. Negative values will
			give left aligned output. Cropping is always done on the
			right.

			SUFFIX lets you specify a unit to be concatenated to
			all non-empty data.

			Other interpreted sequences are:
			  \[	[
			  \]	]
			  \n	new line
			  \t	tab character

			Unescaped brackets are forbidden unless they define a
			field.

			Note: If you have any whitespace in your output string
			you must put it inside quotes or otherwise it will not
			get parsed right.

  -q, --quiet		Omit progress indication
  -s, --strip		Strip output of field headers and empty directories
  -S, --stats		Display statistics results
  -t, --time		Display elapsed time footer
  -T, --text COLOR	Set HTML text color
  -V, --version		Display version
  -w, --wildcards	Expand wildcards in basedirs
"""


__version__ = "0.16.1"


import os, re, string, sys, time
import audiotype, audiodir, conf


class Data:
	def __init__(self):
		self.BadFiles = []
		self.Base = 0
		self.PathStack = []
		self.Start = 0
		self.Size = {
			"Total": 0.0,
			"FLAC": 0.0,
			"Ogg": 0.0,
			"MP3": 0.0,
			"MPC": 0.0}
		self.TimeTotal = 0.0


def to_human(value, radix=1024.0):
	i = 0
	while value >= radix:
		value /= radix
		i += 1
	suffix = " kMG"[i]
	if value > 100:
		return "%d%s" % (value, suffix)
	elif value < 10:
		return "%.2f%s" % (value, suffix)
	else:
		return "%.1f%s" % (value, suffix)


def update_progress():
	"""indicate progress"""
	if sys.stdout.isatty() or conf.conf.Quiet: return
	print >> sys.stderr, "\r%sb processed" % to_human(globals.Size["Total"]), 


def clear_progress():
	"""terminate progress indication"""
	if not sys.stdout.isatty() and not conf.conf.Quiet:
		print >> sys.stderr, "\r               \r",


def eval_fields(fields, obj, suffixes=1):
	"""project an object through a field list into a tuple of strings"""
	list = []
	for field in fields:
		try:
			data, width, suffix = str(obj.get(field[0])), field[1], field[2]
		except KeyError:
			print >> sys.stderr, "Unknown field <%s> in format string" % field[0]
			sys.exit(1)
		if not data: suffix = " " * len(suffix)
		if suffixes: data += suffix
		if width != None: data = "%*.*s" % (width, abs(width), data)
		list.append(data)
	return tuple(list)


def main():
	if conf.conf.DispHelp:
		print >> sys.stderr, __doc__
		return 0
	if conf.conf.OutputFormat == "HTML":
		htmlheader()
	if conf.conf.DispDate:
		headers("date")
	globals.Start = time.clock()
	if conf.conf.Folders:
		headers("header")
		keys = conf.conf.Folders.keys()
		conf.conf.sort(keys)
		for key in keys:
			smash(conf.conf.Folders[key], 0)
	if globals.BadFiles:
		print ""
		print "Audiotype failed on the following files:"
		print string.join(globals.BadFiles, "\n")

	globals.ElapsedTime = time.clock() - globals.Start
	if conf.conf.DispTime:
		print ""
		print "Generation time:     %8.2f s" % globals.ElapsedTime
	if conf.conf.DispResult:
		statistics = [
			["Ogg", globals.Size["Ogg"]],
			["MP3", globals.Size["MP3"]],
			["MPC", globals.Size["MPC"]],
			["FLAC", globals.Size["FLAC"]]]
		line = "+-----------------------+-----------+"

		print ""
		print line
   		print "| Format    Amount (Mb) | Ratio (%) |"
		print line
		for x in statistics:
			if x[1]:
				print "| %-8s %12.2f | %9.2f |" % (
					x[0],
					x[1] / (1024 * 1024),
					x[1] * 100 / globals.Size["Total"])
		print line
		totalMegs = globals.Size["Total"] / (1024 * 1024)
		print "| Total %10.2f Mb   |" % totalMegs
		print "| Speed %10.2f Mb/s |" % (totalMegs / globals.ElapsedTime)
		print line[:25]
	if conf.conf.DispVersion:
		print ""
		print "oidua version:    ", __version__
		print "audiotype version:", audiotype.__version__
	if conf.conf.OutputFormat == "HTML":
		htmlfooter()


def htmlheader():
	"""output HTML header"""
	# XXX Should we _always_ use this charset?
	print """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Music List</title>
<!-- Generated by oidua %s -->
<!-- http://legolas.mdh.se/~dal99mpa/oidua.html -->
<style type="text/css"><!--
body { color: %s; background: %s; }" 
//-->
</style>
</head>
<body>
<pre>""" % (__version__, conf.conf.TextColor, conf.conf.BGColor)


def htmlfooter():
	"""output HTML footer"""
	print"</pre>"
	#print "<p><a href=\"http://validator.w3.org/check/referer\">"
	#print "<img src=\"http://www.w3.org/Icons/valid-html401\" alt=\"Valid HTML 4.01!\" height=\"31\" width=\"88\"></a></p>"
	print"</body></html>"


def set_toggle(set, element):
	"""toggle occurance of element in set"""
	if element in set:
		set.remove(element)
	else:
		set.append(element)


def headers(token):
	if token == "header" and not conf.conf.Stripped:  #top header
		line = conf.conf.OutputString % eval_fields(conf.conf.Fields, HeaderObject(), 0)
		print line
		print "=" * len(line)
	elif token == "date":  #date
		print time.strftime("%a %b %d %H:%M:%S %Y", time.localtime())


def has_suffix(str, suffix):
	"""check string for suffix"""
	return suffix == string.lower(str[-len(suffix):])


def debug(msg):
	"""print debug message"""
	if conf.conf.Debug: print >> sys.stderr, "?? " + msg


class HeaderObject:
	def __init__(self):
		pass

	def get(self, id):
		dict = {
			"a": "Bitrate(s)",
			"b": "Bitrate",
			"B": "Bitrate",
			"c": "Channels",
			"d": "Dir",
			"D": "Depth",
			"f": "Files",
			"l": "Length",
			"L": "Length",
			"m": "Modified",
			"n": "Album/Artist",
			"N": "Album/Artist",
			"p": "Profile",
			"P": "Path",
			"q": "Quality",
			"r": "Sample Rate",
			"s": "Size",
			"S": "Size",
			"t": "Type",
			"T": "BR Type"
			#"v": "Vendor",
			#"V": "Version",
			}
		return dict[id]


class EmptyDir:
	def __init__(self, dir):
		self.dir = dir

	def get(self, id):
		if id in "nNmdPD":
			return self.dir.get(id)
		else:
			return ""

def grab(dir):
	debug("enter grab %s %s" % (dir.depth, dir.name()))
	update_progress()

	if len(dir.streams()):
		for type in dir.types():
			globals.Size[type] += dir.size(type)
		globals.Size["Total"] += dir.size()

		# delayed output
		for ddir, ddepth in globals.PathStack:
			fields = eval_fields(conf.conf.Fields, ddir)
			print conf.conf.OutputString % fields
		globals.PathStack = []

		# evaluate the fields and output string, and output
		fields = eval_fields(conf.conf.Fields, dir)
		print conf.conf.OutputString % fields

	# take care of bad files
	if conf.conf.Debug:
		for badfile in dir.bad_streams():
			print >> sys.stderr, "Audiotype failed for:", badfile
	elif conf.conf.ListBad:
		globals.BadFiles += dir.bad_streams()

	debug("exit  grab %s %s" % (dir.depth, dir.name()))
	return len(dir.streams()) != 0

def subdirectories(dirs):
	dirdict = {}
	for dir in dirs:
		for path in dir.subdirs():
			key = os.path.basename(path)
			if dirdict.has_key(key):
				dirdict[key].append(path)
			else:
				dirdict[key] = [ path ]
	return dirdict


def smash(pathlist, depth):
	debug("enter smash %s %s" % (depth, pathlist))
	displayed = 0

	# create Dir objects for all paths
	dirs = map(lambda x: audiodir.Dir(x, depth), pathlist)

	# grab all Dirs
	for dir in dirs: displayed += grab(dir)

	# create an EmptyDir for the Dir and delay its output
	if not conf.conf.Stripped and not displayed:
		globals.PathStack.append((EmptyDir(dir), depth))

	# create a common dictionary over the subdirectories of all Dirs
	subdir_dict = subdirectories(dirs)

	# sort keys and traverse the dictionary
	keys = subdir_dict.keys()
	conf.conf.sort(keys)
	for key in keys:
		# weed out base and excluded directories
		dirs = filter(lambda x: x not in conf.conf.ExcludePaths, subdir_dict[key])

		# anything left?
		if dirs: smash(dirs, depth + 1)

	# forget this directory unless its already printed
	if globals.PathStack: globals.PathStack = globals.PathStack[:-1]

	debug("exit  smash %s %s" % (depth, pathlist))


if __name__ == "__main__":
	globals = Data()
	conf.init()
	try:
		main()
	except KeyboardInterrupt:
		print >> sys.stderr, "Aborted by user"
		sys.exit(1)
	clear_progress()