#!/usr/bin/env python
from optparse import OptionParser
import sys, urllib, os, time, threading
import Timeparser
import ogg

blkSize = 2048

_knownStreams = {
	'dlf': ("http://www.dradio.de/streaming/dlf_hq_ogg.m3u",
		"http://www.dradio.de/streaming/dlf_lq_ogg.m3u"),
	'dradio': ("http://www.dradio.de/streaming/dkultur_hq_ogg.m3u",
		"http://www.dradio.de/streaming/dkultur_lq_ogg.m3u"),
	's2': ("http://lsd.newmedia.tiscali-business.com/bb/redirect.lsc?"
			"stream=swr/swr2/live.rm&content=live&media=rm",
		"http://lsd.newmedia.tiscali-business.com/bb/redirect.lsc?"
			"stream=swr/swr2/live.rm&content=live&media=rm"),
}


class Ogg2OggWriter:
	"""This is supposed to convert the confused stream from dlf into
	a properly and quicky searchable ogg stream.  Unfortunately, it's
	more complicated than that, and I'll need to read up on what ogg would
	like to see in the granuleposes (and I'll need to find out what to do at
	the end of the stream).
	"""
	def __init__(self, targetFile):
		self.targetFile = open(targetFile, "w")
		self.oggReader = ogg.OggSyncState()
		self.oggWrapper = None
		self.oggUnwrapper = None
		self.currentSerial = None
		self.currentPageno = 0
		self.firstGranule = None
		self.curGranule = 0
		self.packetCount = 0

	def _flushWrappers(self):
		# untested -- I have no stream that needs it.
		if not self.oggWrapper:
			return
		while True:
			pg = self.oggWrapper.flush()
			if not pg:
				break
			pg.writeout(self.targetFile)

	def _unwrapPage(self, page):
		if not page:
			return
		serial = page.serialno()
		if serial!=self.currentSerial:
			self._flushWrappers()
			self.oggUnwrapper = ogg.OggStreamState(serial)
			self.oggWrapper = ogg.OggStreamState(serial)
			self.currentSerial = serial
		self.oggUnwrapper.pagein(page)
	
	def _wrapPages(self):
		while 1:
			packet = self.oggUnwrapper.packetout()
			if packet is None:
				break
			if self.packetCount>1:  # non-header packet
				if packet.granulepos==0 or packet.granulepos==-1:
					packet.granulepos = self.curGranule
					self.curGranule += 10
				else:
					if self.firstGranule is None:
						self.firstGranule = packet.granulepos
					self.curGranule = packet.granulepos = \
						packet.granulepos-self.firstGranule
			self.packetCount += 1
			self.oggWrapper.packetin(packet)
	
	def _writePages(self):
		while 1:
			pg = self.oggWrapper.pageout()
			if not pg:
				break
			pg.writeout(self.targetFile)

	def _process(self):
		while 1:
			pgNo, page = self.oggReader.pageseek()
			if pgNo==0:
				break
			page.pageno = self.currentPageno
			self.currentPageno += 1
			self._unwrapPage(page)
		self._wrapPages()
		self._writePages()

	def write(self, data):
		self.oggReader.bytesin(data)
		self._process()

	def close(self):
		self._writePages()
		self._flushWrappers()
		self.targetFile.close()


def getMP3URL(opts, m3uURL):
	streamInd = {True:0, False:1}[opts.rate>50]
	m3uURL = _knownStreams.get(m3uURL, (m3uURL, m3uURL))[streamInd]
	inF = urllib.urlopen(m3uURL)
	streamURL = inF.read().strip().split("\n")[-1].strip()
	inF.close()
	if opts.verbose:
		print "Target stream:", repr(streamURL)
	return streamURL


def doSnarf(opts, m3uURL, timeToRec, destName):
	streamURL = getMP3URL(opts, m3uURL)
	srcStream = urllib.urlopen(streamURL)
	startTime = time.time()
	endTime = startTime+timeToRec
	if opts.raw:
		destFile = open(destName, "w")
	else:
		destFile = Ogg2OggWriter(destName)
	while time.time()<endTime:
		destFile.write(srcStream.read(blkSize))
	destFile.close()


if __name__=="__main__":
	parser = OptionParser(usage="%proc [options] time-to-record m3u-url"
		" destination-file")
	parser.add_option("-b", "--a4", type="int", dest="rate", default=24)
	parser.add_option("-r", "--raw", action="store_true", dest="raw")
	parser.add_option("-v", "--verbose", dest="verbose", default=False,
		action="store_true")
	opts, args = parser.parse_args()
	if len(args)!=3:
		parser.print_help()
		sys.exit(1)
	timeToRec = Timeparser.TimeParser(args[0]).getSeconds()
	srcUrl = args[1]
	destName = args[2]
	startTime = time.time()
	doSnarf(opts, srcUrl, timeToRec, destName)
	#os.system("/home/msdemlei/mybin/oggrepack -Q '%s' > /dev/null"%destName)

