# TV grabber mod_python module

import os, fcntl, time
from tempfile import mktemp

import webutil

_title = "Beat Bolli's homepage - TV"

_sizes = [
    '192x144', '200x150', '256x192', '300x225',
    '384x288', '400x300', '512x384', '768x576'
]

_refresh = ['0', '5', '10', '20', '30', '45', '60', '120', '300']


def _allstations():
    f = open("/etc/X11/xawtvrc").readlines()
    f = [l[1:-2] for l in f if l[0] == '[' and l[-2] == ']']
    return [l for l in f if not l in ('global', 'defaults')]

_concat = ''.join

def _select(name, list, default=''):
    options = [
	'<option%s>%s</option>\n' % (
	    (default and item == default) and ' selected="selected"' or '', item
	) for item in list
    ]
    return '<select id="%s" name="%s" size="1">\n%s</select>\n' % (
	name, name, _concat(options)
    )

def _label(name, text):
    return '<label for="%s">%s</label>\n' % (name, text)

def _submit():
    return '<input type="submit" />\n'

def _img(st, s, tm=''):
    alt = tm and st + ' on ' + tm or st
    width, height = s.split('x')
    return ('<img src="snap?st=%(st)s&amp;s=%(s)s" '
        'width="%(width)s" height="%(height)s" '
	'title="%(alt)s" alt="%(alt)s" />') % locals()

def _link(ch):
    return 'station?st=%s' % ch


_station_header = """\
<p class="nav">Nav: <a href="/">Home</a> /
<a href="/bb/">Beat</a> /
<a href="/bb/bblog.html">bblog</a> :
<a href="/bb/news.html">news</a> :
<a href="/bb/links.html">links</a> :
<a href="/bb/py/">Python</a> :
<a href="/bb/js/">JavaScript</a> :
TV / <a href="overview">Overview</a> :
Single station
</p>

<h1>TV page</h1>
"""

_station_main_1 = """\
<form action="station">
<p>Here you can &ldquo;watch&rdquo; TV. The available stations,
sizes and refresh rates are:</p>

<p>
%s</p>
</form>%s
"""

_station_main_2 = """
</div>

<div class="div">

<p>This is the snapshot of station %s on %s:</p>
<p>%s</p>
"""

def station(req, st='', s='', r=''):
    req.content_type = 'text/html'
    req.headers_out.add('Content-Type', 'text/html; charset="iso-8859-1"')
    req.headers_out.add('Pragma', 'no-cache')

    if r and r != _refresh[0]:
	req.headers_out.add('Refresh', r)
    if not s:
	s = _sizes[0]
    if st:
        tm = time.asctime(time.gmtime()) + ' UTC'
	station = _station_main_2 % (st, tm, _img(st, s, tm))
    else:
	station = ''

    form = [
	_label('st', 'Station: '), _select('st', _allstations(), st),
	_label('s', 'Sizes: '), _select('s', _sizes, s),
	_label('r', 'Refresh rate (sec): '), _select('r', _refresh, r),
	_submit(),
    ]

    return webutil._template % (
	_title,
	_station_header,
	_station_main_1 % (_concat(form), station)
    )


_overview_header = """\
<p class="nav">Nav: <a href="/">Home</a> /
<a href="/bb/">Beat</a> /
<a href="/bb/cgi/blosxom.pl">bblog</a> :
<a href="/bb/cgi/blosxom.pl/news">news</a> :
<a href="/bb/py/">Python</a> :
<a href="/bb/js/">JavaScript</a> :
TV / Overview :
<a href="station">Single station</a>
</p>

<h1>TV overview</h1>
"""

_overview_main_1 = """\
<form action="overview">
<p>This is a more or less current overview of all configured stations.</p>
<p>
%s</p>
</form>

</div>

<div class="div">

<h2>Current snapshots</h2>

<table cellpadding="4">
"""

_overview_main_2 = '  <td><a href="%s">%s</a></td>\n'

_overview_main_3 = '</table>\n'

def overview(req, r='', w='3'):
    req.content_type = 'text/html'
    req.headers_out.add('Content-Type', 'text/html; charset="iso-8859-1"')

    if r and r != _refresh[0]:
	req.headers_out.add('Refresh', r)

    form = [
	_label('r', 'Refresh rate (sec): '), _select('r', [0] + _refresh[-3:], r),
	_label('w', 'Width: '), _select('w', [1, 2, 3, 4, 5], w),
	_submit(),
    ]
    main = [_overview_main_1 % _concat(form)]
    add = main.append
    try:
	w = int(w)
    except ValueError:
	w = 3

    i = 0
    for st in _allstations():
	if i % w == 0:
	    add('<tr>\n')
	add(_overview_main_2 % (_link(st), _img(st, _sizes[0])))
	i += 1
	if i % w == 0:
	    add('</tr>\n')
    if i % w != 0:
	add('</tr>\n')

    add(_overview_main_3)

    return webutil._template % (
	_title,
	_overview_header,
	_concat(main)
    )


def snap(req, st, s):
    lock = open('/tmp/tv.lock', 'w')
    fcntl.lockf(lock, fcntl.LOCK_EX)
    capture = mktemp()
    jpeg = ''
    try:
	os.system('v4lctl setstation "%s" 2>/dev/null' % st)
	os.system('v4lctl snap jpeg %s %s 2>/dev/null' % (s, capture))
	try:
	    f = open(capture)
	    jpeg = f.read()
	    f.close()
	    req.content_type = 'image/jpeg'
	except IOError:
	    pass
    finally:
	try:
	    os.unlink(capture)
	except:
	    pass
    fcntl.lockf(lock, fcntl.LOCK_UN)
    lock.close()
    return jpeg